Merge "ART: Simplify MethodHandle invocations"
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/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/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/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/oat_writer.cc b/dex2oat/linker/oat_writer.cc
index d8671d2..1eec592 100644
--- a/dex2oat/linker/oat_writer.cc
+++ b/dex2oat/linker/oat_writer.cc
@@ -2126,20 +2126,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())) {
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..cd2e894 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,
@@ -893,11 +894,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 +976,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 +987,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 +1221,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 +1247,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 +1268,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 +1291,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 +1367,7 @@
vios->Stream() << StringPrintf("(offset=0x%08x)\n", vmap_table_offset);
size_t vmap_table_offset_limit =
- (kIsVdexEnabled && IsMethodGeneratedByDexToDexCompiler(oat_method, code_item))
+ (kIsVdexEnabled && 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 +1379,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 +1400,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 +1442,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 +1455,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 +1493,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 +1518,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 +1533,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 +1551,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 +1562,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 +1577,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 +1595,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 +1617,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 +1757,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 +1768,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 +1824,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 +1864,7 @@
helper.GetEncoding(),
method_info,
oat_method.GetCodeOffset(),
- code_item->registers_size_,
+ code_item_accessor.RegistersSize(),
instruction_set_);
do {
helper.Next();
@@ -2502,8 +2492,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.h b/runtime/art_method.h
index 0e98d47..c17eef1 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"
@@ -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/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/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/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index 378ce2c..b8a13da 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, "
diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc
index 65d01a4..7694f45 100644
--- a/runtime/oat_file_assistant_test.cc
+++ b/runtime/oat_file_assistant_test.cc
@@ -351,50 +351,6 @@
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) {
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/thread_list.cc b/runtime/thread_list.cc
index 7b0ef80..9f55314 100644
--- a/runtime/thread_list.cc
+++ b/runtime/thread_list.cc
@@ -307,6 +307,8 @@
// Unlike suspending all threads where we can wait to acquire the mutator_lock_, suspending an
// individual thread requires polling. delay_us is the requested sleep wait. If delay_us is 0 then
// we use sched_yield instead of calling usleep.
+// Although there is the possibility, here and elsewhere, that usleep could return -1 and
+// errno = EINTR, there should be no problem if interrupted, so we do not check.
static void ThreadSuspendSleep(useconds_t delay_us) {
if (delay_us == 0) {
sched_yield();
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/669-moveable-string-class-equals/run b/test/669-moveable-string-class-equals/run
index d0ab6f8..7c74d8c 100755
--- a/test/669-moveable-string-class-equals/run
+++ b/test/669-moveable-string-class-equals/run
@@ -16,4 +16,4 @@
# Run without image, so that String.class is moveable.
# Reduce heap size to force more frequent GCs.
-${RUN} --no-image --no-dex2oat --runtime-option -Xmx16m "$@"
+${RUN} --no-image --runtime-option -Xmx16m "$@"
diff --git a/test/669-moveable-string-class-equals/src/Main.java b/test/669-moveable-string-class-equals/src/Main.java
index 4badade..d182d51 100644
--- a/test/669-moveable-string-class-equals/src/Main.java
+++ b/test/669-moveable-string-class-equals/src/Main.java
@@ -43,6 +43,10 @@
array[i] = "V" + i;
}
+ // Continually check string equality between a newly allocated String and an
+ // already allocated String with the same contents while allocating over 128MiB
+ // memory (with heap size limited to 16MiB), ensuring we run GC and stress the
+ // instanceof check in the String.equals() implementation.
for (int count = 0; count != 128 * 1024; ++count) {
for (int i = 0; i != length; ++i) {
allocateAtLeast1KiB();
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/tools/buildbot-build.sh b/tools/buildbot-build.sh
index 53b5093..fd9ad0b 100755
--- a/tools/buildbot-build.sh
+++ b/tools/buildbot-build.sh
@@ -35,7 +35,7 @@
using_jack=$(get_build_var ANDROID_COMPILE_WITH_JACK)
java_libraries_dir=${out_dir}/target/common/obj/JAVA_LIBRARIES
-common_targets="vogar core-tests apache-harmony-jdwp-tests-hostdex jsr166-tests mockito-target libjdwp"
+common_targets="vogar core-tests apache-harmony-jdwp-tests-hostdex jsr166-tests mockito-target"
mode="target"
j_arg="-j$(nproc)"
showcommands=
@@ -70,16 +70,23 @@
extra_args=SOONG_ALLOW_MISSING_DEPENDENCIES=true
if [[ $mode == "host" ]]; then
- make_command="make $j_arg $extra_args $showcommands build-art-host-tests $common_targets dx-tests"
- make_command+=" ${out_dir}/host/linux-x86/lib/libjavacoretests.so "
- make_command+=" ${out_dir}/host/linux-x86/lib64/libjavacoretests.so"
- make_command+=" libwrapagentpropertiesd libwrapagentproperties"
+ make_command="make $j_arg $extra_args $showcommands build-art-host-tests $common_targets"
+ make_command+=" dx-tests"
+ mode_suffix="-host"
elif [[ $mode == "target" ]]; then
make_command="make $j_arg $extra_args $showcommands build-art-target-tests $common_targets"
- make_command+=" libjavacrypto libjavacoretests libnetd_client linker toybox toolbox sh"
+ make_command+=" libjavacrypto-target libnetd_client-target linker toybox toolbox sh"
make_command+=" ${out_dir}/host/linux-x86/bin/adb libstdc++ "
make_command+=" ${out_dir}/target/product/${TARGET_PRODUCT}/system/etc/public.libraries.txt"
+ mode_suffix="-target"
fi
+mode_specific_libraries="libjavacoretests libjdwp libwrapagentproperties libwrapagentpropertiesd"
+for LIB in ${mode_specific_libraries} ; do
+ make_command+=" $LIB${mode_suffix}"
+done
+
+
+
echo "Executing $make_command"
$make_command
diff --git a/tools/libjdwp_oj_art_failures.txt b/tools/libjdwp_oj_art_failures.txt
index e0f243c..787c4d2 100644
--- a/tools/libjdwp_oj_art_failures.txt
+++ b/tools/libjdwp_oj_art_failures.txt
@@ -61,5 +61,11 @@
"org.apache.harmony.jpda.tests.jdwp.ThreadGroupReference.NameTest#testName001_NullObject",
"org.apache.harmony.jpda.tests.jdwp.ThreadGroupReference.ParentTest#testParent_NullObject",
"org.apache.harmony.jpda.tests.jdwp.VirtualMachine.CapabilitiesNewTest#testCapabilitiesNew001" ]
+},
+{
+ description: "Test is flaky",
+ result: EXEC_FAILED,
+ bug: 69121056,
+ name: "org.apache.harmony.jpda.tests.jdwp.ObjectReference.IsCollectedTest#testIsCollected001"
}
]
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.