Add verifier support for dequickening

Also some cleanup.

Bug: 17950037

Change-Id: I1f50fe07f1558e9c4f78953b7afa639d7f310b3c
diff --git a/compiler/dex/verified_method.cc b/compiler/dex/verified_method.cc
index 17328c4..d684bc9 100644
--- a/compiler/dex/verified_method.cc
+++ b/compiler/dex/verified_method.cc
@@ -82,13 +82,13 @@
   size_t num_entries, ref_bitmap_bits, pc_bits;
   ComputeGcMapSizes(method_verifier, &num_entries, &ref_bitmap_bits, &pc_bits);
   // There's a single byte to encode the size of each bitmap.
-  if (ref_bitmap_bits >= (8 /* bits per byte */ * 8192 /* 13-bit size */ )) {
+  if (ref_bitmap_bits >= kBitsPerByte * 8192 /* 13-bit size */) {
     // TODO: either a better GC map format or per method failures
     method_verifier->Fail(verifier::VERIFY_ERROR_BAD_CLASS_HARD)
         << "Cannot encode GC map for method with " << ref_bitmap_bits << " registers";
     return false;
   }
-  size_t ref_bitmap_bytes = (ref_bitmap_bits + 7) / 8;
+  size_t ref_bitmap_bytes = RoundUp(ref_bitmap_bits, kBitsPerByte) / kBitsPerByte;
   // There are 2 bytes to encode the number of entries.
   if (num_entries >= 65536) {
     // TODO: Either a better GC map format or per method failures.
@@ -98,10 +98,10 @@
   }
   size_t pc_bytes;
   verifier::RegisterMapFormat format;
-  if (pc_bits <= 8) {
+  if (pc_bits <= kBitsPerByte) {
     format = verifier::kRegMapFormatCompact8;
     pc_bytes = 1;
-  } else if (pc_bits <= 16) {
+  } else if (pc_bits <= kBitsPerByte * 2) {
     format = verifier::kRegMapFormatCompact16;
     pc_bytes = 2;
   } else {
@@ -152,10 +152,10 @@
       verifier::RegisterLine* line = method_verifier->GetRegLine(i);
       for (size_t j = 0; j < code_item->registers_size_; j++) {
         if (line->GetRegisterType(method_verifier, j).IsNonZeroReferenceTypes()) {
-          DCHECK_LT(j / 8, map.RegWidth());
-          DCHECK_EQ((reg_bitmap[j / 8] >> (j % 8)) & 1, 1);
-        } else if ((j / 8) < map.RegWidth()) {
-          DCHECK_EQ((reg_bitmap[j / 8] >> (j % 8)) & 1, 0);
+          DCHECK_LT(j / kBitsPerByte, map.RegWidth());
+          DCHECK_EQ((reg_bitmap[j / kBitsPerByte] >> (j % kBitsPerByte)) & 1, 1);
+        } else if ((j / kBitsPerByte) < map.RegWidth()) {
+          DCHECK_EQ((reg_bitmap[j / kBitsPerByte] >> (j % kBitsPerByte)) & 1, 0);
         } else {
           // If a register doesn't contain a reference then the bitmap may be shorter than the line.
         }
@@ -190,6 +190,31 @@
   *log2_max_gc_pc = i;
 }
 
+void VerifiedMethod::GenerateDeQuickenMap(verifier::MethodVerifier* method_verifier) {
+  if (method_verifier->HasFailures()) {
+    return;
+  }
+  const DexFile::CodeItem* code_item = method_verifier->CodeItem();
+  const uint16_t* insns = code_item->insns_;
+  const Instruction* inst = Instruction::At(insns);
+  const Instruction* end = Instruction::At(insns + code_item->insns_size_in_code_units_);
+  for (; inst < end; inst = inst->Next()) {
+    const bool is_virtual_quick = inst->Opcode() == Instruction::INVOKE_VIRTUAL_QUICK;
+    const bool is_range_quick = inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE_QUICK;
+    if (is_virtual_quick || is_range_quick) {
+      uint32_t dex_pc = inst->GetDexPc(insns);
+      verifier::RegisterLine* line = method_verifier->GetRegLine(dex_pc);
+      mirror::ArtMethod* method = method_verifier->GetQuickInvokedMethod(inst, line,
+                                                                         is_range_quick);
+      CHECK(method != nullptr);
+      // The verifier must know what the type of the object was or else we would have gotten a
+      // failure. Put the dex method index in the dequicken map since we need this to get number of
+      // arguments in the compiler.
+      dequicken_map_.Put(dex_pc, method->ToMethodReference());
+    }
+  }
+}
+
 void VerifiedMethod::GenerateDevirtMap(verifier::MethodVerifier* method_verifier) {
   // It is risky to rely on reg_types for sharpening in cases of soft
   // verification, we might end up sharpening to a wrong implementation. Just abort.
@@ -203,10 +228,10 @@
   const Instruction* end = Instruction::At(insns + code_item->insns_size_in_code_units_);
 
   for (; inst < end; inst = inst->Next()) {
-    bool is_virtual   = (inst->Opcode() == Instruction::INVOKE_VIRTUAL) ||
-        (inst->Opcode() ==  Instruction::INVOKE_VIRTUAL_RANGE);
-    bool is_interface = (inst->Opcode() == Instruction::INVOKE_INTERFACE) ||
-        (inst->Opcode() == Instruction::INVOKE_INTERFACE_RANGE);
+    const bool is_virtual = inst->Opcode() == Instruction::INVOKE_VIRTUAL ||
+        inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE;
+    const bool is_interface = inst->Opcode() == Instruction::INVOKE_INTERFACE ||
+        inst->Opcode() == Instruction::INVOKE_INTERFACE_RANGE;
 
     if (!is_interface && !is_virtual) {
       continue;
@@ -214,8 +239,8 @@
     // Get reg type for register holding the reference to the object that will be dispatched upon.
     uint32_t dex_pc = inst->GetDexPc(insns);
     verifier::RegisterLine* line = method_verifier->GetRegLine(dex_pc);
-    bool is_range = (inst->Opcode() ==  Instruction::INVOKE_VIRTUAL_RANGE) ||
-        (inst->Opcode() ==  Instruction::INVOKE_INTERFACE_RANGE);
+    const bool is_range = inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE ||
+        inst->Opcode() == Instruction::INVOKE_INTERFACE_RANGE;
     const verifier::RegType&
         reg_type(line->GetRegisterType(method_verifier,
                                        is_range ? inst->VRegC_3rc() : inst->VRegC_35c()));
@@ -241,14 +266,14 @@
       continue;
     }
     // Find the concrete method.
-    mirror::ArtMethod* concrete_method = NULL;
+    mirror::ArtMethod* concrete_method = nullptr;
     if (is_interface) {
       concrete_method = reg_type.GetClass()->FindVirtualMethodForInterface(abstract_method);
     }
     if (is_virtual) {
       concrete_method = reg_type.GetClass()->FindVirtualMethodForVirtual(abstract_method);
     }
-    if (concrete_method == NULL || concrete_method->IsAbstract()) {
+    if (concrete_method == nullptr || concrete_method->IsAbstract()) {
       // In cases where concrete_method is not found, or is abstract, continue to the next invoke.
       continue;
     }
@@ -256,10 +281,7 @@
         concrete_method->GetDeclaringClass()->IsFinal()) {
       // If we knew exactly the class being dispatched upon, or if the target method cannot be
       // overridden record the target to be used in the compiler driver.
-      MethodReference concrete_ref(
-          concrete_method->GetDeclaringClass()->GetDexCache()->GetDexFile(),
-          concrete_method->GetDexMethodIndex());
-      devirt_map_.Put(dex_pc, concrete_ref);
+      devirt_map_.Put(dex_pc, concrete_method->ToMethodReference());
     }
   }
 }
diff --git a/compiler/dex/verified_method.h b/compiler/dex/verified_method.h
index 257e70c..fe9dfd1 100644
--- a/compiler/dex/verified_method.h
+++ b/compiler/dex/verified_method.h
@@ -85,12 +85,19 @@
   void GenerateDevirtMap(verifier::MethodVerifier* method_verifier)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  // Generate dequickening map into dequicken_map_.
+  void GenerateDeQuickenMap(verifier::MethodVerifier* method_verifier)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   // Generate safe case set into safe_cast_set_.
   void GenerateSafeCastSet(verifier::MethodVerifier* method_verifier)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   std::vector<uint8_t> dex_gc_map_;
   DevirtualizationMap devirt_map_;
+  // Dequicken map is required for having the compiler compiled quickened invokes. The quicken map
+  // enables us to get the dex method index so that we can get the required argument count.
+  DevirtualizationMap dequicken_map_;
   SafeCastSet safe_cast_set_;
 };
 
diff --git a/runtime/mirror/art_method.h b/runtime/mirror/art_method.h
index 64663ed..9b982b7 100644
--- a/runtime/mirror/art_method.h
+++ b/runtime/mirror/art_method.h
@@ -20,6 +20,7 @@
 #include "dex_file.h"
 #include "gc_root.h"
 #include "invoke_type.h"
+#include "method_reference.h"
 #include "modifiers.h"
 #include "object.h"
 #include "object_callbacks.h"
@@ -522,6 +523,10 @@
   uintptr_t ToNativeQuickPc(const uint32_t dex_pc, bool abort_on_failure = true)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  MethodReference ToMethodReference() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    return MethodReference(GetDexFile(), GetDexMethodIndex());
+  }
+
   // Find the catch block for the given exception type and dex_pc. When a catch block is found,
   // indicates whether the found catch block is responsible for clearing the exception or whether
   // a move-exception instruction is present.
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 59efebf..65c5c21 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -3408,7 +3408,7 @@
     return nullptr;
   }
   mirror::ArtMethod* res_method = dispatch_class->GetVTableEntry(vtable_index);
-  if (FailOrAbort(this, !Thread::Current()->IsExceptionPending(),
+  if (FailOrAbort(this, !self_->IsExceptionPending(),
                   "Unexpected exception pending for quickened invoke at ",
                   work_insn_idx_)) {
     return nullptr;
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index 0c4bf3c..c3bd4af 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -238,6 +238,10 @@
   bool HasFailures() const;
   const RegType& ResolveCheckedClass(uint32_t class_idx)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  mirror::ArtMethod* GetQuickInvokedMethod(const Instruction* inst,
+                                           RegisterLine* reg_line,
+                                           bool is_range)
+        SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
  private:
   // Private constructor for dumping.
@@ -586,11 +590,6 @@
                                                       mirror::ArtMethod* res_method)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  mirror::ArtMethod* GetQuickInvokedMethod(const Instruction* inst,
-                                           RegisterLine* reg_line,
-                                           bool is_range)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
   mirror::ArtMethod* VerifyInvokeVirtualQuickArgs(const Instruction* inst, bool is_range)
   SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);