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/containers/containers_arraylist.h"
17
18 #include "ecmascript/containers/containers_errors.h"
19 #include "ecmascript/base/array_helper.h"
20 #include "ecmascript/base/number_helper.h"
21 #include "ecmascript/ecma_vm.h"
22 #include "ecmascript/js_api/js_api_arraylist.h"
23 #include "ecmascript/js_api/js_api_arraylist_iterator.h"
24 #include "ecmascript/js_array.h"
25 #include "ecmascript/js_function.h"
26 #include "ecmascript/js_iterator.h"
27 #include "ecmascript/object_factory.h"
28 #include "ecmascript/tagged_array-inl.h"
29
30 namespace panda::ecmascript::containers {
ArrayListConstructor(EcmaRuntimeCallInfo * argv)31 JSTaggedValue ContainersArrayList::ArrayListConstructor(EcmaRuntimeCallInfo *argv)
32 {
33 ASSERT(argv);
34 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, Constructor);
35 JSThread *thread = argv->GetThread();
36 [[maybe_unused]] EcmaHandleScope handleScope(thread);
37 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
38 JSHandle<JSTaggedValue> newTarget = GetNewTarget(argv);
39 if (newTarget->IsUndefined()) {
40 JSTaggedValue error =
41 ContainerError::BusinessError(thread, ErrorFlag::IS_NULL_ERROR,
42 "The ArrayList's constructor cannot be directly invoked.");
43 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
44 }
45 JSHandle<JSTaggedValue> constructor = GetConstructor(argv);
46 JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), newTarget);
47 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
48 JSHandle<TaggedArray> newTaggedArray = factory->NewTaggedArray(JSAPIArrayList::DEFAULT_CAPACITY_LENGTH);
49 obj->SetElements(thread, newTaggedArray);
50 return obj.GetTaggedValue();
51 }
52
Add(EcmaRuntimeCallInfo * argv)53 JSTaggedValue ContainersArrayList::Add(EcmaRuntimeCallInfo *argv)
54 {
55 ASSERT(argv);
56 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, Add);
57 JSThread *thread = argv->GetThread();
58 [[maybe_unused]] EcmaHandleScope handleScope(thread);
59 JSHandle<JSTaggedValue> self = GetThis(argv);
60
61 if (!self->IsJSAPIArrayList()) {
62 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
63 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
64 } else {
65 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
66 "The add method cannot be bound");
67 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
68 }
69 }
70
71 JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
72 return GetTaggedBoolean(JSAPIArrayList::Add(thread, JSHandle<JSAPIArrayList>::Cast(self), value));
73 }
74
Insert(EcmaRuntimeCallInfo * argv)75 JSTaggedValue ContainersArrayList::Insert(EcmaRuntimeCallInfo *argv)
76 {
77 ASSERT(argv);
78 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, Insert);
79 JSThread *thread = argv->GetThread();
80 [[maybe_unused]] EcmaHandleScope handleScope(thread);
81 JSHandle<JSTaggedValue> self = GetThis(argv);
82
83 if (!self->IsJSAPIArrayList()) {
84 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
85 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
86 } else {
87 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
88 "The insert method cannot be bound");
89 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
90 }
91 }
92
93 JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
94 JSHandle<JSTaggedValue> index = GetCallArg(argv, 1);
95 if (!index->IsInteger()) {
96 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, index);
97 CString errorMsg = "The type of \"index\" must be number. Received value is: " + ConvertToString(*result);
98 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
99 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
100 }
101 JSAPIArrayList::Insert(thread, JSHandle<JSAPIArrayList>::Cast(self), value, JSTaggedValue::ToUint32(thread, index));
102 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
103
104 return JSTaggedValue::Undefined();
105 }
106
Clear(EcmaRuntimeCallInfo * argv)107 JSTaggedValue ContainersArrayList::Clear(EcmaRuntimeCallInfo *argv)
108 {
109 ASSERT(argv);
110 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, Clear);
111 JSThread *thread = argv->GetThread();
112 [[maybe_unused]] EcmaHandleScope handleScope(thread);
113 JSHandle<JSTaggedValue> self = GetThis(argv);
114
115 if (!self->IsJSAPIArrayList()) {
116 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
117 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
118 } else {
119 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
120 "The clear method cannot be bound");
121 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
122 }
123 }
124
125 JSAPIArrayList::Clear(thread, JSHandle<JSAPIArrayList>::Cast(self));
126
127 return JSTaggedValue::True();
128 }
129
Clone(EcmaRuntimeCallInfo * argv)130 JSTaggedValue ContainersArrayList::Clone(EcmaRuntimeCallInfo *argv)
131 {
132 ASSERT(argv);
133 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, Clone);
134 JSThread *thread = argv->GetThread();
135 [[maybe_unused]] EcmaHandleScope handleScope(thread);
136 JSHandle<JSTaggedValue> self = GetThis(argv);
137
138 if (!self->IsJSAPIArrayList()) {
139 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
140 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
141 } else {
142 JSTaggedValue error = ContainerError::BusinessError(thread, BIND_ERROR,
143 "The clone method cannot be bound");
144 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
145 }
146 }
147
148 JSHandle<JSAPIArrayList> newArrayList = JSAPIArrayList::Clone(thread, JSHandle<JSAPIArrayList>::Cast(self));
149
150 return newArrayList.GetTaggedValue();
151 }
152
Has(EcmaRuntimeCallInfo * argv)153 JSTaggedValue ContainersArrayList::Has(EcmaRuntimeCallInfo *argv)
154 {
155 ASSERT(argv);
156 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, Has);
157 JSThread *thread = argv->GetThread();
158 [[maybe_unused]] EcmaHandleScope handleScope(thread);
159 JSHandle<JSTaggedValue> self = GetThis(argv);
160
161 if (!self->IsJSAPIArrayList()) {
162 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
163 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
164 } else {
165 JSTaggedValue error = ContainerError::BusinessError(thread, BIND_ERROR,
166 "The has method cannot be bound");
167 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
168 }
169 }
170
171 JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
172 bool isHas = JSHandle<JSAPIArrayList>::Cast(self)->Has(value.GetTaggedValue());
173
174 return GetTaggedBoolean(isHas);
175 }
176
GetCapacity(EcmaRuntimeCallInfo * argv)177 JSTaggedValue ContainersArrayList::GetCapacity(EcmaRuntimeCallInfo *argv)
178 {
179 ASSERT(argv);
180
181 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, GetCapacity);
182 JSThread *thread = argv->GetThread();
183
184 JSHandle<JSTaggedValue> self = GetThis(argv);
185 if (!self->IsJSAPIArrayList()) {
186 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
187 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
188 } else {
189 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
190 "The getCapacity method cannot be bound");
191 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
192 }
193 }
194
195 uint32_t capacity = JSAPIArrayList::GetCapacity(thread, JSHandle<JSAPIArrayList>::Cast(self));
196
197 return JSTaggedValue(capacity);
198 }
199
IncreaseCapacityTo(EcmaRuntimeCallInfo * argv)200 JSTaggedValue ContainersArrayList::IncreaseCapacityTo(EcmaRuntimeCallInfo *argv)
201 {
202 ASSERT(argv);
203 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, IncreaseCapacityTo);
204 JSThread *thread = argv->GetThread();
205 [[maybe_unused]] EcmaHandleScope handleScope(thread);
206 JSHandle<JSTaggedValue> self = GetThis(argv);
207
208 if (!self->IsJSAPIArrayList()) {
209 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
210 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
211 } else {
212 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
213 "The increaseCapacityTo method cannot be bound");
214 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
215 }
216 }
217
218 JSHandle<JSTaggedValue> newCapacity = GetCallArg(argv, 0);
219 if (!newCapacity->IsInteger()) {
220 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, newCapacity);
221 CString errorMsg =
222 "The type of \"newCapacity\" must be number. Received value is: " + ConvertToString(*result);
223 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
224 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
225 }
226
227 JSAPIArrayList::IncreaseCapacityTo(thread, JSHandle<JSAPIArrayList>::Cast(self),
228 JSTaggedValue::ToUint32(thread, newCapacity));
229
230 return JSTaggedValue::True();
231 }
232
TrimToCurrentLength(EcmaRuntimeCallInfo * argv)233 JSTaggedValue ContainersArrayList::TrimToCurrentLength(EcmaRuntimeCallInfo *argv)
234 {
235 ASSERT(argv);
236 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, TrimToCurrentLength);
237 JSThread *thread = argv->GetThread();
238 [[maybe_unused]] EcmaHandleScope handleScope(thread);
239 JSHandle<JSTaggedValue> self = GetThis(argv);
240
241 if (!self->IsJSAPIArrayList()) {
242 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
243 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
244 } else {
245 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
246 "The trimToCurrentLength method cannot be bound");
247 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
248 }
249 }
250
251 JSAPIArrayList::TrimToCurrentLength(thread, JSHandle<JSAPIArrayList>::Cast(self));
252
253 return JSTaggedValue::True();
254 }
255
Get(EcmaRuntimeCallInfo * argv)256 JSTaggedValue ContainersArrayList::Get(EcmaRuntimeCallInfo *argv)
257 {
258 ASSERT(argv);
259 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, Get);
260 JSThread *thread = argv->GetThread();
261 [[maybe_unused]] EcmaHandleScope handleScope(thread);
262 JSHandle<JSTaggedValue> self = GetThis(argv);
263
264 if (!self->IsJSAPIArrayList()) {
265 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
266 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
267 } else {
268 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
269 "The get method cannot be bound");
270 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
271 }
272 }
273
274 JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
275
276 JSTaggedValue element = JSHandle<JSAPIArrayList>::Cast(self)->Get(thread, JSTaggedValue::ToUint32(thread, value));
277
278 return element;
279 }
280
GetIndexOf(EcmaRuntimeCallInfo * argv)281 JSTaggedValue ContainersArrayList::GetIndexOf(EcmaRuntimeCallInfo *argv)
282 {
283 ASSERT(argv);
284 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, GetIndexOf);
285 JSThread *thread = argv->GetThread();
286 [[maybe_unused]] EcmaHandleScope handleScope(thread);
287 JSHandle<JSTaggedValue> self = GetThis(argv);
288
289 if (!self->IsJSAPIArrayList()) {
290 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
291 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
292 } else {
293 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
294 "The getIndexOf method cannot be bound");
295 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
296 }
297 }
298
299 JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
300
301 return JSTaggedValue(JSAPIArrayList::GetIndexOf(thread, JSHandle<JSAPIArrayList>::Cast(self), value));
302 }
303
IsEmpty(EcmaRuntimeCallInfo * argv)304 JSTaggedValue ContainersArrayList::IsEmpty(EcmaRuntimeCallInfo *argv)
305 {
306 ASSERT(argv);
307 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, IsEmpty);
308 JSThread *thread = argv->GetThread();
309 [[maybe_unused]] EcmaHandleScope handleScope(thread);
310 JSHandle<JSTaggedValue> self = GetThis(argv);
311
312 if (!self->IsJSAPIArrayList()) {
313 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
314 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
315 } else {
316 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
317 "The isEmpty method cannot be bound");
318 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
319 }
320 }
321
322 return JSTaggedValue(JSAPIArrayList::IsEmpty(JSHandle<JSAPIArrayList>::Cast(self)));
323 }
324
GetLastIndexOf(EcmaRuntimeCallInfo * argv)325 JSTaggedValue ContainersArrayList::GetLastIndexOf(EcmaRuntimeCallInfo *argv)
326 {
327 ASSERT(argv);
328 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, GetLastIndexOf);
329 JSThread *thread = argv->GetThread();
330 [[maybe_unused]] EcmaHandleScope handleScope(thread);
331 JSHandle<JSTaggedValue> self = GetThis(argv);
332
333 if (!self->IsJSAPIArrayList()) {
334 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
335 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
336 } else {
337 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
338 "The getLastIndexOf method cannot be bound");
339 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
340 }
341 }
342
343 JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
344
345 return JSTaggedValue(JSAPIArrayList::GetLastIndexOf(thread, JSHandle<JSAPIArrayList>::Cast(self), value));
346 }
347
RemoveByIndex(EcmaRuntimeCallInfo * argv)348 JSTaggedValue ContainersArrayList::RemoveByIndex(EcmaRuntimeCallInfo *argv)
349 {
350 ASSERT(argv);
351 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, RemoveByIndex);
352 JSThread *thread = argv->GetThread();
353 [[maybe_unused]] EcmaHandleScope handleScope(thread);
354 JSHandle<JSTaggedValue> self = GetThis(argv);
355
356 if (!self->IsJSAPIArrayList()) {
357 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
358 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
359 } else {
360 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
361 "The removeByIndex method cannot be bound");
362 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
363 }
364 }
365
366 JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
367 if (!value->IsInteger()) {
368 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, value.GetTaggedValue());
369 CString errorMsg =
370 "The type of \"index\" must be number. Received value is: " + ConvertToString(*result);
371 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
372 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
373 }
374
375 JSTaggedValue result =
376 JSAPIArrayList::RemoveByIndex(thread,
377 JSHandle<JSAPIArrayList>::Cast(self), JSTaggedValue::ToUint32(thread, value));
378
379 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
380 return result;
381 }
382
Remove(EcmaRuntimeCallInfo * argv)383 JSTaggedValue ContainersArrayList::Remove(EcmaRuntimeCallInfo *argv)
384 {
385 ASSERT(argv);
386 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, Remove);
387 JSThread *thread = argv->GetThread();
388 [[maybe_unused]] EcmaHandleScope handleScope(thread);
389 JSHandle<JSTaggedValue> self = GetThis(argv);
390
391 if (!self->IsJSAPIArrayList()) {
392 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
393 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
394 } else {
395 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
396 "The remove method cannot be bound");
397 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
398 }
399 }
400
401 JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
402
403 bool isRemove = JSAPIArrayList::Remove(thread, JSHandle<JSAPIArrayList>::Cast(self), value);
404 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
405
406 return GetTaggedBoolean(isRemove);
407 }
408
RemoveByRange(EcmaRuntimeCallInfo * argv)409 JSTaggedValue ContainersArrayList::RemoveByRange(EcmaRuntimeCallInfo *argv)
410 {
411 ASSERT(argv);
412 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, RemoveByRange);
413 JSThread *thread = argv->GetThread();
414 [[maybe_unused]] EcmaHandleScope handleScope(thread);
415 JSHandle<JSTaggedValue> self = GetThis(argv);
416
417 if (!self->IsJSAPIArrayList()) {
418 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
419 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
420 } else {
421 JSTaggedValue error = ContainerError::BusinessError(thread, BIND_ERROR,
422 "The removeByRange method cannot be bound");
423 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
424 }
425 }
426
427 JSHandle<JSTaggedValue> startIndex = GetCallArg(argv, 0);
428 JSHandle<JSTaggedValue> endIndex = GetCallArg(argv, 1);
429 if (!startIndex->IsInteger()) {
430 std::ostringstream oss;
431 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, startIndex);
432 CString errorMsg =
433 "The type of \"fromIndex\" must be number. Received value is: " + ConvertToString(*result);
434 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
435 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
436 }
437 if (!endIndex->IsInteger()) {
438 std::ostringstream oss;
439 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, endIndex);
440 CString errorMsg =
441 "The type of \"toIndex\" must be number. Received value is: " + ConvertToString(*result);
442 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
443 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
444 }
445 JSTaggedValue result =
446 JSAPIArrayList::RemoveByRange(thread, JSHandle<JSAPIArrayList>::Cast(self), startIndex, endIndex);
447
448 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
449 return result;
450 }
451
ReplaceAllElements(EcmaRuntimeCallInfo * argv)452 JSTaggedValue ContainersArrayList::ReplaceAllElements(EcmaRuntimeCallInfo *argv)
453 {
454 ASSERT(argv);
455 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, ReplaceAllElements);
456 JSThread *thread = argv->GetThread();
457 [[maybe_unused]] EcmaHandleScope handleScope(thread);
458 JSHandle<JSTaggedValue> self = GetThis(argv);
459
460 if (!self->IsJSAPIArrayList()) {
461 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
462 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
463 } else {
464 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
465 "The replaceAllElements method cannot be bound");
466 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
467 }
468 }
469
470 JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
471 if (!callbackFnHandle->IsCallable()) {
472 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, callbackFnHandle);
473 CString errorMsg =
474 "The type of \"callbackfn\" must be callable. Received value is: " + ConvertToString(*result);
475 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
476 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
477 }
478 JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1);
479
480 return JSAPIArrayList::ReplaceAllElements(thread, self, callbackFnHandle, thisArgHandle);
481 }
482
Set(EcmaRuntimeCallInfo * argv)483 JSTaggedValue ContainersArrayList::Set(EcmaRuntimeCallInfo *argv)
484 {
485 ASSERT(argv);
486 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, Set);
487 JSThread *thread = argv->GetThread();
488 [[maybe_unused]] EcmaHandleScope handleScope(thread);
489 JSHandle<JSTaggedValue> self = GetThis(argv);
490
491 if (!self->IsJSAPIArrayList()) {
492 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
493 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
494 } else {
495 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
496 "The set method cannot be bound");
497 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
498 }
499 }
500
501 JSHandle<JSTaggedValue> index = GetCallArg(argv, 0);
502 JSHandle<JSTaggedValue> value = GetCallArg(argv, 1);
503 JSHandle<JSAPIArrayList>::Cast(self)->Set(thread, JSTaggedValue::ToUint32(thread, index), value.GetTaggedValue());
504
505 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
506 return JSTaggedValue::Undefined();
507 }
508
SubArrayList(EcmaRuntimeCallInfo * argv)509 JSTaggedValue ContainersArrayList::SubArrayList(EcmaRuntimeCallInfo *argv)
510 {
511 ASSERT(argv);
512 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, SubArrayList);
513 JSThread *thread = argv->GetThread();
514 [[maybe_unused]] EcmaHandleScope handleScope(thread);
515 JSHandle<JSTaggedValue> self = GetThis(argv);
516
517 if (!self->IsJSAPIArrayList()) {
518 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
519 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
520 } else {
521 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
522 "The subArrayList method cannot be bound");
523 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
524 }
525 }
526 JSHandle<JSTaggedValue> value1 = GetCallArg(argv, 0);
527 JSHandle<JSTaggedValue> value2 = GetCallArg(argv, 1);
528 if (!value1->IsInteger()) {
529 std::ostringstream oss;
530 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, value1);
531 CString errorMsg =
532 "The type of \"fromIndex\" must be number. Received value is: " + ConvertToString(*result);
533 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
534 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
535 }
536 if (!value2->IsInteger()) {
537 std::ostringstream oss;
538 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, value2);
539 CString errorMsg =
540 "The type of \"toIndex\" must be number. Received value is: " + ConvertToString(*result);
541 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
542 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
543 }
544 JSTaggedValue newArrayList =
545 JSAPIArrayList::SubArrayList(thread, JSHandle<JSAPIArrayList>::Cast(self), value1, value2);
546
547 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
548 return newArrayList;
549 }
550
Sort(EcmaRuntimeCallInfo * argv)551 JSTaggedValue ContainersArrayList::Sort(EcmaRuntimeCallInfo *argv)
552 {
553 ASSERT(argv);
554 BUILTINS_API_TRACE(argv->GetThread(), Array, Sort);
555 JSThread *thread = argv->GetThread();
556 [[maybe_unused]] EcmaHandleScope handleScope(thread);
557 JSHandle<JSTaggedValue> self = GetThis(argv);
558 if (!self->IsJSAPIArrayList()) {
559 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
560 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
561 } else {
562 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
563 "The sort method cannot be bound");
564 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
565 }
566 }
567 JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
568 if (!callbackFnHandle->IsUndefined() && !callbackFnHandle->IsCallable()) {
569 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, callbackFnHandle);
570 CString errorMsg =
571 "The type of \"comparator\" must be callable. Received value is: " + ConvertToString(*result);
572 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
573 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
574 }
575 JSHandle<TaggedArray> elements(thread, JSHandle<JSAPIArrayList>::Cast(self)->GetElements());
576 JSMutableHandle<JSTaggedValue> presentValue(thread, JSTaggedValue::Undefined());
577 JSMutableHandle<JSTaggedValue> middleValue(thread, JSTaggedValue::Undefined());
578 JSMutableHandle<JSTaggedValue> previousValue(thread, JSTaggedValue::Undefined());
579 uint32_t length = JSHandle<JSAPIArrayList>::Cast(self)->GetLength().GetArrayLength();
580 for (uint32_t i = 1; i < length; i++) {
581 uint32_t beginIndex = 0;
582 uint32_t endIndex = i;
583 presentValue.Update(elements->Get(i));
584 while (beginIndex < endIndex) {
585 uint32_t middleIndex = (beginIndex + endIndex) / 2; // 2 : half
586 middleValue.Update(elements->Get(middleIndex));
587 int32_t compareResult = base::ArrayHelper::SortCompare(thread, callbackFnHandle,
588 middleValue, presentValue);
589 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
590 if (compareResult > 0) {
591 endIndex = middleIndex;
592 } else {
593 beginIndex = middleIndex + 1;
594 }
595 }
596 if (endIndex >= 0 && endIndex < i) {
597 for (uint32_t j = i; j > endIndex; j--) {
598 previousValue.Update(elements->Get(j - 1));
599 elements->Set(thread, j, previousValue.GetTaggedValue());
600 }
601 elements->Set(thread, endIndex, presentValue.GetTaggedValue());
602 }
603 }
604 return JSTaggedValue::Undefined();
605 }
606
GetSize(EcmaRuntimeCallInfo * argv)607 JSTaggedValue ContainersArrayList::GetSize(EcmaRuntimeCallInfo *argv)
608 {
609 ASSERT(argv);
610 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, GetSize);
611 JSThread *thread = argv->GetThread();
612 [[maybe_unused]] EcmaHandleScope handleScope(thread);
613 JSHandle<JSTaggedValue> self = GetThis(argv);
614
615 if (!self->IsJSAPIArrayList()) {
616 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
617 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
618 } else {
619 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
620 "The getSize method cannot be bound");
621 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
622 }
623 }
624
625 return JSTaggedValue(JSHandle<JSAPIArrayList>::Cast(self)->GetSize());
626 }
627
ConvertToArray(EcmaRuntimeCallInfo * argv)628 JSTaggedValue ContainersArrayList::ConvertToArray(EcmaRuntimeCallInfo *argv)
629 {
630 ASSERT(argv);
631 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, ConvertToArray);
632 JSThread *thread = argv->GetThread();
633 [[maybe_unused]] EcmaHandleScope handleScope(thread);
634 JSHandle<JSTaggedValue> self = GetThis(argv);
635
636 if (!self->IsJSAPIArrayList()) {
637 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
638 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
639 } else {
640 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
641 "The convertToArray method cannot be bound");
642 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
643 }
644 }
645
646 JSHandle<JSAPIArrayList> arrayList = JSHandle<JSAPIArrayList>::Cast(self);
647 auto factory = thread->GetEcmaVM()->GetFactory();
648 JSHandle<JSArray> array = factory->NewJSArray();
649
650 uint32_t length = arrayList->GetLength().GetArrayLength();
651 array->SetArrayLength(thread, length);
652
653 JSHandle<TaggedArray> srcElements(thread, arrayList->GetElements());
654 JSHandle<TaggedArray> dstElements = factory->NewAndCopyTaggedArray(srcElements, length, length);
655 array->SetElements(thread, dstElements);
656 return array.GetTaggedValue();
657 }
658
ForEach(EcmaRuntimeCallInfo * argv)659 JSTaggedValue ContainersArrayList::ForEach(EcmaRuntimeCallInfo *argv)
660 {
661 ASSERT(argv);
662 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, ForEach);
663 JSThread *thread = argv->GetThread();
664 [[maybe_unused]] EcmaHandleScope handleScope(thread);
665 JSHandle<JSTaggedValue> self = GetThis(argv);
666
667 if (!self->IsJSAPIArrayList()) {
668 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
669 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
670 } else {
671 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
672 "The forEach method cannot be bound");
673 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
674 }
675 }
676
677 JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
678 if (!callbackFnHandle->IsCallable()) {
679 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, callbackFnHandle);
680 CString errorMsg =
681 "The type of \"callbackfn\" must be callable. Received value is: " + ConvertToString(*result);
682 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
683 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
684 }
685
686 JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1);
687
688 return JSAPIArrayList::ForEach(thread, self, callbackFnHandle, thisArgHandle);
689 }
690
GetIteratorObj(EcmaRuntimeCallInfo * argv)691 JSTaggedValue ContainersArrayList::GetIteratorObj(EcmaRuntimeCallInfo *argv)
692 {
693 ASSERT(argv);
694 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, GetIteratorObj);
695 JSThread *thread = argv->GetThread();
696 [[maybe_unused]] EcmaHandleScope handleScope(thread);
697
698 JSHandle<JSTaggedValue> self = GetThis(argv);
699
700 if (!self->IsJSAPIArrayList()) {
701 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
702 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
703 } else {
704 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
705 "The Symbol.iterator method cannot be bound");
706 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
707 }
708 }
709
710 JSTaggedValue values = JSAPIArrayList::GetIteratorObj(thread, JSHandle<JSAPIArrayList>::Cast(self));
711
712 return values;
713 }
714 } // namespace panda::ecmascript::containers
715