ART: Punt to the interpreter for VerifiedMethod errors
In case that the GC map can't be created (because of size restrictions),
do not fail the class. Instead punt to the interpreter.
Bug: 17791183
(cherry picked from commit f535c69f115c61ffadca1bd2706244d0aa30f9aa)
Change-Id: I348bb306dbfc85c235fa93c0c527fba6627551fe
diff --git a/compiler/dex/verification_results.cc b/compiler/dex/verification_results.cc
index 60d2406..4daed67 100644
--- a/compiler/dex/verification_results.cc
+++ b/compiler/dex/verification_results.cc
@@ -57,8 +57,8 @@
const VerifiedMethod* verified_method = VerifiedMethod::Create(method_verifier, compile);
if (verified_method == nullptr) {
- DCHECK(method_verifier->HasFailures());
- return false;
+ // Do not report an error to the verifier. We'll just punt this later.
+ return true;
}
WriterMutexLock mu(Thread::Current(), verified_methods_lock_);
diff --git a/compiler/dex/verified_method.cc b/compiler/dex/verified_method.cc
index d684bc9..93e9a51 100644
--- a/compiler/dex/verified_method.cc
+++ b/compiler/dex/verified_method.cc
@@ -49,7 +49,6 @@
if (compile) {
/* Generate a register map. */
if (!verified_method->GenerateGcMap(method_verifier)) {
- CHECK(method_verifier->HasFailures());
return nullptr; // Not a real failure, but a failure to encode.
}
if (kIsDebugBuild) {
@@ -83,17 +82,17 @@
ComputeGcMapSizes(method_verifier, &num_entries, &ref_bitmap_bits, &pc_bits);
// There's a single byte to encode the size of each bitmap.
if (ref_bitmap_bits >= kBitsPerByte * 8192 /* 13-bit size */) {
- // TODO: either a better GC map format or per method failures
- method_verifier->Fail(verifier::VERIFY_ERROR_BAD_CLASS_HARD)
- << "Cannot encode GC map for method with " << ref_bitmap_bits << " registers";
+ LOG(WARNING) << "Cannot encode GC map for method with " << ref_bitmap_bits << " registers: "
+ << PrettyMethod(method_verifier->GetMethodReference().dex_method_index,
+ *method_verifier->GetMethodReference().dex_file);
return false;
}
size_t ref_bitmap_bytes = RoundUp(ref_bitmap_bits, kBitsPerByte) / kBitsPerByte;
// There are 2 bytes to encode the number of entries.
if (num_entries >= 65536) {
- // TODO: Either a better GC map format or per method failures.
- method_verifier->Fail(verifier::VERIFY_ERROR_BAD_CLASS_HARD)
- << "Cannot encode GC map for method with " << num_entries << " entries";
+ LOG(WARNING) << "Cannot encode GC map for method with " << num_entries << " entries: "
+ << PrettyMethod(method_verifier->GetMethodReference().dex_method_index,
+ *method_verifier->GetMethodReference().dex_file);
return false;
}
size_t pc_bytes;
@@ -105,10 +104,10 @@
format = verifier::kRegMapFormatCompact16;
pc_bytes = 2;
} else {
- // TODO: Either a better GC map format or per method failures.
- method_verifier->Fail(verifier::VERIFY_ERROR_BAD_CLASS_HARD)
- << "Cannot encode GC map for method with "
- << (1 << pc_bits) << " instructions (number is rounded up to nearest power of 2)";
+ LOG(WARNING) << "Cannot encode GC map for method with "
+ << (1 << pc_bits) << " instructions (number is rounded up to nearest power of 2): "
+ << PrettyMethod(method_verifier->GetMethodReference().dex_method_index,
+ *method_verifier->GetMethodReference().dex_file);
return false;
}
size_t table_size = ((pc_bytes + ref_bitmap_bytes) * num_entries) + 4;
@@ -161,7 +160,7 @@
}
}
} else {
- DCHECK(reg_bitmap == NULL);
+ DCHECK(i >= 65536 || reg_bitmap == NULL);
}
}
}
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 051b310..cbb23c2 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -2120,8 +2120,12 @@
} else if ((access_flags & kAccAbstract) != 0) {
// Abstract methods don't have code.
} else {
+ bool has_verified_method = verification_results_->GetVerifiedMethod(method_ref) != nullptr;
bool compile = compilation_enabled &&
- verification_results_->IsCandidateForCompilation(method_ref, access_flags);
+ // Basic checks, e.g., not <clinit>.
+ verification_results_->IsCandidateForCompilation(method_ref, access_flags) &&
+ // Did not fail to create VerifiedMethod metadata.
+ has_verified_method;
if (compile) {
// NOTE: if compiler declines to compile this method, it will return nullptr.
compiled_method = compiler_->Compile(code_item, access_flags, invoke_type, class_def_idx,
@@ -2129,10 +2133,12 @@
}
if (compiled_method == nullptr && dex_to_dex_compilation_level != kDontDexToDexCompile) {
// TODO: add a command-line option to disable DEX-to-DEX compilation ?
+ // Do not optimize if a VerifiedMethod is missing. SafeCast elision, for example, relies on
+ // it.
(*dex_to_dex_compiler_)(*this, code_item, access_flags,
invoke_type, class_def_idx,
method_idx, class_loader, dex_file,
- dex_to_dex_compilation_level);
+ has_verified_method ? dex_to_dex_compilation_level : kRequired);
}
}
if (kTimeCompileMethod) {