Support loop hoist for TryLdGlobalByName

Issue: https://gitee.com/open_harmony/dashboard?issue_id=I8RSIT
Signed-off-by: weng-xi <wengxi1@huawei.com>
Change-Id: If784f048754bf1d92e586de2fce035274ff4f646
This commit is contained in:
weng-xi 2023-12-27 22:12:51 +08:00
parent d6bd761bff
commit 47157ac405
40 changed files with 1161 additions and 130 deletions

View File

@ -111,7 +111,7 @@ public:
BuiltinIndex(const BuiltinIndex&) = delete;
BuiltinIndex& operator=(const BuiltinIndex&) = delete;
static const int32_t NOT_FOUND = -1;
static const size_t NOT_FOUND = -1;
static BuiltinIndex& GetInstance()
{
@ -126,20 +126,25 @@ public:
return sizeof(JSTaggedValue) * (index * 2); // 2 is size of BuiltinEntries
}
int32_t GetBuiltinIndex(JSTaggedValue key) const
size_t GetBuiltinBoxOffset(size_t index)
{
return sizeof(JSTaggedValue) * (index * 2); // 2 is size of BuiltinEntries
}
size_t GetBuiltinIndex(JSTaggedValue key) const
{
auto ecmaString = EcmaString::Cast(key.GetTaggedObject());
auto str = std::string(ConvertToString(ecmaString));
return GetBuiltinIndex(str);
}
int32_t GetBuiltinIndex(const std::string& key) const
size_t GetBuiltinIndex(const std::string& key) const
{
auto it = builtinIndex_.find(key);
if (it == builtinIndex_.end()) {
return NOT_FOUND;
} else {
return static_cast<int32_t>(it->second);
return static_cast<size_t>(it->second);
}
}
@ -216,4 +221,4 @@ private:
BuiltinIndex() {}
}; // class BuiltinIndex
} // namespace panda::ecmascript
#endif // ECMASCRIPT_BUILTIN_ENTRIES_H
#endif // ECMASCRIPT_BUILTIN_ENTRIES_H

View File

@ -364,6 +364,17 @@ JSTaggedValue BuiltinsArkTools::IsAOTDeoptimized(EcmaRuntimeCallInfo *info)
return JSTaggedValue(false);
}
JSTaggedValue BuiltinsArkTools::PrintLoopHoistProfilerAndReset(EcmaRuntimeCallInfo *info)
{
ASSERT(info);
JSThread *thread = info->GetThread();
LoopHoistProfiler *profiler = thread->GetCurrentEcmaContext()->GetLoopHoistProfiler();
if (profiler != nullptr) {
profiler->PrintAndReset();
}
return JSTaggedValue::Undefined();
}
JSTaggedValue BuiltinsArkTools::GetElementsKind(EcmaRuntimeCallInfo *info)
{
ASSERT(info);

View File

@ -24,27 +24,28 @@
// where BuiltinsArkTools::func refers to the native implementation of ArkTools[name].
// kungfu::BuiltinsStubCSigns::stubIndex refers to the builtin stub index, or INVALID if no stub available.
#define BUILTIN_ARK_TOOLS_FUNCTIONS_COMMON(V) \
V("compareHClass", CompareHClass, 2, INVALID) \
V("dumpHClass", DumpHClass, 1, INVALID) \
V("excutePendingJob", ExcutePendingJob, 0, INVALID) \
V("forceFullGC", ForceFullGC, 0, INVALID) \
V("getHClass", GetHClass, 1, INVALID) \
V("getLexicalEnv", GetLexicalEnv, 1, INVALID) \
V("hasTSSubtyping", HasTSSubtyping, 1, INVALID) \
V("hiddenStackSourceFile", HiddenStackSourceFile, 0, INVALID) \
V("hintGC", HintGC, 0, INVALID) \
V("isNotHoleProperty", IsNotHoleProperty, 2, INVALID) \
V("isPrototype", IsPrototype, 1, INVALID) \
V("isRegExpReplaceDetectorValid", IsRegExpReplaceDetectorValid, 0, INVALID) \
V("isSymbolIteratorDetectorValid", IsSymbolIteratorDetectorValid, 1, INVALID) \
V("isTSHClass", IsTSHClass, 1, INVALID) \
V("pgoAssertType", PGOAssertType, 2, INVALID) \
V("print", ObjectDump, 0, INVALID) \
V("removeAOTFlag", RemoveAOTFlag, 1, INVALID) \
V("timeInUs", TimeInUs, 0, INVALID) \
V("getElementsKind", GetElementsKind, 1, INVALID) \
V("isAOTCompiled", IsAOTCompiled, 1, INVALID) \
V("isAOTDeoptimized", IsAOTDeoptimized, 1, INVALID)
V("compareHClass", CompareHClass, 2, INVALID) \
V("dumpHClass", DumpHClass, 1, INVALID) \
V("excutePendingJob", ExcutePendingJob, 0, INVALID) \
V("forceFullGC", ForceFullGC, 0, INVALID) \
V("getHClass", GetHClass, 1, INVALID) \
V("getLexicalEnv", GetLexicalEnv, 1, INVALID) \
V("hasTSSubtyping", HasTSSubtyping, 1, INVALID) \
V("hiddenStackSourceFile", HiddenStackSourceFile, 0, INVALID) \
V("hintGC", HintGC, 0, INVALID) \
V("isNotHoleProperty", IsNotHoleProperty, 2, INVALID) \
V("isPrototype", IsPrototype, 1, INVALID) \
V("isRegExpReplaceDetectorValid", IsRegExpReplaceDetectorValid, 0, INVALID) \
V("isSymbolIteratorDetectorValid", IsSymbolIteratorDetectorValid, 1, INVALID) \
V("isTSHClass", IsTSHClass, 1, INVALID) \
V("pgoAssertType", PGOAssertType, 2, INVALID) \
V("print", ObjectDump, 0, INVALID) \
V("removeAOTFlag", RemoveAOTFlag, 1, INVALID) \
V("timeInUs", TimeInUs, 0, INVALID) \
V("getElementsKind", GetElementsKind, 1, INVALID) \
V("isAOTCompiled", IsAOTCompiled, 1, INVALID) \
V("isAOTDeoptimized", IsAOTDeoptimized, 1, INVALID) \
V("printLoopHoistProfilerAndReset", PrintLoopHoistProfilerAndReset, 0, INVALID)
#define BUILTIN_ARK_TOOLS_FUNCTIONS_REGRESS(V) \
V("prepareFunctionForOptimization", PrepareFunctionForOptimization, 1, INVALID) \
@ -182,6 +183,8 @@ public:
// ArkTools.GetElementsKind(array)
static JSTaggedValue GetElementsKind(EcmaRuntimeCallInfo *info);
static JSTaggedValue PrintLoopHoistProfilerAndReset(EcmaRuntimeCallInfo *info);
static JSTaggedValue IsRegExpReplaceDetectorValid(EcmaRuntimeCallInfo *info);
static JSTaggedValue IsSymbolIteratorDetectorValid(EcmaRuntimeCallInfo *info);
@ -271,7 +274,7 @@ public:
static JSTaggedValue HasOwnConstDataProperty(EcmaRuntimeCallInfo *info);
static JSTaggedValue GetHoleNaNUpper(EcmaRuntimeCallInfo *info);
static JSTaggedValue GetHoleNaNLower(EcmaRuntimeCallInfo *info);
static JSTaggedValue SystemBreak(EcmaRuntimeCallInfo *info);
@ -289,7 +292,7 @@ public:
static JSTaggedValue SetKeyedProperty(EcmaRuntimeCallInfo *info);
static JSTaggedValue DisassembleFunction(EcmaRuntimeCallInfo *info);
static JSTaggedValue TryMigrateInstance(EcmaRuntimeCallInfo *info);
static JSTaggedValue InLargeObjectSpace(EcmaRuntimeCallInfo *info);

View File

@ -442,7 +442,7 @@ public:
// ************************************************************* Middle IR **********************************************************************************
GateRef HeapObjectCheck(GateRef gate, GateRef frameState);
GateRef ProtoChangeMarkerCheck(GateRef gate, GateRef frameState);
GateRef ProtoChangeMarkerCheck(GateRef gate);
GateRef StableArrayCheck(GateRef gate, ElementsKind kind, ArrayMetaDataAccessor::Mode mode);
GateRef COWArrayCheck(GateRef gate);
GateRef EcmaStringCheck(GateRef gate);
@ -569,6 +569,12 @@ public:
GateRef IsSpecificObjectType(GateRef obj, JSType type);
GateRef IsMarkerCellValid(GateRef cell);
GateRef IsMarkerCellValidOp(GateRef cell);
GateRef MonoLoadPropertyOnProto(GateRef receiver, GateRef plrGate, GateRef jsFunc, size_t hclassIndex);
GateRef MonoCallGetterOnProto(GateRef gate, GateRef receiver, GateRef plrGate, GateRef jsFunc, size_t hclassIndex);
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 key);
// bit operation
inline GateRef TaggedIsInt(GateRef x);

View File

@ -32,6 +32,7 @@ public:
profiling_ = options->GetOptCodeProfiler();
stressDeopt_ = options->GetStressDeopt();
verifyVTable_ = options->GetVerifyVTable();
loopHoistProfiling_ = options->GetLoopHoistProfiler();
}
}
~CompilationConfig() = default;
@ -86,6 +87,11 @@ public:
return verifyVTable_;
}
bool IsLoopHoistProfiling() const
{
return loopHoistProfiling_;
}
private:
inline Triple GetTripleFromString(const std::string &triple)
{
@ -109,6 +115,7 @@ private:
bool profiling_ {false};
bool stressDeopt_ {false};
bool verifyVTable_ {false};
bool loopHoistProfiling_ {false};
};
class Label {
@ -459,4 +466,4 @@ private:
}
#endif // ECMASCRIPT_COMPILER_CIRCUIT_BUILDER_H
#endif // ECMASCRIPT_COMPILER_CIRCUIT_BUILDER_H

View File

