Sharpen virtual calls to final methods.

Also remove unused instance resolution stub.

Change-Id: I2abb988d107e98ac0148fb81464b22622a468382
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 700174e..ecf33ac 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -1339,12 +1339,30 @@
   // Special case to get oat code without overwriting a trampoline.
   CHECK(method->GetDeclaringClass()->IsInitializing());
   // Although we overwrite the trampoline of non-static methods, we may get here via the resolution
-  // method for direct methods.
-  CHECK(method->IsStatic() || method->IsDirect());
-  ClassHelper kh(method->GetDeclaringClass());
+  // method for direct methods (or virtual methods made direct).
+  Class* declaring_class = method->GetDeclaringClass();
+  size_t oat_method_index;
+  if (method->IsStatic() || method->IsDirect()) {
+    // Simple case where the oat method index was stashed at load time.
+    oat_method_index = method->GetMethodIndex();
+  } else {
+    // We're invoking a virtual method directly (thanks to sharpening), compute the oat_method_index
+    // by search for its position in the declared virtual methods.
+    oat_method_index = declaring_class->NumDirectMethods();
+    size_t end = declaring_class->NumVirtualMethods();
+    bool found = false;
+    for (size_t i = 0; i < end; i++) {
+      oat_method_index++;
+      if (declaring_class->GetVirtualMethod(i) == method) {
+        found = true;
+        break;
+      }
+    }
+    CHECK(found) << "Didn't find oat method index for virtual method: " << PrettyMethod(method);
+  }
+  ClassHelper kh(declaring_class);
   UniquePtr<const OatFile::OatClass> oat_class(GetOatClass(kh.GetDexFile(), kh.GetDescriptor()));
-  size_t method_index = method->GetMethodIndex();
-  return oat_class->GetOatMethod(method_index).GetCode();
+  return oat_class->GetOatMethod(oat_method_index).GetCode();
 }
 
 void ClassLinker::FixupStaticTrampolines(Class* klass) {
@@ -1470,25 +1488,26 @@
     // TODO: append direct methods to class object
     klass->SetVirtualMethods(AllocObjectArray<Method>(it.NumVirtualMethods()));
   }
-  size_t method_index = 0;
+  size_t class_def_method_index = 0;
   for (size_t i = 0; it.HasNextDirectMethod(); i++, it.Next()) {
     SirtRef<Method> method(AllocMethod());
     klass->SetDirectMethod(i, method.get());
     LoadMethod(dex_file, it, klass, method);
     if (oat_class.get() != NULL) {
-      LinkCode(method, oat_class.get(), method_index);
+      LinkCode(method, oat_class.get(), class_def_method_index);
     }
-    method->SetMethodIndex(method_index);
-    method_index++;
+    method->SetMethodIndex(class_def_method_index);
+    class_def_method_index++;
   }
   for (size_t i = 0; it.HasNextVirtualMethod(); i++, it.Next()) {
     SirtRef<Method> method(AllocMethod());
     klass->SetVirtualMethod(i, method.get());
     LoadMethod(dex_file, it, klass, method);
+    DCHECK_EQ(class_def_method_index, it.NumDirectMethods() + i);
     if (oat_class.get() != NULL) {
-      LinkCode(method, oat_class.get(), method_index);
+      LinkCode(method, oat_class.get(), class_def_method_index);
     }
-    method_index++;
+    class_def_method_index++;
   }
   DCHECK(!it.HasNext());
 }
diff --git a/src/compiler.cc b/src/compiler.cc
index 51354aa..98d8fac 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -86,7 +86,8 @@
      strings_in_dex_cache_(0), strings_not_in_dex_cache_(0),
      resolved_types_(0), unresolved_types_(0),
      resolved_instance_fields_(0), unresolved_instance_fields_(0),
-     resolved_local_static_fields_(0), resolved_static_fields_(0), unresolved_static_fields_(0) {
+     resolved_local_static_fields_(0), resolved_static_fields_(0), unresolved_static_fields_(0),
+     virtual_made_direct_(0) {
     for (size_t i = 0; i < kMaxInvokeType; i++) {
       resolved_methods_[i] = 0;
       unresolved_methods_[i] = 0;
@@ -108,6 +109,8 @@
       oss << "resolved " << static_cast<InvokeType>(i) << " methods";
       DumpStat(resolved_methods_[i], unresolved_methods_[i], oss.str().c_str());
     }
+    DumpStat(virtual_made_direct_, resolved_methods_[kVirtual] + unresolved_methods_[kVirtual],
+             "made direct from virtual");
   }
 
 // Allow lossy statistics in non-debug builds
@@ -184,6 +187,10 @@
     unresolved_methods_[type]++;
   }
 
+  void VirtualMadeDirect() {
+    STATS_LOCK();
+    virtual_made_direct_++;
+  }
  private:
   Mutex stats_lock_;
 
