• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2021-2024 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 ark::interpreter {
20
21// NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic,cppcoreguidelines-avoid-goto, hicpp-no-assembler)
22
23% [[:nodebug, 'HANDLE_'], [:debug, 'DEBUG_HANDLE_']].each do |mode, prefix|
24template <class RuntimeIfaceT, bool IS_DYNAMIC, bool IS_PROFILE_ENABLED>
25// NOLINTNEXTLINE(readability-function-size)
26% if mode == :debug
27void ExecuteImplDebug(ManagedThread *thread, const uint8_t *pc, Frame *frame, bool jumpToEh) {
28% else
29void ExecuteImpl(ManagedThread *thread, const uint8_t *pc, Frame *frame, bool jumpToEh) {
30    if (UNLIKELY(Runtime::GetCurrent()->IsDebugMode())) {
31        ExecuteImplDebug<RuntimeIfaceT, IS_DYNAMIC>(thread, pc, frame, jumpToEh);
32        return;
33    }
34% end
35#if defined(__clang__)
36#pragma clang diagnostic push
37#pragma clang diagnostic ignored "-Wvoid-ptr-dereference"
38#pragma clang diagnostic ignored "-Wgnu-label-as-value"
39#pragma clang diagnostic ignored "-Wtautological-constant-out-of-range-compare"
40#elif defined(__GNUC__)
41#pragma GCC diagnostic push
42#pragma GCC diagnostic ignored "-Wpedantic"
43#endif
44
45% if mode == :debug
46// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
47#define INSTRUMENT_FRAME() do { if (handler.GetFrame()->IsForcePop() || handler.GetFrame()->IsRetryInstruction()) { goto INSTRUMENT_FRAME_HANDLER; } } while (0)
48% end
49
50    ASSERT(!thread->IsCurrentFrameCompiled());
51
52    if (!thread->template StackOverflowCheck<true, true>()) {
53        return;
54    }
55
56    EVENT_METHOD_ENTER(frame->GetMethod()->GetFullName(), events::MethodEnterKind::INTERP, thread->RecordMethodEnter());
57
58#if EVENT_METHOD_EXIT_ENABLED
59    auto method_exit_event = [frame, thread](void* /* unused */) {
60        EVENT_METHOD_EXIT(frame->GetMethod()->GetFullName(), events::MethodExitKind::INTERP, thread->RecordMethodExit());
61    };
62    PandaUniquePtr<void, decltype(method_exit_event)> method_exit(&method_exit_event, method_exit_event);
63#endif
64
65    static constexpr uint32_t DISPATCH_TABLE_LEN = 256 + NUM_PREFIXED + 1;
66
67#if PANDA_WITH_QUICKENER
68% Panda.quickened_plugins.each_key do |namespace|
69%   if mode == :nodebug
70    static std::array<const void*, DISPATCH_TABLE_LEN> quick_<%= namespace %>_inst_dispatch_table {
71%     Quick::select[namespace].each do |ins|
72        &&HANDLE_<%= ins.handler_name %>,
73%     end
74%     n = Panda::dispatch_table.handler_names.size - Quick::select[namespace].size
75%   (0..n-1).each do ||
76        &&HANDLE_INVALID,
77%     end
78        &&EXCEPTION_HANDLER,
79    };
80
81    static std::array<const void*, DISPATCH_TABLE_LEN> quick_<%= namespace %>_debug_dispatch_table {
82%     Quick::select[namespace].each do |ins|
83        &&HANDLE_DEBUG_SWITCH,
84%     end
85        &&EXCEPTION_HANDLER,
86    };
87%   else
88    static std::array<const void*, DISPATCH_TABLE_LEN> quick_<%= namespace %>_inst_dispatch_table {
89%     Quick::select[namespace].each do |ins|
90        &&DEBUG_HANDLE_<%= ins.handler_name %>,
91%     end
92        &&DEBUG_EXCEPTION_HANDLER,
93    };
94%   end
95% end
96#endif
97
98% if mode == :nodebug
99    static std::array<const void*, DISPATCH_TABLE_LEN> instDispatchTable {
100%   Panda::dispatch_table.handler_names.each do |name|
101        &&HANDLE_<%= name %>,
102%   end
103        &&EXCEPTION_HANDLER,
104    };
105
106    static std::array<const void*, DISPATCH_TABLE_LEN> debugDispatchTable {
107%   Panda::dispatch_table.handler_names.each do ||
108        &&HANDLE_DEBUG_SWITCH,
109%   end
110        &&EXCEPTION_HANDLER,
111    };
112
113% else
114    static std::array<const void*, DISPATCH_TABLE_LEN> instDispatchTable {
115%   Panda::dispatch_table.handler_names.each do |name|
116        &&DEBUG_HANDLE_<%= name %>,
117%   end
118        &&DEBUG_EXCEPTION_HANDLER,
119    };
120% end
121
122    constexpr bool IS_DEBUG = <%= mode == :debug %>;
123
124    if (frame->GetMethod()->GetPandaFile()->GetHeader()->quickenedFlag) {
125        switch (frame->GetMethod()->GetClass()->GetSourceLang()) {
126#if PANDA_WITH_QUICKENER
127% Panda.quickened_plugins.each_key do |namespace|
128            case panda_file::SourceLang::<%= namespace.upcase %>:
129                thread->SetCurrentDispatchTable<IS_DEBUG>(quick_<%= namespace %>_inst_dispatch_table.data());
130% if mode == :debug
131                thread->SetDebugDispatchTable(quick_<%= namespace %>_inst_dispatch_table.data());
132% else
133                thread->SetDebugDispatchTable(quick_<%= namespace %>_debug_dispatch_table.data());
134% end
135                break;
136% end
137#endif
138            default:
139                thread->SetCurrentDispatchTable<IS_DEBUG>(instDispatchTable.data());
140% if mode == :debug
141                thread->SetDebugDispatchTable(instDispatchTable.data());
142% else
143                thread->SetDebugDispatchTable(debugDispatchTable.data());
144% end
145                break;
146        }
147    } else {
148        thread->SetCurrentDispatchTable<IS_DEBUG>(instDispatchTable.data());
149% if mode == :debug
150        thread->SetDebugDispatchTable(instDispatchTable.data());
151% else
152        thread->SetDebugDispatchTable(debugDispatchTable.data());
153% end
154    }
155
156    InstructionHandlerState state(thread, pc, frame, thread->GetCurrentDispatchTable<IS_DEBUG>());
157    if (jumpToEh) {
158        goto* state.GetDispatchTable()[DISPATCH_TABLE_LEN - 1];
159    }
160    ASSERT(frame->GetMethod()->GetPandaFile()->GetHeader()->quickenedFlag || state.IsPrimaryOpcodeValid());
161
162    DISPATCH(state.GetDispatchTable(), state.GetPrimaryOpcode());
163
164% Panda::instructions.each do |i|
165%   mnemonic = i.mnemonic.split('.').map { |p| p == '64' ? 'Wide' : p.capitalize }.join
166<%= prefix %><%= i.handler_name %>: {
167%   namespace = i.namespace == 'core' ? '' : "#{i.namespace}::"
168%   if i.namespace != 'core'
169#ifdef PANDA_WITH_<%= i.namespace.upcase %>
170%   end
171    <%= namespace %>InstructionHandler<RuntimeIfaceT, IS_DYNAMIC, IS_DEBUG, IS_PROFILE_ENABLED> handler(&state);
172%   if mode == :debug
173    if (handler.GetFrame()->IsForcePop() || handler.GetFrame()->IsRetryInstruction()) {
174        goto INSTRUMENT_FRAME_HANDLER;
175    }
176    handler.InstrumentInstruction();
177    if (handler.GetFrame()->IsForcePop() || handler.GetFrame()->IsRetryInstruction()) {
178        goto INSTRUMENT_FRAME_HANDLER;
179    }
180    handler.GetFrame()->GetAcc() = handler.GetAcc();
181%   end
182    handler.DumpVRegs();
183    handler.template Handle<%= mnemonic %><BytecodeInstruction::Format::<%= i.format.pretty.upcase %>>();
184%   if i.properties.include?('return')
185    if (handler.GetFrame()->IsStackless()) {
186        handler.HandleReturnStackless();
187        ASSERT(frame->GetMethod()->GetPandaFile()->GetHeader()->quickenedFlag
188               || handler.IsPrimaryOpcodeValid() || (handler.GetExceptionOpcode() == UINT8_MAX + NUM_PREFIXED + 1));
189        DISPATCH(state.GetDispatchTable(), handler.GetExceptionOpcode());
190    } else {
191        return;
192    }
193%   else
194%     if !i.exceptions.include?('x_none')
195    ASSERT(frame->GetMethod()->GetPandaFile()->GetHeader()->quickenedFlag
196           || handler.IsPrimaryOpcodeValid() || (handler.GetExceptionOpcode() == UINT8_MAX + NUM_PREFIXED + 1));
197    DISPATCH(state.GetDispatchTable(), handler.GetExceptionOpcode());
198%     else
199    ASSERT(frame->GetMethod()->GetPandaFile()->GetHeader()->quickenedFlag
200           || handler.IsPrimaryOpcodeValid());
201    DISPATCH(state.GetDispatchTable(), handler.GetPrimaryOpcode());
202%     end
203%   end
204%   if i.namespace != 'core'
205#endif // PANDA_WITH_<%= i.namespace.upcase %>
206%   end
207}
208% end
209<%= prefix %>INVALID: {
210    LOG(FATAL,INTERPRETER) << "Incorrect opcode";
211}
212% Panda::prefixes.each do |p|
213<%= prefix %><%= p.handler_name %>: {
214    const auto secondaryOpcode = state.GetSecondaryOpcode();
215
216    LOG(DEBUG, INTERPRETER) << "Prefix subdispatch: " << "<%= p.name %>, " << static_cast<int32_t>(secondaryOpcode);
217
218    ASSERT(secondaryOpcode <= <%= Panda::dispatch_table.secondary_opcode_bound(p) %>);
219    const size_t dispatchIdx = <%= Panda::dispatch_table.secondary_opcode_offset(p) %> + secondaryOpcode;
220    ASSERT(dispatchIdx < DISPATCH_TABLE_LEN);
221    DISPATCH(state.GetDispatchTable(), dispatchIdx);
222}
223% end
224
225% # quickened handlers
226#if PANDA_WITH_QUICKENER
227% Panda.quickened_plugins.each_key do |namespace|
228% Quick.select[namespace].select { |instr| instr.namespace == namespace }.each do |i|
229%   mnemonic = i.mnemonic.split('.').map { |p| p == '64' ? 'Wide' : p.capitalize }.join
230<%= prefix %><%= i.handler_name %>: {
231% namespace = i.namespace == 'core' ? '' : "#{i.namespace}::"
232%   if i.namespace != 'core'
233#ifdef PANDA_WITH_<%= i.namespace.upcase %>
234%   end
235    <%= namespace %>InstructionHandler<RuntimeIfaceT, IS_DYNAMIC, IS_DEBUG, true> handler(&state);
236%   if mode == :debug
237    INSTRUMENT_FRAME();
238    handler.InstrumentInstruction();
239    INSTRUMENT_FRAME();
240    handler.GetFrame()->GetAcc() = handler.GetAcc();
241%   end
242    handler.DumpVRegs();
243    handler.template Handle<%= mnemonic %><BytecodeInstruction::Format::<%= i.format.pretty.upcase %>>();
244%   if i.properties.include?('return')
245    if (handler.GetFrame()->IsStackless()) {
246        handler.HandleReturnStackless();
247        ASSERT(frame->GetMethod()->GetPandaFile()->GetHeader()->quickenedFlag
248               || handler.IsPrimaryOpcodeValid() || (handler.GetExceptionOpcode() == UINT8_MAX + NUM_PREFIXED + 1));
249        DISPATCH(state.GetDispatchTable(), handler.GetExceptionOpcode());
250    } else {
251        return;
252    }
253%   else
254%     if !i.exceptions.include?('x_none')
255    ASSERT(frame->GetMethod()->GetPandaFile()->GetHeader()->quickenedFlag
256           || handler.IsPrimaryOpcodeValid() || (handler.GetExceptionOpcode() == UINT8_MAX + NUM_PREFIXED + 1));
257    DISPATCH(state.GetDispatchTable(), handler.GetExceptionOpcode());
258%     else
259    ASSERT(frame->GetMethod()->GetPandaFile()->GetHeader()->quickenedFlag
260           || handler.IsPrimaryOpcodeValid());
261    DISPATCH(state.GetDispatchTable(), handler.GetPrimaryOpcode());
262%     end
263%   end
264%   if i.namespace != 'core'
265#endif // PANDA_WITH_<%= i.namespace.upcase %>
266%   end
267}
268% end
269% end
270#endif
271
272% if mode == :debug
273DEBUG_EXCEPTION_HANDLER: {
274% else
275EXCEPTION_HANDLER: {
276% end
277    ASSERT(thread->HasPendingException());
278
279    InstructionHandler<RuntimeIfaceT, IS_DYNAMIC, IS_DEBUG> handler(&state);
280    uint32_t pcOffset = panda_file::INVALID_OFFSET;
281
282% if mode == :debug
283    RuntimeIfaceT::GetNotificationManager()->ExceptionThrowEvent(thread, handler.GetFrame()->GetMethod(), thread->GetException(), pcOffset);
284% end
285    pcOffset = handler.FindCatchBlockStackless();
286    if (pcOffset == panda_file::INVALID_OFFSET) {
287        if constexpr (RUNTIME_ARCH == Arch::AARCH64 || RUNTIME_ARCH == Arch::AARCH32 || RUNTIME_ARCH == Arch::X86_64) {
288            return FindCatchBlockInCallStack(thread);
289        } else {
290            return;
291        }
292    }
293
294    auto *method = handler.GetFrame()->GetMethod();
295    ASSERT(method != nullptr);
296    LanguageContext ctx = RuntimeIfaceT::GetLanguageContext(*method);
297    ObjectHeader *exceptionObject = thread->GetException();
298    ctx.SetExceptionToVReg(handler.GetFrame()->GetAcc(), exceptionObject);
299
300    thread->ClearException();
301% if mode == :debug
302    RuntimeIfaceT::GetNotificationManager()->ExceptionCatchEvent(thread, handler.GetFrame()->GetMethod(), exceptionObject, pcOffset);
303% end
304
305    Span<const uint8_t> sp(handler.GetFrame()->GetMethod()->GetInstructions(), pcOffset);
306    state = InstructionHandlerState(thread, sp.cend(), handler.GetFrame(), handler.GetDispatchTable());
307
308    ASSERT(frame->GetMethod()->GetPandaFile()->GetHeader()->quickenedFlag || state.IsPrimaryOpcodeValid());
309    goto* state.GetDispatchTable()[state.GetPrimaryOpcode()];
310}
311
312% if mode == :debug
313INSTRUMENT_FRAME_HANDLER: {
314    InstructionHandler<RuntimeIfaceT, IS_DYNAMIC, IS_DEBUG> handler(&state);
315
316    ASSERT(handler.GetFrame()->IsForcePop() || handler.GetFrame()->IsRetryInstruction());
317
318    if (handler.GetFrame()->IsForcePop()) {
319        handler.GetFrame()->ClearForcePop();
320        handler.InstrumentForceReturn();
321        if (handler.GetFrame()->IsStackless()) {
322            handler.HandleInstrumentForceReturn();
323            ASSERT(frame->GetMethod()->GetPandaFile()->GetHeader()->quickenedFlag || handler.IsPrimaryOpcodeValid());
324            DISPATCH(handler.GetDispatchTable(), handler.GetPrimaryOpcode());
325        } else {
326            return;
327        }
328    }
329
330    handler.GetFrame()->ClearRetryInstruction();
331    auto* method = handler.GetFrame()->GetMethod();
332    state = InstructionHandlerState(thread, method->GetInstructions() + handler.GetFrame()->GetBytecodeOffset(), handler.GetFrame(), handler.GetDispatchTable());
333    ASSERT(frame->GetMethod()->GetPandaFile()->GetHeader()->quickenedFlag || state.IsPrimaryOpcodeValid());
334    goto* state.GetDispatchTable()[state.GetPrimaryOpcode()];
335}
336% end
337
338% if mode == :nodebug
339HANDLE_DEBUG_SWITCH: {
340    state.GetFrame()->GetAcc() = state.GetAcc();
341    ExecuteImplDebug<RuntimeIfaceT, IS_DYNAMIC>(state.GetThread(), state.GetInst().GetAddress(),
342                                                state.GetFrame(), jumpToEh);
343    return;
344}
345% end
346
347#if defined(__clang__)
348#pragma clang diagnostic pop
349#elif defined(__GNUC__)
350#pragma GCC diagnostic pop
351#endif
352}
353% end
354
355// NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic,cppcoreguidelines-avoid-goto, hicpp-no-assembler)
356
357}  // namespace ark::interpreter
358