1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef ECMASCRIPT_SHARED_OBJECTS_JS_SHARED_ARRAY_H
17 #define ECMASCRIPT_SHARED_OBJECTS_JS_SHARED_ARRAY_H
18 
19 #include "ecmascript/js_array.h"
20 #include "ecmascript/js_object.h"
21 #include "ecmascript/js_tagged_value.h"
22 #include "ecmascript/tagged_array.h"
23 
24 namespace panda::ecmascript {
25 // enum class ArrayMode : uint8_t { UNDEFINED = 0, DICTIONARY, LITERAL };
26 // ecma6 9.4.2 Array Exotic Object
27 class JSSharedArray : public JSObject {
28 public:
29     static constexpr int LENGTH_INLINE_PROPERTY_INDEX = 0;
30 
31     CAST_CHECK(JSSharedArray, IsJSSharedArray);
32 
33     static PUBLIC_API JSHandle<JSTaggedValue> ArrayCreate(JSThread *thread, JSTaggedNumber length,
34                                                           ArrayMode mode = ArrayMode::UNDEFINED);
35     static JSHandle<JSTaggedValue> ArrayCreate(JSThread *thread, JSTaggedNumber length,
36                                                const JSHandle<JSTaggedValue> &newTarget,
37                                                ArrayMode mode = ArrayMode::UNDEFINED);
38     static JSTaggedValue ArraySpeciesCreate(JSThread *thread, const JSHandle<JSObject> &originalArray,
39                                             JSTaggedNumber length);
40     static bool ArraySetLength(JSThread *thread, const JSHandle<JSObject> &array, const PropertyDescriptor &desc);
41     static bool DefineOwnProperty(JSThread *thread, const JSHandle<JSObject> &array, const JSHandle<JSTaggedValue> &key,
42                                   const PropertyDescriptor &desc, SCheckMode sCheckMode = SCheckMode::CHECK);
43     static bool DefineOwnProperty(JSThread *thread, const JSHandle<JSObject> &array, uint32_t index,
44                                   const PropertyDescriptor &desc, SCheckMode sCheckMode = SCheckMode::CHECK);
45 
46     static bool IsLengthString(JSThread *thread, const JSHandle<JSTaggedValue> &key);
47     static JSHandle<JSSharedArray> CreateArrayFromList(JSThread *thread, const JSHandle<TaggedArray> &elements);
48     // use first inlined property slot for array length
GetArrayLength() const49     inline uint32_t GetArrayLength() const
50     {
51         return GetLength();
52     }
53 
SetArrayLength([[maybe_unused]]const JSThread *thread, uint32_t length)54     inline void SetArrayLength([[maybe_unused]]const JSThread *thread, uint32_t length)
55     {
56         SetLength(length);
57     }
58 
GetHintLength() const59     inline uint32_t GetHintLength() const
60     {
61         auto trackInfo = GetTrackInfo();
62         if (trackInfo.IsInt()) {
63             int hint = trackInfo.GetInt();
64             return hint > 0 ? hint : 0;
65         }
66         return 0;
67     }
68 
IsKeyInRange(uint32_t index)69     inline bool IsKeyInRange(uint32_t index)
70     {
71         return index < GetArrayLength();
72     }
73 
IsKeyInRange(const JSHandle<JSTaggedValue> &key)74     inline bool IsKeyInRange(const JSHandle<JSTaggedValue> &key)
75     {
76         uint32_t keyValue = 0;
77         if (key->IsInt()) {
78             keyValue = static_cast<uint32_t>(key->GetInt());
79         }
80 
81         if (key->IsString()) {
82             JSTaggedValue::ToElementIndex(key.GetTaggedValue(), &keyValue);
83         }
84 
85         if (key->IsDouble()) {
86             double number = key->GetDouble();
87             if (number >= 0 && number < JSObject::MAX_ELEMENT_INDEX) {
88                 auto integer = static_cast<uint32_t>(number);
89                 if (integer == number) {
90                     keyValue = static_cast<uint32_t>(number);
91                 }
92             }
93         }
94 
95         return IsKeyInRange(keyValue);
96     }
97 
98     static constexpr size_t LENGTH_OFFSET = JSObject::SIZE;
99     ACCESSORS_SYNCHRONIZED_PRIMITIVE_FIELD(Length, uint32_t, LENGTH_OFFSET, TRACE_INDEX_OFFSET)
100     ACCESSORS_SYNCHRONIZED_PRIMITIVE_FIELD(TraceIndex, uint32_t, TRACE_INDEX_OFFSET, TRACK_INFO_OFFSET)
101     ACCESSORS_SYNCHRONIZED(TrackInfo, TRACK_INFO_OFFSET, MOD_RECORD_OFFSET)
102     ACCESSORS_SYNCHRONIZED_PRIMITIVE_FIELD(ModRecord, uint32_t, MOD_RECORD_OFFSET, LAST_OFFSET)
103     DEFINE_ALIGN_SIZE(LAST_OFFSET);
104 
105     static constexpr uint32_t MAX_INLINE = PropertyAttributes::MAX_FAST_PROPS_CAPACITY -
106         SIZE / JSTaggedValue::TaggedTypeSize() + 1;
107     DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSObject, TRACK_INFO_OFFSET, MOD_RECORD_OFFSET)
108 
109     static const uint32_t MAX_ARRAY_INDEX = MAX_ELEMENT_INDEX;
110     DECL_DUMP()
111 
GetArrayLengthOffset()112     static int32_t GetArrayLengthOffset()
113     {
114         return LENGTH_OFFSET;
115     }
116 
117     static bool PropertyKeyToArrayIndex(JSThread *thread, const JSHandle<JSTaggedValue> &key, uint32_t *output);
118 
119     static JSTaggedValue LengthGetter(JSThread *thread, const JSHandle<JSObject> &self,
120                                       SCheckMode mode = SCheckMode::CHECK);
121 
122     static bool LengthSetter(JSThread *thread, const JSHandle<JSObject> &self, const JSHandle<JSTaggedValue> &value,
123                              bool mayThrow = false);
124     static bool DummyLengthSetter(JSThread *thread, const JSHandle<JSObject> &self,
125                                   const JSHandle<JSTaggedValue> &value, bool mayThrow = false);
126 
127     static JSHandle<JSTaggedValue> FastGetPropertyByValue(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
128                                                           uint32_t index);
129 
130     static JSHandle<JSTaggedValue> FastGetPropertyByValue(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
131                                                           const JSHandle<JSTaggedValue> &key,
132                                                           SCheckMode sCheckMode = SCheckMode::SKIP);
133 
134     static bool FastSetPropertyByValue(JSThread *thread, const JSHandle<JSTaggedValue> &obj, uint32_t index,
135                                        const JSHandle<JSTaggedValue> &value);
136 
137     static bool FastSetPropertyByValue(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
138                                        const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value);
139 
140     static OperationResult GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
141                                       const JSHandle<JSTaggedValue> &key, SCheckMode sCheckMode);
142     static bool SetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, const JSHandle<JSTaggedValue> &key,
143                            const JSHandle<JSTaggedValue> &value, bool mayThrow, SCheckMode sCheckMode);
144     static bool SetProperty(JSThread *thread,
145                             const JSHandle<JSTaggedValue> &obj,
146                             uint32_t index,
147                             const JSHandle<JSTaggedValue> &value,
148                             bool mayThrow,
149                             SCheckMode sCheckMode);
150 
151     static JSTaggedValue Sort(JSThread *thread, const JSHandle<JSTaggedValue> &obj, const JSHandle<JSTaggedValue> &fn);
152     static bool IncludeInSortedValue(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
153                                      const JSHandle<JSTaggedValue> &value);
154     static JSHandle<TaggedArray> ToTaggedArray(JSThread *thread, const JSHandle<JSTaggedValue> &obj);
155     static void PUBLIC_API CheckAndCopyArray(const JSThread *thread, JSHandle<JSSharedArray> obj);
156     static JSHandle<TaggedArray> SetCapacity(const JSThread *thread, const JSHandle<TaggedArray> &array,
157                                              uint32_t capa);
158     static void SetCapacity(JSThread *thread, const JSHandle<JSObject> &array, uint32_t oldLen, uint32_t newLen,
159                             bool isNew = false);
160     static void SortElements(JSThread *thread, const JSHandle<TaggedArray> &elements,
161                              const JSHandle<JSTaggedValue> &fn);
162     static void SortElementsByObject(JSThread *thread, const JSHandle<JSObject> &thisObjHandle,
163                                      const JSHandle<JSTaggedValue> &fn);
164 
165     static void DeleteInElementMode(const JSThread *thread, JSHandle<JSSharedArray> &obj);
166 };
167 }  // namespace panda::ecmascript
168 
169 #endif  // ECMASCRIPT_SHARED_OBJECTS_JS_SHARED_ARRAY_H
170