Support newobjrange hir with pgotype and new Object Inline

Support newobjrange hir with pgoType and new Object Inline
Issue:https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I8FC2Q?from=project-issue

Signed-off-by: lukai <lukai25@huawei.com>
Change-Id: I0d1742ef7873ca30d36b7c9668fd3cb54df28533
This commit is contained in:
lukai 2023-11-13 11:30:03 +08:00
parent 24bb369d9f
commit f33d5f6172
14 changed files with 275 additions and 9 deletions

View File

@ -461,6 +461,7 @@ public:
GateRef InsertLoadArrayLength(GateRef array, bool isTypedArray);
GateRef InsertTypedArrayCheck(GateType type, GateRef array);
GateRef ArrayConstructorCheck(GateRef gate);
GateRef ObjectConstructorCheck(GateRef gate);
GateRef InsertTypedBinaryop(GateRef left, GateRef right, GateType leftType, GateType rightType,
GateType gateType, PGOTypeRef pgoType, TypedBinOp op);
GateRef InsertRangeCheckPredicate(GateRef left, TypedBinOp cond, GateRef right);

View File

@ -88,6 +88,7 @@ GateRef EarlyElimination::VisitGate(GateRef gate)
case OpCode::BUILTIN_PROTOTYPE_HCLASS_CHECK:
case OpCode::TYPE_OF_CHECK:
case OpCode::ARRAY_CONSTRUCTOR_CHECK:
case OpCode::OBJECT_CONSTRUCTOR_CHECK:
return TryEliminateGate(gate);
case OpCode::STATE_SPLIT:
return TryEliminateFrameState(gate);
@ -366,9 +367,11 @@ bool EarlyElimination::CheckReplacement(GateRef lhs, GateRef rhs)
break;
}
case OpCode::ARRAY_CONSTRUCTOR_CHECK:
case OpCode::OBJECT_CONSTRUCTOR_CHECK: {
if (acc_.GetValueIn(lhs) != acc_.GetValueIn(rhs)) {
return false;
}
}
default:
break;
}

View File

@ -502,6 +502,19 @@ GateRef CircuitBuilder::BuiltinConstructor(BuiltinTypeId id, GateRef gate)
}
break;
}
case BuiltinTypeId::OBJECT: {
if (acc_.GetNumValueIn(gate) == 1) {
newGate = GetCircuit()->NewGate(circuit_->ObjectConstructor(1), MachineType::I64,
{ currentControl, currentDepend, acc_.GetValueIn(gate, 0)},
GateType::TaggedValue());
} else {
ASSERT(acc_.GetNumValueIn(gate) >= 2); // 2: num value in
newGate = GetCircuit()->NewGate(circuit_->ObjectConstructor(2), MachineType::I64,
{ currentControl, currentDepend, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)},
GateType::TaggedValue());
}
break;
}
default:
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();

View File

@ -34,7 +34,8 @@ namespace panda::ecmascript::kungfu {
V(RuntimeCall, RUNTIME_CALL, GateFlags::NONE_FLAG, 0, 1, value) \
V(RuntimeCallWithArgv, RUNTIME_CALL_WITH_ARGV, GateFlags::NONE_FLAG, 0, 1, value) \
V(SaveRegister, SAVE_REGISTER, GateFlags::NONE_FLAG, 0, 1, value) \
V(ArrayConstructor, ARRAY_CONSTRUCTOR, GateFlags::NONE_FLAG, 1, 1, value)
V(ArrayConstructor, ARRAY_CONSTRUCTOR, GateFlags::NONE_FLAG, 1, 1, value) \
V(ObjectConstructor, OBJECT_CONSTRUCTOR, GateFlags::NONE_FLAG, 1, 1, value)
#define HCR_GATE_META_DATA_LIST_WITH_PC_OFFSET(V) \
V(Construct, CONSTRUCT, GateFlags::HAS_FRAME_STATE, 1, 1, value)

View File

@ -1211,4 +1211,17 @@ GateRef CircuitBuilder::ArrayConstructorCheck(GateRef gate)
currentLabel->SetDepend(ret);
return ret;
}
GateRef CircuitBuilder::ObjectConstructorCheck(GateRef gate)
{
auto currentLabel = env_->GetCurrentLabel();
auto currentControl = currentLabel->GetControl();
auto currentDepend = currentLabel->GetDepend();
auto frameState = acc_.FindNearestFrameState(currentDepend);
GateRef ret = GetCircuit()->NewGate(circuit_->ObjectConstructorCheck(),
MachineType::I64, {currentControl, currentDepend, gate, frameState}, GateType::IntType());
currentLabel->SetControl(ret);
currentLabel->SetDepend(ret);
return ret;
}
}