@ -89,6 +89,9 @@ GateRef EarlyElimination::VisitGate(GateRef gate)
case OpCode::TYPE_OF_CHECK:
case OpCode::ARRAY_CONSTRUCTOR_CHECK:
case OpCode::OBJECT_CONSTRUCTOR_CHECK:
case OpCode::PROTO_CHANGE_MARKER_CHECK:
case OpCode::MONO_LOAD_PROPERTY_ON_PROTO:
case OpCode::LOAD_BUILTIN_OBJECT:
return TryEliminateGate(gate);
case OpCode::STATE_SPLIT:
return TryEliminateFrameState(gate);
@ -232,6 +235,8 @@ DependInfoNode* EarlyElimination::UpdateWrite(GateRef gate, DependInfoNode* depe
case OpCode::STORE_CONST_OFFSET:
case OpCode::STORE_ELEMENT:
case OpCode::STORE_MEMORY:
case OpCode::MONO_STORE_PROPERTY_LOOK_UP_PROTO:
case OpCode::MONO_STORE_PROPERTY:
return dependInfo->UpdateStoreProperty(this, gate);
default:
return new (chunk_) DependInfoNode(chunk_);
@ -273,6 +278,12 @@ bool EarlyElimination::MayAccessOneMemory(GateRef lhs, GateRef rhs)
}
break;
}
case OpCode::LOAD_PROPERTY:
case OpCode::MONO_LOAD_PROPERTY_ON_PROTO:
if (acc_.GetGateType(lhs).Value() != acc_.GetGateType(rhs).Value()) {
return false;
}
break;
default:
break;
}
@ -378,6 +389,12 @@ bool EarlyElimination::CheckReplacement(GateRef lhs, GateRef rhs)
}
break;
}
case OpCode::LOAD_BUILTIN_OBJECT: {
if (acc_.GetIndex(lhs) != acc_.GetIndex(rhs)) {
return false;
}
break;
}
default:
break;
}

View File

@ -1857,4 +1857,20 @@ bool GateAccessor::IsCreateArray(GateRef gate) const
UNREACHABLE();
return false;
}
void GateAccessor::SetStoreNoBarrier(GateRef gate, bool isNoBarrier)
{
ASSERT(GetOpCode(gate) == OpCode::MONO_STORE_PROPERTY_LOOK_UP_PROTO ||
GetOpCode(gate) == OpCode::MONO_STORE_PROPERTY);
Gate *gatePtr = circuit_->LoadGatePtr(gate);
const_cast<BoolMetaData *>(gatePtr->GetBoolMetaData())->SetBool(isNoBarrier);
}
bool GateAccessor::IsNoBarrier(GateRef gate) const
{
ASSERT(GetOpCode(gate) == OpCode::MONO_STORE_PROPERTY_LOOK_UP_PROTO ||
GetOpCode(gate) == OpCode::MONO_STORE_PROPERTY);
Gate *gatePtr = circuit_->LoadGatePtr(gate);
return gatePtr->GetBoolMetaData()->GetBool();
}
} // namespace panda::ecmascript::kungfu

View File

@ -603,6 +603,8 @@ public:
bool IsLoopBackUse(GateRef gate, const UseIterator &useIt) const;
void GetOutStates(GateRef gate, std::vector<GateRef>& outStates) const;
bool IsCreateArray(GateRef gate) const;
void SetStoreNoBarrier(GateRef gate, bool isNoBarrier);
bool IsNoBarrier(GateRef gate) const;
private:
const GateMetaData *GetMetaData(GateRef gate) const;

View File

@ -41,9 +41,10 @@ namespace panda::ecmascript::kungfu {
#define HCR_GATE_META_DATA_LIST_WITH_PC_OFFSET(V) \
V(Construct, CONSTRUCT, GateFlags::HAS_FRAME_STATE, 1, 1, value)
#define HCR_GATE_META_DATA_LIST_WITH_PC_OFFSET_FIXED_VALUE(V) \
V(CallGetter, CALL_GETTER, GateFlags::HAS_FRAME_STATE, 1, 1, 3) \
V(CallSetter, CALL_SETTER, GateFlags::HAS_FRAME_STATE, 1, 1, 4)
#define HCR_GATE_META_DATA_LIST_WITH_PC_OFFSET_FIXED_VALUE(V) \
V(CallGetter, CALL_GETTER, GateFlags::HAS_FRAME_STATE, 1, 1, 3) \
V(CallSetter, CALL_SETTER, GateFlags::HAS_FRAME_STATE, 1, 1, 4) \
V(MonoCallGetterOnProto, MONO_CALL_GETTER_ON_PROTO, GateFlags::HAS_FRAME_STATE, 1, 1, 4)
#define HCR_GATE_META_DATA_LIST_WITH_VALUE(V) \
V(CreateArray, CREATE_ARRAY, GateFlags::NONE_FLAG, 1, 1, 1) \

View File

@ -67,11 +67,12 @@ GateRef CircuitBuilder::HeapObjectCheck(GateRef gate, GateRef frameState)
return ret;
}
GateRef CircuitBuilder::ProtoChangeMarkerCheck(GateRef gate, GateRef frameState)
GateRef CircuitBuilder::ProtoChangeMarkerCheck(GateRef gate)
{
auto currentLabel = env_->GetCurrentLabel();
auto currentControl = currentLabel->GetControl();
auto currentDepend = currentLabel->GetDepend();
auto frameState = acc_.FindNearestFrameState(currentDepend);
GateRef ret = GetCircuit()->NewGate(circuit_->ProtoChangeMarkerCheck(),
MachineType::I1,
{currentControl, currentDepend, gate, frameState},
@ -1241,4 +1242,70 @@ GateRef CircuitBuilder::ObjectConstructorCheck(GateRef gate)
currentLabel->SetDepend(ret);
return ret;
}
GateRef CircuitBuilder::MonoLoadPropertyOnProto(GateRef receiver, GateRef plrGate, GateRef jsFunc, size_t hclassIndex)
{
auto currentLabel = env_->GetCurrentLabel();
auto currentControl = currentLabel->GetControl();
auto currentDepend = currentLabel->GetDepend();
auto frameState = acc_.FindNearestFrameState(currentDepend);
auto ret = GetCircuit()->NewGate(circuit_->MonoLoadPropertyOnProto(), MachineType::I64,
{ currentControl, currentDepend, receiver, plrGate, Int32(hclassIndex), jsFunc,
frameState },
GateType::AnyType());
currentLabel->SetControl(ret);
currentLabel->SetDepend(ret);
return ret;
}
GateRef CircuitBuilder::MonoCallGetterOnProto(GateRef gate, GateRef receiver, GateRef plrGate, GateRef jsFunc,
size_t hclassIndex)
{
uint64_t pcOffset = acc_.TryGetPcOffset(gate);
ASSERT(pcOffset != 0);
auto currentLabel = env_->GetCurrentLabel();
auto currentControl = currentLabel->GetControl();
auto currentDepend = currentLabel->GetDepend();
auto frameState = acc_.FindNearestFrameState(currentDepend);
std::vector<GateRef> args = { currentControl, currentDepend, receiver, plrGate, Int32(hclassIndex), jsFunc,
frameState };
auto callGate = GetCircuit()->NewGate(circuit_->MonoCallGetterOnProto(pcOffset),
MachineType::I64,
args.size(),
args.data(),
GateType::AnyType());
currentLabel->SetControl(callGate);
currentLabel->SetDepend(callGate);
return callGate;
}
GateRef CircuitBuilder::MonoStorePropertyLookUpProto(GateRef receiver, GateRef plrGate, GateRef jsFunc,
size_t hclassIndex, GateRef value)
{
auto currentLabel = env_->GetCurrentLabel();
auto currentControl = currentLabel->GetControl();
auto currentDepend = currentLabel->GetDepend();
auto frameState = acc_.FindNearestFrameState(currentDepend);
auto ret = GetCircuit()->NewGate(circuit_->MonoStorePropertyLookUpProto(false), MachineType::I64,
{ currentControl, currentDepend, receiver, plrGate, Int32(hclassIndex), jsFunc, value, frameState},
GateType::AnyType());
currentLabel->SetControl(ret);
currentLabel->SetDepend(ret);
return ret;
}
GateRef CircuitBuilder::MonoStoreProperty(GateRef receiver, GateRef plrGate, GateRef jsFunc, size_t hclassIndex,
GateRef value, GateRef key)
{
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), jsFunc, value, key },
GateType::AnyType());
currentLabel->SetControl(ret);
currentLabel->SetDepend(ret);
return ret;
}
}

View File

