!2719 LightWeightMap LightWeightSet ForEach IR

Merge pull request !2719 from 李晨帅/master
This commit is contained in:
openharmony_ci 2022-10-26 11:46:12 +00:00 committed by Gitee
commit 2e5a1c88a2
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
11 changed files with 319 additions and 10 deletions

View File

@ -31,6 +31,8 @@ namespace panda::ecmascript::kungfu {
V(PlainArrayForEach) \
V(QueueForEach) \
V(DequeForEach) \
V(LightWeightMapForEach) \
V(LightWeightSetForEach) \
class BuiltinsStubCSigns {
public:

View File

@ -600,4 +600,46 @@ DECLARE_BUILTINS(DequeForEach)
Bind(&exit);
Return(*res);
}
DECLARE_BUILTINS(LightWeightMapForEach)
{
auto env = GetEnvironment();
DEFVARIABLE(res, VariableType::JS_POINTER(), Undefined());
Label exit(env);
Label slowPath(env);
ContainersStubBuilder containersBuilder(this);
containersBuilder.ContainersLightWeightCall(glue, thisValue, numArgs, &res, &exit,
&slowPath, ContainersType::LIGHTWEIGHTMAP_FOREACH);
Bind(&slowPath);
{
BUILDARG();
res = CALLSLOWPATH();
Jump(&exit);
}
Bind(&exit);
Return(*res);
}
DECLARE_BUILTINS(LightWeightSetForEach)
{
auto env = GetEnvironment();
DEFVARIABLE(res, VariableType::JS_POINTER(), Undefined());
Label exit(env);
Label slowPath(env);
ContainersStubBuilder containersBuilder(this);
containersBuilder.ContainersLightWeightCall(glue, thisValue, numArgs, &res, &exit,
&slowPath, ContainersType::LIGHTWEIGHTSET_FOREACH);
Bind(&slowPath);
{
BUILDARG();
res = CALLSLOWPATH();
Jump(&exit);
}
Bind(&exit);
Return(*res);
}
} // namespace panda::ecmascript::kungfu

View File

