Implement __llvm_deoptimize to void relocate deopt hander

1.implement __llvm_deoptimize in Aot module, __llvm_deoptimize funciton is to call runtime function
2.add asm bridge frame to avoid unnecessary fpdelta calculation

Issue:https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I6NSFQ?from=project-issue

Signed-off-by: zhangyukun8 <zhangyukun8@huawei.com>
Change-Id: Ibb559ae877633c63fd8cc7efee5770ba88597f9c
This commit is contained in:
zhangyukun8 2023-03-17 15:02:11 +08:00
parent 26bdac03bf
commit ff796ce366
19 changed files with 217 additions and 346 deletions

View File

@ -525,7 +525,6 @@ ecma_source = [
"ecmascript/date_parse.cpp",
"ecmascript/deoptimizer/calleeReg.cpp",
"ecmascript/deoptimizer/deoptimizer.cpp",
"ecmascript/deoptimizer/relocator.cpp",
"ecmascript/dfx/stackinfo/js_stackinfo.cpp",
"ecmascript/dfx/vmstat/caller_stat.cpp",
"ecmascript/dfx/vmstat/opt_code_profiler.cpp",

View File

@ -19,7 +19,6 @@
#include "ecmascript/compiler/common_stubs.h"
#include "ecmascript/compiler/compiler_log.h"
#include "ecmascript/deoptimizer/deoptimizer.h"
#include "ecmascript/deoptimizer/relocator.h"
#include "ecmascript/ecma_vm.h"
#include "ecmascript/message_string.h"
#include "ecmascript/jspandafile/constpool_value.h"
@ -277,41 +276,6 @@ void AnFileInfo::Save(const std::string &filename, kungfu::Triple triple)
file.close();
}
void AnFileInfo::RewriteRelcateDeoptHandler([[maybe_unused]] EcmaVM *vm)
{
#if !WIN_OR_MAC_OR_IOS_PLATFORM
JSThread *thread = vm->GetJSThread();
uintptr_t patchAddr = thread->GetRTInterface(RTSTUB_ID(DeoptHandlerAsm));
RewriteRelcateTextSection(LLVM_DEOPT_RELOCATE_SYMBOL, patchAddr);
#endif
}
void AnFileInfo::RewriteRelcateTextSection([[maybe_unused]] const char* symbol,
[[maybe_unused]] uintptr_t patchAddr)
{
#if !WIN_OR_MAC_OR_IOS_PLATFORM
for (auto &des: des_) {
uint32_t relaTextSize = des.GetSecSize(ElfSecName::RELATEXT);
if (relaTextSize != 0) {
uint64_t relatextAddr = des.GetSecAddr(ElfSecName::RELATEXT);
uint64_t textAddr = des.GetSecAddr(ElfSecName::TEXT);
uint64_t symTabAddr = des.GetSecAddr(ElfSecName::SYMTAB);
uint32_t symTabSize = des.GetSecSize(ElfSecName::SYMTAB);
uint32_t strTabSize = des.GetSecSize(ElfSecName::STRTAB);
uint64_t strTabAddr = des.GetSecAddr(ElfSecName::STRTAB);
RelocateTextInfo relaText = {textAddr, relatextAddr, relaTextSize};
SymAndStrTabInfo symAndStrTabInfo = {symTabAddr, symTabSize, strTabAddr, strTabSize};
Relocator relocate(relaText, symAndStrTabInfo);
#ifndef NDEBUG
relocate.DumpRelocateText();
#endif
relocate.RelocateBySymbol(symbol, patchAddr);
}
}
#endif
}
bool AnFileInfo::Load(const std::string &filename)
{
std::string realPath;
@ -432,7 +396,7 @@ void AOTFileManager::LoadStubFile(const std::string &fileName)
void AOTFileManager::LoadAnFile(const std::string &fileName)
{
AnFileDataManager *anFileDataManager = AnFileDataManager::GetInstance();
if (!anFileDataManager->SafeLoad(fileName, AnFileDataManager::Type::AOT, vm_)) {
if (!anFileDataManager->SafeLoad(fileName, AnFileDataManager::Type::AOT)) {
return;
}
}
@ -867,7 +831,7 @@ void AnFileDataManager::SafeDestoryAllData()
loadedAn_.clear();
}
bool AnFileDataManager::SafeLoad(const std::string &fileName, Type type, EcmaVM* vm)
bool AnFileDataManager::SafeLoad(const std::string &fileName, Type type)
{
os::memory::WriteLockHolder lock(lock_);
if (type == Type::STUB) {
@ -880,7 +844,7 @@ bool AnFileDataManager::SafeLoad(const std::string &fileName, Type type, EcmaVM*
if (aotFileInfo != nullptr) {
return true;
}
return UnsafeLoadFromAOT(fileName, vm);
return UnsafeLoadFromAOT(fileName);
}
}
@ -915,7 +879,7 @@ void AnFileDataManager::Dump() const
}
}
bool AnFileDataManager::UnsafeLoadFromAOT(const std::string &fileName, EcmaVM *vm)
bool AnFileDataManager::UnsafeLoadFromAOT(const std::string &fileName)
{
// note: This method is not thread-safe
// need to ensure that the instance of AnFileDataManager has been locked before use
@ -923,7 +887,6 @@ bool AnFileDataManager::UnsafeLoadFromAOT(const std::string &fileName, EcmaVM *v
if (!info->Load(fileName)) {
return false;
}
info->RewriteRelcateDeoptHandler(vm);
std::string anBasename = JSFilePath::GetBaseName(fileName);
anFileNameToIndexMap_.insert({anBasename, loadedAn_.size()});
loadedAn_.emplace_back(info);

View File

@ -378,8 +378,6 @@ public:
void Dump() const;
void RewriteRelcateDeoptHandler(EcmaVM *vm);
private:
bool Load(const std::string &filename);
void RewriteRelcateTextSection(const char* symbol, uintptr_t patchAddr);
@ -473,7 +471,7 @@ public:
static AnFileDataManager *GetInstance();
~AnFileDataManager();
bool SafeLoad(const std::string &fileName, Type type, EcmaVM *vm = nullptr);
bool SafeLoad(const std::string &fileName, Type type);
uint32_t SafeGetFileInfoIndex(const std::string &fileName);
std::shared_ptr<AnFileInfo> SafeGetAnFileInfo(uint32_t index);
std::shared_ptr<StubFileInfo> SafeGetStubFileInfo();
@ -509,7 +507,7 @@ public:
public:
AnFileDataManager() = default;
std::shared_ptr<AnFileInfo> UnsafeFind(const std::string &fileName) const;
bool UnsafeLoadFromAOT(const std::string &fileName, EcmaVM *vm);
bool UnsafeLoadFromAOT(const std::string &fileName);
bool UnsafeLoadFromStub();
os::memory::RWLock lock_;
@ -562,12 +560,6 @@ public:
void DumpAOTInfo() const DUMP_API_ATTR;
private:
void RewriteRelcateDeoptHandler(EcmaVM *vm, AnFileInfo AOTFileInfo)
{
AOTFileInfo.RewriteRelcateDeoptHandler(vm);
}
void PrintAOTEntry(const JSPandaFile *file, const Method *method, uintptr_t entry);
void InitializeStubEntries(const std::vector<AnFileInfo::FuncEntryDes>& stubs);
void AdjustBCStubAndDebuggerStubEntries(JSThread *thread, const std::vector<AOTFileInfo::FuncEntryDes> &stubs,

View File

@ -1702,11 +1702,12 @@ DEF_CALL_SIGNATURE(CreateArrayFromList)
DEF_CALL_SIGNATURE(DeoptHandlerAsm)
{
// 1 : 1 input parameters
CallSignature deoptHandlerAsm("DeoptHandlerAsm", 0, 1,
CallSignature deoptHandlerAsm("DeoptHandlerAsm", 0, 2,
ArgumentsOrder::DEFAULT_ORDER, VariableType::JS_ANY());
*callSign = deoptHandlerAsm;
std::array<VariableType, 1> params = { // 1 : 1 input parameters
std::array<VariableType, 2> params = { // 2 : 2 input parameters
VariableType::NATIVE_POINTER(), // glue
VariableType::NATIVE_POINTER(), // deoptType
};
callSign->SetVariadicArgs(false);
callSign->SetParameters(params.data());

View File

@ -310,7 +310,8 @@ GateRef CircuitBuilder::TypedCallOperator(GateRef hirGate, MachineType type, con
{
ASSERT(acc_.GetOpCode(hirGate) == OpCode::JS_BYTECODE);
auto numValueIn = args.size() - 2; // 2: state & depend
uint64_t pcOffset = acc_.GetPcOffset(hirGate);
uint64_t pcOffset = acc_.TryGetPcOffset(hirGate);
ASSERT(pcOffset != 0);
return GetCircuit()->NewGate(circuit_->TypedCall(numValueIn, pcOffset), type, args, GateType::AnyType());
}
@ -556,7 +557,7 @@ 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()) {
GateRef pcOffset = Int64(acc_.GetPcOffset(hirGate));
GateRef pcOffset = Int64(acc_.TryGetPcOffset(hirGate));
inputs.emplace_back(pcOffset);
numValuesIn += 1;
}
@ -680,7 +681,8 @@ GateRef CircuitBuilder::Construct(GateRef hirGate, std::vector<GateRef> args)
auto currentControl = currentLabel->GetControl();
auto currentDepend = currentLabel->GetDepend();
uint64_t bitfield = args.size();
uint64_t pcOffset = acc_.GetPcOffset(hirGate);
uint64_t pcOffset = acc_.TryGetPcOffset(hirGate);
ASSERT(pcOffset != 0);
args.insert(args.begin(), currentDepend);
args.insert(args.begin(), currentControl);
auto callGate = GetCircuit()->NewGate(circuit_->Construct(bitfield, pcOffset), MachineType::I64,
@ -697,7 +699,8 @@ GateRef CircuitBuilder::TypedAotCall(GateRef hirGate, std::vector<GateRef> args)
auto currentControl = currentLabel->GetControl();
auto currentDepend = currentLabel->GetDepend();
uint64_t bitfield = args.size();
uint64_t pcOffset = acc_.GetPcOffset(hirGate);
uint64_t pcOffset = acc_.TryGetPcOffset(hirGate);
ASSERT(pcOffset != 0);
args.insert(args.begin(), currentDepend);
args.insert(args.begin(), currentControl);
auto callGate = GetCircuit()->NewGate(circuit_->TypedAotCall(bitfield, pcOffset), MachineType::I64,
@ -710,7 +713,8 @@ GateRef CircuitBuilder::TypedAotCall(GateRef hirGate, std::vector<GateRef> args)
GateRef CircuitBuilder::CallGetter(GateRef hirGate, GateRef receiver, GateRef propertyLookupResult)
{
ASSERT(acc_.GetOpCode(hirGate) == OpCode::JS_BYTECODE);
uint64_t pcOffset = acc_.GetPcOffset(hirGate);
uint64_t pcOffset = acc_.TryGetPcOffset(hirGate);
ASSERT(pcOffset != 0);
auto currentLabel = env_->GetCurrentLabel();
auto currentControl = currentLabel->GetControl();
@ -726,7 +730,8 @@ GateRef CircuitBuilder::CallGetter(GateRef hirGate, GateRef receiver, GateRef pr
GateRef CircuitBuilder::CallSetter(GateRef hirGate, GateRef receiver, GateRef propertyLookupResult, GateRef value)
{
ASSERT(acc_.GetOpCode(hirGate) == OpCode::JS_BYTECODE);
uint64_t pcOffset = acc_.GetPcOffset(hirGate);
uint64_t pcOffset = acc_.TryGetPcOffset(hirGate);
ASSERT(pcOffset != 0);
auto currentLabel = env_->GetCurrentLabel();
auto currentControl = currentLabel->GetControl();

View File

@ -176,7 +176,7 @@ const ChunkVector<char>& GateAccessor::GetConstantString(GateRef gate) const
return gatePtr->GetStringMetaData()->GetString();
}
uint32_t GateAccessor::GetPcOffset(GateRef gate) const
uint32_t GateAccessor::TryGetPcOffset(GateRef gate) const
{
Gate *gatePtr = circuit_->LoadGatePtr(gate);
OpCode op = GetOpCode(gate);

View File

@ -380,7 +380,7 @@ public:
TypedUnaryAccessor GetTypedUnOp(GateRef gate) const;
uint64_t GetConstantValue(GateRef gate) const;
const ChunkVector<char>& GetConstantString(GateRef gate) const;
uint32_t GetPcOffset(GateRef gate) const;
uint32_t TryGetPcOffset(GateRef gate) const;
EcmaOpcode GetByteCodeOpcode(GateRef gate) const;
void Print(GateRef gate) const;
void ShortPrint(GateRef gate) const;

View File

@ -332,7 +332,7 @@ void LLVMIRBuilder::GenPrologue()
reservedSlotsSize = OptimizedFrame::ComputeReservedSize(slotSize_);
LLVMAddTargetDependentFunctionAttr(function_, "frame-reserved-slots",
std::to_string(reservedSlotsSize).c_str());
SaveFrameTypeOnFrame(frameType);
SaveFrameTypeOnFrame(frameType, builder_);
} else if (frameType == FrameType::OPTIMIZED_JS_FUNCTION_FRAME) {
reservedSlotsSize = OptimizedJSFunctionFrame::ComputeReservedJSFuncOffset(slotSize_);
LLVMAddTargetDependentFunctionAttr(function_, "frame-reserved-slots",
@ -344,7 +344,7 @@ void LLVMIRBuilder::GenPrologue()
LLVMValueRef value = LLVMGetParam(function_, argth);
if (argth == static_cast<int>(CommonArgIdx::FUNC)) {
SaveJSFuncOnOptJSFuncFrame(value);
SaveFrameTypeOnFrame(frameType);
SaveFrameTypeOnFrame(frameType, builder_);
}
}
} else {
@ -353,15 +353,15 @@ void LLVMIRBuilder::GenPrologue()
}
}
void LLVMIRBuilder::SaveFrameTypeOnFrame(FrameType frameType)
void LLVMIRBuilder::SaveFrameTypeOnFrame(FrameType frameType, LLVMBuilderRef builder)
{
LLVMValueRef llvmFpAddr = CallingFp(module_, builder_, false);
LLVMValueRef llvmFpAddr = CallingFp(module_, builder, false);
LLVMValueRef frameAddr = LLVMBuildPtrToInt(builder_, llvmFpAddr, slotType_, "cast_int_t");
LLVMValueRef frameTypeSlotAddr = LLVMBuildSub(builder_, frameAddr, LLVMConstInt(slotType_, slotSize_, false), "");
LLVMValueRef addr = LLVMBuildIntToPtr(builder_, frameTypeSlotAddr, LLVMPointerType(slotType_, 0), "frameType.Addr");
LLVMValueRef frameAddr = LLVMBuildPtrToInt(builder, llvmFpAddr, slotType_, "cast_int_t");
LLVMValueRef frameTypeSlotAddr = LLVMBuildSub(builder, frameAddr, LLVMConstInt(slotType_, slotSize_, false), "");
LLVMValueRef addr = LLVMBuildIntToPtr(builder, frameTypeSlotAddr, LLVMPointerType(slotType_, 0), "frameType.Addr");
LLVMValueRef llvmFrameType = LLVMConstInt(slotType_, static_cast<uintptr_t>(frameType), 0);
LLVMBuildStore(builder_, llvmFrameType, addr);
LLVMBuildStore(builder, llvmFrameType, addr);
}
LLVMValueRef LLVMIRBuilder::CallingFp(LLVMModuleRef &module, LLVMBuilderRef &builder, bool isCaller)
@ -1969,6 +1969,44 @@ LLVMTypeRef LLVMIRBuilder::GetExperimentalDeoptTy()
return fnTy;
}
LLVMValueRef LLVMModule::GetDeoptFunction()
{
auto fn = LLVMGetNamedFunction(module_, Deoptimizier::GetLLVMDeoptRelocateSymbol());
return fn;
}
void LLVMIRBuilder::GenDeoptEntry(LLVMModuleRef &module)
{
std::vector<LLVMTypeRef> paramTys = {LLVMInt64Type(), LLVMInt64Type()}; // glue type
auto funcType = LLVMFunctionType(LLVMInt64Type(), paramTys.data(), paramTys.size(), 0);
auto function = LLVMAddFunction(module, Deoptimizier::GetLLVMDeoptRelocateSymbol(), funcType);
LLVMSetFunctionCallConv(function, LLVMCCallConv);
llvmModule_->SetFunction(LLVMModule::kDeoptEntryOffset, function);
LLVMBasicBlockRef entry = LLVMAppendBasicBlock(function, "entry");
LLVMBuilderRef builder = LLVMCreateBuilder();
LLVMPositionBuilderAtEnd(builder, entry);
auto reservedSlotsSize = OptimizedFrame::ComputeReservedSize(slotSize_);
LLVMAddTargetDependentFunctionAttr(function, "frame-reserved-slots", std::to_string(reservedSlotsSize).c_str());
SaveFrameTypeOnFrame(FrameType::OPTIMIZED_FRAME, builder);
LLVMValueRef glue = LLVMGetParam(function, 0);
LLVMValueRef check = LLVMGetParam(function, 1);
StubIdType stubId = RTSTUB_ID(DeoptHandlerAsm);
int stubIndex = static_cast<int>(std::get<RuntimeStubCSigns::ID>(stubId));
LLVMValueRef rtoffset = LLVMBuildAdd(builder, glue, GetRTStubOffset(glue, stubIndex), "");
LLVMValueRef patchAddr = LLVMBuildIntToPtr(builder, rtoffset, LLVMPointerType(LLVMInt64Type(), 0), "");
LLVMValueRef llvmAddr = LLVMBuildLoad(builder, patchAddr, "");
LLVMTypeRef rtfuncTypePtr = LLVMPointerType(funcType, 0);
LLVMValueRef callee = LLVMBuildIntToPtr(builder, llvmAddr, rtfuncTypePtr, "");
std::vector<LLVMValueRef> params = {glue, check};
LLVMValueRef runtimeCall = LLVMBuildCall2(builder, funcType, callee, params.data(), params.size(), "");
LLVMBuildRet(builder, runtimeCall);
LLVMPositionBuilderAtEnd(builder, entry);
}
LLVMValueRef LLVMIRBuilder::GetExperimentalDeopt(LLVMModuleRef &module)
{
/* 0:calling 1:its caller */
@ -1976,6 +2014,7 @@ LLVMValueRef LLVMIRBuilder::GetExperimentalDeopt(LLVMModuleRef &module)
if (!fn) {
auto fnTy = GetExperimentalDeoptTy();
fn = LLVMAddFunction(module, "llvm.experimental.deoptimize.p1i64", fnTy);
GenDeoptEntry(module);
}
return fn;
}
@ -2151,6 +2190,7 @@ LLVMValueRef LLVMModule::AddFunc(const panda::ecmascript::MethodLiteral *methodL
name += std::string("@") + std::to_string(offsetInPandaFile) + std::string("@") + fileName;
auto function = LLVMAddFunction(module_, name.c_str(), funcType);
ASSERT(offsetInPandaFile != LLVMModule::kDeoptEntryOffset);
SetFunction(offsetInPandaFile, function);
return function;
}

View File

@ -169,6 +169,9 @@ public:
{
return callSigns_;
}
LLVMValueRef GetDeoptFunction();
static constexpr int kDeoptEntryOffset = 0;
private:
LLVMValueRef AddAndGetFunc(const CallSignature *stubDescriptor);
void InitialLLVMFuncTypeAndFuncByModuleCSigns();
@ -336,10 +339,11 @@ private:
CallExceptionKind kind);
void SaveLexicalEnvOnOptJSFuncFrame(LLVMValueRef value);
void SaveJSFuncOnOptJSFuncFrame(LLVMValueRef value);
void SaveFrameTypeOnFrame(FrameType frameType);
void SaveFrameTypeOnFrame(FrameType frameType, LLVMBuilderRef builder);
void UpdateLeaveFrame(LLVMValueRef glue);
LLVMTypeRef GetExperimentalDeoptTy();
LLVMValueRef GetExperimentalDeopt(LLVMModuleRef &module);
void GenDeoptEntry(LLVMModuleRef &module);
const CompilationConfig *compCfg_ {nullptr};
const std::vector<std::vector<GateRef>> *scheduledGates_ {nullptr};
const Circuit *circuit_ {nullptr};

View File

@ -116,7 +116,7 @@ private:
static void IncreaseStackForArguments(ExtendedAssembler *assembler, Register argC, Register fp);
static void PushOptimizedArgsConfigFrame(ExtendedAssembler *assembler);
static void PopOptimizedArgsConfigFrame(ExtendedAssembler *assembler);
static void PushOptimizedFrame(ExtendedAssembler *assembler);
static void PushAsmBridgeFrame(ExtendedAssembler *assembler);
static void PopOptimizedFrame(ExtendedAssembler *assembler);
static void JSCallInternal(ExtendedAssembler *assembler, Register jsfunc, bool isNew = false);
static void ConstructorJSCallInternal(ExtendedAssembler *assembler, Register jsfunc);

View File

@ -450,7 +450,7 @@ void OptimizedCall::JSCallInternal(ExtendedAssembler *assembler, Register jsfunc
__ Ldp(Register(X6), Register(X7), MemoryOperand(sp, QUINTUPLE_SLOT_SIZE)); // get arg0 arg1
__ Cmp(Register(X5), Immediate(3)); // 3: callarg3
__ B(Condition::NE, &lTailCall);
PushOptimizedFrame(assembler);
PushAsmBridgeFrame(assembler);
{
// push arg3 and call
TempRegister2Scope scope2(assembler);
@ -931,14 +931,14 @@ void OptimizedCall::PopOptimizedArgsConfigFrame(ExtendedAssembler *assembler)
__ RestoreFpAndLr();
}
void OptimizedCall::PushOptimizedFrame(ExtendedAssembler *assembler)
void OptimizedCall::PushAsmBridgeFrame(ExtendedAssembler *assembler)
{
Register sp(SP);
TempRegister2Scope temp2Scope(assembler);
Register frameType = __ TempRegister2();
__ PushFpAndLr();
// construct frame
__ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::OPTIMIZED_FRAME)));
__ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::ASM_BRIDGE_FRAME)));
// 2 : 2 means pairs. X19 means calleesave and 16bytes align
__ Stp(Register(X19), frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
__ Add(Register(FP), sp, Immediate(FRAME_SLOT_SIZE));
@ -1190,7 +1190,7 @@ void OptimizedCall::DeoptHandlerAsm(ExtendedAssembler *assembler)
Register frameType(X2);
Register glueReg(X0);
__ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::OPTIMIZED_FRAME)));
__ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::ASM_BRIDGE_FRAME)));
__ Stp(glueReg, frameType, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
__ Add(fp, sp, Immediate(DOUBLE_SLOT_SIZE));
__ CalleeSave();

View File

@ -693,7 +693,7 @@ void OptimizedCall::GenJSCall(ExtendedAssembler *assembler, bool isNew)
__ Movq(rsp, argV);
__ Addq(SEXTUPLE_SLOT_SIZE, argV);
__ Pushq(rbp);
__ Pushq(static_cast<int32_t>(FrameType::OPTIMIZED_FRAME));
__ Pushq(static_cast<int32_t>(FrameType::ASM_BRIDGE_FRAME));
__ Leaq(Operand(rsp, FRAME_SLOT_SIZE), rbp);
if (!isNew) {
@ -1451,7 +1451,7 @@ void OptimizedCall::DeoptHandlerAsm(ExtendedAssembler *assembler)
Register glueReg = rdi;
__ Pushq(rbp);
__ Pushq(static_cast<int32_t>(FrameType::OPTIMIZED_FRAME));
__ Pushq(static_cast<int32_t>(FrameType::ASM_BRIDGE_FRAME));
__ Leaq(Operand(rsp, FRAME_SLOT_SIZE), rbp);
__ Push(glueReg);
__ PushCppCalleeSaveRegisters();

View File

@ -109,10 +109,57 @@ void Deoptimizier::CollectVregs(const std::vector<kungfu::ARKDeopt>& deoptBundle
}
}
// when AOT trigger deopt, frame layout as the following
// * OptimizedJSFunctionFrame layout description as the following:
// +--------------------------+ ---------------
// | ...... | ^
// | ...... | callerFunction
// | ...... | |
// |--------------------------| |
// | args | v
// +--------------------------+ ---------------
// | returnAddr | ^
// |--------------------------| |
// | callsiteFp | |
// |--------------------------| OptimizedJSFunction FrameType:OPTIMIZED_JS_FUNCTION_FRAME
// | frameType | |
// |--------------------------| |
// | call-target | |
// |--------------------------| |
// | lexEnv | |
// |--------------------------| |
// | ........... | v
// +--------------------------+ ---------------
// | returnAddr | ^
// |--------------------------| |
// | callsiteFp | |
// |--------------------------| __llvm_deoptimize FrameType:OPTIMIZED_FRAME
// | frameType | |
// |--------------------------| |
// | No CalleeSave | |
// | Registers | v
// +--------------------------+ ---------------
// | returnAddr | ^
// |--------------------------| |
// | callsiteFp | |
// |--------------------------| DeoptHandlerAsm FrameType:ASM_BRIDGE_FRAME
// | frameType | |
// |--------------------------| |
// | glue | |
// |--------------------------| |
// | CalleeSave Registers | v
// +--------------------------+ ---------------
// | ......... | ^
// | ......... | CallRuntime FrameType:LEAVE_FRAME
// | ......... | |
// | ......... | v
// |--------------------------| ---------------
void Deoptimizier::CollectDeoptBundleVec(std::vector<kungfu::ARKDeopt>& deoptBundle)
{
JSTaggedType *lastLeave = const_cast<JSTaggedType *>(thread_->GetLastLeaveFrame());
FrameIterator it(lastLeave, thread_);
// note: last deopt bridge frame is generated by DeoptHandlerAsm, callee Regs is grow from this frame
for (; !it.Done() && deoptBundle.empty(); it.Advance<GCVisitedFlag::VISITED>()) {
FrameType type = it.GetFrameType();
switch (type) {
@ -132,12 +179,14 @@ void Deoptimizier::CollectDeoptBundleVec(std::vector<kungfu::ARKDeopt>& deoptBun
stackContext_.callerFp_ = reinterpret_cast<uintptr_t>(frame->GetPrevFrameFp());
break;
}
case FrameType::OPTIMIZED_FRAME: {
case FrameType::ASM_BRIDGE_FRAME: {
auto sp = reinterpret_cast<uintptr_t*>(it.GetSp());
sp -= 2; // 2: skip type & glue
static constexpr size_t TYPE_GLUE_SLOT = 2; // 2: skip type & glue
sp -= TYPE_GLUE_SLOT;
calleeRegAddr_ = sp - numCalleeRegs_;
break;
}
case FrameType::OPTIMIZED_FRAME:
case FrameType::LEAVE_FRAME:
break;
default: {

View File

@ -23,8 +23,6 @@
#include "ecmascript/js_tagged_value.h"
#include "ecmascript/stackmap/llvm_stackmap_type.h"
// todo:place to Deoptimizier class
#define LLVM_DEOPT_RELOCATE_SYMBOL "__llvm_deoptimize"
namespace panda::ecmascript {
class JSThread;
enum class SpecVregIndex: int {
@ -106,6 +104,11 @@ public:
return thread_;
}
static const char *GetLLVMDeoptRelocateSymbol()
{
return "__llvm_deoptimize";
}
private:
size_t GetFrameIndex(kungfu::CommonArgIdx index)
{

View File

@ -1,175 +0,0 @@
/*
* 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.
*/
#include "ecmascript/deoptimizer/relocator.h"
#include <climits>
#include <iomanip>
#include "ecmascript/compiler/assembler/aarch64/assembler_aarch64_constants.h"
#include "ecmascript/message_string.h"
#if !WIN_OR_MAC_OR_IOS_PLATFORM
namespace panda::ecmascript {
std::optional<Elf64_Word> Relocator::GetSymbol(const char* symbol) const
{
ASSERT(symAndStrTabInfo_.symSize_ % sizeof(Elf64_Sym) == 0);
int n = symAndStrTabInfo_.symSize_ / sizeof(Elf64_Sym);
ASSERT(symAndStrTabInfo_.symAddr_ > 0 && symAndStrTabInfo_.symSize_ > 0);
Elf64_Sym *ptr = reinterpret_cast<Elf64_Sym *>(symAndStrTabInfo_.symAddr_);
for (int i = 0; i < n; i++) {
Elf64_Sym *cur = ptr + i;
const char *name = reinterpret_cast<char *>(symAndStrTabInfo_.strAddr_) + cur->st_name;
if (std::strcmp(symbol, name) == 0) {
return static_cast<Elf64_Word>(i);
}
}
return std::nullopt;
}
bool Relocator::Relocate(Elf64_Rela *sec, uintptr_t symbolAddr, uintptr_t patchAddr)
{
bool ret = false;
ASSERT(reinterpret_cast<intptr_t>(sec) > 0);
Elf64_Word type = GetType(sec);
Elf64_Sxword addend = sec->r_addend;
switch (type) {
case R_AARCH64_CALL26: {
/* S + A - P
S: (when used on its own) is the address of the symbol
A: is the addend for the relocation
P: is the address of the place beging relocated(derived from r_offset)
*/
intptr_t imm = patchAddr + addend - symbolAddr;
ASSERT(-(1 << 27) <= imm && imm < (1 << 27)); // 27: "Check that -2^27 <= result < 2^27".
imm = (imm & 0x0FFFFFFC) >> 2; // 0x0FFFFFFC: get immediate file to bits [27:2]
*(reinterpret_cast<uint32_t *>(symbolAddr)) = imm | panda::ecmascript::aarch64::CallOpCode::BL;
break;
}
case R_X86_64_PLT32: {
/* S + A - P
S: (when used on its own) is the address of the symbol
A: is the addend for the relocation
P: is the address of the place beging relocated(derived from r_offset)
*/
intptr_t v = patchAddr + addend - symbolAddr;
ASSERT((v >= INT_MIN) && (v <= INT_MAX));
*(reinterpret_cast<uint32_t *>(symbolAddr)) = v;
ret = true;
break;
}
default: {
LOG_COMPILER(FATAL) << " unsupported type:" << type;
return false;
}
}
return ret;
}
bool Relocator::HasSymStrTable() const
{
return (symAndStrTabInfo_.symAddr_ >= 0) && (symAndStrTabInfo_.symSize_ >= 0) &&
(symAndStrTabInfo_.strAddr_ >= 0) && (symAndStrTabInfo_.strSize_ >= 0);
}
bool Relocator::HasRelocateText() const
{
return (relocateTextInfo_.relaTextAddr_ > 0) && (relocateTextInfo_.relaTextSize_ > 0);
}
bool Relocator::RelocateBySymbolId(Elf64_Word symbolId, uintptr_t patchAddr)
{
bool ret = false;
ASSERT(relocateTextInfo_.relaTextSize_ % sizeof(Elf64_Rela) == 0);
ASSERT(relocateTextInfo_.relaTextAddr_ > 0 && relocateTextInfo_.relaTextSize_ > 0);
size_t n = relocateTextInfo_.relaTextSize_ / sizeof(Elf64_Rela);
Elf64_Rela *ptr = reinterpret_cast<Elf64_Rela *>(relocateTextInfo_.relaTextAddr_);
for (size_t i = 0; i < n; i++) {
Elf64_Rela *cur = ptr + i;
Elf64_Word id = GetSymbol(cur);
intptr_t symbolAddr = relocateTextInfo_.textAddr_ + static_cast<uintptr_t>(cur->r_offset);
if (id == symbolId) {
ret = Relocate(cur, symbolAddr, patchAddr);
}
}
return ret;
}
bool Relocator::RelocateBySymbol(const char* symbol, uintptr_t patchAddr)
{
if (!HasSymStrTable()) {
return false;
}
auto symId = GetSymbol(symbol);
if (!symId.has_value()) {
LOG_COMPILER(DEBUG) << " don't find symbol:" << symbol << " in symbol table.";
return false;
}
bool ret = RelocateBySymbolId(symId.value(), patchAddr);
return ret;
}
void Relocator::DumpRelocateText()
{
if (!HasRelocateText()) {
LOG_COMPILER(ERROR) << " input valid relocateText addr & size:";
return;
}
ASSERT(relocateTextInfo_.relaTextSize_ % sizeof(Elf64_Rela) == 0);
ASSERT(relocateTextInfo_.relaTextAddr_ > 0 && relocateTextInfo_.relaTextSize_ > 0);
size_t n = relocateTextInfo_.relaTextSize_ / sizeof(Elf64_Rela);
Elf64_Rela *ptr = reinterpret_cast<Elf64_Rela *>(relocateTextInfo_.relaTextAddr_);
static constexpr int leftAdjustment = 12;
LOG_COMPILER(DEBUG) << std::left << std::setw(leftAdjustment) << "symbolId "
<< std::left << std::setw(leftAdjustment) << "Info(0x): "
<< std::left << std::setw(leftAdjustment) << "Type: "
<< std::left << std::setw(leftAdjustment) << "r_offset(0x): "
<< std::left << std::setw(leftAdjustment) << "addend: ";
for (size_t i = 0; i < n; i++) {
Elf64_Rela *cur = ptr + i;
Elf64_Word id = GetSymbol(cur);
Elf64_Word type = GetType(cur);
Elf64_Sxword addend = ptr->r_addend;
LOG_COMPILER(DEBUG) << std::left << std::setw(leftAdjustment) << id
<< std::left << std::setw(leftAdjustment) << std::hex << cur->r_info
<< std::left << std::setw(leftAdjustment) << std::dec << type
<< std::left << std::setw(leftAdjustment) << std::hex << static_cast<intptr_t>(cur->r_offset)
<< std::left << std::setw(leftAdjustment) << std::dec << static_cast<intptr_t>(addend);
}
if (!HasSymStrTable()) {
return;
}
ASSERT(symAndStrTabInfo_.symSize_ % sizeof(Elf64_Sym) == 0);
n = symAndStrTabInfo_.symSize_ / sizeof(Elf64_Sym);
ASSERT(symAndStrTabInfo_.symAddr_ > 0 && symAndStrTabInfo_.symSize_ > 0);
Elf64_Sym *symPtr = reinterpret_cast<Elf64_Sym *>(symAndStrTabInfo_.symAddr_);
LOG_COMPILER(DEBUG) << std::left << std::setw(leftAdjustment) << "symbolId "
<< std::left << std::setw(leftAdjustment) << "binding: "
<< std::left << std::setw(leftAdjustment) << "Type: "
<< std::left << std::setw(leftAdjustment) << "st_name: "
<< std::left << std::setw(leftAdjustment) << "name: ";
for (size_t i = 0; i < n; i++) {
Elf64_Sym *cur = symPtr + i;
const char *name = reinterpret_cast<char *>(symAndStrTabInfo_.strAddr_) + cur->st_name;
unsigned char binding = GetBinding(cur);
unsigned char type = GetType(cur);
LOG_COMPILER(DEBUG) << std::left << std::setw(leftAdjustment) << i
<< std::left << std::setw(leftAdjustment) << std::dec << static_cast<int>(binding)
<< std::left << std::setw(leftAdjustment) << std::dec << static_cast<int>(type)
<< std::left << std::setw(leftAdjustment) << std::dec << cur->st_name
<< std::left << std::setw(leftAdjustment) << name;
}
}
} // namespace panda::ecmascript
#endif

View File

@ -1,84 +0,0 @@
/*
* 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.
*/
#ifndef ECMASCRIPT_DEOPTIMIZER_RELCATOR_H
#define ECMASCRIPT_DEOPTIMIZER_RELCATOR_H
#include "ecmascript/common.h"
#if !WIN_OR_MAC_OR_IOS_PLATFORM
#include <elf.h>
#include <optional>
#include "ecmascript/ecma_macros.h"
namespace panda::ecmascript {
struct RelocateTextInfo {
uintptr_t textAddr_ {0};
uintptr_t relaTextAddr_ {0};
uintptr_t relaTextSize_ {0};
};
struct SymAndStrTabInfo {
uintptr_t symAddr_ {0};
uintptr_t symSize_ {0};
uintptr_t strAddr_ {0};
uintptr_t strSize_ {0};
};
class Relocator {
public:
PUBLIC_API Relocator(RelocateTextInfo relaText, SymAndStrTabInfo symAndStrTabInfo)
:relocateTextInfo_(relaText), symAndStrTabInfo_(symAndStrTabInfo) {};
PUBLIC_API bool RelocateBySymbolId(Elf64_Word symbolId, uintptr_t patchAddr);
PUBLIC_API bool RelocateBySymbol(const char* symbol, uintptr_t patchAddr);
PUBLIC_API void DumpRelocateText();
~Relocator() = default;
private:
bool HasSymStrTable() const;
bool HasRelocateText() const;
std::optional<Elf64_Word> GetSymbol(const char* symbol) const;
bool Relocate(Elf64_Rela *sec, uintptr_t symbolAddr, uintptr_t patchAddr);
Elf64_Word GetSymbol(Elf64_Rela *cur) const
{
Elf64_Word id = (cur->r_info >> 32); // 32: get high 32 bits
return id;
}
Elf64_Word GetType(Elf64_Rela *cur) const
{
return (cur->r_info & 0xffffffffL); // 0xffffffff :get lower 32 bits
}
// These accessors and mutators are identical to those defined for ELF32
// symbol table entries.
unsigned char GetBinding(Elf64_Sym *cur) const
{
return cur->st_info >> 4; // 4: offset
}
unsigned char GetType(Elf64_Sym *cur) const
{
return cur->st_info & 0x0f; // f: get lowest 4 bits
}
RelocateTextInfo relocateTextInfo_ {0};
SymAndStrTabInfo symAndStrTabInfo_ {0};
};
} // panda::ecmascript
#endif
#endif // ECMASCRIPT_DEOPTIMIZER_RELCATOR_H

View File

@ -91,6 +91,7 @@ JSTaggedValue FrameIterator::GetFunction() const
}
case FrameType::OPTIMIZED_FRAME:
case FrameType::OPTIMIZED_ENTRY_FRAME:
case FrameType::ASM_BRIDGE_FRAME:
case FrameType::LEAVE_FRAME:
case FrameType::LEAVE_FRAME_WITH_ARGV:
case FrameType::INTERPRETER_ENTRY_FRAME:
@ -139,6 +140,16 @@ void FrameIterator::Advance()
current_ = frame->GetPrevFrameFp();
break;
}
case FrameType::ASM_BRIDGE_FRAME : {
auto frame = GetFrame<AsmBridgeFrame>();
if constexpr (GCVisit == GCVisitedFlag::VISITED) {
optimizedCallSiteSp_ = GetPrevFrameCallSiteSp();
optimizedReturnAddr_ = frame->GetReturnAddr();
needCalCallSiteInfo = true;
}
current_ = frame->GetPrevFrameFp();
break;
}
case FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME: {
auto frame = GetFrame<OptimizedJSFunctionUnfoldArgVFrame>();
if constexpr (GCVisit == GCVisitedFlag::VISITED) {
@ -290,10 +301,6 @@ void FrameIterator::Advance()
std::tie(textStart, stackMapAddr_, fpDeltaPrevFrameSp_, calleeRegInfo_) = CalCallSiteInfo(optimizedReturnAddr_);
ASSERT(optimizedReturnAddr_ >= textStart);
optimizedReturnAddr_ = optimizedReturnAddr_ - textStart;
if (t == FrameType::LEAVE_FRAME && fpDeltaPrevFrameSp_ == 0) {
// it may be asm code stub's leave frame.
fpDeltaPrevFrameSp_ = 2 * sizeof(uintptr_t); // 2: skip prev and return addr
}
}
}
template void FrameIterator::Advance<GCVisitedFlag::VISITED>();
@ -336,6 +343,10 @@ uintptr_t FrameIterator::GetPrevFrameCallSiteSp() const
auto callSiteSp = reinterpret_cast<uintptr_t>(current_) + fpDeltaPrevFrameSp_;
return callSiteSp;
}
case FrameType::ASM_BRIDGE_FRAME: {
auto frame = GetFrame<AsmBridgeFrame>();
return frame->GetCallSiteSp();
}
case FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME: {
auto frame = GetFrame<OptimizedJSFunctionUnfoldArgVFrame>();
return frame->GetPrevFrameSp();
@ -712,6 +723,10 @@ bool GetTypeOffsetAndPrevOffsetFromFrameType(uintptr_t frameType, uintptr_t &typ
typeOffset = OptimizedEntryFrame::GetTypeOffset();
prevOffset = OptimizedEntryFrame::GetLeaveFrameFpOffset();
break;
case FrameType::ASM_BRIDGE_FRAME:
typeOffset = AsmBridgeFrame::GetTypeOffset();
prevOffset = AsmBridgeFrame::GetPrevOffset();
break;
case FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME:
typeOffset = OptimizedJSFunctionUnfoldArgVFrame::GetTypeOffset();
prevOffset = OptimizedJSFunctionUnfoldArgVFrame::GetPrevOffset();

View File

@ -114,6 +114,7 @@ enum class FrameType: uintptr_t {
OPTIMIZED_FRAME = 0,
OPTIMIZED_ENTRY_FRAME,
OPTIMIZED_JS_FUNCTION_FRAME,
ASM_BRIDGE_FRAME,
LEAVE_FRAME,
LEAVE_FRAME_WITH_ARGV,
BUILTIN_CALL_LEAVE_FRAME,
@ -222,6 +223,60 @@ private:
};
STATIC_ASSERT_EQ_ARCH(sizeof(OptimizedFrame), OptimizedFrame::SizeArch32, OptimizedFrame::SizeArch64);
struct AsmBridgeFrame : public base::AlignedStruct<base::AlignedPointer::Size(),
base::AlignedPointer,
base::AlignedPointer,
base::AlignedPointer> {
public:
static size_t GetTypeOffset()
{
return MEMBER_OFFSET(AsmBridgeFrame, type);
}
static size_t GetPrevOffset()
{
return MEMBER_OFFSET(AsmBridgeFrame, prevFp);
}
uintptr_t GetCallSiteSp() const
{
return ToUintPtr(this) + sizeof(AsmBridgeFrame);
}
FrameType GetType() const
{
return type;
}
private:
enum class Index : size_t {
TypeIndex = 0,
PrevFpIndex,
ReturnAddrIndex,
NumOfMembers
};
static_assert(static_cast<size_t>(Index::NumOfMembers) == NumOfTypes);
static AsmBridgeFrame* GetFrameFromSp(const JSTaggedType *sp)
{
return reinterpret_cast<AsmBridgeFrame *>(reinterpret_cast<uintptr_t>(sp) -
MEMBER_OFFSET(AsmBridgeFrame, prevFp));
}
inline JSTaggedType* GetPrevFrameFp()
{
return prevFp;
}
uintptr_t GetReturnAddr() const
{
return returnAddr;
}
alignas(EAS) FrameType type {0};
alignas(EAS) JSTaggedType *prevFp {nullptr};
alignas(EAS) uintptr_t returnAddr {0};
friend class FrameIterator;
};
STATIC_ASSERT_EQ_ARCH(sizeof(AsmBridgeFrame), AsmBridgeFrame::SizeArch32, AsmBridgeFrame::SizeArch64);
// * OptimizedUnfoldArgVFrame layout description as the following:
// sp ----> |--------------------------| ---------------
// | returnAddr | ^
@ -286,7 +341,8 @@ private:
alignas(EAS) uintptr_t returnAddr {0};
friend class FrameIterator;
};
STATIC_ASSERT_EQ_ARCH(sizeof(OptimizedFrame), OptimizedFrame::SizeArch32, OptimizedFrame::SizeArch64);
STATIC_ASSERT_EQ_ARCH(sizeof(OptimizedJSFunctionUnfoldArgVFrame),
OptimizedJSFunctionUnfoldArgVFrame::SizeArch32, OptimizedJSFunctionUnfoldArgVFrame::SizeArch64);
// * The OptimizedJSFunctionArgsConfig Frame's structure is illustrated as the following:
// +--------------------------+

View File

@ -194,6 +194,7 @@ JSTaggedValue FrameHandler::GetFunction() const
case FrameType::ASM_INTERPRETER_BRIDGE_FRAME:
case FrameType::INTERPRETER_BUILTIN_FRAME:
case FrameType::OPTIMIZED_FRAME:
case FrameType::ASM_BRIDGE_FRAME:
case FrameType::LEAVE_FRAME:
case FrameType::LEAVE_FRAME_WITH_ARGV:
case FrameType::BUILTIN_CALL_LEAVE_FRAME:
@ -301,6 +302,7 @@ ARK_INLINE uintptr_t FrameHandler::GetInterpretedFrameEnd(JSTaggedType *prevSp)
case FrameType::BUILTIN_ENTRY_FRAME:
case FrameType::BUILTIN_FRAME:
case FrameType::OPTIMIZED_FRAME:
case FrameType::ASM_BRIDGE_FRAME:
case FrameType::LEAVE_FRAME:
case FrameType::LEAVE_FRAME_WITH_ARGV:
case FrameType::BUILTIN_CALL_LEAVE_FRAME:
@ -427,6 +429,7 @@ void FrameHandler::IterateFrameChain(JSTaggedType *start, const RootVisitor &vis
case FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME:
case FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME:
case FrameType::OPTIMIZED_ENTRY_FRAME:
case FrameType::ASM_BRIDGE_FRAME:
case FrameType::ASM_INTERPRETER_ENTRY_FRAME:
case FrameType::ASM_INTERPRETER_BRIDGE_FRAME: {
break;