Use the quickened metadata to compile -QUICK opcodes.

Change-Id: I28a8d68921698bea81f54c95cc6e4c6d2c03f2b4
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index 1319f2c..52a3a15 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -804,7 +804,9 @@
       invoke_type = kDirect;
       break;
     case Instruction::INVOKE_VIRTUAL:
+    case Instruction::INVOKE_VIRTUAL_QUICK:
     case Instruction::INVOKE_VIRTUAL_RANGE:
+    case Instruction::INVOKE_VIRTUAL_RANGE_QUICK:
       invoke_type = kVirtual;
       break;
     case Instruction::INVOKE_INTERFACE:
@@ -1051,7 +1053,15 @@
                                              bool is_put) {
   uint32_t source_or_dest_reg = instruction.VRegA_22c();
   uint32_t obj_reg = instruction.VRegB_22c();
-  uint16_t field_index = instruction.VRegC_22c();
+  uint16_t field_index;
+  if (instruction.IsQuickened()) {
+    if (!CanDecodeQuickenedInfo()) {
+      return false;
+    }
+    field_index = LookupQuickenedInfo(dex_pc);
+  } else {
+    field_index = instruction.VRegC_22c();
+  }
 
   ScopedObjectAccess soa(Thread::Current());
   ArtField* resolved_field =
@@ -1560,6 +1570,17 @@
   }
 }
 
