• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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_arraylist.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_function.h"
22 
23 namespace panda::ecmascript {
24 using ContainerError = containers::ContainerError;
25 using ErrorFlag = containers::ErrorFlag;
Add(JSThread * thread,const JSHandle<JSAPIArrayList> & arrayList,const JSHandle<JSTaggedValue> & value)26 bool JSAPIArrayList::Add(JSThread *thread, const JSHandle<JSAPIArrayList> &arrayList,
27                          const JSHandle<JSTaggedValue> &value)
28 {
29     uint32_t length = arrayList->GetLength(thread).GetArrayLength();
30     JSHandle<TaggedArray> elements = GrowCapacity(thread, arrayList, length + 1);
31 
32     ASSERT(!elements->IsDictionaryMode());
33     elements->Set(thread, length, value);
34     arrayList->SetLength(thread, JSTaggedValue(++length));
35     return true;
36 }
37 
Insert(JSThread * thread,const JSHandle<JSAPIArrayList> & arrayList,const JSHandle<JSTaggedValue> & value,const int & index)38 void JSAPIArrayList::Insert(JSThread *thread, const JSHandle<JSAPIArrayList> &arrayList,
39                             const JSHandle<JSTaggedValue> &value, const int &index)
40 {
41     int length = arrayList->GetLength(thread).GetInt();
42     if (index < 0 || index > length) {
43         std::ostringstream oss;
44         oss << "The value of \"index\" is out of range. It must be >= 0 && <= " << length
45             << ". Received value is: " << index;
46         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
47         THROW_NEW_ERROR_AND_RETURN(thread, error);
48     }
49     JSHandle<TaggedArray> elements = GrowCapacity(thread, arrayList, length + 1);
50     ASSERT(!elements->IsDictionaryMode());
51     for (int i = length - 1; i >= index; --i) {
52         elements->Set(thread, i + 1, elements->Get(thread, i));
53     }
54     elements->Set(thread, index, value);
55     arrayList->SetLength(thread, JSTaggedValue(++length));
56 }
57 
Clear(JSThread * thread,const JSHandle<JSAPIArrayList> & arrayList)58 void JSAPIArrayList::Clear(JSThread *thread, const JSHandle<JSAPIArrayList> &arrayList)
59 {
60     if (!arrayList.IsEmpty()) {
61         int length = arrayList->GetLength(thread).GetInt();
62         JSHandle<TaggedArray> elements(thread, arrayList->GetElements(thread));
63         ASSERT(!elements->IsDictionaryMode());
64         for (int i = 0; i < length; ++i) {
65             elements->Set(thread, i, JSTaggedValue::Hole());
66         }
67         arrayList->SetLength(thread, JSTaggedValue(0));
68     }
69 }
70 
Clone(JSThread * thread,const JSHandle<JSAPIArrayList> & obj)71 JSHandle<JSAPIArrayList> JSAPIArrayList::Clone(JSThread *thread, const JSHandle<JSAPIArrayList> &obj)
72 {
73     JSHandle<TaggedArray> srcElements(thread, obj->GetElements(thread));
74     ASSERT(!srcElements->IsDictionaryMode());
75 
76     uint32_t length = obj->GetSize(thread);
77     auto factory = thread->GetEcmaVM()->GetFactory();
78     JSHandle<JSAPIArrayList> newArrayList = factory->NewJSAPIArrayList(0);
79     newArrayList->SetLength(thread, JSTaggedValue(length));
80 
81     JSHandle<TaggedArray> dstElements = factory->NewAndCopyTaggedArray(srcElements, length, length);
82     newArrayList->SetElements(thread, dstElements);
83     return newArrayList;
84 }
85 
GetCapacity(JSThread * thread,const JSHandle<JSAPIArrayList> & obj)86 uint32_t JSAPIArrayList::GetCapacity(JSThread *thread, const JSHandle<JSAPIArrayList> &obj)
87 {
88     JSHandle<TaggedArray> elements(thread, obj->GetElements(thread));
89     ASSERT(!elements->IsDictionaryMode());
90     uint32_t capacity = elements->GetLength();
91     return capacity;
92 }
93 
IncreaseCapacityTo(JSThread * thread,const JSHandle<JSAPIArrayList> & arrayList,int capacity)94 void JSAPIArrayList::IncreaseCapacityTo(JSThread *thread, const JSHandle<JSAPIArrayList> &arrayList,
95                                         int capacity)
96 {
97     JSHandle<TaggedArray> elementData(thread, arrayList->GetElements(thread));
98     ASSERT(!elementData->IsDictionaryMode());
99     int length = arrayList->GetLength(thread).GetInt();
100     int oldElementLength = static_cast<int>(elementData->GetLength());
101     if (oldElementLength != capacity && length < capacity) {
102         ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
103         JSHandle<TaggedArray> newElements = factory->NewAndCopyTaggedArray(elementData,
104             static_cast<uint32_t>(capacity), static_cast<uint32_t>(length));
105         arrayList->SetElements(thread, newElements);
106     }
107 }
108 
TrimToCurrentLength(JSThread * thread,const JSHandle<JSAPIArrayList> & arrayList)109 void JSAPIArrayList::TrimToCurrentLength(JSThread *thread, const JSHandle<JSAPIArrayList> &arrayList)
110 {
111     uint32_t length = arrayList->GetLength(thread).GetArrayLength();
112     uint32_t capacity = JSAPIArrayList::GetCapacity(thread, arrayList);
113     JSHandle<TaggedArray> elements(thread, arrayList->GetElements(thread));
114     ASSERT(!elements->IsDictionaryMode());
115     if (capacity > length) {
116         elements->Trim(thread, length);
117     }
118 }
119 
Get(JSThread * thread,const uint32_t index)120 JSTaggedValue JSAPIArrayList::Get(JSThread *thread, const uint32_t index)
121 {
122     if (GetLength(thread).GetArrayLength() == 0) {
123         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, "Container is empty");
124         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
125     }
126     if (index >= GetLength(thread).GetArrayLength()) {
127         ASSERT(GetLength(thread).GetArrayLength() > 0);
128         std::ostringstream oss;
129         oss << "The value of \"index\" is out of range. It must be >= 0 && <= "
130             << (GetLength(thread).GetArrayLength() - 1) << ". Received value is: " << index;
131         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
132         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
133     }
134 
135     TaggedArray *elements = TaggedArray::Cast(GetElements(thread).GetTaggedObject());
136     return elements->Get(thread, index);
137 }
138 
IsEmpty(JSThread * thread,const JSHandle<JSAPIArrayList> & arrayList)139 bool JSAPIArrayList::IsEmpty(JSThread *thread, const JSHandle<JSAPIArrayList> &arrayList)
140 {
141     return arrayList->GetSize(thread) == 0;
142 }
143 
GetIndexOf(JSThread * thread,const JSHandle<JSAPIArrayList> & arrayList,const JSHandle<JSTaggedValue> & value)144 int JSAPIArrayList::GetIndexOf(JSThread *thread, const JSHandle<JSAPIArrayList> &arrayList,
145                                const JSHandle<JSTaggedValue> &value)
146 {
147     JSHandle<TaggedArray> elements(thread, arrayList->GetElements(thread));
148     ASSERT(!elements->IsDictionaryMode());
149     uint32_t length = arrayList->GetLength(thread).GetArrayLength();
150     JSTaggedValue targetValue = value.GetTaggedValue();
151     for (uint32_t i = 0; i < length; ++i) {
152         if (JSTaggedValue::StrictEqual(thread, targetValue, elements->Get(thread, i))) {
153             return i;
154         }
155     }
156     return -1;
157 }
158 
GetLastIndexOf(JSThread * thread,const JSHandle<JSAPIArrayList> & arrayList,const JSHandle<JSTaggedValue> & value)159 int JSAPIArrayList::GetLastIndexOf(JSThread *thread, const JSHandle<JSAPIArrayList> &arrayList,
160                                    const JSHandle<JSTaggedValue> &value)
161 {
162     JSHandle<TaggedArray> elements(thread, arrayList->GetElements(thread));
163     ASSERT(!elements->IsDictionaryMode());
164     JSTaggedValue targetValue = value.GetTaggedValue();
165     int length = arrayList->GetLength(thread).GetInt();
166     for (int i = length - 1; i >= 0; --i) {
167         if (JSTaggedValue::StrictEqual(thread, targetValue, elements->Get(thread, i))) {
168             return i;
169         }
170     }
171     return -1;
172 }
173 
RemoveByIndex(JSThread * thread,const JSHandle<JSAPIArrayList> & arrayList,int index)174 JSTaggedValue JSAPIArrayList::RemoveByIndex(JSThread *thread, const JSHandle<JSAPIArrayList> &arrayList, int index)
175 {
176     int length = arrayList->GetLength(thread).GetInt();
177     if (length <= 0) {
178         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, "Container is empty");
179         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
180     }
181     if (index < 0 || index >= length) {
182         std::ostringstream oss;
183         oss << "The value of \"index\" is out of range. It must be >= 0 && <= " << (length - 1)
184             << ". Received value is: " << index;
185         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
186         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
187     }
188 
189     TaggedArray *resElements = TaggedArray::Cast(arrayList->GetElements(thread).GetTaggedObject());
190     JSTaggedValue oldValue = resElements->Get(thread, index);
191 
192     if (index >= 0) {
193         JSHandle<TaggedArray> elements(thread, arrayList->GetElements(thread));
194         ASSERT(!elements->IsDictionaryMode());
195         TaggedArray::RemoveElementByIndex(thread, elements, index, length);
196         arrayList->SetLength(thread, JSTaggedValue(length - 1));
197     }
198 
199     return oldValue;
200 }
201 
Remove(JSThread * thread,const JSHandle<JSAPIArrayList> & arrayList,const JSHandle<JSTaggedValue> & value)202 bool JSAPIArrayList::Remove(JSThread *thread, const JSHandle<JSAPIArrayList> &arrayList,
203                             const JSHandle<JSTaggedValue> &value)
204 {
205     int index = GetIndexOf(thread, arrayList, value);
206     uint32_t length = arrayList->GetSize(thread);
207     if (index >= 0) {
208         JSHandle<TaggedArray> elements(thread, arrayList->GetElements(thread));
209         ASSERT(!elements->IsDictionaryMode());
210         TaggedArray::RemoveElementByIndex(thread, elements, index, length);
211         arrayList->SetLength(thread, JSTaggedValue(length - 1));
212         return true;
213     }
214     return false;
215 }
216 
RemoveByRange(JSThread * thread,const JSHandle<JSAPIArrayList> & arrayList,const JSHandle<JSTaggedValue> & value1,const JSHandle<JSTaggedValue> & value2)217 JSTaggedValue JSAPIArrayList::RemoveByRange(JSThread *thread, const JSHandle<JSAPIArrayList> &arrayList,
218                                             const JSHandle<JSTaggedValue> &value1,
219                                             const JSHandle<JSTaggedValue> &value2)
220 {
221     int32_t startIndex = JSTaggedValue::ToInt32(thread, value1);
222     int32_t endIndex = JSTaggedValue::ToInt32(thread, value2);
223     int32_t length = arrayList->GetLength(thread).GetInt();
224     if (length <= 0) {
225         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, "Container is empty");
226         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
227     }
228     int32_t size = length > endIndex ? endIndex : length;
229     if (startIndex < 0 || startIndex >= size) {
230         std::ostringstream oss;
231         oss << "The value of \"fromIndex\" is out of range. It must be >= 0 && <= " << (size - 1)
232             << ". Received value is: " << startIndex;
233         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
234         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
235     }
236     if (endIndex <= startIndex || endIndex < 0 || endIndex > length) {
237         std::ostringstream oss;
238         oss << "The value of \"toIndex\" is out of range. It must be >= 0 && <= " << length
239             << ". Received value is: " << endIndex;
240         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
241         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
242     }
243 
244     int32_t toIndex = endIndex >= length ? length : endIndex;
245 
246     JSHandle<TaggedArray> elements(thread, arrayList->GetElements(thread));
247     ASSERT(!elements->IsDictionaryMode());
248     int32_t numMoved = length - toIndex;
249 
250     for (int32_t i = 0; i < numMoved; i++) {
251         elements->Set(thread, startIndex + i, elements->Get(thread, static_cast<uint32_t>(endIndex + i)));
252     }
253     int32_t newLength = length - (endIndex - startIndex);
254     arrayList->SetLength(thread, JSTaggedValue(newLength));
255     elements->Trim(thread, newLength);
256     return JSTaggedValue::Undefined();
257 }
258 
ReplaceAllElements(JSThread * thread,const JSHandle<JSTaggedValue> & thisHandle,const JSHandle<JSTaggedValue> & callbackFn,const JSHandle<JSTaggedValue> & thisArg)259 JSTaggedValue JSAPIArrayList::ReplaceAllElements(JSThread *thread, const JSHandle<JSTaggedValue> &thisHandle,
260                                                  const JSHandle<JSTaggedValue> &callbackFn,
261                                                  const JSHandle<JSTaggedValue> &thisArg)
262 {
263     JSHandle<JSAPIArrayList> arrayList = JSHandle<JSAPIArrayList>::Cast(thisHandle);
264     uint32_t length = arrayList->GetSize(thread);
265     JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
266     JSMutableHandle<JSTaggedValue> kValue(thread, JSTaggedValue::Undefined());
267     const int32_t argsLength = 3;
268     JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
269     for (uint32_t k = 0; k < length; k++) {
270         kValue.Update(arrayList->Get(thread, k));
271         key.Update(JSTaggedValue(k));
272         EcmaRuntimeCallInfo *info =
273             EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFn, thisArg, undefined, argsLength);
274         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
275         info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue(), thisHandle.GetTaggedValue());
276         JSTaggedValue funcResult = JSFunction::Call(info);
277         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, funcResult);
278 
279         arrayList->Set(thread, k, funcResult);
280     }
281 
282     return JSTaggedValue::Undefined();
283 }
284 
Set(JSThread * thread,const uint32_t index,JSTaggedValue value)285 JSTaggedValue JSAPIArrayList::Set(JSThread *thread, const uint32_t index, JSTaggedValue value)
286 {
287     if (GetLength(thread).GetArrayLength() == 0) {
288         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, "Container is empty");
289         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
290     }
291     if (index >= GetLength(thread).GetArrayLength()) {
292         ASSERT(GetLength(thread).GetArrayLength() > 0);
293         std::ostringstream oss;
294         oss << "The value of \"index\" is out of range. It must be >= 0 && <= "
295             << (GetLength(thread).GetArrayLength() - 1) << ". Received value is: " << index;
296         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
297         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
298     }
299 
300     TaggedArray *elements = TaggedArray::Cast(GetElements(thread).GetTaggedObject());
301     elements->Set(thread, index, value);
302     return JSTaggedValue::Undefined();
303 }
304 
SubArrayList(JSThread * thread,const JSHandle<JSAPIArrayList> & arrayList,const JSHandle<JSTaggedValue> & value1,const JSHandle<JSTaggedValue> & value2)305 JSTaggedValue JSAPIArrayList::SubArrayList(JSThread *thread, const JSHandle<JSAPIArrayList> &arrayList,
306                                            const JSHandle<JSTaggedValue> &value1,
307                                            const JSHandle<JSTaggedValue> &value2)
308 {
309     int length = arrayList->GetLength(thread).GetInt();
310     int fromIndex = JSTaggedValue::ToInt32(thread, value1);
311     int toIndex = JSTaggedValue::ToInt32(thread, value2);
312     int32_t size = length > toIndex ? toIndex : length;
313     if (length <= 0) {
314         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, "Container is empty");
315         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
316     }
317     if (fromIndex < 0 || fromIndex >= size) {
318         std::ostringstream oss;
319         oss << "The value of \"fromIndex\" is out of range. It must be >= 0 && <= " << (size - 1)
320             << ". Received value is: " << fromIndex;
321         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
322         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
323     }
324     if (toIndex <= fromIndex || toIndex < 0 || toIndex > length) {
325         std::ostringstream oss;
326         oss << "The value of \"toIndex\" is out of range. It must be >= 0 && <= " << length
327             << ". Received value is: " << toIndex;
328         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
329         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
330     }
331 
332     int endIndex = toIndex >= length - 1 ? length - 1 : toIndex;
333     int newLength = toIndex == length ? length - fromIndex : endIndex - fromIndex;
334     JSHandle<JSAPIArrayList> subArrayList = thread->GetEcmaVM()->GetFactory()->NewJSAPIArrayList(newLength);
335     if (newLength == 0) {
336         return subArrayList.GetTaggedValue();
337     }
338     JSHandle<TaggedArray> elements(thread, arrayList->GetElements(thread));
339     ASSERT(!elements->IsDictionaryMode());
340     subArrayList->SetLength(thread, JSTaggedValue(newLength));
341 
342     for (int i = 0; i < newLength; i++) {
343         subArrayList->Set(thread, i, elements->Get(thread, fromIndex + i));
344     }
345 
346     return subArrayList.GetTaggedValue();
347 }
348 
ForEach(JSThread * thread,const JSHandle<JSTaggedValue> & thisHandle,const JSHandle<JSTaggedValue> & callbackFn,const JSHandle<JSTaggedValue> & thisArg)349 JSTaggedValue JSAPIArrayList::ForEach(JSThread *thread, const JSHandle<JSTaggedValue> &thisHandle,
350                                       const JSHandle<JSTaggedValue> &callbackFn,
351                                       const JSHandle<JSTaggedValue> &thisArg)
352 {
353     JSHandle<JSAPIArrayList> arrayList = JSHandle<JSAPIArrayList>::Cast(thisHandle);
354     uint32_t length = arrayList->GetSize(thread);
355     JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
356     JSMutableHandle<JSTaggedValue> kValue(thread, JSTaggedValue::Undefined());
357     const int32_t argsLength = 3;
358     JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
359     for (uint32_t k = 0; k < length; k++) {
360         kValue.Update(arrayList->Get(thread, k));
361         key.Update(JSTaggedValue(k));
362         EcmaRuntimeCallInfo *info =
363             EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFn, thisArg, undefined, argsLength);
364         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
365         info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue(), thisHandle.GetTaggedValue());
366         JSTaggedValue funcResult = JSFunction::Call(info);
367         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, funcResult);
368         if (length != arrayList->GetSize(thread)) {
369             length = arrayList->GetSize(thread);
370         }
371     }
372 
373     return JSTaggedValue::Undefined();
374 }
375 
GrowCapacity(const JSThread * thread,const JSHandle<JSAPIArrayList> & obj,uint32_t capacity)376 JSHandle<TaggedArray> JSAPIArrayList::GrowCapacity(const JSThread *thread, const JSHandle<JSAPIArrayList> &obj,
377                                                    uint32_t capacity)
378 {
379     JSHandle<TaggedArray> oldElements(thread, obj->GetElements(thread));
380     ASSERT(!oldElements->IsDictionaryMode());
381     uint32_t oldCapacity = oldElements->GetLength();
382     if (capacity < oldCapacity) {
383         return oldElements;
384     }
385     uint32_t newCapacity = ComputeCapacity(capacity);
386     JSHandle<TaggedArray> newElements =
387         thread->GetEcmaVM()->GetFactory()->CopyArray(oldElements, oldCapacity, newCapacity);
388 
389     obj->SetElements(thread, newElements);
390     return newElements;
391 }
392 
Has(JSThread * thread,const JSTaggedValue value) const393 bool JSAPIArrayList::Has(JSThread *thread, const JSTaggedValue value) const
394 {
395     TaggedArray *elements = TaggedArray::Cast(GetElements(thread).GetTaggedObject());
396     uint32_t length = GetSize(thread);
397     if (length == 0) {
398         return false;
399     }
400 
401     for (uint32_t i = 0; i < length; i++) {
402         if (JSTaggedValue::SameValue(thread, elements->Get(thread, i), value)) {
403             return true;
404         }
405     }
406     return false;
407 }
408 
OwnKeys(JSThread * thread,const JSHandle<JSAPIArrayList> & obj)409 JSHandle<TaggedArray> JSAPIArrayList::OwnKeys(JSThread *thread, const JSHandle<JSAPIArrayList> &obj)
410 {
411     return JSObject::GetOwnPropertyKeys(thread, JSHandle<JSObject>::Cast(obj));
412 }
413 
OwnEnumKeys(JSThread * thread,const JSHandle<JSAPIArrayList> & obj)414 JSHandle<TaggedArray> JSAPIArrayList::OwnEnumKeys(JSThread *thread, const JSHandle<JSAPIArrayList> &obj)
415 {
416     return JSObject::GetOwnEnumPropertyKeys(thread, JSHandle<JSObject>::Cast(obj));
417 }
418 
GetOwnProperty(JSThread * thread,const JSHandle<JSAPIArrayList> & obj,const JSHandle<JSTaggedValue> & key)419 bool JSAPIArrayList::GetOwnProperty(JSThread *thread, const JSHandle<JSAPIArrayList> &obj,
420                                     const JSHandle<JSTaggedValue> &key)
421 {
422     uint32_t index = 0;
423     if (UNLIKELY(!JSTaggedValue::ToElementIndex(thread, key.GetTaggedValue(), &index))) {
424         JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, key.GetTaggedValue());
425         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
426         CString errorMsg =
427             "The type of \"index\" can not obtain attributes of no-number type. Received value is: "
428             + ConvertToString(thread, *result);
429         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
430         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, false);
431     }
432 
433     uint32_t length = obj->GetLength(thread).GetArrayLength();
434     if (length == 0) {
435         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, "Container is empty");
436         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, false);
437     }
438     if (index >= length) {
439         ASSERT(length > 0);
440         std::ostringstream oss;
441         oss << "The value of \"index\" is out of range. It must be > " << (length - 1)
442             << ". Received value is: " << index;
443         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
444         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, false);
445     }
446 
447     obj->Get(thread, index);
448     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
449     return true;
450 }
451 
GetIteratorObj(JSThread * thread,const JSHandle<JSAPIArrayList> & obj)452 JSTaggedValue JSAPIArrayList::GetIteratorObj(JSThread *thread, const JSHandle<JSAPIArrayList> &obj)
453 {
454     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
455     JSHandle<JSAPIArrayListIterator> iter(factory->NewJSAPIArrayListIterator(obj));
456 
457     return iter.GetTaggedValue();
458 }
459 
GetProperty(JSThread * thread,const JSHandle<JSAPIArrayList> & obj,const JSHandle<JSTaggedValue> & key)460 OperationResult JSAPIArrayList::GetProperty(JSThread *thread, const JSHandle<JSAPIArrayList> &obj,
461                                             const JSHandle<JSTaggedValue> &key)
462 {
463     int length = obj->GetLength(thread).GetInt();
464     JSHandle<JSTaggedValue> indexKey = key;
465     if (indexKey->IsDouble()) {
466         // Math.floor(1) will produce TaggedDouble, we need to cast into TaggedInt
467         // For integer which is greater than INT32_MAX, it will remain TaggedDouble
468         indexKey = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(indexKey->GetDouble()));
469     }
470     if (!indexKey->IsInt()) {
471         CString errorMsg = "The type of \"index\" must be small integer.";
472         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
473         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error,
474                                          OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false)));
475     }
476 
477     int index = indexKey->GetInt();
478     if (index < 0 || index >= length) {
479         std::ostringstream oss;
480         oss << "The value of \"index\" is out of range. It must be >= 0 && <= " << (length - 1)
481             << ". Received value is: " << index;
482         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
483         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error,
484                                          OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false)));
485     }
486 
487     return OperationResult(thread, obj->Get(thread, index), PropertyMetaData(false));
488 }
489 
SetProperty(JSThread * thread,const JSHandle<JSAPIArrayList> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value)490 bool JSAPIArrayList::SetProperty(JSThread *thread, const JSHandle<JSAPIArrayList> &obj,
491                                  const JSHandle<JSTaggedValue> &key,
492                                  const JSHandle<JSTaggedValue> &value)
493 {
494     int length = obj->GetLength(thread).GetInt();
495     int index = static_cast<int>(key->GetNumber());
496     if (index < 0 || index >= length) {
497         return false;
498     }
499 
500     obj->Set(thread, index, value.GetTaggedValue());
501     return true;
502 }
503 }  // namespace panda::ecmascript
504