• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2022 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_VERIFICATION_ABSINT_ABS_INT_INL_H
17 #define PANDA_VERIFICATION_ABSINT_ABS_INT_INL_H
18 
19 #include "abs_int_inl_compat_checks.h"
20 #include "bytecode_instruction-inl.h"
21 #include "file_items.h"
22 #include "include/mem/panda_containers.h"
23 #include "include/method.h"
24 #include "include/runtime.h"
25 #include "macros.h"
26 #include "runtime/include/class.h"
27 #include "runtime/include/thread_scopes.h"
28 #include "runtime/interpreter/runtime_interface.h"
29 #include "type/type_system.h"
30 #include "util/lazy.h"
31 #include "utils/logger.h"
32 #include "util/str.h"
33 #include "verification/config/debug_breakpoint/breakpoint.h"
34 #include "verification_context.h"
35 #include "verification/public_internal.h"
36 #include "verification/type/type_system.h"
37 #include "verification_status.h"
38 #include "verifier_messages.h"
39 
40 #include <array>
41 #include <cmath>
42 #include <cstdint>
43 #include <functional>
44 #include <iomanip>
45 #include <limits>
46 #include <memory>
47 #include <type_traits>
48 #include <unordered_map>
49 
50 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
51 #define LOG_INST()                                             \
52     do {                                                       \
53         if (!GetInst().IsValid()) {                            \
54             SHOW_MSG(InvalidInstruction)                       \
55             LOG_VERIFIER_INVALID_INSTRUCTION();                \
56             END_SHOW_MSG();                                    \
57             SET_STATUS_FOR_MSG(InvalidInstruction, WARNING);   \
58             return false;                                      \
59         }                                                      \
60         if (job_->Options().ShowContext()) {                   \
61             DumpRegs(ExecCtx().CurrentRegContext());           \
62         }                                                      \
63         SHOW_MSG(DebugAbsIntLogInstruction)                    \
64         LOG_VERIFIER_DEBUG_ABS_INT_LOG_INSTRUCTION(GetInst()); \
65         END_SHOW_MSG();                                        \
66     } while (0)
67 
68 #ifndef NDEBUG
69 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
70 #define DBGBRK()                                                                      \
71     if (debug_) {                                                                     \
72         DBG_MANAGED_BRK(debugCtx, job_->JobMethod()->GetUniqId(), inst_.GetOffset()); \
73     }
74 #else
75 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
76 #define DBGBRK()
77 #endif
78 
79 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
80 #define SHOW_MSG(Message) if (!job_->Options().IsHidden(VerifierMessage::Message)) {
81 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
82 #define END_SHOW_MSG() }
83 
84 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
85 #define SET_STATUS_FOR_MSG(Message, AtLeast)                                                       \
86     do {                                                                                           \
87         SetStatusAtLeast(VerificationStatus::AtLeast);                                             \
88         SetStatusAtLeast(MsgClassToStatus(job_->Options().MsgClassFor(VerifierMessage::Message))); \
89     } while (0)
90 
91 /*
92 NOTE(vdyadov): add AddrMap to verification context where put marks on all checked bytes.
93 after absint process ends, check this AddrMap for holes.
94 holes are either dead byte-code or issues with absint cflow handling.
95 */
96 
97 // NOTE(vdyadov): refactor this file, all utility functions put in separate/other files
98 
99 /*
100 NOTE(vdyadov): IMPORTANT!!! (Done)
101 Current definition of context incompatibility is NOT CORRECT one!
102 There are situations when verifier will rule out fully correct programs.
103 For instance:
104 ....
105 movi v0,0
106 ldai 0
107 jmp label1
108 ....
109 lda.str ""
110 sta v0
111 ldai 0
112 jmp label1
113 .....
114 label1:
115   return
116 
117 Here we have context incompatibility on label1, but it does not harm, because conflicting reg is
118 not used anymore.
119 
120 Solutions:
121 1(current). Conflicts are reported as warnings, conflicting regs are removed fro resulting context.
122 So, on attempt of usage of conflicting reg, absint will fail with message of undefined reg.
123 May be mark them as conflicting? (done)
124 2. On each label/checkpoint compute set of registers that will be used in next conputations and process
125 conflicting contexts modulo used registers set. It is complex solution, but very preciese.
126 */
127 
128 // NOTE(vdyadov): regain laziness, strict evaluation is very expensive!
129 
130 namespace panda::verifier {
131 
132 class AbsIntInstructionHandler {
133 public:
134     // NOLINTBEGIN(misc-non-private-member-variables-in-classes)
135     static constexpr int acc = -1;
136     static constexpr int invalidReg = -2;  // NOTE(vdyadov): may be use Index<..> here?
137 
138     using TypeId = panda_file::Type::TypeId;
139     using Builtin = Type::Builtin;
140 
141     Type const top_ {Builtin::TOP};
142     Type const bot_ {Builtin::BOT};
143     Type const u1_ {Builtin::U1};
144     Type const i8_ {Builtin::I8};
145     Type const u8_ {Builtin::U8};
146     Type const i16_ {Builtin::I16};
147     Type const u16_ {Builtin::U16};
148     Type const i32_ {Builtin::I32};
149     Type const u32_ {Builtin::U32};
150     Type const i64_ {Builtin::I64};
151     Type const u64_ {Builtin::U64};
152     Type const f32_ {Builtin::F32};
153     Type const f64_ {Builtin::F64};
154     Type const integral32_ {Builtin::INTEGRAL32};
155     Type const integral64_ {Builtin::INTEGRAL64};
156     Type const float32_ {Builtin::FLOAT32};
157     Type const float64_ {Builtin::FLOAT64};
158     Type const bits32_ {Builtin::BITS32};
159     Type const bits64_ {Builtin::BITS64};
160     Type const primitive_ {Builtin::PRIMITIVE};
161     Type const refType_ {Builtin::REFERENCE};
162     Type const nullRefType_ {Builtin::NULL_REFERENCE};
163     Type const objectType_ {Builtin::OBJECT};
164     Type const arrayType_ {Builtin::ARRAY};
165 
166     Job const *job_;
167     debug::DebugContext const *debugCtx;
168     Config const *config;
169 
170     // NOLINTEND(misc-non-private-member-variables-in-classes)
171 
AbsIntInstructionHandler(VerificationContext & verifCtx,const uint8_t * pc,EntryPointType codeType)172     AbsIntInstructionHandler(VerificationContext &verifCtx, const uint8_t *pc, EntryPointType codeType)
173         : job_ {verifCtx.GetJob()},
174           debugCtx {&job_->GetService()->debugCtx},
175           config {GetServiceConfig(job_->GetService())},
176           inst_(pc, verifCtx.CflowInfo().GetAddrStart(), verifCtx.CflowInfo().GetAddrEnd()),
177           context_ {verifCtx},
178           codeType_ {codeType}
179     {
180 #ifndef NDEBUG
181         if (config->opts.mode == VerificationMode::DEBUG) {
182             const auto &method = job_->JobMethod();
183             debug_ = debug::ManagedBreakpointPresent(debugCtx, method->GetUniqId());
184             if (debug_) {
185                 LOG(DEBUG, VERIFIER) << "Debug mode for method " << method->GetFullName() << " is on";
186             }
187         }
188 #endif
189     }
190 
191     ~AbsIntInstructionHandler() = default;
192     NO_MOVE_SEMANTIC(AbsIntInstructionHandler);
193     NO_COPY_SEMANTIC(AbsIntInstructionHandler);
194 
GetStatus()195     VerificationStatus GetStatus()
196     {
197         return status_;
198     }
199 
GetPrimaryOpcode()200     uint8_t GetPrimaryOpcode()
201     {
202         return inst_.GetPrimaryOpcode();
203     }
204 
GetSecondaryOpcode()205     uint8_t GetSecondaryOpcode()
206     {
207         return inst_.GetSecondaryOpcode();
208     }
209 
IsPrimaryOpcodeValid()210     bool IsPrimaryOpcodeValid() const
211     {
212         return inst_.IsPrimaryOpcodeValid();
213     }
214 
215     bool IsRegDefined(int reg);
216 
ToString(Type tp)217     PandaString ToString(Type tp) const
218     {
219         return tp.ToString(GetTypeSystem());
220     }
221 
ToString(PandaVector<Type> const & types)222     PandaString ToString(PandaVector<Type> const &types) const
223     {
224         PandaString result {"[ "};
225         bool comma = false;
226         for (const auto &type : types) {
227             if (comma) {
228                 result += ", ";
229             }
230             result += ToString(type);
231             comma = true;
232         }
233         result += " ]";
234         return result;
235     }
236 
ToString(AbstractTypedValue const * atv)237     PandaString ToString(AbstractTypedValue const *atv) const
238     {
239         return atv->ToString(GetTypeSystem());
240     }
241 
StringDataToString(panda_file::File::StringData sd)242     static PandaString StringDataToString(panda_file::File::StringData sd)
243     {
244         PandaString res {reinterpret_cast<char *>(const_cast<uint8_t *>(sd.data))};
245         return res;
246     }
247 
CheckType(Type type,Type tgtType)248     bool CheckType(Type type, Type tgtType)
249     {
250         return IsSubtype(type, tgtType, GetTypeSystem());
251     }
252 
253     bool CheckRegType(int reg, Type tgtType);
254 
255     const AbstractTypedValue &GetReg(int regIdx);
256 
257     Type GetRegType(int regIdx);
258 
259     void SetReg(int regIdx, const AbstractTypedValue &val);
260     void SetReg(int regIdx, Type type);
261 
262     void SetRegAndOthersOfSameOrigin(int regIdx, const AbstractTypedValue &val);
263     void SetRegAndOthersOfSameOrigin(int regIdx, Type type);
264 
265     const AbstractTypedValue &GetAcc();
266 
267     Type GetAccType();
268 
269     void SetAcc(const AbstractTypedValue &val);
270     void SetAcc(Type type);
271 
272     void SetAccAndOthersOfSameOrigin(const AbstractTypedValue &val);
273     void SetAccAndOthersOfSameOrigin(Type type);
274 
275     AbstractTypedValue MkVal(Type t);
276 
GetTypeSystem()277     TypeSystem *GetTypeSystem() const
278     {
279         return context_.GetTypeSystem();
280     }
281 
282     Type TypeOfClass(Class const *klass);
283 
284     Type ReturnType();
285 
286     ExecContext &ExecCtx();
287 
288     void DumpRegs(const RegContext &ctx);
289 
290     bool CheckCtxCompatibility(const RegContext &src, const RegContext &dst);
291 
292     void Sync();
293 
AssignRegToReg(int dst,int src)294     void AssignRegToReg(int dst, int src)
295     {
296         auto atv = GetReg(src);
297         if (!atv.GetOrigin().IsValid()) {
298             // generate new origin and set all values to be originated at it
299             AbstractTypedValue newAtv {atv, inst_};
300             SetReg(src, newAtv);
301             SetReg(dst, newAtv);
302         } else {
303             SetReg(dst, atv);
304         }
305     }
306 
AssignAccToReg(int src)307     void AssignAccToReg(int src)
308     {
309         AssignRegToReg(acc, src);
310     }
311 
AssignRegToAcc(int dst)312     void AssignRegToAcc(int dst)
313     {
314         AssignRegToReg(dst, acc);
315     }
316 
317     // Names meanings: vs - v_source, vd - v_destination
318     template <BytecodeInstructionSafe::Format FORMAT>
HandleMov()319     bool HandleMov()
320     {
321         LOG_INST();
322         DBGBRK();
323         uint16_t vd = inst_.GetVReg<FORMAT, 0x00>();
324         uint16_t vs = inst_.GetVReg<FORMAT, 0x01>();
325         Sync();
326 
327         if (!CheckRegType(vs, bits32_)) {
328             SET_STATUS_FOR_MSG(BadRegisterType, WARNING);
329             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
330             return false;
331         }
332         AssignRegToReg(vd, vs);
333         MoveToNextInst<FORMAT>();
334         return true;
335     }
336 
337     template <BytecodeInstructionSafe::Format FORMAT>
HandleMovWide()338     bool HandleMovWide()
339     {
340         LOG_INST();
341         DBGBRK();
342         uint16_t vd = inst_.GetVReg<FORMAT, 0x00>();
343         uint16_t vs = inst_.GetVReg<FORMAT, 0x01>();
344         Sync();
345 
346         if (!CheckRegType(vs, bits64_)) {
347             SET_STATUS_FOR_MSG(BadRegisterType, WARNING);
348             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
349             return false;
350         }
351         AssignRegToReg(vd, vs);
352         MoveToNextInst<FORMAT>();
353         return true;
354     }
355 
356     template <BytecodeInstructionSafe::Format FORMAT>
HandleMovObj()357     bool HandleMovObj()
358     {
359         LOG_INST();
360         DBGBRK();
361         uint16_t vd = inst_.GetVReg<FORMAT, 0x00>();
362         uint16_t vs = inst_.GetVReg<FORMAT, 0x01>();
363         Sync();
364         if (!CheckRegType(vs, refType_)) {
365             SET_STATUS_FOR_MSG(BadRegisterType, WARNING);
366             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
367             return false;
368         }
369         AssignRegToReg(vd, vs);
370         MoveToNextInst<FORMAT>();
371         return true;
372     }
373 
374     template <BytecodeInstructionSafe::Format FORMAT>
HandleMovDyn()375     bool HandleMovDyn()
376     {
377         LOG_INST();
378         DBGBRK();
379         Sync();
380         LOG(ERROR, VERIFIER) << "Verifier error: instruction is not implemented";
381         status_ = VerificationStatus::ERROR;
382         return false;
383     }
384 
385     template <BytecodeInstructionSafe::Format FORMAT>
HandleNop()386     bool HandleNop()
387     {
388         LOG_INST();
389         DBGBRK();
390         Sync();
391         MoveToNextInst<FORMAT>();
392         return true;
393     }
394 
395     template <BytecodeInstructionSafe::Format FORMAT>
HandleMovi()396     bool HandleMovi()
397     {
398         LOG_INST();
399         DBGBRK();
400         uint16_t vd = inst_.GetVReg<FORMAT>();
401         Sync();
402         SetReg(vd, i32_);
403         MoveToNextInst<FORMAT>();
404         return true;
405     }
406 
407     template <BytecodeInstructionSafe::Format FORMAT>
HandleMoviWide()408     bool HandleMoviWide()
409     {
410         LOG_INST();
411         DBGBRK();
412         uint16_t vd = inst_.GetVReg<FORMAT>();
413         Sync();
414         SetReg(vd, i64_);
415         MoveToNextInst<FORMAT>();
416         return true;
417     }
418 
419     template <BytecodeInstructionSafe::Format FORMAT>
HandleFmovi()420     bool HandleFmovi()
421     {
422         LOG_INST();
423         DBGBRK();
424         uint16_t vd = inst_.GetVReg<FORMAT>();
425         Sync();
426         SetReg(vd, f32_);
427         MoveToNextInst<FORMAT>();
428         return true;
429     }
430 
431     template <BytecodeInstructionSafe::Format FORMAT>
HandleFmoviWide()432     bool HandleFmoviWide()
433     {
434         LOG_INST();
435         DBGBRK();
436         uint16_t vd = inst_.GetVReg<FORMAT>();
437         Sync();
438         SetReg(vd, f64_);
439         MoveToNextInst<FORMAT>();
440         return true;
441     }
442 
443     template <BytecodeInstructionSafe::Format FORMAT>
HandleMovNull()444     bool HandleMovNull()
445     {
446         LOG_INST();
447         DBGBRK();
448         uint16_t vd = inst_.GetVReg<FORMAT>();
449         Sync();
450         SetReg(vd, nullRefType_);
451         MoveToNextInst<FORMAT>();
452         return true;
453     }
454 
455     template <BytecodeInstructionSafe::Format FORMAT>
HandleLda()456     bool HandleLda()
457     {
458         LOG_INST();
459         DBGBRK();
460         uint16_t vs = inst_.GetVReg<FORMAT>();
461         Sync();
462         if (!CheckRegType(vs, bits32_)) {
463             SET_STATUS_FOR_MSG(BadRegisterType, WARNING);
464             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
465             return false;
466         }
467         AssignAccToReg(vs);
468         MoveToNextInst<FORMAT>();
469         return true;
470     }
471 
472     template <BytecodeInstructionSafe::Format FORMAT>
473     bool HandleLdaDyn();
474 
475     template <BytecodeInstructionSafe::Format FORMAT>
476     bool HandleLdaiDyn();
477 
478     template <BytecodeInstructionSafe::Format FORMAT>
HandleLdaWide()479     bool HandleLdaWide()
480     {
481         LOG_INST();
482         DBGBRK();
483         uint16_t vs = inst_.GetVReg<FORMAT>();
484         Sync();
485         if (!CheckRegType(vs, bits64_)) {
486             SET_STATUS_FOR_MSG(BadRegisterType, WARNING);
487             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
488             return false;
489         }
490         AssignAccToReg(vs);
491         MoveToNextInst<FORMAT>();
492         return true;
493     }
494 
495     template <BytecodeInstructionSafe::Format FORMAT>
HandleLdaObj()496     bool HandleLdaObj()
497     {
498         LOG_INST();
499         DBGBRK();
500         uint16_t vs = inst_.GetVReg<FORMAT>();
501         Sync();
502         if (!CheckRegType(vs, refType_)) {
503             SET_STATUS_FOR_MSG(BadRegisterType, WARNING);
504             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
505             return false;
506         }
507         AssignAccToReg(vs);
508         MoveToNextInst<FORMAT>();
509         return true;
510     }
511 
512     template <BytecodeInstructionSafe::Format FORMAT>
HandleLdai()513     bool HandleLdai()
514     {
515         LOG_INST();
516         DBGBRK();
517         Sync();
518         SetAcc(i32_);
519         MoveToNextInst<FORMAT>();
520         return true;
521     }
522 
523     template <BytecodeInstructionSafe::Format FORMAT>
HandleLdaiWide()524     bool HandleLdaiWide()
525     {
526         LOG_INST();
527         DBGBRK();
528         Sync();
529         SetAcc(i64_);
530         MoveToNextInst<FORMAT>();
531         return true;
532     }
533 
534     template <BytecodeInstructionSafe::Format FORMAT>
HandleFldai()535     bool HandleFldai()
536     {
537         LOG_INST();
538         DBGBRK();
539         Sync();
540         SetAcc(f32_);
541         MoveToNextInst<FORMAT>();
542         return true;
543     }
544 
545     template <BytecodeInstructionSafe::Format FORMAT>
HandleFldaiWide()546     bool HandleFldaiWide()
547     {
548         LOG_INST();
549         DBGBRK();
550         Sync();
551         SetAcc(f64_);
552         MoveToNextInst<FORMAT>();
553         return true;
554     }
555 
556     template <BytecodeInstructionSafe::Format FORMAT>
557     bool HandleFldaiDyn();
558 
559     template <BytecodeInstructionSafe::Format FORMAT>
HandleLdaStr()560     bool HandleLdaStr()
561     {
562         LOG_INST();
563         DBGBRK();
564         Sync();
565         Type cachedType = GetCachedType();
566         if (!cachedType.IsConsistent()) {
567             SET_STATUS_FOR_MSG(CannotResolveClassId, OK);
568             return false;
569         }
570         SetAcc(cachedType);
571         MoveToNextInst<FORMAT>();
572         return true;
573     }
574 
575     template <BytecodeInstructionSafe::Format FORMAT>
HandleLdaConst()576     bool HandleLdaConst()
577     {
578         LOG_INST();
579         DBGBRK();
580         uint16_t vd = inst_.GetVReg<FORMAT, 0>();
581         Sync();
582         Type cachedType = GetCachedType();
583         if (!cachedType.IsConsistent()) {
584             // NOTE(vdyadov): refactor to verifier-messages
585             LOG(ERROR, VERIFIER) << "Verifier error: HandleLdaConst cache error";
586             status_ = VerificationStatus::ERROR;
587             return false;
588         }
589         SetReg(vd, cachedType);
590         MoveToNextInst<FORMAT>();
591         return true;
592     }
593 
594     template <BytecodeInstructionSafe::Format FORMAT>
HandleLdaType()595     bool HandleLdaType()
596     {
597         LOG_INST();
598         DBGBRK();
599         Sync();
600         Type cachedType = GetCachedType();
601         if (!cachedType.IsConsistent()) {
602             SET_STATUS_FOR_MSG(CannotResolveClassId, OK);
603             return false;
604         }
605         if (cachedType != GetTypeSystem()->ClassClass()) {
606             LOG(ERROR, VERIFIER) << "LDA_TYPE type must be Class.";
607             return false;
608         }
609         SetAcc(GetTypeSystem()->ClassClass());
610         MoveToNextInst<FORMAT>();
611         return true;
612     }
613 
614     template <BytecodeInstructionSafe::Format FORMAT>
HandleLdaNull()615     bool HandleLdaNull()
616     {
617         LOG_INST();
618         DBGBRK();
619         Sync();
620         SetAcc(nullRefType_);
621         MoveToNextInst<FORMAT>();
622         return true;
623     }
624 
625     template <BytecodeInstructionSafe::Format FORMAT>
HandleSta()626     bool HandleSta()
627     {
628         LOG_INST();
629         DBGBRK();
630         uint16_t vd = inst_.GetVReg<FORMAT>();
631         Sync();
632         if (!CheckRegType(acc, bits32_)) {
633             SET_STATUS_FOR_MSG(BadRegisterType, WARNING);
634             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
635             return false;
636         }
637         AssignRegToAcc(vd);
638         MoveToNextInst<FORMAT>();
639         return true;
640     }
641 
642     template <BytecodeInstructionSafe::Format FORMAT>
643     bool HandleStaDyn();
644 
645     template <BytecodeInstructionSafe::Format FORMAT>
HandleStaWide()646     bool HandleStaWide()
647     {
648         LOG_INST();
649         DBGBRK();
650         uint16_t vd = inst_.GetVReg<FORMAT>();
651         Sync();
652         if (!CheckRegType(acc, bits64_)) {
653             SET_STATUS_FOR_MSG(BadRegisterType, WARNING);
654             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
655             return false;
656         }
657         AssignRegToAcc(vd);
658         MoveToNextInst<FORMAT>();
659         return true;
660     }
661 
662     template <BytecodeInstructionSafe::Format FORMAT>
HandleStaObj()663     bool HandleStaObj()
664     {
665         LOG_INST();
666         DBGBRK();
667         uint16_t vd = inst_.GetVReg<FORMAT>();
668         Sync();
669         if (!CheckRegType(acc, refType_)) {
670             SET_STATUS_FOR_MSG(BadRegisterType, WARNING);
671             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
672             return false;
673         }
674         AssignRegToAcc(vd);
675         MoveToNextInst<FORMAT>();
676         return true;
677     }
678 
679     template <BytecodeInstructionSafe::Format FORMAT>
HandleJmp()680     bool HandleJmp()
681     {
682         LOG_INST();
683         DBGBRK();
684         int32_t imm = inst_.GetImm<FORMAT>();
685         Sync();
686         ProcessBranching(imm);
687         return false;
688     }
689 
690     template <BytecodeInstructionSafe::Format FORMAT>
691     bool HandleCmpWide();
692 
693     template <BytecodeInstructionSafe::Format FORMAT>
694     bool HandleUcmp();
695 
696     template <BytecodeInstructionSafe::Format FORMAT>
697     bool HandleUcmpWide();
698 
699     template <BytecodeInstructionSafe::Format FORMAT>
700     bool HandleFcmpl();
701 
702     template <BytecodeInstructionSafe::Format FORMAT>
703     bool HandleFcmplWide();
704 
705     template <BytecodeInstructionSafe::Format FORMAT>
706     bool HandleFcmpg();
707 
708     template <BytecodeInstructionSafe::Format FORMAT>
709     bool HandleFcmpgWide();
710 
711     template <BytecodeInstructionSafe::Format FORMAT>
712     bool HandleJeqz();
713 
714     template <BytecodeInstructionSafe::Format FORMAT>
HandleJeqzObj()715     bool HandleJeqzObj()
716     {
717         LOG_INST();
718         DBGBRK();
719         auto imm = inst_.GetImm<FORMAT>();
720 
721         Sync();
722 
723         if (!CheckRegType(acc, refType_)) {
724             SET_STATUS_FOR_MSG(BadRegisterType, WARNING);
725             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
726             return false;
727         }
728 
729         // NOTE(vdyadov): think of two-pass absint, where we can catch const-null cases
730 
731         auto type = GetRegType(acc);
732         SetAccAndOthersOfSameOrigin(nullRefType_);
733 
734         if (!ProcessBranching(imm)) {
735             return false;
736         }
737 
738         SetAccAndOthersOfSameOrigin(type);
739         MoveToNextInst<FORMAT>();
740         return true;
741     }
742 
743     template <BytecodeInstructionSafe::Format FORMAT>
744     bool HandleJnez();
745 
746     template <BytecodeInstructionSafe::Format FORMAT>
HandleJnezObj()747     bool HandleJnezObj()
748     {
749         LOG_INST();
750         DBGBRK();
751         auto imm = inst_.GetImm<FORMAT>();
752         Sync();
753 
754         if (!CheckRegType(acc, refType_)) {
755             SET_STATUS_FOR_MSG(BadRegisterType, WARNING);
756             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
757             return false;
758         }
759 
760         if (!ProcessBranching(imm)) {
761             return false;
762         }
763 
764         SetAccAndOthersOfSameOrigin(nullRefType_);
765         MoveToNextInst<FORMAT>();
766         return true;
767     }
768 
769     template <BytecodeInstructionSafe::Format FORMAT>
770     bool HandleJltz();
771 
772     template <BytecodeInstructionSafe::Format FORMAT>
773     bool HandleJgtz();
774 
775     template <BytecodeInstructionSafe::Format FORMAT>
776     bool HandleJlez();
777 
778     template <BytecodeInstructionSafe::Format FORMAT>
779     bool HandleJgez();
780 
781     template <BytecodeInstructionSafe::Format FORMAT>
782     bool HandleJeq();
783 
784     template <BytecodeInstructionSafe::Format FORMAT>
HandleJeqObj()785     bool HandleJeqObj()
786     {
787         LOG_INST();
788         DBGBRK();
789         auto imm = inst_.GetImm<FORMAT>();
790         uint16_t vs = inst_.GetVReg<FORMAT>();
791 
792         Sync();
793 
794         if (!CheckRegType(acc, refType_)) {
795             SET_STATUS_FOR_MSG(BadRegisterType, WARNING);
796             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
797             return false;
798         }
799 
800         if (!CheckRegType(vs, refType_)) {
801             SET_STATUS_FOR_MSG(BadRegisterType, WARNING);
802             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
803             return false;
804         }
805 
806         if (!ProcessBranching(imm)) {
807             return false;
808         }
809 
810         MoveToNextInst<FORMAT>();
811         return true;
812     }
813 
814     template <BytecodeInstructionSafe::Format FORMAT>
815     bool HandleJne();
816 
817     template <BytecodeInstructionSafe::Format FORMAT>
HandleJneObj()818     bool HandleJneObj()
819     {
820         LOG_INST();
821         DBGBRK();
822         auto imm = inst_.GetImm<FORMAT>();
823         uint16_t vs = inst_.GetVReg<FORMAT>();
824 
825         Sync();
826 
827         if (!CheckRegType(acc, refType_)) {
828             SET_STATUS_FOR_MSG(BadRegisterType, WARNING);
829             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
830             return false;
831         }
832 
833         if (!CheckRegType(vs, refType_)) {
834             SET_STATUS_FOR_MSG(BadRegisterType, WARNING);
835             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
836             return false;
837         }
838 
839         if (!ProcessBranching(imm)) {
840             return false;
841         }
842 
843         MoveToNextInst<FORMAT>();
844         return true;
845     }
846 
847     template <BytecodeInstructionSafe::Format FORMAT>
848     bool HandleJlt();
849 
850     template <BytecodeInstructionSafe::Format FORMAT>
851     bool HandleJgt();
852 
853     template <BytecodeInstructionSafe::Format FORMAT>
854     bool HandleJle();
855 
856     template <BytecodeInstructionSafe::Format FORMAT>
857     bool HandleJge();
858 
859     template <BytecodeInstructionSafe::Format FORMAT>
860     bool HandleAdd2();
861 
862     template <BytecodeInstructionSafe::Format FORMAT>
863     bool HandleAdd2Wide();
864 
865     template <BytecodeInstructionSafe::Format FORMAT>
866     bool HandleFadd2();
867 
868     template <BytecodeInstructionSafe::Format FORMAT>
869     bool HandleFadd2Wide();
870 
871     template <BytecodeInstructionSafe::Format FORMAT>
872     bool HandleSub2();
873 
874     template <BytecodeInstructionSafe::Format FORMAT>
875     bool HandleSub2Wide();
876 
877     template <BytecodeInstructionSafe::Format FORMAT>
878     bool HandleFsub2();
879 
880     template <BytecodeInstructionSafe::Format FORMAT>
881     bool HandleFsub2Wide();
882 
883     template <BytecodeInstructionSafe::Format FORMAT>
884     bool HandleMul2();
885 
886     template <BytecodeInstructionSafe::Format FORMAT>
887     bool HandleMul2Wide();
888 
889     template <BytecodeInstructionSafe::Format FORMAT>
890     bool HandleFmul2();
891 
892     template <BytecodeInstructionSafe::Format FORMAT>
893     bool HandleFmul2Wide();
894 
895     template <BytecodeInstructionSafe::Format FORMAT>
896     bool HandleFdiv2();
897 
898     template <BytecodeInstructionSafe::Format FORMAT>
899     bool HandleFdiv2Wide();
900 
901     template <BytecodeInstructionSafe::Format FORMAT>
902     bool HandleFmod2();
903 
904     template <BytecodeInstructionSafe::Format FORMAT>
905     bool HandleFmod2Wide();
906 
907     template <BytecodeInstructionSafe::Format FORMAT>
908     bool HandleAnd2();
909 
910     template <BytecodeInstructionSafe::Format FORMAT>
911     bool HandleAnd2Wide();
912 
913     template <BytecodeInstructionSafe::Format FORMAT>
914     bool HandleOr2();
915 
916     template <BytecodeInstructionSafe::Format FORMAT>
917     bool HandleOr2Wide();
918 
919     template <BytecodeInstructionSafe::Format FORMAT>
920     bool HandleXor2();
921 
922     template <BytecodeInstructionSafe::Format FORMAT>
923     bool HandleXor2Wide();
924 
925     template <BytecodeInstructionSafe::Format FORMAT>
926     bool HandleShl2();
927 
928     template <BytecodeInstructionSafe::Format FORMAT>
929     bool HandleShl2Wide();
930 
931     template <BytecodeInstructionSafe::Format FORMAT>
932     bool HandleShr2();
933 
934     template <BytecodeInstructionSafe::Format FORMAT>
935     bool HandleShr2Wide();
936 
937     template <BytecodeInstructionSafe::Format FORMAT>
938     bool HandleAshr2();
939 
940     template <BytecodeInstructionSafe::Format FORMAT>
941     bool HandleAshr2Wide();
942 
943     template <BytecodeInstructionSafe::Format FORMAT>
944     bool HandleDiv2();
945 
946     template <BytecodeInstructionSafe::Format FORMAT>
947     bool HandleDiv2Wide();
948 
949     template <BytecodeInstructionSafe::Format FORMAT>
950     bool HandleMod2();
951 
952     template <BytecodeInstructionSafe::Format FORMAT>
953     bool HandleMod2Wide();
954 
955     template <BytecodeInstructionSafe::Format FORMAT>
956     bool HandleDivu2();
957 
958     template <BytecodeInstructionSafe::Format FORMAT>
959     bool HandleDivu2Wide();
960 
961     template <BytecodeInstructionSafe::Format FORMAT>
962     bool HandleModu2();
963 
964     template <BytecodeInstructionSafe::Format FORMAT>
965     bool HandleModu2Wide();
966 
967     template <BytecodeInstructionSafe::Format FORMAT>
968     bool HandleAdd2v();
969 
970     template <BytecodeInstructionSafe::Format FORMAT>
971     bool HandleAdd2vWide();
972 
973     template <BytecodeInstructionSafe::Format FORMAT>
974     bool HandleFadd2v();
975 
976     template <BytecodeInstructionSafe::Format FORMAT>
977     bool HandleFadd2vWide();
978 
979     template <BytecodeInstructionSafe::Format FORMAT>
980     bool HandleSub2v();
981 
982     template <BytecodeInstructionSafe::Format FORMAT>
983     bool HandleSub2vWide();
984 
985     template <BytecodeInstructionSafe::Format FORMAT>
986     bool HandleFsub2v();
987 
988     template <BytecodeInstructionSafe::Format FORMAT>
989     bool HandleFsub2vWide();
990 
991     template <BytecodeInstructionSafe::Format FORMAT>
992     bool HandleMul2v();
993 
994     template <BytecodeInstructionSafe::Format FORMAT>
995     bool HandleMul2vWide();
996 
997     template <BytecodeInstructionSafe::Format FORMAT>
998     bool HandleFmul2v();
999 
1000     template <BytecodeInstructionSafe::Format FORMAT>
1001     bool HandleFmul2vWide();
1002 
1003     template <BytecodeInstructionSafe::Format FORMAT>
1004     bool HandleFdiv2v();
1005 
1006     template <BytecodeInstructionSafe::Format FORMAT>
1007     bool HandleFdiv2vWide();
1008 
1009     template <BytecodeInstructionSafe::Format FORMAT>
1010     bool HandleFmod2v();
1011 
1012     template <BytecodeInstructionSafe::Format FORMAT>
1013     bool HandleFmod2vWide();
1014 
1015     template <BytecodeInstructionSafe::Format FORMAT>
1016     bool HandleAnd2v();
1017 
1018     template <BytecodeInstructionSafe::Format FORMAT>
1019     bool HandleAnd2vWide();
1020 
1021     template <BytecodeInstructionSafe::Format FORMAT>
1022     bool HandleOr2v();
1023 
1024     template <BytecodeInstructionSafe::Format FORMAT>
1025     bool HandleOr2vWide();
1026 
1027     template <BytecodeInstructionSafe::Format FORMAT>
1028     bool HandleXor2v();
1029 
1030     template <BytecodeInstructionSafe::Format FORMAT>
1031     bool HandleXor2vWide();
1032 
1033     template <BytecodeInstructionSafe::Format FORMAT>
1034     bool HandleShl2v();
1035 
1036     template <BytecodeInstructionSafe::Format FORMAT>
1037     bool HandleShl2vWide();
1038 
1039     template <BytecodeInstructionSafe::Format FORMAT>
1040     bool HandleShr2v();
1041 
1042     template <BytecodeInstructionSafe::Format FORMAT>
1043     bool HandleShr2vWide();
1044 
1045     template <BytecodeInstructionSafe::Format FORMAT>
1046     bool HandleAshr2v();
1047 
1048     template <BytecodeInstructionSafe::Format FORMAT>
1049     bool HandleAshr2vWide();
1050 
1051     template <BytecodeInstructionSafe::Format FORMAT>
1052     bool HandleDiv2v();
1053 
1054     template <BytecodeInstructionSafe::Format FORMAT>
1055     bool HandleDiv2vWide();
1056 
1057     template <BytecodeInstructionSafe::Format FORMAT>
1058     bool HandleMod2v();
1059 
1060     template <BytecodeInstructionSafe::Format FORMAT>
1061     bool HandleMod2vWide();
1062 
1063     template <BytecodeInstructionSafe::Format FORMAT>
1064     bool HandleDivu2v();
1065 
1066     template <BytecodeInstructionSafe::Format FORMAT>
1067     bool HandleDivu2vWide();
1068 
1069     template <BytecodeInstructionSafe::Format FORMAT>
1070     bool HandleModu2v();
1071 
1072     template <BytecodeInstructionSafe::Format FORMAT>
1073     bool HandleModu2vWide();
1074 
1075     template <BytecodeInstructionSafe::Format FORMAT>
1076     bool HandleAdd();
1077 
1078     template <BytecodeInstructionSafe::Format FORMAT>
1079     bool HandleSub();
1080 
1081     template <BytecodeInstructionSafe::Format FORMAT>
1082     bool HandleMul();
1083 
1084     template <BytecodeInstructionSafe::Format FORMAT>
1085     bool HandleAnd();
1086 
1087     template <BytecodeInstructionSafe::Format FORMAT>
1088     bool HandleOr();
1089 
1090     template <BytecodeInstructionSafe::Format FORMAT>
1091     bool HandleXor();
1092 
1093     template <BytecodeInstructionSafe::Format FORMAT>
1094     bool HandleShl();
1095 
1096     template <BytecodeInstructionSafe::Format FORMAT>
1097     bool HandleShr();
1098 
1099     template <BytecodeInstructionSafe::Format FORMAT>
1100     bool HandleAshr();
1101 
1102     template <BytecodeInstructionSafe::Format FORMAT>
1103     bool HandleDiv();
1104 
1105     template <BytecodeInstructionSafe::Format FORMAT>
1106     bool HandleMod();
1107 
1108     template <BytecodeInstructionSafe::Format FORMAT>
1109     bool HandleAddv();
1110 
1111     template <BytecodeInstructionSafe::Format FORMAT>
1112     bool HandleSubv();
1113 
1114     template <BytecodeInstructionSafe::Format FORMAT>
1115     bool HandleMulv();
1116 
1117     template <BytecodeInstructionSafe::Format FORMAT>
1118     bool HandleAndv();
1119 
1120     template <BytecodeInstructionSafe::Format FORMAT>
1121     bool HandleOrv();
1122 
1123     template <BytecodeInstructionSafe::Format FORMAT>
1124     bool HandleXorv();
1125 
1126     template <BytecodeInstructionSafe::Format FORMAT>
1127     bool HandleShlv();
1128 
1129     template <BytecodeInstructionSafe::Format FORMAT>
1130     bool HandleShrv();
1131 
1132     template <BytecodeInstructionSafe::Format FORMAT>
1133     bool HandleAshrv();
1134 
1135     template <BytecodeInstructionSafe::Format FORMAT>
1136     bool HandleDivv();
1137 
1138     template <BytecodeInstructionSafe::Format FORMAT>
1139     bool HandleModv();
1140 
1141     template <BytecodeInstructionSafe::Format FORMAT>
1142     bool HandleAddi();
1143 
1144     template <BytecodeInstructionSafe::Format FORMAT>
1145     bool HandleSubi();
1146 
1147     template <BytecodeInstructionSafe::Format FORMAT>
1148     bool HandleMuli();
1149 
1150     template <BytecodeInstructionSafe::Format FORMAT>
1151     bool HandleAndi();
1152 
1153     template <BytecodeInstructionSafe::Format FORMAT>
1154     bool HandleOri();
1155 
1156     template <BytecodeInstructionSafe::Format FORMAT>
1157     bool HandleXori();
1158 
1159     template <BytecodeInstructionSafe::Format FORMAT>
1160     bool HandleShli();
1161 
1162     template <BytecodeInstructionSafe::Format FORMAT>
1163     bool HandleShri();
1164 
1165     template <BytecodeInstructionSafe::Format FORMAT>
1166     bool HandleAshri();
1167 
1168     template <BytecodeInstructionSafe::Format FORMAT>
1169     bool HandleDivi();
1170 
1171     template <BytecodeInstructionSafe::Format FORMAT>
1172     bool HandleModi();
1173 
1174     template <BytecodeInstructionSafe::Format FORMAT>
1175     bool HandleAddiv();
1176 
1177     template <BytecodeInstructionSafe::Format FORMAT>
1178     bool HandleSubiv();
1179 
1180     template <BytecodeInstructionSafe::Format FORMAT>
1181     bool HandleMuliv();
1182 
1183     template <BytecodeInstructionSafe::Format FORMAT>
1184     bool HandleAndiv();
1185 
1186     template <BytecodeInstructionSafe::Format FORMAT>
1187     bool HandleOriv();
1188 
1189     template <BytecodeInstructionSafe::Format FORMAT>
1190     bool HandleXoriv();
1191 
1192     template <BytecodeInstructionSafe::Format FORMAT>
1193     bool HandleShliv();
1194 
1195     template <BytecodeInstructionSafe::Format FORMAT>
1196     bool HandleShriv();
1197 
1198     template <BytecodeInstructionSafe::Format FORMAT>
1199     bool HandleAshriv();
1200 
1201     template <BytecodeInstructionSafe::Format FORMAT>
1202     bool HandleDiviv();
1203 
1204     template <BytecodeInstructionSafe::Format FORMAT>
1205     bool HandleModiv();
1206 
1207     template <BytecodeInstructionSafe::Format FORMAT>
HandleNeg()1208     bool HandleNeg()
1209     {
1210         LOG_INST();
1211         DBGBRK();
1212         Sync();
1213         return CheckUnaryOp<FORMAT>(integral32_, i32_);
1214     }
1215 
1216     template <BytecodeInstructionSafe::Format FORMAT>
HandleNegWide()1217     bool HandleNegWide()
1218     {
1219         LOG_INST();
1220         DBGBRK();
1221         Sync();
1222         return CheckUnaryOp<FORMAT>(integral64_, i64_);
1223     }
1224 
1225     template <BytecodeInstructionSafe::Format FORMAT>
HandleFneg()1226     bool HandleFneg()
1227     {
1228         LOG_INST();
1229         DBGBRK();
1230         Sync();
1231         return CheckUnaryOp<FORMAT>(f32_);
1232     }
1233 
1234     template <BytecodeInstructionSafe::Format FORMAT>
HandleFnegWide()1235     bool HandleFnegWide()
1236     {
1237         LOG_INST();
1238         DBGBRK();
1239         Sync();
1240         return CheckUnaryOp<FORMAT>(f64_);
1241     }
1242 
1243     template <BytecodeInstructionSafe::Format FORMAT>
HandleNot()1244     bool HandleNot()
1245     {
1246         LOG_INST();
1247         DBGBRK();
1248         Sync();
1249         return CheckUnaryOp<FORMAT>(integral32_);
1250     }
1251 
1252     template <BytecodeInstructionSafe::Format FORMAT>
HandleNotWide()1253     bool HandleNotWide()
1254     {
1255         LOG_INST();
1256         DBGBRK();
1257         Sync();
1258         return CheckUnaryOp<FORMAT>(integral64_);
1259     }
1260 
1261     template <BytecodeInstructionSafe::Format FORMAT>
HandleInci()1262     bool HandleInci()
1263     {
1264         LOG_INST();
1265         DBGBRK();
1266         uint16_t vx = inst_.GetVReg<FORMAT>();
1267         Sync();
1268         if (!CheckRegType(vx, integral32_)) {
1269             SET_STATUS_FOR_MSG(BadRegisterType, WARNING);
1270             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
1271             return false;
1272         }
1273         MoveToNextInst<FORMAT>();
1274         return true;
1275     }
1276 
1277     template <BytecodeInstructionSafe::Format FORMAT>
1278     bool HandleI32toi64();
1279 
1280     template <BytecodeInstructionSafe::Format FORMAT>
1281     bool HandleI32toi16();
1282 
1283     template <BytecodeInstructionSafe::Format FORMAT>
1284     bool HandleI32tou16();
1285 
1286     template <BytecodeInstructionSafe::Format FORMAT>
1287     bool HandleI32toi8();
1288 
1289     template <BytecodeInstructionSafe::Format FORMAT>
1290     bool HandleI32tou8();
1291 
1292     template <BytecodeInstructionSafe::Format FORMAT>
1293     bool HandleI32tou1();
1294 
1295     template <BytecodeInstructionSafe::Format FORMAT>
1296     bool HandleI32tof32();
1297 
1298     template <BytecodeInstructionSafe::Format FORMAT>
1299     bool HandleI32tof64();
1300 
1301     template <BytecodeInstructionSafe::Format FORMAT>
1302     bool HandleU32toi64();
1303 
1304     template <BytecodeInstructionSafe::Format FORMAT>
1305     bool HandleU32toi16();
1306 
1307     template <BytecodeInstructionSafe::Format FORMAT>
1308     bool HandleU32tou16();
1309 
1310     template <BytecodeInstructionSafe::Format FORMAT>
1311     bool HandleU32toi8();
1312 
1313     template <BytecodeInstructionSafe::Format FORMAT>
1314     bool HandleU32tou8();
1315 
1316     template <BytecodeInstructionSafe::Format FORMAT>
1317     bool HandleU32tou1();
1318 
1319     template <BytecodeInstructionSafe::Format FORMAT>
1320     bool HandleU32tof32();
1321 
1322     template <BytecodeInstructionSafe::Format FORMAT>
1323     bool HandleU32tof64();
1324 
1325     template <BytecodeInstructionSafe::Format FORMAT>
1326     bool HandleI64toi32();
1327 
1328     template <BytecodeInstructionSafe::Format FORMAT>
1329     bool HandleI64tou1();
1330 
1331     template <BytecodeInstructionSafe::Format FORMAT>
1332     bool HandleI64tof32();
1333 
1334     template <BytecodeInstructionSafe::Format FORMAT>
1335     bool HandleI64tof64();
1336 
1337     template <BytecodeInstructionSafe::Format FORMAT>
1338     bool HandleU64toi32();
1339 
1340     template <BytecodeInstructionSafe::Format FORMAT>
1341     bool HandleU64tou32();
1342 
1343     template <BytecodeInstructionSafe::Format FORMAT>
1344     bool HandleU64tou1();
1345 
1346     template <BytecodeInstructionSafe::Format FORMAT>
1347     bool HandleU64tof32();
1348 
1349     template <BytecodeInstructionSafe::Format FORMAT>
1350     bool HandleU64tof64();
1351 
1352     template <BytecodeInstructionSafe::Format FORMAT>
1353     bool HandleF32tof64();
1354 
1355     template <BytecodeInstructionSafe::Format FORMAT>
1356     bool HandleF32toi32();
1357 
1358     template <BytecodeInstructionSafe::Format FORMAT>
1359     bool HandleF32toi64();
1360 
1361     template <BytecodeInstructionSafe::Format FORMAT>
1362     bool HandleF32tou32();
1363 
1364     template <BytecodeInstructionSafe::Format FORMAT>
1365     bool HandleF32tou64();
1366 
1367     template <BytecodeInstructionSafe::Format FORMAT>
1368     bool HandleF64tof32();
1369 
1370     template <BytecodeInstructionSafe::Format FORMAT>
1371     bool HandleF64toi64();
1372 
1373     template <BytecodeInstructionSafe::Format FORMAT>
1374     bool HandleF64toi32();
1375 
1376     template <BytecodeInstructionSafe::Format FORMAT>
1377     bool HandleF64tou64();
1378 
1379     template <BytecodeInstructionSafe::Format FORMAT>
1380     bool HandleF64tou32();
1381 
1382     template <BytecodeInstructionSafe::Format FORMAT>
HandleCallPolymorphicShort()1383     bool HandleCallPolymorphicShort()
1384     {
1385         LOG_INST();
1386         DBGBRK();
1387         Sync();
1388         MoveToNextInst<FORMAT>();
1389         return true;
1390     }
1391 
1392     template <BytecodeInstructionSafe::Format FORMAT>
HandleCallPolymorphic()1393     bool HandleCallPolymorphic()
1394     {
1395         LOG_INST();
1396         DBGBRK();
1397         Sync();
1398         MoveToNextInst<FORMAT>();
1399         return true;
1400     }
1401 
1402     template <BytecodeInstructionSafe::Format FORMAT>
HandleCallPolymorphicRange()1403     bool HandleCallPolymorphicRange()
1404     {
1405         LOG_INST();
1406         DBGBRK();
1407         Sync();
1408         // It is a runtime (not verifier) responibility to check the MethodHandle.invoke()
1409         // parameter types and throw the WrongMethodTypeException if need
1410         MoveToNextInst<FORMAT>();
1411         return true;
1412     }
1413 
1414     template <BytecodeInstructionSafe::Format FORMAT>
HandleCallePolymorphicShort()1415     bool HandleCallePolymorphicShort()
1416     {
1417         LOG_INST();
1418         DBGBRK();
1419         Sync();
1420         MoveToNextInst<FORMAT>();
1421         return true;
1422     }
1423 
1424     template <BytecodeInstructionSafe::Format FORMAT>
HandleCallePolymorphic()1425     bool HandleCallePolymorphic()
1426     {
1427         LOG_INST();
1428         DBGBRK();
1429         Sync();
1430         MoveToNextInst<FORMAT>();
1431         return true;
1432     }
1433 
1434     template <BytecodeInstructionSafe::Format FORMAT>
HandleCallePolymorphicRange()1435     bool HandleCallePolymorphicRange()
1436     {
1437         LOG_INST();
1438         DBGBRK();
1439         Sync();
1440         // It is a runtime (not verifier) responibility to check the  MethodHandle.invokeExact()
1441         // parameter types and throw the WrongMethodTypeException if need
1442         MoveToNextInst<FORMAT>();
1443         return true;
1444     }
1445 
1446     template <BytecodeInstructionSafe::Format FORMAT>
HandleLdarr8()1447     bool HandleLdarr8()
1448     {
1449         LOG_INST();
1450         DBGBRK();
1451         uint16_t vs = inst_.GetVReg<FORMAT>();
1452         Sync();
1453         return CheckArrayLoad<FORMAT>(vs, {u1_, i8_});
1454     }
1455 
1456     template <BytecodeInstructionSafe::Format FORMAT>
HandleLdarr16()1457     bool HandleLdarr16()
1458     {
1459         LOG_INST();
1460         DBGBRK();
1461         uint16_t vs = inst_.GetVReg<FORMAT>();
1462         Sync();
1463         return CheckArrayLoad<FORMAT>(vs, {i16_});
1464     }
1465 
1466     template <BytecodeInstructionSafe::Format FORMAT>
HandleLdarr()1467     bool HandleLdarr()
1468     {
1469         LOG_INST();
1470         DBGBRK();
1471         uint16_t vs = inst_.GetVReg<FORMAT>();
1472         Sync();
1473         return CheckArrayLoad<FORMAT>(vs, {i32_, u32_});
1474     }
1475 
1476     template <BytecodeInstructionSafe::Format FORMAT>
HandleLdarrWide()1477     bool HandleLdarrWide()
1478     {
1479         LOG_INST();
1480         DBGBRK();
1481         uint16_t vs = inst_.GetVReg<FORMAT>();
1482         Sync();
1483         return CheckArrayLoad<FORMAT>(vs, {i64_, u64_});
1484     }
1485 
1486     template <BytecodeInstructionSafe::Format FORMAT>
HandleLdarru8()1487     bool HandleLdarru8()
1488     {
1489         LOG_INST();
1490         DBGBRK();
1491         uint16_t vs = inst_.GetVReg<FORMAT>();
1492         Sync();
1493         return CheckArrayLoad<FORMAT>(vs, {u1_, u8_});
1494     }
1495 
1496     template <BytecodeInstructionSafe::Format FORMAT>
HandleLdarru16()1497     bool HandleLdarru16()
1498     {
1499         LOG_INST();
1500         DBGBRK();
1501         uint16_t vs = inst_.GetVReg<FORMAT>();
1502         Sync();
1503         return CheckArrayLoad<FORMAT>(vs, {u16_});
1504     }
1505 
1506     template <BytecodeInstructionSafe::Format FORMAT>
HandleFldarr32()1507     bool HandleFldarr32()
1508     {
1509         LOG_INST();
1510         DBGBRK();
1511         uint16_t vs = inst_.GetVReg<FORMAT>();
1512         Sync();
1513         return CheckArrayLoad<FORMAT>(vs, {f32_});
1514     }
1515 
1516     template <BytecodeInstructionSafe::Format FORMAT>
HandleFldarrWide()1517     bool HandleFldarrWide()
1518     {
1519         LOG_INST();
1520         DBGBRK();
1521         uint16_t vs = inst_.GetVReg<FORMAT>();
1522         Sync();
1523         return CheckArrayLoad<FORMAT>(vs, {f64_});
1524     }
1525 
1526     template <BytecodeInstructionSafe::Format FORMAT>
HandleLdarrObj()1527     bool HandleLdarrObj()
1528     {
1529         LOG_INST();
1530         DBGBRK();
1531         uint16_t vs = inst_.GetVReg<FORMAT>();
1532         Sync();
1533         if (!CheckRegType(acc, integral32_)) {
1534             SET_STATUS_FOR_MSG(BadRegisterType, WARNING);
1535             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
1536             return false;
1537         }
1538 
1539         if (!CheckRegType(vs, arrayType_)) {
1540             SET_STATUS_FOR_MSG(BadRegisterType, WARNING);
1541             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
1542             return false;
1543         }
1544 
1545         auto regType = GetRegType(vs);
1546         if (regType == nullRefType_) {
1547             // NOTE(vdyadov): redesign next code, after support exception handlers,
1548             //                treat it as always throw NPE
1549             SHOW_MSG(AlwaysNpe)
1550             LOG_VERIFIER_ALWAYS_NPE(vs);
1551             END_SHOW_MSG();
1552             SetAcc(top_);
1553             SET_STATUS_FOR_MSG(AlwaysNpe, OK);
1554             return false;
1555         }
1556 
1557         auto arrEltType = regType.GetArrayElementType(GetTypeSystem());
1558         if (!IsSubtype(arrEltType, refType_, GetTypeSystem())) {
1559             SHOW_MSG(BadArrayElementType)
1560             LOG_VERIFIER_BAD_ARRAY_ELEMENT_TYPE(ToString(arrEltType), ToString(refType_));
1561             END_SHOW_MSG();
1562             SET_STATUS_FOR_MSG(BadArrayElementType, WARNING);
1563             return false;
1564         }
1565         SetAcc(arrEltType);
1566         MoveToNextInst<FORMAT>();
1567         return true;
1568     }
1569 
1570     template <BytecodeInstructionSafe::Format FORMAT>
HandleStarr8()1571     bool HandleStarr8()
1572     {
1573         LOG_INST();
1574         DBGBRK();
1575         uint16_t v1 = inst_.GetVReg<FORMAT, 0x00>();
1576         uint16_t v2 = inst_.GetVReg<FORMAT, 0x01>();
1577         Sync();
1578         return CheckArrayStoreExact<FORMAT>(v1, v2, integral32_, {u1_, i8_, u8_});
1579     }
1580 
1581     template <BytecodeInstructionSafe::Format FORMAT>
HandleStarr16()1582     bool HandleStarr16()
1583     {
1584         LOG_INST();
1585         DBGBRK();
1586         uint16_t v1 = inst_.GetVReg<FORMAT, 0x00>();
1587         uint16_t v2 = inst_.GetVReg<FORMAT, 0x01>();
1588         Sync();
1589         return CheckArrayStoreExact<FORMAT>(v1, v2, integral32_, {i16_, u16_});
1590     }
1591 
1592     template <BytecodeInstructionSafe::Format FORMAT>
HandleStarr()1593     bool HandleStarr()
1594     {
1595         LOG_INST();
1596         DBGBRK();
1597         uint16_t v1 = inst_.GetVReg<FORMAT, 0x00>();
1598         uint16_t v2 = inst_.GetVReg<FORMAT, 0x01>();
1599         Sync();
1600         return CheckArrayStoreExact<FORMAT>(v1, v2, integral32_, {i32_, u32_});
1601     }
1602 
1603     template <BytecodeInstructionSafe::Format FORMAT>
HandleStarrWide()1604     bool HandleStarrWide()
1605     {
1606         LOG_INST();
1607         DBGBRK();
1608         uint16_t v1 = inst_.GetVReg<FORMAT, 0x00>();
1609         uint16_t v2 = inst_.GetVReg<FORMAT, 0x01>();
1610         Sync();
1611         return CheckArrayStoreExact<FORMAT>(v1, v2, integral64_, {i64_, u64_});
1612     }
1613 
1614     template <BytecodeInstructionSafe::Format FORMAT>
HandleFstarr32()1615     bool HandleFstarr32()
1616     {
1617         LOG_INST();
1618         DBGBRK();
1619         uint16_t v1 = inst_.GetVReg<FORMAT, 0x00>();
1620         uint16_t v2 = inst_.GetVReg<FORMAT, 0x01>();
1621         Sync();
1622         return CheckArrayStoreExact<FORMAT>(v1, v2, float32_, {f32_});
1623     }
1624 
1625     template <BytecodeInstructionSafe::Format FORMAT>
HandleFstarrWide()1626     bool HandleFstarrWide()
1627     {
1628         LOG_INST();
1629         DBGBRK();
1630         uint16_t v1 = inst_.GetVReg<FORMAT, 0x00>();
1631         uint16_t v2 = inst_.GetVReg<FORMAT, 0x01>();
1632         Sync();
1633         return CheckArrayStoreExact<FORMAT>(v1, v2, float64_, {f64_});
1634     }
1635 
1636     template <BytecodeInstructionSafe::Format FORMAT>
HandleStarrObj()1637     bool HandleStarrObj()
1638     {
1639         LOG_INST();
1640         DBGBRK();
1641         uint16_t v1 = inst_.GetVReg<FORMAT, 0x00>();
1642         uint16_t v2 = inst_.GetVReg<FORMAT, 0x01>();
1643         Sync();
1644         return CheckArrayStore<FORMAT>(v1, v2, refType_);
1645     }
1646 
1647     template <BytecodeInstructionSafe::Format FORMAT>
HandleLenarr()1648     bool HandleLenarr()
1649     {
1650         LOG_INST();
1651         DBGBRK();
1652         uint16_t vs = inst_.GetVReg<FORMAT>();
1653         Sync();
1654         if (!CheckRegType(vs, arrayType_)) {
1655             SET_STATUS_FOR_MSG(BadRegisterType, WARNING);
1656             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
1657             return false;
1658         }
1659         SetAcc(i32_);
1660         MoveToNextInst<FORMAT>();
1661         return true;
1662     }
1663 
1664     template <BytecodeInstructionSafe::Format FORMAT>
HandleNewarr()1665     bool HandleNewarr()
1666     {
1667         LOG_INST();
1668         DBGBRK();
1669         uint16_t vd = inst_.GetVReg<FORMAT, 0>();
1670         uint16_t vs = inst_.GetVReg<FORMAT, 1>();
1671         Sync();
1672         if (!CheckRegType(vs, integral32_)) {
1673             SET_STATUS_FOR_MSG(BadRegisterType, WARNING);
1674             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
1675             return false;
1676         }
1677         Type type = GetCachedType();
1678         if (!type.IsConsistent()) {
1679             SET_STATUS_FOR_MSG(CannotResolveClassId, OK);
1680             return false;
1681         }
1682         SHOW_MSG(DebugType)
1683         LOG_VERIFIER_DEBUG_TYPE(ToString(type));
1684         END_SHOW_MSG();
1685         if (!IsSubtype(type, arrayType_, GetTypeSystem())) {
1686             // NOTE(vdyadov): implement StrictSubtypes function to not include array_type_ in output
1687             SHOW_MSG(ArrayOfNonArrayType)
1688             LOG_VERIFIER_ARRAY_OF_NON_ARRAY_TYPE(ToString(type));
1689             END_SHOW_MSG();
1690             SET_STATUS_FOR_MSG(ArrayOfNonArrayType, WARNING);
1691             return false;
1692         }
1693         SetReg(vd, type);
1694         MoveToNextInst<FORMAT>();
1695         return true;
1696     }
1697 
1698     template <BytecodeInstructionSafe::Format FORMAT>
HandleNewobj()1699     bool HandleNewobj()
1700     {
1701         LOG_INST();
1702         DBGBRK();
1703         uint16_t vd = inst_.GetVReg<FORMAT, 0>();
1704         Sync();
1705         Type cachedType = GetCachedType();
1706         if (!cachedType.IsConsistent()) {
1707             LOG(ERROR, VERIFIER) << "Verifier error: HandleNewobj cache error";
1708             status_ = VerificationStatus::ERROR;
1709             return false;
1710         }
1711         SHOW_MSG(DebugType)
1712         LOG_VERIFIER_DEBUG_TYPE(ToString(cachedType));
1713         END_SHOW_MSG();
1714         if (!IsSubtype(cachedType, objectType_, GetTypeSystem())) {
1715             SHOW_MSG(ObjectOfNonObjectType)
1716             LOG_VERIFIER_OBJECT_OF_NON_OBJECT_TYPE(ToString(cachedType));
1717             END_SHOW_MSG();
1718             SET_STATUS_FOR_MSG(ObjectOfNonObjectType, WARNING);
1719             return false;
1720         }
1721         SetReg(vd, cachedType);
1722         MoveToNextInst<FORMAT>();
1723         return true;
1724     }
1725 
1726     template <BytecodeInstructionSafe::Format FORMAT>
CheckCallCtor(Method const * ctor,Span<int> regs)1727     bool CheckCallCtor(Method const *ctor, Span<int> regs)
1728     {
1729         Type objType = TypeOfClass(ctor->GetClass());
1730 
1731         // NOTE(vdyadov): put under NDEBUG?
1732         {
1733             if (debugCtx->SkipVerificationOfCall(ctor->GetUniqId())) {
1734                 SetAcc(objType);
1735                 MoveToNextInst<FORMAT>();
1736                 return true;
1737             }
1738         }
1739 
1740         auto ctorNameGetter = [&ctor]() { return ctor->GetFullName(); };
1741 
1742         bool check = CheckMethodArgs(ctorNameGetter, ctor, regs, objType);
1743         if (check) {
1744             SetAcc(objType);
1745             MoveToNextInst<FORMAT>();
1746         }
1747         return check;
1748     }
1749 
1750     template <BytecodeInstructionSafe::Format FORMAT>
CheckCtor(Span<int> regs)1751     bool CheckCtor(Span<int> regs)
1752     {
1753         Type type = GetCachedType();
1754         if (UNLIKELY(type.IsClass() && type.GetClass()->IsArrayClass())) {
1755             if (job_->IsMethodPresentForOffset(inst_.GetOffset())) {
1756                 // Array constructors are synthetic methods; ClassLinker does not provide them.
1757                 LOG(ERROR, VERIFIER) << "Verifier internal error: ArrayCtor should not be instantiated as method";
1758                 return false;
1759             }
1760             SHOW_MSG(DebugArrayConstructor)
1761             LOG_VERIFIER_DEBUG_ARRAY_CONSTRUCTOR();
1762             END_SHOW_MSG();
1763             return CheckArrayCtor<FORMAT>(type, regs);
1764         }
1765 
1766         Method const *ctor = GetCachedMethod();
1767 
1768         if (!type.IsConsistent() || ctor == nullptr) {
1769             SET_STATUS_FOR_MSG(CannotResolveMethodId, OK);
1770             SET_STATUS_FOR_MSG(CannotResolveClassId, OK);
1771             return false;
1772         }
1773 
1774         PandaString expectedName = panda::panda_file::GetCtorName(ctor->GetClass()->GetSourceLang());
1775         if (!ctor->IsConstructor() || ctor->IsStatic() || expectedName != StringDataToString(ctor->GetName())) {
1776             SHOW_MSG(InitobjCallsNotConstructor)
1777             LOG_VERIFIER_INITOBJ_CALLS_NOT_CONSTRUCTOR(ctor->GetFullName());
1778             END_SHOW_MSG();
1779             SET_STATUS_FOR_MSG(InitobjCallsNotConstructor, WARNING);
1780             return false;
1781         }
1782 
1783         SHOW_MSG(DebugConstructor)
1784         LOG_VERIFIER_DEBUG_CONSTRUCTOR(ctor->GetFullName());
1785         END_SHOW_MSG();
1786 
1787         return CheckCallCtor<FORMAT>(ctor, regs);
1788     }
1789 
1790     template <BytecodeInstructionSafe::Format FORMAT>
HandleInitobj()1791     bool HandleInitobj()
1792     {
1793         LOG_INST();
1794         DBGBRK();
1795         uint16_t vs1 = inst_.GetVReg<FORMAT, 0x00>();
1796         uint16_t vs2 = inst_.GetVReg<FORMAT, 0x01>();
1797         uint16_t vs3 = inst_.GetVReg<FORMAT, 0x02>();
1798         uint16_t vs4 = inst_.GetVReg<FORMAT, 0x03>();
1799         Sync();
1800         std::array<int, 4UL> regs {vs1, vs2, vs3, vs4};
1801         return CheckCtor<FORMAT>(Span {regs});
1802     }
1803 
1804     template <BytecodeInstructionSafe::Format FORMAT>
HandleInitobjShort()1805     bool HandleInitobjShort()
1806     {
1807         LOG_INST();
1808         DBGBRK();
1809         uint16_t vs1 = inst_.GetVReg<FORMAT, 0x00>();
1810         uint16_t vs2 = inst_.GetVReg<FORMAT, 0x01>();
1811         Sync();
1812         std::array<int, 2UL> regs {vs1, vs2};
1813         return CheckCtor<FORMAT>(Span {regs});
1814     }
1815 
1816     template <BytecodeInstructionSafe::Format FORMAT>
HandleInitobjRange()1817     bool HandleInitobjRange()
1818     {
1819         LOG_INST();
1820         DBGBRK();
1821         uint16_t vs = inst_.GetVReg<FORMAT, 0x00>();
1822         Sync();
1823         std::vector<int> regs;
1824         for (auto regIdx = vs; ExecCtx().CurrentRegContext().IsRegDefined(regIdx); regIdx++) {
1825             regs.push_back(regIdx);
1826         }
1827         return CheckCtor<FORMAT>(Span {regs});
1828     }
1829 
GetFieldType()1830     Type GetFieldType()
1831     {
1832         const Field *field = GetCachedField();
1833 
1834         if (field == nullptr) {
1835             SET_STATUS_FOR_MSG(CannotResolveFieldId, OK);
1836             return {};
1837         }
1838 
1839         ScopedChangeThreadStatus st {ManagedThread::GetCurrent(), ThreadStatus::RUNNING};
1840         Job::ErrorHandler handler;
1841         auto typeCls = field->ResolveTypeClass(&handler);
1842         if (typeCls == nullptr) {
1843             return Type {};
1844         }
1845         return Type {typeCls};
1846     }
1847 
GetFieldObject()1848     Type GetFieldObject()
1849     {
1850         Field const *field = GetCachedField();
1851 
1852         if (field == nullptr) {
1853             SET_STATUS_FOR_MSG(CannotResolveFieldId, OK);
1854             return {};
1855         }
1856         return TypeOfClass(field->GetClass());
1857     }
1858 
CheckFieldAccess(int regIdx,Type expectedFieldType,bool isStatic,bool isVolatile)1859     bool CheckFieldAccess(int regIdx, Type expectedFieldType, bool isStatic, bool isVolatile)
1860     {
1861         Field const *field = GetCachedField();
1862 
1863         if (field == nullptr) {
1864             SET_STATUS_FOR_MSG(CannotResolveFieldId, OK);
1865             return false;
1866         }
1867 
1868         if (isStatic != field->IsStatic()) {
1869             SHOW_MSG(ExpectedStaticOrInstanceField)
1870             LOG_VERIFIER_EXPECTED_STATIC_OR_INSTANCE_FIELD(isStatic);
1871             END_SHOW_MSG();
1872             SET_STATUS_FOR_MSG(ExpectedStaticOrInstanceField, WARNING);
1873             return false;
1874         }
1875 
1876         if (isVolatile != field->IsVolatile()) {
1877             // if the inst is volatile but the field is not
1878             if (isVolatile) {
1879                 SHOW_MSG(ExpectedVolatileField)
1880                 LOG_VERIFIER_EXPECTED_VOLATILE_FIELD();
1881                 END_SHOW_MSG();
1882                 SET_STATUS_FOR_MSG(ExpectedVolatileField, WARNING);
1883                 return false;
1884             }
1885             // if the instruction is not volatile but the field is
1886             SHOW_MSG(ExpectedInstanceField)
1887             LOG_VERIFIER_EXPECTED_INSTANCE_FIELD();
1888             END_SHOW_MSG();
1889             SET_STATUS_FOR_MSG(ExpectedInstanceField, ERROR);
1890             return false;
1891         }
1892 
1893         Type fieldObjType = GetFieldObject();
1894         Type fieldType = GetFieldType();
1895         if (!fieldType.IsConsistent()) {
1896             LOG_VERIFIER_CANNOT_RESOLVE_FIELD_TYPE(GetFieldName(field));
1897             return false;
1898         }
1899 
1900         if (!isStatic) {
1901             if (!IsRegDefined(regIdx)) {
1902                 SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
1903                 return false;
1904             }
1905             Type objType = GetRegType(regIdx);
1906             if (objType == nullRefType_) {
1907                 // NOTE(vdyadov): redesign next code, after support exception handlers,
1908                 //                treat it as always throw NPE
1909                 SHOW_MSG(AlwaysNpe)
1910                 LOG_VERIFIER_ALWAYS_NPE(regIdx);
1911                 END_SHOW_MSG();
1912                 SET_STATUS_FOR_MSG(AlwaysNpe, OK);
1913                 return false;
1914             }
1915             if (!IsSubtype(objType, fieldObjType, GetTypeSystem())) {
1916                 SHOW_MSG(InconsistentRegisterAndFieldTypes)
1917                 LOG_VERIFIER_INCONSISTENT_REGISTER_AND_FIELD_TYPES(GetFieldName(field), regIdx, ToString(objType),
1918                                                                    ToString(fieldObjType));
1919                 END_SHOW_MSG();
1920                 SET_STATUS_FOR_MSG(InconsistentRegisterAndFieldTypes, WARNING);
1921             }
1922         }
1923 
1924         if (!IsSubtype(fieldType, expectedFieldType, GetTypeSystem())) {
1925             SHOW_MSG(UnexpectedFieldType)
1926             LOG_VERIFIER_UNEXPECTED_FIELD_TYPE(GetFieldName(field), ToString(fieldType), ToString(expectedFieldType));
1927             END_SHOW_MSG();
1928             SET_STATUS_FOR_MSG(UnexpectedFieldType, WARNING);
1929             return false;
1930         }
1931 
1932         auto *plugin = job_->JobPlugin();
1933         auto const *jobMethod = job_->JobMethod();
1934         auto result = plugin->CheckFieldAccessViolation(field, jobMethod, GetTypeSystem());
1935         if (!result.IsOk()) {
1936             const auto &verifOpts = config->opts;
1937             if (verifOpts.debug.allow.fieldAccessViolation && result.IsError()) {
1938                 result.status = VerificationStatus::WARNING;
1939             }
1940             LogInnerMessage(result);
1941             LOG_VERIFIER_DEBUG_FIELD2(GetFieldName(field));
1942             status_ = result.status;
1943             return status_ != VerificationStatus::ERROR;
1944         }
1945 
1946         return !result.IsError();
1947     }
1948 
1949     template <BytecodeInstructionSafe::Format FORMAT>
1950     bool ProcessFieldLoad(int regDest, int regSrc, Type expectedFieldType, bool isStatic, bool isVolatile = false)
1951     {
1952         if (!CheckFieldAccess(regSrc, expectedFieldType, isStatic, isVolatile)) {
1953             return false;
1954         }
1955         Field const *field = GetCachedField();
1956 
1957         if (field == nullptr) {
1958             SET_STATUS_FOR_MSG(CannotResolveFieldId, OK);
1959             return false;
1960         }
1961 
1962         auto type = GetFieldType();
1963         if (!type.IsConsistent()) {
1964             return false;
1965         }
1966         SetReg(regDest, type);
1967         MoveToNextInst<FORMAT>();
1968         return true;
1969     }
1970 
1971     template <BytecodeInstructionSafe::Format FORMAT>
ProcessFieldLoad(int regIdx,Type expectedFieldType,bool isStatic)1972     bool ProcessFieldLoad(int regIdx, Type expectedFieldType, bool isStatic)
1973     {
1974         return ProcessFieldLoad<FORMAT>(acc, regIdx, expectedFieldType, isStatic);
1975     }
1976 
1977     template <BytecodeInstructionSafe::Format FORMAT>
ProcessFieldLoadVolatile(int regDest,int regSrc,Type expectedFieldType,bool isStatic)1978     bool ProcessFieldLoadVolatile(int regDest, int regSrc, Type expectedFieldType, bool isStatic)
1979     {
1980         return ProcessFieldLoad<FORMAT>(regDest, regSrc, expectedFieldType, isStatic, true);
1981     }
1982 
1983     template <BytecodeInstructionSafe::Format FORMAT>
ProcessFieldLoadVolatile(int regIdx,Type expectedFieldType,bool isStatic)1984     bool ProcessFieldLoadVolatile(int regIdx, Type expectedFieldType, bool isStatic)
1985     {
1986         return ProcessFieldLoadVolatile<FORMAT>(acc, regIdx, expectedFieldType, isStatic);
1987     }
1988 
1989     template <BytecodeInstructionSafe::Format FORMAT>
HandleLdobj()1990     bool HandleLdobj()
1991     {
1992         LOG_INST();
1993         DBGBRK();
1994         uint16_t vs = inst_.GetVReg<FORMAT>();
1995         Sync();
1996         return ProcessFieldLoad<FORMAT>(vs, bits32_, false);
1997     }
1998 
1999     template <BytecodeInstructionSafe::Format FORMAT>
HandleLdobjWide()2000     bool HandleLdobjWide()
2001     {
2002         LOG_INST();
2003         DBGBRK();
2004         uint16_t vs = inst_.GetVReg<FORMAT>();
2005         Sync();
2006         return ProcessFieldLoad<FORMAT>(vs, bits64_, false);
2007     }
2008 
2009     template <BytecodeInstructionSafe::Format FORMAT>
HandleLdobjObj()2010     bool HandleLdobjObj()
2011     {
2012         LOG_INST();
2013         DBGBRK();
2014         uint16_t vs = inst_.GetVReg<FORMAT>();
2015         Sync();
2016         return ProcessFieldLoad<FORMAT>(vs, refType_, false);
2017     }
2018 
2019     template <BytecodeInstructionSafe::Format FORMAT>
HandleLdobjV()2020     bool HandleLdobjV()
2021     {
2022         LOG_INST();
2023         DBGBRK();
2024         uint16_t vd = inst_.GetVReg<FORMAT, 0>();
2025         uint16_t vs = inst_.GetVReg<FORMAT, 1>();
2026         Sync();
2027         return ProcessFieldLoad<FORMAT>(vd, vs, bits32_, false);
2028     }
2029 
2030     template <BytecodeInstructionSafe::Format FORMAT>
HandleLdobjVWide()2031     bool HandleLdobjVWide()
2032     {
2033         LOG_INST();
2034         DBGBRK();
2035         uint16_t vd = inst_.GetVReg<FORMAT, 0>();
2036         uint16_t vs = inst_.GetVReg<FORMAT, 1>();
2037         Sync();
2038         return ProcessFieldLoad<FORMAT>(vd, vs, bits64_, false);
2039     }
2040 
2041     template <BytecodeInstructionSafe::Format FORMAT>
HandleLdobjVObj()2042     bool HandleLdobjVObj()
2043     {
2044         LOG_INST();
2045         DBGBRK();
2046         uint16_t vd = inst_.GetVReg<FORMAT, 0>();
2047         uint16_t vs = inst_.GetVReg<FORMAT, 1>();
2048         Sync();
2049         return ProcessFieldLoad<FORMAT>(vd, vs, refType_, false);
2050     }
2051 
2052     template <BytecodeInstructionSafe::Format FORMAT>
HandleLdobjVolatile()2053     bool HandleLdobjVolatile()
2054     {
2055         LOG_INST();
2056         DBGBRK();
2057         uint16_t vs = inst_.GetVReg<FORMAT>();
2058         Sync();
2059         return ProcessFieldLoadVolatile<FORMAT>(vs, bits32_, false);
2060     }
2061 
2062     template <BytecodeInstructionSafe::Format FORMAT>
HandleLdobjVolatileWide()2063     bool HandleLdobjVolatileWide()
2064     {
2065         LOG_INST();
2066         DBGBRK();
2067         uint16_t vs = inst_.GetVReg<FORMAT>();
2068         Sync();
2069         return ProcessFieldLoadVolatile<FORMAT>(vs, bits64_, false);
2070     }
2071 
2072     template <BytecodeInstructionSafe::Format FORMAT>
HandleLdobjVolatileObj()2073     bool HandleLdobjVolatileObj()
2074     {
2075         LOG_INST();
2076         DBGBRK();
2077         uint16_t vs = inst_.GetVReg<FORMAT>();
2078         Sync();
2079         return ProcessFieldLoadVolatile<FORMAT>(vs, refType_, false);
2080     }
2081 
2082     template <BytecodeInstructionSafe::Format FORMAT>
HandleLdobjVolatileV()2083     bool HandleLdobjVolatileV()
2084     {
2085         LOG_INST();
2086         DBGBRK();
2087         uint16_t vd = inst_.GetVReg<FORMAT, 0>();
2088         uint16_t vs = inst_.GetVReg<FORMAT, 1>();
2089         Sync();
2090         return ProcessFieldLoadVolatile<FORMAT>(vd, vs, bits32_, false);
2091     }
2092 
2093     template <BytecodeInstructionSafe::Format FORMAT>
HandleLdobjVolatileVWide()2094     bool HandleLdobjVolatileVWide()
2095     {
2096         LOG_INST();
2097         DBGBRK();
2098         uint16_t vd = inst_.GetVReg<FORMAT, 0>();
2099         uint16_t vs = inst_.GetVReg<FORMAT, 1>();
2100         Sync();
2101         return ProcessFieldLoadVolatile<FORMAT>(vd, vs, bits64_, false);
2102     }
2103 
2104     template <BytecodeInstructionSafe::Format FORMAT>
HandleLdobjVolatileVObj()2105     bool HandleLdobjVolatileVObj()
2106     {
2107         LOG_INST();
2108         DBGBRK();
2109         uint16_t vd = inst_.GetVReg<FORMAT, 0>();
2110         uint16_t vs = inst_.GetVReg<FORMAT, 1>();
2111         Sync();
2112         return ProcessFieldLoadVolatile<FORMAT>(vd, vs, refType_, false);
2113     }
2114 
2115     template <BytecodeInstructionSafe::Format FORMAT, typename Check>
2116     bool ProcessStoreField(int vs, int vd, Type expectedFieldType, bool isStatic, Check check, bool isVolatile = false)
2117     {
2118         if (!CheckRegType(vs, expectedFieldType)) {
2119             SET_STATUS_FOR_MSG(BadRegisterType, WARNING);
2120             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
2121             return false;
2122         }
2123 
2124         if (!CheckFieldAccess(vd, expectedFieldType, isStatic, isVolatile)) {
2125             return false;
2126         }
2127 
2128         Field const *field = GetCachedField();
2129 
2130         if (field == nullptr) {
2131             SET_STATUS_FOR_MSG(CannotResolveFieldId, OK);
2132             return false;
2133         }
2134         Type fieldType = GetFieldType();
2135         if (!fieldType.IsConsistent()) {
2136             return false;
2137         }
2138 
2139         Type vsType = GetRegType(vs);
2140 
2141         CheckResult const &result = check(fieldType.ToTypeId(), vsType.ToTypeId());
2142         if (result.status != VerificationStatus::OK) {
2143             LOG_VERIFIER_DEBUG_STORE_FIELD(GetFieldName(field), ToString(fieldType), ToString(vsType));
2144             status_ = result.status;
2145             if (result.IsError()) {
2146                 return false;
2147             }
2148         }
2149 
2150         MoveToNextInst<FORMAT>();
2151         return true;
2152     }
2153 
2154     template <BytecodeInstructionSafe::Format FORMAT>
ProcessStobj(int vs,int vd,bool isStatic)2155     bool ProcessStobj(int vs, int vd, bool isStatic)
2156     {
2157         return ProcessStoreField<FORMAT>(vs, vd, bits32_, isStatic, CheckStobj);
2158     }
2159 
2160     template <BytecodeInstructionSafe::Format FORMAT>
ProcessStobj(int vd,bool isStatic)2161     bool ProcessStobj(int vd, bool isStatic)
2162     {
2163         return ProcessStobj<FORMAT>(acc, vd, isStatic);
2164     }
2165 
2166     template <BytecodeInstructionSafe::Format FORMAT>
ProcessStobjVolatile(int vs,int vd,bool isStatic)2167     bool ProcessStobjVolatile(int vs, int vd, bool isStatic)
2168     {
2169         return ProcessStoreField<FORMAT>(vs, vd, bits32_, isStatic, CheckStobj, true);
2170     }
2171 
2172     template <BytecodeInstructionSafe::Format FORMAT>
ProcessStobjVolatile(int vd,bool isStatic)2173     bool ProcessStobjVolatile(int vd, bool isStatic)
2174     {
2175         return ProcessStobjVolatile<FORMAT>(acc, vd, isStatic);
2176     }
2177 
2178     template <BytecodeInstructionSafe::Format FORMAT>
HandleStobj()2179     bool HandleStobj()
2180     {
2181         LOG_INST();
2182         DBGBRK();
2183         uint16_t vd = inst_.GetVReg<FORMAT>();
2184         Sync();
2185 
2186         return ProcessStobj<FORMAT>(vd, false);
2187     }
2188 
2189     template <BytecodeInstructionSafe::Format FORMAT>
HandleStobjV()2190     bool HandleStobjV()
2191     {
2192         LOG_INST();
2193         DBGBRK();
2194         uint16_t vs = inst_.GetVReg<FORMAT, 0>();
2195         uint16_t vd = inst_.GetVReg<FORMAT, 1>();
2196         Sync();
2197 
2198         return ProcessStobj<FORMAT>(vs, vd, false);
2199     }
2200 
2201     template <BytecodeInstructionSafe::Format FORMAT>
HandleStobjVolatile()2202     bool HandleStobjVolatile()
2203     {
2204         LOG_INST();
2205         DBGBRK();
2206         uint16_t vd = inst_.GetVReg<FORMAT>();
2207         Sync();
2208 
2209         return ProcessStobjVolatile<FORMAT>(vd, false);
2210     }
2211 
2212     template <BytecodeInstructionSafe::Format FORMAT>
HandleStobjVolatileV()2213     bool HandleStobjVolatileV()
2214     {
2215         LOG_INST();
2216         DBGBRK();
2217         uint16_t vs = inst_.GetVReg<FORMAT, 0>();
2218         uint16_t vd = inst_.GetVReg<FORMAT, 1>();
2219         Sync();
2220 
2221         return ProcessStobjVolatile<FORMAT>(vs, vd, false);
2222     }
2223 
2224     template <BytecodeInstructionSafe::Format FORMAT>
ProcessStobjWide(int vs,int vd,bool isStatic)2225     bool ProcessStobjWide(int vs, int vd, bool isStatic)
2226     {
2227         return ProcessStoreField<FORMAT>(vs, vd, bits64_, isStatic, CheckStobjWide);
2228     }
2229 
2230     template <BytecodeInstructionSafe::Format FORMAT>
ProcessStobjWide(int vd,bool isStatic)2231     bool ProcessStobjWide(int vd, bool isStatic)
2232     {
2233         return ProcessStobjWide<FORMAT>(acc, vd, isStatic);
2234     }
2235 
2236     template <BytecodeInstructionSafe::Format FORMAT>
ProcessStobjVolatileWide(int vs,int vd,bool isStatic)2237     bool ProcessStobjVolatileWide(int vs, int vd, bool isStatic)
2238     {
2239         return ProcessStoreField<FORMAT>(vs, vd, bits64_, isStatic, CheckStobjWide, true);
2240     }
2241 
2242     template <BytecodeInstructionSafe::Format FORMAT>
ProcessStobjVolatileWide(int vd,bool isStatic)2243     bool ProcessStobjVolatileWide(int vd, bool isStatic)
2244     {
2245         return ProcessStobjVolatileWide<FORMAT>(acc, vd, isStatic);
2246     }
2247 
2248     template <BytecodeInstructionSafe::Format FORMAT>
HandleStobjWide()2249     bool HandleStobjWide()
2250     {
2251         LOG_INST();
2252         DBGBRK();
2253         uint16_t vd = inst_.GetVReg<FORMAT>();
2254         Sync();
2255 
2256         return ProcessStobjWide<FORMAT>(vd, false);
2257     }
2258 
2259     template <BytecodeInstructionSafe::Format FORMAT>
HandleStobjVWide()2260     bool HandleStobjVWide()
2261     {
2262         LOG_INST();
2263         DBGBRK();
2264         uint16_t vs = inst_.GetVReg<FORMAT, 0>();
2265         uint16_t vd = inst_.GetVReg<FORMAT, 1>();
2266         Sync();
2267 
2268         return ProcessStobjWide<FORMAT>(vs, vd, false);
2269     }
2270 
2271     template <BytecodeInstructionSafe::Format FORMAT>
HandleStobjVolatileWide()2272     bool HandleStobjVolatileWide()
2273     {
2274         LOG_INST();
2275         DBGBRK();
2276         uint16_t vd = inst_.GetVReg<FORMAT>();
2277         Sync();
2278 
2279         return ProcessStobjVolatileWide<FORMAT>(vd, false);
2280     }
2281 
2282     template <BytecodeInstructionSafe::Format FORMAT>
HandleStobjVolatileVWide()2283     bool HandleStobjVolatileVWide()
2284     {
2285         LOG_INST();
2286         DBGBRK();
2287         uint16_t vs = inst_.GetVReg<FORMAT, 0>();
2288         uint16_t vd = inst_.GetVReg<FORMAT, 1>();
2289         Sync();
2290 
2291         return ProcessStobjVolatileWide<FORMAT>(vs, vd, false);
2292     }
2293 
2294     template <BytecodeInstructionSafe::Format FORMAT>
2295     bool ProcessStobjObj(int vs, int vd, bool isStatic, bool isVolatile = false)
2296     {
2297         if (!CheckFieldAccess(vd, refType_, isStatic, isVolatile)) {
2298             return false;
2299         }
2300 
2301         Field const *field = GetCachedField();
2302 
2303         if (field == nullptr) {
2304             SET_STATUS_FOR_MSG(CannotResolveFieldId, OK);
2305             return false;
2306         }
2307 
2308         Type fieldType = GetFieldType();
2309         if (!fieldType.IsConsistent()) {
2310             return false;
2311         }
2312 
2313         if (!CheckRegType(vs, refType_)) {
2314             SET_STATUS_FOR_MSG(BadRegisterType, WARNING);
2315             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
2316             return false;
2317         }
2318 
2319         Type vsType = GetRegType(vs);
2320         if (!IsSubtype(vsType, fieldType, GetTypeSystem())) {
2321             SHOW_MSG(BadAccumulatorType)
2322             LOG_VERIFIER_BAD_ACCUMULATOR_TYPE(ToString(vsType), ToString(fieldType));
2323             END_SHOW_MSG();
2324             SET_STATUS_FOR_MSG(BadAccumulatorType, WARNING);
2325             return false;
2326         }
2327 
2328         MoveToNextInst<FORMAT>();
2329         return true;
2330     }
2331 
2332     template <BytecodeInstructionSafe::Format FORMAT>
ProcessStobjObj(int vd,bool isStatic)2333     bool ProcessStobjObj(int vd, bool isStatic)
2334     {
2335         return ProcessStobjObj<FORMAT>(acc, vd, isStatic);
2336     }
2337 
2338     template <BytecodeInstructionSafe::Format FORMAT>
ProcessStobjVolatileObj(int vs,int vd,bool isStatic)2339     bool ProcessStobjVolatileObj(int vs, int vd, bool isStatic)
2340     {
2341         return ProcessStobjObj<FORMAT>(vs, vd, isStatic, true);
2342     }
2343 
2344     template <BytecodeInstructionSafe::Format FORMAT>
ProcessStobjVolatileObj(int vd,bool isStatic)2345     bool ProcessStobjVolatileObj(int vd, bool isStatic)
2346     {
2347         return ProcessStobjVolatileObj<FORMAT>(acc, vd, isStatic);
2348     }
2349 
2350     template <BytecodeInstructionSafe::Format FORMAT>
HandleStobjObj()2351     bool HandleStobjObj()
2352     {
2353         LOG_INST();
2354         DBGBRK();
2355         uint16_t vd = inst_.GetVReg<FORMAT>();
2356         Sync();
2357         return ProcessStobjObj<FORMAT>(vd, false);
2358     }
2359 
2360     template <BytecodeInstructionSafe::Format FORMAT>
HandleStobjVObj()2361     bool HandleStobjVObj()
2362     {
2363         LOG_INST();
2364         DBGBRK();
2365         uint16_t vs = inst_.GetVReg<FORMAT, 0>();
2366         uint16_t vd = inst_.GetVReg<FORMAT, 1>();
2367         Sync();
2368         return ProcessStobjObj<FORMAT>(vs, vd, false);
2369     }
2370 
2371     template <BytecodeInstructionSafe::Format FORMAT>
HandleStobjVolatileObj()2372     bool HandleStobjVolatileObj()
2373     {
2374         LOG_INST();
2375         DBGBRK();
2376         uint16_t vd = inst_.GetVReg<FORMAT>();
2377         Sync();
2378         return ProcessStobjVolatileObj<FORMAT>(vd, false);
2379     }
2380 
2381     template <BytecodeInstructionSafe::Format FORMAT>
HandleStobjVolatileVObj()2382     bool HandleStobjVolatileVObj()
2383     {
2384         LOG_INST();
2385         DBGBRK();
2386         uint16_t vs = inst_.GetVReg<FORMAT, 0>();
2387         uint16_t vd = inst_.GetVReg<FORMAT, 1>();
2388         Sync();
2389         return ProcessStobjVolatileObj<FORMAT>(vs, vd, false);
2390     }
2391 
2392     template <BytecodeInstructionSafe::Format FORMAT>
HandleLdstatic()2393     bool HandleLdstatic()
2394     {
2395         LOG_INST();
2396         DBGBRK();
2397         Sync();
2398         return ProcessFieldLoad<FORMAT>(invalidReg, bits32_, true);
2399     }
2400 
2401     template <BytecodeInstructionSafe::Format FORMAT>
HandleLdstaticWide()2402     bool HandleLdstaticWide()
2403     {
2404         LOG_INST();
2405         DBGBRK();
2406         Sync();
2407         return ProcessFieldLoad<FORMAT>(invalidReg, bits64_, true);
2408     }
2409 
2410     template <BytecodeInstructionSafe::Format FORMAT>
HandleLdstaticObj()2411     bool HandleLdstaticObj()
2412     {
2413         LOG_INST();
2414         DBGBRK();
2415         Sync();
2416         return ProcessFieldLoad<FORMAT>(invalidReg, refType_, true);
2417     }
2418 
2419     template <BytecodeInstructionSafe::Format FORMAT>
HandleLdstaticVolatile()2420     bool HandleLdstaticVolatile()
2421     {
2422         LOG_INST();
2423         DBGBRK();
2424         Sync();
2425         return ProcessFieldLoadVolatile<FORMAT>(invalidReg, bits32_, true);
2426     }
2427 
2428     template <BytecodeInstructionSafe::Format FORMAT>
HandleLdstaticVolatileWide()2429     bool HandleLdstaticVolatileWide()
2430     {
2431         LOG_INST();
2432         DBGBRK();
2433         Sync();
2434         return ProcessFieldLoadVolatile<FORMAT>(invalidReg, bits64_, true);
2435     }
2436 
2437     template <BytecodeInstructionSafe::Format FORMAT>
HandleLdstaticVolatileObj()2438     bool HandleLdstaticVolatileObj()
2439     {
2440         LOG_INST();
2441         DBGBRK();
2442         Sync();
2443         return ProcessFieldLoadVolatile<FORMAT>(invalidReg, refType_, true);
2444     }
2445 
2446     template <BytecodeInstructionSafe::Format FORMAT>
HandleStstatic()2447     bool HandleStstatic()
2448     {
2449         LOG_INST();
2450         DBGBRK();
2451         Sync();
2452         return ProcessStobj<FORMAT>(invalidReg, true);
2453     }
2454 
2455     template <BytecodeInstructionSafe::Format FORMAT>
HandleStstaticWide()2456     bool HandleStstaticWide()
2457     {
2458         LOG_INST();
2459         DBGBRK();
2460         Sync();
2461         return ProcessStobjWide<FORMAT>(invalidReg, true);
2462     }
2463 
2464     template <BytecodeInstructionSafe::Format FORMAT>
HandleStstaticObj()2465     bool HandleStstaticObj()
2466     {
2467         LOG_INST();
2468         DBGBRK();
2469         Sync();
2470         return ProcessStobjObj<FORMAT>(invalidReg, true);
2471     }
2472 
2473     template <BytecodeInstructionSafe::Format FORMAT>
HandleStstaticVolatile()2474     bool HandleStstaticVolatile()
2475     {
2476         LOG_INST();
2477         DBGBRK();
2478         Sync();
2479         return ProcessStobjVolatile<FORMAT>(invalidReg, true);
2480     }
2481 
2482     template <BytecodeInstructionSafe::Format FORMAT>
HandleStstaticVolatileWide()2483     bool HandleStstaticVolatileWide()
2484     {
2485         LOG_INST();
2486         DBGBRK();
2487         Sync();
2488         return ProcessStobjVolatileWide<FORMAT>(invalidReg, true);
2489     }
2490 
2491     template <BytecodeInstructionSafe::Format FORMAT>
HandleStstaticVolatileObj()2492     bool HandleStstaticVolatileObj()
2493     {
2494         LOG_INST();
2495         DBGBRK();
2496         Sync();
2497         return ProcessStobjVolatileObj<FORMAT>(invalidReg, true);
2498     }
2499 
2500     template <typename Check>
CheckReturn(Type retType,Type accType,Check check)2501     bool CheckReturn(Type retType, Type accType, Check check)
2502     {
2503         TypeId retTypeId = retType.ToTypeId();
2504 
2505         PandaVector<Type> compatibleAccTypes;
2506         // NOTE (gogabr): why recompute each time?
2507         for (size_t accIdx = 0; accIdx < static_cast<size_t>(TypeId::REFERENCE) + 1; ++accIdx) {
2508             auto accTypeId = static_cast<TypeId>(accIdx);
2509             const CheckResult &info = check(retTypeId, accTypeId);
2510             if (!info.IsError()) {
2511                 compatibleAccTypes.push_back(Type::FromTypeId(accTypeId));
2512             }
2513         }
2514 
2515         if (!CheckType(accType, primitive_) || accType == primitive_) {
2516             LOG_VERIFIER_BAD_ACCUMULATOR_RETURN_VALUE_TYPE(ToString(accType));
2517             SET_STATUS_FOR_MSG(BadAccumulatorReturnValueType, WARNING);
2518             return false;
2519         }
2520 
2521         TypeId accTypeId = accType.ToTypeId();
2522 
2523         const auto &result = check(retTypeId, accTypeId);
2524 
2525         if (!result.IsOk()) {
2526             LogInnerMessage(result);
2527             if (result.IsError()) {
2528                 LOG_VERIFIER_DEBUG_FUNCTION_RETURN_AND_ACCUMULATOR_TYPES_WITH_COMPATIBLE_TYPES(
2529                     ToString(ReturnType()), ToString(accType), ToString(compatibleAccTypes));
2530             } else {
2531                 LOG_VERIFIER_DEBUG_FUNCTION_RETURN_AND_ACCUMULATOR_TYPES(ToString(ReturnType()), ToString(accType));
2532             }
2533         }
2534 
2535         status_ = result.status;
2536         return status_ != VerificationStatus::ERROR;
2537     }
2538 
2539     template <BytecodeInstructionSafe::Format FORMAT>
HandleReturn()2540     bool HandleReturn()
2541     {
2542         LOG_INST();
2543         DBGBRK();
2544         Sync();
2545 
2546         if (!CheckType(ReturnType(), bits32_)) {
2547             LOG_VERIFIER_BAD_RETURN_INSTRUCTION_TYPE("", ToString(ReturnType()), ToString(bits32_));
2548             SET_STATUS_FOR_MSG(BadReturnInstructionType, WARNING);
2549             return false;
2550         }
2551 
2552         if (!IsRegDefined(acc)) {
2553             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
2554             return false;
2555         }
2556 
2557         // NOTE(vdyadov): handle LUB of compatible primitive types
2558         if (!CheckType(GetAccType(), bits32_)) {
2559             LOG_VERIFIER_BAD_ACCUMULATOR_RETURN_VALUE_TYPE(ToString(GetAccType()));
2560             SET_STATUS_FOR_MSG(BadAccumulatorReturnValueType, WARNING);
2561         }
2562         return false;
2563     }
2564 
2565     template <BytecodeInstructionSafe::Format FORMAT>
2566     bool HandleReturnDyn();
2567 
2568     template <BytecodeInstructionSafe::Format FORMAT>
HandleEtsLaunchShort()2569     bool HandleEtsLaunchShort()
2570     {
2571         return true;
2572     }
2573 
2574     template <BytecodeInstructionSafe::Format FORMAT>
HandleEtsLaunch()2575     bool HandleEtsLaunch()
2576     {
2577         return true;
2578     }
2579 
2580     template <BytecodeInstructionSafe::Format FORMAT>
HandleEtsLaunchRange()2581     bool HandleEtsLaunchRange()
2582     {
2583         return true;
2584     }
2585 
2586     template <BytecodeInstructionSafe::Format FORMAT>
HandleEtsLaunchVirtShort()2587     bool HandleEtsLaunchVirtShort()
2588     {
2589         return true;
2590     }
2591 
2592     template <BytecodeInstructionSafe::Format FORMAT>
HandleEtsLaunchVirt()2593     bool HandleEtsLaunchVirt()
2594     {
2595         return true;
2596     }
2597 
2598     template <BytecodeInstructionSafe::Format FORMAT>
HandleEtsLaunchVirtRange()2599     bool HandleEtsLaunchVirtRange()
2600     {
2601         return true;
2602     }
2603 
2604     template <bool IS_LOAD>
CheckFieldAccessByName(int regIdx,Type expectedFieldType)2605     bool CheckFieldAccessByName(int regIdx, Type expectedFieldType)
2606     {
2607         Field const *rawField = GetCachedField();
2608 
2609         if (rawField == nullptr) {
2610             SET_STATUS_FOR_MSG(CannotResolveFieldId, OK);
2611             return false;
2612         }
2613 
2614         if (rawField->IsStatic()) {
2615             SHOW_MSG(ExpectedStaticOrInstanceField)
2616             LOG_VERIFIER_EXPECTED_STATIC_OR_INSTANCE_FIELD(false);
2617             END_SHOW_MSG();
2618             SET_STATUS_FOR_MSG(ExpectedStaticOrInstanceField, WARNING);
2619             return false;
2620         }
2621 
2622         Type rawFieldType = GetFieldType();
2623         if (!rawFieldType.IsConsistent()) {
2624             LOG_VERIFIER_CANNOT_RESOLVE_FIELD_TYPE(GetFieldName(rawField));
2625             return false;
2626         }
2627 
2628         if (!IsRegDefined(regIdx)) {
2629             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
2630             return false;
2631         }
2632         Type objType = GetRegType(regIdx);
2633         if (objType == nullRefType_) {
2634             // NOTE(vdyadov): redesign next code, after support exception handlers,
2635             //                treat it as always throw NPE
2636             SHOW_MSG(AlwaysNpe)
2637             LOG_VERIFIER_ALWAYS_NPE(regIdx);
2638             END_SHOW_MSG();
2639             SET_STATUS_FOR_MSG(AlwaysNpe, OK);
2640             return false;
2641         }
2642 
2643         if (!objType.IsClass()) {
2644             SHOW_MSG(BadRegisterType)
2645             LOG_VERIFIER_BAD_REGISTER_CLASS_TYPE(RegisterName(regIdx, true), ToString(objType));
2646             END_SHOW_MSG();
2647             return false;
2648         }
2649         auto objClass = objType.GetClass();
2650         auto field = objClass->LookupFieldByName(rawField->GetName());
2651         Type fieldType;
2652         if (field != nullptr) {
2653             fieldType = Type::FromTypeId(field->GetTypeId());
2654         } else {
2655             Method *method = nullptr;
2656             if constexpr (IS_LOAD) {
2657                 switch (expectedFieldType.GetTypeWidth()) {
2658                     case coretypes::INT32_BITS:
2659                         method = objClass->LookupGetterByName<panda_file::Type::TypeId::I32>(rawField->GetName());
2660                         break;
2661                     case coretypes::INT64_BITS:
2662                         method = objClass->LookupGetterByName<panda_file::Type::TypeId::I64>(rawField->GetName());
2663                         break;
2664                     case 0:
2665                         method = objClass->LookupGetterByName<panda_file::Type::TypeId::REFERENCE>(rawField->GetName());
2666                         break;
2667                     default:
2668                         UNREACHABLE();
2669                 }
2670             } else {
2671                 switch (expectedFieldType.GetTypeWidth()) {
2672                     case coretypes::INT32_BITS:
2673                         method = objClass->LookupSetterByName<panda_file::Type::TypeId::I32>(rawField->GetName());
2674                         break;
2675                     case coretypes::INT64_BITS:
2676                         method = objClass->LookupSetterByName<panda_file::Type::TypeId::I64>(rawField->GetName());
2677                         break;
2678                     case 0:
2679                         method = objClass->LookupSetterByName<panda_file::Type::TypeId::REFERENCE>(rawField->GetName());
2680                         break;
2681                     default:
2682                         UNREACHABLE();
2683                 }
2684             }
2685             if (method == nullptr) {
2686                 SHOW_MSG(BadFieldNameOrBitWidth)
2687                 LOG_VERIFIER_BAD_FIELD_NAME_OR_BIT_WIDTH(GetFieldName(field), ToString(obj_type),
2688                                                          ToString(expectedFieldType));
2689                 END_SHOW_MSG();
2690                 return false;
2691             }
2692             if constexpr (IS_LOAD) {
2693                 fieldType = Type::FromTypeId(method->GetReturnType().GetId());
2694             } else {
2695                 fieldType = Type::FromTypeId(method->GetArgType(1).GetId());
2696             }
2697         }
2698 
2699         if (!IsSubtype(fieldType, expectedFieldType, GetTypeSystem())) {
2700             SHOW_MSG(UnexpectedFieldType)
2701             LOG_VERIFIER_UNEXPECTED_FIELD_TYPE(GetFieldName(field), ToString(fieldType), ToString(expectedFieldType));
2702             END_SHOW_MSG();
2703             SET_STATUS_FOR_MSG(UnexpectedFieldType, WARNING);
2704             return false;
2705         }
2706 
2707         auto *plugin = job_->JobPlugin();
2708         auto const *jobMethod = job_->JobMethod();
2709         auto result = plugin->CheckFieldAccessViolation(field, jobMethod, GetTypeSystem());
2710         if (!result.IsOk()) {
2711             const auto &verifOpts = config->opts;
2712             if (verifOpts.debug.allow.fieldAccessViolation && result.IsError()) {
2713                 result.status = VerificationStatus::WARNING;
2714             }
2715             LogInnerMessage(result);
2716             LOG_VERIFIER_DEBUG_FIELD2(GetFieldName(field));
2717             status_ = result.status;
2718             return status_ != VerificationStatus::ERROR;
2719         }
2720 
2721         return !result.IsError();
2722     }
2723 
2724     template <BytecodeInstructionSafe::Format FORMAT>
ProcessFieldLoadByName(int regSrc,Type expectedFieldType)2725     bool ProcessFieldLoadByName(int regSrc, Type expectedFieldType)
2726     {
2727         if (!CheckFieldAccessByName<true>(regSrc, expectedFieldType)) {
2728             return false;
2729         }
2730         Field const *field = GetCachedField();
2731 
2732         if (field == nullptr) {
2733             SET_STATUS_FOR_MSG(CannotResolveFieldId, OK);
2734             return false;
2735         }
2736 
2737         auto type = GetFieldType();
2738         if (!type.IsConsistent()) {
2739             return false;
2740         }
2741         SetReg(acc, type);
2742         MoveToNextInst<FORMAT>();
2743         return true;
2744     }
2745 
2746     template <BytecodeInstructionSafe::Format FORMAT>
HandleEtsLdobjName()2747     bool HandleEtsLdobjName()
2748     {
2749         LOG_INST();
2750         DBGBRK();
2751         uint16_t vs = inst_.GetVReg<FORMAT>();
2752         Sync();
2753         return ProcessFieldLoadByName<FORMAT>(vs, bits32_);
2754     }
2755 
2756     template <BytecodeInstructionSafe::Format FORMAT>
HandleEtsLdobjNameWide()2757     bool HandleEtsLdobjNameWide()
2758     {
2759         LOG_INST();
2760         DBGBRK();
2761         uint16_t vs = inst_.GetVReg<FORMAT>();
2762         Sync();
2763         return ProcessFieldLoadByName<FORMAT>(vs, bits64_);
2764     }
2765 
2766     template <BytecodeInstructionSafe::Format FORMAT>
HandleEtsLdobjNameObj()2767     bool HandleEtsLdobjNameObj()
2768     {
2769         LOG_INST();
2770         DBGBRK();
2771         uint16_t vs = inst_.GetVReg<FORMAT>();
2772         Sync();
2773         return ProcessFieldLoadByName<FORMAT>(vs, refType_);
2774     }
2775 
2776     template <BytecodeInstructionSafe::Format FORMAT, typename Check>
ProcessStoreFieldByName(int vd,Type expectedFieldType,Check check)2777     bool ProcessStoreFieldByName(int vd, Type expectedFieldType, Check check)
2778     {
2779         if (!CheckRegType(acc, expectedFieldType)) {
2780             SET_STATUS_FOR_MSG(BadRegisterType, WARNING);
2781             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
2782             return false;
2783         }
2784         if (!CheckFieldAccessByName<false>(vd, expectedFieldType)) {
2785             return false;
2786         }
2787 
2788         Field const *field = GetCachedField();
2789 
2790         if (field == nullptr) {
2791             SET_STATUS_FOR_MSG(CannotResolveFieldId, OK);
2792             return false;
2793         }
2794         Type fieldType = GetFieldType();
2795         if (!fieldType.IsConsistent()) {
2796             return false;
2797         }
2798 
2799         Type vsType = GetRegType(acc);
2800 
2801         CheckResult const &result = check(fieldType.ToTypeId(), vsType.ToTypeId());
2802         if (result.status != VerificationStatus::OK) {
2803             LOG_VERIFIER_DEBUG_STORE_FIELD(GetFieldName(field), ToString(fieldType), ToString(vsType));
2804             status_ = result.status;
2805             if (result.IsError()) {
2806                 return false;
2807             }
2808         }
2809 
2810         MoveToNextInst<FORMAT>();
2811         return true;
2812     }
2813 
2814     template <BytecodeInstructionSafe::Format FORMAT>
ProcessStobjObjByName(int vd)2815     bool ProcessStobjObjByName(int vd)
2816     {
2817         if (!CheckFieldAccessByName<false>(vd, refType_)) {
2818             return false;
2819         }
2820 
2821         Field const *field = GetCachedField();
2822 
2823         if (field == nullptr) {
2824             SET_STATUS_FOR_MSG(CannotResolveFieldId, OK);
2825             return false;
2826         }
2827 
2828         Type fieldType = GetFieldType();
2829         if (!fieldType.IsConsistent()) {
2830             return false;
2831         }
2832 
2833         if (!CheckRegType(acc, refType_)) {
2834             SET_STATUS_FOR_MSG(BadRegisterType, WARNING);
2835             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
2836             return false;
2837         }
2838 
2839         Type vsType = GetRegType(acc);
2840         if (!IsSubtype(vsType, fieldType, GetTypeSystem())) {
2841             SHOW_MSG(BadAccumulatorType)
2842             LOG_VERIFIER_BAD_ACCUMULATOR_TYPE(ToString(vsType), ToString(fieldType));
2843             END_SHOW_MSG();
2844             SET_STATUS_FOR_MSG(BadAccumulatorType, WARNING);
2845             return false;
2846         }
2847 
2848         MoveToNextInst<FORMAT>();
2849         return true;
2850     }
2851 
2852     template <BytecodeInstructionSafe::Format FORMAT>
HandleEtsStobjName()2853     bool HandleEtsStobjName()
2854     {
2855         LOG_INST();
2856         DBGBRK();
2857         uint16_t vd = inst_.GetVReg<FORMAT>();
2858         Sync();
2859 
2860         return ProcessStoreFieldByName<FORMAT>(vd, bits32_, CheckStobj);
2861     }
2862 
2863     template <BytecodeInstructionSafe::Format FORMAT>
HandleEtsStobjNameWide()2864     bool HandleEtsStobjNameWide()
2865     {
2866         LOG_INST();
2867         DBGBRK();
2868         uint16_t vd = inst_.GetVReg<FORMAT>();
2869         Sync();
2870 
2871         return ProcessStoreFieldByName<FORMAT>(vd, bits64_, CheckStobjWide);
2872     }
2873 
2874     template <BytecodeInstructionSafe::Format FORMAT>
HandleEtsStobjNameObj()2875     bool HandleEtsStobjNameObj()
2876     {
2877         LOG_INST();
2878         DBGBRK();
2879         uint16_t vd = inst_.GetVReg<FORMAT>();
2880         Sync();
2881         return ProcessStobjObjByName<FORMAT>(vd);
2882     }
2883 
2884     template <BytecodeInstructionSafe::Format FORMAT>
HandleEtsLdundefined()2885     bool HandleEtsLdundefined()
2886     {
2887         LOG_INST();
2888         DBGBRK();
2889         Sync();
2890         SetAcc(objectType_);
2891         MoveToNextInst<FORMAT>();
2892         return true;
2893     }
2894 
2895     template <BytecodeInstructionSafe::Format FORMAT>
HandleEtsMovundefined()2896     bool HandleEtsMovundefined()
2897     {
2898         LOG_INST();
2899         DBGBRK();
2900         uint16_t vd = inst_.GetVReg<FORMAT>();
2901         Sync();
2902         SetReg(vd, objectType_);
2903         MoveToNextInst<FORMAT>();
2904         return true;
2905     }
2906 
2907     template <BytecodeInstructionSafe::Format FORMAT>
HandleEtsIsundefined()2908     bool HandleEtsIsundefined()
2909     {
2910         LOG_INST();
2911         DBGBRK();
2912         Sync();
2913 
2914         if (!CheckRegType(acc, refType_)) {
2915             SET_STATUS_FOR_MSG(BadRegisterType, WARNING);
2916             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
2917             return false;
2918         }
2919         SetAcc(i32_);
2920 
2921         MoveToNextInst<FORMAT>();
2922         return true;
2923     }
2924 
2925     template <BytecodeInstructionSafe::Format FORMAT>
HandleReturnWide()2926     bool HandleReturnWide()
2927     {
2928         LOG_INST();
2929         DBGBRK();
2930         Sync();
2931 
2932         if (!CheckType(ReturnType(), bits64_)) {
2933             LOG_VERIFIER_BAD_RETURN_INSTRUCTION_TYPE(".64", ToString(ReturnType()), ToString(bits64_));
2934             status_ = VerificationStatus::ERROR;
2935             return false;
2936         }
2937 
2938         if (!IsRegDefined(acc)) {
2939             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
2940             return false;
2941         }
2942 
2943         if (!CheckType(GetAccType(), bits64_)) {
2944             LOG_VERIFIER_BAD_ACCUMULATOR_RETURN_VALUE_TYPE(ToString(GetAccType()));
2945             status_ = VerificationStatus::ERROR;
2946         }
2947         return false;
2948     }
2949 
2950     template <BytecodeInstructionSafe::Format FORMAT>
HandleReturnObj()2951     bool HandleReturnObj()
2952     {
2953         LOG_INST();
2954         DBGBRK();
2955         Sync();
2956 
2957         if (!CheckType(ReturnType(), refType_)) {
2958             LOG_VERIFIER_BAD_RETURN_INSTRUCTION_TYPE(".obj", ToString(ReturnType()), ToString(refType_));
2959             status_ = VerificationStatus::ERROR;
2960             return false;
2961         }
2962 
2963         if (!IsRegDefined(acc)) {
2964             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
2965             return false;
2966         }
2967 
2968         auto accType = GetAccType();
2969         if (!CheckType(accType, ReturnType())) {
2970             LOG_VERIFIER_BAD_ACCUMULATOR_RETURN_VALUE_TYPE_WITH_SUBTYPE(ToString(accType), ToString(ReturnType()));
2971             // NOTE(vdyadov) : after solving issues with set of types in LUB, uncomment next line
2972             status_ = VerificationStatus::WARNING;
2973         }
2974 
2975         return false;
2976     }
2977 
2978     template <BytecodeInstructionSafe::Format FORMAT>
HandleReturnVoid()2979     bool HandleReturnVoid()
2980     {
2981         LOG_INST();
2982         DBGBRK();
2983         // NOTE(vdyadov): think of introducing void as of separate type, like null
2984         Sync();
2985 
2986         if (ReturnType() != Type::Top()) {
2987             LOG_VERIFIER_BAD_RETURN_VOID_INSTRUCTION_TYPE(ToString(ReturnType()));
2988             status_ = VerificationStatus::ERROR;
2989         }
2990 
2991         return false;
2992     }
2993 
2994     template <BytecodeInstructionSafe::Format FORMAT>
HandleCheckcast()2995     bool HandleCheckcast()
2996     {
2997         LOG_INST();
2998         DBGBRK();
2999         Sync();
3000         Type cachedType = GetCachedType();
3001         if (!cachedType.IsConsistent()) {
3002             return false;
3003         }
3004         LOG_VERIFIER_DEBUG_TYPE(ToString(cachedType));
3005         if (!IsSubtype(cachedType, objectType_, GetTypeSystem()) &&
3006             !IsSubtype(cachedType, arrayType_, GetTypeSystem())) {
3007             LOG_VERIFIER_CHECK_CAST_TO_NON_OBJECT_TYPE(ToString(cachedType));
3008             SET_STATUS_FOR_MSG(CheckCastToNonObjectType, WARNING);
3009             return false;
3010         }
3011         if (!IsRegDefined(acc)) {
3012             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
3013             return false;
3014         }
3015         auto accType = GetAccType();
3016         // NOTE(vdyadov): remove this check after #2365
3017         auto res = !IsSubtype(accType, refType_, GetTypeSystem()) && !IsSubtype(accType, arrayType_, GetTypeSystem());
3018         if (res) {
3019             LOG_VERIFIER_NON_OBJECT_ACCUMULATOR_TYPE();
3020             SET_STATUS_FOR_MSG(NonObjectAccumulatorType, WARNING);
3021             return false;
3022         }
3023 
3024         if (IsSubtype(accType, nullRefType_, GetTypeSystem())) {
3025             LOG_VERIFIER_ACCUMULATOR_ALWAYS_NULL();
3026             SET_STATUS_FOR_MSG(AccumulatorAlwaysNull, OK);
3027             // Don't set types for "others of the same origin" when origin is null: n = null, a = n, b = n, a =
3028             // (NewType)x
3029             SetAcc(cachedType);
3030             MoveToNextInst<FORMAT>();
3031             return true;
3032         }
3033 
3034         if (IsSubtype(accType, cachedType, GetTypeSystem())) {
3035             LOG_VERIFIER_REDUNDANT_CHECK_CAST(ToString(accType), ToString(cachedType));
3036             SET_STATUS_FOR_MSG(RedundantCheckCast, OK);
3037             // Do not update register type to parent type as we loose details and can get errors on further flow
3038             MoveToNextInst<FORMAT>();
3039             return true;
3040         }
3041 
3042         if (IsSubtype(cachedType, arrayType_, GetTypeSystem())) {
3043             auto eltType = cachedType.GetArrayElementType(GetTypeSystem());
3044             res = !IsSubtype(accType, arrayType_, GetTypeSystem()) && !IsSubtype(cachedType, accType, GetTypeSystem());
3045             if (res) {
3046                 LOG_VERIFIER_IMPOSSIBLE_CHECK_CAST(ToString(accType));
3047                 status_ = VerificationStatus::WARNING;
3048             } else if (IsSubtype(accType, arrayType_, GetTypeSystem())) {
3049                 auto accEltType = accType.GetArrayElementType(GetTypeSystem());
3050                 if (accEltType.IsConsistent() && !IsSubtype(accEltType, eltType, GetTypeSystem()) &&
3051                     !IsSubtype(eltType, accEltType, GetTypeSystem())) {
3052                     LOG_VERIFIER_IMPOSSIBLE_ARRAY_CHECK_CAST(ToString(accEltType));
3053                     SET_STATUS_FOR_MSG(ImpossibleArrayCheckCast, OK);
3054                 }
3055             }
3056         } else if (TpIntersection(cachedType, accType, GetTypeSystem()) == bot_) {
3057             LOG_VERIFIER_INCOMPATIBLE_ACCUMULATOR_TYPE(ToString(accType));
3058             SET_STATUS_FOR_MSG(IncompatibleAccumulatorType, OK);
3059         }
3060 
3061         if (status_ == VerificationStatus::ERROR) {
3062             SetAcc(top_);
3063             return false;
3064         }
3065 
3066         SetAccAndOthersOfSameOrigin(TpIntersection(cachedType, accType, GetTypeSystem()));
3067 
3068         MoveToNextInst<FORMAT>();
3069         return true;
3070     }
3071 
3072     template <BytecodeInstructionSafe::Format FORMAT>
HandleIsinstance()3073     bool HandleIsinstance()
3074     {
3075         LOG_INST();
3076         DBGBRK();
3077         Sync();
3078         Type cachedType = GetCachedType();
3079         if (!cachedType.IsConsistent()) {
3080             return false;
3081         }
3082         LOG_VERIFIER_DEBUG_TYPE(ToString(cachedType));
3083         if (!IsSubtype(cachedType, objectType_, GetTypeSystem()) &&
3084             !IsSubtype(cachedType, arrayType_, GetTypeSystem())) {
3085             // !(type <= Types().ArrayType()) is redundant, because all arrays
3086             // are subtypes of either panda.Object <: ObjectType or java.lang.Object <: ObjectType
3087             // depending on selected language context
3088             LOG_VERIFIER_BAD_IS_INSTANCE_INSTRUCTION(ToString(cachedType));
3089             SET_STATUS_FOR_MSG(BadIsInstanceInstruction, WARNING);
3090             return false;
3091         }
3092         if (!IsRegDefined(acc)) {
3093             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
3094             return false;
3095         }
3096 
3097         auto *plugin = job_->JobPlugin();
3098         auto const *jobMethod = job_->JobMethod();
3099         auto result = CheckResult::ok;
3100         if (cachedType.IsClass()) {
3101             result = plugin->CheckClassAccessViolation(cachedType.GetClass(), jobMethod, GetTypeSystem());
3102         }
3103         if (!result.IsOk()) {
3104             LogInnerMessage(CheckResult::protected_class);
3105             LOG_VERIFIER_DEBUG_CALL_FROM_TO(job_->JobMethod()->GetClass()->GetName(), ToString(cachedType));
3106             status_ = VerificationStatus::ERROR;
3107             return false;
3108         }
3109 
3110         auto accType = GetAccType();
3111         // NOTE(vdyadov): remove this check after #2365
3112         auto res = !IsSubtype(accType, refType_, GetTypeSystem()) && !IsSubtype(accType, arrayType_, GetTypeSystem());
3113         if (res) {
3114             LOG_VERIFIER_NON_OBJECT_ACCUMULATOR_TYPE();
3115             status_ = VerificationStatus::ERROR;
3116             return false;
3117         }
3118 
3119         if (IsSubtype(accType, nullRefType_, GetTypeSystem())) {
3120             LOG_VERIFIER_ACCUMULATOR_ALWAYS_NULL();
3121             SET_STATUS_FOR_MSG(AccumulatorAlwaysNull, OK);
3122         } else if (IsSubtype(accType, cachedType, GetTypeSystem())) {
3123             LOG_VERIFIER_REDUNDANT_IS_INSTANCE(ToString(accType), ToString(cachedType));
3124             SET_STATUS_FOR_MSG(RedundantIsInstance, OK);
3125         } else if (IsSubtype(cachedType, arrayType_, GetTypeSystem())) {
3126             auto eltType = cachedType.GetArrayElementType(GetTypeSystem());
3127             auto accEltType = accType.GetArrayElementType(GetTypeSystem());
3128             bool accEltTypeIsEmpty = accEltType.IsConsistent();
3129             res = !IsSubtype(accEltType, eltType, GetTypeSystem()) && !IsSubtype(eltType, accEltType, GetTypeSystem());
3130             if (res) {
3131                 if (accEltTypeIsEmpty) {
3132                     LOG_VERIFIER_IMPOSSIBLE_IS_INSTANCE(ToString(accType));
3133                     SET_STATUS_FOR_MSG(ImpossibleIsInstance, OK);
3134                 } else {
3135                     LOG_VERIFIER_IMPOSSIBLE_ARRAY_IS_INSTANCE(ToString(accEltType));
3136                     SET_STATUS_FOR_MSG(ImpossibleArrayIsInstance, OK);
3137                 }
3138             }
3139         } else if (TpIntersection(cachedType, accType, GetTypeSystem()) == bot_) {
3140             LOG_VERIFIER_IMPOSSIBLE_IS_INSTANCE(ToString(accType));
3141             SET_STATUS_FOR_MSG(ImpossibleIsInstance, OK);
3142         }  // else {
3143         // NOTE(vdyadov): here we may increase precision to concrete values in some cases
3144         SetAcc(i32_);
3145         MoveToNextInst<FORMAT>();
3146         return true;
3147     }
3148 
3149     template <typename NameGetter>
3150     bool CheckMethodArgs(NameGetter nameGetter, Method const *method, Span<int> regs, Type constructedType = Type {})
3151     {
3152         bool checkingConstructor = !constructedType.IsNone();
3153         auto const *sig = GetTypeSystem()->GetMethodSignature(method);
3154         auto const &formalArgs = sig->args;
3155         bool result = true;
3156         if (formalArgs.empty()) {
3157             return true;
3158         }
3159 
3160         size_t regsNeeded = checkingConstructor ? formalArgs.size() - 1 : formalArgs.size();
3161         if (regs.size() < regsNeeded) {
3162             SHOW_MSG(BadCallTooFewParameters)
3163             LOG_VERIFIER_BAD_CALL_TOO_FEW_PARAMETERS(nameGetter());
3164             END_SHOW_MSG();
3165             SET_STATUS_FOR_MSG(BadCallTooFewParameters, WARNING);
3166             return false;
3167         }
3168         auto sigIter = formalArgs.cbegin();
3169         auto regsIter = regs.cbegin();
3170         for (size_t argnum = 0; argnum < formalArgs.size(); argnum++) {
3171             auto regNum = (checkingConstructor && sigIter == formalArgs.cbegin()) ? invalidReg : *(regsIter++);
3172             auto formalType = *(sigIter++);
3173             auto const normType = GetTypeSystem()->NormalizedTypeOf(formalType);
3174 
3175             if (regNum != invalidReg && !IsRegDefined(regNum)) {
3176                 LOG_VERIFIER_BAD_CALL_UNDEFINED_REGISTER(nameGetter(), regNum);
3177                 SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
3178                 result = false;
3179                 break;
3180             }
3181             Type actualType = regNum == invalidReg ? constructedType : GetRegType(regNum);
3182             Type normActualType = GetTypeSystem()->NormalizedTypeOf(actualType);
3183             // arg: NormalizedTypeOf(actual_type) <= norm_type
3184             // check of physical compatibility
3185             bool incompatibleTypes = false;
3186             auto actualIsRef = IsSubtype(actualType, refType_, GetTypeSystem());
3187             if (regNum != invalidReg && IsSubtype(formalType, refType_, GetTypeSystem()) && formalType != Type::Bot() &&
3188                 actualIsRef) {
3189                 if (IsSubtype(actualType, formalType, GetTypeSystem())) {
3190                     continue;
3191                 }
3192                 if (!config->opts.debug.allow.wrongSubclassingInMethodArgs) {
3193                     incompatibleTypes = true;
3194                 }
3195             } else if (formalType != Type::Bot() && formalType != Type::Top() &&
3196                        !IsSubtype(normActualType, normType, GetTypeSystem())) {
3197                 incompatibleTypes = true;
3198             }
3199             if (incompatibleTypes) {
3200                 PandaString regOrParam = regNum == invalidReg ? "Actual parameter" : RegisterName(regNum, true);
3201                 SHOW_MSG(BadCallIncompatibleParameter)
3202                 LOG_VERIFIER_BAD_CALL_INCOMPATIBLE_PARAMETER(nameGetter(), regOrParam, ToString(normActualType),
3203                                                              ToString(normType));
3204                 END_SHOW_MSG();
3205                 SET_STATUS_FOR_MSG(BadCallIncompatibleParameter, WARNING);
3206                 return result = false;
3207             }
3208             if (formalType == Type::Bot()) {
3209                 if (actualType == Type::Bot()) {
3210                     LOG_VERIFIER_CALL_FORMAL_ACTUAL_BOTH_BOT_OR_TOP("Bot");
3211                     break;
3212                 }
3213 
3214                 SHOW_MSG(BadCallFormalIsBot)
3215                 LOG_VERIFIER_BAD_CALL_FORMAL_IS_BOT(nameGetter(), ToString(actualType));
3216                 END_SHOW_MSG();
3217                 SET_STATUS_FOR_MSG(BadCallFormalIsBot, WARNING);
3218                 return result = false;
3219             }
3220             if (formalType == Type::Top()) {
3221                 if (actualType == Type::Top()) {
3222                     LOG_VERIFIER_CALL_FORMAL_ACTUAL_BOTH_BOT_OR_TOP("Top");
3223                     break;
3224                 }
3225                 SHOW_MSG(CallFormalTop)
3226                 LOG_VERIFIER_CALL_FORMAL_TOP();
3227                 END_SHOW_MSG();
3228                 break;
3229             }
3230             if (IsSubtype(formalType, primitive_, GetTypeSystem())) {
3231                 // check implicit conversion of primitive types
3232                 TypeId formalId = formalType.ToTypeId();
3233                 CheckResult checkResult = CheckResult::ok;
3234 
3235                 if (!IsSubtype(actualType, primitive_, GetTypeSystem())) {
3236                     result = false;
3237                     break;
3238                 }
3239                 // !!!!!! NOTE: need to check all possible TypeId-s against formal_id
3240                 TypeId actualId = actualType.ToTypeId();
3241                 if (actualId != TypeId::INVALID) {
3242                     checkResult = panda::verifier::CheckMethodArgs(formalId, actualId);
3243                 } else {
3244                     // special case, where type after contexts LUB operation is inexact one, like
3245                     // integral32_Type()
3246                     if ((IsSubtype(formalType, integral32_, GetTypeSystem()) &&
3247                          IsSubtype(actualType, integral32_, GetTypeSystem())) ||
3248                         (IsSubtype(formalType, integral64_, GetTypeSystem()) &&
3249                          IsSubtype(actualType, integral64_, GetTypeSystem())) ||
3250                         (IsSubtype(formalType, float64_, GetTypeSystem()) &&
3251                          IsSubtype(actualType, float64_, GetTypeSystem()))) {
3252                         SHOW_MSG(CallFormalActualDifferent)
3253                         LOG_VERIFIER_CALL_FORMAL_ACTUAL_DIFFERENT(ToString(formalType), ToString(actualType));
3254                         END_SHOW_MSG();
3255                     } else {
3256                         checkResult = panda::verifier::CheckMethodArgs(formalId, actualId);
3257                     }
3258                 }
3259                 if (!checkResult.IsOk()) {
3260                     SHOW_MSG(DebugCallParameterTypes)
3261                     LogInnerMessage(checkResult);
3262                     LOG_VERIFIER_DEBUG_CALL_PARAMETER_TYPES(
3263                         nameGetter(),
3264                         (regNum == invalidReg ? ""
3265                                               : PandaString {"Actual parameter in "} + RegisterName(regNum) + ". "),
3266                         ToString(actualType), ToString(formalType));
3267                     END_SHOW_MSG();
3268                     status_ = checkResult.status;
3269                     if (status_ == VerificationStatus::ERROR) {
3270                         result = false;
3271                         break;
3272                     }
3273                 }
3274                 continue;
3275             }
3276             if (!CheckType(actualType, formalType)) {
3277                 if (regNum == invalidReg) {
3278                     SHOW_MSG(BadCallWrongParameter)
3279                     LOG_VERIFIER_BAD_CALL_WRONG_PARAMETER(nameGetter(), ToString(actualType), ToString(formalType));
3280                     END_SHOW_MSG();
3281                     SET_STATUS_FOR_MSG(BadCallWrongParameter, WARNING);
3282                 } else {
3283                     SHOW_MSG(BadCallWrongRegister)
3284                     LOG_VERIFIER_BAD_CALL_WRONG_REGISTER(nameGetter(), regNum);
3285                     END_SHOW_MSG();
3286                     SET_STATUS_FOR_MSG(BadCallWrongRegister, WARNING);
3287                 }
3288                 if (!config->opts.debug.allow.wrongSubclassingInMethodArgs) {
3289                     status_ = VerificationStatus::ERROR;
3290                     result = false;
3291                     break;
3292                 }
3293             }
3294         }
3295         return result;
3296     }
3297 
3298     template <BytecodeInstructionSafe::Format FORMAT>
CheckCall(Method const * method,Span<int> regs)3299     bool CheckCall(Method const *method, Span<int> regs)
3300     {
3301         if (method == nullptr) {
3302             SET_STATUS_FOR_MSG(CannotResolveMethodId, OK);
3303             return false;
3304         }
3305 
3306         auto *plugin = job_->JobPlugin();
3307         auto const *jobMethod = job_->JobMethod();
3308         auto result = plugin->CheckMethodAccessViolation(method, jobMethod, GetTypeSystem());
3309         if (!result.IsOk()) {
3310             const auto &verifOpts = config->opts;
3311             if (verifOpts.debug.allow.methodAccessViolation && result.IsError()) {
3312                 result.status = VerificationStatus::WARNING;
3313             }
3314             LogInnerMessage(result);
3315             LOG_VERIFIER_DEBUG_CALL_FROM_TO(job_->JobMethod()->GetFullName(), method->GetFullName());
3316             status_ = result.status;
3317             if (status_ == VerificationStatus::ERROR) {
3318                 return false;
3319             }
3320         }
3321 
3322         const auto *methodSig = GetTypeSystem()->GetMethodSignature(method);
3323         auto methodNameGetter = [method]() { return method->GetFullName(); };
3324         Type resultType = methodSig->result;
3325 
3326         if (!debugCtx->SkipVerificationOfCall(method->GetUniqId()) &&
3327             !CheckMethodArgs(methodNameGetter, method, regs)) {
3328             return false;
3329         }
3330         SetAcc(resultType);
3331         MoveToNextInst<FORMAT>();
3332         return true;
3333     }
3334 
3335     template <BytecodeInstructionSafe::Format FORMAT>
HandleCallShort()3336     bool HandleCallShort()
3337     {
3338         LOG_INST();
3339         DBGBRK();
3340         uint16_t vs1 = inst_.GetVReg<FORMAT, 0x00>();
3341         uint16_t vs2 = inst_.GetVReg<FORMAT, 0x01>();
3342         Method const *method = GetCachedMethod();
3343         if (method != nullptr) {
3344             LOG_VERIFIER_DEBUG_METHOD(method->GetFullName());
3345         }
3346 
3347         if (method != nullptr && method->IsAbstract()) {
3348             LOG_VERIFIER_BAD_CALL_STATICALLY_ABSTRACT_METHOD(method->GetFullName());
3349             SET_STATUS_FOR_MSG(BadCallStaticallyAbstractMethod, WARNING);
3350             return false;
3351         }
3352 
3353         Sync();
3354         std::array<int, 2UL> regs {vs1, vs2};
3355         return CheckCall<FORMAT>(method, Span {regs});
3356     }
3357 
3358     template <BytecodeInstructionSafe::Format FORMAT>
HandleCallAccShort()3359     bool HandleCallAccShort()
3360     {
3361         LOG_INST();
3362         DBGBRK();
3363         uint16_t vs1 = inst_.GetVReg<FORMAT, 0x00>();
3364         auto accPos = static_cast<unsigned>(inst_.GetImm<FORMAT, 0x00>());
3365         static constexpr auto numArgs = 2;
3366         if (accPos >= numArgs) {
3367             LOG_VERIFIER_ACCUMULATOR_POSITION_IS_OUT_OF_RANGE();
3368             SET_STATUS_FOR_MSG(AccumulatorPositionIsOutOfRange, WARNING);
3369             return status_ != VerificationStatus::ERROR;
3370         }
3371         Method const *method = GetCachedMethod();
3372         if (method != nullptr) {
3373             LOG_VERIFIER_DEBUG_METHOD(method->GetFullName());
3374         }
3375 
3376         if (method != nullptr && method->IsAbstract()) {
3377             LOG_VERIFIER_BAD_CALL_STATICALLY_ABSTRACT_METHOD(method->GetFullName());
3378             SET_STATUS_FOR_MSG(BadCallStaticallyAbstractMethod, WARNING);
3379             return false;
3380         }
3381 
3382         Sync();
3383         std::array<int, numArgs> regs {};
3384         if (accPos == 0) {
3385             regs = {acc, vs1};
3386         } else {
3387             regs = {vs1, acc};
3388         }
3389         return CheckCall<FORMAT>(method, Span {regs});
3390     }
3391 
3392     template <BytecodeInstructionSafe::Format FORMAT>
3393     bool HandleCalliDynShort();
3394 
3395     template <BytecodeInstructionSafe::Format FORMAT>
3396     bool HandleCalliDyn();
3397 
3398     template <BytecodeInstructionSafe::Format FORMAT>
3399     bool HandleCalliDynRange();
3400 
3401     template <BytecodeInstructionSafe::Format FORMAT>
HandleCall()3402     bool HandleCall()
3403     {
3404         LOG_INST();
3405         DBGBRK();
3406         uint16_t vs1 = inst_.GetVReg<FORMAT, 0x00>();
3407         uint16_t vs2 = inst_.GetVReg<FORMAT, 0x01>();
3408         uint16_t vs3 = inst_.GetVReg<FORMAT, 0x02>();
3409         uint16_t vs4 = inst_.GetVReg<FORMAT, 0x03>();
3410         Method const *method = GetCachedMethod();
3411         if (method != nullptr) {
3412             LOG_VERIFIER_DEBUG_METHOD(method->GetFullName());
3413         }
3414 
3415         if (method != nullptr && method->IsAbstract()) {
3416             LOG_VERIFIER_BAD_CALL_STATICALLY_ABSTRACT_METHOD(method->GetFullName());
3417             SET_STATUS_FOR_MSG(BadCallStaticallyAbstractMethod, WARNING);
3418             return false;
3419         }
3420 
3421         Sync();
3422         std::array<int, 4UL> regs {vs1, vs2, vs3, vs4};
3423         return CheckCall<FORMAT>(method, Span {regs});
3424     }
3425 
3426     template <BytecodeInstructionSafe::Format FORMAT>
HandleCallAcc()3427     bool HandleCallAcc()
3428     {
3429         LOG_INST();
3430         DBGBRK();
3431         auto accPos = static_cast<unsigned>(inst_.GetImm<FORMAT, 0x0>());
3432         static constexpr auto numArgs = 4;
3433         if (accPos >= numArgs) {
3434             LOG_VERIFIER_ACCUMULATOR_POSITION_IS_OUT_OF_RANGE();
3435             SET_STATUS_FOR_MSG(AccumulatorPositionIsOutOfRange, WARNING);
3436             return status_ != VerificationStatus::ERROR;
3437         }
3438         Method const *method = GetCachedMethod();
3439         if (method != nullptr) {
3440             LOG_VERIFIER_DEBUG_METHOD(method->GetFullName());
3441         }
3442 
3443         if (method != nullptr && method->IsAbstract()) {
3444             LOG_VERIFIER_BAD_CALL_STATICALLY_ABSTRACT_METHOD(method->GetFullName());
3445             SET_STATUS_FOR_MSG(BadCallStaticallyAbstractMethod, WARNING);
3446             return false;
3447         }
3448 
3449         Sync();
3450         std::array<int, numArgs> regs {};
3451         auto regIdx = 0;
3452         for (unsigned i = 0; i < numArgs; ++i) {
3453             if (i == accPos) {
3454                 regs[i] = acc;
3455             } else {
3456                 regs[i] = static_cast<int>(inst_.GetVReg(regIdx++));
3457             }
3458         }
3459         return CheckCall<FORMAT>(method, Span {regs});
3460     }
3461 
3462     template <BytecodeInstructionSafe::Format FORMAT>
HandleCallRange()3463     bool HandleCallRange()
3464     {
3465         LOG_INST();
3466         DBGBRK();
3467         uint16_t vs = inst_.GetVReg<FORMAT, 0x00>();
3468         Method const *method = GetCachedMethod();
3469         if (method != nullptr) {
3470             LOG_VERIFIER_DEBUG_METHOD(method->GetFullName());
3471         }
3472 
3473         if (method != nullptr && method->IsAbstract()) {
3474             LOG_VERIFIER_BAD_CALL_STATICALLY_ABSTRACT_METHOD(method->GetFullName());
3475             SET_STATUS_FOR_MSG(BadCallStaticallyAbstractMethod, WARNING);
3476             return false;
3477         }
3478 
3479         Sync();
3480         std::vector<int> regs;
3481         for (auto regIdx = vs; ExecCtx().CurrentRegContext().IsRegDefined(regIdx); regIdx++) {
3482             regs.push_back(regIdx);
3483         }
3484         return CheckCall<FORMAT>(method, Span {regs});
3485     }
3486 
3487     template <BytecodeInstructionSafe::Format FORMAT>
HandleCallVirtShort()3488     bool HandleCallVirtShort()
3489     {
3490         LOG_INST();
3491         DBGBRK();
3492         uint16_t vs1 = inst_.GetVReg<FORMAT, 0x00>();
3493         uint16_t vs2 = inst_.GetVReg<FORMAT, 0x01>();
3494         Method const *method = GetCachedMethod();
3495         if (method != nullptr) {
3496             LOG_VERIFIER_DEBUG_METHOD(method->GetFullName());
3497         }
3498         if (method != nullptr && method->IsStatic()) {
3499             LOG_VERIFIER_BAD_CALL_STATIC_METHOD_AS_VIRTUAL(method->GetFullName());
3500             SET_STATUS_FOR_MSG(BadCallStaticMethodAsVirtual, WARNING);
3501             return false;
3502         }
3503 
3504         Sync();
3505         std::array<int, 2UL> regs {vs1, vs2};
3506         return CheckCall<FORMAT>(method, Span {regs});
3507     }
3508 
3509     template <BytecodeInstructionSafe::Format FORMAT>
HandleCallVirtAccShort()3510     bool HandleCallVirtAccShort()
3511     {
3512         LOG_INST();
3513         DBGBRK();
3514         uint16_t vs1 = inst_.GetVReg<FORMAT, 0x00>();
3515         auto accPos = static_cast<unsigned>(inst_.GetImm<FORMAT, 0x00>());
3516         static constexpr auto numArgs = 2;
3517         Method const *method = GetCachedMethod();
3518         if (method != nullptr) {
3519             LOG_VERIFIER_DEBUG_METHOD(method->GetFullName());
3520         }
3521         if (method != nullptr && method->IsStatic()) {
3522             LOG_VERIFIER_BAD_CALL_STATIC_METHOD_AS_VIRTUAL(method->GetFullName());
3523             SET_STATUS_FOR_MSG(BadCallStaticMethodAsVirtual, WARNING);
3524             return false;
3525         }
3526         Sync();
3527         std::array<int, numArgs> regs {};
3528         if (accPos == 0) {
3529             regs = {acc, vs1};
3530         } else {
3531             regs = {vs1, acc};
3532         }
3533         return CheckCall<FORMAT>(method, Span {regs});
3534     }
3535 
3536     template <BytecodeInstructionSafe::Format FORMAT>
HandleCallVirt()3537     bool HandleCallVirt()
3538     {
3539         LOG_INST();
3540         DBGBRK();
3541         uint16_t vs1 = inst_.GetVReg<FORMAT, 0x00>();
3542         uint16_t vs2 = inst_.GetVReg<FORMAT, 0x01>();
3543         uint16_t vs3 = inst_.GetVReg<FORMAT, 0x02>();
3544         uint16_t vs4 = inst_.GetVReg<FORMAT, 0x03>();
3545         Method const *method = GetCachedMethod();
3546         if (method != nullptr) {
3547             LOG_VERIFIER_DEBUG_METHOD(method->GetFullName());
3548         }
3549         if (method != nullptr && method->IsStatic()) {
3550             LOG_VERIFIER_BAD_CALL_STATIC_METHOD_AS_VIRTUAL(method->GetFullName());
3551             SET_STATUS_FOR_MSG(BadCallStaticMethodAsVirtual, WARNING);
3552             return false;
3553         }
3554 
3555         Sync();
3556         std::array<int, 4UL> regs {vs1, vs2, vs3, vs4};
3557         return CheckCall<FORMAT>(method, Span {regs});
3558     }
3559 
3560     template <BytecodeInstructionSafe::Format FORMAT>
HandleCallVirtAcc()3561     bool HandleCallVirtAcc()
3562     {
3563         LOG_INST();
3564         DBGBRK();
3565         auto accPos = static_cast<unsigned>(inst_.GetImm<FORMAT, 0x0>());
3566         static constexpr auto numArgs = 4;
3567         Method const *method = GetCachedMethod();
3568         if (method != nullptr) {
3569             LOG_VERIFIER_DEBUG_METHOD(method->GetFullName());
3570         }
3571         if (method != nullptr && method->IsStatic()) {
3572             LOG_VERIFIER_BAD_CALL_STATIC_METHOD_AS_VIRTUAL(method->GetFullName());
3573             SET_STATUS_FOR_MSG(BadCallStaticMethodAsVirtual, WARNING);
3574             return false;
3575         }
3576         Sync();
3577         std::array<int, numArgs> regs {};
3578         auto regIdx = 0;
3579         for (unsigned i = 0; i < numArgs; ++i) {
3580             if (i == accPos) {
3581                 regs[i] = acc;
3582             } else {
3583                 regs[i] = static_cast<int>(inst_.GetVReg(regIdx++));
3584             }
3585         }
3586         return CheckCall<FORMAT>(method, Span {regs});
3587     }
3588 
3589     template <BytecodeInstructionSafe::Format FORMAT>
HandleCallVirtRange()3590     bool HandleCallVirtRange()
3591     {
3592         LOG_INST();
3593         DBGBRK();
3594         uint16_t vs = inst_.GetVReg<FORMAT, 0x00>();
3595 
3596         Method const *method = GetCachedMethod();
3597         if (method != nullptr) {
3598             LOG_VERIFIER_DEBUG_METHOD(method->GetFullName());
3599         }
3600         if (method != nullptr && method->IsStatic()) {
3601             LOG_VERIFIER_BAD_CALL_STATIC_METHOD_AS_VIRTUAL(method->GetFullName());
3602             SET_STATUS_FOR_MSG(BadCallStaticMethodAsVirtual, WARNING);
3603             return false;
3604         }
3605 
3606         Sync();
3607         std::vector<int> regs;
3608         for (auto regIdx = vs; ExecCtx().CurrentRegContext().IsRegDefined(regIdx); regIdx++) {
3609             regs.push_back(regIdx);
3610         }
3611         return CheckCall<FORMAT>(method, Span {regs});
3612     }
3613 
3614     template <BytecodeInstructionSafe::Format FORMAT>
HandleThrow()3615     bool HandleThrow()
3616     {
3617         LOG_INST();
3618         DBGBRK();
3619         ExecCtx().SetCheckPoint(inst_.GetAddress());
3620         Sync();
3621         uint16_t vs = inst_.GetVReg<FORMAT>();
3622         if (!CheckRegType(vs, GetTypeSystem()->Throwable())) {
3623             SET_STATUS_FOR_MSG(BadRegisterType, WARNING);
3624             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
3625             return false;
3626         }
3627         // possible implementation:
3628         // on stage of building checkpoints:
3629         // - add all catch block starts as checkpoints/entries
3630         // on absint stage:
3631         // - find corresponding catch block/checkpoint/entry
3632         // - add context to checkpoint/entry
3633         // - add entry to entry list
3634         // - stop absint
3635         return false;
3636     }
3637 
3638     template <BytecodeInstructionSafe::Format FORMAT>
HandleMonitorenter()3639     bool HandleMonitorenter()
3640     {
3641         LOG_INST();
3642         DBGBRK();
3643         Sync();
3644         Type accType = GetAccType();
3645         if (accType == nullRefType_) {
3646             // NOTE(vdyadov): redesign next code, after support exception handlers,
3647             //                treat it as always throw NPE
3648             SHOW_MSG(AlwaysNpeAccumulator)
3649             LOG_VERIFIER_ALWAYS_NPE_ACCUMULATOR();
3650             END_SHOW_MSG();
3651             SET_STATUS_FOR_MSG(AlwaysNpeAccumulator, OK);
3652             return false;
3653         }
3654         if (!CheckType(accType, refType_)) {
3655             SET_STATUS_FOR_MSG(BadRegisterType, WARNING);
3656             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
3657             return false;
3658         }
3659         MoveToNextInst<FORMAT>();
3660         return true;
3661     }
3662 
3663     template <BytecodeInstructionSafe::Format FORMAT>
HandleMonitorexit()3664     bool HandleMonitorexit()
3665     {
3666         LOG_INST();
3667         DBGBRK();
3668         Sync();
3669         Type accType = GetAccType();
3670         if (accType == nullRefType_) {
3671             // NOTE(vdyadov): redesign next code, after support exception handlers,
3672             //                treat it as always throw NPE
3673             SHOW_MSG(AlwaysNpeAccumulator)
3674             LOG_VERIFIER_ALWAYS_NPE_ACCUMULATOR();
3675             END_SHOW_MSG();
3676             SET_STATUS_FOR_MSG(AlwaysNpeAccumulator, OK);
3677             return false;
3678         }
3679         if (!CheckType(accType, refType_)) {
3680             SET_STATUS_FOR_MSG(BadRegisterType, WARNING);
3681             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
3682             return false;
3683         }
3684         MoveToNextInst<FORMAT>();
3685         return true;
3686     }
3687 
GetInst()3688     BytecodeInstructionSafe GetInst()
3689     {
3690         return inst_;
3691     }
3692 
3693     template <BytecodeInstructionSafe::Format FORMAT>
HandleCallspecRange()3694     bool HandleCallspecRange()
3695     {
3696         // CallspecRange has the same semantics as CallRange in terms of
3697         // input and output for verification
3698         return HandleCallRange<FORMAT>();
3699     }
3700 
3701     static PandaString RegisterName(int regIdx, bool capitalize = false)
3702     {
3703         if (regIdx == acc) {
3704             return capitalize ? "Accumulator" : "accumulator";
3705         }
3706         return PandaString {capitalize ? "Register v" : "register v"} + NumToStr(regIdx);
3707     }
3708 
3709 private:
GetCachedType()3710     Type GetCachedType() const
3711     {
3712         auto offset = inst_.GetOffset();
3713         if (!job_->IsTypePresentForOffset(offset)) {
3714             SHOW_MSG(CacheMissForClassAtOffset)
3715             LOG_VERIFIER_CACHE_MISS_FOR_CLASS_AT_OFFSET(offset);
3716             END_SHOW_MSG();
3717 
3718             SHOW_MSG(CannotResolveClassId)
3719             LOG_VERIFIER_CANNOT_RESOLVE_CLASS_ID(inst_.GetId().AsFileId().GetOffset());
3720             END_SHOW_MSG();
3721             return Type {};
3722         }
3723         return job_->GetCachedType(offset);
3724     }
3725 
GetCachedMethod()3726     Method const *GetCachedMethod() const
3727     {
3728         auto offset = inst_.GetOffset();
3729         if (!job_->IsMethodPresentForOffset(offset)) {
3730             SHOW_MSG(CacheMissForMethodAtOffset)
3731             LOG_VERIFIER_CACHE_MISS_FOR_METHOD_AT_OFFSET(offset);
3732             END_SHOW_MSG();
3733 
3734             SHOW_MSG(CannotResolveMethodId)
3735             LOG_VERIFIER_CANNOT_RESOLVE_METHOD_ID(inst_.GetId().AsFileId().GetOffset());
3736             END_SHOW_MSG();
3737             return nullptr;
3738         }
3739         return job_->GetCachedMethod(offset);
3740     }
3741 
GetCachedField()3742     Field const *GetCachedField() const
3743     {
3744         auto offset = inst_.GetOffset();
3745         if (!job_->IsFieldPresentForOffset(offset)) {
3746             SHOW_MSG(CacheMissForFieldAtOffset)
3747             LOG_VERIFIER_CACHE_MISS_FOR_FIELD_AT_OFFSET(offset);
3748             END_SHOW_MSG();
3749 
3750             SHOW_MSG(CannotResolveFieldId)
3751             LOG_VERIFIER_CANNOT_RESOLVE_FIELD_ID(inst_.GetId().AsFileId().GetOffset());
3752             END_SHOW_MSG();
3753             return nullptr;
3754         }
3755         return job_->GetCachedField(offset);
3756     }
3757 
3758     template <BytecodeInstructionSafe::Format FORMAT>
MoveToNextInst()3759     void MoveToNextInst()
3760     {
3761         inst_ = inst_.GetNext<FORMAT>();
3762     }
3763 
3764     template <BytecodeInstructionSafe::Format FORMAT>
CheckArrayStore(int v1,int v2,Type expectedEltType)3765     bool CheckArrayStore(int v1, int v2, Type expectedEltType)
3766     {
3767         /*
3768         main rules:
3769         1. instruction should be strict in array element size, so for primitive types type equality is used
3770         2. accumulator may be subtype of array element type (under question)
3771         */
3772         if (!CheckRegType(v2, integral32_)) {
3773             SET_STATUS_FOR_MSG(BadRegisterType, WARNING);
3774             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
3775             return false;
3776         }
3777         if (!CheckRegType(v1, arrayType_)) {
3778             SET_STATUS_FOR_MSG(BadRegisterType, WARNING);
3779             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
3780             return false;
3781         }
3782         if (!IsRegDefined(acc)) {
3783             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
3784             return false;
3785         }
3786         Type regType = GetRegType(v1);
3787         if (regType == nullRefType_) {
3788             // NOTE(vdyadov): redesign next code, after support exception handlers,
3789             //                treat it as always throw NPE
3790             SHOW_MSG(AlwaysNpe)
3791             LOG_VERIFIER_ALWAYS_NPE(v1);
3792             END_SHOW_MSG();
3793             SetAcc(top_);
3794             SET_STATUS_FOR_MSG(AlwaysNpe, OK);
3795             return false;
3796         }
3797 
3798         auto arrEltType = regType.GetArrayElementType(GetTypeSystem());
3799         if (!IsSubtype(arrEltType, expectedEltType, GetTypeSystem())) {
3800             SHOW_MSG(BadArrayElementType2)
3801             LOG_VERIFIER_BAD_ARRAY_ELEMENT_TYPE2(ToString(arrEltType), ToString(expectedEltType));
3802             END_SHOW_MSG();
3803             SET_STATUS_FOR_MSG(BadArrayElementType2, WARNING);
3804             return false;
3805         }
3806 
3807         Type accType = GetAccType();
3808 
3809         // NOTE(dvyadov): think of subtyping here. Can we really write more precise type into array?
3810         // since there is no problems with storage (all refs are of the same size)
3811         // and no problems with information losses, it seems fine at first sight.
3812         bool res = !IsSubtype(accType, arrEltType, GetTypeSystem());
3813         if (res) {
3814             // accumulator is of wrong type
3815             SHOW_MSG(BadAccumulatorType)
3816             LOG_VERIFIER_BAD_ACCUMULATOR_TYPE(ToString(accType), ToString(arrEltType));
3817             END_SHOW_MSG();
3818             SET_STATUS_FOR_MSG(BadAccumulatorType, WARNING);
3819             return false;
3820         }
3821 
3822         MoveToNextInst<FORMAT>();
3823         return true;
3824     }
3825 
3826     template <BytecodeInstructionSafe::Format FORMAT>
CheckArrayStoreExact(int v1,int v2,Type accSupertype,std::initializer_list<Type> const & expectedEltTypes)3827     bool CheckArrayStoreExact(int v1, int v2, Type accSupertype, std::initializer_list<Type> const &expectedEltTypes)
3828     {
3829         if (!CheckRegType(v2, integral32_) || !CheckRegType(v1, arrayType_) || !IsRegDefined(acc)) {
3830             SET_STATUS_FOR_MSG(BadRegisterType, WARNING);
3831             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
3832             return false;
3833         }
3834         Type regType = GetRegType(v1);
3835         if (regType == nullRefType_) {
3836             SHOW_MSG(AlwaysNpe)
3837             LOG_VERIFIER_ALWAYS_NPE(v1);
3838             END_SHOW_MSG();
3839             SetAcc(top_);
3840             SET_STATUS_FOR_MSG(AlwaysNpe, OK);
3841             return false;
3842         }
3843 
3844         auto arrEltType = regType.GetArrayElementType(GetTypeSystem());
3845 
3846         auto find = [&expectedEltTypes](auto type) {
3847             for (Type t : expectedEltTypes) {
3848                 if (type == t) {
3849                     return true;
3850                 }
3851             }
3852             return false;
3853         };
3854 
3855         if (!find(arrEltType)) {
3856             // array elt type is not expected one
3857             PandaVector<Type> expectedTypesVec;
3858             for (auto et : expectedEltTypes) {
3859                 expectedTypesVec.push_back(et);
3860             }
3861             LOG_VERIFIER_BAD_ARRAY_ELEMENT_TYPE3(ToString(arrEltType), ToString(expectedTypesVec));
3862             SET_STATUS_FOR_MSG(BadArrayElementType, WARNING);
3863             return false;
3864         }
3865 
3866         Type accType = GetAccType();
3867         if (!IsSubtype(accType, accSupertype, GetTypeSystem())) {
3868             LOG_VERIFIER_BAD_ACCUMULATOR_TYPE2(ToString(accType));
3869             SET_STATUS_FOR_MSG(BadArrayElementType, WARNING);
3870             return false;
3871         }
3872 
3873         if (!find(accType)) {
3874             // array elt type is not expected one
3875             PandaVector<Type> expectedTypesVec;
3876             for (auto et : expectedEltTypes) {
3877                 expectedTypesVec.push_back(et);
3878             }
3879             LOG_VERIFIER_BAD_ACCUMULATOR_TYPE3(ToString(accType), ToString(expectedTypesVec));
3880             if (status_ != VerificationStatus::ERROR) {
3881                 status_ = VerificationStatus::WARNING;
3882             }
3883         }
3884 
3885         MoveToNextInst<FORMAT>();
3886         return true;
3887     }
3888 
3889     template <BytecodeInstructionSafe::Format FORMAT, bool REG_DST = false>
CheckBinaryOp2(Type accIn,Type regIn,Type out)3890     bool CheckBinaryOp2(Type accIn, Type regIn, Type out)
3891     {
3892         uint16_t vs;
3893         if constexpr (REG_DST) {
3894             vs = inst_.GetVReg<FORMAT, 0x01>();
3895         } else {
3896             vs = inst_.GetVReg<FORMAT>();
3897         }
3898         if (!CheckRegType(acc, accIn)) {
3899             SET_STATUS_FOR_MSG(BadRegisterType, WARNING);
3900             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
3901             return false;
3902         }
3903         if (!CheckRegType(vs, regIn)) {
3904             SET_STATUS_FOR_MSG(BadRegisterType, WARNING);
3905             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
3906             return false;
3907         }
3908         if constexpr (REG_DST) {
3909             SetReg(inst_.GetVReg<FORMAT, 0x00>(), out);
3910         } else {
3911             SetAcc(out);
3912         }
3913         MoveToNextInst<FORMAT>();
3914         return true;
3915     }
3916 
3917     template <BytecodeInstructionSafe::Format FORMAT, bool REG_DST = false>
CheckBinaryOp2(Type accIn,Type regIn)3918     bool CheckBinaryOp2(Type accIn, Type regIn)
3919     {
3920         if (!IsRegDefined(acc)) {
3921             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
3922             return false;
3923         }
3924         return CheckBinaryOp2<FORMAT, REG_DST>(accIn, regIn, GetAccType());
3925     }
3926 
3927     template <BytecodeInstructionSafe::Format FORMAT>
CheckBinaryOpImm(Type in,Type out)3928     bool CheckBinaryOpImm(Type in, Type out)
3929     {
3930         uint16_t vd = inst_.GetVReg<FORMAT, 0x00>();
3931         uint16_t vs = inst_.GetVReg<FORMAT, 0x01>();
3932         if (!CheckRegType(vs, in)) {
3933             SET_STATUS_FOR_MSG(BadRegisterType, WARNING);
3934             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
3935             return false;
3936         }
3937         SetReg(vd, out);
3938         MoveToNextInst<FORMAT>();
3939         return true;
3940     }
3941 
3942     template <BytecodeInstructionSafe::Format FORMAT>
CheckBinaryOp2Imm(Type accIn,Type accOut)3943     bool CheckBinaryOp2Imm(Type accIn, Type accOut)
3944     {
3945         if (!CheckRegType(acc, accIn)) {
3946             SET_STATUS_FOR_MSG(BadRegisterType, WARNING);
3947             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
3948             return false;
3949         }
3950         SetAcc(accOut);
3951         MoveToNextInst<FORMAT>();
3952         return true;
3953     }
3954 
3955     template <BytecodeInstructionSafe::Format FORMAT>
CheckBinaryOp2Imm(Type accIn)3956     bool CheckBinaryOp2Imm(Type accIn)
3957     {
3958         if (!IsRegDefined(acc)) {
3959             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
3960             return false;
3961         }
3962         return CheckBinaryOp2Imm<FORMAT>(accIn, GetAccType());
3963     }
3964 
3965     template <BytecodeInstructionSafe::Format FORMAT>
CheckUnaryOp(Type accIn,Type accOut)3966     bool CheckUnaryOp(Type accIn, Type accOut)
3967     {
3968         if (!CheckRegType(acc, accIn)) {
3969             SET_STATUS_FOR_MSG(BadRegisterType, WARNING);
3970             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
3971             return false;
3972         }
3973         SetAcc(accOut);
3974         MoveToNextInst<FORMAT>();
3975         return true;
3976     }
3977 
3978     template <BytecodeInstructionSafe::Format FORMAT>
CheckUnaryOp(Type accIn)3979     bool CheckUnaryOp(Type accIn)
3980     {
3981         if (!IsRegDefined(acc)) {
3982             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
3983             return false;
3984         }
3985         return CheckUnaryOp<FORMAT>(accIn, GetAccType());
3986     }
3987 
3988     template <BytecodeInstructionSafe::Format FORMAT, bool REG_DST = false>
CheckBinaryOp(Type v1In,Type v2In,Type out)3989     bool CheckBinaryOp(Type v1In, Type v2In, Type out)
3990     {
3991         uint16_t v1 = inst_.GetVReg<FORMAT, 0x00>();
3992         uint16_t v2 = inst_.GetVReg<FORMAT, 0x01>();
3993         if (!CheckRegType(v1, v1In)) {
3994             SET_STATUS_FOR_MSG(BadRegisterType, WARNING);
3995             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
3996             return false;
3997         }
3998         if (!CheckRegType(v2, v2In)) {
3999             SET_STATUS_FOR_MSG(BadRegisterType, WARNING);
4000             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
4001             return false;
4002         }
4003         if constexpr (REG_DST) {
4004             SetReg(v1, out);
4005         } else {
4006             SetAcc(out);
4007         }
4008         MoveToNextInst<FORMAT>();
4009         return true;
4010     }
4011 
4012     template <BytecodeInstructionSafe::Format FORMAT>
CheckBinaryOp(Type vs1In,Type vs2In)4013     bool CheckBinaryOp(Type vs1In, Type vs2In)
4014     {
4015         if (!IsRegDefined(acc)) {
4016             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
4017             return false;
4018         }
4019         return CheckBinaryOp<FORMAT>(vs1In, vs2In, GetAccType());
4020     }
4021 
4022     template <BytecodeInstructionSafe::Format FORMAT>
HandleConversion(Type from,Type to)4023     bool HandleConversion(Type from, Type to)
4024     {
4025         if (!CheckRegType(acc, from)) {
4026             SET_STATUS_FOR_MSG(BadRegisterType, WARNING);
4027             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
4028             return false;
4029         }
4030         SetAcc(to);
4031         MoveToNextInst<FORMAT>();
4032         return true;
4033     }
4034 
IsConcreteArrayType(Type type)4035     bool IsConcreteArrayType(Type type)
4036     {
4037         return IsSubtype(type, arrayType_, GetTypeSystem()) && type != arrayType_;
4038     }
4039 
4040     template <BytecodeInstructionSafe::Format FORMAT>
CheckArrayLoad(int vs,std::initializer_list<Type> const & expectedEltTypes)4041     bool CheckArrayLoad(int vs, std::initializer_list<Type> const &expectedEltTypes)
4042     {
4043         if (!CheckRegType(acc, integral32_)) {
4044             SET_STATUS_FOR_MSG(BadRegisterType, WARNING);
4045             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
4046             return false;
4047         }
4048         if (!CheckRegType(vs, arrayType_)) {
4049             SET_STATUS_FOR_MSG(BadRegisterType, WARNING);
4050             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
4051             return false;
4052         }
4053 
4054         Type regType = GetRegType(vs);
4055         if (regType == nullRefType_) {
4056             // NOTE(vdyadov): redesign next code, after support exception handlers,
4057             //                treat it as always throw NPE
4058             SHOW_MSG(AlwaysNpe)
4059             LOG_VERIFIER_ALWAYS_NPE(vs);
4060             END_SHOW_MSG();
4061             SetAcc(top_);
4062             SET_STATUS_FOR_MSG(AlwaysNpe, OK);
4063             return false;
4064         }
4065         auto &&arrEltType = regType.GetArrayElementType(GetTypeSystem());
4066         auto find = [&expectedEltTypes](auto type) {
4067             for (Type t : expectedEltTypes) {
4068                 if (type == t) {
4069                     return true;
4070                 }
4071             }
4072             return false;
4073         };
4074         auto res = find(arrEltType);
4075         if (!res) {
4076             PandaVector<Type> expectedTypesVec;
4077             for (auto et : expectedEltTypes) {
4078                 expectedTypesVec.push_back(et);
4079             }
4080             LOG_VERIFIER_BAD_ARRAY_ELEMENT_TYPE3(ToString(arrEltType), ToString(expectedTypesVec));
4081             SET_STATUS_FOR_MSG(BadArrayElementType, WARNING);
4082             return false;
4083         }
4084         SetAcc(arrEltType);
4085         MoveToNextInst<FORMAT>();
4086         return true;
4087     }
4088 
ProcessBranching(int32_t offset)4089     bool ProcessBranching(int32_t offset)
4090     {
4091         auto newInst = inst_.JumpTo(offset);
4092         const uint8_t *target = newInst.GetAddress();
4093         if (!context_.CflowInfo().IsAddrValid(target) ||
4094             !context_.CflowInfo().IsFlagSet(target, CflowMethodInfo::INSTRUCTION)) {
4095             LOG_VERIFIER_INCORRECT_JUMP();
4096             status_ = VerificationStatus::ERROR;
4097             return false;
4098         }
4099 
4100 #ifndef NDEBUG
4101         ExecCtx().ProcessJump(
4102             inst_.GetAddress(), target,
4103             [this, printHdr = true](int regIdx, const auto &srcReg, const auto &dstReg) mutable {
4104                 if (printHdr) {
4105                     LOG_VERIFIER_REGISTER_CONFLICT_HEADER();
4106                     printHdr = false;
4107                 }
4108                 LOG_VERIFIER_REGISTER_CONFLICT(RegisterName(regIdx), ToString(srcReg.GetAbstractType()),
4109                                                ToString(dstReg.GetAbstractType()));
4110                 return true;
4111             },
4112             codeType_);
4113 #else
4114         ExecCtx().ProcessJump(inst_.GetAddress(), target, codeType_);
4115 #endif
4116         return true;
4117     }
4118 
4119     template <BytecodeInstructionSafe::Format FORMAT, template <typename OpT> class Op>
HandleCondJmpz()4120     bool HandleCondJmpz()
4121     {
4122         auto imm = inst_.GetImm<FORMAT>();
4123 
4124         if (!CheckRegType(acc, integral32_)) {
4125             SET_STATUS_FOR_MSG(BadRegisterType, WARNING);
4126             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
4127             return false;
4128         }
4129 
4130         if (!ProcessBranching(imm)) {
4131             return false;
4132         }
4133 
4134         MoveToNextInst<FORMAT>();
4135         return true;
4136     }
4137 
4138     template <BytecodeInstructionSafe::Format FORMAT, template <typename OpT> class Op>
HandleCondJmp()4139     bool HandleCondJmp()
4140     {
4141         auto imm = inst_.GetImm<FORMAT>();
4142         uint16_t vs = inst_.GetVReg<FORMAT>();
4143 
4144         if (!CheckRegType(acc, integral32_)) {
4145             SET_STATUS_FOR_MSG(BadRegisterType, WARNING);
4146             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
4147             return false;
4148         }
4149 
4150         if (!CheckRegType(vs, integral32_)) {
4151             SET_STATUS_FOR_MSG(BadRegisterType, WARNING);
4152             SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
4153             return false;
4154         }
4155 
4156         if (!ProcessBranching(imm)) {
4157             return false;
4158         }
4159 
4160         MoveToNextInst<FORMAT>();
4161         return true;
4162     }
4163 
4164     template <BytecodeInstructionSafe::Format FORMAT>
CheckArrayCtor(Type klass,Span<int> regNums)4165     bool CheckArrayCtor(Type klass, Span<int> regNums)
4166     {
4167         if (!klass.IsConsistent() || !klass.IsClass() || !klass.GetClass()->IsArrayClass()) {
4168             return false;
4169         }
4170         auto argsNum = GetArrayNumDimensions(klass.GetClass());
4171         bool result = false;
4172         for (auto reg : regNums) {
4173             if (!IsRegDefined(reg)) {
4174                 SET_STATUS_FOR_MSG(UndefinedRegister, WARNING);
4175                 result = false;
4176                 break;
4177             }
4178             result = CheckRegType(reg, i32_);
4179             if (!result) {
4180                 LOG(ERROR, VERIFIER) << "Verifier error: ArrayCtor type error";
4181                 status_ = VerificationStatus::ERROR;
4182                 break;
4183             }
4184             --argsNum;
4185             if (argsNum == 0) {
4186                 break;
4187             }
4188         };
4189         if (result && argsNum > 0) {
4190             SHOW_MSG(TooFewArrayConstructorArgs)
4191             LOG_VERIFIER_TOO_FEW_ARRAY_CONSTRUCTOR_ARGS(argsNum);
4192             END_SHOW_MSG();
4193             SET_STATUS_FOR_MSG(TooFewArrayConstructorArgs, WARNING);
4194             result = false;
4195         }
4196         if (result) {
4197             SetAcc(klass);
4198             MoveToNextInst<FORMAT>();
4199         }
4200         return result;
4201     }
4202 
LogInnerMessage(const CheckResult & elt)4203     void LogInnerMessage(const CheckResult &elt)
4204     {
4205         if (elt.IsError()) {
4206             LOG(ERROR, VERIFIER) << "Error: " << elt.msg << ". ";
4207         } else if (elt.IsWarning()) {
4208             LOG(WARNING, VERIFIER) << "Warning: " << elt.msg << ". ";
4209         }
4210     }
4211 
GetArrayNumDimensions(Class const * klass)4212     size_t GetArrayNumDimensions(Class const *klass)
4213     {
4214         size_t res = 0;
4215         while (klass->IsArrayClass()) {
4216             res++;
4217             klass = klass->GetComponentType();
4218         }
4219         return res;
4220     }
4221 
4222 private:
4223     BytecodeInstructionSafe inst_;
4224     VerificationContext &context_;
4225     VerificationStatus status_ {VerificationStatus::OK};
4226     // #ifndef NDEBUG
4227     bool debug_ {false};
4228     uint32_t debugOffset_ {0};
4229     // #endif
4230     EntryPointType codeType_;
4231 
SetStatusAtLeast(VerificationStatus newStatus)4232     void SetStatusAtLeast(VerificationStatus newStatus)
4233     {
4234         status_ = std::max(status_, newStatus);
4235     }
4236 
MsgClassToStatus(MethodOption::MsgClass msgClass)4237     static inline VerificationStatus MsgClassToStatus(MethodOption::MsgClass msgClass)
4238     {
4239         switch (msgClass) {
4240             case MethodOption::MsgClass::HIDDEN:
4241                 return VerificationStatus::OK;
4242             case MethodOption::MsgClass::WARNING:
4243                 return VerificationStatus::WARNING;
4244             case MethodOption::MsgClass::ERROR:
4245                 return VerificationStatus::ERROR;
4246             default:
4247                 UNREACHABLE();
4248         }
4249     }
4250 
GetFieldName(Field const * field)4251     static PandaString GetFieldName(Field const *field)
4252     {
4253         return PandaString {field->GetClass()->GetName()} + "." + utf::Mutf8AsCString(field->GetName().data);
4254     }
4255 };
4256 }  // namespace panda::verifier
4257 
4258 #endif  // PANDA_VERIFICATION_ABSINT_ABS_INT_INL_H
4259