JavascriptArray.h 71 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft Corporation and contributors. 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 Entries;
  214. static FunctionInfo Keys;
  215. static FunctionInfo Values;
  216. static FunctionInfo CopyWithin;
  217. static FunctionInfo Fill;
  218. static FunctionInfo From;
  219. static FunctionInfo Of;
  220. static FunctionInfo GetterSymbolSpecies;
  221. };
  222. static Var NewInstance(RecyclableObject* function, CallInfo callInfo, ...);
  223. static Var NewInstance(RecyclableObject* function, Arguments args);
  224. static Var ProfiledNewInstance(RecyclableObject* function, CallInfo callInfo, ...);
  225. static Var EntryAt(RecyclableObject* function, CallInfo callInfo, ...);
  226. static Var EntryConcat(RecyclableObject* function, CallInfo callInfo, ...);
  227. static Var EntryEvery(RecyclableObject* function, CallInfo callInfo, ...);
  228. static Var EntryFilter(RecyclableObject* function, CallInfo callInfo, ...);
  229. static Var EntryForEach(RecyclableObject* function, CallInfo callInfo, ...);
  230. static Var EntryIndexOf(RecyclableObject* function, CallInfo callInfo, ...);
  231. static Var EntryIncludes(RecyclableObject* function, CallInfo callInfo, ...);
  232. static Var EntryJoin(RecyclableObject* function, CallInfo callInfo, ...);
  233. static Var EntryLastIndexOf(RecyclableObject* function, CallInfo callInfo, ...);
  234. static Var EntryMap(RecyclableObject* function, CallInfo callInfo, ...);
  235. static Var EntryPop(RecyclableObject* function, CallInfo callInfo, ...);
  236. static Var EntryPush(RecyclableObject* function, CallInfo callInfo, ...);
  237. static Var EntryReduce(RecyclableObject* function, CallInfo callInfo, ...);
  238. static Var EntryReduceRight(RecyclableObject* function, CallInfo callInfo, ...);
  239. static Var EntryReverse(RecyclableObject* function, CallInfo callInfo, ...);
  240. static Var EntryShift(RecyclableObject* function, CallInfo callInfo, ...);
  241. static Var EntrySlice(RecyclableObject* function, CallInfo callInfo, ...);
  242. static Var EntrySome(RecyclableObject* function, CallInfo callInfo, ...);
  243. static Var EntrySort(RecyclableObject* function, CallInfo callInfo, ...);
  244. static Var EntrySplice(RecyclableObject* function, CallInfo callInfo, ...);
  245. static Var EntryToString(RecyclableObject* function, CallInfo callInfo, ...);
  246. static Var EntryToLocaleString(RecyclableObject* function, CallInfo callInfo, ...);
  247. static Var EntryUnshift(RecyclableObject* function, CallInfo callInfo, ...);
  248. static Var EntryIsArray(RecyclableObject* function, CallInfo callInfo, ...);
  249. static Var EntryFind(RecyclableObject* function, CallInfo callInfo, ...);
  250. static Var EntryFindIndex(RecyclableObject* function, CallInfo callInfo, ...);
  251. static Var EntryEntries(RecyclableObject* function, CallInfo callInfo, ...);
  252. static Var EntryKeys(RecyclableObject* function, CallInfo callInfo, ...);
  253. static Var EntryValues(RecyclableObject* function, CallInfo callInfo, ...);
  254. static Var EntryCopyWithin(RecyclableObject* function, CallInfo callInfo, ...);
  255. static Var EntryFill(RecyclableObject* function, CallInfo callInfo, ...);
  256. static Var EntryFrom(RecyclableObject* function, CallInfo callInfo, ...);
  257. static Var EntryOf(RecyclableObject* function, CallInfo callInfo, ...);
  258. static Var EntryGetterSymbolSpecies(RecyclableObject* function, CallInfo callInfo, ...);
  259. static Var Push(ScriptContext * scriptContext, Var object, Var value);
  260. static Var EntryPushNonJavascriptArray(ScriptContext * scriptContext, Var * args, uint argCount);
  261. static Var EntryPushJavascriptArray(ScriptContext * scriptContext, Var * args, uint argCount);
  262. static Var EntryPushJavascriptArrayNoFastPath(ScriptContext * scriptContext, Var * args, uint argCount);
  263. static Var Pop(ScriptContext * scriptContext, Var object);
  264. static Var EntryPopJavascriptArray(ScriptContext * scriptContext, JavascriptArray* arr);
  265. static Var EntryPopNonJavascriptArray(ScriptContext * scriptContext, Var object);
  266. #if DEBUG
  267. static BOOL GetIndex(const char16* propName, uint32 *pIndex);
  268. #endif
  269. uint32 GetNextIndex(uint32 index) const;
  270. template<typename T> uint32 GetNextIndexHelper(uint32 index) const;
  271. #ifdef VALIDATE_ARRAY
  272. virtual void ValidateArray();
  273. void ValidateArrayCommon();
  274. template<typename T> static void ValidateSegment(SparseArraySegment<T>* seg);
  275. static void ValidateVarSegment(SparseArraySegment<Var>* seg);
  276. #endif
  277. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  278. void CheckForceES5Array();
  279. #endif
  280. #if DBG
  281. void DoTypeMutation();
  282. #endif
  283. virtual PropertyQueryFlags HasPropertyQuery(PropertyId propertyId, _Inout_opt_ PropertyValueInfo* info) override;
  284. virtual BOOL DeleteProperty(PropertyId propertyId, PropertyOperationFlags flags) override;
  285. virtual BOOL DeleteProperty(JavascriptString *propertyNameString, PropertyOperationFlags flags) override;
  286. virtual BOOL IsEnumerable(PropertyId propertyId) override;
  287. virtual BOOL IsConfigurable(PropertyId propertyId) override;
  288. virtual BOOL SetEnumerable(PropertyId propertyId, BOOL value) override;
  289. virtual BOOL SetWritable(PropertyId propertyId, BOOL value) override;
  290. virtual BOOL SetConfigurable(PropertyId propertyId, BOOL value) override;
  291. virtual BOOL SetAttributes(PropertyId propertyId, PropertyAttributes attributes) override;
  292. virtual PropertyQueryFlags GetPropertyQuery(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext) override;
  293. virtual PropertyQueryFlags GetPropertyQuery(Var originalInstance, JavascriptString* propertyNameString, Var* value, PropertyValueInfo* info, ScriptContext* requestContext) override;
  294. virtual PropertyQueryFlags GetPropertyReferenceQuery(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext);
  295. virtual BOOL SetProperty(PropertyId propertyId, Var value, PropertyOperationFlags flags, PropertyValueInfo* info) override;
  296. virtual BOOL SetProperty(JavascriptString* propertyNameString, Var value, PropertyOperationFlags flags, PropertyValueInfo* info) override;
  297. virtual BOOL SetPropertyWithAttributes(PropertyId propertyId, Var value, PropertyAttributes attributes, PropertyValueInfo* info, PropertyOperationFlags flags = PropertyOperation_None, SideEffects possibleSideEffects = SideEffects_Any) override;
  298. virtual PropertyQueryFlags HasItemQuery(uint32 index) override;
  299. virtual PropertyQueryFlags GetItemQuery(Var originalInstance, uint32 index, Var* value, ScriptContext * requestContext) override;
  300. virtual PropertyQueryFlags GetItemReferenceQuery(Var originalInstance, uint32 index, Var* value, ScriptContext * requestContext) override;
  301. virtual BOOL SetItem(uint32 index, Var value, PropertyOperationFlags flags) override;
  302. virtual BOOL DeleteItem(uint32 index, PropertyOperationFlags flags) override;
  303. virtual BOOL SetAccessors(PropertyId propertyId, Var getter, Var setter, PropertyOperationFlags flags) override;
  304. virtual BOOL PreventExtensions() override;
  305. virtual BOOL Seal() override;
  306. virtual BOOL Freeze() override;
  307. virtual BOOL GetEnumerator(JavascriptStaticEnumerator * enumerator, EnumeratorFlags flags, ScriptContext* requestContext, EnumeratorCache * enumeratorCache = nullptr) override;
  308. virtual BOOL GetDiagValueString(StringBuilder<ArenaAllocator>* stringBuilder, ScriptContext* requestContext) override;
  309. virtual BOOL GetDiagTypeString(StringBuilder<ArenaAllocator>* stringBuilder, ScriptContext* requestContext) override;
  310. virtual BOOL GetSpecialPropertyName(uint32 index, JavascriptString ** propertyName, ScriptContext * requestContext) override;
  311. virtual uint GetSpecialPropertyCount() const override;
  312. virtual PropertyId const * GetSpecialPropertyIds() const override;
  313. virtual DescriptorFlags GetSetter(PropertyId propertyId, Var *setterValue, PropertyValueInfo* info, ScriptContext* requestContext) override;
  314. virtual DescriptorFlags GetSetter(JavascriptString* propertyNameString, Var *setterValue, PropertyValueInfo* info, ScriptContext* requestContext) override;
  315. // objectArray support
  316. virtual BOOL SetItemWithAttributes(uint32 index, Var value, PropertyAttributes attributes) override;
  317. virtual BOOL SetItemAttributes(uint32 index, PropertyAttributes attributes) override;
  318. virtual BOOL SetItemAccessors(uint32 index, Var getter, Var setter) override;
  319. virtual BOOL IsObjectArrayFrozen() override;
  320. virtual JavascriptEnumerator * GetIndexEnumerator(EnumeratorFlags flags, ScriptContext* requestContext) override;
  321. // Get non-index enumerator for SCA
  322. BOOL GetNonIndexEnumerator(JavascriptStaticEnumerator * enumerator, ScriptContext* requestContext);
  323. virtual BOOL IsItemEnumerable(uint32 index);
  324. template<typename Func>
  325. void WalkExisting(Func func)
  326. {
  327. Assert(!VarIs<JavascriptNativeIntArray>(this) && !VarIs<JavascriptNativeFloatArray>(this));
  328. ArrayElementEnumerator e(this, 0);
  329. while(e.MoveNext<Var>())
  330. {
  331. func(e.GetIndex(), e.GetItem<Var>());
  332. }
  333. }
  334. static JavascriptArray* CreateArrayFromConstructor(RecyclableObject* constructor, uint32 length, ScriptContext* scriptContext);
  335. static JavascriptArray* CreateArrayFromConstructorNoArg(RecyclableObject* constructor, ScriptContext* scriptContext);
  336. template<typename unitType, typename className>
  337. static className* New(Recycler* recycler, DynamicType* arrayType);
  338. template<typename unitType, typename className, uint inlineSlots>
  339. static className* New(uint32 length, DynamicType* arrayType, Recycler* recycler);
  340. template<typename unitType, typename className, uint inlineSlots>
  341. static className* NewLiteral(uint32 length, DynamicType* arrayType, Recycler* recycler);
  342. #if ENABLE_COPYONACCESS_ARRAY
  343. template<typename unitType, typename className, uint inlineSlots>
  344. static className* NewCopyOnAccessLiteral(DynamicType* arrayType, ArrayCallSiteInfo *arrayInfo, FunctionBody *functionBody, const Js::AuxArray<int32> *ints, Recycler* recycler);
  345. #endif
  346. static bool HasInlineHeadSegment(uint32 length);
  347. template<class T, uint InlinePropertySlots>
  348. static T *New(void *const stackAllocationPointer, const uint32 length, DynamicType *const arrayType);
  349. template<class T, uint InlinePropertySlots>
  350. static T *NewLiteral(void *const stackAllocationPointer, const uint32 length, DynamicType *const arrayType);
  351. static JavascriptArray *EnsureNonNativeArray(JavascriptArray *arr);
  352. #if ENABLE_PROFILE_INFO
  353. virtual JavascriptArray *FillFromArgs(uint length, uint start, Var *args, ArrayCallSiteInfo *info = nullptr, bool dontCreateNewArray = false);
  354. #else
  355. virtual JavascriptArray *FillFromArgs(uint length, uint start, Var *args, bool dontCreateNewArray = false);
  356. #endif
  357. protected:
  358. // Use static New methods to create array.
  359. JavascriptArray(uint32 length, DynamicType * type);
  360. // For BoxStackInstance
  361. JavascriptArray(JavascriptArray * instance, bool boxHead, bool deepCopy);
  362. template<typename T> inline void LinkSegments(SparseArraySegment<T>* prev, SparseArraySegment<T>* current);
  363. template<typename T> inline SparseArraySegment<T>* ReallocNonLeafSegment(SparseArraySegment<T>* seg, SparseArraySegmentBase* nextSeg, bool forceNonLeaf = false);
  364. void TryAddToSegmentMap(Recycler* recycler, SparseArraySegmentBase* seg);
  365. private:
  366. DynamicObjectFlags GetFlags() const;
  367. DynamicObjectFlags GetFlags_Unchecked() const; // do not use except in extreme circumstances
  368. void SetFlags(const DynamicObjectFlags flags);
  369. void LinkSegmentsCommon(SparseArraySegmentBase* prev, SparseArraySegmentBase* current);
  370. public:
  371. static JavascriptArray *Jit_GetArrayForArrayOrObjectWithArray(const Var var);
  372. static JavascriptArray *Jit_GetArrayForArrayOrObjectWithArray(const Var var, bool *const isObjectWithArrayRef);
  373. static bool Jit_TryGetArrayForObjectWithArray(const Var var, bool *const isObjectWithArrayRef, INT_PTR* vtable, JavascriptArray ** array);
  374. static JavascriptArray *GetArrayForArrayOrObjectWithArray(const Var var, bool *const isObjectWithArrayRef, TypeId *const arrayTypeIdRef);
  375. static const SparseArraySegmentBase *Jit_GetArrayHeadSegmentForArrayOrObjectWithArray(const Var var);
  376. static uint32 Jit_GetArrayHeadSegmentLength(const SparseArraySegmentBase *const headSegment);
  377. static bool Jit_OperationInvalidatedArrayHeadSegment(const SparseArraySegmentBase *const headSegmentBeforeOperation, const uint32 headSegmentLengthBeforeOperation, const Var varAfterOperation);
  378. static uint32 Jit_GetArrayLength(const Var var);
  379. static bool Jit_OperationInvalidatedArrayLength(const uint32 lengthBeforeOperation, const Var varAfterOperation);
  380. static DynamicObjectFlags Jit_GetArrayFlagsForArrayOrObjectWithArray(const Var var);
  381. static bool Jit_OperationCreatedFirstMissingValue(const DynamicObjectFlags flagsBeforeOperation, const Var varAfterOperation);
  382. public:
  383. bool HasNoMissingValues() const; // if true, the head segment has no missing values
  384. bool HasNoMissingValues_Unchecked() const; // do not use except in extreme circumstances
  385. void SetHasNoMissingValues(const bool hasNoMissingValues = true);
  386. template<typename T>
  387. bool IsMissingItemAt(uint32 index) const;
  388. bool IsMissingItem(uint32 index);
  389. virtual bool IsMissingHeadSegmentItem(const uint32 index) const;
  390. static VTableValue VtableHelper()
  391. {
  392. return VTableValue::VtableJavascriptArray;
  393. }
  394. static LibraryValue InitialTypeHelper()
  395. {
  396. return LibraryValue::ValueJavascriptArrayType;
  397. }
  398. static DynamicType * GetInitialType(ScriptContext * scriptContext);
  399. public:
  400. static uint32 defaultSmallSegmentAlignedSize;
  401. template<typename unitType, typename classname>
  402. inline BOOL TryGrowHeadSegmentAndSetItem(uint32 indexInt, unitType iValue);
  403. static int64 GetIndexFromVar(Js::Var arg, int64 length, ScriptContext* scriptContext);
  404. template <typename T>
  405. static Var MapHelper(JavascriptArray* pArr, Js::TypedArrayBase* typedArrayBase, RecyclableObject* obj, T length, Arguments& args, ScriptContext* scriptContext);
  406. template <typename T>
  407. static Var MapObjectHelper(RecyclableObject* obj, T length, T start, RecyclableObject* newObj, JavascriptArray* newArr,
  408. bool isBuiltinArrayCtor, RecyclableObject* callBackFn, Var thisArg, ScriptContext* scriptContext);
  409. static Var FillHelper(JavascriptArray* pArr, Js::TypedArrayBase* typedArrayBase, RecyclableObject* obj, int64 length, Arguments& args, ScriptContext* scriptContext);
  410. static Var CopyWithinHelper(JavascriptArray* pArr, Js::TypedArrayBase* typedArrayBase, RecyclableObject* obj, int64 length, Arguments& args, ScriptContext* scriptContext);
  411. template <typename T>
  412. static BOOL GetParamForIndexOf(T length, Arguments const & args, Var& search, T& fromIndex, ScriptContext * scriptContext);
  413. static BOOL GetParamForLastIndexOf(int64 length, Arguments const & args, Var& search, int64& fromIndex, ScriptContext * scriptContext);
  414. template <bool includesAlgorithm, typename T, typename P = uint32>
  415. static Var TemplatedIndexOfHelper(T* pArr, Var search, P fromIndex, P toIndex, ScriptContext * scriptContext);
  416. template <typename T>
  417. static Var LastIndexOfHelper(T* pArr, Var search, int64 fromIndex, ScriptContext * scriptContext);
  418. template <typename T>
  419. static BOOL TemplatedGetItem(T *pArr, uint32 index, Var * element, ScriptContext * scriptContext, bool checkHasItem = true);
  420. template <typename T>
  421. static BOOL TemplatedGetItem(T *pArr, uint64 index, Var * element, ScriptContext * scriptContext, bool checkHasItem = true);
  422. template <typename T = uint32>
  423. static Var ReverseHelper(JavascriptArray* pArr, Js::TypedArrayBase* typedArrayBase, RecyclableObject* obj, T length, ScriptContext* scriptContext);
  424. template <typename T = uint32>
  425. static Var SliceHelper(JavascriptArray* pArr, Js::TypedArrayBase* typedArrayBase, RecyclableObject* obj, T length, Arguments& args, ScriptContext* scriptContext);
  426. static Var SliceObjectHelper(RecyclableObject* obj, uint32 sliceStart, uint32 start, JavascriptArray* newArr, RecyclableObject* newObj, uint32 newLen, ScriptContext* scriptContext);
  427. template <typename T = uint32>
  428. static Var AtHelper(JavascriptArray* pArr, Js::TypedArrayBase* typedArrayBase, RecyclableObject* obj, T length, Arguments& args, ScriptContext* scriptContext);
  429. template <typename T = uint32>
  430. static Var EveryHelper(JavascriptArray* pArr, Js::TypedArrayBase* typedArrayBase, RecyclableObject* obj, T length, Arguments& args, ScriptContext* scriptContext);
  431. template <typename T = uint32>
  432. static Var EveryObjectHelper(RecyclableObject* obj, T length, T start, RecyclableObject* callBackFn, Var thisArg, ScriptContext* scriptContext);
  433. template <typename T = uint32>
  434. static Var SomeHelper(JavascriptArray* pArr, Js::TypedArrayBase* typedArrayBase, RecyclableObject* obj, T length, Arguments& args, ScriptContext* scriptContext);
  435. template <typename T = uint32>
  436. static Var SomeObjectHelper(RecyclableObject* obj, T length, T start, RecyclableObject* callBackFn, Var thisArg, ScriptContext* scriptContext);
  437. template <bool findIndex>
  438. static Var FindHelper(JavascriptArray* pArr, Js::TypedArrayBase* typedArrayBase, RecyclableObject* obj, int64 length, Arguments& args, ScriptContext* scriptContext);
  439. template <bool findIndex>
  440. static Var FindObjectHelper(RecyclableObject* obj, int64 length, int64 start, RecyclableObject* callBackFn, Var thisArg, ScriptContext* scriptContext);
  441. template <typename T = uint32>
  442. static Var ReduceHelper(JavascriptArray* pArr, Js::TypedArrayBase* typedArrayBase, RecyclableObject* obj, T length, Arguments& args, ScriptContext* scriptContext);
  443. template <typename T>
  444. static Var ReduceObjectHelper(RecyclableObject* obj, T length, T start, RecyclableObject* callBackFn, Var accumulator, ScriptContext* scriptContext);
  445. template <typename T>
  446. static Var FilterHelper(JavascriptArray* pArr, RecyclableObject* obj, T length, Arguments& args, ScriptContext* scriptContext);
  447. template <typename T>
  448. static Var FilterObjectHelper(RecyclableObject* obj, T length, T start, JavascriptArray* newArr, RecyclableObject* newObj, T newStart,
  449. RecyclableObject* callBackFn, Var thisArg, ScriptContext* scriptContext);
  450. template <typename T = uint32>
  451. static Var ReduceRightHelper(JavascriptArray* pArr, Js::TypedArrayBase* typedArrayBase, RecyclableObject* obj, T length, Arguments& args, ScriptContext* scriptContext);
  452. template <typename T>
  453. static Var ReduceRightObjectHelper(RecyclableObject* obj, T length, T start, RecyclableObject* callBackFn, Var accumulator, ScriptContext* scriptContext);
  454. static Var OfHelper(bool isTypedArrayEntryPoint, Arguments& args, ScriptContext* scriptContext);
  455. template<typename T>
  456. static T GetFromIndex(Var arg, T length, ScriptContext *scriptContext, bool addWithLength = true)
  457. {
  458. T fromIndex = 0;
  459. double value = TaggedInt::Is(arg) ? (double)TaggedInt::ToInt64(arg) : JavascriptConversion::ToInteger(arg, scriptContext);
  460. if (value < 0)
  461. {
  462. fromIndex = addWithLength ? (T)max(0i64, (int64)(value + length)) : 0;
  463. }
  464. else
  465. {
  466. fromIndex = (T)min(value, (double)length);
  467. }
  468. return fromIndex;
  469. }
  470. protected:
  471. template<class T> bool IsMissingHeadSegmentItemImpl(const uint32 index) const;
  472. SegmentBTreeRoot * GetSegmentMap() const;
  473. void SetHeadAndLastUsedSegment(SparseArraySegmentBase * segment);
  474. void SetLastUsedSegment(SparseArraySegmentBase * segment);
  475. bool HasSegmentMap() const;
  476. template<typename T>
  477. static void CopyHeadIfInlinedHeadSegment(JavascriptArray *array, Recycler *recycler);
  478. private:
  479. void SetSegmentMap(SegmentBTreeRoot * segmentMap);
  480. void ClearSegmentMap();
  481. template <typename Fn> SparseArraySegmentBase * ForEachSegment(Fn fn) const;
  482. template <typename Fn> static SparseArraySegmentBase * ForEachSegment(SparseArraySegmentBase * segment, Fn fn);
  483. template<typename T> bool NeedScanForMissingValuesUponSetItem(SparseArraySegment<T> *const segment, const uint32 offset) const;
  484. template<typename T> void ScanForMissingValues(const uint startIndex = 0);
  485. template<typename T> bool ScanForMissingValues(const uint startIndex, const uint endIndex);
  486. template<typename T, uint InlinePropertySlots> static SparseArraySegment<typename T::TElement> *InitArrayAndHeadSegment(T *const array, const uint32 length, const uint32 size, const bool wasZeroAllocated);
  487. template<typename T> static void SliceHelper(JavascriptArray*pArr, JavascriptArray* pNewArr, uint32 start, uint32 newLen);
  488. template<typename T>
  489. static void ShiftHelper(JavascriptArray* pArr, ScriptContext * scriptContext);
  490. template<typename T>
  491. static void UnshiftHelper(JavascriptArray* pArr, uint32 unshiftElements, Js::Var * elements);
  492. static Var UnshiftObjectHelper(Js::Arguments& args, ScriptContext * scriptContext);
  493. template<typename T>
  494. static void GrowArrayHeadHelperForUnshift(JavascriptArray* pArr, uint32 unshiftElements, ScriptContext * scriptContext);
  495. static int64 GetFromLastIndex(Var arg, int64 length, ScriptContext *scriptContext);
  496. static JavascriptString* JoinToString(Var value, ScriptContext* scriptContext);
  497. static JavascriptString* JoinHelper(Var thisArg, JavascriptString* separatorStr, ScriptContext* scriptContext);
  498. template <typename T>
  499. static JavascriptString* JoinArrayHelper(T * arr, JavascriptString* separatorStr, ScriptContext* scriptContext);
  500. static JavascriptString* JoinOtherHelper(RecyclableObject *object, JavascriptString* separatorStr, ScriptContext* scriptContext);
  501. template <bool includesAlgorithm>
  502. static Var IndexOfHelper(Arguments const & args, ScriptContext *scriptContext);
  503. virtual int32 HeadSegmentIndexOfHelper(Var search, uint32 &fromIndex, uint32 toIndex, bool includesAlgorithm, ScriptContext * scriptContext);
  504. template<typename T>
  505. static void ReallocateNonLeafLastSegmentIfLeaf(JavascriptArray * arr, Recycler * recycler);
  506. template<typename T>
  507. static void ArraySpliceHelper(JavascriptArray* pNewArr, JavascriptArray* pArr, uint32 start, uint32 deleteLen,
  508. Var* insertArgs, uint32 insertLen, ScriptContext *scriptContext);
  509. template<typename T>
  510. static void ArraySegmentSpliceHelper(
  511. JavascriptArray *pnewArr, SparseArraySegment<T> *seg, Field(SparseArraySegment<T>*) *prev,
  512. uint32 start, uint32 deleteLen, Var* insertArgs, uint32 insertLen, Recycler *recycler);
  513. template<typename T>
  514. static RecyclableObject* ObjectSpliceHelper(RecyclableObject* pObj, T len, T start, T deleteLen,
  515. Var* insertArgs, uint32 insertLen, ScriptContext *scriptContext, RecyclableObject* pNewObj = nullptr);
  516. static JavascriptString* ToLocaleStringHelper(Var value, ScriptContext* scriptContext);
  517. static Js::JavascriptArray* CreateNewArrayHelper(uint32 len, bool isIntArray, bool isFloatArray, Js::JavascriptArray *baseArray, ScriptContext* scriptContext);
  518. static Var TryArraySplice(JavascriptArray* pArr, uint32 start, uint32 len, uint32 deleteLen,
  519. Var* insertArgs, uint32 insertLen, ScriptContext *scriptContext);
  520. void FillFromPrototypes(uint32 startIndex, uint32 endIndex);
  521. bool IsFillFromPrototypes();
  522. void GetArrayTypeAndConvert(bool* isIntArray, bool* isFloatArray);
  523. template<typename T> void EnsureHeadStartsFromZero(Recycler * recycler);
  524. SparseArraySegmentBase * GetBeginLookupSegment(uint32 index, const bool useSegmentMap = true) const;
  525. SegmentBTreeRoot * BuildSegmentMap();
  526. void InvalidateLastUsedSegment();
  527. inline BOOL IsFullArray() const; // no missing elements till array length
  528. inline BOOL IsSingleSegmentArray() const;
  529. template<typename T> void AllocateHead();
  530. template<typename T> void EnsureHead();
  531. uint32 sort(__inout_ecount(*length) Field(Var) *orig, uint32 *length, ScriptContext *scriptContext);
  532. BOOL GetPropertyBuiltIns(PropertyId propertyId, Var* value);
  533. bool GetSetterBuiltIns(PropertyId propertyId, PropertyValueInfo* info, DescriptorFlags* descriptorFlags);
  534. private:
  535. struct Element
  536. {
  537. Field(Var) Value;
  538. Field(JavascriptString*) StringValue;
  539. };
  540. static int __cdecl CompareElements(void* context, const void* elem1, const void* elem2);
  541. void SortElements(Element* elements, uint32 left, uint32 right);
  542. template <typename Fn>
  543. static void ForEachOwnMissingArrayIndexOfObject(JavascriptArray *baseArr, JavascriptArray *destArray, RecyclableObject* obj, uint32 startIndex, uint32 limitIndex, uint32 destIndex, Fn fn);
  544. // This helper function is mainly used as a precheck before going to the FillFromPrototype code path.
  545. // Proxy and CustomExternalObject in the prototype chain will be returned as if ES5Array is there.
  546. static bool HasAnyES5ArrayInPrototypeChain(JavascriptArray *arr, bool forceCheckProtoChain = false);
  547. // NativeArrays may change it's content type, but not others
  548. template <typename T> static bool MayChangeType() { return false; }
  549. // Like normal VarIs, but will return false for <JavascriptArray> if the array has transitioned to ES5Array type.
  550. template<typename T> static bool VarIsWithoutES5Array(RecyclableObject* object);
  551. template<typename T, typename P>
  552. static BOOL TryTemplatedGetItem(RecyclableObject* arr, P index, Var *element, ScriptContext *scriptContext, bool checkHasItem = true)
  553. {
  554. return VarIsWithoutES5Array<T>(arr) ? JavascriptArray::TemplatedGetItem(static_cast<T*>(arr), index, element, scriptContext, checkHasItem) :
  555. JavascriptOperators::GetItem(arr, index, element, scriptContext);
  556. }
  557. template <bool hasSideEffect, typename T, typename Fn>
  558. static void TemplatedForEachItemInRange(T * arr, uint32 startIndex, uint32 limitIndex, Var missingItem, ScriptContext * scriptContext, Fn fn)
  559. {
  560. for (uint32 i = startIndex; i < limitIndex; i++)
  561. {
  562. Var element;
  563. RecyclableObject* curArr = arr;
  564. fn(i, TryTemplatedGetItem<T>(curArr, i, &element, scriptContext) ? element : missingItem);
  565. if (hasSideEffect && MayChangeType<T>() && !VarIsWithoutES5Array<T>(curArr))
  566. {
  567. // The function has changed, go to another ForEachItemInRange. It is possible that the array might have changed to
  568. // an ES5Array, in such cases we don't need to call the JavascriptArray specific implementation.
  569. if (JavascriptArray::IsNonES5Array(curArr))
  570. {
  571. UnsafeVarTo<JavascriptArray>(curArr)->template ForEachItemInRange<true>(i + 1, limitIndex, missingItem, scriptContext, fn);
  572. return;
  573. }
  574. else
  575. {
  576. AssertOrFailFastMsg(VarIs<ES5Array>(curArr), "The array should have been converted to an ES5Array");
  577. }
  578. }
  579. }
  580. }
  581. template <bool hasSideEffect, typename T, typename P, typename Fn>
  582. static void TemplatedForEachItemInRange(T * arr, P startIndex, P limitIndex, ScriptContext * scriptContext, Fn fn)
  583. {
  584. for (P i = startIndex; i < limitIndex; i++)
  585. {
  586. Var element;
  587. RecyclableObject* curArr = arr;
  588. if (TryTemplatedGetItem<T>(curArr, i, &element, scriptContext))
  589. {
  590. fn(i, element);
  591. if (hasSideEffect && MayChangeType<T>() && !VarIsWithoutES5Array<T>(curArr))
  592. {
  593. // The function has changed, go to another ForEachItemInRange. It is possible that the array might have changed to
  594. // an ES5Array, in such cases we don't need to call the JavascriptArray specific implementation.
  595. if (JavascriptArray::IsNonES5Array(curArr))
  596. {
  597. UnsafeVarTo<JavascriptArray>(curArr)->template ForEachItemInRange<true>(i + 1, limitIndex, scriptContext, fn);
  598. return;
  599. }
  600. else
  601. {
  602. AssertOrFailFastMsg(VarIs<ES5Array>(curArr), "The array should have been converted to an ES5Array");
  603. }
  604. }
  605. }
  606. }
  607. }
  608. public:
  609. template <bool hasSideEffect, typename Fn>
  610. void ForEachItemInRange(uint64 startIndex, uint64 limitIndex, ScriptContext * scriptContext, Fn fn)
  611. {
  612. Assert(false);
  613. Throw::InternalError();
  614. }
  615. template <bool hasSideEffect, typename Fn>
  616. void ForEachItemInRange(uint32 startIndex, uint32 limitIndex, ScriptContext * scriptContext, Fn fn)
  617. {
  618. switch (this->GetTypeId())
  619. {
  620. case TypeIds_Array:
  621. TemplatedForEachItemInRange<hasSideEffect>(this, startIndex, limitIndex, scriptContext, fn);
  622. break;
  623. case TypeIds_NativeIntArray:
  624. TemplatedForEachItemInRange<hasSideEffect>(VarTo<JavascriptNativeIntArray>(this), startIndex, limitIndex, scriptContext, fn);
  625. break;
  626. case TypeIds_NativeFloatArray:
  627. TemplatedForEachItemInRange<hasSideEffect>(VarTo<JavascriptNativeFloatArray>(this), startIndex, limitIndex, scriptContext, fn);
  628. break;
  629. default:
  630. Assert(false);
  631. break;
  632. }
  633. }
  634. template <bool hasSideEffect, typename Fn>
  635. void ForEachItemInRange(uint32 startIndex, uint32 limitIndex, Var missingItem, ScriptContext * scriptContext, Fn fn)
  636. {
  637. switch (this->GetTypeId())
  638. {
  639. case TypeIds_Array:
  640. TemplatedForEachItemInRange<hasSideEffect>(this, startIndex, limitIndex, missingItem, scriptContext, fn);
  641. break;
  642. case TypeIds_NativeIntArray:
  643. TemplatedForEachItemInRange<hasSideEffect>(VarTo<JavascriptNativeIntArray>(this), startIndex, limitIndex, missingItem, scriptContext, fn);
  644. break;
  645. case TypeIds_NativeFloatArray:
  646. TemplatedForEachItemInRange<hasSideEffect>(VarTo<JavascriptNativeFloatArray>(this), startIndex, limitIndex, missingItem, scriptContext, fn);
  647. break;
  648. default:
  649. Assert(false);
  650. break;
  651. }
  652. }
  653. // ArrayElementEnumerator walks an array's segments and enumerates the elements in order.
  654. class ArrayElementEnumerator
  655. {
  656. private:
  657. SparseArraySegmentBase* seg;
  658. uint32 index, endIndex;
  659. const uint32 start, end;
  660. public:
  661. ArrayElementEnumerator(JavascriptArray* arr, uint32 start = 0, uint32 end = MaxArrayLength);
  662. template<typename T> bool MoveNext();
  663. uint32 GetIndex() const;
  664. template<typename T> T GetItem() const;
  665. private:
  666. void Init(JavascriptArray* arr);
  667. };
  668. template <typename T>
  669. class IndexTrace
  670. {
  671. public:
  672. static Var ToNumber(const T& index, ScriptContext* scriptContext);
  673. // index on JavascriptArray
  674. static BOOL GetItem(JavascriptArray* arr, const T& index, Var* outVal);
  675. static BOOL SetItem(JavascriptArray* arr, const T& index, Var newValue);
  676. static void SetItemIfNotExist(JavascriptArray* arr, const T& index, Var newValue);
  677. static BOOL DeleteItem(JavascriptArray* arr, const T& index);
  678. // index on RecyclableObject
  679. static BOOL SetItem(RecyclableObject* obj, const T& index, Var newValue, PropertyOperationFlags flags = PropertyOperation_None);
  680. static BOOL DeleteItem(RecyclableObject* obj, const T& index, PropertyOperationFlags flags = PropertyOperation_None);
  681. };
  682. // BigIndex represents a general index which may grow larger than uint32.
  683. class BigIndex
  684. {
  685. private:
  686. uint32 index;
  687. uint64 bigIndex;
  688. typedef IndexTrace<uint32> small_index;
  689. public:
  690. BigIndex(uint32 initIndex = 0);
  691. BigIndex(uint64 initIndex);
  692. bool IsSmallIndex() const;
  693. bool IsUint32Max() const;
  694. uint32 GetSmallIndex() const;
  695. uint64 GetBigIndex() const;
  696. Var ToNumber(ScriptContext* scriptContext) const;
  697. const BigIndex& operator++();
  698. const BigIndex& operator--();
  699. BigIndex operator+(const BigIndex& delta) const;
  700. BigIndex operator+(uint32 delta) const;
  701. bool operator==(const BigIndex& rhs) const;
  702. bool operator> (const BigIndex& rhs) const;
  703. bool operator< (const BigIndex& rhs) const;
  704. bool operator<=(const BigIndex& rhs) const;
  705. bool operator>=(const BigIndex& rhs) const;
  706. BOOL GetItem(JavascriptArray* arr, Var* outVal) const;
  707. BOOL SetItem(JavascriptArray* arr, Var newValue) const;
  708. void SetItemIfNotExist(JavascriptArray* arr, Var newValue) const;
  709. BOOL DeleteItem(JavascriptArray* arr) const;
  710. BOOL SetItem(RecyclableObject* obj, Var newValue, PropertyOperationFlags flags = PropertyOperation_None) const;
  711. BOOL DeleteItem(RecyclableObject* obj, PropertyOperationFlags flags = PropertyOperation_None) const;
  712. };
  713. void GenericDirectSetItemAt(const BigIndex& index, Var newValue) { index.SetItem(this, newValue); }
  714. void GenericDirectSetItemAt(const uint32 index, Var newValue);
  715. void DirectSetItemIfNotExist(const BigIndex& index, Var newValue) { index.SetItemIfNotExist(this, newValue); }
  716. void DirectAppendItem(Var newValue) { BigIndex(this->GetLength()).SetItem(this, newValue); }
  717. void TruncateToProperties(const BigIndex& index, uint32 start);
  718. static void InternalCopyArrayElements(JavascriptArray* dstArray, uint32 dstIndex, JavascriptArray* srcArray, uint32 start, uint32 end);
  719. static void InternalCopyNativeFloatArrayElements(JavascriptArray* dstArray, const uint32 dstIndex, JavascriptNativeFloatArray* srcArray, uint32 start, uint32 end);
  720. static void InternalCopyNativeIntArrayElements(JavascriptArray* dstArray, uint32 dstIndex, JavascriptNativeIntArray* srcArray, uint32 start, uint32 end);
  721. static void InternalFillFromPrototype(JavascriptArray *dstArray, const uint32 dstIndex, JavascriptArray *srcArray, uint32 start, uint32 end, uint32 count);
  722. static void CopyArrayElements(JavascriptArray* dstArray, uint32 dstIndex, JavascriptArray* srcArray, uint32 start = 0, uint32 end = MaxArrayLength);
  723. template <typename T>
  724. static void CopyAnyArrayElementsToVar(JavascriptArray* dstArray, T dstIndex, JavascriptArray* srcArray, uint32 start = 0, uint32 end = MaxArrayLength);
  725. static bool CopyNativeIntArrayElements(JavascriptNativeIntArray* dstArray, uint32 dstIndex, JavascriptNativeIntArray *srcArray, uint32 start = 0, uint32 end = MaxArrayLength);
  726. static bool CopyNativeIntArrayElementsToFloat(JavascriptNativeFloatArray* dstArray, uint32 dstIndex, JavascriptNativeIntArray *srcArray, uint32 start = 0, uint32 end = MaxArrayLength);
  727. static void CopyNativeIntArrayElementsToVar(JavascriptArray* dstArray, uint32 dstIndex, JavascriptNativeIntArray *srcArray, uint32 start = 0, uint32 end = MaxArrayLength);
  728. static bool CopyNativeFloatArrayElements(JavascriptNativeFloatArray* dstArray, uint32 dstIndex, JavascriptNativeFloatArray *srcArray, uint32 start = 0, uint32 end = MaxArrayLength);
  729. static void CopyNativeFloatArrayElementsToVar(JavascriptArray* dstArray, uint32 dstIndex, JavascriptNativeFloatArray *srcArray, uint32 start = 0, uint32 end = MaxArrayLength);
  730. static bool BoxConcatItem(Var aItem, uint idxArg, ScriptContext *scriptContext);
  731. template<typename T>
  732. static void SetConcatItem(Var aItem, uint idxArg, JavascriptArray* pDestArray, RecyclableObject* pDestObj, T idxDest, ScriptContext *scriptContext);
  733. template<typename T>
  734. static void ConcatArgs(RecyclableObject* pDestObj, TypeId* remoteTypeIds, Js::Arguments& args, ScriptContext* scriptContext, uint start,
  735. BigIndex startIdxDest, ConcatSpreadableState previousItemSpreadableState = ConcatSpreadableState_NotChecked, BigIndex *firstPromotedItemLength = nullptr);
  736. template<typename T>
  737. static void ConcatArgs(RecyclableObject* pDestObj, TypeId* remoteTypeIds, Js::Arguments& args, ScriptContext* scriptContext, uint start = 0, uint startIdxDest = 0u,
  738. ConcatSpreadableState previousItemSpreadableState = ConcatSpreadableState_NotChecked, BigIndex *firstPromotedItemLength = nullptr);
  739. static JavascriptArray* ConcatIntArgs(JavascriptNativeIntArray* pDestArray, TypeId* remoteTypeIds, Js::Arguments& args, ScriptContext* scriptContext);
  740. static bool PromoteToBigIndex(BigIndex lhs, BigIndex rhs);
  741. static bool PromoteToBigIndex(BigIndex lhs, uint32 rhs);
  742. static JavascriptArray* ConcatFloatArgs(JavascriptNativeFloatArray* pDestArray, TypeId* remoteTypeIds, Js::Arguments& args, ScriptContext* scriptContext);
  743. template<typename T=uint32>
  744. static RecyclableObject* ArraySpeciesCreate(Var pThisArray, T length, ScriptContext* scriptContext, bool *pIsIntArray = nullptr, bool *pIsFloatArray = nullptr, bool *pIsBuiltinArrayCtor = nullptr);
  745. static void CreateDataPropertyOrThrow(RecyclableObject * obj, BigIndex index, Var item, ScriptContext * scriptContext);
  746. private:
  747. template <typename T, typename R> static R ConvertToIndex(T idxDest, ScriptContext* scriptContext) { Throw::InternalError(); return 0; }
  748. static BOOL SetArrayLikeObjects(RecyclableObject* pDestObj, uint32 idxDest, Var aItem);
  749. static BOOL SetArrayLikeObjects(RecyclableObject* pDestObj, BigIndex idxDest, Var aItem);
  750. static void ConcatArgsCallingHelper(RecyclableObject* pDestObj, TypeId* remoteTypeIds, Js::Arguments& args, ScriptContext* scriptContext, ::Math::RecordOverflowPolicy &destLengthOverflow);
  751. static void ThrowErrorOnFailure(BOOL succeeded, ScriptContext* scriptContext, uint32 index);
  752. static void ThrowErrorOnFailure(BOOL succeeded, ScriptContext* scriptContext, BigIndex index);
  753. template<typename T>
  754. static void TryGetArrayAndLength(Var arg, ScriptContext *scriptContext, PCWSTR methodName, __out JavascriptArray** array, __out RecyclableObject** obj, __out T * length);
  755. static uint64 OP_GetLength(Var obj, ScriptContext *scriptContext);
  756. public:
  757. template<typename T, typename P = uint32>
  758. static void Unshift(RecyclableObject* obj, const T& toIndex, P start, P end, ScriptContext* scriptContext);
  759. template <typename T>
  760. class ItemTrace
  761. {
  762. public:
  763. static uint32 GetLength(T* obj, ScriptContext* scriptContext);
  764. static BOOL GetItem(T* obj, uint32 index, Var* outVal, ScriptContext* scriptContext);
  765. };
  766. template <typename T>
  767. static JavascriptString* ToLocaleString(T* obj, ScriptContext* scriptContext);
  768. public:
  769. static uint32 GetOffsetOfArrayFlags() { return offsetof(JavascriptArray, arrayFlags); }
  770. static uint32 GetOffsetOfHead() { return offsetof(JavascriptArray, head); }
  771. static uint32 GetOffsetOfLastUsedSegmentOrSegmentMap() { return offsetof(JavascriptArray, segmentUnion.lastUsedSegment); }
  772. static Var SpreadArrayArgs(Var arrayToSpread, const Js::AuxArray<uint32> *spreadIndices, ScriptContext *scriptContext);
  773. static uint32 GetSpreadArgLen(Var spreadArg, ScriptContext *scriptContext);
  774. static JavascriptArray * BoxStackInstance(JavascriptArray * instance, bool deepCopy);
  775. static ArrayObject * DeepCopyInstance(ArrayObject * instance);
  776. protected:
  777. template <typename T> void InitBoxedInlineSegments(T * instance, bool deepCopy);
  778. template <typename T> static T * BoxStackInstance(T * instance, bool deepCopy);
  779. template <typename T> static T * DeepCopyInstance(T * instance);
  780. public:
  781. template<class T, uint InlinePropertySlots> static size_t DetermineAllocationSize(const uint inlineElementSlots, size_t *const allocationPlusSizeRef = nullptr, uint *const alignedInlineElementSlotsRef = nullptr);
  782. template<class ArrayType, uint InlinePropertySlots> static size_t DetermineAllocationSizeForArrayObjects(const uint inlineElementSlots, size_t *const allocationPlusSizeRef = nullptr, uint *const alignedInlineElementSlotsRef = nullptr);
  783. template<class ArrayType> static void EnsureCalculationOfAllocationBuckets();
  784. template<class T, uint InlinePropertySlots> static uint DetermineAvailableInlineElementSlots(const size_t allocationSize, bool *const isSufficientSpaceForInlinePropertySlotsRef);
  785. template<class T, uint ConstInlinePropertySlots, bool UseDynamicInlinePropertySlots> static SparseArraySegment<typename T::TElement> *DetermineInlineHeadSegmentPointer(T *const array);
  786. #if ENABLE_TTD
  787. public:
  788. virtual void MarkVisitKindSpecificPtrs(TTD::SnapshotExtractor* extractor) override;
  789. virtual void ProcessCorePaths() override;
  790. virtual TTD::NSSnapObjects::SnapObjectType GetSnapTag_TTD() const override;
  791. virtual void ExtractSnapObjectDataInto(TTD::NSSnapObjects::SnapObject* objData, TTD::SlabAllocator& alloc) override;
  792. #endif
  793. public:
  794. virtual VTableValue DummyVirtualFunctionToHinderLinkerICF()
  795. {
  796. return VtableHelper();
  797. }
  798. };
  799. template <> inline bool VarIsImpl<JavascriptArray>(RecyclableObject* obj)
  800. {
  801. return DynamicObject::IsAnyArray(obj);
  802. }
  803. template<typename T> bool JavascriptArray::VarIsWithoutES5Array(RecyclableObject* object)
  804. {
  805. return VarIs<T>(object);
  806. }
  807. template <> inline bool JavascriptArray::VarIsWithoutES5Array<RecyclableObject>(RecyclableObject* object)
  808. {
  809. return true;
  810. }
  811. template <> inline bool JavascriptArray::VarIsWithoutES5Array<JavascriptArray>(RecyclableObject* object)
  812. {
  813. return IsNonES5Array(object);
  814. }
  815. // 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
  816. // so we are checking for failure on DeleteProperty/DeleteItem/... etc instead. This helper makes that checking a little less intrusive.
  817. class ThrowTypeErrorOnFailureHelper
  818. {
  819. ScriptContext *m_scriptContext;
  820. PCWSTR m_functionName;
  821. public:
  822. ThrowTypeErrorOnFailureHelper(ScriptContext *scriptContext, PCWSTR functionName) : m_scriptContext(scriptContext), m_functionName(functionName) {}
  823. inline void ThrowTypeErrorOnFailure(BOOL operationSucceeded);
  824. inline void ThrowTypeErrorOnFailure();
  825. inline BOOL IsThrowTypeError(BOOL operationSucceeded);
  826. };
  827. class JavascriptNativeArray : public JavascriptArray
  828. {
  829. friend class JavascriptArray;
  830. protected:
  831. DEFINE_VTABLE_CTOR(JavascriptNativeArray, JavascriptArray);
  832. DEFINE_MARSHAL_OBJECT_TO_SCRIPT_CONTEXT(JavascriptNativeArray);
  833. public:
  834. JavascriptNativeArray(DynamicType * type) :
  835. JavascriptArray(type), weakRefToFuncBody(nullptr)
  836. {
  837. }
  838. protected:
  839. JavascriptNativeArray(uint32 length, DynamicType * type) :
  840. JavascriptArray(length, type), weakRefToFuncBody(nullptr) {}
  841. // For BoxStackInstance
  842. JavascriptNativeArray(JavascriptNativeArray * instance, bool deepCopy);
  843. Field(RecyclerWeakReference<FunctionBody> *) weakRefToFuncBody;
  844. public:
  845. static bool Is(TypeId typeId);
  846. void SetArrayCallSite(ProfileId index, RecyclerWeakReference<FunctionBody> *weakRef)
  847. {
  848. Assert(weakRef);
  849. Assert(!weakRefToFuncBody);
  850. SetArrayCallSiteIndex(index);
  851. weakRefToFuncBody = weakRef;
  852. }
  853. void ClearArrayCallSiteIndex()
  854. {
  855. weakRefToFuncBody = nullptr;
  856. }
  857. #if ENABLE_PROFILE_INFO
  858. ArrayCallSiteInfo *GetArrayCallSiteInfo();
  859. #endif
  860. static uint32 GetOffsetOfArrayCallSiteIndex() { return offsetof(JavascriptNativeArray, arrayCallSiteIndex); }
  861. static uint32 GetOffsetOfWeakFuncRef() { return offsetof(JavascriptNativeArray, weakRefToFuncBody); }
  862. #if ENABLE_PROFILE_INFO
  863. void SetArrayProfileInfo(RecyclerWeakReference<FunctionBody> *weakRef, ArrayCallSiteInfo *arrayInfo);
  864. void CopyArrayProfileInfo(Js::JavascriptNativeArray* baseArray);
  865. #endif
  866. Var FindMinOrMax(Js::ScriptContext * scriptContext, bool findMax);
  867. template<typename T, bool checkNaNAndNegZero> Var FindMinOrMax(Js::ScriptContext * scriptContext, bool findMax); // NativeInt arrays can't have NaNs or -0
  868. static void PopWithNoDst(Var nativeArray);
  869. };
  870. template <> inline bool VarIsImpl<JavascriptNativeArray>(RecyclableObject* obj)
  871. {
  872. return JavascriptNativeArray::Is(JavascriptOperators::GetTypeId(obj));
  873. }
  874. class JavascriptNativeFloatArray;
  875. class JavascriptNativeIntArray : public JavascriptNativeArray
  876. {
  877. friend class JavascriptArray;
  878. public:
  879. static const size_t StackAllocationSize;
  880. protected:
  881. DEFINE_VTABLE_CTOR(JavascriptNativeIntArray, JavascriptNativeArray);
  882. DEFINE_MARSHAL_OBJECT_TO_SCRIPT_CONTEXT(JavascriptNativeIntArray);
  883. public:
  884. JavascriptNativeIntArray(DynamicType * type);
  885. JavascriptNativeIntArray(uint32 length, uint32 size, DynamicType * type);
  886. JavascriptNativeIntArray(DynamicType * type, uint32 size);
  887. protected:
  888. JavascriptNativeIntArray(uint32 length, DynamicType * type) :
  889. JavascriptNativeArray(length, type) {}
  890. // For BoxStackInstance
  891. JavascriptNativeIntArray(JavascriptNativeIntArray * instance, bool boxHead, bool deepCopy);
  892. public:
  893. static Var NewInstance(RecyclableObject* function, CallInfo callInfo, ...);
  894. static Var NewInstance(RecyclableObject* function, Arguments args);
  895. static bool Is(TypeId typeId);
  896. typedef int32 TElement;
  897. static const uint8 AllocationBucketsCount = 3;
  898. static uint allocationBuckets[AllocationBucketsCount][AllocationBucketsInfoSize];
  899. static const int32 MissingItem;
  900. virtual PropertyQueryFlags HasItemQuery(uint32 index) override;
  901. virtual PropertyQueryFlags GetItemQuery(Var originalInstance, uint32 index, Var* value, ScriptContext * requestContext) override;
  902. virtual PropertyQueryFlags GetItemReferenceQuery(Var originalInstance, uint32 index, Var* value, ScriptContext * requestContext) override;
  903. virtual BOOL DirectGetVarItemAt(uint index, Var* outval, ScriptContext *scriptContext);
  904. virtual BOOL DirectGetItemAtFull(uint index, Var* outVal);
  905. virtual Var DirectGetItem(uint32 index);
  906. virtual DescriptorFlags GetItemSetter(uint32 index, Var* setterValue, ScriptContext* requestContext) override;
  907. virtual BOOL SetItem(uint32 index, Var value, PropertyOperationFlags flags) override;
  908. virtual BOOL DeleteItem(uint32 index, PropertyOperationFlags flags) override;
  909. #ifdef VALIDATE_ARRAY
  910. virtual void ValidateArray() override;
  911. #endif
  912. BOOL SetItem(uint32 index, int32 iValue);
  913. static JavascriptNativeFloatArray * ToNativeFloatArray(JavascriptNativeIntArray *intArray);
  914. static JavascriptArray * ToVarArray(JavascriptNativeIntArray *intArray);
  915. static JavascriptArray * ConvertToVarArray(JavascriptNativeIntArray *intArray);
  916. static Var Push(ScriptContext * scriptContext, Var array, int value);
  917. static int32 Pop(ScriptContext * scriptContext, Var nativeIntArray);
  918. #if ENABLE_PROFILE_INFO
  919. virtual JavascriptArray *FillFromArgs(uint length, uint start, Var *args, ArrayCallSiteInfo *info = nullptr, bool dontCreateNewArray = false) override;
  920. #else
  921. virtual JavascriptArray *FillFromArgs(uint length, uint start, Var *args, bool dontCreateNewArray = false) override;
  922. #endif
  923. virtual void ClearElements(SparseArraySegmentBase *seg, uint32 newSegmentLength) override;
  924. virtual void SetIsPrototype() override;
  925. TypeId TrySetNativeIntArrayItem(Var value, int32 *iValue, double *dValue);
  926. virtual bool IsMissingHeadSegmentItem(const uint32 index) const override;
  927. static VTableValue VtableHelper()
  928. {
  929. return VTableValue::VtableNativeIntArray;
  930. }
  931. static LibraryValue InitialTypeHelper()
  932. {
  933. return LibraryValue::ValueNativeIntArrayType;
  934. }
  935. static DynamicType * GetInitialType(ScriptContext * scriptContext);
  936. static JavascriptNativeIntArray * BoxStackInstance(JavascriptNativeIntArray * instance, bool deepCopy);
  937. private:
  938. virtual int32 HeadSegmentIndexOfHelper(Var search, uint32 &fromIndex, uint32 toIndex, bool includesAlgorithm, ScriptContext * scriptContext) override;
  939. #if ENABLE_TTD
  940. public:
  941. virtual void MarkVisitKindSpecificPtrs(TTD::SnapshotExtractor* extractor) override
  942. {
  943. return;
  944. }
  945. virtual void ProcessCorePaths() override
  946. {
  947. return;
  948. }
  949. virtual TTD::NSSnapObjects::SnapObjectType GetSnapTag_TTD() const override;
  950. virtual void ExtractSnapObjectDataInto(TTD::NSSnapObjects::SnapObject* objData, TTD::SlabAllocator& alloc) override;
  951. #endif
  952. public:
  953. virtual VTableValue DummyVirtualFunctionToHinderLinkerICF()
  954. {
  955. return VtableHelper();
  956. }
  957. };
  958. template <> inline bool VarIsImpl<JavascriptNativeIntArray>(RecyclableObject* obj)
  959. {
  960. return JavascriptNativeIntArray::Is(JavascriptOperators::GetTypeId(obj));
  961. }
  962. #if ENABLE_COPYONACCESS_ARRAY
  963. class JavascriptCopyOnAccessNativeIntArray : public JavascriptNativeIntArray
  964. {
  965. friend class JavascriptArray;
  966. public:
  967. static const size_t StackAllocationSize;
  968. protected:
  969. DEFINE_VTABLE_CTOR(JavascriptCopyOnAccessNativeIntArray, JavascriptNativeIntArray);
  970. DEFINE_MARSHAL_OBJECT_TO_SCRIPT_CONTEXT(JavascriptCopyOnAccessNativeIntArray);
  971. public:
  972. JavascriptCopyOnAccessNativeIntArray(uint32 length, DynamicType * type) :
  973. JavascriptNativeIntArray(length, type) {}
  974. virtual BOOL IsCopyOnAccessArray() { return TRUE; }
  975. static DynamicType * GetInitialType(ScriptContext * scriptContext);
  976. void ConvertCopyOnAccessSegment();
  977. uint32 GetNextIndex(uint32 index) const;
  978. BOOL DirectGetItemAt(uint32 index, int* outVal);
  979. static VTableValue VtableHelper()
  980. {
  981. return VTableValue::VtableCopyOnAccessNativeIntArray;
  982. }
  983. #if ENABLE_TTD
  984. public:
  985. virtual void MarkVisitKindSpecificPtrs(TTD::SnapshotExtractor* extractor) override
  986. {
  987. return;
  988. }
  989. virtual void ProcessCorePaths() override
  990. {
  991. return;
  992. }
  993. virtual TTD::NSSnapObjects::SnapObjectType GetSnapTag_TTD() const override;
  994. virtual void ExtractSnapObjectDataInto(TTD::NSSnapObjects::SnapObject* objData, TTD::SlabAllocator& alloc) override;
  995. #endif
  996. public:
  997. virtual VTableValue DummyVirtualFunctionToHinderLinkerICF()
  998. {
  999. return VtableHelper();
  1000. }
  1001. };
  1002. template <> inline bool VarIsImpl<JavascriptCopyOnAccessNativeIntArray>(RecyclableObject* obj)
  1003. {
  1004. return JavascriptOperators::GetTypeId(obj) == TypeIds_CopyOnAccessNativeIntArray;
  1005. }
  1006. #endif
  1007. class JavascriptNativeFloatArray : public JavascriptNativeArray
  1008. {
  1009. friend class JavascriptArray;
  1010. public:
  1011. static const size_t StackAllocationSize;
  1012. protected:
  1013. DEFINE_VTABLE_CTOR(JavascriptNativeFloatArray, JavascriptNativeArray);
  1014. DEFINE_MARSHAL_OBJECT_TO_SCRIPT_CONTEXT(JavascriptNativeFloatArray);
  1015. public:
  1016. JavascriptNativeFloatArray(DynamicType * type);
  1017. JavascriptNativeFloatArray(uint32 length, uint32 size, DynamicType * type);
  1018. JavascriptNativeFloatArray(DynamicType * type, uint32 size);
  1019. private:
  1020. JavascriptNativeFloatArray(uint32 length, DynamicType * type) :
  1021. JavascriptNativeArray(length, type) {}
  1022. // For BoxStackInstance
  1023. JavascriptNativeFloatArray(JavascriptNativeFloatArray * instance, bool boxHead, bool deepCopy);
  1024. public:
  1025. static Var NewInstance(RecyclableObject* function, CallInfo callInfo, ...);
  1026. static Var NewInstance(RecyclableObject* function, Arguments args);
  1027. static bool Is(TypeId typeId);
  1028. typedef double TElement;
  1029. static const uint8 AllocationBucketsCount = 3;
  1030. static uint allocationBuckets[AllocationBucketsCount][AllocationBucketsInfoSize];
  1031. static const double MissingItem;
  1032. virtual PropertyQueryFlags HasItemQuery(uint32 index) override;
  1033. virtual PropertyQueryFlags GetItemQuery(Var originalInstance, uint32 index, Var* value, ScriptContext * requestContext) override;
  1034. virtual PropertyQueryFlags GetItemReferenceQuery(Var originalInstance, uint32 index, Var* value, ScriptContext * requestContext) override;
  1035. virtual BOOL DirectGetVarItemAt(uint index, Var* outval, ScriptContext *scriptContext);
  1036. virtual BOOL DirectGetItemAtFull(uint index, Var* outVal);
  1037. virtual Var DirectGetItem(uint32 index);
  1038. virtual DescriptorFlags GetItemSetter(uint32 index, Var* setterValue, ScriptContext* requestContext) override
  1039. {
  1040. double value = 0;
  1041. return this->DirectGetItemAt(index, &value) ? WritableData : None;
  1042. }
  1043. virtual BOOL SetItem(uint32 index, Var value, PropertyOperationFlags flags) override;
  1044. virtual BOOL DeleteItem(uint32 index, PropertyOperationFlags flags) override;
  1045. #ifdef VALIDATE_ARRAY
  1046. virtual void ValidateArray() override;
  1047. #endif
  1048. BOOL SetItem(uint32 index, double dValue);
  1049. static JavascriptArray * ToVarArray(JavascriptNativeFloatArray *fArray);
  1050. static JavascriptArray * ConvertToVarArray(JavascriptNativeFloatArray *fArray);
  1051. #if ENABLE_PROFILE_INFO
  1052. virtual JavascriptArray *FillFromArgs(uint length, uint start, Var *args, ArrayCallSiteInfo *info = nullptr, bool dontCreateNewArray = false) override;
  1053. #else
  1054. virtual JavascriptArray *FillFromArgs(uint length, uint start, Var *args, bool dontCreateNewArray = false) override;
  1055. #endif
  1056. virtual void ClearElements(SparseArraySegmentBase *seg, uint32 newSegmentLength) override;
  1057. virtual void SetIsPrototype() override;
  1058. TypeId TrySetNativeFloatArrayItem(Var value, double *dValue);
  1059. virtual bool IsMissingHeadSegmentItem(const uint32 index) const override;
  1060. static VTableValue VtableHelper()
  1061. {
  1062. return VTableValue::VtableNativeFloatArray;
  1063. }
  1064. static LibraryValue InitialTypeHelper()
  1065. {
  1066. return LibraryValue::ValueNativeFloatArrayType;
  1067. }
  1068. static DynamicType * GetInitialType(ScriptContext * scriptContext);
  1069. static Var Push(ScriptContext * scriptContext, Var nativeFloatArray, double value);
  1070. static JavascriptNativeFloatArray * BoxStackInstance(JavascriptNativeFloatArray * instance, bool deepCopy);
  1071. static double Pop(ScriptContext * scriptContext, Var nativeFloatArray);
  1072. private:
  1073. virtual int32 HeadSegmentIndexOfHelper(Var search, uint32 &fromIndex, uint32 toIndex, bool includesAlgorithm, ScriptContext * scriptContext) override;
  1074. #if ENABLE_TTD
  1075. public:
  1076. virtual void MarkVisitKindSpecificPtrs(TTD::SnapshotExtractor* extractor) override
  1077. {
  1078. return;
  1079. }
  1080. virtual void ProcessCorePaths() override
  1081. {
  1082. return;
  1083. }
  1084. virtual TTD::NSSnapObjects::SnapObjectType GetSnapTag_TTD() const override;
  1085. virtual void ExtractSnapObjectDataInto(TTD::NSSnapObjects::SnapObject* objData, TTD::SlabAllocator& alloc) override;
  1086. #endif
  1087. public:
  1088. virtual VTableValue DummyVirtualFunctionToHinderLinkerICF()
  1089. {
  1090. return VtableHelper();
  1091. }
  1092. };
  1093. template <> inline bool VarIsImpl<JavascriptNativeFloatArray>(RecyclableObject* obj)
  1094. {
  1095. return JavascriptNativeFloatArray::Is(JavascriptOperators::GetTypeId(obj));
  1096. }
  1097. template <>
  1098. inline bool JavascriptArray::MayChangeType<JavascriptNativeIntArray>() { return true; }
  1099. template <>
  1100. inline bool JavascriptArray::MayChangeType<JavascriptNativeFloatArray>() { return true; }
  1101. template <>
  1102. inline uint32 JavascriptArray::ConvertToIndex<uint32, uint32>(uint32 idxDest, ScriptContext* scriptContext) { return idxDest; }
  1103. } // namespace Js