JavascriptArray.h 63 KB

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