h00799777 4f1643a395 opt for cj&arkts interop
Issue: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/IBKI32

Signed-off-by: h00799777 <huangbingyao@huawei.com>
2025-02-14 20:48:53 +08:00

522 lines
18 KiB
C++

/*
* Copyright (c) 2021-2024 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/interpreter/frame_handler.h"
#include "ecmascript/jspandafile/program_object.h"
#include "ecmascript/stubs/runtime_stubs-inl.h"
namespace panda::ecmascript {
FrameHandler::FrameHandler(const JSThread *thread)
: sp_(const_cast<JSTaggedType *>(thread->GetCurrentFrame())), thread_(thread)
{
AdvanceToJSFrame();
}
ARK_INLINE void FrameHandler::AdvanceToJSFrame()
{
if (!thread_->IsAsmInterpreter()) {
return;
}
FrameIterator it(sp_, thread_);
for (; !it.Done(); it.Advance()) {
FrameType t = it.GetFrameType();
if (IsBaselineBuiltinFrame(t)) {
FindAndSetBaselineNativePc(it);
}
if (IsJSFrame(t) || IsJSEntryFrame(t)) {
break;
}
}
sp_ = it.GetSp();
}
ARK_INLINE void FrameHandler::PrevJSFrame()
{
if (!thread_->IsAsmInterpreter()) {
FrameIterator it(sp_, thread_);
if (IsBaselineBuiltinFrame(it.GetFrameType())) {
FindAndSetBaselineNativePc(it);
}
it.Advance();
sp_ = it.GetSp();
return;
}
AdvanceToJSFrame();
FrameIterator it(sp_, thread_);
FrameType t = it.GetFrameType();
if (t == FrameType::ASM_INTERPRETER_FRAME) {
auto frame = it.GetFrame<AsmInterpretedFrame>();
if (thread_->IsAsmInterpreter()) {
fp_ = frame->GetCurrentFramePointer();
}
}
it.Advance();
sp_ = it.GetSp();
AdvanceToJSFrame();
}
JSTaggedType* FrameHandler::GetPrevJSFrame()
{
PrevJSFrame();
return GetSp();
}
uint32_t FrameHandler::GetNumberArgs()
{
if (thread_->IsAsmInterpreter()) {
auto *frame = AsmInterpretedFrame::GetFrameFromSp(sp_);
return static_cast<uint32_t>(frame->GetCurrentFramePointer() - sp_);
}
ASSERT(IsInterpretedFrame());
JSTaggedType *prevSp = nullptr;
FrameIterator it(sp_, thread_);
if (IsAsmInterpretedFrame()) {
auto *frame = it.GetFrame<AsmInterpretedFrame>();
prevSp = frame->GetPrevFrameFp();
} else {
auto *frame = it.GetFrame<InterpretedFrame>();
prevSp = frame->GetPrevFrameFp();
}
auto prevSpEnd = reinterpret_cast<JSTaggedType*>(GetInterpretedFrameEnd(prevSp));
return static_cast<uint32_t>(prevSpEnd - sp_);
}
JSTaggedValue FrameHandler::GetVRegValue(size_t index) const
{
ASSERT(IsInterpretedFrame());
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
return JSTaggedValue(sp_[index]);
}
void FrameHandler::SetVRegValue(size_t index, JSTaggedValue value)
{
ASSERT(IsInterpretedFrame());
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
sp_[index] = value.GetRawData();
}
void FrameHandler::FindAndSetBaselineNativePc(FrameIterator it)
{
ASSERT(IsBaselineBuiltinFrame(it.GetFrameType()));
auto *frame = it.GetFrame<BaselineBuiltinFrame>();
baselineNativePc_ = frame->GetReturnAddr();
}
JSTaggedValue FrameHandler::GetAcc() const
{
ASSERT(IsInterpretedFrame());
FrameIterator it(sp_, thread_);
if (IsAsmInterpretedFrame()) {
auto *frame = it.GetFrame<AsmInterpretedFrame>();
return frame->acc;
} else {
auto *frame = it.GetFrame<InterpretedFrame>();
return frame->acc;
}
}
uint32_t FrameHandler::GetBytecodeOffset() const
{
ASSERT(IsInterpretedFrame());
auto pc = GetPc();
if (reinterpret_cast<uintptr_t>(pc) != std::numeric_limits<uintptr_t>::max()) {
// interpreter frame
Method *method = GetMethod();
auto offset = pc - method->GetBytecodeArray();
return static_cast<uint32_t>(offset);
} else {
// baseline frame
uintptr_t curNativePc = GetBaselineNativePc();
ASSERT(curNativePc != 0);
LOG_BASELINEJIT(DEBUG) << "current native pc in UpFrame: " << std::hex <<
reinterpret_cast<void*>(curNativePc);
JSHandle<JSTaggedValue> funcVal = JSHandle<JSTaggedValue>(thread_, GetFunction());
JSHandle<JSFunction> func = JSHandle<JSFunction>::Cast(funcVal);
uint32_t curBytecodePcOfst = RuntimeStubs::RuntimeGetBytecodePcOfstForBaseline(func, curNativePc);
return curBytecodePcOfst;
}
}
Method *FrameHandler::GetMethod() const
{
ASSERT(IsJSFrame());
auto function = GetFunction();
return ECMAObject::Cast(function.GetTaggedObject())->GetCallTarget();
}
const JSPandaFile* FrameHandler::GetJSPandaFile() const
{
auto method = GetMethod();
return method->GetJSPandaFile();
}
std::string FrameHandler::GetFileName() const
{
auto pandaFile = GetJSPandaFile();
ASSERT(pandaFile != nullptr);
return pandaFile->GetJSPandaFileDesc().c_str();
}
uint32_t FrameHandler::GetAbcId() const
{
std::string abcName = GetFileName();
pgo::PGOProfilerManager* pm = pgo::PGOProfilerManager::GetInstance();
uint32_t abcId;
if (!pm->GetPandaFileId(CString(abcName), abcId) && !abcName.empty()) {
LOG_ECMA(ERROR) << "Get method abc id failed. abcName: " << abcName;
}
return abcId;
}
uint32_t FrameHandler::GetMethodId() const
{
return GetMethod()->GetMethodId().GetOffset();
}
Method *FrameHandler::CheckAndGetMethod() const
{
ASSERT(IsJSFrame());
auto function = GetFunction();
if (function.IsJSFunctionBase() || function.IsJSProxy()) {
return ECMAObject::Cast(function.GetTaggedObject())->GetCallTarget();
}
return nullptr;
}
JSTaggedValue FrameHandler::GetThis() const
{
ASSERT(IsInterpretedFrame());
FrameIterator it(sp_, thread_);
if (IsAsmInterpretedFrame()) {
auto *frame = it.GetFrame<AsmInterpretedFrame>();
return frame->thisObj;
} else {
auto *frame = it.GetFrame<InterpretedFrame>();
return frame->thisObj;
}
}
JSTaggedValue FrameHandler::GetFunction() const
{
ASSERT(IsJSFrame());
if (thread_->IsAsmInterpreter()) {
FrameType type = GetFrameType();
switch (type) {
case FrameType::ASM_INTERPRETER_FRAME:
case FrameType::INTERPRETER_CONSTRUCTOR_FRAME: {
auto frame = AsmInterpretedFrame::GetFrameFromSp(sp_);
return frame->function;
}
case FrameType::BUILTIN_FRAME_WITH_ARGV: {
auto *frame = BuiltinWithArgvFrame::GetFrameFromSp(sp_);
return frame->GetFunction();
}
case FrameType::BUILTIN_ENTRY_FRAME:
case FrameType::BUILTIN_FRAME: {
auto *frame = BuiltinFrame::GetFrameFromSp(sp_);
return frame->GetFunction();
}
case FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME:
case FrameType::OPTIMIZED_JS_FUNCTION_FRAME: {
auto *frame = OptimizedJSFunctionFrame::GetFrameFromSp(sp_);
return frame->GetFunction();
}
case FrameType::FASTJIT_FUNCTION_FRAME:
case FrameType::FASTJIT_FAST_CALL_FUNCTION_FRAME: {
auto *frame = FASTJITFunctionFrame::GetFrameFromSp(sp_);
return frame->GetFunction();
}
case FrameType::BUILTIN_FRAME_WITH_ARGV_STACK_OVER_FLOW_FRAME :
case FrameType::INTERPRETER_FRAME:
case FrameType::INTERPRETER_FAST_NEW_FRAME:
case FrameType::INTERPRETER_ENTRY_FRAME:
case FrameType::ASM_INTERPRETER_ENTRY_FRAME:
case FrameType::ASM_INTERPRETER_BRIDGE_FRAME:
case FrameType::INTERPRETER_BUILTIN_FRAME:
case FrameType::OPTIMIZED_FRAME:
case FrameType::BASELINE_BUILTIN_FRAME:
case FrameType::ASM_BRIDGE_FRAME:
case FrameType::LEAVE_FRAME:
case FrameType::LEAVE_FRAME_WITH_ARGV:
case FrameType::BUILTIN_CALL_LEAVE_FRAME:
case FrameType::OPTIMIZED_ENTRY_FRAME:
default: {
LOG_FULL(FATAL) << "frame type error!";
UNREACHABLE();
}
}
} else {
FrameType type = GetFrameType();
if (type == FrameType::INTERPRETER_FRAME || type == FrameType::INTERPRETER_FAST_NEW_FRAME) {
auto *frame = InterpretedFrame::GetFrameFromSp(sp_);
return frame->function;
} else {
auto *frame = InterpretedBuiltinFrame::GetFrameFromSp(sp_);
return frame->function;
}
}
}
const uint8_t *FrameHandler::GetPc() const
{
ASSERT(IsJSFrame());
FrameIterator it(sp_, thread_);
if (IsAsmInterpretedFrame()) {
auto *frame = it.GetFrame<AsmInterpretedFrame>();
return frame->GetPc();
} else {
auto *frame = it.GetFrame<InterpretedFrame>();
return frame->GetPc();
}
}
ConstantPool *FrameHandler::GetConstpool() const
{
ASSERT(IsInterpretedFrame());
auto method = GetMethod();
JSTaggedValue constpool = method->GetConstantPool();
return ConstantPool::Cast(constpool.GetTaggedObject());
}
JSTaggedValue FrameHandler::GetEnv() const
{
ASSERT(IsInterpretedFrame());
FrameIterator it(sp_, thread_);
if (IsAsmInterpretedFrame()) {
auto *frame = it.GetFrame<AsmInterpretedFrame>();
return frame->GetEnv();
} else {
auto *frame = it.GetFrame<InterpretedFrame>();
return frame->env;
}
}
void FrameHandler::DumpStack(std::ostream &os) const
{
size_t i = 0;
FrameHandler frameHandler(thread_);
for (; frameHandler.HasFrame(); frameHandler.PrevJSFrame()) {
os << "[" << i++
<< "]:" << frameHandler.GetMethod()->ParseFunctionName()
<< "\n";
}
}
void FrameHandler::DumpPC(std::ostream &os, const uint8_t *pc) const
{
FrameHandler frameHandler(thread_);
ASSERT(frameHandler.HasFrame());
// NOLINTNEXTLINE(cppcoreguidelines-narrowing-conversions, bugprone-narrowing-conversions)
int offset = pc - frameHandler.GetMethod()->GetBytecodeArray();
os << "offset: " << offset << "\n";
}
ARK_INLINE uintptr_t FrameHandler::GetInterpretedFrameEnd(JSTaggedType *prevSp) const
{
uintptr_t end = 0U;
FrameIterator it(prevSp, thread_);
FrameType type = it.GetFrameType();
switch (type) {
case FrameType::ASM_INTERPRETER_FRAME:
case FrameType::INTERPRETER_CONSTRUCTOR_FRAME: {
auto frame = it.GetFrame<AsmInterpretedFrame>();
end = ToUintPtr(frame);
break;
}
case FrameType::INTERPRETER_FRAME:
case FrameType::INTERPRETER_FAST_NEW_FRAME: {
auto frame = it.GetFrame<InterpretedFrame>();
end = ToUintPtr(frame);
break;
}
case FrameType::INTERPRETER_ENTRY_FRAME: {
auto frame = it.GetFrame<InterpretedEntryFrame>();
end = ToUintPtr(frame);
break;
}
case FrameType::INTERPRETER_BUILTIN_FRAME: {
auto frame = it.GetFrame<InterpretedBuiltinFrame>();
end = ToUintPtr(frame);
break;
}
case FrameType::BUILTIN_FRAME_WITH_ARGV_STACK_OVER_FLOW_FRAME :
case FrameType::BUILTIN_FRAME_WITH_ARGV:
case FrameType::BUILTIN_ENTRY_FRAME:
case FrameType::BUILTIN_FRAME:
case FrameType::OPTIMIZED_FRAME:
case FrameType::ASM_BRIDGE_FRAME:
case FrameType::LEAVE_FRAME:
case FrameType::BASELINE_BUILTIN_FRAME:
case FrameType::LEAVE_FRAME_WITH_ARGV:
case FrameType::BUILTIN_CALL_LEAVE_FRAME:
case FrameType::OPTIMIZED_ENTRY_FRAME:
case FrameType::ASM_INTERPRETER_ENTRY_FRAME:
case FrameType::ASM_INTERPRETER_BRIDGE_FRAME:
default: {
LOG_FULL(FATAL) << "frame type error!";
UNREACHABLE();
}
}
return end;
}
void FrameHandler::IterateAssembleStack(RootVisitor &visitor)
{
JSTaggedType *current = const_cast<JSTaggedType *>(thread_->GetLastLeaveFrame());
IterateFrameChain(current, visitor);
if (thread_->IsInSubStack() && thread_->GetMainStackInfo().lastLeaveFrame != 0) {
JSTaggedType *mainCurrent = reinterpret_cast<JSTaggedType *>(thread_->GetMainStackInfo().lastLeaveFrame);
IterateFrameChain(mainCurrent, visitor);
}
}
// We seperate InterpretedEntryFrame from assemble stack when asm interpreter is enable.
// To protect EcmaRuntimeCallInfo on InterpretedEntryFrame, we iterate InterpretedEntryFrame on thread sp individually.
// And only InterpretedEntryFrame is on thread sp when asm interpreter is enable.
void FrameHandler::IterateEcmaRuntimeCallInfo(RootVisitor &visitor)
{
ASSERT(thread_->IsAsmInterpreter());
JSTaggedType *current = const_cast<JSTaggedType *>(thread_->GetCurrentSPFrame());
for (FrameIterator it(current, thread_); !it.Done(); it.Advance()) {
ASSERT(it.GetFrameType() == FrameType::INTERPRETER_ENTRY_FRAME);
auto frame = it.GetFrame<InterpretedEntryFrame>();
frame->GCIterate(it, visitor);
}
}
void FrameHandler::Iterate(RootVisitor &visitor)
{
if (thread_->IsAsmInterpreter()) {
IterateEcmaRuntimeCallInfo(visitor);
IterateAssembleStack(visitor);
return;
}
JSTaggedType *current = const_cast<JSTaggedType *>(thread_->GetCurrentSPFrame());
FrameType frameType = FrameHandler::GetFrameType(current);
if (frameType != FrameType::INTERPRETER_ENTRY_FRAME) {
auto leaveFrame = const_cast<JSTaggedType *>(thread_->GetLastLeaveFrame());
if (leaveFrame != nullptr) {
current = leaveFrame;
}
}
// lazy assignment: only Iterate need arkStackMapParser_ in order to high improve performance
if (arkStackMapParser_ == nullptr) {
arkStackMapParser_ =
const_cast<JSThread *>(thread_)->GetEcmaVM()->GetAOTFileManager()->GetStackMapParser();
}
IterateFrameChain(current, visitor);
}
void FrameHandler::IterateFrameChain(JSTaggedType *start, RootVisitor &visitor) const
{
JSTaggedType *current = start;
// if the current frame type is BASELINE_BUILTIN_FRAME, the upper frame must be BaselineFrame.
// isBaselineFrame is used to differentiate the AsmInterpterFrame and BaselineFrame
bool isBaselineFrame = false;
for (FrameIterator it(current, thread_); !it.Done(); it.Advance<GCVisitedFlag::VISITED>()) {
FrameType type = it.GetFrameType();
switch (type) {
case FrameType::OPTIMIZED_FRAME: {
auto frame = it.GetFrame<OptimizedFrame>();
frame->GCIterate(it, visitor);
break;
}
case FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME:
case FrameType::OPTIMIZED_JS_FUNCTION_FRAME: {
auto frame = it.GetFrame<OptimizedJSFunctionFrame>();
frame->GCIterate(it, visitor, type);
break;
}
case FrameType::BASELINE_BUILTIN_FRAME: {
isBaselineFrame = true;
auto frame = it.GetFrame<BaselineBuiltinFrame>();
frame->GCIterate(it, visitor);
break;
}
case FrameType::FASTJIT_FUNCTION_FRAME:
case FrameType::FASTJIT_FAST_CALL_FUNCTION_FRAME: {
auto frame = it.GetFrame<FASTJITFunctionFrame>();
frame->GCIterate(it, visitor, type);
break;
}
case FrameType::ASM_INTERPRETER_FRAME:
case FrameType::INTERPRETER_CONSTRUCTOR_FRAME: {
auto frame = it.GetFrame<AsmInterpretedFrame>();
frame->GCIterate(it, visitor, isBaselineFrame);
isBaselineFrame = false;
break;
}
case FrameType::INTERPRETER_FRAME:
case FrameType::INTERPRETER_FAST_NEW_FRAME: {
auto frame = it.GetFrame<InterpretedFrame>();
frame->GCIterate(it, visitor);
break;
}
case FrameType::INTERPRETER_BUILTIN_FRAME: {
auto frame = it.GetFrame<InterpretedBuiltinFrame>();
frame->GCIterate(it, visitor);
break;
}
case FrameType::LEAVE_FRAME: {
auto frame = it.GetFrame<OptimizedLeaveFrame>();
frame->GCIterate(it, visitor);
break;
}
case FrameType::LEAVE_FRAME_WITH_ARGV: {
auto frame = it.GetFrame<OptimizedWithArgvLeaveFrame>();
frame->GCIterate(it, visitor);
break;
}
case FrameType::BUILTIN_CALL_LEAVE_FRAME: {
auto frame = it.GetFrame<OptimizedBuiltinLeaveFrame>();
frame->GCIterate(it, visitor);
break;
}
case FrameType::BUILTIN_FRAME_WITH_ARGV: {
auto frame = it.GetFrame<BuiltinWithArgvFrame>();
frame->GCIterate(it, visitor);
break;
}
case FrameType::BUILTIN_ENTRY_FRAME:
case FrameType::BUILTIN_FRAME: {
auto frame = it.GetFrame<BuiltinFrame>();
frame->GCIterate(it, visitor);
break;
}
case FrameType::INTERPRETER_ENTRY_FRAME: {
auto frame = it.GetFrame<InterpretedEntryFrame>();
frame->GCIterate(it, visitor);
break;
}
case FrameType::BUILTIN_FRAME_WITH_ARGV_STACK_OVER_FLOW_FRAME:
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;
}
default: {
LOG_FULL(FATAL) << "frame type error!";
UNREACHABLE();
}
}
}
}
} // namespace panda::ecmascript