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_INCLUDE_INTERPRETER_INL_GEN_H_ 17#define PANDA_RUNTIME_INCLUDE_INTERPRETER_INL_GEN_H_ 18 19#include <isa_constants_gen.h> 20 21template <class RuntimeIfaceT, bool enable_instrumentation, bool jump_to_eh> 22// NOLINTNEXTLINE(readability-function-size) 23void ExecuteImpl(ManagedThread* thread, const uint8_t *pc, Frame* frame) { 24#if defined(__clang__) 25#pragma clang diagnostic push 26#pragma clang diagnostic ignored "-Wvoid-ptr-dereference" 27#pragma clang diagnostic ignored "-Wgnu-label-as-value" 28#pragma clang diagnostic ignored "-Wtautological-constant-out-of-range-compare" 29#elif defined(__GNUC__) 30#pragma GCC diagnostic push 31#pragma GCC diagnostic ignored "-Wpedantic" 32#endif 33 34#define INSTRUMENT_FRAME() do { if (enable_instrumentation && (handler.GetFrame()->IsForcePop() || handler.GetFrame()->IsRetryInstruction())) { goto INSTRUMENT_FRAME_HANDLER; } } while (0) 35 36 ASSERT(!thread->IsCurrentFrameCompiled()); 37 38 EVENT_METHOD_ENTER(frame->GetMethod()->GetFullName(), events::MethodEnterKind::INTERP, thread->RecordMethodEnter()); 39 40#if EVENT_METHOD_EXIT_ENABLED 41 auto method_exit_event = [frame, thread](void* /* unused */) { 42 EVENT_METHOD_EXIT(frame->GetMethod()->GetFullName(), events::MethodExitKind::INTERP, thread->RecordMethodExit()); 43 }; 44 PandaUniquePtr<void, decltype(method_exit_event)> method_exit(&method_exit_event, method_exit_event); 45#endif 46 47 static std::array<const void*, 256 + NUM_PREFIXED + 1> dispatch_table{ 48% Panda::dispatch_table.handler_names.each do |name| 49 &&HANDLE_<%= name %>, 50% end 51 &&EXCEPTION_HANDLER, 52 }; 53 54 SetDispatchTable(dispatch_table); 55 56 InstructionHandlerState state(thread, pc, frame); 57 if constexpr (jump_to_eh) { 58 goto EXCEPTION_HANDLER; 59 } 60 ASSERT(state.IsPrimaryOpcodeValid()); 61 62 const void *label; 63 DISPATCH(GetDispatchTable(dispatch_table), state.GetPrimaryOpcode(), label); 64 65% Panda::instructions.each do |i| 66% mnemonic = i.mnemonic.split('.').map { |p| p == '64' ? 'Wide' : p.capitalize }.join 67HANDLE_<%= i.handler_name %>: { 68% namespace = i.namespace == 'core' ? '' : "#{i.namespace}::" 69% if i.namespace != 'core' 70#ifdef PANDA_WITH_<%= i.namespace.upcase %> 71% end 72 <%= namespace %>InstructionHandler<RuntimeIfaceT, enable_instrumentation> handler(&state); 73 INSTRUMENT_FRAME(); 74 handler.DumpVRegs(); 75 handler.InstrumentInstruction(); 76 handler.template Handle<%= mnemonic %><BytecodeInstruction::Format::<%= i.format.pretty.upcase %>>(); 77 if (enable_instrumentation) { 78 handler.GetFrame()->GetAcc() = handler.GetAcc(); 79 } 80% if i.properties.include?('return') 81 if (handler.GetFrame()->IsStackless()) { 82 handler.HandleReturnStackless(); 83 ASSERT(handler.IsPrimaryOpcodeValid() || (handler.GetExceptionOpcode() == UINT8_MAX + NUM_PREFIXED + 1)); 84 DISPATCH(GetDispatchTable(dispatch_table), handler.GetExceptionOpcode(), label); 85 } else { 86 return; 87 } 88% else 89% if !i.exceptions.include?('x_none') || i.properties.include?("call") || ['ststatic', 'ldstatic', 'throw', 'lda'].include?(i.stripped_mnemonic) 90 ASSERT(handler.IsPrimaryOpcodeValid() || (handler.GetExceptionOpcode() == UINT8_MAX + NUM_PREFIXED + 1)); 91 DISPATCH(GetDispatchTable(dispatch_table), handler.GetExceptionOpcode(), label); 92% else 93 ASSERT(handler.IsPrimaryOpcodeValid()); 94 DISPATCH(GetDispatchTable(dispatch_table), handler.GetPrimaryOpcode(), label); 95% end 96% end 97% if i.namespace != 'core' 98#endif // PANDA_WITH_<%= i.namespace.upcase %> 99% end 100} 101% end 102HANDLE_INVALID: { 103 LOG(FATAL,INTERPRETER) << "Incorrect opcode"; 104} 105% Panda::prefixes.each do |p| 106HANDLE_<%= p.handler_name %>: { 107 const auto secondary_opcode = state.GetSecondaryOpcode(); 108 109 LOG(DEBUG, INTERPRETER) << "Prefix subdispatch: " << "<%= p.name %>, " << secondary_opcode; 110 111 ASSERT(secondary_opcode <= <%= Panda::dispatch_table.secondary_opcode_bound(p) %>); 112 const size_t dispatch_idx = <%= Panda::dispatch_table.secondary_opcode_offset(p) %> + secondary_opcode; 113 ASSERT(dispatch_idx < dispatch_table.size()); 114 DISPATCH(GetDispatchTable(dispatch_table), dispatch_idx, label); 115} 116% end 117 118INSTRUMENT_FRAME_HANDLER: { 119 InstructionHandler<RuntimeIfaceT, enable_instrumentation> handler(&state); 120 121 ASSERT(handler.GetFrame()->IsForcePop() || handler.GetFrame()->IsRetryInstruction()); 122 123 if (handler.GetFrame()->IsForcePop()) { 124 handler.GetFrame()->ClearForcePop(); 125 handler.InstrumentForceReturn(); 126 if (handler.GetFrame()->IsStackless()) { 127 handler.HandleInstrumentForceReturn(); 128 ASSERT(handler.IsPrimaryOpcodeValid()); 129 DISPATCH(GetDispatchTable(dispatch_table), handler.GetPrimaryOpcode(), label); 130 } else { 131 return; 132 } 133 } 134 135 handler.GetFrame()->ClearRetryInstruction(); 136 auto* method = handler.GetFrame()->GetMethod(); 137 state = InstructionHandlerState(thread, method->GetInstructions() + handler.GetFrame()->GetBytecodeOffset(), handler.GetFrame()); 138 ASSERT(state.IsPrimaryOpcodeValid()); 139 goto* dispatch_table[state.GetPrimaryOpcode()]; 140} 141 142EXCEPTION_HANDLER: { 143 ASSERT(thread->HasPendingException()); 144 145 InstructionHandler<RuntimeIfaceT, enable_instrumentation> handler(&state); 146 147 uint32_t pc_offset = panda_file::INVALID_OFFSET; 148 pc_offset = handler.FindCatchBlockStackless(); 149 150 if (pc_offset == panda_file::INVALID_OFFSET) { 151 if constexpr (RUNTIME_ARCH == Arch::AARCH64 || RUNTIME_ARCH == Arch::AARCH32 || RUNTIME_ARCH == Arch::X86_64) { 152 return FindCatchBlockInCallStack(thread->GetException()); 153 } else { 154 return; 155 } 156 } 157 158 auto *method = handler.GetFrame()->GetMethod(); 159 ASSERT(method != nullptr); 160 LanguageContext ctx = RuntimeIfaceT::GetLanguageContext(*method); 161 ctx.SetExceptionToVReg(handler.GetFrame()->GetAcc(), thread->GetException()); 162 163 thread->ClearException(); 164 if (enable_instrumentation) { 165 RuntimeIfaceT::GetNotificationManager()->ExceptionCatchEvent(thread, handler.GetFrame()->GetMethod(), pc_offset); 166 } 167 168 Span<const uint8_t> sp(handler.GetFrame()->GetMethod()->GetInstructions(), pc_offset); 169 state = InstructionHandlerState(thread, sp.cend(), handler.GetFrame()); 170 171 ASSERT(state.IsPrimaryOpcodeValid()); 172 goto* dispatch_table[state.GetPrimaryOpcode()]; 173} 174 175#if defined(__clang__) 176#pragma clang diagnostic pop 177#elif defined(__GNUC__) 178#pragma GCC diagnostic pop 179#endif 180} 181 182#endif // PANDA_RUNTIME_INCLUDE_INTERPRETER_INL_GEN_H_ 183