HashMap HashSet LinkedList List ForEach IR

Use IR to save time and to avoid JSFunction::Call().

Issue: #I5Y9UV

Signed-off-by: lichenshuai <lichenshuai@huawei.com>
Change-Id: I54733053d39b3957d0a4789eb02f98cd19b5c394
This commit is contained in:
lichenshuai 2022-10-28 16:12:17 +08:00
parent 55a6cbf81b
commit 39057c8849
17 changed files with 696 additions and 11 deletions

View File

@ -33,6 +33,10 @@ namespace panda::ecmascript::kungfu {
V(DequeForEach) \
V(LightWeightMapForEach) \
V(LightWeightSetForEach) \
V(HashMapForEach) \
V(HashSetForEach) \
V(LinkedListForEach) \
V(ListForEach) \
V(ArrayListForEach) \
V(ArrayListReplaceAllElements) \

View File

@ -643,6 +643,90 @@ DECLARE_BUILTINS(LightWeightSetForEach)
Return(*res);
}
DECLARE_BUILTINS(HashMapForEach)
{
auto env = GetEnvironment();
DEFVARIABLE(res, VariableType::JS_POINTER(), Undefined());
Label exit(env);
Label slowPath(env);
ContainersStubBuilder containersBuilder(this);
containersBuilder.ContainersHashCall(glue, thisValue, numArgs, &res, &exit,
&slowPath, ContainersType::HASHMAP_FOREACH);
Bind(&slowPath);
{
BUILDARG();
res = CALLSLOWPATH();
Jump(&exit);
}
Bind(&exit);
Return(*res);
}
DECLARE_BUILTINS(HashSetForEach)
{
auto env = GetEnvironment();
DEFVARIABLE(res, VariableType::JS_POINTER(), Undefined());
Label exit(env);
Label slowPath(env);
ContainersStubBuilder containersBuilder(this);
containersBuilder.ContainersHashCall(glue, thisValue, numArgs, &res, &exit,
&slowPath, ContainersType::HASHSET_FOREACH);
Bind(&slowPath);
{
BUILDARG();
res = CALLSLOWPATH();
Jump(&exit);
}
Bind(&exit);
Return(*res);
}
DECLARE_BUILTINS(LinkedListForEach)
{
auto env = GetEnvironment();
DEFVARIABLE(res, VariableType::JS_POINTER(), Undefined());
Label exit(env);
Label slowPath(env);
ContainersStubBuilder containersBuilder(this);
containersBuilder.ContainersLinkedListCall(glue, thisValue, numArgs, &res, &exit,
&slowPath, ContainersType::LINKEDLIST_FOREACH);
Bind(&slowPath);
{
BUILDARG();
res = CALLSLOWPATH();
Jump(&exit);
}
Bind(&exit);
Return(*res);
}
DECLARE_BUILTINS(ListForEach)
{
auto env = GetEnvironment();
DEFVARIABLE(res, VariableType::JS_POINTER(), Undefined());
Label exit(env);
Label slowPath(env);
ContainersStubBuilder containersBuilder(this);
containersBuilder.ContainersLinkedListCall(glue, thisValue, numArgs, &res, &exit,
&slowPath, ContainersType::LIST_FOREACH);
Bind(&slowPath);
{
BUILDARG();
res = CALLSLOWPATH();
Jump(&exit);
}
Bind(&exit);
Return(*res);
}
DECLARE_BUILTINS(ArrayListForEach)
{
auto env = GetEnvironment();

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_COMPILER_BUILTINS_CONTAINERS_HASHMAP_STUB_BUILDER_H
#define ECMASCRIPT_COMPILER_BUILTINS_CONTAINERS_HASHMAP_STUB_BUILDER_H
#include "ecmascript/compiler/stub_builder-inl.h"
#include "ecmascript/js_api/js_api_hashmap.h"
namespace panda::ecmascript::kungfu {
class ContainersHashMapStubBuilder : public StubBuilder {
public:
explicit ContainersHashMapStubBuilder(StubBuilder *parent)
: StubBuilder(parent) {}
~ContainersHashMapStubBuilder() = default;
NO_MOVE_SEMANTIC(ContainersHashMapStubBuilder);
NO_COPY_SEMANTIC(ContainersHashMapStubBuilder);
void GenerateCircuit() override {}
GateRef GetTableLength(GateRef obj)
{
GateRef tableOffset = IntPtr(JSAPIHashMap::HASHMAP_TABLE_INDEX);
GateRef table = Load(VariableType::JS_POINTER(), obj, tableOffset);
return GetLengthOfTaggedArray(table);
}
GateRef GetNode(GateRef obj, GateRef index)
{
GateRef tableOffset = IntPtr(JSAPIHashMap::HASHMAP_TABLE_INDEX);
GateRef table = Load(VariableType::JS_POINTER(), obj, tableOffset);
return GetValueFromTaggedArray(table, index);
}
};
} // namespace panda::ecmascript::kungfu
#endif // ECMASCRIPT_COMPILER_BUILTINS_CONTAINERS_HASHMAP_STUB_BUILDER_H

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_COMPILER_BUILTINS_CONTAINERS_HASHSET_STUB_BUILDER_H
#define ECMASCRIPT_COMPILER_BUILTINS_CONTAINERS_HASHSET_STUB_BUILDER_H
#include "ecmascript/compiler/stub_builder-inl.h"
#include "ecmascript/js_api/js_api_hashset.h"
namespace panda::ecmascript::kungfu {
class ContainersHashSetStubBuilder : public StubBuilder {
public:
explicit ContainersHashSetStubBuilder(StubBuilder *parent)
: StubBuilder(parent) {}
~ContainersHashSetStubBuilder() = default;
NO_MOVE_SEMANTIC(ContainersHashSetStubBuilder);
NO_COPY_SEMANTIC(ContainersHashSetStubBuilder);
void GenerateCircuit() override {}
GateRef GetTableLength(GateRef obj)
{
GateRef tableOffset = IntPtr(JSAPIHashSet::HASHSET_TABLE_INDEX);
GateRef table = Load(VariableType::JS_POINTER(), obj, tableOffset);
return GetLengthOfTaggedArray(table);
}
GateRef GetNode(GateRef obj, GateRef index)
{
GateRef tableOffset = IntPtr(JSAPIHashSet::HASHSET_TABLE_INDEX);
GateRef table = Load(VariableType::JS_POINTER(), obj, tableOffset);
return GetValueFromTaggedArray(table, index);
}
};
} // namespace panda::ecmascript::kungfu
#endif // ECMASCRIPT_COMPILER_BUILTINS_CONTAINERS_HASHSET_STUB_BUILDER_H

View File

@ -48,4 +48,4 @@ public:
}
};
} // namespace panda::ecmascript::kungfu
#endif // ECMASCRIPT_COMPILER_BUILTINS_CONTAINERS_VECTOR_STUB_BUILDER_H
#endif // ECMASCRIPT_COMPILER_BUILTINS_CONTAINERS_LIGHTWEIGHTMAP_STUB_BUILDER_H

