summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Nicolas Geoffray <ngeoffray@google.com> 2025-02-17 14:18:17 +0000
committer Nicolas Geoffray <ngeoffray@google.com> 2025-02-18 00:43:56 -0800
commitb03ab575b9acb3fd73861d5d0a7719dcd0a6322a (patch)
treed7bcaa6e6c247d24e82e5c7e0456e9c82bc5f1b7
parent143d99f3efa04935a3b290e66274178ed38519b1 (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.cc2
-rw-r--r--runtime/verifier/method_verifier.cc25
-rw-r--r--runtime/verifier/verifier_compiler_binding.h19
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