@ -42,9 +42,6 @@ GateRef MCRLowering::VisitGate(GateRef gate)
case OpCode::HEAP_OBJECT_CHECK:
LowerHeapObjectCheck(gate);
break;
case OpCode::PROTO_CHANGE_MARKER_CHECK:
LowerProtoChangeMarkerCheck(gate);
break;
case OpCode::LOAD_CONST_OFFSET:
LowerLoadConstOffset(gate);
break;
@ -179,20 +176,6 @@ void MCRLowering::LowerHeapObjectCheck(GateRef gate)
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
}
void MCRLowering::LowerProtoChangeMarkerCheck(GateRef gate)
{
Environment env(gate, circuit_, &builder_);
GateRef frameState = acc_.GetFrameState(gate);
GateRef marker = acc_.GetValueIn(gate, 0);
builder_.DeoptCheck(builder_.TaggedIsNotNull(marker), frameState, DeoptType::PROTOTYPECHANGED);
auto hasChanged = builder_.GetHasChanged(marker);
builder_.DeoptCheck(builder_.BoolNot(hasChanged), frameState,
DeoptType::PROTOTYPECHANGED);
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
}
void MCRLowering::LowerTaggedIsHeapObject(GateRef gate)
{
Environment env(gate, circuit_, &builder_);

View File

@ -39,7 +39,6 @@ private:
void DeleteStateSplit(GateRef gate);
void LowerArrayGuardianCheck(GateRef gate);
void LowerHeapObjectCheck(GateRef gate);
void LowerProtoChangeMarkerCheck(GateRef gate);
void LowerTaggedIsHeapObject(GateRef gate);
void LowerIsMarkerCellValid(GateRef gate);
void LowerIsSpecificObjectType(GateRef gate);

View File

@ -54,6 +54,7 @@ namespace panda::ecmascript::kungfu {
V(ArrayConstructorCheck, ARRAY_CONSTRUCTOR_CHECK, GateFlags::CHECKABLE, 1, 1, 1) \
V(ObjectConstructorCheck, OBJECT_CONSTRUCTOR_CHECK, GateFlags::CHECKABLE, 1, 1, 1) \
V(IndexCheck, INDEX_CHECK, GateFlags::CHECKABLE, 1, 1, 2) \
V(MonoLoadPropertyOnProto, MONO_LOAD_PROPERTY_ON_PROTO, GateFlags::CHECKABLE, 1, 1, 4) \
MCR_BINARY_GATE_META_DATA_CACHE_LIST(V)
#define MCR_GATE_META_DATA_LIST_WITH_PC_OFFSET(V) \
@ -84,8 +85,10 @@ namespace panda::ecmascript::kungfu {
V(IsSpecificObjectType, IS_SPECIFIC_OBJECT_TYPE, GateFlags::NO_WRITE, 1, 1, 1) \
V(LoadBuiltinObject, LOAD_BUILTIN_OBJECT, GateFlags::CHECKABLE, 1, 1, 0)
#define MCR_GATE_META_DATA_LIST_WITH_BOOL(V) \
V(LoadProperty, LOAD_PROPERTY, GateFlags::NO_WRITE, 1, 1, 2)
#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::NONE_FLAG, 1, 1, 6)
#define MCR_GATE_META_DATA_LIST_WITH_GATE_TYPE(V) \
V(PrimitiveTypeCheck, PRIMITIVE_TYPE_CHECK, GateFlags::CHECKABLE, 1, 1, 1) \

View File

@ -102,6 +102,10 @@ void NumberSpeculativeLowering::VisitGate(GateRef gate)
VisitLoadProperty(gate);
break;
}
case OpCode::MONO_LOAD_PROPERTY_ON_PROTO: {
VisitLoadPropertyOnProto(gate);
break;
}
default:
break;
}
@ -972,4 +976,68 @@ void NumberSpeculativeLowering::VisitStringAdd(GateRef gate)
acc_.SetGateType(gate, GateType::NJSValue());
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
}
void NumberSpeculativeLowering::VisitLoadPropertyOnProto(GateRef gate)
{
TypeInfo output = GetOutputType(gate);
if (output == TypeInfo::INT32 || output == TypeInfo::FLOAT64) {
Environment env(gate, circuit_, &builder_);
GateRef frameState = acc_.GetFrameState(gate);
GateRef receiver = acc_.GetValueIn(gate, 0);
GateRef propertyLookupResult = acc_.GetValueIn(gate, 1); // 1: propertyLookupResult
GateRef hclassIndex = acc_.GetValueIn(gate, 2); // 2: hclassIndex
GateRef jsFunc = acc_.GetValueIn(gate, 3); // 3: jsFunc
PropertyLookupResult plr(acc_.TryGetValue(propertyLookupResult));
GateRef result = Circuit::NullGate();
ASSERT(plr.IsLocal() || plr.IsFunction());
auto receiverHC = builder_.LoadConstOffset(VariableType::JS_POINTER(), receiver, TaggedObject::HCLASS_OFFSET);
auto prototype = builder_.LoadConstOffset(VariableType::JS_ANY(), receiverHC, JSHClass::PROTOTYPE_OFFSET);
GateRef constPool = builder_.GetConstPool(jsFunc);
auto holderHC = builder_.LoadHClassFromConstpool(constPool, acc_.GetConstantValue(hclassIndex));
DEFVALUE(current, (&builder_), VariableType::JS_ANY(), prototype);
Label exit(&builder_);
Label loopHead(&builder_);
Label loadHolder(&builder_);
Label lookUpProto(&builder_);
builder_.Jump(&loopHead);
builder_.LoopBegin(&loopHead);
builder_.DeoptCheck(builder_.TaggedIsNotNull(*current), frameState, DeoptType::INCONSISTENTHCLASS);
auto curHC = builder_.LoadConstOffset(VariableType::JS_POINTER(), *current, TaggedObject::HCLASS_OFFSET);
builder_.Branch(builder_.Equal(curHC, holderHC), &loadHolder, &lookUpProto);
builder_.Bind(&lookUpProto);
current = builder_.LoadConstOffset(VariableType::JS_ANY(), curHC, JSHClass::PROTOTYPE_OFFSET);
builder_.LoopEnd(&loopHead);
builder_.Bind(&loadHolder);
if (output == TypeInfo::FLOAT64) {
if (plr.IsInlinedProps()) {
result = builder_.LoadConstOffset(VariableType::FLOAT64(), *current, plr.GetOffset());
} else {
auto properties =
builder_.LoadConstOffset(VariableType::JS_ANY(), *current, JSObject::PROPERTIES_OFFSET);
result = builder_.GetValueFromTaggedArray(
VariableType::FLOAT64(), properties, builder_.Int32(plr.GetOffset()));
}
acc_.SetMachineType(gate, MachineType::F64);
} else {
if (plr.IsInlinedProps()) {
result = builder_.LoadConstOffset(VariableType::INT32(), *current, plr.GetOffset());
} else {
auto properties =
builder_.LoadConstOffset(VariableType::JS_ANY(), *current, JSObject::PROPERTIES_OFFSET);
result = builder_.GetValueFromTaggedArray(
VariableType::INT32(), properties, builder_.Int32(plr.GetOffset()));
}
acc_.SetMachineType(gate, MachineType::I32);
}
builder_.Jump(&exit);
builder_.Bind(&exit);
acc_.SetGateType(gate, GateType::NJSValue());
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
}
}
} // namespace panda::ecmascript

View File

@ -54,6 +54,7 @@ private:
void VisitLoadStringLength(GateRef gate);
void VisitLoadElement(GateRef gate);
void VisitLoadProperty(GateRef gate);
void VisitLoadPropertyOnProto(GateRef gate);
template<TypedBinOp Op>
void VisitNumberCalculate(GateRef gate);

View File

@ -104,6 +104,13 @@ GateRef NumberSpeculativeRetype::VisitGate(GateRef gate)
return VisitStoreProperty(gate);
case OpCode::LOAD_PROPERTY:
return VisitLoadProperty(gate);
case OpCode::MONO_LOAD_PROPERTY_ON_PROTO:
return VisitMonoLoadPropertyOnProto(gate);
case OpCode::MONO_CALL_GETTER_ON_PROTO:
return VisitMonoCallGetterOnProto(gate);
case OpCode::MONO_STORE_PROPERTY:
case OpCode::MONO_STORE_PROPERTY_LOOK_UP_PROTO:
return VisitMonoStoreProperty(gate);
case OpCode::VALUE_SELECTOR:
return VisitPhi(gate);
case OpCode::CONSTANT:
@ -1232,6 +1239,92 @@ GateRef NumberSpeculativeRetype::VisitNumberMod(GateRef gate)
return Circuit::NullGate();
}
GateRef NumberSpeculativeRetype::VisitMonoLoadPropertyOnProto(GateRef gate)
{
if (IsRetype()) {
GateRef propertyLookupResult = acc_.GetValueIn(gate, 1);
PropertyLookupResult plr(acc_.TryGetValue(propertyLookupResult));
return SetOutputType(gate, plr.GetRepresentation());
}
ASSERT(IsConvert());
size_t valueNum = acc_.GetNumValueIn(gate);
for (size_t i = 0; i < valueNum; ++i) {
if (i == PROPERTY_LOOKUP_RESULT_INDEX || i == HCLASS_INDEX) {
continue;
}
GateRef input = acc_.GetValueIn(gate, i);
acc_.ReplaceValueIn(gate, ConvertToTagged(input), i);
}
return Circuit::NullGate();
}
GateRef NumberSpeculativeRetype::VisitMonoCallGetterOnProto(GateRef gate)
{
if (IsRetype()) {
return SetOutputType(gate, GateType::AnyType());
}
if (IsConvert()) {
size_t valueNum = acc_.GetNumValueIn(gate);
for (size_t i = 0; i < valueNum; ++i) {
if (i == PROPERTY_LOOKUP_RESULT_INDEX || i == HCLASS_INDEX) {
continue;
}
GateRef input = acc_.GetValueIn(gate, i);
acc_.ReplaceValueIn(gate, ConvertToTagged(input), i);
}
}
return Circuit::NullGate();
}
GateRef NumberSpeculativeRetype::VisitMonoStoreProperty(GateRef gate)
{
if (IsRetype()) {
return SetOutputType(gate, GateType::AnyType());
}
ASSERT(IsConvert());
GateRef value = acc_.GetValueIn(gate, 4); // 4: value
Environment env(gate, circuit_, &builder_);
GateRef propertyLookupResult = acc_.GetValueIn(gate, 1);
PropertyLookupResult plr(acc_.TryGetValue(propertyLookupResult));
if (plr.IsAccessor()) {
size_t valueNum = acc_.GetNumValueIn(gate);
for (size_t i = 0; i < valueNum; ++i) {
if (i == PROPERTY_LOOKUP_RESULT_INDEX || i == HCLASS_INDEX) {
continue;
}
GateRef input = acc_.GetValueIn(gate, i);
acc_.ReplaceValueIn(gate, ConvertToTagged(input), i);
}
return Circuit::NullGate();
}
if (plr.GetRepresentation() == Representation::DOUBLE) {
acc_.SetStoreNoBarrier(gate, true);
acc_.ReplaceValueIn(
gate, CheckAndConvertToFloat64(value, GateType::NumberType(), ConvertSupport::DISABLE), 4); // 4: value
} else if (plr.GetRepresentation() == Representation::INT) {
acc_.SetStoreNoBarrier(gate, true);
acc_.ReplaceValueIn(
gate, CheckAndConvertToInt32(value, GateType::IntType(), ConvertSupport::DISABLE), 4); // 4: value
} else {
TypeInfo valueType = GetOutputTypeInfo(value);
if (valueType == TypeInfo::INT1 || valueType == TypeInfo::INT32 || valueType == TypeInfo::FLOAT64) {
acc_.SetStoreNoBarrier(gate, true);
}
acc_.ReplaceValueIn(gate, ConvertToTagged(value), 4); // 4: value
}
GateRef receiver = acc_.GetValueIn(gate, 0); // receiver
acc_.ReplaceValueIn(gate, ConvertToTagged(receiver), 0);
acc_.ReplaceStateIn(gate, builder_.GetState());
acc_.ReplaceDependIn(gate, builder_.GetDepend());
return Circuit::NullGate();
}
GateRef NumberSpeculativeRetypeManager::VisitGate(GateRef gate)
{
retype_->setState(state_);

View File

@ -99,6 +99,9 @@ private:
GateRef VisitStringCompare(GateRef gate);
GateRef VisitStringAdd(GateRef gate);
GateRef VisitMonoLoadPropertyOnProto(GateRef gate);
GateRef VisitMonoCallGetterOnProto(GateRef gate);
GateRef VisitMonoStoreProperty(GateRef gate);
void ConvertForBinaryOp(GateRef gate);
void ConvertForCompareOp(GateRef gate);
@ -141,6 +144,7 @@ private:
}
static constexpr size_t PROPERTY_LOOKUP_RESULT_INDEX = 1;
static constexpr size_t HCLASS_INDEX = 2;
Circuit *circuit_ {nullptr};
GateAccessor acc_;
CircuitBuilder builder_;

View File

@ -322,6 +322,11 @@ public:
return value_;
}
void SetBool(bool value)
{
value_ = value;
}
private:
bool value_ { false };
};

View File

