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