diff options
Diffstat (limited to 'compiler/driver/compiler_driver.cc')
-rw-r--r-- | compiler/driver/compiler_driver.cc | 253 |
1 files changed, 142 insertions, 111 deletions
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 120f232..38ffa10 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -582,10 +582,11 @@ void CompilerDriver::PreCompile(jobject class_loader, const std::vector<const De bool CompilerDriver::IsImageClass(const char* descriptor) const { DCHECK(descriptor != NULL); - if (image_classes_.get() == NULL) { + if (!IsImage()) { return true; + } else { + return image_classes_->find(descriptor) != image_classes_->end(); } - return image_classes_->find(descriptor) != image_classes_->end(); } static void ResolveExceptionsForMethod(MethodHelper* mh, @@ -655,7 +656,7 @@ static bool RecordImageClassesVisitor(mirror::Class* klass, void* arg) // Make a list of descriptors for classes to include in the image void CompilerDriver::LoadImageClasses(base::TimingLogger& timings) LOCKS_EXCLUDED(Locks::mutator_lock_) { - if (image_classes_.get() == NULL) { + if (!IsImage()) { return; } @@ -669,7 +670,7 @@ void CompilerDriver::LoadImageClasses(base::TimingLogger& timings) SirtRef<mirror::Class> klass(self, class_linker->FindSystemClass(descriptor.c_str())); if (klass.get() == NULL) { image_classes_->erase(it++); - LOG(WARNING) << "Failed to find class " << descriptor; + VLOG(compiler) << "Failed to find class " << descriptor; Thread::Current()->ClearException(); } else { ++it; @@ -742,21 +743,19 @@ void CompilerDriver::FindClinitImageClassesCallback(mirror::Object* object, void } void CompilerDriver::UpdateImageClasses(base::TimingLogger& timings) { - if (image_classes_.get() == NULL) { - return; - } - - timings.NewSplit("UpdateImageClasses"); + if (IsImage()) { + timings.NewSplit("UpdateImageClasses"); - // Update image_classes_ with classes for objects created by <clinit> methods. - Thread* self = Thread::Current(); - const char* old_cause = self->StartAssertNoThreadSuspension("ImageWriter"); - gc::Heap* heap = Runtime::Current()->GetHeap(); - // TODO: Image spaces only? - WriterMutexLock mu(self, *Locks::heap_bitmap_lock_); - heap->FlushAllocStack(); - heap->GetLiveBitmap()->Walk(FindClinitImageClassesCallback, this); - self->EndAssertNoThreadSuspension(old_cause); + // Update image_classes_ with classes for objects created by <clinit> methods. + Thread* self = Thread::Current(); + const char* old_cause = self->StartAssertNoThreadSuspension("ImageWriter"); + gc::Heap* heap = Runtime::Current()->GetHeap(); + // TODO: Image spaces only? + WriterMutexLock mu(self, *Locks::heap_bitmap_lock_); + heap->FlushAllocStack(); + heap->GetLiveBitmap()->Walk(FindClinitImageClassesCallback, this); + self->EndAssertNoThreadSuspension(old_cause); + } } void CompilerDriver::RecordClassStatus(ClassReference ref, CompiledClass* compiled_class) { @@ -1436,12 +1435,18 @@ static bool SkipClass(mirror::ClassLoader* class_loader, return true; } -static void ResolveClassFieldsAndMethods(const ParallelCompilationManager* manager, size_t class_def_index) +static void ResolveClassFieldsAndMethods(const ParallelCompilationManager* manager, + size_t class_def_index) LOCKS_EXCLUDED(Locks::mutator_lock_) { ScopedObjectAccess soa(Thread::Current()); mirror::ClassLoader* class_loader = soa.Decode<mirror::ClassLoader*>(manager->GetClassLoader()); const DexFile& dex_file = *manager->GetDexFile(); + // If an instance field is final then we need to have a barrier on the return, static final + // fields are assigned within the lock held for class initialization. Conservatively assume + // constructor barriers are always required. + bool requires_constructor_barrier = true; + // Method and Field are the worst. We can't resolve without either // context from the code use (to disambiguate virtual vs direct // method and instance vs static field) or from class @@ -1450,72 +1455,89 @@ static void ResolveClassFieldsAndMethods(const ParallelCompilationManager* manag // definitions, since many of them many never be referenced by // generated code. const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index); - if (SkipClass(class_loader, dex_file, class_def)) { - return; - } - - // Note the class_data pointer advances through the headers, - // static fields, instance fields, direct methods, and virtual - // methods. - const byte* class_data = dex_file.GetClassData(class_def); - if (class_data == NULL) { - // empty class such as a marker interface - return; - } - Thread* self = Thread::Current(); - ClassLinker* class_linker = manager->GetClassLinker(); - mirror::DexCache* dex_cache = class_linker->FindDexCache(dex_file); - ClassDataItemIterator it(dex_file, class_data); - while (it.HasNextStaticField()) { - mirror::ArtField* field = class_linker->ResolveField(dex_file, it.GetMemberIndex(), dex_cache, - class_loader, true); - if (field == NULL) { - CHECK(self->IsExceptionPending()); - self->ClearException(); - } - it.Next(); - } - // If an instance field is final then we need to have a barrier on the return, static final - // fields are assigned within the lock held for class initialization. - bool requires_constructor_barrier = false; - while (it.HasNextInstanceField()) { - if ((it.GetMemberAccessFlags() & kAccFinal) != 0) { - requires_constructor_barrier = true; - } - - mirror::ArtField* field = class_linker->ResolveField(dex_file, it.GetMemberIndex(), dex_cache, - class_loader, false); - if (field == NULL) { - CHECK(self->IsExceptionPending()); - self->ClearException(); + if (!SkipClass(class_loader, dex_file, class_def)) { + // Note the class_data pointer advances through the headers, + // static fields, instance fields, direct methods, and virtual + // methods. + const byte* class_data = dex_file.GetClassData(class_def); + if (class_data == NULL) { + // Empty class such as a marker interface. + requires_constructor_barrier = false; + } else { + ClassLinker* class_linker = manager->GetClassLinker(); + mirror::DexCache* dex_cache = 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 + // attempt to resolve methods and fields when there is no declaring class. + CHECK(soa.Self()->IsExceptionPending()); + Thread::Current()->ClearException(); + resolve_fields_and_methods = false; + } else { + resolve_fields_and_methods = manager->GetCompiler()->IsImage(); + } + ClassDataItemIterator it(dex_file, class_data); + while (it.HasNextStaticField()) { + if (resolve_fields_and_methods) { + mirror::ArtField* field = class_linker->ResolveField(dex_file, it.GetMemberIndex(), + dex_cache, class_loader, true); + if (field == NULL) { + CHECK(soa.Self()->IsExceptionPending()); + soa.Self()->ClearException(); + } + } + it.Next(); + } + // We require a constructor barrier if there are final instance fields. + requires_constructor_barrier = false; + while (it.HasNextInstanceField()) { + if ((it.GetMemberAccessFlags() & kAccFinal) != 0) { + requires_constructor_barrier = true; + } + if (resolve_fields_and_methods) { + mirror::ArtField* field = class_linker->ResolveField(dex_file, it.GetMemberIndex(), + dex_cache, class_loader, false); + if (field == NULL) { + CHECK(soa.Self()->IsExceptionPending()); + soa.Self()->ClearException(); + } + } + it.Next(); + } + if (resolve_fields_and_methods) { + while (it.HasNextDirectMethod()) { + mirror::ArtMethod* method = class_linker->ResolveMethod(dex_file, it.GetMemberIndex(), + dex_cache, class_loader, NULL, + it.GetMethodInvokeType(class_def)); + if (method == NULL) { + CHECK(soa.Self()->IsExceptionPending()); + soa.Self()->ClearException(); + } + it.Next(); + } + while (it.HasNextVirtualMethod()) { + mirror::ArtMethod* method = class_linker->ResolveMethod(dex_file, it.GetMemberIndex(), + dex_cache, class_loader, NULL, + it.GetMethodInvokeType(class_def)); + if (method == NULL) { + CHECK(soa.Self()->IsExceptionPending()); + soa.Self()->ClearException(); + } + it.Next(); + } + DCHECK(!it.HasNext()); + } } - it.Next(); } if (requires_constructor_barrier) { manager->GetCompiler()->AddRequiresConstructorBarrier(soa.Self(), manager->GetDexFile(), class_def_index); } - while (it.HasNextDirectMethod()) { - mirror::ArtMethod* method = class_linker->ResolveMethod(dex_file, it.GetMemberIndex(), - dex_cache, class_loader, NULL, - it.GetMethodInvokeType(class_def)); - if (method == NULL) { - CHECK(self->IsExceptionPending()); - self->ClearException(); - } - it.Next(); - } - while (it.HasNextVirtualMethod()) { - mirror::ArtMethod* method = class_linker->ResolveMethod(dex_file, it.GetMemberIndex(), - dex_cache, class_loader, NULL, - it.GetMethodInvokeType(class_def)); - if (method == NULL) { - CHECK(self->IsExceptionPending()); - self->ClearException(); - } - it.Next(); - } - DCHECK(!it.HasNext()); } static void ResolveType(const ParallelCompilationManager* manager, size_t type_idx) @@ -1541,10 +1563,16 @@ void CompilerDriver::ResolveDexFile(jobject class_loader, const DexFile& dex_fil // TODO: we could resolve strings here, although the string table is largely filled with class // and method names. - timings.NewSplit(strdup(("Resolve " + dex_file.GetLocation() + " Types").c_str())); ParallelCompilationManager context(class_linker, class_loader, this, &dex_file, thread_pool); - context.ForAll(0, dex_file.NumTypeIds(), ResolveType, thread_count_); + if (IsImage()) { + // For images we resolve all types, such as array, whereas for applications just those with + // classdefs are resolved by ResolveClassFieldsAndMethods. + // TODO: strdup memory leak. + timings.NewSplit(strdup(("Resolve " + dex_file.GetLocation() + " Types").c_str())); + context.ForAll(0, dex_file.NumTypeIds(), ResolveType, thread_count_); + } + // TODO: strdup memory leak. timings.NewSplit(strdup(("Resolve " + dex_file.GetLocation() + " MethodsAndFields").c_str())); context.ForAll(0, dex_file.NumClassDefs(), ResolveClassFieldsAndMethods, thread_count_); } @@ -1567,7 +1595,8 @@ static void VerifyClass(const ParallelCompilationManager* manager, size_t class_ mirror::Class* klass = manager->GetClassLinker()->FindClass(descriptor, soa.Decode<mirror::ClassLoader*>(manager->GetClassLoader())); - if (klass == NULL) { CHECK(soa.Self()->IsExceptionPending()); + if (klass == NULL) { + CHECK(soa.Self()->IsExceptionPending()); soa.Self()->ClearException(); /* @@ -1587,25 +1616,25 @@ static void VerifyClass(const ParallelCompilationManager* manager, size_t class_ << PrettyDescriptor(manager->GetDexFile()->GetClassDescriptor(class_def)) << " because: " << error_msg; } - return; - } - CHECK(klass->IsResolved()) << PrettyClass(klass); - manager->GetClassLinker()->VerifyClass(klass); - - if (klass->IsErroneous()) { - // ClassLinker::VerifyClass throws, which isn't useful in the compiler. - CHECK(soa.Self()->IsExceptionPending()); - soa.Self()->ClearException(); - } + } else { + CHECK(klass->IsResolved()) << PrettyClass(klass); + manager->GetClassLinker()->VerifyClass(klass); + if (klass->IsErroneous()) { + // ClassLinker::VerifyClass throws, which isn't useful in the compiler. + CHECK(soa.Self()->IsExceptionPending()); + soa.Self()->ClearException(); + } - CHECK(klass->IsCompileTimeVerified() || klass->IsErroneous()) - << PrettyDescriptor(klass) << ": state=" << klass->GetStatus(); + CHECK(klass->IsCompileTimeVerified() || klass->IsErroneous()) + << PrettyDescriptor(klass) << ": state=" << klass->GetStatus(); + } soa.Self()->AssertNoPendingException(); } void CompilerDriver::VerifyDexFile(jobject class_loader, const DexFile& dex_file, ThreadPool& thread_pool, base::TimingLogger& timings) { + // TODO: strdup memory leak. timings.NewSplit(strdup(("Verify " + dex_file.GetLocation()).c_str())); ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); ParallelCompilationManager context(class_linker, class_loader, this, &dex_file, thread_pool); @@ -2032,23 +2061,20 @@ static void InitializeClass(const ParallelCompilationManager* manager, size_t cl mirror::ClassLoader* class_loader = soa.Decode<mirror::ClassLoader*>(manager->GetClassLoader()); const char* descriptor = manager->GetDexFile()->GetClassDescriptor(class_def); mirror::Class* klass = manager->GetClassLinker()->FindClass(descriptor, class_loader); - bool compiling_boot = Runtime::Current()->GetHeap()->GetContinuousSpaces().size() == 1; - bool can_init_static_fields = compiling_boot && - manager->GetCompiler()->IsImageClass(descriptor); if (klass != NULL) { - // We don't want class initialization occurring on multiple threads due to deadlock problems. - // For example, a parent class is initialized (holding its lock) that refers to a sub-class - // in its static/class initializer causing it to try to acquire the sub-class' lock. While - // on a second thread the sub-class is initialized (holding its lock) after first initializing - // its parents, whose locks are acquired. This leads to a parent-to-child and a child-to-parent - // lock ordering and consequent potential deadlock. - // We need to use an ObjectLock due to potential suspension in the interpreting code. Rather - // than use a special Object for the purpose we use the Class of java.lang.Class. - ObjectLock lock1(soa.Self(), klass->GetClass()); - // The lock required to initialize the class. - ObjectLock lock2(soa.Self(), klass); // Only try to initialize classes that were successfully verified. if (klass->IsVerified()) { + // We don't want class initialization occurring on multiple threads due to deadlock problems. + // For example, a parent class is initialized (holding its lock) that refers to a sub-class + // in its static/class initializer causing it to try to acquire the sub-class' lock. While + // on a second thread the sub-class is initialized (holding its lock) after first initializing + // its parents, whose locks are acquired. This leads to a parent-to-child and a child-to-parent + // lock ordering and consequent potential deadlock. + // We need to use an ObjectLock due to potential suspension in the interpreting code. Rather + // than use a special Object for the purpose we use the Class of java.lang.Class. + ObjectLock lock(soa.Self(), klass->GetClass()); + bool can_init_static_fields = manager->GetCompiler()->IsImage() && + manager->GetCompiler()->IsImageClass(descriptor); manager->GetClassLinker()->EnsureInitialized(klass, false, can_init_static_fields); if (soa.Self()->IsExceptionPending()) { soa.Self()->GetException(NULL)->Dump(); @@ -2069,6 +2095,7 @@ static void InitializeClass(const ParallelCompilationManager* manager, size_t cl VLOG(compiler) << "Initializing: " << descriptor; if (StringPiece(descriptor) == "Ljava/lang/Void;") { // Hand initialize j.l.Void to avoid Dex file operations in un-started runtime. + ObjectLock lock(soa.Self(), klass); mirror::ObjectArray<mirror::ArtField>* fields = klass->GetSFields(); CHECK_EQ(fields->GetLength(), 1); fields->Get(0)->SetObj(klass, manager->GetClassLinker()->FindPrimitiveClass('V')); @@ -2102,11 +2129,15 @@ static void InitializeClass(const ParallelCompilationManager* manager, size_t cl void CompilerDriver::InitializeClasses(jobject jni_class_loader, const DexFile& dex_file, ThreadPool& thread_pool, base::TimingLogger& timings) { + // TODO: strdup memory leak. timings.NewSplit(strdup(("InitializeNoClinit " + dex_file.GetLocation()).c_str())); #ifndef NDEBUG - for (size_t i = 0; i < arraysize(class_initializer_black_list); ++i) { - const char* descriptor = class_initializer_black_list[i]; - CHECK(IsValidDescriptor(descriptor)) << descriptor; + // Sanity check blacklist descriptors. + if (IsImage()) { + for (size_t i = 0; i < arraysize(class_initializer_black_list); ++i) { + const char* descriptor = class_initializer_black_list[i]; + CHECK(IsValidDescriptor(descriptor)) << descriptor; + } } #endif ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); |