diff --git a/BUILD.gn b/BUILD.gn index a749a09185fd75fb7c6be89feda141ed14e8a800..8b1306a11cff54df3d78c55ec7b984c72fe53abf 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -321,6 +321,7 @@ ecma_source = [ "ecmascript/js_array_iterator.cpp", "ecmascript/js_arraybuffer.cpp", "ecmascript/js_arraylist.cpp", + "ecmascript/js_arraylist_iterator.cpp", "ecmascript/js_async_function.cpp", "ecmascript/js_dataview.cpp", "ecmascript/js_date.cpp", diff --git a/ecmascript/containers/containers_arraylist.cpp b/ecmascript/containers/containers_arraylist.cpp index 051a5e970cc7d16e7bad0c6fe275818ff01adbd4..09309550571df80a230819ad96f1271441801816 100644 --- a/ecmascript/containers/containers_arraylist.cpp +++ b/ecmascript/containers/containers_arraylist.cpp @@ -14,10 +14,17 @@ */ #include "containers_arraylist.h" +#include "ecmascript/js_array.h" +#include "ecmascript/base/array_helper.h" +#include "ecmascript/base/number_helper.h" #include "ecmascript/ecma_vm.h" #include "ecmascript/js_arraylist.h" +#include "ecmascript/js_arraylist_iterator.h" #include "ecmascript/object_factory.h" #include "ecmascript/tagged_array-inl.h" +#include "ecmascript/internal_call_params.h" +#include "ecmascript/js_function.h" +#include "ecmascript/js_iterator.h" namespace panda::ecmascript::containers { JSTaggedValue ContainersArrayList::ArrayListConstructor(EcmaRuntimeCallInfo *argv) @@ -33,7 +40,6 @@ JSTaggedValue ContainersArrayList::ArrayListConstructor(EcmaRuntimeCallInfo *arg } JSHandle constructor = GetConstructor(argv); JSHandle obj = factory->NewJSObjectByConstructor(JSHandle(constructor), newTarget); - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return obj.GetTaggedValue(); @@ -51,19 +57,453 @@ JSTaggedValue ContainersArrayList::Add(EcmaRuntimeCallInfo *argv) THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSArrayList", JSTaggedValue::Exception()); } - JSHandle value(GetCallArg(argv, 0)); - JSArrayList::Add(thread, JSHandle::Cast(self), value); + JSHandle value = GetCallArg(argv, 0); + return GetTaggedBoolean(JSArrayList::Add(thread, JSHandle::Cast(self), value)); +} + +JSTaggedValue ContainersArrayList::Insert(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), ArrayList, Insert); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle self = GetThis(argv); + + if (!self->IsJSArrayList()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSArrayList", JSTaggedValue::Exception()); + } + + JSHandle value = GetCallArg(argv, 0); + JSHandle index = GetCallArg(argv, 1); + JSArrayList::Insert(thread, JSHandle::Cast(self), value, JSTaggedValue::ToUint32(thread, index)); + + return JSTaggedValue::Undefined(); +} + +JSTaggedValue ContainersArrayList::Clear(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), ArrayList, Clear); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle self = GetThis(argv); + + if (!self->IsJSArrayList()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSArrayList", JSTaggedValue::Exception()); + } + + JSArrayList::Clear(thread, JSHandle::Cast(self)); + + return JSTaggedValue::True(); +} + +JSTaggedValue ContainersArrayList::Clone(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), ArrayList, Clone); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle self = GetThis(argv); + + if (!self->IsJSArrayList()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSArrayList", JSTaggedValue::Exception()); + } + + JSHandle newArrayList = JSArrayList::Clone(thread, JSHandle::Cast(self)); + + return JSTaggedValue::Cast(*newArrayList); +} + +JSTaggedValue ContainersArrayList::Has(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), ArrayList, Has); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle self = GetThis(argv); + + if (!self->IsJSArrayList()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSArrayList", JSTaggedValue::Exception()); + } + + JSHandle value = GetCallArg(argv, 0); + bool isHas = JSHandle::Cast(self)->Has(value.GetTaggedValue()); + + return GetTaggedBoolean(isHas); +} + +JSTaggedValue ContainersArrayList::GetCapacity(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + + BUILTINS_API_TRACE(argv->GetThread(), ArrayList, GetCapacity); + JSThread *thread = argv->GetThread(); + + JSHandle self = GetThis(argv); + if (!self->IsJSArrayList()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSArrayList", JSTaggedValue::Exception()); + } + + array_size_t capacity = JSArrayList::GetCapacity(thread, JSHandle::Cast(self)); + + return JSTaggedValue(capacity); +} + +JSTaggedValue ContainersArrayList::IncreaseCapacityTo(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), ArrayList, IncreaseCapacityTo); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle self = GetThis(argv); + + if (!self->IsJSArrayList()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSArrayList", JSTaggedValue::Exception()); + } + + JSHandle value = GetCallArg(argv, 0); + JSArrayList::IncreaseCapacityTo(thread, JSHandle::Cast(self), value); + + return JSTaggedValue::True(); +} + +JSTaggedValue ContainersArrayList::TrimToCurrentLength(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), JSArrayList, TrimToCurrentLength); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle self = GetThis(argv); + + if (!self->IsJSArrayList()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSArrayList", JSTaggedValue::Exception()); + } + + JSArrayList::TrimToCurrentLength(thread, JSHandle::Cast(self)); + + return JSTaggedValue::True(); +} + +JSTaggedValue ContainersArrayList::Get(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), ArrayList, Get); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle self = GetThis(argv); + + if (!self->IsJSArrayList()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSArrayList", JSTaggedValue::Exception()); + } + + JSHandle value = GetCallArg(argv, 0); + + JSTaggedValue element = JSHandle::Cast(self)->Get(thread, JSTaggedValue::ToUint32(thread, value)); + + return element; +} + +JSTaggedValue ContainersArrayList::GetIndexOf(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), ArrayList, IndexOf); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle self = GetThis(argv); + + if (!self->IsJSArrayList()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSArrayList", JSTaggedValue::Exception()); + } + + JSHandle value = GetCallArg(argv, 0); + + return JSTaggedValue(JSArrayList::GetIndexOf(thread, JSHandle::Cast(self), value)); +} + +JSTaggedValue ContainersArrayList::IsEmpty(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), ArrayList, IsEmpty); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle self = GetThis(argv); + + if (!self->IsJSArrayList()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSArrayList", JSTaggedValue::Exception()); + } + + return JSTaggedValue(JSArrayList::IsEmpty(JSHandle::Cast(self))); +} + +JSTaggedValue ContainersArrayList::GetLastIndexOf(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), ArrayList, LastIndexOf); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle self = GetThis(argv); + + if (!self->IsJSArrayList()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSArrayList", JSTaggedValue::Exception()); + } + + JSHandle value = GetCallArg(argv, 0); + + return JSTaggedValue(JSArrayList::GetLastIndexOf(thread, JSHandle::Cast(self), value)); +} + +JSTaggedValue ContainersArrayList::RemoveByIndex(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), ArrayList, RemoveByIndex); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle self = GetThis(argv); + + if (!self->IsJSArrayList()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSArrayList", JSTaggedValue::Exception()); + } + + JSHandle value = GetCallArg(argv, 0); + JSArrayList::RemoveByIndex(thread, JSHandle::Cast(self), JSTaggedValue::ToUint32(thread, value)); + + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::False()); + return JSTaggedValue::True(); +} + +JSTaggedValue ContainersArrayList::Remove(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), ArrayList, Remove); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle self = GetThis(argv); + + if (!self->IsJSArrayList()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSArrayList", JSTaggedValue::Exception()); + } + + JSHandle value = GetCallArg(argv, 0); + + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::False()); + return JSArrayList::Remove(thread, JSHandle::Cast(self), value); +} + +JSTaggedValue ContainersArrayList::RemoveByRange(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), ArrayList, RemoveByRange); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle self = GetThis(argv); + + if (!self->IsJSArrayList()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSArrayList", JSTaggedValue::Exception()); + } + + JSHandle startIndex = GetCallArg(argv, 0); + JSHandle endIndex = GetCallArg(argv, 0); + JSArrayList::RemoveByRange(thread, JSHandle::Cast(self), startIndex, endIndex); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::False()); return JSTaggedValue::True(); } -JSTaggedValue ContainersArrayList::Iterator(EcmaRuntimeCallInfo *argv) +JSTaggedValue ContainersArrayList::ReplaceAllElements(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), ArrayList, ReplaceAllElements); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle self = GetThis(argv); + + if (!self->IsJSArrayList()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSArrayList", JSTaggedValue::Exception()); + } + + JSHandle callbackFnHandle = GetCallArg(argv, 0); + if (!callbackFnHandle->IsCallable()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "the callbackfun is not callable.", JSTaggedValue::Exception()); + } + JSHandle thisArgHandle = GetCallArg(argv, 1); + + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::False()); + return JSArrayList::ReplaceAllElements(thread, self, callbackFnHandle, thisArgHandle); +} + +JSTaggedValue ContainersArrayList::Set(EcmaRuntimeCallInfo *argv) { ASSERT(argv); - BUILTINS_API_TRACE(argv->GetThread(), ArrayList, Iterator); + BUILTINS_API_TRACE(argv->GetThread(), ArrayList, Set); JSThread *thread = argv->GetThread(); [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle self = GetThis(argv); + + if (!self->IsJSArrayList()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSArrayList", JSTaggedValue::Exception()); + } + + JSHandle index = GetCallArg(argv, 0); + JSHandle value = GetCallArg(argv, 1); + JSHandle::Cast(self)->Set(thread, JSTaggedValue::ToUint32(thread, index), value.GetTaggedValue()); + + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::False()); return JSTaggedValue::Undefined(); } + +JSTaggedValue ContainersArrayList::SubArrayList(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), ArrayList, SubArrayList); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle self = GetThis(argv); + + if (!self->IsJSArrayList()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSArrayList", JSTaggedValue::Exception()); + } + + JSHandle value1 = GetCallArg(argv, 0); + JSHandle value2 = GetCallArg(argv, 1); + JSHandle newArrayList = JSArrayList::SubArrayList(thread, JSHandle::Cast(self), value1, value2); + + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::False()); + return newArrayList.GetTaggedValue(); +} + +JSTaggedValue ContainersArrayList::Sort(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), Array, Sort); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + + JSHandle self = GetThis(argv); + if (!self->IsJSArrayList()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSArrayList", JSTaggedValue::Exception()); + } + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + JSHandle callbackFnHandle = GetCallArg(argv, 0); + if (!callbackFnHandle->IsUndefined() && !callbackFnHandle->IsCallable()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "Callable is false", JSTaggedValue::Exception()); + } + + JSHandle elements(thread, JSHandle::Cast(self)->GetElements()); + JSMutableHandle presentValue(thread, JSTaggedValue::Undefined()); + JSMutableHandle middleValue(thread, JSTaggedValue::Undefined()); + JSMutableHandle previousValue(thread, JSTaggedValue::Undefined()); + array_size_t length = JSHandle::Cast(self)->GetLength().GetArrayLength(); + + for (array_size_t i = 1; i < length; i++) { + array_size_t beginIndex = 0; + array_size_t endIndex = i; + presentValue.Update(elements->Get(i)); + while (beginIndex < endIndex) { + array_size_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 >= 0 && endIndex < i) { + for (array_size_t j = i; j > endIndex; j--) { + previousValue.Update(elements->Get(j - 1)); + elements->Set(thread, j, previousValue.GetTaggedValue()); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + } + elements->Set(thread, endIndex, presentValue.GetTaggedValue()); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + } + } + + return JSTaggedValue::True(); +} + +JSTaggedValue ContainersArrayList::GetSize(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), ArrayList, GetSize); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle self = GetThis(argv); + + if (!self->IsJSArrayList()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSArrayList", JSTaggedValue::Exception()); + } + + return JSTaggedValue(JSHandle::Cast(self)->GetSize()); +} + +JSTaggedValue ContainersArrayList::ConvertToArray(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), JSArrayList, ConvertToArray); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle self = GetThis(argv); + + if (!self->IsJSArrayList()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSArrayList", JSTaggedValue::Exception()); + } + + JSHandle arrayList = JSHandle::Cast(self); + array_size_t length = arrayList->GetLength().GetArrayLength(); + JSHandle array = thread->GetEcmaVM()->GetFactory()->NewJSArray(); + array->SetArrayLength(thread, length); + JSHandle arrayListElements(thread, arrayList->GetElements()); + JSHandle arrayElements(thread, array->GetElements()); + + for (array_size_t i = 0; i < length; i++) { + arrayElements->Set(thread, i, arrayListElements->Get(i)); + } + + return JSTaggedValue::True(); +} + +JSTaggedValue ContainersArrayList::ForEach(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), ArrayList, ForEach); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle self = GetThis(argv); + + if (!self->IsJSArrayList()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSArrayList", JSTaggedValue::Exception()); + } + + JSHandle callbackFnHandle = GetCallArg(argv, 0); + if (!callbackFnHandle->IsCallable()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "the callbackfun is not callable.", JSTaggedValue::Exception()); + } + + JSHandle thisArgHandle = GetCallArg(argv, 1); + + return JSArrayList::ForEach(thread, self, callbackFnHandle, thisArgHandle); +} + +JSTaggedValue ContainersArrayList::GetIteratorObj(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), ArrayList, GetIteratorObj); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + + JSHandle self = GetThis(argv); + + if (!self->IsJSArrayList()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSArrayList", JSTaggedValue::Exception()); + } + + JSTaggedValue values = JSArrayList::GetIteratorObj(thread, JSHandle::Cast(self)); + + return values; +} } // namespace panda::ecmascript::containers diff --git a/ecmascript/containers/containers_arraylist.h b/ecmascript/containers/containers_arraylist.h index 9a23eb369aee4a0bb91070955343bbd433f2153b..f9720644c3c2765801e2541e42c79dd62384a8f5 100644 --- a/ecmascript/containers/containers_arraylist.h +++ b/ecmascript/containers/containers_arraylist.h @@ -25,7 +25,29 @@ public: static JSTaggedValue ArrayListConstructor(EcmaRuntimeCallInfo *argv); static JSTaggedValue Add(EcmaRuntimeCallInfo *argv); - static JSTaggedValue Iterator(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Insert(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Clear(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Clone(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Has(EcmaRuntimeCallInfo *argv); + static JSTaggedValue GetCapacity(EcmaRuntimeCallInfo *argv); + static JSTaggedValue IncreaseCapacityTo(EcmaRuntimeCallInfo *argv); + static JSTaggedValue TrimToCurrentLength(EcmaRuntimeCallInfo *argv); + static JSTaggedValue GetIndexOf(EcmaRuntimeCallInfo *argv); + static JSTaggedValue IsEmpty(EcmaRuntimeCallInfo *argv); + static JSTaggedValue GetLastIndexOf(EcmaRuntimeCallInfo *argv); + static JSTaggedValue RemoveByIndex(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Remove(EcmaRuntimeCallInfo *argv); + static JSTaggedValue RemoveByRange(EcmaRuntimeCallInfo *argv); + static JSTaggedValue ReplaceAllElements(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Sort(EcmaRuntimeCallInfo *argv); + static JSTaggedValue SubArrayList(EcmaRuntimeCallInfo *argv); + static JSTaggedValue ConvertToArray(EcmaRuntimeCallInfo *argv); + static JSTaggedValue ForEach(EcmaRuntimeCallInfo *argv); + static JSTaggedValue GetIteratorObj(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Get(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Set(EcmaRuntimeCallInfo *argv); + static JSTaggedValue GetSize(EcmaRuntimeCallInfo *argv); }; } // namespace panda::ecmascript::containers #endif // ECMASCRIPT_CONTAINERS_CONTAINERS_ARRAYLIST_H + \ No newline at end of file diff --git a/ecmascript/containers/containers_private.cpp b/ecmascript/containers/containers_private.cpp index 4e736b5c8aa0ec19455686cb592679b80d97e92e..acc37167fe80d6e82c29465ae4e3cca3a6376861 100644 --- a/ecmascript/containers/containers_private.cpp +++ b/ecmascript/containers/containers_private.cpp @@ -17,8 +17,10 @@ #include "containers_arraylist.h" #include "ecmascript/global_env.h" +#include "ecmascript/global_env_constants.h" #include "ecmascript/interpreter/fast_runtime_stub-inl.h" #include "ecmascript/js_arraylist.h" +#include "ecmascript/js_arraylist_iterator.h" #include "ecmascript/js_function.h" namespace panda::ecmascript::containers { @@ -166,7 +168,7 @@ void ContainersPrivate::SetStringTagSymbol(JSThread *thread, const JSHandle ContainersPrivate::InitializeArrayList(JSThread *thread) { - const GlobalEnvConstants *globalConst = thread->GlobalConstants(); + auto globalConst = const_cast(thread->GlobalConstants()); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); // ArrayList.prototype JSHandle arrayListFuncPrototype = factory->NewEmptyJSObject(); @@ -185,7 +187,64 @@ JSHandle ContainersPrivate::InitializeArrayList(JSThread *thread) // ArrayList.prototype.add() SetFrozenFunction(thread, arrayListFuncPrototype, "add", ContainersArrayList::Add, FuncLength::ONE); + SetFrozenFunction(thread, arrayListFuncPrototype, "insert", ContainersArrayList::Insert, FuncLength::TWO); + SetFrozenFunction(thread, arrayListFuncPrototype, "clear", ContainersArrayList::Clear, FuncLength::ZERO); + SetFrozenFunction(thread, arrayListFuncPrototype, "clone", ContainersArrayList::Clone, FuncLength::ZERO); + SetFrozenFunction(thread, arrayListFuncPrototype, "has", ContainersArrayList::Has, FuncLength::ONE); + SetFrozenFunction(thread, arrayListFuncPrototype, "getCapacity", + ContainersArrayList::GetCapacity, FuncLength::ZERO); + SetFrozenFunction(thread, arrayListFuncPrototype, "increaseCapacityTo", + ContainersArrayList::IncreaseCapacityTo, FuncLength::ONE); + SetFrozenFunction(thread, arrayListFuncPrototype, "trimToCurrentLength", + ContainersArrayList::TrimToCurrentLength, FuncLength::ZERO); + SetFrozenFunction(thread, arrayListFuncPrototype, "getIndexOf", + ContainersArrayList::GetIndexOf, FuncLength::ONE); + SetFrozenFunction(thread, arrayListFuncPrototype, "isEmpty", ContainersArrayList::IsEmpty, FuncLength::ZERO); + SetFrozenFunction(thread, arrayListFuncPrototype, "getLastIndexOf", + ContainersArrayList::GetLastIndexOf, FuncLength::ONE); + SetFrozenFunction(thread, arrayListFuncPrototype, "removeByIndex", + ContainersArrayList::RemoveByIndex, FuncLength::ONE); + SetFrozenFunction(thread, arrayListFuncPrototype, "remove", ContainersArrayList::Remove, FuncLength::ONE); + SetFrozenFunction(thread, arrayListFuncPrototype, "removeByRange", + ContainersArrayList::RemoveByRange, FuncLength::TWO); + SetFrozenFunction(thread, arrayListFuncPrototype, "replaceAllElements", + ContainersArrayList::ReplaceAllElements, FuncLength::TWO); + SetFrozenFunction(thread, arrayListFuncPrototype, "sort", ContainersArrayList::Sort, FuncLength::ONE); + SetFrozenFunction(thread, arrayListFuncPrototype, "subArrayList", + ContainersArrayList::SubArrayList, FuncLength::TWO); + SetFrozenFunction(thread, arrayListFuncPrototype, "convertToArray", + ContainersArrayList::ConvertToArray, FuncLength::ZERO); + SetFrozenFunction(thread, arrayListFuncPrototype, "forEach", ContainersArrayList::ForEach, FuncLength::TWO); + + JSHandle lengthGetter = CreateGetter(thread, ContainersArrayList::GetSize, "length", + FuncLength::ZERO); + JSHandle lengthKey(factory->NewFromCanBeCompressString("length")); + SetGetter(thread, arrayListFuncPrototype, lengthKey, lengthGetter); + + JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); + + SetFunctionAtSymbol(thread, env, arrayListFuncPrototype, env->GetIteratorSymbol(), "[Symbol.iterator]", + ContainersArrayList::GetIteratorObj, FuncLength::ONE); + + ContainersPrivate::InitializeArrayListIterator(thread, env, globalConst); + + globalConst->SetConstant(ConstantIndex::ARRAYLIST_FUNCTION_INDEX, arrayListFunction.GetTaggedValue()); return arrayListFunction; } + +void ContainersPrivate::InitializeArrayListIterator(JSThread *thread, const JSHandle &env + GlobalEnvConstants *globalConst) +{ + + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle iteratorFuncDynclass = + factory->NewEcmaDynClass(JSObject::SIZE, JSType::JS_ITERATOR, env->GetIteratorPrototype()); + JSHandle arrayListIteratorPrototype(factory->NewJSObject(iteratorFuncDynclass)); + // Iterator.prototype.next() + SetFrozenFunction(thread, arrayListIteratorPrototype, "next", JSArrayListIterator::Next, FuncLength::ONE); + SetStringTagSymbol(thread, env, arrayListIteratorPrototype, "ArrayList Iterator"); + auto globalConst = const_cast(thread->GlobalConstants()); + globalConst->SetConstant(ConstantIndex::ARRAYLIST_ITERATOR_PROTOTYPE_INDEX, arrayListIteratorPrototype.GetTaggedValue()); +} } // namespace panda::ecmascript::containers diff --git a/ecmascript/containers/containers_private.h b/ecmascript/containers/containers_private.h index 2950ed48e17f101714ce31894dac6a7a55baf886..470f303b42cc422b151fb4a76a864e391b173297 100644 --- a/ecmascript/containers/containers_private.h +++ b/ecmascript/containers/containers_private.h @@ -47,6 +47,8 @@ private: static void SetStringTagSymbol(JSThread *thread, const JSHandle &env, const JSHandle &obj, const char *key); static JSHandle InitializeArrayList(JSThread *thread); + static void InitializeArrayListIterator(JSThread *thread, const JSHandle &env + GlobalEnvConstants *globalConst); }; } // namespace panda::ecmascript::containers diff --git a/ecmascript/dump.cpp b/ecmascript/dump.cpp index 6fd511ec8db6fd742af8be00e39a4ee5d7d3ce02..6ad0a3e55d7e8fece6ac5f7b9747afb3f7721e0a 100644 --- a/ecmascript/dump.cpp +++ b/ecmascript/dump.cpp @@ -35,6 +35,7 @@ #include "ecmascript/js_array_iterator.h" #include "ecmascript/js_arraybuffer.h" #include "ecmascript/js_arraylist.h" +#include "ecmascript/js_arraylist_iterator.h" #include "ecmascript/js_async_function.h" #include "ecmascript/js_collator.h" #include "ecmascript/js_dataview.h" @@ -257,6 +258,8 @@ CString JSHClass::DumpJSType(JSType type) return "ClassInfoExtractor"; case JSType::JS_ARRAY_LIST: return "ArrayList"; + case JSType::JS_ARRAYLIST_ITERATOR: + return "JSArraylistIterator"; default: { CString ret = "unknown type "; return ret + static_cast(type); @@ -603,6 +606,9 @@ static void DumpObject(JSThread *thread, TaggedObject *obj, std::ostream &os) case JSType::JS_ARRAY_LIST: JSArrayList::Cast(obj)->Dump(thread, os); break; + case JSType::JS_ARRAYLIST_ITERATOR: + JSArrayListIterator::Cast(obj)->Dump(thread, os); + break; default: UNREACHABLE(); break; @@ -1100,6 +1106,12 @@ void JSArrayList::Dump(JSThread *thread, std::ostream &os) const JSObject::Dump(thread, os); } +void JSArrayListIterator::Dump(JSThread *thread, std::ostream &os) const +{ + os << " - next: " << std::dec << GetNextIndex().GetInt() << "\n"; + JSObject::Dump(thread, os); +} + void JSArrayIterator::Dump(JSThread *thread, std::ostream &os) const { JSArray *array = JSArray::Cast(GetIteratedArray().GetTaggedObject()); @@ -2154,6 +2166,9 @@ static void DumpObject(JSThread *thread, TaggedObject *obj, case JSType::JS_ARRAY_LIST: JSArrayList::Cast(obj)->DumpForSnapshot(thread, vec); return; + case JSType::JS_ARRAYLIST_ITERATOR: + JSArrayListIterator::Cast(obj)->DumpForSnapshot(thread, vec); + return; default: break; } @@ -2507,6 +2522,12 @@ void JSArrayList::DumpForSnapshot([[maybe_unused]] JSThread *thread, JSObject::DumpForSnapshot(thread, vec); } +void JSArrayListIterator::DumpForSnapshot([[maybe_unused]] JSThread *thread, + std::vector> &vec) const +{ + JSObject::DumpForSnapshot(thread, vec); +} + void JSArrayIterator::DumpForSnapshot([[maybe_unused]] JSThread *thread, std::vector> &vec) const { diff --git a/ecmascript/global_env_constants.h b/ecmascript/global_env_constants.h index dd1e716f82d44851e3399e1cdb2f51150e4fe01d..3b7adebc976a477dbe957dc8f3182af58f282743 100644 --- a/ecmascript/global_env_constants.h +++ b/ecmascript/global_env_constants.h @@ -86,6 +86,9 @@ class JSThread; V(JSTaggedValue, WritableString, WRITABLE_STRING_INDEX, writable) \ V(JSTaggedValue, EnumerableString, ENUMERABLE_STRING_INDEX, enumerable) \ V(JSTaggedValue, ConfigurableString, CONFIGURABLE_STRING_INDEX, configurable) \ + /* for containers */ \ + V(JSTaggedValue, ArrayListFunction, ARRAYLIST_FUNCTION_INDEX, ArrayListFunction) \ + V(JSTaggedValue, ArrayListIteratorPrototype, ARRAYLIST_ITERATOR_PROTOTYPE_INDEX, ArrayListIterator) \ /* SymbolTable*RegisterSymbols */ \ V(JSTaggedValue, NameString, NAME_STRING_INDEX, name) \ V(JSTaggedValue, GetPrototypeOfString, GETPROTOTYPEOF_STRING_INDEX, getPrototypeOf) \ diff --git a/ecmascript/hprof/heap_snapshot.cpp b/ecmascript/hprof/heap_snapshot.cpp index bcf69f2cf35ef4d2ee391e1357f0f230c4234a19..1a107af28a57a19e64663f3994492812290b4e2a 100644 --- a/ecmascript/hprof/heap_snapshot.cpp +++ b/ecmascript/hprof/heap_snapshot.cpp @@ -341,6 +341,8 @@ CString *HeapSnapShot::GenerateNodeName(JSThread *thread, TaggedObject *entry) return GetString("EcmaModule"); case JSType::JS_ARRAY_LIST: return GetString("ArrayList"); + case JSType::JS_ARRAYLIST_ITERATOR: + return GetString("ArrayListIterator"); default: break; } diff --git a/ecmascript/js_arraylist.cpp b/ecmascript/js_arraylist.cpp index 01094a91d79bef61f0d05cf3864274b399f98105..fcd271610d3a32e747cfede436ef68086212c7da 100644 --- a/ecmascript/js_arraylist.cpp +++ b/ecmascript/js_arraylist.cpp @@ -14,36 +14,80 @@ */ #include "js_arraylist.h" - +#include "js_arraylist_iterator.h" +#include "js_iterator.h" +#include "ecmascript/js_function.h" +#include "ecmascript/internal_call_params.h" #include "ecmascript/js_tagged_value.h" #include "ecmascript/object_factory.h" namespace panda::ecmascript { -void JSArrayList::Add(JSThread *thread, const JSHandle &arrayList, const JSHandle &value) +bool JSArrayList::Add(JSThread *thread, const JSHandle &arrayList, const JSHandle &value) { - // GrowCapacity array_size_t length = arrayList->GetLength().GetArrayLength(); JSHandle elements = GrowCapacity(thread, arrayList, length + 1); ASSERT(!elements->IsDictionaryMode()); elements->Set(thread, length, value); arrayList->SetLength(thread, JSTaggedValue(++length)); + return true; } -JSHandle JSArrayList::GrowCapacity(const JSThread *thread, const JSHandle &obj, - array_size_t capacity) +void JSArrayList::Insert(JSThread *thread, const JSHandle &arrayList, + const JSHandle &value, const uint32_t &index) { - JSHandle oldElements(thread, obj->GetElements()); - array_size_t oldLength = oldElements->GetLength(); - if (capacity < oldLength) { - return oldElements; + array_size_t length = arrayList->GetLength().GetArrayLength(); + JSHandle elements = GrowCapacity(thread, arrayList, length + 1); + + ASSERT(!elements->IsDictionaryMode()); + for (uint32_t i = length; i >= index; --i) { + elements->Set(thread, i, elements->Get(i - 1)); } - array_size_t newCapacity = ComputeCapacity(capacity); - JSHandle newElements = - thread->GetEcmaVM()->GetFactory()->CopyArray(oldElements, oldLength, newCapacity); + elements->Set(thread, index, value); + arrayList->SetLength(thread, JSTaggedValue(++length)); +} - obj->SetElements(thread, newElements); - return newElements; +void JSArrayList::Clear(JSThread *thread, const JSHandle &arrayList) +{ + if (!arrayList.IsEmpty()) { + arrayList->SetLength(thread, JSTaggedValue(0)); + } +} + +JSHandle JSArrayList::Clone(JSThread *thread, const JSHandle &obj) +{ + array_size_t length = obj->GetSize(); + JSHandle elements(thread, obj->GetElements()); + array_size_t capacity = elements->GetLength(); + JSHandle newArrayList = thread->GetEcmaVM()->GetFactory()->NewJSArrayList(capacity); + + for (array_size_t i = 0; i < length; i ++) { + newArrayList->Set(thread, i, elements->Get(i)); + } + newArrayList->SetLength(thread, JSTaggedValue(length)); + return newArrayList; +} + +array_size_t JSArrayList::GetCapacity(JSThread *thread, const JSHandle &obj) +{ + JSHandle elements(thread, obj->GetElements()); + array_size_t capacity = elements->GetLength(); + return capacity; +} + +void JSArrayList::IncreaseCapacityTo(JSThread *thread, const JSHandle &arrayList, + JSHandle &capacity) +{ + array_size_t size = arrayList->GetLength().GetArrayLength() + JSTaggedValue::ToUint32(thread, capacity); + GrowCapacity(thread, arrayList, size); +} + +void JSArrayList::TrimToCurrentLength(JSThread *thread, const JSHandle &arrayList) +{ + array_size_t length = arrayList->GetLength().GetArrayLength(); + JSHandle oldElements(thread, arrayList->GetElements()); + JSHandle newElements = thread->GetEcmaVM()->GetFactory()->CopyArray(oldElements, length, length); + arrayList->SetElements(thread, newElements); } JSTaggedValue JSArrayList::Get(JSThread *thread, const uint32_t index) @@ -56,6 +100,119 @@ JSTaggedValue JSArrayList::Get(JSThread *thread, const uint32_t index) return elements->Get(index); } +bool JSArrayList::IsEmpty(const JSHandle &arrayList) +{ + return arrayList->GetLength().GetArrayLength() == 0; +} + +int JSArrayList::GetIndexOf(JSThread *thread, const JSHandle &arrayList, + const JSHandle &value) +{ + JSHandle elements(thread, arrayList->GetElements()); + array_size_t length = arrayList->GetLength().GetArrayLength(); + + for (uint32_t i = 0; i < length; ++i) { + JSHandle element(thread, elements->Get(i)); + if (JSTaggedValue::StrictEqual(thread, value, element)) { + return i; + } + } + return -1; +} + +int JSArrayList::GetLastIndexOf(JSThread *thread, const JSHandle &arrayList, + const JSHandle &value) +{ + JSHandle elements(thread, arrayList->GetElements()); + array_size_t length = arrayList->GetLength().GetArrayLength(); + for (int i = length; i > 0; --i) { + JSHandle element(thread, elements->Get(i)); + if (JSTaggedValue::StrictEqual(thread, value, element)) { + return i; + } + } + return -1; +} + +bool JSArrayList::RemoveByIndex(JSThread *thread, const JSHandle &arrayList, uint32_t index) +{ + array_size_t length = arrayList->GetLength().GetArrayLength(); + if (index < 0 || index >= length) { + THROW_RANGE_ERROR_AND_RETURN(thread, "Can not find this index in arrayList", false); + } + + JSHandle elements(thread, arrayList->GetElements()); + for (array_size_t i = index; i < length - 2; i++) { + elements->Set(thread, i, elements->Get(i + 1)); + } + arrayList->SetLength(thread, JSTaggedValue(--length)); + return true; +} + +JSTaggedValue JSArrayList::Remove(JSThread *thread, const JSHandle &arrayList, + const JSHandle &value) +{ + JSHandle elements(thread, arrayList->GetElements()); + array_size_t length = arrayList->GetLength().GetArrayLength(); + + for (uint32_t i = 0; i < length; ++i) { + JSHandle element(thread, elements->Get(i)); + if (JSTaggedValue::StrictEqual(thread, value, element)) { + if (RemoveByIndex(thread, arrayList, i)) { + continue; + } + THROW_TYPE_ERROR_AND_RETURN(thread, "Can not Remove this value", JSTaggedValue::Exception()); + } + } + + return arrayList.GetTaggedValue(); +} + +JSTaggedValue JSArrayList::RemoveByRange(JSThread *thread, const JSHandle &arrayList, + const JSHandle &value1, const JSHandle &value2) +{ + int startIndex = JSTaggedValue::ToUint32(thread, value1); + int endIndex = JSTaggedValue::ToUint32(thread, value2); + int length = static_cast(arrayList->GetLength().GetArrayLength()); + if (startIndex < 0 || startIndex >= length || endIndex < 0 || endIndex >= length || endIndex <= startIndex) { + THROW_RANGE_ERROR_AND_RETURN(thread, "array length must less than 2^32 - 1", JSTaggedValue::Exception()); + } + + for (int i = startIndex; i < endIndex; i++) { + if (RemoveByIndex(thread, arrayList, i)) { + continue; + } + THROW_TYPE_ERROR_AND_RETURN(thread, "Can not Remove this range", JSTaggedValue::Exception()); + } + + return JSTaggedValue::Undefined(); +} + +JSTaggedValue JSArrayList::ReplaceAllElements(JSThread *thread, const JSHandle &thisHandle, + const JSHandle &callbackFn, + const JSHandle &thisArg) +{ + JSHandle arraylist = JSHandle::Cast(thisHandle); + array_size_t length = arraylist->GetSize(); + JSMutableHandle key(thread, JSTaggedValue::Undefined()); + InternalCallParams *arguments = thread->GetInternalCallParams(); + + for (array_size_t k = 0; k < length; k++) { + JSHandle kValue = JSHandle(thread, arraylist->Get(thread, k)); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + key.Update(JSTaggedValue(k)); + arguments->MakeArgv(kValue, key, thisHandle); + JSTaggedValue funcResult = JSFunction::Call(thread, callbackFn, thisArg, 3, + arguments->GetArgv()); // 3: three args + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, funcResult); + + arraylist->Set(thread, k, funcResult); + } + + return JSTaggedValue::Undefined(); +} + JSTaggedValue JSArrayList::Set(JSThread *thread, const uint32_t index, JSTaggedValue value) { if (index < 0 || index >= GetLength().GetArrayLength()) { @@ -67,22 +224,78 @@ JSTaggedValue JSArrayList::Set(JSThread *thread, const uint32_t index, JSTaggedV return JSTaggedValue::Undefined(); } -bool JSArrayList::Delete(JSThread *thread, const JSHandle &obj, const JSHandle &key) +JSHandle JSArrayList::SubArrayList(JSThread *thread, const JSHandle &arrayList, + const JSHandle &value1, + const JSHandle &value2) { - uint32_t index = 0; - if (UNLIKELY(JSTaggedValue::ToElementIndex(key.GetTaggedValue(), &index))) { - THROW_TYPE_ERROR_AND_RETURN(thread, "Can not delete a type other than number", false); + int length = static_cast(arrayList->GetLength().GetArrayLength()); + int fromIndex = JSTaggedValue::ToUint32(thread, value1); + int toIndex = JSTaggedValue::ToUint32(thread, value2); + if (fromIndex < 0 || fromIndex >= length || toIndex < 0 || toIndex >= length) { + THROW_RANGE_ERROR_AND_RETURN(thread, "Get property index out-of-bounds", + thread->GetEcmaVM()->GetFactory()->NewJSArrayList(0)); } - array_size_t length = obj->GetLength().GetArrayLength(); - if (index < 0 || index >= length) { - THROW_RANGE_ERROR_AND_RETURN(thread, "Delete property index out-of-bounds", false); + + if (fromIndex > toIndex) { + int tmp = fromIndex; + fromIndex = toIndex; + toIndex = tmp; } - TaggedArray *elements = TaggedArray::Cast(obj->GetElements().GetTaggedObject()); - for (array_size_t i = 0; i < length - 1; i++) { - elements->Set(thread, i, elements->Get(i + 1)); + + int newLength = toIndex - fromIndex; + JSHandle subArrayList = thread->GetEcmaVM()->GetFactory()->NewJSArrayList(newLength); + JSHandle elements(thread, arrayList->GetElements()); + subArrayList->SetLength(thread, JSTaggedValue(newLength)); + + for (int i = 0; i < newLength; i++) { + subArrayList->Set(thread, i, elements->Get(fromIndex + i)); } - obj->SetLength(thread, JSTaggedValue(--length)); - return true; + + return subArrayList; +} + +JSTaggedValue JSArrayList::ForEach(JSThread *thread, const JSHandle &thisHandle, + const JSHandle &callbackFn, + const JSHandle &thisArg) +{ + JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); + + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle thisObjVal(thisObjHandle); + + JSHandle arrayList = JSHandle::Cast(thisHandle); + array_size_t length = arrayList->GetSize(); + JSMutableHandle key(thread, JSTaggedValue::Undefined()); + InternalCallParams *arguments = thread->GetInternalCallParams(); + + for (array_size_t k = 0; k < length; k++) { + JSHandle kValue = JSHandle(thread, arrayList->Get(thread, k)); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + key.Update(JSTaggedValue(k)); + arguments->MakeArgv(kValue, key, thisObjVal); + JSTaggedValue funcResult = JSFunction::Call(thread, callbackFn, + thisArg, 3, arguments->GetArgv()); // 3: three args + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, funcResult); + } + + return JSTaggedValue::Undefined(); +} + +JSHandle JSArrayList::GrowCapacity(const JSThread *thread, const JSHandle &obj, + array_size_t capacity) +{ + JSHandle oldElements(thread, obj->GetElements()); + array_size_t oldCapacity = oldElements->GetLength(); + if (capacity < oldCapacity) { + return oldElements; + } + array_size_t newCapacity = ComputeCapacity(capacity); + JSHandle newElements = + thread->GetEcmaVM()->GetFactory()->CopyArray(oldElements, oldCapacity, newCapacity); + + obj->SetElements(thread, newElements); + return newElements; } bool JSArrayList::Has(JSTaggedValue value) const @@ -109,13 +322,22 @@ bool JSArrayList::GetOwnProperty(JSThread *thread, const JSHandle & { uint32_t index = 0; if (UNLIKELY(JSTaggedValue::ToElementIndex(key.GetTaggedValue(), &index))) { - THROW_TYPE_ERROR_AND_RETURN(thread, "Can not get property whose type is not number", false); + THROW_TYPE_ERROR_AND_RETURN(thread, "Can not obtain attributes of no-number type", false); } array_size_t length = obj->GetLength().GetArrayLength(); if (index < 0 || index >= length) { - THROW_RANGE_ERROR_AND_RETURN(thread, "Get property index out-of-bounds", false); + THROW_RANGE_ERROR_AND_RETURN(thread, "GetOwnProperty index out-of-bounds", false); } return JSObject::GetOwnProperty(thread, JSHandle::Cast(obj), key, desc); } + +JSTaggedValue JSArrayList::GetIteratorObj(JSThread *thread, const JSHandle &obj) +{ + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle iter(factory->NewJSArrayListIterator(obj, IterationKind::VALUE)); + + return iter.GetTaggedValue(); +} } // namespace panda::ecmascript diff --git a/ecmascript/js_arraylist.h b/ecmascript/js_arraylist.h index 3a48e7c2ffa8048c66e9481e351bed7193270183..a270fa158faaae536d6b47993fc25dc955350187 100644 --- a/ecmascript/js_arraylist.h +++ b/ecmascript/js_arraylist.h @@ -28,18 +28,45 @@ public: return static_cast(object); } - static void Add(JSThread *thread, const JSHandle &arrayList, const JSHandle &value); + static bool Add(JSThread *thread, const JSHandle &arrayList, const JSHandle &value); + static void Insert(JSThread *thread, const JSHandle &arrayList, + const JSHandle &value, const uint32_t &index); + static void Clear(JSThread *thread, const JSHandle &obj); + static JSHandle Clone(JSThread *thread, const JSHandle &obj); + static array_size_t GetCapacity(JSThread *thread, const JSHandle &obj); + static void IncreaseCapacityTo(JSThread *thread, const JSHandle &arrayList, + JSHandle &capacity); + static void TrimToCurrentLength(JSThread *thread, const JSHandle &arrayList); + //static JSTaggedValue Get(JSThread *thread, const JSHandle &obj, uint32_t index); + static bool IsEmpty(const JSHandle &arrayList); + static int GetIndexOf(JSThread *thread, const JSHandle &arrayList, + const JSHandle &value); + static int GetLastIndexOf(JSThread *thread, const JSHandle &arrayList, + const JSHandle &value); + static bool RemoveByIndex(JSThread *thread, const JSHandle &arrayList, uint32_t value); + static JSTaggedValue Remove(JSThread *thread, const JSHandle &arrayList, + const JSHandle &value); + static JSTaggedValue RemoveByRange(JSThread *thread, const JSHandle &arrayList, + const JSHandle &value1, const JSHandle &value2); + static JSTaggedValue ReplaceAllElements(JSThread *thread, const JSHandle &thisHandle, + const JSHandle &callbackFn, + const JSHandle &thisArg); + static JSHandle SubArrayList(JSThread *thread, const JSHandle &arrayList, + const JSHandle &value1, + const JSHandle &value2); + static JSTaggedValue ForEach(JSThread *thread, const JSHandle &thisHandle, + const JSHandle &callbackFn, + const JSHandle &thisArg); - JSTaggedValue Get(JSThread *thread, const uint32_t index); + static JSTaggedValue GetIteratorObj(JSThread *thread, const JSHandle &obj); JSTaggedValue Set(JSThread *thread, const uint32_t index, JSTaggedValue value); - bool Has(JSTaggedValue value) const; + JSTaggedValue Get(JSThread *thread, const uint32_t index); - static bool Delete(JSThread *thread, const JSHandle &obj, const JSHandle &key); + bool Has(JSTaggedValue value) const; static JSHandle OwnKeys(JSThread *thread, const JSHandle &obj); static bool GetOwnProperty(JSThread *thread, const JSHandle &obj, const JSHandle &key, PropertyDescriptor &desc); - inline int GetSize() const { return GetLength().GetArrayLength(); @@ -61,4 +88,4 @@ private: }; } // namespace panda::ecmascript -#endif // ECMASCRIPT_JSARRAYLIST_H +#endif // ECMASCRIPT_JSARRAYLIST_H \ No newline at end of file diff --git a/ecmascript/js_arraylist_iterator.cpp b/ecmascript/js_arraylist_iterator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bee197c56d18298756ad4a700a81f2698cc6ef27 --- /dev/null +++ b/ecmascript/js_arraylist_iterator.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2021 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 "js_arraylist_iterator.h" +#include "builtins/builtins_errors.h" +#include "ecmascript/base/typed_array_helper-inl.h" +#include "ecmascript/base/typed_array_helper.h" +#include "global_env.h" +#include "js_arraylist.h" +#include "object_factory.h" + +namespace panda::ecmascript { +using BuiltinsBase = base::BuiltinsBase; +// ArrayListIteratorPrototype%.next ( ) +JSTaggedValue JSArrayListIterator::Next(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + + JSHandle input(BuiltinsBase::GetThis(argv)); + if (!input->IsJSArrayListIterator()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "this value is not an arrayList iterator", JSTaggedValue::Exception()); + } + JSHandle iter(input); + JSHandle arrayList(thread, iter->GetIteratedArrayList()); + JSHandle undefinedHandle = thread->GlobalConstants()->GetHandledUndefined(); + + if (arrayList->IsUndefined()) { + return JSIterator::CreateIterResultObject(thread, undefinedHandle, true).GetTaggedValue(); + } + + uint32_t index = iter->GetNextIndex().GetInt(); + uint32_t length = 0; + + if (arrayList->IsJSArrayList()) { + length = JSHandle(arrayList)->GetLength().GetArrayLength(); + } + + if (index >= length) { + iter->SetIteratedArrayList(thread, undefinedHandle); + return JSIterator::CreateIterResultObject(thread, undefinedHandle, true).GetTaggedValue(); + } + + iter->SetNextIndex(thread, JSTaggedValue(index + 1)); + JSHandle value = JSTaggedValue::GetProperty(thread, arrayList, index).GetValue(); + + return JSIterator::CreateIterResultObject(thread, value, false).GetTaggedValue(); +} +} // namespace panda::ecmascript diff --git a/ecmascript/js_arraylist_iterator.h b/ecmascript/js_arraylist_iterator.h new file mode 100644 index 0000000000000000000000000000000000000000..220d333d5aa5f32e49ad00e3a5ea301a52351983 --- /dev/null +++ b/ecmascript/js_arraylist_iterator.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2021 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. + */ + +#ifndef ECMASCRIPT_JS_ARRAYLIST_ITERATOR_H +#define ECMASCRIPT_JS_ARRAYLIST_ITERATOR_H + +#include "js_iterator.h" +#include "js_object.h" + +namespace panda::ecmascript { +class JSArrayListIterator : public JSObject { +public: + static JSArrayListIterator *Cast(ObjectHeader *obj) + { + ASSERT(JSTaggedValue(obj).IsJSArrayListIterator()); + return static_cast(obj); + } + static JSTaggedValue Next(EcmaRuntimeCallInfo *argv); + + static constexpr size_t ITERATED_ARRAYLIST_OFFSET = JSObject::SIZE; + ACCESSORS(IteratedArrayList, ITERATED_ARRAYLIST_OFFSET, NEXT_INDEX_OFFSET) + ACCESSORS(NextIndex, NEXT_INDEX_OFFSET, ITERATION_KIND_OFFSET) + ACCESSORS(IterationKind, ITERATION_KIND_OFFSET, SIZE) + + DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSObject, ITERATED_ARRAYLIST_OFFSET, SIZE) + + DECL_DUMP() +}; +} // namespace panda::ecmascript + +#endif // ECMASCRIPT_JS_ArrayList_ITERATOR_H diff --git a/ecmascript/js_hclass.h b/ecmascript/js_hclass.h index b48b34650b7618eed74080cae9642653b05a4ce8..6d9ec9f9433424db94537c87dcb55832d1492030 100644 --- a/ecmascript/js_hclass.h +++ b/ecmascript/js_hclass.h @@ -95,6 +95,7 @@ class ProtoChangeDetails; JS_SET_ITERATOR, /* ////////////////////////////////////////////////////////////////////////////-PADDING */ \ JS_ARRAY_ITERATOR, /* ////////////////////////////////////////////////////////////////////////////-PADDING */ \ JS_STRING_ITERATOR, /* ////////////////////////////////////////////////////////////////////////////-PADDING */ \ + JS_ARRAYLIST_ITERATOR, /* /////////////////////////////////////////////////////////////////////////-PADDING */ \ JS_INTL, /* ///////////////////////////////////////////////////////////////////////////////////////-PADDING */ \ JS_LOCALE, /* /////////////////////////////////////////////////////////////////////////////////////-PADDING */ \ JS_DATE_TIME_FORMAT, /* ///////////////////////////////////////////////////////////////////////////-PADDING */ \ @@ -670,6 +671,12 @@ public: { return GetObjectType() == JSType::JS_ARRAY_ITERATOR; } + + inline bool IsJSArrayListIterator() const + { + return GetObjectType() == JSType::JS_ARRAYLIST_ITERATOR; + } + inline bool IsPrototypeHandler() const { return GetObjectType() == JSType::PROTOTYPE_HANDLER; diff --git a/ecmascript/js_object-inl.h b/ecmascript/js_object-inl.h index 214721ba3b2f4ed420a710ee486cb06beb40ee14..be939cca946b8b0af2f5bb5c2ab67dd2ea4e90f2 100644 --- a/ecmascript/js_object-inl.h +++ b/ecmascript/js_object-inl.h @@ -176,6 +176,11 @@ inline bool JSObject::IsJSArrayIterator() const return GetJSHClass()->IsJSArrayIterator(); } +inline bool JSObject::IsJSArrayListIterator() const +{ + return GetJSHClass()->IsJSArrayListIterator(); +} + inline bool JSObject::IsJSPrimitiveRef() const { return GetJSHClass()->IsJsPrimitiveRef(); diff --git a/ecmascript/js_object.h b/ecmascript/js_object.h index baa92b6244156c54b80af18736645aa3772c47b6..9bb647bb1e1a6255a150de67406aa8afc86b3070 100644 --- a/ecmascript/js_object.h +++ b/ecmascript/js_object.h @@ -546,6 +546,7 @@ public: bool IsJSSetIterator() const; bool IsJSMapIterator() const; bool IsJSArrayIterator() const; + bool IsJSArrayListIterator() const; bool IsJSPrimitiveRef() const; bool IsElementDict() const; bool IsPropertiesDict() const; diff --git a/ecmascript/js_tagged_value-inl.h b/ecmascript/js_tagged_value-inl.h index 3e02edef54f132aa71f3ef16c236d8fd9bcc79c0..b712f4761705cdddd42b56db003a2fbdf38d609b 100644 --- a/ecmascript/js_tagged_value-inl.h +++ b/ecmascript/js_tagged_value-inl.h @@ -785,6 +785,11 @@ inline bool JSTaggedValue::IsJSArrayIterator() const return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSArrayIterator(); } +inline bool JSTaggedValue::IsJSArrayListIterator() const +{ + return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSArrayListIterator(); +} + inline bool JSTaggedValue::IsIterator() const { return IsHeapObject() && GetTaggedObject()->GetClass()->IsIterator(); diff --git a/ecmascript/js_tagged_value.h b/ecmascript/js_tagged_value.h index f26f15f48a22d9690ae505129c76702ab4b10169..42681edad84394e73c5d1306c7b9e86be12ca69b 100644 --- a/ecmascript/js_tagged_value.h +++ b/ecmascript/js_tagged_value.h @@ -279,6 +279,7 @@ public: bool IsStringIterator() const; bool IsArrayBuffer() const; + bool IsJSArrayListIterator() const; bool IsJSSetIterator() const; bool IsJSMapIterator() const; bool IsJSArrayIterator() const; diff --git a/ecmascript/object_factory.cpp b/ecmascript/object_factory.cpp index e03b4fd34f047a242f9f8edcb642cd7402ee3c70..fc1ab811899a22c279ab19a01a0e1169e8820884 100644 --- a/ecmascript/object_factory.cpp +++ b/ecmascript/object_factory.cpp @@ -41,6 +41,7 @@ #include "ecmascript/js_array_iterator.h" #include "ecmascript/js_arraybuffer.h" #include "ecmascript/js_arraylist.h" +#include "ecmascript/js_arraylist_iterator.h" #include "ecmascript/js_async_function.h" #include "ecmascript/js_dataview.h" #include "ecmascript/js_date.h" @@ -1867,6 +1868,21 @@ JSHandle ObjectFactory::NewJSArrayIterator(const JSHandle ObjectFactory::NewJSArrayListIterator(const JSHandle &arrayList, + IterationKind kind) +{ + NewObjectHook(); + JSHandle protoValue(thread_, thread_->GlobalConstants()->GetArrayListIteratorPrototype()); + JSHandle dynHandle = + NewEcmaDynClass(JSArrayListIterator::SIZE, JSType::JS_ARRAYLIST_ITERATOR, protoValue); + JSHandle iter(NewJSObject(dynHandle)); + iter->GetJSHClass()->SetExtensible(true); + iter->SetIteratedArrayList(thread_, arrayList); + iter->SetNextIndex(thread_, JSTaggedValue(0)); + iter->SetIterationKind(thread_, JSTaggedValue(static_cast(kind))); + return iter; +} + JSHandle ObjectFactory::CreateJSPromiseReactionsFunction(const void *nativeFunc) { JSHandle env = vm_->GetGlobalEnv(); @@ -2013,6 +2029,18 @@ JSHandle ObjectFactory::NewEmptyJSObject() return NewJSObjectByConstructor(JSHandle(builtinObj), builtinObj); } +JSHandle ObjectFactory::NewJSArrayList(array_size_t capacity) +{ + NewObjectHook(); + JSHandle builtinObj(thread_, thread_->GlobalConstants()->GetArrayListFunction()); + JSHandle obj = + JSHandle(NewJSObjectByConstructor(JSHandle(builtinObj), builtinObj)); + ObjectFactory *factory = thread_->GetEcmaVM()->GetFactory(); + obj->SetElements(thread_, factory->NewTaggedArray(capacity)); + + return obj; +} + EcmaString *ObjectFactory::ResolveString(uint32_t stringId) { JSMethod *caller = InterpretedFrameHandler(thread_).GetMethod(); diff --git a/ecmascript/object_factory.h b/ecmascript/object_factory.h index e9263cdc72a233d8e211a9ce3a3007c150e9c97a..317dd04a67b7ace50a2e5f4ca0f6792f7afde8f4 100644 --- a/ecmascript/object_factory.h +++ b/ecmascript/object_factory.h @@ -31,6 +31,7 @@ namespace panda::ecmascript { class JSObject; class JSArray; +class JSArrayList; class JSSymbol; class JSFunctionBase; class JSFunction; @@ -55,6 +56,7 @@ class JSRegExp; class JSSetIterator; class JSMapIterator; class JSArrayIterator; +class JSArrayListIterator; class JSStringIterator; class JSGeneratorObject; class CompletionRecord; @@ -124,6 +126,8 @@ public: JSHandle NewEmptyJSObject(); + JSHandle NewJSArrayList(array_size_t capacity); + // use for others create, prototype is Function.prototype // use for native function JSHandle NewJSFunction(const JSHandle &env, const void *nativeFunc = nullptr, @@ -271,6 +275,9 @@ public: JSHandle NewJSMapIterator(const JSHandle &map, IterationKind kind); JSHandle NewJSArrayIterator(const JSHandle &array, IterationKind kind); + + JSHandle NewJSArrayListIterator(const JSHandle &arrayList, + IterationKind kind); JSHandle NewCompletionRecord(uint8_t type, JSHandle value); diff --git a/ecmascript/snapshot/mem/snapshot_serialize.cpp b/ecmascript/snapshot/mem/snapshot_serialize.cpp index c6e479aa3beb7b34cf147957cfeb711ed2d8dba4..4c4f1027162b81efd33b6d195f8a20f16c5ce20c 100644 --- a/ecmascript/snapshot/mem/snapshot_serialize.cpp +++ b/ecmascript/snapshot/mem/snapshot_serialize.cpp @@ -548,7 +548,28 @@ static uintptr_t g_nativeTable[] = { reinterpret_cast(PluralRules::ResolvedOptions), reinterpret_cast(ArrayList::ArrayListConstructor), reinterpret_cast(ArrayList::Add), - reinterpret_cast(ArrayList::Iterator), + reinterpret_cast(ArrayList::Insert), + reinterpret_cast(ArrayList::Clear), + reinterpret_cast(ArrayList::Clone), + reinterpret_cast(ArrayList::Has), + reinterpret_cast(ArrayList::GetCapacity), + reinterpret_cast(ArrayList::IncreaseCapacityTo), + reinterpret_cast(ArrayList::TrimToCurrentLength), + reinterpret_cast(ArrayList::GetIndexOf), + reinterpret_cast(ArrayList::IsEmpty), + + reinterpret_cast(ArrayList::GetLastIndexOf), + reinterpret_cast(ArrayList::RemoveByIndex), + reinterpret_cast(ArrayList::Remove), + reinterpret_cast(ArrayList::RemoveByRange), + reinterpret_cast(ArrayList::ReplaceAllElements), + reinterpret_cast(ArrayList::SubArrayList), + reinterpret_cast(ArrayList::ConvertToArray), + reinterpret_cast(ArrayList::ForEach), + reinterpret_cast(ArrayList::GetIteratorObj), + reinterpret_cast(ArrayList::Get), + reinterpret_cast(ArrayList::Set), + reinterpret_cast(ArrayList::GetSize), // not builtins method reinterpret_cast(JSFunction::PrototypeSetter),