1 /**
2 * Copyright (c) 2021-2022 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/include/panda_vm.h"
22 #include "runtime/interpreter/interpreter.h"
23 #include "bytecode_instruction.h"
24 #include "bytecode_instruction-inl.h"
25
26 namespace panda {
27 // Actualy it is wrong signature but it is 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 extern "C" void DefaultConflictMethodStub();
32
GetCompiledCodeToInterpreterBridge(const Method * method)33 const void *GetCompiledCodeToInterpreterBridge(const Method *method)
34 {
35 ASSERT(method != nullptr);
36 const void *bridge = nullptr;
37
38 if (method->GetClass() == nullptr) {
39 bridge = reinterpret_cast<const void *>(CompiledCodeToInterpreterBridgeDyn);
40 } else {
41 if (panda::panda_file::IsDynamicLanguage(method->GetClass()->GetSourceLang())) {
42 bridge = reinterpret_cast<const void *>(CompiledCodeToInterpreterBridgeDyn);
43 } else {
44 bridge = reinterpret_cast<const void *>(CompiledCodeToInterpreterBridge);
45 }
46 }
47 return bridge;
48 }
49
GetCompiledCodeToInterpreterBridge()50 const void *GetCompiledCodeToInterpreterBridge()
51 {
52 return reinterpret_cast<const void *>(CompiledCodeToInterpreterBridge);
53 }
54
GetCompiledCodeToInterpreterBridgeDyn()55 const void *GetCompiledCodeToInterpreterBridgeDyn()
56 {
57 return reinterpret_cast<const void *>(CompiledCodeToInterpreterBridgeDyn);
58 }
59
60 template <class VRegRef>
GetVRegValue(VRegRef reg)61 static inline int64_t GetVRegValue(VRegRef reg)
62 {
63 return reg.HasObject() ? static_cast<int64_t>(bit_cast<uintptr_t>(reg.GetReference())) : reg.GetLong();
64 }
65
66 /**
67 * This function supposed to be called from the deoptimization code. It aims to call interpreter for given frame from
68 * specific pc. Note, that it releases input interpreter's frame at the exit.
69 */
InvokeInterpreter(ManagedThread * thread,const uint8_t * pc,Frame * frame,Frame * last_frame)70 extern "C" int64_t InvokeInterpreter(ManagedThread *thread, const uint8_t *pc, Frame *frame, Frame *last_frame)
71 {
72 bool prev_frame_kind = thread->IsCurrentFrameCompiled();
73 thread->SetCurrentFrame(frame);
74 thread->SetCurrentFrameIsCompiled(false);
75 LOG(DEBUG, INTEROP) << "InvokeInterpreter for method: " << frame->GetMethod()->GetFullName();
76
77 interpreter::Execute(thread, pc, frame, thread->HasPendingException());
78
79 int64_t res;
80 auto acc = frame->GetAcc();
81 if (frame->IsDynamic()) {
82 res = GetVRegValue(acc.template AsVRegRef<true>());
83 } else {
84 res = GetVRegValue(acc.AsVRegRef());
85 }
86
87 auto prev_frame = frame->GetPrevFrame();
88 thread->SetCurrentFrame(prev_frame);
89 thread->GetVM()->GetLanguageContext().DeoptimizeEnd();
90 FreeFrame(frame);
91
92 // We need to execute(find catch block) in all inlined methods. For this we use number of inlined method
93 // Else we can execute previus interpreter frames and we will FreeFrames in incorrect order
94 while (prev_frame != nullptr && last_frame != frame) {
95 ASSERT(!StackWalker::IsBoundaryFrame<FrameKind::INTERPRETER>(prev_frame));
96 frame = prev_frame;
97 LOG(DEBUG, INTEROP) << "InvokeInterpreter for method: " << frame->GetMethod()->GetFullName();
98 prev_frame = frame->GetPrevFrame();
99 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
100 pc = frame->GetMethod()->GetInstructions() + frame->GetBytecodeOffset();
101 if (!thread->HasPendingException()) {
102 auto bc_inst = BytecodeInstruction(pc);
103 auto opcode = bc_inst.GetOpcode();
104 // Compiler splites InitObj to NewObject + CallStatic
105 // if we have an deoptimization occurred in the CallStatic, we must not copy acc from CallStatic,
106 // because acc contain result of the NewObject
107 if (opcode != BytecodeInstruction::Opcode::INITOBJ_SHORT_V4_V4_ID16 &&
108 opcode != BytecodeInstruction::Opcode::INITOBJ_V4_V4_V4_V4_ID16 &&
109 opcode != BytecodeInstruction::Opcode::INITOBJ_RANGE_V8_ID16) {
110 frame->GetAcc() = acc;
111 }
112 pc = bc_inst.GetNext().GetAddress();
113 } else {
114 frame->GetAcc() = acc;
115 }
116 interpreter::Execute(thread, pc, frame, thread->HasPendingException());
117
118 acc = frame->GetAcc();
119 if (frame->IsDynamic()) {
120 res = GetVRegValue(acc.template AsVRegRef<true>());
121 } else {
122 res = GetVRegValue(acc.AsVRegRef());
123 }
124
125 thread->SetCurrentFrame(prev_frame);
126 thread->GetVM()->GetLanguageContext().DeoptimizeEnd();
127 FreeFrame(frame);
128 }
129 thread->SetCurrentFrameIsCompiled(prev_frame_kind);
130
131 return res;
132 }
133
GetAbstractMethodStub()134 const void *GetAbstractMethodStub()
135 {
136 return reinterpret_cast<const void *>(AbstractMethodStub);
137 }
138
GetDefaultConflictMethodStub()139 const void *GetDefaultConflictMethodStub()
140 {
141 return reinterpret_cast<const void *>(DefaultConflictMethodStub);
142 }
143 } // namespace panda
144