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