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