AOT callstack supports inline functions

1.Add frame args chain on bytecodes which can throw
2.Record inline method offsets in frame args
3.Push method offsets of inlined methods into stackmaps when callout aot
4.Collect inline method offsets and output them
5.Fix literal offsets error before try-catch
6.Add testcases
Issue:https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I7Z24N?from=project-issue

Signed-off-by: zhangyukun8 <zhangyukun8@huawei.com>
Change-Id: I7f4927a2dfc6a71e44b59cb392acb9b2d3f408e2
This commit is contained in:
zhangyukun8 2023-09-14 17:06:56 +08:00
parent a8d2a0828e
commit f31710d73d
59 changed files with 1078 additions and 57 deletions

View File

@ -3731,6 +3731,8 @@ JSHandle<JSObject> Builtins::InitializeArkTools(const JSHandle<GlobalEnv> &env)
SetFunction(env, tools, "isNotHoleProperty", builtins::BuiltinsArkTools::IsNotHoleProperty,
FunctionLength::TWO);
SetFunction(env, tools, "forceFullGC", builtins::BuiltinsArkTools::ForceFullGC, FunctionLength::ZERO);
SetFunction(env, tools, "hiddenStackSourceFile", builtins::BuiltinsArkTools::HiddenStackSourceFile,
FunctionLength::ZERO);
SetFunction(env, tools, "removeAOTFlag", builtins::BuiltinsArkTools::RemoveAOTFlag, FunctionLength::ONE);
#if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
SetFunction(env, tools, "startCpuProf", builtins::BuiltinsArkTools::StartCpuProfiler, FunctionLength::ZERO);

View File

@ -146,6 +146,15 @@ JSTaggedValue BuiltinsArkTools::IsNotHoleProperty(EcmaRuntimeCallInfo *info)
return GetTaggedBoolean(attr.IsNotHole());
}
JSTaggedValue BuiltinsArkTools::HiddenStackSourceFile(EcmaRuntimeCallInfo *info)
{
[[maybe_unused]] DisallowGarbageCollection noGc;
ASSERT(info);
JSThread *thread = info->GetThread();
thread->SetEnableStackSourceFile(false);
return JSTaggedValue::True();
}
JSTaggedValue BuiltinsArkTools::ExcutePendingJob(EcmaRuntimeCallInfo *info)
{
ASSERT(info);

View File

@ -45,6 +45,8 @@ public:
static JSTaggedValue ForceFullGC(EcmaRuntimeCallInfo *info);
static JSTaggedValue HiddenStackSourceFile(EcmaRuntimeCallInfo *info);
static JSTaggedValue RemoveAOTFlag(EcmaRuntimeCallInfo *info);
#if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)

View File

@ -156,8 +156,14 @@ GateRef ArgumentAccessor::GetFrameArgsIn(GateRef gate, FrameArgIdx idx)
ASSERT(gateAcc.GetOpCode(gate) == OpCode::JS_BYTECODE || gateAcc.GetOpCode(gate) == OpCode::FRAME_STATE);
GateRef frameArgs = Circuit::NullGate();
if (gateAcc.GetOpCode(gate) == OpCode::JS_BYTECODE) {
frameArgs = gateAcc.GetFrameState(gate);
ASSERT(gateAcc.GetOpCode(frameArgs) == OpCode::FRAME_ARGS);
GateRef frameState = gateAcc.GetFrameState(gate);
OpCode op = gateAcc.GetOpCode(frameState);
if (op == OpCode::FRAME_STATE) {
frameArgs = gateAcc.GetValueIn(frameState, 0); // 0: frame args
} else {
ASSERT(op == OpCode::FRAME_ARGS);
frameArgs = frameState;
}
} else {
frameArgs = gateAcc.GetValueIn(gate, 0); // 0: frame args
}

View File

@ -538,14 +538,16 @@ void BytecodeCircuitBuilder::BuildCircuitArgs()
void BytecodeCircuitBuilder::BuildFrameArgs()
{
auto metaData = circuit_->FrameArgs();
size_t numArgs = static_cast<size_t>(FrameArgIdx::NUM_OF_ARGS);
UInt32PairAccessor accessor(0, 0);
auto metaData = circuit_->FrameArgs(accessor.ToValue());
size_t numArgs = metaData->GetNumIns();
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);
args[idx++] = GetPreFrameArgs();
GateRef frameArgs = circuit_->NewGate(metaData, args);
argAcc_.SetFrameArgs(frameArgs);
}
@ -883,7 +885,7 @@ void BytecodeCircuitBuilder::NewJSGate(BytecodeRegion &bb, GateRef &state, GateR
size_t numValueInputs = bytecodeInfo.ComputeValueInputCount();
GateRef gate = 0;
bool writable = !bytecodeInfo.NoSideEffects();
bool hasFrameState = bytecodeInfo.HasFrameArgs();
bool hasFrameState = bytecodeInfo.HasFrameState();
size_t pcOffset = GetPcOffset(iterator.Index());
auto meta = circuit_->JSBytecode(numValueInputs, bytecodeInfo.GetOpcode(), pcOffset, writable, hasFrameState);
std::vector<GateRef> inList = CreateGateInList(bytecodeInfo, meta);

View File

@ -280,6 +280,7 @@ public:
loopExitToVregGate_(circuit->chunk()),
loopExitToAccGate_(circuit->chunk()),
preFrameState_(circuit_->GetRoot()),
preFrameArgs_(circuit_->GetRoot()),
isInline_(isInline)
{
}
@ -532,6 +533,16 @@ public:
preFrameState_ = gate;
}
GateRef GetPreFrameArgs() const
{
return preFrameArgs_;
}
void SetPreFrameArgs(GateRef gate)
{
preFrameArgs_ = gate;
}
const ChunkVector<size_t>& GetDfsList() const
{
return dfsList_;
@ -635,6 +646,7 @@ private:
ChunkMap<std::pair<GateRef, uint16_t>, GateRef> loopExitToVregGate_;
ChunkMap<GateRef, GateRef> loopExitToAccGate_;
GateRef preFrameState_ {Circuit::NullGate()};
GateRef preFrameArgs_ {Circuit::NullGate()};
bool isInline_ {false};
};
} // namespace panda::ecmascript::kungfu

View File

