From 590fee9e8972f872301c2d16a575d579ee564bee Mon Sep 17 00:00:00 2001 From: Mathieu Chartier Date: Fri, 13 Sep 2013 13:46:47 -0700 Subject: 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 --- compiler/driver/compiler_driver.cc | 97 +++++++++++++++++++------------------- 1 file changed, 48 insertions(+), 49 deletions(-) (limited to 'compiler/driver/compiler_driver.cc') diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 9cc94e8c0d..4af492bf6e 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -513,10 +513,9 @@ void CompilerDriver::CompileAll(jobject class_loader, } } -static DexToDexCompilationLevel GetDexToDexCompilationlevel(mirror::ClassLoader* class_loader, - const DexFile& dex_file, - const DexFile::ClassDef& class_def) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { +static DexToDexCompilationLevel GetDexToDexCompilationlevel( + SirtRef& class_loader, const DexFile& dex_file, + const DexFile::ClassDef& class_def) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { const char* descriptor = dex_file.GetClassDescriptor(class_def); ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); mirror::Class* klass = class_linker->FindClass(descriptor, class_loader); @@ -531,7 +530,7 @@ static DexToDexCompilationLevel GetDexToDexCompilationlevel(mirror::ClassLoader* // function). Since image classes can be verified again while compiling an application, // we must prevent the DEX-to-DEX compiler from introducing them. // TODO: find a way to enable "quick" instructions for image classes and remove this check. - bool compiling_image_classes = (class_loader == NULL); + bool compiling_image_classes = class_loader.get() == nullptr; if (compiling_image_classes) { return kRequired; } else if (klass->IsVerified()) { @@ -579,7 +578,8 @@ void CompilerDriver::CompileOne(const mirror::ArtMethod* method, base::TimingLog { ScopedObjectAccess soa(Thread::Current()); const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_idx); - mirror::ClassLoader* class_loader = soa.Decode(jclass_loader); + SirtRef class_loader(soa.Self(), + soa.Decode(jclass_loader)); dex_to_dex_compilation_level = GetDexToDexCompilationlevel(class_loader, *dex_file, class_def); } CompileMethod(code_item, method->GetAccessFlags(), method->GetInvokeType(), @@ -721,8 +721,8 @@ void CompilerDriver::LoadImageClasses(base::TimingLogger& timings) for (const std::pair& exception_type : unresolved_exception_types) { uint16_t exception_type_idx = exception_type.first; const DexFile* dex_file = exception_type.second; - mirror::DexCache* dex_cache = class_linker->FindDexCache(*dex_file); - mirror:: ClassLoader* class_loader = NULL; + SirtRef dex_cache(self, class_linker->FindDexCache(*dex_file)); + SirtRef class_loader(self, nullptr); SirtRef klass(self, class_linker->ResolveType(*dex_file, exception_type_idx, dex_cache, class_loader)); if (klass.get() == NULL) { @@ -782,15 +782,14 @@ void CompilerDriver::UpdateImageClasses(base::TimingLogger& timings) { const char* old_cause = self->StartAssertNoThreadSuspension("ImageWriter"); gc::Heap* heap = Runtime::Current()->GetHeap(); // TODO: Image spaces only? + ScopedObjectAccess soa(Thread::Current()); WriterMutexLock mu(self, *Locks::heap_bitmap_lock_); - heap->FlushAllocStack(); - heap->GetLiveBitmap()->Walk(FindClinitImageClassesCallback, this); + heap->VisitObjects(FindClinitImageClassesCallback, this); self->EndAssertNoThreadSuspension(old_cause); } } -bool CompilerDriver::CanAssumeTypeIsPresentInDexCache(const DexFile& dex_file, - uint32_t type_idx) { +bool CompilerDriver::CanAssumeTypeIsPresentInDexCache(const DexFile& dex_file, uint32_t type_idx) { if (IsImage() && IsImageClass(dex_file.StringDataByIdx(dex_file.GetTypeId(type_idx).descriptor_idx_))) { if (kIsDebugBuild) { @@ -815,7 +814,7 @@ bool CompilerDriver::CanAssumeStringIsPresentInDexCache(const DexFile& dex_file, if (IsImage()) { // We resolve all const-string strings when building for the image. ScopedObjectAccess soa(Thread::Current()); - mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(dex_file); + SirtRef dex_cache(soa.Self(), Runtime::Current()->GetClassLinker()->FindDexCache(dex_file)); Runtime::Current()->GetClassLinker()->ResolveString(dex_file, string_idx, dex_cache); result = true; } @@ -903,26 +902,27 @@ bool CompilerDriver::CanAccessInstantiableTypeWithoutChecks(uint32_t referrer_id } static mirror::Class* ComputeCompilingMethodsClass(ScopedObjectAccess& soa, - mirror::DexCache* dex_cache, + SirtRef& dex_cache, const DexCompilationUnit* mUnit) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { // The passed dex_cache is a hint, sanity check before asking the class linker that will take a // lock. if (dex_cache->GetDexFile() != mUnit->GetDexFile()) { - dex_cache = mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile()); + dex_cache.reset(mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile())); } - mirror::ClassLoader* class_loader = soa.Decode(mUnit->GetClassLoader()); - const DexFile::MethodId& referrer_method_id = mUnit->GetDexFile()->GetMethodId(mUnit->GetDexMethodIndex()); + SirtRef + class_loader(soa.Self(), soa.Decode(mUnit->GetClassLoader())); + const DexFile::MethodId& referrer_method_id = + mUnit->GetDexFile()->GetMethodId(mUnit->GetDexMethodIndex()); return mUnit->GetClassLinker()->ResolveType(*mUnit->GetDexFile(), referrer_method_id.class_idx_, dex_cache, class_loader); } -static mirror::ArtField* ComputeFieldReferencedFromCompilingMethod(ScopedObjectAccess& soa, - const DexCompilationUnit* mUnit, - uint32_t field_idx) +static mirror::ArtField* ComputeFieldReferencedFromCompilingMethod( + ScopedObjectAccess& soa, const DexCompilationUnit* mUnit, uint32_t field_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - mirror::DexCache* dex_cache = mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile()); - mirror::ClassLoader* class_loader = soa.Decode(mUnit->GetClassLoader()); + SirtRef dex_cache(soa.Self(), mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile())); + SirtRef class_loader(soa.Self(), soa.Decode(mUnit->GetClassLoader())); return mUnit->GetClassLinker()->ResolveField(*mUnit->GetDexFile(), field_idx, dex_cache, class_loader, false); } @@ -932,8 +932,8 @@ static mirror::ArtMethod* ComputeMethodReferencedFromCompilingMethod(ScopedObjec uint32_t method_idx, InvokeType type) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - mirror::DexCache* dex_cache = mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile()); - mirror::ClassLoader* class_loader = soa.Decode(mUnit->GetClassLoader()); + SirtRef dex_cache(soa.Self(), mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile())); + SirtRef class_loader(soa.Self(), soa.Decode(mUnit->GetClassLoader())); return mUnit->GetClassLinker()->ResolveMethod(*mUnit->GetDexFile(), method_idx, dex_cache, class_loader, NULL, type); } @@ -947,9 +947,10 @@ bool CompilerDriver::ComputeInstanceFieldInfo(uint32_t field_idx, const DexCompi // Try to resolve field and ignore if an Incompatible Class Change Error (ie is static). mirror::ArtField* resolved_field = ComputeFieldReferencedFromCompilingMethod(soa, mUnit, field_idx); if (resolved_field != NULL && !resolved_field->IsStatic()) { + SirtRef dex_cache(soa.Self(), + resolved_field->GetDeclaringClass()->GetDexCache()); mirror::Class* referrer_class = - ComputeCompilingMethodsClass(soa, resolved_field->GetDeclaringClass()->GetDexCache(), - mUnit); + ComputeCompilingMethodsClass(soa, dex_cache, mUnit); if (referrer_class != NULL) { mirror::Class* fields_class = resolved_field->GetDeclaringClass(); bool access_ok = referrer_class->CanAccess(fields_class) && @@ -997,9 +998,9 @@ bool CompilerDriver::ComputeStaticFieldInfo(uint32_t field_idx, const DexCompila // Try to resolve field and ignore if an Incompatible Class Change Error (ie isn't static). mirror::ArtField* resolved_field = ComputeFieldReferencedFromCompilingMethod(soa, mUnit, field_idx); if (resolved_field != NULL && resolved_field->IsStatic()) { + SirtRef dex_cache(soa.Self(), resolved_field->GetDeclaringClass()->GetDexCache()); mirror::Class* referrer_class = - ComputeCompilingMethodsClass(soa, resolved_field->GetDeclaringClass()->GetDexCache(), - mUnit); + ComputeCompilingMethodsClass(soa, dex_cache, mUnit); if (referrer_class != NULL) { mirror::Class* fields_class = resolved_field->GetDeclaringClass(); if (fields_class == referrer_class) { @@ -1085,7 +1086,7 @@ void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType* type, InvokeType *direct_code = 0; *direct_method = 0; bool use_dex_cache = false; - bool compiling_boot = Runtime::Current()->GetHeap()->GetContinuousSpaces().size() == 1; + const bool compiling_boot = Runtime::Current()->GetHeap()->IsCompilingBoot(); if (compiler_backend_ == kPortable) { if (sharp_type != kStatic && sharp_type != kDirect) { return; @@ -1198,9 +1199,9 @@ bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const ui } // Don't try to fast-path if we don't understand the caller's class or this appears to be an // Incompatible Class Change Error. + SirtRef dex_cache(soa.Self(), resolved_method->GetDeclaringClass()->GetDexCache()); mirror::Class* referrer_class = - ComputeCompilingMethodsClass(soa, resolved_method->GetDeclaringClass()->GetDexCache(), - mUnit); + ComputeCompilingMethodsClass(soa, dex_cache, mUnit); bool icce = resolved_method->CheckIncompatibleClassChange(*invoke_type); if (referrer_class != NULL && !icce) { mirror::Class* methods_class = resolved_method->GetDeclaringClass(); @@ -1254,10 +1255,8 @@ bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const ui const MethodReference* devirt_map_target = verifier::MethodVerifier::GetDevirtMap(caller_method, dex_pc); if (devirt_map_target != NULL) { - mirror::DexCache* target_dex_cache = - mUnit->GetClassLinker()->FindDexCache(*devirt_map_target->dex_file); - mirror::ClassLoader* class_loader = - soa.Decode(mUnit->GetClassLoader()); + SirtRef target_dex_cache(soa.Self(), mUnit->GetClassLinker()->FindDexCache(*devirt_map_target->dex_file)); + SirtRef class_loader(soa.Self(), soa.Decode(mUnit->GetClassLoader())); mirror::ArtMethod* called_method = mUnit->GetClassLinker()->ResolveMethod(*devirt_map_target->dex_file, devirt_map_target->dex_method_index, @@ -1509,13 +1508,11 @@ static void ResolveClassFieldsAndMethods(const ParallelCompilationManager* manag const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index); if (!SkipClass(class_linker, jclass_loader, dex_file, class_def)) { ScopedObjectAccess soa(self); - mirror::ClassLoader* class_loader = soa.Decode(jclass_loader); - mirror::DexCache* dex_cache = class_linker->FindDexCache(dex_file); - + SirtRef class_loader(soa.Self(), soa.Decode(jclass_loader)); + SirtRef dex_cache(soa.Self(), class_linker->FindDexCache(dex_file)); // Resolve the class. mirror::Class* klass = class_linker->ResolveType(dex_file, class_def.class_idx_, dex_cache, class_loader); - bool resolve_fields_and_methods; if (klass == NULL) { // Class couldn't be resolved, for example, super-class is in a different dex file. Don't @@ -1598,8 +1595,8 @@ static void ResolveType(const ParallelCompilationManager* manager, size_t type_i ScopedObjectAccess soa(Thread::Current()); ClassLinker* class_linker = manager->GetClassLinker(); const DexFile& dex_file = *manager->GetDexFile(); - mirror::DexCache* dex_cache = class_linker->FindDexCache(dex_file); - mirror::ClassLoader* class_loader = soa.Decode(manager->GetClassLoader()); + SirtRef dex_cache(soa.Self(), class_linker->FindDexCache(dex_file)); + SirtRef class_loader(soa.Self(), soa.Decode(manager->GetClassLoader())); mirror::Class* klass = class_linker->ResolveType(dex_file, type_idx, dex_cache, class_loader); if (klass == NULL) { @@ -1652,8 +1649,9 @@ static void VerifyClass(const ParallelCompilationManager* manager, size_t class_ const char* descriptor = dex_file.GetClassDescriptor(class_def); ClassLinker* class_linker = manager->GetClassLinker(); jobject jclass_loader = manager->GetClassLoader(); - mirror::Class* klass = class_linker->FindClass(descriptor, - soa.Decode(jclass_loader)); + SirtRef class_loader( + soa.Self(), soa.Decode(jclass_loader)); + mirror::Class* klass = class_linker->FindClass(descriptor, class_loader); if (klass == NULL) { CHECK(soa.Self()->IsExceptionPending()); soa.Self()->ClearException(); @@ -1663,11 +1661,10 @@ static void VerifyClass(const ParallelCompilationManager* manager, size_t class_ * This is to ensure the class is structurally sound for compilation. An unsound class * will be rejected by the verifier and later skipped during compilation in the compiler. */ - mirror::DexCache* dex_cache = class_linker->FindDexCache(dex_file); + SirtRef dex_cache(soa.Self(), class_linker->FindDexCache(dex_file)); std::string error_msg; - if (verifier::MethodVerifier::VerifyClass(&dex_file, dex_cache, - soa.Decode(jclass_loader), - &class_def, true, &error_msg) == + if (verifier::MethodVerifier::VerifyClass(&dex_file, dex_cache, class_loader, &class_def, true, + &error_msg) == verifier::MethodVerifier::kHardFailure) { LOG(ERROR) << "Verification failed on class " << PrettyDescriptor(descriptor) << " because: " << error_msg; @@ -2124,7 +2121,8 @@ static void InitializeClass(const ParallelCompilationManager* manager, size_t cl const char* descriptor = dex_file.StringDataByIdx(class_type_id.descriptor_idx_); ScopedObjectAccess soa(Thread::Current()); - mirror::ClassLoader* class_loader = soa.Decode(jclass_loader); + SirtRef class_loader(soa.Self(), + soa.Decode(jclass_loader)); mirror::Class* klass = manager->GetClassLinker()->FindClass(descriptor, class_loader); if (klass != NULL && !SkipClass(jclass_loader, dex_file, klass)) { @@ -2253,7 +2251,8 @@ void CompilerDriver::CompileClass(const ParallelCompilationManager* manager, siz DexToDexCompilationLevel dex_to_dex_compilation_level = kDontDexToDexCompile; { ScopedObjectAccess soa(Thread::Current()); - mirror::ClassLoader* class_loader = soa.Decode(jclass_loader); + SirtRef class_loader(soa.Self(), + soa.Decode(jclass_loader)); dex_to_dex_compilation_level = GetDexToDexCompilationlevel(class_loader, dex_file, class_def); } ClassDataItemIterator it(dex_file, class_data); -- cgit v1.2.3-59-g8ed1b