• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2025 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()->IsProfilerEnabled()) {
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