diff options
author | 2013-09-13 13:46:47 -0700 | |
---|---|---|
committer | 2013-11-11 15:34:27 -0800 | |
commit | 590fee9e8972f872301c2d16a575d579ee564bee (patch) | |
tree | b02db45c72f1911ec896b93379ada0276aea3199 /runtime/class_linker.cc | |
parent | 5b70680b8df6d8fa95bb8e1070d0107f3d388940 (diff) |
Compacting collector.
The compacting collector is currently similar to semispace. It works by
copying objects back and forth between two bump pointer spaces. There
are types of objects which are "non-movable" due to current runtime
limitations. These are Classes, Methods, and Fields.
Bump pointer spaces are a new type of continuous alloc space which have
no lock in the allocation code path. When you allocate from these it uses
atomic operations to increase an index. Traversing the objects in the bump
pointer space relies on Object::SizeOf matching the allocated size exactly.
Runtime changes:
JNI::GetArrayElements returns copies objects if you attempt to get the
backing data of a movable array. For GetArrayElementsCritical, we return
direct backing storage for any types of arrays, but temporarily disable
the GC until the critical region is completed.
Added a new runtime call called VisitObjects, this is used in place of
the old pattern which was flushing the allocation stack and walking
the bitmaps.
Changed image writer to be compaction safe and use object monitor word
for forwarding addresses.
Added a bunch of added SIRTs to ClassLinker, MethodLinker, etc..
TODO: Enable switching allocators, compacting on background, etc..
Bug: 8981901
Change-Id: I3c886fd322a6eef2b99388d19a765042ec26ab99
Diffstat (limited to 'runtime/class_linker.cc')
-rw-r--r-- | runtime/class_linker.cc | 356 |
1 files changed, 175 insertions, 181 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 184e5d4be9..cfe3bf4c0f 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -170,20 +170,6 @@ const char* ClassLinker::class_roots_descriptors_[] = { "[Ljava/lang/StackTraceElement;", }; -ClassLinker* ClassLinker::CreateFromCompiler(const std::vector<const DexFile*>& boot_class_path, - InternTable* intern_table) { - CHECK_NE(boot_class_path.size(), 0U); - UniquePtr<ClassLinker> class_linker(new ClassLinker(intern_table)); - class_linker->InitFromCompiler(boot_class_path); - return class_linker.release(); -} - -ClassLinker* ClassLinker::CreateFromImage(InternTable* intern_table) { - UniquePtr<ClassLinker> class_linker(new ClassLinker(intern_table)); - class_linker->InitFromImage(); - return class_linker.release(); -} - ClassLinker::ClassLinker(InternTable* intern_table) // dex_lock_ is recursive as it may be used in stack dumping. : dex_lock_("ClassLinker dex lock", kDefaultMutexLevel), @@ -211,14 +197,16 @@ void ClassLinker::InitFromCompiler(const std::vector<const DexFile*>& boot_class // java_lang_Class comes first, it's needed for AllocClass Thread* self = Thread::Current(); gc::Heap* heap = Runtime::Current()->GetHeap(); - SirtRef<mirror::Class> - java_lang_Class(self, - down_cast<mirror::Class*>(heap->AllocObject(self, NULL, - sizeof(mirror::ClassClass)))); + // The GC can't handle an object with a null class since we can't get the size of this object. + heap->IncrementDisableGC(self); + SirtRef<mirror::Class> java_lang_Class( + self, down_cast<mirror::Class*>( + heap->AllocNonMovableObject(self, NULL, sizeof(mirror::ClassClass)))); CHECK(java_lang_Class.get() != NULL); mirror::Class::SetClassClass(java_lang_Class.get()); java_lang_Class->SetClass(java_lang_Class.get()); java_lang_Class->SetClassSize(sizeof(mirror::ClassClass)); + heap->DecrementDisableGC(self); // AllocClass(mirror::Class*) can now be used // Class[] is used for reflection support. @@ -401,7 +389,7 @@ void ClassLinker::InitFromCompiler(const std::vector<const DexFile*>& boot_class array_iftable_->SetInterface(1, java_io_Serializable); // Sanity check Class[] and Object[]'s interfaces. - ClassHelper kh(class_array_class.get(), this); + ClassHelper kh(class_array_class.get()); CHECK_EQ(java_lang_Cloneable, kh.GetDirectInterface(0)); CHECK_EQ(java_io_Serializable, kh.GetDirectInterface(1)); kh.ChangeClass(object_array_class.get()); @@ -487,7 +475,7 @@ void ClassLinker::FinishInit() { FindSystemClass("Ljava/lang/ref/FinalizerReference;"); mirror::ArtField* pendingNext = java_lang_ref_Reference->GetInstanceField(0); - FieldHelper fh(pendingNext, this); + FieldHelper fh(pendingNext); CHECK_STREQ(fh.GetName(), "pendingNext"); CHECK_STREQ(fh.GetTypeDescriptor(), "Ljava/lang/ref/Reference;"); @@ -1043,6 +1031,7 @@ void ClassLinker::InitFromImage() { VLOG(startup) << "ClassLinker::InitFromImage entering"; CHECK(!init_done_); + Thread* self = Thread::Current(); gc::Heap* heap = Runtime::Current()->GetHeap(); gc::space::ImageSpace* space = heap->GetImageSpace(); dex_cache_image_class_lookup_required_ = true; @@ -1059,9 +1048,10 @@ void ClassLinker::InitFromImage() { mirror::ObjectArray<mirror::DexCache>* dex_caches = dex_caches_object->AsObjectArray<mirror::DexCache>(); - mirror::ObjectArray<mirror::Class>* class_roots = - space->GetImageHeader().GetImageRoot(ImageHeader::kClassRoots)->AsObjectArray<mirror::Class>(); - class_roots_ = class_roots; + SirtRef<mirror::ObjectArray<mirror::Class> > class_roots( + self, + space->GetImageHeader().GetImageRoot(ImageHeader::kClassRoots)->AsObjectArray<mirror::Class>()); + class_roots_ = class_roots.get(); // Special case of setting up the String class early so that we can test arbitrary objects // as being Strings or not @@ -1069,7 +1059,6 @@ void ClassLinker::InitFromImage() { CHECK_EQ(oat_file.GetOatHeader().GetDexFileCount(), static_cast<uint32_t>(dex_caches->GetLength())); - Thread* self = Thread::Current(); 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()); @@ -1096,13 +1085,12 @@ void ClassLinker::InitFromImage() { // Set entry point to interpreter if in InterpretOnly mode. if (Runtime::Current()->GetInstrumentation()->InterpretOnly()) { ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_); - heap->FlushAllocStack(); - heap->GetLiveBitmap()->Walk(InitFromImageInterpretOnlyCallback, this); + heap->VisitObjects(InitFromImageInterpretOnlyCallback, this); } // reinit class_roots_ mirror::Class::SetClassClass(class_roots->Get(kJavaLangClass)); - class_roots_ = class_roots; + class_roots_ = class_roots.get(); // reinit array_iftable_ from any array class instance, they should be == array_iftable_ = GetClassRoot(kObjectArrayClass)->GetIfTable(); @@ -1192,7 +1180,6 @@ void ClassLinker::VisitClassesWithoutClassesLock(ClassVisitor* visitor, void* ar } } - ClassLinker::~ClassLinker() { mirror::Class::ResetClass(); mirror::String::ResetClass(); @@ -1214,10 +1201,10 @@ ClassLinker::~ClassLinker() { mirror::DexCache* ClassLinker::AllocDexCache(Thread* self, const DexFile& dex_file) { gc::Heap* heap = Runtime::Current()->GetHeap(); - mirror::Class* dex_cache_class = GetClassRoot(kJavaLangDexCache); - SirtRef<mirror::DexCache> dex_cache(self, - down_cast<mirror::DexCache*>(heap->AllocObject(self, dex_cache_class, - dex_cache_class->GetObjectSize()))); + SirtRef<mirror::Class> dex_cache_class(self, GetClassRoot(kJavaLangDexCache)); + SirtRef<mirror::DexCache> dex_cache( + self, down_cast<mirror::DexCache*>( + heap->AllocObject(self, dex_cache_class.get(), dex_cache_class->GetObjectSize()))); if (dex_cache.get() == NULL) { return NULL; } @@ -1253,13 +1240,8 @@ mirror::DexCache* ClassLinker::AllocDexCache(Thread* self, const DexFile& dex_fi return NULL; } - dex_cache->Init(&dex_file, - location.get(), - strings.get(), - types.get(), - methods.get(), - fields.get(), - initialized_static_storage.get()); + dex_cache->Init(&dex_file, location.get(), strings.get(), types.get(), methods.get(), + fields.get(), initialized_static_storage.get()); return dex_cache.get(); } @@ -1267,7 +1249,7 @@ mirror::Class* ClassLinker::AllocClass(Thread* self, mirror::Class* java_lang_Cl size_t class_size) { DCHECK_GE(class_size, sizeof(mirror::Class)); gc::Heap* heap = Runtime::Current()->GetHeap(); - mirror::Object* k = heap->AllocObject(self, java_lang_Class, class_size); + mirror::Object* k = heap->AllocNonMovableObject(self, java_lang_Class, class_size); if (UNLIKELY(k == NULL)) { CHECK(self->IsExceptionPending()); // OOME. return NULL; @@ -1285,18 +1267,19 @@ mirror::Class* ClassLinker::AllocClass(Thread* self, size_t class_size) { } mirror::ArtField* ClassLinker::AllocArtField(Thread* self) { - return down_cast<mirror::ArtField*>(GetClassRoot(kJavaLangReflectArtField)->AllocObject(self)); + return down_cast<mirror::ArtField*>( + GetClassRoot(kJavaLangReflectArtField)->Alloc<false, true>(self)); } mirror::ArtMethod* ClassLinker::AllocArtMethod(Thread* self) { - return down_cast<mirror::ArtMethod*>(GetClassRoot(kJavaLangReflectArtMethod)->AllocObject(self)); + return down_cast<mirror::ArtMethod*>( + GetClassRoot(kJavaLangReflectArtMethod)->Alloc<false, true>(self)); } -mirror::ObjectArray<mirror::StackTraceElement>* ClassLinker::AllocStackTraceElementArray(Thread* self, - size_t length) { - return mirror::ObjectArray<mirror::StackTraceElement>::Alloc(self, - GetClassRoot(kJavaLangStackTraceElementArrayClass), - length); +mirror::ObjectArray<mirror::StackTraceElement>* ClassLinker::AllocStackTraceElementArray( + Thread* self, size_t length) { + return mirror::ObjectArray<mirror::StackTraceElement>::Alloc( + self, GetClassRoot(kJavaLangStackTraceElementArrayClass), length); } static mirror::Class* EnsureResolved(Thread* self, mirror::Class* klass) @@ -1332,10 +1315,12 @@ bool ClassLinker::IsInBootClassPath(const char* descriptor) { } mirror::Class* ClassLinker::FindSystemClass(const char* descriptor) { - return FindClass(descriptor, NULL); + SirtRef<mirror::ClassLoader> class_loader(Thread::Current(), nullptr); + return FindClass(descriptor, class_loader); } -mirror::Class* ClassLinker::FindClass(const char* descriptor, mirror::ClassLoader* class_loader) { +mirror::Class* ClassLinker::FindClass(const char* descriptor, + SirtRef<mirror::ClassLoader>& class_loader) { DCHECK_NE(*descriptor, '\0') << "descriptor is empty string"; Thread* self = Thread::Current(); DCHECK(self != NULL); @@ -1346,20 +1331,19 @@ mirror::Class* ClassLinker::FindClass(const char* descriptor, mirror::ClassLoade return FindPrimitiveClass(descriptor[0]); } // Find the class in the loaded classes table. - mirror::Class* klass = LookupClass(descriptor, class_loader); + mirror::Class* klass = LookupClass(descriptor, class_loader.get()); if (klass != NULL) { return EnsureResolved(self, klass); } // Class is not yet loaded. if (descriptor[0] == '[') { return CreateArrayClass(descriptor, class_loader); - - } else if (class_loader == NULL) { + } else if (class_loader.get() == nullptr) { DexFile::ClassPathEntry pair = DexFile::FindInClassPath(descriptor, boot_class_path_); if (pair.second != NULL) { - return DefineClass(descriptor, NULL, *pair.first, *pair.second); + SirtRef<mirror::ClassLoader> class_loader(self, nullptr); + return DefineClass(descriptor, class_loader, *pair.first, *pair.second); } - } else if (Runtime::Current()->UseCompileTimeClassPath()) { // First try the boot class path, we check the descriptor first to avoid an unnecessary // throw of a NoClassDefFoundError. @@ -1372,7 +1356,8 @@ mirror::Class* ClassLinker::FindClass(const char* descriptor, mirror::ClassLoade const std::vector<const DexFile*>* class_path; { ScopedObjectAccessUnchecked soa(self); - ScopedLocalRef<jobject> jclass_loader(soa.Env(), soa.AddLocalReference<jobject>(class_loader)); + ScopedLocalRef<jobject> jclass_loader(soa.Env(), + soa.AddLocalReference<jobject>(class_loader.get())); class_path = &Runtime::Current()->GetCompileTimeClassPath(jclass_loader.get()); } @@ -1384,7 +1369,7 @@ mirror::Class* ClassLinker::FindClass(const char* descriptor, mirror::ClassLoade } else { ScopedObjectAccessUnchecked soa(self->GetJniEnv()); ScopedLocalRef<jobject> class_loader_object(soa.Env(), - soa.AddLocalReference<jobject>(class_loader)); + soa.AddLocalReference<jobject>(class_loader.get())); std::string class_name_string(DescriptorToDot(descriptor)); ScopedLocalRef<jobject> result(soa.Env(), NULL); { @@ -1418,7 +1403,7 @@ mirror::Class* ClassLinker::FindClass(const char* descriptor, mirror::ClassLoade } mirror::Class* ClassLinker::DefineClass(const char* descriptor, - mirror::ClassLoader* class_loader, + SirtRef<mirror::ClassLoader>& class_loader, const DexFile& dex_file, const DexFile::ClassDef& dex_class_def) { Thread* self = Thread::Current(); @@ -1449,7 +1434,7 @@ mirror::Class* ClassLinker::DefineClass(const char* descriptor, return NULL; } klass->SetDexCache(FindDexCache(dex_file)); - LoadClass(dex_file, dex_class_def, klass, class_loader); + LoadClass(dex_file, dex_class_def, klass, class_loader.get()); // Check for a pending exception during load if (self->IsExceptionPending()) { klass->SetStatus(mirror::Class::kStatusError, self); @@ -1457,14 +1442,12 @@ mirror::Class* ClassLinker::DefineClass(const char* descriptor, } ObjectLock lock(self, klass.get()); klass->SetClinitThreadId(self->GetTid()); - { - // 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); - } + // 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()); @@ -1476,7 +1459,9 @@ mirror::Class* ClassLinker::DefineClass(const char* descriptor, CHECK(klass->IsLoaded()); // Link the class (if necessary) CHECK(!klass->IsResolved()); - if (!LinkClass(klass, NULL, self)) { + // TODO: Use fast jobjects? + SirtRef<mirror::ObjectArray<mirror::Class> > interfaces(self, nullptr); + if (!LinkClass(self, klass, interfaces)) { // Linking failed. klass->SetStatus(mirror::Class::kStatusError, self); return NULL; @@ -2083,7 +2068,7 @@ mirror::Class* ClassLinker::InitializePrimitiveClass(mirror::Class* primitive_cl // // Returns NULL with an exception raised on failure. mirror::Class* ClassLinker::CreateArrayClass(const char* descriptor, - mirror::ClassLoader* class_loader) { + SirtRef<mirror::ClassLoader>& class_loader) { // Identify the underlying component type CHECK_EQ('[', descriptor[0]); mirror::Class* component_type = FindClass(descriptor + 1, class_loader); @@ -2109,7 +2094,7 @@ mirror::Class* ClassLinker::CreateArrayClass(const char* descriptor, // because we effectively do this lookup again when we add the new // class to the hash table --- necessary because of possible races with // other threads.) - if (class_loader != component_type->GetClassLoader()) { + if (class_loader.get() != component_type->GetClassLoader()) { mirror::Class* new_class = LookupClass(descriptor, component_type->GetClassLoader()); if (new_class != NULL) { return new_class; @@ -2266,11 +2251,10 @@ mirror::Class* ClassLinker::InsertClass(const char* descriptor, mirror::Class* k bool ClassLinker::RemoveClass(const char* descriptor, const mirror::ClassLoader* class_loader) { size_t hash = Hash(descriptor); WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_); - ClassHelper kh; 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); + ClassHelper kh(klass); if ((klass->GetClassLoader() == class_loader) && (strcmp(descriptor, kh.GetDescriptor()) == 0)) { class_table_.erase(it); @@ -2313,18 +2297,17 @@ mirror::Class* ClassLinker::LookupClass(const char* descriptor, mirror::Class* ClassLinker::LookupClassFromTableLocked(const char* descriptor, const mirror::ClassLoader* class_loader, size_t hash) { - ClassHelper kh(NULL, this); 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); + ClassHelper kh(klass); 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); + ClassHelper kh(klass2); CHECK(!((klass2->GetClassLoader() == class_loader) && (strcmp(descriptor, kh.GetDescriptor()) == 0))) << PrettyClass(klass) << " " << klass << " " << klass->GetClassLoader() << " " @@ -2354,14 +2337,13 @@ void ClassLinker::MoveImageClassesToClassTable() { 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 (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); + ClassHelper kh(klass); DCHECK(klass->GetClassLoader() == NULL); const char* descriptor = kh.GetDescriptor(); size_t hash = Hash(descriptor); @@ -2429,11 +2411,10 @@ void ClassLinker::LookupClasses(const char* descriptor, std::vector<mirror::Clas } 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); + ClassHelper kh(klass); if (strcmp(descriptor, kh.GetDescriptor()) == 0) { result.push_back(klass); } @@ -2687,12 +2668,10 @@ static void CheckProxyConstructor(mirror::ArtMethod* constructor); static void CheckProxyMethod(mirror::ArtMethod* method, SirtRef<mirror::ArtMethod>& prototype); -mirror::Class* ClassLinker::CreateProxyClass(mirror::String* name, - mirror::ObjectArray<mirror::Class>* interfaces, - mirror::ClassLoader* loader, - mirror::ObjectArray<mirror::ArtMethod>* methods, - mirror::ObjectArray<mirror::ObjectArray<mirror::Class> >* throws) { - Thread* self = Thread::Current(); +mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccess& soa, jstring name, + jobjectArray interfaces, jobject loader, + jobjectArray methods, jobjectArray throws) { + Thread* self = soa.Self(); SirtRef<mirror::Class> klass(self, AllocClass(self, GetClassRoot(kJavaLangClass), sizeof(mirror::SynthesizedProxyClass))); if (klass.get() == NULL) { @@ -2702,9 +2681,9 @@ mirror::Class* ClassLinker::CreateProxyClass(mirror::String* name, DCHECK(klass->GetClass() != NULL); klass->SetObjectSize(sizeof(mirror::Proxy)); klass->SetAccessFlags(kAccClassIsProxy | kAccPublic | kAccFinal); - klass->SetClassLoader(loader); + klass->SetClassLoader(soa.Decode<mirror::ClassLoader*>(loader)); DCHECK_EQ(klass->GetPrimitiveType(), Primitive::kPrimNot); - klass->SetName(name); + klass->SetName(soa.Decode<mirror::String*>(name)); mirror::Class* proxy_class = GetClassRoot(kJavaLangReflectProxy); klass->SetDexCache(proxy_class->GetDexCache()); klass->SetStatus(mirror::Class::kStatusIdx, self); @@ -2742,8 +2721,7 @@ mirror::Class* ClassLinker::CreateProxyClass(mirror::String* name, // Proxies have 1 direct method, the constructor { - mirror::ObjectArray<mirror::ArtMethod>* directs = - AllocArtMethodArray(self, 1); + mirror::ObjectArray<mirror::ArtMethod>* directs = AllocArtMethodArray(self, 1); if (UNLIKELY(directs == NULL)) { CHECK(self->IsExceptionPending()); // OOME. return NULL; @@ -2757,11 +2735,11 @@ mirror::Class* ClassLinker::CreateProxyClass(mirror::String* name, klass->SetDirectMethod(0, constructor); } - // Create virtual method using specified prototypes - size_t num_virtual_methods = methods->GetLength(); + // Create virtual method using specified prototypes. + size_t num_virtual_methods = + soa.Decode<mirror::ObjectArray<mirror::ArtMethod>*>(methods)->GetLength(); { - mirror::ObjectArray<mirror::ArtMethod>* virtuals = - AllocArtMethodArray(self, num_virtual_methods); + mirror::ObjectArray<mirror::ArtMethod>* virtuals = AllocArtMethodArray(self, num_virtual_methods); if (UNLIKELY(virtuals == NULL)) { CHECK(self->IsExceptionPending()); // OOME. return NULL; @@ -2769,7 +2747,9 @@ mirror::Class* ClassLinker::CreateProxyClass(mirror::String* name, klass->SetVirtualMethods(virtuals); } for (size_t i = 0; i < num_virtual_methods; ++i) { - SirtRef<mirror::ArtMethod> prototype(self, methods->Get(i)); + mirror::ObjectArray<mirror::ArtMethod>* decoded_methods = + soa.Decode<mirror::ObjectArray<mirror::ArtMethod>*>(methods); + SirtRef<mirror::ArtMethod> prototype(self, decoded_methods->Get(i)); mirror::ArtMethod* clone = CreateProxyMethod(self, klass, prototype); if (UNLIKELY(clone == NULL)) { CHECK(self->IsExceptionPending()); // OOME. @@ -2785,13 +2765,15 @@ mirror::Class* ClassLinker::CreateProxyClass(mirror::String* name, { 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)) { + SirtRef<mirror::ObjectArray<mirror::Class> > sirt_interfaces( + self, soa.Decode<mirror::ObjectArray<mirror::Class>*>(interfaces)); + if (!LinkClass(self, klass, sirt_interfaces)) { klass->SetStatus(mirror::Class::kStatusError, self); return NULL; } - interfaces_sfield->SetObject(klass.get(), interfaces); - throws_sfield->SetObject(klass.get(), throws); + interfaces_sfield->SetObject(klass.get(), soa.Decode<mirror::ObjectArray<mirror::Class>*>(interfaces)); + throws_sfield->SetObject(klass.get(), soa.Decode<mirror::ObjectArray<mirror::ObjectArray<mirror::Class> >*>(throws)); klass->SetStatus(mirror::Class::kStatusInitialized, self); } @@ -2800,22 +2782,25 @@ mirror::Class* ClassLinker::CreateProxyClass(mirror::String* name, CHECK(klass->GetIFields() == NULL); CheckProxyConstructor(klass->GetDirectMethod(0)); for (size_t i = 0; i < num_virtual_methods; ++i) { - SirtRef<mirror::ArtMethod> prototype(self, methods->Get(i)); + mirror::ObjectArray<mirror::ArtMethod>* decoded_methods = + soa.Decode<mirror::ObjectArray<mirror::ArtMethod>*>(methods); + SirtRef<mirror::ArtMethod> prototype(self, decoded_methods->Get(i)); CheckProxyMethod(klass->GetVirtualMethod(i), prototype); } + mirror::String* decoded_name = soa.Decode<mirror::String*>(name); std::string interfaces_field_name(StringPrintf("java.lang.Class[] %s.interfaces", - name->ToModifiedUtf8().c_str())); + decoded_name->ToModifiedUtf8().c_str())); CHECK_EQ(PrettyField(klass->GetStaticField(0)), interfaces_field_name); std::string throws_field_name(StringPrintf("java.lang.Class[][] %s.throws", - name->ToModifiedUtf8().c_str())); + decoded_name->ToModifiedUtf8().c_str())); CHECK_EQ(PrettyField(klass->GetStaticField(1)), throws_field_name); mirror::SynthesizedProxyClass* synth_proxy_class = down_cast<mirror::SynthesizedProxyClass*>(klass.get()); - CHECK_EQ(synth_proxy_class->GetInterfaces(), interfaces); - CHECK_EQ(synth_proxy_class->GetThrows(), throws); + CHECK_EQ(synth_proxy_class->GetInterfaces(), soa.Decode<mirror::ObjectArray<mirror::Class>*>(interfaces)); + CHECK_EQ(synth_proxy_class->GetThrows(), soa.Decode<mirror::ObjectArray<mirror::ObjectArray<mirror::Class> >*>(throws)); } std::string descriptor(GetDescriptorForProxy(klass.get())); mirror::Class* existing = InsertClass(descriptor.c_str(), klass.get(), Hash(descriptor.c_str())); @@ -2977,6 +2962,10 @@ static bool CanWeInitializeClass(mirror::Class* klass, bool can_init_statics, return true; } +bool ClassLinker::IsInitialized() const { + return init_done_; +} + bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_init_statics, bool can_init_parents) { // see JLS 3rd edition, 12.4.2 "Detailed Initialization Procedure" for the locking protocol @@ -3084,7 +3073,9 @@ bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_init_statics, const DexFile::ClassDef* dex_class_def = kh.GetClassDef(); CHECK(dex_class_def != NULL); const DexFile& dex_file = kh.GetDexFile(); - EncodedStaticFieldValueIterator it(dex_file, kh.GetDexCache(), klass->GetClassLoader(), + SirtRef<mirror::ClassLoader> class_loader(self, klass->GetClassLoader()); + SirtRef<mirror::DexCache> dex_cache(self, kh.GetDexCache()); + EncodedStaticFieldValueIterator it(dex_file, &dex_cache, &class_loader, this, *dex_class_def); if (it.HasNext()) { CHECK(can_init_statics); @@ -3196,12 +3187,11 @@ bool ClassLinker::ValidateSuperClassDescriptors(const mirror::Class* klass) { } } } - mirror::IfTable* iftable = klass->GetIfTable(); for (int32_t i = 0; i < klass->GetIfTableCount(); ++i) { - mirror::Class* interface = iftable->GetInterface(i); + mirror::Class* interface = klass->GetIfTable()->GetInterface(i); if (klass->GetClassLoader() != interface->GetClassLoader()) { for (size_t j = 0; j < interface->NumVirtualMethods(); ++j) { - const mirror::ArtMethod* method = iftable->GetMethodArray(i)->Get(j); + const mirror::ArtMethod* method = klass->GetIfTable()->GetMethodArray(i)->Get(j); if (!IsSameMethodSignatureInDifferentClassContexts(method, interface, method->GetDeclaringClass())) { ThrowLinkageError(klass, "Class %s method %s resolves differently in interface %s", @@ -3259,11 +3249,14 @@ bool ClassLinker::IsSameDescriptorInDifferentClassContexts(const char* descripto if (klass1 == klass2) { return true; } - mirror::Class* found1 = FindClass(descriptor, klass1->GetClassLoader()); + Thread* self = Thread::Current(); + SirtRef<mirror::ClassLoader> class_loader1(self, klass1->GetClassLoader()); + mirror::Class* found1 = FindClass(descriptor, class_loader1); if (found1 == NULL) { Thread::Current()->ClearException(); } - mirror::Class* found2 = FindClass(descriptor, klass2->GetClassLoader()); + SirtRef<mirror::ClassLoader> class_loader2(self, klass2->GetClassLoader()); + mirror::Class* found2 = FindClass(descriptor, class_loader2); if (found2 == NULL) { Thread::Current()->ClearException(); } @@ -3285,17 +3278,20 @@ bool ClassLinker::EnsureInitialized(mirror::Class* c, bool can_init_fields, bool } void ClassLinker::ConstructFieldMap(const DexFile& dex_file, const DexFile::ClassDef& dex_class_def, - mirror::Class* c, SafeMap<uint32_t, mirror::ArtField*>& field_map) { - mirror::ClassLoader* cl = c->GetClassLoader(); + mirror::Class* c, + SafeMap<uint32_t, mirror::ArtField*>& field_map) { const byte* class_data = dex_file.GetClassData(dex_class_def); ClassDataItemIterator it(dex_file, class_data); + Thread* self = Thread::Current(); + SirtRef<mirror::DexCache> dex_cache(self, c->GetDexCache()); + SirtRef<mirror::ClassLoader> class_loader(self, c->GetClassLoader()); for (size_t i = 0; it.HasNextStaticField(); i++, it.Next()) { - field_map.Put(i, ResolveField(dex_file, it.GetMemberIndex(), c->GetDexCache(), cl, true)); + field_map.Put(i, ResolveField(dex_file, it.GetMemberIndex(), dex_cache, class_loader, true)); } } -bool ClassLinker::LinkClass(SirtRef<mirror::Class>& klass, - mirror::ObjectArray<mirror::Class>* interfaces, Thread* self) { +bool ClassLinker::LinkClass(Thread* self, SirtRef<mirror::Class>& klass, + SirtRef<mirror::ObjectArray<mirror::Class> >& interfaces) { CHECK_EQ(mirror::Class::kStatusLoaded, klass->GetStatus()); if (!LinkSuperClass(klass)) { return false; @@ -3419,7 +3415,7 @@ bool ClassLinker::LinkSuperClass(SirtRef<mirror::Class>& klass) { // Populate the class vtable and itable. Compute return type indices. bool ClassLinker::LinkMethods(SirtRef<mirror::Class>& klass, - mirror::ObjectArray<mirror::Class>* interfaces) { + SirtRef<mirror::ObjectArray<mirror::Class> >& interfaces) { if (klass->IsInterface()) { // No vtable. size_t count = klass->NumVirtualMethods(); @@ -3453,15 +3449,13 @@ bool ClassLinker::LinkVirtualMethods(SirtRef<mirror::Class>& klass) { return false; } // See if any of our virtual methods override the superclass. - MethodHelper local_mh(NULL, this); - MethodHelper super_mh(NULL, this); for (size_t i = 0; i < klass->NumVirtualMethods(); ++i) { mirror::ArtMethod* local_method = klass->GetVirtualMethodDuringLinking(i); - local_mh.ChangeMethod(local_method); + MethodHelper local_mh(local_method); size_t j = 0; for (; j < actual_count; ++j) { mirror::ArtMethod* super_method = vtable->Get(j); - super_mh.ChangeMethod(super_method); + MethodHelper super_mh(super_method); if (local_mh.HasSameNameAndSignature(&super_mh)) { if (klass->CanAccessMember(super_method->GetDeclaringClass(), super_method->GetAccessFlags())) { if (super_method->IsFinal()) { @@ -3525,7 +3519,7 @@ bool ClassLinker::LinkVirtualMethods(SirtRef<mirror::Class>& klass) { } bool ClassLinker::LinkInterfaceMethods(SirtRef<mirror::Class>& klass, - mirror::ObjectArray<mirror::Class>* interfaces) { + SirtRef<mirror::ObjectArray<mirror::Class> >& interfaces) { // Set the imt table to be all conflicts by default. klass->SetImTable(Runtime::Current()->GetDefaultImt()); size_t super_ifcount; @@ -3535,11 +3529,13 @@ bool ClassLinker::LinkInterfaceMethods(SirtRef<mirror::Class>& klass, super_ifcount = 0; } size_t ifcount = super_ifcount; - ClassHelper kh(klass.get(), this); - uint32_t num_interfaces = interfaces == NULL ? kh.NumDirectInterfaces() : interfaces->GetLength(); + ClassHelper kh(klass.get()); + uint32_t num_interfaces = + interfaces.get() == nullptr ? kh.NumDirectInterfaces() : interfaces->GetLength(); ifcount += num_interfaces; for (size_t i = 0; i < num_interfaces; i++) { - mirror::Class* interface = interfaces == NULL ? kh.GetDirectInterface(i) : interfaces->Get(i); + mirror::Class* interface = + interfaces.get() == nullptr ? kh.GetDirectInterface(i) : interfaces->Get(i); ifcount += interface->GetIfTableCount(); } if (ifcount == 0) { @@ -3580,7 +3576,8 @@ bool ClassLinker::LinkInterfaceMethods(SirtRef<mirror::Class>& klass, // Flatten the interface inheritance hierarchy. size_t idx = super_ifcount; for (size_t i = 0; i < num_interfaces; i++) { - mirror::Class* interface = interfaces == NULL ? kh.GetDirectInterface(i) : interfaces->Get(i); + mirror::Class* interface = + interfaces.get() == nullptr ? kh.GetDirectInterface(i) : interfaces->Get(i); DCHECK(interface != NULL); if (!interface->IsInterface()) { ClassHelper ih(interface); @@ -3643,20 +3640,21 @@ bool ClassLinker::LinkInterfaceMethods(SirtRef<mirror::Class>& klass, return false; } std::vector<mirror::ArtMethod*> miranda_list; - MethodHelper vtable_mh(NULL, this); - MethodHelper interface_mh(NULL, this); + MethodHelper vtable_mh(NULL); + MethodHelper interface_mh(NULL); for (size_t i = 0; i < ifcount; ++i) { mirror::Class* interface = iftable->GetInterface(i); size_t num_methods = interface->NumVirtualMethods(); if (num_methods > 0) { - mirror::ObjectArray<mirror::ArtMethod>* method_array = - AllocArtMethodArray(self, num_methods); - if (UNLIKELY(method_array == NULL)) { + SirtRef<mirror::ObjectArray<mirror::ArtMethod> > + method_array(self, AllocArtMethodArray(self, num_methods)); + if (UNLIKELY(method_array.get() == nullptr)) { CHECK(self->IsExceptionPending()); // OOME. return false; } - iftable->SetMethodArray(i, method_array); - mirror::ObjectArray<mirror::ArtMethod>* vtable = klass->GetVTableDuringLinking(); + iftable->SetMethodArray(i, method_array.get()); + SirtRef<mirror::ObjectArray<mirror::ArtMethod> > vtable(self, + klass->GetVTableDuringLinking()); for (size_t j = 0; j < num_methods; ++j) { mirror::ArtMethod* interface_method = interface->GetVirtualMethod(j); interface_mh.ChangeMethod(interface_method); @@ -3709,10 +3707,7 @@ bool ClassLinker::LinkInterfaceMethods(SirtRef<mirror::Class>& klass, CHECK(self->IsExceptionPending()); // OOME. return false; } -#ifdef MOVING_GARBAGE_COLLECTOR // TODO: If a methods move then the miranda_list may hold stale references. - UNIMPLEMENTED(FATAL); -#endif miranda_list.push_back(miranda_method.get()); } method_array->Set(j, miranda_method.get()); @@ -3791,17 +3786,16 @@ bool ClassLinker::LinkStaticFields(SirtRef<mirror::Class>& klass) { } struct LinkFieldsComparator { - explicit LinkFieldsComparator(FieldHelper* fh) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) - : fh_(fh) {} + explicit LinkFieldsComparator() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + } // No thread safety analysis as will be called from STL. Checked lock held in constructor. bool operator()(const mirror::ArtField* field1, const mirror::ArtField* field2) NO_THREAD_SAFETY_ANALYSIS { // First come reference fields, then 64-bit, and finally 32-bit - fh_->ChangeField(field1); - Primitive::Type type1 = fh_->GetTypeAsPrimitiveType(); - fh_->ChangeField(field2); - Primitive::Type type2 = fh_->GetTypeAsPrimitiveType(); + FieldHelper fh1(field1); + Primitive::Type type1 = fh1.GetTypeAsPrimitiveType(); + FieldHelper fh2(field2); + Primitive::Type type2 = fh2.GetTypeAsPrimitiveType(); bool isPrimitive1 = type1 != Primitive::kPrimNot; bool isPrimitive2 = type2 != Primitive::kPrimNot; bool is64bit1 = isPrimitive1 && (type1 == Primitive::kPrimLong || type1 == Primitive::kPrimDouble); @@ -3813,14 +3807,10 @@ struct LinkFieldsComparator { } // same basic group? then sort by string. - fh_->ChangeField(field1); - const char* name1 = fh_->GetName(); - fh_->ChangeField(field2); - const char* name2 = fh_->GetName(); + const char* name1 = fh1.GetName(); + const char* name2 = fh2.GetName(); return strcmp(name1, name2) < 0; } - - FieldHelper* fh_; }; bool ClassLinker::LinkFields(SirtRef<mirror::Class>& klass, bool is_static) { @@ -3855,17 +3845,15 @@ bool ClassLinker::LinkFields(SirtRef<mirror::Class>& klass, bool is_static) { CHECK(f != NULL); grouped_and_sorted_fields.push_back(f); } - FieldHelper fh(NULL, this); - std::sort(grouped_and_sorted_fields.begin(), - grouped_and_sorted_fields.end(), - LinkFieldsComparator(&fh)); + std::sort(grouped_and_sorted_fields.begin(), grouped_and_sorted_fields.end(), + LinkFieldsComparator()); // References should be at the front. size_t current_field = 0; size_t num_reference_fields = 0; for (; current_field < num_fields; current_field++) { mirror::ArtField* field = grouped_and_sorted_fields.front(); - fh.ChangeField(field); + FieldHelper fh(field); Primitive::Type type = fh.GetTypeAsPrimitiveType(); bool isPrimitive = type != Primitive::kPrimNot; if (isPrimitive) { @@ -3884,7 +3872,7 @@ bool ClassLinker::LinkFields(SirtRef<mirror::Class>& klass, bool is_static) { if (current_field != num_fields && !IsAligned<8>(field_offset.Uint32Value())) { for (size_t i = 0; i < grouped_and_sorted_fields.size(); i++) { mirror::ArtField* field = grouped_and_sorted_fields[i]; - fh.ChangeField(field); + FieldHelper fh(field); Primitive::Type type = fh.GetTypeAsPrimitiveType(); CHECK(type != Primitive::kPrimNot); // should only be working on primitive types if (type == Primitive::kPrimLong || type == Primitive::kPrimDouble) { @@ -3906,7 +3894,7 @@ bool ClassLinker::LinkFields(SirtRef<mirror::Class>& klass, bool is_static) { while (!grouped_and_sorted_fields.empty()) { mirror::ArtField* field = grouped_and_sorted_fields.front(); grouped_and_sorted_fields.pop_front(); - fh.ChangeField(field); + FieldHelper fh(field); Primitive::Type type = fh.GetTypeAsPrimitiveType(); CHECK(type != Primitive::kPrimNot); // should only be working on primitive types fields->Set(current_field, field); @@ -3920,11 +3908,11 @@ bool ClassLinker::LinkFields(SirtRef<mirror::Class>& klass, bool is_static) { // We lie to the GC about the java.lang.ref.Reference.referent field, so it doesn't scan it. if (!is_static && - (strcmp("Ljava/lang/ref/Reference;", ClassHelper(klass.get(), this).GetDescriptor()) == 0)) { + (strcmp("Ljava/lang/ref/Reference;", ClassHelper(klass.get()).GetDescriptor()) == 0)) { // We know there are no non-reference fields in the Reference classes, and we know // that 'referent' is alphabetically last, so this is easy... CHECK_EQ(num_reference_fields, num_fields); - fh.ChangeField(fields->Get(num_fields - 1)); + FieldHelper fh(fields->Get(num_fields - 1)); CHECK_STREQ(fh.GetName(), "referent"); --num_reference_fields; } @@ -3942,10 +3930,10 @@ bool ClassLinker::LinkFields(SirtRef<mirror::Class>& klass, bool is_static) { << " offset=" << field->GetField32(MemberOffset(mirror::ArtField::OffsetOffset()), false); } - fh.ChangeField(field); + FieldHelper fh(field); Primitive::Type type = fh.GetTypeAsPrimitiveType(); bool is_primitive = type != Primitive::kPrimNot; - if ((strcmp("Ljava/lang/ref/Reference;", ClassHelper(klass.get(), this).GetDescriptor()) == 0) + if ((strcmp("Ljava/lang/ref/Reference;", ClassHelper(klass.get()).GetDescriptor()) == 0) && (strcmp("referent", fh.GetName()) == 0)) { is_primitive = true; // We lied above, so we have to expect a lie here. } @@ -3970,7 +3958,7 @@ bool ClassLinker::LinkFields(SirtRef<mirror::Class>& klass, bool is_static) { } else { klass->SetNumReferenceInstanceFields(num_reference_fields); if (!klass->IsVariableSize()) { - DCHECK_GE(size, sizeof(mirror::Object)) << ClassHelper(klass.get(), this).GetDescriptor(); + DCHECK_GE(size, sizeof(mirror::Object)) << ClassHelper(klass.get()).GetDescriptor(); size_t previous_size = klass->GetObjectSize(); if (previous_size != 0) { // Make sure that we didn't originally have an incorrect size. @@ -4034,9 +4022,9 @@ void ClassLinker::CreateReferenceOffsets(SirtRef<mirror::Class>& klass, bool is_ } } -mirror::String* ClassLinker::ResolveString(const DexFile& dex_file, - uint32_t string_idx, mirror::DexCache* dex_cache) { - DCHECK(dex_cache != NULL); +mirror::String* ClassLinker::ResolveString(const DexFile& dex_file, uint32_t string_idx, + SirtRef<mirror::DexCache>& dex_cache) { + DCHECK(dex_cache.get() != nullptr); mirror::String* resolved = dex_cache->GetResolvedString(string_idx); if (resolved != NULL) { return resolved; @@ -4048,11 +4036,18 @@ mirror::String* ClassLinker::ResolveString(const DexFile& dex_file, return string; } -mirror::Class* ClassLinker::ResolveType(const DexFile& dex_file, - uint16_t type_idx, - mirror::DexCache* dex_cache, - mirror::ClassLoader* class_loader) { - DCHECK(dex_cache != NULL); +mirror::Class* ClassLinker::ResolveType(const DexFile& dex_file, uint16_t type_idx, + const mirror::Class* referrer) { + Thread* self = Thread::Current(); + SirtRef<mirror::DexCache> dex_cache(self, referrer->GetDexCache()); + SirtRef<mirror::ClassLoader> class_loader(self, referrer->GetClassLoader()); + return ResolveType(dex_file, type_idx, dex_cache, class_loader); +} + +mirror::Class* ClassLinker::ResolveType(const DexFile& dex_file, uint16_t type_idx, + SirtRef<mirror::DexCache>& dex_cache, + SirtRef<mirror::ClassLoader>& class_loader) { + DCHECK(dex_cache.get() != NULL); mirror::Class* resolved = dex_cache->GetResolvedType(type_idx); if (resolved == NULL) { const char* descriptor = dex_file.StringByTypeIdx(type_idx); @@ -4082,11 +4077,11 @@ mirror::Class* ClassLinker::ResolveType(const DexFile& dex_file, mirror::ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file, uint32_t method_idx, - mirror::DexCache* dex_cache, - mirror::ClassLoader* class_loader, + SirtRef<mirror::DexCache>& dex_cache, + SirtRef<mirror::ClassLoader>& class_loader, const mirror::ArtMethod* referrer, InvokeType type) { - DCHECK(dex_cache != NULL); + DCHECK(dex_cache.get() != NULL); // Check for hit in the dex cache. mirror::ArtMethod* resolved = dex_cache->GetResolvedMethod(method_idx); if (resolved != NULL && !resolved->IsRuntimeMethod()) { @@ -4104,15 +4099,15 @@ mirror::ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file, switch (type) { case kDirect: // Fall-through. case kStatic: - resolved = klass->FindDirectMethod(dex_cache, method_idx); + resolved = klass->FindDirectMethod(dex_cache.get(), method_idx); break; case kInterface: - resolved = klass->FindInterfaceMethod(dex_cache, method_idx); + resolved = klass->FindInterfaceMethod(dex_cache.get(), method_idx); DCHECK(resolved == NULL || resolved->GetDeclaringClass()->IsInterface()); break; case kSuper: // Fall-through. case kVirtual: - resolved = klass->FindVirtualMethod(dex_cache, method_idx); + resolved = klass->FindVirtualMethod(dex_cache.get(), method_idx); break; default: LOG(FATAL) << "Unreachable - invocation type: " << type; @@ -4227,12 +4222,11 @@ mirror::ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file, } } -mirror::ArtField* ClassLinker::ResolveField(const DexFile& dex_file, - uint32_t field_idx, - mirror::DexCache* dex_cache, - mirror::ClassLoader* class_loader, +mirror::ArtField* ClassLinker::ResolveField(const DexFile& dex_file, uint32_t field_idx, + SirtRef<mirror::DexCache>& dex_cache, + SirtRef<mirror::ClassLoader>& class_loader, bool is_static) { - DCHECK(dex_cache != NULL); + DCHECK(dex_cache.get() != nullptr); mirror::ArtField* resolved = dex_cache->GetResolvedField(field_idx); if (resolved != NULL) { return resolved; @@ -4245,9 +4239,9 @@ mirror::ArtField* ClassLinker::ResolveField(const DexFile& dex_file, } if (is_static) { - resolved = klass->FindStaticField(dex_cache, field_idx); + resolved = klass->FindStaticField(dex_cache.get(), field_idx); } else { - resolved = klass->FindInstanceField(dex_cache, field_idx); + resolved = klass->FindInstanceField(dex_cache.get(), field_idx); } if (resolved == NULL) { @@ -4269,9 +4263,9 @@ mirror::ArtField* ClassLinker::ResolveField(const DexFile& dex_file, mirror::ArtField* ClassLinker::ResolveFieldJLS(const DexFile& dex_file, uint32_t field_idx, - mirror::DexCache* dex_cache, - mirror::ClassLoader* class_loader) { - DCHECK(dex_cache != NULL); + SirtRef<mirror::DexCache>& dex_cache, + SirtRef<mirror::ClassLoader>& class_loader) { + DCHECK(dex_cache.get() != nullptr); mirror::ArtField* resolved = dex_cache->GetResolvedField(field_idx); if (resolved != NULL) { return resolved; |