!9788 opt storebyname code gen in jit

Merge pull request !9788 from linxinyq/opt-storebyname-code-gen-in-jit
This commit is contained in:
openharmony_ci 2024-11-07 11:16:05 +00:00 committed by Gitee
commit 9a402ce00a
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
16 changed files with 260 additions and 62 deletions

View File

@ -671,7 +671,7 @@ public:
GateRef MonoStorePropertyLookUpProto(GateRef receiver, GateRef plrGate, GateRef jsFunc, size_t hclassIndex,
GateRef value);
GateRef MonoStoreProperty(GateRef receiver, GateRef plrGate, GateRef jsFunc, size_t hclassIndex,
GateRef value, GateRef keyIndex, GateRef frameState);
GateRef value, GateRef keyIndex, GateRef isProto, GateRef frameState);
GateRef TypedCreateObjWithBuffer(std::vector<GateRef> &valueIn);
template<TypedLoadOp Op>
GateRef ConvertJSArrayHoleAsUndefined(GateRef receiver);

View File

@ -1691,14 +1691,15 @@ GateRef CircuitBuilder::MonoStorePropertyLookUpProto(GateRef receiver, GateRef p
}
GateRef CircuitBuilder::MonoStoreProperty(GateRef receiver, GateRef plrGate, GateRef unsharedConstPool,
size_t hclassIndex, GateRef value, GateRef keyIndex, GateRef frameState)
size_t hclassIndex, GateRef value, GateRef keyIndex, GateRef isProto,
GateRef frameState)
{
auto currentLabel = env_->GetCurrentLabel();
auto currentControl = currentLabel->GetControl();
auto currentDepend = currentLabel->GetDepend();
auto ret = GetCircuit()->NewGate(circuit_->MonoStoreProperty(false), MachineType::I64,
{currentControl, currentDepend, receiver, plrGate, Int32(hclassIndex),
unsharedConstPool, value, keyIndex, frameState},
unsharedConstPool, value, keyIndex, isProto, frameState},
GateType::AnyType());
currentLabel->SetControl(ret);
currentLabel->SetDepend(ret);

View File