@@ -205,6 +212,7 @@
 
   size_t resolved_methods_[kMaxInvokeType + 1];
   size_t unresolved_methods_[kMaxInvokeType + 1];
+  size_t virtual_made_direct_;
 
   DISALLOW_COPY_AND_ASSIGN(AOTCompilationStats);;
 };
@@ -566,7 +574,7 @@
   return false;  // Incomplete knowledge needs slow path.
 }
 
-bool Compiler::ComputeInvokeInfo(uint32_t method_idx, OatCompilationUnit* mUnit, InvokeType type,
+bool Compiler::ComputeInvokeInfo(uint32_t method_idx, OatCompilationUnit* mUnit, InvokeType& type,
                                  int& vtable_idx) {
   vtable_idx = -1;
   Method* resolved_method = ComputeReferrerMethod(mUnit, method_idx);
@@ -591,7 +599,16 @@
           referrer_class->CanAccessMember(methods_class,
                                           resolved_method->GetAccessFlags())) {
         vtable_idx = resolved_method->GetMethodIndex();
-        if (type != kSuper) {
+        if (type == kVirtual && (resolved_method->IsFinal() || methods_class->IsFinal())) {
+          stats_->ResolvedMethod(kVirtual);
+          // Sharpen a virtual call into a direct call. The method_idx is into referrer's
+          // dex cache, check that this resolved method is where we expect it.
+          CHECK(referrer_class->GetDexCache()->GetResolvedMethod(method_idx) == resolved_method)
+            << PrettyMethod(resolved_method);
+          type = kDirect;
+          stats_->VirtualMadeDirect();
+          return true;
+        } else if (type != kSuper) {
           // nothing left to do for static/direct/virtual/interface dispatch
           stats_->ResolvedMethod(type);
           return true;
diff --git a/src/compiler.h b/src/compiler.h
index 2ff3b90..476a744 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -120,7 +120,7 @@
                               bool& is_referrers_class, bool& is_volatile, bool is_put);
 
   // Can we fastpath a interface, super class or virtual method call? Computes method's vtable index
-  bool ComputeInvokeInfo(uint32_t method_idx, OatCompilationUnit* mUnit, InvokeType type,
+  bool ComputeInvokeInfo(uint32_t method_idx, OatCompilationUnit* mUnit, InvokeType& type,
                          int& vtable_idx);
 
 #if defined(ART_USE_LLVM_COMPILER)
diff --git a/src/image.h b/src/image.h
index 0a83c39..6286411 100644
--- a/src/image.h
+++ b/src/image.h
@@ -82,7 +82,6 @@
   enum ImageRoot {
     kJniStubArray,
     kAbstractMethodErrorStubArray,
-    kInstanceResolutionStubArray,
     kStaticResolutionStubArray,
     kUnknownMethodResolutionStubArray,
     kResolutionMethod,
diff --git a/src/image_writer.cc b/src/image_writer.cc
index d0e3579..23c2029 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -302,8 +302,6 @@
   image_roots->Set(ImageHeader::kJniStubArray, runtime->GetJniDlsymLookupStub());
   image_roots->Set(ImageHeader::kAbstractMethodErrorStubArray,
                    runtime->GetAbstractMethodErrorStubArray());
-  image_roots->Set(ImageHeader::kInstanceResolutionStubArray,
-                   runtime->GetResolutionStubArray(Runtime::kInstanceMethod));
   image_roots->Set(ImageHeader::kStaticResolutionStubArray,
                    runtime->GetResolutionStubArray(Runtime::kStaticMethod));
   image_roots->Set(ImageHeader::kUnknownMethodResolutionStubArray,
diff --git a/src/oatdump.cc b/src/oatdump.cc
index cf4dc2d..c7b8151 100644
--- a/src/oatdump.cc
+++ b/src/oatdump.cc
@@ -72,7 +72,6 @@
 const char* image_roots_descriptions_[] = {
   "kJniStubArray",
   "kAbstractMethodErrorStubArray",
-  "kInstanceResolutionStubArray",
   "kStaticResolutionStubArray",
   "kUnknownMethodResolutionStubArray",
   "kResolutionMethod",
@@ -618,8 +617,7 @@
   const void* GetOatCode(Method* m) {
     Runtime* runtime = Runtime::Current();
     const void* code = m->GetCode();
-    if (code == runtime->GetResolutionStubArray(Runtime::kStaticMethod)->GetData() ||
-        code == runtime->GetResolutionStubArray(Runtime::kInstanceMethod)->GetData()) {
+    if (code == runtime->GetResolutionStubArray(Runtime::kStaticMethod)->GetData()) {
       code = oat_dumper_->GetOatCode(m);
     }
     return code;
diff --git a/src/object.cc b/src/object.cc
index 85a2d0a..c91a371 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -481,8 +481,7 @@
     code = runtime->GetTracer()->GetSavedCodeFromMap(m);
   }
   // Peel off any resolution stub.
-  if (code == runtime->GetResolutionStubArray(Runtime::kStaticMethod)->GetData() ||
-      code == runtime->GetResolutionStubArray(Runtime::kInstanceMethod)->GetData()) {
+  if (code == runtime->GetResolutionStubArray(Runtime::kStaticMethod)->GetData()) {
     code = runtime->GetClassLinker()->GetOatCodeFor(m);
   }
   return code;
diff --git a/src/runtime.cc b/src/runtime.cc
index f0a6bbc..22f4329 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -847,7 +847,7 @@
   } else if (method->IsStatic()) {
     return Runtime::kStaticMethod;
   } else {
-    return Runtime::kInstanceMethod;
+    return Runtime::kUnknownMethod;
   }
 }
 
diff --git a/src/runtime.h b/src/runtime.h
index fb1cd03..36f0084 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -183,7 +183,6 @@
   void SetAbstractMethodErrorStubArray(ByteArray* abstract_method_error_stub_array);
 
   enum TrampolineType {
-    kInstanceMethod,
     kStaticMethod,
     kUnknownMethod,
     kLastTrampolineMethodType  // Value used for iteration
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index 607542e..c4771b0 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -463,6 +463,7 @@
   ClassLinker* linker = Runtime::Current()->GetClassLinker();
   Method* caller = *caller_sp;
   bool is_static;
+  bool is_virtual;
   uint32_t dex_method_idx;
   const char* shorty;
   uint32_t shorty_len;
@@ -476,14 +477,19 @@
     Instruction::Code instr_code = instr->Opcode();
     is_static = (instr_code == Instruction::INVOKE_STATIC) ||
                 (instr_code == Instruction::INVOKE_STATIC_RANGE);
+    is_virtual = (instr_code == Instruction::INVOKE_VIRTUAL) ||
+                 (instr_code == Instruction::INVOKE_VIRTUAL_RANGE);
     DCHECK(is_static || (instr_code == Instruction::INVOKE_DIRECT) ||
-           (instr_code == Instruction::INVOKE_DIRECT_RANGE));
+           (instr_code == Instruction::INVOKE_DIRECT_RANGE) ||
+           (instr_code == Instruction::INVOKE_VIRTUAL) ||
+           (instr_code == Instruction::INVOKE_VIRTUAL_RANGE));
     Instruction::DecodedInstruction dec_insn(instr);
     dex_method_idx = dec_insn.vB_;
     shorty = linker->MethodShorty(dex_method_idx, caller, &shorty_len);
   } else {
     DCHECK(!called->IsRuntimeMethod());
     is_static = type == Runtime::kStaticMethod;
+    is_virtual = false;
     dex_method_idx = called->GetDexMethodIndex();
     MethodHelper mh(called);
     shorty = mh.GetShorty();
@@ -535,11 +541,11 @@
   }
   // Resolve method filling in dex cache
   if (type == Runtime::kUnknownMethod) {
-    called = linker->ResolveMethod(dex_method_idx, caller, true);
+    called = linker->ResolveMethod(dex_method_idx, caller, !is_virtual);
   }
   const void* code = NULL;
   if (LIKELY(!thread->IsExceptionPending())) {
-    if (LIKELY(called->IsDirect())) {
+    if (LIKELY(called->IsDirect() == !is_virtual)) {
       // Ensure that the called method's class is initialized.
       Class* called_class = called->GetDeclaringClass();
       linker->EnsureInitialized(called_class, true);
diff --git a/src/space.cc b/src/space.cc
index 32d3f3e..6d5a31a 100644
--- a/src/space.cc
+++ b/src/space.cc
@@ -319,10 +319,8 @@
   Object* ame_stub_array = image_header.GetImageRoot(ImageHeader::kAbstractMethodErrorStubArray);
   runtime->SetAbstractMethodErrorStubArray(down_cast<ByteArray*>(ame_stub_array));
 
-  Object* resolution_stub_array = image_header.GetImageRoot(ImageHeader::kInstanceResolutionStubArray);
-  runtime->SetResolutionStubArray(
-      down_cast<ByteArray*>(resolution_stub_array), Runtime::kInstanceMethod);
-  resolution_stub_array = image_header.GetImageRoot(ImageHeader::kStaticResolutionStubArray);
+  Object* resolution_stub_array =
+      image_header.GetImageRoot(ImageHeader::kStaticResolutionStubArray);
   runtime->SetResolutionStubArray(
       down_cast<ByteArray*>(resolution_stub_array), Runtime::kStaticMethod);
   resolution_stub_array = image_header.GetImageRoot(ImageHeader::kUnknownMethodResolutionStubArray);