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_test.cc b/runtime/class_linker_test.cc
index ebf02fe..d6a67cc 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -41,18 +41,20 @@
protected:
void AssertNonExistentClass(const std::string& descriptor)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- EXPECT_TRUE(class_linker_->FindSystemClass(descriptor.c_str()) == NULL);
Thread* self = Thread::Current();
+ EXPECT_TRUE(class_linker_->FindSystemClass(self, descriptor.c_str()) == NULL);
EXPECT_TRUE(self->IsExceptionPending());
mirror::Object* exception = self->GetException(NULL);
self->ClearException();
- mirror::Class* exception_class = class_linker_->FindSystemClass("Ljava/lang/NoClassDefFoundError;");
+ mirror::Class* exception_class =
+ class_linker_->FindSystemClass(self, "Ljava/lang/NoClassDefFoundError;");
EXPECT_TRUE(exception->InstanceOf(exception_class));
}
void AssertPrimitiveClass(const std::string& descriptor)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- AssertPrimitiveClass(descriptor, class_linker_->FindSystemClass(descriptor.c_str()));
+ Thread* self = Thread::Current();
+ AssertPrimitiveClass(descriptor, class_linker_->FindSystemClass(self, descriptor.c_str()));
}
void AssertPrimitiveClass(const std::string& descriptor, mirror::Class* primitive)
@@ -98,7 +100,7 @@
Thread* self = Thread::Current();
SirtRef<mirror::ClassLoader> loader(self, class_loader);
SirtRef<mirror::Class> array(self,
- class_linker_->FindClass(array_descriptor.c_str(), loader));
+ class_linker_->FindClass(self, array_descriptor.c_str(), loader));
ClassHelper array_component_ch(array->GetComponentType());
EXPECT_STREQ(component_type.c_str(), array_component_ch.GetDescriptor());
EXPECT_EQ(class_loader, array->GetClassLoader());
@@ -115,7 +117,8 @@
EXPECT_TRUE(array->GetClass()->GetSuperClass() != NULL);
ASSERT_STREQ(array_descriptor.c_str(), kh.GetDescriptor());
EXPECT_TRUE(array->GetSuperClass() != NULL);
- EXPECT_EQ(class_linker_->FindSystemClass("Ljava/lang/Object;"), array->GetSuperClass());
+ Thread* self = Thread::Current();
+ EXPECT_EQ(class_linker_->FindSystemClass(self, "Ljava/lang/Object;"), array->GetSuperClass());
EXPECT_TRUE(array->HasSuperClass());
ASSERT_TRUE(array->GetComponentType() != NULL);
kh.ChangeClass(array->GetComponentType());
@@ -147,6 +150,7 @@
kh.ChangeClass(array.get());
kh.ChangeClass(kh.GetDirectInterface(1));
EXPECT_STREQ(kh.GetDescriptor(), "Ljava/io/Serializable;");
+ EXPECT_EQ(class_linker_->FindArrayClass(self, array->GetComponentType()), array.get());
}
void AssertMethod(mirror::ArtMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -300,8 +304,8 @@
void AssertDexFileClass(mirror::ClassLoader* class_loader, const std::string& descriptor)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
ASSERT_TRUE(descriptor != NULL);
- SirtRef<mirror::Class> klass(Thread::Current(),
- class_linker_->FindSystemClass(descriptor.c_str()));
+ Thread* self = Thread::Current();
+ SirtRef<mirror::Class> klass(self, class_linker_->FindSystemClass(self, descriptor.c_str()));
ASSERT_TRUE(klass.get() != nullptr);
EXPECT_STREQ(descriptor.c_str(), ClassHelper(klass.get()).GetDescriptor());
EXPECT_EQ(class_loader, klass->GetClassLoader());
@@ -359,7 +363,9 @@
std::vector<CheckOffset> offsets;
bool Check() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- mirror::Class* klass = Runtime::Current()->GetClassLinker()->FindSystemClass(class_descriptor.c_str());
+ Thread* self = Thread::Current();
+ mirror::Class* klass =
+ Runtime::Current()->GetClassLinker()->FindSystemClass(self, class_descriptor.c_str());
CHECK(klass != NULL) << class_descriptor;
bool error = false;
@@ -646,12 +652,12 @@
ScopedObjectAccess soa(Thread::Current());
SirtRef<mirror::ClassLoader> class_loader(soa.Self(), soa.Decode<mirror::ClassLoader*>(LoadDex("Nested")));
- mirror::Class* outer = class_linker_->FindClass("LNested;", class_loader);
+ mirror::Class* outer = class_linker_->FindClass(soa.Self(), "LNested;", class_loader);
ASSERT_TRUE(outer != NULL);
EXPECT_EQ(0U, outer->NumVirtualMethods());
EXPECT_EQ(1U, outer->NumDirectMethods());
- mirror::Class* inner = class_linker_->FindClass("LNested$Inner;", class_loader);
+ mirror::Class* inner = class_linker_->FindClass(soa.Self(), "LNested$Inner;", class_loader);
ASSERT_TRUE(inner != NULL);
EXPECT_EQ(0U, inner->NumVirtualMethods());
EXPECT_EQ(1U, inner->NumDirectMethods());
@@ -673,7 +679,7 @@
TEST_F(ClassLinkerTest, FindClass) {
ScopedObjectAccess soa(Thread::Current());
- mirror::Class* JavaLangObject = class_linker_->FindSystemClass("Ljava/lang/Object;");
+ mirror::Class* JavaLangObject = class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;");
ClassHelper kh(JavaLangObject);
ASSERT_TRUE(JavaLangObject != NULL);
ASSERT_TRUE(JavaLangObject->GetClass() != NULL);
@@ -710,7 +716,7 @@
SirtRef<mirror::ClassLoader> class_loader(soa.Self(), soa.Decode<mirror::ClassLoader*>(LoadDex("MyClass")));
AssertNonExistentClass("LMyClass;");
- mirror::Class* MyClass = class_linker_->FindClass("LMyClass;", class_loader);
+ mirror::Class* MyClass = class_linker_->FindClass(soa.Self(), "LMyClass;", class_loader);
kh.ChangeClass(MyClass);
ASSERT_TRUE(MyClass != NULL);
ASSERT_TRUE(MyClass->GetClass() != NULL);
@@ -761,7 +767,7 @@
// start of the object
TEST_F(ClassLinkerTest, ValidateObjectArrayElementsOffset) {
ScopedObjectAccess soa(Thread::Current());
- mirror::Class* array_class = class_linker_->FindSystemClass("[Ljava/lang/String;");
+ mirror::Class* array_class = class_linker_->FindSystemClass(soa.Self(), "[Ljava/lang/String;");
mirror::ObjectArray<mirror::String>* array =
mirror::ObjectArray<mirror::String>::Alloc(soa.Self(), array_class, 0);
uintptr_t data_offset =
@@ -777,27 +783,27 @@
TEST_F(ClassLinkerTest, ValidatePrimitiveArrayElementsOffset) {
ScopedObjectAccess soa(Thread::Current());
SirtRef<mirror::LongArray> long_array(soa.Self(), mirror::LongArray::Alloc(soa.Self(), 0));
- EXPECT_EQ(class_linker_->FindSystemClass("[J"), long_array->GetClass());
+ EXPECT_EQ(class_linker_->FindSystemClass(soa.Self(), "[J"), long_array->GetClass());
uintptr_t data_offset = reinterpret_cast<uintptr_t>(long_array->GetData());
EXPECT_TRUE(IsAligned<8>(data_offset)); // Longs require 8 byte alignment
SirtRef<mirror::DoubleArray> double_array(soa.Self(), mirror::DoubleArray::Alloc(soa.Self(), 0));
- EXPECT_EQ(class_linker_->FindSystemClass("[D"), double_array->GetClass());
+ EXPECT_EQ(class_linker_->FindSystemClass(soa.Self(), "[D"), double_array->GetClass());
data_offset = reinterpret_cast<uintptr_t>(double_array->GetData());
EXPECT_TRUE(IsAligned<8>(data_offset)); // Doubles require 8 byte alignment
SirtRef<mirror::IntArray> int_array(soa.Self(), mirror::IntArray::Alloc(soa.Self(), 0));
- EXPECT_EQ(class_linker_->FindSystemClass("[I"), int_array->GetClass());
+ EXPECT_EQ(class_linker_->FindSystemClass(soa.Self(), "[I"), int_array->GetClass());
data_offset = reinterpret_cast<uintptr_t>(int_array->GetData());
EXPECT_TRUE(IsAligned<4>(data_offset)); // Ints require 4 byte alignment
SirtRef<mirror::CharArray> char_array(soa.Self(), mirror::CharArray::Alloc(soa.Self(), 0));
- EXPECT_EQ(class_linker_->FindSystemClass("[C"), char_array->GetClass());
+ EXPECT_EQ(class_linker_->FindSystemClass(soa.Self(), "[C"), char_array->GetClass());
data_offset = reinterpret_cast<uintptr_t>(char_array->GetData());
EXPECT_TRUE(IsAligned<2>(data_offset)); // Chars require 2 byte alignment
SirtRef<mirror::ShortArray> short_array(soa.Self(), mirror::ShortArray::Alloc(soa.Self(), 0));
- EXPECT_EQ(class_linker_->FindSystemClass("[S"), short_array->GetClass());
+ EXPECT_EQ(class_linker_->FindSystemClass(soa.Self(), "[S"), short_array->GetClass());
data_offset = reinterpret_cast<uintptr_t>(short_array->GetData());
EXPECT_TRUE(IsAligned<2>(data_offset)); // Shorts require 2 byte alignment
@@ -810,28 +816,28 @@
ScopedObjectAccess soa(Thread::Current());
SirtRef<mirror::ClassLoader> class_loader(soa.Self(), nullptr);
mirror::Class* c;
- c = class_linker_->FindClass("Ljava/lang/Boolean;", class_loader);
+ c = class_linker_->FindClass(soa.Self(), "Ljava/lang/Boolean;", class_loader);
FieldHelper fh(c->GetIFields()->Get(0));
EXPECT_STREQ("value", fh.GetName());
- c = class_linker_->FindClass("Ljava/lang/Byte;", class_loader);
+ c = class_linker_->FindClass(soa.Self(), "Ljava/lang/Byte;", class_loader);
fh.ChangeField(c->GetIFields()->Get(0));
EXPECT_STREQ("value", fh.GetName());
- c = class_linker_->FindClass("Ljava/lang/Character;", class_loader);
+ c = class_linker_->FindClass(soa.Self(), "Ljava/lang/Character;", class_loader);
fh.ChangeField(c->GetIFields()->Get(0));
EXPECT_STREQ("value", fh.GetName());
- c = class_linker_->FindClass("Ljava/lang/Double;", class_loader);
+ c = class_linker_->FindClass(soa.Self(), "Ljava/lang/Double;", class_loader);
fh.ChangeField(c->GetIFields()->Get(0));
EXPECT_STREQ("value", fh.GetName());
- c = class_linker_->FindClass("Ljava/lang/Float;", class_loader);
+ c = class_linker_->FindClass(soa.Self(), "Ljava/lang/Float;", class_loader);
fh.ChangeField(c->GetIFields()->Get(0));
EXPECT_STREQ("value", fh.GetName());
- c = class_linker_->FindClass("Ljava/lang/Integer;", class_loader);
+ c = class_linker_->FindClass(soa.Self(), "Ljava/lang/Integer;", class_loader);
fh.ChangeField(c->GetIFields()->Get(0));
EXPECT_STREQ("value", fh.GetName());
- c = class_linker_->FindClass("Ljava/lang/Long;", class_loader);
+ c = class_linker_->FindClass(soa.Self(), "Ljava/lang/Long;", class_loader);
fh.ChangeField(c->GetIFields()->Get(0));
EXPECT_STREQ("value", fh.GetName());
- c = class_linker_->FindClass("Ljava/lang/Short;", class_loader);
+ c = class_linker_->FindClass(soa.Self(), "Ljava/lang/Short;", class_loader);
fh.ChangeField(c->GetIFields()->Get(0));
EXPECT_STREQ("value", fh.GetName());
}
@@ -840,8 +846,8 @@
ScopedObjectAccess soa(Thread::Current());
SirtRef<mirror::ClassLoader> class_loader_1(soa.Self(), soa.Decode<mirror::ClassLoader*>(LoadDex("MyClass")));
SirtRef<mirror::ClassLoader> class_loader_2(soa.Self(), soa.Decode<mirror::ClassLoader*>(LoadDex("MyClass")));
- mirror::Class* MyClass_1 = class_linker_->FindClass("LMyClass;", class_loader_1);
- mirror::Class* MyClass_2 = class_linker_->FindClass("LMyClass;", class_loader_2);
+ mirror::Class* MyClass_1 = class_linker_->FindClass(soa.Self(), "LMyClass;", class_loader_1);
+ mirror::Class* MyClass_2 = class_linker_->FindClass(soa.Self(), "LMyClass;", class_loader_2);
EXPECT_TRUE(MyClass_1 != NULL);
EXPECT_TRUE(MyClass_2 != NULL);
EXPECT_NE(MyClass_1, MyClass_2);
@@ -849,8 +855,10 @@
TEST_F(ClassLinkerTest, StaticFields) {
ScopedObjectAccess soa(Thread::Current());
- SirtRef<mirror::ClassLoader> class_loader(soa.Self(), soa.Decode<mirror::ClassLoader*>(LoadDex("Statics")));
- SirtRef<mirror::Class> statics(soa.Self(), class_linker_->FindClass("LStatics;", class_loader));
+ SirtRef<mirror::ClassLoader> class_loader(soa.Self(),
+ soa.Decode<mirror::ClassLoader*>(LoadDex("Statics")));
+ SirtRef<mirror::Class> statics(soa.Self(), class_linker_->FindClass(soa.Self(), "LStatics;",
+ class_loader));
class_linker_->EnsureInitialized(statics, true, true);
// Static final primitives that are initialized by a compile-time constant
@@ -933,11 +941,11 @@
TEST_F(ClassLinkerTest, Interfaces) {
ScopedObjectAccess soa(Thread::Current());
SirtRef<mirror::ClassLoader> class_loader(soa.Self(), soa.Decode<mirror::ClassLoader*>(LoadDex("Interfaces")));
- mirror::Class* I = class_linker_->FindClass("LInterfaces$I;", class_loader);
- mirror::Class* J = class_linker_->FindClass("LInterfaces$J;", class_loader);
- mirror::Class* K = class_linker_->FindClass("LInterfaces$K;", class_loader);
- mirror::Class* A = class_linker_->FindClass("LInterfaces$A;", class_loader);
- mirror::Class* B = class_linker_->FindClass("LInterfaces$B;", class_loader);
+ mirror::Class* I = class_linker_->FindClass(soa.Self(), "LInterfaces$I;", class_loader);
+ mirror::Class* J = class_linker_->FindClass(soa.Self(), "LInterfaces$J;", class_loader);
+ mirror::Class* K = class_linker_->FindClass(soa.Self(), "LInterfaces$K;", class_loader);
+ mirror::Class* A = class_linker_->FindClass(soa.Self(), "LInterfaces$A;", class_loader);
+ mirror::Class* B = class_linker_->FindClass(soa.Self(), "LInterfaces$B;", class_loader);
EXPECT_TRUE(I->IsAssignableFrom(A));
EXPECT_TRUE(J->IsAssignableFrom(A));
EXPECT_TRUE(J->IsAssignableFrom(K));
@@ -996,7 +1004,7 @@
SirtRef<mirror::ClassLoader> class_loader(soa.Self(), soa.Decode<mirror::ClassLoader*>(jclass_loader));
const DexFile* dex_file = Runtime::Current()->GetCompileTimeClassPath(jclass_loader)[0];
CHECK(dex_file != NULL);
- mirror::Class* klass = class_linker_->FindClass("LStaticsFromCode;", class_loader);
+ mirror::Class* klass = class_linker_->FindClass(soa.Self(), "LStaticsFromCode;", class_loader);
mirror::ArtMethod* clinit = klass->FindClassInitializer();
mirror::ArtMethod* getS0 = klass->FindDirectMethod("getS0", "()Ljava/lang/Object;");
const DexFile::StringId* string_id = dex_file->FindStringId("LStaticsFromCode;");
@@ -1017,32 +1025,32 @@
mirror::Class* c;
// Object has a finalize method, but we know it's empty.
- c = class_linker_->FindSystemClass("Ljava/lang/Object;");
+ c = class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;");
EXPECT_FALSE(c->IsFinalizable());
// Enum has a finalize method to prevent its subclasses from implementing one.
- c = class_linker_->FindSystemClass("Ljava/lang/Enum;");
+ c = class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Enum;");
EXPECT_FALSE(c->IsFinalizable());
// RoundingMode is an enum.
- c = class_linker_->FindSystemClass("Ljava/math/RoundingMode;");
+ c = class_linker_->FindSystemClass(soa.Self(), "Ljava/math/RoundingMode;");
EXPECT_FALSE(c->IsFinalizable());
// RandomAccessFile extends Object and overrides finalize.
- c = class_linker_->FindSystemClass("Ljava/io/RandomAccessFile;");
+ c = class_linker_->FindSystemClass(soa.Self(), "Ljava/io/RandomAccessFile;");
EXPECT_TRUE(c->IsFinalizable());
// FileInputStream is finalizable and extends InputStream which isn't.
- c = class_linker_->FindSystemClass("Ljava/io/InputStream;");
+ c = class_linker_->FindSystemClass(soa.Self(), "Ljava/io/InputStream;");
EXPECT_FALSE(c->IsFinalizable());
- c = class_linker_->FindSystemClass("Ljava/io/FileInputStream;");
+ c = class_linker_->FindSystemClass(soa.Self(), "Ljava/io/FileInputStream;");
EXPECT_TRUE(c->IsFinalizable());
// ScheduledThreadPoolExecutor doesn't have a finalize method but
// extends ThreadPoolExecutor which does.
- c = class_linker_->FindSystemClass("Ljava/util/concurrent/ThreadPoolExecutor;");
+ c = class_linker_->FindSystemClass(soa.Self(), "Ljava/util/concurrent/ThreadPoolExecutor;");
EXPECT_TRUE(c->IsFinalizable());
- c = class_linker_->FindSystemClass("Ljava/util/concurrent/ScheduledThreadPoolExecutor;");
+ c = class_linker_->FindSystemClass(soa.Self(), "Ljava/util/concurrent/ScheduledThreadPoolExecutor;");
EXPECT_TRUE(c->IsFinalizable());
}