• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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_RUNTIME_INTERPRETER_INSTRUCTION_HANDLER_BASE_H_
17 #define PANDA_RUNTIME_INTERPRETER_INSTRUCTION_HANDLER_BASE_H_
18 
19 #include <isa_constants_gen.h>
20 #include "runtime/interpreter/instruction_handler_state.h"
21 
22 namespace panda::interpreter {
23 
24 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
25 #define LOG_INST()                                                                           \
26     LOG(DEBUG, INTERPRETER) << std::hex << std::setw(sizeof(uintptr_t)) << std::setfill('0') \
27                             << reinterpret_cast<uintptr_t>(this->GetInst().GetAddress()) << std::dec << ": "
28 
29 template <class RuntimeIfaceT, bool enable_instrumentation>
30 class InstructionHandlerBase {
31 public:
InstructionHandlerBase(InstructionHandlerState * state)32     ALWAYS_INLINE InstructionHandlerBase(InstructionHandlerState *state) : state_(state) {}
33     ~InstructionHandlerBase() = default;
34     DEFAULT_MOVE_SEMANTIC(InstructionHandlerBase);
35     DEFAULT_COPY_SEMANTIC(InstructionHandlerBase);
36 
GetExceptionOpcode()37     ALWAYS_INLINE uint16_t GetExceptionOpcode() const
38     {
39         // Need to call GetInst().GetOpcode() in this case too, otherwise compiler can generate non optimal code
40         return (static_cast<unsigned>(GetInst().GetOpcode()) & 0xff) + state_->GetOpcodeExtension();
41     }
42 
GetPrimaryOpcode()43     ALWAYS_INLINE uint8_t GetPrimaryOpcode() const
44     {
45         return static_cast<unsigned>(GetInst().GetOpcode()) & 0xff;
46     }
47 
GetSecondaryOpcode()48     ALWAYS_INLINE uint8_t GetSecondaryOpcode() const
49     {
50         return (static_cast<unsigned>(GetInst().GetOpcode()) >> 8) & 0xff;
51     }
52 
IsPrimaryOpcodeValid()53     ALWAYS_INLINE bool IsPrimaryOpcodeValid() const
54     {
55         return GetInst().IsPrimaryOpcodeValid();
56     }
57 
DumpVRegs()58     void DumpVRegs()
59     {
60 #ifndef NDEBUG
61         static constexpr uint64_t STANDARD_DEBUG_INDENT = 5;
62         LOG(DEBUG, INTERPRETER) << PandaString(STANDARD_DEBUG_INDENT, ' ') << "acc." << GetAcc().DumpVReg();
63         for (size_t i = 0; i < GetFrame()->GetSize(); ++i) {
64             LOG(DEBUG, INTERPRETER) << PandaString(STANDARD_DEBUG_INDENT, ' ') << "v" << i << "."
65                                     << GetFrame()->GetVReg(i).DumpVReg();
66         }
67 #endif
68     }
69 
UpdateBytecodeOffset()70     ALWAYS_INLINE uint32_t UpdateBytecodeOffset()
71     {
72         auto pc = GetBytecodeOffset();
73         GetFrame()->SetBytecodeOffset(pc);
74         return pc;
75     }
76 
InstrumentInstruction()77     void InstrumentInstruction()
78     {
79         if (!enable_instrumentation) {
80             return;
81         }
82 
83         // Should set ACC to Frame, so that ACC will be marked when GC
84         GetFrame()->SetAcc(GetAcc());
85 
86         auto pc = UpdateBytecodeOffset();
87         RuntimeIfaceT::GetNotificationManager()->BytecodePcChangedEvent(GetThread(), GetFrame()->GetMethod(), pc);
88 
89         // BytecodePcChangedEvent hook can call the GC, so we need to update the ACC
90         GetAcc() = GetFrame()->GetAcc();
91     }
92 
InstrumentForceReturn()93     void InstrumentForceReturn()
94     {
95         Frame::VRegister result;  // empty result, because forced exit
96         GetAcc() = result;
97         GetFrame()->GetAcc() = result;
98     }
99 
GetAcc()100     ALWAYS_INLINE const AccVRegister &GetAcc() const
101     {
102         return state_->GetAcc();
103     }
104 
GetAcc()105     ALWAYS_INLINE AccVRegister &GetAcc()
106     {
107         return state_->GetAcc();
108     }
109 
GetInst()110     ALWAYS_INLINE BytecodeInstruction GetInst() const
111     {
112         return state_->GetInst();
113     }
114 
115     void DebugDump();
116 
GetFrame()117     ALWAYS_INLINE Frame *GetFrame() const
118     {
119         return state_->GetFrame();
120     }
121 
SetFrame(Frame * frame)122     ALWAYS_INLINE void SetFrame(Frame *frame)
123     {
124         state_->SetFrame(frame);
125     }
126 
127 protected:
128     template <BytecodeInstruction::Format format, bool can_throw>
MoveToNextInst()129     ALWAYS_INLINE void MoveToNextInst()
130     {
131         SetInst(GetInst().template GetNext<format>());
132 
133         if (can_throw) {
134             SetOpcodeExtension(0);
135         }
136     }
137 
138     template <bool can_throw>
JumpToInst(int32_t offset)139     ALWAYS_INLINE void JumpToInst(int32_t offset)
140     {
141         SetInst(GetInst().JumpTo(offset));
142 
143         if (can_throw) {
144             SetOpcodeExtension(0);
145         }
146     }
147 
148     template <bool can_throw>
JumpTo(const uint8_t * pc)149     ALWAYS_INLINE void JumpTo(const uint8_t *pc)
150     {
151         SetInst(BytecodeInstruction(pc));
152 
153         if (can_throw) {
154             SetOpcodeExtension(0);
155         }
156     }
157 
MoveToExceptionHandler()158     ALWAYS_INLINE void MoveToExceptionHandler()
159     {
160         SetOpcodeExtension(UINT8_MAX + NUM_PREFIXED + 1);
161         SetOpcodeExtension(GetOpcodeExtension() - GetPrimaryOpcode());
162     }
163 
GetThread()164     ALWAYS_INLINE ManagedThread *GetThread() const
165     {
166         return state_->GetThread();
167     }
168 
SetThread(ManagedThread * thread)169     ALWAYS_INLINE void SetThread(ManagedThread *thread)
170     {
171         state_->SetThread(thread);
172     }
173 
SetInst(BytecodeInstruction inst)174     ALWAYS_INLINE void SetInst(BytecodeInstruction inst)
175     {
176         state_->SetInst(inst);
177     }
178 
GetDispatchTable()179     ALWAYS_INLINE const void *const *GetDispatchTable() const
180     {
181         return state_->GetDispatchTable();
182     }
183 
SetDispatchTable(const void * const * dispatch_table)184     ALWAYS_INLINE void SetDispatchTable(const void *const *dispatch_table)
185     {
186         return state_->SetDispatchTable(dispatch_table);
187     }
188 
SaveState()189     ALWAYS_INLINE void SaveState()
190     {
191         state_->SaveState();
192     }
193 
RestoreState()194     ALWAYS_INLINE void RestoreState()
195     {
196         state_->RestoreState();
197     }
198 
GetOpcodeExtension()199     ALWAYS_INLINE uint16_t GetOpcodeExtension() const
200     {
201         return state_->GetOpcodeExtension();
202     }
203 
SetOpcodeExtension(uint16_t opcode_extension)204     ALWAYS_INLINE void SetOpcodeExtension(uint16_t opcode_extension)
205     {
206         state_->SetOpcodeExtension(opcode_extension);
207     }
208 
GetFakeInstBuf()209     ALWAYS_INLINE auto &GetFakeInstBuf()
210     {
211         return state_->GetFakeInstBuf();
212     }
213 
UpdateHotness(Method * method)214     ALWAYS_INLINE void UpdateHotness(Method *method)
215     {
216         method->IncrementHotnessCounter(0, nullptr);
217     }
218 
GetBytecodeOffset()219     ALWAYS_INLINE uint32_t GetBytecodeOffset() const
220     {
221         return state_->GetBytecodeOffset();
222     }
223 
GetInstructionHandlerState()224     ALWAYS_INLINE InstructionHandlerState *GetInstructionHandlerState()
225     {
226         return state_;
227     }
228 
229 private:
230     InstructionHandlerState *state_;
231 };
232 
233 }  // namespace panda::interpreter
234 
235 #endif  // PANDA_RUNTIME_INTERPRETER_INSTRUCTION_HANDLER_BASE_H_
236