14514f5e3Sopenharmony_ci/* 24514f5e3Sopenharmony_ci * Copyright (c) 2021-2024 Huawei Device Co., Ltd. 34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License. 54514f5e3Sopenharmony_ci * You may obtain a copy of the License at 64514f5e3Sopenharmony_ci * 74514f5e3Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 84514f5e3Sopenharmony_ci * 94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and 134514f5e3Sopenharmony_ci * limitations under the License. 144514f5e3Sopenharmony_ci */ 154514f5e3Sopenharmony_ci 164514f5e3Sopenharmony_ci#ifndef ECMASCRIPT_JSARRAY_H 174514f5e3Sopenharmony_ci#define ECMASCRIPT_JSARRAY_H 184514f5e3Sopenharmony_ci 194514f5e3Sopenharmony_ci#include "ecmascript/js_object.h" 204514f5e3Sopenharmony_ci#include "ecmascript/js_tagged_value-inl.h" 214514f5e3Sopenharmony_ci#include "ecmascript/js_tagged_value.h" 224514f5e3Sopenharmony_ci#include "ecmascript/js_thread.h" 234514f5e3Sopenharmony_ci#include "ecmascript/tagged_array.h" 244514f5e3Sopenharmony_ci 254514f5e3Sopenharmony_cinamespace panda::ecmascript { 264514f5e3Sopenharmony_cienum class ArrayMode : uint8_t { UNDEFINED = 0, DICTIONARY, LITERAL }; 274514f5e3Sopenharmony_ci// ecma6 9.4.2 Array Exotic Object 284514f5e3Sopenharmony_ciclass JSArray : public JSObject { 294514f5e3Sopenharmony_cipublic: 304514f5e3Sopenharmony_ci static constexpr int LENGTH_INLINE_PROPERTY_INDEX = 0; 314514f5e3Sopenharmony_ci 324514f5e3Sopenharmony_ci CAST_CHECK(JSArray, IsJSArray); 334514f5e3Sopenharmony_ci 344514f5e3Sopenharmony_ci static PUBLIC_API JSHandle<JSTaggedValue> ArrayCreate(JSThread *thread, JSTaggedNumber length, 354514f5e3Sopenharmony_ci ArrayMode mode = ArrayMode::UNDEFINED); 364514f5e3Sopenharmony_ci static JSHandle<JSTaggedValue> ArrayCreate(JSThread *thread, JSTaggedNumber length, 374514f5e3Sopenharmony_ci const JSHandle<JSTaggedValue> &newTarget, 384514f5e3Sopenharmony_ci ArrayMode mode = ArrayMode::UNDEFINED); 394514f5e3Sopenharmony_ci static JSTaggedValue ArraySpeciesCreate(JSThread *thread, const JSHandle<JSObject> &originalArray, 404514f5e3Sopenharmony_ci JSTaggedNumber length); 414514f5e3Sopenharmony_ci static bool ArraySetLength(JSThread *thread, const JSHandle<JSObject> &array, const PropertyDescriptor &desc); 424514f5e3Sopenharmony_ci static bool DefineOwnProperty(JSThread *thread, const JSHandle<JSObject> &array, const JSHandle<JSTaggedValue> &key, 434514f5e3Sopenharmony_ci const PropertyDescriptor &desc); 444514f5e3Sopenharmony_ci static bool DefineOwnProperty(JSThread *thread, const JSHandle<JSObject> &array, uint32_t index, 454514f5e3Sopenharmony_ci const PropertyDescriptor &desc); 464514f5e3Sopenharmony_ci 474514f5e3Sopenharmony_ci static bool IsLengthString(JSThread *thread, const JSHandle<JSTaggedValue> &key); 484514f5e3Sopenharmony_ci // ecma6 7.3 Operations on Objects 494514f5e3Sopenharmony_ci static JSHandle<JSArray> CreateArrayFromList(JSThread *thread, const JSHandle<TaggedArray> &elements); 504514f5e3Sopenharmony_ci static JSHandle<JSArray> CreateArrayFromList(JSThread *thread, const JSHandle<JSTaggedValue> &newtarget, 514514f5e3Sopenharmony_ci const JSHandle<TaggedArray> &elements); 524514f5e3Sopenharmony_ci // use first inlined property slot for array length 534514f5e3Sopenharmony_ci inline uint32_t GetArrayLength() const 544514f5e3Sopenharmony_ci { 554514f5e3Sopenharmony_ci return GetLength(); 564514f5e3Sopenharmony_ci } 574514f5e3Sopenharmony_ci 584514f5e3Sopenharmony_ci inline void SetArrayLength([[maybe_unused]]const JSThread *thread, uint32_t length) 594514f5e3Sopenharmony_ci { 604514f5e3Sopenharmony_ci SetLength(length); 614514f5e3Sopenharmony_ci } 624514f5e3Sopenharmony_ci 634514f5e3Sopenharmony_ci inline uint32_t GetHintLength() const 644514f5e3Sopenharmony_ci { 654514f5e3Sopenharmony_ci auto trackInfo = GetTrackInfo(); 664514f5e3Sopenharmony_ci if (trackInfo.IsInt()) { 674514f5e3Sopenharmony_ci int hint = trackInfo.GetInt(); 684514f5e3Sopenharmony_ci return hint > 0 ? hint : 0; 694514f5e3Sopenharmony_ci } 704514f5e3Sopenharmony_ci return 0; 714514f5e3Sopenharmony_ci } 724514f5e3Sopenharmony_ci 734514f5e3Sopenharmony_ci static constexpr size_t LENGTH_OFFSET = JSObject::SIZE; 744514f5e3Sopenharmony_ci ACCESSORS_PRIMITIVE_FIELD(Length, uint32_t, LENGTH_OFFSET, TRACE_INDEX_OFFSET) 754514f5e3Sopenharmony_ci ACCESSORS_PRIMITIVE_FIELD(TraceIndex, uint32_t, TRACE_INDEX_OFFSET, TRACK_INFO_OFFSET) 764514f5e3Sopenharmony_ci ACCESSORS(TrackInfo, TRACK_INFO_OFFSET, SIZE) 774514f5e3Sopenharmony_ci 784514f5e3Sopenharmony_ci DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSObject, TRACK_INFO_OFFSET, SIZE) 794514f5e3Sopenharmony_ci 804514f5e3Sopenharmony_ci static const uint32_t MAX_ARRAY_INDEX = MAX_ELEMENT_INDEX; 814514f5e3Sopenharmony_ci DECL_DUMP() 824514f5e3Sopenharmony_ci 834514f5e3Sopenharmony_ci static int32_t GetArrayLengthOffset() 844514f5e3Sopenharmony_ci { 854514f5e3Sopenharmony_ci return LENGTH_OFFSET; 864514f5e3Sopenharmony_ci } 874514f5e3Sopenharmony_ci 884514f5e3Sopenharmony_ci static bool PropertyKeyToArrayIndex(JSThread *thread, const JSHandle<JSTaggedValue> &key, uint32_t *output); 894514f5e3Sopenharmony_ci 904514f5e3Sopenharmony_ci static JSTaggedValue LengthGetter(JSThread *thread, const JSHandle<JSObject> &self); 914514f5e3Sopenharmony_ci 924514f5e3Sopenharmony_ci static bool LengthSetter(JSThread *thread, const JSHandle<JSObject> &self, const JSHandle<JSTaggedValue> &value, 934514f5e3Sopenharmony_ci bool mayThrow = false); 944514f5e3Sopenharmony_ci 954514f5e3Sopenharmony_ci static JSHandle<JSTaggedValue> FastGetPropertyByValue(JSThread *thread, const JSHandle<JSTaggedValue> &obj, 964514f5e3Sopenharmony_ci uint32_t index); 974514f5e3Sopenharmony_ci 984514f5e3Sopenharmony_ci static JSHandle<JSTaggedValue> FastGetPropertyByValue(JSThread *thread, const JSHandle<JSTaggedValue> &obj, 994514f5e3Sopenharmony_ci const JSHandle<JSTaggedValue> &key); 1004514f5e3Sopenharmony_ci 1014514f5e3Sopenharmony_ci static bool FastSetPropertyByValue(JSThread *thread, const JSHandle<JSTaggedValue> &obj, uint32_t index, 1024514f5e3Sopenharmony_ci const JSHandle<JSTaggedValue> &value); 1034514f5e3Sopenharmony_ci 1044514f5e3Sopenharmony_ci static bool FastSetPropertyByValue(JSThread *thread, const JSHandle<JSTaggedValue> &obj, 1054514f5e3Sopenharmony_ci const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value); 1064514f5e3Sopenharmony_ci 1074514f5e3Sopenharmony_ci static bool TryFastCreateDataProperty(JSThread *thread, const JSHandle<JSObject> &obj, uint32_t index, 1084514f5e3Sopenharmony_ci const JSHandle<JSTaggedValue> &value, 1094514f5e3Sopenharmony_ci SCheckMode sCheckMode = SCheckMode::CHECK); 1104514f5e3Sopenharmony_ci 1114514f5e3Sopenharmony_ci static JSTaggedValue Sort(JSThread *thread, const JSHandle<JSTaggedValue> &obj, const JSHandle<JSTaggedValue> &fn); 1124514f5e3Sopenharmony_ci static bool IncludeInSortedValue(JSThread *thread, const JSHandle<JSTaggedValue> &obj, 1134514f5e3Sopenharmony_ci const JSHandle<JSTaggedValue> &value); 1144514f5e3Sopenharmony_ci static JSHandle<TaggedArray> ToTaggedArray(JSThread *thread, const JSHandle<JSTaggedValue> &obj); 1154514f5e3Sopenharmony_ci static void PUBLIC_API CheckAndCopyArray(const JSThread *thread, JSHandle<JSArray> obj); 1164514f5e3Sopenharmony_ci static void SetCapacity(JSThread *thread, const JSHandle<JSObject> &array, uint32_t oldLen, uint32_t newLen, 1174514f5e3Sopenharmony_ci bool isNew = false); 1184514f5e3Sopenharmony_ci static void SortElements(JSThread *thread, const JSHandle<TaggedArray> &elements, 1194514f5e3Sopenharmony_ci const JSHandle<JSTaggedValue> &fn); 1204514f5e3Sopenharmony_ci static void SortElementsByObject(JSThread *thread, const JSHandle<JSObject> &thisObjHandle, 1214514f5e3Sopenharmony_ci const JSHandle<JSTaggedValue> &fn); 1224514f5e3Sopenharmony_ci static void SortElementsByInsertionSort(JSThread *thread, const JSHandle<TaggedArray> &elements, uint32_t len, 1234514f5e3Sopenharmony_ci const JSHandle<JSTaggedValue> &fn); 1244514f5e3Sopenharmony_ci static void SortElementsByMergeSort(JSThread *thread, const JSHandle<TaggedArray> &elements, 1254514f5e3Sopenharmony_ci const JSHandle<JSTaggedValue> &fn, int64_t startIdx, int64_t endIdx); 1264514f5e3Sopenharmony_ci static void MergeSortedElements(JSThread *thread, const JSHandle<TaggedArray> &elements, 1274514f5e3Sopenharmony_ci const JSHandle<JSTaggedValue> &fn, int64_t startIdx, int64_t middleIdx, int64_t endIdx); 1284514f5e3Sopenharmony_ci 1294514f5e3Sopenharmony_ci template <class Callback> 1304514f5e3Sopenharmony_ci static JSTaggedValue ArrayCreateWithInit(JSThread *thread, uint32_t length, const Callback &cb) 1314514f5e3Sopenharmony_ci { 1324514f5e3Sopenharmony_ci ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 1334514f5e3Sopenharmony_ci JSHandle<TaggedArray> newElements(factory->NewTaggedArray(length)); 1344514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1354514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> array(JSArray::CreateArrayFromList(thread, newElements)); 1364514f5e3Sopenharmony_ci cb(newElements, length); 1374514f5e3Sopenharmony_ci return array.GetTaggedValue(); 1384514f5e3Sopenharmony_ci } 1394514f5e3Sopenharmony_ci}; 1404514f5e3Sopenharmony_ci 1414514f5e3Sopenharmony_ciclass TrackInfo : public TaggedObject { 1424514f5e3Sopenharmony_cipublic: 1434514f5e3Sopenharmony_ci static TrackInfo *Cast(TaggedObject *object) 1444514f5e3Sopenharmony_ci { 1454514f5e3Sopenharmony_ci ASSERT(JSTaggedValue(object).IsTrackInfoObject()); 1464514f5e3Sopenharmony_ci return static_cast<TrackInfo *>(object); 1474514f5e3Sopenharmony_ci } 1484514f5e3Sopenharmony_ci 1494514f5e3Sopenharmony_ci static constexpr size_t CACHED_HCLASS_OFFSET = TaggedObjectSize(); 1504514f5e3Sopenharmony_ci ACCESSORS(CachedHClass, CACHED_HCLASS_OFFSET, CACHED_FUNC_OFFSET); 1514514f5e3Sopenharmony_ci ACCESSORS(CachedFunc, CACHED_FUNC_OFFSET, BIT_FIELD_OFFSET); 1524514f5e3Sopenharmony_ci ACCESSORS_BIT_FIELD(BitField, BIT_FIELD_OFFSET, ARRAY_LENGTH_OFFSET); 1534514f5e3Sopenharmony_ci ACCESSORS_PRIMITIVE_FIELD(ArrayLength, uint32_t, ARRAY_LENGTH_OFFSET, LAST_OFFSET) 1544514f5e3Sopenharmony_ci DEFINE_ALIGN_SIZE(LAST_OFFSET); 1554514f5e3Sopenharmony_ci 1564514f5e3Sopenharmony_ci // define BitField 1574514f5e3Sopenharmony_ci static constexpr size_t ELEMENTS_KIND_BITS = 8; 1584514f5e3Sopenharmony_ci static constexpr size_t SPACE_FALG_BITS = 8; 1594514f5e3Sopenharmony_ci FIRST_BIT_FIELD(BitField, ElementsKind, ElementsKind, ELEMENTS_KIND_BITS); 1604514f5e3Sopenharmony_ci NEXT_BIT_FIELD(BitField, SpaceFlag, RegionSpaceFlag, SPACE_FALG_BITS, ElementsKind); 1614514f5e3Sopenharmony_ci 1624514f5e3Sopenharmony_ci DECL_DUMP() 1634514f5e3Sopenharmony_ci 1644514f5e3Sopenharmony_ci DECL_VISIT_OBJECT(CACHED_HCLASS_OFFSET, BIT_FIELD_OFFSET); 1654514f5e3Sopenharmony_ci}; 1664514f5e3Sopenharmony_ci} // namespace panda::ecmascript 1674514f5e3Sopenharmony_ci 1684514f5e3Sopenharmony_ci#endif // ECMASCRIPT_JSARRAY_H 169