summaryrefslogtreecommitdiffstats
path: root/runtime/class_linker.cc
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/class_linker.cc')
-rw-r--r--runtime/class_linker.cc456
1 files changed, 261 insertions, 195 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 3387a70..cd4a720 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -187,6 +187,8 @@ ClassLinker* ClassLinker::CreateFromImage(InternTable* intern_table) {
ClassLinker::ClassLinker(InternTable* intern_table)
// dex_lock_ is recursive as it may be used in stack dumping.
: 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),
init_done_(false),
@@ -225,7 +227,7 @@ void ClassLinker::InitFromCompiler(const std::vector<const DexFile*>& boot_class
CHECK(java_lang_Object.get() != NULL);
// backfill Object as the super class of Class.
java_lang_Class->SetSuperClass(java_lang_Object.get());
- java_lang_Object->SetStatus(mirror::Class::kStatusLoaded);
+ java_lang_Object->SetStatus(mirror::Class::kStatusLoaded, self);
// Object[] next to hold class roots.
SirtRef<mirror::Class> object_array_class(self, AllocClass(self, java_lang_Class.get(), sizeof(mirror::Class)));
@@ -243,7 +245,7 @@ void ClassLinker::InitFromCompiler(const std::vector<const DexFile*>& boot_class
SirtRef<mirror::Class> java_lang_String(self, AllocClass(self, java_lang_Class.get(), sizeof(mirror::StringClass)));
mirror::String::SetClass(java_lang_String.get());
java_lang_String->SetObjectSize(sizeof(mirror::String));
- java_lang_String->SetStatus(mirror::Class::kStatusResolved);
+ java_lang_String->SetStatus(mirror::Class::kStatusResolved, self);
// Create storage for root classes, save away our work so far (requires descriptors).
class_roots_ = mirror::ObjectArray<mirror::Class>::Alloc(self, object_array_class.get(), kClassRootsMax);
@@ -281,7 +283,7 @@ void ClassLinker::InitFromCompiler(const std::vector<const DexFile*>& boot_class
java_lang_DexCache(self, AllocClass(self, java_lang_Class.get(), sizeof(mirror::DexCacheClass)));
SetClassRoot(kJavaLangDexCache, java_lang_DexCache.get());
java_lang_DexCache->SetObjectSize(sizeof(mirror::DexCacheClass));
- java_lang_DexCache->SetStatus(mirror::Class::kStatusResolved);
+ java_lang_DexCache->SetStatus(mirror::Class::kStatusResolved, self);
// Constructor, Field, Method, and AbstractMethod are necessary so that FindClass can link members.
SirtRef<mirror::Class> java_lang_reflect_ArtField(self, AllocClass(self, java_lang_Class.get(),
@@ -289,7 +291,7 @@ void ClassLinker::InitFromCompiler(const std::vector<const DexFile*>& boot_class
CHECK(java_lang_reflect_ArtField.get() != NULL);
java_lang_reflect_ArtField->SetObjectSize(sizeof(mirror::ArtField));
SetClassRoot(kJavaLangReflectArtField, java_lang_reflect_ArtField.get());
- java_lang_reflect_ArtField->SetStatus(mirror::Class::kStatusResolved);
+ java_lang_reflect_ArtField->SetStatus(mirror::Class::kStatusResolved, self);
mirror::ArtField::SetClass(java_lang_reflect_ArtField.get());
SirtRef<mirror::Class> java_lang_reflect_ArtMethod(self, AllocClass(self, java_lang_Class.get(),
@@ -297,7 +299,7 @@ void ClassLinker::InitFromCompiler(const std::vector<const DexFile*>& boot_class
CHECK(java_lang_reflect_ArtMethod.get() != NULL);
java_lang_reflect_ArtMethod->SetObjectSize(sizeof(mirror::ArtMethod));
SetClassRoot(kJavaLangReflectArtMethod, java_lang_reflect_ArtMethod.get());
- java_lang_reflect_ArtMethod->SetStatus(mirror::Class::kStatusResolved);
+ java_lang_reflect_ArtMethod->SetStatus(mirror::Class::kStatusResolved, self);
mirror::ArtMethod::SetClass(java_lang_reflect_ArtMethod.get());
@@ -334,15 +336,15 @@ void ClassLinker::InitFromCompiler(const std::vector<const DexFile*>& boot_class
SetClassRoot(kPrimitiveChar, char_class.get()); // needs descriptor
// Object, String and DexCache need to be rerun through FindSystemClass to finish init
- java_lang_Object->SetStatus(mirror::Class::kStatusNotReady);
+ java_lang_Object->SetStatus(mirror::Class::kStatusNotReady, self);
mirror::Class* Object_class = FindSystemClass("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);
+ java_lang_String->SetStatus(mirror::Class::kStatusNotReady, self);
mirror::Class* String_class = FindSystemClass("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);
+ java_lang_DexCache->SetStatus(mirror::Class::kStatusNotReady, self);
mirror::Class* DexCache_class = FindSystemClass("Ljava/lang/DexCache;");
CHECK_EQ(java_lang_String.get(), String_class);
CHECK_EQ(java_lang_DexCache.get(), DexCache_class);
@@ -397,15 +399,15 @@ void ClassLinker::InitFromCompiler(const std::vector<const DexFile*>& boot_class
CHECK_EQ(java_lang_Cloneable, kh.GetDirectInterface(0));
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 classes_.
+ // dex_cache_ fields and register them in class_table_.
mirror::Class* Class_class = FindSystemClass("Ljava/lang/Class;");
CHECK_EQ(java_lang_Class.get(), Class_class);
- java_lang_reflect_ArtMethod->SetStatus(mirror::Class::kStatusNotReady);
+ java_lang_reflect_ArtMethod->SetStatus(mirror::Class::kStatusNotReady, self);
mirror::Class* Art_method_class = FindSystemClass("Ljava/lang/reflect/ArtMethod;");
CHECK_EQ(java_lang_reflect_ArtMethod.get(), Art_method_class);
- java_lang_reflect_ArtField->SetStatus(mirror::Class::kStatusNotReady);
+ java_lang_reflect_ArtField->SetStatus(mirror::Class::kStatusNotReady, self);
mirror::Class* Art_field_class = FindSystemClass("Ljava/lang/reflect/ArtField;");
CHECK_EQ(java_lang_reflect_ArtField.get(), Art_field_class);
@@ -984,21 +986,14 @@ const OatFile* ClassLinker::FindOatFileFromOatLocationLocked(const std::string&
return oat_file;
}
-static void InitFromImageCallbackCommon(mirror::Object* obj, ClassLinker* class_linker,
- bool interpret_only_mode)
+static void InitFromImageInterpretOnlyCallback(mirror::Object* obj, void* arg)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ ClassLinker* class_linker = reinterpret_cast<ClassLinker*>(arg);
+
DCHECK(obj != NULL);
DCHECK(class_linker != NULL);
- if (obj->GetClass()->IsStringClass()) {
- class_linker->GetInternTable()->RegisterStrong(obj->AsString());
- } else if (obj->IsClass()) {
- // Restore class to ClassLinker::classes_ table.
- mirror::Class* klass = obj->AsClass();
- ClassHelper kh(klass, class_linker);
- mirror::Class* existing = class_linker->InsertClass(kh.GetDescriptor(), klass, true);
- DCHECK(existing == NULL) << kh.GetDescriptor();
- } else if (interpret_only_mode && obj->IsArtMethod()) {
+ if (obj->IsArtMethod()) {
mirror::ArtMethod* method = obj->AsArtMethod();
if (!method->IsNative()) {
method->SetEntryPointFromInterpreter(interpreter::artInterpreterToInterpreterBridge);
@@ -1009,24 +1004,13 @@ static void InitFromImageCallbackCommon(mirror::Object* obj, ClassLinker* class_
}
}
-static void InitFromImageCallback(mirror::Object* obj, void* arg)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- ClassLinker* class_linker = reinterpret_cast<ClassLinker*>(arg);
- InitFromImageCallbackCommon(obj, class_linker, false);
-}
-
-static void InitFromImageInterpretOnlyCallback(mirror::Object* obj, void* arg)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- ClassLinker* class_linker = reinterpret_cast<ClassLinker*>(arg);
- InitFromImageCallbackCommon(obj, class_linker, true);
-}
-
void ClassLinker::InitFromImage() {
VLOG(startup) << "ClassLinker::InitFromImage entering";
CHECK(!init_done_);
gc::Heap* heap = Runtime::Current()->GetHeap();
gc::space::ImageSpace* space = heap->GetImageSpace();
+ dex_cache_image_class_lookup_required_ = true;
CHECK(space != NULL);
OatFile& oat_file = GetImageOatFile(space);
CHECK_EQ(oat_file.GetOatHeader().GetImageFileLocationOatChecksum(), 0U);
@@ -1049,7 +1033,7 @@ void ClassLinker::InitFromImage() {
CHECK_EQ(oat_file.GetOatHeader().GetDexFileCount(),
static_cast<uint32_t>(dex_caches->GetLength()));
Thread* self = Thread::Current();
- for (int i = 0; i < dex_caches->GetLength(); i++) {
+ for (int32_t i = 0; i < dex_caches->GetLength(); i++) {
SirtRef<mirror::DexCache> dex_cache(self, dex_caches->Get(i));
const std::string& dex_file_location(dex_cache->GetLocation()->ToModifiedUtf8());
const OatFile::OatDexFile* oat_dex_file = oat_file.GetOatDexFile(dex_file_location);
@@ -1069,15 +1053,11 @@ void ClassLinker::InitFromImage() {
// bitmap walk.
mirror::ArtMethod::SetClass(GetClassRoot(kJavaLangReflectArtMethod));
- // reinit clases_ table
- {
+ // Set entry point to interpreter if in InterpretOnly mode.
+ if (Runtime::Current()->GetInstrumentation()->InterpretOnly()) {
ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
heap->FlushAllocStack();
- if (Runtime::Current()->GetInstrumentation()->InterpretOnly()) {
- heap->GetLiveBitmap()->Walk(InitFromImageInterpretOnlyCallback, this);
- } else {
- heap->GetLiveBitmap()->Walk(InitFromImageCallback, this);
- }
+ heap->GetLiveBitmap()->Walk(InitFromImageInterpretOnlyCallback, this);
}
// reinit class_roots_
@@ -1120,7 +1100,7 @@ void ClassLinker::VisitRoots(RootVisitor* visitor, void* arg, bool clean_dirty)
{
ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_);
- for (const std::pair<size_t, mirror::Class*>& it : classes_) {
+ for (const std::pair<size_t, mirror::Class*>& it : class_table_) {
visitor(it.second, arg);
}
@@ -1134,14 +1114,12 @@ void ClassLinker::VisitRoots(RootVisitor* visitor, void* arg, bool clean_dirty)
}
}
-void ClassLinker::VisitClasses(ClassVisitor* visitor, void* arg) const {
- ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
- for (const std::pair<size_t, mirror::Class*>& it : classes_) {
- if (!visitor(it.second, arg)) {
- return;
- }
+void ClassLinker::VisitClasses(ClassVisitor* visitor, void* arg) {
+ if (dex_cache_image_class_lookup_required_) {
+ MoveImageClassesToClassTable();
}
- for (const std::pair<size_t, mirror::Class*>& it : image_classes_) {
+ ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
+ for (const std::pair<size_t, mirror::Class*>& it : class_table_) {
if (!visitor(it.second, arg)) {
return;
}
@@ -1154,7 +1132,7 @@ static bool GetClassesVisitor(mirror::Class* c, void* arg) {
return true;
}
-void ClassLinker::VisitClassesWithoutClassesLock(ClassVisitor* visitor, void* arg) const {
+void ClassLinker::VisitClassesWithoutClassesLock(ClassVisitor* visitor, void* arg) {
std::set<mirror::Class*> classes;
VisitClasses(GetClassesVisitor, &classes);
for (mirror::Class* klass : classes) {
@@ -1274,7 +1252,7 @@ static mirror::Class* EnsureResolved(Thread* self, mirror::Class* klass)
// Check for circular dependencies between classes.
if (!klass->IsResolved() && klass->GetClinitThreadId() == self->GetTid()) {
ThrowClassCircularityError(klass);
- klass->SetStatus(mirror::Class::kStatusError);
+ klass->SetStatus(mirror::Class::kStatusError, self);
return NULL;
}
// Wait for the pending initialization to complete.
@@ -1383,26 +1361,26 @@ mirror::Class* ClassLinker::FindClass(const char* descriptor, mirror::ClassLoade
return NULL;
}
-mirror::Class* ClassLinker::DefineClass(const StringPiece& descriptor,
+mirror::Class* ClassLinker::DefineClass(const char* descriptor,
mirror::ClassLoader* class_loader,
const DexFile& dex_file,
const DexFile::ClassDef& dex_class_def) {
Thread* self = Thread::Current();
SirtRef<mirror::Class> klass(self, NULL);
// Load the class from the dex file.
- if (!init_done_) {
+ if (UNLIKELY(!init_done_)) {
// finish up init of hand crafted class_roots_
- if (descriptor == "Ljava/lang/Object;") {
+ if (strcmp(descriptor, "Ljava/lang/Object;") == 0) {
klass.reset(GetClassRoot(kJavaLangObject));
- } else if (descriptor == "Ljava/lang/Class;") {
+ } else if (strcmp(descriptor, "Ljava/lang/Class;") == 0) {
klass.reset(GetClassRoot(kJavaLangClass));
- } else if (descriptor == "Ljava/lang/String;") {
+ } else if (strcmp(descriptor, "Ljava/lang/String;") == 0) {
klass.reset(GetClassRoot(kJavaLangString));
- } else if (descriptor == "Ljava/lang/DexCache;") {
+ } else if (strcmp(descriptor, "Ljava/lang/DexCache;") == 0) {
klass.reset(GetClassRoot(kJavaLangDexCache));
- } else if (descriptor == "Ljava/lang/reflect/ArtField;") {
+ } else if (strcmp(descriptor, "Ljava/lang/reflect/ArtField;") == 0) {
klass.reset(GetClassRoot(kJavaLangReflectArtField));
- } else if (descriptor == "Ljava/lang/reflect/ArtMethod;") {
+ } else if (strcmp(descriptor, "Ljava/lang/reflect/ArtMethod;") == 0) {
klass.reset(GetClassRoot(kJavaLangReflectArtMethod));
} else {
klass.reset(AllocClass(self, SizeOfClass(dex_file, dex_class_def)));
@@ -1414,32 +1392,33 @@ mirror::Class* ClassLinker::DefineClass(const StringPiece& descriptor,
LoadClass(dex_file, dex_class_def, klass, class_loader);
// Check for a pending exception during load
if (self->IsExceptionPending()) {
- klass->SetStatus(mirror::Class::kStatusError);
+ klass->SetStatus(mirror::Class::kStatusError, self);
return NULL;
}
ObjectLock lock(self, klass.get());
klass->SetClinitThreadId(self->GetTid());
- // Add the newly loaded class to the loaded classes table.
- SirtRef<mirror::Class> existing(self, InsertClass(descriptor, klass.get(), false));
- if (existing.get() != NULL) {
- // We failed to insert because we raced with another thread.
- return EnsureResolved(self, existing.get());
+ {
+ // Add the newly loaded class to the loaded classes table.
+ mirror::Class* existing = InsertClass(descriptor, klass.get(), Hash(descriptor));
+ if (existing != NULL) {
+ // We failed to insert because we raced with another thread. Calling EnsureResolved may cause
+ // this thread to block.
+ return EnsureResolved(self, existing);
+ }
}
// Finish loading (if necessary) by finding parents
CHECK(!klass->IsLoaded());
if (!LoadSuperAndInterfaces(klass, dex_file)) {
// Loading failed.
- klass->SetStatus(mirror::Class::kStatusError);
- lock.NotifyAll();
+ klass->SetStatus(mirror::Class::kStatusError, self);
return NULL;
}
CHECK(klass->IsLoaded());
// Link the class (if necessary)
CHECK(!klass->IsResolved());
- if (!LinkClass(klass, NULL)) {
+ if (!LinkClass(klass, NULL, self)) {
// Linking failed.
- klass->SetStatus(mirror::Class::kStatusError);
- lock.NotifyAll();
+ klass->SetStatus(mirror::Class::kStatusError, self);
return NULL;
}
CHECK(klass->IsResolved());
@@ -1734,7 +1713,7 @@ void ClassLinker::LoadClass(const DexFile& dex_file,
klass->SetAccessFlags(access_flags);
klass->SetClassLoader(class_loader);
DCHECK_EQ(klass->GetPrimitiveType(), Primitive::kPrimNot);
- klass->SetStatus(mirror::Class::kStatusIdx);
+ klass->SetStatus(mirror::Class::kStatusIdx, NULL);
klass->SetDexTypeIndex(dex_class_def.class_idx_);
@@ -1966,11 +1945,13 @@ mirror::Class* ClassLinker::CreatePrimitiveClass(Thread* self, Primitive::Type t
mirror::Class* ClassLinker::InitializePrimitiveClass(mirror::Class* primitive_class, Primitive::Type type) {
CHECK(primitive_class != NULL);
// Must hold lock on object when initializing.
- ObjectLock lock(Thread::Current(), primitive_class);
+ Thread* self = Thread::Current();
+ ObjectLock lock(self, primitive_class);
primitive_class->SetAccessFlags(kAccPublic | kAccFinal | kAccAbstract);
primitive_class->SetPrimitiveType(type);
- primitive_class->SetStatus(mirror::Class::kStatusInitialized);
- mirror::Class* existing = InsertClass(Primitive::Descriptor(type), primitive_class, false);
+ primitive_class->SetStatus(mirror::Class::kStatusInitialized, self);
+ const char* descriptor = Primitive::Descriptor(type);
+ mirror::Class* existing = InsertClass(descriptor, primitive_class, Hash(descriptor));
CHECK(existing == NULL) << "InitPrimitiveClass(" << type << ") failed";
return primitive_class;
}
@@ -1988,12 +1969,11 @@ mirror::Class* ClassLinker::InitializePrimitiveClass(mirror::Class* primitive_cl
// array class; that always comes from the base element class.
//
// Returns NULL with an exception raised on failure.
-mirror::Class* ClassLinker::CreateArrayClass(const std::string& descriptor,
+mirror::Class* ClassLinker::CreateArrayClass(const char* descriptor,
mirror::ClassLoader* class_loader) {
- CHECK_EQ('[', descriptor[0]);
-
// Identify the underlying component type
- mirror::Class* component_type = FindClass(descriptor.substr(1).c_str(), class_loader);
+ CHECK_EQ('[', descriptor[0]);
+ mirror::Class* component_type = FindClass(descriptor + 1, class_loader);
if (component_type == NULL) {
DCHECK(Thread::Current()->IsExceptionPending());
return NULL;
@@ -2017,7 +1997,7 @@ mirror::Class* ClassLinker::CreateArrayClass(const std::string& descriptor,
// class to the hash table --- necessary because of possible races with
// other threads.)
if (class_loader != component_type->GetClassLoader()) {
- mirror::Class* new_class = LookupClass(descriptor.c_str(), component_type->GetClassLoader());
+ mirror::Class* new_class = LookupClass(descriptor, component_type->GetClassLoader());
if (new_class != NULL) {
return new_class;
}
@@ -2033,21 +2013,23 @@ mirror::Class* ClassLinker::CreateArrayClass(const std::string& descriptor,
// link step.
Thread* self = Thread::Current();
SirtRef<mirror::Class> new_class(self, NULL);
- if (!init_done_) {
+ if (UNLIKELY(!init_done_)) {
// Classes that were hand created, ie not by FindSystemClass
- if (descriptor == "[Ljava/lang/Class;") {
+ if (strcmp(descriptor, "[Ljava/lang/Class;") == 0) {
new_class.reset(GetClassRoot(kClassArrayClass));
- } else if (descriptor == "[Ljava/lang/Object;") {
+ } else if (strcmp(descriptor, "[Ljava/lang/Object;") == 0) {
new_class.reset(GetClassRoot(kObjectArrayClass));
- } else if (descriptor == class_roots_descriptors_[kJavaLangStringArrayClass]) {
+ } else if (strcmp(descriptor, class_roots_descriptors_[kJavaLangStringArrayClass]) == 0) {
new_class.reset(GetClassRoot(kJavaLangStringArrayClass));
- } else if (descriptor == class_roots_descriptors_[kJavaLangReflectArtMethodArrayClass]) {
+ } else if (strcmp(descriptor,
+ class_roots_descriptors_[kJavaLangReflectArtMethodArrayClass]) == 0) {
new_class.reset(GetClassRoot(kJavaLangReflectArtMethodArrayClass));
- } else if (descriptor == class_roots_descriptors_[kJavaLangReflectArtFieldArrayClass]) {
+ } else if (strcmp(descriptor,
+ class_roots_descriptors_[kJavaLangReflectArtFieldArrayClass]) == 0) {
new_class.reset(GetClassRoot(kJavaLangReflectArtFieldArrayClass));
- } else if (descriptor == "[C") {
+ } else if (strcmp(descriptor, "[C") == 0) {
new_class.reset(GetClassRoot(kCharArrayClass));
- } else if (descriptor == "[I") {
+ } else if (strcmp(descriptor, "[I") == 0) {
new_class.reset(GetClassRoot(kIntArrayClass));
}
}
@@ -2065,7 +2047,7 @@ mirror::Class* ClassLinker::CreateArrayClass(const std::string& descriptor,
new_class->SetVTable(java_lang_Object->GetVTable());
new_class->SetPrimitiveType(Primitive::kPrimNot);
new_class->SetClassLoader(component_type->GetClassLoader());
- new_class->SetStatus(mirror::Class::kStatusInitialized);
+ new_class->SetStatus(mirror::Class::kStatusInitialized, self);
// don't need to set new_class->SetObjectSize(..)
// because Object::SizeOf delegates to Array::SizeOf
@@ -2096,7 +2078,7 @@ mirror::Class* ClassLinker::CreateArrayClass(const std::string& descriptor,
new_class->SetAccessFlags(access_flags);
- mirror::Class* existing = InsertClass(descriptor, new_class.get(), false);
+ mirror::Class* existing = InsertClass(descriptor, new_class.get(), Hash(descriptor));
if (existing == NULL) {
return new_class.get();
}
@@ -2137,8 +2119,8 @@ mirror::Class* ClassLinker::FindPrimitiveClass(char type) {
return NULL;
}
-mirror::Class* ClassLinker::InsertClass(const StringPiece& descriptor, mirror::Class* klass,
- bool image_class) {
+mirror::Class* ClassLinker::InsertClass(const char* descriptor, mirror::Class* klass,
+ size_t hash) {
if (VLOG_IS_ON(class_linker)) {
mirror::DexCache* dex_cache = klass->GetDexCache();
std::string source;
@@ -2148,21 +2130,22 @@ mirror::Class* ClassLinker::InsertClass(const StringPiece& descriptor, mirror::C
}
LOG(INFO) << "Loaded class " << descriptor << source;
}
- size_t hash = StringPieceHash()(descriptor);
WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
- Table& classes = image_class ? image_classes_ : classes_;
mirror::Class* existing =
- LookupClassLocked(descriptor.data(), klass->GetClassLoader(), hash, classes);
-#ifndef NDEBUG
- // Check we don't have the class in the other table in error
- Table& other_classes = image_class ? classes_ : image_classes_;
- CHECK(LookupClassLocked(descriptor.data(), klass->GetClassLoader(), hash, other_classes) == NULL);
-#endif
+ LookupClassFromTableLocked(descriptor, klass->GetClassLoader(), hash);
if (existing != NULL) {
return existing;
}
+ if (kIsDebugBuild && klass->GetClassLoader() == NULL && dex_cache_image_class_lookup_required_) {
+ // Check a class loaded with the system class loader matches one in the image if the class
+ // is in the image.
+ existing = LookupClassFromImage(descriptor);
+ if (existing != NULL) {
+ CHECK(klass == existing);
+ }
+ }
Runtime::Current()->GetHeap()->VerifyObject(klass);
- classes.insert(std::make_pair(hash, klass));
+ class_table_.insert(std::make_pair(hash, klass));
Dirty();
return NULL;
}
@@ -2170,23 +2153,13 @@ mirror::Class* ClassLinker::InsertClass(const StringPiece& descriptor, mirror::C
bool ClassLinker::RemoveClass(const char* descriptor, const mirror::ClassLoader* class_loader) {
size_t hash = Hash(descriptor);
WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
- // TODO: determine if its better to search classes_ or image_classes_ first
ClassHelper kh;
- for (auto it = classes_.lower_bound(hash), end = classes_.end(); it != end && it->first == hash;
+ for (auto it = class_table_.lower_bound(hash), end = class_table_.end(); it != end && it->first == hash;
++it) {
mirror::Class* klass = it->second;
kh.ChangeClass(klass);
if (strcmp(kh.GetDescriptor(), descriptor) == 0 && klass->GetClassLoader() == class_loader) {
- classes_.erase(it);
- return true;
- }
- }
- for (auto it = image_classes_.lower_bound(hash), end = classes_.end();
- it != end && it->first == hash; ++it) {
- mirror::Class* klass = it->second;
- kh.ChangeClass(klass);
- if (strcmp(kh.GetDescriptor(), descriptor) == 0 && klass->GetClassLoader() == class_loader) {
- image_classes_.erase(it);
+ class_table_.erase(it);
return true;
}
}
@@ -2196,64 +2169,153 @@ bool ClassLinker::RemoveClass(const char* descriptor, const mirror::ClassLoader*
mirror::Class* ClassLinker::LookupClass(const char* descriptor,
const mirror::ClassLoader* class_loader) {
size_t hash = Hash(descriptor);
- ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
- // TODO: determine if its better to search classes_ or image_classes_ first
- mirror::Class* klass = NULL;
- // Use image class only if the class_loader is null.
- if (class_loader == NULL) {
- klass = LookupClassLocked(descriptor, class_loader, hash, image_classes_);
+ {
+ ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
+ mirror::Class* result = LookupClassFromTableLocked(descriptor, class_loader, hash);
+ if (result != NULL) {
+ return result;
+ }
}
- if (klass != NULL) {
- return klass;
+ if (class_loader != NULL || !dex_cache_image_class_lookup_required_) {
+ return NULL;
+ } else {
+ // Lookup failed but need to search dex_caches_.
+ mirror::Class* result = LookupClassFromImage(descriptor);
+ if (result != NULL) {
+ InsertClass(descriptor, result, hash);
+ } else {
+ // Searching the image dex files/caches failed, we don't want to get into this situation
+ // often as map searches are faster, so after kMaxFailedDexCacheLookups move all image
+ // classes into the class table.
+ const int32_t kMaxFailedDexCacheLookups = 1000;
+ if (++failed_dex_cache_class_lookups_ > kMaxFailedDexCacheLookups) {
+ MoveImageClassesToClassTable();
+ }
+ }
+ return result;
}
- return LookupClassLocked(descriptor, class_loader, hash, classes_);
}
-mirror::Class* ClassLinker::LookupClassLocked(const char* descriptor,
- const mirror::ClassLoader* class_loader,
- size_t hash, const Table& classes) {
+mirror::Class* ClassLinker::LookupClassFromTableLocked(const char* descriptor,
+ const mirror::ClassLoader* class_loader,
+ size_t hash) {
ClassHelper kh(NULL, this);
- auto end = classes_.end();
- for (auto it = classes.lower_bound(hash); it != end && it->first == hash;
- ++it) {
+ auto end = class_table_.end();
+ for (auto it = class_table_.lower_bound(hash); it != end && it->first == hash; ++it) {
mirror::Class* klass = it->second;
kh.ChangeClass(klass);
- if (strcmp(descriptor, kh.GetDescriptor()) == 0 && klass->GetClassLoader() == class_loader) {
-#ifndef NDEBUG
- for (++it; it != end && it->first == hash; ++it) {
- mirror::Class* klass2 = it->second;
- kh.ChangeClass(klass2);
- CHECK(!(strcmp(descriptor, kh.GetDescriptor()) == 0 && klass2->GetClassLoader() == class_loader))
- << PrettyClass(klass) << " " << klass << " " << klass->GetClassLoader() << " "
- << PrettyClass(klass2) << " " << klass2 << " " << klass2->GetClassLoader();
+ if (klass->GetClassLoader() == class_loader && strcmp(descriptor, kh.GetDescriptor()) == 0) {
+ if (kIsDebugBuild) {
+ // Check for duplicates in the table.
+ for (++it; it != end && it->first == hash; ++it) {
+ mirror::Class* klass2 = it->second;
+ kh.ChangeClass(klass2);
+ CHECK(!(strcmp(descriptor, kh.GetDescriptor()) == 0 && klass2->GetClassLoader() == class_loader))
+ << PrettyClass(klass) << " " << klass << " " << klass->GetClassLoader() << " "
+ << PrettyClass(klass2) << " " << klass2 << " " << klass2->GetClassLoader();
+ }
}
-#endif
return klass;
}
}
return NULL;
}
-void ClassLinker::LookupClasses(const char* descriptor, std::vector<mirror::Class*>& classes) {
- classes.clear();
- size_t hash = Hash(descriptor);
- ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
- // TODO: determine if its better to search classes_ or image_classes_ first
+static mirror::ObjectArray<mirror::DexCache>* GetImageDexCaches()
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ gc::space::ImageSpace* image = Runtime::Current()->GetHeap()->GetImageSpace();
+ CHECK(image != NULL);
+ mirror::Object* root = image->GetImageHeader().GetImageRoot(ImageHeader::kDexCaches);
+ return root->AsObjectArray<mirror::DexCache>();
+}
+
+void ClassLinker::MoveImageClassesToClassTable() {
+ Thread* self = Thread::Current();
+ WriterMutexLock mu(self, *Locks::classlinker_classes_lock_);
+ if (!dex_cache_image_class_lookup_required_) {
+ return; // All dex cache classes are already in the class table.
+ }
+ const char* old_no_suspend_cause =
+ self->StartAssertNoThreadSuspension("Moving image classes to class table");
+ mirror::ObjectArray<mirror::DexCache>* dex_caches = GetImageDexCaches();
ClassHelper kh(NULL, this);
- for (auto it = classes_.lower_bound(hash), end = classes_.end(); it != end && it->first == hash;
- ++it) {
- mirror::Class* klass = it->second;
- kh.ChangeClass(klass);
- if (strcmp(descriptor, kh.GetDescriptor()) == 0) {
- classes.push_back(klass);
+ for (int32_t i = 0; i < dex_caches->GetLength(); i++) {
+ mirror::DexCache* dex_cache = dex_caches->Get(i);
+ mirror::ObjectArray<mirror::Class>* types = dex_cache->GetResolvedTypes();
+ for (int32_t j = 0; j < types->GetLength(); j++) {
+ mirror::Class* klass = types->Get(j);
+ if (klass != NULL) {
+ kh.ChangeClass(klass);
+ DCHECK(klass->GetClassLoader() == NULL);
+ const char* descriptor = kh.GetDescriptor();
+ size_t hash = Hash(descriptor);
+ mirror::Class* existing = LookupClassFromTableLocked(descriptor, NULL, hash);
+ if (existing != NULL) {
+ CHECK(existing == klass) << PrettyClassAndClassLoader(existing) << " != "
+ << PrettyClassAndClassLoader(klass);
+ } else {
+ class_table_.insert(std::make_pair(hash, klass));
+ }
+ }
}
}
- for (auto it = image_classes_.lower_bound(hash), end = classes_.end();
+ Dirty();
+ dex_cache_image_class_lookup_required_ = false;
+ self->EndAssertNoThreadSuspension(old_no_suspend_cause);
+}
+
+mirror::Class* ClassLinker::LookupClassFromImage(const char* descriptor) {
+ Thread* self = Thread::Current();
+ const char* old_no_suspend_cause =
+ self->StartAssertNoThreadSuspension("Image class lookup");
+ mirror::ObjectArray<mirror::DexCache>* dex_caches = GetImageDexCaches();
+ for (int32_t i = 0; i < dex_caches->GetLength(); ++i) {
+ mirror::DexCache* dex_cache = dex_caches->Get(i);
+ const DexFile* dex_file = dex_cache->GetDexFile();
+ // First search using the class def map, but don't bother for non-class types.
+ if (descriptor[0] == 'L') {
+ const DexFile::ClassDef* class_def = dex_file->FindClassDef(descriptor);
+ if (class_def != NULL) {
+ mirror::Class* klass = dex_cache->GetResolvedType(class_def->class_idx_);
+ if (klass != NULL) {
+ self->EndAssertNoThreadSuspension(old_no_suspend_cause);
+ return klass;
+ }
+ }
+ }
+ // Now try binary searching the string/type index.
+ const DexFile::StringId* string_id = dex_file->FindStringId(descriptor);
+ if (string_id != NULL) {
+ const DexFile::TypeId* type_id =
+ dex_file->FindTypeId(dex_file->GetIndexForStringId(*string_id));
+ if (type_id != NULL) {
+ uint16_t type_idx = dex_file->GetIndexForTypeId(*type_id);
+ mirror::Class* klass = dex_cache->GetResolvedType(type_idx);
+ if (klass != NULL) {
+ self->EndAssertNoThreadSuspension(old_no_suspend_cause);
+ return klass;
+ }
+ }
+ }
+ }
+ self->EndAssertNoThreadSuspension(old_no_suspend_cause);
+ return NULL;
+}
+
+void ClassLinker::LookupClasses(const char* descriptor, std::vector<mirror::Class*>& result) {
+ result.clear();
+ if (dex_cache_image_class_lookup_required_) {
+ MoveImageClassesToClassTable();
+ }
+ size_t hash = Hash(descriptor);
+ ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
+ ClassHelper kh(NULL, this);
+ for (auto it = class_table_.lower_bound(hash), end = class_table_.end();
it != end && it->first == hash; ++it) {
mirror::Class* klass = it->second;
kh.ChangeClass(klass);
if (strcmp(descriptor, kh.GetDescriptor()) == 0) {
- classes.push_back(klass);
+ result.push_back(klass);
}
}
}
@@ -2277,12 +2339,12 @@ void ClassLinker::VerifyClass(mirror::Class* klass) {
}
if (klass->GetStatus() == mirror::Class::kStatusResolved) {
- klass->SetStatus(mirror::Class::kStatusVerifying);
+ klass->SetStatus(mirror::Class::kStatusVerifying, self);
} else {
CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusRetryVerificationAtRuntime)
<< PrettyClass(klass);
CHECK(!Runtime::Current()->IsCompiler());
- klass->SetStatus(mirror::Class::kStatusVerifyingAtRuntime);
+ klass->SetStatus(mirror::Class::kStatusVerifyingAtRuntime, self);
}
// Verify super class.
@@ -2307,7 +2369,7 @@ void ClassLinker::VerifyClass(mirror::Class* klass) {
if (cause.get() != NULL) {
self->GetException(NULL)->SetCause(cause.get());
}
- klass->SetStatus(mirror::Class::kStatusError);
+ klass->SetStatus(mirror::Class::kStatusError, self);
return;
}
}
@@ -2322,7 +2384,7 @@ void ClassLinker::VerifyClass(mirror::Class* klass) {
<< klass->GetDexCache()->GetLocation()->ToModifiedUtf8();
ThrowVerifyError(klass, "Rejecting class %s because it failed compile-time verification",
PrettyDescriptor(klass).c_str());
- klass->SetStatus(mirror::Class::kStatusError);
+ klass->SetStatus(mirror::Class::kStatusError, self);
return;
}
verifier::MethodVerifier::FailureKind verifier_failure = verifier::MethodVerifier::kNoFailure;
@@ -2344,10 +2406,10 @@ void ClassLinker::VerifyClass(mirror::Class* klass) {
// Even though there were no verifier failures we need to respect whether the super-class
// was verified or requiring runtime reverification.
if (super.get() == NULL || super->IsVerified()) {
- klass->SetStatus(mirror::Class::kStatusVerified);
+ klass->SetStatus(mirror::Class::kStatusVerified, self);
} else {
CHECK_EQ(super->GetStatus(), mirror::Class::kStatusRetryVerificationAtRuntime);
- klass->SetStatus(mirror::Class::kStatusRetryVerificationAtRuntime);
+ klass->SetStatus(mirror::Class::kStatusRetryVerificationAtRuntime, self);
// Pretend a soft failure occured so that we don't consider the class verified below.
verifier_failure = verifier::MethodVerifier::kSoftFailure;
}
@@ -2357,9 +2419,9 @@ void ClassLinker::VerifyClass(mirror::Class* klass) {
// failures at runtime will be handled by slow paths in the generated
// code. Set status accordingly.
if (Runtime::Current()->IsCompiler()) {
- klass->SetStatus(mirror::Class::kStatusRetryVerificationAtRuntime);
+ klass->SetStatus(mirror::Class::kStatusRetryVerificationAtRuntime, self);
} else {
- klass->SetStatus(mirror::Class::kStatusVerified);
+ klass->SetStatus(mirror::Class::kStatusVerified, self);
}
}
} else {
@@ -2368,7 +2430,7 @@ void ClassLinker::VerifyClass(mirror::Class* klass) {
<< " because: " << error_msg;
self->AssertNoPendingException();
ThrowVerifyError(klass, "%s", error_msg.c_str());
- klass->SetStatus(mirror::Class::kStatusError);
+ klass->SetStatus(mirror::Class::kStatusError, self);
}
if (preverified || verifier_failure == verifier::MethodVerifier::kNoFailure) {
// Class is verified so we don't need to do any access check on its methods.
@@ -2522,7 +2584,7 @@ mirror::Class* ClassLinker::CreateProxyClass(mirror::String* name,
mirror::Class* proxy_class = GetClassRoot(kJavaLangReflectProxy);
klass->SetDexCache(proxy_class->GetDexCache());
- klass->SetStatus(mirror::Class::kStatusIdx);
+ klass->SetStatus(mirror::Class::kStatusIdx, self);
klass->SetDexTypeIndex(DexFile::kDexNoIndex16);
@@ -2555,19 +2617,20 @@ mirror::Class* ClassLinker::CreateProxyClass(mirror::String* name,
}
klass->SetSuperClass(proxy_class); // The super class is java.lang.reflect.Proxy
- klass->SetStatus(mirror::Class::kStatusLoaded); // Class is now effectively in the loaded state
+ klass->SetStatus(mirror::Class::kStatusLoaded, self); // Class is now effectively in the loaded state
self->AssertNoPendingException();
- // Link the fields and virtual methods, creating vtable and iftables
- if (!LinkClass(klass, interfaces)) {
- klass->SetStatus(mirror::Class::kStatusError);
- return NULL;
- }
{
- ObjectLock lock(self, klass.get()); // Must hold lock on object when initializing.
+ ObjectLock lock(self, klass.get()); // Must hold lock on object when resolved.
+ // Link the fields and virtual methods, creating vtable and iftables
+ if (!LinkClass(klass, interfaces, self)) {
+ klass->SetStatus(mirror::Class::kStatusError, self);
+ return NULL;
+ }
+
interfaces_sfield->SetObject(klass.get(), interfaces);
throws_sfield->SetObject(klass.get(), throws);
- klass->SetStatus(mirror::Class::kStatusInitialized);
+ klass->SetStatus(mirror::Class::kStatusInitialized, self);
}
// sanity checks
@@ -2806,7 +2869,7 @@ bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_init_statics,
}
if (!ValidateSuperClassDescriptors(klass)) {
- klass->SetStatus(mirror::Class::kStatusError);
+ klass->SetStatus(mirror::Class::kStatusError, self);
return false;
}
@@ -2815,7 +2878,7 @@ bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_init_statics,
// From here out other threads may observe that we're initializing and so changes of state
// require the a notification.
klass->SetClinitThreadId(self->GetTid());
- klass->SetStatus(mirror::Class::kStatusInitializing);
+ klass->SetStatus(mirror::Class::kStatusInitializing, self);
t0 = NanoTime();
}
@@ -2837,8 +2900,7 @@ bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_init_statics,
<< (self->GetException(NULL) != NULL ? self->GetException(NULL)->Dump() : "");
ObjectLock lock(self, klass);
// Initialization failed because the super-class is erroneous.
- klass->SetStatus(mirror::Class::kStatusError);
- lock.NotifyAll();
+ klass->SetStatus(mirror::Class::kStatusError, self);
return false;
}
}
@@ -2884,7 +2946,7 @@ bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_init_statics,
if (self->IsExceptionPending()) {
WrapExceptionInInitializer();
- klass->SetStatus(mirror::Class::kStatusError);
+ klass->SetStatus(mirror::Class::kStatusError, self);
success = false;
} else {
RuntimeStats* global_stats = Runtime::Current()->GetStats();
@@ -2894,13 +2956,12 @@ bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_init_statics,
global_stats->class_init_time_ns += (t1 - t0);
thread_stats->class_init_time_ns += (t1 - t0);
// Set the class as initialized except if failed to initialize static fields.
- klass->SetStatus(mirror::Class::kStatusInitialized);
+ klass->SetStatus(mirror::Class::kStatusInitialized, self);
if (VLOG_IS_ON(class_linker)) {
ClassHelper kh(klass);
LOG(INFO) << "Initialized class " << kh.GetDescriptor() << " from " << kh.GetLocation();
}
}
- lock.NotifyAll();
}
return success;
}
@@ -2917,7 +2978,7 @@ bool ClassLinker::WaitForInitializeClass(mirror::Class* klass, Thread* self, Obj
// "interruptShouldThrow" was set), bail out.
if (self->IsExceptionPending()) {
WrapExceptionInInitializer();
- klass->SetStatus(mirror::Class::kStatusError);
+ klass->SetStatus(mirror::Class::kStatusError, self);
return false;
}
// Spurious wakeup? Go back to waiting.
@@ -3061,7 +3122,7 @@ void ClassLinker::ConstructFieldMap(const DexFile& dex_file, const DexFile::Clas
}
bool ClassLinker::LinkClass(SirtRef<mirror::Class>& klass,
- mirror::ObjectArray<mirror::Class>* interfaces) {
+ mirror::ObjectArray<mirror::Class>* interfaces, Thread* self) {
CHECK_EQ(mirror::Class::kStatusLoaded, klass->GetStatus());
if (!LinkSuperClass(klass)) {
return false;
@@ -3078,7 +3139,7 @@ bool ClassLinker::LinkClass(SirtRef<mirror::Class>& klass,
CreateReferenceInstanceOffsets(klass);
CreateReferenceStaticOffsets(klass);
CHECK_EQ(mirror::Class::kStatusLoaded, klass->GetStatus());
- klass->SetStatus(mirror::Class::kStatusResolved);
+ klass->SetStatus(mirror::Class::kStatusResolved, self);
return true;
}
@@ -3123,7 +3184,7 @@ bool ClassLinker::LoadSuperAndInterfaces(SirtRef<mirror::Class>& klass, const De
}
}
// Mark the class as loaded.
- klass->SetStatus(mirror::Class::kStatusLoaded);
+ klass->SetStatus(mirror::Class::kStatusLoaded, NULL);
return true;
}
@@ -3175,13 +3236,13 @@ bool ClassLinker::LinkSuperClass(SirtRef<mirror::Class>& klass) {
return false;
}
-#ifndef NDEBUG
- // Ensure super classes are fully resolved prior to resolving fields..
- while (super != NULL) {
- CHECK(super->IsResolved());
- super = super->GetSuperClass();
+ if (kIsDebugBuild) {
+ // Ensure super classes are fully resolved prior to resolving fields..
+ while (super != NULL) {
+ CHECK(super->IsResolved());
+ super = super->GetSuperClass();
+ }
}
-#endif
return true;
}
@@ -3992,16 +4053,16 @@ const char* ClassLinker::MethodShorty(uint32_t method_idx, mirror::ArtMethod* re
return dex_file.GetMethodShorty(method_id, length);
}
-void ClassLinker::DumpAllClasses(int flags) const {
+void ClassLinker::DumpAllClasses(int flags) {
+ if (dex_cache_image_class_lookup_required_) {
+ MoveImageClassesToClassTable();
+ }
// TODO: at the time this was written, it wasn't safe to call PrettyField with the ClassLinker
// lock held, because it might need to resolve a field's type, which would try to take the lock.
std::vector<mirror::Class*> all_classes;
{
ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
- for (const std::pair<size_t, mirror::Class*>& it : classes_) {
- all_classes.push_back(it.second);
- }
- for (const std::pair<size_t, mirror::Class*>& it : image_classes_) {
+ for (const std::pair<size_t, mirror::Class*>& it : class_table_) {
all_classes.push_back(it.second);
}
}
@@ -4011,15 +4072,20 @@ void ClassLinker::DumpAllClasses(int flags) const {
}
}
-void ClassLinker::DumpForSigQuit(std::ostream& os) const {
+void ClassLinker::DumpForSigQuit(std::ostream& os) {
+ if (dex_cache_image_class_lookup_required_) {
+ MoveImageClassesToClassTable();
+ }
ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
- os << "Loaded classes: " << image_classes_.size() << " image classes; "
- << classes_.size() << " allocated classes\n";
+ os << "Loaded classes: " << class_table_.size() << " allocated classes\n";
}
-size_t ClassLinker::NumLoadedClasses() const {
+size_t ClassLinker::NumLoadedClasses() {
+ if (dex_cache_image_class_lookup_required_) {
+ MoveImageClassesToClassTable();
+ }
ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
- return classes_.size() + image_classes_.size();
+ return class_table_.size();
}
pid_t ClassLinker::GetClassesLockOwner() {