diff options
111 files changed, 1870 insertions, 1191 deletions
diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc index 52c767f935..22720ce524 100644 --- a/compiler/common_compiler_test.cc +++ b/compiler/common_compiler_test.cc @@ -153,11 +153,7 @@ void CommonCompilerTest::SetUp() { { ScopedObjectAccess soa(Thread::Current()); - const InstructionSet instruction_set = kRuntimeISA; - // Take the default set of instruction features from the build. - instruction_set_features_ = InstructionSetFeatures::FromCppDefines(); - - runtime_->SetInstructionSet(instruction_set); + runtime_->SetInstructionSet(instruction_set_); for (uint32_t i = 0; i < static_cast<uint32_t>(CalleeSaveType::kLastCalleeSaveType); ++i) { CalleeSaveType type = CalleeSaveType(i); if (!runtime_->HasCalleeSaveMethod(type)) { @@ -165,23 +161,48 @@ void CommonCompilerTest::SetUp() { } } - CreateCompilerDriver(compiler_kind_, instruction_set); + CreateCompilerDriver(); + } +} + +void CommonCompilerTest::ApplyInstructionSet() { + // Copy local instruction_set_ and instruction_set_features_ to *compiler_options_; + CHECK(instruction_set_features_ != nullptr); + if (instruction_set_ == InstructionSet::kThumb2) { + CHECK_EQ(InstructionSet::kArm, instruction_set_features_->GetInstructionSet()); + } else { + CHECK_EQ(instruction_set_, instruction_set_features_->GetInstructionSet()); } + compiler_options_->instruction_set_ = instruction_set_; + compiler_options_->instruction_set_features_ = + InstructionSetFeatures::FromBitmap(instruction_set_, instruction_set_features_->AsBitmap()); + CHECK(compiler_options_->instruction_set_features_->Equals(instruction_set_features_.get())); } -void CommonCompilerTest::CreateCompilerDriver(Compiler::Kind kind, - InstructionSet isa, - size_t number_of_threads) { +void CommonCompilerTest::OverrideInstructionSetFeatures(InstructionSet instruction_set, + const std::string& variant) { + instruction_set_ = instruction_set; + std::string error_msg; + instruction_set_features_ = + InstructionSetFeatures::FromVariant(instruction_set, variant, &error_msg); + CHECK(instruction_set_features_ != nullptr) << error_msg; + + if (compiler_options_ != nullptr) { + ApplyInstructionSet(); + } +} + +void CommonCompilerTest::CreateCompilerDriver() { + ApplyInstructionSet(); + 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(), + compiler_kind_, &compiler_options_->image_classes_, - number_of_threads, + number_of_threads_, /* swap_fd */ -1, GetProfileCompilationInfo())); // We typically don't generate an image in unit tests, disable this optimization by default. @@ -207,11 +228,6 @@ void CommonCompilerTest::SetCompilerKind(Compiler::Kind compiler_kind) { compiler_kind_ = compiler_kind; } -InstructionSet CommonCompilerTest::GetInstructionSet() const { - DCHECK(compiler_driver_.get() != nullptr); - return compiler_driver_->GetInstructionSet(); -} - void CommonCompilerTest::TearDown() { compiler_driver_.reset(); callbacks_.reset(); @@ -339,4 +355,8 @@ void CommonCompilerTest::SetDexFilesForOatFile(const std::vector<const DexFile*> compiler_driver_->dex_to_dex_compiler_.SetDexFiles(dex_files); } +void CommonCompilerTest::ClearBootImageOption() { + compiler_options_->boot_image_ = false; +} + } // namespace art diff --git a/compiler/common_compiler_test.h b/compiler/common_compiler_test.h index f070bbbeb8..db38110400 100644 --- a/compiler/common_compiler_test.h +++ b/compiler/common_compiler_test.h @@ -20,6 +20,8 @@ #include <list> #include <vector> +#include "arch/instruction_set.h" +#include "arch/instruction_set_features.h" #include "base/hash_set.h" #include "common_runtime_test.h" #include "compiler.h" @@ -55,15 +57,13 @@ class CommonCompilerTest : public CommonRuntimeTest { REQUIRES_SHARED(Locks::mutator_lock_); protected: - virtual void SetUp(); + void SetUp() OVERRIDE; - virtual void SetUpRuntimeOptions(RuntimeOptions* options); + void SetUpRuntimeOptions(RuntimeOptions* options) OVERRIDE; Compiler::Kind GetCompilerKind() const; void SetCompilerKind(Compiler::Kind compiler_kind); - InstructionSet GetInstructionSet() const; - // Get the set of image classes given to the compiler-driver in SetUp. virtual std::unique_ptr<HashSet<std::string>> GetImageClasses(); @@ -73,7 +73,7 @@ class CommonCompilerTest : public CommonRuntimeTest { return CompilerFilter::kDefaultCompilerFilter; } - virtual void TearDown(); + void TearDown() OVERRIDE; void CompileClass(mirror::ClassLoader* class_loader, const char* class_name) REQUIRES_SHARED(Locks::mutator_lock_); @@ -88,7 +88,10 @@ class CommonCompilerTest : public CommonRuntimeTest { const char* method_name, const char* signature) REQUIRES_SHARED(Locks::mutator_lock_); - void CreateCompilerDriver(Compiler::Kind kind, InstructionSet isa, size_t number_of_threads = 2U); + void ApplyInstructionSet(); + void OverrideInstructionSetFeatures(InstructionSet instruction_set, const std::string& variant); + + void CreateCompilerDriver(); void ReserveImageSpace(); @@ -96,12 +99,20 @@ class CommonCompilerTest : public CommonRuntimeTest { void SetDexFilesForOatFile(const std::vector<const DexFile*>& dex_files); + void ClearBootImageOption(); + Compiler::Kind compiler_kind_ = Compiler::kOptimizing; + size_t number_of_threads_ = 2u; + + InstructionSet instruction_set_ = + (kRuntimeISA == InstructionSet::kArm) ? InstructionSet::kThumb2 : kRuntimeISA; + // Take the default set of instruction features from the build. + std::unique_ptr<const InstructionSetFeatures> instruction_set_features_ + = InstructionSetFeatures::FromCppDefines(); + std::unique_ptr<CompilerOptions> compiler_options_; std::unique_ptr<VerificationResults> verification_results_; std::unique_ptr<CompilerDriver> compiler_driver_; - std::unique_ptr<const InstructionSetFeatures> instruction_set_features_; - private: std::unique_ptr<MemMap> image_reservation_; diff --git a/compiler/debug/dwarf/dwarf_test.h b/compiler/debug/dwarf/dwarf_test.h index 9a7c604ca1..6b039a7b5f 100644 --- a/compiler/debug/dwarf/dwarf_test.h +++ b/compiler/debug/dwarf/dwarf_test.h @@ -28,7 +28,7 @@ #include "base/os.h" #include "base/unix_file/fd_file.h" -#include "common_runtime_test.h" +#include "common_compiler_test.h" #include "gtest/gtest.h" #include "linker/elf_builder.h" #include "linker/file_output_stream.h" @@ -39,7 +39,7 @@ namespace dwarf { #define DW_CHECK(substring) Check(substring, false, __FILE__, __LINE__) #define DW_CHECK_NEXT(substring) Check(substring, true, __FILE__, __LINE__) -class DwarfTest : public CommonRuntimeTest { +class DwarfTest : public CommonCompilerTest { public: static constexpr bool kPrintObjdumpOutput = false; // debugging. diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc index fb6a72b1c5..fcaa0cdd07 100644 --- a/compiler/dex/dex_to_dex_compiler.cc +++ b/compiler/dex/dex_to_dex_compiler.cc @@ -31,6 +31,7 @@ #include "dex/dex_instruction-inl.h" #include "dex_to_dex_decompiler.h" #include "driver/compiler_driver.h" +#include "driver/compiler_options.h" #include "driver/dex_compilation_unit.h" #include "mirror/dex_cache.h" #include "quicken_info.h" @@ -609,7 +610,7 @@ CompiledMethod* DexToDexCompiler::CompileMethod( } // Create a `CompiledMethod`, with the quickened information in the vmap table. - InstructionSet instruction_set = driver_->GetInstructionSet(); + InstructionSet instruction_set = driver_->GetCompilerOptions().GetInstructionSet(); if (instruction_set == InstructionSet::kThumb2) { // Don't use the thumb2 instruction set to avoid the one off code delta. instruction_set = InstructionSet::kArm; diff --git a/compiler/driver/compiled_method_storage_test.cc b/compiler/driver/compiled_method_storage_test.cc index 42fbba5109..aed04f9c75 100644 --- a/compiler/driver/compiled_method_storage_test.cc +++ b/compiler/driver/compiled_method_storage_test.cc @@ -31,8 +31,6 @@ TEST(CompiledMethodStorage, Deduplicate) { CompilerDriver driver(&compiler_options, &verification_results, Compiler::kOptimizing, - /* instruction_set_ */ InstructionSet::kNone, - /* instruction_set_features */ nullptr, /* image_classes */ nullptr, /* thread_count */ 1u, /* swap_fd */ -1, diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 66a8a57b36..7c13894a2c 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -261,8 +261,6 @@ CompilerDriver::CompilerDriver( const CompilerOptions* compiler_options, VerificationResults* verification_results, Compiler::Kind compiler_kind, - InstructionSet instruction_set, - const InstructionSetFeatures* instruction_set_features, HashSet<std::string>* image_classes, size_t thread_count, int swap_fd, @@ -271,9 +269,6 @@ CompilerDriver::CompilerDriver( verification_results_(verification_results), compiler_(Compiler::Create(this, compiler_kind)), compiler_kind_(compiler_kind), - instruction_set_( - instruction_set == InstructionSet::kArm ? InstructionSet::kThumb2 : instruction_set), - instruction_set_features_(instruction_set_features), requires_constructor_barrier_lock_("constructor barrier lock"), non_relative_linker_patch_count_(0u), image_classes_(std::move(image_classes)), @@ -309,13 +304,15 @@ CompilerDriver::~CompilerDriver() { } -#define CREATE_TRAMPOLINE(type, abi, offset) \ - if (Is64BitInstructionSet(instruction_set_)) { \ - return CreateTrampoline64(instruction_set_, abi, \ - type ## _ENTRYPOINT_OFFSET(PointerSize::k64, offset)); \ - } else { \ - return CreateTrampoline32(instruction_set_, abi, \ - type ## _ENTRYPOINT_OFFSET(PointerSize::k32, offset)); \ +#define CREATE_TRAMPOLINE(type, abi, offset) \ + if (Is64BitInstructionSet(GetCompilerOptions().GetInstructionSet())) { \ + return CreateTrampoline64(GetCompilerOptions().GetInstructionSet(), \ + abi, \ + type ## _ENTRYPOINT_OFFSET(PointerSize::k64, offset)); \ + } else { \ + return CreateTrampoline32(GetCompilerOptions().GetInstructionSet(), \ + abi, \ + type ## _ENTRYPOINT_OFFSET(PointerSize::k32, offset)); \ } std::unique_ptr<const std::vector<uint8_t>> CompilerDriver::CreateJniDlsymLookup() const { @@ -601,7 +598,7 @@ static void CompileMethodQuick( if ((access_flags & kAccNative) != 0) { // Are we extracting only and have support for generic JNI down calls? if (!driver->GetCompilerOptions().IsJniCompilationEnabled() && - InstructionSetHasGenericJniStub(driver->GetInstructionSet())) { + InstructionSetHasGenericJniStub(driver->GetCompilerOptions().GetInstructionSet())) { // Leaving this empty will trigger the generic JNI version } else { // Query any JNI optimization annotations such as @FastNative or @CriticalNative. @@ -2146,8 +2143,9 @@ class SetVerifiedClassVisitor : public CompilationVisitor { mirror::Class::SetStatus(klass, ClassStatus::kVerified, soa.Self()); // Mark methods as pre-verified. If we don't do this, the interpreter will run with // access checks. - klass->SetSkipAccessChecksFlagOnAllMethods( - GetInstructionSetPointerSize(manager_->GetCompiler()->GetInstructionSet())); + InstructionSet instruction_set = + manager_->GetCompiler()->GetCompilerOptions().GetInstructionSet(); + klass->SetSkipAccessChecksFlagOnAllMethods(GetInstructionSetPointerSize(instruction_set)); klass->SetVerificationAttempted(); } // Record the final class status if necessary. diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index 54e1f3747f..8739dc3a35 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -97,8 +97,6 @@ class CompilerDriver { CompilerDriver(const CompilerOptions* compiler_options, VerificationResults* verification_results, Compiler::Kind compiler_kind, - InstructionSet instruction_set, - const InstructionSetFeatures* instruction_set_features, HashSet<std::string>* image_classes, size_t thread_count, int swap_fd, @@ -129,14 +127,6 @@ class CompilerDriver { VerificationResults* GetVerificationResults() const; - InstructionSet GetInstructionSet() const { - return instruction_set_; - } - - const InstructionSetFeatures* GetInstructionSetFeatures() const { - return instruction_set_features_; - } - const CompilerOptions& GetCompilerOptions() const { return *compiler_options_; } @@ -451,9 +441,6 @@ class CompilerDriver { std::unique_ptr<Compiler> compiler_; Compiler::Kind compiler_kind_; - const InstructionSet instruction_set_; - const InstructionSetFeatures* const instruction_set_features_; - // All class references that require constructor barriers. If the class reference is not in the // set then the result has not yet been computed. mutable ReaderWriterMutex requires_constructor_barrier_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER; diff --git a/compiler/driver/compiler_options.cc b/compiler/driver/compiler_options.cc index cc1af3e108..62d547de44 100644 --- a/compiler/driver/compiler_options.cc +++ b/compiler/driver/compiler_options.cc @@ -20,6 +20,8 @@ #include "android-base/stringprintf.h" +#include "arch/instruction_set.h" +#include "arch/instruction_set_features.h" #include "base/runtime_debug.h" #include "base/variant_map.h" #include "cmdline_parser.h" @@ -37,13 +39,14 @@ CompilerOptions::CompilerOptions() tiny_method_threshold_(kDefaultTinyMethodThreshold), num_dex_methods_threshold_(kDefaultNumDexMethodsThreshold), inline_max_code_units_(kUnsetInlineMaxCodeUnits), + instruction_set_(kRuntimeISA == InstructionSet::kArm ? InstructionSet::kThumb2 : kRuntimeISA), + instruction_set_features_(nullptr), no_inline_from_(), dex_files_for_oat_file_(), image_classes_(), boot_image_(false), core_image_(false), app_image_(false), - top_k_profile_threshold_(kDefaultTopKProfileThreshold), debuggable_(false), generate_debug_info_(kDefaultGenerateDebugInfo), generate_mini_debug_info_(kDefaultGenerateMiniDebugInfo), @@ -55,6 +58,7 @@ CompilerOptions::CompilerOptions() dump_timings_(false), dump_pass_timings_(false), dump_stats_(false), + top_k_profile_threshold_(kDefaultTopKProfileThreshold), verbose_methods_(), abort_on_hard_verifier_failure_(false), abort_on_soft_verifier_failure_(false), diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h index 908ff3302c..601c9140dd 100644 --- a/compiler/driver/compiler_options.h +++ b/compiler/driver/compiler_options.h @@ -17,6 +17,7 @@ #ifndef ART_COMPILER_DRIVER_COMPILER_OPTIONS_H_ #define ART_COMPILER_DRIVER_COMPILER_OPTIONS_H_ +#include <memory> #include <ostream> #include <string> #include <vector> @@ -30,11 +31,17 @@ namespace art { +namespace jit { +class JitCompiler; +} // namespace jit + namespace verifier { class VerifierDepsTest; } // namespace verifier class DexFile; +enum class InstructionSet; +class InstructionSetFeatures; class CompilerOptions FINAL { public: @@ -231,6 +238,15 @@ class CompilerOptions FINAL { return abort_on_soft_verifier_failure_; } + InstructionSet GetInstructionSet() const { + return instruction_set_; + } + + const InstructionSetFeatures* GetInstructionSetFeatures() const { + return instruction_set_features_.get(); + } + + const std::vector<const DexFile*>& GetNoInlineFromDexFile() const { return no_inline_from_; } @@ -312,6 +328,9 @@ class CompilerOptions FINAL { size_t num_dex_methods_threshold_; size_t inline_max_code_units_; + InstructionSet instruction_set_; + std::unique_ptr<const InstructionSetFeatures> instruction_set_features_; + // 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<>. @@ -327,8 +346,6 @@ class CompilerOptions FINAL { bool boot_image_; bool core_image_; bool app_image_; - // When using a profile file only the top K% of the profiled samples will be compiled. - double top_k_profile_threshold_; bool debuggable_; bool generate_debug_info_; bool generate_mini_debug_info_; @@ -341,6 +358,9 @@ class CompilerOptions FINAL { bool dump_pass_timings_; bool dump_stats_; + // When using a profile file only the top K% of the profiled samples will be compiled. + double top_k_profile_threshold_; + // Vector of methods to have verbose output enabled for. std::vector<std::string> verbose_methods_; @@ -380,6 +400,7 @@ class CompilerOptions FINAL { friend class Dex2Oat; friend class DexToDexDecompilerTest; friend class CommonCompilerTest; + friend class jit::JitCompiler; friend class verifier::VerifierDepsTest; template <class Base> diff --git a/compiler/exception_test.cc b/compiler/exception_test.cc index 8235be943b..b56a991e74 100644 --- a/compiler/exception_test.cc +++ b/compiler/exception_test.cc @@ -77,13 +77,10 @@ class ExceptionTest : public CommonRuntimeTest { ArenaStack arena_stack(&pool); ScopedArenaAllocator allocator(&arena_stack); StackMapStream stack_maps(&allocator, kRuntimeISA); - stack_maps.BeginStackMapEntry(kDexPc, - native_pc_offset, - /* register_mask */ 0u, - /* sp_mask */ nullptr, - /* num_dex_registers */ 0u, - /* inlining_depth */ 0u); + stack_maps.BeginMethod(4 * sizeof(void*), 0u, 0u, 0u); + stack_maps.BeginStackMapEntry(kDexPc, native_pc_offset); stack_maps.EndStackMapEntry(); + stack_maps.EndMethod(); const size_t stack_maps_size = stack_maps.PrepareForFillIn(); const size_t header_size = sizeof(OatQuickMethodHeader); const size_t code_alignment = GetInstructionSetAlignment(kRuntimeISA); diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc index 0de00a82fa..d7bd828f80 100644 --- a/compiler/jit/jit_compiler.cc +++ b/compiler/jit/jit_compiler.cc @@ -33,6 +33,7 @@ #include "jit/debugger_interface.h" #include "jit/jit.h" #include "jit/jit_code_cache.h" +#include "jit/jit_logger.h" #include "oat_file-inl.h" #include "oat_quick_method_header.h" #include "object_lock.h" @@ -50,7 +51,7 @@ extern "C" void* jit_load(bool* generate_debug_info) { VLOG(jit) << "loading jit compiler"; auto* const jit_compiler = JitCompiler::Create(); CHECK(jit_compiler != nullptr); - *generate_debug_info = jit_compiler->GetCompilerOptions()->GetGenerateDebugInfo(); + *generate_debug_info = jit_compiler->GetCompilerOptions().GetGenerateDebugInfo(); VLOG(jit) << "Done loading jit compiler"; return jit_compiler; } @@ -72,10 +73,11 @@ extern "C" void jit_types_loaded(void* handle, mirror::Class** types, size_t cou REQUIRES_SHARED(Locks::mutator_lock_) { auto* jit_compiler = reinterpret_cast<JitCompiler*>(handle); DCHECK(jit_compiler != nullptr); - if (jit_compiler->GetCompilerOptions()->GetGenerateDebugInfo()) { + const CompilerOptions& compiler_options = jit_compiler->GetCompilerOptions(); + if (compiler_options.GetGenerateDebugInfo()) { const ArrayRef<mirror::Class*> types_array(types, count); std::vector<uint8_t> elf_file = debug::WriteDebugElfFileForClasses( - kRuntimeISA, jit_compiler->GetCompilerDriver()->GetInstructionSetFeatures(), types_array); + kRuntimeISA, compiler_options.GetInstructionSetFeatures(), types_array); MutexLock mu(Thread::Current(), *Locks::native_debug_interface_lock_); // We never free debug info for types, so we don't need to provide a handle // (which would have been otherwise used as identifier to remove it later). @@ -103,44 +105,50 @@ JitCompiler::JitCompiler() { // Set debuggability based on the runtime value. compiler_options_->SetDebuggable(Runtime::Current()->IsJavaDebuggable()); - const InstructionSet instruction_set = kRuntimeISA; + const InstructionSet instruction_set = compiler_options_->GetInstructionSet(); + if (kRuntimeISA == InstructionSet::kArm) { + DCHECK_EQ(instruction_set, InstructionSet::kThumb2); + } else { + DCHECK_EQ(instruction_set, kRuntimeISA); + } + std::unique_ptr<const InstructionSetFeatures> instruction_set_features; for (const StringPiece option : Runtime::Current()->GetCompilerOptions()) { VLOG(compiler) << "JIT compiler option " << option; std::string error_msg; if (option.starts_with("--instruction-set-variant=")) { StringPiece str = option.substr(strlen("--instruction-set-variant=")).data(); VLOG(compiler) << "JIT instruction set variant " << str; - instruction_set_features_ = InstructionSetFeatures::FromVariant( + instruction_set_features = InstructionSetFeatures::FromVariant( instruction_set, str.as_string(), &error_msg); - if (instruction_set_features_ == nullptr) { + if (instruction_set_features == nullptr) { LOG(WARNING) << "Error parsing " << option << " message=" << error_msg; } } else if (option.starts_with("--instruction-set-features=")) { StringPiece str = option.substr(strlen("--instruction-set-features=")).data(); VLOG(compiler) << "JIT instruction set features " << str; - if (instruction_set_features_ == nullptr) { - instruction_set_features_ = InstructionSetFeatures::FromVariant( + if (instruction_set_features == nullptr) { + instruction_set_features = InstructionSetFeatures::FromVariant( instruction_set, "default", &error_msg); - if (instruction_set_features_ == nullptr) { + if (instruction_set_features == nullptr) { LOG(WARNING) << "Error parsing " << option << " message=" << error_msg; } } - instruction_set_features_ = - instruction_set_features_->AddFeaturesFromString(str.as_string(), &error_msg); - if (instruction_set_features_ == nullptr) { + instruction_set_features = + instruction_set_features->AddFeaturesFromString(str.as_string(), &error_msg); + if (instruction_set_features == nullptr) { LOG(WARNING) << "Error parsing " << option << " message=" << error_msg; } } } - if (instruction_set_features_ == nullptr) { - instruction_set_features_ = InstructionSetFeatures::FromCppDefines(); + if (instruction_set_features == nullptr) { + instruction_set_features = InstructionSetFeatures::FromCppDefines(); } + compiler_options_->instruction_set_features_ = std::move(instruction_set_features); + compiler_driver_.reset(new CompilerDriver( compiler_options_.get(), /* verification_results */ nullptr, Compiler::kOptimizing, - instruction_set, - instruction_set_features_.get(), /* image_classes */ nullptr, /* thread_count */ 1, /* swap_fd */ -1, diff --git a/compiler/jit/jit_compiler.h b/compiler/jit/jit_compiler.h index 31dc9e2fe5..5840fece2e 100644 --- a/compiler/jit/jit_compiler.h +++ b/compiler/jit/jit_compiler.h @@ -18,18 +18,19 @@ #define ART_COMPILER_JIT_JIT_COMPILER_H_ #include "base/mutex.h" -#include "compiled_method.h" -#include "driver/compiler_driver.h" -#include "driver/compiler_options.h" -#include "jit_logger.h" namespace art { class ArtMethod; -class InstructionSetFeatures; +class CompiledMethod; +class CompilerDriver; +class CompilerOptions; +class Thread; namespace jit { +class JitLogger; + class JitCompiler { public: static JitCompiler* Create(); @@ -39,8 +40,8 @@ class JitCompiler { bool CompileMethod(Thread* self, ArtMethod* method, bool osr) REQUIRES_SHARED(Locks::mutator_lock_); - CompilerOptions* GetCompilerOptions() const { - return compiler_options_.get(); + const CompilerOptions& GetCompilerOptions() const { + return *compiler_options_.get(); } CompilerDriver* GetCompilerDriver() const { return compiler_driver_.get(); @@ -49,7 +50,6 @@ class JitCompiler { private: std::unique_ptr<CompilerOptions> compiler_options_; std::unique_ptr<CompilerDriver> compiler_driver_; - std::unique_ptr<const InstructionSetFeatures> instruction_set_features_; std::unique_ptr<JitLogger> jit_logger_; JitCompiler(); diff --git a/compiler/jni/quick/jni_compiler.cc b/compiler/jni/quick/jni_compiler.cc index 0902bf2bce..62e8e0264f 100644 --- a/compiler/jni/quick/jni_compiler.cc +++ b/compiler/jni/quick/jni_compiler.cc @@ -34,7 +34,6 @@ #include "class_linker.h" #include "debug/dwarf/debug_frame_opcode_writer.h" #include "dex/dex_file-inl.h" -#include "driver/compiler_driver.h" #include "driver/compiler_options.h" #include "entrypoints/quick/quick_entrypoints.h" #include "jni/jni_env_ext.h" @@ -115,7 +114,7 @@ static ThreadOffset<kPointerSize> GetJniEntrypointThreadOffset(JniEntrypoint whi // convention. // template <PointerSize kPointerSize> -static JniCompiledMethod ArtJniCompileMethodInternal(CompilerDriver* driver, +static JniCompiledMethod ArtJniCompileMethodInternal(const CompilerOptions& compiler_options, uint32_t access_flags, uint32_t method_idx, const DexFile& dex_file) { @@ -124,8 +123,9 @@ static JniCompiledMethod ArtJniCompileMethodInternal(CompilerDriver* driver, const bool is_static = (access_flags & kAccStatic) != 0; const bool is_synchronized = (access_flags & kAccSynchronized) != 0; const char* shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx)); - InstructionSet instruction_set = driver->GetInstructionSet(); - const InstructionSetFeatures* instruction_set_features = driver->GetInstructionSetFeatures(); + InstructionSet instruction_set = compiler_options.GetInstructionSet(); + const InstructionSetFeatures* instruction_set_features = + compiler_options.GetInstructionSetFeatures(); // i.e. if the method was annotated with @FastNative const bool is_fast_native = (access_flags & kAccFastNative) != 0u; @@ -216,7 +216,6 @@ static JniCompiledMethod ArtJniCompileMethodInternal(CompilerDriver* driver, // Assembler that holds generated instructions std::unique_ptr<JNIMacroAssembler<kPointerSize>> jni_asm = GetMacroAssembler<kPointerSize>(&allocator, instruction_set, instruction_set_features); - const CompilerOptions& compiler_options = driver->GetCompilerOptions(); jni_asm->cfi().SetEnabled(compiler_options.GenerateAnyDebugInfo()); jni_asm->SetEmitRunTimeChecksInDebugMode(compiler_options.EmitRunTimeChecksInDebugMode()); @@ -771,16 +770,16 @@ static void SetNativeParameter(JNIMacroAssembler<kPointerSize>* jni_asm, } } -JniCompiledMethod ArtQuickJniCompileMethod(CompilerDriver* compiler, +JniCompiledMethod ArtQuickJniCompileMethod(const CompilerOptions& compiler_options, uint32_t access_flags, uint32_t method_idx, const DexFile& dex_file) { - if (Is64BitInstructionSet(compiler->GetInstructionSet())) { + if (Is64BitInstructionSet(compiler_options.GetInstructionSet())) { return ArtJniCompileMethodInternal<PointerSize::k64>( - compiler, access_flags, method_idx, dex_file); + compiler_options, access_flags, method_idx, dex_file); } else { return ArtJniCompileMethodInternal<PointerSize::k32>( - compiler, access_flags, method_idx, dex_file); + compiler_options, access_flags, method_idx, dex_file); } } diff --git a/compiler/jni/quick/jni_compiler.h b/compiler/jni/quick/jni_compiler.h index 11419947a0..313fcd361e 100644 --- a/compiler/jni/quick/jni_compiler.h +++ b/compiler/jni/quick/jni_compiler.h @@ -25,7 +25,7 @@ namespace art { class ArtMethod; -class CompilerDriver; +class CompilerOptions; class DexFile; class JniCompiledMethod { @@ -62,7 +62,7 @@ class JniCompiledMethod { std::vector<uint8_t> cfi_; }; -JniCompiledMethod ArtQuickJniCompileMethod(CompilerDriver* compiler, +JniCompiledMethod ArtQuickJniCompileMethod(const CompilerOptions& compiler_options, uint32_t access_flags, uint32_t method_idx, const DexFile& dex_file); diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc index 2589869859..074f249fe1 100644 --- a/compiler/optimizing/code_generator.cc +++ b/compiler/optimizing/code_generator.cc @@ -393,6 +393,11 @@ void CodeGenerator::Compile(CodeAllocator* allocator) { HGraphVisitor* instruction_visitor = GetInstructionVisitor(); DCHECK_EQ(current_block_index_, 0u); + GetStackMapStream()->BeginMethod(HasEmptyFrame() ? 0 : frame_size_, + core_spill_mask_, + fpu_spill_mask_, + GetGraph()->GetNumberOfVRegs()); + size_t frame_start = GetAssembler()->CodeSize(); GenerateFrameEntry(); DCHECK_EQ(GetAssembler()->cfi().GetCurrentCFAOffset(), static_cast<int>(frame_size_)); @@ -435,6 +440,8 @@ void CodeGenerator::Compile(CodeAllocator* allocator) { // Finalize instructions in assember; Finalize(allocator); + + GetStackMapStream()->EndMethod(); } void CodeGenerator::Finalize(CodeAllocator* allocator) { @@ -877,53 +884,45 @@ void CodeGenerator::AllocateLocations(HInstruction* instruction) { } std::unique_ptr<CodeGenerator> CodeGenerator::Create(HGraph* graph, - InstructionSet instruction_set, - const InstructionSetFeatures& isa_features, const CompilerOptions& compiler_options, OptimizingCompilerStats* stats) { ArenaAllocator* allocator = graph->GetAllocator(); - switch (instruction_set) { + switch (compiler_options.GetInstructionSet()) { #ifdef ART_ENABLE_CODEGEN_arm case InstructionSet::kArm: case InstructionSet::kThumb2: { return std::unique_ptr<CodeGenerator>( - new (allocator) arm::CodeGeneratorARMVIXL( - graph, *isa_features.AsArmInstructionSetFeatures(), compiler_options, stats)); + new (allocator) arm::CodeGeneratorARMVIXL(graph, compiler_options, stats)); } #endif #ifdef ART_ENABLE_CODEGEN_arm64 case InstructionSet::kArm64: { return std::unique_ptr<CodeGenerator>( - new (allocator) arm64::CodeGeneratorARM64( - graph, *isa_features.AsArm64InstructionSetFeatures(), compiler_options, stats)); + new (allocator) arm64::CodeGeneratorARM64(graph, compiler_options, stats)); } #endif #ifdef ART_ENABLE_CODEGEN_mips case InstructionSet::kMips: { return std::unique_ptr<CodeGenerator>( - new (allocator) mips::CodeGeneratorMIPS( - graph, *isa_features.AsMipsInstructionSetFeatures(), compiler_options, stats)); + new (allocator) mips::CodeGeneratorMIPS(graph, compiler_options, stats)); } #endif #ifdef ART_ENABLE_CODEGEN_mips64 case InstructionSet::kMips64: { return std::unique_ptr<CodeGenerator>( - new (allocator) mips64::CodeGeneratorMIPS64( - graph, *isa_features.AsMips64InstructionSetFeatures(), compiler_options, stats)); + new (allocator) mips64::CodeGeneratorMIPS64(graph, compiler_options, stats)); } #endif #ifdef ART_ENABLE_CODEGEN_x86 case InstructionSet::kX86: { return std::unique_ptr<CodeGenerator>( - new (allocator) x86::CodeGeneratorX86( - graph, *isa_features.AsX86InstructionSetFeatures(), compiler_options, stats)); + new (allocator) x86::CodeGeneratorX86(graph, compiler_options, stats)); } #endif #ifdef ART_ENABLE_CODEGEN_x86_64 case InstructionSet::kX86_64: { return std::unique_ptr<CodeGenerator>( - new (allocator) x86_64::CodeGeneratorX86_64( - graph, *isa_features.AsX86_64InstructionSetFeatures(), compiler_options, stats)); + new (allocator) x86_64::CodeGeneratorX86_64(graph, compiler_options, stats)); } #endif default: @@ -1087,7 +1086,7 @@ void CodeGenerator::RecordPcInfo(HInstruction* instruction, if (instruction == nullptr) { // For stack overflow checks and native-debug-info entries without dex register // mapping (i.e. start of basic block or start of slow path). - stack_map_stream->BeginStackMapEntry(dex_pc, native_pc, 0, 0, 0, 0); + stack_map_stream->BeginStackMapEntry(dex_pc, native_pc); stack_map_stream->EndStackMapEntry(); return; } @@ -1135,8 +1134,6 @@ void CodeGenerator::RecordPcInfo(HInstruction* instruction, native_pc, register_mask, locations->GetStackMask(), - outer_environment_size, - inlining_depth, kind); EmitEnvironment(environment, slow_path); // Record invoke info, the common case for the trampoline is super and static invokes. Only @@ -1204,15 +1201,12 @@ void CodeGenerator::RecordCatchBlockInfo() { uint32_t dex_pc = block->GetDexPc(); uint32_t num_vregs = graph_->GetNumberOfVRegs(); - uint32_t inlining_depth = 0; // Inlining of catch blocks is not supported at the moment. uint32_t native_pc = GetAddressOf(block); stack_map_stream->BeginStackMapEntry(dex_pc, native_pc, /* register_mask */ 0, /* stack_mask */ nullptr, - num_vregs, - inlining_depth, StackMap::Kind::Catch); HInstruction* current_phi = block->GetFirstPhi(); diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h index 03ae4983d4..59f858ea52 100644 --- a/compiler/optimizing/code_generator.h +++ b/compiler/optimizing/code_generator.h @@ -188,8 +188,6 @@ class CodeGenerator : public DeletableArenaObject<kArenaAllocCodeGenerator> { // Compiles the graph to executable instructions. void Compile(CodeAllocator* allocator); static std::unique_ptr<CodeGenerator> Create(HGraph* graph, - InstructionSet instruction_set, - const InstructionSetFeatures& isa_features, const CompilerOptions& compiler_options, OptimizingCompilerStats* stats = nullptr); virtual ~CodeGenerator(); diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index ad4b5cf339..7fa272acee 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -69,7 +69,7 @@ using helpers::InputCPURegisterOrZeroRegAt; using helpers::InputFPRegisterAt; using helpers::InputOperandAt; using helpers::InputRegisterAt; -using helpers::Int64ConstantFrom; +using helpers::Int64FromLocation; using helpers::IsConstantZeroBitPattern; using helpers::LocationFrom; using helpers::OperandFromMemOperand; @@ -1374,7 +1374,6 @@ Location InvokeDexCallingConventionVisitorARM64::GetMethodLocation() const { } CodeGeneratorARM64::CodeGeneratorARM64(HGraph* graph, - const Arm64InstructionSetFeatures& isa_features, const CompilerOptions& compiler_options, OptimizingCompilerStats* stats) : CodeGenerator(graph, @@ -1391,7 +1390,6 @@ CodeGeneratorARM64::CodeGeneratorARM64(HGraph* graph, instruction_visitor_(graph, this), move_resolver_(graph->GetAllocator(), this), assembler_(graph->GetAllocator()), - isa_features_(isa_features), uint32_literals_(std::less<uint32_t>(), graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)), uint64_literals_(std::less<uint64_t>(), @@ -1729,6 +1727,10 @@ void CodeGeneratorARM64::DumpFloatingPointRegister(std::ostream& stream, int reg stream << DRegister(reg); } +const Arm64InstructionSetFeatures& CodeGeneratorARM64::GetInstructionSetFeatures() const { + return *GetCompilerOptions().GetInstructionSetFeatures()->AsArm64InstructionSetFeatures(); +} + void CodeGeneratorARM64::MoveConstant(CPURegister destination, HConstant* constant) { if (constant->IsIntConstant()) { __ Mov(Register(destination), constant->AsIntConstant()->GetValue()); @@ -2702,7 +2704,7 @@ void LocationsBuilderARM64::VisitIntermediateAddressIndex(HIntermediateAddressIn void InstructionCodeGeneratorARM64::VisitIntermediateAddressIndex( HIntermediateAddressIndex* instruction) { Register index_reg = InputRegisterAt(instruction, 0); - uint32_t shift = Int64ConstantFrom(instruction->GetLocations()->InAt(2)); + uint32_t shift = Int64FromLocation(instruction->GetLocations()->InAt(2)); uint32_t offset = instruction->GetOffset()->AsIntConstant()->GetValue(); if (shift == 0) { @@ -2832,7 +2834,7 @@ void InstructionCodeGeneratorARM64::VisitArrayGet(HArrayGet* instruction) { DCHECK(!instruction->CanDoImplicitNullCheckOn(instruction->InputAt(0))); if (index.IsConstant()) { // Array load with a constant index can be treated as a field load. - offset += Int64ConstantFrom(index) << DataType::SizeShift(type); + offset += Int64FromLocation(index) << DataType::SizeShift(type); Location maybe_temp = (locations->GetTempCount() != 0) ? locations->GetTemp(0) : Location::NoLocation(); codegen_->GenerateFieldLoadWithBakerReadBarrier(instruction, @@ -2877,14 +2879,14 @@ void InstructionCodeGeneratorARM64::VisitArrayGet(HArrayGet* instruction) { "Expecting 0=compressed, 1=uncompressed"); __ Tbnz(length.W(), 0, &uncompressed_load); __ Ldrb(Register(OutputCPURegister(instruction)), - HeapOperand(obj, offset + Int64ConstantFrom(index))); + HeapOperand(obj, offset + Int64FromLocation(index))); __ B(&done); __ Bind(&uncompressed_load); __ Ldrh(Register(OutputCPURegister(instruction)), - HeapOperand(obj, offset + (Int64ConstantFrom(index) << 1))); + HeapOperand(obj, offset + (Int64FromLocation(index) << 1))); __ Bind(&done); } else { - offset += Int64ConstantFrom(index) << DataType::SizeShift(type); + offset += Int64FromLocation(index) << DataType::SizeShift(type); source = HeapOperand(obj, offset); } } else { @@ -2997,7 +2999,7 @@ void InstructionCodeGeneratorARM64::VisitArraySet(HArraySet* instruction) { if (!needs_write_barrier) { DCHECK(!may_need_runtime_call_for_type_check); if (index.IsConstant()) { - offset += Int64ConstantFrom(index) << DataType::SizeShift(value_type); + offset += Int64FromLocation(index) << DataType::SizeShift(value_type); destination = HeapOperand(array, offset); } else { UseScratchRegisterScope temps(masm); @@ -3035,7 +3037,7 @@ void InstructionCodeGeneratorARM64::VisitArraySet(HArraySet* instruction) { UseScratchRegisterScope temps(masm); Register temp = temps.AcquireSameSizeAs(array); if (index.IsConstant()) { - offset += Int64ConstantFrom(index) << DataType::SizeShift(value_type); + offset += Int64FromLocation(index) << DataType::SizeShift(value_type); destination = HeapOperand(array, offset); } else { destination = HeapOperand(temp, @@ -3345,20 +3347,25 @@ FOR_EACH_CONDITION_INSTRUCTION(DEFINE_CONDITION_VISITORS) #undef FOR_EACH_CONDITION_INSTRUCTION void InstructionCodeGeneratorARM64::GenerateIntDivForPower2Denom(HDiv* instruction) { - int64_t imm = Int64ConstantFrom(instruction->GetLocations()->InAt(1)); + int64_t imm = Int64FromLocation(instruction->GetLocations()->InAt(1)); uint64_t abs_imm = static_cast<uint64_t>(AbsOrMin(imm)); DCHECK(IsPowerOfTwo(abs_imm)) << abs_imm; Register out = OutputRegister(instruction); Register dividend = InputRegisterAt(instruction, 0); - int ctz_imm = CTZ(abs_imm); - UseScratchRegisterScope temps(GetVIXLAssembler()); - Register temp = temps.AcquireSameSizeAs(out); + if (abs_imm == 2) { + int bits = DataType::Size(instruction->GetResultType()) * kBitsPerByte; + __ Add(out, dividend, Operand(dividend, LSR, bits - 1)); + } else { + UseScratchRegisterScope temps(GetVIXLAssembler()); + Register temp = temps.AcquireSameSizeAs(out); + __ Add(temp, dividend, abs_imm - 1); + __ Cmp(dividend, 0); + __ Csel(out, temp, dividend, lt); + } - __ Add(temp, dividend, abs_imm - 1); - __ Cmp(dividend, 0); - __ Csel(out, temp, dividend, lt); + int ctz_imm = CTZ(abs_imm); if (imm > 0) { __ Asr(out, out, ctz_imm); } else { @@ -3419,7 +3426,7 @@ void InstructionCodeGeneratorARM64::GenerateDivRemWithAnyConstant(HBinaryOperati } void InstructionCodeGeneratorARM64::GenerateIntDivForConstDenom(HDiv *instruction) { - int64_t imm = Int64ConstantFrom(instruction->GetLocations()->InAt(1)); + int64_t imm = Int64FromLocation(instruction->GetLocations()->InAt(1)); if (imm == 0) { // Do not generate anything. DivZeroCheck would prevent any code to be executed. @@ -3509,7 +3516,7 @@ void InstructionCodeGeneratorARM64::VisitDivZeroCheck(HDivZeroCheck* instruction } if (value.IsConstant()) { - int64_t divisor = Int64ConstantFrom(value); + int64_t divisor = Int64FromLocation(value); if (divisor == 0) { __ B(slow_path->GetEntryLabel()); } else { @@ -5629,27 +5636,30 @@ void LocationsBuilderARM64::VisitRem(HRem* rem) { } void InstructionCodeGeneratorARM64::GenerateIntRemForPower2Denom(HRem *instruction) { - int64_t imm = Int64ConstantFrom(instruction->GetLocations()->InAt(1)); + int64_t imm = Int64FromLocation(instruction->GetLocations()->InAt(1)); uint64_t abs_imm = static_cast<uint64_t>(AbsOrMin(imm)); DCHECK(IsPowerOfTwo(abs_imm)) << abs_imm; Register out = OutputRegister(instruction); Register dividend = InputRegisterAt(instruction, 0); - int ctz_imm = CTZ(abs_imm); - UseScratchRegisterScope temps(GetVIXLAssembler()); - Register temp = temps.AcquireSameSizeAs(out); + if (abs_imm == 2) { + __ Cmp(dividend, 0); + __ And(out, dividend, 1); + __ Csneg(out, out, out, ge); + } else { + UseScratchRegisterScope temps(GetVIXLAssembler()); + Register temp = temps.AcquireSameSizeAs(out); - int bits = (instruction->GetResultType() == DataType::Type::kInt32) ? 32 : 64; - __ Asr(temp, dividend, bits - 1); - __ Lsr(temp, temp, bits - ctz_imm); - __ Add(out, dividend, temp); - __ And(out, out, abs_imm - 1); - __ Sub(out, out, temp); + __ Negs(temp, dividend); + __ And(out, dividend, abs_imm - 1); + __ And(temp, temp, abs_imm - 1); + __ Csneg(out, out, temp, mi); + } } void InstructionCodeGeneratorARM64::GenerateIntRemForOneOrMinusOneDenom(HRem *instruction) { - int64_t imm = Int64ConstantFrom(instruction->GetLocations()->InAt(1)); + int64_t imm = Int64FromLocation(instruction->GetLocations()->InAt(1)); DCHECK(imm == 1 || imm == -1) << imm; Register out = OutputRegister(instruction); @@ -5657,7 +5667,7 @@ void InstructionCodeGeneratorARM64::GenerateIntRemForOneOrMinusOneDenom(HRem *in } void InstructionCodeGeneratorARM64::GenerateIntRemForConstDenom(HRem *instruction) { - int64_t imm = Int64ConstantFrom(instruction->GetLocations()->InAt(1)); + int64_t imm = Int64FromLocation(instruction->GetLocations()->InAt(1)); if (imm == 0) { // Do not generate anything. @@ -6656,7 +6666,7 @@ void CodeGeneratorARM64::GenerateRawReferenceLoad(HInstruction* instruction, // ArrayGet and UnsafeGetObject and UnsafeCASObject intrinsics cases. // /* HeapReference<mirror::Object> */ ref = *(obj + offset + (index << scale_factor)) if (index.IsConstant()) { - uint32_t computed_offset = offset + (Int64ConstantFrom(index) << scale_factor); + uint32_t computed_offset = offset + (Int64FromLocation(index) << scale_factor); EmissionCheckScope guard(GetVIXLAssembler(), kMaxMacroInstructionSizeInBytes); Load(type, ref_reg, HeapOperand(obj, computed_offset)); if (needs_null_check) { diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h index dc4964d9e4..548c59ca35 100644 --- a/compiler/optimizing/code_generator_arm64.h +++ b/compiler/optimizing/code_generator_arm64.h @@ -405,7 +405,6 @@ class ParallelMoveResolverARM64 : public ParallelMoveResolverNoSwap { class CodeGeneratorARM64 : public CodeGenerator { public: CodeGeneratorARM64(HGraph* graph, - const Arm64InstructionSetFeatures& isa_features, const CompilerOptions& compiler_options, OptimizingCompilerStats* stats = nullptr); virtual ~CodeGeneratorARM64() {} @@ -478,9 +477,7 @@ class CodeGeneratorARM64 : public CodeGenerator { return InstructionSet::kArm64; } - const Arm64InstructionSetFeatures& GetInstructionSetFeatures() const { - return isa_features_; - } + const Arm64InstructionSetFeatures& GetInstructionSetFeatures() const; void Initialize() OVERRIDE { block_labels_.resize(GetGraph()->GetBlocks().size()); @@ -896,7 +893,6 @@ class CodeGeneratorARM64 : public CodeGenerator { InstructionCodeGeneratorARM64 instruction_visitor_; ParallelMoveResolverARM64 move_resolver_; Arm64Assembler assembler_; - const Arm64InstructionSetFeatures& isa_features_; // Deduplication map for 32-bit literals, used for non-patchable boot image addresses. Uint32ToLiteralMap uint32_literals_; diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc index 6804340cd4..6c8d5636d5 100644 --- a/compiler/optimizing/code_generator_arm_vixl.cc +++ b/compiler/optimizing/code_generator_arm_vixl.cc @@ -1502,6 +1502,10 @@ void CodeGeneratorARMVIXL::DumpFloatingPointRegister(std::ostream& stream, int r stream << vixl32::SRegister(reg); } +const ArmInstructionSetFeatures& CodeGeneratorARMVIXL::GetInstructionSetFeatures() const { + return *GetCompilerOptions().GetInstructionSetFeatures()->AsArmInstructionSetFeatures(); +} + static uint32_t ComputeSRegisterListMask(const SRegisterList& regs) { uint32_t mask = 0; for (uint32_t i = regs.GetFirstSRegister().GetCode(); @@ -2319,7 +2323,6 @@ vixl32::Label* CodeGeneratorARMVIXL::GetFinalLabel(HInstruction* instruction, } CodeGeneratorARMVIXL::CodeGeneratorARMVIXL(HGraph* graph, - const ArmInstructionSetFeatures& isa_features, const CompilerOptions& compiler_options, OptimizingCompilerStats* stats) : CodeGenerator(graph, @@ -2336,7 +2339,6 @@ CodeGeneratorARMVIXL::CodeGeneratorARMVIXL(HGraph* graph, instruction_visitor_(graph, this), move_resolver_(graph->GetAllocator(), this), assembler_(graph->GetAllocator()), - isa_features_(isa_features), uint32_literals_(std::less<uint32_t>(), graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)), boot_image_method_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)), diff --git a/compiler/optimizing/code_generator_arm_vixl.h b/compiler/optimizing/code_generator_arm_vixl.h index 4893d3c25e..ae19cdbc50 100644 --- a/compiler/optimizing/code_generator_arm_vixl.h +++ b/compiler/optimizing/code_generator_arm_vixl.h @@ -428,7 +428,6 @@ class InstructionCodeGeneratorARMVIXL : public InstructionCodeGenerator { class CodeGeneratorARMVIXL : public CodeGenerator { public: CodeGeneratorARMVIXL(HGraph* graph, - const ArmInstructionSetFeatures& isa_features, const CompilerOptions& compiler_options, OptimizingCompilerStats* stats = nullptr); virtual ~CodeGeneratorARMVIXL() {} @@ -475,6 +474,9 @@ class CodeGeneratorARMVIXL : public CodeGenerator { ParallelMoveResolver* GetMoveResolver() OVERRIDE { return &move_resolver_; } InstructionSet GetInstructionSet() const OVERRIDE { return InstructionSet::kThumb2; } + + const ArmInstructionSetFeatures& GetInstructionSetFeatures() const; + // Helper method to move a 32-bit value between two locations. void Move32(Location destination, Location source); @@ -523,8 +525,6 @@ class CodeGeneratorARMVIXL : public CodeGenerator { void Finalize(CodeAllocator* allocator) OVERRIDE; - const ArmInstructionSetFeatures& GetInstructionSetFeatures() const { return isa_features_; } - bool NeedsTwoRegisters(DataType::Type type) const OVERRIDE { return type == DataType::Type::kFloat64 || type == DataType::Type::kInt64; } @@ -888,7 +888,6 @@ class CodeGeneratorARMVIXL : public CodeGenerator { ParallelMoveResolverARMVIXL move_resolver_; ArmVIXLAssembler assembler_; - const ArmInstructionSetFeatures& isa_features_; // Deduplication map for 32-bit literals, used for non-patchable boot image addresses. Uint32ToLiteralMap uint32_literals_; diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc index 112eb517b5..8c38824d12 100644 --- a/compiler/optimizing/code_generator_mips.cc +++ b/compiler/optimizing/code_generator_mips.cc @@ -997,7 +997,6 @@ class ReadBarrierForRootSlowPathMIPS : public SlowPathCodeMIPS { }; CodeGeneratorMIPS::CodeGeneratorMIPS(HGraph* graph, - const MipsInstructionSetFeatures& isa_features, const CompilerOptions& compiler_options, OptimizingCompilerStats* stats) : CodeGenerator(graph, @@ -1014,8 +1013,8 @@ CodeGeneratorMIPS::CodeGeneratorMIPS(HGraph* graph, location_builder_(graph, this), instruction_visitor_(graph, this), move_resolver_(graph->GetAllocator(), this), - assembler_(graph->GetAllocator(), &isa_features), - isa_features_(isa_features), + assembler_(graph->GetAllocator(), + compiler_options.GetInstructionSetFeatures()->AsMipsInstructionSetFeatures()), uint32_literals_(std::less<uint32_t>(), graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)), boot_image_method_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)), @@ -1912,6 +1911,10 @@ void CodeGeneratorMIPS::DumpFloatingPointRegister(std::ostream& stream, int reg) stream << FRegister(reg); } +const MipsInstructionSetFeatures& CodeGeneratorMIPS::GetInstructionSetFeatures() const { + return *GetCompilerOptions().GetInstructionSetFeatures()->AsMipsInstructionSetFeatures(); +} + constexpr size_t kMipsDirectEntrypointRuntimeOffset = 16; void CodeGeneratorMIPS::InvokeRuntime(QuickEntrypointEnum entrypoint, diff --git a/compiler/optimizing/code_generator_mips.h b/compiler/optimizing/code_generator_mips.h index 9fdb385ce6..9758d35335 100644 --- a/compiler/optimizing/code_generator_mips.h +++ b/compiler/optimizing/code_generator_mips.h @@ -370,7 +370,6 @@ class InstructionCodeGeneratorMIPS : public InstructionCodeGenerator { class CodeGeneratorMIPS : public CodeGenerator { public: CodeGeneratorMIPS(HGraph* graph, - const MipsInstructionSetFeatures& isa_features, const CompilerOptions& compiler_options, OptimizingCompilerStats* stats = nullptr); virtual ~CodeGeneratorMIPS() {} @@ -509,9 +508,7 @@ class CodeGeneratorMIPS : public CodeGenerator { InstructionSet GetInstructionSet() const OVERRIDE { return InstructionSet::kMips; } - const MipsInstructionSetFeatures& GetInstructionSetFeatures() const { - return isa_features_; - } + const MipsInstructionSetFeatures& GetInstructionSetFeatures() const; MipsLabel* GetLabelOf(HBasicBlock* block) const { return CommonGetLabelOf<MipsLabel>(block_labels_, block); @@ -695,7 +692,6 @@ class CodeGeneratorMIPS : public CodeGenerator { InstructionCodeGeneratorMIPS instruction_visitor_; ParallelMoveResolverMIPS move_resolver_; MipsAssembler assembler_; - const MipsInstructionSetFeatures& isa_features_; // Deduplication map for 32-bit literals, used for non-patchable boot image addresses. Uint32ToLiteralMap uint32_literals_; diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc index 9f863640d5..9682377f5e 100644 --- a/compiler/optimizing/code_generator_mips64.cc +++ b/compiler/optimizing/code_generator_mips64.cc @@ -940,7 +940,6 @@ class ReadBarrierForRootSlowPathMIPS64 : public SlowPathCodeMIPS64 { }; CodeGeneratorMIPS64::CodeGeneratorMIPS64(HGraph* graph, - const Mips64InstructionSetFeatures& isa_features, const CompilerOptions& compiler_options, OptimizingCompilerStats* stats) : CodeGenerator(graph, @@ -957,8 +956,8 @@ CodeGeneratorMIPS64::CodeGeneratorMIPS64(HGraph* graph, location_builder_(graph, this), instruction_visitor_(graph, this), move_resolver_(graph->GetAllocator(), this), - assembler_(graph->GetAllocator(), &isa_features), - isa_features_(isa_features), + assembler_(graph->GetAllocator(), + compiler_options.GetInstructionSetFeatures()->AsMips64InstructionSetFeatures()), uint32_literals_(std::less<uint32_t>(), graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)), uint64_literals_(std::less<uint64_t>(), @@ -1772,6 +1771,10 @@ void CodeGeneratorMIPS64::DumpFloatingPointRegister(std::ostream& stream, int re stream << FpuRegister(reg); } +const Mips64InstructionSetFeatures& CodeGeneratorMIPS64::GetInstructionSetFeatures() const { + return *GetCompilerOptions().GetInstructionSetFeatures()->AsMips64InstructionSetFeatures(); +} + void CodeGeneratorMIPS64::InvokeRuntime(QuickEntrypointEnum entrypoint, HInstruction* instruction, uint32_t dex_pc, diff --git a/compiler/optimizing/code_generator_mips64.h b/compiler/optimizing/code_generator_mips64.h index 25c886f55d..96306d12c4 100644 --- a/compiler/optimizing/code_generator_mips64.h +++ b/compiler/optimizing/code_generator_mips64.h @@ -352,7 +352,6 @@ class InstructionCodeGeneratorMIPS64 : public InstructionCodeGenerator { class CodeGeneratorMIPS64 : public CodeGenerator { public: CodeGeneratorMIPS64(HGraph* graph, - const Mips64InstructionSetFeatures& isa_features, const CompilerOptions& compiler_options, OptimizingCompilerStats* stats = nullptr); virtual ~CodeGeneratorMIPS64() {} @@ -484,9 +483,7 @@ class CodeGeneratorMIPS64 : public CodeGenerator { InstructionSet GetInstructionSet() const OVERRIDE { return InstructionSet::kMips64; } - const Mips64InstructionSetFeatures& GetInstructionSetFeatures() const { - return isa_features_; - } + const Mips64InstructionSetFeatures& GetInstructionSetFeatures() const; Mips64Label* GetLabelOf(HBasicBlock* block) const { return CommonGetLabelOf<Mips64Label>(block_labels_, block); @@ -657,7 +654,6 @@ class CodeGeneratorMIPS64 : public CodeGenerator { InstructionCodeGeneratorMIPS64 instruction_visitor_; ParallelMoveResolverMIPS64 move_resolver_; Mips64Assembler assembler_; - const Mips64InstructionSetFeatures& isa_features_; // Deduplication map for 32-bit literals, used for non-patchable boot image addresses. Uint32ToLiteralMap uint32_literals_; diff --git a/compiler/optimizing/code_generator_vector_arm64.cc b/compiler/optimizing/code_generator_vector_arm64.cc index 6b0ec253e9..6d135a9bfb 100644 --- a/compiler/optimizing/code_generator_vector_arm64.cc +++ b/compiler/optimizing/code_generator_vector_arm64.cc @@ -29,7 +29,7 @@ using helpers::Arm64CanEncodeConstantAsImmediate; using helpers::DRegisterFrom; using helpers::HeapOperand; using helpers::InputRegisterAt; -using helpers::Int64ConstantFrom; +using helpers::Int64FromLocation; using helpers::OutputRegister; using helpers::VRegisterFrom; using helpers::WRegisterFrom; @@ -78,7 +78,7 @@ void InstructionCodeGeneratorARM64::VisitVecReplicateScalar(HVecReplicateScalar* case DataType::Type::kInt8: DCHECK_EQ(16u, instruction->GetVectorLength()); if (src_loc.IsConstant()) { - __ Movi(dst.V16B(), Int64ConstantFrom(src_loc)); + __ Movi(dst.V16B(), Int64FromLocation(src_loc)); } else { __ Dup(dst.V16B(), InputRegisterAt(instruction, 0)); } @@ -87,7 +87,7 @@ void InstructionCodeGeneratorARM64::VisitVecReplicateScalar(HVecReplicateScalar* case DataType::Type::kInt16: DCHECK_EQ(8u, instruction->GetVectorLength()); if (src_loc.IsConstant()) { - __ Movi(dst.V8H(), Int64ConstantFrom(src_loc)); + __ Movi(dst.V8H(), Int64FromLocation(src_loc)); } else { __ Dup(dst.V8H(), InputRegisterAt(instruction, 0)); } @@ -95,7 +95,7 @@ void InstructionCodeGeneratorARM64::VisitVecReplicateScalar(HVecReplicateScalar* case DataType::Type::kInt32: DCHECK_EQ(4u, instruction->GetVectorLength()); if (src_loc.IsConstant()) { - __ Movi(dst.V4S(), Int64ConstantFrom(src_loc)); + __ Movi(dst.V4S(), Int64FromLocation(src_loc)); } else { __ Dup(dst.V4S(), InputRegisterAt(instruction, 0)); } @@ -103,7 +103,7 @@ void InstructionCodeGeneratorARM64::VisitVecReplicateScalar(HVecReplicateScalar* case DataType::Type::kInt64: DCHECK_EQ(2u, instruction->GetVectorLength()); if (src_loc.IsConstant()) { - __ Movi(dst.V2D(), Int64ConstantFrom(src_loc)); + __ Movi(dst.V2D(), Int64FromLocation(src_loc)); } else { __ Dup(dst.V2D(), XRegisterFrom(src_loc)); } @@ -1333,7 +1333,7 @@ MemOperand InstructionCodeGeneratorARM64::VecAddress( DCHECK(!instruction->InputAt(0)->IsIntermediateAddress()); if (index.IsConstant()) { - offset += Int64ConstantFrom(index) << shift; + offset += Int64FromLocation(index) << shift; return HeapOperand(base, offset); } else { *scratch = temps_scope->AcquireSameSizeAs(base); diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index 12872edd0d..b03d72c0f3 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -958,6 +958,10 @@ void CodeGeneratorX86::DumpFloatingPointRegister(std::ostream& stream, int reg) stream << XmmRegister(reg); } +const X86InstructionSetFeatures& CodeGeneratorX86::GetInstructionSetFeatures() const { + return *GetCompilerOptions().GetInstructionSetFeatures()->AsX86InstructionSetFeatures(); +} + size_t CodeGeneratorX86::SaveCoreRegister(size_t stack_index, uint32_t reg_id) { __ movl(Address(ESP, stack_index), static_cast<Register>(reg_id)); return kX86WordSize; @@ -1009,7 +1013,6 @@ void CodeGeneratorX86::GenerateInvokeRuntime(int32_t entry_point_offset) { } CodeGeneratorX86::CodeGeneratorX86(HGraph* graph, - const X86InstructionSetFeatures& isa_features, const CompilerOptions& compiler_options, OptimizingCompilerStats* stats) : CodeGenerator(graph, @@ -1027,7 +1030,6 @@ CodeGeneratorX86::CodeGeneratorX86(HGraph* graph, instruction_visitor_(graph, this), move_resolver_(graph->GetAllocator(), this), assembler_(graph->GetAllocator()), - isa_features_(isa_features), boot_image_method_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)), method_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)), boot_image_type_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)), diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h index 7d18e2b4f3..e947b9dfc8 100644 --- a/compiler/optimizing/code_generator_x86.h +++ b/compiler/optimizing/code_generator_x86.h @@ -316,7 +316,6 @@ class JumpTableRIPFixup; class CodeGeneratorX86 : public CodeGenerator { public: CodeGeneratorX86(HGraph* graph, - const X86InstructionSetFeatures& isa_features, const CompilerOptions& compiler_options, OptimizingCompilerStats* stats = nullptr); virtual ~CodeGeneratorX86() {} @@ -390,6 +389,8 @@ class CodeGeneratorX86 : public CodeGenerator { return InstructionSet::kX86; } + const X86InstructionSetFeatures& GetInstructionSetFeatures() const; + // Helper method to move a 32bits value between two locations. void Move32(Location destination, Location source); // Helper method to move a 64bits value between two locations. @@ -474,10 +475,6 @@ class CodeGeneratorX86 : public CodeGenerator { Label* GetFrameEntryLabel() { return &frame_entry_label_; } - const X86InstructionSetFeatures& GetInstructionSetFeatures() const { - return isa_features_; - } - void AddMethodAddressOffset(HX86ComputeBaseMethodAddress* method_base, int32_t offset) { method_address_offset_.Put(method_base->GetId(), offset); } @@ -640,7 +637,6 @@ class CodeGeneratorX86 : public CodeGenerator { InstructionCodeGeneratorX86 instruction_visitor_; ParallelMoveResolverX86 move_resolver_; X86Assembler assembler_; - const X86InstructionSetFeatures& isa_features_; // PC-relative method patch info for kBootImageLinkTimePcRelative/kBootImageRelRo. // Also used for type/string patches for kBootImageRelRo (same linker patch as for methods). diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index 9631c15668..28f3abff79 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -1185,6 +1185,10 @@ void CodeGeneratorX86_64::DumpFloatingPointRegister(std::ostream& stream, int re stream << FloatRegister(reg); } +const X86_64InstructionSetFeatures& CodeGeneratorX86_64::GetInstructionSetFeatures() const { + return *GetCompilerOptions().GetInstructionSetFeatures()->AsX86_64InstructionSetFeatures(); +} + size_t CodeGeneratorX86_64::SaveCoreRegister(size_t stack_index, uint32_t reg_id) { __ movq(Address(CpuRegister(RSP), stack_index), CpuRegister(reg_id)); return kX86_64WordSize; @@ -1239,7 +1243,6 @@ static constexpr int kNumberOfCpuRegisterPairs = 0; // Use a fake return address register to mimic Quick. static constexpr Register kFakeReturnRegister = Register(kLastCpuRegister + 1); CodeGeneratorX86_64::CodeGeneratorX86_64(HGraph* graph, - const X86_64InstructionSetFeatures& isa_features, const CompilerOptions& compiler_options, OptimizingCompilerStats* stats) : CodeGenerator(graph, @@ -1258,7 +1261,6 @@ CodeGeneratorX86_64::CodeGeneratorX86_64(HGraph* graph, instruction_visitor_(graph, this), move_resolver_(graph->GetAllocator(), this), assembler_(graph->GetAllocator()), - isa_features_(isa_features), constant_area_start_(0), boot_image_method_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)), method_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)), diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h index cf862d3f34..0937f55899 100644 --- a/compiler/optimizing/code_generator_x86_64.h +++ b/compiler/optimizing/code_generator_x86_64.h @@ -296,7 +296,6 @@ class JumpTableRIPFixup; class CodeGeneratorX86_64 : public CodeGenerator { public: CodeGeneratorX86_64(HGraph* graph, - const X86_64InstructionSetFeatures& isa_features, const CompilerOptions& compiler_options, OptimizingCompilerStats* stats = nullptr); virtual ~CodeGeneratorX86_64() {} @@ -370,6 +369,8 @@ class CodeGeneratorX86_64 : public CodeGenerator { return InstructionSet::kX86_64; } + const X86_64InstructionSetFeatures& GetInstructionSetFeatures() const; + // Emit a write barrier. void MarkGCCard(CpuRegister temp, CpuRegister card, @@ -440,10 +441,6 @@ class CodeGeneratorX86_64 : public CodeGenerator { void EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) OVERRIDE; - const X86_64InstructionSetFeatures& GetInstructionSetFeatures() const { - return isa_features_; - } - // Fast path implementation of ReadBarrier::Barrier for a heap // reference field load when Baker's read barriers are used. void GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction, @@ -606,7 +603,6 @@ class CodeGeneratorX86_64 : public CodeGenerator { InstructionCodeGeneratorX86_64 instruction_visitor_; ParallelMoveResolverX86_64 move_resolver_; X86_64Assembler assembler_; - const X86_64InstructionSetFeatures& isa_features_; // Offset to the start of the constant area in the assembled code. // Used for fixups to the constant area. diff --git a/compiler/optimizing/codegen_test.cc b/compiler/optimizing/codegen_test.cc index a0fd5ffcb1..86687e60a9 100644 --- a/compiler/optimizing/codegen_test.cc +++ b/compiler/optimizing/codegen_test.cc @@ -89,7 +89,8 @@ void CodegenTest::TestCode(const std::vector<uint16_t>& data, bool has_result, i HGraph* graph = CreateCFG(data); // Remove suspend checks, they cannot be executed in this context. RemoveSuspendChecks(graph); - RunCode(target_config, graph, [](HGraph*) {}, has_result, expected); + OverrideInstructionSetFeatures(target_config.GetInstructionSet(), "default"); + RunCode(target_config, *compiler_options_, graph, [](HGraph*) {}, has_result, expected); } } @@ -100,7 +101,8 @@ void CodegenTest::TestCodeLong(const std::vector<uint16_t>& data, HGraph* graph = CreateCFG(data, DataType::Type::kInt64); // Remove suspend checks, they cannot be executed in this context. RemoveSuspendChecks(graph); - RunCode(target_config, graph, [](HGraph*) {}, has_result, expected); + OverrideInstructionSetFeatures(target_config.GetInstructionSet(), "default"); + RunCode(target_config, *compiler_options_, graph, [](HGraph*) {}, has_result, expected); } } @@ -460,7 +462,8 @@ TEST_F(CodegenTest, NonMaterializedCondition) { block->InsertInstructionBefore(move, block->GetLastInstruction()); }; - RunCode(target_config, graph, hook_before_codegen, true, 0); + OverrideInstructionSetFeatures(target_config.GetInstructionSet(), "default"); + RunCode(target_config, *compiler_options_, graph, hook_before_codegen, true, 0); } } @@ -506,7 +509,8 @@ TEST_F(CodegenTest, MaterializedCondition1) { new (graph_in->GetAllocator()) HParallelMove(graph_in->GetAllocator()); block->InsertInstructionBefore(move, block->GetLastInstruction()); }; - RunCode(target_config, graph, hook_before_codegen, true, lhs[i] < rhs[i]); + OverrideInstructionSetFeatures(target_config.GetInstructionSet(), "default"); + RunCode(target_config, *compiler_options_, graph, hook_before_codegen, true, lhs[i] < rhs[i]); } } } @@ -573,7 +577,8 @@ TEST_F(CodegenTest, MaterializedCondition2) { new (graph_in->GetAllocator()) HParallelMove(graph_in->GetAllocator()); block->InsertInstructionBefore(move, block->GetLastInstruction()); }; - RunCode(target_config, graph, hook_before_codegen, true, lhs[i] < rhs[i]); + OverrideInstructionSetFeatures(target_config.GetInstructionSet(), "default"); + RunCode(target_config, *compiler_options_, graph, hook_before_codegen, true, lhs[i] < rhs[i]); } } } @@ -682,7 +687,8 @@ void CodegenTest::TestComparison(IfCondition condition, block->AddInstruction(new (GetAllocator()) HReturn(comparison)); graph->BuildDominatorTree(); - RunCode(target_config, graph, [](HGraph*) {}, true, expected_result); + OverrideInstructionSetFeatures(target_config.GetInstructionSet(), "default"); + RunCode(target_config, *compiler_options_, graph, [](HGraph*) {}, true, expected_result); } TEST_F(CodegenTest, ComparisonsInt) { @@ -713,10 +719,9 @@ TEST_F(CodegenTest, ComparisonsLong) { #ifdef ART_ENABLE_CODEGEN_arm TEST_F(CodegenTest, ARMVIXLParallelMoveResolver) { - std::unique_ptr<const ArmInstructionSetFeatures> features( - ArmInstructionSetFeatures::FromCppDefines()); + OverrideInstructionSetFeatures(InstructionSet::kThumb2, "default"); HGraph* graph = CreateGraph(); - arm::CodeGeneratorARMVIXL codegen(graph, *features.get(), CompilerOptions()); + arm::CodeGeneratorARMVIXL codegen(graph, *compiler_options_); codegen.Initialize(); @@ -737,10 +742,9 @@ TEST_F(CodegenTest, ARMVIXLParallelMoveResolver) { #ifdef ART_ENABLE_CODEGEN_arm64 // Regression test for b/34760542. TEST_F(CodegenTest, ARM64ParallelMoveResolverB34760542) { - std::unique_ptr<const Arm64InstructionSetFeatures> features( - Arm64InstructionSetFeatures::FromCppDefines()); + OverrideInstructionSetFeatures(InstructionSet::kArm64, "default"); HGraph* graph = CreateGraph(); - arm64::CodeGeneratorARM64 codegen(graph, *features.get(), CompilerOptions()); + arm64::CodeGeneratorARM64 codegen(graph, *compiler_options_); codegen.Initialize(); @@ -787,10 +791,9 @@ TEST_F(CodegenTest, ARM64ParallelMoveResolverB34760542) { // Check that ParallelMoveResolver works fine for ARM64 for both cases when SIMD is on and off. TEST_F(CodegenTest, ARM64ParallelMoveResolverSIMD) { - std::unique_ptr<const Arm64InstructionSetFeatures> features( - Arm64InstructionSetFeatures::FromCppDefines()); + OverrideInstructionSetFeatures(InstructionSet::kArm64, "default"); HGraph* graph = CreateGraph(); - arm64::CodeGeneratorARM64 codegen(graph, *features.get(), CompilerOptions()); + arm64::CodeGeneratorARM64 codegen(graph, *compiler_options_); codegen.Initialize(); @@ -824,9 +827,9 @@ TEST_F(CodegenTest, ARM64ParallelMoveResolverSIMD) { #ifdef ART_ENABLE_CODEGEN_mips TEST_F(CodegenTest, MipsClobberRA) { - std::unique_ptr<const MipsInstructionSetFeatures> features_mips( - MipsInstructionSetFeatures::FromCppDefines()); - if (!CanExecute(InstructionSet::kMips) || features_mips->IsR6()) { + OverrideInstructionSetFeatures(InstructionSet::kMips, "mips32r"); + CHECK(!instruction_set_features_->AsMipsInstructionSetFeatures()->IsR6()); + if (!CanExecute(InstructionSet::kMips)) { // HMipsComputeBaseMethodAddress and the NAL instruction behind it // should only be generated on non-R6. return; @@ -860,7 +863,7 @@ TEST_F(CodegenTest, MipsClobberRA) { graph->BuildDominatorTree(); - mips::CodeGeneratorMIPS codegenMIPS(graph, *features_mips.get(), CompilerOptions()); + mips::CodeGeneratorMIPS codegenMIPS(graph, *compiler_options_); // Since there isn't HLoadClass or HLoadString, we need to manually indicate // that RA is clobbered and the method entry code should generate a stack frame // and preserve RA in it. And this is what we're testing here. diff --git a/compiler/optimizing/codegen_test_utils.h b/compiler/optimizing/codegen_test_utils.h index 792cfb539a..91811262de 100644 --- a/compiler/optimizing/codegen_test_utils.h +++ b/compiler/optimizing/codegen_test_utils.h @@ -17,17 +17,11 @@ #ifndef ART_COMPILER_OPTIMIZING_CODEGEN_TEST_UTILS_H_ #define ART_COMPILER_OPTIMIZING_CODEGEN_TEST_UTILS_H_ -#include "arch/arm/instruction_set_features_arm.h" #include "arch/arm/registers_arm.h" -#include "arch/arm64/instruction_set_features_arm64.h" #include "arch/instruction_set.h" -#include "arch/mips/instruction_set_features_mips.h" #include "arch/mips/registers_mips.h" -#include "arch/mips64/instruction_set_features_mips64.h" #include "arch/mips64/registers_mips64.h" -#include "arch/x86/instruction_set_features_x86.h" #include "arch/x86/registers_x86.h" -#include "arch/x86_64/instruction_set_features_x86_64.h" #include "code_simulator.h" #include "code_simulator_container.h" #include "common_compiler_test.h" @@ -101,10 +95,8 @@ class CodegenTargetConfig { // to just overwrite the code generator. class TestCodeGeneratorARMVIXL : public arm::CodeGeneratorARMVIXL { public: - TestCodeGeneratorARMVIXL(HGraph* graph, - const ArmInstructionSetFeatures& isa_features, - const CompilerOptions& compiler_options) - : arm::CodeGeneratorARMVIXL(graph, isa_features, compiler_options) { + TestCodeGeneratorARMVIXL(HGraph* graph, const CompilerOptions& compiler_options) + : arm::CodeGeneratorARMVIXL(graph, compiler_options) { AddAllocatedRegister(Location::RegisterLocation(arm::R6)); AddAllocatedRegister(Location::RegisterLocation(arm::R7)); } @@ -145,10 +137,8 @@ class TestCodeGeneratorARMVIXL : public arm::CodeGeneratorARMVIXL { // function. class TestCodeGeneratorARM64 : public arm64::CodeGeneratorARM64 { public: - TestCodeGeneratorARM64(HGraph* graph, - const Arm64InstructionSetFeatures& isa_features, - const CompilerOptions& compiler_options) - : arm64::CodeGeneratorARM64(graph, isa_features, compiler_options) {} + TestCodeGeneratorARM64(HGraph* graph, const CompilerOptions& compiler_options) + : arm64::CodeGeneratorARM64(graph, compiler_options) {} void MaybeGenerateMarkingRegisterCheck(int codem ATTRIBUTE_UNUSED, Location temp_loc ATTRIBUTE_UNUSED) OVERRIDE { @@ -165,10 +155,8 @@ class TestCodeGeneratorARM64 : public arm64::CodeGeneratorARM64 { #ifdef ART_ENABLE_CODEGEN_x86 class TestCodeGeneratorX86 : public x86::CodeGeneratorX86 { public: - TestCodeGeneratorX86(HGraph* graph, - const X86InstructionSetFeatures& isa_features, - const CompilerOptions& compiler_options) - : x86::CodeGeneratorX86(graph, isa_features, compiler_options) { + TestCodeGeneratorX86(HGraph* graph, const CompilerOptions& compiler_options) + : x86::CodeGeneratorX86(graph, compiler_options) { // Save edi, we need it for getting enough registers for long multiplication. AddAllocatedRegister(Location::RegisterLocation(x86::EDI)); } @@ -324,11 +312,11 @@ static void RunCode(CodeGenerator* codegen, template <typename Expected> static void RunCode(CodegenTargetConfig target_config, + const CompilerOptions& compiler_options, HGraph* graph, std::function<void(HGraph*)> hook_before_codegen, bool has_result, Expected expected) { - CompilerOptions compiler_options; std::unique_ptr<CodeGenerator> codegen(target_config.CreateCodeGenerator(graph, compiler_options)); RunCode(codegen.get(), graph, hook_before_codegen, has_result, expected); @@ -336,55 +324,37 @@ static void RunCode(CodegenTargetConfig target_config, #ifdef ART_ENABLE_CODEGEN_arm CodeGenerator* create_codegen_arm_vixl32(HGraph* graph, const CompilerOptions& compiler_options) { - std::unique_ptr<const ArmInstructionSetFeatures> features_arm( - ArmInstructionSetFeatures::FromCppDefines()); - return new (graph->GetAllocator()) - TestCodeGeneratorARMVIXL(graph, *features_arm.get(), compiler_options); + return new (graph->GetAllocator()) TestCodeGeneratorARMVIXL(graph, compiler_options); } #endif #ifdef ART_ENABLE_CODEGEN_arm64 CodeGenerator* create_codegen_arm64(HGraph* graph, const CompilerOptions& compiler_options) { - std::unique_ptr<const Arm64InstructionSetFeatures> features_arm64( - Arm64InstructionSetFeatures::FromCppDefines()); - return new (graph->GetAllocator()) - TestCodeGeneratorARM64(graph, *features_arm64.get(), compiler_options); + return new (graph->GetAllocator()) TestCodeGeneratorARM64(graph, compiler_options); } #endif #ifdef ART_ENABLE_CODEGEN_x86 CodeGenerator* create_codegen_x86(HGraph* graph, const CompilerOptions& compiler_options) { - std::unique_ptr<const X86InstructionSetFeatures> features_x86( - X86InstructionSetFeatures::FromCppDefines()); - return new (graph->GetAllocator()) TestCodeGeneratorX86( - graph, *features_x86.get(), compiler_options); + return new (graph->GetAllocator()) TestCodeGeneratorX86(graph, compiler_options); } #endif #ifdef ART_ENABLE_CODEGEN_x86_64 CodeGenerator* create_codegen_x86_64(HGraph* graph, const CompilerOptions& compiler_options) { - std::unique_ptr<const X86_64InstructionSetFeatures> features_x86_64( - X86_64InstructionSetFeatures::FromCppDefines()); - return new (graph->GetAllocator()) - x86_64::CodeGeneratorX86_64(graph, *features_x86_64.get(), compiler_options); + return new (graph->GetAllocator()) x86_64::CodeGeneratorX86_64(graph, compiler_options); } #endif #ifdef ART_ENABLE_CODEGEN_mips CodeGenerator* create_codegen_mips(HGraph* graph, const CompilerOptions& compiler_options) { - std::unique_ptr<const MipsInstructionSetFeatures> features_mips( - MipsInstructionSetFeatures::FromCppDefines()); - return new (graph->GetAllocator()) - mips::CodeGeneratorMIPS(graph, *features_mips.get(), compiler_options); + return new (graph->GetAllocator()) mips::CodeGeneratorMIPS(graph, compiler_options); } #endif #ifdef ART_ENABLE_CODEGEN_mips64 CodeGenerator* create_codegen_mips64(HGraph* graph, const CompilerOptions& compiler_options) { - std::unique_ptr<const Mips64InstructionSetFeatures> features_mips64( - Mips64InstructionSetFeatures::FromCppDefines()); - return new (graph->GetAllocator()) - mips64::CodeGeneratorMIPS64(graph, *features_mips64.get(), compiler_options); + return new (graph->GetAllocator()) mips64::CodeGeneratorMIPS64(graph, compiler_options); } #endif diff --git a/compiler/optimizing/common_arm64.h b/compiler/optimizing/common_arm64.h index 5191ee2b1e..5556f16740 100644 --- a/compiler/optimizing/common_arm64.h +++ b/compiler/optimizing/common_arm64.h @@ -151,23 +151,15 @@ inline vixl::aarch64::CPURegister InputCPURegisterOrZeroRegAt(HInstruction* inst return InputCPURegisterAt(instr, index); } -inline int64_t Int64ConstantFrom(Location location) { - HConstant* instr = location.GetConstant(); - if (instr->IsIntConstant()) { - return instr->AsIntConstant()->GetValue(); - } else if (instr->IsNullConstant()) { - return 0; - } else { - DCHECK(instr->IsLongConstant()) << instr->DebugName(); - return instr->AsLongConstant()->GetValue(); - } +inline int64_t Int64FromLocation(Location location) { + return Int64FromConstant(location.GetConstant()); } inline vixl::aarch64::Operand OperandFrom(Location location, DataType::Type type) { if (location.IsRegister()) { return vixl::aarch64::Operand(RegisterFrom(location, type)); } else { - return vixl::aarch64::Operand(Int64ConstantFrom(location)); + return vixl::aarch64::Operand(Int64FromLocation(location)); } } diff --git a/compiler/optimizing/constant_folding_test.cc b/compiler/optimizing/constant_folding_test.cc index d27104752b..b1436f863c 100644 --- a/compiler/optimizing/constant_folding_test.cc +++ b/compiler/optimizing/constant_folding_test.cc @@ -16,8 +16,6 @@ #include <functional> -#include "arch/x86/instruction_set_features_x86.h" -#include "code_generator_x86.h" #include "constant_folding.h" #include "dead_code_elimination.h" #include "driver/compiler_options.h" @@ -60,9 +58,6 @@ class ConstantFoldingTest : public OptimizingUnitTest { std::string actual_before = printer_before.str(); EXPECT_EQ(expected_before, actual_before); - std::unique_ptr<const X86InstructionSetFeatures> features_x86( - X86InstructionSetFeatures::FromCppDefines()); - x86::CodeGeneratorX86 codegenX86(graph_, *features_x86.get(), CompilerOptions()); HConstantFolding(graph_, "constant_folding").Run(); GraphChecker graph_checker_cf(graph_); graph_checker_cf.Run(); diff --git a/compiler/optimizing/dead_code_elimination_test.cc b/compiler/optimizing/dead_code_elimination_test.cc index adb6ce1187..277453545a 100644 --- a/compiler/optimizing/dead_code_elimination_test.cc +++ b/compiler/optimizing/dead_code_elimination_test.cc @@ -16,8 +16,6 @@ #include "dead_code_elimination.h" -#include "arch/x86/instruction_set_features_x86.h" -#include "code_generator_x86.h" #include "driver/compiler_options.h" #include "graph_checker.h" #include "optimizing_unit_test.h" @@ -45,9 +43,6 @@ void DeadCodeEliminationTest::TestCode(const std::vector<uint16_t>& data, std::string actual_before = printer_before.str(); ASSERT_EQ(actual_before, expected_before); - std::unique_ptr<const X86InstructionSetFeatures> features_x86( - X86InstructionSetFeatures::FromCppDefines()); - x86::CodeGeneratorX86 codegenX86(graph, *features_x86.get(), CompilerOptions()); HDeadCodeElimination(graph, nullptr /* stats */, "dead_code_elimination").Run(); GraphChecker graph_checker(graph); graph_checker.Run(); diff --git a/compiler/optimizing/emit_swap_mips_test.cc b/compiler/optimizing/emit_swap_mips_test.cc index b63914faf7..293c1ab3f3 100644 --- a/compiler/optimizing/emit_swap_mips_test.cc +++ b/compiler/optimizing/emit_swap_mips_test.cc @@ -28,11 +28,12 @@ namespace art { class EmitSwapMipsTest : public OptimizingUnitTest { public: void SetUp() OVERRIDE { + instruction_set_ = InstructionSet::kMips; + instruction_set_features_ = MipsInstructionSetFeatures::FromCppDefines(); + OptimizingUnitTest::SetUp(); graph_ = CreateGraph(); - isa_features_ = MipsInstructionSetFeatures::FromCppDefines(); - codegen_ = new (graph_->GetAllocator()) mips::CodeGeneratorMIPS(graph_, - *isa_features_.get(), - CompilerOptions()); + codegen_.reset( + new (graph_->GetAllocator()) mips::CodeGeneratorMIPS(graph_, *compiler_options_)); moves_ = new (GetAllocator()) HParallelMove(GetAllocator()); test_helper_.reset( new AssemblerTestInfrastructure(GetArchitectureString(), @@ -47,8 +48,10 @@ class EmitSwapMipsTest : public OptimizingUnitTest { void TearDown() OVERRIDE { test_helper_.reset(); - isa_features_.reset(); + codegen_.reset(); + graph_ = nullptr; ResetPoolAndAllocator(); + OptimizingUnitTest::TearDown(); } // Get the typically used name for this architecture. @@ -106,10 +109,9 @@ class EmitSwapMipsTest : public OptimizingUnitTest { protected: HGraph* graph_; HParallelMove* moves_; - mips::CodeGeneratorMIPS* codegen_; + std::unique_ptr<mips::CodeGeneratorMIPS> codegen_; mips::MipsAssembler* assembler_; std::unique_ptr<AssemblerTestInfrastructure> test_helper_; - std::unique_ptr<const MipsInstructionSetFeatures> isa_features_; }; TEST_F(EmitSwapMipsTest, TwoRegisters) { diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc index 72d53d28cf..a104070dd3 100644 --- a/compiler/optimizing/inliner.cc +++ b/compiler/optimizing/inliner.cc @@ -1783,7 +1783,7 @@ bool HInliner::TryBuildAndInlineHelper(HInvoke* invoke_instruction, graph_->GetArenaStack(), callee_dex_file, method_index, - compiler_driver_->GetInstructionSet(), + codegen_->GetCompilerOptions().GetInstructionSet(), invoke_type, graph_->IsDebuggable(), /* osr */ false, @@ -1820,8 +1820,8 @@ bool HInliner::TryBuildAndInlineHelper(HInvoke* invoke_instruction, return false; } - if (!RegisterAllocator::CanAllocateRegistersFor(*callee_graph, - compiler_driver_->GetInstructionSet())) { + if (!RegisterAllocator::CanAllocateRegistersFor( + *callee_graph, codegen_->GetCompilerOptions().GetInstructionSet())) { LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedRegisterAllocator) << "Method " << callee_dex_file.PrettyMethod(method_index) << " cannot be inlined because of the register allocator"; diff --git a/compiler/optimizing/linearize_test.cc b/compiler/optimizing/linearize_test.cc index 9fa5b74c62..50bfe843b5 100644 --- a/compiler/optimizing/linearize_test.cc +++ b/compiler/optimizing/linearize_test.cc @@ -16,11 +16,9 @@ #include <fstream> -#include "arch/x86/instruction_set_features_x86.h" #include "base/arena_allocator.h" #include "builder.h" #include "code_generator.h" -#include "code_generator_x86.h" #include "dex/dex_file.h" #include "dex/dex_instruction.h" #include "driver/compiler_options.h" @@ -43,10 +41,8 @@ template <size_t number_of_blocks> void LinearizeTest::TestCode(const std::vector<uint16_t>& data, const uint32_t (&expected_order)[number_of_blocks]) { HGraph* graph = CreateCFG(data); - std::unique_ptr<const X86InstructionSetFeatures> features_x86( - X86InstructionSetFeatures::FromCppDefines()); - x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions()); - SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator()); + std::unique_ptr<CodeGenerator> codegen = CodeGenerator::Create(graph, *compiler_options_); + SsaLivenessAnalysis liveness(graph, codegen.get(), GetScopedAllocator()); liveness.Analyze(); ASSERT_EQ(graph->GetLinearOrder().size(), number_of_blocks); diff --git a/compiler/optimizing/live_ranges_test.cc b/compiler/optimizing/live_ranges_test.cc index 66660662e4..0fb90fb370 100644 --- a/compiler/optimizing/live_ranges_test.cc +++ b/compiler/optimizing/live_ranges_test.cc @@ -14,11 +14,9 @@ * limitations under the License. */ -#include "arch/x86/instruction_set_features_x86.h" #include "base/arena_allocator.h" #include "builder.h" #include "code_generator.h" -#include "code_generator_x86.h" #include "dex/dex_file.h" #include "dex/dex_instruction.h" #include "driver/compiler_options.h" @@ -63,10 +61,8 @@ TEST_F(LiveRangesTest, CFG1) { HGraph* graph = BuildGraph(data); - std::unique_ptr<const X86InstructionSetFeatures> features_x86( - X86InstructionSetFeatures::FromCppDefines()); - x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions()); - SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator()); + std::unique_ptr<CodeGenerator> codegen = CodeGenerator::Create(graph, *compiler_options_); + SsaLivenessAnalysis liveness(graph, codegen.get(), GetScopedAllocator()); liveness.Analyze(); LiveInterval* interval = liveness.GetInstructionFromSsaIndex(0)->GetLiveInterval(); @@ -109,10 +105,8 @@ TEST_F(LiveRangesTest, CFG2) { Instruction::RETURN | 0 << 8); HGraph* graph = BuildGraph(data); - std::unique_ptr<const X86InstructionSetFeatures> features_x86( - X86InstructionSetFeatures::FromCppDefines()); - x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions()); - SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator()); + std::unique_ptr<CodeGenerator> codegen = CodeGenerator::Create(graph, *compiler_options_); + SsaLivenessAnalysis liveness(graph, codegen.get(), GetScopedAllocator()); liveness.Analyze(); LiveInterval* interval = liveness.GetInstructionFromSsaIndex(0)->GetLiveInterval(); @@ -158,10 +152,8 @@ TEST_F(LiveRangesTest, CFG3) { Instruction::RETURN | 0 << 8); HGraph* graph = BuildGraph(data); - std::unique_ptr<const X86InstructionSetFeatures> features_x86( - X86InstructionSetFeatures::FromCppDefines()); - x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions()); - SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator()); + std::unique_ptr<CodeGenerator> codegen = CodeGenerator::Create(graph, *compiler_options_); + SsaLivenessAnalysis liveness(graph, codegen.get(), GetScopedAllocator()); liveness.Analyze(); // Test for the 4 constant. @@ -235,10 +227,8 @@ TEST_F(LiveRangesTest, Loop1) { HGraph* graph = BuildGraph(data); RemoveSuspendChecks(graph); - std::unique_ptr<const X86InstructionSetFeatures> features_x86( - X86InstructionSetFeatures::FromCppDefines()); - x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions()); - SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator()); + std::unique_ptr<CodeGenerator> codegen = CodeGenerator::Create(graph, *compiler_options_); + SsaLivenessAnalysis liveness(graph, codegen.get(), GetScopedAllocator()); liveness.Analyze(); // Test for the 0 constant. @@ -312,10 +302,8 @@ TEST_F(LiveRangesTest, Loop2) { Instruction::RETURN | 0 << 8); HGraph* graph = BuildGraph(data); - std::unique_ptr<const X86InstructionSetFeatures> features_x86( - X86InstructionSetFeatures::FromCppDefines()); - x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions()); - SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator()); + std::unique_ptr<CodeGenerator> codegen = CodeGenerator::Create(graph, *compiler_options_); + SsaLivenessAnalysis liveness(graph, codegen.get(), GetScopedAllocator()); liveness.Analyze(); // Test for the 0 constant. @@ -388,10 +376,8 @@ TEST_F(LiveRangesTest, CFG4) { Instruction::RETURN); HGraph* graph = BuildGraph(data); - std::unique_ptr<const X86InstructionSetFeatures> features_x86( - X86InstructionSetFeatures::FromCppDefines()); - x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions()); - SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator()); + std::unique_ptr<CodeGenerator> codegen = CodeGenerator::Create(graph, *compiler_options_); + SsaLivenessAnalysis liveness(graph, codegen.get(), GetScopedAllocator()); liveness.Analyze(); // Test for the 0 constant. diff --git a/compiler/optimizing/liveness_test.cc b/compiler/optimizing/liveness_test.cc index 6621a03568..72f995e773 100644 --- a/compiler/optimizing/liveness_test.cc +++ b/compiler/optimizing/liveness_test.cc @@ -14,11 +14,9 @@ * limitations under the License. */ -#include "arch/x86/instruction_set_features_x86.h" #include "base/arena_allocator.h" #include "builder.h" #include "code_generator.h" -#include "code_generator_x86.h" #include "dex/dex_file.h" #include "dex/dex_instruction.h" #include "driver/compiler_options.h" @@ -50,10 +48,8 @@ void LivenessTest::TestCode(const std::vector<uint16_t>& data, const char* expec HGraph* graph = CreateCFG(data); // `Inline` conditions into ifs. PrepareForRegisterAllocation(graph).Run(); - std::unique_ptr<const X86InstructionSetFeatures> features_x86( - X86InstructionSetFeatures::FromCppDefines()); - x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions()); - SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator()); + std::unique_ptr<CodeGenerator> codegen = CodeGenerator::Create(graph, *compiler_options_); + SsaLivenessAnalysis liveness(graph, codegen.get(), GetScopedAllocator()); liveness.Analyze(); std::ostringstream buffer; diff --git a/compiler/optimizing/loop_analysis.h b/compiler/optimizing/loop_analysis.h index c09d3ff00f..7f321b73c8 100644 --- a/compiler/optimizing/loop_analysis.h +++ b/compiler/optimizing/loop_analysis.h @@ -113,9 +113,7 @@ class LoopAnalysis : public ValueObject { instruction->IsUnresolvedStaticFieldGet() || instruction->IsUnresolvedStaticFieldSet() || // TODO: Support loops with intrinsified invokes. - instruction->IsInvoke() || - // TODO: Support loops with ClinitChecks. - instruction->IsClinitCheck()); + instruction->IsInvoke()); } }; diff --git a/compiler/optimizing/loop_optimization.cc b/compiler/optimizing/loop_optimization.cc index eda6bd1e86..72aa25302e 100644 --- a/compiler/optimizing/loop_optimization.cc +++ b/compiler/optimizing/loop_optimization.cc @@ -23,7 +23,7 @@ #include "arch/mips64/instruction_set_features_mips64.h" #include "arch/x86/instruction_set_features_x86.h" #include "arch/x86_64/instruction_set_features_x86_64.h" -#include "driver/compiler_driver.h" +#include "driver/compiler_options.h" #include "linear_order.h" #include "mirror/array-inl.h" #include "mirror/string.h" @@ -427,12 +427,12 @@ static void TryToEvaluateIfCondition(HIf* instruction, HGraph* graph) { // HLoopOptimization::HLoopOptimization(HGraph* graph, - CompilerDriver* compiler_driver, + const CompilerOptions* compiler_options, HInductionVarAnalysis* induction_analysis, OptimizingCompilerStats* stats, const char* name) : HOptimization(graph, name, stats), - compiler_driver_(compiler_driver), + compiler_options_(compiler_options), induction_range_(induction_analysis), loop_allocator_(nullptr), global_allocator_(graph_->GetAllocator()), @@ -454,8 +454,8 @@ HLoopOptimization::HLoopOptimization(HGraph* graph, vector_header_(nullptr), vector_body_(nullptr), vector_index_(nullptr), - arch_loop_helper_(ArchNoOptsLoopHelper::Create(compiler_driver_ != nullptr - ? compiler_driver_->GetInstructionSet() + arch_loop_helper_(ArchNoOptsLoopHelper::Create(compiler_options_ != nullptr + ? compiler_options_->GetInstructionSet() : InstructionSet::kNone, global_allocator_)) { } @@ -756,9 +756,9 @@ bool HLoopOptimization::OptimizeInnerLoop(LoopNode* node) { // bool HLoopOptimization::TryUnrollingForBranchPenaltyReduction(LoopNode* node) { - // Don't run peeling/unrolling if compiler_driver_ is nullptr (i.e., running under tests) + // Don't run peeling/unrolling if compiler_options_ is nullptr (i.e., running under tests) // as InstructionSet is needed. - if (compiler_driver_ == nullptr) { + if (compiler_options_ == nullptr) { return false; } @@ -802,9 +802,9 @@ bool HLoopOptimization::TryUnrollingForBranchPenaltyReduction(LoopNode* node) { } bool HLoopOptimization::TryPeelingForLoopInvariantExitsElimination(LoopNode* node) { - // Don't run peeling/unrolling if compiler_driver_ is nullptr (i.e., running under tests) + // Don't run peeling/unrolling if compiler_options_ is nullptr (i.e., running under tests) // as InstructionSet is needed. - if (compiler_driver_ == nullptr) { + if (compiler_options_ == nullptr) { return false; } @@ -1459,7 +1459,7 @@ bool HLoopOptimization::VectorizeUse(LoopNode* node, } uint32_t HLoopOptimization::GetVectorSizeInBytes() { - switch (compiler_driver_->GetInstructionSet()) { + switch (compiler_options_->GetInstructionSet()) { case InstructionSet::kArm: case InstructionSet::kThumb2: return 8; // 64-bit SIMD @@ -1469,8 +1469,8 @@ uint32_t HLoopOptimization::GetVectorSizeInBytes() { } bool HLoopOptimization::TrySetVectorType(DataType::Type type, uint64_t* restrictions) { - const InstructionSetFeatures* features = compiler_driver_->GetInstructionSetFeatures(); - switch (compiler_driver_->GetInstructionSet()) { + const InstructionSetFeatures* features = compiler_options_->GetInstructionSetFeatures(); + switch (compiler_options_->GetInstructionSet()) { case InstructionSet::kArm: case InstructionSet::kThumb2: // Allow vectorization for all ARM devices, because Android assumes that diff --git a/compiler/optimizing/loop_optimization.h b/compiler/optimizing/loop_optimization.h index 191a93da26..9743b25259 100644 --- a/compiler/optimizing/loop_optimization.h +++ b/compiler/optimizing/loop_optimization.h @@ -27,7 +27,7 @@ namespace art { -class CompilerDriver; +class CompilerOptions; class ArchNoOptsLoopHelper; /** @@ -38,7 +38,7 @@ class ArchNoOptsLoopHelper; class HLoopOptimization : public HOptimization { public: HLoopOptimization(HGraph* graph, - CompilerDriver* compiler_driver, + const CompilerOptions* compiler_options, HInductionVarAnalysis* induction_analysis, OptimizingCompilerStats* stats, const char* name = kLoopOptimizationPassName); @@ -243,8 +243,8 @@ class HLoopOptimization : public HOptimization { void RemoveDeadInstructions(const HInstructionList& list); bool CanRemoveCycle(); // Whether the current 'iset_' is removable. - // Compiler driver (to query ISA features). - const CompilerDriver* compiler_driver_; + // Compiler options (to query ISA features). + const CompilerOptions* compiler_options_; // Range information based on prior induction variable analysis. InductionVarRange induction_range_; diff --git a/compiler/optimizing/loop_optimization_test.cc b/compiler/optimizing/loop_optimization_test.cc index c21bd65d97..c7cc661303 100644 --- a/compiler/optimizing/loop_optimization_test.cc +++ b/compiler/optimizing/loop_optimization_test.cc @@ -29,7 +29,8 @@ class LoopOptimizationTest : public OptimizingUnitTest { LoopOptimizationTest() : graph_(CreateGraph()), iva_(new (GetAllocator()) HInductionVarAnalysis(graph_)), - loop_opt_(new (GetAllocator()) HLoopOptimization(graph_, nullptr, iva_, nullptr)) { + loop_opt_(new (GetAllocator()) HLoopOptimization( + graph_, /* compiler_options */ nullptr, iva_, /* stats */ nullptr)) { BuildGraph(); } diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 975ad1c324..825779989c 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -5155,6 +5155,7 @@ class HDivZeroCheck FINAL : public HExpression<1> { SetRawInputAt(0, value); } + bool IsClonable() const OVERRIDE { return true; } bool CanBeMoved() const OVERRIDE { return true; } bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE { @@ -5606,6 +5607,7 @@ class HTypeConversion FINAL : public HExpression<1> { DataType::Type GetInputType() const { return GetInput()->GetType(); } DataType::Type GetResultType() const { return GetType(); } + bool IsClonable() const OVERRIDE { return true; } bool CanBeMoved() const OVERRIDE { return true; } bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE { return true; @@ -6641,8 +6643,7 @@ class HClinitCheck FINAL : public HExpression<1> { dex_pc) { SetRawInputAt(0, constant); } - - bool IsClonable() const OVERRIDE { return true; } + // TODO: Make ClinitCheck clonable. bool CanBeMoved() const OVERRIDE { return true; } bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE { return true; @@ -7112,6 +7113,8 @@ class HInstanceOf FINAL : public HTypeCheckInstruction { bitstring_mask, SideEffectsForArchRuntimeCalls(check_kind)) {} + bool IsClonable() const OVERRIDE { return true; } + bool NeedsEnvironment() const OVERRIDE { return CanCallRuntime(GetTypeCheckKind()); } @@ -7201,6 +7204,7 @@ class HCheckCast FINAL : public HTypeCheckInstruction { bitstring_mask, SideEffects::CanTriggerGC()) {} + bool IsClonable() const OVERRIDE { return true; } bool NeedsEnvironment() const OVERRIDE { // Instruction may throw a CheckCastError. return true; diff --git a/compiler/optimizing/optimization.cc b/compiler/optimizing/optimization.cc index d37c43db81..a38bd2464d 100644 --- a/compiler/optimizing/optimization.cc +++ b/compiler/optimizing/optimization.cc @@ -40,6 +40,7 @@ #include "constructor_fence_redundancy_elimination.h" #include "dead_code_elimination.h" #include "dex/code_item_accessors-inl.h" +#include "driver/compiler_options.h" #include "driver/dex_compilation_unit.h" #include "gvn.h" #include "induction_var_analysis.h" @@ -224,7 +225,7 @@ ArenaVector<HOptimization*> ConstructOptimizations( case OptimizationPass::kLoopOptimization: CHECK(most_recent_induction != nullptr); opt = new (allocator) HLoopOptimization( - graph, driver, most_recent_induction, stats, pass_name); + graph, &codegen->GetCompilerOptions(), most_recent_induction, stats, pass_name); break; case OptimizationPass::kBoundsCheckElimination: CHECK(most_recent_side_effects != nullptr && most_recent_induction != nullptr); @@ -286,7 +287,7 @@ ArenaVector<HOptimization*> ConstructOptimizations( break; case OptimizationPass::kScheduling: opt = new (allocator) HInstructionScheduling( - graph, driver->GetInstructionSet(), codegen, pass_name); + graph, codegen->GetCompilerOptions().GetInstructionSet(), codegen, pass_name); break; // // Arch-specific passes. diff --git a/compiler/optimizing/optimizing_cfi_test.cc b/compiler/optimizing/optimizing_cfi_test.cc index 2e189fdd14..1c1cf28294 100644 --- a/compiler/optimizing/optimizing_cfi_test.cc +++ b/compiler/optimizing/optimizing_cfi_test.cc @@ -47,25 +47,20 @@ class OptimizingCFITest : public CFITest, public OptimizingUnitTestHelper { static constexpr bool kGenerateExpected = false; OptimizingCFITest() - : pool_and_allocator_(), - opts_(), - isa_features_(), - graph_(nullptr), + : graph_(nullptr), code_gen_(), blocks_(GetAllocator()->Adapter()) {} - ArenaAllocator* GetAllocator() { return pool_and_allocator_.GetAllocator(); } - void SetUpFrame(InstructionSet isa) { + OverrideInstructionSetFeatures(isa, "default"); + // Ensure that slow-debug is off, so that there is no unexpected read-barrier check emitted. SetRuntimeDebugFlagsEnabled(false); // Setup simple context. - std::string error; - isa_features_ = InstructionSetFeatures::FromVariant(isa, "default", &error); graph_ = CreateGraph(); // Generate simple frame with some spills. - code_gen_ = CodeGenerator::Create(graph_, isa, *isa_features_, opts_); + code_gen_ = CodeGenerator::Create(graph_, *compiler_options_); code_gen_->GetAssembler()->cfi().SetEnabled(true); code_gen_->InitializeCodeGenerationData(); const int frame_size = 64; @@ -148,9 +143,6 @@ class OptimizingCFITest : public CFITest, public OptimizingUnitTestHelper { DISALLOW_COPY_AND_ASSIGN(InternalCodeAllocator); }; - ArenaPoolAndAllocator pool_and_allocator_; - CompilerOptions opts_; - std::unique_ptr<const InstructionSetFeatures> isa_features_; HGraph* graph_; std::unique_ptr<CodeGenerator> code_gen_; ArenaVector<HBasicBlock*> blocks_; diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index 79ac6b9b9d..84863e4357 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -287,7 +287,7 @@ class OptimizingCompiler FINAL : public Compiler { uintptr_t GetEntryPointOf(ArtMethod* method) const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { return reinterpret_cast<uintptr_t>(method->GetEntryPointFromQuickCompiledCodePtrSize( - InstructionSetPointerSize(GetCompilerDriver()->GetInstructionSet()))); + InstructionSetPointerSize(GetCompilerDriver()->GetCompilerOptions().GetInstructionSet()))); } void Init() OVERRIDE; @@ -460,7 +460,7 @@ bool OptimizingCompiler::RunArchOptimizations(HGraph* graph, const DexCompilationUnit& dex_compilation_unit, PassObserver* pass_observer, VariableSizedHandleScope* handles) const { - switch (GetCompilerDriver()->GetInstructionSet()) { + switch (codegen->GetCompilerOptions().GetInstructionSet()) { #if defined(ART_ENABLE_CODEGEN_arm) case InstructionSet::kThumb2: case InstructionSet::kArm: { @@ -758,7 +758,8 @@ CodeGenerator* OptimizingCompiler::TryCompile(ArenaAllocator* allocator, VariableSizedHandleScope* handles) const { MaybeRecordStat(compilation_stats_.get(), MethodCompilationStat::kAttemptBytecodeCompilation); CompilerDriver* compiler_driver = GetCompilerDriver(); - InstructionSet instruction_set = compiler_driver->GetInstructionSet(); + const CompilerOptions& compiler_options = compiler_driver->GetCompilerOptions(); + InstructionSet instruction_set = compiler_options.GetInstructionSet(); const DexFile& dex_file = *dex_compilation_unit.GetDexFile(); uint32_t method_idx = dex_compilation_unit.GetDexMethodIndex(); const DexFile::CodeItem* code_item = dex_compilation_unit.GetCodeItem(); @@ -782,7 +783,6 @@ CodeGenerator* OptimizingCompiler::TryCompile(ArenaAllocator* allocator, // Implementation of the space filter: do not compile a code item whose size in // code units is bigger than 128. static constexpr size_t kSpaceFilterOptimizingThreshold = 128; - const CompilerOptions& compiler_options = compiler_driver->GetCompilerOptions(); if ((compiler_options.GetCompilerFilter() == CompilerFilter::kSpace) && (CodeItemInstructionAccessor(dex_file, code_item).InsnsSizeInCodeUnits() > kSpaceFilterOptimizingThreshold)) { @@ -796,7 +796,7 @@ CodeGenerator* OptimizingCompiler::TryCompile(ArenaAllocator* allocator, arena_stack, dex_file, method_idx, - compiler_driver->GetInstructionSet(), + compiler_options.GetInstructionSet(), kInvalidInvokeType, compiler_driver->GetCompilerOptions().GetDebuggable(), osr); @@ -813,9 +813,7 @@ CodeGenerator* OptimizingCompiler::TryCompile(ArenaAllocator* allocator, std::unique_ptr<CodeGenerator> codegen( CodeGenerator::Create(graph, - instruction_set, - *compiler_driver->GetInstructionSetFeatures(), - compiler_driver->GetCompilerOptions(), + compiler_options, compilation_stats_.get())); if (codegen.get() == nullptr) { MaybeRecordStat(compilation_stats_.get(), MethodCompilationStat::kNotCompiledNoCodegen); @@ -903,7 +901,8 @@ CodeGenerator* OptimizingCompiler::TryCompileIntrinsic( VariableSizedHandleScope* handles) const { MaybeRecordStat(compilation_stats_.get(), MethodCompilationStat::kAttemptIntrinsicCompilation); CompilerDriver* compiler_driver = GetCompilerDriver(); - InstructionSet instruction_set = compiler_driver->GetInstructionSet(); + const CompilerOptions& compiler_options = compiler_driver->GetCompilerOptions(); + InstructionSet instruction_set = compiler_options.GetInstructionSet(); const DexFile& dex_file = *dex_compilation_unit.GetDexFile(); uint32_t method_idx = dex_compilation_unit.GetDexMethodIndex(); @@ -921,7 +920,7 @@ CodeGenerator* OptimizingCompiler::TryCompileIntrinsic( arena_stack, dex_file, method_idx, - compiler_driver->GetInstructionSet(), + compiler_driver->GetCompilerOptions().GetInstructionSet(), kInvalidInvokeType, compiler_driver->GetCompilerOptions().GetDebuggable(), /* osr */ false); @@ -932,15 +931,12 @@ CodeGenerator* OptimizingCompiler::TryCompileIntrinsic( std::unique_ptr<CodeGenerator> codegen( CodeGenerator::Create(graph, - instruction_set, - *compiler_driver->GetInstructionSetFeatures(), - compiler_driver->GetCompilerOptions(), + compiler_options, compilation_stats_.get())); if (codegen.get() == nullptr) { return nullptr; } - codegen->GetAssembler()->cfi().SetEnabled( - compiler_driver->GetCompilerOptions().GenerateAnyDebugInfo()); + codegen->GetAssembler()->cfi().SetEnabled(compiler_options.GenerateAnyDebugInfo()); PassObserver pass_observer(graph, codegen.get(), @@ -1095,7 +1091,7 @@ CompiledMethod* OptimizingCompiler::Compile(const DexFile::CodeItem* code_item, if (kIsDebugBuild && IsCompilingWithCoreImage() && - IsInstructionSetSupported(compiler_driver->GetInstructionSet())) { + IsInstructionSetSupported(compiler_driver->GetCompilerOptions().GetInstructionSet())) { // For testing purposes, we put a special marker on method names // that should be compiled with this compiler (when the // instruction set is supported). This makes sure we're not @@ -1112,7 +1108,8 @@ CompiledMethod* OptimizingCompiler::JniCompile(uint32_t access_flags, uint32_t method_idx, const DexFile& dex_file, Handle<mirror::DexCache> dex_cache) const { - if (GetCompilerDriver()->GetCompilerOptions().IsBootImage()) { + const CompilerOptions& compiler_options = GetCompilerDriver()->GetCompilerOptions(); + if (compiler_options.IsBootImage()) { ScopedObjectAccess soa(Thread::Current()); Runtime* runtime = Runtime::Current(); ArtMethod* method = runtime->GetClassLinker()->LookupResolvedMethod( @@ -1154,7 +1151,7 @@ CompiledMethod* OptimizingCompiler::JniCompile(uint32_t access_flags, } JniCompiledMethod jni_compiled_method = ArtQuickJniCompileMethod( - GetCompilerDriver(), access_flags, method_idx, dex_file); + compiler_options, access_flags, method_idx, dex_file); MaybeRecordStat(compilation_stats_.get(), MethodCompilationStat::kCompiledNativeStub); return CompiledMethod::SwapAllocCompiledMethod( GetCompilerDriver(), @@ -1218,8 +1215,9 @@ bool OptimizingCompiler::JitCompile(Thread* self, ArenaAllocator allocator(runtime->GetJitArenaPool()); if (UNLIKELY(method->IsNative())) { + const CompilerOptions& compiler_options = GetCompilerDriver()->GetCompilerOptions(); JniCompiledMethod jni_compiled_method = ArtQuickJniCompileMethod( - GetCompilerDriver(), access_flags, method_idx, *dex_file); + compiler_options, access_flags, method_idx, *dex_file); ScopedNullHandle<mirror::ObjectArray<mirror::Object>> roots; ArenaSet<ArtMethod*, std::less<ArtMethod*>> cha_single_implementation_list( allocator.Adapter(kArenaAllocCHA)); @@ -1243,7 +1241,6 @@ bool OptimizingCompiler::JitCompile(Thread* self, return false; } - const CompilerOptions& compiler_options = GetCompilerDriver()->GetCompilerOptions(); if (compiler_options.GenerateAnyDebugInfo()) { const auto* method_header = reinterpret_cast<const OatQuickMethodHeader*>(code); const uintptr_t code_address = reinterpret_cast<uintptr_t>(method_header->GetCode()); @@ -1420,8 +1417,8 @@ void OptimizingCompiler::GenerateJitDebugInfo(ArtMethod* method, debug::MethodDe // Create entry for the single method that we just compiled. std::vector<uint8_t> elf_file = debug::MakeElfFileForJIT( - GetCompilerDriver()->GetInstructionSet(), - GetCompilerDriver()->GetInstructionSetFeatures(), + compiler_options.GetInstructionSet(), + compiler_options.GetInstructionSetFeatures(), mini_debug_info, ArrayRef<const debug::MethodDebugInfo>(&info, 1)); MutexLock mu(Thread::Current(), *Locks::native_debug_interface_lock_); diff --git a/compiler/optimizing/register_allocator_test.cc b/compiler/optimizing/register_allocator_test.cc index a70b0664dc..7144775c2b 100644 --- a/compiler/optimizing/register_allocator_test.cc +++ b/compiler/optimizing/register_allocator_test.cc @@ -40,6 +40,12 @@ using Strategy = RegisterAllocator::Strategy; class RegisterAllocatorTest : public OptimizingUnitTest { protected: + void SetUp() OVERRIDE { + // This test is using the x86 ISA. + OverrideInstructionSetFeatures(InstructionSet::kX86, "default"); + OptimizingUnitTest::SetUp(); + } + // These functions need to access private variables of LocationSummary, so we declare it // as a member of RegisterAllocatorTest, which we make a friend class. void SameAsFirstInputHint(Strategy strategy); @@ -81,9 +87,7 @@ TEST_F(RegisterAllocatorTest, test_name##_GraphColor) {\ bool RegisterAllocatorTest::Check(const std::vector<uint16_t>& data, Strategy strategy) { HGraph* graph = CreateCFG(data); - std::unique_ptr<const X86InstructionSetFeatures> features_x86( - X86InstructionSetFeatures::FromCppDefines()); - x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions()); + x86::CodeGeneratorX86 codegen(graph, *compiler_options_); SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator()); liveness.Analyze(); std::unique_ptr<RegisterAllocator> register_allocator = @@ -98,9 +102,7 @@ bool RegisterAllocatorTest::Check(const std::vector<uint16_t>& data, Strategy st */ TEST_F(RegisterAllocatorTest, ValidateIntervals) { HGraph* graph = CreateGraph(); - std::unique_ptr<const X86InstructionSetFeatures> features_x86( - X86InstructionSetFeatures::FromCppDefines()); - x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions()); + x86::CodeGeneratorX86 codegen(graph, *compiler_options_); ScopedArenaVector<LiveInterval*> intervals(GetScopedAllocator()->Adapter()); // Test with two intervals of the same range. @@ -324,9 +326,7 @@ void RegisterAllocatorTest::Loop3(Strategy strategy) { Instruction::GOTO | 0xF900); HGraph* graph = CreateCFG(data); - std::unique_ptr<const X86InstructionSetFeatures> features_x86( - X86InstructionSetFeatures::FromCppDefines()); - x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions()); + x86::CodeGeneratorX86 codegen(graph, *compiler_options_); SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator()); liveness.Analyze(); std::unique_ptr<RegisterAllocator> register_allocator = @@ -359,9 +359,7 @@ TEST_F(RegisterAllocatorTest, FirstRegisterUse) { Instruction::RETURN_VOID); HGraph* graph = CreateCFG(data); - std::unique_ptr<const X86InstructionSetFeatures> features_x86( - X86InstructionSetFeatures::FromCppDefines()); - x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions()); + x86::CodeGeneratorX86 codegen(graph, *compiler_options_); SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator()); liveness.Analyze(); @@ -412,9 +410,7 @@ void RegisterAllocatorTest::DeadPhi(Strategy strategy) { HGraph* graph = CreateCFG(data); SsaDeadPhiElimination(graph).Run(); - std::unique_ptr<const X86InstructionSetFeatures> features_x86( - X86InstructionSetFeatures::FromCppDefines()); - x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions()); + x86::CodeGeneratorX86 codegen(graph, *compiler_options_); SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator()); liveness.Analyze(); std::unique_ptr<RegisterAllocator> register_allocator = @@ -438,9 +434,7 @@ TEST_F(RegisterAllocatorTest, FreeUntil) { HGraph* graph = CreateCFG(data); SsaDeadPhiElimination(graph).Run(); - std::unique_ptr<const X86InstructionSetFeatures> features_x86( - X86InstructionSetFeatures::FromCppDefines()); - x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions()); + x86::CodeGeneratorX86 codegen(graph, *compiler_options_); SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator()); liveness.Analyze(); RegisterAllocatorLinearScan register_allocator(GetScopedAllocator(), &codegen, liveness); @@ -566,9 +560,7 @@ void RegisterAllocatorTest::PhiHint(Strategy strategy) { { HGraph* graph = BuildIfElseWithPhi(&phi, &input1, &input2); - std::unique_ptr<const X86InstructionSetFeatures> features_x86( - X86InstructionSetFeatures::FromCppDefines()); - x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions()); + x86::CodeGeneratorX86 codegen(graph, *compiler_options_); SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator()); liveness.Analyze(); @@ -584,9 +576,7 @@ void RegisterAllocatorTest::PhiHint(Strategy strategy) { { HGraph* graph = BuildIfElseWithPhi(&phi, &input1, &input2); - std::unique_ptr<const X86InstructionSetFeatures> features_x86( - X86InstructionSetFeatures::FromCppDefines()); - x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions()); + x86::CodeGeneratorX86 codegen(graph, *compiler_options_); SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator()); liveness.Analyze(); @@ -604,9 +594,7 @@ void RegisterAllocatorTest::PhiHint(Strategy strategy) { { HGraph* graph = BuildIfElseWithPhi(&phi, &input1, &input2); - std::unique_ptr<const X86InstructionSetFeatures> features_x86( - X86InstructionSetFeatures::FromCppDefines()); - x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions()); + x86::CodeGeneratorX86 codegen(graph, *compiler_options_); SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator()); liveness.Analyze(); @@ -624,9 +612,7 @@ void RegisterAllocatorTest::PhiHint(Strategy strategy) { { HGraph* graph = BuildIfElseWithPhi(&phi, &input1, &input2); - std::unique_ptr<const X86InstructionSetFeatures> features_x86( - X86InstructionSetFeatures::FromCppDefines()); - x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions()); + x86::CodeGeneratorX86 codegen(graph, *compiler_options_); SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator()); liveness.Analyze(); @@ -689,9 +675,7 @@ void RegisterAllocatorTest::ExpectedInRegisterHint(Strategy strategy) { { HGraph* graph = BuildFieldReturn(&field, &ret); - std::unique_ptr<const X86InstructionSetFeatures> features_x86( - X86InstructionSetFeatures::FromCppDefines()); - x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions()); + x86::CodeGeneratorX86 codegen(graph, *compiler_options_); SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator()); liveness.Analyze(); @@ -705,9 +689,7 @@ void RegisterAllocatorTest::ExpectedInRegisterHint(Strategy strategy) { { HGraph* graph = BuildFieldReturn(&field, &ret); - std::unique_ptr<const X86InstructionSetFeatures> features_x86( - X86InstructionSetFeatures::FromCppDefines()); - x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions()); + x86::CodeGeneratorX86 codegen(graph, *compiler_options_); SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator()); liveness.Analyze(); @@ -761,9 +743,7 @@ void RegisterAllocatorTest::SameAsFirstInputHint(Strategy strategy) { { HGraph* graph = BuildTwoSubs(&first_sub, &second_sub); - std::unique_ptr<const X86InstructionSetFeatures> features_x86( - X86InstructionSetFeatures::FromCppDefines()); - x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions()); + x86::CodeGeneratorX86 codegen(graph, *compiler_options_); SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator()); liveness.Analyze(); @@ -778,9 +758,7 @@ void RegisterAllocatorTest::SameAsFirstInputHint(Strategy strategy) { { HGraph* graph = BuildTwoSubs(&first_sub, &second_sub); - std::unique_ptr<const X86InstructionSetFeatures> features_x86( - X86InstructionSetFeatures::FromCppDefines()); - x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions()); + x86::CodeGeneratorX86 codegen(graph, *compiler_options_); SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator()); liveness.Analyze(); @@ -834,9 +812,7 @@ HGraph* RegisterAllocatorTest::BuildDiv(HInstruction** div) { void RegisterAllocatorTest::ExpectedExactInRegisterAndSameOutputHint(Strategy strategy) { HInstruction *div; HGraph* graph = BuildDiv(&div); - std::unique_ptr<const X86InstructionSetFeatures> features_x86( - X86InstructionSetFeatures::FromCppDefines()); - x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions()); + x86::CodeGeneratorX86 codegen(graph, *compiler_options_); SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator()); liveness.Analyze(); @@ -934,9 +910,7 @@ TEST_F(RegisterAllocatorTest, SpillInactive) { new (GetAllocator()) LocationSummary(fourth->GetDefinedBy(), LocationSummary::kNoCall); locations->SetOut(Location::RequiresRegister()); - std::unique_ptr<const X86InstructionSetFeatures> features_x86( - X86InstructionSetFeatures::FromCppDefines()); - x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions()); + x86::CodeGeneratorX86 codegen(graph, *compiler_options_); SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator()); // Populate the instructions in the liveness object, to please the register allocator. for (size_t i = 0; i < 32; ++i) { diff --git a/compiler/optimizing/scheduler_test.cc b/compiler/optimizing/scheduler_test.cc index d4cae72c7e..7079e07ae1 100644 --- a/compiler/optimizing/scheduler_test.cc +++ b/compiler/optimizing/scheduler_test.cc @@ -192,7 +192,9 @@ class SchedulerTest : public OptimizingUnitTest { HInstructionScheduling scheduling(graph, target_config.GetInstructionSet()); scheduling.Run(/*only_optimize_loop_blocks*/ false, /*schedule_randomly*/ true); + OverrideInstructionSetFeatures(target_config.GetInstructionSet(), "default"); RunCode(target_config, + *compiler_options_, graph, [](HGraph* graph_arg) { RemoveSuspendChecks(graph_arg); }, has_result, expected); diff --git a/compiler/optimizing/ssa_liveness_analysis_test.cc b/compiler/optimizing/ssa_liveness_analysis_test.cc index ae5e4e7176..a683c698d9 100644 --- a/compiler/optimizing/ssa_liveness_analysis_test.cc +++ b/compiler/optimizing/ssa_liveness_analysis_test.cc @@ -28,18 +28,11 @@ namespace art { class SsaLivenessAnalysisTest : public OptimizingUnitTest { - public: - SsaLivenessAnalysisTest() - : graph_(CreateGraph()), - compiler_options_(), - instruction_set_(kRuntimeISA) { - std::string error_msg; - instruction_set_features_ = - InstructionSetFeatures::FromVariant(instruction_set_, "default", &error_msg); - codegen_ = CodeGenerator::Create(graph_, - instruction_set_, - *instruction_set_features_, - compiler_options_); + protected: + void SetUp() OVERRIDE { + OptimizingUnitTest::SetUp(); + graph_ = CreateGraph(); + codegen_ = CodeGenerator::Create(graph_, *compiler_options_); CHECK(codegen_ != nullptr) << instruction_set_ << " is not a supported target architecture."; // Create entry block. entry_ = new (GetAllocator()) HBasicBlock(graph_); @@ -57,9 +50,6 @@ class SsaLivenessAnalysisTest : public OptimizingUnitTest { } HGraph* graph_; - CompilerOptions compiler_options_; - InstructionSet instruction_set_; - std::unique_ptr<const InstructionSetFeatures> instruction_set_features_; std::unique_ptr<CodeGenerator> codegen_; HBasicBlock* entry_; }; diff --git a/compiler/optimizing/stack_map_stream.cc b/compiler/optimizing/stack_map_stream.cc index 57f47af777..5d361953ba 100644 --- a/compiler/optimizing/stack_map_stream.cc +++ b/compiler/optimizing/stack_map_stream.cc @@ -39,22 +39,33 @@ void StackMapStream::SetStackMapNativePcOffset(size_t i, uint32_t native_pc_offs StackMap::PackNativePc(native_pc_offset, instruction_set_); } +void StackMapStream::BeginMethod(size_t frame_size_in_bytes, + size_t core_spill_mask, + size_t fp_spill_mask, + uint32_t num_dex_registers) { + DCHECK(!in_method_) << "Mismatched Begin/End calls"; + in_method_ = true; + DCHECK_EQ(frame_size_in_bytes_, 0u) << "BeginMethod was already called"; + + frame_size_in_bytes_ = frame_size_in_bytes; + core_spill_mask_ = core_spill_mask; + fp_spill_mask_ = fp_spill_mask; + num_dex_registers_ = num_dex_registers; +} + +void StackMapStream::EndMethod() { + DCHECK(in_method_) << "Mismatched Begin/End calls"; + in_method_ = false; +} + void StackMapStream::BeginStackMapEntry(uint32_t dex_pc, uint32_t native_pc_offset, uint32_t register_mask, BitVector* stack_mask, - uint32_t num_dex_registers, - uint8_t inlining_depth, StackMap::Kind kind) { + DCHECK(in_method_) << "Call BeginMethod first"; DCHECK(!in_stack_map_) << "Mismatched Begin/End calls"; in_stack_map_ = true; - // num_dex_registers_ is the constant per-method number of registers. - // However we initially don't know what the value is, so lazily initialize it. - if (num_dex_registers_ == 0) { - num_dex_registers_ = num_dex_registers; - } else if (num_dex_registers > 0) { - DCHECK_EQ(num_dex_registers_, num_dex_registers) << "Inconsistent register count"; - } current_stack_map_ = BitTableBuilder<StackMap>::Entry(); current_stack_map_[StackMap::kKind] = static_cast<uint32_t>(kind); @@ -84,7 +95,7 @@ void StackMapStream::BeginStackMapEntry(uint32_t dex_pc, lazy_stack_masks_.push_back(stack_mask); current_inline_infos_.clear(); current_dex_registers_.clear(); - expected_num_dex_registers_ = num_dex_registers; + expected_num_dex_registers_ = num_dex_registers_; if (kVerifyStackMaps) { size_t stack_map_index = stack_maps_.size(); @@ -109,8 +120,6 @@ void StackMapStream::BeginStackMapEntry(uint32_t dex_pc, for (size_t b = 0; b < seen_stack_mask.size_in_bits(); b++) { CHECK_EQ(seen_stack_mask.LoadBit(b), stack_mask != nullptr && stack_mask->IsBitSet(b)); } - CHECK_EQ(stack_map.HasInlineInfo(), (inlining_depth != 0)); - CHECK_EQ(code_info.GetInlineDepthOf(stack_map), inlining_depth); }); } } @@ -118,9 +127,9 @@ void StackMapStream::BeginStackMapEntry(uint32_t dex_pc, void StackMapStream::EndStackMapEntry() { DCHECK(in_stack_map_) << "Mismatched Begin/End calls"; in_stack_map_ = false; - DCHECK_EQ(expected_num_dex_registers_, current_dex_registers_.size()); // Generate index into the InlineInfo table. + size_t inlining_depth = current_inline_infos_.size(); if (!current_inline_infos_.empty()) { current_inline_infos_.back()[InlineInfo::kIsLast] = InlineInfo::kLast; current_stack_map_[StackMap::kInlineInfoIndex] = @@ -128,9 +137,23 @@ void StackMapStream::EndStackMapEntry() { } // Generate delta-compressed dex register map. - CreateDexRegisterMap(); + size_t num_dex_registers = current_dex_registers_.size(); + if (!current_dex_registers_.empty()) { + DCHECK_EQ(expected_num_dex_registers_, current_dex_registers_.size()); + CreateDexRegisterMap(); + } stack_maps_.Add(current_stack_map_); + + if (kVerifyStackMaps) { + size_t stack_map_index = stack_maps_.size() - 1; + dchecks_.emplace_back([=](const CodeInfo& code_info) { + StackMap stack_map = code_info.GetStackMapAt(stack_map_index); + CHECK_EQ(stack_map.HasDexRegisterMap(), (num_dex_registers != 0)); + CHECK_EQ(stack_map.HasInlineInfo(), (inlining_depth != 0)); + CHECK_EQ(code_info.GetInlineDepthOf(stack_map), inlining_depth); + }); + } } void StackMapStream::AddInvoke(InvokeType invoke_type, uint32_t dex_method_index) { @@ -157,6 +180,7 @@ void StackMapStream::BeginInlineInfoEntry(ArtMethod* method, uint32_t dex_pc, uint32_t num_dex_registers, const DexFile* outer_dex_file) { + DCHECK(in_stack_map_) << "Call BeginStackMapEntry first"; DCHECK(!in_inline_info_) << "Mismatched Begin/End calls"; in_inline_info_ = true; DCHECK_EQ(expected_num_dex_registers_, current_dex_registers_.size()); @@ -301,7 +325,11 @@ size_t StackMapStream::PrepareForFillIn() { } } - BitMemoryWriter<ScopedArenaVector<uint8_t>> out(&out_); + EncodeUnsignedLeb128(&out_, frame_size_in_bytes_); + EncodeUnsignedLeb128(&out_, core_spill_mask_); + EncodeUnsignedLeb128(&out_, fp_spill_mask_); + EncodeUnsignedLeb128(&out_, num_dex_registers_); + BitMemoryWriter<ScopedArenaVector<uint8_t>> out(&out_, out_.size() * kBitsPerByte); stack_maps_.Encode(out); register_masks_.Encode(out); stack_masks_.Encode(out); @@ -310,24 +338,25 @@ size_t StackMapStream::PrepareForFillIn() { dex_register_masks_.Encode(out); dex_register_maps_.Encode(out); dex_register_catalog_.Encode(out); - EncodeVarintBits(out, num_dex_registers_); - return UnsignedLeb128Size(out_.size()) + out_.size(); + return out_.size(); } void StackMapStream::FillInCodeInfo(MemoryRegion region) { DCHECK(in_stack_map_ == false) << "Mismatched Begin/End calls"; DCHECK(in_inline_info_ == false) << "Mismatched Begin/End calls"; DCHECK_NE(0u, out_.size()) << "PrepareForFillIn not called before FillIn"; - DCHECK_EQ(region.size(), UnsignedLeb128Size(out_.size()) + out_.size()); + DCHECK_EQ(region.size(), out_.size()); + + region.CopyFromVector(0, out_); - uint8_t* ptr = EncodeUnsignedLeb128(region.begin(), out_.size()); - region.CopyFromVector(ptr - region.begin(), out_); + // Verify that we can load the CodeInfo and check some essentials. + CodeInfo code_info(region); + CHECK_EQ(code_info.Size(), out_.size()); + CHECK_EQ(code_info.GetNumberOfStackMaps(), stack_maps_.size()); // Verify all written data (usually only in debug builds). if (kVerifyStackMaps) { - CodeInfo code_info(region); - CHECK_EQ(code_info.GetNumberOfStackMaps(), stack_maps_.size()); for (const auto& dcheck : dchecks_) { dcheck(code_info); } diff --git a/compiler/optimizing/stack_map_stream.h b/compiler/optimizing/stack_map_stream.h index 7d1820d67f..ed865b12f7 100644 --- a/compiler/optimizing/stack_map_stream.h +++ b/compiler/optimizing/stack_map_stream.h @@ -50,8 +50,6 @@ class StackMapStream : public ValueObject { out_(allocator->Adapter(kArenaAllocStackMapStream)), method_infos_(allocator), lazy_stack_masks_(allocator->Adapter(kArenaAllocStackMapStream)), - in_stack_map_(false), - in_inline_info_(false), current_stack_map_(), current_inline_infos_(allocator->Adapter(kArenaAllocStackMapStream)), current_dex_registers_(allocator->Adapter(kArenaAllocStackMapStream)), @@ -61,12 +59,16 @@ class StackMapStream : public ValueObject { temp_dex_register_map_(allocator->Adapter(kArenaAllocStackMapStream)) { } + void BeginMethod(size_t frame_size_in_bytes, + size_t core_spill_mask, + size_t fp_spill_mask, + uint32_t num_dex_registers); + void EndMethod(); + void BeginStackMapEntry(uint32_t dex_pc, uint32_t native_pc_offset, - uint32_t register_mask, - BitVector* sp_mask, - uint32_t num_dex_registers, - uint8_t inlining_depth, + uint32_t register_mask = 0, + BitVector* sp_mask = nullptr, StackMap::Kind kind = StackMap::Kind::Default); void EndStackMapEntry(); @@ -103,6 +105,10 @@ class StackMapStream : public ValueObject { void CreateDexRegisterMap(); const InstructionSet instruction_set_; + uint32_t frame_size_in_bytes_ = 0; + uint32_t core_spill_mask_ = 0; + uint32_t fp_spill_mask_ = 0; + uint32_t num_dex_registers_ = 0; BitTableBuilder<StackMap> stack_maps_; BitTableBuilder<RegisterMask> register_masks_; BitmapTableBuilder stack_masks_; @@ -111,7 +117,6 @@ class StackMapStream : public ValueObject { BitmapTableBuilder dex_register_masks_; BitTableBuilder<MaskInfo> dex_register_maps_; BitTableBuilder<DexRegisterInfo> dex_register_catalog_; - uint32_t num_dex_registers_ = 0; // TODO: Make this const and get the value in constructor. ScopedArenaVector<uint8_t> out_; BitTableBuilderBase<1> method_infos_; @@ -119,8 +124,9 @@ class StackMapStream : public ValueObject { ScopedArenaVector<BitVector*> lazy_stack_masks_; // Variables which track the current state between Begin/End calls; - bool in_stack_map_; - bool in_inline_info_; + bool in_method_ = false; + bool in_stack_map_ = false; + bool in_inline_info_ = false; BitTableBuilder<StackMap>::Entry current_stack_map_; ScopedArenaVector<BitTableBuilder<InlineInfo>::Entry> current_inline_infos_; ScopedArenaVector<DexRegisterLocation> current_dex_registers_; diff --git a/compiler/optimizing/stack_map_test.cc b/compiler/optimizing/stack_map_test.cc index fd856671ba..6241e0c25a 100644 --- a/compiler/optimizing/stack_map_test.cc +++ b/compiler/optimizing/stack_map_test.cc @@ -52,14 +52,16 @@ TEST(StackMapTest, Test1) { ArenaStack arena_stack(&pool); ScopedArenaAllocator allocator(&arena_stack); StackMapStream stream(&allocator, kRuntimeISA); + stream.BeginMethod(32, 0, 0, 2); ArenaBitVector sp_mask(&allocator, 0, false); size_t number_of_dex_registers = 2; - stream.BeginStackMapEntry(0, 64 * kPcAlign, 0x3, &sp_mask, number_of_dex_registers, 0); + stream.BeginStackMapEntry(0, 64 * kPcAlign, 0x3, &sp_mask); stream.AddDexRegisterEntry(Kind::kInStack, 0); // Short location. stream.AddDexRegisterEntry(Kind::kConstant, -2); // Short location. stream.EndStackMapEntry(); + stream.EndMethod(); size_t size = stream.PrepareForFillIn(); void* memory = allocator.Alloc(size, kArenaAllocMisc); MemoryRegion region(memory, size); @@ -107,6 +109,7 @@ TEST(StackMapTest, Test2) { ArenaStack arena_stack(&pool); ScopedArenaAllocator allocator(&arena_stack); StackMapStream stream(&allocator, kRuntimeISA); + stream.BeginMethod(32, 0, 0, 2); ArtMethod art_method; ArenaBitVector sp_mask1(&allocator, 0, true); @@ -114,7 +117,7 @@ TEST(StackMapTest, Test2) { sp_mask1.SetBit(4); size_t number_of_dex_registers = 2; size_t number_of_dex_registers_in_inline_info = 0; - stream.BeginStackMapEntry(0, 64 * kPcAlign, 0x3, &sp_mask1, number_of_dex_registers, 2); + stream.BeginStackMapEntry(0, 64 * kPcAlign, 0x3, &sp_mask1); stream.AddDexRegisterEntry(Kind::kInStack, 0); // Short location. stream.AddDexRegisterEntry(Kind::kConstant, -2); // Large location. stream.BeginInlineInfoEntry(&art_method, 3, number_of_dex_registers_in_inline_info); @@ -126,7 +129,7 @@ TEST(StackMapTest, Test2) { ArenaBitVector sp_mask2(&allocator, 0, true); sp_mask2.SetBit(3); sp_mask2.SetBit(8); - stream.BeginStackMapEntry(1, 128 * kPcAlign, 0xFF, &sp_mask2, number_of_dex_registers, 0); + stream.BeginStackMapEntry(1, 128 * kPcAlign, 0xFF, &sp_mask2); stream.AddDexRegisterEntry(Kind::kInRegister, 18); // Short location. stream.AddDexRegisterEntry(Kind::kInFpuRegister, 3); // Short location. stream.EndStackMapEntry(); @@ -134,7 +137,7 @@ TEST(StackMapTest, Test2) { ArenaBitVector sp_mask3(&allocator, 0, true); sp_mask3.SetBit(1); sp_mask3.SetBit(5); - stream.BeginStackMapEntry(2, 192 * kPcAlign, 0xAB, &sp_mask3, number_of_dex_registers, 0); + stream.BeginStackMapEntry(2, 192 * kPcAlign, 0xAB, &sp_mask3); stream.AddDexRegisterEntry(Kind::kInRegister, 6); // Short location. stream.AddDexRegisterEntry(Kind::kInRegisterHigh, 8); // Short location. stream.EndStackMapEntry(); @@ -142,11 +145,12 @@ TEST(StackMapTest, Test2) { ArenaBitVector sp_mask4(&allocator, 0, true); sp_mask4.SetBit(6); sp_mask4.SetBit(7); - stream.BeginStackMapEntry(3, 256 * kPcAlign, 0xCD, &sp_mask4, number_of_dex_registers, 0); + stream.BeginStackMapEntry(3, 256 * kPcAlign, 0xCD, &sp_mask4); stream.AddDexRegisterEntry(Kind::kInFpuRegister, 3); // Short location, same in stack map 2. stream.AddDexRegisterEntry(Kind::kInFpuRegisterHigh, 1); // Short location. stream.EndStackMapEntry(); + stream.EndMethod(); size_t size = stream.PrepareForFillIn(); void* memory = allocator.Alloc(size, kArenaAllocMisc); MemoryRegion region(memory, size); @@ -303,6 +307,7 @@ TEST(StackMapTest, TestDeduplicateInlineInfoDexRegisterMap) { ArenaStack arena_stack(&pool); ScopedArenaAllocator allocator(&arena_stack); StackMapStream stream(&allocator, kRuntimeISA); + stream.BeginMethod(32, 0, 0, 2); ArtMethod art_method; ArenaBitVector sp_mask1(&allocator, 0, true); @@ -310,7 +315,7 @@ TEST(StackMapTest, TestDeduplicateInlineInfoDexRegisterMap) { sp_mask1.SetBit(4); const size_t number_of_dex_registers = 2; const size_t number_of_dex_registers_in_inline_info = 2; - stream.BeginStackMapEntry(0, 64 * kPcAlign, 0x3, &sp_mask1, number_of_dex_registers, 1); + stream.BeginStackMapEntry(0, 64 * kPcAlign, 0x3, &sp_mask1); stream.AddDexRegisterEntry(Kind::kInStack, 0); // Short location. stream.AddDexRegisterEntry(Kind::kConstant, -2); // Large location. stream.BeginInlineInfoEntry(&art_method, 3, number_of_dex_registers_in_inline_info); @@ -319,6 +324,7 @@ TEST(StackMapTest, TestDeduplicateInlineInfoDexRegisterMap) { stream.EndInlineInfoEntry(); stream.EndStackMapEntry(); + stream.EndMethod(); size_t size = stream.PrepareForFillIn(); void* memory = allocator.Alloc(size, kArenaAllocMisc); MemoryRegion region(memory, size); @@ -367,14 +373,16 @@ TEST(StackMapTest, TestNonLiveDexRegisters) { ArenaStack arena_stack(&pool); ScopedArenaAllocator allocator(&arena_stack); StackMapStream stream(&allocator, kRuntimeISA); + stream.BeginMethod(32, 0, 0, 2); ArenaBitVector sp_mask(&allocator, 0, false); uint32_t number_of_dex_registers = 2; - stream.BeginStackMapEntry(0, 64 * kPcAlign, 0x3, &sp_mask, number_of_dex_registers, 0); + stream.BeginStackMapEntry(0, 64 * kPcAlign, 0x3, &sp_mask); stream.AddDexRegisterEntry(Kind::kNone, 0); // No location. stream.AddDexRegisterEntry(Kind::kConstant, -2); // Large location. stream.EndStackMapEntry(); + stream.EndMethod(); size_t size = stream.PrepareForFillIn(); void* memory = allocator.Alloc(size, kArenaAllocMisc); MemoryRegion region(memory, size); @@ -416,25 +424,27 @@ TEST(StackMapTest, TestShareDexRegisterMap) { ArenaStack arena_stack(&pool); ScopedArenaAllocator allocator(&arena_stack); StackMapStream stream(&allocator, kRuntimeISA); + stream.BeginMethod(32, 0, 0, 2); ArenaBitVector sp_mask(&allocator, 0, false); uint32_t number_of_dex_registers = 2; // First stack map. - stream.BeginStackMapEntry(0, 64 * kPcAlign, 0x3, &sp_mask, number_of_dex_registers, 0); + stream.BeginStackMapEntry(0, 64 * kPcAlign, 0x3, &sp_mask); stream.AddDexRegisterEntry(Kind::kInRegister, 0); // Short location. stream.AddDexRegisterEntry(Kind::kConstant, -2); // Large location. stream.EndStackMapEntry(); // Second stack map, which should share the same dex register map. - stream.BeginStackMapEntry(0, 65 * kPcAlign, 0x3, &sp_mask, number_of_dex_registers, 0); + stream.BeginStackMapEntry(0, 65 * kPcAlign, 0x3, &sp_mask); stream.AddDexRegisterEntry(Kind::kInRegister, 0); // Short location. stream.AddDexRegisterEntry(Kind::kConstant, -2); // Large location. stream.EndStackMapEntry(); // Third stack map (doesn't share the dex register map). - stream.BeginStackMapEntry(0, 66 * kPcAlign, 0x3, &sp_mask, number_of_dex_registers, 0); + stream.BeginStackMapEntry(0, 66 * kPcAlign, 0x3, &sp_mask); stream.AddDexRegisterEntry(Kind::kInRegister, 2); // Short location. stream.AddDexRegisterEntry(Kind::kConstant, -2); // Large location. stream.EndStackMapEntry(); + stream.EndMethod(); size_t size = stream.PrepareForFillIn(); void* memory = allocator.Alloc(size, kArenaAllocMisc); MemoryRegion region(memory, size); @@ -473,17 +483,19 @@ TEST(StackMapTest, TestNoDexRegisterMap) { ArenaStack arena_stack(&pool); ScopedArenaAllocator allocator(&arena_stack); StackMapStream stream(&allocator, kRuntimeISA); + stream.BeginMethod(32, 0, 0, 1); ArenaBitVector sp_mask(&allocator, 0, false); uint32_t number_of_dex_registers = 0; - stream.BeginStackMapEntry(0, 64 * kPcAlign, 0x3, &sp_mask, number_of_dex_registers, 0); + stream.BeginStackMapEntry(0, 64 * kPcAlign, 0x3, &sp_mask); stream.EndStackMapEntry(); number_of_dex_registers = 1; - stream.BeginStackMapEntry(1, 68 * kPcAlign, 0x4, &sp_mask, number_of_dex_registers, 0); + stream.BeginStackMapEntry(1, 68 * kPcAlign, 0x4, &sp_mask); stream.AddDexRegisterEntry(Kind::kNone, 0); stream.EndStackMapEntry(); + stream.EndMethod(); size_t size = stream.PrepareForFillIn(); void* memory = allocator.Alloc(size, kArenaAllocMisc); MemoryRegion region(memory, size); @@ -521,6 +533,7 @@ TEST(StackMapTest, InlineTest) { ArenaStack arena_stack(&pool); ScopedArenaAllocator allocator(&arena_stack); StackMapStream stream(&allocator, kRuntimeISA); + stream.BeginMethod(32, 0, 0, 2); ArtMethod art_method; ArenaBitVector sp_mask1(&allocator, 0, true); @@ -528,7 +541,7 @@ TEST(StackMapTest, InlineTest) { sp_mask1.SetBit(4); // First stack map. - stream.BeginStackMapEntry(0, 10 * kPcAlign, 0x3, &sp_mask1, 2, 2); + stream.BeginStackMapEntry(0, 10 * kPcAlign, 0x3, &sp_mask1); stream.AddDexRegisterEntry(Kind::kInStack, 0); stream.AddDexRegisterEntry(Kind::kConstant, 4); @@ -544,7 +557,7 @@ TEST(StackMapTest, InlineTest) { stream.EndStackMapEntry(); // Second stack map. - stream.BeginStackMapEntry(2, 22 * kPcAlign, 0x3, &sp_mask1, 2, 3); + stream.BeginStackMapEntry(2, 22 * kPcAlign, 0x3, &sp_mask1); stream.AddDexRegisterEntry(Kind::kInStack, 56); stream.AddDexRegisterEntry(Kind::kConstant, 0); @@ -562,13 +575,13 @@ TEST(StackMapTest, InlineTest) { stream.EndStackMapEntry(); // Third stack map. - stream.BeginStackMapEntry(4, 56 * kPcAlign, 0x3, &sp_mask1, 2, 0); + stream.BeginStackMapEntry(4, 56 * kPcAlign, 0x3, &sp_mask1); stream.AddDexRegisterEntry(Kind::kNone, 0); stream.AddDexRegisterEntry(Kind::kConstant, 4); stream.EndStackMapEntry(); // Fourth stack map. - stream.BeginStackMapEntry(6, 78 * kPcAlign, 0x3, &sp_mask1, 2, 3); + stream.BeginStackMapEntry(6, 78 * kPcAlign, 0x3, &sp_mask1); stream.AddDexRegisterEntry(Kind::kInStack, 56); stream.AddDexRegisterEntry(Kind::kConstant, 0); @@ -584,6 +597,7 @@ TEST(StackMapTest, InlineTest) { stream.EndStackMapEntry(); + stream.EndMethod(); size_t size = stream.PrepareForFillIn(); void* memory = allocator.Alloc(size, kArenaAllocMisc); MemoryRegion region(memory, size); @@ -725,15 +739,17 @@ TEST(StackMapTest, TestDeduplicateStackMask) { ArenaStack arena_stack(&pool); ScopedArenaAllocator allocator(&arena_stack); StackMapStream stream(&allocator, kRuntimeISA); + stream.BeginMethod(32, 0, 0, 0); ArenaBitVector sp_mask(&allocator, 0, true); sp_mask.SetBit(1); sp_mask.SetBit(4); - stream.BeginStackMapEntry(0, 4 * kPcAlign, 0x3, &sp_mask, 0, 0); + stream.BeginStackMapEntry(0, 4 * kPcAlign, 0x3, &sp_mask); stream.EndStackMapEntry(); - stream.BeginStackMapEntry(0, 8 * kPcAlign, 0x3, &sp_mask, 0, 0); + stream.BeginStackMapEntry(0, 8 * kPcAlign, 0x3, &sp_mask); stream.EndStackMapEntry(); + stream.EndMethod(); size_t size = stream.PrepareForFillIn(); void* memory = allocator.Alloc(size, kArenaAllocMisc); MemoryRegion region(memory, size); @@ -753,19 +769,21 @@ TEST(StackMapTest, TestInvokeInfo) { ArenaStack arena_stack(&pool); ScopedArenaAllocator allocator(&arena_stack); StackMapStream stream(&allocator, kRuntimeISA); + stream.BeginMethod(32, 0, 0, 0); ArenaBitVector sp_mask(&allocator, 0, true); sp_mask.SetBit(1); - stream.BeginStackMapEntry(0, 4 * kPcAlign, 0x3, &sp_mask, 0, 0); + stream.BeginStackMapEntry(0, 4 * kPcAlign, 0x3, &sp_mask); stream.AddInvoke(kSuper, 1); stream.EndStackMapEntry(); - stream.BeginStackMapEntry(0, 8 * kPcAlign, 0x3, &sp_mask, 0, 0); + stream.BeginStackMapEntry(0, 8 * kPcAlign, 0x3, &sp_mask); stream.AddInvoke(kStatic, 3); stream.EndStackMapEntry(); - stream.BeginStackMapEntry(0, 16 * kPcAlign, 0x3, &sp_mask, 0, 0); + stream.BeginStackMapEntry(0, 16 * kPcAlign, 0x3, &sp_mask); stream.AddInvoke(kDirect, 65535); stream.EndStackMapEntry(); + stream.EndMethod(); const size_t code_info_size = stream.PrepareForFillIn(); MemoryRegion code_info_region(allocator.Alloc(code_info_size, kArenaAllocMisc), code_info_size); stream.FillInCodeInfo(code_info_region); diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index be3f922340..c9eb71d809 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -610,7 +610,6 @@ class Dex2Oat FINAL { public: explicit Dex2Oat(TimingLogger* timings) : compiler_kind_(Compiler::kOptimizing), - instruction_set_(kRuntimeISA == InstructionSet::kArm ? InstructionSet::kThumb2 : kRuntimeISA), // Take the default set of instruction features from the build. image_file_location_oat_checksum_(0), image_file_location_oat_data_begin_(0), @@ -700,25 +699,26 @@ class Dex2Oat FINAL { } void ParseInstructionSetVariant(const std::string& option, ParserOptions* parser_options) { - instruction_set_features_ = InstructionSetFeatures::FromVariant( - instruction_set_, option, &parser_options->error_msg); - if (instruction_set_features_.get() == nullptr) { + compiler_options_->instruction_set_features_ = InstructionSetFeatures::FromVariant( + compiler_options_->instruction_set_, option, &parser_options->error_msg); + if (compiler_options_->instruction_set_features_ == nullptr) { Usage("%s", parser_options->error_msg.c_str()); } } void ParseInstructionSetFeatures(const std::string& option, ParserOptions* parser_options) { - if (instruction_set_features_ == nullptr) { - instruction_set_features_ = InstructionSetFeatures::FromVariant( - instruction_set_, "default", &parser_options->error_msg); - if (instruction_set_features_.get() == nullptr) { + if (compiler_options_->instruction_set_features_ == nullptr) { + compiler_options_->instruction_set_features_ = InstructionSetFeatures::FromVariant( + compiler_options_->instruction_set_, "default", &parser_options->error_msg); + if (compiler_options_->instruction_set_features_ == nullptr) { Usage("Problem initializing default instruction set features variant: %s", parser_options->error_msg.c_str()); } } - instruction_set_features_ = - instruction_set_features_->AddFeaturesFromString(option, &parser_options->error_msg); - if (instruction_set_features_ == nullptr) { + compiler_options_->instruction_set_features_ = + compiler_options_->instruction_set_features_->AddFeaturesFromString( + option, &parser_options->error_msg); + if (compiler_options_->instruction_set_features_ == nullptr) { Usage("Error parsing '%s': %s", option.c_str(), parser_options->error_msg.c_str()); } } @@ -870,23 +870,23 @@ class Dex2Oat FINAL { // If no instruction set feature was given, use the default one for the target // instruction set. - if (instruction_set_features_.get() == nullptr) { - instruction_set_features_ = InstructionSetFeatures::FromVariant( - instruction_set_, "default", &parser_options->error_msg); - if (instruction_set_features_.get() == nullptr) { + if (compiler_options_->instruction_set_features_.get() == nullptr) { + compiler_options_->instruction_set_features_ = InstructionSetFeatures::FromVariant( + compiler_options_->instruction_set_, "default", &parser_options->error_msg); + if (compiler_options_->instruction_set_features_ == nullptr) { Usage("Problem initializing default instruction set features variant: %s", parser_options->error_msg.c_str()); } } - if (instruction_set_ == kRuntimeISA) { + if (compiler_options_->instruction_set_ == kRuntimeISA) { std::unique_ptr<const InstructionSetFeatures> runtime_features( InstructionSetFeatures::FromCppDefines()); - if (!instruction_set_features_->Equals(runtime_features.get())) { + if (!compiler_options_->GetInstructionSetFeatures()->Equals(runtime_features.get())) { LOG(WARNING) << "Mismatch between dex2oat instruction set features (" - << *instruction_set_features_ << ") and those of dex2oat executable (" - << *runtime_features <<") for the command line:\n" - << CommandLine(); + << *compiler_options_->GetInstructionSetFeatures() + << ") and those of dex2oat executable (" << *runtime_features + << ") for the command line:\n" << CommandLine(); } } @@ -896,7 +896,7 @@ class Dex2Oat FINAL { // Checks are all explicit until we know the architecture. // Set the compilation target's implicit checks options. - switch (instruction_set_) { + switch (compiler_options_->GetInstructionSet()) { case InstructionSet::kArm: case InstructionSet::kThumb2: case InstructionSet::kArm64: @@ -1215,10 +1215,10 @@ class Dex2Oat FINAL { AssignIfExists(args, M::Backend, &compiler_kind_); parser_options->requested_specific_compiler = args.Exists(M::Backend); - AssignIfExists(args, M::TargetInstructionSet, &instruction_set_); + AssignIfExists(args, M::TargetInstructionSet, &compiler_options_->instruction_set_); // arm actually means thumb2. - if (instruction_set_ == InstructionSet::kArm) { - instruction_set_ = InstructionSet::kThumb2; + if (compiler_options_->instruction_set_ == InstructionSet::kArm) { + compiler_options_->instruction_set_ = InstructionSet::kThumb2; } AssignTrueIfExists(args, M::Host, &is_host_); @@ -1628,8 +1628,6 @@ class Dex2Oat FINAL { if (!oat_writers_[i]->WriteAndOpenDexFiles( vdex_files_[i].get(), rodata_.back(), - instruction_set_, - instruction_set_features_.get(), key_value_store_.get(), verify, update_input_vdex_, @@ -1847,8 +1845,6 @@ class Dex2Oat FINAL { driver_.reset(new CompilerDriver(compiler_options_.get(), verification_results_.get(), compiler_kind_, - instruction_set_, - instruction_set_features_.get(), &compiler_options_->image_classes_, thread_count_, swap_fd_, @@ -2021,7 +2017,7 @@ class Dex2Oat FINAL { VLOG(compiler) << "App image base=" << reinterpret_cast<void*>(image_base_); } - image_writer_.reset(new linker::ImageWriter(*driver_, + image_writer_.reset(new linker::ImageWriter(*compiler_options_, image_base_, compiler_options_->GetCompilePic(), IsAppImage(), @@ -2076,8 +2072,8 @@ class Dex2Oat FINAL { { TimingLogger::ScopedTiming t2("dex2oat Write ELF", timings_); - linker::MultiOatRelativePatcher patcher(instruction_set_, - instruction_set_features_.get(), + linker::MultiOatRelativePatcher patcher(compiler_options_->GetInstructionSet(), + compiler_options_->GetInstructionSetFeatures(), driver_->GetCompiledMethodStorage()); for (size_t i = 0, size = oat_files_.size(); i != size; ++i) { std::unique_ptr<linker::ElfWriter>& elf_writer = elf_writers_[i]; @@ -2486,17 +2482,14 @@ class Dex2Oat FINAL { elf_writers_.reserve(oat_files_.size()); oat_writers_.reserve(oat_files_.size()); for (const std::unique_ptr<File>& oat_file : oat_files_) { - elf_writers_.emplace_back(linker::CreateElfWriterQuick(instruction_set_, - instruction_set_features_.get(), - compiler_options_.get(), - oat_file.get())); + elf_writers_.emplace_back(linker::CreateElfWriterQuick(*compiler_options_, oat_file.get())); elf_writers_.back()->Start(); bool do_oat_writer_layout = DoDexLayoutOptimizations() || DoOatLayoutOptimizations(); if (profile_compilation_info_ != nullptr && profile_compilation_info_->IsEmpty()) { do_oat_writer_layout = false; } oat_writers_.emplace_back(new linker::OatWriter( - IsBootImage(), + *compiler_options_, timings_, do_oat_writer_layout ? profile_compilation_info_.get() : nullptr, compact_dex_level_)); @@ -2544,7 +2537,8 @@ class Dex2Oat FINAL { raw_options.push_back(std::make_pair("compilercallbacks", callbacks)); raw_options.push_back( - std::make_pair("imageinstructionset", GetInstructionSetString(instruction_set_))); + std::make_pair("imageinstructionset", + GetInstructionSetString(compiler_options_->GetInstructionSet()))); // Only allow no boot image for the runtime if we're compiling one. When we compile an app, // we don't want fallback mode, it will abort as we do not push a boot classpath (it might @@ -2607,7 +2601,7 @@ class Dex2Oat FINAL { SetThreadName(kIsDebugBuild ? "dex2oatd" : "dex2oat"); runtime_.reset(Runtime::Current()); - runtime_->SetInstructionSet(instruction_set_); + runtime_->SetInstructionSet(compiler_options_->GetInstructionSet()); for (uint32_t i = 0; i < static_cast<uint32_t>(CalleeSaveType::kLastCalleeSaveType); ++i) { CalleeSaveType type = CalleeSaveType(i); if (!runtime_->HasCalleeSaveMethod(type)) { @@ -2802,9 +2796,6 @@ class Dex2Oat FINAL { std::unique_ptr<CompilerOptions> compiler_options_; Compiler::Kind compiler_kind_; - InstructionSet instruction_set_; - std::unique_ptr<const InstructionSetFeatures> instruction_set_features_; - uint32_t image_file_location_oat_checksum_; uintptr_t image_file_location_oat_data_begin_; int32_t image_patch_delta_; diff --git a/dex2oat/linker/arm/relative_patcher_thumb2_test.cc b/dex2oat/linker/arm/relative_patcher_thumb2_test.cc index 3fe97e146c..3d7277aab3 100644 --- a/dex2oat/linker/arm/relative_patcher_thumb2_test.cc +++ b/dex2oat/linker/arm/relative_patcher_thumb2_test.cc @@ -197,10 +197,7 @@ class Thumb2RelativePatcherTest : public RelativePatcherTest { OptimizingUnitTestHelper helper; HGraph* graph = helper.CreateGraph(); std::string error_msg; - ArmFeaturesUniquePtr features = - ArmInstructionSetFeatures::FromVariant("default", &error_msg); - CompilerOptions options; - arm::CodeGeneratorARMVIXL codegen(graph, *features, options); + arm::CodeGeneratorARMVIXL codegen(graph, *compiler_options_); ArenaVector<uint8_t> code(helper.GetAllocator()->Adapter()); codegen.EmitThunkCode(patch, &code, debug_name); return std::vector<uint8_t>(code.begin(), code.end()); diff --git a/dex2oat/linker/arm64/relative_patcher_arm64_test.cc b/dex2oat/linker/arm64/relative_patcher_arm64_test.cc index 393733dd0c..07e6860f9c 100644 --- a/dex2oat/linker/arm64/relative_patcher_arm64_test.cc +++ b/dex2oat/linker/arm64/relative_patcher_arm64_test.cc @@ -176,10 +176,7 @@ class Arm64RelativePatcherTest : public RelativePatcherTest { OptimizingUnitTestHelper helper; HGraph* graph = helper.CreateGraph(); std::string error_msg; - Arm64FeaturesUniquePtr features = - Arm64InstructionSetFeatures::FromVariant("default", &error_msg); - CompilerOptions options; - arm64::CodeGeneratorARM64 codegen(graph, *features, options); + arm64::CodeGeneratorARM64 codegen(graph, *compiler_options_); ArenaVector<uint8_t> code(helper.GetAllocator()->Adapter()); codegen.EmitThunkCode(patch, &code, debug_name); return std::vector<uint8_t>(code.begin(), code.end()); diff --git a/dex2oat/linker/elf_writer_quick.cc b/dex2oat/linker/elf_writer_quick.cc index 58bd1b0f1f..8f6ff702cc 100644 --- a/dex2oat/linker/elf_writer_quick.cc +++ b/dex2oat/linker/elf_writer_quick.cc @@ -96,9 +96,7 @@ class DebugInfoTask : public Task { template <typename ElfTypes> class ElfWriterQuick FINAL : public ElfWriter { public: - ElfWriterQuick(InstructionSet instruction_set, - const InstructionSetFeatures* features, - const CompilerOptions* compiler_options, + ElfWriterQuick(const CompilerOptions& compiler_options, File* elf_file); ~ElfWriterQuick(); @@ -129,8 +127,7 @@ class ElfWriterQuick FINAL : public ElfWriter { std::vector<uint8_t>* buffer); private: - const InstructionSetFeatures* instruction_set_features_; - const CompilerOptions* const compiler_options_; + const CompilerOptions& compiler_options_; File* const elf_file_; size_t rodata_size_; size_t text_size_; @@ -147,30 +144,18 @@ class ElfWriterQuick FINAL : public ElfWriter { DISALLOW_IMPLICIT_CONSTRUCTORS(ElfWriterQuick); }; -std::unique_ptr<ElfWriter> CreateElfWriterQuick(InstructionSet instruction_set, - const InstructionSetFeatures* features, - const CompilerOptions* compiler_options, +std::unique_ptr<ElfWriter> CreateElfWriterQuick(const CompilerOptions& compiler_options, File* elf_file) { - if (Is64BitInstructionSet(instruction_set)) { - return std::make_unique<ElfWriterQuick<ElfTypes64>>(instruction_set, - features, - compiler_options, - elf_file); + if (Is64BitInstructionSet(compiler_options.GetInstructionSet())) { + return std::make_unique<ElfWriterQuick<ElfTypes64>>(compiler_options, elf_file); } else { - return std::make_unique<ElfWriterQuick<ElfTypes32>>(instruction_set, - features, - compiler_options, - elf_file); + return std::make_unique<ElfWriterQuick<ElfTypes32>>(compiler_options, elf_file); } } template <typename ElfTypes> -ElfWriterQuick<ElfTypes>::ElfWriterQuick(InstructionSet instruction_set, - const InstructionSetFeatures* features, - const CompilerOptions* compiler_options, - File* elf_file) +ElfWriterQuick<ElfTypes>::ElfWriterQuick(const CompilerOptions& compiler_options, File* elf_file) : ElfWriter(), - instruction_set_features_(features), compiler_options_(compiler_options), elf_file_(elf_file), rodata_size_(0u), @@ -180,7 +165,9 @@ ElfWriterQuick<ElfTypes>::ElfWriterQuick(InstructionSet instruction_set, dex_section_size_(0u), output_stream_( std::make_unique<BufferedOutputStream>(std::make_unique<FileOutputStream>(elf_file))), - builder_(new ElfBuilder<ElfTypes>(instruction_set, features, output_stream_.get())) {} + builder_(new ElfBuilder<ElfTypes>(compiler_options_.GetInstructionSet(), + compiler_options_.GetInstructionSetFeatures(), + output_stream_.get())) {} template <typename ElfTypes> ElfWriterQuick<ElfTypes>::~ElfWriterQuick() {} @@ -188,7 +175,7 @@ ElfWriterQuick<ElfTypes>::~ElfWriterQuick() {} template <typename ElfTypes> void ElfWriterQuick<ElfTypes>::Start() { builder_->Start(); - if (compiler_options_->GetGenerateBuildId()) { + if (compiler_options_.GetGenerateBuildId()) { builder_->GetBuildId()->AllocateVirtualMemory(builder_->GetBuildId()->GetSize()); builder_->WriteBuildIdSection(); } @@ -272,12 +259,12 @@ void ElfWriterQuick<ElfTypes>::WriteDynamicSection() { template <typename ElfTypes> void ElfWriterQuick<ElfTypes>::PrepareDebugInfo(const debug::DebugInfo& debug_info) { - if (!debug_info.Empty() && compiler_options_->GetGenerateMiniDebugInfo()) { + if (!debug_info.Empty() && compiler_options_.GetGenerateMiniDebugInfo()) { // Prepare the mini-debug-info in background while we do other I/O. Thread* self = Thread::Current(); debug_info_task_ = std::unique_ptr<DebugInfoTask>( new DebugInfoTask(builder_->GetIsa(), - instruction_set_features_, + compiler_options_.GetInstructionSetFeatures(), builder_->GetText()->GetAddress(), text_size_, builder_->GetDex()->Exists() ? builder_->GetDex()->GetAddress() : 0, @@ -293,11 +280,11 @@ void ElfWriterQuick<ElfTypes>::PrepareDebugInfo(const debug::DebugInfo& debug_in template <typename ElfTypes> void ElfWriterQuick<ElfTypes>::WriteDebugInfo(const debug::DebugInfo& debug_info) { if (!debug_info.Empty()) { - if (compiler_options_->GetGenerateDebugInfo()) { + if (compiler_options_.GetGenerateDebugInfo()) { // Generate all the debug information we can. debug::WriteDebugInfo(builder_.get(), debug_info, kCFIFormat, true /* write_oat_patches */); } - if (compiler_options_->GetGenerateMiniDebugInfo()) { + if (compiler_options_.GetGenerateMiniDebugInfo()) { // Wait for the mini-debug-info generation to finish and write it to disk. Thread* self = Thread::Current(); DCHECK(debug_info_thread_pool_ != nullptr); @@ -310,7 +297,7 @@ void ElfWriterQuick<ElfTypes>::WriteDebugInfo(const debug::DebugInfo& debug_info template <typename ElfTypes> bool ElfWriterQuick<ElfTypes>::End() { builder_->End(); - if (compiler_options_->GetGenerateBuildId()) { + if (compiler_options_.GetGenerateBuildId()) { uint8_t build_id[ElfBuilder<ElfTypes>::kBuildIdLen]; ComputeFileBuildId(&build_id); builder_->WriteBuildId(build_id); diff --git a/dex2oat/linker/elf_writer_quick.h b/dex2oat/linker/elf_writer_quick.h index 274d18b858..333c6e3b06 100644 --- a/dex2oat/linker/elf_writer_quick.h +++ b/dex2oat/linker/elf_writer_quick.h @@ -30,9 +30,7 @@ class InstructionSetFeatures; namespace linker { -std::unique_ptr<ElfWriter> CreateElfWriterQuick(InstructionSet instruction_set, - const InstructionSetFeatures* features, - const CompilerOptions* compiler_options, +std::unique_ptr<ElfWriter> CreateElfWriterQuick(const CompilerOptions& compiler_options, File* elf_file); } // namespace linker diff --git a/dex2oat/linker/image_test.h b/dex2oat/linker/image_test.h index 66b37fb08d..fa8c7784f5 100644 --- a/dex2oat/linker/image_test.h +++ b/dex2oat/linker/image_test.h @@ -35,6 +35,7 @@ #include "compiler_callbacks.h" #include "debug/method_debug_info.h" #include "dex/quick_compiler_callbacks.h" +#include "driver/compiler_driver.h" #include "driver/compiler_options.h" #include "gc/space/image_space.h" #include "image_writer.h" @@ -211,7 +212,7 @@ inline void ImageTest::DoCompile(ImageHeader::StorageMode storage_mode, ++image_idx; } // TODO: compile_pic should be a test argument. - std::unique_ptr<ImageWriter> writer(new ImageWriter(*driver, + std::unique_ptr<ImageWriter> writer(new ImageWriter(*compiler_options_, kRequestedImageBase, /*compile_pic*/false, /*compile_app_image*/false, @@ -242,12 +243,9 @@ inline void ImageTest::DoCompile(ImageHeader::StorageMode storage_mode, std::vector<std::unique_ptr<ElfWriter>> elf_writers; std::vector<std::unique_ptr<OatWriter>> oat_writers; for (ScratchFile& oat_file : out_helper.oat_files) { - elf_writers.emplace_back(CreateElfWriterQuick(driver->GetInstructionSet(), - driver->GetInstructionSetFeatures(), - &driver->GetCompilerOptions(), - oat_file.GetFile())); + elf_writers.emplace_back(CreateElfWriterQuick(*compiler_options_, oat_file.GetFile())); elf_writers.back()->Start(); - oat_writers.emplace_back(new OatWriter(/*compiling_boot_image*/true, + oat_writers.emplace_back(new OatWriter(*compiler_options_, &timings, /*profile_compilation_info*/nullptr, CompactDexLevel::kCompactDexLevelNone)); @@ -272,8 +270,6 @@ inline void ImageTest::DoCompile(ImageHeader::StorageMode storage_mode, bool dex_files_ok = oat_writers[i]->WriteAndOpenDexFiles( out_helper.vdex_files[i].GetFile(), rodata.back(), - driver->GetInstructionSet(), - driver->GetInstructionSetFeatures(), &key_value_store, /* verify */ false, // Dex files may be dex-to-dex-ed, don't verify. /* update_input_vdex */ false, @@ -299,8 +295,8 @@ inline void ImageTest::DoCompile(ImageHeader::StorageMode storage_mode, 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(), + MultiOatRelativePatcher patcher(compiler_options_->GetInstructionSet(), + compiler_options_->GetInstructionSetFeatures(), driver->GetCompiledMethodStorage()); OatWriter* const oat_writer = oat_writers[i].get(); ElfWriter* const elf_writer = elf_writers[i].get(); @@ -381,7 +377,8 @@ inline void ImageTest::Compile(ImageHeader::StorageMode storage_mode, for (const std::string& image_class : image_classes) { image_classes_.insert(image_class); } - CreateCompilerDriver(Compiler::kOptimizing, kRuntimeISA, kIsTargetBuild ? 2U : 16U); + number_of_threads_ = kIsTargetBuild ? 2U : 16U; + CreateCompilerDriver(); // Set inline filter values. compiler_options_->SetInlineMaxCodeUnits(CompilerOptions::kDefaultInlineMaxCodeUnits); image_classes_.clear(); diff --git a/dex2oat/linker/image_writer.cc b/dex2oat/linker/image_writer.cc index bb730d3374..8778cd8adc 100644 --- a/dex2oat/linker/image_writer.cc +++ b/dex2oat/linker/image_writer.cc @@ -37,7 +37,6 @@ #include "compiled_method.h" #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" @@ -137,7 +136,7 @@ static void ClearDexFileCookies() REQUIRES_SHARED(Locks::mutator_lock_) { } bool ImageWriter::PrepareImageAddressSpace(TimingLogger* timings) { - target_ptr_size_ = InstructionSetPointerSize(compiler_driver_.GetInstructionSet()); + target_ptr_size_ = InstructionSetPointerSize(compiler_options_.GetInstructionSet()); gc::Heap* const heap = Runtime::Current()->GetHeap(); { ScopedObjectAccess soa(Thread::Current()); @@ -439,10 +438,10 @@ void ImageWriter::SetImageBinSlot(mirror::Object* object, BinSlot bin_slot) { } void ImageWriter::PrepareDexCacheArraySlots() { - // Prepare dex cache array starts based on the ordering specified in the CompilerDriver. + // Prepare dex cache array starts based on the ordering specified in the CompilerOptions. // 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_.GetCompilerOptions().GetDexFilesForOatFile()) { + for (const DexFile* dex_file : compiler_options_.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); @@ -852,8 +851,7 @@ 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_.GetCompilerOptions().IsImageClass(klass->GetDescriptor(&temp)); + result = result || !compiler_options_.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. @@ -943,7 +941,7 @@ bool ImageWriter::KeepClass(ObjPtr<mirror::Class> klass) { return true; } std::string temp; - if (!compiler_driver_.GetCompilerOptions().IsImageClass(klass->GetDescriptor(&temp))) { + if (!compiler_options_.IsImageClass(klass->GetDescriptor(&temp))) { return false; } if (compile_app_image_) { @@ -1229,7 +1227,7 @@ void ImageWriter::CheckNonImageClassesRemoved() { } void ImageWriter::DumpImageClasses() { - for (const std::string& image_class : compiler_driver_.GetCompilerOptions().GetImageClasses()) { + for (const std::string& image_class : compiler_options_.GetImageClasses()) { LOG(INFO) << " " << image_class; } } @@ -1738,7 +1736,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_.GetCompilerOptions().GetDexFilesForOatFile()) { + for (const DexFile* dex_file : compiler_options_.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; @@ -2819,7 +2817,7 @@ void ImageWriter::UpdateOatFileHeader(size_t oat_index, const OatHeader& oat_hea } ImageWriter::ImageWriter( - const CompilerDriver& compiler_driver, + const CompilerOptions& compiler_options, uintptr_t image_begin, bool compile_pic, bool compile_app_image, @@ -2827,12 +2825,12 @@ ImageWriter::ImageWriter( const std::vector<const char*>& oat_filenames, const std::unordered_map<const DexFile*, size_t>& dex_file_oat_index_map, const HashSet<std::string>* dirty_image_objects) - : compiler_driver_(compiler_driver), + : compiler_options_(compiler_options), global_image_begin_(reinterpret_cast<uint8_t*>(image_begin)), image_objects_offset_begin_(0), compile_pic_(compile_pic), compile_app_image_(compile_app_image), - target_ptr_size_(InstructionSetPointerSize(compiler_driver_.GetInstructionSet())), + target_ptr_size_(InstructionSetPointerSize(compiler_options.GetInstructionSet())), image_infos_(oat_filenames.size()), dirty_methods_(0u), clean_methods_(0u), diff --git a/dex2oat/linker/image_writer.h b/dex2oat/linker/image_writer.h index 2fcf5fd56a..4111e84df2 100644 --- a/dex2oat/linker/image_writer.h +++ b/dex2oat/linker/image_writer.h @@ -39,7 +39,6 @@ #include "base/safe_map.h" #include "base/utils.h" #include "class_table.h" -#include "driver/compiler_driver.h" #include "image.h" #include "intern_table.h" #include "lock_word.h" @@ -63,6 +62,7 @@ class ClassLoader; } // namespace mirror class ClassLoaderVisitor; +class CompilerOptions; class ImTable; class ImtConflictTable; class TimingLogger; @@ -74,7 +74,7 @@ namespace linker { // Write a Space built during compilation for use during execution. class ImageWriter FINAL { public: - ImageWriter(const CompilerDriver& compiler_driver, + ImageWriter(const CompilerOptions& compiler_options, uintptr_t image_begin, bool compile_pic, bool compile_app_image, @@ -511,9 +511,8 @@ class ImageWriter FINAL { // classes since we do not want any boot class loader classes in the image. This means that // we also cannot have any classes which refer to these boot class loader non image classes. // PruneAppImageClass also prunes if klass depends on a non-image class according to the compiler - // driver. - bool PruneAppImageClass(ObjPtr<mirror::Class> klass) - REQUIRES_SHARED(Locks::mutator_lock_); + // options. + bool PruneAppImageClass(ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_); // early_exit is true if we had a cyclic dependency anywhere down the chain. bool PruneAppImageClassInternal(ObjPtr<mirror::Class> klass, @@ -575,7 +574,7 @@ class ImageWriter FINAL { void CopyAndFixupPointer(void** target, void* value); - const CompilerDriver& compiler_driver_; + const CompilerOptions& compiler_options_; // Beginning target image address for the first image. uint8_t* global_image_begin_; diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc index 0ed9579aed..154f9ca677 100644 --- a/dex2oat/linker/oat_writer.cc +++ b/dex2oat/linker/oat_writer.cc @@ -355,7 +355,7 @@ class OatWriter::OatDexFile { DCHECK_EQ(static_cast<off_t>(file_offset + offset_), out->Seek(0, kSeekCurrent)) \ << "file_offset=" << file_offset << " offset_=" << offset_ -OatWriter::OatWriter(bool compiling_boot_image, +OatWriter::OatWriter(const CompilerOptions& compiler_options, TimingLogger* timings, ProfileCompilationInfo* info, CompactDexLevel compact_dex_level) @@ -366,9 +366,8 @@ OatWriter::OatWriter(bool compiling_boot_image, zipped_dex_files_(), zipped_dex_file_locations_(), compiler_driver_(nullptr), - compiler_options_(nullptr), + compiler_options_(compiler_options), image_writer_(nullptr), - compiling_boot_image_(compiling_boot_image), extract_dex_files_into_vdex_(true), dex_files_(nullptr), vdex_size_(0u), @@ -649,8 +648,6 @@ bool OatWriter::MayHaveCompiledMethods() const { bool OatWriter::WriteAndOpenDexFiles( File* vdex_file, OutputStream* oat_rodata, - InstructionSet instruction_set, - const InstructionSetFeatures* instruction_set_features, SafeMap<std::string, std::string>* key_value_store, bool verify, bool update_input_vdex, @@ -672,9 +669,7 @@ bool OatWriter::WriteAndOpenDexFiles( // Reserve space for Vdex header and checksums. vdex_size_ = sizeof(VdexFile::VerifierDepsHeader) + oat_dex_files_.size() * sizeof(VdexFile::VdexChecksum); - oat_size_ = InitOatHeader(instruction_set, - instruction_set_features, - dchecked_integral_cast<uint32_t>(oat_dex_files_.size()), + oat_size_ = InitOatHeader(dchecked_integral_cast<uint32_t>(oat_dex_files_.size()), key_value_store); ChecksumUpdatingOutputStream checksum_updating_rodata(oat_rodata, oat_header_.get()); @@ -708,7 +703,6 @@ 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; } @@ -719,10 +713,10 @@ void OatWriter::PrepareLayout(MultiOatRelativePatcher* relative_patcher) { relative_patcher_ = relative_patcher; SetMultiOatRelativePatcherAdjustment(); - if (compiling_boot_image_) { + if (GetCompilerOptions().IsBootImage()) { CHECK(image_writer_ != nullptr); } - InstructionSet instruction_set = compiler_driver_->GetInstructionSet(); + InstructionSet instruction_set = compiler_options_.GetInstructionSet(); CHECK_EQ(instruction_set, oat_header_->GetInstructionSet()); { @@ -769,7 +763,7 @@ void OatWriter::PrepareLayout(MultiOatRelativePatcher* relative_patcher) { bss_start_ = (bss_size_ != 0u) ? RoundUp(oat_size_, kPageSize) : 0u; CHECK_EQ(dex_files_->size(), oat_dex_files_.size()); - if (compiling_boot_image_) { + if (GetCompilerOptions().IsBootImage()) { CHECK_EQ(image_writer_ != nullptr, oat_header_->GetStoreValueByKey(OatHeader::kImageLocationKey) == nullptr); } @@ -1551,7 +1545,7 @@ class OatWriter::InitImageMethodVisitor : public OatDexMethodVisitor { size_t offset, const std::vector<const DexFile*>* dex_files) : OatDexMethodVisitor(writer, offset), - pointer_size_(GetInstructionSetPointerSize(writer_->compiler_driver_->GetInstructionSet())), + pointer_size_(GetInstructionSetPointerSize(writer_->compiler_options_.GetInstructionSet())), class_loader_(writer->HasImage() ? writer->image_writer_->GetClassLoader() : nullptr), dex_files_(dex_files), class_linker_(Runtime::Current()->GetClassLinker()) {} @@ -1619,7 +1613,7 @@ class OatWriter::InitImageMethodVisitor : public OatDexMethodVisitor { Thread* self = Thread::Current(); ObjPtr<mirror::DexCache> dex_cache = class_linker_->FindDexCache(self, *dex_file_); ArtMethod* method; - if (writer_->HasBootImage()) { + if (writer_->GetCompilerOptions().IsBootImage()) { const InvokeType invoke_type = it.GetMethodInvokeType( dex_file_->GetClassDef(class_def_index_)); // Unchecked as we hold mutator_lock_ on entry. @@ -1702,7 +1696,7 @@ class OatWriter::WriteCodeMethodVisitor : public OrderedMethodVisitor { writer_(writer), offset_(relative_offset), dex_file_(nullptr), - pointer_size_(GetInstructionSetPointerSize(writer_->compiler_driver_->GetInstructionSet())), + pointer_size_(GetInstructionSetPointerSize(writer_->compiler_options_.GetInstructionSet())), class_loader_(writer->HasImage() ? writer->image_writer_->GetClassLoader() : nullptr), out_(out), file_offset_(file_offset), @@ -1710,7 +1704,7 @@ class OatWriter::WriteCodeMethodVisitor : public OrderedMethodVisitor { dex_cache_(nullptr), no_thread_suspension_("OatWriter patching") { patched_code_.reserve(16 * KB); - if (writer_->HasBootImage()) { + if (writer_->GetCompilerOptions().IsBootImage()) { // If we're creating the image, the address space must be ready so that we can apply patches. CHECK(writer_->image_writer_->IsImageAddressSpaceReady()); } @@ -1958,7 +1952,7 @@ class OatWriter::WriteCodeMethodVisitor : public OrderedMethodVisitor { const void* oat_code_offset = target->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size_); if (oat_code_offset != 0) { - DCHECK(!writer_->HasBootImage()); + DCHECK(!writer_->GetCompilerOptions().IsBootImage()); DCHECK(!Runtime::Current()->GetClassLinker()->IsQuickResolutionStub(oat_code_offset)); DCHECK(!Runtime::Current()->GetClassLinker()->IsQuickToInterpreterBridge(oat_code_offset)); DCHECK(!Runtime::Current()->GetClassLinker()->IsQuickGenericJniStub(oat_code_offset)); @@ -1995,13 +1989,13 @@ class OatWriter::WriteCodeMethodVisitor : public OrderedMethodVisitor { ObjPtr<mirror::String> string = linker->LookupString(patch.TargetStringIndex(), GetDexCache(patch.TargetStringDexFile())); DCHECK(string != nullptr); - DCHECK(writer_->HasBootImage() || + DCHECK(writer_->GetCompilerOptions().IsBootImage() || Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(string)); return string; } uint32_t GetTargetMethodOffset(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) { - DCHECK(writer_->HasBootImage()); + DCHECK(writer_->GetCompilerOptions().IsBootImage()); method = writer_->image_writer_->GetImageMethodAddress(method); size_t oat_index = writer_->image_writer_->GetOatIndexForDexFile(dex_file_); uintptr_t oat_data_begin = writer_->image_writer_->GetOatDataBegin(oat_index); @@ -2011,7 +2005,7 @@ class OatWriter::WriteCodeMethodVisitor : public OrderedMethodVisitor { uint32_t GetTargetObjectOffset(ObjPtr<mirror::Object> object) REQUIRES_SHARED(Locks::mutator_lock_) { - DCHECK(writer_->HasBootImage()); + DCHECK(writer_->GetCompilerOptions().IsBootImage()); object = writer_->image_writer_->GetImageAddress(object.Ptr()); size_t oat_index = writer_->image_writer_->GetOatIndexForDexFile(dex_file_); uintptr_t oat_data_begin = writer_->image_writer_->GetOatDataBegin(oat_index); @@ -2021,7 +2015,7 @@ class OatWriter::WriteCodeMethodVisitor : public OrderedMethodVisitor { void PatchObjectAddress(std::vector<uint8_t>* code, uint32_t offset, mirror::Object* object) REQUIRES_SHARED(Locks::mutator_lock_) { - if (writer_->HasBootImage()) { + if (writer_->GetCompilerOptions().IsBootImage()) { object = writer_->image_writer_->GetImageAddress(object); } else { // NOTE: We're using linker patches for app->boot references when the image can @@ -2042,7 +2036,7 @@ class OatWriter::WriteCodeMethodVisitor : public OrderedMethodVisitor { void PatchCodeAddress(std::vector<uint8_t>* code, uint32_t offset, uint32_t target_offset) REQUIRES_SHARED(Locks::mutator_lock_) { uint32_t address = target_offset; - if (writer_->HasBootImage()) { + if (writer_->GetCompilerOptions().IsBootImage()) { size_t oat_index = writer_->image_writer_->GetOatIndexForDexCache(dex_cache_); // TODO: Clean up offset types. // The target_offset must be treated as signed for cross-oat patching. @@ -2212,13 +2206,11 @@ bool OatWriter::VisitDexMethods(DexMethodVisitor* visitor) { return true; } -size_t OatWriter::InitOatHeader(InstructionSet instruction_set, - const InstructionSetFeatures* instruction_set_features, - uint32_t num_dex_files, +size_t OatWriter::InitOatHeader(uint32_t num_dex_files, SafeMap<std::string, std::string>* key_value_store) { TimingLogger::ScopedTiming split("InitOatHeader", timings_); - oat_header_.reset(OatHeader::Create(instruction_set, - instruction_set_features, + oat_header_.reset(OatHeader::Create(GetCompilerOptions().GetInstructionSet(), + GetCompilerOptions().GetInstructionSetFeatures(), num_dex_files, key_value_store)); size_oat_header_ += sizeof(OatHeader); @@ -2399,7 +2391,7 @@ size_t OatWriter::InitOatCode(size_t offset) { oat_header_->SetInterpreterToInterpreterBridgeOffset(0); oat_header_->SetInterpreterToCompiledCodeBridgeOffset(0); if (GetCompilerOptions().IsBootImage()) { - InstructionSet instruction_set = compiler_driver_->GetInstructionSet(); + InstructionSet instruction_set = compiler_options_.GetInstructionSet(); const bool generate_debug_info = GetCompilerOptions().GenerateAnyDebugInfo(); size_t adjusted_offset = offset; @@ -2522,7 +2514,7 @@ void OatWriter::InitBssLayout(InstructionSet instruction_set) { } DCHECK_EQ(bss_size_, 0u); - if (HasBootImage()) { + if (GetCompilerOptions().IsBootImage()) { DCHECK(bss_string_entries_.empty()); } if (bss_method_entries_.empty() && @@ -3294,7 +3286,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 (GetCompilerOptions().IsBootImage()) { - InstructionSet instruction_set = compiler_driver_->GetInstructionSet(); + InstructionSet instruction_set = compiler_options_.GetInstructionSet(); #define DO_TRAMPOLINE(field) \ do { \ @@ -3652,7 +3644,7 @@ bool OatWriter::LayoutAndWriteDexFile(OutputStream* out, OatDexFile* oat_dex_fil dex_file = dex_file_loader.Open(location, zip_entry->GetCrc32(), std::move(mem_map), - /* verify */ !compiling_boot_image_, + /* verify */ !GetCompilerOptions().IsBootImage(), /* verify_checksum */ true, &error_msg); } else if (oat_dex_file->source_.IsRawFile()) { @@ -3664,7 +3656,7 @@ bool OatWriter::LayoutAndWriteDexFile(OutputStream* out, OatDexFile* oat_dex_fil } TimingLogger::ScopedTiming extract("Open", timings_); dex_file = dex_file_loader.OpenDex(dup_fd, location, - /* verify */ !compiling_boot_image_, + /* verify */ !GetCompilerOptions().IsBootImage(), /* verify_checksum */ true, /* mmap_shared */ false, &error_msg); diff --git a/dex2oat/linker/oat_writer.h b/dex2oat/linker/oat_writer.h index e8eee88bcd..298859bb38 100644 --- a/dex2oat/linker/oat_writer.h +++ b/dex2oat/linker/oat_writer.h @@ -124,7 +124,7 @@ class OatWriter { kDefault = kCreate }; - OatWriter(bool compiling_boot_image, + OatWriter(const CompilerOptions& compiler_options, TimingLogger* timings, ProfileCompilationInfo* info, CompactDexLevel compact_dex_level); @@ -178,8 +178,6 @@ class OatWriter { // and the compiler will just re-use the existing vdex file. bool WriteAndOpenDexFiles(File* vdex_file, OutputStream* oat_rodata, - InstructionSet instruction_set, - const InstructionSetFeatures* instruction_set_features, SafeMap<std::string, std::string>* key_value_store, bool verify, bool update_input_vdex, @@ -217,10 +215,6 @@ class OatWriter { return image_writer_ != nullptr; } - bool HasBootImage() const { - return compiling_boot_image_; - } - const OatHeader& GetOatHeader() const { return *oat_header_; } @@ -266,8 +260,7 @@ class OatWriter { } const CompilerOptions& GetCompilerOptions() const { - DCHECK(compiler_options_ != nullptr); - return *compiler_options_; + return compiler_options_; } private: @@ -332,10 +325,7 @@ class OatWriter { /*out*/ std::vector<std::unique_ptr<MemMap>>* opened_dex_files_map, /*out*/ std::vector<std::unique_ptr<const DexFile>>* opened_dex_files); - size_t InitOatHeader(InstructionSet instruction_set, - const InstructionSetFeatures* instruction_set_features, - uint32_t num_dex_files, - SafeMap<std::string, std::string>* key_value_store); + size_t InitOatHeader(uint32_t num_dex_files, SafeMap<std::string, std::string>* key_value_store); size_t InitClassOffsets(size_t offset); size_t InitOatClasses(size_t offset); size_t InitOatMaps(size_t offset); @@ -395,9 +385,8 @@ class OatWriter { dchecked_vector<debug::MethodDebugInfo> method_info_; const CompilerDriver* compiler_driver_; - const CompilerOptions* compiler_options_; + 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. bool extract_dex_files_into_vdex_; diff --git a/dex2oat/linker/oat_writer_test.cc b/dex2oat/linker/oat_writer_test.cc index e43a7f3d0c..7aa1ebb98e 100644 --- a/dex2oat/linker/oat_writer_test.cc +++ b/dex2oat/linker/oat_writer_test.cc @@ -86,33 +86,17 @@ class OatTest : public CommonCompilerTest { } } - void SetupCompiler(Compiler::Kind compiler_kind, - InstructionSet insn_set, - const std::vector<std::string>& compiler_options, - /*out*/std::string* error_msg) { - ASSERT_TRUE(error_msg != nullptr); - insn_features_ = InstructionSetFeatures::FromVariant(insn_set, "default", error_msg); - ASSERT_TRUE(insn_features_ != nullptr) << *error_msg; - compiler_options_.reset(new CompilerOptions); + void SetupCompiler(const std::vector<std::string>& compiler_options) { + std::string error_msg; if (!compiler_options_->ParseCompilerOptions(compiler_options, false /* ignore_unrecognized */, - error_msg)) { - LOG(FATAL) << *error_msg; + &error_msg)) { + LOG(FATAL) << error_msg; UNREACHABLE(); } - verification_results_.reset(new VerificationResults(compiler_options_.get())); callbacks_.reset(new QuickCompilerCallbacks(CompilerCallbacks::CallbackMode::kCompileApp)); callbacks_->SetVerificationResults(verification_results_.get()); Runtime::Current()->SetCompilerCallbacks(callbacks_.get()); - compiler_driver_.reset(new CompilerDriver(compiler_options_.get(), - verification_results_.get(), - compiler_kind, - insn_set, - insn_features_.get(), - /* image_classes */ nullptr, - /* thread_count */ 2, - /* swap_fd */ -1, - /* profile_compilation_info */ nullptr)); } bool WriteElf(File* vdex_file, @@ -121,7 +105,8 @@ class OatTest : public CommonCompilerTest { SafeMap<std::string, std::string>& key_value_store, bool verify) { TimingLogger timings("WriteElf", false, false); - OatWriter oat_writer(/*compiling_boot_image*/false, + ClearBootImageOption(); + OatWriter oat_writer(*compiler_options_, &timings, /*profile_compilation_info*/nullptr, CompactDexLevel::kCompactDexLevelNone); @@ -145,7 +130,8 @@ class OatTest : public CommonCompilerTest { bool verify, ProfileCompilationInfo* profile_compilation_info) { TimingLogger timings("WriteElf", false, false); - OatWriter oat_writer(/*compiling_boot_image*/false, + ClearBootImageOption(); + OatWriter oat_writer(*compiler_options_, &timings, profile_compilation_info, CompactDexLevel::kCompactDexLevelNone); @@ -164,7 +150,8 @@ class OatTest : public CommonCompilerTest { SafeMap<std::string, std::string>& key_value_store, bool verify) { TimingLogger timings("WriteElf", false, false); - OatWriter oat_writer(/*compiling_boot_image*/false, + ClearBootImageOption(); + OatWriter oat_writer(*compiler_options_, &timings, /*profile_compilation_info*/nullptr, CompactDexLevel::kCompactDexLevelNone); @@ -180,9 +167,7 @@ class OatTest : public CommonCompilerTest { SafeMap<std::string, std::string>& key_value_store, bool verify) { std::unique_ptr<ElfWriter> elf_writer = CreateElfWriterQuick( - compiler_driver_->GetInstructionSet(), - compiler_driver_->GetInstructionSetFeatures(), - &compiler_driver_->GetCompilerOptions(), + compiler_driver_->GetCompilerOptions(), oat_file); elf_writer->Start(); OutputStream* oat_rodata = elf_writer->StartRoData(); @@ -191,8 +176,6 @@ class OatTest : public CommonCompilerTest { if (!oat_writer.WriteAndOpenDexFiles( vdex_file, oat_rodata, - compiler_driver_->GetInstructionSet(), - compiler_driver_->GetInstructionSetFeatures(), &key_value_store, verify, /* update_input_vdex */ false, @@ -210,8 +193,8 @@ class OatTest : public CommonCompilerTest { ScopedObjectAccess soa(Thread::Current()); class_linker->RegisterDexFile(*dex_file, nullptr); } - MultiOatRelativePatcher patcher(compiler_driver_->GetInstructionSet(), - instruction_set_features_.get(), + MultiOatRelativePatcher patcher(compiler_options_->GetInstructionSet(), + compiler_options_->GetInstructionSetFeatures(), compiler_driver_->GetCompiledMethodStorage()); oat_writer.Initialize(compiler_driver_.get(), nullptr, dex_files); oat_writer.PrepareLayout(&patcher); @@ -278,7 +261,6 @@ class OatTest : public CommonCompilerTest { void TestZipFileInput(bool verify); void TestZipFileInputWithEmptyDex(); - std::unique_ptr<const InstructionSetFeatures> insn_features_; std::unique_ptr<QuickCompilerCallbacks> callbacks_; std::vector<std::unique_ptr<MemMap>> opened_dex_files_maps_; @@ -400,11 +382,8 @@ TEST_F(OatTest, WriteRead) { TimingLogger timings("OatTest::WriteRead", false, false); ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - // TODO: make selectable. - Compiler::Kind compiler_kind = Compiler::kQuick; - InstructionSet insn_set = kIsTargetBuild ? InstructionSet::kThumb2 : InstructionSet::kX86; std::string error_msg; - SetupCompiler(compiler_kind, insn_set, std::vector<std::string>(), /*out*/ &error_msg); + SetupCompiler(std::vector<std::string>()); jobject class_loader = nullptr; if (kCompile) { @@ -446,8 +425,8 @@ TEST_F(OatTest, WriteRead) { ASSERT_TRUE(java_lang_dex_file_ != nullptr); const DexFile& dex_file = *java_lang_dex_file_; uint32_t dex_file_checksum = dex_file.GetLocationChecksum(); - const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation().c_str(), - &dex_file_checksum); + const OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation().c_str(), + &dex_file_checksum); ASSERT_TRUE(oat_dex_file != nullptr); CHECK_EQ(dex_file.GetLocationChecksum(), oat_dex_file->GetDexFileLocationChecksum()); ScopedObjectAccess soa(Thread::Current()); @@ -524,14 +503,9 @@ TEST_F(OatTest, OatHeaderIsValid) { TEST_F(OatTest, EmptyTextSection) { TimingLogger timings("OatTest::EmptyTextSection", false, false); - // TODO: make selectable. - Compiler::Kind compiler_kind = Compiler::kQuick; - InstructionSet insn_set = kRuntimeISA; - if (insn_set == InstructionSet::kArm) insn_set = InstructionSet::kThumb2; - std::string error_msg; std::vector<std::string> compiler_options; compiler_options.push_back("--compiler-filter=extract"); - SetupCompiler(compiler_kind, insn_set, compiler_options, /*out*/ &error_msg); + SetupCompiler(compiler_options); jobject class_loader; { @@ -560,6 +534,7 @@ TEST_F(OatTest, EmptyTextSection) { /* verify */ false); ASSERT_TRUE(success); + std::string error_msg; std::unique_ptr<OatFile> oat_file(OatFile::Open(/* zip_fd */ -1, tmp_oat.GetFilename(), tmp_oat.GetFilename(), diff --git a/dex2oat/linker/relative_patcher_test.h b/dex2oat/linker/relative_patcher_test.h index b4123eea3e..ae58b54863 100644 --- a/dex2oat/linker/relative_patcher_test.h +++ b/dex2oat/linker/relative_patcher_test.h @@ -22,6 +22,7 @@ #include "base/array_ref.h" #include "base/globals.h" #include "base/macros.h" +#include "common_compiler_test.h" #include "compiled_method-inl.h" #include "dex/verification_results.h" #include "dex/method_reference.h" @@ -38,38 +39,40 @@ namespace art { namespace linker { // Base class providing infrastructure for architecture-specific tests. -class RelativePatcherTest : public testing::Test { +class RelativePatcherTest : public CommonCompilerTest { protected: RelativePatcherTest(InstructionSet instruction_set, const std::string& variant) - : compiler_options_(), - verification_results_(&compiler_options_), - driver_(&compiler_options_, - &verification_results_, - Compiler::kQuick, - instruction_set, - /* instruction_set_features*/ nullptr, - /* image_classes */ nullptr, - /* thread_count */ 1u, - /* swap_fd */ -1, - /* profile_compilation_info */ nullptr), - error_msg_(), - instruction_set_(instruction_set), - features_(InstructionSetFeatures::FromVariant(instruction_set, variant, &error_msg_)), + : variant_(variant), method_offset_map_(), - patcher_(RelativePatcher::Create(instruction_set, - features_.get(), - &thunk_provider_, - &method_offset_map_)), + patcher_(nullptr), bss_begin_(0u), compiled_method_refs_(), compiled_methods_(), patched_code_(), output_(), out_("test output stream", &output_) { - CHECK(error_msg_.empty()) << instruction_set << "/" << variant; + // Override CommonCompilerTest's defaults. + instruction_set_ = instruction_set; + number_of_threads_ = 1u; patched_code_.reserve(16 * KB); } + void SetUp() OVERRIDE { + OverrideInstructionSetFeatures(instruction_set_, variant_); + CommonCompilerTest::SetUp(); + + patcher_ = RelativePatcher::Create(compiler_options_->GetInstructionSet(), + compiler_options_->GetInstructionSetFeatures(), + &thunk_provider_, + &method_offset_map_); + } + + void TearDown() OVERRIDE { + compiled_methods_.clear(); + patcher_.reset(); + CommonCompilerTest::TearDown(); + } + MethodReference MethodRef(uint32_t method_idx) { CHECK_NE(method_idx, 0u); return MethodReference(nullptr, method_idx); @@ -81,7 +84,7 @@ class RelativePatcherTest : public testing::Test { const ArrayRef<const LinkerPatch>& patches = ArrayRef<const LinkerPatch>()) { compiled_method_refs_.push_back(method_ref); compiled_methods_.emplace_back(new CompiledMethod( - &driver_, + compiler_driver_.get(), instruction_set_, code, /* frame_size_in_bytes */ 0u, @@ -333,12 +336,7 @@ class RelativePatcherTest : public testing::Test { static const uint32_t kTrampolineSize = 4u; static const uint32_t kTrampolineOffset = 0u; - CompilerOptions compiler_options_; - VerificationResults verification_results_; - CompilerDriver driver_; // Needed for constructing CompiledMethod. - std::string error_msg_; - InstructionSet instruction_set_; - std::unique_ptr<const InstructionSetFeatures> features_; + std::string variant_; ThunkProvider thunk_provider_; MethodOffsetMap method_offset_map_; std::unique_ptr<RelativePatcher> patcher_; diff --git a/libartbase/base/bit_memory_region.h b/libartbase/base/bit_memory_region.h index 6e491b0868..07c1611c60 100644 --- a/libartbase/base/bit_memory_region.h +++ b/libartbase/base/bit_memory_region.h @@ -57,6 +57,15 @@ class BitMemoryRegion FINAL : public ValueObject { return result; } + // Increase the size of the region and return the newly added range (starting at the old end). + ALWAYS_INLINE BitMemoryRegion Extend(size_t bit_length) { + BitMemoryRegion result = *this; + result.bit_start_ += result.bit_size_; + result.bit_size_ = bit_length; + bit_size_ += bit_length; + return result; + } + // Load a single bit in the region. The bit at offset 0 is the least // significant bit in the first byte. ATTRIBUTE_NO_SANITIZE_ADDRESS // We might touch extra bytes due to the alignment. @@ -167,26 +176,26 @@ class BitMemoryRegion FINAL : public ValueObject { class BitMemoryReader { public: - explicit BitMemoryReader(BitMemoryRegion region, size_t bit_offset = 0) - : region_(region), bit_offset_(bit_offset) { } + explicit BitMemoryReader(const uint8_t* data, size_t bit_offset = 0) { + MemoryRegion region(const_cast<uint8_t*>(data), BitsToBytesRoundUp(bit_offset)); + finished_region_ = BitMemoryRegion(region, 0, bit_offset); + DCHECK_EQ(GetBitOffset(), bit_offset); + } - size_t GetBitOffset() const { return bit_offset_; } + size_t GetBitOffset() const { return finished_region_.size_in_bits(); } ALWAYS_INLINE BitMemoryRegion Skip(size_t bit_length) { - BitMemoryRegion result = region_.Subregion(bit_offset_, bit_length); - bit_offset_ += bit_length; - return result; + return finished_region_.Extend(bit_length); } ALWAYS_INLINE uint32_t ReadBits(size_t bit_length) { - uint32_t result = region_.LoadBits(bit_offset_, bit_length); - bit_offset_ += bit_length; - return result; + return finished_region_.Extend(bit_length).LoadBits(0, bit_length); } private: - BitMemoryRegion region_; - size_t bit_offset_; + // Represents all of the bits which were read so far. There is no upper bound. + // Therefore, by definition, the "cursor" is always at the end of the region. + BitMemoryRegion finished_region_; DISALLOW_COPY_AND_ASSIGN(BitMemoryReader); }; @@ -195,7 +204,11 @@ template<typename Vector> class BitMemoryWriter { public: explicit BitMemoryWriter(Vector* out, size_t bit_offset = 0) - : out_(out), bit_offset_(bit_offset) { } + : out_(out), bit_offset_(bit_offset) { + DCHECK_EQ(GetBitOffset(), bit_offset); + } + + const uint8_t* data() const { return out_->data(); } size_t GetBitOffset() const { return bit_offset_; } @@ -210,10 +223,6 @@ class BitMemoryWriter { Allocate(bit_length).StoreBits(0, value, bit_length); } - BitMemoryRegion GetWrittenRegion() const { - return BitMemoryRegion(MemoryRegion(out_->data(), out_->size()), 0, bit_offset_); - } - private: Vector* out_; size_t bit_offset_; diff --git a/libartbase/base/bit_table.h b/libartbase/base/bit_table.h index 418d7c4251..b0fc4d1d1b 100644 --- a/libartbase/base/bit_table.h +++ b/libartbase/base/bit_table.h @@ -355,7 +355,7 @@ class BitTableBuilderBase { // Verify the written data. if (kIsDebugBuild) { BitTableBase<kNumColumns> table; - BitMemoryReader reader(out.GetWrittenRegion(), initial_bit_offset); + BitMemoryReader reader(out.data(), initial_bit_offset); table.Decode(reader); DCHECK_EQ(size(), table.NumRows()); for (uint32_t c = 0; c < kNumColumns; c++) { @@ -441,7 +441,7 @@ class BitmapTableBuilder { // Verify the written data. if (kIsDebugBuild) { BitTableBase<1> table; - BitMemoryReader reader(out.GetWrittenRegion(), initial_bit_offset); + BitMemoryReader reader(out.data(), initial_bit_offset); table.Decode(reader); DCHECK_EQ(size(), table.NumRows()); DCHECK_EQ(max_num_bits_, table.NumColumnBits(0)); diff --git a/libartbase/base/bit_table_test.cc b/libartbase/base/bit_table_test.cc index a6941487b2..2fd9052516 100644 --- a/libartbase/base/bit_table_test.cc +++ b/libartbase/base/bit_table_test.cc @@ -34,7 +34,7 @@ TEST(BitTableTest, TestVarint) { BitMemoryWriter<std::vector<uint8_t>> writer(&buffer, start_bit_offset); EncodeVarintBits(writer, value); - BitMemoryReader reader(writer.GetWrittenRegion(), start_bit_offset); + BitMemoryReader reader(buffer.data(), start_bit_offset); uint32_t result = DecodeVarintBits(reader); EXPECT_EQ(writer.GetBitOffset(), reader.GetBitOffset()); EXPECT_EQ(value, result); @@ -52,7 +52,7 @@ TEST(BitTableTest, TestEmptyTable) { BitTableBuilderBase<1> builder(&allocator); builder.Encode(writer); - BitMemoryReader reader(writer.GetWrittenRegion()); + BitMemoryReader reader(buffer.data()); BitTableBase<1> table(reader); EXPECT_EQ(writer.GetBitOffset(), reader.GetBitOffset()); EXPECT_EQ(0u, table.NumRows()); @@ -73,7 +73,7 @@ TEST(BitTableTest, TestSingleColumnTable) { builder.Add({kNoValue}); builder.Encode(writer); - BitMemoryReader reader(writer.GetWrittenRegion()); + BitMemoryReader reader(buffer.data()); BitTableBase<1> table(reader); EXPECT_EQ(writer.GetBitOffset(), reader.GetBitOffset()); EXPECT_EQ(4u, table.NumRows()); @@ -96,7 +96,7 @@ TEST(BitTableTest, TestUnalignedTable) { builder.Add({42u}); builder.Encode(writer); - BitMemoryReader reader(writer.GetWrittenRegion(), start_bit_offset); + BitMemoryReader reader(buffer.data(), start_bit_offset); BitTableBase<1> table(reader); EXPECT_EQ(writer.GetBitOffset(), reader.GetBitOffset()); EXPECT_EQ(1u, table.NumRows()); @@ -117,7 +117,7 @@ TEST(BitTableTest, TestBigTable) { builder.Add({62u, kNoValue, 63u, static_cast<uint32_t>(-3)}); builder.Encode(writer); - BitMemoryReader reader(writer.GetWrittenRegion()); + BitMemoryReader reader(buffer.data()); BitTableBase<4> table(reader); EXPECT_EQ(writer.GetBitOffset(), reader.GetBitOffset()); EXPECT_EQ(2u, table.NumRows()); @@ -167,7 +167,7 @@ TEST(BitTableTest, TestBitmapTable) { builder.Encode(writer); EXPECT_EQ(1 + static_cast<uint32_t>(POPCOUNT(value)), builder.size()); - BitMemoryReader reader(writer.GetWrittenRegion()); + BitMemoryReader reader(buffer.data()); BitTableBase<1> table(reader); EXPECT_EQ(writer.GetBitOffset(), reader.GetBitOffset()); for (auto it : indicies) { diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index 2b0095ce27..21ce8c84c4 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -115,10 +115,9 @@ const char* image_roots_descriptions_[] = { }; // Map is so that we don't allocate multiple dex files for the same OatDexFile. -static std::map<const OatFile::OatDexFile*, - std::unique_ptr<const DexFile>> opened_dex_files; +static std::map<const OatDexFile*, std::unique_ptr<const DexFile>> opened_dex_files; -const DexFile* OpenDexFile(const OatFile::OatDexFile* oat_dex_file, std::string* error_msg) { +const DexFile* OpenDexFile(const OatDexFile* oat_dex_file, std::string* error_msg) { DCHECK(oat_dex_file != nullptr); auto it = opened_dex_files.find(oat_dex_file); if (it != opened_dex_files.end()) { @@ -240,15 +239,15 @@ class OatSymbolizer FINAL { } void Walk() { - std::vector<const OatFile::OatDexFile*> oat_dex_files = oat_file_->GetOatDexFiles(); + std::vector<const OatDexFile*> oat_dex_files = oat_file_->GetOatDexFiles(); for (size_t i = 0; i < oat_dex_files.size(); i++) { - const OatFile::OatDexFile* oat_dex_file = oat_dex_files[i]; + const OatDexFile* oat_dex_file = oat_dex_files[i]; CHECK(oat_dex_file != nullptr); WalkOatDexFile(oat_dex_file); } } - void WalkOatDexFile(const OatFile::OatDexFile* oat_dex_file) { + void WalkOatDexFile(const OatDexFile* oat_dex_file) { std::string error_msg; const DexFile* const dex_file = OpenDexFile(oat_dex_file, &error_msg); if (dex_file == nullptr) { @@ -529,7 +528,7 @@ class OatDumper { // Dumping the dex file overview is compact enough to do even if header only. for (size_t i = 0; i < oat_dex_files_.size(); i++) { - const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i]; + const OatDexFile* oat_dex_file = oat_dex_files_[i]; CHECK(oat_dex_file != nullptr); std::string error_msg; const DexFile* const dex_file = OpenDexFile(oat_dex_file, &error_msg); @@ -598,7 +597,7 @@ class OatDumper { << "\n"; } for (size_t i = 0; i < oat_dex_files_.size(); i++) { - const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i]; + const OatDexFile* oat_dex_file = oat_dex_files_[i]; CHECK(oat_dex_file != nullptr); if (!DumpOatDexFile(os, *oat_dex_file)) { success = false; @@ -630,7 +629,7 @@ class OatDumper { size_t i = 0; for (const auto& vdex_dex_file : vdex_dex_files) { - const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i]; + const OatDexFile* oat_dex_file = oat_dex_files_[i]; CHECK(oat_dex_file != nullptr); CHECK(vdex_dex_file != nullptr); if (!ExportDexFile(os, *oat_dex_file, vdex_dex_file.get())) { @@ -670,7 +669,7 @@ class OatDumper { const void* GetQuickOatCode(ArtMethod* m) REQUIRES_SHARED(Locks::mutator_lock_) { for (size_t i = 0; i < oat_dex_files_.size(); i++) { - const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i]; + const OatDexFile* oat_dex_file = oat_dex_files_[i]; CHECK(oat_dex_file != nullptr); std::string error_msg; const DexFile* const dex_file = OpenDexFile(oat_dex_file, &error_msg); @@ -786,7 +785,7 @@ class OatDumper { // region, so if we keep a sorted sequence of the start of each region, we can infer the length // of a piece of code by using upper_bound to find the start of the next region. for (size_t i = 0; i < oat_dex_files_.size(); i++) { - const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i]; + const OatDexFile* oat_dex_file = oat_dex_files_[i]; CHECK(oat_dex_file != nullptr); std::string error_msg; const DexFile* const dex_file = OpenDexFile(oat_dex_file, &error_msg); @@ -825,7 +824,7 @@ class OatDumper { offsets_.insert(oat_method.GetVmapTableOffset()); } - bool DumpOatDexFile(std::ostream& os, const OatFile::OatDexFile& oat_dex_file) { + bool DumpOatDexFile(std::ostream& os, const OatDexFile& oat_dex_file) { bool success = true; bool stop_analysis = false; os << "OatDexFile:\n"; @@ -906,9 +905,7 @@ class OatDumper { // Dex resource is extracted from the oat_dex_file and its checksum is repaired since it's not // unquickened. Otherwise the dex_file has been fully unquickened and is expected to verify the // original checksum. - bool ExportDexFile(std::ostream& os, - const OatFile::OatDexFile& oat_dex_file, - const DexFile* dex_file) { + bool ExportDexFile(std::ostream& os, const OatDexFile& oat_dex_file, const DexFile* dex_file) { std::string error_msg; std::string dex_file_location = oat_dex_file.GetDexFileLocation(); size_t fsize = oat_dex_file.FileSize(); @@ -1717,7 +1714,7 @@ class OatDumper { } const OatFile& oat_file_; - const std::vector<const OatFile::OatDexFile*> oat_dex_files_; + const std::vector<const OatDexFile*> oat_dex_files_; const OatDumperOptions& options_; uint32_t resolved_addr2instr_; const InstructionSet instruction_set_; @@ -1856,7 +1853,7 @@ class ImageDumper { oat_dumper_.reset(new OatDumper(*oat_file, *oat_dumper_options_)); - for (const OatFile::OatDexFile* oat_dex_file : oat_file->GetOatDexFiles()) { + for (const OatDexFile* oat_dex_file : oat_file->GetOatDexFiles()) { CHECK(oat_dex_file != nullptr); stats_.oat_dex_file_sizes.push_back(std::make_pair(oat_dex_file->GetDexFileLocation(), oat_dex_file->FileSize())); @@ -2782,7 +2779,7 @@ static jobject InstallOatFile(Runtime* runtime, OatFile* oat_file_ptr = oat_file.get(); ClassLinker* class_linker = runtime->GetClassLinker(); runtime->GetOatFileManager().RegisterOatFile(std::move(oat_file)); - for (const OatFile::OatDexFile* odf : oat_file_ptr->GetOatDexFiles()) { + for (const OatDexFile* odf : oat_file_ptr->GetOatDexFiles()) { std::string error_msg; const DexFile* const dex_file = OpenDexFile(odf, &error_msg); CHECK(dex_file != nullptr) << error_msg; diff --git a/runtime/art_method.cc b/runtime/art_method.cc index 5b4dcb73fd..80b6921c8a 100644 --- a/runtime/art_method.cc +++ b/runtime/art_method.cc @@ -550,7 +550,7 @@ bool ArtMethod::EqualParameters(Handle<mirror::ObjectArray<mirror::Class>> param ArrayRef<const uint8_t> ArtMethod::GetQuickenedInfo() { const DexFile& dex_file = GetDeclaringClass()->GetDexFile(); - const OatFile::OatDexFile* oat_dex_file = dex_file.GetOatDexFile(); + const OatDexFile* oat_dex_file = dex_file.GetOatDexFile(); if (oat_dex_file == nullptr || (oat_dex_file->GetOatFile() == nullptr)) { return ArrayRef<const uint8_t>(); } diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 7b92ba41a5..c219d3dd68 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -1338,7 +1338,7 @@ static std::unique_ptr<const DexFile> OpenOatDexFile(const OatFile* oat_file, REQUIRES_SHARED(Locks::mutator_lock_) { DCHECK(error_msg != nullptr); std::unique_ptr<const DexFile> dex_file; - const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(location, nullptr, error_msg); + const OatDexFile* oat_dex_file = oat_file->GetOatDexFile(location, nullptr, error_msg); if (oat_dex_file == nullptr) { return std::unique_ptr<const DexFile>(); } @@ -4181,7 +4181,7 @@ bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file, } } - const OatFile::OatDexFile* oat_dex_file = dex_file.GetOatDexFile(); + const OatDexFile* oat_dex_file = dex_file.GetOatDexFile(); // In case we run without an image there won't be a backing oat file. if (oat_dex_file == nullptr || oat_dex_file->GetOatFile() == nullptr) { return false; diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc index e754fbcbae..cbce940337 100644 --- a/runtime/gc/space/image_space.cc +++ b/runtime/gc/space/image_space.cc @@ -1875,7 +1875,7 @@ std::string ImageSpace::GetMultiImageBootClassPath( bool ImageSpace::ValidateOatFile(const OatFile& oat_file, std::string* error_msg) { const ArtDexFileLoader dex_file_loader; - for (const OatFile::OatDexFile* oat_dex_file : oat_file.GetOatDexFiles()) { + for (const OatDexFile* oat_dex_file : oat_file.GetOatDexFiles()) { const std::string& dex_file_location = oat_dex_file->GetDexFileLocation(); // Skip multidex locations - These will be checked when we visit their @@ -1909,9 +1909,9 @@ bool ImageSpace::ValidateOatFile(const OatFile& oat_file, std::string* error_msg std::string multi_dex_location = DexFileLoader::GetMultiDexLocation( i, dex_file_location.c_str()); - const OatFile::OatDexFile* multi_dex = oat_file.GetOatDexFile(multi_dex_location.c_str(), - nullptr, - error_msg); + const OatDexFile* multi_dex = oat_file.GetOatDexFile(multi_dex_location.c_str(), + nullptr, + error_msg); if (multi_dex == nullptr) { *error_msg = StringPrintf("ValidateOatFile oat file '%s' is missing entry '%s'", oat_file.GetLocation().c_str(), diff --git a/runtime/oat.h b/runtime/oat.h index 22c6a39e09..6c3cc20032 100644 --- a/runtime/oat.h +++ b/runtime/oat.h @@ -32,8 +32,8 @@ class InstructionSetFeatures; class PACKED(4) OatHeader { public: static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' }; - // Last oat version changed reason: Add Kind column to stack maps. - static constexpr uint8_t kOatVersion[] = { '1', '4', '9', '\0' }; + // Last oat version changed reason: Remove explicit size from CodeInfo. + static constexpr uint8_t kOatVersion[] = { '1', '5', '1', '\0' }; static constexpr const char* kImageLocationKey = "image-location"; static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline"; diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc index 9355ae720d..8842942e7a 100644 --- a/runtime/oat_file.cc +++ b/runtime/oat_file.cc @@ -1598,9 +1598,9 @@ ArrayRef<GcRoot<mirror::Object>> OatFile::GetBssGcRoots() const { } } -const OatFile::OatDexFile* OatFile::GetOatDexFile(const char* dex_location, - const uint32_t* dex_location_checksum, - std::string* error_msg) const { +const OatDexFile* OatFile::GetOatDexFile(const char* dex_location, + const uint32_t* dex_location_checksum, + std::string* error_msg) const { // NOTE: We assume here that the canonical location for a given dex_location never // changes. If it does (i.e. some symlink used by the filename changes) we may return // an incorrect OatDexFile. As long as we have a checksum to check, we shall return @@ -1609,7 +1609,7 @@ const OatFile::OatDexFile* OatFile::GetOatDexFile(const char* dex_location, // TODO: Additional analysis of usage patterns to see if this can be simplified // without any performance loss, for example by not doing the first lock-free lookup. - const OatFile::OatDexFile* oat_dex_file = nullptr; + const OatDexFile* oat_dex_file = nullptr; StringPiece key(dex_location); // Try to find the key cheaply in the oat_dex_files_ map which holds dex locations // directly mentioned in the oat file and doesn't require locking. @@ -1667,17 +1667,17 @@ const OatFile::OatDexFile* OatFile::GetOatDexFile(const char* dex_location, return oat_dex_file; } -OatFile::OatDexFile::OatDexFile(const OatFile* oat_file, - const std::string& dex_file_location, - const std::string& canonical_dex_file_location, - uint32_t dex_file_location_checksum, - const uint8_t* dex_file_pointer, - const uint8_t* lookup_table_data, - const IndexBssMapping* method_bss_mapping_data, - const IndexBssMapping* type_bss_mapping_data, - const IndexBssMapping* string_bss_mapping_data, - const uint32_t* oat_class_offsets_pointer, - const DexLayoutSections* dex_layout_sections) +OatDexFile::OatDexFile(const OatFile* oat_file, + const std::string& dex_file_location, + const std::string& canonical_dex_file_location, + uint32_t dex_file_location_checksum, + const uint8_t* dex_file_pointer, + const uint8_t* lookup_table_data, + const IndexBssMapping* method_bss_mapping_data, + const IndexBssMapping* type_bss_mapping_data, + const IndexBssMapping* string_bss_mapping_data, + const uint32_t* oat_class_offsets_pointer, + const DexLayoutSections* dex_layout_sections) : oat_file_(oat_file), dex_file_location_(dex_file_location), canonical_dex_file_location_(canonical_dex_file_location), @@ -1708,16 +1708,15 @@ OatFile::OatDexFile::OatDexFile(const OatFile* oat_file, } } -OatFile::OatDexFile::OatDexFile(TypeLookupTable&& lookup_table) - : lookup_table_(std::move(lookup_table)) {} +OatDexFile::OatDexFile(TypeLookupTable&& lookup_table) : lookup_table_(std::move(lookup_table)) {} -OatFile::OatDexFile::~OatDexFile() {} +OatDexFile::~OatDexFile() {} -size_t OatFile::OatDexFile::FileSize() const { +size_t OatDexFile::FileSize() const { return reinterpret_cast<const DexFile::Header*>(dex_file_pointer_)->file_size_; } -std::unique_ptr<const DexFile> OatFile::OatDexFile::OpenDexFile(std::string* error_msg) const { +std::unique_ptr<const DexFile> OatDexFile::OpenDexFile(std::string* error_msg) const { ScopedTrace trace(__PRETTY_FUNCTION__); static constexpr bool kVerify = false; static constexpr bool kVerifyChecksum = false; @@ -1732,11 +1731,11 @@ std::unique_ptr<const DexFile> OatFile::OatDexFile::OpenDexFile(std::string* err error_msg); } -uint32_t OatFile::OatDexFile::GetOatClassOffset(uint16_t class_def_index) const { +uint32_t OatDexFile::GetOatClassOffset(uint16_t class_def_index) const { return oat_class_offsets_pointer_[class_def_index]; } -OatFile::OatClass OatFile::OatDexFile::GetOatClass(uint16_t class_def_index) const { +OatFile::OatClass OatDexFile::GetOatClass(uint16_t class_def_index) const { uint32_t oat_class_offset = GetOatClassOffset(class_def_index); const uint8_t* oat_class_pointer = oat_file_->Begin() + oat_class_offset; @@ -1778,10 +1777,10 @@ OatFile::OatClass OatFile::OatDexFile::GetOatClass(uint16_t class_def_index) con reinterpret_cast<const OatMethodOffsets*>(methods_pointer)); } -const DexFile::ClassDef* OatFile::OatDexFile::FindClassDef(const DexFile& dex_file, - const char* descriptor, - size_t hash) { - const OatFile::OatDexFile* oat_dex_file = dex_file.GetOatDexFile(); +const DexFile::ClassDef* OatDexFile::FindClassDef(const DexFile& dex_file, + const char* descriptor, + size_t hash) { + const OatDexFile* oat_dex_file = dex_file.GetOatDexFile(); DCHECK_EQ(ComputeModifiedUtf8Hash(descriptor), hash); bool used_lookup_table = false; const DexFile::ClassDef* lookup_table_classdef = nullptr; @@ -1829,7 +1828,7 @@ void OatDexFile::MadviseDexFile(const DexFile& dex_file, MadviseState state) { dex_file.Begin() + dex_file.Size(), MADV_RANDOM); } - const OatFile::OatDexFile* oat_dex_file = dex_file.GetOatDexFile(); + const OatDexFile* oat_dex_file = dex_file.GetOatDexFile(); if (oat_dex_file != nullptr) { // Should always be there. const DexLayoutSections* const sections = oat_dex_file->GetDexLayoutSections(); @@ -1947,7 +1946,7 @@ OatFile::OatClass OatFile::FindOatClass(const DexFile& dex_file, uint16_t class_def_idx, bool* found) { DCHECK_NE(class_def_idx, DexFile::kDexNoIndex16); - const OatFile::OatDexFile* oat_dex_file = dex_file.GetOatDexFile(); + const OatDexFile* oat_dex_file = dex_file.GetOatDexFile(); if (oat_dex_file == nullptr || oat_dex_file->GetOatFile() == nullptr) { *found = false; return OatFile::OatClass::Invalid(); @@ -1956,7 +1955,7 @@ OatFile::OatClass OatFile::FindOatClass(const DexFile& dex_file, return oat_dex_file->GetOatClass(class_def_idx); } -void OatFile::OatDexFile::AssertAotCompiler() { +void OatDexFile::AssertAotCompiler() { CHECK(Runtime::Current()->IsAotCompiler()); } diff --git a/runtime/oat_file.h b/runtime/oat_file.h index d72b6a8971..5f87bf0f99 100644 --- a/runtime/oat_file.h +++ b/runtime/oat_file.h @@ -70,8 +70,6 @@ class OatFile { // Special classpath that skips shared library check. static constexpr const char* kSpecialSharedLibrary = "&"; - typedef art::OatDexFile OatDexFile; - // Opens an oat file contained within the given elf file. This is always opened as // non-executable at the moment. static OatFile* OpenWithElfFile(int zip_fd, diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc index 6c869cada5..f7c74cc23b 100644 --- a/runtime/oat_file_assistant.cc +++ b/runtime/oat_file_assistant.cc @@ -354,7 +354,7 @@ bool OatFileAssistant::LoadDexFiles( std::vector<std::unique_ptr<const DexFile>>* out_dex_files) { // Load the main dex file. std::string error_msg; - const OatFile::OatDexFile* oat_dex_file = oat_file.GetOatDexFile( + const OatDexFile* oat_dex_file = oat_file.GetOatDexFile( dex_location.c_str(), nullptr, &error_msg); if (oat_dex_file == nullptr) { LOG(WARNING) << error_msg; @@ -453,7 +453,7 @@ bool OatFileAssistant::DexChecksumUpToDate(const OatFile& file, std::string* err for (uint32_t i = 0; i < number_of_dex_files; i++) { std::string dex = DexFileLoader::GetMultiDexLocation(i, dex_location_.c_str()); uint32_t expected_checksum = (*required_dex_checksums)[i]; - const OatFile::OatDexFile* oat_dex_file = file.GetOatDexFile(dex.c_str(), nullptr); + const OatDexFile* oat_dex_file = file.GetOatDexFile(dex.c_str(), nullptr); if (oat_dex_file == nullptr) { *error_msg = StringPrintf("failed to find %s in %s", dex.c_str(), file.GetLocation().c_str()); return false; @@ -921,7 +921,7 @@ const std::vector<uint32_t>* OatFileAssistant::GetRequiredDexChecksums() { required_dex_checksums_found_ = true; for (size_t i = 0; i < odex_file->GetOatHeader().GetDexFileCount(); i++) { std::string dex = DexFileLoader::GetMultiDexLocation(i, dex_location_.c_str()); - const OatFile::OatDexFile* odex_dex_file = odex_file->GetOatDexFile(dex.c_str(), nullptr); + const OatDexFile* odex_dex_file = odex_file->GetOatDexFile(dex.c_str(), nullptr); if (odex_dex_file == nullptr) { required_dex_checksums_found_ = false; break; diff --git a/runtime/runtime.cc b/runtime/runtime.cc index 3b4d177646..f7674c89d3 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -1020,7 +1020,7 @@ static bool OpenDexFilesFromImage(const std::string& image_location, return false; } - for (const OatFile::OatDexFile* oat_dex_file : oat_file->GetOatDexFiles()) { + for (const OatDexFile* oat_dex_file : oat_file->GetOatDexFiles()) { if (oat_dex_file == nullptr) { *failures += 1; continue; diff --git a/runtime/stack_map.cc b/runtime/stack_map.cc index 7f7f6fce0a..a3c6e05045 100644 --- a/runtime/stack_map.cc +++ b/runtime/stack_map.cc @@ -22,15 +22,22 @@ #include "art_method.h" #include "base/indenter.h" #include "base/stats.h" +#include "oat_quick_method_header.h" #include "scoped_thread_state_change-inl.h" namespace art { +CodeInfo::CodeInfo(const OatQuickMethodHeader* header) + : CodeInfo(header->GetOptimizedCodeInfoPtr()) { +} + void CodeInfo::Decode(const uint8_t* data) { - size_t non_header_size = DecodeUnsignedLeb128(&data); - size_ = UnsignedLeb128Size(non_header_size) + non_header_size; - MemoryRegion region(const_cast<uint8_t*>(data), non_header_size); - BitMemoryReader reader(BitMemoryRegion(region), /* bit_offset */ 0); + const uint8_t* begin = data; + frame_size_in_bytes_ = DecodeUnsignedLeb128(&data); + core_spill_mask_ = DecodeUnsignedLeb128(&data); + fp_spill_mask_ = DecodeUnsignedLeb128(&data); + number_of_dex_registers_ = DecodeUnsignedLeb128(&data); + BitMemoryReader reader(data, /* bit_offset */ 0); stack_maps_.Decode(reader); register_masks_.Decode(reader); stack_masks_.Decode(reader); @@ -39,8 +46,7 @@ void CodeInfo::Decode(const uint8_t* data) { dex_register_masks_.Decode(reader); dex_register_maps_.Decode(reader); dex_register_catalog_.Decode(reader); - number_of_dex_registers_ = DecodeVarintBits(reader); - CHECK_EQ(non_header_size, BitsToBytesRoundUp(reader.GetBitOffset())) << "Invalid CodeInfo"; + size_in_bits_ = (data - begin) * kBitsPerByte + reader.GetBitOffset(); } BitTable<StackMap>::const_iterator CodeInfo::BinarySearchNativePc(uint32_t packed_pc) const { @@ -145,8 +151,7 @@ static void AddTableSizeStats(const char* table_name, void CodeInfo::AddSizeStats(/*out*/ Stats* parent) const { Stats* stats = parent->Child("CodeInfo"); - stats->AddBytes(size_); - stats->Child("Header")->AddBytes(UnsignedLeb128Size(size_)); + stats->AddBytes(Size()); AddTableSizeStats<StackMap>("StackMaps", stack_maps_, stats); AddTableSizeStats<RegisterMask>("RegisterMasks", register_masks_, stats); AddTableSizeStats<MaskInfo>("StackMasks", stack_masks_, stats); @@ -213,7 +218,7 @@ void CodeInfo::Dump(VariableIndentationOutputStream* vios, const MethodInfo& method_info) const { vios->Stream() << "CodeInfo" - << " BitSize=" << size_ * kBitsPerByte + << " BitSize=" << size_in_bits_ << "\n"; ScopedIndentation indent1(vios); DumpTable<StackMap>(vios, "StackMaps", stack_maps_, verbose); diff --git a/runtime/stack_map.h b/runtime/stack_map.h index 83f0c05501..ad52f377cf 100644 --- a/runtime/stack_map.h +++ b/runtime/stack_map.h @@ -19,6 +19,7 @@ #include <limits> +#include "arch/instruction_set.h" #include "base/bit_memory_region.h" #include "base/bit_table.h" #include "base/bit_utils.h" @@ -28,10 +29,11 @@ #include "dex/dex_file_types.h" #include "dex_register_location.h" #include "method_info.h" -#include "oat_quick_method_header.h" +#include "quick/quick_method_frame_info.h" namespace art { +class OatQuickMethodHeader; class VariableIndentationOutputStream; // Size of a frame slot, in bytes. This constant is a signed value, @@ -287,15 +289,13 @@ class CodeInfo { } explicit CodeInfo(MemoryRegion region) : CodeInfo(region.begin()) { - DCHECK_EQ(size_, region.size()); + DCHECK_EQ(Size(), region.size()); } - explicit CodeInfo(const OatQuickMethodHeader* header) - : CodeInfo(header->GetOptimizedCodeInfoPtr()) { - } + explicit CodeInfo(const OatQuickMethodHeader* header); size_t Size() const { - return size_; + return BitsToBytesRoundUp(size_in_bits_); } bool HasInlineInfo() const { @@ -435,6 +435,13 @@ class CodeInfo { // Accumulate code info size statistics into the given Stats tree. void AddSizeStats(/*out*/ Stats* parent) const; + ALWAYS_INLINE static QuickMethodFrameInfo DecodeFrameInfo(const uint8_t* data) { + return QuickMethodFrameInfo( + DecodeUnsignedLeb128(&data), + DecodeUnsignedLeb128(&data), + DecodeUnsignedLeb128(&data)); + } + private: // Returns lower bound (fist stack map which has pc greater or equal than the desired one). // It ignores catch stack maps at the end (it is the same as if they had maximum pc value). @@ -447,7 +454,10 @@ class CodeInfo { void Decode(const uint8_t* data); - size_t size_; + uint32_t frame_size_in_bytes_; + uint32_t core_spill_mask_; + uint32_t fp_spill_mask_; + uint32_t number_of_dex_registers_; BitTable<StackMap> stack_maps_; BitTable<RegisterMask> register_masks_; BitTable<MaskInfo> stack_masks_; @@ -456,7 +466,7 @@ class CodeInfo { BitTable<MaskInfo> dex_register_masks_; BitTable<DexRegisterMapInfo> dex_register_maps_; BitTable<DexRegisterInfo> dex_register_catalog_; - uint32_t number_of_dex_registers_; // Excludes any inlined methods. + uint32_t size_in_bits_; }; #undef ELEMENT_BYTE_OFFSET_AFTER diff --git a/test/117-nopatchoat/nopatchoat.cc b/test/117-nopatchoat/nopatchoat.cc index 7c382588a4..a8a895a6b3 100644 --- a/test/117-nopatchoat/nopatchoat.cc +++ b/test/117-nopatchoat/nopatchoat.cc @@ -28,7 +28,7 @@ namespace art { class NoPatchoatTest { public: - static const OatFile::OatDexFile* getOatDexFile(jclass cls) { + static const OatDexFile* getOatDexFile(jclass cls) { ScopedObjectAccess soa(Thread::Current()); ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(cls); const DexFile& dex_file = klass->GetDexFile(); @@ -42,13 +42,13 @@ class NoPatchoatTest { } static bool hasExecutableOat(jclass cls) { - const OatFile::OatDexFile* oat_dex_file = getOatDexFile(cls); + const OatDexFile* oat_dex_file = getOatDexFile(cls); return oat_dex_file != nullptr && oat_dex_file->GetOatFile()->IsExecutable(); } static bool needsRelocation(jclass cls) { - const OatFile::OatDexFile* oat_dex_file = getOatDexFile(cls); + const OatDexFile* oat_dex_file = getOatDexFile(cls); if (oat_dex_file == nullptr) { return false; diff --git a/test/411-checker-hdiv-hrem-pow2/expected.txt b/test/411-checker-hdiv-hrem-pow2/expected.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/411-checker-hdiv-hrem-pow2/expected.txt diff --git a/test/411-checker-hdiv-hrem-pow2/info.txt b/test/411-checker-hdiv-hrem-pow2/info.txt new file mode 100644 index 0000000000..df1c988052 --- /dev/null +++ b/test/411-checker-hdiv-hrem-pow2/info.txt @@ -0,0 +1,2 @@ +Test the optimization of integer division and remainder instructions when +the denominator is power of 2 on arm64. diff --git a/test/411-checker-hdiv-hrem-pow2/src/DivTest.java b/test/411-checker-hdiv-hrem-pow2/src/DivTest.java new file mode 100644 index 0000000000..a3882e7c15 --- /dev/null +++ b/test/411-checker-hdiv-hrem-pow2/src/DivTest.java @@ -0,0 +1,251 @@ +/* + * Copyright (C) 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 + * + * 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. + */ + +public class DivTest { + + public static <T extends Number> void expectEquals(T expected, T result) { + if (!expected.equals(result)) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } + + public static void main() { + divInt(); + divLong(); + } + + private static void divInt() { + expectEquals(0, $noinline$IntDivBy2(0)); + expectEquals(0, $noinline$IntDivBy2(1)); + expectEquals(0, $noinline$IntDivBy2(-1)); + expectEquals(1, $noinline$IntDivBy2(2)); + expectEquals(-1, $noinline$IntDivBy2(-2)); + expectEquals(1, $noinline$IntDivBy2(3)); + expectEquals(-1, $noinline$IntDivBy2(-3)); + expectEquals(3, $noinline$IntDivBy2(7)); + expectEquals(-3, $noinline$IntDivBy2(-7)); + expectEquals(4, $noinline$IntDivBy2(8)); + expectEquals(-4, $noinline$IntDivBy2(-8)); + expectEquals(7, $noinline$IntDivBy2(0x0f)); + expectEquals(0x007f, $noinline$IntDivBy2(0x00ff)); + expectEquals(0x07ff, $noinline$IntDivBy2(0x0fff)); + expectEquals(0x007fff, $noinline$IntDivBy2(0x00ffff)); + expectEquals(0x3fffffff, $noinline$IntDivBy2(Integer.MAX_VALUE)); + expectEquals(0xc0000000, $noinline$IntDivBy2(Integer.MIN_VALUE)); + + expectEquals(0, $noinline$IntDivByMinus2(0)); + expectEquals(0, $noinline$IntDivByMinus2(1)); + expectEquals(0, $noinline$IntDivByMinus2(-1)); + expectEquals(-1, $noinline$IntDivByMinus2(2)); + expectEquals(1, $noinline$IntDivByMinus2(-2)); + expectEquals(-1, $noinline$IntDivByMinus2(3)); + expectEquals(1, $noinline$IntDivByMinus2(-3)); + expectEquals(-3, $noinline$IntDivByMinus2(7)); + expectEquals(3, $noinline$IntDivByMinus2(-7)); + expectEquals(-4, $noinline$IntDivByMinus2(8)); + expectEquals(4, $noinline$IntDivByMinus2(-8)); + expectEquals(-7, $noinline$IntDivByMinus2(0x0f)); + expectEquals(0xffffff81, $noinline$IntDivByMinus2(0x00ff)); + expectEquals(0xfffff801, $noinline$IntDivByMinus2(0x0fff)); + expectEquals(0xffff8001, $noinline$IntDivByMinus2(0x00ffff)); + expectEquals(0xc0000001, $noinline$IntDivByMinus2(Integer.MAX_VALUE)); + expectEquals(0x40000000, $noinline$IntDivByMinus2(Integer.MIN_VALUE)); + + expectEquals(0, $noinline$IntDivBy16(0)); + expectEquals(1, $noinline$IntDivBy16(16)); + expectEquals(-1, $noinline$IntDivBy16(-16)); + expectEquals(2, $noinline$IntDivBy16(33)); + expectEquals(0x000f, $noinline$IntDivBy16(0x00ff)); + expectEquals(0x00ff, $noinline$IntDivBy16(0x0fff)); + expectEquals(0x000fff, $noinline$IntDivBy16(0x00ffff)); + expectEquals(0x07ffffff, $noinline$IntDivBy16(Integer.MAX_VALUE)); + expectEquals(0xf8000000, $noinline$IntDivBy16(Integer.MIN_VALUE)); + + expectEquals(0, $noinline$IntDivByMinus16(0)); + expectEquals(-1, $noinline$IntDivByMinus16(16)); + expectEquals(1, $noinline$IntDivByMinus16(-16)); + expectEquals(-2, $noinline$IntDivByMinus16(33)); + expectEquals(0xfffffff1, $noinline$IntDivByMinus16(0x00ff)); + expectEquals(0xffffff01, $noinline$IntDivByMinus16(0x0fff)); + expectEquals(0xfffff001, $noinline$IntDivByMinus16(0x00ffff)); + expectEquals(0xf8000001, $noinline$IntDivByMinus16(Integer.MAX_VALUE)); + expectEquals(0x08000000, $noinline$IntDivByMinus16(Integer.MIN_VALUE)); + + expectEquals(0, $noinline$IntDivByIntMin(0)); + expectEquals(0, $noinline$IntDivByIntMin(1)); + expectEquals(0, $noinline$IntDivByIntMin(-1)); + expectEquals(1, $noinline$IntDivByIntMin(Integer.MIN_VALUE)); + expectEquals(0, $noinline$IntDivByIntMin(Integer.MAX_VALUE)); + } + + /// CHECK-START-ARM64: java.lang.Integer DivTest.$noinline$IntDivBy2(int) disassembly (after) + /// CHECK: add w{{\d+}}, w{{\d+}}, w{{\d+}}, lsr #31 + /// CHECK: asr w{{\d+}}, w{{\d+}}, #1 + private static Integer $noinline$IntDivBy2(int v) { + int r = v / 2; + return r; + } + + /// CHECK-START-ARM64: java.lang.Integer DivTest.$noinline$IntDivByMinus2(int) disassembly (after) + /// CHECK: add w{{\d+}}, w{{\d+}}, w{{\d+}}, lsr #31 + /// CHECK: neg w{{\d+}}, w{{\d+}}, asr #1 + private static Integer $noinline$IntDivByMinus2(int v) { + int r = v / -2; + return r; + } + + /// CHECK-START-ARM64: java.lang.Integer DivTest.$noinline$IntDivBy16(int) disassembly (after) + /// CHECK: add w{{\d+}}, w{{\d+}}, #0xf + /// CHECK: cmp w{{\d+}}, #0x0 + /// CHECK: csel w{{\d+}}, w{{\d+}}, w{{\d+}}, lt + /// CHECK: asr w{{\d+}}, w{{\d+}}, #4 + private static Integer $noinline$IntDivBy16(int v) { + int r = v / 16; + return r; + } + + /// CHECK-START-ARM64: java.lang.Integer DivTest.$noinline$IntDivByMinus16(int) disassembly (after) + /// CHECK: add w{{\d+}}, w{{\d+}}, #0xf + /// CHECK: cmp w{{\d+}}, #0x0 + /// CHECK: csel w{{\d+}}, w{{\d+}}, w{{\d+}}, lt + /// CHECK: neg w{{\d+}}, w{{\d+}}, asr #4 + private static Integer $noinline$IntDivByMinus16(int v) { + int r = v / -16; + return r; + } + + /// CHECK-START-ARM64: java.lang.Integer DivTest.$noinline$IntDivByIntMin(int) disassembly (after) + /// CHECK: mov w{{\d+}}, #0x7fffffff + /// CHECK: add w{{\d+}}, w{{\d+}}, w{{\d+}} + /// CHECK: cmp w{{\d+}}, #0x0 + /// CHECK: csel w{{\d+}}, w{{\d+}}, w{{\d+}}, lt + /// CHECK: neg w{{\d+}}, w{{\d+}}, asr #31 + private static Integer $noinline$IntDivByIntMin(int v) { + int r = v / Integer.MIN_VALUE; + return r; + } + + private static void divLong() { + expectEquals(0L, $noinline$LongDivBy2(0L)); + expectEquals(0L, $noinline$LongDivBy2(1L)); + expectEquals(0L, $noinline$LongDivBy2(-1L)); + expectEquals(1L, $noinline$LongDivBy2(2L)); + expectEquals(-1L, $noinline$LongDivBy2(-2L)); + expectEquals(1L, $noinline$LongDivBy2(3L)); + expectEquals(-1L, $noinline$LongDivBy2(-3L)); + expectEquals(3L, $noinline$LongDivBy2(7L)); + expectEquals(-3L, $noinline$LongDivBy2(-7L)); + expectEquals(4L, $noinline$LongDivBy2(8L)); + expectEquals(-4L, $noinline$LongDivBy2(-8L)); + expectEquals(7L, $noinline$LongDivBy2(0x0fL)); + expectEquals(0x007fL, $noinline$LongDivBy2(0x00ffL)); + expectEquals(0x07ffL, $noinline$LongDivBy2(0x0fffL)); + expectEquals(0x007fffL, $noinline$LongDivBy2(0x00ffffL)); + expectEquals(0x3fffffffffffffffL, $noinline$LongDivBy2(Long.MAX_VALUE)); + expectEquals(0xc000000000000000L, $noinline$LongDivBy2(Long.MIN_VALUE)); + + expectEquals(0L, $noinline$LongDivByMinus2(0)); + expectEquals(0L, $noinline$LongDivByMinus2(1L)); + expectEquals(0L, $noinline$LongDivByMinus2(-1L)); + expectEquals(-1L, $noinline$LongDivByMinus2(2L)); + expectEquals(1L, $noinline$LongDivByMinus2(-2L)); + expectEquals(-1L, $noinline$LongDivByMinus2(3L)); + expectEquals(1L, $noinline$LongDivByMinus2(-3L)); + expectEquals(-3L, $noinline$LongDivByMinus2(7L)); + expectEquals(3L, $noinline$LongDivByMinus2(-7L)); + expectEquals(-4L, $noinline$LongDivByMinus2(8L)); + expectEquals(4L, $noinline$LongDivByMinus2(-8L)); + expectEquals(-7L, $noinline$LongDivByMinus2(0x0fL)); + expectEquals(0xffffffffffffff81L, $noinline$LongDivByMinus2(0x00ffL)); + expectEquals(0xfffffffffffff801L, $noinline$LongDivByMinus2(0x0fffL)); + expectEquals(0xffffffffffff8001L, $noinline$LongDivByMinus2(0x00ffffL)); + expectEquals(0xc000000000000001L, $noinline$LongDivByMinus2(Long.MAX_VALUE)); + expectEquals(0x4000000000000000L, $noinline$LongDivByMinus2(Long.MIN_VALUE)); + + expectEquals(0L, $noinline$LongDivBy16(0)); + expectEquals(1L, $noinline$LongDivBy16(16L)); + expectEquals(-1L, $noinline$LongDivBy16(-16L)); + expectEquals(2L, $noinline$LongDivBy16(33L)); + expectEquals(0x000fL, $noinline$LongDivBy16(0x00ffL)); + expectEquals(0x00ffL, $noinline$LongDivBy16(0x0fffL)); + expectEquals(0x000fffL, $noinline$LongDivBy16(0x00ffffL)); + expectEquals(0x07ffffffffffffffL, $noinline$LongDivBy16(Long.MAX_VALUE)); + expectEquals(0xf800000000000000L, $noinline$LongDivBy16(Long.MIN_VALUE)); + + expectEquals(0L, $noinline$LongDivByMinus16(0)); + expectEquals(-1L, $noinline$LongDivByMinus16(16L)); + expectEquals(1L, $noinline$LongDivByMinus16(-16L)); + expectEquals(-2L, $noinline$LongDivByMinus16(33L)); + expectEquals(0xfffffffffffffff1L, $noinline$LongDivByMinus16(0x00ffL)); + expectEquals(0xffffffffffffff01L, $noinline$LongDivByMinus16(0x0fffL)); + expectEquals(0xfffffffffffff001L, $noinline$LongDivByMinus16(0x00ffffL)); + expectEquals(0xf800000000000001L, $noinline$LongDivByMinus16(Long.MAX_VALUE)); + expectEquals(0x0800000000000000L, $noinline$LongDivByMinus16(Long.MIN_VALUE)); + + expectEquals(0L, $noinline$LongDivByLongMin(0)); + expectEquals(0L, $noinline$LongDivByLongMin(1)); + expectEquals(0L, $noinline$LongDivByLongMin(-1)); + expectEquals(1L, $noinline$LongDivByLongMin(Long.MIN_VALUE)); + expectEquals(0L, $noinline$LongDivByLongMin(Long.MAX_VALUE)); + } + + /// CHECK-START-ARM64: java.lang.Long DivTest.$noinline$LongDivBy2(long) disassembly (after) + /// CHECK: add x{{\d+}}, x{{\d+}}, x{{\d+}}, lsr #63 + /// CHECK: asr x{{\d+}}, x{{\d+}}, #1 + private static Long $noinline$LongDivBy2(long v) { + long r = v / 2; + return r; + } + + /// CHECK-START-ARM64: java.lang.Long DivTest.$noinline$LongDivByMinus2(long) disassembly (after) + /// CHECK: add x{{\d+}}, x{{\d+}}, x{{\d+}}, lsr #63 + /// CHECK: neg x{{\d+}}, x{{\d+}}, asr #1 + private static Long $noinline$LongDivByMinus2(long v) { + long r = v / -2; + return r; + } + + /// CHECK-START-ARM64: java.lang.Long DivTest.$noinline$LongDivBy16(long) disassembly (after) + /// CHECK: add x{{\d+}}, x{{\d+}}, #0xf + /// CHECK: cmp x{{\d+}}, #0x0 + /// CHECK: csel x{{\d+}}, x{{\d+}}, x{{\d+}}, lt + /// CHECK: asr x{{\d+}}, x{{\d+}}, #4 + private static Long $noinline$LongDivBy16(long v) { + long r = v / 16; + return r; + } + + /// CHECK-START-ARM64: java.lang.Long DivTest.$noinline$LongDivByMinus16(long) disassembly (after) + /// CHECK: add x{{\d+}}, x{{\d+}}, #0xf + /// CHECK: cmp x{{\d+}}, #0x0 + /// CHECK: csel x{{\d+}}, x{{\d+}}, x{{\d+}}, lt + /// CHECK: neg x{{\d+}}, x{{\d+}}, asr #4 + private static Long $noinline$LongDivByMinus16(long v) { + long r = v / -16; + return r; + } + + /// CHECK-START-ARM64: java.lang.Long DivTest.$noinline$LongDivByLongMin(long) disassembly (after) + /// CHECK: mov x{{\d+}}, #0x7fffffffffffffff + /// CHECK: add x{{\d+}}, x{{\d+}}, x{{\d+}} + /// CHECK: cmp x{{\d+}}, #0x0 + /// CHECK: csel x{{\d+}}, x{{\d+}}, x{{\d+}}, lt + /// CHECK: neg x{{\d+}}, x{{\d+}}, asr #63 + private static Long $noinline$LongDivByLongMin(long v) { + long r = v / Long.MIN_VALUE; + return r; + } +} diff --git a/test/411-checker-hdiv-hrem-pow2/src/Main.java b/test/411-checker-hdiv-hrem-pow2/src/Main.java new file mode 100644 index 0000000000..4b34bf1af4 --- /dev/null +++ b/test/411-checker-hdiv-hrem-pow2/src/Main.java @@ -0,0 +1,22 @@ +/* + * Copyright (C) 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 + * + * 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. + */ + +public class Main { + public static void main(String args[]) { + DivTest.main(); + RemTest.main(); + } +} diff --git a/test/411-checker-hdiv-hrem-pow2/src/RemTest.java b/test/411-checker-hdiv-hrem-pow2/src/RemTest.java new file mode 100644 index 0000000000..72725c1cd4 --- /dev/null +++ b/test/411-checker-hdiv-hrem-pow2/src/RemTest.java @@ -0,0 +1,257 @@ +/* + * Copyright (C) 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 + * + * 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. + */ + +public class RemTest { + + public static <T extends Number> void expectEquals(T expected, T result) { + if (!expected.equals(result)) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } + + public static void main() { + remInt(); + remLong(); + } + + private static void remInt() { + expectEquals(0, $noinline$IntMod2(0)); + expectEquals(1, $noinline$IntMod2(1)); + expectEquals(-1, $noinline$IntMod2(-1)); + expectEquals(0, $noinline$IntMod2(2)); + expectEquals(0, $noinline$IntMod2(-2)); + expectEquals(1, $noinline$IntMod2(3)); + expectEquals(-1, $noinline$IntMod2(-3)); + expectEquals(1, $noinline$IntMod2(0x0f)); + expectEquals(1, $noinline$IntMod2(0x00ff)); + expectEquals(1, $noinline$IntMod2(0x00ffff)); + expectEquals(1, $noinline$IntMod2(Integer.MAX_VALUE)); + expectEquals(0, $noinline$IntMod2(Integer.MIN_VALUE)); + + expectEquals(0, $noinline$IntModMinus2(0)); + expectEquals(1, $noinline$IntModMinus2(1)); + expectEquals(-1, $noinline$IntModMinus2(-1)); + expectEquals(0, $noinline$IntModMinus2(2)); + expectEquals(0, $noinline$IntModMinus2(-2)); + expectEquals(1, $noinline$IntModMinus2(3)); + expectEquals(-1, $noinline$IntModMinus2(-3)); + expectEquals(1, $noinline$IntModMinus2(0x0f)); + expectEquals(1, $noinline$IntModMinus2(0x00ff)); + expectEquals(1, $noinline$IntModMinus2(0x00ffff)); + expectEquals(1, $noinline$IntModMinus2(Integer.MAX_VALUE)); + expectEquals(0, $noinline$IntModMinus2(Integer.MIN_VALUE)); + + expectEquals(0, $noinline$IntMod16(0)); + expectEquals(1, $noinline$IntMod16(1)); + expectEquals(1, $noinline$IntMod16(17)); + expectEquals(-1, $noinline$IntMod16(-1)); + expectEquals(0, $noinline$IntMod16(32)); + expectEquals(0, $noinline$IntMod16(-32)); + expectEquals(0x0f, $noinline$IntMod16(0x0f)); + expectEquals(0x0f, $noinline$IntMod16(0x00ff)); + expectEquals(0x0f, $noinline$IntMod16(0x00ffff)); + expectEquals(15, $noinline$IntMod16(Integer.MAX_VALUE)); + expectEquals(0, $noinline$IntMod16(Integer.MIN_VALUE)); + + expectEquals(0, $noinline$IntModMinus16(0)); + expectEquals(1, $noinline$IntModMinus16(1)); + expectEquals(1, $noinline$IntModMinus16(17)); + expectEquals(-1, $noinline$IntModMinus16(-1)); + expectEquals(0, $noinline$IntModMinus16(32)); + expectEquals(0, $noinline$IntModMinus16(-32)); + expectEquals(0x0f, $noinline$IntModMinus16(0x0f)); + expectEquals(0x0f, $noinline$IntModMinus16(0x00ff)); + expectEquals(0x0f, $noinline$IntModMinus16(0x00ffff)); + expectEquals(15, $noinline$IntModMinus16(Integer.MAX_VALUE)); + expectEquals(0, $noinline$IntModMinus16(Integer.MIN_VALUE)); + + expectEquals(0, $noinline$IntModIntMin(0)); + expectEquals(1, $noinline$IntModIntMin(1)); + expectEquals(0, $noinline$IntModIntMin(Integer.MIN_VALUE)); + expectEquals(-1, $noinline$IntModIntMin(-1)); + expectEquals(0x0f, $noinline$IntModIntMin(0x0f)); + expectEquals(0x00ff, $noinline$IntModIntMin(0x00ff)); + expectEquals(0x00ffff, $noinline$IntModIntMin(0x00ffff)); + expectEquals(Integer.MAX_VALUE, $noinline$IntModIntMin(Integer.MAX_VALUE)); + } + + /// CHECK-START-ARM64: java.lang.Integer RemTest.$noinline$IntMod2(int) disassembly (after) + /// CHECK: cmp w{{\d+}}, #0x0 + /// CHECK: and w{{\d+}}, w{{\d+}}, #0x1 + /// CHECK: cneg w{{\d+}}, w{{\d+}}, lt + private static Integer $noinline$IntMod2(int v) { + int r = v % 2; + return r; + } + + /// CHECK-START-ARM64: java.lang.Integer RemTest.$noinline$IntModMinus2(int) disassembly (after) + /// CHECK: cmp w{{\d+}}, #0x0 + /// CHECK: and w{{\d+}}, w{{\d+}}, #0x1 + /// CHECK: cneg w{{\d+}}, w{{\d+}}, lt + private static Integer $noinline$IntModMinus2(int v) { + int r = v % -2; + return r; + } + + /// CHECK-START-ARM64: java.lang.Integer RemTest.$noinline$IntMod16(int) disassembly (after) + /// CHECK: negs w{{\d+}}, w{{\d+}} + /// CHECK: and w{{\d+}}, w{{\d+}}, #0xf + /// CHECK: and w{{\d+}}, w{{\d+}}, #0xf + /// CHECK: csneg w{{\d+}}, w{{\d+}}, mi + private static Integer $noinline$IntMod16(int v) { + int r = v % 16; + return r; + } + + /// CHECK-START-ARM64: java.lang.Integer RemTest.$noinline$IntModMinus16(int) disassembly (after) + /// CHECK: negs w{{\d+}}, w{{\d+}} + /// CHECK: and w{{\d+}}, w{{\d+}}, #0xf + /// CHECK: and w{{\d+}}, w{{\d+}}, #0xf + /// CHECK: csneg w{{\d+}}, w{{\d+}}, mi + private static Integer $noinline$IntModMinus16(int v) { + int r = v % -16; + return r; + } + + /// CHECK-START-ARM64: java.lang.Integer RemTest.$noinline$IntModIntMin(int) disassembly (after) + /// CHECK: negs w{{\d+}}, w{{\d+}} + /// CHECK: and w{{\d+}}, w{{\d+}}, #0x7fffffff + /// CHECK: and w{{\d+}}, w{{\d+}}, #0x7fffffff + /// CHECK: csneg w{{\d+}}, w{{\d+}}, mi + private static Integer $noinline$IntModIntMin(int v) { + int r = v % Integer.MIN_VALUE; + return r; + } + + private static void remLong() { + expectEquals(0L, $noinline$LongMod2(0)); + expectEquals(1L, $noinline$LongMod2(1)); + expectEquals(-1L, $noinline$LongMod2(-1)); + expectEquals(0L, $noinline$LongMod2(2)); + expectEquals(0L, $noinline$LongMod2(-2)); + expectEquals(1L, $noinline$LongMod2(3)); + expectEquals(-1L, $noinline$LongMod2(-3)); + expectEquals(1L, $noinline$LongMod2(0x0f)); + expectEquals(1L, $noinline$LongMod2(0x00ff)); + expectEquals(1L, $noinline$LongMod2(0x00ffff)); + expectEquals(1L, $noinline$LongMod2(0x00ffffff)); + expectEquals(1L, $noinline$LongMod2(0x00ffffffffL)); + expectEquals(1L, $noinline$LongMod2(Long.MAX_VALUE)); + expectEquals(0L, $noinline$LongMod2(Long.MIN_VALUE)); + + expectEquals(0L, $noinline$LongModMinus2(0)); + expectEquals(1L, $noinline$LongModMinus2(1)); + expectEquals(-1L, $noinline$LongModMinus2(-1)); + expectEquals(0L, $noinline$LongModMinus2(2)); + expectEquals(0L, $noinline$LongModMinus2(-2)); + expectEquals(1L, $noinline$LongModMinus2(3)); + expectEquals(-1L, $noinline$LongModMinus2(-3)); + expectEquals(1L, $noinline$LongModMinus2(0x0f)); + expectEquals(1L, $noinline$LongModMinus2(0x00ff)); + expectEquals(1L, $noinline$LongModMinus2(0x00ffff)); + expectEquals(1L, $noinline$LongModMinus2(0x00ffffff)); + expectEquals(1L, $noinline$LongModMinus2(0x00ffffffffL)); + expectEquals(1L, $noinline$LongModMinus2(Long.MAX_VALUE)); + expectEquals(0L, $noinline$LongModMinus2(Long.MIN_VALUE)); + + expectEquals(0L, $noinline$LongMod16(0)); + expectEquals(1L, $noinline$LongMod16(1)); + expectEquals(1L, $noinline$LongMod16(17)); + expectEquals(-1L, $noinline$LongMod16(-1)); + expectEquals(0L, $noinline$LongMod16(32)); + expectEquals(0L, $noinline$LongMod16(-32)); + expectEquals(0x0fL, $noinline$LongMod16(0x0f)); + expectEquals(0x0fL, $noinline$LongMod16(0x00ff)); + expectEquals(0x0fL, $noinline$LongMod16(0x00ffff)); + expectEquals(0x0fL, $noinline$LongMod16(0x00ffffff)); + expectEquals(0x0fL, $noinline$LongMod16(0x00ffffffffL)); + expectEquals(15L, $noinline$LongMod16(Long.MAX_VALUE)); + expectEquals(0L, $noinline$LongMod16(Long.MIN_VALUE)); + + expectEquals(0L, $noinline$LongModMinus16(0)); + expectEquals(1L, $noinline$LongModMinus16(1)); + expectEquals(1L, $noinline$LongModMinus16(17)); + expectEquals(-1L, $noinline$LongModMinus16(-1)); + expectEquals(0L, $noinline$LongModMinus16(32)); + expectEquals(0L, $noinline$LongModMinus16(-32)); + expectEquals(0x0fL, $noinline$LongModMinus16(0x0f)); + expectEquals(0x0fL, $noinline$LongModMinus16(0x00ff)); + expectEquals(0x0fL, $noinline$LongModMinus16(0x00ffff)); + expectEquals(0x0fL, $noinline$LongModMinus16(0x00ffffff)); + expectEquals(0x0fL, $noinline$LongModMinus16(0x00ffffffffL)); + expectEquals(15L, $noinline$LongModMinus16(Long.MAX_VALUE)); + expectEquals(0L, $noinline$LongModMinus16(Long.MIN_VALUE)); + + expectEquals(0L, $noinline$LongModLongMin(0)); + expectEquals(1L, $noinline$LongModLongMin(1)); + expectEquals(0L, $noinline$LongModLongMin(Long.MIN_VALUE)); + expectEquals(-1L, $noinline$LongModLongMin(-1)); + expectEquals(0x0fL, $noinline$LongModLongMin(0x0f)); + expectEquals(0x00ffL, $noinline$LongModLongMin(0x00ff)); + expectEquals(0x00ffffL, $noinline$LongModLongMin(0x00ffff)); + expectEquals(0x00ffffffL, $noinline$LongModLongMin(0x00ffffff)); + expectEquals(0x00ffffffffL, $noinline$LongModLongMin(0x00ffffffffL)); + expectEquals(Long.MAX_VALUE, $noinline$LongModLongMin(Long.MAX_VALUE)); + } + + /// CHECK-START-ARM64: java.lang.Long RemTest.$noinline$LongMod2(long) disassembly (after) + /// CHECK: cmp x{{\d+}}, #0x0 + /// CHECK: and x{{\d+}}, x{{\d+}}, #0x1 + /// CHECK: cneg x{{\d+}}, x{{\d+}}, lt + private static Long $noinline$LongMod2(long v) { + long r = v % 2; + return r; + } + + /// CHECK-START-ARM64: java.lang.Long RemTest.$noinline$LongModMinus2(long) disassembly (after) + /// CHECK: cmp x{{\d+}}, #0x0 + /// CHECK: and x{{\d+}}, x{{\d+}}, #0x1 + /// CHECK: cneg x{{\d+}}, x{{\d+}}, lt + private static Long $noinline$LongModMinus2(long v) { + long r = v % -2; + return r; + } + + /// CHECK-START-ARM64: java.lang.Long RemTest.$noinline$LongMod16(long) disassembly (after) + /// CHECK: negs x{{\d+}}, x{{\d+}} + /// CHECK: and x{{\d+}}, x{{\d+}}, #0xf + /// CHECK: and x{{\d+}}, x{{\d+}}, #0xf + /// CHECK: csneg x{{\d+}}, x{{\d+}}, mi + private static Long $noinline$LongMod16(long v) { + long r = v % 16; + return r; + } + + /// CHECK-START-ARM64: java.lang.Long RemTest.$noinline$LongModMinus16(long) disassembly (after) + /// CHECK: negs x{{\d+}}, x{{\d+}} + /// CHECK: and x{{\d+}}, x{{\d+}}, #0xf + /// CHECK: and x{{\d+}}, x{{\d+}}, #0xf + /// CHECK: csneg x{{\d+}}, x{{\d+}}, mi + private static Long $noinline$LongModMinus16(long v) { + long r = v % -16; + return r; + } + + /// CHECK-START-ARM64: java.lang.Long RemTest.$noinline$LongModLongMin(long) disassembly (after) + /// CHECK: negs x{{\d+}}, x{{\d+}} + /// CHECK: and x{{\d+}}, x{{\d+}}, #0x7fffffffffffffff + /// CHECK: and x{{\d+}}, x{{\d+}}, #0x7fffffffffffffff + /// CHECK: csneg x{{\d+}}, x{{\d+}}, mi + private static Long $noinline$LongModLongMin(long v) { + long r = v % Long.MIN_VALUE; + return r; + } +} diff --git a/test/530-checker-peel-unroll/src/Main.java b/test/530-checker-peel-unroll/src/Main.java index 804c9fe916..11c29649ff 100644 --- a/test/530-checker-peel-unroll/src/Main.java +++ b/test/530-checker-peel-unroll/src/Main.java @@ -53,11 +53,17 @@ public class Main { } private static final void initIntArray(int[] a) { - for (int i = 0; i < LENGTH; i++) { + for (int i = 0; i < a.length; i++) { a[i] = i % 4; } } + private static final void initDoubleArray(double[] a) { + for (int i = 0; i < a.length; i++) { + a[i] = (double)(i % 4); + } + } + /// CHECK-START: void Main.unrollingLoadStoreElimination(int[]) loop_optimization (before) /// CHECK-DAG: <<Array:l\d+>> ParameterValue loop:none /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none @@ -684,6 +690,96 @@ public class Main { return s + t; } + /// CHECK-START: void Main.unrollingInstanceOf(int[], java.lang.Object[]) loop_optimization (before) + /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: Phi [<<Const0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: InstanceOf loop:<<Loop>> outer_loop:none + // + /// CHECK-NOT: InstanceOf + + /// CHECK-START: void Main.unrollingInstanceOf(int[], java.lang.Object[]) loop_optimization (after) + /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: Phi [<<Const0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: InstanceOf loop:<<Loop>> outer_loop:none + /// CHECK-DAG: InstanceOf loop:<<Loop>> outer_loop:none + // + /// CHECK-NOT: InstanceOf + public void unrollingInstanceOf(int[] a, Object[] obj_array) { + for (int i = 0; i < LENGTH_B; i++) { + if (obj_array[i] instanceof Integer) { + a[i] += 1; + } + } + } + + /// CHECK-START: void Main.unrollingDivZeroCheck(int[], int) loop_optimization (before) + /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: Phi [<<Const0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: DivZeroCheck loop:<<Loop>> outer_loop:none + // + /// CHECK-NOT: DivZeroCheck + + /// CHECK-START: void Main.unrollingDivZeroCheck(int[], int) loop_optimization (after) + /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: Phi [<<Const0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: DivZeroCheck loop:<<Loop>> outer_loop:none + /// CHECK-DAG: DivZeroCheck loop:<<Loop>> outer_loop:none + // + /// CHECK-NOT: DivZeroCheck + public void unrollingDivZeroCheck(int[] a, int r) { + for (int i = 0; i < LENGTH_B; i++) { + a[i] += a[i] / r; + } + } + + /// CHECK-START: void Main.unrollingTypeConversion(int[], double[]) loop_optimization (before) + /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: Phi [<<Const0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: TypeConversion loop:<<Loop>> outer_loop:none + // + /// CHECK-NOT: TypeConversion + + /// CHECK-START: void Main.unrollingTypeConversion(int[], double[]) loop_optimization (after) + /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: Phi [<<Const0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: TypeConversion loop:<<Loop>> outer_loop:none + /// CHECK-DAG: TypeConversion loop:<<Loop>> outer_loop:none + // + /// CHECK-NOT: TypeConversion + public void unrollingTypeConversion(int[] a, double[] b) { + for (int i = 0; i < LENGTH_B; i++) { + a[i] = (int) b[i]; + } + } + + interface Itf { + } + + class SubMain extends Main implements Itf { + } + + /// CHECK-START: void Main.unrollingCheckCast(int[], java.lang.Object) loop_optimization (before) + /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: Phi [<<Const0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: CheckCast loop:<<Loop>> outer_loop:none + // + /// CHECK-NOT: CheckCast + + /// CHECK-START: void Main.unrollingCheckCast(int[], java.lang.Object) loop_optimization (after) + /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: Phi [<<Const0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: CheckCast loop:<<Loop>> outer_loop:none + /// CHECK-DAG: CheckCast loop:<<Loop>> outer_loop:none + // + /// CHECK-NOT: CheckCast + public void unrollingCheckCast(int[] a, Object o) { + for (int i = 0; i < LENGTH_B; i++) { + if (((SubMain)o) == o) { + a[i] = i; + } + } + } + /// CHECK-START: void Main.noUnrollingOddTripCount(int[]) loop_optimization (before) /// CHECK-DAG: <<Array:l\d+>> ParameterValue loop:none /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none @@ -985,9 +1081,17 @@ public class Main { initMatrix(mB); initMatrix(mC); - int expected = 174291419; + int expected = 174291515; int found = 0; + double[] doubleArray = new double[LENGTH_B]; + initDoubleArray(doubleArray); + + unrollingInstanceOf(a, new Integer[LENGTH_B]); + unrollingDivZeroCheck(a, 15); + unrollingTypeConversion(a, doubleArray); + unrollingCheckCast(a, new SubMain()); + unrollingWhile(a); unrollingLoadStoreElimination(a); unrollingSwitch(a); diff --git a/test/910-methods/check b/test/910-methods/check deleted file mode 100644 index 61846adf9b..0000000000 --- a/test/910-methods/check +++ /dev/null @@ -1,27 +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. - -./default-check "$@" -if [[ "$?" == "0" ]]; then - exit 0; -fi - -# We cannot always correctly determine if D8 was used because of (b/68406220). -# So we are just going to try to see it matches the expect output of D8 no -# matter what. -patch -p0 expected.txt < expected_d8.diff - -./default-check "$@" diff --git a/test/910-methods/expected.txt b/test/910-methods/expected.txt index 45de3db1fb..6672dc0d09 100644 --- a/test/910-methods/expected.txt +++ b/test/910-methods/expected.txt @@ -4,7 +4,7 @@ class java.lang.Object Max locals: 3 Argument size: 1 Location start: 0 -Location end: 39 +Location end: 36 Is native: false Is obsolete: false Is synthetic: false diff --git a/test/910-methods/expected_d8.diff b/test/910-methods/expected_d8.diff deleted file mode 100644 index 2c5d085418..0000000000 --- a/test/910-methods/expected_d8.diff +++ /dev/null @@ -1,4 +0,0 @@ -7c7 -< Location end: 39 ---- -> Location end: 36 diff --git a/test/913-heaps/check b/test/913-heaps/check deleted file mode 100644 index f7f8dab8cd..0000000000 --- a/test/913-heaps/check +++ /dev/null @@ -1,22 +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. - -# D8 has a different set of bytecode offsets/method IDs in the expected.txt -if [[ "$USE_D8" == true ]]; then - patch -p0 expected.txt < expected_d8.diff -fi - -./default-check "$@" diff --git a/test/913-heaps/expected.txt b/test/913-heaps/expected.txt index 57c2dc660a..01d374bebd 100644 --- a/test/913-heaps/expected.txt +++ b/test/913-heaps/expected.txt @@ -1,8 +1,7 @@ --- true true root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=136, length=-1] -root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=13,location= 30])--> 1@1000 [size=16, length=-1] -root@root --(stack-local[id=1,tag=3000,depth=3,method=doFollowReferencesTest,vreg=1,location= 28])--> 3000@0 [size=136, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=8,location= 31])--> 1@1000 [size=16, length=-1] root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=136, length=-1] root@root --(thread)--> 3000@0 [size=136, length=-1] 1001@0 --(superclass)--> 1000@0 [size=123456780000, length=-1] @@ -46,9 +45,10 @@ root@root --(thread)--> 3000@0 [size=136, length=-1] root@root --(jni-global)--> 1@1000 [size=16, length=-1] root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 1@1000 [size=16, length=-1] root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=136, length=-1] -root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=11,location= 8])--> 1@1000 [size=16, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=10,location= 8])--> 1@1000 [size=16, length=-1] root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=5,location= 8])--> 1@1000 [size=16, length=-1] -root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 19])--> 1@1000 [size=16, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=13,location= 20])--> 1@1000 [size=16, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 20])--> 1@1000 [size=16, length=-1] root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=136, length=-1] root@root --(thread)--> 1@1000 [size=16, length=-1] root@root --(thread)--> 3000@0 [size=136, length=-1] @@ -99,8 +99,7 @@ root@root --(thread)--> 3000@0 [size=136, length=-1] 3@1001 --(class)--> 1001@0 [size=123456780016, length=-1] --- root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=136, length=-1] -root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=13,location= 30])--> 1@1000 [size=16, length=-1] -root@root --(stack-local[id=1,tag=3000,depth=3,method=doFollowReferencesTest,vreg=1,location= 28])--> 3000@0 [size=136, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=8,location= 31])--> 1@1000 [size=16, length=-1] root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=136, length=-1] root@root --(thread)--> 3000@0 [size=136, length=-1] --- @@ -112,9 +111,10 @@ root@root --(thread)--> 3000@0 [size=136, length=-1] root@root --(jni-global)--> 1@1000 [size=16, length=-1] root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 1@1000 [size=16, length=-1] root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=136, length=-1] -root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=11,location= 8])--> 1@1000 [size=16, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=10,location= 8])--> 1@1000 [size=16, length=-1] root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=5,location= 8])--> 1@1000 [size=16, length=-1] -root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 19])--> 1@1000 [size=16, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=13,location= 20])--> 1@1000 [size=16, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 20])--> 1@1000 [size=16, length=-1] root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=136, length=-1] root@root --(thread)--> 1@1000 [size=16, length=-1] root@root --(thread)--> 3000@0 [size=136, length=-1] @@ -159,7 +159,7 @@ root@root --(thread)--> 3000@0 [size=136, length=-1] 10007@0 (instance, float, index=13) 000000003f9d70a4 10008 --- klass --- -root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=13,location= 30])--> 1@1000 [size=16, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=8,location= 31])--> 1@1000 [size=16, length=-1] 1@1000 --(field@2)--> 2@1000 [size=16, length=-1] 3@1001 --(field@4)--> 4@1000 [size=16, length=-1] 500@0 --(array-element@1)--> 2@1000 [size=16, length=-1] @@ -174,9 +174,10 @@ root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonR --- root@root --(jni-global)--> 1@1000 [size=16, length=-1] root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 1@1000 [size=16, length=-1] -root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=11,location= 8])--> 1@1000 [size=16, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=10,location= 8])--> 1@1000 [size=16, length=-1] root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=5,location= 8])--> 1@1000 [size=16, length=-1] -root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 19])--> 1@1000 [size=16, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=13,location= 20])--> 1@1000 [size=16, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 20])--> 1@1000 [size=16, length=-1] root@root --(thread)--> 1@1000 [size=16, length=-1] 1@1000 --(field@2)--> 2@1000 [size=16, length=-1] 3@1001 --(field@4)--> 4@1000 [size=16, length=-1] @@ -198,8 +199,7 @@ root@root --(thread)--> 1@1000 [size=16, length=-1] --- ---- untagged objects root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=136, length=-1] -root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=13,location= 30])--> 1@1000 [size=16, length=-1] -root@root --(stack-local[id=1,tag=3000,depth=3,method=doFollowReferencesTest,vreg=1,location= 28])--> 3000@0 [size=136, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=8,location= 31])--> 1@1000 [size=16, length=-1] root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=136, length=-1] root@root --(thread)--> 3000@0 [size=136, length=-1] 1001@0 --(superclass)--> 1000@0 [size=123456780050, length=-1] @@ -243,9 +243,10 @@ root@root --(thread)--> 3000@0 [size=136, length=-1] root@root --(jni-global)--> 1@1000 [size=16, length=-1] root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 1@1000 [size=16, length=-1] root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=136, length=-1] -root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=11,location= 8])--> 1@1000 [size=16, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=10,location= 8])--> 1@1000 [size=16, length=-1] root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=5,location= 8])--> 1@1000 [size=16, length=-1] -root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 19])--> 1@1000 [size=16, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=13,location= 20])--> 1@1000 [size=16, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 20])--> 1@1000 [size=16, length=-1] root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=136, length=-1] root@root --(thread)--> 1@1000 [size=16, length=-1] root@root --(thread)--> 3000@0 [size=136, length=-1] @@ -289,7 +290,6 @@ root@root --(thread)--> 3000@0 [size=136, length=-1] --- ---- tagged classes root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=136, length=-1] -root@root --(stack-local[id=1,tag=3000,depth=3,method=doFollowReferencesTest,vreg=1,location= 28])--> 3000@0 [size=136, length=-1] root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=136, length=-1] root@root --(thread)--> 3000@0 [size=136, length=-1] 1001@0 --(superclass)--> 1000@0 [size=123456780060, length=-1] @@ -344,7 +344,7 @@ root@root --(thread)--> 3000@0 [size=136, length=-1] 6@1000 --(class)--> 1000@0 [size=123456780065, length=-1] --- ---- untagged classes -root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=13,location= 30])--> 1@1000 [size=16, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=8,location= 31])--> 1@1000 [size=16, length=-1] 1@1000 --(field@2)--> 2@1000 [size=16, length=-1] 1@1000 --(field@3)--> 3@1001 [size=24, length=-1] 3@1001 --(field@4)--> 4@1000 [size=16, length=-1] @@ -363,9 +363,10 @@ root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonR --- root@root --(jni-global)--> 1@1000 [size=16, length=-1] root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 1@1000 [size=16, length=-1] -root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=11,location= 8])--> 1@1000 [size=16, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=10,location= 8])--> 1@1000 [size=16, length=-1] root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=5,location= 8])--> 1@1000 [size=16, length=-1] -root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 19])--> 1@1000 [size=16, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=13,location= 20])--> 1@1000 [size=16, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 20])--> 1@1000 [size=16, length=-1] root@root --(thread)--> 1@1000 [size=16, length=-1] 1@1000 --(field@2)--> 2@1000 [size=16, length=-1] 1@1000 --(field@3)--> 3@1001 [size=24, length=-1] diff --git a/test/913-heaps/expected_d8.diff b/test/913-heaps/expected_d8.diff deleted file mode 100644 index 1ad0cbdd3b..0000000000 --- a/test/913-heaps/expected_d8.diff +++ /dev/null @@ -1,70 +0,0 @@ -4,5c4 -< root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=13,location= 30])--> 1@1000 [size=16, length=-1] -< root@root --(stack-local[id=1,tag=3000,depth=3,method=doFollowReferencesTest,vreg=1,location= 28])--> 3000@0 [size=136, length=-1] ---- -> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=8,location= 31])--> 1@1000 [size=16, length=-1] -49c48 -< root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=11,location= 8])--> 1@1000 [size=16, length=-1] ---- -> root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=10,location= 8])--> 1@1000 [size=16, length=-1] -51c50,51 -< root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 19])--> 1@1000 [size=16, length=-1] ---- -> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=13,location= 20])--> 1@1000 [size=16, length=-1] -> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 20])--> 1@1000 [size=16, length=-1] -102,103c102 -< root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=13,location= 30])--> 1@1000 [size=16, length=-1] -< root@root --(stack-local[id=1,tag=3000,depth=3,method=doFollowReferencesTest,vreg=1,location= 28])--> 3000@0 [size=136, length=-1] ---- -> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=8,location= 31])--> 1@1000 [size=16, length=-1] -115c114 -< root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=11,location= 8])--> 1@1000 [size=16, length=-1] ---- -> root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=10,location= 8])--> 1@1000 [size=16, length=-1] -117c116,117 -< root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 19])--> 1@1000 [size=16, length=-1] ---- -> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=13,location= 20])--> 1@1000 [size=16, length=-1] -> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 20])--> 1@1000 [size=16, length=-1] -162c162 -< root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=13,location= 30])--> 1@1000 [size=16, length=-1] ---- -> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=8,location= 31])--> 1@1000 [size=16, length=-1] -177c177 -< root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=11,location= 8])--> 1@1000 [size=16, length=-1] ---- -> root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=10,location= 8])--> 1@1000 [size=16, length=-1] -179c179,180 -< root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 19])--> 1@1000 [size=16, length=-1] ---- -> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=13,location= 20])--> 1@1000 [size=16, length=-1] -> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 20])--> 1@1000 [size=16, length=-1] -201,202c202 -< root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=13,location= 30])--> 1@1000 [size=16, length=-1] -< root@root --(stack-local[id=1,tag=3000,depth=3,method=doFollowReferencesTest,vreg=1,location= 28])--> 3000@0 [size=136, length=-1] ---- -> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=8,location= 31])--> 1@1000 [size=16, length=-1] -246c246 -< root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=11,location= 8])--> 1@1000 [size=16, length=-1] ---- -> root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=10,location= 8])--> 1@1000 [size=16, length=-1] -248c248,249 -< root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 19])--> 1@1000 [size=16, length=-1] ---- -> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=13,location= 20])--> 1@1000 [size=16, length=-1] -> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 20])--> 1@1000 [size=16, length=-1] -292d292 -< root@root --(stack-local[id=1,tag=3000,depth=3,method=doFollowReferencesTest,vreg=1,location= 28])--> 3000@0 [size=136, length=-1] -347c347 -< root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=13,location= 30])--> 1@1000 [size=16, length=-1] ---- -> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=8,location= 31])--> 1@1000 [size=16, length=-1] -366c366 -< root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=11,location= 8])--> 1@1000 [size=16, length=-1] ---- -> root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=10,location= 8])--> 1@1000 [size=16, length=-1] -368c368,369 -< root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 19])--> 1@1000 [size=16, length=-1] ---- -> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=13,location= 20])--> 1@1000 [size=16, length=-1] -> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 20])--> 1@1000 [size=16, length=-1] diff --git a/test/common/runtime_state.cc b/test/common/runtime_state.cc index f89888bb99..f2da6febe0 100644 --- a/test/common/runtime_state.cc +++ b/test/common/runtime_state.cc @@ -60,7 +60,7 @@ extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasOatFile(JNIEnv* env, jclass c ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(cls); const DexFile& dex_file = klass->GetDexFile(); - const OatFile::OatDexFile* oat_dex_file = dex_file.GetOatDexFile(); + const OatDexFile* oat_dex_file = dex_file.GetOatDexFile(); return (oat_dex_file != nullptr) ? JNI_TRUE : JNI_FALSE; } @@ -100,7 +100,7 @@ extern "C" JNIEXPORT jboolean JNICALL Java_Main_compiledWithOptimizing(JNIEnv* e ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(cls); const DexFile& dex_file = klass->GetDexFile(); - const OatFile::OatDexFile* oat_dex_file = dex_file.GetOatDexFile(); + const OatDexFile* oat_dex_file = dex_file.GetOatDexFile(); if (oat_dex_file == nullptr) { // Could be JIT, which also uses optimizing, but conservatively say no. return JNI_FALSE; diff --git a/test/knownfailures.json b/test/knownfailures.json index f6ae0be5c0..9ba2b50cba 100644 --- a/test/knownfailures.json +++ b/test/knownfailures.json @@ -454,6 +454,14 @@ }, { "tests": [ + "638-no-line-number" + ], + "description": ["Tests that fail on redefine stress due to branch instruction selection"], + "bug": "b/110869946", + "variant": "redefine-stress" + }, + { + "tests": [ "097-duplicate-method", "138-duplicate-classes-check2", "159-app-image-fields", diff --git a/tools/ahat/etc/ahat_api.txt b/tools/ahat/etc/ahat_api.txt index 84266d9164..f60c1a84fa 100644 --- a/tools/ahat/etc/ahat_api.txt +++ b/tools/ahat/etc/ahat_api.txt @@ -66,19 +66,21 @@ package com.android.ahat.heapdump { method public java.util.List<com.android.ahat.heapdump.AhatInstance> getDominated(); method public java.lang.Object getDominatorsComputationState(); method public com.android.ahat.heapdump.Value getField(java.lang.String); - method public java.util.List<com.android.ahat.heapdump.AhatInstance> getHardReverseReferences(); + method public deprecated java.util.List<com.android.ahat.heapdump.AhatInstance> getHardReverseReferences(); method public com.android.ahat.heapdump.AhatHeap getHeap(); method public long getId(); method public com.android.ahat.heapdump.AhatInstance getImmediateDominator(); method public java.util.List<com.android.ahat.heapdump.PathElement> getPathFromGcRoot(); + method public com.android.ahat.heapdump.Reachability getReachability(); method public com.android.ahat.heapdump.AhatInstance getRefField(java.lang.String); method public java.lang.Iterable<? extends com.android.ahat.dominators.DominatorsComputation.Node> getReferencesForDominators(); method public com.android.ahat.heapdump.AhatInstance getReferent(); method public com.android.ahat.heapdump.Size getRetainedSize(com.android.ahat.heapdump.AhatHeap); + method public java.util.List<com.android.ahat.heapdump.AhatInstance> getReverseReferences(); method public java.util.Collection<com.android.ahat.heapdump.RootType> getRootTypes(); method public com.android.ahat.heapdump.Site getSite(); method public com.android.ahat.heapdump.Size getSize(); - method public java.util.List<com.android.ahat.heapdump.AhatInstance> getSoftReverseReferences(); + method public deprecated java.util.List<com.android.ahat.heapdump.AhatInstance> getSoftReverseReferences(); method public com.android.ahat.heapdump.Size getTotalRetainedSize(); method public boolean isArrayInstance(); method public boolean isClassInstance(); @@ -87,7 +89,7 @@ package com.android.ahat.heapdump { method public boolean isRoot(); method public boolean isStronglyReachable(); method public boolean isUnreachable(); - method public boolean isWeaklyReachable(); + method public deprecated boolean isWeaklyReachable(); method public void setDominator(com.android.ahat.dominators.DominatorsComputation.Node); method public void setDominatorsComputationState(java.lang.Object); method public abstract java.lang.String toString(); @@ -174,6 +176,17 @@ package com.android.ahat.heapdump { field public boolean isDominator; } + public final class Reachability extends java.lang.Enum { + method public static com.android.ahat.heapdump.Reachability valueOf(java.lang.String); + method public static final com.android.ahat.heapdump.Reachability[] values(); + enum_constant public static final com.android.ahat.heapdump.Reachability FINALIZER; + enum_constant public static final com.android.ahat.heapdump.Reachability PHANTOM; + enum_constant public static final com.android.ahat.heapdump.Reachability SOFT; + enum_constant public static final com.android.ahat.heapdump.Reachability STRONG; + enum_constant public static final com.android.ahat.heapdump.Reachability UNREACHABLE; + enum_constant public static final com.android.ahat.heapdump.Reachability WEAK; + } + public final class RootType extends java.lang.Enum { method public static com.android.ahat.heapdump.RootType valueOf(java.lang.String); method public static final com.android.ahat.heapdump.RootType[] values(); diff --git a/tools/ahat/src/main/com/android/ahat/ObjectHandler.java b/tools/ahat/src/main/com/android/ahat/ObjectHandler.java index bfd5d5cacd..c099da8ceb 100644 --- a/tools/ahat/src/main/com/android/ahat/ObjectHandler.java +++ b/tools/ahat/src/main/com/android/ahat/ObjectHandler.java @@ -44,8 +44,7 @@ class ObjectHandler implements AhatHandler { private static final String DOMINATED_OBJECTS_ID = "dominated"; private static final String INSTANCE_FIELDS_ID = "ifields"; private static final String STATIC_FIELDS_ID = "sfields"; - private static final String HARD_REFS_ID = "refs"; - private static final String SOFT_REFS_ID = "srefs"; + private static final String REFS_ID = "refs"; private AhatSnapshot mSnapshot; @@ -223,24 +222,12 @@ class ObjectHandler implements AhatHandler { private static void printReferences(Doc doc, Query query, AhatInstance inst) { doc.section("Objects with References to this Object"); - if (inst.getHardReverseReferences().isEmpty()) { + if (inst.getReverseReferences().isEmpty()) { doc.println(DocString.text("(none)")); } else { doc.table(new Column("Object")); - List<AhatInstance> references = inst.getHardReverseReferences(); - SubsetSelector<AhatInstance> selector = new SubsetSelector(query, HARD_REFS_ID, references); - for (AhatInstance ref : selector.selected()) { - doc.row(Summarizer.summarize(ref)); - } - doc.end(); - selector.render(doc); - } - - if (!inst.getSoftReverseReferences().isEmpty()) { - doc.section("Objects with Soft References to this Object"); - doc.table(new Column("Object")); - List<AhatInstance> references = inst.getSoftReverseReferences(); - SubsetSelector<AhatInstance> selector = new SubsetSelector(query, SOFT_REFS_ID, references); + List<AhatInstance> references = inst.getReverseReferences(); + SubsetSelector<AhatInstance> selector = new SubsetSelector(query, REFS_ID, references); for (AhatInstance ref : selector.selected()) { doc.row(Summarizer.summarize(ref)); } diff --git a/tools/ahat/src/main/com/android/ahat/Summarizer.java b/tools/ahat/src/main/com/android/ahat/Summarizer.java index 127ff37aea..ab88c04d32 100644 --- a/tools/ahat/src/main/com/android/ahat/Summarizer.java +++ b/tools/ahat/src/main/com/android/ahat/Summarizer.java @@ -18,6 +18,7 @@ package com.android.ahat; import com.android.ahat.heapdump.AhatClassObj; import com.android.ahat.heapdump.AhatInstance; +import com.android.ahat.heapdump.Reachability; import com.android.ahat.heapdump.Site; import com.android.ahat.heapdump.Value; import java.net.URI; @@ -51,11 +52,10 @@ class Summarizer { formatted.append(DocString.removed("del ")); } - // Annotate unreachable objects as such. - if (inst.isWeaklyReachable()) { - formatted.append("weak "); - } else if (inst.isUnreachable()) { - formatted.append("unreachable "); + // Annotate non-strongly reachable objects as such. + Reachability reachability = inst.getReachability(); + if (reachability != Reachability.STRONG) { + formatted.append(reachability.toString() + " "); } // Annotate roots as roots. diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/AhatArrayInstance.java b/tools/ahat/src/main/com/android/ahat/heapdump/AhatArrayInstance.java index c574e98788..cf48d6d459 100644 --- a/tools/ahat/src/main/com/android/ahat/heapdump/AhatArrayInstance.java +++ b/tools/ahat/src/main/com/android/ahat/heapdump/AhatArrayInstance.java @@ -240,7 +240,10 @@ public class AhatArrayInstance extends AhatInstance { if (value != null) { assert value.isAhatInstance(); String field = "[" + Integer.toString(index) + "]"; - return new Reference(AhatArrayInstance.this, field, value.asAhatInstance(), true); + return new Reference(AhatArrayInstance.this, + field, + value.asAhatInstance(), + Reachability.STRONG); } return null; } @@ -324,7 +327,7 @@ public class AhatArrayInstance extends AhatInstance { @Override public AhatInstance getAssociatedBitmapInstance() { if (mByteArray != null) { - List<AhatInstance> refs = getHardReverseReferences(); + List<AhatInstance> refs = getReverseReferences(); if (refs.size() == 1) { AhatInstance ref = refs.get(0); return ref.getAssociatedBitmapInstance(); diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/AhatClassInstance.java b/tools/ahat/src/main/com/android/ahat/heapdump/AhatClassInstance.java index c82ef20e9b..f377ae37bc 100644 --- a/tools/ahat/src/main/com/android/ahat/heapdump/AhatClassInstance.java +++ b/tools/ahat/src/main/com/android/ahat/heapdump/AhatClassInstance.java @@ -104,10 +104,7 @@ public class AhatClassInstance extends AhatInstance { @Override Iterable<Reference> getReferences() { - if (isInstanceOfClass("java.lang.ref.Reference")) { - return new WeakReferentReferenceIterator(); - } - return new StrongReferenceIterator(); + return new ReferenceIterator(); } /** @@ -352,59 +349,48 @@ public class AhatClassInstance extends AhatInstance { } /** - * A Reference iterator that iterates over the fields of this instance - * assuming all field references are strong references. + * Returns the reachability type associated with this instance. + * For example, returns Reachability.WEAK for an instance of + * java.lang.ref.WeakReference. */ - private class StrongReferenceIterator implements Iterable<Reference>, - Iterator<Reference> { - private Iterator<FieldValue> mIter = getInstanceFields().iterator(); - private Reference mNext = null; - - @Override - public boolean hasNext() { - while (mNext == null && mIter.hasNext()) { - FieldValue field = mIter.next(); - if (field.value != null && field.value.isAhatInstance()) { - AhatInstance ref = field.value.asAhatInstance(); - mNext = new Reference(AhatClassInstance.this, "." + field.name, ref, true); - } - } - return mNext != null; - } - - @Override - public Reference next() { - if (!hasNext()) { - throw new NoSuchElementException(); + private Reachability getJavaLangRefType() { + AhatClassObj cls = getClassObj(); + while (cls != null) { + switch (cls.getName()) { + case "java.lang.ref.PhantomReference": return Reachability.PHANTOM; + case "java.lang.ref.WeakReference": return Reachability.WEAK; + case "java.lang.ref.FinalizerReference": return Reachability.FINALIZER; + case "java.lang.ref.SoftReference": return Reachability.SOFT; } - Reference next = mNext; - mNext = null; - return next; - } - - @Override - public Iterator<Reference> iterator() { - return this; + cls = cls.getSuperClassObj(); } + return Reachability.STRONG; } /** - * A Reference iterator that iterates over the fields of a subclass of - * java.lang.ref.Reference, where the 'referent' field is considered weak. + * A Reference iterator that iterates over the fields of this instance. */ - private class WeakReferentReferenceIterator implements Iterable<Reference>, - Iterator<Reference> { - private Iterator<FieldValue> mIter = getInstanceFields().iterator(); + private class ReferenceIterator implements Iterable<Reference>, + Iterator<Reference> { + private final Iterator<FieldValue> mIter = getInstanceFields().iterator(); private Reference mNext = null; + // If we are iterating over a subclass of java.lang.ref.Reference, the + // 'referent' field doesn't have strong reachability. mJavaLangRefType + // describes what type of java.lang.ref.Reference subinstance this is. + private final Reachability mJavaLangRefType = getJavaLangRefType(); + @Override public boolean hasNext() { while (mNext == null && mIter.hasNext()) { FieldValue field = mIter.next(); if (field.value != null && field.value.isAhatInstance()) { - boolean strong = !field.name.equals("referent"); + Reachability reachability = Reachability.STRONG; + if (mJavaLangRefType != Reachability.STRONG && "referent".equals(field.name)) { + reachability = mJavaLangRefType; + } AhatInstance ref = field.value.asAhatInstance(); - mNext = new Reference(AhatClassInstance.this, "." + field.name, ref, strong); + mNext = new Reference(AhatClassInstance.this, "." + field.name, ref, reachability); } } return mNext != null; diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/AhatClassObj.java b/tools/ahat/src/main/com/android/ahat/heapdump/AhatClassObj.java index 36ada2857c..765a411e41 100644 --- a/tools/ahat/src/main/com/android/ahat/heapdump/AhatClassObj.java +++ b/tools/ahat/src/main/com/android/ahat/heapdump/AhatClassObj.java @@ -131,7 +131,10 @@ public class AhatClassObj extends AhatInstance { FieldValue field = mStaticFieldValues[index]; Value value = field.value; if (value != null && value.isAhatInstance()) { - return new Reference(AhatClassObj.this, "." + field.name, value.asAhatInstance(), true); + return new Reference(AhatClassObj.this, + "." + field.name, + value.asAhatInstance(), + Reachability.STRONG); } return null; } diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/AhatInstance.java b/tools/ahat/src/main/com/android/ahat/heapdump/AhatInstance.java index a91da82ce9..20f368f4ff 100644 --- a/tools/ahat/src/main/com/android/ahat/heapdump/AhatInstance.java +++ b/tools/ahat/src/main/com/android/ahat/heapdump/AhatInstance.java @@ -24,6 +24,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Deque; +import java.util.EnumMap; import java.util.List; import java.util.Queue; @@ -48,11 +49,11 @@ public abstract class AhatInstance implements Diffable<AhatInstance>, // Field initialized via addRegisterednativeSize. private long mRegisteredNativeSize = 0; - // Fields initialized in computeReverseReferences(). + // Fields initialized in computeReachability(). + private Reachability mReachability = Reachability.UNREACHABLE; private AhatInstance mNextInstanceToGcRoot; private String mNextInstanceToGcRootField; - private ArrayList<AhatInstance> mHardReverseReferences; - private ArrayList<AhatInstance> mSoftReverseReferences; + private ArrayList<AhatInstance> mReverseReferences; // Fields initialized in DominatorsComputation.computeDominators(). // mDominated - the list of instances immediately dominated by this instance. @@ -157,6 +158,15 @@ public abstract class AhatInstance implements Diffable<AhatInstance>, } /** + * Returns the reachability of the instance. + * + * @return the reachability of the instance. + */ + public Reachability getReachability() { + return mReachability; + } + + /** * Returns true if this object is strongly reachable. An object is strongly * reachable if there exists a path of (strong) references from some root * object to this object. @@ -164,7 +174,7 @@ public abstract class AhatInstance implements Diffable<AhatInstance>, * @return true if the object is strongly reachable */ public boolean isStronglyReachable() { - return mImmediateDominator != null; + return mReachability == Reachability.STRONG; } /** @@ -178,10 +188,13 @@ public abstract class AhatInstance implements Diffable<AhatInstance>, * Unlike a strongly reachable object, a weakly reachable object is allowed * to be garbage collected. * + * @deprecated Use {@link #getReachability()} instead, which can distinguish + * among soft, weak, phantom, and other kinds of references. + * * @return true if the object is weakly reachable */ - public boolean isWeaklyReachable() { - return !isStronglyReachable() && mNextInstanceToGcRoot != null; + @Deprecated public boolean isWeaklyReachable() { + return !isStronglyReachable() && !isUnreachable(); } /** @@ -193,7 +206,7 @@ public abstract class AhatInstance implements Diffable<AhatInstance>, * @return true if the object is completely unreachable */ public boolean isUnreachable() { - return !isStronglyReachable() && !isWeaklyReachable(); + return mReachability == Reachability.UNREACHABLE; } /** @@ -215,7 +228,6 @@ public abstract class AhatInstance implements Diffable<AhatInstance>, * Returns true if this instance is a GC root. * * @return true if this instance is a GC root. - * @see getRootTypes */ public boolean isRoot() { return mRootTypes != 0; @@ -374,28 +386,50 @@ public abstract class AhatInstance implements Diffable<AhatInstance>, } /** - * Returns a list of objects with (strong) references to this object. + * Returns a list of objects with any kind of reference to this object. * * @return the objects referencing this object */ - public List<AhatInstance> getHardReverseReferences() { - if (mHardReverseReferences != null) { - return mHardReverseReferences; + public List<AhatInstance> getReverseReferences() { + if (mReverseReferences != null) { + return mReverseReferences; } return Collections.emptyList(); } /** + * Returns a list of objects with (strong) references to this object. + * + * @deprecated Use {@link #getReverseReferences()} instead. + * + * @return the objects referencing this object + */ + @Deprecated public List<AhatInstance> getHardReverseReferences() { + List<AhatInstance> refs = new ArrayList<AhatInstance>(); + for (AhatInstance ref : getReverseReferences()) { + if (ref.getReachability() == Reachability.STRONG && ref.getReferent() != this) { + refs.add(ref); + } + } + return refs; + } + + /** * Returns a list of objects with soft/weak/phantom/finalizer references to * this object. * + * @deprecated Use {@link #getReverseReferences()} instead. + * * @return the objects weakly referencing this object */ - public List<AhatInstance> getSoftReverseReferences() { - if (mSoftReverseReferences != null) { - return mSoftReverseReferences; + @Deprecated public List<AhatInstance> getSoftReverseReferences() { + List<AhatInstance> refs = new ArrayList<AhatInstance>(); + for (AhatInstance ref : getReverseReferences()) { + if (ref.getReachability() != Reachability.STRONG || ref.getReferent() == this) { + refs.add(ref); + } } - return Collections.emptyList(); + return refs; } /** @@ -610,82 +644,60 @@ public abstract class AhatInstance implements Diffable<AhatInstance>, } /** - * Initialize the reverse reference fields of this instance and all other - * instances reachable from it. Initializes the following fields: + * Determine the reachability of the all instances reachable from the given + * root instance. Initializes the following fields: + * mReachability * mNextInstanceToGcRoot * mNextInstanceToGcRootField - * mHardReverseReferences - * mSoftReverseReferences + * mReverseReferences * * @param progress used to track progress of the traversal. * @param numInsts upper bound on the total number of instances reachable * from the root, solely used for the purposes of tracking * progress. */ - static void computeReverseReferences(SuperRoot root, Progress progress, long numInsts) { + static void computeReachability(SuperRoot root, Progress progress, long numInsts) { // Start by doing a breadth first search through strong references. - // Then continue the breadth first search through weak references. - progress.start("Reversing references", numInsts); - Queue<Reference> strong = new ArrayDeque<Reference>(); - Queue<Reference> weak = new ArrayDeque<Reference>(); + // Then continue the breadth first through each weaker kind of reference. + progress.start("Computing reachability", numInsts); + EnumMap<Reachability, Queue<Reference>> queues = new EnumMap<>(Reachability.class); + for (Reachability reachability : Reachability.values()) { + queues.put(reachability, new ArrayDeque<Reference>()); + } for (Reference ref : root.getReferences()) { - strong.add(ref); + queues.get(Reachability.STRONG).add(ref); } - while (!strong.isEmpty()) { - Reference ref = strong.poll(); - assert ref.strong; - - if (ref.ref.mNextInstanceToGcRoot == null) { - // This is the first time we have seen ref.ref. - progress.advance(); - ref.ref.mNextInstanceToGcRoot = ref.src; - ref.ref.mNextInstanceToGcRootField = ref.field; - ref.ref.mHardReverseReferences = new ArrayList<AhatInstance>(); - - for (Reference childRef : ref.ref.getReferences()) { - if (childRef.strong) { - strong.add(childRef); - } else { - weak.add(childRef); + for (Reachability reachability : Reachability.values()) { + Queue<Reference> queue = queues.get(reachability); + while (!queue.isEmpty()) { + Reference ref = queue.poll(); + if (ref.ref.mReachability == Reachability.UNREACHABLE) { + // This is the first time we have seen ref.ref. + progress.advance(); + ref.ref.mReachability = reachability; + ref.ref.mNextInstanceToGcRoot = ref.src; + ref.ref.mNextInstanceToGcRootField = ref.field; + ref.ref.mReverseReferences = new ArrayList<AhatInstance>(); + + for (Reference childRef : ref.ref.getReferences()) { + if (childRef.reachability.ordinal() <= reachability.ordinal()) { + queue.add(childRef); + } else { + queues.get(childRef.reachability).add(childRef); + } } } - } - - // Note: We specifically exclude 'root' from the reverse references - // because it is a fake SuperRoot instance not present in the original - // heap dump. - if (ref.src != root) { - ref.ref.mHardReverseReferences.add(ref.src); - } - } - - while (!weak.isEmpty()) { - Reference ref = weak.poll(); - - if (ref.ref.mNextInstanceToGcRoot == null) { - // This is the first time we have seen ref.ref. - progress.advance(); - ref.ref.mNextInstanceToGcRoot = ref.src; - ref.ref.mNextInstanceToGcRootField = ref.field; - ref.ref.mHardReverseReferences = new ArrayList<AhatInstance>(); - - for (Reference childRef : ref.ref.getReferences()) { - weak.add(childRef); - } - } - if (ref.strong) { - ref.ref.mHardReverseReferences.add(ref.src); - } else { - if (ref.ref.mSoftReverseReferences == null) { - ref.ref.mSoftReverseReferences = new ArrayList<AhatInstance>(); + // Note: We specifically exclude 'root' from the reverse references + // because it is a fake SuperRoot instance not present in the original + // heap dump. + if (ref.src != root) { + ref.ref.mReverseReferences.add(ref.src); } - ref.ref.mSoftReverseReferences.add(ref.src); } } - progress.done(); } diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/AhatSnapshot.java b/tools/ahat/src/main/com/android/ahat/heapdump/AhatSnapshot.java index bc940479b1..d9c7a19431 100644 --- a/tools/ahat/src/main/com/android/ahat/heapdump/AhatSnapshot.java +++ b/tools/ahat/src/main/com/android/ahat/heapdump/AhatSnapshot.java @@ -55,7 +55,7 @@ public class AhatSnapshot implements Diffable<AhatSnapshot> { } } - AhatInstance.computeReverseReferences(mSuperRoot, progress, mInstances.size()); + AhatInstance.computeReachability(mSuperRoot, progress, mInstances.size()); DominatorsComputation.computeDominators(mSuperRoot, progress, mInstances.size()); AhatInstance.computeRetainedSize(mSuperRoot, mHeaps.size()); diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/DominatorReferenceIterator.java b/tools/ahat/src/main/com/android/ahat/heapdump/DominatorReferenceIterator.java index 0b99e496cc..8c8de2383b 100644 --- a/tools/ahat/src/main/com/android/ahat/heapdump/DominatorReferenceIterator.java +++ b/tools/ahat/src/main/com/android/ahat/heapdump/DominatorReferenceIterator.java @@ -37,7 +37,7 @@ class DominatorReferenceIterator implements Iterator<AhatInstance>, public boolean hasNext() { while (mNext == null && mIter.hasNext()) { Reference ref = mIter.next(); - if (ref.strong) { + if (ref.reachability == Reachability.STRONG) { mNext = ref.ref; } } diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/Reachability.java b/tools/ahat/src/main/com/android/ahat/heapdump/Reachability.java new file mode 100644 index 0000000000..8df6c8ca23 --- /dev/null +++ b/tools/ahat/src/main/com/android/ahat/heapdump/Reachability.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 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 + * + * 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. + */ + +package com.android.ahat.heapdump; + +/** + * Enum corresponding to the reachability of an instance. + * See {@link java.lang.ref} for a specification of the various kinds of + * reachibility. The enum constants are specified in decreasing order of + * strength. + */ +public enum Reachability { + /** + * The instance is strongly reachable. + */ + STRONG("strong"), + + /** + * The instance is softly reachable. + */ + SOFT("soft"), + + /** + * The instance is finalizer reachable, but is neither strongly nor softly + * reachable. + */ + FINALIZER("finalizer"), + + /** + * The instance is weakly reachable. + */ + WEAK("weak"), + + /** + * The instance is phantom reachable. + */ + PHANTOM("phantom"), + + /** + * The instance is unreachable. + */ + UNREACHABLE("unreachable"); + + /** + * The name of the reachibility. + */ + private final String name; + + Reachability(String name) { + this.name = name; + } + + @Override + public String toString() { + return name; + } +} diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/Reference.java b/tools/ahat/src/main/com/android/ahat/heapdump/Reference.java index f1340bd07b..2de76fdc87 100644 --- a/tools/ahat/src/main/com/android/ahat/heapdump/Reference.java +++ b/tools/ahat/src/main/com/android/ahat/heapdump/Reference.java @@ -20,19 +20,18 @@ package com.android.ahat.heapdump; * Reference represents a reference from 'src' to 'ref' through 'field'. * Field is a string description for human consumption. This is typically * either "." followed by the field name or an array subscript such as "[4]". - * 'strong' is true if this is a strong reference, false if it is a - * weak/soft/other reference. + * reachability describes whether the reference is strong/soft/weak/etc. */ class Reference { public final AhatInstance src; public final String field; public final AhatInstance ref; - public final boolean strong; + public final Reachability reachability; - public Reference(AhatInstance src, String field, AhatInstance ref, boolean strong) { + public Reference(AhatInstance src, String field, AhatInstance ref, Reachability reachability) { this.src = src; this.field = field; this.ref = ref; - this.strong = strong; + this.reachability = reachability; } } diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/SuperRoot.java b/tools/ahat/src/main/com/android/ahat/heapdump/SuperRoot.java index b01cffff72..d06df900fb 100644 --- a/tools/ahat/src/main/com/android/ahat/heapdump/SuperRoot.java +++ b/tools/ahat/src/main/com/android/ahat/heapdump/SuperRoot.java @@ -54,7 +54,7 @@ class SuperRoot extends AhatInstance implements DominatorsComputation.Node { @Override public Reference get(int index) { String field = ".roots[" + Integer.toString(index) + "]"; - return new Reference(SuperRoot.this, field, mRoots.get(index), true); + return new Reference(SuperRoot.this, field, mRoots.get(index), Reachability.STRONG); } }; } diff --git a/tools/ahat/src/test-dump/DumpedStuff.java b/tools/ahat/src/test-dump/DumpedStuff.java index 98ead07492..804a3a37d4 100644 --- a/tools/ahat/src/test-dump/DumpedStuff.java +++ b/tools/ahat/src/test-dump/DumpedStuff.java @@ -136,6 +136,7 @@ public class DumpedStuff extends SuperDumpedStuff { public WeakReference aWeakReference = new WeakReference(anObject, referenceQueue); public WeakReference aNullReferentReference = new WeakReference(null, referenceQueue); public SoftReference aSoftReference = new SoftReference(new Object()); + public Reference reachabilityReferenceChain; public byte[] bigArray; public ObjectTree[] gcPathArray = new ObjectTree[]{null, null, new ObjectTree( @@ -145,7 +146,7 @@ public class DumpedStuff extends SuperDumpedStuff { public Reference aLongStrongPathToSamplePathObject; public WeakReference aShortWeakPathToSamplePathObject; public WeakReference aWeakRefToGcRoot = new WeakReference(Main.class); - public SoftReference aWeakChain = new SoftReference(new Reference(new Reference(new Object()))); + public SoftReference aSoftChain = new SoftReference(new Reference(new Reference(new Object()))); public Object[] basicStringRef; public AddedObject addedObject; public UnchangedObject unchangedObject = new UnchangedObject(); @@ -157,4 +158,15 @@ public class DumpedStuff extends SuperDumpedStuff { public int[] modifiedArray; public Object objectAllocatedAtKnownSite; public Object objectAllocatedAtKnownSubSite; + + // Allocate those objects that we need to not be GC'd before taking the heap + // dump. + public void shouldNotGc() { + reachabilityReferenceChain = new Reference( + new SoftReference( + new Reference( + new WeakReference( + new SoftReference( + new PhantomReference(new Object(), referenceQueue)))))); + } } diff --git a/tools/ahat/src/test-dump/Main.java b/tools/ahat/src/test-dump/Main.java index de3674846b..ca18fd8cec 100644 --- a/tools/ahat/src/test-dump/Main.java +++ b/tools/ahat/src/test-dump/Main.java @@ -49,6 +49,8 @@ public class Main { stuff.basicStringRef = new Object[]{stuff.basicString}; } + stuff.shouldNotGc(); + // Take a heap dump that will include that instance of DumpedStuff. System.err.println("Dumping hprof data to " + file); VMDebug.dumpHprofData(file); diff --git a/tools/ahat/src/test/com/android/ahat/InstanceTest.java b/tools/ahat/src/test/com/android/ahat/InstanceTest.java index 65a3fb8777..f886e9df5f 100644 --- a/tools/ahat/src/test/com/android/ahat/InstanceTest.java +++ b/tools/ahat/src/test/com/android/ahat/InstanceTest.java @@ -21,6 +21,7 @@ import com.android.ahat.heapdump.AhatHeap; import com.android.ahat.heapdump.AhatInstance; import com.android.ahat.heapdump.AhatSnapshot; import com.android.ahat.heapdump.PathElement; +import com.android.ahat.heapdump.Reachability; import com.android.ahat.heapdump.Size; import com.android.ahat.heapdump.Value; import java.io.IOException; @@ -216,10 +217,31 @@ public class InstanceTest { AhatInstance ref = dump.getDumpedAhatInstance("aSoftReference"); AhatInstance referent = ref.getReferent(); assertNotNull(referent); + assertEquals(Reachability.SOFT, referent.getReachability()); assertTrue(referent.isWeaklyReachable()); } @Test + public void reachability() throws IOException { + TestDump dump = TestDump.getTestDump(); + AhatInstance strong1 = dump.getDumpedAhatInstance("reachabilityReferenceChain"); + AhatInstance soft1 = strong1.getField("referent").asAhatInstance(); + AhatInstance strong2 = soft1.getField("referent").asAhatInstance(); + AhatInstance weak1 = strong2.getField("referent").asAhatInstance(); + AhatInstance soft2 = weak1.getField("referent").asAhatInstance(); + AhatInstance phantom1 = soft2.getField("referent").asAhatInstance(); + AhatInstance obj = phantom1.getField("referent").asAhatInstance(); + + assertEquals(Reachability.STRONG, strong1.getReachability()); + assertEquals(Reachability.STRONG, soft1.getReachability()); + assertEquals(Reachability.SOFT, strong2.getReachability()); + assertEquals(Reachability.SOFT, weak1.getReachability()); + assertEquals(Reachability.WEAK, soft2.getReachability()); + assertEquals(Reachability.WEAK, phantom1.getReachability()); + assertEquals(Reachability.PHANTOM, obj.getReachability()); + } + + @Test public void gcRootPath() throws IOException { TestDump dump = TestDump.getTestDump(); @@ -388,24 +410,31 @@ public class InstanceTest { // We had a bug in the past where weak references to GC roots caused the // roots to be incorrectly be considered weakly reachable. + assertEquals(Reachability.STRONG, root.getReachability()); assertTrue(root.isStronglyReachable()); assertFalse(root.isWeaklyReachable()); } @Test - public void weakReferenceChain() throws IOException { + public void softReferenceChain() throws IOException { // If the only reference to a chain of strongly referenced objects is a - // weak reference, then all of the objects should be considered weakly + // soft reference, then all of the objects should be considered softly // reachable. TestDump dump = TestDump.getTestDump(); - AhatInstance ref = dump.getDumpedAhatInstance("aWeakChain"); - AhatInstance weak1 = ref.getField("referent").asAhatInstance(); - AhatInstance weak2 = weak1.getField("referent").asAhatInstance(); - AhatInstance weak3 = weak2.getField("referent").asAhatInstance(); + AhatInstance ref = dump.getDumpedAhatInstance("aSoftChain"); + AhatInstance soft1 = ref.getField("referent").asAhatInstance(); + AhatInstance soft2 = soft1.getField("referent").asAhatInstance(); + AhatInstance soft3 = soft2.getField("referent").asAhatInstance(); assertTrue(ref.isStronglyReachable()); - assertTrue(weak1.isWeaklyReachable()); - assertTrue(weak2.isWeaklyReachable()); - assertTrue(weak3.isWeaklyReachable()); + assertEquals(Reachability.SOFT, soft1.getReachability()); + assertEquals(Reachability.SOFT, soft2.getReachability()); + assertEquals(Reachability.SOFT, soft3.getReachability()); + + // Test the deprecated isWeaklyReachable API, which interprets weak as any + // kind of phantom/finalizer/weak/soft reference. + assertTrue(soft1.isWeaklyReachable()); + assertTrue(soft2.isWeaklyReachable()); + assertTrue(soft3.isWeaklyReachable()); } @Test @@ -414,6 +443,8 @@ public class InstanceTest { AhatInstance obj = dump.getDumpedAhatInstance("anObject"); AhatInstance ref = dump.getDumpedAhatInstance("aReference"); AhatInstance weak = dump.getDumpedAhatInstance("aWeakReference"); + assertTrue(obj.getReverseReferences().contains(ref)); + assertTrue(obj.getReverseReferences().contains(weak)); assertTrue(obj.getHardReverseReferences().contains(ref)); assertFalse(obj.getHardReverseReferences().contains(weak)); assertFalse(obj.getSoftReverseReferences().contains(ref)); diff --git a/tools/dexanalyze/dexanalyze_experiments.cc b/tools/dexanalyze/dexanalyze_experiments.cc index d4e3f1f597..c5f7e8ebb5 100644 --- a/tools/dexanalyze/dexanalyze_experiments.cc +++ b/tools/dexanalyze/dexanalyze_experiments.cc @@ -321,15 +321,73 @@ void CountDexIndices::ProcessDexFile(const DexFile& dex_file) { // Types accessed and count. std::map<size_t, size_t> types_accessed; - // Map from dex field index -> class field index. - std::map<uint32_t, uint32_t> field_index_map_; + // Maps from dex field index -> class field index (static or instance). + std::map<uint32_t, uint32_t> static_field_index_map_; size_t current_idx = 0u; + for (const ClassAccessor::Field& field : accessor.GetStaticFields()) { + static_field_index_map_[field.GetIndex()] = current_idx++; + } + std::map<uint32_t, uint32_t> instance_field_index_map_; + current_idx = 0u; for (const ClassAccessor::Field& field : accessor.GetInstanceFields()) { - field_index_map_[field.GetIndex()] = current_idx++; + instance_field_index_map_[field.GetIndex()] = current_idx++; } + auto ProcessFieldIndex = [&](uint32_t dex_field_idx, + uint32_t inout, + const std::map<uint32_t, uint32_t>& index_map, + /*inout*/ FieldAccessStats* stats) { + auto it = index_map.find(dex_field_idx); + if (it != index_map.end()) { + if (it->second < FieldAccessStats::kMaxFieldIndex) { + ++stats->field_index_[it->second]; + } else { + ++stats->field_index_other_; + } + } else { + ++stats->field_index_other_class_; + } + if (it != index_map.end() && + it->second < FieldAccessStats::kShortBytecodeFieldIndexOutCutOff && + inout < FieldAccessStats::kShortBytecodeInOutCutOff) { + ++stats->short_bytecode_; + } + }; + auto ProcessInstanceField = [&](const Instruction& inst, + uint32_t first_arg_reg, + const std::map<uint32_t, uint32_t>& index_map, + /*inout*/ InstanceFieldAccessStats* stats) { + const uint32_t dex_field_idx = inst.VRegC_22c(); + ++types_accessed[dex_file.GetFieldId(dex_field_idx).class_idx_.index_]; + uint32_t input = inst.VRegA_22c(); + ++stats->inout_[input]; + const uint32_t receiver = inst.VRegB_22c(); + // FIXME: This is weird if receiver < first_arg_reg. + ++stats->receiver_[(receiver - first_arg_reg) & 0xF]; + if (first_arg_reg == receiver) { + ProcessFieldIndex(dex_field_idx, input, index_map, stats); + } + }; + auto ProcessStaticField = [&](const Instruction& inst, + const std::map<uint32_t, uint32_t>& index_map, + /*inout*/ StaticFieldAccessStats* stats) { + const uint32_t dex_field_idx = inst.VRegB_21c(); + ++types_accessed[dex_file.GetFieldId(dex_field_idx).class_idx_.index_]; + uint8_t output = inst.VRegA_21c(); + if (output < 16u) { + ++stats->inout_[output]; + } else { + ++stats->inout_other_; + } + ProcessFieldIndex(dex_field_idx, output, index_map, stats); + }; for (const ClassAccessor::Method& method : accessor.GetMethods()) { CodeItemDataAccessor code_item(dex_file, method.GetCodeItem()); + const uint32_t first_arg_reg = + ((method.GetAccessFlags() & kAccStatic) == 0) + ? code_item.RegistersSize() - code_item.InsSize() + : static_cast<uint32_t>(-1); + dex_code_bytes_ += code_item.InsnsSizeInBytes(); unique_code_items.insert(method.GetCodeItemOffset()); for (const DexInstructionPcPair& inst : code_item) { @@ -346,7 +404,11 @@ void CountDexIndices::ProcessDexFile(const DexFile& dex_file) { case Instruction::IGET_BOOLEAN: case Instruction::IGET_BYTE: case Instruction::IGET_CHAR: - case Instruction::IGET_SHORT: + case Instruction::IGET_SHORT: { + ProcessInstanceField( + inst.Inst(), first_arg_reg, instance_field_index_map_, &iget_stats_); + break; + } case Instruction::IPUT: case Instruction::IPUT_WIDE: case Instruction::IPUT_OBJECT: @@ -354,20 +416,28 @@ void CountDexIndices::ProcessDexFile(const DexFile& dex_file) { case Instruction::IPUT_BYTE: case Instruction::IPUT_CHAR: case Instruction::IPUT_SHORT: { - const uint32_t receiver = inst->VRegB_22c(); - const uint32_t dex_field_idx = inst->VRegC_22c(); - const uint32_t first_arg_reg = code_item.RegistersSize() - code_item.InsSize(); - ++field_receiver_[(receiver - first_arg_reg) & 0xF]; - ++types_accessed[dex_file.GetFieldId(dex_field_idx).class_idx_.index_]; - if (first_arg_reg == receiver) { - auto it = field_index_map_.find(dex_field_idx); - if (it != field_index_map_.end() && it->second < kMaxFieldIndex) { - ++field_index_[it->second]; - } else { - ++field_index_other_; - } - } - ++field_output_[inst->VRegA_22c()]; + ProcessInstanceField( + inst.Inst(), first_arg_reg, instance_field_index_map_, &iput_stats_); + break; + } + case Instruction::SGET: + case Instruction::SGET_WIDE: + case Instruction::SGET_OBJECT: + case Instruction::SGET_BOOLEAN: + case Instruction::SGET_BYTE: + case Instruction::SGET_CHAR: + case Instruction::SGET_SHORT: { + ProcessStaticField(inst.Inst(), static_field_index_map_, &sget_stats_); + break; + } + case Instruction::SPUT: + case Instruction::SPUT_WIDE: + case Instruction::SPUT_OBJECT: + case Instruction::SPUT_BOOLEAN: + case Instruction::SPUT_BYTE: + case Instruction::SPUT_CHAR: + case Instruction::SPUT_SHORT: { + ProcessStaticField(inst.Inst(), static_field_index_map_, &sput_stats_); break; } case Instruction::CONST_STRING_JUMBO: { @@ -479,22 +549,53 @@ void CountDexIndices::ProcessDexFile(const DexFile& dex_file) { } void CountDexIndices::Dump(std::ostream& os, uint64_t total_size) const { - const uint64_t fields_total = std::accumulate(field_receiver_, field_receiver_ + 16u, 0u); - for (size_t i = 0; i < 16; ++i) { - os << "receiver_reg=" << i << ": " << Percent(field_receiver_[i], fields_total) << "\n"; - } - for (size_t i = 0; i < 16; ++i) { - os << "output_reg=" << i << ": " << Percent(field_output_[i], fields_total) << "\n"; - } - const uint64_t fields_idx_total = std::accumulate(field_index_, - field_index_ + kMaxFieldIndex, - 0u) + field_index_other_; - for (size_t i = 0; i < kMaxFieldIndex; ++i) { - os << "field_idx=" << i << ": " << Percent(field_index_[i], fields_idx_total) << "\n"; - } - os << "field_idx=other: " << Percent(field_index_other_, fields_idx_total) << "\n"; - os << "field_idx_savings=" << Percent((fields_idx_total - field_index_other_) * 2, total_size) - << "\n"; + auto DumpFieldIndexes = [&](const FieldAccessStats& stats) { + const uint64_t fields_idx_total = std::accumulate( + stats.field_index_, + stats.field_index_ + FieldAccessStats::kMaxFieldIndex, + stats.field_index_other_ + stats.field_index_other_class_); + for (size_t i = 0; i < FieldAccessStats::kMaxFieldIndex; ++i) { + os << " field_idx=" << i << ": " << Percent(stats.field_index_[i], fields_idx_total) << "\n"; + } + os << " field_idx=other: " << Percent(stats.field_index_other_, fields_idx_total) << "\n"; + os << " field_idx=other_class: " << Percent(stats.field_index_other_class_, fields_idx_total) + << "\n"; + }; + auto DumpInstanceFieldStats = [&](const char* tag, const InstanceFieldAccessStats& stats) { + const uint64_t fields_total = std::accumulate(stats.inout_, stats.inout_ + 16u, 0u); + os << tag << "\n"; + for (size_t i = 0; i < 16; ++i) { + os << " receiver_reg=" << i << ": " << Percent(stats.receiver_[i], fields_total) << "\n"; + } + DCHECK(tag[1] == 'G' || tag[1] == 'P'); + const char* inout_tag = (tag[1] == 'G') ? "output_reg" : "input_reg"; + for (size_t i = 0; i < 16; ++i) { + os << " " << inout_tag << "=" << i << ": " << Percent(stats.inout_[i], fields_total) << "\n"; + } + DumpFieldIndexes(stats); + os << " short_bytecode: " << Percent(stats.short_bytecode_, fields_total) << "\n"; + os << " short_bytecode_savings=" << Percent(stats.short_bytecode_ * 2, total_size) << "\n"; + }; + DumpInstanceFieldStats("IGET", iget_stats_); + DumpInstanceFieldStats("IPUT", iput_stats_); + + auto DumpStaticFieldStats = [&](const char* tag, const StaticFieldAccessStats& stats) { + const uint64_t fields_total = + std::accumulate(stats.inout_, stats.inout_ + 16u, stats.inout_other_); + os << tag << "\n"; + DCHECK(tag[1] == 'G' || tag[1] == 'P'); + const char* inout_tag = (tag[1] == 'G') ? "output_reg" : "input_reg"; + for (size_t i = 0; i < 16; ++i) { + os << " " << inout_tag << "=" << i << ": " << Percent(stats.inout_[i], fields_total) << "\n"; + } + os << " " << inout_tag << "=other: " << Percent(stats.inout_other_, fields_total) << "\n"; + DumpFieldIndexes(stats); + os << " short_bytecode: " << Percent(stats.short_bytecode_, fields_total) << "\n"; + os << " short_bytecode_savings=" << Percent(stats.short_bytecode_ * 2, total_size) << "\n"; + }; + DumpStaticFieldStats("SGET", sget_stats_); + DumpStaticFieldStats("SPUT", sput_stats_); + os << "Num string ids: " << num_string_ids_ << "\n"; os << "Num method ids: " << num_method_ids_ << "\n"; os << "Num field ids: " << num_field_ids_ << "\n"; diff --git a/tools/dexanalyze/dexanalyze_experiments.h b/tools/dexanalyze/dexanalyze_experiments.h index 0cafe27f27..0e147ddb76 100644 --- a/tools/dexanalyze/dexanalyze_experiments.h +++ b/tools/dexanalyze/dexanalyze_experiments.h @@ -98,11 +98,29 @@ class CountDexIndices : public Experiment { size_t total_unique_string_ids_ = 0; uint64_t total_unique_code_items_ = 0u; - static constexpr size_t kMaxFieldIndex = 32; - uint64_t field_index_[kMaxFieldIndex] = {}; - uint64_t field_index_other_ = 0u; - uint64_t field_receiver_[16] = {}; - uint64_t field_output_[16] = {}; + struct FieldAccessStats { + static constexpr size_t kMaxFieldIndex = 32; + uint64_t field_index_[kMaxFieldIndex] = {}; + uint64_t field_index_other_ = 0u; + uint64_t field_index_other_class_ = 0u; // Includes superclass fields referenced with + // type index pointing to this class. + + static constexpr size_t kShortBytecodeFieldIndexOutCutOff = 16u; + static constexpr size_t kShortBytecodeInOutCutOff = 16u; + uint64_t short_bytecode_ = 0u; + + uint64_t inout_[16] = {}; // Input for IPUT/SPUT, output for IGET/SGET. + }; + struct InstanceFieldAccessStats : FieldAccessStats { + uint64_t receiver_[16] = {}; + }; + struct StaticFieldAccessStats : FieldAccessStats { + uint64_t inout_other_ = 0u; // Input for SPUT, output for SGET. + }; + InstanceFieldAccessStats iget_stats_; + InstanceFieldAccessStats iput_stats_; + StaticFieldAccessStats sget_stats_; + StaticFieldAccessStats sput_stats_; // Unique names. uint64_t total_unique_method_names_ = 0u; |