Merge "Add JVMTI DDMS extension method and event."
diff --git a/Android.mk b/Android.mk
index 7081f7b..174cde3 100644
--- a/Android.mk
+++ b/Android.mk
@@ -484,7 +484,7 @@
########################################################################
# Phony target for building what go/lem requires for syncing /system to target.
.PHONY: build-art-unbundled-golem
-build-art-unbundled-golem: art-runtime linker oatdump $(TARGET_CORE_JARS)
+build-art-unbundled-golem: art-runtime linker oatdump $(TARGET_CORE_JARS) crash_dump
########################################################################
# Rules for building all dependencies for tests.
diff --git a/build/Android.common_test.mk b/build/Android.common_test.mk
index 37e6d42..0f29f29 100644
--- a/build/Android.common_test.mk
+++ b/build/Android.common_test.mk
@@ -33,13 +33,6 @@
# rule name such as test-art-host-oat-optimizing-HelloWorld64.
ART_TEST_KNOWN_BROKEN :=
-# List of run-tests to skip running in any configuration. This needs to be the full name of the
-# run-test such as '457-regs'.
-ART_TEST_RUN_TEST_SKIP ?=
-
-# Failing valgrind tests.
-# Note: *all* 64b tests involving the runtime do not work currently. b/15170219.
-
# List of known failing tests that when executed won't cause test execution to not finish.
# The test name must be the full rule name such as test-art-host-oat-optimizing-HelloWorld64.
ART_TEST_KNOWN_FAILING :=
@@ -47,85 +40,9 @@
# Keep going after encountering a test failure?
ART_TEST_KEEP_GOING ?= true
-# Do you want all tests, even those that are time consuming?
-ART_TEST_FULL ?= false
-
# Do you want run-test to be quieter? run-tests will only show output if they fail.
ART_TEST_QUIET ?= true
-# Do you want interpreter tests run?
-ART_TEST_INTERPRETER ?= true
-ART_TEST_INTERPRETER_ACCESS_CHECKS ?= true
-
-# Do you want JIT tests run?
-ART_TEST_JIT ?= true
-
-# Do you want optimizing compiler tests run?
-ART_TEST_OPTIMIZING ?= true
-
-# Do you want to test the optimizing compiler with graph coloring register allocation?
-ART_TEST_OPTIMIZING_GRAPH_COLOR ?= $(ART_TEST_FULL)
-
-# Do you want to do run-tests with profiles?
-ART_TEST_SPEED_PROFILE ?= $(ART_TEST_FULL)
-
-# Do we want to test PIC-compiled tests ("apps")?
-ART_TEST_PIC_TEST ?= $(ART_TEST_FULL)
-
-# Do you want tracing tests run?
-ART_TEST_TRACE ?= $(ART_TEST_FULL)
-
-# Do you want tracing tests (streaming mode) run?
-ART_TEST_TRACE_STREAM ?= $(ART_TEST_FULL)
-
-# Do you want tests with GC verification enabled run?
-ART_TEST_GC_VERIFY ?= $(ART_TEST_FULL)
-
-# Do you want tests with the GC stress mode enabled run?
-ART_TEST_GC_STRESS ?= $(ART_TEST_FULL)
-
-# Do you want tests with the JNI forcecopy mode enabled run?
-ART_TEST_JNI_FORCECOPY ?= $(ART_TEST_FULL)
-
-# Do you want run-tests with relocation enabled run?
-ART_TEST_RUN_TEST_RELOCATE ?= $(ART_TEST_FULL)
-
-# Do you want run-tests with prebuilding?
-ART_TEST_RUN_TEST_PREBUILD ?= true
-
-# Do you want run-tests with no prebuilding enabled run?
-ART_TEST_RUN_TEST_NO_PREBUILD ?= $(ART_TEST_FULL)
-
-# Do you want run-tests with a pregenerated core.art?
-ART_TEST_RUN_TEST_IMAGE ?= true
-
-# Do you want run-tests without a pregenerated core.art?
-ART_TEST_RUN_TEST_NO_IMAGE ?= $(ART_TEST_FULL)
-
-# Do you want run-tests with relocation enabled but patchoat failing?
-ART_TEST_RUN_TEST_RELOCATE_NO_PATCHOAT ?= $(ART_TEST_FULL)
-
-# Do you want run-tests without a dex2oat?
-ART_TEST_RUN_TEST_NO_DEX2OAT ?= $(ART_TEST_FULL)
-
-# Do you want run-tests with libartd.so?
-ART_TEST_RUN_TEST_DEBUG ?= true
-
-# Do you want run-tests with libart.so?
-ART_TEST_RUN_TEST_NDEBUG ?= $(ART_TEST_FULL)
-
-# Do you want run-tests with the host/target's second arch?
-ART_TEST_RUN_TEST_2ND_ARCH ?= true
-
-# Do you want failed tests to have their artifacts cleaned up?
-ART_TEST_RUN_TEST_ALWAYS_CLEAN ?= true
-
-# Do you want run-tests with the --debuggable flag
-ART_TEST_RUN_TEST_DEBUGGABLE ?= $(ART_TEST_FULL)
-
-# Do you want to test multi-part boot-image functionality?
-ART_TEST_RUN_TEST_MULTI_IMAGE ?= $(ART_TEST_FULL)
-
# Define the command run on test failure. $(1) is the name of the test. Executed by the shell.
# If the test was a top-level make target (e.g. `test-art-host-gtest-codegen_test64`), the command
# fails with exit status 1 (returned by the last `grep` statement below).
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index 7769aad..42d0ba5 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -146,13 +146,13 @@
$(HOST_CORE_IMAGE_optimizing_32) \
$(HOST_CORE_IMAGE_interpreter_64) \
$(HOST_CORE_IMAGE_interpreter_32) \
- $(HOST_OUT_EXECUTABLES)/patchoatd
+ patchoatd-host
ART_GTEST_dex2oat_environment_tests_TARGET_DEPS := \
$(TARGET_CORE_IMAGE_optimizing_64) \
$(TARGET_CORE_IMAGE_optimizing_32) \
$(TARGET_CORE_IMAGE_interpreter_64) \
$(TARGET_CORE_IMAGE_interpreter_32) \
- $(TARGET_OUT_EXECUTABLES)/patchoatd
+ patchoatd-target
ART_GTEST_oat_file_assistant_test_HOST_DEPS := \
$(ART_GTEST_dex2oat_environment_tests_HOST_DEPS)
@@ -161,10 +161,10 @@
ART_GTEST_dexoptanalyzer_test_HOST_DEPS := \
$(ART_GTEST_dex2oat_environment_tests_HOST_DEPS) \
- $(HOST_OUT_EXECUTABLES)/dexoptanalyzerd
+ dexoptanalyzerd-host
ART_GTEST_dexoptanalyzer_test_TARGET_DEPS := \
$(ART_GTEST_dex2oat_environment_tests_TARGET_DEPS) \
- dexoptanalyzerd
+ dexoptanalyzerd-target
ART_GTEST_image_space_test_HOST_DEPS := \
$(ART_GTEST_dex2oat_environment_tests_HOST_DEPS)
@@ -172,57 +172,59 @@
$(ART_GTEST_dex2oat_environment_tests_TARGET_DEPS)
ART_GTEST_dex2oat_test_HOST_DEPS := \
- $(ART_GTEST_dex2oat_environment_tests_HOST_DEPS)
+ $(ART_GTEST_dex2oat_environment_tests_HOST_DEPS) \
+ dex2oatd-host
ART_GTEST_dex2oat_test_TARGET_DEPS := \
- $(ART_GTEST_dex2oat_environment_tests_TARGET_DEPS)
+ $(ART_GTEST_dex2oat_environment_tests_TARGET_DEPS) \
+ dex2oatd-target
ART_GTEST_dex2oat_image_test_HOST_DEPS := \
- $(ART_GTEST_dex2oat_environment_tests_HOST_DEPS)
+ $(ART_GTEST_dex2oat_environment_tests_HOST_DEPS) \
+ dex2oatd-host
ART_GTEST_dex2oat_image_test_TARGET_DEPS := \
- $(ART_GTEST_dex2oat_environment_tests_TARGET_DEPS)
+ $(ART_GTEST_dex2oat_environment_tests_TARGET_DEPS) \
+ dex2oatd-target
# TODO: document why this is needed.
ART_GTEST_proxy_test_HOST_DEPS := $(HOST_CORE_IMAGE_DEFAULT_64) $(HOST_CORE_IMAGE_DEFAULT_32)
# The dexdiag test requires the dexdiag utility.
-ART_GTEST_dexdiag_test_HOST_DEPS := \
- $(HOST_OUT_EXECUTABLES)/dexdiag
-ART_GTEST_dexdiag_test_TARGET_DEPS := \
- dexdiag
+ART_GTEST_dexdiag_test_HOST_DEPS := dexdiag-host
+ART_GTEST_dexdiag_test_TARGET_DEPS := dexdiag-target
# The dexdump test requires an image and the dexdump utility.
# TODO: rename into dexdump when migration completes
ART_GTEST_dexdump_test_HOST_DEPS := \
$(HOST_CORE_IMAGE_DEFAULT_64) \
$(HOST_CORE_IMAGE_DEFAULT_32) \
- $(HOST_OUT_EXECUTABLES)/dexdump2
+ dexdump2-host
ART_GTEST_dexdump_test_TARGET_DEPS := \
$(TARGET_CORE_IMAGE_DEFAULT_64) \
$(TARGET_CORE_IMAGE_DEFAULT_32) \
- dexdump2
+ dexdump2-target
# The dexlayout test requires an image and the dexlayout utility.
# TODO: rename into dexdump when migration completes
ART_GTEST_dexlayout_test_HOST_DEPS := \
$(HOST_CORE_IMAGE_DEFAULT_64) \
$(HOST_CORE_IMAGE_DEFAULT_32) \
- $(HOST_OUT_EXECUTABLES)/dexlayout \
- $(HOST_OUT_EXECUTABLES)/dexdump2
+ dexlayoutd-host \
+ dexdump2-host
ART_GTEST_dexlayout_test_TARGET_DEPS := \
$(TARGET_CORE_IMAGE_DEFAULT_64) \
$(TARGET_CORE_IMAGE_DEFAULT_32) \
- dexlayout \
- dexdump2
+ dexlayoutd-target \
+ dexdump2-target
# The dexlist test requires an image and the dexlist utility.
ART_GTEST_dexlist_test_HOST_DEPS := \
$(HOST_CORE_IMAGE_DEFAULT_64) \
$(HOST_CORE_IMAGE_DEFAULT_32) \
- $(HOST_OUT_EXECUTABLES)/dexlist
+ dexlist-host
ART_GTEST_dexlist_test_TARGET_DEPS := \
$(TARGET_CORE_IMAGE_DEFAULT_64) \
$(TARGET_CORE_IMAGE_DEFAULT_32) \
- dexlist
+ dexlist-target
# The imgdiag test has dependencies on core.oat since it needs to load it during the test.
# For the host, also add the installed tool (in the base size, that should suffice). For the
@@ -230,30 +232,28 @@
ART_GTEST_imgdiag_test_HOST_DEPS := \
$(HOST_CORE_IMAGE_DEFAULT_64) \
$(HOST_CORE_IMAGE_DEFAULT_32) \
- $(HOST_OUT_EXECUTABLES)/imgdiagd
+ imgdiagd-host
ART_GTEST_imgdiag_test_TARGET_DEPS := \
$(TARGET_CORE_IMAGE_DEFAULT_64) \
$(TARGET_CORE_IMAGE_DEFAULT_32) \
- imgdiagd
+ imgdiagd-target
# Oatdump test requires an image and oatfile to dump.
ART_GTEST_oatdump_test_HOST_DEPS := \
$(HOST_CORE_IMAGE_DEFAULT_64) \
$(HOST_CORE_IMAGE_DEFAULT_32) \
- $(HOST_OUT_EXECUTABLES)/oatdumpd \
- $(HOST_OUT_EXECUTABLES)/oatdumpds
+ oatdumpd-host \
+ oatdumpds-host
ART_GTEST_oatdump_test_TARGET_DEPS := \
$(TARGET_CORE_IMAGE_DEFAULT_64) \
$(TARGET_CORE_IMAGE_DEFAULT_32) \
- oatdump
+ oatdumpd-target
ART_GTEST_oatdump_image_test_HOST_DEPS := $(ART_GTEST_oatdump_test_HOST_DEPS)
ART_GTEST_oatdump_image_test_TARGET_DEPS := $(ART_GTEST_oatdump_test_TARGET_DEPS)
# Profile assistant tests requires profman utility.
-ART_GTEST_profile_assistant_test_HOST_DEPS := \
- $(HOST_OUT_EXECUTABLES)/profmand
-ART_GTEST_profile_assistant_test_TARGET_DEPS := \
- profman
+ART_GTEST_profile_assistant_test_HOST_DEPS := profmand-host
+ART_GTEST_profile_assistant_test_TARGET_DEPS := profmand-target
# The path for which all the source files are relative, not actually the current directory.
LOCAL_PATH := art
diff --git a/build/art.go b/build/art.go
index 4e48d2d..5704b43 100644
--- a/build/art.go
+++ b/build/art.go
@@ -46,10 +46,6 @@
cflags = append(cflags, "-DART_USE_TLAB=1")
}
- if !envFalse(ctx, "ART_ENABLE_VDEX") {
- cflags = append(cflags, "-DART_ENABLE_VDEX")
- }
-
imtSize := envDefault(ctx, "ART_IMT_SIZE", "43")
cflags = append(cflags, "-DIMT_SIZE="+imtSize)
diff --git a/compiler/dex/dex_to_dex_decompiler_test.cc b/compiler/dex/dex_to_dex_decompiler_test.cc
index 6637be2..979c4c4 100644
--- a/compiler/dex/dex_to_dex_decompiler_test.cc
+++ b/compiler/dex/dex_to_dex_decompiler_test.cc
@@ -91,19 +91,7 @@
it.SkipAllFields();
// Unquicken each method.
- while (it.HasNextDirectMethod()) {
- uint32_t method_idx = it.GetMemberIndex();
- CompiledMethod* compiled_method =
- compiler_driver_->GetCompiledMethod(MethodReference(updated_dex_file, method_idx));
- ArrayRef<const uint8_t> table;
- if (compiled_method != nullptr) {
- table = compiled_method->GetVmapTable();
- }
- optimizer::ArtDecompileDEX(
- *it.GetMethodCodeItem(), table, /* decompile_return_instruction */ true);
- it.Next();
- }
- while (it.HasNextVirtualMethod()) {
+ while (it.HasNextMethod()) {
uint32_t method_idx = it.GetMemberIndex();
CompiledMethod* compiled_method =
compiler_driver_->GetCompiledMethod(MethodReference(updated_dex_file, method_idx));
diff --git a/compiler/dex/inline_method_analyser.cc b/compiler/dex/inline_method_analyser.cc
index 518b0ec..b409eb2 100644
--- a/compiler/dex/inline_method_analyser.cc
+++ b/compiler/dex/inline_method_analyser.cc
@@ -20,6 +20,7 @@
#include "art_method-inl.h"
#include "base/enums.h"
#include "class_linker-inl.h"
+#include "code_item_accessors-inl.h"
#include "dex_file-inl.h"
#include "dex_instruction-inl.h"
#include "dex_instruction.h"
@@ -43,7 +44,7 @@
typedef bool MatchFn(Matcher* matcher);
template <size_t size>
- static bool Match(const DexFile::CodeItem* code_item, MatchFn* const (&pattern)[size]);
+ static bool Match(const CodeItemDataAccessor* code_item, MatchFn* const (&pattern)[size]);
// Match and advance.
@@ -62,22 +63,20 @@
bool IPutOnThis();
private:
- explicit Matcher(const DexFile::CodeItem* code_item)
+ explicit Matcher(const CodeItemDataAccessor* code_item)
: code_item_(code_item),
- instruction_(code_item->Instructions().begin()),
- pos_(0u),
- mark_(0u) { }
+ instruction_(code_item->begin()) {}
- static bool DoMatch(const DexFile::CodeItem* code_item, MatchFn* const* pattern, size_t size);
+ static bool DoMatch(const CodeItemDataAccessor* code_item, MatchFn* const* pattern, size_t size);
- const DexFile::CodeItem* const code_item_;
+ const CodeItemDataAccessor* const code_item_;
DexInstructionIterator instruction_;
- size_t pos_;
- size_t mark_;
+ size_t pos_ = 0u;
+ size_t mark_ = 0u;
};
template <size_t size>
-bool Matcher::Match(const DexFile::CodeItem* code_item, MatchFn* const (&pattern)[size]) {
+bool Matcher::Match(const CodeItemDataAccessor* code_item, MatchFn* const (&pattern)[size]) {
return DoMatch(code_item, pattern, size);
}
@@ -122,12 +121,12 @@
}
bool Matcher::IPutOnThis() {
- DCHECK_NE(code_item_->ins_size_, 0u);
+ DCHECK_NE(code_item_->InsSize(), 0u);
return IsInstructionIPut(instruction_->Opcode()) &&
- instruction_->VRegB_22c() == code_item_->registers_size_ - code_item_->ins_size_;
+ instruction_->VRegB_22c() == code_item_->RegistersSize() - code_item_->InsSize();
}
-bool Matcher::DoMatch(const DexFile::CodeItem* code_item, MatchFn* const* pattern, size_t size) {
+bool Matcher::DoMatch(const CodeItemDataAccessor* code_item, MatchFn* const* pattern, size_t size) {
Matcher matcher(code_item);
while (matcher.pos_ != size) {
if (!pattern[matcher.pos_](&matcher)) {
@@ -158,7 +157,7 @@
// Return the forwarded arguments and check that all remaining arguments are zero.
// If the check fails, return static_cast<size_t>(-1).
-size_t CountForwardedConstructorArguments(const DexFile::CodeItem* code_item,
+size_t CountForwardedConstructorArguments(const CodeItemDataAccessor* code_item,
const Instruction* invoke_direct,
uint16_t zero_vreg_mask) {
DCHECK_EQ(invoke_direct->Opcode(), Instruction::INVOKE_DIRECT);
@@ -167,7 +166,7 @@
uint32_t args[Instruction::kMaxVarArgRegs];
invoke_direct->GetVarArgs(args);
uint16_t this_vreg = args[0];
- DCHECK_EQ(this_vreg, code_item->registers_size_ - code_item->ins_size_); // Checked by verifier.
+ DCHECK_EQ(this_vreg, code_item->RegistersSize() - code_item->InsSize()); // Checked by verifier.
size_t forwarded = 1u;
while (forwarded < number_of_args &&
args[forwarded] == this_vreg + forwarded &&
@@ -249,7 +248,7 @@
return true;
}
-bool DoAnalyseConstructor(const DexFile::CodeItem* code_item,
+bool DoAnalyseConstructor(const CodeItemDataAccessor* code_item,
ArtMethod* method,
/*inout*/ ConstructorIPutData (&iputs)[kMaxConstructorIPuts])
REQUIRES_SHARED(Locks::mutator_lock_) {
@@ -292,17 +291,17 @@
DCHECK(method->IsConstructor());
DCHECK(code_item != nullptr);
if (!method->GetDeclaringClass()->IsVerified() ||
- code_item->insns_size_in_code_units_ > kMaxCodeUnits ||
- code_item->registers_size_ > kMaxVRegs ||
+ code_item->InsnsSizeInCodeUnits() > kMaxCodeUnits ||
+ code_item->RegistersSize() > kMaxVRegs ||
!Matcher::Match(code_item, kConstructorPattern)) {
return false;
}
// Verify the invoke, prevent a few odd cases and collect IPUTs.
- uint16_t this_vreg = code_item->registers_size_ - code_item->ins_size_;
+ uint16_t this_vreg = code_item->RegistersSize() - code_item->InsSize();
uint16_t zero_vreg_mask = 0u;
- for (const DexInstructionPcPair& pair : code_item->Instructions()) {
+ for (const DexInstructionPcPair& pair : *code_item) {
const Instruction& instruction = pair.Inst();
if (instruction.Opcode() == Instruction::RETURN_VOID) {
break;
@@ -314,7 +313,7 @@
// We allow forwarding constructors only if they pass more arguments
// to prevent infinite recursion.
if (target_method->GetDeclaringClass() == method->GetDeclaringClass() &&
- instruction.VRegA_35c() <= code_item->ins_size_) {
+ instruction.VRegA_35c() <= code_item->InsSize()) {
return false;
}
size_t forwarded = CountForwardedConstructorArguments(code_item, &instruction, zero_vreg_mask);
@@ -322,14 +321,13 @@
return false;
}
if (target_method->GetDeclaringClass()->IsObjectClass()) {
- DCHECK_EQ(target_method->GetCodeItem()->Instructions().begin()->Opcode(),
- Instruction::RETURN_VOID);
+ DCHECK_EQ(CodeItemDataAccessor(target_method).begin()->Opcode(), Instruction::RETURN_VOID);
} else {
- const DexFile::CodeItem* target_code_item = target_method->GetCodeItem();
- if (target_code_item == nullptr) {
+ CodeItemDataAccessor target_code_item = CodeItemDataAccessor::CreateNullable(target_method);
+ if (!target_code_item.HasCodeItem()) {
return false; // Native constructor?
}
- if (!DoAnalyseConstructor(target_code_item, target_method, iputs)) {
+ if (!DoAnalyseConstructor(&target_code_item, target_method, iputs)) {
return false;
}
// Prune IPUTs with zero input.
@@ -365,7 +363,7 @@
} // anonymous namespace
-bool AnalyseConstructor(const DexFile::CodeItem* code_item,
+bool AnalyseConstructor(const CodeItemDataAccessor* code_item,
ArtMethod* method,
InlineMethod* result)
REQUIRES_SHARED(Locks::mutator_lock_) {
@@ -429,27 +427,27 @@
InlineMethodAnalyser::IPutVariant(Instruction::IPUT_SHORT), "iget/iput_short variant");
bool InlineMethodAnalyser::AnalyseMethodCode(ArtMethod* method, InlineMethod* result) {
- const DexFile::CodeItem* code_item = method->GetCodeItem();
- if (code_item == nullptr) {
+ CodeItemDataAccessor code_item = CodeItemDataAccessor::CreateNullable(method);
+ if (!code_item.HasCodeItem()) {
// Native or abstract.
return false;
}
- return AnalyseMethodCode(code_item,
+ return AnalyseMethodCode(&code_item,
MethodReference(method->GetDexFile(), method->GetDexMethodIndex()),
method->IsStatic(),
method,
result);
}
-bool InlineMethodAnalyser::AnalyseMethodCode(const DexFile::CodeItem* code_item,
+bool InlineMethodAnalyser::AnalyseMethodCode(const CodeItemDataAccessor* code_item,
const MethodReference& method_ref,
bool is_static,
ArtMethod* method,
InlineMethod* result) {
// We currently support only plain return or 2-instruction methods.
- DCHECK_NE(code_item->insns_size_in_code_units_, 0u);
- Instruction::Code opcode = code_item->Instructions().begin()->Opcode();
+ DCHECK_NE(code_item->InsnsSizeInCodeUnits(), 0u);
+ Instruction::Code opcode = code_item->begin()->Opcode();
switch (opcode) {
case Instruction::RETURN_VOID:
@@ -518,15 +516,15 @@
strncmp(method_name, "-", strlen("-")) == 0;
}
-bool InlineMethodAnalyser::AnalyseReturnMethod(const DexFile::CodeItem* code_item,
+bool InlineMethodAnalyser::AnalyseReturnMethod(const CodeItemDataAccessor* code_item,
InlineMethod* result) {
- DexInstructionIterator return_instruction = code_item->Instructions().begin();
+ DexInstructionIterator return_instruction = code_item->begin();
Instruction::Code return_opcode = return_instruction->Opcode();
uint32_t reg = return_instruction->VRegA_11x();
- uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_;
+ uint32_t arg_start = code_item->RegistersSize() - code_item->InsSize();
DCHECK_GE(reg, arg_start);
DCHECK_LT((return_opcode == Instruction::RETURN_WIDE) ? reg + 1 : reg,
- code_item->registers_size_);
+ code_item->RegistersSize());
if (result != nullptr) {
result->opcode = kInlineOpReturnArg;
@@ -540,9 +538,9 @@
return true;
}
-bool InlineMethodAnalyser::AnalyseConstMethod(const DexFile::CodeItem* code_item,
+bool InlineMethodAnalyser::AnalyseConstMethod(const CodeItemDataAccessor* code_item,
InlineMethod* result) {
- DexInstructionIterator instruction = code_item->Instructions().begin();
+ DexInstructionIterator instruction = code_item->begin();
const Instruction* return_instruction = instruction->Next();
Instruction::Code return_opcode = return_instruction->Opcode();
if (return_opcode != Instruction::RETURN &&
@@ -551,13 +549,13 @@
}
int32_t return_reg = return_instruction->VRegA_11x();
- DCHECK_LT(return_reg, code_item->registers_size_);
+ DCHECK_LT(return_reg, code_item->RegistersSize());
int32_t const_value = instruction->VRegB();
if (instruction->Opcode() == Instruction::CONST_HIGH16) {
const_value <<= 16;
}
- DCHECK_LT(instruction->VRegA(), code_item->registers_size_);
+ DCHECK_LT(instruction->VRegA(), code_item->RegistersSize());
if (instruction->VRegA() != return_reg) {
return false; // Not returning the value set by const?
}
@@ -571,12 +569,12 @@
return true;
}
-bool InlineMethodAnalyser::AnalyseIGetMethod(const DexFile::CodeItem* code_item,
+bool InlineMethodAnalyser::AnalyseIGetMethod(const CodeItemDataAccessor* code_item,
const MethodReference& method_ref,
bool is_static,
ArtMethod* method,
InlineMethod* result) {
- DexInstructionIterator instruction = code_item->Instructions().begin();
+ DexInstructionIterator instruction = code_item->begin();
Instruction::Code opcode = instruction->Opcode();
DCHECK(IsInstructionIGet(opcode));
@@ -591,17 +589,17 @@
uint32_t return_reg = return_instruction->VRegA_11x();
DCHECK_LT(return_opcode == Instruction::RETURN_WIDE ? return_reg + 1 : return_reg,
- code_item->registers_size_);
+ code_item->RegistersSize());
uint32_t dst_reg = instruction->VRegA_22c();
uint32_t object_reg = instruction->VRegB_22c();
uint32_t field_idx = instruction->VRegC_22c();
- uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_;
+ uint32_t arg_start = code_item->RegistersSize() - code_item->InsSize();
DCHECK_GE(object_reg, arg_start);
- DCHECK_LT(object_reg, code_item->registers_size_);
+ DCHECK_LT(object_reg, code_item->RegistersSize());
uint32_t object_arg = object_reg - arg_start;
- DCHECK_LT(opcode == Instruction::IGET_WIDE ? dst_reg + 1 : dst_reg, code_item->registers_size_);
+ DCHECK_LT(opcode == Instruction::IGET_WIDE ? dst_reg + 1 : dst_reg, code_item->RegistersSize());
if (dst_reg != return_reg) {
return false; // Not returning the value retrieved by IGET?
}
@@ -635,18 +633,18 @@
return true;
}
-bool InlineMethodAnalyser::AnalyseIPutMethod(const DexFile::CodeItem* code_item,
+bool InlineMethodAnalyser::AnalyseIPutMethod(const CodeItemDataAccessor* code_item,
const MethodReference& method_ref,
bool is_static,
ArtMethod* method,
InlineMethod* result) {
- DexInstructionIterator instruction = code_item->Instructions().begin();
+ DexInstructionIterator instruction = code_item->begin();
Instruction::Code opcode = instruction->Opcode();
DCHECK(IsInstructionIPut(opcode));
const Instruction* return_instruction = instruction->Next();
Instruction::Code return_opcode = return_instruction->Opcode();
- uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_;
+ uint32_t arg_start = code_item->RegistersSize() - code_item->InsSize();
uint16_t return_arg_plus1 = 0u;
if (return_opcode != Instruction::RETURN_VOID) {
if (return_opcode != Instruction::RETURN &&
@@ -658,7 +656,7 @@
uint32_t return_reg = return_instruction->VRegA_11x();
DCHECK_GE(return_reg, arg_start);
DCHECK_LT(return_opcode == Instruction::RETURN_WIDE ? return_reg + 1u : return_reg,
- code_item->registers_size_);
+ code_item->RegistersSize());
return_arg_plus1 = return_reg - arg_start + 1u;
}
@@ -666,9 +664,9 @@
uint32_t object_reg = instruction->VRegB_22c();
uint32_t field_idx = instruction->VRegC_22c();
DCHECK_GE(object_reg, arg_start);
- DCHECK_LT(object_reg, code_item->registers_size_);
+ DCHECK_LT(object_reg, code_item->RegistersSize());
DCHECK_GE(src_reg, arg_start);
- DCHECK_LT(opcode == Instruction::IPUT_WIDE ? src_reg + 1 : src_reg, code_item->registers_size_);
+ DCHECK_LT(opcode == Instruction::IPUT_WIDE ? src_reg + 1 : src_reg, code_item->RegistersSize());
uint32_t object_arg = object_reg - arg_start;
uint32_t src_arg = src_reg - arg_start;
diff --git a/compiler/dex/inline_method_analyser.h b/compiler/dex/inline_method_analyser.h
index a35e97f..cde2147 100644
--- a/compiler/dex/inline_method_analyser.h
+++ b/compiler/dex/inline_method_analyser.h
@@ -30,6 +30,8 @@
namespace art {
+class CodeItemDataAccessor;
+
namespace verifier {
class MethodVerifier;
} // namespace verifier
@@ -121,21 +123,21 @@
static bool IsSyntheticAccessor(MethodReference ref);
private:
- static bool AnalyseMethodCode(const DexFile::CodeItem* code_item,
+ static bool AnalyseMethodCode(const CodeItemDataAccessor* code_item,
const MethodReference& method_ref,
bool is_static,
ArtMethod* method,
InlineMethod* result)
REQUIRES_SHARED(Locks::mutator_lock_);
- static bool AnalyseReturnMethod(const DexFile::CodeItem* code_item, InlineMethod* result);
- static bool AnalyseConstMethod(const DexFile::CodeItem* code_item, InlineMethod* result);
- static bool AnalyseIGetMethod(const DexFile::CodeItem* code_item,
+ static bool AnalyseReturnMethod(const CodeItemDataAccessor* code_item, InlineMethod* result);
+ static bool AnalyseConstMethod(const CodeItemDataAccessor* code_item, InlineMethod* result);
+ static bool AnalyseIGetMethod(const CodeItemDataAccessor* code_item,
const MethodReference& method_ref,
bool is_static,
ArtMethod* method,
InlineMethod* result)
REQUIRES_SHARED(Locks::mutator_lock_);
- static bool AnalyseIPutMethod(const DexFile::CodeItem* code_item,
+ static bool AnalyseIPutMethod(const CodeItemDataAccessor* code_item,
const MethodReference& method_ref,
bool is_static,
ArtMethod* method,
diff --git a/compiler/dex/verified_method.cc b/compiler/dex/verified_method.cc
index df75e07..524b0a6 100644
--- a/compiler/dex/verified_method.cc
+++ b/compiler/dex/verified_method.cc
@@ -20,6 +20,7 @@
#include <memory>
#include "base/logging.h"
+#include "code_item_accessors-inl.h"
#include "dex_file.h"
#include "dex_instruction-inl.h"
#include "runtime.h"
@@ -64,7 +65,7 @@
if (method_verifier->HasFailures()) {
return;
}
- for (const DexInstructionPcPair& pair : method_verifier->CodeItem()->Instructions()) {
+ for (const DexInstructionPcPair& pair : method_verifier->CodeItem()) {
const Instruction& inst = pair.Inst();
const Instruction::Code code = inst.Opcode();
if (code == Instruction::CHECK_CAST) {
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 32d0bbe..f4700d4 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -762,31 +762,17 @@
continue;
}
- // Direct methods.
- int64_t previous_direct_method_idx = -1;
- while (it.HasNextDirectMethod()) {
+ // Direct and virtual methods.
+ int64_t previous_method_idx = -1;
+ while (it.HasNextMethod()) {
uint32_t method_idx = it.GetMemberIndex();
- if (method_idx == previous_direct_method_idx) {
+ if (method_idx == previous_method_idx) {
// smali can create dex files with two encoded_methods sharing the same method_idx
// http://code.google.com/p/smali/issues/detail?id=119
it.Next();
continue;
}
- previous_direct_method_idx = method_idx;
- ResolveConstStrings(dex_cache, *dex_file, it.GetMethodCodeItem());
- it.Next();
- }
- // Virtual methods.
- int64_t previous_virtual_method_idx = -1;
- while (it.HasNextVirtualMethod()) {
- uint32_t method_idx = it.GetMemberIndex();
- if (method_idx == previous_virtual_method_idx) {
- // smali can create dex files with two encoded_methods sharing the same method_idx
- // http://code.google.com/p/smali/issues/detail?id=119
- it.Next();
- continue;
- }
- previous_virtual_method_idx = method_idx;
+ previous_method_idx = method_idx;
ResolveConstStrings(dex_cache, *dex_file, it.GetMethodCodeItem());
it.Next();
}
@@ -1702,16 +1688,7 @@
it.Next();
}
if (resolve_fields_and_methods) {
- while (it.HasNextDirectMethod()) {
- ArtMethod* method = class_linker->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>(
- dex_file, it.GetMemberIndex(), dex_cache, class_loader, nullptr,
- it.GetMethodInvokeType(class_def));
- if (method == nullptr) {
- CheckAndClearResolveException(soa.Self());
- }
- it.Next();
- }
- while (it.HasNextVirtualMethod()) {
+ while (it.HasNextMethod()) {
ArtMethod* method = class_linker->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>(
dex_file, it.GetMemberIndex(), dex_cache, class_loader, nullptr,
it.GetMethodInvokeType(class_def));
@@ -1820,12 +1797,7 @@
ClassDataItemIterator it(dex_file, class_data);
it.SkipAllFields();
- while (it.HasNextDirectMethod()) {
- verification_results->CreateVerifiedMethodFor(MethodReference(&dex_file, it.GetMemberIndex()));
- it.Next();
- }
-
- while (it.HasNextVirtualMethod()) {
+ while (it.HasNextMethod()) {
verification_results->CreateVerifiedMethodFor(MethodReference(&dex_file, it.GetMemberIndex()));
it.Next();
}
@@ -2752,17 +2724,17 @@
bool compilation_enabled = driver->IsClassToCompile(
dex_file.StringByTypeIdx(class_def.class_idx_));
- // Compile direct methods
- int64_t previous_direct_method_idx = -1;
- while (it.HasNextDirectMethod()) {
+ // Compile direct and virtual methods.
+ int64_t previous_method_idx = -1;
+ while (it.HasNextMethod()) {
uint32_t method_idx = it.GetMemberIndex();
- if (method_idx == previous_direct_method_idx) {
+ if (method_idx == previous_method_idx) {
// smali can create dex files with two encoded_methods sharing the same method_idx
// http://code.google.com/p/smali/issues/detail?id=119
it.Next();
continue;
}
- previous_direct_method_idx = method_idx;
+ previous_method_idx = method_idx;
CompileMethod(soa.Self(),
driver,
it.GetMethodCodeItem(),
@@ -2777,30 +2749,6 @@
dex_cache);
it.Next();
}
- // Compile virtual methods
- int64_t previous_virtual_method_idx = -1;
- while (it.HasNextVirtualMethod()) {
- uint32_t method_idx = it.GetMemberIndex();
- if (method_idx == previous_virtual_method_idx) {
- // smali can create dex files with two encoded_methods sharing the same method_idx
- // http://code.google.com/p/smali/issues/detail?id=119
- it.Next();
- continue;
- }
- previous_virtual_method_idx = method_idx;
- CompileMethod(soa.Self(),
- driver, it.GetMethodCodeItem(),
- it.GetMethodAccessFlags(),
- it.GetMethodInvokeType(class_def),
- class_def_index,
- method_idx,
- class_loader,
- dex_file,
- dex_to_dex_compilation_level,
- compilation_enabled,
- dex_cache);
- it.Next();
- }
DCHECK(!it.HasNext());
}
diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc
index 5c89869..0c82d60 100644
--- a/compiler/jit/jit_compiler.cc
+++ b/compiler/jit/jit_compiler.cc
@@ -80,6 +80,9 @@
JitCompiler::JitCompiler() {
compiler_options_.reset(new CompilerOptions());
+ // Special case max code units for inlining, whose default is "unset" (implictly
+ // meaning no limit). Do this before parsing the actuall passed options.
+ compiler_options_->SetInlineMaxCodeUnits(CompilerOptions::kDefaultInlineMaxCodeUnits);
{
std::string error_msg;
if (!compiler_options_->ParseCompilerOptions(Runtime::Current()->GetCompilerOptions(),
@@ -95,10 +98,6 @@
// Set debuggability based on the runtime value.
compiler_options_->SetDebuggable(Runtime::Current()->IsJavaDebuggable());
- // Special case max code units for inlining, whose default is "unset" (implictly
- // meaning no limit).
- compiler_options_->SetInlineMaxCodeUnits(CompilerOptions::kDefaultInlineMaxCodeUnits);
-
const InstructionSet instruction_set = kRuntimeISA;
for (const StringPiece option : Runtime::Current()->GetCompilerOptions()) {
VLOG(compiler) << "JIT compiler option " << option;
diff --git a/compiler/optimizing/block_builder.cc b/compiler/optimizing/block_builder.cc
index 595dd4d..2432f13 100644
--- a/compiler/optimizing/block_builder.cc
+++ b/compiler/optimizing/block_builder.cc
@@ -269,7 +269,9 @@
// loop for synchronized blocks.
if (ContainsElement(throwing_blocks_, block)) {
// Try to find a TryItem covering the block.
- const int32_t try_item_idx = DexFile::FindTryItem(code_item_, block->GetDexPc());
+ const int32_t try_item_idx = DexFile::FindTryItem(DexFile::GetTryItems(code_item_, 0u),
+ code_item_.tries_size_,
+ block->GetDexPc());
if (try_item_idx != -1) {
// Block throwing and in a TryItem. Store the try block information.
try_block_info.Put(block->GetBlockId(), DexFile::GetTryItems(code_item_, try_item_idx));
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index f9f5a4d..ddec0cc 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -2474,6 +2474,7 @@
}
}
} else {
+ const bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
MipsLabel done;
if (instr->IsShl()) {
__ Sllv(dst_low, lhs_low, rhs_reg);
@@ -2483,9 +2484,14 @@
__ Sllv(dst_high, lhs_high, rhs_reg);
__ Or(dst_high, dst_high, TMP);
__ Andi(TMP, rhs_reg, kMipsBitsPerWord);
- __ Beqz(TMP, &done);
- __ Move(dst_high, dst_low);
- __ Move(dst_low, ZERO);
+ if (isR6) {
+ __ Beqzc(TMP, &done, /* is_bare */ true);
+ __ Move(dst_high, dst_low);
+ __ Move(dst_low, ZERO);
+ } else {
+ __ Movn(dst_high, dst_low, TMP);
+ __ Movn(dst_low, ZERO, TMP);
+ }
} else if (instr->IsShr()) {
__ Srav(dst_high, lhs_high, rhs_reg);
__ Nor(AT, ZERO, rhs_reg);
@@ -2494,9 +2500,15 @@
__ Srlv(dst_low, lhs_low, rhs_reg);
__ Or(dst_low, dst_low, TMP);
__ Andi(TMP, rhs_reg, kMipsBitsPerWord);
- __ Beqz(TMP, &done);
- __ Move(dst_low, dst_high);
- __ Sra(dst_high, dst_high, 31);
+ if (isR6) {
+ __ Beqzc(TMP, &done, /* is_bare */ true);
+ __ Move(dst_low, dst_high);
+ __ Sra(dst_high, dst_high, 31);
+ } else {
+ __ Sra(AT, dst_high, 31);
+ __ Movn(dst_low, dst_high, TMP);
+ __ Movn(dst_high, AT, TMP);
+ }
} else if (instr->IsUShr()) {
__ Srlv(dst_high, lhs_high, rhs_reg);
__ Nor(AT, ZERO, rhs_reg);
@@ -2505,10 +2517,15 @@
__ Srlv(dst_low, lhs_low, rhs_reg);
__ Or(dst_low, dst_low, TMP);
__ Andi(TMP, rhs_reg, kMipsBitsPerWord);
- __ Beqz(TMP, &done);
- __ Move(dst_low, dst_high);
- __ Move(dst_high, ZERO);
- } else {
+ if (isR6) {
+ __ Beqzc(TMP, &done, /* is_bare */ true);
+ __ Move(dst_low, dst_high);
+ __ Move(dst_high, ZERO);
+ } else {
+ __ Movn(dst_low, dst_high, TMP);
+ __ Movn(dst_high, ZERO, TMP);
+ }
+ } else { // Rotate.
__ Nor(AT, ZERO, rhs_reg);
__ Srlv(TMP, lhs_low, rhs_reg);
__ Sll(dst_low, lhs_high, 1);
@@ -2519,10 +2536,16 @@
__ Sllv(dst_high, dst_high, AT);
__ Or(dst_high, dst_high, TMP);
__ Andi(TMP, rhs_reg, kMipsBitsPerWord);
- __ Beqz(TMP, &done);
- __ Move(TMP, dst_high);
- __ Move(dst_high, dst_low);
- __ Move(dst_low, TMP);
+ if (isR6) {
+ __ Beqzc(TMP, &done, /* is_bare */ true);
+ __ Move(TMP, dst_high);
+ __ Move(dst_high, dst_low);
+ __ Move(dst_low, TMP);
+ } else {
+ __ Movn(AT, dst_high, TMP);
+ __ Movn(dst_high, dst_low, TMP);
+ __ Movn(dst_low, AT, TMP);
+ }
}
__ Bind(&done);
}
diff --git a/compiler/optimizing/code_generator_vector_mips.cc b/compiler/optimizing/code_generator_vector_mips.cc
index 384b642..3cf150a 100644
--- a/compiler/optimizing/code_generator_vector_mips.cc
+++ b/compiler/optimizing/code_generator_vector_mips.cc
@@ -1071,11 +1071,195 @@
void LocationsBuilderMIPS::VisitVecSADAccumulate(HVecSADAccumulate* instruction) {
CreateVecAccumLocations(GetGraph()->GetAllocator(), instruction);
+ LocationSummary* locations = instruction->GetLocations();
+ // All conversions require at least one temporary register.
+ locations->AddTemp(Location::RequiresFpuRegister());
+ // Some conversions require a second temporary register.
+ HVecOperation* a = instruction->InputAt(1)->AsVecOperation();
+ HVecOperation* b = instruction->InputAt(2)->AsVecOperation();
+ DCHECK_EQ(HVecOperation::ToSignedType(a->GetPackedType()),
+ HVecOperation::ToSignedType(b->GetPackedType()));
+ switch (a->GetPackedType()) {
+ case DataType::Type::kInt32:
+ if (instruction->GetPackedType() == DataType::Type::kInt32) {
+ break;
+ }
+ FALLTHROUGH_INTENDED;
+ case DataType::Type::kUint8:
+ case DataType::Type::kInt8:
+ case DataType::Type::kUint16:
+ case DataType::Type::kInt16:
+ locations->AddTemp(Location::RequiresFpuRegister());
+ break;
+ default:
+ break;
+ }
}
void InstructionCodeGeneratorMIPS::VisitVecSADAccumulate(HVecSADAccumulate* instruction) {
- LOG(FATAL) << "No SIMD for " << instruction->GetId();
- // TODO: implement this, location helper already filled out (shared with MulAcc).
+ LocationSummary* locations = instruction->GetLocations();
+ VectorRegister acc = VectorRegisterFrom(locations->InAt(0));
+ VectorRegister left = VectorRegisterFrom(locations->InAt(1));
+ VectorRegister right = VectorRegisterFrom(locations->InAt(2));
+ VectorRegister tmp = static_cast<VectorRegister>(FTMP);
+ VectorRegister tmp1 = VectorRegisterFrom(locations->GetTemp(0));
+
+ DCHECK(locations->InAt(0).Equals(locations->Out()));
+
+ // Handle all feasible acc_T += sad(a_S, b_S) type combinations (T x S).
+ HVecOperation* a = instruction->InputAt(1)->AsVecOperation();
+ HVecOperation* b = instruction->InputAt(2)->AsVecOperation();
+ DCHECK_EQ(HVecOperation::ToSignedType(a->GetPackedType()),
+ HVecOperation::ToSignedType(b->GetPackedType()));
+ switch (a->GetPackedType()) {
+ case DataType::Type::kUint8:
+ case DataType::Type::kInt8:
+ DCHECK_EQ(16u, a->GetVectorLength());
+ switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint16:
+ case DataType::Type::kInt16: {
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ VectorRegister tmp2 = VectorRegisterFrom(locations->GetTemp(1));
+ __ FillB(tmp, ZERO);
+ __ Hadd_sH(tmp1, left, tmp);
+ __ Hadd_sH(tmp2, right, tmp);
+ __ Asub_sH(tmp1, tmp1, tmp2);
+ __ AddvH(acc, acc, tmp1);
+ __ Hadd_sH(tmp1, tmp, left);
+ __ Hadd_sH(tmp2, tmp, right);
+ __ Asub_sH(tmp1, tmp1, tmp2);
+ __ AddvH(acc, acc, tmp1);
+ break;
+ }
+ case DataType::Type::kInt32: {
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ VectorRegister tmp2 = VectorRegisterFrom(locations->GetTemp(1));
+ __ FillB(tmp, ZERO);
+ __ Hadd_sH(tmp1, left, tmp);
+ __ Hadd_sH(tmp2, right, tmp);
+ __ Asub_sH(tmp1, tmp1, tmp2);
+ __ Hadd_sW(tmp1, tmp1, tmp1);
+ __ AddvW(acc, acc, tmp1);
+ __ Hadd_sH(tmp1, tmp, left);
+ __ Hadd_sH(tmp2, tmp, right);
+ __ Asub_sH(tmp1, tmp1, tmp2);
+ __ Hadd_sW(tmp1, tmp1, tmp1);
+ __ AddvW(acc, acc, tmp1);
+ break;
+ }
+ case DataType::Type::kInt64: {
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ VectorRegister tmp2 = VectorRegisterFrom(locations->GetTemp(1));
+ __ FillB(tmp, ZERO);
+ __ Hadd_sH(tmp1, left, tmp);
+ __ Hadd_sH(tmp2, right, tmp);
+ __ Asub_sH(tmp1, tmp1, tmp2);
+ __ Hadd_sW(tmp1, tmp1, tmp1);
+ __ Hadd_sD(tmp1, tmp1, tmp1);
+ __ AddvD(acc, acc, tmp1);
+ __ Hadd_sH(tmp1, tmp, left);
+ __ Hadd_sH(tmp2, tmp, right);
+ __ Asub_sH(tmp1, tmp1, tmp2);
+ __ Hadd_sW(tmp1, tmp1, tmp1);
+ __ Hadd_sD(tmp1, tmp1, tmp1);
+ __ AddvD(acc, acc, tmp1);
+ break;
+ }
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
+ break;
+ case DataType::Type::kUint16:
+ case DataType::Type::kInt16:
+ DCHECK_EQ(8u, a->GetVectorLength());
+ switch (instruction->GetPackedType()) {
+ case DataType::Type::kInt32: {
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ VectorRegister tmp2 = VectorRegisterFrom(locations->GetTemp(1));
+ __ FillH(tmp, ZERO);
+ __ Hadd_sW(tmp1, left, tmp);
+ __ Hadd_sW(tmp2, right, tmp);
+ __ Asub_sW(tmp1, tmp1, tmp2);
+ __ AddvW(acc, acc, tmp1);
+ __ Hadd_sW(tmp1, tmp, left);
+ __ Hadd_sW(tmp2, tmp, right);
+ __ Asub_sW(tmp1, tmp1, tmp2);
+ __ AddvW(acc, acc, tmp1);
+ break;
+ }
+ case DataType::Type::kInt64: {
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ VectorRegister tmp2 = VectorRegisterFrom(locations->GetTemp(1));
+ __ FillH(tmp, ZERO);
+ __ Hadd_sW(tmp1, left, tmp);
+ __ Hadd_sW(tmp2, right, tmp);
+ __ Asub_sW(tmp1, tmp1, tmp2);
+ __ Hadd_sD(tmp1, tmp1, tmp1);
+ __ AddvD(acc, acc, tmp1);
+ __ Hadd_sW(tmp1, tmp, left);
+ __ Hadd_sW(tmp2, tmp, right);
+ __ Asub_sW(tmp1, tmp1, tmp2);
+ __ Hadd_sD(tmp1, tmp1, tmp1);
+ __ AddvD(acc, acc, tmp1);
+ break;
+ }
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
+ break;
+ case DataType::Type::kInt32:
+ DCHECK_EQ(4u, a->GetVectorLength());
+ switch (instruction->GetPackedType()) {
+ case DataType::Type::kInt32: {
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ FillW(tmp, ZERO);
+ __ SubvW(tmp1, left, right);
+ __ Add_aW(tmp1, tmp1, tmp);
+ __ AddvW(acc, acc, tmp1);
+ break;
+ }
+ case DataType::Type::kInt64: {
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ VectorRegister tmp2 = VectorRegisterFrom(locations->GetTemp(1));
+ __ FillW(tmp, ZERO);
+ __ Hadd_sD(tmp1, left, tmp);
+ __ Hadd_sD(tmp2, right, tmp);
+ __ Asub_sD(tmp1, tmp1, tmp2);
+ __ AddvD(acc, acc, tmp1);
+ __ Hadd_sD(tmp1, tmp, left);
+ __ Hadd_sD(tmp2, tmp, right);
+ __ Asub_sD(tmp1, tmp1, tmp2);
+ __ AddvD(acc, acc, tmp1);
+ break;
+ }
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
+ break;
+ case DataType::Type::kInt64: {
+ DCHECK_EQ(2u, a->GetVectorLength());
+ switch (instruction->GetPackedType()) {
+ case DataType::Type::kInt64: {
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ __ FillW(tmp, ZERO);
+ __ SubvD(tmp1, left, right);
+ __ Add_aD(tmp1, tmp1, tmp);
+ __ AddvD(acc, acc, tmp1);
+ break;
+ }
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
+ break;
+ }
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
}
// Helper to set up locations for vector memory operations.
diff --git a/compiler/optimizing/code_generator_vector_mips64.cc b/compiler/optimizing/code_generator_vector_mips64.cc
index 0c59b73..2d69533 100644
--- a/compiler/optimizing/code_generator_vector_mips64.cc
+++ b/compiler/optimizing/code_generator_vector_mips64.cc
@@ -1069,11 +1069,195 @@
void LocationsBuilderMIPS64::VisitVecSADAccumulate(HVecSADAccumulate* instruction) {
CreateVecAccumLocations(GetGraph()->GetAllocator(), instruction);
+ LocationSummary* locations = instruction->GetLocations();
+ // All conversions require at least one temporary register.
+ locations->AddTemp(Location::RequiresFpuRegister());
+ // Some conversions require a second temporary register.
+ HVecOperation* a = instruction->InputAt(1)->AsVecOperation();
+ HVecOperation* b = instruction->InputAt(2)->AsVecOperation();
+ DCHECK_EQ(HVecOperation::ToSignedType(a->GetPackedType()),
+ HVecOperation::ToSignedType(b->GetPackedType()));
+ switch (a->GetPackedType()) {
+ case DataType::Type::kInt32:
+ if (instruction->GetPackedType() == DataType::Type::kInt32) {
+ break;
+ }
+ FALLTHROUGH_INTENDED;
+ case DataType::Type::kUint8:
+ case DataType::Type::kInt8:
+ case DataType::Type::kUint16:
+ case DataType::Type::kInt16:
+ locations->AddTemp(Location::RequiresFpuRegister());
+ break;
+ default:
+ break;
+ }
}
void InstructionCodeGeneratorMIPS64::VisitVecSADAccumulate(HVecSADAccumulate* instruction) {
- LOG(FATAL) << "No SIMD for " << instruction->GetId();
- // TODO: implement this, location helper already filled out (shared with MulAcc).
+ LocationSummary* locations = instruction->GetLocations();
+ VectorRegister acc = VectorRegisterFrom(locations->InAt(0));
+ VectorRegister left = VectorRegisterFrom(locations->InAt(1));
+ VectorRegister right = VectorRegisterFrom(locations->InAt(2));
+ VectorRegister tmp = static_cast<VectorRegister>(FTMP);
+ VectorRegister tmp1 = VectorRegisterFrom(locations->GetTemp(0));
+
+ DCHECK(locations->InAt(0).Equals(locations->Out()));
+
+ // Handle all feasible acc_T += sad(a_S, b_S) type combinations (T x S).
+ HVecOperation* a = instruction->InputAt(1)->AsVecOperation();
+ HVecOperation* b = instruction->InputAt(2)->AsVecOperation();
+ DCHECK_EQ(HVecOperation::ToSignedType(a->GetPackedType()),
+ HVecOperation::ToSignedType(b->GetPackedType()));
+ switch (a->GetPackedType()) {
+ case DataType::Type::kUint8:
+ case DataType::Type::kInt8:
+ DCHECK_EQ(16u, a->GetVectorLength());
+ switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint16:
+ case DataType::Type::kInt16: {
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ VectorRegister tmp2 = VectorRegisterFrom(locations->GetTemp(1));
+ __ FillB(tmp, ZERO);
+ __ Hadd_sH(tmp1, left, tmp);
+ __ Hadd_sH(tmp2, right, tmp);
+ __ Asub_sH(tmp1, tmp1, tmp2);
+ __ AddvH(acc, acc, tmp1);
+ __ Hadd_sH(tmp1, tmp, left);
+ __ Hadd_sH(tmp2, tmp, right);
+ __ Asub_sH(tmp1, tmp1, tmp2);
+ __ AddvH(acc, acc, tmp1);
+ break;
+ }
+ case DataType::Type::kInt32: {
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ VectorRegister tmp2 = VectorRegisterFrom(locations->GetTemp(1));
+ __ FillB(tmp, ZERO);
+ __ Hadd_sH(tmp1, left, tmp);
+ __ Hadd_sH(tmp2, right, tmp);
+ __ Asub_sH(tmp1, tmp1, tmp2);
+ __ Hadd_sW(tmp1, tmp1, tmp1);
+ __ AddvW(acc, acc, tmp1);
+ __ Hadd_sH(tmp1, tmp, left);
+ __ Hadd_sH(tmp2, tmp, right);
+ __ Asub_sH(tmp1, tmp1, tmp2);
+ __ Hadd_sW(tmp1, tmp1, tmp1);
+ __ AddvW(acc, acc, tmp1);
+ break;
+ }
+ case DataType::Type::kInt64: {
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ VectorRegister tmp2 = VectorRegisterFrom(locations->GetTemp(1));
+ __ FillB(tmp, ZERO);
+ __ Hadd_sH(tmp1, left, tmp);
+ __ Hadd_sH(tmp2, right, tmp);
+ __ Asub_sH(tmp1, tmp1, tmp2);
+ __ Hadd_sW(tmp1, tmp1, tmp1);
+ __ Hadd_sD(tmp1, tmp1, tmp1);
+ __ AddvD(acc, acc, tmp1);
+ __ Hadd_sH(tmp1, tmp, left);
+ __ Hadd_sH(tmp2, tmp, right);
+ __ Asub_sH(tmp1, tmp1, tmp2);
+ __ Hadd_sW(tmp1, tmp1, tmp1);
+ __ Hadd_sD(tmp1, tmp1, tmp1);
+ __ AddvD(acc, acc, tmp1);
+ break;
+ }
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
+ break;
+ case DataType::Type::kUint16:
+ case DataType::Type::kInt16:
+ DCHECK_EQ(8u, a->GetVectorLength());
+ switch (instruction->GetPackedType()) {
+ case DataType::Type::kInt32: {
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ VectorRegister tmp2 = VectorRegisterFrom(locations->GetTemp(1));
+ __ FillH(tmp, ZERO);
+ __ Hadd_sW(tmp1, left, tmp);
+ __ Hadd_sW(tmp2, right, tmp);
+ __ Asub_sW(tmp1, tmp1, tmp2);
+ __ AddvW(acc, acc, tmp1);
+ __ Hadd_sW(tmp1, tmp, left);
+ __ Hadd_sW(tmp2, tmp, right);
+ __ Asub_sW(tmp1, tmp1, tmp2);
+ __ AddvW(acc, acc, tmp1);
+ break;
+ }
+ case DataType::Type::kInt64: {
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ VectorRegister tmp2 = VectorRegisterFrom(locations->GetTemp(1));
+ __ FillH(tmp, ZERO);
+ __ Hadd_sW(tmp1, left, tmp);
+ __ Hadd_sW(tmp2, right, tmp);
+ __ Asub_sW(tmp1, tmp1, tmp2);
+ __ Hadd_sD(tmp1, tmp1, tmp1);
+ __ AddvD(acc, acc, tmp1);
+ __ Hadd_sW(tmp1, tmp, left);
+ __ Hadd_sW(tmp2, tmp, right);
+ __ Asub_sW(tmp1, tmp1, tmp2);
+ __ Hadd_sD(tmp1, tmp1, tmp1);
+ __ AddvD(acc, acc, tmp1);
+ break;
+ }
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
+ break;
+ case DataType::Type::kInt32:
+ DCHECK_EQ(4u, a->GetVectorLength());
+ switch (instruction->GetPackedType()) {
+ case DataType::Type::kInt32: {
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ FillW(tmp, ZERO);
+ __ SubvW(tmp1, left, right);
+ __ Add_aW(tmp1, tmp1, tmp);
+ __ AddvW(acc, acc, tmp1);
+ break;
+ }
+ case DataType::Type::kInt64: {
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ VectorRegister tmp2 = VectorRegisterFrom(locations->GetTemp(1));
+ __ FillW(tmp, ZERO);
+ __ Hadd_sD(tmp1, left, tmp);
+ __ Hadd_sD(tmp2, right, tmp);
+ __ Asub_sD(tmp1, tmp1, tmp2);
+ __ AddvD(acc, acc, tmp1);
+ __ Hadd_sD(tmp1, tmp, left);
+ __ Hadd_sD(tmp2, tmp, right);
+ __ Asub_sD(tmp1, tmp1, tmp2);
+ __ AddvD(acc, acc, tmp1);
+ break;
+ }
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
+ break;
+ case DataType::Type::kInt64: {
+ DCHECK_EQ(2u, a->GetVectorLength());
+ switch (instruction->GetPackedType()) {
+ case DataType::Type::kInt64: {
+ DCHECK_EQ(2u, instruction->GetVectorLength());
+ __ FillD(tmp, ZERO);
+ __ SubvD(tmp1, left, right);
+ __ Add_aD(tmp1, tmp1, tmp);
+ __ AddvD(acc, acc, tmp1);
+ break;
+ }
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
+ break;
+ }
+ default:
+ LOG(FATAL) << "Unsupported SIMD type";
+ UNREACHABLE();
+ }
}
// Helper to set up locations for vector memory operations.
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index 4d846fa..7adb196 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -1672,7 +1672,7 @@
compiler_driver_,
codegen_,
inline_stats_,
- resolved_method->GetQuickenedInfo(class_linker->GetImagePointerSize()),
+ resolved_method->GetQuickenedInfo(),
handles_);
if (builder.BuildGraph() != kAnalysisSuccess) {
diff --git a/compiler/optimizing/load_store_analysis.h b/compiler/optimizing/load_store_analysis.h
index 999026c..aa8b5bb 100644
--- a/compiler/optimizing/load_store_analysis.h
+++ b/compiler/optimizing/load_store_analysis.h
@@ -32,8 +32,7 @@
position_(pos),
is_singleton_(true),
is_singleton_and_not_returned_(true),
- is_singleton_and_not_deopt_visible_(true),
- has_index_aliasing_(false) {
+ is_singleton_and_not_deopt_visible_(true) {
CalculateEscape(reference_,
nullptr,
&is_singleton_,
@@ -70,16 +69,6 @@
(!is_singleton_and_not_returned_ || !is_singleton_and_not_deopt_visible_);
}
- bool HasIndexAliasing() {
- return has_index_aliasing_;
- }
-
- void SetHasIndexAliasing(bool has_index_aliasing) {
- // Only allow setting to true.
- DCHECK(has_index_aliasing);
- has_index_aliasing_ = has_index_aliasing;
- }
-
private:
HInstruction* const reference_;
const size_t position_; // position in HeapLocationCollector's ref_info_array_.
@@ -90,9 +79,6 @@
bool is_singleton_and_not_returned_;
// Is singleton and not used as an environment local of HDeoptimize.
bool is_singleton_and_not_deopt_visible_;
- // Some heap locations with reference_ have array index aliasing,
- // e.g. arr[i] and arr[j] may be the same location.
- bool has_index_aliasing_;
DISALLOW_COPY_AND_ASSIGN(ReferenceInfo);
};
@@ -117,7 +103,8 @@
index_(index),
vector_length_(vector_length),
declaring_class_def_index_(declaring_class_def_index),
- value_killed_by_loop_side_effects_(true) {
+ value_killed_by_loop_side_effects_(true),
+ has_aliased_locations_(false) {
DCHECK(ref_info != nullptr);
DCHECK((offset == kInvalidFieldOffset && index != nullptr) ||
(offset != kInvalidFieldOffset && index == nullptr));
@@ -151,6 +138,14 @@
value_killed_by_loop_side_effects_ = val;
}
+ bool HasAliasedLocations() const {
+ return has_aliased_locations_;
+ }
+
+ void SetHasAliasedLocations(bool val) {
+ has_aliased_locations_ = val;
+ }
+
private:
// Reference for instance/static field, array element or vector data.
ReferenceInfo* const ref_info_;
@@ -173,6 +168,11 @@
// value may be killed by loop side effects.
bool value_killed_by_loop_side_effects_;
+ // Has aliased heap locations in the method, due to either the
+ // reference is aliased or the array element is aliased via different
+ // index names.
+ bool has_aliased_locations_;
+
DISALLOW_COPY_AND_ASSIGN(HeapLocation);
};
@@ -377,6 +377,7 @@
// Compute if two locations may alias to each other.
bool ComputeMayAlias(size_t index1, size_t index2) const {
+ DCHECK_NE(index1, index2);
HeapLocation* loc1 = heap_locations_[index1];
HeapLocation* loc2 = heap_locations_[index2];
if (loc1->GetOffset() != loc2->GetOffset()) {
@@ -399,9 +400,9 @@
if (!CanArrayElementsAlias(idx1, vector_length1, idx2, vector_length2)) {
return false;
}
- ReferenceInfo* ref_info = loc1->GetReferenceInfo();
- ref_info->SetHasIndexAliasing(true);
}
+ loc1->SetHasAliasedLocations(true);
+ loc2->SetHasAliasedLocations(true);
return true;
}
diff --git a/compiler/optimizing/load_store_elimination.cc b/compiler/optimizing/load_store_elimination.cc
index 8678fab..605fdae 100644
--- a/compiler/optimizing/load_store_elimination.cc
+++ b/compiler/optimizing/load_store_elimination.cc
@@ -384,8 +384,10 @@
if (Equal(heap_value, value)) {
// Store into the heap location with the same value.
same_value = true;
- } else if (index != nullptr && ref_info->HasIndexAliasing()) {
- // For array element, don't eliminate stores if the index can be aliased.
+ } else if (index != nullptr &&
+ heap_location_collector_.GetHeapLocation(idx)->HasAliasedLocations()) {
+ // For array element, don't eliminate stores if the location can be aliased
+ // (due to either ref or index aliasing).
} else if (ref_info->IsSingleton()) {
// Store into a field/element of a singleton. The value cannot be killed due to
// aliasing/invocation. It can be redundant since future loads can
diff --git a/compiler/optimizing/loop_optimization.cc b/compiler/optimizing/loop_optimization.cc
index 69c5827..fcc59ea 100644
--- a/compiler/optimizing/loop_optimization.cc
+++ b/compiler/optimizing/loop_optimization.cc
@@ -1512,17 +1512,17 @@
case DataType::Type::kBool:
case DataType::Type::kUint8:
case DataType::Type::kInt8:
- *restrictions |= kNoDiv | kNoReduction | kNoSAD;
+ *restrictions |= kNoDiv;
return TrySetVectorLength(16);
case DataType::Type::kUint16:
case DataType::Type::kInt16:
- *restrictions |= kNoDiv | kNoStringCharAt | kNoReduction | kNoSAD;
+ *restrictions |= kNoDiv | kNoStringCharAt;
return TrySetVectorLength(8);
case DataType::Type::kInt32:
- *restrictions |= kNoDiv | kNoSAD;
+ *restrictions |= kNoDiv;
return TrySetVectorLength(4);
case DataType::Type::kInt64:
- *restrictions |= kNoDiv | kNoSAD;
+ *restrictions |= kNoDiv;
return TrySetVectorLength(2);
case DataType::Type::kFloat32:
*restrictions |= kNoMinMax | kNoReduction; // min/max(x, NaN)
@@ -1541,17 +1541,17 @@
case DataType::Type::kBool:
case DataType::Type::kUint8:
case DataType::Type::kInt8:
- *restrictions |= kNoDiv | kNoReduction | kNoSAD;
+ *restrictions |= kNoDiv;
return TrySetVectorLength(16);
case DataType::Type::kUint16:
case DataType::Type::kInt16:
- *restrictions |= kNoDiv | kNoStringCharAt | kNoReduction | kNoSAD;
+ *restrictions |= kNoDiv | kNoStringCharAt;
return TrySetVectorLength(8);
case DataType::Type::kInt32:
- *restrictions |= kNoDiv | kNoSAD;
+ *restrictions |= kNoDiv;
return TrySetVectorLength(4);
case DataType::Type::kInt64:
- *restrictions |= kNoDiv | kNoSAD;
+ *restrictions |= kNoDiv;
return TrySetVectorLength(2);
case DataType::Type::kFloat32:
*restrictions |= kNoMinMax | kNoReduction; // min/max(x, NaN)
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 252d538..2bba985 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -1007,7 +1007,7 @@
if (method != nullptr) {
graph->SetArtMethod(method);
ScopedObjectAccess soa(Thread::Current());
- interpreter_metadata = method->GetQuickenedInfo(class_linker->GetImagePointerSize());
+ interpreter_metadata = method->GetQuickenedInfo();
}
std::unique_ptr<CodeGenerator> codegen(
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 9fa7f69..8137fb1 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -1565,7 +1565,7 @@
// 2) when we have a vdex file, which means it was already verified.
const bool verify = !DoDexLayoutOptimizations() && (input_vdex_file_ == nullptr);
if (!oat_writers_[i]->WriteAndOpenDexFiles(
- kIsVdexEnabled ? vdex_files_[i].get() : oat_files_[i].get(),
+ vdex_files_[i].get(),
rodata_.back(),
instruction_set_,
instruction_set_features_.get(),
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index afca26d..fdada8f 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -941,7 +941,7 @@
class_it.Next()) {
if (class_it.IsAtMethod() && class_it.GetMethodCodeItem() != nullptr) {
for (const DexInstructionPcPair& inst :
- class_it.GetMethodCodeItem()->Instructions()) {
+ class_it.GetMethodCodeItem()->Instructions()) {
ASSERT_FALSE(inst->IsQuickened());
}
}
@@ -1244,7 +1244,7 @@
ClassDataItemIterator it(*dex, dex->GetClassData(*class_def));
it.SkipAllFields();
std::set<size_t> code_item_offsets;
- for (; it.HasNextDirectMethod() || it.HasNextVirtualMethod(); it.Next()) {
+ for (; it.HasNextMethod(); it.Next()) {
const uint16_t method_idx = it.GetMemberIndex();
const size_t code_item_offset = it.GetMethodCodeItemOffset();
if (code_item_offsets.insert(code_item_offset).second) {
@@ -1356,7 +1356,7 @@
// corresponding code item offsets to verify the layout.
ClassDataItemIterator it(*dex_file, dex_file->GetClassData(*class_def));
it.SkipAllFields();
- for (; it.HasNextDirectMethod() || it.HasNextVirtualMethod(); it.Next()) {
+ for (; it.HasNextMethod(); it.Next()) {
const size_t method_idx = it.GetMemberIndex();
const size_t code_item_offset = it.GetMethodCodeItemOffset();
const bool is_hot = ContainsElement(hot_methods, method_idx);
@@ -1382,7 +1382,7 @@
// or this method is part of the last code item and the end is 4 byte aligned.
ClassDataItemIterator it2(*dex_file, dex_file->GetClassData(*class_def));
it2.SkipAllFields();
- for (; it2.HasNextDirectMethod() || it2.HasNextVirtualMethod(); it2.Next()) {
+ for (; it2.HasNextMethod(); it2.Next()) {
EXPECT_LE(it2.GetMethodCodeItemOffset(), code_item_offset);
}
uint32_t code_item_size = dex_file->FindCodeItemOffset(*class_def, method_idx);
diff --git a/dex2oat/linker/image_test.h b/dex2oat/linker/image_test.h
index d3d42b9..cedbccf 100644
--- a/dex2oat/linker/image_test.h
+++ b/dex2oat/linker/image_test.h
@@ -269,7 +269,7 @@
std::unique_ptr<MemMap> cur_opened_dex_files_map;
std::vector<std::unique_ptr<const DexFile>> cur_opened_dex_files;
bool dex_files_ok = oat_writers[i]->WriteAndOpenDexFiles(
- kIsVdexEnabled ? vdex_files[i].GetFile() : oat_files[i].GetFile(),
+ vdex_files[i].GetFile(),
rodata.back(),
driver->GetInstructionSet(),
driver->GetInstructionSetFeatures(),
@@ -293,14 +293,12 @@
bool image_space_ok = writer->PrepareImageAddressSpace();
ASSERT_TRUE(image_space_ok);
- if (kIsVdexEnabled) {
- for (size_t i = 0, size = vdex_files.size(); i != size; ++i) {
- std::unique_ptr<BufferedOutputStream> vdex_out =
- std::make_unique<BufferedOutputStream>(
- std::make_unique<FileOutputStream>(vdex_files[i].GetFile()));
- oat_writers[i]->WriteVerifierDeps(vdex_out.get(), nullptr);
- oat_writers[i]->WriteChecksumsAndVdexHeader(vdex_out.get());
- }
+ for (size_t i = 0, size = vdex_files.size(); i != size; ++i) {
+ std::unique_ptr<BufferedOutputStream> vdex_out =
+ std::make_unique<BufferedOutputStream>(
+ std::make_unique<FileOutputStream>(vdex_files[i].GetFile()));
+ oat_writers[i]->WriteVerifierDeps(vdex_out.get(), nullptr);
+ oat_writers[i]->WriteChecksumsAndVdexHeader(vdex_out.get());
}
for (size_t i = 0, size = oat_files.size(); i != size; ++i) {
diff --git a/dex2oat/linker/multi_oat_relative_patcher.h b/dex2oat/linker/multi_oat_relative_patcher.h
index 6683366..d97be8d 100644
--- a/dex2oat/linker/multi_oat_relative_patcher.h
+++ b/dex2oat/linker/multi_oat_relative_patcher.h
@@ -26,7 +26,6 @@
namespace art {
class CompiledMethod;
-class LinkerPatch;
class InstructionSetFeatures;
namespace linker {
diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc
index d8671d2..d3e920f 100644
--- a/dex2oat/linker/oat_writer.cc
+++ b/dex2oat/linker/oat_writer.cc
@@ -571,10 +571,9 @@
std::vector<std::unique_ptr<const DexFile>> dex_files;
// Initialize VDEX and OAT headers.
- if (kIsVdexEnabled) {
- // Reserve space for Vdex header and checksums.
- vdex_size_ = sizeof(VdexFile::Header) + oat_dex_files_.size() * sizeof(VdexFile::VdexChecksum);
- }
+
+ // Reserve space for Vdex header and checksums.
+ vdex_size_ = sizeof(VdexFile::Header) + oat_dex_files_.size() * sizeof(VdexFile::VdexChecksum);
oat_size_ = InitOatHeader(instruction_set,
instruction_set_features,
dchecked_integral_cast<uint32_t>(oat_dex_files_.size()),
@@ -582,28 +581,12 @@
ChecksumUpdatingOutputStream checksum_updating_rodata(oat_rodata, oat_header_.get());
- if (kIsVdexEnabled) {
- std::unique_ptr<BufferedOutputStream> vdex_out =
- std::make_unique<BufferedOutputStream>(std::make_unique<FileOutputStream>(vdex_file));
- // Write DEX files into VDEX, mmap and open them.
- if (!WriteDexFiles(vdex_out.get(), vdex_file, update_input_vdex) ||
- !OpenDexFiles(vdex_file, verify, &dex_files_map, &dex_files)) {
- return false;
- }
- } else {
- DCHECK(!update_input_vdex);
- // Write DEX files into OAT, mmap and open them.
- if (!WriteDexFiles(oat_rodata, vdex_file, update_input_vdex) ||
- !OpenDexFiles(vdex_file, verify, &dex_files_map, &dex_files)) {
- return false;
- }
-
- // Do a bulk checksum update for Dex[]. Doing it piece by piece would be
- // difficult because we're not using the OutputStream directly.
- if (!oat_dex_files_.empty()) {
- size_t size = oat_size_ - oat_dex_files_[0].dex_file_offset_;
- oat_header_->UpdateChecksum(dex_files_map->Begin(), size);
- }
+ std::unique_ptr<BufferedOutputStream> vdex_out =
+ std::make_unique<BufferedOutputStream>(std::make_unique<FileOutputStream>(vdex_file));
+ // Write DEX files into VDEX, mmap and open them.
+ if (!WriteDexFiles(vdex_out.get(), vdex_file, update_input_vdex) ||
+ !OpenDexFiles(vdex_file, verify, &dex_files_map, &dex_files)) {
+ return false;
}
// Write type lookup tables into the oat file.
@@ -755,13 +738,12 @@
};
static bool HasCompiledCode(const CompiledMethod* method) {
- // The dextodexcompiler puts the quickening info table into the CompiledMethod
- // for simplicity. For such methods, we will emit an OatQuickMethodHeader
- // only when vdex is disabled.
- return method != nullptr && (!method->GetQuickCode().empty() || !kIsVdexEnabled);
+ return method != nullptr && !method->GetQuickCode().empty();
}
static bool HasQuickeningInfo(const CompiledMethod* method) {
+ // The dextodexcompiler puts the quickening info table into the CompiledMethod
+ // for simplicity.
return method != nullptr && method->GetQuickCode().empty() && !method->GetVmapTable().empty();
}
@@ -1214,23 +1196,17 @@
// The code offset was 0 when the mapping/vmap table offset was set, so it's set
// to 0-offset and we need to adjust it by code_offset.
uint32_t code_offset = quick_code_offset - thumb_offset;
- if (!compiled_method->GetQuickCode().empty()) {
- // If the code is compiled, we write the offset of the stack map relative
- // to the code,
- if (vmap_table_offset != 0u) {
- vmap_table_offset += code_offset;
- DCHECK_LT(vmap_table_offset, code_offset);
- }
- if (method_info_offset != 0u) {
- method_info_offset += code_offset;
- DCHECK_LT(method_info_offset, code_offset);
- }
- } else {
- CHECK(!kIsVdexEnabled);
- // We write the offset of the quickening info relative to the code.
+ CHECK(!compiled_method->GetQuickCode().empty());
+ // If the code is compiled, we write the offset of the stack map relative
+ // to the code.
+ if (vmap_table_offset != 0u) {
vmap_table_offset += code_offset;
DCHECK_LT(vmap_table_offset, code_offset);
}
+ if (method_info_offset != 0u) {
+ method_info_offset += code_offset;
+ DCHECK_LT(method_info_offset, code_offset);
+ }
uint32_t frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
uint32_t core_spill_mask = compiled_method->GetCoreSpillMask();
uint32_t fp_spill_mask = compiled_method->GetFpSpillMask();
@@ -2126,20 +2102,14 @@
ClassDataItemIterator it(*dex_file, class_data);
it.SkipAllFields();
size_t class_def_method_index = 0u;
- while (it.HasNextDirectMethod()) {
+ while (it.HasNextMethod()) {
if (!visitor->VisitMethod(class_def_method_index, it)) {
return false;
}
++class_def_method_index;
it.Next();
}
- while (it.HasNextVirtualMethod()) {
- if (UNLIKELY(!visitor->VisitMethod(class_def_method_index, it))) {
- return false;
- }
- ++class_def_method_index;
- it.Next();
- }
+ DCHECK(!it.HasNext());
}
}
if (UNLIKELY(!visitor->EndClass())) {
@@ -2599,10 +2569,6 @@
};
bool OatWriter::WriteQuickeningInfo(OutputStream* vdex_out) {
- if (!kIsVdexEnabled) {
- return true;
- }
-
size_t initial_offset = vdex_size_;
size_t start_offset = RoundUp(initial_offset, 4u);
@@ -2661,10 +2627,6 @@
}
bool OatWriter::WriteVerifierDeps(OutputStream* vdex_out, verifier::VerifierDeps* verifier_deps) {
- if (!kIsVdexEnabled) {
- return true;
- }
-
if (verifier_deps == nullptr) {
// Nothing to write. Record the offset, but no need
// for alignment.
@@ -3176,23 +3138,17 @@
}
// Update current size and account for the written data.
- if (kIsVdexEnabled) {
- DCHECK_EQ(vdex_size_, oat_dex_file->dex_file_offset_);
- vdex_size_ += oat_dex_file->dex_file_size_;
- } else {
- DCHECK(!update_input_vdex);
- DCHECK_EQ(oat_size_, oat_dex_file->dex_file_offset_);
- oat_size_ += oat_dex_file->dex_file_size_;
- }
+ DCHECK_EQ(vdex_size_, oat_dex_file->dex_file_offset_);
+ vdex_size_ += oat_dex_file->dex_file_size_;
size_dex_file_ += oat_dex_file->dex_file_size_;
return true;
}
bool OatWriter::SeekToDexFile(OutputStream* out, File* file, OatDexFile* oat_dex_file) {
// Dex files are required to be 4 byte aligned.
- size_t initial_offset = kIsVdexEnabled ? vdex_size_ : oat_size_;
+ size_t initial_offset = vdex_size_;
size_t start_offset = RoundUp(initial_offset, 4);
- size_t file_offset = kIsVdexEnabled ? start_offset : (oat_data_offset_ + start_offset);
+ size_t file_offset = start_offset;
size_dex_file_alignment_ += start_offset - initial_offset;
// Seek to the start of the dex file and flush any pending operations in the stream.
@@ -3217,11 +3173,7 @@
return false;
}
- if (kIsVdexEnabled) {
- vdex_size_ = start_offset;
- } else {
- oat_size_ = start_offset;
- }
+ vdex_size_ = start_offset;
oat_dex_file->dex_file_offset_ = start_offset;
return true;
}
@@ -3297,7 +3249,7 @@
File* file,
OatDexFile* oat_dex_file,
ZipEntry* dex_file) {
- size_t start_offset = kIsVdexEnabled ? vdex_size_ : oat_data_offset_ + oat_size_;
+ size_t start_offset = vdex_size_;
DCHECK_EQ(static_cast<off_t>(start_offset), out->Seek(0, kSeekCurrent));
// Extract the dex file and get the extracted size.
@@ -3390,7 +3342,7 @@
File* file,
OatDexFile* oat_dex_file,
File* dex_file) {
- size_t start_offset = kIsVdexEnabled ? vdex_size_ : oat_data_offset_ + oat_size_;
+ size_t start_offset = vdex_size_;
DCHECK_EQ(static_cast<off_t>(start_offset), out->Seek(0, kSeekCurrent));
off_t input_offset = lseek(dex_file->Fd(), 0, SEEK_SET);
@@ -3486,7 +3438,7 @@
}
size_t map_offset = oat_dex_files_[0].dex_file_offset_;
- size_t length = kIsVdexEnabled ? (vdex_size_ - map_offset) : (oat_size_ - map_offset);
+ size_t length = vdex_size_ - map_offset;
std::string error_msg;
std::unique_ptr<MemMap> dex_files_map(MemMap::MapFile(
@@ -3494,7 +3446,7 @@
PROT_READ | PROT_WRITE,
MAP_SHARED,
file->Fd(),
- kIsVdexEnabled ? map_offset : (oat_data_offset_ + map_offset),
+ map_offset,
/* low_4gb */ false,
file->GetPath().c_str(),
&error_msg));
@@ -3698,9 +3650,6 @@
}
bool OatWriter::WriteChecksumsAndVdexHeader(OutputStream* vdex_out) {
- if (!kIsVdexEnabled) {
- return true;
- }
// Write checksums
off_t actual_offset = vdex_out->Seek(sizeof(VdexFile::Header), kSeekSet);
if (actual_offset != sizeof(VdexFile::Header)) {
diff --git a/dex2oat/linker/oat_writer_test.cc b/dex2oat/linker/oat_writer_test.cc
index 1ee2e4e..022aa1b 100644
--- a/dex2oat/linker/oat_writer_test.cc
+++ b/dex2oat/linker/oat_writer_test.cc
@@ -192,7 +192,7 @@
OutputStream* oat_rodata = elf_writer->StartRoData();
std::unique_ptr<MemMap> opened_dex_files_map;
std::vector<std::unique_ptr<const DexFile>> opened_dex_files;
- if (!oat_writer.WriteAndOpenDexFiles(kIsVdexEnabled ? vdex_file : oat_file,
+ if (!oat_writer.WriteAndOpenDexFiles(vdex_file,
oat_rodata,
compiler_driver_->GetInstructionSet(),
compiler_driver_->GetInstructionSetFeatures(),
@@ -224,15 +224,13 @@
oat_writer.GetBssMethodsOffset(),
oat_writer.GetBssRootsOffset());
- if (kIsVdexEnabled) {
- std::unique_ptr<BufferedOutputStream> vdex_out =
- std::make_unique<BufferedOutputStream>(std::make_unique<FileOutputStream>(vdex_file));
- if (!oat_writer.WriteVerifierDeps(vdex_out.get(), nullptr)) {
- return false;
- }
- if (!oat_writer.WriteChecksumsAndVdexHeader(vdex_out.get())) {
- return false;
- }
+ std::unique_ptr<BufferedOutputStream> vdex_out =
+ std::make_unique<BufferedOutputStream>(std::make_unique<FileOutputStream>(vdex_file));
+ if (!oat_writer.WriteVerifierDeps(vdex_out.get(), nullptr)) {
+ return false;
+ }
+ if (!oat_writer.WriteChecksumsAndVdexHeader(vdex_out.get())) {
+ return false;
}
if (!oat_writer.WriteRodata(oat_rodata)) {
diff --git a/dexdump/dexdump.cc b/dexdump/dexdump.cc
index 4bfd91f..84ccaa0 100644
--- a/dexdump/dexdump.cc
+++ b/dexdump/dexdump.cc
@@ -1391,18 +1391,12 @@
}
ClassDataItemIterator it(*dex_file, class_data);
it.SkipAllFields();
- while (it.HasNextDirectMethod()) {
+ while (it.HasNextMethod()) {
dumpCfg(dex_file,
it.GetMemberIndex(),
it.GetMethodCodeItem());
it.Next();
}
- while (it.HasNextVirtualMethod()) {
- dumpCfg(dex_file,
- it.GetMemberIndex(),
- it.GetMethodCodeItem());
- it.Next();
- }
}
/*
diff --git a/dexdump/dexdump_cfg.cc b/dexdump/dexdump_cfg.cc
index 2831707..62c970d 100644
--- a/dexdump/dexdump_cfg.cc
+++ b/dexdump/dexdump_cfg.cc
@@ -377,7 +377,7 @@
it.SkipAllFields();
// Find method, and dump it.
- while (it.HasNextDirectMethod() || it.HasNextVirtualMethod()) {
+ while (it.HasNextMethod()) {
uint32_t method_idx = it.GetMemberIndex();
if (method_idx == dex_method_idx) {
dumpMethodCFGImpl(dex_file, dex_method_idx, it.GetMethodCodeItem(), os);
diff --git a/dexlayout/Android.bp b/dexlayout/Android.bp
index fabe6e7..a02f75a 100644
--- a/dexlayout/Android.bp
+++ b/dexlayout/Android.bp
@@ -45,16 +45,34 @@
shared_libs: ["libartd"],
}
-art_cc_binary {
- name: "dexlayout",
+cc_defaults {
+ name: "dexlayout-defaults",
defaults: ["art_defaults"],
host_supported: true,
srcs: ["dexlayout_main.cc"],
- cflags: ["-Wall"],
+ shared_libs: [
+ "libbase",
+ ],
+}
+
+art_cc_binary {
+ name: "dexlayout",
+ defaults: ["dexlayout-defaults"],
shared_libs: [
"libart",
"libart-dexlayout",
- "libbase",
+ ],
+}
+
+art_cc_binary {
+ name: "dexlayoutd",
+ defaults: [
+ "art_debug_defaults",
+ "dexlayout-defaults",
+ ],
+ shared_libs: [
+ "libartd",
+ "libartd-dexlayout",
],
}
diff --git a/dexlayout/dexlayout_test.cc b/dexlayout/dexlayout_test.cc
index 0867305..c4f7acc 100644
--- a/dexlayout/dexlayout_test.cc
+++ b/dexlayout/dexlayout_test.cc
@@ -241,8 +241,8 @@
class DexLayoutTest : public CommonRuntimeTest {
protected:
- virtual void SetUp() {
- CommonRuntimeTest::SetUp();
+ std::string GetDexLayoutPath() {
+ return GetTestAndroidRoot() + "/bin/dexlayoutd";
}
// Runs FullPlainOutput test.
@@ -255,18 +255,16 @@
ScratchFile dexlayout_output;
const std::string& dexlayout_filename = dexlayout_output.GetFilename();
- std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout";
- EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
for (const std::string &dex_file : GetLibCoreDexFileNames()) {
std::vector<std::string> dexdump_exec_argv =
{ dexdump, "-d", "-f", "-h", "-l", "plain", "-o", dexdump_filename, dex_file };
- std::vector<std::string> dexlayout_exec_argv =
- { dexlayout, "-d", "-f", "-h", "-l", "plain", "-o", dexlayout_filename, dex_file };
+ std::vector<std::string> dexlayout_args =
+ { "-d", "-f", "-h", "-l", "plain", "-o", dexlayout_filename, dex_file };
if (!::art::Exec(dexdump_exec_argv, error_msg)) {
return false;
}
- if (!::art::Exec(dexlayout_exec_argv, error_msg)) {
+ if (!DexLayoutExec(dexlayout_args, error_msg)) {
return false;
}
std::vector<std::string> diff_exec_argv =
@@ -284,13 +282,11 @@
const std::string& tmp_name = tmp_file.GetFilename();
size_t tmp_last_slash = tmp_name.rfind('/');
std::string tmp_dir = tmp_name.substr(0, tmp_last_slash + 1);
- std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout";
- EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
for (const std::string &dex_file : GetLibCoreDexFileNames()) {
- std::vector<std::string> dexlayout_exec_argv =
- { dexlayout, "-w", tmp_dir, "-o", tmp_name, dex_file };
- if (!::art::Exec(dexlayout_exec_argv, error_msg)) {
+ std::vector<std::string> dexlayout_args =
+ { "-w", tmp_dir, "-o", tmp_name, dex_file };
+ if (!DexLayoutExec(dexlayout_args, error_msg)) {
return false;
}
size_t dex_file_last_slash = dex_file.rfind('/');
@@ -418,12 +414,9 @@
// WriteFileBase64(kDexFileLayoutInputProfile, profile_file.c_str());
std::string output_dex = tmp_dir + "classes.dex.new";
- std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout";
- EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
-
- std::vector<std::string> dexlayout_exec_argv =
- { dexlayout, "-v", "-w", tmp_dir, "-o", tmp_name, "-p", profile_file, dex_file };
- if (!::art::Exec(dexlayout_exec_argv, error_msg)) {
+ std::vector<std::string> dexlayout_args =
+ { "-v", "-w", tmp_dir, "-o", tmp_name, "-p", profile_file, dex_file };
+ if (!DexLayoutExec(dexlayout_args, error_msg)) {
return false;
}
@@ -466,13 +459,10 @@
std::string output_dex = tmp_dir + "classes.dex.new";
std::string second_output_dex = tmp_dir + "classes.dex.new.new";
- std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout";
- EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
-
// -v makes sure that the layout did not corrupt the dex file.
- std::vector<std::string> dexlayout_exec_argv =
- { dexlayout, "-i", "-v", "-w", tmp_dir, "-o", tmp_name, "-p", profile_file, dex_file };
- if (!::art::Exec(dexlayout_exec_argv, error_msg)) {
+ std::vector<std::string> dexlayout_args =
+ { "-i", "-v", "-w", tmp_dir, "-o", tmp_name, "-p", profile_file, dex_file };
+ if (!DexLayoutExec(dexlayout_args, error_msg)) {
return false;
}
@@ -482,9 +472,9 @@
// -v makes sure that the layout did not corrupt the dex file.
// -i since the checksum won't match from the first layout.
- std::vector<std::string> second_dexlayout_exec_argv =
- { dexlayout, "-i", "-v", "-w", tmp_dir, "-o", tmp_name, "-p", profile_file, output_dex };
- if (!::art::Exec(second_dexlayout_exec_argv, error_msg)) {
+ std::vector<std::string> second_dexlayout_args =
+ { "-i", "-v", "-w", tmp_dir, "-o", tmp_name, "-p", profile_file, output_dex };
+ if (!DexLayoutExec(second_dexlayout_args, error_msg)) {
return false;
}
@@ -516,12 +506,8 @@
WriteFileBase64(filename, input_dex.c_str());
std::string output_dex = tmp_dir + "classes.dex.new";
- std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout";
- EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
-
- std::vector<std::string> dexlayout_exec_argv =
- { dexlayout, "-w", tmp_dir, "-o", "/dev/null", input_dex };
- if (!::art::Exec(dexlayout_exec_argv, error_msg)) {
+ std::vector<std::string> dexlayout_args = { "-w", tmp_dir, "-o", "/dev/null", input_dex };
+ if (!DexLayoutExec(dexlayout_args, error_msg)) {
return false;
}
@@ -541,7 +527,7 @@
bool DexLayoutExec(ScratchFile* dex_file,
const char* dex_filename,
ScratchFile* profile_file,
- std::vector<std::string>& dexlayout_exec_argv) {
+ const std::vector<std::string>& dexlayout_args) {
if (dex_filename != nullptr) {
WriteBase64ToFile(dex_filename, dex_file->GetFile());
EXPECT_EQ(dex_file->GetFile()->Flush(), 0);
@@ -549,14 +535,27 @@
if (profile_file != nullptr) {
CreateProfile(dex_file->GetFilename(), profile_file->GetFilename(), dex_file->GetFilename());
}
+
std::string error_msg;
- const bool result = ::art::Exec(dexlayout_exec_argv, &error_msg);
+ const bool result = DexLayoutExec(dexlayout_args, &error_msg);
if (!result) {
LOG(ERROR) << "Error: " << error_msg;
return false;
}
return true;
}
+
+ bool DexLayoutExec(const std::vector<std::string>& dexlayout_args, std::string* error_msg) {
+ std::vector<std::string> argv;
+
+ std::string dexlayout = GetDexLayoutPath();
+ CHECK(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
+ argv.push_back(dexlayout);
+
+ argv.insert(argv.end(), dexlayout_args.begin(), dexlayout_args.end());
+
+ return ::art::Exec(argv, error_msg);
+ }
};
@@ -614,89 +613,72 @@
TEST_F(DexLayoutTest, DuplicateOffset) {
ScratchFile temp_dex;
- std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout";
- EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
- std::vector<std::string> dexlayout_exec_argv =
- { dexlayout, "-a", "-i", "-o", "/dev/null", temp_dex.GetFilename() };
+ std::vector<std::string> dexlayout_args =
+ { "-a", "-i", "-o", "/dev/null", temp_dex.GetFilename() };
ASSERT_TRUE(DexLayoutExec(&temp_dex,
kDexFileDuplicateOffset,
nullptr /* profile_file */,
- dexlayout_exec_argv));
+ dexlayout_args));
}
TEST_F(DexLayoutTest, NullSetRefListElement) {
ScratchFile temp_dex;
- std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout";
- EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
- std::vector<std::string> dexlayout_exec_argv =
- { dexlayout, "-o", "/dev/null", temp_dex.GetFilename() };
+ std::vector<std::string> dexlayout_args = { "-o", "/dev/null", temp_dex.GetFilename() };
ASSERT_TRUE(DexLayoutExec(&temp_dex,
kNullSetRefListElementInputDex,
nullptr /* profile_file */,
- dexlayout_exec_argv));
+ dexlayout_args));
}
TEST_F(DexLayoutTest, MultiClassData) {
ScratchFile temp_dex;
ScratchFile temp_profile;
- std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout";
- EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
- std::vector<std::string> dexlayout_exec_argv =
- { dexlayout, "-p", temp_profile.GetFilename(), "-o", "/dev/null", temp_dex.GetFilename() };
+ std::vector<std::string> dexlayout_args =
+ { "-p", temp_profile.GetFilename(), "-o", "/dev/null", temp_dex.GetFilename() };
ASSERT_TRUE(DexLayoutExec(&temp_dex,
kMultiClassDataInputDex,
&temp_profile,
- dexlayout_exec_argv));
+ dexlayout_args));
}
TEST_F(DexLayoutTest, UnalignedCodeInfo) {
ScratchFile temp_dex;
ScratchFile temp_profile;
- std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout";
- EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
- std::vector<std::string> dexlayout_exec_argv =
- { dexlayout, "-p", temp_profile.GetFilename(), "-o", "/dev/null", temp_dex.GetFilename() };
+ std::vector<std::string> dexlayout_args =
+ { "-p", temp_profile.GetFilename(), "-o", "/dev/null", temp_dex.GetFilename() };
ASSERT_TRUE(DexLayoutExec(&temp_dex,
kUnalignedCodeInfoInputDex,
&temp_profile,
- dexlayout_exec_argv));
+ dexlayout_args));
}
TEST_F(DexLayoutTest, ClassDataBeforeCode) {
ScratchFile temp_dex;
ScratchFile temp_profile;
- std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout";
- EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
- std::vector<std::string> dexlayout_exec_argv =
- { dexlayout, "-p", temp_profile.GetFilename(), "-o", "/dev/null", temp_dex.GetFilename() };
+ std::vector<std::string> dexlayout_args =
+ { "-p", temp_profile.GetFilename(), "-o", "/dev/null", temp_dex.GetFilename() };
ASSERT_TRUE(DexLayoutExec(&temp_dex,
kClassDataBeforeCodeInputDex,
&temp_profile,
- dexlayout_exec_argv));
+ dexlayout_args));
}
TEST_F(DexLayoutTest, UnknownTypeDebugInfo) {
ScratchFile temp_dex;
- std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout";
- EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
- std::vector<std::string> dexlayout_exec_argv =
- { dexlayout, "-o", "/dev/null", temp_dex.GetFilename() };
+ std::vector<std::string> dexlayout_args = { "-o", "/dev/null", temp_dex.GetFilename() };
ASSERT_TRUE(DexLayoutExec(&temp_dex,
kUnknownTypeDebugInfoInputDex,
nullptr /* profile_file */,
- dexlayout_exec_argv));
+ dexlayout_args));
}
TEST_F(DexLayoutTest, DuplicateCodeItem) {
ScratchFile temp_dex;
- std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout";
- EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
- std::vector<std::string> dexlayout_exec_argv =
- { dexlayout, "-o", "/dev/null", temp_dex.GetFilename() };
+ std::vector<std::string> dexlayout_args = { "-o", "/dev/null", temp_dex.GetFilename() };
ASSERT_TRUE(DexLayoutExec(&temp_dex,
kDuplicateCodeItemInputDex,
nullptr /* profile_file */,
- dexlayout_exec_argv));
+ dexlayout_args));
}
// Test that instructions that go past the end of the code items don't cause crashes.
@@ -713,7 +695,7 @@
}
ClassDataItemIterator it(*dex, data);
it.SkipAllFields();
- while (it.HasNextDirectMethod() || it.HasNextVirtualMethod()) {
+ while (it.HasNextMethod()) {
DexFile::CodeItem* item = const_cast<DexFile::CodeItem*>(it.GetMethodCodeItem());
if (item != nullptr) {
IterationRange<DexInstructionIterator> instructions = item->Instructions();
@@ -743,14 +725,11 @@
CHECK(mutated_successfully)
<< "Failed to find candidate code item with only one code unit in last instruction.";
});
- std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout";
- EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
- std::vector<std::string> dexlayout_exec_argv =
- { dexlayout, "-i", "-o", "/dev/null", temp_dex.GetFilename() };
+ std::vector<std::string> dexlayout_args = { "-i", "-o", "/dev/null", temp_dex.GetFilename() };
ASSERT_TRUE(DexLayoutExec(&temp_dex,
/*dex_filename*/ nullptr,
nullptr /* profile_file */,
- dexlayout_exec_argv));
+ dexlayout_args));
}
} // namespace art
diff --git a/dexlist/dexlist.cc b/dexlist/dexlist.cc
index c8bc132..e3ca59c 100644
--- a/dexlist/dexlist.cc
+++ b/dexlist/dexlist.cc
@@ -151,16 +151,8 @@
if (pEncodedData != nullptr) {
ClassDataItemIterator pClassData(*pDexFile, pEncodedData);
pClassData.SkipAllFields();
- // Direct methods.
- for (; pClassData.HasNextDirectMethod(); pClassData.Next()) {
- dumpMethod(pDexFile, fileName,
- pClassData.GetMemberIndex(),
- pClassData.GetRawMemberAccessFlags(),
- pClassData.GetMethodCodeItem(),
- pClassData.GetMethodCodeItemOffset());
- }
- // Virtual methods.
- for (; pClassData.HasNextVirtualMethod(); pClassData.Next()) {
+ // Direct and virtual methods.
+ for (; pClassData.HasNextMethod(); pClassData.Next()) {
dumpMethod(pDexFile, fileName,
pClassData.GetMemberIndex(),
pClassData.GetRawMemberAccessFlags(),
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index b20fa90..5a3d34c 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -36,6 +36,7 @@
#include "base/unix_file/fd_file.h"
#include "class_linker-inl.h"
#include "class_linker.h"
+#include "code_item_accessors-inl.h"
#include "compiled_method.h"
#include "debug/elf_debug_writer.h"
#include "debug/method_debug_info.h"
@@ -274,7 +275,7 @@
ClassDataItemIterator it(dex_file, class_data);
uint32_t class_method_idx = 0;
it.SkipAllFields();
- for (; it.HasNextDirectMethod() || it.HasNextVirtualMethod(); it.Next()) {
+ for (; it.HasNextMethod(); it.Next()) {
WalkOatMethod(oat_class.GetOatMethod(class_method_idx++),
dex_file,
class_def_index,
@@ -572,46 +573,36 @@
}
if (options_.export_dex_location_) {
- if (kIsVdexEnabled) {
- std::string error_msg;
- std::string vdex_filename = GetVdexFilename(oat_file_.GetLocation());
- if (!OS::FileExists(vdex_filename.c_str())) {
- os << "File " << vdex_filename.c_str() << " does not exist\n";
- return false;
- }
+ std::string error_msg;
+ std::string vdex_filename = GetVdexFilename(oat_file_.GetLocation());
+ if (!OS::FileExists(vdex_filename.c_str())) {
+ os << "File " << vdex_filename.c_str() << " does not exist\n";
+ return false;
+ }
- DexFileUniqV vdex_dex_files;
- std::unique_ptr<const VdexFile> vdex_file = OpenVdexUnquicken(vdex_filename,
- &vdex_dex_files,
- &error_msg);
- if (vdex_file.get() == nullptr) {
- os << "Failed to open vdex file: " << error_msg << "\n";
- return false;
- }
- if (oat_dex_files_.size() != vdex_dex_files.size()) {
- os << "Dex files number in Vdex file does not match Dex files number in Oat file: "
- << vdex_dex_files.size() << " vs " << oat_dex_files_.size() << '\n';
- return false;
- }
+ DexFileUniqV vdex_dex_files;
+ std::unique_ptr<const VdexFile> vdex_file = OpenVdexUnquicken(vdex_filename,
+ &vdex_dex_files,
+ &error_msg);
+ if (vdex_file.get() == nullptr) {
+ os << "Failed to open vdex file: " << error_msg << "\n";
+ return false;
+ }
+ if (oat_dex_files_.size() != vdex_dex_files.size()) {
+ os << "Dex files number in Vdex file does not match Dex files number in Oat file: "
+ << vdex_dex_files.size() << " vs " << oat_dex_files_.size() << '\n';
+ return false;
+ }
- size_t i = 0;
- for (const auto& vdex_dex_file : vdex_dex_files) {
- const OatFile::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())) {
- success = false;
- }
- i++;
+ size_t i = 0;
+ for (const auto& vdex_dex_file : vdex_dex_files) {
+ const OatFile::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())) {
+ success = false;
}
- } else {
- for (size_t i = 0; i < oat_dex_files_.size(); i++) {
- const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i];
- CHECK(oat_dex_file != nullptr);
- if (!ExportDexFile(os, *oat_dex_file, /* vdex_dex_file */ nullptr)) {
- success = false;
- }
- }
+ i++;
}
}
@@ -893,11 +884,7 @@
ClassDataItemIterator it(*dex_file, class_data);
it.SkipAllFields();
uint32_t class_method_index = 0;
- while (it.HasNextDirectMethod()) {
- AddOffsets(oat_class.GetOatMethod(class_method_index++));
- it.Next();
- }
- while (it.HasNextVirtualMethod()) {
+ while (it.HasNextMethod()) {
AddOffsets(oat_class.GetOatMethod(class_method_index++));
it.Next();
}
@@ -979,11 +966,7 @@
}
ClassDataItemIterator it(dex_file, class_data);
it.SkipAllFields();
- while (it.HasNextDirectMethod()) {
- WalkCodeItem(dex_file, it.GetMethodCodeItem());
- it.Next();
- }
- while (it.HasNextVirtualMethod()) {
+ while (it.HasNextMethod()) {
WalkCodeItem(dex_file, it.GetMethodCodeItem());
it.Next();
}
@@ -994,14 +977,15 @@
if (code_item == nullptr) {
return;
}
+ CodeItemInstructionAccessor instructions(&dex_file, code_item);
- const uint16_t* code_ptr = code_item->insns_;
// If we inserted a new dex code item pointer, add to total code bytes.
+ const uint16_t* code_ptr = instructions.Insns();
if (dex_code_item_ptrs_.insert(code_ptr).second) {
- dex_code_bytes_ += code_item->insns_size_in_code_units_ * sizeof(code_ptr[0]);
+ dex_code_bytes_ += instructions.InsnsSizeInCodeUnits() * sizeof(code_ptr[0]);
}
- for (const DexInstructionPcPair& inst : code_item->Instructions()) {
+ for (const DexInstructionPcPair& inst : instructions) {
switch (inst->Opcode()) {
case Instruction::CONST_STRING: {
const dex::StringIndex string_index(inst->VRegB_21c());
@@ -1227,20 +1211,7 @@
ClassDataItemIterator it(dex_file, class_data);
it.SkipAllFields();
uint32_t class_method_index = 0;
- while (it.HasNextDirectMethod()) {
- if (!DumpOatMethod(vios, class_def, class_method_index, oat_class, dex_file,
- it.GetMemberIndex(), it.GetMethodCodeItem(),
- it.GetRawMemberAccessFlags(), &addr_found)) {
- success = false;
- }
- if (addr_found) {
- *stop_analysis = true;
- return success;
- }
- class_method_index++;
- it.Next();
- }
- while (it.HasNextVirtualMethod()) {
+ while (it.HasNextMethod()) {
if (!DumpOatMethod(vios, class_def, class_method_index, oat_class, dex_file,
it.GetMemberIndex(), it.GetMethodCodeItem(),
it.GetRawMemberAccessFlags(), &addr_found)) {
@@ -1266,11 +1237,17 @@
bool DumpOatMethod(VariableIndentationOutputStream* vios,
const DexFile::ClassDef& class_def,
uint32_t class_method_index,
- const OatFile::OatClass& oat_class, const DexFile& dex_file,
- uint32_t dex_method_idx, const DexFile::CodeItem* code_item,
- uint32_t method_access_flags, bool* addr_found) {
+ const OatFile::OatClass& oat_class,
+ const DexFile& dex_file,
+ uint32_t dex_method_idx,
+ const DexFile::CodeItem* code_item,
+ uint32_t method_access_flags,
+ bool* addr_found) {
bool success = true;
+ CodeItemDataAccessor code_item_accessor(CodeItemDataAccessor::CreateNullable(&dex_file,
+ code_item));
+
// TODO: Support regex
std::string method_name = dex_file.GetMethodName(dex_file.GetMethodId(dex_method_idx));
if (method_name.find(options_.method_filter_) == std::string::npos) {
@@ -1281,7 +1258,9 @@
vios->Stream() << StringPrintf("%d: %s (dex_method_idx=%d)\n",
class_method_index, pretty_method.c_str(),
dex_method_idx);
- if (options_.list_methods_) return success;
+ if (options_.list_methods_) {
+ return success;
+ }
uint32_t oat_method_offsets_offset = oat_class.GetOatMethodOffsetsOffset(class_method_index);
const OatMethodOffsets* oat_method_offsets = oat_class.GetOatMethodOffsets(class_method_index);
@@ -1302,7 +1281,12 @@
{
vios->Stream() << "DEX CODE:\n";
ScopedIndentation indent2(vios);
- DumpDexCode(vios->Stream(), dex_file, code_item);
+ if (code_item_accessor.HasCodeItem()) {
+ for (const DexInstructionPcPair& inst : code_item_accessor) {
+ vios->Stream() << StringPrintf("0x%04x: ", inst.DexPc()) << inst->DumpHexLE(5)
+ << StringPrintf("\t| %s\n", inst->DumpString(&dex_file).c_str());
+ }
+ }
}
std::unique_ptr<StackHandleScope<1>> hs;
@@ -1373,7 +1357,7 @@
vios->Stream() << StringPrintf("(offset=0x%08x)\n", vmap_table_offset);
size_t vmap_table_offset_limit =
- (kIsVdexEnabled && IsMethodGeneratedByDexToDexCompiler(oat_method, code_item))
+ IsMethodGeneratedByDexToDexCompiler(oat_method, code_item_accessor)
? oat_file_.GetVdexFile()->Size()
: method_header->GetCode() - oat_file_.Begin();
if (vmap_table_offset >= vmap_table_offset_limit) {
@@ -1385,7 +1369,7 @@
oat_method.GetVmapTableOffsetOffset());
success = false;
} else if (options_.dump_vmap_) {
- DumpVmapData(vios, oat_method, code_item);
+ DumpVmapData(vios, oat_method, code_item_accessor);
}
}
{
@@ -1406,7 +1390,7 @@
// after it is dumped, but useful for understanding quick
// code, so dumped here.
ScopedIndentation indent2(vios);
- DumpVregLocations(vios->Stream(), oat_method, code_item);
+ DumpVregLocations(vios->Stream(), oat_method, code_item_accessor);
}
{
vios->Stream() << "CODE: ";
@@ -1448,7 +1432,7 @@
success = false;
if (options_.disassemble_code_) {
if (code_size_offset + kPrologueBytes <= oat_file_.Size()) {
- DumpCode(vios, oat_method, code_item, true, kPrologueBytes);
+ DumpCode(vios, oat_method, code_item_accessor, true, kPrologueBytes);
}
}
} else if (code_size > kMaxCodeSize) {
@@ -1461,11 +1445,11 @@
success = false;
if (options_.disassemble_code_) {
if (code_size_offset + kPrologueBytes <= oat_file_.Size()) {
- DumpCode(vios, oat_method, code_item, true, kPrologueBytes);
+ DumpCode(vios, oat_method, code_item_accessor, true, kPrologueBytes);
}
}
} else if (options_.disassemble_code_) {
- DumpCode(vios, oat_method, code_item, !success, 0);
+ DumpCode(vios, oat_method, code_item_accessor, !success, 0);
}
}
}
@@ -1499,18 +1483,18 @@
// Display data stored at the the vmap offset of an oat method.
void DumpVmapData(VariableIndentationOutputStream* vios,
const OatFile::OatMethod& oat_method,
- const DexFile::CodeItem* code_item) {
- if (IsMethodGeneratedByOptimizingCompiler(oat_method, code_item)) {
+ const CodeItemDataAccessor& code_item_accessor) {
+ if (IsMethodGeneratedByOptimizingCompiler(oat_method, code_item_accessor)) {
// The optimizing compiler outputs its CodeInfo data in the vmap table.
const void* raw_code_info = oat_method.GetVmapTable();
if (raw_code_info != nullptr) {
CodeInfo code_info(raw_code_info);
- DCHECK(code_item != nullptr);
+ DCHECK(code_item_accessor.HasCodeItem());
ScopedIndentation indent1(vios);
MethodInfo method_info = oat_method.GetOatQuickMethodHeader()->GetOptimizedMethodInfo();
- DumpCodeInfo(vios, code_info, oat_method, *code_item, method_info);
+ DumpCodeInfo(vios, code_info, oat_method, code_item_accessor, method_info);
}
- } else if (IsMethodGeneratedByDexToDexCompiler(oat_method, code_item)) {
+ } else if (IsMethodGeneratedByDexToDexCompiler(oat_method, code_item_accessor)) {
// We don't encode the size in the table, so just emit that we have quickened
// information.
ScopedIndentation indent(vios);
@@ -1524,11 +1508,11 @@
void DumpCodeInfo(VariableIndentationOutputStream* vios,
const CodeInfo& code_info,
const OatFile::OatMethod& oat_method,
- const DexFile::CodeItem& code_item,
+ const CodeItemDataAccessor& code_item_accessor,
const MethodInfo& method_info) {
code_info.Dump(vios,
oat_method.GetCodeOffset(),
- code_item.registers_size_,
+ code_item_accessor.RegistersSize(),
options_.dump_code_info_stack_maps_,
instruction_set_,
method_info);
@@ -1539,7 +1523,7 @@
return static_cast<size_t>(InstructionSetPointerSize(isa)) + out_num * sizeof(uint32_t);
}
- static uint32_t GetVRegOffsetFromQuickCode(const DexFile::CodeItem* code_item,
+ static uint32_t GetVRegOffsetFromQuickCode(const CodeItemDataAccessor& code_item_accessor,
uint32_t core_spills,
uint32_t fp_spills,
size_t frame_size,
@@ -1557,8 +1541,8 @@
int spill_size = POPCOUNT(core_spills) * GetBytesPerGprSpillLocation(isa)
+ POPCOUNT(fp_spills) * GetBytesPerFprSpillLocation(isa)
+ sizeof(uint32_t); // Filler.
- int num_regs = code_item->registers_size_ - code_item->ins_size_;
- int temp_threshold = code_item->registers_size_;
+ int num_regs = code_item_accessor.RegistersSize() - code_item_accessor.InsSize();
+ int temp_threshold = code_item_accessor.RegistersSize();
const int max_num_special_temps = 1;
if (reg == temp_threshold) {
// The current method pointer corresponds to special location on stack.
@@ -1568,7 +1552,7 @@
* Special temporaries may have custom locations and the logic above deals with that.
* However, non-special temporaries are placed relative to the outs.
*/
- int temps_start = code_item->outs_size_ * sizeof(uint32_t)
+ int temps_start = code_item_accessor.OutsSize() * sizeof(uint32_t)
+ static_cast<size_t>(pointer_size) /* art method */;
int relative_offset = (reg - (temp_threshold + max_num_special_temps)) * sizeof(uint32_t);
return temps_start + relative_offset;
@@ -1583,12 +1567,12 @@
}
void DumpVregLocations(std::ostream& os, const OatFile::OatMethod& oat_method,
- const DexFile::CodeItem* code_item) {
- if (code_item != nullptr) {
- size_t num_locals_ins = code_item->registers_size_;
- size_t num_ins = code_item->ins_size_;
+ const CodeItemDataAccessor& code_item_accessor) {
+ if (code_item_accessor.HasCodeItem()) {
+ size_t num_locals_ins = code_item_accessor.RegistersSize();
+ size_t num_ins = code_item_accessor.InsSize();
size_t num_locals = num_locals_ins - num_ins;
- size_t num_outs = code_item->outs_size_;
+ size_t num_outs = code_item_accessor.OutsSize();
os << "vr_stack_locations:";
for (size_t reg = 0; reg <= num_locals_ins; reg++) {
@@ -1601,7 +1585,7 @@
os << "\n\tlocals:";
}
- uint32_t offset = GetVRegOffsetFromQuickCode(code_item,
+ uint32_t offset = GetVRegOffsetFromQuickCode(code_item_accessor,
oat_method.GetCoreSpillMask(),
oat_method.GetFpSpillMask(),
oat_method.GetFrameSizeInBytes(),
@@ -1623,37 +1607,30 @@
}
}
- void DumpDexCode(std::ostream& os, const DexFile& dex_file, const DexFile::CodeItem* code_item) {
- if (code_item != nullptr) {
- for (const DexInstructionPcPair& inst : code_item->Instructions()) {
- os << StringPrintf("0x%04x: ", inst.DexPc()) << inst->DumpHexLE(5)
- << StringPrintf("\t| %s\n", inst->DumpString(&dex_file).c_str());
- }
- }
- }
-
// Has `oat_method` -- corresponding to the Dex `code_item` -- been compiled by
// the optimizing compiler?
- static bool IsMethodGeneratedByOptimizingCompiler(const OatFile::OatMethod& oat_method,
- const DexFile::CodeItem* code_item) {
+ static bool IsMethodGeneratedByOptimizingCompiler(
+ const OatFile::OatMethod& oat_method,
+ const CodeItemDataAccessor& code_item_accessor) {
// If the native GC map is null and the Dex `code_item` is not
// null, then this method has been compiled with the optimizing
// compiler.
return oat_method.GetQuickCode() != nullptr &&
oat_method.GetVmapTable() != nullptr &&
- code_item != nullptr;
+ code_item_accessor.HasCodeItem();
}
// Has `oat_method` -- corresponding to the Dex `code_item` -- been compiled by
// the dextodex compiler?
- static bool IsMethodGeneratedByDexToDexCompiler(const OatFile::OatMethod& oat_method,
- const DexFile::CodeItem* code_item) {
+ static bool IsMethodGeneratedByDexToDexCompiler(
+ const OatFile::OatMethod& oat_method,
+ const CodeItemDataAccessor& code_item_accessor) {
// If the quick code is null, the Dex `code_item` is not
// null, and the vmap table is not null, then this method has been compiled
// with the dextodex compiler.
return oat_method.GetQuickCode() == nullptr &&
oat_method.GetVmapTable() != nullptr &&
- code_item != nullptr;
+ code_item_accessor.HasCodeItem();
}
verifier::MethodVerifier* DumpVerifier(VariableIndentationOutputStream* vios,
@@ -1770,7 +1747,8 @@
};
void DumpCode(VariableIndentationOutputStream* vios,
- const OatFile::OatMethod& oat_method, const DexFile::CodeItem* code_item,
+ const OatFile::OatMethod& oat_method,
+ const CodeItemDataAccessor& code_item_accessor,
bool bad_input, size_t code_size) {
const void* quick_code = oat_method.GetQuickCode();
@@ -1780,7 +1758,8 @@
if (code_size == 0 || quick_code == nullptr) {
vios->Stream() << "NO CODE!\n";
return;
- } else if (!bad_input && IsMethodGeneratedByOptimizingCompiler(oat_method, code_item)) {
+ } else if (!bad_input && IsMethodGeneratedByOptimizingCompiler(oat_method,
+ code_item_accessor)) {
// The optimizing compiler outputs its CodeInfo data in the vmap table.
StackMapsHelper helper(oat_method.GetVmapTable(), instruction_set_);
MethodInfo method_info(oat_method.GetOatQuickMethodHeader()->GetOptimizedMethodInfo());
@@ -1835,7 +1814,8 @@
kBitsPerByte * location_catalog_bytes);
// Dex register bytes.
const size_t dex_register_bytes =
- helper.GetCodeInfo().GetDexRegisterMapsSize(encoding, code_item->registers_size_);
+ helper.GetCodeInfo().GetDexRegisterMapsSize(encoding,
+ code_item_accessor.RegistersSize());
stats_.AddBits(
Stats::kByteKindCodeInfoDexRegisterMap,
kBitsPerByte * dex_register_bytes);
@@ -1874,7 +1854,7 @@
helper.GetEncoding(),
method_info,
oat_method.GetCodeOffset(),
- code_item->registers_size_,
+ code_item_accessor.RegistersSize(),
instruction_set_);
do {
helper.Next();
@@ -2502,8 +2482,8 @@
}
}
} else {
- const DexFile::CodeItem* code_item = method->GetCodeItem();
- size_t dex_instruction_bytes = code_item->insns_size_in_code_units_ * 2;
+ CodeItemDataAccessor code_item_accessor(method);
+ size_t dex_instruction_bytes = code_item_accessor.InsnsSizeInCodeUnits() * 2;
stats_.dex_instruction_bytes += dex_instruction_bytes;
bool first_occurrence;
diff --git a/openjdkjvmti/ti_redefine.cc b/openjdkjvmti/ti_redefine.cc
index dcc237d..5b125f6 100644
--- a/openjdkjvmti/ti_redefine.cc
+++ b/openjdkjvmti/ti_redefine.cc
@@ -610,7 +610,7 @@
// Check each of the methods. NB we don't need to specifically check for removals since the 2 dex
// files have the same number of methods, which means there must be an equal amount of additions
// and removals.
- for (; new_iter.HasNextVirtualMethod() || new_iter.HasNextDirectMethod(); new_iter.Next()) {
+ for (; new_iter.HasNextMethod(); new_iter.Next()) {
// Get the data on the method we are searching for
const art::DexFile::MethodId& new_method_id = dex_file_->GetMethodId(new_iter.GetMemberIndex());
const char* new_method_name = dex_file_->GetMethodName(new_method_id);
diff --git a/openjdkjvmti/ti_thread.cc b/openjdkjvmti/ti_thread.cc
index 6d075a6..b7b81ce 100644
--- a/openjdkjvmti/ti_thread.cc
+++ b/openjdkjvmti/ti_thread.cc
@@ -47,6 +47,7 @@
#include "mirror/object-inl.h"
#include "mirror/string.h"
#include "nativehelper/scoped_local_ref.h"
+#include "nativehelper/scoped_utf_chars.h"
#include "obj_ptr.h"
#include "runtime.h"
#include "runtime_callbacks.h"
@@ -701,6 +702,7 @@
JavaVM* java_vm;
jvmtiEnv* jvmti_env;
jint priority;
+ std::string name;
};
static void* AgentCallback(void* arg) {
@@ -708,13 +710,13 @@
CHECK(data->thread != nullptr);
// We already have a peer. So call our special Attach function.
- art::Thread* self = art::Thread::Attach("JVMTI Agent thread", true, data->thread);
+ art::Thread* self = art::Thread::Attach(data->name.c_str(), true, data->thread);
CHECK(self != nullptr) << "threads_being_born_ should have ensured thread could be attached.";
// The name in Attach() is only for logging. Set the thread name. This is important so
// that the thread is no longer seen as starting up.
{
art::ScopedObjectAccess soa(self);
- self->SetThreadName("JVMTI Agent thread");
+ self->SetThreadName(data->name.c_str());
}
// Release the peer.
@@ -781,6 +783,16 @@
data->java_vm = art::Runtime::Current()->GetJavaVM();
data->jvmti_env = jvmti_env;
data->priority = priority;
+ ScopedLocalRef<jstring> s(
+ env,
+ reinterpret_cast<jstring>(
+ env->GetObjectField(thread, art::WellKnownClasses::java_lang_Thread_name)));
+ if (s == nullptr) {
+ data->name = "JVMTI Agent Thread";
+ } else {
+ ScopedUtfChars name(env, s.get());
+ data->name = name.c_str();
+ }
pthread_t pthread;
int pthread_create_result = pthread_create(&pthread,
diff --git a/profman/boot_image_profile.cc b/profman/boot_image_profile.cc
index e5645d3..48b87c9 100644
--- a/profman/boot_image_profile.cc
+++ b/profman/boot_image_profile.cc
@@ -90,7 +90,7 @@
it.Next();
}
it.SkipInstanceFields();
- while (it.HasNextDirectMethod() || it.HasNextVirtualMethod()) {
+ while (it.HasNextMethod()) {
const uint32_t flags = it.GetMethodAccessFlags();
if ((flags & kAccNative) != 0) {
// Native method will get dirtied.
diff --git a/profman/profman.cc b/profman/profman.cc
index 1c50645..31d28e4 100644
--- a/profman/profman.cc
+++ b/profman/profman.cc
@@ -810,7 +810,7 @@
if (class_data != nullptr) {
ClassDataItemIterator it(*dex_file, class_data);
it.SkipAllFields();
- while (it.HasNextDirectMethod() || it.HasNextVirtualMethod()) {
+ while (it.HasNextMethod()) {
if (it.GetMethodCodeItemOffset() != 0) {
// Add all of the methods that have code to the profile.
const uint32_t method_idx = it.GetMemberIndex();
diff --git a/runtime/Android.bp b/runtime/Android.bp
index e032238..69e4434 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -567,6 +567,7 @@
"class_linker_test.cc",
"class_loader_context_test.cc",
"class_table_test.cc",
+ "code_item_accessors_test.cc",
"compiler_filter_test.cc",
"dex_file_test.cc",
"dex_file_verifier_test.cc",
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index e1671c9..50913de 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -23,6 +23,7 @@
#include "base/callee_save_type.h"
#include "base/logging.h"
#include "class_linker-inl.h"
+#include "code_item_accessors-inl.h"
#include "common_throws.h"
#include "dex_file-inl.h"
#include "dex_file_annotations.h"
@@ -459,6 +460,18 @@
}
}
+inline IterationRange<DexInstructionIterator> ArtMethod::DexInstructions() {
+ CodeItemInstructionAccessor accessor(this);
+ return { accessor.begin(),
+ accessor.end() };
+}
+
+inline IterationRange<DexInstructionIterator> ArtMethod::NullableDexInstructions() {
+ CodeItemInstructionAccessor accessor(CodeItemInstructionAccessor::CreateNullable(this));
+ return { accessor.begin(),
+ accessor.end() };
+}
+
} // namespace art
#endif // ART_RUNTIME_ART_METHOD_INL_H_
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index 0a108f9..fa0c501 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -563,23 +563,14 @@
return true;
}
-const uint8_t* ArtMethod::GetQuickenedInfo(PointerSize pointer_size) {
- if (kIsVdexEnabled) {
- const DexFile& dex_file = GetDeclaringClass()->GetDexFile();
- const OatFile::OatDexFile* oat_dex_file = dex_file.GetOatDexFile();
- if (oat_dex_file == nullptr || (oat_dex_file->GetOatFile() == nullptr)) {
- return nullptr;
- }
- return oat_dex_file->GetOatFile()->GetVdexFile()->GetQuickenedInfoOf(
- dex_file, GetCodeItemOffset());
- } else {
- bool found = false;
- OatFile::OatMethod oat_method = FindOatMethodFor(this, pointer_size, &found);
- if (!found || (oat_method.GetQuickCode() != nullptr)) {
- return nullptr;
- }
- return oat_method.GetVmapTable();
+const uint8_t* ArtMethod::GetQuickenedInfo() {
+ const DexFile& dex_file = GetDeclaringClass()->GetDexFile();
+ const OatFile::OatDexFile* oat_dex_file = dex_file.GetOatDexFile();
+ if (oat_dex_file == nullptr || (oat_dex_file->GetOatFile() == nullptr)) {
+ return nullptr;
}
+ return oat_dex_file->GetOatFile()->GetVdexFile()->GetQuickenedInfoOf(
+ dex_file, GetCodeItemOffset());
}
const OatQuickMethodHeader* ArtMethod::GetOatQuickMethodHeader(uintptr_t pc) {
diff --git a/runtime/art_method.h b/runtime/art_method.h
index 0e98d47..dca6f37 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -22,8 +22,10 @@
#include "base/bit_utils.h"
#include "base/casts.h"
#include "base/enums.h"
+#include "base/iteration_range.h"
#include "base/logging.h"
#include "dex_file.h"
+#include "dex_instruction_iterator.h"
#include "gc_root.h"
#include "modifiers.h"
#include "obj_ptr.h"
@@ -462,7 +464,7 @@
// where the declaring class is treated as a weak reference (accessing it with
// a read barrier would either prevent unloading the class, or crash the runtime if
// the GC wants to unload it).
- DCHECK(!IsNative());
+ DCHECK(!IsNative<kWithoutReadBarrier>());
if (UNLIKELY(IsProxyMethod())) {
return nullptr;
}
@@ -655,7 +657,7 @@
return hotness_count_;
}
- const uint8_t* GetQuickenedInfo(PointerSize pointer_size) REQUIRES_SHARED(Locks::mutator_lock_);
+ const uint8_t* GetQuickenedInfo() REQUIRES_SHARED(Locks::mutator_lock_);
// Returns the method header for the compiled code containing 'pc'. Note that runtime
// methods will return null for this method, as they are not oat based.
@@ -710,6 +712,15 @@
"ptr_sized_fields_.entry_point_from_quick_compiled_code_");
}
+ // Returns the dex instructions of the code item for the art method. Must not be called on null
+ // code items.
+ ALWAYS_INLINE IterationRange<DexInstructionIterator> DexInstructions()
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
+ // Handles a null code item by returning iterators that have a null address.
+ ALWAYS_INLINE IterationRange<DexInstructionIterator> NullableDexInstructions()
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
protected:
// Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
// The class we are a part of.
diff --git a/runtime/base/casts.h b/runtime/base/casts.h
index 0cbabba..92c493a 100644
--- a/runtime/base/casts.h
+++ b/runtime/base/casts.h
@@ -77,6 +77,14 @@
return static_cast<To>(f);
}
+template<typename To, typename From> // use like this: down_cast<T&>(foo);
+inline To down_cast(From& f) { // so we only accept references
+ static_assert(std::is_base_of<From, typename std::remove_reference<To>::type>::value,
+ "down_cast unsafe as To is not a subtype of From");
+
+ return static_cast<To>(f);
+}
+
template <class Dest, class Source>
inline Dest bit_cast(const Source& source) {
// Compile time assertion: sizeof(Dest) == sizeof(Source)
diff --git a/runtime/cdex/compact_dex_file.h b/runtime/cdex/compact_dex_file.h
index 8ab9247..f17f8cf 100644
--- a/runtime/cdex/compact_dex_file.h
+++ b/runtime/cdex/compact_dex_file.h
@@ -24,11 +24,18 @@
// CompactDex is a currently ART internal dex file format that aims to reduce storage/RAM usage.
class CompactDexFile : public DexFile {
public:
+ static constexpr uint8_t kDexMagic[kDexMagicSize] = { 'c', 'd', 'e', 'x' };
+ static constexpr uint8_t kDexMagicVersion[] = {'0', '0', '1', '\0'};
+
class Header : public DexFile::Header {
// Same for now.
};
- static constexpr uint8_t kDexMagic[kDexMagicSize] = { 'c', 'd', 'e', 'x' };
- static constexpr uint8_t kDexMagicVersion[] = {'0', '0', '1', '\0'};
+
+ struct CodeItem : public DexFile::CodeItem {
+ private:
+ // TODO: Insert compact dex specific fields here.
+ DISALLOW_COPY_AND_ASSIGN(CodeItem);
+ };
// Write the compact dex specific magic.
static void WriteMagic(uint8_t* magic);
@@ -44,10 +51,6 @@
static bool IsVersionValid(const uint8_t* magic);
virtual bool IsVersionValid() const OVERRIDE;
- bool IsCompactDexFile() const OVERRIDE {
- return true;
- }
-
private:
// Not supported yet.
CompactDexFile(const uint8_t* base,
@@ -56,7 +59,13 @@
uint32_t location_checksum,
const OatDexFile* oat_dex_file,
DexFileContainer* container)
- : DexFile(base, size, location, location_checksum, oat_dex_file, container) {}
+ : DexFile(base,
+ size,
+ location,
+ location_checksum,
+ oat_dex_file,
+ container,
+ /*is_compact_dex*/ true) {}
friend class DexFile;
friend class DexFileLoader;
diff --git a/runtime/class_loader_context.cc b/runtime/class_loader_context.cc
index 38f59ef..54e7558 100644
--- a/runtime/class_loader_context.cc
+++ b/runtime/class_loader_context.cc
@@ -16,9 +16,6 @@
#include "class_loader_context.h"
-#include <stdlib.h>
-
-#include "android-base/file.h"
#include "art_field-inl.h"
#include "base/dchecked_vector.h"
#include "base/stl_util.h"
@@ -210,19 +207,9 @@
size_t opened_dex_files_index = info.opened_dex_files.size();
for (const std::string& cp_elem : info.classpath) {
// If path is relative, append it to the provided base directory.
- std::string raw_location = cp_elem;
- if (raw_location[0] != '/' && !classpath_dir.empty()) {
- raw_location = classpath_dir + '/' + raw_location;
- }
-
- std::string location; // the real location of the class path element.
-
- if (!android::base::Realpath(raw_location, &location)) {
- // If we can't get the realpath of the location there might be something wrong with the
- // classpath (maybe the file was deleted).
- // Do not continue in this case and return false.
- PLOG(WARNING) << "Could not get the realpath of dex location " << raw_location;
- return false;
+ std::string location = cp_elem;
+ if (location[0] != '/' && !classpath_dir.empty()) {
+ location = classpath_dir + (classpath_dir.back() == '/' ? "" : "/") + location;
}
std::string error_msg;
@@ -728,15 +715,20 @@
dex_name = info.classpath[k];
expected_dex_name = OatFile::ResolveRelativeEncodedDexLocation(
info.classpath[k].c_str(), expected_info.classpath[k]);
- } else {
+ } else if (is_expected_dex_name_absolute) {
// The runtime name is relative but the compiled name is absolute.
// There is no expected use case that would end up here as dex files are always loaded
// with their absolute location. However, be tolerant and do the best effort (in case
// there are unexpected new use case...).
- DCHECK(is_expected_dex_name_absolute);
dex_name = OatFile::ResolveRelativeEncodedDexLocation(
expected_info.classpath[k].c_str(), info.classpath[k]);
expected_dex_name = expected_info.classpath[k];
+ } else {
+ // Both locations are relative. In this case there's not much we can be sure about
+ // except that the names are the same. The checksum will ensure that the files are
+ // are same. This should not happen outside testing and manual invocations.
+ dex_name = info.classpath[k];
+ expected_dex_name = expected_info.classpath[k];
}
// Compare the locations.
diff --git a/runtime/class_loader_context_test.cc b/runtime/class_loader_context_test.cc
index be6acde..fc3446c 100644
--- a/runtime/class_loader_context_test.cc
+++ b/runtime/class_loader_context_test.cc
@@ -17,17 +17,13 @@
#include "class_loader_context.h"
#include <gtest/gtest.h>
-#include <stdlib.h>
#include "android-base/strings.h"
-
#include "base/dchecked_vector.h"
#include "base/stl_util.h"
-#include "class_loader_context.h"
#include "class_linker.h"
#include "common_runtime_test.h"
#include "dex_file.h"
-#include "dex2oat_environment_test.h"
#include "handle_scope-inl.h"
#include "mirror/class.h"
#include "mirror/class_loader.h"
@@ -84,6 +80,10 @@
kEndsWith
};
+ static bool IsAbsoluteLocation(const std::string& location) {
+ return !location.empty() && location[0] == '/';
+ }
+
void VerifyOpenDexFiles(
ClassLoaderContext* context,
size_t index,
@@ -100,17 +100,22 @@
info.opened_dex_files[cur_open_dex_index++];
std::unique_ptr<const DexFile>& expected_dex_file = (*all_dex_files)[k];
- std::string expected_location =
- DexFileLoader::GetBaseLocation(expected_dex_file->GetLocation());
- UniqueCPtr<const char[]> expected_real_location(
- realpath(expected_location.c_str(), nullptr));
- ASSERT_TRUE(expected_real_location != nullptr) << expected_location;
- expected_location.assign(expected_real_location.get());
- expected_location += DexFileLoader::GetMultiDexSuffix(expected_dex_file->GetLocation());
+ std::string expected_location = expected_dex_file->GetLocation();
- ASSERT_EQ(expected_location, opened_dex_file->GetLocation());
+ const std::string& opened_location = opened_dex_file->GetLocation();
+ if (!IsAbsoluteLocation(opened_location)) {
+ // If the opened location is relative (it was open from a relative path without a
+ // classpath_dir) it might not match the expected location which is absolute in tests).
+ // So we compare the endings (the checksum will validate it's actually the same file).
+ ASSERT_EQ(0, expected_location.compare(
+ expected_location.length() - opened_location.length(),
+ opened_location.length(),
+ opened_location));
+ } else {
+ ASSERT_EQ(expected_location, opened_location);
+ }
ASSERT_EQ(expected_dex_file->GetLocationChecksum(), opened_dex_file->GetLocationChecksum());
- ASSERT_EQ(info.classpath[k], opened_dex_file->GetLocation());
+ ASSERT_EQ(info.classpath[k], opened_location);
}
}
@@ -252,6 +257,7 @@
std::string myclass_dex_name = GetTestDexFileName("MyClass");
std::string dex_name = GetTestDexFileName("Main");
+
std::unique_ptr<ClassLoaderContext> context =
ClassLoaderContext::Create(
"PCL[" + multidex_name + ":" + myclass_dex_name + "];" +
@@ -272,42 +278,6 @@
VerifyOpenDexFiles(context.get(), 1, &all_dex_files1);
}
-class ScratchSymLink {
- public:
- explicit ScratchSymLink(const std::string& file) {
- // Use a temporary scratch file to get a unique name for the link.
- ScratchFile scratchFile;
- scratch_link_name_ = scratchFile.GetFilename() + ".link.jar";
- CHECK_EQ(0, symlink(file.c_str(), scratch_link_name_.c_str()));
- }
-
- ~ScratchSymLink() {
- CHECK_EQ(0, unlink(scratch_link_name_.c_str()));
- }
-
- const std::string& GetFilename() { return scratch_link_name_; }
-
- private:
- std::string scratch_link_name_;
-};
-
-TEST_F(ClassLoaderContextTest, OpenValidDexFilesSymLink) {
- std::string myclass_dex_name = GetTestDexFileName("MyClass");
- // Now replace the dex location with a symlink.
- ScratchSymLink link(myclass_dex_name);
-
- std::unique_ptr<ClassLoaderContext> context =
- ClassLoaderContext::Create("PCL[" + link.GetFilename() + "]");
-
- ASSERT_TRUE(context->OpenDexFiles(InstructionSet::kArm, /*classpath_dir*/ ""));
-
- VerifyContextSize(context.get(), 1);
-
- std::vector<std::unique_ptr<const DexFile>> myclass_dex_files = OpenTestDexFiles("MyClass");
-
- VerifyOpenDexFiles(context.get(), 0, &myclass_dex_files);
-}
-
static std::string CreateRelativeString(const std::string& in, const char* cwd) {
int cwd_len = strlen(cwd);
if (!android::base::StartsWith(in, cwd) || (cwd_len < 1)) {
diff --git a/runtime/code_item_accessors-inl.h b/runtime/code_item_accessors-inl.h
new file mode 100644
index 0000000..d04849d
--- /dev/null
+++ b/runtime/code_item_accessors-inl.h
@@ -0,0 +1,155 @@
+/*
+ * 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.
+ */
+
+#ifndef ART_RUNTIME_CODE_ITEM_ACCESSORS_INL_H_
+#define ART_RUNTIME_CODE_ITEM_ACCESSORS_INL_H_
+
+#include "code_item_accessors.h"
+
+#include "art_method-inl.h"
+#include "cdex/compact_dex_file.h"
+#include "dex_file-inl.h"
+#include "standard_dex_file.h"
+
+namespace art {
+
+inline void CodeItemInstructionAccessor::Init(const CompactDexFile::CodeItem& code_item) {
+ insns_size_in_code_units_ = code_item.insns_size_in_code_units_;
+ insns_ = code_item.insns_;
+}
+
+inline void CodeItemInstructionAccessor::Init(const StandardDexFile::CodeItem& code_item) {
+ insns_size_in_code_units_ = code_item.insns_size_in_code_units_;
+ insns_ = code_item.insns_;
+}
+
+inline void CodeItemInstructionAccessor::Init(const DexFile* dex_file,
+ const DexFile::CodeItem* code_item) {
+ DCHECK(dex_file != nullptr);
+ DCHECK(code_item != nullptr);
+ if (dex_file->IsCompactDexFile()) {
+ Init(down_cast<const CompactDexFile::CodeItem&>(*code_item));
+ } else {
+ DCHECK(dex_file->IsStandardDexFile());
+ Init(down_cast<const StandardDexFile::CodeItem&>(*code_item));
+ }
+}
+
+inline CodeItemInstructionAccessor::CodeItemInstructionAccessor(
+ const DexFile* dex_file,
+ const DexFile::CodeItem* code_item) {
+ Init(dex_file, code_item);
+}
+
+inline CodeItemInstructionAccessor::CodeItemInstructionAccessor(ArtMethod* method)
+ : CodeItemInstructionAccessor(method->GetDexFile(), method->GetCodeItem()) {}
+
+inline DexInstructionIterator CodeItemInstructionAccessor::begin() const {
+ return DexInstructionIterator(insns_, 0u);
+}
+
+inline DexInstructionIterator CodeItemInstructionAccessor::end() const {
+ return DexInstructionIterator(insns_, insns_size_in_code_units_);
+}
+
+inline CodeItemInstructionAccessor CodeItemInstructionAccessor::CreateNullable(
+ ArtMethod* method) {
+ DCHECK(method != nullptr);
+ CodeItemInstructionAccessor ret;
+ const DexFile::CodeItem* code_item = method->GetCodeItem();
+ if (code_item != nullptr) {
+ ret.Init(method->GetDexFile(), code_item);
+ } else {
+ DCHECK(!ret.HasCodeItem()) << "Should be null initialized";
+ }
+ return ret;
+}
+
+inline void CodeItemDataAccessor::Init(const CompactDexFile::CodeItem& code_item) {
+ CodeItemInstructionAccessor::Init(code_item);
+ registers_size_ = code_item.registers_size_;
+ ins_size_ = code_item.ins_size_;
+ outs_size_ = code_item.outs_size_;
+ tries_size_ = code_item.tries_size_;
+}
+
+inline void CodeItemDataAccessor::Init(const StandardDexFile::CodeItem& code_item) {
+ CodeItemInstructionAccessor::Init(code_item);
+ registers_size_ = code_item.registers_size_;
+ ins_size_ = code_item.ins_size_;
+ outs_size_ = code_item.outs_size_;
+ tries_size_ = code_item.tries_size_;
+}
+
+inline void CodeItemDataAccessor::Init(const DexFile* dex_file,
+ const DexFile::CodeItem* code_item) {
+ DCHECK(dex_file != nullptr);
+ DCHECK(code_item != nullptr);
+ if (dex_file->IsCompactDexFile()) {
+ CodeItemDataAccessor::Init(down_cast<const CompactDexFile::CodeItem&>(*code_item));
+ } else {
+ DCHECK(dex_file->IsStandardDexFile());
+ CodeItemDataAccessor::Init(down_cast<const StandardDexFile::CodeItem&>(*code_item));
+ }
+}
+
+inline CodeItemDataAccessor::CodeItemDataAccessor(const DexFile* dex_file,
+ const DexFile::CodeItem* code_item) {
+ Init(dex_file, code_item);
+}
+
+inline CodeItemDataAccessor::CodeItemDataAccessor(ArtMethod* method)
+ : CodeItemDataAccessor(method->GetDexFile(), method->GetCodeItem()) {}
+
+inline CodeItemDataAccessor CodeItemDataAccessor::CreateNullable(
+ const DexFile* dex_file,
+ const DexFile::CodeItem* code_item) {
+ CodeItemDataAccessor ret;
+ if (code_item != nullptr) {
+ ret.Init(dex_file, code_item);
+ } else {
+ DCHECK(!ret.HasCodeItem()) << "Should be null initialized";
+ }
+ return ret;
+}
+
+inline CodeItemDataAccessor CodeItemDataAccessor::CreateNullable(ArtMethod* method) {
+ DCHECK(method != nullptr);
+ return CreateNullable(method->GetDexFile(), method->GetCodeItem());
+}
+
+inline IterationRange<const DexFile::TryItem*> CodeItemDataAccessor::TryItems() const {
+ const DexFile::TryItem* try_items = DexFile::GetTryItems(end(), 0u);
+ return {
+ try_items,
+ try_items + TriesSize() };
+}
+
+inline const uint8_t* CodeItemDataAccessor::GetCatchHandlerData(size_t offset) const {
+ return DexFile::GetCatchHandlerData(end(), TriesSize(), offset);
+}
+
+inline const DexFile::TryItem* CodeItemDataAccessor::FindTryItem(uint32_t try_dex_pc) const {
+ IterationRange<const DexFile::TryItem*> try_items(TryItems());
+ int32_t index = DexFile::FindTryItem(try_items.begin(),
+ try_items.end() - try_items.begin(),
+ try_dex_pc);
+ return index != -1 ? &try_items.begin()[index] : nullptr;
+}
+
+} // namespace art
+
+#endif // ART_RUNTIME_CODE_ITEM_ACCESSORS_INL_H_
diff --git a/runtime/code_item_accessors.h b/runtime/code_item_accessors.h
new file mode 100644
index 0000000..aa1305a
--- /dev/null
+++ b/runtime/code_item_accessors.h
@@ -0,0 +1,137 @@
+/*
+ * 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.
+ */
+
+// TODO: Dex helpers have ART specific APIs, we may want to refactor these for use in dexdump.
+
+#ifndef ART_RUNTIME_CODE_ITEM_ACCESSORS_H_
+#define ART_RUNTIME_CODE_ITEM_ACCESSORS_H_
+
+#include "base/mutex.h"
+#include "cdex/compact_dex_file.h"
+#include "dex_file.h"
+#include "dex_instruction_iterator.h"
+#include "standard_dex_file.h"
+
+namespace art {
+
+class ArtMethod;
+
+// Abstracts accesses to the instruction fields of code items for CompactDexFile and
+// StandardDexFile.
+class CodeItemInstructionAccessor {
+ public:
+ ALWAYS_INLINE CodeItemInstructionAccessor(const DexFile* dex_file,
+ const DexFile::CodeItem* code_item);
+
+ ALWAYS_INLINE explicit CodeItemInstructionAccessor(ArtMethod* method);
+
+ ALWAYS_INLINE DexInstructionIterator begin() const;
+
+ ALWAYS_INLINE DexInstructionIterator end() const;
+
+ uint32_t InsnsSizeInCodeUnits() const {
+ return insns_size_in_code_units_;
+ }
+
+ const uint16_t* Insns() const {
+ return insns_;
+ }
+
+ // Return the instruction for a dex pc.
+ const Instruction& InstructionAt(uint32_t dex_pc) const {
+ return *Instruction::At(insns_ + dex_pc);
+ }
+
+ // Return true if the accessor has a code item.
+ bool HasCodeItem() const {
+ return Insns() != nullptr;
+ }
+
+ // CreateNullable allows ArtMethods that have a null code item.
+ ALWAYS_INLINE static CodeItemInstructionAccessor CreateNullable(ArtMethod* method)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
+ protected:
+ CodeItemInstructionAccessor() = default;
+
+ ALWAYS_INLINE void Init(const CompactDexFile::CodeItem& code_item);
+ ALWAYS_INLINE void Init(const StandardDexFile::CodeItem& code_item);
+ ALWAYS_INLINE void Init(const DexFile* dex_file, const DexFile::CodeItem* code_item);
+
+ private:
+ // size of the insns array, in 2 byte code units. 0 if there is no code item.
+ uint32_t insns_size_in_code_units_ = 0;
+
+ // Pointer to the instructions, null if there is no code item.
+ const uint16_t* insns_ = 0;
+};
+
+// Abstracts accesses to code item fields other than debug info for CompactDexFile and
+// StandardDexFile.
+class CodeItemDataAccessor : public CodeItemInstructionAccessor {
+ public:
+ ALWAYS_INLINE CodeItemDataAccessor(const DexFile* dex_file, const DexFile::CodeItem* code_item);
+
+ ALWAYS_INLINE explicit CodeItemDataAccessor(ArtMethod* method);
+
+ uint16_t RegistersSize() const {
+ return registers_size_;
+ }
+
+ uint16_t InsSize() const {
+ return ins_size_;
+ }
+
+ uint16_t OutsSize() const {
+ return outs_size_;
+ }
+
+ uint16_t TriesSize() const {
+ return tries_size_;
+ }
+
+ IterationRange<const DexFile::TryItem*> TryItems() const;
+
+ const uint8_t* GetCatchHandlerData(size_t offset = 0) const;
+
+ const DexFile::TryItem* FindTryItem(uint32_t try_dex_pc) const;
+
+ // CreateNullable allows ArtMethods that have a null code item.
+ ALWAYS_INLINE static CodeItemDataAccessor CreateNullable(ArtMethod* method)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
+ ALWAYS_INLINE static CodeItemDataAccessor CreateNullable(
+ const DexFile* dex_file,
+ const DexFile::CodeItem* code_item);
+
+ protected:
+ CodeItemDataAccessor() = default;
+
+ ALWAYS_INLINE void Init(const CompactDexFile::CodeItem& code_item);
+ ALWAYS_INLINE void Init(const StandardDexFile::CodeItem& code_item);
+ ALWAYS_INLINE void Init(const DexFile* dex_file, const DexFile::CodeItem* code_item);
+
+ private:
+ // Fields mirrored from the dex/cdex code item.
+ uint16_t registers_size_;
+ uint16_t ins_size_;
+ uint16_t outs_size_;
+ uint16_t tries_size_;
+};
+
+} // namespace art
+
+#endif // ART_RUNTIME_CODE_ITEM_ACCESSORS_H_
diff --git a/runtime/code_item_accessors_test.cc b/runtime/code_item_accessors_test.cc
new file mode 100644
index 0000000..ef5d246
--- /dev/null
+++ b/runtime/code_item_accessors_test.cc
@@ -0,0 +1,108 @@
+/*
+ * 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.
+ */
+
+#include "code_item_accessors-inl.h"
+
+#include <memory>
+
+#include "common_runtime_test.h"
+#include "dex_file_loader.h"
+#include "mem_map.h"
+
+namespace art {
+
+class CodeItemAccessorsTest : public CommonRuntimeTest {};
+
+std::unique_ptr<const DexFile> CreateFakeDex(bool compact_dex) {
+ std::string error_msg;
+ std::unique_ptr<MemMap> map(
+ MemMap::MapAnonymous(/*name*/ "map",
+ /*addr*/ nullptr,
+ /*byte_count*/ kPageSize,
+ PROT_READ | PROT_WRITE,
+ /*low_4gb*/ false,
+ /*reuse*/ false,
+ &error_msg));
+ CHECK(map != nullptr) << error_msg;
+ if (compact_dex) {
+ CompactDexFile::WriteMagic(map->Begin());
+ CompactDexFile::WriteCurrentVersion(map->Begin());
+ } else {
+ StandardDexFile::WriteMagic(map->Begin());
+ StandardDexFile::WriteCurrentVersion(map->Begin());
+ }
+ std::unique_ptr<const DexFile> dex(
+ DexFileLoader::Open("location",
+ /*location_checksum*/ 123,
+ std::move(map),
+ /*verify*/false,
+ /*verify_checksum*/false,
+ &error_msg));
+ CHECK(dex != nullptr) << error_msg;
+ return dex;
+}
+
+TEST(CodeItemAccessorsTest, TestDexInstructionsAccessor) {
+ MemMap::Init();
+ std::unique_ptr<const DexFile> standard_dex(CreateFakeDex(/*compact_dex*/false));
+ ASSERT_TRUE(standard_dex != nullptr);
+ std::unique_ptr<const DexFile> compact_dex(CreateFakeDex(/*compact_dex*/true));
+ ASSERT_TRUE(compact_dex != nullptr);
+ static constexpr uint16_t kRegisterSize = 1;
+ static constexpr uint16_t kInsSize = 2;
+ static constexpr uint16_t kOutsSize = 3;
+ static constexpr uint16_t kTriesSize = 4;
+ // debug_info_off_ is not accessible from the helpers yet.
+ static constexpr size_t kInsnsSizeInCodeUnits = 5;
+
+ auto verify_code_item = [&](const DexFile* dex,
+ const DexFile::CodeItem* item,
+ const uint16_t* insns) {
+ CodeItemInstructionAccessor insns_accessor(dex, item);
+ EXPECT_TRUE(insns_accessor.HasCodeItem());
+ ASSERT_EQ(insns_accessor.InsnsSizeInCodeUnits(), kInsnsSizeInCodeUnits);
+ EXPECT_EQ(insns_accessor.Insns(), insns);
+
+ CodeItemDataAccessor data_accessor(dex, item);
+ EXPECT_TRUE(data_accessor.HasCodeItem());
+ EXPECT_EQ(data_accessor.InsnsSizeInCodeUnits(), kInsnsSizeInCodeUnits);
+ EXPECT_EQ(data_accessor.Insns(), insns);
+ EXPECT_EQ(data_accessor.RegistersSize(), kRegisterSize);
+ EXPECT_EQ(data_accessor.InsSize(), kInsSize);
+ EXPECT_EQ(data_accessor.OutsSize(), kOutsSize);
+ EXPECT_EQ(data_accessor.TriesSize(), kTriesSize);
+ };
+
+ uint8_t buffer1[sizeof(CompactDexFile::CodeItem) + kInsnsSizeInCodeUnits * sizeof(uint16_t)] = {};
+ CompactDexFile::CodeItem* dex_code_item = reinterpret_cast<CompactDexFile::CodeItem*>(buffer1);
+ dex_code_item->registers_size_ = kRegisterSize;
+ dex_code_item->ins_size_ = kInsSize;
+ dex_code_item->outs_size_ = kOutsSize;
+ dex_code_item->tries_size_ = kTriesSize;
+ dex_code_item->insns_size_in_code_units_ = kInsnsSizeInCodeUnits;
+ verify_code_item(compact_dex.get(), dex_code_item, dex_code_item->insns_);
+
+ uint8_t buffer2[sizeof(CompactDexFile::CodeItem) + kInsnsSizeInCodeUnits * sizeof(uint16_t)] = {};
+ CompactDexFile::CodeItem* cdex_code_item = reinterpret_cast<CompactDexFile::CodeItem*>(buffer2);
+ cdex_code_item->registers_size_ = kRegisterSize;
+ cdex_code_item->ins_size_ = kInsSize;
+ cdex_code_item->outs_size_ = kOutsSize;
+ cdex_code_item->tries_size_ = kTriesSize;
+ cdex_code_item->insns_size_in_code_units_ = kInsnsSizeInCodeUnits;
+ verify_code_item(compact_dex.get(), cdex_code_item, cdex_code_item->insns_);
+}
+
+} // namespace art
diff --git a/runtime/dex_file-inl.h b/runtime/dex_file-inl.h
index 5dfbd9b..c926a0d 100644
--- a/runtime/dex_file-inl.h
+++ b/runtime/dex_file-inl.h
@@ -21,9 +21,11 @@
#include "base/casts.h"
#include "base/logging.h"
#include "base/stringpiece.h"
+#include "cdex/compact_dex_file.h"
#include "dex_file.h"
#include "invoke_type.h"
#include "leb128.h"
+#include "standard_dex_file.h"
namespace art {
@@ -133,9 +135,13 @@
}
inline const DexFile::TryItem* DexFile::GetTryItems(const CodeItem& code_item, uint32_t offset) {
- const uint16_t* insns_end_ = &code_item.insns_[code_item.insns_size_in_code_units_];
+ return GetTryItems(code_item.Instructions().end(), offset);
+}
+
+inline const DexFile::TryItem* DexFile::GetTryItems(const DexInstructionIterator& code_item_end,
+ uint32_t offset) {
return reinterpret_cast<const TryItem*>
- (RoundUp(reinterpret_cast<uintptr_t>(insns_end_), 4)) + offset;
+ (RoundUp(reinterpret_cast<uintptr_t>(&code_item_end.Inst()), 4)) + offset;
}
static inline bool DexFileStringEquals(const DexFile* df1, dex::StringIndex sidx1,
@@ -495,6 +501,16 @@
context);
}
+inline const CompactDexFile* DexFile::AsCompactDexFile() const {
+ DCHECK(IsCompactDexFile());
+ return down_cast<const CompactDexFile*>(this);
+}
+
+inline const StandardDexFile* DexFile::AsStandardDexFile() const {
+ DCHECK(IsStandardDexFile());
+ return down_cast<const StandardDexFile*>(this);
+}
+
} // namespace art
#endif // ART_RUNTIME_DEX_FILE_INL_H_
diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc
index 974c7ac..af79207 100644
--- a/runtime/dex_file.cc
+++ b/runtime/dex_file.cc
@@ -77,7 +77,8 @@
const std::string& location,
uint32_t location_checksum,
const OatDexFile* oat_dex_file,
- DexFileContainer* container)
+ DexFileContainer* container,
+ bool is_compact_dex)
: begin_(base),
size_(size),
location_(location),
@@ -94,7 +95,8 @@
call_site_ids_(nullptr),
num_call_site_ids_(0),
oat_dex_file_(oat_dex_file),
- container_(container) {
+ container_(container),
+ is_compact_dex_(is_compact_dex) {
CHECK(begin_ != nullptr) << GetLocation();
CHECK_GT(size_, 0U) << GetLocation();
// Check base (=header) alignment.
@@ -484,20 +486,18 @@
return Signature(this, *proto_id);
}
-int32_t DexFile::FindTryItem(const CodeItem &code_item, uint32_t address) {
- // Note: Signed type is important for max and min.
- int32_t min = 0;
- int32_t max = code_item.tries_size_ - 1;
+int32_t DexFile::FindTryItem(const TryItem* try_items, uint32_t tries_size, uint32_t address) {
+ uint32_t min = 0;
+ uint32_t max = tries_size;
+ while (min < max) {
+ const uint32_t mid = (min + max) / 2;
- while (min <= max) {
- int32_t mid = min + ((max - min) / 2);
-
- const art::DexFile::TryItem* ti = GetTryItems(code_item, mid);
- uint32_t start = ti->start_addr_;
- uint32_t end = start + ti->insn_count_;
+ const art::DexFile::TryItem& ti = try_items[mid];
+ const uint32_t start = ti.start_addr_;
+ const uint32_t end = start + ti.insn_count_;
if (address < start) {
- max = mid - 1;
+ max = mid;
} else if (address >= end) {
min = mid + 1;
} else { // We have a winner!
@@ -509,12 +509,8 @@
}
int32_t DexFile::FindCatchHandlerOffset(const CodeItem &code_item, uint32_t address) {
- int32_t try_item = FindTryItem(code_item, address);
- if (try_item == -1) {
- return -1;
- } else {
- return DexFile::GetTryItems(code_item, try_item)->handler_off_;
- }
+ int32_t try_item = FindTryItem(GetTryItems(code_item, 0), code_item.tries_size_, address);
+ return (try_item == -1) ? -1 : DexFile::GetTryItems(code_item, try_item)->handler_off_;
}
bool DexFile::LineNumForPcCb(void* raw_context, const PositionInfo& entry) {
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index 5c9b258..cdefb23 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -32,10 +32,12 @@
namespace art {
+class CompactDexFile;
enum InvokeType : uint32_t;
class MemMap;
class OatDexFile;
class Signature;
+class StandardDexFile;
class StringPiece;
class ZipArchive;
@@ -751,17 +753,23 @@
return begin_ + call_site_id.data_off_;
}
+ static const TryItem* GetTryItems(const DexInstructionIterator& code_item_end, uint32_t offset);
static const TryItem* GetTryItems(const CodeItem& code_item, uint32_t offset);
// Get the base of the encoded data for the given DexCode.
- static const uint8_t* GetCatchHandlerData(const CodeItem& code_item, uint32_t offset) {
+ static const uint8_t* GetCatchHandlerData(const DexInstructionIterator& code_item_end,
+ uint32_t tries_size,
+ uint32_t offset) {
const uint8_t* handler_data =
- reinterpret_cast<const uint8_t*>(GetTryItems(code_item, code_item.tries_size_));
+ reinterpret_cast<const uint8_t*>(GetTryItems(code_item_end, tries_size));
return handler_data + offset;
}
+ static const uint8_t* GetCatchHandlerData(const CodeItem& code_item, uint32_t offset) {
+ return GetCatchHandlerData(code_item.Instructions().end(), code_item.tries_size_, offset);
+ }
// Find which try region is associated with the given address (ie dex pc). Returns -1 if none.
- static int32_t FindTryItem(const CodeItem &code_item, uint32_t address);
+ static int32_t FindTryItem(const TryItem* try_items, uint32_t tries_size, uint32_t address);
// Find the handler offset associated with the given address (ie dex pc). Returns -1 if none.
static int32_t FindCatchHandlerOffset(const CodeItem &code_item, uint32_t address);
@@ -993,13 +1001,15 @@
// Returns a human-readable form of the type at an index.
std::string PrettyType(dex::TypeIndex type_idx) const;
- // Helper functions.
- virtual bool IsCompactDexFile() const {
- return false;
+ // Not virtual for performance reasons.
+ ALWAYS_INLINE bool IsCompactDexFile() const {
+ return is_compact_dex_;
}
- virtual bool IsStandardDexFile() const {
- return false;
+ ALWAYS_INLINE bool IsStandardDexFile() const {
+ return !is_compact_dex_;
}
+ ALWAYS_INLINE const StandardDexFile* AsStandardDexFile() const;
+ ALWAYS_INLINE const CompactDexFile* AsCompactDexFile() const;
protected:
DexFile(const uint8_t* base,
@@ -1007,7 +1017,8 @@
const std::string& location,
uint32_t location_checksum,
const OatDexFile* oat_dex_file,
- DexFileContainer* container);
+ DexFileContainer* container,
+ bool is_compact_dex);
// Top-level initializer that calls other Init methods.
bool Init(std::string* error_msg);
@@ -1073,6 +1084,9 @@
// Manages the underlying memory allocation.
std::unique_ptr<DexFileContainer> container_;
+ // If the dex file is a compact dex file. If false then the dex file is a standard dex file.
+ const bool is_compact_dex_;
+
friend class DexFileLoader;
friend class DexFileVerifierTest;
friend class OatWriter;
@@ -1178,6 +1192,11 @@
bool HasNextVirtualMethod() const {
return pos_ >= EndOfDirectMethodsPos() && pos_ < EndOfVirtualMethodsPos();
}
+ bool HasNextMethod() const {
+ const bool result = pos_ >= EndOfInstanceFieldsPos() && pos_ < EndOfVirtualMethodsPos();
+ DCHECK_EQ(result, HasNextDirectMethod() || HasNextVirtualMethod());
+ return result;
+ }
void SkipStaticFields() {
while (HasNextStaticField()) {
Next();
diff --git a/runtime/dex_file_tracking_registrar.cc b/runtime/dex_file_tracking_registrar.cc
index 3411586..874d8ea 100644
--- a/runtime/dex_file_tracking_registrar.cc
+++ b/runtime/dex_file_tracking_registrar.cc
@@ -158,7 +158,7 @@
if (class_data != nullptr) {
ClassDataItemIterator cdit(*dex_file_, class_data);
cdit.SkipAllFields();
- while (cdit.HasNextDirectMethod()) {
+ while (cdit.HasNextMethod()) {
const DexFile::CodeItem* code_item = cdit.GetMethodCodeItem();
if (code_item != nullptr) {
const void* code_item_begin = reinterpret_cast<const void*>(code_item);
@@ -178,7 +178,7 @@
if (class_data != nullptr) {
ClassDataItemIterator cdit(*dex_file_, class_data);
cdit.SkipAllFields();
- while (cdit.HasNextDirectMethod()) {
+ while (cdit.HasNextMethod()) {
const DexFile::CodeItem* code_item = cdit.GetMethodCodeItem();
if (code_item != nullptr) {
const void* code_item_begin = reinterpret_cast<const void*>(code_item);
@@ -200,7 +200,7 @@
if (class_data != nullptr) {
ClassDataItemIterator cdit(*dex_file_, class_data);
cdit.SkipAllFields();
- while (cdit.HasNextDirectMethod()) {
+ while (cdit.HasNextMethod()) {
const DexFile::CodeItem* code_item = cdit.GetMethodCodeItem();
if (code_item != nullptr) {
const void* insns_begin = reinterpret_cast<const void*>(&code_item->insns_);
@@ -221,7 +221,7 @@
if (class_data != nullptr) {
ClassDataItemIterator cdit(*dex_file_, class_data);
cdit.SkipAllFields();
- while (cdit.HasNextDirectMethod()) {
+ while (cdit.HasNextMethod()) {
const DexFile::MethodId& methodid_item = dex_file_->GetMethodId(cdit.GetMemberIndex());
const char * methodid_name = dex_file_->GetMethodName(methodid_item);
const DexFile::CodeItem* code_item = cdit.GetMethodCodeItem();
diff --git a/runtime/dex_file_verifier.cc b/runtime/dex_file_verifier.cc
index 50f56c7..025952f 100644
--- a/runtime/dex_file_verifier.cc
+++ b/runtime/dex_file_verifier.cc
@@ -1970,7 +1970,7 @@
return field->class_idx_;
}
- if (it.HasNextDirectMethod() || it.HasNextVirtualMethod()) {
+ if (it.HasNextMethod()) {
LOAD_METHOD(method, it.GetMemberIndex(), "first_class_data_definer method_id",
*success = false; return dex::TypeIndex(DexFile::kDexNoIndex16))
return method->class_idx_;
@@ -2566,7 +2566,7 @@
return false;
}
}
- for (; it.HasNextDirectMethod() || it.HasNextVirtualMethod(); it.Next()) {
+ for (; it.HasNextMethod(); it.Next()) {
uint32_t code_off = it.GetMethodCodeItemOffset();
if (code_off != 0 && !CheckOffsetToTypeMap(code_off, DexFile::kDexTypeCodeItem)) {
return false;
diff --git a/runtime/dex_file_verifier_test.cc b/runtime/dex_file_verifier_test.cc
index ee577e7..d4d912c 100644
--- a/runtime/dex_file_verifier_test.cc
+++ b/runtime/dex_file_verifier_test.cc
@@ -249,7 +249,7 @@
it.Next();
}
- while (it.HasNextDirectMethod() || it.HasNextVirtualMethod()) {
+ while (it.HasNextMethod()) {
uint32_t method_index = it.GetMemberIndex();
dex::StringIndex name_index = dex_file->GetMethodId(method_index).name_idx_;
const DexFile::StringId& string_id = dex_file->GetStringId(name_index);
diff --git a/runtime/dex_instruction.cc b/runtime/dex_instruction.cc
index e64c0f6..6ebe228 100644
--- a/runtime/dex_instruction.cc
+++ b/runtime/dex_instruction.cc
@@ -548,4 +548,14 @@
return os << Instruction::Name(code);
}
+uint32_t RangeInstructionOperands::GetOperand(size_t operand_index) const {
+ DCHECK_LT(operand_index, GetNumberOfOperands());
+ return first_operand_ + operand_index;
+}
+
+uint32_t VarArgsInstructionOperands::GetOperand(size_t operand_index) const {
+ DCHECK_LT(operand_index, GetNumberOfOperands());
+ return operands_[operand_index];
+}
+
} // namespace art
diff --git a/runtime/dex_instruction.h b/runtime/dex_instruction.h
index 09c78b2..4041820 100644
--- a/runtime/dex_instruction.h
+++ b/runtime/dex_instruction.h
@@ -689,6 +689,53 @@
std::ostream& operator<<(std::ostream& os, const Instruction::Flags& flags);
std::ostream& operator<<(std::ostream& os, const Instruction::VerifyFlag& vflags);
+// Base class for accessing instruction operands. Unifies operand
+// access for instructions that have range and varargs forms
+// (e.g. invoke-polymoprhic/range and invoke-polymorphic).
+class InstructionOperands {
+ public:
+ explicit InstructionOperands(size_t num_operands) : num_operands_(num_operands) {}
+ virtual ~InstructionOperands() {}
+ virtual uint32_t GetOperand(size_t index) const = 0;
+ size_t GetNumberOfOperands() const { return num_operands_; }
+
+ private:
+ size_t num_operands_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(InstructionOperands);
+};
+
+// Class for accessing operands for instructions with a range format
+// (e.g. 3rc and 4rcc).
+class RangeInstructionOperands FINAL : public InstructionOperands {
+ public:
+ RangeInstructionOperands(uint32_t first_operand, size_t num_operands)
+ : InstructionOperands(num_operands), first_operand_(first_operand) {}
+ ~RangeInstructionOperands() {}
+ uint32_t GetOperand(size_t operand_index) const OVERRIDE;
+
+ private:
+ const uint32_t first_operand_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(RangeInstructionOperands);
+};
+
+// Class for accessing operands for instructions with a variable
+// number of arguments format (e.g. 35c and 45cc).
+class VarArgsInstructionOperands FINAL : public InstructionOperands {
+ public:
+ VarArgsInstructionOperands(const uint32_t (&operands)[Instruction::kMaxVarArgRegs],
+ size_t num_operands)
+ : InstructionOperands(num_operands), operands_(operands) {}
+ ~VarArgsInstructionOperands() {}
+ uint32_t GetOperand(size_t operand_index) const OVERRIDE;
+
+ private:
+ const uint32_t (&operands_)[Instruction::kMaxVarArgRegs];
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(VarArgsInstructionOperands);
+};
+
} // namespace art
#endif // ART_RUNTIME_DEX_INSTRUCTION_H_
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 127b5d7..22c9a1d 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -2649,28 +2649,24 @@
// Call DoInvokePolymorphic with |is_range| = true, as shadow frame has argument registers in
// consecutive order.
- uint32_t unused_args[Instruction::kMaxVarArgRegs] = {};
- uint32_t first_callee_arg = first_arg + 1;
-
+ RangeInstructionOperands operands(first_arg + 1, num_vregs - 1);
bool isExact = (jni::EncodeArtMethod(resolved_method) ==
WellKnownClasses::java_lang_invoke_MethodHandle_invokeExact);
bool success = false;
if (isExact) {
- success = MethodHandleInvokeExact<true/*is_range*/>(self,
- *shadow_frame,
- method_handle,
- method_type,
- unused_args,
- first_callee_arg,
- result);
+ success = MethodHandleInvokeExact(self,
+ *shadow_frame,
+ method_handle,
+ method_type,
+ &operands,
+ result);
} else {
- success = MethodHandleInvoke<true/*is_range*/>(self,
- *shadow_frame,
- method_handle,
- method_type,
- unused_args,
- first_callee_arg,
- result);
+ success = MethodHandleInvoke(self,
+ *shadow_frame,
+ method_handle,
+ method_type,
+ &operands,
+ result);
}
DCHECK(success || self->IsExceptionPending());
diff --git a/runtime/gc/allocator/dlmalloc.h b/runtime/gc/allocator/dlmalloc.h
index c07da5d..29b96ee 100644
--- a/runtime/gc/allocator/dlmalloc.h
+++ b/runtime/gc/allocator/dlmalloc.h
@@ -35,13 +35,6 @@
#include "../../external/dlmalloc/malloc.h"
#pragma GCC diagnostic pop
-#ifdef ART_TARGET_ANDROID
-// Define dlmalloc routines from bionic that cannot be included directly because of redefining
-// symbols from the include above.
-extern "C" void dlmalloc_inspect_all(void(*handler)(void*, void *, size_t, void*), void* arg);
-extern "C" int dlmalloc_trim(size_t);
-#endif
-
// Callback for dlmalloc_inspect_all or mspace_inspect_all that will madvise(2) unused
// pages back to the kernel.
extern "C" void DlmallocMadviseCallback(void* start, void* end, size_t used_bytes, void* /*arg*/);
diff --git a/runtime/gc/task_processor.cc b/runtime/gc/task_processor.cc
index e928644..64e8322 100644
--- a/runtime/gc/task_processor.cc
+++ b/runtime/gc/task_processor.cc
@@ -23,32 +23,37 @@
namespace gc {
TaskProcessor::TaskProcessor()
- : lock_(new Mutex("Task processor lock", kReferenceProcessorLock)), is_running_(false),
+ : lock_("Task processor lock", kReferenceProcessorLock),
+ cond_("Task processor condition", lock_),
+ is_running_(false),
running_thread_(nullptr) {
- // Piggyback off the reference processor lock level.
- cond_.reset(new ConditionVariable("Task processor condition", *lock_));
}
TaskProcessor::~TaskProcessor() {
- delete lock_;
+ if (!tasks_.empty()) {
+ LOG(WARNING) << "TaskProcessor: Finalizing " << tasks_.size() << " unprocessed tasks.";
+ for (HeapTask* task : tasks_) {
+ task->Finalize();
+ }
+ }
}
void TaskProcessor::AddTask(Thread* self, HeapTask* task) {
ScopedThreadStateChange tsc(self, kWaitingForTaskProcessor);
- MutexLock mu(self, *lock_);
+ MutexLock mu(self, lock_);
tasks_.insert(task);
- cond_->Signal(self);
+ cond_.Signal(self);
}
HeapTask* TaskProcessor::GetTask(Thread* self) {
ScopedThreadStateChange tsc(self, kWaitingForTaskProcessor);
- MutexLock mu(self, *lock_);
+ MutexLock mu(self, lock_);
while (true) {
if (tasks_.empty()) {
if (!is_running_) {
return nullptr;
}
- cond_->Wait(self); // Empty queue, wait until we are signalled.
+ cond_.Wait(self); // Empty queue, wait until we are signalled.
} else {
// Non empty queue, look at the top element and see if we are ready to run it.
const uint64_t current_time = NanoTime();
@@ -61,18 +66,18 @@
return task;
}
DCHECK_GT(target_time, current_time);
- // Wait untl we hit the target run time.
+ // Wait until we hit the target run time.
const uint64_t delta_time = target_time - current_time;
const uint64_t ms_delta = NsToMs(delta_time);
const uint64_t ns_delta = delta_time - MsToNs(ms_delta);
- cond_->TimedWait(self, static_cast<int64_t>(ms_delta), static_cast<int32_t>(ns_delta));
+ cond_.TimedWait(self, static_cast<int64_t>(ms_delta), static_cast<int32_t>(ns_delta));
}
}
UNREACHABLE();
}
void TaskProcessor::UpdateTargetRunTime(Thread* self, HeapTask* task, uint64_t new_target_time) {
- MutexLock mu(self, *lock_);
+ MutexLock mu(self, lock_);
// Find the task.
auto range = tasks_.equal_range(task);
for (auto it = range.first; it != range.second; ++it) {
@@ -85,7 +90,7 @@
// If we became the first task then we may need to signal since we changed the task that we
// are sleeping on.
if (*tasks_.begin() == task) {
- cond_->Signal(self);
+ cond_.Signal(self);
}
return;
}
@@ -94,24 +99,24 @@
}
bool TaskProcessor::IsRunning() const {
- MutexLock mu(Thread::Current(), *lock_);
+ MutexLock mu(Thread::Current(), lock_);
return is_running_;
}
Thread* TaskProcessor::GetRunningThread() const {
- MutexLock mu(Thread::Current(), *lock_);
+ MutexLock mu(Thread::Current(), lock_);
return running_thread_;
}
void TaskProcessor::Stop(Thread* self) {
- MutexLock mu(self, *lock_);
+ MutexLock mu(self, lock_);
is_running_ = false;
running_thread_ = nullptr;
- cond_->Broadcast(self);
+ cond_.Broadcast(self);
}
void TaskProcessor::Start(Thread* self) {
- MutexLock mu(self, *lock_);
+ MutexLock mu(self, lock_);
is_running_ = true;
running_thread_ = self;
}
diff --git a/runtime/gc/task_processor.h b/runtime/gc/task_processor.h
index e40fa06..f6b5607 100644
--- a/runtime/gc/task_processor.h
+++ b/runtime/gc/task_processor.h
@@ -54,17 +54,17 @@
public:
TaskProcessor();
virtual ~TaskProcessor();
- void AddTask(Thread* self, HeapTask* task) REQUIRES(!*lock_);
- HeapTask* GetTask(Thread* self) REQUIRES(!*lock_);
- void Start(Thread* self) REQUIRES(!*lock_);
+ void AddTask(Thread* self, HeapTask* task) REQUIRES(!lock_);
+ HeapTask* GetTask(Thread* self) REQUIRES(!lock_);
+ void Start(Thread* self) REQUIRES(!lock_);
// Stop tells the RunAllTasks to finish up the remaining tasks as soon as
// possible then return.
- void Stop(Thread* self) REQUIRES(!*lock_);
- void RunAllTasks(Thread* self) REQUIRES(!*lock_);
- bool IsRunning() const REQUIRES(!*lock_);
+ void Stop(Thread* self) REQUIRES(!lock_);
+ void RunAllTasks(Thread* self) REQUIRES(!lock_);
+ bool IsRunning() const REQUIRES(!lock_);
void UpdateTargetRunTime(Thread* self, HeapTask* target_time, uint64_t new_target_time)
- REQUIRES(!*lock_);
- Thread* GetRunningThread() const REQUIRES(!*lock_);
+ REQUIRES(!lock_);
+ Thread* GetRunningThread() const REQUIRES(!lock_);
private:
class CompareByTargetRunTime {
@@ -74,9 +74,9 @@
}
};
- mutable Mutex* lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+ mutable Mutex lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+ ConditionVariable cond_ GUARDED_BY(lock_);
bool is_running_ GUARDED_BY(lock_);
- std::unique_ptr<ConditionVariable> cond_ GUARDED_BY(lock_);
std::multiset<HeapTask*, CompareByTargetRunTime> tasks_ GUARDED_BY(lock_);
Thread* running_thread_ GUARDED_BY(lock_);
diff --git a/runtime/globals.h b/runtime/globals.h
index 53932fd..f14d6e9 100644
--- a/runtime/globals.h
+++ b/runtime/globals.h
@@ -125,12 +125,6 @@
static constexpr bool kDefaultMustRelocate = true;
-#ifdef ART_ENABLE_VDEX
-static constexpr bool kIsVdexEnabled = true;
-#else
-static constexpr bool kIsVdexEnabled = false;
-#endif
-
// Size of a heap reference.
static constexpr size_t kHeapReferenceSize = sizeof(uint32_t);
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 0a1ae36..d2d017e 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -644,52 +644,47 @@
// arguments either from a range or an array of arguments depending
// on whether the DEX instruction is invoke-polymorphic/range or
// invoke-polymorphic. The array here is for the latter.
- uint32_t args[Instruction::kMaxVarArgRegs] = {};
if (UNLIKELY(is_range)) {
// VRegC is the register holding the method handle. Arguments passed
// to the method handle's target do not include the method handle.
- uint32_t first_arg = inst->VRegC_4rcc() + 1;
- static const bool kIsRange = true;
+ RangeInstructionOperands operands(inst->VRegC_4rcc() + 1, inst->VRegA_4rcc() - 1);
if (invoke_exact) {
- return art::MethodHandleInvokeExact<kIsRange>(self,
- shadow_frame,
- method_handle,
- callsite_type,
- args /* unused */,
- first_arg,
- result);
+ return MethodHandleInvokeExact(self,
+ shadow_frame,
+ method_handle,
+ callsite_type,
+ &operands,
+ result);
} else {
- return art::MethodHandleInvoke<kIsRange>(self,
- shadow_frame,
- method_handle,
- callsite_type,
- args /* unused */,
- first_arg,
- result);
+ return MethodHandleInvoke(self,
+ shadow_frame,
+ method_handle,
+ callsite_type,
+ &operands,
+ result);
}
} else {
// Get the register arguments for the invoke.
+ uint32_t args[Instruction::kMaxVarArgRegs] = {};
inst->GetVarArgs(args, inst_data);
// Drop the first register which is the method handle performing the invoke.
memmove(args, args + 1, sizeof(args[0]) * (Instruction::kMaxVarArgRegs - 1));
args[Instruction::kMaxVarArgRegs - 1] = 0;
- static const bool kIsRange = false;
+ VarArgsInstructionOperands operands(args, inst->VRegA_45cc() - 1);
if (invoke_exact) {
- return art::MethodHandleInvokeExact<kIsRange>(self,
- shadow_frame,
- method_handle,
- callsite_type,
- args,
- args[0],
- result);
+ return MethodHandleInvokeExact(self,
+ shadow_frame,
+ method_handle,
+ callsite_type,
+ &operands,
+ result);
} else {
- return art::MethodHandleInvoke<kIsRange>(self,
- shadow_frame,
- method_handle,
- callsite_type,
- args,
- args[0],
- result);
+ return MethodHandleInvoke(self,
+ shadow_frame,
+ method_handle,
+ callsite_type,
+ &operands,
+ result);
}
}
}
@@ -1180,17 +1175,13 @@
// Invoke the bootstrap method handle.
JValue result;
-
- // This array of arguments is unused. DoMethodHandleInvokeExact() operates on either a
- // an argument array or a range, but always takes an array argument.
- uint32_t args_unused[Instruction::kMaxVarArgRegs];
- bool invoke_success = art::MethodHandleInvokeExact<true /* is_range */>(self,
- *bootstrap_frame,
- bootstrap,
- bootstrap_method_type,
- args_unused,
- 0,
- &result);
+ RangeInstructionOperands operands(0, vreg);
+ bool invoke_success = MethodHandleInvokeExact(self,
+ *bootstrap_frame,
+ bootstrap,
+ bootstrap_method_type,
+ &operands,
+ &result);
if (!invoke_success) {
DCHECK(self->IsExceptionPending());
return nullptr;
@@ -1273,21 +1264,25 @@
Handle<mirror::MethodHandle> target = hs.NewHandle(call_site->GetTarget());
Handle<mirror::MethodType> target_method_type = hs.NewHandle(target->GetMethodType());
DCHECK_EQ(static_cast<size_t>(inst->VRegA()), target_method_type->NumberOfVRegs());
-
- uint32_t args[Instruction::kMaxVarArgRegs];
if (is_range) {
- args[0] = inst->VRegC_3rc();
+ RangeInstructionOperands operands(inst->VRegC_3rc(), inst->VRegA_3rc());
+ return MethodHandleInvokeExact(self,
+ shadow_frame,
+ target,
+ target_method_type,
+ &operands,
+ result);
} else {
+ uint32_t args[Instruction::kMaxVarArgRegs];
inst->GetVarArgs(args, inst_data);
+ VarArgsInstructionOperands operands(args, inst->VRegA_35c());
+ return MethodHandleInvokeExact(self,
+ shadow_frame,
+ target,
+ target_method_type,
+ &operands,
+ result);
}
-
- return art::MethodHandleInvokeExact<is_range>(self,
- shadow_frame,
- target,
- target_method_type,
- args,
- args[0],
- result);
}
template <bool is_range>
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index e180752..3220513 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -30,6 +30,7 @@
#include "entrypoints/runtime_asm_entrypoints.h"
#include "gc/accounting/bitmap-inl.h"
#include "gc/scoped_gc_critical_section.h"
+#include "handle.h"
#include "intern_table.h"
#include "jit/jit.h"
#include "jit/profiling_info.h"
@@ -38,8 +39,10 @@
#include "oat_file-inl.h"
#include "oat_quick_method_header.h"
#include "object_callbacks.h"
+#include "profile_compilation_info.h"
#include "scoped_thread_state_change-inl.h"
#include "stack.h"
+#include "thread-current-inl.h"
#include "thread_list.h"
namespace art {
@@ -182,6 +185,8 @@
<< PrettySize(initial_code_capacity);
}
+JitCodeCache::~JitCodeCache() {}
+
bool JitCodeCache::ContainsPc(const void* ptr) const {
return code_map_->Begin() <= ptr && ptr < code_map_->End();
}
diff --git a/runtime/jit/jit_code_cache.h b/runtime/jit/jit_code_cache.h
index 9790e3a..46a4085 100644
--- a/runtime/jit/jit_code_cache.h
+++ b/runtime/jit/jit_code_cache.h
@@ -24,24 +24,33 @@
#include "base/histogram-inl.h"
#include "base/macros.h"
#include "base/mutex.h"
-#include "gc/accounting/bitmap.h"
#include "gc_root.h"
-#include "jni.h"
#include "method_reference.h"
-#include "oat_file.h"
-#include "profile_compilation_info.h"
#include "safe_map.h"
-#include "thread_pool.h"
namespace art {
class ArtMethod;
+template<class T> class Handle;
class LinearAlloc;
class InlineCache;
class IsMarkedVisitor;
class OatQuickMethodHeader;
+struct ProfileMethodInfo;
class ProfilingInfo;
+namespace gc {
+namespace accounting {
+template<size_t kAlignment> class MemoryRangeBitmap;
+} // namespace accounting
+} // namespace gc
+
+namespace mirror {
+class Class;
+class Object;
+template<class T> class ObjectArray;
+} // namespace mirror
+
namespace jit {
class JitInstrumentationCache;
@@ -66,6 +75,7 @@
size_t max_capacity,
bool generate_debug_info,
std::string* error_msg);
+ ~JitCodeCache();
// Number of bytes allocated in the code cache.
size_t CodeCacheSize() REQUIRES(!lock_);
@@ -210,11 +220,6 @@
uint64_t GetLastUpdateTimeNs() const;
- size_t GetCurrentCapacity() REQUIRES(!lock_) {
- MutexLock lock(Thread::Current(), lock_);
- return current_capacity_;
- }
-
size_t GetMemorySizeOfCodePointer(const void* ptr) REQUIRES(!lock_);
void InvalidateCompiledCodeFor(ArtMethod* method, const OatQuickMethodHeader* code)
diff --git a/runtime/jit/profile_compilation_info.cc b/runtime/jit/profile_compilation_info.cc
index 805b9c1..bb8e5e5 100644
--- a/runtime/jit/profile_compilation_info.cc
+++ b/runtime/jit/profile_compilation_info.cc
@@ -1034,7 +1034,7 @@
return kProfileLoadBadData;
}
const uint8_t* base_ptr = buffer.GetCurrentPtr();
- std::copy_n(base_ptr, bytes, &data->bitmap_storage[0]);
+ std::copy_n(base_ptr, bytes, data->bitmap_storage.data());
buffer.Advance(bytes);
// Read method bitmap.
return kProfileLoadSuccess;
diff --git a/runtime/jit/profiling_info.cc b/runtime/jit/profiling_info.cc
index 1344ca0..e54a017 100644
--- a/runtime/jit/profiling_info.cc
+++ b/runtime/jit/profiling_info.cc
@@ -44,8 +44,7 @@
DCHECK(!method->IsNative());
std::vector<uint32_t> entries;
-
- for (const DexInstructionPcPair& inst : method->GetCodeItem()->Instructions()) {
+ for (const DexInstructionPcPair& inst : method->DexInstructions()) {
switch (inst->Opcode()) {
case Instruction::INVOKE_VIRTUAL:
case Instruction::INVOKE_VIRTUAL_RANGE:
diff --git a/runtime/method_handles.cc b/runtime/method_handles.cc
index 5a5d571..8eb31c1 100644
--- a/runtime/method_handles.cc
+++ b/runtime/method_handles.cc
@@ -299,17 +299,14 @@
namespace {
-template <bool is_range>
inline void CopyArgumentsFromCallerFrame(const ShadowFrame& caller_frame,
ShadowFrame* callee_frame,
- const uint32_t (&args)[Instruction::kMaxVarArgRegs],
- uint32_t first_arg,
- const size_t first_dst_reg,
- const size_t num_regs)
+ const InstructionOperands* const operands,
+ const size_t first_dst_reg)
REQUIRES_SHARED(Locks::mutator_lock_) {
- for (size_t i = 0; i < num_regs; ++i) {
+ for (size_t i = 0; i < operands->GetNumberOfOperands(); ++i) {
size_t dst_reg = first_dst_reg + i;
- size_t src_reg = is_range ? (first_arg + i) : args[i];
+ size_t src_reg = operands->GetOperand(i);
// Uint required, so that sign extension does not make this wrong on 64-bit systems
uint32_t src_value = caller_frame.GetVReg(src_reg);
ObjPtr<mirror::Object> o = caller_frame.GetVRegReference<kVerifyNone>(src_reg);
@@ -324,15 +321,13 @@
}
}
-template <bool is_range>
inline bool ConvertAndCopyArgumentsFromCallerFrame(
Thread* self,
Handle<mirror::MethodType> callsite_type,
Handle<mirror::MethodType> callee_type,
const ShadowFrame& caller_frame,
- const uint32_t (&args)[Instruction::kMaxVarArgRegs],
- uint32_t first_arg,
- uint32_t first_dst_reg,
+ uint32_t first_dest_reg,
+ const InstructionOperands* const operands,
ShadowFrame* callee_frame)
REQUIRES_SHARED(Locks::mutator_lock_) {
ObjPtr<mirror::ObjectArray<mirror::Class>> from_types(callsite_type->GetPTypes());
@@ -344,15 +339,14 @@
return false;
}
- ShadowFrameGetter<is_range> getter(first_arg, args, caller_frame);
- ShadowFrameSetter setter(callee_frame, first_dst_reg);
-
- return PerformConversions<ShadowFrameGetter<is_range>, ShadowFrameSetter>(self,
- callsite_type,
- callee_type,
- &getter,
- &setter,
- num_method_params);
+ ShadowFrameGetter getter(operands, caller_frame);
+ ShadowFrameSetter setter(callee_frame, first_dest_reg);
+ return PerformConversions<ShadowFrameGetter, ShadowFrameSetter>(self,
+ callsite_type,
+ callee_type,
+ &getter,
+ &setter,
+ num_method_params);
}
inline bool IsInvoke(const mirror::MethodHandle::Kind handle_kind) {
@@ -406,14 +400,12 @@
return false;
}
-template <bool is_range>
static inline bool MethodHandleInvokeMethod(ArtMethod* called_method,
Handle<mirror::MethodType> callsite_type,
Handle<mirror::MethodType> target_type,
Thread* self,
ShadowFrame& shadow_frame,
- const uint32_t (&args)[Instruction::kMaxVarArgRegs],
- uint32_t first_arg,
+ const InstructionOperands* const operands,
JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
// Compute method information.
const DexFile::CodeItem* code_item = called_method->GetCodeItem();
@@ -455,12 +447,10 @@
if (callsite_type->IsExactMatch(target_type.Get())) {
// This is an exact invoke, we can take the fast path of just copying all
// registers without performing any argument conversions.
- CopyArgumentsFromCallerFrame<is_range>(shadow_frame,
- new_shadow_frame,
- args,
- first_arg,
- first_dest_reg,
- num_input_regs);
+ CopyArgumentsFromCallerFrame(shadow_frame,
+ new_shadow_frame,
+ operands,
+ first_dest_reg);
} else {
// This includes the case where we're entering this invoke-polymorphic
// from a transformer method. In that case, the callsite_type will contain
@@ -471,7 +461,7 @@
is_caller_transformer = true;
// The emulated stack frame is the first and only argument when we're coming
// through from a transformer.
- size_t first_arg_register = (is_range) ? first_arg : args[0];
+ size_t first_arg_register = operands->GetOperand(0);
ObjPtr<mirror::EmulatedStackFrame> emulated_stack_frame(
reinterpret_cast<mirror::EmulatedStackFrame*>(
shadow_frame.GetVRegReference(first_arg_register)));
@@ -488,14 +478,13 @@
ThrowWrongMethodTypeException(target_type.Get(), callsite_type.Get());
return false;
}
- if (!ConvertAndCopyArgumentsFromCallerFrame<is_range>(self,
- callsite_type,
- target_type,
- shadow_frame,
- args,
- first_arg,
- first_dest_reg,
- new_shadow_frame)) {
+ if (!ConvertAndCopyArgumentsFromCallerFrame(self,
+ callsite_type,
+ target_type,
+ shadow_frame,
+ first_dest_reg,
+ operands,
+ new_shadow_frame)) {
DCHECK(self->IsExceptionPending());
result->SetL(0);
return false;
@@ -521,7 +510,7 @@
// we need to copy the result back out to the emulated stack frame.
if (is_caller_transformer) {
StackHandleScope<2> hs(self);
- size_t first_callee_register = is_range ? (first_arg) : args[0];
+ size_t first_callee_register = operands->GetOperand(0);
Handle<mirror::EmulatedStackFrame> emulated_stack_frame(
hs.NewHandle(reinterpret_cast<mirror::EmulatedStackFrame*>(
shadow_frame.GetVRegReference(first_callee_register))));
@@ -541,15 +530,13 @@
return ConvertReturnValue(callsite_type, target_type, result);
}
-template <bool is_range>
static inline bool MethodHandleInvokeTransform(ArtMethod* called_method,
Handle<mirror::MethodType> callsite_type,
Handle<mirror::MethodType> callee_type,
Thread* self,
ShadowFrame& shadow_frame,
Handle<mirror::MethodHandle> receiver,
- const uint32_t (&args)[Instruction::kMaxVarArgRegs],
- uint32_t first_arg,
+ const InstructionOperands* const operands,
JValue* result)
REQUIRES_SHARED(Locks::mutator_lock_) {
// This can be fixed to two, because the method we're calling here
@@ -578,16 +565,15 @@
// If we're entering this transformer from another transformer, we can pass
// through the handle directly to the callee, instead of having to
// instantiate a new stack frame based on the shadow frame.
- size_t first_callee_register = is_range ? first_arg : args[0];
+ size_t first_callee_register = operands->GetOperand(0);
sf.Assign(reinterpret_cast<mirror::EmulatedStackFrame*>(
shadow_frame.GetVRegReference(first_callee_register)));
} else {
- sf.Assign(mirror::EmulatedStackFrame::CreateFromShadowFrameAndArgs<is_range>(self,
- callsite_type,
- callee_type,
- shadow_frame,
- first_arg,
- args));
+ sf.Assign(mirror::EmulatedStackFrame::CreateFromShadowFrameAndArgs(self,
+ callsite_type,
+ callee_type,
+ shadow_frame,
+ operands));
// Something went wrong while creating the emulated stack frame, we should
// throw the pending exception.
@@ -699,13 +685,11 @@
return target_method;
}
-template <bool is_range>
bool DoInvokePolymorphicMethod(Thread* self,
ShadowFrame& shadow_frame,
Handle<mirror::MethodHandle> method_handle,
Handle<mirror::MethodType> callsite_type,
- const uint32_t (&args)[Instruction::kMaxVarArgRegs],
- uint32_t first_arg,
+ const InstructionOperands* const operands,
JValue* result)
REQUIRES_SHARED(Locks::mutator_lock_) {
StackHandleScope<1> hs(self);
@@ -718,7 +702,7 @@
// point because they would have been performed on our behalf at the point
// of creation of the method handle.
ArtMethod* target_method = method_handle->GetTargetMethod();
- uint32_t receiver_reg = is_range ? first_arg: args[0];
+ uint32_t receiver_reg = (operands->GetNumberOfOperands() > 0) ? operands->GetOperand(0) : 0u;
ArtMethod* called_method = RefineTargetMethod(self,
shadow_frame,
handle_kind,
@@ -743,24 +727,22 @@
Handle<mirror::MethodType> callee_type =
(handle_kind == mirror::MethodHandle::Kind::kInvokeCallSiteTransform) ? callsite_type
: handle_type;
- return MethodHandleInvokeTransform<is_range>(called_method,
- callsite_type,
- callee_type,
- self,
- shadow_frame,
- method_handle /* receiver */,
- args,
- first_arg,
- result);
+ return MethodHandleInvokeTransform(called_method,
+ callsite_type,
+ callee_type,
+ self,
+ shadow_frame,
+ method_handle /* receiver */,
+ operands,
+ result);
} else {
- return MethodHandleInvokeMethod<is_range>(called_method,
- callsite_type,
- handle_type,
- self,
- shadow_frame,
- args,
- first_arg,
- result);
+ return MethodHandleInvokeMethod(called_method,
+ callsite_type,
+ handle_type,
+ self,
+ shadow_frame,
+ operands,
+ result);
}
}
@@ -884,23 +866,21 @@
return field_value;
}
-template <bool is_range, bool do_conversions>
+template <bool do_conversions>
bool MethodHandleFieldAccess(Thread* self,
ShadowFrame& shadow_frame,
Handle<mirror::MethodHandle> method_handle,
Handle<mirror::MethodType> callsite_type,
- const uint32_t (&args)[Instruction::kMaxVarArgRegs],
- uint32_t first_arg,
+ const InstructionOperands* const operands,
JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
StackHandleScope<1> hs(self);
Handle<mirror::MethodType> handle_type(hs.NewHandle(method_handle->GetMethodType()));
const mirror::MethodHandle::Kind handle_kind = method_handle->GetHandleKind();
ArtField* field = method_handle->GetTargetField();
Primitive::Type field_type = field->GetTypeAsPrimitiveType();
-
switch (handle_kind) {
case mirror::MethodHandle::kInstanceGet: {
- size_t obj_reg = is_range ? first_arg : args[0];
+ size_t obj_reg = operands->GetOperand(0);
ObjPtr<mirror::Object> obj = shadow_frame.GetVRegReference(obj_reg);
MethodHandleFieldGet(self, shadow_frame, obj, field, field_type, result);
if (do_conversions && !ConvertReturnValue(callsite_type, handle_type, result)) {
@@ -923,8 +903,8 @@
return true;
}
case mirror::MethodHandle::kInstancePut: {
- size_t obj_reg = is_range ? first_arg : args[0];
- size_t value_reg = is_range ? (first_arg + 1) : args[1];
+ size_t obj_reg = operands->GetOperand(0);
+ size_t value_reg = operands->GetOperand(1);
const size_t kPTypeIndex = 1;
// Use ptypes instead of field type since we may be unboxing a reference for a primitive
// field. The field type is incorrect for this case.
@@ -948,7 +928,7 @@
DCHECK(self->IsExceptionPending());
return false;
}
- size_t value_reg = is_range ? first_arg : args[0];
+ size_t value_reg = operands->GetOperand(0);
const size_t kPTypeIndex = 0;
// Use ptypes instead of field type since we may be unboxing a reference for a primitive
// field. The field type is incorrect for this case.
@@ -971,13 +951,11 @@
}
}
-template <bool is_range>
static inline bool MethodHandleInvokeInternal(Thread* self,
ShadowFrame& shadow_frame,
Handle<mirror::MethodHandle> method_handle,
Handle<mirror::MethodType> callsite_type,
- const uint32_t (&args)[Instruction::kMaxVarArgRegs],
- uint32_t first_arg,
+ const InstructionOperands* const operands,
JValue* result)
REQUIRES_SHARED(Locks::mutator_lock_) {
const mirror::MethodHandle::Kind handle_kind = method_handle->GetHandleKind();
@@ -989,32 +967,28 @@
return false;
}
const bool do_convert = true;
- return MethodHandleFieldAccess<is_range, do_convert>(
+ return MethodHandleFieldAccess<do_convert>(
self,
shadow_frame,
method_handle,
callsite_type,
- args,
- first_arg,
+ operands,
result);
}
- return DoInvokePolymorphicMethod<is_range>(self,
- shadow_frame,
- method_handle,
- callsite_type,
- args,
- first_arg,
- result);
+ return DoInvokePolymorphicMethod(self,
+ shadow_frame,
+ method_handle,
+ callsite_type,
+ operands,
+ result);
}
-template <bool is_range>
static inline bool MethodHandleInvokeExactInternal(
Thread* self,
ShadowFrame& shadow_frame,
Handle<mirror::MethodHandle> method_handle,
Handle<mirror::MethodType> callsite_type,
- const uint32_t (&args)[Instruction::kMaxVarArgRegs],
- uint32_t first_arg,
+ const InstructionOperands* const operands,
JValue* result)
REQUIRES_SHARED(Locks::mutator_lock_) {
StackHandleScope<1> hs(self);
@@ -1027,29 +1001,27 @@
const mirror::MethodHandle::Kind handle_kind = method_handle->GetHandleKind();
if (IsFieldAccess(handle_kind)) {
const bool do_convert = false;
- return MethodHandleFieldAccess<is_range, do_convert>(self,
- shadow_frame,
- method_handle,
- callsite_type,
- args,
- first_arg,
- result);
+ return MethodHandleFieldAccess<do_convert>(self,
+ shadow_frame,
+ method_handle,
+ callsite_type,
+ operands,
+ result);
}
// Slow-path check.
if (IsInvokeTransform(handle_kind) || IsCallerTransformer(callsite_type)) {
- return DoInvokePolymorphicMethod<is_range>(self,
- shadow_frame,
- method_handle,
- callsite_type,
- args,
- first_arg,
- result);
+ return DoInvokePolymorphicMethod(self,
+ shadow_frame,
+ method_handle,
+ callsite_type,
+ operands,
+ result);
}
// On the fast-path. This is equivalent to DoCallPolymoprhic without the conversion paths.
ArtMethod* target_method = method_handle->GetTargetMethod();
- uint32_t receiver_reg = is_range ? first_arg : args[0];
+ uint32_t receiver_reg = (operands->GetNumberOfOperands() > 0) ? operands->GetOperand(0) : 0u;
ArtMethod* called_method = RefineTargetMethod(self,
shadow_frame,
handle_kind,
@@ -1085,12 +1057,10 @@
ShadowFrameAllocaUniquePtr shadow_frame_unique_ptr =
CREATE_SHADOW_FRAME(num_regs, &shadow_frame, called_method, /* dex pc */ 0);
ShadowFrame* new_shadow_frame = shadow_frame_unique_ptr.get();
- CopyArgumentsFromCallerFrame<is_range>(shadow_frame,
- new_shadow_frame,
- args,
- first_arg,
- first_dest_reg,
- num_input_regs);
+ CopyArgumentsFromCallerFrame(shadow_frame,
+ new_shadow_frame,
+ operands,
+ first_dest_reg);
self->EndAssertNoThreadSuspension(old_cause);
bool use_interpreter_entrypoint = ClassLinker::ShouldUseInterpreterEntrypoint(
@@ -1110,43 +1080,37 @@
} // namespace
-template <bool is_range>
-inline bool MethodHandleInvoke(Thread* self,
- ShadowFrame& shadow_frame,
- Handle<mirror::MethodHandle> method_handle,
- Handle<mirror::MethodType> callsite_type,
- const uint32_t (&args)[Instruction::kMaxVarArgRegs],
- uint32_t first_arg,
- JValue* result)
+bool MethodHandleInvoke(Thread* self,
+ ShadowFrame& shadow_frame,
+ Handle<mirror::MethodHandle> method_handle,
+ Handle<mirror::MethodType> callsite_type,
+ const InstructionOperands* const operands,
+ JValue* result)
REQUIRES_SHARED(Locks::mutator_lock_) {
if (UNLIKELY(callsite_type->IsExactMatch(method_handle->GetMethodType()))) {
// A non-exact invoke that can be invoked exactly.
- return MethodHandleInvokeExactInternal<is_range>(self,
- shadow_frame,
- method_handle,
- callsite_type,
- args,
- first_arg,
- result);
+ return MethodHandleInvokeExactInternal(self,
+ shadow_frame,
+ method_handle,
+ callsite_type,
+ operands,
+ result);
} else {
- return MethodHandleInvokeInternal<is_range>(self,
- shadow_frame,
- method_handle,
- callsite_type,
- args,
- first_arg,
- result);
+ return MethodHandleInvokeInternal(self,
+ shadow_frame,
+ method_handle,
+ callsite_type,
+ operands,
+ result);
}
}
-template <bool is_range>
bool MethodHandleInvokeExact(Thread* self,
- ShadowFrame& shadow_frame,
- Handle<mirror::MethodHandle> method_handle,
- Handle<mirror::MethodType> callsite_type,
- const uint32_t (&args)[Instruction::kMaxVarArgRegs],
- uint32_t first_arg,
- JValue* result)
+ ShadowFrame& shadow_frame,
+ Handle<mirror::MethodHandle> method_handle,
+ Handle<mirror::MethodType> callsite_type,
+ const InstructionOperands* const operands,
+ JValue* result)
REQUIRES_SHARED(Locks::mutator_lock_) {
// We need to check the nominal type of the handle in addition to the
// real type. The "nominal" type is present when MethodHandle.asType is
@@ -1160,39 +1124,20 @@
}
if (LIKELY(!nominal_type->IsExactMatch(method_handle->GetMethodType()))) {
// Different nominal type means we have to treat as non-exact.
- return MethodHandleInvokeInternal<is_range>(self,
- shadow_frame,
- method_handle,
- callsite_type,
- args,
- first_arg,
- result);
+ return MethodHandleInvokeInternal(self,
+ shadow_frame,
+ method_handle,
+ callsite_type,
+ operands,
+ result);
}
}
- return MethodHandleInvokeExactInternal<is_range>(self,
- shadow_frame,
- method_handle,
- callsite_type,
- args,
- first_arg,
- result);
+ return MethodHandleInvokeExactInternal(self,
+ shadow_frame,
+ method_handle,
+ callsite_type,
+ operands,
+ result);
}
-#define EXPLICIT_DO_METHOD_HANDLE_METHOD(_name, _is_range) \
- template REQUIRES_SHARED(Locks::mutator_lock_) \
- bool MethodHandle##_name<_is_range>( \
- Thread* self, \
- ShadowFrame& shadow_frame, \
- Handle<mirror::MethodHandle> method_handle, \
- Handle<mirror::MethodType> callsite_type, \
- const uint32_t (&args)[Instruction::kMaxVarArgRegs], \
- uint32_t first_arg, \
- JValue* result)
-
-EXPLICIT_DO_METHOD_HANDLE_METHOD(Invoke, true);
-EXPLICIT_DO_METHOD_HANDLE_METHOD(Invoke, false);
-EXPLICIT_DO_METHOD_HANDLE_METHOD(InvokeExact, true);
-EXPLICIT_DO_METHOD_HANDLE_METHOD(InvokeExact, false);
-#undef EXPLICIT_DO_METHOD_HANDLE_METHOD
-
} // namespace art
diff --git a/runtime/method_handles.h b/runtime/method_handles.h
index 930b8db..bc74bf2 100644
--- a/runtime/method_handles.h
+++ b/runtime/method_handles.h
@@ -126,50 +126,40 @@
int32_t num_conversions) REQUIRES_SHARED(Locks::mutator_lock_);
// A convenience class that allows for iteration through a list of
-// input argument registers |arg| for non-range invokes or a list of
-// consecutive registers starting with a given based for range
-// invokes.
-//
-// This is used to iterate over input arguments while performing standard
-// argument conversions.
-template <bool is_range>
+// input argument registers. This is used to iterate over input
+// arguments while performing standard argument conversions.
class ShadowFrameGetter {
public:
- ShadowFrameGetter(size_t first_src_reg,
- const uint32_t (&arg)[Instruction::kMaxVarArgRegs],
- const ShadowFrame& shadow_frame) :
- first_src_reg_(first_src_reg),
- arg_(arg),
- shadow_frame_(shadow_frame),
- arg_index_(0) {
- }
+ ShadowFrameGetter(const InstructionOperands* const operands, const ShadowFrame& shadow_frame)
+ : operands_(operands), operand_index_(0), shadow_frame_(shadow_frame) {}
ALWAYS_INLINE uint32_t Get() REQUIRES_SHARED(Locks::mutator_lock_) {
- const uint32_t next = (is_range ? first_src_reg_ + arg_index_ : arg_[arg_index_]);
- ++arg_index_;
-
- return shadow_frame_.GetVReg(next);
+ return shadow_frame_.GetVReg(Next());
}
ALWAYS_INLINE int64_t GetLong() REQUIRES_SHARED(Locks::mutator_lock_) {
- const uint32_t next = (is_range ? first_src_reg_ + arg_index_ : arg_[arg_index_]);
- arg_index_ += 2;
-
- return shadow_frame_.GetVRegLong(next);
+ return shadow_frame_.GetVRegLong(NextLong());
}
ALWAYS_INLINE ObjPtr<mirror::Object> GetReference() REQUIRES_SHARED(Locks::mutator_lock_) {
- const uint32_t next = (is_range ? first_src_reg_ + arg_index_ : arg_[arg_index_]);
- ++arg_index_;
-
- return shadow_frame_.GetVRegReference(next);
+ return shadow_frame_.GetVRegReference(Next());
}
private:
- const size_t first_src_reg_;
- const uint32_t (&arg_)[Instruction::kMaxVarArgRegs];
+ uint32_t Next() {
+ const uint32_t next = operands_->GetOperand(operand_index_);
+ operand_index_ += 1;
+ return next;
+ }
+ uint32_t NextLong() {
+ const uint32_t next = operands_->GetOperand(operand_index_);
+ operand_index_ += 2;
+ return next;
+ }
+
+ const InstructionOperands* const operands_;
+ size_t operand_index_; // the next register operand to read from frame
const ShadowFrame& shadow_frame_;
- size_t arg_index_;
};
// A convenience class that allows values to be written to a given shadow frame,
@@ -201,23 +191,19 @@
size_t arg_index_;
};
-template <bool is_range>
bool MethodHandleInvoke(Thread* self,
ShadowFrame& shadow_frame,
Handle<mirror::MethodHandle> method_handle,
Handle<mirror::MethodType> callsite_type,
- const uint32_t (&args)[Instruction::kMaxVarArgRegs],
- uint32_t first_arg,
+ const InstructionOperands* const args,
JValue* result)
REQUIRES_SHARED(Locks::mutator_lock_);
-template <bool is_range>
bool MethodHandleInvokeExact(Thread* self,
ShadowFrame& shadow_frame,
Handle<mirror::MethodHandle> method_handle,
Handle<mirror::MethodType> callsite_type,
- const uint32_t (&args)[Instruction::kMaxVarArgRegs],
- uint32_t first_arg,
+ const InstructionOperands* const args,
JValue* result)
REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/mirror/emulated_stack_frame.cc b/runtime/mirror/emulated_stack_frame.cc
index f82bfbf..5757992 100644
--- a/runtime/mirror/emulated_stack_frame.cc
+++ b/runtime/mirror/emulated_stack_frame.cc
@@ -139,14 +139,12 @@
DISALLOW_COPY_AND_ASSIGN(EmulatedStackFrameAccessor);
};
-template <bool is_range>
mirror::EmulatedStackFrame* EmulatedStackFrame::CreateFromShadowFrameAndArgs(
Thread* self,
Handle<mirror::MethodType> caller_type,
Handle<mirror::MethodType> callee_type,
const ShadowFrame& caller_frame,
- const uint32_t first_src_reg,
- const uint32_t (&arg)[Instruction::kMaxVarArgRegs]) {
+ const InstructionOperands* const operands) {
StackHandleScope<6> hs(self);
// Step 1: We must throw a WrongMethodTypeException if there's a mismatch in the
@@ -185,9 +183,9 @@
}
// Step 4 : Perform argument conversions (if required).
- ShadowFrameGetter<is_range> getter(first_src_reg, arg, caller_frame);
+ ShadowFrameGetter getter(operands, caller_frame);
EmulatedStackFrameAccessor setter(references, stack_frame, stack_frame->GetLength());
- if (!PerformConversions<ShadowFrameGetter<is_range>, EmulatedStackFrameAccessor>(
+ if (!PerformConversions<ShadowFrameGetter, EmulatedStackFrameAccessor>(
self, caller_type, callee_type, &getter, &setter, num_method_params)) {
return nullptr;
}
@@ -289,21 +287,5 @@
static_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass));
}
-// Explicit CreateFromShadowFrameAndArgs template function declarations.
-#define EXPLICIT_CREATE_FROM_SHADOW_FRAME_AND_ARGS_DECL(_is_range) \
- template REQUIRES_SHARED(Locks::mutator_lock_) \
- mirror::EmulatedStackFrame* EmulatedStackFrame::CreateFromShadowFrameAndArgs<_is_range>( \
- Thread* self, \
- Handle<mirror::MethodType> caller_type, \
- Handle<mirror::MethodType> callee_type, \
- const ShadowFrame& caller_frame, \
- const uint32_t first_src_reg, \
- const uint32_t (&arg)[Instruction::kMaxVarArgRegs]) \
-
-EXPLICIT_CREATE_FROM_SHADOW_FRAME_AND_ARGS_DECL(true);
-EXPLICIT_CREATE_FROM_SHADOW_FRAME_AND_ARGS_DECL(false);
-#undef EXPLICIT_CREATE_FROM_SHADOW_FRAME_AND_ARGS_DECL
-
-
} // namespace mirror
} // namespace art
diff --git a/runtime/mirror/emulated_stack_frame.h b/runtime/mirror/emulated_stack_frame.h
index 76859ef..b6aa949 100644
--- a/runtime/mirror/emulated_stack_frame.h
+++ b/runtime/mirror/emulated_stack_frame.h
@@ -35,14 +35,12 @@
public:
// Creates an emulated stack frame whose type is |frame_type| from
// a shadow frame.
- template <bool is_range>
static mirror::EmulatedStackFrame* CreateFromShadowFrameAndArgs(
Thread* self,
Handle<mirror::MethodType> args_type,
Handle<mirror::MethodType> frame_type,
const ShadowFrame& caller_frame,
- const uint32_t first_src_reg,
- const uint32_t (&arg)[Instruction::kMaxVarArgRegs]) REQUIRES_SHARED(Locks::mutator_lock_);
+ const InstructionOperands* const operands) REQUIRES_SHARED(Locks::mutator_lock_);
// Writes the contents of this emulated stack frame to the |callee_frame|
// whose type is |callee_type|, starting at |first_dest_reg|.
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index 4429ade..69bd46d 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -193,7 +193,7 @@
ret->PreLoad();
- if (kIsVdexEnabled && !ret->LoadVdex(vdex_filename, writable, low_4gb, error_msg)) {
+ if (!ret->LoadVdex(vdex_filename, writable, low_4gb, error_msg)) {
return nullptr;
}
@@ -233,7 +233,7 @@
std::string* error_msg) {
std::unique_ptr<OatFileBase> ret(new kOatFileBaseSubType(oat_location, executable));
- if (kIsVdexEnabled && !ret->LoadVdex(vdex_fd, vdex_location, writable, low_4gb, error_msg)) {
+ if (!ret->LoadVdex(vdex_fd, vdex_location, writable, low_4gb, error_msg)) {
return nullptr;
}
@@ -1275,7 +1275,7 @@
std::string vdex_filename = GetVdexFilename(oat_filename);
// Check that the files even exist, fast-fail.
- if (kIsVdexEnabled && !OS::FileExists(vdex_filename.c_str())) {
+ if (!OS::FileExists(vdex_filename.c_str())) {
*error_msg = StringPrintf("File %s does not exist.", vdex_filename.c_str());
return nullptr;
} else if (!OS::FileExists(oat_filename.c_str())) {
@@ -1427,11 +1427,11 @@
}
const uint8_t* OatFile::DexBegin() const {
- return kIsVdexEnabled ? vdex_->Begin() : Begin();
+ return vdex_->Begin();
}
const uint8_t* OatFile::DexEnd() const {
- return kIsVdexEnabled ? vdex_->End() : End();
+ return vdex_->End();
}
ArrayRef<ArtMethod*> OatFile::GetBssMethods() const {
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index 378ce2c..cd18ce1 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -99,28 +99,7 @@
<< " vdex_fd=" << vdex_fd;;
}
- // Try to get the realpath for the dex location.
- //
- // This is OK with respect to dalvik cache naming scheme because we never
- // generate oat files starting from symlinks which go into dalvik cache.
- // (recall that the oat files in dalvik cache are encoded by replacing '/'
- // with '@' in the path).
- // The boot image oat files (which are symlinked in dalvik-cache) are not
- // loaded via the oat file assistant.
- //
- // The only case when the dex location may resolve to a different path
- // is for secondary dex files (e.g. /data/user/0 symlinks to /data/data and
- // the app is free to create its own internal layout). Related to this it is
- // worthwhile to mention that installd resolves the secondary dex location
- // before calling dex2oat.
- UniqueCPtr<const char[]> dex_location_real(realpath(dex_location, nullptr));
- if (dex_location_real != nullptr) {
- dex_location_.assign(dex_location_real.get());
- } else {
- // If we can't get the realpath of the location there's not much point in trying to move on.
- PLOG(ERROR) << "Could not get the realpath of dex_location " << dex_location;
- return;
- }
+ dex_location_.assign(dex_location);
if (load_executable_ && isa != kRuntimeISA) {
LOG(WARNING) << "OatFileAssistant: Load executable specified, "
@@ -496,17 +475,10 @@
// Verify the dex checksum.
std::string error_msg;
- if (kIsVdexEnabled) {
- VdexFile* vdex = file.GetVdexFile();
- if (!DexChecksumUpToDate(*vdex, &error_msg)) {
- LOG(ERROR) << error_msg;
- return kOatDexOutOfDate;
- }
- } else {
- if (!DexChecksumUpToDate(file, &error_msg)) {
- LOG(ERROR) << error_msg;
- return kOatDexOutOfDate;
- }
+ VdexFile* vdex = file.GetVdexFile();
+ if (!DexChecksumUpToDate(*vdex, &error_msg)) {
+ LOG(ERROR) << error_msg;
+ return kOatDexOutOfDate;
}
CompilerFilter::Filter current_compiler_filter = file.GetCompilerFilter();
diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc
index 65d01a4..a98da0f 100644
--- a/runtime/oat_file_assistant_test.cc
+++ b/runtime/oat_file_assistant_test.cc
@@ -351,58 +351,9 @@
EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
}
-// Case: We have a DEX file and up-to-date OAT file for it. We load the dex file
-// via a symlink.
-// Expect: The status is kNoDexOptNeeded.
-TEST_F(OatFileAssistantTest, OatUpToDateSymLink) {
- if (IsExecutedAsRoot()) {
- // We cannot simulate non writable locations when executed as root: b/38000545.
- LOG(ERROR) << "Test skipped because it's running as root";
- return;
- }
-
- std::string real = GetScratchDir() + "/real";
- ASSERT_EQ(0, mkdir(real.c_str(), 0700));
- std::string link = GetScratchDir() + "/link";
- ASSERT_EQ(0, symlink(real.c_str(), link.c_str()));
-
- std::string dex_location = real + "/OatUpToDate.jar";
-
- Copy(GetDexSrc1(), dex_location);
- GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
-
- // Update the dex location to point to the symlink.
- dex_location = link + "/OatUpToDate.jar";
-
- // For the use of oat location by making the dex parent not writable.
- ScopedNonWritable scoped_non_writable(dex_location);
- ASSERT_TRUE(scoped_non_writable.IsSuccessful());
-
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
-
- EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
- EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kQuicken));
- EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kExtract));
- EXPECT_EQ(OatFileAssistant::kDex2OatForFilter,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kEverything));
-
- EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
- EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OatFileStatus());
- EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
-}
-
// Case: We have a DEX file and up-to-date (ODEX) VDEX file for it, but no
// ODEX file.
TEST_F(OatFileAssistantTest, VdexUpToDateNoOdex) {
- // This test case is only meaningful if vdex is enabled.
- if (!kIsVdexEnabled) {
- return;
- }
-
std::string dex_location = GetScratchDir() + "/VdexUpToDateNoOdex.jar";
std::string odex_location = GetOdexDir() + "/VdexUpToDateNoOdex.oat";
@@ -446,10 +397,6 @@
// Case: We have a DEX file and up-to-date (OAT) VDEX file for it, but no OAT
// file.
TEST_F(OatFileAssistantTest, VdexUpToDateNoOat) {
- // This test case is only meaningful if vdex is enabled.
- if (!kIsVdexEnabled) {
- return;
- }
if (IsExecutedAsRoot()) {
// We cannot simulate non writable locations when executed as root: b/38000545.
LOG(ERROR) << "Test skipped because it's running as root";
@@ -668,11 +615,6 @@
// Case: We have a DEX file and an (ODEX) VDEX file out of date with respect
// to the dex checksum, but no ODEX file.
TEST_F(OatFileAssistantTest, VdexDexOutOfDate) {
- // This test case is only meaningful if vdex is enabled.
- if (!kIsVdexEnabled) {
- return;
- }
-
std::string dex_location = GetScratchDir() + "/VdexDexOutOfDate.jar";
std::string odex_location = GetOdexDir() + "/VdexDexOutOfDate.oat";
@@ -690,11 +632,6 @@
// Case: We have a MultiDEX (ODEX) VDEX file where the non-main multidex entry
// is out of date and there is no corresponding ODEX file.
TEST_F(OatFileAssistantTest, VdexMultiDexNonMainOutOfDate) {
- // This test case is only meaningful if vdex is enabled.
- if (!kIsVdexEnabled) {
- return;
- }
-
std::string dex_location = GetScratchDir() + "/VdexMultiDexNonMainOutOfDate.jar";
std::string odex_location = GetOdexDir() + "/VdexMultiDexNonMainOutOfDate.odex";
diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc
index ee35d9c..3071348 100644
--- a/runtime/oat_file_manager.cc
+++ b/runtime/oat_file_manager.cc
@@ -144,6 +144,9 @@
return nullptr;
}
+OatFileManager::OatFileManager()
+ : have_non_pic_oat_file_(false), only_use_system_oat_files_(false) {}
+
OatFileManager::~OatFileManager() {
// Explicitly clear oat_files_ since the OatFile destructor calls back into OatFileManager for
// UnRegisterOatFileLocation.
diff --git a/runtime/oat_file_manager.h b/runtime/oat_file_manager.h
index 1205773..dd6b7ba 100644
--- a/runtime/oat_file_manager.h
+++ b/runtime/oat_file_manager.h
@@ -45,7 +45,7 @@
// pointers returned from functions are always valid.
class OatFileManager {
public:
- OatFileManager() : have_non_pic_oat_file_(false), only_use_system_oat_files_(false) {}
+ OatFileManager();
~OatFileManager();
// Add an oat file to the internal accounting, std::aborts if there already exists an oat file
diff --git a/runtime/standard_dex_file.cc b/runtime/standard_dex_file.cc
index 36bb37a..4c1d308 100644
--- a/runtime/standard_dex_file.cc
+++ b/runtime/standard_dex_file.cc
@@ -31,6 +31,16 @@
{'0', '3', '9', '\0'},
};
+void StandardDexFile::WriteMagic(uint8_t* magic) {
+ std::copy_n(kDexMagic, kDexMagicSize, magic);
+}
+
+void StandardDexFile::WriteCurrentVersion(uint8_t* magic) {
+ std::copy_n(kDexMagicVersions[StandardDexFile::kDexVersionLen - 1],
+ kDexVersionLen,
+ magic + kDexMagicSize);
+}
+
bool StandardDexFile::IsMagicValid(const uint8_t* magic) {
return (memcmp(magic, kDexMagic, sizeof(kDexMagic)) == 0);
}
diff --git a/runtime/standard_dex_file.h b/runtime/standard_dex_file.h
index 784ab31..5d53597 100644
--- a/runtime/standard_dex_file.h
+++ b/runtime/standard_dex_file.h
@@ -32,6 +32,18 @@
// Same for now.
};
+ struct CodeItem : public DexFile::CodeItem {
+ private:
+ // TODO: Insert standard dex specific fields here.
+ DISALLOW_COPY_AND_ASSIGN(CodeItem);
+ };
+
+ // Write the standard dex specific magic.
+ static void WriteMagic(uint8_t* magic);
+
+ // Write the current version, note that the input is the address of the magic.
+ static void WriteCurrentVersion(uint8_t* magic);
+
static const uint8_t kDexMagic[kDexMagicSize];
static constexpr size_t kNumDexVersions = 4;
static const uint8_t kDexMagicVersions[kNumDexVersions][kDexVersionLen];
@@ -44,10 +56,6 @@
static bool IsVersionValid(const uint8_t* magic);
virtual bool IsVersionValid() const OVERRIDE;
- bool IsStandardDexFile() const OVERRIDE {
- return true;
- }
-
private:
StandardDexFile(const uint8_t* base,
size_t size,
@@ -55,7 +63,13 @@
uint32_t location_checksum,
const OatDexFile* oat_dex_file,
DexFileContainer* container)
- : DexFile(base, size, location, location_checksum, oat_dex_file, container) {}
+ : DexFile(base,
+ size,
+ location,
+ location_checksum,
+ oat_dex_file,
+ container,
+ /*is_compact_dex*/ false) {}
friend class DexFileLoader;
friend class DexFileVerifierTest;
diff --git a/runtime/verifier/method_verifier-inl.h b/runtime/verifier/method_verifier-inl.h
index 9bb875c..a7fa9f3 100644
--- a/runtime/verifier/method_verifier-inl.h
+++ b/runtime/verifier/method_verifier-inl.h
@@ -27,10 +27,6 @@
namespace art {
namespace verifier {
-inline const DexFile::CodeItem* MethodVerifier::CodeItem() const {
- return code_item_;
-}
-
inline RegisterLine* MethodVerifier::GetRegLine(uint32_t dex_pc) {
return reg_table_.GetLine(dex_pc);
}
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 121f3cf..a75157d 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -564,7 +564,7 @@
dex_cache_(dex_cache),
class_loader_(class_loader),
class_def_(class_def),
- code_item_(code_item),
+ code_item_accessor_(CodeItemDataAccessor::CreateNullable(dex_file, code_item)),
declaring_class_(nullptr),
interesting_dex_pc_(-1),
monitor_enter_dex_pcs_(nullptr),
@@ -616,29 +616,21 @@
verifier.FindLocksAtDexPc();
}
-static bool HasMonitorEnterInstructions(const DexFile::CodeItem* const code_item) {
- for (const DexInstructionPcPair& inst : code_item->Instructions()) {
- if (inst->Opcode() == Instruction::MONITOR_ENTER) {
- return true;
- }
- }
- return false;
-}
-
void MethodVerifier::FindLocksAtDexPc() {
CHECK(monitor_enter_dex_pcs_ != nullptr);
- CHECK(code_item_ != nullptr); // This only makes sense for methods with code.
+ CHECK(code_item_accessor_.HasCodeItem()); // This only makes sense for methods with code.
- // Quick check whether there are any monitor_enter instructions at all.
- if (!HasMonitorEnterInstructions(code_item_)) {
- return;
+ // Quick check whether there are any monitor_enter instructions before verifying.
+ for (const DexInstructionPcPair& inst : code_item_accessor_) {
+ if (inst->Opcode() == Instruction::MONITOR_ENTER) {
+ // Strictly speaking, we ought to be able to get away with doing a subset of the full method
+ // verification. In practice, the phase we want relies on data structures set up by all the
+ // earlier passes, so we just run the full method verification and bail out early when we've
+ // got what we wanted.
+ Verify();
+ return;
+ }
}
-
- // Strictly speaking, we ought to be able to get away with doing a subset of the full method
- // verification. In practice, the phase we want relies on data structures set up by all the
- // earlier passes, so we just run the full method verification and bail out early when we've
- // got what we wanted.
- Verify();
}
ArtField* MethodVerifier::FindAccessedFieldAtDexPc(ArtMethod* m, uint32_t dex_pc) {
@@ -663,7 +655,7 @@
}
ArtField* MethodVerifier::FindAccessedFieldAtDexPc(uint32_t dex_pc) {
- CHECK(code_item_ != nullptr); // This only makes sense for methods with code.
+ CHECK(code_item_accessor_.HasCodeItem()); // This only makes sense for methods with code.
// Strictly speaking, we ought to be able to get away with doing a subset of the full method
// verification. In practice, the phase we want relies on data structures set up by all the
@@ -677,7 +669,7 @@
if (register_line == nullptr) {
return nullptr;
}
- const Instruction* inst = &code_item_->InstructionAt(dex_pc);
+ const Instruction* inst = &code_item_accessor_.InstructionAt(dex_pc);
return GetQuickFieldAccess(inst, register_line);
}
@@ -703,7 +695,7 @@
}
ArtMethod* MethodVerifier::FindInvokedMethodAtDexPc(uint32_t dex_pc) {
- CHECK(code_item_ != nullptr); // This only makes sense for methods with code.
+ CHECK(code_item_accessor_.HasCodeItem()); // This only makes sense for methods with code.
// Strictly speaking, we ought to be able to get away with doing a subset of the full method
// verification. In practice, the phase we want relies on data structures set up by all the
@@ -717,7 +709,7 @@
if (register_line == nullptr) {
return nullptr;
}
- const Instruction* inst = &code_item_->InstructionAt(dex_pc);
+ const Instruction* inst = &code_item_accessor_.InstructionAt(dex_pc);
const bool is_range = (inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE_QUICK);
return GetQuickInvokedMethod(inst, register_line, is_range, false);
}
@@ -769,7 +761,7 @@
}
// If there aren't any instructions, make sure that's expected, then exit successfully.
- if (code_item_ == nullptr) {
+ if (!code_item_accessor_.HasCodeItem()) {
// Only native or abstract methods may not have code.
if ((method_access_flags_ & (kAccNative | kAccAbstract)) == 0) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "zero-length code in concrete non-native method";
@@ -861,17 +853,19 @@
}
// Sanity-check the register counts. ins + locals = registers, so make sure that ins <= registers.
- if (code_item_->ins_size_ > code_item_->registers_size_) {
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "bad register counts (ins=" << code_item_->ins_size_
- << " regs=" << code_item_->registers_size_;
+ if (code_item_accessor_.InsSize() > code_item_accessor_.RegistersSize()) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "bad register counts (ins="
+ << code_item_accessor_.InsSize()
+ << " regs=" << code_item_accessor_.RegistersSize();
return false;
}
// Allocate and initialize an array to hold instruction data.
- insn_flags_.reset(allocator_.AllocArray<InstructionFlags>(code_item_->insns_size_in_code_units_));
+ insn_flags_.reset(allocator_.AllocArray<InstructionFlags>(
+ code_item_accessor_.InsnsSizeInCodeUnits()));
DCHECK(insn_flags_ != nullptr);
std::uninitialized_fill_n(insn_flags_.get(),
- code_item_->insns_size_in_code_units_,
+ code_item_accessor_.InsnsSizeInCodeUnits(),
InstructionFlags());
// Run through the instructions and see if the width checks out.
bool result = ComputeWidthsAndCountOps();
@@ -923,7 +917,7 @@
// Note: this can fail before we touch any instruction, for the signature of a method. So
// add a check.
if (work_insn_idx_ < dex::kDexNoIndex) {
- const Instruction& inst = code_item_->InstructionAt(work_insn_idx_);
+ const Instruction& inst = code_item_accessor_.InstructionAt(work_insn_idx_);
int opcode_flags = Instruction::FlagsOf(inst.Opcode());
if ((opcode_flags & Instruction::kThrow) == 0 && CurrentInsnFlags()->IsInTry()) {
@@ -986,15 +980,14 @@
size_t new_instance_count = 0;
size_t monitor_enter_count = 0;
- IterationRange<DexInstructionIterator> instructions = code_item_->Instructions();
// We can't assume the instruction is well formed, handle the case where calculating the size
// goes past the end of the code item.
- SafeDexInstructionIterator it(instructions.begin(), instructions.end());
- for ( ; !it.IsErrorState() && it < instructions.end(); ++it) {
+ SafeDexInstructionIterator it(code_item_accessor_.begin(), code_item_accessor_.end());
+ for ( ; !it.IsErrorState() && it < code_item_accessor_.end(); ++it) {
// In case the instruction goes past the end of the code item, make sure to not process it.
SafeDexInstructionIterator next = it;
++next;
- if (next.IsErrorState() || next > instructions.end()) {
+ if (next.IsErrorState()) {
break;
}
Instruction::Code opcode = it->Opcode();
@@ -1021,8 +1014,8 @@
GetInstructionFlags(it.DexPc()).SetIsOpcode();
}
- if (it != instructions.end()) {
- const size_t insns_size = code_item_->insns_size_in_code_units_;
+ if (it != code_item_accessor_.end()) {
+ const size_t insns_size = code_item_accessor_.InsnsSizeInCodeUnits();
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "code did not end where expected ("
<< it.DexPc() << " vs. " << insns_size << ")";
return false;
@@ -1034,17 +1027,14 @@
}
bool MethodVerifier::ScanTryCatchBlocks() {
- uint32_t tries_size = code_item_->tries_size_;
+ const uint32_t tries_size = code_item_accessor_.TriesSize();
if (tries_size == 0) {
return true;
}
- uint32_t insns_size = code_item_->insns_size_in_code_units_;
- const DexFile::TryItem* tries = DexFile::GetTryItems(*code_item_, 0);
-
- for (uint32_t idx = 0; idx < tries_size; idx++) {
- const DexFile::TryItem* try_item = &tries[idx];
- uint32_t start = try_item->start_addr_;
- uint32_t end = start + try_item->insn_count_;
+ const uint32_t insns_size = code_item_accessor_.InsnsSizeInCodeUnits();
+ for (const DexFile::TryItem& try_item : code_item_accessor_.TryItems()) {
+ const uint32_t start = try_item.start_addr_;
+ const uint32_t end = start + try_item.insn_count_;
if ((start >= end) || (start >= insns_size) || (end > insns_size)) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "bad exception entry: startAddr=" << start
<< " endAddr=" << end << " (size=" << insns_size << ")";
@@ -1055,18 +1045,14 @@
<< "'try' block starts inside an instruction (" << start << ")";
return false;
}
- uint32_t dex_pc = start;
- const Instruction* inst = Instruction::At(code_item_->insns_ + dex_pc);
- while (dex_pc < end) {
- GetInstructionFlags(dex_pc).SetInTry();
- size_t insn_size = inst->SizeInCodeUnits();
- dex_pc += insn_size;
- inst = inst->RelativeAt(insn_size);
+ DexInstructionIterator end_it(code_item_accessor_.Insns(), end);
+ for (DexInstructionIterator it(code_item_accessor_.Insns(), start); it < end_it; ++it) {
+ GetInstructionFlags(it.DexPc()).SetInTry();
}
}
// Iterate over each of the handlers to verify target addresses.
- const uint8_t* handlers_ptr = DexFile::GetCatchHandlerData(*code_item_, 0);
- uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
+ const uint8_t* handlers_ptr = code_item_accessor_.GetCatchHandlerData();
+ const uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
ClassLinker* linker = Runtime::Current()->GetClassLinker();
for (uint32_t idx = 0; idx < handlers_size; idx++) {
CatchHandlerIterator iterator(handlers_ptr);
@@ -1077,7 +1063,7 @@
<< "exception handler starts at bad address (" << dex_pc << ")";
return false;
}
- if (!CheckNotMoveResult(code_item_->insns_, dex_pc)) {
+ if (!CheckNotMoveResult(code_item_accessor_.Insns(), dex_pc)) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD)
<< "exception handler begins with move-result* (" << dex_pc << ")";
return false;
@@ -1105,7 +1091,7 @@
/* Flag the start of the method as a branch target, and a GC point due to stack overflow errors */
GetInstructionFlags(0).SetBranchTarget();
GetInstructionFlags(0).SetCompileTimeInfoPoint();
- for (const DexInstructionPcPair& inst : code_item_->Instructions()) {
+ for (const DexInstructionPcPair& inst : code_item_accessor_) {
const uint32_t dex_pc = inst.DexPc();
if (!VerifyInstruction<kAllowRuntimeOnlyInstructions>(&inst.Inst(), dex_pc)) {
DCHECK_NE(failures_.size(), 0U);
@@ -1259,18 +1245,18 @@
}
inline bool MethodVerifier::CheckRegisterIndex(uint32_t idx) {
- if (UNLIKELY(idx >= code_item_->registers_size_)) {
+ if (UNLIKELY(idx >= code_item_accessor_.RegistersSize())) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "register index out of range (" << idx << " >= "
- << code_item_->registers_size_ << ")";
+ << code_item_accessor_.RegistersSize() << ")";
return false;
}
return true;
}
inline bool MethodVerifier::CheckWideRegisterIndex(uint32_t idx) {
- if (UNLIKELY(idx + 1 >= code_item_->registers_size_)) {
+ if (UNLIKELY(idx + 1 >= code_item_accessor_.RegistersSize())) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "wide register index out of range (" << idx
- << "+1 >= " << code_item_->registers_size_ << ")";
+ << "+1 >= " << code_item_accessor_.RegistersSize() << ")";
return false;
}
return true;
@@ -1387,8 +1373,8 @@
}
bool MethodVerifier::CheckArrayData(uint32_t cur_offset) {
- const uint32_t insn_count = code_item_->insns_size_in_code_units_;
- const uint16_t* insns = code_item_->insns_ + cur_offset;
+ const uint32_t insn_count = code_item_accessor_.InsnsSizeInCodeUnits();
+ const uint16_t* insns = code_item_accessor_.Insns() + cur_offset;
const uint16_t* array_data;
int32_t array_data_offset;
@@ -1451,10 +1437,9 @@
<< reinterpret_cast<void*>(cur_offset) << " +" << offset;
return false;
}
- const uint32_t insn_count = code_item_->insns_size_in_code_units_;
int32_t abs_offset = cur_offset + offset;
if (UNLIKELY(abs_offset < 0 ||
- (uint32_t) abs_offset >= insn_count ||
+ (uint32_t) abs_offset >= code_item_accessor_.InsnsSizeInCodeUnits() ||
!GetInstructionFlags(abs_offset).IsOpcode())) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid branch target " << offset << " (-> "
<< reinterpret_cast<void*>(abs_offset) << ") at "
@@ -1467,7 +1452,7 @@
bool MethodVerifier::GetBranchOffset(uint32_t cur_offset, int32_t* pOffset, bool* pConditional,
bool* selfOkay) {
- const uint16_t* insns = code_item_->insns_ + cur_offset;
+ const uint16_t* insns = code_item_accessor_.Insns() + cur_offset;
*pConditional = false;
*selfOkay = false;
switch (*insns & 0xff) {
@@ -1503,9 +1488,9 @@
}
bool MethodVerifier::CheckSwitchTargets(uint32_t cur_offset) {
- const uint32_t insn_count = code_item_->insns_size_in_code_units_;
+ const uint32_t insn_count = code_item_accessor_.InsnsSizeInCodeUnits();
DCHECK_LT(cur_offset, insn_count);
- const uint16_t* insns = code_item_->insns_ + cur_offset;
+ const uint16_t* insns = code_item_accessor_.Insns() + cur_offset;
/* make sure the start of the switch is in range */
int32_t switch_offset = insns[1] | (static_cast<int32_t>(insns[2]) << 16);
if (UNLIKELY(static_cast<int32_t>(cur_offset) + switch_offset < 0 ||
@@ -1610,7 +1595,7 @@
}
bool MethodVerifier::CheckVarArgRegs(uint32_t vA, uint32_t arg[]) {
- uint16_t registers_size = code_item_->registers_size_;
+ uint16_t registers_size = code_item_accessor_.RegistersSize();
for (uint32_t idx = 0; idx < vA; idx++) {
if (UNLIKELY(arg[idx] >= registers_size)) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid reg index (" << arg[idx]
@@ -1623,7 +1608,7 @@
}
bool MethodVerifier::CheckVarArgRangeRegs(uint32_t vA, uint32_t vC) {
- uint16_t registers_size = code_item_->registers_size_;
+ uint16_t registers_size = code_item_accessor_.RegistersSize();
// vA/vC are unsigned 8-bit/16-bit quantities for /range instructions, so there's no risk of
// integer overflow when adding them here.
if (UNLIKELY(vA + vC > registers_size)) {
@@ -1635,13 +1620,12 @@
}
bool MethodVerifier::VerifyCodeFlow() {
- uint16_t registers_size = code_item_->registers_size_;
- uint32_t insns_size = code_item_->insns_size_in_code_units_;
+ const uint16_t registers_size = code_item_accessor_.RegistersSize();
/* Create and initialize table holding register status */
reg_table_.Init(kTrackCompilerInterestPoints,
insn_flags_.get(),
- insns_size,
+ code_item_accessor_.InsnsSizeInCodeUnits(),
registers_size,
this);
@@ -1681,7 +1665,7 @@
}
void MethodVerifier::Dump(VariableIndentationOutputStream* vios) {
- if (code_item_ == nullptr) {
+ if (!code_item_accessor_.HasCodeItem()) {
vios->Stream() << "Native method\n";
return;
}
@@ -1693,7 +1677,7 @@
vios->Stream() << "Dumping instructions and register lines:\n";
ScopedIndentation indent1(vios);
- for (const DexInstructionPcPair& inst : code_item_->Instructions()) {
+ for (const DexInstructionPcPair& inst : code_item_accessor_) {
const size_t dex_pc = inst.DexPc();
RegisterLine* reg_line = reg_table_.GetLine(dex_pc);
if (reg_line != nullptr) {
@@ -1729,10 +1713,10 @@
RegisterLine* reg_line = reg_table_.GetLine(0);
// Should have been verified earlier.
- DCHECK_GE(code_item_->registers_size_, code_item_->ins_size_);
+ DCHECK_GE(code_item_accessor_.RegistersSize(), code_item_accessor_.InsSize());
- uint32_t arg_start = code_item_->registers_size_ - code_item_->ins_size_;
- size_t expected_args = code_item_->ins_size_; /* long/double count as two */
+ uint32_t arg_start = code_item_accessor_.RegistersSize() - code_item_accessor_.InsSize();
+ size_t expected_args = code_item_accessor_.InsSize(); /* long/double count as two */
// Include the "this" pointer.
size_t cur_arg = 0;
@@ -1884,8 +1868,8 @@
}
bool MethodVerifier::CodeFlowVerifyMethod() {
- const uint16_t* insns = code_item_->insns_;
- const uint32_t insns_size = code_item_->insns_size_in_code_units_;
+ const uint16_t* insns = code_item_accessor_.Insns();
+ const uint32_t insns_size = code_item_accessor_.InsnsSizeInCodeUnits();
/* Begin by marking the first instruction as "changed". */
GetInstructionFlags(0).SetChanged();
@@ -1960,7 +1944,7 @@
*/
int dead_start = -1;
- for (const DexInstructionPcPair& inst : code_item_->Instructions()) {
+ for (const DexInstructionPcPair& inst : code_item_accessor_) {
const uint32_t insn_idx = inst.DexPc();
/*
* Switch-statement data doesn't get "visited" by scanner. It
@@ -1989,7 +1973,7 @@
if (dead_start >= 0) {
LogVerifyInfo()
<< "dead code " << reinterpret_cast<void*>(dead_start)
- << "-" << reinterpret_cast<void*>(code_item_->insns_size_in_code_units_ - 1);
+ << "-" << reinterpret_cast<void*>(code_item_accessor_.InsnsSizeInCodeUnits() - 1);
}
// To dump the state of the verify after a method, do something like:
// if (dex_file_->PrettyMethod(dex_method_idx_) ==
@@ -2075,7 +2059,7 @@
*
* The behavior can be determined from the opcode flags.
*/
- const uint16_t* insns = code_item_->insns_ + work_insn_idx_;
+ const uint16_t* insns = code_item_accessor_.Insns() + work_insn_idx_;
const Instruction* inst = Instruction::At(insns);
int opcode_flags = Instruction::FlagsOf(inst->Opcode());
@@ -2375,7 +2359,7 @@
while (0 != prev_idx && !GetInstructionFlags(prev_idx).IsOpcode()) {
prev_idx--;
}
- const Instruction& prev_inst = code_item_->InstructionAt(prev_idx);
+ const Instruction& prev_inst = code_item_accessor_.InstructionAt(prev_idx);
switch (prev_inst.Opcode()) {
case Instruction::MOVE_OBJECT:
case Instruction::MOVE_OBJECT_16:
@@ -2683,7 +2667,7 @@
break;
}
- const Instruction& instance_of_inst = code_item_->InstructionAt(instance_of_idx);
+ const Instruction& instance_of_inst = code_item_accessor_.InstructionAt(instance_of_idx);
/* Check for peep-hole pattern of:
* ...;
@@ -2722,7 +2706,8 @@
(orig_type.IsZero() ||
orig_type.IsStrictlyAssignableFrom(
cast_type.Merge(orig_type, ®_types_, this), this))) {
- RegisterLine* update_line = RegisterLine::Create(code_item_->registers_size_, this);
+ RegisterLine* update_line = RegisterLine::Create(code_item_accessor_.RegistersSize(),
+ this);
if (inst->Opcode() == Instruction::IF_EQZ) {
fallthrough_line.reset(update_line);
} else {
@@ -2745,7 +2730,7 @@
work_insn_idx_)) {
break;
}
- const Instruction& move_inst = code_item_->InstructionAt(move_idx);
+ const Instruction& move_inst = code_item_accessor_.InstructionAt(move_idx);
switch (move_inst.Opcode()) {
case Instruction::MOVE_OBJECT:
if (move_inst.VRegA_12x() == instance_of_inst.VRegB_22c()) {
@@ -3564,7 +3549,8 @@
return false;
}
DCHECK_EQ(isConditional, (opcode_flags & Instruction::kContinue) != 0);
- if (!CheckNotMoveExceptionOrMoveResult(code_item_->insns_, work_insn_idx_ + branch_target)) {
+ if (!CheckNotMoveExceptionOrMoveResult(code_item_accessor_.Insns(),
+ work_insn_idx_ + branch_target)) {
return false;
}
/* update branch target, set "changed" if appropriate */
@@ -3609,8 +3595,8 @@
offset = switch_insns[offset_to_targets + targ * 2] |
(static_cast<int32_t>(switch_insns[offset_to_targets + targ * 2 + 1]) << 16);
abs_offset = work_insn_idx_ + offset;
- DCHECK_LT(abs_offset, code_item_->insns_size_in_code_units_);
- if (!CheckNotMoveExceptionOrMoveResult(code_item_->insns_, abs_offset)) {
+ DCHECK_LT(abs_offset, code_item_accessor_.InsnsSizeInCodeUnits());
+ if (!CheckNotMoveExceptionOrMoveResult(code_item_accessor_.Insns(), abs_offset)) {
return false;
}
if (!UpdateRegisters(abs_offset, work_line_.get(), false)) {
@@ -3625,7 +3611,9 @@
*/
if ((opcode_flags & Instruction::kThrow) != 0 && GetInstructionFlags(work_insn_idx_).IsInTry()) {
bool has_catch_all_handler = false;
- CatchHandlerIterator iterator(*code_item_, work_insn_idx_);
+ const DexFile::TryItem* try_item = code_item_accessor_.FindTryItem(work_insn_idx_);
+ CHECK(try_item != nullptr);
+ CatchHandlerIterator iterator(code_item_accessor_.GetCatchHandlerData(try_item->handler_off_));
// Need the linker to try and resolve the handled class to check if it's Throwable.
ClassLinker* linker = Runtime::Current()->GetClassLinker();
@@ -3682,15 +3670,15 @@
* and this change should not be used in those cases.
*/
if ((opcode_flags & Instruction::kContinue) != 0) {
- DCHECK_EQ(&code_item_->InstructionAt(work_insn_idx_), inst);
+ DCHECK_EQ(&code_item_accessor_.InstructionAt(work_insn_idx_), inst);
uint32_t next_insn_idx = work_insn_idx_ + inst->SizeInCodeUnits();
- if (next_insn_idx >= code_item_->insns_size_in_code_units_) {
+ if (next_insn_idx >= code_item_accessor_.InsnsSizeInCodeUnits()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Execution can walk off end of code area";
return false;
}
// The only way to get to a move-exception instruction is to get thrown there. Make sure the
// next instruction isn't one.
- if (!CheckNotMoveException(code_item_->insns_, next_insn_idx)) {
+ if (!CheckNotMoveException(code_item_accessor_.Insns(), next_insn_idx)) {
return false;
}
if (nullptr != fallthrough_line) {
@@ -3699,7 +3687,7 @@
}
if (GetInstructionFlags(next_insn_idx).IsReturn()) {
// For returns we only care about the operand to the return, all other registers are dead.
- const Instruction* ret_inst = Instruction::At(code_item_->insns_ + next_insn_idx);
+ const Instruction* ret_inst = &code_item_accessor_.InstructionAt(next_insn_idx);
AdjustReturnLine(this, ret_inst, work_line_.get());
}
RegisterLine* next_line = reg_table_.GetLine(next_insn_idx);
@@ -3731,14 +3719,14 @@
* alone and let the caller sort it out.
*/
if ((opcode_flags & Instruction::kContinue) != 0) {
- DCHECK_EQ(Instruction::At(code_item_->insns_ + work_insn_idx_), inst);
+ DCHECK_EQ(&code_item_accessor_.InstructionAt(work_insn_idx_), inst);
*start_guess = work_insn_idx_ + inst->SizeInCodeUnits();
} else if ((opcode_flags & Instruction::kBranch) != 0) {
/* we're still okay if branch_target is zero */
*start_guess = work_insn_idx_ + branch_target;
}
- DCHECK_LT(*start_guess, code_item_->insns_size_in_code_units_);
+ DCHECK_LT(*start_guess, code_item_accessor_.InsnsSizeInCodeUnits());
DCHECK(GetInstructionFlags(*start_guess).IsOpcode());
if (have_pending_runtime_throw_failure_) {
@@ -3821,8 +3809,8 @@
const RegType& MethodVerifier::GetCaughtExceptionType() {
const RegType* common_super = nullptr;
- if (code_item_->tries_size_ != 0) {
- const uint8_t* handlers_ptr = DexFile::GetCatchHandlerData(*code_item_, 0);
+ if (code_item_accessor_.TriesSize() != 0) {
+ const uint8_t* handlers_ptr = code_item_accessor_.GetCatchHandlerData();
uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
for (uint32_t i = 0; i < handlers_size; i++) {
CatchHandlerIterator iterator(handlers_ptr);
@@ -4041,9 +4029,10 @@
/* caught by static verifier */
DCHECK(is_range || expected_args <= 5);
- if (expected_args > code_item_->outs_size_) {
+ if (expected_args > code_item_accessor_.OutsSize()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid argument count (" << expected_args
- << ") exceeds outsSize (" << code_item_->outs_size_ << ")";
+ << ") exceeds outsSize ("
+ << code_item_accessor_.OutsSize() << ")";
return nullptr;
}
@@ -4554,9 +4543,9 @@
const size_t expected_args = (is_range) ? inst->VRegA_3rc() : inst->VRegA_35c();
/* caught by static verifier */
DCHECK(is_range || expected_args <= 5);
- if (expected_args > code_item_->outs_size_) {
+ if (expected_args > code_item_accessor_.OutsSize()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid argument count (" << expected_args
- << ") exceeds outsSize (" << code_item_->outs_size_ << ")";
+ << ") exceeds outsSize (" << code_item_accessor_.OutsSize() << ")";
return nullptr;
}
@@ -5142,8 +5131,7 @@
}
}
-ArtField* MethodVerifier::GetQuickFieldAccess(const Instruction* inst,
- RegisterLine* reg_line) {
+ArtField* MethodVerifier::GetQuickFieldAccess(const Instruction* inst, RegisterLine* reg_line) {
DCHECK(IsInstructionIGetQuickOrIPutQuick(inst->Opcode())) << inst->Opcode();
const RegType& object_type = reg_line->GetRegisterType(this, inst->VRegB_22c());
if (!object_type.HasClass()) {
@@ -5330,7 +5318,7 @@
// For returns we only care about the operand to the return, all other registers are dead.
// Initialize them as conflicts so they don't add to GC and deoptimization information.
- const Instruction* ret_inst = Instruction::At(code_item_->insns_ + next_insn);
+ const Instruction* ret_inst = &code_item_accessor_.InstructionAt(next_insn);
AdjustReturnLine(this, ret_inst, target_line);
// Directly bail if a hard failure was found.
if (have_pending_hard_failure_) {
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index 1f1d7c1..813ce87 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -25,6 +25,7 @@
#include "base/macros.h"
#include "base/scoped_arena_containers.h"
#include "base/value_object.h"
+#include "code_item_accessors.h"
#include "dex_file.h"
#include "dex_file_types.h"
#include "handle.h"
@@ -186,7 +187,9 @@
REQUIRES_SHARED(Locks::mutator_lock_);
// Accessors used by the compiler via CompilerCallback
- const DexFile::CodeItem* CodeItem() const;
+ const CodeItemDataAccessor& CodeItem() const {
+ return code_item_accessor_;
+ }
RegisterLine* GetRegLine(uint32_t dex_pc);
ALWAYS_INLINE const InstructionFlags& GetInstructionFlags(size_t index) const;
ALWAYS_INLINE InstructionFlags& GetInstructionFlags(size_t index);
@@ -738,7 +741,7 @@
// The class loader for the declaring class of the method.
Handle<mirror::ClassLoader> class_loader_ GUARDED_BY(Locks::mutator_lock_);
const DexFile::ClassDef& class_def_; // The class def of the declaring class of the method.
- const DexFile::CodeItem* const code_item_; // The code item containing the code for the method.
+ const CodeItemDataAccessor code_item_accessor_;
const RegType* declaring_class_; // Lazily computed reg type of the method's declaring class.
// Instruction widths and flags, one entry per code unit.
// Owned, but not unique_ptr since insn_flags_ are allocated in arenas.
diff --git a/test/163-app-image-methods/src/Main.java b/test/163-app-image-methods/src/Main.java
index a995bb8..c513470 100644
--- a/test/163-app-image-methods/src/Main.java
+++ b/test/163-app-image-methods/src/Main.java
@@ -22,6 +22,9 @@
// Allocate memory for the "AAA.Derived" class name before eating memory.
String aaaDerivedName = "AAA.Derived";
System.out.println("Eating all memory.");
+ // Resolve VMClassLoader before eating all the memory since we can not fail
+ // initializtaion of boot classpath classes.
+ Class.forName("java.lang.VMClassLoader");
Object memory = eatAllMemory();
// This test assumes that Derived is not yet resolved. In some configurations
diff --git a/test/165-lock-owner-proxy/src/Main.java b/test/165-lock-owner-proxy/src/Main.java
index 1b1694d..fff8e58 100644
--- a/test/165-lock-owner-proxy/src/Main.java
+++ b/test/165-lock-owner-proxy/src/Main.java
@@ -65,8 +65,13 @@
int count = totalOperations;
while (count > 0) {
synchronized (lockObject) {
- inf.foo(10000 - count, 11000 - count, 12000 - count, 13000 - count,
- 14000 - count, 15000 - count);
+ try {
+ inf.foo(10000 - count, 11000 - count, 12000 - count, 13000 - count,
+ 14000 - count, 15000 - count);
+ } catch (OutOfMemoryError e) {
+ // Ignore errors. This is the test for b/69121347 - see an exception
+ // instead of native abort.
+ }
}
count--;
}
@@ -96,7 +101,12 @@
while (!finish) {
// Some random allocations adding up to almost 2M.
for (int i = 0; i < 188; i++) {
- byte b[] = new byte[i * 100 + 10];
+ try {
+ byte b[] = new byte[i * 100 + 10];
+ } catch (OutOfMemoryError e) {
+ // Ignore. This is just to improve chances that an OOME is thrown during
+ // proxy invocation.
+ }
}
try {
Thread.sleep(10);
diff --git a/test/566-polymorphic-inlining/polymorphic_inline.cc b/test/566-polymorphic-inlining/polymorphic_inline.cc
index b75becf..e2b8aa0 100644
--- a/test/566-polymorphic-inlining/polymorphic_inline.cc
+++ b/test/566-polymorphic-inlining/polymorphic_inline.cc
@@ -19,6 +19,7 @@
#include "jit/jit.h"
#include "jit/jit_code_cache.h"
#include "jit/profiling_info.h"
+#include "mirror/class.h"
#include "oat_quick_method_header.h"
#include "scoped_thread_state_change-inl.h"
#include "stack_map.h"
diff --git a/test/626-checker-arm64-scratch-register/smali/Smali.smali b/test/626-checker-arm64-scratch-register/smali/Smali.smali
new file mode 100644
index 0000000..e6943cf
--- /dev/null
+++ b/test/626-checker-arm64-scratch-register/smali/Smali.smali
@@ -0,0 +1,2119 @@
+# 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.
+
+.class public LSmali;
+.super Ljava/lang/Object;
+.field b00:Z
+.field b01:Z
+.field b02:Z
+.field b03:Z
+.field b04:Z
+.field b05:Z
+.field b06:Z
+.field b07:Z
+.field b08:Z
+.field b09:Z
+.field b10:Z
+.field b11:Z
+.field b12:Z
+.field b13:Z
+.field b14:Z
+.field b15:Z
+.field b16:Z
+.field b17:Z
+.field b18:Z
+.field b19:Z
+.field b20:Z
+.field b21:Z
+.field b22:Z
+.field b23:Z
+.field b24:Z
+.field b25:Z
+.field b26:Z
+.field b27:Z
+.field b28:Z
+.field b29:Z
+.field b30:Z
+.field b31:Z
+.field b32:Z
+.field b33:Z
+.field b34:Z
+.field b35:Z
+.field b36:Z
+
+.field conditionA:Z
+.field conditionB:Z
+.field conditionC:Z
+
+.method public constructor <init>()V
+ .registers 1
+ invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+ return-void
+.end method
+
+## CHECK-START-ARM64: void Smali.test() register (after)
+## CHECK: begin_block
+## CHECK: name "B0"
+## CHECK: <<This:l\d+>> ParameterValue
+## CHECK: end_block
+## CHECK: begin_block
+## CHECK: successors "<<ThenBlock:B\d+>>" "<<ElseBlock:B\d+>>"
+## CHECK: <<CondB:z\d+>> InstanceFieldGet [<<This>>] field_name:Smali.conditionB
+## CHECK: If [<<CondB>>]
+## CHECK: end_block
+## CHECK: begin_block
+## CHECK: name "<<ElseBlock>>"
+## CHECK: ParallelMove moves:[40(sp)->d0,24(sp)->32(sp),28(sp)->36(sp),d0->d3,d3->d4,d2->d5,d4->d6,d5->d7,d6->d18,d7->d19,d18->d20,d19->d21,d20->d22,d21->d23,d22->d10,d23->d11,16(sp)->24(sp),20(sp)->28(sp),d10->d14,d11->d12,d12->d13,d13->d1,d14->d2,32(sp)->16(sp),36(sp)->20(sp)]
+## CHECK: end_block
+
+## CHECK-START-ARM64: void Smali.test() disassembly (after)
+## CHECK: begin_block
+## CHECK: name "B0"
+## CHECK: <<This:l\d+>> ParameterValue
+## CHECK: end_block
+## CHECK: begin_block
+## CHECK: successors "<<ThenBlock:B\d+>>" "<<ElseBlock:B\d+>>"
+## CHECK: <<CondB:z\d+>> InstanceFieldGet [<<This>>] field_name:Smali.conditionB
+## CHECK: If [<<CondB>>]
+## CHECK: end_block
+## CHECK: begin_block
+## CHECK: name "<<ElseBlock>>"
+## CHECK: ParallelMove moves:[invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid]
+## CHECK: fmov d31, d2
+## CHECK: ldr s2, [sp, #36]
+## CHECK: ldr w16, [sp, #16]
+## CHECK: str w16, [sp, #36]
+## CHECK: str s14, [sp, #16]
+## CHECK: ldr s14, [sp, #28]
+## CHECK: str s1, [sp, #28]
+## CHECK: ldr s1, [sp, #32]
+## CHECK: str s31, [sp, #32]
+## CHECK: ldr s31, [sp, #20]
+## CHECK: str s31, [sp, #40]
+## CHECK: str s12, [sp, #20]
+## CHECK: fmov d12, d11
+## CHECK: fmov d11, d10
+## CHECK: fmov d10, d23
+## CHECK: fmov d23, d22
+## CHECK: fmov d22, d21
+## CHECK: fmov d21, d20
+## CHECK: fmov d20, d19
+## CHECK: fmov d19, d18
+## CHECK: fmov d18, d7
+## CHECK: fmov d7, d6
+## CHECK: fmov d6, d5
+## CHECK: fmov d5, d4
+## CHECK: fmov d4, d3
+## CHECK: fmov d3, d13
+## CHECK: ldr s13, [sp, #24]
+## CHECK: str s3, [sp, #24]
+## CHECK: ldr s3, pc+{{\d+}} (addr {{0x[0-9a-f]+}}) (100)
+## CHECK: end_block
+.method public test()V
+ .registers 45
+
+ const-string v39, ""
+
+ move-object/from16 v0, p0
+
+ iget-boolean v0, v0, LSmali;->b17:Z
+
+ move/from16 v42, v0
+
+ if-eqz v42, :cond_367
+
+ const/16 v19, 0x0
+
+ :goto_c
+ move-object/from16 v0, p0
+
+ iget-boolean v0, v0, LSmali;->b16:Z
+
+ move/from16 v42, v0
+
+ if-eqz v42, :cond_36b
+
+ const/16 v18, 0x0
+
+ :goto_16
+ move-object/from16 v0, p0
+
+ iget-boolean v0, v0, LSmali;->b18:Z
+
+ move/from16 v42, v0
+
+ if-eqz v42, :cond_36f
+
+ const/16 v20, 0x0
+
+ :goto_20
+ move-object/from16 v0, p0
+
+ iget-boolean v0, v0, LSmali;->b19:Z
+
+ move/from16 v42, v0
+
+ if-eqz v42, :cond_373
+
+ const/16 v21, 0x0
+
+ :goto_2a
+ move-object/from16 v0, p0
+
+ iget-boolean v0, v0, LSmali;->b20:Z
+
+ move/from16 v42, v0
+
+ if-eqz v42, :cond_377
+
+ const/16 v22, 0x0
+
+ :goto_34
+ move-object/from16 v0, p0
+
+ iget-boolean v0, v0, LSmali;->b21:Z
+
+ move/from16 v42, v0
+
+ if-eqz v42, :cond_37b
+
+ const/16 v23, 0x0
+
+ :goto_3e
+ move-object/from16 v0, p0
+
+ iget-boolean v0, v0, LSmali;->b15:Z
+
+ move/from16 v42, v0
+
+ if-eqz v42, :cond_37f
+
+ const/16 v17, 0x0
+
+ :goto_48
+ move-object/from16 v0, p0
+
+ iget-boolean v0, v0, LSmali;->b00:Z
+
+ move/from16 v42, v0
+
+ if-eqz v42, :cond_383
+
+ const/4 v2, 0x0
+
+ :goto_51
+ move-object/from16 v0, p0
+
+ iget-boolean v0, v0, LSmali;->b22:Z
+
+ move/from16 v42, v0
+
+ if-eqz v42, :cond_387
+
+ const/16 v24, 0x0
+
+ :goto_5b
+ move-object/from16 v0, p0
+
+ iget-boolean v0, v0, LSmali;->b23:Z
+
+ move/from16 v42, v0
+
+ if-eqz v42, :cond_38b
+
+ const/16 v25, 0x0
+
+ :goto_65
+ move-object/from16 v0, p0
+
+ iget-boolean v0, v0, LSmali;->b24:Z
+
+ move/from16 v42, v0
+
+ if-eqz v42, :cond_38f
+
+ const/16 v26, 0x0
+
+ :goto_6f
+ move-object/from16 v0, p0
+
+ iget-boolean v0, v0, LSmali;->b25:Z
+
+ move/from16 v42, v0
+
+ if-eqz v42, :cond_393
+
+ const/16 v27, 0x0
+
+ :goto_79
+ move-object/from16 v0, p0
+
+ iget-boolean v0, v0, LSmali;->b26:Z
+
+ move/from16 v42, v0
+
+ if-eqz v42, :cond_397
+
+ const/16 v28, 0x0
+
+ :goto_83
+ move-object/from16 v0, p0
+
+ iget-boolean v0, v0, LSmali;->b27:Z
+
+ move/from16 v42, v0
+
+ if-eqz v42, :cond_39b
+
+ const/16 v29, 0x0
+
+ :goto_8d
+ move-object/from16 v0, p0
+
+ iget-boolean v0, v0, LSmali;->b29:Z
+
+ move/from16 v42, v0
+
+ if-eqz v42, :cond_39f
+
+ const/16 v31, 0x0
+
+ :goto_97
+ move-object/from16 v0, p0
+
+ iget-boolean v0, v0, LSmali;->b28:Z
+
+ move/from16 v42, v0
+
+ if-eqz v42, :cond_3a3
+
+ const/16 v30, 0x0
+
+ :goto_a1
+ move-object/from16 v0, p0
+
+ iget-boolean v0, v0, LSmali;->b01:Z
+
+ move/from16 v42, v0
+
+ if-eqz v42, :cond_3a7
+
+ const/4 v3, 0x0
+
+ :goto_aa
+ move-object/from16 v0, p0
+
+ iget-boolean v0, v0, LSmali;->b02:Z
+
+ move/from16 v42, v0
+
+ if-eqz v42, :cond_3ab
+
+ const/4 v4, 0x0
+
+ :goto_b3
+ move-object/from16 v0, p0
+
+ iget-boolean v0, v0, LSmali;->b03:Z
+
+ move/from16 v42, v0
+
+ if-eqz v42, :cond_3af
+
+ const/4 v5, 0x0
+
+ :goto_bc
+ move-object/from16 v0, p0
+
+ iget-boolean v0, v0, LSmali;->b04:Z
+
+ move/from16 v42, v0
+
+ if-eqz v42, :cond_3b3
+
+ const/4 v6, 0x0
+
+ :goto_c5
+ move-object/from16 v0, p0
+
+ iget-boolean v0, v0, LSmali;->b05:Z
+
+ move/from16 v42, v0
+
+ if-eqz v42, :cond_3b7
+
+ const/4 v7, 0x0
+
+ :goto_ce
+ move-object/from16 v0, p0
+
+ iget-boolean v0, v0, LSmali;->b07:Z
+
+ move/from16 v42, v0
+
+ if-eqz v42, :cond_3bb
+
+ const/4 v9, 0x0
+
+ :goto_d7
+ move-object/from16 v0, p0
+
+ iget-boolean v0, v0, LSmali;->b06:Z
+
+ move/from16 v42, v0
+
+ if-eqz v42, :cond_3bf
+
+ const/4 v8, 0x0
+
+ :goto_e0
+ move-object/from16 v0, p0
+
+ iget-boolean v0, v0, LSmali;->b30:Z
+
+ move/from16 v42, v0
+
+ if-eqz v42, :cond_3c3
+
+ const/16 v32, 0x0
+
+ :goto_ea
+ move-object/from16 v0, p0
+
+ iget-boolean v0, v0, LSmali;->b31:Z
+
+ move/from16 v42, v0
+
+ if-eqz v42, :cond_3c7
+
+ const/16 v33, 0x0
+
+ :goto_f4
+ move-object/from16 v0, p0
+
+ iget-boolean v0, v0, LSmali;->b32:Z
+
+ move/from16 v42, v0
+
+ if-eqz v42, :cond_3cb
+
+ const/16 v34, 0x0
+
+ :goto_fe
+ move-object/from16 v0, p0
+
+ iget-boolean v0, v0, LSmali;->b33:Z
+
+ move/from16 v42, v0
+
+ if-eqz v42, :cond_3cf
+
+ const/16 v35, 0x0
+
+ :goto_108
+ move-object/from16 v0, p0
+
+ iget-boolean v0, v0, LSmali;->b34:Z
+
+ move/from16 v42, v0
+
+ if-eqz v42, :cond_3d3
+
+ const/16 v36, 0x0
+
+ :goto_112
+ move-object/from16 v0, p0
+
+ iget-boolean v0, v0, LSmali;->b36:Z
+
+ move/from16 v42, v0
+
+ if-eqz v42, :cond_3d7
+
+ const/16 v38, 0x0
+
+ :goto_11c
+ move-object/from16 v0, p0
+
+ iget-boolean v0, v0, LSmali;->b35:Z
+
+ move/from16 v42, v0
+
+ if-eqz v42, :cond_3db
+
+ const/16 v37, 0x0
+
+ :goto_126
+ move-object/from16 v0, p0
+
+ iget-boolean v0, v0, LSmali;->b08:Z
+
+ move/from16 v42, v0
+
+ if-eqz v42, :cond_3df
+
+ const/4 v10, 0x0
+
+ :goto_12f
+ move-object/from16 v0, p0
+
+ iget-boolean v0, v0, LSmali;->b09:Z
+
+ move/from16 v42, v0
+
+ if-eqz v42, :cond_3e3
+
+ const/4 v11, 0x0
+
+ :goto_138
+ move-object/from16 v0, p0
+
+ iget-boolean v0, v0, LSmali;->b10:Z
+
+ move/from16 v42, v0
+
+ if-eqz v42, :cond_3e7
+
+ const/4 v12, 0x0
+
+ :goto_141
+ move-object/from16 v0, p0
+
+ iget-boolean v0, v0, LSmali;->b11:Z
+
+ move/from16 v42, v0
+
+ if-eqz v42, :cond_3eb
+
+ const/4 v13, 0x0
+
+ :goto_14a
+ move-object/from16 v0, p0
+
+ iget-boolean v0, v0, LSmali;->b12:Z
+
+ move/from16 v42, v0
+
+ if-eqz v42, :cond_3ef
+
+ const/4 v14, 0x0
+
+ :goto_153
+ move-object/from16 v0, p0
+
+ iget-boolean v0, v0, LSmali;->b14:Z
+
+ move/from16 v42, v0
+
+ if-eqz v42, :cond_3f3
+
+ const/16 v16, 0x0
+
+ :goto_15d
+ move-object/from16 v0, p0
+
+ iget-boolean v0, v0, LSmali;->b13:Z
+
+ move/from16 v42, v0
+
+ if-eqz v42, :cond_3f7
+
+ const/4 v15, 0x0
+
+ :goto_166
+ move-object/from16 v0, p0
+
+ iget-boolean v0, v0, LSmali;->conditionA:Z
+
+ move/from16 v42, v0
+
+ if-eqz v42, :cond_202
+
+ const/high16 v42, 0x447a0000 # 1000.0f
+
+ div-float v18, v18, v42
+
+ const/high16 v42, 0x447a0000 # 1000.0f
+
+ div-float v19, v19, v42
+
+ const/high16 v42, 0x447a0000 # 1000.0f
+
+ div-float v20, v20, v42
+
+ const/high16 v42, 0x447a0000 # 1000.0f
+
+ div-float v21, v21, v42
+
+ const/high16 v42, 0x447a0000 # 1000.0f
+
+ div-float v22, v22, v42
+
+ const/high16 v42, 0x447a0000 # 1000.0f
+
+ div-float v23, v23, v42
+
+ const/high16 v42, 0x447a0000 # 1000.0f
+
+ div-float v17, v17, v42
+
+ const/high16 v42, 0x447a0000 # 1000.0f
+
+ div-float v10, v10, v42
+
+ const/high16 v42, 0x447a0000 # 1000.0f
+
+ div-float v11, v11, v42
+
+ const/high16 v42, 0x447a0000 # 1000.0f
+
+ div-float v12, v12, v42
+
+ const/high16 v42, 0x447a0000 # 1000.0f
+
+ div-float v13, v13, v42
+
+ const/high16 v42, 0x447a0000 # 1000.0f
+
+ div-float v14, v14, v42
+
+ const/high16 v42, 0x447a0000 # 1000.0f
+
+ div-float v32, v32, v42
+
+ const/high16 v42, 0x447a0000 # 1000.0f
+
+ div-float v33, v33, v42
+
+ const/high16 v42, 0x447a0000 # 1000.0f
+
+ div-float v34, v34, v42
+
+ const/high16 v42, 0x447a0000 # 1000.0f
+
+ div-float v35, v35, v42
+
+ const/high16 v42, 0x447a0000 # 1000.0f
+
+ div-float v36, v36, v42
+
+ const/high16 v42, 0x447a0000 # 1000.0f
+
+ div-float v3, v3, v42
+
+ const/high16 v42, 0x447a0000 # 1000.0f
+
+ div-float v4, v4, v42
+
+ const/high16 v42, 0x447a0000 # 1000.0f
+
+ div-float v5, v5, v42
+
+ const/high16 v42, 0x447a0000 # 1000.0f
+
+ div-float v6, v6, v42
+
+ const/high16 v42, 0x447a0000 # 1000.0f
+
+ div-float v7, v7, v42
+
+ const/high16 v42, 0x447a0000 # 1000.0f
+
+ div-float v25, v25, v42
+
+ const/high16 v42, 0x447a0000 # 1000.0f
+
+ div-float v26, v26, v42
+
+ const/high16 v42, 0x447a0000 # 1000.0f
+
+ div-float v27, v27, v42
+
+ const/high16 v42, 0x447a0000 # 1000.0f
+
+ div-float v28, v28, v42
+
+ const/high16 v42, 0x447a0000 # 1000.0f
+
+ div-float v29, v29, v42
+
+ const/high16 v42, 0x447a0000 # 1000.0f
+
+ div-float v24, v24, v42
+
+ const/high16 v42, 0x447a0000 # 1000.0f
+
+ div-float v2, v2, v42
+
+ const/high16 v42, 0x447a0000 # 1000.0f
+
+ div-float v16, v16, v42
+
+ const/high16 v42, 0x447a0000 # 1000.0f
+
+ div-float v15, v15, v42
+
+ const/high16 v42, 0x447a0000 # 1000.0f
+
+ div-float v38, v38, v42
+
+ const/high16 v42, 0x447a0000 # 1000.0f
+
+ div-float v37, v37, v42
+
+ const/high16 v42, 0x447a0000 # 1000.0f
+
+ div-float v9, v9, v42
+
+ const/high16 v42, 0x447a0000 # 1000.0f
+
+ div-float v8, v8, v42
+
+ const/high16 v42, 0x447a0000 # 1000.0f
+
+ div-float v31, v31, v42
+
+ const/high16 v42, 0x447a0000 # 1000.0f
+
+ div-float v30, v30, v42
+
+ :cond_202
+ move-object/from16 v0, p0
+
+ iget-boolean v0, v0, LSmali;->conditionB:Z
+
+ move/from16 v42, v0
+
+ if-eqz v42, :cond_29e
+
+ const/high16 v42, 0x42c80000 # 100.0f
+
+ div-float v18, v18, v42
+
+ const/high16 v42, 0x42c80000 # 100.0f
+
+ div-float v19, v19, v42
+
+ const/high16 v42, 0x42c80000 # 100.0f
+
+ div-float v20, v20, v42
+
+ const/high16 v42, 0x42c80000 # 100.0f
+
+ div-float v21, v21, v42
+
+ const/high16 v42, 0x42c80000 # 100.0f
+
+ div-float v22, v22, v42
+
+ const/high16 v42, 0x42c80000 # 100.0f
+
+ div-float v23, v23, v42
+
+ const/high16 v42, 0x42c80000 # 100.0f
+
+ div-float v17, v17, v42
+
+ const/high16 v42, 0x42c80000 # 100.0f
+
+ div-float v10, v10, v42
+
+ const/high16 v42, 0x42c80000 # 100.0f
+
+ div-float v11, v11, v42
+
+ const/high16 v42, 0x42c80000 # 100.0f
+
+ div-float v12, v12, v42
+
+ const/high16 v42, 0x42c80000 # 100.0f
+
+ div-float v13, v13, v42
+
+ const/high16 v42, 0x42c80000 # 100.0f
+
+ div-float v14, v14, v42
+
+ const/high16 v42, 0x42c80000 # 100.0f
+
+ div-float v32, v32, v42
+
+ const/high16 v42, 0x42c80000 # 100.0f
+
+ div-float v33, v33, v42
+
+ const/high16 v42, 0x42c80000 # 100.0f
+
+ div-float v34, v34, v42
+
+ const/high16 v42, 0x42c80000 # 100.0f
+
+ div-float v35, v35, v42
+
+ const/high16 v42, 0x42c80000 # 100.0f
+
+ div-float v36, v36, v42
+
+ const/high16 v42, 0x42c80000 # 100.0f
+
+ div-float v3, v3, v42
+
+ const/high16 v42, 0x42c80000 # 100.0f
+
+ div-float v4, v4, v42
+
+ const/high16 v42, 0x42c80000 # 100.0f
+
+ div-float v5, v5, v42
+
+ const/high16 v42, 0x42c80000 # 100.0f
+
+ div-float v6, v6, v42
+
+ const/high16 v42, 0x42c80000 # 100.0f
+
+ div-float v7, v7, v42
+
+ const/high16 v42, 0x42c80000 # 100.0f
+
+ div-float v25, v25, v42
+
+ const/high16 v42, 0x42c80000 # 100.0f
+
+ div-float v26, v26, v42
+
+ const/high16 v42, 0x42c80000 # 100.0f
+
+ div-float v27, v27, v42
+
+ const/high16 v42, 0x42c80000 # 100.0f
+
+ div-float v28, v28, v42
+
+ const/high16 v42, 0x42c80000 # 100.0f
+
+ div-float v29, v29, v42
+
+ const/high16 v42, 0x42c80000 # 100.0f
+
+ div-float v24, v24, v42
+
+ const/high16 v42, 0x42c80000 # 100.0f
+
+ div-float v2, v2, v42
+
+ const/high16 v42, 0x42c80000 # 100.0f
+
+ div-float v16, v16, v42
+
+ const/high16 v42, 0x42c80000 # 100.0f
+
+ div-float v15, v15, v42
+
+ const/high16 v42, 0x42c80000 # 100.0f
+
+ div-float v38, v38, v42
+
+ const/high16 v42, 0x42c80000 # 100.0f
+
+ div-float v37, v37, v42
+
+ const/high16 v42, 0x42c80000 # 100.0f
+
+ div-float v9, v9, v42
+
+ const/high16 v42, 0x42c80000 # 100.0f
+
+ div-float v8, v8, v42
+
+ const/high16 v42, 0x42c80000 # 100.0f
+
+ div-float v31, v31, v42
+
+ const/high16 v42, 0x42c80000 # 100.0f
+
+ div-float v30, v30, v42
+
+ :cond_29e
+ move-object/from16 v0, p0
+
+ iget-boolean v0, v0, LSmali;->conditionC:Z
+
+ move/from16 v42, v0
+
+ if-eqz v42, :cond_33a
+
+ const/high16 v42, 0x41400000 # 12.0f
+
+ div-float v18, v18, v42
+
+ const/high16 v42, 0x41400000 # 12.0f
+
+ div-float v19, v19, v42
+
+ const/high16 v42, 0x41400000 # 12.0f
+
+ div-float v20, v20, v42
+
+ const/high16 v42, 0x41400000 # 12.0f
+
+ div-float v21, v21, v42
+
+ const/high16 v42, 0x41400000 # 12.0f
+
+ div-float v22, v22, v42
+
+ const/high16 v42, 0x41400000 # 12.0f
+
+ div-float v23, v23, v42
+
+ const/high16 v42, 0x41400000 # 12.0f
+
+ div-float v17, v17, v42
+
+ const/high16 v42, 0x41400000 # 12.0f
+
+ div-float v10, v10, v42
+
+ const/high16 v42, 0x41400000 # 12.0f
+
+ div-float v11, v11, v42
+
+ const/high16 v42, 0x41400000 # 12.0f
+
+ div-float v12, v12, v42
+
+ const/high16 v42, 0x41400000 # 12.0f
+
+ div-float v13, v13, v42
+
+ const/high16 v42, 0x41400000 # 12.0f
+
+ div-float v14, v14, v42
+
+ const/high16 v42, 0x41400000 # 12.0f
+
+ div-float v32, v32, v42
+
+ const/high16 v42, 0x41400000 # 12.0f
+
+ div-float v33, v33, v42
+
+ const/high16 v42, 0x41400000 # 12.0f
+
+ div-float v34, v34, v42
+
+ const/high16 v42, 0x41400000 # 12.0f
+
+ div-float v35, v35, v42
+
+ const/high16 v42, 0x41400000 # 12.0f
+
+ div-float v36, v36, v42
+
+ const/high16 v42, 0x41400000 # 12.0f
+
+ div-float v3, v3, v42
+
+ const/high16 v42, 0x41400000 # 12.0f
+
+ div-float v4, v4, v42
+
+ const/high16 v42, 0x41400000 # 12.0f
+
+ div-float v5, v5, v42
+
+ const/high16 v42, 0x41400000 # 12.0f
+
+ div-float v6, v6, v42
+
+ const/high16 v42, 0x41400000 # 12.0f
+
+ div-float v7, v7, v42
+
+ const/high16 v42, 0x41400000 # 12.0f
+
+ div-float v25, v25, v42
+
+ const/high16 v42, 0x41400000 # 12.0f
+
+ div-float v26, v26, v42
+
+ const/high16 v42, 0x41400000 # 12.0f
+
+ div-float v27, v27, v42
+
+ const/high16 v42, 0x41400000 # 12.0f
+
+ div-float v28, v28, v42
+
+ const/high16 v42, 0x41400000 # 12.0f
+
+ div-float v29, v29, v42
+
+ const/high16 v42, 0x41400000 # 12.0f
+
+ div-float v24, v24, v42
+
+ const/high16 v42, 0x41400000 # 12.0f
+
+ div-float v2, v2, v42
+
+ const/high16 v42, 0x41400000 # 12.0f
+
+ div-float v16, v16, v42
+
+ const/high16 v42, 0x41400000 # 12.0f
+
+ div-float v15, v15, v42
+
+ const/high16 v42, 0x41400000 # 12.0f
+
+ div-float v38, v38, v42
+
+ const/high16 v42, 0x41400000 # 12.0f
+
+ div-float v37, v37, v42
+
+ const/high16 v42, 0x41400000 # 12.0f
+
+ div-float v9, v9, v42
+
+ const/high16 v42, 0x41400000 # 12.0f
+
+ div-float v8, v8, v42
+
+ const/high16 v42, 0x41400000 # 12.0f
+
+ div-float v31, v31, v42
+
+ const/high16 v42, 0x41400000 # 12.0f
+
+ div-float v30, v30, v42
+
+ :cond_33a
+ const/16 v41, 0x0
+
+ const/high16 v42, 0x42c80000 # 100.0f
+
+ mul-float v42, v42, v41
+
+ invoke-static/range {v42 .. v42}, Ljava/lang/Math;->round(F)I
+
+ move-result v42
+
+ move/from16 v0, v42
+
+ int-to-float v0, v0
+
+ move/from16 v42, v0
+
+ const/high16 v43, 0x42c80000 # 100.0f
+
+ div-float v41, v42, v43
+
+ new-instance v42, Ljava/lang/StringBuilder;
+
+ invoke-direct/range {v42 .. v42}, Ljava/lang/StringBuilder;-><init>()V
+
+ move-object/from16 v0, v42
+
+ move/from16 v1, v41
+
+ invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(F)Ljava/lang/StringBuilder;
+
+ move-result-object v42
+
+ move-object/from16 v0, v42
+
+ move-object/from16 v1, v39
+
+ invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
+
+ move-result-object v42
+
+ invoke-virtual/range {v42 .. v42}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
+
+ move-result-object v40
+
+ return-void
+
+ :cond_367
+ const/high16 v19, 0x3f800000 # 1.0f
+
+ goto/16 :goto_c
+
+ :cond_36b
+ const/high16 v18, 0x3f800000 # 1.0f
+
+ goto/16 :goto_16
+
+ :cond_36f
+ const/high16 v20, 0x3f800000 # 1.0f
+
+ goto/16 :goto_20
+
+ :cond_373
+ const/high16 v21, 0x3f800000 # 1.0f
+
+ goto/16 :goto_2a
+
+ :cond_377
+ const/high16 v22, 0x3f800000 # 1.0f
+
+ goto/16 :goto_34
+
+ :cond_37b
+ const/high16 v23, 0x3f800000 # 1.0f
+
+ goto/16 :goto_3e
+
+ :cond_37f
+ const/high16 v17, 0x3f800000 # 1.0f
+
+ goto/16 :goto_48
+
+ :cond_383
+ const/high16 v2, 0x3f800000 # 1.0f
+
+ goto/16 :goto_51
+
+ :cond_387
+ const/high16 v24, 0x3f800000 # 1.0f
+
+ goto/16 :goto_5b
+
+ :cond_38b
+ const/high16 v25, 0x3f800000 # 1.0f
+
+ goto/16 :goto_65
+
+ :cond_38f
+ const/high16 v26, 0x3f800000 # 1.0f
+
+ goto/16 :goto_6f
+
+ :cond_393
+ const/high16 v27, 0x3f800000 # 1.0f
+
+ goto/16 :goto_79
+
+ :cond_397
+ const/high16 v28, 0x3f800000 # 1.0f
+
+ goto/16 :goto_83
+
+ :cond_39b
+ const/high16 v29, 0x3f800000 # 1.0f
+
+ goto/16 :goto_8d
+
+ :cond_39f
+ const/high16 v31, 0x3f800000 # 1.0f
+
+ goto/16 :goto_97
+
+ :cond_3a3
+ const/high16 v30, 0x3f800000 # 1.0f
+
+ goto/16 :goto_a1
+
+ :cond_3a7
+ const/high16 v3, 0x3f800000 # 1.0f
+
+ goto/16 :goto_aa
+
+ :cond_3ab
+ const/high16 v4, 0x3f800000 # 1.0f
+
+ goto/16 :goto_b3
+
+ :cond_3af
+ const/high16 v5, 0x3f800000 # 1.0f
+
+ goto/16 :goto_bc
+
+ :cond_3b3
+ const/high16 v6, 0x3f800000 # 1.0f
+
+ goto/16 :goto_c5
+
+ :cond_3b7
+ const/high16 v7, 0x3f800000 # 1.0f
+
+ goto/16 :goto_ce
+
+ :cond_3bb
+ const/high16 v9, 0x3f800000 # 1.0f
+
+ goto/16 :goto_d7
+
+ :cond_3bf
+ const/high16 v8, 0x3f800000 # 1.0f
+
+ goto/16 :goto_e0
+
+ :cond_3c3
+ const/high16 v32, 0x3f800000 # 1.0f
+
+ goto/16 :goto_ea
+
+ :cond_3c7
+ const/high16 v33, 0x3f800000 # 1.0f
+
+ goto/16 :goto_f4
+
+ :cond_3cb
+ const/high16 v34, 0x3f800000 # 1.0f
+
+ goto/16 :goto_fe
+
+ :cond_3cf
+ const/high16 v35, 0x3f800000 # 1.0f
+
+ goto/16 :goto_108
+
+ :cond_3d3
+ const/high16 v36, 0x3f800000 # 1.0f
+
+ goto/16 :goto_112
+
+ :cond_3d7
+ const/high16 v38, 0x3f800000 # 1.0f
+
+ goto/16 :goto_11c
+
+ :cond_3db
+ const/high16 v37, 0x3f800000 # 1.0f
+
+ goto/16 :goto_126
+
+ :cond_3df
+ const/high16 v10, 0x3f800000 # 1.0f
+
+ goto/16 :goto_12f
+
+ :cond_3e3
+ const/high16 v11, 0x3f800000 # 1.0f
+
+ goto/16 :goto_138
+
+ :cond_3e7
+ const/high16 v12, 0x3f800000 # 1.0f
+
+ goto/16 :goto_141
+
+ :cond_3eb
+ const/high16 v13, 0x3f800000 # 1.0f
+
+ goto/16 :goto_14a
+
+ :cond_3ef
+ const/high16 v14, 0x3f800000 # 1.0f
+
+ goto/16 :goto_153
+
+ :cond_3f3
+ const/high16 v16, 0x3f800000 # 1.0f
+
+ goto/16 :goto_15d
+
+ :cond_3f7
+ const/high16 v15, 0x3f800000 # 1.0f
+
+ goto/16 :goto_166
+.end method
+
+## CHECK-START-ARM64: void Smali.testD8() register (after)
+## CHECK: begin_block
+## CHECK: name "B0"
+## CHECK: <<This:l\d+>> ParameterValue
+## CHECK: end_block
+
+## CHECK: begin_block
+## CHECK: successors "<<ThenBlockA:B\d+>>" "<<ElseBlockA:B\d+>>"
+## CHECK: <<CondA:z\d+>> InstanceFieldGet [<<This>>] field_name:Smali.conditionA
+## CHECK: If [<<CondA>>]
+## CHECK: end_block
+
+## CHECK: begin_block
+## CHECK: name "<<ThenBlockA>>"
+## CHECK: end_block
+## CHECK: begin_block
+## CHECK: name "<<ElseBlockA>>"
+## CHECK: ParallelMove moves:[d2->d0,40(sp)->d17,d20->d26,d19->d27,d27->d1,d26->d2,d14->d20,d13->d19,d17->d14,d0->d13]
+## CHECK: end_block
+
+## CHECK: begin_block
+## CHECK: successors "<<ThenBlockB:B\d+>>" "<<ElseBlockB:B\d+>>"
+## CHECK: <<CondB:z\d+>> InstanceFieldGet [<<This>>] field_name:Smali.conditionB
+## CHECK: If [<<CondB>>]
+## CHECK: end_block
+
+## CHECK: begin_block
+## CHECK: name "<<ThenBlockB>>"
+## CHECK: end_block
+## CHECK: begin_block
+## CHECK: name "<<ElseBlockB>>"
+## CHECK: ParallelMove moves:[#100->d13,16(sp)->d1,20(sp)->d2,28(sp)->d19,24(sp)->d20,36(sp)->d14,32(sp)->16(sp),d1->20(sp),d2->24(sp),d20->28(sp),d19->32(sp),d14->36(sp),d13->40(sp)]
+## CHECK: end_block
+
+## CHECK-START-ARM64: void Smali.testD8() disassembly (after)
+## CHECK: begin_block
+## CHECK: name "B0"
+## CHECK: <<This:l\d+>> ParameterValue
+## CHECK: end_block
+
+## CHECK: begin_block
+## CHECK: successors "<<ThenBlockA:B\d+>>" "<<ElseBlockA:B\d+>>"
+## CHECK: <<CondA:z\d+>> InstanceFieldGet [<<This>>] field_name:Smali.conditionA
+## CHECK: If [<<CondA>>]
+## CHECK: end_block
+
+## CHECK: begin_block
+## CHECK: name "<<ThenBlockA>>"
+## CHECK: end_block
+## CHECK: begin_block
+## CHECK: name "<<ElseBlockA>>"
+## CHECK: end_block
+
+## CHECK: begin_block
+## CHECK: successors "<<ThenBlockB:B\d+>>" "<<ElseBlockB:B\d+>>"
+## CHECK: <<CondB:z\d+>> InstanceFieldGet [<<This>>] field_name:Smali.conditionB
+## CHECK: If [<<CondB>>]
+## CHECK: end_block
+
+## CHECK: begin_block
+## CHECK: name "<<ThenBlockB>>"
+## CHECK: end_block
+## CHECK: begin_block
+## CHECK: name "<<ElseBlockB>>"
+## CHECK: ParallelMove moves:[invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid]
+## CHECK: ldr w16, [sp, #32]
+## CHECK: str s19, [sp, #32]
+## CHECK: ldr s19, [sp, #28]
+## CHECK: str s20, [sp, #28]
+## CHECK: ldr s20, [sp, #24]
+## CHECK: str s2, [sp, #24]
+## CHECK: ldr s2, [sp, #20]
+## CHECK: str s1, [sp, #20]
+## CHECK: ldr s1, [sp, #16]
+## CHECK: str w16, [sp, #16]
+## CHECK: fmov d31, d14
+## CHECK: ldr s14, [sp, #36]
+## CHECK: str s31, [sp, #36]
+## CHECK: str s13, [sp, #40]
+## CHECK: ldr s13, pc+580 (addr 0x61c) (100)
+## CHECK: end_block
+.method public testD8()V
+ .registers 47
+
+ move-object/from16 v0, p0
+
+ const-string v1, ""
+
+ iget-boolean v2, v0, LSmali;->b17:Z
+
+ if-eqz v2, :cond_a
+
+ const/4 v2, 0x0
+
+ goto :goto_c
+
+ :cond_a
+ const/high16 v2, 0x3f800000 # 1.0f
+
+ :goto_c
+ iget-boolean v5, v0, LSmali;->b16:Z
+
+ if-eqz v5, :cond_12
+
+ const/4 v5, 0x0
+
+ goto :goto_14
+
+ :cond_12
+ const/high16 v5, 0x3f800000 # 1.0f
+
+ :goto_14
+ iget-boolean v6, v0, LSmali;->b18:Z
+
+ if-eqz v6, :cond_1a
+
+ const/4 v6, 0x0
+
+ goto :goto_1c
+
+ :cond_1a
+ const/high16 v6, 0x3f800000 # 1.0f
+
+ :goto_1c
+ iget-boolean v7, v0, LSmali;->b19:Z
+
+ if-eqz v7, :cond_22
+
+ const/4 v7, 0x0
+
+ goto :goto_24
+
+ :cond_22
+ const/high16 v7, 0x3f800000 # 1.0f
+
+ :goto_24
+ iget-boolean v8, v0, LSmali;->b20:Z
+
+ if-eqz v8, :cond_2a
+
+ const/4 v8, 0x0
+
+ goto :goto_2c
+
+ :cond_2a
+ const/high16 v8, 0x3f800000 # 1.0f
+
+ :goto_2c
+ iget-boolean v9, v0, LSmali;->b21:Z
+
+ if-eqz v9, :cond_32
+
+ const/4 v9, 0x0
+
+ goto :goto_34
+
+ :cond_32
+ const/high16 v9, 0x3f800000 # 1.0f
+
+ :goto_34
+ iget-boolean v10, v0, LSmali;->b15:Z
+
+ if-eqz v10, :cond_3a
+
+ const/4 v10, 0x0
+
+ goto :goto_3c
+
+ :cond_3a
+ const/high16 v10, 0x3f800000 # 1.0f
+
+ :goto_3c
+ iget-boolean v11, v0, LSmali;->b00:Z
+
+ if-eqz v11, :cond_42
+
+ const/4 v11, 0x0
+
+ goto :goto_44
+
+ :cond_42
+ const/high16 v11, 0x3f800000 # 1.0f
+
+ :goto_44
+ iget-boolean v12, v0, LSmali;->b22:Z
+
+ if-eqz v12, :cond_4a
+
+ const/4 v12, 0x0
+
+ goto :goto_4c
+
+ :cond_4a
+ const/high16 v12, 0x3f800000 # 1.0f
+
+ :goto_4c
+ iget-boolean v13, v0, LSmali;->b23:Z
+
+ if-eqz v13, :cond_52
+
+ const/4 v13, 0x0
+
+ goto :goto_54
+
+ :cond_52
+ const/high16 v13, 0x3f800000 # 1.0f
+
+ :goto_54
+ iget-boolean v14, v0, LSmali;->b24:Z
+
+ if-eqz v14, :cond_5a
+
+ const/4 v14, 0x0
+
+ goto :goto_5c
+
+ :cond_5a
+ const/high16 v14, 0x3f800000 # 1.0f
+
+ :goto_5c
+ iget-boolean v15, v0, LSmali;->b25:Z
+
+ if-eqz v15, :cond_62
+
+ const/4 v15, 0x0
+
+ goto :goto_64
+
+ :cond_62
+ const/high16 v15, 0x3f800000 # 1.0f
+
+ :goto_64
+ iget-boolean v3, v0, LSmali;->b26:Z
+
+ if-eqz v3, :cond_6a
+
+ const/4 v3, 0x0
+
+ goto :goto_6c
+
+ :cond_6a
+ const/high16 v3, 0x3f800000 # 1.0f
+
+ :goto_6c
+ iget-boolean v4, v0, LSmali;->b27:Z
+
+ if-eqz v4, :cond_72
+
+ const/4 v4, 0x0
+
+ goto :goto_74
+
+ :cond_72
+ const/high16 v4, 0x3f800000 # 1.0f
+
+ :goto_74
+ move-object/from16 v18, v1
+
+ iget-boolean v1, v0, LSmali;->b29:Z
+
+ if-eqz v1, :cond_7c
+
+ const/4 v1, 0x0
+
+ goto :goto_7e
+
+ :cond_7c
+ const/high16 v1, 0x3f800000 # 1.0f
+
+ :goto_7e
+ move/from16 v19, v1
+
+ iget-boolean v1, v0, LSmali;->b28:Z
+
+ if-eqz v1, :cond_86
+
+ const/4 v1, 0x0
+
+ goto :goto_88
+
+ :cond_86
+ const/high16 v1, 0x3f800000 # 1.0f
+
+ :goto_88
+ move/from16 v20, v1
+
+ iget-boolean v1, v0, LSmali;->b01:Z
+
+ if-eqz v1, :cond_90
+
+ const/4 v1, 0x0
+
+ goto :goto_92
+
+ :cond_90
+ const/high16 v1, 0x3f800000 # 1.0f
+
+ :goto_92
+ move/from16 v21, v11
+
+ iget-boolean v11, v0, LSmali;->b02:Z
+
+ if-eqz v11, :cond_9a
+
+ const/4 v11, 0x0
+
+ goto :goto_9c
+
+ :cond_9a
+ const/high16 v11, 0x3f800000 # 1.0f
+
+ :goto_9c
+ move/from16 v22, v12
+
+ iget-boolean v12, v0, LSmali;->b03:Z
+
+ if-eqz v12, :cond_a4
+
+ const/4 v12, 0x0
+
+ goto :goto_a6
+
+ :cond_a4
+ const/high16 v12, 0x3f800000 # 1.0f
+
+ :goto_a6
+ move/from16 v23, v4
+
+ iget-boolean v4, v0, LSmali;->b04:Z
+
+ if-eqz v4, :cond_ae
+
+ const/4 v4, 0x0
+
+ goto :goto_b0
+
+ :cond_ae
+ const/high16 v4, 0x3f800000 # 1.0f
+
+ :goto_b0
+ move/from16 v24, v3
+
+ iget-boolean v3, v0, LSmali;->b05:Z
+
+ if-eqz v3, :cond_b8
+
+ const/4 v3, 0x0
+
+ goto :goto_ba
+
+ :cond_b8
+ const/high16 v3, 0x3f800000 # 1.0f
+
+ :goto_ba
+ move/from16 v25, v15
+
+ iget-boolean v15, v0, LSmali;->b07:Z
+
+ if-eqz v15, :cond_c2
+
+ const/4 v15, 0x0
+
+ goto :goto_c4
+
+ :cond_c2
+ const/high16 v15, 0x3f800000 # 1.0f
+
+ :goto_c4
+ move/from16 v26, v15
+
+ iget-boolean v15, v0, LSmali;->b06:Z
+
+ if-eqz v15, :cond_cc
+
+ const/4 v15, 0x0
+
+ goto :goto_ce
+
+ :cond_cc
+ const/high16 v15, 0x3f800000 # 1.0f
+
+ :goto_ce
+ move/from16 v27, v15
+
+ iget-boolean v15, v0, LSmali;->b30:Z
+
+ if-eqz v15, :cond_d6
+
+ const/4 v15, 0x0
+
+ goto :goto_d8
+
+ :cond_d6
+ const/high16 v15, 0x3f800000 # 1.0f
+
+ :goto_d8
+ move/from16 v28, v14
+
+ iget-boolean v14, v0, LSmali;->b31:Z
+
+ if-eqz v14, :cond_e0
+
+ const/4 v14, 0x0
+
+ goto :goto_e2
+
+ :cond_e0
+ const/high16 v14, 0x3f800000 # 1.0f
+
+ :goto_e2
+ move/from16 v29, v13
+
+ iget-boolean v13, v0, LSmali;->b32:Z
+
+ if-eqz v13, :cond_ea
+
+ const/4 v13, 0x0
+
+ goto :goto_ec
+
+ :cond_ea
+ const/high16 v13, 0x3f800000 # 1.0f
+
+ :goto_ec
+ move/from16 v30, v3
+
+ iget-boolean v3, v0, LSmali;->b33:Z
+
+ if-eqz v3, :cond_f4
+
+ const/4 v3, 0x0
+
+ goto :goto_f6
+
+ :cond_f4
+ const/high16 v3, 0x3f800000 # 1.0f
+
+ :goto_f6
+ move/from16 v31, v4
+
+ iget-boolean v4, v0, LSmali;->b34:Z
+
+ if-eqz v4, :cond_fe
+
+ const/4 v4, 0x0
+
+ goto :goto_100
+
+ :cond_fe
+ const/high16 v4, 0x3f800000 # 1.0f
+
+ :goto_100
+ move/from16 v32, v12
+
+ iget-boolean v12, v0, LSmali;->b36:Z
+
+ if-eqz v12, :cond_108
+
+ const/4 v12, 0x0
+
+ goto :goto_10a
+
+ :cond_108
+ const/high16 v12, 0x3f800000 # 1.0f
+
+ :goto_10a
+ move/from16 v33, v12
+
+ iget-boolean v12, v0, LSmali;->b35:Z
+
+ if-eqz v12, :cond_112
+
+ const/4 v12, 0x0
+
+ goto :goto_114
+
+ :cond_112
+ const/high16 v12, 0x3f800000 # 1.0f
+
+ :goto_114
+ move/from16 v34, v12
+
+ iget-boolean v12, v0, LSmali;->b08:Z
+
+ if-eqz v12, :cond_11c
+
+ const/4 v12, 0x0
+
+ goto :goto_11e
+
+ :cond_11c
+ const/high16 v12, 0x3f800000 # 1.0f
+
+ :goto_11e
+ move/from16 v35, v11
+
+ iget-boolean v11, v0, LSmali;->b09:Z
+
+ if-eqz v11, :cond_126
+
+ const/4 v11, 0x0
+
+ goto :goto_128
+
+ :cond_126
+ const/high16 v11, 0x3f800000 # 1.0f
+
+ :goto_128
+ move/from16 v36, v1
+
+ iget-boolean v1, v0, LSmali;->b10:Z
+
+ if-eqz v1, :cond_130
+
+ const/4 v1, 0x0
+
+ goto :goto_132
+
+ :cond_130
+ const/high16 v1, 0x3f800000 # 1.0f
+
+ :goto_132
+ move/from16 v37, v4
+
+ iget-boolean v4, v0, LSmali;->b11:Z
+
+ if-eqz v4, :cond_13a
+
+ const/4 v4, 0x0
+
+ goto :goto_13c
+
+ :cond_13a
+ const/high16 v4, 0x3f800000 # 1.0f
+
+ :goto_13c
+ move/from16 v38, v3
+
+ iget-boolean v3, v0, LSmali;->b12:Z
+
+ if-eqz v3, :cond_144
+
+ const/4 v3, 0x0
+
+ goto :goto_146
+
+ :cond_144
+ const/high16 v3, 0x3f800000 # 1.0f
+
+ :goto_146
+ move/from16 v39, v13
+
+ iget-boolean v13, v0, LSmali;->b14:Z
+
+ if-eqz v13, :cond_14e
+
+ const/4 v13, 0x0
+
+ goto :goto_150
+
+ :cond_14e
+ const/high16 v13, 0x3f800000 # 1.0f
+
+ :goto_150
+ move/from16 v40, v13
+
+ iget-boolean v13, v0, LSmali;->b13:Z
+
+ if-eqz v13, :cond_159
+
+ const/16 v16, 0x0
+
+ goto :goto_15b
+
+ :cond_159
+ const/high16 v16, 0x3f800000 # 1.0f
+
+ :goto_15b
+ move/from16 v13, v16
+
+ move/from16 v41, v13
+
+ iget-boolean v13, v0, LSmali;->conditionA:Z
+
+ if-eqz v13, :cond_1a2
+
+ const/high16 v13, 0x447a0000 # 1000.0f
+
+ div-float/2addr v5, v13
+
+ div-float/2addr v2, v13
+
+ div-float/2addr v6, v13
+
+ div-float/2addr v7, v13
+
+ div-float/2addr v8, v13
+
+ div-float/2addr v9, v13
+
+ div-float/2addr v10, v13
+
+ div-float/2addr v12, v13
+
+ div-float/2addr v11, v13
+
+ div-float/2addr v1, v13
+
+ div-float/2addr v4, v13
+
+ div-float/2addr v3, v13
+
+ div-float/2addr v15, v13
+
+ div-float/2addr v14, v13
+
+ div-float v16, v39, v13
+
+ div-float v38, v38, v13
+
+ div-float v37, v37, v13
+
+ div-float v36, v36, v13
+
+ div-float v35, v35, v13
+
+ div-float v32, v32, v13
+
+ div-float v31, v31, v13
+
+ div-float v30, v30, v13
+
+ div-float v29, v29, v13
+
+ div-float v28, v28, v13
+
+ div-float v25, v25, v13
+
+ div-float v24, v24, v13
+
+ div-float v23, v23, v13
+
+ div-float v22, v22, v13
+
+ div-float v21, v21, v13
+
+ div-float v39, v40, v13
+
+ div-float v40, v41, v13
+
+ div-float v33, v33, v13
+
+ div-float v34, v34, v13
+
+ div-float v26, v26, v13
+
+ div-float v27, v27, v13
+
+ div-float v19, v19, v13
+
+ div-float v13, v20, v13
+
+ goto :goto_1aa
+
+ :cond_1a2
+ move/from16 v13, v20
+
+ move/from16 v16, v39
+
+ move/from16 v39, v40
+
+ move/from16 v40, v41
+
+ :goto_1aa
+ move/from16 v42, v13
+
+ iget-boolean v13, v0, LSmali;->conditionB:Z
+
+ const/high16 v20, 0x42c80000 # 100.0f
+
+ if-eqz v13, :cond_1fd
+
+ div-float v5, v5, v20
+
+ div-float v2, v2, v20
+
+ div-float v6, v6, v20
+
+ div-float v7, v7, v20
+
+ div-float v8, v8, v20
+
+ div-float v9, v9, v20
+
+ div-float v10, v10, v20
+
+ div-float v12, v12, v20
+
+ div-float v11, v11, v20
+
+ div-float v1, v1, v20
+
+ div-float v4, v4, v20
+
+ div-float v3, v3, v20
+
+ div-float v15, v15, v20
+
+ div-float v14, v14, v20
+
+ div-float v16, v16, v20
+
+ div-float v38, v38, v20
+
+ div-float v37, v37, v20
+
+ div-float v36, v36, v20
+
+ div-float v35, v35, v20
+
+ div-float v32, v32, v20
+
+ div-float v31, v31, v20
+
+ div-float v30, v30, v20
+
+ div-float v29, v29, v20
+
+ div-float v28, v28, v20
+
+ div-float v25, v25, v20
+
+ div-float v24, v24, v20
+
+ div-float v23, v23, v20
+
+ div-float v22, v22, v20
+
+ div-float v21, v21, v20
+
+ div-float v39, v39, v20
+
+ div-float v40, v40, v20
+
+ div-float v33, v33, v20
+
+ div-float v34, v34, v20
+
+ div-float v26, v26, v20
+
+ div-float v27, v27, v20
+
+ div-float v19, v19, v20
+
+ div-float v13, v42, v20
+
+ goto :goto_1ff
+
+ :cond_1fd
+ move/from16 v13, v42
+
+ :goto_1ff
+ move/from16 v43, v13
+
+ iget-boolean v13, v0, LSmali;->conditionC:Z
+
+ if-eqz v13, :cond_244
+
+ const/high16 v13, 0x41400000 # 12.0f
+
+ div-float/2addr v5, v13
+
+ div-float/2addr v2, v13
+
+ div-float/2addr v6, v13
+
+ div-float/2addr v7, v13
+
+ div-float/2addr v8, v13
+
+ div-float/2addr v9, v13
+
+ div-float/2addr v10, v13
+
+ div-float/2addr v12, v13
+
+ div-float/2addr v11, v13
+
+ div-float/2addr v1, v13
+
+ div-float/2addr v4, v13
+
+ div-float/2addr v3, v13
+
+ div-float/2addr v15, v13
+
+ div-float/2addr v14, v13
+
+ div-float v16, v16, v13
+
+ div-float v38, v38, v13
+
+ div-float v37, v37, v13
+
+ div-float v36, v36, v13
+
+ div-float v35, v35, v13
+
+ div-float v32, v32, v13
+
+ div-float v31, v31, v13
+
+ div-float v30, v30, v13
+
+ div-float v29, v29, v13
+
+ div-float v28, v28, v13
+
+ div-float v25, v25, v13
+
+ div-float v24, v24, v13
+
+ div-float v23, v23, v13
+
+ div-float v22, v22, v13
+
+ div-float v21, v21, v13
+
+ div-float v39, v39, v13
+
+ div-float v40, v40, v13
+
+ div-float v33, v33, v13
+
+ div-float v34, v34, v13
+
+ div-float v26, v26, v13
+
+ div-float v27, v27, v13
+
+ div-float v19, v19, v13
+
+ div-float v13, v43, v13
+
+ goto :goto_246
+
+ :cond_244
+ move/from16 v13, v43
+
+ :goto_246
+ const/16 v17, 0x0
+
+ mul-float v0, v20, v17
+
+ invoke-static {v0}, Ljava/lang/Math;->round(F)I
+
+ move-result v0
+
+ int-to-float v0, v0
+
+ div-float v0, v0, v20
+
+ move/from16 v44, v1
+
+ new-instance v1, Ljava/lang/StringBuilder;
+
+ invoke-direct {v1}, Ljava/lang/StringBuilder;-><init>()V
+
+ invoke-virtual {v1, v0}, Ljava/lang/StringBuilder;->append(F)Ljava/lang/StringBuilder;
+
+ move/from16 v45, v0
+
+ move-object/from16 v0, v18
+
+ invoke-virtual {v1, v0}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
+
+ invoke-virtual {v1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
+
+ move-result-object v1
+
+ return-void
+.end method
diff --git a/test/626-checker-arm64-scratch-register/src/Main.java b/test/626-checker-arm64-scratch-register/src/Main.java
index 1394917..cf94b87 100644
--- a/test/626-checker-arm64-scratch-register/src/Main.java
+++ b/test/626-checker-arm64-scratch-register/src/Main.java
@@ -13,6 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
public class Main {
@@ -63,14 +65,17 @@
/// CHECK: name "B0"
/// CHECK: <<This:l\d+>> ParameterValue
/// CHECK: end_block
+
/// CHECK: begin_block
- /// CHECK: successors "<<ThenBlock:B\d+>>" "<<ElseBlock:B\d+>>"
+ /// CHECK: successors "<<ThenBlockA:B\d+>>" "<<ElseBlockA:B\d+>>"
+ /// CHECK: <<CondA:z\d+>> InstanceFieldGet [<<This>>] field_name:Main.conditionA
+ /// CHECK: If [<<CondA>>]
+ /// CHECK: end_block
+
+ /// CHECK: begin_block
+ /// CHECK: successors "<<ThenBlockB:B\d+>>" "<<ElseBlockB:B\d+>>"
/// CHECK: <<CondB:z\d+>> InstanceFieldGet [<<This>>] field_name:Main.conditionB
/// CHECK: If [<<CondB>>]
- /// CHECK: end_block
- /// CHECK: begin_block
- /// CHECK: name "<<ElseBlock>>"
- /// CHECK: ParallelMove moves:[40(sp)->d0,24(sp)->32(sp),28(sp)->36(sp),d0->d3,d3->d4,d2->d5,d4->d6,d5->d7,d6->d18,d7->d19,d18->d20,d19->d21,d20->d22,d21->d23,d22->d10,d23->d11,16(sp)->24(sp),20(sp)->28(sp),d10->d14,d11->d12,d12->d13,d13->d1,d14->d2,32(sp)->16(sp),36(sp)->20(sp)]
/// CHECK: end_block
/// CHECK-START-ARM64: void Main.test() disassembly (after)
@@ -82,39 +87,6 @@
/// CHECK: successors "<<ThenBlock:B\d+>>" "<<ElseBlock:B\d+>>"
/// CHECK: <<CondB:z\d+>> InstanceFieldGet [<<This>>] field_name:Main.conditionB
/// CHECK: If [<<CondB>>]
- /// CHECK: end_block
- /// CHECK: begin_block
- /// CHECK: name "<<ElseBlock>>"
- /// CHECK: ParallelMove moves:[invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid]
- /// CHECK: fmov d31, d2
- /// CHECK: ldr s2, [sp, #36]
- /// CHECK: ldr w16, [sp, #16]
- /// CHECK: str w16, [sp, #36]
- /// CHECK: str s14, [sp, #16]
- /// CHECK: ldr s14, [sp, #28]
- /// CHECK: str s1, [sp, #28]
- /// CHECK: ldr s1, [sp, #32]
- /// CHECK: str s31, [sp, #32]
- /// CHECK: ldr s31, [sp, #20]
- /// CHECK: str s31, [sp, #40]
- /// CHECK: str s12, [sp, #20]
- /// CHECK: fmov d12, d11
- /// CHECK: fmov d11, d10
- /// CHECK: fmov d10, d23
- /// CHECK: fmov d23, d22
- /// CHECK: fmov d22, d21
- /// CHECK: fmov d21, d20
- /// CHECK: fmov d20, d19
- /// CHECK: fmov d19, d18
- /// CHECK: fmov d18, d7
- /// CHECK: fmov d7, d6
- /// CHECK: fmov d6, d5
- /// CHECK: fmov d5, d4
- /// CHECK: fmov d4, d3
- /// CHECK: fmov d3, d13
- /// CHECK: ldr s13, [sp, #24]
- /// CHECK: str s3, [sp, #24]
- /// CHECK: ldr s3, pc+{{\d+}} (addr {{0x[0-9a-f]+}}) (100)
/// CHECK: end_block
public void test() {
@@ -289,9 +261,20 @@
String res = s + r;
}
- public static void main(String[] args) {
+ public static void main(String[] args) throws Exception {
Main main = new Main();
main.test();
+
+ Class<?> cl = Class.forName("Smali");
+ Constructor<?> cons = cl.getConstructor();
+ Object o = cons.newInstance();
+
+ Method test = cl.getMethod("test");
+ test.invoke(o);
+
+ Method testD8 = cl.getMethod("testD8");
+ testD8.invoke(o);
+
System.out.println("passed");
}
}
diff --git a/test/651-checker-byte-simd-minmax/src/Main.java b/test/651-checker-byte-simd-minmax/src/Main.java
index d365689..2188346 100644
--- a/test/651-checker-byte-simd-minmax/src/Main.java
+++ b/test/651-checker-byte-simd-minmax/src/Main.java
@@ -183,6 +183,13 @@
/// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Min:d\d+>> VecMin [<<Get>>,<<Repl>>] packed_type:Int8 loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<Min>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.doitMin100(byte[], byte[]) loop_optimization (after)
+ /// CHECK-DAG: <<I100:i\d+>> IntConstant 100 loop:none
+ /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<I100>>] loop:none
+ /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Min:d\d+>> VecMin [<<Get>>,<<Repl>>] packed_type:Int8 loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<Min>>] loop:<<Loop>> outer_loop:none
private static void doitMin100(byte[] x, byte[] y) {
int min = Math.min(x.length, y.length);
for (int i = 0; i < min; i++) {
diff --git a/test/651-checker-char-simd-minmax/src/Main.java b/test/651-checker-char-simd-minmax/src/Main.java
index 72e8958..d92bdaf 100644
--- a/test/651-checker-char-simd-minmax/src/Main.java
+++ b/test/651-checker-char-simd-minmax/src/Main.java
@@ -97,6 +97,13 @@
/// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Min:d\d+>> VecMin [<<Get>>,<<Repl>>] packed_type:Uint16 loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<Min>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.doitMin100(char[], char[]) loop_optimization (after)
+ /// CHECK-DAG: <<I100:i\d+>> IntConstant 100 loop:none
+ /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<I100>>] loop:none
+ /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Min:d\d+>> VecMin [<<Get>>,<<Repl>>] packed_type:Uint16 loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<Min>>] loop:<<Loop>> outer_loop:none
private static void doitMin100(char[] x, char[] y) {
int min = Math.min(x.length, y.length);
for (int i = 0; i < min; i++) {
diff --git a/test/651-checker-short-simd-minmax/src/Main.java b/test/651-checker-short-simd-minmax/src/Main.java
index d8c4d1e..91f2a2d 100644
--- a/test/651-checker-short-simd-minmax/src/Main.java
+++ b/test/651-checker-short-simd-minmax/src/Main.java
@@ -183,6 +183,13 @@
/// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: <<Min:d\d+>> VecMin [<<Get>>,<<Repl>>] packed_type:Int16 loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<Min>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.doitMin100(short[], short[]) loop_optimization (after)
+ /// CHECK-DAG: <<I100:i\d+>> IntConstant 100 loop:none
+ /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<I100>>] loop:none
+ /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Min:d\d+>> VecMin [<<Get>>,<<Repl>>] packed_type:Int16 loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<Min>>] loop:<<Loop>> outer_loop:none
private static void doitMin100(short[] x, short[] y) {
int min = Math.min(x.length, y.length);
for (int i = 0; i < min; i++) {
diff --git a/test/656-checker-simd-opt/src/Main.java b/test/656-checker-simd-opt/src/Main.java
index 39a126f..31d28e8 100644
--- a/test/656-checker-simd-opt/src/Main.java
+++ b/test/656-checker-simd-opt/src/Main.java
@@ -114,6 +114,19 @@
/// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecAdd [<<Phi2>>,<<Rep>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<L2>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: long Main.longInductionReduction(long[]) loop_optimization (after)
+ /// CHECK-DAG: <<L0:j\d+>> LongConstant 0 loop:none
+ /// CHECK-DAG: <<L1:j\d+>> LongConstant 1 loop:none
+ /// CHECK-DAG: <<L2:j\d+>> LongConstant 2 loop:none
+ /// CHECK-DAG: <<I0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Get:j\d+>> ArrayGet [{{l\d+}},<<I0>>] loop:none
+ /// CHECK-DAG: <<Rep:d\d+>> VecReplicateScalar [<<Get>>] loop:none
+ /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<L1>>] loop:none
+ /// CHECK-DAG: <<Phi1:j\d+>> Phi [<<L0>>,{{j\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecAdd [<<Phi2>>,<<Rep>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: Add [<<Phi1>>,<<L2>>] loop:<<Loop>> outer_loop:none
static long longInductionReduction(long[] y) {
long x = 1;
for (long i = 0; i < 10; i++) {
@@ -141,6 +154,17 @@
/// CHECK-DAG: <<Phi:i\d+>> Phi [<<I0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<Rep>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi>>,<<I4>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.intVectorLongInvariant(int[], long[]) loop_optimization (after)
+ /// CHECK-DAG: <<I0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<I1:i\d+>> IntConstant 1 loop:none
+ /// CHECK-DAG: <<I4:i\d+>> IntConstant 4 loop:none
+ /// CHECK-DAG: <<Get:j\d+>> ArrayGet [{{l\d+}},<<I0>>] loop:none
+ /// CHECK-DAG: <<Cnv:i\d+>> TypeConversion [<<Get>>] loop:none
+ /// CHECK-DAG: <<Rep:d\d+>> VecReplicateScalar [<<Cnv>>] loop:none
+ /// CHECK-DAG: <<Phi:i\d+>> Phi [<<I0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<Rep>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: Add [<<Phi>>,<<I4>>] loop:<<Loop>> outer_loop:none
static void intVectorLongInvariant(int[] x, long[] y) {
for (int i = 0; i < 100; i++) {
x[i] = (int) y[0];
@@ -170,6 +194,18 @@
/// CHECK-DAG: <<Add:d\d+>> VecAdd [<<Load>>,<<Rep>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<Add>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi>>,<<I4>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: void Main.longCanBeDoneWithInt(int[], int[]) loop_optimization (after)
+ /// CHECK-DAG: <<I0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<I4:i\d+>> IntConstant 4 loop:none
+ /// CHECK-DAG: <<L1:j\d+>> LongConstant 1 loop:none
+ /// CHECK-DAG: <<Cnv:i\d+>> TypeConversion [<<L1>>] loop:none
+ /// CHECK-DAG: <<Rep:d\d+>> VecReplicateScalar [<<Cnv>>] loop:none
+ /// CHECK-DAG: <<Phi:i\d+>> Phi [<<I0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<Phi>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Add:d\d+>> VecAdd [<<Load>>,<<Rep>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<Add>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: Add [<<Phi>>,<<I4>>] loop:<<Loop>> outer_loop:none
static void longCanBeDoneWithInt(int[] x, int[] y) {
for (int i = 0; i < 100; i++) {
x[i] = (int) (y[i] + 1L);
diff --git a/test/660-checker-simd-sad-byte/src/Main.java b/test/660-checker-simd-sad-byte/src/Main.java
index 72d1c24..877d718 100644
--- a/test/660-checker-simd-sad-byte/src/Main.java
+++ b/test/660-checker-simd-sad-byte/src/Main.java
@@ -109,6 +109,17 @@
/// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons16>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: int Main.sadByte2Int(byte[], byte[]) loop_optimization (after)
+ /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Cons16:i\d+>> IntConstant 16 loop:none
+ /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load1:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: Add [<<Phi1>>,<<Cons16>>] loop:<<Loop>> outer_loop:none
private static int sadByte2Int(byte[] b1, byte[] b2) {
int min_length = Math.min(b1.length, b2.length);
int sad = 0;
@@ -140,6 +151,17 @@
/// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load2>>,<<Load1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons16>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: int Main.sadByte2IntAlt(byte[], byte[]) loop_optimization (after)
+ /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Cons16:i\d+>> IntConstant 16 loop:none
+ /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load1:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load2>>,<<Load1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: Add [<<Phi1>>,<<Cons16>>] loop:<<Loop>> outer_loop:none
private static int sadByte2IntAlt(byte[] b1, byte[] b2) {
int min_length = Math.min(b1.length, b2.length);
int sad = 0;
@@ -173,6 +195,17 @@
/// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons16>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: int Main.sadByte2IntAlt2(byte[], byte[]) loop_optimization (after)
+ /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Cons16:i\d+>> IntConstant 16 loop:none
+ /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load1:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: Add [<<Phi1>>,<<Cons16>>] loop:<<Loop>> outer_loop:none
private static int sadByte2IntAlt2(byte[] b1, byte[] b2) {
int min_length = Math.min(b1.length, b2.length);
int sad = 0;
@@ -212,6 +245,18 @@
/// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons16>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: long Main.sadByte2Long(byte[], byte[]) loop_optimization (after)
+ /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Cons16:i\d+>> IntConstant 16 loop:none
+ /// CHECK-DAG: <<ConsL:j\d+>> LongConstant 0 loop:none
+ /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<ConsL>>] loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load1:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: Add [<<Phi1>>,<<Cons16>>] loop:<<Loop>> outer_loop:none
private static long sadByte2Long(byte[] b1, byte[] b2) {
int min_length = Math.min(b1.length, b2.length);
long sad = 0;
@@ -249,6 +294,18 @@
/// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons16>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: long Main.sadByte2LongAt1(byte[], byte[]) loop_optimization (after)
+ /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Cons16:i\d+>> IntConstant 16 loop:none
+ /// CHECK-DAG: <<ConsL:j\d+>> LongConstant 1 loop:none
+ /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<ConsL>>] loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load1:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: Add [<<Phi1>>,<<Cons16>>] loop:<<Loop>> outer_loop:none
private static long sadByte2LongAt1(byte[] b1, byte[] b2) {
int min_length = Math.min(b1.length, b2.length);
long sad = 1; // starts at 1
diff --git a/test/660-checker-simd-sad-char/src/Main.java b/test/660-checker-simd-sad-char/src/Main.java
index 2535d49..ba22614 100644
--- a/test/660-checker-simd-sad-char/src/Main.java
+++ b/test/660-checker-simd-sad-char/src/Main.java
@@ -68,7 +68,7 @@
/// CHECK-DAG: Add [<<Phi2>>,<<Intrin>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: int Main.sadChar2Int(char[], char[]) loop_optimization (after)
+ /// CHECK-START: int Main.sadChar2Int(char[], char[]) loop_optimization (after)
/// CHECK-NOT: VecSADAccumulate
private static int sadChar2Int(char[] s1, char[] s2) {
int min_length = Math.min(s1.length, s2.length);
@@ -91,7 +91,7 @@
/// CHECK-DAG: Add [<<Phi2>>,<<Intrin>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: int Main.sadChar2IntAlt(char[], char[]) loop_optimization (after)
+ /// CHECK-START: int Main.sadChar2IntAlt(char[], char[]) loop_optimization (after)
/// CHECK-NOT: VecSADAccumulate
private static int sadChar2IntAlt(char[] s1, char[] s2) {
int min_length = Math.min(s1.length, s2.length);
@@ -116,7 +116,7 @@
/// CHECK-DAG: Add [<<Phi2>>,<<Intrin>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: int Main.sadChar2IntAlt2(char[], char[]) loop_optimization (after)
+ /// CHECK-START: int Main.sadChar2IntAlt2(char[], char[]) loop_optimization (after)
/// CHECK-NOT: VecSADAccumulate
private static int sadChar2IntAlt2(char[] s1, char[] s2) {
int min_length = Math.min(s1.length, s2.length);
@@ -146,7 +146,7 @@
/// CHECK-DAG: Add [<<Phi2>>,<<Intrin>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: long Main.sadChar2Long(char[], char[]) loop_optimization (after)
+ /// CHECK-START: long Main.sadChar2Long(char[], char[]) loop_optimization (after)
/// CHECK-NOT: VecSADAccumulate
private static long sadChar2Long(char[] s1, char[] s2) {
int min_length = Math.min(s1.length, s2.length);
@@ -174,7 +174,7 @@
/// CHECK-DAG: Add [<<Phi2>>,<<Intrin>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-ARM64: long Main.sadChar2LongAt1(char[], char[]) loop_optimization (after)
+ /// CHECK-START: long Main.sadChar2LongAt1(char[], char[]) loop_optimization (after)
/// CHECK-NOT: VecSADAccumulate
private static long sadChar2LongAt1(char[] s1, char[] s2) {
int min_length = Math.min(s1.length, s2.length);
diff --git a/test/660-checker-simd-sad-int/src/Main.java b/test/660-checker-simd-sad-int/src/Main.java
index 388bfba..d7d5a95 100644
--- a/test/660-checker-simd-sad-int/src/Main.java
+++ b/test/660-checker-simd-sad-int/src/Main.java
@@ -48,6 +48,15 @@
/// CHECK-DAG: <<Ld2:d\d+>> VecLoad [{{l\d+}},<<I>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi>>,<<Ld1>>,<<Ld2>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<I>>,<<Cons4>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: int Main.sadInt2Int(int[], int[]) loop_optimization (after)
+ /// CHECK-DAG: <<Cons4:i\d+>> IntConstant 4 loop:none
+ /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [{{i\d+}}] loop:none
+ /// CHECK-DAG: <<Phi:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Ld1:d\d+>> VecLoad [{{l\d+}},<<I:i\d+>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Ld2:d\d+>> VecLoad [{{l\d+}},<<I>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi>>,<<Ld1>>,<<Ld2>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: Add [<<I>>,<<Cons4>>] loop:<<Loop>> outer_loop:none
private static int sadInt2Int(int[] x, int[] y) {
int min_length = Math.min(x.length, y.length);
int sad = 0;
@@ -72,10 +81,7 @@
//
// No ABS? No SAD!
//
- /// CHECK-START-ARM: int Main.sadInt2IntAlt(int[], int[]) loop_optimization (after)
- /// CHECK-NOT: VecSADAccumulate
- //
- /// CHECK-START-ARM64: int Main.sadInt2IntAlt(int[], int[]) loop_optimization (after)
+ /// CHECK-START: int Main.sadInt2IntAlt(int[], int[]) loop_optimization (after)
/// CHECK-NOT: VecSADAccumulate
private static int sadInt2IntAlt(int[] x, int[] y) {
int min_length = Math.min(x.length, y.length);
@@ -117,6 +123,15 @@
/// CHECK-DAG: <<Ld2:d\d+>> VecLoad [{{l\d+}},<<I>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi>>,<<Ld1>>,<<Ld2>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<I>>,<<Cons4>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: int Main.sadInt2IntAlt2(int[], int[]) loop_optimization (after)
+ /// CHECK-DAG: <<Cons4:i\d+>> IntConstant 4 loop:none
+ /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [{{i\d+}}] loop:none
+ /// CHECK-DAG: <<Phi:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Ld1:d\d+>> VecLoad [{{l\d+}},<<I:i\d+>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Ld2:d\d+>> VecLoad [{{l\d+}},<<I>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi>>,<<Ld1>>,<<Ld2>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: Add [<<I>>,<<Cons4>>] loop:<<Loop>> outer_loop:none
private static int sadInt2IntAlt2(int[] x, int[] y) {
int min_length = Math.min(x.length, y.length);
int sad = 0;
@@ -156,6 +171,18 @@
/// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons4>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: long Main.sadInt2Long(int[], int[]) loop_optimization (after)
+ /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Cons4:i\d+>> IntConstant 4 loop:none
+ /// CHECK-DAG: <<ConsL:j\d+>> LongConstant 0 loop:none
+ /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<ConsL>>] loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load1:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: Add [<<Phi1>>,<<Cons4>>] loop:<<Loop>> outer_loop:none
private static long sadInt2Long(int[] x, int[] y) {
int min_length = Math.min(x.length, y.length);
long sad = 0;
@@ -193,6 +220,18 @@
/// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons4>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: long Main.sadInt2LongAt1(int[], int[]) loop_optimization (after)
+ /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Cons4:i\d+>> IntConstant 4 loop:none
+ /// CHECK-DAG: <<ConsL:j\d+>> LongConstant 1 loop:none
+ /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<ConsL>>] loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load1:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: Add [<<Phi1>>,<<Cons4>>] loop:<<Loop>> outer_loop:none
private static long sadInt2LongAt1(int[] x, int[] y) {
int min_length = Math.min(x.length, y.length);
long sad = 1; // starts at 1
diff --git a/test/660-checker-simd-sad-long/src/Main.java b/test/660-checker-simd-sad-long/src/Main.java
index 06f62bd..d080e0c 100644
--- a/test/660-checker-simd-sad-long/src/Main.java
+++ b/test/660-checker-simd-sad-long/src/Main.java
@@ -43,6 +43,18 @@
/// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons2>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: long Main.sadLong2Long(long[], long[]) loop_optimization (after)
+ /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Cons2:i\d+>> IntConstant 2 loop:none
+ /// CHECK-DAG: <<ConsL:j\d+>> LongConstant 0 loop:none
+ /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<ConsL>>] loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load1:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: Add [<<Phi1>>,<<Cons2>>] loop:<<Loop>> outer_loop:none
private static long sadLong2Long(long[] x, long[] y) {
int min_length = Math.min(x.length, y.length);
long sad = 0;
@@ -105,6 +117,18 @@
/// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons2>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: long Main.sadLong2LongAlt2(long[], long[]) loop_optimization (after)
+ /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Cons2:i\d+>> IntConstant 2 loop:none
+ /// CHECK-DAG: <<ConsL:j\d+>> LongConstant 0 loop:none
+ /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<ConsL>>] loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load1:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: Add [<<Phi1>>,<<Cons2>>] loop:<<Loop>> outer_loop:none
private static long sadLong2LongAlt2(long[] x, long[] y) {
int min_length = Math.min(x.length, y.length);
long sad = 0;
@@ -142,6 +166,18 @@
/// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons2>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: long Main.sadLong2LongAt1(long[], long[]) loop_optimization (after)
+ /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Cons2:i\d+>> IntConstant 2 loop:none
+ /// CHECK-DAG: <<ConsL:j\d+>> LongConstant 1 loop:none
+ /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<ConsL>>] loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load1:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: Add [<<Phi1>>,<<Cons2>>] loop:<<Loop>> outer_loop:none
private static long sadLong2LongAt1(long[] x, long[] y) {
int min_length = Math.min(x.length, y.length);
long sad = 1; // starts at 1
diff --git a/test/660-checker-simd-sad-short/src/Main.java b/test/660-checker-simd-sad-short/src/Main.java
index d94308e..4ab6682 100644
--- a/test/660-checker-simd-sad-short/src/Main.java
+++ b/test/660-checker-simd-sad-short/src/Main.java
@@ -76,6 +76,17 @@
/// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: int Main.sadShort2Int(short[], short[]) loop_optimization (after)
+ /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
+ /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load1:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
private static int sadShort2Int(short[] s1, short[] s2) {
int min_length = Math.min(s1.length, s2.length);
int sad = 0;
@@ -107,6 +118,17 @@
/// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load2>>,<<Load1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: int Main.sadShort2IntAlt(short[], short[]) loop_optimization (after)
+ /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
+ /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load1:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load2>>,<<Load1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
private static int sadShort2IntAlt(short[] s1, short[] s2) {
int min_length = Math.min(s1.length, s2.length);
int sad = 0;
@@ -140,6 +162,17 @@
/// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: int Main.sadShort2IntAlt2(short[], short[]) loop_optimization (after)
+ /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
+ /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load1:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
private static int sadShort2IntAlt2(short[] s1, short[] s2) {
int min_length = Math.min(s1.length, s2.length);
int sad = 0;
@@ -179,6 +212,18 @@
/// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: long Main.sadShort2Long(short[], short[]) loop_optimization (after)
+ /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
+ /// CHECK-DAG: <<ConsL:j\d+>> LongConstant 0 loop:none
+ /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<ConsL>>] loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load1:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
private static long sadShort2Long(short[] s1, short[] s2) {
int min_length = Math.min(s1.length, s2.length);
long sad = 0;
@@ -216,6 +261,18 @@
/// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: long Main.sadShort2LongAt1(short[], short[]) loop_optimization (after)
+ /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
+ /// CHECK-DAG: <<ConsL:j\d+>> LongConstant 1 loop:none
+ /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<ConsL>>] loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load1:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
private static long sadShort2LongAt1(short[] s1, short[] s2) {
int min_length = Math.min(s1.length, s2.length);
long sad = 1; // starts at 1
diff --git a/test/660-checker-simd-sad-short2/src/Main.java b/test/660-checker-simd-sad-short2/src/Main.java
index 708f3aa..331f5ce 100644
--- a/test/660-checker-simd-sad-short2/src/Main.java
+++ b/test/660-checker-simd-sad-short2/src/Main.java
@@ -94,6 +94,17 @@
/// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: int Main.sadCastedChar2Int(char[], char[]) loop_optimization (after)
+ /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
+ /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load1:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
private static int sadCastedChar2Int(char[] s1, char[] s2) {
int min_length = Math.min(s1.length, s2.length);
int sad = 0;
@@ -144,6 +155,17 @@
/// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load2>>,<<Load1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: int Main.sadCastedChar2IntAlt(char[], char[]) loop_optimization (after)
+ /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
+ /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load1:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load2>>,<<Load1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
private static int sadCastedChar2IntAlt(char[] s1, char[] s2) {
int min_length = Math.min(s1.length, s2.length);
int sad = 0;
@@ -196,6 +218,17 @@
/// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: int Main.sadCastedChar2IntAlt2(char[], char[]) loop_optimization (after)
+ /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
+ /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load1:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
private static int sadCastedChar2IntAlt2(char[] s1, char[] s2) {
int min_length = Math.min(s1.length, s2.length);
int sad = 0;
@@ -254,6 +287,18 @@
/// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: long Main.sadCastedChar2Long(char[], char[]) loop_optimization (after)
+ /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
+ /// CHECK-DAG: <<ConsL:j\d+>> LongConstant 0 loop:none
+ /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<ConsL>>] loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load1:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
private static long sadCastedChar2Long(char[] s1, char[] s2) {
int min_length = Math.min(s1.length, s2.length);
long sad = 0;
@@ -310,6 +355,18 @@
/// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: long Main.sadCastedChar2LongAt1(char[], char[]) loop_optimization (after)
+ /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
+ /// CHECK-DAG: <<ConsL:j\d+>> LongConstant 1 loop:none
+ /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<ConsL>>] loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load1:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load2:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load1>>,<<Load2>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
private static long sadCastedChar2LongAt1(char[] s1, char[] s2) {
int min_length = Math.min(s1.length, s2.length);
long sad = 1; // starts at 1
diff --git a/test/660-checker-simd-sad-short3/src/Main.java b/test/660-checker-simd-sad-short3/src/Main.java
index c8850b4..ecda884 100644
--- a/test/660-checker-simd-sad-short3/src/Main.java
+++ b/test/660-checker-simd-sad-short3/src/Main.java
@@ -44,6 +44,18 @@
/// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load>>,<<Rep>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: int Main.sadShort2IntParamRight(short[], short) loop_optimization (after)
+ /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
+ /// CHECK-DAG: <<Param:s\d+>> ParameterValue loop:none
+ /// CHECK-DAG: <<Rep:d\d+>> VecReplicateScalar [<<Param>>] loop:none
+ /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load>>,<<Rep>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
private static int sadShort2IntParamRight(short[] s, short param) {
int sad = 0;
for (int i = 0; i < s.length; i++) {
@@ -75,6 +87,18 @@
/// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Rep>>,<<Load>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: int Main.sadShort2IntParamLeft(short[], short) loop_optimization (after)
+ /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
+ /// CHECK-DAG: <<Param:s\d+>> ParameterValue loop:none
+ /// CHECK-DAG: <<Rep:d\d+>> VecReplicateScalar [<<Param>>] loop:none
+ /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Rep>>,<<Load>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
private static int sadShort2IntParamLeft(short[] s, short param) {
int sad = 0;
for (int i = 0; i < s.length; i++) {
@@ -106,6 +130,18 @@
/// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load>>,<<Rep>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: int Main.sadShort2IntConstRight(short[]) loop_optimization (after)
+ /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
+ /// CHECK-DAG: <<ConsI:i\d+>> IntConstant 32767 loop:none
+ /// CHECK-DAG: <<Rep:d\d+>> VecReplicateScalar [<<ConsI>>] loop:none
+ /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load>>,<<Rep>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
private static int sadShort2IntConstRight(short[] s) {
int sad = 0;
for (int i = 0; i < s.length; i++) {
@@ -137,6 +173,18 @@
/// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Rep>>,<<Load>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: int Main.sadShort2IntConstLeft(short[]) loop_optimization (after)
+ /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
+ /// CHECK-DAG: <<ConsI:i\d+>> IntConstant 32767 loop:none
+ /// CHECK-DAG: <<Rep:d\d+>> VecReplicateScalar [<<ConsI>>] loop:none
+ /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Rep>>,<<Load>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
private static int sadShort2IntConstLeft(short[] s) {
int sad = 0;
for (int i = 0; i < s.length; i++) {
@@ -168,6 +216,18 @@
/// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load>>,<<Rep>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: int Main.sadShort2IntInvariantRight(short[], int) loop_optimization (after)
+ /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
+ /// CHECK-DAG: <<Conv:s\d+>> TypeConversion [{{i\d+}}] loop:none
+ /// CHECK-DAG: <<Rep:d\d+>> VecReplicateScalar [<<Conv>>] loop:none
+ /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load>>,<<Rep>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none
private static int sadShort2IntInvariantRight(short[] s, int val) {
int sad = 0;
short x = (short) (val + 1);
@@ -199,6 +259,17 @@
/// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Rep>>,<<Load>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: int Main.sadShort2IntInvariantLeft(short[], int) loop_optimization (after)
+ /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
+ /// CHECK-DAG: <<Conv:s\d+>> TypeConversion [{{i\d+}}] loop:none
+ /// CHECK-DAG: <<Rep:d\d+>> VecReplicateScalar [<<Conv>>] loop:none
+ /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Rep>>,<<Load>>] loop:<<Loop>> outer_loop:none
private static int sadShort2IntInvariantLeft(short[] s, int val) {
int sad = 0;
short x = (short) (val + 1);
@@ -233,6 +304,18 @@
/// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Add:d\d+>> VecAdd [<<Load>>,<<Rep>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load>>,<<Add>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: int Main.sadShort2IntCastedExprRight(short[]) loop_optimization (after)
+ /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
+ /// CHECK-DAG: <<ConsI:i\d+>> IntConstant 110 loop:none
+ /// CHECK-DAG: <<Rep:d\d+>> VecReplicateScalar [<<ConsI>>] loop:none
+ /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Add:d\d+>> VecAdd [<<Load>>,<<Rep>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load>>,<<Add>>] loop:<<Loop>> outer_loop:none
private static int sadShort2IntCastedExprRight(short[] s) {
int sad = 0;
for (int i = 0; i < s.length; i++) {
@@ -267,6 +350,18 @@
/// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Add:d\d+>> VecAdd [<<Load>>,<<Rep>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Add>>,<<Load>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-START-MIPS64: int Main.sadShort2IntCastedExprLeft(short[]) loop_optimization (after)
+ /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none
+ /// CHECK-DAG: <<ConsI:i\d+>> IntConstant 110 loop:none
+ /// CHECK-DAG: <<Rep:d\d+>> VecReplicateScalar [<<ConsI>>] loop:none
+ /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Add:d\d+>> VecAdd [<<Load>>,<<Rep>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Add>>,<<Load>>] loop:<<Loop>> outer_loop:none
private static int sadShort2IntCastedExprLeft(short[] s) {
int sad = 0;
for (int i = 0; i < s.length; i++) {
diff --git a/test/913-heaps/build b/test/913-heaps/build
deleted file mode 100644
index 10ffcc5..0000000
--- a/test/913-heaps/build
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-#
-# Copyright 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.
-
-# See b/65168732
-export USE_D8=false
-
-./default-build "$@"
diff --git a/test/913-heaps/check b/test/913-heaps/check
index 8358500..f4892d0 100644
--- a/test/913-heaps/check
+++ b/test/913-heaps/check
@@ -14,9 +14,12 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# Jack has a different set of bytecode offsets/method IDs in the expected.txt
+# Jack/D8 has a different set of bytecode offsets/method IDs in the expected.txt
+
if [[ "$USE_JACK" == true ]]; then
patch -p0 expected.txt < expected_jack.diff
+elif [[ "$USE_D8" == true ]]; then
+ patch -p0 expected.txt < expected_d8.diff
fi
./default-check "$@"
diff --git a/test/913-heaps/expected_d8.diff b/test/913-heaps/expected_d8.diff
new file mode 100644
index 0000000..8369422
--- /dev/null
+++ b/test/913-heaps/expected_d8.diff
@@ -0,0 +1,76 @@
+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=5,location= 21])--> 1@1000 [size=16, length=-1]
+> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=8,location= 21])--> 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=5,location= 21])--> 1@1000 [size=16, length=-1]
+> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=8,location= 21])--> 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=5,location= 21])--> 1@1000 [size=16, length=-1]
+> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=8,location= 21])--> 1@1000 [size=16, length=-1]
+201,202c202,203
+< 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=4,method=runFollowReferences,vreg=3,location= 164])--> 1000@0 [size=123456780050, length=-1]
+246c247
+< 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]
+248c249,251
+< 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=5,location= 21])--> 1@1000 [size=16, length=-1]
+> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=8,location= 21])--> 1@1000 [size=16, length=-1]
+> root@root --(stack-local[id=1,tag=3000,depth=4,method=runFollowReferences,vreg=3,location= 164])--> 1000@0 [size=123456780055, length=-1]
+292c295
+< 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=4,method=runFollowReferences,vreg=3,location= 181])--> 1000@0 [size=123456780060, length=-1]
+319a323
+> root@root --(stack-local[id=1,tag=3000,depth=4,method=runFollowReferences,vreg=3,location= 181])--> 1000@0 [size=123456780065, length=-1]
+347c351
+< 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]
+366c370
+< 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]
+368c372,373
+< 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=5,location= 21])--> 1@1000 [size=16, length=-1]
+> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=8,location= 21])--> 1@1000 [size=16, length=-1]
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index 69e4b87..8755f04 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -40,46 +40,22 @@
TEST_ART_TARGET_SYNC_DEPS += $(ART_TARGET_EXECUTABLES) $(TARGET_CORE_IMG_OUTS)
# Also need libartagent.
-TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_ARCH)_libartagent)
-TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_ARCH)_libartagentd)
-ifdef TARGET_2ND_ARCH
-TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_2ND_ARCH)_libartagent)
-TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_2ND_ARCH)_libartagentd)
-endif
+TEST_ART_TARGET_SYNC_DEPS += libartagent-target libartagentd-target
# Also need libtiagent.
-TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_ARCH)_libtiagent)
-TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_ARCH)_libtiagentd)
-ifdef TARGET_2ND_ARCH
-TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_2ND_ARCH)_libtiagent)
-TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_2ND_ARCH)_libtiagentd)
-endif
+TEST_ART_TARGET_SYNC_DEPS += libtiagent-target libtiagentd-target
# Also need libtistress.
-TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_ARCH)_libtistress)
-TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_ARCH)_libtistressd)
-ifdef TARGET_2ND_ARCH
-TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_2ND_ARCH)_libtistress)
-TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_2ND_ARCH)_libtistressd)
-endif
+TEST_ART_TARGET_SYNC_DEPS += libtistress-target libtistressd-target
# Also need libarttest.
-TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_ARCH)_libarttest)
-TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_ARCH)_libarttestd)
-ifdef TARGET_2ND_ARCH
-TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_2ND_ARCH)_libarttest)
-TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_2ND_ARCH)_libarttestd)
-endif
+TEST_ART_TARGET_SYNC_DEPS += libarttest-target libarttestd-target
# Also need libnativebridgetest.
-TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_ARCH)_libnativebridgetest)
-ifdef TARGET_2ND_ARCH
-TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_2ND_ARCH)_libnativebridgetest)
-endif
+TEST_ART_TARGET_SYNC_DEPS += libnativebridgetest-target
# Also need libopenjdkjvmti.
-TEST_ART_TARGET_SYNC_DEPS += libopenjdkjvmti
-TEST_ART_TARGET_SYNC_DEPS += libopenjdkjvmtid
+TEST_ART_TARGET_SYNC_DEPS += libopenjdkjvmti-target libopenjdkjvmtid-target
TEST_ART_TARGET_SYNC_DEPS += $(TARGET_OUT_JAVA_LIBRARIES)/core-libart-testdex.jar
TEST_ART_TARGET_SYNC_DEPS += $(TARGET_OUT_JAVA_LIBRARIES)/core-oj-testdex.jar
diff --git a/test/common/runtime_state.cc b/test/common/runtime_state.cc
index 2b940ab..df497c1 100644
--- a/test/common/runtime_state.cc
+++ b/test/common/runtime_state.cc
@@ -26,6 +26,7 @@
#include "jit/profiling_info.h"
#include "mirror/class-inl.h"
#include "nativehelper/ScopedUtfChars.h"
+#include "oat_file.h"
#include "oat_quick_method_header.h"
#include "runtime.h"
#include "scoped_thread_state_change-inl.h"
diff --git a/tools/ahat/etc/test-dump.pro b/tools/ahat/etc/test-dump.pro
index 284e4b8..296d411 100644
--- a/tools/ahat/etc/test-dump.pro
+++ b/tools/ahat/etc/test-dump.pro
@@ -3,3 +3,12 @@
public static void main(java.lang.String[]);
}
+-keep public class SuperDumpedStuff {
+ public void allocateObjectAtUnObfSuperSite();
+}
+
+# Produce useful obfuscated stack traces so we can test useful deobfuscation
+# of stack traces.
+-renamesourcefileattribute SourceFile
+-keepattributes SourceFile,LineNumberTable
+
diff --git a/tools/ahat/src/main/com/android/ahat/proguard/ProguardMap.java b/tools/ahat/src/main/com/android/ahat/proguard/ProguardMap.java
index 131bbf3..32bb209 100644
--- a/tools/ahat/src/main/com/android/ahat/proguard/ProguardMap.java
+++ b/tools/ahat/src/main/com/android/ahat/proguard/ProguardMap.java
@@ -88,12 +88,10 @@
String key = obfuscatedMethodName + clearSignature;
FrameData frame = mFrames.get(key);
if (frame == null) {
- return new Frame(obfuscatedMethodName, clearSignature,
- obfuscatedFilename, obfuscatedLine);
+ frame = new FrameData(obfuscatedMethodName, 0);
}
return new Frame(frame.clearMethodName, clearSignature,
- getFileName(clearClassName, frame.clearMethodName),
- obfuscatedLine - frame.lineDelta);
+ getFileName(clearClassName), obfuscatedLine - frame.lineDelta);
}
}
@@ -313,15 +311,10 @@
return builder.toString();
}
- // Return a file name for the given clear class name and method.
- private static String getFileName(String clearClass, String method) {
- int dot = method.lastIndexOf('.');
- if (dot != -1) {
- clearClass = method.substring(0, dot);
- }
-
+ // Return a file name for the given clear class name.
+ private static String getFileName(String clearClass) {
String filename = clearClass;
- dot = filename.lastIndexOf('.');
+ int dot = filename.lastIndexOf('.');
if (dot != -1) {
filename = filename.substring(dot + 1);
}
diff --git a/tools/ahat/src/test-dump/DumpedStuff.java b/tools/ahat/src/test-dump/DumpedStuff.java
new file mode 100644
index 0000000..98ead07
--- /dev/null
+++ b/tools/ahat/src/test-dump/DumpedStuff.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+import java.lang.ref.PhantomReference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.SoftReference;
+import java.lang.ref.WeakReference;
+import libcore.util.NativeAllocationRegistry;
+
+// We take a heap dump that includes a single instance of this
+// DumpedStuff class. Objects stored as fields in this class can be easily
+// found in the hprof dump by searching for the instance of the DumpedStuff
+// class and reading the desired field.
+public class DumpedStuff extends SuperDumpedStuff {
+ private void allocateObjectAtKnownSite() {
+ objectAllocatedAtKnownSite = new Object();
+ allocateObjectAtKnownSubSite();
+ allocateObjectAtObfSuperSite();
+ allocateObjectAtUnObfSuperSite();
+ allocateObjectAtOverriddenSite();
+ }
+
+ private void allocateObjectAtKnownSubSite() {
+ objectAllocatedAtKnownSubSite = new Object();
+ }
+
+ public void allocateObjectAtOverriddenSite() {
+ objectAllocatedAtOverriddenSite = new Object();
+ }
+
+ DumpedStuff(boolean baseline) {
+ allocateObjectAtKnownSite();
+
+ int n = baseline ? 400000 : 1000000;
+ bigArray = new byte[n];
+ for (int i = 0; i < n; i++) {
+ bigArray[i] = (byte)((i * i) & 0xFF);
+ }
+
+ // 0x12345, 50000, and 0xABCDABCD are arbitrary values.
+ NativeAllocationRegistry registry = new NativeAllocationRegistry(
+ Main.class.getClassLoader(), 0x12345, 50000);
+ registry.registerNativeAllocation(anObject, 0xABCDABCD);
+
+ {
+ Object object = new Object();
+ aLongStrongPathToSamplePathObject = new Reference(new Reference(new Reference(object)));
+ aShortWeakPathToSamplePathObject = new WeakReference(new Reference(object));
+ }
+
+ addedObject = baseline ? null : new AddedObject();
+ removedObject = baseline ? new RemovedObject() : null;
+ modifiedObject = new ModifiedObject();
+ modifiedObject.value = baseline ? 5 : 8;
+ modifiedObject.modifiedRefField = baseline ? "A1" : "A2";
+ modifiedObject.unmodifiedRefField = "B";
+ modifiedStaticField = baseline ? "C1" : "C2";
+ modifiedArray = baseline ? new int[]{0, 1, 2, 3} : new int[]{3, 1, 2, 0};
+
+ // Deep matching dominator trees shouldn't smash the stack when we try
+ // to diff them. Make some deep dominator trees to help test it.
+ for (int i = 0; i < 10000; i++) {
+ StackSmasher smasher = new StackSmasher();
+ smasher.child = stackSmasher;
+ stackSmasher = smasher;
+
+ if (!baseline) {
+ smasher = new StackSmasher();
+ smasher.child = stackSmasherAdded;
+ stackSmasherAdded = smasher;
+ }
+ }
+
+ gcPathArray[2].right.left = gcPathArray[2].left.right;
+ }
+
+ public static class ObjectTree {
+ public ObjectTree left;
+ public ObjectTree right;
+
+ public ObjectTree(ObjectTree left, ObjectTree right) {
+ this.left = left;
+ this.right = right;
+ }
+ }
+
+ public static class AddedObject {
+ }
+
+ public static class RemovedObject {
+ }
+
+ public static class UnchangedObject {
+ }
+
+ public static class ModifiedObject {
+ public int value;
+ public String modifiedRefField;
+ public String unmodifiedRefField;
+ }
+
+ public static class StackSmasher {
+ public StackSmasher child;
+ }
+
+ public static class Reference {
+ public Object referent;
+
+ public Reference(Object referent) {
+ this.referent = referent;
+ }
+ }
+
+ public String basicString = "hello, world";
+ public String nonAscii = "Sigma (Ʃ) is not ASCII";
+ public String embeddedZero = "embedded\0..."; // Non-ASCII for string compression purposes.
+ public char[] charArray = "char thing".toCharArray();
+ public String nullString = null;
+ public Object anObject = new Object();
+ public Reference aReference = new Reference(anObject);
+ public ReferenceQueue<Object> referenceQueue = new ReferenceQueue<Object>();
+ public PhantomReference aPhantomReference = new PhantomReference(anObject, referenceQueue);
+ public WeakReference aWeakReference = new WeakReference(anObject, referenceQueue);
+ public WeakReference aNullReferentReference = new WeakReference(null, referenceQueue);
+ public SoftReference aSoftReference = new SoftReference(new Object());
+ public byte[] bigArray;
+ public ObjectTree[] gcPathArray = new ObjectTree[]{null, null,
+ new ObjectTree(
+ new ObjectTree(null, new ObjectTree(null, null)),
+ new ObjectTree(null, null)),
+ null};
+ 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 Object[] basicStringRef;
+ public AddedObject addedObject;
+ public UnchangedObject unchangedObject = new UnchangedObject();
+ public RemovedObject removedObject;
+ public ModifiedObject modifiedObject;
+ public StackSmasher stackSmasher;
+ public StackSmasher stackSmasherAdded;
+ public static String modifiedStaticField;
+ public int[] modifiedArray;
+ public Object objectAllocatedAtKnownSite;
+ public Object objectAllocatedAtKnownSubSite;
+}
diff --git a/tools/ahat/src/test-dump/Main.java b/tools/ahat/src/test-dump/Main.java
index 079be7d..de36748 100644
--- a/tools/ahat/src/test-dump/Main.java
+++ b/tools/ahat/src/test-dump/Main.java
@@ -16,11 +16,6 @@
import dalvik.system.VMDebug;
import java.io.IOException;
-import java.lang.ref.PhantomReference;
-import java.lang.ref.ReferenceQueue;
-import java.lang.ref.SoftReference;
-import java.lang.ref.WeakReference;
-import libcore.util.NativeAllocationRegistry;
import org.apache.harmony.dalvik.ddmc.DdmVmInternal;
/**
@@ -31,138 +26,6 @@
// collected before we take the heap dump.
public static DumpedStuff stuff;
- public static class ObjectTree {
- public ObjectTree left;
- public ObjectTree right;
-
- public ObjectTree(ObjectTree left, ObjectTree right) {
- this.left = left;
- this.right = right;
- }
- }
-
- public static class AddedObject {
- }
-
- public static class RemovedObject {
- }
-
- public static class UnchangedObject {
- }
-
- public static class ModifiedObject {
- public int value;
- public String modifiedRefField;
- public String unmodifiedRefField;
- }
-
- public static class StackSmasher {
- public StackSmasher child;
- }
-
- public static class Reference {
- public Object referent;
-
- public Reference(Object referent) {
- this.referent = referent;
- }
- }
-
- // We will take a heap dump that includes a single instance of this
- // DumpedStuff class. Objects stored as fields in this class can be easily
- // found in the hprof dump by searching for the instance of the DumpedStuff
- // class and reading the desired field.
- public static class DumpedStuff {
- public String basicString = "hello, world";
- public String nonAscii = "Sigma (Ʃ) is not ASCII";
- public String embeddedZero = "embedded\0..."; // Non-ASCII for string compression purposes.
- public char[] charArray = "char thing".toCharArray();
- public String nullString = null;
- public Object anObject = new Object();
- public Reference aReference = new Reference(anObject);
- public ReferenceQueue<Object> referenceQueue = new ReferenceQueue<Object>();
- public PhantomReference aPhantomReference = new PhantomReference(anObject, referenceQueue);
- public WeakReference aWeakReference = new WeakReference(anObject, referenceQueue);
- public WeakReference aNullReferentReference = new WeakReference(null, referenceQueue);
- public SoftReference aSoftReference = new SoftReference(new Object());
- public byte[] bigArray;
- public ObjectTree[] gcPathArray = new ObjectTree[]{null, null,
- new ObjectTree(
- new ObjectTree(null, new ObjectTree(null, null)),
- new ObjectTree(null, null)),
- null};
- 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 Object[] basicStringRef;
- public AddedObject addedObject;
- public UnchangedObject unchangedObject = new UnchangedObject();
- public RemovedObject removedObject;
- public ModifiedObject modifiedObject;
- public StackSmasher stackSmasher;
- public StackSmasher stackSmasherAdded;
- public static String modifiedStaticField;
- public int[] modifiedArray;
- public Object objectAllocatedAtKnownSite1;
- public Object objectAllocatedAtKnownSite2;
-
- private void allocateObjectAtKnownSite1() {
- objectAllocatedAtKnownSite1 = new Object();
- allocateObjectAtKnownSite2();
- }
-
- private void allocateObjectAtKnownSite2() {
- objectAllocatedAtKnownSite2 = new Object();
- }
-
- DumpedStuff(boolean baseline) {
- int n = baseline ? 400000 : 1000000;
- bigArray = new byte[n];
- for (int i = 0; i < n; i++) {
- bigArray[i] = (byte)((i * i) & 0xFF);
- }
-
- // 0x12345, 50000, and 0xABCDABCD are arbitrary values.
- NativeAllocationRegistry registry = new NativeAllocationRegistry(
- Main.class.getClassLoader(), 0x12345, 50000);
- registry.registerNativeAllocation(anObject, 0xABCDABCD);
-
- {
- Object object = new Object();
- aLongStrongPathToSamplePathObject = new Reference(new Reference(new Reference(object)));
- aShortWeakPathToSamplePathObject = new WeakReference(new Reference(object));
- }
-
- addedObject = baseline ? null : new AddedObject();
- removedObject = baseline ? new RemovedObject() : null;
- modifiedObject = new ModifiedObject();
- modifiedObject.value = baseline ? 5 : 8;
- modifiedObject.modifiedRefField = baseline ? "A1" : "A2";
- modifiedObject.unmodifiedRefField = "B";
- modifiedStaticField = baseline ? "C1" : "C2";
- modifiedArray = baseline ? new int[]{0, 1, 2, 3} : new int[]{3, 1, 2, 0};
-
- allocateObjectAtKnownSite1();
-
- // Deep matching dominator trees shouldn't smash the stack when we try
- // to diff them. Make some deep dominator trees to help test it.
- for (int i = 0; i < 10000; i++) {
- StackSmasher smasher = new StackSmasher();
- smasher.child = stackSmasher;
- stackSmasher = smasher;
-
- if (!baseline) {
- smasher = new StackSmasher();
- smasher.child = stackSmasherAdded;
- stackSmasherAdded = smasher;
- }
- }
-
- gcPathArray[2].right.left = gcPathArray[2].left.right;
- }
- }
-
public static void main(String[] args) throws IOException {
if (args.length < 1) {
System.err.println("no output file specified");
diff --git a/tools/ahat/src/test-dump/SuperDumpedStuff.java b/tools/ahat/src/test-dump/SuperDumpedStuff.java
new file mode 100644
index 0000000..5ec62ae
--- /dev/null
+++ b/tools/ahat/src/test-dump/SuperDumpedStuff.java
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+// A super class for DumpedStuff to test deobfuscation of methods inherited
+// from the super class.
+public class SuperDumpedStuff {
+
+ public void allocateObjectAtObfSuperSite() {
+ objectAllocatedAtObfSuperSite = new Object();
+ }
+
+ public void allocateObjectAtUnObfSuperSite() {
+ objectAllocatedAtUnObfSuperSite = new Object();
+ }
+
+ public void allocateObjectAtOverriddenSite() {
+ objectAllocatedAtOverriddenSite = new Object();
+ }
+
+ public Object objectAllocatedAtObfSuperSite;
+ public Object objectAllocatedAtUnObfSuperSite;
+ public Object objectAllocatedAtOverriddenSite;
+}
diff --git a/tools/ahat/src/test/com/android/ahat/ProguardMapTest.java b/tools/ahat/src/test/com/android/ahat/ProguardMapTest.java
index ad40f45..02976b5 100644
--- a/tools/ahat/src/test/com/android/ahat/ProguardMapTest.java
+++ b/tools/ahat/src/test/com/android/ahat/ProguardMapTest.java
@@ -45,7 +45,6 @@
+ " 64:66:class.with.only.Fields methodWithObfRes() -> n\n"
+ " 80:80:void lineObfuscatedMethod():8:8 -> o\n"
+ " 90:90:void lineObfuscatedMethod2():9 -> p\n"
- + " 120:121:void method.from.a.Superclass.supermethod() -> q\n"
;
@Test
@@ -160,12 +159,10 @@
assertEquals("Methods.java", frame.filename);
assertEquals(13, frame.line);
- frame = map.getFrame("class.with.Methods", "q", "()V", "SourceFile.java", 120);
- // TODO: Should this be "supermethod", instead of
- // "method.from.a.Superclass.supermethod"?
- assertEquals("method.from.a.Superclass.supermethod", frame.method);
- assertEquals("()V", frame.signature);
- assertEquals("Superclass.java", frame.filename);
- assertEquals(120, frame.line);
+ // Some methods may not have been obfuscated. We should still be able
+ // to compute the filename properly.
+ frame = map.getFrame("class.with.Methods", "unObfuscatedMethodName",
+ "()V", "SourceFile.java", 0);
+ assertEquals("Methods.java", frame.filename);
}
}
diff --git a/tools/ahat/src/test/com/android/ahat/SiteTest.java b/tools/ahat/src/test/com/android/ahat/SiteTest.java
index dc0fe08..0443d7f 100644
--- a/tools/ahat/src/test/com/android/ahat/SiteTest.java
+++ b/tools/ahat/src/test/com/android/ahat/SiteTest.java
@@ -23,6 +23,7 @@
import org.junit.Test;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertSame;
public class SiteTest {
@@ -31,36 +32,54 @@
TestDump dump = TestDump.getTestDump();
AhatSnapshot snapshot = dump.getAhatSnapshot();
- AhatInstance obj1 = dump.getDumpedAhatInstance("objectAllocatedAtKnownSite1");
- AhatInstance obj2 = dump.getDumpedAhatInstance("objectAllocatedAtKnownSite2");
- Site s2 = obj2.getSite();
- Site s1b = s2.getParent();
- Site s1a = obj1.getSite();
- Site s = s1a.getParent();
+ AhatInstance oKnownSite = dump.getDumpedAhatInstance("objectAllocatedAtKnownSite");
+ Site sKnownSite = oKnownSite.getSite();
+ assertEquals("DumpedStuff.java", sKnownSite.getFilename());
+ assertEquals("allocateObjectAtKnownSite", sKnownSite.getMethodName());
+ assertEquals(29, sKnownSite.getLineNumber());
+ assertSame(sKnownSite, snapshot.getSite(sKnownSite.getId()));
- // TODO: The following commented out assertion fails due to a problem with
- // proguard deobfuscation. That bug should be fixed.
- // assertEquals("Main.java", s.getFilename());
+ AhatInstance oKnownSubSite = dump.getDumpedAhatInstance("objectAllocatedAtKnownSubSite");
+ Site sKnownSubSite = oKnownSubSite.getSite();
+ assertEquals("DumpedStuff.java", sKnownSubSite.getFilename());
+ assertEquals("allocateObjectAtKnownSubSite", sKnownSubSite.getMethodName());
+ assertEquals(37, sKnownSubSite.getLineNumber());
+ assertSame(sKnownSubSite, snapshot.getSite(sKnownSubSite.getId()));
- assertEquals("Main.java", s1a.getFilename());
- assertEquals("Main.java", s1b.getFilename());
- assertEquals("Main.java", s2.getFilename());
+ Site sKnownSubSiteParent = sKnownSubSite.getParent();
+ assertEquals("DumpedStuff.java", sKnownSubSiteParent.getFilename());
+ assertEquals("allocateObjectAtKnownSite", sKnownSubSiteParent.getMethodName());
+ assertEquals(30, sKnownSubSiteParent.getLineNumber());
+ assertSame(sKnownSubSiteParent, snapshot.getSite(sKnownSubSiteParent.getId()));
- assertEquals("allocateObjectAtKnownSite1", s1a.getMethodName());
- assertEquals("allocateObjectAtKnownSite1", s1b.getMethodName());
- assertEquals("allocateObjectAtKnownSite2", s2.getMethodName());
+ assertNotSame(sKnownSite, sKnownSubSiteParent);
+ assertSame(sKnownSite.getParent(), sKnownSubSiteParent.getParent());
- // TODO: The following commented out assertion fails due to a problem with
- // stack frame line numbers - we don't get different line numbers
- // for the different sites, so they are indistiguishable. The
- // problem with line numbers should be understood and fixed.
- // assertNotSame(s1a, s1b);
+ Site sKnownSiteParent = sKnownSite.getParent();
+ assertEquals("DumpedStuff.java", sKnownSiteParent.getFilename());
+ assertEquals("<init>", sKnownSiteParent.getMethodName());
+ assertEquals(45, sKnownSiteParent.getLineNumber());
+ assertSame(sKnownSiteParent, snapshot.getSite(sKnownSiteParent.getId()));
- assertSame(s1a.getParent(), s1b.getParent());
+ AhatInstance oObfSuperSite = dump.getDumpedAhatInstance("objectAllocatedAtObfSuperSite");
+ Site sObfSuperSite = oObfSuperSite.getSite();
+ assertEquals("SuperDumpedStuff.java", sObfSuperSite.getFilename());
+ assertEquals("allocateObjectAtObfSuperSite", sObfSuperSite.getMethodName());
+ assertEquals(22, sObfSuperSite.getLineNumber());
+ assertSame(sObfSuperSite, snapshot.getSite(sObfSuperSite.getId()));
- assertSame(s, snapshot.getSite(s.getId()));
- assertSame(s1a, snapshot.getSite(s1a.getId()));
- assertSame(s1b, snapshot.getSite(s1b.getId()));
- assertSame(s2, snapshot.getSite(s2.getId()));
+ AhatInstance oUnObfSuperSite = dump.getDumpedAhatInstance("objectAllocatedAtUnObfSuperSite");
+ Site sUnObfSuperSite = oUnObfSuperSite.getSite();
+ assertEquals("SuperDumpedStuff.java", sUnObfSuperSite.getFilename());
+ assertEquals("allocateObjectAtUnObfSuperSite", sUnObfSuperSite.getMethodName());
+ assertEquals(26, sUnObfSuperSite.getLineNumber());
+ assertSame(sUnObfSuperSite, snapshot.getSite(sUnObfSuperSite.getId()));
+
+ AhatInstance oOverriddenSite = dump.getDumpedAhatInstance("objectAllocatedAtOverriddenSite");
+ Site sOverriddenSite = oOverriddenSite.getSite();
+ assertEquals("DumpedStuff.java", sOverriddenSite.getFilename());
+ assertEquals("allocateObjectAtOverriddenSite", sOverriddenSite.getMethodName());
+ assertEquals(41, sOverriddenSite.getLineNumber());
+ assertSame(sOverriddenSite, snapshot.getSite(sOverriddenSite.getId()));
}
}
diff --git a/tools/run-jdwp-tests.sh b/tools/run-jdwp-tests.sh
index db8c540..f5fbcd8 100755
--- a/tools/run-jdwp-tests.sh
+++ b/tools/run-jdwp-tests.sh
@@ -284,8 +284,10 @@
if [[ $using_jack == "true" ]]; then
toolchain_args="--toolchain jack --language JN --jack-arg -g"
-else
+elif [[ $mode != "ri" ]]; then
toolchain_args="--toolchain dx --language CUR"
+else
+ toolchain_args="--toolchain javac --language CUR"
fi
# Run the tests using vogar.