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);