diff options
author | 2024-11-20 14:55:49 +0000 | |
---|---|---|
committer | 2024-11-25 07:36:44 +0000 | |
commit | 98ffb6ed4cfe81af20815fe52aaf6f75b5150432 (patch) | |
tree | 593534fd0d609c76907b2f7e97dd6d55fc9267b6 /runtime/verifier/method_verifier.cc | |
parent | 581aa379c235065caf81845fcfd0146af8a54871 (diff) |
verifier: Faster primitive assignability checks.
Rewrite primitive assignability checks to use the cache id
directly without going through the corresponding `RegType`.
Use the pre-calculated assignability table and protect
against unreachable `Assignability` values with `DCHECK()`,
avoiding unnecessary runtime checks in release builds.
Move failure output to `NO_INLINE` functions to avoid code
bloat from inlining.
Note that this change leaves field and array access and
invoke argument checks untouched because that code needs
to deal with references and narrowing conversions as well.
The verification of `return` is also untouched because the
special-casing of narrowing conversions is a mess - this
should be cleaned up with a standalone change.
Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Bug: 181943478
Change-Id: I8dc24d2d1c09762f38e58ce065ca914490967642
Diffstat (limited to 'runtime/verifier/method_verifier.cc')
-rw-r--r-- | runtime/verifier/method_verifier.cc | 419 |
1 files changed, 221 insertions, 198 deletions
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index a18b00e66d..ede8e366d7 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -708,6 +708,39 @@ class MethodVerifier final : public ::art::verifier::MethodVerifier { } } + NO_INLINE void FailForRegisterType(uint32_t vsrc, + const RegType& check_type, + const RegType& src_type, + VerifyError fail_type = VERIFY_ERROR_BAD_CLASS_HARD) + REQUIRES_SHARED(Locks::mutator_lock_) { + Fail(fail_type) + << "register v" << vsrc << " has type " << src_type << " but expected " << check_type; + } + + NO_INLINE void FailForRegisterType(uint32_t vsrc, + RegType::Kind check_kind, + uint16_t src_type_id) + REQUIRES_SHARED(Locks::mutator_lock_) { + FailForRegisterType( + vsrc, reg_types_.GetFromRegKind(check_kind), reg_types_.GetFromId(src_type_id)); + } + + NO_INLINE void FailForRegisterTypeWide(uint32_t vsrc, + const RegType& src_type, + const RegType& src_type_h) + REQUIRES_SHARED(Locks::mutator_lock_) { + Fail(VERIFY_ERROR_BAD_CLASS_HARD) + << "wide register v" << vsrc << " has type " << src_type << "/" << src_type_h; + } + + NO_INLINE void FailForRegisterTypeWide(uint32_t vsrc, + uint16_t src_type_id, + uint16_t src_type_id_h) + REQUIRES_SHARED(Locks::mutator_lock_) { + FailForRegisterTypeWide( + vsrc, reg_types_.GetFromId(src_type_id), reg_types_.GetFromId(src_type_id_h)); + } + ALWAYS_INLINE inline bool VerifyRegisterType(uint32_t vsrc, const RegType& check_type) REQUIRES_SHARED(Locks::mutator_lock_) { // Verify the src register type against the check type refining the type of the register @@ -725,15 +758,13 @@ class MethodVerifier final : public ::art::verifier::MethodVerifier { } else { fail_type = VERIFY_ERROR_BAD_CLASS_HARD; } - Fail(fail_type) << "register v" << vsrc << " has type " - << src_type << " but expected " << check_type; + FailForRegisterType(vsrc, check_type, src_type, fail_type); return false; } if (check_type.IsLowHalf()) { const RegType& src_type_h = work_line_->GetRegisterType(this, vsrc + 1); if (UNLIKELY(!src_type.CheckWidePair(src_type_h))) { - Fail(VERIFY_ERROR_BAD_CLASS_HARD) - << "wide register v" << vsrc << " has type " << src_type << "/" << src_type_h; + FailForRegisterTypeWide(vsrc, src_type, src_type_h); return false; } } @@ -744,22 +775,46 @@ class MethodVerifier final : public ::art::verifier::MethodVerifier { return true; } - bool VerifyRegisterTypeWide(uint32_t vsrc, - const RegType& check_type1, - const RegType& check_type2) + ALWAYS_INLINE inline bool VerifyRegisterType(uint32_t vsrc, RegType::Kind check_kind) REQUIRES_SHARED(Locks::mutator_lock_) { - DCHECK(check_type1.CheckWidePair(check_type2)); + DCHECK(check_kind == RegType::Kind::kInteger || check_kind == RegType::Kind::kFloat); // Verify the src register type against the check type refining the type of the register - const RegType& src_type = work_line_->GetRegisterType(this, vsrc); - if (!check_type1.IsAssignableFrom(src_type, this)) { - Fail(VERIFY_ERROR_BAD_CLASS_HARD) - << "register v" << vsrc << " has type " << src_type << " but expected " << check_type1; + uint16_t src_type_id = work_line_->GetRegisterTypeId(vsrc); + if (UNLIKELY(src_type_id >= RegTypeCache::NumberOfRegKindCacheIds()) || + UNLIKELY(RegType::AssignabilityFrom(check_kind, RegTypeCache::RegKindForId(src_type_id)) != + RegType::Assignability::kAssignable)) { + // Integer or float assignability is never a `kNarrowingConversion` or `kReference`. + DCHECK_EQ( + RegType::AssignabilityFrom(check_kind, reg_types_.GetFromId(src_type_id).GetKind()), + RegType::Assignability::kNotAssignable); + FailForRegisterType(vsrc, check_kind, src_type_id); return false; } - const RegType& src_type_h = work_line_->GetRegisterType(this, vsrc + 1); - if (!src_type.CheckWidePair(src_type_h)) { - Fail(VERIFY_ERROR_BAD_CLASS_HARD) - << "wide register v" << vsrc << " has type " << src_type << "/" << src_type_h; + return true; + } + + bool VerifyRegisterTypeWide(uint32_t vsrc, RegType::Kind check_kind) + REQUIRES_SHARED(Locks::mutator_lock_) { + DCHECK(check_kind == RegType::Kind::kLongLo || check_kind == RegType::Kind::kDoubleLo); + // Verify the src register type against the check type refining the type of the register + uint16_t src_type_id = work_line_->GetRegisterTypeId(vsrc); + if (UNLIKELY(src_type_id >= RegTypeCache::NumberOfRegKindCacheIds()) || + UNLIKELY(RegType::AssignabilityFrom(check_kind, RegTypeCache::RegKindForId(src_type_id)) != + RegType::Assignability::kAssignable)) { + // Wide assignability is never a `kNarrowingConversion` or `kReference`. + DCHECK_EQ( + RegType::AssignabilityFrom(check_kind, reg_types_.GetFromId(src_type_id).GetKind()), + RegType::Assignability::kNotAssignable); + FailForRegisterType(vsrc, check_kind, src_type_id); + return false; + } + uint16_t src_type_id_h = work_line_->GetRegisterTypeId(vsrc + 1); + uint16_t expected_src_type_id_h = + RegTypeCache::IdForRegKind(RegType::ToHighHalf(RegTypeCache::RegKindForId(src_type_id))); + DCHECK_EQ(src_type_id_h == expected_src_type_id_h, + reg_types_.GetFromId(src_type_id).CheckWidePair(reg_types_.GetFromId(src_type_id_h))); + if (UNLIKELY(src_type_id_h != expected_src_type_id_h)) { + FailForRegisterTypeWide(vsrc, src_type_id, src_type_id_h); return false; } // The register at vsrc has a defined type, we know the lower-upper-bound, but this is less @@ -773,41 +828,37 @@ class MethodVerifier final : public ::art::verifier::MethodVerifier { * Verify types for a simple two-register instruction (e.g. "neg-int"). * "dst_type" is stored into vA, and "src_type" is verified against vB. */ - void CheckUnaryOp(const Instruction* inst, const RegType& dst_type, const RegType& src_type) + void CheckUnaryOp(const Instruction* inst, RegType::Kind dst_kind, RegType::Kind src_kind) REQUIRES_SHARED(Locks::mutator_lock_) { - if (VerifyRegisterType(inst->VRegB_12x(), src_type)) { - work_line_->SetRegisterType<LockOp::kClear>(inst->VRegA_12x(), dst_type); + if (VerifyRegisterType(inst->VRegB_12x(), src_kind)) { + work_line_->SetRegisterType(inst->VRegA_12x(), dst_kind); } } void CheckUnaryOpWide(const Instruction* inst, - const RegType& dst_type1, - const RegType& dst_type2, - const RegType& src_type1, - const RegType& src_type2) + RegType::Kind dst_kind, + RegType::Kind src_kind) REQUIRES_SHARED(Locks::mutator_lock_) { - if (VerifyRegisterTypeWide(inst->VRegB_12x(), src_type1, src_type2)) { - work_line_->SetRegisterTypeWide(inst->VRegA_12x(), dst_type1, dst_type2); + if (VerifyRegisterTypeWide(inst->VRegB_12x(), src_kind)) { + work_line_->SetRegisterTypeWide(inst->VRegA_12x(), dst_kind, RegType::ToHighHalf(dst_kind)); } } void CheckUnaryOpToWide(const Instruction* inst, - const RegType& dst_type1, - const RegType& dst_type2, - const RegType& src_type) + RegType::Kind dst_kind, + RegType::Kind src_kind) REQUIRES_SHARED(Locks::mutator_lock_) { - if (VerifyRegisterType(inst->VRegB_12x(), src_type)) { - work_line_->SetRegisterTypeWide(inst->VRegA_12x(), dst_type1, dst_type2); + if (VerifyRegisterType(inst->VRegB_12x(), src_kind)) { + work_line_->SetRegisterTypeWide(inst->VRegA_12x(), dst_kind, RegType::ToHighHalf(dst_kind)); } } void CheckUnaryOpFromWide(const Instruction* inst, - const RegType& dst_type, - const RegType& src_type1, - const RegType& src_type2) + RegType::Kind dst_kind, + RegType::Kind src_kind) REQUIRES_SHARED(Locks::mutator_lock_) { - if (VerifyRegisterTypeWide(inst->VRegB_12x(), src_type1, src_type2)) { - work_line_->SetRegisterType<LockOp::kClear>(inst->VRegA_12x(), dst_type); + if (VerifyRegisterTypeWide(inst->VRegB_12x(), src_kind)) { + work_line_->SetRegisterType(inst->VRegA_12x(), dst_kind); } } @@ -817,49 +868,60 @@ class MethodVerifier final : public ::art::verifier::MethodVerifier { * against vB/vC. */ void CheckBinaryOp(const Instruction* inst, - const RegType& dst_type, - const RegType& src_type1, - const RegType& src_type2, + RegType::Kind dst_kind, + RegType::Kind src_kind1, + RegType::Kind src_kind2, bool check_boolean_op) REQUIRES_SHARED(Locks::mutator_lock_) { + const uint32_t vregA = inst->VRegA_23x(); const uint32_t vregB = inst->VRegB_23x(); const uint32_t vregC = inst->VRegC_23x(); - if (VerifyRegisterType(vregB, src_type1) && - VerifyRegisterType(vregC, src_type2)) { + if (VerifyRegisterType(vregB, src_kind1) && + VerifyRegisterType(vregC, src_kind2)) { if (check_boolean_op) { - DCHECK(dst_type.IsInteger()); - if (work_line_->GetRegisterType(this, vregB).IsBooleanTypes() && - work_line_->GetRegisterType(this, vregC).IsBooleanTypes()) { - work_line_->SetRegisterType<LockOp::kClear>(inst->VRegA_23x(), reg_types_.Boolean()); + DCHECK_EQ(dst_kind, RegType::Kind::kInteger); + if (RegType::IsBooleanTypes( + RegTypeCache::RegKindForId(work_line_->GetRegisterTypeId(vregB))) && + RegType::IsBooleanTypes( + RegTypeCache::RegKindForId(work_line_->GetRegisterTypeId(vregC)))) { + work_line_->SetRegisterType(vregA, RegType::Kind::kBoolean); return; } } - work_line_->SetRegisterType<LockOp::kClear>(inst->VRegA_23x(), dst_type); + work_line_->SetRegisterType(vregA, dst_kind); } } void CheckBinaryOpWide(const Instruction* inst, - const RegType& dst_type1, - const RegType& dst_type2, - const RegType& src_type1_1, - const RegType& src_type1_2, - const RegType& src_type2_1, - const RegType& src_type2_2) + RegType::Kind dst_kind, + RegType::Kind src_kind1, + RegType::Kind src_kind2) + REQUIRES_SHARED(Locks::mutator_lock_) { + if (VerifyRegisterTypeWide(inst->VRegB_23x(), src_kind1) && + VerifyRegisterTypeWide(inst->VRegC_23x(), src_kind2)) { + work_line_->SetRegisterTypeWide(inst->VRegA_23x(), dst_kind, RegType::ToHighHalf(dst_kind)); + } + } + + void CheckBinaryOpWideCmp(const Instruction* inst, + RegType::Kind dst_kind, + RegType::Kind src_kind1, + RegType::Kind src_kind2) REQUIRES_SHARED(Locks::mutator_lock_) { - if (VerifyRegisterTypeWide(inst->VRegB_23x(), src_type1_1, src_type1_2) && - VerifyRegisterTypeWide(inst->VRegC_23x(), src_type2_1, src_type2_2)) { - work_line_->SetRegisterTypeWide(inst->VRegA_23x(), dst_type1, dst_type2); + if (VerifyRegisterTypeWide(inst->VRegB_23x(), src_kind1) && + VerifyRegisterTypeWide(inst->VRegC_23x(), src_kind2)) { + work_line_->SetRegisterType(inst->VRegA_23x(), dst_kind); } } void CheckBinaryOpWideShift(const Instruction* inst, - const RegType& long_lo_type, - const RegType& long_hi_type, - const RegType& int_type) + RegType::Kind long_lo_kind, + RegType::Kind int_kind) REQUIRES_SHARED(Locks::mutator_lock_) { - if (VerifyRegisterTypeWide(inst->VRegB_23x(), long_lo_type, long_hi_type) && - VerifyRegisterType(inst->VRegC_23x(), int_type)) { - work_line_->SetRegisterTypeWide(inst->VRegA_23x(), long_lo_type, long_hi_type); + if (VerifyRegisterTypeWide(inst->VRegB_23x(), long_lo_kind) && + VerifyRegisterType(inst->VRegC_23x(), int_kind)) { + RegType::Kind long_hi_kind = RegType::ToHighHalf(long_lo_kind); + work_line_->SetRegisterTypeWide(inst->VRegA_23x(), long_lo_kind, long_hi_kind); } } @@ -868,53 +930,52 @@ class MethodVerifier final : public ::art::verifier::MethodVerifier { * are verified against vA/vB, then "dst_type" is stored into vA. */ void CheckBinaryOp2addr(const Instruction* inst, - const RegType& dst_type, - const RegType& src_type1, - const RegType& src_type2, + RegType::Kind dst_kind, + RegType::Kind src_kind1, + RegType::Kind src_kind2, bool check_boolean_op) REQUIRES_SHARED(Locks::mutator_lock_) { const uint32_t vregA = inst->VRegA_12x(); const uint32_t vregB = inst->VRegB_12x(); - if (VerifyRegisterType(vregA, src_type1) && - VerifyRegisterType(vregB, src_type2)) { + if (VerifyRegisterType(vregA, src_kind1) && + VerifyRegisterType(vregB, src_kind2)) { if (check_boolean_op) { - DCHECK(dst_type.IsInteger()); - if (work_line_->GetRegisterType(this, vregA).IsBooleanTypes() && - work_line_->GetRegisterType(this, vregB).IsBooleanTypes()) { - work_line_->SetRegisterType<LockOp::kClear>(vregA, reg_types_.Boolean()); + DCHECK_EQ(dst_kind, RegType::Kind::kInteger); + if (RegType::IsBooleanTypes( + RegTypeCache::RegKindForId(work_line_->GetRegisterTypeId(vregA))) && + RegType::IsBooleanTypes( + RegTypeCache::RegKindForId(work_line_->GetRegisterTypeId(vregB)))) { + work_line_->SetRegisterType(vregA, RegType::Kind::kBoolean); return; } } - work_line_->SetRegisterType<LockOp::kClear>(vregA, dst_type); + work_line_->SetRegisterType(vregA, dst_kind); } } void CheckBinaryOp2addrWide(const Instruction* inst, - const RegType& dst_type1, - const RegType& dst_type2, - const RegType& src_type1_1, - const RegType& src_type1_2, - const RegType& src_type2_1, - const RegType& src_type2_2) + RegType::Kind dst_kind, + RegType::Kind src_kind1, + RegType::Kind src_kind2) REQUIRES_SHARED(Locks::mutator_lock_) { const uint32_t vregA = inst->VRegA_12x(); const uint32_t vregB = inst->VRegB_12x(); - if (VerifyRegisterTypeWide(vregA, src_type1_1, src_type1_2) && - VerifyRegisterTypeWide(vregB, src_type2_1, src_type2_2)) { - work_line_->SetRegisterTypeWide(vregA, dst_type1, dst_type2); + if (VerifyRegisterTypeWide(vregA, src_kind1) && + VerifyRegisterTypeWide(vregB, src_kind2)) { + work_line_->SetRegisterTypeWide(vregA, dst_kind, RegType::ToHighHalf(dst_kind)); } } void CheckBinaryOp2addrWideShift(const Instruction* inst, - const RegType& long_lo_type, - const RegType& long_hi_type, - const RegType& int_type) + RegType::Kind long_lo_kind, + RegType::Kind int_kind) REQUIRES_SHARED(Locks::mutator_lock_) { const uint32_t vregA = inst->VRegA_12x(); const uint32_t vregB = inst->VRegB_12x(); - if (VerifyRegisterTypeWide(vregA, long_lo_type, long_hi_type) && - VerifyRegisterType(vregB, int_type)) { - work_line_->SetRegisterTypeWide(vregA, long_lo_type, long_hi_type); + if (VerifyRegisterTypeWide(vregA, long_lo_kind) && + VerifyRegisterType(vregB, int_kind)) { + RegType::Kind long_hi_kind = RegType::ToHighHalf(long_lo_kind); + work_line_->SetRegisterTypeWide(vregA, long_lo_kind, long_hi_kind); } } @@ -925,24 +986,24 @@ class MethodVerifier final : public ::art::verifier::MethodVerifier { * If "check_boolean_op" is set, we use the constant value in vC. */ void CheckLiteralOp(const Instruction* inst, - const RegType& dst_type, - const RegType& src_type, + RegType::Kind dst_kind, + RegType::Kind src_kind, bool check_boolean_op, bool is_lit16) REQUIRES_SHARED(Locks::mutator_lock_) { const uint32_t vregA = is_lit16 ? inst->VRegA_22s() : inst->VRegA_22b(); const uint32_t vregB = is_lit16 ? inst->VRegB_22s() : inst->VRegB_22b(); - if (VerifyRegisterType(vregB, src_type)) { + if (VerifyRegisterType(vregB, src_kind)) { if (check_boolean_op) { - DCHECK(dst_type.IsInteger()); + DCHECK_EQ(dst_kind, RegType::Kind::kInteger); /* check vB with the call, then check the constant manually */ const uint32_t val = is_lit16 ? inst->VRegC_22s() : inst->VRegC_22b(); if (work_line_->GetRegisterType(this, vregB).IsBooleanTypes() && (val == 0 || val == 1)) { - work_line_->SetRegisterType<LockOp::kClear>(vregA, reg_types_.Boolean()); + work_line_->SetRegisterType(vregA, RegType::Kind::kBoolean); return; } } - work_line_->SetRegisterType<LockOp::kClear>(vregA, dst_type); + work_line_->SetRegisterType(vregA, dst_kind); } } @@ -950,7 +1011,7 @@ class MethodVerifier final : public ::art::verifier::MethodVerifier { return &GetModifiableInstructionFlags(work_insn_idx_); } - const RegType& DetermineCat1Constant(int32_t value) + RegType::Kind DetermineCat1Constant(int32_t value) REQUIRES_SHARED(Locks::mutator_lock_); ALWAYS_INLINE bool FailOrAbort(bool condition, const char* error_msg, uint32_t work_insn_idx); @@ -1968,22 +2029,22 @@ bool MethodVerifier<kVerifierDebug>::SetTypesFromSignature() { } break; case 'Z': - reg_line->SetRegisterType<LockOp::kClear>(arg_start + cur_arg, reg_types_.Boolean()); + reg_line->SetRegisterType(arg_start + cur_arg, RegType::Kind::kBoolean); break; case 'C': - reg_line->SetRegisterType<LockOp::kClear>(arg_start + cur_arg, reg_types_.Char()); + reg_line->SetRegisterType(arg_start + cur_arg, RegType::Kind::kChar); break; case 'B': - reg_line->SetRegisterType<LockOp::kClear>(arg_start + cur_arg, reg_types_.Byte()); + reg_line->SetRegisterType(arg_start + cur_arg, RegType::Kind::kByte); break; case 'I': - reg_line->SetRegisterType<LockOp::kClear>(arg_start + cur_arg, reg_types_.Integer()); + reg_line->SetRegisterType(arg_start + cur_arg, RegType::Kind::kInteger); break; case 'S': - reg_line->SetRegisterType<LockOp::kClear>(arg_start + cur_arg, reg_types_.Short()); + reg_line->SetRegisterType(arg_start + cur_arg, RegType::Kind::kShort); break; case 'F': - reg_line->SetRegisterType<LockOp::kClear>(arg_start + cur_arg, reg_types_.Float()); + reg_line->SetRegisterType(arg_start + cur_arg, RegType::Kind::kFloat); break; case 'J': case 'D': { @@ -2291,6 +2352,7 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g RegisterLineArenaUniquePtr branch_line; RegisterLineArenaUniquePtr fallthrough_line; + using enum RegType::Kind; switch (inst->Opcode()) { case Instruction::NOP: /* @@ -2398,7 +2460,7 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g } else { /* check the register contents */ const uint32_t vregA = inst->VRegA_11x(); - bool success = VerifyRegisterType(vregA, return_type); + bool success = VerifyRegisterTypeWide(vregA, return_type.GetKind()); if (!success) { AppendToLastFailMessage(StringPrintf(" return-wide on invalid register v%d", vregA)); } @@ -2445,22 +2507,22 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g /* could be boolean, int, float, or a null reference */ case Instruction::CONST_4: { int32_t val = static_cast<int32_t>(inst->VRegB_11n() << 28) >> 28; - work_line_->SetRegisterType<LockOp::kClear>(inst->VRegA_11n(), DetermineCat1Constant(val)); + work_line_->SetRegisterType(inst->VRegA_11n(), DetermineCat1Constant(val)); break; } case Instruction::CONST_16: { int16_t val = static_cast<int16_t>(inst->VRegB_21s()); - work_line_->SetRegisterType<LockOp::kClear>(inst->VRegA_21s(), DetermineCat1Constant(val)); + work_line_->SetRegisterType(inst->VRegA_21s(), DetermineCat1Constant(val)); break; } case Instruction::CONST: { int32_t val = inst->VRegB_31i(); - work_line_->SetRegisterType<LockOp::kClear>(inst->VRegA_31i(), DetermineCat1Constant(val)); + work_line_->SetRegisterType(inst->VRegA_31i(), DetermineCat1Constant(val)); break; } case Instruction::CONST_HIGH16: { int32_t val = static_cast<int32_t>(inst->VRegB_21h() << 16); - work_line_->SetRegisterType<LockOp::kClear>(inst->VRegA_21h(), DetermineCat1Constant(val)); + work_line_->SetRegisterType(inst->VRegA_21h(), DetermineCat1Constant(val)); break; } /* could be long or double; resolved upon use */ @@ -2633,7 +2695,7 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g DCHECK_NE(failures_.size(), 0U); if (!is_checkcast) { - work_line_->SetRegisterType<LockOp::kClear>(inst->VRegA_22c(), reg_types_.Boolean()); + work_line_->SetRegisterType(inst->VRegA_22c(), kBoolean); } break; // bad class } @@ -2664,7 +2726,7 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g if (is_checkcast) { work_line_->SetRegisterType<LockOp::kKeep>(inst->VRegA_21c(), res_type); } else { - work_line_->SetRegisterType<LockOp::kClear>(inst->VRegA_22c(), reg_types_.Boolean()); + work_line_->SetRegisterType(inst->VRegA_22c(), kBoolean); } } break; @@ -2676,7 +2738,7 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g // ie not an array or null Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "array-length on non-array " << res_type; } else { - work_line_->SetRegisterType<LockOp::kClear>(inst->VRegA_12x(), reg_types_.Integer()); + work_line_->SetRegisterType(inst->VRegA_12x(), kInteger); } } else { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "array-length on non-array " << res_type; @@ -2718,34 +2780,14 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g break; case Instruction::CMPL_FLOAT: case Instruction::CMPG_FLOAT: - if (!VerifyRegisterType(inst->VRegB_23x(), reg_types_.Float())) { - break; - } - if (!VerifyRegisterType(inst->VRegC_23x(), reg_types_.Float())) { - break; - } - work_line_->SetRegisterType<LockOp::kClear>(inst->VRegA_23x(), reg_types_.Integer()); + CheckBinaryOp(inst, kInteger, kFloat, kFloat, /*check_boolean_op=*/ false); break; case Instruction::CMPL_DOUBLE: case Instruction::CMPG_DOUBLE: - if (!VerifyRegisterTypeWide(inst->VRegB_23x(), reg_types_.DoubleLo(), - reg_types_.DoubleHi())) { - break; - } - if (!VerifyRegisterTypeWide(inst->VRegC_23x(), reg_types_.DoubleLo(), - reg_types_.DoubleHi())) { - break; - } - work_line_->SetRegisterType<LockOp::kClear>(inst->VRegA_23x(), reg_types_.Integer()); + CheckBinaryOpWideCmp(inst, kInteger, kDoubleLo, kDoubleLo); break; case Instruction::CMP_LONG: - if (!VerifyRegisterTypeWide(inst->VRegB_23x(), reg_types_.LongLo(), reg_types_.LongHi())) { - break; - } - if (!VerifyRegisterTypeWide(inst->VRegC_23x(), reg_types_.LongLo(), reg_types_.LongHi())) { - break; - } - work_line_->SetRegisterType<LockOp::kClear>(inst->VRegA_23x(), reg_types_.Integer()); + CheckBinaryOpWideCmp(inst, kInteger, kLongLo, kLongLo); break; case Instruction::THROW: { const RegType& res_type = work_line_->GetRegisterType(this, inst->VRegA_11x()); @@ -2771,7 +2813,7 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g case Instruction::PACKED_SWITCH: case Instruction::SPARSE_SWITCH: /* verify that vAA is an integer, or can be converted to one */ - VerifyRegisterType(inst->VRegA_31t(), reg_types_.Integer()); + VerifyRegisterType(inst->VRegA_31t(), kInteger); break; case Instruction::FILL_ARRAY_DATA: { @@ -3321,69 +3363,62 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g } case Instruction::NEG_INT: case Instruction::NOT_INT: - CheckUnaryOp(inst, reg_types_.Integer(), reg_types_.Integer()); + CheckUnaryOp(inst, kInteger, kInteger); break; case Instruction::NEG_LONG: case Instruction::NOT_LONG: - CheckUnaryOpWide(inst, reg_types_.LongLo(), reg_types_.LongHi(), - reg_types_.LongLo(), reg_types_.LongHi()); + CheckUnaryOpWide(inst, kLongLo, kLongLo); break; case Instruction::NEG_FLOAT: - CheckUnaryOp(inst, reg_types_.Float(), reg_types_.Float()); + CheckUnaryOp(inst, kFloat, kFloat); break; case Instruction::NEG_DOUBLE: - CheckUnaryOpWide(inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(), - reg_types_.DoubleLo(), reg_types_.DoubleHi()); + CheckUnaryOpWide(inst, kDoubleLo, kDoubleLo); break; case Instruction::INT_TO_LONG: - CheckUnaryOpToWide(inst, reg_types_.LongLo(), reg_types_.LongHi(), reg_types_.Integer()); + CheckUnaryOpToWide(inst, kLongLo, kInteger); break; case Instruction::INT_TO_FLOAT: - CheckUnaryOp(inst, reg_types_.Float(), reg_types_.Integer()); + CheckUnaryOp(inst, kFloat, kInteger); break; case Instruction::INT_TO_DOUBLE: - CheckUnaryOpToWide(inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(), - reg_types_.Integer()); + CheckUnaryOpToWide(inst, kDoubleLo, kInteger); break; case Instruction::LONG_TO_INT: - CheckUnaryOpFromWide(inst, reg_types_.Integer(), reg_types_.LongLo(), reg_types_.LongHi()); + CheckUnaryOpFromWide(inst, kInteger, kLongLo); break; case Instruction::LONG_TO_FLOAT: - CheckUnaryOpFromWide(inst, reg_types_.Float(), reg_types_.LongLo(), reg_types_.LongHi()); + CheckUnaryOpFromWide(inst, kFloat, kLongLo); break; case Instruction::LONG_TO_DOUBLE: - CheckUnaryOpWide(inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(), - reg_types_.LongLo(), reg_types_.LongHi()); + CheckUnaryOpWide(inst, kDoubleLo, kLongLo); break; case Instruction::FLOAT_TO_INT: - CheckUnaryOp(inst, reg_types_.Integer(), reg_types_.Float()); + CheckUnaryOp(inst, kInteger, kFloat); break; case Instruction::FLOAT_TO_LONG: - CheckUnaryOpToWide(inst, reg_types_.LongLo(), reg_types_.LongHi(), reg_types_.Float()); + CheckUnaryOpToWide(inst, kLongLo, kFloat); break; case Instruction::FLOAT_TO_DOUBLE: - CheckUnaryOpToWide(inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(), reg_types_.Float()); + CheckUnaryOpToWide(inst, kDoubleLo, kFloat); break; case Instruction::DOUBLE_TO_INT: - CheckUnaryOpFromWide(inst, reg_types_.Integer(), - reg_types_.DoubleLo(), reg_types_.DoubleHi()); + CheckUnaryOpFromWide(inst, kInteger, kDoubleLo); break; case Instruction::DOUBLE_TO_LONG: - CheckUnaryOpWide(inst, reg_types_.LongLo(), reg_types_.LongHi(), - reg_types_.DoubleLo(), reg_types_.DoubleHi()); + CheckUnaryOpWide(inst, kLongLo, kDoubleLo); break; case Instruction::DOUBLE_TO_FLOAT: - CheckUnaryOpFromWide(inst, reg_types_.Float(), - reg_types_.DoubleLo(), reg_types_.DoubleHi()); + CheckUnaryOpFromWide(inst, kFloat, kDoubleLo); break; case Instruction::INT_TO_BYTE: - CheckUnaryOp(inst, reg_types_.Byte(), reg_types_.Integer()); + CheckUnaryOp(inst, kByte, kInteger); break; case Instruction::INT_TO_CHAR: - CheckUnaryOp(inst, reg_types_.Char(), reg_types_.Integer()); + CheckUnaryOp(inst, kChar, kInteger); break; case Instruction::INT_TO_SHORT: - CheckUnaryOp(inst, reg_types_.Short(), reg_types_.Integer()); + CheckUnaryOp(inst, kShort, kInteger); break; case Instruction::ADD_INT: @@ -3394,12 +3429,12 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g case Instruction::SHL_INT: case Instruction::SHR_INT: case Instruction::USHR_INT: - CheckBinaryOp(inst, reg_types_.Integer(), reg_types_.Integer(), reg_types_.Integer(), false); + CheckBinaryOp(inst, kInteger, kInteger, kInteger, /*check_boolean_op=*/ false); break; case Instruction::AND_INT: case Instruction::OR_INT: case Instruction::XOR_INT: - CheckBinaryOp(inst, reg_types_.Integer(), reg_types_.Integer(), reg_types_.Integer(), true); + CheckBinaryOp(inst, kInteger, kInteger, kInteger, /*check_boolean_op=*/ true); break; case Instruction::ADD_LONG: case Instruction::SUB_LONG: @@ -3409,31 +3444,27 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g case Instruction::AND_LONG: case Instruction::OR_LONG: case Instruction::XOR_LONG: - CheckBinaryOpWide(inst, reg_types_.LongLo(), reg_types_.LongHi(), - reg_types_.LongLo(), reg_types_.LongHi(), - reg_types_.LongLo(), reg_types_.LongHi()); + CheckBinaryOpWide(inst, kLongLo, kLongLo, kLongLo); break; case Instruction::SHL_LONG: case Instruction::SHR_LONG: case Instruction::USHR_LONG: /* shift distance is Int, making these different from other binary operations */ - CheckBinaryOpWideShift(inst, reg_types_.LongLo(), reg_types_.LongHi(), reg_types_.Integer()); + CheckBinaryOpWideShift(inst, kLongLo, kInteger); break; case Instruction::ADD_FLOAT: case Instruction::SUB_FLOAT: case Instruction::MUL_FLOAT: case Instruction::DIV_FLOAT: case Instruction::REM_FLOAT: - CheckBinaryOp(inst, reg_types_.Float(), reg_types_.Float(), reg_types_.Float(), false); + CheckBinaryOp(inst, kFloat, kFloat, kFloat, /*check_boolean_op=*/ false); break; case Instruction::ADD_DOUBLE: case Instruction::SUB_DOUBLE: case Instruction::MUL_DOUBLE: case Instruction::DIV_DOUBLE: case Instruction::REM_DOUBLE: - CheckBinaryOpWide(inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(), - reg_types_.DoubleLo(), reg_types_.DoubleHi(), - reg_types_.DoubleLo(), reg_types_.DoubleHi()); + CheckBinaryOpWide(inst, kDoubleLo, kDoubleLo, kDoubleLo); break; case Instruction::ADD_INT_2ADDR: case Instruction::SUB_INT_2ADDR: @@ -3442,18 +3473,15 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g case Instruction::SHL_INT_2ADDR: case Instruction::SHR_INT_2ADDR: case Instruction::USHR_INT_2ADDR: - CheckBinaryOp2addr( - inst, reg_types_.Integer(), reg_types_.Integer(), reg_types_.Integer(), false); + CheckBinaryOp2addr(inst, kInteger, kInteger, kInteger, /*check_boolean_op=*/ false); break; case Instruction::AND_INT_2ADDR: case Instruction::OR_INT_2ADDR: case Instruction::XOR_INT_2ADDR: - CheckBinaryOp2addr( - inst, reg_types_.Integer(), reg_types_.Integer(), reg_types_.Integer(), true); + CheckBinaryOp2addr(inst, kInteger, kInteger, kInteger, /*check_boolean_op=*/ true); break; case Instruction::DIV_INT_2ADDR: - CheckBinaryOp2addr( - inst, reg_types_.Integer(), reg_types_.Integer(), reg_types_.Integer(), false); + CheckBinaryOp2addr(inst, kInteger, kInteger, kInteger, /*check_boolean_op=*/ false); break; case Instruction::ADD_LONG_2ADDR: case Instruction::SUB_LONG_2ADDR: @@ -3463,43 +3491,38 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g case Instruction::AND_LONG_2ADDR: case Instruction::OR_LONG_2ADDR: case Instruction::XOR_LONG_2ADDR: - CheckBinaryOp2addrWide(inst, reg_types_.LongLo(), reg_types_.LongHi(), - reg_types_.LongLo(), reg_types_.LongHi(), - reg_types_.LongLo(), reg_types_.LongHi()); + CheckBinaryOp2addrWide(inst, kLongLo, kLongLo, kLongLo); break; case Instruction::SHL_LONG_2ADDR: case Instruction::SHR_LONG_2ADDR: case Instruction::USHR_LONG_2ADDR: - CheckBinaryOp2addrWideShift( - inst, reg_types_.LongLo(), reg_types_.LongHi(), reg_types_.Integer()); + CheckBinaryOp2addrWideShift(inst, kLongLo, kInteger); break; case Instruction::ADD_FLOAT_2ADDR: case Instruction::SUB_FLOAT_2ADDR: case Instruction::MUL_FLOAT_2ADDR: case Instruction::DIV_FLOAT_2ADDR: case Instruction::REM_FLOAT_2ADDR: - CheckBinaryOp2addr(inst, reg_types_.Float(), reg_types_.Float(), reg_types_.Float(), false); + CheckBinaryOp2addr(inst, kFloat, kFloat, kFloat, /*check_boolean_op=*/ false); break; case Instruction::ADD_DOUBLE_2ADDR: case Instruction::SUB_DOUBLE_2ADDR: case Instruction::MUL_DOUBLE_2ADDR: case Instruction::DIV_DOUBLE_2ADDR: case Instruction::REM_DOUBLE_2ADDR: - CheckBinaryOp2addrWide(inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(), - reg_types_.DoubleLo(), reg_types_.DoubleHi(), - reg_types_.DoubleLo(), reg_types_.DoubleHi()); + CheckBinaryOp2addrWide(inst, kDoubleLo, kDoubleLo, kDoubleLo); break; case Instruction::ADD_INT_LIT16: case Instruction::RSUB_INT_LIT16: case Instruction::MUL_INT_LIT16: case Instruction::DIV_INT_LIT16: case Instruction::REM_INT_LIT16: - CheckLiteralOp(inst, reg_types_.Integer(), reg_types_.Integer(), false, true); + CheckLiteralOp(inst, kInteger, kInteger, /*check_boolean_op=*/ false, /*is_lit16=*/ true); break; case Instruction::AND_INT_LIT16: case Instruction::OR_INT_LIT16: case Instruction::XOR_INT_LIT16: - CheckLiteralOp(inst, reg_types_.Integer(), reg_types_.Integer(), true, true); + CheckLiteralOp(inst, kInteger, kInteger, /*check_boolean_op=*/ true, /*is_lit16=*/ true); break; case Instruction::ADD_INT_LIT8: case Instruction::RSUB_INT_LIT8: @@ -3509,12 +3532,12 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g case Instruction::SHL_INT_LIT8: case Instruction::SHR_INT_LIT8: case Instruction::USHR_INT_LIT8: - CheckLiteralOp(inst, reg_types_.Integer(), reg_types_.Integer(), false, false); + CheckLiteralOp(inst, kInteger, kInteger, /*check_boolean_op=*/ false, /*is_lit16=*/ false); break; case Instruction::AND_INT_LIT8: case Instruction::OR_INT_LIT8: case Instruction::XOR_INT_LIT8: - CheckLiteralOp(inst, reg_types_.Integer(), reg_types_.Integer(), true, false); + CheckLiteralOp(inst, kInteger, kInteger, /*check_boolean_op=*/ true, /*is_lit16=*/ false); break; /* These should never appear during verification. */ @@ -4468,7 +4491,7 @@ void MethodVerifier<kVerifierDebug>::VerifyNewArray(const Instruction* inst, Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "new-array on non-array class " << res_type; } else if (!is_filled) { /* make sure "size" register is valid type */ - VerifyRegisterType(inst->VRegB_22c(), reg_types_.Integer()); + VerifyRegisterType(inst->VRegB_22c(), RegType::Kind::kInteger); /* set register type to array class */ work_line_->SetRegisterType<LockOp::kClear>(inst->VRegA_22c(), res_type); } else { @@ -4512,7 +4535,7 @@ void MethodVerifier<kVerifierDebug>::VerifyAGet(const Instruction* inst, } else if (insn_type.IsInteger()) { // Pick a non-zero constant (to distinguish with null) that can fit in any primitive. // We cannot use 'insn_type' as it could be a float array or an int array. - work_line_->SetRegisterType<LockOp::kClear>(inst->VRegA_23x(), DetermineCat1Constant(1)); + work_line_->SetRegisterType(inst->VRegA_23x(), DetermineCat1Constant(1)); } else if (insn_type.IsCategory1Types()) { // Category 1 // The 'insn_type' is exactly the type we need. @@ -4534,7 +4557,7 @@ void MethodVerifier<kVerifierDebug>::VerifyAGet(const Instruction* inst, Fail(VERIFY_ERROR_NO_CLASS) << "cannot verify aget for " << array_type << " because of missing class"; // Approximate with java.lang.Object[]. - work_line_->SetRegisterType<LockOp::kClear>(inst->VRegA_23x(), reg_types_.JavaLangObject()); + work_line_->SetRegisterType(inst->VRegA_23x(), RegType::Kind::kJavaLangObject); } } else { /* verify the class */ @@ -5017,26 +5040,26 @@ const RegType& MethodVerifier<kVerifierDebug>::GetMethodReturnType() { } template <bool kVerifierDebug> -const RegType& MethodVerifier<kVerifierDebug>::DetermineCat1Constant(int32_t value) { +RegType::Kind MethodVerifier<kVerifierDebug>::DetermineCat1Constant(int32_t value) { // Imprecise constant type. if (value < -32768) { - return reg_types_.IntegerConstant(); + return RegType::Kind::kIntegerConstant; } else if (value < -128) { - return reg_types_.ShortConstant(); + return RegType::Kind::kShortConstant; } else if (value < 0) { - return reg_types_.ByteConstant(); + return RegType::Kind::kByteConstant; } else if (value == 0) { - return reg_types_.Zero(); + return RegType::Kind::kZero; } else if (value == 1) { - return reg_types_.BooleanConstant(); + return RegType::Kind::kBooleanConstant; } else if (value < 128) { - return reg_types_.PositiveByteConstant(); + return RegType::Kind::kPositiveByteConstant; } else if (value < 32768) { - return reg_types_.PositiveShortConstant(); + return RegType::Kind::kPositiveShortConstant; } else if (value < 65536) { - return reg_types_.CharConstant(); + return RegType::Kind::kCharConstant; } else { - return reg_types_.IntegerConstant(); + return RegType::Kind::kIntegerConstant; } } |