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