Add Container Plainarray

Description
  To ensure the high performance of container classes, Plainarray is
   provided in ark.
Related issue
   #I4XXYA:Add Container Plainarray

Signed-off-by: zhangjixing <zhangjixing4@huawei.com>
This commit is contained in:
zhangjixing 2022-04-12 09:39:08 +08:00
parent ac88a6ad3f
commit eafc261ff6
28 changed files with 2047 additions and 15 deletions

View File

@ -339,6 +339,7 @@ ecma_source = [
"ecmascript/builtins/builtins_weak_set.cpp",
"ecmascript/containers/containers_arraylist.cpp",
"ecmascript/containers/containers_deque.cpp",
"ecmascript/containers/containers_plainarray.cpp",
"ecmascript/containers/containers_private.cpp",
"ecmascript/containers/containers_queue.cpp",
"ecmascript/containers/containers_stack.cpp",
@ -371,12 +372,6 @@ ecma_source = [
"ecmascript/jobs/micro_job_queue.cpp",
"ecmascript/jspandafile/js_pandafile.cpp",
"ecmascript/jspandafile/js_pandafile_manager.cpp",
"ecmascript/js_api_deque.cpp",
"ecmascript/js_api_deque_iterator.cpp",
"ecmascript/js_api_queue.cpp",
"ecmascript/js_api_queue_iterator.cpp",
"ecmascript/js_api_stack.cpp",
"ecmascript/js_api_stack_iterator.cpp",
"ecmascript/jspandafile/class_info_extractor.cpp",
"ecmascript/jspandafile/debug_info_extractor.cpp",
"ecmascript/jspandafile/ecma_class_linker_extension.cpp",
@ -386,6 +381,16 @@ ecma_source = [
"ecmascript/jspandafile/panda_file_translator.cpp",
"ecmascript/jspandafile/js_pandafile_executor.cpp",
"ecmascript/jspandafile/scope_info_extractor.cpp",
"ecmascript/js_api_arraylist.cpp",
"ecmascript/js_api_arraylist_iterator.cpp",
"ecmascript/js_api_deque.cpp",
"ecmascript/js_api_deque_iterator.cpp",
"ecmascript/js_api_plain_array.cpp",
"ecmascript/js_api_plain_array_iterator.cpp",
"ecmascript/js_api_queue.cpp",
"ecmascript/js_api_queue_iterator.cpp",
"ecmascript/js_api_stack.cpp",
"ecmascript/js_api_stack_iterator.cpp",
"ecmascript/js_api_tree_map.cpp",
"ecmascript/js_api_tree_map_iterator.cpp",
"ecmascript/js_api_tree_set.cpp",
@ -394,8 +399,6 @@ ecma_source = [
"ecmascript/js_array.cpp",
"ecmascript/js_array_iterator.cpp",
"ecmascript/js_arraybuffer.cpp",
"ecmascript/js_api_arraylist.cpp",
"ecmascript/js_api_arraylist_iterator.cpp",
"ecmascript/js_async_function.cpp",
"ecmascript/js_bigint.cpp",
"ecmascript/js_dataview.cpp",

View File

@ -0,0 +1,355 @@
/*
* 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 "containers_plainarray.h"
#include "ecmascript/ecma_vm.h"
#include "ecmascript/js_api_plain_array.h"
#include "ecmascript/js_iterator.h"
#include "ecmascript/object_factory.h"
#include "ecmascript/tagged_array-inl.h"
namespace panda::ecmascript::containers {
JSTaggedValue ContainersPlainArray::PlainArrayConstructor(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, PlainArray, Constructor);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<JSTaggedValue> newTarget = GetNewTarget(argv);
if (newTarget->IsUndefined()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "new target can't be undefined", JSTaggedValue::Exception());
}
JSHandle<JSTaggedValue> constructor = GetConstructor(argv);
JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), newTarget);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<JSAPIPlainArray> plainArray = JSHandle<JSAPIPlainArray>::Cast(obj);
JSHandle<TaggedArray> keys =
JSAPIPlainArray::CreateSlot(thread, JSAPIPlainArray::DEFAULT_CAPACITY_LENGTH);
JSHandle<TaggedArray> values =
JSAPIPlainArray::CreateSlot(thread, JSAPIPlainArray::DEFAULT_CAPACITY_LENGTH);
plainArray->SetKeys(thread, keys);
plainArray->SetValues(thread, values);
return obj.GetTaggedValue();
}
JSTaggedValue ContainersPlainArray::Add(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, PlainArray, Add);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPIPlainArray()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIPlainArray", JSTaggedValue::Exception());
}
JSHandle<JSTaggedValue> key(GetCallArg(argv, 0));
JSHandle<JSTaggedValue> value(GetCallArg(argv, 1));
if (!key->IsNumber()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "the index is not integer", JSTaggedValue::Exception());
}
JSAPIPlainArray::Add(thread, JSHandle<JSAPIPlainArray>::Cast(self), key, value);
return JSTaggedValue::True();
}
JSTaggedValue ContainersPlainArray::Clear(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, PlainArray, Clear);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPIPlainArray()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIPlainArray", JSTaggedValue::Exception());
}
JSAPIPlainArray *array = JSAPIPlainArray::Cast(self->GetTaggedObject());
array->Clear(thread);
return JSTaggedValue::True();
}
JSTaggedValue ContainersPlainArray::Clone(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, PlainArray, Clone);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPIPlainArray()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIPlainArray", JSTaggedValue::Exception());
}
JSHandle<JSAPIPlainArray> newPlainArray =
JSAPIPlainArray::Clone(thread, JSHandle<JSAPIPlainArray>::Cast(self));
return newPlainArray.GetTaggedValue();
}
JSTaggedValue ContainersPlainArray::Has(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, PlainArray, Has);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPIPlainArray()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIPlainArray", JSTaggedValue::Exception());
}
JSHandle<JSTaggedValue> value(GetCallArg(argv, 0));
if (!value->IsNumber()) {
return JSTaggedValue::False();
}
JSAPIPlainArray *array = JSAPIPlainArray::Cast(self->GetTaggedObject());
int32_t key = value->GetNumber();
bool result = array->Has(key);
return JSTaggedValue(result);
}
JSTaggedValue ContainersPlainArray::Get(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, PlainArray, Get);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPIPlainArray()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIPlainArray", JSTaggedValue::Exception());
}
JSHandle<JSTaggedValue> key(GetCallArg(argv, 0));
if (!key->IsNumber()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "the key is not integer", JSTaggedValue::Exception());
}
JSAPIPlainArray *array = JSAPIPlainArray::Cast(self->GetTaggedObject());
JSTaggedValue value = array->Get(key.GetTaggedValue());
return value;
}
JSTaggedValue ContainersPlainArray::GetIteratorObj(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, PlainArray, GetIteratorObj);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPIPlainArray()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIPlainArray", JSTaggedValue::Exception());
}
JSHandle<JSTaggedValue> iter =
JSAPIPlainArray::GetIteratorObj(thread, JSHandle<JSAPIPlainArray>::Cast(self), IterationKind::KEY_AND_VALUE);
return iter.GetTaggedValue();
}
JSTaggedValue ContainersPlainArray::ForEach(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, PlainArray, ForEach);
JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
if (!callbackFnHandle->IsCallable()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "the callbackfun is not callable.", JSTaggedValue::Exception());
}
JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1);
return JSAPIPlainArray::ForEach(thread, thisHandle, callbackFnHandle, thisArgHandle);
}
JSTaggedValue ContainersPlainArray::ToString(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, PlainArray, ToString);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPIPlainArray()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIPlainArray", JSTaggedValue::Exception());
}
JSTaggedValue value = JSAPIPlainArray::ToString(thread, JSHandle<JSAPIPlainArray>::Cast(self));
return value;
}
JSTaggedValue ContainersPlainArray::GetIndexOfKey(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, PlainArray, GetIndexOfKey);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPIPlainArray()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIPlainArray", JSTaggedValue::Exception());
}
JSHandle<JSTaggedValue> value(GetCallArg(argv, 0));
if (!value->IsNumber()) {
return JSTaggedValue(-1);
}
JSAPIPlainArray *array = JSAPIPlainArray::Cast(self->GetTaggedObject());
int32_t key = value->GetNumber();
JSTaggedValue result = array->GetIndexOfKey(key);
return result;
}
JSTaggedValue ContainersPlainArray::GetIndexOfValue(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, PlainArray, GetIndexOfValue);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPIPlainArray()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIPlainArray", JSTaggedValue::Exception());
}
JSAPIPlainArray *array = JSAPIPlainArray::Cast(self->GetTaggedObject());
JSHandle<JSTaggedValue> value(GetCallArg(argv, 0));
JSTaggedValue jsValue = array->GetIndexOfValue(value.GetTaggedValue());
return jsValue;
}
JSTaggedValue ContainersPlainArray::IsEmpty(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, PlainArray, IsEmpty);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPIPlainArray()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIPlainArray", JSTaggedValue::Exception());
}
JSAPIPlainArray *array = JSAPIPlainArray::Cast(self->GetTaggedObject());
bool ret = array->IsEmpty();
return JSTaggedValue(ret);
}
JSTaggedValue ContainersPlainArray::GetKeyAt(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, PlainArray, GetKeyAt);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPIPlainArray()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIPlainArray", JSTaggedValue::Exception());
}
JSHandle<JSTaggedValue> value(GetCallArg(argv, 0));
if (!value->IsNumber()) {
return JSTaggedValue(-1);
}
JSAPIPlainArray *array = JSAPIPlainArray::Cast(self->GetTaggedObject());
int32_t index = value->GetNumber();
JSTaggedValue result = array->GetKeyAt(index);
return result;
}
JSTaggedValue ContainersPlainArray::Remove(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, PlainArray, Remove);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPIPlainArray()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIPlainArray", JSTaggedValue::Exception());
}
JSHandle<JSTaggedValue> key(GetCallArg(argv, 0));
if (!key->IsNumber()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "the key is not integer", JSTaggedValue::Undefined());
}
JSAPIPlainArray *array = JSAPIPlainArray::Cast(self->GetTaggedObject());
JSTaggedValue value = array->Remove(thread, key.GetTaggedValue());
return value;
}
JSTaggedValue ContainersPlainArray::RemoveAt(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, PlainArray, RemoveAt);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPIPlainArray()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIPlainArray", JSTaggedValue::Exception());
}
JSHandle<JSTaggedValue> index(GetCallArg(argv, 0));
if (!index->IsNumber()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "the index is not integer", JSTaggedValue::Undefined());
}
JSAPIPlainArray *array = JSAPIPlainArray::Cast(self->GetTaggedObject());
JSTaggedValue value = array->RemoveAt(thread, index.GetTaggedValue());
return value;
}
JSTaggedValue ContainersPlainArray::RemoveRangeFrom(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, PlainArray, RemoveRangeFrom);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPIPlainArray()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIPlainArray", JSTaggedValue::Exception());
}
JSHandle<JSTaggedValue> valueIndex(GetCallArg(argv, 0));
JSHandle<JSTaggedValue> valueSize(GetCallArg(argv, 1));
if (!valueIndex->IsNumber() || !valueSize->IsNumber()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "the index or the value is not integer", JSTaggedValue::Undefined());
}
int32_t index = valueIndex->GetNumber();
int32_t size = valueSize->GetNumber();
JSAPIPlainArray *array = JSAPIPlainArray::Cast(self->GetTaggedObject());
JSTaggedValue value = array->RemoveRangeFrom(thread, index, size);
return value;
}
JSTaggedValue ContainersPlainArray::SetValueAt(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, PlainArray, SetValueAt);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPIPlainArray()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIPlainArray", JSTaggedValue::Exception());
}
JSHandle<JSTaggedValue> index(GetCallArg(argv, 0));
JSHandle<JSTaggedValue> value(GetCallArg(argv, 1));
if (!index->IsNumber()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "the index is not integer", JSTaggedValue::Exception());
}
JSAPIPlainArray *array = JSAPIPlainArray::Cast(self->GetTaggedObject());
array->SetValueAt(thread, index.GetTaggedValue(), value.GetTaggedValue());
return JSTaggedValue::Undefined();
}
JSTaggedValue ContainersPlainArray::GetValueAt(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, PlainArray, GetValueAt);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPIPlainArray()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIPlainArray", JSTaggedValue::Exception());
}
JSHandle<JSTaggedValue> idx(GetCallArg(argv, 0));
if (!idx->IsNumber()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "the index is not integer", JSTaggedValue::Undefined());
}
JSAPIPlainArray *array = JSAPIPlainArray::Cast(self->GetTaggedObject());
int32_t index = idx->GetNumber();
JSTaggedValue value = array->GetValueAt(index);
return value;
}
JSTaggedValue ContainersPlainArray::GetSize(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv != nullptr);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, PlainArray, GetSize);
JSHandle<JSTaggedValue> self = GetThis(argv);
if (!self->IsJSAPIPlainArray()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPIPlainArray", JSTaggedValue::Exception());
}
uint32_t length = JSHandle<JSAPIPlainArray>::Cast(self)->GetSize();
return JSTaggedValue(length);
}
} // namespace panda::ecmascript::containers

View File

@ -0,0 +1,46 @@
/*
* 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.
*/
#ifndef ECMASCRIPT_CONTAINERS_CONTAINERS_PLAIN_ARRAY_H
#define ECMASCRIPT_CONTAINERS_CONTAINERS_PLAIN_ARRAY_H
#include "ecmascript/base/builtins_base.h"
#include "ecmascript/ecma_runtime_call_info.h"
namespace panda::ecmascript::containers {
class ContainersPlainArray : public base::BuiltinsBase {
public:
static JSTaggedValue PlainArrayConstructor(EcmaRuntimeCallInfo *argv);
static JSTaggedValue Add(EcmaRuntimeCallInfo *argv);
static JSTaggedValue Clear(EcmaRuntimeCallInfo *argv);
static JSTaggedValue Clone(EcmaRuntimeCallInfo *argv);
static JSTaggedValue Has(EcmaRuntimeCallInfo *argv);
static JSTaggedValue Get(EcmaRuntimeCallInfo *argv);
static JSTaggedValue GetIteratorObj(EcmaRuntimeCallInfo *argv);
static JSTaggedValue ForEach(EcmaRuntimeCallInfo *argv);
static JSTaggedValue ToString(EcmaRuntimeCallInfo *argv);
static JSTaggedValue GetIndexOfKey(EcmaRuntimeCallInfo *argv);
static JSTaggedValue GetIndexOfValue(EcmaRuntimeCallInfo *argv);
static JSTaggedValue IsEmpty(EcmaRuntimeCallInfo *argv);
static JSTaggedValue GetKeyAt(EcmaRuntimeCallInfo *argv);
static JSTaggedValue Remove(EcmaRuntimeCallInfo *argv);
static JSTaggedValue RemoveAt(EcmaRuntimeCallInfo *argv);
static JSTaggedValue RemoveRangeFrom(EcmaRuntimeCallInfo *argv);
static JSTaggedValue SetValueAt(EcmaRuntimeCallInfo *argv);
static JSTaggedValue GetValueAt(EcmaRuntimeCallInfo *argv);
static JSTaggedValue GetSize(EcmaRuntimeCallInfo *argv);
};
} // namespace panda::ecmascript::containers
#endif // ECMASCRIPT_CONTAINERS_CONTAINERS_PLAIN_ARRAY_H

View File

@ -17,6 +17,7 @@
#include "containers_arraylist.h"
#include "containers_deque.h"
#include "containers_plainarray.h"
#include "containers_queue.h"
#include "containers_stack.h"
#include "containers_treemap.h"
@ -26,6 +27,8 @@
#include "ecmascript/interpreter/fast_runtime_stub-inl.h"
#include "ecmascript/js_api_deque.h"
#include "ecmascript/js_api_deque_iterator.h"
#include "ecmascript/js_api_plain_array.h"
#include "ecmascript/js_api_plain_array_iterator.h"
#include "ecmascript/js_api_queue.h"
#include "ecmascript/js_api_queue_iterator.h"
#include "ecmascript/js_api_stack.h"
@ -41,7 +44,7 @@
namespace panda::ecmascript::containers {
JSTaggedValue ContainersPrivate::Load(EcmaRuntimeCallInfo *msg)
{
ASSERT(msg);
ASSERT(msg != nullptr);
JSThread *thread = msg->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> argv = GetCallArg(msg, 0);
@ -78,6 +81,10 @@ JSTaggedValue ContainersPrivate::Load(EcmaRuntimeCallInfo *msg)
res = InitializeContainer(thread, thisValue, InitializeDeque, "DequeConstructor");
break;
}
case ContainerTag::PlainArray: {
res = InitializeContainer(thread, thisValue, InitializePlainArray, "PlainArrayConstructor");
break;
}
case ContainerTag::Vector:
case ContainerTag::List:
case ContainerTag::LinkedList:
@ -85,7 +92,6 @@ JSTaggedValue ContainersPrivate::Load(EcmaRuntimeCallInfo *msg)
case ContainerTag::HashSet:
case ContainerTag::LightWeightMap:
case ContainerTag::LightWeightSet:
case ContainerTag::PlainArray:
case ContainerTag::END:
break;
default:
@ -198,7 +204,6 @@ void ContainersPrivate::SetFunctionAtSymbol(JSThread *thread, const JSHandle<Glo
JSHandle<JSTaggedValue> nameString(factory->NewFromASCII(name));
JSHandle<JSFunctionBase> baseFunction(function);
JSFunction::SetFunctionName(thread, baseFunction, nameString, thread->GlobalConstants()->GetHandledUndefined());
PropertyDescriptor descriptor(thread, JSHandle<JSTaggedValue>::Cast(function), false, false, false);
JSObject::DefineOwnProperty(thread, obj, symbol, descriptor);
}
@ -433,6 +438,79 @@ void ContainersPrivate::InitializeTreeSetIterator(JSThread *thread)
globalConst->SetConstant(ConstantIndex::TREESET_ITERATOR_PROTOTYPE_INDEX, setIteratorPrototype.GetTaggedValue());
}
JSHandle<JSTaggedValue> ContainersPrivate::InitializePlainArray(JSThread *thread)
{
auto globalConst = const_cast<GlobalEnvConstants *>(thread->GlobalConstants());
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
// PlainArray.prototype
JSHandle<JSObject> plainArrayFuncPrototype = factory->NewEmptyJSObject();
JSHandle<JSTaggedValue> plainArrayFuncPrototypeValue(plainArrayFuncPrototype);
// PlainArray.prototype_or_dynclass
JSHandle<JSHClass> plainArrayInstanceDynclass =
factory->NewEcmaDynClass(JSAPIPlainArray::SIZE, JSType::JS_API_PLAIN_ARRAY, plainArrayFuncPrototypeValue);
JSHandle<JSTaggedValue> plainArrayFunction(
NewContainerConstructor(thread, plainArrayFuncPrototype, ContainersPlainArray::PlainArrayConstructor,
"PlainArray", FuncLength::ZERO));
JSHandle<JSFunction>(plainArrayFunction)->SetFunctionPrototype(thread,
plainArrayInstanceDynclass.GetTaggedValue());
// "constructor" property on the prototype
JSHandle<JSTaggedValue> constructorKey = globalConst->GetHandledConstructorString();
JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(plainArrayFuncPrototype), constructorKey,
plainArrayFunction);
// PlainArray.prototype.add()
SetFrozenFunction(thread, plainArrayFuncPrototype, "add", ContainersPlainArray::Add, FuncLength::ONE);
SetFrozenFunction(thread, plainArrayFuncPrototype, "clear", ContainersPlainArray::Clear, FuncLength::ONE);
SetFrozenFunction(thread, plainArrayFuncPrototype, "clone", ContainersPlainArray::Clone, FuncLength::ONE);
SetFrozenFunction(thread, plainArrayFuncPrototype, "has", ContainersPlainArray::Has, FuncLength::ONE);
SetFrozenFunction(thread, plainArrayFuncPrototype, "get", ContainersPlainArray::Get, FuncLength::ONE);
SetFrozenFunction(thread, plainArrayFuncPrototype, "forEach", ContainersPlainArray::ForEach, FuncLength::ONE);
SetFrozenFunction(thread, plainArrayFuncPrototype, "toString", ContainersPlainArray::ToString,
FuncLength::ZERO);
SetFrozenFunction(thread, plainArrayFuncPrototype, "getIndexOfKey", ContainersPlainArray::GetIndexOfKey,
FuncLength::ZERO);
SetFrozenFunction(thread, plainArrayFuncPrototype, "getIndexOfValue", ContainersPlainArray::GetIndexOfValue,
FuncLength::ZERO);
SetFrozenFunction(thread, plainArrayFuncPrototype, "isEmpty", ContainersPlainArray::IsEmpty, FuncLength::ZERO);
SetFrozenFunction(thread, plainArrayFuncPrototype, "getKeyAt",
ContainersPlainArray::GetKeyAt, FuncLength::ZERO);
SetFrozenFunction(thread, plainArrayFuncPrototype, "remove", ContainersPlainArray::Remove, FuncLength::ZERO);
SetFrozenFunction(thread, plainArrayFuncPrototype, "removeAt", ContainersPlainArray::RemoveAt,
FuncLength::ZERO);
SetFrozenFunction(thread, plainArrayFuncPrototype, "removeRangeFrom", ContainersPlainArray::RemoveRangeFrom,
FuncLength::ZERO);
SetFrozenFunction(thread, plainArrayFuncPrototype, "setValueAt", ContainersPlainArray::SetValueAt,
FuncLength::ZERO);
SetFrozenFunction(thread, plainArrayFuncPrototype, "getValueAt", ContainersPlainArray::GetValueAt,
FuncLength::ZERO);
JSHandle<JSTaggedValue> lengthGetter = CreateGetter(thread, ContainersPlainArray::GetSize, "length",
FuncLength::ZERO);
JSHandle<JSTaggedValue> lengthKey(factory->NewFromASCII("length"));
SetGetter(thread, plainArrayFuncPrototype, lengthKey, lengthGetter);
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
SetFunctionAtSymbol(thread, env, plainArrayFuncPrototype, env->GetIteratorSymbol(), "[Symbol.iterator]",
ContainersPlainArray::GetIteratorObj, FuncLength::ONE);
InitializePlainArrayIterator(thread);
globalConst->SetConstant(ConstantIndex::PLAIN_ARRAY_FUNCTION_INDEX, plainArrayFunction.GetTaggedValue());
return plainArrayFunction;
}
void ContainersPrivate::InitializePlainArrayIterator(JSThread *thread)
{
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
auto globalConst = const_cast<GlobalEnvConstants *>(thread->GlobalConstants());
JSHandle<JSHClass> iteratorDynclass = JSHandle<JSHClass>(thread, globalConst->
GetHandledJSAPIIteratorFuncDynClass().
GetObject<JSHClass>());
JSHandle<JSObject> plainarrayIteratorPrototype(factory->NewJSObject(iteratorDynclass));
SetFrozenFunction(thread, plainarrayIteratorPrototype, "next", JSAPIPlainArrayIterator::Next, FuncLength::ONE);
SetStringTagSymbol(thread, env, plainarrayIteratorPrototype, "PlainArray Iterator");
globalConst->SetConstant(ConstantIndex::PLAIN_ARRAY_ITERATOR_PROTOTYPE_INDEX,
plainarrayIteratorPrototype.GetTaggedValue());
}
JSHandle<JSTaggedValue> ContainersPrivate::InitializeStack(JSThread *thread)
{
auto globalConst = const_cast<GlobalEnvConstants *>(thread->GlobalConstants());

View File

@ -74,6 +74,8 @@ private:
static void InitializeTreeMapIterator(JSThread *thread);
static JSHandle<JSTaggedValue> InitializeTreeSet(JSThread *thread);
static void InitializeTreeSetIterator(JSThread *thread);
static JSHandle<JSTaggedValue> InitializePlainArray(JSThread *thread);
static void InitializePlainArrayIterator(JSThread *thread);
static JSHandle<JSTaggedValue> InitializeQueue(JSThread *thread);
static void InitializeQueueIterator(JSThread *thread, const JSHandle<GlobalEnv> &env,
GlobalEnvConstants *globalConst);

View File

@ -59,6 +59,32 @@ host_unittest_action("ContainersTreeSetTest") {
}
}
host_unittest_action("ContainersPlainArrayTest") {
module_out_path = module_output_path
sources = [
# test file
"containers_plainarray_test.cpp",
]
configs = [
"//ark/js_runtime:ecma_test_config",
"//ark/js_runtime:ark_jsruntime_public_config", # should add before
# arkruntime_public_config
"//ark/js_runtime:ark_jsruntime_common_config",
"$ark_root/runtime:arkruntime_public_config",
]
deps = [
"$ark_root/libpandabase:libarkbase",
"//ark/js_runtime:libark_jsruntime_test",
sdk_libc_secshared_dep,
]
if (!is_standard_system) {
deps += [ "$ark_root/runtime:libarkruntime" ]
}
}
host_unittest_action("ContainersStackTest") {
module_out_path = module_output_path
@ -119,6 +145,7 @@ group("unittest") {
# deps file
deps = [
":ContainersDequeTest",
":ContainersPlainArrayTest",
":ContainersStackTest",
":ContainersTreeMapTest",
":ContainersTreeSetTest",
@ -131,6 +158,7 @@ group("host_unittest") {
# deps file
deps = [
":ContainersDequeTestAction",
":ContainersPlainArrayTestAction",
":ContainersStackTestAction",
":ContainersTreeMapTestAction",
":ContainersTreeSetTestAction",

View File

@ -0,0 +1,376 @@
/*
* 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/js_api_plain_array.h"
#include "ecmascript/containers/containers_private.h"
#include "ecmascript/containers/containers_plainarray.h"
#include "ecmascript/ecma_runtime_call_info.h"
#include "ecmascript/global_env.h"
#include "ecmascript/js_api_plain_array_iterator.h"
#include "ecmascript/js_handle.h"
#include "ecmascript/js_tagged_value-inl.h"
#include "ecmascript/js_thread.h"
#include "ecmascript/object_factory.h"
#include "ecmascript/tests/test_helper.h"
using namespace panda::ecmascript;
using namespace panda::ecmascript::containers;
namespace panda::test {
class ContainersPlainArrayTest : public testing::Test {
public:
static void SetUpTestCase()
{
GTEST_LOG_(INFO) << "SetUpTestCase";
}
static void TearDownTestCase()
{
GTEST_LOG_(INFO) << "TearDownCase";
}
void SetUp() override
{
TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
}
void TearDown() override
{
TestHelper::DestroyEcmaVMWithScope(instance, scope);
}
PandaVM *instance {nullptr};
EcmaHandleScope *scope {nullptr};
JSThread *thread {nullptr};
class TestClass : public base::BuiltinsBase {
public:
static JSTaggedValue TestForEachFunc(EcmaRuntimeCallInfo *argv)
{
JSThread *thread = argv->GetThread();
JSHandle<JSTaggedValue> key = GetCallArg(argv, 0); // 0 means the value
JSHandle<JSTaggedValue> value = GetCallArg(argv, 1); // 1 means the value
JSHandle<JSAPIPlainArray> plainArray(GetCallArg(argv, 2)); // 2 means the value
if (key->IsNumber()) {
JSHandle<JSTaggedValue> newValue(thread, JSTaggedValue(value->GetInt() * 2)); // 2 means the value
JSAPIPlainArray::Add(thread, plainArray, key, newValue);
}
return JSTaggedValue::True();
}
};
protected:
JSTaggedValue InitializePlainArrayConstructor()
{
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
JSHandle<JSTaggedValue> globalObject = env->GetJSGlobalObject();
JSHandle<JSTaggedValue> key(factory->NewFromASCII("ArkPrivate"));
JSHandle<JSTaggedValue> value =
JSObject::GetProperty(thread, JSHandle<JSTaggedValue>(globalObject), key).GetValue();
auto objCallInfo =
TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6); // 6 means the value
objCallInfo->SetFunction(JSTaggedValue::Undefined());
objCallInfo->SetThis(value.GetTaggedValue());
objCallInfo->SetCallArg(0, JSTaggedValue(static_cast<int>(ContainerTag::PlainArray)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, objCallInfo.get());
JSTaggedValue result = ContainersPrivate::Load(objCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
return result;
}
JSHandle<JSAPIPlainArray> CreateJSAPIPlainArray()
{
JSHandle<JSFunction> newTarget(thread, InitializePlainArrayConstructor());
auto objCallInfo =
TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4); // 4 means the value
objCallInfo->SetFunction(newTarget.GetTaggedValue());
objCallInfo->SetNewTarget(newTarget.GetTaggedValue());
objCallInfo->SetThis(JSTaggedValue::Undefined());
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, objCallInfo.get());
JSTaggedValue result = ContainersPlainArray::PlainArrayConstructor(objCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
JSHandle<JSAPIPlainArray> plain(thread, result);
return plain;
}
};
HWTEST_F_L0(ContainersPlainArrayTest, PlainArrayConstructor)
{
InitializePlainArrayConstructor();
JSHandle<JSFunction> newTarget(thread, InitializePlainArrayConstructor());
auto objCallInfo =
TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4); // 4 means the value
objCallInfo->SetFunction(newTarget.GetTaggedValue());
objCallInfo->SetNewTarget(newTarget.GetTaggedValue());
objCallInfo->SetThis(JSTaggedValue::Undefined());
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, objCallInfo.get());
JSTaggedValue result = ContainersPlainArray::PlainArrayConstructor(objCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_TRUE(result.IsJSAPIPlainArray());
JSHandle<JSAPIPlainArray> arrayHandle(thread, result);
JSTaggedValue resultProto = JSObject::GetPrototype(JSHandle<JSObject>::Cast(arrayHandle));
JSTaggedValue funcProto = newTarget->GetFunctionPrototype();
ASSERT_EQ(resultProto, funcProto);
int size = arrayHandle->GetSize();
ASSERT_EQ(size, 0);
}
HWTEST_F_L0(ContainersPlainArrayTest, AddAndHas)
{
constexpr uint32_t NODE_NUMBERS = 8; // 8 means the value
JSHandle<JSAPIPlainArray> tArray1 = CreateJSAPIPlainArray();
for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
auto callInfo =
TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8); // 8 means the value
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(tArray1.GetTaggedValue());
callInfo->SetCallArg(0, JSTaggedValue(i));
callInfo->SetCallArg(1, JSTaggedValue(i + 1));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
JSTaggedValue result = ContainersPlainArray::Add(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
EXPECT_TRUE(result.IsTrue());
EXPECT_EQ(tArray1->GetSize(), static_cast<int>(i + 1));
}
EXPECT_EQ(tArray1->GetSize(), static_cast<int>(NODE_NUMBERS));
// test has
for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
auto callInfo =
TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8); // 8 means the value
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(tArray1.GetTaggedValue());
callInfo->SetCallArg(0, JSTaggedValue(i));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
JSTaggedValue result = ContainersPlainArray::Has(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
EXPECT_TRUE(result.IsTrue());
}
EXPECT_EQ(tArray1->GetSize(), static_cast<int>(NODE_NUMBERS));
// test add string
JSHandle<JSAPIPlainArray> tArray = CreateJSAPIPlainArray();
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
std::string myValue("myvalue");
for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
std::string ivalue = myValue + std::to_string(i);
key.Update(JSTaggedValue(i));
value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
auto callInfo =
TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8); // 8 means the value
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(tArray.GetTaggedValue());
callInfo->SetCallArg(0, key.GetTaggedValue());
callInfo->SetCallArg(1, value.GetTaggedValue());
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
JSTaggedValue result = ContainersPlainArray::Add(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
EXPECT_TRUE(result.IsTrue());
}
EXPECT_EQ(tArray->GetSize(), static_cast<int>(NODE_NUMBERS));
// test get
for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
std::string ivalue = myValue + std::to_string(i);
key.Update(JSTaggedValue(i));
value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
auto callInfo =
TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8); // 8 means the value
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(tArray.GetTaggedValue());
callInfo->SetCallArg(0, key.GetTaggedValue());
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
JSTaggedValue result = ContainersPlainArray::Get(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
EXPECT_TRUE(JSTaggedValue::Equal(thread, JSHandle<JSTaggedValue>(thread, result), value));
}
}
HWTEST_F_L0(ContainersPlainArrayTest, Iterator)
{
constexpr uint32_t NODE_NUMBERS = 8;
JSHandle<JSAPIPlainArray> array = CreateJSAPIPlainArray();
for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
auto callInfo =
TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8); // 8 means the value
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(array.GetTaggedValue());
callInfo->SetCallArg(0, JSTaggedValue(i));
callInfo->SetCallArg(1, JSTaggedValue(i + 1));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
JSTaggedValue result = ContainersPlainArray::Add(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
EXPECT_TRUE(result.IsTrue());
EXPECT_EQ(array->GetSize(), static_cast<int>(i + 1));
}
// test iterator
{
auto callInf = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
callInf->SetFunction(JSTaggedValue::Undefined());
callInf->SetThis(array.GetTaggedValue());
[[maybe_unused]] auto pre = TestHelper::SetupFrame(thread, callInf.get());
JSHandle<JSTaggedValue> iter(thread, ContainersPlainArray::GetIteratorObj(callInf.get()));
TestHelper::TearDownFrame(thread, pre);
EXPECT_TRUE(iter->IsJSAPIPlainArrayIterator());
JSHandle<JSTaggedValue> first(thread, JSTaggedValue(0));
JSHandle<JSTaggedValue> second(thread, JSTaggedValue(1));
JSMutableHandle<JSTaggedValue> result(thread, JSTaggedValue::Undefined());
JSMutableHandle<JSTaggedValue> entries(thread, JSTaggedValue::Undefined());
for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
auto callInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(iter.GetTaggedValue());
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
result.Update(JSAPIPlainArrayIterator::Next(callInfo.get()));
TestHelper::TearDownFrame(thread, prev);
entries.Update(JSIterator::IteratorValue(thread, result).GetTaggedValue());
EXPECT_EQ(static_cast<int>(i), JSObject::GetProperty(thread, entries, first).GetValue()->GetInt());
EXPECT_EQ(static_cast<int>(i + 1), JSObject::GetProperty(thread, entries, second).GetValue()->GetInt());
}
}
// test add string
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
std::string myValue("myvalue");
for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
std::string iValue = myValue + std::to_string(i);
value.Update(factory->NewFromStdString(iValue).GetTaggedValue());
auto callInfo =
TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8); // 8 means the value
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(array.GetTaggedValue());
callInfo->SetCallArg(0, JSTaggedValue(100 + i));
callInfo->SetCallArg(1, value.GetTaggedValue());
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
JSTaggedValue result = ContainersPlainArray::Add(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
EXPECT_TRUE(result.IsTrue());
EXPECT_EQ(array->GetSize(), static_cast<int>(NODE_NUMBERS + i + 1));
}
EXPECT_EQ(array->GetSize(), static_cast<int>(NODE_NUMBERS * 2));
}
HWTEST_F_L0(ContainersPlainArrayTest, GetIndexOfKeyAndGetIndexOfValue)
{
constexpr uint32_t NODE_NUMBERS = 8;
JSHandle<JSAPIPlainArray> pArray = CreateJSAPIPlainArray();
for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
auto callInfo =
TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8); // 4 means the value
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(pArray.GetTaggedValue());
callInfo->SetCallArg(0, JSTaggedValue(i));
callInfo->SetCallArg(1, JSTaggedValue(i + 1));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
JSTaggedValue result = ContainersPlainArray::Add(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
EXPECT_TRUE(result.IsTrue());
EXPECT_EQ(pArray->GetSize(), static_cast<int>(i + 1));
}
// test GetIndexOfKey
{
auto callInfo =
TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6); // 6 means the value
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(pArray.GetTaggedValue());
callInfo->SetCallArg(0, JSTaggedValue(2));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
JSTaggedValue result = ContainersPlainArray::GetIndexOfKey(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
EXPECT_EQ(result, JSTaggedValue(2));
}
// test GetIndexOfValue
{
auto callInfo =
TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6); // 6 means the value
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(pArray.GetTaggedValue());
callInfo->SetCallArg(0, JSTaggedValue(4));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
JSTaggedValue result = ContainersPlainArray::GetIndexOfValue(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
EXPECT_EQ(result, JSTaggedValue(3));
}
// test add string
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
std::string myValue("myvalue");
for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
std::string iValue = myValue + std::to_string(i);
value.Update(factory->NewFromStdString(iValue).GetTaggedValue());
auto callInfo =
TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8); // 8 means the value
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(pArray.GetTaggedValue());
callInfo->SetCallArg(0, JSTaggedValue(100 + i));
callInfo->SetCallArg(1, value.GetTaggedValue());
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
JSTaggedValue result = ContainersPlainArray::Add(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
EXPECT_TRUE(result.IsTrue());
EXPECT_EQ(pArray->GetSize(), static_cast<int>(NODE_NUMBERS + i + 1));
}
EXPECT_EQ(pArray->GetSize(), static_cast<int>(NODE_NUMBERS * 2));
// test GetIndexOfKey
{
auto callInfo =
TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6); // 6 means the value
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(pArray.GetTaggedValue());
callInfo->SetCallArg(0, JSTaggedValue(102));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
JSTaggedValue result = ContainersPlainArray::GetIndexOfKey(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
EXPECT_EQ(result, JSTaggedValue(10));
}
// test GetIndexOfValue
{
std::string tValue("myvalue3");
value.Update(factory->NewFromStdString(tValue).GetTaggedValue());
auto callInfo =
TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6); // 6 means the value
callInfo->SetFunction(JSTaggedValue::Undefined());
callInfo->SetThis(pArray.GetTaggedValue());
callInfo->SetCallArg(0, value.GetTaggedValue());
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, callInfo.get());
JSTaggedValue result = ContainersPlainArray::GetIndexOfValue(callInfo.get());
TestHelper::TearDownFrame(thread, prev);
EXPECT_EQ(result, JSTaggedValue(11));
}
}
}

View File

@ -364,6 +364,10 @@ CString *HeapSnapShot::GenerateNodeName(TaggedObject *entry)
return GetString("ResolvedBinding");
case JSType::JS_MODULE_NAMESPACE:
return GetString("ModuleNamespace");
case JSType::JS_API_PLAIN_ARRAY:
return GetString("PlainArray");
case JSType::JS_API_PLAIN_ARRAY_ITERATOR:
return GetString("PlainArrayIterator");
default:
break;
}

View File

@ -28,14 +28,18 @@
#include "ecmascript/interpreter/frame_handler.h"
#include "ecmascript/jobs/micro_job_queue.h"
#include "ecmascript/jobs/pending_job.h"
#include "ecmascript/jspandafile/class_info_extractor.h"
#include "ecmascript/jspandafile/program_object.h"
#include "ecmascript/js_api_arraylist.h"
#include "ecmascript/js_api_arraylist_iterator.h"
#include "ecmascript/js_api_deque.h"
#include "ecmascript/js_api_deque_iterator.h"
#include "ecmascript/js_api_plain_array.h"
#include "ecmascript/js_api_plain_array_iterator.h"
#include "ecmascript/js_api_queue.h"
#include "ecmascript/js_api_queue_iterator.h"
#include "ecmascript/js_api_stack.h"
#include "ecmascript/js_api_stack_iterator.h"
#include "ecmascript/jspandafile/class_info_extractor.h"
#include "ecmascript/jspandafile/program_object.h"
#include "ecmascript/js_api_tree_map.h"
#include "ecmascript/js_api_tree_map_iterator.h"
#include "ecmascript/js_api_tree_set.h"
@ -43,8 +47,6 @@
#include "ecmascript/js_array.h"
#include "ecmascript/js_array_iterator.h"
#include "ecmascript/js_arraybuffer.h"
#include "ecmascript/js_api_arraylist.h"
#include "ecmascript/js_api_arraylist_iterator.h"
#include "ecmascript/js_async_function.h"
#include "ecmascript/js_bigint.h"
#include "ecmascript/js_collator.h"
@ -307,6 +309,10 @@ CString JSHClass::DumpJSType(JSType type)
return "Queue";
case JSType::JS_API_QUEUE_ITERATOR:
return "QueueIterator";
case JSType::JS_API_PLAIN_ARRAY:
return "PlainArray";
case JSType::JS_API_PLAIN_ARRAY_ITERATOR:
return "PlainArrayIterator";
case JSType::JS_API_DEQUE:
return "Deque";
case JSType::JS_API_DEQUE_ITERATOR:
@ -732,6 +738,12 @@ static void DumpObject(TaggedObject *obj, std::ostream &os)
case JSType::JS_MODULE_NAMESPACE:
ModuleNamespace::Cast(obj)->Dump(os);
break;
case JSType::JS_API_PLAIN_ARRAY:
JSAPIPlainArray::Cast(obj)->Dump(os);
break;
case JSType::JS_API_PLAIN_ARRAY_ITERATOR:
JSAPIPlainArrayIterator::Cast(obj)->Dump(os);
break;
default:
UNREACHABLE();
break;
@ -1332,6 +1344,44 @@ void TaggedTreeSet::Dump(std::ostream &os) const
}
}
void JSAPIPlainArray::Dump(std::ostream &os) const
{
TaggedArray *keys = TaggedArray::Cast(GetKeys().GetTaggedObject());
TaggedArray *values = TaggedArray::Cast(GetValues().GetTaggedObject());
uint32_t len = GetLength();
for (uint32_t i = 0; i < len; i++) {
os << " - keys: ";
keys->Get(i).DumpTaggedValue(os);
os << "\n";
os << " - values: ";
values->Get(i).DumpTaggedValue(os);
os << "\n";
}
os << " - length: " << std::dec << len << "\n";
JSObject::Dump(os);
}
void JSAPIPlainArray::DumpForSnapshot(std::vector<std::pair<CString, JSTaggedValue>> &vec) const
{
JSObject::DumpForSnapshot(vec);
}
void JSAPIPlainArrayIterator::Dump(std::ostream &os) const
{
JSAPIPlainArray *array = JSAPIPlainArray::Cast(GetIteratedPlainArray().GetTaggedObject());
os << " - length: " << std::dec << array->GetSize() << "\n";
os << " - nextIndex: " << std::dec << GetNextIndex() << "\n";
JSObject::Dump(os);
}
void JSAPIPlainArrayIterator::DumpForSnapshot(std::vector<std::pair<CString, JSTaggedValue>> &vec) const
{
JSAPIPlainArray *array = JSAPIPlainArray::Cast(GetIteratedPlainArray().GetTaggedObject());
array->DumpForSnapshot(vec);
vec.push_back(std::make_pair(CString("NextIndex"), JSTaggedValue(GetNextIndex())));
JSObject::DumpForSnapshot(vec);
}
void JSForInIterator::Dump(std::ostream &os) const
{
os << " - Object : ";
@ -2905,6 +2955,12 @@ static void DumpObject(TaggedObject *obj,
case JSType::JS_MODULE_NAMESPACE:
ModuleNamespace::Cast(obj)->DumpForSnapshot(vec);
return;
case JSType::JS_API_PLAIN_ARRAY:
JSAPIPlainArray::Cast(obj)->DumpForSnapshot(vec);
return;
case JSType::JS_API_PLAIN_ARRAY_ITERATOR:
JSAPIPlainArrayIterator::Cast(obj)->DumpForSnapshot(vec);
return;
default:
break;
}
@ -3515,6 +3571,8 @@ void GlobalEnv::DumpForSnapshot(std::vector<std::pair<CString, JSTaggedValue>> &
vec.push_back(std::make_pair(CString("TreeMapIteratorPrototype"), globalConst->GetTreeMapIteratorPrototype()));
vec.push_back(std::make_pair(CString("TreeSetIteratorPrototype"), globalConst->GetTreeSetIteratorPrototype()));
vec.push_back(std::make_pair(CString("QueueIteratorPrototype"), globalConst->GetQueueIteratorPrototype()));
vec.push_back(
std::make_pair(CString("PlainArrayIteratorPrototype"), globalConst->GetPlainArrayIteratorPrototype()));
vec.push_back(std::make_pair(CString("DequeIteratorPrototype"), globalConst->GetDequeIteratorPrototype()));
vec.push_back(std::make_pair(CString("StackIteratorPrototype"), globalConst->GetStackIteratorPrototype()));
}

View File

@ -29,6 +29,7 @@
#include "ecmascript/jobs/pending_job.h"
#include "ecmascript/js_api_arraylist_iterator.h"
#include "ecmascript/js_api_deque_iterator.h"
#include "ecmascript/js_api_plain_array_iterator.h"
#include "ecmascript/js_api_queue_iterator.h"
#include "ecmascript/js_api_stack_iterator.h"
#include "ecmascript/js_api_tree_map_iterator.h"
@ -184,6 +185,9 @@ void GlobalEnvConstants::InitRootsClass([[maybe_unused]] JSThread *thread, JSHCl
factory->NewEcmaDynClass(dynClassClass, JSAPIArrayListIterator::SIZE, JSType::JS_API_ARRAYLIST_ITERATOR));
SetConstant(ConstantIndex::JS_API_DEQUE_ITERATOR_CLASS_INDEX,
factory->NewEcmaDynClass(dynClassClass, JSAPIDequeIterator::SIZE, JSType::JS_API_DEQUE_ITERATOR));
SetConstant(
ConstantIndex::JS_API_PLAIN_ARRAY_ITERATOR_CLASS_INDEX,
factory->NewEcmaDynClass(dynClassClass, JSAPIPlainArrayIterator::SIZE, JSType::JS_API_PLAIN_ARRAY_ITERATOR));
SetConstant(ConstantIndex::JS_API_QUEUE_ITERATOR_CLASS_INDEX,
factory->NewEcmaDynClass(dynClassClass, JSAPIQueueIterator::SIZE, JSType::JS_API_QUEUE_ITERATOR));
SetConstant(ConstantIndex::JS_API_STACK_ITERATOR_CLASS_INDEX,

View File

@ -84,6 +84,7 @@ class JSThread;
V(JSTaggedValue, JSArrayIteratorClass, JS_ARRAY_ITERATOR_CLASS_INDEX, ecma_roots_class) \
V(JSTaggedValue, JSAPIArrayListIteratorClass, JS_API_ARRAYLIST_ITERATOR_CLASS_INDEX, ecma_roots_class) \
V(JSTaggedValue, JSAPIDequeIteratorClass, JS_API_DEQUE_ITERATOR_CLASS_INDEX, ecma_roots_class) \
V(JSTaggedValue, JSAPIPlainArrayIteratorClass, JS_API_PLAIN_ARRAY_ITERATOR_CLASS_INDEX, ecma_roots_class) \
V(JSTaggedValue, JSAPIQueueIteratorClass, JS_API_QUEUE_ITERATOR_CLASS_INDEX, ecma_roots_class) \
V(JSTaggedValue, JSAPIStackIteratorClass, JS_API_STACK_ITERATOR_CLASS_INDEX, ecma_roots_class) \
V(JSTaggedValue, JSAPITreeMapIteratorClass, JS_API_TREE_MAP_ITERATOR_CLASS_INDEX, ecma_roots_class) \
@ -116,6 +117,8 @@ class JSThread;
V(JSTaggedValue, TreeMapIteratorPrototype, TREEMAP_ITERATOR_PROTOTYPE_INDEX, TreeMapIterator) \
V(JSTaggedValue, TreeSetIteratorPrototype, TREESET_ITERATOR_PROTOTYPE_INDEX, TreeSetIterator) \
V(JSTaggedValue, QueueIteratorPrototype, QUEUE_ITERATOR_PROTOTYPE_INDEX, QueueIterator) \
V(JSTaggedValue, PlainArrayIteratorPrototype, PLAIN_ARRAY_ITERATOR_PROTOTYPE_INDEX, PlainArrayIterator) \
V(JSTaggedValue, PlainArrayFunction, PLAIN_ARRAY_FUNCTION_INDEX, PlainArrayFunction) \
V(JSTaggedValue, DequeIteratorPrototype, DEQUE_ITERATOR_PROTOTYPE_INDEX, DequeIterator) \
V(JSTaggedValue, StackIteratorPrototype, STACK_ITERATOR_PROTOTYPE_INDEX, StackIterator) \
/* SymbolTable*RegisterSymbols */ \

View File

@ -23,6 +23,7 @@
#include "ecmascript/interpreter/interpreter.h"
#include "ecmascript/js_api_arraylist.h"
#include "ecmascript/js_api_deque.h"
#include "ecmascript/js_api_plain_array.h"
#include "ecmascript/js_api_queue.h"
#include "ecmascript/js_api_stack.h"
#include "ecmascript/js_function.h"
@ -1366,6 +1367,9 @@ JSTaggedValue FastRuntimeStub::GetContainerProperty(JSThread *thread, JSTaggedVa
case JSType::JS_API_QUEUE:
res = JSAPIQueue::Cast(receiver.GetTaggedObject())->Get(thread, index);
break;
case JSType::JS_API_PLAIN_ARRAY:
res = JSAPIPlainArray::Cast(receiver.GetTaggedObject())->Get(JSTaggedValue(index));
break;
case JSType::JS_API_DEQUE:
res = JSAPIDeque::Cast(receiver.GetTaggedObject())->Get(index);
break;
@ -1389,6 +1393,9 @@ JSTaggedValue FastRuntimeStub::SetContainerProperty(JSThread *thread, JSTaggedVa
case JSType::JS_API_QUEUE:
res = JSAPIQueue::Cast(receiver.GetTaggedObject())->Set(thread, index, value);
break;
case JSType::JS_API_PLAIN_ARRAY:
res = JSAPIPlainArray::Set(thread, JSHandle<JSAPIPlainArray> (thread, receiver), index, value);
break;
case JSType::JS_API_DEQUE:
res = JSAPIDeque::Cast(receiver.GetTaggedObject())->Set(thread, index, value);
break;

View File

@ -0,0 +1,394 @@
/*
* 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 "js_api_plain_array.h"
#include "js_api_plain_array_iterator.h"
#include "ecmascript/js_function.h"
#include "ecmascript/interpreter/interpreter.h"
#include "ecmascript/js_tagged_value.h"
#include "ecmascript/object_factory.h"
namespace panda::ecmascript {
void JSAPIPlainArray::Add(JSThread *thread, const JSHandle<JSAPIPlainArray> &obj, JSHandle<JSTaggedValue> key,
JSHandle<JSTaggedValue> value)
{
JSHandle<TaggedArray> keyArray(thread, obj->GetKeys());
JSHandle<TaggedArray> valueArray(thread, obj->GetValues());
int32_t size = obj->GetLength();
int32_t index = obj->BinarySearch(*keyArray, 0, size, key.GetTaggedValue().GetNumber());
if (index >= 0) {
keyArray->Set(thread, index, key);
valueArray->Set(thread, index, value);
return;
}
index ^= 0xFFFFFFFF;
if (index < size) {
obj->AdjustArray(thread, *keyArray, index, size, true);
obj->AdjustArray(thread, *valueArray, index, size, true);
}
int32_t capacity = valueArray->GetLength();
if (size + 1 >= capacity) {
uint32_t newCapacity = capacity << 1U;
keyArray =
thread->GetEcmaVM()->GetFactory()->CopyArray(keyArray, capacity, newCapacity);
valueArray =
thread->GetEcmaVM()->GetFactory()->CopyArray(valueArray, capacity, newCapacity);
obj->SetKeys(thread, keyArray);
obj->SetValues(thread, valueArray);
}
keyArray->Set(thread, index, key);
valueArray->Set(thread, index, value);
size++;
obj->SetLength(size);
}
JSHandle<TaggedArray> JSAPIPlainArray::CreateSlot(const JSThread *thread, const uint32_t capacity)
{
ASSERT_PRINT(capacity > 0, "size must be a non-negative integer");
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<TaggedArray> taggedArray = factory->NewTaggedArray(capacity, JSTaggedValue::Hole());
return taggedArray;
}
bool JSAPIPlainArray::AdjustForward(JSThread *thread, int32_t index, int32_t forwardSize)
{
int32_t size = GetLength();
TaggedArray *keys = TaggedArray::Cast(GetKeys().GetTaggedObject());
TaggedArray *values = TaggedArray::Cast(GetValues().GetTaggedObject());
AdjustArray(thread, keys, index + forwardSize, index, false);
AdjustArray(thread, values, index + forwardSize, index, false);
size = size - forwardSize;
SetLength(size);
return true;
}
void JSAPIPlainArray::AdjustArray(JSThread *thread, TaggedArray *srcArray, int32_t fromIndex,
int32_t toIndex, bool direction)
{
int32_t size = GetLength();
int32_t idx = size - 1;
if (direction) {
while (fromIndex < toIndex) {
JSTaggedValue value = srcArray->Get(idx);
srcArray->Set(thread, idx + 1, value);
idx--;
fromIndex++;
}
} else {
int32_t moveSize = size - fromIndex;
for (int32_t i = 0; i < moveSize; i++) {
if ((fromIndex + i) < size) {
JSTaggedValue value = srcArray->Get(fromIndex + i);
srcArray->Set(thread, toIndex + i, value);
} else {
srcArray->Set(thread, toIndex + i, JSTaggedValue::Hole());
}
}
}
}
int32_t JSAPIPlainArray::BinarySearch(TaggedArray *array, int32_t fromIndex, int32_t toIndex, int32_t key)
{
int32_t low = fromIndex;
int32_t high = toIndex - 1;
while (low <= high) {
int32_t mid = (low + high) >> 1U;
int32_t midVal = static_cast<int32_t>(array->Get(mid).GetNumber());
if (midVal < key) {
low = mid + 1;
} else {
if (midVal <= key) {
return mid;
}
high = mid - 1;
}
}
return -(low + 1);
}
void JSAPIPlainArray::Clear(JSThread *thread)
{
TaggedArray *keys = TaggedArray::Cast(GetKeys().GetTaggedObject());
TaggedArray *values = TaggedArray::Cast(GetValues().GetTaggedObject());
int32_t size = GetLength();
for (int32_t index = 0; index < size; index++) {
keys->Set(thread, index, JSTaggedValue::Hole());
values->Set(thread, index, JSTaggedValue::Hole());
}
SetLength(0);
}
JSTaggedValue JSAPIPlainArray::RemoveRangeFrom(JSThread *thread, int32_t index, int32_t batchSize)
{
int32_t size = GetLength();
if (index < 0 || index >= size) {
return JSTaggedValue(-1);
}
if (batchSize < 1) {
return JSTaggedValue(-1);
}
int32_t safeSize = (size - (index + batchSize)) < 0 ? size - index : batchSize;
AdjustForward(thread, index, safeSize);
return JSTaggedValue(safeSize);
}
JSTaggedValue JSAPIPlainArray::Set(JSThread *thread, const JSHandle<JSAPIPlainArray> &obj,
const uint32_t index, JSTaggedValue value)
{
JSHandle<JSTaggedValue> key(thread, JSTaggedValue(index));
JSHandle<JSTaggedValue> valueHandle(thread, value);
JSAPIPlainArray::Add(thread, obj, key, valueHandle);
return JSTaggedValue::Undefined();
}
bool JSAPIPlainArray::GetOwnProperty(JSThread *thread, const JSHandle<JSAPIPlainArray> &obj,
const JSHandle<JSTaggedValue> &key, PropertyDescriptor &desc)
{
TaggedArray *keyArray = TaggedArray::Cast(obj->GetKeys().GetTaggedObject());
int32_t size = obj->GetLength();
int32_t index = obj->BinarySearch(keyArray, 0, size, key.GetTaggedValue().GetNumber());
if (index < 0 || index > size) {
THROW_RANGE_ERROR_AND_RETURN(thread, "GetOwnProperty index out-of-bounds", false);
}
return JSObject::GetOwnProperty(thread, JSHandle<JSObject>::Cast(obj), key, desc);
}
OperationResult JSAPIPlainArray::GetProperty(JSThread *thread, const JSHandle<JSAPIPlainArray> &obj,
const JSHandle<JSTaggedValue> &key)
{
TaggedArray *keyArray = TaggedArray::Cast(obj->GetKeys().GetTaggedObject());
int32_t size = obj->GetLength();
int32_t index = obj->BinarySearch(keyArray, 0, size, key.GetTaggedValue().GetNumber());
if (index < 0 || index > size) {
THROW_RANGE_ERROR_AND_RETURN(thread, "GetProperty index out-of-bounds",
OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false)));
}
return OperationResult(thread, obj->Get(JSTaggedValue(index)), PropertyMetaData(false));
}
JSHandle<JSAPIPlainArray> JSAPIPlainArray::Clone(JSThread *thread, const JSHandle<JSAPIPlainArray> &obj)
{
JSHandle<TaggedArray> keys(thread, obj->GetKeys());
JSHandle<TaggedArray> values(thread, obj->GetValues());
int32_t capacity = keys->GetLength();
int32_t size = obj->GetLength();
JSHandle<JSAPIPlainArray> newPlainArray = thread->GetEcmaVM()->GetFactory()->NewJSAPIPlainArray(capacity);
newPlainArray->SetLength(size);
TaggedArray *newKeys = TaggedArray::Cast(newPlainArray->GetKeys().GetTaggedObject());
TaggedArray *newValues = TaggedArray::Cast(newPlainArray->GetValues().GetTaggedObject());
for (int32_t i = 0; i < size; i++) {
newKeys->Set(thread, i, keys->Get(i));
newValues->Set(thread, i, values->Get(i));
}
return newPlainArray;
}
bool JSAPIPlainArray::Has(const int32_t key)
{
int32_t size = GetLength();
TaggedArray *keyArray = TaggedArray::Cast(GetKeys().GetTaggedObject());
int32_t index = BinarySearch(keyArray, 0, size, key);
if (index < 0) {
return false;
}
return true;
}
JSTaggedValue JSAPIPlainArray::Get(const JSTaggedValue key)
{
int32_t size = GetLength();
TaggedArray *keyArray = TaggedArray::Cast(GetKeys().GetTaggedObject());
int32_t index = BinarySearch(keyArray, 0, size, key.GetNumber());
if (index < 0) {
return JSTaggedValue::Undefined();
}
TaggedArray *values = TaggedArray::Cast(GetValues().GetTaggedObject());
return values->Get(index);
}
JSHandle<JSTaggedValue> JSAPIPlainArray::GetIteratorObj(JSThread *thread, const JSHandle<JSAPIPlainArray> &obj,
IterationKind kind)
{
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<JSTaggedValue> iter =
JSHandle<JSTaggedValue>::Cast(factory->NewJSAPIPlainArrayIterator(obj, kind));
return iter;
}
JSTaggedValue JSAPIPlainArray::ForEach(JSThread *thread, const JSHandle<JSTaggedValue> &thisHandle,
const JSHandle<JSTaggedValue> &callbackFn,
const JSHandle<JSTaggedValue> &thisArg)
{
JSAPIPlainArray *plainarray = JSAPIPlainArray::Cast(thisHandle->GetTaggedObject());
int32_t length = plainarray->GetLength();
JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
JSHandle<TaggedArray> keyArray(thread, plainarray->GetKeys());
JSHandle<TaggedArray> valueArray(thread, plainarray->GetValues());
for (int32_t k = 0; k < length; k++) {
JSTaggedValue kValue = valueArray->Get(k);
JSTaggedValue key = keyArray->Get(k);
EcmaRuntimeCallInfo info =
EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFn, thisArg, undefined, 3); // 3: three args
info.SetCallArg(kValue, key, thisHandle.GetTaggedValue());
JSTaggedValue funcResult = JSFunction::Call(&info);
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, funcResult);
}
return JSTaggedValue::Undefined();
}
JSTaggedValue JSAPIPlainArray::ToString(JSThread *thread, const JSHandle<JSAPIPlainArray> &plainarray)
{
EcmaVM *ecmaVM = thread->GetEcmaVM();
ObjectFactory *factory = ecmaVM->GetFactory();
std::u16string sepStr = std::wstring_convert < std::codecvt_utf8_utf16<char16_t>, char16_t > {}.from_bytes(",");
int32_t length = plainarray->GetLength();
JSHandle<TaggedArray> keyArray(thread, plainarray->GetKeys());
JSHandle<TaggedArray> elements(thread, plainarray->GetValues());
std::u16string concatStr;
std::u16string concatStrNew;
JSHandle<EcmaString> stringSeparate = factory->NewFromASCII(":");
JSMutableHandle<JSTaggedValue> keys(thread, JSTaggedValue::Undefined());
JSMutableHandle<JSTaggedValue> element(thread, JSTaggedValue::Undefined());
JSMutableHandle<EcmaString> ret(thread, nullptr);
JSMutableHandle<EcmaString> stringKey(thread, nullptr);
JSMutableHandle<EcmaString> stringValue(thread, nullptr);
JSMutableHandle<EcmaString> concatValue(thread, nullptr);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
for (int32_t k = 0; k < length; k++) {
std::u16string nextStr;
keys.Update(JSTaggedValue(keyArray->Get(k)));
element.Update(JSTaggedValue(elements->Get(k)));
if (!element->IsUndefined() && !element->IsNull()) {
stringKey.Update(JSTaggedValue::ToString(thread, keys).GetTaggedValue());
ret.Update(JSTaggedValue(EcmaString::Concat(stringKey, stringSeparate, ecmaVM)));
stringValue.Update(JSTaggedValue::ToString(thread, element).GetTaggedValue());
concatValue.Update(JSTaggedValue(EcmaString::Concat(ret, stringValue, ecmaVM)));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
uint32_t nextLen = concatValue->GetLength();
if (concatValue->IsUtf16()) {
nextStr = base::StringHelper::Utf16ToU16String(concatValue->GetDataUtf16(), nextLen);
} else {
nextStr = base::StringHelper::Utf8ToU16String(concatValue->GetDataUtf8(), nextLen);
}
}
if (k > 0) {
concatStrNew = base::StringHelper::Append(concatStr, sepStr);
concatStr = base::StringHelper::Append(concatStrNew, nextStr);
continue;
}
concatStr = base::StringHelper::Append(concatStr, nextStr);
}
char16_t *char16tData = concatStr.data();
auto *uint16tData = reinterpret_cast<uint16_t *>(char16tData);
int32_t u16strSize = concatStr.size();
return factory->NewFromUtf16Literal(uint16tData, u16strSize).GetTaggedValue();
}
JSTaggedValue JSAPIPlainArray::GetIndexOfKey(int32_t key)
{
int32_t size = GetLength();
TaggedArray *keyArray = TaggedArray::Cast(GetKeys().GetTaggedObject());
int32_t index = BinarySearch(keyArray, 0, size, key);
if (index < 0) {
return JSTaggedValue(-1);
}
return JSTaggedValue(index);
}
JSTaggedValue JSAPIPlainArray::GetIndexOfValue(JSTaggedValue value)
{
TaggedArray *values = TaggedArray::Cast(GetValues().GetTaggedObject());
int32_t size = GetLength();
int32_t index = -1;
for (int32_t i = 0; i < size; i++) {
if (JSTaggedValue::SameValue(values->Get(i), value)) {
index = i;
break;
}
}
if (index < 0) {
return JSTaggedValue(-1);
}
return JSTaggedValue(index);
}
bool JSAPIPlainArray::IsEmpty()
{
int32_t length = GetLength();
return length == 0;
}
JSTaggedValue JSAPIPlainArray::GetKeyAt(int32_t index)
{
int32_t size = GetLength();
TaggedArray *keyArray = TaggedArray::Cast(GetKeys().GetTaggedObject());
if (index < 0 || index >= size) {
return JSTaggedValue::Undefined();
}
return keyArray->Get(index);
}
JSTaggedValue JSAPIPlainArray::GetValueAt(int32_t index)
{
int32_t size = GetLength();
if (index < 0 || index >= size) {
return JSTaggedValue::Undefined();
}
TaggedArray *values = TaggedArray::Cast(GetValues().GetTaggedObject());
return values->Get(index);
}
JSTaggedValue JSAPIPlainArray::Remove(JSThread *thread, JSTaggedValue key)
{
int32_t size = GetLength();
TaggedArray *keyArray = TaggedArray::Cast(GetKeys().GetTaggedObject());
int32_t index = BinarySearch(keyArray, 0, size, key.GetNumber());
if (index < 0 || index >= size) {
return JSTaggedValue::Undefined();
}
TaggedArray *values = TaggedArray::Cast(GetValues().GetTaggedObject());
JSTaggedValue value = values->Get(index);
AdjustForward(thread, index, 1); // 1 means the length of array
return value;
}
JSTaggedValue JSAPIPlainArray::RemoveAt(JSThread *thread, JSTaggedValue index)
{
int32_t size = GetLength();
int32_t seat = index.GetNumber();
if (seat < 0 || seat >= size) {
return JSTaggedValue::Undefined();
}
TaggedArray *values = TaggedArray::Cast(GetValues().GetTaggedObject());
JSTaggedValue value = values->Get(seat);
AdjustForward(thread, seat, 1);
return value;
}
bool JSAPIPlainArray::SetValueAt(JSThread *thread, JSTaggedValue index, JSTaggedValue value)
{
int32_t size = GetLength();
int32_t seat = index.GetNumber();
if (seat < 0 || seat >= size) {
THROW_RANGE_ERROR_AND_RETURN(thread, "the index is out-of-bounds", false);
}
TaggedArray *values = TaggedArray::Cast(GetValues().GetTaggedObject());
values->Set(thread, seat, value);
return true;
}
} // namespace panda::ecmascript

View File

@ -0,0 +1,82 @@
/*
* 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.
*/
#ifndef ECMASCRIPT_JSPLAIN_ARRAY_H
#define ECMASCRIPT_JSPLAIN_ARRAY_H
#include "js_object.h"
#include "js_tagged_value-inl.h"
namespace panda::ecmascript {
class JSAPIPlainArray : public JSObject {
public:
static constexpr int DEFAULT_CAPACITY_LENGTH = 8;
static JSAPIPlainArray *Cast(ObjectHeader *object)
{
ASSERT(JSTaggedValue(object).IsJSAPIPlainArray());
return static_cast<JSAPIPlainArray *>(object);
}
static void Add(JSThread *thread, const JSHandle<JSAPIPlainArray> &obj, JSHandle<JSTaggedValue> key,
JSHandle<JSTaggedValue> value);
static bool GetOwnProperty(JSThread *thread, const JSHandle<JSAPIPlainArray> &obj,
const JSHandle<JSTaggedValue> &key, PropertyDescriptor &desc);
static JSHandle<TaggedArray> CreateSlot(const JSThread *thread, const uint32_t capacity);
static JSHandle<JSAPIPlainArray> Clone(JSThread *thread, const JSHandle<JSAPIPlainArray> &plainArray);
static JSHandle<JSTaggedValue> GetIteratorObj(JSThread *thread, const JSHandle<JSAPIPlainArray> &obj,
IterationKind kind);
static JSTaggedValue ForEach(JSThread *thread, const JSHandle<JSTaggedValue> &thisHandle,
const JSHandle<JSTaggedValue> &callbackFn, const JSHandle<JSTaggedValue> &thisArg);
static JSTaggedValue ToString(JSThread *thread, const JSHandle<JSAPIPlainArray> &plainarray);
static OperationResult GetProperty(JSThread *thread, const JSHandle<JSAPIPlainArray> &obj,
const JSHandle<JSTaggedValue> &key);
static JSTaggedValue Set(JSThread *thread, const JSHandle<JSAPIPlainArray> &obj,
const uint32_t index, JSTaggedValue value);
JSTaggedValue RemoveAt(JSThread *thread, JSTaggedValue index);
JSTaggedValue GetIndexOfKey(int32_t key);
JSTaggedValue GetIndexOfValue(JSTaggedValue value);
JSTaggedValue GetKeyAt(int32_t index);
JSTaggedValue GetValueAt(int32_t index);
JSTaggedValue Get(const JSTaggedValue key);
JSTaggedValue Remove(JSThread *thread, JSTaggedValue key);
JSTaggedValue RemoveRangeFrom(JSThread *thread, int32_t index, int32_t batchSize);
bool SetValueAt(JSThread *thread, JSTaggedValue index, JSTaggedValue value);
bool Has(const int32_t key);
bool IsEmpty();
bool AdjustForward(JSThread *thread, int32_t index, int32_t forwardSize);
int32_t BinarySearch(TaggedArray *array, int32_t fromIndex, int32_t toIndex, int32_t key);
void Clear(JSThread *thread);
void AdjustArray(JSThread *thread, TaggedArray *srcArray, int32_t fromIndex, int32_t toIndex,
bool direction);
inline int GetSize() const
{
return GetLength();
}
static constexpr size_t KEYS_OFFSET = JSObject::SIZE;
ACCESSORS(Keys, KEYS_OFFSET, VALUES_OFFSET);
ACCESSORS(Values, VALUES_OFFSET, LENGTH_OFFSET);
ACCESSORS_PRIMITIVE_FIELD(Length, int32_t, LENGTH_OFFSET, LAST_OFFSET);
DEFINE_ALIGN_SIZE(LAST_OFFSET);
DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSObject, KEYS_OFFSET, LENGTH_OFFSET)
DECL_DUMP()
private:
inline static uint32_t ComputeCapacity(uint32_t oldCapacity)
{
uint32_t newCapacity = oldCapacity + (oldCapacity >> 1U);
return newCapacity > DEFAULT_CAPACITY_LENGTH ? newCapacity : DEFAULT_CAPACITY_LENGTH;
}
};
} // namespace panda::ecmascript
#endif // ECMASCRIPT_JSPLAIN_ARRAY_H

View File

@ -0,0 +1,65 @@
/*
* 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 "js_api_plain_array_iterator.h"
#include "builtins/builtins_errors.h"
#include "ecmascript/base/typed_array_helper.h"
#include "ecmascript/base/typed_array_helper-inl.h"
#include "global_env.h"
#include "js_api_plain_array.h"
#include "js_array.h"
#include "object_factory.h"
namespace panda::ecmascript {
using BuiltinsBase = base::BuiltinsBase;
JSTaggedValue JSAPIPlainArrayIterator::Next(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> input(BuiltinsBase::GetThis(argv));
if (!input->IsJSAPIPlainArrayIterator()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "this value is not an plainarray iterator", JSTaggedValue::Exception());
}
JSHandle<JSAPIPlainArrayIterator> iter(input);
JSHandle<JSTaggedValue> plainArray(thread, iter->GetIteratedPlainArray());
JSHandle<JSTaggedValue> undefinedHandle(thread, JSTaggedValue::Undefined());
if (plainArray->IsUndefined()) {
return JSIterator::CreateIterResultObject(thread, undefinedHandle, true).GetTaggedValue();
}
JSHandle<JSAPIPlainArray> apiPlainArray(plainArray);
ASSERT(plainArray->IsJSAPIPlainArray());
int32_t length = apiPlainArray->GetLength();
int32_t index = iter->GetNextIndex();
if (index >= length) {
iter->SetIteratedPlainArray(thread, undefinedHandle);
return JSIterator::CreateIterResultObject(thread, undefinedHandle, true).GetTaggedValue();
}
iter->SetNextIndex(index + 1);
JSHandle<TaggedArray> valueArray(thread, TaggedArray::Cast(apiPlainArray->GetValues().GetTaggedObject()));
JSHandle<JSTaggedValue> value(thread, valueArray->Get(index));
JSHandle<TaggedArray> keyArray(thread, TaggedArray::
Cast(JSHandle<JSAPIPlainArray>(plainArray)->GetKeys().GetTaggedObject()));
JSHandle<JSTaggedValue> keyHandle(thread, keyArray->Get(index));
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<TaggedArray> array(factory->NewTaggedArray(2)); // 2 means the length of array
array->Set(thread, 0, keyHandle);
array->Set(thread, 1, value);
JSHandle<JSTaggedValue> keyAndValue(JSArray::CreateArrayFromList(thread, array));
return JSIterator::CreateIterResultObject(thread, keyAndValue, false).GetTaggedValue();
}
} // namespace panda::ecmascript

View File

@ -0,0 +1,45 @@
/*
* 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.
*/
#ifndef ECMASCRIPT_JS_API_PLAIN_ARRAY_ITERATOR_H
#define ECMASCRIPT_JS_API_PLAIN_ARRAY_ITERATOR_H
#include "js_iterator.h"
#include "js_object.h"
namespace panda::ecmascript {
class JSAPIPlainArrayIterator : public JSObject {
public:
static JSAPIPlainArrayIterator *Cast(ObjectHeader *obj)
{
ASSERT(JSTaggedValue(obj).IsJSAPIPlainArrayIterator());
return static_cast<JSAPIPlainArrayIterator *>(obj);
}
static JSTaggedValue Next(EcmaRuntimeCallInfo *argv);
static constexpr size_t ITERATED_PLAIN_ARRAY_OFFSET = JSObject::SIZE;
ACCESSORS(IteratedPlainArray, ITERATED_PLAIN_ARRAY_OFFSET, NEXT_INDEX_OFFSET);
ACCESSORS_PRIMITIVE_FIELD(NextIndex, int32_t, NEXT_INDEX_OFFSET, BIT_FIELD_OFFSET)
ACCESSORS_BIT_FIELD(BitField, BIT_FIELD_OFFSET, LAST_OFFSET)
DEFINE_ALIGN_SIZE(LAST_OFFSET);
// define BitField
static constexpr size_t ITERATION_KIND_BITS = 2; // 2 is define bit field
FIRST_BIT_FIELD(BitField, IterationKind, IterationKind, ITERATION_KIND_BITS)
DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSObject, ITERATED_PLAIN_ARRAY_OFFSET, NEXT_INDEX_OFFSET)
DECL_DUMP()
};
} // namespace panda::ecmascript
#endif // ECMASCRIPT_JS_API_PLAIN_ARRAY_ITERATOR_H

View File

@ -98,6 +98,7 @@ class ProtoChangeDetails;
JS_SET_ITERATOR, /* ///////////////////////////////////////////////////////////////////////-PADDING */ \
JS_API_ARRAYLIST_ITERATOR, /* /////////////////////////////////////////////////////////////////////-PADDING */ \
JS_API_DEQUE_ITERATOR, /* ///////////////////////////////////////////////////////////////////////-PADDING */ \
JS_API_PLAIN_ARRAY_ITERATOR, /* //////////////////////////////////////////////////////////////////-PADDING */ \
JS_API_QUEUE_ITERATOR, /* ///////////////////////////////////////////////////////////////////////-PADDING */ \
JS_API_STACK_ITERATOR, /* ///////////////////////////////////////////////////////////////////////-PADDING */ \
JS_API_TREEMAP_ITERATOR, /* ///////////////////////////////////////////////////////////////////////-PADDING */ \
@ -129,6 +130,7 @@ class ProtoChangeDetails;
JS_API_TREE_SET, /* /////////////////////////////////////////////////////////////////////////////-PADDING */ \
JS_API_DEQUE, /* /////////////////////////////////////////////////////////////////////////////-PADDING */ \
JS_API_STACK, /* /////////////////////////////////////////////////////////////////////////////-PADDING */ \
JS_API_PLAIN_ARRAY, /* ////////////////////////////////////////////////////////////////////////////-PADDING */ \
JS_API_QUEUE, /* /////////////////////////////////////////////////////////////////////////////-PADDING */ \
JS_TYPED_ARRAY, /* JS_TYPED_ARRAY_BEGIN /////////////////////////////////////////////////////////////////// */ \
JS_INT8_ARRAY, /* ////////////////////////////////////////////////////////////////////////////////-PADDING */ \
@ -661,10 +663,12 @@ public:
{
return GetObjectType() >= JSType::JS_API_ARRAY_LIST && GetObjectType() <= JSType::JS_API_QUEUE;
}
inline bool IsJSAPIArrayList() const
{
return GetObjectType() == JSType::JS_API_ARRAY_LIST;
}
inline bool IsJSAPIArrayListIterator() const
{
return GetObjectType() == JSType::JS_API_ARRAYLIST_ITERATOR;
@ -684,6 +688,12 @@ public:
{
return GetObjectType() == JSType::JS_API_QUEUE;
}
inline bool IsJSAPIPlainArray() const
{
return GetObjectType() == JSType::JS_API_PLAIN_ARRAY;
}
inline bool IsJSAPIQueueIterator() const
{
return GetObjectType() == JSType::JS_API_QUEUE_ITERATOR;
@ -693,14 +703,17 @@ public:
{
return GetObjectType() == JSType::JS_API_TREE_MAP;
}
inline bool IsJSAPITreeSet() const
{
return GetObjectType() == JSType::JS_API_TREE_SET;
}
inline bool IsJSAPITreeMapIterator() const
{
return GetObjectType() == JSType::JS_API_TREEMAP_ITERATOR;
}
inline bool IsJSAPITreeSetIterator() const
{
return GetObjectType() == JSType::JS_API_TREESET_ITERATOR;
@ -762,6 +775,11 @@ public:
return GetObjectType() == JSType::JS_ARRAY_ITERATOR;
}
inline bool IsJSAPIPlainArrayIterator() const
{
return GetObjectType() == JSType::JS_API_PLAIN_ARRAY_ITERATOR;
}
inline bool IsJSAPIDequeIterator() const
{
return GetObjectType() == JSType::JS_API_DEQUE_ITERATOR;

View File

@ -609,6 +609,16 @@ inline bool JSTaggedValue::IsJSAPITreeSet() const
return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSAPITreeSet();
}
inline bool JSTaggedValue::IsJSAPIPlainArray() const
{
return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSAPIPlainArray();
}
inline bool JSTaggedValue::IsJSAPIPlainArrayIterator() const
{
return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSAPIPlainArrayIterator();
}
inline bool JSTaggedValue::IsJSAPIQueue() const
{
return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSAPIQueue();

View File

@ -19,6 +19,7 @@
#include "ecmascript/global_env.h"
#include "ecmascript/interpreter/interpreter.h"
#include "ecmascript/js_api_deque.h"
#include "ecmascript/js_api_plain_array.h"
#include "ecmascript/js_api_queue.h"
#include "ecmascript/js_api_stack.h"
#include "ecmascript/js_array.h"
@ -507,6 +508,10 @@ OperationResult JSTaggedValue::GetProperty(JSThread *thread, const JSHandle<JSTa
return ModuleNamespace::GetProperty(thread, obj, key);
}
if (obj->IsSpecialContainer()) {
return GetJSAPIProperty(thread, obj, key);
}
return JSObject::GetProperty(thread, obj, key);
}
@ -526,6 +531,11 @@ OperationResult JSTaggedValue::GetProperty(JSThread *thread, const JSHandle<JSTa
return JSTypedArray::GetProperty(thread, obj, key);
}
if (obj->IsSpecialContainer()) {
JSHandle<JSTaggedValue> keyHandle = JSHandle<JSTaggedValue>(thread, JSTaggedValue(key));
return GetJSAPIProperty(thread, obj, keyHandle);
}
return JSObject::GetProperty(thread, obj, key);
}
@ -545,6 +555,10 @@ OperationResult JSTaggedValue::GetProperty(JSThread *thread, const JSHandle<JSTa
return JSTypedArray::GetProperty(thread, obj, JSTypedArray::ToPropKey(thread, key), receiver);
}
if (obj->IsSpecialContainer()) {
return GetJSAPIProperty(thread, obj, key);
}
return JSObject::GetProperty(thread, obj, key, receiver);
}
@ -915,6 +929,9 @@ bool JSTaggedValue::HasContainerProperty(JSThread *thread, const JSHandle<JSTagg
case JSType::JS_API_QUEUE: {
return JSHandle<JSAPIQueue>::Cast(obj)->Has(key.GetTaggedValue());
}
case JSType::JS_API_PLAIN_ARRAY: {
return JSObject::HasProperty(thread, JSHandle<JSObject>(obj), key);
}
case JSType::JS_API_DEQUE: {
return JSHandle<JSAPIDeque>::Cast(obj)->Has(key.GetTaggedValue());
}
@ -943,6 +960,9 @@ JSHandle<TaggedArray> JSTaggedValue::GetOwnContainerPropertyKeys(JSThread *threa
case JSType::JS_API_QUEUE: {
return JSAPIQueue::OwnKeys(thread, JSHandle<JSAPIQueue>::Cast(obj));
}
case JSType::JS_API_PLAIN_ARRAY: {
return JSObject::GetOwnPropertyKeys(thread, JSHandle<JSObject>(obj));
}
case JSType::JS_API_DEQUE: {
return JSAPIDeque::OwnKeys(thread, JSHandle<JSAPIDeque>::Cast(obj));
}
@ -972,6 +992,9 @@ bool JSTaggedValue::GetContainerProperty(JSThread *thread, const JSHandle<JSTagg
case JSType::JS_API_QUEUE: {
return JSAPIQueue::GetOwnProperty(thread, JSHandle<JSAPIQueue>::Cast(obj), key, desc);
}
case JSType::JS_API_PLAIN_ARRAY: {
return JSAPIPlainArray::GetOwnProperty(thread, JSHandle<JSAPIPlainArray>::Cast(obj), key, desc);
}
case JSType::JS_API_DEQUE: {
return JSAPIDeque::GetOwnProperty(thread, JSHandle<JSAPIDeque>::Cast(obj), key, desc);
}
@ -1005,4 +1028,22 @@ JSHandle<JSTaggedValue> JSTaggedValue::ToNumeric(JSThread *thread, JSTaggedValue
JSHandle<JSTaggedValue> value(thread, number);
return value;
}
OperationResult JSTaggedValue::GetJSAPIProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
const JSHandle<JSTaggedValue> &key)
{
auto *hclass = obj->GetTaggedObject()->GetClass();
JSType jsType = hclass->GetObjectType();
if (key->IsNumber()) {
switch (jsType) {
case JSType::JS_API_PLAIN_ARRAY:
return JSAPIPlainArray::GetProperty(thread, JSHandle<JSAPIPlainArray>::Cast(obj), key);
default: {
return JSObject::GetProperty(thread, JSHandle<JSObject>(obj), key);
}
}
} else {
return JSObject::GetProperty(thread, JSHandle<JSObject>(obj), key);
}
return OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false));
}
} // namespace panda::ecmascript

View File

@ -338,6 +338,8 @@ public:
bool IsJSAPITreeSetIterator() const;
bool IsJSAPIQueue() const;
bool IsJSAPIQueueIterator() const;
bool IsJSAPIPlainArray() const;
bool IsJSAPIPlainArrayIterator() const;
bool IsJSAPIDeque() const;
bool IsJSAPIDequeIterator() const;
bool IsJSAPIStack() const;
@ -396,6 +398,8 @@ private:
static JSHandle<TaggedArray> GetOwnContainerPropertyKeys(JSThread *thread, const JSHandle<JSTaggedValue> &obj);
static bool GetContainerProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
const JSHandle<JSTaggedValue> &key, PropertyDescriptor &desc);
static OperationResult GetJSAPIProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
const JSHandle<JSTaggedValue> &key);
};
STATIC_ASSERT_EQ_ARCH(sizeof(JSTaggedValue), JSTaggedValue::SizeArch32, JSTaggedValue::SizeArch64);
} // namespace panda::ecmascript

View File

@ -25,6 +25,8 @@
#include "ecmascript/jobs/pending_job.h"
#include "ecmascript/js_api_deque.h"
#include "ecmascript/js_api_deque_iterator.h"
#include "ecmascript/js_api_plain_array.h"
#include "ecmascript/js_api_plain_array_iterator.h"
#include "ecmascript/js_api_queue.h"
#include "ecmascript/js_api_queue_iterator.h"
#include "ecmascript/js_api_stack.h"
@ -431,6 +433,12 @@ void ObjectXRay::VisitObjectBody(TaggedObject *object, JSHClass *klass, const Ec
case JSType::JS_API_TREESET_ITERATOR:
JSAPITreeSetIterator::Cast(object)->VisitRangeSlot(visitor);
break;
case JSType::JS_API_PLAIN_ARRAY:
JSAPIPlainArray::Cast(object)->VisitRangeSlot(visitor);
break;
case JSType::JS_API_PLAIN_ARRAY_ITERATOR:
JSAPIPlainArrayIterator::Cast(object)->VisitRangeSlot(visitor);
break;
case JSType::JS_API_DEQUE:
JSAPIDeque::Cast(object)->VisitRangeSlot(visitor);
break;

View File

@ -34,6 +34,8 @@
#include "ecmascript/jobs/pending_job.h"
#include "ecmascript/js_api_deque.h"
#include "ecmascript/js_api_deque_iterator.h"
#include "ecmascript/js_api_plain_array.h"
#include "ecmascript/js_api_plain_array_iterator.h"
#include "ecmascript/js_api_queue.h"
#include "ecmascript/js_api_queue_iterator.h"
#include "ecmascript/js_api_stack.h"
@ -874,6 +876,11 @@ JSHandle<JSObject> ObjectFactory::NewJSObjectByConstructor(const JSHandle<JSFunc
JSAPIQueue::Cast(*obj)->SetFront(0);
JSAPIQueue::Cast(*obj)->SetTail(0);
break;
case JSType::JS_API_PLAIN_ARRAY:
JSAPIPlainArray::Cast(*obj)->SetLength(0);
JSAPIPlainArray::Cast(*obj)->SetValues(thread_, JSTaggedValue(0));
JSAPIPlainArray::Cast(*obj)->SetKeys(thread_, JSTaggedValue(0));
break;
case JSType::JS_API_STACK:
JSAPIStack::Cast(*obj)->SetTop(0);
break;
@ -893,6 +900,7 @@ JSHandle<JSObject> ObjectFactory::NewJSObjectByConstructor(const JSHandle<JSFunc
case JSType::JS_API_DEQUE_ITERATOR:
case JSType::JS_API_STACK_ITERATOR:
case JSType::JS_ARRAY_ITERATOR:
case JSType::JS_API_PLAIN_ARRAY_ITERATOR:
default:
UNREACHABLE();
}
@ -2521,6 +2529,38 @@ JSHandle<JSAPIArrayListIterator> ObjectFactory::NewJSAPIArrayListIterator(const
return iter;
}
JSHandle<JSAPIPlainArray> ObjectFactory::NewJSAPIPlainArray(array_size_t capacity)
{
NewObjectHook();
JSHandle<JSTaggedValue> builtinObj(thread_, thread_->GlobalConstants()->GetPlainArrayFunction());
JSHandle<JSAPIPlainArray> obj =
JSHandle<JSAPIPlainArray>(NewJSObjectByConstructor(JSHandle<JSFunction>(builtinObj), builtinObj));
ObjectFactory *factory = thread_->GetEcmaVM()->GetFactory();
JSHandle<TaggedArray> keyArray = factory->NewTaggedArray(capacity);
JSHandle<TaggedArray> valueArray = factory->NewTaggedArray(capacity);
obj->SetKeys(thread_, keyArray);
obj->SetValues(thread_, valueArray);
return obj;
}
JSHandle<JSAPIPlainArrayIterator> ObjectFactory::NewJSAPIPlainArrayIterator(const JSHandle<JSAPIPlainArray> &plainarray,
IterationKind kind)
{
NewObjectHook();
JSHandle<JSTaggedValue> protoValue(thread_, thread_->GlobalConstants()->GetPlainArrayIteratorPrototype());
const GlobalEnvConstants *globalConst = thread_->GlobalConstants();
JSHandle<JSHClass> dynHandle(globalConst->GetHandledJSAPIPlainArrayIteratorClass());
dynHandle->SetPrototype(thread_, protoValue);
JSHandle<JSAPIPlainArrayIterator> iter(NewJSObject(dynHandle));
iter->GetJSHClass()->SetExtensible(true);
iter->SetIteratedPlainArray(thread_, plainarray);
iter->SetNextIndex(0);
iter->SetIterationKind(kind);
return iter;
}
JSHandle<JSAPIStackIterator> ObjectFactory::NewJSAPIStackIterator(const JSHandle<JSAPIStack> &stack)
{
NewObjectHook();

View File

@ -33,6 +33,7 @@ namespace panda::ecmascript {
class JSMethod;
class JSObject;
class JSArray;
class JSAPIPlainArray;
class JSSymbol;
class JSFunctionBase;
class JSFunction;
@ -57,6 +58,7 @@ class JSRegExp;
class JSSetIterator;
class JSMapIterator;
class JSArrayIterator;
class JSAPIPlainArrayIterator;
class JSStringIterator;
class JSGeneratorObject;
class CompletionRecord;
@ -404,6 +406,9 @@ public:
JSHandle<JSHClass> NewEcmaDynClass(uint32_t size, JSType type, const JSHandle<JSTaggedValue> &prototype);
// It is used to provide iterators for non ECMA standard jsapi containers.
JSHandle<JSAPIPlainArray> NewJSAPIPlainArray(array_size_t capacity);
JSHandle<JSAPIPlainArrayIterator> NewJSAPIPlainArrayIterator(const JSHandle<JSAPIPlainArray> &plainarray,
IterationKind kind);
JSHandle<JSAPIArrayList> NewJSAPIArrayList(uint32_t capacity);
JSHandle<TaggedArray> CopyQueue(const JSHandle<TaggedArray> &old, uint32_t oldLength,
uint32_t newLength, uint32_t front, uint32_t tail);

View File

@ -559,6 +559,25 @@ namespace panda::ecmascript {
V(ArrayList, Get) \
V(ArrayList, Set) \
V(ArrayList, GetSize) \
V(PlainArray, Constructor) \
V(PlainArray, Add) \
V(PlainArray, Clear) \
V(PlainArray, Clone) \
V(PlainArray, Has) \
V(PlainArray, Get) \
V(PlainArray, GetIteratorObj) \
V(PlainArray, ForEach) \
V(PlainArray, ToString) \
V(PlainArray, GetIndexOfKey) \
V(PlainArray, GetIndexOfValue) \
V(PlainArray, IsEmpty) \
V(PlainArray, GetKeyAt) \
V(PlainArray, Remove) \
V(PlainArray, RemoveAt) \
V(PlainArray, RemoveRangeFrom) \
V(PlainArray, SetValueAt) \
V(PlainArray, GetValueAt) \
V(PlainArray, GetSize) \
V(TreeMap, Constructor) \
V(TreeMap, HasKey) \
V(TreeMap, HasValue) \

View File

@ -55,6 +55,7 @@
#include "ecmascript/builtins/builtins_weak_set.h"
#include "ecmascript/containers/containers_arraylist.h"
#include "ecmascript/containers/containers_deque.h"
#include "ecmascript/containers/containers_plainarray.h"
#include "ecmascript/containers/containers_private.h"
#include "ecmascript/containers/containers_queue.h"
#include "ecmascript/containers/containers_stack.h"
@ -63,6 +64,7 @@
#include "ecmascript/jspandafile/program_object.h"
#include "ecmascript/global_env.h"
#include "ecmascript/js_api_deque_iterator.h"
#include "ecmascript/js_api_plain_array_iterator.h"
#include "ecmascript/js_api_queue_iterator.h"
#include "ecmascript/js_api_stack_iterator.h"
#include "ecmascript/js_api_tree_map_iterator.h"
@ -131,6 +133,7 @@ using ArrayList = containers::ContainersArrayList;
using TreeMap = containers::ContainersTreeMap;
using TreeSet = containers::ContainersTreeSet;
using Queue = containers::ContainersQueue;
using PlainArray = containers::ContainersPlainArray;
using Deque = containers::ContainersDeque;
using ContainerStack = panda::ecmascript::containers::ContainersStack;
using ContainersPrivate = containers::ContainersPrivate;
@ -660,6 +663,26 @@ static uintptr_t g_nativeTable[] = {
reinterpret_cast<uintptr_t>(Queue::GetIteratorObj),
reinterpret_cast<uintptr_t>(Queue::GetSize),
reinterpret_cast<uintptr_t>(JSAPIQueueIterator::Next),
reinterpret_cast<uintptr_t>(PlainArray::PlainArrayConstructor),
reinterpret_cast<uintptr_t>(PlainArray::Add),
reinterpret_cast<uintptr_t>(PlainArray::Clear),
reinterpret_cast<uintptr_t>(PlainArray::Clone),
reinterpret_cast<uintptr_t>(PlainArray::Has),
reinterpret_cast<uintptr_t>(PlainArray::Get),
reinterpret_cast<uintptr_t>(PlainArray::GetIteratorObj),
reinterpret_cast<uintptr_t>(PlainArray::ForEach),
reinterpret_cast<uintptr_t>(PlainArray::ToString),
reinterpret_cast<uintptr_t>(PlainArray::GetIndexOfKey),
reinterpret_cast<uintptr_t>(PlainArray::GetIndexOfValue),
reinterpret_cast<uintptr_t>(PlainArray::IsEmpty),
reinterpret_cast<uintptr_t>(PlainArray::GetKeyAt),
reinterpret_cast<uintptr_t>(PlainArray::Remove),
reinterpret_cast<uintptr_t>(PlainArray::RemoveAt),
reinterpret_cast<uintptr_t>(PlainArray::RemoveRangeFrom),
reinterpret_cast<uintptr_t>(PlainArray::SetValueAt),
reinterpret_cast<uintptr_t>(PlainArray::GetValueAt),
reinterpret_cast<uintptr_t>(PlainArray::GetSize),
reinterpret_cast<uintptr_t>(JSAPIPlainArrayIterator::Next),
reinterpret_cast<uintptr_t>(ContainerStack::StackConstructor),
reinterpret_cast<uintptr_t>(ContainerStack::Iterator),
reinterpret_cast<uintptr_t>(ContainerStack::IsEmpty),

View File

@ -1049,6 +1049,33 @@ host_unittest_action("ConcurrentMarkingTest") {
}
}
host_unittest_action("JSAPIPlainArrayTest") {
module_out_path = module_output_path
sources = [
# test file
"js_api_plain_array_test.cpp",
]
configs = [
"//ark/js_runtime:ecma_test_config",
"//ark/js_runtime:ark_jsruntime_public_config", # should add before
# arkruntime_public_config
"//ark/js_runtime:ark_jsruntime_common_config",
"$ark_root/runtime:arkruntime_public_config",
]
deps = [
"$ark_root/libpandabase:libarkbase",
"//ark/js_runtime:libark_jsruntime_test",
sdk_libc_secshared_dep,
]
if (!is_standard_system) {
deps += [ "$ark_root/runtime:libarkruntime" ]
}
}
group("unittest") {
testonly = true
@ -1067,6 +1094,7 @@ group("unittest") {
":GlueRegsTest",
":HugeObjectTest",
":JSAPIDequeTest",
":JSAPIPlainArrayTest",
":JSAPIStackTest",
":JSAPITreeMapTest",
":JSAPITreeSetTest",
@ -1122,6 +1150,7 @@ group("host_unittest") {
":GlueRegsTestAction",
":HugeObjectTestAction",
":JSAPIDequeTestAction",
":JSAPIPlainArrayTestAction",
":JSAPIStackTestAction",
":JSAPITreeMapTestAction",
":JSAPITreeSetTestAction",

View File

@ -29,6 +29,8 @@
#include "ecmascript/jobs/pending_job.h"
#include "ecmascript/js_api_deque.h"
#include "ecmascript/js_api_deque_iterator.h"
#include "ecmascript/js_api_plain_array.h"
#include "ecmascript/js_api_plain_array_iterator.h"
#include "ecmascript/js_api_queue.h"
#include "ecmascript/js_api_queue_iterator.h"
#include "ecmascript/js_api_stack.h"
@ -182,6 +184,22 @@ static JSHandle<JSAPITreeSet> NewJSAPITreeSet(JSThread *thread, ObjectFactory *f
return jsTreeSet;
}
static JSHandle<JSAPIPlainArray> NewJSAPIPlainArray(JSThread *thread, ObjectFactory *factory)
{
auto globalEnv = thread->GetEcmaVM()->GetGlobalEnv();
JSHandle<JSTaggedValue> proto = globalEnv->GetObjectFunctionPrototype();
JSHandle<JSHClass> mapClass = factory->NewEcmaDynClass(JSAPIPlainArray::SIZE, JSType::JS_API_PLAIN_ARRAY, proto);
JSHandle<JSAPIPlainArray> jSAPIPlainArray = JSHandle<JSAPIPlainArray>::Cast(factory->NewJSObject(mapClass));
JSHandle<TaggedArray> keys =
JSAPIPlainArray::CreateSlot(thread, JSAPIPlainArray::DEFAULT_CAPACITY_LENGTH);
JSHandle<TaggedArray> values =
JSAPIPlainArray::CreateSlot(thread, JSAPIPlainArray::DEFAULT_CAPACITY_LENGTH);
jSAPIPlainArray->SetKeys(thread, keys);
jSAPIPlainArray->SetValues(thread, values);
jSAPIPlainArray->SetLength(0);
return jSAPIPlainArray;
}
static JSHandle<JSObject> NewJSObject(JSThread *thread, ObjectFactory *factory, JSHandle<GlobalEnv> globalEnv)
{
JSFunction *jsFunc = globalEnv->GetObjectFunction().GetObject<JSFunction>();
@ -777,6 +795,20 @@ HWTEST_F_L0(EcmaDumpTest, HeapProfileDump)
DUMP_FOR_HANDLE(jsQueueIter)
break;
}
case JSType::JS_API_PLAIN_ARRAY: {
CHECK_DUMP_FIELDS(JSObject::SIZE, JSAPIPlainArray::SIZE, 3)
JSHandle<JSAPIPlainArray> jSAPIPlainArray = NewJSAPIPlainArray(thread, factory);
DUMP_FOR_HANDLE(jSAPIPlainArray)
break;
}
case JSType::JS_API_PLAIN_ARRAY_ITERATOR: {
CHECK_DUMP_FIELDS(JSObject::SIZE, JSAPIPlainArrayIterator::SIZE, 2)
JSHandle<JSAPIPlainArray> jSAPIPlainArray = NewJSAPIPlainArray(thread, factory);
JSHandle<JSAPIPlainArrayIterator> jSAPIPlainArrayIter =
factory->NewJSAPIPlainArrayIterator(jSAPIPlainArray, IterationKind::KEY);
DUMP_FOR_HANDLE(jSAPIPlainArrayIter)
break;
}
case JSType::JS_API_TREE_MAP: {
// 1 : 1 dump fileds number
CHECK_DUMP_FIELDS(JSObject::SIZE, JSAPITreeMap::SIZE, 1)

View File

@ -0,0 +1,253 @@
/*
* 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/js_api_plain_array.h"
#include "ecmascript/containers/containers_private.h"
#include "ecmascript/ecma_string.h"
#include "ecmascript/ecma_vm.h"
#include "ecmascript/global_env.h"
#include "ecmascript/js_api_plain_array_iterator.h"
#include "ecmascript/js_function.h"
#include "ecmascript/js_handle.h"
#include "ecmascript/js_iterator.h"
#include "ecmascript/js_object-inl.h"
#include "ecmascript/js_tagged_value.h"
#include "ecmascript/object_factory.h"
#include "ecmascript/tests/test_helper.h"
using namespace panda;
using namespace panda::ecmascript;
namespace panda::test {
class JSAPIPlainArrayTest : public testing::Test {
public:
static void SetUpTestCase()
{
GTEST_LOG_(INFO) << "SetUpTestCase";
}
static void TearDownTestCase()
{
GTEST_LOG_(INFO) << "TearDownCase";
}
void SetUp() override
{
TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
}
void TearDown() override
{
TestHelper::DestroyEcmaVMWithScope(instance, scope);
}
PandaVM *instance {nullptr};
ecmascript::EcmaHandleScope *scope {nullptr};
JSThread *thread {nullptr};
protected:
JSAPIPlainArray *CreatePlainArray()
{
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
JSHandle<JSTaggedValue> globalObject = env->GetJSGlobalObject();
JSHandle<JSTaggedValue> key(factory->NewFromASCII("ArkPrivate"));
JSHandle<JSTaggedValue> value =
JSObject::GetProperty(thread, JSHandle<JSTaggedValue>(globalObject), key).GetValue();
auto objCallInfo =
TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6); // 6 means the value
objCallInfo->SetFunction(JSTaggedValue::Undefined());
objCallInfo->SetThis(value.GetTaggedValue());
objCallInfo->SetCallArg(0, JSTaggedValue(static_cast<int>(containers::ContainerTag::PlainArray)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, objCallInfo.get());
JSTaggedValue result = containers::ContainersPrivate::Load(objCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
JSHandle<JSTaggedValue> constructor(thread, result);
JSHandle<JSAPIPlainArray> plainArray(
factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), constructor));
JSHandle<JSTaggedValue> keyArray = JSHandle<JSTaggedValue>(factory->NewTaggedArray(8)); // 8 means the value
JSHandle<JSTaggedValue> valueArray = JSHandle<JSTaggedValue>(factory->NewTaggedArray(8)); // 8 means the value
plainArray->SetKeys(thread, keyArray);
plainArray->SetValues(thread, valueArray);
return *plainArray;
}
};
HWTEST_F_L0(JSAPIPlainArrayTest, PlainArrayCreate)
{
JSAPIPlainArray *plainArray = CreatePlainArray();
EXPECT_TRUE(plainArray != nullptr);
}
HWTEST_F_L0(JSAPIPlainArrayTest, PA_AddAndGetKeyAtAndClear)
{
constexpr uint32_t NODE_NUMBERS = 8; // 8 means the value
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
// test JSAPIPlainArray
JSHandle<JSAPIPlainArray> array(thread, CreatePlainArray());
std::string myValue("myvalue");
for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
uint32_t ikey = 100 + i;
std::string ivalue = myValue + std::to_string(i);
key.Update(JSTaggedValue(ikey));
value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
JSAPIPlainArray::Add(thread, array, key, value);
}
EXPECT_EQ(array->GetSize(), static_cast<int>(NODE_NUMBERS));
for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
uint32_t ikey = 100 + i;
std::string ivalue = myValue + std::to_string(i);
key.Update(JSTaggedValue(ikey));
value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
// test getKeyAt
JSTaggedValue gvalue = array->GetKeyAt(i);
EXPECT_EQ(gvalue, key.GetTaggedValue());
}
// test clear
array->Clear(thread);
EXPECT_EQ(array->GetSize(), 0); // 0 means the value
}
HWTEST_F_L0(JSAPIPlainArrayTest, PA_CloneAndHasAndGet)
{
constexpr uint32_t NODE_NUMBERS = 8; // 8 means the value
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
// test JSAPIPlainArray
JSHandle<JSAPIPlainArray> array(thread, CreatePlainArray());
std::string myValue("myvalue");
for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
uint32_t ikey = 100 + i;
std::string ivalue = myValue + std::to_string(i);
key.Update(JSTaggedValue(ikey));
value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
JSAPIPlainArray::Add(thread, array, key, value);
}
EXPECT_EQ(array->GetSize(), static_cast<int>(NODE_NUMBERS));
// test clone
JSHandle<JSAPIPlainArray> newArray(thread, CreatePlainArray());
EXPECT_EQ(newArray->GetSize(), 0); // 0 means the value
newArray = JSAPIPlainArray::Clone(thread, array);
EXPECT_EQ(newArray->GetSize(), static_cast<int>(NODE_NUMBERS));
// test has
key.Update(JSTaggedValue(103)); // 103 means the value
int32_t lkey = 103;
bool result = array->Has(lkey);
EXPECT_TRUE(result);
// test get
myValue = std::string("myvalue3");
value.Update(factory->NewFromStdString(myValue).GetTaggedValue());
EXPECT_TRUE(JSTaggedValue::Equal(thread, JSHandle<JSTaggedValue>(thread, array->Get(key.GetTaggedValue())), value));
}
HWTEST_F_L0(JSAPIPlainArrayTest, PA_GetIndexOfKeyAndGeIndexOfValueAndIsEmptyAndRemoveRangeFrom)
{
constexpr uint32_t NODE_NUMBERS = 8; // 8 means the value
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
JSHandle<JSAPIPlainArray> array(thread, CreatePlainArray());
EXPECT_TRUE(array->IsEmpty());
std::string myValue("myvalue");
for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
uint32_t ikey = 100 + i;
std::string ivalue = myValue + std::to_string(i);
key.Update(JSTaggedValue(ikey));
value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
JSAPIPlainArray::Add(thread, array, key, value);
}
EXPECT_EQ(array->GetSize(), static_cast<int>(NODE_NUMBERS));
EXPECT_FALSE(array->IsEmpty());
value.Update(JSTaggedValue(103)); // 103 means the value
int32_t lvalue = 103;
JSTaggedValue value2 = array->GetIndexOfKey(lvalue);
EXPECT_EQ(value2.GetNumber(), 3); // 3 means the value
myValue = "myvalue2";
value.Update(factory->NewFromStdString(myValue).GetTaggedValue());
JSTaggedValue value3 = array->GetIndexOfValue(value.GetTaggedValue());
EXPECT_EQ(value3.GetNumber(), 2); // 2 means the value
value.Update(JSTaggedValue(1));
int32_t batchSize = 3; // 3 means the value
lvalue = 1;
value3 = array->RemoveRangeFrom(thread, lvalue, batchSize);
EXPECT_EQ(value3.GetNumber(), 3); // 3 means the value
EXPECT_EQ(array->GetSize(), static_cast<int>(NODE_NUMBERS - 3));
}
HWTEST_F_L0(JSAPIPlainArrayTest, PA_RemvoeAnrRemvoeAtAndSetValueAtAndGetValueAt)
{
constexpr uint32_t NODE_NUMBERS = 8; // 8 means the value
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
JSHandle<JSAPIPlainArray> array(thread, CreatePlainArray());
EXPECT_TRUE(array->IsEmpty());
std::string myValue("myvalue");
for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
uint32_t ikey = 100 + i;
std::string ivalue = myValue + std::to_string(i);
key.Update(JSTaggedValue(ikey));
value.Update(factory->NewFromStdString(ivalue).GetTaggedValue());
JSAPIPlainArray::Add(thread, array, key, value);
}
EXPECT_EQ(array->GetSize(), static_cast<int>(NODE_NUMBERS));
EXPECT_FALSE(array->IsEmpty());
// test Remove
myValue = "myvalue2";
value.Update(factory->NewFromStdString(myValue).GetTaggedValue());
JSTaggedValue taggedValue =
array->Remove(thread, JSTaggedValue(102)); // 102 means the value
EXPECT_TRUE(JSTaggedValue::Equal(thread, value, JSHandle<JSTaggedValue>(thread, taggedValue)));
// test RemoveAt
myValue = "myvalue4";
value.Update(factory->NewFromStdString(myValue).GetTaggedValue());
taggedValue =
array->RemoveAt(thread, JSTaggedValue(3)); // 3 means the value
EXPECT_TRUE(JSTaggedValue::Equal(thread, value, JSHandle<JSTaggedValue>(thread, taggedValue)));
EXPECT_EQ(array->GetSize(), static_cast<int>(NODE_NUMBERS - 2));
// test SetValueAt
myValue = "myvalue14";
value.Update(factory->NewFromStdString(myValue).GetTaggedValue());
array->SetValueAt(thread, JSTaggedValue(3), value.GetTaggedValue()); // 3 means the value
int32_t lvalue = 3; // 3 means the value
taggedValue = array->GetValueAt(lvalue);
EXPECT_TRUE(JSTaggedValue::Equal(thread, value, JSHandle<JSTaggedValue>(thread, taggedValue)));
}
} // namespace panda::test