Add fast path for FindClass using the type dex file.
If we are using the PathClassLoader with a BootClassLoader
parent, we can handle the common case in the FindClass function
without needing to go back to java code.
Around 10% speedup measured of maps launch, could be noise due to
large variation of app launch times. Eliminates defineClassNative
from being anywhere near the top of sampling profiles.
Bug: 17397179
Bug: 16828525
(cherry picked from commit 8a39e7fe02e9a81853dc7a75cb50d9ece07a9b37)
Change-Id: I1f31de76c1b1a53e32173b1e61a59b0e2f267c98
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 1e64c00..9c2cc6c 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -2093,7 +2093,6 @@
// The boot class loader, search the boot class path.
ClassPathEntry pair = FindInClassPath(descriptor, boot_class_path_);
if (pair.second != nullptr) {
- StackHandleScope<1> hs(self);
return DefineClass(descriptor, NullHandle<mirror::ClassLoader>(), *pair.first, *pair.second);
} else {
// The boot class loader is searched ahead of the application class loader, failures are
@@ -2132,6 +2131,87 @@
}
} else {
ScopedObjectAccessUnchecked soa(self);
+ if (class_loader->GetClass() ==
+ soa.Decode<mirror::Class*>(WellKnownClasses::dalvik_system_PathClassLoader) &&
+ class_loader->GetParent()->GetClass() ==
+ soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_BootClassLoader)) {
+ ClassPathEntry pair = FindInClassPath(descriptor, boot_class_path_);
+ // Check if this would be found in the parent boot class loader.
+ if (pair.second != nullptr) {
+ mirror::Class* klass = LookupClass(descriptor, nullptr);
+ if (klass != nullptr) {
+ return klass;
+ }
+ klass = DefineClass(descriptor, NullHandle<mirror::ClassLoader>(), *pair.first,
+ *pair.second);
+ if (klass == nullptr) {
+ CHECK(self->IsExceptionPending()) << descriptor;
+ self->ClearException();
+ } else {
+ return klass;
+ }
+ } else {
+ // RegisterDexFile may allocate dex caches (and cause thread suspension).
+ StackHandleScope<3> hs(self);
+ // The class loader is a PathClassLoader which inherits from BaseDexClassLoader.
+ // We need to get the DexPathList and loop through it.
+ Handle<mirror::ArtField> cookie_field =
+ hs.NewHandle(soa.DecodeField(WellKnownClasses::dalvik_system_DexFile_cookie));
+ Handle<mirror::ArtField> dex_file_field =
+ hs.NewHandle(
+ soa.DecodeField(WellKnownClasses::dalvik_system_DexPathList$Element_dexFile));
+ mirror::Object* dex_path_list =
+ soa.DecodeField(WellKnownClasses::dalvik_system_PathClassLoader_pathList)->
+ GetObject(class_loader.Get());
+ if (dex_path_list != nullptr && dex_file_field.Get() != nullptr &&
+ cookie_field.Get() != nullptr) {
+ // DexPathList has an array dexElements of Elements[] which each contain a dex file.
+ mirror::Object* dex_elements_obj =
+ soa.DecodeField(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) {
+ 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) {
+ mirror::Object* element = dex_elements->GetWithoutChecks(i);
+ if (element == nullptr) {
+ // Should never happen, fall back to java code to throw a NPE.
+ break;
+ }
+ mirror::Object* dex_file = dex_file_field->GetObject(element);
+ if (dex_file != nullptr) {
+ const uint64_t cookie = cookie_field->GetLong(dex_file);
+ auto* dex_files =
+ reinterpret_cast<std::vector<const DexFile*>*>(static_cast<uintptr_t>(cookie));
+ if (dex_files == nullptr) {
+ // This should never happen so log a warning.
+ LOG(WARNING) << "Null DexFile::mCookie for " << descriptor;
+ break;
+ }
+ for (const DexFile* dex_file : *dex_files) {
+ const DexFile::ClassDef* dex_class_def = dex_file->FindClassDef(descriptor);
+ if (dex_class_def != nullptr) {
+ RegisterDexFile(*dex_file);
+ mirror::Class* klass =
+ DefineClass(descriptor, class_loader, *dex_file, *dex_class_def);
+ if (klass == nullptr) {
+ CHECK(self->IsExceptionPending()) << descriptor;
+ self->ClearException();
+ // Exit the loop to make the java code generate an exception.
+ i = dex_elements->GetLength();
+ break;
+ }
+ return klass;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
ScopedLocalRef<jobject> class_loader_object(soa.Env(),
soa.AddLocalReference<jobject>(class_loader.Get()));
std::string class_name_string(DescriptorToDot(descriptor));