Add flag to ArtMethod to skip compilation.
To ensure even the JIT will not try to compile methods with
soft failures a runtime_throw.
bug:28293819
bug:28313047
Change-Id: Ie3fd71ded0b77de8dab1c3c825b867cb321b8873
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index 836bcfa..ff4b9a7 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -795,6 +795,11 @@
return false;
}
+ if (!method->IsCompilable()) {
+ VLOG(compiler) << "Method " << PrettyMethod(method)
+ << " has soft failures un-handled by the compiler, so it cannot be inlined";
+ }
+
if (!method->GetDeclaringClass()->IsVerified()) {
uint16_t class_def_idx = method->GetDeclaringClass()->GetDexClassDefIndex();
if (Runtime::Current()->UseJit() ||
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 3670ce2..37197af 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -769,15 +769,6 @@
return codegen.release();
}
-static bool CanHandleVerificationFailure(const VerifiedMethod* verified_method) {
- // For access errors the compiler will use the unresolved helpers (e.g. HInvokeUnresolved).
- uint32_t unresolved_mask = verifier::VerifyError::VERIFY_ERROR_NO_CLASS
- | verifier::VerifyError::VERIFY_ERROR_ACCESS_CLASS
- | verifier::VerifyError::VERIFY_ERROR_ACCESS_FIELD
- | verifier::VerifyError::VERIFY_ERROR_ACCESS_METHOD;
- return (verified_method->GetEncounteredVerificationFailures() & (~unresolved_mask)) == 0;
-}
-
CompiledMethod* OptimizingCompiler::Compile(const DexFile::CodeItem* code_item,
uint32_t access_flags,
InvokeType invoke_type,
@@ -792,7 +783,8 @@
const VerifiedMethod* verified_method = compiler_driver->GetVerifiedMethod(&dex_file, method_idx);
DCHECK(!verified_method->HasRuntimeThrow());
if (compiler_driver->IsMethodVerifiedWithoutFailures(method_idx, class_def_idx, dex_file)
- || CanHandleVerificationFailure(verified_method)) {
+ || verifier::MethodVerifier::CanCompilerHandleVerificationFailure(
+ verified_method->GetEncounteredVerificationFailures())) {
ArenaAllocator arena(Runtime::Current()->GetArenaPool());
CodeVectorAllocator code_allocator(&arena);
std::unique_ptr<CodeGenerator> codegen(
@@ -865,6 +857,7 @@
Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
method->GetDeclaringClass()->GetClassLoader()));
Handle<mirror::DexCache> dex_cache(hs.NewHandle(method->GetDexCache()));
+ DCHECK(method->IsCompilable());
jobject jclass_loader = class_loader.ToJObject();
const DexFile* dex_file = method->GetDexFile();
diff --git a/runtime/art_method.h b/runtime/art_method.h
index d1ef019..08f0285 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -220,6 +220,10 @@
return !IsAbstract() && !IsDefaultConflicting();
}
+ bool IsCompilable() {
+ return (GetAccessFlags() & kAccCompileDontBother) == 0;
+ }
+
// A default conflict method is a special sentinel method that stands for a conflict between
// multiple default methods. It cannot be invoked, throwing an IncompatibleClassChangeError if one
// attempts to do so.
diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc
index 2a66847..c2bfe16 100644
--- a/runtime/jit/jit.cc
+++ b/runtime/jit/jit.cc
@@ -562,7 +562,7 @@
return;
}
- if (method->IsClassInitializer() || method->IsNative()) {
+ if (method->IsClassInitializer() || method->IsNative() || !method->IsCompilable()) {
// We do not want to compile such methods.
return;
}
diff --git a/runtime/modifiers.h b/runtime/modifiers.h
index c31b22e..6dd182a 100644
--- a/runtime/modifiers.h
+++ b/runtime/modifiers.h
@@ -62,6 +62,9 @@
// invoking this method will throw an exception.
static constexpr uint32_t kAccDefaultConflict = 0x00800000; // method (runtime)
+// Set by the verifier for a method we do not want the compiler to compile.
+static constexpr uint32_t kAccCompileDontBother = 0x01000000; // method (runtime)
+
// Special runtime-only flags.
// Interface and all its super-interfaces with default methods have been recursively initialized.
static constexpr uint32_t kAccRecursivelyInitialized = 0x20000000;
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 647578e..8802e62 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -396,6 +396,13 @@
<< PrettyMethod(method_idx, *dex_file) << "\n");
}
result.kind = kSoftFailure;
+ if (method != nullptr &&
+ !CanCompilerHandleVerificationFailure(verifier.encountered_failure_types_)) {
+ method->SetAccessFlags(method->GetAccessFlags() | kAccCompileDontBother);
+ }
+ }
+ if (method != nullptr && verifier.HasInstructionThatWillThrow()) {
+ method->SetAccessFlags(method->GetAccessFlags() | kAccCompileDontBother);
}
} else {
// Bad method data.
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index ebb0b8c..2592a21 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -142,6 +142,14 @@
kHardFailure,
};
+ static bool CanCompilerHandleVerificationFailure(uint32_t encountered_failure_types) {
+ constexpr uint32_t unresolved_mask = verifier::VerifyError::VERIFY_ERROR_NO_CLASS
+ | 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;
+ }
+
// Verify a class. Returns "kNoFailure" on success.
static FailureKind VerifyClass(Thread* self,
mirror::Class* klass,