1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "runtime/bridge/bridge.h"
17
18 #include "libpandafile/bytecode_instruction-inl.h"
19 #include "runtime/entrypoints/entrypoints.h"
20 #include "runtime/include/managed_thread.h"
21 #include "runtime/interpreter/interpreter.h"
22 #include "bytecode_instruction.h"
23 #include "bytecode_instruction-inl.h"
24
25 namespace panda {
26
27 // Actually it is wrong signature but it is the only way to make linker don't remove this function
28 extern "C" void CompiledCodeToInterpreterBridge(Method *);
29 extern "C" void CompiledCodeToInterpreterBridgeDyn(Method *);
30 extern "C" void AbstractMethodStub();
31
GetCompiledCodeToInterpreterBridge(const Method * method)32 const void *GetCompiledCodeToInterpreterBridge(const Method *method)
33 {
34 ASSERT(method != nullptr);
35 const void *bridge = nullptr;
36
37 if (method->GetClass() == nullptr) {
38 bridge = reinterpret_cast<const void *>(CompiledCodeToInterpreterBridgeDyn);
39 } else {
40 if (method->GetClass()->GetSourceLang() == panda_file::SourceLang::ECMASCRIPT) {
41 bridge = reinterpret_cast<const void *>(CompiledCodeToInterpreterBridgeDyn);
42 } else {
43 bridge = reinterpret_cast<const void *>(CompiledCodeToInterpreterBridge);
44 }
45 }
46 return bridge;
47 }
48
49 /**
50 * This function is supposed to be called from the deoptimization code. It aims to call interpreter for given frame
51 * from specific pc. Note, that it releases input interpreter's frame at the exit.
52 */
InvokeInterpreter(ManagedThread * thread,const uint8_t * pc,Frame * frame,Frame * last_frame)53 extern "C" int64_t InvokeInterpreter(ManagedThread *thread, const uint8_t *pc, Frame *frame, Frame *last_frame)
54 {
55 bool prev_frame_kind = thread->IsCurrentFrameCompiled();
56 thread->SetCurrentFrame(frame);
57 thread->SetCurrentFrameIsCompiled(false);
58 LOG(DEBUG, INTEROP) << "InvokeInterpreter for method: " << frame->GetMethod()->GetFullName();
59
60 interpreter::Execute(thread, pc, frame, thread->HasPendingException());
61
62 auto acc = frame->GetAcc();
63 auto res = acc.HasObject() ? static_cast<int64_t>(bit_cast<uintptr_t>(acc.GetReference())) : acc.GetLong();
64
65 auto prev_frame = frame->GetPrevFrame();
66 thread->SetCurrentFrame(prev_frame);
67 FreeFrame(frame);
68
69 // We need to execute (find catch block) in all inlined methods. For this we use the number of inlined method.
70 // Else we can execute previous interpreter frames and we will FreeFrames in incorrect order.
71 while (prev_frame != nullptr && last_frame != frame) {
72 ASSERT(!StackWalker::IsBoundaryFrame<FrameKind::INTERPRETER>(prev_frame));
73 frame = prev_frame;
74 LOG(DEBUG, INTEROP) << "InvokeInterpreter for method: " << frame->GetMethod()->GetFullName();
75 prev_frame = frame->GetPrevFrame();
76 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
77 pc = frame->GetMethod()->GetInstructions() + frame->GetBytecodeOffset();
78 if (!thread->HasPendingException()) {
79 auto bc_inst = BytecodeInstruction(pc);
80 auto opcode = bc_inst.GetOpcode();
81 // Compiler splits InitObj to NewObject + CallStatic
82 // if we have a deoptimization occurred in the CallStatic, we must not copy acc from CallStatic,
83 // because acc contains result of the NewObject
84 if (opcode != BytecodeInstruction::Opcode::INITOBJ_SHORT_V4_V4_ID16 &&
85 opcode != BytecodeInstruction::Opcode::INITOBJ_V4_V4_V4_V4_ID16 &&
86 opcode != BytecodeInstruction::Opcode::INITOBJ_RANGE_V8_ID16) {
87 frame->GetAcc() = acc;
88 }
89 pc = bc_inst.GetNext().GetAddress();
90 } else {
91 frame->GetAcc() = acc;
92 }
93 interpreter::Execute(thread, pc, frame, thread->HasPendingException());
94
95 acc = frame->GetAcc();
96 res = acc.HasObject() ? static_cast<int64_t>(bit_cast<uintptr_t>(acc.GetReference())) : acc.GetLong();
97
98 thread->SetCurrentFrame(prev_frame);
99 FreeFrame(frame);
100 }
101 thread->SetCurrentFrameIsCompiled(prev_frame_kind);
102
103 return res;
104 }
105
106 } // namespace panda
107