summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/common_compiler_test.cc56
-rw-r--r--compiler/common_compiler_test.h27
-rw-r--r--compiler/debug/dwarf/dwarf_test.h4
-rw-r--r--compiler/dex/dex_to_dex_compiler.cc3
-rw-r--r--compiler/driver/compiled_method_storage_test.cc2
-rw-r--r--compiler/driver/compiler_driver.cc28
-rw-r--r--compiler/driver/compiler_driver.h13
-rw-r--r--compiler/driver/compiler_options.cc6
-rw-r--r--compiler/driver/compiler_options.h25
-rw-r--r--compiler/exception_test.cc9
-rw-r--r--compiler/jit/jit_compiler.cc40
-rw-r--r--compiler/jit/jit_compiler.h16
-rw-r--r--compiler/jni/quick/jni_compiler.cc17
-rw-r--r--compiler/jni/quick/jni_compiler.h4
-rw-r--r--compiler/optimizing/code_generator.cc36
-rw-r--r--compiler/optimizing/code_generator.h2
-rw-r--r--compiler/optimizing/code_generator_arm64.cc74
-rw-r--r--compiler/optimizing/code_generator_arm64.h6
-rw-r--r--compiler/optimizing/code_generator_arm_vixl.cc6
-rw-r--r--compiler/optimizing/code_generator_arm_vixl.h7
-rw-r--r--compiler/optimizing/code_generator_mips.cc9
-rw-r--r--compiler/optimizing/code_generator_mips.h6
-rw-r--r--compiler/optimizing/code_generator_mips64.cc9
-rw-r--r--compiler/optimizing/code_generator_mips64.h6
-rw-r--r--compiler/optimizing/code_generator_vector_arm64.cc12
-rw-r--r--compiler/optimizing/code_generator_x86.cc6
-rw-r--r--compiler/optimizing/code_generator_x86.h8
-rw-r--r--compiler/optimizing/code_generator_x86_64.cc6
-rw-r--r--compiler/optimizing/code_generator_x86_64.h8
-rw-r--r--compiler/optimizing/codegen_test.cc41
-rw-r--r--compiler/optimizing/codegen_test_utils.h56
-rw-r--r--compiler/optimizing/common_arm64.h14
-rw-r--r--compiler/optimizing/constant_folding_test.cc5
-rw-r--r--compiler/optimizing/dead_code_elimination_test.cc5
-rw-r--r--compiler/optimizing/emit_swap_mips_test.cc16
-rw-r--r--compiler/optimizing/inliner.cc6
-rw-r--r--compiler/optimizing/linearize_test.cc8
-rw-r--r--compiler/optimizing/live_ranges_test.cc38
-rw-r--r--compiler/optimizing/liveness_test.cc8
-rw-r--r--compiler/optimizing/loop_analysis.h4
-rw-r--r--compiler/optimizing/loop_optimization.cc24
-rw-r--r--compiler/optimizing/loop_optimization.h8
-rw-r--r--compiler/optimizing/loop_optimization_test.cc3
-rw-r--r--compiler/optimizing/nodes.h8
-rw-r--r--compiler/optimizing/optimization.cc5
-rw-r--r--compiler/optimizing/optimizing_cfi_test.cc16
-rw-r--r--compiler/optimizing/optimizing_compiler.cc41
-rw-r--r--compiler/optimizing/register_allocator_test.cc70
-rw-r--r--compiler/optimizing/scheduler_test.cc2
-rw-r--r--compiler/optimizing/ssa_liveness_analysis_test.cc20
-rw-r--r--compiler/optimizing/stack_map_stream.cc73
-rw-r--r--compiler/optimizing/stack_map_stream.h24
-rw-r--r--compiler/optimizing/stack_map_test.cc60
-rw-r--r--dex2oat/dex2oat.cc73
-rw-r--r--dex2oat/linker/arm/relative_patcher_thumb2_test.cc5
-rw-r--r--dex2oat/linker/arm64/relative_patcher_arm64_test.cc5
-rw-r--r--dex2oat/linker/elf_writer_quick.cc45
-rw-r--r--dex2oat/linker/elf_writer_quick.h4
-rw-r--r--dex2oat/linker/image_test.h19
-rw-r--r--dex2oat/linker/image_writer.cc22
-rw-r--r--dex2oat/linker/image_writer.h11
-rw-r--r--dex2oat/linker/oat_writer.cc56
-rw-r--r--dex2oat/linker/oat_writer.h19
-rw-r--r--dex2oat/linker/oat_writer_test.cc61
-rw-r--r--dex2oat/linker/relative_patcher_test.h52
-rw-r--r--libartbase/base/bit_memory_region.h41
-rw-r--r--libartbase/base/bit_table.h4
-rw-r--r--libartbase/base/bit_table_test.cc12
-rw-r--r--oatdump/oatdump.cc33
-rw-r--r--runtime/art_method.cc2
-rw-r--r--runtime/class_linker.cc4
-rw-r--r--runtime/gc/space/image_space.cc8
-rw-r--r--runtime/oat.h4
-rw-r--r--runtime/oat_file.cc57
-rw-r--r--runtime/oat_file.h2
-rw-r--r--runtime/oat_file_assistant.cc6
-rw-r--r--runtime/runtime.cc2
-rw-r--r--runtime/stack_map.cc23
-rw-r--r--runtime/stack_map.h26
-rw-r--r--test/117-nopatchoat/nopatchoat.cc6
-rw-r--r--test/411-checker-hdiv-hrem-pow2/expected.txt0
-rw-r--r--test/411-checker-hdiv-hrem-pow2/info.txt2
-rw-r--r--test/411-checker-hdiv-hrem-pow2/src/DivTest.java251
-rw-r--r--test/411-checker-hdiv-hrem-pow2/src/Main.java22
-rw-r--r--test/411-checker-hdiv-hrem-pow2/src/RemTest.java257
-rw-r--r--test/530-checker-peel-unroll/src/Main.java108
-rw-r--r--test/910-methods/check27
-rw-r--r--test/910-methods/expected.txt2
-rw-r--r--test/910-methods/expected_d8.diff4
-rw-r--r--test/913-heaps/check22
-rw-r--r--test/913-heaps/expected.txt39
-rw-r--r--test/913-heaps/expected_d8.diff70
-rw-r--r--test/common/runtime_state.cc4
-rw-r--r--test/knownfailures.json8
-rw-r--r--tools/ahat/etc/ahat_api.txt19
-rw-r--r--tools/ahat/src/main/com/android/ahat/ObjectHandler.java21
-rw-r--r--tools/ahat/src/main/com/android/ahat/Summarizer.java10
-rw-r--r--tools/ahat/src/main/com/android/ahat/heapdump/AhatArrayInstance.java7
-rw-r--r--tools/ahat/src/main/com/android/ahat/heapdump/AhatClassInstance.java70
-rw-r--r--tools/ahat/src/main/com/android/ahat/heapdump/AhatClassObj.java5
-rw-r--r--tools/ahat/src/main/com/android/ahat/heapdump/AhatInstance.java158
-rw-r--r--tools/ahat/src/main/com/android/ahat/heapdump/AhatSnapshot.java2
-rw-r--r--tools/ahat/src/main/com/android/ahat/heapdump/DominatorReferenceIterator.java2
-rw-r--r--tools/ahat/src/main/com/android/ahat/heapdump/Reachability.java70
-rw-r--r--tools/ahat/src/main/com/android/ahat/heapdump/Reference.java9
-rw-r--r--tools/ahat/src/main/com/android/ahat/heapdump/SuperRoot.java2
-rw-r--r--tools/ahat/src/test-dump/DumpedStuff.java14
-rw-r--r--tools/ahat/src/test-dump/Main.java2
-rw-r--r--tools/ahat/src/test/com/android/ahat/InstanceTest.java49
-rw-r--r--tools/dexanalyze/dexanalyze_experiments.cc169
-rw-r--r--tools/dexanalyze/dexanalyze_experiments.h28
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;