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#include <isa_constants_gen.h> 17#include "plugins_interpreters-inl.h" 18 19namespace panda::interpreter { 20 21template <class RuntimeIfaceT, bool jump_to_eh, bool is_dynamic> 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 35#define INSTRUMENT_FRAME() do { if (handler.GetFrame()->IsForcePop() || handler.GetFrame()->IsRetryInstruction()) { goto INSTRUMENT_FRAME_HANDLER; } } while (0) 36 37 ASSERT(!thread->IsCurrentFrameCompiled()); 38 39 if (!thread->template StackOverflowCheck<true, true>()) { 40 return; 41 } 42 43 EVENT_METHOD_ENTER(frame->GetMethod()->GetFullName(), events::MethodEnterKind::INTERP, thread->RecordMethodEnter()); 44 45#if EVENT_METHOD_EXIT_ENABLED 46 auto method_exit_event = [frame, thread](void* /* unused */) { 47 EVENT_METHOD_EXIT(frame->GetMethod()->GetFullName(), events::MethodExitKind::INTERP, thread->RecordMethodExit()); 48 }; 49 PandaUniquePtr<void, decltype(method_exit_event)> method_exit(&method_exit_event, method_exit_event); 50#endif 51 52 static constexpr uint32_t DISPATCH_TABLE_LEN = 256 + NUM_PREFIXED + 1; 53 54 static std::array<const void*, DISPATCH_TABLE_LEN> inst_dispatch_table { 55% Panda::dispatch_table.handler_names.each do |name| 56 &&HANDLE_<%= name %>, 57% end 58 &&EXCEPTION_HANDLER, 59 }; 60 61 static std::array<const void*, DISPATCH_TABLE_LEN> debug_dispatch_table { 62% Panda::dispatch_table.handler_names.each do |name| 63 &&DEBUG_HANDLE_<%= name %>, 64% end 65 &&DEBUG_EXCEPTION_HANDLER, 66 }; 67 68 auto *dispatch_table = inst_dispatch_table.data(); 69 if (UNLIKELY(Runtime::GetCurrent()->IsDebugMode())) { 70 dispatch_table = debug_dispatch_table.data(); 71 } 72 SetDispatchTable(dispatch_table); 73 thread->SetCurrentDispatchTable(dispatch_table); 74 thread->SetDebugDispatchTable(debug_dispatch_table.data()); 75 76 InstructionHandlerState state(thread, pc, frame); 77 if constexpr (jump_to_eh) { 78 goto* dispatch_table[DISPATCH_TABLE_LEN - 1]; 79 } 80 ASSERT(state.IsPrimaryOpcodeValid()); 81 82 const void *label; 83 DISPATCH(GetDispatchTable(dispatch_table), state.GetPrimaryOpcode(), label); 84 85% [[:nodebug, 'HANDLE_'], [:debug, 'DEBUG_HANDLE_']].each do |mode, prefix| 86% Panda::instructions.each do |i| 87% mnemonic = i.mnemonic.split('.').map { |p| p == '64' ? 'Wide' : p.capitalize }.join 88<%= prefix %><%= i.handler_name %>: { 89% namespace = i.namespace == 'core' ? '' : "#{i.namespace}::" 90% if i.namespace != 'core' 91#ifdef PANDA_WITH_<%= i.namespace.upcase %> 92% end 93 <%= namespace %>InstructionHandler<RuntimeIfaceT, is_dynamic> handler(&state); 94% if mode == :nodebug 95 handler.DumpVRegs(); 96 handler.template Handle<%= mnemonic %><BytecodeInstruction::Format::<%= i.format.pretty.upcase %>>(); 97% if i.properties.include?('return') 98 if (handler.GetFrame()->IsStackless()) { 99 handler.HandleReturnStackless(); 100 ASSERT(handler.IsPrimaryOpcodeValid() || (handler.GetExceptionOpcode() == UINT8_MAX + NUM_PREFIXED + 1)); 101 DISPATCH(GetDispatchTable(dispatch_table), handler.GetExceptionOpcode(), label); 102 } else { 103 return; 104 } 105% else 106% if !i.exceptions.include?('x_none') 107 ASSERT(handler.IsPrimaryOpcodeValid() || (handler.GetExceptionOpcode() == UINT8_MAX + NUM_PREFIXED + 1)); 108 DISPATCH(GetDispatchTable(dispatch_table), handler.GetExceptionOpcode(), label); 109% else 110 ASSERT(handler.IsPrimaryOpcodeValid()); 111 DISPATCH(GetDispatchTable(dispatch_table), handler.GetPrimaryOpcode(), label); 112% end 113% end 114% else 115 if (handler.GetFrame()->IsForcePop() || handler.GetFrame()->IsRetryInstruction()) { 116 goto INSTRUMENT_FRAME_HANDLER; 117 } 118 handler.InstrumentInstruction(); 119 handler.GetFrame()->GetAcc() = handler.GetAcc(); 120 goto HANDLE_<%= i.handler_name %>; 121% end 122% if i.namespace != 'core' 123#endif // PANDA_WITH_<%= i.namespace.upcase %> 124% end 125} 126% end 127<%= prefix %>INVALID: { 128 LOG(FATAL,INTERPRETER) << "Incorrect opcode"; 129} 130% Panda::prefixes.each do |p| 131<%= prefix %><%= p.handler_name %>: { 132 const auto secondary_opcode = state.GetSecondaryOpcode(); 133 134 LOG(DEBUG, INTERPRETER) << "Prefix subdispatch: " << "<%= p.name %>, " << static_cast<int32_t>(secondary_opcode); 135 136 ASSERT(secondary_opcode <= <%= Panda::dispatch_table.secondary_opcode_bound(p) %>); 137 const size_t dispatch_idx = <%= Panda::dispatch_table.secondary_opcode_offset(p) %> + secondary_opcode; 138 ASSERT(dispatch_idx < DISPATCH_TABLE_LEN); 139 DISPATCH(GetDispatchTable(dispatch_table), dispatch_idx, label); 140} 141% end 142 143% if mode == :debug 144DEBUG_EXCEPTION_HANDLER: { 145% else 146EXCEPTION_HANDLER: { 147% end 148 ASSERT(thread->HasPendingException()); 149 150 InstructionHandler<RuntimeIfaceT, is_dynamic> handler(&state); 151 uint32_t pc_offset = panda_file::INVALID_OFFSET; 152 153% if mode == :debug 154 RuntimeIfaceT::GetNotificationManager()->ExceptionThrowEvent(thread, handler.GetFrame()->GetMethod(), thread->GetException(), pc_offset); 155% end 156 pc_offset = handler.FindCatchBlockStackless(); 157 if (pc_offset == panda_file::INVALID_OFFSET) { 158 if constexpr (RUNTIME_ARCH == Arch::AARCH64 || RUNTIME_ARCH == Arch::AARCH32 || RUNTIME_ARCH == Arch::X86_64) { 159 return FindCatchBlockInCallStack(thread); 160 } else { 161 return; 162 } 163 } 164 165 auto *method = handler.GetFrame()->GetMethod(); 166 ASSERT(method != nullptr); 167 LanguageContext ctx = RuntimeIfaceT::GetLanguageContext(*method); 168 ObjectHeader *exception_object = thread->GetException(); 169 ctx.SetExceptionToVReg(handler.GetFrame()->GetAcc(), exception_object); 170 171 thread->ClearException(); 172% if mode == :debug 173 RuntimeIfaceT::GetNotificationManager()->ExceptionCatchEvent(thread, handler.GetFrame()->GetMethod(), exception_object, pc_offset); 174% end 175 176 Span<const uint8_t> sp(handler.GetFrame()->GetMethod()->GetInstructions(), pc_offset); 177 state = InstructionHandlerState(thread, sp.cend(), handler.GetFrame()); 178 179 ASSERT(state.IsPrimaryOpcodeValid()); 180 goto* dispatch_table[state.GetPrimaryOpcode()]; 181} 182% end 183 184INSTRUMENT_FRAME_HANDLER: { 185 InstructionHandler<RuntimeIfaceT, is_dynamic> handler(&state); 186 187 ASSERT(handler.GetFrame()->IsForcePop() || handler.GetFrame()->IsRetryInstruction()); 188 189 if (handler.GetFrame()->IsForcePop()) { 190 handler.GetFrame()->ClearForcePop(); 191 handler.InstrumentForceReturn(); 192 if (handler.GetFrame()->IsStackless()) { 193 handler.HandleInstrumentForceReturn(); 194 ASSERT(handler.IsPrimaryOpcodeValid()); 195 DISPATCH(GetDispatchTable(dispatch_table), handler.GetPrimaryOpcode(), label); 196 } else { 197 return; 198 } 199 } 200 201 handler.GetFrame()->ClearRetryInstruction(); 202 auto* method = handler.GetFrame()->GetMethod(); 203 state = InstructionHandlerState(thread, method->GetInstructions() + handler.GetFrame()->GetBytecodeOffset(), handler.GetFrame()); 204 ASSERT(state.IsPrimaryOpcodeValid()); 205 goto* dispatch_table[state.GetPrimaryOpcode()]; 206} 207 208#if defined(__clang__) 209#pragma clang diagnostic pop 210#elif defined(__GNUC__) 211#pragma GCC diagnostic pop 212#endif 213} 214 215} // namespace panda::interpreter 216