@ -453,6 +453,9 @@ void TypeBytecodeLowering::LowerTypedLdObjByName(GateRef gate)
DISALLOW_GARBAGE_COLLECTION;
LoadObjByNameTypeInfoAccessor tacc(thread_, circuit_, gate, chunk_);
if (TryLowerTypedLdobjBynameFromGloablBuiltin(gate)) {
return;
}
if (TryLowerTypedLdObjByNameForBuiltin(gate)) {
return;
}
@ -470,6 +473,28 @@ void TypeBytecodeLowering::LowerTypedLdObjByName(GateRef gate)
}
Label exit(&builder_);
AddProfiling(gate);
if (tacc.IsMono()) {
GateRef receiver = tacc.GetReceiver();
builder_.ObjectTypeCheck(acc_.GetGateType(gate), true, receiver,
builder_.Int32(tacc.GetExpectedHClassIndex(0)));
if (tacc.IsReceiverEqHolder(0)) {
result = BuildNamedPropertyAccess(gate, receiver, receiver, tacc.GetAccessInfo(0).Plr());
} else {
builder_.ProtoChangeMarkerCheck(receiver);
PropertyLookupResult plr = tacc.GetAccessInfo(0).Plr();
GateRef plrGate = builder_.Int32(plr.GetData());
GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
size_t holderHClassIndex = tacc.GetAccessInfo(0).HClassIndex();
if (LIKELY(!plr.IsAccessor())) {
result = builder_.MonoLoadPropertyOnProto(receiver, plrGate, jsFunc, holderHClassIndex);
} else {
result = builder_.MonoCallGetterOnProto(gate, receiver, plrGate, jsFunc, holderHClassIndex);
}
}
acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), *result);
DeleteConstDataIfNoUser(tacc.GetKey());
return;
}
auto receiverHC = builder_.LoadConstOffset(VariableType::JS_POINTER(), tacc.GetReceiver(),
TaggedObject::HCLASS_OFFSET);
for (size_t i = 0; i < typeCount; ++i) {
@ -489,13 +514,9 @@ void TypeBytecodeLowering::LowerTypedLdObjByName(GateRef gate)
builder_.Jump(&exit);
} else {
// prototype change marker check
builder_.ProtoChangeMarkerCheck(tacc.GetReceiver());
// lookup from receiver for holder
auto prototype = builder_.LoadConstOffset(VariableType::JS_ANY(), receiverHC, JSHClass::PROTOTYPE_OFFSET);
auto protoHClass =
builder_.LoadConstOffset(VariableType::JS_POINTER(), prototype, TaggedObject::HCLASS_OFFSET);
auto marker =
builder_.LoadConstOffset(VariableType::JS_ANY(), protoHClass, JSHClass::PROTO_CHANGE_MARKER_OFFSET);
builder_.ProtoChangeMarkerCheck(marker, acc_.FindNearestFrameState(builder_.GetDepend()));
// lookup from receiver for holder
ObjectAccessTypeInfoAccessor::ObjectAccessInfo info = tacc.GetAccessInfo(i);
auto holderHC = builder_.GetHClassGateFromIndex(gate, info.HClassIndex());
@ -545,6 +566,34 @@ void TypeBytecodeLowering::LowerTypedStObjByName(GateRef gate)
Label exit(&builder_);
AddProfiling(gate);
if (tacc.IsMono()) {
GateRef receiver = tacc.GetReceiver();
builder_.ObjectTypeCheck(acc_.GetGateType(gate), true, receiver,
builder_.Int32(tacc.GetExpectedHClassIndex(0)));
if (tacc.IsReceiverNoEqNewHolder(0)) {
builder_.ProtoChangeMarkerCheck(tacc.GetReceiver());
PropertyLookupResult plr = tacc.GetAccessInfo(0).Plr();
GateRef plrGate = builder_.Int32(plr.GetData());
GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
size_t holderHClassIndex = tacc.GetAccessInfo(0).HClassIndex();
GateRef value = tacc.GetValue();
if (tacc.IsHolderEqNewHolder(0)) {
builder_.MonoStorePropertyLookUpProto(tacc.GetReceiver(), plrGate, jsFunc, holderHClassIndex, value);
} else {
auto propKey = builder_.LoadObjectFromConstPool(argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC),
tacc.GetKey());
builder_.MonoStoreProperty(tacc.GetReceiver(), plrGate, jsFunc, holderHClassIndex, value,
propKey);
}
} else if (tacc.IsReceiverEqHolder(0)) {
BuildNamedPropertyAccess(gate, tacc.GetReceiver(), tacc.GetReceiver(),
tacc.GetValue(), tacc.GetAccessInfo(0).Plr());
}
acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), Circuit::NullGate());
DeleteConstDataIfNoUser(tacc.GetKey());
return;
}
auto receiverHC = builder_.LoadConstOffset(VariableType::JS_POINTER(), tacc.GetReceiver(),
TaggedObject::HCLASS_OFFSET);
for (size_t i = 0; i < typeCount; ++i) {
@ -558,14 +607,8 @@ void TypeBytecodeLowering::LowerTypedStObjByName(GateRef gate)
acc_.FindNearestFrameState(builder_.GetDepend()), DeoptType::INCONSISTENTHCLASS);
}
if (tacc.IsReceiverNoEqNewHolder(i)) {
// prototype change marker check
builder_.ProtoChangeMarkerCheck(tacc.GetReceiver());
auto prototype = builder_.LoadConstOffset(VariableType::JS_ANY(), receiverHC, JSHClass::PROTOTYPE_OFFSET);
auto protoHClass =
builder_.LoadConstOffset(VariableType::JS_POINTER(), prototype, TaggedObject::HCLASS_OFFSET);
auto marker =
builder_.LoadConstOffset(VariableType::JS_ANY(), protoHClass, JSHClass::PROTO_CHANGE_MARKER_OFFSET);
builder_.ProtoChangeMarkerCheck(marker, acc_.FindNearestFrameState(builder_.GetDepend()));
if (tacc.IsHolderEqNewHolder(i)) {
// lookup from receiver for holder
auto holderHC = builder_.GetHClassGateFromIndex(gate, tacc.GetAccessInfo(i).HClassIndex());
@ -753,6 +796,34 @@ bool TypeBytecodeLowering::TryLowerTypedLdObjByNameForBuiltin(const LoadBulitinO
return false;
}
bool TypeBytecodeLowering::TryLowerTypedLdobjBynameFromGloablBuiltin(GateRef gate)
{
LoadBulitinObjTypeInfoAccessor tacc(thread_, circuit_, gate, chunk_);
GateRef receiver = tacc.GetReceiver();
if (acc_.GetOpCode(receiver) != OpCode::LOAD_BUILTIN_OBJECT) {
return false;
}
JSHandle<GlobalEnv> globalEnv = thread_->GetEcmaVM()->GetGlobalEnv();
uint64_t index = acc_.TryGetValue(receiver);
BuiltinType type = static_cast<BuiltinType>(index);
if (type == BuiltinType::BT_MATH) {
auto math = globalEnv->GetMathFunction();
JSHClass *hclass = math.GetTaggedValue().GetTaggedObject()->GetClass();
JSTaggedValue key = tacc.GetKeyTaggedValue();
PropertyLookupResult plr = JSHClass::LookupPropertyInBuiltinHClass(thread_, hclass, key);
if (!plr.IsFound() || plr.IsAccessor()) {
return false;
}
AddProfiling(gate);
GateRef plrGate = builder_.Int32(plr.GetData());
GateRef result = builder_.LoadProperty(receiver, plrGate, plr.IsFunction());
acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
DeleteConstDataIfNoUser(tacc.GetKey());
return true;
}
return false;
}
void TypeBytecodeLowering::LowerTypedLdArrayLength(const LoadBulitinObjTypeInfoAccessor &tacc)
{
GateRef gate = tacc.GetGate();
@ -1727,7 +1798,7 @@ void TypeBytecodeLowering::LowerTypedTryLdGlobalByName(GateRef gate)
return;
}
AddProfiling(gate);
GateRef result = builder_.LoadBuiltinObject(static_cast<uint64_t>(builtin.GetBuiltinBoxOffset(key)));
GateRef result = builder_.LoadBuiltinObject(index);
acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
DeleteConstDataIfNoUser(tacc.GetKey());
}
@ -1753,13 +1824,7 @@ void TypeBytecodeLowering::LowerInstanceOf(GateRef gate)
GateRef target = tacc.GetTarget();
builder_.ObjectTypeCheck(acc_.GetGateType(gate), true, target, expectedHCIndexes[0]);
auto ctorHC = builder_.LoadConstOffset(VariableType::JS_POINTER(), target, TaggedObject::HCLASS_OFFSET);
auto prototype = builder_.LoadConstOffset(VariableType::JS_ANY(), ctorHC, JSHClass::PROTOTYPE_OFFSET);
auto protoHClass =
builder_.LoadConstOffset(VariableType::JS_POINTER(), prototype, TaggedObject::HCLASS_OFFSET);
auto marker =
builder_.LoadConstOffset(VariableType::JS_ANY(), protoHClass, JSHClass::PROTO_CHANGE_MARKER_OFFSET);
builder_.ProtoChangeMarkerCheck(marker, acc_.FindNearestFrameState(builder_.GetDepend()));
builder_.ProtoChangeMarkerCheck(target);
result = builder_.OrdinaryHasInstance(obj, target);
acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), *result);

View File

@ -203,6 +203,7 @@ private:
BuiltinsStubCSigns::ID id, bool isThrow);
void DeleteConstDataIfNoUser(GateRef gate);
bool TryLowerNewBuiltinConstructor(GateRef gate);
bool TryLowerTypedLdobjBynameFromGloablBuiltin(GateRef gate);
void AddProfiling(GateRef gate);

View File

