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