Move quickening info logic to its own table

Added a table that is indexed by dex method index. To prevent size
overhead, there is only one slot for each 16 method indices. This
means there is up to 15 loop iterations to get the quickening info
for a method. The quickening infos are now prefixed by a leb
encoded length. This allows methods that aren't quickened to only
have 1.25 bytes of space overhead.

The value was picked arbitrarily, there is little advantage to
increasing the value since the table only takes 1 byte per 4 method
indices currently. JIT benchmarks do not regress with the change.

There is a net space saving from removing 8 bytes from each
quickening info since most scenarios have more quickened methods than
compiled methods.

For getting quick access to the table, a 4 byte preheader was added
to each dex in the vdex file

Removed logic that stored the quickening info in the CodeItem
debug_info_offset field.

The change adds a small quicken table for each method index, this
means that filters that don't quicken will have a slight increase in
size. The worst case scenario is compiling all the methods, this
results in 0.3% larger vdex for this case. The change also disables
deduping since the quicken infos need to be in dex method index
order.

For filters that don't compile most methods like quicken and
speed-profile, there is space savings. For quicken, the vdex is 2%
smaller.

Bug: 71605148
Bug: 63756964
Test: test-art-host

Change-Id: I89cb679538811369c36b6ac8c40ea93135f813cd
diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc
index 52cb217..308e75d 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();
-      // Add the index.
-      quicken_data.push_back(static_cast<uint8_t>(info.dex_member_index >> 0));
-      quicken_data.push_back(static_cast<uint8_t>(info.dex_member_index >> 8));
+      builder.AddIndex(info.dex_member_index);
     }
     InstructionSet instruction_set = driver->GetInstructionSet();
     if (instruction_set == InstructionSet::kThumb2) {
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index c0886d0..8698659 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -424,10 +424,6 @@
     // 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 af537dd..a1a5692 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -43,7 +43,7 @@
                              CompilerDriver* driver,
                              CodeGenerator* code_generator,
                              OptimizingCompilerStats* compiler_stats,
-                             const uint8_t* interpreter_metadata,
+                             ArrayRef<const uint8_t> interpreter_metadata,
                              VariableSizedHandleScope* handles)
     : graph_(graph),
       dex_file_(&graph->GetDexFile()),
@@ -70,7 +70,6 @@
       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 c16a3a9..5a1914c 100644
--- a/compiler/optimizing/builder.h
+++ b/compiler/optimizing/builder.h
@@ -18,6 +18,7 @@
 #define ART_COMPILER_OPTIMIZING_BUILDER_H_
 
 #include "base/arena_object.h"
+#include "base/array_ref.h"
 #include "dex/code_item_accessors.h"
 #include "dex/dex_file-inl.h"
 #include "dex/dex_file.h"
@@ -40,7 +41,7 @@
                 CompilerDriver* driver,
                 CodeGenerator* code_generator,
                 OptimizingCompilerStats* compiler_stats,
-                const uint8_t* interpreter_metadata,
+                ArrayRef<const uint8_t> interpreter_metadata,
                 VariableSizedHandleScope* handles);
 
   // Only for unit testing.
@@ -73,7 +74,7 @@
   CodeGenerator* const code_generator_;
 
   OptimizingCompilerStats* const compilation_stats_;
-  const uint8_t* const interpreter_metadata_;
+  const ArrayRef<const uint8_t> interpreter_metadata_;
   VariableSizedHandleScope* const handles_;
   const DataType::Type return_type_;
 
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index 72a93c1..64a1ecc 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,
-                                         const uint8_t* interpreter_metadata,
+                                         ArrayRef<const uint8_t> interpreter_metadata,
                                          OptimizingCompilerStats* compiler_stats,
                                          VariableSizedHandleScope* handles,
                                          ScopedArenaAllocator* local_allocator)
diff --git a/compiler/optimizing/instruction_builder.h b/compiler/optimizing/instruction_builder.h
index 708a097..4428c53 100644
--- a/compiler/optimizing/instruction_builder.h
+++ b/compiler/optimizing/instruction_builder.h
@@ -17,6 +17,7 @@
 #ifndef ART_COMPILER_OPTIMIZING_INSTRUCTION_BUILDER_H_
 #define ART_COMPILER_OPTIMIZING_INSTRUCTION_BUILDER_H_
 
+#include "base/array_ref.h"
 #include "base/scoped_arena_allocator.h"
 #include "base/scoped_arena_containers.h"
 #include "data_type.h"
@@ -57,7 +58,7 @@
                       const DexCompilationUnit* outer_compilation_unit,
                       CompilerDriver* compiler_driver,
                       CodeGenerator* code_generator,
-                      const uint8_t* interpreter_metadata,
+                      ArrayRef<const uint8_t> interpreter_metadata,
                       OptimizingCompilerStats* compiler_stats,
                       VariableSizedHandleScope* handles,
                       ScopedArenaAllocator* local_allocator);
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index f4115f7..8966d56 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -783,7 +783,7 @@
       compiler_driver->GetCompilerOptions().GetDebuggable(),
       osr);
 
-  const uint8_t* interpreter_metadata = nullptr;
+  ArrayRef<const uint8_t> interpreter_metadata;
   // For AOT compilation, we may not get a method, for example if its class is erroneous.
   // JIT should always have a method.
   DCHECK(Runtime::Current()->IsAotCompiler() || method != nullptr);
@@ -940,7 +940,7 @@
                           compiler_driver,
                           codegen.get(),
                           compilation_stats_.get(),
-                          /* interpreter_metadata */ nullptr,
+                          /* interpreter_metadata */ ArrayRef<const uint8_t>(),
                           handles);
     builder.BuildIntrinsicGraph(method);
   }