diff options
author | 2018-01-12 09:06:14 +0000 | |
---|---|---|
committer | 2018-01-12 09:06:14 +0000 | |
commit | 6716941120ae9f47ba1b8ef8e79820c4b5640350 (patch) | |
tree | 76dd7d32703505d4ab44c0b55a7ecaf3ff66a94e | |
parent | 7a26f948204377130be7b738d70d7365c86a804b (diff) |
Revert "Move quickening info logic to its own table"
Bug: 71605148
Bug: 63756964
Seems to fail on armv7.
This reverts commit f5245188d9c61f6b90eb30cca0875fbdcc493b15.
Change-Id: I37786c04a8260ae3ec4a2cd73710126783c3ae7e
26 files changed, 301 insertions, 396 deletions
diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc index 308e75d9c1..52cb217980 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(); - builder.AddIndex(info.dex_member_index); + // 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)); } 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 869865956c..c0886d0185 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -424,6 +424,10 @@ 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 a1a5692ef6..af537dd653 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, - ArrayRef<const uint8_t> interpreter_metadata, + const uint8_t* interpreter_metadata, VariableSizedHandleScope* handles) : graph_(graph), dex_file_(&graph->GetDexFile()), @@ -70,6 +70,7 @@ 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 5a1914ce08..c16a3a928d 100644 --- a/compiler/optimizing/builder.h +++ b/compiler/optimizing/builder.h @@ -18,7 +18,6 @@ #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" @@ -41,7 +40,7 @@ class HGraphBuilder : public ValueObject { CompilerDriver* driver, CodeGenerator* code_generator, OptimizingCompilerStats* compiler_stats, - ArrayRef<const uint8_t> interpreter_metadata, + const uint8_t* interpreter_metadata, VariableSizedHandleScope* handles); // Only for unit testing. @@ -74,7 +73,7 @@ class HGraphBuilder : public ValueObject { CodeGenerator* const code_generator_; OptimizingCompilerStats* const compilation_stats_; - const ArrayRef<const uint8_t> interpreter_metadata_; + const uint8_t* const interpreter_metadata_; VariableSizedHandleScope* const handles_; const DataType::Type return_type_; diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc index 64a1eccf60..72a93c1f77 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, - ArrayRef<const uint8_t> interpreter_metadata, + 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 4428c53277..708a09711a 100644 --- a/compiler/optimizing/instruction_builder.h +++ b/compiler/optimizing/instruction_builder.h @@ -17,7 +17,6 @@ #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" @@ -58,7 +57,7 @@ class HInstructionBuilder : public ValueObject { const DexCompilationUnit* outer_compilation_unit, CompilerDriver* compiler_driver, CodeGenerator* code_generator, - ArrayRef<const uint8_t> interpreter_metadata, + const uint8_t* interpreter_metadata, OptimizingCompilerStats* compiler_stats, VariableSizedHandleScope* handles, ScopedArenaAllocator* local_allocator); diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index 8966d560db..f4115f7e7b 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -783,7 +783,7 @@ CodeGenerator* OptimizingCompiler::TryCompile(ArenaAllocator* allocator, compiler_driver->GetCompilerOptions().GetDebuggable(), osr); - ArrayRef<const uint8_t> interpreter_metadata; + const uint8_t* interpreter_metadata = nullptr; // 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 */ ArrayRef<const uint8_t>(), + /* interpreter_metadata */ nullptr, handles); builder.BuildIntrinsicGraph(method); } diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index 06cc71b4db..8d0d89ed5c 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -1807,7 +1807,9 @@ 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). - input_vdex_file_->Unquicken(dex_files_, /* decompile_return_instruction */ false); + VdexFile::Unquicken(dex_files_, + input_vdex_file_->GetQuickeningInfo(), + /* 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. diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc index cec7960682..16d70daddf 100644 --- a/dex2oat/linker/oat_writer.cc +++ b/dex2oat/linker/oat_writer.cc @@ -57,7 +57,6 @@ #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" @@ -2618,54 +2617,42 @@ bool OatWriter::WriteRodata(OutputStream* out) { return true; } -class OatWriter::WriteQuickeningInfoMethodVisitor { +class OatWriter::WriteQuickeningInfoMethodVisitor : public DexMethodVisitor { public: - WriteQuickeningInfoMethodVisitor(OatWriter* writer, OutputStream* out) - : writer_(writer), - out_(out) {} - - 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(); - } - - // 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()); + 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) {} - // 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_); - } + 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)); - if (!out_->WriteFully(map.data(), length)) { - PLOG(ERROR) << "Failed to write quickening info for " << method_ref.PrettyMethod() - << " to " << out_->GetLocation(); + 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(); return false; } - written_bytes_ += length; + written_bytes_ += sizeof(length) + length; + offset_ += sizeof(length) + length; } } + return true; } @@ -2673,59 +2660,71 @@ class OatWriter::WriteQuickeningInfoMethodVisitor { 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_ = 0u; - // Map of offsets for quicken info related to method indices. - SafeMap<const DexFile*, std::vector<uint32_t>> quicken_info_offset_indices_; + size_t written_bytes_; + // Maps quickening map to its offset in the file. + SafeMap<const uint8_t*, uint32_t>* offset_map_; }; -class OatWriter::WriteQuickeningInfoOffsetsMethodVisitor { +class OatWriter::WriteQuickeningIndicesMethodVisitor { public: - 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) + WriteQuickeningIndicesMethodVisitor(OutputStream* out, + uint32_t quickening_info_bytes, + const SafeMap<const uint8_t*, uint32_t>& offset_map) : out_(out), - start_offset_(start_offset), - quicken_info_offset_indices_(quicken_info_offset_indices), - out_table_offsets_(out_table_offsets) {} + quickening_info_bytes_(quickening_info_bytes), + written_bytes_(0u), + offset_map_(offset_map) {} - bool VisitDexMethods(const std::vector<const DexFile*>& dex_files) { + bool VisitDexMethods(const std::vector<const DexFile*>& dex_files, const CompilerDriver& driver) { for (const DexFile* dex_file : dex_files) { - 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; + 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); + } + } } - written_bytes_ += length; } return true; } @@ -2736,16 +2735,14 @@ class OatWriter::WriteQuickeningInfoOffsetsMethodVisitor { private: OutputStream* const out_; - 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_; + 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_; }; 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); @@ -2756,71 +2753,36 @@ bool OatWriter::WriteQuickeningInfo(OutputStream* vdex_out) { return false; } - size_t current_offset = start_offset; - if (compiler_driver_->GetCompilerOptions().IsQuickeningCompilationEnabled()) { + if (compiler_driver_->GetCompilerOptions().IsAnyCompilationEnabled()) { std::vector<uint32_t> dex_files_indices; - WriteQuickeningInfoMethodVisitor write_quicken_info_visitor(this, vdex_out); - if (!write_quicken_info_visitor.VisitDexMethods(*dex_files_)) { + SafeMap<const uint8_t*, uint32_t> offset_map; + WriteQuickeningInfoMethodVisitor visitor1(this, vdex_out, start_offset, &offset_map); + if (!VisitDexMethods(&visitor1)) { PLOG(ERROR) << "Failed to write the vdex quickening info. File: " << vdex_out->GetLocation(); return false; } - 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(); + 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(); return false; } - 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." + + if (!vdex_out->Flush()) { + PLOG(ERROR) << "Failed to flush stream after writing quickening info." << " File: " << vdex_out->GetLocation(); return false; } - ++index; - } - if (!vdex_out->Flush()) { - PLOG(ERROR) << "Failed to flush stream after writing quickening info." - << " File: " << vdex_out->GetLocation(); - return false; + size_quickening_info_ = visitor1.GetNumberOfWrittenBytes() + + visitor2.GetNumberOfWrittenBytes(); + } else { + // We know we did not quicken. + size_quickening_info_ = 0; } - size_quickening_info_ = current_offset - start_offset; } else { // We know we did not quicken. size_quickening_info_ = 0; @@ -3395,14 +3357,8 @@ 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_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; + size_dex_file_alignment_ += start_offset - initial_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. diff --git a/dex2oat/linker/oat_writer.h b/dex2oat/linker/oat_writer.h index 824b395b02..c9deea9a4b 100644 --- a/dex2oat/linker/oat_writer.h +++ b/dex2oat/linker/oat_writer.h @@ -275,7 +275,7 @@ class OatWriter { class WriteMapMethodVisitor; class WriteMethodInfoVisitor; class WriteQuickeningInfoMethodVisitor; - class WriteQuickeningInfoOffsetsMethodVisitor; + class WriteQuickeningIndicesMethodVisitor; // 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 321a2e4d46..99bc1adabb 100644 --- a/dex2oat/linker/oat_writer_test.cc +++ b/dex2oat/linker/oat_writer_test.cc @@ -659,11 +659,7 @@ 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(); - 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); - } + 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 c2532e4235..2c98e12741 100644 --- a/dexdump/dexdump.cc +++ b/dexdump/dexdump.cc @@ -1186,7 +1186,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); + CodeItemDebugInfoAccessor accessor(*pDexFile, pCode, pDexFile->GetDebugInfoOffset(pCode)); fprintf(gOutFile, " registers : %d\n", accessor.RegistersSize()); fprintf(gOutFile, " ins : %d\n", accessor.InsSize()); diff --git a/dexlist/dexlist.cc b/dexlist/dexlist.cc index 28370aac44..556938b563 100644 --- a/dexlist/dexlist.cc +++ b/dexlist/dexlist.cc @@ -100,7 +100,7 @@ static void dumpMethod(const DexFile* pDexFile, if (pCode == nullptr || codeOffset == 0) { return; } - CodeItemDebugInfoAccessor accessor(*pDexFile, pCode); + CodeItemDebugInfoAccessor accessor(*pDexFile, pCode, pDexFile->GetDebugInfoOffset(pCode)); // Method information. const DexFile::MethodId& pMethodId = pDexFile->GetMethodId(idx); diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index f53846c04d..6668dace89 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -718,6 +718,7 @@ 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/fixed_up_dex_file.cc b/openjdkjvmti/fixed_up_dex_file.cc index 731566f267..da7d60ac2f 100644 --- a/openjdkjvmti/fixed_up_dex_file.cc +++ b/openjdkjvmti/fixed_up_dex_file.cc @@ -62,7 +62,8 @@ static void DoDexUnquicken(const art::DexFile& new_dex_file, const art::DexFile& if (vdex == nullptr) { return; } - vdex->UnquickenDexFile(new_dex_file, original_dex_file, /* decompile_return_instruction */true); + art::VdexFile::UnquickenDexFile( + new_dex_file, vdex->GetQuickeningInfo(), /* decompile_return_instruction */true); } std::unique_ptr<FixedUpDexFile> FixedUpDexFile::Create(const art::DexFile& original) { diff --git a/runtime/art_method.cc b/runtime/art_method.cc index 96468bba60..44a5dde485 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; } -ArrayRef<const uint8_t> ArtMethod::GetQuickenedInfo() { +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 ArrayRef<const uint8_t>(); + return nullptr; } - return oat_dex_file->GetOatFile()->GetVdexFile()->GetQuickenedInfoOf(dex_file, - GetDexMethodIndex()); + return oat_dex_file->GetOatFile()->GetVdexFile()->GetQuickenedInfoOf( + dex_file, GetCodeItemOffset()); } const OatQuickMethodHeader* ArtMethod::GetOatQuickMethodHeader(uintptr_t pc) { diff --git a/runtime/art_method.h b/runtime/art_method.h index cd06354859..c4a586ed92 100644 --- a/runtime/art_method.h +++ b/runtime/art_method.h @@ -21,7 +21,6 @@ #include <android-base/logging.h> -#include "base/array_ref.h" #include "base/bit_utils.h" #include "base/casts.h" #include "base/enums.h" @@ -663,7 +662,7 @@ class ArtMethod FINAL { return hotness_count_; } - ArrayRef<const uint8_t> GetQuickenedInfo() REQUIRES_SHARED(Locks::mutator_lock_); + const uint8_t* GetQuickenedInfo() REQUIRES_SHARED(Locks::mutator_lock_); // Returns the method header for the compiled code containing 'pc'. Note that runtime // methods will return null for this method, as they are not oat based. diff --git a/runtime/dex/code_item_accessors-inl.h b/runtime/dex/code_item_accessors-inl.h index 01a2b2f8e6..2792dc0663 100644 --- a/runtime/dex/code_item_accessors-inl.h +++ b/runtime/dex/code_item_accessors-inl.h @@ -36,6 +36,14 @@ inline CodeItemDataAccessor::CodeItemDataAccessor(ArtMethod* method) 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_)); +} + } // namespace art #endif // ART_RUNTIME_DEX_CODE_ITEM_ACCESSORS_INL_H_ diff --git a/runtime/dex/code_item_accessors-no_art-inl.h b/runtime/dex/code_item_accessors-no_art-inl.h index a613559644..baea856e71 100644 --- a/runtime/dex/code_item_accessors-no_art-inl.h +++ b/runtime/dex/code_item_accessors-no_art-inl.h @@ -180,14 +180,6 @@ inline bool CodeItemDebugInfoAccessor::DecodeDebugLocalInfo(bool is_static, context); } -inline CodeItemDebugInfoAccessor::CodeItemDebugInfoAccessor(const DexFile& dex_file, - const DexFile::CodeItem* code_item) { - if (code_item == nullptr) { - return; - } - Init(dex_file, code_item, code_item->debug_info_off_); -} - } // namespace art #endif // ART_RUNTIME_DEX_CODE_ITEM_ACCESSORS_NO_ART_INL_H_ diff --git a/runtime/dex/dex_file.h b/runtime/dex/dex_file.h index 9b31a75ac5..c2a36ce01a 100644 --- a/runtime/dex/dex_file.h +++ b/runtime/dex/dex_file.h @@ -303,6 +303,15 @@ class DexFile { // Raw code_item. 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) @@ -313,7 +322,12 @@ class DexFile { 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. + // 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. @@ -323,6 +337,7 @@ class DexFile { 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); }; @@ -697,6 +712,15 @@ 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_to_dex_decompiler.cc b/runtime/dex_to_dex_decompiler.cc index 7887191713..e1c07baede 100644 --- a/runtime/dex_to_dex_decompiler.cc +++ b/runtime/dex_to_dex_decompiler.cc @@ -36,7 +36,8 @@ class DexDecompiler { const ArrayRef<const uint8_t>& quickened_info, bool decompile_return_instruction) : code_item_accessor_(dex_file, &code_item), - quicken_info_(quickened_info), + quicken_info_(quickened_info.data()), + quicken_info_number_of_indices_(QuickenInfoTable::NumberOfIndices(quickened_info.size())), decompile_return_instruction_(decompile_return_instruction) {} bool Decompile(); @@ -71,7 +72,7 @@ class DexDecompiler { } uint16_t NextIndex() { - DCHECK_LT(quicken_index_, quicken_info_.NumIndices()); + DCHECK_LT(quicken_index_, quicken_info_number_of_indices_); const uint16_t ret = quicken_info_.GetData(quicken_index_); quicken_index_++; return ret; @@ -79,6 +80,7 @@ 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; @@ -102,7 +104,7 @@ bool DexDecompiler::Decompile() { break; case Instruction::NOP: - if (quicken_info_.NumIndices() > 0) { + if (quicken_info_number_of_indices_ > 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. @@ -179,14 +181,14 @@ bool DexDecompiler::Decompile() { } } - if (quicken_index_ != quicken_info_.NumIndices()) { + if (quicken_index_ != quicken_info_number_of_indices_) { 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_.NumIndices(); + << " Expected: " << quicken_info_number_of_indices_; return false; } } diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc index 110b60e9e0..c6664411e4 100644 --- a/runtime/oat_file.cc +++ b/runtime/oat_file.cc @@ -1534,6 +1534,21 @@ 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 { diff --git a/runtime/oat_file.h b/runtime/oat_file.h index bf22e0b88b..e9f7edca61 100644 --- a/runtime/oat_file.h +++ b/runtime/oat_file.h @@ -115,6 +115,10 @@ 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/quicken_info.h b/runtime/quicken_info.h index 52eca61c06..ce11f3c19b 100644 --- a/runtime/quicken_info.h +++ b/runtime/quicken_info.h @@ -17,93 +17,15 @@ #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 { -// 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. +// QuickenInfoTable is a table of 16 bit dex indices. There is one slot fo every instruction that is +// possibly dequickenable. class QuickenInfoTable { public: - 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) {} + explicit QuickenInfoTable(const uint8_t* data) : data_(data) {} bool IsNull() const { return data_ == nullptr; @@ -122,18 +44,8 @@ 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* data_; - const uint32_t num_elements_; + const uint8_t* const data_; DISALLOW_COPY_AND_ASSIGN(QuickenInfoTable); }; diff --git a/runtime/vdex_file.cc b/runtime/vdex_file.cc index aa77b21757..3ac4aa24c9 100644 --- a/runtime/vdex_file.cc +++ b/runtime/vdex_file.cc @@ -28,7 +28,6 @@ #include "dex/dex_file.h" #include "dex/dex_file_loader.h" #include "dex_to_dex_decompiler.h" -#include "quicken_info.h" namespace art { @@ -149,8 +148,9 @@ std::unique_ptr<VdexFile> VdexFile::OpenAtAddress(uint8_t* mmap_addr, if (!vdex->OpenAllDexFiles(&unique_ptr_dex_files, error_msg)) { return nullptr; } - vdex->Unquicken(MakeNonOwningPointerVector(unique_ptr_dex_files), - /* decompile_return_instruction */ false); + Unquicken(MakeNonOwningPointerVector(unique_ptr_dex_files), + vdex->GetQuickeningInfo(), + /* 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; } @@ -163,15 +163,14 @@ 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() + sizeof(QuickeningTableOffsetType) : nullptr; + return HasDexSection() ? DexBegin() : 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 + sizeof(QuickeningTableOffsetType); + return (data == DexEnd()) ? nullptr : data; } } @@ -201,68 +200,64 @@ bool VdexFile::OpenAllDexFiles(std::vector<std::unique_ptr<const DexFile>>* dex_ return true; } -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); +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; } - DCHECK(source_dex == nullptr); -} -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]; -} - -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); + for (uint32_t i = 0; i < dex_files.size(); ++i) { + UnquickenDexFile(*dex_files[i], quickening_info, decompile_return_instruction); + } } -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); -} +typedef __attribute__((__aligned__(1))) uint32_t unaligned_uint32_t; -static ArrayRef<const uint8_t> GetQuickeningInfoAt(const ArrayRef<const uint8_t>& quickening_info, - uint32_t quickening_offset) { - ArrayRef<const uint8_t> remaining = quickening_info.SubArray(quickening_offset); - return remaining.SubArray(0u, QuickenInfoTable::SizeInBytes(remaining)); +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); } -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; +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; } - return offset; + if (quickening_info.size() == 0) { + // No quickening info. + return VdexFile::kNoQuickeningInfoOffset; + } + uint32_t quickening_offset = offset_in_code_item - dex_file.Size(); + + // 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)); } -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); +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)); } void VdexFile::UnquickenDexFile(const DexFile& target_dex_file, - const uint8_t* source_dex_begin, - bool decompile_return_instruction) const { - ArrayRef<const uint8_t> quickening_info = GetQuickeningInfo(); + 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. @@ -277,20 +272,19 @@ 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(); - 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); + 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)); } optimizer::ArtDecompileDEX( target_dex_file, *code_item, - quicken_data, + GetQuickeningInfoAt(quickening_info, quickening_offset), decompile_return_instruction); } } @@ -298,17 +292,25 @@ void VdexFile::UnquickenDexFile(const DexFile& target_dex_file, } } -ArrayRef<const uint8_t> VdexFile::GetQuickenedInfoOf(const DexFile& dex_file, - uint32_t dex_method_idx) const { +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> quickening_info = GetQuickeningInfo(); - 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); + 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); } } // namespace art diff --git a/runtime/vdex_file.h b/runtime/vdex_file.h index 22599b0b13..f78335d347 100644 --- a/runtime/vdex_file.h +++ b/runtime/vdex_file.h @@ -24,7 +24,6 @@ #include "base/macros.h" #include "mem_map.h" #include "os.h" -#include "quicken_info.h" namespace art { @@ -36,17 +35,18 @@ class DexFile; // File format: // VdexFile::Header fixed-length header // -// 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[0] array of the input DEX files +// DEX[1] the bytecode may have been quickened // ... // DEX[D] // VerifierDeps // uint8[D][] verification dependencies // QuickeningInfo // uint8[D][] quickening data -// uint32[D][] quickening data offset tables +// 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 class VdexFile { public: @@ -84,8 +84,8 @@ class VdexFile { private: static constexpr uint8_t kVdexMagic[] = { 'v', 'd', 'e', 'x' }; - // Last update: Compact quicken info tables that don't modify the dex code items. - static constexpr uint8_t kVdexVersion[] = { '0', '1', '2', '\0' }; + // Last update: Lookup-friendly encoding for quickening info. + static constexpr uint8_t kVdexVersion[] = { '0', '1', '1', '\0' }; uint8_t magic_[4]; uint8_t version_[4]; @@ -98,7 +98,6 @@ class VdexFile { }; typedef uint32_t VdexChecksum; - using QuickeningTableOffsetType = uint32_t; explicit VdexFile(MemMap* mmap) : mmap_(mmap) {} @@ -205,42 +204,29 @@ 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. - // 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; + static void Unquicken(const std::vector<const DexFile*>& dex_files, + ArrayRef<const uint8_t> quickening_info, + bool decompile_return_instruction); // Fully unquicken `target_dex_file` based on `quickening_info`. - void UnquickenDexFile(const DexFile& target_dex_file, - const DexFile& source_dex_file, - bool decompile_return_instruction) const; + static void UnquickenDexFile(const DexFile& target_dex_file, + ArrayRef<const uint8_t> quickening_info, + bool decompile_return_instruction); - // 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; + // Return the quickening info of the given code item. + const uint8_t* GetQuickenedInfoOf(const DexFile& dex_file, uint32_t code_item_offset) const; - private: - uint32_t GetQuickeningInfoTableOffset(const uint8_t* source_dex_begin) const; - - // 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; + uint32_t GetDebugInfoOffset(const DexFile& dex_file, uint32_t offset_in_code_item) const; - QuickenInfoOffsetTableAccessor GetQuickenInfoOffsetTable( - const DexFile& dex_file, - const ArrayRef<const uint8_t>& quickening_info) const; + static bool CanEncodeQuickenedData(const DexFile& dex_file); - QuickenInfoOffsetTableAccessor GetQuickenInfoOffsetTable( - const uint8_t* source_dex_begin, - uint32_t num_method_ids, - const ArrayRef<const uint8_t>& quickening_info) const; + static constexpr uint32_t kNoQuickeningInfoOffset = -1; + 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(); } @@ -249,6 +235,8 @@ class VdexFile { return DexBegin() + GetHeader().GetDexSize(); } + uint32_t GetDexFileIndex(const DexFile& dex_file) const; + std::unique_ptr<MemMap> mmap_; DISALLOW_COPY_AND_ASSIGN(VdexFile); |