diff options
83 files changed, 845 insertions, 1044 deletions
diff --git a/build/Android.bp b/build/Android.bp index 3a1d5839f5..b7d2cbc070 100644 --- a/build/Android.bp +++ b/build/Android.bp @@ -17,6 +17,27 @@ bootstrap_go_package { pluginFor: ["soong_build"], } +art_clang_tidy_errors = [ + // Protect scoped things like MutexLock. + "bugprone-unused-raii", +] +// Should be: strings.Join(art_clang_tidy_errors, ","). +art_clang_tidy_errors_str = "bugprone-unused-raii" + +art_clang_tidy_disabled = [ + "-google-default-arguments", + // We have local stores that are only used for debug checks. + "-clang-analyzer-deadcode.DeadStores", + // We are OK with some static globals and that they can, in theory, throw. + "-cert-err58-cpp", + // We have lots of C-style variadic functions, and are OK with them. JNI ensures + // that working around this warning would be extra-painful. + "-cert-dcl50-cpp", + // No exceptions. + "-misc-noexcept-move-constructor", + "-performance-noexcept-move-constructor", +] + art_global_defaults { // Additional flags are computed by art.go @@ -130,18 +151,7 @@ art_global_defaults { "external/vixl/src", ], - tidy_checks: [ - "-google-default-arguments", - // We have local stores that are only used for debug checks. - "-clang-analyzer-deadcode.DeadStores", - // We are OK with some static globals and that they can, in theory, throw. - "-cert-err58-cpp", - // We have lots of C-style variadic functions, and are OK with them. JNI ensures - // that working around this warning would be extra-painful. - "-cert-dcl50-cpp", - // No exceptions. - "-misc-noexcept-move-constructor", - ], + tidy_checks: art_clang_tidy_errors + art_clang_tidy_disabled, tidy_flags: [ // The static analyzer treats DCHECK as always enabled; we sometimes get @@ -151,6 +161,8 @@ art_global_defaults { // void foo() { CHECK(kIsFooEnabled); /* do foo... */ } // not being marked noreturn if kIsFooEnabled is false. "-extra-arg=-Wno-missing-noreturn", + // Use art_clang_tidy_errors for build errors. + "-warnings-as-errors=" + art_clang_tidy_errors_str, ], } diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk index 9f42727a2f..7d1115eec0 100644 --- a/build/Android.gtest.mk +++ b/build/Android.gtest.mk @@ -668,7 +668,7 @@ define define-test-art-gtest-combination dependencies := $$(ART_TEST_$(2)_GTEST$(3)_RULES) .PHONY: $$(rule_name) -$$(rule_name): $$(dependencies) dx d8-compat-dx desugar +$$(rule_name): $$(dependencies) d8 d8-compat-dx $(hide) $$(call ART_TEST_PREREQ_FINISHED,$$@) # Clear locally defined variables. diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc index c37d4523c4..52c767f935 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" @@ -39,6 +40,7 @@ #include "oat_quick_method_header.h" #include "scoped_thread_state_change-inl.h" #include "thread-current-inl.h" +#include "utils/atomic_dex_ref_map-inl.h" namespace art { @@ -134,8 +136,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 +174,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 +237,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); } @@ -291,4 +333,10 @@ void CommonCompilerTest::UnreserveImageSpace() { image_reservation_.reset(); } +void CommonCompilerTest::SetDexFilesForOatFile(const std::vector<const DexFile*>& dex_files) { + compiler_options_->dex_files_for_oat_file_ = dex_files; + compiler_driver_->compiled_classes_.AddDexFiles(dex_files); + compiler_driver_->dex_to_dex_compiler_.SetDexFiles(dex_files); +} + } // namespace art diff --git a/compiler/common_compiler_test.h b/compiler/common_compiler_test.h index 46b59a35be..f070bbbeb8 100644 --- a/compiler/common_compiler_test.h +++ b/compiler/common_compiler_test.h @@ -33,6 +33,7 @@ class ClassLoader; class CompilerDriver; class CompilerOptions; class CumulativeLogger; +class DexFile; class ProfileCompilationInfo; class VerificationResults; @@ -93,6 +94,8 @@ class CommonCompilerTest : public CommonRuntimeTest { void UnreserveImageSpace(); + void SetDexFilesForOatFile(const std::vector<const DexFile*>& dex_files); + Compiler::Kind compiler_kind_ = Compiler::kOptimizing; std::unique_ptr<CompilerOptions> compiler_options_; std::unique_ptr<VerificationResults> verification_results_; diff --git a/compiler/compiler.h b/compiler/compiler.h index f2ec3a9fa3..ef3d87f02b 100644 --- a/compiler/compiler.h +++ b/compiler/compiler.h @@ -39,12 +39,6 @@ template<class T> class Handle; class OatWriter; class Thread; -enum class CopyOption { - kNever, - kAlways, - kOnlyIfCompressed -}; - class Compiler { public: enum Kind { diff --git a/compiler/dex/dex_to_dex_decompiler_test.cc b/compiler/dex/dex_to_dex_decompiler_test.cc index 76250d202c..4f83d605a3 100644 --- a/compiler/dex/dex_to_dex_decompiler_test.cc +++ b/compiler/dex/dex_to_dex_decompiler_test.cc @@ -47,7 +47,7 @@ class DexToDexDecompilerTest : public CommonCompilerTest { // the results for all the dex files, not just the results for the current dex file. down_cast<QuickCompilerCallbacks*>(Runtime::Current()->GetCompilerCallbacks())->SetVerifierDeps( new verifier::VerifierDeps(GetDexFiles(class_loader))); - compiler_driver_->SetDexFilesForOatFile(GetDexFiles(class_loader)); + SetDexFilesForOatFile(GetDexFiles(class_loader)); compiler_driver_->CompileAll(class_loader, GetDexFiles(class_loader), &timings); } diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index bd2b1070fc..66a8a57b36 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(), @@ -919,6 +886,20 @@ void CompilerDriver::PreCompile(jobject class_loader, TimingLogger* timings) { CheckThreadPools(); + VLOG(compiler) << "Before precompile " << GetMemoryUsageString(false); + + compiled_classes_.AddDexFiles(GetCompilerOptions().GetDexFilesForOatFile()); + dex_to_dex_compiler_.SetDexFiles(GetCompilerOptions().GetDexFilesForOatFile()); + + // 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 +969,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 +1087,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 +1145,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 +1329,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 +1353,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, @@ -1981,7 +1952,8 @@ void CompilerDriver::Verify(jobject jclass_loader, // Create per-thread VerifierDeps to avoid contention on the main one. // We will merge them after verification. for (ThreadPoolWorker* worker : parallel_thread_pool_->GetWorkers()) { - worker->GetThread()->SetVerifierDeps(new verifier::VerifierDeps(dex_files_for_oat_file_)); + worker->GetThread()->SetVerifierDeps( + new verifier::VerifierDeps(GetCompilerOptions().GetDexFilesForOatFile())); } } @@ -2006,7 +1978,7 @@ void CompilerDriver::Verify(jobject jclass_loader, for (ThreadPoolWorker* worker : parallel_thread_pool_->GetWorkers()) { verifier::VerifierDeps* thread_deps = worker->GetThread()->GetVerifierDeps(); worker->GetThread()->SetVerifierDeps(nullptr); - verifier_deps->MergeWith(*thread_deps, dex_files_for_oat_file_); + verifier_deps->MergeWith(*thread_deps, GetCompilerOptions().GetDexFilesForOatFile()); delete thread_deps; } Thread::Current()->SetVerifierDeps(nullptr); @@ -2292,7 +2264,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 @@ -2879,7 +2851,7 @@ void CompilerDriver::RecordClassStatus(const ClassReference& ref, ClassStatus st if (kIsDebugBuild) { // Check to make sure it's not a dex file for an oat file we are compiling since these // should always succeed. These do not include classes in for used libraries. - for (const DexFile* dex_file : GetDexFilesForOatFile()) { + for (const DexFile* dex_file : GetCompilerOptions().GetDexFilesForOatFile()) { CHECK_NE(ref.dex_file, dex_file) << ref.dex_file->GetLocation(); } } @@ -2978,18 +2950,6 @@ std::string CompilerDriver::GetMemoryUsageString(bool extended) const { return oss.str(); } -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)) { - return false; - } - - return true; -} - void CompilerDriver::InitializeThreadPools() { size_t parallel_count = parallel_thread_count_ > 0 ? parallel_thread_count_ - 1 : 0; parallel_thread_pool_.reset( @@ -3002,12 +2962,6 @@ void CompilerDriver::FreeThreadPools() { single_thread_pool_.reset(); } -void CompilerDriver::SetDexFilesForOatFile(const std::vector<const DexFile*>& dex_files) { - dex_files_for_oat_file_ = dex_files; - compiled_classes_.AddDexFiles(dex_files); - dex_to_dex_compiler_.SetDexFiles(dex_files); -} - void CompilerDriver::SetClasspathDexFiles(const std::vector<const DexFile*>& dex_files) { classpath_classes_.AddDexFiles(dex_files); } diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index ff70d96272..54e1f3747f 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -99,32 +99,33 @@ 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); ~CompilerDriver(); - // Set dex files associated with the oat file being compiled. - void SetDexFilesForOatFile(const std::vector<const DexFile*>& dex_files); - // Set dex files classpath. void SetClasspathDexFiles(const std::vector<const DexFile*>& dex_files); - // Get dex files associated with the the oat file being compiled. - ArrayRef<const DexFile* const> GetDexFilesForOatFile() const { - return ArrayRef<const DexFile* const>(dex_files_for_oat_file_); - } - void CompileAll(jobject class_loader, const std::vector<const DexFile*>& dex_files, 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 +145,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 +305,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; @@ -352,13 +346,6 @@ class CompilerDriver { bool CanAssumeClassIsLoaded(mirror::Class* klass) REQUIRES_SHARED(Locks::mutator_lock_); - bool MayInline(const DexFile* inlined_from, const DexFile* inlined_into) const { - if (!kIsTargetBuild) { - return MayInlineInternal(inlined_from, inlined_into); - } - return true; - } - const ProfileCompilationInfo* GetProfileCompilationInfo() const { return profile_compilation_info_; } @@ -452,8 +439,6 @@ class CompilerDriver { const std::vector<const DexFile*>& dex_files, TimingLogger* timings); - bool MayInlineInternal(const DexFile* inlined_from, const DexFile* inlined_into) const; - void InitializeThreadPools(); void FreeThreadPools(); void CheckThreadPools(); @@ -491,9 +476,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 +492,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_; @@ -521,9 +508,6 @@ class CompilerDriver { bool support_boot_image_fixup_; - // List of dex files associates with the oat file. - std::vector<const DexFile*> dex_files_for_oat_file_; - CompiledMethodStorage compiled_method_storage_; // Info for profile guided compilation. @@ -534,6 +518,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_driver_test.cc b/compiler/driver/compiler_driver_test.cc index 491e61f9b5..2eeb4399db 100644 --- a/compiler/driver/compiler_driver_test.cc +++ b/compiler/driver/compiler_driver_test.cc @@ -46,7 +46,7 @@ class CompilerDriverTest : public CommonCompilerTest { TimingLogger timings("CompilerDriverTest::CompileAll", false, false); TimingLogger::ScopedTiming t(__FUNCTION__, &timings); dex_files_ = GetDexFiles(class_loader); - compiler_driver_->SetDexFilesForOatFile(dex_files_);; + SetDexFilesForOatFile(dex_files_); compiler_driver_->CompileAll(class_loader, dex_files_, &timings); t.NewTiming("MakeAllExecutable"); MakeAllExecutable(class_loader); @@ -331,7 +331,7 @@ TEST_F(CompilerDriverVerifyTest, RetryVerifcationStatusCheckVerified) { ASSERT_GT(dex_files.size(), 0u); dex_file = dex_files.front(); } - compiler_driver_->SetDexFilesForOatFile(dex_files); + SetDexFilesForOatFile(dex_files); callbacks_->SetDoesClassUnloading(true, compiler_driver_.get()); ClassReference ref(dex_file, 0u); // Test that the status is read from the compiler driver as expected. diff --git a/compiler/driver/compiler_options.cc b/compiler/driver/compiler_options.cc index 933be4f004..cc1af3e108 100644 --- a/compiler/driver/compiler_options.cc +++ b/compiler/driver/compiler_options.cc @@ -37,7 +37,9 @@ CompilerOptions::CompilerOptions() tiny_method_threshold_(kDefaultTinyMethodThreshold), num_dex_methods_threshold_(kDefaultNumDexMethodsThreshold), inline_max_code_units_(kUnsetInlineMaxCodeUnits), - no_inline_from_(nullptr), + no_inline_from_(), + dex_files_for_oat_file_(), + image_classes_(), boot_image_(false), core_image_(false), app_image_(false), @@ -67,8 +69,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 +131,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..908ff3302c 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,20 @@ 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 std::vector<const DexFile*>& GetDexFilesForOatFile() const { + return dex_files_for_oat_file_; + } + + 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 +312,17 @@ 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_; + + // List of dex files associated with the oat file, empty for JIT. + std::vector<const DexFile*> dex_files_for_oat_file_; + + // 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/inliner.cc b/compiler/optimizing/inliner.cc index 7dd756e13a..72d53d28cf 100644 --- a/compiler/optimizing/inliner.cc +++ b/compiler/optimizing/inliner.cc @@ -126,7 +126,7 @@ void HInliner::UpdateInliningBudget() { } bool HInliner::Run() { - if (compiler_driver_->GetCompilerOptions().GetInlineMaxCodeUnits() == 0) { + if (codegen_->GetCompilerOptions().GetInlineMaxCodeUnits() == 0) { // Inlining effectively disabled. return false; } else if (graph_->IsDebuggable()) { @@ -731,7 +731,7 @@ HInliner::InlineCacheType HInliner::ExtractClassesFromOfflineProfile( offline_profile.dex_references.size()); for (size_t i = 0; i < offline_profile.dex_references.size(); i++) { bool found = false; - for (const DexFile* dex_file : compiler_driver_->GetDexFilesForOatFile()) { + for (const DexFile* dex_file : codegen_->GetCompilerOptions().GetDexFilesForOatFile()) { if (offline_profile.dex_references[i].MatchesDex(dex_file)) { dex_profile_index_to_dex_cache[i] = caller_compilation_unit_.GetClassLinker()->FindDexCache(self, *dex_file); @@ -1418,6 +1418,22 @@ size_t HInliner::CountRecursiveCallsOf(ArtMethod* method) const { return count; } +static inline bool MayInline(const CompilerOptions& compiler_options, + const DexFile& inlined_from, + const DexFile& inlined_into) { + if (kIsTargetBuild) { + return true; + } + + // We're not allowed to inline across dex files if we're the no-inline-from dex file. + if (!IsSameDexFile(inlined_from, inlined_into) && + ContainsElement(compiler_options.GetNoInlineFromDexFile(), &inlined_from)) { + return false; + } + + return true; +} + bool HInliner::TryBuildAndInline(HInvoke* invoke_instruction, ArtMethod* method, ReferenceTypeInfo receiver_type, @@ -1439,8 +1455,9 @@ bool HInliner::TryBuildAndInline(HInvoke* invoke_instruction, // Check whether we're allowed to inline. The outermost compilation unit is the relevant // dex file here (though the transitivity of an inline chain would allow checking the calller). - if (!compiler_driver_->MayInline(method->GetDexFile(), - outer_compilation_unit_.GetDexFile())) { + if (!MayInline(codegen_->GetCompilerOptions(), + *method->GetDexFile(), + *outer_compilation_unit_.GetDexFile())) { if (TryPatternSubstitution(invoke_instruction, method, return_replacement)) { LOG_SUCCESS() << "Successfully replaced pattern of invoke " << method->PrettyMethod(); @@ -1465,7 +1482,7 @@ bool HInliner::TryBuildAndInline(HInvoke* invoke_instruction, return false; } - size_t inline_max_code_units = compiler_driver_->GetCompilerOptions().GetInlineMaxCodeUnits(); + size_t inline_max_code_units = codegen_->GetCompilerOptions().GetInlineMaxCodeUnits(); if (accessor.InsnsSizeInCodeUnits() > inline_max_code_units) { LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedCodeItem) << "Method " << method->PrettyMethod() 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..1e29c21313 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,26 +178,27 @@ 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 { // Not a boot image class. - DCHECK(ContainsElement(compiler_driver->GetDexFilesForOatFile(), &dex_file)); + DCHECK(ContainsElement(compiler_options.GetDexFilesForOatFile(), &dex_file)); desired_load_kind = HLoadClass::LoadKind::kBssEntry; } } else { is_in_boot_image = (klass != nullptr) && runtime->GetHeap()->ObjectIsInBootImageSpace(klass.Get()); if (runtime->UseJitCompilation()) { - DCHECK(!codegen->GetCompilerOptions().GetCompilePic()); + DCHECK(!compiler_options.GetCompilePic()); if (is_in_boot_image) { // TODO: Use direct pointers for all non-moving spaces, not just boot image. Bug: 29530787 desired_load_kind = HLoadClass::LoadKind::kBootImageAddress; @@ -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; @@ -332,14 +331,15 @@ void HSharpening::ProcessLoadString( : hs.NewHandle(class_linker->FindDexCache(soa.Self(), dex_file)); ObjPtr<mirror::String> string = nullptr; - if (codegen->GetCompilerOptions().IsBootImage()) { + const CompilerOptions& compiler_options = codegen->GetCompilerOptions(); + if (compiler_options.IsBootImage()) { // Compiling boot image. Resolve the string and allocate it if needed, to ensure // the string will be added to the boot image. DCHECK(!runtime->UseJitCompilation()); string = class_linker->ResolveString(string_index, dex_cache); CHECK(string != nullptr); if (compiler_driver->GetSupportBootImageFixup()) { - DCHECK(ContainsElement(compiler_driver->GetDexFilesForOatFile(), &dex_file)); + DCHECK(ContainsElement(compiler_options.GetDexFilesForOatFile(), &dex_file)); desired_load_kind = HLoadString::LoadKind::kBootImageLinkTimePcRelative; } else { // compiler_driver_test. Do not sharpen. 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/compiler/verifier_deps_test.cc b/compiler/verifier_deps_test.cc index 3fe2ec0ac0..c223549710 100644 --- a/compiler/verifier_deps_test.cc +++ b/compiler/verifier_deps_test.cc @@ -129,7 +129,7 @@ class VerifierDepsTest : public CommonCompilerTest { for (const DexFile* dex_file : dex_files_) { compiler_driver_->GetVerificationResults()->AddDexFile(dex_file); } - compiler_driver_->SetDexFilesForOatFile(dex_files_); + SetDexFilesForOatFile(dex_files_); } void LoadDexFile(ScopedObjectAccess& soa) REQUIRES_SHARED(Locks::mutator_lock_) { diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index 6cd947c8cf..be3f922340 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), @@ -697,7 +696,7 @@ class Dex2Oat FINAL { } bool VerifyProfileData() { - return profile_compilation_info_->VerifyProfileData(dex_files_); + return profile_compilation_info_->VerifyProfileData(compiler_options_->dex_files_for_oat_file_); } void ParseInstructionSetVariant(const std::string& option, ParserOptions* parser_options) { @@ -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( + compiler_options_->dex_files_for_oat_file_); + 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); } } @@ -1655,10 +1653,11 @@ class Dex2Oat FINAL { } } - dex_files_ = MakeNonOwningPointerVector(opened_dex_files_); + compiler_options_->dex_files_for_oat_file_ = MakeNonOwningPointerVector(opened_dex_files_); + const std::vector<const DexFile*>& dex_files = compiler_options_->dex_files_for_oat_file_; // If we need to downgrade the compiler-filter for size reasons. - if (!IsBootImage() && IsVeryLarge(dex_files_)) { + if (!IsBootImage() && IsVeryLarge(dex_files)) { // Disable app image to make sure dex2oat unloading is enabled. compiler_options_->DisableAppImage(); @@ -1691,7 +1690,7 @@ class Dex2Oat FINAL { CHECK(driver_ == nullptr); // If we use a swap file, ensure we are above the threshold to make it necessary. if (swap_fd_ != -1) { - if (!UseSwap(IsBootImage(), dex_files_)) { + if (!UseSwap(IsBootImage(), dex_files)) { close(swap_fd_); swap_fd_ = -1; VLOG(compiler) << "Decided to run without swap."; @@ -1734,7 +1733,7 @@ class Dex2Oat FINAL { // Verification results are only required for modes that have any compilation. Avoid // adding the dex files if possible to prevent allocating large arrays. if (verification_results_ != nullptr) { - for (const auto& dex_file : dex_files_) { + for (const auto& dex_file : dex_files) { // Pre-register dex files so that we can access verification results without locks during // compilation and verification. verification_results_->AddDexFile(dex_file); @@ -1752,7 +1751,7 @@ class Dex2Oat FINAL { // Doesn't return the class loader since it's not meant to be used for image compilation. void CompileDexFilesIndividually() { CHECK(!IsImage()) << "Not supported with image"; - for (const DexFile* dex_file : dex_files_) { + for (const DexFile* dex_file : compiler_options_->dex_files_for_oat_file_) { std::vector<const DexFile*> dex_files(1u, dex_file); VLOG(compiler) << "Compiling " << dex_file->GetLocation(); jobject class_loader = CompileDexFiles(dex_files); @@ -1783,7 +1782,7 @@ class Dex2Oat FINAL { // mode (to reduce RAM used by the compiler). return !IsImage() && !update_input_vdex_ && - dex_files_.size() > 1 && + compiler_options_->dex_files_for_oat_file_.size() > 1 && !CompilerFilter::IsAotCompilationEnabled(compiler_options_->GetCompilerFilter()); } @@ -1810,10 +1809,12 @@ class Dex2Oat FINAL { class_path_files = class_loader_context_->FlattenOpenedDexFiles(); } - std::vector<const std::vector<const DexFile*>*> dex_file_vectors = { + const std::vector<const DexFile*>& dex_files = compiler_options_->dex_files_for_oat_file_; + std::vector<const DexFile*> no_inline_from_dex_files; + const std::vector<const DexFile*>* dex_file_vectors[] = { &class_linker->GetBootClassPath(), &class_path_files, - &dex_files_ + &dex_files }; for (const std::vector<const DexFile*>* dex_file_vector : dex_file_vectors) { for (const DexFile* dex_file : *dex_file_vector) { @@ -1832,14 +1833,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,11 +1849,10 @@ 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())); - driver_->SetDexFilesForOatFile(dex_files_); if (!IsBootImage()) { driver_->SetClasspathDexFiles(class_loader_context_->FlattenOpenedDexFiles()); } @@ -1868,9 +1868,10 @@ class Dex2Oat FINAL { } // Setup vdex for compilation. + const std::vector<const DexFile*>& dex_files = compiler_options_->dex_files_for_oat_file_; if (!DoEagerUnquickeningOfVdex() && input_vdex_file_ != nullptr) { callbacks_->SetVerifierDeps( - new verifier::VerifierDeps(dex_files_, input_vdex_file_->GetVerifierDepsData())); + new verifier::VerifierDeps(dex_files, input_vdex_file_->GetVerifierDepsData())); // TODO: we unquicken unconditionally, as we don't know // if the boot image has changed. How exactly we'll know is under @@ -1880,11 +1881,11 @@ class Dex2Oat FINAL { // We do not decompile a RETURN_VOID_NO_BARRIER into a RETURN_VOID, as the quickening // optimization does not depend on the boot image (the optimization relies on not // having final fields in a class, which does not change for an app). - input_vdex_file_->Unquicken(dex_files_, /* decompile_return_instruction */ false); + input_vdex_file_->Unquicken(dex_files, /* decompile_return_instruction */ false); } else { // Create the main VerifierDeps, here instead of in the compiler since we want to aggregate // the results for all the dex files, not just the results for the current dex file. - callbacks_->SetVerifierDeps(new verifier::VerifierDeps(dex_files_)); + callbacks_->SetVerifierDeps(new verifier::VerifierDeps(dex_files)); } // Invoke the compilation. if (compile_individually) { @@ -1892,7 +1893,7 @@ class Dex2Oat FINAL { // Return a null classloader since we already freed released it. return nullptr; } - return CompileDexFiles(dex_files_); + return CompileDexFiles(dex_files); } // Create the class loader, use it to compile, and return. @@ -1901,7 +1902,8 @@ class Dex2Oat FINAL { jobject class_loader = nullptr; if (!IsBootImage()) { - class_loader = class_loader_context_->CreateClassLoader(dex_files_); + class_loader = + class_loader_context_->CreateClassLoader(compiler_options_->dex_files_for_oat_file_); callbacks_->SetDexFiles(&dex_files); } @@ -2371,7 +2373,7 @@ class Dex2Oat FINAL { return dex_files_size >= min_dex_file_cumulative_size_for_swap_; } - bool IsVeryLarge(std::vector<const DexFile*>& dex_files) { + bool IsVeryLarge(const std::vector<const DexFile*>& dex_files) { size_t dex_files_size = 0; for (const auto* dex_file : dex_files) { dex_files_size += dex_file->GetHeader().file_size_; @@ -2381,14 +2383,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; } @@ -2502,8 +2504,9 @@ class Dex2Oat FINAL { } void SaveDexInput() { - for (size_t i = 0; i < dex_files_.size(); ++i) { - const DexFile* dex_file = dex_files_[i]; + const std::vector<const DexFile*>& dex_files = compiler_options_->dex_files_for_oat_file_; + for (size_t i = 0, size = dex_files.size(); i != size; ++i) { + const DexFile* dex_file = dex_files[i]; std::string tmp_file_name(StringPrintf("/data/local/tmp/dex2oat.%d.%zd.dex", getpid(), i)); std::unique_ptr<File> tmp_file(OS::CreateEmptyFile(tmp_file_name.c_str())); @@ -2704,8 +2707,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,14 +2853,11 @@ 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_; bool is_host_; std::string android_root_; - // Dex files we are compiling, does not include the class path dex files. - std::vector<const DexFile*> dex_files_; std::string no_inline_from_string_; CompactDexLevel compact_dex_level_ = kDefaultCompactDexLevel; @@ -2872,9 +2871,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_; @@ -2904,7 +2900,7 @@ class Dex2Oat FINAL { // By default, copy the dex to the vdex file only if dex files are // compressed in APK. - CopyOption copy_dex_files_ = CopyOption::kOnlyIfCompressed; + linker::CopyOption copy_dex_files_ = linker::CopyOption::kOnlyIfCompressed; // The reason for invoking the compiler. std::string compilation_reason_; diff --git a/dex2oat/dex2oat_options.cc b/dex2oat/dex2oat_options.cc index dbb00c22e9..bf9edf7384 100644 --- a/dex2oat/dex2oat_options.cc +++ b/dex2oat/dex2oat_options.cc @@ -222,10 +222,10 @@ static Parser CreateArgumentParser() { .Define("--force-determinism") .IntoKey(M::ForceDeterminism) .Define("--copy-dex-files=_") - .WithType<CopyOption>() - .WithValueMap({{"true", CopyOption::kOnlyIfCompressed}, - {"false", CopyOption::kNever}, - {"always", CopyOption::kAlways}}) + .WithType<linker::CopyOption>() + .WithValueMap({{"true", linker::CopyOption::kOnlyIfCompressed}, + {"false", linker::CopyOption::kNever}, + {"always", linker::CopyOption::kAlways}}) .IntoKey(M::CopyDexFiles) .Define("--classpath-dir=_") .WithType<std::string>() diff --git a/dex2oat/dex2oat_options.def b/dex2oat/dex2oat_options.def index 7be8e56501..fe5c4e69a7 100644 --- a/dex2oat/dex2oat_options.def +++ b/dex2oat/dex2oat_options.def @@ -70,7 +70,7 @@ DEX2OAT_OPTIONS_KEY (Unit, Host) DEX2OAT_OPTIONS_KEY (Unit, DumpTiming) DEX2OAT_OPTIONS_KEY (Unit, DumpPasses) DEX2OAT_OPTIONS_KEY (Unit, DumpStats) -DEX2OAT_OPTIONS_KEY (CopyOption, CopyDexFiles) +DEX2OAT_OPTIONS_KEY (linker::CopyOption, CopyDexFiles) DEX2OAT_OPTIONS_KEY (Unit, AvoidStoringInvocation) DEX2OAT_OPTIONS_KEY (std::string, SwapFile) DEX2OAT_OPTIONS_KEY (int, SwapFileFd) diff --git a/dex2oat/dex2oat_options.h b/dex2oat/dex2oat_options.h index cc124c1afa..27d3d25f2a 100644 --- a/dex2oat/dex2oat_options.h +++ b/dex2oat/dex2oat_options.h @@ -28,6 +28,7 @@ #include "dex/compact_dex_level.h" #include "driver/compiler_options_map.h" #include "image.h" +#include "linker/oat_writer.h" namespace art { diff --git a/dex2oat/linker/image_test.h b/dex2oat/linker/image_test.h index 12ecd3a4fc..66b37fb08d 100644 --- a/dex2oat/linker/image_test.h +++ b/dex2oat/linker/image_test.h @@ -63,9 +63,6 @@ struct CompilationHelper { std::vector<ScratchFile> vdex_files; std::string image_dir; - void Compile(CompilerDriver* driver, - ImageHeader::StorageMode storage_mode); - std::vector<size_t> GetImageObjectSectionSizes(); ~CompilationHelper(); @@ -81,7 +78,7 @@ class ImageTest : public CommonCompilerTest { void TestWriteRead(ImageHeader::StorageMode storage_mode); void Compile(ImageHeader::StorageMode storage_mode, - CompilationHelper& out_helper, + /*out*/ CompilationHelper& out_helper, const std::string& extra_dex = "", const std::initializer_list<std::string>& image_classes = {}); @@ -111,6 +108,8 @@ class ImageTest : public CommonCompilerTest { } private: + void DoCompile(ImageHeader::StorageMode storage_mode, /*out*/ CompilationHelper& out_helper); + HashSet<std::string> image_classes_; }; @@ -141,12 +140,13 @@ inline std::vector<size_t> CompilationHelper::GetImageObjectSectionSizes() { return ret; } -inline void CompilationHelper::Compile(CompilerDriver* driver, - ImageHeader::StorageMode storage_mode) { +inline void ImageTest::DoCompile(ImageHeader::StorageMode storage_mode, + /*out*/ CompilationHelper& out_helper) { + CompilerDriver* driver = compiler_driver_.get(); ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); std::vector<const DexFile*> class_path = class_linker->GetBootClassPath(); - for (const std::unique_ptr<const DexFile>& dex_file : extra_dex_files) { + for (const std::unique_ptr<const DexFile>& dex_file : out_helper.extra_dex_files) { { ScopedObjectAccess soa(Thread::Current()); // Inject in boot class path so that the compiler driver can see it. @@ -157,7 +157,7 @@ inline void CompilationHelper::Compile(CompilerDriver* driver, // Enable write for dex2dex. for (const DexFile* dex_file : class_path) { - dex_file_locations.push_back(dex_file->GetLocation()); + out_helper.dex_file_locations.push_back(dex_file->GetLocation()); if (dex_file->IsReadOnly()) { dex_file->EnableWrite(); } @@ -168,31 +168,31 @@ inline void CompilationHelper::Compile(CompilerDriver* driver, for (int i = 0; i < static_cast<int>(class_path.size()); ++i) { std::string cur_location = android::base::StringPrintf("%s-%d.art", location.GetFilename().c_str(), i); - image_locations.push_back(ScratchFile(cur_location)); + out_helper.image_locations.push_back(ScratchFile(cur_location)); } } std::vector<std::string> image_filenames; - for (ScratchFile& file : image_locations) { + for (ScratchFile& file : out_helper.image_locations) { std::string image_filename(GetSystemImageFilename(file.GetFilename().c_str(), kRuntimeISA)); image_filenames.push_back(image_filename); size_t pos = image_filename.rfind('/'); CHECK_NE(pos, std::string::npos) << image_filename; - if (image_dir.empty()) { - image_dir = image_filename.substr(0, pos); - int mkdir_result = mkdir(image_dir.c_str(), 0700); - CHECK_EQ(0, mkdir_result) << image_dir; + if (out_helper.image_dir.empty()) { + out_helper.image_dir = image_filename.substr(0, pos); + int mkdir_result = mkdir(out_helper.image_dir.c_str(), 0700); + CHECK_EQ(0, mkdir_result) << out_helper.image_dir; } - image_files.push_back(ScratchFile(OS::CreateEmptyFile(image_filename.c_str()))); + out_helper.image_files.push_back(ScratchFile(OS::CreateEmptyFile(image_filename.c_str()))); } std::vector<std::string> oat_filenames; std::vector<std::string> vdex_filenames; for (const std::string& image_filename : image_filenames) { std::string oat_filename = ReplaceFileExtension(image_filename, "oat"); - oat_files.push_back(ScratchFile(OS::CreateEmptyFile(oat_filename.c_str()))); + out_helper.oat_files.push_back(ScratchFile(OS::CreateEmptyFile(oat_filename.c_str()))); oat_filenames.push_back(oat_filename); std::string vdex_filename = ReplaceFileExtension(image_filename, "vdex"); - vdex_files.push_back(ScratchFile(OS::CreateEmptyFile(vdex_filename.c_str()))); + out_helper.vdex_files.push_back(ScratchFile(OS::CreateEmptyFile(vdex_filename.c_str()))); vdex_filenames.push_back(vdex_filename); } @@ -224,7 +224,7 @@ inline void CompilationHelper::Compile(CompilerDriver* driver, jobject class_loader = nullptr; TimingLogger timings("ImageTest::WriteRead", false, false); TimingLogger::ScopedTiming t("CompileAll", &timings); - driver->SetDexFilesForOatFile(class_path); + SetDexFilesForOatFile(class_path); driver->CompileAll(class_loader, class_path, &timings); t.NewTiming("WriteElf"); @@ -241,7 +241,7 @@ inline void CompilationHelper::Compile(CompilerDriver* driver, std::vector<std::unique_ptr<ElfWriter>> elf_writers; std::vector<std::unique_ptr<OatWriter>> oat_writers; - for (ScratchFile& oat_file : oat_files) { + for (ScratchFile& oat_file : out_helper.oat_files) { elf_writers.emplace_back(CreateElfWriterQuick(driver->GetInstructionSet(), driver->GetInstructionSetFeatures(), &driver->GetCompilerOptions(), @@ -270,7 +270,7 @@ inline void CompilationHelper::Compile(CompilerDriver* driver, std::vector<std::unique_ptr<MemMap>> cur_opened_dex_files_maps; std::vector<std::unique_ptr<const DexFile>> cur_opened_dex_files; bool dex_files_ok = oat_writers[i]->WriteAndOpenDexFiles( - vdex_files[i].GetFile(), + out_helper.vdex_files[i].GetFile(), rodata.back(), driver->GetInstructionSet(), driver->GetInstructionSetFeatures(), @@ -297,8 +297,8 @@ inline void CompilationHelper::Compile(CompilerDriver* driver, bool image_space_ok = writer->PrepareImageAddressSpace(&timings); ASSERT_TRUE(image_space_ok); - DCHECK_EQ(vdex_files.size(), oat_files.size()); - for (size_t i = 0, size = oat_files.size(); i != size; ++i) { + DCHECK_EQ(out_helper.vdex_files.size(), out_helper.oat_files.size()); + for (size_t i = 0, size = out_helper.oat_files.size(); i != size; ++i) { MultiOatRelativePatcher patcher(driver->GetInstructionSet(), driver->GetInstructionSetFeatures(), driver->GetCompiledMethodStorage()); @@ -309,7 +309,7 @@ inline void CompilationHelper::Compile(CompilerDriver* driver, std::unique_ptr<BufferedOutputStream> vdex_out = std::make_unique<BufferedOutputStream>( - std::make_unique<FileOutputStream>(vdex_files[i].GetFile())); + std::make_unique<FileOutputStream>(out_helper.vdex_files[i].GetFile())); oat_writer->WriteVerifierDeps(vdex_out.get(), nullptr); oat_writer->WriteQuickeningInfo(vdex_out.get()); oat_writer->WriteChecksumsAndVdexHeader(vdex_out.get()); @@ -366,8 +366,7 @@ inline void CompilationHelper::Compile(CompilerDriver* driver, const char* oat_filename = oat_filenames[i].c_str(); std::unique_ptr<File> oat_file(OS::OpenFileReadWrite(oat_filename)); ASSERT_TRUE(oat_file != nullptr); - bool success_fixup = ElfWriter::Fixup(oat_file.get(), - writer->GetOatDataBegin(i)); + bool success_fixup = ElfWriter::Fixup(oat_file.get(), writer->GetOatDataBegin(i)); ASSERT_TRUE(success_fixup); ASSERT_EQ(oat_file->FlushCloseOrErase(), 0) << "Could not flush and close oat file " << oat_filename; @@ -389,7 +388,7 @@ inline void ImageTest::Compile(ImageHeader::StorageMode storage_mode, if (!extra_dex.empty()) { helper.extra_dex_files = OpenTestDexFiles(extra_dex.c_str()); } - helper.Compile(compiler_driver_.get(), storage_mode); + DoCompile(storage_mode, helper); if (image_classes.begin() != image_classes.end()) { // Make sure the class got initialized. ScopedObjectAccess soa(Thread::Current()); @@ -426,9 +425,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 +465,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..bb730d3374 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" @@ -441,7 +442,7 @@ void ImageWriter::PrepareDexCacheArraySlots() { // Prepare dex cache array starts based on the ordering specified in the CompilerDriver. // Set the slot size early to avoid DCHECK() failures in IsImageBinSlotAssigned() // when AssignImageBinSlot() assigns their indexes out or order. - for (const DexFile* dex_file : compiler_driver_.GetDexFilesForOatFile()) { + for (const DexFile* dex_file : compiler_driver_.GetCompilerOptions().GetDexFilesForOatFile()) { auto it = dex_file_oat_index_map_.find(dex_file); DCHECK(it != dex_file_oat_index_map_.end()) << dex_file->GetLocation(); ImageInfo& image_info = GetImageInfo(it->second); @@ -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; } } @@ -1741,7 +1738,7 @@ void ImageWriter::CalculateNewObjectOffsets() { WorkStack work_stack; // Special case interned strings to put them in the image they are likely to be resolved from. - for (const DexFile* dex_file : compiler_driver_.GetDexFilesForOatFile()) { + for (const DexFile* dex_file : compiler_driver_.GetCompilerOptions().GetDexFilesForOatFile()) { auto it = dex_file_oat_index_map_.find(dex_file); DCHECK(it != dex_file_oat_index_map_.end()) << dex_file->GetLocation(); const size_t oat_index = it->second; 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..e8eee88bcd 100644 --- a/dex2oat/linker/oat_writer.h +++ b/dex2oat/linker/oat_writer.h @@ -27,7 +27,6 @@ #include "base/os.h" #include "base/mem_map.h" #include "base/safe_map.h" -#include "compiler.h" #include "debug/debug_info.h" #include "dex/compact_dex_level.h" #include "dex/method_reference.h" @@ -42,6 +41,7 @@ namespace art { class BitVector; class CompiledMethod; class CompilerDriver; +class CompilerOptions; class DexContainer; class ProfileCompilationInfo; class TimingLogger; @@ -63,6 +63,12 @@ class ImageWriter; class MultiOatRelativePatcher; class OutputStream; +enum class CopyOption { + kNever, + kAlways, + kOnlyIfCompressed +}; + // OatHeader variable length with count of D OatDexFiles // // TypeLookupTable[0] one descriptor to class def index hash table for each OatDexFile. @@ -180,17 +186,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 +265,11 @@ class OatWriter { return compiler_driver_; } + const CompilerOptions& GetCompilerOptions() const { + DCHECK(compiler_options_ != nullptr); + return *compiler_options_; + } + private: class DexFileSource; class OatClassHeader; @@ -388,6 +395,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. diff --git a/dex2oat/linker/oat_writer_test.cc b/dex2oat/linker/oat_writer_test.cc index 2bc286a7f4..e43a7f3d0c 100644 --- a/dex2oat/linker/oat_writer_test.cc +++ b/dex2oat/linker/oat_writer_test.cc @@ -409,7 +409,7 @@ TEST_F(OatTest, WriteRead) { jobject class_loader = nullptr; if (kCompile) { TimingLogger timings2("OatTest::WriteRead", false, false); - compiler_driver_->SetDexFilesForOatFile(class_linker->GetBootClassPath()); + SetDexFilesForOatFile(class_linker->GetBootClassPath()); compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), &timings2); } @@ -547,7 +547,7 @@ TEST_F(OatTest, EmptyTextSection) { ScopedObjectAccess soa(Thread::Current()); class_linker->RegisterDexFile(*dex_file, soa.Decode<mirror::ClassLoader>(class_loader)); } - compiler_driver_->SetDexFilesForOatFile(dex_files); + SetDexFilesForOatFile(dex_files); compiler_driver_->CompileAll(class_loader, dex_files, &timings); ScratchFile tmp_base, tmp_oat(tmp_base, ".oat"), tmp_vdex(tmp_base, ".vdex"); diff --git a/libdexfile/dex/dex_file-inl.h b/libdexfile/dex/dex_file-inl.h index f5dd374253..09668594dd 100644 --- a/libdexfile/dex/dex_file-inl.h +++ b/libdexfile/dex/dex_file-inl.h @@ -17,12 +17,14 @@ #ifndef ART_LIBDEXFILE_DEX_DEX_FILE_INL_H_ #define ART_LIBDEXFILE_DEX_DEX_FILE_INL_H_ +#include "dex_file.h" + #include "base/casts.h" #include "base/leb128.h" #include "base/stringpiece.h" #include "class_iterator.h" #include "compact_dex_file.h" -#include "dex_file.h" +#include "dex_instruction_iterator.h" #include "invoke_type.h" #include "standard_dex_file.h" diff --git a/libdexfile/dex/dex_file.h b/libdexfile/dex/dex_file.h index a8cd1871b4..67abdca148 100644 --- a/libdexfile/dex/dex_file.h +++ b/libdexfile/dex/dex_file.h @@ -29,7 +29,6 @@ #include "base/value_object.h" #include "class_iterator.h" #include "dex_file_types.h" -#include "dex_instruction_iterator.h" #include "hidden_api_access_flags.h" #include "jni.h" #include "modifiers.h" @@ -38,6 +37,7 @@ namespace art { class ClassDataItemIterator; class CompactDexFile; +class DexInstructionIterator; enum InvokeType : uint32_t; class MemMap; class OatDexFile; diff --git a/runtime/Android.bp b/runtime/Android.bp index b347019be2..0345c2f4f7 100644 --- a/runtime/Android.bp +++ b/runtime/Android.bp @@ -338,14 +338,10 @@ libart_cc_defaults { "thread_android.cc", ], shared_libs: [ - // For android::FileMap used by libziparchive. - "libutils", "libtombstoned_client", ], static_libs: [ - // ZipArchive support, the order matters here to get all symbols. - "libziparchive", - "libz", + "libz", // For adler32. ], }, android_arm: { @@ -367,8 +363,7 @@ libart_cc_defaults { "thread_linux.cc", ], shared_libs: [ - "libziparchive", - "libz", + "libz", // For adler32. ], }, }, @@ -600,7 +595,6 @@ art_cc_test { ], shared_libs: [ "libbacktrace", - "libziparchive", ], header_libs: [ "art_cmdlineparser_headers", // For parsed_options_test. diff --git a/runtime/base/mutex-inl.h b/runtime/base/mutex-inl.h index dfa14b91f0..51ca274cbb 100644 --- a/runtime/base/mutex-inl.h +++ b/runtime/base/mutex-inl.h @@ -290,10 +290,6 @@ inline ReaderMutexLock::~ReaderMutexLock() { mu_.SharedUnlock(self_); } -// Catch bug where variable name is omitted. "ReaderMutexLock (lock);" instead of -// "ReaderMutexLock mu(lock)". -#define ReaderMutexLock(x) static_assert(0, "ReaderMutexLock declaration missing variable name") - } // namespace art #endif // ART_RUNTIME_BASE_MUTEX_INL_H_ diff --git a/runtime/base/mutex.h b/runtime/base/mutex.h index 602d183bbb..ee47e7ce56 100644 --- a/runtime/base/mutex.h +++ b/runtime/base/mutex.h @@ -525,8 +525,6 @@ class SCOPED_CAPABILITY MutexLock { Mutex& mu_; DISALLOW_COPY_AND_ASSIGN(MutexLock); }; -// Catch bug where variable name is omitted. "MutexLock (lock);" instead of "MutexLock mu(lock)". -#define MutexLock(x) static_assert(0, "MutexLock declaration missing variable name") // Scoped locker/unlocker for a ReaderWriterMutex that acquires read access to mu upon // construction and releases it upon destruction. @@ -560,9 +558,6 @@ class SCOPED_CAPABILITY WriterMutexLock { ReaderWriterMutex& mu_; DISALLOW_COPY_AND_ASSIGN(WriterMutexLock); }; -// Catch bug where variable name is omitted. "WriterMutexLock (lock);" instead of -// "WriterMutexLock mu(lock)". -#define WriterMutexLock(x) static_assert(0, "WriterMutexLock declaration missing variable name") // For StartNoThreadSuspension and EndNoThreadSuspension. class CAPABILITY("role") Role { diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 19554cd44c..7b92ba41a5 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -805,7 +805,7 @@ void ClassLinker::FinishInit(Thread* self) { // Note: we hard code the field indexes here rather than using FindInstanceField // as the types of the field can't be resolved prior to the runtime being // fully initialized - StackHandleScope<2> hs(self); + StackHandleScope<3> hs(self); Handle<mirror::Class> java_lang_ref_Reference = hs.NewHandle(GetClassRoot<mirror::Reference>(this)); Handle<mirror::Class> java_lang_ref_FinalizerReference = @@ -847,6 +847,20 @@ void ClassLinker::FinishInit(Thread* self) { // that Object, Class, and Object[] are setup init_done_ = true; + // Under sanitization, the small carve-out to handle stack overflow might not be enough to + // initialize the StackOverflowError class (as it might require running the verifier). Instead, + // ensure that the class will be initialized. + if (kMemoryToolIsAvailable && !Runtime::Current()->IsAotCompiler()) { + verifier::MethodVerifier::Init(); // Need to prepare the verifier. + + ObjPtr<mirror::Class> soe_klass = FindSystemClass(self, "Ljava/lang/StackOverflowError;"); + if (soe_klass == nullptr || !EnsureInitialized(self, hs.NewHandle(soe_klass), true, true)) { + // Strange, but don't crash. + LOG(WARNING) << "Could not prepare StackOverflowError."; + self->ClearException(); + } + } + VLOG(startup) << "ClassLinker::FinishInit exiting"; } diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc index cbd98800f4..12baede59b 100644 --- a/runtime/gc/collector/concurrent_copying.cc +++ b/runtime/gc/collector/concurrent_copying.cc @@ -2153,10 +2153,12 @@ inline void ConcurrentCopying::Process(mirror::Object* obj, MemberOffset offset) break; } // Use release CAS to make sure threads reading the reference see contents of copied objects. - } while (!obj->CasFieldWeakReleaseObjectWithoutWriteBarrier<false, false, kVerifyNone>( + } while (!obj->CasFieldObjectWithoutWriteBarrier<false, false, kVerifyNone>( offset, expected_ref, - new_ref)); + new_ref, + CASMode::kWeak, + std::memory_order_release)); } // Process some roots. diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc index 8e3bbde224..58becb1d09 100644 --- a/runtime/gc/heap.cc +++ b/runtime/gc/heap.cc @@ -37,7 +37,6 @@ #include "base/systrace.h" #include "base/time_utils.h" #include "common_throws.h" -#include "cutils/sched_policy.h" #include "debugger.h" #include "dex/dex_file-inl.h" #include "entrypoints/quick/quick_alloc_entrypoints.h" diff --git a/runtime/hprof/hprof.cc b/runtime/hprof/hprof.cc index 7bd5a6a68a..c9e8426340 100644 --- a/runtime/hprof/hprof.cc +++ b/runtime/hprof/hprof.cc @@ -24,7 +24,6 @@ #include "hprof.h" -#include <cutils/open_memstream.h> #include <errno.h> #include <fcntl.h> #include <stdio.h> diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc index 6a4cf56e2a..22a6e9d941 100644 --- a/runtime/interpreter/unstarted_runtime.cc +++ b/runtime/interpreter/unstarted_runtime.cc @@ -1485,13 +1485,17 @@ void UnstartedRuntime::UnstartedUnsafeCompareAndSwapObject( bool success; // Check whether we're in a transaction, call accordingly. if (Runtime::Current()->IsActiveTransaction()) { - success = obj->CasFieldStrongSequentiallyConsistentObject<true>(MemberOffset(offset), - expected_value, - newValue); + success = obj->CasFieldObject<true>(MemberOffset(offset), + expected_value, + newValue, + CASMode::kStrong, + std::memory_order_seq_cst); } else { - success = obj->CasFieldStrongSequentiallyConsistentObject<false>(MemberOffset(offset), - expected_value, - newValue); + success = obj->CasFieldObject<false>(MemberOffset(offset), + expected_value, + newValue, + CASMode::kStrong, + std::memory_order_seq_cst); } result->SetZ(success ? 1 : 0); } diff --git a/runtime/jit/profiling_info_test.cc b/runtime/jit/profiling_info_test.cc index 106a80a568..8424610cf8 100644 --- a/runtime/jit/profiling_info_test.cc +++ b/runtime/jit/profiling_info_test.cc @@ -31,7 +31,6 @@ #include "mirror/class_loader.h" #include "profile/profile_compilation_info.h" #include "scoped_thread_state_change-inl.h" -#include "ziparchive/zip_writer.h" namespace art { diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc index 44b0c2b007..26dba024c6 100644 --- a/runtime/mirror/class.cc +++ b/runtime/mirror/class.cc @@ -114,13 +114,17 @@ ClassExt* Class::EnsureExtDataPresent(Thread* self) { bool set; // Set the ext_data_ field using CAS semantics. if (Runtime::Current()->IsActiveTransaction()) { - set = h_this->CasFieldStrongSequentiallyConsistentObject<true>(ext_offset, - ObjPtr<ClassExt>(nullptr), - new_ext.Get()); + set = h_this->CasFieldObject<true>(ext_offset, + nullptr, + new_ext.Get(), + CASMode::kStrong, + std::memory_order_seq_cst); } else { - set = h_this->CasFieldStrongSequentiallyConsistentObject<false>(ext_offset, - ObjPtr<ClassExt>(nullptr), - new_ext.Get()); + set = h_this->CasFieldObject<false>(ext_offset, + nullptr, + new_ext.Get(), + CASMode::kStrong, + std::memory_order_seq_cst); } ObjPtr<ClassExt> ret(set ? new_ext.Get() : h_this->GetExtData()); DCHECK(!set || h_this->GetExtData() == new_ext.Get()); diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h index d94ded0f01..47f0a298de 100644 --- a/runtime/mirror/object-inl.h +++ b/runtime/mirror/object-inl.h @@ -665,22 +665,11 @@ inline HeapReference<Object>* Object::GetFieldObjectReferenceAddr(MemberOffset f } template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags> -inline bool Object::CasFieldWeakSequentiallyConsistentObject(MemberOffset field_offset, - ObjPtr<Object> old_value, - ObjPtr<Object> new_value) { - bool success = CasFieldWeakSequentiallyConsistentObjectWithoutWriteBarrier< - kTransactionActive, kCheckTransaction, kVerifyFlags>(field_offset, old_value, new_value); - if (success) { - WriteBarrier::ForFieldWrite(this, field_offset, new_value); - } - return success; -} - -template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags> -inline bool Object::CasFieldWeakSequentiallyConsistentObjectWithoutWriteBarrier( - MemberOffset field_offset, - ObjPtr<Object> old_value, - ObjPtr<Object> new_value) { +inline bool Object::CasFieldObjectWithoutWriteBarrier(MemberOffset field_offset, + ObjPtr<Object> old_value, + ObjPtr<Object> new_value, + CASMode mode, + std::memory_order memory_order) { VerifyTransaction<kTransactionActive, kCheckTransaction>(); VerifyCAS<kVerifyFlags>(new_value, old_value); if (kTransactionActive) { @@ -690,17 +679,21 @@ inline bool Object::CasFieldWeakSequentiallyConsistentObjectWithoutWriteBarrier( uint32_t new_ref(PtrCompression<kPoisonHeapReferences, Object>::Compress(new_value)); uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value(); Atomic<uint32_t>* atomic_addr = reinterpret_cast<Atomic<uint32_t>*>(raw_addr); - - bool success = atomic_addr->CompareAndSetWeakSequentiallyConsistent(old_ref, new_ref); - return success; + return atomic_addr->CompareAndSet(old_ref, new_ref, mode, memory_order); } template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags> -inline bool Object::CasFieldStrongSequentiallyConsistentObject(MemberOffset field_offset, - ObjPtr<Object> old_value, - ObjPtr<Object> new_value) { - bool success = CasFieldStrongSequentiallyConsistentObjectWithoutWriteBarrier< - kTransactionActive, kCheckTransaction, kVerifyFlags>(field_offset, old_value, new_value); +inline bool Object::CasFieldObject(MemberOffset field_offset, + ObjPtr<Object> old_value, + ObjPtr<Object> new_value, + CASMode mode, + std::memory_order memory_order) { + bool success = CasFieldObjectWithoutWriteBarrier< + kTransactionActive, kCheckTransaction, kVerifyFlags>(field_offset, + old_value, + new_value, + mode, + memory_order); if (success) { WriteBarrier::ForFieldWrite(this, field_offset, new_value); } @@ -708,63 +701,6 @@ inline bool Object::CasFieldStrongSequentiallyConsistentObject(MemberOffset fiel } template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags> -inline bool Object::CasFieldStrongSequentiallyConsistentObjectWithoutWriteBarrier( - MemberOffset field_offset, - ObjPtr<Object> old_value, - ObjPtr<Object> new_value) { - VerifyTransaction<kTransactionActive, kCheckTransaction>(); - VerifyCAS<kVerifyFlags>(new_value, old_value); - if (kTransactionActive) { - Runtime::Current()->RecordWriteFieldReference(this, field_offset, old_value, true); - } - uint32_t old_ref(PtrCompression<kPoisonHeapReferences, Object>::Compress(old_value)); - uint32_t new_ref(PtrCompression<kPoisonHeapReferences, Object>::Compress(new_value)); - uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value(); - Atomic<uint32_t>* atomic_addr = reinterpret_cast<Atomic<uint32_t>*>(raw_addr); - - bool success = atomic_addr->CompareAndSetStrongSequentiallyConsistent(old_ref, new_ref); - return success; -} - -template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags> -inline bool Object::CasFieldWeakRelaxedObjectWithoutWriteBarrier( - MemberOffset field_offset, - ObjPtr<Object> old_value, - ObjPtr<Object> new_value) { - VerifyTransaction<kTransactionActive, kCheckTransaction>(); - VerifyCAS<kVerifyFlags>(new_value, old_value); - if (kTransactionActive) { - Runtime::Current()->RecordWriteFieldReference(this, field_offset, old_value, true); - } - uint32_t old_ref(PtrCompression<kPoisonHeapReferences, Object>::Compress(old_value)); - uint32_t new_ref(PtrCompression<kPoisonHeapReferences, Object>::Compress(new_value)); - uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value(); - Atomic<uint32_t>* atomic_addr = reinterpret_cast<Atomic<uint32_t>*>(raw_addr); - - bool success = atomic_addr->CompareAndSetWeakRelaxed(old_ref, new_ref); - return success; -} - -template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags> -inline bool Object::CasFieldWeakReleaseObjectWithoutWriteBarrier( - MemberOffset field_offset, - ObjPtr<Object> old_value, - ObjPtr<Object> new_value) { - VerifyTransaction<kTransactionActive, kCheckTransaction>(); - VerifyCAS<kVerifyFlags>(new_value, old_value); - if (kTransactionActive) { - Runtime::Current()->RecordWriteFieldReference(this, field_offset, old_value, true); - } - uint32_t old_ref(PtrCompression<kPoisonHeapReferences, Object>::Compress(old_value)); - uint32_t new_ref(PtrCompression<kPoisonHeapReferences, Object>::Compress(new_value)); - uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value(); - Atomic<uint32_t>* atomic_addr = reinterpret_cast<Atomic<uint32_t>*>(raw_addr); - - bool success = atomic_addr->CompareAndSetWeakRelease(old_ref, new_ref); - return success; -} - -template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags> inline ObjPtr<Object> Object::CompareAndExchangeFieldObject(MemberOffset field_offset, ObjPtr<Object> old_value, ObjPtr<Object> new_value) { diff --git a/runtime/mirror/object-readbarrier-inl.h b/runtime/mirror/object-readbarrier-inl.h index 634a83a6a5..df50d0613a 100644 --- a/runtime/mirror/object-readbarrier-inl.h +++ b/runtime/mirror/object-readbarrier-inl.h @@ -193,64 +193,6 @@ inline bool Object::AtomicSetMarkBit(uint32_t expected_mark_bit, uint32_t mark_b return true; } -template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags> -inline bool Object::CasFieldStrongRelaxedObjectWithoutWriteBarrier( - MemberOffset field_offset, - ObjPtr<Object> old_value, - ObjPtr<Object> new_value) { - if (kCheckTransaction) { - DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction()); - } - if (kVerifyFlags & kVerifyThis) { - VerifyObject(this); - } - if (kVerifyFlags & kVerifyWrites) { - VerifyObject(new_value); - } - if (kVerifyFlags & kVerifyReads) { - VerifyObject(old_value); - } - if (kTransactionActive) { - Runtime::Current()->RecordWriteFieldReference(this, field_offset, old_value, true); - } - uint32_t old_ref(PtrCompression<kPoisonHeapReferences, Object>::Compress(old_value)); - uint32_t new_ref(PtrCompression<kPoisonHeapReferences, Object>::Compress(new_value)); - uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value(); - Atomic<uint32_t>* atomic_addr = reinterpret_cast<Atomic<uint32_t>*>(raw_addr); - - bool success = atomic_addr->CompareAndSetStrongRelaxed(old_ref, new_ref); - return success; -} - -template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags> -inline bool Object::CasFieldStrongReleaseObjectWithoutWriteBarrier( - MemberOffset field_offset, - ObjPtr<Object> old_value, - ObjPtr<Object> new_value) { - if (kCheckTransaction) { - DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction()); - } - if (kVerifyFlags & kVerifyThis) { - VerifyObject(this); - } - if (kVerifyFlags & kVerifyWrites) { - VerifyObject(new_value); - } - if (kVerifyFlags & kVerifyReads) { - VerifyObject(old_value); - } - if (kTransactionActive) { - Runtime::Current()->RecordWriteFieldReference(this, field_offset, old_value, true); - } - uint32_t old_ref(PtrCompression<kPoisonHeapReferences, Object>::Compress(old_value)); - uint32_t new_ref(PtrCompression<kPoisonHeapReferences, Object>::Compress(new_value)); - uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value(); - Atomic<uint32_t>* atomic_addr = reinterpret_cast<Atomic<uint32_t>*>(raw_addr); - - bool success = atomic_addr->CompareAndSetStrongRelease(old_ref, new_ref); - return success; -} - } // namespace mirror } // namespace art diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h index e19b524ef3..c7cffed69b 100644 --- a/runtime/mirror/object.h +++ b/runtime/mirror/object.h @@ -315,30 +315,20 @@ class MANAGED LOCKABLE Object { template<bool kTransactionActive, bool kCheckTransaction = true, VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> - bool CasFieldWeakSequentiallyConsistentObject(MemberOffset field_offset, - ObjPtr<Object> old_value, - ObjPtr<Object> new_value) + ALWAYS_INLINE bool CasFieldObject(MemberOffset field_offset, + ObjPtr<Object> old_value, + ObjPtr<Object> new_value, + CASMode mode, + std::memory_order memory_order) REQUIRES_SHARED(Locks::mutator_lock_); template<bool kTransactionActive, bool kCheckTransaction = true, VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> - bool CasFieldWeakSequentiallyConsistentObjectWithoutWriteBarrier(MemberOffset field_offset, - ObjPtr<Object> old_value, - ObjPtr<Object> new_value) - REQUIRES_SHARED(Locks::mutator_lock_); - template<bool kTransactionActive, - bool kCheckTransaction = true, - VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> - bool CasFieldStrongSequentiallyConsistentObject(MemberOffset field_offset, - ObjPtr<Object> old_value, - ObjPtr<Object> new_value) - REQUIRES_SHARED(Locks::mutator_lock_); - template<bool kTransactionActive, - bool kCheckTransaction = true, - VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> - bool CasFieldStrongSequentiallyConsistentObjectWithoutWriteBarrier(MemberOffset field_offset, - ObjPtr<Object> old_value, - ObjPtr<Object> new_value) + ALWAYS_INLINE bool CasFieldObjectWithoutWriteBarrier(MemberOffset field_offset, + ObjPtr<Object> old_value, + ObjPtr<Object> new_value, + CASMode mode, + std::memory_order memory_order) REQUIRES_SHARED(Locks::mutator_lock_); template<bool kTransactionActive, @@ -355,36 +345,6 @@ class MANAGED LOCKABLE Object { ObjPtr<Object> ExchangeFieldObject(MemberOffset field_offset, ObjPtr<Object> new_value) REQUIRES_SHARED(Locks::mutator_lock_); - template<bool kTransactionActive, - bool kCheckTransaction = true, - VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> - bool CasFieldWeakRelaxedObjectWithoutWriteBarrier(MemberOffset field_offset, - ObjPtr<Object> old_value, - ObjPtr<Object> new_value) - REQUIRES_SHARED(Locks::mutator_lock_); - template<bool kTransactionActive, - bool kCheckTransaction = true, - VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> - bool CasFieldWeakReleaseObjectWithoutWriteBarrier(MemberOffset field_offset, - ObjPtr<Object> old_value, - ObjPtr<Object> new_value) - REQUIRES_SHARED(Locks::mutator_lock_); - - template<bool kTransactionActive, - bool kCheckTransaction = true, - VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> - bool CasFieldStrongRelaxedObjectWithoutWriteBarrier(MemberOffset field_offset, - ObjPtr<Object> old_value, - ObjPtr<Object> new_value) - REQUIRES_SHARED(Locks::mutator_lock_); - template<bool kTransactionActive, - bool kCheckTransaction = true, - VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> - bool CasFieldStrongReleaseObjectWithoutWriteBarrier(MemberOffset field_offset, - ObjPtr<Object> old_value, - ObjPtr<Object> new_value) - REQUIRES_SHARED(Locks::mutator_lock_); - template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> HeapReference<Object>* GetFieldObjectReferenceAddr(MemberOffset field_offset) REQUIRES_SHARED(Locks::mutator_lock_); diff --git a/runtime/mirror/var_handle.cc b/runtime/mirror/var_handle.cc index 4319c5df25..56c953b816 100644 --- a/runtime/mirror/var_handle.cc +++ b/runtime/mirror/var_handle.cc @@ -1021,15 +1021,17 @@ bool FieldAccessor<ObjPtr<Object>>::Dispatch(VarHandle::AccessMode access_mode, ObjPtr<Object> desired_value = ValueGetter<ObjPtr<Object>>::Get(getter); bool cas_result; if (Runtime::Current()->IsActiveTransaction()) { - cas_result = obj->CasFieldStrongSequentiallyConsistentObject<kTransactionActive>( - field_offset, - expected_value, - desired_value); + cas_result = obj->CasFieldObject<kTransactionActive>(field_offset, + expected_value, + desired_value, + CASMode::kStrong, + std::memory_order_seq_cst); } else { - cas_result = obj->CasFieldStrongSequentiallyConsistentObject<kTransactionInactive>( - field_offset, - expected_value, - desired_value); + cas_result = obj->CasFieldObject<kTransactionInactive>(field_offset, + expected_value, + desired_value, + CASMode::kStrong, + std::memory_order_seq_cst); } StoreResult(cas_result, result); break; @@ -1043,15 +1045,18 @@ bool FieldAccessor<ObjPtr<Object>>::Dispatch(VarHandle::AccessMode access_mode, ObjPtr<Object> desired_value = ValueGetter<ObjPtr<Object>>::Get(getter); bool cas_result; if (Runtime::Current()->IsActiveTransaction()) { - cas_result = obj->CasFieldWeakSequentiallyConsistentObject<kTransactionActive>( - field_offset, - expected_value, - desired_value); + cas_result = obj->CasFieldObject<kTransactionActive>(field_offset, + expected_value, + desired_value, + CASMode::kWeak, + std::memory_order_seq_cst); } else { - cas_result = obj->CasFieldWeakSequentiallyConsistentObject<kTransactionInactive>( + cas_result = obj->CasFieldObject<kTransactionInactive>( field_offset, expected_value, - desired_value); + desired_value, + CASMode::kWeak, + std::memory_order_seq_cst); } StoreResult(cas_result, result); break; @@ -1064,15 +1069,13 @@ bool FieldAccessor<ObjPtr<Object>>::Dispatch(VarHandle::AccessMode access_mode, ObjPtr<Object> desired_value = ValueGetter<ObjPtr<Object>>::Get(getter); ObjPtr<Object> witness_value; if (Runtime::Current()->IsActiveTransaction()) { - witness_value = obj->CompareAndExchangeFieldObject<kTransactionActive>( - field_offset, - expected_value, - desired_value); + witness_value = obj->CompareAndExchangeFieldObject<kTransactionActive>(field_offset, + expected_value, + desired_value); } else { - witness_value = obj->CompareAndExchangeFieldObject<kTransactionInactive>( - field_offset, - expected_value, - desired_value); + witness_value = obj->CompareAndExchangeFieldObject<kTransactionInactive>(field_offset, + expected_value, + desired_value); } StoreResult(witness_value, result); break; diff --git a/runtime/native/sun_misc_Unsafe.cc b/runtime/native/sun_misc_Unsafe.cc index 0f474d3c9d..46444808d7 100644 --- a/runtime/native/sun_misc_Unsafe.cc +++ b/runtime/native/sun_misc_Unsafe.cc @@ -80,9 +80,11 @@ static jboolean Unsafe_compareAndSwapObject(JNIEnv* env, jobject, jobject javaOb MemberOffset(offset), field_addr); } - bool success = obj->CasFieldStrongSequentiallyConsistentObject<false>(MemberOffset(offset), - expectedValue, - newValue); + bool success = obj->CasFieldObject<false>(MemberOffset(offset), + expectedValue, + newValue, + CASMode::kStrong, + std::memory_order_seq_cst); return success ? JNI_TRUE : JNI_FALSE; } diff --git a/runtime/read_barrier-inl.h b/runtime/read_barrier-inl.h index 5035ba077c..640fa7e393 100644 --- a/runtime/read_barrier-inl.h +++ b/runtime/read_barrier-inl.h @@ -64,8 +64,11 @@ inline MirrorType* ReadBarrier::Barrier( // If kAlwaysUpdateField is true, update the field atomically. This may fail if mutator // updates before us, but it's OK. if (kAlwaysUpdateField && ref != old_ref) { - obj->CasFieldStrongReleaseObjectWithoutWriteBarrier<false, false>( - offset, old_ref, ref); + obj->CasFieldObjectWithoutWriteBarrier<false, false>(offset, + old_ref, + ref, + CASMode::kStrong, + std::memory_order_release); } } AssertToSpaceInvariant(obj, offset, ref); @@ -82,8 +85,11 @@ inline MirrorType* ReadBarrier::Barrier( ref = reinterpret_cast<MirrorType*>(Mark(old_ref)); // Update the field atomically. This may fail if mutator updates before us, but it's ok. if (ref != old_ref) { - obj->CasFieldStrongReleaseObjectWithoutWriteBarrier<false, false>( - offset, old_ref, ref); + obj->CasFieldObjectWithoutWriteBarrier<false, false>(offset, + old_ref, + ref, + CASMode::kStrong, + std::memory_order_release); } } AssertToSpaceInvariant(obj, offset, ref); diff --git a/runtime/thread.cc b/runtime/thread.cc index 3c5569fe05..1a078d5fe6 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -1579,7 +1579,7 @@ void Thread::FullSuspendCheck() { VLOG(threads) << this << " self-suspending"; // Make thread appear suspended to other threads, release mutator_lock_. // Transition to suspended and back to runnable, re-acquire share on mutator_lock_. - ScopedThreadSuspension(this, kSuspended); + ScopedThreadSuspension(this, kSuspended); // NOLINT VLOG(threads) << this << " self-reviving"; } diff --git a/test/003-omnibus-opcodes/build b/test/003-omnibus-opcodes/build index 4d3fb37d1d..c2e611259b 100644 --- a/test/003-omnibus-opcodes/build +++ b/test/003-omnibus-opcodes/build @@ -17,12 +17,20 @@ # Stop if something fails. set -e -mkdir classes -${JAVAC} -d classes `find src -name '*.java'` -rm classes/UnresClass.class -${JAVAC} -d classes `find src2 -name '*.java'` +export ORIGINAL_JAVAC="$JAVAC" -if [ ${NEED_DEX} = "true" ]; then - ${DX} -JXmx256m --debug --dex --output=classes.dex classes - zip $TEST_NAME.jar classes.dex -fi +# Wrapper function for javac which invokes the compiler and applies +# additional setup steps for the test. +function javac_wrapper { + set -e # Stop on error - the caller script may not have this set. + + $ORIGINAL_JAVAC "$@" + rm -f classes/UnresClass.class +} + +export -f javac_wrapper +export JAVAC=javac_wrapper + +###################################################################### + +./default-build "$@" diff --git a/test/004-JniTest/build b/test/004-JniTest/build index e563d734c2..a786b8bc62 100755 --- a/test/004-JniTest/build +++ b/test/004-JniTest/build @@ -23,16 +23,18 @@ # This enables the test to compile with vanilla RI javac and work on either ART or RI. # +# Stop on failure. +set -e + export ORIGINAL_JAVAC="$JAVAC" -# Delete CriticalNative.java, FastNative.java annotations after building the .class files. +# Wrapper function for javac which invokes the compiler and applies +# additional setup steps for the test. function javac_wrapper { + set -e # Stop on error - the caller script may not have this set. $ORIGINAL_JAVAC "$@" - local stat=$? - - [[ -d classes ]] && (find classes/dalvik -name '*.class' | xargs rm -rf) - - return $stat + # Delete CriticalNative.java, FastNative.java annotations after building the .class files. + find classes/dalvik -name '*.class' -exec rm {} \; } export -f javac_wrapper @@ -40,28 +42,6 @@ export JAVAC=javac_wrapper ###################################################################### -# Use the original dx with no extra magic or pessimizing flags. -# This ensures that any default optimizations that dx do would not break JNI. - -export ORIGINAL_DX="$DX" - -# Filter out --debug flag from dx. -function dx_wrapper { - local args=("$@") - local args_filtered=() - for i in "${args[@]}"; do - case "$i" in - --debug) - ;; - *) - args_filtered+=("$i") - ;; - esac - done - "$ORIGINAL_DX" "${args_filtered[@]}" -} - -export -f dx_wrapper -export DX=dx_wrapper - +# Use release mode to check optimizations do not break JNI. +export D8_FLAGS=--release ./default-build "$@" diff --git a/test/004-ReferenceMap/build b/test/004-ReferenceMap/build index 3bb63ca624..d928cd7daf 100644 --- a/test/004-ReferenceMap/build +++ b/test/004-ReferenceMap/build @@ -17,9 +17,26 @@ # Stop if something fails. set -e -# The test relies on DEX file produced by javac+dx so keep building with them for now -# (see b/19467889) -mkdir classes -${JAVAC} -d classes `find src -name '*.java'` -${DX} -JXmx256m --debug --dex --output=classes.dex ${DX_FLAGS} classes -zip $TEST_NAME.jar classes.dex +# This test depends on the exact format of the DEX file. Since dx is deprecated, +# the classes.dex file is packaged as a test input. It was created with: +# +# $ javac -g -Xlint:-options -source 1.7 -target 1.7 -d classes src/Main.java +# $ dx --debug --dex --output=classes.dex classes + +# Wrapper function for javac which for this test does nothing as the +# test uses a pre-built DEX file. +function javac_wrapper { + # Nothing to compile, using dx generated classes.dex. + return 0 +} + +export -f javac_wrapper +export JAVAC=javac_wrapper + +# Do not invoke D8 for this test. +export D8=':' + +###################################################################### + +jar -cf classes.jar classes.dex +./default-build "$@" diff --git a/test/004-ReferenceMap/classes.dex b/test/004-ReferenceMap/classes.dex Binary files differnew file mode 100644 index 0000000000..993c077e43 --- /dev/null +++ b/test/004-ReferenceMap/classes.dex diff --git a/test/004-StackWalk/build b/test/004-StackWalk/build index 3bb63ca624..eeecbfcc40 100644 --- a/test/004-StackWalk/build +++ b/test/004-StackWalk/build @@ -17,9 +17,25 @@ # Stop if something fails. set -e -# The test relies on DEX file produced by javac+dx so keep building with them for now -# (see b/19467889) -mkdir classes -${JAVAC} -d classes `find src -name '*.java'` -${DX} -JXmx256m --debug --dex --output=classes.dex ${DX_FLAGS} classes -zip $TEST_NAME.jar classes.dex +# This test depends on the exact format of the DEX file. Since dx is deprecated, +# the classes.dex file is packaged as a test input. It was created with: +# +# $ javac -g -Xlint:-options -source 1.7 -target 1.7 -d classes src/Main.java +# $ dx --debug --dex --output=classes.dex classes + +# Wrapper function for javac which for this test does nothing as the +# test uses a pre-built DEX file. +function javac_wrapper { + return 0 +} + +export -f javac_wrapper +export JAVAC=javac_wrapper + +# Do not invoke D8 for this test. +export D8=':' + +###################################################################### + +jar -cf classes.jar classes.dex +./default-build "$@" diff --git a/test/004-StackWalk/classes.dex b/test/004-StackWalk/classes.dex Binary files differnew file mode 100644 index 0000000000..ad452960c3 --- /dev/null +++ b/test/004-StackWalk/classes.dex diff --git a/test/005-annotations/build b/test/005-annotations/build index 8eb07a9bf5..5342eea4c4 100644 --- a/test/005-annotations/build +++ b/test/005-annotations/build @@ -17,18 +17,28 @@ # Stop if something fails. set -e -mkdir classes +export ORIGINAL_JAVAC="$JAVAC" -# android.test.anno.MissingAnnotation is available at compile time... -${JAVAC} -d classes `find src -name '*.java'` -# overwrite RenamedEnum -${JAVAC} -d classes `find src2 -name '*.java'` +# Wrapper function for javac which invokes the compiler and applies +# additional setup steps for the test. +function javac_wrapper { + set -e # Stop on error - the caller script may not have this set. -# ...but not at run time. -rm 'classes/android/test/anno/MissingAnnotation.class' -rm 'classes/android/test/anno/ClassWithInnerAnnotationClass$MissingInnerAnnotationClass.class' + $ORIGINAL_JAVAC "$@" -if [ ${NEED_DEX} = "true" ]; then - ${DX} -JXmx256m --debug --dex --output=classes.dex classes - zip $TEST_NAME.jar classes.dex -fi + # Classes available at compile time, but not at runtime. + rm -f classes/android/test/anno/MissingAnnotation.class + rm -f 'classes/android/test/anno/ClassWithInnerAnnotationClass$MissingInnerAnnotationClass.class' + + # overwrite RenamedEnum in classes + if [ -f classes2/android/test/anno/RenamedEnumClass.java ] ; then + mv classes2/android/test/anno/RenamedEnumClass.java classes/android/test/anno/RenamedEnumClass.java + fi +} + +export -f javac_wrapper +export JAVAC=javac_wrapper + +###################################################################### + +./default-build "$@" diff --git a/test/056-const-string-jumbo/build b/test/056-const-string-jumbo/build index 47641d5891..c1d711b436 100644 --- a/test/056-const-string-jumbo/build +++ b/test/056-const-string-jumbo/build @@ -39,10 +39,4 @@ function writeFile(name, start, end) { printf("}\n") > fileName; }' -mkdir classes -${JAVAC} -d classes src/*.java - -if [ ${NEED_DEX} = "true" ]; then - ${DX} -JXmx500m --debug --dex --no-optimize --positions=none --no-locals --output=classes.dex classes - zip $TEST_NAME.jar classes.dex -fi +./default-build "$@" diff --git a/test/442-checker-constant-folding/build b/test/066-mismatched-super/build index 42b99ad9f8..c1c9ed304e 100755..100644 --- a/test/442-checker-constant-folding/build +++ b/test/066-mismatched-super/build @@ -1,6 +1,6 @@ #!/bin/bash # -# Copyright 2017 The Android Open Source Project +# Copyright 2018 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -14,7 +14,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -# See b/65168732 -export DX=$ANDROID_HOST_OUT/bin/dx - -./default-build "$@" +DESUGAR=false ./default-build "$@" diff --git a/test/089-many-methods/build b/test/089-many-methods/build index ff77c60f64..5b4cda87c1 100644 --- a/test/089-many-methods/build +++ b/test/089-many-methods/build @@ -43,8 +43,9 @@ function writeFileMethod(name) { printf("}\n") > fileName; }' -# The test relies on the error message produced by dx, not jack, so keep building with dx for now -# (b/19467889). -mkdir classes -${JAVAC} -d classes `find src -name '*.java'` -${DX} -JXmx1024m --dex --no-optimize classes +# Force DEX generation so test also passes with --jvm. +export NEED_DEX=true + +# Specify old API level as d8 automagically produces a multidex file +# when the API level is above 20. Failing the build here is deliberate. +./default-build --api-level 20 "$@" diff --git a/test/089-many-methods/check b/test/089-many-methods/check index 65b71397b8..1f71e8e0a0 100755 --- a/test/089-many-methods/check +++ b/test/089-many-methods/check @@ -14,7 +14,5 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Strip build error debug messages, as they are environment-specific. -sed -e '/^Failed to build/d' -e '/^Non-canonical tmpdir/d' -e '/^Args:/d' -e '/^Max filename/d' -e '/^Max pathlength/d' "$2" > "$2.tmp" - -diff --strip-trailing-cr -q "$1" "$2.tmp" >/dev/null
\ No newline at end of file +grep Error "$2" > "$2.tmp" +diff --strip-trailing-cr -q "$1" "$2.tmp" >/dev/null diff --git a/test/089-many-methods/expected.txt b/test/089-many-methods/expected.txt index 786df7c76d..bb6ba3c7bc 100644 --- a/test/089-many-methods/expected.txt +++ b/test/089-many-methods/expected.txt @@ -1,6 +1 @@ - -trouble writing output: Too many field references to fit in one dex file: 131000; max is 65536. -You may try using multi-dex. If multi-dex is enabled then the list of classes for the main dex list is too large. -References by package: -131000 default -build exit status: 2 +Error: Cannot fit requested classes in a single dex file (# fields: 131000 > 65536) diff --git a/test/091-override-package-private-method/build b/test/091-override-package-private-method/build index e5fa6693a3..8257d92156 100755 --- a/test/091-override-package-private-method/build +++ b/test/091-override-package-private-method/build @@ -17,15 +17,20 @@ # Stop if something fails. set -e -mkdir classes -${JAVAC} -d classes `find src -name '*.java'` +export ORIGINAL_JAVAC="$JAVAC" -mkdir classes-ex -mv classes/OverridePackagePrivateMethodSuper.class classes-ex +# Wrapper function for javac which invokes the compiler and applies +# additional setup steps for the test. +function javac_wrapper { + set -e # Stop on error - the caller script may not have this set. + $ORIGINAL_JAVAC "$@" + mkdir -p classes-ex + mv classes/OverridePackagePrivateMethodSuper.class classes-ex +} -if [ ${NEED_DEX} = "true" ]; then - ${DX} -JXmx256m --debug --dex --output=classes.dex classes - zip $TEST_NAME.jar classes.dex - ${DX} -JXmx256m --debug --dex --output=classes.dex classes-ex - zip ${TEST_NAME}-ex.jar classes.dex -fi +export -f javac_wrapper +export JAVAC=javac_wrapper + +###################################################################### + +./default-build "$@" diff --git a/test/111-unresolvable-exception/build b/test/111-unresolvable-exception/build index f24c5b2004..1c275aa2fe 100644 --- a/test/111-unresolvable-exception/build +++ b/test/111-unresolvable-exception/build @@ -17,11 +17,22 @@ # Stop if something fails. set -e -mkdir classes -${JAVAC} -d classes `find src -name '*.java'` -rm classes/TestException.class - -if [ ${NEED_DEX} = "true" ]; then - ${DX} -JXmx256m --debug --dex --output=classes.dex classes - zip $TEST_NAME.jar classes.dex -fi +export ORIGINAL_JAVAC="$JAVAC" + +# Wrapper function for javac which invokes the compiler and applies +# additional setup steps for the test. +function javac_wrapper { + set -e # Stop on error - the caller script may not have this set. + + $ORIGINAL_JAVAC "$@" + + # Remove class available at compile time but not at run time. + rm classes/TestException.class +} + +export -f javac_wrapper +export JAVAC=javac_wrapper + +###################################################################### + +./default-build "$@" diff --git a/test/113-multidex/build b/test/113-multidex/build deleted file mode 100644 index 4ad7cb9134..0000000000 --- a/test/113-multidex/build +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/bash -# -# Copyright (C) 2014 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Stop if something fails. -set -e - -# All except Main -mkdir classes -${JAVAC} -d classes `find src -name '*.java'` -rm classes/Main.class - -# Only Main -mkdir classes2 -${JAVAC} -d classes2 `find src -name '*.java'` -rm classes2/Second.class classes2/FillerA.class classes2/FillerB.class classes2/Inf*.class - -if [ ${NEED_DEX} = "true" ]; then - # All except Main - ${DX} -JXmx256m --debug --dex --output=classes.dex classes - - # Only Main - ${DX} -JXmx256m --debug --dex --output=classes2.dex classes2 - zip $TEST_NAME.jar classes.dex classes2.dex -fi diff --git a/test/113-multidex/src/Main.java b/test/113-multidex/src-multidex/Main.java index 1c74220525..1c74220525 100644 --- a/test/113-multidex/src/Main.java +++ b/test/113-multidex/src-multidex/Main.java diff --git a/test/124-missing-classes/build b/test/124-missing-classes/build index b13aa6e851..ec4ec84e09 100644 --- a/test/124-missing-classes/build +++ b/test/124-missing-classes/build @@ -17,16 +17,24 @@ # Stop if something fails. set -e -mkdir classes +export ORIGINAL_JAVAC="$JAVAC" -# Some classes are available at compile time... -${JAVAC} -d classes `find src -name '*.java'` +# Wrapper function for javac which invokes the compiler and applies +# additional setup steps for the test. -# ...but not at run time. -rm 'classes/MissingClass.class' -rm 'classes/Main$MissingInnerClass.class' +function javac_wrapper { + set -e # Stop on error - the caller script may not have this set. -if [ ${NEED_DEX} = "true" ]; then - ${DX} -JXmx256m --debug --dex --output=classes.dex classes - zip $TEST_NAME.jar classes.dex -fi + # Some classes are available at compile time... + $ORIGINAL_JAVAC "$@" + + # ...but not at run time. + rm 'classes/MissingClass.class' 'classes/Main$MissingInnerClass.class' +} + +export -f javac_wrapper +export JAVAC=javac_wrapper + +###################################################################### + +./default-build "$@" diff --git a/test/126-miranda-multidex/build b/test/126-miranda-multidex/build index b4bb88d644..7b44863fa9 100644 --- a/test/126-miranda-multidex/build +++ b/test/126-miranda-multidex/build @@ -17,21 +17,30 @@ # Stop if something fails. set -e -# All except MirandaInterface -mkdir classes -${JAVAC} -d classes `find src -name '*.java'` -rm classes/MirandaInterface.class +export ORIGINAL_JAVAC="$JAVAC" -# Only MirandaInterface -mkdir classes2 -${JAVAC} -d classes2 `find src -name '*.java'` -rm classes2/Main.class classes2/MirandaAbstract.class classes2/MirandaClass*.class classes2/MirandaInterface2*.class +# Wrapper function for javac which invokes the compiler and applies +# additional setup steps for the test. +function javac_wrapper { + set -e # Stop on error - the caller script may not have this set. -if [ ${NEED_DEX} = "true" ]; then - # All except Main - ${DX} -JXmx256m --debug --dex --output=classes.dex classes + if [[ "$*" != *"classes2"* ]]; then + # First invocation: compile src/ files. + $ORIGINAL_JAVAC "$@" + else + # Second invocation: move MirandaInterface.class for placement in + # a secondary dex file. There are no other source files for the + # secondary DEX so no compilation required. + mv classes/MirandaInterface.class classes2 + fi + return $? +} - # Only Main - ${DX} -JXmx256m --debug --dex --output=classes2.dex classes2 - zip $TEST_NAME.jar classes.dex classes2.dex -fi +export -f javac_wrapper +export JAVAC=javac_wrapper + +###################################################################### + +# Signal to default-build that this is a multidex test. +mkdir src-multidex +./default-build "$@" diff --git a/test/127-checker-secondarydex/build b/test/127-checker-secondarydex/build index c23b7613b9..3135681eec 100755 --- a/test/127-checker-secondarydex/build +++ b/test/127-checker-secondarydex/build @@ -17,15 +17,22 @@ # Stop if something fails. set -e -mkdir classes -${JAVAC} -d classes `find src -name '*.java'` - -mkdir classes-ex -mv classes/Super.class classes-ex - -if [ ${NEED_DEX} = "true" ]; then - ${DX} -JXmx256m --debug --dex --output=classes.dex classes - zip $TEST_NAME.jar classes.dex - ${DX} -JXmx256m --debug --dex --output=classes.dex classes-ex - zip ${TEST_NAME}-ex.jar classes.dex -fi +export ORIGINAL_JAVAC="$JAVAC" + +# Wrapper function for javac which invokes the compiler and applies +# additional setup steps for the test. +function javac_wrapper { + set -e # Stop on error - the caller script may not have this set. + + $ORIGINAL_JAVAC "$@" + + mkdir classes-ex + mv classes/Super.class classes-ex +} + +export -f javac_wrapper +export JAVAC=javac_wrapper + +###################################################################### + +./default-build "$@" diff --git a/test/138-duplicate-classes-check2/build b/test/138-duplicate-classes-check2/build index 3ff15aae38..4ab7320699 100755 --- a/test/138-duplicate-classes-check2/build +++ b/test/138-duplicate-classes-check2/build @@ -17,16 +17,22 @@ # Stop if something fails. set -e -mkdir classes -${JAVAC} -d classes `find src -name '*.java'` - -mkdir classes-ex -${JAVAC} -d classes-ex `find src-ex -name '*.java'` -rm classes-ex/A.class - -if [ ${NEED_DEX} = "true" ]; then - ${DX} -JXmx256m --debug --dex --output=classes.dex classes - zip ${TEST_NAME}.jar classes.dex - ${DX} -JXmx256m --debug --dex --output=classes.dex classes-ex - zip ${TEST_NAME}-ex.jar classes.dex -fi +export ORIGINAL_JAVAC="$JAVAC" + +# Wrapper function for javac which invokes the compiler and applies +# additional setup steps for the test. +function javac_wrapper { + set -e # Stop on error - the caller script may not have this set. + + $ORIGINAL_JAVAC "$@" + + # Remove one A.class from classes-ex + rm -f classes-ex/A.class +} + +export -f javac_wrapper +export JAVAC=javac_wrapper + +###################################################################### + +./default-build "$@" diff --git a/test/1948-obsolete-const-method-handle/build b/test/1948-obsolete-const-method-handle/build index ac0dcd97b8..d0e7a8c0d8 100644 --- a/test/1948-obsolete-const-method-handle/build +++ b/test/1948-obsolete-const-method-handle/build @@ -20,6 +20,4 @@ set -e mkdir classes ./util-src/build-classes $PWD/classes -${DX} --dex --min-sdk-version=28 --output=classes.dex classes - -zip $TEST_NAME.jar classes.dex +./default-build --api-level 28 "$@" diff --git a/test/303-verification-stress/build b/test/303-verification-stress/build index ba79541478..87a4a851d7 100644 --- a/test/303-verification-stress/build +++ b/test/303-verification-stress/build @@ -21,11 +21,4 @@ set -e gcc -Wall -Werror -o classes-gen classes-gen.c ./classes-gen -mkdir classes -${JAVAC} -d classes src/*.java - -# dx needs more memory for that test so do not pass Xmx option here. -if [ ${NEED_DEX} = "true" ]; then - ${DX} --debug --dex --output=classes.dex classes - zip $TEST_NAME.jar classes.dex -fi +./default-build "$@" diff --git a/test/638-no-line-number/build b/test/638-no-line-number/build index 7eaf50e938..9cd19554bc 100644 --- a/test/638-no-line-number/build +++ b/test/638-no-line-number/build @@ -17,9 +17,6 @@ # Stop if something fails. set -e -mkdir classes # Only keep the source name, to make sure we do remove it in the stack trace # when there is no line number mapping. -${JAVAC} -g:source -source 7 -target 7 -d classes `find src -name '*.java'` -${DX} --dex --output=classes.dex classes -zip $TEST_NAME.jar classes.dex +JAVAC_ARGS="$JAVAC_ARGS -g:source" ./default-build "$@" diff --git a/test/638-no-line-number/expected.txt b/test/638-no-line-number/expected.txt index ffde15312b..4b351f4bf9 100644 --- a/test/638-no-line-number/expected.txt +++ b/test/638-no-line-number/expected.txt @@ -2,4 +2,4 @@ java.lang.Error at Main.main(Unknown Source:2) java.lang.NullPointerException: throw with null exception at Main.doThrow(Unknown Source:0) - at Main.main(Unknown Source:9) + at Main.main(Unknown Source:16) diff --git a/test/712-varhandle-invocations/build b/test/712-varhandle-invocations/build index 253765be91..9a6e96e18b 100755 --- a/test/712-varhandle-invocations/build +++ b/test/712-varhandle-invocations/build @@ -32,8 +32,4 @@ MANUAL_TESTS=$(cd "${MANUAL_SRC}" && find . -name 'Var*Tests.java' | sed -e 's@. # Generate tests and Main that covers both the generated tests and manual tests python3 ./util-src/generate_java.py "${GENERATED_SRC}" ${MANUAL_TESTS} -# Desugar is not happy with our Java 9 byte code, it shouldn't be necessary here anyway. -export USE_DESUGAR=false - -# Invoke default build with increased heap size for dx -./default-build "$@" --experimental var-handles --dx-vm-option -JXmx384m +./default-build "$@" --experimental var-handles diff --git a/test/715-clinit-implicit-parameter-annotations/build b/test/715-clinit-implicit-parameter-annotations/build index 4753c8c7dc..2b5f92cc88 100644 --- a/test/715-clinit-implicit-parameter-annotations/build +++ b/test/715-clinit-implicit-parameter-annotations/build @@ -17,8 +17,4 @@ # Make us exit on a failure set -e -# Always use D8 as DX does not support propagating parameter name and -# access_flag information. -export USE_D8=true - ./default-build "$@" --experimental parameter-annotations diff --git a/test/022-interface/build b/test/804-class-extends-itself/build index ab1c822ebf..71cb3cacdc 100644 --- a/test/022-interface/build +++ b/test/804-class-extends-itself/build @@ -1,12 +1,12 @@ #!/bin/bash # -# Copyright (C) 2012 The Android Open Source Project +# Copyright 2018 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, @@ -14,9 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Stop if something fails. -set -e - -${DX} --debug --dex --output=classes.dex classes - -zip $TEST_NAME.jar classes.dex +# Use old API level to create DEX file with 035 version. Stricter +# checking introduced with DEX file version 37 rejects class +# otherwise (see DexFile::kClassDefinitionOrderEnforcedVersion). +./default-build "$@" --api-level 13 diff --git a/test/952-invoke-custom/build b/test/952-invoke-custom/build index 53d8228808..a70fc20c05 100755 --- a/test/952-invoke-custom/build +++ b/test/952-invoke-custom/build @@ -14,34 +14,60 @@ # See the License for the specific language governing permissions and # limitations under the License. -# make us exit on a failure +# Stop on failure. set -e -ASM_JAR="${ANDROID_BUILD_TOP}/prebuilts/misc/common/asm/asm-6.0.jar" -INTERMEDIATE_CLASSES=classes-intermediate -CLASSES=classes +export ASM_JAR="${ANDROID_BUILD_TOP}/prebuilts/misc/common/asm/asm-6.0.jar" -# Create directory for intermediate classes -rm -rf "${INTERMEDIATE_CLASSES}" -mkdir "${INTERMEDIATE_CLASSES}" +export ORIGINAL_JAVAC="$JAVAC" -# Generate intermediate classes that will allow transform to be applied to test classes -JAVAC_ARGS="${JAVAC_ARGS} -source 1.8 -target 1.8 -cp ${ASM_JAR}" -${JAVAC:-javac} ${JAVAC_ARGS} -d ${INTERMEDIATE_CLASSES} $(find src -name '*.java') +# Wrapper function for javac which invokes the compiler and applies +# transforms to class files after compilation. +function javac_wrapper { + set -e # Stop on error - the caller script may not have this set. -# Create directory for transformed classes -rm -rf "${CLASSES}" -mkdir "${CLASSES}" + # Update arguments to add transformer and ASM to the compiler classpath. + local args=() + local classpath="./transformer.jar:$ASM_JAR" + while [ $# -ne 0 ] ; do + case $1 in + -cp|-classpath|--class-path) + shift + shift + args+=(-cp $classpath) + ;; + *) + args+=("$1") + shift + ;; + esac + done -# Run transform -for class in ${INTERMEDIATE_CLASSES}/*.class ; do - transformed_class=${CLASSES}/$(basename ${class}) - ${JAVA:-java} -cp "${ASM_JAR}:${INTERMEDIATE_CLASSES}" transformer.IndyTransformer ${class} ${transformed_class} -done + # Compile. + $ORIGINAL_JAVAC "${args[@]}" -# Create DEX -DX_FLAGS="${DX_FLAGS} --min-sdk-version=26 --debug --dump-width=1000" -${DX} -JXmx256m --dex ${DX_FLAGS} --output=classes.dex ${CLASSES} + # Move original classes to intermediate location. + mv classes intermediate-classes + mkdir classes -# Zip DEX to file name expected by test runner -zip ${TEST_NAME:-classes-dex}.jar classes.dex + # Transform intermediate classes. + local transformer_args="-cp ${ASM_JAR}:transformer.jar transformer.IndyTransformer" + for class in intermediate-classes/*.class ; do + local transformed_class=classes/$(basename ${class}) + ${JAVA:-java} ${transformer_args} $PWD/${class} ${transformed_class} + done +} + +export -f javac_wrapper +export JAVAC=javac_wrapper + +###################################################################### + +# Build the transformer to apply to compiled classes. +mkdir classes +${ORIGINAL_JAVAC:-javac} ${JAVAC_ARGS} -cp "${ASM_JAR}" -d classes $(find util-src -name '*.java') +jar -cf transformer.jar -C classes transformer/ -C classes annotations/ +rm -rf classes + +# Use API level 28 for invoke-custom bytecode support. +DESUGAR=false ./default-build "$@" --api-level 28 diff --git a/test/952-invoke-custom/src/annotations/BootstrapMethod.java b/test/952-invoke-custom/util-src/annotations/BootstrapMethod.java index c16783007f..c16783007f 100644 --- a/test/952-invoke-custom/src/annotations/BootstrapMethod.java +++ b/test/952-invoke-custom/util-src/annotations/BootstrapMethod.java diff --git a/test/952-invoke-custom/src/annotations/CalledByIndy.java b/test/952-invoke-custom/util-src/annotations/CalledByIndy.java index c4d13a2af4..c4d13a2af4 100644 --- a/test/952-invoke-custom/src/annotations/CalledByIndy.java +++ b/test/952-invoke-custom/util-src/annotations/CalledByIndy.java diff --git a/test/952-invoke-custom/src/annotations/Constant.java b/test/952-invoke-custom/util-src/annotations/Constant.java index 7966a524ba..7966a524ba 100644 --- a/test/952-invoke-custom/src/annotations/Constant.java +++ b/test/952-invoke-custom/util-src/annotations/Constant.java diff --git a/test/952-invoke-custom/src/transformer/IndyTransformer.java b/test/952-invoke-custom/util-src/transformer/IndyTransformer.java index 45cb4760c9..d21dbbeabc 100644 --- a/test/952-invoke-custom/src/transformer/IndyTransformer.java +++ b/test/952-invoke-custom/util-src/transformer/IndyTransformer.java @@ -69,7 +69,7 @@ import org.objectweb.asm.Type; * * <p>In the example above, this results in add() being replaced by invocations of magicAdd(). */ -class IndyTransformer { +public class IndyTransformer { static class BootstrapBuilder extends ClassVisitor { @@ -164,10 +164,9 @@ class IndyTransformer { } private static void transform(Path inputClassPath, Path outputClassPath) throws Throwable { + URL url = inputClassPath.getParent().toUri().toURL(); URLClassLoader classLoader = - new URLClassLoader( - new URL[] {inputClassPath.toUri().toURL()}, - ClassLoader.getSystemClassLoader()); + new URLClassLoader(new URL[] {url}, ClassLoader.getSystemClassLoader()); String inputClassName = inputClassPath.getFileName().toString().replace(".class", ""); Class<?> inputClass = classLoader.loadClass(inputClassName); Map<String, CalledByIndy> callsiteMap = new HashMap<>(); diff --git a/test/961-default-iface-resolution-gen/build b/test/961-default-iface-resolution-gen/build index d719a9ffe9..1d245894de 100755 --- a/test/961-default-iface-resolution-gen/build +++ b/test/961-default-iface-resolution-gen/build @@ -22,5 +22,4 @@ mkdir -p ./src # Generate the smali files and expected.txt or fail ./util-src/generate_java.py ./src ./expected.txt -# dx runs out of memory with default 256M, give it more memory. -./default-build "$@" --experimental default-methods --dx-vm-option -JXmx1024M +./default-build "$@" --experimental default-methods diff --git a/test/964-default-iface-init-gen/build b/test/964-default-iface-init-gen/build index e504690043..1d245894de 100755 --- a/test/964-default-iface-init-gen/build +++ b/test/964-default-iface-init-gen/build @@ -22,5 +22,4 @@ mkdir -p ./src # Generate the smali files and expected.txt or fail ./util-src/generate_java.py ./src ./expected.txt -# dx runs out of memory with just 256m, so increase it. -./default-build "$@" --experimental default-methods --dx-vm-option -JXmx1024M +./default-build "$@" --experimental default-methods diff --git a/test/979-const-method-handle/build b/test/979-const-method-handle/build index 67fc2a6339..4d22cb608b 100755 --- a/test/979-const-method-handle/build +++ b/test/979-const-method-handle/build @@ -17,34 +17,41 @@ # make us exit on a failure set -e -ASM_JAR="${ANDROID_BUILD_TOP}/prebuilts/misc/common/asm/asm-6.0.jar" -INTERMEDIATE_CLASSES=classes-intermediate -TRANSFORMER_CLASSES=classes-transformer -CLASSES=classes - -# Create directories for classes -for class_dir in "${INTERMEDIATE_CLASSES}" "${TRANSFORMER_CLASSES}" "${CLASSES}"; do - rm -rf "${class_dir}" - mkdir "${class_dir}" -done - -# Build transformer -${JAVAC:-javac} ${JAVAC_ARGS} -cp "${ASM_JAR}" -d ${TRANSFORMER_CLASSES} $(find util-src -name '*.java') - -# Generate intermediate classes that will allow transform to be applied to test classes -JAVAC_ARGS="${JAVAC_ARGS} -source 1.8 -target 1.8" -${JAVAC:-javac} ${JAVAC_ARGS} -cp ${TRANSFORMER_CLASSES} -d ${INTERMEDIATE_CLASSES} $(find src -name '*.java') - -# Run transform -for class in ${INTERMEDIATE_CLASSES}/*.class ; do - transformed_class=${CLASSES}/$(basename ${class}) - ${JAVA:-java} -cp "${ASM_JAR}:${TRANSFORMER_CLASSES}" \ - transformer.ConstantTransformer ${class} ${transformed_class} -done - -# Create DEX -DX_FLAGS="${DX_FLAGS} --min-sdk-version=28 --debug --dump-width=1000" -${DX} -JXmx256m --dex ${DX_FLAGS} --output=classes.dex ${CLASSES} ${TRANSFORMER_CLASSES} - -# Zip DEX to file name expected by test runner -zip ${TEST_NAME:-classes-dex}.jar classes.dex +export ASM_JAR="${ANDROID_BUILD_TOP}/prebuilts/misc/common/asm/asm-6.0.jar" + +export ORIGINAL_JAVAC="$JAVAC" + +function javac_wrapper { + set -e + + # Add annotation src files to our compiler inputs. + local asrcs=util-src/annotations/*.java + + # Compile. + $ORIGINAL_JAVAC "$@" $asrcs + + # Move original classes to intermediate location. + mv classes intermediate-classes + mkdir classes + + # Transform intermediate classes. + local transformer_args="-cp ${ASM_JAR}:$PWD/transformer.jar transformer.ConstantTransformer" + for class in intermediate-classes/*.class ; do + local transformed_class=classes/$(basename ${class}) + ${JAVA:-java} ${transformer_args} ${class} ${transformed_class} + done +} + +export -f javac_wrapper +export JAVAC=javac_wrapper + +###################################################################### + +# Build the transformer to apply to compiled classes. +mkdir classes +${ORIGINAL_JAVAC:-javac} ${JAVAC_ARGS} -cp "${ASM_JAR}" -d classes $(find util-src -name '*.java') +jar -cf transformer.jar -C classes transformer/ -C classes annotations/ +rm -rf classes + +# Use API level 28 for DEX file support constant method handles. +./default-build "$@" --api-level 28 diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk index ad292fd0a7..53d4c372c4 100644 --- a/test/Android.run-test.mk +++ b/test/Android.run-test.mk @@ -19,13 +19,11 @@ include art/build/Android.common_test.mk # Dependencies for actually running a run-test. TEST_ART_RUN_TEST_DEPENDENCIES := \ - $(HOST_OUT_EXECUTABLES)/dx \ $(HOST_OUT_EXECUTABLES)/d8 \ $(HOST_OUT_EXECUTABLES)/d8-compat-dx \ $(HOST_OUT_EXECUTABLES)/hiddenapi \ $(HOST_OUT_EXECUTABLES)/jasmin \ - $(HOST_OUT_EXECUTABLES)/smali \ - $(HOST_OUT_JAVA_LIBRARIES)/desugar.jar + $(HOST_OUT_EXECUTABLES)/smali # We need dex2oat and dalvikvm on the target as well as the core images (all images as we sync # only once). @@ -97,7 +95,7 @@ endif # Host executables. host_prereq_rules := $(ART_TEST_HOST_RUN_TEST_DEPENDENCIES) -# Required for dx, jasmin, smali. +# Required for jasmin and smali. host_prereq_rules += $(TEST_ART_RUN_TEST_DEPENDENCIES) # Sync test files to the target, depends upon all things that must be pushed diff --git a/test/etc/default-build b/test/etc/default-build index 39f1a251c7..073ae2c796 100755 --- a/test/etc/default-build +++ b/test/etc/default-build @@ -17,9 +17,14 @@ # Stop if something fails. set -e +function fail() { + echo "$*" >&2 + exit 1 +} + if [[ $# -le 0 ]]; then echo 'Error:' '$0 should have the parameters from the "build" script forwarded to it' >&2 - echo 'Error: An example of how do it correctly is ./default-build "$@"' + fail 'Error: An example of how do it correctly is ./default-build "$@"' exit 1 fi @@ -98,7 +103,7 @@ if [ -z "${USE_HIDDENAPI}" ]; then USE_HIDDENAPI=true fi -# DESUGAR=false run-test... will disable desugar. +# DESUGAR=false run-test... will disable desugaring. if [[ "$DESUGAR" == false ]]; then USE_DESUGAR=false fi @@ -109,45 +114,25 @@ ZIP_COMPRESSION_METHOD="deflate" WITH_ZIP_ALIGN=false ZIP_ALIGN_BYTES="-1" -DX_FLAGS="--min-sdk-version=26" -DX_VM_FLAGS="" -EXPERIMENTAL="" - BUILD_MODE="target" DEV_MODE="no" -# The key for default arguments if no experimental things are enabled. DEFAULT_EXPERIMENT="no-experiment" +# The key for default arguments if no experimental things are enabled. +EXPERIMENTAL=$DEFAULT_EXPERIMENT + # Setup experimental API level mappings in a bash associative array. declare -A EXPERIMENTAL_API_LEVEL +EXPERIMENTAL_API_LEVEL[${DEFAULT_EXPERIMENT}]="26" EXPERIMENTAL_API_LEVEL["default-methods"]="24" EXPERIMENTAL_API_LEVEL["parameter-annotations"]="25" EXPERIMENTAL_API_LEVEL["agents"]="26" EXPERIMENTAL_API_LEVEL["method-handles"]="26" EXPERIMENTAL_API_LEVEL["var-handles"]="28" -declare -A JAVAC_EXPERIMENTAL_ARGS -JAVAC_EXPERIMENTAL_ARGS["default-methods"]="-source 1.8 -target 1.8" -JAVAC_EXPERIMENTAL_ARGS["lambdas"]="-source 1.8 -target 1.8" -JAVAC_EXPERIMENTAL_ARGS["method-handles"]="-source 1.8 -target 1.8" -JAVAC_EXPERIMENTAL_ARGS["parameter-annotations"]="-source 1.8 -target 1.8" -JAVAC_EXPERIMENTAL_ARGS["var-handles"]="-source 1.8 -target 1.8" -JAVAC_EXPERIMENTAL_ARGS[${DEFAULT_EXPERIMENT}]="-source 1.8 -target 1.8" -JAVAC_EXPERIMENTAL_ARGS["agents"]="-source 1.8 -target 1.8" - while true; do - if [ "x$1" = "x--dx-option" ]; then - shift - option="$1" - DX_FLAGS="${DX_FLAGS} $option" - shift - elif [ "x$1" = "x--dx-vm-option" ]; then - shift - option="$1" - DX_VM_FLAGS="${DX_VM_FLAGS} $option" - shift - elif [ "x$1" = "x--no-src" ]; then + if [ "x$1" = "x--no-src" ]; then HAS_SRC=false shift elif [ "x$1" = "x--no-src2" ]; then @@ -168,11 +153,14 @@ while true; do elif [ "x$1" = "x--no-jasmin" ]; then HAS_JASMIN=false shift + elif [ "x$1" = "x--api-level" ]; then + shift + EXPERIMENTAL_API_LEVEL[${EXPERIMENTAL}]=$1 + shift elif [ "x$1" = "x--experimental" ]; then shift # We have a specific experimental configuration so don't use the default. - DEFAULT_EXPERIMENT="" - EXPERIMENTAL="${EXPERIMENTAL} $1" + EXPERIMENTAL="$1" shift elif [ "x$1" = "x--zip-compression-method" ]; then # Allow using different zip compression method, e.g. 'store' @@ -198,30 +186,25 @@ while true; do DEV_MODE="yes" shift elif expr "x$1" : "x--" >/dev/null 2>&1; then - echo "unknown $0 option: $1" 1>&2 - exit 1 + fail "unknown $0 option: $1" else break fi done if [[ $BUILD_MODE == jvm ]]; then - # Does not need desugar on jvm because it supports the latest functionality. + # Does not need desugaring on jvm because it supports the latest functionality. USE_DESUGAR=false # Do not attempt to build src-art directories on jvm, it would fail without libcore. HAS_SRC_ART=false fi -# Add args from the experimental mappings. -for experiment in ${EXPERIMENTAL} ${DEFAULT_EXPERIMENT}; do - JAVAC_ARGS="${JAVAC_ARGS} ${JAVAC_EXPERIMENTAL_ARGS[${experiment}]}" -done +# Set API level for smali and d8. +API_LEVEL="${EXPERIMENTAL_API_LEVEL[${EXPERIMENTAL}]}" -for experiment in ${EXPERIMENTAL}; do - SMALI_ARGS="${SMALI_ARGS} --api ${EXPERIMENTAL_API_LEVEL[${experiment}]}" - DX_FLAGS="${DX_FLAGS} --min-sdk-version=${EXPERIMENTAL_API_LEVEL[${experiment}]}" - D8_FLAGS="--min-api ${EXPERIMENTAL_API_LEVEL[${experiment}]}" -done +# Add API level arguments to smali and dx +SMALI_ARGS="${SMALI_ARGS} --api $API_LEVEL" +D8_FLAGS="${D8_FLAGS} --min-api $API_LEVEL" ######################################### @@ -258,16 +241,6 @@ function make_jasmin() { fi } -function desugar() { - local desugar_args="--mode=$BUILD_MODE" - - if [[ $DEV_MODE == yes ]]; then - desugar_args="$desugar_args --show-commands" - fi - - "$DESUGAR" --core-only $desugar_args "$@" -} - # Like regular javac but may include libcore on the bootclasspath. function javac_with_bootclasspath { local helper_args="--mode=$BUILD_MODE" @@ -280,39 +253,34 @@ function javac_with_bootclasspath { "$ANDROID_BUILD_TOP/art/tools/javac-helper.sh" --core-only $helper_args ${JAVAC_ARGS} "$@" } -# Make a "dex" file given a directory of classes in $1. -# Also calls desugar on the classes first to convert lambdas. +# Make a "dex" file given a directory of classes in $1. This will be +# packaged in a jar file. function make_dex() { local name="$1" - - local dx_input - if [[ "$USE_DESUGAR" != "true" ]]; then - # Use d8 with --no-desugaring for the 3 tests that opt out of desugaring (b/110150973). - local d8_inputs=$(find classes -name '*.class' -type f) - ${D8} ${D8_FLAGS} --debug --no-desugaring --output ${name}.jar $d8_inputs && \ - jar -xf ${name}.jar ${name}.dex && \ - rm ${name}.jar - return $? + local d8_inputs=$(find $name -name '*.class' -type f) + local d8_output=${name}.jar + local dex_output=${name}.dex + local d8_local_flags="" + if [[ "$USE_DESUGAR" = "true" ]]; then + local boot_class_path_list=$($ANDROID_BUILD_TOP/art/tools/bootjars.sh --$BUILD_MODE --core --path) + for boot_class_path_element in $boot_class_path_list; do + d8_local_flags="$d8_local_flags --classpath $boot_class_path_element" + done + else + d8_local_flags="$d8_local_flags --no-desugaring" fi - - # Make a jar first so desugar doesn't need every .class file individually. - jar cf "$name.before-desugar.jar" -C "$name" . - - # Make desugared JAR. - dx_input="${name}.desugar.jar" - desugar --input "$name.before-desugar.jar" --output "$dx_input" - - local dexer="${DX}" - if [[ "${USE_D8}" != "false" ]]; then - dexer="${ANDROID_HOST_OUT}/bin/d8-compat-dx" + if [ "$DEV_MODE" = "yes" ]; then + echo ${D8} ${D8_FLAGS} $d8_local_flags --output $d8_output $d8_inputs fi + ${D8} ${D8_FLAGS} $d8_local_flags --output $d8_output $d8_inputs - # Make dex file from desugared JAR. - local dexer_flags="${DX_FLAGS} --debug --dex" - if [ $DEV_MODE = "yes" ]; then - echo ${dexer} -JXmx256m ${DX_VM_FLAGS} $dexer_flags --output=${name}.dex "${dx_input}" + # D8 outputs to JAR files today rather than DEX files as DX used + # to. To compensate, we extract the DEX from d8's output to meet the + # expectations of make_dex callers. + if [ "$DEV_MODE" = "yes" ]; then + echo unzip -p $d8_output classes.dex \> $dex_output fi - ${dexer} -JXmx256m ${DX_VM_FLAGS} $dexer_flags --output=${name}.dex "${dx_input}" + unzip -p $d8_output classes.dex > $dex_output } # Merge all the dex files in $1..$N into $1. Skip non-existing files, but at least 1 file must exist. @@ -342,11 +310,10 @@ function make_dexmerge() { # We assume the dexer did all the API level checks and just merge away. mkdir d8_merge_out - ${DXMERGER} --min-api 1000 --output ./d8_merge_out "${dex_files_to_merge[@]}" + ${DEXMERGER} --min-api 1000 --output ./d8_merge_out "${dex_files_to_merge[@]}" if [[ -e "./d8_merge_out/classes2.dex" ]]; then - echo "Cannot merge all dex files into a single dex" - exit 1 + fail "Cannot merge all dex files into a single dex" fi mv ./d8_merge_out/classes.dex "$dst_file"; @@ -426,7 +393,9 @@ else javac_with_bootclasspath -classpath classes -d classes `find src2 -name '*.java'` fi - if [[ "${HAS_SRC}" == "true" || "${HAS_SRC2}" == "true" || "${HAS_SRC_ART}" == "true" ]]; then + # If the classes directory is not-empty, package classes in a DEX file. NB some + # tests provide classes rather than java files. + if [ "$(ls -A classes)" ]; then if [ ${NEED_DEX} = "true" ]; then make_dex classes fi @@ -450,8 +419,7 @@ if [ "${HAS_SMALI}" = "true" -a ${NEED_DEX} = "true" ]; then # Compile Smali classes ${SMALI} -JXmx512m assemble ${SMALI_ARGS} --output smali_classes.dex `find smali -name '*.smali'` if [[ ! -s smali_classes.dex ]] ; then - echo ${SMALI} produced no output. >&2 - exit 1 + fail "${SMALI} produced no output." fi # Merge smali files into classes.dex, this takes priority over any jasmin files. make_dexmerge classes.dex smali_classes.dex @@ -479,7 +447,6 @@ if [ "${HAS_SMALI_MULTIDEX}" = "true" -a ${NEED_DEX} = "true" ]; then make_dexmerge classes2.dex smali_classes2.dex fi - if [ ${HAS_SRC_EX} = "true" ]; then # Build src-ex into classes-ex. # Includes 'src', 'src-art' source when compiling classes-ex, but exclude their .class files. @@ -524,7 +491,7 @@ fi # Create a single dex jar with two dex files for multidex. if [ ${NEED_DEX} = "true" ]; then - if $(has_multidex); then + if [ -f classes2.dex ] ; then zip $TEST_NAME.jar classes.dex classes2.dex else zip $TEST_NAME.jar classes.dex diff --git a/test/run-test b/test/run-test index b5b42854e5..d90eccdf75 100755 --- a/test/run-test +++ b/test/run-test @@ -41,7 +41,7 @@ else fi checker="${progdir}/../tools/checker/checker.py" export JAVA="java" -export JAVAC="javac -g -Xlint:-options" +export JAVAC="javac -g -Xlint:-options -source 1.8 -target 1.8" export RUN="${progdir}/etc/run-test-jar" export DEX_LOCATION=/data/run-test/${test_dir} export NEED_DEX="true" @@ -56,10 +56,10 @@ fi # If dx was not set by the environment variable, assume it is in the path. if [ -z "$DX" ]; then - export DX="dx" + export DX="d8-compat-dx" fi -export DXMERGER="$D8" +export DEXMERGER="$D8" # If jasmin was not set by the environment variable, assume it is in the path. if [ -z "$JASMIN" ]; then @@ -675,13 +675,6 @@ if [ "$usage" = "no" ]; then shift fi -# For building with javac and dx always use Java 7. The dx compiler -# only support byte codes from Java 7 or earlier (class file major -# version 51 or lower). -if [ "$NEED_DEX" = "true" ]; then - export JAVAC="${JAVAC} -source 1.7 -target 1.7" -fi - if [ "$usage" = "yes" ]; then prog=`basename $prog` ( diff --git a/tools/desugar.sh b/tools/desugar.sh deleted file mode 100755 index 7f73852ee5..0000000000 --- a/tools/desugar.sh +++ /dev/null @@ -1,95 +0,0 @@ -#!/bin/bash -# -# Copyright (C) 2017 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# -# Calls desugar.jar with the --bootclasspath_entry values passed in automatically. -# (This avoids having to manually set a boot class path). -# -# -# Script-specific args: -# --mode=[host|target]: Select between host or target bootclasspath (default target). -# --core-only: Use only "core" bootclasspath (e.g. do not include framework). -# --show-commands: Print the desugar command being executed. -# --help: Print above list of args. -# -# All other args are forwarded to desugar.jar -# - -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -TOP=$DIR/../.. - -pushd "$TOP" >/dev/null # back to android root. - -out=${OUT_DIR:-out} -desugar_jar=$out/host/linux-x86/framework/desugar.jar - -if ! [[ -f $desugar_jar ]]; then - echo "Error: Missing $desugar_jar; did you do a build?" >&2 - exit 1 -fi - -desugar_jar=$(readlink -f "$desugar_jar") # absolute path to desugar jar -popd >/dev/null - -bootjars_args= -mode=target -showcommands=n -while true; do - case $1 in - --help) - echo "Usage: $0 [--mode=host|target] [--core-only] [--show-commands] <desugar args>" - exit 0 - ;; - --mode=host) - bootjars_args="$bootjars_args --host" - ;; - --mode=target) - bootjars_args="$bootjars_args --target" - ;; - --mode=*) - echo "Unsupported $0 usage with --mode=$1" >&2 - exit 1 - ;; - --core-only) - bootjars_args="$bootjars_args --core" - ;; - --show-commands) - showcommands=y - ;; - *) - break - ;; - esac - shift -done - -desugar_args=(--min_sdk_version=10000) -boot_class_path_list=$($TOP/art/tools/bootjars.sh $bootjars_args --path) - -for path in $boot_class_path_list; do - desugar_args+=(--bootclasspath_entry="$path") -done - -if [[ ${#desugar_args[@]} -eq 0 ]]; then - echo "FATAL: Missing bootjars.sh file path list" >&2 - exit 1 -fi - -if [[ $showcommands == y ]]; then - echo java -jar "$desugar_jar" "${desugar_args[@]}" "$@" -fi - -java -jar "$desugar_jar" "${desugar_args[@]}" "$@" |