/* * Copyright (c) 2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "ecmascript/containers/containers_lightweightmap.h" #include "ecmascript/base/array_helper.h" #include "ecmascript/base/number_helper.h" #include "ecmascript/base/typed_array_helper.h" #include "ecmascript/base/typed_array_helper-inl.h" #include "ecmascript/containers/containers_errors.h" #include "ecmascript/ecma_vm.h" #include "ecmascript/interpreter/interpreter.h" #include "ecmascript/js_api/js_api_lightweightmap.h" #include "ecmascript/js_api/js_api_lightweightmap_iterator.h" #include "ecmascript/js_array.h" #include "ecmascript/object_factory.h" #include "ecmascript/tagged_array-inl.h" namespace panda::ecmascript::containers { JSTaggedValue ContainersLightWeightMap::LightWeightMapConstructor(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, LightWeightMap, Constructor); [[maybe_unused]] EcmaHandleScope handleScope(thread); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle newTarget = GetNewTarget(argv); if (newTarget->IsUndefined()) { JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::IS_NULL_ERROR, "The LightWeightMap's constructor cannot be directly invoked"); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } JSHandle constructor = GetConstructor(argv); JSHandle obj = factory->NewJSObjectByConstructor(JSHandle(constructor), newTarget); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle lwMap = JSHandle::Cast(obj); JSHandle hashArray = factory->NewTaggedArray(JSAPILightWeightMap::DEFAULT_CAPACITY_LENGTH); JSHandle keyArray = factory->NewTaggedArray(JSAPILightWeightMap::DEFAULT_CAPACITY_LENGTH); JSHandle valueArray = factory->NewTaggedArray(JSAPILightWeightMap::DEFAULT_CAPACITY_LENGTH); lwMap->SetHashes(thread, hashArray.GetTaggedValue()); lwMap->SetKeys(thread, keyArray.GetTaggedValue()); lwMap->SetValues(thread, valueArray.GetTaggedValue()); return lwMap.GetTaggedValue(); } JSTaggedValue ContainersLightWeightMap::Length(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, LightWeightMap, Length); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPILightWeightMap()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPILightWeightMap()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, "The length method cannot be bound"); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } } return JSTaggedValue(JSHandle::Cast(self)->GetLength()); } JSTaggedValue ContainersLightWeightMap::HasAll(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, LightWeightMap, HasAll); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPILightWeightMap()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPILightWeightMap()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, "The hasAll method cannot be bound"); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } } JSHandle lightWeightMap(GetCallArg(argv, 0)); if (!lightWeightMap->IsJSAPILightWeightMap()) { if (lightWeightMap->IsJSProxy() && JSHandle::Cast(lightWeightMap)->GetTarget().IsJSAPILightWeightMap()) { lightWeightMap = JSHandle(thread, JSHandle::Cast(lightWeightMap)->GetTarget()); } else { JSHandle result = JSTaggedValue::ToString(thread, lightWeightMap.GetTaggedValue()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); CString errorMsg = "The type of \"map\" must be LightWeightMap. Received value is: " + ConvertToString(*result); JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str()); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } } return JSAPILightWeightMap::HasAll(thread, JSHandle::Cast(self), JSHandle::Cast(lightWeightMap)); } JSTaggedValue ContainersLightWeightMap::HasKey(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, LightWeightMap, HasKey); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPILightWeightMap()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPILightWeightMap()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, "The hasKey method cannot be bound"); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } } JSHandle key(GetCallArg(argv, 0)); return JSAPILightWeightMap::HasKey(thread, JSHandle::Cast(self), key); } JSTaggedValue ContainersLightWeightMap::HasValue(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, LightWeightMap, HasValue); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPILightWeightMap()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPILightWeightMap()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, "The hasValue method cannot be bound"); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } } JSHandle value(GetCallArg(argv, 0)); return JSAPILightWeightMap::HasValue(thread, JSHandle::Cast(self), value); } JSTaggedValue ContainersLightWeightMap::IncreaseCapacityTo(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, LightWeightMap, IncreaseCapacityTo); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPILightWeightMap()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPILightWeightMap()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, "The increaseCapacityTo method cannot be bound"); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } } JSHandle index(GetCallArg(argv, 0)); if (!index->IsInt()) { JSHandle result = JSTaggedValue::ToString(thread, index); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); CString errorMsg = "The type of \"minimumCapacity\" must be number. Received value is: " + ConvertToString(*result); JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str()); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } JSAPILightWeightMap::IncreaseCapacityTo(thread, JSHandle::Cast(self), index.GetTaggedValue().GetInt()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return JSTaggedValue::Undefined(); } JSTaggedValue ContainersLightWeightMap::Entries(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, LightWeightMap, Entries); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); JSHandle iter = JSAPILightWeightMapIterator::CreateLightWeightMapIterator(thread, self, IterationKind::KEY_AND_VALUE); return iter.GetTaggedValue(); } JSTaggedValue ContainersLightWeightMap::Get(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, LightWeightMap, Get); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPILightWeightMap()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPILightWeightMap()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, "The get method cannot be bound"); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } } JSHandle key(GetCallArg(argv, 0)); return JSAPILightWeightMap::Get(thread, JSHandle::Cast(self), key); } JSTaggedValue ContainersLightWeightMap::GetIndexOfKey(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, LightWeightMap, GetIndexOfKey); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPILightWeightMap()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPILightWeightMap()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, "The getIndexOfKey method cannot be bound"); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } } JSHandle key(GetCallArg(argv, 0)); int32_t index = JSAPILightWeightMap::GetIndexOfKey(thread, JSHandle::Cast(self), key); return JSTaggedValue(index); } JSTaggedValue ContainersLightWeightMap::GetIndexOfValue(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, LightWeightMap, GetIndexOfValue); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPILightWeightMap()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPILightWeightMap()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, "The getIndexOfValue method cannot be bound"); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } } JSHandle value(GetCallArg(argv, 0)); int32_t index = JSAPILightWeightMap::GetIndexOfValue(thread, JSHandle::Cast(self), value); return JSTaggedValue(index); } JSTaggedValue ContainersLightWeightMap::IsEmpty(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, LightWeightMap, IsEmpty); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPILightWeightMap()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPILightWeightMap()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, "The isEmpty method cannot be bound"); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } } return JSHandle::Cast(self)->IsEmpty(); } JSTaggedValue ContainersLightWeightMap::GetKeyAt(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, LightWeightMap, GetKeyAt); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPILightWeightMap()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPILightWeightMap()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, "The getKeyAt method cannot be bound"); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } } JSHandle index(GetCallArg(argv, 0)); if (!index->IsInt()) { JSHandle result = JSTaggedValue::ToString(thread, index); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); CString errorMsg = "The type of \"index\" must be number. Received value is: " + ConvertToString(*result); JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str()); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } return JSAPILightWeightMap::GetKeyAt(thread, JSHandle::Cast(self), index->GetInt()); } JSTaggedValue ContainersLightWeightMap::Keys(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, LightWeightMap, Keys); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); JSHandle iter = JSAPILightWeightMapIterator::CreateLightWeightMapIterator(thread, self, IterationKind::KEY); return iter.GetTaggedValue(); } JSTaggedValue ContainersLightWeightMap::SetAll(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, LightWeightMap, SetAll); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPILightWeightMap()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPILightWeightMap()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, "The setAll method cannot be bound"); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } } JSHandle lightWeightMap(GetCallArg(argv, 0)); if (!lightWeightMap->IsJSAPILightWeightMap()) { if (lightWeightMap->IsJSProxy() && JSHandle::Cast(lightWeightMap)->GetTarget().IsJSAPILightWeightMap()) { lightWeightMap = JSHandle(thread, JSHandle::Cast(lightWeightMap)->GetTarget()); } else { JSHandle result = JSTaggedValue::ToString(thread, lightWeightMap.GetTaggedValue()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); CString errorMsg = "The type of \"map\" must be LightWeightMap. Received value is: " + ConvertToString(*result); JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str()); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } } JSAPILightWeightMap::SetAll(thread, JSHandle::Cast(self), JSHandle::Cast(lightWeightMap)); return JSTaggedValue::True(); } JSTaggedValue ContainersLightWeightMap::Set(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, LightWeightMap, Set); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPILightWeightMap()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPILightWeightMap()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, "The set method cannot be bound"); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } } JSHandle key(GetCallArg(argv, 0)); JSHandle value(GetCallArg(argv, 1)); JSAPILightWeightMap::Set(thread, JSHandle::Cast(self), key, value); return JSTaggedValue::True(); } JSTaggedValue ContainersLightWeightMap::Remove(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, LightWeightMap, Remove); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPILightWeightMap()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPILightWeightMap()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, "The remove method cannot be bound"); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } } JSHandle key(GetCallArg(argv, 0)); return JSAPILightWeightMap::Remove(thread, JSHandle::Cast(self), key); } JSTaggedValue ContainersLightWeightMap::RemoveAt(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, LightWeightMap, RemoveAt); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPILightWeightMap()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPILightWeightMap()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, "The removeAt method cannot be bound"); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } } JSHandle index(GetCallArg(argv, 0)); if (!index->IsInt()) { JSHandle result = JSTaggedValue::ToString(thread, index); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); CString errorMsg = "The type of \"index\" must be number. Received value is: " + ConvertToString(*result); JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str()); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } return JSAPILightWeightMap::RemoveAt(thread, JSHandle::Cast(self), index->GetInt()); } JSTaggedValue ContainersLightWeightMap::Clear(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, LightWeightMap, Clear); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPILightWeightMap()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPILightWeightMap()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, "The clear method cannot be bound"); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } } JSAPILightWeightMap::Clear(thread, JSHandle::Cast(self)); return JSTaggedValue::True(); } JSTaggedValue ContainersLightWeightMap::SetValueAt(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, LightWeightMap, SetValueAt); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPILightWeightMap()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPILightWeightMap()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, "The setValueAt method cannot be bound"); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } } JSHandle index(GetCallArg(argv, 0)); JSHandle value(GetCallArg(argv, 1)); if (!index->IsInt()) { JSHandle result = JSTaggedValue::ToString(thread, index); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); CString errorMsg = "The type of \"index\" must be number. Received value is: " + ConvertToString(*result); JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str()); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } return JSAPILightWeightMap::SetValueAt(thread, JSHandle::Cast(self), index->GetInt(), value); } JSTaggedValue ContainersLightWeightMap::ForEach(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, LightWeightMap, ForEach); [[maybe_unused]] EcmaHandleScope handleScope(thread); // get and check lightweightmap object JSHandle self = GetThis(argv); if (!self->IsJSAPILightWeightMap()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPILightWeightMap()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, "The forEach method cannot be bound"); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } } // get and check callback function JSHandle func(GetCallArg(argv, 0)); if (!func->IsCallable()) { JSHandle result = JSTaggedValue::ToString(thread, func.GetTaggedValue()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); CString errorMsg = "The type of \"callbackfn\" must be callable. Received value is: " + ConvertToString(*result); JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str()); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } // If thisArg was supplied, let T be thisArg; else let T be undefined. JSHandle thisArg = GetCallArg(argv, 1); JSHandle tmap = JSHandle::Cast(self); JSMutableHandle keys(thread, tmap->GetKeys()); JSMutableHandle values(thread, tmap->GetValues()); uint32_t index = 0; uint32_t length = tmap->GetSize(); const uint32_t argsLength = 3; JSHandle undefined = thread->GlobalConstants()->GetHandledUndefined(); while (index < length) { // ignore the hash value is required to determine the true index // Let funcResult be Call(callbackfn, T, «e, e, S»). EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo(thread, func, thisArg, undefined, argsLength); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); info->SetCallArg(values->Get(index), keys->Get(index), self.GetTaggedValue()); JSTaggedValue ret = JSFunction::Call(info); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ret); // check entries should be update, size will be update in tmap set or remove. if (tmap->GetSize() != length) { keys.Update(tmap->GetKeys()); values.Update(tmap->GetValues()); length = tmap->GetSize(); } index++; } return JSTaggedValue::Undefined(); } JSTaggedValue ContainersLightWeightMap::ToString(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, LightWeightMap, ToString); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPILightWeightMap()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPILightWeightMap()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, "The toString method cannot be bound"); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } } return JSAPILightWeightMap::ToString(thread, JSHandle::Cast(self)); } JSTaggedValue ContainersLightWeightMap::GetValueAt(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, LightWeightMap, GetValueAt); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPILightWeightMap()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPILightWeightMap()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, "The getValueAt method cannot be bound"); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } } JSHandle index(GetCallArg(argv, 0)); if (!index->IsInt()) { JSHandle result = JSTaggedValue::ToString(thread, index); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); CString errorMsg = "The type of \"index\" must be number. Received value is: " + ConvertToString(*result); JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str()); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } return JSAPILightWeightMap::GetValueAt(thread, JSHandle::Cast(self), index->GetInt()); } JSTaggedValue ContainersLightWeightMap::Values(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, LightWeightMap, Keys); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); JSHandle iter = JSAPILightWeightMapIterator::CreateLightWeightMapIterator(thread, self, IterationKind::VALUE); return iter.GetTaggedValue(); } } // namespace panda::ecmascript::containers