diff options
author | 2024-11-20 13:47:10 +0000 | |
---|---|---|
committer | 2024-11-21 12:52:06 +0000 | |
commit | d4b4368669a4d7cd6abe9ecbd133e29a646d37a3 (patch) | |
tree | bce0420490aa9e2d1cc6c2efc4a28bdaa819b9ae | |
parent | a21eb118c8c1e9d362b7465327f1fae8db48a572 (diff) |
verifier: Refactor type verification.
Move type verification from the `RegisterLine` to the
`MethodVerifier`.
Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Change-Id: Ibab8b3fb07723fbb79a27eb47e9a25ba746d5d90
-rw-r--r-- | runtime/verifier/method_verifier.cc | 399 | ||||
-rw-r--r-- | runtime/verifier/register_line-inl.h | 36 | ||||
-rw-r--r-- | runtime/verifier/register_line.cc | 155 | ||||
-rw-r--r-- | runtime/verifier/register_line.h | 116 |
4 files changed, 310 insertions, 396 deletions
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index bd4c9d2128..a18b00e66d 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -708,6 +708,244 @@ class MethodVerifier final : public ::art::verifier::MethodVerifier { } } + 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 + const RegType& src_type = work_line_->GetRegisterType(this, vsrc); + if (UNLIKELY(!check_type.IsAssignableFrom(src_type, this))) { + enum VerifyError fail_type; + if (!check_type.IsNonZeroReferenceTypes() || !src_type.IsNonZeroReferenceTypes()) { + // Hard fail if one of the types is primitive, since they are concretely known. + fail_type = VERIFY_ERROR_BAD_CLASS_HARD; + } else if (check_type.IsUninitializedTypes() || src_type.IsUninitializedTypes()) { + // Hard fail for uninitialized types, which don't match anything but themselves. + fail_type = VERIFY_ERROR_BAD_CLASS_HARD; + } else if (check_type.IsUnresolvedTypes() || src_type.IsUnresolvedTypes()) { + fail_type = VERIFY_ERROR_UNRESOLVED_TYPE_CHECK; + } else { + fail_type = VERIFY_ERROR_BAD_CLASS_HARD; + } + Fail(fail_type) << "register v" << vsrc << " has type " + << src_type << " but expected " << check_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; + return false; + } + } + // The register at vsrc has a defined type, we know the lower-upper-bound, but this is less + // precise than the subtype in vsrc so leave it for reference types. For primitive types if + // they are a defined type then they are as precise as we can get, however, for constant types + // we may wish to refine them. Unfortunately constant propagation has rendered this useless. + return true; + } + + bool VerifyRegisterTypeWide(uint32_t vsrc, + const RegType& check_type1, + const RegType& check_type2) + REQUIRES_SHARED(Locks::mutator_lock_) { + DCHECK(check_type1.CheckWidePair(check_type2)); + // 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; + 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 false; + } + // The register at vsrc has a defined type, we know the lower-upper-bound, but this is less + // precise than the subtype in vsrc so leave it for reference types. For primitive types if + // they are a defined type then they are as precise as we can get, however, for constant types + // we may wish to refine them. Unfortunately constant propagation has rendered this useless. + return true; + } + + /* + * 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) + REQUIRES_SHARED(Locks::mutator_lock_) { + if (VerifyRegisterType(inst->VRegB_12x(), src_type)) { + work_line_->SetRegisterType<LockOp::kClear>(inst->VRegA_12x(), dst_type); + } + } + + void CheckUnaryOpWide(const Instruction* inst, + const RegType& dst_type1, + const RegType& dst_type2, + const RegType& src_type1, + const RegType& src_type2) + REQUIRES_SHARED(Locks::mutator_lock_) { + if (VerifyRegisterTypeWide(inst->VRegB_12x(), src_type1, src_type2)) { + work_line_->SetRegisterTypeWide(inst->VRegA_12x(), dst_type1, dst_type2); + } + } + + void CheckUnaryOpToWide(const Instruction* inst, + const RegType& dst_type1, + const RegType& dst_type2, + const RegType& src_type) + REQUIRES_SHARED(Locks::mutator_lock_) { + if (VerifyRegisterType(inst->VRegB_12x(), src_type)) { + work_line_->SetRegisterTypeWide(inst->VRegA_12x(), dst_type1, dst_type2); + } + } + + void CheckUnaryOpFromWide(const Instruction* inst, + const RegType& dst_type, + const RegType& src_type1, + const RegType& src_type2) + REQUIRES_SHARED(Locks::mutator_lock_) { + if (VerifyRegisterTypeWide(inst->VRegB_12x(), src_type1, src_type2)) { + work_line_->SetRegisterType<LockOp::kClear>(inst->VRegA_12x(), dst_type); + } + } + + /* + * Verify types for a simple three-register instruction (e.g. "add-int"). + * "dst_type" is stored into vA, and "src_type1"/"src_type2" are verified + * against vB/vC. + */ + void CheckBinaryOp(const Instruction* inst, + const RegType& dst_type, + const RegType& src_type1, + const RegType& src_type2, + bool check_boolean_op) + REQUIRES_SHARED(Locks::mutator_lock_) { + const uint32_t vregB = inst->VRegB_23x(); + const uint32_t vregC = inst->VRegC_23x(); + if (VerifyRegisterType(vregB, src_type1) && + VerifyRegisterType(vregC, src_type2)) { + 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()); + return; + } + } + work_line_->SetRegisterType<LockOp::kClear>(inst->VRegA_23x(), dst_type); + } + } + + 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) + 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); + } + } + + void CheckBinaryOpWideShift(const Instruction* inst, + const RegType& long_lo_type, + const RegType& long_hi_type, + const RegType& int_type) + 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); + } + } + + /* + * Verify types for a binary "2addr" operation. "src_type1"/"src_type2" + * 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, + 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 (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()); + return; + } + } + work_line_->SetRegisterType<LockOp::kClear>(vregA, dst_type); + } + } + + 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) + 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); + } + } + + void CheckBinaryOp2addrWideShift(const Instruction* inst, + const RegType& long_lo_type, + const RegType& long_hi_type, + const RegType& int_type) + 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); + } + } + + /* + * Verify types for A two-register instruction with a literal constant (e.g. "add-int/lit8"). + * "dst_type" is stored into vA, and "src_type" is verified against vB. + * + * 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, + 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 (check_boolean_op) { + DCHECK(dst_type.IsInteger()); + /* 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()); + return; + } + } + work_line_->SetRegisterType<LockOp::kClear>(vregA, dst_type); + } + } + InstructionFlags* CurrentInsnFlags() { return &GetModifiableInstructionFlags(work_insn_idx_); } @@ -2144,8 +2382,7 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g return_type.IsShort() || return_type.IsChar()) && src_type.IsInteger())); /* check the register contents */ - bool success = - work_line_->VerifyRegisterType(this, vregA, use_src ? src_type : return_type); + bool success = VerifyRegisterType(vregA, use_src ? src_type : return_type); if (!success) { AppendToLastFailMessage(StringPrintf(" return-1nr on invalid register v%d", vregA)); } @@ -2161,7 +2398,7 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g } else { /* check the register contents */ const uint32_t vregA = inst->VRegA_11x(); - bool success = work_line_->VerifyRegisterType(this, vregA, return_type); + bool success = VerifyRegisterType(vregA, return_type); if (!success) { AppendToLastFailMessage(StringPrintf(" return-wide on invalid register v%d", vregA)); } @@ -2481,33 +2718,31 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g break; case Instruction::CMPL_FLOAT: case Instruction::CMPG_FLOAT: - if (!work_line_->VerifyRegisterType(this, inst->VRegB_23x(), reg_types_.Float())) { + if (!VerifyRegisterType(inst->VRegB_23x(), reg_types_.Float())) { break; } - if (!work_line_->VerifyRegisterType(this, inst->VRegC_23x(), reg_types_.Float())) { + if (!VerifyRegisterType(inst->VRegC_23x(), reg_types_.Float())) { break; } work_line_->SetRegisterType<LockOp::kClear>(inst->VRegA_23x(), reg_types_.Integer()); break; case Instruction::CMPL_DOUBLE: case Instruction::CMPG_DOUBLE: - if (!work_line_->VerifyRegisterTypeWide(this, inst->VRegB_23x(), reg_types_.DoubleLo(), - reg_types_.DoubleHi())) { + if (!VerifyRegisterTypeWide(inst->VRegB_23x(), reg_types_.DoubleLo(), + reg_types_.DoubleHi())) { break; } - if (!work_line_->VerifyRegisterTypeWide(this, inst->VRegC_23x(), reg_types_.DoubleLo(), - reg_types_.DoubleHi())) { + if (!VerifyRegisterTypeWide(inst->VRegC_23x(), reg_types_.DoubleLo(), + reg_types_.DoubleHi())) { break; } work_line_->SetRegisterType<LockOp::kClear>(inst->VRegA_23x(), reg_types_.Integer()); break; case Instruction::CMP_LONG: - if (!work_line_->VerifyRegisterTypeWide(this, inst->VRegB_23x(), reg_types_.LongLo(), - reg_types_.LongHi())) { + if (!VerifyRegisterTypeWide(inst->VRegB_23x(), reg_types_.LongLo(), reg_types_.LongHi())) { break; } - if (!work_line_->VerifyRegisterTypeWide(this, inst->VRegC_23x(), reg_types_.LongLo(), - reg_types_.LongHi())) { + if (!VerifyRegisterTypeWide(inst->VRegC_23x(), reg_types_.LongLo(), reg_types_.LongHi())) { break; } work_line_->SetRegisterType<LockOp::kClear>(inst->VRegA_23x(), reg_types_.Integer()); @@ -2536,7 +2771,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 */ - work_line_->VerifyRegisterType(this, inst->VRegA_31t(), reg_types_.Integer()); + VerifyRegisterType(inst->VRegA_31t(), reg_types_.Integer()); break; case Instruction::FILL_ARRAY_DATA: { @@ -3086,74 +3321,69 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g } case Instruction::NEG_INT: case Instruction::NOT_INT: - work_line_->CheckUnaryOp(this, inst, reg_types_.Integer(), reg_types_.Integer()); + CheckUnaryOp(inst, reg_types_.Integer(), reg_types_.Integer()); break; case Instruction::NEG_LONG: case Instruction::NOT_LONG: - work_line_->CheckUnaryOpWide(this, inst, reg_types_.LongLo(), reg_types_.LongHi(), - reg_types_.LongLo(), reg_types_.LongHi()); + CheckUnaryOpWide(inst, reg_types_.LongLo(), reg_types_.LongHi(), + reg_types_.LongLo(), reg_types_.LongHi()); break; case Instruction::NEG_FLOAT: - work_line_->CheckUnaryOp(this, inst, reg_types_.Float(), reg_types_.Float()); + CheckUnaryOp(inst, reg_types_.Float(), reg_types_.Float()); break; case Instruction::NEG_DOUBLE: - work_line_->CheckUnaryOpWide(this, inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(), - reg_types_.DoubleLo(), reg_types_.DoubleHi()); + CheckUnaryOpWide(inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(), + reg_types_.DoubleLo(), reg_types_.DoubleHi()); break; case Instruction::INT_TO_LONG: - work_line_->CheckUnaryOpToWide(this, inst, reg_types_.LongLo(), reg_types_.LongHi(), - reg_types_.Integer()); + CheckUnaryOpToWide(inst, reg_types_.LongLo(), reg_types_.LongHi(), reg_types_.Integer()); break; case Instruction::INT_TO_FLOAT: - work_line_->CheckUnaryOp(this, inst, reg_types_.Float(), reg_types_.Integer()); + CheckUnaryOp(inst, reg_types_.Float(), reg_types_.Integer()); break; case Instruction::INT_TO_DOUBLE: - work_line_->CheckUnaryOpToWide(this, inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(), - reg_types_.Integer()); + CheckUnaryOpToWide(inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(), + reg_types_.Integer()); break; case Instruction::LONG_TO_INT: - work_line_->CheckUnaryOpFromWide(this, inst, reg_types_.Integer(), - reg_types_.LongLo(), reg_types_.LongHi()); + CheckUnaryOpFromWide(inst, reg_types_.Integer(), reg_types_.LongLo(), reg_types_.LongHi()); break; case Instruction::LONG_TO_FLOAT: - work_line_->CheckUnaryOpFromWide(this, inst, reg_types_.Float(), - reg_types_.LongLo(), reg_types_.LongHi()); + CheckUnaryOpFromWide(inst, reg_types_.Float(), reg_types_.LongLo(), reg_types_.LongHi()); break; case Instruction::LONG_TO_DOUBLE: - work_line_->CheckUnaryOpWide(this, inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(), - reg_types_.LongLo(), reg_types_.LongHi()); + CheckUnaryOpWide(inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(), + reg_types_.LongLo(), reg_types_.LongHi()); break; case Instruction::FLOAT_TO_INT: - work_line_->CheckUnaryOp(this, inst, reg_types_.Integer(), reg_types_.Float()); + CheckUnaryOp(inst, reg_types_.Integer(), reg_types_.Float()); break; case Instruction::FLOAT_TO_LONG: - work_line_->CheckUnaryOpToWide(this, inst, reg_types_.LongLo(), reg_types_.LongHi(), - reg_types_.Float()); + CheckUnaryOpToWide(inst, reg_types_.LongLo(), reg_types_.LongHi(), reg_types_.Float()); break; case Instruction::FLOAT_TO_DOUBLE: - work_line_->CheckUnaryOpToWide(this, inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(), - reg_types_.Float()); + CheckUnaryOpToWide(inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(), reg_types_.Float()); break; case Instruction::DOUBLE_TO_INT: - work_line_->CheckUnaryOpFromWide(this, inst, reg_types_.Integer(), - reg_types_.DoubleLo(), reg_types_.DoubleHi()); + CheckUnaryOpFromWide(inst, reg_types_.Integer(), + reg_types_.DoubleLo(), reg_types_.DoubleHi()); break; case Instruction::DOUBLE_TO_LONG: - work_line_->CheckUnaryOpWide(this, inst, reg_types_.LongLo(), reg_types_.LongHi(), - reg_types_.DoubleLo(), reg_types_.DoubleHi()); + CheckUnaryOpWide(inst, reg_types_.LongLo(), reg_types_.LongHi(), + reg_types_.DoubleLo(), reg_types_.DoubleHi()); break; case Instruction::DOUBLE_TO_FLOAT: - work_line_->CheckUnaryOpFromWide(this, inst, reg_types_.Float(), - reg_types_.DoubleLo(), reg_types_.DoubleHi()); + CheckUnaryOpFromWide(inst, reg_types_.Float(), + reg_types_.DoubleLo(), reg_types_.DoubleHi()); break; case Instruction::INT_TO_BYTE: - work_line_->CheckUnaryOp(this, inst, reg_types_.Byte(), reg_types_.Integer()); + CheckUnaryOp(inst, reg_types_.Byte(), reg_types_.Integer()); break; case Instruction::INT_TO_CHAR: - work_line_->CheckUnaryOp(this, inst, reg_types_.Char(), reg_types_.Integer()); + CheckUnaryOp(inst, reg_types_.Char(), reg_types_.Integer()); break; case Instruction::INT_TO_SHORT: - work_line_->CheckUnaryOp(this, inst, reg_types_.Short(), reg_types_.Integer()); + CheckUnaryOp(inst, reg_types_.Short(), reg_types_.Integer()); break; case Instruction::ADD_INT: @@ -3164,14 +3394,12 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g case Instruction::SHL_INT: case Instruction::SHR_INT: case Instruction::USHR_INT: - work_line_->CheckBinaryOp(this, inst, reg_types_.Integer(), reg_types_.Integer(), - reg_types_.Integer(), false); + CheckBinaryOp(inst, reg_types_.Integer(), reg_types_.Integer(), reg_types_.Integer(), false); break; case Instruction::AND_INT: case Instruction::OR_INT: case Instruction::XOR_INT: - work_line_->CheckBinaryOp(this, inst, reg_types_.Integer(), reg_types_.Integer(), - reg_types_.Integer(), true); + CheckBinaryOp(inst, reg_types_.Integer(), reg_types_.Integer(), reg_types_.Integer(), true); break; case Instruction::ADD_LONG: case Instruction::SUB_LONG: @@ -3181,33 +3409,31 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g case Instruction::AND_LONG: case Instruction::OR_LONG: case Instruction::XOR_LONG: - work_line_->CheckBinaryOpWide(this, inst, reg_types_.LongLo(), reg_types_.LongHi(), - reg_types_.LongLo(), reg_types_.LongHi(), - reg_types_.LongLo(), reg_types_.LongHi()); + CheckBinaryOpWide(inst, reg_types_.LongLo(), reg_types_.LongHi(), + reg_types_.LongLo(), reg_types_.LongHi(), + reg_types_.LongLo(), reg_types_.LongHi()); break; case Instruction::SHL_LONG: case Instruction::SHR_LONG: case Instruction::USHR_LONG: /* shift distance is Int, making these different from other binary operations */ - work_line_->CheckBinaryOpWideShift(this, inst, reg_types_.LongLo(), reg_types_.LongHi(), - reg_types_.Integer()); + CheckBinaryOpWideShift(inst, reg_types_.LongLo(), reg_types_.LongHi(), reg_types_.Integer()); break; case Instruction::ADD_FLOAT: case Instruction::SUB_FLOAT: case Instruction::MUL_FLOAT: case Instruction::DIV_FLOAT: case Instruction::REM_FLOAT: - work_line_->CheckBinaryOp(this, inst, reg_types_.Float(), reg_types_.Float(), - reg_types_.Float(), false); + CheckBinaryOp(inst, reg_types_.Float(), reg_types_.Float(), reg_types_.Float(), false); break; case Instruction::ADD_DOUBLE: case Instruction::SUB_DOUBLE: case Instruction::MUL_DOUBLE: case Instruction::DIV_DOUBLE: case Instruction::REM_DOUBLE: - work_line_->CheckBinaryOpWide(this, inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(), - reg_types_.DoubleLo(), reg_types_.DoubleHi(), - reg_types_.DoubleLo(), reg_types_.DoubleHi()); + CheckBinaryOpWide(inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(), + reg_types_.DoubleLo(), reg_types_.DoubleHi(), + reg_types_.DoubleLo(), reg_types_.DoubleHi()); break; case Instruction::ADD_INT_2ADDR: case Instruction::SUB_INT_2ADDR: @@ -3216,18 +3442,18 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g case Instruction::SHL_INT_2ADDR: case Instruction::SHR_INT_2ADDR: case Instruction::USHR_INT_2ADDR: - work_line_->CheckBinaryOp2addr(this, inst, reg_types_.Integer(), reg_types_.Integer(), - reg_types_.Integer(), false); + CheckBinaryOp2addr( + inst, reg_types_.Integer(), reg_types_.Integer(), reg_types_.Integer(), false); break; case Instruction::AND_INT_2ADDR: case Instruction::OR_INT_2ADDR: case Instruction::XOR_INT_2ADDR: - work_line_->CheckBinaryOp2addr(this, inst, reg_types_.Integer(), reg_types_.Integer(), - reg_types_.Integer(), true); + CheckBinaryOp2addr( + inst, reg_types_.Integer(), reg_types_.Integer(), reg_types_.Integer(), true); break; case Instruction::DIV_INT_2ADDR: - work_line_->CheckBinaryOp2addr(this, inst, reg_types_.Integer(), reg_types_.Integer(), - reg_types_.Integer(), false); + CheckBinaryOp2addr( + inst, reg_types_.Integer(), reg_types_.Integer(), reg_types_.Integer(), false); break; case Instruction::ADD_LONG_2ADDR: case Instruction::SUB_LONG_2ADDR: @@ -3237,46 +3463,43 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g case Instruction::AND_LONG_2ADDR: case Instruction::OR_LONG_2ADDR: case Instruction::XOR_LONG_2ADDR: - work_line_->CheckBinaryOp2addrWide(this, inst, reg_types_.LongLo(), reg_types_.LongHi(), - reg_types_.LongLo(), reg_types_.LongHi(), - reg_types_.LongLo(), reg_types_.LongHi()); + CheckBinaryOp2addrWide(inst, reg_types_.LongLo(), reg_types_.LongHi(), + reg_types_.LongLo(), reg_types_.LongHi(), + reg_types_.LongLo(), reg_types_.LongHi()); break; case Instruction::SHL_LONG_2ADDR: case Instruction::SHR_LONG_2ADDR: case Instruction::USHR_LONG_2ADDR: - work_line_->CheckBinaryOp2addrWideShift(this, inst, reg_types_.LongLo(), reg_types_.LongHi(), - reg_types_.Integer()); + CheckBinaryOp2addrWideShift( + inst, reg_types_.LongLo(), reg_types_.LongHi(), reg_types_.Integer()); 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: - work_line_->CheckBinaryOp2addr(this, inst, reg_types_.Float(), reg_types_.Float(), - reg_types_.Float(), false); + CheckBinaryOp2addr(inst, reg_types_.Float(), reg_types_.Float(), reg_types_.Float(), 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: - work_line_->CheckBinaryOp2addrWide(this, inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(), - reg_types_.DoubleLo(), reg_types_.DoubleHi(), - reg_types_.DoubleLo(), reg_types_.DoubleHi()); + CheckBinaryOp2addrWide(inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(), + reg_types_.DoubleLo(), reg_types_.DoubleHi(), + reg_types_.DoubleLo(), reg_types_.DoubleHi()); 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: - work_line_->CheckLiteralOp(this, inst, reg_types_.Integer(), reg_types_.Integer(), false, - true); + CheckLiteralOp(inst, reg_types_.Integer(), reg_types_.Integer(), false, true); break; case Instruction::AND_INT_LIT16: case Instruction::OR_INT_LIT16: case Instruction::XOR_INT_LIT16: - work_line_->CheckLiteralOp(this, inst, reg_types_.Integer(), reg_types_.Integer(), true, - true); + CheckLiteralOp(inst, reg_types_.Integer(), reg_types_.Integer(), true, true); break; case Instruction::ADD_INT_LIT8: case Instruction::RSUB_INT_LIT8: @@ -3286,14 +3509,12 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g case Instruction::SHL_INT_LIT8: case Instruction::SHR_INT_LIT8: case Instruction::USHR_INT_LIT8: - work_line_->CheckLiteralOp(this, inst, reg_types_.Integer(), reg_types_.Integer(), false, - false); + CheckLiteralOp(inst, reg_types_.Integer(), reg_types_.Integer(), false, false); break; case Instruction::AND_INT_LIT8: case Instruction::OR_INT_LIT8: case Instruction::XOR_INT_LIT8: - work_line_->CheckLiteralOp(this, inst, reg_types_.Integer(), reg_types_.Integer(), true, - false); + CheckLiteralOp(inst, reg_types_.Integer(), reg_types_.Integer(), true, false); break; /* These should never appear during verification. */ @@ -3947,7 +4168,7 @@ ArtMethod* MethodVerifier<kVerifierDebug>::VerifyInvocationArgsFromIterator( return nullptr; } } else { - if (!work_line_->VerifyRegisterType(this, get_reg, reg_type)) { + if (!VerifyRegisterType(get_reg, reg_type)) { // Continue on soft failures. We need to find possible hard failures to avoid problems in // the compiler. if (flags_.have_pending_hard_failure_) { @@ -4247,7 +4468,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 */ - work_line_->VerifyRegisterType(this, inst->VRegB_22c(), reg_types_.Integer()); + VerifyRegisterType(inst->VRegB_22c(), reg_types_.Integer()); /* set register type to array class */ work_line_->SetRegisterType<LockOp::kClear>(inst->VRegA_22c(), res_type); } else { @@ -4262,7 +4483,7 @@ void MethodVerifier<kVerifierDebug>::VerifyNewArray(const Instruction* inst, } for (size_t ui = 0; ui < arg_count; ui++) { uint32_t get_reg = is_range ? inst->VRegC_3rc() + ui : arg[ui]; - work_line_->VerifyRegisterType(this, get_reg, expected_type); + VerifyRegisterType(get_reg, expected_type); if (flags_.have_pending_hard_failure_) { // Don't continue on hard failures. return; @@ -4426,7 +4647,7 @@ void MethodVerifier<kVerifierDebug>::VerifyAPut(const Instruction* inst, } } } - work_line_->VerifyRegisterType(this, inst->VRegA_23x(), *modified_reg_type); + VerifyRegisterType(inst->VRegA_23x(), *modified_reg_type); } else if (!array_type.IsArrayTypes()) { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "not array type " << array_type << " with aput"; } else if (array_type.IsUnresolvedMergedReference()) { @@ -4451,7 +4672,7 @@ void MethodVerifier<kVerifierDebug>::VerifyAPut(const Instruction* inst, // The instruction agrees with the type of array, confirm the value to be stored does too // Note: we use the instruction type (rather than the component type) for aput-object as // incompatible classes will be caught at runtime as an array store exception - work_line_->VerifyRegisterType(this, vregA, insn_type); + VerifyRegisterType(vregA, insn_type); } } } @@ -4692,7 +4913,7 @@ void MethodVerifier<kVerifierDebug>::VerifyISFieldAccess(const Instruction* inst << "' in put-object"; return; } - work_line_->VerifyRegisterType(this, vregA, field_type); + VerifyRegisterType(vregA, field_type); } } else if (kAccType == FieldAccessType::kAccGet) { // sget or iget. diff --git a/runtime/verifier/register_line-inl.h b/runtime/verifier/register_line-inl.h index c49649021e..ad4999b205 100644 --- a/runtime/verifier/register_line-inl.h +++ b/runtime/verifier/register_line-inl.h @@ -139,42 +139,6 @@ inline bool RegisterLine::NeedsAllocationDexPc(const RegType& reg_type) { return reg_type.IsUninitializedReference() || reg_type.IsUnresolvedUninitializedReference(); } -inline bool RegisterLine::VerifyRegisterType(MethodVerifier* verifier, uint32_t vsrc, - const RegType& check_type) { - // Verify the src register type against the check type refining the type of the register - const RegType& src_type = GetRegisterType(verifier, vsrc); - if (UNLIKELY(!check_type.IsAssignableFrom(src_type, verifier))) { - enum VerifyError fail_type; - if (!check_type.IsNonZeroReferenceTypes() || !src_type.IsNonZeroReferenceTypes()) { - // Hard fail if one of the types is primitive, since they are concretely known. - fail_type = VERIFY_ERROR_BAD_CLASS_HARD; - } else if (check_type.IsUninitializedTypes() || src_type.IsUninitializedTypes()) { - // Hard fail for uninitialized types, which don't match anything but themselves. - fail_type = VERIFY_ERROR_BAD_CLASS_HARD; - } else if (check_type.IsUnresolvedTypes() || src_type.IsUnresolvedTypes()) { - fail_type = VERIFY_ERROR_UNRESOLVED_TYPE_CHECK; - } else { - fail_type = VERIFY_ERROR_BAD_CLASS_HARD; - } - verifier->Fail(fail_type) << "register v" << vsrc << " has type " - << src_type << " but expected " << check_type; - return false; - } - if (check_type.IsLowHalf()) { - const RegType& src_type_h = GetRegisterType(verifier, vsrc + 1); - if (UNLIKELY(!src_type.CheckWidePair(src_type_h))) { - verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "wide register v" << vsrc << " has type " - << src_type << "/" << src_type_h; - return false; - } - } - // The register at vsrc has a defined type, we know the lower-upper-bound, but this is less - // precise than the subtype in vsrc so leave it for reference types. For primitive types - // if they are a defined type then they are as precise as we can get, however, for constant - // types we may wish to refine them. Unfortunately constant propagation has rendered this useless. - return true; -} - inline void RegisterLine::DCheckUniqueNewInstanceDexPc(MethodVerifier* verifier, uint32_t dex_pc) { if (kIsDebugBuild && allocation_dex_pcs_ != nullptr) { // Note: We do not clear the `allocation_dex_pcs_` entries when copying data from diff --git a/runtime/verifier/register_line.cc b/runtime/verifier/register_line.cc index db4dbb06e4..6c4227cf8e 100644 --- a/runtime/verifier/register_line.cc +++ b/runtime/verifier/register_line.cc @@ -46,30 +46,6 @@ bool RegisterLine::CheckConstructorReturn(MethodVerifier* verifier) const { return this_initialized_; } -bool RegisterLine::VerifyRegisterTypeWide(MethodVerifier* verifier, uint32_t vsrc, - const RegType& check_type1, - const RegType& check_type2) { - DCHECK(check_type1.CheckWidePair(check_type2)); - // Verify the src register type against the check type refining the type of the register - const RegType& src_type = GetRegisterType(verifier, vsrc); - if (!check_type1.IsAssignableFrom(src_type, verifier)) { - verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "register v" << vsrc << " has type " << src_type - << " but expected " << check_type1; - return false; - } - const RegType& src_type_h = GetRegisterType(verifier, vsrc + 1); - if (!src_type.CheckWidePair(src_type_h)) { - verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "wide register v" << vsrc << " has type " - << src_type << "/" << src_type_h; - return false; - } - // The register at vsrc has a defined type, we know the lower-upper-bound, but this is less - // precise than the subtype in vsrc so leave it for reference types. For primitive types - // if they are a defined type then they are as precise as we can get, however, for constant - // types we may wish to refine them. Unfortunately constant propagation has rendered this useless. - return true; -} - void RegisterLine::CopyFromLine(const RegisterLine* src) { DCHECK_EQ(num_regs_, src->num_regs_); memcpy(&line_, &src->line_, num_regs_ * sizeof(uint16_t)); @@ -189,137 +165,6 @@ void RegisterLine::CopyResultRegister2(MethodVerifier* verifier, uint32_t vdst) } } -void RegisterLine::CheckUnaryOp(MethodVerifier* verifier, const Instruction* inst, - const RegType& dst_type, const RegType& src_type) { - if (VerifyRegisterType(verifier, inst->VRegB_12x(), src_type)) { - SetRegisterType<LockOp::kClear>(inst->VRegA_12x(), dst_type); - } -} - -void RegisterLine::CheckUnaryOpWide(MethodVerifier* verifier, const Instruction* inst, - const RegType& dst_type1, const RegType& dst_type2, - const RegType& src_type1, const RegType& src_type2) { - if (VerifyRegisterTypeWide(verifier, inst->VRegB_12x(), src_type1, src_type2)) { - SetRegisterTypeWide(inst->VRegA_12x(), dst_type1, dst_type2); - } -} - -void RegisterLine::CheckUnaryOpToWide(MethodVerifier* verifier, const Instruction* inst, - const RegType& dst_type1, const RegType& dst_type2, - const RegType& src_type) { - if (VerifyRegisterType(verifier, inst->VRegB_12x(), src_type)) { - SetRegisterTypeWide(inst->VRegA_12x(), dst_type1, dst_type2); - } -} - -void RegisterLine::CheckUnaryOpFromWide(MethodVerifier* verifier, const Instruction* inst, - const RegType& dst_type, - const RegType& src_type1, const RegType& src_type2) { - if (VerifyRegisterTypeWide(verifier, inst->VRegB_12x(), src_type1, src_type2)) { - SetRegisterType<LockOp::kClear>(inst->VRegA_12x(), dst_type); - } -} - -void RegisterLine::CheckBinaryOp(MethodVerifier* verifier, const Instruction* inst, - const RegType& dst_type, - const RegType& src_type1, const RegType& src_type2, - bool check_boolean_op) { - const uint32_t vregB = inst->VRegB_23x(); - const uint32_t vregC = inst->VRegC_23x(); - if (VerifyRegisterType(verifier, vregB, src_type1) && - VerifyRegisterType(verifier, vregC, src_type2)) { - if (check_boolean_op) { - DCHECK(dst_type.IsInteger()); - if (GetRegisterType(verifier, vregB).IsBooleanTypes() && - GetRegisterType(verifier, vregC).IsBooleanTypes()) { - SetRegisterType<LockOp::kClear>(inst->VRegA_23x(), verifier->GetRegTypeCache()->Boolean()); - return; - } - } - SetRegisterType<LockOp::kClear>(inst->VRegA_23x(), dst_type); - } -} - -void RegisterLine::CheckBinaryOpWide(MethodVerifier* verifier, 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) { - if (VerifyRegisterTypeWide(verifier, inst->VRegB_23x(), src_type1_1, src_type1_2) && - VerifyRegisterTypeWide(verifier, inst->VRegC_23x(), src_type2_1, src_type2_2)) { - SetRegisterTypeWide(inst->VRegA_23x(), dst_type1, dst_type2); - } -} - -void RegisterLine::CheckBinaryOpWideShift(MethodVerifier* verifier, const Instruction* inst, - const RegType& long_lo_type, const RegType& long_hi_type, - const RegType& int_type) { - if (VerifyRegisterTypeWide(verifier, inst->VRegB_23x(), long_lo_type, long_hi_type) && - VerifyRegisterType(verifier, inst->VRegC_23x(), int_type)) { - SetRegisterTypeWide(inst->VRegA_23x(), long_lo_type, long_hi_type); - } -} - -void RegisterLine::CheckBinaryOp2addr(MethodVerifier* verifier, const Instruction* inst, - const RegType& dst_type, const RegType& src_type1, - const RegType& src_type2, bool check_boolean_op) { - const uint32_t vregA = inst->VRegA_12x(); - const uint32_t vregB = inst->VRegB_12x(); - if (VerifyRegisterType(verifier, vregA, src_type1) && - VerifyRegisterType(verifier, vregB, src_type2)) { - if (check_boolean_op) { - DCHECK(dst_type.IsInteger()); - if (GetRegisterType(verifier, vregA).IsBooleanTypes() && - GetRegisterType(verifier, vregB).IsBooleanTypes()) { - SetRegisterType<LockOp::kClear>(vregA, verifier->GetRegTypeCache()->Boolean()); - return; - } - } - SetRegisterType<LockOp::kClear>(vregA, dst_type); - } -} - -void RegisterLine::CheckBinaryOp2addrWide(MethodVerifier* verifier, 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) { - const uint32_t vregA = inst->VRegA_12x(); - const uint32_t vregB = inst->VRegB_12x(); - if (VerifyRegisterTypeWide(verifier, vregA, src_type1_1, src_type1_2) && - VerifyRegisterTypeWide(verifier, vregB, src_type2_1, src_type2_2)) { - SetRegisterTypeWide(vregA, dst_type1, dst_type2); - } -} - -void RegisterLine::CheckBinaryOp2addrWideShift(MethodVerifier* verifier, const Instruction* inst, - const RegType& long_lo_type, const RegType& long_hi_type, - const RegType& int_type) { - const uint32_t vregA = inst->VRegA_12x(); - const uint32_t vregB = inst->VRegB_12x(); - if (VerifyRegisterTypeWide(verifier, vregA, long_lo_type, long_hi_type) && - VerifyRegisterType(verifier, vregB, int_type)) { - SetRegisterTypeWide(vregA, long_lo_type, long_hi_type); - } -} - -void RegisterLine::CheckLiteralOp(MethodVerifier* verifier, const Instruction* inst, - const RegType& dst_type, const RegType& src_type, - bool check_boolean_op, bool is_lit16) { - 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(verifier, vregB, src_type)) { - if (check_boolean_op) { - DCHECK(dst_type.IsInteger()); - /* check vB with the call, then check the constant manually */ - const uint32_t val = is_lit16 ? inst->VRegC_22s() : inst->VRegC_22b(); - if (GetRegisterType(verifier, vregB).IsBooleanTypes() && (val == 0 || val == 1)) { - SetRegisterType<LockOp::kClear>(vregA, verifier->GetRegTypeCache()->Boolean()); - return; - } - } - SetRegisterType<LockOp::kClear>(vregA, dst_type); - } -} - static constexpr uint32_t kVirtualNullRegister = std::numeric_limits<uint32_t>::max(); void RegisterLine::PushMonitor(MethodVerifier* verifier, uint32_t reg_idx, int32_t insn_idx) { diff --git a/runtime/verifier/register_line.h b/runtime/verifier/register_line.h index 58f4a6a6fb..f51b107e28 100644 --- a/runtime/verifier/register_line.h +++ b/runtime/verifier/register_line.h @@ -138,17 +138,6 @@ class RegisterLine { // Get the type of register vsrc. const RegType& GetRegisterType(MethodVerifier* verifier, uint32_t vsrc) const; - ALWAYS_INLINE bool VerifyRegisterType(MethodVerifier* verifier, - uint32_t vsrc, - const RegType& check_type) - REQUIRES_SHARED(Locks::mutator_lock_); - - bool VerifyRegisterTypeWide(MethodVerifier* verifier, - uint32_t vsrc, - const RegType& check_type1, - const RegType& check_type2) - REQUIRES_SHARED(Locks::mutator_lock_); - void CopyFromLine(const RegisterLine* src); std::string Dump(MethodVerifier* verifier) const REQUIRES_SHARED(Locks::mutator_lock_); @@ -216,111 +205,6 @@ class RegisterLine { // Return how many bytes of memory a register line uses. ALWAYS_INLINE static size_t ComputeSize(size_t num_regs); - /* - * 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(MethodVerifier* verifier, - const Instruction* inst, - const RegType& dst_type, - const RegType& src_type) - REQUIRES_SHARED(Locks::mutator_lock_); - - void CheckUnaryOpWide(MethodVerifier* verifier, - const Instruction* inst, - const RegType& dst_type1, - const RegType& dst_type2, - const RegType& src_type1, - const RegType& src_type2) - REQUIRES_SHARED(Locks::mutator_lock_); - - void CheckUnaryOpToWide(MethodVerifier* verifier, - const Instruction* inst, - const RegType& dst_type1, - const RegType& dst_type2, - const RegType& src_type) - REQUIRES_SHARED(Locks::mutator_lock_); - - void CheckUnaryOpFromWide(MethodVerifier* verifier, - const Instruction* inst, - const RegType& dst_type, - const RegType& src_type1, - const RegType& src_type2) - REQUIRES_SHARED(Locks::mutator_lock_); - - /* - * Verify types for a simple three-register instruction (e.g. "add-int"). - * "dst_type" is stored into vA, and "src_type1"/"src_type2" are verified - * against vB/vC. - */ - void CheckBinaryOp(MethodVerifier* verifier, - const Instruction* inst, - const RegType& dst_type, - const RegType& src_type1, - const RegType& src_type2, - bool check_boolean_op) - REQUIRES_SHARED(Locks::mutator_lock_); - - void CheckBinaryOpWide(MethodVerifier* verifier, - 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) - REQUIRES_SHARED(Locks::mutator_lock_); - - void CheckBinaryOpWideShift(MethodVerifier* verifier, - const Instruction* inst, - const RegType& long_lo_type, - const RegType& long_hi_type, - const RegType& int_type) - REQUIRES_SHARED(Locks::mutator_lock_); - - /* - * Verify types for a binary "2addr" operation. "src_type1"/"src_type2" - * are verified against vA/vB, then "dst_type" is stored into vA. - */ - void CheckBinaryOp2addr(MethodVerifier* verifier, - const Instruction* inst, - const RegType& dst_type, - const RegType& src_type1, - const RegType& src_type2, - bool check_boolean_op) - REQUIRES_SHARED(Locks::mutator_lock_); - - void CheckBinaryOp2addrWide(MethodVerifier* verifier, - 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) - REQUIRES_SHARED(Locks::mutator_lock_); - - void CheckBinaryOp2addrWideShift(MethodVerifier* verifier, - const Instruction* inst, - const RegType& long_lo_type, - const RegType& long_hi_type, - const RegType& int_type) - REQUIRES_SHARED(Locks::mutator_lock_); - - /* - * Verify types for A two-register instruction with a literal constant (e.g. "add-int/lit8"). - * "dst_type" is stored into vA, and "src_type" is verified against vB. - * - * If "check_boolean_op" is set, we use the constant value in vC. - */ - void CheckLiteralOp(MethodVerifier* verifier, - const Instruction* inst, - const RegType& dst_type, - const RegType& src_type, - bool check_boolean_op, - bool is_lit16) - REQUIRES_SHARED(Locks::mutator_lock_); - // Verify/push monitor onto the monitor stack, locking the value in reg_idx at location insn_idx. void PushMonitor(MethodVerifier* verifier, uint32_t reg_idx, int32_t insn_idx) REQUIRES_SHARED(Locks::mutator_lock_); |