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 #ifndef PANDA_INTERPRETER_INL_H_
17 #define PANDA_INTERPRETER_INL_H_
18
19 #include <array>
20 #include <cmath>
21 #include <cstddef>
22 #include <cstdint>
23 #include <functional>
24 #include <iomanip>
25 #include <limits>
26 #include <memory>
27 #include <type_traits>
28 #include <unordered_map>
29
30 #include "bytecode_instruction.h"
31 #include "libpandabase/events/events.h"
32 #include "libpandabase/macros.h"
33 #include "libpandabase/utils/logger.h"
34 #include "libpandabase/utils/type_helpers.h"
35 #include "libpandafile/bytecode_instruction-inl.h"
36 #include "libpandafile/file_items.h"
37 #include "libpandafile/shorty_iterator.h"
38 #include "runtime/bridge/bridge.h"
39 #include "runtime/include/class.h"
40 #include "runtime/include/coretypes/array-inl.h"
41 #include "runtime/include/coretypes/dyn_objects.h"
42 #include "runtime/include/coretypes/string.h"
43 #include "runtime/include/exceptions.h"
44 #include "runtime/include/locks.h"
45 #include "runtime/include/method-inl.h"
46 #include "runtime/include/object_header-inl.h"
47 #include "runtime/include/relayout_profiler.h"
48 #include "runtime/include/runtime.h"
49 #include "runtime/include/runtime_notification.h"
50 #include "runtime/include/thread-inl.h"
51 #include "runtime/include/value-inl.h"
52 #include "runtime/interpreter/acc_vregister.h"
53 #include "runtime/interpreter/arch/macros.h"
54 #include "runtime/interpreter/dispatch_table.h"
55 #include "runtime/interpreter/frame.h"
56 #include "runtime/interpreter/instruction_handler_base.h"
57 #include "runtime/interpreter/math_helpers.h"
58 #include "runtime/interpreter/runtime_interface.h"
59 #include "runtime/interpreter/vregister_iterator.h"
60 #include "runtime/jit/profiling_data.h"
61 #include "runtime/mem/vm_handle.h"
62 #include "runtime/handle_base-inl.h"
63
64 // ALWAYS_INLINE is mandatory attribute for handlers. There are cases which will be failed without it.
65
66 namespace panda::interpreter {
67
68 template <class RuntimeIfaceT, bool jump_to_eh = false, bool is_dynamic>
69 void ExecuteImpl(ManagedThread *thread, const uint8_t *pc, Frame *frame);
70
71 template <class RuntimeIfaceT, bool jump_to_eh = false, bool is_dynamic>
72 void ExecuteImpl_Inner(ManagedThread *thread, const uint8_t *pc, Frame *frame);
73
74 template <BytecodeInstruction::Format format, bool is_dynamic>
75 class DimIterator final : VRegisterIterator<format> {
76 public:
77 // NOLINTNEXTLINE(performance-move-const-arg)
DimIterator(BytecodeInstruction insn,Frame * frame)78 explicit DimIterator(BytecodeInstruction insn, Frame *frame) : VRegisterIterator<format>(std::move(insn), frame) {}
79
Get(size_t param_idx)80 ALWAYS_INLINE inline int32_t Get(size_t param_idx) const
81 {
82 return this->template GetAs<int32_t>(param_idx);
83 }
84 };
85
86 class FrameHelperDefault {
87 public:
88 template <BytecodeInstruction::Format format, class InstructionHandler>
GetNumberActualArgsDyn(InstructionHandler * instr_handler)89 ALWAYS_INLINE static uint32_t GetNumberActualArgsDyn(InstructionHandler *instr_handler)
90 {
91 // +1 means function object itself
92 return instr_handler->GetInst().template GetImm<format, 0>() + 1;
93 }
94
95 template <BytecodeInstruction::Format format, class InstructionHandler>
CopyArgumentsDyn(InstructionHandler * instr_handler,Frame * new_frame,uint32_t num_vregs,uint32_t num_actual_args)96 ALWAYS_INLINE static void CopyArgumentsDyn([[maybe_unused]] InstructionHandler *instr_handler,
97 [[maybe_unused]] Frame *new_frame, [[maybe_unused]] uint32_t num_vregs,
98 [[maybe_unused]] uint32_t num_actual_args)
99 {
100 }
101
102 template <class RuntimeIfaceT>
CreateFrame(ManagedThread * thread,uint32_t nregs_size,Method * method,Frame * prev,uint32_t nregs,uint32_t num_actual_args)103 ALWAYS_INLINE static Frame *CreateFrame([[maybe_unused]] ManagedThread *thread, uint32_t nregs_size, Method *method,
104 Frame *prev, uint32_t nregs, uint32_t num_actual_args)
105 {
106 return RuntimeIfaceT::CreateFrameWithActualArgsAndSize(nregs_size, nregs, num_actual_args, method, prev);
107 }
108 };
109
110 template <class RuntimeIfaceT, bool is_dynamic>
111 class InstructionHandler : public InstructionHandlerBase<RuntimeIfaceT, is_dynamic> {
112 public:
InstructionHandler(InstructionHandlerState * state)113 ALWAYS_INLINE inline explicit InstructionHandler(InstructionHandlerState *state)
114 : InstructionHandlerBase<RuntimeIfaceT, is_dynamic>(state)
115 {
116 }
117
118 #include "unimplemented_handlers-inl.h"
119
120 template <BytecodeInstruction::Format format>
HandleNop()121 ALWAYS_INLINE void HandleNop()
122 {
123 LOG_INST() << "nop";
124 this->template MoveToNextInst<format, false>();
125 }
126
127 template <BytecodeInstruction::Format format>
HandleFldaiDyn()128 ALWAYS_INLINE void HandleFldaiDyn()
129 {
130 auto imm = bit_cast<double>(this->GetInst().template GetImm<format>());
131 LOG_INST() << "fldai.dyn " << imm;
132 this->GetAcc().SetValue(coretypes::TaggedValue(imm).GetRawData());
133 this->template MoveToNextInst<format, false>();
134 }
135
136 template <BytecodeInstruction::Format format>
HandleLdaiDyn()137 ALWAYS_INLINE void HandleLdaiDyn()
138 {
139 int32_t imm = this->GetInst().template GetImm<format>();
140 LOG_INST() << "ldai.dyn " << std::hex << "0x" << imm;
141 this->GetAcc().SetValue(coretypes::TaggedValue(imm).GetRawData());
142 this->template MoveToNextInst<format, false>();
143 }
144
145 template <BytecodeInstruction::Format format>
HandleMov()146 ALWAYS_INLINE void HandleMov()
147 {
148 uint16_t vd = this->GetInst().template GetVReg<format, 0>();
149 uint16_t vs = this->GetInst().template GetVReg<format, 1>();
150 LOG_INST() << "mov v" << vd << ", v" << vs;
151 auto cur_frame_handler = this->GetFrameHandler();
152 cur_frame_handler.GetVReg(vd).MovePrimitive(cur_frame_handler.GetVReg(vs));
153 this->template MoveToNextInst<format, false>();
154 }
155
156 template <BytecodeInstruction::Format format>
HandleMovWide()157 ALWAYS_INLINE void HandleMovWide()
158 {
159 uint16_t vd = this->GetInst().template GetVReg<format, 0>();
160 uint16_t vs = this->GetInst().template GetVReg<format, 1>();
161 LOG_INST() << "mov.64 v" << vd << ", v" << vs;
162 auto cur_frame_handler = this->GetFrameHandler();
163 cur_frame_handler.GetVReg(vd).MovePrimitive(cur_frame_handler.GetVReg(vs));
164 this->template MoveToNextInst<format, false>();
165 }
166
167 template <BytecodeInstruction::Format format>
HandleMovObj()168 ALWAYS_INLINE void HandleMovObj()
169 {
170 uint16_t vd = this->GetInst().template GetVReg<format, 0>();
171 uint16_t vs = this->GetInst().template GetVReg<format, 1>();
172 LOG_INST() << "mov.obj v" << vd << ", v" << vs;
173 auto cur_frame_handler = this->GetFrameHandler();
174 cur_frame_handler.GetVReg(vd).MoveReference(cur_frame_handler.GetVReg(vs));
175 this->template MoveToNextInst<format, false>();
176 }
177
178 template <BytecodeInstruction::Format format>
HandleMovDyn()179 ALWAYS_INLINE void HandleMovDyn()
180 {
181 uint16_t vd = this->GetInst().template GetVReg<format, 0>();
182 uint16_t vs = this->GetInst().template GetVReg<format, 1>();
183 LOG_INST() << "mov.dyn v" << vd << ", v" << vs;
184 auto cur_frame_handler = this->GetFrameHandler();
185 cur_frame_handler.GetVReg(vd).Move(cur_frame_handler.GetVReg(vs));
186 this->template MoveToNextInst<format, false>();
187 }
188
189 template <BytecodeInstruction::Format format>
HandleMovi()190 ALWAYS_INLINE void HandleMovi()
191 {
192 int32_t imm = this->GetInst().template GetImm<format>();
193 uint16_t vd = this->GetInst().template GetVReg<format>();
194 LOG_INST() << "movi v" << vd << ", " << std::hex << "0x" << imm;
195 this->GetFrameHandler().GetVReg(vd).SetPrimitive(imm);
196 this->template MoveToNextInst<format, false>();
197 }
198
199 template <BytecodeInstruction::Format format>
HandleMoviWide()200 ALWAYS_INLINE void HandleMoviWide()
201 {
202 int64_t imm = this->GetInst().template GetImm<format>();
203 uint16_t vd = this->GetInst().template GetVReg<format>();
204 LOG_INST() << "movi.64 v" << vd << ", " << std::hex << "0x" << imm;
205 this->GetFrameHandler().GetVReg(vd).SetPrimitive(imm);
206 this->template MoveToNextInst<format, false>();
207 }
208
209 template <BytecodeInstruction::Format format>
HandleFmovi()210 ALWAYS_INLINE void HandleFmovi()
211 {
212 auto imm = bit_cast<float>(this->GetInst().template GetImm<format>());
213 uint16_t vd = this->GetInst().template GetVReg<format>();
214 LOG_INST() << "fmovi v" << vd << ", " << imm;
215 this->GetFrameHandler().GetVReg(vd).SetPrimitive(imm);
216 this->template MoveToNextInst<format, false>();
217 }
218
219 template <BytecodeInstruction::Format format>
HandleFmoviWide()220 ALWAYS_INLINE void HandleFmoviWide()
221 {
222 auto imm = bit_cast<double>(this->GetInst().template GetImm<format>());
223 uint16_t vd = this->GetInst().template GetVReg<format>();
224 LOG_INST() << "fmovi.64 v" << vd << ", " << imm;
225 this->GetFrameHandler().GetVReg(vd).SetPrimitive(imm);
226 this->template MoveToNextInst<format, false>();
227 }
228
229 template <BytecodeInstruction::Format format>
HandleMovNull()230 ALWAYS_INLINE void HandleMovNull()
231 {
232 uint16_t vd = this->GetInst().template GetVReg<format>();
233 LOG_INST() << "mov.null v" << vd;
234 this->GetFrameHandler().GetVReg(vd).SetReference(nullptr);
235 this->template MoveToNextInst<format, false>();
236 }
237
238 template <BytecodeInstruction::Format format>
HandleLda()239 ALWAYS_INLINE void HandleLda()
240 {
241 uint16_t vs = this->GetInst().template GetVReg<format>();
242 LOG_INST() << "lda v" << vs;
243 this->GetAccAsVReg().SetPrimitive(this->GetFrame()->GetVReg(vs).Get());
244 this->template MoveToNextInst<format, false>();
245 }
246
247 template <BytecodeInstruction::Format format>
HandleLdaWide()248 ALWAYS_INLINE void HandleLdaWide()
249 {
250 uint16_t vs = this->GetInst().template GetVReg<format>();
251 LOG_INST() << "lda.64 v" << vs;
252 this->GetAccAsVReg().SetPrimitive(this->GetFrame()->GetVReg(vs).GetLong());
253 this->template MoveToNextInst<format, false>();
254 }
255
256 template <BytecodeInstruction::Format format>
HandleLdaObj()257 ALWAYS_INLINE void HandleLdaObj()
258 {
259 uint16_t vs = this->GetInst().template GetVReg<format>();
260 LOG_INST() << "lda.obj v" << vs;
261 this->GetAccAsVReg().SetReference(this->GetFrame()->GetVReg(vs).GetReference());
262 this->template MoveToNextInst<format, false>();
263 }
264
265 template <BytecodeInstruction::Format format>
HandleLdai()266 ALWAYS_INLINE void HandleLdai()
267 {
268 int32_t imm = this->GetInst().template GetImm<format>();
269 LOG_INST() << "ldai " << std::hex << "0x" << imm;
270 this->GetAccAsVReg().SetPrimitive(imm);
271 this->template MoveToNextInst<format, false>();
272 }
273
274 template <BytecodeInstruction::Format format>
HandleLdaiWide()275 ALWAYS_INLINE void HandleLdaiWide()
276 {
277 int64_t imm = this->GetInst().template GetImm<format>();
278 LOG_INST() << "ldai.64 " << std::hex << "0x" << imm;
279 this->GetAccAsVReg().SetPrimitive(imm);
280 this->template MoveToNextInst<format, false>();
281 }
282
283 template <BytecodeInstruction::Format format>
HandleFldai()284 ALWAYS_INLINE void HandleFldai()
285 {
286 auto imm = bit_cast<float>(this->GetInst().template GetImm<format>());
287 LOG_INST() << "fldai " << imm;
288 this->GetAccAsVReg().SetPrimitive(imm);
289 this->template MoveToNextInst<format, false>();
290 }
291
292 template <BytecodeInstruction::Format format>
HandleFldaiWide()293 ALWAYS_INLINE void HandleFldaiWide()
294 {
295 auto imm = bit_cast<double>(this->GetInst().template GetImm<format>());
296 LOG_INST() << "fldai.64 " << imm;
297 this->GetAccAsVReg().SetPrimitive(imm);
298 this->template MoveToNextInst<format, false>();
299 }
300
301 template <BytecodeInstruction::Format format>
HandleLdaStr()302 ALWAYS_INLINE void HandleLdaStr()
303 {
304 auto string_id = this->GetInst().template GetId<format>();
305 LOG_INST() << "lda.str " << std::hex << "0x" << string_id;
306
307 this->GetFrame()->SetAcc(this->GetAcc());
308 PandaVM *vm = this->GetThread()->GetVM();
309 vm->HandleLdaStr(this->GetFrame(), string_id);
310 if (UNLIKELY(this->GetThread()->HasPendingException())) {
311 this->MoveToExceptionHandler();
312 } else {
313 this->GetAcc() = this->GetFrame()->GetAcc();
314 this->template MoveToNextInst<format, false>();
315 }
316 }
317
318 template <class T>
CheckLoadConstOp(coretypes::Array * array,T elem)319 ALWAYS_INLINE bool CheckLoadConstOp(coretypes::Array *array, T elem)
320 {
321 if constexpr (std::is_same_v<T, ObjectHeader *>) {
322 if (elem != nullptr) {
323 auto *array_class = array->ClassAddr<Class>();
324 auto *element_class = array_class->GetComponentType();
325 if (UNLIKELY(!elem->IsInstanceOf(element_class))) {
326 RuntimeIfaceT::ThrowArrayStoreException(array_class, elem->template ClassAddr<Class>());
327 return false;
328 }
329 }
330 }
331 return true;
332 }
333
334 template <BytecodeInstruction::Format format>
HandleLdaType()335 ALWAYS_INLINE void HandleLdaType()
336 {
337 auto type_id = this->GetInst().template GetId<format>();
338 LOG_INST() << "lda.type " << std::hex << "0x" << type_id;
339 Class *type = ResolveType(type_id);
340 if (LIKELY(type != nullptr)) {
341 this->GetAccAsVReg().SetReference(type->GetManagedObject());
342 this->template MoveToNextInst<format, false>();
343 } else {
344 this->MoveToExceptionHandler();
345 }
346 }
347
348 template <BytecodeInstruction::Format format>
HandleLdaNull()349 ALWAYS_INLINE void HandleLdaNull()
350 {
351 LOG_INST() << "lda.null";
352 this->GetAccAsVReg().SetReference(nullptr);
353 this->template MoveToNextInst<format, false>();
354 }
355
356 template <BytecodeInstruction::Format format>
HandleSta()357 ALWAYS_INLINE void HandleSta()
358 {
359 uint16_t vd = this->GetInst().template GetVReg<format>();
360 LOG_INST() << "sta v" << vd;
361 this->GetFrameHandler().GetVReg(vd).SetPrimitive(this->GetAcc().Get());
362 this->template MoveToNextInst<format, false>();
363 }
364
365 template <BytecodeInstruction::Format format>
HandleStaWide()366 ALWAYS_INLINE void HandleStaWide()
367 {
368 uint16_t vd = this->GetInst().template GetVReg<format>();
369 LOG_INST() << "sta.64 v" << vd;
370 this->GetFrameHandler().GetVReg(vd).SetPrimitive(this->GetAcc().GetValue());
371 this->template MoveToNextInst<format, false>();
372 }
373
374 template <BytecodeInstruction::Format format>
HandleStaObj()375 ALWAYS_INLINE void HandleStaObj()
376 {
377 uint16_t vd = this->GetInst().template GetVReg<format>();
378 LOG_INST() << "sta.obj v" << vd;
379 this->GetFrameHandler().GetVReg(vd).SetReference(this->GetAcc().GetReference());
380 this->template MoveToNextInst<format, false>();
381 }
382
383 template <BytecodeInstruction::Format format>
HandleStaDyn()384 ALWAYS_INLINE void HandleStaDyn()
385 {
386 uint16_t vd = this->GetInst().template GetVReg<format>();
387 LOG_INST() << "sta.dyn v" << vd;
388 this->GetFrameHandler().GetVReg(vd).Move(this->GetAccAsVReg());
389 this->template MoveToNextInst<format, false>();
390 }
391
392 template <BytecodeInstruction::Format format>
HandleJmp()393 ALWAYS_INLINE void HandleJmp()
394 {
395 int32_t imm = this->GetInst().template GetImm<format>();
396 LOG_INST() << "jmp " << std::hex << "0x" << imm;
397 if (!InstrumentBranches(imm)) {
398 this->template JumpToInst<false>(imm);
399 }
400 }
401
402 template <BytecodeInstruction::Format format>
HandleCmpWide()403 ALWAYS_INLINE void HandleCmpWide()
404 {
405 LOG_INST() << "cmp.64 ->";
406 HandleBinaryOp2<format, int64_t, math_helpers::cmp>();
407 }
408
409 template <BytecodeInstruction::Format format>
HandleUcmp()410 ALWAYS_INLINE void HandleUcmp()
411 {
412 LOG_INST() << "ucmp ->";
413 HandleBinaryOp2<format, uint32_t, math_helpers::cmp>();
414 }
415
416 template <BytecodeInstruction::Format format>
HandleUcmpWide()417 ALWAYS_INLINE void HandleUcmpWide()
418 {
419 LOG_INST() << "ucmp.64 ->";
420 HandleBinaryOp2<format, uint64_t, math_helpers::cmp>();
421 }
422
423 template <BytecodeInstruction::Format format>
HandleFcmpl()424 ALWAYS_INLINE void HandleFcmpl()
425 {
426 LOG_INST() << "fcmpl ->";
427 HandleBinaryOp2<format, float, math_helpers::fcmpl>();
428 }
429
430 template <BytecodeInstruction::Format format>
HandleFcmplWide()431 ALWAYS_INLINE void HandleFcmplWide()
432 {
433 LOG_INST() << "fcmpl.64 ->";
434 HandleBinaryOp2<format, double, math_helpers::fcmpl>();
435 }
436
437 template <BytecodeInstruction::Format format>
HandleFcmpg()438 ALWAYS_INLINE void HandleFcmpg()
439 {
440 LOG_INST() << "fcmpg ->";
441 HandleBinaryOp2<format, float, math_helpers::fcmpg>();
442 }
443
444 template <BytecodeInstruction::Format format>
HandleFcmpgWide()445 ALWAYS_INLINE void HandleFcmpgWide()
446 {
447 LOG_INST() << "fcmpg.64 ->";
448 HandleBinaryOp2<format, double, math_helpers::fcmpg>();
449 }
450
451 template <BytecodeInstruction::Format format>
HandleJeqz()452 ALWAYS_INLINE void HandleJeqz()
453 {
454 LOG_INST() << "jeqz ->";
455 HandleCondJmpz<format, std::equal_to>();
456 }
457
458 template <BytecodeInstruction::Format format>
HandleJnez()459 ALWAYS_INLINE void HandleJnez()
460 {
461 LOG_INST() << "jnez ->";
462 HandleCondJmpz<format, std::not_equal_to>();
463 }
464
465 template <BytecodeInstruction::Format format>
HandleJltz()466 ALWAYS_INLINE void HandleJltz()
467 {
468 LOG_INST() << "jltz ->";
469 HandleCondJmpz<format, std::less>();
470 }
471
472 template <BytecodeInstruction::Format format>
HandleJgtz()473 ALWAYS_INLINE void HandleJgtz()
474 {
475 LOG_INST() << "jgtz ->";
476 HandleCondJmpz<format, std::greater>();
477 }
478
479 template <BytecodeInstruction::Format format>
HandleJlez()480 ALWAYS_INLINE void HandleJlez()
481 {
482 LOG_INST() << "jlez ->";
483 HandleCondJmpz<format, std::less_equal>();
484 }
485
486 template <BytecodeInstruction::Format format>
HandleJgez()487 ALWAYS_INLINE void HandleJgez()
488 {
489 LOG_INST() << "jgez ->";
490 HandleCondJmpz<format, std::greater_equal>();
491 }
492
493 template <BytecodeInstruction::Format format>
HandleJeq()494 ALWAYS_INLINE void HandleJeq()
495 {
496 LOG_INST() << "jeq ->";
497 HandleCondJmp<format, std::equal_to>();
498 }
499
500 template <BytecodeInstruction::Format format>
HandleJne()501 ALWAYS_INLINE void HandleJne()
502 {
503 LOG_INST() << "jne ->";
504 HandleCondJmp<format, std::not_equal_to>();
505 }
506
507 template <BytecodeInstruction::Format format>
HandleJlt()508 ALWAYS_INLINE void HandleJlt()
509 {
510 LOG_INST() << "jlt ->";
511 HandleCondJmp<format, std::less>();
512 }
513
514 template <BytecodeInstruction::Format format>
HandleJgt()515 ALWAYS_INLINE void HandleJgt()
516 {
517 LOG_INST() << "jgt ->";
518 HandleCondJmp<format, std::greater>();
519 }
520
521 template <BytecodeInstruction::Format format>
HandleJle()522 ALWAYS_INLINE void HandleJle()
523 {
524 LOG_INST() << "jle ->";
525 HandleCondJmp<format, std::less_equal>();
526 }
527
528 template <BytecodeInstruction::Format format>
HandleJge()529 ALWAYS_INLINE void HandleJge()
530 {
531 LOG_INST() << "jge ->";
532 HandleCondJmp<format, std::greater_equal>();
533 }
534
535 template <BytecodeInstruction::Format format>
HandleJeqzObj()536 ALWAYS_INLINE void HandleJeqzObj()
537 {
538 LOG_INST() << "jeqz.obj ->";
539 HandleCondJmpzObj<format, std::equal_to>();
540 }
541
542 template <BytecodeInstruction::Format format>
HandleJnezObj()543 ALWAYS_INLINE void HandleJnezObj()
544 {
545 LOG_INST() << "jnez.obj ->";
546 HandleCondJmpzObj<format, std::not_equal_to>();
547 }
548
549 template <BytecodeInstruction::Format format>
HandleJeqObj()550 ALWAYS_INLINE void HandleJeqObj()
551 {
552 LOG_INST() << "jeq.obj ->";
553 HandleCondJmpObj<format, std::equal_to>();
554 }
555
556 template <BytecodeInstruction::Format format>
HandleJneObj()557 ALWAYS_INLINE void HandleJneObj()
558 {
559 LOG_INST() << "jne.obj ->";
560 HandleCondJmpObj<format, std::not_equal_to>();
561 }
562
563 template <BytecodeInstruction::Format format>
HandleAdd2()564 ALWAYS_INLINE void HandleAdd2()
565 {
566 LOG_INST() << "add2 ->";
567 HandleBinaryOp2<format, int32_t, math_helpers::Plus>();
568 }
569
570 template <BytecodeInstruction::Format format>
HandleAdd2Wide()571 ALWAYS_INLINE void HandleAdd2Wide()
572 {
573 LOG_INST() << "add2.64 ->";
574 HandleBinaryOp2<format, int64_t, math_helpers::Plus>();
575 }
576
577 template <BytecodeInstruction::Format format>
HandleFadd2()578 ALWAYS_INLINE void HandleFadd2()
579 {
580 LOG_INST() << "fadd2 ->";
581 HandleBinaryOp2<format, float, std::plus>();
582 }
583
584 template <BytecodeInstruction::Format format>
HandleFadd2Wide()585 ALWAYS_INLINE void HandleFadd2Wide()
586 {
587 LOG_INST() << "fadd2.64 ->";
588 HandleBinaryOp2<format, double, std::plus>();
589 }
590
591 template <BytecodeInstruction::Format format>
HandleSub2()592 ALWAYS_INLINE void HandleSub2()
593 {
594 LOG_INST() << "sub2 ->";
595 HandleBinaryOp2<format, int32_t, math_helpers::Minus>();
596 }
597
598 template <BytecodeInstruction::Format format>
HandleSub2Wide()599 ALWAYS_INLINE void HandleSub2Wide()
600 {
601 LOG_INST() << "sub2.64 ->";
602 HandleBinaryOp2<format, int64_t, math_helpers::Minus>();
603 }
604
605 template <BytecodeInstruction::Format format>
HandleFsub2()606 ALWAYS_INLINE void HandleFsub2()
607 {
608 LOG_INST() << "fsub2 ->";
609 HandleBinaryOp2<format, float, std::minus>();
610 }
611
612 template <BytecodeInstruction::Format format>
HandleFsub2Wide()613 ALWAYS_INLINE void HandleFsub2Wide()
614 {
615 LOG_INST() << "fsub2.64 ->";
616 HandleBinaryOp2<format, double, std::minus>();
617 }
618
619 template <BytecodeInstruction::Format format>
HandleMul2()620 ALWAYS_INLINE void HandleMul2()
621 {
622 LOG_INST() << "mul2 ->";
623 HandleBinaryOp2<format, int32_t, math_helpers::Multiplies>();
624 }
625
626 template <BytecodeInstruction::Format format>
HandleMul2Wide()627 ALWAYS_INLINE void HandleMul2Wide()
628 {
629 LOG_INST() << "mul2.64 ->";
630 HandleBinaryOp2<format, int64_t, math_helpers::Multiplies>();
631 }
632
633 template <BytecodeInstruction::Format format>
HandleFmul2()634 ALWAYS_INLINE void HandleFmul2()
635 {
636 LOG_INST() << "fmul2 ->";
637 HandleBinaryOp2<format, float, std::multiplies>();
638 }
639
640 template <BytecodeInstruction::Format format>
HandleFmul2Wide()641 ALWAYS_INLINE void HandleFmul2Wide()
642 {
643 LOG_INST() << "fmul2.64 ->";
644 HandleBinaryOp2<format, double, std::multiplies>();
645 }
646
647 template <BytecodeInstruction::Format format>
HandleFdiv2()648 ALWAYS_INLINE void HandleFdiv2()
649 {
650 LOG_INST() << "fdiv2 ->";
651 HandleBinaryOp2<format, float, std::divides>();
652 }
653
654 template <BytecodeInstruction::Format format>
HandleFdiv2Wide()655 ALWAYS_INLINE void HandleFdiv2Wide()
656 {
657 LOG_INST() << "fdiv2.64 ->";
658 HandleBinaryOp2<format, double, std::divides>();
659 }
660
661 template <BytecodeInstruction::Format format>
HandleFmod2()662 ALWAYS_INLINE void HandleFmod2()
663 {
664 LOG_INST() << "fmod2 ->";
665 HandleBinaryOp2<format, float, math_helpers::fmodulus>();
666 }
667
668 template <BytecodeInstruction::Format format>
HandleFmod2Wide()669 ALWAYS_INLINE void HandleFmod2Wide()
670 {
671 LOG_INST() << "fmod2.64 ->";
672 HandleBinaryOp2<format, double, math_helpers::fmodulus>();
673 }
674
675 template <BytecodeInstruction::Format format>
HandleAnd2()676 ALWAYS_INLINE void HandleAnd2()
677 {
678 LOG_INST() << "and2 ->";
679 HandleBinaryOp2<format, int32_t, std::bit_and>();
680 }
681
682 template <BytecodeInstruction::Format format>
HandleAnd2Wide()683 ALWAYS_INLINE void HandleAnd2Wide()
684 {
685 LOG_INST() << "and2.64 ->";
686 HandleBinaryOp2<format, int64_t, std::bit_and>();
687 }
688
689 template <BytecodeInstruction::Format format>
HandleOr2()690 ALWAYS_INLINE void HandleOr2()
691 {
692 LOG_INST() << "or2 ->";
693 HandleBinaryOp2<format, int32_t, std::bit_or>();
694 }
695
696 template <BytecodeInstruction::Format format>
HandleOr2Wide()697 ALWAYS_INLINE void HandleOr2Wide()
698 {
699 LOG_INST() << "or2.64 ->";
700 HandleBinaryOp2<format, int64_t, std::bit_or>();
701 }
702
703 template <BytecodeInstruction::Format format>
HandleXor2()704 ALWAYS_INLINE void HandleXor2()
705 {
706 LOG_INST() << "xor2 ->";
707 HandleBinaryOp2<format, int32_t, std::bit_xor>();
708 }
709
710 template <BytecodeInstruction::Format format>
HandleXor2Wide()711 ALWAYS_INLINE void HandleXor2Wide()
712 {
713 LOG_INST() << "xor2.64 ->";
714 HandleBinaryOp2<format, int64_t, std::bit_xor>();
715 }
716
717 template <BytecodeInstruction::Format format>
HandleShl2()718 ALWAYS_INLINE void HandleShl2()
719 {
720 LOG_INST() << "shl2 ->";
721 HandleBinaryOp2<format, int32_t, math_helpers::bit_shl>();
722 }
723
724 template <BytecodeInstruction::Format format>
HandleShl2Wide()725 ALWAYS_INLINE void HandleShl2Wide()
726 {
727 LOG_INST() << "shl2.64 ->";
728 HandleBinaryOp2<format, int64_t, math_helpers::bit_shl>();
729 }
730
731 template <BytecodeInstruction::Format format>
HandleShr2()732 ALWAYS_INLINE void HandleShr2()
733 {
734 LOG_INST() << "shr2 ->";
735 HandleBinaryOp2<format, int32_t, math_helpers::bit_shr>();
736 }
737
738 template <BytecodeInstruction::Format format>
HandleShr2Wide()739 ALWAYS_INLINE void HandleShr2Wide()
740 {
741 LOG_INST() << "shr2.64 ->";
742 HandleBinaryOp2<format, int64_t, math_helpers::bit_shr>();
743 }
744
745 template <BytecodeInstruction::Format format>
HandleAshr2()746 ALWAYS_INLINE void HandleAshr2()
747 {
748 LOG_INST() << "ashr2 ->";
749 HandleBinaryOp2<format, int32_t, math_helpers::bit_ashr>();
750 }
751
752 template <BytecodeInstruction::Format format>
HandleAshr2Wide()753 ALWAYS_INLINE void HandleAshr2Wide()
754 {
755 LOG_INST() << "ashr2.64 ->";
756 HandleBinaryOp2<format, int64_t, math_helpers::bit_ashr>();
757 }
758
759 template <BytecodeInstruction::Format format>
HandleDiv2()760 ALWAYS_INLINE void HandleDiv2()
761 {
762 LOG_INST() << "div2 ->";
763 HandleBinaryOp2<format, int32_t, math_helpers::idivides, true>();
764 }
765
766 template <BytecodeInstruction::Format format>
HandleDiv2Wide()767 ALWAYS_INLINE void HandleDiv2Wide()
768 {
769 LOG_INST() << "div2.64 ->";
770 HandleBinaryOp2<format, int64_t, math_helpers::idivides, true>();
771 }
772
773 template <BytecodeInstruction::Format format>
HandleMod2()774 ALWAYS_INLINE void HandleMod2()
775 {
776 LOG_INST() << "mod2 ->";
777 HandleBinaryOp2<format, int32_t, math_helpers::imodulus, true>();
778 }
779
780 template <BytecodeInstruction::Format format>
HandleMod2Wide()781 ALWAYS_INLINE void HandleMod2Wide()
782 {
783 LOG_INST() << "mod2.64 ->";
784 HandleBinaryOp2<format, int64_t, math_helpers::imodulus, true>();
785 }
786
787 template <BytecodeInstruction::Format format>
HandleDivu2()788 ALWAYS_INLINE void HandleDivu2()
789 {
790 LOG_INST() << "divu2 ->";
791 HandleBinaryOp2<format, uint32_t, math_helpers::idivides, true>();
792 }
793
794 template <BytecodeInstruction::Format format>
HandleDivu2Wide()795 ALWAYS_INLINE void HandleDivu2Wide()
796 {
797 LOG_INST() << "divu2.64 ->";
798 HandleBinaryOp2<format, uint64_t, math_helpers::idivides, true>();
799 }
800
801 template <BytecodeInstruction::Format format>
HandleModu2()802 ALWAYS_INLINE void HandleModu2()
803 {
804 LOG_INST() << "modu2 ->";
805 HandleBinaryOp2<format, uint32_t, math_helpers::imodulus, true>();
806 }
807
808 template <BytecodeInstruction::Format format>
HandleModu2Wide()809 ALWAYS_INLINE void HandleModu2Wide()
810 {
811 LOG_INST() << "modu2.64 ->";
812 HandleBinaryOp2<format, uint64_t, math_helpers::imodulus, true>();
813 }
814
815 template <BytecodeInstruction::Format format>
HandleAdd()816 ALWAYS_INLINE void HandleAdd()
817 {
818 LOG_INST() << "add ->";
819 HandleBinaryOp<format, int32_t, math_helpers::Plus>();
820 }
821
822 template <BytecodeInstruction::Format format>
HandleSub()823 ALWAYS_INLINE void HandleSub()
824 {
825 LOG_INST() << "sub ->";
826 HandleBinaryOp<format, int32_t, math_helpers::Minus>();
827 }
828
829 template <BytecodeInstruction::Format format>
HandleMul()830 ALWAYS_INLINE void HandleMul()
831 {
832 LOG_INST() << "mul ->";
833 HandleBinaryOp<format, int32_t, math_helpers::Multiplies>();
834 }
835
836 template <BytecodeInstruction::Format format>
HandleAnd()837 ALWAYS_INLINE void HandleAnd()
838 {
839 LOG_INST() << "and ->";
840 HandleBinaryOp<format, int32_t, std::bit_and>();
841 }
842
843 template <BytecodeInstruction::Format format>
HandleOr()844 ALWAYS_INLINE void HandleOr()
845 {
846 LOG_INST() << "or ->";
847 HandleBinaryOp<format, int32_t, std::bit_or>();
848 }
849
850 template <BytecodeInstruction::Format format>
HandleXor()851 ALWAYS_INLINE void HandleXor()
852 {
853 LOG_INST() << "xor ->";
854 HandleBinaryOp<format, int32_t, std::bit_xor>();
855 }
856
857 template <BytecodeInstruction::Format format>
HandleShl()858 ALWAYS_INLINE void HandleShl()
859 {
860 LOG_INST() << "shl ->";
861 HandleBinaryOp<format, int32_t, math_helpers::bit_shl>();
862 }
863
864 template <BytecodeInstruction::Format format>
HandleShr()865 ALWAYS_INLINE void HandleShr()
866 {
867 LOG_INST() << "shr ->";
868 HandleBinaryOp<format, int32_t, math_helpers::bit_shr>();
869 }
870
871 template <BytecodeInstruction::Format format>
HandleAshr()872 ALWAYS_INLINE void HandleAshr()
873 {
874 LOG_INST() << "ashr ->";
875 HandleBinaryOp<format, int32_t, math_helpers::bit_ashr>();
876 }
877
878 template <BytecodeInstruction::Format format>
HandleDiv()879 ALWAYS_INLINE void HandleDiv()
880 {
881 LOG_INST() << "div ->";
882 HandleBinaryOp<format, int32_t, math_helpers::idivides, true>();
883 }
884
885 template <BytecodeInstruction::Format format>
HandleMod()886 ALWAYS_INLINE void HandleMod()
887 {
888 LOG_INST() << "mod ->";
889 HandleBinaryOp<format, int32_t, math_helpers::imodulus, true>();
890 }
891
892 template <BytecodeInstruction::Format format>
HandleAddi()893 ALWAYS_INLINE void HandleAddi()
894 {
895 LOG_INST() << "addi ->";
896 HandleBinaryOp2Imm<format, int32_t, math_helpers::Plus>();
897 }
898
899 template <BytecodeInstruction::Format format>
HandleSubi()900 ALWAYS_INLINE void HandleSubi()
901 {
902 LOG_INST() << "subi ->";
903 HandleBinaryOp2Imm<format, int32_t, math_helpers::Minus>();
904 }
905
906 template <BytecodeInstruction::Format format>
HandleMuli()907 ALWAYS_INLINE void HandleMuli()
908 {
909 LOG_INST() << "muli ->";
910 HandleBinaryOp2Imm<format, int32_t, math_helpers::Multiplies>();
911 }
912
913 template <BytecodeInstruction::Format format>
HandleAndi()914 ALWAYS_INLINE void HandleAndi()
915 {
916 LOG_INST() << "andi ->";
917 HandleBinaryOp2Imm<format, int32_t, std::bit_and>();
918 }
919
920 template <BytecodeInstruction::Format format>
HandleOri()921 ALWAYS_INLINE void HandleOri()
922 {
923 LOG_INST() << "ori ->";
924 HandleBinaryOp2Imm<format, int32_t, std::bit_or>();
925 }
926
927 template <BytecodeInstruction::Format format>
HandleXori()928 ALWAYS_INLINE void HandleXori()
929 {
930 LOG_INST() << "xori ->";
931 HandleBinaryOp2Imm<format, int32_t, std::bit_xor>();
932 }
933
934 template <BytecodeInstruction::Format format>
HandleShli()935 ALWAYS_INLINE void HandleShli()
936 {
937 LOG_INST() << "shli ->";
938 HandleBinaryOp2Imm<format, int32_t, math_helpers::bit_shl>();
939 }
940
941 template <BytecodeInstruction::Format format>
HandleShri()942 ALWAYS_INLINE void HandleShri()
943 {
944 LOG_INST() << "shri ->";
945 HandleBinaryOp2Imm<format, int32_t, math_helpers::bit_shr>();
946 }
947
948 template <BytecodeInstruction::Format format>
HandleAshri()949 ALWAYS_INLINE void HandleAshri()
950 {
951 LOG_INST() << "ashri ->";
952 HandleBinaryOp2Imm<format, int32_t, math_helpers::bit_ashr>();
953 }
954
955 template <BytecodeInstruction::Format format>
HandleDivi()956 ALWAYS_INLINE void HandleDivi()
957 {
958 LOG_INST() << "divi ->";
959 HandleBinaryOp2Imm<format, int32_t, math_helpers::idivides, true>();
960 }
961
962 template <BytecodeInstruction::Format format>
HandleModi()963 ALWAYS_INLINE void HandleModi()
964 {
965 LOG_INST() << "modi ->";
966 HandleBinaryOp2Imm<format, int32_t, math_helpers::imodulus, true>();
967 }
968
969 template <BytecodeInstruction::Format format>
HandleNeg()970 ALWAYS_INLINE void HandleNeg()
971 {
972 LOG_INST() << "neg";
973 HandleUnaryOp<format, int32_t, std::negate>();
974 }
975
976 template <BytecodeInstruction::Format format>
HandleNegWide()977 ALWAYS_INLINE void HandleNegWide()
978 {
979 LOG_INST() << "neg.64";
980 HandleUnaryOp<format, int64_t, std::negate>();
981 }
982
983 template <BytecodeInstruction::Format format>
HandleFneg()984 ALWAYS_INLINE void HandleFneg()
985 {
986 LOG_INST() << "fneg";
987 HandleUnaryOp<format, float, std::negate>();
988 }
989
990 template <BytecodeInstruction::Format format>
HandleFnegWide()991 ALWAYS_INLINE void HandleFnegWide()
992 {
993 LOG_INST() << "fneg.64";
994 HandleUnaryOp<format, double, std::negate>();
995 }
996
997 template <BytecodeInstruction::Format format>
HandleNot()998 ALWAYS_INLINE void HandleNot()
999 {
1000 LOG_INST() << "not";
1001 HandleUnaryOp<format, int32_t, std::bit_not>();
1002 }
1003
1004 template <BytecodeInstruction::Format format>
HandleNotWide()1005 ALWAYS_INLINE void HandleNotWide()
1006 {
1007 LOG_INST() << "not.64";
1008 HandleUnaryOp<format, int64_t, std::bit_not>();
1009 }
1010
1011 template <BytecodeInstruction::Format format>
HandleInci()1012 ALWAYS_INLINE void HandleInci()
1013 {
1014 int32_t imm = this->GetInst().template GetImm<format>();
1015 uint16_t vx = this->GetInst().template GetVReg<format>();
1016 LOG_INST() << "inci v" << vx << ", " << std::hex << "0x" << imm;
1017 auto ® = this->GetFrame()->GetVReg(vx);
1018 int32_t value = reg.template GetAs<int32_t>();
1019 reg.Set(value + imm);
1020 this->template MoveToNextInst<format, false>();
1021 }
1022
1023 template <BytecodeInstruction::Format format>
HandleU32toi64()1024 ALWAYS_INLINE void HandleU32toi64()
1025 {
1026 LOG_INST() << "u32toi64";
1027 HandleConversion<format, uint32_t, int64_t>();
1028 }
1029
1030 template <BytecodeInstruction::Format format>
HandleU32toi16()1031 ALWAYS_INLINE void HandleU32toi16()
1032 {
1033 LOG_INST() << "u32toi16";
1034 HandleConversion<format, uint32_t, int16_t>();
1035 }
1036
1037 template <BytecodeInstruction::Format format>
HandleU32tou16()1038 ALWAYS_INLINE void HandleU32tou16()
1039 {
1040 LOG_INST() << "u32tou16";
1041 HandleConversion<format, uint32_t, uint16_t>();
1042 }
1043
1044 template <BytecodeInstruction::Format format>
HandleU32toi8()1045 ALWAYS_INLINE void HandleU32toi8()
1046 {
1047 LOG_INST() << "u32toi8";
1048 HandleConversion<format, uint32_t, int8_t>();
1049 }
1050
1051 template <BytecodeInstruction::Format format>
HandleU32tou8()1052 ALWAYS_INLINE void HandleU32tou8()
1053 {
1054 LOG_INST() << "u32tou8";
1055 HandleConversion<format, uint32_t, uint8_t>();
1056 }
1057
1058 template <BytecodeInstruction::Format format>
HandleU32tou1()1059 ALWAYS_INLINE void HandleU32tou1()
1060 {
1061 LOG_INST() << "u32tou1";
1062 HandleConversion<format, uint32_t, bool>();
1063 }
1064
1065 template <BytecodeInstruction::Format format>
HandleI32toi64()1066 ALWAYS_INLINE void HandleI32toi64()
1067 {
1068 LOG_INST() << "i32toi64";
1069 HandleConversion<format, int32_t, int64_t>();
1070 }
1071
1072 template <BytecodeInstruction::Format format>
HandleI32tou16()1073 ALWAYS_INLINE void HandleI32tou16()
1074 {
1075 LOG_INST() << "i32tou16";
1076 HandleConversion<format, int32_t, uint16_t>();
1077 }
1078
1079 template <BytecodeInstruction::Format format>
HandleI32toi16()1080 ALWAYS_INLINE void HandleI32toi16()
1081 {
1082 LOG_INST() << "i32toi16";
1083 HandleConversion<format, int32_t, int16_t>();
1084 }
1085
1086 template <BytecodeInstruction::Format format>
HandleI32toi8()1087 ALWAYS_INLINE void HandleI32toi8()
1088 {
1089 LOG_INST() << "i32toi8";
1090 HandleConversion<format, int32_t, int8_t>();
1091 }
1092
1093 template <BytecodeInstruction::Format format>
HandleI32tou8()1094 ALWAYS_INLINE void HandleI32tou8()
1095 {
1096 LOG_INST() << "i32tou8";
1097 HandleConversion<format, int32_t, uint8_t>();
1098 }
1099
1100 template <BytecodeInstruction::Format format>
HandleI32tou1()1101 ALWAYS_INLINE void HandleI32tou1()
1102 {
1103 LOG_INST() << "i32tou1";
1104 HandleConversion<format, int32_t, bool>();
1105 }
1106
1107 template <BytecodeInstruction::Format format>
HandleI32tof32()1108 ALWAYS_INLINE void HandleI32tof32()
1109 {
1110 LOG_INST() << "i32tof32";
1111 HandleConversion<format, int32_t, float>();
1112 }
1113
1114 template <BytecodeInstruction::Format format>
HandleI32tof64()1115 ALWAYS_INLINE void HandleI32tof64()
1116 {
1117 LOG_INST() << "i32tof64";
1118 HandleConversion<format, int32_t, double>();
1119 }
1120
1121 template <BytecodeInstruction::Format format>
HandleU32tof32()1122 ALWAYS_INLINE void HandleU32tof32()
1123 {
1124 LOG_INST() << "u32tof32";
1125 HandleConversion<format, uint32_t, float>();
1126 }
1127
1128 template <BytecodeInstruction::Format format>
HandleU32tof64()1129 ALWAYS_INLINE void HandleU32tof64()
1130 {
1131 LOG_INST() << "u32tof64";
1132 HandleConversion<format, uint32_t, double>();
1133 }
1134
1135 template <BytecodeInstruction::Format format>
HandleI64toi32()1136 ALWAYS_INLINE void HandleI64toi32()
1137 {
1138 LOG_INST() << "i64toi32";
1139 HandleConversion<format, int64_t, int32_t>();
1140 }
1141
1142 template <BytecodeInstruction::Format format>
HandleI64tou1()1143 ALWAYS_INLINE void HandleI64tou1()
1144 {
1145 LOG_INST() << "i64tou1";
1146 HandleConversion<format, int64_t, bool>();
1147 }
1148
1149 template <BytecodeInstruction::Format format>
HandleI64tof32()1150 ALWAYS_INLINE void HandleI64tof32()
1151 {
1152 LOG_INST() << "i64tof32";
1153 HandleConversion<format, int64_t, float>();
1154 }
1155
1156 template <BytecodeInstruction::Format format>
HandleI64tof64()1157 ALWAYS_INLINE void HandleI64tof64()
1158 {
1159 LOG_INST() << "i64tof64";
1160 HandleConversion<format, int64_t, double>();
1161 }
1162
1163 template <BytecodeInstruction::Format format>
HandleU64toi32()1164 ALWAYS_INLINE void HandleU64toi32()
1165 {
1166 LOG_INST() << "u64toi32";
1167 HandleConversion<format, uint64_t, int32_t>();
1168 }
1169
1170 template <BytecodeInstruction::Format format>
HandleU64tou32()1171 ALWAYS_INLINE void HandleU64tou32()
1172 {
1173 LOG_INST() << "u64tou32";
1174 HandleConversion<format, uint64_t, uint32_t>();
1175 }
1176
1177 template <BytecodeInstruction::Format format>
HandleU64tou1()1178 ALWAYS_INLINE void HandleU64tou1()
1179 {
1180 LOG_INST() << "u64tou1";
1181 HandleConversion<format, uint64_t, bool>();
1182 }
1183
1184 template <BytecodeInstruction::Format format>
HandleU64tof32()1185 ALWAYS_INLINE void HandleU64tof32()
1186 {
1187 LOG_INST() << "u64tof32";
1188 HandleConversion<format, uint64_t, float>();
1189 }
1190
1191 template <BytecodeInstruction::Format format>
HandleU64tof64()1192 ALWAYS_INLINE void HandleU64tof64()
1193 {
1194 LOG_INST() << "u64tof64";
1195 HandleConversion<format, uint64_t, double>();
1196 }
1197
1198 template <BytecodeInstruction::Format format>
HandleF32tof64()1199 ALWAYS_INLINE void HandleF32tof64()
1200 {
1201 LOG_INST() << "f32tof64";
1202 HandleConversion<format, float, double>();
1203 }
1204
1205 template <BytecodeInstruction::Format format>
HandleF32toi32()1206 ALWAYS_INLINE void HandleF32toi32()
1207 {
1208 LOG_INST() << "f32toi32";
1209 HandleFloatToIntConversion<format, float, int32_t>();
1210 }
1211
1212 template <BytecodeInstruction::Format format>
HandleF32toi64()1213 ALWAYS_INLINE void HandleF32toi64()
1214 {
1215 LOG_INST() << "f32toi64";
1216 HandleFloatToIntConversion<format, float, int64_t>();
1217 }
1218
1219 template <BytecodeInstruction::Format format>
HandleF32tou32()1220 ALWAYS_INLINE void HandleF32tou32()
1221 {
1222 LOG_INST() << "f32tou32";
1223 HandleFloatToIntConversion<format, float, uint32_t>();
1224 }
1225
1226 template <BytecodeInstruction::Format format>
HandleF32tou64()1227 ALWAYS_INLINE void HandleF32tou64()
1228 {
1229 LOG_INST() << "f32tou64";
1230 HandleFloatToIntConversion<format, float, uint64_t>();
1231 }
1232
1233 template <BytecodeInstruction::Format format>
HandleF64tof32()1234 ALWAYS_INLINE void HandleF64tof32()
1235 {
1236 LOG_INST() << "f64tof32";
1237 HandleConversion<format, double, float>();
1238 }
1239
1240 template <BytecodeInstruction::Format format>
HandleF64toi64()1241 ALWAYS_INLINE void HandleF64toi64()
1242 {
1243 LOG_INST() << "f64toi64";
1244 HandleFloatToIntConversion<format, double, int64_t>();
1245 }
1246
1247 template <BytecodeInstruction::Format format>
HandleF64toi32()1248 ALWAYS_INLINE void HandleF64toi32()
1249 {
1250 LOG_INST() << "f64toi32";
1251 HandleFloatToIntConversion<format, double, int32_t>();
1252 }
1253
1254 template <BytecodeInstruction::Format format>
HandleF64tou64()1255 ALWAYS_INLINE void HandleF64tou64()
1256 {
1257 LOG_INST() << "f64tou64";
1258 HandleFloatToIntConversion<format, double, uint64_t>();
1259 }
1260
1261 template <BytecodeInstruction::Format format>
HandleF64tou32()1262 ALWAYS_INLINE void HandleF64tou32()
1263 {
1264 LOG_INST() << "f64tou32";
1265 HandleFloatToIntConversion<format, double, uint32_t>();
1266 }
1267
1268 template <BytecodeInstruction::Format format>
HandleLdarr8()1269 ALWAYS_INLINE void HandleLdarr8()
1270 {
1271 LOG_INST() << "ldarr.8";
1272 HandleArrayPrimitiveLoad<format, int8_t>();
1273 }
1274
1275 template <BytecodeInstruction::Format format>
HandleLdarr16()1276 ALWAYS_INLINE void HandleLdarr16()
1277 {
1278 LOG_INST() << "ldarr.16";
1279 HandleArrayPrimitiveLoad<format, int16_t>();
1280 }
1281
1282 template <BytecodeInstruction::Format format>
HandleLdarr()1283 ALWAYS_INLINE void HandleLdarr()
1284 {
1285 LOG_INST() << "ldarr";
1286 HandleArrayPrimitiveLoad<format, int32_t>();
1287 }
1288
1289 template <BytecodeInstruction::Format format>
HandleLdarrWide()1290 ALWAYS_INLINE void HandleLdarrWide()
1291 {
1292 LOG_INST() << "ldarr.64";
1293 HandleArrayPrimitiveLoad<format, int64_t>();
1294 }
1295
1296 template <BytecodeInstruction::Format format>
HandleLdarru8()1297 ALWAYS_INLINE void HandleLdarru8()
1298 {
1299 LOG_INST() << "ldarru.8";
1300 HandleArrayPrimitiveLoad<format, uint8_t>();
1301 }
1302
1303 template <BytecodeInstruction::Format format>
HandleLdarru16()1304 ALWAYS_INLINE void HandleLdarru16()
1305 {
1306 LOG_INST() << "ldarru.16";
1307 HandleArrayPrimitiveLoad<format, uint16_t>();
1308 }
1309
1310 template <BytecodeInstruction::Format format>
HandleFldarr32()1311 ALWAYS_INLINE void HandleFldarr32()
1312 {
1313 LOG_INST() << "fldarr.32";
1314 HandleArrayPrimitiveLoad<format, float>();
1315 }
1316
1317 template <BytecodeInstruction::Format format>
HandleFldarrWide()1318 ALWAYS_INLINE void HandleFldarrWide()
1319 {
1320 LOG_INST() << "fldarr.64";
1321 HandleArrayPrimitiveLoad<format, double>();
1322 }
1323
1324 template <BytecodeInstruction::Format format>
HandleLdarrObj()1325 ALWAYS_INLINE void HandleLdarrObj()
1326 {
1327 uint16_t vs = this->GetInst().template GetVReg<format>();
1328
1329 LOG_INST() << "ldarr.obj v" << vs;
1330 auto *array = static_cast<coretypes::Array *>(this->GetFrame()->GetVReg(vs).GetReference());
1331 int32_t idx = this->GetAcc().Get();
1332
1333 if (LIKELY(CheckLoadArrayOp(array, idx))) {
1334 this->GetAccAsVReg().SetReference(
1335 array->Get<ObjectHeader *, RuntimeIfaceT::NEED_READ_BARRIER>(this->GetThread(), idx));
1336 this->template MoveToNextInst<format, true>();
1337 } else {
1338 this->MoveToExceptionHandler();
1339 }
1340 }
1341
1342 template <BytecodeInstruction::Format format>
HandleLdaDyn()1343 ALWAYS_INLINE void HandleLdaDyn()
1344 {
1345 uint16_t vs = this->GetInst().template GetVReg<format>();
1346 LOG_INST() << "lda.dyn v" << vs;
1347 this->GetAccAsVReg().Move(this->GetFrameHandler().GetVReg(vs));
1348 this->template MoveToNextInst<format, false>();
1349 }
1350
1351 template <BytecodeInstruction::Format format>
HandleStarr8()1352 ALWAYS_INLINE void HandleStarr8()
1353 {
1354 LOG_INST() << "starr.8";
1355 HandleArrayStore<format, uint8_t>();
1356 }
1357
1358 template <BytecodeInstruction::Format format>
HandleStarr16()1359 ALWAYS_INLINE void HandleStarr16()
1360 {
1361 LOG_INST() << "starr.16";
1362 HandleArrayStore<format, uint16_t>();
1363 }
1364
1365 template <BytecodeInstruction::Format format>
HandleStarr()1366 ALWAYS_INLINE void HandleStarr()
1367 {
1368 LOG_INST() << "starr";
1369 HandleArrayStore<format, uint32_t>();
1370 }
1371
1372 template <BytecodeInstruction::Format format>
HandleStarrWide()1373 ALWAYS_INLINE void HandleStarrWide()
1374 {
1375 LOG_INST() << "starr.64";
1376 HandleArrayStore<format, uint64_t>();
1377 }
1378
1379 template <BytecodeInstruction::Format format>
HandleFstarr32()1380 ALWAYS_INLINE void HandleFstarr32()
1381 {
1382 LOG_INST() << "fstarr.32";
1383 HandleArrayStore<format, float>();
1384 }
1385
1386 template <BytecodeInstruction::Format format>
HandleFstarrWide()1387 ALWAYS_INLINE void HandleFstarrWide()
1388 {
1389 LOG_INST() << "fstarr.64";
1390 HandleArrayStore<format, double>();
1391 }
1392
1393 template <BytecodeInstruction::Format format>
HandleStarrObj()1394 ALWAYS_INLINE void HandleStarrObj()
1395 {
1396 LOG_INST() << "starr.obj";
1397 HandleArrayStore<format, ObjectHeader *>();
1398 }
1399
1400 template <BytecodeInstruction::Format format>
HandleLenarr()1401 ALWAYS_INLINE void HandleLenarr()
1402 {
1403 uint16_t vs = this->GetInst().template GetVReg<format>();
1404
1405 LOG_INST() << "lenarr v" << vs;
1406
1407 ObjectHeader *obj = this->GetFrame()->GetVReg(vs).GetReference();
1408 if (UNLIKELY(obj == nullptr)) {
1409 RuntimeIfaceT::ThrowNullPointerException();
1410 this->MoveToExceptionHandler();
1411 } else {
1412 auto *array = static_cast<coretypes::Array *>(obj);
1413 this->GetAccAsVReg().SetPrimitive(static_cast<int32_t>(array->GetLength()));
1414 this->template MoveToNextInst<format, true>();
1415 }
1416 }
1417
1418 template <BytecodeInstruction::Format format>
HandleLdaConst()1419 ALWAYS_INLINE void HandleLdaConst()
1420 {
1421 auto litarr_id = this->GetInst().template GetId<format>();
1422 uint16_t vd = this->GetInst().template GetVReg<format>();
1423
1424 LOG_INST() << "lda.const v" << vd << ", " << std::hex << "0x" << litarr_id;
1425
1426 this->GetFrame()->SetAcc(this->GetAcc());
1427 auto array = ResolveLiteralArray(litarr_id);
1428 this->GetAcc() = this->GetFrame()->GetAcc();
1429
1430 if (UNLIKELY(array == nullptr)) {
1431 this->MoveToExceptionHandler();
1432 } else {
1433 this->GetFrameHandler().GetVReg(vd).SetReference(array);
1434 this->template MoveToNextInst<format, false>();
1435 }
1436 }
1437
1438 template <BytecodeInstruction::Format format>
HandleNewarr()1439 ALWAYS_INLINE void HandleNewarr()
1440 {
1441 uint16_t vd = this->GetInst().template GetVReg<format, 0>();
1442 uint16_t vs = this->GetInst().template GetVReg<format, 1>();
1443 auto id = this->GetInst().template GetId<format>();
1444
1445 LOG_INST() << "newarr v" << vd << ", v" << vs << ", " << std::hex << "0x" << id;
1446
1447 int32_t size = this->GetFrame()->GetVReg(vs).Get();
1448
1449 if (UNLIKELY(size < 0)) {
1450 RuntimeIfaceT::ThrowNegativeArraySizeException(size);
1451 this->MoveToExceptionHandler();
1452 } else {
1453 Class *klass = ResolveType<true>(id);
1454 if (LIKELY(klass != nullptr)) {
1455 this->GetFrame()->GetAcc() = this->GetAcc();
1456 coretypes::Array *array = RuntimeIfaceT::CreateArray(klass, size);
1457 this->GetAcc() = this->GetFrame()->GetAcc();
1458 this->GetFrameHandler().GetVReg(vd).SetReference(array);
1459 if (UNLIKELY(array == nullptr)) {
1460 this->MoveToExceptionHandler();
1461 } else {
1462 this->template MoveToNextInst<format, true>();
1463 }
1464 } else {
1465 this->MoveToExceptionHandler();
1466 }
1467 }
1468 }
1469
1470 template <BytecodeInstruction::Format format>
HandleNewobj()1471 ALWAYS_INLINE void HandleNewobj()
1472 {
1473 uint16_t vd = this->GetInst().template GetVReg<format, 0>();
1474 auto id = this->GetInst().template GetId<format>();
1475
1476 LOG_INST() << "newobj v" << vd << std::hex << "0x" << id;
1477
1478 Class *klass = ResolveType<true>(id);
1479 if (LIKELY(klass != nullptr)) {
1480 this->GetFrame()->GetAcc() = this->GetAcc();
1481 ObjectHeader *obj = RuntimeIfaceT::CreateObject(klass);
1482 this->GetAcc() = this->GetFrame()->GetAcc();
1483 if (LIKELY(obj != nullptr)) {
1484 this->GetFrameHandler().GetVReg(vd).SetReference(obj);
1485 this->template MoveToNextInst<format, false>();
1486 } else {
1487 this->MoveToExceptionHandler();
1488 }
1489 } else {
1490 this->MoveToExceptionHandler();
1491 }
1492 }
1493
1494 template <BytecodeInstruction::Format format>
HandleInitobj()1495 ALWAYS_INLINE void HandleInitobj()
1496 {
1497 auto id = this->GetInst().template GetId<format>();
1498
1499 LOG_INST() << "initobj " << this->GetInst().template GetVReg<format, 0>() << ", v"
1500 << this->GetInst().template GetVReg<format, 1>() << ", v"
1501 << this->GetInst().template GetVReg<format, 2>() << ", v"
1502 << this->GetInst().template GetVReg<format, 3>() << ", " << std::hex << "0x" << id;
1503
1504 InitializeObject<format>(id);
1505 }
1506
1507 template <BytecodeInstruction::Format format>
HandleInitobjShort()1508 ALWAYS_INLINE void HandleInitobjShort()
1509 {
1510 auto id = this->GetInst().template GetId<format>();
1511
1512 LOG_INST() << "initobj.short v" << this->GetInst().template GetVReg<format, 0>() << ", v"
1513 << this->GetInst().template GetVReg<format, 1>() << ", " << std::hex << "0x" << id;
1514
1515 InitializeObject<format>(id);
1516 }
1517
1518 template <BytecodeInstruction::Format format>
HandleInitobjRange()1519 ALWAYS_INLINE void HandleInitobjRange()
1520 {
1521 auto id = this->GetInst().template GetId<format>();
1522
1523 LOG_INST() << "initobj.range v" << this->GetInst().template GetVReg<format, 0>() << ", " << std::hex << "0x"
1524 << id;
1525
1526 InitializeObject<format>(id);
1527 }
1528
1529 template <BytecodeInstruction::Format format>
HandleLdobj()1530 ALWAYS_INLINE void HandleLdobj()
1531 {
1532 uint16_t vs = this->GetInst().template GetVReg<format>();
1533 auto id = this->GetInst().template GetId<format>();
1534
1535 LOG_INST() << "ldobj v" << vs << ", " << std::hex << "0x" << id;
1536
1537 ObjectHeader *obj = this->GetFrame()->GetVReg(vs).GetReference();
1538 if (UNLIKELY(obj == nullptr)) {
1539 RuntimeIfaceT::ThrowNullPointerException();
1540 this->MoveToExceptionHandler();
1541 } else {
1542 Field *field = ResolveField(id);
1543 obj = this->GetFrame()->GetVReg(vs).GetReference();
1544 if (LIKELY(field != nullptr)) {
1545 ASSERT(!field->IsStatic());
1546 LoadPrimitiveField(obj, field);
1547 this->template MoveToNextInst<format, true>();
1548 } else {
1549 this->MoveToExceptionHandler();
1550 }
1551 }
1552 }
1553
1554 template <BytecodeInstruction::Format format>
HandleLdobjWide()1555 ALWAYS_INLINE void HandleLdobjWide()
1556 {
1557 uint16_t vs = this->GetInst().template GetVReg<format>();
1558 auto id = this->GetInst().template GetId<format>();
1559
1560 LOG_INST() << "ldobj.64 v" << vs << ", " << std::hex << "0x" << id;
1561
1562 ObjectHeader *obj = this->GetFrame()->GetVReg(vs).GetReference();
1563 if (UNLIKELY(obj == nullptr)) {
1564 RuntimeIfaceT::ThrowNullPointerException();
1565 this->MoveToExceptionHandler();
1566 } else {
1567 Field *field = ResolveField(id);
1568 obj = this->GetFrame()->GetVReg(vs).GetReference();
1569 if (LIKELY(field != nullptr)) {
1570 ASSERT(!field->IsStatic());
1571 LoadPrimitiveField(obj, field);
1572 this->template MoveToNextInst<format, true>();
1573 } else {
1574 this->MoveToExceptionHandler();
1575 }
1576 }
1577 }
1578
1579 template <BytecodeInstruction::Format format>
HandleLdobjObj()1580 ALWAYS_INLINE void HandleLdobjObj()
1581 {
1582 uint16_t vs = this->GetInst().template GetVReg<format>();
1583 auto id = this->GetInst().template GetId<format>();
1584
1585 LOG_INST() << "ldobj.obj v" << vs << ", " << std::hex << "0x" << id;
1586
1587 ObjectHeader *obj = this->GetFrame()->GetVReg(vs).GetReference();
1588 if (UNLIKELY(obj == nullptr)) {
1589 RuntimeIfaceT::ThrowNullPointerException();
1590 this->MoveToExceptionHandler();
1591 } else {
1592 Field *field = ResolveField(id);
1593 obj = this->GetFrame()->GetVReg(vs).GetReference();
1594 if (LIKELY(field != nullptr)) {
1595 ASSERT(!field->IsStatic());
1596 ASSERT(field->GetType().IsReference());
1597 this->GetAccAsVReg().SetReference(
1598 obj->GetFieldObject<RuntimeIfaceT::NEED_READ_BARRIER>(this->GetThread(), *field));
1599 this->template MoveToNextInst<format, true>();
1600 } else {
1601 this->MoveToExceptionHandler();
1602 }
1603 }
1604 }
1605
1606 template <BytecodeInstruction::Format format>
HandleLdobjV()1607 ALWAYS_INLINE void HandleLdobjV()
1608 {
1609 uint16_t vd = this->GetInst().template GetVReg<format, 0>();
1610 uint16_t vs = this->GetInst().template GetVReg<format, 1>();
1611 auto id = this->GetInst().template GetId<format>();
1612
1613 LOG_INST() << "ldobj.v v" << vd << ", v" << vs << ", " << std::hex << "0x" << id;
1614
1615 ObjectHeader *obj = this->GetFrame()->GetVReg(vs).GetReference();
1616 if (UNLIKELY(obj == nullptr)) {
1617 RuntimeIfaceT::ThrowNullPointerException();
1618 this->MoveToExceptionHandler();
1619 } else {
1620 Field *field = ResolveField(id);
1621 obj = this->GetFrame()->GetVReg(vs).GetReference();
1622 if (LIKELY(field != nullptr)) {
1623 ASSERT(!field->IsStatic());
1624 auto vreg = this->GetFrameHandler().GetVReg(vd);
1625 LoadPrimitiveFieldReg(vreg, obj, field);
1626 this->template MoveToNextInst<format, true>();
1627 } else {
1628 this->MoveToExceptionHandler();
1629 }
1630 }
1631 }
1632
1633 template <BytecodeInstruction::Format format>
HandleLdobjVWide()1634 ALWAYS_INLINE void HandleLdobjVWide()
1635 {
1636 uint16_t vd = this->GetInst().template GetVReg<format, 0>();
1637 uint16_t vs = this->GetInst().template GetVReg<format, 1>();
1638 auto id = this->GetInst().template GetId<format>();
1639
1640 LOG_INST() << "ldobj.v.64 v" << vd << ", v" << vs << ", " << std::hex << "0x" << id;
1641
1642 ObjectHeader *obj = this->GetFrame()->GetVReg(vs).GetReference();
1643 if (UNLIKELY(obj == nullptr)) {
1644 RuntimeIfaceT::ThrowNullPointerException();
1645 this->MoveToExceptionHandler();
1646 } else {
1647 Field *field = ResolveField(id);
1648 obj = this->GetFrame()->GetVReg(vs).GetReference();
1649 if (LIKELY(field != nullptr)) {
1650 ASSERT(!field->IsStatic());
1651 auto vreg = this->GetFrameHandler().GetVReg(vd);
1652 LoadPrimitiveFieldReg(vreg, obj, field);
1653 this->template MoveToNextInst<format, true>();
1654 } else {
1655 this->MoveToExceptionHandler();
1656 }
1657 }
1658 }
1659
1660 template <BytecodeInstruction::Format format>
HandleLdobjVObj()1661 ALWAYS_INLINE void HandleLdobjVObj()
1662 {
1663 uint16_t vd = this->GetInst().template GetVReg<format, 0>();
1664 uint16_t vs = this->GetInst().template GetVReg<format, 1>();
1665 auto id = this->GetInst().template GetId<format>();
1666
1667 LOG_INST() << "ldobj.v.obj v" << vd << ", v" << vs << ", " << std::hex << "0x" << id;
1668
1669 ObjectHeader *obj = this->GetFrame()->GetVReg(vs).GetReference();
1670 if (UNLIKELY(obj == nullptr)) {
1671 RuntimeIfaceT::ThrowNullPointerException();
1672 this->MoveToExceptionHandler();
1673 } else {
1674 Field *field = ResolveField(id);
1675 obj = this->GetFrame()->GetVReg(vs).GetReference();
1676 if (LIKELY(field != nullptr)) {
1677 ASSERT(!field->IsStatic());
1678 ASSERT(field->GetType().IsReference());
1679 this->GetFrameHandler().GetVReg(vd).SetReference(
1680 obj->GetFieldObject<RuntimeIfaceT::NEED_READ_BARRIER>(this->GetThread(), *field));
1681 this->template MoveToNextInst<format, true>();
1682 } else {
1683 this->MoveToExceptionHandler();
1684 }
1685 }
1686 }
1687
1688 template <BytecodeInstruction::Format format>
HandleStobj()1689 ALWAYS_INLINE void HandleStobj()
1690 {
1691 uint16_t vs = this->GetInst().template GetVReg<format>();
1692 auto id = this->GetInst().template GetId<format>();
1693
1694 LOG_INST() << "stobj v" << vs << ", " << std::hex << "0x" << id;
1695
1696 ObjectHeader *obj = this->GetFrame()->GetVReg(vs).GetReference();
1697 if (UNLIKELY(obj == nullptr)) {
1698 RuntimeIfaceT::ThrowNullPointerException();
1699 this->MoveToExceptionHandler();
1700 } else {
1701 Field *field = ResolveField(id);
1702 obj = this->GetFrame()->GetVReg(vs).GetReference();
1703 if (LIKELY(field != nullptr)) {
1704 ASSERT(!field->IsStatic());
1705 StorePrimitiveField(obj, field);
1706 this->template MoveToNextInst<format, true>();
1707 } else {
1708 this->MoveToExceptionHandler();
1709 }
1710 }
1711 }
1712
1713 template <BytecodeInstruction::Format format>
HandleStobjWide()1714 ALWAYS_INLINE void HandleStobjWide()
1715 {
1716 uint16_t vs = this->GetInst().template GetVReg<format>();
1717 auto id = this->GetInst().template GetId<format>();
1718
1719 LOG_INST() << "stobj.64 v" << vs << ", " << std::hex << "0x" << id;
1720
1721 ObjectHeader *obj = this->GetFrame()->GetVReg(vs).GetReference();
1722 if (UNLIKELY(obj == nullptr)) {
1723 RuntimeIfaceT::ThrowNullPointerException();
1724 this->MoveToExceptionHandler();
1725 } else {
1726 Field *field = ResolveField(id);
1727 obj = this->GetFrame()->GetVReg(vs).GetReference();
1728 if (LIKELY(field != nullptr)) {
1729 ASSERT(!field->IsStatic());
1730 StorePrimitiveField(obj, field);
1731 this->template MoveToNextInst<format, true>();
1732 } else {
1733 this->MoveToExceptionHandler();
1734 }
1735 }
1736 }
1737
1738 template <BytecodeInstruction::Format format>
HandleStobjObj()1739 ALWAYS_INLINE void HandleStobjObj()
1740 {
1741 uint16_t vs = this->GetInst().template GetVReg<format>();
1742 auto id = this->GetInst().template GetId<format>();
1743
1744 LOG_INST() << "stobj.obj v" << vs << ", " << std::hex << "0x" << id;
1745
1746 ObjectHeader *obj = this->GetFrame()->GetVReg(vs).GetReference();
1747 if (UNLIKELY(obj == nullptr)) {
1748 RuntimeIfaceT::ThrowNullPointerException();
1749 this->MoveToExceptionHandler();
1750 } else {
1751 Field *field = ResolveField(id);
1752 obj = this->GetFrame()->GetVReg(vs).GetReference();
1753 if (LIKELY(field != nullptr)) {
1754 ASSERT(!field->IsStatic());
1755 ASSERT(field->GetType().IsReference());
1756 obj->SetFieldObject<RuntimeIfaceT::NEED_WRITE_BARRIER>(this->GetThread(), *field,
1757 this->GetAcc().GetReference());
1758 this->template MoveToNextInst<format, true>();
1759 } else {
1760 this->MoveToExceptionHandler();
1761 }
1762 }
1763 }
1764
1765 template <BytecodeInstruction::Format format>
HandleStobjV()1766 ALWAYS_INLINE void HandleStobjV()
1767 {
1768 uint16_t vd = this->GetInst().template GetVReg<format, 0>();
1769 uint16_t vs = this->GetInst().template GetVReg<format, 1>();
1770 auto id = this->GetInst().template GetId<format>();
1771
1772 LOG_INST() << "stobj.v v" << vd << ", v" << vs << ", " << std::hex << "0x" << id;
1773
1774 ObjectHeader *obj = this->GetFrame()->GetVReg(vs).GetReference();
1775 if (UNLIKELY(obj == nullptr)) {
1776 RuntimeIfaceT::ThrowNullPointerException();
1777 this->MoveToExceptionHandler();
1778 } else {
1779 Field *field = ResolveField(id);
1780 obj = this->GetFrame()->GetVReg(vs).GetReference();
1781 if (LIKELY(field != nullptr)) {
1782 ASSERT(!field->IsStatic());
1783 StorePrimitiveFieldReg(this->GetFrame()->GetVReg(vd), obj, field);
1784 this->template MoveToNextInst<format, true>();
1785 } else {
1786 this->MoveToExceptionHandler();
1787 }
1788 }
1789 }
1790
1791 template <BytecodeInstruction::Format format>
HandleStobjVWide()1792 ALWAYS_INLINE void HandleStobjVWide()
1793 {
1794 uint16_t vd = this->GetInst().template GetVReg<format, 0>();
1795 uint16_t vs = this->GetInst().template GetVReg<format, 1>();
1796 auto id = this->GetInst().template GetId<format>();
1797
1798 LOG_INST() << "stobj.v.64 v" << vd << ", v" << vs << ", " << std::hex << "0x" << id;
1799
1800 ObjectHeader *obj = this->GetFrame()->GetVReg(vs).GetReference();
1801 if (UNLIKELY(obj == nullptr)) {
1802 RuntimeIfaceT::ThrowNullPointerException();
1803 this->MoveToExceptionHandler();
1804 } else {
1805 Field *field = ResolveField(id);
1806 obj = this->GetFrame()->GetVReg(vs).GetReference();
1807 if (LIKELY(field != nullptr)) {
1808 ASSERT(!field->IsStatic());
1809 StorePrimitiveFieldReg(this->GetFrame()->GetVReg(vd), obj, field);
1810 this->template MoveToNextInst<format, true>();
1811 } else {
1812 this->MoveToExceptionHandler();
1813 }
1814 }
1815 }
1816
1817 template <BytecodeInstruction::Format format>
HandleStobjVObj()1818 ALWAYS_INLINE void HandleStobjVObj()
1819 {
1820 uint16_t vd = this->GetInst().template GetVReg<format, 0>();
1821 uint16_t vs = this->GetInst().template GetVReg<format, 1>();
1822 auto id = this->GetInst().template GetId<format>();
1823
1824 LOG_INST() << "stobj.v.obj v" << vd << ", v" << vs << ", " << std::hex << "0x" << id;
1825
1826 ObjectHeader *obj = this->GetFrame()->GetVReg(vs).GetReference();
1827 if (UNLIKELY(obj == nullptr)) {
1828 RuntimeIfaceT::ThrowNullPointerException();
1829 this->MoveToExceptionHandler();
1830 } else {
1831 Field *field = ResolveField(id);
1832 obj = this->GetFrame()->GetVReg(vs).GetReference();
1833 if (LIKELY(field != nullptr)) {
1834 ASSERT(!field->IsStatic());
1835 ASSERT(field->GetType().IsReference());
1836 obj->SetFieldObject<RuntimeIfaceT::NEED_WRITE_BARRIER>(this->GetThread(), *field,
1837 this->GetFrame()->GetVReg(vd).GetReference());
1838 this->template MoveToNextInst<format, true>();
1839 } else {
1840 this->MoveToExceptionHandler();
1841 }
1842 }
1843 }
1844
1845 template <BytecodeInstruction::Format format>
HandleLdstatic()1846 ALWAYS_INLINE void HandleLdstatic()
1847 {
1848 auto id = this->GetInst().template GetId<format>();
1849
1850 LOG_INST() << "ldstatic " << std::hex << "0x" << id;
1851
1852 Field *field = ResolveField<true>(id);
1853 if (LIKELY(field != nullptr)) {
1854 ASSERT(field->IsStatic());
1855 LoadPrimitiveField(GetClass(field), field);
1856 this->template MoveToNextInst<format, false>();
1857 } else {
1858 this->MoveToExceptionHandler();
1859 }
1860 }
1861
1862 template <BytecodeInstruction::Format format>
HandleLdstaticWide()1863 ALWAYS_INLINE void HandleLdstaticWide()
1864 {
1865 auto id = this->GetInst().template GetId<format>();
1866
1867 LOG_INST() << "ldstatic.64 " << std::hex << "0x" << id;
1868
1869 Field *field = ResolveField<true>(id);
1870 if (LIKELY(field != nullptr)) {
1871 ASSERT(field->IsStatic());
1872 LoadPrimitiveField(GetClass(field), field);
1873 this->template MoveToNextInst<format, false>();
1874 } else {
1875 this->MoveToExceptionHandler();
1876 }
1877 }
1878
1879 template <BytecodeInstruction::Format format>
HandleLdstaticObj()1880 ALWAYS_INLINE void HandleLdstaticObj()
1881 {
1882 auto id = this->GetInst().template GetId<format>();
1883
1884 LOG_INST() << "ldstatic.obj " << std::hex << "0x" << id;
1885
1886 Field *field = ResolveField<true>(id);
1887 if (LIKELY(field != nullptr)) {
1888 ASSERT(field->IsStatic());
1889 Class *klass = GetClass(field);
1890 ASSERT(field->GetType().IsReference());
1891 this->GetAccAsVReg().SetReference(
1892 klass->GetFieldObject<RuntimeIfaceT::NEED_READ_BARRIER>(this->GetThread(), *field));
1893 this->template MoveToNextInst<format, false>();
1894 } else {
1895 this->MoveToExceptionHandler();
1896 }
1897 }
1898
1899 template <BytecodeInstruction::Format format>
HandleStstatic()1900 ALWAYS_INLINE void HandleStstatic()
1901 {
1902 auto id = this->GetInst().template GetId<format>();
1903
1904 LOG_INST() << "ststatic " << std::hex << "0x" << id;
1905
1906 Field *field = ResolveField<true>(id);
1907 if (LIKELY(field != nullptr)) {
1908 ASSERT(field->IsStatic());
1909 Class *klass = GetClass(field);
1910 StorePrimitiveField(klass, field);
1911 this->template MoveToNextInst<format, false>();
1912 } else {
1913 this->MoveToExceptionHandler();
1914 }
1915 }
1916
1917 template <BytecodeInstruction::Format format>
HandleStstaticWide()1918 ALWAYS_INLINE void HandleStstaticWide()
1919 {
1920 auto id = this->GetInst().template GetId<format>();
1921
1922 LOG_INST() << "ststatic.64 " << std::hex << "0x" << id;
1923
1924 Field *field = ResolveField<true>(id);
1925 if (LIKELY(field != nullptr)) {
1926 ASSERT(field->IsStatic());
1927 Class *klass = GetClass(field);
1928 StorePrimitiveField(klass, field);
1929 this->template MoveToNextInst<format, false>();
1930 } else {
1931 this->MoveToExceptionHandler();
1932 }
1933 }
1934
1935 template <BytecodeInstruction::Format format>
HandleStstaticObj()1936 ALWAYS_INLINE void HandleStstaticObj()
1937 {
1938 auto id = this->GetInst().template GetId<format>();
1939
1940 LOG_INST() << "ststatic.obj " << std::hex << "0x" << id;
1941
1942 Field *field = ResolveField<true>(id);
1943 if (LIKELY(field != nullptr)) {
1944 ASSERT(field->IsStatic());
1945 Class *klass = GetClass(field);
1946 ASSERT(field->GetType().IsReference());
1947 klass->SetFieldObject<RuntimeIfaceT::NEED_WRITE_BARRIER>(this->GetThread(), *field,
1948 this->GetAcc().GetReference());
1949 this->template MoveToNextInst<format, false>();
1950 } else {
1951 this->MoveToExceptionHandler();
1952 }
1953 }
1954
1955 template <BytecodeInstruction::Format format>
HandleReturn()1956 ALWAYS_INLINE void HandleReturn()
1957 {
1958 LOG_INST() << "return";
1959 this->GetFrame()->GetAccAsVReg().SetPrimitive(this->GetAcc().Get());
1960 }
1961
1962 template <BytecodeInstruction::Format format>
HandleReturnWide()1963 ALWAYS_INLINE void HandleReturnWide()
1964 {
1965 LOG_INST() << "return.64";
1966 this->GetFrame()->GetAccAsVReg().SetPrimitive(this->GetAcc().GetValue());
1967 }
1968
1969 template <BytecodeInstruction::Format format>
HandleReturnObj()1970 ALWAYS_INLINE void HandleReturnObj()
1971 {
1972 LOG_INST() << "return.obj";
1973 this->GetFrame()->GetAccAsVReg().SetReference(this->GetAcc().GetReference());
1974 }
1975
1976 template <BytecodeInstruction::Format format>
HandleReturnVoid()1977 ALWAYS_INLINE void HandleReturnVoid()
1978 {
1979 LOG_INST() << "return.void";
1980 }
1981
1982 template <BytecodeInstruction::Format format>
DoReturnDyn()1983 ALWAYS_INLINE void DoReturnDyn()
1984 {
1985 this->GetFrame()->SetAcc((this->GetAcc()));
1986 }
1987
1988 template <BytecodeInstruction::Format format>
HandleReturnDyn()1989 ALWAYS_INLINE void HandleReturnDyn()
1990 {
1991 LOG_INST() << "return.dyn";
1992 DoReturnDyn<format>();
1993 }
1994
HandleReturnStackless()1995 ALWAYS_INLINE void HandleReturnStackless()
1996 {
1997 Frame *frame = this->GetFrame();
1998 Frame *prev = frame->GetPrevFrame();
1999
2000 ASSERT(frame->IsStackless());
2001
2002 Method *method = frame->GetMethod();
2003 ManagedThread *thread = this->GetThread();
2004
2005 #if EVENT_METHOD_EXIT_ENABLED
2006 EVENT_METHOD_EXIT(frame->GetMethod()->GetFullName(), events::MethodExitKind::INTERP,
2007 thread->RecordMethodExit());
2008 #endif
2009
2010 Runtime::GetCurrent()->GetNotificationManager()->MethodExitEvent(thread, method);
2011
2012 this->GetInstructionHandlerState()->UpdateInstructionHandlerState(
2013 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
2014 prev->GetInstruction() + prev->GetBytecodeOffset(), prev);
2015
2016 this->SetDispatchTable(this->GetThread()->GetCurrentDispatchTable());
2017 RuntimeIfaceT::SetCurrentFrame(thread, prev);
2018
2019 if (UNLIKELY(this->GetThread()->HasPendingException())) {
2020 this->MoveToExceptionHandler();
2021 } else {
2022 this->GetAcc() = frame->GetAcc();
2023 this->SetInst(prev->GetNextInstruction());
2024 }
2025
2026 if (frame->IsInitobj()) {
2027 this->GetAcc() = prev->GetAcc();
2028 }
2029
2030 RuntimeIfaceT::FreeFrame(this->GetThread(), frame);
2031
2032 LOG(DEBUG, INTERPRETER) << "Exit: Runtime Call.";
2033 }
2034
HandleInstrumentForceReturn()2035 ALWAYS_INLINE void HandleInstrumentForceReturn()
2036 {
2037 HandleReturnStackless();
2038 }
2039
2040 template <BytecodeInstruction::Format format>
HandleCheckcast()2041 ALWAYS_INLINE void HandleCheckcast()
2042 {
2043 auto type_id = this->GetInst().template GetId<format>();
2044
2045 LOG_INST() << "checkcast " << std::hex << "0x" << type_id;
2046
2047 Class *type = ResolveType(type_id);
2048 if (LIKELY(type != nullptr)) {
2049 ObjectHeader *obj = this->GetAcc().GetReference();
2050
2051 if (UNLIKELY(obj != nullptr && !type->IsAssignableFrom(obj->ClassAddr<Class>()))) {
2052 RuntimeIfaceT::ThrowClassCastException(type, obj->ClassAddr<Class>());
2053 this->MoveToExceptionHandler();
2054 } else {
2055 this->template MoveToNextInst<format, true>();
2056 }
2057 } else {
2058 this->MoveToExceptionHandler();
2059 }
2060 }
2061
2062 template <BytecodeInstruction::Format format>
HandleIsinstance()2063 ALWAYS_INLINE void HandleIsinstance()
2064 {
2065 auto type_id = this->GetInst().template GetId<format>();
2066
2067 LOG_INST() << "isinstance " << std::hex << "0x" << type_id;
2068
2069 Class *type = ResolveType(type_id);
2070 if (LIKELY(type != nullptr)) {
2071 ObjectHeader *obj = this->GetAcc().GetReference();
2072
2073 if (obj != nullptr && type->IsAssignableFrom(obj->ClassAddr<Class>())) {
2074 this->GetAccAsVReg().SetPrimitive(1);
2075 } else {
2076 this->GetAccAsVReg().SetPrimitive(0);
2077 }
2078 this->template MoveToNextInst<format, false>();
2079 } else {
2080 this->MoveToExceptionHandler();
2081 }
2082 }
2083
2084 template <BytecodeInstruction::Format format>
HandleCallShort()2085 ALWAYS_INLINE void HandleCallShort()
2086 {
2087 auto id = this->GetInst().template GetId<format>();
2088
2089 LOG_INST() << "call.short v" << this->GetInst().template GetVReg<format, 0>() << ", v"
2090 << this->GetInst().template GetVReg<format, 1>() << ", " << std::hex << "0x" << id;
2091
2092 auto *method = ResolveMethod(id);
2093 if (LIKELY(method != nullptr)) {
2094 if (!method->IsStatic() && this->GetCallerObject<format>() == nullptr) {
2095 return;
2096 }
2097 HandleCall<FrameHelperDefault, format>(method);
2098 } else {
2099 this->MoveToExceptionHandler();
2100 }
2101 }
2102
2103 template <BytecodeInstruction::Format format>
HandleCallAccShort()2104 ALWAYS_INLINE void HandleCallAccShort()
2105 {
2106 auto id = this->GetInst().template GetId<format>();
2107
2108 LOG_INST() << "call.acc.short v" << this->GetInst().template GetVReg<format, 0>() << ", "
2109 << this->GetInst().template GetImm<format, 0>() << ", " << std::hex << "0x" << id;
2110
2111 auto *method = ResolveMethod(id);
2112 if (LIKELY(method != nullptr)) {
2113 if (!method->IsStatic() && this->GetCallerObject<format, true>() == nullptr) {
2114 return;
2115 }
2116 HandleCall<FrameHelperDefault, format, false, false, true>(method);
2117 } else {
2118 this->MoveToExceptionHandler();
2119 }
2120 }
2121
2122 template <BytecodeInstruction::Format format>
HandleCall()2123 ALWAYS_INLINE void HandleCall()
2124 {
2125 auto id = this->GetInst().template GetId<format>();
2126
2127 LOG_INST() << "call v" << this->GetInst().template GetVReg<format, 0>() << ", v"
2128 << this->GetInst().template GetVReg<format, 1>() << ", v"
2129 << this->GetInst().template GetVReg<format, 2>() << ", v"
2130 << this->GetInst().template GetVReg<format, 3>() << ", " << std::hex << "0x" << id;
2131
2132 auto *method = ResolveMethod(id);
2133 if (LIKELY(method != nullptr)) {
2134 if (!method->IsStatic() && this->GetCallerObject<format>() == nullptr) {
2135 return;
2136 }
2137 HandleCall<FrameHelperDefault, format>(method);
2138 } else {
2139 this->MoveToExceptionHandler();
2140 }
2141 }
2142
2143 template <BytecodeInstruction::Format format>
HandleCallAcc()2144 ALWAYS_INLINE void HandleCallAcc()
2145 {
2146 auto id = this->GetInst().template GetId<format>();
2147
2148 LOG_INST() << "call.acc v" << this->GetInst().template GetVReg<format, 0>() << ", v"
2149 << this->GetInst().template GetVReg<format, 1>() << ", v"
2150 << this->GetInst().template GetVReg<format, 2>() << ", "
2151 << this->GetInst().template GetImm<format, 0>() << ", " << std::hex << "0x" << id;
2152
2153 auto *method = ResolveMethod(id);
2154 if (LIKELY(method != nullptr)) {
2155 if (!method->IsStatic() && this->GetCallerObject<format, true>() == nullptr) {
2156 return;
2157 }
2158 HandleCall<FrameHelperDefault, format, false, false, true>(method);
2159 } else {
2160 this->MoveToExceptionHandler();
2161 }
2162 }
2163
2164 template <BytecodeInstruction::Format format>
HandleCallRange()2165 ALWAYS_INLINE void HandleCallRange()
2166 {
2167 auto id = this->GetInst().template GetId<format>();
2168
2169 LOG_INST() << "call.range v" << this->GetInst().template GetVReg<format, 0>() << ", " << std::hex << "0x" << id;
2170
2171 auto *method = ResolveMethod(id);
2172 if (LIKELY(method != nullptr)) {
2173 if (!method->IsStatic() && this->GetCallerObject<format>() == nullptr) {
2174 return;
2175 }
2176 HandleCall<FrameHelperDefault, format, false, true>(method);
2177 } else {
2178 this->MoveToExceptionHandler();
2179 }
2180 }
2181
2182 template <BytecodeInstruction::Format format>
HandleCallVirtShort()2183 ALWAYS_INLINE void HandleCallVirtShort()
2184 {
2185 auto id = this->GetInst().template GetId<format>();
2186
2187 LOG_INST() << "call.virt.short v" << this->GetInst().template GetVReg<format, 0>() << ", v"
2188 << this->GetInst().template GetVReg<format, 1>() << ", " << std::hex << "0x" << id;
2189
2190 auto *method = ResolveMethod(id);
2191 if (LIKELY(method != nullptr)) {
2192 HandleVirtualCall<format>(method);
2193 } else {
2194 this->MoveToExceptionHandler();
2195 }
2196 }
2197
2198 template <BytecodeInstruction::Format format>
HandleCallVirtAccShort()2199 ALWAYS_INLINE void HandleCallVirtAccShort()
2200 {
2201 auto id = this->GetInst().template GetId<format>();
2202
2203 LOG_INST() << "call.virt.acc.short v" << this->GetInst().template GetVReg<format, 0>() << ", "
2204 << this->GetInst().template GetImm<format, 0>() << ", " << std::hex << "0x" << id;
2205
2206 auto *method = ResolveMethod(id);
2207 if (LIKELY(method != nullptr)) {
2208 HandleVirtualCall<format, false, true>(method);
2209 } else {
2210 this->MoveToExceptionHandler();
2211 }
2212 }
2213
2214 template <BytecodeInstruction::Format format>
HandleCallVirt()2215 ALWAYS_INLINE void HandleCallVirt()
2216 {
2217 auto id = this->GetInst().template GetId<format>();
2218
2219 LOG_INST() << "call.virt v" << this->GetInst().template GetVReg<format, 0>() << ", v"
2220 << this->GetInst().template GetVReg<format, 1>() << ", v"
2221 << this->GetInst().template GetVReg<format, 2>() << ", v"
2222 << this->GetInst().template GetVReg<format, 3>() << ", " << std::hex << "0x" << id;
2223
2224 auto *method = ResolveMethod(id);
2225 if (LIKELY(method != nullptr)) {
2226 HandleVirtualCall<format>(method);
2227 } else {
2228 this->MoveToExceptionHandler();
2229 }
2230 }
2231
2232 template <BytecodeInstruction::Format format>
HandleCallVirtAcc()2233 ALWAYS_INLINE void HandleCallVirtAcc()
2234 {
2235 auto id = this->GetInst().template GetId<format>();
2236
2237 LOG_INST() << "call.virt.acc v" << this->GetInst().template GetVReg<format, 0>() << ", v"
2238 << this->GetInst().template GetVReg<format, 1>() << ", v"
2239 << this->GetInst().template GetVReg<format, 2>() << ", "
2240 << this->GetInst().template GetImm<format, 0>() << ", " << std::hex << "0x" << id;
2241
2242 auto *method = ResolveMethod(id);
2243 if (LIKELY(method != nullptr)) {
2244 HandleVirtualCall<format, false, true>(method);
2245 } else {
2246 this->MoveToExceptionHandler();
2247 }
2248 }
2249
2250 template <BytecodeInstruction::Format format>
HandleCallVirtRange()2251 ALWAYS_INLINE void HandleCallVirtRange()
2252 {
2253 auto id = this->GetInst().template GetId<format>();
2254
2255 LOG_INST() << "call.virt.range v" << this->GetInst().template GetVReg<format, 0>() << ", " << std::hex << "0x"
2256 << id;
2257
2258 auto *method = ResolveMethod(id);
2259 if (LIKELY(method != nullptr)) {
2260 HandleVirtualCall<format, true>(method);
2261 } else {
2262 this->MoveToExceptionHandler();
2263 }
2264 }
2265
2266 template <BytecodeInstruction::Format format>
HandleCalliDynRange()2267 ALWAYS_INLINE void HandleCalliDynRange()
2268 {
2269 auto actual_num_args = static_cast<uint16_t>(this->GetInst().template GetImm<format, 0>());
2270 auto first_arg_reg_idx = static_cast<uint16_t>(this->GetInst().template GetVReg<format, 0>());
2271
2272 LOG_INST() << "calli.dyn.range " << actual_num_args << ", v" << first_arg_reg_idx;
2273
2274 auto vreg = this->GetFrameHandler().GetVReg(first_arg_reg_idx);
2275
2276 if (!vreg.HasObject()) {
2277 RuntimeInterface::ThrowTypedErrorDyn("is not object");
2278 this->MoveToExceptionHandler();
2279 return;
2280 }
2281 auto obj = reinterpret_cast<ObjectHeader *>(vreg.GetLong());
2282 auto ctx = this->GetThread()->GetLanguageContext();
2283 if (!ctx.IsCallableObject(obj)) {
2284 RuntimeInterface::ThrowTypedErrorDyn("is not callable");
2285 this->MoveToExceptionHandler();
2286 return;
2287 }
2288
2289 HandleCall<FrameHelperDefault, format, true, true>(ctx.GetCallTarget(obj));
2290 }
2291
2292 template <BytecodeInstruction::Format format>
HandleThrow()2293 ALWAYS_INLINE void HandleThrow()
2294 {
2295 uint16_t vs = this->GetInst().template GetVReg<format>();
2296
2297 LOG_INST() << "throw v" << vs;
2298
2299 ObjectHeader *exception = this->GetFrame()->GetVReg(vs).GetReference();
2300 if (UNLIKELY(exception == nullptr)) {
2301 RuntimeIfaceT::ThrowNullPointerException();
2302 } else {
2303 this->GetThread()->SetException(exception);
2304 }
2305
2306 this->MoveToExceptionHandler();
2307 }
2308
FindCatchBlockStackless()2309 ALWAYS_INLINE uint32_t FindCatchBlockStackless()
2310 {
2311 Frame *frame = this->GetFrame();
2312 while (frame != nullptr) {
2313 ManagedThread *thread = this->GetThread();
2314 Frame *prev = frame->GetPrevFrame();
2315
2316 ASSERT(thread->HasPendingException());
2317
2318 uint32_t pc_offset = this->FindCatchBlock(thread->GetException(), this->GetBytecodeOffset());
2319
2320 if (pc_offset != panda_file::INVALID_OFFSET) {
2321 return pc_offset;
2322 }
2323
2324 if (!frame->IsStackless() || prev == nullptr ||
2325 StackWalker::IsBoundaryFrame<FrameKind::INTERPRETER>(prev)) {
2326 return pc_offset;
2327 }
2328
2329 Method *method = frame->GetMethod();
2330 EVENT_METHOD_EXIT(method->GetFullName(), events::MethodExitKind::INTERP, thread->RecordMethodExit());
2331
2332 Runtime::GetCurrent()->GetNotificationManager()->MethodExitEvent(thread, method);
2333
2334 this->GetInstructionHandlerState()->UpdateInstructionHandlerState(
2335 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
2336 prev->GetInstruction() + prev->GetBytecodeOffset(), prev);
2337
2338 thread->GetVM()->HandleReturnFrame();
2339
2340 RuntimeIfaceT::SetCurrentFrame(thread, prev);
2341
2342 ASSERT(thread->HasPendingException());
2343
2344 if (frame->IsInitobj()) {
2345 this->GetAcc() = prev->GetAcc();
2346 }
2347
2348 RuntimeIfaceT::FreeFrame(this->GetThread(), frame);
2349
2350 LOG(DEBUG, INTERPRETER) << "Exit: Runtime Call.";
2351
2352 frame = prev;
2353 }
2354 return panda_file::INVALID_OFFSET;
2355 }
2356
IsCompilerEnableJit()2357 ALWAYS_INLINE static bool IsCompilerEnableJit()
2358 {
2359 return !Runtime::GetCurrent()->IsDebugMode() && RuntimeIfaceT::IsCompilerEnableJit();
2360 }
2361
UpdateHotnessOSR(Method * method,int offset)2362 ALWAYS_INLINE bool UpdateHotnessOSR(Method *method, int offset)
2363 {
2364 ASSERT(ArchTraits<RUNTIME_ARCH>::SUPPORT_OSR);
2365 if (this->GetFrame()->IsDeoptimized() || !Runtime::GetOptions().IsCompilerEnableOsr()) {
2366 method->IncrementHotnessCounter(0, nullptr);
2367 return false;
2368 }
2369 return method->IncrementHotnessCounter(this->GetBytecodeOffset() + offset, &this->GetAcc(), true);
2370 }
2371
FindCatchBlock(ObjectHeader * exception,uint32_t pc)2372 uint32_t FindCatchBlock(ObjectHeader *exception, uint32_t pc) const
2373 {
2374 auto *method = this->GetFrame()->GetMethod();
2375 return RuntimeIfaceT::FindCatchBlock(*method, exception, pc);
2376 }
2377
2378 template <class T>
GetClass(const T * entity)2379 ALWAYS_INLINE Class *GetClass(const T *entity)
2380 {
2381 auto *klass = entity->GetClass();
2382
2383 // Whenever we obtain a class by a field, method, etc.,
2384 // we expect it to be either fully initialized or in process
2385 // of initialization (e.g. during executing a cctor).
2386 ASSERT(klass != nullptr);
2387 ASSERT(klass->IsInitializing() || klass->IsInitialized());
2388
2389 return klass;
2390 }
2391
2392 template <class F, class T, class R>
LoadPrimitiveFieldReg(R & vreg,T * obj,Field * field)2393 ALWAYS_INLINE void LoadPrimitiveFieldReg(R &vreg, T *obj, Field *field)
2394 {
2395 auto value = static_cast<int64_t>(obj->template GetFieldPrimitive<F>(*field));
2396 vreg.SetPrimitive(value);
2397 }
2398
2399 template <class T, class R>
LoadPrimitiveFieldReg(R & vreg,T * obj,Field * field)2400 ALWAYS_INLINE void LoadPrimitiveFieldReg(R &vreg, T *obj, Field *field)
2401 {
2402 switch (field->GetTypeId()) {
2403 case panda_file::Type::TypeId::U1:
2404 case panda_file::Type::TypeId::U8:
2405 LoadPrimitiveFieldReg<uint8_t>(vreg, obj, field);
2406 break;
2407 case panda_file::Type::TypeId::I8:
2408 LoadPrimitiveFieldReg<int8_t>(vreg, obj, field);
2409 break;
2410 case panda_file::Type::TypeId::I16:
2411 LoadPrimitiveFieldReg<int16_t>(vreg, obj, field);
2412 break;
2413 case panda_file::Type::TypeId::U16:
2414 LoadPrimitiveFieldReg<uint16_t>(vreg, obj, field);
2415 break;
2416 case panda_file::Type::TypeId::I32:
2417 LoadPrimitiveFieldReg<int32_t>(vreg, obj, field);
2418 break;
2419 case panda_file::Type::TypeId::U32:
2420 LoadPrimitiveFieldReg<uint32_t>(vreg, obj, field);
2421 break;
2422 case panda_file::Type::TypeId::I64:
2423 LoadPrimitiveFieldReg<int64_t>(vreg, obj, field);
2424 break;
2425 case panda_file::Type::TypeId::U64:
2426 LoadPrimitiveFieldReg<uint64_t>(vreg, obj, field);
2427 break;
2428 case panda_file::Type::TypeId::F32:
2429 vreg.SetPrimitive(obj->template GetFieldPrimitive<float>(*field));
2430 break;
2431 case panda_file::Type::TypeId::F64:
2432 vreg.SetPrimitive(obj->template GetFieldPrimitive<double>(*field));
2433 break;
2434 default:
2435 UNREACHABLE();
2436 break;
2437 }
2438 }
2439
2440 template <class F, class T>
LoadPrimitiveField(T * obj,Field * field)2441 ALWAYS_INLINE void LoadPrimitiveField(T *obj, Field *field)
2442 {
2443 auto value = static_cast<int64_t>(obj->template GetFieldPrimitive<F>(*field));
2444 this->GetAccAsVReg().SetPrimitive(value);
2445 }
2446
2447 template <class T>
LoadPrimitiveField(T * obj,Field * field)2448 ALWAYS_INLINE void LoadPrimitiveField(T *obj, Field *field)
2449 {
2450 switch (field->GetTypeId()) {
2451 case panda_file::Type::TypeId::U1:
2452 case panda_file::Type::TypeId::U8:
2453 LoadPrimitiveField<uint8_t>(obj, field);
2454 break;
2455 case panda_file::Type::TypeId::I8:
2456 LoadPrimitiveField<int8_t>(obj, field);
2457 break;
2458 case panda_file::Type::TypeId::I16:
2459 LoadPrimitiveField<int16_t>(obj, field);
2460 break;
2461 case panda_file::Type::TypeId::U16:
2462 LoadPrimitiveField<uint16_t>(obj, field);
2463 break;
2464 case panda_file::Type::TypeId::I32:
2465 LoadPrimitiveField<int32_t>(obj, field);
2466 break;
2467 case panda_file::Type::TypeId::U32:
2468 LoadPrimitiveField<uint32_t>(obj, field);
2469 break;
2470 case panda_file::Type::TypeId::I64:
2471 LoadPrimitiveField<int64_t>(obj, field);
2472 break;
2473 case panda_file::Type::TypeId::U64:
2474 LoadPrimitiveField<uint64_t>(obj, field);
2475 break;
2476 case panda_file::Type::TypeId::F32:
2477 this->GetAccAsVReg().SetPrimitive(obj->template GetFieldPrimitive<float>(*field));
2478 break;
2479 case panda_file::Type::TypeId::F64:
2480 this->GetAccAsVReg().SetPrimitive(obj->template GetFieldPrimitive<double>(*field));
2481 break;
2482 default:
2483 UNREACHABLE();
2484 break;
2485 }
2486 }
2487
2488 template <class T, class R>
StorePrimitiveFieldReg(R & vreg,T * obj,Field * field)2489 ALWAYS_INLINE void StorePrimitiveFieldReg(R &vreg, T *obj, Field *field)
2490 {
2491 switch (field->GetTypeId()) {
2492 case panda_file::Type::TypeId::U1:
2493 case panda_file::Type::TypeId::U8: {
2494 obj->SetFieldPrimitive(*field, vreg.template GetAs<uint8_t>());
2495 break;
2496 }
2497 case panda_file::Type::TypeId::I8: {
2498 obj->SetFieldPrimitive(*field, vreg.template GetAs<int8_t>());
2499 break;
2500 }
2501 case panda_file::Type::TypeId::I16: {
2502 obj->SetFieldPrimitive(*field, vreg.template GetAs<int16_t>());
2503 break;
2504 }
2505 case panda_file::Type::TypeId::U16: {
2506 obj->SetFieldPrimitive(*field, vreg.template GetAs<uint16_t>());
2507 break;
2508 }
2509 case panda_file::Type::TypeId::I32: {
2510 obj->SetFieldPrimitive(*field, vreg.template GetAs<int32_t>());
2511 break;
2512 }
2513 case panda_file::Type::TypeId::U32: {
2514 obj->SetFieldPrimitive(*field, vreg.template GetAs<uint32_t>());
2515 break;
2516 }
2517 case panda_file::Type::TypeId::I64: {
2518 obj->SetFieldPrimitive(*field, vreg.template GetAs<int64_t>());
2519 break;
2520 }
2521 case panda_file::Type::TypeId::U64: {
2522 obj->SetFieldPrimitive(*field, vreg.template GetAs<uint64_t>());
2523 break;
2524 }
2525 case panda_file::Type::TypeId::F32: {
2526 obj->SetFieldPrimitive(*field, vreg.template GetAs<float>());
2527 break;
2528 }
2529 case panda_file::Type::TypeId::F64: {
2530 obj->SetFieldPrimitive(*field, vreg.template GetAs<double>());
2531 break;
2532 }
2533 default: {
2534 UNREACHABLE();
2535 break;
2536 }
2537 }
2538 }
2539
2540 template <class T>
StorePrimitiveField(T * obj,Field * field)2541 ALWAYS_INLINE void StorePrimitiveField(T *obj, Field *field)
2542 {
2543 switch (field->GetTypeId()) {
2544 case panda_file::Type::TypeId::U1:
2545 case panda_file::Type::TypeId::U8: {
2546 obj->SetFieldPrimitive(*field, this->GetAcc().template GetAs<uint8_t>());
2547 break;
2548 }
2549 case panda_file::Type::TypeId::I8: {
2550 obj->SetFieldPrimitive(*field, this->GetAcc().template GetAs<int8_t>());
2551 break;
2552 }
2553 case panda_file::Type::TypeId::I16: {
2554 obj->SetFieldPrimitive(*field, this->GetAcc().template GetAs<int16_t>());
2555 break;
2556 }
2557 case panda_file::Type::TypeId::U16: {
2558 obj->SetFieldPrimitive(*field, this->GetAcc().template GetAs<uint16_t>());
2559 break;
2560 }
2561 case panda_file::Type::TypeId::I32: {
2562 obj->SetFieldPrimitive(*field, this->GetAcc().template GetAs<int32_t>());
2563 break;
2564 }
2565 case panda_file::Type::TypeId::U32: {
2566 obj->SetFieldPrimitive(*field, this->GetAcc().template GetAs<uint32_t>());
2567 break;
2568 }
2569 case panda_file::Type::TypeId::I64: {
2570 obj->SetFieldPrimitive(*field, this->GetAcc().template GetAs<int64_t>());
2571 break;
2572 }
2573 case panda_file::Type::TypeId::U64: {
2574 obj->SetFieldPrimitive(*field, this->GetAcc().template GetAs<uint64_t>());
2575 break;
2576 }
2577 case panda_file::Type::TypeId::F32: {
2578 obj->SetFieldPrimitive(*field, this->GetAcc().template GetAs<float>());
2579 break;
2580 }
2581 case panda_file::Type::TypeId::F64: {
2582 obj->SetFieldPrimitive(*field, this->GetAcc().template GetAs<double>());
2583 break;
2584 }
2585 default: {
2586 UNREACHABLE();
2587 break;
2588 }
2589 }
2590 }
2591
2592 template <BytecodeInstruction::Format format, class T>
HandleArrayPrimitiveLoad()2593 ALWAYS_INLINE void HandleArrayPrimitiveLoad()
2594 {
2595 static_assert(std::is_integral_v<T> || std::is_floating_point_v<T>,
2596 "T should be either integral or floating point type");
2597 uint16_t vs = this->GetInst().template GetVReg<format>();
2598
2599 LOG_INST() << "\t"
2600 << "load v" << vs;
2601
2602 auto *array = static_cast<coretypes::Array *>(this->GetFrame()->GetVReg(vs).GetReference());
2603 int32_t idx = this->GetAcc().Get();
2604
2605 if (LIKELY(CheckLoadArrayOp(array, idx))) {
2606 this->GetAcc().Set(array->Get<T>(idx));
2607 this->template MoveToNextInst<format, true>();
2608 } else {
2609 this->MoveToExceptionHandler();
2610 }
2611 }
2612
2613 template <BytecodeInstruction::Format format, class T>
HandleArrayStore()2614 ALWAYS_INLINE void HandleArrayStore()
2615 {
2616 uint16_t vs1 = this->GetInst().template GetVReg<format, 0>();
2617 uint16_t vs2 = this->GetInst().template GetVReg<format, 1>();
2618
2619 LOG_INST() << "\t"
2620 << "store v" << vs1 << ", v" << vs2;
2621
2622 auto *array = static_cast<coretypes::Array *>(this->GetFrame()->GetVReg(vs1).GetReference());
2623 int32_t idx = this->GetFrame()->GetVReg(vs2).Get();
2624
2625 auto elem = this->GetAcc().template GetAs<T>();
2626 if (LIKELY(CheckStoreArrayOp(array, idx, elem))) {
2627 array->Set<T, RuntimeIfaceT::NEED_WRITE_BARRIER>(this->GetThread(), idx, elem);
2628 this->template MoveToNextInst<format, true>();
2629 } else {
2630 this->MoveToExceptionHandler();
2631 }
2632 }
2633
2634 template <class T>
CheckStoreArrayOp(coretypes::Array * array,int32_t idx,T elem)2635 ALWAYS_INLINE bool CheckStoreArrayOp(coretypes::Array *array, int32_t idx, [[maybe_unused]] T elem)
2636 {
2637 if (UNLIKELY(array == nullptr)) {
2638 RuntimeIfaceT::ThrowNullPointerException();
2639 return false;
2640 }
2641
2642 if (UNLIKELY(idx < 0 || helpers::ToUnsigned(idx) >= array->GetLength())) {
2643 RuntimeIfaceT::ThrowArrayIndexOutOfBoundsException(idx, array->GetLength());
2644 return false;
2645 }
2646
2647 if constexpr (std::is_same_v<T, ObjectHeader *>) {
2648 if (elem != nullptr) {
2649 auto *array_class = array->ClassAddr<Class>();
2650 auto *element_class = array_class->GetComponentType();
2651 if (UNLIKELY(!elem->IsInstanceOf(element_class))) {
2652 RuntimeIfaceT::ThrowArrayStoreException(array_class, elem->template ClassAddr<Class>());
2653 return false;
2654 }
2655 }
2656 }
2657
2658 return true;
2659 }
2660
CheckLoadArrayOp(coretypes::Array * array,int32_t idx)2661 ALWAYS_INLINE bool CheckLoadArrayOp(coretypes::Array *array, int32_t idx)
2662 {
2663 if (UNLIKELY(array == nullptr)) {
2664 RuntimeIfaceT::ThrowNullPointerException();
2665 return false;
2666 }
2667
2668 if (UNLIKELY(idx < 0 || helpers::ToUnsigned(idx) >= array->GetLength())) {
2669 RuntimeIfaceT::ThrowArrayIndexOutOfBoundsException(idx, array->GetLength());
2670 return false;
2671 }
2672
2673 return true;
2674 }
2675
InstrumentBranches(int32_t offset)2676 ALWAYS_INLINE bool InstrumentBranches(int32_t offset)
2677 {
2678 // Offset may be 0 in case of infinite empty loops (see issue #5301)
2679 if (offset <= 0) {
2680 if (this->GetThread()->TestAllFlags()) {
2681 this->GetFrame()->SetAcc(this->GetAcc());
2682 RuntimeIfaceT::Safepoint();
2683 this->GetAcc() = this->GetFrame()->GetAcc();
2684 }
2685 if constexpr (ArchTraits<RUNTIME_ARCH>::SUPPORT_OSR) {
2686 if (UpdateHotnessOSR(this->GetFrame()->GetMethod(), offset)) {
2687 static_assert(static_cast<unsigned>(BytecodeInstruction::Opcode::RETURN_VOID) <=
2688 std::numeric_limits<uint8_t>::max());
2689 this->GetFakeInstBuf()[0] = static_cast<uint8_t>(BytecodeInstruction::Opcode::RETURN_VOID);
2690 this->SetInst(BytecodeInstruction(this->GetFakeInstBuf().data()));
2691 return true;
2692 }
2693 } else {
2694 this->UpdateHotness(this->GetFrame()->GetMethod());
2695 }
2696 }
2697 return false;
2698 }
2699
ResolveLiteralArray(BytecodeId id)2700 ALWAYS_INLINE coretypes::Array *ResolveLiteralArray(BytecodeId id)
2701 {
2702 return RuntimeIfaceT::ResolveLiteralArray(this->GetThread()->GetVM(), *this->GetFrame()->GetMethod(), id);
2703 }
2704
ResolveMethod(BytecodeId id)2705 ALWAYS_INLINE Method *ResolveMethod(BytecodeId id)
2706 {
2707 this->UpdateBytecodeOffset();
2708
2709 auto cache = this->GetThread()->GetInterpreterCache();
2710 auto *res = cache->template Get<Method>(this->GetInst().GetAddress(), this->GetFrame()->GetMethod());
2711 if (res != nullptr) {
2712 return res;
2713 }
2714
2715 this->GetFrame()->SetAcc(this->GetAcc());
2716 auto *method = RuntimeIfaceT::ResolveMethod(this->GetThread(), *this->GetFrame()->GetMethod(), id);
2717 this->GetAcc() = this->GetFrame()->GetAcc();
2718 if (UNLIKELY(method == nullptr)) {
2719 ASSERT(this->GetThread()->HasPendingException());
2720 return nullptr;
2721 }
2722
2723 cache->Set(this->GetInst().GetAddress(), method, this->GetFrame()->GetMethod());
2724 return method;
2725 }
2726
2727 template <bool need_init = false>
ResolveField(BytecodeId id)2728 ALWAYS_INLINE Field *ResolveField(BytecodeId id)
2729 {
2730 auto cache = this->GetThread()->GetInterpreterCache();
2731 auto *res = cache->template Get<Field>(this->GetInst().GetAddress(), this->GetFrame()->GetMethod());
2732 if (res != nullptr) {
2733 return res;
2734 }
2735
2736 if (need_init) {
2737 // Update bytecode offset in the current frame as RuntimeIfaceT::ResolveField can trigger class initializer
2738 this->UpdateBytecodeOffset();
2739 }
2740
2741 this->GetFrame()->SetAcc(this->GetAcc());
2742 auto *field = RuntimeIfaceT::ResolveField(this->GetThread(), *this->GetFrame()->GetMethod(), id);
2743 this->GetAcc() = this->GetFrame()->GetAcc();
2744 if (UNLIKELY(field == nullptr)) {
2745 ASSERT(this->GetThread()->HasPendingException());
2746 return nullptr;
2747 }
2748
2749 cache->Set(this->GetInst().GetAddress(), field, this->GetFrame()->GetMethod());
2750 return field;
2751 }
2752
2753 template <bool need_init = false>
ResolveType(BytecodeId id)2754 ALWAYS_INLINE Class *ResolveType(BytecodeId id)
2755 {
2756 auto cache = this->GetThread()->GetInterpreterCache();
2757 auto *res = cache->template Get<Class>(this->GetInst().GetAddress(), this->GetFrame()->GetMethod());
2758 if (res != nullptr) {
2759 ASSERT(!need_init || res->IsInitializing() || res->IsInitialized());
2760 return res;
2761 }
2762
2763 this->GetFrame()->SetAcc(this->GetAcc());
2764 auto *klass =
2765 RuntimeIfaceT::template ResolveClass<need_init>(this->GetThread(), *this->GetFrame()->GetMethod(), id);
2766 this->GetAcc() = this->GetFrame()->GetAcc();
2767 if (UNLIKELY(klass == nullptr)) {
2768 ASSERT(this->GetThread()->HasPendingException());
2769 return nullptr;
2770 }
2771
2772 ASSERT(!need_init || klass->IsInitializing() || klass->IsInitialized());
2773
2774 cache->Set(this->GetInst().GetAddress(), klass, this->GetFrame()->GetMethod());
2775 return klass;
2776 }
2777
2778 template <BytecodeInstruction::Format format, bool is_dynamic_t>
CopyCallAccShortArguments(Frame & frame,uint32_t num_vregs)2779 ALWAYS_INLINE inline void CopyCallAccShortArguments(Frame &frame, uint32_t num_vregs)
2780 {
2781 auto cur_frame_handler = this->template GetFrameHandler<is_dynamic_t>();
2782 auto frame_handler = this->template GetFrameHandler<is_dynamic_t>(&frame);
2783 static_assert(format == BytecodeInstruction::Format::V4_IMM4_ID16, "Invalid call acc short format");
2784 auto acc_position = static_cast<size_t>(this->GetInst().template GetImm<format, 0>());
2785 switch (acc_position) {
2786 case 0U:
2787 frame_handler.GetVReg(num_vregs).Move(this->template GetAccAsVReg<is_dynamic_t>());
2788 frame_handler.GetVReg(num_vregs + 1U) =
2789 cur_frame_handler.GetVReg(this->GetInst().template GetVReg<format, 0>());
2790 break;
2791 case 1U:
2792 frame_handler.GetVReg(num_vregs) =
2793 cur_frame_handler.GetVReg(this->GetInst().template GetVReg<format, 0>());
2794 frame_handler.GetVReg(num_vregs + 1U).Move(this->template GetAccAsVReg<is_dynamic_t>());
2795 break;
2796 default:
2797 UNREACHABLE();
2798 }
2799 }
2800
2801 template <BytecodeInstruction::Format format, bool is_dynamic_t>
CopyCallAccArguments(Frame & frame,uint32_t num_vregs)2802 ALWAYS_INLINE inline void CopyCallAccArguments(Frame &frame, uint32_t num_vregs)
2803 {
2804 auto cur_frame_handler = this->template GetFrameHandler<is_dynamic_t>();
2805 auto frame_handler = this->template GetFrameHandler<is_dynamic_t>(&frame);
2806 static_assert(format == BytecodeInstruction::Format::V4_V4_V4_IMM4_ID16, "Invalid call acc format");
2807 auto acc_position = static_cast<size_t>(this->GetInst().template GetImm<format, 0>());
2808 switch (acc_position) {
2809 case 0U:
2810 frame_handler.GetVReg(num_vregs).Move(this->template GetAccAsVReg<is_dynamic_t>());
2811 frame_handler.GetVReg(num_vregs + 1U) =
2812 cur_frame_handler.GetVReg(this->GetInst().template GetVReg<format, 0>());
2813 frame_handler.GetVReg(num_vregs + 2U) =
2814 cur_frame_handler.GetVReg(this->GetInst().template GetVReg<format, 1>());
2815 frame_handler.GetVReg(num_vregs + 3U) =
2816 cur_frame_handler.GetVReg(this->GetInst().template GetVReg<format, 2>());
2817 break;
2818 case 1U:
2819 frame_handler.GetVReg(num_vregs) =
2820 cur_frame_handler.GetVReg(this->GetInst().template GetVReg<format, 0>());
2821 frame_handler.GetVReg(num_vregs + 1U).Move(this->template GetAccAsVReg<is_dynamic_t>());
2822 frame_handler.GetVReg(num_vregs + 2U) =
2823 cur_frame_handler.GetVReg(this->GetInst().template GetVReg<format, 1>());
2824 frame_handler.GetVReg(num_vregs + 3U) =
2825 cur_frame_handler.GetVReg(this->GetInst().template GetVReg<format, 2>());
2826 break;
2827 case 2U:
2828 frame_handler.GetVReg(num_vregs) =
2829 cur_frame_handler.GetVReg(this->GetInst().template GetVReg<format, 0>());
2830 frame_handler.GetVReg(num_vregs + 1U) =
2831 cur_frame_handler.GetVReg(this->GetInst().template GetVReg<format, 1>());
2832 frame_handler.GetVReg(num_vregs + 2U).Move(this->template GetAccAsVReg<is_dynamic_t>());
2833 frame_handler.GetVReg(num_vregs + 3U) =
2834 cur_frame_handler.GetVReg(this->GetInst().template GetVReg<format, 2>());
2835 break;
2836 case 3U:
2837 frame_handler.GetVReg(num_vregs) =
2838 cur_frame_handler.GetVReg(this->GetInst().template GetVReg<format, 0>());
2839 frame_handler.GetVReg(num_vregs + 1U) =
2840 cur_frame_handler.GetVReg(this->GetInst().template GetVReg<format, 1>());
2841 frame_handler.GetVReg(num_vregs + 2U) =
2842 cur_frame_handler.GetVReg(this->GetInst().template GetVReg<format, 2>());
2843 frame_handler.GetVReg(num_vregs + 3U).Move(this->template GetAccAsVReg<is_dynamic_t>());
2844 break;
2845 default:
2846 UNREACHABLE();
2847 }
2848 }
2849
2850 template <BytecodeInstruction::Format format, bool is_dynamic_t, bool initobj>
CopyCallShortArguments(Frame & frame,uint32_t num_vregs)2851 ALWAYS_INLINE inline void CopyCallShortArguments(Frame &frame, uint32_t num_vregs)
2852 {
2853 static_assert(format == BytecodeInstruction::Format::V4_V4_ID16, "Invalid call short format");
2854
2855 auto cur_frame_handler = this->template GetFrameHandler<is_dynamic_t>();
2856 auto frame_handler = this->template GetFrameHandler<is_dynamic_t>(&frame);
2857 constexpr size_t shift = initobj ? 1U : 0;
2858 if constexpr (initobj) {
2859 frame_handler.GetVReg(num_vregs).Move(this->template GetAccAsVReg<is_dynamic_t>());
2860 }
2861
2862 frame_handler.GetVReg(num_vregs + shift) =
2863 cur_frame_handler.GetVReg(this->GetInst().template GetVReg<format, 0>());
2864 frame_handler.GetVReg(num_vregs + shift + 1U) =
2865 cur_frame_handler.GetVReg(this->GetInst().template GetVReg<format, 1U>());
2866 }
2867
2868 template <BytecodeInstruction::Format format, bool is_dynamic_t, bool initobj>
CopyCallArguments(Frame & frame,uint32_t num_vregs)2869 ALWAYS_INLINE inline void CopyCallArguments(Frame &frame, uint32_t num_vregs)
2870 {
2871 static_assert(format == BytecodeInstruction::Format::V4_V4_V4_V4_ID16, "Invalid call format");
2872
2873 auto cur_frame_handler = this->template GetFrameHandler<is_dynamic_t>();
2874 auto frame_handler = this->template GetFrameHandler<is_dynamic_t>(&frame);
2875 constexpr size_t shift = initobj ? 1U : 0;
2876 if constexpr (initobj) {
2877 frame_handler.GetVReg(num_vregs).Move(this->template GetAccAsVReg<is_dynamic_t>());
2878 }
2879
2880 frame_handler.GetVReg(num_vregs + shift) =
2881 cur_frame_handler.GetVReg(this->GetInst().template GetVReg<format, 0>());
2882 frame_handler.GetVReg(num_vregs + shift + 1U) =
2883 cur_frame_handler.GetVReg(this->GetInst().template GetVReg<format, 1U>());
2884 frame_handler.GetVReg(num_vregs + shift + 2U) =
2885 cur_frame_handler.GetVReg(this->GetInst().template GetVReg<format, 2U>());
2886 frame_handler.GetVReg(num_vregs + shift + 3U) =
2887 cur_frame_handler.GetVReg(this->GetInst().template GetVReg<format, 3U>());
2888 }
2889
2890 template <bool is_dynamic_t, bool initobj>
CopyCallArguments(Frame & frame,uint32_t num_vregs,uint32_t num_actual_args)2891 ALWAYS_INLINE inline void CopyCallArguments(Frame &frame, uint32_t num_vregs, uint32_t num_actual_args)
2892 {
2893 auto cur_frame_handler = this->template GetFrameHandler<is_dynamic_t>();
2894 auto frame_handler = this->template GetFrameHandler<is_dynamic_t>(&frame);
2895 constexpr size_t shift = initobj ? 1U : 0;
2896 if constexpr (initobj) {
2897 frame_handler.GetVReg(num_vregs).Move(this->template GetAccAsVReg<is_dynamic_t>());
2898 }
2899
2900 for (size_t i = 0; i < num_actual_args - shift; i++) {
2901 uint16_t vs = this->GetInst().GetVReg(i);
2902 frame_handler.GetVReg(num_vregs + shift + i) = cur_frame_handler.GetVReg(vs);
2903 }
2904 }
2905
2906 template <BytecodeInstruction::Format format, bool is_dynamic_t, bool initobj>
CopyRangeArguments(Frame & frame,uint32_t num_vregs,uint32_t num_actual_args)2907 ALWAYS_INLINE inline void CopyRangeArguments(Frame &frame, uint32_t num_vregs, uint32_t num_actual_args)
2908 {
2909 auto cur_frame_handler = this->template GetFrameHandler<is_dynamic_t>();
2910 auto frame_handler = this->template GetFrameHandler<is_dynamic_t>(&frame);
2911 constexpr size_t shift = initobj ? 1U : 0;
2912 if constexpr (initobj) {
2913 frame_handler.GetVReg(num_vregs).Move(this->template GetAccAsVReg<is_dynamic_t>());
2914 }
2915
2916 uint16_t start_reg = this->GetInst().template GetVReg<format, 0>();
2917 for (size_t i = 0; i < num_actual_args - shift; i++) {
2918 frame_handler.GetVReg(num_vregs + shift + i) = cur_frame_handler.GetVReg(start_reg + i);
2919 }
2920 }
2921
2922 template <class FrameHelper, BytecodeInstruction::Format format, bool is_dynamic_t, bool is_range, bool accept_acc,
2923 bool initobj>
CopyArguments(Frame & frame,uint32_t num_vregs,uint32_t num_actual_args,uint32_t num_args)2924 ALWAYS_INLINE inline void CopyArguments(Frame &frame, uint32_t num_vregs, [[maybe_unused]] uint32_t num_actual_args,
2925 uint32_t num_args)
2926 {
2927 if constexpr (is_dynamic_t) {
2928 FrameHelper::template CopyArgumentsDyn<format>(this, &frame, num_vregs, num_actual_args);
2929 return;
2930 }
2931 if (num_args == 0) {
2932 return;
2933 }
2934
2935 if constexpr (is_range) {
2936 CopyRangeArguments<format, is_dynamic_t, initobj>(frame, num_vregs, num_actual_args);
2937 } else if constexpr (accept_acc) {
2938 if constexpr (format == BytecodeInstruction::Format::V4_IMM4_ID16) {
2939 CopyCallAccShortArguments<format, is_dynamic_t>(frame, num_vregs);
2940 } else if constexpr (format == BytecodeInstruction::Format::V4_V4_V4_IMM4_ID16) {
2941 CopyCallAccArguments<format, is_dynamic_t>(frame, num_vregs);
2942 } else {
2943 CopyCallAccArguments<format, is_dynamic_t>(frame, num_vregs, num_actual_args);
2944 }
2945 } else {
2946 if constexpr (format == BytecodeInstruction::Format::V4_V4_ID16) {
2947 CopyCallShortArguments<format, is_dynamic_t, initobj>(frame, num_vregs);
2948 } else if constexpr (format == BytecodeInstruction::Format::V4_V4_V4_V4_ID16) {
2949 CopyCallArguments<format, is_dynamic_t, initobj>(frame, num_vregs);
2950 } else {
2951 CopyCallArguments<is_dynamic_t, initobj>(frame, num_vregs, num_actual_args);
2952 }
2953 }
2954 }
2955
2956 template <class FrameHelper, BytecodeInstruction::Format format, bool is_dynamic_t, bool is_range, bool accept_acc,
2957 bool initobj, bool stack_less>
CreateAndSetFrame(Method * method,Frame ** frame,uint32_t num_vregs)2958 ALWAYS_INLINE inline bool CreateAndSetFrame(Method *method, Frame **frame, uint32_t num_vregs)
2959 {
2960 uint32_t num_declared_args = method->GetNumArgs();
2961 uint32_t num_actual_args;
2962 uint32_t nregs;
2963
2964 if constexpr (is_dynamic_t) {
2965 num_actual_args = FrameHelper::template GetNumberActualArgsDyn<format>(this);
2966 nregs = num_vregs + std::max(num_declared_args, num_actual_args);
2967 } else {
2968 num_actual_args = num_declared_args;
2969 if (format == BytecodeInstruction::Format::V4_V4_ID16 ||
2970 format == BytecodeInstruction::Format::V4_IMM4_ID16) {
2971 nregs = num_vregs + (initobj ? 3U : 2U);
2972 } else if (format == BytecodeInstruction::Format::V4_V4_V4_V4_ID16 ||
2973 format == BytecodeInstruction::Format::V4_V4_V4_IMM4_ID16) {
2974 nregs = num_vregs + (initobj ? 5U : 4U);
2975 } else {
2976 nregs = num_vregs + num_declared_args;
2977 }
2978 }
2979
2980 *frame =
2981 FrameHelper::template CreateFrame<RuntimeIfaceT>(this->GetThread(), Frame::GetActualSize<is_dynamic>(nregs),
2982 method, this->GetFrame(), nregs, num_actual_args);
2983
2984 if (UNLIKELY(*frame == nullptr)) {
2985 RuntimeIfaceT::ThrowOutOfMemoryError("CreateFrame failed: " + method->GetFullName());
2986 this->MoveToExceptionHandler();
2987 return false;
2988 }
2989 if constexpr (stack_less) {
2990 if (!this->GetThread()->template StackOverflowCheck<false, true>()) {
2991 RuntimeIfaceT::FreeFrame(this->GetThread(), *frame);
2992 *frame = nullptr;
2993 this->MoveToExceptionHandler();
2994 return false;
2995 }
2996 }
2997 (*frame)->SetAcc(this->GetAcc());
2998 if constexpr (is_dynamic_t) {
2999 (*frame)->SetDynamic();
3000 }
3001
3002 CopyArguments<FrameHelper, format, is_dynamic_t, is_range, accept_acc, initobj>(
3003 **frame, num_vregs, num_actual_args, num_declared_args);
3004
3005 RuntimeIfaceT::SetCurrentFrame(this->GetThread(), *frame);
3006
3007 return true;
3008 }
3009
3010 template <bool is_dynamic_t = false>
HandleCallPrologue(Method * method)3011 ALWAYS_INLINE void HandleCallPrologue(Method *method)
3012 {
3013 ASSERT(method != nullptr);
3014 if constexpr (is_dynamic_t) {
3015 LOG(DEBUG, INTERPRETER) << "Entry: Runtime Call.";
3016 } else {
3017 LOG(DEBUG, INTERPRETER) << "Entry: " << method->GetFullName();
3018 }
3019 if (this->GetThread()->TestAllFlags()) {
3020 this->GetFrame()->SetAcc(this->GetAcc());
3021 RuntimeIfaceT::Safepoint();
3022 this->GetAcc() = this->GetFrame()->GetAcc();
3023 }
3024 if (!method->HasCompiledCode()) {
3025 this->UpdateHotness(method);
3026 }
3027 }
3028
3029 template <class FrameHelper, BytecodeInstruction::Format format, bool is_dynamic_t, bool is_range, bool accept_acc,
3030 bool initobj>
CallInterpreterStackless(Method * method)3031 ALWAYS_INLINE inline void CallInterpreterStackless(Method *method)
3032 {
3033 if (UNLIKELY(!method->Verify())) {
3034 RuntimeIfaceT::ThrowVerificationException(method->GetFullName());
3035 this->MoveToExceptionHandler();
3036 return;
3037 }
3038
3039 uint32_t num_vregs;
3040 auto *instructions =
3041 panda_file::CodeDataAccessor::GetInstructions(*method->GetPandaFile(), method->GetCodeId(), &num_vregs);
3042
3043 Frame *frame = nullptr;
3044 if (!CreateAndSetFrame<FrameHelper, format, is_dynamic_t, is_range, accept_acc, initobj, true>(method, &frame,
3045 num_vregs)) {
3046 return;
3047 }
3048
3049 Runtime::GetCurrent()->GetNotificationManager()->MethodEntryEvent(this->GetThread(), method);
3050
3051 frame->SetStackless();
3052 if constexpr (initobj) {
3053 frame->SetInitobj();
3054 }
3055 frame->SetInstruction(instructions);
3056 this->SetDispatchTable(this->GetThread()->GetCurrentDispatchTable());
3057 this->template MoveToNextInst<format, false>();
3058 this->GetFrame()->SetNextInstruction(this->GetInst());
3059 this->GetInstructionHandlerState()->UpdateInstructionHandlerState(instructions, frame);
3060 EVENT_METHOD_ENTER(frame->GetMethod()->GetFullName(), events::MethodEnterKind::INTERP,
3061 this->GetThread()->RecordMethodEnter());
3062 }
3063
3064 template <BytecodeInstruction::Format format, bool is_dynamic_t>
CallCompiledCode(Method * method)3065 ALWAYS_INLINE inline void CallCompiledCode(Method *method)
3066 {
3067 this->GetFrame()->SetAcc(this->GetAcc());
3068 if constexpr (is_dynamic_t) {
3069 InterpreterToCompiledCodeBridgeDyn(this->GetInst().GetAddress(), this->GetFrame(), method,
3070 this->GetThread());
3071 } else {
3072 InterpreterToCompiledCodeBridge(this->GetInst().GetAddress(), this->GetFrame(), method, this->GetThread());
3073 }
3074
3075 this->GetThread()->SetCurrentFrameIsCompiled(false);
3076 this->GetThread()->SetCurrentFrame(this->GetFrame());
3077
3078 if (UNLIKELY(this->GetThread()->HasPendingException())) {
3079 this->MoveToExceptionHandler();
3080 } else {
3081 this->GetAcc() = this->GetFrame()->GetAcc();
3082 this->template MoveToNextInst<format, true>();
3083 }
3084
3085 if constexpr (is_dynamic_t) {
3086 LOG(DEBUG, INTERPRETER) << "Exit: Runtime Call.";
3087 } else {
3088 LOG(DEBUG, INTERPRETER) << "Exit: " << method->GetFullName();
3089 }
3090 }
3091
3092 template <class FrameHelper, BytecodeInstruction::Format format, bool is_dynamic_t = false, bool is_range = false,
3093 bool accept_acc = false, bool initobj = false>
HandleCall(Method * method)3094 ALWAYS_INLINE void HandleCall(Method *method)
3095 {
3096 HandleCallPrologue<is_dynamic_t>(method);
3097
3098 if (method->HasCompiledCode()) {
3099 CallCompiledCode<format, is_dynamic_t>(method);
3100 } else {
3101 ADD_PROFILE_CODE_ITEM(method);
3102 CallInterpreterStackless<FrameHelper, format, is_dynamic_t, is_range, accept_acc, initobj>(method);
3103 }
3104 }
3105
3106 template <BytecodeInstruction::Format format, bool is_range = false, bool accept_acc = false>
HandleVirtualCall(Method * method)3107 ALWAYS_INLINE void HandleVirtualCall(Method *method)
3108 {
3109 ASSERT(method != nullptr);
3110 ASSERT(!method->IsStatic());
3111 ASSERT(!method->IsConstructor());
3112
3113 ObjectHeader *obj = this->GetCallerObject<format, accept_acc>();
3114 if (UNLIKELY(obj == nullptr)) {
3115 return;
3116 }
3117 auto *cls = obj->ClassAddr<Class>();
3118 ASSERT(cls != nullptr);
3119 auto *resolved = cls->ResolveVirtualMethod(method);
3120 ASSERT(resolved != nullptr);
3121
3122 ProfilingData *prof_data = this->GetFrame()->GetMethod()->GetProfilingData();
3123 if (prof_data != nullptr) {
3124 prof_data->UpdateInlineCaches(this->GetBytecodeOffset(), obj->ClassAddr<Class>());
3125 }
3126
3127 HandleCall<FrameHelperDefault, format, false, is_range, accept_acc>(resolved);
3128 }
3129
3130 template <BytecodeInstruction::Format format, template <typename OpT> class Op>
HandleCondJmpz()3131 ALWAYS_INLINE void HandleCondJmpz()
3132 {
3133 auto imm = this->GetInst().template GetImm<format>();
3134
3135 LOG_INST() << "\t"
3136 << "cond jmpz " << std::hex << "0x" << imm;
3137
3138 int32_t v1 = this->GetAcc().Get();
3139
3140 if (Op<int32_t>()(v1, 0)) {
3141 this->template UpdateBranchStatistics<true>();
3142 if (!InstrumentBranches(imm)) {
3143 this->template JumpToInst<false>(imm);
3144 }
3145 } else {
3146 this->template UpdateBranchStatistics<false>();
3147 this->template MoveToNextInst<format, false>();
3148 }
3149 }
3150
3151 template <BytecodeInstruction::Format format, template <typename OpT> class Op>
HandleCondJmp()3152 ALWAYS_INLINE void HandleCondJmp()
3153 {
3154 auto imm = this->GetInst().template GetImm<format>();
3155 uint16_t vs = this->GetInst().template GetVReg<format>();
3156
3157 LOG_INST() << "\t"
3158 << "cond jmp v" << vs << ", " << std::hex << "0x" << imm;
3159
3160 int32_t v1 = this->GetAcc().Get();
3161 int32_t v2 = this->GetFrame()->GetVReg(vs).Get();
3162
3163 if (Op<int32_t>()(v1, v2)) {
3164 this->template UpdateBranchStatistics<true>();
3165 if (!InstrumentBranches(imm)) {
3166 this->template JumpToInst<false>(imm);
3167 }
3168 } else {
3169 this->template UpdateBranchStatistics<false>();
3170 this->template MoveToNextInst<format, false>();
3171 }
3172 }
3173
3174 template <BytecodeInstruction::Format format, template <typename OpT> class Op>
HandleCondJmpzObj()3175 ALWAYS_INLINE void HandleCondJmpzObj()
3176 {
3177 auto imm = this->GetInst().template GetImm<format>();
3178 ObjectHeader *v1 = this->GetAcc().GetReference();
3179
3180 LOG_INST() << "\t"
3181 << "cond jmpz.obj " << std::hex << "0x" << imm;
3182
3183 if (Op<ObjectHeader *>()(v1, nullptr)) {
3184 this->template UpdateBranchStatistics<true>();
3185 if (!InstrumentBranches(imm)) {
3186 this->template JumpToInst<false>(imm);
3187 }
3188 } else {
3189 this->template UpdateBranchStatistics<false>();
3190 this->template MoveToNextInst<format, false>();
3191 }
3192 }
3193
3194 template <BytecodeInstruction::Format format, template <typename OpT> class Op>
HandleCondJmpObj()3195 ALWAYS_INLINE void HandleCondJmpObj()
3196 {
3197 auto imm = this->GetInst().template GetImm<format>();
3198 uint16_t vs = this->GetInst().template GetVReg<format>();
3199
3200 LOG_INST() << "\t"
3201 << "cond jmp.obj v" << vs << ", " << std::hex << "0x" << imm;
3202
3203 ObjectHeader *v1 = this->GetAcc().GetReference();
3204 ObjectHeader *v2 = this->GetFrame()->GetVReg(vs).GetReference();
3205
3206 if (Op<ObjectHeader *>()(v1, v2)) {
3207 this->template UpdateBranchStatistics<true>();
3208 if (!InstrumentBranches(imm)) {
3209 this->template JumpToInst<false>(imm);
3210 }
3211 } else {
3212 this->template UpdateBranchStatistics<false>();
3213 this->template MoveToNextInst<format, false>();
3214 }
3215 }
3216
3217 template <BytecodeInstruction::Format format, typename OpT, template <typename> class Op, bool is_div = false>
HandleBinaryOp2Imm()3218 ALWAYS_INLINE void HandleBinaryOp2Imm()
3219 {
3220 OpT v1 = this->GetAcc().template GetAs<OpT>();
3221 OpT v2 = this->GetInst().template GetImm<format>();
3222
3223 LOG_INST() << "\t"
3224 << "binop2imm " << std::hex << "0x" << v2;
3225
3226 if (is_div && UNLIKELY(v2 == 0)) {
3227 RuntimeIfaceT::ThrowArithmeticException();
3228 this->MoveToExceptionHandler();
3229 } else {
3230 this->GetAcc().Set(Op<OpT>()(v1, v2));
3231 this->template MoveToNextInst<format, is_div>();
3232 }
3233 }
3234
3235 template <BytecodeInstruction::Format format, typename OpT, template <typename> class Op, bool is_div = false>
HandleBinaryOp2()3236 ALWAYS_INLINE void HandleBinaryOp2()
3237 {
3238 OpT v1 = this->GetAcc().template GetAs<OpT>();
3239 uint16_t vs1 = this->GetInst().template GetVReg<format>();
3240
3241 LOG_INST() << "\t"
3242 << "binop2 v" << vs1;
3243
3244 OpT v2 = this->GetFrame()->GetVReg(vs1).template GetAs<OpT>();
3245
3246 if (is_div && UNLIKELY(v2 == 0)) {
3247 RuntimeIfaceT::ThrowArithmeticException();
3248 this->MoveToExceptionHandler();
3249 } else {
3250 this->GetAcc().Set(Op<OpT>()(v1, v2));
3251 this->template MoveToNextInst<format, is_div>();
3252 }
3253 }
3254
3255 template <BytecodeInstruction::Format format, typename OpT, template <typename> class Op, bool is_div = false>
HandleBinaryOp()3256 ALWAYS_INLINE void HandleBinaryOp()
3257 {
3258 uint16_t vs1 = this->GetInst().template GetVReg<format, 0>();
3259 uint16_t vs2 = this->GetInst().template GetVReg<format, 1>();
3260
3261 LOG_INST() << "\t"
3262 << "binop2 v" << vs1 << ", v" << vs2;
3263
3264 OpT v1 = this->GetFrame()->GetVReg(vs1).template GetAs<OpT>();
3265 OpT v2 = this->GetFrame()->GetVReg(vs2).template GetAs<OpT>();
3266
3267 if (is_div && UNLIKELY(v2 == 0)) {
3268 RuntimeIfaceT::ThrowArithmeticException();
3269 this->MoveToExceptionHandler();
3270 } else {
3271 this->GetAccAsVReg().SetPrimitive(Op<OpT>()(v1, v2));
3272 this->template MoveToNextInst<format, is_div>();
3273 }
3274 }
3275
3276 template <BytecodeInstruction::Format format, typename OpT, template <typename> class Op>
HandleUnaryOp()3277 ALWAYS_INLINE void HandleUnaryOp()
3278 {
3279 OpT v = this->GetAcc().template GetAs<OpT>();
3280 this->GetAcc().Set(Op<OpT>()(v));
3281 this->template MoveToNextInst<format, false>();
3282 }
3283
3284 template <BytecodeInstruction::Format format, typename From, typename To>
HandleConversion()3285 ALWAYS_INLINE void HandleConversion()
3286 {
3287 this->GetAcc().Set(static_cast<To>(this->GetAcc().template GetAs<From>()));
3288 this->template MoveToNextInst<format, false>();
3289 }
3290
3291 template <BytecodeInstruction::Format format, typename From, typename To>
HandleFloatToIntConversion()3292 ALWAYS_INLINE void HandleFloatToIntConversion()
3293 {
3294 auto value = this->GetAcc().template GetAs<From>();
3295 this->GetAcc().Set(CastFloatToInt<From, To>(value));
3296 this->template MoveToNextInst<format, false>();
3297 }
3298
3299 template <BytecodeInstruction::Format format>
InitializeObject(Class * klass,Method * method)3300 ALWAYS_INLINE void InitializeObject(Class *klass, Method *method)
3301 {
3302 if (UNLIKELY(method == nullptr)) {
3303 this->MoveToExceptionHandler();
3304 return;
3305 }
3306
3307 auto *obj = RuntimeIfaceT::CreateObject(klass);
3308 if (UNLIKELY(obj == nullptr)) {
3309 this->MoveToExceptionHandler();
3310 return;
3311 }
3312
3313 this->GetAccAsVReg().SetReference(obj);
3314 this->GetFrame()->GetAcc() = this->GetAcc();
3315
3316 constexpr bool is_range = format == BytecodeInstruction::Format::V8_ID16;
3317 HandleCall<FrameHelperDefault, format, false, is_range, false, true>(method);
3318 }
3319
3320 template <BytecodeInstruction::Format format>
InitializeObject(BytecodeId & method_id)3321 ALWAYS_INLINE void InitializeObject(BytecodeId &method_id)
3322 {
3323 Class *klass;
3324 auto cache = this->GetThread()->GetInterpreterCache();
3325 auto *method = cache->template Get<Method>(this->GetInst().GetAddress(), this->GetFrame()->GetMethod());
3326 if (method != nullptr) {
3327 klass = method->GetClass();
3328 } else {
3329 klass = RuntimeIfaceT::GetMethodClass(this->GetFrame()->GetMethod(), method_id);
3330 this->GetAccAsVReg().SetPrimitive(0);
3331 if (UNLIKELY(klass == nullptr)) {
3332 this->MoveToExceptionHandler();
3333 return;
3334 }
3335 }
3336
3337 if (UNLIKELY(klass->IsArrayClass())) {
3338 ASSERT(utf::IsEqual(RuntimeIfaceT::GetMethodName(this->GetFrame()->GetMethod(), method_id),
3339 utf::CStringAsMutf8("<init>")));
3340
3341 DimIterator<format> dim_iter {this->GetInst(), this->GetFrame()};
3342 auto nargs = RuntimeIfaceT::GetMethodArgumentsCount(this->GetFrame()->GetMethod(), method_id);
3343 auto obj = coretypes::Array::CreateMultiDimensionalArray<DimIterator<format>>(this->GetThread(), klass,
3344 nargs, dim_iter);
3345 if (LIKELY(obj != nullptr)) {
3346 this->GetAccAsVReg().SetReference(obj);
3347 this->template MoveToNextInst<format, false>();
3348 } else {
3349 this->MoveToExceptionHandler();
3350 }
3351 } else {
3352 if (UNLIKELY(method == nullptr)) {
3353 method = ResolveMethod(method_id);
3354 }
3355 this->UpdateBytecodeOffset();
3356 InitializeObject<format>(klass, method);
3357 }
3358 }
3359
3360 private:
3361 template <BytecodeInstruction::Format format>
GetObjHelper()3362 ALWAYS_INLINE ObjectHeader *GetObjHelper()
3363 {
3364 uint16_t obj_vreg = this->GetInst().template GetVReg<format, 0>();
3365 return this->GetFrame()->GetVReg(obj_vreg).GetReference();
3366 }
3367
3368 template <BytecodeInstruction::Format format, bool accept_acc = false>
GetCallerObject()3369 ALWAYS_INLINE ObjectHeader *GetCallerObject()
3370 {
3371 ObjectHeader *obj = nullptr;
3372 if constexpr (accept_acc) {
3373 if (this->GetInst().template GetImm<format, 0>() == 0) {
3374 obj = this->GetAcc().GetReference();
3375 } else {
3376 obj = GetObjHelper<format>();
3377 }
3378 } else {
3379 obj = GetObjHelper<format>();
3380 }
3381
3382 if (UNLIKELY(obj == nullptr)) {
3383 RuntimeIfaceT::ThrowNullPointerException();
3384 this->MoveToExceptionHandler();
3385 return nullptr;
3386 }
3387 return obj;
3388 }
3389 };
3390
3391 extern "C" void ExecuteImplStub(ManagedThread *thread, const uint8_t *pc, Frame *frame, void *impl);
3392
3393 template <class RuntimeIfaceT, bool jump_to_eh, bool is_dynamic>
ExecuteImpl_Inner(ManagedThread * thread,const uint8_t * pc,Frame * frame)3394 void ExecuteImpl_Inner(ManagedThread *thread, const uint8_t *pc, Frame *frame)
3395 {
3396 void *impl = reinterpret_cast<void *>(&ExecuteImpl<RuntimeIfaceT, jump_to_eh, is_dynamic>);
3397 ExecuteImplStub(thread, pc, frame, impl);
3398 }
3399
3400 } // namespace panda::interpreter
3401
3402 #endif // PANDA_INTERPRETER_INL_H_
3403