diff options
-rw-r--r-- | compiler/driver/compiler_driver.cc | 2 | ||||
-rw-r--r-- | compiler/image_test.cc | 2 | ||||
-rw-r--r-- | runtime/base/stringpiece.h | 13 | ||||
-rw-r--r-- | runtime/class_linker.cc | 456 | ||||
-rw-r--r-- | runtime/class_linker.h | 51 | ||||
-rw-r--r-- | runtime/dex_instruction.cc | 15 | ||||
-rw-r--r-- | runtime/intern_table.cc | 85 | ||||
-rw-r--r-- | runtime/intern_table.h | 5 | ||||
-rw-r--r-- | runtime/mirror/class.cc | 30 | ||||
-rw-r--r-- | runtime/mirror/class.h | 4 | ||||
-rw-r--r-- | runtime/monitor.cc | 25 | ||||
-rw-r--r-- | runtime/monitor.h | 3 | ||||
-rw-r--r-- | runtime/native/dalvik_system_DexFile.cc | 3 | ||||
-rw-r--r-- | runtime/native/dalvik_system_VMDebug.cc | 3 | ||||
-rw-r--r-- | test/016-intern/expected.txt | 2 | ||||
-rw-r--r-- | test/016-intern/src/Main.java | 24 |
16 files changed, 446 insertions, 277 deletions
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index c079e52..99f8fb7 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -2094,7 +2094,7 @@ static void InitializeClass(const ParallelCompilationManager* manager, size_t cl mirror::ObjectArray<mirror::ArtField>* fields = klass->GetSFields(); CHECK_EQ(fields->GetLength(), 1); fields->Get(0)->SetObj(klass, manager->GetClassLinker()->FindPrimitiveClass('V')); - klass->SetStatus(mirror::Class::kStatusInitialized); + klass->SetStatus(mirror::Class::kStatusInitialized, soa.Self()); } else { manager->GetClassLinker()->EnsureInitialized(klass, true, true); } diff --git a/compiler/image_test.cc b/compiler/image_test.cc index dcafc19..106ef9a 100644 --- a/compiler/image_test.cc +++ b/compiler/image_test.cc @@ -152,7 +152,7 @@ TEST_F(ImageTest, WriteRead) { // non image classes should be in a space after the image. EXPECT_GT(reinterpret_cast<byte*>(klass), image_end) << descriptor; } - EXPECT_EQ(*klass->GetRawLockWordAddress(), 0); // address should have been removed from monitor + EXPECT_TRUE(Monitor::IsValidLockWord(*klass->GetRawLockWordAddress())); } } diff --git a/runtime/base/stringpiece.h b/runtime/base/stringpiece.h index 62088cc..91b83f6 100644 --- a/runtime/base/stringpiece.h +++ b/runtime/base/stringpiece.h @@ -208,19 +208,6 @@ inline bool operator>=(const StringPiece& x, const StringPiece& y) { extern std::ostream& operator<<(std::ostream& o, const StringPiece& piece); -struct StringPieceHash { - size_t operator()(const StringPiece& string_piece) const { - size_t string_size = string_piece.size(); - const char* string_data = string_piece.data(); - // This is the java.lang.String hashcode for convenience, not interoperability. - size_t hash = 0; - while (string_size--) { - hash = hash * 31 + *string_data++; - } - return hash; - } -}; - } // namespace art #endif // ART_RUNTIME_BASE_STRINGPIECE_H_ 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() { diff --git a/runtime/class_linker.h b/runtime/class_linker.h index 5ef6d8f..c5fb72c 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -73,7 +73,7 @@ class ClassLinker { SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Define a new a class based on a ClassDef from a DexFile - mirror::Class* DefineClass(const StringPiece& descriptor, mirror::ClassLoader* class_loader, + mirror::Class* DefineClass(const char* descriptor, mirror::ClassLoader* class_loader, const DexFile& dex_file, const DexFile::ClassDef& dex_class_def) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); @@ -96,14 +96,17 @@ class ClassLinker { LOCKS_EXCLUDED(Locks::classlinker_classes_lock_) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void DumpAllClasses(int flags) const + void DumpAllClasses(int flags) LOCKS_EXCLUDED(Locks::classlinker_classes_lock_) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void DumpForSigQuit(std::ostream& os) const - LOCKS_EXCLUDED(Locks::classlinker_classes_lock_); + void DumpForSigQuit(std::ostream& os) + LOCKS_EXCLUDED(Locks::classlinker_classes_lock_) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - size_t NumLoadedClasses() const LOCKS_EXCLUDED(Locks::classlinker_classes_lock_); + size_t NumLoadedClasses() + LOCKS_EXCLUDED(Locks::classlinker_classes_lock_) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Resolve a String with the given index from the DexFile, storing the // result in the DexCache. The referrer is used to identify the @@ -219,12 +222,14 @@ class ClassLinker { return boot_class_path_; } - void VisitClasses(ClassVisitor* visitor, void* arg) const - LOCKS_EXCLUDED(Locks::classlinker_classes_lock_); + void VisitClasses(ClassVisitor* visitor, void* arg) + LOCKS_EXCLUDED(dex_lock_) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Less efficient variant of VisitClasses that doesn't hold the classlinker_classes_lock_ // when calling the visitor. - void VisitClassesWithoutClassesLock(ClassVisitor* visitor, void* arg) const - LOCKS_EXCLUDED(Locks::classlinker_classes_lock_); + void VisitClassesWithoutClassesLock(ClassVisitor* visitor, void* arg) + LOCKS_EXCLUDED(dex_lock_) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void VisitRoots(RootVisitor* visitor, void* arg, bool clean_dirty) LOCKS_EXCLUDED(Locks::classlinker_classes_lock_, dex_lock_); @@ -353,7 +358,7 @@ class ClassLinker { // Attempts to insert a class into a class table. Returns NULL if // the class was inserted, otherwise returns an existing class with // the same descriptor and ClassLoader. - mirror::Class* InsertClass(const StringPiece& descriptor, mirror::Class* klass, bool image_class) + mirror::Class* InsertClass(const char* descriptor, mirror::Class* klass, size_t hash) LOCKS_EXCLUDED(Locks::classlinker_classes_lock_) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); @@ -394,7 +399,7 @@ class ClassLinker { SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - mirror::Class* CreateArrayClass(const std::string& descriptor, mirror::ClassLoader* class_loader) + mirror::Class* CreateArrayClass(const char* descriptor, mirror::ClassLoader* class_loader) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void AppendToBootClassPath(const DexFile& dex_file) @@ -453,7 +458,8 @@ class ClassLinker { const mirror::Class* klass2) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - bool LinkClass(SirtRef<mirror::Class>& klass, mirror::ObjectArray<mirror::Class>* interfaces) + bool LinkClass(SirtRef<mirror::Class>& klass, mirror::ObjectArray<mirror::Class>* interfaces, + Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); bool LinkSuperClass(SirtRef<mirror::Class>& klass) @@ -530,12 +536,23 @@ class ClassLinker { // mirror::Class* instances. Results should be compared for a matching // Class::descriptor_ and Class::class_loader_. typedef std::multimap<size_t, mirror::Class*> Table; - Table image_classes_ GUARDED_BY(Locks::classlinker_classes_lock_); - Table classes_ GUARDED_BY(Locks::classlinker_classes_lock_); + Table class_table_ GUARDED_BY(Locks::classlinker_classes_lock_); + + // Do we need to search dex caches to find image classes? + bool dex_cache_image_class_lookup_required_; + // Number of times we've searched dex caches for a class. After a certain number of misses we move + // the classes into the class_table_ to avoid dex cache based searches. + AtomicInteger failed_dex_cache_class_lookups_; - mirror::Class* LookupClassLocked(const char* descriptor, const mirror::ClassLoader* class_loader, - size_t hash, const Table& classes) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::classlinker_classes_lock_); + mirror::Class* LookupClassFromTableLocked(const char* descriptor, + const mirror::ClassLoader* class_loader, + size_t hash) + SHARED_LOCKS_REQUIRED(Locks::classlinker_classes_lock_, Locks::mutator_lock_); + + void MoveImageClassesToClassTable() LOCKS_EXCLUDED(Locks::classlinker_classes_lock_) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + mirror::Class* LookupClassFromImage(const char* descriptor) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // indexes into class_roots_. // needs to be kept in sync with class_roots_descriptors_. diff --git a/runtime/dex_instruction.cc b/runtime/dex_instruction.cc index 09fa19e..6e8736a 100644 --- a/runtime/dex_instruction.cc +++ b/runtime/dex_instruction.cc @@ -529,7 +529,20 @@ std::string Instruction::DumpString(const DexFile* file) const { case k30t: os << StringPrintf("%s %+d", opcode, VRegA_30t()); break; case k31t: os << StringPrintf("%s v%d, %+d", opcode, VRegA_31t(), VRegB_31t()); break; case k31i: os << StringPrintf("%s v%d, #%+d", opcode, VRegA_31i(), VRegB_31i()); break; - case k31c: os << StringPrintf("%s v%d, thing@%d", opcode, VRegA_31c(), VRegB_31c()); break; + case k31c: + if (Opcode() == CONST_STRING_JUMBO) { + uint32_t string_idx = VRegB_31c(); + if (file != NULL) { + os << StringPrintf("%s v%d, %s // string@%d", opcode, VRegA_31c(), + PrintableString(file->StringDataByIdx(string_idx)).c_str(), + string_idx); + } else { + os << StringPrintf("%s v%d, string@%d", opcode, VRegA_31c(), string_idx); + } + } else { + os << StringPrintf("%s v%d, thing@%d", opcode, VRegA_31c(), VRegB_31c()); break; + } + break; case k35c: { uint32_t arg[5]; GetArgs(arg); diff --git a/runtime/intern_table.cc b/runtime/intern_table.cc index d7398ca..e3a75cf 100644 --- a/runtime/intern_table.cc +++ b/runtime/intern_table.cc @@ -16,6 +16,10 @@ #include "intern_table.h" +#include "gc/space/image_space.h" +#include "mirror/dex_cache.h" +#include "mirror/object_array-inl.h" +#include "mirror/object-inl.h" #include "mirror/string.h" #include "thread.h" #include "UniquePtr.h" @@ -23,8 +27,8 @@ namespace art { -InternTable::InternTable() : intern_table_lock_("InternTable lock"), is_dirty_(false) { -} +InternTable::InternTable() + : intern_table_lock_("InternTable lock"), is_dirty_(false) {} size_t InternTable::Size() const { MutexLock mu(Thread::Current(), intern_table_lock_); @@ -34,11 +38,11 @@ size_t InternTable::Size() const { void InternTable::DumpForSigQuit(std::ostream& os) const { MutexLock mu(Thread::Current(), intern_table_lock_); os << "Intern table: " << strong_interns_.size() << " strong; " - << weak_interns_.size() << " weak; " - << image_strong_interns_.size() << " image strong\n"; + << weak_interns_.size() << " weak\n"; } -void InternTable::VisitRoots(RootVisitor* visitor, void* arg, bool clean_dirty) { +void InternTable::VisitRoots(RootVisitor* visitor, void* arg, + bool clean_dirty) { MutexLock mu(Thread::Current(), intern_table_lock_); for (const auto& strong_intern : strong_interns_) { visitor(strong_intern.second, arg); @@ -46,10 +50,12 @@ void InternTable::VisitRoots(RootVisitor* visitor, void* arg, bool clean_dirty) if (clean_dirty) { is_dirty_ = false; } - // Note: we deliberately don't visit the weak_interns_ table and the immutable image roots. + // Note: we deliberately don't visit the weak_interns_ table and the immutable + // image roots. } -mirror::String* InternTable::Lookup(Table& table, mirror::String* s, uint32_t hash_code) { +mirror::String* InternTable::Lookup(Table& table, mirror::String* s, + uint32_t hash_code) { intern_table_lock_.AssertHeld(Thread::Current()); for (auto it = table.find(hash_code), end = table.end(); it != end; ++it) { mirror::String* existing_string = it->second; @@ -60,18 +66,15 @@ mirror::String* InternTable::Lookup(Table& table, mirror::String* s, uint32_t ha return NULL; } -mirror::String* InternTable::Insert(Table& table, mirror::String* s, uint32_t hash_code) { +mirror::String* InternTable::Insert(Table& table, mirror::String* s, + uint32_t hash_code) { intern_table_lock_.AssertHeld(Thread::Current()); table.insert(std::make_pair(hash_code, s)); return s; } -void InternTable::RegisterStrong(mirror::String* s) { - MutexLock mu(Thread::Current(), intern_table_lock_); - Insert(image_strong_interns_, s, s->GetHashCode()); -} - -void InternTable::Remove(Table& table, const mirror::String* s, uint32_t hash_code) { +void InternTable::Remove(Table& table, const mirror::String* s, + uint32_t hash_code) { intern_table_lock_.AssertHeld(Thread::Current()); for (auto it = table.find(hash_code), end = table.end(); it != end; ++it) { if (it->second == s) { @@ -81,6 +84,31 @@ void InternTable::Remove(Table& table, const mirror::String* s, uint32_t hash_co } } +static mirror::String* LookupStringFromImage(mirror::String* s) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + gc::space::ImageSpace* image = Runtime::Current()->GetHeap()->GetImageSpace(); + if (image == NULL) { + return NULL; // No image present. + } + mirror::Object* root = image->GetImageHeader().GetImageRoot(ImageHeader::kDexCaches); + mirror::ObjectArray<mirror::DexCache>* dex_caches = root->AsObjectArray<mirror::DexCache>(); + const std::string utf8 = s->ToModifiedUtf8(); + 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(); + // Binary search the dex file for the string index. + const DexFile::StringId* string_id = dex_file->FindStringId(utf8.c_str()); + if (string_id != NULL) { + uint32_t string_idx = dex_file->GetIndexForStringId(*string_id); + mirror::String* image = dex_cache->GetResolvedString(string_idx); + if (image != NULL) { + return image; + } + } + } + return NULL; +} + mirror::String* InternTable::Insert(mirror::String* s, bool is_strong) { MutexLock mu(Thread::Current(), intern_table_lock_); @@ -93,15 +121,16 @@ mirror::String* InternTable::Insert(mirror::String* s, bool is_strong) { if (strong != NULL) { return strong; } - // Check the image table for a match. - mirror::String* image = Lookup(image_strong_interns_, s, hash_code); - if (image != NULL) { - return image; - } // Mark as dirty so that we rescan the roots. Dirty(); + // Check the image for a match. + mirror::String* image = LookupStringFromImage(s); + if (image != NULL) { + return Insert(strong_interns_, image, hash_code); + } + // There is no match in the strong table, check the weak table. mirror::String* weak = Lookup(weak_interns_, s, hash_code); if (weak != NULL) { @@ -110,7 +139,8 @@ mirror::String* InternTable::Insert(mirror::String* s, bool is_strong) { return Insert(strong_interns_, weak, hash_code); } - // No match in the strong table or the weak table. Insert into the strong table. + // No match in the strong table or the weak table. Insert into the strong + // table. return Insert(strong_interns_, s, hash_code); } @@ -119,10 +149,10 @@ mirror::String* InternTable::Insert(mirror::String* s, bool is_strong) { if (strong != NULL) { return strong; } - // Check the image table for a match. - mirror::String* image = Lookup(image_strong_interns_, s, hash_code); + // Check the image for a match. + mirror::String* image = LookupStringFromImage(s); if (image != NULL) { - return image; + return Insert(weak_interns_, image, hash_code); } // Check the weak table for a match. mirror::String* weak = Lookup(weak_interns_, s, hash_code); @@ -133,12 +163,15 @@ mirror::String* InternTable::Insert(mirror::String* s, bool is_strong) { return Insert(weak_interns_, s, hash_code); } -mirror::String* InternTable::InternStrong(int32_t utf16_length, const char* utf8_data) { - return InternStrong(mirror::String::AllocFromModifiedUtf8(Thread::Current(), utf16_length, utf8_data)); +mirror::String* InternTable::InternStrong(int32_t utf16_length, + const char* utf8_data) { + return InternStrong(mirror::String::AllocFromModifiedUtf8( + Thread::Current(), utf16_length, utf8_data)); } mirror::String* InternTable::InternStrong(const char* utf8_data) { - return InternStrong(mirror::String::AllocFromModifiedUtf8(Thread::Current(), utf8_data)); + return InternStrong( + mirror::String::AllocFromModifiedUtf8(Thread::Current(), utf8_data)); } mirror::String* InternTable::InternStrong(mirror::String* s) { diff --git a/runtime/intern_table.h b/runtime/intern_table.h index 5031ce3..a804d1f 100644 --- a/runtime/intern_table.h +++ b/runtime/intern_table.h @@ -55,10 +55,6 @@ class InternTable { // Interns a potentially new string in the 'weak' table. (See above.) mirror::String* InternWeak(mirror::String* s) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - // Register a String trusting that it is safe to intern. - // Used when reinitializing InternTable from an image. - void RegisterStrong(mirror::String* s) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void SweepInternTableWeaks(IsMarkedTester is_marked, void* arg) SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_); @@ -88,7 +84,6 @@ class InternTable { mutable Mutex intern_table_lock_; bool is_dirty_; - Table image_strong_interns_ GUARDED_BY(intern_table_lock_); Table strong_interns_ GUARDED_BY(intern_table_lock_); Table weak_interns_ GUARDED_BY(intern_table_lock_); }; diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc index 19e134f..5e8b827 100644 --- a/runtime/mirror/class.cc +++ b/runtime/mirror/class.cc @@ -50,24 +50,26 @@ void Class::ResetClass() { java_lang_Class_ = NULL; } -void Class::SetStatus(Status new_status) { - if (UNLIKELY(new_status <= GetStatus() && new_status != kStatusError)) { - bool class_linker_initialized = Runtime::Current()->GetClassLinker() != nullptr; - if (class_linker_initialized) { +void Class::SetStatus(Status new_status, Thread* self) { + Status old_status = GetStatus(); + bool class_linker_initialized = Runtime::Current()->GetClassLinker() != nullptr; + if (LIKELY(class_linker_initialized)) { + if (UNLIKELY(new_status <= old_status && new_status != kStatusError)) { LOG(FATAL) << "Unexpected change back of class status for " << PrettyClass(this) << " " - << GetStatus() << " -> " << new_status; + << old_status << " -> " << new_status; + } + if (new_status >= kStatusResolved || old_status >= kStatusResolved) { + // When classes are being resolved the resolution code should hold the lock. + CHECK_EQ(GetThinLockId(), self->GetThinLockId()) + << "Attempt to change status of class while not holding its lock: " + << PrettyClass(this) << " " << old_status << " -> " << new_status; } - } - if (new_status > kStatusResolved) { - CHECK_EQ(GetThinLockId(), Thread::Current()->GetThinLockId()) - << "Attempt to change status of class while not holding its lock " << PrettyClass(this); } if (new_status == kStatusError) { CHECK_NE(GetStatus(), kStatusError) << "Attempt to set as erroneous an already erroneous class " << PrettyClass(this); // Stash current exception. - Thread* self = Thread::Current(); SirtRef<mirror::Object> old_throw_this_object(self, NULL); SirtRef<mirror::ArtMethod> old_throw_method(self, NULL); SirtRef<mirror::Throwable> old_exception(self, NULL); @@ -103,7 +105,13 @@ void Class::SetStatus(Status new_status) { self->SetException(gc_safe_throw_location, old_exception.get()); } CHECK(sizeof(Status) == sizeof(uint32_t)) << PrettyClass(this); - return SetField32(OFFSET_OF_OBJECT_MEMBER(Class, status_), new_status, false); + SetField32(OFFSET_OF_OBJECT_MEMBER(Class, status_), new_status, false); + // Classes that are being resolved or initialized need to notify waiters that the class status + // changed. See ClassLinker::EnsureResolved and ClassLinker::WaitForInitializeClass. + if ((old_status >= kStatusResolved || new_status >= kStatusResolved) && + class_linker_initialized) { + NotifyAll(self); + } } void Class::SetDexCache(DexCache* new_dex_cache) { diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h index 638b67f..99f3850 100644 --- a/runtime/mirror/class.h +++ b/runtime/mirror/class.h @@ -125,10 +125,10 @@ class MANAGED Class : public StaticStorageBase { Status GetStatus() const { DCHECK_EQ(sizeof(Status), sizeof(uint32_t)); - return static_cast<Status>(GetField32(OFFSET_OF_OBJECT_MEMBER(Class, status_), false)); + return static_cast<Status>(GetField32(OFFSET_OF_OBJECT_MEMBER(Class, status_), true)); } - void SetStatus(Status new_status) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + void SetStatus(Status new_status, Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Returns true if the class has failed to link. bool IsErroneous() const { diff --git a/runtime/monitor.cc b/runtime/monitor.cc index ff193c9..66c51e6 100644 --- a/runtime/monitor.cc +++ b/runtime/monitor.cc @@ -792,6 +792,8 @@ void Monitor::Notify(Thread* self, mirror::Object *obj) { return; } // no-op; there are no waiters to notify. + // We inflate here in case the Notify is in a tight loop. Without inflation here the waiter + // will struggle to get in. Bug 6961405. Inflate(self, obj); } else { // It's a fat lock. @@ -811,6 +813,8 @@ void Monitor::NotifyAll(Thread* self, mirror::Object *obj) { return; } // no-op; there are no waiters to notify. + // We inflate here in case the NotifyAll is in a tight loop. Without inflation here the waiter + // will struggle to get in. Bug 6961405. Inflate(self, obj); } else { // It's a fat lock. @@ -948,6 +952,27 @@ void Monitor::VisitLocks(StackVisitor* stack_visitor, void (*callback)(mirror::O } } +bool Monitor::IsValidLockWord(int32_t lock_word) { + if (lock_word == 0) { + return true; + } else if (LW_SHAPE(lock_word) == LW_SHAPE_FAT) { + Monitor* mon = LW_MONITOR(lock_word); + MonitorList* list = Runtime::Current()->GetMonitorList(); + MutexLock mu(Thread::Current(), list->monitor_list_lock_); + bool found = false; + for (Monitor* list_mon : list->list_) { + if (mon == list_mon) { + found = true; + break; + } + } + return found; + } else { + // TODO: thin lock validity checking. + return LW_SHAPE(lock_word) == LW_SHAPE_THIN; + } +} + void Monitor::TranslateLocation(const mirror::ArtMethod* method, uint32_t dex_pc, const char*& source_file, uint32_t& line_number) const { // If method is null, location is unknown diff --git a/runtime/monitor.h b/runtime/monitor.h index 02c10a7..6651768 100644 --- a/runtime/monitor.h +++ b/runtime/monitor.h @@ -100,6 +100,8 @@ class Monitor { void* callback_context) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + static bool IsValidLockWord(int32_t lock_word); + mirror::Object* GetObject(); private: @@ -188,6 +190,7 @@ class MonitorList { Mutex monitor_list_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER; std::list<Monitor*> list_ GUARDED_BY(monitor_list_lock_); + friend class Monitor; DISALLOW_COPY_AND_ASSIGN(MonitorList); }; diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc index 4ee3533..2f4e427 100644 --- a/runtime/native/dalvik_system_DexFile.cc +++ b/runtime/native/dalvik_system_DexFile.cc @@ -158,7 +158,8 @@ static jclass DexFile_defineClassNative(JNIEnv* env, jclass, jstring javaName, j ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); class_linker->RegisterDexFile(*dex_file); mirror::ClassLoader* class_loader = soa.Decode<mirror::ClassLoader*>(javaLoader); - mirror::Class* result = class_linker->DefineClass(descriptor, class_loader, *dex_file, *dex_class_def); + mirror::Class* result = class_linker->DefineClass(descriptor.c_str(), class_loader, *dex_file, + *dex_class_def); VLOG(class_linker) << "DexFile_defineClassNative returning " << result; return soa.AddLocalReference<jclass>(result); } diff --git a/runtime/native/dalvik_system_VMDebug.cc b/runtime/native/dalvik_system_VMDebug.cc index e3ec3bc..2956c2c 100644 --- a/runtime/native/dalvik_system_VMDebug.cc +++ b/runtime/native/dalvik_system_VMDebug.cc @@ -151,7 +151,8 @@ static void VMDebug_printLoadedClasses(JNIEnv* env, jclass, jint flags) { return Runtime::Current()->GetClassLinker()->DumpAllClasses(flags); } -static jint VMDebug_getLoadedClassCount(JNIEnv*, jclass) { +static jint VMDebug_getLoadedClassCount(JNIEnv* env, jclass) { + ScopedObjectAccess soa(env); return Runtime::Current()->GetClassLinker()->NumLoadedClasses(); } diff --git a/test/016-intern/expected.txt b/test/016-intern/expected.txt index 7d91963..0b7ac3d 100644 --- a/test/016-intern/expected.txt +++ b/test/016-intern/expected.txt @@ -1 +1,3 @@ good! foobar +good! foo +good! null diff --git a/test/016-intern/src/Main.java b/test/016-intern/src/Main.java index 4306863..01cbf18 100644 --- a/test/016-intern/src/Main.java +++ b/test/016-intern/src/Main.java @@ -20,15 +20,33 @@ public class Main { public static void main(String args[]) { String a, b; - String foo = "foo"; - String bar = "bar"; + final String foo = "foo"; + final String bar = "bar"; + // Two interned strings should match. a = foo.concat(bar).intern(); b = foo.concat(bar).intern(); if (a == b && foo != bar) { System.out.println("good! " + a); } else { - System.out.println("bad!"); + System.out.println("bad! " + a + " != " + b); + } + + // An interned string should match a string literal. + a = ("f" + foo.substring(1,3)).intern(); + if (a == foo) { + System.out.println("good! " + a); + } else { + System.out.println("bad! " + a + " != " + b); + } + + // Check that a string literal in libcore equals one in the app. + a = (new java.nio.charset.IllegalCharsetNameException(null)).getMessage(); + b = "null"; + if (a == b) { + System.out.println("good! " + a); + } else { + System.out.println("bad! " + a + " != " + b); } } } |