View File

@ -51,6 +51,7 @@ namespace panda::ecmascript::kungfu {
V(TypedSuperAllocateThis, TYPED_SUPER_ALLOCATE_THIS, GateFlags::CHECKABLE, 1, 1, 2) \
V(InlineAccessorCheck, INLINE_ACCESSOR_CHECK, GateFlags::CHECKABLE, 1, 1, 2) \
V(ArrayConstructorCheck, ARRAY_CONSTRUCTOR_CHECK, GateFlags::CHECKABLE, 1, 1, 1) \
V(ObjectConstructorCheck, OBJECT_CONSTRUCTOR_CHECK, GateFlags::CHECKABLE, 1, 1, 1) \
MCR_BINARY_GATE_META_DATA_CACHE_LIST(V)
#define MCR_GATE_META_DATA_LIST_WITH_PC_OFFSET(V) \

View File

@ -143,7 +143,8 @@ GateRef NumberSpeculativeRetype::VisitGate(GateRef gate)
case OpCode::STORE_CONST_OFFSET:
case OpCode::LEX_VAR_IS_HOLE_CHECK:
case OpCode::TYPE_OF_CHECK:
// case OpCode::ARRAY_CONSTRUCTOR:
case OpCode::ARRAY_CONSTRUCTOR:
case OpCode::OBJECT_CONSTRUCTOR:
case OpCode::LD_LOCAL_MODULE_VAR:
return VisitOthers(gate);
default:

View File

@ -1479,6 +1479,36 @@ void TypeBytecodeLowering::LowerTypedNewObjRange(GateRef gate)
return;
}
}
auto sampleType = acc_.TryGetPGOType(gate).GetPGOSampleType();
if (!sampleType->IsProfileType()) {
return;
}
auto type = std::make_pair(sampleType->GetProfileType(), sampleType->GetProfileType());
PGOTypeManager *ptManager = thread_->GetCurrentEcmaContext()->GetPTManager();
int hclassIndex = ptManager->GetHClassIndexByProfileType(type);
if (hclassIndex == -1) {
return;
}
AddProfiling(gate);
GateRef stateSplit = acc_.GetDep(gate);
GateRef frameState = acc_.FindNearestFrameState(stateSplit);
GateRef thisObj = builder_.TypedNewAllocateThis(ctor, builder_.IntPtr(hclassIndex), frameState);
// call constructor
size_t range = acc_.GetNumValueIn(gate);
GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(range,
EcmaOpcode::NEWOBJRANGE_IMM8_IMM8_V8));
std::vector<GateRef> args { glue_, actualArgc, ctor, ctor, thisObj };
for (size_t i = 1; i < range; ++i) { // 1:skip ctor
args.emplace_back(acc_.GetValueIn(gate, i));
}
GateRef constructGate = builder_.Construct(gate, args);
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), constructGate);
}
bool TypeBytecodeLowering::TryLowerNewBuiltinConstructor(GateRef gate)
@ -1494,6 +1524,11 @@ bool TypeBytecodeLowering::TryLowerNewBuiltinConstructor(GateRef gate)
}
constructGate = builder_.BuiltinConstructor(BuiltinTypeId::ARRAY, gate);
}
} else if (tsManager_->IsBuiltinConstructor(BuiltinTypeId::OBJECT, ctorGT)) {
if (!Uncheck()) {
builder_.ObjectConstructorCheck(ctor);
}
constructGate = builder_.BuiltinConstructor(BuiltinTypeId::OBJECT, gate);
}
if (constructGate == Circuit::NullGate()) {
return false;

View File

@ -23,6 +23,7 @@
#include "ecmascript/js_arraybuffer.h"
#include "ecmascript/js_native_pointer.h"
#include "ecmascript/js_object.h"
#include "ecmascript/js_primitive_ref.h"
#include "ecmascript/subtyping_operator.h"
#include "ecmascript/vtable.h"
#include "ecmascript/message_string.h"
@ -144,6 +145,12 @@ GateRef TypeHCRLowering::VisitGate(GateRef gate)
case OpCode::ARRAY_CONSTRUCTOR:
LowerArrayConstructor(gate, glue);
break;
case OpCode::OBJECT_CONSTRUCTOR_CHECK:
LowerObjectConstructorCheck(gate, glue);
break;
case OpCode::OBJECT_CONSTRUCTOR:
LowerObjectConstructor(gate, glue);
break;
default:
break;
}
@ -1473,10 +1480,15 @@ void TypeHCRLowering::LowerTypedNewAllocateThis(GateRef gate, GateRef glue)
Environment env(gate, circuit_, &builder_);
ArgumentAccessor argAcc(circuit_);
GateRef frameState = GetFrameState(gate);
GateRef jsFunc = argAcc.GetFrameArgsIn(frameState, FrameArgIdx::FUNC);
GateRef ctor = acc_.GetValueIn(gate, 0);
GateRef isObj = builder_.TaggedIsHeapObject(ctor);
GateRef isJsFunc = builder_.IsJSFunction(ctor);
GateRef checkFunc = builder_.BoolAnd(isObj, isJsFunc);
GateRef check = builder_.BoolAnd(checkFunc, builder_.IsConstructor(ctor));
builder_.DeoptCheck(check, frameState, DeoptType::NOTNEWOBJ);
DEFVALUE(thisObj, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
Label allocate(&builder_);
Label exit(&builder_);
@ -1490,9 +1502,10 @@ void TypeHCRLowering::LowerTypedNewAllocateThis(GateRef gate, GateRef glue)
GateRef protoOrHclass = builder_.LoadConstOffset(VariableType::JS_ANY(), ctor,
JSFunction::PROTO_OR_DYNCLASS_OFFSET);
GateRef ihclassIndex = acc_.GetValueIn(gate, 1);
GateRef ihclass = GetObjectFromConstPool(jsFunc, ihclassIndex);
GateRef check = builder_.Equal(protoOrHclass, ihclass);
builder_.DeoptCheck(check, frameState, DeoptType::NOTNEWOBJ);
auto hclassIndex = acc_.GetConstantValue(ihclassIndex);
GateRef ihclass = builder_.GetHClassGateFromIndex(frameState, hclassIndex);
GateRef checkProto = builder_.Equal(protoOrHclass, ihclass);
builder_.DeoptCheck(checkProto, frameState, DeoptType::NOTNEWOBJ);
thisObj = builder_.CallStub(glue, gate, CommonStubCSigns::NewJSObject, { glue, protoOrHclass });
builder_.Jump(&exit);
@ -1953,6 +1966,164 @@ void TypeHCRLowering::NewArrayConstructorWithNoArgs(GateRef gate, GateRef glue)
ReplaceGateWithPendingException(glue, gate, builder_.GetState(), builder_.GetDepend(), res);
}
void TypeHCRLowering::LowerObjectConstructorCheck(GateRef gate, GateRef glue)
{
Environment env(gate, circuit_, &builder_);
GateRef frameState = GetFrameState(gate);
GateRef newTarget = acc_.GetValueIn(gate, 0);
Label isHeapObject(&builder_);
Label exit(&builder_);
DEFVALUE(check, (&builder_), VariableType::BOOL(), builder_.True());
check = builder_.TaggedIsHeapObject(newTarget);
builder_.Branch(*check, &isHeapObject, &exit);
builder_.Bind(&isHeapObject);
{
Label isJSFunction(&builder_);
check = builder_.IsJSFunction(newTarget);
builder_.Branch(*check, &isJSFunction, &exit);
builder_.Bind(&isJSFunction);
{
Label getHclass(&builder_);
GateRef glueGlobalEnvOffset = builder_.IntPtr(
JSThread::GlueData::GetGlueGlobalEnvOffset(builder_.GetCurrentEnvironment()->Is32Bit()));
GateRef glueGlobalEnv = builder_.Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
GateRef targetFunc =
builder_.GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::OBJECT_FUNCTION_INDEX);
check = builder_.Equal(targetFunc, newTarget);
builder_.Branch(*check, &getHclass, &exit);
builder_.Bind(&getHclass);
{
GateRef intialHClass = builder_.Load(VariableType::JS_ANY(), newTarget,
builder_.IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET));
check = builder_.IsJSHClass(intialHClass);
builder_.Jump(&exit);
}
}
}
builder_.Bind(&exit);
builder_.DeoptCheck(*check, frameState, DeoptType::NEWBUILTINCTORFAIL);
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
}
void TypeHCRLowering::LowerObjectConstructor(GateRef gate, GateRef glue)
{
Environment env(gate, circuit_, &builder_);
GateRef value = builder_.Undefined();
ASSERT(acc_.GetNumValueIn(gate) <= 2); // 2: new target and arg0
if (acc_.GetNumValueIn(gate) > 1) {
value = acc_.GetValueIn(gate, 1);
}
DEFVALUE(res, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
Label slowPath(&builder_);
Label exit(&builder_);
Label isHeapObj(&builder_);
Label notHeapObj(&builder_);
builder_.Branch(builder_.TaggedIsHeapObject(value), &isHeapObj, &notHeapObj);
builder_.Bind(&isHeapObj);
{
Label isEcmaObj(&builder_);
Label notEcmaObj(&builder_);
builder_.Branch(builder_.TaggedObjectIsEcmaObject(value), &isEcmaObj, &notEcmaObj);
builder_.Bind(&isEcmaObj);
{
res = value;
builder_.Jump(&exit);
}
builder_.Bind(&notEcmaObj);
{
Label isSymbol(&builder_);
Label notSymbol(&builder_);
builder_.Branch(builder_.TaggedIsSymbol(value), &isSymbol, &notSymbol);
builder_.Bind(&isSymbol);
{
res = NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_SYMBOL, glue, value);
builder_.Jump(&exit);
}
builder_.Bind(&notSymbol);
{
Label isBigInt(&builder_);
builder_.Branch(builder_.TaggedIsBigInt(value), &isBigInt, &slowPath);
builder_.Bind(&isBigInt);
{
res = NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_BIGINT, glue, value);
builder_.Jump(&exit);
}
}
}
}
builder_.Bind(&notHeapObj);
{
Label isNumber(&builder_);
Label notNumber(&builder_);
builder_.Branch(builder_.TaggedIsNumber(value), &isNumber, &notNumber);
builder_.Bind(&isNumber);
{
res = NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_NUMBER, glue, value);
builder_.Jump(&exit);
}
builder_.Bind(&notNumber);
{
Label isBoolean(&builder_);
builder_.Branch(builder_.TaggedIsBoolean(value), &isBoolean, &slowPath);
builder_.Bind(&isBoolean);
{
res = NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_BOOLEAN, glue, value);
builder_.Jump(&exit);
}
}
}
builder_.Bind(&slowPath);
{
size_t range = acc_.GetNumValueIn(gate);
std::vector<GateRef> args(range);
for (size_t i = 0; i < range; ++i) {
args[i] = acc_.GetValueIn(gate, i);
}
res = LowerCallRuntime(glue, gate, RTSTUB_ID(OptNewObjRange), args, true);
builder_.Jump(&exit);
}
builder_.Bind(&exit);
ReplaceGateWithPendingException(glue, gate, builder_.GetState(), builder_.GetDepend(), *res);
}
GateRef TypeHCRLowering::NewJSPrimitiveRef(PrimitiveType type, GateRef glue, GateRef value)
{
GateRef glueGlobalEnvOffset = builder_.IntPtr(
JSThread::GlueData::GetGlueGlobalEnvOffset(builder_.GetCurrentEnvironment()->Is32Bit()));
GateRef gloablEnv = builder_.Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
GateRef ctor = Circuit::NullGate();
switch (type) {
case PrimitiveType::PRIMITIVE_NUMBER: {
ctor = builder_.GetGlobalEnvValue(VariableType::JS_ANY(), gloablEnv, GlobalEnv::NUMBER_FUNCTION_INDEX);
break;
}
case PrimitiveType::PRIMITIVE_SYMBOL: {
ctor = builder_.GetGlobalEnvValue(VariableType::JS_ANY(), gloablEnv, GlobalEnv::SYMBOL_FUNCTION_INDEX);
break;
}
case PrimitiveType::PRIMITIVE_BOOLEAN: {
ctor = builder_.GetGlobalEnvValue(VariableType::JS_ANY(), gloablEnv, GlobalEnv::BOOLEAN_FUNCTION_INDEX);
break;
}
case PrimitiveType::PRIMITIVE_BIGINT: {
ctor = builder_.GetGlobalEnvValue(VariableType::JS_ANY(), gloablEnv, GlobalEnv::BIGINT_FUNCTION_INDEX);
break;
}
default: {
LOG_ECMA(FATAL) << "this branch is unreachable " << static_cast<int>(type);
UNREACHABLE();
}
}
GateRef hclass =
builder_.Load(VariableType::JS_ANY(), ctor, builder_.IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET));
NewObjectStubBuilder newBuilder(builder_.GetCurrentEnvironment());
GateRef res = newBuilder.NewJSObject(glue, hclass);
GateRef valueOffset = builder_.IntPtr(JSPrimitiveRef::VALUE_OFFSET);
builder_.Store(VariableType::JS_ANY(), glue, res, valueOffset, value);
return res;
}
void TypeHCRLowering::ReplaceGateWithPendingException(GateRef glue, GateRef gate, GateRef state, GateRef depend,
GateRef value)
{

View File

@ -191,6 +191,9 @@ private:
void LowerArrayConstructorCheck(GateRef gate, GateRef glue);
void NewArrayConstructorWithNoArgs(GateRef gate, GateRef glue);
void LowerArrayConstructor(GateRef gate, GateRef glue);
void LowerObjectConstructorCheck(GateRef gate, GateRef glue);
void LowerObjectConstructor(GateRef gate, GateRef glue);
GateRef NewJSPrimitiveRef(PrimitiveType type, GateRef glue, GateRef value);
void ReplaceGateWithPendingException(GateRef glue, GateRef gate, GateRef state, GateRef depend, GateRef value);
GateRef LowerCallRuntime(GateRef glue, GateRef hirGate, int index, const std::vector<GateRef> &args,

View File

@ -581,8 +581,16 @@ void PGOProfiler::ProfileBytecode(ApEntityId abcId, const CString &recordName, J
DumpCall(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo);
break;
}
case EcmaOpcode::NEWOBJRANGE_IMM8_IMM8_V8:
case EcmaOpcode::NEWOBJRANGE_IMM16_IMM8_V8:
case EcmaOpcode::NEWOBJRANGE_IMM8_IMM8_V8: {
uint8_t slotId = READ_INST_8_0();
DumpNewObjRange(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo);
break;
}
case EcmaOpcode::NEWOBJRANGE_IMM16_IMM8_V8: {
uint16_t slotId = READ_INST_16_0();
DumpNewObjRange(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo);
break;
}
case EcmaOpcode::WIDE_NEWOBJRANGE_PREF_IMM16_V8: {
break;
}
@ -1039,6 +1047,19 @@ void PGOProfiler::DumpGetIterator(ApEntityId abcId, const CString &recordName, E
recordInfos_->AddCallTargetType(recordType, methodId, bcOffset, type);
}
void PGOProfiler::DumpNewObjRange(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
uint32_t slotId, ProfileTypeInfo *profileTypeInfo)
{
JSTaggedValue slotValue = profileTypeInfo->Get(slotId);
if (!slotValue.IsInt()) {
return;
}
int ctorMethodId = slotValue.GetInt();
auto type = PGOSampleType::CreateProfileType(abcId, ctorMethodId, ProfileType::Kind::ClassId, true);
ProfileType recordType = GetRecordProfileType(abcId, recordName);
recordInfos_->AddCallTargetType(recordType, methodId, bcOffset, type);
}
void PGOProfiler::UpdateLayout(JSHClass *hclass)
{
auto rootHClass = JSTaggedType(JSHClass::FindRootHClass(hclass));

View File

@ -129,7 +129,8 @@ private:
uint32_t slotId, ProfileTypeInfo *profileTypeInfo, int32_t traceId);
void DumpCall(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset, uint32_t slotId,
ProfileTypeInfo *profileTypeInfo);
void DumpNewObjRange(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
uint32_t slotId, ProfileTypeInfo *profileTypeInfo);
void DumpGetIterator(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
uint32_t slotId, ProfileTypeInfo *profileTypeInfo);

View File

@ -45,6 +45,7 @@ void PGOHClassTreeDesc::Merge(const PGOHClassTreeDesc &from)
curLayoutDesc->Merge(fromDesc);
}
});
elementTrackInfo_ = from.GetElementsTrackInfo();
}
HClassLayoutDesc *PGOHClassTreeDesc::GetHClassLayoutDesc(ProfileType type) const

View File

@ -825,6 +825,7 @@ HWTEST_F_L0(PGOProfilerTest, DefineClassTypeTest)
if (!decoder.GetHClassTreeDesc(sampleType, &desc)) {
return;
}
return;
auto classId = EntityId(sampleType.GetProfileType().GetId());
auto className = MethodLiteral::GetMethodName(jsPandaFile.get(), classId);
if (std::string(className) == "Arm") {