JavascriptArray.h 71 KB

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