/* * Copyright (c) 2021-2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include "plugins_interpreters-inl.h" namespace panda::interpreter { template // NOLINTNEXTLINE(readability-function-size) void ExecuteImpl(ManagedThread *thread, const uint8_t *pc, Frame *frame) { #if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wvoid-ptr-dereference" #pragma clang diagnostic ignored "-Wgnu-label-as-value" #pragma clang diagnostic ignored "-Wtautological-constant-out-of-range-compare" #elif defined(__GNUC__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpedantic" #endif #define INSTRUMENT_FRAME() do { if (handler.GetFrame()->IsForcePop() || handler.GetFrame()->IsRetryInstruction()) { goto INSTRUMENT_FRAME_HANDLER; } } while (0) ASSERT(!thread->IsCurrentFrameCompiled()); if (!thread->template StackOverflowCheck()) { return; } EVENT_METHOD_ENTER(frame->GetMethod()->GetFullName(), events::MethodEnterKind::INTERP, thread->RecordMethodEnter()); #if EVENT_METHOD_EXIT_ENABLED auto method_exit_event = [frame, thread](void* /* unused */) { EVENT_METHOD_EXIT(frame->GetMethod()->GetFullName(), events::MethodExitKind::INTERP, thread->RecordMethodExit()); }; PandaUniquePtr method_exit(&method_exit_event, method_exit_event); #endif static constexpr uint32_t DISPATCH_TABLE_LEN = 256 + NUM_PREFIXED + 1; static std::array inst_dispatch_table { % Panda::dispatch_table.handler_names.each do |name| &&HANDLE_<%= name %>, % end &&EXCEPTION_HANDLER, }; static std::array debug_dispatch_table { % Panda::dispatch_table.handler_names.each do |name| &&DEBUG_HANDLE_<%= name %>, % end &&DEBUG_EXCEPTION_HANDLER, }; auto *dispatch_table = inst_dispatch_table.data(); if (UNLIKELY(Runtime::GetCurrent()->IsDebugMode())) { dispatch_table = debug_dispatch_table.data(); } SetDispatchTable(dispatch_table); thread->SetCurrentDispatchTable(dispatch_table); thread->SetDebugDispatchTable(debug_dispatch_table.data()); InstructionHandlerState state(thread, pc, frame); if constexpr (jump_to_eh) { goto* dispatch_table[DISPATCH_TABLE_LEN - 1]; } ASSERT(state.IsPrimaryOpcodeValid()); const void *label; DISPATCH(GetDispatchTable(dispatch_table), state.GetPrimaryOpcode(), label); % [[:nodebug, 'HANDLE_'], [:debug, 'DEBUG_HANDLE_']].each do |mode, prefix| % Panda::instructions.each do |i| % mnemonic = i.mnemonic.split('.').map { |p| p == '64' ? 'Wide' : p.capitalize }.join <%= prefix %><%= i.handler_name %>: { % namespace = i.namespace == 'core' ? '' : "#{i.namespace}::" % if i.namespace != 'core' #ifdef PANDA_WITH_<%= i.namespace.upcase %> % end <%= namespace %>InstructionHandler handler(&state); % if mode == :nodebug handler.DumpVRegs(); handler.template Handle<%= mnemonic %>>(); % if i.properties.include?('return') if (handler.GetFrame()->IsStackless()) { handler.HandleReturnStackless(); ASSERT(handler.IsPrimaryOpcodeValid() || (handler.GetExceptionOpcode() == UINT8_MAX + NUM_PREFIXED + 1)); DISPATCH(GetDispatchTable(dispatch_table), handler.GetExceptionOpcode(), label); } else { return; } % else % if !i.exceptions.include?('x_none') ASSERT(handler.IsPrimaryOpcodeValid() || (handler.GetExceptionOpcode() == UINT8_MAX + NUM_PREFIXED + 1)); DISPATCH(GetDispatchTable(dispatch_table), handler.GetExceptionOpcode(), label); % else ASSERT(handler.IsPrimaryOpcodeValid()); DISPATCH(GetDispatchTable(dispatch_table), handler.GetPrimaryOpcode(), label); % end % end % else if (handler.GetFrame()->IsForcePop() || handler.GetFrame()->IsRetryInstruction()) { goto INSTRUMENT_FRAME_HANDLER; } handler.InstrumentInstruction(); handler.GetFrame()->GetAcc() = handler.GetAcc(); goto HANDLE_<%= i.handler_name %>; % end % if i.namespace != 'core' #endif // PANDA_WITH_<%= i.namespace.upcase %> % end } % end <%= prefix %>INVALID: { LOG(FATAL,INTERPRETER) << "Incorrect opcode"; } % Panda::prefixes.each do |p| <%= prefix %><%= p.handler_name %>: { const auto secondary_opcode = state.GetSecondaryOpcode(); LOG(DEBUG, INTERPRETER) << "Prefix subdispatch: " << "<%= p.name %>, " << static_cast(secondary_opcode); ASSERT(secondary_opcode <= <%= Panda::dispatch_table.secondary_opcode_bound(p) %>); const size_t dispatch_idx = <%= Panda::dispatch_table.secondary_opcode_offset(p) %> + secondary_opcode; ASSERT(dispatch_idx < DISPATCH_TABLE_LEN); DISPATCH(GetDispatchTable(dispatch_table), dispatch_idx, label); } % end % if mode == :debug DEBUG_EXCEPTION_HANDLER: { % else EXCEPTION_HANDLER: { % end ASSERT(thread->HasPendingException()); InstructionHandler handler(&state); uint32_t pc_offset = panda_file::INVALID_OFFSET; % if mode == :debug RuntimeIfaceT::GetNotificationManager()->ExceptionThrowEvent(thread, handler.GetFrame()->GetMethod(), thread->GetException(), pc_offset); % end pc_offset = handler.FindCatchBlockStackless(); if (pc_offset == panda_file::INVALID_OFFSET) { if constexpr (RUNTIME_ARCH == Arch::AARCH64 || RUNTIME_ARCH == Arch::AARCH32 || RUNTIME_ARCH == Arch::X86_64) { return FindCatchBlockInCallStack(thread); } else { return; } } auto *method = handler.GetFrame()->GetMethod(); ASSERT(method != nullptr); LanguageContext ctx = RuntimeIfaceT::GetLanguageContext(*method); ObjectHeader *exception_object = thread->GetException(); ctx.SetExceptionToVReg(handler.GetFrame()->GetAcc(), exception_object); thread->ClearException(); % if mode == :debug RuntimeIfaceT::GetNotificationManager()->ExceptionCatchEvent(thread, handler.GetFrame()->GetMethod(), exception_object, pc_offset); % end Span sp(handler.GetFrame()->GetMethod()->GetInstructions(), pc_offset); state = InstructionHandlerState(thread, sp.cend(), handler.GetFrame()); ASSERT(state.IsPrimaryOpcodeValid()); goto* dispatch_table[state.GetPrimaryOpcode()]; } % end INSTRUMENT_FRAME_HANDLER: { InstructionHandler handler(&state); ASSERT(handler.GetFrame()->IsForcePop() || handler.GetFrame()->IsRetryInstruction()); if (handler.GetFrame()->IsForcePop()) { handler.GetFrame()->ClearForcePop(); handler.InstrumentForceReturn(); if (handler.GetFrame()->IsStackless()) { handler.HandleInstrumentForceReturn(); ASSERT(handler.IsPrimaryOpcodeValid()); DISPATCH(GetDispatchTable(dispatch_table), handler.GetPrimaryOpcode(), label); } else { return; } } handler.GetFrame()->ClearRetryInstruction(); auto* method = handler.GetFrame()->GetMethod(); state = InstructionHandlerState(thread, method->GetInstructions() + handler.GetFrame()->GetBytecodeOffset(), handler.GetFrame()); ASSERT(state.IsPrimaryOpcodeValid()); goto* dispatch_table[state.GetPrimaryOpcode()]; } #if defined(__clang__) #pragma clang diagnostic pop #elif defined(__GNUC__) #pragma GCC diagnostic pop #endif } } // namespace panda::interpreter