/* * Copyright (c) 2022-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/frames.h" #include "ecmascript/aot_file_manager.h" #include "ecmascript/ecma_vm.h" #include "ecmascript/interpreter/frame_handler.h" #include "ecmascript/js_thread.h" #include "ecmascript/platform/os.h" #include "ecmascript/stackmap/ark_stackmap_parser.h" #include "ecmascript/stackmap/llvm_stackmap_parser.h" namespace panda::ecmascript { FrameIterator::FrameIterator(JSTaggedType *sp, const JSThread *thread) : current_(sp), thread_(thread) { if (thread != nullptr) { arkStackMapParser_ = thread->GetEcmaVM()->GetAOTFileManager()->GetStackMapParser(); } } int FrameIterator::ComputeDelta() const { return fpDeltaPrevFrameSp_; } int FrameIterator::GetCallSiteDelta(uintptr_t returnAddr) const { auto callsiteInfo = CalCallSiteInfo(returnAddr); int delta = std::get<2>(callsiteInfo); // 2:delta index return delta; } Method *FrameIterator::CheckAndGetMethod() const { auto function = GetFunction(); if (function.IsJSFunctionBase() || function.IsJSProxy()) { return ECMAObject::Cast(function.GetTaggedObject())->GetCallTarget(); } return nullptr; } JSTaggedValue FrameIterator::GetFunction() const { FrameType type = GetFrameType(); switch (type) { case FrameType::OPTIMIZED_JS_FUNCTION_FRAME: { auto frame = GetFrame(); return frame->GetFunction(); } case FrameType::ASM_INTERPRETER_FRAME: case FrameType::INTERPRETER_CONSTRUCTOR_FRAME: { auto frame = GetFrame(); return frame->function; } case FrameType::INTERPRETER_FRAME: case FrameType::INTERPRETER_FAST_NEW_FRAME: { auto frame = GetFrame(); return frame->function; } case FrameType::INTERPRETER_BUILTIN_FRAME: { auto frame = GetFrame(); return frame->function; } case FrameType::BUILTIN_FRAME_WITH_ARGV: { auto *frame = BuiltinWithArgvFrame::GetFrameFromSp(GetSp()); return frame->GetFunction(); } case FrameType::BUILTIN_ENTRY_FRAME: case FrameType::BUILTIN_FRAME: { auto *frame = BuiltinFrame::GetFrameFromSp(GetSp()); return frame->GetFunction(); } default: { return JSTaggedValue::Undefined(); } } } AOTFileInfo::CallSiteInfo FrameIterator::CalCallSiteInfo(uintptr_t retAddr) const { auto loader = thread_->GetEcmaVM()->GetAOTFileManager(); return loader->CalCallSiteInfo(retAddr); } template void FrameIterator::Advance() { ASSERT(!Done()); FrameType t = GetFrameType(); [[maybe_unused]] bool needCalCallSiteInfo = false; switch (t) { case FrameType::OPTIMIZED_FRAME : { auto frame = GetFrame(); if constexpr (GCVisit == GCVisitedFlag::VISITED) { optimizedCallSiteSp_ = GetPrevFrameCallSiteSp(optimizedReturnAddr_); optimizedReturnAddr_ = frame->GetReturnAddr(); needCalCallSiteInfo = true; } current_ = frame->GetPrevFrameFp(); break; } case FrameType::OPTIMIZED_ENTRY_FRAME : { auto frame = GetFrame(); if constexpr (GCVisit == GCVisitedFlag::VISITED) { optimizedReturnAddr_ = 0; optimizedCallSiteSp_ = 0; } current_ = frame->GetPrevFrameFp(); break; } case FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME: { auto frame = GetFrame(); if constexpr (GCVisit == GCVisitedFlag::VISITED) { optimizedCallSiteSp_ = frame->GetPrevFrameSp(); optimizedReturnAddr_ = frame->GetReturnAddr(); needCalCallSiteInfo = true; } current_ = frame->GetPrevFrameFp(); break; } case FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME: { auto frame = GetFrame(); if constexpr (GCVisit == GCVisitedFlag::VISITED) { optimizedCallSiteSp_ = GetPrevFrameCallSiteSp(); optimizedReturnAddr_ = frame->GetReturnAddr(); needCalCallSiteInfo = true; } current_ = frame->GetPrevFrameFp(); break; } case FrameType::OPTIMIZED_JS_FUNCTION_FRAME: { auto frame = GetFrame(); if constexpr (GCVisit == GCVisitedFlag::VISITED) { optimizedCallSiteSp_ = GetPrevFrameCallSiteSp(optimizedReturnAddr_); optimizedReturnAddr_ = frame->GetReturnAddr(); needCalCallSiteInfo = true; } current_ = frame->GetPrevFrameFp(); break; } case FrameType::LEAVE_FRAME : { auto frame = GetFrame(); if constexpr (GCVisit == GCVisitedFlag::VISITED) { optimizedCallSiteSp_ = GetPrevFrameCallSiteSp(); optimizedReturnAddr_ = frame->GetReturnAddr(); needCalCallSiteInfo = true; } current_ = frame->GetPrevFrameFp(); break; } case FrameType::LEAVE_FRAME_WITH_ARGV : { auto frame = GetFrame(); if constexpr (GCVisit == GCVisitedFlag::VISITED) { optimizedCallSiteSp_ = GetPrevFrameCallSiteSp(); optimizedReturnAddr_ = frame->GetReturnAddr(); needCalCallSiteInfo = true; } current_ = frame->GetPrevFrameFp(); break; } case FrameType::BUILTIN_CALL_LEAVE_FRAME : { auto frame = GetFrame(); if constexpr (GCVisit == GCVisitedFlag::VISITED) { optimizedCallSiteSp_ = GetPrevFrameCallSiteSp(); optimizedReturnAddr_ = frame->GetReturnAddr(); needCalCallSiteInfo = true; } current_ = frame->GetPrevFrameFp(); break; } case FrameType::INTERPRETER_FRAME: case FrameType::INTERPRETER_FAST_NEW_FRAME : { auto frame = GetFrame(); if constexpr (GCVisit == GCVisitedFlag::VISITED) { optimizedReturnAddr_ = 0; optimizedCallSiteSp_ = 0; } current_ = frame->GetPrevFrameFp(); break; } case FrameType::INTERPRETER_BUILTIN_FRAME: { auto frame = GetFrame(); if constexpr (GCVisit == GCVisitedFlag::VISITED) { optimizedReturnAddr_ = 0; optimizedCallSiteSp_ = 0; } current_ = frame->GetPrevFrameFp(); break; } case FrameType::INTERPRETER_CONSTRUCTOR_FRAME: case FrameType::ASM_INTERPRETER_FRAME : { auto frame = GetFrame(); if constexpr (GCVisit == GCVisitedFlag::VISITED) { optimizedReturnAddr_ = 0; optimizedCallSiteSp_ = 0; } current_ = frame->GetPrevFrameFp(); break; } case FrameType::BUILTIN_FRAME: case FrameType::BUILTIN_ENTRY_FRAME : { auto frame = GetFrame(); if constexpr (GCVisit == GCVisitedFlag::VISITED) { optimizedReturnAddr_ = frame->GetReturnAddr(); optimizedCallSiteSp_ = GetPrevFrameCallSiteSp(); needCalCallSiteInfo = true; } current_ = frame->GetPrevFrameFp(); break; } case FrameType::BUILTIN_FRAME_WITH_ARGV : { auto frame = GetFrame(); if constexpr (GCVisit == GCVisitedFlag::VISITED) { optimizedReturnAddr_ = frame->GetReturnAddr(); optimizedCallSiteSp_ = GetPrevFrameCallSiteSp(); needCalCallSiteInfo = true; } current_ = frame->GetPrevFrameFp(); break; } case FrameType::INTERPRETER_ENTRY_FRAME : { auto frame = GetFrame(); if constexpr (GCVisit == GCVisitedFlag::VISITED) { optimizedReturnAddr_ = 0; optimizedCallSiteSp_ = 0; } current_ = frame->GetPrevFrameFp(); break; } case FrameType::ASM_INTERPRETER_ENTRY_FRAME : { auto frame = GetFrame(); if constexpr (GCVisit == GCVisitedFlag::VISITED) { optimizedReturnAddr_ = 0; optimizedCallSiteSp_ = 0; } current_ = frame->GetPrevFrameFp(); break; } case FrameType::ASM_INTERPRETER_BRIDGE_FRAME : { auto frame = GetFrame(); if constexpr (GCVisit == GCVisitedFlag::VISITED) { optimizedCallSiteSp_ = GetPrevFrameCallSiteSp(optimizedReturnAddr_); optimizedReturnAddr_ = frame->GetReturnAddr(); needCalCallSiteInfo = true; } current_ = frame->GetPrevFrameFp(); break; } default: { LOG_ECMA(FATAL) << "this branch is unreachable"; UNREACHABLE(); } } if constexpr (GCVisit == GCVisitedFlag::VISITED) { if (!needCalCallSiteInfo) { return; } uint64_t textStart = 0; 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(); template void FrameIterator::Advance(); uintptr_t FrameIterator::GetPrevFrameCallSiteSp([[maybe_unused]] uintptr_t curPc) const { if (Done()) { return 0; } auto type = GetFrameType(); switch (type) { case FrameType::LEAVE_FRAME: { auto frame = GetFrame(); return frame->GetCallSiteSp(); } case FrameType::LEAVE_FRAME_WITH_ARGV: { auto frame = GetFrame(); return frame->GetCallSiteSp(); } case FrameType::BUILTIN_CALL_LEAVE_FRAME: { auto frame = GetFrame(); return frame->GetCallSiteSp(); } case FrameType::BUILTIN_FRAME_WITH_ARGV: { auto frame = GetFrame(); return frame->GetCallSiteSp(); } case FrameType::BUILTIN_FRAME: { auto frame = GetFrame(); return frame->GetCallSiteSp(); } case FrameType::ASM_INTERPRETER_BRIDGE_FRAME: { auto frame = GetFrame(); return frame->GetCallSiteSp(); } case FrameType::OPTIMIZED_FRAME: case FrameType::OPTIMIZED_JS_FUNCTION_FRAME: { ASSERT(thread_ != nullptr); auto callSiteSp = reinterpret_cast(current_) + fpDeltaPrevFrameSp_; return callSiteSp; } case FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME: { auto frame = GetFrame(); return frame->GetPrevFrameSp(); } case FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME : { auto callSiteSp = OptimizedJSFunctionFrame::ComputeArgsConfigFrameSp(current_); return callSiteSp; } case FrameType::BUILTIN_ENTRY_FRAME: case FrameType::ASM_INTERPRETER_FRAME: case FrameType::INTERPRETER_CONSTRUCTOR_FRAME: case FrameType::INTERPRETER_FRAME: case FrameType::INTERPRETER_FAST_NEW_FRAME: case FrameType::OPTIMIZED_ENTRY_FRAME: case FrameType::INTERPRETER_BUILTIN_FRAME: case FrameType::INTERPRETER_ENTRY_FRAME: case FrameType::ASM_INTERPRETER_ENTRY_FRAME: { return 0; } default: { LOG_FULL(FATAL) << "frame type error!"; } } } uintptr_t FrameIterator::GetPrevFrame() const { FrameType type = GetFrameType(); uintptr_t end = 0U; switch (type) { case FrameType::INTERPRETER_FRAME: case FrameType::INTERPRETER_FAST_NEW_FRAME: { auto prevFrame = GetFrame(); end = ToUintPtr(prevFrame); break; } case FrameType::INTERPRETER_ENTRY_FRAME: { auto prevFrame = GetFrame(); end = ToUintPtr(prevFrame); break; } case FrameType::INTERPRETER_BUILTIN_FRAME: { auto prevFrame = GetFrame(); end = ToUintPtr(prevFrame); break; } default: { LOG_FULL(FATAL) << "frame type error!"; } } return end; } bool FrameIterator::IteratorStackMap(const RootVisitor &visitor, const RootBaseAndDerivedVisitor &derivedVisitor) const { ASSERT(arkStackMapParser_ != nullptr); if (!stackMapAddr_) { // enter by assembler, no stack map return true; } return arkStackMapParser_->IteratorStackMap(visitor, derivedVisitor, optimizedReturnAddr_, reinterpret_cast(current_), optimizedCallSiteSp_, stackMapAddr_); } ARK_INLINE void OptimizedFrame::GCIterate(const FrameIterator &it, [[maybe_unused]] const RootVisitor &visitor, [[maybe_unused]] const RootRangeVisitor &rangeVisitor, const RootBaseAndDerivedVisitor &derivedVisitor) const { bool ret = it.IteratorStackMap(visitor, derivedVisitor); if (!ret) { #ifndef NDEBUG LOG_ECMA(DEBUG) << " stackmap don't found returnAddr " << it.GetOptimizedReturnAddr(); #endif } } void FrameIterator::CollectBCOffsetInfo(kungfu::ConstInfo &info) const { arkStackMapParser_->GetConstInfo(optimizedReturnAddr_, info, stackMapAddr_); } void FrameIterator::CollectArkDeopt(std::vector& deopts) const { arkStackMapParser_->GetArkDeopt(optimizedReturnAddr_, stackMapAddr_, deopts); } ARK_INLINE JSTaggedType* OptimizedJSFunctionFrame::GetArgv(const FrameIterator &it) const { uintptr_t *preFrameSp = ComputePrevFrameSp(it); return GetArgv(preFrameSp); } ARK_INLINE uintptr_t* OptimizedJSFunctionFrame::ComputePrevFrameSp(const FrameIterator &it) const { const JSTaggedType *sp = it.GetSp(); int delta = it.ComputeDelta(); ASSERT((delta > 0) && (delta % sizeof(uintptr_t) == 0)); uintptr_t *preFrameSp = reinterpret_cast(const_cast(sp)) + delta / sizeof(uintptr_t); return preFrameSp; } void OptimizedJSFunctionFrame::CollectBCOffsetInfo(const FrameIterator &it, kungfu::ConstInfo &info) const { it.CollectBCOffsetInfo(info); } ARK_INLINE void OptimizedJSFunctionFrame::GCIterate(const FrameIterator &it, const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor, const RootBaseAndDerivedVisitor &derivedVisitor) const { OptimizedJSFunctionFrame *frame = OptimizedJSFunctionFrame::GetFrameFromSp(it.GetSp()); uintptr_t *jsFuncPtr = reinterpret_cast(frame); uintptr_t jsFuncSlot = ToUintPtr(jsFuncPtr); uintptr_t envslot = jsFuncSlot + sizeof(uintptr_t); visitor(Root::ROOT_FRAME, ObjectSlot(jsFuncSlot)); visitor(Root::ROOT_FRAME, ObjectSlot(envslot)); uintptr_t *preFrameSp = frame->ComputePrevFrameSp(it); auto argc = frame->GetArgc(preFrameSp); JSTaggedType *argv = frame->GetArgv(reinterpret_cast(preFrameSp)); if (argc > 0) { uintptr_t start = ToUintPtr(argv); // argv uintptr_t end = ToUintPtr(argv + argc); rangeVisitor(Root::ROOT_FRAME, ObjectSlot(start), ObjectSlot(end)); } bool ret = it.IteratorStackMap(visitor, derivedVisitor); if (!ret) { #ifndef NDEBUG LOG_ECMA(DEBUG) << " stackmap don't found returnAddr " << it.GetOptimizedReturnAddr(); #endif } } void OptimizedJSFunctionFrame::GetDeoptBundleInfo(const FrameIterator &it, std::vector& deopts) const { it.CollectArkDeopt(deopts); } void OptimizedJSFunctionFrame::GetFuncCalleeRegAndOffset( const FrameIterator &it, kungfu::CalleeRegAndOffsetVec &ret) const { it.GetCalleeRegAndOffsetVec(ret); } ARK_INLINE void AsmInterpretedFrame::GCIterate(const FrameIterator &it, const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor, const RootBaseAndDerivedVisitor &derivedVisitor) const { AsmInterpretedFrame *frame = AsmInterpretedFrame::GetFrameFromSp(it.GetSp()); uintptr_t start = ToUintPtr(it.GetSp()); uintptr_t end = ToUintPtr(frame->GetCurrentFramePointer()); rangeVisitor(Root::ROOT_FRAME, ObjectSlot(start), ObjectSlot(end)); visitor(Root::ROOT_FRAME, ObjectSlot(ToUintPtr(&frame->function))); visitor(Root::ROOT_FRAME, ObjectSlot(ToUintPtr(&frame->thisObj))); if (frame->pc != nullptr) { visitor(Root::ROOT_FRAME, ObjectSlot(ToUintPtr(&frame->acc))); visitor(Root::ROOT_FRAME, ObjectSlot(ToUintPtr(&frame->env))); } bool ret = it.IteratorStackMap(visitor, derivedVisitor); if (!ret) { #ifndef NDEBUG LOG_ECMA(DEBUG) << " stackmap don't found returnAddr " << it.GetOptimizedReturnAddr(); #endif } } ARK_INLINE void InterpretedFrame::GCIterate(const FrameIterator &it, const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor) const { auto sp = it.GetSp(); InterpretedFrame *frame = InterpretedFrame::GetFrameFromSp(sp); if (frame->function == JSTaggedValue::Hole()) { return; } JSTaggedType *prevSp = frame->GetPrevFrameFp(); uintptr_t start = ToUintPtr(sp); const JSThread *thread = it.GetThread(); FrameIterator prevIt(prevSp, thread); uintptr_t end = prevIt.GetPrevFrame(); rangeVisitor(Root::ROOT_FRAME, ObjectSlot(start), ObjectSlot(end)); visitor(Root::ROOT_FRAME, ObjectSlot(ToUintPtr(&frame->function))); visitor(Root::ROOT_FRAME, ObjectSlot(ToUintPtr(&frame->thisObj))); // pc == nullptr, init InterpretedFrame & native InterpretedFrame. if (frame->pc != nullptr) { visitor(Root::ROOT_FRAME, ObjectSlot(ToUintPtr(&frame->acc))); visitor(Root::ROOT_FRAME, ObjectSlot(ToUintPtr(&frame->constpool))); visitor(Root::ROOT_FRAME, ObjectSlot(ToUintPtr(&frame->env))); visitor(Root::ROOT_FRAME, ObjectSlot(ToUintPtr(&frame->profileTypeInfo))); } } ARK_INLINE void InterpretedBuiltinFrame::GCIterate(const FrameIterator &it, const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor) const { auto sp = it.GetSp(); InterpretedBuiltinFrame *frame = InterpretedBuiltinFrame::GetFrameFromSp(sp); JSTaggedType *prevSp = frame->GetPrevFrameFp(); const JSThread *thread = it.GetThread(); FrameIterator prevIt(prevSp, thread); uintptr_t start = ToUintPtr(sp + 2); // 2: numArgs & thread. uintptr_t end = prevIt.GetPrevFrame(); rangeVisitor(Root::ROOT_FRAME, ObjectSlot(start), ObjectSlot(end)); visitor(Root::ROOT_FRAME, ObjectSlot(ToUintPtr(&frame->function))); } ARK_INLINE void OptimizedLeaveFrame::GCIterate(const FrameIterator &it, [[maybe_unused]] const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor) const { const JSTaggedType *sp = it.GetSp(); OptimizedLeaveFrame *frame = OptimizedLeaveFrame::GetFrameFromSp(sp); if (frame->argc > 0) { JSTaggedType *argv = reinterpret_cast(&frame->argc + 1); uintptr_t start = ToUintPtr(argv); // argv uintptr_t end = ToUintPtr(argv + frame->argc); rangeVisitor(Root::ROOT_FRAME, ObjectSlot(start), ObjectSlot(end)); } } ARK_INLINE void OptimizedWithArgvLeaveFrame::GCIterate(const FrameIterator &it, [[maybe_unused]] const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor) const { const JSTaggedType *sp = it.GetSp(); OptimizedWithArgvLeaveFrame *frame = OptimizedWithArgvLeaveFrame::GetFrameFromSp(sp); if (frame->argc > 0) { uintptr_t* argvPtr = reinterpret_cast(&frame->argc + 1); JSTaggedType *argv = reinterpret_cast(*argvPtr); uintptr_t start = ToUintPtr(argv); // argv uintptr_t end = ToUintPtr(argv + frame->argc); rangeVisitor(Root::ROOT_FRAME, ObjectSlot(start), ObjectSlot(end)); } } ARK_INLINE void OptimizedBuiltinLeaveFrame::GCIterate(const FrameIterator &it, [[maybe_unused]] const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor) const { const JSTaggedType *sp = it.GetSp(); OptimizedBuiltinLeaveFrame *frame = OptimizedBuiltinLeaveFrame::GetFrameFromSp(sp); if (frame->argc > 0) { JSTaggedType *argv = reinterpret_cast(&frame->argc + 1); uintptr_t start = ToUintPtr(argv); // argv uintptr_t end = ToUintPtr(argv + frame->argc); rangeVisitor(Root::ROOT_FRAME, ObjectSlot(start), ObjectSlot(end)); } } ARK_INLINE void BuiltinWithArgvFrame::GCIterate(const FrameIterator &it, [[maybe_unused]] const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor) const { const JSTaggedType *sp = it.GetSp(); auto frame = BuiltinWithArgvFrame::GetFrameFromSp(sp); auto argc = static_cast(frame->GetNumArgs()) + NUM_MANDATORY_JSFUNC_ARGS; JSTaggedType *argv = reinterpret_cast(frame->GetStackArgsAddress()); uintptr_t start = ToUintPtr(argv); uintptr_t end = ToUintPtr(argv + argc); rangeVisitor(Root::ROOT_FRAME, ObjectSlot(start), ObjectSlot(end)); } ARK_INLINE void BuiltinFrame::GCIterate(const FrameIterator &it, const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor) const { const JSTaggedType *sp = it.GetSp(); auto frame = BuiltinFrame::GetFrameFromSp(sp); // no need to visit stack map for entry frame if (frame->type == FrameType::BUILTIN_ENTRY_FRAME) { // only visit function visitor(Root::ROOT_FRAME, ObjectSlot(frame->GetStackArgsAddress())); return; } JSTaggedType *argv = reinterpret_cast(frame->GetStackArgsAddress()); auto argc = frame->GetNumArgs(); uintptr_t start = ToUintPtr(argv); uintptr_t end = ToUintPtr(argv + argc); rangeVisitor(Root::ROOT_FRAME, ObjectSlot(start), ObjectSlot(end)); } ARK_INLINE void InterpretedEntryFrame::GCIterate(const FrameIterator &it, [[maybe_unused]] const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor) const { const JSTaggedType* sp = it.GetSp(); InterpretedEntryFrame *frame = InterpretedEntryFrame::GetFrameFromSp(sp); JSTaggedType *prevSp = frame->GetPrevFrameFp(); if (prevSp == nullptr) { return; } const JSThread *thread = it.GetThread(); FrameIterator prevIt(prevSp, thread); uintptr_t start = ToUintPtr(sp + 2); // 2: numArgs & thread. uintptr_t end = prevIt.GetPrevFrame(); rangeVisitor(Root::ROOT_FRAME, ObjectSlot(start), ObjectSlot(end)); } bool ReadUintptrFromAddr(int pid, uintptr_t addr, uintptr_t &value) { if (pid == getpid()) { value = *(reinterpret_cast(addr)); return true; } long *retAddr = reinterpret_cast(&value); // note: big endian for (size_t i = 0; i < sizeof(uintptr_t) / sizeof(long); i++) { *retAddr = PtracePeektext(pid, addr); if (*retAddr == -1) { LOG_ECMA(ERROR) << "ReadFromAddr ERROR, addr: " << addr; return false; } addr += sizeof(long); retAddr++; } return true; } bool GetTypeOffsetAndPrevOffsetFromFrameType(uintptr_t frameType, uintptr_t &typeOffset, uintptr_t &prevOffset) { FrameType type = static_cast(frameType); switch (type) { case FrameType::OPTIMIZED_FRAME: typeOffset = OptimizedFrame::GetTypeOffset(); prevOffset = OptimizedFrame::GetPrevOffset(); break; case FrameType::OPTIMIZED_ENTRY_FRAME: typeOffset = OptimizedEntryFrame::GetTypeOffset(); prevOffset = OptimizedEntryFrame::GetLeaveFrameFpOffset(); break; case FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME: typeOffset = OptimizedJSFunctionUnfoldArgVFrame::GetTypeOffset(); prevOffset = OptimizedJSFunctionUnfoldArgVFrame::GetPrevOffset(); break; case FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME: case FrameType::OPTIMIZED_JS_FUNCTION_FRAME: typeOffset = OptimizedJSFunctionFrame::GetTypeOffset(); prevOffset = OptimizedJSFunctionFrame::GetPrevOffset(); break; case FrameType::LEAVE_FRAME: typeOffset = MEMBER_OFFSET(OptimizedLeaveFrame, type); prevOffset = MEMBER_OFFSET(OptimizedLeaveFrame, callsiteFp); break; case FrameType::LEAVE_FRAME_WITH_ARGV: typeOffset = MEMBER_OFFSET(OptimizedWithArgvLeaveFrame, type); prevOffset = MEMBER_OFFSET(OptimizedWithArgvLeaveFrame, callsiteFp); break; case FrameType::BUILTIN_CALL_LEAVE_FRAME: typeOffset = OptimizedBuiltinLeaveFrame::GetTypeOffset(); prevOffset = OptimizedBuiltinLeaveFrame::GetPrevOffset(); break; case FrameType::INTERPRETER_FRAME: case FrameType::INTERPRETER_FAST_NEW_FRAME: typeOffset = MEMBER_OFFSET(InterpretedFrame, base) + MEMBER_OFFSET(InterpretedFrameBase, type); prevOffset = MEMBER_OFFSET(InterpretedFrame, base) + MEMBER_OFFSET(InterpretedFrameBase, prev); break; case FrameType::INTERPRETER_BUILTIN_FRAME: typeOffset = MEMBER_OFFSET(InterpretedBuiltinFrame, base) + MEMBER_OFFSET(InterpretedFrameBase, type); prevOffset = MEMBER_OFFSET(InterpretedBuiltinFrame, base) + MEMBER_OFFSET(InterpretedFrameBase, prev); break; case FrameType::INTERPRETER_CONSTRUCTOR_FRAME: case FrameType::ASM_INTERPRETER_FRAME: typeOffset = MEMBER_OFFSET(AsmInterpretedFrame, base) + MEMBER_OFFSET(InterpretedFrameBase, type); prevOffset = MEMBER_OFFSET(AsmInterpretedFrame, base) + MEMBER_OFFSET(InterpretedFrameBase, prev); break; case FrameType::BUILTIN_FRAME: case FrameType::BUILTIN_ENTRY_FRAME: typeOffset = MEMBER_OFFSET(BuiltinFrame, type); prevOffset = MEMBER_OFFSET(BuiltinFrame, prevFp); break; case FrameType::BUILTIN_FRAME_WITH_ARGV: typeOffset = MEMBER_OFFSET(BuiltinWithArgvFrame, type); prevOffset = MEMBER_OFFSET(BuiltinWithArgvFrame, prevFp); break; case FrameType::INTERPRETER_ENTRY_FRAME: typeOffset = MEMBER_OFFSET(InterpretedEntryFrame, base) + MEMBER_OFFSET(InterpretedFrameBase, type); prevOffset = MEMBER_OFFSET(InterpretedEntryFrame, base) + MEMBER_OFFSET(InterpretedFrameBase, prev); break; case FrameType::ASM_INTERPRETER_ENTRY_FRAME: typeOffset = MEMBER_OFFSET(AsmInterpretedEntryFrame, base) + MEMBER_OFFSET(InterpretedFrameBase, type); prevOffset = MEMBER_OFFSET(AsmInterpretedEntryFrame, base) + MEMBER_OFFSET(InterpretedFrameBase, prev); break; case FrameType::ASM_INTERPRETER_BRIDGE_FRAME: typeOffset = MEMBER_OFFSET(AsmInterpretedBridgeFrame, entry) + MEMBER_OFFSET(AsmInterpretedEntryFrame, base) + MEMBER_OFFSET(InterpretedFrameBase, type); prevOffset = MEMBER_OFFSET(AsmInterpretedBridgeFrame, entry) + MEMBER_OFFSET(AsmInterpretedEntryFrame, base) + MEMBER_OFFSET(InterpretedFrameBase, prev); break; default: return false; } return true; } bool StepArkManagedNativeFrame(int pid, uintptr_t *pc, uintptr_t *fp, uintptr_t *sp, [[maybe_unused]] char *buf, [[maybe_unused]] size_t bufSize) { uintptr_t currentPtr = *fp; while (true) { currentPtr -= sizeof(FrameType); uintptr_t frameType = 0; if (!ReadUintptrFromAddr(pid, currentPtr, frameType)) { return false; } uintptr_t typeOffset = 0; uintptr_t prevOffset = 0; if (!GetTypeOffsetAndPrevOffsetFromFrameType(frameType, typeOffset, prevOffset)) { LOG_ECMA(ERROR) << "FrameType ERROR, addr: " << currentPtr << ", frameType: " << frameType; return false; } if (frameType == (uintptr_t)(FrameType::ASM_INTERPRETER_ENTRY_FRAME)) { break; } currentPtr -= typeOffset; currentPtr += prevOffset; if (!ReadUintptrFromAddr(pid, currentPtr, currentPtr)) { return false; } } currentPtr += sizeof(FrameType); *fp = currentPtr; currentPtr += 8; // 8: size of fp if (!ReadUintptrFromAddr(pid, currentPtr, *pc)) { return false; } currentPtr += 8; // 8: size of lr *sp = currentPtr; return true; } } // namespace panda::ecmascript __attribute__((visibility("default"))) int step_ark_managed_native_frame( int pid, uintptr_t *pc, uintptr_t *fp, uintptr_t *sp, char *buf, size_t buf_sz) { if (panda::ecmascript::StepArkManagedNativeFrame(pid, pc, fp, sp, buf, buf_sz)) { return 1; } return -1; }