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