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 ® = 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