@ -162,6 +162,21 @@ GateRef TypeHCRLowering::VisitGate(GateRef gate)
case OpCode::ORDINARY_HAS_INSTANCE:
LowerOrdinaryHasInstance(gate, glue);
break;
case OpCode::PROTO_CHANGE_MARKER_CHECK:
LowerProtoChangeMarkerCheck(gate);
break;
case OpCode::MONO_CALL_GETTER_ON_PROTO:
LowerMonoCallGetterOnProto(gate, glue);
break;
case OpCode::MONO_LOAD_PROPERTY_ON_PROTO:
LowerMonoLoadPropertyOnProto(gate);
break;
case OpCode::MONO_STORE_PROPERTY_LOOK_UP_PROTO:
LowerMonoStorePropertyLookUpProto(gate, glue);
break;
case OpCode::MONO_STORE_PROPERTY:
LowerMonoStoreProperty(gate, glue);
break;
default:
break;
}
@ -691,32 +706,14 @@ GateRef TypeHCRLowering::GetObjectFromConstPool(GateRef jsFunc, GateRef index)
void TypeHCRLowering::LowerLoadProperty(GateRef gate)
{
Environment env(gate, circuit_, &builder_);
AddProfiling(gate);
ASSERT(acc_.GetNumValueIn(gate) == 2); // 2: receiver, plr
GateRef receiver = acc_.GetValueIn(gate, 0);
GateRef propertyLookupResult = acc_.GetValueIn(gate, 1);
PropertyLookupResult plr(acc_.TryGetValue(propertyLookupResult));
ASSERT(plr.IsLocal() || plr.IsFunction());
GateRef result = Circuit::NullGate();
if (plr.IsNotHole()) {
ASSERT(plr.IsLocal());
if (plr.IsInlinedProps()) {
result = builder_.LoadConstOffset(VariableType::JS_ANY(), receiver, plr.GetOffset());
} else {
auto properties = builder_.LoadConstOffset(VariableType::JS_ANY(), receiver, JSObject::PROPERTIES_OFFSET);
result = builder_.GetValueFromTaggedArray(properties, builder_.Int32(plr.GetOffset()));
}
} else if (plr.IsLocal()) {
if (plr.IsInlinedProps()) {
result = builder_.LoadConstOffset(VariableType::JS_ANY(), receiver, plr.GetOffset());
} else {
auto properties = builder_.LoadConstOffset(VariableType::JS_ANY(), receiver, JSObject::PROPERTIES_OFFSET);
result = builder_.GetValueFromTaggedArray(properties, builder_.Int32(plr.GetOffset()));
}
result = builder_.ConvertHoleAsUndefined(result);
} else {
UNREACHABLE();
}
GateRef result = LoadPropertyFromHolder(receiver, plr);
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
}
@ -730,26 +727,7 @@ void TypeHCRLowering::LowerCallGetter(GateRef gate, GateRef glue)
GateRef holder = acc_.GetValueIn(gate, 2);
PropertyLookupResult plr(acc_.TryGetValue(propertyLookupResult));
GateRef accessor = Circuit::NullGate();
if (plr.IsNotHole()) {
ASSERT(plr.IsLocal());
if (plr.IsInlinedProps()) {
accessor = builder_.LoadConstOffset(VariableType::JS_ANY(), holder, plr.GetOffset());
} else {
auto properties = builder_.LoadConstOffset(VariableType::JS_ANY(), holder, JSObject::PROPERTIES_OFFSET);
accessor = builder_.GetValueFromTaggedArray(properties, builder_.Int32(plr.GetOffset()));
}
} else if (plr.IsLocal()) {
if (plr.IsInlinedProps()) {
accessor = builder_.LoadConstOffset(VariableType::JS_ANY(), holder, plr.GetOffset());
} else {
auto properties = builder_.LoadConstOffset(VariableType::JS_ANY(), holder, JSObject::PROPERTIES_OFFSET);
accessor = builder_.GetValueFromTaggedArray(properties, builder_.Int32(plr.GetOffset()));
}
accessor = builder_.ConvertHoleAsUndefined(accessor);
} else {
UNREACHABLE();
}
GateRef accessor = LoadPropertyFromHolder(holder, plr);
DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.UndefineConstant());
Label isInternalAccessor(&builder_);
@ -2200,9 +2178,11 @@ void TypeHCRLowering::ReplaceGateWithPendingException(GateRef glue, GateRef gate
void TypeHCRLowering::LowerLoadBuiltinObject(GateRef gate)
{
Environment env(gate, circuit_, &builder_);
AddProfiling(gate);
GateRef glue = acc_.GetGlueFromArgList();
auto builtinEntriesOffset = JSThread::GlueData::GetBuiltinEntriesOffset(false);
auto boxOffset = builtinEntriesOffset + acc_.GetIndex(gate);
size_t index = acc_.GetIndex(gate);
auto boxOffset = builtinEntriesOffset + BuiltinIndex::GetInstance().GetBuiltinBoxOffset(index);
GateRef box = builder_.LoadConstOffset(VariableType::JS_POINTER(), glue, boxOffset);
GateRef builtin = builder_.LoadConstOffset(VariableType::JS_POINTER(), box, PropertyBox::VALUE_OFFSET);
auto frameState = GetFrameState(gate);
@ -2353,4 +2333,367 @@ void TypeHCRLowering::LowerOrdinaryHasInstance(GateRef gate, GateRef glue)
builder_.Bind(&exit);
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result);
}
void TypeHCRLowering::LowerProtoChangeMarkerCheck(GateRef gate)
{
Environment env(gate, circuit_, &builder_);
GateRef frameState = acc_.GetFrameState(gate);
GateRef receiver = acc_.GetValueIn(gate, 0);
auto hclass = builder_.LoadConstOffset(VariableType::JS_POINTER(), receiver, TaggedObject::HCLASS_OFFSET);
auto prototype = builder_.LoadConstOffset(VariableType::JS_ANY(), hclass, JSHClass::PROTOTYPE_OFFSET);
auto protoHClass = builder_.LoadConstOffset(VariableType::JS_POINTER(), prototype, TaggedObject::HCLASS_OFFSET);
auto marker = builder_.LoadConstOffset(VariableType::JS_ANY(), protoHClass, JSHClass::PROTO_CHANGE_MARKER_OFFSET);
auto notNull = builder_.TaggedIsNotNull(marker);
auto hasChanged = builder_.GetHasChanged(marker);
auto check = builder_.BoolAnd(builder_.BoolNot(hasChanged), notNull);
builder_.DeoptCheck(check, frameState, DeoptType::PROTOTYPECHANGED);
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
}
void TypeHCRLowering::LowerMonoLoadPropertyOnProto(GateRef gate)
{
Environment env(gate, circuit_, &builder_);
GateRef frameState = acc_.GetFrameState(gate);
GateRef receiver = acc_.GetValueIn(gate, 0);
GateRef propertyLookupResult = acc_.GetValueIn(gate, 1); // 1: propertyLookupResult
GateRef hclassIndex = acc_.GetValueIn(gate, 2); // 2: hclassIndex
GateRef jsFunc = acc_.GetValueIn(gate, 3); // 3: jsFunc
PropertyLookupResult plr(acc_.TryGetValue(propertyLookupResult));
GateRef result = Circuit::NullGate();
ASSERT(plr.IsLocal() || plr.IsFunction());
auto receiverHC = builder_.LoadConstOffset(VariableType::JS_POINTER(), receiver, TaggedObject::HCLASS_OFFSET);
auto prototype = builder_.LoadConstOffset(VariableType::JS_ANY(), receiverHC, JSHClass::PROTOTYPE_OFFSET);
// lookup from receiver for holder
GateRef constPool = builder_.GetConstPool(jsFunc);
auto holderHC = builder_.LoadHClassFromConstpool(constPool, acc_.GetConstantValue(hclassIndex));
DEFVALUE(current, (&builder_), VariableType::JS_ANY(), prototype);
Label exit(&builder_);
Label loopHead(&builder_);
Label loadHolder(&builder_);
Label lookUpProto(&builder_);
builder_.Jump(&loopHead);
builder_.LoopBegin(&loopHead);
builder_.DeoptCheck(builder_.TaggedIsNotNull(*current), frameState, DeoptType::INCONSISTENTHCLASS);
auto curHC = builder_.LoadConstOffset(VariableType::JS_POINTER(), *current, TaggedObject::HCLASS_OFFSET);
builder_.Branch(builder_.Equal(curHC, holderHC), &loadHolder, &lookUpProto);
builder_.Bind(&lookUpProto);
current = builder_.LoadConstOffset(VariableType::JS_ANY(), curHC, JSHClass::PROTOTYPE_OFFSET);
builder_.LoopEnd(&loopHead);
builder_.Bind(&loadHolder);
result = LoadPropertyFromHolder(*current, plr);
builder_.Jump(&exit);
builder_.Bind(&exit);
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
}
void TypeHCRLowering::LowerMonoCallGetterOnProto(GateRef gate, GateRef glue)
{
Environment env(gate, circuit_, &builder_);
GateRef frameState = acc_.GetFrameState(gate);
GateRef receiver = acc_.GetValueIn(gate, 0);
GateRef propertyLookupResult = acc_.GetValueIn(gate, 1); // 1: propertyLookupResult
GateRef hclassIndex = acc_.GetValueIn(gate, 2); // 2: hclassIndex
GateRef jsFunc = acc_.GetValueIn(gate, 3); // 3: jsFunc
PropertyLookupResult plr(acc_.TryGetValue(propertyLookupResult));
GateRef accessor = Circuit::NullGate();
GateRef holder = Circuit::NullGate();
auto receiverHC = builder_.LoadConstOffset(VariableType::JS_POINTER(), receiver, TaggedObject::HCLASS_OFFSET);
auto prototype = builder_.LoadConstOffset(VariableType::JS_ANY(), receiverHC, JSHClass::PROTOTYPE_OFFSET);
// lookup from receiver for holder
GateRef constPool = builder_.GetConstPool(jsFunc);
auto holderHC = builder_.LoadHClassFromConstpool(constPool, acc_.GetConstantValue(hclassIndex));
DEFVALUE(current, (&builder_), VariableType::JS_ANY(), prototype);
Label exitLoad(&builder_);
Label loopHead(&builder_);
Label loadHolder(&builder_);
Label lookUpProto(&builder_);
builder_.Jump(&loopHead);
builder_.LoopBegin(&loopHead);
builder_.DeoptCheck(builder_.TaggedIsNotNull(*current), frameState, DeoptType::INCONSISTENTHCLASS);
auto curHC = builder_.LoadConstOffset(VariableType::JS_POINTER(), *current, TaggedObject::HCLASS_OFFSET);
builder_.Branch(builder_.Equal(curHC, holderHC), &loadHolder, &lookUpProto);
builder_.Bind(&lookUpProto);
current = builder_.LoadConstOffset(VariableType::JS_ANY(), curHC, JSHClass::PROTOTYPE_OFFSET);
builder_.LoopEnd(&loopHead);
builder_.Bind(&loadHolder);
holder = *current;
accessor = LoadPropertyFromHolder(holder, plr);
builder_.Jump(&exitLoad);
builder_.Bind(&exitLoad);
DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.UndefineConstant());
Label isInternalAccessor(&builder_);
Label notInternalAccessor(&builder_);
Label callGetter(&builder_);
Label exit(&builder_);
builder_.Branch(builder_.IsAccessorInternal(accessor), &isInternalAccessor, &notInternalAccessor);
{
builder_.Bind(&isInternalAccessor);
{
result = builder_.CallRuntime(glue, RTSTUB_ID(CallInternalGetter),
Gate::InvalidGateRef, { accessor, holder }, gate);
builder_.Jump(&exit);
}
builder_.Bind(&notInternalAccessor);
{
GateRef getter = builder_.LoadConstOffset(VariableType::JS_ANY(), accessor, AccessorData::GETTER_OFFSET);
builder_.Branch(builder_.IsSpecial(getter, JSTaggedValue::VALUE_UNDEFINED), &exit, &callGetter);
builder_.Bind(&callGetter);
{
result = CallAccessor(glue, gate, getter, receiver, AccessorMode::GETTER);
builder_.Jump(&exit);
}
}
}
builder_.Bind(&exit);
ReplaceHirWithPendingException(gate, glue, builder_.GetState(), builder_.GetDepend(), *result);
}
GateRef TypeHCRLowering::LoadPropertyFromHolder(GateRef holder, PropertyLookupResult plr)
{
GateRef result = Circuit::NullGate();
if (plr.IsNotHole()) {
ASSERT(plr.IsLocal());
if (plr.IsInlinedProps()) {
result = builder_.LoadConstOffset(VariableType::JS_ANY(), holder, plr.GetOffset());
} else {
auto properties = builder_.LoadConstOffset(VariableType::JS_ANY(), holder, JSObject::PROPERTIES_OFFSET);
result = builder_.GetValueFromTaggedArray(properties, builder_.Int32(plr.GetOffset()));
}
} else if (plr.IsLocal()) {
if (plr.IsInlinedProps()) {
result = builder_.LoadConstOffset(VariableType::JS_ANY(), holder, plr.GetOffset());
} else {
auto properties = builder_.LoadConstOffset(VariableType::JS_ANY(), holder, JSObject::PROPERTIES_OFFSET);
result = builder_.GetValueFromTaggedArray(properties, builder_.Int32(plr.GetOffset()));
}
result = builder_.ConvertHoleAsUndefined(result);
} else {
UNREACHABLE();
}
return result;
}
void TypeHCRLowering::LowerMonoStorePropertyLookUpProto(GateRef gate, GateRef glue)
{
Environment env(gate, circuit_, &builder_);
GateRef frameState = acc_.GetFrameState(gate);
GateRef receiver = acc_.GetValueIn(gate, 0);
GateRef propertyLookupResult = acc_.GetValueIn(gate, 1); // 1: propertyLookupResult
GateRef hclassIndex = acc_.GetValueIn(gate, 2); // 2: hclassIndex
GateRef jsFunc = acc_.GetValueIn(gate, 3); // 3: jsFunc
GateRef value = acc_.GetValueIn(gate, 4); // 4: value
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);
// lookup from receiver for holder
GateRef constPool = builder_.GetConstPool(jsFunc);
auto holderHC = builder_.LoadHClassFromConstpool(constPool, acc_.GetConstantValue(hclassIndex));
DEFVALUE(current, (&builder_), VariableType::JS_ANY(), prototype);
Label exit(&builder_);
Label loopHead(&builder_);
Label loadHolder(&builder_);
Label lookUpProto(&builder_);
builder_.Jump(&loopHead);
builder_.LoopBegin(&loopHead);
builder_.DeoptCheck(builder_.TaggedIsNotNull(*current), frameState, DeoptType::INCONSISTENTHCLASS);
auto curHC = builder_.LoadConstOffset(VariableType::JS_POINTER(), *current,
TaggedObject::HCLASS_OFFSET);
builder_.Branch(builder_.Equal(curHC, holderHC), &loadHolder, &lookUpProto);
builder_.Bind(&lookUpProto);
current = builder_.LoadConstOffset(VariableType::JS_ANY(), curHC, JSHClass::PROTOTYPE_OFFSET);
builder_.LoopEnd(&loopHead);
builder_.Bind(&loadHolder);
if (!plr.IsAccessor()) {
StorePropertyOnHolder(*current, value, plr, noBarrier);
builder_.Jump(&exit);
} else {
GateRef accessor = LoadPropertyFromHolder(*current, plr);
Label isInternalAccessor(&builder_);
Label notInternalAccessor(&builder_);
Label callSetter(&builder_);
builder_.Branch(builder_.IsAccessorInternal(accessor), &isInternalAccessor, &notInternalAccessor);
{
builder_.Bind(&isInternalAccessor);
{
builder_.CallRuntime(glue, RTSTUB_ID(CallInternalSetter),
Gate::InvalidGateRef, { receiver, accessor, value }, gate);
builder_.Jump(&exit);
}
builder_.Bind(&notInternalAccessor);
{
GateRef setter =
builder_.LoadConstOffset(VariableType::JS_ANY(), accessor, AccessorData::SETTER_OFFSET);
builder_.Branch(builder_.IsSpecial(setter, JSTaggedValue::VALUE_UNDEFINED), &exit, &callSetter);
builder_.Bind(&callSetter);
{
CallAccessor(glue, gate, setter, receiver, AccessorMode::SETTER, value);
builder_.Jump(&exit);
}
}
}
}
builder_.Bind(&exit);
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
}
void TypeHCRLowering::LowerMonoStoreProperty(GateRef gate, GateRef glue)
{
Environment env(gate, circuit_, &builder_);
GateRef receiver = acc_.GetValueIn(gate, 0);
GateRef propertyLookupResult = acc_.GetValueIn(gate, 1); // 1: propertyLookupResult
GateRef hclassIndex = acc_.GetValueIn(gate, 2); // 2: hclassIndex
GateRef jsFunc = acc_.GetValueIn(gate, 3); // 3: jsFunc
GateRef value = acc_.GetValueIn(gate, 4); // 4: value
GateRef key = acc_.GetValueIn(gate, 5); // 5: key
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_);
GateRef constPool = builder_.GetConstPool(jsFunc);
auto newHolderHC = builder_.LoadHClassFromConstpool(constPool, 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);
builder_.Bind(&isProto);
builder_.CallRuntime(glue, RTSTUB_ID(UpdateAOTHClass), Gate::InvalidGateRef,
{ receiverHC, newHolderHC, key }, gate);
builder_.Jump(&notProto);
builder_.Bind(&notProto);
MemoryOrder order = MemoryOrder::Create(MemoryOrder::MEMORY_ORDER_RELEASE);
builder_.StoreConstOffset(VariableType::JS_ANY(), receiver, TaggedObject::HCLASS_OFFSET, newHolderHC, order);
if (!plr.IsInlinedProps()) {
auto properties =
builder_.LoadConstOffset(VariableType::JS_ANY(), receiver, JSObject::PROPERTIES_OFFSET);
auto capacity = builder_.LoadConstOffset(VariableType::INT32(), properties, TaggedArray::LENGTH_OFFSET);
auto index = builder_.Int32(plr.GetOffset());
Label needExtend(&builder_);
Label notExtend(&builder_);
builder_.Branch(builder_.Int32UnsignedLessThan(index, capacity), &notExtend, &needExtend);
builder_.Bind(&notExtend);
{
if (!plr.IsAccessor()) {
StorePropertyOnHolder(receiver, value, plr, noBarrier);
builder_.Jump(&exit);
} else {
GateRef accessor = LoadPropertyFromHolder(receiver, plr);
Label isInternalAccessor(&builder_);
Label notInternalAccessor(&builder_);
Label callSetter(&builder_);
builder_.Branch(builder_.IsAccessorInternal(accessor), &isInternalAccessor, &notInternalAccessor);
{
builder_.Bind(&isInternalAccessor);
{
builder_.CallRuntime(glue, RTSTUB_ID(CallInternalSetter),
Gate::InvalidGateRef, { receiver, accessor, value }, gate);
builder_.Jump(&exit);
}
builder_.Bind(&notInternalAccessor);
{
GateRef setter =
builder_.LoadConstOffset(VariableType::JS_ANY(), accessor, AccessorData::SETTER_OFFSET);
builder_.Branch(builder_.IsSpecial(setter, JSTaggedValue::VALUE_UNDEFINED), &exit, &callSetter);
builder_.Bind(&callSetter);
{
CallAccessor(glue, gate, setter, receiver, AccessorMode::SETTER, value);
builder_.Jump(&exit);
}
}
}
}
}
builder_.Bind(&needExtend);
{
builder_.CallRuntime(glue,
RTSTUB_ID(PropertiesSetValue),
Gate::InvalidGateRef,
{ receiver, value, properties, builder_.Int32ToTaggedInt(capacity),
builder_.Int32ToTaggedInt(index) }, gate);
builder_.Jump(&exit);
}
} else {
if (!plr.IsAccessor()) {
StorePropertyOnHolder(receiver, value, plr, noBarrier);
builder_.Jump(&exit);
} else {
GateRef accessor = LoadPropertyFromHolder(receiver, plr);
Label isInternalAccessor(&builder_);
Label notInternalAccessor(&builder_);
Label callSetter(&builder_);
builder_.Branch(builder_.IsAccessorInternal(accessor), &isInternalAccessor, &notInternalAccessor);
{
builder_.Bind(&isInternalAccessor);
{
builder_.CallRuntime(glue, RTSTUB_ID(CallInternalSetter),
Gate::InvalidGateRef, { receiver, accessor, value }, gate);
builder_.Jump(&exit);
}
builder_.Bind(&notInternalAccessor);
{
GateRef setter =
builder_.LoadConstOffset(VariableType::JS_ANY(), accessor, AccessorData::SETTER_OFFSET);
builder_.Branch(builder_.IsSpecial(setter, JSTaggedValue::VALUE_UNDEFINED), &exit, &callSetter);
builder_.Bind(&callSetter);
{
CallAccessor(glue, gate, setter, receiver, AccessorMode::SETTER, value);
builder_.Jump(&exit);
}
}
}
}
}
builder_.Bind(&exit);
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
}
void TypeHCRLowering::StorePropertyOnHolder(GateRef holder, GateRef value, PropertyLookupResult plr, bool noBarrier)
{
if (!noBarrier) {
if (plr.IsInlinedProps()) {
builder_.StoreConstOffset(VariableType::JS_ANY(), holder, plr.GetOffset(), value);
} else {
auto properties = builder_.LoadConstOffset(VariableType::JS_ANY(), holder, JSObject::PROPERTIES_OFFSET);
builder_.SetValueToTaggedArray(
VariableType::JS_ANY(), acc_.GetGlueFromArgList(), properties, builder_.Int32(plr.GetOffset()), value);
}
} else {
if (plr.IsInlinedProps()) {
builder_.StoreConstOffset(GetVarType(plr), holder, plr.GetOffset(), value);
} else {
auto properties = builder_.LoadConstOffset(VariableType::JS_ANY(), holder, JSObject::PROPERTIES_OFFSET);
builder_.SetValueToTaggedArray(
GetVarType(plr), acc_.GetGlueFromArgList(), properties, builder_.Int32(plr.GetOffset()), value);
}
}
}
void TypeHCRLowering::AddProfiling(GateRef gate)
{
if (IsLoopHoistProfiling()) {
OpCode opcode = acc_.GetOpCode(gate);
auto opcodeGate = builder_.Int32(static_cast<uint32_t>(opcode));
GateRef constOpcode = builder_.Int32ToTaggedInt(opcodeGate);
builder_.CallRuntime(acc_.GetGlueFromArgList(), RTSTUB_ID(ProfileLoopHoist),
Gate::InvalidGateRef, { constOpcode }, gate);
}
}
} // namespace panda::ecmascript::kungfu