+bool HGraphBuilder::CanDecodeQuickenedInfo() const {
+  return interpreter_metadata_ != nullptr;
+}
+
+uint16_t HGraphBuilder::LookupQuickenedInfo(uint32_t dex_pc) {
+  DCHECK(interpreter_metadata_ != nullptr);
+  uint32_t dex_pc_in_map = DecodeUnsignedLeb128(&interpreter_metadata_);
+  DCHECK_EQ(dex_pc, dex_pc_in_map);
+  return DecodeUnsignedLeb128(&interpreter_metadata_);
+}
+
 bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32_t dex_pc) {
   if (current_block_ == nullptr) {
     return true;  // Dead code
@@ -1657,6 +1678,7 @@
       break;
     }
 
+    case Instruction::RETURN_VOID_NO_BARRIER:
     case Instruction::RETURN_VOID: {
       BuildReturn(instruction, Primitive::kPrimVoid);
       break;
@@ -1705,8 +1727,17 @@
     case Instruction::INVOKE_INTERFACE:
     case Instruction::INVOKE_STATIC:
     case Instruction::INVOKE_SUPER:
-    case Instruction::INVOKE_VIRTUAL: {
-      uint32_t method_idx = instruction.VRegB_35c();
+    case Instruction::INVOKE_VIRTUAL:
+    case Instruction::INVOKE_VIRTUAL_QUICK: {
+      uint16_t method_idx;
+      if (instruction.Opcode() == Instruction::INVOKE_VIRTUAL_QUICK) {
+        if (!CanDecodeQuickenedInfo()) {
+          return false;
+        }
+        method_idx = LookupQuickenedInfo(dex_pc);
+      } else {
+        method_idx = instruction.VRegB_35c();
+      }
       uint32_t number_of_vreg_arguments = instruction.VRegA_35c();
       uint32_t args[5];
       instruction.GetVarArgs(args);
@@ -1721,8 +1752,17 @@
     case Instruction::INVOKE_INTERFACE_RANGE:
     case Instruction::INVOKE_STATIC_RANGE:
     case Instruction::INVOKE_SUPER_RANGE:
-    case Instruction::INVOKE_VIRTUAL_RANGE: {
-      uint32_t method_idx = instruction.VRegB_3rc();
+    case Instruction::INVOKE_VIRTUAL_RANGE:
+    case Instruction::INVOKE_VIRTUAL_RANGE_QUICK: {
+      uint16_t method_idx;
+      if (instruction.Opcode() == Instruction::INVOKE_VIRTUAL_RANGE_QUICK) {
+        if (!CanDecodeQuickenedInfo()) {
+          return false;
+        }
+        method_idx = LookupQuickenedInfo(dex_pc);
+      } else {
+        method_idx = instruction.VRegB_3rc();
+      }
       uint32_t number_of_vreg_arguments = instruction.VRegA_3rc();
       uint32_t register_index = instruction.VRegC();
       if (!BuildInvoke(instruction, dex_pc, method_idx,
@@ -2375,12 +2415,19 @@
       break;
 
     case Instruction::IGET:
+    case Instruction::IGET_QUICK:
     case Instruction::IGET_WIDE:
+    case Instruction::IGET_WIDE_QUICK:
     case Instruction::IGET_OBJECT:
+    case Instruction::IGET_OBJECT_QUICK:
     case Instruction::IGET_BOOLEAN:
+    case Instruction::IGET_BOOLEAN_QUICK:
     case Instruction::IGET_BYTE:
+    case Instruction::IGET_BYTE_QUICK:
     case Instruction::IGET_CHAR:
-    case Instruction::IGET_SHORT: {
+    case Instruction::IGET_CHAR_QUICK:
+    case Instruction::IGET_SHORT:
+    case Instruction::IGET_SHORT_QUICK: {
       if (!BuildInstanceFieldAccess(instruction, dex_pc, false)) {
         return false;
       }
@@ -2388,12 +2435,19 @@
     }
 
     case Instruction::IPUT:
+    case Instruction::IPUT_QUICK:
     case Instruction::IPUT_WIDE:
+    case Instruction::IPUT_WIDE_QUICK:
     case Instruction::IPUT_OBJECT:
+    case Instruction::IPUT_OBJECT_QUICK:
     case Instruction::IPUT_BOOLEAN:
+    case Instruction::IPUT_BOOLEAN_QUICK:
     case Instruction::IPUT_BYTE:
+    case Instruction::IPUT_BYTE_QUICK:
     case Instruction::IPUT_CHAR:
-    case Instruction::IPUT_SHORT: {
+    case Instruction::IPUT_CHAR_QUICK:
+    case Instruction::IPUT_SHORT:
+    case Instruction::IPUT_SHORT_QUICK: {
       if (!BuildInstanceFieldAccess(instruction, dex_pc, true)) {
         return false;
       }
diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h
index 76610f5..ad5d923 100644
--- a/compiler/optimizing/builder.h
+++ b/compiler/optimizing/builder.h
@@ -39,7 +39,8 @@
                 const DexCompilationUnit* const outer_compilation_unit,
                 const DexFile* dex_file,
                 CompilerDriver* driver,
-                OptimizingCompilerStats* compiler_stats)
+                OptimizingCompilerStats* compiler_stats,
+                const uint8_t* interpreter_metadata)
       : arena_(graph->GetArena()),
         branch_targets_(graph->GetArena(), 0),
         locals_(graph->GetArena(), 0),
@@ -55,7 +56,8 @@
         code_start_(nullptr),
         latest_result_(nullptr),
         can_use_baseline_for_string_init_(true),
-        compilation_stats_(compiler_stats) {}
+        compilation_stats_(compiler_stats),
+        interpreter_metadata_(interpreter_metadata) {}
 
   // Only for unit testing.
   HGraphBuilder(HGraph* graph, Primitive::Type return_type = Primitive::kPrimInt)
@@ -120,6 +122,9 @@
                             const DexFile::CodeItem& code_item,
                             const DexFile::TryItem& try_item);
 
+  bool CanDecodeQuickenedInfo() const;
+  uint16_t LookupQuickenedInfo(uint32_t dex_pc);
+
   void InitializeLocals(uint16_t count);
   HLocal* GetLocalAt(int register_index) const;
   void UpdateLocal(int register_index, HInstruction* instruction) const;
@@ -307,6 +312,8 @@
 
   OptimizingCompilerStats* compilation_stats_;
 
+  const uint8_t* interpreter_metadata_;
+
   DISALLOW_COPY_AND_ASSIGN(HGraphBuilder);
 };
 
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index 3efe7c7..cea7dd9 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -326,7 +326,8 @@
                         &outer_compilation_unit_,
                         resolved_method->GetDexFile(),
                         compiler_driver_,
-                        &inline_stats);
+                        &inline_stats,
+                        resolved_method->GetQuickenedInfo());
 
   if (!builder.BuildGraph(*code_item)) {
     VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file)
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index aeb1ae2..03141d2 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -35,6 +35,7 @@
 #include "dex/verified_method.h"
 #include "dex/verification_results.h"
 #include "driver/compiler_driver.h"
+#include "driver/compiler_driver-inl.h"
 #include "driver/compiler_options.h"
 #include "driver/dex_compilation_unit.h"
 #include "elf_writer_quick.h"
@@ -565,7 +566,7 @@
   }
 
   DexCompilationUnit dex_compilation_unit(
-    nullptr, class_loader, art::Runtime::Current()->GetClassLinker(), dex_file, code_item,
+    nullptr, class_loader, Runtime::Current()->GetClassLinker(), dex_file, code_item,
     class_def_idx, method_idx, access_flags,
     compiler_driver->GetVerifiedMethod(&dex_file, method_idx));
 
@@ -602,12 +603,25 @@
                              visualizer_output_.get(),
                              compiler_driver);
 
+  const uint8_t* interpreter_metadata = nullptr;
+  {
+    ScopedObjectAccess soa(Thread::Current());
+    StackHandleScope<4> hs(soa.Self());
+    ClassLinker* class_linker = dex_compilation_unit.GetClassLinker();
+    Handle<mirror::DexCache> dex_cache(hs.NewHandle(class_linker->FindDexCache(dex_file)));
+    Handle<mirror::ClassLoader> loader(hs.NewHandle(
+        soa.Decode<mirror::ClassLoader*>(class_loader)));
+    ArtMethod* art_method = compiler_driver->ResolveMethod(
+        soa, dex_cache, loader, &dex_compilation_unit, method_idx, invoke_type);
+    interpreter_metadata = art_method->GetQuickenedInfo();
+  }
   HGraphBuilder builder(graph,
                         &dex_compilation_unit,
                         &dex_compilation_unit,
                         &dex_file,
                         compiler_driver,
-                        compilation_stats_.get());
+                        compilation_stats_.get(),
+                        interpreter_metadata);
 
   VLOG(compiler) << "Building " << method_name;
 
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index c78a851..7673418 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -35,6 +35,7 @@
 #include "mirror/object_array-inl.h"
 #include "mirror/object-inl.h"
 #include "mirror/string.h"
+#include "oat_file-inl.h"
 #include "scoped_thread_state_change.h"
 #include "well_known_classes.h"
 
@@ -561,4 +562,14 @@
   return true;
 }
 
+const uint8_t* ArtMethod::GetQuickenedInfo() {
+  bool found = false;
+  OatFile::OatMethod oat_method =
+      Runtime::Current()->GetClassLinker()->FindOatMethodFor(this, &found);
+  if (!found || (oat_method.GetQuickCode() != nullptr)) {
+    return nullptr;
+  }
+  return oat_method.GetVmapTable();
+}
+
 }  // namespace art
