mirror of
https://gitee.com/openharmony/arkcompiler_ets_runtime
synced 2025-02-01 01:14:10 +00:00
TSAOT Exception Handler
1. Throw JS exception in tsaot 2. Print bcoffset when occur JS exception issue: https://gitee.com/openharmony/ark_js_runtime/issues/I5AMHL Signed-off-by: xujie <xujie101@huawei.com> Change-Id: I046d76c092a399354ddcdedd859f0c1e622387c2
This commit is contained in:
parent
6eaee6c7e7
commit
81a69cf09f
@ -485,6 +485,16 @@ JSTaggedValue BuiltinsGlobal::PrintEntrypoint(EcmaRuntimeCallInfo *msg)
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
PrintString(thread, *stringContent);
|
||||
|
||||
// print bc offset for ts aot
|
||||
if (GetCallArg(msg, i)->IsJSError() && thread->IsPrintBCOffset()) {
|
||||
auto list = thread->GetEcmaVM()->GetBCOffsetInfoList();
|
||||
if (!list.empty()) {
|
||||
for (auto info : list) {
|
||||
std::cout << "\nException at function " << info.first << ": " << info.second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (i != numArgs - 1) {
|
||||
std::cout << " ";
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "bytecode_circuit_builder.h"
|
||||
#include "ecmascript/base/number_helper.h"
|
||||
#include "ecmascript/ts_types/ts_loader.h"
|
||||
#include "ecmascript/compiler/gate_accessor.h"
|
||||
|
||||
namespace panda::ecmascript::kungfu {
|
||||
void BytecodeCircuitBuilder::BytecodeToCircuit()
|
||||
@ -24,17 +25,22 @@ void BytecodeCircuitBuilder::BytecodeToCircuit()
|
||||
auto prePc = curPc;
|
||||
std::map<uint8_t *, uint8_t *> byteCodeCurPrePc;
|
||||
std::vector<CfgInfo> bytecodeBlockInfos;
|
||||
int32_t offsetIndex = 1;
|
||||
auto startPc = curPc;
|
||||
bytecodeBlockInfos.emplace_back(startPc, SplitKind::START, std::vector<uint8_t *>(1, startPc));
|
||||
byteCodeCurPrePc.insert(std::pair<uint8_t *, uint8_t *>(curPc, prePc));
|
||||
byteCodeCurPrePc[curPc] = prePc;
|
||||
pcToBCOffset_[curPc]=offsetIndex++;
|
||||
for (size_t i = 1; i < pcArray_.size() - 1; i++) {
|
||||
curPc = pcArray_[i];
|
||||
byteCodeCurPrePc.insert(std::pair<uint8_t *, uint8_t *>(curPc, prePc));
|
||||
byteCodeCurPrePc[curPc] = prePc;
|
||||
pcToBCOffset_[curPc]=offsetIndex++;
|
||||
prePc = curPc;
|
||||
CollectBytecodeBlockInfo(curPc, bytecodeBlockInfos);
|
||||
}
|
||||
// handle empty
|
||||
byteCodeCurPrePc.insert(std::pair<uint8_t *, uint8_t *>(pcArray_[pcArray_.size() - 1], prePc));
|
||||
uint8_t *emptyPc = pcArray_.back();
|
||||
byteCodeCurPrePc[emptyPc] = prePc;
|
||||
pcToBCOffset_[emptyPc] = offsetIndex++;
|
||||
|
||||
// collect try catch block info
|
||||
auto exceptionInfo = CollectTryCatchBlockInfo(byteCodeCurPrePc, bytecodeBlockInfos);
|
||||
@ -1966,9 +1972,10 @@ void BytecodeCircuitBuilder::BuildBlockCircuitHead()
|
||||
|
||||
std::vector<GateRef> BytecodeCircuitBuilder::CreateGateInList(const BytecodeInfo &info)
|
||||
{
|
||||
size_t numValueInputs = (info.accIn ? 1 : 0) + info.inputs.size();
|
||||
size_t numValueInputs = info.ComputeValueInputCount();
|
||||
const size_t length = 2; // 2: state and depend on input
|
||||
std::vector<GateRef> inList(length + numValueInputs, Circuit::NullGate());
|
||||
const size_t numBCOffsetInput = info.ComputeBCOffsetInputCount();
|
||||
std::vector<GateRef> inList(length + numValueInputs + numBCOffsetInput, Circuit::NullGate());
|
||||
for (size_t i = 0; i < info.inputs.size(); i++) {
|
||||
const auto &input = info.inputs[i];
|
||||
if (std::holds_alternative<MethodId>(input)) {
|
||||
@ -2083,7 +2090,7 @@ GateRef BytecodeCircuitBuilder::NewConst(const BytecodeInfo &info)
|
||||
void BytecodeCircuitBuilder::NewJSGate(BytecodeRegion &bb, const uint8_t *pc, GateRef &state, GateRef &depend)
|
||||
{
|
||||
auto bytecodeInfo = GetBytecodeInfo(pc);
|
||||
size_t numValueInputs = (bytecodeInfo.accIn ? 1 : 0) + bytecodeInfo.inputs.size();
|
||||
size_t numValueInputs = bytecodeInfo.ComputeTotalValueCount();
|
||||
GateRef gate = 0;
|
||||
std::vector<GateRef> inList = CreateGateInList(bytecodeInfo);
|
||||
if (!bytecodeInfo.vregOut.empty() || bytecodeInfo.accOut) {
|
||||
@ -2093,6 +2100,8 @@ void BytecodeCircuitBuilder::NewJSGate(BytecodeRegion &bb, const uint8_t *pc, Ga
|
||||
gate = circuit_.NewGate(OpCode(OpCode::JS_BYTECODE), MachineType::NOVALUE, numValueInputs,
|
||||
inList, GateType::Empty());
|
||||
}
|
||||
// 1: store bcoffset in the end.
|
||||
AddBytecodeOffsetInfo(gate, bytecodeInfo, numValueInputs + 1, const_cast<uint8_t *>(pc));
|
||||
circuit_.NewIn(gate, 0, state);
|
||||
circuit_.NewIn(gate, 1, depend);
|
||||
auto ifSuccess = circuit_.NewGate(OpCode(OpCode::IF_SUCCESS), 0, {gate}, GateType::Empty());
|
||||
@ -2141,7 +2150,7 @@ void BytecodeCircuitBuilder::NewJSGate(BytecodeRegion &bb, const uint8_t *pc, Ga
|
||||
void BytecodeCircuitBuilder::NewJump(BytecodeRegion &bb, const uint8_t *pc, GateRef &state, GateRef &depend)
|
||||
{
|
||||
auto bytecodeInfo = GetBytecodeInfo(pc);
|
||||
size_t numValueInputs = (bytecodeInfo.accIn ? 1 : 0) + bytecodeInfo.inputs.size();
|
||||
size_t numValueInputs = bytecodeInfo.ComputeValueInputCount();
|
||||
if (bytecodeInfo.IsCondJump()) {
|
||||
GateRef gate = 0;
|
||||
gate = circuit_.NewGate(OpCode(OpCode::JS_BYTECODE), MachineType::NOVALUE, numValueInputs,
|
||||
@ -2460,8 +2469,8 @@ void BytecodeCircuitBuilder::BuildCircuit()
|
||||
}
|
||||
const auto &[id, pc] = it->second;
|
||||
auto bytecodeInfo = GetBytecodeInfo(pc);
|
||||
[[maybe_unused]] size_t numValueInputs = (bytecodeInfo.accIn ? 1 : 0) + bytecodeInfo.inputs.size();
|
||||
[[maybe_unused]] size_t numValueOutputs = (bytecodeInfo.accOut ? 1 : 0) + bytecodeInfo.vregOut.size();
|
||||
[[maybe_unused]] size_t numValueInputs = bytecodeInfo.ComputeTotalValueCount();
|
||||
[[maybe_unused]] size_t numValueOutputs = bytecodeInfo.ComputeOutCount() + bytecodeInfo.vregOut.size();
|
||||
ASSERT(numValueInputs == valueCount);
|
||||
ASSERT(numValueOutputs <= 1);
|
||||
auto stateCount = circuit_.GetOpCode(gate).GetStateCount(circuit_.GetBitField(gate));
|
||||
@ -2492,6 +2501,19 @@ size_t BytecodeCircuitBuilder::GetFunctionArgIndex(size_t currentVreg, size_t nu
|
||||
return (currentVreg - numVregs + CommonArgIdx::NUM_OF_ARGS);
|
||||
}
|
||||
|
||||
void BytecodeCircuitBuilder::AddBytecodeOffsetInfo(GateRef &gate, const BytecodeInfo &info, size_t bcOffsetIndex,
|
||||
uint8_t *pc)
|
||||
{
|
||||
if (info.IsCall()) {
|
||||
GateAccessor acc(&circuit_);
|
||||
auto bcOffset = circuit_.NewGate(OpCode(OpCode::CONSTANT), MachineType::I64,
|
||||
pcToBCOffset_[pc],
|
||||
{Circuit::GetCircuitRoot(OpCode(OpCode::CONSTANT_LIST))},
|
||||
GateType::NJSValue());
|
||||
acc.NewIn(gate, bcOffsetIndex, bcOffset);
|
||||
}
|
||||
}
|
||||
|
||||
void BytecodeCircuitBuilder::PrintCollectBlockInfo(std::vector<CfgInfo> &bytecodeBlockInfos)
|
||||
{
|
||||
for (auto iter = bytecodeBlockInfos.cbegin(); iter != bytecodeBlockInfos.cend(); iter++) {
|
||||
|
@ -323,6 +323,42 @@ struct BytecodeInfo {
|
||||
{
|
||||
return !IsMov() && !IsJump() && !IsReturn() && !IsSetConstant() && !IsDiscarded();
|
||||
}
|
||||
|
||||
bool IsCall() const
|
||||
{
|
||||
auto ecmaOpcode = static_cast<EcmaOpcode>(opcode);
|
||||
switch (ecmaOpcode) {
|
||||
case EcmaOpcode::CALLARG0DYN_PREF_V8:
|
||||
case EcmaOpcode::CALLARG1DYN_PREF_V8_V8:
|
||||
case EcmaOpcode::CALLARGS2DYN_PREF_V8_V8_V8:
|
||||
case EcmaOpcode::CALLARGS3DYN_PREF_V8_V8_V8_V8:
|
||||
case EcmaOpcode::CALLITHISRANGEDYN_PREF_IMM16_V8:
|
||||
case EcmaOpcode::CALLIRANGEDYN_PREF_IMM16_V8:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
size_t ComputeBCOffsetInputCount() const
|
||||
{
|
||||
return IsCall() ? 1 : 0;
|
||||
}
|
||||
|
||||
size_t ComputeValueInputCount() const
|
||||
{
|
||||
return (accIn ? 1 : 0) + inputs.size();
|
||||
}
|
||||
|
||||
size_t ComputeOutCount() const
|
||||
{
|
||||
return accOut ? 1 : 0;
|
||||
}
|
||||
|
||||
size_t ComputeTotalValueCount() const
|
||||
{
|
||||
return ComputeValueInputCount() + ComputeBCOffsetInputCount();
|
||||
}
|
||||
};
|
||||
|
||||
enum BytecodeOffset {
|
||||
@ -444,6 +480,7 @@ private:
|
||||
void NewJump(BytecodeRegion &bb, const uint8_t *pc, GateRef &state, GateRef &depend);
|
||||
void NewReturn(BytecodeRegion &bb, const uint8_t *pc, GateRef &state, GateRef &depend);
|
||||
void NewByteCode(BytecodeRegion &bb, const uint8_t *pc, GateRef &state, GateRef &depend);
|
||||
void AddBytecodeOffsetInfo(GateRef &gate, const BytecodeInfo &info, size_t bcOffsetIndex, uint8_t *pc);
|
||||
void BuildSubCircuit();
|
||||
GateRef NewPhi(BytecodeRegion &bb, uint16_t reg, bool acc);
|
||||
GateRef RenameVariable(const size_t bbId, const uint8_t *end,
|
||||
@ -474,6 +511,7 @@ private:
|
||||
const std::vector<uint8_t *> pcArray_;
|
||||
JSHandle<JSTaggedValue> constantPool_;
|
||||
bool enableLog_ {false};
|
||||
std::map<uint8_t *, int32_t> pcToBCOffset_;
|
||||
};
|
||||
} // namespace panda::ecmascript::kungfu
|
||||
#endif // ECMASCRIPT_CLASS_LINKER_BYTECODE_CIRCUIT_IR_BUILDER_H
|
||||
|
@ -175,4 +175,9 @@ void GateAccessor::DecreaseIn(UsesIterator &useIt)
|
||||
circuit_->DecreaseIn(*useIt, idx);
|
||||
useIt.SetChanged();
|
||||
}
|
||||
|
||||
void GateAccessor::NewIn(GateRef gate, size_t idx, GateRef in)
|
||||
{
|
||||
circuit_->NewIn(gate, idx, in);
|
||||
}
|
||||
}
|
@ -335,6 +335,7 @@ public:
|
||||
void DeleteIn(UsesIterator &useIt);
|
||||
void DeleteGate(UsesIterator &useIt);
|
||||
void DecreaseIn(UsesIterator &useIt);
|
||||
void NewIn(GateRef gate, size_t idx, GateRef in);
|
||||
|
||||
private:
|
||||
[[nodiscard]] ConstUsesIterator ConstUseBegin(GateRef gate) const
|
||||
|
@ -509,50 +509,11 @@ void LLVMIRBuilder::HandleRuntimeCall(GateRef gate)
|
||||
VisitRuntimeCall(gate, ins);
|
||||
}
|
||||
|
||||
LLVMValueRef LLVMIRBuilder::GetFunction(LLVMValueRef glue, StubIdType id, bool isDebug)
|
||||
LLVMValueRef LLVMIRBuilder::GetFunction(LLVMValueRef glue, const CallSignature *signature, LLVMValueRef rtbaseoffset)
|
||||
{
|
||||
const CallSignature *signature;
|
||||
int index = 0;
|
||||
if (std::holds_alternative<RuntimeStubCSigns::ID>(id)) {
|
||||
signature = RuntimeStubCSigns::Get(std::get<RuntimeStubCSigns::ID>(id));
|
||||
index = static_cast<int>(std::get<RuntimeStubCSigns::ID>(id));
|
||||
} else if (std::holds_alternative<CommonStubCSigns::ID>(id)) {
|
||||
signature = CommonStubCSigns::Get(std::get<CommonStubCSigns::ID>(id));
|
||||
index = static_cast<int>(std::get<CommonStubCSigns::ID>(id));
|
||||
} else if (std::holds_alternative<LLVMValueRef>(id)) {
|
||||
signature = BytecodeStubCSigns::BCHandler();
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
LLVMTypeRef rtfuncType = llvmModule_->GetFuncType(signature);
|
||||
LLVMTypeRef rtfuncTypePtr = LLVMPointerType(rtfuncType, 0);
|
||||
LLVMTypeRef glueType = LLVMTypeOf(glue);
|
||||
LLVMValueRef rtoffset;
|
||||
LLVMValueRef rtbaseoffset;
|
||||
if (std::holds_alternative<RuntimeStubCSigns::ID>(id)) {
|
||||
rtoffset = LLVMConstInt(glueType,
|
||||
static_cast<int>(JSThread::GlueData::GetRTStubEntriesOffset(compCfg_->Is32Bit())) +
|
||||
index * slotSize_, 0);
|
||||
rtbaseoffset = LLVMBuildAdd(builder_, glue, rtoffset, "");
|
||||
} else if (std::holds_alternative<CommonStubCSigns::ID>(id)) {
|
||||
rtoffset = LLVMConstInt(glueType, JSThread::GlueData::GetCOStubEntriesOffset(compCfg_->Is32Bit()) +
|
||||
static_cast<size_t>(index * slotSize_), 0);
|
||||
rtbaseoffset = LLVMBuildAdd(builder_, glue, rtoffset, "");
|
||||
} else if (std::holds_alternative<LLVMValueRef>(id)) {
|
||||
LLVMValueRef bytecodeoffset;
|
||||
if (isDebug) {
|
||||
bytecodeoffset = LLVMConstInt(glueType,
|
||||
JSThread::GlueData::GetBCDebuggerStubEntriesOffset(compCfg_->Is32Bit()), 0);
|
||||
} else {
|
||||
bytecodeoffset = LLVMConstInt(glueType,
|
||||
JSThread::GlueData::GetBCStubEntriesOffset(compCfg_->Is32Bit()), 0);
|
||||
}
|
||||
LLVMValueRef opcodeOffset = std::get<LLVMValueRef>(id);
|
||||
rtbaseoffset = LLVMBuildAdd(
|
||||
builder_, glue, LLVMBuildAdd(builder_, bytecodeoffset, opcodeOffset, ""), "");
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
LLVMValueRef rtbaseAddr = LLVMBuildIntToPtr(builder_, rtbaseoffset, LLVMPointerType(glueType, 0), "");
|
||||
LLVMValueRef llvmAddr = LLVMBuildLoad(builder_, rtbaseAddr, "");
|
||||
LLVMValueRef callee = LLVMBuildIntToPtr(builder_, llvmAddr, rtfuncTypePtr, "cast");
|
||||
@ -574,8 +535,12 @@ void LLVMIRBuilder::VisitRuntimeCall(GateRef gate, const std::vector<GateRef> &i
|
||||
{
|
||||
ASSERT(llvmModule_ != nullptr);
|
||||
StubIdType stubId = RTSTUB_ID(CallRuntime);
|
||||
LLVMValueRef glue = gate2LValue_[inList[static_cast<size_t>(CallInputs::GLUE)]];
|
||||
LLVMValueRef callee = GetFunction(glue, stubId);
|
||||
LLVMValueRef glue = GetGlue(inList);
|
||||
int stubIndex = static_cast<int>(std::get<RuntimeStubCSigns::ID>(stubId));
|
||||
LLVMValueRef rtoffset = GetRTStubOffset(glue, stubIndex);
|
||||
LLVMValueRef rtbaseoffset = LLVMBuildAdd(builder_, glue, rtoffset, "");
|
||||
const CallSignature *signature = RuntimeStubCSigns::Get(std::get<RuntimeStubCSigns::ID>(stubId));
|
||||
LLVMValueRef callee = GetFunction(glue, signature, rtbaseoffset);
|
||||
|
||||
std::vector<LLVMValueRef> params;
|
||||
params.push_back(glue); // glue
|
||||
@ -603,8 +568,13 @@ void LLVMIRBuilder::HandleRuntimeCallWithArgv(GateRef gate)
|
||||
void LLVMIRBuilder::VisitRuntimeCallWithArgv(GateRef gate, const std::vector<GateRef> &inList)
|
||||
{
|
||||
assert(IsOptimized() == true);
|
||||
LLVMValueRef glue = gate2LValue_[inList[static_cast<size_t>(CallInputs::GLUE)]];
|
||||
LLVMValueRef callee = GetFunction(glue, RTSTUB_ID(CallRuntimeWithArgv));
|
||||
StubIdType stubId = RTSTUB_ID(CallRuntimeWithArgv);
|
||||
LLVMValueRef glue = GetGlue(inList);
|
||||
int stubIndex = static_cast<int>(std::get<RuntimeStubCSigns::ID>(stubId));
|
||||
LLVMValueRef rtoffset = GetRTStubOffset(glue, stubIndex);
|
||||
LLVMValueRef rtbaseoffset = LLVMBuildAdd(builder_, glue, rtoffset, "");
|
||||
const CallSignature *signature = RuntimeStubCSigns::Get(std::get<RuntimeStubCSigns::ID>(stubId));
|
||||
LLVMValueRef callee = GetFunction(glue, signature, rtbaseoffset);
|
||||
|
||||
std::vector<LLVMValueRef> params;
|
||||
params.push_back(glue); // glue
|
||||
@ -668,20 +638,72 @@ void LLVMIRBuilder::SetCallConvAttr(const CallSignature *calleeDescriptor, LLVMV
|
||||
}
|
||||
}
|
||||
|
||||
LLVMValueRef LLVMIRBuilder::GetGlue(const std::vector<GateRef> &inList)
|
||||
{
|
||||
return gate2LValue_[inList[static_cast<size_t>(CallInputs::GLUE)]];
|
||||
}
|
||||
|
||||
LLVMValueRef LLVMIRBuilder::GetRTStubOffset(LLVMValueRef glue, int index)
|
||||
{
|
||||
LLVMTypeRef glueType = LLVMTypeOf(glue);
|
||||
return LLVMConstInt(glueType,
|
||||
static_cast<int>(JSThread::GlueData::GetRTStubEntriesOffset(compCfg_->Is32Bit())) + index * slotSize_, 0);
|
||||
}
|
||||
|
||||
LLVMValueRef LLVMIRBuilder::GetCoStubOffset(LLVMValueRef glue, int index)
|
||||
{
|
||||
LLVMTypeRef glueType = LLVMTypeOf(glue);
|
||||
return LLVMConstInt(glueType, JSThread::GlueData::GetCOStubEntriesOffset(compCfg_->Is32Bit()) +
|
||||
static_cast<size_t>(index * slotSize_), 0);
|
||||
}
|
||||
|
||||
LLVMValueRef LLVMIRBuilder::GetBCStubOffset(LLVMValueRef glue)
|
||||
{
|
||||
LLVMTypeRef glueType = LLVMTypeOf(glue);
|
||||
return LLVMConstInt(glueType, JSThread::GlueData::GetBCStubEntriesOffset(compCfg_->Is32Bit()), 0);
|
||||
}
|
||||
|
||||
LLVMValueRef LLVMIRBuilder::GetBCDebugStubOffset(LLVMValueRef glue)
|
||||
{
|
||||
LLVMTypeRef glueType = LLVMTypeOf(glue);
|
||||
return LLVMConstInt(glueType, JSThread::GlueData::GetBCDebuggerStubEntriesOffset(compCfg_->Is32Bit()), 0);
|
||||
}
|
||||
|
||||
// Only related to the call bytecode in Aot can record bcoffset
|
||||
bool LLVMIRBuilder::NeedBCOffset(OpCode op)
|
||||
{
|
||||
return callConv_ == CallSignature::CallConv::WebKitJSCallConv && op == OpCode::NOGC_RUNTIME_CALL;
|
||||
}
|
||||
|
||||
void LLVMIRBuilder::ComputeArgCountAndBCOffset(size_t &actualNumArgs, LLVMValueRef &bcOffset,
|
||||
const std::vector<GateRef> &inList, OpCode op)
|
||||
{
|
||||
if (NeedBCOffset(op)) {
|
||||
actualNumArgs = inList.size() - 1;
|
||||
bcOffset = gate2LValue_[inList[actualNumArgs]];
|
||||
} else {
|
||||
actualNumArgs = inList.size();
|
||||
}
|
||||
}
|
||||
|
||||
void LLVMIRBuilder::VisitCall(GateRef gate, const std::vector<GateRef> &inList, OpCode op)
|
||||
{
|
||||
static_assert(static_cast<size_t>(CallInputs::FIRST_PARAMETER) == 3);
|
||||
const size_t index = circuit_->GetBitField(inList[static_cast<size_t>(CallInputs::TARGET)]);
|
||||
|
||||
const CallSignature *calleeDescriptor = (op == OpCode::CALL)
|
||||
? CommonStubCSigns::Get(index)
|
||||
: RuntimeStubCSigns::Get(index);
|
||||
StubIdType stubId = static_cast<RuntimeStubCSigns::ID>(index);
|
||||
const CallSignature *calleeDescriptor = nullptr;
|
||||
LLVMValueRef glue = GetGlue(inList);
|
||||
LLVMValueRef rtoffset;
|
||||
LLVMValueRef rtbaseoffset;
|
||||
if (op == OpCode::CALL) {
|
||||
stubId = static_cast<CommonStubCSigns::ID>(index);
|
||||
calleeDescriptor = CommonStubCSigns::Get(index);
|
||||
rtoffset = GetCoStubOffset(glue, index);
|
||||
rtbaseoffset = LLVMBuildAdd(builder_, glue, rtoffset, "");
|
||||
} else {
|
||||
calleeDescriptor = RuntimeStubCSigns::Get(index);
|
||||
rtoffset = GetRTStubOffset(glue, index);
|
||||
rtbaseoffset = LLVMBuildAdd(builder_, glue, rtoffset, "");
|
||||
}
|
||||
LLVMValueRef glue = gate2LValue_[inList[static_cast<size_t>(CallInputs::GLUE)]];
|
||||
LLVMValueRef callee = GetFunction(glue, stubId);
|
||||
LLVMValueRef callee = GetFunction(glue, calleeDescriptor, rtbaseoffset);
|
||||
|
||||
std::vector<LLVMValueRef> params;
|
||||
const size_t firstArg = static_cast<size_t>(CallInputs::FIRST_PARAMETER);
|
||||
@ -698,13 +720,27 @@ void LLVMIRBuilder::VisitCall(GateRef gate, const std::vector<GateRef> &inList,
|
||||
extraParameterCnt += CompilationConfig::FAKE_REGISTER_PARAMTERS_ARM32;
|
||||
}
|
||||
}
|
||||
size_t actualNumArgs = 0;
|
||||
LLVMValueRef bcOffset = LLVMConstInt(LLVMInt32Type(), 0, 0);
|
||||
ComputeArgCountAndBCOffset(actualNumArgs, bcOffset, inList, op);
|
||||
|
||||
// then push the actual parameter for js function call
|
||||
for (size_t paraIdx = firstArg + 1; paraIdx < inList.size(); ++paraIdx) {
|
||||
for (size_t paraIdx = firstArg + 1; paraIdx < actualNumArgs; ++paraIdx) {
|
||||
GateRef gateTmp = inList[paraIdx];
|
||||
params.push_back(gate2LValue_[gateTmp]);
|
||||
}
|
||||
LLVMValueRef call = LLVMBuildCall(builder_, callee, params.data(),
|
||||
inList.size() - firstArg + extraParameterCnt, "");
|
||||
|
||||
LLVMValueRef call = 0;
|
||||
if (NeedBCOffset(op)) {
|
||||
LLVMTypeRef funcType = llvmModule_->GetFuncType(calleeDescriptor);
|
||||
std::vector<LLVMValueRef> values;
|
||||
values.push_back(bcOffset);
|
||||
call = LLVMBuildCall3(
|
||||
builder_, funcType, callee, params.data(), actualNumArgs - firstArg + extraParameterCnt, "", values.data(),
|
||||
values.size());
|
||||
} else {
|
||||
call = LLVMBuildCall(builder_, callee, params.data(), actualNumArgs - firstArg + extraParameterCnt, "");
|
||||
}
|
||||
SetCallConvAttr(calleeDescriptor, call);
|
||||
gate2LValue_[gate] = call;
|
||||
return;
|
||||
@ -720,8 +756,11 @@ void LLVMIRBuilder::VisitBytecodeCall(GateRef gate, const std::vector<GateRef> &
|
||||
|
||||
// start index of bytecode handler csign in llvmModule
|
||||
LLVMValueRef glue = gate2LValue_[inList[glueIndex]];
|
||||
StubIdType stubId = opcodeOffset;
|
||||
LLVMValueRef callee = GetFunction(glue, stubId);
|
||||
LLVMValueRef bytecodeoffset = GetBCStubOffset(glue);
|
||||
LLVMValueRef rtbaseoffset = LLVMBuildAdd(
|
||||
builder_, glue, LLVMBuildAdd(builder_, bytecodeoffset, opcodeOffset, ""), "");
|
||||
const CallSignature *signature = BytecodeStubCSigns::BCHandler();
|
||||
LLVMValueRef callee = GetFunction(glue, signature, rtbaseoffset);
|
||||
|
||||
std::vector<LLVMValueRef> params;
|
||||
for (size_t paraIdx = paraStartIndex; paraIdx < inList.size(); ++paraIdx) {
|
||||
@ -745,8 +784,11 @@ void LLVMIRBuilder::VisitDebuggerBytecodeCall(GateRef gate, const std::vector<Ga
|
||||
|
||||
// start index of bytecode handler csign in llvmModule
|
||||
LLVMValueRef glue = gate2LValue_[inList[glueIndex]];
|
||||
StubIdType stubId = opcodeOffset;
|
||||
LLVMValueRef callee = GetFunction(glue, stubId, true);
|
||||
LLVMValueRef bytecodeoffset = GetBCDebugStubOffset(glue);
|
||||
LLVMValueRef rtbaseoffset = LLVMBuildAdd(
|
||||
builder_, glue, LLVMBuildAdd(builder_, bytecodeoffset, opcodeOffset, ""), "");
|
||||
const CallSignature *signature = BytecodeStubCSigns::BCHandler();
|
||||
LLVMValueRef callee = GetFunction(glue, signature, rtbaseoffset);
|
||||
|
||||
std::vector<LLVMValueRef> params;
|
||||
for (size_t paraIdx = paraStartIndex; paraIdx < inList.size(); ++paraIdx) {
|
||||
|
@ -289,13 +289,21 @@ private:
|
||||
{
|
||||
return enableLog_;
|
||||
}
|
||||
LLVMValueRef GetFunction(LLVMValueRef glue, StubIdType id, bool isDebug = false);
|
||||
LLVMValueRef GetFunction(LLVMValueRef glue, const CallSignature *signature, LLVMValueRef rtbaseoffset);
|
||||
bool IsInterpreted();
|
||||
bool IsOptimized();
|
||||
void SetGCLeafFunction(LLVMValueRef call);
|
||||
void SetCallConvAttr(const CallSignature *calleeDescriptor, LLVMValueRef call);
|
||||
|
||||
private:
|
||||
LLVMValueRef GetGlue(const std::vector<GateRef> &inList);
|
||||
LLVMValueRef GetRTStubOffset(LLVMValueRef glue, int index);
|
||||
LLVMValueRef GetCoStubOffset(LLVMValueRef glue, int index);
|
||||
LLVMValueRef GetBCStubOffset(LLVMValueRef glue);
|
||||
LLVMValueRef GetBCDebugStubOffset(LLVMValueRef glue);
|
||||
bool NeedBCOffset(OpCode op);
|
||||
void ComputeArgCountAndBCOffset(size_t &actualNumArgs, LLVMValueRef &bcOffset, const std::vector<GateRef> &inList,
|
||||
OpCode op);
|
||||
const CompilationConfig *compCfg_ {nullptr};
|
||||
const std::vector<std::vector<GateRef>> *scheduledGates_ {nullptr};
|
||||
const Circuit *circuit_ {nullptr};
|
||||
|
@ -48,6 +48,14 @@ void SlowPathLowering::CallRuntimeLowering()
|
||||
}
|
||||
}
|
||||
|
||||
int32_t SlowPathLowering::ComputeCallArgc(GateRef gate, EcmaOpcode op)
|
||||
{
|
||||
if (op == EcmaOpcode::CALLITHISRANGEDYN_PREF_IMM16_V8) {
|
||||
return acc_.GetNumValueIn(gate) + NUM_MANDATORY_JSFUNC_ARGS - 3; // 3: calltarget, this and bcoffset
|
||||
}
|
||||
return acc_.GetNumValueIn(gate) + NUM_MANDATORY_JSFUNC_ARGS - 2; // 2: calltarget and bcoffset
|
||||
}
|
||||
|
||||
void SlowPathLowering::ReplaceHirControlGate(GateAccessor::UsesIterator &useIt, GateRef newGate, bool noThrow)
|
||||
{
|
||||
GateAccessor acc(circuit_);
|
||||
@ -796,40 +804,47 @@ void SlowPathLowering::LowerToJSCall(GateRef gate, GateRef glue, const std::vect
|
||||
|
||||
void SlowPathLowering::LowerCallArg0Dyn(GateRef gate, GateRef glue)
|
||||
{
|
||||
ASSERT(acc_.GetNumValueIn(gate) == 1);
|
||||
GateRef actualArgc = builder_.Int32(acc_.GetNumValueIn(gate) - 1 + NUM_MANDATORY_JSFUNC_ARGS);
|
||||
// 2: number of value inputs
|
||||
ASSERT(acc_.GetNumValueIn(gate) == 2);
|
||||
|
||||
GateRef actualArgc = builder_.Int32(ComputeCallArgc(gate, EcmaOpcode::CALLARG0DYN_PREF_V8));
|
||||
GateRef newTarget = builder_.Undefined();
|
||||
GateRef thisObj = builder_.Undefined();
|
||||
LowerToJSCall(gate, glue, {glue, actualArgc, acc_.GetValueIn(gate, 0), newTarget, thisObj});
|
||||
LowerToJSCall(gate, glue, {glue, actualArgc, acc_.GetValueIn(gate, 0), newTarget, thisObj,
|
||||
acc_.GetValueIn(gate, 1)});
|
||||
}
|
||||
|
||||
void SlowPathLowering::LowerCallArg1Dyn(GateRef gate, GateRef glue)
|
||||
{
|
||||
// 2: number of value inputs
|
||||
ASSERT(acc_.GetNumValueIn(gate) == 2);
|
||||
GateRef actualArgc = builder_.Int32(acc_.GetNumValueIn(gate) - 1 + NUM_MANDATORY_JSFUNC_ARGS);
|
||||
GateRef newTarget = builder_.Undefined();
|
||||
GateRef thisObj = builder_.Undefined();
|
||||
LowerToJSCall(gate, glue, {glue, actualArgc,
|
||||
acc_.GetValueIn(gate, 0), newTarget, thisObj, acc_.GetValueIn(gate, 1)});
|
||||
}
|
||||
|
||||
void SlowPathLowering::LowerCallArgs2Dyn(GateRef gate, GateRef glue)
|
||||
{
|
||||
// 3: number of value inputs
|
||||
ASSERT(acc_.GetNumValueIn(gate) == 3);
|
||||
GateRef actualArgc = builder_.Int32(acc_.GetNumValueIn(gate) - 1 + NUM_MANDATORY_JSFUNC_ARGS);
|
||||
// 2: func and bcoffset
|
||||
GateRef actualArgc = builder_.Int32(ComputeCallArgc(gate, EcmaOpcode::CALLARG1DYN_PREF_V8_V8));
|
||||
GateRef newTarget = builder_.Undefined();
|
||||
GateRef thisObj = builder_.Undefined();
|
||||
LowerToJSCall(gate, glue, {glue, actualArgc,
|
||||
acc_.GetValueIn(gate, 0), newTarget, thisObj, acc_.GetValueIn(gate, 1), acc_.GetValueIn(gate, 2)});
|
||||
}
|
||||
|
||||
void SlowPathLowering::LowerCallArgs3Dyn(GateRef gate, GateRef glue)
|
||||
void SlowPathLowering::LowerCallArgs2Dyn(GateRef gate, GateRef glue)
|
||||
{
|
||||
// 4: number of value inputs
|
||||
ASSERT(acc_.GetNumValueIn(gate) == 4);
|
||||
GateRef actualArgc = builder_.Int32(acc_.GetNumValueIn(gate) - 1 + NUM_MANDATORY_JSFUNC_ARGS);
|
||||
// 2: func and bcoffset
|
||||
GateRef actualArgc = builder_.Int32(ComputeCallArgc(gate, EcmaOpcode::CALLARGS2DYN_PREF_V8_V8_V8));
|
||||
GateRef newTarget = builder_.Undefined();
|
||||
GateRef thisObj = builder_.Undefined();
|
||||
LowerToJSCall(gate, glue, {glue, actualArgc,
|
||||
acc_.GetValueIn(gate, 0), newTarget, thisObj, acc_.GetValueIn(gate, 1), acc_.GetValueIn(gate, 2),
|
||||
acc_.GetValueIn(gate, 3)});
|
||||
}
|
||||
|
||||
void SlowPathLowering::LowerCallArgs3Dyn(GateRef gate, GateRef glue)
|
||||
{
|
||||
// 5: number of value inputs
|
||||
ASSERT(acc_.GetNumValueIn(gate) == 5);
|
||||
// 2: func and bcoffset
|
||||
GateRef actualArgc = builder_.Int32(ComputeCallArgc(gate, EcmaOpcode::CALLARGS3DYN_PREF_V8_V8_V8_V8));
|
||||
GateRef newTarget = builder_.Undefined();
|
||||
GateRef thisObj = builder_.Undefined();
|
||||
LowerToJSCall(gate, glue, {glue, actualArgc,
|
||||
@ -842,9 +857,8 @@ void SlowPathLowering::LowerCallIThisRangeDyn(GateRef gate, GateRef glue)
|
||||
std::vector<GateRef> vec;
|
||||
// The first register input is callTarget, second is thisObj and other inputs are common args.
|
||||
size_t fixedInputsNum = 2;
|
||||
size_t numArgs = acc_.GetNumValueIn(gate) - fixedInputsNum;
|
||||
ASSERT(numArgs >= 0);
|
||||
GateRef actualArgc = builder_.Int32(numArgs + NUM_MANDATORY_JSFUNC_ARGS);
|
||||
ASSERT(acc_.GetNumValueIn(gate) - fixedInputsNum >= 0);
|
||||
GateRef actualArgc = builder_.Int32(ComputeCallArgc(gate, EcmaOpcode::CALLITHISRANGEDYN_PREF_IMM16_V8));
|
||||
GateRef callTarget = acc_.GetValueIn(gate, 0);
|
||||
GateRef thisObj = acc_.GetValueIn(gate, 1);
|
||||
GateRef newTarget = builder_.Undefined();
|
||||
@ -875,7 +889,7 @@ void SlowPathLowering::LowerCallIRangeDyn(GateRef gate, GateRef glue)
|
||||
{
|
||||
std::vector<GateRef> vec;
|
||||
size_t numArgs = acc_.GetNumValueIn(gate) - 1;
|
||||
GateRef actualArgc = builder_.Int32(numArgs + NUM_MANDATORY_JSFUNC_ARGS);
|
||||
GateRef actualArgc = builder_.Int32(ComputeCallArgc(gate, EcmaOpcode::CALLIRANGEDYN_PREF_IMM16_V8));
|
||||
GateRef callTarget = acc_.GetValueIn(gate, 0);
|
||||
GateRef newTarget = builder_.Undefined();
|
||||
GateRef thisObj = builder_.Undefined();
|
||||
|
@ -263,6 +263,7 @@ private:
|
||||
void LowerGetUnmappedArgs(GateRef gate, GateRef glue);
|
||||
void LowerCopyRestArgs(GateRef gate, GateRef glue);
|
||||
GateRef LowerCallRuntime(GateRef glue, int index, const std::vector<GateRef> &args, bool useLabel = false);
|
||||
int32_t ComputeCallArgc(GateRef gate, EcmaOpcode op);
|
||||
|
||||
BytecodeCircuitBuilder *bcBuilder_;
|
||||
Circuit *circuit_;
|
||||
|
@ -33,11 +33,12 @@ void FooAOTStub::GenerateCircuit(const CompilationConfig *cfg)
|
||||
GateRef thisObj = TaggedArgument(4);
|
||||
GateRef a = TaggedArgument(5);
|
||||
GateRef b = TaggedArgument(6);
|
||||
GateRef bcOffset = Int32Argument(1);
|
||||
(void)calltarget;
|
||||
GateRef barIndex = IntBuildTaggedWithNoGC(Int32(CommonStubCSigns::BarAOT));
|
||||
GateRef numArgs = IntBuildTaggedWithNoGC(Int32(2));
|
||||
GateRef barfunc = CallRuntime(glue, RTSTUB_ID(DefineAotFunc), {barIndex, numArgs});
|
||||
GateRef result = CallNGCRuntime(glue, RTSTUB_ID(JSCall), {glue, argc, barfunc, newtarget, thisObj, a, b});
|
||||
GateRef result = CallNGCRuntime(glue, RTSTUB_ID(JSCall), {glue, argc, barfunc, newtarget, thisObj, a, b, bcOffset});
|
||||
Return(result);
|
||||
}
|
||||
|
||||
@ -65,11 +66,12 @@ void Foo1AOTStub::GenerateCircuit(const CompilationConfig *cfg)
|
||||
GateRef thisObj = TaggedArgument(4);
|
||||
GateRef a = TaggedArgument(5);
|
||||
GateRef b = TaggedArgument(6);
|
||||
GateRef bcOffset = Int32Argument(1);
|
||||
(void)calltarget;
|
||||
GateRef barIndex = IntBuildTaggedTypeWithNoGC(Int32(CommonStubCSigns::Bar1AOT));
|
||||
GateRef numArgs = IntBuildTaggedTypeWithNoGC(Int32(3));
|
||||
GateRef barfunc = CallRuntime(glue, RTSTUB_ID(DefineAotFunc), {barIndex, numArgs});
|
||||
GateRef result = CallNGCRuntime(glue, RTSTUB_ID(JSCall), {glue, argc, barfunc, newtarget, thisObj, a, b});
|
||||
GateRef result = CallNGCRuntime(glue, RTSTUB_ID(JSCall), {glue, argc, barfunc, newtarget, thisObj, a, b, bcOffset});
|
||||
Return(result);
|
||||
}
|
||||
|
||||
@ -103,13 +105,14 @@ void Foo2AOTStub::GenerateCircuit(const CompilationConfig *cfg)
|
||||
GateRef thisObj = TaggedArgument(4);
|
||||
GateRef a = TaggedArgument(5);
|
||||
GateRef b = TaggedArgument(6);
|
||||
GateRef bcOffset = Int32Argument(1);
|
||||
(void)calltarget;
|
||||
GateRef actualArgC = Int32Add(argc, Int32(1));
|
||||
GateRef barIndex = IntBuildTaggedTypeWithNoGC(Int32(CommonStubCSigns::BarAOT));
|
||||
GateRef numArgs = IntBuildTaggedTypeWithNoGC(Int32(2));
|
||||
GateRef barfunc = CallRuntime(glue, RTSTUB_ID(DefineAotFunc), {barIndex, numArgs});
|
||||
GateRef result = CallNGCRuntime(glue, RTSTUB_ID(JSCall), {glue, actualArgC, barfunc, newtarget, thisObj,
|
||||
a, b, Undefined()});
|
||||
a, b, Undefined(), bcOffset});
|
||||
Return(result);
|
||||
}
|
||||
|
||||
@ -123,11 +126,12 @@ void FooNativeAOTStub::GenerateCircuit(const CompilationConfig *cfg)
|
||||
GateRef thisObj = TaggedArgument(4);
|
||||
GateRef a = TaggedArgument(5);
|
||||
GateRef b = TaggedArgument(6);
|
||||
GateRef bcOffset = Int32Argument(1);
|
||||
(void)calltarget;
|
||||
GateRef actualArgC = Int32Add(argc, Int32(1));
|
||||
GateRef printfunc = CallRuntime(glue, RTSTUB_ID(GetPrintFunc), {});
|
||||
GateRef result = CallNGCRuntime(glue, RTSTUB_ID(JSCall), {glue, actualArgC, printfunc, newtarget, thisObj,
|
||||
a, b, Undefined()});
|
||||
a, b, Undefined(), bcOffset});
|
||||
Return(result);
|
||||
}
|
||||
|
||||
@ -142,15 +146,16 @@ void FooBoundAOTStub::GenerateCircuit(const CompilationConfig *cfg)
|
||||
GateRef a = TaggedArgument(5);
|
||||
GateRef b = TaggedArgument(6);
|
||||
GateRef bindArguments = IntBuildTaggedTypeWithNoGC(Int32(37));
|
||||
GateRef bcOffset = Int32Argument(1);
|
||||
(void)calltarget;
|
||||
GateRef numArgs = IntBuildTaggedTypeWithNoGC(Int32(2));
|
||||
GateRef barIndex = IntBuildTaggedTypeWithNoGC(Int32(CommonStubCSigns::BarAOT));
|
||||
GateRef barfunc = CallRuntime(glue, RTSTUB_ID(DefineAotFunc), {barIndex, numArgs});
|
||||
GateRef bindfunc = CallRuntime(glue, RTSTUB_ID(GetBindFunc), {barfunc});
|
||||
GateRef newjsfunc = CallNGCRuntime(glue, RTSTUB_ID(JSCall), {glue, Int32(5), bindfunc, newtarget, barfunc,
|
||||
Int64(0x02), bindArguments});
|
||||
Int64(0x02), bindArguments, bcOffset});
|
||||
GateRef result = CallNGCRuntime(glue, RTSTUB_ID(JSCall), {glue, argc, newjsfunc, newtarget, thisObj,
|
||||
a, b});
|
||||
a, b, bcOffset});
|
||||
Return(result);
|
||||
}
|
||||
|
||||
@ -164,13 +169,15 @@ void FooProxyAOTStub::GenerateCircuit(const CompilationConfig *cfg)
|
||||
GateRef thisObj = TaggedArgument(4);
|
||||
GateRef a = TaggedArgument(5);
|
||||
GateRef b = TaggedArgument(6);
|
||||
GateRef bcOffset = Int32Argument(1);
|
||||
|
||||
GateRef barIndex = IntBuildTaggedTypeWithNoGC(Int32(CommonStubCSigns::BarAOT));
|
||||
GateRef numArgs = IntBuildTaggedTypeWithNoGC(Int32(2));
|
||||
GateRef barfunc = CallRuntime(glue, RTSTUB_ID(DefineAotFunc), {barIndex, numArgs});
|
||||
|
||||
GateRef proxyfunc = CallRuntime(glue, RTSTUB_ID(DefineProxyFunc), {barfunc});
|
||||
GateRef result = CallNGCRuntime(glue, RTSTUB_ID(JSCall), {glue, argc, proxyfunc, newtarget, thisObj, a, b});
|
||||
GateRef result =
|
||||
CallNGCRuntime(glue, RTSTUB_ID(JSCall), {glue, argc, proxyfunc, newtarget, thisObj, a, b, bcOffset});
|
||||
Return(result);
|
||||
}
|
||||
|
||||
@ -184,6 +191,7 @@ void FooProxy2AOTStub::GenerateCircuit(const CompilationConfig *cfg)
|
||||
GateRef thisObj = TaggedArgument(4);
|
||||
GateRef a = TaggedArgument(5);
|
||||
GateRef b = TaggedArgument(6);
|
||||
GateRef bcOffset = Int32Argument(1);
|
||||
|
||||
GateRef barIndex = IntBuildTaggedTypeWithNoGC(Int32(CommonStubCSigns::Bar2AOT));
|
||||
GateRef numArgs = IntBuildTaggedTypeWithNoGC(Int32(2));
|
||||
@ -191,7 +199,8 @@ void FooProxy2AOTStub::GenerateCircuit(const CompilationConfig *cfg)
|
||||
GateRef proxyHandler = CallRuntime(glue, RTSTUB_ID(DefineProxyHandler), {barfunc});
|
||||
|
||||
GateRef proxyfunc = CallRuntime(glue, RTSTUB_ID(DefineProxyFunc2), {barfunc, proxyHandler});
|
||||
GateRef result = CallNGCRuntime(glue, RTSTUB_ID(JSCall), {glue, argc, proxyfunc, newtarget, thisObj, a, b});
|
||||
GateRef result =
|
||||
CallNGCRuntime(glue, RTSTUB_ID(JSCall), {glue, argc, proxyfunc, newtarget, thisObj, a, b, bcOffset});
|
||||
Return(result);
|
||||
}
|
||||
|
||||
|
@ -275,12 +275,15 @@
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||
#define THROW_NEW_ERROR_AND_RETURN(thread, error) \
|
||||
do { \
|
||||
if (!(thread)->HasPendingException()) { \
|
||||
(thread)->SetException(error); \
|
||||
} \
|
||||
return; \
|
||||
#define THROW_NEW_ERROR_AND_RETURN(thread, error) \
|
||||
do { \
|
||||
if (!(thread)->HasPendingException()) { \
|
||||
(thread)->SetException(error); \
|
||||
if ((thread)->IsPrintBCOffset()) { \
|
||||
(thread)->CollectBCOffsetInfo(); \
|
||||
} \
|
||||
} \
|
||||
return; \
|
||||
} while (false)
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||
@ -292,6 +295,9 @@
|
||||
ObjectFactory *_factory = (thread)->GetEcmaVM()->GetFactory(); \
|
||||
JSHandle<JSObject> _error = _factory->GetJSError(type, message); \
|
||||
(thread)->SetException(_error.GetTaggedValue()); \
|
||||
if ((thread)->IsPrintBCOffset()) { \
|
||||
(thread)->CollectBCOffsetInfo(); \
|
||||
} \
|
||||
return; \
|
||||
} while (false)
|
||||
|
||||
@ -300,6 +306,9 @@
|
||||
do { \
|
||||
if (!(thread)->HasPendingException()) { \
|
||||
(thread)->SetException(error); \
|
||||
if ((thread)->IsPrintBCOffset()) { \
|
||||
(thread)->CollectBCOffsetInfo(); \
|
||||
} \
|
||||
} \
|
||||
return (value); \
|
||||
} while (false)
|
||||
@ -313,6 +322,9 @@
|
||||
ObjectFactory *_factory = (thread)->GetEcmaVM()->GetFactory(); \
|
||||
JSHandle<JSObject> _error = _factory->GetJSError(errorType, message); \
|
||||
(thread)->SetException(_error.GetTaggedValue()); \
|
||||
if ((thread)->IsPrintBCOffset()) { \
|
||||
(thread)->CollectBCOffsetInfo(); \
|
||||
} \
|
||||
return (value); \
|
||||
} while (false)
|
||||
|
||||
|
@ -391,6 +391,7 @@ Expected<JSTaggedValue, bool> EcmaVM::InvokeEcmaEntrypoint(const JSPandaFile *js
|
||||
|
||||
auto options = GetJSOptions();
|
||||
if (options.EnableTSAot()) {
|
||||
thread_->SetPrintBCOffset(true);
|
||||
result = InvokeEcmaAotEntrypoint(func, jsPandaFile);
|
||||
} else {
|
||||
if (jsPandaFile->IsCjs()) {
|
||||
@ -501,6 +502,11 @@ void EcmaVM::HandleUncaughtException(ObjectHeader *exception)
|
||||
thread_->ClearException();
|
||||
if (exceptionHandle->IsJSError()) {
|
||||
PrintJSErrorInfo(exceptionHandle);
|
||||
if (thread_->IsPrintBCOffset() && exceptionBCList_.size() != 0) {
|
||||
for (auto info : exceptionBCList_) {
|
||||
LOG(ERROR, RUNTIME) << "Exception at function " << info.first << ": " << info.second;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
JSHandle<EcmaString> result = JSTaggedValue::ToString(thread_, exceptionHandle);
|
||||
|
@ -328,6 +328,21 @@ public:
|
||||
JSTaggedValue FindConstpool(const JSPandaFile *jsPandaFile);
|
||||
|
||||
void SetAOTFuncEntry(uint32_t hash, uint32_t methodId, uint64_t funcEntry);
|
||||
void StoreBCOffsetInfo(const std::string& methodName, int32_t bcOffset)
|
||||
{
|
||||
exceptionBCList_.emplace_back(std::pair<std::string, int32_t>(methodName, bcOffset));
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, int32_t>> GetBCOffsetInfoList() const
|
||||
{
|
||||
return exceptionBCList_;
|
||||
}
|
||||
|
||||
void ClearExceptionBCList()
|
||||
{
|
||||
exceptionBCList_.clear();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
void HandleUncaughtException(ObjectHeader *exception);
|
||||
@ -415,6 +430,7 @@ private:
|
||||
// atomics
|
||||
bool AllowAtomicWait_ {true};
|
||||
WaiterListNode waiterListNode_;
|
||||
std::vector<std::pair<std::string, int32_t>> exceptionBCList_;
|
||||
|
||||
// CJS resolve path Callbacks
|
||||
ResolvePathCallback resolvePathCallback_ {nullptr};
|
||||
|
@ -783,4 +783,103 @@ void FrameHandler::IterateFrameChain(JSTaggedType *start, const RootVisitor &v0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string FrameHandler::GetAotExceptionFuncName(JSTaggedType* fp) const
|
||||
{
|
||||
ASSERT(FrameHandler::GetFrameType(fp) == FrameType::OPTIMIZED_JS_FUNCTION_FRAME);
|
||||
JSTaggedValue func = JSTaggedValue(*(fp + 3)); // 3: skip returnaddr and argc
|
||||
JSMethod *method = JSFunction::Cast(func.GetTaggedObject())->GetMethod();
|
||||
return method->GetMethodName();
|
||||
}
|
||||
|
||||
void FrameHandler::CollectBCOffsetInfo()
|
||||
{
|
||||
thread_->GetEcmaVM()->ClearExceptionBCList();
|
||||
JSTaggedType *current = const_cast<JSTaggedType *>(thread_->GetLastLeaveFrame());
|
||||
while (current) {
|
||||
FrameType type = FrameHandler::GetFrameType(current);
|
||||
switch (type) {
|
||||
case FrameType::OPTIMIZED_FRAME: {
|
||||
auto frame = OptimizedFrame::GetFrameFromSp(current);
|
||||
current = frame->GetPrevFrameFp();
|
||||
break;
|
||||
}
|
||||
case FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME:
|
||||
case FrameType::OPTIMIZED_JS_FUNCTION_FRAME: {
|
||||
auto frame = OptimizedJSFunctionFrame::GetFrameFromSp(current);
|
||||
auto returnAddr = reinterpret_cast<uintptr_t>(
|
||||
*(reinterpret_cast<uintptr_t*>(const_cast<JSTaggedType *>(current)) + 1));
|
||||
bool enableCompilerLog = thread_->GetEcmaVM()->GetJSOptions().WasSetlogCompiledMethods();
|
||||
auto constInfo = kungfu::LLVMStackMapParser::GetInstance(enableCompilerLog).GetConstInfo(returnAddr);
|
||||
if (!constInfo.empty()) {
|
||||
auto prevFp = frame->GetPrevFrameFp();
|
||||
auto name = GetAotExceptionFuncName(prevFp);
|
||||
thread_->GetEcmaVM()->StoreBCOffsetInfo(name, constInfo[0]);
|
||||
}
|
||||
current = frame->GetPrevFrameFp();
|
||||
break;
|
||||
}
|
||||
case FrameType::OPTIMIZED_ENTRY_FRAME: {
|
||||
auto frame = OptimizedEntryFrame::GetFrameFromSp(current);
|
||||
current = frame->GetPrevFrameFp();
|
||||
break;
|
||||
}
|
||||
case FrameType::ASM_INTERPRETER_ENTRY_FRAME: {
|
||||
auto frame = AsmInterpretedEntryFrame::GetFrameFromSp(current);
|
||||
current = frame->GetPrevFrameFp();
|
||||
break;
|
||||
}
|
||||
case FrameType::ASM_INTERPRETER_FRAME:
|
||||
case FrameType::INTERPRETER_CONSTRUCTOR_FRAME: {
|
||||
auto frame = AsmInterpretedFrame::GetFrameFromSp(current);
|
||||
current = frame->GetPrevFrameFp();
|
||||
break;
|
||||
}
|
||||
case FrameType::INTERPRETER_FRAME:
|
||||
case FrameType::INTERPRETER_FAST_NEW_FRAME: {
|
||||
auto frame = InterpretedFrame::GetFrameFromSp(current);
|
||||
current = frame->GetPrevFrameFp();
|
||||
break;
|
||||
}
|
||||
case FrameType::LEAVE_FRAME: {
|
||||
auto frame = OptimizedLeaveFrame::GetFrameFromSp(current);
|
||||
auto returnAddr = frame->returnAddr;
|
||||
bool enableCompilerLog = thread_->GetEcmaVM()->GetJSOptions().WasSetlogCompiledMethods();
|
||||
auto constInfo = kungfu::LLVMStackMapParser::GetInstance(enableCompilerLog).GetConstInfo(returnAddr);
|
||||
if (!constInfo.empty()) {
|
||||
auto prevFp = frame->GetPrevFrameFp();
|
||||
auto name = GetAotExceptionFuncName(prevFp);
|
||||
thread_->GetEcmaVM()->StoreBCOffsetInfo(name, constInfo[0]);
|
||||
}
|
||||
current = frame->GetPrevFrameFp();
|
||||
break;
|
||||
}
|
||||
case FrameType::LEAVE_FRAME_WITH_ARGV: {
|
||||
auto frame = OptimizedLeaveFrame::GetFrameFromSp(current);
|
||||
current = frame->GetPrevFrameFp();
|
||||
break;
|
||||
}
|
||||
case FrameType::BUILTIN_FRAME_WITH_ARGV: {
|
||||
auto frame = BuiltinWithArgvFrame::GetFrameFromSp(current);
|
||||
current = frame->GetPrevFrameFp();
|
||||
break;
|
||||
}
|
||||
case FrameType::BUILTIN_ENTRY_FRAME:
|
||||
case FrameType::BUILTIN_FRAME: {
|
||||
auto frame = BuiltinFrame::GetFrameFromSp(current);
|
||||
current = frame->GetPrevFrameFp();
|
||||
break;
|
||||
}
|
||||
case FrameType::INTERPRETER_ENTRY_FRAME: {
|
||||
auto frame = InterpretedEntryFrame::GetFrameFromSp(current);
|
||||
current = frame->GetPrevFrameFp();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
LOG_ECMA(FATAL) << "frame type error!";
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace panda::ecmascript
|
||||
|
@ -152,6 +152,10 @@ public:
|
||||
void IterateRsp(const RootVisitor &v0, const RootRangeVisitor &v1);
|
||||
void IterateSp(const RootVisitor &v0, const RootRangeVisitor &v1);
|
||||
|
||||
// for collecting bc offset in aot
|
||||
void CollectBCOffsetInfo();
|
||||
std::string GetAotExceptionFuncName(JSTaggedType* fp) const;
|
||||
|
||||
private:
|
||||
FrameType GetFrameType() const
|
||||
{
|
||||
|
@ -296,4 +296,10 @@ void JSThread::CheckJSTaggedType(JSTaggedType value) const
|
||||
LOG(FATAL, RUNTIME) << "value:" << value << " is invalid!";
|
||||
}
|
||||
}
|
||||
|
||||
void JSThread::CollectBCOffsetInfo()
|
||||
{
|
||||
FrameHandler frameHandler(this);
|
||||
frameHandler.CollectBCOffsetInfo();
|
||||
}
|
||||
} // namespace panda::ecmascript
|
||||
|
@ -490,6 +490,18 @@ public:
|
||||
return reinterpret_cast<JSThread *>(glue - GetGlueDataOffset());
|
||||
}
|
||||
|
||||
bool IsPrintBCOffset() const
|
||||
{
|
||||
return enablePrintBCOffset_;
|
||||
}
|
||||
|
||||
void SetPrintBCOffset(bool flag)
|
||||
{
|
||||
enablePrintBCOffset_ = flag;
|
||||
}
|
||||
|
||||
void CollectBCOffsetInfo();
|
||||
|
||||
struct GlueData : public base::AlignedStruct<JSTaggedValue::TaggedTypeSize(),
|
||||
JSTaggedValue,
|
||||
JSTaggedValue,
|
||||
@ -641,6 +653,7 @@ private:
|
||||
bool gcState_ {false};
|
||||
bool isAsmInterpreter_ {false};
|
||||
VmThreadControl *vmThreadControl_ {nullptr};
|
||||
bool enablePrintBCOffset_ {false};
|
||||
bool stableArrayElementsGuardians_ {true};
|
||||
GlueData glueData_;
|
||||
|
||||
|
@ -165,9 +165,10 @@ JSMethod *ObjectFactory::NewMethodForNativeFunction(const void *func)
|
||||
return nativeMethods_.back();
|
||||
}
|
||||
|
||||
JSMethod *ObjectFactory::NewMethodForAOTFunction(const void *func, size_t numArgs)
|
||||
JSMethod *ObjectFactory::NewMethodForAOTFunction(const void *func, size_t numArgs, const JSPandaFile *pf,
|
||||
uint32_t methodId)
|
||||
{
|
||||
auto method = vm_->GetChunk()->New<JSMethod>(nullptr, panda_file::File::EntityId(0)); // 0 : temporary file id
|
||||
auto method = vm_->GetChunk()->New<JSMethod>(pf, panda_file::File::EntityId(methodId));
|
||||
method->SetNativePointer(const_cast<void *>(func));
|
||||
method->SetAotCodeBit(true);
|
||||
method->SetNativeBit(false);
|
||||
|
@ -174,7 +174,7 @@ public:
|
||||
void GenerateInternalNativeMethods();
|
||||
JSMethod *GetMethodByIndex(MethodIndex idx);
|
||||
JSMethod *NewMethodForNativeFunction(const void *func);
|
||||
JSMethod *NewMethodForAOTFunction(const void *func, size_t numArgs);
|
||||
JSMethod *NewMethodForAOTFunction(const void *func, size_t numArgs, const JSPandaFile *pf, uint32_t methodId);
|
||||
|
||||
JSHandle<ProfileTypeInfo> NewProfileTypeInfo(uint32_t length);
|
||||
JSHandle<ConstantPool> NewConstantPool(uint32_t capacity);
|
||||
|
@ -29,6 +29,7 @@ group("ark_aot_test") {
|
||||
# "definencfunc:definencfuncAotAction",
|
||||
"delobjprop:delobjpropAotAction",
|
||||
"div:divAotAction",
|
||||
"exceptionhandler:exceptionhandlerAotAction",
|
||||
"exp:expAotAction",
|
||||
"helloaot:helloaotAotAction",
|
||||
"inc:incAotAction",
|
||||
|
18
test/aottest/exceptionhandler/BUILD.gn
Normal file
18
test/aottest/exceptionhandler/BUILD.gn
Normal file
@ -0,0 +1,18 @@
|
||||
# Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import("//ark/js_runtime/test/test_helper.gni")
|
||||
|
||||
host_aot_test_action("exceptionhandler") {
|
||||
deps = []
|
||||
}
|
26
test/aottest/exceptionhandler/exceptionhandler.ts
Normal file
26
test/aottest/exceptionhandler/exceptionhandler.ts
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
declare function print(str:string):string;
|
||||
|
||||
try {
|
||||
function foo() {
|
||||
JSON.parse("[1, 2");
|
||||
}
|
||||
foo();
|
||||
} catch(e) {
|
||||
print(e);
|
||||
}
|
||||
|
16
test/aottest/exceptionhandler/expect_output.txt
Normal file
16
test/aottest/exceptionhandler/expect_output.txt
Normal file
@ -0,0 +1,16 @@
|
||||
# Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
SyntaxError: Unexpected Array in JSON
|
||||
Exception at function foo: 9
|
||||
Exception at function func_main_0: 11
|
Loading…
x
Reference in New Issue
Block a user