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