View File

@ -112,6 +112,9 @@ public:
tsManager_(tsManager),
enableLoweringBuiltin_(enableLoweringBuiltin)
{
if (cmpCfg != nullptr) {
loopHoistProfiling_ =cmpCfg->IsLoopHoistProfiling();
}
}
~TypeHCRLowering() = default;
@ -206,6 +209,11 @@ private:
GateRef NewJSPrimitiveRef(PrimitiveType type, GateRef glue, GateRef value);
void ReplaceGateWithPendingException(GateRef glue, GateRef gate, GateRef state, GateRef depend, GateRef value);
void LowerOrdinaryHasInstance(GateRef gate, GateRef glue);
void LowerProtoChangeMarkerCheck(GateRef gate);
void LowerMonoCallGetterOnProto(GateRef gate, GateRef glue);
void LowerMonoLoadPropertyOnProto(GateRef gate);
void LowerMonoStorePropertyLookUpProto(GateRef gate, GateRef glue);
void LowerMonoStoreProperty(GateRef gate, GateRef glue);
GateRef LowerCallRuntime(GateRef glue, GateRef hirGate, int index, const std::vector<GateRef> &args,
bool useLabel = false);
@ -242,6 +250,15 @@ private:
GateRef LoadFromConstPool(GateRef jsFunc, size_t index, size_t valVecType);
GateRef LoadFromVTable(GateRef receiver, size_t index);
GateRef GetLengthFromString(GateRef gate);
GateRef LoadPropertyFromHolder(GateRef holder, PropertyLookupResult plr);
void StorePropertyOnHolder(GateRef holder, GateRef value, PropertyLookupResult plr, bool needBarrier);
void AddProfiling(GateRef gate);
bool IsLoopHoistProfiling() const
{
return loopHoistProfiling_;
}
Circuit *circuit_;
GateAccessor acc_;
@ -249,6 +266,7 @@ private:
GateRef dependEntry_;
[[maybe_unused]] TSManager *tsManager_ {nullptr};
bool enableLoweringBuiltin_ {false};
bool loopHoistProfiling_ {false};
};
} // panda::ecmascript::kungfu
#endif // ECMASCRIPT_COMPILER_TYPE_HCR_LOWERING_H

