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/interpreter/interpreter_impl.h"
17
18 #include "libpandabase/macros.h"
19 #include "runtime/interpreter/interpreter-inl.h"
20 #include "runtime/interpreter/runtime_interface.h"
21 #ifdef PANDA_WITH_IRTOC
22 #include "irtoc_interpreter_utils.h"
23 #endif
24 #include "interpreter-inl_gen.h"
25
26 extern "C" void ExecuteImplFast(void *, void *, void *, void *);
27 extern "C" void ExecuteImplFastEH(void *, void *, void *, void *);
28 #ifdef PANDA_LLVM_INTERPRETER
29 extern "C" void ExecuteImplFast_LLVM(void *, void *, void *, void *); // NOLINT(readability-identifier-naming)
30 extern "C" void ExecuteImplFastEH_LLVM(void *, void *, void *, void *); // NOLINT(readability-identifier-naming)
31 #endif
32
33 namespace ark::interpreter {
34
35 enum InterpreterType { CPP = 0, IRTOC, LLVM };
36
ExecuteImplType(InterpreterType interpreterType,ManagedThread * thread,const uint8_t * pc,Frame * frame,bool jumpToEh)37 void ExecuteImplType(InterpreterType interpreterType, ManagedThread *thread, const uint8_t *pc, Frame *frame,
38 bool jumpToEh)
39 {
40 if (interpreterType == InterpreterType::LLVM) {
41 #ifdef PANDA_LLVM_INTERPRETER
42 LOG(DEBUG, RUNTIME) << "Setting up LLVM Irtoc dispatch table";
43 auto dispathTable = SetupLLVMDispatchTableImpl();
44 if (jumpToEh) {
45 ExecuteImplFastEH_LLVM(thread, const_cast<uint8_t *>(pc), frame, dispathTable);
46 } else {
47 ExecuteImplFast_LLVM(thread, const_cast<uint8_t *>(pc), frame, dispathTable);
48 }
49 #else
50 LOG(FATAL, RUNTIME) << "--interpreter-type=llvm is not supported in this configuration";
51 #endif
52 } else if (interpreterType == InterpreterType::IRTOC) {
53 #ifdef PANDA_WITH_IRTOC
54 LOG(DEBUG, RUNTIME) << "Setting up Irtoc dispatch table";
55 auto dispathTable = SetupDispatchTableImpl();
56 if (jumpToEh) {
57 ExecuteImplFastEH(thread, const_cast<uint8_t *>(pc), frame, dispathTable);
58 } else {
59 ExecuteImplFast(thread, const_cast<uint8_t *>(pc), frame, dispathTable);
60 }
61 #else
62 LOG(FATAL, RUNTIME) << "--interpreter-type=irtoc is not supported in this configuration";
63 #endif
64 } else {
65 if (frame->IsDynamic()) {
66 if (thread->GetVM()->IsBytecodeProfilingEnabled()) {
67 ExecuteImplInner<RuntimeInterface, true, true>(thread, pc, frame, jumpToEh);
68 } else {
69 ExecuteImplInner<RuntimeInterface, true, false>(thread, pc, frame, jumpToEh);
70 }
71 } else {
72 ExecuteImplInner<RuntimeInterface, false>(thread, pc, frame, jumpToEh);
73 }
74 }
75 }
76
ExecuteImpl(ManagedThread * thread,const uint8_t * pc,Frame * frame,bool jumpToEh)77 void ExecuteImpl(ManagedThread *thread, const uint8_t *pc, Frame *frame, bool jumpToEh)
78 {
79 const uint8_t *inst = frame->GetMethod()->GetInstructions();
80 frame->SetInstruction(inst);
81 InterpreterType interpreterType = InterpreterType::CPP;
82 #if !defined(PANDA_TARGET_ARM32) // Arm32 sticks to cpp - irtoc is not available there
83 bool wasSet = Runtime::GetOptions().WasSetInterpreterType();
84 // Dynamic languages default is always cpp interpreter (unless option was set)
85 if (!frame->IsDynamic() || wasSet) {
86 auto interpreterTypeStr = Runtime::GetOptions().GetInterpreterType();
87 if (interpreterTypeStr == "llvm") {
88 interpreterType = InterpreterType::LLVM;
89 } else if (interpreterTypeStr == "irtoc") {
90 interpreterType = InterpreterType::IRTOC;
91 } else {
92 ASSERT(interpreterTypeStr == "cpp");
93 }
94 if (!wasSet) {
95 #ifndef PANDA_LLVM_INTERPRETER
96 if (interpreterType == InterpreterType::LLVM) {
97 interpreterType = InterpreterType::IRTOC;
98 }
99 #endif
100 #ifndef PANDA_WITH_IRTOC
101 if (interpreterType == InterpreterType::IRTOC) {
102 interpreterType = InterpreterType::CPP;
103 }
104 #endif
105 }
106 }
107 if (interpreterType > InterpreterType::CPP) {
108 if (Runtime::GetCurrent()->IsDebugMode()) {
109 LOG(FATAL, RUNTIME) << "--debug-mode=true option is supported only with --interpreter-type=cpp";
110 return;
111 }
112 if (frame->IsDynamic()) {
113 auto gcType = thread->GetVM()->GetGC()->GetType();
114 if (gcType != mem::GCType::G1_GC) {
115 LOG(FATAL, RUNTIME) << "For dynamic languages, --gc-type=" << mem::GCStringFromType(gcType)
116 << " option is supported only with --interpreter-type=cpp";
117 return;
118 }
119 if (Runtime::GetCurrent()->IsJitEnabled()) {
120 LOG(INFO, RUNTIME) << "Dynamic types profiling disabled, use --interpreter-type=cpp to enable";
121 }
122 }
123 }
124 #endif
125 ExecuteImplType(interpreterType, thread, pc, frame, jumpToEh);
126 }
127
128 // Methods for debugging
129
130 template <class RuntimeIfaceT, bool IS_DYNAMIC>
DebugDump()131 void InstructionHandlerBase<RuntimeIfaceT, IS_DYNAMIC>::DebugDump()
132 {
133 #ifndef NDEBUG
134 auto frame = GetFrame();
135 auto method = frame->GetMethod();
136 PandaString pad = " ";
137 std::cerr << "Method " << method->GetFullName(true) << std::endl;
138 std::cerr << pad << "nargs = " << method->GetNumArgs() << std::endl;
139 std::cerr << pad << "nregs = " << method->GetNumVregs() << std::endl;
140 std::cerr << pad << "total frame size = " << frame->GetSize() << std::endl;
141 std::cerr << "Frame:" << std::endl;
142 std::cerr << pad << "acc." << GetAccAsVReg<IS_DYNAMIC>().DumpVReg() << std::endl;
143 auto frameHandler = GetFrameHandler(frame);
144 for (size_t i = 0; i < frame->GetSize(); ++i) {
145 std::cerr << pad << "v" << i << "." << frameHandler.GetVReg(i).DumpVReg() << std::endl;
146 }
147 std::cerr << "Bytecode:" << std::endl;
148 size_t offset = 0;
149 BytecodeInstruction inst(method->GetInstructions());
150 while (offset < method->GetCodeSize()) {
151 if (inst.GetAddress() == GetInst().GetAddress()) {
152 std::cerr << " -> ";
153 } else {
154 std::cerr << " ";
155 }
156
157 std::cerr << std::hex << std::setw(sizeof(uintptr_t)) << std::setfill('0')
158 << reinterpret_cast<uintptr_t>(inst.GetAddress()) << std::dec << ": " << inst << std::endl;
159 offset += inst.GetSize();
160 inst = inst.GetNext();
161 }
162 #endif // NDEBUG
163 }
164
EnsureDebugMethodsInstantiation(void * handler)165 void EnsureDebugMethodsInstantiation(void *handler)
166 {
167 static_cast<InstructionHandlerBase<RuntimeInterface, false> *>(handler)->DebugDump();
168 static_cast<InstructionHandlerBase<RuntimeInterface, true> *>(handler)->DebugDump();
169 }
170
171 } // namespace ark::interpreter
172