diff --git a/runtime/art_method.h b/runtime/art_method.h
index e8c47d9..4169c5e 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -336,6 +336,8 @@
   const uint8_t* GetVmapTable(const void* code_pointer, size_t pointer_size)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  const uint8_t* GetQuickenedInfo() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   CodeInfo GetOptimizedCodeInfo() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Callers should wrap the uint8_t* in a GcMap instance for convenient access.
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index e4f7b7a..b60cba4 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -406,6 +406,9 @@
   const void* GetOatMethodQuickCodeFor(ArtMethod* method)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  const OatFile::OatMethod FindOatMethodFor(ArtMethod* method, bool* found)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   pid_t GetClassesLockOwner();  // For SignalCatcher.
   pid_t GetDexLockOwner();  // For SignalCatcher.
 
@@ -484,9 +487,6 @@
   void DropFindArrayClassCache() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
  private:
-  const OatFile::OatMethod FindOatMethodFor(ArtMethod* method, bool* found)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
   OatFile& GetImageOatFile(gc::space::ImageSpace* space)
       LOCKS_EXCLUDED(dex_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/dex_instruction.h b/runtime/dex_instruction.h
index 0ddbf7c..df2d379 100644
--- a/runtime/dex_instruction.h
+++ b/runtime/dex_instruction.h
@@ -488,6 +488,12 @@
   // Returns true if the instruction allows control flow to go to the following instruction.
   bool CanFlowThrough() const;
 
+  // Returns true if the instruction is a quickened instruction.
+  bool IsQuickened() const {
+    return (kInstructionIndexTypes[Opcode()] == kIndexFieldOffset) ||
+        (kInstructionIndexTypes[Opcode()] == kIndexVtableOffset);
+  }
+
   // Returns true if this instruction is a switch.
   bool IsSwitch() const {
     return (kInstructionFlags[Opcode()] & kSwitch) != 0;