View File

@ -17,6 +17,7 @@
#include "ecmascript/compiler/bytecodes.h"
#include "ecmascript/compiler/ecma_opcode_des.h"
#include "ecmascript/compiler/share_opcodes.h"
// bcIndex bytecode count fast slow typerate
// ====================(print all)=======================
@ -204,5 +205,41 @@ private:
std::map<uint64_t, Name> methodIdToName_;
std::vector<CString> abcNames_;
};
class LoopHoistProfiler {
public:
using OpCode = kungfu::OpCode;
LoopHoistProfiler()
{
profMap_ = {
{ OpCode::LOAD_BUILTIN_OBJECT, 0 },
{ OpCode::LOAD_PROPERTY, 0}
};
}
void Update (OpCode opcode)
{
if (opcode == OpCode::LOAD_BUILTIN_OBJECT ||
opcode == OpCode::LOAD_PROPERTY) {
profMap_.at(opcode)++;
}
}
void PrintAndReset()
{
LOG_TRACE(INFO) << "LoopHoistProfiler:";
LOG_TRACE(INFO) << "Opcode: LOAD_BUILTIN_OBJECT Count:"
<< profMap_.at(OpCode::LOAD_BUILTIN_OBJECT);
profMap_.at(OpCode::LOAD_BUILTIN_OBJECT) = 0;
LOG_TRACE(INFO) << "Opcode: LOAD_PROPERTY Count:"
<< profMap_.at(OpCode::LOAD_PROPERTY);
profMap_.at(OpCode::LOAD_PROPERTY) = 0;
}
private:
std::map<OpCode, uint64_t> profMap_;
};
} // namespace panda::ecmascript
#endif // ECMASCRIPT_DFX_VMSTAT_OPT_CODE_PROFILER_H

View File

@ -123,6 +123,9 @@ bool EcmaContext::Initialize()
tsManager_ = new TSManager(vm_);
ptManager_ = new kungfu::PGOTypeManager(vm_);
optCodeProfiler_ = new OptCodeProfiler();
if (vm_->GetJSOptions().GetLoopHoistProfiler()) {
loopHoistProfiler_ = new LoopHoistProfiler();
}
initialized_ = true;
return true;
}
@ -210,6 +213,10 @@ EcmaContext::~EcmaContext()
delete optCodeProfiler_;
optCodeProfiler_ = nullptr;
}
if (loopHoistProfiler_ != nullptr) {
delete loopHoistProfiler_;
loopHoistProfiler_ = nullptr;
}
if (moduleManager_ != nullptr) {
delete moduleManager_;
moduleManager_ = nullptr;

View File

@ -292,6 +292,11 @@ public:
return optCodeProfiler_;
}
LoopHoistProfiler *GetLoopHoistProfiler() const
{
return loopHoistProfiler_;
}
// For icu objects cache
void SetIcuFormatterToCache(IcuFormatterType type, const std::string &locale, void *icuObj,
IcuDeleteEntry deleteEntry = nullptr)
@ -558,6 +563,9 @@ private:
// opt code Profiler
OptCodeProfiler *optCodeProfiler_ {nullptr};
// opt code loop hoist
LoopHoistProfiler *loopHoistProfiler_ {nullptr};
// For icu objects cache
struct IcuFormatter {
std::string locale;

View File

@ -154,10 +154,6 @@ bool JSFunction::PrototypeSetter(JSThread *thread, const JSHandle<JSObject> &sel
func->SetProtoOrHClass(thread, newClass);
} else {
func->SetFunctionPrototype(thread, value.GetTaggedValue());
if (thread->GetEcmaVM()->IsEnablePGOProfiler() && value->IsECMAObject()) {
thread->GetEcmaVM()->GetPGOProfiler()->ProfileClassRootHClass(func.GetTaggedType(),
JSTaggedType(value->GetTaggedObject()->GetClass()), pgo::ProfileType::Kind::PrototypeId);
}
}
return true;
}

View File

@ -1203,4 +1203,45 @@ CString JSHClass::DumpToString(JSTaggedType hclassVal)
}
return result;
}
PropertyLookupResult JSHClass::LookupPropertyInBuiltinHClass(const JSThread *thread, JSHClass *hclass,
JSTaggedValue key)
{
DISALLOW_GARBAGE_COLLECTION;
PropertyLookupResult result;
if (hclass->IsDictionaryMode()) {
result.SetIsFound(false);
return result;
}
int entry = JSHClass::FindPropertyEntry(thread, hclass, key);
// found in local
if (entry != -1) {
result.SetIsFound(true);
result.SetIsLocal(true);
PropertyAttributes attr = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject())->GetAttr(entry);
if (attr.IsInlinedProps()) {
result.SetIsInlinedProps(true);
result.SetOffset(hclass->GetInlinedPropertiesOffset(entry));
} else {
result.SetIsInlinedProps(false);
result.SetOffset(attr.GetOffset() - hclass->GetInlinedProperties());
}
if (attr.IsNotHole()) {
result.SetIsNotHole(true);
}
if (attr.IsAccessor()) {
result.SetIsAccessor(true);
}
result.SetRepresentation(attr.GetRepresentation());
result.SetIsWritable(attr.IsWritable());
return result;
}
// not fuond
result.SetIsFound(false);
return result;
}
} // namespace panda::ecmascript

View File

@ -1772,6 +1772,8 @@ public:
static PropertyLookupResult LookupPropertyInPGOHClass(const JSThread *thread, JSHClass *hclass, JSTaggedValue key);
static PropertyLookupResult LookupPropertyInBuiltinPrototypeHClass(const JSThread *thread, JSHClass *hclass,
JSTaggedValue key);
static PropertyLookupResult LookupPropertyInBuiltinHClass(const JSThread *thread, JSHClass *hclass,
JSTaggedValue key);
static constexpr size_t PROTOTYPE_OFFSET = TaggedObjectSize();
ACCESSORS(Proto, PROTOTYPE_OFFSET, LAYOUT_OFFSET);

View File

