summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--adbconnection/adbconnection.cc9
-rw-r--r--compiler/Android.bp7
-rw-r--r--compiler/debug/elf_debug_info_writer.h4
-rw-r--r--compiler/debug/elf_debug_line_writer.h2
-rw-r--r--compiler/dex/dex_to_dex_compiler.cc6
-rw-r--r--compiler/driver/compiler_driver.cc4
-rw-r--r--compiler/optimizing/builder.cc3
-rw-r--r--compiler/optimizing/builder.h5
-rw-r--r--compiler/optimizing/codegen_test.cc87
-rw-r--r--compiler/optimizing/constant_folding_test.cc20
-rw-r--r--compiler/optimizing/dead_code_elimination_test.cc8
-rw-r--r--compiler/optimizing/dominator_test.cc34
-rw-r--r--compiler/optimizing/find_loops_test.cc28
-rw-r--r--compiler/optimizing/graph_checker_test.cc14
-rw-r--r--compiler/optimizing/inliner.cc2
-rw-r--r--compiler/optimizing/instruction_builder.cc2
-rw-r--r--compiler/optimizing/instruction_builder.h3
-rw-r--r--compiler/optimizing/linearize_test.cc19
-rw-r--r--compiler/optimizing/live_ranges_test.cc16
-rw-r--r--compiler/optimizing/liveness_test.cc28
-rw-r--r--compiler/optimizing/optimizing_cfi_test.cc4
-rw-r--r--compiler/optimizing/optimizing_compiler.cc6
-rw-r--r--compiler/optimizing/optimizing_unit_test.h60
-rw-r--r--compiler/optimizing/pretty_printer_test.cc28
-rw-r--r--compiler/optimizing/register_allocator_test.cc18
-rw-r--r--compiler/optimizing/scheduler_test.cc6
-rw-r--r--compiler/optimizing/ssa_test.cc30
-rw-r--r--compiler/optimizing/suspend_check_test.cc16
-rw-r--r--compiler/utils/test_dex_file_builder.h4
-rw-r--r--dex2oat/Android.bp12
-rw-r--r--dex2oat/dex2oat.cc10
-rw-r--r--dex2oat/dex2oat_image_test.cc14
-rw-r--r--dex2oat/dex2oat_test.cc40
-rw-r--r--dex2oat/linker/oat_writer.cc313
-rw-r--r--dex2oat/linker/oat_writer.h2
-rw-r--r--dex2oat/linker/oat_writer_test.cc6
-rw-r--r--dexdump/dexdump.cc7
-rw-r--r--dexlayout/Android.bp7
-rw-r--r--dexlayout/compact_dex_writer.cc238
-rw-r--r--dexlayout/compact_dex_writer.h17
-rw-r--r--dexlayout/dex_ir.cc11
-rw-r--r--dexlayout/dex_ir.h9
-rw-r--r--dexlayout/dex_writer.cc152
-rw-r--r--dexlayout/dex_writer.h27
-rw-r--r--dexlayout/dexlayout.cc22
-rw-r--r--dexlayout/dexlayout_test.cc27
-rw-r--r--dexlist/dexlist.cc6
-rw-r--r--oatdump/oatdump.cc1
-rw-r--r--openjdkjvmti/OpenjdkJvmTi.cc179
-rw-r--r--openjdkjvmti/art_jvmti.h68
-rw-r--r--openjdkjvmti/deopt_manager.cc31
-rw-r--r--openjdkjvmti/deopt_manager.h7
-rw-r--r--openjdkjvmti/fixed_up_dex_file.cc9
-rw-r--r--openjdkjvmti/ti_class.cc14
-rw-r--r--openjdkjvmti/ti_redefine.cc14
-rw-r--r--openjdkjvmti/ti_search.cc4
-rw-r--r--profman/profman.cc26
-rw-r--r--runtime/Android.bp68
-rw-r--r--runtime/art_method.cc8
-rw-r--r--runtime/art_method.h3
-rw-r--r--runtime/class_loader_context.cc14
-rw-r--r--runtime/common_runtime_test.cc15
-rw-r--r--runtime/dex/art_dex_file_loader.cc465
-rw-r--r--runtime/dex/art_dex_file_loader.h125
-rw-r--r--runtime/dex/code_item_accessors-inl.h12
-rw-r--r--runtime/dex/code_item_accessors-no_art-inl.h14
-rw-r--r--runtime/dex/code_item_accessors.h12
-rw-r--r--runtime/dex/code_item_accessors_test.cc15
-rw-r--r--runtime/dex/compact_dex_debug_info.cc117
-rw-r--r--runtime/dex/compact_dex_debug_info.h65
-rw-r--r--runtime/dex/compact_dex_debug_info_test.cc95
-rw-r--r--runtime/dex/compact_dex_file.cc17
-rw-r--r--runtime/dex/compact_dex_file.h52
-rw-r--r--runtime/dex/compact_dex_utils.h37
-rw-r--r--runtime/dex/dex_file.h46
-rw-r--r--runtime/dex/dex_file_loader.cc498
-rw-r--r--runtime/dex/dex_file_loader.h123
-rw-r--r--runtime/dex/dex_file_test.cc46
-rw-r--r--runtime/dex/dex_file_verifier_test.cc4
-rw-r--r--runtime/dex/standard_dex_file.h25
-rw-r--r--runtime/dex2oat_environment_test.h28
-rw-r--r--runtime/dex_to_dex_decompiler.cc12
-rw-r--r--runtime/gc/space/image_space.cc4
-rw-r--r--runtime/globals.h6
-rw-r--r--runtime/native/dalvik_system_DexFile.cc14
-rw-r--r--runtime/oat_file.cc33
-rw-r--r--runtime/oat_file.h4
-rw-r--r--runtime/oat_file_assistant.cc10
-rw-r--r--runtime/oat_file_manager.cc25
-rw-r--r--runtime/quicken_info.h96
-rw-r--r--runtime/runtime.cc28
-rw-r--r--runtime/runtime.h5
-rw-r--r--runtime/utils.cc5
-rw-r--r--runtime/vdex_file.cc170
-rw-r--r--runtime/vdex_file.h56
-rw-r--r--test/983-source-transform-verify/source_transform.cc18
-rwxr-xr-xtest/etc/run-test-jar5
97 files changed, 2743 insertions, 1398 deletions
diff --git a/adbconnection/adbconnection.cc b/adbconnection/adbconnection.cc
index a5c885a933..80cfc83d3c 100644
--- a/adbconnection/adbconnection.cc
+++ b/adbconnection/adbconnection.cc
@@ -63,9 +63,7 @@ static constexpr int kControlSockSendTimeout = 10;
static AdbConnectionState* gState;
static bool IsDebuggingPossible() {
- // TODO We need to do this on IsJdwpAllowed not IsDebuggable in order to support userdebug
- // workloads. For now we will only allow it when we are debuggable so that testing is easier.
- return art::Runtime::Current()->IsJavaDebuggable() && art::Dbg::IsJdwpAllowed();
+ return art::Dbg::IsJdwpAllowed();
}
// Begin running the debugger.
@@ -581,11 +579,14 @@ void AdbConnectionState::RunPollLoop(art::Thread* self) {
DCHECK(!agent_has_socket_);
if (!agent_loaded_) {
DCHECK(!agent_listening_);
+ // TODO Should we check in some other way if we are userdebug/eng?
+ CHECK(art::Dbg::IsJdwpAllowed());
// Load the agent now!
self->AssertNoPendingException();
art::Runtime::Current()->AttachAgent(/* JNIEnv* */ nullptr,
MakeAgentArg(),
- /* classloader */ nullptr);
+ /* classloader */ nullptr,
+ /*allow_non_debuggable_tooling*/ true);
if (self->IsExceptionPending()) {
LOG(ERROR) << "Failed to load agent " << agent_name_;
art::ScopedObjectAccess soa(self);
diff --git a/compiler/Android.bp b/compiler/Android.bp
index 164f9c1e8f..d4d72f380b 100644
--- a/compiler/Android.bp
+++ b/compiler/Android.bp
@@ -249,6 +249,13 @@ art_cc_library {
shared_libs: [
"libart",
],
+
+ pgo: {
+ instrumentation: true,
+ profile_file: "dex2oat.profdata",
+ benchmarks: ["dex2oat"],
+ enable_profile_use: false,
+ }
}
art_cc_library {
diff --git a/compiler/debug/elf_debug_info_writer.h b/compiler/debug/elf_debug_info_writer.h
index 713f8eb05d..893cad288b 100644
--- a/compiler/debug/elf_debug_info_writer.h
+++ b/compiler/debug/elf_debug_info_writer.h
@@ -49,7 +49,7 @@ static void LocalInfoCallback(void* ctx, const DexFile::LocalInfo& entry) {
static std::vector<const char*> GetParamNames(const MethodDebugInfo* mi) {
std::vector<const char*> names;
- CodeItemDebugInfoAccessor accessor(*mi->dex_file, mi->code_item);
+ CodeItemDebugInfoAccessor accessor(*mi->dex_file, mi->code_item, mi->dex_method_index);
if (accessor.HasCodeItem()) {
DCHECK(mi->dex_file != nullptr);
const uint8_t* stream = mi->dex_file->GetDebugInfoStream(accessor.DebugInfoOffset());
@@ -163,7 +163,7 @@ class ElfCompilationUnitWriter {
for (auto mi : compilation_unit.methods) {
DCHECK(mi->dex_file != nullptr);
const DexFile* dex = mi->dex_file;
- CodeItemDebugInfoAccessor accessor(*dex, mi->code_item);
+ CodeItemDebugInfoAccessor accessor(*dex, mi->code_item, mi->dex_method_index);
const DexFile::MethodId& dex_method = dex->GetMethodId(mi->dex_method_index);
const DexFile::ProtoId& dex_proto = dex->GetMethodPrototype(dex_method);
const DexFile::TypeList* dex_params = dex->GetProtoParameters(dex_proto);
diff --git a/compiler/debug/elf_debug_line_writer.h b/compiler/debug/elf_debug_line_writer.h
index 4e37f4e4ba..44504c1efb 100644
--- a/compiler/debug/elf_debug_line_writer.h
+++ b/compiler/debug/elf_debug_line_writer.h
@@ -159,7 +159,7 @@ class ElfDebugLineWriter {
PositionInfos dex2line_map;
DCHECK(mi->dex_file != nullptr);
const DexFile* dex = mi->dex_file;
- CodeItemDebugInfoAccessor accessor(*dex, mi->code_item);
+ CodeItemDebugInfoAccessor accessor(*dex, mi->code_item, mi->dex_method_index);
const uint32_t debug_info_offset = accessor.DebugInfoOffset();
if (!dex->DecodeDebugPositionInfo(debug_info_offset, PositionInfoCallback, &dex2line_map)) {
continue;
diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc
index 52cb217980..308e75d9c1 100644
--- a/compiler/dex/dex_to_dex_compiler.cc
+++ b/compiler/dex/dex_to_dex_compiler.cc
@@ -373,15 +373,15 @@ CompiledMethod* ArtCompileDEX(
CHECK_EQ(quicken_count, dex_compiler.GetQuickenedInfo().size());
}
std::vector<uint8_t> quicken_data;
+ QuickenInfoTable::Builder builder(&quicken_data, dex_compiler.GetQuickenedInfo().size());
+ // Length is encoded by the constructor.
for (QuickenedInfo info : dex_compiler.GetQuickenedInfo()) {
// Dex pc is not serialized, only used for checking the instructions. Since we access the
// array based on the index of the quickened instruction, the indexes must line up perfectly.
// The reader side uses the NeedsIndexForInstruction function too.
const Instruction& inst = unit.GetCodeItemAccessor().InstructionAt(info.dex_pc);
CHECK(QuickenInfoTable::NeedsIndexForInstruction(&inst)) << inst.Opcode();
- // Add the index.
- quicken_data.push_back(static_cast<uint8_t>(info.dex_member_index >> 0));
- quicken_data.push_back(static_cast<uint8_t>(info.dex_member_index >> 8));
+ builder.AddIndex(info.dex_member_index);
}
InstructionSet instruction_set = driver->GetInstructionSet();
if (instruction_set == InstructionSet::kThumb2) {
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index c0886d0185..869865956c 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -424,10 +424,6 @@ static optimizer::DexToDexCompilationLevel GetDexToDexCompilationLevel(
// optimizations that could break that.
max_level = optimizer::DexToDexCompilationLevel::kDontDexToDexCompile;
}
- if (!VdexFile::CanEncodeQuickenedData(dex_file)) {
- // Don't do any dex level optimizations if we cannot encode the quickening.
- return optimizer::DexToDexCompilationLevel::kDontDexToDexCompile;
- }
if (klass->IsVerified()) {
// Class is verified so we can enable DEX-to-DEX compilation for performance.
return max_level;
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index af537dd653..a1a5692ef6 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -43,7 +43,7 @@ HGraphBuilder::HGraphBuilder(HGraph* graph,
CompilerDriver* driver,
CodeGenerator* code_generator,
OptimizingCompilerStats* compiler_stats,
- const uint8_t* interpreter_metadata,
+ ArrayRef<const uint8_t> interpreter_metadata,
VariableSizedHandleScope* handles)
: graph_(graph),
dex_file_(&graph->GetDexFile()),
@@ -70,7 +70,6 @@ HGraphBuilder::HGraphBuilder(HGraph* graph,
compiler_driver_(nullptr),
code_generator_(nullptr),
compilation_stats_(nullptr),
- interpreter_metadata_(nullptr),
handles_(handles),
return_type_(return_type) {}
diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h
index c16a3a928d..5a1914ce08 100644
--- a/compiler/optimizing/builder.h
+++ b/compiler/optimizing/builder.h
@@ -18,6 +18,7 @@
#define ART_COMPILER_OPTIMIZING_BUILDER_H_
#include "base/arena_object.h"
+#include "base/array_ref.h"
#include "dex/code_item_accessors.h"
#include "dex/dex_file-inl.h"
#include "dex/dex_file.h"
@@ -40,7 +41,7 @@ class HGraphBuilder : public ValueObject {
CompilerDriver* driver,
CodeGenerator* code_generator,
OptimizingCompilerStats* compiler_stats,
- const uint8_t* interpreter_metadata,
+ ArrayRef<const uint8_t> interpreter_metadata,
VariableSizedHandleScope* handles);
// Only for unit testing.
@@ -73,7 +74,7 @@ class HGraphBuilder : public ValueObject {
CodeGenerator* const code_generator_;
OptimizingCompilerStats* const compilation_stats_;
- const uint8_t* const interpreter_metadata_;
+ const ArrayRef<const uint8_t> interpreter_metadata_;
VariableSizedHandleScope* const handles_;
const DataType::Type return_type_;
diff --git a/compiler/optimizing/codegen_test.cc b/compiler/optimizing/codegen_test.cc
index 6eda289861..ba4040acad 100644
--- a/compiler/optimizing/codegen_test.cc
+++ b/compiler/optimizing/codegen_test.cc
@@ -74,8 +74,8 @@ static ::std::vector<CodegenTargetConfig> GetTargetConfigs() {
class CodegenTest : public OptimizingUnitTest {
protected:
- void TestCode(const uint16_t* data, bool has_result = false, int32_t expected = 0);
- void TestCodeLong(const uint16_t* data, bool has_result, int64_t expected);
+ void TestCode(const std::vector<uint16_t>& data, bool has_result = false, int32_t expected = 0);
+ void TestCodeLong(const std::vector<uint16_t>& data, bool has_result, int64_t expected);
void TestComparison(IfCondition condition,
int64_t i,
int64_t j,
@@ -83,7 +83,7 @@ class CodegenTest : public OptimizingUnitTest {
const CodegenTargetConfig target_config);
};
-void CodegenTest::TestCode(const uint16_t* data, bool has_result, int32_t expected) {
+void CodegenTest::TestCode(const std::vector<uint16_t>& data, bool has_result, int32_t expected) {
for (const CodegenTargetConfig& target_config : GetTargetConfigs()) {
ResetPoolAndAllocator();
HGraph* graph = CreateCFG(data);
@@ -93,7 +93,8 @@ void CodegenTest::TestCode(const uint16_t* data, bool has_result, int32_t expect
}
}
-void CodegenTest::TestCodeLong(const uint16_t* data, bool has_result, int64_t expected) {
+void CodegenTest::TestCodeLong(const std::vector<uint16_t>& data,
+ bool has_result, int64_t expected) {
for (const CodegenTargetConfig& target_config : GetTargetConfigs()) {
ResetPoolAndAllocator();
HGraph* graph = CreateCFG(data, DataType::Type::kInt64);
@@ -104,12 +105,12 @@ void CodegenTest::TestCodeLong(const uint16_t* data, bool has_result, int64_t ex
}
TEST_F(CodegenTest, ReturnVoid) {
- const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(Instruction::RETURN_VOID);
+ const std::vector<uint16_t> data = ZERO_REGISTER_CODE_ITEM(Instruction::RETURN_VOID);
TestCode(data);
}
TEST_F(CodegenTest, CFG1) {
- const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ZERO_REGISTER_CODE_ITEM(
Instruction::GOTO | 0x100,
Instruction::RETURN_VOID);
@@ -117,7 +118,7 @@ TEST_F(CodegenTest, CFG1) {
}
TEST_F(CodegenTest, CFG2) {
- const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ZERO_REGISTER_CODE_ITEM(
Instruction::GOTO | 0x100,
Instruction::GOTO | 0x100,
Instruction::RETURN_VOID);
@@ -126,21 +127,21 @@ TEST_F(CodegenTest, CFG2) {
}
TEST_F(CodegenTest, CFG3) {
- const uint16_t data1[] = ZERO_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data1 = ZERO_REGISTER_CODE_ITEM(
Instruction::GOTO | 0x200,
Instruction::RETURN_VOID,
Instruction::GOTO | 0xFF00);
TestCode(data1);
- const uint16_t data2[] = ZERO_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data2 = ZERO_REGISTER_CODE_ITEM(
Instruction::GOTO_16, 3,
Instruction::RETURN_VOID,
Instruction::GOTO_16, 0xFFFF);
TestCode(data2);
- const uint16_t data3[] = ZERO_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data3 = ZERO_REGISTER_CODE_ITEM(
Instruction::GOTO_32, 4, 0,
Instruction::RETURN_VOID,
Instruction::GOTO_32, 0xFFFF, 0xFFFF);
@@ -149,7 +150,7 @@ TEST_F(CodegenTest, CFG3) {
}
TEST_F(CodegenTest, CFG4) {
- const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ZERO_REGISTER_CODE_ITEM(
Instruction::RETURN_VOID,
Instruction::GOTO | 0x100,
Instruction::GOTO | 0xFE00);
@@ -158,7 +159,7 @@ TEST_F(CodegenTest, CFG4) {
}
TEST_F(CodegenTest, CFG5) {
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 3,
Instruction::GOTO | 0x100,
@@ -168,7 +169,7 @@ TEST_F(CodegenTest, CFG5) {
}
TEST_F(CodegenTest, IntConstant) {
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::RETURN_VOID);
@@ -176,7 +177,7 @@ TEST_F(CodegenTest, IntConstant) {
}
TEST_F(CodegenTest, Return1) {
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::RETURN | 0);
@@ -184,7 +185,7 @@ TEST_F(CodegenTest, Return1) {
}
TEST_F(CodegenTest, Return2) {
- const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+ const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::CONST_4 | 0 | 1 << 8,
Instruction::RETURN | 1 << 8);
@@ -193,7 +194,7 @@ TEST_F(CodegenTest, Return2) {
}
TEST_F(CodegenTest, Return3) {
- const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+ const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::CONST_4 | 1 << 8 | 1 << 12,
Instruction::RETURN | 1 << 8);
@@ -202,7 +203,7 @@ TEST_F(CodegenTest, Return3) {
}
TEST_F(CodegenTest, ReturnIf1) {
- const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+ const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::CONST_4 | 1 << 8 | 1 << 12,
Instruction::IF_EQ, 3,
@@ -213,7 +214,7 @@ TEST_F(CodegenTest, ReturnIf1) {
}
TEST_F(CodegenTest, ReturnIf2) {
- const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+ const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::CONST_4 | 1 << 8 | 1 << 12,
Instruction::IF_EQ | 0 << 4 | 1 << 8, 3,
@@ -224,17 +225,17 @@ TEST_F(CodegenTest, ReturnIf2) {
}
// Exercise bit-wise (one's complement) not-int instruction.
-#define NOT_INT_TEST(TEST_NAME, INPUT, EXPECTED_OUTPUT) \
-TEST_F(CodegenTest, TEST_NAME) { \
- const int32_t input = INPUT; \
- const uint16_t input_lo = Low16Bits(input); \
- const uint16_t input_hi = High16Bits(input); \
- const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( \
- Instruction::CONST | 0 << 8, input_lo, input_hi, \
- Instruction::NOT_INT | 1 << 8 | 0 << 12 , \
- Instruction::RETURN | 1 << 8); \
- \
- TestCode(data, true, EXPECTED_OUTPUT); \
+#define NOT_INT_TEST(TEST_NAME, INPUT, EXPECTED_OUTPUT) \
+TEST_F(CodegenTest, TEST_NAME) { \
+ const int32_t input = INPUT; \
+ const uint16_t input_lo = Low16Bits(input); \
+ const uint16_t input_hi = High16Bits(input); \
+ const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM( \
+ Instruction::CONST | 0 << 8, input_lo, input_hi, \
+ Instruction::NOT_INT | 1 << 8 | 0 << 12 , \
+ Instruction::RETURN | 1 << 8); \
+ \
+ TestCode(data, true, EXPECTED_OUTPUT); \
}
NOT_INT_TEST(ReturnNotIntMinus2, -2, 1)
@@ -256,7 +257,7 @@ TEST_F(CodegenTest, TEST_NAME) { \
const uint16_t word1 = High16Bits(Low32Bits(input)); \
const uint16_t word2 = Low16Bits(High32Bits(input)); \
const uint16_t word3 = High16Bits(High32Bits(input)); /* MSW. */ \
- const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM( \
+ const std::vector<uint16_t> data = FOUR_REGISTERS_CODE_ITEM( \
Instruction::CONST_WIDE | 0 << 8, word0, word1, word2, word3, \
Instruction::NOT_LONG | 2 << 8 | 0 << 12, \
Instruction::RETURN_WIDE | 2 << 8); \
@@ -306,7 +307,7 @@ TEST_F(CodegenTest, IntToLongOfLongToInt) {
const uint16_t word1 = High16Bits(Low32Bits(input));
const uint16_t word2 = Low16Bits(High32Bits(input));
const uint16_t word3 = High16Bits(High32Bits(input)); // MSW.
- const uint16_t data[] = FIVE_REGISTERS_CODE_ITEM(
+ const std::vector<uint16_t> data = FIVE_REGISTERS_CODE_ITEM(
Instruction::CONST_WIDE | 0 << 8, word0, word1, word2, word3,
Instruction::CONST_WIDE | 2 << 8, 1, 0, 0, 0,
Instruction::ADD_LONG | 0, 0 << 8 | 2, // v0 <- 2^32 + 1
@@ -318,7 +319,7 @@ TEST_F(CodegenTest, IntToLongOfLongToInt) {
}
TEST_F(CodegenTest, ReturnAdd1) {
- const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+ const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Instruction::CONST_4 | 3 << 12 | 0,
Instruction::CONST_4 | 4 << 12 | 1 << 8,
Instruction::ADD_INT, 1 << 8 | 0,
@@ -328,7 +329,7 @@ TEST_F(CodegenTest, ReturnAdd1) {
}
TEST_F(CodegenTest, ReturnAdd2) {
- const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+ const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Instruction::CONST_4 | 3 << 12 | 0,
Instruction::CONST_4 | 4 << 12 | 1 << 8,
Instruction::ADD_INT_2ADDR | 1 << 12,
@@ -338,7 +339,7 @@ TEST_F(CodegenTest, ReturnAdd2) {
}
TEST_F(CodegenTest, ReturnAdd3) {
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 4 << 12 | 0 << 8,
Instruction::ADD_INT_LIT8, 3 << 8 | 0,
Instruction::RETURN);
@@ -347,7 +348,7 @@ TEST_F(CodegenTest, ReturnAdd3) {
}
TEST_F(CodegenTest, ReturnAdd4) {
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 4 << 12 | 0 << 8,
Instruction::ADD_INT_LIT16, 3,
Instruction::RETURN);
@@ -356,7 +357,7 @@ TEST_F(CodegenTest, ReturnAdd4) {
}
TEST_F(CodegenTest, ReturnMulInt) {
- const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+ const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Instruction::CONST_4 | 3 << 12 | 0,
Instruction::CONST_4 | 4 << 12 | 1 << 8,
Instruction::MUL_INT, 1 << 8 | 0,
@@ -366,7 +367,7 @@ TEST_F(CodegenTest, ReturnMulInt) {
}
TEST_F(CodegenTest, ReturnMulInt2addr) {
- const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+ const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Instruction::CONST_4 | 3 << 12 | 0,
Instruction::CONST_4 | 4 << 12 | 1 << 8,
Instruction::MUL_INT_2ADDR | 1 << 12,
@@ -376,7 +377,7 @@ TEST_F(CodegenTest, ReturnMulInt2addr) {
}
TEST_F(CodegenTest, ReturnMulLong) {
- const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM(
+ const std::vector<uint16_t> data = FOUR_REGISTERS_CODE_ITEM(
Instruction::CONST_WIDE | 0 << 8, 3, 0, 0, 0,
Instruction::CONST_WIDE | 2 << 8, 4, 0, 0, 0,
Instruction::MUL_LONG, 2 << 8 | 0,
@@ -386,7 +387,7 @@ TEST_F(CodegenTest, ReturnMulLong) {
}
TEST_F(CodegenTest, ReturnMulLong2addr) {
- const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM(
+ const std::vector<uint16_t> data = FOUR_REGISTERS_CODE_ITEM(
Instruction::CONST_WIDE | 0 << 8, 3, 0, 0, 0,
Instruction::CONST_WIDE | 2 << 8, 4, 0, 0, 0,
Instruction::MUL_LONG_2ADDR | 2 << 12,
@@ -396,7 +397,7 @@ TEST_F(CodegenTest, ReturnMulLong2addr) {
}
TEST_F(CodegenTest, ReturnMulIntLit8) {
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 4 << 12 | 0 << 8,
Instruction::MUL_INT_LIT8, 3 << 8 | 0,
Instruction::RETURN);
@@ -405,7 +406,7 @@ TEST_F(CodegenTest, ReturnMulIntLit8) {
}
TEST_F(CodegenTest, ReturnMulIntLit16) {
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 4 << 12 | 0 << 8,
Instruction::MUL_INT_LIT16, 3,
Instruction::RETURN);
@@ -578,7 +579,7 @@ TEST_F(CodegenTest, MaterializedCondition2) {
}
TEST_F(CodegenTest, ReturnDivIntLit8) {
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 4 << 12 | 0 << 8,
Instruction::DIV_INT_LIT8, 3 << 8 | 0,
Instruction::RETURN);
@@ -587,7 +588,7 @@ TEST_F(CodegenTest, ReturnDivIntLit8) {
}
TEST_F(CodegenTest, ReturnDivInt2Addr) {
- const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+ const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Instruction::CONST_4 | 4 << 12 | 0,
Instruction::CONST_4 | 2 << 12 | 1 << 8,
Instruction::DIV_INT_2ADDR | 1 << 12,
diff --git a/compiler/optimizing/constant_folding_test.cc b/compiler/optimizing/constant_folding_test.cc
index e1980e080e..d27104752b 100644
--- a/compiler/optimizing/constant_folding_test.cc
+++ b/compiler/optimizing/constant_folding_test.cc
@@ -36,7 +36,7 @@ class ConstantFoldingTest : public OptimizingUnitTest {
public:
ConstantFoldingTest() : graph_(nullptr) { }
- void TestCode(const uint16_t* data,
+ void TestCode(const std::vector<uint16_t>& data,
const std::string& expected_before,
const std::string& expected_after_cf,
const std::string& expected_after_dce,
@@ -100,7 +100,7 @@ class ConstantFoldingTest : public OptimizingUnitTest {
* return v1 2. return v1
*/
TEST_F(ConstantFoldingTest, IntConstantFoldingNegation) {
- const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+ const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Instruction::CONST_4 | 0 << 8 | 1 << 12,
Instruction::NEG_INT | 1 << 8 | 0 << 12,
Instruction::RETURN | 1 << 8);
@@ -161,7 +161,7 @@ TEST_F(ConstantFoldingTest, LongConstantFoldingNegation) {
const uint16_t word1 = High16Bits(Low32Bits(input));
const uint16_t word2 = Low16Bits(High32Bits(input));
const uint16_t word3 = High16Bits(High32Bits(input)); // MSW.
- const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM(
+ const std::vector<uint16_t> data = FOUR_REGISTERS_CODE_ITEM(
Instruction::CONST_WIDE | 0 << 8, word0, word1, word2, word3,
Instruction::NEG_LONG | 2 << 8 | 0 << 12,
Instruction::RETURN_WIDE | 2 << 8);
@@ -219,7 +219,7 @@ TEST_F(ConstantFoldingTest, LongConstantFoldingNegation) {
* return v2 4. return v2
*/
TEST_F(ConstantFoldingTest, IntConstantFoldingOnAddition1) {
- const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
+ const std::vector<uint16_t> data = THREE_REGISTERS_CODE_ITEM(
Instruction::CONST_4 | 0 << 8 | 1 << 12,
Instruction::CONST_4 | 1 << 8 | 2 << 12,
Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
@@ -284,7 +284,7 @@ TEST_F(ConstantFoldingTest, IntConstantFoldingOnAddition1) {
* return v2 8. return v2
*/
TEST_F(ConstantFoldingTest, IntConstantFoldingOnAddition2) {
- const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
+ const std::vector<uint16_t> data = THREE_REGISTERS_CODE_ITEM(
Instruction::CONST_4 | 0 << 8 | 1 << 12,
Instruction::CONST_4 | 1 << 8 | 2 << 12,
Instruction::ADD_INT_2ADDR | 0 << 8 | 1 << 12,
@@ -369,7 +369,7 @@ TEST_F(ConstantFoldingTest, IntConstantFoldingOnAddition2) {
* return v2 4. return v2
*/
TEST_F(ConstantFoldingTest, IntConstantFoldingOnSubtraction) {
- const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
+ const std::vector<uint16_t> data = THREE_REGISTERS_CODE_ITEM(
Instruction::CONST_4 | 0 << 8 | 3 << 12,
Instruction::CONST_4 | 1 << 8 | 2 << 12,
Instruction::SUB_INT | 2 << 8, 0 | 1 << 8,
@@ -432,7 +432,7 @@ TEST_F(ConstantFoldingTest, IntConstantFoldingOnSubtraction) {
* return (v4, v5) 6. return-wide v4
*/
TEST_F(ConstantFoldingTest, LongConstantFoldingOnAddition) {
- const uint16_t data[] = SIX_REGISTERS_CODE_ITEM(
+ const std::vector<uint16_t> data = SIX_REGISTERS_CODE_ITEM(
Instruction::CONST_WIDE_16 | 0 << 8, 1,
Instruction::CONST_WIDE_16 | 2 << 8, 2,
Instruction::ADD_LONG | 4 << 8, 0 | 2 << 8,
@@ -496,7 +496,7 @@ TEST_F(ConstantFoldingTest, LongConstantFoldingOnAddition) {
* return (v4, v5) 6. return-wide v4
*/
TEST_F(ConstantFoldingTest, LongConstantFoldingOnSubtraction) {
- const uint16_t data[] = SIX_REGISTERS_CODE_ITEM(
+ const std::vector<uint16_t> data = SIX_REGISTERS_CODE_ITEM(
Instruction::CONST_WIDE_16 | 0 << 8, 3,
Instruction::CONST_WIDE_16 | 2 << 8, 2,
Instruction::SUB_LONG | 4 << 8, 0 | 2 << 8,
@@ -569,7 +569,7 @@ TEST_F(ConstantFoldingTest, LongConstantFoldingOnSubtraction) {
* return v2 13. return v2
*/
TEST_F(ConstantFoldingTest, IntConstantFoldingAndJumps) {
- const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
+ const std::vector<uint16_t> data = THREE_REGISTERS_CODE_ITEM(
Instruction::CONST_4 | 0 << 8 | 1 << 12,
Instruction::CONST_4 | 1 << 8 | 2 << 12,
Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
@@ -672,7 +672,7 @@ TEST_F(ConstantFoldingTest, IntConstantFoldingAndJumps) {
* return-void 7. return
*/
TEST_F(ConstantFoldingTest, ConstantCondition) {
- const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
+ const std::vector<uint16_t> data = THREE_REGISTERS_CODE_ITEM(
Instruction::CONST_4 | 1 << 8 | 1 << 12,
Instruction::CONST_4 | 0 << 8 | 0 << 12,
Instruction::IF_GEZ | 1 << 8, 3,
diff --git a/compiler/optimizing/dead_code_elimination_test.cc b/compiler/optimizing/dead_code_elimination_test.cc
index 929572ee3b..adb6ce1187 100644
--- a/compiler/optimizing/dead_code_elimination_test.cc
+++ b/compiler/optimizing/dead_code_elimination_test.cc
@@ -29,12 +29,12 @@ namespace art {
class DeadCodeEliminationTest : public OptimizingUnitTest {
protected:
- void TestCode(const uint16_t* data,
+ void TestCode(const std::vector<uint16_t>& data,
const std::string& expected_before,
const std::string& expected_after);
};
-void DeadCodeEliminationTest::TestCode(const uint16_t* data,
+void DeadCodeEliminationTest::TestCode(const std::vector<uint16_t>& data,
const std::string& expected_before,
const std::string& expected_after) {
HGraph* graph = CreateCFG(data);
@@ -73,7 +73,7 @@ void DeadCodeEliminationTest::TestCode(const uint16_t* data,
* return-void 7. return
*/
TEST_F(DeadCodeEliminationTest, AdditionAndConditionalJump) {
- const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
+ const std::vector<uint16_t> data = THREE_REGISTERS_CODE_ITEM(
Instruction::CONST_4 | 1 << 8 | 1 << 12,
Instruction::CONST_4 | 0 << 8 | 0 << 12,
Instruction::IF_GEZ | 1 << 8, 3,
@@ -135,7 +135,7 @@ TEST_F(DeadCodeEliminationTest, AdditionAndConditionalJump) {
* return 13. return-void
*/
TEST_F(DeadCodeEliminationTest, AdditionsAndInconditionalJumps) {
- const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
+ const std::vector<uint16_t> data = THREE_REGISTERS_CODE_ITEM(
Instruction::CONST_4 | 0 << 8 | 0 << 12,
Instruction::CONST_4 | 1 << 8 | 1 << 12,
Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
diff --git a/compiler/optimizing/dominator_test.cc b/compiler/optimizing/dominator_test.cc
index 572466eec8..1d72ba116e 100644
--- a/compiler/optimizing/dominator_test.cc
+++ b/compiler/optimizing/dominator_test.cc
@@ -26,10 +26,12 @@ namespace art {
class OptimizerTest : public OptimizingUnitTest {
protected:
- void TestCode(const uint16_t* data, const uint32_t* blocks, size_t blocks_length);
+ void TestCode(const std::vector<uint16_t>& data, const uint32_t* blocks, size_t blocks_length);
};
-void OptimizerTest::TestCode(const uint16_t* data, const uint32_t* blocks, size_t blocks_length) {
+void OptimizerTest::TestCode(const std::vector<uint16_t>& data,
+ const uint32_t* blocks,
+ size_t blocks_length) {
HGraph* graph = CreateCFG(data);
ASSERT_EQ(graph->GetBlocks().size(), blocks_length);
for (size_t i = 0, e = blocks_length; i < e; ++i) {
@@ -49,7 +51,7 @@ void OptimizerTest::TestCode(const uint16_t* data, const uint32_t* blocks, size_
}
TEST_F(OptimizerTest, ReturnVoid) {
- const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ZERO_REGISTER_CODE_ITEM(
Instruction::RETURN_VOID); // Block number 1
const uint32_t dominators[] = {
@@ -62,7 +64,7 @@ TEST_F(OptimizerTest, ReturnVoid) {
}
TEST_F(OptimizerTest, CFG1) {
- const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ZERO_REGISTER_CODE_ITEM(
Instruction::GOTO | 0x100, // Block number 1
Instruction::RETURN_VOID); // Block number 2
@@ -77,7 +79,7 @@ TEST_F(OptimizerTest, CFG1) {
}
TEST_F(OptimizerTest, CFG2) {
- const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ZERO_REGISTER_CODE_ITEM(
Instruction::GOTO | 0x100, // Block number 1
Instruction::GOTO | 0x100, // Block number 2
Instruction::RETURN_VOID); // Block number 3
@@ -94,7 +96,7 @@ TEST_F(OptimizerTest, CFG2) {
}
TEST_F(OptimizerTest, CFG3) {
- const uint16_t data1[] = ZERO_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data1 = ZERO_REGISTER_CODE_ITEM(
Instruction::GOTO | 0x200, // Block number 1
Instruction::RETURN_VOID, // Block number 2
Instruction::GOTO | 0xFF00); // Block number 3
@@ -109,14 +111,14 @@ TEST_F(OptimizerTest, CFG3) {
TestCode(data1, dominators, sizeof(dominators) / sizeof(int));
- const uint16_t data2[] = ZERO_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data2 = ZERO_REGISTER_CODE_ITEM(
Instruction::GOTO_16, 3,
Instruction::RETURN_VOID,
Instruction::GOTO_16, 0xFFFF);
TestCode(data2, dominators, sizeof(dominators) / sizeof(int));
- const uint16_t data3[] = ZERO_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data3 = ZERO_REGISTER_CODE_ITEM(
Instruction::GOTO_32, 4, 0,
Instruction::RETURN_VOID,
Instruction::GOTO_32, 0xFFFF, 0xFFFF);
@@ -125,7 +127,7 @@ TEST_F(OptimizerTest, CFG3) {
}
TEST_F(OptimizerTest, CFG4) {
- const uint16_t data1[] = ZERO_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data1 = ZERO_REGISTER_CODE_ITEM(
Instruction::NOP,
Instruction::GOTO | 0xFF00);
@@ -138,14 +140,14 @@ TEST_F(OptimizerTest, CFG4) {
TestCode(data1, dominators, sizeof(dominators) / sizeof(int));
- const uint16_t data2[] = ZERO_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data2 = ZERO_REGISTER_CODE_ITEM(
Instruction::GOTO_32, 0, 0);
TestCode(data2, dominators, sizeof(dominators) / sizeof(int));
}
TEST_F(OptimizerTest, CFG5) {
- const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ZERO_REGISTER_CODE_ITEM(
Instruction::RETURN_VOID, // Block number 1
Instruction::GOTO | 0x100, // Dead block
Instruction::GOTO | 0xFE00); // Block number 2
@@ -162,7 +164,7 @@ TEST_F(OptimizerTest, CFG5) {
}
TEST_F(OptimizerTest, CFG6) {
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 3,
Instruction::GOTO | 0x100,
@@ -181,7 +183,7 @@ TEST_F(OptimizerTest, CFG6) {
}
TEST_F(OptimizerTest, CFG7) {
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 3, // Block number 1
Instruction::GOTO | 0x100, // Block number 2
@@ -201,7 +203,7 @@ TEST_F(OptimizerTest, CFG7) {
}
TEST_F(OptimizerTest, CFG8) {
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 3, // Block number 1
Instruction::GOTO | 0x200, // Block number 2
@@ -222,7 +224,7 @@ TEST_F(OptimizerTest, CFG8) {
}
TEST_F(OptimizerTest, CFG9) {
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 3, // Block number 1
Instruction::GOTO | 0x200, // Block number 2
@@ -243,7 +245,7 @@ TEST_F(OptimizerTest, CFG9) {
}
TEST_F(OptimizerTest, CFG10) {
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 6, // Block number 1
Instruction::IF_EQ, 3, // Block number 2
diff --git a/compiler/optimizing/find_loops_test.cc b/compiler/optimizing/find_loops_test.cc
index b799fb4688..75b8e9609e 100644
--- a/compiler/optimizing/find_loops_test.cc
+++ b/compiler/optimizing/find_loops_test.cc
@@ -31,7 +31,7 @@ class FindLoopsTest : public OptimizingUnitTest {};
TEST_F(FindLoopsTest, CFG1) {
// Constant is not used.
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::RETURN_VOID);
@@ -42,7 +42,7 @@ TEST_F(FindLoopsTest, CFG1) {
}
TEST_F(FindLoopsTest, CFG2) {
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::RETURN);
@@ -53,7 +53,7 @@ TEST_F(FindLoopsTest, CFG2) {
}
TEST_F(FindLoopsTest, CFG3) {
- const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+ const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Instruction::CONST_4 | 3 << 12 | 0,
Instruction::CONST_4 | 4 << 12 | 1 << 8,
Instruction::ADD_INT_2ADDR | 1 << 12,
@@ -67,7 +67,7 @@ TEST_F(FindLoopsTest, CFG3) {
}
TEST_F(FindLoopsTest, CFG4) {
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 4,
Instruction::CONST_4 | 4 << 12 | 0,
@@ -82,7 +82,7 @@ TEST_F(FindLoopsTest, CFG4) {
}
TEST_F(FindLoopsTest, CFG5) {
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 3,
Instruction::CONST_4 | 4 << 12 | 0,
@@ -126,7 +126,7 @@ TEST_F(FindLoopsTest, Loop1) {
// while (a == a) {
// }
// return;
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 3,
Instruction::GOTO | 0xFE00,
@@ -150,7 +150,7 @@ TEST_F(FindLoopsTest, Loop2) {
// while (a == a) {
// }
// return a;
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::GOTO | 0x400,
Instruction::IF_EQ, 4,
@@ -173,7 +173,7 @@ TEST_F(FindLoopsTest, Loop2) {
TEST_F(FindLoopsTest, Loop3) {
// Make sure we create a preheader of a loop when a header originally has two
// incoming blocks and one back edge.
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 3,
Instruction::GOTO | 0x100,
@@ -197,7 +197,7 @@ TEST_F(FindLoopsTest, Loop3) {
TEST_F(FindLoopsTest, Loop4) {
// Test loop with originally two back edges.
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 6,
Instruction::IF_EQ, 3,
@@ -221,7 +221,7 @@ TEST_F(FindLoopsTest, Loop4) {
TEST_F(FindLoopsTest, Loop5) {
// Test loop with two exit edges.
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 6,
Instruction::IF_EQ, 3,
@@ -244,7 +244,7 @@ TEST_F(FindLoopsTest, Loop5) {
}
TEST_F(FindLoopsTest, InnerLoop) {
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 6,
Instruction::IF_EQ, 3,
@@ -273,7 +273,7 @@ TEST_F(FindLoopsTest, InnerLoop) {
}
TEST_F(FindLoopsTest, TwoLoops) {
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 3,
Instruction::GOTO | 0xFE00, // first loop
@@ -301,7 +301,7 @@ TEST_F(FindLoopsTest, TwoLoops) {
}
TEST_F(FindLoopsTest, NonNaturalLoop) {
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 3,
Instruction::GOTO | 0x0100,
@@ -317,7 +317,7 @@ TEST_F(FindLoopsTest, NonNaturalLoop) {
}
TEST_F(FindLoopsTest, DoWhileLoop) {
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::GOTO | 0x0100,
Instruction::IF_EQ, 0xFFFF,
diff --git a/compiler/optimizing/graph_checker_test.cc b/compiler/optimizing/graph_checker_test.cc
index 9ca3e4953a..08bfa5d80f 100644
--- a/compiler/optimizing/graph_checker_test.cc
+++ b/compiler/optimizing/graph_checker_test.cc
@@ -22,7 +22,7 @@ namespace art {
class GraphCheckerTest : public OptimizingUnitTest {
protected:
HGraph* CreateSimpleCFG();
- void TestCode(const uint16_t* data);
+ void TestCode(const std::vector<uint16_t>& data);
};
/**
@@ -48,7 +48,7 @@ HGraph* GraphCheckerTest::CreateSimpleCFG() {
return graph;
}
-void GraphCheckerTest::TestCode(const uint16_t* data) {
+void GraphCheckerTest::TestCode(const std::vector<uint16_t>& data) {
HGraph* graph = CreateCFG(data);
ASSERT_NE(graph, nullptr);
@@ -58,14 +58,14 @@ void GraphCheckerTest::TestCode(const uint16_t* data) {
}
TEST_F(GraphCheckerTest, ReturnVoid) {
- const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ZERO_REGISTER_CODE_ITEM(
Instruction::RETURN_VOID);
TestCode(data);
}
TEST_F(GraphCheckerTest, CFG1) {
- const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ZERO_REGISTER_CODE_ITEM(
Instruction::GOTO | 0x100,
Instruction::RETURN_VOID);
@@ -73,7 +73,7 @@ TEST_F(GraphCheckerTest, CFG1) {
}
TEST_F(GraphCheckerTest, CFG2) {
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 3,
Instruction::GOTO | 0x100,
@@ -83,7 +83,7 @@ TEST_F(GraphCheckerTest, CFG2) {
}
TEST_F(GraphCheckerTest, CFG3) {
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 3,
Instruction::GOTO | 0x100,
@@ -128,7 +128,7 @@ TEST_F(GraphCheckerTest, BlockEndingWithNonBranchInstruction) {
TEST_F(GraphCheckerTest, SSAPhi) {
// This code creates one Phi function during the conversion to SSA form.
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 3,
Instruction::CONST_4 | 4 << 12 | 0,
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index b2ad8ec400..81a75584a4 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -1660,7 +1660,7 @@ bool HInliner::TryBuildAndInlineHelper(HInvoke* invoke_instruction,
const DexFile::CodeItem* code_item = resolved_method->GetCodeItem();
const DexFile& callee_dex_file = *resolved_method->GetDexFile();
uint32_t method_index = resolved_method->GetDexMethodIndex();
- CodeItemDebugInfoAccessor code_item_accessor(callee_dex_file, code_item);
+ CodeItemDebugInfoAccessor code_item_accessor(resolved_method);
ClassLinker* class_linker = caller_compilation_unit_.GetClassLinker();
Handle<mirror::DexCache> dex_cache = NewHandleIfDifferent(resolved_method->GetDexCache(),
caller_compilation_unit_.GetDexCache(),
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index 72a93c1f77..64a1eccf60 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -49,7 +49,7 @@ HInstructionBuilder::HInstructionBuilder(HGraph* graph,
const DexCompilationUnit* outer_compilation_unit,
CompilerDriver* compiler_driver,
CodeGenerator* code_generator,
- const uint8_t* interpreter_metadata,
+ ArrayRef<const uint8_t> interpreter_metadata,
OptimizingCompilerStats* compiler_stats,
VariableSizedHandleScope* handles,
ScopedArenaAllocator* local_allocator)
diff --git a/compiler/optimizing/instruction_builder.h b/compiler/optimizing/instruction_builder.h
index 708a09711a..4428c53277 100644
--- a/compiler/optimizing/instruction_builder.h
+++ b/compiler/optimizing/instruction_builder.h
@@ -17,6 +17,7 @@
#ifndef ART_COMPILER_OPTIMIZING_INSTRUCTION_BUILDER_H_
#define ART_COMPILER_OPTIMIZING_INSTRUCTION_BUILDER_H_
+#include "base/array_ref.h"
#include "base/scoped_arena_allocator.h"
#include "base/scoped_arena_containers.h"
#include "data_type.h"
@@ -57,7 +58,7 @@ class HInstructionBuilder : public ValueObject {
const DexCompilationUnit* outer_compilation_unit,
CompilerDriver* compiler_driver,
CodeGenerator* code_generator,
- const uint8_t* interpreter_metadata,
+ ArrayRef<const uint8_t> interpreter_metadata,
OptimizingCompilerStats* compiler_stats,
VariableSizedHandleScope* handles,
ScopedArenaAllocator* local_allocator);
diff --git a/compiler/optimizing/linearize_test.cc b/compiler/optimizing/linearize_test.cc
index 43b63a73ef..9fa5b74c62 100644
--- a/compiler/optimizing/linearize_test.cc
+++ b/compiler/optimizing/linearize_test.cc
@@ -35,11 +35,12 @@ namespace art {
class LinearizeTest : public OptimizingUnitTest {
protected:
template <size_t number_of_blocks>
- void TestCode(const uint16_t* data, const uint32_t (&expected_order)[number_of_blocks]);
+ void TestCode(const std::vector<uint16_t>& data,
+ const uint32_t (&expected_order)[number_of_blocks]);
};
template <size_t number_of_blocks>
-void LinearizeTest::TestCode(const uint16_t* data,
+void LinearizeTest::TestCode(const std::vector<uint16_t>& data,
const uint32_t (&expected_order)[number_of_blocks]) {
HGraph* graph = CreateCFG(data);
std::unique_ptr<const X86InstructionSetFeatures> features_x86(
@@ -68,7 +69,7 @@ TEST_F(LinearizeTest, CFG1) {
// + / \ +
// Block4 Block8
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 5,
Instruction::IF_EQ, 0xFFFE,
@@ -93,7 +94,7 @@ TEST_F(LinearizeTest, CFG2) {
// + / \ +
// Block5 Block8
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 3,
Instruction::RETURN_VOID,
@@ -119,7 +120,7 @@ TEST_F(LinearizeTest, CFG3) {
// Block6 + Block9
// | +
// Block4 ++
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 4,
Instruction::RETURN_VOID,
@@ -149,7 +150,7 @@ TEST_F(LinearizeTest, CFG4) {
// + / \ +
// Block5 Block11
*/
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 7,
Instruction::IF_EQ, 0xFFFE,
@@ -179,7 +180,7 @@ TEST_F(LinearizeTest, CFG5) {
// +/ \ +
// Block6 Block11
*/
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 3,
Instruction::RETURN_VOID,
@@ -205,7 +206,7 @@ TEST_F(LinearizeTest, CFG6) {
// Block5 <- Block9 Block6 +
// |
// Block7
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::GOTO | 0x0100,
Instruction::IF_EQ, 0x0004,
@@ -233,7 +234,7 @@ TEST_F(LinearizeTest, CFG7) {
// |
// Block7
//
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::GOTO | 0x0100,
Instruction::IF_EQ, 0x0005,
diff --git a/compiler/optimizing/live_ranges_test.cc b/compiler/optimizing/live_ranges_test.cc
index e45d7c820c..66660662e4 100644
--- a/compiler/optimizing/live_ranges_test.cc
+++ b/compiler/optimizing/live_ranges_test.cc
@@ -31,10 +31,10 @@ namespace art {
class LiveRangesTest : public OptimizingUnitTest {
public:
- HGraph* BuildGraph(const uint16_t* data);
+ HGraph* BuildGraph(const std::vector<uint16_t>& data);
};
-HGraph* LiveRangesTest::BuildGraph(const uint16_t* data) {
+HGraph* LiveRangesTest::BuildGraph(const std::vector<uint16_t>& data) {
HGraph* graph = CreateCFG(data);
// Suspend checks implementation may change in the future, and this test relies
// on how instructions are ordered.
@@ -57,7 +57,7 @@ TEST_F(LiveRangesTest, CFG1) {
* |
* 12: exit
*/
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::RETURN);
@@ -102,7 +102,7 @@ TEST_F(LiveRangesTest, CFG2) {
* |
* 26: exit
*/
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 3,
Instruction::GOTO | 0x100,
@@ -151,7 +151,7 @@ TEST_F(LiveRangesTest, CFG3) {
* |
* 28: exit
*/
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 3,
Instruction::CONST_4 | 4 << 12 | 0,
@@ -225,7 +225,7 @@ TEST_F(LiveRangesTest, Loop1) {
* 30: exit
*/
- const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+ const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 4,
Instruction::CONST_4 | 4 << 12 | 0,
@@ -304,7 +304,7 @@ TEST_F(LiveRangesTest, Loop2) {
* We want to make sure the phi at 10 has a lifetime hole after the add at 20.
*/
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 6,
Instruction::ADD_INT, 0, 0,
@@ -378,7 +378,7 @@ TEST_F(LiveRangesTest, CFG4) {
*
* We want to make sure the constant0 has a lifetime hole after the 16: add.
*/
- const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+ const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::CONST_4 | 4 << 12 | 1 << 8,
Instruction::IF_EQ, 5,
diff --git a/compiler/optimizing/liveness_test.cc b/compiler/optimizing/liveness_test.cc
index 35bc4ff8b3..6621a03568 100644
--- a/compiler/optimizing/liveness_test.cc
+++ b/compiler/optimizing/liveness_test.cc
@@ -31,7 +31,7 @@ namespace art {
class LivenessTest : public OptimizingUnitTest {
protected:
- void TestCode(const uint16_t* data, const char* expected);
+ void TestCode(const std::vector<uint16_t>& data, const char* expected);
};
static void DumpBitVector(BitVector* vector,
@@ -46,7 +46,7 @@ static void DumpBitVector(BitVector* vector,
buffer << ")\n";
}
-void LivenessTest::TestCode(const uint16_t* data, const char* expected) {
+void LivenessTest::TestCode(const std::vector<uint16_t>& data, const char* expected) {
HGraph* graph = CreateCFG(data);
// `Inline` conditions into ifs.
PrepareForRegisterAllocation(graph).Run();
@@ -86,7 +86,7 @@ TEST_F(LivenessTest, CFG1) {
" kill: (0)\n";
// Constant is not used.
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::RETURN_VOID);
@@ -108,7 +108,7 @@ TEST_F(LivenessTest, CFG2) {
" live out: (0)\n"
" kill: (0)\n";
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::RETURN);
@@ -134,7 +134,7 @@ TEST_F(LivenessTest, CFG3) {
" live out: (000)\n"
" kill: (000)\n";
- const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+ const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Instruction::CONST_4 | 3 << 12 | 0,
Instruction::CONST_4 | 4 << 12 | 1 << 8,
Instruction::ADD_INT_2ADDR | 1 << 12,
@@ -181,7 +181,7 @@ TEST_F(LivenessTest, CFG4) {
" live out: (0000)\n"
" kill: (0000)\n";
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 4,
Instruction::CONST_4 | 4 << 12 | 0,
@@ -228,7 +228,7 @@ TEST_F(LivenessTest, CFG5) {
" live out: (000)\n"
" kill: (000)\n";
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 3,
Instruction::CONST_4 | 4 << 12 | 0,
@@ -273,7 +273,7 @@ TEST_F(LivenessTest, Loop1) {
" kill: (000)\n";
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 4,
Instruction::CONST_4 | 4 << 12 | 0,
@@ -318,7 +318,7 @@ TEST_F(LivenessTest, Loop3) {
" live out: (0000)\n"
" kill: (0000)\n";
- const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+ const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 4,
Instruction::CONST_4 | 4 << 12 | 0,
@@ -370,7 +370,7 @@ TEST_F(LivenessTest, Loop4) {
" live out: (000)\n"
" kill: (000)\n";
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::GOTO | 0x500,
Instruction::IF_EQ, 5,
@@ -425,7 +425,7 @@ TEST_F(LivenessTest, Loop5) {
" live out: (0001)\n"
" kill: (0001)\n";
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 4,
Instruction::CONST_4 | 4 << 12 | 0,
@@ -475,7 +475,7 @@ TEST_F(LivenessTest, Loop6) {
" live out: (0000)\n"
" kill: (0000)\n";
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 8,
Instruction::CONST_4 | 4 << 12 | 0,
@@ -530,7 +530,7 @@ TEST_F(LivenessTest, Loop7) {
" live out: (00000)\n"
" kill: (00000)\n";
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 8,
Instruction::CONST_4 | 4 << 12 | 0,
@@ -580,7 +580,7 @@ TEST_F(LivenessTest, Loop8) {
" live out: (000)\n"
" kill: (000)\n";
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 6,
Instruction::ADD_INT, 0, 0,
diff --git a/compiler/optimizing/optimizing_cfi_test.cc b/compiler/optimizing/optimizing_cfi_test.cc
index e2b2106f65..d20b681b49 100644
--- a/compiler/optimizing/optimizing_cfi_test.cc
+++ b/compiler/optimizing/optimizing_cfi_test.cc
@@ -41,7 +41,7 @@ namespace art {
// Run the tests only on host.
#ifndef ART_TARGET_ANDROID
-class OptimizingCFITest : public CFITest {
+class OptimizingCFITest : public CFITest, public OptimizingUnitTestHelper {
public:
// Enable this flag to generate the expected outputs.
static constexpr bool kGenerateExpected = false;
@@ -63,7 +63,7 @@ class OptimizingCFITest : public CFITest {
// Setup simple context.
std::string error;
isa_features_ = InstructionSetFeatures::FromVariant(isa, "default", &error);
- graph_ = CreateGraph(&pool_and_allocator_);
+ graph_ = CreateGraph();
// Generate simple frame with some spills.
code_gen_ = CodeGenerator::Create(graph_, isa, *isa_features_, opts_);
code_gen_->GetAssembler()->cfi().SetEnabled(true);
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index f4115f7e7b..a3b1f0c5af 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -772,7 +772,7 @@ CodeGenerator* OptimizingCompiler::TryCompile(ArenaAllocator* allocator,
return nullptr;
}
- CodeItemDebugInfoAccessor code_item_accessor(dex_file, code_item);
+ CodeItemDebugInfoAccessor code_item_accessor(dex_file, code_item, method_idx);
HGraph* graph = new (allocator) HGraph(
allocator,
arena_stack,
@@ -783,7 +783,7 @@ CodeGenerator* OptimizingCompiler::TryCompile(ArenaAllocator* allocator,
compiler_driver->GetCompilerOptions().GetDebuggable(),
osr);
- const uint8_t* interpreter_metadata = nullptr;
+ ArrayRef<const uint8_t> interpreter_metadata;
// For AOT compilation, we may not get a method, for example if its class is erroneous.
// JIT should always have a method.
DCHECK(Runtime::Current()->IsAotCompiler() || method != nullptr);
@@ -940,7 +940,7 @@ CodeGenerator* OptimizingCompiler::TryCompileIntrinsic(
compiler_driver,
codegen.get(),
compilation_stats_.get(),
- /* interpreter_metadata */ nullptr,
+ /* interpreter_metadata */ ArrayRef<const uint8_t>(),
handles);
builder.BuildIntrinsicGraph(method);
}
diff --git a/compiler/optimizing/optimizing_unit_test.h b/compiler/optimizing/optimizing_unit_test.h
index 8c97d57f4a..6dcbadba6e 100644
--- a/compiler/optimizing/optimizing_unit_test.h
+++ b/compiler/optimizing/optimizing_unit_test.h
@@ -17,12 +17,16 @@
#ifndef ART_COMPILER_OPTIMIZING_OPTIMIZING_UNIT_TEST_H_
#define ART_COMPILER_OPTIMIZING_OPTIMIZING_UNIT_TEST_H_
+#include <memory>
+#include <vector>
+
#include "base/scoped_arena_allocator.h"
#include "builder.h"
#include "common_compiler_test.h"
#include "dex/code_item_accessors-inl.h"
#include "dex/dex_file.h"
#include "dex/dex_instruction.h"
+#include "dex/standard_dex_file.h"
#include "driver/dex_compilation_unit.h"
#include "handle_scope-inl.h"
#include "mirror/class_loader.h"
@@ -99,18 +103,11 @@ class ArenaPoolAndAllocator {
ScopedArenaAllocator scoped_allocator_;
};
-inline HGraph* CreateGraph(ArenaPoolAndAllocator* pool_and_allocator) {
- return new (pool_and_allocator->GetAllocator()) HGraph(
- pool_and_allocator->GetAllocator(),
- pool_and_allocator->GetArenaStack(),
- *reinterpret_cast<DexFile*>(pool_and_allocator->GetAllocator()->Alloc(sizeof(DexFile))),
- /*method_idx*/-1,
- kRuntimeISA);
-}
-
-class OptimizingUnitTest : public CommonCompilerTest {
- protected:
- OptimizingUnitTest() : pool_and_allocator_(new ArenaPoolAndAllocator()) { }
+// Have a separate helper so the OptimizingCFITest can inherit it without causing
+// multiple inheritance errors from having two gtest as a parent twice.
+class OptimizingUnitTestHelper {
+ public:
+ OptimizingUnitTestHelper() : pool_and_allocator_(new ArenaPoolAndAllocator()) { }
ArenaAllocator* GetAllocator() { return pool_and_allocator_->GetAllocator(); }
ArenaStack* GetArenaStack() { return pool_and_allocator_->GetArenaStack(); }
@@ -122,14 +119,42 @@ class OptimizingUnitTest : public CommonCompilerTest {
}
HGraph* CreateGraph() {
- return art::CreateGraph(pool_and_allocator_.get());
+ ArenaAllocator* const allocator = pool_and_allocator_->GetAllocator();
+
+ // Reserve a big array of 0s so the dex file constructor can offsets from the header.
+ static constexpr size_t kDexDataSize = 4 * KB;
+ const uint8_t* dex_data = reinterpret_cast<uint8_t*>(allocator->Alloc(kDexDataSize));
+
+ // Create the dex file based on the fake data. Call the constructor so that we can use virtual
+ // functions. Don't use the arena for the StandardDexFile otherwise the dex location leaks.
+ dex_files_.emplace_back(new StandardDexFile(
+ dex_data,
+ sizeof(StandardDexFile::Header),
+ "no_location",
+ /*location_checksum*/ 0,
+ /*oat_dex_file*/ nullptr,
+ /*container*/ nullptr));
+
+ return new (allocator) HGraph(
+ allocator,
+ pool_and_allocator_->GetArenaStack(),
+ *dex_files_.back(),
+ /*method_idx*/-1,
+ kRuntimeISA);
}
// Create a control-flow graph from Dex instructions.
- HGraph* CreateCFG(const uint16_t* data, DataType::Type return_type = DataType::Type::kInt32) {
- const DexFile::CodeItem* code_item = reinterpret_cast<const DexFile::CodeItem*>(data);
+ HGraph* CreateCFG(const std::vector<uint16_t>& data,
+ DataType::Type return_type = DataType::Type::kInt32) {
HGraph* graph = CreateGraph();
+ // The code item data might not aligned to 4 bytes, copy it to ensure that.
+ const size_t code_item_size = data.size() * sizeof(data.front());
+ void* aligned_data = GetAllocator()->Alloc(code_item_size);
+ memcpy(aligned_data, &data[0], code_item_size);
+ CHECK_ALIGNED(aligned_data, StandardDexFile::CodeItem::kAlignment);
+ const DexFile::CodeItem* code_item = reinterpret_cast<const DexFile::CodeItem*>(aligned_data);
+
{
ScopedObjectAccess soa(Thread::Current());
if (handles_ == nullptr) {
@@ -146,7 +171,7 @@ class OptimizingUnitTest : public CommonCompilerTest {
/* access_flags */ 0u,
/* verified_method */ nullptr,
handles_->NewHandle<mirror::DexCache>(nullptr));
- CodeItemDebugInfoAccessor accessor(graph->GetDexFile(), code_item);
+ CodeItemDebugInfoAccessor accessor(graph->GetDexFile(), code_item, /*dex_method_idx*/ 0u);
HGraphBuilder builder(graph, dex_compilation_unit, accessor, handles_.get(), return_type);
bool graph_built = (builder.BuildGraph() == kAnalysisSuccess);
return graph_built ? graph : nullptr;
@@ -154,10 +179,13 @@ class OptimizingUnitTest : public CommonCompilerTest {
}
private:
+ std::vector<std::unique_ptr<const StandardDexFile>> dex_files_;
std::unique_ptr<ArenaPoolAndAllocator> pool_and_allocator_;
std::unique_ptr<VariableSizedHandleScope> handles_;
};
+class OptimizingUnitTest : public CommonCompilerTest, public OptimizingUnitTestHelper {};
+
// Naive string diff data type.
typedef std::list<std::pair<std::string, std::string>> diff_t;
diff --git a/compiler/optimizing/pretty_printer_test.cc b/compiler/optimizing/pretty_printer_test.cc
index 4fc7fe9427..6ef386b4a5 100644
--- a/compiler/optimizing/pretty_printer_test.cc
+++ b/compiler/optimizing/pretty_printer_test.cc
@@ -29,10 +29,10 @@ namespace art {
class PrettyPrinterTest : public OptimizingUnitTest {
protected:
- void TestCode(const uint16_t* data, const char* expected);
+ void TestCode(const std::vector<uint16_t>& data, const char* expected);
};
-void PrettyPrinterTest::TestCode(const uint16_t* data, const char* expected) {
+void PrettyPrinterTest::TestCode(const std::vector<uint16_t>& data, const char* expected) {
HGraph* graph = CreateCFG(data);
StringPrettyPrinter printer(graph);
printer.VisitInsertionOrder();
@@ -40,7 +40,7 @@ void PrettyPrinterTest::TestCode(const uint16_t* data, const char* expected) {
}
TEST_F(PrettyPrinterTest, ReturnVoid) {
- const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ZERO_REGISTER_CODE_ITEM(
Instruction::RETURN_VOID);
const char* expected =
@@ -67,7 +67,7 @@ TEST_F(PrettyPrinterTest, CFG1) {
"BasicBlock 3, pred: 2\n"
" 4: Exit\n";
- const uint16_t data[] =
+ const std::vector<uint16_t> data =
ZERO_REGISTER_CODE_ITEM(
Instruction::GOTO | 0x100,
Instruction::RETURN_VOID);
@@ -89,7 +89,7 @@ TEST_F(PrettyPrinterTest, CFG2) {
"BasicBlock 4, pred: 3\n"
" 5: Exit\n";
- const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ZERO_REGISTER_CODE_ITEM(
Instruction::GOTO | 0x100,
Instruction::GOTO | 0x100,
Instruction::RETURN_VOID);
@@ -111,21 +111,21 @@ TEST_F(PrettyPrinterTest, CFG3) {
"BasicBlock 4, pred: 2\n"
" 5: Exit\n";
- const uint16_t data1[] = ZERO_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data1 = ZERO_REGISTER_CODE_ITEM(
Instruction::GOTO | 0x200,
Instruction::RETURN_VOID,
Instruction::GOTO | 0xFF00);
TestCode(data1, expected);
- const uint16_t data2[] = ZERO_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data2 = ZERO_REGISTER_CODE_ITEM(
Instruction::GOTO_16, 3,
Instruction::RETURN_VOID,
Instruction::GOTO_16, 0xFFFF);
TestCode(data2, expected);
- const uint16_t data3[] = ZERO_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data3 = ZERO_REGISTER_CODE_ITEM(
Instruction::GOTO_32, 4, 0,
Instruction::RETURN_VOID,
Instruction::GOTO_32, 0xFFFF, 0xFFFF);
@@ -144,13 +144,13 @@ TEST_F(PrettyPrinterTest, CFG4) {
"BasicBlock 3, pred: 0, succ: 1\n"
" 0: Goto 1\n";
- const uint16_t data1[] = ZERO_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data1 = ZERO_REGISTER_CODE_ITEM(
Instruction::NOP,
Instruction::GOTO | 0xFF00);
TestCode(data1, expected);
- const uint16_t data2[] = ZERO_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data2 = ZERO_REGISTER_CODE_ITEM(
Instruction::GOTO_32, 0, 0);
TestCode(data2, expected);
@@ -166,7 +166,7 @@ TEST_F(PrettyPrinterTest, CFG5) {
"BasicBlock 3, pred: 1\n"
" 3: Exit\n";
- const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ZERO_REGISTER_CODE_ITEM(
Instruction::RETURN_VOID,
Instruction::GOTO | 0x100,
Instruction::GOTO | 0xFE00);
@@ -192,7 +192,7 @@ TEST_F(PrettyPrinterTest, CFG6) {
"BasicBlock 5, pred: 1, succ: 3\n"
" 0: Goto 3\n";
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 3,
Instruction::GOTO | 0x100,
@@ -220,7 +220,7 @@ TEST_F(PrettyPrinterTest, CFG7) {
"BasicBlock 6, pred: 1, succ: 2\n"
" 1: Goto 2\n";
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 3,
Instruction::GOTO | 0x100,
@@ -240,7 +240,7 @@ TEST_F(PrettyPrinterTest, IntConstant) {
"BasicBlock 2, pred: 1\n"
" 4: Exit\n";
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::RETURN_VOID);
diff --git a/compiler/optimizing/register_allocator_test.cc b/compiler/optimizing/register_allocator_test.cc
index 3748d599a3..a70b0664dc 100644
--- a/compiler/optimizing/register_allocator_test.cc
+++ b/compiler/optimizing/register_allocator_test.cc
@@ -46,7 +46,7 @@ class RegisterAllocatorTest : public OptimizingUnitTest {
void ExpectedInRegisterHint(Strategy strategy);
// Helper functions that make use of the OptimizingUnitTest's members.
- bool Check(const uint16_t* data, Strategy strategy);
+ bool Check(const std::vector<uint16_t>& data, Strategy strategy);
void CFG1(Strategy strategy);
void Loop1(Strategy strategy);
void Loop2(Strategy strategy);
@@ -79,7 +79,7 @@ TEST_F(RegisterAllocatorTest, test_name##_GraphColor) {\
test_name(Strategy::kRegisterAllocatorGraphColor);\
}
-bool RegisterAllocatorTest::Check(const uint16_t* data, Strategy strategy) {
+bool RegisterAllocatorTest::Check(const std::vector<uint16_t>& data, Strategy strategy) {
HGraph* graph = CreateCFG(data);
std::unique_ptr<const X86InstructionSetFeatures> features_x86(
X86InstructionSetFeatures::FromCppDefines());
@@ -185,7 +185,7 @@ void RegisterAllocatorTest::CFG1(Strategy strategy) {
* |
* exit
*/
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::RETURN);
@@ -222,7 +222,7 @@ void RegisterAllocatorTest::Loop1(Strategy strategy) {
* exit
*/
- const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+ const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 4,
Instruction::CONST_4 | 4 << 12 | 0,
@@ -268,7 +268,7 @@ void RegisterAllocatorTest::Loop2(Strategy strategy) {
* exit
*/
- const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+ const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::CONST_4 | 8 << 12 | 1 << 8,
Instruction::IF_EQ | 1 << 8, 7,
@@ -314,7 +314,7 @@ void RegisterAllocatorTest::Loop3(Strategy strategy) {
* exit
*/
- const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
+ const std::vector<uint16_t> data = THREE_REGISTERS_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::ADD_INT_LIT8 | 1 << 8, 1 << 8,
Instruction::CONST_4 | 5 << 12 | 2 << 8,
@@ -351,7 +351,7 @@ void RegisterAllocatorTest::Loop3(Strategy strategy) {
TEST_ALL_STRATEGIES(Loop3);
TEST_F(RegisterAllocatorTest, FirstRegisterUse) {
- const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
+ const std::vector<uint16_t> data = THREE_REGISTERS_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::XOR_INT_LIT8 | 1 << 8, 1 << 8,
Instruction::XOR_INT_LIT8 | 0 << 8, 1 << 8,
@@ -402,7 +402,7 @@ void RegisterAllocatorTest::DeadPhi(Strategy strategy) {
* } while (true);
*/
- const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+ const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::CONST_4 | 1 << 8 | 0,
Instruction::IF_NE | 1 << 8 | 1 << 12, 3,
@@ -432,7 +432,7 @@ TEST_ALL_STRATEGIES(DeadPhi);
* This test only applies to the linear scan allocator.
*/
TEST_F(RegisterAllocatorTest, FreeUntil) {
- const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+ const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::RETURN);
diff --git a/compiler/optimizing/scheduler_test.cc b/compiler/optimizing/scheduler_test.cc
index 104ebc79c2..fb15fc8975 100644
--- a/compiler/optimizing/scheduler_test.cc
+++ b/compiler/optimizing/scheduler_test.cc
@@ -182,7 +182,9 @@ class SchedulerTest : public OptimizingUnitTest {
scheduler->Schedule(graph_);
}
- void CompileWithRandomSchedulerAndRun(const uint16_t* data, bool has_result, int expected) {
+ void CompileWithRandomSchedulerAndRun(const std::vector<uint16_t>& data,
+ bool has_result,
+ int expected) {
for (CodegenTargetConfig target_config : GetTargetConfigs()) {
HGraph* graph = CreateCFG(data);
@@ -393,7 +395,7 @@ TEST_F(SchedulerTest, RandomScheduling) {
// }
// return result;
//
- const uint16_t data[] = SIX_REGISTERS_CODE_ITEM(
+ const std::vector<uint16_t> data = SIX_REGISTERS_CODE_ITEM(
Instruction::CONST_4 | 0 << 12 | 2 << 8, // const/4 v2, #int 0
Instruction::CONST_HIGH16 | 0 << 8, 0x4120, // const/high16 v0, #float 10.0 // #41200000
Instruction::CONST_4 | 1 << 12 | 1 << 8, // const/4 v1, #int 1
diff --git a/compiler/optimizing/ssa_test.cc b/compiler/optimizing/ssa_test.cc
index 77e70d733e..85ed06eb9b 100644
--- a/compiler/optimizing/ssa_test.cc
+++ b/compiler/optimizing/ssa_test.cc
@@ -31,7 +31,7 @@ namespace art {
class SsaTest : public OptimizingUnitTest {
protected:
- void TestCode(const uint16_t* data, const char* expected);
+ void TestCode(const std::vector<uint16_t>& data, const char* expected);
};
class SsaPrettyPrinter : public HPrettyPrinter {
@@ -80,7 +80,7 @@ static void ReNumberInstructions(HGraph* graph) {
}
}
-void SsaTest::TestCode(const uint16_t* data, const char* expected) {
+void SsaTest::TestCode(const std::vector<uint16_t>& data, const char* expected) {
HGraph* graph = CreateCFG(data);
// Suspend checks implementation may change in the future, and this test relies
// on how instructions are ordered.
@@ -119,7 +119,7 @@ TEST_F(SsaTest, CFG1) {
"BasicBlock 5, pred: 1, succ: 3\n"
" 7: Goto\n";
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 3,
Instruction::GOTO | 0x100,
@@ -150,7 +150,7 @@ TEST_F(SsaTest, CFG2) {
"BasicBlock 5, pred: 1, succ: 3\n"
" 9: Goto\n";
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 3,
Instruction::CONST_4 | 4 << 12 | 0,
@@ -181,7 +181,7 @@ TEST_F(SsaTest, CFG3) {
"BasicBlock 5, pred: 4\n"
" 10: Exit\n";
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 4,
Instruction::CONST_4 | 4 << 12 | 0,
@@ -214,7 +214,7 @@ TEST_F(SsaTest, Loop1) {
"BasicBlock 6, pred: 5\n"
" 10: Exit\n";
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 4,
Instruction::CONST_4 | 4 << 12 | 0,
@@ -245,7 +245,7 @@ TEST_F(SsaTest, Loop2) {
"BasicBlock 5, pred: 4\n"
" 9: Exit\n";
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 4,
Instruction::CONST_4 | 4 << 12 | 0,
@@ -276,7 +276,7 @@ TEST_F(SsaTest, Loop3) {
"BasicBlock 5, pred: 4\n"
" 10: Exit\n";
- const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+ const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 4,
Instruction::CONST_4 | 4 << 12 | 0,
@@ -310,7 +310,7 @@ TEST_F(SsaTest, Loop4) {
"BasicBlock 6, pred: 5\n"
" 10: Exit\n";
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::GOTO | 0x500,
Instruction::IF_EQ, 5,
@@ -351,7 +351,7 @@ TEST_F(SsaTest, Loop5) {
" 13: Phi(2, 1) [11, 8, 8]\n"
" 14: Goto\n";
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 4,
Instruction::CONST_4 | 4 << 12 | 0,
@@ -390,7 +390,7 @@ TEST_F(SsaTest, Loop6) {
"BasicBlock 7, pred: 6\n"
" 13: Exit\n";
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 8,
Instruction::CONST_4 | 4 << 12 | 0,
@@ -432,7 +432,7 @@ TEST_F(SsaTest, Loop7) {
"BasicBlock 8, pred: 2, succ: 6\n"
" 15: Goto\n";
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 8,
Instruction::CONST_4 | 4 << 12 | 0,
@@ -456,7 +456,7 @@ TEST_F(SsaTest, DeadLocal) {
"BasicBlock 2, pred: 1\n"
" 3: Exit\n";
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::RETURN_VOID);
@@ -484,7 +484,7 @@ TEST_F(SsaTest, LocalInIf) {
"BasicBlock 5, pred: 1, succ: 3\n"
" 8: Goto\n";
- const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+ const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 3,
Instruction::CONST_4 | 4 << 12 | 1 << 8,
@@ -520,7 +520,7 @@ TEST_F(SsaTest, MultiplePredecessors) {
"BasicBlock 7, pred: 3, succ: 5\n"
" 12: Goto\n";
- const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+ const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 5,
Instruction::ADD_INT_LIT8 | 1 << 8, 0 << 8,
diff --git a/compiler/optimizing/suspend_check_test.cc b/compiler/optimizing/suspend_check_test.cc
index 7e83f8ce5f..33823e2a11 100644
--- a/compiler/optimizing/suspend_check_test.cc
+++ b/compiler/optimizing/suspend_check_test.cc
@@ -30,10 +30,10 @@ namespace art {
class SuspendCheckTest : public OptimizingUnitTest {
protected:
- void TestCode(const uint16_t* data);
+ void TestCode(const std::vector<uint16_t>& data);
};
-void SuspendCheckTest::TestCode(const uint16_t* data) {
+void SuspendCheckTest::TestCode(const std::vector<uint16_t>& data) {
HGraph* graph = CreateCFG(data);
HBasicBlock* first_block = graph->GetEntryBlock()->GetSingleSuccessor();
HBasicBlock* loop_header = first_block->GetSingleSuccessor();
@@ -43,7 +43,7 @@ void SuspendCheckTest::TestCode(const uint16_t* data) {
}
TEST_F(SuspendCheckTest, CFG1) {
- const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ZERO_REGISTER_CODE_ITEM(
Instruction::NOP,
Instruction::GOTO | 0xFF00);
@@ -51,14 +51,14 @@ TEST_F(SuspendCheckTest, CFG1) {
}
TEST_F(SuspendCheckTest, CFG2) {
- const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ZERO_REGISTER_CODE_ITEM(
Instruction::GOTO_32, 0, 0);
TestCode(data);
}
TEST_F(SuspendCheckTest, CFG3) {
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 0xFFFF,
Instruction::RETURN_VOID);
@@ -67,7 +67,7 @@ TEST_F(SuspendCheckTest, CFG3) {
}
TEST_F(SuspendCheckTest, CFG4) {
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_NE, 0xFFFF,
Instruction::RETURN_VOID);
@@ -76,7 +76,7 @@ TEST_F(SuspendCheckTest, CFG4) {
}
TEST_F(SuspendCheckTest, CFG5) {
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQZ, 0xFFFF,
Instruction::RETURN_VOID);
@@ -85,7 +85,7 @@ TEST_F(SuspendCheckTest, CFG5) {
}
TEST_F(SuspendCheckTest, CFG6) {
- const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+ const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_NEZ, 0xFFFF,
Instruction::RETURN_VOID);
diff --git a/compiler/utils/test_dex_file_builder.h b/compiler/utils/test_dex_file_builder.h
index 04fba51dc1..58f1ec7b08 100644
--- a/compiler/utils/test_dex_file_builder.h
+++ b/compiler/utils/test_dex_file_builder.h
@@ -27,6 +27,7 @@
#include <android-base/logging.h>
#include "base/bit_utils.h"
+#include "dex/art_dex_file_loader.h"
#include "dex/dex_file_loader.h"
#include "dex/standard_dex_file.h"
@@ -233,7 +234,8 @@ class TestDexFileBuilder {
static constexpr bool kVerify = false;
static constexpr bool kVerifyChecksum = false;
std::string error_msg;
- std::unique_ptr<const DexFile> dex_file(DexFileLoader::Open(
+ const ArtDexFileLoader dex_file_loader;
+ std::unique_ptr<const DexFile> dex_file(dex_file_loader.Open(
&dex_file_data_[0],
dex_file_data_.size(),
dex_location,
diff --git a/dex2oat/Android.bp b/dex2oat/Android.bp
index 6bebf7d2da..dc71b9ba3e 100644
--- a/dex2oat/Android.bp
+++ b/dex2oat/Android.bp
@@ -129,6 +129,18 @@ art_cc_binary {
static_libs: [
"libart-dex2oat",
],
+
+ pgo: {
+ instrumentation: true,
+ profile_file: "dex2oat.profdata",
+ benchmarks: ["dex2oat"],
+ enable_profile_use: false,
+ cflags: [
+ // Ignore frame-size increase resulting from instrumentation.
+ "-Wno-frame-larger-than=",
+ "-DART_PGO_INSTRUMENTATION",
+ ],
+ }
}
art_cc_binary {
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 9c15c4a194..7796b3acc6 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -1807,9 +1807,7 @@ class Dex2Oat FINAL {
// We do not decompile a RETURN_VOID_NO_BARRIER into a RETURN_VOID, as the quickening
// optimization does not depend on the boot image (the optimization relies on not
// having final fields in a class, which does not change for an app).
- VdexFile::Unquicken(dex_files_,
- input_vdex_file_->GetQuickeningInfo(),
- /* decompile_return_instruction */ false);
+ input_vdex_file_->Unquicken(dex_files_, /* decompile_return_instruction */ false);
} else {
// Create the main VerifierDeps, here instead of in the compiler since we want to aggregate
// the results for all the dex files, not just the results for the current dex file.
@@ -3064,9 +3062,9 @@ static dex2oat::ReturnCode Dex2oat(int argc, char** argv) {
int main(int argc, char** argv) {
int result = static_cast<int>(art::Dex2oat(argc, argv));
// Everything was done, do an explicit exit here to avoid running Runtime destructors that take
- // time (bug 10645725) unless we're a debug build or running on valgrind. Note: The Dex2Oat class
- // should not destruct the runtime in this case.
- if (!art::kIsDebugBuild && (RUNNING_ON_MEMORY_TOOL == 0)) {
+ // time (bug 10645725) unless we're a debug or instrumented build or running on valgrind. Note:
+ // The Dex2Oat class should not destruct the runtime in this case.
+ if (!art::kIsDebugBuild && !art::kIsPGOInstrumentation && (RUNNING_ON_MEMORY_TOOL == 0)) {
_exit(result);
}
return result;
diff --git a/dex2oat/dex2oat_image_test.cc b/dex2oat/dex2oat_image_test.cc
index 980363b1bb..05592f1806 100644
--- a/dex2oat/dex2oat_image_test.cc
+++ b/dex2oat/dex2oat_image_test.cc
@@ -29,6 +29,7 @@
#include "base/file_utils.h"
#include "base/macros.h"
#include "base/unix_file/fd_file.h"
+#include "dex/art_dex_file_loader.h"
#include "dex/dex_file-inl.h"
#include "dex/dex_file_loader.h"
#include "jit/profile_compilation_info.h"
@@ -65,12 +66,13 @@ class Dex2oatImageTest : public CommonRuntimeTest {
for (const std::string& dex : GetLibCoreDexFileNames()) {
std::vector<std::unique_ptr<const DexFile>> dex_files;
std::string error_msg;
- CHECK(DexFileLoader::Open(dex.c_str(),
- dex,
- /*verify*/ true,
- /*verify_checksum*/ false,
- &error_msg,
- &dex_files))
+ const ArtDexFileLoader dex_file_loader;
+ CHECK(dex_file_loader.Open(dex.c_str(),
+ dex,
+ /*verify*/ true,
+ /*verify_checksum*/ false,
+ &error_msg,
+ &dex_files))
<< error_msg;
for (const std::unique_ptr<const DexFile>& dex_file : dex_files) {
for (size_t i = 0; i < dex_file->NumMethodIds(); ++i) {
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index f176cc2839..8799540fd3 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -30,6 +30,7 @@
#include "base/macros.h"
#include "base/mutex-inl.h"
#include "bytecode_utils.h"
+#include "dex/art_dex_file_loader.h"
#include "dex/code_item_accessors-inl.h"
#include "dex/dex_file-inl.h"
#include "dex/dex_file_loader.h"
@@ -108,6 +109,8 @@ class Dex2oatTest : public Dex2oatEnvironmentTest {
[](const OatFile&) {});
}
+ bool test_accepts_odex_file_on_failure = false;
+
template <typename T>
void GenerateOdexForTest(
const std::string& dex_location,
@@ -124,7 +127,7 @@ class Dex2oatTest : public Dex2oatEnvironmentTest {
&error_msg,
extra_args,
use_fd);
- bool success = (status == 0);
+ bool success = (WIFEXITED(status) && WEXITSTATUS(status) == 0);
if (expect_success) {
ASSERT_TRUE(success) << error_msg << std::endl << output_;
@@ -146,16 +149,18 @@ class Dex2oatTest : public Dex2oatEnvironmentTest {
error_msg_ = error_msg;
- // Verify there's no loadable odex file.
- std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
- odex_location.c_str(),
- nullptr,
- nullptr,
- false,
- /*low_4gb*/false,
- dex_location.c_str(),
- &error_msg));
- ASSERT_TRUE(odex_file.get() == nullptr);
+ if (!test_accepts_odex_file_on_failure) {
+ // Verify there's no loadable odex file.
+ std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
+ odex_location.c_str(),
+ nullptr,
+ nullptr,
+ false,
+ /*low_4gb*/false,
+ dex_location.c_str(),
+ &error_msg));
+ ASSERT_TRUE(odex_file.get() == nullptr);
+ }
}
}
@@ -680,7 +685,8 @@ class Dex2oatLayoutTest : public Dex2oatTest {
const char* location = dex_location.c_str();
std::string error_msg;
std::vector<std::unique_ptr<const DexFile>> dex_files;
- ASSERT_TRUE(DexFileLoader::Open(
+ const ArtDexFileLoader dex_file_loader;
+ ASSERT_TRUE(dex_file_loader.Open(
location, location, /* verify */ true, /* verify_checksum */ true, &error_msg, &dex_files));
EXPECT_EQ(dex_files.size(), 1U);
std::unique_ptr<const DexFile>& dex_file = dex_files[0];
@@ -815,7 +821,8 @@ class Dex2oatLayoutTest : public Dex2oatTest {
const char* location = dex_location.c_str();
std::vector<std::unique_ptr<const DexFile>> dex_files;
- ASSERT_TRUE(DexFileLoader::Open(
+ const ArtDexFileLoader dex_file_loader;
+ ASSERT_TRUE(dex_file_loader.Open(
location, location, /* verify */ true, /* verify_checksum */ true, &error_msg, &dex_files));
EXPECT_EQ(dex_files.size(), 1U);
std::unique_ptr<const DexFile>& old_dex_file = dex_files[0];
@@ -993,7 +1000,12 @@ TEST_F(Dex2oatWatchdogTest, TestWatchdogOK) {
TEST_F(Dex2oatWatchdogTest, TestWatchdogTrigger) {
TEST_DISABLED_FOR_MEMORY_TOOL_VALGRIND(); // b/63052624
- TEST_DISABLED_WITHOUT_BAKER_READ_BARRIERS(); // b/63052624
+
+ // The watchdog is independent of dex2oat and will not delete intermediates. It is possible
+ // that the compilation succeeds and the file is completely written by the time the watchdog
+ // kills dex2oat (but the dex2oat threads must have been scheduled pretty badly).
+ test_accepts_odex_file_on_failure = true;
+
// Check with ten milliseconds.
RunTest(false, { "--watchdog-timeout=10" });
}
diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc
index e9a2553cd3..31b6ac305c 100644
--- a/dex2oat/linker/oat_writer.cc
+++ b/dex2oat/linker/oat_writer.cc
@@ -33,6 +33,7 @@
#include "class_table-inl.h"
#include "compiled_method-inl.h"
#include "debug/method_debug_info.h"
+#include "dex/art_dex_file_loader.h"
#include "dex/dex_file-inl.h"
#include "dex/dex_file_loader.h"
#include "dex/dex_file_types.h"
@@ -57,6 +58,7 @@
#include "mirror/object-inl.h"
#include "oat_quick_method_header.h"
#include "os.h"
+#include "quicken_info.h"
#include "safe_map.h"
#include "scoped_thread_state_change-inl.h"
#include "type_lookup_table.h"
@@ -2617,42 +2619,54 @@ bool OatWriter::WriteRodata(OutputStream* out) {
return true;
}
-class OatWriter::WriteQuickeningInfoMethodVisitor : public DexMethodVisitor {
+class OatWriter::WriteQuickeningInfoMethodVisitor {
public:
- WriteQuickeningInfoMethodVisitor(OatWriter* writer,
- OutputStream* out,
- uint32_t offset,
- SafeMap<const uint8_t*, uint32_t>* offset_map)
- : DexMethodVisitor(writer, offset),
- out_(out),
- written_bytes_(0u),
- offset_map_(offset_map) {}
+ WriteQuickeningInfoMethodVisitor(OatWriter* writer, OutputStream* out)
+ : writer_(writer),
+ out_(out) {}
- bool VisitMethod(size_t class_def_method_index ATTRIBUTE_UNUSED, const ClassDataItemIterator& it)
- OVERRIDE {
- uint32_t method_idx = it.GetMemberIndex();
- CompiledMethod* compiled_method =
- writer_->compiler_driver_->GetCompiledMethod(MethodReference(dex_file_, method_idx));
+ bool VisitDexMethods(const std::vector<const DexFile*>& dex_files) {
+ std::vector<uint8_t> empty_quicken_info;
+ {
+ // Since we need to be able to access by dex method index, put a one byte empty quicken info
+ // for any method that isn't quickened.
+ QuickenInfoTable::Builder empty_info(&empty_quicken_info, /*num_elements*/ 0u);
+ CHECK(!empty_quicken_info.empty());
+ }
+ for (const DexFile* dex_file : dex_files) {
+ std::vector<uint32_t>* const offsets =
+ &quicken_info_offset_indices_.Put(dex_file, std::vector<uint32_t>())->second;
+
+ // Every method needs an index in the table.
+ for (uint32_t method_idx = 0; method_idx < dex_file->NumMethodIds(); ++method_idx) {
+ ArrayRef<const uint8_t> map(empty_quicken_info);
+
+ // Use the existing quicken info if it exists.
+ MethodReference method_ref(dex_file, method_idx);
+ CompiledMethod* compiled_method = writer_->compiler_driver_->GetCompiledMethod(method_ref);
+ if (compiled_method != nullptr && HasQuickeningInfo(compiled_method)) {
+ map = compiled_method->GetVmapTable();
+ }
- if (HasQuickeningInfo(compiled_method)) {
- ArrayRef<const uint8_t> map = compiled_method->GetVmapTable();
- // Deduplication is already done on a pointer basis by the compiler driver,
- // so we can simply compare the pointers to find out if things are duplicated.
- if (offset_map_->find(map.data()) == offset_map_->end()) {
- uint32_t length = map.size() * sizeof(map.front());
- offset_map_->Put(map.data(), written_bytes_);
- if (!out_->WriteFully(&length, sizeof(length)) ||
- !out_->WriteFully(map.data(), length)) {
- PLOG(ERROR) << "Failed to write quickening info for "
- << dex_file_->PrettyMethod(it.GetMemberIndex()) << " to "
- << out_->GetLocation();
+ // The current approach prevents deduplication of quicken infos since each method index
+ // has one unique quicken info. Deduplication does not provide much savings for dex indices
+ // since they are rarely duplicated.
+ const uint32_t length = map.size() * sizeof(map.front());
+
+ // Record each index if required. written_bytes_ is the offset from the start of the
+ // quicken info data.
+ if (QuickenInfoOffsetTableAccessor::IsCoveredIndex(method_idx)) {
+ offsets->push_back(written_bytes_);
+ }
+
+ if (!out_->WriteFully(map.data(), length)) {
+ PLOG(ERROR) << "Failed to write quickening info for " << method_ref.PrettyMethod()
+ << " to " << out_->GetLocation();
return false;
}
- written_bytes_ += sizeof(length) + length;
- offset_ += sizeof(length) + length;
+ written_bytes_ += length;
}
}
-
return true;
}
@@ -2660,71 +2674,59 @@ class OatWriter::WriteQuickeningInfoMethodVisitor : public DexMethodVisitor {
return written_bytes_;
}
+ SafeMap<const DexFile*, std::vector<uint32_t>>& GetQuickenInfoOffsetIndicies() {
+ return quicken_info_offset_indices_;
+ }
+
+
private:
+ OatWriter* const writer_;
OutputStream* const out_;
- size_t written_bytes_;
- // Maps quickening map to its offset in the file.
- SafeMap<const uint8_t*, uint32_t>* offset_map_;
+ size_t written_bytes_ = 0u;
+ // Map of offsets for quicken info related to method indices.
+ SafeMap<const DexFile*, std::vector<uint32_t>> quicken_info_offset_indices_;
};
-class OatWriter::WriteQuickeningIndicesMethodVisitor {
+class OatWriter::WriteQuickeningInfoOffsetsMethodVisitor {
public:
- WriteQuickeningIndicesMethodVisitor(OutputStream* out,
- uint32_t quickening_info_bytes,
- const SafeMap<const uint8_t*, uint32_t>& offset_map)
+ WriteQuickeningInfoOffsetsMethodVisitor(
+ OutputStream* out,
+ uint32_t start_offset,
+ SafeMap<const DexFile*, std::vector<uint32_t>>* quicken_info_offset_indices,
+ std::vector<uint32_t>* out_table_offsets)
: out_(out),
- quickening_info_bytes_(quickening_info_bytes),
- written_bytes_(0u),
- offset_map_(offset_map) {}
+ start_offset_(start_offset),
+ quicken_info_offset_indices_(quicken_info_offset_indices),
+ out_table_offsets_(out_table_offsets) {}
- bool VisitDexMethods(const std::vector<const DexFile*>& dex_files, const CompilerDriver& driver) {
+ bool VisitDexMethods(const std::vector<const DexFile*>& dex_files) {
for (const DexFile* dex_file : dex_files) {
- const size_t class_def_count = dex_file->NumClassDefs();
- for (size_t class_def_index = 0; class_def_index != class_def_count; ++class_def_index) {
- const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
- const uint8_t* class_data = dex_file->GetClassData(class_def);
- if (class_data == nullptr) {
- continue;
- }
- for (ClassDataItemIterator class_it(*dex_file, class_data);
- class_it.HasNext();
- class_it.Next()) {
- if (!class_it.IsAtMethod() || class_it.GetMethodCodeItem() == nullptr) {
- continue;
- }
- uint32_t method_idx = class_it.GetMemberIndex();
- CompiledMethod* compiled_method =
- driver.GetCompiledMethod(MethodReference(dex_file, method_idx));
- const DexFile::CodeItem* code_item = class_it.GetMethodCodeItem();
- CodeItemDebugInfoAccessor accessor(*dex_file, code_item);
- const uint32_t existing_debug_info_offset = accessor.DebugInfoOffset();
- // If the existing offset is already out of bounds (and not magic marker 0xFFFFFFFF)
- // we will pretend the method has been quickened.
- bool existing_offset_out_of_bounds =
- (existing_debug_info_offset >= dex_file->Size() &&
- existing_debug_info_offset != 0xFFFFFFFF);
- bool has_quickening_info = HasQuickeningInfo(compiled_method);
- if (has_quickening_info || existing_offset_out_of_bounds) {
- uint32_t new_debug_info_offset =
- dex_file->Size() + quickening_info_bytes_ + written_bytes_;
- // Abort if overflow.
- CHECK_GE(new_debug_info_offset, dex_file->Size());
- const_cast<DexFile::CodeItem*>(code_item)->SetDebugInfoOffset(new_debug_info_offset);
- uint32_t quickening_offset = has_quickening_info
- ? offset_map_.Get(compiled_method->GetVmapTable().data())
- : VdexFile::kNoQuickeningInfoOffset;
- if (!out_->WriteFully(&existing_debug_info_offset,
- sizeof(existing_debug_info_offset)) ||
- !out_->WriteFully(&quickening_offset, sizeof(quickening_offset))) {
- PLOG(ERROR) << "Failed to write quickening info for "
- << dex_file->PrettyMethod(method_idx) << " to "
- << out_->GetLocation();
- return false;
- }
- written_bytes_ += sizeof(existing_debug_info_offset) + sizeof(quickening_offset);
- }
- }
+ auto it = quicken_info_offset_indices_->find(dex_file);
+ DCHECK(it != quicken_info_offset_indices_->end()) << "Failed to find dex file "
+ << dex_file->GetLocation();
+ const std::vector<uint32_t>* const offsets = &it->second;
+
+ const uint32_t current_offset = start_offset_ + written_bytes_;
+ CHECK_ALIGNED_PARAM(current_offset, QuickenInfoOffsetTableAccessor::Alignment());
+
+ // Generate and write the data.
+ std::vector<uint8_t> table_data;
+ QuickenInfoOffsetTableAccessor::Builder builder(&table_data);
+ for (uint32_t offset : *offsets) {
+ builder.AddOffset(offset);
+ }
+
+ // Store the offset since we need to put those after the dex file. Table offsets are relative
+ // to the start of the quicken info section.
+ out_table_offsets_->push_back(current_offset);
+
+ const uint32_t length = table_data.size() * sizeof(table_data.front());
+ if (!out_->WriteFully(table_data.data(), length)) {
+ PLOG(ERROR) << "Failed to write quickening offset table for " << dex_file->GetLocation()
+ << " to " << out_->GetLocation();
+ return false;
}
+ written_bytes_ += length;
}
return true;
}
@@ -2735,14 +2737,16 @@ class OatWriter::WriteQuickeningIndicesMethodVisitor {
private:
OutputStream* const out_;
- const uint32_t quickening_info_bytes_;
- size_t written_bytes_;
- // Maps quickening map to its offset in the file.
- const SafeMap<const uint8_t*, uint32_t>& offset_map_;
+ const uint32_t start_offset_;
+ size_t written_bytes_ = 0u;
+ // Maps containing the offsets for the tables.
+ SafeMap<const DexFile*, std::vector<uint32_t>>* const quicken_info_offset_indices_;
+ std::vector<uint32_t>* const out_table_offsets_;
};
bool OatWriter::WriteQuickeningInfo(OutputStream* vdex_out) {
size_t initial_offset = vdex_size_;
+ // Make sure the table is properly aligned.
size_t start_offset = RoundUp(initial_offset, 4u);
off_t actual_offset = vdex_out->Seek(start_offset, kSeekSet);
@@ -2753,36 +2757,71 @@ bool OatWriter::WriteQuickeningInfo(OutputStream* vdex_out) {
return false;
}
- if (compiler_driver_->GetCompilerOptions().IsAnyCompilationEnabled()) {
+ size_t current_offset = start_offset;
+ if (compiler_driver_->GetCompilerOptions().IsQuickeningCompilationEnabled()) {
std::vector<uint32_t> dex_files_indices;
- SafeMap<const uint8_t*, uint32_t> offset_map;
- WriteQuickeningInfoMethodVisitor visitor1(this, vdex_out, start_offset, &offset_map);
- if (!VisitDexMethods(&visitor1)) {
+ WriteQuickeningInfoMethodVisitor write_quicken_info_visitor(this, vdex_out);
+ if (!write_quicken_info_visitor.VisitDexMethods(*dex_files_)) {
PLOG(ERROR) << "Failed to write the vdex quickening info. File: " << vdex_out->GetLocation();
return false;
}
- if (visitor1.GetNumberOfWrittenBytes() > 0) {
- WriteQuickeningIndicesMethodVisitor visitor2(vdex_out,
- visitor1.GetNumberOfWrittenBytes(),
- offset_map);
- if (!visitor2.VisitDexMethods(*dex_files_, *compiler_driver_)) {
- PLOG(ERROR) << "Failed to write the vdex quickening info. File: "
- << vdex_out->GetLocation();
+ uint32_t quicken_info_offset = write_quicken_info_visitor.GetNumberOfWrittenBytes();
+ current_offset = current_offset + quicken_info_offset;
+ uint32_t before_offset = current_offset;
+ current_offset = RoundUp(current_offset, QuickenInfoOffsetTableAccessor::Alignment());
+ const size_t extra_bytes = current_offset - before_offset;
+ quicken_info_offset += extra_bytes;
+ actual_offset = vdex_out->Seek(current_offset, kSeekSet);
+ if (actual_offset != static_cast<off_t>(current_offset)) {
+ PLOG(ERROR) << "Failed to seek to quickening offset table section. Actual: " << actual_offset
+ << " Expected: " << current_offset
+ << " Output: " << vdex_out->GetLocation();
+ return false;
+ }
+
+ std::vector<uint32_t> table_offsets;
+ WriteQuickeningInfoOffsetsMethodVisitor table_visitor(
+ vdex_out,
+ quicken_info_offset,
+ &write_quicken_info_visitor.GetQuickenInfoOffsetIndicies(),
+ /*out*/ &table_offsets);
+ if (!table_visitor.VisitDexMethods(*dex_files_)) {
+ PLOG(ERROR) << "Failed to write the vdex quickening info. File: "
+ << vdex_out->GetLocation();
+ return false;
+ }
+
+ CHECK_EQ(table_offsets.size(), dex_files_->size());
+
+ current_offset += table_visitor.GetNumberOfWrittenBytes();
+
+ // Store the offset table offset as a preheader for each dex.
+ size_t index = 0;
+ for (const OatDexFile& oat_dex_file : oat_dex_files_) {
+ const off_t desired_offset = oat_dex_file.dex_file_offset_ -
+ sizeof(VdexFile::QuickeningTableOffsetType);
+ actual_offset = vdex_out->Seek(desired_offset, kSeekSet);
+ if (actual_offset != desired_offset) {
+ PLOG(ERROR) << "Failed to seek to before dex file for writing offset table offset: "
+ << actual_offset << " Expected: " << desired_offset
+ << " Output: " << vdex_out->GetLocation();
return false;
}
-
- if (!vdex_out->Flush()) {
- PLOG(ERROR) << "Failed to flush stream after writing quickening info."
+ uint32_t offset = table_offsets[index];
+ if (!vdex_out->WriteFully(reinterpret_cast<const uint8_t*>(&offset), sizeof(offset))) {
+ PLOG(ERROR) << "Failed to write verifier deps."
<< " File: " << vdex_out->GetLocation();
return false;
}
- size_quickening_info_ = visitor1.GetNumberOfWrittenBytes() +
- visitor2.GetNumberOfWrittenBytes();
- } else {
- // We know we did not quicken.
- size_quickening_info_ = 0;
+ ++index;
}
+ if (!vdex_out->Flush()) {
+ PLOG(ERROR) << "Failed to flush stream after writing quickening info."
+ << " File: " << vdex_out->GetLocation();
+ return false;
+ }
+ size_quickening_info_ = current_offset - start_offset;
} else {
// We know we did not quicken.
size_quickening_info_ = 0;
@@ -3357,9 +3396,15 @@ bool OatWriter::SeekToDexFile(OutputStream* out, File* file, OatDexFile* oat_dex
// Dex files are required to be 4 byte aligned.
size_t initial_offset = vdex_size_;
size_t start_offset = RoundUp(initial_offset, 4);
- size_t file_offset = start_offset;
size_dex_file_alignment_ += start_offset - initial_offset;
+ // Leave extra room for the quicken offset table offset.
+ start_offset += sizeof(VdexFile::QuickeningTableOffsetType);
+ // TODO: Not count the offset as part of alignment.
+ size_dex_file_alignment_ += sizeof(VdexFile::QuickeningTableOffsetType);
+
+ size_t file_offset = start_offset;
+
// Seek to the start of the dex file and flush any pending operations in the stream.
// Verify that, after flushing the stream, the file is at the same offset as the stream.
off_t actual_offset = out->Seek(file_offset, kSeekSet);
@@ -3392,6 +3437,7 @@ bool OatWriter::LayoutAndWriteDexFile(OutputStream* out, OatDexFile* oat_dex_fil
std::string error_msg;
std::string location(oat_dex_file->GetLocation());
std::unique_ptr<const DexFile> dex_file;
+ const ArtDexFileLoader dex_file_loader;
if (oat_dex_file->source_.IsZipEntry()) {
ZipEntry* zip_entry = oat_dex_file->source_.GetZipEntry();
std::unique_ptr<MemMap> mem_map(
@@ -3400,12 +3446,12 @@ bool OatWriter::LayoutAndWriteDexFile(OutputStream* out, OatDexFile* oat_dex_fil
LOG(ERROR) << "Failed to extract dex file to mem map for layout: " << error_msg;
return false;
}
- dex_file = DexFileLoader::Open(location,
- zip_entry->GetCrc32(),
- std::move(mem_map),
- /* verify */ true,
- /* verify_checksum */ true,
- &error_msg);
+ dex_file = dex_file_loader.Open(location,
+ zip_entry->GetCrc32(),
+ std::move(mem_map),
+ /* verify */ true,
+ /* verify_checksum */ true,
+ &error_msg);
} else if (oat_dex_file->source_.IsRawFile()) {
File* raw_file = oat_dex_file->source_.GetRawFile();
int dup_fd = dup(raw_file->Fd());
@@ -3413,7 +3459,7 @@ bool OatWriter::LayoutAndWriteDexFile(OutputStream* out, OatDexFile* oat_dex_fil
PLOG(ERROR) << "Failed to dup dex file descriptor (" << raw_file->Fd() << ") at " << location;
return false;
}
- dex_file = DexFileLoader::OpenDex(
+ dex_file = dex_file_loader.OpenDex(
dup_fd, location, /* verify */ true, /* verify_checksum */ true, &error_msg);
} else {
// The source data is a vdex file.
@@ -3426,14 +3472,14 @@ bool OatWriter::LayoutAndWriteDexFile(OutputStream* out, OatDexFile* oat_dex_fil
DCHECK(ValidateDexFileHeader(raw_dex_file, oat_dex_file->GetLocation()));
const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(raw_dex_file);
// Since the source may have had its layout changed, or may be quickened, don't verify it.
- dex_file = DexFileLoader::Open(raw_dex_file,
- header->file_size_,
- location,
- oat_dex_file->dex_file_location_checksum_,
- nullptr,
- /* verify */ false,
- /* verify_checksum */ false,
- &error_msg);
+ dex_file = dex_file_loader.Open(raw_dex_file,
+ header->file_size_,
+ location,
+ oat_dex_file->dex_file_location_checksum_,
+ nullptr,
+ /* verify */ false,
+ /* verify_checksum */ false,
+ &error_msg);
}
if (dex_file == nullptr) {
LOG(ERROR) << "Failed to open dex file for layout: " << error_msg;
@@ -3653,6 +3699,7 @@ bool OatWriter::OpenDexFiles(
<< " error: " << error_msg;
return false;
}
+ const ArtDexFileLoader dex_file_loader;
std::vector<std::unique_ptr<const DexFile>> dex_files;
for (OatDexFile& oat_dex_file : oat_dex_files_) {
const uint8_t* raw_dex_file =
@@ -3674,14 +3721,14 @@ bool OatWriter::OpenDexFiles(
}
// Now, open the dex file.
- dex_files.emplace_back(DexFileLoader::Open(raw_dex_file,
- oat_dex_file.dex_file_size_,
- oat_dex_file.GetLocation(),
- oat_dex_file.dex_file_location_checksum_,
- /* oat_dex_file */ nullptr,
- verify,
- verify,
- &error_msg));
+ dex_files.emplace_back(dex_file_loader.Open(raw_dex_file,
+ oat_dex_file.dex_file_size_,
+ oat_dex_file.GetLocation(),
+ oat_dex_file.dex_file_location_checksum_,
+ /* oat_dex_file */ nullptr,
+ verify,
+ verify,
+ &error_msg));
if (dex_files.back() == nullptr) {
LOG(ERROR) << "Failed to open dex file from oat file. File: " << oat_dex_file.GetLocation()
<< " Error: " << error_msg;
@@ -3689,7 +3736,7 @@ bool OatWriter::OpenDexFiles(
}
// Set the class_offsets size now that we have easy access to the DexFile and
- // it has been verified in DexFileLoader::Open.
+ // it has been verified in dex_file_loader.Open.
oat_dex_file.class_offsets_.resize(dex_files.back()->GetHeader().class_defs_size_);
}
diff --git a/dex2oat/linker/oat_writer.h b/dex2oat/linker/oat_writer.h
index 86b114433e..ac96bb8d56 100644
--- a/dex2oat/linker/oat_writer.h
+++ b/dex2oat/linker/oat_writer.h
@@ -274,7 +274,7 @@ class OatWriter {
class WriteMapMethodVisitor;
class WriteMethodInfoVisitor;
class WriteQuickeningInfoMethodVisitor;
- class WriteQuickeningIndicesMethodVisitor;
+ class WriteQuickeningInfoOffsetsMethodVisitor;
// Visit all the methods in all the compiled dex files in their definition order
// with a given DexMethodVisitor.
diff --git a/dex2oat/linker/oat_writer_test.cc b/dex2oat/linker/oat_writer_test.cc
index 4e35382f89..c45166b17e 100644
--- a/dex2oat/linker/oat_writer_test.cc
+++ b/dex2oat/linker/oat_writer_test.cc
@@ -659,7 +659,11 @@ void OatTest::TestDexFileInput(bool verify, bool low_4gb, bool use_profile) {
ASSERT_EQ(dex_file2_data->GetLocation(), opened_dex_file2->GetLocation());
const VdexFile::Header &vdex_header = opened_oat_file->GetVdexFile()->GetHeader();
- ASSERT_EQ(vdex_header.GetQuickeningInfoSize(), 0u);
+ if (!compiler_driver_->GetCompilerOptions().IsQuickeningCompilationEnabled()) {
+ // If quickening is enabled we will always write the table since there is no special logic that
+ // checks for all methods not being quickened (not worth the complexity).
+ ASSERT_EQ(vdex_header.GetQuickeningInfoSize(), 0u);
+ }
int64_t actual_vdex_size = vdex_file.GetFile()->GetLength();
ASSERT_GE(actual_vdex_size, 0);
diff --git a/dexdump/dexdump.cc b/dexdump/dexdump.cc
index 2c98e12741..1518e1d205 100644
--- a/dexdump/dexdump.cc
+++ b/dexdump/dexdump.cc
@@ -44,6 +44,7 @@
#include "android-base/stringprintf.h"
+#include "dex/art_dex_file_loader.h"
#include "dex/code_item_accessors-no_art-inl.h"
#include "dex/dex_file-inl.h"
#include "dex/dex_file_exception_helpers.h"
@@ -1186,7 +1187,7 @@ static void dumpBytecodes(const DexFile* pDexFile, u4 idx,
*/
static void dumpCode(const DexFile* pDexFile, u4 idx, u4 flags,
const DexFile::CodeItem* pCode, u4 codeOffset) {
- CodeItemDebugInfoAccessor accessor(*pDexFile, pCode, pDexFile->GetDebugInfoOffset(pCode));
+ CodeItemDebugInfoAccessor accessor(*pDexFile, pCode, idx);
fprintf(gOutFile, " registers : %d\n", accessor.RegistersSize());
fprintf(gOutFile, " ins : %d\n", accessor.InsSize());
@@ -1879,8 +1880,10 @@ int processFile(const char* fileName) {
// all of which are Zip archives with "classes.dex" inside.
const bool kVerifyChecksum = !gOptions.ignoreBadChecksum;
std::string error_msg;
+ // TODO: Use DexFileLoader when that is implemented.
+ const ArtDexFileLoader dex_file_loader;
std::vector<std::unique_ptr<const DexFile>> dex_files;
- if (!DexFileLoader::Open(
+ if (!dex_file_loader.Open(
fileName, fileName, /* verify */ true, kVerifyChecksum, &error_msg, &dex_files)) {
// Display returned error message to user. Note that this error behavior
// differs from the error messages shown by the original Dalvik dexdump.
diff --git a/dexlayout/Android.bp b/dexlayout/Android.bp
index a02f75ad00..4f5d81095f 100644
--- a/dexlayout/Android.bp
+++ b/dexlayout/Android.bp
@@ -34,6 +34,13 @@ art_cc_library {
name: "libart-dexlayout",
defaults: ["libart-dexlayout-defaults"],
shared_libs: ["libart"],
+
+ pgo: {
+ instrumentation: true,
+ profile_file: "dex2oat.profdata",
+ benchmarks: ["dex2oat"],
+ enable_profile_use: false,
+ }
}
art_cc_library {
diff --git a/dexlayout/compact_dex_writer.cc b/dexlayout/compact_dex_writer.cc
index 1c5b16d84b..d1dc6587c0 100644
--- a/dexlayout/compact_dex_writer.cc
+++ b/dexlayout/compact_dex_writer.cc
@@ -16,10 +16,144 @@
#include "compact_dex_writer.h"
+#include "base/logging.h"
+#include "base/time_utils.h"
+#include "dex/compact_dex_debug_info.h"
#include "dex/compact_dex_file.h"
+#include "dexlayout.h"
namespace art {
+uint32_t CompactDexWriter::WriteDebugInfoOffsetTable(uint32_t offset) {
+ const uint32_t start_offset = offset;
+ const dex_ir::Collections& collections = header_->GetCollections();
+ // Debug offsets for method indexes. 0 means no debug info.
+ std::vector<uint32_t> debug_info_offsets(collections.MethodIdsSize(), 0u);
+
+ static constexpr InvokeType invoke_types[] = {
+ kDirect,
+ kVirtual
+ };
+
+ for (InvokeType invoke_type : invoke_types) {
+ for (const std::unique_ptr<dex_ir::ClassDef>& class_def : collections.ClassDefs()) {
+ // Skip classes that are not defined in this dex file.
+ dex_ir::ClassData* class_data = class_def->GetClassData();
+ if (class_data == nullptr) {
+ continue;
+ }
+ for (auto& method : *(invoke_type == InvokeType::kDirect
+ ? class_data->DirectMethods()
+ : class_data->VirtualMethods())) {
+ const dex_ir::MethodId* method_id = method->GetMethodId();
+ dex_ir::CodeItem* code_item = method->GetCodeItem();
+ if (code_item != nullptr && code_item->DebugInfo() != nullptr) {
+ const uint32_t debug_info_offset = code_item->DebugInfo()->GetOffset();
+ const uint32_t method_idx = method_id->GetIndex();
+ if (debug_info_offsets[method_idx] != 0u) {
+ CHECK_EQ(debug_info_offset, debug_info_offsets[method_idx]);
+ }
+ debug_info_offsets[method_idx] = debug_info_offset;
+ }
+ }
+ }
+ }
+
+ std::vector<uint8_t> data;
+ debug_info_base_ = 0u;
+ debug_info_offsets_table_offset_ = 0u;
+ CompactDexDebugInfoOffsetTable::Build(debug_info_offsets,
+ &data,
+ &debug_info_base_,
+ &debug_info_offsets_table_offset_);
+ // Align the table and write it out.
+ offset = RoundUp(offset, CompactDexDebugInfoOffsetTable::kAlignment);
+ debug_info_offsets_pos_ = offset;
+ offset += Write(data.data(), data.size(), offset);
+
+ // Verify that the whole table decodes as expected and measure average performance.
+ const bool kMeasureAndTestOutput = dex_layout_->GetOptions().verify_output_;
+ if (kMeasureAndTestOutput && !debug_info_offsets.empty()) {
+ uint64_t start_time = NanoTime();
+ CompactDexDebugInfoOffsetTable::Accessor accessor(mem_map_->Begin() + debug_info_offsets_pos_,
+ debug_info_base_,
+ debug_info_offsets_table_offset_);
+
+ for (size_t i = 0; i < debug_info_offsets.size(); ++i) {
+ CHECK_EQ(accessor.GetDebugInfoOffset(i), debug_info_offsets[i]);
+ }
+ uint64_t end_time = NanoTime();
+ VLOG(dex) << "Average lookup time (ns) for debug info offsets: "
+ << (end_time - start_time) / debug_info_offsets.size();
+ }
+
+ return offset - start_offset;
+}
+
+uint32_t CompactDexWriter::WriteCodeItem(dex_ir::CodeItem* code_item,
+ uint32_t offset,
+ bool reserve_only) {
+ DCHECK(code_item != nullptr);
+ const uint32_t start_offset = offset;
+ offset = RoundUp(offset, CompactDexFile::CodeItem::kAlignment);
+ ProcessOffset(&offset, code_item);
+
+ CompactDexFile::CodeItem disk_code_item;
+ disk_code_item.registers_size_ = code_item->RegistersSize();
+ disk_code_item.ins_size_ = code_item->InsSize();
+ disk_code_item.outs_size_ = code_item->OutsSize();
+ disk_code_item.tries_size_ = code_item->TriesSize();
+ disk_code_item.insns_size_in_code_units_ = code_item->InsnsSize();
+ // Avoid using sizeof so that we don't write the fake instruction array at the end of the code
+ // item.
+ offset += Write(&disk_code_item,
+ OFFSETOF_MEMBER(CompactDexFile::CodeItem, insns_),
+ offset);
+ // Write the instructions.
+ offset += Write(code_item->Insns(), code_item->InsnsSize() * sizeof(uint16_t), offset);
+ // Write the post instruction data.
+ offset += WriteCodeItemPostInstructionData(code_item, offset, reserve_only);
+ return offset - start_offset;
+}
+
+void CompactDexWriter::SortDebugInfosByMethodIndex() {
+ dex_ir::Collections& collections = header_->GetCollections();
+ static constexpr InvokeType invoke_types[] = {
+ kDirect,
+ kVirtual
+ };
+ std::map<const dex_ir::DebugInfoItem*, uint32_t> method_idx_map;
+ for (InvokeType invoke_type : invoke_types) {
+ for (std::unique_ptr<dex_ir::ClassDef>& class_def : collections.ClassDefs()) {
+ // Skip classes that are not defined in this dex file.
+ dex_ir::ClassData* class_data = class_def->GetClassData();
+ if (class_data == nullptr) {
+ continue;
+ }
+ for (auto& method : *(invoke_type == InvokeType::kDirect
+ ? class_data->DirectMethods()
+ : class_data->VirtualMethods())) {
+ const dex_ir::MethodId* method_id = method->GetMethodId();
+ dex_ir::CodeItem* code_item = method->GetCodeItem();
+ if (code_item != nullptr && code_item->DebugInfo() != nullptr) {
+ const dex_ir::DebugInfoItem* debug_item = code_item->DebugInfo();
+ method_idx_map.insert(std::make_pair(debug_item, method_id->GetIndex()));
+ }
+ }
+ }
+ }
+ std::sort(collections.DebugInfoItems().begin(),
+ collections.DebugInfoItems().end(),
+ [&](const std::unique_ptr<dex_ir::DebugInfoItem>& a,
+ const std::unique_ptr<dex_ir::DebugInfoItem>& b) {
+ auto it_a = method_idx_map.find(a.get());
+ auto it_b = method_idx_map.find(b.get());
+ uint32_t idx_a = it_a != method_idx_map.end() ? it_a->second : 0u;
+ uint32_t idx_b = it_b != method_idx_map.end() ? it_b->second : 0u;
+ return idx_a < idx_b;
+ });
+}
+
void CompactDexWriter::WriteHeader() {
CompactDexFile::Header header;
CompactDexFile::WriteMagic(&header.magic_[0]);
@@ -49,6 +183,11 @@ void CompactDexWriter::WriteHeader() {
header.class_defs_off_ = collections.ClassDefsOffset();
header.data_size_ = header_->DataSize();
header.data_off_ = header_->DataOffset();
+
+ // Compact dex specific flags.
+ header.debug_info_offsets_pos_ = debug_info_offsets_pos_;
+ header.debug_info_offsets_table_offset_ = debug_info_offsets_table_offset_;
+ header.debug_info_base_ = debug_info_base_;
header.feature_flags_ = 0u;
// In cases where apps are converted to cdex during install, maintain feature flags so that
// the verifier correctly verifies apps that aren't targetting default methods.
@@ -62,4 +201,103 @@ size_t CompactDexWriter::GetHeaderSize() const {
return sizeof(CompactDexFile::Header);
}
+void CompactDexWriter::WriteMemMap() {
+ // Starting offset is right after the header.
+ uint32_t offset = GetHeaderSize();
+
+ dex_ir::Collections& collection = header_->GetCollections();
+
+ // Based on: https://source.android.com/devices/tech/dalvik/dex-format
+ // Since the offsets may not be calculated already, the writing must be done in the correct order.
+ const uint32_t string_ids_offset = offset;
+ offset += WriteStringIds(offset, /*reserve_only*/ true);
+ offset += WriteTypeIds(offset);
+ const uint32_t proto_ids_offset = offset;
+ offset += WriteProtoIds(offset, /*reserve_only*/ true);
+ offset += WriteFieldIds(offset);
+ offset += WriteMethodIds(offset);
+ const uint32_t class_defs_offset = offset;
+ offset += WriteClassDefs(offset, /*reserve_only*/ true);
+ const uint32_t call_site_ids_offset = offset;
+ offset += WriteCallSiteIds(offset, /*reserve_only*/ true);
+ offset += WriteMethodHandles(offset);
+
+ uint32_t data_offset_ = 0u;
+ if (compute_offsets_) {
+ // Data section.
+ offset = RoundUp(offset, kDataSectionAlignment);
+ data_offset_ = offset;
+ }
+
+ // Write code item first to minimize the space required for encoded methods.
+ // For cdex, the code items don't depend on the debug info.
+ offset += WriteCodeItems(offset, /*reserve_only*/ false);
+
+ // Sort the debug infos by method index order, this reduces size by ~0.1% by reducing the size of
+ // the debug info offset table.
+ SortDebugInfosByMethodIndex();
+ offset += WriteDebugInfoItems(offset);
+
+ offset += WriteEncodedArrays(offset);
+ offset += WriteAnnotations(offset);
+ offset += WriteAnnotationSets(offset);
+ offset += WriteAnnotationSetRefs(offset);
+ offset += WriteAnnotationsDirectories(offset);
+ offset += WriteTypeLists(offset);
+ offset += WriteClassDatas(offset);
+ offset += WriteStringDatas(offset);
+
+ // Write delayed id sections that depend on data sections.
+ WriteStringIds(string_ids_offset, /*reserve_only*/ false);
+ WriteProtoIds(proto_ids_offset, /*reserve_only*/ false);
+ WriteClassDefs(class_defs_offset, /*reserve_only*/ false);
+ WriteCallSiteIds(call_site_ids_offset, /*reserve_only*/ false);
+
+ // Write the map list.
+ if (compute_offsets_) {
+ offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeMapList));
+ collection.SetMapListOffset(offset);
+ } else {
+ offset = collection.MapListOffset();
+ }
+ offset += GenerateAndWriteMapItems(offset);
+ offset = RoundUp(offset, kDataSectionAlignment);
+
+ // Map items are included in the data section.
+ if (compute_offsets_) {
+ header_->SetDataSize(offset - data_offset_);
+ if (header_->DataSize() != 0) {
+ // Offset must be zero when the size is zero.
+ header_->SetDataOffset(data_offset_);
+ } else {
+ header_->SetDataOffset(0u);
+ }
+ }
+
+ // Write link data if it exists.
+ const std::vector<uint8_t>& link_data = collection.LinkData();
+ if (link_data.size() > 0) {
+ CHECK_EQ(header_->LinkSize(), static_cast<uint32_t>(link_data.size()));
+ if (compute_offsets_) {
+ header_->SetLinkOffset(offset);
+ }
+ offset += Write(&link_data[0], link_data.size(), header_->LinkOffset());
+ }
+
+ // Write debug info offset table last to make dex file verifier happy.
+ offset += WriteDebugInfoOffsetTable(offset);
+
+ // Write header last.
+ if (compute_offsets_) {
+ header_->SetFileSize(offset);
+ }
+ WriteHeader();
+
+ if (dex_layout_->GetOptions().update_checksum_) {
+ header_->SetChecksum(DexFile::CalculateChecksum(mem_map_->Begin(), offset));
+ // Rewrite the header with the calculated checksum.
+ WriteHeader();
+ }
+}
+
} // namespace art
diff --git a/dexlayout/compact_dex_writer.h b/dexlayout/compact_dex_writer.h
index d13333bb18..37f6ff11a0 100644
--- a/dexlayout/compact_dex_writer.h
+++ b/dexlayout/compact_dex_writer.h
@@ -33,13 +33,30 @@ class CompactDexWriter : public DexWriter {
compact_dex_level_(compact_dex_level) {}
protected:
+ void WriteMemMap() OVERRIDE;
+
void WriteHeader() OVERRIDE;
size_t GetHeaderSize() const OVERRIDE;
+ uint32_t WriteDebugInfoOffsetTable(uint32_t offset);
+
const CompactDexLevel compact_dex_level_;
+ uint32_t WriteCodeItem(dex_ir::CodeItem* code_item, uint32_t offset, bool reserve_only) OVERRIDE;
+
+ void SortDebugInfosByMethodIndex();
+
private:
+ // Position in the compact dex file for the debug info table data starts.
+ uint32_t debug_info_offsets_pos_ = 0u;
+
+ // Offset into the debug info table data where the lookup table is.
+ uint32_t debug_info_offsets_table_offset_ = 0u;
+
+ // Base offset of where debug info starts in the dex file.
+ uint32_t debug_info_base_ = 0u;
+
DISALLOW_COPY_AND_ASSIGN(CompactDexWriter);
};
diff --git a/dexlayout/dex_ir.cc b/dexlayout/dex_ir.cc
index 2191ea601f..0a59cc9ba2 100644
--- a/dexlayout/dex_ir.cc
+++ b/dexlayout/dex_ir.cc
@@ -566,8 +566,10 @@ ParameterAnnotation* Collections::GenerateParameterAnnotation(
}
CodeItem* Collections::CreateCodeItem(const DexFile& dex_file,
- const DexFile::CodeItem& disk_code_item, uint32_t offset) {
- CodeItemDebugInfoAccessor accessor(dex_file, &disk_code_item);
+ const DexFile::CodeItem& disk_code_item,
+ uint32_t offset,
+ uint32_t dex_method_index) {
+ CodeItemDebugInfoAccessor accessor(dex_file, &disk_code_item, dex_method_index);
const uint16_t registers_size = accessor.RegistersSize();
const uint16_t ins_size = accessor.InsSize();
const uint16_t outs_size = accessor.OutsSize();
@@ -705,7 +707,10 @@ MethodItem* Collections::GenerateMethodItem(const DexFile& dex_file, ClassDataIt
DebugInfoItem* debug_info = nullptr;
if (disk_code_item != nullptr) {
if (code_item == nullptr) {
- code_item = CreateCodeItem(dex_file, *disk_code_item, cdii.GetMethodCodeItemOffset());
+ code_item = CreateCodeItem(dex_file,
+ *disk_code_item,
+ cdii.GetMethodCodeItemOffset(),
+ cdii.GetMemberIndex());
}
debug_info = code_item->DebugInfo();
}
diff --git a/dexlayout/dex_ir.h b/dexlayout/dex_ir.h
index 6797fa5dd6..ca47b348f1 100644
--- a/dexlayout/dex_ir.h
+++ b/dexlayout/dex_ir.h
@@ -133,6 +133,7 @@ template<class T> class CollectionVector : public CollectionBase<T> {
uint32_t Size() const { return collection_.size(); }
Vector& Collection() { return collection_; }
+ const Vector& Collection() const { return collection_; }
protected:
Vector collection_;
@@ -230,6 +231,8 @@ class Collections {
CollectionVector<CodeItem>::Vector& CodeItems() { return code_items_.Collection(); }
CollectionVector<ClassData>::Vector& ClassDatas() { return class_datas_.Collection(); }
+ const CollectionVector<ClassDef>::Vector& ClassDefs() const { return class_defs_.Collection(); }
+
void CreateStringId(const DexFile& dex_file, uint32_t i);
void CreateTypeId(const DexFile& dex_file, uint32_t i);
void CreateProtoId(const DexFile& dex_file, uint32_t i);
@@ -251,8 +254,10 @@ class Collections {
const DexFile::AnnotationSetItem* disk_annotations_item, uint32_t offset);
AnnotationsDirectoryItem* CreateAnnotationsDirectoryItem(const DexFile& dex_file,
const DexFile::AnnotationsDirectoryItem* disk_annotations_item, uint32_t offset);
- CodeItem* CreateCodeItem(
- const DexFile& dex_file, const DexFile::CodeItem& disk_code_item, uint32_t offset);
+ CodeItem* CreateCodeItem(const DexFile& dex_file,
+ const DexFile::CodeItem& disk_code_item,
+ uint32_t offset,
+ uint32_t dex_method_index);
ClassData* CreateClassData(const DexFile& dex_file, const uint8_t* encoded_data, uint32_t offset);
void AddAnnotationsFromMapListSection(const DexFile& dex_file,
uint32_t start_offset,
diff --git a/dexlayout/dex_writer.cc b/dexlayout/dex_writer.cc
index 489a6b15ba..6e1cb62f0b 100644
--- a/dexlayout/dex_writer.cc
+++ b/dexlayout/dex_writer.cc
@@ -30,25 +30,6 @@
namespace art {
-static constexpr uint32_t kDataSectionAlignment = sizeof(uint32_t) * 2;
-static constexpr uint32_t kDexSectionWordAlignment = 4;
-
-static constexpr uint32_t SectionAlignment(DexFile::MapItemType type) {
- switch (type) {
- case DexFile::kDexTypeClassDataItem:
- case DexFile::kDexTypeStringDataItem:
- case DexFile::kDexTypeDebugInfoItem:
- case DexFile::kDexTypeAnnotationItem:
- case DexFile::kDexTypeEncodedArrayItem:
- return alignof(uint8_t);
-
- default:
- // All other sections are kDexAlignedSection.
- return kDexSectionWordAlignment;
- }
-}
-
-
size_t EncodeIntValue(int32_t value, uint8_t* buffer) {
size_t length = 0;
if (value >= 0) {
@@ -526,69 +507,96 @@ uint32_t DexWriter::WriteDebugInfoItems(uint32_t offset) {
return offset - start;
}
+uint32_t DexWriter::WriteCodeItemPostInstructionData(dex_ir::CodeItem* code_item,
+ uint32_t offset,
+ bool reserve_only) {
+ const uint32_t start_offset = offset;
+ if (code_item->TriesSize() != 0) {
+ // Make sure the try items are properly aligned.
+ offset = RoundUp(offset, kDexTryItemAlignment);
+ // Write try items.
+ for (std::unique_ptr<const dex_ir::TryItem>& try_item : *code_item->Tries()) {
+ DexFile::TryItem disk_try_item;
+ if (!reserve_only) {
+ disk_try_item.start_addr_ = try_item->StartAddr();
+ disk_try_item.insn_count_ = try_item->InsnCount();
+ disk_try_item.handler_off_ = try_item->GetHandlers()->GetListOffset();
+ }
+ offset += Write(&disk_try_item, sizeof(disk_try_item), offset);
+ }
+ size_t max_offset = offset;
+ // Leave offset pointing to the end of the try items.
+ UNUSED(WriteUleb128(code_item->Handlers()->size(), offset));
+ for (std::unique_ptr<const dex_ir::CatchHandler>& handlers : *code_item->Handlers()) {
+ size_t list_offset = offset + handlers->GetListOffset();
+ uint32_t size = handlers->HasCatchAll() ? (handlers->GetHandlers()->size() - 1) * -1 :
+ handlers->GetHandlers()->size();
+ list_offset += WriteSleb128(size, list_offset);
+ for (std::unique_ptr<const dex_ir::TypeAddrPair>& handler : *handlers->GetHandlers()) {
+ if (handler->GetTypeId() != nullptr) {
+ list_offset += WriteUleb128(handler->GetTypeId()->GetIndex(), list_offset);
+ }
+ list_offset += WriteUleb128(handler->GetAddress(), list_offset);
+ }
+ // TODO: Clean this up to write the handlers in address order.
+ max_offset = std::max(max_offset, list_offset);
+ }
+ offset = max_offset;
+ }
+
+ return offset - start_offset;
+}
+
+uint32_t DexWriter::WriteCodeItem(dex_ir::CodeItem* code_item,
+ uint32_t offset,
+ bool reserve_only) {
+ DCHECK(code_item != nullptr);
+ const uint32_t start_offset = offset;
+ offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeCodeItem));
+ ProcessOffset(&offset, code_item);
+
+ StandardDexFile::CodeItem disk_code_item;
+ if (!reserve_only) {
+ disk_code_item.registers_size_ = code_item->RegistersSize();
+ disk_code_item.ins_size_ = code_item->InsSize();
+ disk_code_item.outs_size_ = code_item->OutsSize();
+ disk_code_item.tries_size_ = code_item->TriesSize();
+ disk_code_item.debug_info_off_ = code_item->DebugInfo() == nullptr
+ ? 0
+ : code_item->DebugInfo()->GetOffset();
+ disk_code_item.insns_size_in_code_units_ = code_item->InsnsSize();
+ }
+ // Avoid using sizeof so that we don't write the fake instruction array at the end of the code
+ // item.
+ offset += Write(&disk_code_item,
+ OFFSETOF_MEMBER(StandardDexFile::CodeItem, insns_),
+ offset);
+ // Write the instructions.
+ offset += Write(code_item->Insns(), code_item->InsnsSize() * sizeof(uint16_t), offset);
+ // Write the post instruction data.
+ offset += WriteCodeItemPostInstructionData(code_item, offset, reserve_only);
+ return offset - start_offset;
+}
+
uint32_t DexWriter::WriteCodeItems(uint32_t offset, bool reserve_only) {
DexLayoutSection* code_section = nullptr;
if (!reserve_only && dex_layout_ != nullptr) {
code_section = &dex_layout_->GetSections().sections_[static_cast<size_t>(
DexLayoutSections::SectionType::kSectionTypeCode)];
}
- uint16_t uint16_buffer[4] = {};
- uint32_t uint32_buffer[2] = {};
uint32_t start = offset;
for (auto& code_item : header_->GetCollections().CodeItems()) {
- offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeCodeItem));
- ProcessOffset(&offset, code_item.get());
- if (!reserve_only) {
- uint16_buffer[0] = code_item->RegistersSize();
- uint16_buffer[1] = code_item->InsSize();
- uint16_buffer[2] = code_item->OutsSize();
- uint16_buffer[3] = code_item->TriesSize();
- uint32_buffer[0] = code_item->DebugInfo() == nullptr ? 0 :
- code_item->DebugInfo()->GetOffset();
- uint32_buffer[1] = code_item->InsnsSize();
- // Only add the section hotness info once.
- if (code_section != nullptr) {
- auto it = dex_layout_->LayoutHotnessInfo().code_item_layout_.find(code_item.get());
- if (it != dex_layout_->LayoutHotnessInfo().code_item_layout_.end()) {
- code_section->parts_[static_cast<size_t>(it->second)].CombineSection(
- code_item->GetOffset(), code_item->GetOffset() + code_item->GetSize());
- }
- }
- }
- offset += Write(uint16_buffer, 4 * sizeof(uint16_t), offset);
- offset += Write(uint32_buffer, 2 * sizeof(uint32_t), offset);
- offset += Write(code_item->Insns(), code_item->InsnsSize() * sizeof(uint16_t), offset);
- if (code_item->TriesSize() != 0) {
- if (code_item->InsnsSize() % 2 != 0) {
- uint16_t padding[1] = { 0 };
- offset += Write(padding, sizeof(uint16_t), offset);
- }
- uint32_t start_addr[1];
- uint16_t insn_count_and_handler_off[2];
- for (std::unique_ptr<const dex_ir::TryItem>& try_item : *code_item->Tries()) {
- start_addr[0] = try_item->StartAddr();
- insn_count_and_handler_off[0] = try_item->InsnCount();
- insn_count_and_handler_off[1] = try_item->GetHandlers()->GetListOffset();
- offset += Write(start_addr, sizeof(uint32_t), offset);
- offset += Write(insn_count_and_handler_off, 2 * sizeof(uint16_t), offset);
- }
- // Leave offset pointing to the end of the try items.
- UNUSED(WriteUleb128(code_item->Handlers()->size(), offset));
- for (std::unique_ptr<const dex_ir::CatchHandler>& handlers : *code_item->Handlers()) {
- size_t list_offset = offset + handlers->GetListOffset();
- uint32_t size = handlers->HasCatchAll() ? (handlers->GetHandlers()->size() - 1) * -1 :
- handlers->GetHandlers()->size();
- list_offset += WriteSleb128(size, list_offset);
- for (std::unique_ptr<const dex_ir::TypeAddrPair>& handler : *handlers->GetHandlers()) {
- if (handler->GetTypeId() != nullptr) {
- list_offset += WriteUleb128(handler->GetTypeId()->GetIndex(), list_offset);
- }
- list_offset += WriteUleb128(handler->GetAddress(), list_offset);
- }
+ const size_t code_item_size = WriteCodeItem(code_item.get(), offset, reserve_only);
+ // Only add the section hotness info once.
+ if (!reserve_only && code_section != nullptr) {
+ auto it = dex_layout_->LayoutHotnessInfo().code_item_layout_.find(code_item.get());
+ if (it != dex_layout_->LayoutHotnessInfo().code_item_layout_.end()) {
+ code_section->parts_[static_cast<size_t>(it->second)].CombineSection(
+ offset,
+ offset + code_item_size);
}
}
- // TODO: Clean this up to properly calculate the size instead of assuming it doesn't change.
- offset = code_item->GetOffset() + code_item->GetSize();
+ offset += code_item_size;
}
if (compute_offsets_ && start != offset) {
diff --git a/dexlayout/dex_writer.h b/dexlayout/dex_writer.h
index 92a002edc7..fdeb299aa4 100644
--- a/dexlayout/dex_writer.h
+++ b/dexlayout/dex_writer.h
@@ -23,6 +23,7 @@
#include "base/unix_file/fd_file.h"
#include "dex/compact_dex_level.h"
+#include "dex/dex_file.h"
#include "dex_ir.h"
#include "mem_map.h"
#include "os.h"
@@ -59,6 +60,25 @@ class MapItemQueue : public
class DexWriter {
public:
+ static constexpr uint32_t kDataSectionAlignment = sizeof(uint32_t) * 2;
+ static constexpr uint32_t kDexSectionWordAlignment = 4;
+ static constexpr uint32_t kDexTryItemAlignment = sizeof(uint32_t);
+
+ static inline constexpr uint32_t SectionAlignment(DexFile::MapItemType type) {
+ switch (type) {
+ case DexFile::kDexTypeClassDataItem:
+ case DexFile::kDexTypeStringDataItem:
+ case DexFile::kDexTypeDebugInfoItem:
+ case DexFile::kDexTypeAnnotationItem:
+ case DexFile::kDexTypeEncodedArrayItem:
+ return alignof(uint8_t);
+
+ default:
+ // All other sections are kDexAlignedSection.
+ return DexWriter::kDexSectionWordAlignment;
+ }
+ }
+
DexWriter(dex_ir::Header* header,
MemMap* mem_map,
DexLayout* dex_layout,
@@ -77,7 +97,7 @@ class DexWriter {
virtual ~DexWriter() {}
protected:
- void WriteMemMap();
+ virtual void WriteMemMap();
size_t Write(const void* buffer, size_t length, size_t offset) WARN_UNUSED;
size_t WriteSleb128(uint32_t value, size_t offset) WARN_UNUSED;
@@ -118,6 +138,11 @@ class DexWriter {
uint32_t WriteMapItems(uint32_t offset, MapItemQueue* queue);
uint32_t GenerateAndWriteMapItems(uint32_t offset);
+ virtual uint32_t WriteCodeItemPostInstructionData(dex_ir::CodeItem* item,
+ uint32_t offset,
+ bool reserve_only);
+ virtual uint32_t WriteCodeItem(dex_ir::CodeItem* item, uint32_t offset, bool reserve_only);
+
// Process an offset, if compute_offset is set, write into the dex ir item, otherwise read the
// existing offset and use that for writing.
void ProcessOffset(uint32_t* const offset, dex_ir::Item* item) {
diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc
index 000d1356b9..a43dd074f8 100644
--- a/dexlayout/dexlayout.cc
+++ b/dexlayout/dexlayout.cc
@@ -34,6 +34,7 @@
#include "android-base/stringprintf.h"
#include "base/logging.h" // For VLOG_IS_ON.
+#include "dex/art_dex_file_loader.h"
#include "dex/dex_file-inl.h"
#include "dex/dex_file_layout.h"
#include "dex/dex_file_loader.h"
@@ -1923,14 +1924,16 @@ void DexLayout::ProcessDexFile(const char* file_name,
if (options_.verify_output_) {
std::string error_msg;
std::string location = "memory mapped file for " + std::string(file_name);
- std::unique_ptr<const DexFile> output_dex_file(DexFileLoader::Open(mem_map_->Begin(),
- file_size,
- location,
- /* checksum */ 0,
- /*oat_dex_file*/ nullptr,
- /*verify*/ true,
- /*verify_checksum*/ false,
- &error_msg));
+ const ArtDexFileLoader dex_file_loader;
+ std::unique_ptr<const DexFile> output_dex_file(
+ dex_file_loader.Open(mem_map_->Begin(),
+ file_size,
+ location,
+ /* checksum */ 0,
+ /*oat_dex_file*/ nullptr,
+ /*verify*/ true,
+ /*verify_checksum*/ false,
+ &error_msg));
CHECK(output_dex_file != nullptr) << "Failed to re-open output file:" << error_msg;
// Do IR-level comparison between input and output. This check ignores potential differences
@@ -1961,8 +1964,9 @@ int DexLayout::ProcessFile(const char* file_name) {
// all of which are Zip archives with "classes.dex" inside.
const bool verify_checksum = !options_.ignore_bad_checksum_;
std::string error_msg;
+ const ArtDexFileLoader dex_file_loader;
std::vector<std::unique_ptr<const DexFile>> dex_files;
- if (!DexFileLoader::Open(
+ if (!dex_file_loader.Open(
file_name, file_name, /* verify */ true, verify_checksum, &error_msg, &dex_files)) {
// Display returned error message to user. Note that this error behavior
// differs from the error messages shown by the original Dalvik dexdump.
diff --git a/dexlayout/dexlayout_test.cc b/dexlayout/dexlayout_test.cc
index 5da3b1d366..3a7f9eeda6 100644
--- a/dexlayout/dexlayout_test.cc
+++ b/dexlayout/dexlayout_test.cc
@@ -23,6 +23,7 @@
#include "base/unix_file/fd_file.h"
#include "common_runtime_test.h"
+#include "dex/art_dex_file_loader.h"
#include "dex/code_item_accessors-inl.h"
#include "dex/dex_file-inl.h"
#include "dex/dex_file_loader.h"
@@ -318,12 +319,13 @@ class DexLayoutTest : public CommonRuntimeTest {
bool MutateDexFile(File* output_dex, const std::string& input_jar, const Mutator& mutator) {
std::vector<std::unique_ptr<const DexFile>> dex_files;
std::string error_msg;
- CHECK(DexFileLoader::Open(input_jar.c_str(),
- input_jar.c_str(),
- /*verify*/ true,
- /*verify_checksum*/ true,
- &error_msg,
- &dex_files)) << error_msg;
+ const ArtDexFileLoader dex_file_loader;
+ CHECK(dex_file_loader.Open(input_jar.c_str(),
+ input_jar.c_str(),
+ /*verify*/ true,
+ /*verify_checksum*/ true,
+ &error_msg,
+ &dex_files)) << error_msg;
EXPECT_EQ(dex_files.size(), 1u) << "Only one input dex is supported";
for (const std::unique_ptr<const DexFile>& dex : dex_files) {
CHECK(dex->EnableWrite()) << "Failed to enable write";
@@ -344,12 +346,13 @@ class DexLayoutTest : public CommonRuntimeTest {
const std::string& dex_location) {
std::vector<std::unique_ptr<const DexFile>> dex_files;
std::string error_msg;
- bool result = DexFileLoader::Open(input_dex.c_str(),
- input_dex,
- /*verify*/ true,
- /*verify_checksum*/ false,
- &error_msg,
- &dex_files);
+ const ArtDexFileLoader dex_file_loader;
+ bool result = dex_file_loader.Open(input_dex.c_str(),
+ input_dex,
+ /*verify*/ true,
+ /*verify_checksum*/ false,
+ &error_msg,
+ &dex_files);
ASSERT_TRUE(result) << error_msg;
ASSERT_GE(dex_files.size(), 1u);
diff --git a/dexlist/dexlist.cc b/dexlist/dexlist.cc
index 556938b563..1ced8ca771 100644
--- a/dexlist/dexlist.cc
+++ b/dexlist/dexlist.cc
@@ -27,6 +27,7 @@
#include <stdlib.h>
#include "base/logging.h" // For InitLogging.
+#include "dex/art_dex_file_loader.h"
#include "dex/code_item_accessors-no_art-inl.h"
#include "dex/dex_file-inl.h"
#include "dex/dex_file_loader.h"
@@ -100,7 +101,7 @@ static void dumpMethod(const DexFile* pDexFile,
if (pCode == nullptr || codeOffset == 0) {
return;
}
- CodeItemDebugInfoAccessor accessor(*pDexFile, pCode, pDexFile->GetDebugInfoOffset(pCode));
+ CodeItemDebugInfoAccessor accessor(*pDexFile, pCode, idx);
// Method information.
const DexFile::MethodId& pMethodId = pDexFile->GetMethodId(idx);
@@ -174,7 +175,8 @@ static int processFile(const char* fileName) {
static constexpr bool kVerifyChecksum = true;
std::string error_msg;
std::vector<std::unique_ptr<const DexFile>> dex_files;
- if (!DexFileLoader::Open(
+ const ArtDexFileLoader dex_file_loader;
+ if (!dex_file_loader.Open(
fileName, fileName, /* verify */ true, kVerifyChecksum, &error_msg, &dex_files)) {
fputs(error_msg.c_str(), stderr);
fputc('\n', stderr);
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index d2b1c66d72..2b90614b93 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -724,7 +724,6 @@ class OatDumper {
}
vdex_file->Unquicken(MakeNonOwningPointerVector(tmp_dex_files),
- vdex_file->GetQuickeningInfo(),
/* decompile_return_instruction */ true);
*dex_files = std::move(tmp_dex_files);
diff --git a/openjdkjvmti/OpenjdkJvmTi.cc b/openjdkjvmti/OpenjdkJvmTi.cc
index aae805569f..027635bbb5 100644
--- a/openjdkjvmti/OpenjdkJvmTi.cc
+++ b/openjdkjvmti/OpenjdkJvmTi.cc
@@ -83,6 +83,12 @@ DeoptManager gDeoptManager;
} \
} while (false)
+// Returns whether we are able to use all jvmti features.
+static bool IsFullJvmtiAvailable() {
+ art::Runtime* runtime = art::Runtime::Current();
+ return runtime->GetInstrumentation()->IsForcedInterpretOnly() || runtime->IsJavaDebuggable();
+}
+
class JvmtiFunctions {
private:
static jvmtiError getEnvironmentError(jvmtiEnv* env) {
@@ -1092,10 +1098,64 @@ class JvmtiFunctions {
&gEventHandler);
}
+#define FOR_ALL_CAPABILITIES(FUN) \
+ FUN(can_tag_objects) \
+ FUN(can_generate_field_modification_events) \
+ FUN(can_generate_field_access_events) \
+ FUN(can_get_bytecodes) \
+ FUN(can_get_synthetic_attribute) \
+ FUN(can_get_owned_monitor_info) \
+ FUN(can_get_current_contended_monitor) \
+ FUN(can_get_monitor_info) \
+ FUN(can_pop_frame) \
+ FUN(can_redefine_classes) \
+ FUN(can_signal_thread) \
+ FUN(can_get_source_file_name) \
+ FUN(can_get_line_numbers) \
+ FUN(can_get_source_debug_extension) \
+ FUN(can_access_local_variables) \
+ FUN(can_maintain_original_method_order) \
+ FUN(can_generate_single_step_events) \
+ FUN(can_generate_exception_events) \
+ FUN(can_generate_frame_pop_events) \
+ FUN(can_generate_breakpoint_events) \
+ FUN(can_suspend) \
+ FUN(can_redefine_any_class) \
+ FUN(can_get_current_thread_cpu_time) \
+ FUN(can_get_thread_cpu_time) \
+ FUN(can_generate_method_entry_events) \
+ FUN(can_generate_method_exit_events) \
+ FUN(can_generate_all_class_hook_events) \
+ FUN(can_generate_compiled_method_load_events) \
+ FUN(can_generate_monitor_events) \
+ FUN(can_generate_vm_object_alloc_events) \
+ FUN(can_generate_native_method_bind_events) \
+ FUN(can_generate_garbage_collection_events) \
+ FUN(can_generate_object_free_events) \
+ FUN(can_force_early_return) \
+ FUN(can_get_owned_monitor_stack_depth_info) \
+ FUN(can_get_constant_pool) \
+ FUN(can_set_native_method_prefix) \
+ FUN(can_retransform_classes) \
+ FUN(can_retransform_any_class) \
+ FUN(can_generate_resource_exhaustion_heap_events) \
+ FUN(can_generate_resource_exhaustion_threads_events)
+
static jvmtiError GetPotentialCapabilities(jvmtiEnv* env, jvmtiCapabilities* capabilities_ptr) {
ENSURE_VALID_ENV(env);
ENSURE_NON_NULL(capabilities_ptr);
*capabilities_ptr = kPotentialCapabilities;
+ if (UNLIKELY(!IsFullJvmtiAvailable())) {
+#define REMOVE_NONDEBUGGABLE_UNSUPPORTED(e) \
+ do { \
+ if (kNonDebuggableUnsupportedCapabilities.e == 1) { \
+ capabilities_ptr->e = 0; \
+ } \
+ } while (false);
+
+ FOR_ALL_CAPABILITIES(REMOVE_NONDEBUGGABLE_UNSUPPORTED);
+#undef REMOVE_NONDEBUGGABLE_UNSUPPORTED
+ }
return OK;
}
@@ -1122,49 +1182,9 @@ class JvmtiFunctions {
ret = ERR(NOT_AVAILABLE); \
} \
} \
- } while (false)
-
- ADD_CAPABILITY(can_tag_objects);
- ADD_CAPABILITY(can_generate_field_modification_events);
- ADD_CAPABILITY(can_generate_field_access_events);
- ADD_CAPABILITY(can_get_bytecodes);
- ADD_CAPABILITY(can_get_synthetic_attribute);
- ADD_CAPABILITY(can_get_owned_monitor_info);
- ADD_CAPABILITY(can_get_current_contended_monitor);
- ADD_CAPABILITY(can_get_monitor_info);
- ADD_CAPABILITY(can_pop_frame);
- ADD_CAPABILITY(can_redefine_classes);
- ADD_CAPABILITY(can_signal_thread);
- ADD_CAPABILITY(can_get_source_file_name);
- ADD_CAPABILITY(can_get_line_numbers);
- ADD_CAPABILITY(can_get_source_debug_extension);
- ADD_CAPABILITY(can_access_local_variables);
- ADD_CAPABILITY(can_maintain_original_method_order);
- ADD_CAPABILITY(can_generate_single_step_events);
- ADD_CAPABILITY(can_generate_exception_events);
- ADD_CAPABILITY(can_generate_frame_pop_events);
- ADD_CAPABILITY(can_generate_breakpoint_events);
- ADD_CAPABILITY(can_suspend);
- ADD_CAPABILITY(can_redefine_any_class);
- ADD_CAPABILITY(can_get_current_thread_cpu_time);
- ADD_CAPABILITY(can_get_thread_cpu_time);
- ADD_CAPABILITY(can_generate_method_entry_events);
- ADD_CAPABILITY(can_generate_method_exit_events);
- ADD_CAPABILITY(can_generate_all_class_hook_events);
- ADD_CAPABILITY(can_generate_compiled_method_load_events);
- ADD_CAPABILITY(can_generate_monitor_events);
- ADD_CAPABILITY(can_generate_vm_object_alloc_events);
- ADD_CAPABILITY(can_generate_native_method_bind_events);
- ADD_CAPABILITY(can_generate_garbage_collection_events);
- ADD_CAPABILITY(can_generate_object_free_events);
- ADD_CAPABILITY(can_force_early_return);
- ADD_CAPABILITY(can_get_owned_monitor_stack_depth_info);
- ADD_CAPABILITY(can_get_constant_pool);
- ADD_CAPABILITY(can_set_native_method_prefix);
- ADD_CAPABILITY(can_retransform_classes);
- ADD_CAPABILITY(can_retransform_any_class);
- ADD_CAPABILITY(can_generate_resource_exhaustion_heap_events);
- ADD_CAPABILITY(can_generate_resource_exhaustion_threads_events);
+ } while (false);
+
+ FOR_ALL_CAPABILITIES(ADD_CAPABILITY);
#undef ADD_CAPABILITY
gEventHandler.HandleChangedCapabilities(ArtJvmTiEnv::AsArtJvmTiEnv(env),
changed,
@@ -1186,49 +1206,9 @@ class JvmtiFunctions {
changed.e = 1; \
} \
} \
- } while (false)
-
- DEL_CAPABILITY(can_tag_objects);
- DEL_CAPABILITY(can_generate_field_modification_events);
- DEL_CAPABILITY(can_generate_field_access_events);
- DEL_CAPABILITY(can_get_bytecodes);
- DEL_CAPABILITY(can_get_synthetic_attribute);
- DEL_CAPABILITY(can_get_owned_monitor_info);
- DEL_CAPABILITY(can_get_current_contended_monitor);
- DEL_CAPABILITY(can_get_monitor_info);
- DEL_CAPABILITY(can_pop_frame);
- DEL_CAPABILITY(can_redefine_classes);
- DEL_CAPABILITY(can_signal_thread);
- DEL_CAPABILITY(can_get_source_file_name);
- DEL_CAPABILITY(can_get_line_numbers);
- DEL_CAPABILITY(can_get_source_debug_extension);
- DEL_CAPABILITY(can_access_local_variables);
- DEL_CAPABILITY(can_maintain_original_method_order);
- DEL_CAPABILITY(can_generate_single_step_events);
- DEL_CAPABILITY(can_generate_exception_events);
- DEL_CAPABILITY(can_generate_frame_pop_events);
- DEL_CAPABILITY(can_generate_breakpoint_events);
- DEL_CAPABILITY(can_suspend);
- DEL_CAPABILITY(can_redefine_any_class);
- DEL_CAPABILITY(can_get_current_thread_cpu_time);
- DEL_CAPABILITY(can_get_thread_cpu_time);
- DEL_CAPABILITY(can_generate_method_entry_events);
- DEL_CAPABILITY(can_generate_method_exit_events);
- DEL_CAPABILITY(can_generate_all_class_hook_events);
- DEL_CAPABILITY(can_generate_compiled_method_load_events);
- DEL_CAPABILITY(can_generate_monitor_events);
- DEL_CAPABILITY(can_generate_vm_object_alloc_events);
- DEL_CAPABILITY(can_generate_native_method_bind_events);
- DEL_CAPABILITY(can_generate_garbage_collection_events);
- DEL_CAPABILITY(can_generate_object_free_events);
- DEL_CAPABILITY(can_force_early_return);
- DEL_CAPABILITY(can_get_owned_monitor_stack_depth_info);
- DEL_CAPABILITY(can_get_constant_pool);
- DEL_CAPABILITY(can_set_native_method_prefix);
- DEL_CAPABILITY(can_retransform_classes);
- DEL_CAPABILITY(can_retransform_any_class);
- DEL_CAPABILITY(can_generate_resource_exhaustion_heap_events);
- DEL_CAPABILITY(can_generate_resource_exhaustion_threads_events);
+ } while (false);
+
+ FOR_ALL_CAPABILITIES(DEL_CAPABILITY);
#undef DEL_CAPABILITY
gEventHandler.HandleChangedCapabilities(ArtJvmTiEnv::AsArtJvmTiEnv(env),
changed,
@@ -1236,6 +1216,8 @@ class JvmtiFunctions {
return OK;
}
+#undef FOR_ALL_CAPABILITIES
+
static jvmtiError GetCapabilities(jvmtiEnv* env, jvmtiCapabilities* capabilities_ptr) {
ENSURE_VALID_ENV(env);
ENSURE_NON_NULL(capabilities_ptr);
@@ -1341,7 +1323,7 @@ class JvmtiFunctions {
static jvmtiError GetVersionNumber(jvmtiEnv* env, jint* version_ptr) {
ENSURE_VALID_ENV(env);
- *version_ptr = JVMTI_VERSION;
+ *version_ptr = ArtJvmTiEnv::AsArtJvmTiEnv(env)->ti_version;
return OK;
}
@@ -1495,9 +1477,10 @@ static bool IsJvmtiVersion(jint version) {
extern const jvmtiInterface_1 gJvmtiInterface;
-ArtJvmTiEnv::ArtJvmTiEnv(art::JavaVMExt* runtime, EventHandler* event_handler)
+ArtJvmTiEnv::ArtJvmTiEnv(art::JavaVMExt* runtime, EventHandler* event_handler, jint version)
: art_vm(runtime),
local_data(nullptr),
+ ti_version(version),
capabilities(),
event_info_mutex_("jvmtiEnv_EventInfoMutex") {
object_tag_table = std::unique_ptr<ObjectTagTable>(new ObjectTagTable(event_handler, this));
@@ -1506,8 +1489,8 @@ ArtJvmTiEnv::ArtJvmTiEnv(art::JavaVMExt* runtime, EventHandler* event_handler)
// Creates a jvmtiEnv and returns it with the art::ti::Env that is associated with it. new_art_ti
// is a pointer to the uninitialized memory for an art::ti::Env.
-static void CreateArtJvmTiEnv(art::JavaVMExt* vm, /*out*/void** new_jvmtiEnv) {
- struct ArtJvmTiEnv* env = new ArtJvmTiEnv(vm, &gEventHandler);
+static void CreateArtJvmTiEnv(art::JavaVMExt* vm, jint version, /*out*/void** new_jvmtiEnv) {
+ struct ArtJvmTiEnv* env = new ArtJvmTiEnv(vm, &gEventHandler, version);
*new_jvmtiEnv = env;
gEventHandler.RegisterArtJvmTiEnv(env);
@@ -1520,8 +1503,14 @@ static void CreateArtJvmTiEnv(art::JavaVMExt* vm, /*out*/void** new_jvmtiEnv) {
// places the return value in 'env' if this library can handle the GetEnv request. Otherwise
// returns false and does not modify the 'env' pointer.
static jint GetEnvHandler(art::JavaVMExt* vm, /*out*/void** env, jint version) {
- if (IsJvmtiVersion(version)) {
- CreateArtJvmTiEnv(vm, env);
+ // JavaDebuggable will either be set by the runtime as it is starting up or the plugin if it's
+ // loaded early enough. If this is false we cannot guarantee conformance to all JVMTI behaviors
+ // due to optimizations. We will only allow agents to get ArtTiEnvs using the kArtTiVersion.
+ if (IsFullJvmtiAvailable() && IsJvmtiVersion(version)) {
+ CreateArtJvmTiEnv(vm, JVMTI_VERSION, env);
+ return JNI_OK;
+ } else if (version == kArtTiVersion) {
+ CreateArtJvmTiEnv(vm, kArtTiVersion, env);
return JNI_OK;
} else {
printf("version 0x%x is not valid!", version);
@@ -1547,6 +1536,12 @@ extern "C" bool ArtPlugin_Initialize() {
SearchUtil::Register();
HeapUtil::Register();
+ {
+ // Make sure we can deopt anything we need to.
+ art::ScopedObjectAccess soa(art::Thread::Current());
+ gDeoptManager.FinishSetup();
+ }
+
runtime->GetJavaVM()->AddEnvironmentHook(GetEnvHandler);
return true;
diff --git a/openjdkjvmti/art_jvmti.h b/openjdkjvmti/art_jvmti.h
index 2a8c2e91df..73cc601e3e 100644
--- a/openjdkjvmti/art_jvmti.h
+++ b/openjdkjvmti/art_jvmti.h
@@ -62,10 +62,22 @@ namespace openjdkjvmti {
class ObjectTagTable;
+// A special version that we use to identify special tooling interface versions which mostly matches
+// the jvmti spec but everything is best effort. This is used to implement the userdebug
+// 'debug-anything' behavior.
+//
+// This is the value 0x70010200.
+static constexpr jint kArtTiVersion = JVMTI_VERSION_1_2 | 0x40000000;
+
// A structure that is a jvmtiEnv with additional information for the runtime.
struct ArtJvmTiEnv : public jvmtiEnv {
art::JavaVMExt* art_vm;
void* local_data;
+
+ // The ti_version we are compatible with. This is only for giving the correct value for GetVersion
+ // when running on a userdebug/eng device.
+ jint ti_version;
+
jvmtiCapabilities capabilities;
EventMasks event_masks;
@@ -90,7 +102,7 @@ struct ArtJvmTiEnv : public jvmtiEnv {
// RW lock to protect access to all of the event data.
art::ReaderWriterMutex event_info_mutex_ DEFAULT_MUTEX_ACQUIRED_AFTER;
- ArtJvmTiEnv(art::JavaVMExt* runtime, EventHandler* event_handler);
+ ArtJvmTiEnv(art::JavaVMExt* runtime, EventHandler* event_handler, jint ti_version);
static ArtJvmTiEnv* AsArtJvmTiEnv(jvmtiEnv* env) {
return art::down_cast<ArtJvmTiEnv*>(env);
@@ -272,6 +284,60 @@ const jvmtiCapabilities kPotentialCapabilities = {
.can_generate_resource_exhaustion_threads_events = 0,
};
+// These are capabilities that are disabled if we were loaded without being debuggable.
+//
+// This includes the following capabilities:
+// can_retransform_any_class:
+// can_retransform_classes:
+// can_redefine_any_class:
+// can_redefine_classes:
+// We need to ensure that inlined code is either not present or can always be deoptimized. This
+// is not guaranteed for non-debuggable processes since we might have inlined bootclasspath code
+// on a threads stack.
+const jvmtiCapabilities kNonDebuggableUnsupportedCapabilities = {
+ .can_tag_objects = 0,
+ .can_generate_field_modification_events = 0,
+ .can_generate_field_access_events = 0,
+ .can_get_bytecodes = 0,
+ .can_get_synthetic_attribute = 0,
+ .can_get_owned_monitor_info = 0,
+ .can_get_current_contended_monitor = 0,
+ .can_get_monitor_info = 0,
+ .can_pop_frame = 0,
+ .can_redefine_classes = 1,
+ .can_signal_thread = 0,
+ .can_get_source_file_name = 0,
+ .can_get_line_numbers = 0,
+ .can_get_source_debug_extension = 0,
+ .can_access_local_variables = 0,
+ .can_maintain_original_method_order = 0,
+ .can_generate_single_step_events = 0,
+ .can_generate_exception_events = 0,
+ .can_generate_frame_pop_events = 0,
+ .can_generate_breakpoint_events = 0,
+ .can_suspend = 0,
+ .can_redefine_any_class = 1,
+ .can_get_current_thread_cpu_time = 0,
+ .can_get_thread_cpu_time = 0,
+ .can_generate_method_entry_events = 0,
+ .can_generate_method_exit_events = 0,
+ .can_generate_all_class_hook_events = 0,
+ .can_generate_compiled_method_load_events = 0,
+ .can_generate_monitor_events = 0,
+ .can_generate_vm_object_alloc_events = 0,
+ .can_generate_native_method_bind_events = 0,
+ .can_generate_garbage_collection_events = 0,
+ .can_generate_object_free_events = 0,
+ .can_force_early_return = 0,
+ .can_get_owned_monitor_stack_depth_info = 0,
+ .can_get_constant_pool = 0,
+ .can_set_native_method_prefix = 0,
+ .can_retransform_classes = 1,
+ .can_retransform_any_class = 1,
+ .can_generate_resource_exhaustion_heap_events = 0,
+ .can_generate_resource_exhaustion_threads_events = 0,
+};
+
} // namespace openjdkjvmti
#endif // ART_OPENJDKJVMTI_ART_JVMTI_H_
diff --git a/openjdkjvmti/deopt_manager.cc b/openjdkjvmti/deopt_manager.cc
index aced769cb5..53d84836fc 100644
--- a/openjdkjvmti/deopt_manager.cc
+++ b/openjdkjvmti/deopt_manager.cc
@@ -68,7 +68,9 @@ bool JvmtiMethodInspectionCallback::IsMethodSafeToJit(art::ArtMethod* method) {
}
DeoptManager::DeoptManager()
- : deoptimization_status_lock_("JVMTI_DeoptimizationStatusLock"),
+ : deoptimization_status_lock_("JVMTI_DeoptimizationStatusLock",
+ static_cast<art::LockLevel>(
+ art::LockLevel::kClassLinkerClassesLock + 1)),
deoptimization_condition_("JVMTI_DeoptimizationCondition", deoptimization_status_lock_),
performing_deoptimization_(false),
global_deopt_count_(0),
@@ -91,6 +93,33 @@ void DeoptManager::Shutdown() {
callbacks->RemoveMethodInspectionCallback(&inspection_callback_);
}
+void DeoptManager::FinishSetup() {
+ art::Thread* self = art::Thread::Current();
+ art::MutexLock mu(self, deoptimization_status_lock_);
+
+ art::Runtime* runtime = art::Runtime::Current();
+ // See if we need to do anything.
+ if (!runtime->IsJavaDebuggable()) {
+ // See if we can enable all JVMTI functions. If this is false, only kArtTiVersion agents can be
+ // retrieved and they will all be best-effort.
+ if (PhaseUtil::GetPhaseUnchecked() == JVMTI_PHASE_ONLOAD) {
+ // We are still early enough to change the compiler options and get full JVMTI support.
+ LOG(INFO) << "Openjdkjvmti plugin loaded on a non-debuggable runtime. Changing runtime to "
+ << "debuggable state. Please pass '--debuggable' to dex2oat and "
+ << "'-Xcompiler-option --debuggable' to dalvikvm in the future.";
+ DCHECK(runtime->GetJit() == nullptr) << "Jit should not be running yet!";
+ runtime->AddCompilerOption("--debuggable");
+ runtime->SetJavaDebuggable(true);
+ } else {
+ LOG(WARNING) << "Openjdkjvmti plugin was loaded on a non-debuggable Runtime. Plugin was "
+ << "loaded too late to change runtime state to DEBUGGABLE. Only kArtTiVersion "
+ << "(0x" << std::hex << kArtTiVersion << ") environments are available. Some "
+ << "functionality might not work properly.";
+ }
+ runtime->DeoptimizeBootImage();
+ }
+}
+
bool DeoptManager::MethodHasBreakpoints(art::ArtMethod* method) {
art::MutexLock lk(art::Thread::Current(), deoptimization_status_lock_);
return MethodHasBreakpointsLocked(method);
diff --git a/openjdkjvmti/deopt_manager.h b/openjdkjvmti/deopt_manager.h
index b265fa8ec2..a495b6835c 100644
--- a/openjdkjvmti/deopt_manager.h
+++ b/openjdkjvmti/deopt_manager.h
@@ -101,6 +101,10 @@ class DeoptManager {
void DeoptimizeThread(art::Thread* target) REQUIRES_SHARED(art::Locks::mutator_lock_);
void DeoptimizeAllThreads() REQUIRES_SHARED(art::Locks::mutator_lock_);
+ void FinishSetup()
+ REQUIRES(!deoptimization_status_lock_, !art::Roles::uninterruptible_)
+ REQUIRES_SHARED(art::Locks::mutator_lock_);
+
static DeoptManager* Get();
private:
@@ -141,9 +145,8 @@ class DeoptManager {
REQUIRES(!art::Roles::uninterruptible_, !art::Locks::mutator_lock_);
static constexpr const char* kDeoptManagerInstrumentationKey = "JVMTI_DeoptManager";
- // static constexpr const char* kDeoptManagerThreadName = "JVMTI_DeoptManagerWorkerThread";
- art::Mutex deoptimization_status_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+ art::Mutex deoptimization_status_lock_ ACQUIRED_BEFORE(art::Locks::classlinker_classes_lock_);
art::ConditionVariable deoptimization_condition_ GUARDED_BY(deoptimization_status_lock_);
bool performing_deoptimization_ GUARDED_BY(deoptimization_status_lock_);
diff --git a/openjdkjvmti/fixed_up_dex_file.cc b/openjdkjvmti/fixed_up_dex_file.cc
index da7d60ac2f..dcc834abe9 100644
--- a/openjdkjvmti/fixed_up_dex_file.cc
+++ b/openjdkjvmti/fixed_up_dex_file.cc
@@ -30,6 +30,7 @@
*/
#include "fixed_up_dex_file.h"
+#include "dex/art_dex_file_loader.h"
#include "dex/dex_file-inl.h"
#include "dex/dex_file_loader.h"
@@ -62,8 +63,7 @@ static void DoDexUnquicken(const art::DexFile& new_dex_file, const art::DexFile&
if (vdex == nullptr) {
return;
}
- art::VdexFile::UnquickenDexFile(
- new_dex_file, vdex->GetQuickeningInfo(), /* decompile_return_instruction */true);
+ vdex->UnquickenDexFile(new_dex_file, original_dex_file, /* decompile_return_instruction */true);
}
std::unique_ptr<FixedUpDexFile> FixedUpDexFile::Create(const art::DexFile& original) {
@@ -72,7 +72,8 @@ std::unique_ptr<FixedUpDexFile> FixedUpDexFile::Create(const art::DexFile& origi
data.resize(original.Size());
memcpy(data.data(), original.Begin(), original.Size());
std::string error;
- std::unique_ptr<const art::DexFile> new_dex_file(art::DexFileLoader::Open(
+ const art::ArtDexFileLoader dex_file_loader;
+ std::unique_ptr<const art::DexFile> new_dex_file(dex_file_loader.Open(
data.data(),
data.size(),
/*location*/"Unquickening_dexfile.dex",
@@ -103,7 +104,7 @@ std::unique_ptr<FixedUpDexFile> FixedUpDexFile::Create(const art::DexFile& origi
// Overwrite the dex file stored in data with the new result.
data.clear();
data.insert(data.end(), mem_map->Begin(), mem_map->Begin() + dex_file_size);
- new_dex_file = art::DexFileLoader::Open(
+ new_dex_file = dex_file_loader.Open(
data.data(),
data.size(),
/*location*/"Unquickening_dexfile.dex",
diff --git a/openjdkjvmti/ti_class.cc b/openjdkjvmti/ti_class.cc
index f9eb008af2..b3f5c1886e 100644
--- a/openjdkjvmti/ti_class.cc
+++ b/openjdkjvmti/ti_class.cc
@@ -42,6 +42,7 @@
#include "class_linker.h"
#include "class_table-inl.h"
#include "common_throws.h"
+#include "dex/art_dex_file_loader.h"
#include "dex/dex_file_annotations.h"
#include "dex/dex_file_loader.h"
#include "events-inl.h"
@@ -107,12 +108,13 @@ static std::unique_ptr<const art::DexFile> MakeSingleDexFile(art::Thread* self,
}
uint32_t checksum = reinterpret_cast<const art::DexFile::Header*>(map->Begin())->checksum_;
std::string map_name = map->GetName();
- std::unique_ptr<const art::DexFile> dex_file(art::DexFileLoader::Open(map_name,
- checksum,
- std::move(map),
- /*verify*/true,
- /*verify_checksum*/true,
- &error_msg));
+ const art::ArtDexFileLoader dex_file_loader;
+ std::unique_ptr<const art::DexFile> dex_file(dex_file_loader.Open(map_name,
+ checksum,
+ std::move(map),
+ /*verify*/true,
+ /*verify_checksum*/true,
+ &error_msg));
if (dex_file.get() == nullptr) {
LOG(WARNING) << "Unable to load modified dex file for " << descriptor << ": " << error_msg;
art::ThrowClassFormatError(nullptr,
diff --git a/openjdkjvmti/ti_redefine.cc b/openjdkjvmti/ti_redefine.cc
index 6194d1e42c..717b2ba669 100644
--- a/openjdkjvmti/ti_redefine.cc
+++ b/openjdkjvmti/ti_redefine.cc
@@ -43,6 +43,7 @@
#include "base/stringpiece.h"
#include "class_linker-inl.h"
#include "debugger.h"
+#include "dex/art_dex_file_loader.h"
#include "dex/dex_file.h"
#include "dex/dex_file_loader.h"
#include "dex/dex_file_types.h"
@@ -426,12 +427,13 @@ jvmtiError Redefiner::AddRedefinition(ArtJvmTiEnv* env, const ArtClassDefinition
return ERR(INVALID_CLASS_FORMAT);
}
uint32_t checksum = reinterpret_cast<const art::DexFile::Header*>(map->Begin())->checksum_;
- std::unique_ptr<const art::DexFile> dex_file(art::DexFileLoader::Open(map->GetName(),
- checksum,
- std::move(map),
- /*verify*/true,
- /*verify_checksum*/true,
- error_msg_));
+ const art::ArtDexFileLoader dex_file_loader;
+ std::unique_ptr<const art::DexFile> dex_file(dex_file_loader.Open(map->GetName(),
+ checksum,
+ std::move(map),
+ /*verify*/true,
+ /*verify_checksum*/true,
+ error_msg_));
if (dex_file.get() == nullptr) {
os << "Unable to load modified dex file for " << def.GetName() << ": " << *error_msg_;
*error_msg_ = os.str();
diff --git a/openjdkjvmti/ti_search.cc b/openjdkjvmti/ti_search.cc
index 9d5f4ea3f9..cbb7b53bff 100644
--- a/openjdkjvmti/ti_search.cc
+++ b/openjdkjvmti/ti_search.cc
@@ -38,6 +38,7 @@
#include "base/enums.h"
#include "base/macros.h"
#include "class_linker.h"
+#include "dex/art_dex_file_loader.h"
#include "dex/dex_file.h"
#include "dex/dex_file_loader.h"
#include "jni_internal.h"
@@ -227,7 +228,8 @@ jvmtiError SearchUtil::AddToBootstrapClassLoaderSearch(jvmtiEnv* env ATTRIBUTE_U
std::string error_msg;
std::vector<std::unique_ptr<const art::DexFile>> dex_files;
- if (!art::DexFileLoader::Open(
+ const art::ArtDexFileLoader dex_file_loader;
+ if (!dex_file_loader.Open(
segment, segment, /* verify */ true, /* verify_checksum */ true, &error_msg, &dex_files)) {
LOG(WARNING) << "Could not open " << segment << " for boot classpath extension: " << error_msg;
return ERR(ILLEGAL_ARGUMENT);
diff --git a/profman/profman.cc b/profman/profman.cc
index c4216fab99..9f3e3b6ac5 100644
--- a/profman/profman.cc
+++ b/profman/profman.cc
@@ -39,6 +39,7 @@
#include "base/unix_file/fd_file.h"
#include "boot_image_profile.h"
#include "bytecode_utils.h"
+#include "dex/art_dex_file_loader.h"
#include "dex/code_item_accessors-inl.h"
#include "dex/dex_file.h"
#include "dex/dex_file_loader.h"
@@ -329,25 +330,26 @@ class ProfMan FINAL {
static constexpr bool kVerifyChecksum = true;
for (size_t i = 0; i < dex_locations_.size(); ++i) {
std::string error_msg;
+ const ArtDexFileLoader dex_file_loader;
std::vector<std::unique_ptr<const DexFile>> dex_files_for_location;
if (use_apk_fd_list) {
- if (DexFileLoader::OpenZip(apks_fd_[i],
- dex_locations_[i],
- /* verify */ true,
- kVerifyChecksum,
- &error_msg,
- &dex_files_for_location)) {
+ if (dex_file_loader.OpenZip(apks_fd_[i],
+ dex_locations_[i],
+ /* verify */ true,
+ kVerifyChecksum,
+ &error_msg,
+ &dex_files_for_location)) {
} else {
LOG(WARNING) << "OpenZip failed for '" << dex_locations_[i] << "' " << error_msg;
continue;
}
} else {
- if (DexFileLoader::Open(apk_files_[i].c_str(),
- dex_locations_[i],
- /* verify */ true,
- kVerifyChecksum,
- &error_msg,
- &dex_files_for_location)) {
+ if (dex_file_loader.Open(apk_files_[i].c_str(),
+ dex_locations_[i],
+ /* verify */ true,
+ kVerifyChecksum,
+ &error_msg,
+ &dex_files_for_location)) {
} else {
LOG(WARNING) << "Open failed for '" << dex_locations_[i] << "' " << error_msg;
continue;
diff --git a/runtime/Android.bp b/runtime/Android.bp
index 2657f4fa86..2e34bafd54 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -21,6 +21,71 @@
JIT_DEBUG_REGISTER_CODE_LDFLAGS = ["-Wl,--keep-unique,__jit_debug_register_code"]
cc_defaults {
+ name: "libdexfile_defaults",
+ defaults: ["art_defaults"],
+ host_supported: true,
+ srcs: [
+ "dex/compact_dex_debug_info.cc",
+ "dex/compact_dex_file.cc",
+ "dex/dex_file.cc",
+ "dex/dex_file_exception_helpers.cc",
+ "dex/dex_file_loader.cc",
+ "dex/dex_file_tracking_registrar.cc",
+ "dex/dex_file_verifier.cc",
+ "dex/dex_instruction.cc",
+ "dex/standard_dex_file.cc",
+ "utf.cc",
+ "utils.cc",
+ ],
+
+ target: {
+ android: {
+ shared_libs: [
+ "libutils",
+ ],
+ static_libs: [
+ "libz",
+ "libbase",
+ ],
+ },
+ host: {
+ shared_libs: [
+ "libz",
+ ],
+ },
+ },
+ generated_sources: ["art_operator_srcs"],
+ // asm_support_gen.h (used by asm_support.h) is generated with cpp-define-generator
+ generated_headers: ["cpp-define-generator-asm-support"],
+ // export our headers so the libart-gtest targets can use it as well.
+ export_generated_headers: ["cpp-define-generator-asm-support"],
+ include_dirs: [
+ "external/icu/icu4c/source/common",
+ "external/zlib",
+ ],
+ shared_libs: [
+ "liblog",
+ // For common macros.
+ "libbase",
+ ],
+ export_include_dirs: ["."],
+ // ART's macros.h depends on libbase's macros.h.
+ // Note: runtime_options.h depends on cmdline. But we don't really want to export this
+ // generically. dex2oat takes care of it itself.
+ export_shared_lib_headers: ["libbase"],
+}
+
+art_cc_library {
+ name: "libdexfile",
+ defaults: ["libdexfile_defaults"],
+ // Leave the symbols in the shared library so that stack unwinders can
+ // produce meaningful name resolution.
+ strip: {
+ keep_symbols: true,
+ },
+}
+
+cc_defaults {
name: "libart_defaults",
defaults: ["art_defaults"],
host_supported: true,
@@ -56,12 +121,14 @@ cc_defaults {
"common_throws.cc",
"compiler_filter.cc",
"debugger.cc",
+ "dex/compact_dex_debug_info.cc",
"dex/compact_dex_file.cc",
"dex/dex_file.cc",
"dex/dex_file_annotations.cc",
"dex/dex_file_exception_helpers.cc",
"dex/dex_file_layout.cc",
"dex/dex_file_loader.cc",
+ "dex/art_dex_file_loader.cc",
"dex/dex_file_tracking_registrar.cc",
"dex/dex_file_verifier.cc",
"dex/dex_instruction.cc",
@@ -572,6 +639,7 @@ art_cc_test {
"class_table_test.cc",
"compiler_filter_test.cc",
"dex/code_item_accessors_test.cc",
+ "dex/compact_dex_debug_info_test.cc",
"dex/compact_dex_file_test.cc",
"dex/dex_file_test.cc",
"dex/dex_file_verifier_test.cc",
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index 44a5dde485..96468bba60 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -562,14 +562,14 @@ bool ArtMethod::EqualParameters(Handle<mirror::ObjectArray<mirror::Class>> param
return true;
}
-const uint8_t* ArtMethod::GetQuickenedInfo() {
+ArrayRef<const uint8_t> ArtMethod::GetQuickenedInfo() {
const DexFile& dex_file = GetDeclaringClass()->GetDexFile();
const OatFile::OatDexFile* oat_dex_file = dex_file.GetOatDexFile();
if (oat_dex_file == nullptr || (oat_dex_file->GetOatFile() == nullptr)) {
- return nullptr;
+ return ArrayRef<const uint8_t>();
}
- return oat_dex_file->GetOatFile()->GetVdexFile()->GetQuickenedInfoOf(
- dex_file, GetCodeItemOffset());
+ return oat_dex_file->GetOatFile()->GetVdexFile()->GetQuickenedInfoOf(dex_file,
+ GetDexMethodIndex());
}
const OatQuickMethodHeader* ArtMethod::GetOatQuickMethodHeader(uintptr_t pc) {
diff --git a/runtime/art_method.h b/runtime/art_method.h
index c4a586ed92..cd06354859 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -21,6 +21,7 @@
#include <android-base/logging.h>
+#include "base/array_ref.h"
#include "base/bit_utils.h"
#include "base/casts.h"
#include "base/enums.h"
@@ -662,7 +663,7 @@ class ArtMethod FINAL {
return hotness_count_;
}
- const uint8_t* GetQuickenedInfo() REQUIRES_SHARED(Locks::mutator_lock_);
+ ArrayRef<const uint8_t> GetQuickenedInfo() REQUIRES_SHARED(Locks::mutator_lock_);
// Returns the method header for the compiled code containing 'pc'. Note that runtime
// methods will return null for this method, as they are not oat based.
diff --git a/runtime/class_loader_context.cc b/runtime/class_loader_context.cc
index 3ec5335a80..e646520f3d 100644
--- a/runtime/class_loader_context.cc
+++ b/runtime/class_loader_context.cc
@@ -21,6 +21,7 @@
#include "base/stl_util.h"
#include "class_linker.h"
#include "class_loader_utils.h"
+#include "dex/art_dex_file_loader.h"
#include "dex/dex_file.h"
#include "dex/dex_file_loader.h"
#include "handle_scope-inl.h"
@@ -203,6 +204,7 @@ bool ClassLoaderContext::OpenDexFiles(InstructionSet isa, const std::string& cla
// We may get resource-only apks which we cannot load.
// TODO(calin): Refine the dex opening interface to be able to tell if an archive contains
// no dex files. So that we can distinguish the real failures...
+ const ArtDexFileLoader dex_file_loader;
for (ClassLoaderInfo& info : class_loader_chain_) {
size_t opened_dex_files_index = info.opened_dex_files.size();
for (const std::string& cp_elem : info.classpath) {
@@ -215,12 +217,12 @@ bool ClassLoaderContext::OpenDexFiles(InstructionSet isa, const std::string& cla
std::string error_msg;
// When opening the dex files from the context we expect their checksum to match their
// contents. So pass true to verify_checksum.
- if (!DexFileLoader::Open(location.c_str(),
- location.c_str(),
- Runtime::Current()->IsVerificationEnabled(),
- /*verify_checksum*/ true,
- &error_msg,
- &info.opened_dex_files)) {
+ if (!dex_file_loader.Open(location.c_str(),
+ location.c_str(),
+ Runtime::Current()->IsVerificationEnabled(),
+ /*verify_checksum*/ true,
+ &error_msg,
+ &info.opened_dex_files)) {
// If we fail to open the dex file because it's been stripped, try to open the dex file
// from its corresponding oat file.
// This could happen when we need to recompile a pre-build whose dex code has been stripped.
diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc
index 96d660fd64..39dbebfdf2 100644
--- a/runtime/common_runtime_test.cc
+++ b/runtime/common_runtime_test.cc
@@ -35,6 +35,7 @@
#include "base/unix_file/fd_file.h"
#include "class_linker.h"
#include "compiler_callbacks.h"
+#include "dex/art_dex_file_loader.h"
#include "dex/dex_file-inl.h"
#include "dex/dex_file_loader.h"
#include "gc/heap.h"
@@ -375,7 +376,8 @@ std::unique_ptr<const DexFile> CommonRuntimeTestImpl::LoadExpectSingleDexFile(
std::string error_msg;
MemMap::Init();
static constexpr bool kVerifyChecksum = true;
- if (!DexFileLoader::Open(
+ const ArtDexFileLoader dex_file_loader;
+ if (!dex_file_loader.Open(
location, location, /* verify */ true, kVerifyChecksum, &error_msg, &dex_files)) {
LOG(FATAL) << "Could not open .dex file '" << location << "': " << error_msg << "\n";
UNREACHABLE();
@@ -574,12 +576,13 @@ std::vector<std::unique_ptr<const DexFile>> CommonRuntimeTestImpl::OpenTestDexFi
std::string filename = GetTestDexFileName(name);
static constexpr bool kVerifyChecksum = true;
std::string error_msg;
+ const ArtDexFileLoader dex_file_loader;
std::vector<std::unique_ptr<const DexFile>> dex_files;
- bool success = DexFileLoader::Open(filename.c_str(),
- filename.c_str(),
- /* verify */ true,
- kVerifyChecksum,
- &error_msg, &dex_files);
+ bool success = dex_file_loader.Open(filename.c_str(),
+ filename.c_str(),
+ /* verify */ true,
+ kVerifyChecksum,
+ &error_msg, &dex_files);
CHECK(success) << "Failed to open '" << filename << "': " << error_msg;
for (auto& dex_file : dex_files) {
CHECK_EQ(PROT_READ, dex_file->GetPermissions());
diff --git a/runtime/dex/art_dex_file_loader.cc b/runtime/dex/art_dex_file_loader.cc
new file mode 100644
index 0000000000..282b282707
--- /dev/null
+++ b/runtime/dex/art_dex_file_loader.cc
@@ -0,0 +1,465 @@
+/*
+ * 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 "art_dex_file_loader.h"
+
+#include <sys/mman.h> // For the PROT_* and MAP_* constants.
+#include <sys/stat.h>
+
+#include "android-base/stringprintf.h"
+
+#include "base/file_magic.h"
+#include "base/stl_util.h"
+#include "base/systrace.h"
+#include "base/unix_file/fd_file.h"
+#include "compact_dex_file.h"
+#include "dex_file.h"
+#include "dex_file_verifier.h"
+#include "standard_dex_file.h"
+#include "zip_archive.h"
+
+namespace art {
+
+namespace {
+
+class MemMapContainer : public DexFileContainer {
+ public:
+ explicit MemMapContainer(std::unique_ptr<MemMap>&& mem_map) : mem_map_(std::move(mem_map)) { }
+ virtual ~MemMapContainer() OVERRIDE { }
+
+ int GetPermissions() OVERRIDE {
+ if (mem_map_.get() == nullptr) {
+ return 0;
+ } else {
+ return mem_map_->GetProtect();
+ }
+ }
+
+ bool IsReadOnly() OVERRIDE {
+ return GetPermissions() == PROT_READ;
+ }
+
+ bool EnableWrite() OVERRIDE {
+ CHECK(IsReadOnly());
+ if (mem_map_.get() == nullptr) {
+ return false;
+ } else {
+ return mem_map_->Protect(PROT_READ | PROT_WRITE);
+ }
+ }
+
+ bool DisableWrite() OVERRIDE {
+ CHECK(!IsReadOnly());
+ if (mem_map_.get() == nullptr) {
+ return false;
+ } else {
+ return mem_map_->Protect(PROT_READ);
+ }
+ }
+
+ private:
+ std::unique_ptr<MemMap> mem_map_;
+ DISALLOW_COPY_AND_ASSIGN(MemMapContainer);
+};
+
+} // namespace
+
+using android::base::StringPrintf;
+
+static constexpr OatDexFile* kNoOatDexFile = nullptr;
+
+
+bool ArtDexFileLoader::GetMultiDexChecksums(const char* filename,
+ std::vector<uint32_t>* checksums,
+ std::string* error_msg,
+ int zip_fd) const {
+ CHECK(checksums != nullptr);
+ uint32_t magic;
+
+ File fd;
+ if (zip_fd != -1) {
+ if (ReadMagicAndReset(zip_fd, &magic, error_msg)) {
+ fd = File(zip_fd, false /* check_usage */);
+ }
+ } else {
+ fd = OpenAndReadMagic(filename, &magic, error_msg);
+ }
+ if (fd.Fd() == -1) {
+ DCHECK(!error_msg->empty());
+ return false;
+ }
+ if (IsZipMagic(magic)) {
+ std::unique_ptr<ZipArchive> zip_archive(
+ ZipArchive::OpenFromFd(fd.Release(), filename, error_msg));
+ if (zip_archive.get() == nullptr) {
+ *error_msg = StringPrintf("Failed to open zip archive '%s' (error msg: %s)", filename,
+ error_msg->c_str());
+ return false;
+ }
+
+ uint32_t i = 0;
+ std::string zip_entry_name = GetMultiDexClassesDexName(i++);
+ std::unique_ptr<ZipEntry> zip_entry(zip_archive->Find(zip_entry_name.c_str(), error_msg));
+ if (zip_entry.get() == nullptr) {
+ *error_msg = StringPrintf("Zip archive '%s' doesn't contain %s (error msg: %s)", filename,
+ zip_entry_name.c_str(), error_msg->c_str());
+ return false;
+ }
+
+ do {
+ checksums->push_back(zip_entry->GetCrc32());
+ zip_entry_name = GetMultiDexClassesDexName(i++);
+ zip_entry.reset(zip_archive->Find(zip_entry_name.c_str(), error_msg));
+ } while (zip_entry.get() != nullptr);
+ return true;
+ }
+ if (IsMagicValid(magic)) {
+ std::unique_ptr<const DexFile> dex_file(
+ OpenFile(fd.Release(), filename, false, false, error_msg));
+ if (dex_file == nullptr) {
+ return false;
+ }
+ checksums->push_back(dex_file->GetHeader().checksum_);
+ return true;
+ }
+ *error_msg = StringPrintf("Expected valid zip or dex file: '%s'", filename);
+ return false;
+}
+
+std::unique_ptr<const DexFile> ArtDexFileLoader::Open(const uint8_t* base,
+ size_t size,
+ const std::string& location,
+ uint32_t location_checksum,
+ const OatDexFile* oat_dex_file,
+ bool verify,
+ bool verify_checksum,
+ std::string* error_msg) const {
+ ScopedTrace trace(std::string("Open dex file from RAM ") + location);
+ return OpenCommon(base,
+ size,
+ location,
+ location_checksum,
+ oat_dex_file,
+ verify,
+ verify_checksum,
+ error_msg,
+ /*container*/ nullptr,
+ /*verify_result*/ nullptr);
+}
+
+std::unique_ptr<const DexFile> ArtDexFileLoader::Open(const std::string& location,
+ uint32_t location_checksum,
+ std::unique_ptr<MemMap> map,
+ bool verify,
+ bool verify_checksum,
+ std::string* error_msg) const {
+ ScopedTrace trace(std::string("Open dex file from mapped-memory ") + location);
+ CHECK(map.get() != nullptr);
+
+ if (map->Size() < sizeof(DexFile::Header)) {
+ *error_msg = StringPrintf(
+ "DexFile: failed to open dex file '%s' that is too short to have a header",
+ location.c_str());
+ return nullptr;
+ }
+
+ std::unique_ptr<DexFile> dex_file = OpenCommon(map->Begin(),
+ map->Size(),
+ location,
+ location_checksum,
+ kNoOatDexFile,
+ verify,
+ verify_checksum,
+ error_msg,
+ new MemMapContainer(std::move(map)),
+ /*verify_result*/ nullptr);
+ return dex_file;
+}
+
+bool ArtDexFileLoader::Open(const char* filename,
+ const std::string& location,
+ bool verify,
+ bool verify_checksum,
+ std::string* error_msg,
+ std::vector<std::unique_ptr<const DexFile>>* dex_files) const {
+ ScopedTrace trace(std::string("Open dex file ") + std::string(location));
+ DCHECK(dex_files != nullptr) << "DexFile::Open: out-param is nullptr";
+ uint32_t magic;
+ File fd = OpenAndReadMagic(filename, &magic, error_msg);
+ if (fd.Fd() == -1) {
+ DCHECK(!error_msg->empty());
+ return false;
+ }
+ if (IsZipMagic(magic)) {
+ return OpenZip(fd.Release(), location, verify, verify_checksum, error_msg, dex_files);
+ }
+ if (IsMagicValid(magic)) {
+ std::unique_ptr<const DexFile> dex_file(OpenFile(fd.Release(),
+ location,
+ verify,
+ verify_checksum,
+ error_msg));
+ if (dex_file.get() != nullptr) {
+ dex_files->push_back(std::move(dex_file));
+ return true;
+ } else {
+ return false;
+ }
+ }
+ *error_msg = StringPrintf("Expected valid zip or dex file: '%s'", filename);
+ return false;
+}
+
+std::unique_ptr<const DexFile> ArtDexFileLoader::OpenDex(int fd,
+ const std::string& location,
+ bool verify,
+ bool verify_checksum,
+ std::string* error_msg) const {
+ ScopedTrace trace("Open dex file " + std::string(location));
+ return OpenFile(fd, location, verify, verify_checksum, error_msg);
+}
+
+bool ArtDexFileLoader::OpenZip(int fd,
+ const std::string& location,
+ bool verify,
+ bool verify_checksum,
+ std::string* error_msg,
+ std::vector<std::unique_ptr<const DexFile>>* dex_files) const {
+ ScopedTrace trace("Dex file open Zip " + std::string(location));
+ DCHECK(dex_files != nullptr) << "DexFile::OpenZip: out-param is nullptr";
+ std::unique_ptr<ZipArchive> zip_archive(ZipArchive::OpenFromFd(fd, location.c_str(), error_msg));
+ if (zip_archive.get() == nullptr) {
+ DCHECK(!error_msg->empty());
+ return false;
+ }
+ return OpenAllDexFilesFromZip(
+ *zip_archive, location, verify, verify_checksum, error_msg, dex_files);
+}
+
+std::unique_ptr<const DexFile> ArtDexFileLoader::OpenFile(int fd,
+ const std::string& location,
+ bool verify,
+ bool verify_checksum,
+ std::string* error_msg) const {
+ ScopedTrace trace(std::string("Open dex file ") + std::string(location));
+ CHECK(!location.empty());
+ std::unique_ptr<MemMap> map;
+ {
+ File delayed_close(fd, /* check_usage */ false);
+ struct stat sbuf;
+ memset(&sbuf, 0, sizeof(sbuf));
+ if (fstat(fd, &sbuf) == -1) {
+ *error_msg = StringPrintf("DexFile: fstat '%s' failed: %s", location.c_str(),
+ strerror(errno));
+ return nullptr;
+ }
+ if (S_ISDIR(sbuf.st_mode)) {
+ *error_msg = StringPrintf("Attempt to mmap directory '%s'", location.c_str());
+ return nullptr;
+ }
+ size_t length = sbuf.st_size;
+ map.reset(MemMap::MapFile(length,
+ PROT_READ,
+ MAP_PRIVATE,
+ fd,
+ 0,
+ /*low_4gb*/false,
+ location.c_str(),
+ error_msg));
+ if (map == nullptr) {
+ DCHECK(!error_msg->empty());
+ return nullptr;
+ }
+ }
+
+ if (map->Size() < sizeof(DexFile::Header)) {
+ *error_msg = StringPrintf(
+ "DexFile: failed to open dex file '%s' that is too short to have a header",
+ location.c_str());
+ return nullptr;
+ }
+
+ const DexFile::Header* dex_header = reinterpret_cast<const DexFile::Header*>(map->Begin());
+
+ std::unique_ptr<DexFile> dex_file = OpenCommon(map->Begin(),
+ map->Size(),
+ location,
+ dex_header->checksum_,
+ kNoOatDexFile,
+ verify,
+ verify_checksum,
+ error_msg,
+ new MemMapContainer(std::move(map)),
+ /*verify_result*/ nullptr);
+
+ return dex_file;
+}
+
+std::unique_ptr<const DexFile> ArtDexFileLoader::OpenOneDexFileFromZip(
+ const ZipArchive& zip_archive,
+ const char* entry_name,
+ const std::string& location,
+ bool verify,
+ bool verify_checksum,
+ std::string* error_msg,
+ ZipOpenErrorCode* error_code) const {
+ ScopedTrace trace("Dex file open from Zip Archive " + std::string(location));
+ CHECK(!location.empty());
+ std::unique_ptr<ZipEntry> zip_entry(zip_archive.Find(entry_name, error_msg));
+ if (zip_entry == nullptr) {
+ *error_code = ZipOpenErrorCode::kEntryNotFound;
+ return nullptr;
+ }
+ if (zip_entry->GetUncompressedLength() == 0) {
+ *error_msg = StringPrintf("Dex file '%s' has zero length", location.c_str());
+ *error_code = ZipOpenErrorCode::kDexFileError;
+ return nullptr;
+ }
+
+ std::unique_ptr<MemMap> map;
+ if (zip_entry->IsUncompressed()) {
+ if (!zip_entry->IsAlignedTo(alignof(DexFile::Header))) {
+ // Do not mmap unaligned ZIP entries because
+ // doing so would fail dex verification which requires 4 byte alignment.
+ LOG(WARNING) << "Can't mmap dex file " << location << "!" << entry_name << " directly; "
+ << "please zipalign to " << alignof(DexFile::Header) << " bytes. "
+ << "Falling back to extracting file.";
+ } else {
+ // Map uncompressed files within zip as file-backed to avoid a dirty copy.
+ map.reset(zip_entry->MapDirectlyFromFile(location.c_str(), /*out*/error_msg));
+ if (map == nullptr) {
+ LOG(WARNING) << "Can't mmap dex file " << location << "!" << entry_name << " directly; "
+ << "is your ZIP file corrupted? Falling back to extraction.";
+ // Try again with Extraction which still has a chance of recovery.
+ }
+ }
+ }
+
+ if (map == nullptr) {
+ // Default path for compressed ZIP entries,
+ // and fallback for stored ZIP entries.
+ map.reset(zip_entry->ExtractToMemMap(location.c_str(), entry_name, error_msg));
+ }
+
+ if (map == nullptr) {
+ *error_msg = StringPrintf("Failed to extract '%s' from '%s': %s", entry_name, location.c_str(),
+ error_msg->c_str());
+ *error_code = ZipOpenErrorCode::kExtractToMemoryError;
+ return nullptr;
+ }
+ VerifyResult verify_result;
+ std::unique_ptr<DexFile> dex_file = OpenCommon(map->Begin(),
+ map->Size(),
+ location,
+ zip_entry->GetCrc32(),
+ kNoOatDexFile,
+ verify,
+ verify_checksum,
+ error_msg,
+ new MemMapContainer(std::move(map)),
+ &verify_result);
+ if (dex_file == nullptr) {
+ if (verify_result == VerifyResult::kVerifyNotAttempted) {
+ *error_code = ZipOpenErrorCode::kDexFileError;
+ } else {
+ *error_code = ZipOpenErrorCode::kVerifyError;
+ }
+ return nullptr;
+ }
+ if (!dex_file->DisableWrite()) {
+ *error_msg = StringPrintf("Failed to make dex file '%s' read only", location.c_str());
+ *error_code = ZipOpenErrorCode::kMakeReadOnlyError;
+ return nullptr;
+ }
+ CHECK(dex_file->IsReadOnly()) << location;
+ if (verify_result != VerifyResult::kVerifySucceeded) {
+ *error_code = ZipOpenErrorCode::kVerifyError;
+ return nullptr;
+ }
+ *error_code = ZipOpenErrorCode::kNoError;
+ return dex_file;
+}
+
+// Technically we do not have a limitation with respect to the number of dex files that can be in a
+// multidex APK. However, it's bad practice, as each dex file requires its own tables for symbols
+// (types, classes, methods, ...) and dex caches. So warn the user that we open a zip with what
+// seems an excessive number.
+static constexpr size_t kWarnOnManyDexFilesThreshold = 100;
+
+bool ArtDexFileLoader::OpenAllDexFilesFromZip(
+ const ZipArchive& zip_archive,
+ const std::string& location,
+ bool verify,
+ bool verify_checksum,
+ std::string* error_msg,
+ std::vector<std::unique_ptr<const DexFile>>* dex_files) const {
+ ScopedTrace trace("Dex file open from Zip " + std::string(location));
+ DCHECK(dex_files != nullptr) << "DexFile::OpenFromZip: out-param is nullptr";
+ ZipOpenErrorCode error_code;
+ std::unique_ptr<const DexFile> dex_file(OpenOneDexFileFromZip(zip_archive,
+ kClassesDex,
+ location,
+ verify,
+ verify_checksum,
+ error_msg,
+ &error_code));
+ if (dex_file.get() == nullptr) {
+ return false;
+ } else {
+ // Had at least classes.dex.
+ dex_files->push_back(std::move(dex_file));
+
+ // Now try some more.
+
+ // We could try to avoid std::string allocations by working on a char array directly. As we
+ // do not expect a lot of iterations, this seems too involved and brittle.
+
+ for (size_t i = 1; ; ++i) {
+ std::string name = GetMultiDexClassesDexName(i);
+ std::string fake_location = GetMultiDexLocation(i, location.c_str());
+ std::unique_ptr<const DexFile> next_dex_file(OpenOneDexFileFromZip(zip_archive,
+ name.c_str(),
+ fake_location,
+ verify,
+ verify_checksum,
+ error_msg,
+ &error_code));
+ if (next_dex_file.get() == nullptr) {
+ if (error_code != ZipOpenErrorCode::kEntryNotFound) {
+ LOG(WARNING) << "Zip open failed: " << *error_msg;
+ }
+ break;
+ } else {
+ dex_files->push_back(std::move(next_dex_file));
+ }
+
+ if (i == kWarnOnManyDexFilesThreshold) {
+ LOG(WARNING) << location << " has in excess of " << kWarnOnManyDexFilesThreshold
+ << " dex files. Please consider coalescing and shrinking the number to "
+ " avoid runtime overhead.";
+ }
+
+ if (i == std::numeric_limits<size_t>::max()) {
+ LOG(ERROR) << "Overflow in number of dex files!";
+ break;
+ }
+ }
+
+ return true;
+ }
+}
+
+} // namespace art
diff --git a/runtime/dex/art_dex_file_loader.h b/runtime/dex/art_dex_file_loader.h
new file mode 100644
index 0000000000..a6191d9f54
--- /dev/null
+++ b/runtime/dex/art_dex_file_loader.h
@@ -0,0 +1,125 @@
+/*
+ * 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_DEX_ART_DEX_FILE_LOADER_H_
+#define ART_RUNTIME_DEX_ART_DEX_FILE_LOADER_H_
+
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "dex_file_loader.h"
+#include "base/macros.h"
+
+namespace art {
+
+class DexFile;
+class DexFileContainer;
+class MemMap;
+class OatDexFile;
+class ZipArchive;
+
+// Class that is used to open dex files and deal with corresponding multidex and location logic.
+class ArtDexFileLoader : public DexFileLoader {
+ public:
+ virtual ~ArtDexFileLoader() { }
+
+ // Returns the checksums of a file for comparison with GetLocationChecksum().
+ // For .dex files, this is the single header checksum.
+ // For zip files, this is the zip entry CRC32 checksum for classes.dex and
+ // each additional multidex entry classes2.dex, classes3.dex, etc.
+ // If a valid zip_fd is provided the file content will be read directly from
+ // the descriptor and `filename` will be used as alias for error logging. If
+ // zip_fd is -1, the method will try to open the `filename` and read the
+ // content from it.
+ // Return true if the checksums could be found, false otherwise.
+ bool GetMultiDexChecksums(const char* filename,
+ std::vector<uint32_t>* checksums,
+ std::string* error_msg,
+ int zip_fd = -1) const OVERRIDE;
+
+ // Opens .dex file, backed by existing memory
+ std::unique_ptr<const DexFile> Open(const uint8_t* base,
+ size_t size,
+ const std::string& location,
+ uint32_t location_checksum,
+ const OatDexFile* oat_dex_file,
+ bool verify,
+ bool verify_checksum,
+ std::string* error_msg) const OVERRIDE;
+
+ // Opens .dex file that has been memory-mapped by the caller.
+ std::unique_ptr<const DexFile> Open(const std::string& location,
+ uint32_t location_checkum,
+ std::unique_ptr<MemMap> mem_map,
+ bool verify,
+ bool verify_checksum,
+ std::string* error_msg) const OVERRIDE;
+
+ // Opens all .dex files found in the file, guessing the container format based on file extension.
+ bool Open(const char* filename,
+ const std::string& location,
+ bool verify,
+ bool verify_checksum,
+ std::string* error_msg,
+ std::vector<std::unique_ptr<const DexFile>>* dex_files) const OVERRIDE;
+
+ // Open a single dex file from an fd. This function closes the fd.
+ std::unique_ptr<const DexFile> OpenDex(int fd,
+ const std::string& location,
+ bool verify,
+ bool verify_checksum,
+ std::string* error_msg) const OVERRIDE;
+
+ // Opens dex files from within a .jar, .zip, or .apk file
+ bool OpenZip(int fd,
+ const std::string& location,
+ bool verify,
+ bool verify_checksum,
+ std::string* error_msg,
+ std::vector<std::unique_ptr<const DexFile>>* dex_files) const OVERRIDE;
+
+ private:
+ std::unique_ptr<const DexFile> OpenFile(int fd,
+ const std::string& location,
+ bool verify,
+ bool verify_checksum,
+ std::string* error_msg) const OVERRIDE;
+
+ // Open all classesXXX.dex files from a zip archive.
+ bool OpenAllDexFilesFromZip(const ZipArchive& zip_archive,
+ const std::string& location,
+ bool verify,
+ bool verify_checksum,
+ std::string* error_msg,
+ std::vector<std::unique_ptr<const DexFile>>* dex_files)
+ const OVERRIDE;
+
+ // Opens .dex file from the entry_name in a zip archive. error_code is undefined when non-null
+ // return.
+ std::unique_ptr<const DexFile> OpenOneDexFileFromZip(const ZipArchive& zip_archive,
+ const char* entry_name,
+ const std::string& location,
+ bool verify,
+ bool verify_checksum,
+ std::string* error_msg,
+ ZipOpenErrorCode* error_code) const OVERRIDE;
+};
+
+} // namespace art
+
+#endif // ART_RUNTIME_DEX_ART_DEX_FILE_LOADER_H_
diff --git a/runtime/dex/code_item_accessors-inl.h b/runtime/dex/code_item_accessors-inl.h
index 2792dc0663..63fd120991 100644
--- a/runtime/dex/code_item_accessors-inl.h
+++ b/runtime/dex/code_item_accessors-inl.h
@@ -34,15 +34,9 @@ inline CodeItemDataAccessor::CodeItemDataAccessor(ArtMethod* method)
: CodeItemDataAccessor(*method->GetDexFile(), method->GetCodeItem()) {}
inline CodeItemDebugInfoAccessor::CodeItemDebugInfoAccessor(ArtMethod* method)
- : CodeItemDebugInfoAccessor(*method->GetDexFile(), method->GetCodeItem()) {}
-
-inline CodeItemDebugInfoAccessor::CodeItemDebugInfoAccessor(const DexFile& dex_file,
- const DexFile::CodeItem* code_item) {
- if (code_item == nullptr) {
- return;
- }
- Init(dex_file, code_item, OatFile::GetDebugInfoOffset(dex_file, code_item->debug_info_off_));
-}
+ : CodeItemDebugInfoAccessor(*method->GetDexFile(),
+ method->GetCodeItem(),
+ method->GetDexMethodIndex()) {}
} // namespace art
diff --git a/runtime/dex/code_item_accessors-no_art-inl.h b/runtime/dex/code_item_accessors-no_art-inl.h
index baea856e71..aaa86d4b14 100644
--- a/runtime/dex/code_item_accessors-no_art-inl.h
+++ b/runtime/dex/code_item_accessors-no_art-inl.h
@@ -146,22 +146,28 @@ inline const void* CodeItemDataAccessor::CodeItemDataEnd() const {
inline void CodeItemDebugInfoAccessor::Init(const DexFile& dex_file,
const DexFile::CodeItem* code_item,
- uint32_t debug_info_offset) {
+ uint32_t dex_method_index) {
+ if (code_item == nullptr) {
+ return;
+ }
dex_file_ = &dex_file;
- debug_info_offset_ = debug_info_offset;
if (dex_file.IsCompactDexFile()) {
- Init(down_cast<const CompactDexFile::CodeItem&>(*code_item));
+ Init(down_cast<const CompactDexFile::CodeItem&>(*code_item), dex_method_index);
} else {
DCHECK(dex_file.IsStandardDexFile());
Init(down_cast<const StandardDexFile::CodeItem&>(*code_item));
}
}
-inline void CodeItemDebugInfoAccessor::Init(const CompactDexFile::CodeItem& code_item) {
+inline void CodeItemDebugInfoAccessor::Init(const CompactDexFile::CodeItem& code_item,
+ uint32_t dex_method_index) {
+ debug_info_offset_ = down_cast<const CompactDexFile*>(dex_file_)->GetDebugInfoOffset(
+ dex_method_index);
CodeItemDataAccessor::Init(code_item);
}
inline void CodeItemDebugInfoAccessor::Init(const StandardDexFile::CodeItem& code_item) {
+ debug_info_offset_ = code_item.debug_info_off_;
CodeItemDataAccessor::Init(code_item);
}
diff --git a/runtime/dex/code_item_accessors.h b/runtime/dex/code_item_accessors.h
index b5a6957548..66531f96bc 100644
--- a/runtime/dex/code_item_accessors.h
+++ b/runtime/dex/code_item_accessors.h
@@ -131,20 +131,16 @@ class CodeItemDebugInfoAccessor : public CodeItemDataAccessor {
public:
CodeItemDebugInfoAccessor() = default;
- // Handles null code items, but not null dex files.
- ALWAYS_INLINE CodeItemDebugInfoAccessor(const DexFile& dex_file,
- const DexFile::CodeItem* code_item);
-
// Initialize with an existing offset.
ALWAYS_INLINE CodeItemDebugInfoAccessor(const DexFile& dex_file,
const DexFile::CodeItem* code_item,
- uint32_t debug_info_offset) {
- Init(dex_file, code_item, debug_info_offset);
+ uint32_t dex_method_index) {
+ Init(dex_file, code_item, dex_method_index);
}
ALWAYS_INLINE void Init(const DexFile& dex_file,
const DexFile::CodeItem* code_item,
- uint32_t debug_info_offset);
+ uint32_t dex_method_index);
ALWAYS_INLINE explicit CodeItemDebugInfoAccessor(ArtMethod* method);
@@ -159,7 +155,7 @@ class CodeItemDebugInfoAccessor : public CodeItemDataAccessor {
void* context) const;
protected:
- ALWAYS_INLINE void Init(const CompactDexFile::CodeItem& code_item);
+ ALWAYS_INLINE void Init(const CompactDexFile::CodeItem& code_item, uint32_t dex_method_index);
ALWAYS_INLINE void Init(const StandardDexFile::CodeItem& code_item);
private:
diff --git a/runtime/dex/code_item_accessors_test.cc b/runtime/dex/code_item_accessors_test.cc
index b29d10b113..2e219562e9 100644
--- a/runtime/dex/code_item_accessors_test.cc
+++ b/runtime/dex/code_item_accessors_test.cc
@@ -19,6 +19,7 @@
#include <memory>
#include "common_runtime_test.h"
+#include "art_dex_file_loader.h"
#include "dex_file_loader.h"
#include "mem_map.h"
@@ -44,13 +45,13 @@ std::unique_ptr<const DexFile> CreateFakeDex(bool compact_dex) {
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));
+ const ArtDexFileLoader dex_file_loader;
+ std::unique_ptr<const DexFile> dex(dex_file_loader.Open("location",
+ /*location_checksum*/ 123,
+ std::move(map),
+ /*verify*/false,
+ /*verify_checksum*/false,
+ &error_msg));
CHECK(dex != nullptr) << error_msg;
return dex;
}
diff --git a/runtime/dex/compact_dex_debug_info.cc b/runtime/dex/compact_dex_debug_info.cc
new file mode 100644
index 0000000000..19495ca92c
--- /dev/null
+++ b/runtime/dex/compact_dex_debug_info.cc
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "compact_dex_debug_info.h"
+
+#include "compact_dex_utils.h"
+#include "leb128.h"
+
+namespace art {
+
+constexpr size_t CompactDexDebugInfoOffsetTable::kElementsPerIndex;
+
+CompactDexDebugInfoOffsetTable::Accessor::Accessor(const uint8_t* data_begin,
+ uint32_t debug_info_base,
+ uint32_t debug_info_table_offset)
+ : table_(reinterpret_cast<const uint32_t*>(data_begin + debug_info_table_offset)),
+ debug_info_base_(debug_info_base),
+ data_begin_(data_begin) {}
+
+uint32_t CompactDexDebugInfoOffsetTable::Accessor::GetDebugInfoOffset(uint32_t method_idx) const {
+ const uint32_t offset = table_[method_idx / kElementsPerIndex];
+ const size_t bit_index = method_idx % kElementsPerIndex;
+
+ const uint8_t* block = data_begin_ + offset;
+ uint16_t bit_mask = *block;
+ ++block;
+ bit_mask = (bit_mask << kBitsPerByte) | *block;
+ ++block;
+ if ((bit_mask & (1 << bit_index)) == 0) {
+ // Bit is not set means the offset is 0 for the debug info.
+ return 0u;
+ }
+ // Trim off the bits above the index we want and count how many bits are set. This is how many
+ // lebs we need to decode.
+ size_t count = POPCOUNT(static_cast<uintptr_t>(bit_mask) << (kBitsPerIntPtrT - 1 - bit_index));
+ DCHECK_GT(count, 0u);
+ uint32_t current_offset = debug_info_base_;
+ do {
+ current_offset += DecodeUnsignedLeb128(&block);
+ --count;
+ } while (count > 0);
+ return current_offset;
+}
+
+void CompactDexDebugInfoOffsetTable::Build(const std::vector<uint32_t>& debug_info_offsets,
+ std::vector<uint8_t>* out_data,
+ uint32_t* out_min_offset,
+ uint32_t* out_table_offset) {
+ DCHECK(out_data != nullptr);
+ DCHECK(out_data->empty());
+ // Calculate the base offset and return it.
+ *out_min_offset = std::numeric_limits<uint32_t>::max();
+ for (const uint32_t offset : debug_info_offsets) {
+ if (offset != 0u) {
+ *out_min_offset = std::min(*out_min_offset, offset);
+ }
+ }
+ // Write the leb blocks and store the important offsets (each kElementsPerIndex elements).
+ size_t block_start = 0;
+
+ std::vector<uint32_t> offset_table;
+
+ // Write data first then the table.
+ while (block_start < debug_info_offsets.size()) {
+ // Write the offset of the block for each block.
+ offset_table.push_back(out_data->size());
+
+ // Block size of up to kElementsPerIndex
+ const size_t block_size = std::min(debug_info_offsets.size() - block_start, kElementsPerIndex);
+
+ // Calculate bit mask since need to write that first.
+ uint16_t bit_mask = 0u;
+ for (size_t i = 0; i < block_size; ++i) {
+ if (debug_info_offsets[block_start + i] != 0u) {
+ bit_mask |= 1 << i;
+ }
+ }
+ // Write bit mask.
+ out_data->push_back(static_cast<uint8_t>(bit_mask >> kBitsPerByte));
+ out_data->push_back(static_cast<uint8_t>(bit_mask));
+
+ // Write debug info offsets relative to the current offset.
+ uint32_t current_offset = *out_min_offset;
+ for (size_t i = 0; i < block_size; ++i) {
+ const uint32_t debug_info_offset = debug_info_offsets[block_start + i];
+ if (debug_info_offset != 0u) {
+ uint32_t delta = debug_info_offset - current_offset;
+ EncodeUnsignedLeb128(out_data, delta);
+ current_offset = debug_info_offset;
+ }
+ }
+
+ block_start += block_size;
+ }
+
+ // Write the offset table.
+ AlignmentPadVector(out_data, alignof(uint32_t));
+ *out_table_offset = out_data->size();
+ out_data->insert(out_data->end(),
+ reinterpret_cast<const uint8_t*>(&offset_table[0]),
+ reinterpret_cast<const uint8_t*>(&offset_table[0] + offset_table.size()));
+}
+
+} // namespace art
diff --git a/runtime/dex/compact_dex_debug_info.h b/runtime/dex/compact_dex_debug_info.h
new file mode 100644
index 0000000000..1aff75879e
--- /dev/null
+++ b/runtime/dex/compact_dex_debug_info.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_DEX_COMPACT_DEX_DEBUG_INFO_H_
+#define ART_RUNTIME_DEX_COMPACT_DEX_DEBUG_INFO_H_
+
+#include <cstdint>
+#include <vector>
+
+namespace art {
+
+// Debug offset table for compact dex, aims to minimize size while still providing reasonable
+// speed (10-20ns average time per lookup on host).
+class CompactDexDebugInfoOffsetTable {
+ public:
+ // This value is coupled with the leb chunk bitmask. That logic must also be adjusted when the
+ // integer is modified.
+ static constexpr size_t kElementsPerIndex = 16;
+
+ // Leb block format:
+ // [uint16_t] 16 bit mask for what method ids actually have a debug info offset for the chunk.
+ // [lebs] Up to 16 lebs encoded using leb128, one leb bit. The leb specifies how the offset
+ // changes compared to the previous index.
+
+ class Accessor {
+ public:
+ Accessor(const uint8_t* data_begin,
+ uint32_t debug_info_base,
+ uint32_t debug_info_table_offset);
+
+ // Return the debug info for a method index (or 0 if it doesn't have one).
+ uint32_t GetDebugInfoOffset(uint32_t method_idx) const;
+
+ private:
+ const uint32_t* const table_;
+ const uint32_t debug_info_base_;
+ const uint8_t* const data_begin_;
+ };
+
+ // Returned offsets are all relative to debug_info_offsets.
+ static void Build(const std::vector<uint32_t>& debug_info_offsets,
+ std::vector<uint8_t>* out_data,
+ uint32_t* out_min_offset,
+ uint32_t* out_table_offset);
+
+ // 32 bit aligned for the offset table.
+ static constexpr size_t kAlignment = sizeof(uint32_t);
+};
+
+} // namespace art
+
+#endif // ART_RUNTIME_DEX_COMPACT_DEX_DEBUG_INFO_H_
diff --git a/runtime/dex/compact_dex_debug_info_test.cc b/runtime/dex/compact_dex_debug_info_test.cc
new file mode 100644
index 0000000000..02b95e68d7
--- /dev/null
+++ b/runtime/dex/compact_dex_debug_info_test.cc
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vector>
+#include <sys/mman.h>
+
+#include "base/logging.h"
+#include "dex/compact_dex_debug_info.h"
+#include "gtest/gtest.h"
+#include "mem_map.h"
+
+namespace art {
+
+TEST(CompactDexDebugInfoTest, TestBuildAndAccess) {
+ MemMap::Init();
+
+ const size_t kDebugInfoMinOffset = 1234567;
+ std::vector<uint32_t> offsets = {
+ 0, 17, 2, 3, 11, 0, 0, 0, 0, 1, 0, 1552, 100, 122, 44, 1234567, 0, 0,
+ std::numeric_limits<uint32_t>::max() - kDebugInfoMinOffset, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12,
+ };
+ // Add some large offset since the debug info section will never be that close to the beginning
+ // of the file.
+ for (uint32_t& offset : offsets) {
+ if (offset != 0u) {
+ offset += kDebugInfoMinOffset;
+ }
+ }
+
+ std::vector<uint8_t> data;
+ uint32_t base_offset = 0;
+ uint32_t table_offset = 0;
+ CompactDexDebugInfoOffsetTable::Build(offsets,
+ /*out*/ &data,
+ /*out*/ &base_offset,
+ /*out*/ &table_offset);
+ EXPECT_GE(base_offset, kDebugInfoMinOffset);
+ EXPECT_LT(table_offset, data.size());
+ ASSERT_GT(data.size(), 0u);
+ const size_t before_size = offsets.size() * sizeof(offsets.front());
+ EXPECT_LT(data.size(), before_size);
+
+ // Note that the accessor requires the data to be aligned. Use memmap to accomplish this.
+ std::string error_msg;
+ // Leave some extra room since we don't copy the table at the start (for testing).
+ constexpr size_t kExtraOffset = 4 * 128;
+ std::unique_ptr<MemMap> fake_dex(MemMap::MapAnonymous("fake dex",
+ nullptr,
+ data.size() + kExtraOffset,
+ PROT_READ | PROT_WRITE,
+ /*low_4gb*/ false,
+ /*reuse*/ false,
+ &error_msg));
+ ASSERT_TRUE(fake_dex != nullptr) << error_msg;
+ std::copy(data.begin(), data.end(), fake_dex->Begin() + kExtraOffset);
+
+ CompactDexDebugInfoOffsetTable::Accessor accessor(fake_dex->Begin() + kExtraOffset,
+ base_offset,
+ table_offset);
+ for (size_t i = 0; i < offsets.size(); ++i) {
+ EXPECT_EQ(offsets[i], accessor.GetDebugInfoOffset(i));
+ }
+
+ // Sort to produce a try and produce a smaller table. This happens because the leb diff is smaller
+ // for sorted increasing order.
+ std::sort(offsets.begin(), offsets.end());
+ std::vector<uint8_t> sorted_data;
+ CompactDexDebugInfoOffsetTable::Build(offsets,
+ /*out*/ &sorted_data,
+ /*out*/ &base_offset,
+ /*out*/ &table_offset);
+ EXPECT_LT(sorted_data.size(), data.size());
+ {
+ ScopedLogSeverity sls(LogSeverity::INFO);
+ LOG(INFO) << "raw size " << before_size
+ << " table size " << data.size()
+ << " sorted table size " << sorted_data.size();
+ }
+}
+
+} // namespace art
diff --git a/runtime/dex/compact_dex_file.cc b/runtime/dex/compact_dex_file.cc
index 2d1ee0420e..ff193ffb07 100644
--- a/runtime/dex/compact_dex_file.cc
+++ b/runtime/dex/compact_dex_file.cc
@@ -63,4 +63,21 @@ uint32_t CompactDexFile::GetCodeItemSize(const DexFile::CodeItem& item) const {
reinterpret_cast<uintptr_t>(&item);
}
+CompactDexFile::CompactDexFile(const uint8_t* base,
+ size_t size,
+ const std::string& location,
+ uint32_t location_checksum,
+ const OatDexFile* oat_dex_file,
+ DexFileContainer* container)
+ : DexFile(base,
+ size,
+ location,
+ location_checksum,
+ oat_dex_file,
+ container,
+ /*is_compact_dex*/ true),
+ debug_info_offsets_(Begin() + GetHeader().debug_info_offsets_pos_,
+ GetHeader().debug_info_base_,
+ GetHeader().debug_info_offsets_table_offset_) {}
+
} // namespace art
diff --git a/runtime/dex/compact_dex_file.h b/runtime/dex/compact_dex_file.h
index 280c6f70cc..af782a981a 100644
--- a/runtime/dex/compact_dex_file.h
+++ b/runtime/dex/compact_dex_file.h
@@ -19,6 +19,7 @@
#include "base/casts.h"
#include "dex_file.h"
+#include "dex/compact_dex_debug_info.h"
namespace art {
@@ -41,13 +42,45 @@ class CompactDexFile : public DexFile {
private:
uint32_t feature_flags_ = 0u;
+ // Position in the compact dex file for the debug info table data starts.
+ uint32_t debug_info_offsets_pos_ = 0u;
+
+ // Offset into the debug info table data where the lookup table is.
+ uint32_t debug_info_offsets_table_offset_ = 0u;
+
+ // Base offset of where debug info starts in the dex file.
+ uint32_t debug_info_base_ = 0u;
+
+ friend class CompactDexFile;
friend class CompactDexWriter;
};
+ // Like the standard code item except without a debug info offset.
struct CodeItem : public DexFile::CodeItem {
+ static constexpr size_t kAlignment = sizeof(uint32_t);
+
private:
- // TODO: Insert compact dex specific fields here.
+ CodeItem() = default;
+
+ uint16_t registers_size_; // the number of registers used by this code
+ // (locals + parameters)
+ uint16_t ins_size_; // the number of words of incoming arguments to the method
+ // that this code is for
+ uint16_t outs_size_; // the number of words of outgoing argument space required
+ // by this code for method invocation
+ uint16_t tries_size_; // the number of try_items for this instance. If non-zero,
+ // then these appear as the tries array just after the
+ // insns in this instance.
+
+ uint32_t insns_size_in_code_units_; // size of the insns array, in 2 byte code units
+ uint16_t insns_[1]; // actual array of bytecode.
+
+ ART_FRIEND_TEST(CodeItemAccessorsTest, TestDexInstructionsAccessor);
+ friend class CodeItemDataAccessor;
+ friend class CodeItemDebugInfoAccessor;
+ friend class CodeItemInstructionAccessor;
friend class CompactDexFile;
+ friend class CompactDexWriter;
DISALLOW_COPY_AND_ASSIGN(CodeItem);
};
@@ -73,25 +106,22 @@ class CompactDexFile : public DexFile {
uint32_t GetCodeItemSize(const DexFile::CodeItem& item) const OVERRIDE;
+ uint32_t GetDebugInfoOffset(uint32_t dex_method_index) const {
+ return debug_info_offsets_.GetDebugInfoOffset(dex_method_index);
+ }
+
private:
- // Not supported yet.
CompactDexFile(const uint8_t* base,
size_t size,
const std::string& location,
uint32_t location_checksum,
const OatDexFile* oat_dex_file,
- DexFileContainer* container)
- : DexFile(base,
- size,
- location,
- location_checksum,
- oat_dex_file,
- container,
- /*is_compact_dex*/ true) {}
+ DexFileContainer* container);
+
+ CompactDexDebugInfoOffsetTable::Accessor debug_info_offsets_;
friend class DexFile;
friend class DexFileLoader;
-
DISALLOW_COPY_AND_ASSIGN(CompactDexFile);
};
diff --git a/runtime/dex/compact_dex_utils.h b/runtime/dex/compact_dex_utils.h
new file mode 100644
index 0000000000..1c7e9514fd
--- /dev/null
+++ b/runtime/dex/compact_dex_utils.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_DEX_COMPACT_DEX_UTILS_H_
+#define ART_RUNTIME_DEX_COMPACT_DEX_UTILS_H_
+
+#include <vector>
+
+#include "base/bit_utils.h"
+
+namespace art {
+
+// Add padding to the end of the array until the size is aligned.
+template <typename T, template<typename> class Allocator>
+static inline void AlignmentPadVector(std::vector<T, Allocator<T>>* dest,
+ size_t alignment) {
+ while (!IsAlignedParam(dest->size(), alignment)) {
+ dest->push_back(T());
+ }
+}
+
+} // namespace art
+
+#endif // ART_RUNTIME_DEX_COMPACT_DEX_UTILS_H_
diff --git a/runtime/dex/dex_file.h b/runtime/dex/dex_file.h
index c2a36ce01a..183d84e15d 100644
--- a/runtime/dex/dex_file.h
+++ b/runtime/dex/dex_file.h
@@ -301,43 +301,12 @@ class DexFile {
DISALLOW_COPY_AND_ASSIGN(CallSiteIdItem);
};
- // Raw code_item.
+ // Base code_item, compact dex and standard dex have different code item layouts.
struct CodeItem {
- // Used when quickening / unquickening.
- void SetDebugInfoOffset(uint32_t new_offset) {
- debug_info_off_ = new_offset;
- }
-
- uint32_t GetDebugInfoOffset() const {
- return debug_info_off_;
- }
-
protected:
- uint16_t registers_size_; // the number of registers used by this code
- // (locals + parameters)
- uint16_t ins_size_; // the number of words of incoming arguments to the method
- // that this code is for
- uint16_t outs_size_; // the number of words of outgoing argument space required
- // by this code for method invocation
- uint16_t tries_size_; // the number of try_items for this instance. If non-zero,
- // then these appear as the tries array just after the
- // insns in this instance.
- // Normally holds file offset to debug info stream. In case the method has been quickened
- // holds an offset in the Vdex file containing both the actual debug_info_off and the
- // quickening info offset.
- // Don't use this field directly, use OatFile::GetDebugInfoOffset in general ART code,
- // or DexFile::GetDebugInfoOffset in code that are not using a Runtime.
- uint32_t debug_info_off_;
-
- uint32_t insns_size_in_code_units_; // size of the insns array, in 2 byte code units
- uint16_t insns_[1]; // actual array of bytecode.
+ CodeItem() = default;
private:
- ART_FRIEND_TEST(CodeItemAccessorsTest, TestDexInstructionsAccessor);
- friend class CodeItemDataAccessor;
- friend class CodeItemDebugInfoAccessor;
- friend class CodeItemInstructionAccessor;
- friend class VdexFile; // TODO: Remove this one when it's cleaned up.
DISALLOW_COPY_AND_ASSIGN(CodeItem);
};
@@ -348,6 +317,8 @@ class DexFile {
uint16_t handler_off_;
private:
+ TryItem() = default;
+ friend class DexWriter;
DISALLOW_COPY_AND_ASSIGN(TryItem);
};
@@ -712,15 +683,6 @@ class DexFile {
return reinterpret_cast<const CodeItem*>(addr);
}
- uint32_t GetDebugInfoOffset(const CodeItem* code_item) const {
- if (code_item == nullptr) {
- return 0;
- }
- CHECK(oat_dex_file_ == nullptr)
- << "Should only use GetDebugInfoOffset in a non runtime setup";
- return code_item->GetDebugInfoOffset();
- }
-
const char* GetReturnTypeDescriptor(const ProtoId& proto_id) const;
// Returns the number of prototype identifiers in the .dex file.
diff --git a/runtime/dex/dex_file_loader.cc b/runtime/dex/dex_file_loader.cc
index fafd69889d..10aef56125 100644
--- a/runtime/dex/dex_file_loader.cc
+++ b/runtime/dex/dex_file_loader.cc
@@ -16,72 +16,25 @@
#include "dex_file_loader.h"
-#include <sys/mman.h> // For the PROT_* and MAP_* constants.
-#include <sys/stat.h>
+// #include <sys/mman.h> // For the PROT_* and MAP_* constants.
+// #include <sys/stat.h>
#include "android-base/stringprintf.h"
#include "base/file_magic.h"
#include "base/stl_util.h"
-#include "base/systrace.h"
-#include "base/unix_file/fd_file.h"
+// #include "base/systrace.h"
+// #include "base/unix_file/fd_file.h"
#include "compact_dex_file.h"
#include "dex_file.h"
#include "dex_file_verifier.h"
#include "standard_dex_file.h"
-#include "zip_archive.h"
+// #include "zip_archive.h"
namespace art {
-namespace {
-
-class MemMapContainer : public DexFileContainer {
- public:
- explicit MemMapContainer(std::unique_ptr<MemMap>&& mem_map) : mem_map_(std::move(mem_map)) { }
- virtual ~MemMapContainer() OVERRIDE { }
-
- int GetPermissions() OVERRIDE {
- if (mem_map_.get() == nullptr) {
- return 0;
- } else {
- return mem_map_->GetProtect();
- }
- }
-
- bool IsReadOnly() OVERRIDE {
- return GetPermissions() == PROT_READ;
- }
-
- bool EnableWrite() OVERRIDE {
- CHECK(IsReadOnly());
- if (mem_map_.get() == nullptr) {
- return false;
- } else {
- return mem_map_->Protect(PROT_READ | PROT_WRITE);
- }
- }
-
- bool DisableWrite() OVERRIDE {
- CHECK(!IsReadOnly());
- if (mem_map_.get() == nullptr) {
- return false;
- } else {
- return mem_map_->Protect(PROT_READ);
- }
- }
-
- private:
- std::unique_ptr<MemMap> mem_map_;
- DISALLOW_COPY_AND_ASSIGN(MemMapContainer);
-};
-
-} // namespace
-
using android::base::StringPrintf;
-static constexpr OatDexFile* kNoOatDexFile = nullptr;
-
-
bool DexFileLoader::IsMagicValid(uint32_t magic) {
return IsMagicValid(reinterpret_cast<uint8_t*>(&magic));
}
@@ -101,63 +54,6 @@ bool DexFileLoader::IsVersionAndMagicValid(const uint8_t* magic) {
return false;
}
-bool DexFileLoader::GetMultiDexChecksums(const char* filename,
- std::vector<uint32_t>* checksums,
- std::string* error_msg,
- int zip_fd) {
- CHECK(checksums != nullptr);
- uint32_t magic;
-
- File fd;
- if (zip_fd != -1) {
- if (ReadMagicAndReset(zip_fd, &magic, error_msg)) {
- fd = File(zip_fd, false /* check_usage */);
- }
- } else {
- fd = OpenAndReadMagic(filename, &magic, error_msg);
- }
- if (fd.Fd() == -1) {
- DCHECK(!error_msg->empty());
- return false;
- }
- if (IsZipMagic(magic)) {
- std::unique_ptr<ZipArchive> zip_archive(
- ZipArchive::OpenFromFd(fd.Release(), filename, error_msg));
- if (zip_archive.get() == nullptr) {
- *error_msg = StringPrintf("Failed to open zip archive '%s' (error msg: %s)", filename,
- error_msg->c_str());
- return false;
- }
-
- uint32_t i = 0;
- std::string zip_entry_name = GetMultiDexClassesDexName(i++);
- std::unique_ptr<ZipEntry> zip_entry(zip_archive->Find(zip_entry_name.c_str(), error_msg));
- if (zip_entry.get() == nullptr) {
- *error_msg = StringPrintf("Zip archive '%s' doesn't contain %s (error msg: %s)", filename,
- zip_entry_name.c_str(), error_msg->c_str());
- return false;
- }
-
- do {
- checksums->push_back(zip_entry->GetCrc32());
- zip_entry_name = GetMultiDexClassesDexName(i++);
- zip_entry.reset(zip_archive->Find(zip_entry_name.c_str(), error_msg));
- } while (zip_entry.get() != nullptr);
- return true;
- }
- if (IsMagicValid(magic)) {
- std::unique_ptr<const DexFile> dex_file(
- OpenFile(fd.Release(), filename, false, false, error_msg));
- if (dex_file == nullptr) {
- return false;
- }
- checksums->push_back(dex_file->GetHeader().checksum_);
- return true;
- }
- *error_msg = StringPrintf("Expected valid zip or dex file: '%s'", filename);
- return false;
-}
-
bool DexFileLoader::IsMultiDexLocation(const char* location) {
return strrchr(location, kMultiDexSeparator) != nullptr;
}
@@ -187,326 +83,102 @@ std::string DexFileLoader::GetDexCanonicalLocation(const char* dex_location) {
}
}
-std::unique_ptr<const DexFile> DexFileLoader::Open(const uint8_t* base,
- size_t size,
- const std::string& location,
- uint32_t location_checksum,
- const OatDexFile* oat_dex_file,
- bool verify,
- bool verify_checksum,
- std::string* error_msg) {
- ScopedTrace trace(std::string("Open dex file from RAM ") + location);
- return OpenCommon(base,
- size,
- location,
- location_checksum,
- oat_dex_file,
- verify,
- verify_checksum,
- error_msg,
- /*container*/ nullptr,
- /*verify_result*/ nullptr);
-}
+// All of the implementations here should be independent of the runtime.
+// TODO: implement all the virtual methods.
-std::unique_ptr<const DexFile> DexFileLoader::Open(const std::string& location,
- uint32_t location_checksum,
- std::unique_ptr<MemMap> map,
- bool verify,
- bool verify_checksum,
- std::string* error_msg) {
- ScopedTrace trace(std::string("Open dex file from mapped-memory ") + location);
- CHECK(map.get() != nullptr);
-
- if (map->Size() < sizeof(DexFile::Header)) {
- *error_msg = StringPrintf(
- "DexFile: failed to open dex file '%s' that is too short to have a header",
- location.c_str());
- return nullptr;
- }
-
- std::unique_ptr<DexFile> dex_file = OpenCommon(map->Begin(),
- map->Size(),
- location,
- location_checksum,
- kNoOatDexFile,
- verify,
- verify_checksum,
- error_msg,
- new MemMapContainer(std::move(map)),
- /*verify_result*/ nullptr);
- return dex_file;
+bool DexFileLoader::GetMultiDexChecksums(const char* filename ATTRIBUTE_UNUSED,
+ std::vector<uint32_t>* checksums ATTRIBUTE_UNUSED,
+ std::string* error_msg,
+ int zip_fd ATTRIBUTE_UNUSED) const {
+ *error_msg = "UNIMPLEMENTED";
+ return false;
}
-bool DexFileLoader::Open(const char* filename,
- const std::string& location,
- bool verify,
- bool verify_checksum,
- std::string* error_msg,
- std::vector<std::unique_ptr<const DexFile>>* dex_files) {
- ScopedTrace trace(std::string("Open dex file ") + std::string(location));
- DCHECK(dex_files != nullptr) << "DexFile::Open: out-param is nullptr";
- uint32_t magic;
- File fd = OpenAndReadMagic(filename, &magic, error_msg);
- if (fd.Fd() == -1) {
- DCHECK(!error_msg->empty());
- return false;
- }
- if (IsZipMagic(magic)) {
- return OpenZip(fd.Release(), location, verify, verify_checksum, error_msg, dex_files);
- }
- if (IsMagicValid(magic)) {
- std::unique_ptr<const DexFile> dex_file(OpenFile(fd.Release(),
- location,
- verify,
- verify_checksum,
- error_msg));
- if (dex_file.get() != nullptr) {
- dex_files->push_back(std::move(dex_file));
- return true;
- } else {
- return false;
- }
- }
- *error_msg = StringPrintf("Expected valid zip or dex file: '%s'", filename);
+std::unique_ptr<const DexFile> DexFileLoader::Open(const uint8_t* base ATTRIBUTE_UNUSED,
+ size_t size ATTRIBUTE_UNUSED,
+ const std::string& location ATTRIBUTE_UNUSED,
+ uint32_t location_checksum ATTRIBUTE_UNUSED,
+ const OatDexFile* oat_dex_file ATTRIBUTE_UNUSED,
+ bool verify ATTRIBUTE_UNUSED,
+ bool verify_checksum ATTRIBUTE_UNUSED,
+ std::string* error_msg) const {
+ *error_msg = "UNIMPLEMENTED";
+ return nullptr;
+}
+
+std::unique_ptr<const DexFile> DexFileLoader::Open(const std::string& location ATTRIBUTE_UNUSED,
+ uint32_t location_checksum ATTRIBUTE_UNUSED,
+ std::unique_ptr<MemMap> map ATTRIBUTE_UNUSED,
+ bool verify ATTRIBUTE_UNUSED,
+ bool verify_checksum ATTRIBUTE_UNUSED,
+ std::string* error_msg) const {
+ *error_msg = "UNIMPLEMENTED";
+ return nullptr;
+}
+
+bool DexFileLoader::Open(
+ const char* filename ATTRIBUTE_UNUSED,
+ const std::string& location ATTRIBUTE_UNUSED,
+ bool verify ATTRIBUTE_UNUSED,
+ bool verify_checksum ATTRIBUTE_UNUSED,
+ std::string* error_msg,
+ std::vector<std::unique_ptr<const DexFile>>* dex_files ATTRIBUTE_UNUSED) const {
+ *error_msg = "UNIMPLEMENTED";
return false;
}
-std::unique_ptr<const DexFile> DexFileLoader::OpenDex(int fd,
- const std::string& location,
- bool verify,
- bool verify_checksum,
- std::string* error_msg) {
- ScopedTrace trace("Open dex file " + std::string(location));
- return OpenFile(fd, location, verify, verify_checksum, error_msg);
+std::unique_ptr<const DexFile> DexFileLoader::OpenDex(
+ int fd ATTRIBUTE_UNUSED,
+ const std::string& location ATTRIBUTE_UNUSED,
+ bool verify ATTRIBUTE_UNUSED,
+ bool verify_checksum ATTRIBUTE_UNUSED,
+ std::string* error_msg) const {
+ *error_msg = "UNIMPLEMENTED";
+ return nullptr;
}
-bool DexFileLoader::OpenZip(int fd,
- const std::string& location,
- bool verify,
- bool verify_checksum,
- std::string* error_msg,
- std::vector<std::unique_ptr<const DexFile>>* dex_files) {
- ScopedTrace trace("Dex file open Zip " + std::string(location));
- DCHECK(dex_files != nullptr) << "DexFile::OpenZip: out-param is nullptr";
- std::unique_ptr<ZipArchive> zip_archive(ZipArchive::OpenFromFd(fd, location.c_str(), error_msg));
- if (zip_archive.get() == nullptr) {
- DCHECK(!error_msg->empty());
- return false;
- }
- return OpenAllDexFilesFromZip(
- *zip_archive, location, verify, verify_checksum, error_msg, dex_files);
+bool DexFileLoader::OpenZip(
+ int fd ATTRIBUTE_UNUSED,
+ const std::string& location ATTRIBUTE_UNUSED,
+ bool verify ATTRIBUTE_UNUSED,
+ bool verify_checksum ATTRIBUTE_UNUSED,
+ std::string* error_msg,
+ std::vector<std::unique_ptr<const DexFile>>* dex_files ATTRIBUTE_UNUSED) const {
+ *error_msg = "UNIMPLEMENTED";
+ return false;
}
-std::unique_ptr<const DexFile> DexFileLoader::OpenFile(int fd,
- const std::string& location,
- bool verify,
- bool verify_checksum,
- std::string* error_msg) {
- ScopedTrace trace(std::string("Open dex file ") + std::string(location));
- CHECK(!location.empty());
- std::unique_ptr<MemMap> map;
- {
- File delayed_close(fd, /* check_usage */ false);
- struct stat sbuf;
- memset(&sbuf, 0, sizeof(sbuf));
- if (fstat(fd, &sbuf) == -1) {
- *error_msg = StringPrintf("DexFile: fstat '%s' failed: %s", location.c_str(),
- strerror(errno));
- return nullptr;
- }
- if (S_ISDIR(sbuf.st_mode)) {
- *error_msg = StringPrintf("Attempt to mmap directory '%s'", location.c_str());
- return nullptr;
- }
- size_t length = sbuf.st_size;
- map.reset(MemMap::MapFile(length,
- PROT_READ,
- MAP_PRIVATE,
- fd,
- 0,
- /*low_4gb*/false,
- location.c_str(),
- error_msg));
- if (map == nullptr) {
- DCHECK(!error_msg->empty());
- return nullptr;
- }
- }
-
- if (map->Size() < sizeof(DexFile::Header)) {
- *error_msg = StringPrintf(
- "DexFile: failed to open dex file '%s' that is too short to have a header",
- location.c_str());
- return nullptr;
- }
-
- const DexFile::Header* dex_header = reinterpret_cast<const DexFile::Header*>(map->Begin());
-
- std::unique_ptr<DexFile> dex_file = OpenCommon(map->Begin(),
- map->Size(),
- location,
- dex_header->checksum_,
- kNoOatDexFile,
- verify,
- verify_checksum,
- error_msg,
- new MemMapContainer(std::move(map)),
- /*verify_result*/ nullptr);
-
- return dex_file;
+std::unique_ptr<const DexFile> DexFileLoader::OpenFile(
+ int fd ATTRIBUTE_UNUSED,
+ const std::string& location ATTRIBUTE_UNUSED,
+ bool verify ATTRIBUTE_UNUSED,
+ bool verify_checksum ATTRIBUTE_UNUSED,
+ std::string* error_msg) const {
+ *error_msg = "UNIMPLEMENTED";
+ return nullptr;
}
std::unique_ptr<const DexFile> DexFileLoader::OpenOneDexFileFromZip(
- const ZipArchive& zip_archive,
- const char* entry_name,
- const std::string& location,
- bool verify,
- bool verify_checksum,
+ const ZipArchive& zip_archive ATTRIBUTE_UNUSED,
+ const char* entry_name ATTRIBUTE_UNUSED,
+ const std::string& location ATTRIBUTE_UNUSED,
+ bool verify ATTRIBUTE_UNUSED,
+ bool verify_checksum ATTRIBUTE_UNUSED,
std::string* error_msg,
- ZipOpenErrorCode* error_code) {
- ScopedTrace trace("Dex file open from Zip Archive " + std::string(location));
- CHECK(!location.empty());
- std::unique_ptr<ZipEntry> zip_entry(zip_archive.Find(entry_name, error_msg));
- if (zip_entry == nullptr) {
- *error_code = ZipOpenErrorCode::kEntryNotFound;
- return nullptr;
- }
- if (zip_entry->GetUncompressedLength() == 0) {
- *error_msg = StringPrintf("Dex file '%s' has zero length", location.c_str());
- *error_code = ZipOpenErrorCode::kDexFileError;
- return nullptr;
- }
-
- std::unique_ptr<MemMap> map;
- if (zip_entry->IsUncompressed()) {
- if (!zip_entry->IsAlignedTo(alignof(DexFile::Header))) {
- // Do not mmap unaligned ZIP entries because
- // doing so would fail dex verification which requires 4 byte alignment.
- LOG(WARNING) << "Can't mmap dex file " << location << "!" << entry_name << " directly; "
- << "please zipalign to " << alignof(DexFile::Header) << " bytes. "
- << "Falling back to extracting file.";
- } else {
- // Map uncompressed files within zip as file-backed to avoid a dirty copy.
- map.reset(zip_entry->MapDirectlyFromFile(location.c_str(), /*out*/error_msg));
- if (map == nullptr) {
- LOG(WARNING) << "Can't mmap dex file " << location << "!" << entry_name << " directly; "
- << "is your ZIP file corrupted? Falling back to extraction.";
- // Try again with Extraction which still has a chance of recovery.
- }
- }
- }
-
- if (map == nullptr) {
- // Default path for compressed ZIP entries,
- // and fallback for stored ZIP entries.
- map.reset(zip_entry->ExtractToMemMap(location.c_str(), entry_name, error_msg));
- }
-
- if (map == nullptr) {
- *error_msg = StringPrintf("Failed to extract '%s' from '%s': %s", entry_name, location.c_str(),
- error_msg->c_str());
- *error_code = ZipOpenErrorCode::kExtractToMemoryError;
- return nullptr;
- }
- VerifyResult verify_result;
- std::unique_ptr<DexFile> dex_file = OpenCommon(map->Begin(),
- map->Size(),
- location,
- zip_entry->GetCrc32(),
- kNoOatDexFile,
- verify,
- verify_checksum,
- error_msg,
- new MemMapContainer(std::move(map)),
- &verify_result);
- if (dex_file == nullptr) {
- if (verify_result == VerifyResult::kVerifyNotAttempted) {
- *error_code = ZipOpenErrorCode::kDexFileError;
- } else {
- *error_code = ZipOpenErrorCode::kVerifyError;
- }
- return nullptr;
- }
- if (!dex_file->DisableWrite()) {
- *error_msg = StringPrintf("Failed to make dex file '%s' read only", location.c_str());
- *error_code = ZipOpenErrorCode::kMakeReadOnlyError;
- return nullptr;
- }
- CHECK(dex_file->IsReadOnly()) << location;
- if (verify_result != VerifyResult::kVerifySucceeded) {
- *error_code = ZipOpenErrorCode::kVerifyError;
- return nullptr;
- }
- *error_code = ZipOpenErrorCode::kNoError;
- return dex_file;
+ ZipOpenErrorCode* error_code ATTRIBUTE_UNUSED) const {
+ *error_msg = "UNIMPLEMENTED";
+ return nullptr;
}
-// Technically we do not have a limitation with respect to the number of dex files that can be in a
-// multidex APK. However, it's bad practice, as each dex file requires its own tables for symbols
-// (types, classes, methods, ...) and dex caches. So warn the user that we open a zip with what
-// seems an excessive number.
-static constexpr size_t kWarnOnManyDexFilesThreshold = 100;
-
-bool DexFileLoader::OpenAllDexFilesFromZip(const ZipArchive& zip_archive,
- const std::string& location,
- bool verify,
- bool verify_checksum,
- std::string* error_msg,
- std::vector<std::unique_ptr<const DexFile>>* dex_files) {
- ScopedTrace trace("Dex file open from Zip " + std::string(location));
- DCHECK(dex_files != nullptr) << "DexFile::OpenFromZip: out-param is nullptr";
- ZipOpenErrorCode error_code;
- std::unique_ptr<const DexFile> dex_file(OpenOneDexFileFromZip(zip_archive,
- kClassesDex,
- location,
- verify,
- verify_checksum,
- error_msg,
- &error_code));
- if (dex_file.get() == nullptr) {
- return false;
- } else {
- // Had at least classes.dex.
- dex_files->push_back(std::move(dex_file));
-
- // Now try some more.
-
- // We could try to avoid std::string allocations by working on a char array directly. As we
- // do not expect a lot of iterations, this seems too involved and brittle.
-
- for (size_t i = 1; ; ++i) {
- std::string name = GetMultiDexClassesDexName(i);
- std::string fake_location = GetMultiDexLocation(i, location.c_str());
- std::unique_ptr<const DexFile> next_dex_file(OpenOneDexFileFromZip(zip_archive,
- name.c_str(),
- fake_location,
- verify,
- verify_checksum,
- error_msg,
- &error_code));
- if (next_dex_file.get() == nullptr) {
- if (error_code != ZipOpenErrorCode::kEntryNotFound) {
- LOG(WARNING) << "Zip open failed: " << *error_msg;
- }
- break;
- } else {
- dex_files->push_back(std::move(next_dex_file));
- }
-
- if (i == kWarnOnManyDexFilesThreshold) {
- LOG(WARNING) << location << " has in excess of " << kWarnOnManyDexFilesThreshold
- << " dex files. Please consider coalescing and shrinking the number to "
- " avoid runtime overhead.";
- }
-
- if (i == std::numeric_limits<size_t>::max()) {
- LOG(ERROR) << "Overflow in number of dex files!";
- break;
- }
- }
-
- return true;
- }
+bool DexFileLoader::OpenAllDexFilesFromZip(
+ const ZipArchive& zip_archive ATTRIBUTE_UNUSED,
+ const std::string& location ATTRIBUTE_UNUSED,
+ bool verify ATTRIBUTE_UNUSED,
+ bool verify_checksum ATTRIBUTE_UNUSED,
+ std::string* error_msg,
+ std::vector<std::unique_ptr<const DexFile>>* dex_files ATTRIBUTE_UNUSED) const {
+ *error_msg = "UNIMPLEMENTED";
+ return false;
}
std::unique_ptr<DexFile> DexFileLoader::OpenCommon(const uint8_t* base,
diff --git a/runtime/dex/dex_file_loader.h b/runtime/dex/dex_file_loader.h
index 7db8d8e08e..6f1afd636f 100644
--- a/runtime/dex/dex_file_loader.h
+++ b/runtime/dex/dex_file_loader.h
@@ -46,6 +46,8 @@ class DexFileLoader {
// Return true if the corresponding version and magic is valid.
static bool IsVersionAndMagicValid(const uint8_t* magic);
+ virtual ~DexFileLoader() { }
+
// Returns the checksums of a file for comparison with GetLocationChecksum().
// For .dex files, this is the single header checksum.
// For zip files, this is the zip entry CRC32 checksum for classes.dex and
@@ -55,55 +57,55 @@ class DexFileLoader {
// zip_fd is -1, the method will try to open the `filename` and read the
// content from it.
// Return true if the checksums could be found, false otherwise.
- static bool GetMultiDexChecksums(const char* filename,
- std::vector<uint32_t>* checksums,
- std::string* error_msg,
- int zip_fd = -1);
+ virtual bool GetMultiDexChecksums(const char* filename,
+ std::vector<uint32_t>* checksums,
+ std::string* error_msg,
+ int zip_fd = -1) const;
// Check whether a location denotes a multidex dex file. This is a very simple check: returns
// whether the string contains the separator character.
static bool IsMultiDexLocation(const char* location);
// Opens .dex file, backed by existing memory
- static std::unique_ptr<const DexFile> Open(const uint8_t* base,
- size_t size,
- const std::string& location,
- uint32_t location_checksum,
- const OatDexFile* oat_dex_file,
- bool verify,
- bool verify_checksum,
- std::string* error_msg);
+ virtual std::unique_ptr<const DexFile> Open(const uint8_t* base,
+ size_t size,
+ const std::string& location,
+ uint32_t location_checksum,
+ const OatDexFile* oat_dex_file,
+ bool verify,
+ bool verify_checksum,
+ std::string* error_msg) const;
// Opens .dex file that has been memory-mapped by the caller.
- static std::unique_ptr<const DexFile> Open(const std::string& location,
- uint32_t location_checkum,
- std::unique_ptr<MemMap> mem_map,
- bool verify,
- bool verify_checksum,
- std::string* error_msg);
+ virtual std::unique_ptr<const DexFile> Open(const std::string& location,
+ uint32_t location_checkum,
+ std::unique_ptr<MemMap> mem_map,
+ bool verify,
+ bool verify_checksum,
+ std::string* error_msg) const;
// Opens all .dex files found in the file, guessing the container format based on file extension.
- static bool Open(const char* filename,
- const std::string& location,
- bool verify,
- bool verify_checksum,
- std::string* error_msg,
- std::vector<std::unique_ptr<const DexFile>>* dex_files);
+ virtual bool Open(const char* filename,
+ const std::string& location,
+ bool verify,
+ bool verify_checksum,
+ std::string* error_msg,
+ std::vector<std::unique_ptr<const DexFile>>* dex_files) const;
// Open a single dex file from an fd. This function closes the fd.
- static std::unique_ptr<const DexFile> OpenDex(int fd,
- const std::string& location,
- bool verify,
- bool verify_checksum,
- std::string* error_msg);
+ virtual std::unique_ptr<const DexFile> OpenDex(int fd,
+ const std::string& location,
+ bool verify,
+ bool verify_checksum,
+ std::string* error_msg) const;
// Opens dex files from within a .jar, .zip, or .apk file
- static bool OpenZip(int fd,
- const std::string& location,
- bool verify,
- bool verify_checksum,
- std::string* error_msg,
- std::vector<std::unique_ptr<const DexFile>>* dex_files);
+ virtual bool OpenZip(int fd,
+ const std::string& location,
+ bool verify,
+ bool verify_checksum,
+ std::string* error_msg,
+ std::vector<std::unique_ptr<const DexFile>>* dex_files) const;
// Return the name of the index-th classes.dex in a multidex zip file. This is classes.dex for
// index == 0, and classes{index + 1}.dex else.
@@ -148,13 +150,7 @@ class DexFileLoader {
return (pos == std::string::npos) ? std::string() : location.substr(pos);
}
- private:
- static std::unique_ptr<const DexFile> OpenFile(int fd,
- const std::string& location,
- bool verify,
- bool verify_checksum,
- std::string* error_msg);
-
+ protected:
enum class ZipOpenErrorCode {
kNoError,
kEntryNotFound,
@@ -164,24 +160,6 @@ class DexFileLoader {
kVerifyError
};
- // Open all classesXXX.dex files from a zip archive.
- static bool OpenAllDexFilesFromZip(const ZipArchive& zip_archive,
- const std::string& location,
- bool verify,
- bool verify_checksum,
- std::string* error_msg,
- std::vector<std::unique_ptr<const DexFile>>* dex_files);
-
- // Opens .dex file from the entry_name in a zip archive. error_code is undefined when non-null
- // return.
- static std::unique_ptr<const DexFile> OpenOneDexFileFromZip(const ZipArchive& zip_archive,
- const char* entry_name,
- const std::string& location,
- bool verify,
- bool verify_checksum,
- std::string* error_msg,
- ZipOpenErrorCode* error_code);
-
enum class VerifyResult { // private
kVerifyNotAttempted,
kVerifySucceeded,
@@ -198,6 +176,31 @@ class DexFileLoader {
std::string* error_msg,
DexFileContainer* container,
VerifyResult* verify_result);
+
+ private:
+ virtual std::unique_ptr<const DexFile> OpenFile(int fd,
+ const std::string& location,
+ bool verify,
+ bool verify_checksum,
+ std::string* error_msg) const;
+
+ // Open all classesXXX.dex files from a zip archive.
+ virtual bool OpenAllDexFilesFromZip(const ZipArchive& zip_archive,
+ const std::string& location,
+ bool verify,
+ bool verify_checksum,
+ std::string* error_msg,
+ std::vector<std::unique_ptr<const DexFile>>* dex_files) const;
+
+ // Opens .dex file from the entry_name in a zip archive. error_code is undefined when non-null
+ // return.
+ virtual std::unique_ptr<const DexFile> OpenOneDexFileFromZip(const ZipArchive& zip_archive,
+ const char* entry_name,
+ const std::string& location,
+ bool verify,
+ bool verify_checksum,
+ std::string* error_msg,
+ ZipOpenErrorCode* error_code) const;
};
} // namespace art
diff --git a/runtime/dex/dex_file_test.cc b/runtime/dex/dex_file_test.cc
index 3ee115c01b..cb721af754 100644
--- a/runtime/dex/dex_file_test.cc
+++ b/runtime/dex/dex_file_test.cc
@@ -20,6 +20,7 @@
#include <memory>
+#include "art_dex_file_loader.h"
#include "base/stl_util.h"
#include "base/unix_file/fd_file.h"
#include "code_item_accessors-inl.h"
@@ -237,7 +238,8 @@ static bool OpenDexFilesBase64(const char* base64,
ScopedObjectAccess soa(Thread::Current());
static constexpr bool kVerifyChecksum = true;
std::vector<std::unique_ptr<const DexFile>> tmp;
- bool success = DexFileLoader::Open(
+ const ArtDexFileLoader dex_file_loader;
+ bool success = dex_file_loader.Open(
location, location, /* verify */ true, kVerifyChecksum, error_msg, &tmp);
if (success) {
for (std::unique_ptr<const DexFile>& dex_file : tmp) {
@@ -277,12 +279,13 @@ static std::unique_ptr<const DexFile> OpenDexFileInMemoryBase64(const char* base
/* reuse */ false,
&error_message));
memcpy(region->Begin(), dex_bytes.data(), dex_bytes.size());
- std::unique_ptr<const DexFile> dex_file(DexFileLoader::Open(location,
- location_checksum,
- std::move(region),
- /* verify */ true,
- /* verify_checksum */ true,
- &error_message));
+ const ArtDexFileLoader dex_file_loader;
+ std::unique_ptr<const DexFile> dex_file(dex_file_loader.Open(location,
+ location_checksum,
+ std::move(region),
+ /* verify */ true,
+ /* verify_checksum */ true,
+ &error_message));
if (expect_success) {
CHECK(dex_file != nullptr) << error_message;
} else {
@@ -368,7 +371,8 @@ TEST_F(DexFileTest, Version40Rejected) {
static constexpr bool kVerifyChecksum = true;
std::string error_msg;
std::vector<std::unique_ptr<const DexFile>> dex_files;
- ASSERT_FALSE(DexFileLoader::Open(
+ const ArtDexFileLoader dex_file_loader;
+ ASSERT_FALSE(dex_file_loader.Open(
location, location, /* verify */ true, kVerifyChecksum, &error_msg, &dex_files));
}
@@ -381,7 +385,8 @@ TEST_F(DexFileTest, Version41Rejected) {
static constexpr bool kVerifyChecksum = true;
std::string error_msg;
std::vector<std::unique_ptr<const DexFile>> dex_files;
- ASSERT_FALSE(DexFileLoader::Open(
+ const ArtDexFileLoader dex_file_loader;
+ ASSERT_FALSE(dex_file_loader.Open(
location, location, /* verify */ true, kVerifyChecksum, &error_msg, &dex_files));
}
@@ -394,7 +399,8 @@ TEST_F(DexFileTest, ZeroLengthDexRejected) {
static constexpr bool kVerifyChecksum = true;
std::string error_msg;
std::vector<std::unique_ptr<const DexFile>> dex_files;
- ASSERT_FALSE(DexFileLoader::Open(
+ const ArtDexFileLoader dex_file_loader;
+ ASSERT_FALSE(dex_file_loader.Open(
location, location, /* verify */ true, kVerifyChecksum, &error_msg, &dex_files));
}
@@ -408,9 +414,10 @@ TEST_F(DexFileTest, GetChecksum) {
std::vector<uint32_t> checksums;
ScopedObjectAccess soa(Thread::Current());
std::string error_msg;
- EXPECT_TRUE(DexFileLoader::GetMultiDexChecksums(GetLibCoreDexFileNames()[0].c_str(),
- &checksums,
- &error_msg))
+ const ArtDexFileLoader dex_file_loader;
+ EXPECT_TRUE(dex_file_loader.GetMultiDexChecksums(GetLibCoreDexFileNames()[0].c_str(),
+ &checksums,
+ &error_msg))
<< error_msg;
ASSERT_EQ(1U, checksums.size());
EXPECT_EQ(java_lang_dex_file_->GetLocationChecksum(), checksums[0]);
@@ -420,9 +427,10 @@ TEST_F(DexFileTest, GetMultiDexChecksums) {
std::string error_msg;
std::vector<uint32_t> checksums;
std::string multidex_file = GetTestDexFileName("MultiDex");
- EXPECT_TRUE(DexFileLoader::GetMultiDexChecksums(multidex_file.c_str(),
- &checksums,
- &error_msg)) << error_msg;
+ const ArtDexFileLoader dex_file_loader;
+ EXPECT_TRUE(dex_file_loader.GetMultiDexChecksums(multidex_file.c_str(),
+ &checksums,
+ &error_msg)) << error_msg;
std::vector<std::unique_ptr<const DexFile>> dexes = OpenTestDexFiles("MultiDex");
ASSERT_EQ(2U, dexes.size());
@@ -730,8 +738,10 @@ TEST_F(DexFileTest, OpenDexDebugInfoLocalNullType) {
std::unique_ptr<const DexFile> raw = OpenDexFileInMemoryBase64(
kRawDexDebugInfoLocalNullType, tmp.GetFilename().c_str(), 0xf25f2b38U, true);
const DexFile::ClassDef& class_def = raw->GetClassDef(0);
- const DexFile::CodeItem* code_item = raw->GetCodeItem(raw->FindCodeItemOffset(class_def, 1));
- CodeItemDebugInfoAccessor accessor(*raw, code_item);
+ constexpr uint32_t kMethodIdx = 1;
+ const DexFile::CodeItem* code_item = raw->GetCodeItem(raw->FindCodeItemOffset(class_def,
+ kMethodIdx));
+ CodeItemDebugInfoAccessor accessor(*raw, code_item, kMethodIdx);
ASSERT_TRUE(accessor.DecodeDebugLocalInfo(true, 1, Callback, nullptr));
}
diff --git a/runtime/dex/dex_file_verifier_test.cc b/runtime/dex/dex_file_verifier_test.cc
index d4d912cbfb..9759685961 100644
--- a/runtime/dex/dex_file_verifier_test.cc
+++ b/runtime/dex/dex_file_verifier_test.cc
@@ -22,6 +22,7 @@
#include <functional>
#include <memory>
+#include "art_dex_file_loader.h"
#include "base/bit_utils.h"
#include "base/macros.h"
#include "base/unix_file/fd_file.h"
@@ -114,7 +115,8 @@ static std::unique_ptr<const DexFile> OpenDexFileBase64(const char* base64,
// read dex file
ScopedObjectAccess soa(Thread::Current());
std::vector<std::unique_ptr<const DexFile>> tmp;
- bool success = DexFileLoader::Open(
+ const ArtDexFileLoader dex_file_loader;
+ bool success = dex_file_loader.Open(
location, location, /* verify */ true, /* verify_checksum */ true, error_msg, &tmp);
CHECK(success) << *error_msg;
EXPECT_EQ(1U, tmp.size());
diff --git a/runtime/dex/standard_dex_file.h b/runtime/dex/standard_dex_file.h
index fb2f720920..6437def4f5 100644
--- a/runtime/dex/standard_dex_file.h
+++ b/runtime/dex/standard_dex_file.h
@@ -33,8 +33,30 @@ class StandardDexFile : public DexFile {
};
struct CodeItem : public DexFile::CodeItem {
+ static constexpr size_t kAlignment = 4;
+
private:
- // TODO: Insert standard dex specific fields here.
+ CodeItem() = default;
+
+ uint16_t registers_size_; // the number of registers used by this code
+ // (locals + parameters)
+ uint16_t ins_size_; // the number of words of incoming arguments to the method
+ // that this code is for
+ uint16_t outs_size_; // the number of words of outgoing argument space required
+ // by this code for method invocation
+ uint16_t tries_size_; // the number of try_items for this instance. If non-zero,
+ // then these appear as the tries array just after the
+ // insns in this instance.
+ uint32_t debug_info_off_; // Holds file offset to debug info stream.
+
+ uint32_t insns_size_in_code_units_; // size of the insns array, in 2 byte code units
+ uint16_t insns_[1]; // actual array of bytecode.
+
+ ART_FRIEND_TEST(CodeItemAccessorsTest, TestDexInstructionsAccessor);
+ friend class CodeItemDataAccessor;
+ friend class CodeItemDebugInfoAccessor;
+ friend class CodeItemInstructionAccessor;
+ friend class DexWriter;
friend class StandardDexFile;
DISALLOW_COPY_AND_ASSIGN(CodeItem);
};
@@ -80,6 +102,7 @@ class StandardDexFile : public DexFile {
friend class DexFileVerifierTest;
ART_FRIEND_TEST(ClassLinkerTest, RegisterDexFileName); // for constructor
+ friend class OptimizingUnitTestHelper; // for constructor
DISALLOW_COPY_AND_ASSIGN(StandardDexFile);
};
diff --git a/runtime/dex2oat_environment_test.h b/runtime/dex2oat_environment_test.h
index e459f09e95..20cde530c2 100644
--- a/runtime/dex2oat_environment_test.h
+++ b/runtime/dex2oat_environment_test.h
@@ -27,6 +27,7 @@
#include "base/stl_util.h"
#include "common_runtime_test.h"
#include "compiler_callbacks.h"
+#include "dex/art_dex_file_loader.h"
#include "dex/dex_file_loader.h"
#include "exec_utils.h"
#include "gc/heap.h"
@@ -43,6 +44,7 @@ class Dex2oatEnvironmentTest : public CommonRuntimeTest {
public:
virtual void SetUp() OVERRIDE {
CommonRuntimeTest::SetUp();
+ const ArtDexFileLoader dex_file_loader;
// Create a scratch directory to work from.
@@ -74,7 +76,7 @@ class Dex2oatEnvironmentTest : public CommonRuntimeTest {
ASSERT_TRUE(OS::FileExists(GetStrippedDexSrc1().c_str()))
<< "Expected stripped dex file to be at: " << GetStrippedDexSrc1();
ASSERT_FALSE(
- DexFileLoader::GetMultiDexChecksums(GetStrippedDexSrc1().c_str(), &checksums, &error_msg))
+ dex_file_loader.GetMultiDexChecksums(GetStrippedDexSrc1().c_str(), &checksums, &error_msg))
<< "Expected stripped dex file to be stripped: " << GetStrippedDexSrc1();
ASSERT_TRUE(OS::FileExists(GetDexSrc2().c_str()))
<< "Expected dex file to be at: " << GetDexSrc2();
@@ -83,21 +85,21 @@ class Dex2oatEnvironmentTest : public CommonRuntimeTest {
// GetMultiDexSrc1, but a different secondary dex checksum.
static constexpr bool kVerifyChecksum = true;
std::vector<std::unique_ptr<const DexFile>> multi1;
- ASSERT_TRUE(DexFileLoader::Open(GetMultiDexSrc1().c_str(),
- GetMultiDexSrc1().c_str(),
- /* verify */ true,
- kVerifyChecksum,
- &error_msg,
- &multi1)) << error_msg;
+ ASSERT_TRUE(dex_file_loader.Open(GetMultiDexSrc1().c_str(),
+ GetMultiDexSrc1().c_str(),
+ /* verify */ true,
+ kVerifyChecksum,
+ &error_msg,
+ &multi1)) << error_msg;
ASSERT_GT(multi1.size(), 1u);
std::vector<std::unique_ptr<const DexFile>> multi2;
- ASSERT_TRUE(DexFileLoader::Open(GetMultiDexSrc2().c_str(),
- GetMultiDexSrc2().c_str(),
- /* verify */ true,
- kVerifyChecksum,
- &error_msg,
- &multi2)) << error_msg;
+ ASSERT_TRUE(dex_file_loader.Open(GetMultiDexSrc2().c_str(),
+ GetMultiDexSrc2().c_str(),
+ /* verify */ true,
+ kVerifyChecksum,
+ &error_msg,
+ &multi2)) << error_msg;
ASSERT_GT(multi2.size(), 1u);
ASSERT_EQ(multi1[0]->GetLocationChecksum(), multi2[0]->GetLocationChecksum());
diff --git a/runtime/dex_to_dex_decompiler.cc b/runtime/dex_to_dex_decompiler.cc
index e1c07baede..7887191713 100644
--- a/runtime/dex_to_dex_decompiler.cc
+++ b/runtime/dex_to_dex_decompiler.cc
@@ -36,8 +36,7 @@ class DexDecompiler {
const ArrayRef<const uint8_t>& quickened_info,
bool decompile_return_instruction)
: code_item_accessor_(dex_file, &code_item),
- quicken_info_(quickened_info.data()),
- quicken_info_number_of_indices_(QuickenInfoTable::NumberOfIndices(quickened_info.size())),
+ quicken_info_(quickened_info),
decompile_return_instruction_(decompile_return_instruction) {}
bool Decompile();
@@ -72,7 +71,7 @@ class DexDecompiler {
}
uint16_t NextIndex() {
- DCHECK_LT(quicken_index_, quicken_info_number_of_indices_);
+ DCHECK_LT(quicken_index_, quicken_info_.NumIndices());
const uint16_t ret = quicken_info_.GetData(quicken_index_);
quicken_index_++;
return ret;
@@ -80,7 +79,6 @@ class DexDecompiler {
const CodeItemInstructionAccessor code_item_accessor_;
const QuickenInfoTable quicken_info_;
- const size_t quicken_info_number_of_indices_;
const bool decompile_return_instruction_;
size_t quicken_index_ = 0u;
@@ -104,7 +102,7 @@ bool DexDecompiler::Decompile() {
break;
case Instruction::NOP:
- if (quicken_info_number_of_indices_ > 0) {
+ if (quicken_info_.NumIndices() > 0) {
// Only try to decompile NOP if there are more than 0 indices. Not having
// any index happens when we unquicken a code item that only has
// RETURN_VOID_NO_BARRIER as quickened instruction.
@@ -181,14 +179,14 @@ bool DexDecompiler::Decompile() {
}
}
- if (quicken_index_ != quicken_info_number_of_indices_) {
+ if (quicken_index_ != quicken_info_.NumIndices()) {
if (quicken_index_ == 0) {
LOG(WARNING) << "Failed to use any value in quickening info,"
<< " potentially due to duplicate methods.";
} else {
LOG(FATAL) << "Failed to use all values in quickening info."
<< " Actual: " << std::hex << quicken_index_
- << " Expected: " << quicken_info_number_of_indices_;
+ << " Expected: " << quicken_info_.NumIndices();
return false;
}
}
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 251d94ca25..ca5a3eeb17 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -36,6 +36,7 @@
#include "base/stl_util.h"
#include "base/systrace.h"
#include "base/time_utils.h"
+#include "dex/art_dex_file_loader.h"
#include "dex/dex_file_loader.h"
#include "exec_utils.h"
#include "gc/accounting/space_bitmap-inl.h"
@@ -1828,6 +1829,7 @@ std::string ImageSpace::GetMultiImageBootClassPath(
}
bool ImageSpace::ValidateOatFile(const OatFile& oat_file, std::string* error_msg) {
+ const ArtDexFileLoader dex_file_loader;
for (const OatFile::OatDexFile* oat_dex_file : oat_file.GetOatDexFiles()) {
const std::string& dex_file_location = oat_dex_file->GetDexFileLocation();
@@ -1838,7 +1840,7 @@ bool ImageSpace::ValidateOatFile(const OatFile& oat_file, std::string* error_msg
}
std::vector<uint32_t> checksums;
- if (!DexFileLoader::GetMultiDexChecksums(dex_file_location.c_str(), &checksums, error_msg)) {
+ if (!dex_file_loader.GetMultiDexChecksums(dex_file_location.c_str(), &checksums, error_msg)) {
*error_msg = StringPrintf("ValidateOatFile failed to get checksums of dex file '%s' "
"referenced by oat file %s: %s",
dex_file_location.c_str(),
diff --git a/runtime/globals.h b/runtime/globals.h
index f14d6e95a6..ca4040d777 100644
--- a/runtime/globals.h
+++ b/runtime/globals.h
@@ -62,6 +62,12 @@ static constexpr bool kIsDebugBuild = GlobalsReturnSelf(false);
static constexpr bool kIsDebugBuild = GlobalsReturnSelf(true);
#endif
+#if defined(ART_PGO_INSTRUMENTATION)
+static constexpr bool kIsPGOInstrumentation = true;
+#else
+static constexpr bool kIsPGOInstrumentation = false;
+#endif
+
// ART_TARGET - Defined for target builds of ART.
// ART_TARGET_LINUX - Defined for target Linux builds of ART.
// ART_TARGET_ANDROID - Defined for target Android builds of ART.
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index a992b5cb5b..0f430874cf 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -27,6 +27,7 @@
#include <class_loader_context.h>
#include "common_throws.h"
#include "compiler_filter.h"
+#include "dex/art_dex_file_loader.h"
#include "dex/dex_file-inl.h"
#include "dex/dex_file_loader.h"
#include "jni_internal.h"
@@ -188,12 +189,13 @@ static const DexFile* CreateDexFile(JNIEnv* env, std::unique_ptr<MemMap> dex_mem
dex_mem_map->Begin(),
dex_mem_map->End());
std::string error_message;
- std::unique_ptr<const DexFile> dex_file(DexFileLoader::Open(location,
- 0,
- std::move(dex_mem_map),
- /* verify */ true,
- /* verify_location */ true,
- &error_message));
+ const ArtDexFileLoader dex_file_loader;
+ std::unique_ptr<const DexFile> dex_file(dex_file_loader.Open(location,
+ 0,
+ std::move(dex_mem_map),
+ /* verify */ true,
+ /* verify_location */ true,
+ &error_message));
if (dex_file == nullptr) {
ScopedObjectAccess soa(env);
ThrowWrappedIOException("%s", error_message.c_str());
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index c6664411e4..c03dbccbc4 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -43,6 +43,7 @@
#include "base/stl_util.h"
#include "base/systrace.h"
#include "base/unix_file/fd_file.h"
+#include "dex/art_dex_file_loader.h"
#include "dex/dex_file_loader.h"
#include "dex/dex_file_types.h"
#include "dex/standard_dex_file.h"
@@ -1534,21 +1535,6 @@ ArrayRef<GcRoot<mirror::Object>> OatFile::GetBssGcRoots() const {
}
}
-uint32_t OatFile::GetDebugInfoOffset(const DexFile& dex_file, uint32_t debug_info_off) {
- // Note that although the specification says that 0 should be used if there
- // is no debug information, some applications incorrectly use 0xFFFFFFFF.
- // The following check also handles debug_info_off == 0.
- if (debug_info_off < dex_file.Size() || debug_info_off == 0xFFFFFFFF) {
- return debug_info_off;
- }
- const OatFile::OatDexFile* oat_dex_file = dex_file.GetOatDexFile();
- if (oat_dex_file == nullptr || (oat_dex_file->GetOatFile() == nullptr)) {
- return debug_info_off;
- }
- return oat_dex_file->GetOatFile()->GetVdexFile()->GetDebugInfoOffset(
- dex_file, debug_info_off);
-}
-
const OatFile::OatDexFile* OatFile::GetOatDexFile(const char* dex_location,
const uint32_t* dex_location_checksum,
std::string* error_msg) const {
@@ -1666,14 +1652,15 @@ std::unique_ptr<const DexFile> OatFile::OatDexFile::OpenDexFile(std::string* err
ScopedTrace trace(__PRETTY_FUNCTION__);
static constexpr bool kVerify = false;
static constexpr bool kVerifyChecksum = false;
- return DexFileLoader::Open(dex_file_pointer_,
- FileSize(),
- dex_file_location_,
- dex_file_location_checksum_,
- this,
- kVerify,
- kVerifyChecksum,
- error_msg);
+ const ArtDexFileLoader dex_file_loader;
+ return dex_file_loader.Open(dex_file_pointer_,
+ FileSize(),
+ dex_file_location_,
+ dex_file_location_checksum_,
+ this,
+ kVerify,
+ kVerifyChecksum,
+ error_msg);
}
uint32_t OatFile::OatDexFile::GetOatClassOffset(uint16_t class_def_index) const {
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index e9f7edca61..bf22e0b88b 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -115,10 +115,6 @@ class OatFile {
const char* abs_dex_location,
std::string* error_msg);
- // Return the actual debug info offset for an offset that might be actually pointing to
- // dequickening info. The returned debug info offset is the one originally in the the dex file.
- static uint32_t GetDebugInfoOffset(const DexFile& dex_file, uint32_t debug_info_off);
-
virtual ~OatFile();
bool IsExecutable() const {
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index 240030cf5b..73ca19a363 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -28,6 +28,7 @@
#include "base/stl_util.h"
#include "class_linker.h"
#include "compiler_filter.h"
+#include "dex/art_dex_file_loader.h"
#include "dex/dex_file_loader.h"
#include "exec_utils.h"
#include "gc/heap.h"
@@ -869,10 +870,11 @@ const std::vector<uint32_t>* OatFileAssistant::GetRequiredDexChecksums() {
required_dex_checksums_found_ = false;
cached_required_dex_checksums_.clear();
std::string error_msg;
- if (DexFileLoader::GetMultiDexChecksums(dex_location_.c_str(),
- &cached_required_dex_checksums_,
- &error_msg,
- zip_fd_)) {
+ const ArtDexFileLoader dex_file_loader;
+ if (dex_file_loader.GetMultiDexChecksums(dex_location_.c_str(),
+ &cached_required_dex_checksums_,
+ &error_msg,
+ zip_fd_)) {
required_dex_checksums_found_ = true;
has_original_dex_files_ = true;
} else {
diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc
index 29b9bfcf7f..9503360167 100644
--- a/runtime/oat_file_manager.cc
+++ b/runtime/oat_file_manager.cc
@@ -31,6 +31,7 @@
#include "base/systrace.h"
#include "class_linker.h"
#include "class_loader_context.h"
+#include "dex/art_dex_file_loader.h"
#include "dex/dex_file-inl.h"
#include "dex/dex_file_loader.h"
#include "dex/dex_file_tracking_registrar.h"
@@ -40,6 +41,7 @@
#include "jni_internal.h"
#include "mirror/class_loader.h"
#include "mirror/object-inl.h"
+#include "oat_file.h"
#include "oat_file_assistant.h"
#include "obj_ptr-inl.h"
#include "scoped_thread_state_change-inl.h"
@@ -527,8 +529,14 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat(
if (source_oat_file != nullptr) {
bool added_image_space = false;
if (source_oat_file->IsExecutable()) {
- std::unique_ptr<gc::space::ImageSpace> image_space =
- kEnableAppImage ? oat_file_assistant.OpenImageSpace(source_oat_file) : nullptr;
+ // We need to throw away the image space if we are debuggable but the oat-file source of the
+ // image is not otherwise we might get classes with inlined methods or other such things.
+ std::unique_ptr<gc::space::ImageSpace> image_space;
+ if (kEnableAppImage && (!runtime->IsJavaDebuggable() || source_oat_file->IsDebuggable())) {
+ image_space = oat_file_assistant.OpenImageSpace(source_oat_file);
+ } else {
+ image_space = nullptr;
+ }
if (image_space != nullptr) {
ScopedObjectAccess soa(self);
StackHandleScope<1> hs(self);
@@ -606,12 +614,13 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat(
if (oat_file_assistant.HasOriginalDexFiles()) {
if (Runtime::Current()->IsDexFileFallbackEnabled()) {
static constexpr bool kVerifyChecksum = true;
- if (!DexFileLoader::Open(dex_location,
- dex_location,
- Runtime::Current()->IsVerificationEnabled(),
- kVerifyChecksum,
- /*out*/ &error_msg,
- &dex_files)) {
+ const ArtDexFileLoader dex_file_loader;
+ if (!dex_file_loader.Open(dex_location,
+ dex_location,
+ Runtime::Current()->IsVerificationEnabled(),
+ kVerifyChecksum,
+ /*out*/ &error_msg,
+ &dex_files)) {
LOG(WARNING) << error_msg;
error_msgs->push_back("Failed to open dex files from " + std::string(dex_location)
+ " because: " + error_msg);
diff --git a/runtime/quicken_info.h b/runtime/quicken_info.h
index ce11f3c19b..52eca61c06 100644
--- a/runtime/quicken_info.h
+++ b/runtime/quicken_info.h
@@ -17,15 +17,93 @@
#ifndef ART_RUNTIME_QUICKEN_INFO_H_
#define ART_RUNTIME_QUICKEN_INFO_H_
+#include "base/array_ref.h"
#include "dex/dex_instruction.h"
+#include "leb128.h"
namespace art {
-// QuickenInfoTable is a table of 16 bit dex indices. There is one slot fo every instruction that is
-// possibly dequickenable.
+// Table for getting the offset of quicken info. Doesn't have one slot for each index, so a
+// combination of iteration and indexing is required to get the quicken info for a given dex method
+// index.
+class QuickenInfoOffsetTableAccessor {
+ public:
+ using TableType = uint32_t;
+ static constexpr uint32_t kElementsPerIndex = 16;
+
+ class Builder {
+ public:
+ explicit Builder(std::vector<uint8_t>* out_data) : out_data_(out_data) {}
+
+ void AddOffset(uint32_t index) {
+ out_data_->insert(out_data_->end(),
+ reinterpret_cast<const uint8_t*>(&index),
+ reinterpret_cast<const uint8_t*>(&index + 1));
+ }
+
+ private:
+ std::vector<uint8_t>* const out_data_;
+ };
+
+ // The table only covers every kElementsPerIndex indices.
+ static bool IsCoveredIndex(uint32_t index) {
+ return index % kElementsPerIndex == 0;
+ }
+
+ explicit QuickenInfoOffsetTableAccessor(const uint8_t* data, uint32_t max_index)
+ : table_(reinterpret_cast<const uint32_t*>(data)),
+ num_indices_(RoundUp(max_index, kElementsPerIndex) / kElementsPerIndex) {}
+
+ size_t SizeInBytes() const {
+ return NumIndices() * sizeof(table_[0]);
+ }
+
+ uint32_t NumIndices() const {
+ return num_indices_;
+ }
+
+ // Returns the offset for the index at or before the desired index. If the offset is for an index
+ // before the desired one, remainder is how many elements to traverse to reach the desired index.
+ TableType ElementOffset(uint32_t index, uint32_t* remainder) const {
+ *remainder = index % kElementsPerIndex;
+ return table_[index / kElementsPerIndex];
+ }
+
+ const uint8_t* DataEnd() const {
+ return reinterpret_cast<const uint8_t*>(table_ + NumIndices());
+ }
+
+ static uint32_t Alignment() {
+ return alignof(TableType);
+ }
+
+ private:
+ const TableType* table_;
+ uint32_t num_indices_;
+};
+
+// QuickenInfoTable is a table of 16 bit dex indices. There is one slot for every instruction that
+// is possibly dequickenable.
class QuickenInfoTable {
public:
- explicit QuickenInfoTable(const uint8_t* data) : data_(data) {}
+ class Builder {
+ public:
+ Builder(std::vector<uint8_t>* out_data, size_t num_elements) : out_data_(out_data) {
+ EncodeUnsignedLeb128(out_data_, num_elements);
+ }
+
+ void AddIndex(uint16_t index) {
+ out_data_->push_back(static_cast<uint8_t>(index));
+ out_data_->push_back(static_cast<uint8_t>(index >> 8));
+ }
+
+ private:
+ std::vector<uint8_t>* const out_data_;
+ };
+
+ explicit QuickenInfoTable(ArrayRef<const uint8_t> data)
+ : data_(data.data()),
+ num_elements_(!data.empty() ? DecodeUnsignedLeb128(&data_) : 0u) {}
bool IsNull() const {
return data_ == nullptr;
@@ -44,8 +122,18 @@ class QuickenInfoTable {
return bytes / sizeof(uint16_t);
}
+ static size_t SizeInBytes(ArrayRef<const uint8_t> data) {
+ QuickenInfoTable table(data);
+ return table.data_ + table.NumIndices() * 2 - data.data();
+ }
+
+ uint32_t NumIndices() const {
+ return num_elements_;
+ }
+
private:
- const uint8_t* const data_;
+ const uint8_t* data_;
+ const uint32_t num_elements_;
DISALLOW_COPY_AND_ASSIGN(QuickenInfoTable);
};
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 38c2bfd96f..377e0a3fca 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -69,6 +69,7 @@
#include "class_linker-inl.h"
#include "compiler_callbacks.h"
#include "debugger.h"
+#include "dex/art_dex_file_loader.h"
#include "dex/dex_file_loader.h"
#include "elf_file.h"
#include "entrypoints/runtime_asm_entrypoints.h"
@@ -1041,6 +1042,7 @@ static size_t OpenDexFiles(const std::vector<std::string>& dex_filenames,
if (!image_location.empty() && OpenDexFilesFromImage(image_location, dex_files, &failure_count)) {
return failure_count;
}
+ const ArtDexFileLoader dex_file_loader;
failure_count = 0;
for (size_t i = 0; i < dex_filenames.size(); i++) {
const char* dex_filename = dex_filenames[i].c_str();
@@ -1051,12 +1053,12 @@ static size_t OpenDexFiles(const std::vector<std::string>& dex_filenames,
LOG(WARNING) << "Skipping non-existent dex file '" << dex_filename << "'";
continue;
}
- if (!DexFileLoader::Open(dex_filename,
- dex_location,
- Runtime::Current()->IsVerificationEnabled(),
- kVerifyChecksum,
- &error_msg,
- dex_files)) {
+ if (!dex_file_loader.Open(dex_filename,
+ dex_location,
+ Runtime::Current()->IsVerificationEnabled(),
+ kVerifyChecksum,
+ &error_msg,
+ dex_files)) {
LOG(WARNING) << "Failed to open .dex from file '" << dex_filename << "': " << error_msg;
++failure_count;
}
@@ -1551,6 +1553,7 @@ bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) {
}
static bool EnsureJvmtiPlugin(Runtime* runtime,
+ bool allow_non_debuggable_tooling,
std::vector<Plugin>* plugins,
std::string* error_msg) {
constexpr const char* plugin_name = kIsDebugBuild ? "libopenjdkjvmtid.so" : "libopenjdkjvmti.so";
@@ -1562,9 +1565,9 @@ static bool EnsureJvmtiPlugin(Runtime* runtime,
}
}
- // Is the process debuggable? Otherwise, do not attempt to load the plugin.
- // TODO Support a crimped jvmti for non-debuggable runtimes.
- if (!runtime->IsJavaDebuggable()) {
+ // Is the process debuggable? Otherwise, do not attempt to load the plugin unless we are
+ // specifically allowed.
+ if (!allow_non_debuggable_tooling && !runtime->IsJavaDebuggable()) {
*error_msg = "Process is not debuggable.";
return false;
}
@@ -1585,9 +1588,12 @@ static bool EnsureJvmtiPlugin(Runtime* runtime,
// revisit this and make sure we're doing this on the right thread
// (and we synchronize access to any shared data structures like "agents_")
//
-void Runtime::AttachAgent(JNIEnv* env, const std::string& agent_arg, jobject class_loader) {
+void Runtime::AttachAgent(JNIEnv* env,
+ const std::string& agent_arg,
+ jobject class_loader,
+ bool allow_non_debuggable_tooling) {
std::string error_msg;
- if (!EnsureJvmtiPlugin(this, &plugins_, &error_msg)) {
+ if (!EnsureJvmtiPlugin(this, allow_non_debuggable_tooling, &plugins_, &error_msg)) {
LOG(WARNING) << "Could not load plugin: " << error_msg;
ScopedObjectAccess soa(Thread::Current());
ThrowIOException("%s", error_msg.c_str());
diff --git a/runtime/runtime.h b/runtime/runtime.h
index c8edabce09..3e055c3f84 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -661,7 +661,10 @@ class Runtime {
void AddSystemWeakHolder(gc::AbstractSystemWeakHolder* holder);
void RemoveSystemWeakHolder(gc::AbstractSystemWeakHolder* holder);
- void AttachAgent(JNIEnv* env, const std::string& agent_arg, jobject class_loader);
+ void AttachAgent(JNIEnv* env,
+ const std::string& agent_arg,
+ jobject class_loader,
+ bool allow_non_debuggable_tooling = false);
const std::list<std::unique_ptr<ti::Agent>>& GetAgents() const {
return agents_;
diff --git a/runtime/utils.cc b/runtime/utils.cc
index bd4175f5fd..79ddcb9bff 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -26,10 +26,10 @@
#include <memory>
+#include "android-base/file.h"
#include "android-base/stringprintf.h"
#include "android-base/strings.h"
-#include "base/file_utils.h"
#include "dex/dex_file-inl.h"
#include "os.h"
#include "utf-inl.h"
@@ -46,6 +46,7 @@
namespace art {
+using android::base::ReadFileToString;
using android::base::StringAppendF;
using android::base::StringPrintf;
@@ -63,6 +64,7 @@ pid_t GetTid() {
std::string GetThreadName(pid_t tid) {
std::string result;
+ // TODO: make this less Linux-specific.
if (ReadFileToString(StringPrintf("/proc/self/task/%d/comm", tid), &result)) {
result.resize(result.size() - 1); // Lose the trailing '\n'.
} else {
@@ -611,6 +613,7 @@ void SetThreadName(const char* thread_name) {
void GetTaskStats(pid_t tid, char* state, int* utime, int* stime, int* task_cpu) {
*utime = *stime = *task_cpu = 0;
std::string stats;
+ // TODO: make this less Linux-specific.
if (!ReadFileToString(StringPrintf("/proc/self/task/%d/stat", tid), &stats)) {
return;
}
diff --git a/runtime/vdex_file.cc b/runtime/vdex_file.cc
index c536054883..118cffeda6 100644
--- a/runtime/vdex_file.cc
+++ b/runtime/vdex_file.cc
@@ -25,9 +25,11 @@
#include "base/bit_utils.h"
#include "base/stl_util.h"
#include "base/unix_file/fd_file.h"
+#include "dex/art_dex_file_loader.h"
#include "dex/dex_file.h"
#include "dex/dex_file_loader.h"
#include "dex_to_dex_decompiler.h"
+#include "quicken_info.h"
namespace art {
@@ -143,9 +145,8 @@ std::unique_ptr<VdexFile> VdexFile::OpenAtAddress(uint8_t* mmap_addr,
if (!vdex->OpenAllDexFiles(&unique_ptr_dex_files, error_msg)) {
return nullptr;
}
- Unquicken(MakeNonOwningPointerVector(unique_ptr_dex_files),
- vdex->GetQuickeningInfo(),
- /* decompile_return_instruction */ false);
+ vdex->Unquicken(MakeNonOwningPointerVector(unique_ptr_dex_files),
+ /* decompile_return_instruction */ false);
// Update the quickening info size to pretend there isn't any.
reinterpret_cast<Header*>(vdex->mmap_->Begin())->quickening_info_size_ = 0;
}
@@ -158,19 +159,21 @@ const uint8_t* VdexFile::GetNextDexFileData(const uint8_t* cursor) const {
DCHECK(cursor == nullptr || (cursor > Begin() && cursor <= End()));
if (cursor == nullptr) {
// Beginning of the iteration, return the first dex file if there is one.
- return HasDexSection() ? DexBegin() : nullptr;
+ return HasDexSection() ? DexBegin() + sizeof(QuickeningTableOffsetType) : nullptr;
} else {
// Fetch the next dex file. Return null if there is none.
const uint8_t* data = cursor + reinterpret_cast<const DexFile::Header*>(cursor)->file_size_;
// Dex files are required to be 4 byte aligned. the OatWriter makes sure they are, see
// OatWriter::SeekToDexFiles.
data = AlignUp(data, 4);
- return (data == DexEnd()) ? nullptr : data;
+
+ return (data == DexEnd()) ? nullptr : data + sizeof(QuickeningTableOffsetType);
}
}
bool VdexFile::OpenAllDexFiles(std::vector<std::unique_ptr<const DexFile>>* dex_files,
std::string* error_msg) {
+ const ArtDexFileLoader dex_file_loader;
size_t i = 0;
for (const uint8_t* dex_file_start = GetNextDexFileData(nullptr);
dex_file_start != nullptr;
@@ -179,14 +182,14 @@ bool VdexFile::OpenAllDexFiles(std::vector<std::unique_ptr<const DexFile>>* dex_
// TODO: Supply the location information for a vdex file.
static constexpr char kVdexLocation[] = "";
std::string location = DexFileLoader::GetMultiDexLocation(i, kVdexLocation);
- std::unique_ptr<const DexFile> dex(DexFileLoader::Open(dex_file_start,
- size,
- location,
- GetLocationChecksum(i),
- nullptr /*oat_dex_file*/,
- false /*verify*/,
- false /*verify_checksum*/,
- error_msg));
+ std::unique_ptr<const DexFile> dex(dex_file_loader.Open(dex_file_start,
+ size,
+ location,
+ GetLocationChecksum(i),
+ nullptr /*oat_dex_file*/,
+ false /*verify*/,
+ false /*verify_checksum*/,
+ error_msg));
if (dex == nullptr) {
return false;
}
@@ -195,64 +198,68 @@ bool VdexFile::OpenAllDexFiles(std::vector<std::unique_ptr<const DexFile>>* dex_
return true;
}
-void VdexFile::Unquicken(const std::vector<const DexFile*>& dex_files,
- ArrayRef<const uint8_t> quickening_info,
- bool decompile_return_instruction) {
- if (quickening_info.size() == 0 && !decompile_return_instruction) {
- // Bail early if there is no quickening info and no need to decompile
- // RETURN_VOID_NO_BARRIER instructions to RETURN_VOID instructions.
- return;
- }
-
- for (uint32_t i = 0; i < dex_files.size(); ++i) {
- UnquickenDexFile(*dex_files[i], quickening_info, decompile_return_instruction);
+void VdexFile::Unquicken(const std::vector<const DexFile*>& target_dex_files,
+ bool decompile_return_instruction) const {
+ const uint8_t* source_dex = GetNextDexFileData(nullptr);
+ for (const DexFile* target_dex : target_dex_files) {
+ UnquickenDexFile(*target_dex, source_dex, decompile_return_instruction);
+ source_dex = GetNextDexFileData(source_dex);
}
+ DCHECK(source_dex == nullptr);
}
-typedef __attribute__((__aligned__(1))) uint32_t unaligned_uint32_t;
-
-static uint32_t GetDebugInfoOffsetInternal(const DexFile& dex_file,
- uint32_t offset_in_code_item,
- const ArrayRef<const uint8_t>& quickening_info) {
- if (quickening_info.size() == 0) {
- // No quickening info: offset is the right one, return it.
- return offset_in_code_item;
- }
- uint32_t quickening_offset = offset_in_code_item - dex_file.Size();
- return *reinterpret_cast<const unaligned_uint32_t*>(quickening_info.data() + quickening_offset);
+uint32_t VdexFile::GetQuickeningInfoTableOffset(const uint8_t* source_dex_begin) const {
+ DCHECK_GE(source_dex_begin, DexBegin());
+ DCHECK_LT(source_dex_begin, DexEnd());
+ return reinterpret_cast<const QuickeningTableOffsetType*>(source_dex_begin)[-1];
}
-static uint32_t GetQuickeningInfoOffsetFrom(const DexFile& dex_file,
- uint32_t offset_in_code_item,
- const ArrayRef<const uint8_t>& quickening_info) {
- if (offset_in_code_item < dex_file.Size()) {
- return VdexFile::kNoQuickeningInfoOffset;
- }
- if (quickening_info.size() == 0) {
- // No quickening info.
- return VdexFile::kNoQuickeningInfoOffset;
- }
- uint32_t quickening_offset = offset_in_code_item - dex_file.Size();
+QuickenInfoOffsetTableAccessor VdexFile::GetQuickenInfoOffsetTable(
+ const uint8_t* source_dex_begin,
+ uint32_t num_method_ids,
+ const ArrayRef<const uint8_t>& quickening_info) const {
+ // The offset a is in preheader right before the dex file.
+ const uint32_t offset = GetQuickeningInfoTableOffset(source_dex_begin);
+ const uint8_t* data_ptr = quickening_info.data() + offset;
+ return QuickenInfoOffsetTableAccessor(data_ptr, num_method_ids);
+}
- // Add 2 * sizeof(uint32_t) for the debug info offset and the data offset.
- CHECK_LE(quickening_offset + 2 * sizeof(uint32_t), quickening_info.size());
- return *reinterpret_cast<const unaligned_uint32_t*>(
- quickening_info.data() + quickening_offset + sizeof(uint32_t));
+QuickenInfoOffsetTableAccessor VdexFile::GetQuickenInfoOffsetTable(
+ const DexFile& dex_file,
+ const ArrayRef<const uint8_t>& quickening_info) const {
+ return GetQuickenInfoOffsetTable(dex_file.Begin(), dex_file.NumMethodIds(), quickening_info);
}
static ArrayRef<const uint8_t> GetQuickeningInfoAt(const ArrayRef<const uint8_t>& quickening_info,
uint32_t quickening_offset) {
- return (quickening_offset == VdexFile::kNoQuickeningInfoOffset)
- ? ArrayRef<const uint8_t>(nullptr, 0)
- : quickening_info.SubArray(
- quickening_offset + sizeof(uint32_t),
- *reinterpret_cast<const unaligned_uint32_t*>(
- quickening_info.data() + quickening_offset));
+ ArrayRef<const uint8_t> remaining = quickening_info.SubArray(quickening_offset);
+ return remaining.SubArray(0u, QuickenInfoTable::SizeInBytes(remaining));
+}
+
+static uint32_t GetQuickeningInfoOffset(const QuickenInfoOffsetTableAccessor& table,
+ uint32_t dex_method_index,
+ const ArrayRef<const uint8_t>& quickening_info) {
+ DCHECK(!quickening_info.empty());
+ uint32_t remainder;
+ uint32_t offset = table.ElementOffset(dex_method_index, &remainder);
+ // Decode the sizes for the remainder offsets (not covered by the table).
+ while (remainder != 0) {
+ offset += GetQuickeningInfoAt(quickening_info, offset).size();
+ --remainder;
+ }
+ return offset;
+}
+
+void VdexFile::UnquickenDexFile(const DexFile& target_dex_file,
+ const DexFile& source_dex_file,
+ bool decompile_return_instruction) const {
+ UnquickenDexFile(target_dex_file, source_dex_file.Begin(), decompile_return_instruction);
}
void VdexFile::UnquickenDexFile(const DexFile& target_dex_file,
- ArrayRef<const uint8_t> quickening_info,
- bool decompile_return_instruction) {
+ const uint8_t* source_dex_begin,
+ bool decompile_return_instruction) const {
+ ArrayRef<const uint8_t> quickening_info = GetQuickeningInfo();
if (quickening_info.size() == 0 && !decompile_return_instruction) {
// Bail early if there is no quickening info and no need to decompile
// RETURN_VOID_NO_BARRIER instructions to RETURN_VOID instructions.
@@ -267,19 +274,20 @@ void VdexFile::UnquickenDexFile(const DexFile& target_dex_file,
class_it.Next()) {
if (class_it.IsAtMethod() && class_it.GetMethodCodeItem() != nullptr) {
const DexFile::CodeItem* code_item = class_it.GetMethodCodeItem();
- uint32_t quickening_offset = GetQuickeningInfoOffsetFrom(
- target_dex_file, code_item->debug_info_off_, quickening_info);
- if (quickening_offset != VdexFile::kNoQuickeningInfoOffset) {
- // If we have quickening data, put back the original debug_info_off.
- const_cast<DexFile::CodeItem*>(code_item)->SetDebugInfoOffset(
- GetDebugInfoOffsetInternal(target_dex_file,
- code_item->debug_info_off_,
- quickening_info));
+ ArrayRef<const uint8_t> quicken_data;
+ if (!quickening_info.empty()) {
+ const uint32_t quickening_offset = GetQuickeningInfoOffset(
+ GetQuickenInfoOffsetTable(source_dex_begin,
+ target_dex_file.NumMethodIds(),
+ quickening_info),
+ class_it.GetMemberIndex(),
+ quickening_info);
+ quicken_data = GetQuickeningInfoAt(quickening_info, quickening_offset);
}
optimizer::ArtDecompileDEX(
target_dex_file,
*code_item,
- GetQuickeningInfoAt(quickening_info, quickening_offset),
+ quicken_data,
decompile_return_instruction);
}
}
@@ -287,25 +295,17 @@ void VdexFile::UnquickenDexFile(const DexFile& target_dex_file,
}
}
-uint32_t VdexFile::GetDebugInfoOffset(const DexFile& dex_file, uint32_t offset_in_code_item) const {
- return GetDebugInfoOffsetInternal(dex_file, offset_in_code_item, GetQuickeningInfo());
-}
-
-const uint8_t* VdexFile::GetQuickenedInfoOf(const DexFile& dex_file,
- uint32_t code_item_offset) const {
+ArrayRef<const uint8_t> VdexFile::GetQuickenedInfoOf(const DexFile& dex_file,
+ uint32_t dex_method_idx) const {
ArrayRef<const uint8_t> quickening_info = GetQuickeningInfo();
- uint32_t quickening_offset = GetQuickeningInfoOffsetFrom(
- dex_file, dex_file.GetCodeItem(code_item_offset)->debug_info_off_, quickening_info);
-
- return GetQuickeningInfoAt(quickening_info, quickening_offset).data();
-}
-
-bool VdexFile::CanEncodeQuickenedData(const DexFile& dex_file) {
- // We are going to use the debug_info_off_ to signal there is
- // quickened data, by putting a value greater than dex_file.Size(). So
- // make sure we have some room in the offset by checking that we have at least
- // half of the range of a uint32_t.
- return dex_file.Size() <= (std::numeric_limits<uint32_t>::max() >> 1);
+ if (quickening_info.empty()) {
+ return ArrayRef<const uint8_t>();
+ }
+ const uint32_t quickening_offset = GetQuickeningInfoOffset(
+ GetQuickenInfoOffsetTable(dex_file, quickening_info),
+ dex_method_idx,
+ quickening_info);
+ return GetQuickeningInfoAt(quickening_info, quickening_offset);
}
} // namespace art
diff --git a/runtime/vdex_file.h b/runtime/vdex_file.h
index f78335d347..4687a393e2 100644
--- a/runtime/vdex_file.h
+++ b/runtime/vdex_file.h
@@ -24,6 +24,7 @@
#include "base/macros.h"
#include "mem_map.h"
#include "os.h"
+#include "quicken_info.h"
namespace art {
@@ -35,18 +36,17 @@ class DexFile;
// File format:
// VdexFile::Header fixed-length header
//
-// DEX[0] array of the input DEX files
-// DEX[1] the bytecode may have been quickened
+// quicken_table_off[0] offset into QuickeningInfo section for offset table for DEX[0].
+// DEX[0] array of the input DEX files, the bytecode may have been quickened.
+// quicken_table_off[1]
+// DEX[1]
// ...
// DEX[D]
// VerifierDeps
// uint8[D][] verification dependencies
// QuickeningInfo
// uint8[D][] quickening data
-// unaligned_uint32_t[D][2][] table of offsets pair:
-// uint32_t[0] contains original CodeItem::debug_info_off_
-// uint32_t[1] contains quickening data offset from the start
-// of QuickeningInfo
+// uint32[D][] quickening data offset tables
class VdexFile {
public:
@@ -84,8 +84,8 @@ class VdexFile {
private:
static constexpr uint8_t kVdexMagic[] = { 'v', 'd', 'e', 'x' };
- // Last update: Lookup-friendly encoding for quickening info.
- static constexpr uint8_t kVdexVersion[] = { '0', '1', '1', '\0' };
+ // Last update: Side table for debug info offsets in compact dex.
+ static constexpr uint8_t kVdexVersion[] = { '0', '1', '4', '\0' };
uint8_t magic_[4];
uint8_t version_[4];
@@ -98,6 +98,7 @@ class VdexFile {
};
typedef uint32_t VdexChecksum;
+ using QuickeningTableOffsetType = uint32_t;
explicit VdexFile(MemMap* mmap) : mmap_(mmap) {}
@@ -204,29 +205,42 @@ class VdexFile {
// `decompile_return_instruction` controls if RETURN_VOID_BARRIER instructions are
// decompiled to RETURN_VOID instructions using the slower ClassDataItemIterator
// instead of the faster QuickeningInfoIterator.
- static void Unquicken(const std::vector<const DexFile*>& dex_files,
- ArrayRef<const uint8_t> quickening_info,
- bool decompile_return_instruction);
+ // Always unquickens using the vdex dex files as the source for quicken tables.
+ void Unquicken(const std::vector<const DexFile*>& target_dex_files,
+ bool decompile_return_instruction) const;
// Fully unquicken `target_dex_file` based on `quickening_info`.
- static void UnquickenDexFile(const DexFile& target_dex_file,
- ArrayRef<const uint8_t> quickening_info,
- bool decompile_return_instruction);
+ void UnquickenDexFile(const DexFile& target_dex_file,
+ const DexFile& source_dex_file,
+ bool decompile_return_instruction) const;
- // Return the quickening info of the given code item.
- const uint8_t* GetQuickenedInfoOf(const DexFile& dex_file, uint32_t code_item_offset) const;
+ // Return the quickening info of a given method index (or null if it's empty).
+ ArrayRef<const uint8_t> GetQuickenedInfoOf(const DexFile& dex_file,
+ uint32_t dex_method_idx) const;
- uint32_t GetDebugInfoOffset(const DexFile& dex_file, uint32_t offset_in_code_item) const;
+ private:
+ uint32_t GetQuickeningInfoTableOffset(const uint8_t* source_dex_begin) const;
- static bool CanEncodeQuickenedData(const DexFile& dex_file);
+ // Source dex must be the in the vdex file.
+ void UnquickenDexFile(const DexFile& target_dex_file,
+ const uint8_t* source_dex_begin,
+ bool decompile_return_instruction) const;
- static constexpr uint32_t kNoQuickeningInfoOffset = -1;
+ QuickenInfoOffsetTableAccessor GetQuickenInfoOffsetTable(
+ const DexFile& dex_file,
+ const ArrayRef<const uint8_t>& quickening_info) const;
+
+ QuickenInfoOffsetTableAccessor GetQuickenInfoOffsetTable(
+ const uint8_t* source_dex_begin,
+ uint32_t num_method_ids,
+ const ArrayRef<const uint8_t>& quickening_info) const;
- private:
bool HasDexSection() const {
return GetHeader().GetDexSize() != 0;
}
+ bool ContainsDexFile(const DexFile& dex_file) const;
+
const uint8_t* DexBegin() const {
return Begin() + sizeof(Header) + GetHeader().GetSizeOfChecksumsSection();
}
@@ -235,8 +249,6 @@ class VdexFile {
return DexBegin() + GetHeader().GetDexSize();
}
- uint32_t GetDexFileIndex(const DexFile& dex_file) const;
-
std::unique_ptr<MemMap> mmap_;
DISALLOW_COPY_AND_ASSIGN(VdexFile);
diff --git a/test/983-source-transform-verify/source_transform.cc b/test/983-source-transform-verify/source_transform.cc
index e9cb35e944..c076d1521f 100644
--- a/test/983-source-transform-verify/source_transform.cc
+++ b/test/983-source-transform-verify/source_transform.cc
@@ -28,6 +28,7 @@
#include "base/macros.h"
#include "bytecode_utils.h"
#include "dex/code_item_accessors-inl.h"
+#include "dex/art_dex_file_loader.h"
#include "dex/dex_file.h"
#include "dex/dex_file_loader.h"
#include "dex/dex_instruction.h"
@@ -66,15 +67,16 @@ void JNICALL CheckDexFileHook(jvmtiEnv* jvmti_env ATTRIBUTE_UNUSED,
if (IsJVM()) {
return;
}
+ const ArtDexFileLoader dex_file_loader;
std::string error;
- std::unique_ptr<const DexFile> dex(DexFileLoader::Open(class_data,
- class_data_len,
- "fake_location.dex",
- /*location_checksum*/ 0,
- /*oat_dex_file*/ nullptr,
- /*verify*/ true,
- /*verify_checksum*/ true,
- &error));
+ std::unique_ptr<const DexFile> dex(dex_file_loader.Open(class_data,
+ class_data_len,
+ "fake_location.dex",
+ /*location_checksum*/ 0,
+ /*oat_dex_file*/ nullptr,
+ /*verify*/ true,
+ /*verify_checksum*/ true,
+ &error));
if (dex.get() == nullptr) {
std::cout << "Failed to verify dex file for " << name << " because " << error << std::endl;
return;
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index 132099a45d..631b14afc8 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -466,10 +466,9 @@ if [ "$USE_JVMTI" = "y" ]; then
if [[ "$TEST_IS_NDEBUG" = "y" ]]; then
plugin=libopenjdkjvmti.so
fi
+ # We used to add flags here that made the runtime debuggable but that is not
+ # needed anymore since the plugin can do it for us now.
FLAGS="${FLAGS} -Xplugin:${plugin}"
- FLAGS="${FLAGS} -Xcompiler-option --debuggable"
- # Always make the compilation be debuggable.
- COMPILE_FLAGS="${COMPILE_FLAGS} --debuggable"
fi
fi