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