Merge "Add ClassLoader to app-image roots."
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index b22ca47..9c38445 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -1113,11 +1113,15 @@
}
// build an Object[] of the roots needed to restore the runtime
+ int32_t image_roots_size = ImageHeader::NumberOfImageRoots(compile_app_image_);
auto image_roots(hs.NewHandle(
- ObjectArray<Object>::Alloc(self, object_array_class.Get(), ImageHeader::kImageRootsMax)));
+ ObjectArray<Object>::Alloc(self, object_array_class.Get(), image_roots_size)));
image_roots->Set<false>(ImageHeader::kDexCaches, dex_caches.Get());
image_roots->Set<false>(ImageHeader::kClassRoots, class_linker->GetClassRoots());
- for (int i = 0; i < ImageHeader::kImageRootsMax; i++) {
+ // image_roots[ImageHeader::kClassLoader] will be set later for app image.
+ static_assert(ImageHeader::kClassLoader + 1u == ImageHeader::kImageRootsMax,
+ "Class loader should be the last image root.");
+ for (int32_t i = 0; i < ImageHeader::kImageRootsMax - 1; ++i) {
CHECK(image_roots->Get(i) != nullptr);
}
return image_roots.Get();
@@ -1539,6 +1543,12 @@
}
// Process the work stack in case anything was added by TryAssignBinSlot.
ProcessWorkStack(&work_stack);
+
+ // Store the class loader in the class roots.
+ CHECK_EQ(class_loaders_.size(), 1u);
+ CHECK_EQ(image_roots.size(), 1u);
+ CHECK(*class_loaders_.begin() != nullptr);
+ image_roots[0]->Set<false>(ImageHeader::kClassLoader, *class_loaders_.begin());
}
// Verify that all objects have assigned image bin slots.
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index e4462d8..17b47a4 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -89,6 +89,7 @@
const char* image_roots_descriptions_[] = {
"kDexCaches",
"kClassRoots",
+ "kClassLoader",
};
// Map is so that we don't allocate multiple dex files for the same OatDexFile.
@@ -1506,12 +1507,13 @@
os << "ROOTS: " << reinterpret_cast<void*>(image_header_.GetImageRoots()) << "\n";
static_assert(arraysize(image_roots_descriptions_) ==
static_cast<size_t>(ImageHeader::kImageRootsMax), "sizes must match");
- for (int i = 0; i < ImageHeader::kImageRootsMax; i++) {
+ DCHECK_LE(image_header_.GetImageRoots()->GetLength(), ImageHeader::kImageRootsMax);
+ for (int32_t i = 0, size = image_header_.GetImageRoots()->GetLength(); i != size; ++i) {
ImageHeader::ImageRoot image_root = static_cast<ImageHeader::ImageRoot>(i);
const char* image_root_description = image_roots_descriptions_[i];
mirror::Object* image_root_object = image_header_.GetImageRoot(image_root);
indent_os << StringPrintf("%s: %p\n", image_root_description, image_root_object);
- if (image_root_object->IsObjectArray()) {
+ if (image_root_object != nullptr && image_root_object->IsObjectArray()) {
mirror::ObjectArray<mirror::Object>* image_root_object_array
= image_root_object->AsObjectArray<mirror::Object>();
ScopedIndentation indent2(&vios_);
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index f3a5be2..6565f6b 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -1655,13 +1655,6 @@
Runtime* const runtime = Runtime::Current();
gc::Heap* const heap = runtime->GetHeap();
Thread* const self = Thread::Current();
- StackHandleScope<2> hs(self);
- Handle<mirror::ObjectArray<mirror::DexCache>> dex_caches(
- hs.NewHandle(dex_caches_object->AsObjectArray<mirror::DexCache>()));
- Handle<mirror::ObjectArray<mirror::Class>> class_roots(hs.NewHandle(
- header.GetImageRoot(ImageHeader::kClassRoots)->AsObjectArray<mirror::Class>()));
- const OatFile* oat_file = space->GetOatFile();
- std::unordered_set<mirror::ClassLoader*> image_class_loaders;
// Check that the image is what we are expecting.
if (image_pointer_size_ != space->GetImageHeader().GetPointerSize()) {
*error_msg = StringPrintf("Application image pointer size does not match runtime: %zu vs %zu",
@@ -1669,6 +1662,22 @@
image_pointer_size_);
return false;
}
+ size_t expected_image_roots = ImageHeader::NumberOfImageRoots(app_image);
+ if (static_cast<size_t>(header.GetImageRoots()->GetLength()) != expected_image_roots) {
+ *error_msg = StringPrintf("Expected %zu image roots but got %d",
+ expected_image_roots,
+ header.GetImageRoots()->GetLength());
+ return false;
+ }
+ StackHandleScope<3> hs(self);
+ Handle<mirror::ObjectArray<mirror::DexCache>> dex_caches(
+ hs.NewHandle(dex_caches_object->AsObjectArray<mirror::DexCache>()));
+ Handle<mirror::ObjectArray<mirror::Class>> class_roots(hs.NewHandle(
+ header.GetImageRoot(ImageHeader::kClassRoots)->AsObjectArray<mirror::Class>()));
+ static_assert(ImageHeader::kClassLoader + 1u == ImageHeader::kImageRootsMax,
+ "Class loader should be the last image root.");
+ MutableHandle<mirror::ClassLoader> image_class_loader(hs.NewHandle(
+ app_image ? header.GetImageRoot(ImageHeader::kClassLoader)->AsClassLoader() : nullptr));
DCHECK(class_roots.Get() != nullptr);
if (class_roots->GetLength() != static_cast<int32_t>(kClassRootsMax)) {
*error_msg = StringPrintf("Expected %d class roots but got %d",
@@ -1683,6 +1692,7 @@
return false;
}
}
+ const OatFile* oat_file = space->GetOatFile();
if (oat_file->GetOatHeader().GetDexFileCount() !=
static_cast<uint32_t>(dex_caches->GetLength())) {
*error_msg = "Dex cache count and dex file count mismatch while trying to initialize from "
@@ -1715,15 +1725,11 @@
// The current dex file field is bogus, overwrite it so that we can get the dex file in the
// loop below.
h_dex_cache->SetDexFile(dex_file.get());
- // Check that each class loader resolved the same way.
- // TODO: Store image class loaders as image roots.
GcRoot<mirror::Class>* const types = h_dex_cache->GetResolvedTypes();
for (int32_t j = 0, num_types = h_dex_cache->NumResolvedTypes(); j < num_types; j++) {
ObjPtr<mirror::Class> klass = types[j].Read();
if (klass != nullptr) {
DCHECK_NE(klass->GetStatus(), mirror::Class::kStatusError);
- ObjPtr<mirror::ClassLoader> image_class_loader = klass->GetClassLoader();
- image_class_loaders.insert(image_class_loader.Ptr());
}
}
} else {
@@ -1749,59 +1755,57 @@
// for PathClassLoader does this by looping through the array of dex files. To ensure they
// resolve the same way, simply flatten the hierarchy in the way the resolution order would be,
// and check that the dex file names are the same.
- for (ObjPtr<mirror::ClassLoader> image_class_loader : image_class_loaders) {
- if (IsBootClassLoader(soa, image_class_loader)) {
- // The dex cache can reference types from the boot class loader.
- continue;
+ if (IsBootClassLoader(soa, image_class_loader.Get())) {
+ *error_msg = "Unexpected BootClassLoader in app image";
+ return false;
+ }
+ std::list<mirror::String*> image_dex_file_names;
+ std::string temp_error_msg;
+ if (!FlattenPathClassLoader(image_class_loader.Get(), &image_dex_file_names, &temp_error_msg)) {
+ *error_msg = StringPrintf("Failed to flatten image class loader hierarchy '%s'",
+ temp_error_msg.c_str());
+ return false;
+ }
+ std::list<mirror::String*> loader_dex_file_names;
+ if (!FlattenPathClassLoader(class_loader.Get(), &loader_dex_file_names, &temp_error_msg)) {
+ *error_msg = StringPrintf("Failed to flatten class loader hierarchy '%s'",
+ temp_error_msg.c_str());
+ return false;
+ }
+ // Add the temporary dex path list elements at the end.
+ auto elements = soa.Decode<mirror::ObjectArray<mirror::Object>>(dex_elements);
+ for (size_t i = 0, num_elems = elements->GetLength(); i < num_elems; ++i) {
+ ObjPtr<mirror::Object> element = elements->GetWithoutChecks(i);
+ if (element != nullptr) {
+ // If we are somewhere in the middle of the array, there may be nulls at the end.
+ loader_dex_file_names.push_back(GetDexPathListElementName(element));
}
- std::list<mirror::String*> image_dex_file_names;
- std::string temp_error_msg;
- if (!FlattenPathClassLoader(image_class_loader, &image_dex_file_names, &temp_error_msg)) {
- *error_msg = StringPrintf("Failed to flatten image class loader hierarchy '%s'",
- temp_error_msg.c_str());
- return false;
+ }
+ // Ignore the number of image dex files since we are adding those to the class loader anyways.
+ CHECK_GE(static_cast<size_t>(image_dex_file_names.size()),
+ static_cast<size_t>(dex_caches->GetLength()));
+ size_t image_count = image_dex_file_names.size() - dex_caches->GetLength();
+ // Check that the dex file names match.
+ bool equal = image_count == loader_dex_file_names.size();
+ if (equal) {
+ auto it1 = image_dex_file_names.begin();
+ auto it2 = loader_dex_file_names.begin();
+ for (size_t i = 0; equal && i < image_count; ++i, ++it1, ++it2) {
+ equal = equal && (*it1)->Equals(*it2);
}
- std::list<mirror::String*> loader_dex_file_names;
- if (!FlattenPathClassLoader(class_loader.Get(), &loader_dex_file_names, &temp_error_msg)) {
- *error_msg = StringPrintf("Failed to flatten class loader hierarchy '%s'",
- temp_error_msg.c_str());
- return false;
+ }
+ if (!equal) {
+ VLOG(image) << "Image dex files " << image_dex_file_names.size();
+ for (ObjPtr<mirror::String> name : image_dex_file_names) {
+ VLOG(image) << name->ToModifiedUtf8();
}
- // Add the temporary dex path list elements at the end.
- auto elements = soa.Decode<mirror::ObjectArray<mirror::Object>>(dex_elements);
- for (size_t i = 0, num_elems = elements->GetLength(); i < num_elems; ++i) {
- ObjPtr<mirror::Object> element = elements->GetWithoutChecks(i);
- if (element != nullptr) {
- // If we are somewhere in the middle of the array, there may be nulls at the end.
- loader_dex_file_names.push_back(GetDexPathListElementName(element));
- }
+ VLOG(image) << "Loader dex files " << loader_dex_file_names.size();
+ for (ObjPtr<mirror::String> name : loader_dex_file_names) {
+ VLOG(image) << name->ToModifiedUtf8();
}
- // Ignore the number of image dex files since we are adding those to the class loader anyways.
- CHECK_GE(static_cast<size_t>(image_dex_file_names.size()),
- static_cast<size_t>(dex_caches->GetLength()));
- size_t image_count = image_dex_file_names.size() - dex_caches->GetLength();
- // Check that the dex file names match.
- bool equal = image_count == loader_dex_file_names.size();
- if (equal) {
- auto it1 = image_dex_file_names.begin();
- auto it2 = loader_dex_file_names.begin();
- for (size_t i = 0; equal && i < image_count; ++i, ++it1, ++it2) {
- equal = equal && (*it1)->Equals(*it2);
- }
- }
- if (!equal) {
- VLOG(image) << "Image dex files " << image_dex_file_names.size();
- for (ObjPtr<mirror::String> name : image_dex_file_names) {
- VLOG(image) << name->ToModifiedUtf8();
- }
- VLOG(image) << "Loader dex files " << loader_dex_file_names.size();
- for (ObjPtr<mirror::String> name : loader_dex_file_names) {
- VLOG(image) << name->ToModifiedUtf8();
- }
- *error_msg = "Rejecting application image due to class loader mismatch";
- // Ignore class loader mismatch for now since these would just use possibly incorrect
- // oat code anyways. The structural class check should be done in the parent.
- }
+ *error_msg = "Rejecting application image due to class loader mismatch";
+ // Ignore class loader mismatch for now since these would just use possibly incorrect
+ // oat code anyways. The structural class check should be done in the parent.
}
}
diff --git a/runtime/image.h b/runtime/image.h
index da9976a..6c76f49 100644
--- a/runtime/image.h
+++ b/runtime/image.h
@@ -189,6 +189,7 @@
enum ImageRoot {
kDexCaches,
kClassRoots,
+ kClassLoader, // App image only.
kImageRootsMax,
};
@@ -206,6 +207,10 @@
kSectionCount, // Number of elements in enum.
};
+ static size_t NumberOfImageRoots(bool app_image) {
+ return app_image ? kImageRootsMax : kImageRootsMax - 1u;
+ }
+
ArtMethod* GetImageMethod(ImageMethod index) const;
void SetImageMethod(ImageMethod index, ArtMethod* method);
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 59c5961..0977093 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -1721,7 +1721,7 @@
if (space->IsImageSpace()) {
auto* image_space = space->AsImageSpace();
const auto& image_header = image_space->GetImageHeader();
- for (size_t i = 0; i < ImageHeader::kImageRootsMax; ++i) {
+ for (int32_t i = 0, size = image_header.GetImageRoots()->GetLength(); i != size; ++i) {
auto* obj = image_header.GetImageRoot(static_cast<ImageHeader::ImageRoot>(i));
if (obj != nullptr) {
auto* after_obj = obj;