Avoid std::string allocations for finding an array class.
Introduce ClassLinker::FindArrayClass which performs an array class lookup
given the element/component class. This has a 16 element cache of recently
looked up arrays.
Pass the current thread to ClassLinker Find .. Class routines to avoid calls
to Thread::Current().
Avoid some uses of FindClass in the debugger where WellKnownClasses is a
faster and more compacting GC friendly alternative.
Change-Id: I60e231820b349543a7edb3ceb9cf1ce92db3c843
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 48ec5ab..a165a68 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -176,17 +176,19 @@
: dex_lock_("ClassLinker dex lock", kDefaultMutexLevel),
dex_cache_image_class_lookup_required_(false),
failed_dex_cache_class_lookups_(0),
- class_roots_(NULL),
- array_iftable_(NULL),
+ class_roots_(nullptr),
+ array_iftable_(nullptr),
+ find_array_class_cache_next_victim_(0),
init_done_(false),
dex_caches_dirty_(false),
class_table_dirty_(false),
intern_table_(intern_table),
- portable_resolution_trampoline_(NULL),
- quick_resolution_trampoline_(NULL),
- portable_imt_conflict_trampoline_(NULL),
- quick_imt_conflict_trampoline_(NULL) {
+ portable_resolution_trampoline_(nullptr),
+ quick_resolution_trampoline_(nullptr),
+ portable_imt_conflict_trampoline_(nullptr),
+ quick_imt_conflict_trampoline_(nullptr) {
CHECK_EQ(arraysize(class_roots_descriptors_), size_t(kClassRootsMax));
+ memset(find_array_class_cache_, 0, kFindArrayCacheSize * sizeof(mirror::Class*));
}
void ClassLinker::InitFromCompiler(const std::vector<const DexFile*>& boot_class_path) {
@@ -335,54 +337,54 @@
// Object, String and DexCache need to be rerun through FindSystemClass to finish init
java_lang_Object->SetStatus(mirror::Class::kStatusNotReady, self);
- mirror::Class* Object_class = FindSystemClass("Ljava/lang/Object;");
+ mirror::Class* Object_class = FindSystemClass(self, "Ljava/lang/Object;");
CHECK_EQ(java_lang_Object.get(), Object_class);
CHECK_EQ(java_lang_Object->GetObjectSize(), sizeof(mirror::Object));
java_lang_String->SetStatus(mirror::Class::kStatusNotReady, self);
- mirror::Class* String_class = FindSystemClass("Ljava/lang/String;");
+ mirror::Class* String_class = FindSystemClass(self, "Ljava/lang/String;");
CHECK_EQ(java_lang_String.get(), String_class);
CHECK_EQ(java_lang_String->GetObjectSize(), sizeof(mirror::String));
java_lang_DexCache->SetStatus(mirror::Class::kStatusNotReady, self);
- mirror::Class* DexCache_class = FindSystemClass("Ljava/lang/DexCache;");
+ mirror::Class* DexCache_class = FindSystemClass(self, "Ljava/lang/DexCache;");
CHECK_EQ(java_lang_String.get(), String_class);
CHECK_EQ(java_lang_DexCache.get(), DexCache_class);
CHECK_EQ(java_lang_DexCache->GetObjectSize(), sizeof(mirror::DexCache));
// Setup the primitive array type classes - can't be done until Object has a vtable.
- SetClassRoot(kBooleanArrayClass, FindSystemClass("[Z"));
+ SetClassRoot(kBooleanArrayClass, FindSystemClass(self, "[Z"));
mirror::BooleanArray::SetArrayClass(GetClassRoot(kBooleanArrayClass));
- SetClassRoot(kByteArrayClass, FindSystemClass("[B"));
+ SetClassRoot(kByteArrayClass, FindSystemClass(self, "[B"));
mirror::ByteArray::SetArrayClass(GetClassRoot(kByteArrayClass));
- mirror::Class* found_char_array_class = FindSystemClass("[C");
+ mirror::Class* found_char_array_class = FindSystemClass(self, "[C");
CHECK_EQ(char_array_class.get(), found_char_array_class);
- SetClassRoot(kShortArrayClass, FindSystemClass("[S"));
+ SetClassRoot(kShortArrayClass, FindSystemClass(self, "[S"));
mirror::ShortArray::SetArrayClass(GetClassRoot(kShortArrayClass));
- mirror::Class* found_int_array_class = FindSystemClass("[I");
+ mirror::Class* found_int_array_class = FindSystemClass(self, "[I");
CHECK_EQ(int_array_class.get(), found_int_array_class);
- SetClassRoot(kLongArrayClass, FindSystemClass("[J"));
+ SetClassRoot(kLongArrayClass, FindSystemClass(self, "[J"));
mirror::LongArray::SetArrayClass(GetClassRoot(kLongArrayClass));
- SetClassRoot(kFloatArrayClass, FindSystemClass("[F"));
+ SetClassRoot(kFloatArrayClass, FindSystemClass(self, "[F"));
mirror::FloatArray::SetArrayClass(GetClassRoot(kFloatArrayClass));
- SetClassRoot(kDoubleArrayClass, FindSystemClass("[D"));
+ SetClassRoot(kDoubleArrayClass, FindSystemClass(self, "[D"));
mirror::DoubleArray::SetArrayClass(GetClassRoot(kDoubleArrayClass));
- mirror::Class* found_class_array_class = FindSystemClass("[Ljava/lang/Class;");
+ mirror::Class* found_class_array_class = FindSystemClass(self, "[Ljava/lang/Class;");
CHECK_EQ(class_array_class.get(), found_class_array_class);
- mirror::Class* found_object_array_class = FindSystemClass("[Ljava/lang/Object;");
+ mirror::Class* found_object_array_class = FindSystemClass(self, "[Ljava/lang/Object;");
CHECK_EQ(object_array_class.get(), found_object_array_class);
// Setup the single, global copy of "iftable".
- mirror::Class* java_lang_Cloneable = FindSystemClass("Ljava/lang/Cloneable;");
+ mirror::Class* java_lang_Cloneable = FindSystemClass(self, "Ljava/lang/Cloneable;");
CHECK(java_lang_Cloneable != NULL);
- mirror::Class* java_io_Serializable = FindSystemClass("Ljava/io/Serializable;");
+ mirror::Class* java_io_Serializable = FindSystemClass(self, "Ljava/io/Serializable;");
CHECK(java_io_Serializable != NULL);
// We assume that Cloneable/Serializable don't have superinterfaces -- normally we'd have to
// crawl up and explicitly list all of the supers as well.
@@ -398,73 +400,73 @@
CHECK_EQ(java_io_Serializable, kh.GetDirectInterface(1));
// Run Class, ArtField, and ArtMethod through FindSystemClass. This initializes their
// dex_cache_ fields and register them in class_table_.
- mirror::Class* Class_class = FindSystemClass("Ljava/lang/Class;");
+ mirror::Class* Class_class = FindSystemClass(self, "Ljava/lang/Class;");
CHECK_EQ(java_lang_Class.get(), Class_class);
java_lang_reflect_ArtMethod->SetStatus(mirror::Class::kStatusNotReady, self);
- mirror::Class* Art_method_class = FindSystemClass("Ljava/lang/reflect/ArtMethod;");
+ mirror::Class* Art_method_class = FindSystemClass(self, "Ljava/lang/reflect/ArtMethod;");
CHECK_EQ(java_lang_reflect_ArtMethod.get(), Art_method_class);
java_lang_reflect_ArtField->SetStatus(mirror::Class::kStatusNotReady, self);
- mirror::Class* Art_field_class = FindSystemClass("Ljava/lang/reflect/ArtField;");
+ mirror::Class* Art_field_class = FindSystemClass(self, "Ljava/lang/reflect/ArtField;");
CHECK_EQ(java_lang_reflect_ArtField.get(), Art_field_class);
- mirror::Class* String_array_class = FindSystemClass(class_roots_descriptors_[kJavaLangStringArrayClass]);
+ mirror::Class* String_array_class = FindSystemClass(self, class_roots_descriptors_[kJavaLangStringArrayClass]);
CHECK_EQ(object_array_string.get(), String_array_class);
mirror::Class* Art_method_array_class =
- FindSystemClass(class_roots_descriptors_[kJavaLangReflectArtMethodArrayClass]);
+ FindSystemClass(self, class_roots_descriptors_[kJavaLangReflectArtMethodArrayClass]);
CHECK_EQ(object_array_art_method.get(), Art_method_array_class);
mirror::Class* Art_field_array_class =
- FindSystemClass(class_roots_descriptors_[kJavaLangReflectArtFieldArrayClass]);
+ FindSystemClass(self, class_roots_descriptors_[kJavaLangReflectArtFieldArrayClass]);
CHECK_EQ(object_array_art_field.get(), Art_field_array_class);
// End of special init trickery, subsequent classes may be loaded via FindSystemClass.
// Create java.lang.reflect.Proxy root.
- mirror::Class* java_lang_reflect_Proxy = FindSystemClass("Ljava/lang/reflect/Proxy;");
+ mirror::Class* java_lang_reflect_Proxy = FindSystemClass(self, "Ljava/lang/reflect/Proxy;");
SetClassRoot(kJavaLangReflectProxy, java_lang_reflect_Proxy);
// java.lang.ref classes need to be specially flagged, but otherwise are normal classes
- mirror::Class* java_lang_ref_Reference = FindSystemClass("Ljava/lang/ref/Reference;");
+ mirror::Class* java_lang_ref_Reference = FindSystemClass(self, "Ljava/lang/ref/Reference;");
SetClassRoot(kJavaLangRefReference, java_lang_ref_Reference);
- mirror::Class* java_lang_ref_FinalizerReference = FindSystemClass("Ljava/lang/ref/FinalizerReference;");
+ mirror::Class* java_lang_ref_FinalizerReference = FindSystemClass(self, "Ljava/lang/ref/FinalizerReference;");
java_lang_ref_FinalizerReference->SetAccessFlags(
java_lang_ref_FinalizerReference->GetAccessFlags() |
kAccClassIsReference | kAccClassIsFinalizerReference);
- mirror::Class* java_lang_ref_PhantomReference = FindSystemClass("Ljava/lang/ref/PhantomReference;");
+ mirror::Class* java_lang_ref_PhantomReference = FindSystemClass(self, "Ljava/lang/ref/PhantomReference;");
java_lang_ref_PhantomReference->SetAccessFlags(
java_lang_ref_PhantomReference->GetAccessFlags() |
kAccClassIsReference | kAccClassIsPhantomReference);
- mirror::Class* java_lang_ref_SoftReference = FindSystemClass("Ljava/lang/ref/SoftReference;");
+ mirror::Class* java_lang_ref_SoftReference = FindSystemClass(self, "Ljava/lang/ref/SoftReference;");
java_lang_ref_SoftReference->SetAccessFlags(
java_lang_ref_SoftReference->GetAccessFlags() | kAccClassIsReference);
- mirror::Class* java_lang_ref_WeakReference = FindSystemClass("Ljava/lang/ref/WeakReference;");
+ mirror::Class* java_lang_ref_WeakReference = FindSystemClass(self, "Ljava/lang/ref/WeakReference;");
java_lang_ref_WeakReference->SetAccessFlags(
java_lang_ref_WeakReference->GetAccessFlags() |
kAccClassIsReference | kAccClassIsWeakReference);
// Setup the ClassLoader, verifying the object_size_.
- mirror::Class* java_lang_ClassLoader = FindSystemClass("Ljava/lang/ClassLoader;");
+ mirror::Class* java_lang_ClassLoader = FindSystemClass(self, "Ljava/lang/ClassLoader;");
CHECK_EQ(java_lang_ClassLoader->GetObjectSize(), sizeof(mirror::ClassLoader));
SetClassRoot(kJavaLangClassLoader, java_lang_ClassLoader);
// Set up java.lang.Throwable, java.lang.ClassNotFoundException, and
// java.lang.StackTraceElement as a convenience.
- SetClassRoot(kJavaLangThrowable, FindSystemClass("Ljava/lang/Throwable;"));
+ SetClassRoot(kJavaLangThrowable, FindSystemClass(self, "Ljava/lang/Throwable;"));
mirror::Throwable::SetClass(GetClassRoot(kJavaLangThrowable));
- SetClassRoot(kJavaLangClassNotFoundException, FindSystemClass("Ljava/lang/ClassNotFoundException;"));
- SetClassRoot(kJavaLangStackTraceElement, FindSystemClass("Ljava/lang/StackTraceElement;"));
- SetClassRoot(kJavaLangStackTraceElementArrayClass, FindSystemClass("[Ljava/lang/StackTraceElement;"));
+ SetClassRoot(kJavaLangClassNotFoundException, FindSystemClass(self, "Ljava/lang/ClassNotFoundException;"));
+ SetClassRoot(kJavaLangStackTraceElement, FindSystemClass(self, "Ljava/lang/StackTraceElement;"));
+ SetClassRoot(kJavaLangStackTraceElementArrayClass, FindSystemClass(self, "[Ljava/lang/StackTraceElement;"));
mirror::StackTraceElement::SetClass(GetClassRoot(kJavaLangStackTraceElement));
- FinishInit();
+ FinishInit(self);
VLOG(startup) << "ClassLinker::InitFromCompiler exiting";
}
-void ClassLinker::FinishInit() {
+void ClassLinker::FinishInit(Thread* self) {
VLOG(startup) << "ClassLinker::FinishInit entering";
// Let the heap know some key offsets into java.lang.ref instances
@@ -473,7 +475,7 @@
// fully initialized
mirror::Class* java_lang_ref_Reference = GetClassRoot(kJavaLangRefReference);
mirror::Class* java_lang_ref_FinalizerReference =
- FindSystemClass("Ljava/lang/ref/FinalizerReference;");
+ FindSystemClass(self, "Ljava/lang/ref/FinalizerReference;");
mirror::ArtField* pendingNext = java_lang_ref_Reference->GetInstanceField(0);
FieldHelper fh(pendingNext);
@@ -1111,7 +1113,7 @@
mirror::Throwable::SetClass(GetClassRoot(kJavaLangThrowable));
mirror::StackTraceElement::SetClass(GetClassRoot(kJavaLangStackTraceElement));
- FinishInit();
+ FinishInit(self);
VLOG(startup) << "ClassLinker::InitFromImage exiting";
}
@@ -1150,6 +1152,13 @@
}
callback(reinterpret_cast<mirror::Object**>(&array_iftable_), arg, 0, kRootVMInternal);
DCHECK(array_iftable_ != nullptr);
+ for (size_t i = 0; i < kFindArrayCacheSize; ++i) {
+ if (find_array_class_cache_[i] != nullptr) {
+ callback(reinterpret_cast<mirror::Object**>(&find_array_class_cache_[i]), arg, 0,
+ kRootVMInternal);
+ DCHECK(find_array_class_cache_[i] != nullptr);
+ }
+ }
}
void ClassLinker::VisitClasses(ClassVisitor* visitor, void* arg) {
@@ -1307,21 +1316,10 @@
return klass;
}
-bool ClassLinker::IsInBootClassPath(const char* descriptor) {
- DexFile::ClassPathEntry pair = DexFile::FindInClassPath(descriptor, boot_class_path_);
- return pair.second != NULL;
-}
-
-mirror::Class* ClassLinker::FindSystemClass(const char* descriptor) {
- SirtRef<mirror::ClassLoader> class_loader(Thread::Current(), nullptr);
- return FindClass(descriptor, class_loader);
-}
-
-mirror::Class* ClassLinker::FindClass(const char* descriptor,
+mirror::Class* ClassLinker::FindClass(Thread* self, const char* descriptor,
const SirtRef<mirror::ClassLoader>& class_loader) {
DCHECK_NE(*descriptor, '\0') << "descriptor is empty string";
- Thread* self = Thread::Current();
- DCHECK(self != NULL);
+ DCHECK(self != nullptr);
self->AssertNoPendingException();
if (descriptor[1] == '\0') {
// only the descriptors of primitive types should be 1 character long, also avoid class lookup
@@ -1335,7 +1333,7 @@
}
// Class is not yet loaded.
if (descriptor[0] == '[') {
- return CreateArrayClass(descriptor, class_loader);
+ return CreateArrayClass(self, descriptor, class_loader);
} else if (class_loader.get() == nullptr) {
DexFile::ClassPathEntry pair = DexFile::FindInClassPath(descriptor, boot_class_path_);
if (pair.second != NULL) {
@@ -1346,7 +1344,7 @@
// First try the boot class path, we check the descriptor first to avoid an unnecessary
// throw of a NoClassDefFoundError.
if (IsInBootClassPath(descriptor)) {
- mirror::Class* system_class = FindSystemClass(descriptor);
+ mirror::Class* system_class = FindSystemClass(self, descriptor);
CHECK(system_class != NULL);
return system_class;
}
@@ -1365,7 +1363,7 @@
}
} else {
- ScopedObjectAccessUnchecked soa(self->GetJniEnv());
+ ScopedObjectAccessUnchecked soa(self);
ScopedLocalRef<jobject> class_loader_object(soa.Env(),
soa.AddLocalReference<jobject>(class_loader.get()));
std::string class_name_string(DescriptorToDot(descriptor));
@@ -1382,7 +1380,7 @@
WellKnownClasses::java_lang_ClassLoader_loadClass,
class_name_object.get()));
}
- if (soa.Self()->IsExceptionPending()) {
+ if (self->IsExceptionPending()) {
// If the ClassLoader threw, pass that exception up.
return NULL;
} else if (result.get() == NULL) {
@@ -2133,12 +2131,11 @@
// array class; that always comes from the base element class.
//
// Returns NULL with an exception raised on failure.
-mirror::Class* ClassLinker::CreateArrayClass(const char* descriptor,
+mirror::Class* ClassLinker::CreateArrayClass(Thread* self, const char* descriptor,
const SirtRef<mirror::ClassLoader>& class_loader) {
// Identify the underlying component type
CHECK_EQ('[', descriptor[0]);
- Thread* self = Thread::Current();
- SirtRef<mirror::Class> component_type(self, FindClass(descriptor + 1, class_loader));
+ SirtRef<mirror::Class> component_type(self, FindClass(self, descriptor + 1, class_loader));
if (component_type.get() == nullptr) {
DCHECK(self->IsExceptionPending());
return nullptr;
@@ -3242,7 +3239,7 @@
for (int i = super->GetVTable()->GetLength() - 1; i >= 0; --i) {
mirror::ArtMethod* method = klass->GetVTable()->Get(i);
if (method != super->GetVTable()->Get(i) &&
- !IsSameMethodSignatureInDifferentClassContexts(method, super.get(), klass.get())) {
+ !IsSameMethodSignatureInDifferentClassContexts(self, method, super.get(), klass.get())) {
ThrowLinkageError(klass.get(), "Class %s method %s resolves differently in superclass %s",
PrettyDescriptor(klass.get()).c_str(), PrettyMethod(method).c_str(),
PrettyDescriptor(super.get()).c_str());
@@ -3255,7 +3252,7 @@
if (klass->GetClassLoader() != interface->GetClassLoader()) {
for (size_t j = 0; j < interface->NumVirtualMethods(); ++j) {
mirror::ArtMethod* method = klass->GetIfTable()->GetMethodArray(i)->Get(j);
- if (!IsSameMethodSignatureInDifferentClassContexts(method, interface.get(),
+ if (!IsSameMethodSignatureInDifferentClassContexts(self, method, interface.get(),
method->GetDeclaringClass())) {
ThrowLinkageError(klass.get(), "Class %s method %s resolves differently in interface %s",
PrettyDescriptor(method->GetDeclaringClass()).c_str(),
@@ -3271,13 +3268,13 @@
// Returns true if classes referenced by the signature of the method are the
// same classes in klass1 as they are in klass2.
-bool ClassLinker::IsSameMethodSignatureInDifferentClassContexts(mirror::ArtMethod* method,
+bool ClassLinker::IsSameMethodSignatureInDifferentClassContexts(Thread* self,
+ mirror::ArtMethod* method,
mirror::Class* klass1,
mirror::Class* klass2) {
if (klass1 == klass2) {
return true;
}
- Thread* self = Thread::Current();
CHECK(klass1 != nullptr);
CHECK(klass2 != nullptr);
SirtRef<mirror::ClassLoader> loader1(self, klass1->GetClassLoader());
@@ -3292,7 +3289,7 @@
}
if (descriptor[0] == 'L' || descriptor[0] == '[') {
// Found a non-primitive type.
- if (!IsSameDescriptorInDifferentClassContexts(descriptor, loader1, loader2)) {
+ if (!IsSameDescriptorInDifferentClassContexts(self, descriptor, loader1, loader2)) {
return false;
}
}
@@ -3300,7 +3297,7 @@
// Check the return type
const char* descriptor = dex_file.GetReturnTypeDescriptor(proto_id);
if (descriptor[0] == 'L' || descriptor[0] == '[') {
- if (!IsSameDescriptorInDifferentClassContexts(descriptor, loader1, loader2)) {
+ if (!IsSameDescriptorInDifferentClassContexts(self, descriptor, loader1, loader2)) {
return false;
}
}
@@ -3308,16 +3305,15 @@
}
// Returns true if the descriptor resolves to the same class in the context of loader1 and loader2.
-bool ClassLinker::IsSameDescriptorInDifferentClassContexts(const char* descriptor,
+bool ClassLinker::IsSameDescriptorInDifferentClassContexts(Thread* self, const char* descriptor,
SirtRef<mirror::ClassLoader>& loader1,
SirtRef<mirror::ClassLoader>& loader2) {
CHECK(descriptor != nullptr);
- Thread* self = Thread::Current();
- SirtRef<mirror::Class> found1(self, FindClass(descriptor, loader1));
+ SirtRef<mirror::Class> found1(self, FindClass(self, descriptor, loader1));
if (found1.get() == nullptr) {
self->ClearException();
}
- mirror::Class* found2 = FindClass(descriptor, loader2);
+ mirror::Class* found2 = FindClass(self, descriptor, loader2);
if (found2 == nullptr) {
self->ClearException();
}
@@ -4117,22 +4113,22 @@
DCHECK(dex_cache.get() != NULL);
mirror::Class* resolved = dex_cache->GetResolvedType(type_idx);
if (resolved == NULL) {
+ Thread* self = Thread::Current();
const char* descriptor = dex_file.StringByTypeIdx(type_idx);
- resolved = FindClass(descriptor, class_loader);
+ resolved = FindClass(self, descriptor, class_loader);
if (resolved != NULL) {
// TODO: we used to throw here if resolved's class loader was not the
// boot class loader. This was to permit different classes with the
// same name to be loaded simultaneously by different loaders
dex_cache->SetResolvedType(type_idx, resolved);
} else {
- Thread* self = Thread::Current();
CHECK(self->IsExceptionPending())
<< "Expected pending exception for failed resolution of: " << descriptor;
// Convert a ClassNotFoundException to a NoClassDefFoundError.
SirtRef<mirror::Throwable> cause(self, self->GetException(NULL));
if (cause->InstanceOf(GetClassRoot(kJavaLangClassNotFoundException))) {
DCHECK(resolved == NULL); // No SirtRef needed to preserve resolved.
- Thread::Current()->ClearException();
+ self->ClearException();
ThrowNoClassDefFoundError("Failed resolution of: %s", descriptor);
self->GetException(NULL)->SetCause(cause.get());
}