• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifndef PANDA_INTERPRETER_INSTRUCTION_HANDLER_BASE_H_
17 #define PANDA_INTERPRETER_INSTRUCTION_HANDLER_BASE_H_
18 
19 #include <isa_constants_gen.h>
20 #include "runtime/include/method.h"
21 #include "runtime/interpreter/instruction_handler_state.h"
22 
23 namespace panda::interpreter {
24 
25 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
26 #define LOG_INST()                                                                           \
27     LOG(DEBUG, INTERPRETER) << std::hex << std::setw(sizeof(uintptr_t)) << std::setfill('0') \
28                             << reinterpret_cast<uintptr_t>(this->GetInst().GetAddress()) << std::dec << ": "
29 
30 #ifdef PANDA_ENABLE_GLOBAL_REGISTER_VARIABLES
31 #include "arch/global_regs.h"
32 
33 class StaticFrameHandlerT : public StaticFrameHandler {
34 public:
StaticFrameHandlerT(Frame * frame)35     ALWAYS_INLINE inline explicit StaticFrameHandlerT(Frame *frame) : StaticFrameHandler(frame) {}
36 
37 private:
GetVRegisters()38     ALWAYS_INLINE inline interpreter::VRegister *GetVRegisters()
39     {
40         return reinterpret_cast<interpreter::VRegister *>(arch::regs::GetFp());
41     }
42 
GetMirrorVRegisters()43     ALWAYS_INLINE inline interpreter::VRegister *GetMirrorVRegisters()
44     {
45         return reinterpret_cast<interpreter::VRegister *>(arch::regs::GetMirrorFp());
46     }
47 };
48 
49 class DynamicFrameHandlerT : public DynamicFrameHandler {
50 public:
DynamicFrameHandlerT(Frame * frame)51     ALWAYS_INLINE inline explicit DynamicFrameHandlerT(Frame *frame) : DynamicFrameHandler(frame) {}
52 
53 private:
GetVRegisters()54     ALWAYS_INLINE inline interpreter::VRegister *GetVRegisters()
55     {
56         return reinterpret_cast<interpreter::VRegister *>(arch::regs::GetFp());
57     }
58 };
59 
60 #else
61 
62 using StaticFrameHandlerT = StaticFrameHandler;
63 using DynamicFrameHandlerT = DynamicFrameHandler;
64 
65 #endif  // PANDA_ENABLE_GLOBAL_REGISTER_VARIABLES
66 
67 template <class RuntimeIfaceT, bool is_dynamic>
68 class InstructionHandlerBase {
69 public:
InstructionHandlerBase(InstructionHandlerState * state)70     ALWAYS_INLINE explicit InstructionHandlerBase(InstructionHandlerState *state) : state_(state) {}
71 
GetExceptionOpcode()72     ALWAYS_INLINE uint16_t GetExceptionOpcode() const
73     {
74         // Need to call GetInst().GetOpcode() in this case too, otherwise compiler can generate non optimal code
75         return static_cast<unsigned>(GetInst().GetPrimaryOpcode()) + state_->GetOpcodeExtension();
76     }
77 
GetPrimaryOpcode()78     ALWAYS_INLINE uint8_t GetPrimaryOpcode() const
79     {
80         return static_cast<unsigned>(GetInst().GetPrimaryOpcode());
81     }
82 
GetSecondaryOpcode()83     ALWAYS_INLINE uint8_t GetSecondaryOpcode() const
84     {
85         return static_cast<unsigned>(GetInst().GetSecondaryOpcode());
86     }
87 
IsPrimaryOpcodeValid()88     ALWAYS_INLINE bool IsPrimaryOpcodeValid() const
89     {
90         return GetInst().IsPrimaryOpcodeValid();
91     }
92 
DumpVRegs()93     void DumpVRegs()
94     {
95 #if PANDA_ENABLE_SLOW_DEBUG
96         // Skip dump if logger is disable. This allows us to speed up interpretation in the 'Debug' build.
97         if (!Logger::IsLoggingOn(Logger::Level::DEBUG, Logger::Component::INTERPRETER)) {
98             return;
99         }
100 
101         static constexpr uint64_t STANDARD_DEBUG_INDENT = 5;
102         LOG(DEBUG, INTERPRETER) << PandaString(STANDARD_DEBUG_INDENT, ' ') << "acc."
103                                 << GetAccAsVReg<is_dynamic>().DumpVReg();
104         auto frame_handler = GetFrameHandler();
105         for (size_t i = 0; i < GetFrame()->GetSize(); ++i) {
106             LOG(DEBUG, INTERPRETER) << PandaString(STANDARD_DEBUG_INDENT, ' ') << "v" << i << "."
107                                     << frame_handler.GetVReg(i).DumpVReg();
108         }
109 #endif
110     }
111 
UpdateBytecodeOffset()112     ALWAYS_INLINE uint32_t UpdateBytecodeOffset()
113     {
114         auto pc = GetBytecodeOffset();
115         GetFrame()->SetBytecodeOffset(pc);
116         return pc;
117     }
118 
InstrumentInstruction()119     void InstrumentInstruction()
120     {
121         // Should set ACC to Frame, so that ACC will be marked when GC
122         GetFrame()->SetAcc(GetAcc());
123 
124         auto pc = UpdateBytecodeOffset();
125         RuntimeIfaceT::GetNotificationManager()->BytecodePcChangedEvent(GetThread(), GetFrame()->GetMethod(), pc);
126 
127         // BytecodePcChangedEvent hook can call the GC, so we need to update the ACC
128         GetAcc() = GetFrame()->GetAcc();
129     }
130 
InstrumentForceReturn()131     void InstrumentForceReturn()
132     {
133         interpreter::AccVRegister result;  // empty result, because force exit
134         GetAcc() = result;
135         GetFrame()->GetAcc() = result;
136     }
137 
GetAcc()138     ALWAYS_INLINE const AccVRegisterT &GetAcc() const
139     {
140         return state_->GetAcc();
141     }
142 
GetAcc()143     ALWAYS_INLINE AccVRegisterT &GetAcc()
144     {
145         return state_->GetAcc();
146     }
147 
148 #ifdef PANDA_ENABLE_GLOBAL_REGISTER_VARIABLES
149     template <bool is_dynamic_t = is_dynamic>
GetAccAsVReg()150     ALWAYS_INLINE AccVRegisterTRef<is_dynamic_t> GetAccAsVReg()
151     {
152         return AccVRegisterTRef<is_dynamic_t>(&state_->GetAcc());
153     }
154 #else
155     template <bool is_dynamic_t = is_dynamic>
GetAccAsVReg()156     ALWAYS_INLINE typename std::enable_if<is_dynamic_t, DynamicVRegisterRef>::type GetAccAsVReg()
157     {
158         return state_->GetAcc().template AsVRegRef<is_dynamic_t>();
159     }
160 
161     template <bool is_dynamic_t = is_dynamic>
GetAccAsVReg()162     ALWAYS_INLINE typename std::enable_if<!is_dynamic_t, StaticVRegisterRef>::type GetAccAsVReg()
163     {
164         return state_->GetAcc().template AsVRegRef<is_dynamic_t>();
165     }
166 #endif  // PANDA_ENABLE_GLOBAL_REGISTER_VARIABLES
167 
GetInst()168     ALWAYS_INLINE BytecodeInstruction GetInst() const
169     {
170         return state_->GetInst();
171     }
172 
173     void DebugDump();
174 
175     template <bool is_dynamic_t = is_dynamic>
GetFrameHandler()176     ALWAYS_INLINE typename std::enable_if<is_dynamic_t, DynamicFrameHandlerT>::type GetFrameHandler()
177     {
178         return DynamicFrameHandlerT(state_->GetFrame());
179     }
180 
181     template <bool is_dynamic_t = is_dynamic>
GetFrameHandler()182     ALWAYS_INLINE typename std::enable_if<!is_dynamic_t, StaticFrameHandlerT>::type GetFrameHandler()
183     {
184         return StaticFrameHandlerT(state_->GetFrame());
185     }
186 
187     template <bool is_dynamic_t = is_dynamic>
GetFrameHandler(Frame * frame)188     ALWAYS_INLINE typename std::enable_if<is_dynamic_t, DynamicFrameHandler>::type GetFrameHandler(Frame *frame)
189     {
190         return DynamicFrameHandler(frame);
191     }
192 
193     template <bool is_dynamic_t = is_dynamic>
GetFrameHandler(Frame * frame)194     ALWAYS_INLINE typename std::enable_if<!is_dynamic_t, StaticFrameHandler>::type GetFrameHandler(Frame *frame)
195     {
196         return StaticFrameHandler(frame);
197     }
198 
GetFrame()199     ALWAYS_INLINE Frame *GetFrame() const
200     {
201         return state_->GetFrame();
202     }
203 
SetFrame(Frame * frame)204     ALWAYS_INLINE void SetFrame(Frame *frame)
205     {
206         state_->SetFrame(frame);
207     }
208 
GetThread()209     ALWAYS_INLINE ManagedThread *GetThread() const
210     {
211         return state_->GetThread();
212     }
213 
214 protected:
215     template <BytecodeInstruction::Format format, bool can_throw>
MoveToNextInst()216     ALWAYS_INLINE void MoveToNextInst()
217     {
218         SetInst(GetInst().template GetNext<format>());
219 
220         if (can_throw) {
221             SetOpcodeExtension(0);
222         }
223     }
224 
225     template <bool can_throw>
JumpToInst(int32_t offset)226     ALWAYS_INLINE void JumpToInst(int32_t offset)
227     {
228         SetInst(GetInst().JumpTo(offset));
229 
230         if (can_throw) {
231             SetOpcodeExtension(0);
232         }
233     }
234 
235     template <bool can_throw>
JumpTo(const uint8_t * pc)236     ALWAYS_INLINE void JumpTo(const uint8_t *pc)
237     {
238         SetInst(BytecodeInstruction(pc));
239 
240         if (can_throw) {
241             SetOpcodeExtension(0);
242         }
243     }
244 
MoveToExceptionHandler()245     ALWAYS_INLINE void MoveToExceptionHandler()
246     {
247         SetOpcodeExtension(UINT8_MAX + NUM_PREFIXED + 1);
248         SetOpcodeExtension(GetOpcodeExtension() - GetPrimaryOpcode());
249     }
250 
SetThread(ManagedThread * thread)251     ALWAYS_INLINE void SetThread(ManagedThread *thread)
252     {
253         state_->SetThread(thread);
254     }
255 
SetInst(BytecodeInstruction inst)256     ALWAYS_INLINE void SetInst(BytecodeInstruction inst)
257     {
258         state_->SetInst(inst);
259     }
260 
GetDispatchTable()261     ALWAYS_INLINE const void *const *GetDispatchTable() const
262     {
263         return state_->GetDispatchTable();
264     }
265 
SetDispatchTable(const void * const * dispatch_table)266     ALWAYS_INLINE void SetDispatchTable(const void *const *dispatch_table)
267     {
268         return state_->SetDispatchTable(dispatch_table);
269     }
270 
SaveState()271     ALWAYS_INLINE void SaveState()
272     {
273         state_->SaveState();
274     }
275 
RestoreState()276     ALWAYS_INLINE void RestoreState()
277     {
278         state_->RestoreState();
279     }
280 
GetOpcodeExtension()281     ALWAYS_INLINE uint16_t GetOpcodeExtension() const
282     {
283         return state_->GetOpcodeExtension();
284     }
285 
SetOpcodeExtension(uint16_t opcode_extension)286     ALWAYS_INLINE void SetOpcodeExtension(uint16_t opcode_extension)
287     {
288         state_->SetOpcodeExtension(opcode_extension);
289     }
290 
GetFakeInstBuf()291     ALWAYS_INLINE auto &GetFakeInstBuf()
292     {
293         return state_->GetFakeInstBuf();
294     }
295 
UpdateHotness(Method * method)296     ALWAYS_INLINE void UpdateHotness(Method *method)
297     {
298         method->IncrementHotnessCounter(0, nullptr);
299     }
300 
GetBytecodeOffset()301     ALWAYS_INLINE uint32_t GetBytecodeOffset() const
302     {
303         return state_->GetBytecodeOffset();
304     }
305 
GetInstructionHandlerState()306     ALWAYS_INLINE InstructionHandlerState *GetInstructionHandlerState()
307     {
308         return state_;
309     }
310 
311     template <bool taken>
UpdateBranchStatistics()312     ALWAYS_INLINE void UpdateBranchStatistics()
313     {
314         ProfilingData *prof_data = this->GetFrame()->GetMethod()->GetProfilingDataWithoutCheck();
315         if (prof_data != nullptr) {
316             auto pc = this->GetBytecodeOffset();
317             if constexpr (taken) {
318                 prof_data->UpdateBranchTaken(pc);
319             } else {
320                 prof_data->UpdateBranchNotTaken(pc);
321             }
322         }
323     }
324 
325 private:
326     InstructionHandlerState *state_;
327 };
328 
329 }  // namespace panda::interpreter
330 
331 #endif  // PANDA_INTERPRETER_INSTRUCTION_HANDLER_BASE_H_
332