Add some extra debugging/diagnostic support.
CHECK that we don't bring a class back from a "permanent" error status in the
oat file at runtime.
CHECK that runtime_support.cc doesn't hand out 0 as an address for its caller
to branch to.
Also remove some accidentally left in debugging output.
Also fix a few comment typos.
Change-Id: Ibf4224940e9013184888c7854e675b17e0500ac9
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 0fd184c..00ddeee 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -2037,10 +2037,16 @@
}
}
- // Try to use verification information from oat file, otherwise do runtime verification
+ // Try to use verification information from the oat file, otherwise do runtime verification.
const DexFile& dex_file = FindDexFile(klass->GetDexCache());
- if (VerifyClassUsingOatFile(dex_file, klass) ||
- verifier::DexVerifier::VerifyClass(klass, error_msg)) {
+ Class::Status oat_file_class_status(Class::kStatusNotReady);
+ bool preverified = VerifyClassUsingOatFile(dex_file, klass, oat_file_class_status);
+ bool verified = preverified || verifier::DexVerifier::VerifyClass(klass, error_msg);
+ if (verified) {
+ if (!preverified && oat_file_class_status == Class::kStatusError) {
+ LOG(FATAL) << "Verification failed hard on class " << PrettyDescriptor(klass)
+ << " at compile time, but succeeded at runtime! The verifier must be broken.";
+ }
DCHECK(!Thread::Current()->IsExceptionPending());
// Make sure all classes referenced by catch blocks are resolved
ResolveClassExceptionHandlerTypes(dex_file, klass);
@@ -2059,7 +2065,8 @@
}
}
-bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file, Class* klass) {
+bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file, Class* klass,
+ Class::Status& oat_file_class_status) {
if (!Runtime::Current()->IsStarted()) {
return false;
}
@@ -2077,11 +2084,11 @@
UniquePtr<const OatFile::OatClass> oat_class(oat_dex_file->GetOatClass(class_def_index));
CHECK(oat_class.get() != NULL)
<< dex_file.GetLocation() << " " << PrettyClass(klass) << " " << descriptor;
- Class::Status status = oat_class->GetStatus();
- if (status == Class::kStatusVerified || status == Class::kStatusInitialized) {
+ oat_file_class_status = oat_class->GetStatus();
+ if (oat_file_class_status == Class::kStatusVerified || oat_file_class_status == Class::kStatusInitialized) {
return true;
}
- if (status == Class::kStatusError) {
+ if (oat_file_class_status == Class::kStatusError) {
// Compile time verification failed. Compile time verification can fail because we have
// incomplete type information. Consider the following:
// class ... {
@@ -2101,14 +2108,14 @@
// at compile time).
return false;
}
- if (status == Class::kStatusNotReady) {
+ if (oat_file_class_status == Class::kStatusNotReady) {
// Status is uninitialized if we couldn't determine the status at compile time, for example,
// not loading the class.
// TODO: when the verifier doesn't rely on Class-es failing to resolve/load the type hierarchy
// isn't a problem and this case shouldn't occur
return false;
}
- LOG(FATAL) << "Unexpected class status: " << status
+ LOG(FATAL) << "Unexpected class status: " << oat_file_class_status
<< " " << dex_file.GetLocation() << " " << PrettyClass(klass) << " " << descriptor;
return false;
@@ -2610,9 +2617,6 @@
}
bool ClassLinker::EnsureInitialized(Class* c, bool can_run_clinit) {
- if (PrettyClass(c).find("TestClass") != std::string::npos) {
- LOG(INFO) << "ClassLinker::EnsureInitialized " << PrettyClass(c);
- }
CHECK(c != NULL);
if (c->IsInitialized()) {
return true;
diff --git a/src/class_linker.h b/src/class_linker.h
index 9ba79eb..eb76738 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -277,7 +277,8 @@
ObjectArray<StackTraceElement>* AllocStackTraceElementArray(size_t length);
void VerifyClass(Class* klass);
- bool VerifyClassUsingOatFile(const DexFile& dex_file, Class* klass);
+ bool VerifyClassUsingOatFile(const DexFile& dex_file, Class* klass,
+ Class::Status& oat_file_class_status);
void ResolveClassExceptionHandlerTypes(const DexFile& dex_file, Class* klass);
void ResolveMethodExceptionHandlerTypes(const DexFile& dex_file, Method* klass);
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index b002c5c..af8ce22 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -1013,6 +1013,9 @@
DCHECK(!self->IsExceptionPending());
const void* code = method->GetCode();
+ // When we return, the caller will branch to this address, so it had better not be 0!
+ CHECK(code != NULL) << PrettyMethod(method);
+
uint32_t method_uint = reinterpret_cast<uint32_t>(method);
uint64_t code_uint = reinterpret_cast<uint32_t>(code);
uint64_t result = ((code_uint << 32) | method_uint);
diff --git a/src/runtime_support_arm.S b/src/runtime_support_arm.S
index be6945b..606fa1f 100644
--- a/src/runtime_support_arm.S
+++ b/src/runtime_support_arm.S
@@ -175,7 +175,7 @@
* as usual - except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
* the method_idx. This wrapper will save arg1-arg3, load the caller's Method*, align the
* stack and call the appropriate C helper.
- * NOTE: "this" is first visable argument of the target, and so can be found in arg1/r1.
+ * NOTE: "this" is first visible argument of the target, and so can be found in arg1/r1.
*
* The helper will attempt to locate the target and return a 64-bit result in r0/r1 consisting
* of the target Method* in r0 and method->code_ in r1.
@@ -195,7 +195,7 @@
mov r3, r9 @ pass Thread::Current
str sp, [sp, #0] @ pass SP
bl \cxx_name @ (method_idx, this, caller, Thread*, SP)
- mov r12, r1 @ save r0->code_
+ mov r12, r1 @ save Method*->code_
RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
cmp r0, #0 @ did we find the target?
bxne r12 @ tail call to target if so