• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-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 #include "ecmascript/js_api/js_api_plain_array.h"
17 
18 #include "ecmascript/containers/containers_errors.h"
19 #include "ecmascript/interpreter/interpreter.h"
20 #include "ecmascript/js_function.h"
21 #include <codecvt>
22 
23 namespace panda::ecmascript {
24 using ContainerError = containers::ContainerError;
25 using ErrorFlag = containers::ErrorFlag;
Add(JSThread * thread,const JSHandle<JSAPIPlainArray> & obj,JSHandle<JSTaggedValue> key,JSHandle<JSTaggedValue> value)26 void JSAPIPlainArray::Add(JSThread *thread, const JSHandle<JSAPIPlainArray> &obj, JSHandle<JSTaggedValue> key,
27                           JSHandle<JSTaggedValue> value)
28 {
29     JSHandle<TaggedArray> keyArray(thread, obj->GetKeys(thread));
30     JSHandle<TaggedArray> valueArray(thread, obj->GetValues(thread));
31     uint32_t size = obj->GetLength();
32     int32_t index = obj->BinarySearch(thread, *keyArray, 0, size, key.GetTaggedValue().GetNumber());
33     if (index >= 0) {
34         keyArray->Set(thread, index, key);
35         valueArray->Set(thread, index, value);
36         return;
37     }
38     index ^= 0xFFFFFFFF;
39     if (index < static_cast<int32_t>(size)) {
40         obj->AdjustArray(thread, *keyArray, index, size, true);
41         obj->AdjustArray(thread, *valueArray, index, size, true);
42     }
43     uint32_t capacity = valueArray->GetLength();
44     if (size + 1 >= capacity) {
45         uint32_t newCapacity = capacity << 1U;
46         keyArray =
47             thread->GetEcmaVM()->GetFactory()->CopyArray(keyArray, capacity, newCapacity);
48         valueArray =
49             thread->GetEcmaVM()->GetFactory()->CopyArray(valueArray, capacity, newCapacity);
50         obj->SetKeys(thread, keyArray);
51         obj->SetValues(thread, valueArray);
52     }
53     keyArray->Set(thread, index, key);
54     valueArray->Set(thread, index, value);
55     size++;
56     obj->SetLength(size);
57 }
58 
CreateSlot(const JSThread * thread,const uint32_t capacity)59 JSHandle<TaggedArray> JSAPIPlainArray::CreateSlot(const JSThread *thread, const uint32_t capacity)
60 {
61     ASSERT_PRINT(capacity > 0, "size must be a non-negative integer");
62     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
63     JSHandle<TaggedArray> taggedArray = factory->NewTaggedArray(capacity, JSTaggedValue::Hole());
64     return taggedArray;
65 }
66 
AdjustForward(JSThread * thread,int32_t index,int32_t forwardSize)67 bool JSAPIPlainArray::AdjustForward(JSThread *thread, int32_t index, int32_t forwardSize)
68 {
69     uint32_t size = GetLength();
70     TaggedArray *keys = TaggedArray::Cast(GetKeys(thread).GetTaggedObject());
71     TaggedArray *values = TaggedArray::Cast(GetValues(thread).GetTaggedObject());
72     AdjustPrimitiveArray(keys, index + forwardSize, index);
73     AdjustArray(thread, values, index + forwardSize, index, false);
74     size = size - static_cast<uint32_t>(forwardSize);
75     SetLength(size);
76     return true;
77 }
78 
AdjustPrimitiveArray(TaggedArray * srcArray,int32_t fromIndex,int32_t toIndex)79 void JSAPIPlainArray::AdjustPrimitiveArray(TaggedArray *srcArray, int32_t fromIndex, int32_t toIndex)
80 {
81     uint32_t size = GetLength();
82     auto srcPtr = reinterpret_cast<JSTaggedType *>(
83                             ToUintPtr(srcArray->GetData()) + fromIndex * JSTaggedValue::TaggedTypeSize());
84     auto dstPtr = reinterpret_cast<JSTaggedType *>(
85                             ToUintPtr(srcArray->GetData()) + toIndex * JSTaggedValue::TaggedTypeSize());
86     // move Array element from srcPtr to dstPtr
87     for (uint32_t count = size - fromIndex; count > 0; --count) {
88         *dstPtr = *srcPtr;
89         ++srcPtr;
90         ++dstPtr;
91     }
92     for (uint32_t count = fromIndex - toIndex; count > 0; --count) {
93         *dstPtr = JSTaggedValue::Hole().GetRawData();
94         ++dstPtr;
95     }
96 }
97 
AdjustArray(JSThread * thread,TaggedArray * srcArray,int32_t fromIndex,int32_t toIndex,bool direction)98 void JSAPIPlainArray::AdjustArray(JSThread *thread, TaggedArray *srcArray, int32_t fromIndex,
99                                   int32_t toIndex, bool direction)
100 {
101     uint32_t size = GetLength();
102     ASSERT(size > 0);
103     uint32_t idx = size - 1;
104     if (direction) {
105         while (fromIndex < toIndex) {
106             JSTaggedValue value = srcArray->Get(thread, idx);
107             srcArray->Set(thread, idx + 1, value);
108             idx--;
109             fromIndex++;
110         }
111     } else {
112         if (srcArray->IsYoungAndNotMarking(thread)) {
113             AdjustPrimitiveArray(srcArray, fromIndex, toIndex);
114         } else {
115             auto srcPtr = reinterpret_cast<JSTaggedType *>(
116                                     ToUintPtr(srcArray->GetData()) + fromIndex * JSTaggedValue::TaggedTypeSize());
117             uint32_t dstIndex = toIndex;
118             for (uint32_t count = size - fromIndex; count > 0; --count) {
119                 srcArray->Set(thread, dstIndex, JSTaggedValue(*srcPtr));
120                 ++srcPtr;
121                 ++dstIndex;
122             }
123             for (uint32_t count = fromIndex - toIndex; count > 0; --count) {
124                 srcArray->Set(thread, dstIndex, JSTaggedValue::Hole());
125                 ++dstIndex;
126             }
127         }
128     }
129 }
130 
BinarySearch(JSThread * thread,TaggedArray * array,int32_t fromIndex,int32_t toIndex,int32_t key)131 int32_t JSAPIPlainArray::BinarySearch(JSThread *thread, TaggedArray *array, int32_t fromIndex, int32_t toIndex,
132                                       int32_t key)
133 {
134     int32_t low = fromIndex;
135     int32_t high = toIndex - 1;
136     while (low <= high) {
137         int32_t mid = static_cast<int32_t>(static_cast<uint32_t>(low + high) >> 1U);
138         int32_t midVal = static_cast<int32_t>(array->Get(thread, mid).GetNumber());
139         if (midVal < key) {
140             low = mid + 1;
141         } else {
142             if (midVal <= key) {
143                 return mid;
144             }
145             high = mid - 1;
146         }
147     }
148     return -(low + 1);
149 }
150 
Clear(JSThread * thread)151 void JSAPIPlainArray::Clear(JSThread *thread)
152 {
153     TaggedArray *keys = TaggedArray::Cast(GetKeys(thread).GetTaggedObject());
154     TaggedArray *values = TaggedArray::Cast(GetValues(thread).GetTaggedObject());
155     uint32_t size = GetLength();
156     for (uint32_t index = 0; index < size; index++) {
157         keys->Set(thread, index, JSTaggedValue::Hole());
158         values->Set(thread, index, JSTaggedValue::Hole());
159     }
160     SetLength(0);
161 }
162 
RemoveRangeFrom(JSThread * thread,int32_t index,int32_t batchSize)163 JSTaggedValue JSAPIPlainArray::RemoveRangeFrom(JSThread *thread, int32_t index, int32_t batchSize)
164 {
165     int32_t size = static_cast<int32_t>(GetLength());
166     if (size <= 0) {
167         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, "Container is empty");
168         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
169     }
170     if (index < 0 || index >= size) {
171         std::ostringstream oss;
172         oss << "The value of \"index\" is out of range. It must be >= 0 && <= " << (size - 1)
173             << ". Received value is: " << index;
174         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
175         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
176     }
177     if (batchSize < 1) {
178         std::ostringstream oss;
179         oss << "The value of \"size\" is out of range. It must be > 0" << ". Received value is: " << batchSize;
180         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
181         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
182     }
183     int32_t safeSize = (size - (index + batchSize)) < 0 ? size - index : batchSize;
184     AdjustForward(thread, index, safeSize);
185     return JSTaggedValue(safeSize);
186 }
187 
Set(JSThread * thread,const JSHandle<JSAPIPlainArray> & obj,const uint32_t index,JSTaggedValue value)188 JSTaggedValue JSAPIPlainArray::Set(JSThread *thread, const JSHandle<JSAPIPlainArray> &obj,
189                                    const uint32_t index, JSTaggedValue value)
190 {
191     JSHandle<JSTaggedValue> key(thread, JSTaggedValue(index));
192     JSHandle<JSTaggedValue> valueHandle(thread, value);
193     JSAPIPlainArray::Add(thread, obj, key, valueHandle);
194     return JSTaggedValue::Undefined();
195 }
196 
GetOwnProperty(JSThread * thread,const JSHandle<JSAPIPlainArray> & obj,const JSHandle<JSTaggedValue> & key)197 bool JSAPIPlainArray::GetOwnProperty(JSThread *thread, const JSHandle<JSAPIPlainArray> &obj,
198                                      const JSHandle<JSTaggedValue> &key)
199 {
200     TaggedArray *keyArray = TaggedArray::Cast(obj->GetKeys(thread).GetTaggedObject());
201     uint32_t size = obj->GetLength();
202     if (size == 0) {
203         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, "Container is empty");
204         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, false);
205     }
206     int32_t index = obj->BinarySearch(thread, keyArray, 0, size, key.GetTaggedValue().GetInt());
207     if (index < 0 || index >= static_cast<int32_t>(size)) {
208         ASSERT(size > 0);
209         std::ostringstream oss;
210         oss << "The value of \"index\" is out of range. It must be >= 0 && <= " << (size - 1)
211             << ". Received value is: " << index;
212         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
213         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, false);
214     }
215 
216     obj->Get(thread, key.GetTaggedValue());
217     return true;
218 }
219 
GetProperty(JSThread * thread,const JSHandle<JSAPIPlainArray> & obj,const JSHandle<JSTaggedValue> & key)220 OperationResult JSAPIPlainArray::GetProperty(JSThread *thread, const JSHandle<JSAPIPlainArray> &obj,
221                                              const JSHandle<JSTaggedValue> &key)
222 {
223     TaggedArray *keyArray = TaggedArray::Cast(obj->GetKeys(thread).GetTaggedObject());
224     uint32_t size = obj->GetLength();
225     if (size == 0) {
226         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, "Container is empty");
227         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, OperationResult(thread,
228                                                                         JSTaggedValue::Exception(),
229                                                                         PropertyMetaData(false)));
230     }
231     JSHandle<JSTaggedValue> indexKey = key;
232     if (indexKey->IsDouble()) {
233         // Math.floor(1) will produce TaggedDouble, we need to cast into TaggedInt
234         // For integer which is greater than INT32_MAX, it will remain TaggedDouble
235         indexKey = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(indexKey->GetDouble()));
236     }
237     if (!indexKey->IsInt()) {
238         CString errorMsg = "The type of \"index\" must be small integer.";
239         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
240         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error,
241                                          OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false)));
242     }
243 
244     int keyVal = indexKey->GetInt();
245     int32_t index = obj->BinarySearch(thread, keyArray, 0, size, keyVal);
246     if (index < 0 || index >= static_cast<int32_t>(size)) {
247         std::ostringstream oss;
248         ASSERT(size > 0);
249         oss << "The value of \"index\" is out of range. It must be >= 0 && <= " << (size - 1)
250             << ". Received value is: " << index;
251         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
252         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, OperationResult(thread,
253                                                                         JSTaggedValue::Exception(),
254                                                                         PropertyMetaData(false)));
255     }
256 
257     return OperationResult(thread, obj->Get(thread, JSTaggedValue(index)), PropertyMetaData(false));
258 }
259 
SetProperty(JSThread * thread,const JSHandle<JSAPIPlainArray> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value)260 bool JSAPIPlainArray::SetProperty(JSThread *thread, const JSHandle<JSAPIPlainArray> &obj,
261                                   const JSHandle<JSTaggedValue> &key,
262                                   const JSHandle<JSTaggedValue> &value)
263 {
264     TaggedArray *keyArray = TaggedArray::Cast(obj->GetKeys(thread).GetTaggedObject());
265     uint32_t size = obj->GetLength();
266     JSHandle<JSTaggedValue> indexKey = key;
267     if (indexKey->IsDouble()) {
268         // Math.floor(1) will produce TaggedDouble, we need to cast into TaggedInt
269         // For integer which is greater than INT32_MAX, it will remain TaggedDouble
270         indexKey = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(indexKey->GetDouble()));
271     }
272     if (!indexKey->IsInt()) {
273         return false;
274     }
275     int32_t index = obj->BinarySearch(thread, keyArray, 0, size, indexKey->GetInt());
276     if (index < 0 || index >= static_cast<int32_t>(size)) {
277         return false;
278     }
279 
280     obj->Set(thread, obj, index, value.GetTaggedValue());
281     return true;
282 }
283 
Clone(JSThread * thread,const JSHandle<JSAPIPlainArray> & obj)284 JSHandle<JSAPIPlainArray> JSAPIPlainArray::Clone(JSThread *thread, const JSHandle<JSAPIPlainArray> &obj)
285 {
286     JSHandle<TaggedArray> srckeys(thread, obj->GetKeys(thread));
287     JSHandle<TaggedArray> srcvalues(thread, obj->GetValues(thread));
288     auto factory = thread->GetEcmaVM()->GetFactory();
289     JSHandle<JSAPIPlainArray> newPlainArray = factory->NewJSAPIPlainArray(0);
290 
291     uint32_t length = obj->GetLength();
292     newPlainArray->SetLength(length);
293     JSHandle<TaggedArray> srcKeyArray(thread, obj->GetKeys(thread));
294     JSHandle<TaggedArray> srcValueArray(thread, obj->GetValues(thread));
295 
296     JSHandle<TaggedArray> dstKeyArray = factory->NewAndCopyTaggedArray(srcKeyArray, length, length);
297     JSHandle<TaggedArray> dstValueArray = factory->NewAndCopyTaggedArray(srcValueArray, length, length);
298 
299     newPlainArray->SetKeys(thread, dstKeyArray);
300     newPlainArray->SetValues(thread, dstValueArray);
301     return newPlainArray;
302 }
303 
Has(JSThread * thread,const int32_t key)304 bool JSAPIPlainArray::Has(JSThread *thread, const int32_t key)
305 {
306     uint32_t size = GetLength();
307     TaggedArray *keyArray = TaggedArray::Cast(GetKeys(thread).GetTaggedObject());
308     int32_t index = BinarySearch(thread, keyArray, 0, size, key);
309     if (index < 0) {
310         return false;
311     }
312     return true;
313 }
314 
Get(JSThread * thread,const JSTaggedValue key)315 JSTaggedValue JSAPIPlainArray::Get(JSThread *thread, const JSTaggedValue key)
316 {
317     uint32_t size = GetLength();
318     TaggedArray *keyArray = TaggedArray::Cast(GetKeys(thread).GetTaggedObject());
319     int32_t index = BinarySearch(thread, keyArray, 0, size, key.GetNumber());
320     if (index < 0) {
321         return JSTaggedValue::Undefined();
322     }
323     TaggedArray *values = TaggedArray::Cast(GetValues(thread).GetTaggedObject());
324     return values->Get(thread, index);
325 }
326 
GetIteratorObj(JSThread * thread,const JSHandle<JSAPIPlainArray> & obj,IterationKind kind)327 JSHandle<JSTaggedValue> JSAPIPlainArray::GetIteratorObj(JSThread *thread, const JSHandle<JSAPIPlainArray> &obj,
328                                                         IterationKind kind)
329 {
330     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
331     JSHandle<JSTaggedValue> iter =
332         JSHandle<JSTaggedValue>::Cast(factory->NewJSAPIPlainArrayIterator(obj, kind));
333     return iter;
334 }
335 
ForEach(JSThread * thread,const JSHandle<JSTaggedValue> & thisHandle,const JSHandle<JSTaggedValue> & callbackFn,const JSHandle<JSTaggedValue> & thisArg)336 JSTaggedValue JSAPIPlainArray::ForEach(JSThread *thread, const JSHandle<JSTaggedValue> &thisHandle,
337                                        const JSHandle<JSTaggedValue> &callbackFn,
338                                        const JSHandle<JSTaggedValue> &thisArg)
339 {
340     JSAPIPlainArray *plainarray = JSAPIPlainArray::Cast(thisHandle->GetTaggedObject());
341     uint32_t length = plainarray->GetLength();
342     JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
343     JSHandle<TaggedArray> keyArray(thread, plainarray->GetKeys(thread));
344     JSHandle<TaggedArray> valueArray(thread, plainarray->GetValues(thread));
345     for (uint32_t k = 0; k < length; k++) {
346         JSTaggedValue kValue = valueArray->Get(thread, k);
347         JSTaggedValue key = keyArray->Get(thread, k);
348         EcmaRuntimeCallInfo *info =
349             EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFn, thisArg, undefined, 3);  // 3: three args
350         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
351         info->SetCallArg(kValue, key, thisHandle.GetTaggedValue());
352         JSTaggedValue funcResult = JSFunction::Call(info);
353         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, funcResult);
354     }
355     return JSTaggedValue::Undefined();
356 }
357 
ToString(JSThread * thread,const JSHandle<JSAPIPlainArray> & plainarray)358 JSTaggedValue JSAPIPlainArray::ToString(JSThread *thread, const JSHandle<JSAPIPlainArray> &plainarray)
359 {
360     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
361     std::u16string sepStr = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> {}.from_bytes(",");
362     std::u16string colonStr = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> {}.from_bytes(":");
363 
364     uint32_t length = plainarray->GetLength();
365     std::u16string concatStr = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> {}.from_bytes("");
366     std::u16string concatStrNew = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> {}.from_bytes("");
367     JSMutableHandle<JSTaggedValue> valueHandle(thread, JSTaggedValue::Undefined());
368     JSMutableHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue::Undefined());
369     for (uint32_t k = 0; k < length; k++) {
370         std::u16string valueStr;
371         valueHandle.Update(plainarray->GetValueAt(thread, k));
372         if (!valueHandle->IsUndefined() && !valueHandle->IsNull()) {
373             JSHandle<EcmaString> valueStringHandle = JSTaggedValue::ToString(thread, valueHandle);
374             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
375             valueStr = EcmaStringAccessor(valueStringHandle).ToU16String(thread);
376         }
377 
378         std::u16string nextStr;
379         keyHandle.Update(plainarray->GetKeyAt(thread, k));
380         if (!keyHandle->IsUndefined() && !keyHandle->IsNull()) {
381             JSHandle<EcmaString> keyStringHandle = JSTaggedValue::ToString(thread, keyHandle);
382             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
383             nextStr = EcmaStringAccessor(keyStringHandle).ToU16String(thread);
384         }
385 
386         nextStr.append(colonStr);
387         nextStr.append(valueStr);
388         if (k > 0) {
389             concatStr.append(sepStr);
390             concatStr.append(nextStr);
391             continue;
392         }
393         concatStr.append(nextStr);
394     }
395 
396     char16_t *char16tData = concatStr.data();
397     auto *uint16tData = reinterpret_cast<uint16_t *>(char16tData);
398     uint32_t u16strSize = concatStr.size();
399     return factory->NewFromUtf16Literal(uint16tData, u16strSize).GetTaggedValue();
400 }
401 
GetIndexOfKey(JSThread * thread,int32_t key)402 JSTaggedValue JSAPIPlainArray::GetIndexOfKey(JSThread *thread, int32_t key)
403 {
404     uint32_t size = GetLength();
405     TaggedArray *keyArray = TaggedArray::Cast(GetKeys(thread).GetTaggedObject());
406     int32_t index = BinarySearch(thread, keyArray, 0, size, key);
407     if (index < 0) {
408         return JSTaggedValue(-1);
409     }
410     return JSTaggedValue(index);
411 }
412 
TryFastGetIndexOfValue(JSThread * thread,TaggedArray * values,JSTaggedValue value)413 JSTaggedValue JSAPIPlainArray::TryFastGetIndexOfValue(JSThread *thread, TaggedArray *values, JSTaggedValue value)
414 {
415     uint32_t size = GetLength();
416     for (uint32_t i = 0; i < size; ++i) {
417         JSTaggedValue currVal = values->Get(thread, i);
418         if (currVal.IsInt() && (currVal == value)) {
419             return JSTaggedValue(i);
420         }
421     }
422     return JSTaggedValue(-1);
423 }
424 
GetIndexOfValue(JSThread * thread,JSTaggedValue value)425 JSTaggedValue JSAPIPlainArray::GetIndexOfValue(JSThread *thread, JSTaggedValue value)
426 {
427     TaggedArray *values = TaggedArray::Cast(GetValues(thread).GetTaggedObject());
428     if (value.IsInt()) {
429         return TryFastGetIndexOfValue(thread, values, value);
430     } else {
431         uint32_t size = GetLength();
432         for (uint32_t i = 0; i < size; ++i) {
433             if (JSTaggedValue::SameValue(thread, values->Get(thread, i), value)) {
434                 return JSTaggedValue(i);
435             }
436         }
437     }
438     return JSTaggedValue(-1);
439 }
440 
IsEmpty()441 bool JSAPIPlainArray::IsEmpty()
442 {
443     uint32_t length = GetLength();
444     return length == 0;
445 }
446 
GetKeyAt(JSThread * thread,int32_t index)447 JSTaggedValue JSAPIPlainArray::GetKeyAt(JSThread *thread, int32_t index)
448 {
449     uint32_t size = GetLength();
450     TaggedArray *keyArray = TaggedArray::Cast(GetKeys(thread).GetTaggedObject());
451     if (index < 0 || index >= static_cast<int32_t>(size)) {
452         return JSTaggedValue::Undefined();
453     }
454     return keyArray->Get(thread, index);
455 }
456 
GetValueAt(JSThread * thread,int32_t index)457 JSTaggedValue JSAPIPlainArray::GetValueAt(JSThread *thread, int32_t index)
458 {
459     uint32_t size = GetLength();
460     if (size == 0) {
461         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, "Container is empty");
462         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
463     }
464     if (index < 0 || index >= static_cast<int32_t>(size)) {
465         ASSERT(size > 0);
466         std::ostringstream oss;
467         oss << "The value of \"index\" is out of range. It must be >= 0 && <= " << (size - 1)
468             << ". Received value is: " << index;
469         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
470         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
471     }
472     TaggedArray *values = TaggedArray::Cast(GetValues(thread).GetTaggedObject());
473     return values->Get(thread, index);
474 }
475 
Remove(JSThread * thread,JSTaggedValue key)476 JSTaggedValue JSAPIPlainArray::Remove(JSThread *thread, JSTaggedValue key)
477 {
478     uint32_t size = GetLength();
479     TaggedArray *keyArray = TaggedArray::Cast(GetKeys(thread).GetTaggedObject());
480     int32_t index = BinarySearch(thread, keyArray, 0, size, key.GetNumber());
481     if (index < 0 || index >= static_cast<int32_t>(size)) {
482         return JSTaggedValue::Undefined();
483     }
484     TaggedArray *values = TaggedArray::Cast(GetValues(thread).GetTaggedObject());
485     JSTaggedValue value = values->Get(thread, index);
486     AdjustForward(thread, index, 1); // 1 means the length of array
487     return value;
488 }
489 
RemoveAt(JSThread * thread,JSTaggedValue index)490 JSTaggedValue JSAPIPlainArray::RemoveAt(JSThread *thread, JSTaggedValue index)
491 {
492     uint32_t size = GetLength();
493     int32_t seat = index.GetNumber();
494     if (seat < 0 || static_cast<uint32_t>(seat) >= size) {
495         return JSTaggedValue::Undefined();
496     }
497     TaggedArray *values = TaggedArray::Cast(GetValues(thread).GetTaggedObject());
498     JSTaggedValue value = values->Get(thread, seat);
499     AdjustForward(thread, seat, 1);
500     return value;
501 }
502 
SetValueAt(JSThread * thread,JSTaggedValue index,JSTaggedValue value)503 bool JSAPIPlainArray::SetValueAt(JSThread *thread, JSTaggedValue index, JSTaggedValue value)
504 {
505     uint32_t size = GetLength();
506     if (size == 0) {
507         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, "Container is empty");
508         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, false);
509     }
510     int32_t seat = index.GetNumber();
511     if (seat < 0 || static_cast<uint32_t>(seat) >= size) {
512         std::ostringstream oss;
513         oss << "The value of \"index\" is out of range. It must be >= 0 && <= " << (size - 1)
514             << ". Received value is: " << seat;
515         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
516         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, false);
517     }
518     TaggedArray *values = TaggedArray::Cast(GetValues(thread).GetTaggedObject());
519     values->Set(thread, seat, value);
520     return true;
521 }
522 } // namespace panda::ecmascript
523