Avoid throwing NoClassDefFoundError at compile time.
Change-Id: I8ba56a8750e1718babcb1f94e0408d89f58ea9b5
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 9dd880f..bf541c6 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -1416,31 +1416,22 @@
// classes found in the boot classpath. Since at runtime we will
// select the class from the boot classpath, do not attempt to resolve
// or compile it now.
-static bool SkipClass(mirror::ClassLoader* class_loader,
- const DexFile& dex_file,
- const DexFile::ClassDef& class_def)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+static bool SkipClass(ClassLinker* class_linker, jobject class_loader, const DexFile& dex_file,
+ const DexFile::ClassDef& class_def) {
if (class_loader == NULL) {
return false;
}
const char* descriptor = dex_file.GetClassDescriptor(class_def);
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- mirror::Class* klass = class_linker->FindClass(descriptor, NULL);
- if (klass == NULL) {
- Thread* self = Thread::Current();
- CHECK(self->IsExceptionPending());
- self->ClearException();
- return false;
- }
- return true;
+ return class_linker->IsInBootClassPath(descriptor);
}
static void ResolveClassFieldsAndMethods(const ParallelCompilationManager* manager,
size_t class_def_index)
LOCKS_EXCLUDED(Locks::mutator_lock_) {
- ScopedObjectAccess soa(Thread::Current());
- mirror::ClassLoader* class_loader = soa.Decode<mirror::ClassLoader*>(manager->GetClassLoader());
+ Thread* self = Thread::Current();
+ jobject jclass_loader = manager->GetClassLoader();
const DexFile& dex_file = *manager->GetDexFile();
+ ClassLinker* class_linker = manager->GetClassLinker();
// If an instance field is final then we need to have a barrier on the return, static final
// fields are assigned within the lock held for class initialization. Conservatively assume
@@ -1455,7 +1446,7 @@
// definitions, since many of them many never be referenced by
// generated code.
const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
- if (!SkipClass(class_loader, dex_file, class_def)) {
+ if (!SkipClass(class_linker, jclass_loader, dex_file, class_def)) {
// Note the class_data pointer advances through the headers,
// static fields, instance fields, direct methods, and virtual
// methods.
@@ -1464,7 +1455,8 @@
// Empty class such as a marker interface.
requires_constructor_barrier = false;
} else {
- ClassLinker* class_linker = manager->GetClassLinker();
+ ScopedObjectAccess soa(self);
+ mirror::ClassLoader* class_loader = soa.Decode<mirror::ClassLoader*>(jclass_loader);
mirror::DexCache* dex_cache = class_linker->FindDexCache(dex_file);
// Resolve the class.
@@ -1535,8 +1527,7 @@
}
}
if (requires_constructor_barrier) {
- manager->GetCompiler()->AddRequiresConstructorBarrier(soa.Self(), manager->GetDexFile(),
- class_def_index);
+ manager->GetCompiler()->AddRequiresConstructorBarrier(self, &dex_file, class_def_index);
}
}
@@ -2170,12 +2161,9 @@
jobject jclass_loader = manager->GetClassLoader();
const DexFile& dex_file = *manager->GetDexFile();
const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
- {
- ScopedObjectAccess soa(Thread::Current());
- mirror::ClassLoader* class_loader = soa.Decode<mirror::ClassLoader*>(jclass_loader);
- if (SkipClass(class_loader, dex_file, class_def)) {
- return;
- }
+ ClassLinker* class_linker = manager->GetClassLinker();
+ if (SkipClass(class_linker, jclass_loader, dex_file, class_def)) {
+ return;
}
ClassReference ref(&dex_file, class_def_index);
// Skip compiling classes with generic verifier failures since they will still fail at runtime
@@ -2203,6 +2191,7 @@
while (it.HasNextInstanceField()) {
it.Next();
}
+ CompilerDriver* driver = manager->GetCompiler();
// Compile direct methods
int64_t previous_direct_method_idx = -1;
while (it.HasNextDirectMethod()) {
@@ -2214,9 +2203,9 @@
continue;
}
previous_direct_method_idx = method_idx;
- manager->GetCompiler()->CompileMethod(it.GetMethodCodeItem(), it.GetMemberAccessFlags(),
- it.GetMethodInvokeType(class_def), class_def_index,
- method_idx, jclass_loader, dex_file, dex_to_dex_compilation_level);
+ driver->CompileMethod(it.GetMethodCodeItem(), it.GetMemberAccessFlags(),
+ it.GetMethodInvokeType(class_def), class_def_index,
+ method_idx, jclass_loader, dex_file, dex_to_dex_compilation_level);
it.Next();
}
// Compile virtual methods
@@ -2230,9 +2219,9 @@
continue;
}
previous_virtual_method_idx = method_idx;
- manager->GetCompiler()->CompileMethod(it.GetMethodCodeItem(), it.GetMemberAccessFlags(),
- it.GetMethodInvokeType(class_def), class_def_index,
- method_idx, jclass_loader, dex_file, dex_to_dex_compilation_level);
+ driver->CompileMethod(it.GetMethodCodeItem(), it.GetMemberAccessFlags(),
+ it.GetMethodInvokeType(class_def), class_def_index,
+ method_idx, jclass_loader, dex_file, dex_to_dex_compilation_level);
it.Next();
}
DCHECK(!it.HasNext());
@@ -2240,8 +2229,10 @@
void CompilerDriver::CompileDexFile(jobject class_loader, const DexFile& dex_file,
ThreadPool& thread_pool, base::TimingLogger& timings) {
+ // TODO: strdup memory leak.
timings.NewSplit(strdup(("Compile " + dex_file.GetLocation()).c_str()));
- ParallelCompilationManager context(NULL, class_loader, this, &dex_file, thread_pool);
+ ParallelCompilationManager context(Runtime::Current()->GetClassLinker(), class_loader, this,
+ &dex_file, thread_pool);
context.ForAll(0, dex_file.NumClassDefs(), CompilerDriver::CompileClass, thread_count_);
}
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index b4c767d..0110b36 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -1290,6 +1290,11 @@
return klass;
}
+bool ClassLinker::IsInBootClassPath(const char* descriptor) {
+ DexFile::ClassPathEntry pair = DexFile::FindInClassPath(descriptor, boot_class_path_);
+ return pair.second != NULL;
+}
+
mirror::Class* ClassLinker::FindSystemClass(const char* descriptor) {
return FindClass(descriptor, NULL);
}
@@ -1320,18 +1325,17 @@
}
} else if (Runtime::Current()->UseCompileTimeClassPath()) {
- // first try the boot class path
- mirror::Class* system_class = FindSystemClass(descriptor);
- if (system_class != NULL) {
+ // First try the boot class path, we check the descriptor first to avoid an unnecessary
+ // throw of a NoClassDefFoundError.
+ if (IsInBootClassPath(descriptor)) {
+ mirror::Class* system_class = FindSystemClass(descriptor);
+ CHECK(system_class != NULL);
return system_class;
}
- CHECK(self->IsExceptionPending());
- self->ClearException();
-
- // next try the compile time class path
+ // Next try the compile time class path.
const std::vector<const DexFile*>* class_path;
{
- ScopedObjectAccessUnchecked soa(Thread::Current());
+ ScopedObjectAccessUnchecked soa(self);
ScopedLocalRef<jobject> jclass_loader(soa.Env(), soa.AddLocalReference<jobject>(class_loader));
class_path = &Runtime::Current()->GetCompileTimeClassPath(jclass_loader.get());
}
@@ -2697,7 +2701,6 @@
Thread* self = Thread::Current();
- mirror::ArtMethod* clinit = NULL;
{
// see JLS 3rd edition, 12.4.2 "Detailed Initialization Procedure" for the locking protocol
ObjectLock lock(self, klass);
@@ -2722,8 +2725,6 @@
}
}
- clinit = klass->FindDeclaredDirectMethod("<clinit>", "()V");
-
// If the class is kStatusInitializing, either this thread is
// initializing higher up the stack or another thread has beat us
// to initializing and we need to wait. Either way, this
@@ -2770,6 +2771,7 @@
bool has_static_field_initializers = InitializeStaticFields(klass, can_init_statics);
+ mirror::ArtMethod* clinit = klass->FindDeclaredDirectMethod("<clinit>", "()V");
if (clinit != NULL && can_run_clinit) {
if (Runtime::Current()->IsStarted()) {
JValue result;
@@ -2779,7 +2781,7 @@
}
}
- // Opportunistically set static method trampolines to their destiniation. Unless initialization
+ // Opportunistically set static method trampolines to their destination. Unless initialization
// is being hindered at compile time.
if (can_init_statics || can_run_clinit || (!has_static_field_initializers && clinit == NULL)) {
FixupStaticTrampolines(klass);
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index fdf17a2..624b7ce 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -62,6 +62,8 @@
~ClassLinker();
+ bool IsInBootClassPath(const char* descriptor);
+
// Finds a class by its descriptor, loading it if necessary.
// If class_loader is null, searches boot_class_path_.
mirror::Class* FindClass(const char* descriptor, mirror::ClassLoader* class_loader)