ART: Refactor known-classloader visits
Refactor visiting dex Elements and DexFiles in known classloaders,
unifying the walking code.
Test: m test-art-host
Change-Id: I4203ac4fbb0ee68660aadc0dfbf8affacbc03b8b
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index c667fe2..ebac5c1 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -1122,12 +1122,8 @@
DCHECK(out_dex_file_names != nullptr);
DCHECK(error_msg != nullptr);
ScopedObjectAccessUnchecked soa(Thread::Current());
- ArtField* const dex_path_list_field =
- jni::DecodeArtField(WellKnownClasses::dalvik_system_BaseDexClassLoader_pathList);
- ArtField* const dex_elements_field =
- jni::DecodeArtField(WellKnownClasses::dalvik_system_DexPathList_dexElements);
- CHECK(dex_path_list_field != nullptr);
- CHECK(dex_elements_field != nullptr);
+ StackHandleScope<1> hs(soa.Self());
+ Handle<mirror::ClassLoader> handle(hs.NewHandle(class_loader));
while (!ClassLinker::IsBootClassLoader(soa, class_loader)) {
if (soa.Decode<mirror::Class>(WellKnownClasses::dalvik_system_PathClassLoader) !=
class_loader->GetClass()) {
@@ -1136,32 +1132,29 @@
// Unsupported class loader.
return false;
}
- ObjPtr<mirror::Object> dex_path_list = dex_path_list_field->GetObject(class_loader);
- if (dex_path_list != nullptr) {
- // DexPathList has an array dexElements of Elements[] which each contain a dex file.
- ObjPtr<mirror::Object> dex_elements_obj = dex_elements_field->GetObject(dex_path_list);
- // Loop through each dalvik.system.DexPathList$Element's dalvik.system.DexFile and look
- // at the mCookie which is a DexFile vector.
- if (dex_elements_obj != nullptr) {
- ObjPtr<mirror::ObjectArray<mirror::Object>> dex_elements =
- dex_elements_obj->AsObjectArray<mirror::Object>();
- // Reverse order since we insert the parent at the front.
- for (int32_t i = dex_elements->GetLength() - 1; i >= 0; --i) {
- ObjPtr<mirror::Object> element = dex_elements->GetWithoutChecks(i);
- if (element == nullptr) {
- *error_msg = StringPrintf("Null dex element at index %d", i);
- return false;
- }
- ObjPtr<mirror::String> name;
- if (!GetDexPathListElementName(element, &name)) {
- *error_msg = StringPrintf("Invalid dex path list element at index %d", i);
- return false;
- }
- if (name != nullptr) {
- out_dex_file_names->push_front(name.Ptr());
- }
- }
+ // Get element names. Sets error to true on failure.
+ auto add_element_names = [&](ObjPtr<mirror::Object> element, bool* error)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (element == nullptr) {
+ *error_msg = "Null dex element";
+ *error = true; // Null element is a critical error.
+ return false; // Had an error, stop the visit.
}
+ ObjPtr<mirror::String> name;
+ if (!GetDexPathListElementName(element, &name)) {
+ *error_msg = "Invalid dex path list element";
+ *error = false; // Invalid element is not a critical error.
+ return false; // Stop the visit.
+ }
+ if (name != nullptr) {
+ out_dex_file_names->push_front(name.Ptr());
+ }
+ return true; // Continue with the next Element.
+ };
+ bool error = VisitClassLoaderDexElements(soa, handle, add_element_names, /* error */ false);
+ if (error) {
+ // An error occurred during DexPathList Element visiting.
+ return false;
}
class_loader = class_loader->GetParent();
}
@@ -2444,71 +2437,33 @@
const char* descriptor,
size_t hash,
Handle<mirror::ClassLoader> class_loader) {
- CHECK(IsPathOrDexClassLoader(soa, class_loader) || IsDelegateLastClassLoader(soa, class_loader))
+ DCHECK(IsPathOrDexClassLoader(soa, class_loader) || IsDelegateLastClassLoader(soa, class_loader))
<< "Unexpected class loader for descriptor " << descriptor;
- Thread* self = soa.Self();
- ArtField* const cookie_field =
- jni::DecodeArtField(WellKnownClasses::dalvik_system_DexFile_cookie);
- ArtField* const dex_file_field =
- jni::DecodeArtField(WellKnownClasses::dalvik_system_DexPathList__Element_dexFile);
- ObjPtr<mirror::Object> dex_path_list =
- jni::DecodeArtField(WellKnownClasses::dalvik_system_BaseDexClassLoader_pathList)->
- GetObject(class_loader.Get());
- if (dex_path_list != nullptr && dex_file_field != nullptr && cookie_field != nullptr) {
- // DexPathList has an array dexElements of Elements[] which each contain a dex file.
- ObjPtr<mirror::Object> dex_elements_obj =
- jni::DecodeArtField(WellKnownClasses::dalvik_system_DexPathList_dexElements)->
- GetObject(dex_path_list);
- // Loop through each dalvik.system.DexPathList$Element's dalvik.system.DexFile and look
- // at the mCookie which is a DexFile vector.
- if (dex_elements_obj != nullptr) {
- StackHandleScope<1> hs(self);
- Handle<mirror::ObjectArray<mirror::Object>> dex_elements =
- hs.NewHandle(dex_elements_obj->AsObjectArray<mirror::Object>());
- for (int32_t i = 0; i < dex_elements->GetLength(); ++i) {
- ObjPtr<mirror::Object> element = dex_elements->GetWithoutChecks(i);
- if (element == nullptr) {
- // Should never happen, fall back to java code to throw a NPE.
- break;
- }
- ObjPtr<mirror::Object> dex_file = dex_file_field->GetObject(element);
- if (dex_file != nullptr) {
- ObjPtr<mirror::LongArray> long_array = cookie_field->GetObject(dex_file)->AsLongArray();
- if (long_array == nullptr) {
- // This should never happen so log a warning.
- LOG(WARNING) << "Null DexFile::mCookie for " << descriptor;
- break;
- }
- int32_t long_array_size = long_array->GetLength();
- // First element is the oat file.
- for (int32_t j = kDexFileIndexStart; j < long_array_size; ++j) {
- const DexFile* cp_dex_file = reinterpret_cast<const DexFile*>(static_cast<uintptr_t>(
- long_array->GetWithoutChecks(j)));
- const DexFile::ClassDef* dex_class_def =
- OatDexFile::FindClassDef(*cp_dex_file, descriptor, hash);
- if (dex_class_def != nullptr) {
- ObjPtr<mirror::Class> klass = DefineClass(self,
- descriptor,
- hash,
- class_loader,
- *cp_dex_file,
- *dex_class_def);
- if (klass == nullptr) {
- CHECK(self->IsExceptionPending()) << descriptor;
- self->ClearException();
- // TODO: Is it really right to break here, and not check the other dex files?
- return nullptr;
- }
- return klass;
- }
- }
- }
+ ObjPtr<mirror::Class> ret;
+ auto define_class = [&](const DexFile* cp_dex_file) REQUIRES_SHARED(Locks::mutator_lock_) {
+ const DexFile::ClassDef* dex_class_def =
+ OatDexFile::FindClassDef(*cp_dex_file, descriptor, hash);
+ if (dex_class_def != nullptr) {
+ ObjPtr<mirror::Class> klass = DefineClass(soa.Self(),
+ descriptor,
+ hash,
+ class_loader,
+ *cp_dex_file,
+ *dex_class_def);
+ if (klass == nullptr) {
+ CHECK(soa.Self()->IsExceptionPending()) << descriptor;
+ soa.Self()->ClearException();
+ // TODO: Is it really right to break here, and not check the other dex files?
}
+ ret = klass;
+ return false; // Found a Class (or error == nullptr), stop visit.
}
- self->AssertNoPendingException();
- }
- return nullptr;
+ return true; // Continue with the next DexFile.
+ };
+
+ VisitClassLoaderDexFiles(soa, class_loader, define_class);
+ return ret;
}
mirror::Class* ClassLinker::FindClass(Thread* self,
@@ -7901,42 +7856,19 @@
if (loader->GetClass() == path_class_loader ||
loader->GetClass() == dex_class_loader ||
loader->GetClass() == delegate_last_class_loader) {
- ArtField* const cookie_field =
- jni::DecodeArtField(WellKnownClasses::dalvik_system_DexFile_cookie);
- ArtField* const dex_file_field =
- jni::DecodeArtField(WellKnownClasses::dalvik_system_DexPathList__Element_dexFile);
- ObjPtr<mirror::Object> dex_path_list =
- jni::DecodeArtField(WellKnownClasses::dalvik_system_BaseDexClassLoader_pathList)->
- GetObject(loader);
- if (dex_path_list != nullptr && dex_file_field != nullptr && cookie_field != nullptr) {
- ObjPtr<mirror::Object> dex_elements_obj =
- jni::DecodeArtField(WellKnownClasses::dalvik_system_DexPathList_dexElements)->
- GetObject(dex_path_list);
- if (dex_elements_obj != nullptr) {
- ObjPtr<mirror::ObjectArray<mirror::Object>> dex_elements =
- dex_elements_obj->AsObjectArray<mirror::Object>();
- oss << "(";
- const char* path_separator = "";
- for (int32_t i = 0; i != dex_elements->GetLength(); ++i) {
- ObjPtr<mirror::Object> element = dex_elements->GetWithoutChecks(i);
- ObjPtr<mirror::Object> dex_file =
- (element != nullptr) ? dex_file_field->GetObject(element) : nullptr;
- ObjPtr<mirror::LongArray> long_array =
- (dex_file != nullptr) ? cookie_field->GetObject(dex_file)->AsLongArray() : nullptr;
- if (long_array != nullptr) {
- int32_t long_array_size = long_array->GetLength();
- // First element is the oat file.
- for (int32_t j = kDexFileIndexStart; j < long_array_size; ++j) {
- const DexFile* cp_dex_file = reinterpret_cast<const DexFile*>(
- static_cast<uintptr_t>(long_array->GetWithoutChecks(j)));
- oss << path_separator << cp_dex_file->GetLocation();
- path_separator = ":";
- }
- }
- }
- oss << ")";
- }
- }
+ oss << "(";
+ ScopedObjectAccessUnchecked soa(Thread::Current());
+ StackHandleScope<1> hs(soa.Self());
+ Handle<mirror::ClassLoader> handle(hs.NewHandle(loader));
+ const char* path_separator = "";
+ VisitClassLoaderDexFiles(soa,
+ handle,
+ [&](const DexFile* dex_file) {
+ oss << path_separator << dex_file->GetLocation();
+ path_separator = ":";
+ return true; // Continue with the next DexFile.
+ });
+ oss << ")";
}
}