• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #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 &reg = 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