JavascriptArray.h 61 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #pragma once
  6. #define ARRAY_CROSSOVER_FOR_VALIDATE 0
  7. namespace Js
  8. {
  9. class SegmentBTree
  10. {
  11. // This is an auxiliary data structure to speed finding the correct array segment for sparse arrays.
  12. // Rather than implement remove we only implement SwapSegment which requires the segment to be
  13. // swapped is in the same relative order as the segment it replaces.
  14. // The B-tree algorithm used is adapted from the pseudo-code in
  15. // Introduction to Algorithms by Corman, Leiserson, and Rivest.
  16. protected:
  17. uint32* keys; // keys[i] == segments[i]->left
  18. SparseArraySegmentBase** segments; // Length of segmentCount.
  19. SegmentBTree* children; // Length of segmentCount+1.
  20. uint32 segmentCount; // number of sparseArray segments in the Node
  21. public:
  22. static const uint MinDegree = 20; // Degree is the minimum branching factor. (If non-root, and non-leaf.)
  23. // non-root nodes are between MinDegree and MinDegree*2-1 in size.
  24. // e.g. For MinDegree == 32 -> this is 31 to 62 keys
  25. // and 32 to 63 children (every key is surrounded by before and after children).
  26. //
  27. // Allocations are simply the max possible sizes of nodes
  28. // We may do something more clever in the future.
  29. static const uint32 MinKeys = MinDegree - 1; // Minimum number of keys in any non-root node.
  30. static const uint32 MaxKeys = MinDegree*2 - 1;// Max number of keys in any node
  31. static const uint32 MaxDegree = MinDegree*2; // Max number of children
  32. static uint32 GetLazyCrossOverLimit(); // = MinDegree*3; // This is the crossover point for using the segmentBTee in our Arrays
  33. // Ideally this doesn't belong here.
  34. // Putting it here simply acknowledges that this BTree is not generic.
  35. // The implementation is tightly coupled with it's use in arrays.
  36. // The segment BTree adds memory overhead, we only want to incur it if
  37. // it is needed to prevent O(n) effects from using large sparse arrays
  38. // the BtreeNode is implicit:
  39. // btreenode := (children[0], segments[0], children[1], segments[1], ... segments[segmentCount-1], children[segmentCount])
  40. // Children pointers to the left contain segments strictly less than the segment to the right
  41. // Children points to the right contain segments strictly greater than the segment to the left.
  42. // Segments do not overlap, so the left index in a segment is sufficient to determine ordering.
  43. // keys are replicated in another array so that we do not incur the overhead of touching the memory for segments
  44. // that are uninteresting.
  45. public:
  46. SegmentBTree();
  47. void SwapSegment(uint32 originalKey, SparseArraySegmentBase* oldSeg, SparseArraySegmentBase* newSeg);
  48. template<typename Func>
  49. void Walk(Func& func) const;
  50. protected:
  51. BOOL IsLeaf() const;
  52. BOOL IsFullNode() const;
  53. static void InternalFind(SegmentBTree* node, uint32 itemIndex, SparseArraySegmentBase*& prev, SparseArraySegmentBase*& matchOrNext);
  54. static void SplitChild(Recycler* recycler, SegmentBTree* tree, uint32 count, SegmentBTree* root);
  55. static void InsertNonFullNode(Recycler* recycler, SegmentBTree* tree, SparseArraySegmentBase* newSeg);
  56. };
  57. class SegmentBTreeRoot : public SegmentBTree
  58. {
  59. public:
  60. void Add(Recycler* recycler, SparseArraySegmentBase* newSeg);
  61. void Find(uint itemIndex, SparseArraySegmentBase*& prevOrMatch, SparseArraySegmentBase*& matchOrNext);
  62. SparseArraySegmentBase * lastUsedSegment;
  63. };
  64. class JavascriptArray : public ArrayObject
  65. {
  66. template <class TPropertyIndex>
  67. friend class ES5ArrayTypeHandlerBase;
  68. public:
  69. static const size_t StackAllocationSize;
  70. private:
  71. static PropertyId const specialPropertyIds[];
  72. protected:
  73. DEFINE_VTABLE_CTOR(JavascriptArray, ArrayObject);
  74. DEFINE_MARSHAL_OBJECT_TO_SCRIPT_CONTEXT(JavascriptArray);
  75. private:
  76. bool isInitialized;
  77. protected:
  78. SparseArraySegmentBase* head;
  79. union
  80. {
  81. SparseArraySegmentBase* lastUsedSegment;
  82. SegmentBTreeRoot* segmentBTreeRoot;
  83. }segmentUnion;
  84. public:
  85. typedef Var TElement;
  86. static const SparseArraySegmentBase *EmptySegment;
  87. static uint32 const InvalidIndex = 0xFFFFFFFF;
  88. static uint32 const MaxArrayLength = InvalidIndex;
  89. static uint32 const MaxInitialDenseLength=1<<18;
  90. static ushort const MergeSegmentsLengthHeuristics = 128; // If the length is less than MergeSegmentsLengthHeuristics then try to merge the segments
  91. static uint64 const FiftyThirdPowerOfTwoMinusOne = 0x1FFFFFFFFFFFFF; // 2^53-1
  92. static const Var MissingItem;
  93. template<typename T> static T GetMissingItem();
  94. SparseArraySegmentBase * GetHead() const { return head; }
  95. SparseArraySegmentBase * GetLastUsedSegment() const;
  96. public:
  97. JavascriptArray(DynamicType * type);
  98. JavascriptArray(uint32 length, uint32 size, DynamicType * type);
  99. JavascriptArray(DynamicType * type, uint32 size);
  100. static Var OP_NewScArray(uint32 argLength, ScriptContext* scriptContext);
  101. static Var OP_NewScArrayWithElements(uint32 argLength, Var *elements, ScriptContext* scriptContext);
  102. static Var OP_NewScArrayWithMissingValues(uint32 argLength, ScriptContext* scriptContext);
  103. static Var OP_NewScIntArray(AuxArray<int32> *ints, ScriptContext* scriptContext);
  104. static Var OP_NewScFltArray(AuxArray<double> *doubles, ScriptContext* scriptContext);
  105. #if ENABLE_PROFILE_INFO
  106. static Var ProfiledNewScArray(uint32 argLength, ScriptContext *scriptContext, ArrayCallSiteInfo *arrayInfo, RecyclerWeakReference<FunctionBody> *weakFuncRef);
  107. static Var ProfiledNewScIntArray(AuxArray<int32> *ints, ScriptContext* scriptContext, ArrayCallSiteInfo *arrayInfo, RecyclerWeakReference<FunctionBody> *weakFuncRef);
  108. static Var ProfiledNewScFltArray(AuxArray<double> *doubles, ScriptContext* scriptContext, ArrayCallSiteInfo *arrayInfo, RecyclerWeakReference<FunctionBody> *weakFuncRef);
  109. static Var ProfiledNewInstanceNoArg(RecyclableObject *function, ScriptContext *scriptContext, ArrayCallSiteInfo *arrayInfo, RecyclerWeakReference<FunctionBody> *weakFuncRef);
  110. #endif
  111. static TypeId OP_SetNativeIntElementC(JavascriptNativeIntArray *arr, uint32 index, Var value, ScriptContext *scriptContext);
  112. static TypeId OP_SetNativeFloatElementC(JavascriptNativeFloatArray *arr, uint32 index, Var value, ScriptContext *scriptContext);
  113. template<typename T> void SetArrayLiteralItem(uint32 index, T value);
  114. void Sort(RecyclableObject* compFn);
  115. template<typename NativeArrayType, typename T> NativeArrayType * ConvertToNativeArrayInPlace(JavascriptArray *varArray);
  116. template <typename T> T GetNativeValue(Var iVal, ScriptContext * scriptContext);
  117. template <> int32 GetNativeValue<int32>(Var iVal, ScriptContext * scriptContext);
  118. template <> double GetNativeValue<double>(Var iVal, ScriptContext * scriptContext);
  119. template<typename T> void ChangeArrayTypeToNativeArray(JavascriptArray * varArray, ScriptContext * scriptContext);
  120. template<> void ChangeArrayTypeToNativeArray<double>(JavascriptArray * varArray, ScriptContext * scriptContext);
  121. template<> void ChangeArrayTypeToNativeArray<int32>(JavascriptArray * varArray, ScriptContext * scriptContext);
  122. template<typename T> inline BOOL DirectGetItemAt(uint32 index, T* outVal);
  123. virtual BOOL DirectGetVarItemAt(uint index, Var* outval, ScriptContext *scriptContext);
  124. virtual BOOL DirectGetItemAtFull(uint index, Var* outVal);
  125. virtual Var DirectGetItem(uint32 index);
  126. Var DirectGetItem(JavascriptString *propName, ScriptContext* scriptContext);
  127. template<typename T> inline void DirectSetItemAt(uint32 itemIndex, T newValue);
  128. template<typename T> inline void DirectSetItemInLastUsedSegmentAt(const uint32 offset, const T newValue);
  129. #if ENABLE_PROFILE_INFO
  130. template<typename T> inline void DirectProfiledSetItemInHeadSegmentAt(const uint32 offset, const T newValue, StElemInfo *const stElemInfo);
  131. #endif
  132. template<typename T> void DirectSetItem_Full(uint32 itemIndex, T newValue);
  133. template<typename T> SparseArraySegment<T>* PrepareSegmentForMemOp(uint32 startIndex, uint32 length);
  134. template<typename T> bool DirectSetItemAtRange(uint32 startIndex, uint32 length, T newValue);
  135. template<typename T> bool DirectSetItemAtRangeFull(uint32 startIndex, uint32 length, T newValue);
  136. template<typename T> bool DirectSetItemAtRangeFromArray(uint32 startIndex, uint32 length, JavascriptArray *fromArray, uint32 fromStartIndex);
  137. #if DBG
  138. template <typename T> void VerifyNotNeedMarshal(T value) {};
  139. template <> void VerifyNotNeedMarshal<Var>(Var value) { Assert(value == JavascriptArray::MissingItem || !CrossSite::NeedMarshalVar(value, this->GetScriptContext())); }
  140. #endif
  141. void DirectSetItemIfNotExist(uint32 index, Var newValue);
  142. template<typename T> BOOL DirectDeleteItemAt(uint32 itemIndex);
  143. virtual DescriptorFlags GetItemSetter(uint32 index, Var* setterValue, ScriptContext* requestContext) override
  144. {
  145. Var value = nullptr;
  146. return this->DirectGetItemAt(index, &value) ? WritableData : None;
  147. }
  148. static bool Is(Var aValue);
  149. static bool Is(TypeId typeId);
  150. static JavascriptArray* FromVar(Var aValue);
  151. static bool IsVarArray(Var aValue);
  152. static bool IsVarArray(TypeId typeId);
  153. static JavascriptArray* FromAnyArray(Var aValue);
  154. static bool IsDirectAccessArray(Var aValue);
  155. void SetLength(uint32 newLength);
  156. BOOL SetLength(Var newLength);
  157. virtual void ClearElements(SparseArraySegmentBase *seg, uint32 newSegmentLength);
  158. class EntryInfo
  159. {
  160. public:
  161. static FunctionInfo NewInstance;
  162. static FunctionInfo Concat;
  163. static FunctionInfo Every;
  164. static FunctionInfo Filter;
  165. static FunctionInfo ForEach;
  166. static FunctionInfo IndexOf;
  167. static FunctionInfo Includes;
  168. static FunctionInfo Join;
  169. static FunctionInfo LastIndexOf;
  170. static FunctionInfo Map;
  171. static FunctionInfo Pop;
  172. static FunctionInfo Push;
  173. static FunctionInfo Reduce;
  174. static FunctionInfo ReduceRight;
  175. static FunctionInfo Reverse;
  176. static FunctionInfo Shift;
  177. static FunctionInfo Slice;
  178. static FunctionInfo Some;
  179. static FunctionInfo Sort;
  180. static FunctionInfo Splice;
  181. static FunctionInfo ToString;
  182. static FunctionInfo ToLocaleString;
  183. static FunctionInfo Unshift;
  184. static FunctionInfo IsArray;
  185. static FunctionInfo Find;
  186. static FunctionInfo FindIndex;
  187. static FunctionInfo Entries;
  188. static FunctionInfo Keys;
  189. static FunctionInfo Values;
  190. static FunctionInfo CopyWithin;
  191. static FunctionInfo Fill;
  192. static FunctionInfo From;
  193. static FunctionInfo Of;
  194. static FunctionInfo GetterSymbolSpecies;
  195. };
  196. static Var NewInstance(RecyclableObject* function, CallInfo callInfo, ...);
  197. static Var NewInstance(RecyclableObject* function, Arguments args);
  198. static Var ProfiledNewInstance(RecyclableObject* function, CallInfo callInfo, ...);
  199. static Var EntryConcat(RecyclableObject* function, CallInfo callInfo, ...);
  200. static Var EntryEvery(RecyclableObject* function, CallInfo callInfo, ...);
  201. static Var EntryFilter(RecyclableObject* function, CallInfo callInfo, ...);
  202. static Var EntryForEach(RecyclableObject* function, CallInfo callInfo, ...);
  203. static Var EntryIndexOf(RecyclableObject* function, CallInfo callInfo, ...);
  204. static Var EntryIncludes(RecyclableObject* function, CallInfo callInfo, ...);
  205. static Var EntryJoin(RecyclableObject* function, CallInfo callInfo, ...);
  206. static Var EntryLastIndexOf(RecyclableObject* function, CallInfo callInfo, ...);
  207. static Var EntryMap(RecyclableObject* function, CallInfo callInfo, ...);
  208. static Var EntryPop(RecyclableObject* function, CallInfo callInfo, ...);
  209. static Var EntryPush(RecyclableObject* function, CallInfo callInfo, ...);
  210. static Var EntryReduce(RecyclableObject* function, CallInfo callInfo, ...);
  211. static Var EntryReduceRight(RecyclableObject* function, CallInfo callInfo, ...);
  212. static Var EntryReverse(RecyclableObject* function, CallInfo callInfo, ...);
  213. static Var EntryShift(RecyclableObject* function, CallInfo callInfo, ...);
  214. static Var EntrySlice(RecyclableObject* function, CallInfo callInfo, ...);
  215. static Var EntrySome(RecyclableObject* function, CallInfo callInfo, ...);
  216. static Var EntrySort(RecyclableObject* function, CallInfo callInfo, ...);
  217. static Var EntrySplice(RecyclableObject* function, CallInfo callInfo, ...);
  218. static Var EntryToString(RecyclableObject* function, CallInfo callInfo, ...);
  219. static Var EntryToLocaleString(RecyclableObject* function, CallInfo callInfo, ...);
  220. static Var EntryUnshift(RecyclableObject* function, CallInfo callInfo, ...);
  221. static Var EntryIsArray(RecyclableObject* function, CallInfo callInfo, ...);
  222. static Var EntryFind(RecyclableObject* function, CallInfo callInfo, ...);
  223. static Var EntryFindIndex(RecyclableObject* function, CallInfo callInfo, ...);
  224. static Var EntryEntries(RecyclableObject* function, CallInfo callInfo, ...);
  225. static Var EntryKeys(RecyclableObject* function, CallInfo callInfo, ...);
  226. static Var EntryValues(RecyclableObject* function, CallInfo callInfo, ...);
  227. static Var EntryCopyWithin(RecyclableObject* function, CallInfo callInfo, ...);
  228. static Var EntryFill(RecyclableObject* function, CallInfo callInfo, ...);
  229. static Var EntryFrom(RecyclableObject* function, CallInfo callInfo, ...);
  230. static Var EntryOf(RecyclableObject* function, CallInfo callInfo, ...);
  231. static Var EntryGetterSymbolSpecies(RecyclableObject* function, CallInfo callInfo, ...);
  232. static Var Push(ScriptContext * scriptContext, Var object, Var value);
  233. static Var EntryPushNonJavascriptArray(ScriptContext * scriptContext, Var * args, uint argCount);
  234. static Var EntryPushJavascriptArray(ScriptContext * scriptContext, Var * args, uint argCount);
  235. static Var EntryPushJavascriptArrayNoFastPath(ScriptContext * scriptContext, Var * args, uint argCount);
  236. static Var Pop(ScriptContext * scriptContext, Var object);
  237. static Var EntryPopJavascriptArray(ScriptContext * scriptContext, Var object);
  238. static Var EntryPopNonJavascriptArray(ScriptContext * scriptContext, Var object);
  239. #if DEBUG
  240. static BOOL GetIndex(const char16* propName, uint32 *pIndex);
  241. #endif
  242. uint32 GetNextIndex(uint32 index) const;
  243. template<typename T> uint32 GetNextIndexHelper(uint32 index) const;
  244. #ifdef VALIDATE_ARRAY
  245. virtual void ValidateArray();
  246. void ValidateArrayCommon();
  247. template<typename T> static void ValidateSegment(SparseArraySegment<T>* seg);
  248. static void ValidateVarSegment(SparseArraySegment<Var>* seg);
  249. #endif
  250. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  251. void CheckForceES5Array();
  252. #endif
  253. virtual BOOL HasProperty(PropertyId propertyId) override;
  254. virtual BOOL DeleteProperty(PropertyId propertyId, PropertyOperationFlags flags) override;
  255. virtual BOOL IsEnumerable(PropertyId propertyId) override;
  256. virtual BOOL IsConfigurable(PropertyId propertyId) override;
  257. virtual BOOL SetEnumerable(PropertyId propertyId, BOOL value) override;
  258. virtual BOOL SetWritable(PropertyId propertyId, BOOL value) override;
  259. virtual BOOL SetConfigurable(PropertyId propertyId, BOOL value) override;
  260. virtual BOOL SetAttributes(PropertyId propertyId, PropertyAttributes attributes) override;
  261. virtual BOOL GetProperty(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext) override;
  262. virtual BOOL GetProperty(Var originalInstance, JavascriptString* propertyNameString, Var* value, PropertyValueInfo* info, ScriptContext* requestContext) override;
  263. virtual BOOL GetPropertyReference(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext);
  264. virtual BOOL SetProperty(PropertyId propertyId, Var value, PropertyOperationFlags flags, PropertyValueInfo* info) override;
  265. virtual BOOL SetProperty(JavascriptString* propertyNameString, Var value, PropertyOperationFlags flags, PropertyValueInfo* info) override;
  266. virtual BOOL SetPropertyWithAttributes(PropertyId propertyId, Var value, PropertyAttributes attributes, PropertyValueInfo* info, PropertyOperationFlags flags = PropertyOperation_None, SideEffects possibleSideEffects = SideEffects_Any) override;
  267. virtual BOOL HasItem(uint32 index) override;
  268. virtual BOOL GetItem(Var originalInstance, uint32 index, Var* value, ScriptContext * requestContext) override;
  269. virtual BOOL GetItemReference(Var originalInstance, uint32 index, Var* value, ScriptContext * requestContext) override;
  270. virtual BOOL SetItem(uint32 index, Var value, PropertyOperationFlags flags) override;
  271. virtual BOOL DeleteItem(uint32 index, PropertyOperationFlags flags) override;
  272. virtual BOOL SetAccessors(PropertyId propertyId, Var getter, Var setter, PropertyOperationFlags flags) override;
  273. virtual BOOL PreventExtensions() override;
  274. virtual BOOL Seal() override;
  275. virtual BOOL Freeze() override;
  276. virtual BOOL GetEnumerator(BOOL enumNonEnumerable, Var* enumerator, ScriptContext * requestContext, bool preferSnapshotSemantics = true, bool enumSymbols = false) override;
  277. virtual BOOL GetDiagValueString(StringBuilder<ArenaAllocator>* stringBuilder, ScriptContext* requestContext) override;
  278. virtual BOOL GetDiagTypeString(StringBuilder<ArenaAllocator>* stringBuilder, ScriptContext* requestContext) override;
  279. virtual BOOL GetSpecialPropertyName(uint32 index, Var *propertyName, ScriptContext * requestContext) override;
  280. virtual uint GetSpecialPropertyCount() const override;
  281. virtual PropertyId const * GetSpecialPropertyIds() const override;
  282. virtual DescriptorFlags GetSetter(PropertyId propertyId, Var *setterValue, PropertyValueInfo* info, ScriptContext* requestContext) override;
  283. virtual DescriptorFlags GetSetter(JavascriptString* propertyNameString, Var *setterValue, PropertyValueInfo* info, ScriptContext* requestContext) override;
  284. // objectArray support
  285. virtual BOOL SetItemWithAttributes(uint32 index, Var value, PropertyAttributes attributes) override;
  286. virtual BOOL SetItemAttributes(uint32 index, PropertyAttributes attributes) override;
  287. virtual BOOL SetItemAccessors(uint32 index, Var getter, Var setter) override;
  288. virtual BOOL IsObjectArrayFrozen() override;
  289. virtual BOOL GetEnumerator(Var originalInstance, BOOL enumNonEnumerable, Var* enumerator, ScriptContext* requestContext, bool preferSnapshotSemantics = true, bool enumSymbols = false) override;
  290. // Get non-index enumerator for SCA
  291. virtual BOOL GetNonIndexEnumerator(Var* enumerator, ScriptContext* requestContext);
  292. virtual BOOL IsItemEnumerable(uint32 index);
  293. template<typename Func>
  294. void WalkExisting(Func func)
  295. {
  296. Assert(!JavascriptNativeIntArray::Is(this) && !JavascriptNativeFloatArray::Is(this));
  297. ArrayElementEnumerator e(this, 0);
  298. while(e.MoveNext<Var>())
  299. {
  300. func(e.GetIndex(), e.GetItem<Var>());
  301. }
  302. }
  303. static JavascriptArray* CreateArrayFromConstructor(RecyclableObject* constructor, uint32 length, ScriptContext* scriptContext);
  304. template<typename unitType, typename className>
  305. static className* New(Recycler* recycler, DynamicType* arrayType);
  306. template<typename unitType, typename className, uint inlineSlots>
  307. static className* New(uint32 length, DynamicType* arrayType, Recycler* recycler);
  308. template<typename unitType, typename className, uint inlineSlots>
  309. static className* NewLiteral(uint32 length, DynamicType* arrayType, Recycler* recycler);
  310. #if ENABLE_COPYONACCESS_ARRAY
  311. template<typename unitType, typename className, uint inlineSlots>
  312. static className* NewCopyOnAccessLiteral(DynamicType* arrayType, ArrayCallSiteInfo *arrayInfo, FunctionBody *functionBody, const Js::AuxArray<int32> *ints, Recycler* recycler);
  313. #endif
  314. static bool HasInlineHeadSegment(uint32 length);
  315. template<class T, uint InlinePropertySlots>
  316. static T *New(void *const stackAllocationPointer, const uint32 length, DynamicType *const arrayType);
  317. template<class T, uint InlinePropertySlots>
  318. static T *NewLiteral(void *const stackAllocationPointer, const uint32 length, DynamicType *const arrayType);
  319. static JavascriptArray *EnsureNonNativeArray(JavascriptArray *arr);
  320. #if ENABLE_PROFILE_INFO
  321. virtual JavascriptArray *FillFromArgs(uint length, uint start, Var *args, ArrayCallSiteInfo *info = nullptr, bool dontCreateNewArray = false);
  322. #else
  323. virtual JavascriptArray *FillFromArgs(uint length, uint start, Var *args, bool dontCreateNewArray = false);
  324. #endif
  325. protected:
  326. // Use static New methods to create array.
  327. JavascriptArray(uint32 length, DynamicType * type);
  328. // For BoxStackInstance
  329. JavascriptArray(JavascriptArray * instance, bool boxHead);
  330. template<typename T> inline void LinkSegments(SparseArraySegment<T>* prev, SparseArraySegment<T>* current);
  331. template<typename T> inline SparseArraySegment<T>* ReallocNonLeafSegment(SparseArraySegment<T>* seg, SparseArraySegmentBase* nextSeg);
  332. void TryAddToSegmentMap(Recycler* recycler, SparseArraySegmentBase* seg);
  333. private:
  334. DynamicObjectFlags GetFlags() const;
  335. DynamicObjectFlags GetFlags_Unchecked() const; // do not use except in extreme circumstances
  336. void SetFlags(const DynamicObjectFlags flags);
  337. void LinkSegmentsCommon(SparseArraySegmentBase* prev, SparseArraySegmentBase* current);
  338. public:
  339. static JavascriptArray *GetArrayForArrayOrObjectWithArray(const Var var);
  340. static JavascriptArray *GetArrayForArrayOrObjectWithArray(const Var var, bool *const isObjectWithArrayRef, TypeId *const arrayTypeIdRef);
  341. static const SparseArraySegmentBase *Jit_GetArrayHeadSegmentForArrayOrObjectWithArray(const Var var);
  342. static uint32 Jit_GetArrayHeadSegmentLength(const SparseArraySegmentBase *const headSegment);
  343. static bool Jit_OperationInvalidatedArrayHeadSegment(const SparseArraySegmentBase *const headSegmentBeforeOperation, const uint32 headSegmentLengthBeforeOperation, const Var varAfterOperation);
  344. static uint32 Jit_GetArrayLength(const Var var);
  345. static bool Jit_OperationInvalidatedArrayLength(const uint32 lengthBeforeOperation, const Var varAfterOperation);
  346. static DynamicObjectFlags Jit_GetArrayFlagsForArrayOrObjectWithArray(const Var var);
  347. static bool Jit_OperationCreatedFirstMissingValue(const DynamicObjectFlags flagsBeforeOperation, const Var varAfterOperation);
  348. public:
  349. bool HasNoMissingValues() const; // if true, the head segment has no missing values
  350. bool HasNoMissingValues_Unchecked() const; // do not use except in extreme circumstances
  351. void SetHasNoMissingValues(const bool hasNoMissingValues = true);
  352. virtual bool IsMissingHeadSegmentItem(const uint32 index) const;
  353. static VTableValue VtableHelper()
  354. {
  355. return VTableValue::VtableJavascriptArray;
  356. }
  357. static LibraryValue InitialTypeHelper()
  358. {
  359. return LibraryValue::ValueJavascriptArrayType;
  360. }
  361. static DynamicType * GetInitialType(ScriptContext * scriptContext);
  362. public:
  363. static uint32 defaultSmallSegmentAlignedSize;
  364. template<typename unitType, typename classname>
  365. inline BOOL TryGrowHeadSegmentAndSetItem(uint32 indexInt, unitType iValue);
  366. static int64 GetIndexFromVar(Js::Var arg, int64 length, ScriptContext* scriptContext);
  367. template <typename T>
  368. static Var MapHelper(JavascriptArray* pArr, Js::TypedArrayBase* typedArrayBase, RecyclableObject* obj, T length, Arguments& args, ScriptContext* scriptContext);
  369. static Var FillHelper(JavascriptArray* pArr, Js::TypedArrayBase* typedArrayBase, RecyclableObject* obj, int64 length, Arguments& args, ScriptContext* scriptContext);
  370. static Var CopyWithinHelper(JavascriptArray* pArr, Js::TypedArrayBase* typedArrayBase, RecyclableObject* obj, int64 length, Arguments& args, ScriptContext* scriptContext);
  371. template <typename T>
  372. static BOOL GetParamForIndexOf(T length, Arguments const & args, Var& search, T& fromIndex, ScriptContext * scriptContext);
  373. static BOOL GetParamForLastIndexOf(int64 length, Arguments const & args, Var& search, int64& fromIndex, ScriptContext * scriptContext);
  374. template <bool includesAlgorithm, typename T, typename P = uint32>
  375. static Var TemplatedIndexOfHelper(T* pArr, Var search, P fromIndex, P toIndex, ScriptContext * scriptContext);
  376. template <typename T>
  377. static Var LastIndexOfHelper(T* pArr, Var search, int64 fromIndex, ScriptContext * scriptContext);
  378. template <typename T>
  379. static BOOL TemplatedGetItem(T *pArr, uint32 index, Var * element, ScriptContext * scriptContext);
  380. template <typename T>
  381. static BOOL TemplatedGetItem(T *pArr, uint64 index, Var * element, ScriptContext * scriptContext);
  382. template <typename T = uint32>
  383. static Var ReverseHelper(JavascriptArray* pArr, Js::TypedArrayBase* typedArrayBase, RecyclableObject* obj, T length, ScriptContext* scriptContext);
  384. template <typename T = uint32>
  385. static Var SliceHelper(JavascriptArray* pArr, Js::TypedArrayBase* typedArrayBase, RecyclableObject* obj, T length, Arguments& args, ScriptContext* scriptContext);
  386. template <typename T = uint32>
  387. static Var EveryHelper(JavascriptArray* pArr, Js::TypedArrayBase* typedArrayBase, RecyclableObject* obj, T length, Arguments& args, ScriptContext* scriptContext);
  388. template <typename T = uint32>
  389. static Var SomeHelper(JavascriptArray* pArr, Js::TypedArrayBase* typedArrayBase, RecyclableObject* obj, T length, Arguments& args, ScriptContext* scriptContext);
  390. template <bool findIndex>
  391. static Var FindHelper(JavascriptArray* pArr, Js::TypedArrayBase* typedArrayBase, RecyclableObject* obj, int64 length, Arguments& args, ScriptContext* scriptContext);
  392. template <typename T = uint32>
  393. static Var ReduceHelper(JavascriptArray* pArr, Js::TypedArrayBase* typedArrayBase, RecyclableObject* obj, T length, Arguments& args, ScriptContext* scriptContext);
  394. template <typename T>
  395. static Var FilterHelper(JavascriptArray* pArr, RecyclableObject* obj, T length, Arguments& args, ScriptContext* scriptContext);
  396. template <typename T = uint32>
  397. static Var ReduceRightHelper(JavascriptArray* pArr, Js::TypedArrayBase* typedArrayBase, RecyclableObject* obj, T length, Arguments& args, ScriptContext* scriptContext);
  398. static Var OfHelper(bool isTypedArrayEntryPoint, Arguments& args, ScriptContext* scriptContext);
  399. protected:
  400. template<class T> bool IsMissingHeadSegmentItemImpl(const uint32 index) const;
  401. SegmentBTreeRoot * GetSegmentMap() const;
  402. void SetHeadAndLastUsedSegment(SparseArraySegmentBase * segment);
  403. void SetLastUsedSegment(SparseArraySegmentBase * segment);
  404. bool HasSegmentMap() const;
  405. private:
  406. void SetSegmentMap(SegmentBTreeRoot * segmentMap);
  407. void ClearSegmentMap();
  408. template <typename Fn> SparseArraySegmentBase * ForEachSegment(Fn fn) const;
  409. template <typename Fn> static SparseArraySegmentBase * ForEachSegment(SparseArraySegmentBase * segment, Fn fn);
  410. template<typename T> bool NeedScanForMissingValuesUponSetItem(SparseArraySegment<T> *const segment, const uint32 offset) const;
  411. template<typename T> void ScanForMissingValues(const uint startIndex = 0);
  412. template<typename T> bool ScanForMissingValues(const uint startIndex, const uint endIndex);
  413. template<typename T, uint InlinePropertySlots> static SparseArraySegment<typename T::TElement> *InitArrayAndHeadSegment(T *const array, const uint32 length, const uint32 size, const bool wasZeroAllocated);
  414. template<typename T> static void SliceHelper(JavascriptArray*pArr, JavascriptArray* pNewArr, uint32 start, uint32 newLen);
  415. template<typename T>
  416. static void ShiftHelper(JavascriptArray* pArr, ScriptContext * scriptContext);
  417. template<typename T>
  418. static void UnshiftHelper(JavascriptArray* pArr, uint32 unshiftElements, Js::Var * elements);
  419. template<typename T>
  420. static void GrowArrayHeadHelperForUnshift(JavascriptArray* pArr, uint32 unshiftElements, ScriptContext * scriptContext);
  421. static uint32 GetFromIndex(Var arg, uint32 length, ScriptContext *scriptContext);
  422. static uint64 GetFromIndex(Var arg, uint64 length, ScriptContext *scriptContext);
  423. static int64 GetFromLastIndex(Var arg, int64 length, ScriptContext *scriptContext);
  424. static JavascriptString* JoinToString(Var value, ScriptContext* scriptContext);
  425. static JavascriptString* JoinHelper(Var thisArg, JavascriptString* separatorStr, ScriptContext* scriptContext);
  426. template <typename T>
  427. static JavascriptString* JoinArrayHelper(T * arr, JavascriptString* separatorStr, ScriptContext* scriptContext);
  428. static JavascriptString* JoinOtherHelper(RecyclableObject *object, JavascriptString* separatorStr, ScriptContext* scriptContext);
  429. template <bool includesAlgorithm>
  430. static Var IndexOfHelper(Arguments const & args, ScriptContext *scriptContext);
  431. virtual int32 HeadSegmentIndexOfHelper(Var search, uint32 &fromIndex, uint32 toIndex, bool includesAlgorithm, ScriptContext * scriptContext);
  432. template<typename T>
  433. static void ArraySpliceHelper(JavascriptArray* pNewArr, JavascriptArray* pArr, uint32 start, uint32 deleteLen,
  434. Var* insertArgs, uint32 insertLen, ScriptContext *scriptContext);
  435. template<typename T>
  436. static void ArraySegmentSpliceHelper(JavascriptArray *pnewArr, SparseArraySegment<T> *seg, SparseArraySegment<T> **prev, uint32 start, uint32 deleteLen,
  437. Var* insertArgs, uint32 insertLen, Recycler *recycler);
  438. template<typename T>
  439. static RecyclableObject* ObjectSpliceHelper(RecyclableObject* pObj, uint32 len, uint32 start, uint32 deleteLen,
  440. Var* insertArgs, uint32 insertLen, ScriptContext *scriptContext, RecyclableObject* pNewObj = nullptr);
  441. static JavascriptString* ToLocaleStringHelper(Var value, ScriptContext* scriptContext);
  442. static Js::JavascriptArray* CreateNewArrayHelper(uint32 len, bool isIntArray, bool isFloatArray, Js::JavascriptArray *baseArray, ScriptContext* scriptContext);
  443. void FillFromPrototypes(uint32 startIndex, uint32 endIndex);
  444. bool IsFillFromPrototypes();
  445. void GetArrayTypeAndConvert(bool* isIntArray, bool* isFloatArray);
  446. template<typename T> void EnsureHeadStartsFromZero(Recycler * recycler);
  447. SparseArraySegmentBase * GetBeginLookupSegment(uint32 index, const bool useSegmentMap = true) const;
  448. SegmentBTreeRoot * BuildSegmentMap();
  449. void InvalidateLastUsedSegment();
  450. inline BOOL IsFullArray() const; // no missing elements till array length
  451. inline BOOL IsSingleSegmentArray() const;
  452. template<typename T> void AllocateHead();
  453. template<typename T> void EnsureHead();
  454. uint32 sort(__inout_ecount(*length) Var *orig, uint32 *length, ScriptContext *scriptContext);
  455. BOOL GetPropertyBuiltIns(PropertyId propertyId, Var* value);
  456. bool GetSetterBuiltIns(PropertyId propertyId, PropertyValueInfo* info, DescriptorFlags* descriptorFlags);
  457. private:
  458. struct Element {
  459. Var Value;
  460. JavascriptString* StringValue;
  461. };
  462. static int __cdecl CompareElements(void* context, const void* elem1, const void* elem2);
  463. void SortElements(Element* elements, uint32 left, uint32 right);
  464. template <typename Fn>
  465. static void ForEachOwnArrayIndexOfObject(RecyclableObject* obj, uint32 startIndex, uint32 limitIndex, Fn fn);
  466. template <typename T, typename Fn>
  467. static void ForEachOwnMissingArrayIndexOfObject(JavascriptArray *baseArr, JavascriptArray *destArray, RecyclableObject* obj, uint32 startIndex, uint32 limitIndex, T destIndex, Fn fn);
  468. // NativeArrays may change it's content type, but not others
  469. template <typename T> static bool MayChangeType() { return false; }
  470. template <bool hasSideEffect, typename T, typename Fn>
  471. static void TemplatedForEachItemInRange(T * arr, uint32 startIndex, uint32 limitIndex, Var missingItem, ScriptContext * scriptContext, Fn fn)
  472. {
  473. for (uint32 i = startIndex; i < limitIndex; i++)
  474. {
  475. Var element;
  476. fn(i, TemplatedGetItem(arr, i, &element, scriptContext) ? element : missingItem);
  477. if (hasSideEffect && MayChangeType<T>() && !T::Is(arr))
  478. {
  479. // The function has changed, go to another ForEachItemInRange
  480. JavascriptArray::FromVar(arr)->template ForEachItemInRange<true>(i + 1, limitIndex, missingItem, scriptContext, fn);
  481. return;
  482. }
  483. }
  484. }
  485. template <bool hasSideEffect, typename T, typename P, typename Fn>
  486. static void TemplatedForEachItemInRange(T * arr, P startIndex, P limitIndex, ScriptContext * scriptContext, Fn fn)
  487. {
  488. for (P i = startIndex; i < limitIndex; i++)
  489. {
  490. Var element;
  491. if (TemplatedGetItem(arr, i, &element, scriptContext))
  492. {
  493. fn(i, element);
  494. if (hasSideEffect && MayChangeType<T>() && !T::Is(arr))
  495. {
  496. // The function has changed, go to another ForEachItemInRange
  497. JavascriptArray::FromVar(arr)->template ForEachItemInRange<true>(i + 1, limitIndex, scriptContext, fn);
  498. return;
  499. }
  500. }
  501. }
  502. }
  503. public:
  504. template <bool hasSideEffect, typename Fn>
  505. void ForEachItemInRange(uint64 startIndex, uint64 limitIndex, ScriptContext * scriptContext, Fn fn)
  506. {
  507. Assert(false);
  508. Throw::InternalError();
  509. }
  510. template <bool hasSideEffect, typename Fn>
  511. void ForEachItemInRange(uint32 startIndex, uint32 limitIndex, ScriptContext * scriptContext, Fn fn)
  512. {
  513. switch (this->GetTypeId())
  514. {
  515. case TypeIds_Array:
  516. TemplatedForEachItemInRange<hasSideEffect>(this, startIndex, limitIndex, scriptContext, fn);
  517. break;
  518. case TypeIds_NativeIntArray:
  519. TemplatedForEachItemInRange<hasSideEffect>(JavascriptNativeIntArray::FromVar(this), startIndex, limitIndex, scriptContext, fn);
  520. break;
  521. case TypeIds_NativeFloatArray:
  522. TemplatedForEachItemInRange<hasSideEffect>(JavascriptNativeFloatArray::FromVar(this), startIndex, limitIndex, scriptContext, fn);
  523. break;
  524. default:
  525. Assert(false);
  526. break;
  527. }
  528. }
  529. template <bool hasSideEffect, typename Fn>
  530. void ForEachItemInRange(uint32 startIndex, uint32 limitIndex, Var missingItem, ScriptContext * scriptContext, Fn fn)
  531. {
  532. switch (this->GetTypeId())
  533. {
  534. case TypeIds_Array:
  535. TemplatedForEachItemInRange<hasSideEffect>(this, startIndex, limitIndex, missingItem, scriptContext, fn);
  536. break;
  537. case TypeIds_NativeIntArray:
  538. TemplatedForEachItemInRange<hasSideEffect>(JavascriptNativeIntArray::FromVar(this), startIndex, limitIndex, missingItem, scriptContext, fn);
  539. break;
  540. case TypeIds_NativeFloatArray:
  541. TemplatedForEachItemInRange<hasSideEffect>(JavascriptNativeFloatArray::FromVar(this), startIndex, limitIndex, missingItem, scriptContext, fn);
  542. break;
  543. default:
  544. Assert(false);
  545. break;
  546. }
  547. }
  548. // ArrayElementEnumerator walks an array's segments and enumerates the elements in order.
  549. class ArrayElementEnumerator
  550. {
  551. private:
  552. SparseArraySegmentBase* seg;
  553. uint32 index, endIndex;
  554. const uint32 start, end;
  555. public:
  556. ArrayElementEnumerator(JavascriptArray* arr, uint32 start = 0, uint32 end = MaxArrayLength);
  557. template<typename T> bool MoveNext();
  558. uint32 GetIndex() const;
  559. template<typename T> T GetItem() const;
  560. private:
  561. void Init(JavascriptArray* arr);
  562. };
  563. template <typename T>
  564. class IndexTrace
  565. {
  566. public:
  567. static Var ToNumber(const T& index, ScriptContext* scriptContext);
  568. // index on JavascriptArray
  569. static BOOL GetItem(JavascriptArray* arr, const T& index, Var* outVal);
  570. static BOOL SetItem(JavascriptArray* arr, const T& index, Var newValue);
  571. static void SetItemIfNotExist(JavascriptArray* arr, const T& index, Var newValue);
  572. static BOOL DeleteItem(JavascriptArray* arr, const T& index);
  573. // index on RecyclableObject
  574. static BOOL SetItem(RecyclableObject* obj, const T& index, Var newValue, PropertyOperationFlags flags = PropertyOperation_None);
  575. static BOOL DeleteItem(RecyclableObject* obj, const T& index, PropertyOperationFlags flags = PropertyOperation_None);
  576. };
  577. // BigIndex represents a general index which may grow larger than uint32.
  578. class BigIndex
  579. {
  580. private:
  581. uint32 index;
  582. uint64 bigIndex;
  583. typedef IndexTrace<uint32> small_index;
  584. public:
  585. BigIndex(uint32 initIndex = 0);
  586. BigIndex(uint64 initIndex);
  587. bool IsSmallIndex() const;
  588. bool IsUint32Max() const;
  589. uint32 GetSmallIndex() const;
  590. uint64 GetBigIndex() const;
  591. Var ToNumber(ScriptContext* scriptContext) const;
  592. const BigIndex& operator++();
  593. const BigIndex& operator--();
  594. BigIndex operator+(const BigIndex& delta) const;
  595. BigIndex operator+(uint32 delta) const;
  596. bool operator==(const BigIndex& rhs) const;
  597. bool operator> (const BigIndex& rhs) const;
  598. bool operator< (const BigIndex& rhs) const;
  599. bool operator<=(const BigIndex& rhs) const;
  600. bool operator>=(const BigIndex& rhs) const;
  601. BOOL GetItem(JavascriptArray* arr, Var* outVal) const;
  602. BOOL SetItem(JavascriptArray* arr, Var newValue) const;
  603. void SetItemIfNotExist(JavascriptArray* arr, Var newValue) const;
  604. BOOL DeleteItem(JavascriptArray* arr) const;
  605. BOOL SetItem(RecyclableObject* obj, Var newValue, PropertyOperationFlags flags = PropertyOperation_None) const;
  606. BOOL DeleteItem(RecyclableObject* obj, PropertyOperationFlags flags = PropertyOperation_None) const;
  607. };
  608. BOOL DirectGetItemAt(const BigIndex& index, Var* outVal) { return index.GetItem(this, outVal); }
  609. void DirectSetItemAt(const BigIndex& index, Var newValue) { index.SetItem(this, newValue); }
  610. void DirectSetItemIfNotExist(const BigIndex& index, Var newValue) { index.SetItemIfNotExist(this, newValue); }
  611. void DirectAppendItem(Var newValue) { BigIndex(this->GetLength()).SetItem(this, newValue); }
  612. void TruncateToProperties(const BigIndex& index, uint32 start);
  613. template<typename T>
  614. static void InternalCopyArrayElements(JavascriptArray* dstArray, const T& dstIndex, JavascriptArray* srcArray, uint32 start, uint32 end);
  615. template<typename T>
  616. static void InternalCopyNativeFloatArrayElements(JavascriptArray* dstArray, const T& dstIndex, JavascriptNativeFloatArray* srcArray, uint32 start, uint32 end);
  617. template<typename T>
  618. static void InternalCopyNativeIntArrayElements(JavascriptArray* dstArray, const T& dstIndex, JavascriptNativeIntArray* srcArray, uint32 start, uint32 end);
  619. template<typename T>
  620. static void InternalFillFromPrototype(JavascriptArray *dstArray, const T& dstIndex, JavascriptArray *srcArray, uint32 start, uint32 end, uint32 count);
  621. static void CopyArrayElements(JavascriptArray* dstArray, uint32 dstIndex, JavascriptArray* srcArray, uint32 start = 0, uint32 end = MaxArrayLength);
  622. static void CopyArrayElements(JavascriptArray* dstArray, const BigIndex& dstIndex, JavascriptArray* srcArray, uint32 start = 0, uint32 end = MaxArrayLength);
  623. template <typename T>
  624. static void CopyAnyArrayElementsToVar(JavascriptArray* dstArray, T dstIndex, JavascriptArray* srcArray, uint32 start = 0, uint32 end = MaxArrayLength);
  625. static bool CopyNativeIntArrayElements(JavascriptNativeIntArray* dstArray, uint32 dstIndex, JavascriptNativeIntArray *srcArray, uint32 start = 0, uint32 end = MaxArrayLength);
  626. static bool CopyNativeIntArrayElementsToFloat(JavascriptNativeFloatArray* dstArray, uint32 dstIndex, JavascriptNativeIntArray *srcArray, uint32 start = 0, uint32 end = MaxArrayLength);
  627. static void CopyNativeIntArrayElementsToVar(JavascriptArray* dstArray, uint32 dstIndex, JavascriptNativeIntArray *srcArray, uint32 start = 0, uint32 end = MaxArrayLength);
  628. static void CopyNativeIntArrayElementsToVar(JavascriptArray* dstArray, const BigIndex& dstIndex, JavascriptNativeIntArray *srcArray, uint32 start = 0, uint32 end = MaxArrayLength);
  629. static bool CopyNativeFloatArrayElements(JavascriptNativeFloatArray* dstArray, uint32 dstIndex, JavascriptNativeFloatArray *srcArray, uint32 start = 0, uint32 end = MaxArrayLength);
  630. static void CopyNativeFloatArrayElementsToVar(JavascriptArray* dstArray, uint32 dstIndex, JavascriptNativeFloatArray *srcArray, uint32 start = 0, uint32 end = MaxArrayLength);
  631. static void CopyNativeFloatArrayElementsToVar(JavascriptArray* dstArray, const BigIndex& dstIndex, JavascriptNativeFloatArray *srcArray, uint32 start = 0, uint32 end = MaxArrayLength);
  632. static bool BoxConcatItem(Var aItem, uint idxArg, ScriptContext *scriptContext);
  633. template<typename T>
  634. static void SetConcatItem(Var aItem, uint idxArg, JavascriptArray* pDestArray, RecyclableObject* pDestObj, T idxDest, ScriptContext *scriptContext);
  635. template<typename T>
  636. static void ConcatArgs(RecyclableObject* pDestObj, TypeId* remoteTypeIds, Js::Arguments& args, ScriptContext* scriptContext, uint start, BigIndex startIdxDest, BOOL firstPromotedItemIsSpreadable, BigIndex firstPromotedItemLength);
  637. template<typename T>
  638. static void ConcatArgs(RecyclableObject* pDestObj, TypeId* remoteTypeIds, Js::Arguments& args, ScriptContext* scriptContext, uint start = 0, uint startIdxDest = 0u, BOOL FirstPromotedItemIsSpreadable = false, BigIndex FirstPromotedItemLength = 0u);
  639. static JavascriptArray* ConcatIntArgs(JavascriptNativeIntArray* pDestArray, TypeId* remoteTypeIds, Js::Arguments& args, ScriptContext* scriptContext);
  640. static bool PromoteToBigIndex(BigIndex lhs, BigIndex rhs);
  641. static bool PromoteToBigIndex(BigIndex lhs, uint32 rhs);
  642. static JavascriptArray* ConcatFloatArgs(JavascriptNativeFloatArray* pDestArray, TypeId* remoteTypeIds, Js::Arguments& args, ScriptContext* scriptContext);
  643. private:
  644. template<typename T=uint32>
  645. static RecyclableObject* ArraySpeciesCreate(Var pThisArray, T length, ScriptContext* scriptContext, bool* pIsIntArray = nullptr, bool* pIsFloatArray = nullptr);
  646. template <typename T, typename R> static R ConvertToIndex(T idxDest, ScriptContext* scriptContext) { Throw::InternalError(); return 0; }
  647. static BOOL SetArrayLikeObjects(RecyclableObject* pDestObj, uint32 idxDest, Var aItem);
  648. static BOOL SetArrayLikeObjects(RecyclableObject* pDestObj, BigIndex idxDest, Var aItem);
  649. static void ConcatArgsCallingHelper(RecyclableObject* pDestObj, TypeId* remoteTypeIds, Js::Arguments& args, ScriptContext* scriptContext, ::Math::RecordOverflowPolicy &destLengthOverflow);
  650. public:
  651. template<typename T, typename P = uint32>
  652. static void Unshift(RecyclableObject* obj, const T& toIndex, uint32 start, P end, ScriptContext* scriptContext);
  653. template <typename T>
  654. class ItemTrace
  655. {
  656. public:
  657. static uint32 GetLength(T* obj, ScriptContext* scriptContext);
  658. static BOOL GetItem(T* obj, uint32 index, Var* outVal, ScriptContext* scriptContext);
  659. };
  660. template <typename T>
  661. static JavascriptString* ToLocaleString(T* obj, ScriptContext* scriptContext);
  662. static JavascriptString* GetLocaleSeparator(ScriptContext* scriptContext);
  663. public:
  664. static uint32 GetOffsetOfArrayFlags() { return offsetof(JavascriptArray, arrayFlags); }
  665. static uint32 GetOffsetOfHead() { return offsetof(JavascriptArray, head); }
  666. static uint32 GetOffsetOfLastUsedSegmentOrSegmentMap() { return offsetof(JavascriptArray, segmentUnion.lastUsedSegment); }
  667. static Var SpreadArrayArgs(Var arrayToSpread, const Js::AuxArray<uint32> *spreadIndices, ScriptContext *scriptContext);
  668. static uint32 GetSpreadArgLen(Var spreadArg, ScriptContext *scriptContext);
  669. static JavascriptArray * BoxStackInstance(JavascriptArray * instance);
  670. protected:
  671. template <typename T> void InitBoxedInlineHeadSegment(SparseArraySegment<T> * dst, SparseArraySegment<T> * src);
  672. template <typename T> static T * BoxStackInstance(T * instance);
  673. public:
  674. template<class T, uint InlinePropertySlots> static size_t DetermineAllocationSize(const uint inlineElementSlots, size_t *const allocationPlusSizeRef = nullptr, uint *const alignedInlineElementSlotsRef = nullptr);
  675. template<class T, uint InlinePropertySlots> static uint DetermineAvailableInlineElementSlots(const size_t allocationSize, bool *const isSufficientSpaceForInlinePropertySlotsRef);
  676. template<class T, uint ConstInlinePropertySlots, bool UseDynamicInlinePropertySlots> static SparseArraySegment<typename T::TElement> *DetermineInlineHeadSegmentPointer(T *const array);
  677. #if ENABLE_TTD
  678. public:
  679. virtual void MarkVisitKindSpecificPtrs(TTD::SnapshotExtractor* extractor) override;
  680. virtual void ProcessCorePaths() override;
  681. virtual TTD::NSSnapObjects::SnapObjectType GetSnapTag_TTD() const override;
  682. virtual void ExtractSnapObjectDataInto(TTD::NSSnapObjects::SnapObject* objData, TTD::SlabAllocator& alloc) override;
  683. #endif
  684. };
  685. // Ideally we would propagate the throw flag setting of true from the array operations down to the [[Delete]]/[[Put]]/... methods. But that is a big change
  686. // so we are checking for failure on DeleteProperty/DeleteItem/... etc instead. This helper makes that checking a little less intrusive.
  687. class ThrowTypeErrorOnFailureHelper
  688. {
  689. ScriptContext *m_scriptContext;
  690. PCWSTR m_functionName;
  691. public:
  692. ThrowTypeErrorOnFailureHelper(ScriptContext *scriptContext, PCWSTR functionName) : m_scriptContext(scriptContext), m_functionName(functionName) {}
  693. inline void ThrowTypeErrorOnFailure(BOOL operationSucceeded);
  694. inline void ThrowTypeErrorOnFailure();
  695. inline BOOL IsThrowTypeError(BOOL operationSucceeded);
  696. };
  697. class JavascriptNativeArray : public JavascriptArray
  698. {
  699. friend class JavascriptArray;
  700. protected:
  701. DEFINE_VTABLE_CTOR(JavascriptNativeArray, JavascriptArray);
  702. DEFINE_MARSHAL_OBJECT_TO_SCRIPT_CONTEXT(JavascriptNativeArray);
  703. public:
  704. JavascriptNativeArray(DynamicType * type) :
  705. JavascriptArray(type), weakRefToFuncBody(nullptr)
  706. {
  707. }
  708. protected:
  709. JavascriptNativeArray(uint32 length, DynamicType * type) :
  710. JavascriptArray(length, type), weakRefToFuncBody(nullptr) {}
  711. // For BoxStackInstance
  712. JavascriptNativeArray(JavascriptNativeArray * instance);
  713. RecyclerWeakReference<FunctionBody> *weakRefToFuncBody;
  714. public:
  715. static bool Is(Var aValue);
  716. static bool Is(TypeId typeId);
  717. static JavascriptNativeArray* FromVar(Var aValue);
  718. void SetArrayCallSite(ProfileId index, RecyclerWeakReference<FunctionBody> *weakRef)
  719. {
  720. Assert(weakRef);
  721. Assert(!weakRefToFuncBody);
  722. SetArrayCallSiteIndex(index);
  723. weakRefToFuncBody = weakRef;
  724. }
  725. void ClearArrayCallSiteIndex()
  726. {
  727. weakRefToFuncBody = nullptr;
  728. }
  729. #if ENABLE_PROFILE_INFO
  730. ArrayCallSiteInfo *GetArrayCallSiteInfo();
  731. #endif
  732. static uint32 GetOffsetOfArrayCallSiteIndex() { return offsetof(JavascriptNativeArray, arrayCallSiteIndex); }
  733. static uint32 GetOffsetOfWeakFuncRef() { return offsetof(JavascriptNativeArray, weakRefToFuncBody); }
  734. #if ENABLE_PROFILE_INFO
  735. void SetArrayProfileInfo(RecyclerWeakReference<FunctionBody> *weakRef, ArrayCallSiteInfo *arrayInfo);
  736. void CopyArrayProfileInfo(Js::JavascriptNativeArray* baseArray);
  737. #endif
  738. Var FindMinOrMax(Js::ScriptContext * scriptContext, bool findMax);
  739. template<typename T, bool checkNaNAndNegZero> Var FindMinOrMax(Js::ScriptContext * scriptContext, bool findMax); // NativeInt arrays can't have NaNs or -0
  740. static void PopWithNoDst(Var nativeArray);
  741. };
  742. class JavascriptNativeFloatArray;
  743. class JavascriptNativeIntArray : public JavascriptNativeArray
  744. {
  745. friend class JavascriptArray;
  746. public:
  747. static const size_t StackAllocationSize;
  748. protected:
  749. DEFINE_VTABLE_CTOR(JavascriptNativeIntArray, JavascriptNativeArray);
  750. DEFINE_MARSHAL_OBJECT_TO_SCRIPT_CONTEXT(JavascriptNativeIntArray);
  751. public:
  752. JavascriptNativeIntArray(DynamicType * type);
  753. JavascriptNativeIntArray(uint32 length, uint32 size, DynamicType * type);
  754. JavascriptNativeIntArray(DynamicType * type, uint32 size);
  755. protected:
  756. JavascriptNativeIntArray(uint32 length, DynamicType * type) :
  757. JavascriptNativeArray(length, type) {}
  758. // For BoxStackInstance
  759. JavascriptNativeIntArray(JavascriptNativeIntArray * instance, bool boxHead);
  760. public:
  761. static Var NewInstance(RecyclableObject* function, CallInfo callInfo, ...);
  762. static Var NewInstance(RecyclableObject* function, Arguments args);
  763. static bool Is(Var aValue);
  764. static bool Is(TypeId typeId);
  765. static JavascriptNativeIntArray* FromVar(Var aValue);
  766. static bool IsNonCrossSite(Var aValue);
  767. typedef int32 TElement;
  768. static const int32 MissingItem;
  769. virtual BOOL HasItem(uint32 index) override;
  770. virtual BOOL GetItem(Var originalInstance, uint32 index, Var* value, ScriptContext * requestContext) override;
  771. virtual BOOL GetItemReference(Var originalInstance, uint32 index, Var* value, ScriptContext * requestContext) override;
  772. virtual BOOL DirectGetVarItemAt(uint index, Var* outval, ScriptContext *scriptContext);
  773. virtual BOOL DirectGetItemAtFull(uint index, Var* outVal);
  774. virtual Var DirectGetItem(uint32 index);
  775. virtual DescriptorFlags GetItemSetter(uint32 index, Var* setterValue, ScriptContext* requestContext) override
  776. {
  777. int32 value = 0;
  778. return this->DirectGetItemAt(index, &value) ? WritableData : None;
  779. }
  780. virtual BOOL SetItem(uint32 index, Var value, PropertyOperationFlags flags) override;
  781. virtual BOOL DeleteItem(uint32 index, PropertyOperationFlags flags) override;
  782. #ifdef VALIDATE_ARRAY
  783. virtual void ValidateArray() override;
  784. #endif
  785. BOOL SetItem(uint32 index, int32 iValue);
  786. static JavascriptNativeFloatArray * ToNativeFloatArray(JavascriptNativeIntArray *intArray);
  787. static JavascriptArray * ToVarArray(JavascriptNativeIntArray *intArray);
  788. static JavascriptArray * ConvertToVarArray(JavascriptNativeIntArray *intArray);
  789. static Var Push(ScriptContext * scriptContext, Var array, int value);
  790. static int32 Pop(ScriptContext * scriptContext, Var nativeIntArray);
  791. #if ENABLE_PROFILE_INFO
  792. virtual JavascriptArray *FillFromArgs(uint length, uint start, Var *args, ArrayCallSiteInfo *info = nullptr, bool dontCreateNewArray = false) override;
  793. #else
  794. virtual JavascriptArray *FillFromArgs(uint length, uint start, Var *args, bool dontCreateNewArray = false) override;
  795. #endif
  796. virtual void ClearElements(SparseArraySegmentBase *seg, uint32 newSegmentLength) override;
  797. virtual void SetIsPrototype() override;
  798. TypeId TrySetNativeIntArrayItem(Var value, int32 *iValue, double *dValue);
  799. virtual bool IsMissingHeadSegmentItem(const uint32 index) const override;
  800. static VTableValue VtableHelper()
  801. {
  802. return VTableValue::VtableNativeIntArray;
  803. }
  804. static LibraryValue InitialTypeHelper()
  805. {
  806. return LibraryValue::ValueNativeIntArrayType;
  807. }
  808. static DynamicType * GetInitialType(ScriptContext * scriptContext);
  809. static JavascriptNativeIntArray * BoxStackInstance(JavascriptNativeIntArray * instance);
  810. private:
  811. virtual int32 HeadSegmentIndexOfHelper(Var search, uint32 &fromIndex, uint32 toIndex, bool includesAlgorithm, ScriptContext * scriptContext) override;
  812. #if ENABLE_TTD
  813. public:
  814. virtual void MarkVisitKindSpecificPtrs(TTD::SnapshotExtractor* extractor) override
  815. {
  816. return;
  817. }
  818. virtual void ProcessCorePaths() override
  819. {
  820. return;
  821. }
  822. virtual TTD::NSSnapObjects::SnapObjectType GetSnapTag_TTD() const override;
  823. virtual void ExtractSnapObjectDataInto(TTD::NSSnapObjects::SnapObject* objData, TTD::SlabAllocator& alloc) override;
  824. #endif
  825. };
  826. #if ENABLE_COPYONACCESS_ARRAY
  827. class JavascriptCopyOnAccessNativeIntArray : public JavascriptNativeIntArray
  828. {
  829. friend class JavascriptArray;
  830. public:
  831. static const size_t StackAllocationSize;
  832. protected:
  833. DEFINE_VTABLE_CTOR(JavascriptCopyOnAccessNativeIntArray, JavascriptNativeIntArray);
  834. DEFINE_MARSHAL_OBJECT_TO_SCRIPT_CONTEXT(JavascriptCopyOnAccessNativeIntArray);
  835. public:
  836. JavascriptCopyOnAccessNativeIntArray(uint32 length, DynamicType * type) :
  837. JavascriptNativeIntArray(length, type) {}
  838. virtual BOOL IsCopyOnAccessArray() { return TRUE; }
  839. static bool Is(Var aValue);
  840. static bool Is(TypeId typeId);
  841. static JavascriptCopyOnAccessNativeIntArray* FromVar(Var aValue);
  842. static DynamicType * GetInitialType(ScriptContext * scriptContext);
  843. void ConvertCopyOnAccessSegment();
  844. uint32 GetNextIndex(uint32 index) const;
  845. BOOL DirectGetItemAt(uint32 index, int* outVal);
  846. static VTableValue VtableHelper()
  847. {
  848. return VTableValue::VtableCopyOnAccessNativeIntArray;
  849. }
  850. };
  851. #endif
  852. class JavascriptNativeFloatArray : public JavascriptNativeArray
  853. {
  854. friend class JavascriptArray;
  855. public:
  856. static const size_t StackAllocationSize;
  857. protected:
  858. DEFINE_VTABLE_CTOR(JavascriptNativeFloatArray, JavascriptNativeArray);
  859. DEFINE_MARSHAL_OBJECT_TO_SCRIPT_CONTEXT(JavascriptNativeFloatArray);
  860. public:
  861. JavascriptNativeFloatArray(DynamicType * type);
  862. JavascriptNativeFloatArray(uint32 length, uint32 size, DynamicType * type);
  863. JavascriptNativeFloatArray(DynamicType * type, uint32 size);
  864. private:
  865. JavascriptNativeFloatArray(uint32 length, DynamicType * type) :
  866. JavascriptNativeArray(length, type) {}
  867. // For BoxStackInstance
  868. JavascriptNativeFloatArray(JavascriptNativeFloatArray * instance, bool boxHead);
  869. public:
  870. static Var NewInstance(RecyclableObject* function, CallInfo callInfo, ...);
  871. static Var NewInstance(RecyclableObject* function, Arguments args);
  872. static bool Is(Var aValue);
  873. static bool Is(TypeId typeId);
  874. static JavascriptNativeFloatArray* FromVar(Var aValue);
  875. static bool IsNonCrossSite(Var aValue);
  876. typedef double TElement;
  877. static const double MissingItem;
  878. virtual BOOL HasItem(uint32 index) override;
  879. virtual BOOL GetItem(Var originalInstance, uint32 index, Var* value, ScriptContext * requestContext) override;
  880. virtual BOOL GetItemReference(Var originalInstance, uint32 index, Var* value, ScriptContext * requestContext) override;
  881. virtual BOOL DirectGetVarItemAt(uint index, Var* outval, ScriptContext *scriptContext);
  882. virtual BOOL DirectGetItemAtFull(uint index, Var* outVal);
  883. virtual Var DirectGetItem(uint32 index);
  884. virtual DescriptorFlags GetItemSetter(uint32 index, Var* setterValue, ScriptContext* requestContext) override
  885. {
  886. double value = 0;
  887. return this->DirectGetItemAt(index, &value) ? WritableData : None;
  888. }
  889. virtual BOOL SetItem(uint32 index, Var value, PropertyOperationFlags flags) override;
  890. virtual BOOL DeleteItem(uint32 index, PropertyOperationFlags flags) override;
  891. #ifdef VALIDATE_ARRAY
  892. virtual void ValidateArray() override;
  893. #endif
  894. BOOL SetItem(uint32 index, double dValue);
  895. static JavascriptArray * ToVarArray(JavascriptNativeFloatArray *fArray);
  896. static JavascriptArray * ConvertToVarArray(JavascriptNativeFloatArray *fArray);
  897. #if ENABLE_PROFILE_INFO
  898. virtual JavascriptArray *FillFromArgs(uint length, uint start, Var *args, ArrayCallSiteInfo *info = nullptr, bool dontCreateNewArray = false) override;
  899. #else
  900. virtual JavascriptArray *FillFromArgs(uint length, uint start, Var *args, bool dontCreateNewArray = false) override;
  901. #endif
  902. virtual void ClearElements(SparseArraySegmentBase *seg, uint32 newSegmentLength) override;
  903. virtual void SetIsPrototype() override;
  904. TypeId TrySetNativeFloatArrayItem(Var value, double *dValue);
  905. virtual bool IsMissingHeadSegmentItem(const uint32 index) const override;
  906. static VTableValue VtableHelper()
  907. {
  908. return VTableValue::VtableNativeFloatArray;
  909. }
  910. static LibraryValue InitialTypeHelper()
  911. {
  912. return LibraryValue::ValueNativeFloatArrayType;
  913. }
  914. static DynamicType * GetInitialType(ScriptContext * scriptContext);
  915. static Var Push(ScriptContext * scriptContext, Var * nativeFloatArray, double value);
  916. static JavascriptNativeFloatArray * BoxStackInstance(JavascriptNativeFloatArray * instance);
  917. static double Pop(ScriptContext * scriptContext, Var nativeFloatArray);
  918. private:
  919. virtual int32 HeadSegmentIndexOfHelper(Var search, uint32 &fromIndex, uint32 toIndex, bool includesAlgorithm, ScriptContext * scriptContext) override;
  920. #if ENABLE_TTD
  921. public:
  922. virtual void MarkVisitKindSpecificPtrs(TTD::SnapshotExtractor* extractor) override
  923. {
  924. return;
  925. }
  926. virtual void ProcessCorePaths() override
  927. {
  928. return;
  929. }
  930. virtual TTD::NSSnapObjects::SnapObjectType GetSnapTag_TTD() const override;
  931. virtual void ExtractSnapObjectDataInto(TTD::NSSnapObjects::SnapObject* objData, TTD::SlabAllocator& alloc) override;
  932. #endif
  933. };
  934. template <>
  935. inline bool JavascriptArray::MayChangeType<JavascriptNativeIntArray>() { return true; }
  936. template <>
  937. inline bool JavascriptArray::MayChangeType<JavascriptNativeFloatArray>() { return true; }
  938. template <>
  939. inline uint32 JavascriptArray::ConvertToIndex<uint32, uint32>(uint32 idxDest, ScriptContext* scriptContext) { return idxDest; }
  940. } // namespace Js