diff options
-rw-r--r-- | runtime/verifier/method_verifier.cc | 52 | ||||
-rw-r--r-- | runtime/verifier/method_verifier.h | 33 |
2 files changed, 44 insertions, 41 deletions
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index 6d091b8ed6..b644dbae80 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -1059,7 +1059,7 @@ bool MethodVerifier<kVerifierDebug>::VerifyInstruction(const Instruction* inst, // the data flow analysis will fail. Fail(VERIFY_ERROR_FORCE_INTERPRETER) << "experimental instruction is not supported by verifier; skipping verification"; - have_pending_experimental_failure_ = true; + flags_.have_pending_experimental_failure_ = true; return false; } @@ -1597,7 +1597,7 @@ bool MethodVerifier<kVerifierDebug>::VerifyCodeFlow() { return false; } // We may have a runtime failure here, clear. - have_pending_runtime_throw_failure_ = false; + flags_.have_pending_runtime_throw_failure_ = false; /* Perform code flow verification. */ if (!CodeFlowVerifyMethod()) { @@ -2057,7 +2057,8 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g } else if (kIsDebugBuild) { saved_line_->FillWithGarbage(); } - DCHECK(!have_pending_runtime_throw_failure_); // Per-instruction flag, should not be set here. + // Per-instruction flag, should not be set here. + DCHECK(!flags_.have_pending_runtime_throw_failure_); bool exc_handler_unreachable = false; @@ -3457,7 +3458,7 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g */ } // end - switch (dec_insn.opcode) - if (have_pending_hard_failure_) { + if (flags_.have_pending_hard_failure_) { if (Runtime::Current()->IsAotCompiler()) { /* When AOT compiling, check that the last failure is a hard failure */ if (failures_[failures_.size() - 1] != VERIFY_ERROR_BAD_CLASS_HARD) { @@ -3474,7 +3475,7 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g /* immediate failure, reject class */ info_messages_ << "Rejecting opcode " << inst->DumpString(dex_file_); return false; - } else if (have_pending_runtime_throw_failure_) { + } else if (flags_.have_pending_runtime_throw_failure_) { LogVerifyInfo() << "Elevating opcode flags from " << opcode_flags << " to Throw"; /* checking interpreter will throw, mark following code as unreachable */ opcode_flags = Instruction::kThrow; @@ -3695,10 +3696,10 @@ bool MethodVerifier<kVerifierDebug>::CodeFlowVerifyInstruction(uint32_t* start_g DCHECK_LT(*start_guess, code_item_accessor_.InsnsSizeInCodeUnits()); DCHECK(GetInstructionFlags(*start_guess).IsOpcode()); - if (have_pending_runtime_throw_failure_) { - have_any_pending_runtime_throw_failure_ = true; + if (flags_.have_pending_runtime_throw_failure_) { + flags_.have_any_pending_runtime_throw_failure_ = true; // Reset the pending_runtime_throw flag now. - have_pending_runtime_throw_failure_ = false; + flags_.have_pending_runtime_throw_failure_ = false; } return true; @@ -4025,7 +4026,7 @@ ArtMethod* MethodVerifier<kVerifierDebug>::VerifyInvocationArgsFromIterator( if (method_type != METHOD_STATIC) { const RegType& actual_arg_type = work_line_->GetInvocationThis(this, inst); if (actual_arg_type.IsConflict()) { // GetInvocationThis failed. - CHECK(have_pending_hard_failure_); + CHECK(flags_.have_pending_hard_failure_); return nullptr; } bool is_init = false; @@ -4074,7 +4075,7 @@ ArtMethod* MethodVerifier<kVerifierDebug>::VerifyInvocationArgsFromIterator( << *res_method_class << "'"; // Continue on soft failures. We need to find possible hard failures to avoid problems in // the compiler. - if (have_pending_hard_failure_) { + if (flags_.have_pending_hard_failure_) { return nullptr; } } @@ -4117,7 +4118,7 @@ ArtMethod* MethodVerifier<kVerifierDebug>::VerifyInvocationArgsFromIterator( if (!work_line_->VerifyRegisterType(this, get_reg, reg_type)) { // Continue on soft failures. We need to find possible hard failures to avoid problems in // the compiler. - if (have_pending_hard_failure_) { + if (flags_.have_pending_hard_failure_) { return nullptr; } } else if (reg_type.IsLongOrDoubleTypes()) { @@ -4249,7 +4250,7 @@ ArtMethod* MethodVerifier<kVerifierDebug>::VerifyInvocationArgs( ArtMethod* res_method = ResolveMethodAndCheckAccess(method_idx, method_type); if (res_method == nullptr) { // error or class is unresolved // Check what we can statically. - if (!have_pending_hard_failure_) { + if (!flags_.have_pending_hard_failure_) { VerifyInvocationArgsUnresolvedMethod(inst, method_type, is_range); } return nullptr; @@ -4840,7 +4841,7 @@ void MethodVerifier<kVerifierDebug>::VerifyISFieldAccess(const Instruction* inst ? GetRegTypeCache()->FromUninitialized(object_type) : object_type; field = GetInstanceField(adjusted_type, field_idx); - if (UNLIKELY(have_pending_hard_failure_)) { + if (UNLIKELY(flags_.have_pending_hard_failure_)) { return; } if (should_adjust) { @@ -4997,7 +4998,7 @@ bool MethodVerifier<kVerifierDebug>::UpdateRegisters(uint32_t next_insn, const Instruction* ret_inst = &code_item_accessor_.InstructionAt(next_insn); AdjustReturnLine(this, ret_inst, target_line); // Directly bail if a hard failure was found. - if (have_pending_hard_failure_) { + if (flags_.have_pending_hard_failure_) { return false; } } @@ -5008,7 +5009,7 @@ bool MethodVerifier<kVerifierDebug>::UpdateRegisters(uint32_t next_insn, copy->CopyFromLine(target_line); } changed = target_line->MergeRegisters(this, merge_line); - if (have_pending_hard_failure_) { + if (flags_.have_pending_hard_failure_) { return false; } if (kVerifierDebug && changed) { @@ -5132,10 +5133,7 @@ MethodVerifier::MethodVerifier(Thread* self, dex_method_idx_(dex_method_idx), dex_file_(dex_file), code_item_accessor_(*dex_file, code_item), - have_pending_hard_failure_(false), - have_pending_runtime_throw_failure_(false), - have_pending_experimental_failure_(false), - have_any_pending_runtime_throw_failure_(false), + flags_({false, false, false, false}), encountered_failure_types_(0), can_load_classes_(can_load_classes), allow_soft_failures_(allow_soft_failures), @@ -5237,7 +5235,7 @@ MethodVerifier::FailureData MethodVerifier::VerifyMethod(Thread* self, if (verifier.Verify()) { // Verification completed, however failures may be pending that didn't cause the verification // to hard fail. - CHECK(!verifier.have_pending_hard_failure_); + CHECK(!verifier.flags_.have_pending_hard_failure_); if (code_item != nullptr && callbacks != nullptr) { // Let the interested party know that the method was verified. @@ -5284,12 +5282,12 @@ MethodVerifier::FailureData MethodVerifier::VerifyMethod(Thread* self, // Bad method data. CHECK_NE(verifier.failures_.size(), 0U); - if (UNLIKELY(verifier.have_pending_experimental_failure_)) { + if (UNLIKELY(verifier.flags_.have_pending_experimental_failure_)) { // Failed due to being forced into interpreter. This is ok because // we just want to skip verification. result.kind = FailureKind::kSoftFailure; } else { - CHECK(verifier.have_pending_hard_failure_); + CHECK(verifier.flags_.have_pending_hard_failure_); if (VLOG_IS_ON(verifier)) { log_level = std::max(HardFailLogMode::kLogVerbose, log_level); } @@ -5388,7 +5386,7 @@ MethodVerifier* MethodVerifier::CalculateVerificationInfo( VLOG(verifier) << verifier->info_messages_.str(); verifier->Dump(VLOG_STREAM(verifier)); } - if (verifier->have_pending_hard_failure_) { + if (verifier->flags_.have_pending_hard_failure_) { return nullptr; } else { return verifier.release(); @@ -5428,7 +5426,7 @@ MethodVerifier* MethodVerifier::VerifyMethodAndDump(Thread* self, vios->Stream() << verifier->info_messages_.str(); // Only dump and return if no hard failures. Otherwise the verifier may be not fully initialized // and querying any info is dangerous/can abort. - if (verifier->have_pending_hard_failure_) { + if (verifier->flags_.have_pending_hard_failure_) { delete verifier; return nullptr; } else { @@ -5542,7 +5540,7 @@ std::ostream& MethodVerifier::Fail(VerifyError error) { } else { // If we fail again at runtime, mark that this instruction would throw and force this // method to be executed using the interpreter with checks. - have_pending_runtime_throw_failure_ = true; + flags_.have_pending_runtime_throw_failure_ = true; // We need to save the work_line if the instruction wasn't throwing before. Otherwise we'll // try to merge garbage. @@ -5564,14 +5562,14 @@ std::ostream& MethodVerifier::Fail(VerifyError error) { // Indication that verification should be retried at runtime. case VERIFY_ERROR_BAD_CLASS_SOFT: if (!allow_soft_failures_) { - have_pending_hard_failure_ = true; + flags_.have_pending_hard_failure_ = true; } break; // Hard verification failures at compile time will still fail at runtime, so the class is // marked as rejected to prevent it from being compiled. case VERIFY_ERROR_BAD_CLASS_HARD: { - have_pending_hard_failure_ = true; + flags_.have_pending_hard_failure_ = true; break; } diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h index bd320ce2a2..e3d0901d3f 100644 --- a/runtime/verifier/method_verifier.h +++ b/runtime/verifier/method_verifier.h @@ -184,7 +184,7 @@ class MethodVerifier { bool HasCheckCasts() const; bool HasFailures() const; bool HasInstructionThatWillThrow() const { - return have_any_pending_runtime_throw_failure_; + return flags_.have_any_pending_runtime_throw_failure_; } virtual const RegType& ResolveCheckedClass(dex::TypeIndex class_idx) @@ -315,19 +315,24 @@ class MethodVerifier { std::vector<VerifyError> failures_; // Error messages associated with failures. std::vector<std::ostringstream*> failure_messages_; - // Is there a pending hard failure? - bool have_pending_hard_failure_; - // Is there a pending runtime throw failure? A runtime throw failure is when an instruction - // would fail at runtime throwing an exception. Such an instruction causes the following code - // to be unreachable. This is set by Fail and used to ensure we don't process unreachable - // instructions that would hard fail the verification. - // Note: this flag is reset after processing each instruction. - bool have_pending_runtime_throw_failure_; - // Is there a pending experimental failure? - bool have_pending_experimental_failure_; - - // A version of the above that is not reset and thus captures if there were *any* throw failures. - bool have_any_pending_runtime_throw_failure_; + struct { + // Is there a pending hard failure? + bool have_pending_hard_failure_ : 1; + + // Is there a pending runtime throw failure? A runtime throw failure is when an instruction + // would fail at runtime throwing an exception. Such an instruction causes the following code + // to be unreachable. This is set by Fail and used to ensure we don't process unreachable + // instructions that would hard fail the verification. + // Note: this flag is reset after processing each instruction. + bool have_pending_runtime_throw_failure_ : 1; + + // Is there a pending experimental failure? + bool have_pending_experimental_failure_ : 1; + + // A version of the above that is not reset and thus captures if there were *any* throw + // failures. + bool have_any_pending_runtime_throw_failure_ : 1; + } flags_; // Info message log use primarily for verifier diagnostics. std::ostringstream info_messages_; |