ART: PathClassLoader for compiler
Use an actual PathClassLoader when compiling apps, instead of a
side structure and cutout.
This CL sets up a minimal object 'cluster' that recreates the Java
side of a regular ClassLoader such that the Class-Linker will
recognize it and use the internal native fast-path.
This CL removes the now unnecessary compile-time-classpath and
replaces it with a single 'compiling-the-boot-image' flag in the
compiler callbacks.
Note: This functionality is *only* intended for the compiler, as
the objects have not been completely initialized.
Bug: 19781184
Change-Id: I7f36af12dd7852d21281110a25c119e8c0669c1d
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 67872d7..b81a99a 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -1372,38 +1372,6 @@
self->SetException(pre_allocated);
return nullptr;
}
- } else if (Runtime::Current()->UseCompileTimeClassPath()) {
- // First try with the bootstrap class loader.
- if (class_loader.Get() != nullptr) {
- klass = LookupClass(self, descriptor, hash, nullptr);
- if (klass != nullptr) {
- return EnsureResolved(self, descriptor, klass);
- }
- }
- // If the lookup failed search the boot class path. We don't perform a recursive call to avoid
- // a NoClassDefFoundError being allocated.
- ClassPathEntry pair = FindInClassPath(descriptor, hash, boot_class_path_);
- if (pair.second != nullptr) {
- return DefineClass(self, descriptor, hash, NullHandle<mirror::ClassLoader>(), *pair.first,
- *pair.second);
- }
- // Next try the compile time class path.
- const std::vector<const DexFile*>* class_path;
- {
- ScopedObjectAccessUnchecked soa(self);
- ScopedLocalRef<jobject> jclass_loader(soa.Env(),
- soa.AddLocalReference<jobject>(class_loader.Get()));
- class_path = &Runtime::Current()->GetCompileTimeClassPath(jclass_loader.get());
- }
- pair = FindInClassPath(descriptor, hash, *class_path);
- if (pair.second != nullptr) {
- return DefineClass(self, descriptor, hash, class_loader, *pair.first, *pair.second);
- } else {
- // Use the pre-allocated NCDFE at compile time to avoid wasting time constructing exceptions.
- mirror::Throwable* pre_allocated = Runtime::Current()->GetPreAllocatedNoClassDefFoundError();
- self->SetException(pre_allocated);
- return nullptr;
- }
} else {
ScopedObjectAccessUnchecked soa(self);
mirror::Class* cp_klass = FindClassInPathClassLoader(soa, self, descriptor, hash,
@@ -1411,6 +1379,14 @@
if (cp_klass != nullptr) {
return cp_klass;
}
+
+ if (Runtime::Current()->IsAotCompiler()) {
+ // Oops, compile-time, can't run actual class-loader code.
+ mirror::Throwable* pre_allocated = Runtime::Current()->GetPreAllocatedNoClassDefFoundError();
+ self->SetException(pre_allocated);
+ return nullptr;
+ }
+
ScopedLocalRef<jobject> class_loader_object(soa.Env(),
soa.AddLocalReference<jobject>(class_loader.Get()));
std::string class_name_string(DescriptorToDot(descriptor));
@@ -1767,7 +1743,7 @@
return; // No direct methods => no static methods.
}
Runtime* runtime = Runtime::Current();
- if (!runtime->IsStarted() || runtime->UseCompileTimeClassPath()) {
+ if (!runtime->IsStarted()) {
if (runtime->IsAotCompiler() || runtime->GetHeap()->HasImageSpace()) {
return; // OAT file unavailable.
}
@@ -1907,7 +1883,7 @@
bool has_oat_class = false;
- if (Runtime::Current()->IsStarted() && !Runtime::Current()->UseCompileTimeClassPath()) {
+ if (Runtime::Current()->IsStarted() && !Runtime::Current()->IsAotCompiler()) {
OatFile::OatClass oat_class = FindOatClass(dex_file, klass->GetDexClassDefIndex(),
&has_oat_class);
if (has_oat_class) {
@@ -2808,7 +2784,7 @@
// classes.
if (Runtime::Current()->IsAotCompiler()) {
// Are we compiling the bootclasspath?
- if (!Runtime::Current()->UseCompileTimeClassPath()) {
+ if (Runtime::Current()->GetCompilerCallbacks()->IsBootImage()) {
return false;
}
// We are compiling an app (not the image).
@@ -5315,4 +5291,98 @@
}
}
+jobject ClassLinker::CreatePathClassLoader(Thread* self, std::vector<const DexFile*>& dex_files) {
+ // SOAAlreadyRunnable is protected, and we need something to add a global reference.
+ // We could move the jobject to the callers, but all call-sites do this...
+ ScopedObjectAccessUnchecked soa(self);
+
+ // Register the dex files.
+ for (const DexFile* dex_file : dex_files) {
+ RegisterDexFile(*dex_file);
+ }
+
+ // For now, create a libcore-level DexFile for each ART DexFile. This "explodes" multidex.
+ StackHandleScope<11> hs(self);
+
+ Handle<mirror::ArtField> h_dex_elements_field =
+ hs.NewHandle(soa.DecodeField(WellKnownClasses::dalvik_system_DexPathList_dexElements));
+
+ mirror::Class* dex_elements_class = h_dex_elements_field->GetType(true);
+ DCHECK(dex_elements_class != nullptr);
+ DCHECK(dex_elements_class->IsArrayClass());
+ Handle<mirror::ObjectArray<mirror::Object>> h_dex_elements =
+ hs.NewHandle(reinterpret_cast<mirror::ObjectArray<mirror::Object>*>(
+ mirror::Array::Alloc<false>(self, dex_elements_class, dex_files.size(),
+ dex_elements_class->GetComponentSizeShift(),
+ Runtime::Current()->GetHeap()->GetCurrentAllocator())));
+ Handle<mirror::Class> h_dex_element_class =
+ hs.NewHandle(dex_elements_class->GetComponentType());
+
+ Handle<mirror::ArtField> h_element_file_field =
+ hs.NewHandle(
+ soa.DecodeField(WellKnownClasses::dalvik_system_DexPathList__Element_dexFile));
+ DCHECK_EQ(h_dex_element_class.Get(), h_element_file_field->GetDeclaringClass());
+
+ Handle<mirror::ArtField> h_cookie_field =
+ hs.NewHandle(soa.DecodeField(WellKnownClasses::dalvik_system_DexFile_cookie));
+ DCHECK_EQ(h_cookie_field->GetDeclaringClass(), h_element_file_field->GetType(false));
+
+ // Fill the elements array.
+ int32_t index = 0;
+ for (const DexFile* dex_file : dex_files) {
+ StackHandleScope<3> hs2(self);
+
+ Handle<mirror::LongArray> h_long_array = hs2.NewHandle(mirror::LongArray::Alloc(self, 1));
+ DCHECK(h_long_array.Get() != nullptr);
+ h_long_array->Set(0, reinterpret_cast<intptr_t>(dex_file));
+
+ Handle<mirror::Object> h_dex_file = hs2.NewHandle(
+ h_cookie_field->GetDeclaringClass()->AllocObject(self));
+ DCHECK(h_dex_file.Get() != nullptr);
+ h_cookie_field->SetObject<false>(h_dex_file.Get(), h_long_array.Get());
+
+ Handle<mirror::Object> h_element = hs2.NewHandle(h_dex_element_class->AllocObject(self));
+ DCHECK(h_element.Get() != nullptr);
+ h_element_file_field->SetObject<false>(h_element.Get(), h_dex_file.Get());
+
+ h_dex_elements->Set(index, h_element.Get());
+ index++;
+ }
+ DCHECK_EQ(index, h_dex_elements->GetLength());
+
+ // Create DexPathList.
+ Handle<mirror::Object> h_dex_path_list = hs.NewHandle(
+ h_dex_elements_field->GetDeclaringClass()->AllocObject(self));
+ DCHECK(h_dex_path_list.Get() != nullptr);
+ // Set elements.
+ h_dex_elements_field->SetObject<false>(h_dex_path_list.Get(), h_dex_elements.Get());
+
+ // Create PathClassLoader.
+ Handle<mirror::Class> h_path_class_class = hs.NewHandle(
+ soa.Decode<mirror::Class*>(WellKnownClasses::dalvik_system_PathClassLoader));
+ Handle<mirror::Object> h_path_class_loader = hs.NewHandle(
+ h_path_class_class->AllocObject(self));
+ DCHECK(h_path_class_loader.Get() != nullptr);
+ // Set DexPathList.
+ Handle<mirror::ArtField> h_path_list_field = hs.NewHandle(
+ soa.DecodeField(WellKnownClasses::dalvik_system_PathClassLoader_pathList));
+ DCHECK(h_path_list_field.Get() != nullptr);
+ h_path_list_field->SetObject<false>(h_path_class_loader.Get(), h_dex_path_list.Get());
+
+ // Make a pretend boot-classpath.
+ // TODO: Should we scan the image?
+ Handle<mirror::ArtField> h_parent_field = hs.NewHandle(
+ mirror::Class::FindField(self, hs.NewHandle(h_path_class_loader->GetClass()), "parent",
+ "Ljava/lang/ClassLoader;"));
+ DCHECK(h_parent_field.Get() != nullptr);
+ mirror::Object* boot_cl =
+ soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_BootClassLoader)->AllocObject(self);
+ h_parent_field->SetObject<false>(h_path_class_loader.Get(), boot_cl);
+
+ // Make it a global ref and return.
+ ScopedLocalRef<jobject> local_ref(
+ soa.Env(), soa.Env()->AddLocalReference<jobject>(h_path_class_loader.Get()));
+ return soa.Env()->NewGlobalRef(local_ref.get());
+}
+
} // namespace art