diff options
-rw-r--r-- | compiler/common_compiler_test.cc | 51 | ||||
-rw-r--r-- | compiler/driver/compiler_driver.cc | 108 | ||||
-rw-r--r-- | compiler/driver/compiler_driver.h | 35 | ||||
-rw-r--r-- | compiler/driver/compiler_options.cc | 14 | ||||
-rw-r--r-- | compiler/driver/compiler_options.h | 17 | ||||
-rw-r--r-- | compiler/optimizing/instruction_builder.cc | 2 | ||||
-rw-r--r-- | compiler/optimizing/sharpening.cc | 19 | ||||
-rw-r--r-- | compiler/optimizing/sharpening.h | 1 | ||||
-rw-r--r-- | dex2oat/dex2oat.cc | 42 | ||||
-rw-r--r-- | dex2oat/linker/image_test.h | 4 | ||||
-rw-r--r-- | dex2oat/linker/image_writer.cc | 35 | ||||
-rw-r--r-- | dex2oat/linker/oat_writer.cc | 36 | ||||
-rw-r--r-- | dex2oat/linker/oat_writer.h | 19 |
13 files changed, 207 insertions, 176 deletions
diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc index c37d4523c4..7491173ed6 100644 --- a/compiler/common_compiler_test.cc +++ b/compiler/common_compiler_test.cc @@ -31,6 +31,7 @@ #include "dex/verification_results.h" #include "driver/compiler_driver.h" #include "driver/compiler_options.h" +#include "jni/java_vm_ext.h" #include "interpreter/interpreter.h" #include "mirror/class-inl.h" #include "mirror/class_loader.h" @@ -134,8 +135,7 @@ void CommonCompilerTest::MakeExecutable(ObjPtr<mirror::ClassLoader> class_loader } } -// Get the set of image classes given to the compiler-driver in SetUp. Note: the compiler -// driver assumes ownership of the set, so the test should properly release the set. +// Get the set of image classes given to the compiler options in SetUp. std::unique_ptr<HashSet<std::string>> CommonCompilerTest::GetImageClasses() { // Empty set: by default no classes are retained in the image. return std::make_unique<HashSet<std::string>>(); @@ -173,12 +173,13 @@ void CommonCompilerTest::CreateCompilerDriver(Compiler::Kind kind, size_t number_of_threads) { compiler_options_->boot_image_ = true; compiler_options_->SetCompilerFilter(GetCompilerFilter()); + compiler_options_->image_classes_.swap(*GetImageClasses()); compiler_driver_.reset(new CompilerDriver(compiler_options_.get(), verification_results_.get(), kind, isa, instruction_set_features_.get(), - GetImageClasses(), + &compiler_options_->image_classes_, number_of_threads, /* swap_fd */ -1, GetProfileCompilationInfo())); @@ -235,9 +236,49 @@ void CommonCompilerTest::CompileClass(mirror::ClassLoader* class_loader, const c void CommonCompilerTest::CompileMethod(ArtMethod* method) { CHECK(method != nullptr); - TimingLogger timings("CommonTest::CompileMethod", false, false); + TimingLogger timings("CommonCompilerTest::CompileMethod", false, false); TimingLogger::ScopedTiming t(__FUNCTION__, &timings); - compiler_driver_->CompileOne(Thread::Current(), method, &timings); + { + Thread* self = Thread::Current(); + jobject class_loader = self->GetJniEnv()->GetVm()->AddGlobalRef(self, method->GetClassLoader()); + + DCHECK(!Runtime::Current()->IsStarted()); + const DexFile* dex_file = method->GetDexFile(); + uint16_t class_def_idx = method->GetClassDefIndex(); + uint32_t method_idx = method->GetDexMethodIndex(); + uint32_t access_flags = method->GetAccessFlags(); + InvokeType invoke_type = method->GetInvokeType(); + StackHandleScope<2> hs(self); + Handle<mirror::DexCache> dex_cache(hs.NewHandle(method->GetDexCache())); + Handle<mirror::ClassLoader> h_class_loader = hs.NewHandle( + self->DecodeJObject(class_loader)->AsClassLoader()); + const DexFile::CodeItem* code_item = dex_file->GetCodeItem(method->GetCodeItemOffset()); + + std::vector<const DexFile*> dex_files; + dex_files.push_back(dex_file); + + // Go to native so that we don't block GC during compilation. + ScopedThreadSuspension sts(self, kNative); + + compiler_driver_->InitializeThreadPools(); + + compiler_driver_->PreCompile(class_loader, dex_files, &timings); + + compiler_driver_->CompileOne(self, + class_loader, + *dex_file, + class_def_idx, + method_idx, + access_flags, + invoke_type, + code_item, + dex_cache, + h_class_loader); + + compiler_driver_->FreeThreadPools(); + + self->GetJniEnv()->DeleteGlobalRef(class_loader); + } TimingLogger::ScopedTiming t2("MakeExecutable", &timings); MakeExecutable(method); } diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index bd2b1070fc..ed4fb6f30f 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -67,7 +67,6 @@ #include "mirror/object-refvisitor-inl.h" #include "mirror/object_array-inl.h" #include "mirror/throwable.h" -#include "nativehelper/ScopedLocalRef.h" #include "object_lock.h" #include "profile/profile_compilation_info.h" #include "runtime.h" @@ -264,7 +263,7 @@ CompilerDriver::CompilerDriver( Compiler::Kind compiler_kind, InstructionSet instruction_set, const InstructionSetFeatures* instruction_set_features, - std::unique_ptr<HashSet<std::string>>&& image_classes, + HashSet<std::string>* image_classes, size_t thread_count, int swap_fd, const ProfileCompilationInfo* profile_compilation_info) @@ -293,7 +292,7 @@ CompilerDriver::CompilerDriver( compiler_->Init(); if (GetCompilerOptions().IsBootImage()) { - CHECK(image_classes_.get() != nullptr) << "Expected image classes for boot image"; + CHECK(image_classes_ != nullptr) << "Expected image classes for boot image"; } compiled_method_storage_.SetDedupeEnabled(compiler_options_->DeduplicateCode()); @@ -351,12 +350,6 @@ void CompilerDriver::CompileAll(jobject class_loader, InitializeThreadPools(); - VLOG(compiler) << "Before precompile " << GetMemoryUsageString(false); - // Precompile: - // 1) Load image classes - // 2) Resolve all classes - // 3) Attempt to verify all classes - // 4) Attempt to initialize image classes, and trivially initialized classes PreCompile(class_loader, dex_files, timings); if (GetCompilerOptions().IsBootImage()) { // We don't need to setup the intrinsics for non boot image compilation, as @@ -673,46 +666,24 @@ static void CompileMethodQuick( quick_fn); } -void CompilerDriver::CompileOne(Thread* self, ArtMethod* method, TimingLogger* timings) { - DCHECK(!Runtime::Current()->IsStarted()); - jobject jclass_loader; - const DexFile* dex_file; - uint16_t class_def_idx; - uint32_t method_idx = method->GetDexMethodIndex(); - uint32_t access_flags = method->GetAccessFlags(); - InvokeType invoke_type = method->GetInvokeType(); - StackHandleScope<2> hs(self); - Handle<mirror::DexCache> dex_cache(hs.NewHandle(method->GetDexCache())); - Handle<mirror::ClassLoader> class_loader( - hs.NewHandle(method->GetDeclaringClass()->GetClassLoader())); - { - ScopedObjectAccessUnchecked soa(self); - ScopedLocalRef<jobject> local_class_loader( - soa.Env(), soa.AddLocalReference<jobject>(class_loader.Get())); - jclass_loader = soa.Env()->NewGlobalRef(local_class_loader.get()); - // Find the dex_file - dex_file = method->GetDexFile(); - class_def_idx = method->GetClassDefIndex(); - } - const DexFile::CodeItem* code_item = dex_file->GetCodeItem(method->GetCodeItemOffset()); - - // Go to native so that we don't block GC during compilation. - ScopedThreadSuspension sts(self, kNative); - - std::vector<const DexFile*> dex_files; - dex_files.push_back(dex_file); - - InitializeThreadPools(); - - PreCompile(jclass_loader, dex_files, timings); - +// Compile a single Method. (For testing only.) +void CompilerDriver::CompileOne(Thread* self, + jobject class_loader, + const DexFile& dex_file, + uint16_t class_def_idx, + uint32_t method_idx, + uint32_t access_flags, + InvokeType invoke_type, + const DexFile::CodeItem* code_item, + Handle<mirror::DexCache> dex_cache, + Handle<mirror::ClassLoader> h_class_loader) { // Can we run DEX-to-DEX compiler on this class ? optimizer::DexToDexCompiler::CompilationLevel dex_to_dex_compilation_level = GetDexToDexCompilationLevel(self, *this, - jclass_loader, - *dex_file, - dex_file->GetClassDef(class_def_idx)); + class_loader, + dex_file, + dex_file.GetClassDef(class_def_idx)); CompileMethodQuick(self, this, @@ -721,8 +692,8 @@ void CompilerDriver::CompileOne(Thread* self, ArtMethod* method, TimingLogger* t invoke_type, class_def_idx, method_idx, - class_loader, - *dex_file, + h_class_loader, + dex_file, dex_to_dex_compilation_level, true, dex_cache); @@ -737,17 +708,13 @@ void CompilerDriver::CompileOne(Thread* self, ArtMethod* method, TimingLogger* t invoke_type, class_def_idx, method_idx, - class_loader, - *dex_file, + h_class_loader, + dex_file, dex_to_dex_compilation_level, true, dex_cache); dex_to_dex_compiler_.ClearState(); } - - FreeThreadPools(); - - self->GetJniEnv()->DeleteGlobalRef(jclass_loader); } void CompilerDriver::Resolve(jobject class_loader, @@ -838,7 +805,7 @@ static void InitializeTypeCheckBitstrings(CompilerDriver* driver, // primitive) classes. We may reconsider this in future if it's deemed to be beneficial. // And we cannot use it for classes outside the boot image as we do not know the runtime // value of their bitstring when compiling (it may not even get assigned at runtime). - if (descriptor[0] == 'L' && driver->IsImageClass(descriptor)) { + if (descriptor[0] == 'L' && driver->GetCompilerOptions().IsImageClass(descriptor)) { ObjPtr<mirror::Class> klass = class_linker->LookupResolvedType(type_index, dex_cache.Get(), @@ -918,6 +885,16 @@ void CompilerDriver::PreCompile(jobject class_loader, const std::vector<const DexFile*>& dex_files, TimingLogger* timings) { CheckThreadPools(); + VLOG(compiler) << "Before precompile " << GetMemoryUsageString(false); + + // Precompile: + // 1) Load image classes. + // 2) Resolve all classes. + // 3) For deterministic boot image, resolve strings for const-string instructions. + // 4) Attempt to verify all classes. + // 5) Attempt to initialize image classes, and trivially initialized classes. + // 6) Update the set of image classes. + // 7) For deterministic boot image, initialize bitstrings for type checking. LoadImageClasses(timings); VLOG(compiler) << "LoadImageClasses: " << GetMemoryUsageString(false); @@ -988,16 +965,6 @@ void CompilerDriver::PreCompile(jobject class_loader, } } -bool CompilerDriver::IsImageClass(const char* descriptor) const { - if (image_classes_ != nullptr) { - // If we have a set of image classes, use those. - return image_classes_->find(StringPiece(descriptor)) != image_classes_->end(); - } - // No set of image classes, assume we include all the classes. - // NOTE: Currently only reachable from InitImageMethodVisitor for the app image case. - return !GetCompilerOptions().IsBootImage(); -} - bool CompilerDriver::IsClassToCompile(const char* descriptor) const { if (classes_to_compile_ == nullptr) { return true; @@ -1116,7 +1083,7 @@ void CompilerDriver::LoadImageClasses(TimingLogger* timings) { Thread* self = Thread::Current(); ScopedObjectAccess soa(self); ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - CHECK(image_classes_.get() != nullptr); + CHECK(image_classes_ != nullptr); for (auto it = image_classes_->begin(), end = image_classes_->end(); it != end;) { const std::string& descriptor(*it); StackHandleScope<1> hs(self); @@ -1174,7 +1141,7 @@ void CompilerDriver::LoadImageClasses(TimingLogger* timings) { // We walk the roots looking for classes so that we'll pick up the // above classes plus any classes them depend on such super // classes, interfaces, and the required ClassLinker roots. - RecordImageClassesVisitor visitor(image_classes_.get()); + RecordImageClassesVisitor visitor(image_classes_); class_linker->VisitClasses(&visitor); CHECK(!image_classes_->empty()); @@ -1358,7 +1325,7 @@ void CompilerDriver::UpdateImageClasses(TimingLogger* timings) { VariableSizedHandleScope hs(Thread::Current()); std::string error_msg; std::unique_ptr<ClinitImageUpdate> update(ClinitImageUpdate::Create(hs, - image_classes_.get(), + image_classes_, Thread::Current(), runtime->GetClassLinker())); @@ -1382,7 +1349,7 @@ bool CompilerDriver::CanAssumeClassIsLoaded(mirror::Class* klass) { } std::string temp; const char* descriptor = klass->GetDescriptor(&temp); - return IsImageClass(descriptor); + return GetCompilerOptions().IsImageClass(descriptor); } bool CompilerDriver::CanAccessTypeWithoutChecks(ObjPtr<mirror::Class> referrer_class, @@ -2292,7 +2259,7 @@ class InitializeClassVisitor : public CompilationVisitor { (is_app_image || is_boot_image) && is_superclass_initialized && !too_many_encoded_fields && - manager_->GetCompiler()->IsImageClass(descriptor)) { + manager_->GetCompiler()->GetCompilerOptions().IsImageClass(descriptor)) { bool can_init_static_fields = false; if (is_boot_image) { // We need to initialize static fields, we only do this for image classes that aren't @@ -2982,8 +2949,7 @@ bool CompilerDriver::MayInlineInternal(const DexFile* inlined_from, const DexFile* inlined_into) const { // We're not allowed to inline across dex files if we're the no-inline-from dex file. if (inlined_from != inlined_into && - compiler_options_->GetNoInlineFromDexFile() != nullptr && - ContainsElement(*compiler_options_->GetNoInlineFromDexFile(), inlined_from)) { + ContainsElement(compiler_options_->GetNoInlineFromDexFile(), inlined_from)) { return false; } diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index ff70d96272..36e93a84d1 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -99,7 +99,7 @@ class CompilerDriver { Compiler::Kind compiler_kind, InstructionSet instruction_set, const InstructionSetFeatures* instruction_set_features, - std::unique_ptr<HashSet<std::string>>&& image_classes, + HashSet<std::string>* image_classes, size_t thread_count, int swap_fd, const ProfileCompilationInfo* profile_compilation_info); @@ -122,9 +122,18 @@ class CompilerDriver { TimingLogger* timings) REQUIRES(!Locks::mutator_lock_); - // Compile a single Method. - void CompileOne(Thread* self, ArtMethod* method, TimingLogger* timings) - REQUIRES_SHARED(Locks::mutator_lock_); + // Compile a single Method. (For testing only.) + void CompileOne(Thread* self, + jobject class_loader, + const DexFile& dex_file, + uint16_t class_def_idx, + uint32_t method_idx, + uint32_t access_flags, + InvokeType invoke_type, + const DexFile::CodeItem* code_item, + Handle<mirror::DexCache> dex_cache, + Handle<mirror::ClassLoader> h_class_loader) + REQUIRES(!Locks::mutator_lock_); VerificationResults* GetVerificationResults() const; @@ -144,10 +153,6 @@ class CompilerDriver { return compiler_.get(); } - const HashSet<std::string>* GetImageClasses() const { - return image_classes_.get(); - } - // Generate the trampolines that are invoked by unresolved direct methods. std::unique_ptr<const std::vector<uint8_t>> CreateJniDlsymLookup() const; std::unique_ptr<const std::vector<uint8_t>> CreateQuickGenericJniTrampoline() const; @@ -308,9 +313,6 @@ class CompilerDriver { return compiled_method_storage_.DedupeEnabled(); } - // Checks if class specified by type_idx is one of the image_classes_ - bool IsImageClass(const char* descriptor) const; - // Checks whether the provided class should be compiled, i.e., is in classes_to_compile_. bool IsClassToCompile(const char* descriptor) const; @@ -491,9 +493,11 @@ class CompilerDriver { // in the .oat_patches ELF section if requested in the compiler options. Atomic<size_t> non_relative_linker_patch_count_; - // If image_ is true, specifies the classes that will be included in the image. - // Note if image_classes_ is null, all classes are included in the image. - std::unique_ptr<HashSet<std::string>> image_classes_; + // Image classes to be updated by PreCompile(). + // TODO: Remove this member which is a non-const pointer to the CompilerOptions' data. + // Pass this explicitly to the PreCompile() which should be called directly from + // Dex2Oat rather than implicitly by CompileAll(). + HashSet<std::string>* image_classes_; // Specifies the classes that will be compiled. Note that if classes_to_compile_ is null, // all classes are eligible for compilation (duplication filters etc. will still apply). @@ -505,8 +509,8 @@ class CompilerDriver { bool had_hard_verifier_failure_; // A thread pool that can (potentially) run tasks in parallel. - std::unique_ptr<ThreadPool> parallel_thread_pool_; size_t parallel_thread_count_; + std::unique_ptr<ThreadPool> parallel_thread_pool_; // A thread pool that guarantees running single-threaded on the main thread. std::unique_ptr<ThreadPool> single_thread_pool_; @@ -534,6 +538,7 @@ class CompilerDriver { // Compiler for dex to dex (quickening). optimizer::DexToDexCompiler dex_to_dex_compiler_; + friend class CommonCompilerTest; friend class CompileClassVisitor; friend class DexToDexDecompilerTest; friend class verifier::VerifierDepsTest; diff --git a/compiler/driver/compiler_options.cc b/compiler/driver/compiler_options.cc index 933be4f004..3d37b680ee 100644 --- a/compiler/driver/compiler_options.cc +++ b/compiler/driver/compiler_options.cc @@ -37,7 +37,8 @@ CompilerOptions::CompilerOptions() tiny_method_threshold_(kDefaultTinyMethodThreshold), num_dex_methods_threshold_(kDefaultNumDexMethodsThreshold), inline_max_code_units_(kUnsetInlineMaxCodeUnits), - no_inline_from_(nullptr), + no_inline_from_(), + image_classes_(), boot_image_(false), core_image_(false), app_image_(false), @@ -67,8 +68,8 @@ CompilerOptions::CompilerOptions() } CompilerOptions::~CompilerOptions() { - // The destructor looks empty but it destroys a PassManagerOptions object. We keep it here - // because we don't want to include the PassManagerOptions definition from the header file. + // Everything done by member destructors. + // The definitions of classes forward-declared in the header have now been #included. } namespace { @@ -129,4 +130,11 @@ bool CompilerOptions::ParseCompilerOptions(const std::vector<std::string>& optio #pragma GCC diagnostic pop +bool CompilerOptions::IsImageClass(const char* descriptor) const { + // Historical note: We used to hold the set indirectly and there was a distinction between an + // empty set and a null, null meaning to include all classes. However, the distiction has been + // removed; if we don't have a profile, we treat it as an empty set of classes. b/77340429 + return image_classes_.find(StringPiece(descriptor)) != image_classes_.end(); +} + } // namespace art diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h index cee989b315..0709fafaeb 100644 --- a/compiler/driver/compiler_options.h +++ b/compiler/driver/compiler_options.h @@ -22,6 +22,7 @@ #include <vector> #include "base/globals.h" +#include "base/hash_set.h" #include "base/macros.h" #include "base/utils.h" #include "compiler_filter.h" @@ -230,10 +231,16 @@ class CompilerOptions FINAL { return abort_on_soft_verifier_failure_; } - const std::vector<const DexFile*>* GetNoInlineFromDexFile() const { + const std::vector<const DexFile*>& GetNoInlineFromDexFile() const { return no_inline_from_; } + const HashSet<std::string>& GetImageClasses() const { + return image_classes_; + } + + bool IsImageClass(const char* descriptor) const; + bool ParseCompilerOptions(const std::vector<std::string>& options, bool ignore_unrecognized, std::string* error_msg); @@ -301,10 +308,14 @@ class CompilerOptions FINAL { size_t num_dex_methods_threshold_; size_t inline_max_code_units_; - // Dex files from which we should not inline code. + // Dex files from which we should not inline code. Does not own the dex files. // This is usually a very short list (i.e. a single dex file), so we // prefer vector<> over a lookup-oriented container, such as set<>. - const std::vector<const DexFile*>* no_inline_from_; + std::vector<const DexFile*> no_inline_from_; + + // Image classes, specifies the classes that will be included in the image if creating an image. + // Must not be empty for real boot image, only for tests pretending to compile boot image. + HashSet<std::string> image_classes_; bool boot_image_; bool core_image_; diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc index 8a347dfea7..7cda6e9da3 100644 --- a/compiler/optimizing/instruction_builder.cc +++ b/compiler/optimizing/instruction_builder.cc @@ -1879,7 +1879,7 @@ void HInstructionBuilder::BuildTypeCheck(const Instruction& instruction, Handle<mirror::Class> klass = ResolveClass(soa, type_index); bool needs_access_check = LoadClassNeedsAccessCheck(klass); TypeCheckKind check_kind = HSharpening::ComputeTypeCheckKind( - klass.Get(), code_generator_, compiler_driver_, needs_access_check); + klass.Get(), code_generator_, needs_access_check); HInstruction* class_or_null = nullptr; HIntConstant* bitstring_path_to_root = nullptr; diff --git a/compiler/optimizing/sharpening.cc b/compiler/optimizing/sharpening.cc index 6541043046..ebac3f6854 100644 --- a/compiler/optimizing/sharpening.cc +++ b/compiler/optimizing/sharpening.cc @@ -71,7 +71,8 @@ static bool AOTCanEmbedMethod(ArtMethod* method, const CompilerOptions& options) } static bool BootImageAOTCanEmbedMethod(ArtMethod* method, CompilerDriver* compiler_driver) { - DCHECK(compiler_driver->GetCompilerOptions().IsBootImage()); + const CompilerOptions& compiler_options = compiler_driver->GetCompilerOptions(); + DCHECK(compiler_options.IsBootImage()); if (!compiler_driver->GetSupportBootImageFixup()) { return false; } @@ -79,7 +80,7 @@ static bool BootImageAOTCanEmbedMethod(ArtMethod* method, CompilerDriver* compil ObjPtr<mirror::Class> klass = method->GetDeclaringClass(); DCHECK(klass != nullptr); const DexFile& dex_file = klass->GetDexFile(); - return compiler_driver->IsImageClass(dex_file.StringByTypeIdx(klass->GetDexTypeIndex())); + return compiler_options.IsImageClass(dex_file.StringByTypeIdx(klass->GetDexTypeIndex())); } void HSharpening::SharpenInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke, @@ -177,14 +178,15 @@ HLoadClass::LoadKind HSharpening::ComputeLoadClassKind( bool is_in_boot_image = false; HLoadClass::LoadKind desired_load_kind = HLoadClass::LoadKind::kInvalid; Runtime* runtime = Runtime::Current(); - if (codegen->GetCompilerOptions().IsBootImage()) { + const CompilerOptions& compiler_options = codegen->GetCompilerOptions(); + if (compiler_options.IsBootImage()) { // Compiling boot image. Check if the class is a boot image class. DCHECK(!runtime->UseJitCompilation()); if (!compiler_driver->GetSupportBootImageFixup()) { // compiler_driver_test. Do not sharpen. desired_load_kind = HLoadClass::LoadKind::kRuntimeCall; } else if ((klass != nullptr) && - compiler_driver->IsImageClass(dex_file.StringByTypeIdx(type_index))) { + compiler_options.IsImageClass(dex_file.StringByTypeIdx(type_index))) { is_in_boot_image = true; desired_load_kind = HLoadClass::LoadKind::kBootImageLinkTimePcRelative; } else { @@ -241,9 +243,7 @@ HLoadClass::LoadKind HSharpening::ComputeLoadClassKind( return load_kind; } -static inline bool CanUseTypeCheckBitstring(ObjPtr<mirror::Class> klass, - CodeGenerator* codegen, - CompilerDriver* compiler_driver) +static inline bool CanUseTypeCheckBitstring(ObjPtr<mirror::Class> klass, CodeGenerator* codegen) REQUIRES_SHARED(Locks::mutator_lock_) { DCHECK(!klass->IsProxyClass()); DCHECK(!klass->IsArrayClass()); @@ -252,7 +252,7 @@ static inline bool CanUseTypeCheckBitstring(ObjPtr<mirror::Class> klass, // If we're JITting, try to assign a type check bitstring (fall through). } else if (codegen->GetCompilerOptions().IsBootImage()) { const char* descriptor = klass->GetDexFile().StringByTypeIdx(klass->GetDexTypeIndex()); - if (!compiler_driver->IsImageClass(descriptor)) { + if (!codegen->GetCompilerOptions().IsImageClass(descriptor)) { return false; } // If the target is a boot image class, try to assign a type check bitstring (fall through). @@ -281,7 +281,6 @@ static inline bool CanUseTypeCheckBitstring(ObjPtr<mirror::Class> klass, TypeCheckKind HSharpening::ComputeTypeCheckKind(ObjPtr<mirror::Class> klass, CodeGenerator* codegen, - CompilerDriver* compiler_driver, bool needs_access_check) { if (klass == nullptr) { return TypeCheckKind::kUnresolvedCheck; @@ -299,7 +298,7 @@ TypeCheckKind HSharpening::ComputeTypeCheckKind(ObjPtr<mirror::Class> klass, return TypeCheckKind::kExactCheck; } else if (kBitstringSubtypeCheckEnabled && !needs_access_check && - CanUseTypeCheckBitstring(klass, codegen, compiler_driver)) { + CanUseTypeCheckBitstring(klass, codegen)) { // TODO: We should not need the `!needs_access_check` check but getting rid of that // requires rewriting some optimizations in instruction simplifier. return TypeCheckKind::kBitstringCheck; diff --git a/compiler/optimizing/sharpening.h b/compiler/optimizing/sharpening.h index 9ccbcaf220..e77732814b 100644 --- a/compiler/optimizing/sharpening.h +++ b/compiler/optimizing/sharpening.h @@ -59,7 +59,6 @@ class HSharpening : public HOptimization { // Used by the builder. static TypeCheckKind ComputeTypeCheckKind(ObjPtr<mirror::Class> klass, CodeGenerator* codegen, - CompilerDriver* compiler_driver, bool needs_access_check) REQUIRES_SHARED(Locks::mutator_lock_); diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index 6cd947c8cf..779128f924 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -642,7 +642,6 @@ class Dex2Oat FINAL { driver_(nullptr), opened_dex_files_maps_(), opened_dex_files_(), - no_inline_from_dex_files_(), avoid_storing_invocation_(false), swap_fd_(kInvalidFd), app_image_fd_(kInvalidFd), @@ -1489,22 +1488,21 @@ class Dex2Oat FINAL { if (!IsImage()) { return; } - // If we don't have a profile, treat it as an empty set of classes. b/77340429 - if (image_classes_ == nullptr) { - // May be non-null when --image-classes is passed in, in that case avoid clearing the list. - image_classes_.reset(new HashSet<std::string>()); - } if (profile_compilation_info_ != nullptr) { + // TODO: The following comment looks outdated or misplaced. // Filter out class path classes since we don't want to include these in the image. - image_classes_.reset( - new HashSet<std::string>(profile_compilation_info_->GetClassDescriptors(dex_files_))); - VLOG(compiler) << "Loaded " << image_classes_->size() + HashSet<std::string> image_classes = + profile_compilation_info_->GetClassDescriptors(dex_files_); + VLOG(compiler) << "Loaded " << image_classes.size() << " image class descriptors from profile"; if (VLOG_IS_ON(compiler)) { - for (const std::string& s : *image_classes_) { + for (const std::string& s : image_classes) { LOG(INFO) << "Image class " << s; } } + // Note: If we have a profile, classes previously loaded for the --image-classes + // option are overwritten here. + compiler_options_->image_classes_.swap(image_classes); } } @@ -1810,6 +1808,7 @@ class Dex2Oat FINAL { class_path_files = class_loader_context_->FlattenOpenedDexFiles(); } + std::vector<const DexFile*> no_inline_from_dex_files; std::vector<const std::vector<const DexFile*>*> dex_file_vectors = { &class_linker->GetBootClassPath(), &class_path_files, @@ -1832,14 +1831,14 @@ class Dex2Oat FINAL { if (android::base::StartsWith(dex_location, filter.c_str())) { VLOG(compiler) << "Disabling inlining from " << dex_file->GetLocation(); - no_inline_from_dex_files_.push_back(dex_file); + no_inline_from_dex_files.push_back(dex_file); break; } } } } - if (!no_inline_from_dex_files_.empty()) { - compiler_options_->no_inline_from_ = &no_inline_from_dex_files_; + if (!no_inline_from_dex_files.empty()) { + compiler_options_->no_inline_from_.swap(no_inline_from_dex_files); } } @@ -1848,7 +1847,7 @@ class Dex2Oat FINAL { compiler_kind_, instruction_set_, instruction_set_features_.get(), - std::move(image_classes_), + &compiler_options_->image_classes_, thread_count_, swap_fd_, profile_compilation_info_.get())); @@ -2381,14 +2380,14 @@ class Dex2Oat FINAL { bool PrepareImageClasses() { // If --image-classes was specified, calculate the full list of classes to include in the image. + DCHECK(compiler_options_->image_classes_.empty()); if (image_classes_filename_ != nullptr) { - image_classes_ = + std::unique_ptr<HashSet<std::string>> image_classes = ReadClasses(image_classes_zip_filename_, image_classes_filename_, "image"); - if (image_classes_ == nullptr) { + if (image_classes == nullptr) { return false; } - } else if (IsBootImage()) { - image_classes_.reset(new HashSet<std::string>); + compiler_options_->image_classes_.swap(*image_classes); } return true; } @@ -2704,8 +2703,7 @@ class Dex2Oat FINAL { LOG(ERROR) << "Failed to open input file " << input_filename; return nullptr; } - std::unique_ptr<T> result( - ReadCommentedInputStream<T>(*input_file, process)); + std::unique_ptr<T> result = ReadCommentedInputStream<T>(*input_file, process); input_file->close(); return result; } @@ -2851,7 +2849,6 @@ class Dex2Oat FINAL { ImageHeader::StorageMode image_storage_mode_; const char* passes_to_run_filename_; const char* dirty_image_objects_filename_; - std::unique_ptr<HashSet<std::string>> image_classes_; std::unique_ptr<HashSet<std::string>> dirty_image_objects_; std::unique_ptr<std::vector<std::string>> passes_to_run_; bool multi_image_; @@ -2872,9 +2869,6 @@ class Dex2Oat FINAL { std::vector<std::unique_ptr<MemMap>> opened_dex_files_maps_; std::vector<std::unique_ptr<const DexFile>> opened_dex_files_; - // Note that this might contain pointers owned by class_loader_context_. - std::vector<const DexFile*> no_inline_from_dex_files_; - bool avoid_storing_invocation_; std::string swap_file_name_; int swap_fd_; diff --git a/dex2oat/linker/image_test.h b/dex2oat/linker/image_test.h index 12ecd3a4fc..2acdf256e1 100644 --- a/dex2oat/linker/image_test.h +++ b/dex2oat/linker/image_test.h @@ -426,9 +426,6 @@ inline void ImageTest::TestWriteRead(ImageHeader::StorageMode storage_mode) { image_file_sizes.push_back(file->GetLength()); } - ASSERT_TRUE(compiler_driver_->GetImageClasses() != nullptr); - HashSet<std::string> image_classes(*compiler_driver_->GetImageClasses()); - // Need to delete the compiler since it has worker threads which are attached to runtime. compiler_driver_.reset(); @@ -469,6 +466,7 @@ inline void ImageTest::TestWriteRead(ImageHeader::StorageMode storage_mode) { // We loaded the runtime with an explicit image, so it must exist. ASSERT_EQ(heap->GetBootImageSpaces().size(), image_file_sizes.size()); + const HashSet<std::string>& image_classes = compiler_options_->GetImageClasses(); for (size_t i = 0; i < helper.dex_file_locations.size(); ++i) { std::unique_ptr<const DexFile> dex( LoadExpectSingleDexFile(helper.dex_file_locations[i].c_str())); diff --git a/dex2oat/linker/image_writer.cc b/dex2oat/linker/image_writer.cc index a61ad8f7c2..b98dc683ed 100644 --- a/dex2oat/linker/image_writer.cc +++ b/dex2oat/linker/image_writer.cc @@ -38,6 +38,7 @@ #include "dex/dex_file-inl.h" #include "dex/dex_file_types.h" #include "driver/compiler_driver.h" +#include "driver/compiler_options.h" #include "elf_file.h" #include "elf_utils.h" #include "gc/accounting/card_table-inl.h" @@ -851,7 +852,8 @@ bool ImageWriter::PruneAppImageClassInternal( std::string temp; // Prune if not an image class, this handles any broken sets of image classes such as having a // class in the set but not it's superclass. - result = result || !compiler_driver_.IsImageClass(klass->GetDescriptor(&temp)); + result = result || + !compiler_driver_.GetCompilerOptions().IsImageClass(klass->GetDescriptor(&temp)); bool my_early_exit = false; // Only for ourselves, ignore caller. // Remove classes that failed to verify since we don't want to have java.lang.VerifyError in the // app image. @@ -941,7 +943,7 @@ bool ImageWriter::KeepClass(ObjPtr<mirror::Class> klass) { return true; } std::string temp; - if (!compiler_driver_.IsImageClass(klass->GetDescriptor(&temp))) { + if (!compiler_driver_.GetCompilerOptions().IsImageClass(klass->GetDescriptor(&temp))) { return false; } if (compile_app_image_) { @@ -1212,27 +1214,22 @@ void ImageWriter::PruneNonImageClasses() { } void ImageWriter::CheckNonImageClassesRemoved() { - if (compiler_driver_.GetImageClasses() != nullptr) { - auto visitor = [&](Object* obj) REQUIRES_SHARED(Locks::mutator_lock_) { - if (obj->IsClass() && !IsInBootImage(obj)) { - Class* klass = obj->AsClass(); - if (!KeepClass(klass)) { - DumpImageClasses(); - std::string temp; - CHECK(KeepClass(klass)) - << Runtime::Current()->GetHeap()->GetVerification()->FirstPathFromRootSet(klass); - } + auto visitor = [&](Object* obj) REQUIRES_SHARED(Locks::mutator_lock_) { + if (obj->IsClass() && !IsInBootImage(obj)) { + Class* klass = obj->AsClass(); + if (!KeepClass(klass)) { + DumpImageClasses(); + CHECK(KeepClass(klass)) + << Runtime::Current()->GetHeap()->GetVerification()->FirstPathFromRootSet(klass); } - }; - gc::Heap* heap = Runtime::Current()->GetHeap(); - heap->VisitObjects(visitor); - } + } + }; + gc::Heap* heap = Runtime::Current()->GetHeap(); + heap->VisitObjects(visitor); } void ImageWriter::DumpImageClasses() { - auto image_classes = compiler_driver_.GetImageClasses(); - CHECK(image_classes != nullptr); - for (const std::string& image_class : *image_classes) { + for (const std::string& image_class : compiler_driver_.GetCompilerOptions().GetImageClasses()) { LOG(INFO) << " " << image_class; } } diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc index 99516684e8..0ed9579aed 100644 --- a/dex2oat/linker/oat_writer.cc +++ b/dex2oat/linker/oat_writer.cc @@ -366,6 +366,7 @@ OatWriter::OatWriter(bool compiling_boot_image, zipped_dex_files_(), zipped_dex_file_locations_(), compiler_driver_(nullptr), + compiler_options_(nullptr), image_writer_(nullptr), compiling_boot_image_(compiling_boot_image), extract_dex_files_into_vdex_(true), @@ -642,8 +643,7 @@ dchecked_vector<std::string> OatWriter::GetSourceLocations() const { } bool OatWriter::MayHaveCompiledMethods() const { - return CompilerFilter::IsAnyCompilationEnabled( - GetCompilerDriver()->GetCompilerOptions().GetCompilerFilter()); + return GetCompilerOptions().IsAnyCompilationEnabled(); } bool OatWriter::WriteAndOpenDexFiles( @@ -703,6 +703,16 @@ bool OatWriter::WriteAndOpenDexFiles( return true; } +// Initialize the writer with the given parameters. +void OatWriter::Initialize(const CompilerDriver* compiler_driver, + ImageWriter* image_writer, + const std::vector<const DexFile*>& dex_files) { + compiler_driver_ = compiler_driver; + compiler_options_ = &compiler_driver->GetCompilerOptions(); + image_writer_ = image_writer; + dex_files_ = &dex_files; +} + void OatWriter::PrepareLayout(MultiOatRelativePatcher* relative_patcher) { CHECK(write_state_ == WriteState::kPrepareLayout); @@ -1157,7 +1167,7 @@ class OatWriter::LayoutCodeMethodVisitor : public OatDexMethodVisitor { size_t debug_info_idx = OrderedMethodData::kDebugInfoIdxInvalid; { - const CompilerOptions& compiler_options = writer_->compiler_driver_->GetCompilerOptions(); + const CompilerOptions& compiler_options = writer_->GetCompilerOptions(); ArrayRef<const uint8_t> quick_code = compiled_method->GetQuickCode(); uint32_t code_size = quick_code.size() * sizeof(uint8_t); @@ -1238,7 +1248,7 @@ class OatWriter::LayoutReserveOffsetCodeMethodVisitor : public OrderedMethodVisi OrderedMethodList ordered_methods) : LayoutReserveOffsetCodeMethodVisitor(writer, offset, - writer->GetCompilerDriver()->GetCompilerOptions(), + writer->GetCompilerOptions(), std::move(ordered_methods)) { } @@ -1651,7 +1661,7 @@ class OatWriter::InitImageMethodVisitor : public OatDexMethodVisitor { const DexFile::TypeId& type_id = dex_file_->GetTypeId(dex_file_->GetClassDef(class_def_index_).class_idx_); const char* class_descriptor = dex_file_->GetTypeDescriptor(type_id); - return writer_->GetCompilerDriver()->IsImageClass(class_descriptor); + return writer_->GetCompilerOptions().IsImageClass(class_descriptor); } // Check whether specified dex file is in the compiled oat file. @@ -1717,7 +1727,7 @@ class OatWriter::WriteCodeMethodVisitor : public OrderedMethodVisitor { // Ordered method visiting is only for compiled methods. DCHECK(writer_->MayHaveCompiledMethods()); - if (writer_->GetCompilerDriver()->GetCompilerOptions().IsAotCompilationEnabled()) { + if (writer_->GetCompilerOptions().IsAotCompilationEnabled()) { // Only need to set the dex cache if we have compilation. Other modes might have unloaded it. if (dex_cache_ == nullptr || dex_cache_->GetDexFile() != dex_file) { dex_cache_ = class_linker_->FindDexCache(Thread::Current(), *dex_file); @@ -2388,9 +2398,9 @@ size_t OatWriter::InitOatCode(size_t offset) { // TODO: Remove unused trampoline offsets from the OatHeader (requires oat version change). oat_header_->SetInterpreterToInterpreterBridgeOffset(0); oat_header_->SetInterpreterToCompiledCodeBridgeOffset(0); - if (compiler_driver_->GetCompilerOptions().IsBootImage()) { + if (GetCompilerOptions().IsBootImage()) { InstructionSet instruction_set = compiler_driver_->GetInstructionSet(); - const bool generate_debug_info = compiler_driver_->GetCompilerOptions().GenerateAnyDebugInfo(); + const bool generate_debug_info = GetCompilerOptions().GenerateAnyDebugInfo(); size_t adjusted_offset = offset; #define DO_TRAMPOLINE(field, fn_name) \ @@ -2428,7 +2438,7 @@ size_t OatWriter::InitOatCode(size_t offset) { } size_t OatWriter::InitOatCodeDexFiles(size_t offset) { - if (!compiler_driver_->GetCompilerOptions().IsAnyCompilationEnabled()) { + if (!GetCompilerOptions().IsAnyCompilationEnabled()) { if (kOatWriterDebugOatCodeLayout) { LOG(INFO) << "InitOatCodeDexFiles: OatWriter(" << this << "), " @@ -2741,7 +2751,7 @@ bool OatWriter::WriteQuickeningInfo(OutputStream* vdex_out) { } size_t current_offset = start_offset; - if (compiler_driver_->GetCompilerOptions().IsQuickeningCompilationEnabled()) { + if (GetCompilerOptions().IsQuickeningCompilationEnabled()) { std::vector<uint32_t> dex_files_indices; WriteQuickeningInfoMethodVisitor write_quicken_info_visitor(this, vdex_out); if (!write_quicken_info_visitor.VisitDexMethods(*dex_files_)) { @@ -3019,7 +3029,7 @@ bool OatWriter::WriteHeader(OutputStream* out, oat_header_->SetImageFileLocationOatChecksum(image_file_location_oat_checksum); oat_header_->SetImageFileLocationOatDataBegin(image_file_location_oat_begin); - if (compiler_driver_->GetCompilerOptions().IsBootImage()) { + if (GetCompilerOptions().IsBootImage()) { CHECK_EQ(image_patch_delta, 0); CHECK_EQ(oat_header_->GetImagePatchDelta(), 0); } else { @@ -3283,7 +3293,7 @@ size_t OatWriter::WriteOatDexFiles(OutputStream* out, size_t file_offset, size_t } size_t OatWriter::WriteCode(OutputStream* out, size_t file_offset, size_t relative_offset) { - if (compiler_driver_->GetCompilerOptions().IsBootImage()) { + if (GetCompilerOptions().IsBootImage()) { InstructionSet instruction_set = compiler_driver_->GetInstructionSet(); #define DO_TRAMPOLINE(field) \ @@ -3314,7 +3324,7 @@ size_t OatWriter::WriteCode(OutputStream* out, size_t file_offset, size_t relati size_t OatWriter::WriteCodeDexFiles(OutputStream* out, size_t file_offset, size_t relative_offset) { - if (!compiler_driver_->GetCompilerOptions().IsAnyCompilationEnabled()) { + if (!GetCompilerOptions().IsAnyCompilationEnabled()) { // As with InitOatCodeDexFiles, also skip the writer if // compilation was disabled. if (kOatWriterDebugOatCodeLayout) { diff --git a/dex2oat/linker/oat_writer.h b/dex2oat/linker/oat_writer.h index 619743ef14..ccafe05544 100644 --- a/dex2oat/linker/oat_writer.h +++ b/dex2oat/linker/oat_writer.h @@ -42,6 +42,7 @@ namespace art { class BitVector; class CompiledMethod; class CompilerDriver; +class CompilerOptions; class DexContainer; class ProfileCompilationInfo; class TimingLogger; @@ -180,17 +181,13 @@ class OatWriter { CopyOption copy_dex_files, /*out*/ std::vector<std::unique_ptr<MemMap>>* opened_dex_files_map, /*out*/ std::vector<std::unique_ptr<const DexFile>>* opened_dex_files); + // Initialize the writer with the given parameters. + void Initialize(const CompilerDriver* compiler_driver, + ImageWriter* image_writer, + const std::vector<const DexFile*>& dex_files); bool WriteQuickeningInfo(OutputStream* vdex_out); bool WriteVerifierDeps(OutputStream* vdex_out, verifier::VerifierDeps* verifier_deps); bool WriteChecksumsAndVdexHeader(OutputStream* vdex_out); - // Initialize the writer with the given parameters. - void Initialize(const CompilerDriver* compiler, - ImageWriter* image_writer, - const std::vector<const DexFile*>& dex_files) { - compiler_driver_ = compiler; - image_writer_ = image_writer; - dex_files_ = &dex_files; - } // Prepare layout of remaining data. void PrepareLayout(MultiOatRelativePatcher* relative_patcher); @@ -263,6 +260,11 @@ class OatWriter { return compiler_driver_; } + const CompilerOptions& GetCompilerOptions() const { + DCHECK(compiler_options_ != nullptr); + return *compiler_options_; + } + private: class DexFileSource; class OatClassHeader; @@ -388,6 +390,7 @@ class OatWriter { dchecked_vector<debug::MethodDebugInfo> method_info_; const CompilerDriver* compiler_driver_; + const CompilerOptions* compiler_options_; ImageWriter* image_writer_; const bool compiling_boot_image_; // Whether the dex files being compiled are going to be extracted to the vdex. |