mirror of
https://gitee.com/openharmony/arkcompiler_ets_runtime
synced 2024-12-04 09:13:37 +00:00
Some TsAot Inline Modification
1. Resolves conflicts between inline and loop optimizations 2. Adds an inline target check to prevent changes 3. Modify the framestate metadata structure 4. Add inline testcase ISSUE:https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I73MZY Signed-off-by: ginxu <xujie101@huawei.com> Change-Id: I4256b3edce3e901afb67d48b0e649f39f6c251a4
This commit is contained in:
parent
b266e4cbc8
commit
d88428b060
@ -530,14 +530,16 @@ void BytecodeCircuitBuilder::BuildCircuitArgs()
|
||||
|
||||
void BytecodeCircuitBuilder::BuildFrameArgs()
|
||||
{
|
||||
size_t numArgs = static_cast<size_t>(FrameArgIdx::NUM_OF_ARGS);
|
||||
auto metaData = circuit_->FrameArgs();
|
||||
size_t numArgs = static_cast<size_t>(FrameArgIdx::NUM_OF_ARGS) + metaData->GetInFrameStateCount();
|
||||
std::vector<GateRef> args(numArgs, Circuit::NullGate());
|
||||
size_t idx = 0;
|
||||
args[idx++] = argAcc_.GetCommonArgGate(CommonArgIdx::FUNC);
|
||||
args[idx++] = argAcc_.GetCommonArgGate(CommonArgIdx::NEW_TARGET);
|
||||
args[idx++] = argAcc_.GetCommonArgGate(CommonArgIdx::THIS_OBJECT);
|
||||
args[idx++] = argAcc_.GetCommonArgGate(CommonArgIdx::ACTUAL_ARGC);
|
||||
GateRef frameArgs = circuit_->NewGate(circuit_->FrameArgs(), args);
|
||||
args[idx++] = circuit_->ReplaceableGate();
|
||||
GateRef frameArgs = circuit_->NewGate(metaData, args);
|
||||
argAcc_.SetFrameArgs(frameArgs);
|
||||
}
|
||||
|
||||
|
@ -464,21 +464,16 @@ public:
|
||||
return hasTryCatch_;
|
||||
}
|
||||
|
||||
GateRef GetFrameStateByIndex(size_t idx) const
|
||||
{
|
||||
return frameStateBuilder_.GetFrameStateByIndex(idx);
|
||||
}
|
||||
|
||||
size_t GetNumOfFrameState() const
|
||||
{
|
||||
return frameStateBuilder_.GetNumOfFrameState();
|
||||
}
|
||||
|
||||
bool EnableLoopOptimization() const
|
||||
{
|
||||
return (!HasTryCatch()) && (loopHeads_.size() != 0);
|
||||
}
|
||||
|
||||
GateRef GetFrameArgs() const
|
||||
{
|
||||
return argAcc_.GetFrameArgs();
|
||||
}
|
||||
|
||||
private:
|
||||
void CollectTryCatchBlockInfo(ExceptionInfo &Exception);
|
||||
void BuildCatchBlocks(const ExceptionInfo &Exception);
|
||||
|
@ -169,6 +169,8 @@ BytecodeMetaData BytecodeMetaData::InitBytecodeMetaData(const uint8_t *pc)
|
||||
case EcmaOpcode::WIDE_NEWOBJRANGE_PREF_IMM16_V8:
|
||||
case EcmaOpcode::SUPERCALLTHISRANGE_IMM8_IMM8_V8:
|
||||
case EcmaOpcode::WIDE_SUPERCALLTHISRANGE_PREF_IMM16_V8:
|
||||
flags |= BytecodeFlags::SUPPORT_DEOPT;
|
||||
break;
|
||||
case EcmaOpcode::CALLTHIS1_IMM8_V8_V8:
|
||||
case EcmaOpcode::CALLARG0_IMM8:
|
||||
case EcmaOpcode::CALLARG1_IMM8_V8:
|
||||
@ -180,6 +182,7 @@ BytecodeMetaData BytecodeMetaData::InitBytecodeMetaData(const uint8_t *pc)
|
||||
case EcmaOpcode::CALLTHIS3_IMM8_V8_V8_V8_V8:
|
||||
case EcmaOpcode::CALLTHISRANGE_IMM8_IMM8_V8:
|
||||
flags |= BytecodeFlags::SUPPORT_DEOPT;
|
||||
kind = BytecodeKind::CALL_BC;
|
||||
break;
|
||||
case EcmaOpcode::RETURN:
|
||||
flags |= BytecodeFlags::READ_ACC;
|
||||
@ -356,7 +359,8 @@ BytecodeMetaData BytecodeMetaData::InitBytecodeMetaData(const uint8_t *pc)
|
||||
kind == BytecodeKind::THROW_BC ||
|
||||
kind == BytecodeKind::RESUME ||
|
||||
kind == BytecodeKind::SUSPEND ||
|
||||
kind == BytecodeKind::GENERATOR_RESOLVE) {
|
||||
kind == BytecodeKind::GENERATOR_RESOLVE ||
|
||||
kind == BytecodeKind::CALL_BC) {
|
||||
flags |= BytecodeFlags::GENERAL_BC;
|
||||
}
|
||||
auto size = inst.GetSize();
|
||||
|
@ -63,6 +63,7 @@ enum BytecodeKind : uint32_t {
|
||||
RESUME,
|
||||
GENERATOR_RESOLVE,
|
||||
DISCARDED,
|
||||
CALL_BC,
|
||||
};
|
||||
|
||||
class BytecodeMetaData {
|
||||
@ -209,6 +210,11 @@ public:
|
||||
return value_ == 0;
|
||||
}
|
||||
|
||||
bool IsCall() const
|
||||
{
|
||||
return GetKind() == BytecodeKind::CALL_BC;
|
||||
}
|
||||
|
||||
private:
|
||||
BytecodeMetaData() = default;
|
||||
DEFAULT_NOEXCEPT_MOVE_SEMANTIC(BytecodeMetaData);
|
||||
@ -630,6 +636,11 @@ public:
|
||||
return HasFuncIn() || HasNewTargetIn() || ThisObjectIn() || HasArgcIn();
|
||||
}
|
||||
|
||||
bool IsCall() const
|
||||
{
|
||||
return metaData_.IsCall();
|
||||
}
|
||||
|
||||
inline EcmaOpcode GetOpcode() const
|
||||
{
|
||||
return metaData_.GetOpcode();
|
||||
|
@ -177,7 +177,7 @@ public:
|
||||
|
||||
GateRef DeadGate()
|
||||
{
|
||||
if (dead_ == 0) {
|
||||
if (dead_ == NullGate()) {
|
||||
dead_ = NewGate(Dead(), MachineType::NOVALUE, GateType::Empty());
|
||||
}
|
||||
return dead_;
|
||||
@ -196,6 +196,14 @@ public:
|
||||
|
||||
bool GetDebugInfo(GateRef g, size_t &index) const;
|
||||
|
||||
GateRef ReplaceableGate()
|
||||
{
|
||||
if (replaceable_ == NullGate()) {
|
||||
replaceable_ = NewGate(Replaceable(), MachineType::NOVALUE, GateType::Empty());
|
||||
}
|
||||
return replaceable_;
|
||||
}
|
||||
|
||||
private:
|
||||
static const size_t CIRCUIT_SPACE = 1U << 30U; // 1GB
|
||||
|
||||
@ -251,8 +259,9 @@ private:
|
||||
bool isArch64_ { false };
|
||||
|
||||
Chunk chunk_;
|
||||
GateRef root_ { 0 };
|
||||
GateRef dead_ { 0 };
|
||||
GateRef root_ { NullGate() };
|
||||
GateRef dead_ { NullGate() };
|
||||
GateRef replaceable_ { NullGate() };
|
||||
GateMetaBuilder metaBuilder_;
|
||||
ChunkMap<GateRef, size_t> gateToDInfo_;
|
||||
DebugInfo* debugInfo_ {nullptr};
|
||||
|
@ -1029,6 +1029,16 @@ inline GateRef CircuitBuilder::TypedCallBuiltin(GateRef hirGate, GateRef x, Buil
|
||||
return numberMathOp;
|
||||
}
|
||||
|
||||
inline GateRef CircuitBuilder::GetMethodId(GateRef func)
|
||||
{
|
||||
GateRef method = GetMethodFromFunction(func);
|
||||
GateRef literalInfoOffset = IntPtr(Method::LITERAL_INFO_OFFSET);
|
||||
GateRef LiteralInfo = Load(VariableType::INT64(), method, literalInfoOffset);
|
||||
GateRef methodId = Int64And(Int64LSR(LiteralInfo, Int64(MethodLiteral::MethodIdBits::START_BIT)),
|
||||
Int64((1LLU << MethodLiteral::MethodIdBits::SIZE) - 1));
|
||||
return methodId;
|
||||
}
|
||||
|
||||
void Label::Seal()
|
||||
{
|
||||
return impl_->Seal();
|
||||
|
@ -434,7 +434,7 @@ GateRef CircuitBuilder::DeoptCheck(GateRef condition, GateRef frameState, DeoptT
|
||||
std::vector<GateRef> vec{frameState};
|
||||
auto it = vec.begin();
|
||||
GateRef preFrameState = acc_.GetPreFrameState(frameState);
|
||||
while (preFrameState != Circuit::NullGate()) {
|
||||
while (acc_.GetOpCode(preFrameState) != OpCode::REPLACEABLE) {
|
||||
vec.insert(it, preFrameState);
|
||||
preFrameState = acc_.GetPreFrameState(preFrameState);
|
||||
}
|
||||
|
@ -592,6 +592,7 @@ public:
|
||||
GateRef GetGlobalEnvValue(VariableType type, GateRef env, size_t index);
|
||||
GateRef GetGlobalConstantValue(VariableType type, GateRef glue, ConstantIndex index);
|
||||
GateRef IsBase(GateRef ctor);
|
||||
inline GateRef GetMethodId(GateRef func);
|
||||
|
||||
private:
|
||||
#define ARITHMETIC_UNARY_OP_WITH_BITWIDTH(NAME, OPCODEID, MACHINETYPEID) \
|
||||
|
@ -75,7 +75,6 @@ void FrameStateBuilder::BindStateSplit(GateRef state, GateRef depend,
|
||||
size_t pcOffset, FrameStateInfo *stateInfo)
|
||||
{
|
||||
GateRef frameState = FrameState(pcOffset, stateInfo);
|
||||
frameStateList_.emplace_back(frameState);
|
||||
GateRef stateSplit = circuit_->NewGate(circuit_->StateSplit(), {state, depend, frameState});
|
||||
auto uses = gateAcc_.Uses(depend);
|
||||
for (auto useIt = uses.begin(); useIt != uses.end();) {
|
||||
@ -98,7 +97,6 @@ void FrameStateBuilder::BindStateSplit(GateRef gate, size_t pcOffset, FrameState
|
||||
state = gateAcc_.GetState(state);
|
||||
}
|
||||
GateRef frameState = FrameState(pcOffset, stateInfo);
|
||||
frameStateList_.emplace_back(frameState);
|
||||
GateRef stateSplit = circuit_->NewGate(circuit_->StateSplit(), {state, depend, frameState});
|
||||
gateAcc_.ReplaceDependIn(gate, stateSplit);
|
||||
if (builder_->IsLogEnabled()) {
|
||||
@ -344,7 +342,6 @@ void FrameStateBuilder::BuildFrameState(GateRef frameArgs)
|
||||
bcEndStateInfos_.resize(builder_->GetLastBcIndex() + 1, nullptr); // 1: +1 pcOffsets size
|
||||
auto size = builder_->GetBasicBlockCount();
|
||||
bbBeginStateInfos_.resize(size, nullptr);
|
||||
frameStateList_.clear();
|
||||
liveOutResult_ = CreateEmptyStateInfo();
|
||||
BuildPostOrderList(size);
|
||||
ComputeLiveState();
|
||||
@ -443,6 +440,9 @@ void FrameStateBuilder::BindStateSplit(size_t size)
|
||||
builder_->EnumerateBlock(bb, [&](const BytecodeInfo &bytecodeInfo) -> bool {
|
||||
auto &iterator = bb.GetBytecodeIterator();
|
||||
auto index = iterator.Index();
|
||||
if (bytecodeInfo.IsCall()) {
|
||||
needStateSplit = true;
|
||||
}
|
||||
if (needStateSplit && NeedBindStateSplit(bb, bytecodeInfo, index)) {
|
||||
auto pcOffset = builder_->GetPcOffset(index);
|
||||
auto stateInfo = GetCurrentFrameInfo(bb, index);
|
||||
|
@ -76,14 +76,6 @@ public:
|
||||
~FrameStateBuilder();
|
||||
|
||||
void BuildFrameState(GateRef frameArgs);
|
||||
GateRef GetFrameStateByIndex(size_t idx) const
|
||||
{
|
||||
return frameStateList_.at(idx);
|
||||
}
|
||||
size_t GetNumOfFrameState() const
|
||||
{
|
||||
return frameStateList_.size();
|
||||
}
|
||||
|
||||
private:
|
||||
GateRef ValuesAt(size_t index) const
|
||||
@ -156,7 +148,6 @@ private:
|
||||
std::vector<FrameStateInfo *> bcEndStateInfos_;
|
||||
std::vector<FrameStateInfo *> bbBeginStateInfos_;
|
||||
std::vector<size_t> postOrderList_;
|
||||
std::vector<GateRef> frameStateList_;
|
||||
};
|
||||
} // panda::ecmascript::kungfu
|
||||
#endif // ECMASCRIPT_COMPILER_FRAME_STATE_H
|
||||
|
@ -1132,18 +1132,12 @@ bool ConstGateAccessor::IsSchedulable(GateRef g) const
|
||||
return GetMetaData(g)->IsSchedulable();
|
||||
}
|
||||
|
||||
void GateAccessor::SetPreFrameState(GateRef gate, GateRef preFrameState)
|
||||
{
|
||||
ASSERT(GetOpCode(gate) == OpCode::FRAME_STATE && GetOpCode(preFrameState) == OpCode::FRAME_STATE);
|
||||
Gate *gatePtr = circuit_->LoadGatePtr(gate);
|
||||
const_cast<FrameStateMetaData *>(gatePtr->GetFrameStateMetaData())->SetPreFrameState(preFrameState);
|
||||
}
|
||||
|
||||
GateRef GateAccessor::GetPreFrameState(GateRef gate) const
|
||||
{
|
||||
ASSERT(GetOpCode(gate) == OpCode::FRAME_STATE);
|
||||
Gate *gatePtr = circuit_->LoadGatePtr(gate);
|
||||
return gatePtr->GetFrameStateMetaData()->GetPreFrameState();
|
||||
GateRef frameArgs = GetFrameState(gate);
|
||||
GateRef preFrameState = GetFrameState(frameArgs);
|
||||
return preFrameState;
|
||||
}
|
||||
|
||||
void GateAccessor::SetInlineCallFrameStateFlag(GateRef gate, bool isInline)
|
||||
@ -1163,13 +1157,13 @@ bool GateAccessor::IsInlineCallFrameState(GateRef gate) const
|
||||
size_t GateAccessor::GetFrameStateDepth(GateRef gate) const
|
||||
{
|
||||
ASSERT(GetOpCode(gate) == OpCode::FRAME_STATE);
|
||||
Gate *gatePtr = circuit_->LoadGatePtr(gate);
|
||||
GateRef preFrameState = gatePtr->GetFrameStateMetaData()->GetPreFrameState();
|
||||
GateRef frameArgs = GetFrameState(gate);
|
||||
GateRef preFrameState = GetFrameState(frameArgs);
|
||||
size_t depth = 0;
|
||||
while (preFrameState != Circuit::NullGate()) {
|
||||
while (GetOpCode(preFrameState) != OpCode::REPLACEABLE) {
|
||||
if (GetOpCode(preFrameState) == OpCode::FRAME_STATE) {
|
||||
Gate *preGatePtr = circuit_->LoadGatePtr(preFrameState);
|
||||
preFrameState = preGatePtr->GetFrameStateMetaData()->GetPreFrameState();
|
||||
frameArgs = GetFrameState(preFrameState);
|
||||
preFrameState = GetFrameState(frameArgs);
|
||||
depth++;
|
||||
} else {
|
||||
break;
|
||||
|
@ -99,6 +99,7 @@ enum class DeoptType : uint8_t {
|
||||
DIVZERO,
|
||||
NEGTIVEINDEX,
|
||||
LARGEINDEX,
|
||||
INLINEFAIL,
|
||||
};
|
||||
|
||||
enum class ICmpCondition : uint8_t {
|
||||
@ -227,9 +228,10 @@ std::string MachineTypeToStr(MachineType machineType);
|
||||
V(GetSuperConstructor, GET_SUPER_CONSTRUCTOR, GateFlags::NO_WRITE, 1, 1, 1) \
|
||||
V(UpdateHotness, UPDATE_HOTNESS, GateFlags::NO_WRITE, 1, 1, 0) \
|
||||
V(Dead, DEAD, GateFlags::NONE_FLAG, 0, 0, 0) \
|
||||
V(FrameArgs, FRAME_ARGS, GateFlags::NONE_FLAG, 0, 0, 4) \
|
||||
V(FrameArgs, FRAME_ARGS, GateFlags::HAS_FRAME_STATE, 0, 0, 4) \
|
||||
V(GetEnv, GET_ENV, GateFlags::NONE_FLAG, 0, 0, 1) \
|
||||
V(ConvertHoleAsUndefined, CONVERT_HOLE_AS_UNDEFINED, GateFlags::NO_WRITE, 1, 1, 1) \
|
||||
V(Replaceable, REPLACEABLE, GateFlags::NONE_FLAG, 0, 0, 0) \
|
||||
BINARY_GATE_META_DATA_CACHE_LIST(V) \
|
||||
UNARY_GATE_META_DATA_CACHE_LIST(V)
|
||||
|
||||
@ -272,7 +274,8 @@ std::string MachineTypeToStr(MachineType machineType);
|
||||
V(TypedConditionJump, TYPED_CONDITION_JUMP, GateFlags::NO_WRITE, 1, 1, 1) \
|
||||
V(TypedConvert, TYPE_CONVERT, GateFlags::NO_WRITE, 1, 1, 1) \
|
||||
V(CheckAndConvert, CHECK_AND_CONVERT, GateFlags::NO_WRITE, 1, 1, 1) \
|
||||
V(Convert, CONVERT, GateFlags::NONE_FLAG, 0, 0, 1)
|
||||
V(Convert, CONVERT, GateFlags::NONE_FLAG, 0, 0, 1) \
|
||||
V(JSInlineTargetTypeCheck, JSINLINETARGET_TYPE_CHECK, GateFlags::CHECKABLE, 1, 1, 2)
|
||||
|
||||
#define GATE_META_DATA_LIST_WITH_VALUE(V) \
|
||||
V(Icmp, ICMP, GateFlags::NONE_FLAG, 0, 0, 2) \
|
||||
@ -697,12 +700,10 @@ private:
|
||||
|
||||
class FrameStateMetaData : public GateMetaData {
|
||||
public:
|
||||
static constexpr GateRef invalidGate = -1;
|
||||
FrameStateMetaData(uint64_t value)
|
||||
: GateMetaData(OpCode::FRAME_STATE, GateFlags::HAS_FRAME_STATE, 0, 0, value)
|
||||
{
|
||||
SetKind(GateMetaData::Kind::FRAME_STATE);
|
||||
preFrameState_ = invalidGate;
|
||||
isInlineCallFrameState_ = false;
|
||||
}
|
||||
|
||||
@ -722,18 +723,7 @@ public:
|
||||
isInlineCallFrameState_ = isInline;
|
||||
}
|
||||
|
||||
GateRef GetPreFrameState() const
|
||||
{
|
||||
return preFrameState_;
|
||||
}
|
||||
|
||||
void SetPreFrameState(GateRef preFrameState)
|
||||
{
|
||||
preFrameState_ = preFrameState;
|
||||
}
|
||||
|
||||
private:
|
||||
GateRef preFrameState_ {0};
|
||||
bool isInlineCallFrameState_ {false};
|
||||
};
|
||||
|
||||
|
@ -218,7 +218,7 @@ void LLVMIRBuilder::InitializeHandlers()
|
||||
OpCode::ARG_LIST, OpCode::THROW,
|
||||
OpCode::DEPEND_SELECTOR, OpCode::DEPEND_RELAY,
|
||||
OpCode::FRAME_STATE, OpCode::STATE_SPLIT, OpCode::FRAME_ARGS,
|
||||
OpCode::LOOP_EXIT_DEPEND, OpCode::LOOP_EXIT, OpCode::FRAME_STATE_CHAIN
|
||||
OpCode::LOOP_EXIT_DEPEND, OpCode::LOOP_EXIT, OpCode::FRAME_STATE_CHAIN, OpCode::REPLACEABLE
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -266,7 +266,8 @@ public:
|
||||
{
|
||||
TimeScope timescope("TSInlineLoweringPass", data->GetMethodName(), data->GetMethodOffset(), data->GetLog());
|
||||
bool enableLog = data->GetLog()->EnableMethodCIRLog();
|
||||
TSInlineLowering inlining(data->GetCircuit(), data->GetPassContext(), enableLog, data->GetMethodName());
|
||||
TSInlineLowering inlining(data->GetCircuit(), data->GetPassContext(), enableLog, data->GetMethodName(),
|
||||
data->GetNativeAreaAllocator());
|
||||
inlining.RunTSInlineLowering();
|
||||
return true;
|
||||
}
|
||||
|
@ -117,7 +117,7 @@ bool PassManager::Compile(const std::string &fileName, AOTFileGenerator &gen)
|
||||
if (data.IsTypeAbort()) {
|
||||
return;
|
||||
}
|
||||
if (passOptions_->EnableOptInlining()) {
|
||||
if (passOptions_->EnableOptInlining() && passOptions_->EnableTypeLowering()) {
|
||||
pipeline.RunPass<TSInlineLoweringPass>();
|
||||
}
|
||||
pipeline.RunPass<AsyncFunctionLoweringPass>();
|
||||
|
@ -47,10 +47,8 @@ void StateSplitLinearizer::Run()
|
||||
|
||||
void StateSplitLinearizer::VisitGate(GateRef gate)
|
||||
{
|
||||
if (acc_.GetOpCode(gate) == OpCode::STATE_SPLIT) {
|
||||
frameState_ = acc_.GetFrameState(gate);
|
||||
} else if (acc_.GetOpCode(gate) == OpCode::CHECK_AND_CONVERT) {
|
||||
ASSERT(acc_.FindNearestFrameState(gate) == frameState_);
|
||||
if (acc_.GetOpCode(gate) == OpCode::CHECK_AND_CONVERT) {
|
||||
frameState_ = acc_.FindNearestFrameState(gate);
|
||||
genericTypeLowering_.LowerCheckAndConvert(gate, frameState_);
|
||||
}
|
||||
}
|
||||
|
@ -91,6 +91,7 @@ void TSInlineLowering::TryInline(GateRef gate, bool isCallThis)
|
||||
if (inlineSuccess_) {
|
||||
GateRef glue = acc_.GetGlueFromArgList();
|
||||
CircuitRootScope scope(circuit_);
|
||||
InlineFuncCheck(gate);
|
||||
InlineCall(methodInfo, methodPcInfo, inlinedMethod, gate);
|
||||
ReplaceCallInput(gate, isCallThis, glue);
|
||||
inlinedCall_++;
|
||||
@ -178,8 +179,11 @@ void TSInlineLowering::InlineCall(MethodInfo &methodInfo, MethodPcInfo &methodPC
|
||||
|
||||
PassData data(&builder, circuit_, ctx_, log, fullName,
|
||||
&methodInfo, hasTyps, recordName,
|
||||
method, method->GetMethodId().GetOffset());
|
||||
method, method->GetMethodId().GetOffset(), nativeAreaAllocator_);
|
||||
PassRunner<PassData> pipeline(&data);
|
||||
if (builder.EnableLoopOptimization()) {
|
||||
pipeline.RunPass<LoopOptimizationPass>();
|
||||
}
|
||||
pipeline.RunPass<TypeInferPass>();
|
||||
}
|
||||
|
||||
@ -342,6 +346,24 @@ void TSInlineLowering::LowerToInlineCall(GateRef callGate, const std::vector<Gat
|
||||
RemoveRoot();
|
||||
}
|
||||
|
||||
void TSInlineLowering::InlineFuncCheck(GateRef gate)
|
||||
{
|
||||
GateRef callState = acc_.GetState(gate);
|
||||
GateRef callDepend = acc_.GetDep(gate);
|
||||
ASSERT(acc_.HasFrameState(callDepend));
|
||||
GateRef frameState = acc_.GetFrameState(callDepend);
|
||||
size_t funcIndex = acc_.GetNumValueIn(gate) - 1;
|
||||
GateRef inlineFunc = acc_.GetValueIn(gate, funcIndex);
|
||||
auto type = acc_.GetGateType(inlineFunc);
|
||||
GlobalTSTypeRef funcGt = type.GetGTRef();
|
||||
auto methodOffset = tsManager_->GetFuncMethodOffset(funcGt);
|
||||
GateRef ret = circuit_->NewGate(circuit_->JSInlineTargetTypeCheck(static_cast<size_t>(type.Value())),
|
||||
MachineType::I1, {callState, callDepend, inlineFunc, builder_.IntPtr(methodOffset), frameState},
|
||||
GateType::NJSValue());
|
||||
acc_.ReplaceStateIn(gate, ret);
|
||||
acc_.ReplaceDependIn(gate, ret);
|
||||
}
|
||||
|
||||
void TSInlineLowering::RemoveRoot()
|
||||
{
|
||||
GateRef circuitRoot = acc_.GetCircuitRoot();
|
||||
@ -355,15 +377,14 @@ void TSInlineLowering::RemoveRoot()
|
||||
|
||||
void TSInlineLowering::BuildFrameStateChain(GateRef gate, BytecodeCircuitBuilder &builder)
|
||||
{
|
||||
size_t size = builder.GetNumOfFrameState();
|
||||
GateRef depend = acc_.GetDep(gate);
|
||||
GateRef preFrameState = acc_.FindNearestFrameState(depend);
|
||||
GateRef check = acc_.GetDep(gate);
|
||||
GateRef stateSplit = acc_.GetDep(check);
|
||||
ASSERT(acc_.GetOpCode(stateSplit) == OpCode::STATE_SPLIT);
|
||||
GateRef preFrameState = acc_.FindNearestFrameState(stateSplit);
|
||||
ASSERT(acc_.GetOpCode(preFrameState) == OpCode::FRAME_STATE);
|
||||
acc_.SetInlineCallFrameStateFlag(preFrameState, true);
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
GateRef curFrameState = builder.GetFrameStateByIndex(i);
|
||||
acc_.SetPreFrameState(curFrameState, preFrameState);
|
||||
}
|
||||
GateRef frameArgs = builder.GetFrameArgs();
|
||||
acc_.ReplaceFrameStateIn(frameArgs, preFrameState);
|
||||
}
|
||||
|
||||
bool TSInlineLowering::FilterCallInTryCatch(GateRef gate)
|
||||
|
@ -45,7 +45,8 @@ private:
|
||||
class TSInlineLowering {
|
||||
public:
|
||||
static constexpr size_t MAX_INLINE_CALL_ALLOWED = 5;
|
||||
TSInlineLowering(Circuit *circuit, PassContext *ctx, bool enableLog, const std::string& name)
|
||||
TSInlineLowering(Circuit *circuit, PassContext *ctx, bool enableLog, const std::string& name,
|
||||
NativeAreaAllocator* nativeAreaAllocator)
|
||||
: circuit_(circuit),
|
||||
acc_(circuit),
|
||||
builder_(circuit, ctx->GetCompilerConfig()),
|
||||
@ -55,7 +56,8 @@ public:
|
||||
methodName_(name),
|
||||
enableTypeLowering_(ctx->GetEcmaVM()->GetJSOptions().IsEnableTypeLowering()),
|
||||
traceInline_(ctx->GetEcmaVM()->GetJSOptions().GetTraceInline()),
|
||||
maxInlineBytecodesCount_(ctx->GetEcmaVM()->GetJSOptions().GetMaxInlineBytecodes()) {}
|
||||
maxInlineBytecodesCount_(ctx->GetEcmaVM()->GetJSOptions().GetMaxInlineBytecodes()),
|
||||
nativeAreaAllocator_(nativeAreaAllocator) {}
|
||||
|
||||
~TSInlineLowering() = default;
|
||||
|
||||
@ -91,6 +93,7 @@ private:
|
||||
void RemoveRoot();
|
||||
void BuildFrameStateChain(GateRef gate, BytecodeCircuitBuilder &builder);
|
||||
GateRef TraceInlineFunction(GateRef glue, GateRef depend, std::vector<GateRef> &args, GateRef callGate);
|
||||
void InlineFuncCheck(GateRef gate);
|
||||
|
||||
Circuit *circuit_ {nullptr};
|
||||
GateAccessor acc_;
|
||||
@ -104,6 +107,7 @@ private:
|
||||
bool inlineSuccess_ {false};
|
||||
bool traceInline_ {false};
|
||||
size_t maxInlineBytecodesCount_ {0};
|
||||
NativeAreaAllocator *nativeAreaAllocator_ {nullptr};
|
||||
};
|
||||
} // panda::ecmascript::kungfu
|
||||
#endif // ECMASCRIPT_COMPILER_TS_INLINE_LOWERING_H
|
@ -71,6 +71,9 @@ void TypeLowering::LowerType(GateRef gate)
|
||||
case OpCode::TYPED_CALL_CHECK:
|
||||
LowerCallTargetCheck(gate);
|
||||
break;
|
||||
case OpCode::JSINLINETARGET_TYPE_CHECK:
|
||||
LowerJSInlineTargetTypeCheck(gate);
|
||||
break;
|
||||
case OpCode::TYPED_BINARY_OP:
|
||||
LowerTypedBinaryOp(gate);
|
||||
break;
|
||||
@ -1043,6 +1046,20 @@ void TypeLowering::LowerCallTargetCheck(GateRef gate)
|
||||
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
|
||||
}
|
||||
|
||||
void TypeLowering::LowerJSInlineTargetTypeCheck(GateRef gate)
|
||||
{
|
||||
Environment env(gate, circuit_, &builder_);
|
||||
GateRef frameState = GetFrameState(gate);
|
||||
auto func = acc_.GetValueIn(gate, 0);
|
||||
GateRef isObj = builder_.TaggedIsHeapObject(func);
|
||||
GateRef isJsFunc = builder_.IsJSFunction(func);
|
||||
GateRef checkFunc = builder_.BoolAnd(isObj, isJsFunc);
|
||||
GateRef GetMethodId = builder_.GetMethodId(func);
|
||||
GateRef check = builder_.BoolAnd(checkFunc, builder_.Equal(GetMethodId, acc_.GetValueIn(gate, 1)));
|
||||
builder_.DeoptCheck(check, frameState, DeoptType::INLINEFAIL);
|
||||
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
|
||||
}
|
||||
|
||||
void TypeLowering::LowerTypedNewAllocateThis(GateRef gate, GateRef glue)
|
||||
{
|
||||
Environment env(gate, circuit_, &builder_);
|
||||
|
@ -161,6 +161,7 @@ private:
|
||||
void LowerTypedNewAllocateThis(GateRef gate, GateRef glue);
|
||||
void LowerTypedSuperAllocateThis(GateRef gate, GateRef glue);
|
||||
void LowerGetSuperConstructor(GateRef gate);
|
||||
void LowerJSInlineTargetTypeCheck(GateRef gate);
|
||||
|
||||
GateRef LowerCallRuntime(GateRef glue, GateRef hirGate, int index, const std::vector<GateRef> &args,
|
||||
bool useLabel = false);
|
||||
|
@ -424,7 +424,7 @@ std::string Deoptimizier::DisplayItems(DeoptType type)
|
||||
return "NOT F32ARRAY";
|
||||
case DeoptType::INCONSISTENTHCLASS:
|
||||
return "INCONSISTENT HCLASS";
|
||||
case kungfu::DeoptType::NOTNEWOBJ:
|
||||
case DeoptType::NOTNEWOBJ:
|
||||
return "NOT NEWOBJ TYPE";
|
||||
case DeoptType::NOTARRAYIDX:
|
||||
return "NOT ARRAY IDX";
|
||||
@ -438,8 +438,10 @@ std::string Deoptimizier::DisplayItems(DeoptType type)
|
||||
return "NOT NEG OVERFLOW";
|
||||
case DeoptType::NOTCALLTGT:
|
||||
return "NOT CALL TARGET";
|
||||
case kungfu::DeoptType::NOTJSCALLTGT:
|
||||
case DeoptType::NOTJSCALLTGT:
|
||||
return "NOT JS CALL TARGET";
|
||||
case DeoptType::INLINEFAIL:
|
||||
return "INLINE FAILED";
|
||||
default: {
|
||||
return "NOT CHECK";
|
||||
}
|
||||
|
@ -181,7 +181,10 @@ group("ark_aot_ts_test") {
|
||||
"try_catch_finally",
|
||||
"trystglobalbynameprefid32",
|
||||
"ts_inline",
|
||||
"ts_inline_change_target",
|
||||
"ts_inline_deopt",
|
||||
"ts_inline_extends",
|
||||
"ts_inline_loop",
|
||||
"ts_inline_max_call",
|
||||
"typeof",
|
||||
"xor",
|
||||
|
21
test/aottest/ts_inline_change_target/BUILD.gn
Normal file
21
test/aottest/ts_inline_change_target/BUILD.gn
Normal file
@ -0,0 +1,21 @@
|
||||
# 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("ts_inline_change_target") {
|
||||
deps = []
|
||||
is_enable_opt_inlining = true
|
||||
is_enable_inline_trace = true
|
||||
log_option = " --log-info=trace"
|
||||
}
|
16
test/aottest/ts_inline_change_target/expect_output.txt
Normal file
16
test/aottest/ts_inline_change_target/expect_output.txt
Normal file
@ -0,0 +1,16 @@
|
||||
# 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] aot inline function name: foo@ts_inline_change_target caller function name: func_main_0@ts_inline_change_target
|
||||
foo
|
||||
bar
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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 function print(arg:any):string;
|
||||
|
||||
class A {
|
||||
foo () {
|
||||
print("foo");
|
||||
}
|
||||
}
|
||||
let a = new A();
|
||||
a.foo();
|
||||
|
||||
function bar()
|
||||
{
|
||||
print("bar");
|
||||
}
|
||||
|
||||
let p = A.prototype;
|
||||
Object.defineProperty(p, "foo", {value:bar});
|
||||
a.foo();
|
21
test/aottest/ts_inline_extends/BUILD.gn
Normal file
21
test/aottest/ts_inline_extends/BUILD.gn
Normal file
@ -0,0 +1,21 @@
|
||||
# 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("ts_inline_extends") {
|
||||
deps = []
|
||||
is_enable_opt_inlining = true
|
||||
is_enable_inline_trace = true
|
||||
log_option = " --log-info=trace"
|
||||
}
|
15
test/aottest/ts_inline_extends/expect_output.txt
Normal file
15
test/aottest/ts_inline_extends/expect_output.txt
Normal file
@ -0,0 +1,15 @@
|
||||
# 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] aot inline function name: foo@ts_inline_extends caller function name: func_main_0@ts_inline_extends
|
||||
B.run
|
42
test/aottest/ts_inline_extends/ts_inline_extends.ts
Normal file
42
test/aottest/ts_inline_extends/ts_inline_extends.ts
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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 function print(arg:any):string;
|
||||
|
||||
class A {
|
||||
run() {
|
||||
print("A.run")
|
||||
}
|
||||
}
|
||||
|
||||
class B extends A {
|
||||
run() {
|
||||
print("B.run")
|
||||
}
|
||||
}
|
||||
|
||||
class C {
|
||||
obj: A
|
||||
constructor(obj: A) {
|
||||
this.obj = obj
|
||||
}
|
||||
|
||||
foo() {
|
||||
this.obj.run()
|
||||
}
|
||||
}
|
||||
let b = new B()
|
||||
let c = new C(b)
|
||||
c.foo();
|
21
test/aottest/ts_inline_loop/BUILD.gn
Normal file
21
test/aottest/ts_inline_loop/BUILD.gn
Normal file
@ -0,0 +1,21 @@
|
||||
# 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("ts_inline_loop") {
|
||||
deps = []
|
||||
is_enable_opt_inlining = true
|
||||
is_enable_inline_trace = true
|
||||
log_option = " --log-info=trace"
|
||||
}
|
15
test/aottest/ts_inline_loop/expect_output.txt
Normal file
15
test/aottest/ts_inline_loop/expect_output.txt
Normal file
@ -0,0 +1,15 @@
|
||||
# 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] aot inline function name: loop@ts_inline_loop caller function name: func_main_0@ts_inline_loop
|
||||
128
|
26
test/aottest/ts_inline_loop/ts_inline_loop.ts
Normal file
26
test/aottest/ts_inline_loop/ts_inline_loop.ts
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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 function print(arg:any):string;
|
||||
|
||||
function loop(arg : number) : number {
|
||||
let a = arg;
|
||||
while (a < 100) {
|
||||
a = a * 2;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
print(loop(1));
|
@ -395,7 +395,8 @@ template("host_aot_js_test_action") {
|
||||
|
||||
if (defined(invoker.is_enable_opt_inlining) &&
|
||||
invoker.is_enable_opt_inlining) {
|
||||
_aot_compile_options_ += " --compiler-opt-inlining=true"
|
||||
_aot_compile_options_ +=
|
||||
" --compiler-opt-inlining=true --compiler-opt-type-lowering=true"
|
||||
}
|
||||
|
||||
if (defined(invoker.is_enable_inline_trace) &&
|
||||
@ -605,7 +606,8 @@ template("host_aot_test_action") {
|
||||
}
|
||||
if (defined(invoker.is_enable_opt_inlining) &&
|
||||
invoker.is_enable_opt_inlining) {
|
||||
_aot_compile_options_ += " --compiler-opt-inlining=true"
|
||||
_aot_compile_options_ +=
|
||||
" --compiler-opt-inlining=true --compiler-opt-type-lowering=true"
|
||||
}
|
||||
|
||||
if (defined(invoker.is_enable_inline_trace) &&
|
||||
@ -679,7 +681,8 @@ template("host_aot_test_action") {
|
||||
|
||||
if (defined(invoker.is_enable_opt_inlining) &&
|
||||
invoker.is_enable_opt_inlining) {
|
||||
_aot_compile_options_ += " --compiler-opt-inlining=true"
|
||||
_aot_compile_options_ +=
|
||||
" --compiler-opt-inlining=true --compiler-opt-type-lowering=true"
|
||||
}
|
||||
|
||||
if (defined(invoker.is_enable_inline_trace) &&
|
||||
|
Loading…
Reference in New Issue
Block a user