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