• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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