diff options
author | 2025-02-17 14:18:17 +0000 | |
---|---|---|
committer | 2025-02-18 00:43:56 -0800 | |
commit | b03ab575b9acb3fd73861d5d0a7719dcd0a6322a (patch) | |
tree | d7bcaa6e6c247d24e82e5c7e0456e9c82bc5f1b7 | |
parent | 143d99f3efa04935a3b290e66274178ed38519b1 (diff) |
Only locking error and runtime throws should retrigger verification.
This ensures the stability of the vdex file.
Test: 412-new-array
Change-Id: I73a6be0a46b6eb184ea127de720bfaf7104f3777
-rw-r--r-- | compiler/optimizing/instruction_builder.cc | 2 | ||||
-rw-r--r-- | runtime/verifier/method_verifier.cc | 25 | ||||
-rw-r--r-- | runtime/verifier/verifier_compiler_binding.h | 19 |
3 files changed, 13 insertions, 33 deletions
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc index 74880463c3..8cc79c2424 100644 --- a/compiler/optimizing/instruction_builder.cc +++ b/compiler/optimizing/instruction_builder.cc @@ -2554,8 +2554,6 @@ bool HInstructionBuilder::BuildFilledNewArray(uint32_t dex_pc, char primitive = descriptor[1]; if (primitive != 'I' && primitive != 'L' && primitive != '[') { DCHECK(primitive != 'J' && primitive != 'D'); // Rejected by the verifier. - // FIXME: Why do we JIT compile a method with `VERIFY_ERROR_FILLED_NEW_ARRAY` when - // `CanCompilerHandleVerificationFailure(VERIFY_ERROR_FILLED_NEW_ARRAY)` returns false? MaybeRecordStat(compilation_stats_, MethodCompilationStat::kNotCompiledMalformedOpcode); return false; } diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index fce0b2b374..91e46365cf 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -65,6 +65,7 @@ #include "stack.h" #include "vdex_file.h" #include "verifier/method_verifier.h" +#include "verifier_compiler_binding.h" #include "verifier_deps.h" namespace art HIDDEN { @@ -5587,25 +5588,6 @@ MethodVerifier::FailureData MethodVerifier::VerifyMethod(Thread* self, } } -// Return whether the runtime knows how to execute a method without needing to -// re-verify it at runtime (and therefore save on first use of the class). -// The AOT/JIT compiled code is not affected. -static inline bool CanRuntimeHandleVerificationFailure(uint32_t encountered_failure_types) { - constexpr uint32_t unresolved_mask = - verifier::VerifyError::VERIFY_ERROR_UNRESOLVED_TYPE_CHECK | - verifier::VerifyError::VERIFY_ERROR_NO_CLASS | - verifier::VerifyError::VERIFY_ERROR_CLASS_CHANGE | - verifier::VerifyError::VERIFY_ERROR_INSTANTIATION | - verifier::VerifyError::VERIFY_ERROR_FILLED_NEW_ARRAY | - verifier::VerifyError::VERIFY_ERROR_ACCESS_CLASS | - verifier::VerifyError::VERIFY_ERROR_ACCESS_FIELD | - verifier::VerifyError::VERIFY_ERROR_NO_METHOD | - verifier::VerifyError::VERIFY_ERROR_NO_FIELD | - verifier::VerifyError::VERIFY_ERROR_ACCESS_METHOD | - verifier::VerifyError::VERIFY_ERROR_RUNTIME_THROW; - return (encountered_failure_types & (~unresolved_mask)) == 0; -} - template <bool kVerifierDebug> MethodVerifier::FailureData MethodVerifier::VerifyMethod(Thread* self, ArenaPool* arena_pool, @@ -5650,13 +5632,16 @@ MethodVerifier::FailureData MethodVerifier::VerifyMethod(Thread* self, LOG(INFO) << verifier.InfoMessages().view(); verifier.Dump(LOG_STREAM(INFO)); } - if (CanRuntimeHandleVerificationFailure(verifier.encountered_failure_types_)) { + if (CanCompilerHandleVerificationFailure(verifier.encountered_failure_types_)) { if (verifier.encountered_failure_types_ & VERIFY_ERROR_UNRESOLVED_TYPE_CHECK) { result.kind = FailureKind::kTypeChecksFailure; } else { result.kind = FailureKind::kAccessChecksFailure; } } else { + // If the compiler cannot handle the failure, force a soft failure to + // ensure the class will be re-verified at runtime and the method marked + // as not compilable. result.kind = FailureKind::kSoftFailure; } } diff --git a/runtime/verifier/verifier_compiler_binding.h b/runtime/verifier/verifier_compiler_binding.h index dd96a75975..d492751e64 100644 --- a/runtime/verifier/verifier_compiler_binding.h +++ b/runtime/verifier/verifier_compiler_binding.h @@ -27,17 +27,14 @@ namespace verifier { ALWAYS_INLINE static inline bool CanCompilerHandleVerificationFailure(uint32_t encountered_failure_types) { - constexpr uint32_t unresolved_mask = - verifier::VerifyError::VERIFY_ERROR_NO_CLASS | - verifier::VerifyError::VERIFY_ERROR_UNRESOLVED_TYPE_CHECK | - verifier::VerifyError::VERIFY_ERROR_CLASS_CHANGE | - verifier::VerifyError::VERIFY_ERROR_NO_METHOD | - verifier::VerifyError::VERIFY_ERROR_NO_FIELD | - verifier::VerifyError::VERIFY_ERROR_INSTANTIATION | - verifier::VerifyError::VERIFY_ERROR_ACCESS_CLASS | - verifier::VerifyError::VERIFY_ERROR_ACCESS_FIELD | - verifier::VerifyError::VERIFY_ERROR_ACCESS_METHOD; - return (encountered_failure_types & (~unresolved_mask)) == 0; + // These are and should remain the only two reasons a verified method cannot + // be compiled. The vdex file will mark classes where those methods are defined + // as verify-at-runtime and we should ideally not break that format in adding + // a new kind of failure. + constexpr uint32_t errors_needing_reverification = + verifier::VerifyError::VERIFY_ERROR_RUNTIME_THROW | + verifier::VerifyError::VERIFY_ERROR_LOCKING; + return (encountered_failure_types & errors_needing_reverification) == 0; } } // namespace verifier |