Allow dex2oat to create a full class loader context
We previously checked that dex2oat sees only a single class loader. This
CL removes the restriction and enables dex2oat to create and compile with
a full class loader context.
Test: m test-art-host
Bug: 38138251
Change-Id: I03e75a75757995ce8ce3addf0bc0a708e18ac050
diff --git a/runtime/class_loader_context_test.cc b/runtime/class_loader_context_test.cc
index 659db4b..1b46f67 100644
--- a/runtime/class_loader_context_test.cc
+++ b/runtime/class_loader_context_test.cc
@@ -117,6 +117,24 @@
ASSERT_FALSE(context->special_shared_library_);
}
+ void VerifyClassLoaderDexFiles(ScopedObjectAccess& soa,
+ Handle<mirror::ClassLoader> class_loader,
+ jclass type,
+ std::vector<const DexFile*>& expected_dex_files)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ ASSERT_TRUE(class_loader->GetClass() == soa.Decode<mirror::Class>(type));
+
+ std::vector<const DexFile*> class_loader_dex_files = GetDexFiles(soa, class_loader);
+ ASSERT_EQ(expected_dex_files.size(), class_loader_dex_files.size());
+
+ for (size_t i = 0; i < expected_dex_files.size(); i++) {
+ ASSERT_EQ(expected_dex_files[i]->GetLocation(),
+ class_loader_dex_files[i]->GetLocation());
+ ASSERT_EQ(expected_dex_files[i]->GetLocationChecksum(),
+ class_loader_dex_files[i]->GetLocationChecksum());
+ }
+ }
+
private:
void VerifyClassLoaderInfo(ClassLoaderContext* context,
size_t index,
@@ -246,7 +264,7 @@
ScopedObjectAccess soa(Thread::Current());
- StackHandleScope<2> hs(soa.Self());
+ StackHandleScope<1> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader = hs.NewHandle(
soa.Decode<mirror::ClassLoader>(jclass_loader));
@@ -255,25 +273,17 @@
ASSERT_TRUE(class_loader->GetParent()->GetClass() ==
soa.Decode<mirror::Class>(WellKnownClasses::java_lang_BootClassLoader));
-
- std::vector<const DexFile*> class_loader_dex_files = GetDexFiles(jclass_loader);
- ASSERT_EQ(classpath_dex.size() + compilation_sources.size(), class_loader_dex_files.size());
-
- // The classpath dex files must come first.
- for (size_t i = 0; i < classpath_dex.size(); i++) {
- ASSERT_EQ(classpath_dex[i]->GetLocation(),
- class_loader_dex_files[i]->GetLocation());
- ASSERT_EQ(classpath_dex[i]->GetLocationChecksum(),
- class_loader_dex_files[i]->GetLocationChecksum());
+ // For the first class loader the class path dex files must come first and then the
+ // compilation sources.
+ std::vector<const DexFile*> expected_classpath = MakeNonOwningPointerVector(classpath_dex);
+ for (auto& dex : compilation_sources_raw) {
+ expected_classpath.push_back(dex);
}
- // The compilation dex files must come second.
- for (size_t i = 0, k = classpath_dex.size(); i < compilation_sources.size(); i++, k++) {
- ASSERT_EQ(compilation_sources[i]->GetLocation(),
- class_loader_dex_files[k]->GetLocation());
- ASSERT_EQ(compilation_sources[i]->GetLocationChecksum(),
- class_loader_dex_files[k]->GetLocationChecksum());
- }
+ VerifyClassLoaderDexFiles(soa,
+ class_loader,
+ WellKnownClasses::dalvik_system_PathClassLoader,
+ expected_classpath);
}
TEST_F(ClassLoaderContextTest, CreateClassLoaderWithEmptyContext) {
@@ -290,28 +300,90 @@
ScopedObjectAccess soa(Thread::Current());
- StackHandleScope<2> hs(soa.Self());
+ StackHandleScope<1> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader = hs.NewHandle(
soa.Decode<mirror::ClassLoader>(jclass_loader));
- ASSERT_TRUE(class_loader->GetClass() ==
- soa.Decode<mirror::Class>(WellKnownClasses::dalvik_system_PathClassLoader));
+ // An empty context should create a single PathClassLoader with only the compilation sources.
+ VerifyClassLoaderDexFiles(soa,
+ class_loader,
+ WellKnownClasses::dalvik_system_PathClassLoader,
+ compilation_sources_raw);
ASSERT_TRUE(class_loader->GetParent()->GetClass() ==
soa.Decode<mirror::Class>(WellKnownClasses::java_lang_BootClassLoader));
-
-
- std::vector<const DexFile*> class_loader_dex_files = GetDexFiles(jclass_loader);
-
- // The compilation sources should be the only files present in the class loader
- ASSERT_EQ(compilation_sources.size(), class_loader_dex_files.size());
- for (size_t i = 0; i < compilation_sources.size(); i++) {
- ASSERT_EQ(compilation_sources[i]->GetLocation(),
- class_loader_dex_files[i]->GetLocation());
- ASSERT_EQ(compilation_sources[i]->GetLocationChecksum(),
- class_loader_dex_files[i]->GetLocationChecksum());
- }
}
+TEST_F(ClassLoaderContextTest, CreateClassLoaderWithComplexChain) {
+ // Setup the context.
+ std::vector<std::unique_ptr<const DexFile>> classpath_dex_a = OpenTestDexFiles("ForClassLoaderA");
+ std::vector<std::unique_ptr<const DexFile>> classpath_dex_b = OpenTestDexFiles("ForClassLoaderB");
+ std::vector<std::unique_ptr<const DexFile>> classpath_dex_c = OpenTestDexFiles("ForClassLoaderC");
+ std::vector<std::unique_ptr<const DexFile>> classpath_dex_d = OpenTestDexFiles("ForClassLoaderD");
+
+ std::string context_spec =
+ "PCL[" + CreateClassPath(classpath_dex_a) + ":" + CreateClassPath(classpath_dex_b) + "];" +
+ "DLC[" + CreateClassPath(classpath_dex_c) + "];" +
+ "PCL[" + CreateClassPath(classpath_dex_d) + "]";
+
+ std::unique_ptr<ClassLoaderContext> context = ClassLoaderContext::Create(context_spec);
+ ASSERT_TRUE(context->OpenDexFiles(InstructionSet::kArm, ""));
+
+ // Setup the compilation sources.
+ std::vector<std::unique_ptr<const DexFile>> compilation_sources = OpenTestDexFiles("MultiDex");
+ std::vector<const DexFile*> compilation_sources_raw =
+ MakeNonOwningPointerVector(compilation_sources);
+
+ // Create the class loader.
+ jobject jclass_loader = context->CreateClassLoader(compilation_sources_raw);
+ ASSERT_TRUE(jclass_loader != nullptr);
+
+ // Verify the class loader.
+ ScopedObjectAccess soa(Thread::Current());
+
+ StackHandleScope<3> hs(soa.Self());
+ Handle<mirror::ClassLoader> class_loader_1 = hs.NewHandle(
+ soa.Decode<mirror::ClassLoader>(jclass_loader));
+
+ // Verify the first class loader
+
+ // For the first class loader the class path dex files must come first and then the
+ // compilation sources.
+ std::vector<const DexFile*> class_loader_1_dex_files =
+ MakeNonOwningPointerVector(classpath_dex_a);
+ for (auto& dex : classpath_dex_b) {
+ class_loader_1_dex_files.push_back(dex.get());
+ }
+ for (auto& dex : compilation_sources_raw) {
+ class_loader_1_dex_files.push_back(dex);
+ }
+ VerifyClassLoaderDexFiles(soa,
+ class_loader_1,
+ WellKnownClasses::dalvik_system_PathClassLoader,
+ class_loader_1_dex_files);
+
+ // Verify the second class loader
+ Handle<mirror::ClassLoader> class_loader_2 = hs.NewHandle(class_loader_1->GetParent());
+ std::vector<const DexFile*> class_loader_2_dex_files =
+ MakeNonOwningPointerVector(classpath_dex_c);
+ VerifyClassLoaderDexFiles(soa,
+ class_loader_2,
+ WellKnownClasses::dalvik_system_DelegateLastClassLoader,
+ class_loader_2_dex_files);
+
+ // Verify the third class loader
+ Handle<mirror::ClassLoader> class_loader_3 = hs.NewHandle(class_loader_2->GetParent());
+ std::vector<const DexFile*> class_loader_3_dex_files =
+ MakeNonOwningPointerVector(classpath_dex_d);
+ VerifyClassLoaderDexFiles(soa,
+ class_loader_3,
+ WellKnownClasses::dalvik_system_PathClassLoader,
+ class_loader_3_dex_files);
+ // The last class loader should have the BootClassLoader as a parent.
+ ASSERT_TRUE(class_loader_3->GetParent()->GetClass() ==
+ soa.Decode<mirror::Class>(WellKnownClasses::java_lang_BootClassLoader));
+}
+
+
TEST_F(ClassLoaderContextTest, RemoveSourceLocations) {
std::unique_ptr<ClassLoaderContext> context =
ClassLoaderContext::Create("PCL[a.dex]");
@@ -338,9 +410,8 @@
std::vector<std::unique_ptr<const DexFile>> dex1 = OpenTestDexFiles("Main");
std::vector<std::unique_ptr<const DexFile>> dex2 = OpenTestDexFiles("MyClass");
std::string encoding = context->EncodeContextForOatFile("");
- std::string expected_encoding = "PCL[" +
- dex1[0]->GetLocation() + "*" + std::to_string(dex1[0]->GetLocationChecksum()) + ":" +
- dex2[0]->GetLocation() + "*" + std::to_string(dex2[0]->GetLocationChecksum()) + "]";
+ std::string expected_encoding = "PCL[" + CreateClassPathWithChecksums(dex1) + ":" +
+ CreateClassPathWithChecksums(dex2) + "]";
ASSERT_EQ(expected_encoding, context->EncodeContextForOatFile(""));
}