View File

@ -46,4 +46,4 @@ public:
}
};
} // namespace panda::ecmascript::kungfu
#endif // ECMASCRIPT_COMPILER_BUILTINS_CONTAINERS_VECTOR_STUB_BUILDER_H
#endif // ECMASCRIPT_COMPILER_BUILTINS_CONTAINERS_LIGHTWEIGHTSET_STUB_BUILDER_H

View File

@ -0,0 +1,47 @@
/*
* 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_COMPILER_BUILTINS_CONTAINERS_LINKEDLIST_STUB_BUILDER_H
#define ECMASCRIPT_COMPILER_BUILTINS_CONTAINERS_LINKEDLIST_STUB_BUILDER_H
#include "ecmascript/compiler/stub_builder-inl.h"
#include "ecmascript/js_api/js_api_linked_list.h"
namespace panda::ecmascript::kungfu {
class ContainersLinkedListStubBuilder : public StubBuilder {
public:
explicit ContainersLinkedListStubBuilder(StubBuilder *parent)
: StubBuilder(parent) {}
~ContainersLinkedListStubBuilder() = default;
NO_MOVE_SEMANTIC(ContainersLinkedListStubBuilder);
NO_COPY_SEMANTIC(ContainersLinkedListStubBuilder);
void GenerateCircuit() override {}
GateRef GetTableLength(GateRef obj)
{
GateRef tableOffset = IntPtr(JSAPILinkedList::DOUBLE_LIST_OFFSET);
GateRef table = Load(VariableType::JS_POINTER(), obj, tableOffset);
GateRef value = GetValueFromTaggedArray(table, Int32(TaggedDoubleList::NUMBER_OF_NODE_INDEX));
return TaggedGetInt(value);
}
GateRef GetNode(GateRef obj, GateRef index)
{
GateRef tableOffset = IntPtr(JSAPILinkedList::DOUBLE_LIST_OFFSET);
GateRef table = Load(VariableType::JS_POINTER(), obj, tableOffset);
return GetValueFromTaggedArray(table, index);
}
};
} // namespace panda::ecmascript::kungfu
#endif // ECMASCRIPT_COMPILER_BUILTINS_CONTAINERS_LINKEDLIST_STUB_BUILDER_H

View File

@ -0,0 +1,47 @@
/*
* 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_COMPILER_BUILTINS_CONTAINERS_LIST_STUB_BUILDER_H
#define ECMASCRIPT_COMPILER_BUILTINS_CONTAINERS_LIST_STUB_BUILDER_H
#include "ecmascript/compiler/stub_builder-inl.h"
#include "ecmascript/js_api/js_api_list.h"
namespace panda::ecmascript::kungfu {
class ContainersListStubBuilder : public StubBuilder {
public:
explicit ContainersListStubBuilder(StubBuilder *parent)
: StubBuilder(parent) {}
~ContainersListStubBuilder() = default;
NO_MOVE_SEMANTIC(ContainersListStubBuilder);
NO_COPY_SEMANTIC(ContainersListStubBuilder);
void GenerateCircuit() override {}
GateRef GetTableLength(GateRef obj)
{
GateRef tableOffset = IntPtr(JSAPIList::SINGLY_LIST_OFFSET);
GateRef table = Load(VariableType::JS_POINTER(), obj, tableOffset);
GateRef value = GetValueFromTaggedArray(table, Int32(TaggedSingleList::NUMBER_OF_NODE_INDEX));
return TaggedGetInt(value);
}
GateRef GetNode(GateRef obj, GateRef index)
{
GateRef tableOffset = IntPtr(JSAPIList::SINGLY_LIST_OFFSET);
GateRef table = Load(VariableType::JS_POINTER(), obj, tableOffset);
return GetValueFromTaggedArray(table, index);
}
};
} // namespace panda::ecmascript::kungfu
#endif // ECMASCRIPT_COMPILER_BUILTINS_CONTAINERS_LIST_STUB_BUILDER_H

View File

@ -456,4 +456,247 @@ void ContainersStubBuilder::ContainersLightWeightCall(GateRef glue, GateRef this
Bind(&afterLoop);
Jump(exit);
}
void ContainersStubBuilder::ContainersHashCall(GateRef glue, GateRef thisValue,
GateRef numArgs, Variable* result, Label *exit, Label *slowPath, ContainersType type)
{
auto env = GetEnvironment();
DEFVARIABLE(thisObj, VariableType::JS_ANY(), thisValue);
DEFVARIABLE(thisArg, VariableType::JS_ANY(), Undefined());
DEFVARIABLE(node, VariableType::JS_ANY(), Undefined());
DEFVARIABLE(key, VariableType::JS_ANY(), Undefined());
DEFVARIABLE(value, VariableType::JS_ANY(), Undefined());
DEFVARIABLE(length, VariableType::INT32(), Int32(0));
DEFVARIABLE(index, VariableType::INT32(), Int32(0));
Label valueIsJSAPIHash(env);
Label valueNotJSAPIHash(env);
Label objIsJSProxy(env);
Label objNotJSProxy(env);
Label objIsJSAPIHash(env);
Label thisArgUndefined(env);
Label thisArgNotUndefined(env);
Label callbackUndefined(env);
Label callbackNotUndefined(env);
Label nextCount(env);
Label nodeNotHole(env);
Label nodeIsLinked(env);
Label nodeIsRBTree(env);
Label loopLinked(env);
Label loopHead(env);
Label loopEnd(env);
Label next(env);
Label afterLoop(env);
GateRef callbackFnHandle;
Branch(IsContainer(*thisObj, type), &valueIsJSAPIHash, &valueNotJSAPIHash);
Bind(&valueNotJSAPIHash);
{
Branch(IsJsProxy(*thisObj), &objIsJSProxy, &objNotJSProxy);
Bind(&objIsJSProxy);
{
GateRef tempObj = GetTarget(*thisObj);
Branch(IsContainer(tempObj, type), &objIsJSAPIHash, slowPath);
Bind(&objIsJSAPIHash);
{
thisObj = tempObj;
Jump(&valueIsJSAPIHash);
}
}
Bind(&objNotJSProxy);
Jump(slowPath);
}
Bind(&valueIsJSAPIHash);
{
Branch(Int64GreaterThanOrEqual(IntPtr(0), numArgs), &callbackUndefined, &callbackNotUndefined);
Bind(&callbackUndefined);
Jump(slowPath);
Bind(&callbackNotUndefined);
{
Label isCall(env);
Label notCall(env);
Label isHeapObj(env);
callbackFnHandle = GetCallArg0();
Branch(TaggedIsHeapObject(callbackFnHandle), &isHeapObj, &notCall);
Bind(&isHeapObj);
Branch(IsCallable(callbackFnHandle), &isCall, &notCall);
Bind(&notCall);
Jump(slowPath);
Bind(&isCall);
{
Branch(Int64GreaterThanOrEqual(IntPtr(1), numArgs), &thisArgUndefined, &thisArgNotUndefined);
Bind(&thisArgUndefined);
Jump(&nextCount);
Bind(&thisArgNotUndefined);
thisArg = GetCallArg1();
Jump(&nextCount);
}
}
}
Bind(&nextCount);
{
length = ContainerGetSize(*thisObj, type);
Jump(&loopHead);
LoopBegin(&loopHead);
{
Label hasExceptionLinked(env);
Label notHasExceptionLinked(env);
Label hasExceptionRBTree(env);
Label notHasExceptionRBTree(env);
Branch(Int32LessThan(*index, *length), &next, &afterLoop);
Bind(&next);
{
node = ContainerGetNode(*thisObj, *index, type);
Branch(TaggedIsHole(*node), &loopEnd, &nodeNotHole);
Bind(&nodeNotHole);
Branch(IsLinkedNode(*node), &nodeIsLinked, &nodeIsRBTree);
LoopBegin(&nodeIsLinked);
{
value = Load(VariableType::JS_POINTER(), *node, IntPtr(
type == ContainersType::HASHSET_FOREACH ? LinkedNode::KEY_OFFSET : LinkedNode::VALUE_OFFSET));
key = Load(VariableType::JS_POINTER(), *node, IntPtr(LinkedNode::KEY_OFFSET));
GateRef retValue = JSCallDispatch(glue, callbackFnHandle, Int32(3), 0, // 3: numArgs
JSCallMode::CALL_THIS_ARG3_WITH_RETURN, { *thisArg, *value, *key, *thisObj });
Branch(HasPendingException(glue), &hasExceptionLinked, &notHasExceptionLinked);
Bind(&hasExceptionLinked);
{
result->WriteVariable(retValue);
Jump(exit);
}
Bind(&notHasExceptionLinked);
node = Load(VariableType::JS_POINTER(), *node, IntPtr(LinkedNode::NEXT_OFFSET));
Branch(TaggedIsHole(*node), &loopEnd, &loopLinked);
}
Bind(&loopLinked);
LoopEnd(&nodeIsLinked);
Bind(&nodeIsRBTree);
{
GateRef retValue = CallRuntime(glue, RTSTUB_ID(ContainerRBTreeForEach),
{ *node, callbackFnHandle, *thisArg, *thisObj,
IntToTaggedInt(Int32(static_cast<int32_t>(type))) });
Branch(HasPendingException(glue), &hasExceptionRBTree, &notHasExceptionRBTree);
Bind(&hasExceptionRBTree);
{
result->WriteVariable(retValue);
Jump(exit);
}
Bind(&notHasExceptionRBTree);
Jump(&loopEnd);
}
}
}
Bind(&loopEnd);
index = Int32Add(*index, Int32(1));
LoopEnd(&loopHead);
}
Bind(&afterLoop);
Jump(exit);
}
void ContainersStubBuilder::ContainersLinkedListCall(GateRef glue, GateRef thisValue,
GateRef numArgs, Variable* result, Label *exit, Label *slowPath, ContainersType type)
{
auto env = GetEnvironment();
DEFVARIABLE(thisObj, VariableType::JS_ANY(), thisValue);
DEFVARIABLE(thisArg, VariableType::JS_ANY(), Undefined());
DEFVARIABLE(valueNode, VariableType::INT32(), Int32(0));
DEFVARIABLE(key, VariableType::JS_ANY(), Undefined());
DEFVARIABLE(value, VariableType::JS_ANY(), Undefined());
DEFVARIABLE(length, VariableType::INT32(), Int32(0));
DEFVARIABLE(index, VariableType::INT32(), Int32(0));
Label valueIsJSAPILinkedList(env);
Label valueNotJSAPILinkedList(env);
Label objIsJSProxy(env);
Label objNotJSProxy(env);
Label objIsJSAPILinkedList(env);
Label thisArgUndefined(env);
Label thisArgNotUndefined(env);
Label callbackUndefined(env);
Label callbackNotUndefined(env);
Label nextCount(env);
Label valueNotHole(env);
Label loopHead(env);
Label loopEnd(env);
Label next(env);
Label afterLoop(env);
GateRef callbackFnHandle;
Branch(IsContainer(*thisObj, type), &valueIsJSAPILinkedList, &valueNotJSAPILinkedList);
Bind(&valueNotJSAPILinkedList);
{
Branch(IsJsProxy(*thisObj), &objIsJSProxy, &objNotJSProxy);
Bind(&objIsJSProxy);
{
GateRef tempObj = GetTarget(*thisObj);
Branch(IsContainer(tempObj, type), &objIsJSAPILinkedList, slowPath);
Bind(&objIsJSAPILinkedList);
{
thisObj = tempObj;
Jump(&valueIsJSAPILinkedList);
}
}
Bind(&objNotJSProxy);
Jump(slowPath);
}
Bind(&valueIsJSAPILinkedList);
{
Branch(Int64GreaterThanOrEqual(IntPtr(0), numArgs), &callbackUndefined, &callbackNotUndefined);
Bind(&callbackUndefined);
Jump(slowPath);
Bind(&callbackNotUndefined);
{
Label isCall(env);
Label notCall(env);
Label isHeapObj(env);
callbackFnHandle = GetCallArg0();
Branch(TaggedIsHeapObject(callbackFnHandle), &isHeapObj, &notCall);
Bind(&isHeapObj);
Branch(IsCallable(callbackFnHandle), &isCall, &notCall);
Bind(&notCall);
Jump(slowPath);
Bind(&isCall);
{
Branch(Int64GreaterThanOrEqual(IntPtr(1), numArgs), &thisArgUndefined, &thisArgNotUndefined);
Bind(&thisArgUndefined);
Jump(&nextCount);
Bind(&thisArgNotUndefined);
thisArg = GetCallArg1();
Jump(&nextCount);
}
}
}
Bind(&nextCount);
{
length = ContainerGetSize(*thisObj, type);
valueNode = Int32(TaggedList<TaggedArray>::ELEMENTS_START_INDEX);
Jump(&loopHead);
LoopBegin(&loopHead);
{
Label hasException(env);
Label notHasException(env);
Branch(Int32LessThan(*index, *length), &next, &afterLoop);
Bind(&next);
{
valueNode = TaggedGetInt(ContainerGetNode(*thisObj,
Int32Add(*valueNode, Int32(TaggedList<TaggedArray>::NEXT_PTR_OFFSET)), type));
value = ContainerGetNode(*thisObj, *valueNode, type);
Branch(TaggedIsHole(*value), &loopEnd, &valueNotHole);
Bind(&valueNotHole);
key = IntToTaggedInt(*index);
GateRef retValue = JSCallDispatch(glue, callbackFnHandle, Int32(3), 0, // 3: numArgs
JSCallMode::CALL_THIS_ARG3_WITH_RETURN, { *thisArg, *value, *key, *thisObj });
Branch(HasPendingException(glue), &hasException, &notHasException);
Bind(&hasException);
{
result->WriteVariable(retValue);
Jump(exit);
}
Bind(&notHasException);
Jump(&loopEnd);
}
}
Bind(&loopEnd);
index = Int32Add(*index, Int32(1));
LoopEnd(&loopHead);
}
Bind(&afterLoop);
Jump(exit);
}
} // namespace panda::ecmascript::kungfu

View File

@ -17,8 +17,12 @@
#define ECMASCRIPT_COMPILER_BUILTINS_CONTAINERS_STUB_BUILDER_H
#include "ecmascript/compiler/builtins/containers_arraylist_stub_builder.h"
#include "ecmascript/compiler/builtins/containers_deque_stub_builder.h"
#include "ecmascript/compiler/builtins/containers_hashmap_stub_builder.h"
#include "ecmascript/compiler/builtins/containers_hashset_stub_builder.h"
#include "ecmascript/compiler/builtins/containers_lightweightmap_stub_builder.h"
#include "ecmascript/compiler/builtins/containers_lightweightset_stub_builder.h"
#include "ecmascript/compiler/builtins/containers_linkedlist_stub_builder.h"
#include "ecmascript/compiler/builtins/containers_list_stub_builder.h"
#include "ecmascript/compiler/builtins/containers_plainarray_stub_builder.h"
#include "ecmascript/compiler/builtins/containers_queue_stub_builder.h"
#include "ecmascript/compiler/builtins/containers_stack_stub_builder.h"
@ -37,6 +41,10 @@ enum class ContainersType : uint8_t {
DEQUE_FOREACH,
LIGHTWEIGHTMAP_FOREACH,
LIGHTWEIGHTSET_FOREACH,
HASHMAP_FOREACH,
HASHSET_FOREACH,
LINKEDLIST_FOREACH,
LIST_FOREACH,
ARRAYLIST_FOREACH,
ARRAYLIST_REPLACEALLELEMENTS,
};
@ -62,6 +70,12 @@ public:
void ContainersLightWeightCall(GateRef glue, GateRef thisValue, GateRef numArgs,
Variable* result, Label *exit, Label *slowPath, ContainersType type);
void ContainersHashCall(GateRef glue, GateRef thisValue, GateRef numArgs,
Variable* result, Label *exit, Label *slowPath, ContainersType type);
void ContainersLinkedListCall(GateRef glue, GateRef thisValue, GateRef numArgs,
Variable* result, Label *exit, Label *slowPath, ContainersType type);
GateRef IsContainer(GateRef obj, ContainersType type)
{
switch (type) {
@ -80,6 +94,14 @@ public:
return IsJSAPILightWeightMap(obj);
case ContainersType::LIGHTWEIGHTSET_FOREACH:
return IsJSAPILightWeightSet(obj);
case ContainersType::HASHMAP_FOREACH:
return IsJSAPIHashMap(obj);
case ContainersType::HASHSET_FOREACH:
return IsJSAPIHashSet(obj);
case ContainersType::LINKEDLIST_FOREACH:
return IsJSAPILinkedList(obj);
case ContainersType::LIST_FOREACH:
return IsJSAPIList(obj);
case ContainersType::ARRAYLIST_FOREACH:
case ContainersType::ARRAYLIST_REPLACEALLELEMENTS:
return IsJSAPIArrayList(obj);
@ -177,6 +199,22 @@ public:
ContainersLightWeightSetStubBuilder lightWeightSetBuilder(this);
return lightWeightSetBuilder.GetSize(obj);
}
case ContainersType::HASHMAP_FOREACH: {
ContainersHashMapStubBuilder hashMapBuilder(this);
return hashMapBuilder.GetTableLength(obj);
}
case ContainersType::HASHSET_FOREACH: {
ContainersHashSetStubBuilder hashSetBuilder(this);
return hashSetBuilder.GetTableLength(obj);
}
case ContainersType::LINKEDLIST_FOREACH: {
ContainersLinkedListStubBuilder linkedListBuilder(this);
return linkedListBuilder.GetTableLength(obj);
}
case ContainersType::LIST_FOREACH: {
ContainersListStubBuilder listBuilder(this);
return listBuilder.GetTableLength(obj);
}
case ContainersType::ARRAYLIST_REPLACEALLELEMENTS:
case ContainersType::ARRAYLIST_FOREACH: {
ContainersArrayListStubBuilder arrayListBuilder(this);
@ -248,6 +286,31 @@ public:
return False();
}
GateRef ContainerGetNode(GateRef obj, GateRef index, ContainersType type)
{
switch (type) {
case ContainersType::HASHMAP_FOREACH: {
ContainersHashMapStubBuilder hashMapBuilder(this);
return hashMapBuilder.GetNode(obj, index);
}
case ContainersType::HASHSET_FOREACH: {
ContainersHashSetStubBuilder hashSetBuilder(this);
return hashSetBuilder.GetNode(obj, index);
}
case ContainersType::LINKEDLIST_FOREACH: {
ContainersLinkedListStubBuilder linkedListBuilder(this);
return linkedListBuilder.GetNode(obj, index);
}
case ContainersType::LIST_FOREACH: {
ContainersListStubBuilder listBuilder(this);
return listBuilder.GetNode(obj, index);
}
default:
UNREACHABLE();
}
return False();
}
GateRef PlainArrayGetKey(GateRef obj, GateRef index)
{
ContainersPlainArrayStubBuilder plainArrayBuilder(this);

View File

@ -1092,6 +1092,36 @@ inline GateRef StubBuilder::IsJSAPILightWeightSet(GateRef obj)
return Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::JS_API_LIGHT_WEIGHT_SET)));
}
inline GateRef StubBuilder::IsLinkedNode(GateRef obj)
{
GateRef objectType = GetObjectType(LoadHClass(obj));
return Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::LINKED_NODE)));
}
inline GateRef StubBuilder::IsJSAPIHashMap(GateRef obj)
{
GateRef objectType = GetObjectType(LoadHClass(obj));
return Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::JS_API_HASH_MAP)));
}
inline GateRef StubBuilder::IsJSAPIHashSet(GateRef obj)
{
GateRef objectType = GetObjectType(LoadHClass(obj));
return Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::JS_API_HASH_SET)));
}
inline GateRef StubBuilder::IsJSAPILinkedList(GateRef obj)
{
GateRef objectType = GetObjectType(LoadHClass(obj));
return Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::JS_API_LINKED_LIST)));
}
inline GateRef StubBuilder::IsJSAPIList(GateRef obj)
{
GateRef objectType = GetObjectType(LoadHClass(obj));
return Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::JS_API_LIST)));
}
inline GateRef StubBuilder::IsJSAPIArrayList(GateRef obj)
{
GateRef objectType = GetObjectType(LoadHClass(obj));

View File

@ -261,8 +261,13 @@ public:
GateRef IsJSAPIPlainArray(GateRef obj);
GateRef IsJSAPIQueue(GateRef obj);
GateRef IsJSAPIDeque(GateRef obj);
GateRef IsJSAPILightWeightMap(GateRef attr);
GateRef IsJSAPILightWeightSet(GateRef attr);
GateRef IsJSAPILightWeightMap(GateRef obj);
GateRef IsJSAPILightWeightSet(GateRef obj);
GateRef IsLinkedNode(GateRef obj);
GateRef IsJSAPIHashMap(GateRef obj);
GateRef IsJSAPIHashSet(GateRef obj);
GateRef IsJSAPILinkedList(GateRef obj);
GateRef IsJSAPIList(GateRef obj);
GateRef IsJSAPIArrayList(GateRef obj);
GateRef GetTarget(GateRef proxyObj);
GateRef HandlerBaseIsAccessor(GateRef attr);

View File

@ -269,9 +269,9 @@ JSTaggedValue ContainersHashSet::ForEach(EcmaRuntimeCallInfo *argv)
currentKey.Update(node->GetKey());
EcmaRuntimeCallInfo *info =
EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle,
thisArgHandle, undefined, 2); // 2: two args
thisArgHandle, undefined, 3); // 3: three args
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
info->SetCallArg(currentKey.GetTaggedValue(), thisHandle.GetTaggedValue());
info->SetCallArg(currentKey.GetTaggedValue(), currentKey.GetTaggedValue(), thisHandle.GetTaggedValue());
JSTaggedValue funcResult = JSFunction::Call(info);
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, funcResult);
}

View File

@ -980,7 +980,8 @@ JSHandle<JSTaggedValue> ContainersPrivate::InitializeList(JSThread *thread)
SetFrozenFunction(thread, listFuncPrototype, "getIndexOf", ContainersList::GetIndexOf, FuncLength::ONE);
SetFrozenFunction(thread, listFuncPrototype, "getLastIndexOf", ContainersList::GetLastIndexOf, FuncLength::ONE);
SetFrozenFunction(thread, listFuncPrototype, "set", ContainersList::Set, FuncLength::ONE);
SetFrozenFunction(thread, listFuncPrototype, "forEach", ContainersList::ForEach, FuncLength::ONE);
SetFrozenFunction(thread, listFuncPrototype, "forEach", ContainersList::ForEach, FuncLength::ONE,
static_cast<uint8_t>(BUILTINS_STUB_ID(ListForEach)));
SetFrozenFunction(thread, listFuncPrototype, "replaceAllElements", ContainersList::ReplaceAllElements,
FuncLength::ONE);
SetFrozenFunction(thread, listFuncPrototype, "equal", ContainersList::Equal, FuncLength::ONE);
@ -1042,7 +1043,8 @@ JSHandle<JSTaggedValue> ContainersPrivate::InitializeLinkedList(JSThread *thread
SetFrozenFunction(thread, linkedListFuncPrototype, "convertToArray", ContainersLinkedList::ConvertToArray,
FuncLength::ONE);
SetFrozenFunction(thread, linkedListFuncPrototype, "set", ContainersLinkedList::Set, FuncLength::ONE);
SetFrozenFunction(thread, linkedListFuncPrototype, "forEach", ContainersLinkedList::ForEach, FuncLength::ONE);
SetFrozenFunction(thread, linkedListFuncPrototype, "forEach", ContainersLinkedList::ForEach, FuncLength::ONE,
static_cast<uint8_t>(BUILTINS_STUB_ID(LinkedListForEach)));
JSHandle<JSTaggedValue> lengthGetter = CreateGetter(thread, ContainersLinkedList::Length, "length",
FuncLength::ZERO);
@ -1114,7 +1116,8 @@ JSHandle<JSTaggedValue> ContainersPrivate::InitializeHashMap(JSThread *thread)
// HashMap.prototype.get()
SetFrozenFunction(thread, hashMapFuncPrototype, "get", ContainersHashMap::Get, FuncLength::ONE);
// HashMap.prototype.forEach()
SetFrozenFunction(thread, hashMapFuncPrototype, "forEach", ContainersHashMap::ForEach, FuncLength::TWO);
SetFrozenFunction(thread, hashMapFuncPrototype, "forEach", ContainersHashMap::ForEach, FuncLength::TWO,
static_cast<uint8_t>(BUILTINS_STUB_ID(HashMapForEach)));
// HashMap.prototype.hasKey()
SetFrozenFunction(thread, hashMapFuncPrototype, "hasKey", ContainersHashMap::HasKey, FuncLength::ONE);
// HashMap.prototype.hasValue()
@ -1190,7 +1193,8 @@ JSHandle<JSTaggedValue> ContainersPrivate::InitializeHashSet(JSThread *thread)
SetFrozenFunction(thread, hashSetFuncPrototype, "clear", ContainersHashSet::Clear, FuncLength::ZERO);
SetFrozenFunction(thread, hashSetFuncPrototype, "values", ContainersHashSet::Values, FuncLength::ZERO);
SetFrozenFunction(thread, hashSetFuncPrototype, "entries", ContainersHashSet::Entries, FuncLength::ZERO);
SetFrozenFunction(thread, hashSetFuncPrototype, "forEach", ContainersHashSet::ForEach, FuncLength::TWO);
SetFrozenFunction(thread, hashSetFuncPrototype, "forEach", ContainersHashSet::ForEach, FuncLength::TWO,
static_cast<uint8_t>(BUILTINS_STUB_ID(HashSetForEach)));
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
// @@ToStringTag

View File

@ -18,6 +18,7 @@
#include "ecmascript/accessor_data.h"
#include "ecmascript/base/number_helper.h"
#include "ecmascript/base/string_helper.h"
#include "ecmascript/compiler/builtins/containers_stub_builder.h"
#include "ecmascript/compiler/call_signature.h"
#include "ecmascript/compiler/ecma_opcode_des.h"
#include "ecmascript/compiler/rt_call_signature.h"
@ -44,6 +45,7 @@
#include "ecmascript/message_string.h"
#include "ecmascript/object_factory.h"
#include "ecmascript/tagged_dictionary.h"
#include "ecmascript/tagged_node.h"
#include "ecmascript/ts_types/ts_manager.h"
#include "libpandafile/bytecode_instruction-inl.h"
@ -2055,6 +2057,44 @@ DEF_RUNTIME_STUBS(LdObjByName)
return RuntimeLdObjByName(thread, receiver, propKey, callGetter, undefined).GetRawData();
}
DEF_RUNTIME_STUBS(ContainerRBTreeForEach)
{
RUNTIME_STUBS_HEADER(ContainerRBTreeForEach);
JSHandle<JSTaggedValue> node = GetHArg<JSTaggedValue>(argv, argc, 0); // 0: param index
JSHandle<JSTaggedValue> callbackFnHandle = GetHArg<JSTaggedValue>(argv, argc, 1); // 1: param index
JSHandle<JSTaggedValue> thisArgHandle = GetHArg<JSTaggedValue>(argv, argc, 2); // 2: param index
JSHandle<JSTaggedValue> thisHandle = GetHArg<JSTaggedValue>(argv, argc, 3); // 3: param index
JSHandle<JSTaggedValue> type = GetHArg<JSTaggedValue>(argv, argc, 4); // 4: param index
ASSERT(node->IsRBTreeNode());
ASSERT(callbackFnHandle->IsCallable());
ASSERT(type->IsInt());
JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
auto containersType = static_cast<kungfu::ContainersType>(type->GetInt());
JSMutableHandle<TaggedQueue> queue(thread, thread->GetEcmaVM()->GetFactory()->NewTaggedQueue(0));
JSMutableHandle<RBTreeNode> treeNode(thread, JSTaggedValue::Undefined());
queue.Update(JSTaggedValue(TaggedQueue::Push(thread, queue, node)));
while (!queue->Empty()) {
treeNode.Update(queue->Pop(thread));
EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle,
undefined, 3); // 3: three args
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception().GetRawData());
info->SetCallArg(containersType == kungfu::ContainersType::HASHSET_FOREACH ?
treeNode->GetKey() : treeNode->GetValue(), treeNode->GetKey(), thisHandle.GetTaggedValue());
JSTaggedValue funcResult = JSFunction::Call(info);
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, funcResult.GetRawData());
if (!treeNode->GetLeft().IsHole()) {
JSHandle<JSTaggedValue> left(thread, treeNode->GetLeft());
queue.Update(JSTaggedValue(TaggedQueue::Push(thread, queue, left)));
}
if (!treeNode->GetRight().IsHole()) {
JSHandle<JSTaggedValue> right(thread, treeNode->GetRight());
queue.Update(JSTaggedValue(TaggedQueue::Push(thread, queue, right)));
}
}
return JSTaggedValue::True().GetRawData();
}
JSTaggedType RuntimeStubs::CreateArrayFromList([[maybe_unused]]uintptr_t argGlue, int32_t argc, JSTaggedValue *argvPtr)
{
auto thread = JSThread::GlueToJSThread(argGlue);

View File

@ -292,7 +292,8 @@ using JSFunctionReentry = JSTaggedValue (*)(uintptr_t glue, uint32_t argc, const
V(LdPatchVar) \
V(StPatchVar) \
V(LdObjByName) \
V(DeoptHandler)
V(DeoptHandler) \
V(ContainerRBTreeForEach)
#define RUNTIME_STUB_LIST(V) \
RUNTIME_ASM_STUB_LIST(V) \

View File

@ -165,6 +165,31 @@ if (globalThis["ArkPrivate"] != undefined) {
}
}
res.forEach(elements);
// test RBTree
let collisionMap = new fastmap();
let count = 0;
// same hash when mod 1024
collisionMap.set(1224, 1);
collisionMap.set(1285, 2);
collisionMap.set(1463, 3);
collisionMap.set(4307, 4);
collisionMap.set(5135, 5);
collisionMap.set(5903, 6);
collisionMap.set(6603, 7);
collisionMap.set(6780, 8);
collisionMap.set(8416, 9);
collisionMap.set(9401, 10);
collisionMap.set(9740, 11);
collisionMap.forEach((value, key, hashMap) => {
if (hashMap.get(key) == value) {
count += value;
}
});
if (count != 66) { // 66: 1 + 2 + 3 + ... + 11
print("test RBTree forEach fail. count=" + count);
}
if (!flag) {
print("Test HashMap success!!!");
} else {