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