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