@ -212,7 +212,7 @@ namespace panda::ecmascript::kungfu {
#define MCR_GATE_META_DATA_LIST_WITH_BOOL(V) \
V(LoadProperty, LOAD_PROPERTY, GateFlags::NO_WRITE, 1, 1, 2) \
V(MonoStorePropertyLookUpProto, MONO_STORE_PROPERTY_LOOK_UP_PROTO, GateFlags::HAS_FRAME_STATE, 1, 1, 5) \
V(MonoStoreProperty, MONO_STORE_PROPERTY, GateFlags::HAS_FRAME_STATE, 1, 1, 6)
V(MonoStoreProperty, MONO_STORE_PROPERTY, GateFlags::HAS_FRAME_STATE, 1, 1, 7)
#define MCR_GATE_META_DATA_LIST_WITH_GATE_TYPE(V) \
V(PrimitiveTypeCheck, PRIMITIVE_TYPE_CHECK, GateFlags::CHECKABLE, 1, 1, 1) \

View File

@ -1369,6 +1369,7 @@ public:
virtual bool IsHolderEqNewHolder(size_t index) const = 0;
virtual void FetchPGORWTypesDual() = 0;
virtual bool GenerateObjectAccessInfo() = 0;
virtual bool IsPrototypeHclass(size_t index) const = 0;
};
class AotAccessorStrategy : public AccessorStrategy {
@ -1409,6 +1410,17 @@ public:
return std::get<HclassIndex::Holder>(parent_.types_[index]) ==
std::get<HclassIndex::HolderTra>(parent_.types_[index]);
}
bool IsPrototypeHclass(size_t index) const override
{
ProfileTyper recv = std::get<HclassIndex::Reciver>(parent_.types_[index]);
JSTaggedValue hclass = parent_.ptManager_->QueryHClass(recv.first, recv.second);
if (!hclass.IsJSHClass()) {
return false;
}
return JSHClass::Cast(hclass.GetTaggedObject())->IsPrototype();
}
void FetchPGORWTypesDual() override;
bool GenerateObjectAccessInfo() override;
@ -1451,6 +1463,12 @@ public:
{
return parent_.jitTypes_[index].GetHolderHclass() == parent_.jitTypes_[index].GetHolderTraHclass();
}
bool IsPrototypeHclass(size_t index) const override
{
return parent_.jitTypes_[index].GetReceiverHclass()->IsPrototype();
}
void FetchPGORWTypesDual() override;
bool GenerateObjectAccessInfo() override;
@ -1492,6 +1510,11 @@ public:
return strategy_->IsHolderEqNewHolder(index);
}
bool IsPrototypeHclass(size_t index) const
{
return strategy_->IsPrototypeHclass(index);
}
GateRef GetValue() const
{
return value_;

View File

@ -805,7 +805,8 @@ void TypedBytecodeLowering::LowerTypedStObjByName(GateRef gate)
value);
} else {
builder_.MonoStoreProperty(tacc.GetReceiver(), plrGate, unsharedConstPool, holderHClassIndex, value,
builder_.TruncInt64ToInt32(tacc.GetKey()), frameState);
builder_.TruncInt64ToInt32(tacc.GetKey()),
builder_.Boolean(tacc.IsPrototypeHclass(0)), frameState);
}
} else if (tacc.IsReceiverEqHolder(0)) {
BuildNamedPropertyAccess(gate, tacc.GetReceiver(), tacc.GetReceiver(),
@ -829,9 +830,10 @@ void TypedBytecodeLowering::LowerTypedStObjByName(GateRef gate)
}
if (tacc.IsReceiverNoEqNewHolder(i)) {
builder_.ProtoChangeMarkerCheck(tacc.GetReceiver(), frameState);
auto prototype = builder_.LoadConstOffset(VariableType::JS_ANY(), receiverHC, JSHClass::PROTOTYPE_OFFSET);
if (tacc.IsHolderEqNewHolder(i)) {
// lookup from receiver for holder
auto prototype = builder_.LoadConstOffset(VariableType::JS_ANY(), receiverHC,
JSHClass::PROTOTYPE_OFFSET);
auto holderHC = builder_.GetHClassGateFromIndex(gate, tacc.GetAccessInfo(i).HClassIndex());
DEFVALUE(current, (&builder_), VariableType::JS_ANY(), prototype);
Label loopHead(&builder_);
@ -854,52 +856,7 @@ void TypedBytecodeLowering::LowerTypedStObjByName(GateRef gate)
tacc.GetAccessInfo(i).Plr());
builder_.Jump(&exit);
} else {
// transition happened
Label notProto(&builder_);
Label isProto(&builder_);
auto newHolderHC = builder_.GetHClassGateFromIndex(gate, tacc.GetAccessInfo(i).HClassIndex());
builder_.StoreConstOffset(VariableType::JS_ANY(), newHolderHC, JSHClass::PROTOTYPE_OFFSET, prototype);
builder_.Branch(builder_.IsProtoTypeHClass(receiverHC), &isProto, &notProto,
BranchWeight::ONE_WEIGHT, BranchWeight::DEOPT_WEIGHT, "isProtoTypeHClass");
builder_.Bind(&isProto);
GateRef propKey = builder_.GetObjectByIndexFromConstPool(
glue_, gate, frameState, builder_.TruncInt64ToInt32(tacc.GetKey()), ConstPoolType::STRING);
builder_.CallRuntime(glue_, RTSTUB_ID(UpdateAOTHClass), Gate::InvalidGateRef,
{ receiverHC, newHolderHC, propKey }, gate);
builder_.Jump(&notProto);
builder_.Bind(&notProto);
MemoryAttribute mAttr = MemoryAttribute::NeedBarrierAndAtomic();
builder_.StoreConstOffset(VariableType::JS_ANY(), tacc.GetReceiver(),
TaggedObject::HCLASS_OFFSET, newHolderHC, mAttr);
if (!tacc.GetAccessInfo(i).Plr().IsInlinedProps()) {
auto properties = builder_.LoadConstOffset(VariableType::JS_ANY(), tacc.GetReceiver(),
JSObject::PROPERTIES_OFFSET);
auto capacity =
builder_.LoadConstOffset(VariableType::INT32(), properties, TaggedArray::LENGTH_OFFSET);
auto index = builder_.Int32(tacc.GetAccessInfo(i).Plr().GetOffset());
Label needExtend(&builder_);
Label notExtend(&builder_);
BRANCH_CIR(builder_.Int32UnsignedLessThan(index, capacity), &notExtend, &needExtend);
builder_.Bind(&notExtend);
{
BuildNamedPropertyAccess(gate, tacc.GetReceiver(), tacc.GetReceiver(),
tacc.GetValue(), tacc.GetAccessInfo(i).Plr());
builder_.Jump(&exit);
}
builder_.Bind(&needExtend);
{
builder_.CallRuntime(glue_,
RTSTUB_ID(PropertiesSetValue),
Gate::InvalidGateRef,
{ tacc.GetReceiver(), tacc.GetValue(), properties, builder_.Int32ToTaggedInt(capacity),
builder_.Int32ToTaggedInt(index) }, gate);
builder_.Jump(&exit);
}
} else {
BuildNamedPropertyAccess(gate, tacc.GetReceiver(), tacc.GetReceiver(),
tacc.GetValue(), tacc.GetAccessInfo(i).Plr());
builder_.Jump(&exit);
}
TypedStObjByNameTransition(gate, receiverHC, frameState, exit, tacc, i);
}
} else if (tacc.IsReceiverEqHolder(i)) {
// Local
@ -921,6 +878,58 @@ void TypedBytecodeLowering::LowerTypedStObjByName(GateRef gate)
DeleteConstDataIfNoUser(tacc.GetKey());
}
void TypedBytecodeLowering::TypedStObjByNameTransition(GateRef gate, GateRef receiverHC, GateRef frameState,
Label &exit, StoreObjByNameTypeInfoAccessor &tacc, size_t i)
{
Label notProto(&builder_);
Label isProto(&builder_);
auto newHolderHC = builder_.GetHClassGateFromIndex(gate, tacc.GetAccessInfo(i).HClassIndex());
if (compilationEnv_->IsAotCompiler()) {
auto prototype = builder_.LoadConstOffset(VariableType::JS_ANY(), receiverHC, JSHClass::PROTOTYPE_OFFSET);
builder_.StoreConstOffset(VariableType::JS_ANY(), newHolderHC, JSHClass::PROTOTYPE_OFFSET, prototype);
}
if (!tacc.IsPrototypeHclass(i)) {
builder_.DeoptCheck(builder_.BoolNot(builder_.IsProtoTypeHClass(receiverHC)), frameState,
DeoptType::PROTOTYPECHANGED2);
} else {
builder_.Branch(builder_.IsProtoTypeHClass(receiverHC), &isProto, &notProto,
BranchWeight::ONE_WEIGHT, BranchWeight::DEOPT_WEIGHT, "isProtoTypeHClass");
builder_.Bind(&isProto);
GateRef propKey =
builder_.GetObjectByIndexFromConstPool(glue_, gate, frameState,
builder_.TruncInt64ToInt32(tacc.GetKey()), ConstPoolType::STRING);
builder_.CallRuntime(glue_, RTSTUB_ID(UpdateAOTHClass), Gate::InvalidGateRef,
{ receiverHC, newHolderHC, propKey }, gate);
builder_.Jump(&notProto);
builder_.Bind(&notProto);
}
MemoryAttribute mAttr = MemoryAttribute::NeedBarrierAndAtomic();
builder_.StoreConstOffset(VariableType::JS_ANY(), tacc.GetReceiver(), TaggedObject::HCLASS_OFFSET,
newHolderHC, mAttr);
if (!tacc.GetAccessInfo(i).Plr().IsInlinedProps()) {
auto properties = builder_.LoadConstOffset(VariableType::JS_ANY(), tacc.GetReceiver(),
JSObject::PROPERTIES_OFFSET);
auto capacity = builder_.LoadConstOffset(VariableType::INT32(), properties, TaggedArray::LENGTH_OFFSET);
auto index = builder_.Int32(tacc.GetAccessInfo(i).Plr().GetOffset());
Label needExtend(&builder_);
Label notExtend(&builder_);
BRANCH_CIR(builder_.Int32UnsignedLessThan(index, capacity), &notExtend, &needExtend);
builder_.Bind(&notExtend);
BuildNamedPropertyAccess(gate, tacc.GetReceiver(), tacc.GetReceiver(), tacc.GetValue(),
tacc.GetAccessInfo(i).Plr());
builder_.Jump(&exit);
builder_.Bind(&needExtend);
builder_.CallRuntime(glue_, RTSTUB_ID(PropertiesSetValue), Gate::InvalidGateRef,
{ tacc.GetReceiver(), tacc.GetValue(), properties, builder_.Int32ToTaggedInt(capacity),
builder_.Int32ToTaggedInt(index) }, gate);
builder_.Jump(&exit);
} else {
BuildNamedPropertyAccess(gate, tacc.GetReceiver(), tacc.GetReceiver(), tacc.GetValue(),
tacc.GetAccessInfo(i).Plr());
builder_.Jump(&exit);
}
}
void TypedBytecodeLowering::LowerTypedStOwnByName(GateRef gate)
{
LowerTypedStObjByName(gate);

View File

@ -124,6 +124,8 @@ private:
void LowerTypedLdPrivateProperty(GateRef gate);
void LowerTypedLdObjByName(GateRef gate);
void LowerTypedStObjByName(GateRef gate);
void TypedStObjByNameTransition(GateRef gate, GateRef receiverHC, GateRef frameState,
Label &exit, StoreObjByNameTypeInfoAccessor &tacc, size_t i);
void LowerTypedStOwnByName(GateRef gate);
GateRef BuildNamedPropertyAccess(GateRef hir, GateRef receiver, GateRef holder, PropertyLookupResult plr);
GateRef BuildNamedPropertyAccess(GateRef hir, GateRef receiver, GateRef holder,

View File

@ -2813,25 +2813,34 @@ void TypedHCRLowering::LowerMonoStoreProperty(GateRef gate, GateRef glue)
GateRef unsharedConstPool = acc_.GetValueIn(gate, 3); // 3: constPool
GateRef value = acc_.GetValueIn(gate, 4); // 4: value
GateRef keyIndex = acc_.GetValueIn(gate, 5); // 5: keyIndex
bool isPrototype = acc_.TryGetValue(acc_.GetValueIn(gate, 6)); // 6: proto flag Index
PropertyLookupResult plr(acc_.TryGetValue(propertyLookupResult));
bool noBarrier = acc_.IsNoBarrier(gate);
auto receiverHC = builder_.LoadConstOffset(VariableType::JS_POINTER(), receiver, TaggedObject::HCLASS_OFFSET);
auto prototype = builder_.LoadConstOffset(VariableType::JS_ANY(), receiverHC, JSHClass::PROTOTYPE_OFFSET);
// transition happened
Label exit(&builder_);
Label notProto(&builder_);
Label isProto(&builder_);
auto newHolderHC = builder_.LoadHClassFromConstpool(unsharedConstPool, acc_.GetConstantValue(hclassIndex));
builder_.StoreConstOffset(VariableType::JS_ANY(), newHolderHC, JSHClass::PROTOTYPE_OFFSET, prototype);
builder_.Branch(builder_.IsProtoTypeHClass(receiverHC), &isProto, &notProto,
BranchWeight::ONE_WEIGHT, BranchWeight::DEOPT_WEIGHT, "isProtoTypeHClass");
builder_.Bind(&isProto);
if (compilationEnv_->IsAotCompiler()) {
auto prototype = builder_.LoadConstOffset(VariableType::JS_ANY(), receiverHC, JSHClass::PROTOTYPE_OFFSET);
builder_.StoreConstOffset(VariableType::JS_ANY(), newHolderHC, JSHClass::PROTOTYPE_OFFSET, prototype);
}
if (!isPrototype) {
builder_.DeoptCheck(builder_.BoolNot(builder_.IsProtoTypeHClass(receiverHC)), frameState,
DeoptType::PROTOTYPECHANGED2);
} else {
builder_.Branch(builder_.IsProtoTypeHClass(receiverHC), &isProto, &notProto,
BranchWeight::ONE_WEIGHT, BranchWeight::DEOPT_WEIGHT, "isProtoTypeHClass");
builder_.Bind(&isProto);
GateRef propKey = builder_.GetObjectByIndexFromConstPool(glue, gate, frameState, keyIndex, ConstPoolType::STRING);
builder_.CallRuntime(glue, RTSTUB_ID(UpdateAOTHClass), Gate::InvalidGateRef,
{ receiverHC, newHolderHC, propKey }, gate);
builder_.Jump(&notProto);
builder_.Bind(&notProto);
GateRef propKey =
builder_.GetObjectByIndexFromConstPool(glue, gate, frameState, keyIndex, ConstPoolType::STRING);
builder_.CallRuntime(glue, RTSTUB_ID(UpdateAOTHClass), Gate::InvalidGateRef,
{ receiverHC, newHolderHC, propKey }, gate);
builder_.Jump(&notProto);
builder_.Bind(&notProto);
}
MemoryAttribute mAttr = MemoryAttribute::NeedBarrierAndAtomic();
builder_.StoreConstOffset(VariableType::JS_ANY(), receiver, TaggedObject::HCLASS_OFFSET, newHolderHC, mAttr);
if (!plr.IsInlinedProps()) {

View File

@ -285,6 +285,7 @@ group("ark_aot_ts_test") {
"stlettoglobalrecord",
"stobjbyindex",
"stobjbyname",
"stobjbyname1",
"stobjbyvalue",
"stownbyindex",
"stownbyname",

View File

@ -0,0 +1,22 @@
# 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.
import("//arkcompiler/ets_runtime/test/test_helper.gni")
host_aot_test_action("stobjbyname1") {
deps = []
is_only_typed_path = true
is_enable_pgo = true
is_enable_trace_deopt = true
log_option = " --log-info=trace"
}

View File

@ -0,0 +1,15 @@
# 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.
true
[trace] Check Type: InconsistentHClass6

View File

@ -0,0 +1,14 @@
# 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.
false

View File

@ -0,0 +1,35 @@
/*
* 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.
*/
function A() {
this.a = 0;
this.b = 2;
}
function test(a) {
a.c = 9
}
test(new A());
if (ArkTools.isAOTCompiled(test)) {
print(true);
let a = new A();
function B() {}
B.prototype = a;
test(a);
} else {
print(false);
}

View File

@ -31,6 +31,7 @@ group("ark_jit_ts_test") {
"addition_assignment",
"catch_with_osr",
"jit_test_0001",
"jit_test_0002",
"string_length",
"ts_inline",
"proxy_fast_call",

View File

@ -0,0 +1,19 @@
# Copyright (c) 2024 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.
import("//arkcompiler/ets_runtime/test/test_helper.gni")
host_jit_test_action("jit_test_0002") {
deps = []
extra_option = " --log-info=trace --compiler-trace-deopt=true "
}

View File

@ -0,0 +1,14 @@
# Copyright (c) 2024 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.
[trace] Check Type: InconsistentHClass6

View File

@ -0,0 +1,33 @@
/*
* Copyright (c) 2024 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.
*/
function A() {
this.a = 0;
this.b = 2;
}
function test(a) {
a.c = 9
}
test(new A());
ArkTools.jitCompileAsync(test);
ArkTools.waitJitCompileFinish(test);
let a = new A();
function B() {}
B.prototype = a;
test(a);