@ -0,0 +1,51 @@
/*
* 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_LIGHTWEIGHTMAP_STUB_BUILDER_H
#define ECMASCRIPT_COMPILER_BUILTINS_CONTAINERS_LIGHTWEIGHTMAP_STUB_BUILDER_H
#include "ecmascript/compiler/stub_builder-inl.h"
#include "ecmascript/js_api/js_api_lightweightmap.h"
namespace panda::ecmascript::kungfu {
class ContainersLightWeightMapStubBuilder : public StubBuilder {
public:
explicit ContainersLightWeightMapStubBuilder(StubBuilder *parent)
: StubBuilder(parent) {}
~ContainersLightWeightMapStubBuilder() = default;
NO_MOVE_SEMANTIC(ContainersLightWeightMapStubBuilder);
NO_COPY_SEMANTIC(ContainersLightWeightMapStubBuilder);
void GenerateCircuit() override {}
GateRef GetSize(GateRef obj)
{
return Load(VariableType::INT32(), obj, IntPtr(JSAPILightWeightMap::LWP_LENGTH_OFFSET));
}
GateRef GetKey(GateRef obj, GateRef index)
{
GateRef keysOffset = IntPtr(JSAPILightWeightMap::LWP_KEYS_OFFSET);
GateRef keys = Load(VariableType::JS_POINTER(), obj, keysOffset);
return GetValueFromTaggedArray(keys, index);
}
GateRef GetValue(GateRef obj, GateRef index)
{
GateRef valuesOffset = IntPtr(JSAPILightWeightMap::LWP_VALUES_OFFSET);
GateRef values = Load(VariableType::JS_POINTER(), obj, valuesOffset);
return GetValueFromTaggedArray(values, index);
}
};
} // namespace panda::ecmascript::kungfu
#endif // ECMASCRIPT_COMPILER_BUILTINS_CONTAINERS_VECTOR_STUB_BUILDER_H

View File

@ -0,0 +1,49 @@
/*
* 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_LIGHTWEIGHTSET_STUB_BUILDER_H
#define ECMASCRIPT_COMPILER_BUILTINS_CONTAINERS_LIGHTWEIGHTSET_STUB_BUILDER_H
#include "ecmascript/compiler/stub_builder-inl.h"
#include "ecmascript/js_api/js_api_lightweightset.h"
namespace panda::ecmascript::kungfu {
class ContainersLightWeightSetStubBuilder : public StubBuilder {
public:
explicit ContainersLightWeightSetStubBuilder(StubBuilder *parent)
: StubBuilder(parent) {}
~ContainersLightWeightSetStubBuilder() = default;
NO_MOVE_SEMANTIC(ContainersLightWeightSetStubBuilder);
NO_COPY_SEMANTIC(ContainersLightWeightSetStubBuilder);
void GenerateCircuit() override {}
GateRef GetSize(GateRef obj)
{
return Load(VariableType::INT32(), obj, IntPtr(JSAPILightWeightSet::LENGTH_OFFSET));
}
GateRef GetKey(GateRef obj, GateRef index)
{
return GetValue(obj, index);
}
GateRef GetValue(GateRef obj, GateRef index)
{
GateRef valuesOffset = IntPtr(JSAPILightWeightSet::VALUES_OFFSET);
GateRef values = Load(VariableType::JS_POINTER(), obj, valuesOffset);
return GetValueFromTaggedArray(values, index);
}
};
} // namespace panda::ecmascript::kungfu
#endif // ECMASCRIPT_COMPILER_BUILTINS_CONTAINERS_VECTOR_STUB_BUILDER_H

View File

@ -340,4 +340,108 @@ void ContainersStubBuilder::DequeCommonFuncCall(GateRef glue, GateRef thisValue,
Bind(&afterLoop);
Jump(exit);
}
void ContainersStubBuilder::ContainersLightWeightCall(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(key, VariableType::JS_ANY(), Undefined());
DEFVARIABLE(value, VariableType::JS_ANY(), Undefined());
DEFVARIABLE(length, VariableType::INT32(), Int32(0));
DEFVARIABLE(index, VariableType::INT32(), Int32(0));
Label valueIsJSAPILightWeight(env);
Label valueNotJSAPILightWeight(env);
Label objIsJSProxy(env);
Label objNotJSProxy(env);
Label objIsJSAPILightWeight(env);
Label thisArgUndefined(env);
Label thisArgNotUndefined(env);
Label callbackUndefined(env);
Label callbackNotUndefined(env);
Label nextCount(env);
Label loopHead(env);
Label loopEnd(env);
Label next(env);
Label afterLoop(env);
GateRef callbackFnHandle;
Branch(IsContainer(*thisObj, type), &valueIsJSAPILightWeight, &valueNotJSAPILightWeight);
Bind(&valueNotJSAPILightWeight);
{
Branch(IsJsProxy(*thisObj), &objIsJSProxy, &objNotJSProxy);
Bind(&objIsJSProxy);
{
GateRef tempObj = GetTarget(*thisObj);
Branch(IsContainer(tempObj, type), &objIsJSAPILightWeight, slowPath);
Bind(&objIsJSAPILightWeight);
{
thisObj = tempObj;
Jump(&valueIsJSAPILightWeight);
}
}
Bind(&objNotJSProxy);
Jump(slowPath);
}
Bind(&valueIsJSAPILightWeight);
{
Branch(Int64GreaterThanOrEqual(IntPtr(0), numArgs), &callbackUndefined, &callbackNotUndefined);
Bind(&callbackUndefined);
Jump(slowPath);
Bind(&callbackNotUndefined);
{
Label isCall(env);
Label notCall(env);
callbackFnHandle = GetCallArg0();
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 lenChange(env);
Label hasException(env);
Label notHasException(env);
Branch(Int32LessThan(*index, *length), &next, &afterLoop);
Bind(&next);
{
value = ContainerGetValue(*thisObj, *index, type);
key = ContainerGetKey(*thisObj, *index, type);
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);
GateRef currentLen = ContainerGetSize(*thisObj, type);
Branch(Int32NotEqual(currentLen, *length), &lenChange, &loopEnd);
Bind(&lenChange);
length = currentLen;
Jump(&loopEnd);
}
}
Bind(&loopEnd);
index = Int32Add(*index, Int32(1));
LoopEnd(&loopHead);
}
Bind(&afterLoop);
Jump(exit);
}
} // namespace panda::ecmascript::kungfu

View File

@ -16,6 +16,8 @@
#ifndef ECMASCRIPT_COMPILER_BUILTINS_CONTAINERS_STUB_BUILDER_H
#define ECMASCRIPT_COMPILER_BUILTINS_CONTAINERS_STUB_BUILDER_H
#include "ecmascript/compiler/builtins/containers_deque_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_plainarray_stub_builder.h"
#include "ecmascript/compiler/builtins/containers_queue_stub_builder.h"
#include "ecmascript/compiler/builtins/containers_stack_stub_builder.h"
@ -32,6 +34,8 @@ enum class ContainersType : uint8_t {
PLAINARRAY_FOREACH,
QUEUE_FOREACH,
DEQUE_FOREACH,
LIGHTWEIGHTMAP_FOREACH,
LIGHTWEIGHTSET_FOREACH,
};
class ContainersStubBuilder : public BuiltinsStubBuilder {
@ -52,6 +56,9 @@ public:
void DequeCommonFuncCall(GateRef glue, GateRef thisValue, GateRef numArgs,
Variable* result, Label *exit, Label *slowPath, ContainersType type);
void ContainersLightWeightCall(GateRef glue, GateRef thisValue, GateRef numArgs,
Variable* result, Label *exit, Label *slowPath, ContainersType type);
GateRef IsContainer(GateRef obj, ContainersType type)
{
switch (type) {
@ -66,6 +73,10 @@ public:
return IsJSAPIQueue(obj);
case ContainersType::DEQUE_FOREACH:
return IsJSAPIDeque(obj);
case ContainersType::LIGHTWEIGHTMAP_FOREACH:
return IsJSAPILightWeightMap(obj);
case ContainersType::LIGHTWEIGHTSET_FOREACH:
return IsJSAPILightWeightSet(obj);
default:
UNREACHABLE();
}
@ -142,6 +153,14 @@ public:
ContainersDequeStubBuilder dequeBuilder(this);
return dequeBuilder.GetSize(obj);
}
case ContainersType::LIGHTWEIGHTMAP_FOREACH: {
ContainersLightWeightMapStubBuilder lightWeightMapBuilder(this);
return lightWeightMapBuilder.GetSize(obj);
}
case ContainersType::LIGHTWEIGHTSET_FOREACH: {
ContainersLightWeightSetStubBuilder lightWeightSetBuilder(this);
return lightWeightSetBuilder.GetSize(obj);
}
default:
UNREACHABLE();
}
@ -172,11 +191,37 @@ public:
ContainersDequeStubBuilder dequeBuilder(this);
return dequeBuilder.Get(obj, index);
}
case ContainersType::LIGHTWEIGHTMAP_FOREACH: {
ContainersLightWeightMapStubBuilder lightWeightMapBuilder(this);
return lightWeightMapBuilder.GetValue(obj, index);
}
case ContainersType::LIGHTWEIGHTSET_FOREACH: {
ContainersLightWeightSetStubBuilder lightWeightSetBuilder(this);
return lightWeightSetBuilder.GetValue(obj, index);
}
default:
UNREACHABLE();
}
return False();
}
GateRef ContainerGetKey(GateRef obj, GateRef index, ContainersType type)
{
switch (type) {
case ContainersType::LIGHTWEIGHTMAP_FOREACH: {
ContainersLightWeightMapStubBuilder lightWeightMapBuilder(this);
return lightWeightMapBuilder.GetKey(obj, index);
}
case ContainersType::LIGHTWEIGHTSET_FOREACH: {
ContainersLightWeightSetStubBuilder lightWeightSetBuilder(this);
return lightWeightSetBuilder.GetKey(obj, index);
}
default:
UNREACHABLE();
}
return False();
}
GateRef PlainArrayGetKey(GateRef obj, GateRef index)
{
ContainersPlainArrayStubBuilder plainArrayBuilder(this);

View File

@ -1080,6 +1080,18 @@ inline GateRef StubBuilder::IsJSAPIDeque(GateRef obj)
return Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::JS_API_DEQUE)));
}
inline GateRef StubBuilder::IsJSAPILightWeightMap(GateRef obj)
{
GateRef objectType = GetObjectType(LoadHClass(obj));
return Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::JS_API_LIGHT_WEIGHT_MAP)));
}
inline GateRef StubBuilder::IsJSAPILightWeightSet(GateRef obj)
{
GateRef objectType = GetObjectType(LoadHClass(obj));
return Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::JS_API_LIGHT_WEIGHT_SET)));
}
inline GateRef StubBuilder::GetTarget(GateRef proxyObj)
{
GateRef offset = IntPtr(JSProxy::TARGET_OFFSET);

View File

@ -261,6 +261,8 @@ public:
GateRef IsJSAPIPlainArray(GateRef obj);
GateRef IsJSAPIQueue(GateRef obj);
GateRef IsJSAPIDeque(GateRef obj);
GateRef IsJSAPILightWeightMap(GateRef attr);
GateRef IsJSAPILightWeightSet(GateRef attr);
GateRef GetTarget(GateRef proxyObj);
GateRef HandlerBaseIsAccessor(GateRef attr);
GateRef HandlerBaseIsJSArray(GateRef attr);

View File

@ -540,13 +540,12 @@ JSTaggedValue ContainersLightWeightMap::ForEach(EcmaRuntimeCallInfo *argv)
JSHandle<JSAPILightWeightMap> tmap = JSHandle<JSAPILightWeightMap>::Cast(self);
JSMutableHandle<TaggedArray> keys(thread, tmap->GetKeys());
JSMutableHandle<TaggedArray> values(thread, tmap->GetValues());
int elements = tmap->GetSize();
int index = 0;
uint32_t length = keys->GetLength();
int32_t length = tmap->GetSize();
const int32_t argsLength = 3;
JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
while (index < elements) {
while (index < length) {
// ignore the hash value is required to determine the true index
// Let funcResult be Call(callbackfn, T, «e, e, S»).
EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo(thread, func, thisArg, undefined, argsLength);
@ -556,11 +555,10 @@ JSTaggedValue ContainersLightWeightMap::ForEach(EcmaRuntimeCallInfo *argv)
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ret);
// check entries should be update, size will be update in tmap set or remove.
if (tmap->GetLength() != length) {
if (tmap->GetSize() != length) {
keys.Update(tmap->GetKeys());
values.Update(tmap->GetValues());
elements = tmap->GetSize();
length = keys->GetLength();
length = tmap->GetSize();
}
index++;
}

View File

@ -381,7 +381,8 @@ JSHandle<JSTaggedValue> ContainersPrivate::InitializeLightWeightMap(JSThread *th
SetFrozenFunction(thread, funcPrototype, "removeAt", ContainersLightWeightMap::RemoveAt, FuncLength::ONE);
SetFrozenFunction(thread, funcPrototype, "clear", ContainersLightWeightMap::Clear, FuncLength::ONE);
SetFrozenFunction(thread, funcPrototype, "setValueAt", ContainersLightWeightMap::SetValueAt, FuncLength::ONE);
SetFrozenFunction(thread, funcPrototype, "forEach", ContainersLightWeightMap::ForEach, FuncLength::ONE);
SetFrozenFunction(thread, funcPrototype, "forEach", ContainersLightWeightMap::ForEach, FuncLength::ONE,
static_cast<uint8_t>(BUILTINS_STUB_ID(LightWeightMapForEach)));
SetFrozenFunction(thread, funcPrototype, "toString", ContainersLightWeightMap::ToString, FuncLength::ONE);
SetFrozenFunction(thread, funcPrototype, "getValueAt", ContainersLightWeightMap::GetValueAt, FuncLength::ONE);
SetFrozenFunction(thread, funcPrototype, "values", ContainersLightWeightMap::Values, FuncLength::ONE);
@ -441,7 +442,8 @@ JSHandle<JSTaggedValue> ContainersPrivate::InitializeLightWeightSet(JSThread *th
SetFrozenFunction(thread, funcPrototype, "equal", ContainersLightWeightSet::Equal, FuncLength::ONE);
SetFrozenFunction(thread, funcPrototype, "increaseCapacityTo",
ContainersLightWeightSet::IncreaseCapacityTo, FuncLength::ONE);
SetFrozenFunction(thread, funcPrototype, "forEach", ContainersLightWeightSet::ForEach, FuncLength::ONE);
SetFrozenFunction(thread, funcPrototype, "forEach", ContainersLightWeightSet::ForEach, FuncLength::ONE,
static_cast<uint8_t>(BUILTINS_STUB_ID(LightWeightSetForEach)));
SetFrozenFunction(thread, funcPrototype, "getIndexOf", ContainersLightWeightSet::GetIndexOf, FuncLength::ONE);
SetFrozenFunction(thread, funcPrototype, "remove", ContainersLightWeightSet::Remove, FuncLength::ZERO);
SetFrozenFunction(thread, funcPrototype, "removeAt", ContainersLightWeightSet::RemoveAt, FuncLength::ZERO);

View File

@ -329,13 +329,15 @@ JSTaggedValue JSAPILightWeightSet::ForEach(JSThread *thread, const JSHandle<JSTa
JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
for (uint32_t k = 0; k < length; k++) {
JSTaggedValue kValue = lightweightset->GetValueAt(k);
JSTaggedValue kHash = lightweightset->GetHashAt(k);
EcmaRuntimeCallInfo *info =
EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFn, thisArg, undefined, 3); // 3:three args
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
info->SetCallArg(kValue, kHash, thisHandle.GetTaggedValue());
info->SetCallArg(kValue, kValue, thisHandle.GetTaggedValue());
JSTaggedValue funcResult = JSFunction::Call(info);
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, funcResult);
if (lightweightset->GetSize() != length) { // prevent length change
length = lightweightset->GetSize();
}
}
return JSTaggedValue::Undefined();
}