diff options
Diffstat (limited to 'compiler/driver/compiler_driver.cc')
-rw-r--r-- | compiler/driver/compiler_driver.cc | 175 |
1 files changed, 114 insertions, 61 deletions
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 01e0ac4abe..b99301566e 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -350,10 +350,10 @@ CompilerDriver::CompilerDriver(const CompilerOptions* compiler_options, dump_stats_(dump_stats), dump_passes_(dump_passes), timings_logger_(timer), - compiler_library_(NULL), - compiler_context_(NULL), - compiler_enable_auto_elf_loading_(NULL), - compiler_get_method_code_addr_(NULL), + compiler_library_(nullptr), + compiler_context_(nullptr), + compiler_enable_auto_elf_loading_(nullptr), + compiler_get_method_code_addr_(nullptr), support_boot_image_fixup_(instruction_set != kMips), dedupe_code_("dedupe code"), dedupe_src_mapping_table_("dedupe source mapping table"), @@ -365,7 +365,7 @@ CompilerDriver::CompilerDriver(const CompilerOptions* compiler_options, DCHECK(verification_results_ != nullptr); DCHECK(method_inliner_map_ != nullptr); - CHECK_PTHREAD_CALL(pthread_key_create, (&tls_key_, NULL), "compiler tls key"); + CHECK_PTHREAD_CALL(pthread_key_create, (&tls_key_, nullptr), "compiler tls key"); dex_to_dex_compiler_ = reinterpret_cast<DexToDexCompilerFn>(ArtCompileDEX); @@ -445,7 +445,7 @@ CompilerDriver::~CompilerDriver() { CompilerTls* CompilerDriver::GetTls() { // Lazily create thread-local storage CompilerTls* res = static_cast<CompilerTls*>(pthread_getspecific(tls_key_)); - if (res == NULL) { + if (res == nullptr) { res = compiler_->CreateNewCompilerTls(); CHECK_PTHREAD_CALL(pthread_setspecific, (tls_key_, res), "compiler tls"); } @@ -520,20 +520,18 @@ static DexToDexCompilationLevel GetDexToDexCompilationlevel( const char* descriptor = dex_file.GetClassDescriptor(class_def); ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); mirror::Class* klass = class_linker->FindClass(self, descriptor, class_loader); - if (klass == NULL) { + if (klass == nullptr) { CHECK(self->IsExceptionPending()); self->ClearException(); return kDontDexToDexCompile; } - // The verifier can only run on "quick" instructions at runtime (see usage of - // FindAccessedFieldAtDexPc and FindInvokedMethodAtDexPc in ThrowNullPointerExceptionFromDexPC - // 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.Get() == nullptr; - if (compiling_image_classes) { - return kRequired; - } else if (klass->IsVerified()) { + // DexToDex at the kOptimize level may introduce quickened opcodes, which replace symbolic + // references with actual offsets. We cannot re-verify such instructions. + // + // We store the verification information in the class status in the oat file, which the linker + // can validate (checksums) and use to skip load-time verification. It is thus safe to + // optimize when a class has been fully verified before. + if (klass->IsVerified()) { // Class is verified so we can enable DEX-to-DEX compilation for performance. return kOptimize; } else if (klass->IsCompileTimeVerified()) { @@ -606,13 +604,14 @@ void CompilerDriver::PreCompile(jobject class_loader, const std::vector<const De ThreadPool* thread_pool, TimingLogger* timings) { LoadImageClasses(timings); + Resolve(class_loader, dex_files, thread_pool, timings); + if (!compiler_options_->IsVerificationEnabled()) { - VLOG(compiler) << "Verify none mode specified, skipping pre-compilation"; + VLOG(compiler) << "Verify none mode specified, skipping verification."; + SetVerified(class_loader, dex_files, thread_pool, timings); return; } - Resolve(class_loader, dex_files, thread_pool, timings); - Verify(class_loader, dex_files, thread_pool, timings); InitializeClasses(class_loader, dex_files, thread_pool, timings); @@ -632,7 +631,7 @@ static void ResolveExceptionsForMethod(MethodHelper* mh, std::set<std::pair<uint16_t, const DexFile*>>& exceptions_to_resolve) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { const DexFile::CodeItem* code_item = mh->GetMethod()->GetCodeItem(); - if (code_item == NULL) { + if (code_item == nullptr) { return; // native or abstract method } if (code_item->tries_size_ == 0) { @@ -710,7 +709,7 @@ void CompilerDriver::LoadImageClasses(TimingLogger* timings) StackHandleScope<1> hs(self); Handle<mirror::Class> klass( hs.NewHandle(class_linker->FindSystemClass(self, descriptor.c_str()))); - if (klass.Get() == NULL) { + if (klass.Get() == nullptr) { VLOG(compiler) << "Failed to find class " << descriptor; image_classes_->erase(it++); self->ClearException(); @@ -738,7 +737,7 @@ void CompilerDriver::LoadImageClasses(TimingLogger* timings) Handle<mirror::Class> klass(hs.NewHandle( class_linker->ResolveType(*dex_file, exception_type_idx, dex_cache, NullHandle<mirror::ClassLoader>()))); - if (klass.Get() == NULL) { + if (klass.Get() == nullptr) { const DexFile::TypeId& type_id = dex_file->GetTypeId(exception_type_idx); const char* descriptor = dex_file->GetTypeDescriptor(type_id); LOG(FATAL) << "Failed to resolve class " << descriptor; @@ -785,8 +784,8 @@ static void MaybeAddToImageClasses(Handle<mirror::Class> c, std::set<std::string } void CompilerDriver::FindClinitImageClassesCallback(mirror::Object* object, void* arg) { - DCHECK(object != NULL); - DCHECK(arg != NULL); + DCHECK(object != nullptr); + DCHECK(arg != nullptr); CompilerDriver* compiler_driver = reinterpret_cast<CompilerDriver*>(arg); StackHandleScope<1> hs(Thread::Current()); MaybeAddToImageClasses(hs.NewHandle(object->GetClass()), compiler_driver->image_classes_.get()); @@ -854,29 +853,29 @@ bool CompilerDriver::CanAccessTypeWithoutChecks(uint32_t referrer_idx, const Dex uint32_t type_idx, bool* type_known_final, bool* type_known_abstract, bool* equals_referrers_class) { - if (type_known_final != NULL) { + if (type_known_final != nullptr) { *type_known_final = false; } - if (type_known_abstract != NULL) { + if (type_known_abstract != nullptr) { *type_known_abstract = false; } - if (equals_referrers_class != NULL) { + if (equals_referrers_class != nullptr) { *equals_referrers_class = false; } ScopedObjectAccess soa(Thread::Current()); mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(dex_file); // Get type from dex cache assuming it was populated by the verifier mirror::Class* resolved_class = dex_cache->GetResolvedType(type_idx); - if (resolved_class == NULL) { + if (resolved_class == nullptr) { stats_->TypeNeedsAccessCheck(); return false; // Unknown class needs access checks. } const DexFile::MethodId& method_id = dex_file.GetMethodId(referrer_idx); - if (equals_referrers_class != NULL) { + if (equals_referrers_class != nullptr) { *equals_referrers_class = (method_id.class_idx_ == type_idx); } mirror::Class* referrer_class = dex_cache->GetResolvedType(method_id.class_idx_); - if (referrer_class == NULL) { + if (referrer_class == nullptr) { stats_->TypeNeedsAccessCheck(); return false; // Incomplete referrer knowledge needs access check. } @@ -885,10 +884,10 @@ bool CompilerDriver::CanAccessTypeWithoutChecks(uint32_t referrer_idx, const Dex bool result = referrer_class->CanAccess(resolved_class); if (result) { stats_->TypeDoesntNeedAccessCheck(); - if (type_known_final != NULL) { + if (type_known_final != nullptr) { *type_known_final = resolved_class->IsFinal() && !resolved_class->IsArrayClass(); } - if (type_known_abstract != NULL) { + if (type_known_abstract != nullptr) { *type_known_abstract = resolved_class->IsAbstract() && !resolved_class->IsArrayClass(); } } else { @@ -904,13 +903,13 @@ bool CompilerDriver::CanAccessInstantiableTypeWithoutChecks(uint32_t referrer_id mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(dex_file); // Get type from dex cache assuming it was populated by the verifier. mirror::Class* resolved_class = dex_cache->GetResolvedType(type_idx); - if (resolved_class == NULL) { + if (resolved_class == nullptr) { stats_->TypeNeedsAccessCheck(); return false; // Unknown class needs access checks. } const DexFile::MethodId& method_id = dex_file.GetMethodId(referrer_idx); mirror::Class* referrer_class = dex_cache->GetResolvedType(method_id.class_idx_); - if (referrer_class == NULL) { + if (referrer_class == nullptr) { stats_->TypeNeedsAccessCheck(); return false; // Incomplete referrer knowledge needs access check. } @@ -1310,6 +1309,10 @@ const VerifiedMethod* CompilerDriver::GetVerifiedMethod(const DexFile* dex_file, } bool CompilerDriver::IsSafeCast(const DexCompilationUnit* mUnit, uint32_t dex_pc) { + if (!compiler_options_->IsVerificationEnabled()) { + // If we didn't verify, every cast has to be treated as non-safe. + return false; + } DCHECK(mUnit->GetVerifiedMethod() != nullptr); bool result = mUnit->GetVerifiedMethod()->IsSafeCast(dex_pc); if (result) { @@ -1410,7 +1413,7 @@ class ParallelCompilationManager { thread_pool_(thread_pool) {} ClassLinker* GetClassLinker() const { - CHECK(class_linker_ != NULL); + CHECK(class_linker_ != nullptr); return class_linker_; } @@ -1419,12 +1422,12 @@ class ParallelCompilationManager { } CompilerDriver* GetCompiler() const { - CHECK(compiler_ != NULL); + CHECK(compiler_ != nullptr); return compiler_; } const DexFile* GetDexFile() const { - CHECK(dex_file_ != NULL); + CHECK(dex_file_ != nullptr); return dex_file_; } @@ -1499,10 +1502,10 @@ class ParallelCompilationManager { // that avoids the expensive FindInClassPath search. static bool SkipClass(jobject class_loader, const DexFile& dex_file, mirror::Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - DCHECK(klass != NULL); + DCHECK(klass != nullptr); const DexFile& original_dex_file = *klass->GetDexCache()->GetDexFile(); if (&dex_file != &original_dex_file) { - if (class_loader == NULL) { + if (class_loader == nullptr) { LOG(WARNING) << "Skipping class " << PrettyDescriptor(klass) << " from " << dex_file.GetLocation() << " previously found in " << original_dex_file.GetLocation(); @@ -1587,7 +1590,7 @@ static void ResolveClassFieldsAndMethods(const ParallelCompilationManager* manag // static fields, instance fields, direct methods, and virtual // methods. const byte* class_data = dex_file.GetClassData(class_def); - if (class_data == NULL) { + if (class_data == nullptr) { // Empty class such as a marker interface. requires_constructor_barrier = false; } else { @@ -1596,7 +1599,7 @@ static void ResolveClassFieldsAndMethods(const ParallelCompilationManager* manag if (resolve_fields_and_methods) { mirror::ArtField* field = class_linker->ResolveField(dex_file, it.GetMemberIndex(), dex_cache, class_loader, true); - if (field == NULL) { + if (field == nullptr) { CheckAndClearResolveException(soa.Self()); } } @@ -1611,7 +1614,7 @@ static void ResolveClassFieldsAndMethods(const ParallelCompilationManager* manag if (resolve_fields_and_methods) { mirror::ArtField* field = class_linker->ResolveField(dex_file, it.GetMemberIndex(), dex_cache, class_loader, false); - if (field == NULL) { + if (field == nullptr) { CheckAndClearResolveException(soa.Self()); } } @@ -1623,7 +1626,7 @@ static void ResolveClassFieldsAndMethods(const ParallelCompilationManager* manag dex_cache, class_loader, NullHandle<mirror::ArtMethod>(), it.GetMethodInvokeType(class_def)); - if (method == NULL) { + if (method == nullptr) { CheckAndClearResolveException(soa.Self()); } it.Next(); @@ -1633,7 +1636,7 @@ static void ResolveClassFieldsAndMethods(const ParallelCompilationManager* manag dex_cache, class_loader, NullHandle<mirror::ArtMethod>(), it.GetMethodInvokeType(class_def)); - if (method == NULL) { + if (method == nullptr) { CheckAndClearResolveException(soa.Self()); } it.Next(); @@ -1658,9 +1661,9 @@ static void ResolveType(const ParallelCompilationManager* manager, size_t type_i hs.NewHandle(soa.Decode<mirror::ClassLoader*>(manager->GetClassLoader()))); mirror::Class* klass = class_linker->ResolveType(dex_file, type_idx, dex_cache, class_loader); - if (klass == NULL) { + if (klass == nullptr) { CHECK(soa.Self()->IsExceptionPending()); - mirror::Throwable* exception = soa.Self()->GetException(NULL); + mirror::Throwable* exception = soa.Self()->GetException(nullptr); VLOG(compiler) << "Exception during type resolution: " << exception->Dump(); if (exception->GetClass()->DescriptorEquals("Ljava/lang/OutOfMemoryError;")) { // There's little point continuing compilation if the heap is exhausted. @@ -1691,11 +1694,20 @@ void CompilerDriver::ResolveDexFile(jobject class_loader, const DexFile& dex_fil context.ForAll(0, dex_file.NumClassDefs(), ResolveClassFieldsAndMethods, thread_count_); } +void CompilerDriver::SetVerified(jobject class_loader, const std::vector<const DexFile*>& dex_files, + ThreadPool* thread_pool, TimingLogger* timings) { + for (size_t i = 0; i != dex_files.size(); ++i) { + const DexFile* dex_file = dex_files[i]; + CHECK(dex_file != nullptr); + SetVerifiedDexFile(class_loader, *dex_file, dex_files, thread_pool, timings); + } +} + void CompilerDriver::Verify(jobject class_loader, const std::vector<const DexFile*>& dex_files, ThreadPool* thread_pool, TimingLogger* timings) { for (size_t i = 0; i != dex_files.size(); ++i) { const DexFile* dex_file = dex_files[i]; - CHECK(dex_file != NULL); + CHECK(dex_file != nullptr); VerifyDexFile(class_loader, *dex_file, dex_files, thread_pool, timings); } } @@ -1757,6 +1769,47 @@ void CompilerDriver::VerifyDexFile(jobject class_loader, const DexFile& dex_file context.ForAll(0, dex_file.NumClassDefs(), VerifyClass, thread_count_); } +static void SetVerifiedClass(const ParallelCompilationManager* manager, size_t class_def_index) + LOCKS_EXCLUDED(Locks::mutator_lock_) { + ATRACE_CALL(); + ScopedObjectAccess soa(Thread::Current()); + const DexFile& dex_file = *manager->GetDexFile(); + const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index); + const char* descriptor = dex_file.GetClassDescriptor(class_def); + ClassLinker* class_linker = manager->GetClassLinker(); + jobject jclass_loader = manager->GetClassLoader(); + StackHandleScope<3> hs(soa.Self()); + Handle<mirror::ClassLoader> class_loader( + hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader))); + Handle<mirror::Class> klass( + hs.NewHandle(class_linker->FindClass(soa.Self(), descriptor, class_loader))); + // Class might have failed resolution. Then don't set it to verified. + if (klass.Get() != nullptr) { + // Only do this if the class is resolved. If even resolution fails, quickening will go very, + // very wrong. + if (klass->IsResolved()) { + if (klass->GetStatus() < mirror::Class::kStatusVerified) { + ObjectLock<mirror::Class> lock(soa.Self(), klass); + klass->SetStatus(mirror::Class::kStatusVerified, soa.Self()); + } + // Record the final class status if necessary. + ClassReference ref(manager->GetDexFile(), class_def_index); + manager->GetCompiler()->RecordClassStatus(ref, klass->GetStatus()); + } + } + soa.Self()->AssertNoPendingException(); +} + +void CompilerDriver::SetVerifiedDexFile(jobject class_loader, const DexFile& dex_file, + const std::vector<const DexFile*>& dex_files, + ThreadPool* thread_pool, TimingLogger* timings) { + TimingLogger::ScopedTiming t("Verify Dex File", timings); + ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); + ParallelCompilationManager context(class_linker, class_loader, this, &dex_file, dex_files, + thread_pool); + context.ForAll(0, dex_file.NumClassDefs(), SetVerifiedClass, thread_count_); +} + static void InitializeClass(const ParallelCompilationManager* manager, size_t class_def_index) LOCKS_EXCLUDED(Locks::mutator_lock_) { ATRACE_CALL(); @@ -1865,7 +1918,7 @@ void CompilerDriver::InitializeClasses(jobject class_loader, ThreadPool* thread_pool, TimingLogger* timings) { for (size_t i = 0; i != dex_files.size(); ++i) { const DexFile* dex_file = dex_files[i]; - CHECK(dex_file != NULL); + CHECK(dex_file != nullptr); InitializeClasses(class_loader, *dex_file, dex_files, thread_pool, timings); } if (IsImage()) { @@ -1878,7 +1931,7 @@ void CompilerDriver::Compile(jobject class_loader, const std::vector<const DexFi ThreadPool* thread_pool, TimingLogger* timings) { for (size_t i = 0; i != dex_files.size(); ++i) { const DexFile* dex_file = dex_files[i]; - CHECK(dex_file != NULL); + CHECK(dex_file != nullptr); CompileDexFile(class_loader, *dex_file, dex_files, thread_pool, timings); } } @@ -1911,7 +1964,7 @@ void CompilerDriver::CompileClass(const ParallelCompilationManager* manager, siz return; } const byte* class_data = dex_file.GetClassData(class_def); - if (class_data == NULL) { + if (class_data == nullptr) { // empty class, probably a marker interface return; } @@ -1984,7 +2037,7 @@ void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t uint32_t method_idx, jobject class_loader, const DexFile& dex_file, DexToDexCompilationLevel dex_to_dex_compilation_level) { - CompiledMethod* compiled_method = NULL; + CompiledMethod* compiled_method = nullptr; uint64_t start_ns = kTimeCompileMethod ? NanoTime() : 0; if ((access_flags & kAccNative) != 0) { @@ -1994,14 +2047,14 @@ void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t // Leaving this empty will trigger the generic JNI version } else { compiled_method = compiler_->JniCompile(access_flags, method_idx, dex_file); - CHECK(compiled_method != NULL); + CHECK(compiled_method != nullptr); } } else if ((access_flags & kAccAbstract) != 0) { } else { MethodReference method_ref(&dex_file, method_idx); bool compile = verification_results_->IsCandidateForCompilation(method_ref, access_flags); if (compile) { - // NOTE: if compiler declines to compile this method, it will return NULL. + // NOTE: if compiler declines to compile this method, it will return nullptr. compiled_method = compiler_->Compile(code_item, access_flags, invoke_type, class_def_idx, method_idx, class_loader, dex_file); } @@ -2022,20 +2075,20 @@ void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t } Thread* self = Thread::Current(); - if (compiled_method != NULL) { + if (compiled_method != nullptr) { MethodReference ref(&dex_file, method_idx); - DCHECK(GetCompiledMethod(ref) == NULL) << PrettyMethod(method_idx, dex_file); + DCHECK(GetCompiledMethod(ref) == nullptr) << PrettyMethod(method_idx, dex_file); { MutexLock mu(self, compiled_methods_lock_); compiled_methods_.Put(ref, compiled_method); } - DCHECK(GetCompiledMethod(ref) != NULL) << PrettyMethod(method_idx, dex_file); + DCHECK(GetCompiledMethod(ref) != nullptr) << PrettyMethod(method_idx, dex_file); } if (self->IsExceptionPending()) { ScopedObjectAccess soa(self); LOG(FATAL) << "Unexpected exception compiling: " << PrettyMethod(method_idx, dex_file) << "\n" - << self->GetException(NULL)->Dump(); + << self->GetException(nullptr)->Dump(); } } @@ -2043,9 +2096,9 @@ CompiledClass* CompilerDriver::GetCompiledClass(ClassReference ref) const { MutexLock mu(Thread::Current(), compiled_classes_lock_); ClassTable::const_iterator it = compiled_classes_.find(ref); if (it == compiled_classes_.end()) { - return NULL; + return nullptr; } - CHECK(it->second != NULL); + CHECK(it->second != nullptr); return it->second; } @@ -2079,9 +2132,9 @@ CompiledMethod* CompilerDriver::GetCompiledMethod(MethodReference ref) const { MutexLock mu(Thread::Current(), compiled_methods_lock_); MethodTable::const_iterator it = compiled_methods_.find(ref); if (it == compiled_methods_.end()) { - return NULL; + return nullptr; } - CHECK(it->second != NULL); + CHECK(it->second != nullptr); return it->second; } |