/* * 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_vector.h" #include "ecmascript/base/array_helper.h" #include "ecmascript/base/number_helper.h" #include "ecmascript/base/typed_array_helper-inl.h" #include "ecmascript/base/typed_array_helper.h" #include "ecmascript/ecma_vm.h" #include "ecmascript/js_array.h" #include "ecmascript/js_api/js_api_vector.h" #include "ecmascript/object_factory.h" #include "ecmascript/tagged_array-inl.h" namespace panda::ecmascript::containers { JSTaggedValue ContainersVector::VectorConstructor(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, Vector, Constructor); [[maybe_unused]] EcmaHandleScope handleScope(thread); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle newTarget = GetNewTarget(argv); if (newTarget->IsUndefined()) { THROW_TYPE_ERROR_AND_RETURN(thread, "new target can't be undefined", JSTaggedValue::Exception()); } JSHandle constructor = GetConstructor(argv); JSHandle obj = JSHandle(factory->NewJSObjectByConstructor(JSHandle(constructor), newTarget)); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle newTaggedArray = factory->NewTaggedArray(JSAPIVector::DEFAULT_CAPACITY_LENGTH); obj->SetElements(thread, newTaggedArray); return obj.GetTaggedValue(); } JSTaggedValue ContainersVector::Add(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, Vector, Add); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPIVector()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPIVector()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIVector", JSTaggedValue::Exception()); } } JSHandle value(GetCallArg(argv, 0)); JSAPIVector::Add(thread, JSHandle::Cast(self), value); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return JSTaggedValue::True(); } JSTaggedValue ContainersVector::Insert(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, Vector, Insert); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPIVector()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPIVector()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIVector", JSTaggedValue::Exception()); } } JSHandle value = GetCallArg(argv, 0); JSHandle index = GetCallArg(argv, 1); if (!index->IsNumber()) { THROW_TYPE_ERROR_AND_RETURN(thread, "The passed in index needs to be number", JSTaggedValue::Exception()); } int32_t indexInt = JSTaggedValue::ToInt32(thread, index); JSAPIVector::Insert(thread, JSHandle::Cast(self), value, indexInt); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return JSTaggedValue::Undefined(); } JSTaggedValue ContainersVector::SetLength(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, Vector, SetLength); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPIVector()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPIVector()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIVector", JSTaggedValue::Exception()); } } JSHandle newSize = GetCallArg(argv, 0); if (!newSize->IsNumber()) { THROW_TYPE_ERROR_AND_RETURN(thread, "The passed in parameter needs to be number", JSTaggedValue::Exception()); } if (newSize->GetNumber() < 0) { THROW_RANGE_ERROR_AND_RETURN(thread, "An incorrect size was set", JSTaggedValue::Exception()); } JSAPIVector::SetLength(thread, JSHandle::Cast(self), JSTaggedValue::ToUint32(thread, newSize)); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return JSTaggedValue::Undefined(); } JSTaggedValue ContainersVector::GetCapacity(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, Vector, GetCapacity); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPIVector()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPIVector()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIVector", JSTaggedValue::Exception()); } } uint32_t capacity = JSHandle::Cast(self)->GetCapacity(); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return JSTaggedValue(capacity); } JSTaggedValue ContainersVector::IncreaseCapacityTo(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, Vector, IncreaseCapacityTo); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPIVector()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPIVector()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIVector", JSTaggedValue::Exception()); } } JSHandle newCapacity = GetCallArg(argv, 0); if (!newCapacity->IsNumber()) { THROW_TYPE_ERROR_AND_RETURN(thread, "The passed in parameter needs to be number", JSTaggedValue::Exception()); } JSAPIVector::IncreaseCapacityTo(thread, JSHandle::Cast(self), JSTaggedValue::ToInt32(thread, newCapacity)); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return JSTaggedValue::Undefined(); } JSTaggedValue ContainersVector::Get(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, Vector, Get); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPIVector()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPIVector()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIVector", JSTaggedValue::Exception()); } } JSHandle index = GetCallArg(argv, 0); if (!index->IsNumber()) { THROW_TYPE_ERROR_AND_RETURN(thread, "The passed in index needs to be number", JSTaggedValue::Exception()); } int32_t indexInt = JSTaggedValue::ToInt32(thread, index); JSTaggedValue value = JSAPIVector::Get(thread, JSHandle::Cast(self), indexInt); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return value; } JSTaggedValue ContainersVector::GetIndexOf(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, Vector, GetIndexOf); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPIVector()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPIVector()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIVector", JSTaggedValue::Exception()); } } JSHandle element = GetCallArg(argv, 0); int index = JSAPIVector::GetIndexOf(thread, JSHandle::Cast(self), element); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return JSTaggedValue(index); } JSTaggedValue ContainersVector::GetIndexFrom(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, Vector, GetIndexFrom); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPIVector()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPIVector()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIVector", JSTaggedValue::Exception()); } } JSHandle element = GetCallArg(argv, 0); JSHandle index = GetCallArg(argv, 1); if (!index->IsNumber()) { THROW_TYPE_ERROR_AND_RETURN(thread, "The passed in index needs to be number", JSTaggedValue::Exception()); } int32_t indexInt = JSTaggedValue::ToInt32(thread, index); int indexOut = JSAPIVector::GetIndexFrom(thread, JSHandle::Cast(self), element, indexInt); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return JSTaggedValue(indexOut); } JSTaggedValue ContainersVector::IsEmpty(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, Vector, IsEmpty); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPIVector()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPIVector()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIVector", JSTaggedValue::Exception()); } } bool ret = JSHandle::Cast(self)->IsEmpty(); return GetTaggedBoolean(ret); } JSTaggedValue ContainersVector::GetLastElement(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, Vector, GetLastElement); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPIVector()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPIVector()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIVector", JSTaggedValue::Exception()); } } JSTaggedValue value = JSHandle::Cast(self)->GetLastElement(); return value; } JSTaggedValue ContainersVector::GetLastIndexOf(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, Vector, GetLastIndexOf); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPIVector()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPIVector()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIVector", JSTaggedValue::Exception()); } } JSHandle element = GetCallArg(argv, 0); int index = JSAPIVector::GetLastIndexOf(thread, JSHandle::Cast(self), element); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return JSTaggedValue(index); } JSTaggedValue ContainersVector::GetLastIndexFrom(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, Vector, GetLastIndexFrom); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPIVector()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPIVector()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIVector", JSTaggedValue::Exception()); } } JSHandle element = GetCallArg(argv, 0); JSHandle index = GetCallArg(argv, 1); if (!index->IsNumber()) { THROW_TYPE_ERROR_AND_RETURN(thread, "The passed in index needs to be number", JSTaggedValue::Exception()); } int32_t indexInt = JSTaggedValue::ToInt32(thread, index); int indexOut = JSAPIVector::GetLastIndexFrom(thread, JSHandle::Cast(self), element, indexInt); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return JSTaggedValue(indexOut); } JSTaggedValue ContainersVector::Remove(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, Vector, Remove); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPIVector()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPIVector()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIVector", JSTaggedValue::Exception()); } } JSHandle element = GetCallArg(argv, 0); bool ret = JSAPIVector::Remove(thread, JSHandle::Cast(self), element); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return GetTaggedBoolean(ret); } JSTaggedValue ContainersVector::RemoveByIndex(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, Vector, RemoveByIndex); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPIVector()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPIVector()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIVector", JSTaggedValue::Exception()); } } JSHandle index = GetCallArg(argv, 0); if (!index->IsNumber()) { THROW_TYPE_ERROR_AND_RETURN(thread, "The passed in index needs to be number", JSTaggedValue::Exception()); } JSTaggedValue value = JSAPIVector::RemoveByIndex(thread, JSHandle::Cast(self), JSTaggedValue::ToInt32(thread, index)); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return value; } JSTaggedValue ContainersVector::RemoveByRange(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, Vector, RemoveByRange); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPIVector()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPIVector()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIVector", JSTaggedValue::Exception()); } } JSHandle fromIndex = GetCallArg(argv, 0); JSHandle toIndex = GetCallArg(argv, 1); if (!fromIndex->IsNumber() || !toIndex->IsNumber()) { THROW_TYPE_ERROR_AND_RETURN(thread, "The passed in parameter needs to be number", JSTaggedValue::Exception()); } JSAPIVector::RemoveByRange(thread, JSHandle::Cast(self), JSTaggedValue::ToInt32(thread, fromIndex), JSTaggedValue::ToInt32(thread, toIndex)); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return JSTaggedValue::Undefined(); } JSTaggedValue ContainersVector::Set(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, Vector, Set); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPIVector()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPIVector()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIVector", JSTaggedValue::Exception()); } } JSHandle index = GetCallArg(argv, 0); JSHandle element = GetCallArg(argv, 1); if (!index->IsNumber()) { THROW_TYPE_ERROR_AND_RETURN(thread, "The passed in index needs to be number", JSTaggedValue::Exception()); } int32_t indexInt = JSTaggedValue::ToInt32(thread, index); int32_t len = static_cast(JSHandle::Cast(self)->GetSize()); if (indexInt < 0 || indexInt >= len) { THROW_RANGE_ERROR_AND_RETURN(thread, "the index is out-of-bounds", JSTaggedValue::Exception()); } JSTaggedValue value = JSHandle::Cast(self)->Set(thread, indexInt, element.GetTaggedValue()); return value; } JSTaggedValue ContainersVector::SubVector(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, Vector, SubVector); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPIVector()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPIVector()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIVector", JSTaggedValue::Exception()); } } JSHandle fromIndex = GetCallArg(argv, 0); JSHandle toIndex = GetCallArg(argv, 1); if (!fromIndex->IsNumber() || !toIndex->IsNumber()) { THROW_TYPE_ERROR_AND_RETURN(thread, "The passed in parameter needs to be number", JSTaggedValue::Exception()); } JSHandle subVector = JSAPIVector::SubVector(thread, JSHandle::Cast(self), JSTaggedValue::ToInt32(thread, fromIndex), JSTaggedValue::ToInt32(thread, toIndex)); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return subVector.GetTaggedValue(); } JSTaggedValue ContainersVector::ToString(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, Vector, ToString); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPIVector()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPIVector()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIVector", JSTaggedValue::Exception()); } } JSTaggedValue value = JSAPIVector::ToString(thread, JSHandle::Cast(self)); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return value; } JSTaggedValue ContainersVector::GetSize(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, Vector, GetSize); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPIVector()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPIVector()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIVector", JSTaggedValue::Exception()); } } int32_t length = JSHandle::Cast(self)->GetSize(); return JSTaggedValue(length); } JSTaggedValue ContainersVector::ForEach(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, Vector, ForEach); [[maybe_unused]] EcmaHandleScope handleScope(thread); // Let O be ToObject(this value). JSHandle thisHandle = GetThis(argv); // JSAPIVector if (!thisHandle->IsJSAPIVector()) { if (thisHandle->IsJSProxy() && JSHandle::Cast(thisHandle)->GetTarget().IsJSAPIVector()) { thisHandle = JSHandle(thread, JSHandle::Cast(thisHandle)->GetTarget()); } else { THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIVector", JSTaggedValue::Exception()); } } // If IsCallable(callbackfn) is false, throw a TypeError exception. JSHandle callbackFnHandle = GetCallArg(argv, 0); if (!callbackFnHandle->IsCallable()) { THROW_TYPE_ERROR_AND_RETURN(thread, "the callbackfun is not callable.", JSTaggedValue::Exception()); } // If thisArg was supplied, let T be thisArg; else let T be undefined. JSHandle thisArgHandle = GetCallArg(argv, 1); return JSAPIVector::ForEach(thread, thisHandle, callbackFnHandle, thisArgHandle); } JSTaggedValue ContainersVector::ReplaceAllElements(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, Vector, ReplaceAllElements); [[maybe_unused]] EcmaHandleScope handleScope(thread); // Let O be ToObject(this value). JSHandle thisHandle = GetThis(argv); // JSAPIVector if (!thisHandle->IsJSAPIVector()) { if (thisHandle->IsJSProxy() && JSHandle::Cast(thisHandle)->GetTarget().IsJSAPIVector()) { thisHandle = JSHandle(thread, JSHandle::Cast(thisHandle)->GetTarget()); } else { THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIVector", JSTaggedValue::Exception()); } } // If IsCallable(callbackfn) is false, throw a TypeError exception. JSHandle callbackFnHandle = GetCallArg(argv, 0); if (!callbackFnHandle->IsCallable()) { THROW_TYPE_ERROR_AND_RETURN(thread, "the callbackfun is not callable.", JSTaggedValue::Exception()); } // If thisArg was supplied, let T be thisArg; else let T be undefined. JSHandle thisArgHandle = GetCallArg(argv, 1); return JSAPIVector::ReplaceAllElements(thread, thisHandle, callbackFnHandle, thisArgHandle); } JSTaggedValue ContainersVector::TrimToCurrentLength(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, Vector, TrimToCurrentLength); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPIVector()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPIVector()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIVector", JSTaggedValue::Exception()); } } JSAPIVector::TrimToCurrentLength(thread, JSHandle::Cast(self)); return JSTaggedValue::True(); } JSTaggedValue ContainersVector::Clear(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, Vector, Clear); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPIVector()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPIVector()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIVector", JSTaggedValue::Exception()); } } JSAPIVector::Clear(thread, JSHandle::Cast(self)); return JSTaggedValue::True(); } JSTaggedValue ContainersVector::Clone(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, Vector, Clone); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPIVector()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPIVector()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIVector", JSTaggedValue::Exception()); } } JSHandle newVector = JSAPIVector::Clone(thread, JSHandle::Cast(self)); return newVector.GetTaggedValue(); } JSTaggedValue ContainersVector::Has(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, Vector, Has); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPIVector()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPIVector()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIVector", JSTaggedValue::Exception()); } } JSHandle value(GetCallArg(argv, 0)); bool isHas = JSHandle::Cast(self)->Has(value.GetTaggedValue()); return GetTaggedBoolean(isHas); } JSTaggedValue ContainersVector::CopyToArray(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, Vector, CopyToArray); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPIVector()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPIVector()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIVector", JSTaggedValue::Exception()); } } JSHandle arg0(GetCallArg(argv, 0)); if (!arg0->IsJSArray()) { return JSTaggedValue::False(); } JSHandle vector = JSHandle::Cast(self); JSHandle vectorElements(thread, vector->GetElements()); uint32_t vectorLength = static_cast(vector->GetSize()); JSHandle array = JSHandle::Cast(arg0); JSHandle arrayElements(thread, array->GetElements()); uint32_t arrayLength = array->GetArrayLength(); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); if (vectorLength <= arrayLength) { factory->CopyTaggedArrayElement(vectorElements, arrayElements, vectorLength); for (uint32_t i = vectorLength; i < arrayLength; i++) { arrayElements->Set(thread, i, JSTaggedValue::Undefined()); } } else { JSHandle newArrayElement = factory->NewAndCopyTaggedArray(vectorElements, vectorLength, vectorLength); array->SetElements(thread, newArrayElement); array->SetLength(thread, JSTaggedValue(vectorLength)); } RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return JSTaggedValue::True(); } JSTaggedValue ContainersVector::ConvertToArray(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, Vector, ConvertToArray); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPIVector()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPIVector()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIVector", JSTaggedValue::Exception()); } } JSHandle vector = JSHandle::Cast(self); auto factory = thread->GetEcmaVM()->GetFactory(); JSHandle array = factory->NewJSArray(); int32_t length = vector->GetSize(); array->SetArrayLength(thread, length); JSHandle srcElements(thread, vector->GetElements()); JSHandle dstElements = factory->NewAndCopyTaggedArray(srcElements, length, length); array->SetElements(thread, dstElements); return array.GetTaggedValue(); } JSTaggedValue ContainersVector::GetFirstElement(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, Vector, GetFirstElement); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPIVector()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPIVector()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIVector", JSTaggedValue::Exception()); } } JSTaggedValue firstElement = JSAPIVector::GetFirstElement(JSHandle::Cast(self)); return firstElement; } JSTaggedValue ContainersVector::Sort(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, Vector, Sort); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPIVector()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPIVector()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIVector", JSTaggedValue::Exception()); } } JSHandle callbackFnHandle = GetCallArg(argv, 0); JSHandle elements(thread, JSHandle::Cast(self)->GetElements()); JSMutableHandle presentValue(thread, JSTaggedValue::Undefined()); JSMutableHandle middleValue(thread, JSTaggedValue::Undefined()); JSMutableHandle previousValue(thread, JSTaggedValue::Undefined()); uint32_t length = static_cast(JSHandle::Cast(self)->GetSize()); for (uint32_t i = 1; i < length; i++) { uint32_t beginIndex = 0; uint32_t endIndex = i; presentValue.Update(elements->Get(i)); while (beginIndex < endIndex) { uint32_t middleIndex = (beginIndex + endIndex) / 2; // 2 : half middleValue.Update(elements->Get(middleIndex)); int32_t compareResult = base::ArrayHelper::SortCompare(thread, callbackFnHandle, middleValue, presentValue); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); if (compareResult > 0) { endIndex = middleIndex; } else { beginIndex = middleIndex + 1; } } if (endIndex < i) { for (uint32_t j = i; j > endIndex; j--) { previousValue.Update(elements->Get(j - 1)); elements->Set(thread, j, previousValue.GetTaggedValue()); } elements->Set(thread, endIndex, presentValue.GetTaggedValue()); } } return JSTaggedValue::True(); } JSTaggedValue ContainersVector::GetIteratorObj(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, Vector, GetIteratorObj); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPIVector()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPIVector()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIVector", JSTaggedValue::Exception()); } } JSTaggedValue values = JSAPIVector::GetIteratorObj(thread, JSHandle::Cast(self)); return values; } } // namespace panda::ecmascript::containers