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