summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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);
}
}
}