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/containers/containers_lightweightmap.h" 17 18#include "ecmascript/containers/containers_errors.h" 19#include "ecmascript/interpreter/interpreter.h" 20#include "ecmascript/js_api/js_api_lightweightmap.h" 21#include "ecmascript/js_api/js_api_lightweightmap_iterator.h" 22#include "ecmascript/js_function.h" 23 24namespace panda::ecmascript::containers { 25JSTaggedValue ContainersLightWeightMap::LightWeightMapConstructor(EcmaRuntimeCallInfo *argv) 26{ 27 ASSERT(argv != nullptr); 28 JSThread *thread = argv->GetThread(); 29 BUILTINS_API_TRACE(thread, LightWeightMap, Constructor); 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 LightWeightMap'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<JSAPILightWeightMap> lwMap = JSHandle<JSAPILightWeightMap>::Cast(obj); 43 JSHandle<TaggedArray> hashArray = factory->NewTaggedArray(JSAPILightWeightMap::DEFAULT_CAPACITY_LENGTH); 44 JSHandle<TaggedArray> keyArray = factory->NewTaggedArray(JSAPILightWeightMap::DEFAULT_CAPACITY_LENGTH); 45 JSHandle<TaggedArray> valueArray = factory->NewTaggedArray(JSAPILightWeightMap::DEFAULT_CAPACITY_LENGTH); 46 lwMap->SetHashes(thread, hashArray.GetTaggedValue()); 47 lwMap->SetKeys(thread, keyArray.GetTaggedValue()); 48 lwMap->SetValues(thread, valueArray.GetTaggedValue()); 49 50 return lwMap.GetTaggedValue(); 51} 52 53JSTaggedValue ContainersLightWeightMap::Length(EcmaRuntimeCallInfo *argv) 54{ 55 ASSERT(argv != nullptr); 56 JSThread *thread = argv->GetThread(); 57 BUILTINS_API_TRACE(thread, LightWeightMap, Length); 58 [[maybe_unused]] EcmaHandleScope handleScope(thread); 59 JSHandle<JSTaggedValue> self = GetThis(argv); 60 61 if (!self->IsJSAPILightWeightMap()) { 62 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) { 63 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 64 } else { 65 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 66 "The getLength method cannot be bound"); 67 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 68 } 69 } 70 71 return JSTaggedValue(JSHandle<JSAPILightWeightMap>::Cast(self)->GetLength()); 72} 73 74JSTaggedValue ContainersLightWeightMap::HasAll(EcmaRuntimeCallInfo *argv) 75{ 76 ASSERT(argv != nullptr); 77 JSThread *thread = argv->GetThread(); 78 BUILTINS_API_TRACE(thread, LightWeightMap, HasAll); 79 [[maybe_unused]] EcmaHandleScope handleScope(thread); 80 JSHandle<JSTaggedValue> self = GetThis(argv); 81 82 if (!self->IsJSAPILightWeightMap()) { 83 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) { 84 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 85 } else { 86 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 87 "The hasAll method cannot be bound"); 88 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 89 } 90 } 91 92 JSHandle<JSTaggedValue> lightWeightMap(GetCallArg(argv, 0)); 93 if (!lightWeightMap->IsJSAPILightWeightMap()) { 94 if (lightWeightMap->IsJSProxy() && 95 JSHandle<JSProxy>::Cast(lightWeightMap)->GetTarget().IsJSAPILightWeightMap()) { 96 lightWeightMap = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(lightWeightMap)->GetTarget()); 97 } else { 98 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, lightWeightMap.GetTaggedValue()); 99 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 100 CString errorMsg = 101 "The type of \"map\" must be LightWeightMap. Received value is: " + ConvertToString(*result); 102 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str()); 103 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 104 } 105 } 106 107 return JSAPILightWeightMap::HasAll(thread, JSHandle<JSAPILightWeightMap>::Cast(self), 108 JSHandle<JSAPILightWeightMap>::Cast(lightWeightMap)); 109} 110 111JSTaggedValue ContainersLightWeightMap::HasKey(EcmaRuntimeCallInfo *argv) 112{ 113 ASSERT(argv != nullptr); 114 JSThread *thread = argv->GetThread(); 115 BUILTINS_API_TRACE(thread, LightWeightMap, HasKey); 116 [[maybe_unused]] EcmaHandleScope handleScope(thread); 117 JSHandle<JSTaggedValue> self = GetThis(argv); 118 119 if (!self->IsJSAPILightWeightMap()) { 120 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) { 121 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 122 } else { 123 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 124 "The hasKey method cannot be bound"); 125 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 126 } 127 } 128 JSHandle<JSTaggedValue> key(GetCallArg(argv, 0)); 129 130 return JSAPILightWeightMap::HasKey(thread, JSHandle<JSAPILightWeightMap>::Cast(self), key); 131} 132 133JSTaggedValue ContainersLightWeightMap::HasValue(EcmaRuntimeCallInfo *argv) 134{ 135 ASSERT(argv != nullptr); 136 JSThread *thread = argv->GetThread(); 137 BUILTINS_API_TRACE(thread, LightWeightMap, HasValue); 138 [[maybe_unused]] EcmaHandleScope handleScope(thread); 139 JSHandle<JSTaggedValue> self = GetThis(argv); 140 141 if (!self->IsJSAPILightWeightMap()) { 142 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) { 143 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 144 } else { 145 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 146 "The hasValue method cannot be bound"); 147 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 148 } 149 } 150 151 JSHandle<JSTaggedValue> value(GetCallArg(argv, 0)); 152 return JSAPILightWeightMap::HasValue(thread, JSHandle<JSAPILightWeightMap>::Cast(self), value); 153} 154 155JSTaggedValue ContainersLightWeightMap::IncreaseCapacityTo(EcmaRuntimeCallInfo *argv) 156{ 157 ASSERT(argv != nullptr); 158 JSThread *thread = argv->GetThread(); 159 BUILTINS_API_TRACE(thread, LightWeightMap, IncreaseCapacityTo); 160 [[maybe_unused]] EcmaHandleScope handleScope(thread); 161 JSHandle<JSTaggedValue> self = GetThis(argv); 162 163 if (!self->IsJSAPILightWeightMap()) { 164 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) { 165 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 166 } else { 167 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 168 "The increaseCapacityTo method cannot be bound"); 169 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 170 } 171 } 172 173 JSHandle<JSTaggedValue> index(GetCallArg(argv, 0)); 174 175 // for case like Math.foor(1.3), it gives double 1.0; 176 if (index->IsDouble()) { 177 index = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(index->GetDouble())); 178 } 179 180 if (!index->IsInt()) { 181 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, index); 182 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 183 CString errorMsg = 184 "The type of \"minimumCapacity\" must be small integer. Received value is: " + ConvertToString(*result); 185 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str()); 186 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 187 } 188 JSAPILightWeightMap::IncreaseCapacityTo(thread, JSHandle<JSAPILightWeightMap>::Cast(self), 189 index->GetInt()); 190 191 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 192 return JSTaggedValue::Undefined(); 193} 194 195JSTaggedValue ContainersLightWeightMap::Entries(EcmaRuntimeCallInfo *argv) 196{ 197 ASSERT(argv != nullptr); 198 JSThread *thread = argv->GetThread(); 199 BUILTINS_API_TRACE(thread, LightWeightMap, Entries); 200 [[maybe_unused]] EcmaHandleScope handleScope(thread); 201 JSHandle<JSTaggedValue> self = GetThis(argv); 202 JSHandle<JSTaggedValue> iter = 203 JSAPILightWeightMapIterator::CreateLightWeightMapIterator(thread, self, IterationKind::KEY_AND_VALUE); 204 return iter.GetTaggedValue(); 205} 206 207JSTaggedValue ContainersLightWeightMap::Get(EcmaRuntimeCallInfo *argv) 208{ 209 ASSERT(argv != nullptr); 210 JSThread *thread = argv->GetThread(); 211 BUILTINS_API_TRACE(thread, LightWeightMap, Get); 212 [[maybe_unused]] EcmaHandleScope handleScope(thread); 213 JSHandle<JSTaggedValue> self = GetThis(argv); 214 215 if (!self->IsJSAPILightWeightMap()) { 216 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) { 217 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 218 } else { 219 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 220 "The get method cannot be bound"); 221 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 222 } 223 } 224 225 JSHandle<JSTaggedValue> key(GetCallArg(argv, 0)); 226 227 return JSAPILightWeightMap::Get(thread, JSHandle<JSAPILightWeightMap>::Cast(self), key); 228} 229 230JSTaggedValue ContainersLightWeightMap::GetIndexOfKey(EcmaRuntimeCallInfo *argv) 231{ 232 ASSERT(argv != nullptr); 233 JSThread *thread = argv->GetThread(); 234 BUILTINS_API_TRACE(thread, LightWeightMap, GetIndexOfKey); 235 [[maybe_unused]] EcmaHandleScope handleScope(thread); 236 JSHandle<JSTaggedValue> self = GetThis(argv); 237 238 if (!self->IsJSAPILightWeightMap()) { 239 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) { 240 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 241 } else { 242 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 243 "The getIndexOfKey method cannot be bound"); 244 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 245 } 246 } 247 248 JSHandle<JSTaggedValue> key(GetCallArg(argv, 0)); 249 250 int32_t index = JSAPILightWeightMap::GetIndexOfKey(thread, JSHandle<JSAPILightWeightMap>::Cast(self), key); 251 return JSTaggedValue(index); 252} 253 254JSTaggedValue ContainersLightWeightMap::GetIndexOfValue(EcmaRuntimeCallInfo *argv) 255{ 256 ASSERT(argv != nullptr); 257 JSThread *thread = argv->GetThread(); 258 BUILTINS_API_TRACE(thread, LightWeightMap, GetIndexOfValue); 259 [[maybe_unused]] EcmaHandleScope handleScope(thread); 260 JSHandle<JSTaggedValue> self = GetThis(argv); 261 262 if (!self->IsJSAPILightWeightMap()) { 263 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) { 264 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 265 } else { 266 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 267 "The getIndexOfValue method cannot be bound"); 268 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 269 } 270 } 271 272 JSHandle<JSTaggedValue> value(GetCallArg(argv, 0)); 273 274 int32_t index = JSAPILightWeightMap::GetIndexOfValue(thread, JSHandle<JSAPILightWeightMap>::Cast(self), value); 275 return JSTaggedValue(index); 276} 277 278JSTaggedValue ContainersLightWeightMap::IsEmpty(EcmaRuntimeCallInfo *argv) 279{ 280 ASSERT(argv != nullptr); 281 JSThread *thread = argv->GetThread(); 282 BUILTINS_API_TRACE(thread, LightWeightMap, IsEmpty); 283 [[maybe_unused]] EcmaHandleScope handleScope(thread); 284 JSHandle<JSTaggedValue> self = GetThis(argv); 285 286 if (!self->IsJSAPILightWeightMap()) { 287 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) { 288 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 289 } else { 290 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 291 "The isEmpty method cannot be bound"); 292 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 293 } 294 } 295 return JSHandle<JSAPILightWeightMap>::Cast(self)->IsEmpty(); 296} 297 298JSTaggedValue ContainersLightWeightMap::GetKeyAt(EcmaRuntimeCallInfo *argv) 299{ 300 ASSERT(argv != nullptr); 301 JSThread *thread = argv->GetThread(); 302 BUILTINS_API_TRACE(thread, LightWeightMap, GetKeyAt); 303 [[maybe_unused]] EcmaHandleScope handleScope(thread); 304 JSHandle<JSTaggedValue> self = GetThis(argv); 305 306 if (!self->IsJSAPILightWeightMap()) { 307 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) { 308 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 309 } else { 310 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 311 "The getKeyAt method cannot be bound"); 312 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 313 } 314 } 315 316 JSHandle<JSTaggedValue> index(GetCallArg(argv, 0)); 317 318 if (index->IsDouble()) { 319 index = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(index->GetDouble())); 320 } 321 if (!index->IsInt()) { 322 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, index); 323 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 324 CString errorMsg = 325 "The type of \"index\" must be small integer. Received value is: " + ConvertToString(*result); 326 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str()); 327 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 328 } 329 330 return JSAPILightWeightMap::GetKeyAt(thread, JSHandle<JSAPILightWeightMap>::Cast(self), 331 index->GetInt()); 332} 333 334JSTaggedValue ContainersLightWeightMap::Keys(EcmaRuntimeCallInfo *argv) 335{ 336 ASSERT(argv != nullptr); 337 JSThread *thread = argv->GetThread(); 338 BUILTINS_API_TRACE(thread, LightWeightMap, Keys); 339 [[maybe_unused]] EcmaHandleScope handleScope(thread); 340 JSHandle<JSTaggedValue> self = GetThis(argv); 341 JSHandle<JSTaggedValue> iter = 342 JSAPILightWeightMapIterator::CreateLightWeightMapIterator(thread, self, IterationKind::KEY); 343 return iter.GetTaggedValue(); 344} 345 346JSTaggedValue ContainersLightWeightMap::SetAll(EcmaRuntimeCallInfo *argv) 347{ 348 ASSERT(argv != nullptr); 349 JSThread *thread = argv->GetThread(); 350 BUILTINS_API_TRACE(thread, LightWeightMap, SetAll); 351 [[maybe_unused]] EcmaHandleScope handleScope(thread); 352 JSHandle<JSTaggedValue> self = GetThis(argv); 353 354 if (!self->IsJSAPILightWeightMap()) { 355 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) { 356 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 357 } else { 358 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 359 "The setAll method cannot be bound"); 360 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 361 } 362 } 363 364 JSHandle<JSTaggedValue> lightWeightMap(GetCallArg(argv, 0)); 365 366 if (!lightWeightMap->IsJSAPILightWeightMap()) { 367 if (lightWeightMap->IsJSProxy() && 368 JSHandle<JSProxy>::Cast(lightWeightMap)->GetTarget().IsJSAPILightWeightMap()) { 369 lightWeightMap = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(lightWeightMap)->GetTarget()); 370 } else { 371 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, lightWeightMap.GetTaggedValue()); 372 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 373 CString errorMsg = 374 "The type of \"map\" must be LightWeightMap. Received value is: " + ConvertToString(*result); 375 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str()); 376 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 377 } 378 } 379 380 JSAPILightWeightMap::SetAll(thread, JSHandle<JSAPILightWeightMap>::Cast(self), 381 JSHandle<JSAPILightWeightMap>::Cast(lightWeightMap)); 382 return JSTaggedValue::True(); 383} 384 385JSTaggedValue ContainersLightWeightMap::Set(EcmaRuntimeCallInfo *argv) 386{ 387 ASSERT(argv != nullptr); 388 JSThread *thread = argv->GetThread(); 389 BUILTINS_API_TRACE(thread, LightWeightMap, Set); 390 [[maybe_unused]] EcmaHandleScope handleScope(thread); 391 JSHandle<JSTaggedValue> self = GetThis(argv); 392 393 if (!self->IsJSAPILightWeightMap()) { 394 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) { 395 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 396 } else { 397 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 398 "The set method cannot be bound"); 399 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 400 } 401 } 402 403 JSHandle<JSTaggedValue> key(GetCallArg(argv, 0)); 404 JSHandle<JSTaggedValue> value(GetCallArg(argv, 1)); 405 JSHandle<JSAPILightWeightMap> lightWeightMap = JSHandle<JSAPILightWeightMap>::Cast(self); 406 JSAPILightWeightMap::Set(thread, lightWeightMap, key, value); 407 408 return lightWeightMap.GetTaggedValue(); 409} 410 411JSTaggedValue ContainersLightWeightMap::Remove(EcmaRuntimeCallInfo *argv) 412{ 413 ASSERT(argv != nullptr); 414 JSThread *thread = argv->GetThread(); 415 BUILTINS_API_TRACE(thread, LightWeightMap, Remove); 416 [[maybe_unused]] EcmaHandleScope handleScope(thread); 417 JSHandle<JSTaggedValue> self = GetThis(argv); 418 419 if (!self->IsJSAPILightWeightMap()) { 420 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) { 421 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 422 } else { 423 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 424 "The remove method cannot be bound"); 425 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 426 } 427 } 428 JSHandle<JSTaggedValue> key(GetCallArg(argv, 0)); 429 430 return JSAPILightWeightMap::Remove(thread, JSHandle<JSAPILightWeightMap>::Cast(self), key); 431} 432 433JSTaggedValue ContainersLightWeightMap::RemoveAt(EcmaRuntimeCallInfo *argv) 434{ 435 ASSERT(argv != nullptr); 436 JSThread *thread = argv->GetThread(); 437 BUILTINS_API_TRACE(thread, LightWeightMap, RemoveAt); 438 [[maybe_unused]] EcmaHandleScope handleScope(thread); 439 JSHandle<JSTaggedValue> self = GetThis(argv); 440 441 if (!self->IsJSAPILightWeightMap()) { 442 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) { 443 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 444 } else { 445 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 446 "The removeAt method cannot be bound"); 447 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 448 } 449 } 450 451 JSHandle<JSTaggedValue> index(GetCallArg(argv, 0)); 452 453 if (index->IsDouble()) { 454 index = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(index->GetDouble())); 455 } 456 if (!index->IsInt()) { 457 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, index); 458 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 459 CString errorMsg = 460 "The type of \"index\" must be small integer. Received value is: " + ConvertToString(*result); 461 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str()); 462 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 463 } 464 465 return JSAPILightWeightMap::RemoveAt(thread, JSHandle<JSAPILightWeightMap>::Cast(self), 466 index->GetInt()); 467} 468 469JSTaggedValue ContainersLightWeightMap::Clear(EcmaRuntimeCallInfo *argv) 470{ 471 ASSERT(argv != nullptr); 472 JSThread *thread = argv->GetThread(); 473 BUILTINS_API_TRACE(thread, LightWeightMap, Clear); 474 [[maybe_unused]] EcmaHandleScope handleScope(thread); 475 JSHandle<JSTaggedValue> self = GetThis(argv); 476 477 if (!self->IsJSAPILightWeightMap()) { 478 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) { 479 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 480 } else { 481 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 482 "The clear method cannot be bound"); 483 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 484 } 485 } 486 487 JSAPILightWeightMap::Clear(thread, JSHandle<JSAPILightWeightMap>::Cast(self)); 488 return JSTaggedValue::Undefined(); 489} 490 491JSTaggedValue ContainersLightWeightMap::SetValueAt(EcmaRuntimeCallInfo *argv) 492{ 493 ASSERT(argv != nullptr); 494 JSThread *thread = argv->GetThread(); 495 BUILTINS_API_TRACE(thread, LightWeightMap, SetValueAt); 496 [[maybe_unused]] EcmaHandleScope handleScope(thread); 497 JSHandle<JSTaggedValue> self = GetThis(argv); 498 499 if (!self->IsJSAPILightWeightMap()) { 500 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) { 501 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 502 } else { 503 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 504 "The setValueAt method cannot be bound"); 505 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 506 } 507 } 508 509 JSHandle<JSTaggedValue> index(GetCallArg(argv, 0)); 510 JSHandle<JSTaggedValue> value(GetCallArg(argv, 1)); 511 if (index->IsDouble()) { 512 index = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(index->GetDouble())); 513 } 514 if (!index->IsInt()) { 515 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, index); 516 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 517 CString errorMsg = 518 "The type of \"index\" must be small integer. Received value is: " + ConvertToString(*result); 519 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str()); 520 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 521 } 522 523 return JSAPILightWeightMap::SetValueAt(thread, JSHandle<JSAPILightWeightMap>::Cast(self), 524 index->GetInt(), value); 525} 526 527JSTaggedValue ContainersLightWeightMap::ForEach(EcmaRuntimeCallInfo *argv) 528{ 529 ASSERT(argv != nullptr); 530 JSThread *thread = argv->GetThread(); 531 BUILTINS_API_TRACE(thread, LightWeightMap, ForEach); 532 [[maybe_unused]] EcmaHandleScope handleScope(thread); 533 // get and check lightweightmap object 534 JSHandle<JSTaggedValue> self = GetThis(argv); 535 if (!self->IsJSAPILightWeightMap()) { 536 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) { 537 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 538 } else { 539 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 540 "The forEach method cannot be bound"); 541 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 542 } 543 } 544 // get and check callback function 545 JSHandle<JSTaggedValue> func(GetCallArg(argv, 0)); 546 if (!func->IsCallable()) { 547 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, func.GetTaggedValue()); 548 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 549 CString errorMsg = 550 "The type of \"callbackfn\" must be callable. Received value is: " + ConvertToString(*result); 551 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str()); 552 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 553 } 554 // If thisArg was supplied, let T be thisArg; else let T be undefined. 555 JSHandle<JSTaggedValue> thisArg = GetCallArg(argv, 1); 556 JSHandle<JSAPILightWeightMap> tmap = JSHandle<JSAPILightWeightMap>::Cast(self); 557 JSMutableHandle<TaggedArray> keys(thread, tmap->GetKeys()); 558 JSMutableHandle<TaggedArray> values(thread, tmap->GetValues()); 559 560 uint32_t index = 0; 561 uint32_t length = tmap->GetSize(); 562 const uint32_t argsLength = 3; 563 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined(); 564 while (index < length) { 565 // ignore the hash value is required to determine the true index 566 // Let funcResult be Call(callbackfn, T, «e, e, S»). 567 EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo(thread, func, thisArg, undefined, argsLength); 568 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 569 info->SetCallArg(values->Get(index), keys->Get(index), self.GetTaggedValue()); 570 JSTaggedValue ret = JSFunction::Call(info); 571 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ret); 572 573 // check entries should be update, size will be update in tmap set or remove. 574 if (tmap->GetSize() != length) { 575 keys.Update(tmap->GetKeys()); 576 values.Update(tmap->GetValues()); 577 length = tmap->GetSize(); 578 } 579 index++; 580 } 581 return JSTaggedValue::Undefined(); 582} 583 584JSTaggedValue ContainersLightWeightMap::ToString(EcmaRuntimeCallInfo *argv) 585{ 586 ASSERT(argv != nullptr); 587 JSThread *thread = argv->GetThread(); 588 BUILTINS_API_TRACE(thread, LightWeightMap, ToString); 589 [[maybe_unused]] EcmaHandleScope handleScope(thread); 590 JSHandle<JSTaggedValue> self = GetThis(argv); 591 592 if (!self->IsJSAPILightWeightMap()) { 593 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) { 594 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 595 } else { 596 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 597 "The toString method cannot be bound"); 598 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 599 } 600 } 601 602 return JSAPILightWeightMap::ToString(thread, JSHandle<JSAPILightWeightMap>::Cast(self)); 603} 604 605JSTaggedValue ContainersLightWeightMap::GetValueAt(EcmaRuntimeCallInfo *argv) 606{ 607 ASSERT(argv != nullptr); 608 JSThread *thread = argv->GetThread(); 609 BUILTINS_API_TRACE(thread, LightWeightMap, GetValueAt); 610 [[maybe_unused]] EcmaHandleScope handleScope(thread); 611 JSHandle<JSTaggedValue> self = GetThis(argv); 612 613 if (!self->IsJSAPILightWeightMap()) { 614 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) { 615 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 616 } else { 617 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 618 "The getValueAt method cannot be bound"); 619 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 620 } 621 } 622 JSHandle<JSTaggedValue> index(GetCallArg(argv, 0)); 623 if (index->IsDouble()) { 624 index = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(index->GetDouble())); 625 } 626 if (!index->IsInt()) { 627 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, index); 628 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 629 CString errorMsg = 630 "The type of \"index\" must be small integer. Received value is: " + ConvertToString(*result); 631 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str()); 632 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 633 } 634 635 if (index->IsDouble()) { 636 index = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(index->GetDouble())); 637 } 638 return JSAPILightWeightMap::GetValueAt(thread, JSHandle<JSAPILightWeightMap>::Cast(self), 639 index->GetInt()); 640} 641 642JSTaggedValue ContainersLightWeightMap::Values(EcmaRuntimeCallInfo *argv) 643{ 644 ASSERT(argv != nullptr); 645 JSThread *thread = argv->GetThread(); 646 BUILTINS_API_TRACE(thread, LightWeightMap, Keys); 647 [[maybe_unused]] EcmaHandleScope handleScope(thread); 648 JSHandle<JSTaggedValue> self = GetThis(argv); 649 JSHandle<JSTaggedValue> iter = 650 JSAPILightWeightMapIterator::CreateLightWeightMapIterator(thread, self, IterationKind::VALUE); 651 return iter.GetTaggedValue(); 652} 653} // namespace panda::ecmascript::containers 654