@ -292,7 +292,7 @@ void JSObject::OptimizeAsFastProperties(const JSThread *thread, JSHandle<JSObjec
if (numberOfProperties > static_cast<int>(PropertyAttributes::MAX_FAST_PROPS_CAPACITY)) {
return ;
}
// 2. iteration indices
std::vector<int> indexOrder = properties->GetEnumerationOrder();
ASSERT(static_cast<int>(indexOrder.size()) == numberOfProperties);
@ -300,7 +300,7 @@ void JSObject::OptimizeAsFastProperties(const JSThread *thread, JSHandle<JSObjec
// 3. Change Hclass
int numberOfInlinedProps = obj->GetJSHClass()->GetInlinedProperties();
JSHClass::OptimizeAsFastProperties(thread, obj, indexOrder, true);
// 4. New out-properties
int numberOfOutProperties = numberOfProperties - numberOfInlinedProps;
ASSERT(numberOfOutProperties >= 0);
@ -362,7 +362,7 @@ bool JSObject::AddElementInternal(JSThread *thread, const JSHandle<JSObject> &re
JSObject::TryOptimizeAsFastElements(thread, receiver);
}
}
bool isDictionary = receiver->GetJSHClass()->IsDictionaryElement();
TaggedArray *elements = TaggedArray::Cast(receiver->GetElements().GetTaggedObject());
if (isDictionary) {
@ -1117,7 +1117,7 @@ bool JSObject::DeleteProperty(JSThread *thread, const JSHandle<JSObject> &obj, c
ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
// 2. Let desc be O.[[GetOwnProperty]](P).
ObjectOperator op(thread, JSHandle<JSTaggedValue>(obj), key, OperatorType::OWN);
// 4. If desc is undefined, return true.
if (!op.IsFound()) {
return true;

View File

@ -159,10 +159,11 @@ const std::string PUBLIC_API HELP_OPTION_MSG =
"--compiler-enable-lowering-builtin: Enable lowering global object: Default: 'false'\n"
"--compiler-opt-array-onheap-check: Enable TypedArray on heap check for aot compiler: Default: 'false'\n"
"--compiler-enable-litecg: Enable LiteCG: Default: 'false'\n"
"--compiler-enable-jit: Enable jit: Default: 'false'\n"
"--compiler-jit-hotness-threshold: Set hotness threshold for jit. Default: '2'\n"
"--compiler-force-jit-compile-main: Enable jit compile main function: Default: 'false'\n"
"--compiler-trace-jit: Enable trace jit: Default: 'false'\n\n";
"--compiler-enable-jit: Enable jit: Default: 'false'\n"
"--compiler-jit-hotness-threshold: Set hotness threshold for jit. Default: '2'\n"
"--compiler-force-jit-compile-main: Enable jit compile main function: Default: 'false'\n"
"--compiler-trace-jit: Enable trace jit: Default: 'false'\n\n"
"--compiler-loop-hoist-profiler: Enable loop hoist IR Statistics for aot runtime. Default: 'false'\n";
bool JSRuntimeOptions::ParseCommand(const int argc, const char **argv)
{
@ -266,6 +267,7 @@ bool JSRuntimeOptions::ParseCommand(const int argc, const char **argv)
{"compiler-enable-jit", required_argument, nullptr, OPTION_COMPILER_ENABLE_JIT},
{"compiler-jit-hotness-threshold", required_argument, nullptr, OPTION_COMPILER_JIT_HOTNESS_THRESHOLD},
{"compiler-force-jit-compile-main", required_argument, nullptr, OPTION_COMPILER_FORCE_JIT_COMPILE_MAIN},
{"compiler-loop-hoist-profiler", required_argument, nullptr, OPTION_COMPILER_LOOP_HOIST_PROFILER},
{nullptr, 0, nullptr, 0},
};
@ -934,6 +936,14 @@ bool JSRuntimeOptions::ParseCommand(const int argc, const char **argv)
return false;
}
break;
case OPTION_COMPILER_LOOP_HOIST_PROFILER:
ret = ParseBoolParam(&argBool);
if (ret) {
SetLoopHoistProfiler(argBool);
} else {
return false;
}
break;
default:
LOG_ECMA(ERROR) << "Invalid option\n";
return false;

View File

@ -159,6 +159,7 @@ enum CommandValues {
OPTION_COMPILER_FORCE_JIT_COMPILE_MAIN,
OPTION_COMPILER_TRACE_JIT,
OPTION_ENABLE_ELEMENTSKIND,
OPTION_COMPILER_LOOP_HOIST_PROFILER,
};
class PUBLIC_API JSRuntimeOptions {
@ -1037,7 +1038,7 @@ public:
return enableValueNumbering_;
}
void SetEnableJIT(bool value)
{
enableJIT_ = value;
@ -1222,7 +1223,7 @@ public:
{
return traceValueNumbering_;
}
void SetTraceJIT(bool value)
{
traceJIT_ = value;
@ -1412,6 +1413,16 @@ public:
return enableLiteCG_;
}
void SetLoopHoistProfiler(bool value)
{
enableLoopHoistProfiler_ = value;
}
bool GetLoopHoistProfiler() const
{
return enableLoopHoistProfiler_;
}
private:
static bool StartsWith(const std::string &haystack, const std::string &needle)
{
@ -1528,6 +1539,7 @@ private:
bool enableNativeInline_ {false};
bool enableLoweringBuiltin_ {false};
bool enableLiteCG_ {false};
bool enableLoopHoistProfiler_ {false};
};
} // namespace panda::ecmascript

View File

@ -108,6 +108,9 @@ void PGOProfiler::ProfileClassRootHClass(JSTaggedType ctor, JSTaggedType rootHcV
return;
}
auto ctorFunc = JSFunction::Cast(ctorValue.GetTaggedObject());
if (!FunctionKindVerify(ctorFunc)) {
return;
}
auto ctorMethodValue = ctorFunc->GetMethod();
if (!ctorMethodValue.IsMethod()) {
return;

View File

@ -2462,6 +2462,17 @@ DEF_RUNTIME_STUBS(ProfileOptimizedCode)
return JSTaggedValue::Undefined().GetRawData();
}
DEF_RUNTIME_STUBS(ProfileLoopHoist)
{
RUNTIME_STUBS_HEADER(ProfileOptimizedCode);
kungfu::OpCode opcode = static_cast<kungfu::OpCode>(GetArg(argv, argc, 0).GetInt());
LoopHoistProfiler *profiler = thread->GetCurrentEcmaContext()->GetLoopHoistProfiler();
if (profiler != nullptr) {
profiler->Update(opcode);
}
return JSTaggedValue::Undefined().GetRawData();
}
DEF_RUNTIME_STUBS(VerifyVTableLoading)
{
RUNTIME_STUBS_HEADER(VerifyVTableLoading);

View File

@ -341,6 +341,7 @@ using FastCallAotEntryType = JSTaggedValue (*)(uintptr_t glue, uint32_t argc, co
V(JSObjectGetMethod) \
V(DebugAOTPrint) \
V(ProfileOptimizedCode) \
V(ProfileLoopHoist) \
V(VerifyVTableLoading) \
V(VerifyVTableStoring) \
V(GetMethodFromCache) \

View File

@ -165,6 +165,7 @@ group("ark_aot_ts_test") {
"lexenv_specialization_noopt",
"load_local_module_var",
"logic_op",
"loop_hoist",
"loop_peeling",
"loop_phi",
"loop_with_variable_exchange",

View File

@ -0,0 +1,25 @@
# Copyright (c) 2023 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("loop_hoist") {
deps = []
is_only_typed_path = true
is_enable_builtins_dts = true
is_enable_pgo = true
is_enable_opt_loop_peeling = true
is_enable_lowering_builtin = true
is_enable_loop_hoist_profiler = true
log_option = " --log-info=trace"
}

View File

@ -0,0 +1,31 @@
# Copyright (c) 2023 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] LoopHoistProfiler:
[trace] Opcode: LOAD_BUILTIN_OBJECT Count:1
[trace] Opcode: LOAD_PROPERTY Count:0
[trace] LoopHoistProfiler:
[trace] Opcode: LOAD_BUILTIN_OBJECT Count:1
[trace] Opcode: LOAD_PROPERTY Count:0
[trace] LoopHoistProfiler:
[trace] Opcode: LOAD_BUILTIN_OBJECT Count:1
[trace] Opcode: LOAD_PROPERTY Count:1
[trace] LoopHoistProfiler:
[trace] Opcode: LOAD_BUILTIN_OBJECT Count:1
[trace] Opcode: LOAD_PROPERTY Count:1
[trace] LoopHoistProfiler:
[trace] Opcode: LOAD_BUILTIN_OBJECT Count:1
[trace] Opcode: LOAD_PROPERTY Count:1
[trace] LoopHoistProfiler:
[trace] Opcode: LOAD_BUILTIN_OBJECT Count:1
[trace] Opcode: LOAD_PROPERTY Count:1

View File

@ -0,0 +1,51 @@
/*
* Copyright (c) 2023 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.
*/
declare var ArkTools:any;
for (let i = 0; i < 10; ++i) {
Math;
}
ArkTools.printLoopHoistProfilerAndReset();
for (let i = 0; i < 1; ++i) {
for (let j = 0; j < 10; ++j) {
Math;
}
}
ArkTools.printLoopHoistProfilerAndReset();
for (let i = 0; i < 10; ++i) {
Math.sqrt;
}
ArkTools.printLoopHoistProfilerAndReset();
for (let i = 0; i < 1; ++i) {
for (let j = 0; j < 10; ++j) {
Math.sqrt;
}
}
ArkTools.printLoopHoistProfilerAndReset();
for (let i = 0; i < 10; ++i) {
Math.sqrt(4);
}
ArkTools.printLoopHoistProfilerAndReset();
for (let i = 0; i < 1; ++i) {
for (let j = 0; j < 10; ++j) {
Math.sqrt(4);
}
}
ArkTools.printLoopHoistProfilerAndReset();

View File

@ -0,0 +1,13 @@
# Copyright (c) 2023 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.

View File

@ -695,6 +695,16 @@ template("host_aot_js_test_action") {
" --compiler-opt-inlining=true --compiler-opt-type-lowering=true"
}
if (defined(invoker.is_enable_loop_hoist_profiler) &&
invoker.is_enable_loop_hoist_profiler) {
_aot_compile_options_ += " --compiler-loop-hoist-profiler=true "
}
if (defined(invoker.is_enable_lowering_builtin) &&
invoker.is_enable_lowering_builtin) {
_aot_compile_options_ += " --compiler-enable-lowering-builtin=true"
}
if (defined(invoker.is_enable_native_inline) &&
invoker.is_enable_native_inline) {
_aot_compile_options_ += " --compiler-enable-native-inline"
@ -772,6 +782,20 @@ template("host_aot_js_test_action") {
_aot_run_options_ += " --enable-force-gc=false"
}
if (defined(invoker.log_option)) {
_aot_run_options_ += invoker.log_option
}
if (defined(invoker.is_enable_loop_hoist_profiler) &&
invoker.is_enable_loop_hoist_profiler) {
_aot_run_options_ += " --compiler-loop-hoist-profiler=ture"
}
if (defined(invoker.is_enable_lowering_builtin) &&
invoker.is_enable_lowering_builtin) {
_aot_run_options_ += " --compiler-enable-lowering-builtin=true"
}
_icu_data_path_options_ =
" --icu-data-path=" + rebase_path("//third_party/icu/ohos_icu4j/data")
_aot_run_options_ += _icu_data_path_options_
@ -834,6 +858,16 @@ template("host_aot_js_test_action") {
_aot_run_options_ += invoker.log_option
}
if (defined(invoker.is_enable_loop_hoist_profiler) &&
invoker.is_enable_loop_hoist_profiler) {
_aot_run_options_ += " --compiler-loop-hoist-profiler=ture"
}
if (defined(invoker.is_enable_lowering_builtin) &&
invoker.is_enable_lowering_builtin) {
_aot_run_options_ += " --compiler-enable-lowering-builtin=true"
}
_icu_data_path_options_ =
" --icu-data-path=" + rebase_path("//third_party/icu/ohos_icu4j/data")
_aot_run_options_ += _icu_data_path_options_
@ -1011,6 +1045,16 @@ template("host_aot_test_action") {
" --compiler-opt-inlining=true --compiler-opt-type-lowering=true"
}
if (defined(invoker.is_enable_loop_hoist_profiler) &&
invoker.is_enable_loop_hoist_profiler) {
_aot_compile_options_ += " --compiler-loop-hoist-profiler=true "
}
if (defined(invoker.is_enable_lowering_builtin) &&
invoker.is_enable_lowering_builtin) {
_aot_compile_options_ += " --compiler-enable-lowering-builtin=true"
}
if (defined(invoker.is_enable_native_inline) &&
invoker.is_enable_native_inline) {
_aot_compile_options_ += " --compiler-enable-native-inline"
@ -1185,6 +1229,16 @@ template("host_aot_test_action") {
_aot_run_options_ += invoker.log_option
}
if (defined(invoker.is_enable_loop_hoist_profiler) &&
invoker.is_enable_loop_hoist_profiler) {
_aot_run_options_ += " --compiler-loop-hoist-profiler=ture"
}
if (defined(invoker.is_enable_lowering_builtin) &&
invoker.is_enable_lowering_builtin) {
_aot_run_options_ += " --compiler-enable-lowering-builtin=true"
}
args = [
"--script-file",
rebase_path(_root_out_dir_) + "/arkcompiler/ets_runtime/ark_js_vm",
@ -1246,6 +1300,16 @@ template("host_aot_test_action") {
}
_aot_run_options_ += " --enable-context=true"
if (defined(invoker.is_enable_loop_hoist_profiler) &&
invoker.is_enable_loop_hoist_profiler) {
_aot_run_options_ += " --compiler-loop-hoist-profiler=ture"
}
if (defined(invoker.is_enable_lowering_builtin) &&
invoker.is_enable_lowering_builtin) {
_aot_run_options_ += " --compiler-enable-lowering-builtin=true"
}
args = [
"--script-file",
rebase_path(_root_out_dir_) + "/arkcompiler/ets_runtime/ark_js_vm",