/* * Copyright (c) 2021 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/interpreter/interpreter.h" #include "ecmascript/js_thread.h" #include "libpandafile/bytecode_instruction-inl.h" #include "ecmascript/compiler/llvm/llvm_stackmap_parser.h" namespace panda::ecmascript { InterpretedFrameHandler::InterpretedFrameHandler(const JSThread *thread) { sp_ = const_cast(thread->GetCurrentSPFrame()); } bool InterpretedFrameHandler::HasFrame() const { // Breakframe also is a frame return sp_ != nullptr; } bool InterpretedFrameHandler::IsBreakFrame() const { ASSERT(HasFrame()); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) FrameState *state = reinterpret_cast(sp_) - 1; return state->sp == nullptr; } void InterpretedFrameHandler::PrevFrame() { ASSERT(HasFrame()); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) FrameState *state = reinterpret_cast(sp_) - 1; sp_ = state->base.prev; } InterpretedFrameHandler InterpretedFrameHandler::GetPrevFrame() const { ASSERT(HasFrame()); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) FrameState *state = reinterpret_cast(sp_) - 1; return InterpretedFrameHandler(state->base.prev); } JSTaggedValue InterpretedFrameHandler::GetVRegValue(size_t index) const { ASSERT(HasFrame()); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) return JSTaggedValue(sp_[index]); } void InterpretedFrameHandler::SetVRegValue(size_t index, JSTaggedValue value) { ASSERT(HasFrame()); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) sp_[index] = value.GetRawData(); } JSTaggedValue InterpretedFrameHandler::GetAcc() const { ASSERT(HasFrame()); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) FrameState *state = reinterpret_cast(sp_) - 1; return state->acc; } uint32_t InterpretedFrameHandler::GetSize() const { ASSERT(HasFrame()); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) FrameState *state = reinterpret_cast(sp_) - 1; JSTaggedType *prevSp = state->base.prev; ASSERT(prevSp != nullptr); auto size = (prevSp - sp_) - FRAME_STATE_SIZE; return static_cast(size); } uint32_t InterpretedFrameHandler::GetBytecodeOffset() const { ASSERT(HasFrame()); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) FrameState *state = reinterpret_cast(sp_) - 1; // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) auto offset = state->pc - JSMethod::Cast(state->method)->GetBytecodeArray(); return static_cast(offset); } JSMethod *InterpretedFrameHandler::GetMethod() const { ASSERT(HasFrame()); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) FrameState *state = reinterpret_cast(sp_) - 1; return state->method; } JSTaggedValue InterpretedFrameHandler::GetFunction() const { ASSERT(HasFrame()); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) FrameState *state = reinterpret_cast(sp_) - 1; uint32_t numVregs = state->method->GetNumVregs(); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) auto func = JSTaggedValue(sp_[numVregs]); return func; } const uint8_t *InterpretedFrameHandler::GetPc() const { ASSERT(HasFrame()); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) FrameState *state = reinterpret_cast(sp_) - 1; return state->pc; } JSTaggedType *InterpretedFrameHandler::GetSp() const { ASSERT(HasFrame()); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) FrameState *state = reinterpret_cast(sp_) - 1; return state->sp; } ConstantPool *InterpretedFrameHandler::GetConstpool() const { ASSERT(HasFrame()); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) FrameState *state = reinterpret_cast(sp_) - 1; return state->constpool; } JSTaggedValue InterpretedFrameHandler::GetEnv() const { ASSERT(HasFrame()); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) FrameState *state = reinterpret_cast(sp_) - 1; return state->env; } void InterpretedFrameHandler::Iterate(const RootVisitor &v0, const RootRangeVisitor &v1) { JSTaggedType *current = sp_; if (current != nullptr) { // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) FrameState *state = reinterpret_cast(current) - 1; if (state->sp != nullptr) { uintptr_t start = ToUintPtr(current); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) FrameState *prev_state = reinterpret_cast(state->base.prev) - 1; uintptr_t end = ToUintPtr(prev_state); v1(Root::ROOT_FRAME, ObjectSlot(start), ObjectSlot(end)); if (state->pc != nullptr) { // interpreter frame v0(Root::ROOT_FRAME, ObjectSlot(ToUintPtr(&state->acc))); v0(Root::ROOT_FRAME, ObjectSlot(ToUintPtr(&state->constpool))); v0(Root::ROOT_FRAME, ObjectSlot(ToUintPtr(&state->env))); v0(Root::ROOT_FRAME, ObjectSlot(ToUintPtr(&state->profileTypeInfo))); } } } } void InterpretedFrameHandler::DumpStack(std::ostream &os) const { size_t i = 0; InterpretedFrameHandler frameHandler(sp_); for (; frameHandler.HasFrame(); frameHandler.PrevFrame()) { os << "[" << i++ << "]:" << frameHandler.GetMethod()->ParseFunctionName() << "\n"; } } void InterpretedFrameHandler::DumpPC(std::ostream &os, const uint8_t *pc) const { InterpretedFrameHandler frameHandler(sp_); ASSERT(frameHandler.HasFrame()); // NOLINTNEXTLINE(cppcoreguidelines-narrowing-conversions, bugprone-narrowing-conversions) int offset = pc - JSMethod::Cast(frameHandler.GetMethod())->GetBytecodeArray(); os << "offset: " << offset << "\n"; } void OptimizedFrameHandler::Iterate(const RootVisitor &v0, const RootRangeVisitor &v1) const { uintptr_t *current = fp_; if (current != nullptr) { // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) std::vector slotAddrs; auto returnAddr = reinterpret_cast(*(current + 1)); bool ret = kungfu::LLVMStackMapParser::GetInstance().StackMapByFuncAddrFp( returnAddr, reinterpret_cast(fp_), slotAddrs); if (ret == false) { return; } for (auto &address: slotAddrs) { v0(Root::ROOT_FRAME, ObjectSlot(address)); } } } void OptimizedEntryFrameHandler::Iterate(const RootVisitor &v0, const RootRangeVisitor &v1) const { uintptr_t *current = fp_; if (current != nullptr) { // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) std::vector slotAddrs; auto returnAddr = *(current + 1); bool ret = kungfu::LLVMStackMapParser::GetInstance().StackMapByFuncAddrFp( reinterpret_cast(returnAddr), reinterpret_cast(fp_), slotAddrs); if (ret == false) { return; } for (auto &address: slotAddrs) { v0(Root::ROOT_FRAME, ObjectSlot(address)); } } } void FrameIterator::Iterate(const RootVisitor &v0, const RootRangeVisitor &v1) const { JSTaggedType *current = fp_; while (current) { FrameType type = *(reinterpret_cast( reinterpret_cast(current) + FrameConst::kFrameType)); if (type == FrameType::INTERPRETER_FRAME) { FrameState *state = reinterpret_cast(current) - 1; InterpretedFrameHandler(current).Iterate(v0, v1); current = state->base.prev; } else if (type == FrameType::OPTIMIZED_FRAME) { OptimizedFrameStateBase *state = reinterpret_cast( reinterpret_cast(current) - MEMBER_OFFSET(OptimizedFrameStateBase, prev)); OptimizedFrameHandler(reinterpret_cast(current)).Iterate(v0, v1); current = reinterpret_cast(state->prev); } else { ASSERT(type == FrameType::OPTIMIZED_ENTRY_FRAME); OptimizedEntryFrameState *state = reinterpret_cast( reinterpret_cast(current) - MEMBER_OFFSET(OptimizedEntryFrameState, base.prev)); OptimizedEntryFrameHandler(reinterpret_cast(current)).Iterate(v0, v1); current = reinterpret_cast(state->threadFp); } } } } // namespace panda::ecmascript