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
diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc
index 308e75d..52cb217 100644
--- a/compiler/dex/dex_to_dex_compiler.cc
+++ b/compiler/dex/dex_to_dex_compiler.cc
@@ -373,15 +373,15 @@
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 8698659..c0886d0 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -424,6 +424,10 @@
// 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 a1a5692..af537dd 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -43,7 +43,7 @@
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 @@
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 5a1914c..c16a3a9 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 @@
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 @@
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 64a1ecc..72a93c1 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -49,7 +49,7 @@
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 4428c53..708a097 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 @@
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 8966d56..f4115f7 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -783,7 +783,7 @@
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 @@
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 06cc71b..8d0d89e 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -1807,7 +1807,9 @@
// 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 cec7960..16d70da 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 @@
return true;
}
-class OatWriter::WriteQuickeningInfoMethodVisitor {
+class OatWriter::WriteQuickeningInfoMethodVisitor : public DexMethodVisitor {
public:
- WriteQuickeningInfoMethodVisitor(OatWriter* writer, OutputStream* out)
- : writer_(writer),
- out_(out) {}
+ 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) {}
- 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;
+ 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));
- // 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());
-
- // 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();
+ 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 @@
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);
+ 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);
+ }
+ }
}
-
- // 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;
}
@@ -2736,16 +2735,14 @@
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 @@
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;
+ size_quickening_info_ = visitor1.GetNumberOfWrittenBytes() +
+ visitor2.GetNumberOfWrittenBytes();
+ } else {
+ // We know we did not quicken.
+ size_quickening_info_ = 0;
}
- 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;
@@ -3395,14 +3357,8 @@
// 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 824b395..c9deea9 100644
--- a/dex2oat/linker/oat_writer.h
+++ b/dex2oat/linker/oat_writer.h
@@ -275,7 +275,7 @@
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 321a2e4..99bc1ad 100644
--- a/dex2oat/linker/oat_writer_test.cc
+++ b/dex2oat/linker/oat_writer_test.cc
@@ -659,11 +659,7 @@
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 c2532e4..2c98e12 100644
--- a/dexdump/dexdump.cc
+++ b/dexdump/dexdump.cc
@@ -1186,7 +1186,7 @@
*/
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 28370aa..556938b 100644
--- a/dexlist/dexlist.cc
+++ b/dexlist/dexlist.cc
@@ -100,7 +100,7 @@
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 f53846c..6668dac 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -718,6 +718,7 @@
}
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 731566f..da7d60a 100644
--- a/openjdkjvmti/fixed_up_dex_file.cc
+++ b/openjdkjvmti/fixed_up_dex_file.cc
@@ -62,7 +62,8 @@
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 96468bb..44a5dde 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -562,14 +562,14 @@
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 cd06354..c4a586e 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 @@
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 01a2b2f..2792dc0 100644
--- a/runtime/dex/code_item_accessors-inl.h
+++ b/runtime/dex/code_item_accessors-inl.h
@@ -36,6 +36,14 @@
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 a613559..baea856 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 @@
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 9b31a75..c2a36ce 100644
--- a/runtime/dex/dex_file.h
+++ b/runtime/dex/dex_file.h
@@ -303,6 +303,15 @@
// 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 @@
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 @@
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 @@
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 7887191..e1c07ba 100644
--- a/runtime/dex_to_dex_decompiler.cc
+++ b/runtime/dex_to_dex_decompiler.cc
@@ -36,7 +36,8 @@
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 @@
}
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 @@
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 @@
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 @@
}
}
- 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 110b60e..c666441 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -1534,6 +1534,21 @@
}
}
+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 bf22e0b..e9f7edc 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -115,6 +115,10 @@
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 52eca61..ce11f3c 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 @@
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 aa77b21..3ac4aa2 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 @@
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 @@
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 @@
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);
+
+ for (uint32_t i = 0; i < dex_files.size(); ++i) {
+ UnquickenDexFile(*dex_files[i], quickening_info, decompile_return_instruction);
+ }
}
-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];
+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);
}
-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);
-}
+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 DexFile& dex_file,
- const ArrayRef<const uint8_t>& quickening_info) const {
- return GetQuickenInfoOffsetTable(dex_file.Begin(), dex_file.NumMethodIds(), quickening_info);
+ // 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));
}
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 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;
+ 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 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,
- 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 @@
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 @@
}
}
-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 22599b0..f78335d 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 @@
// 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 @@
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 @@
};
typedef uint32_t VdexChecksum;
- using QuickeningTableOffsetType = uint32_t;
explicit VdexFile(MemMap* mmap) : mmap_(mmap) {}
@@ -205,42 +204,29 @@
// `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;
+
+ uint32_t GetDebugInfoOffset(const DexFile& dex_file, uint32_t offset_in_code_item) const;
+
+ static bool CanEncodeQuickenedData(const DexFile& dex_file);
+
+ static constexpr uint32_t kNoQuickeningInfoOffset = -1;
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;
-
- 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;
-
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 @@
return DexBegin() + GetHeader().GetDexSize();
}
+ uint32_t GetDexFileIndex(const DexFile& dex_file) const;
+
std::unique_ptr<MemMap> mmap_;
DISALLOW_COPY_AND_ASSIGN(VdexFile);