@ -94,17 +94,50 @@ BytecodeMetaData BytecodeMetaData::InitBytecodeMetaData(const uint8_t *pc)
}
switch (inst.GetOpcode()) {
case EcmaOpcode::MOV_V4_V4:
case EcmaOpcode::MOV_V8_V8:
case EcmaOpcode::MOV_V16_V16:
case EcmaOpcode::STA_V8:
case EcmaOpcode::LDA_V8:
case EcmaOpcode::LDNAN:
case EcmaOpcode::LDINFINITY:
case EcmaOpcode::LDUNDEFINED:
case EcmaOpcode::LDNULL:
case EcmaOpcode::LDTRUE:
case EcmaOpcode::LDFALSE:
case EcmaOpcode::LDHOLE:
case EcmaOpcode::LDAI_IMM32:
case EcmaOpcode::FLDAI_IMM64:
case EcmaOpcode::LDFUNCTION:
case EcmaOpcode::LDA_STR_ID16:
case EcmaOpcode::TYPEOF_IMM8:
case EcmaOpcode::TYPEOF_IMM16:
case EcmaOpcode::ISTRUE:
case EcmaOpcode::ISFALSE:
case EcmaOpcode::JEQZ_IMM8:
case EcmaOpcode::JEQZ_IMM16:
case EcmaOpcode::JEQZ_IMM32:
case EcmaOpcode::JNEZ_IMM8:
case EcmaOpcode::JNEZ_IMM16:
case EcmaOpcode::JNEZ_IMM32:
case EcmaOpcode::JMP_IMM8:
case EcmaOpcode::JMP_IMM16:
case EcmaOpcode::JMP_IMM32:
case EcmaOpcode::STMODULEVAR_IMM8:
case EcmaOpcode::WIDE_STMODULEVAR_PREF_IMM16:
case EcmaOpcode::LDEXTERNALMODULEVAR_IMM8:
case EcmaOpcode::WIDE_LDEXTERNALMODULEVAR_PREF_IMM16:
case EcmaOpcode::NEWLEXENV_IMM8:
case EcmaOpcode::WIDE_NEWLEXENV_PREF_IMM16:
case EcmaOpcode::POPLEXENV:
case EcmaOpcode::NEWLEXENVWITHNAME_IMM8_ID16:
case EcmaOpcode::WIDE_NEWLEXENVWITHNAME_PREF_IMM16_ID16:
case EcmaOpcode::ASYNCFUNCTIONENTER:
case EcmaOpcode::SETGENERATORSTATE_IMM8:
case EcmaOpcode::GETRESUMEMODE:
case EcmaOpcode::RESUMEGENERATOR:
case EcmaOpcode::RETURN:
case EcmaOpcode::RETURNUNDEFINED:
case EcmaOpcode::LDLEXVAR_IMM4_IMM4:
case EcmaOpcode::LDLEXVAR_IMM8_IMM8:
case EcmaOpcode::WIDE_LDLEXVAR_PREF_IMM16_IMM16:
@ -118,7 +151,14 @@ BytecodeMetaData BytecodeMetaData::InitBytecodeMetaData(const uint8_t *pc)
case EcmaOpcode::CREATEEMPTYOBJECT:
case EcmaOpcode::CREATEARRAYWITHBUFFER_IMM8_ID16:
case EcmaOpcode::CREATEARRAYWITHBUFFER_IMM16_ID16:
case EcmaOpcode::SETGENERATORSTATE_IMM8:
case EcmaOpcode::CREATEITERRESULTOBJ_V8_V8:
case EcmaOpcode::DEFINEFUNC_IMM8_ID16_IMM8:
case EcmaOpcode::DEFINEFUNC_IMM16_ID16_IMM8:
case EcmaOpcode::DEFINEMETHOD_IMM8_ID16_IMM8:
case EcmaOpcode::DEFINEMETHOD_IMM16_ID16_IMM8:
case EcmaOpcode::GETUNMAPPEDARGS:
case EcmaOpcode::DEBUGGER:
case EcmaOpcode::NOP:
flags |= BytecodeFlags::NO_THROW;
break;
default:

View File

@ -685,6 +685,11 @@ public:
return HasFuncIn() || HasNewTargetIn() || ThisObjectIn() || HasArgcIn();
}
bool HasFrameState() const
{
return HasFrameArgs() || !NoThrow();
}
bool IsCall() const
{
return metaData_.IsCall();

View File

@ -1237,6 +1237,7 @@ inline GateRef CircuitBuilder::TypedCallBuiltin(GateRef hirGate, const std::vect
std::vector<GateRef> inList { currentControl, currentDepend };
inList.insert(inList.end(), args.begin(), args.end());
inList.push_back(Int8(static_cast<int8_t>(id)));
AppendFrameArgs(inList, hirGate);
auto builtinOp = TypedCallOperator(hirGate, MachineType::I64, inList);
currentLabel->SetControl(builtinOp);

View File

@ -601,7 +601,7 @@ GateRef CircuitBuilder::GetSuperConstructor(GateRef ctor)
GateRef CircuitBuilder::TypedCallOperator(GateRef hirGate, MachineType type, const std::vector<GateRef> &inList)
{
ASSERT(acc_.GetOpCode(hirGate) == OpCode::JS_BYTECODE);
auto numValueIn = inList.size() - 2; // 2: state & depend
auto numValueIn = inList.size() - 3; // 3: state & depend & frame state
uint64_t pcOffset = acc_.TryGetPcOffset(hirGate);
ASSERT(pcOffset != 0);
return GetCircuit()->NewGate(circuit_->TypedCallBuiltin(numValueIn, pcOffset), type, inList.size(), inList.data(),
@ -1050,6 +1050,9 @@ GateRef CircuitBuilder::Call(const CallSignature* cs, GateRef glue, GateRef targ
inputs.insert(inputs.end(), args.begin(), args.end());
auto numValuesIn = args.size() + 2; // 2: target & glue
if (GetCircuit()->IsOptimizedJSFunctionFrame() && hirGate != Circuit::NullGate()) {
AppendFrameArgs(inputs, hirGate);
numValuesIn += 1;
GateRef pcOffset = Int64(acc_.TryGetPcOffset(hirGate));
inputs.emplace_back(pcOffset);
numValuesIn += 1;
@ -1112,6 +1115,8 @@ GateRef CircuitBuilder::NoLabelCallRuntime(GateRef glue, GateRef depend, size_t
std::vector<GateRef> inputs { depend, target, glue };
inputs.insert(inputs.end(), args.begin(), args.end());
auto numValuesIn = args.size() + 2; // 2: target & glue
inputs.emplace_back(IntPtr(0)); // framestate slot
numValuesIn += 1;
GateRef pcOffset = Int64(acc_.TryGetPcOffset(hirGate));
inputs.emplace_back(pcOffset);
numValuesIn += 1;
@ -1264,6 +1269,16 @@ GateRef CircuitBuilder::ConvertHoleAsUndefined(GateRef receiver)
return ret;
}
void CircuitBuilder::AppendFrameArgs(std::vector<GateRef> &args, GateRef hirGate)
{
GateRef frameArgs = acc_.GetFrameArgs(hirGate);
if (frameArgs == Circuit::NullGate()) {
args.emplace_back(IntPtr(0));
} else {
args.emplace_back(frameArgs);
}
}
GateRef CircuitBuilder::Construct(GateRef hirGate, std::vector<GateRef> args)
{
ASSERT(acc_.GetOpCode(hirGate) == OpCode::JS_BYTECODE);
@ -1275,6 +1290,7 @@ GateRef CircuitBuilder::Construct(GateRef hirGate, std::vector<GateRef> args)
ASSERT(pcOffset != 0);
args.insert(args.begin(), currentDepend);
args.insert(args.begin(), currentControl);
AppendFrameArgs(args, hirGate);
auto callGate = GetCircuit()->NewGate(circuit_->Construct(bitfield, pcOffset), MachineType::I64,
args.size(), args.data(), GateType::AnyType());
currentLabel->SetControl(callGate);
@ -1293,6 +1309,7 @@ GateRef CircuitBuilder::TypedCall(GateRef hirGate, std::vector<GateRef> args, bo
ASSERT(pcOffset != 0);
args.insert(args.begin(), currentDepend);
args.insert(args.begin(), currentControl);
AppendFrameArgs(args, hirGate);
auto callGate = GetCircuit()->NewGate(circuit_->TypedCall(bitfield, pcOffset, isNoGC), MachineType::I64,
args.size(), args.data(), GateType::AnyType());
currentLabel->SetControl(callGate);
@ -1311,6 +1328,7 @@ GateRef CircuitBuilder::TypedFastCall(GateRef hirGate, std::vector<GateRef> args
ASSERT(pcOffset != 0);
args.insert(args.begin(), currentDepend);
args.insert(args.begin(), currentControl);
AppendFrameArgs(args, hirGate);
auto callGate = GetCircuit()->NewGate(circuit_->TypedFastCall(bitfield, pcOffset, isNoGC), MachineType::I64,
args.size(), args.data(), GateType::AnyType());
currentLabel->SetControl(callGate);
@ -1328,9 +1346,12 @@ GateRef CircuitBuilder::CallGetter(GateRef hirGate, GateRef receiver, GateRef pr
auto currentLabel = env_->GetCurrentLabel();
auto currentControl = currentLabel->GetControl();
auto currentDepend = currentLabel->GetDepend();
std::vector<GateRef> args = { currentControl, currentDepend, receiver, propertyLookupResult };
AppendFrameArgs(args, hirGate);
auto callGate = GetCircuit()->NewGate(circuit_->CallGetter(pcOffset),
MachineType::I64,
{ currentControl, currentDepend, receiver, propertyLookupResult },
args.size(),
args.data(),
GateType::AnyType(),
comment);
currentLabel->SetControl(callGate);
@ -1348,9 +1369,12 @@ GateRef CircuitBuilder::CallSetter(GateRef hirGate, GateRef receiver, GateRef pr
auto currentLabel = env_->GetCurrentLabel();
auto currentControl = currentLabel->GetControl();
auto currentDepend = currentLabel->GetDepend();
std::vector<GateRef> args = { currentControl, currentDepend, receiver, propertyLookupResult, value };
AppendFrameArgs(args, hirGate);
auto callGate = GetCircuit()->NewGate(circuit_->CallSetter(pcOffset),
MachineType::I64,
{ currentControl, currentDepend, receiver, propertyLookupResult, value },
args.size(),
args.data(),
GateType::AnyType(),
comment);
currentLabel->SetControl(callGate);

View File

@ -324,6 +324,7 @@ public:
GateRef InsertTypedBinaryop(GateRef left, GateRef right, GateType leftType, GateType rightType,
GateType gateType, PGOSampleType sampleType, TypedBinOp op);
GateRef InsertRangeCheckPredicate(GateRef left, TypedBinOp cond, GateRef right);
void AppendFrameArgs(std::vector<GateRef> &args, GateRef hirGate);
GateRef TypedConditionJump(MachineType type, TypedJumpOp jumpOp, BranchKind branchKind, GateType typeVal,
const std::vector<GateRef>& inList);
GateRef TypedNewAllocateThis(GateRef ctor, GateRef hclassIndex, GateRef frameState);

View File

@ -34,7 +34,7 @@ public:
virtual void GenerateCode(Circuit *circuit, const ControlFlowGraph &graph, const CompilationConfig *cfg,
const MethodLiteral *methodLiteral, const JSPandaFile *jsPandaFile,
const std::string &methodName) = 0;
const std::string &methodName, bool enableOptInlining) = 0;
};
class CodeGenerator {
@ -57,9 +57,9 @@ public:
}
void Run(Circuit *circuit, const ControlFlowGraph &graph, const CompilationConfig *cfg,
const MethodLiteral *methodLiteral, const JSPandaFile *jsPandaFile)
const MethodLiteral *methodLiteral, const JSPandaFile *jsPandaFile, bool enableOptInlining)
{
impl_->GenerateCode(circuit, graph, cfg, methodLiteral, jsPandaFile, methodName_);
impl_->GenerateCode(circuit, graph, cfg, methodLiteral, jsPandaFile, methodName_, enableOptInlining);
}
private:

View File

@ -57,6 +57,11 @@ GateRef FrameStateBuilder::BuildFrameValues(FrameStateInfo *stateInfo)
return circuit_->NewGate(circuit_->FrameValues(frameStateInputs), inList);
}
GateRef FrameStateBuilder::BuildEmptyFrameValues()
{
return circuit_->NewGate(circuit_->FrameValues(0), {});
}
GateRef FrameStateBuilder::BuildFrameStateGate(size_t pcOffset, GateRef frameValues, FrameStateOutput output)
{
GateRef frameArgs = builder_->GetFrameArgs();

View File

@ -107,6 +107,7 @@ private:
void UpdateVirtualRegister(size_t id, size_t index, GateRef gate);
GateRef BuildFrameStateGate(size_t pcOffset, GateRef frameValues, FrameStateOutput output);
GateRef BuildFrameValues(FrameStateInfo *stateInfo);
GateRef BuildEmptyFrameValues();
FrameStateInfo *CreateEmptyStateInfo();
void BuildPostOrderList(size_t size);

View File

@ -434,6 +434,48 @@ uint32_t GateAccessor::TryGetPcOffset(GateRef gate) const
return 0;
}
uint32_t GateAccessor::TryGetMethodOffset(GateRef gate) const
{
Gate *gatePtr = circuit_->LoadGatePtr(gate);
OpCode op = GetOpCode(gate);
switch (op) {
case OpCode::FRAME_ARGS: {
UInt32PairAccessor accessor(gatePtr->GetOneParameterMetaData()->GetValue());
return accessor.GetFirstValue();
}
default:
break;
}
return 0;
}
GateRef GateAccessor::GetFrameArgs(GateRef gate) const
{
if (!HasFrameState(gate)) {
return Circuit::NullGate();
}
if (GetOpCode(gate) == OpCode::FRAME_STATE) {
return GetValueIn(gate, 0); // 0: frame args
}
GateRef frameState = GetFrameState(gate);
OpCode op = GetOpCode(frameState);
if (op == OpCode::FRAME_ARGS) {
return frameState;
}
if (op == OpCode::FRAME_STATE) {
return GetValueIn(frameState, 0); // 0: frame args
}
return Circuit::NullGate();
}
void GateAccessor::UpdateMethodOffset(GateRef gate, uint32_t methodOffset)
{
ASSERT(GetOpCode(gate) == OpCode::FRAME_ARGS);
Gate *gatePtr = circuit_->LoadGatePtr(gate);
UInt32PairAccessor accessor(methodOffset, 0);
const_cast<OneParameterMetaData *>(gatePtr->GetOneParameterMetaData())->SetValue(accessor.ToValue());
}
PGOSampleType GateAccessor::TryGetPGOType(GateRef gate) const
{
Gate *gatePtr = circuit_->LoadGatePtr(gate);
@ -1306,6 +1348,20 @@ void GateAccessor::GetStateInAndDependIn(GateRef insertAfter, GateRef &stateIn,
ASSERT(GetDependCount(dependIn) > 0);
}
size_t GateAccessor::GetFrameDepth(GateRef gate, OpCode op)
{
if (GetOpCode(gate) != op) {
return 0;
}
size_t depth = 0;
GateRef prev = GetFrameState(gate);
while ((GetOpCode(prev) == op)) {
depth++;
prev = GetFrameState(prev);
}
return depth;
}
GateRef GateAccessor::GetFrameState(GateRef gate) const
{
ASSERT(HasFrameState(gate));

View File

@ -410,6 +410,9 @@ public:
bool TypedCallIsNoGC(GateRef gate) const;
bool IsNoGC(GateRef gate) const;
uint32_t TryGetPcOffset(GateRef gate) const;
uint32_t TryGetMethodOffset(GateRef gate) const;
GateRef GetFrameArgs(GateRef gate) const;
void UpdateMethodOffset(GateRef gate, uint32_t methodOffset);
PGOSampleType TryGetPGOType(GateRef gate) const;
void TrySetPGOType(GateRef gate, PGOSampleType type);
ElementsKind TryGetElementsKind(GateRef gate) const;
@ -553,6 +556,7 @@ public:
return gate == GetStateRoot();
}
size_t GetFrameDepth(GateRef gate, OpCode op);
GateRef GetFrameState(GateRef gate) const;
void ReplaceFrameStateIn(GateRef gate, GateRef in);
bool HasFrameState(GateRef gate) const;

View File

@ -316,7 +316,6 @@ std::string MachineTypeToStr(MachineType machineType);
V(GetSuperConstructor, GET_SUPER_CONSTRUCTOR, GateFlags::NO_WRITE, 1, 1, 1) \
V(CheckSafePointAndStackOver, CHECK_SAFEPOINT_AND_STACKOVER, 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(GetEnv, GET_ENV, GateFlags::NONE_FLAG, 0, 0, 1) \
V(ConvertHoleAsUndefined, CONVERT_HOLE_AS_UNDEFINED, GateFlags::NO_WRITE, 1, 1, 1) \
V(StartAllocate, START_ALLOCATE, GateFlags::NONE_FLAG, 0, 1, 0) \
@ -340,17 +339,17 @@ std::string MachineTypeToStr(MachineType machineType);
V(BuiltinsCall, BUILTINS_CALL, GateFlags::NONE_FLAG, 0, 1, value) \
V(SaveRegister, SAVE_REGISTER, GateFlags::NONE_FLAG, 0, 1, value)
#define GATE_META_DATA_LIST_WITH_PC_OFFSET(V) \
V(TypedCallBuiltin, TYPED_CALL_BUILTIN, GateFlags::NO_WRITE, 1, 1, value) \
V(Construct, CONSTRUCT, GateFlags::NONE_FLAG, 1, 1, value)
#define GATE_META_DATA_LIST_WITH_PC_OFFSET(V) \
V(TypedCallBuiltin, TYPED_CALL_BUILTIN, GateFlags::CHECKABLE, 1, 1, value) \
V(Construct, CONSTRUCT, GateFlags::HAS_FRAME_STATE, 1, 1, value)
#define GATE_META_DATA_LIST_FOR_CALL(V) \
V(TypedCall, TYPEDCALL, GateFlags::NONE_FLAG, 1, 1, value) \
V(TypedFastCall, TYPEDFASTCALL, GateFlags::NONE_FLAG, 1, 1, value)
V(TypedCall, TYPEDCALL, GateFlags::HAS_FRAME_STATE, 1, 1, value) \
V(TypedFastCall, TYPEDFASTCALL, GateFlags::HAS_FRAME_STATE, 1, 1, value)
#define GATE_META_DATA_LIST_WITH_PC_OFFSET_FIXED_VALUE(V) \
V(CallGetter, CALL_GETTER, GateFlags::NONE_FLAG, 1, 1, 2) \
V(CallSetter, CALL_SETTER, GateFlags::NONE_FLAG, 1, 1, 3)
V(CallGetter, CALL_GETTER, GateFlags::HAS_FRAME_STATE, 1, 1, 2) \
V(CallSetter, CALL_SETTER, GateFlags::HAS_FRAME_STATE, 1, 1, 3)
#define GATE_META_DATA_LIST_WITH_SIZE(V) \
V(Merge, MERGE, GateFlags::CONTROL, value, 0, 0) \
@ -389,6 +388,7 @@ std::string MachineTypeToStr(MachineType machineType);
V(GetGlobalEnvObj, GET_GLOBAL_ENV_OBJ, GateFlags::NO_WRITE, 0, 1, 1) \
V(GetGlobalEnvObjHClass, GET_GLOBAL_ENV_OBJ_HCLASS, GateFlags::NO_WRITE, 0, 1, 1) \
V(GetGlobalConstantValue, GET_GLOBAL_CONSTANT_VALUE, GateFlags::NO_WRITE, 0, 1, 0) \
V(FrameArgs, FRAME_ARGS, GateFlags::HAS_FRAME_STATE, 0, 0, 4) \
V(FrameState, FRAME_STATE, GateFlags::HAS_FRAME_STATE, 0, 0, 2) \
V(CreateArray, CREATE_ARRAY, GateFlags::NONE_FLAG, 1, 1, 0) \
V(CreateArrayWithBuffer, CREATE_ARRAY_WITH_BUFFER, GateFlags::CHECKABLE, 1, 1, 2) \

View File

@ -225,7 +225,8 @@ void LLVMIRGeneratorImpl::GenerateCodeForStub(Circuit *circuit, const ControlFlo
void LLVMIRGeneratorImpl::GenerateCode(Circuit *circuit, const ControlFlowGraph &graph, const CompilationConfig *cfg,
const panda::ecmascript::MethodLiteral *methodLiteral,
const JSPandaFile *jsPandaFile, const std::string &methodName)
const JSPandaFile *jsPandaFile, const std::string &methodName,
bool enableOptInlining)
{
auto function = module_->AddFunc(methodLiteral, jsPandaFile);
circuit->SetFrameType(FrameType::OPTIMIZED_JS_FUNCTION_FRAME);
@ -236,7 +237,7 @@ void LLVMIRGeneratorImpl::GenerateCode(Circuit *circuit, const ControlFlowGraph
conv = CallSignature::CallConv::WebKitJSCallConv;
}
LLVMIRBuilder builder(&graph, circuit, module_, function, cfg, conv,
enableLog_, methodLiteral->IsFastCall(), methodName);
enableLog_, methodLiteral->IsFastCall(), methodName, enableOptInlining);
builder.Build();
}

View File

@ -210,7 +210,8 @@ public:
void GenerateCodeForStub(Circuit *circuit, const ControlFlowGraph &graph, size_t index,
const CompilationConfig *cfg) override;
void GenerateCode(Circuit *circuit, const ControlFlowGraph &graph, const CompilationConfig *cfg,
const MethodLiteral *methodLiteral, const JSPandaFile *jsPandaFile, const std::string &methodName) override;
const MethodLiteral *methodLiteral, const JSPandaFile *jsPandaFile, const std::string &methodName,
bool enableOptInlining) override;
bool IsLogEnabled() const
{

View File

@ -59,10 +59,10 @@ namespace panda::ecmascript::kungfu {
LLVMIRBuilder::LLVMIRBuilder(const std::vector<std::vector<GateRef>> *schedule, Circuit *circuit,
LLVMModule *module, LLVMValueRef function, const CompilationConfig *cfg,
CallSignature::CallConv callConv, bool enableLog, bool isFastCallAot,
const std::string &funcName)
const std::string &funcName, bool enableOptInlining)
: compCfg_(cfg), scheduledGates_(schedule), circuit_(circuit), acc_(circuit), module_(module->GetModule()),
function_(function), llvmModule_(module), callConv_(callConv), enableLog_(enableLog),
isFastCallAot_(isFastCallAot)
isFastCallAot_(isFastCallAot), enableOptInlining_(enableOptInlining)
{
ASSERT(compCfg_->Is64Bit());
context_ = module->GetContext();
@ -568,7 +568,8 @@ void LLVMIRBuilder::VisitRuntimeCall(GateRef gate, const std::vector<GateRef> &i
size_t actualNumArgs = 0;
LLVMValueRef pcOffset = LLVMConstInt(GetInt32T(), 0, 0);
ComputeArgCountAndPCOffset(actualNumArgs, pcOffset, inList, kind);
GateRef frameArgs = Circuit::NullGate();
ComputeArgCountAndExtraInfo(actualNumArgs, pcOffset, frameArgs, inList, kind);
std::vector<LLVMValueRef> params;
params.push_back(glue); // glue
@ -588,9 +589,7 @@ void LLVMIRBuilder::VisitRuntimeCall(GateRef gate, const std::vector<GateRef> &i
LLVMValueRef runtimeCall = nullptr;
if (kind == CallExceptionKind::HAS_PC_OFFSET) {
std::vector<LLVMValueRef> values;
auto pcIndex = LLVMConstInt(GetInt64T(), static_cast<int>(SpecVregIndex::PC_OFFSET_INDEX), 1);
values.push_back(pcIndex);
values.push_back(pcOffset);
CollectExraCallSiteInfo(values, pcOffset, frameArgs);
runtimeCall = LLVMBuildCall3(builder_, funcType, callee, params.data(), actualNumArgs,
"", values.data(), values.size());
} else {
@ -753,13 +752,14 @@ LLVMValueRef LLVMIRBuilder::GetBuiltinsStubOffset(LLVMValueRef glue)
return LLVMConstInt(glueType, JSThread::GlueData::GetBuiltinsStubEntriesOffset(compCfg_->Is32Bit()), 0);
}
void LLVMIRBuilder::ComputeArgCountAndPCOffset(size_t &actualNumArgs, LLVMValueRef &pcOffset,
const std::vector<GateRef> &inList, CallExceptionKind kind)
void LLVMIRBuilder::ComputeArgCountAndExtraInfo(size_t &actualNumArgs, LLVMValueRef &pcOffset, GateRef &frameArgs,
const std::vector<GateRef> &inList, CallExceptionKind kind)
{
if (kind == CallExceptionKind::HAS_PC_OFFSET) {
actualNumArgs = inList.size() - 1;
pcOffset = gate2LValue_[inList[actualNumArgs]];
ASSERT(acc_.GetOpCode(inList[actualNumArgs]) == OpCode::CONSTANT);
actualNumArgs = inList.size() - 2; // 2: pcOffset and frameArgs
pcOffset = gate2LValue_[inList[actualNumArgs + 1]];
frameArgs = inList[actualNumArgs];
ASSERT(acc_.GetOpCode(inList[actualNumArgs + 1]) == OpCode::CONSTANT);
} else {
actualNumArgs = inList.size();
}
@ -806,6 +806,47 @@ void LLVMIRBuilder::VisitReadSp(GateRef gate)
gate2LValue_[gate] = spValue;
}
void LLVMIRBuilder::CollectExraCallSiteInfo(std::vector<LLVMValueRef> &values, LLVMValueRef pcOffset,
GateRef frameArgs)
{
// pc offset
auto pcIndex = LLVMConstInt(GetInt64T(), static_cast<int>(SpecVregIndex::PC_OFFSET_INDEX), 1);
values.push_back(pcIndex);
values.push_back(pcOffset);
if (!enableOptInlining_) {
return;
}
if (frameArgs == Circuit::NullGate()) {
return;
}
if (acc_.GetOpCode(frameArgs) != OpCode::FRAME_ARGS) {
return;
}
uint32_t maxDepth = acc_.GetFrameDepth(frameArgs, OpCode::FRAME_ARGS);
if (maxDepth == 0) {
return;
}
maxDepth = std::min(maxDepth, MAX_METHOD_OFFSET_NUM);
size_t shift = Deoptimizier::ComputeShift(MAX_METHOD_OFFSET_NUM);
ArgumentAccessor argAcc(const_cast<Circuit *>(circuit_));
for (int32_t curDepth = static_cast<int32_t>(maxDepth - 1); curDepth >= 0; curDepth--) {
ASSERT(acc_.GetOpCode(frameArgs) == OpCode::FRAME_ARGS);
// method id
uint32_t methodOffset = acc_.TryGetMethodOffset(frameArgs);
frameArgs = acc_.GetFrameState(frameArgs);
if (methodOffset == FrameStateOutput::INVALID_INDEX) {
methodOffset = 0;
}
int32_t specCallTargetIndex = static_cast<int32_t>(SpecVregIndex::FIRST_METHOD_OFFSET_INDEX) - curDepth;
int32_t encodeIndex = Deoptimizier::EncodeDeoptVregIndex(specCallTargetIndex, curDepth, shift);
values.emplace_back(LLVMConstInt(GetInt32T(), encodeIndex, false));
values.emplace_back(LLVMConstInt(GetInt32T(), methodOffset, false));
}
}
void LLVMIRBuilder::VisitCall(GateRef gate, const std::vector<GateRef> &inList, OpCode op)
{
size_t targetIndex = static_cast<size_t>(CallInputs::TARGET);
@ -877,7 +918,8 @@ void LLVMIRBuilder::VisitCall(GateRef gate, const std::vector<GateRef> &inList,
int extraParameterCnt = 0;
size_t actualNumArgs = 0;
LLVMValueRef pcOffset = LLVMConstInt(GetInt32T(), 0, 0);
ComputeArgCountAndPCOffset(actualNumArgs, pcOffset, inList, kind);
GateRef frameArgs = Circuit::NullGate();
ComputeArgCountAndExtraInfo(actualNumArgs, pcOffset, frameArgs, inList, kind);
// then push the actual parameter for js function call
for (size_t paraIdx = firstArg + 1; paraIdx < actualNumArgs; ++paraIdx) {
@ -903,9 +945,7 @@ void LLVMIRBuilder::VisitCall(GateRef gate, const std::vector<GateRef> &inList,
callee = LLVMBuildPointerCast(builder_, callee, LLVMPointerType(funcType, 0), "");
if (kind == CallExceptionKind::HAS_PC_OFFSET) {
std::vector<LLVMValueRef> values;
auto pcIndex = LLVMConstInt(GetInt64T(), static_cast<int>(SpecVregIndex::PC_OFFSET_INDEX), 1);
values.push_back(pcIndex);
values.push_back(pcOffset);
CollectExraCallSiteInfo(values, pcOffset, frameArgs);
call = LLVMBuildCall3(builder_, funcType, callee, params.data(), actualNumArgs - firstArg + extraParameterCnt,
"", values.data(), values.size());
} else {
@ -2342,15 +2382,10 @@ void LLVMIRBuilder::VisitDeoptCheck(GateRef gate)
LLVMTypeRef funcType = GetExperimentalDeoptTy();
std::vector<LLVMValueRef> values;
size_t maxDepth = 0;
GateRef frameState = acc_.GetFrameState(deoptFrameState);
while ((acc_.GetOpCode(frameState) == OpCode::FRAME_STATE)) {
maxDepth++;
frameState = acc_.GetFrameState(frameState);
}
size_t maxDepth = acc_.GetFrameDepth(deoptFrameState, OpCode::FRAME_STATE);
params.push_back(ConvertInt32ToTaggedInt(LLVMConstInt(GetInt32T(), static_cast<uint32_t>(maxDepth), false)));
size_t shift = Deoptimizier::ComputeShift(maxDepth);
frameState = deoptFrameState;
GateRef frameState = deoptFrameState;
ArgumentAccessor argAcc(const_cast<Circuit *>(circuit_));
for (int32_t curDepth = static_cast<int32_t>(maxDepth); curDepth >= 0; curDepth--) {
ASSERT(acc_.GetOpCode(frameState) == OpCode::FRAME_STATE);

View File

@ -366,7 +366,8 @@ class LLVMIRBuilder {
public:
LLVMIRBuilder(const std::vector<std::vector<GateRef>> *schedule, Circuit *circuit,
LLVMModule *module, LLVMValueRef function, const CompilationConfig *cfg,
CallSignature::CallConv callConv, bool enableLog, bool isFastCallAot, const std::string &funcName);
CallSignature::CallConv callConv, bool enableLog, bool isFastCallAot, const std::string &funcName,
bool enableOptInlining = false);
~LLVMIRBuilder();
void Build();
@ -418,6 +419,8 @@ private:
const std::string &realName = "") const;
LLVMValueRef GetCallee(const std::vector<GateRef> &inList, const CallSignature *signature,
const std::string &realName = "");
void CollectExraCallSiteInfo(std::vector<LLVMValueRef> &values, LLVMValueRef pcOffset,
GateRef frameState);
LLVMValueRef GetFunctionFromGlobalValue(LLVMValueRef glue, const CallSignature *signature,
LLVMValueRef reloc) const;
bool IsInterpreted() const;
@ -513,7 +516,7 @@ private:
LLVMValueRef GetBuiltinsStubOffset(LLVMValueRef glue);
LLVMValueRef GetBaseOffset(GateRef gate, LLVMValueRef glue);
CallExceptionKind GetCallExceptionKind(size_t index, OpCode op) const;
void ComputeArgCountAndPCOffset(size_t &actualNumArgs, LLVMValueRef &pcOffset,
void ComputeArgCountAndExtraInfo(size_t &actualNumArgs, LLVMValueRef &pcOffset, GateRef &frameArgs,
const std::vector<GateRef> &inList, CallExceptionKind kind);
void SaveLexicalEnvOnOptJSFuncFrame(LLVMValueRef value);
void SaveJSFuncOnOptJSFuncFrame(LLVMValueRef value);
@ -560,6 +563,7 @@ private:
bool enableLog_ {false};
bool isFastCallAot_ {false};
LLVMMetadataRef dFuncMD_ {nullptr};
bool enableOptInlining_ {false};
};
} // namespace panda::ecmascript::kungfu
#endif // ECMASCRIPT_COMPILER_LLVM_IR_BUILDER_H

View File

@ -598,10 +598,12 @@ public:
auto module = data->GetAotModule();
TimeScope timescope("LLVMIRGenPass", data->GetMethodName(), data->GetMethodOffset(), data->GetLog());
bool enableLog = data->GetLog()->EnableMethodCIRLog() || data->GetLog()->OutputASM();
PassOptions *passOptions = data->GetPassOptions();
bool enableOptInlining = passOptions->EnableOptInlining() && passOptions->EnableTypeLowering();
CreateCodeGen(module, enableLog);
CodeGenerator codegen(llvmImpl_, data->GetMethodName());
codegen.Run(data->GetCircuit(), data->GetConstScheduleResult(), data->GetCompilerConfig(),
data->GetMethodLiteral(), data->GetJSPandaFile());
data->GetMethodLiteral(), data->GetJSPandaFile(), enableOptInlining);
return true;
}
private:

View File

@ -56,7 +56,7 @@ HWTEST_F_L0(LoweringRelateGateTests, TypeCheckFramework)
auto arg0 = builder.Arguments(0);
auto pcGate = circuit.GetConstantGate(MachineType::I64, 0, GateType::NJSValue());
auto frameArgs = circuit.NewGate(
circuit.FrameArgs(), {builder.Arguments(3), builder.Arguments(4), builder.Arguments(5), builder.Arguments(2)});
circuit.FrameArgs(0), {builder.Arguments(3), builder.Arguments(4), builder.Arguments(5), builder.Arguments(2)});
auto frameState = circuit.NewGate(circuit.FrameState(1), {pcGate, frameArgs});
auto stateSplit = circuit.NewGate(circuit.StateSplit(), {state, depend, frameState});
builder.SetDepend(stateSplit);

View File

@ -35,6 +35,32 @@ void TSInlineLowering::RunTSInlineLowering()
workList.pop();
TryInline(info, workList);
}
CollectInlineInfo();
}
void TSInlineLowering::CollectInlineInfo()
{
std::vector<GateRef> gateList;
circuit_->GetAllGates(gateList);
for (const auto &gate : gateList) {
auto op = acc_.GetOpCode(gate);
if (op == OpCode::FRAME_ARGS) {
GetInlinedMethodId(gate);
}
}
}
void TSInlineLowering::GetInlinedMethodId(GateRef gate)
{
ASSERT(acc_.GetOpCode(gate) == OpCode::FRAME_ARGS);
GateRef func = acc_.GetValueIn(gate, static_cast<size_t>(FrameArgIdx::FUNC));
uint32_t methodOffset = 0;
auto funcType = acc_.GetGateType(func);
if (tsManager_->IsFunctionTypeKind(funcType)) {
GlobalTSTypeRef gt = funcType.GetGTRef();
methodOffset = tsManager_->GetFuncMethodOffset(gt);
}
acc_.UpdateMethodOffset(gate, methodOffset);
}
void TSInlineLowering::CandidateInlineCall(GateRef gate, ChunkQueue<CallGateInfo> &workList)
@ -533,6 +559,8 @@ void TSInlineLowering::BuildFrameStateChain(CallGateInfo &info, BytecodeCircuitB
GateRef preFrameState = GetFrameState(info);
ASSERT(acc_.GetOpCode(preFrameState) == OpCode::FRAME_STATE);
builder.SetPreFrameState(preFrameState);
GateRef frameArgs = acc_.GetFrameArgs(preFrameState);
builder.SetPreFrameArgs(frameArgs);
}
bool TSInlineLowering::FilterCallInTryCatch(GateRef gate)

View File

@ -169,6 +169,8 @@ private:
return kind == CallKind::CALL_SETTER;
}
void CollectInlineInfo();
void GetInlinedMethodId(GateRef gate);
void CandidateInlineCall(GateRef gate, ChunkQueue<CallGateInfo> &workList);
void TryInline(CallGateInfo &info, ChunkQueue<CallGateInfo> &workList);
bool FilterInlinedMethod(MethodLiteral* method, std::vector<const uint8_t*> pcOffsets);

View File

@ -94,7 +94,7 @@ void TypeRecorder::CollectLiteralGT(TSManager *tsManager, TypeLocation &loc, Glo
return;
}
if (bytecodes_->GetOpcode(pcOffsets_[bcIdx]) == EcmaOpcode::STA_V8) {
while (bytecodes_->GetOpcode(pcOffsets_[bcIdx]) == EcmaOpcode::STA_V8) {
// bcIndex of literal marked in es2abc maybe in the next bc whose opcode should be sta.
bcIdx--;
loc.SetBcIdx(bcIdx);

View File

@ -33,8 +33,16 @@ enum class SpecVregIndex: int {
NEWTARGET_INDEX = -5,
THIS_OBJECT_INDEX = -6,
ACTUAL_ARGC_INDEX = -7,
FIRST_METHOD_OFFSET_INDEX = -8,
PADDING1 = -9,
PADDING2 = -10,
PADDING3 = -11,
MAX_METHOD_OFFSET_INDEX = -12,
};
static constexpr uint32_t MAX_METHOD_OFFSET_NUM = static_cast<int32_t>(SpecVregIndex::FIRST_METHOD_OFFSET_INDEX) -
static_cast<int32_t>(SpecVregIndex::MAX_METHOD_OFFSET_INDEX) + 1;
struct Context {
uintptr_t callsiteSp;
uintptr_t callsiteFp;

View File

@ -27,7 +27,7 @@
#endif
namespace panda::ecmascript {
std::string JsStackInfo::BuildMethodTrace(Method *method, uint32_t pcOffset)
std::string JsStackInfo::BuildMethodTrace(Method *method, uint32_t pcOffset, bool enableStackSourceFile)
{
std::string data;
data.append(" at ");
@ -40,12 +40,17 @@ std::string JsStackInfo::BuildMethodTrace(Method *method, uint32_t pcOffset)
// source file
DebugInfoExtractor *debugExtractor =
JSPandaFileManager::GetInstance()->GetJSPtExtractor(method->GetJSPandaFile());
const std::string &sourceFile = debugExtractor->GetSourceFile(method->GetMethodId());
if (sourceFile.empty()) {
data.push_back('?');
if (enableStackSourceFile) {
const std::string &sourceFile = debugExtractor->GetSourceFile(method->GetMethodId());
if (sourceFile.empty()) {
data.push_back('?');
} else {
data += sourceFile;
}
} else {
data += sourceFile;
data.append("hidden");
}
data.push_back(':');
// line number and column number
auto callbackLineFunc = [&data](int32_t line) -> bool {
@ -67,6 +72,32 @@ std::string JsStackInfo::BuildMethodTrace(Method *method, uint32_t pcOffset)
return data;
}
std::string JsStackInfo::BuildInlinedMethodTrace(const JSPandaFile *pf, std::map<uint32_t, uint32_t> &methodOffsets)
{
std::string data;
std::map<uint32_t, uint32_t>::reverse_iterator it;
for (it = methodOffsets.rbegin(); it != methodOffsets.rend(); it++) {
uint32_t methodId = it->second;
std::string name;
if (methodId == 0) {
name = "unknown";
} else {
name = std::string(MethodLiteral::GetMethodName(pf, EntityId(methodId)));
if (name == "") {
name = "anonymous";
}
}
data.append(" at ");
data.append(name);
data.append(" (maybe inlined).");
data.append(" depth: ");
data.append(std::to_string(it->first));
data.push_back('\n');
}
return data;
}
std::string JsStackInfo::BuildJsStackTrace(JSThread *thread, bool needNative)
{
std::string data;
@ -82,7 +113,10 @@ std::string JsStackInfo::BuildJsStackTrace(JSThread *thread, bool needNative)
}
if (!method->IsNativeWithCallField()) {
auto pcOffset = it.GetBytecodeOffset();
data += BuildMethodTrace(method, pcOffset);
const JSPandaFile *pf = method->GetJSPandaFile();
std::map<uint32_t, uint32_t> methodOffsets = it.GetInlinedMethodInfo();
data += BuildInlinedMethodTrace(pf, methodOffsets);
data += BuildMethodTrace(method, pcOffset, thread->GetEnableStackSourceFile());
} else if (needNative) {
auto addr = method->GetNativePointer();
std::stringstream strm;

View File

@ -29,9 +29,10 @@ struct JsFrameInfo {
};
class JsStackInfo {
public:
static std::string BuildInlinedMethodTrace(const JSPandaFile *pf, std::map<uint32_t, uint32_t> &methodOffsets);
static std::string BuildJsStackTrace(JSThread *thread, bool needNative);
static std::vector<JsFrameInfo> BuildJsStackInfo(JSThread *thread);
static std::string BuildMethodTrace(Method *method, uint32_t pcOffset);
static std::string BuildMethodTrace(Method *method, uint32_t pcOffset, bool enableStackSourceFile = true);
static AOTFileManager *loader;
};
void CrashCallback(char *buf, size_t len, void *ucontext);

View File

@ -394,6 +394,22 @@ uintptr_t FrameIterator::GetPrevFrameCallSiteSp() const
return 0;
}
std::map<uint32_t, uint32_t> FrameIterator::GetInlinedMethodInfo()
{
std::map<uint32_t, uint32_t> inlineMethodInfos;
FrameType type = this->GetFrameType();
switch (type) {
case FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME:
case FrameType::OPTIMIZED_JS_FUNCTION_FRAME: {
CollectMethodOffsetInfo(inlineMethodInfos);
}
default: {
break;
}
}
return inlineMethodInfos;
}
uint32_t FrameIterator::GetBytecodeOffset() const
{
FrameType type = this->GetFrameType();
@ -486,6 +502,11 @@ void FrameIterator::CollectPcOffsetInfo(ConstInfo &info) const
arkStackMapParser_->GetConstInfo(optimizedReturnAddr_, info, stackMapAddr_);
}
void FrameIterator::CollectMethodOffsetInfo(std::map<uint32_t, uint32_t> &info) const
{
arkStackMapParser_->GetMethodOffsetInfo(optimizedReturnAddr_, info, stackMapAddr_);
}
void FrameIterator::CollectArkDeopt(std::vector<kungfu::ARKDeopt>& deopts) const
{
arkStackMapParser_->GetArkDeopt(optimizedReturnAddr_, stackMapAddr_, deopts);

View File

@ -1625,6 +1625,7 @@ public:
int ComputeDelta() const;
template <GCVisitedFlag GCVisit = GCVisitedFlag::IGNORED>
void Advance();
std::map<uint32_t, uint32_t> GetInlinedMethodInfo();
uint32_t GetBytecodeOffset() const;
uintptr_t GetPrevFrameCallSiteSp() const;
uintptr_t GetPrevFrame() const;
@ -1642,6 +1643,7 @@ public:
}
bool IteratorStackMap(const RootVisitor &visitor, const RootBaseAndDerivedVisitor &derivedVisitor) const;
void CollectPcOffsetInfo(ConstInfo &info) const;
void CollectMethodOffsetInfo(std::map<uint32_t, uint32_t> &info) const;
void CollectArkDeopt(std::vector<kungfu::ARKDeopt>& deopts) const;
std::tuple<uint64_t, uint8_t *, int, kungfu::CalleeRegAndOffsetVec> CalCallSiteInfo(uintptr_t retAddr) const;
int GetCallSiteDelta(uintptr_t retAddr) const;

View File

@ -527,6 +527,16 @@ public:
return vmThreadControl_;
}
void SetEnableStackSourceFile(bool value)
{
enableStackSourceFile_ = value;
}
bool GetEnableStackSourceFile() const
{
return enableStackSourceFile_;
}
static constexpr size_t GetGlueDataOffset()
{
return MEMBER_OFFSET(JSThread, glueData_);
@ -993,6 +1003,7 @@ private:
bool runtimeState_ {false};
bool isAsmInterpreter_ {false};
VmThreadControl *vmThreadControl_ {nullptr};
bool enableStackSourceFile_ {true};
// CpuProfiler
bool isProfiling_ {false};

View File

@ -91,6 +91,35 @@ void ArkStackMapParser::GetConstInfo(uintptr_t callSiteAddr, LLVMStackMapType::C
info.emplace_back(v);
}
void ArkStackMapParser::GetMethodOffsetInfo(uintptr_t callSiteAddr, std::map<uint32_t, uint32_t>& info,
uint8_t *stackmapAddr) const
{
std::vector<ARKDeopt> deopts;
GetArkDeopt(callSiteAddr, stackmapAddr, deopts);
if (deopts.empty()) {
return;
}
ARKDeopt target;
size_t shift = Deoptimizier::ComputeShift(MAX_METHOD_OFFSET_NUM);
LLVMStackMapType::VRegId startId = static_cast<LLVMStackMapType::VRegId>(SpecVregIndex::FIRST_METHOD_OFFSET_INDEX);
for (int i = MAX_METHOD_OFFSET_NUM - 1; i >= 0; i--) {
LLVMStackMapType::VRegId id = startId - i;
target.id = Deoptimizier::EncodeDeoptVregIndex(id, i, shift);
auto it = std::lower_bound(deopts.begin(), deopts.end(), target,
[](const ARKDeopt& a, const ARKDeopt& b) {
return a.id < b.id;
});
if (it == deopts.end() || (it->id > target.id)) {
continue;
}
ASSERT(it->kind == LocationTy::Kind::CONSTANT);
ASSERT(std::holds_alternative<LLVMStackMapType::IntType>(it->value));
auto v = std::get<LLVMStackMapType::IntType>(it->value);
info[static_cast<int32_t>(SpecVregIndex::FIRST_METHOD_OFFSET_INDEX) - id] = v;
}
}
uintptr_t ArkStackMapParser::GetStackSlotAddress(const LLVMStackMapType::DwarfRegAndOffsetType info,
uintptr_t callSiteSp, uintptr_t callsiteFp) const
{

View File

@ -38,6 +38,8 @@ public:
enableLog_ = false;
}
void GetConstInfo(uintptr_t callsite, LLVMStackMapType::ConstInfo& info, uint8_t *stackmapAddr = nullptr) const;
void GetMethodOffsetInfo(uintptr_t callSiteAddr, std::map<uint32_t, uint32_t>& info,
uint8_t *stackmapAddr) const;
bool IteratorStackMap(const RootVisitor& visitor,
const RootBaseAndDerivedVisitor& derivedVisitor,
uintptr_t callSiteAddr, uintptr_t callsiteFp,

View File

@ -211,6 +211,14 @@ group("ark_aot_ts_test") {
"ts_inline_change_target",
"ts_inline_deopt",
"ts_inline_deopt_loop",
"ts_inline_exception1",
"ts_inline_exception2",
"ts_inline_exception3",
"ts_inline_exception4",
"ts_inline_exception5",
"ts_inline_exception6",
"ts_inline_exception7",
"ts_inline_exception8",
"ts_inline_extends",
"ts_inline_loop",
"ts_inline_max_call",

View File

@ -0,0 +1,19 @@
# 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_exception1") {
deps = []
is_enable_opt_inlining = true
}

View File

@ -0,0 +1,18 @@
# 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.
ReferenceError: b is not defined
at foo1 (maybe inlined). depth: 0
at foo2 (hidden:26:26)
at func_main_0 (hidden:28:1)

View File

@ -0,0 +1,32 @@
/*
* 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;
declare class ArkTools {
static hiddenStackSourceFile(): boolean;
}
ArkTools.hiddenStackSourceFile()
try {
function foo1() {
b.c
}
function foo2() {
foo1()
}
foo2()
} catch (e) {
print(e)
print(e.stack)
}

View File

@ -0,0 +1,19 @@
# 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_exception2") {
deps = []
is_enable_opt_inlining = true
}

View File

@ -0,0 +1,22 @@
# 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.
TypeError: CallObj is NonCallable
at foo1 (maybe inlined). depth: 4
at foo2 (maybe inlined). depth: 3
at foo3 (maybe inlined). depth: 2
at foo4 (maybe inlined). depth: 1
at foo5 (maybe inlined). depth: 0
at foo6 (hidden:40:40)
at func_main_0 (hidden:42:1)

View File

@ -0,0 +1,53 @@
/*
* 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;
declare class ArkTools {
static hiddenStackSourceFile(): boolean;
}
ArkTools.hiddenStackSourceFile()
try {
let a = {}
function foo1() {
a()
}
function foo2() {
foo1()
}
function foo3() {
foo2()
}
function foo4() {
foo3()
}
function foo5() {
foo4()
}
function foo6() {
foo5()
}
foo6()
function foo7() {
foo6()
}
function foo8() {
foo7()
}
foo8()
} catch (e) {
print(e)
print(e.stack)
}

View File

@ -0,0 +1,19 @@
# 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_exception3") {
deps = []
is_enable_opt_inlining = true
}

View File

@ -0,0 +1,20 @@
# 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.
SyntaxError: Unexpected Array in JSON
at foo1 (maybe inlined). depth: 2
at foo3 (maybe inlined). depth: 1
at foo4 (maybe inlined). depth: 0
at foo5 (hidden:36:36)
at func_main_0 (hidden:38:1)

View 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;
declare class ArkTools {
static hiddenStackSourceFile(): boolean;
}
ArkTools.hiddenStackSourceFile()
try {
function foo1() {
JSON.parse("[1, 2");
}
function foo2() {
}
function foo3() {
foo2()
foo1()
}
function foo4() {
foo3()
}
function foo5() {
foo4()
}
foo5()
} catch (e) {
print(e)
print(e.stack)
}

View File

@ -0,0 +1,19 @@
# 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_exception4") {
deps = []
is_enable_opt_inlining = true
}

View 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.
ReferenceError: c is not defined
at anonymous (hidden:23:23)
at foo1 (maybe inlined). depth: 1
at foo2 (maybe inlined). depth: 0
at foo3 (hidden:35:35)
at foo4 (hidden:38:38)
at func_main_0 (hidden:41:1)

View File

@ -0,0 +1,45 @@
/*
* 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;
declare class ArkTools {
static hiddenStackSourceFile(): boolean;
}
ArkTools.hiddenStackSourceFile()
const o = {
[Symbol.toPrimitive] () {
c
return 1
}
}
try {
function foo1() {
if (o == 1) {}
}
function foo2() {
foo1()
}
function foo3(a) {
foo2()
}
function foo4() {
foo3()
}
foo4()
} catch (e) {
print(e)
print(e.stack)
}

View File

@ -0,0 +1,19 @@
# 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_exception5") {
deps = []
is_enable_opt_inlining = true
}

View File

@ -0,0 +1,20 @@
# 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.
RangeError: Invalid array length
at foo1 (maybe inlined). depth: 1
at foo2 (maybe inlined). depth: 0
at foo3 (hidden:30:30)
at foo4 (hidden:33:33)
at func_main_0 (hidden:35:1)

View File

@ -0,0 +1,39 @@
/*
* 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;
declare class ArkTools {
static hiddenStackSourceFile(): boolean;
}
ArkTools.hiddenStackSourceFile()
try {
function foo1() {
new Array(111111111111111111111)
}
function foo2() {
foo1()
}
function foo3(a) {
foo2()
}
function foo4() {
foo3()
}
foo4()
} catch (e) {
print(e)
print(e.stack)
}

View File

@ -0,0 +1,19 @@
# 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_exception6") {
deps = []
is_enable_opt_inlining = true
}

View File

@ -0,0 +1,22 @@
# 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.
ReferenceError: c is not defined
at foo1 (maybe inlined). depth: 0
at foo2 (hidden:27:27)
at foo3 (hidden:31:31)
at foo4 (hidden:34:34)
at foo5 (maybe inlined). depth: 0
at foo6 (hidden:40:40)
at func_main_0 (hidden:42:1)

View File

@ -0,0 +1,46 @@
/*
* 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;
declare class ArkTools {
static hiddenStackSourceFile(): boolean;
}
ArkTools.hiddenStackSourceFile()
try {
function foo1() {
c
}
function foo2() {
foo1()
}
function foo3(a: number): number {
let b: number = a + 1
foo2()
}
function foo4() {
foo3(<number><Object>'a', 1)
}
function foo5() {
foo4(1)
}
function foo6() {
foo5()
}
foo6(1)
} catch (e) {
print(e)
print(e.stack)
}

View 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_exception7") {
deps = []
is_only_typed_path = true
is_enable_opt_inlining = true
is_enable_trace_deopt = true
}

View File

@ -0,0 +1,20 @@
# 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.
SyntaxError: Unexpected Array in JSON
at Student (hidden:26:26)
at foo1 (maybe inlined). depth: 1
at foo2 (maybe inlined). depth: 0
at foo3 (hidden:40:40)
at func_main_0 (hidden:43:1)

View File

@ -0,0 +1,47 @@
/*
* 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;
declare class ArkTools {
static hiddenStackSourceFile(): boolean;
}
ArkTools.hiddenStackSourceFile()
try {
class Student {
name : string;
constructor(name:string) {
this.name = name;
JSON.parse("[1, 2");
}
}
function foo1() {
let stu = new Student("xiaoming");
let ans = stu.name
}
function foo2() {
foo1()
}
function foo3() {
foo2()
}
foo3(1)
} catch (e) {
print(e)
print(e.stack)
}

View File

@ -0,0 +1,19 @@
# 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_exception8") {
deps = []
is_enable_opt_inlining = true
}

View File

@ -0,0 +1,20 @@
# 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.
0
ReferenceError: a is not defined
at name (hidden:25:25)
at foo1 (maybe inlined). depth: 0
at foo2 (hidden:34:34)
at func_main_0 (hidden:37:1)

View File

@ -0,0 +1,41 @@
/*
* 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;
declare class ArkTools {
static hiddenStackSourceFile(): boolean;
}
ArkTools.hiddenStackSourceFile()
class A {
constructor() {}
get name() {
print(arguments.length)
a.b
}
set name(a) {}
}
let ins = new A()
function foo1() {
ins.name
}
function foo2() {
foo1()
}
try {
foo2()
} catch (e) {
print(e)
print(e.stack)
}