Add GC map to oat file
Change-Id: Ied0462c711a09e2542f231c3b2fa31239958bd28
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 5ff2293..20e6514 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -1799,26 +1799,105 @@
}
void ClassLinker::VerifyClass(Class* klass) {
+ // TODO: assert that the monitor on the Class is held
if (klass->IsVerified()) {
return;
}
- CHECK_EQ(klass->GetStatus(), Class::kStatusResolved);
+ CHECK_EQ(klass->GetStatus(), Class::kStatusResolved) << PrettyClass(klass);
klass->SetStatus(Class::kStatusVerifying);
- if (verifier::DexVerifier::VerifyClass(klass)) {
+ // Try to use verification information from oat file, otherwise do runtime verification
+ const DexFile& dex_file = FindDexFile(klass->GetDexCache());
+ if (VerifyClassUsingOatFile(dex_file, klass) || verifier::DexVerifier::VerifyClass(klass)) {
+ // Make sure all classes referenced by catch blocks are resolved
+ ResolveClassExceptionHandlerTypes(dex_file, klass);
klass->SetStatus(Class::kStatusVerified);
} else {
LOG(ERROR) << "Verification failed on class " << PrettyClass(klass);
Thread* self = Thread::Current();
- CHECK(!self->IsExceptionPending()) << PrettyTypeOf(self->GetException());
+ CHECK(!self->IsExceptionPending()) << PrettyTypeOf(self->GetException()) << PrettyClass(klass);
self->ThrowNewExceptionF("Ljava/lang/VerifyError;", "Verification of %s failed",
PrettyDescriptor(klass).c_str());
- CHECK_EQ(klass->GetStatus(), Class::kStatusVerifying);
+ CHECK_EQ(klass->GetStatus(), Class::kStatusVerifying) << PrettyClass(klass);
klass->SetStatus(Class::kStatusError);
}
}
+bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file, Class* klass) {
+ if (!Runtime::Current()->IsStarted()) {
+ return false;
+ }
+ if (ClassLoader::UseCompileTimeClassPath()) {
+ return false;
+ }
+ const OatFile* oat_file = FindOatFileForDexFile(dex_file);
+ if (oat_file == NULL) {
+ return false;
+ }
+ const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation());
+ CHECK(oat_dex_file != NULL) << PrettyClass(klass);
+ const char* descriptor = ClassHelper(klass).GetDescriptor();
+ uint32_t class_def_index;
+ bool found = dex_file.FindClassDefIndex(descriptor, class_def_index);
+ CHECK(found) << descriptor;
+ UniquePtr<const OatFile::OatClass> oat_class(oat_dex_file->GetOatClass(class_def_index));
+ CHECK(oat_class.get() != NULL) << descriptor;
+ Class::Status status = oat_class->GetStatus();
+ if (status == Class::kStatusError) {
+ ThrowEarlierClassFailure(klass);
+ klass->SetVerifyErrorClass(Thread::Current()->GetException()->GetClass());
+ klass->SetStatus(Class::kStatusError);
+ return true;
+ }
+ if (status == Class::kStatusVerified || status == Class::kStatusInitialized) {
+ return true;
+ }
+ if (status == Class::kStatusNotReady) {
+ return false;
+ }
+ LOG(FATAL) << "Unexpected class status: " << status;
+ return false;
+}
+
+void ClassLinker::ResolveClassExceptionHandlerTypes(const DexFile& dex_file, Class* klass) {
+ for (size_t i = 0; i < klass->NumDirectMethods(); i++) {
+ ResolveMethodExceptionHandlerTypes(dex_file, klass->GetDirectMethod(i));
+ }
+ for (size_t i = 0; i < klass->NumVirtualMethods(); i++) {
+ ResolveMethodExceptionHandlerTypes(dex_file, klass->GetVirtualMethod(i));
+ }
+}
+
+void ClassLinker::ResolveMethodExceptionHandlerTypes(const DexFile& dex_file, Method* method) {
+ // similar to DexVerifier::ScanTryCatchBlocks and dex2oat's ResolveExceptionsForMethod.
+ const DexFile::CodeItem* code_item = dex_file.GetCodeItem(method->GetCodeItemOffset());
+ if (code_item == NULL) {
+ return; // native or abstract method
+ }
+ if (code_item->tries_size_ == 0) {
+ return; // nothing to process
+ }
+ const byte* handlers_ptr = DexFile::GetCatchHandlerData(*code_item, 0);
+ uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
+ ClassLinker* linker = Runtime::Current()->GetClassLinker();
+ for (uint32_t idx = 0; idx < handlers_size; idx++) {
+ CatchHandlerIterator iterator(handlers_ptr);
+ for (; iterator.HasNext(); iterator.Next()) {
+ // Ensure exception types are resolved so that they don't need resolution to be delivered,
+ // unresolved exception types will be ignored by exception delivery
+ if (iterator.GetHandlerTypeIndex() != DexFile::kDexNoIndex16) {
+ Class* exception_type = linker->ResolveType(iterator.GetHandlerTypeIndex(), method);
+ if (exception_type == NULL) {
+ DCHECK(Thread::Current()->IsExceptionPending());
+ Thread::Current()->ClearException();
+ }
+ }
+ }
+ handlers_ptr = iterator.EndDataPointer();
+ }
+}
+
static void CheckProxyConstructor(Method* constructor);
static void CheckProxyMethod(Method* method, SirtRef<Method>& prototype);
@@ -2025,7 +2104,7 @@
return false;
}
- DCHECK_EQ(klass->GetStatus(), Class::kStatusVerified);
+ DCHECK_EQ(klass->GetStatus(), Class::kStatusVerified) << PrettyClass(klass);
klass->SetClinitThreadId(self->GetTid());
klass->SetStatus(Class::kStatusInitializing);
@@ -2211,7 +2290,7 @@
if (!super_initialized) {
if (!can_run_clinit) {
// Don't set status to error when we can't run <clinit>.
- CHECK_EQ(klass->GetStatus(), Class::kStatusInitializing);
+ CHECK_EQ(klass->GetStatus(), Class::kStatusInitializing) << PrettyClass(klass);
klass->SetStatus(Class::kStatusVerified);
return false;
}