summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIan Rogers <irogers@google.com>2013-08-22 08:18:36 -0700
committerIan Rogers <irogers@google.com>2013-08-23 10:49:29 -0700
commit7dfb28c066159e6cde8181720f0c451a700ef966 (patch)
tree5279fb95da015365846eb48d931b9355b540cb9e
parenta7e885013753df3f07bf038a8c4a187fb97c78e1 (diff)
downloadart-7dfb28c066159e6cde8181720f0c451a700ef966.zip
art-7dfb28c066159e6cde8181720f0c451a700ef966.tar.gz
art-7dfb28c066159e6cde8181720f0c451a700ef966.tar.bz2
Don't scan image space when starting runtime.
Bug 10432288. Find Classes and Strings from dex caches lazily rather than when the image is loaded. Make class status changes do notifies when there can be waiters. For Class lookup there's a pathology if we always search dex caches and so after 1000 failures move all classes into the class table. Be consistent in using "const char*" for class linker descriptors as this most easily agrees with the type in the dex file. Improve the intern run-test so that it has a case of a literal contained in the image. Modify image_test to allow any valid lock word rather than expecting 0, ideally we wouldn't see inflated monitors but we do due to NotifyAll (see bug 6961405). Change-Id: Ia9bfa748eeccb9b4498784b97c6823141b1f6db8
-rw-r--r--compiler/driver/compiler_driver.cc2
-rw-r--r--compiler/image_test.cc2
-rw-r--r--runtime/base/stringpiece.h13
-rw-r--r--runtime/class_linker.cc456
-rw-r--r--runtime/class_linker.h51
-rw-r--r--runtime/dex_instruction.cc15
-rw-r--r--runtime/intern_table.cc85
-rw-r--r--runtime/intern_table.h5
-rw-r--r--runtime/mirror/class.cc30
-rw-r--r--runtime/mirror/class.h4
-rw-r--r--runtime/monitor.cc25
-rw-r--r--runtime/monitor.h3
-rw-r--r--runtime/native/dalvik_system_DexFile.cc3
-rw-r--r--runtime/native/dalvik_system_VMDebug.cc3
-rw-r--r--test/016-intern/expected.txt2
-rw-r--r--test/016-intern/src/Main.java24
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);
}
}
}