Revert "Revert "Do a second check for testing intrinsic types.""

This reverts commit a14b9fef395b94fa9a32147862c198fe7c22e3d7.

When an intrinsic with invoke-type virtual is recognized, replace
the instruction with a new HInvokeStaticOrDirect.

Minimal update for dex-cache rework. Fix includes.

Change-Id: I1c8e735a2fa7cda4419f76ca0717125ef236d332
diff --git a/compiler/optimizing/intrinsics.cc b/compiler/optimizing/intrinsics.cc
index 075ec1e..41c239d 100644
--- a/compiler/optimizing/intrinsics.cc
+++ b/compiler/optimizing/intrinsics.cc
@@ -16,12 +16,17 @@
 
 #include "intrinsics.h"
 
+#include "art_method.h"
+#include "class_linker.h"
 #include "dex/quick/dex_file_method_inliner.h"
 #include "dex/quick/dex_file_to_method_inliner_map.h"
 #include "driver/compiler_driver.h"
 #include "invoke_type.h"
+#include "mirror/dex_cache-inl.h"
 #include "nodes.h"
 #include "quick/inline_method_analyser.h"
+#include "scoped_thread_state_change.h"
+#include "thread-inl.h"
 #include "utils.h"
 
 namespace art {
@@ -328,14 +333,23 @@
   return Intrinsics::kNone;
 }
 
-static bool CheckInvokeType(Intrinsics intrinsic, HInvoke* invoke) {
+static bool CheckInvokeType(Intrinsics intrinsic, HInvoke* invoke, const DexFile& dex_file) {
   // The DexFileMethodInliner should have checked whether the methods are agreeing with
   // what we expect, i.e., static methods are called as such. Add another check here for
   // our expectations:
-  // Whenever the intrinsic is marked as static-or-direct, report an error if we find an
-  // InvokeVirtual. The other direction is not possible: we have intrinsics for virtual
-  // functions that will perform a check inline. If the precise type is known, however,
-  // the instruction will be sharpened to an InvokeStaticOrDirect.
+  //
+  // Whenever the intrinsic is marked as static, report an error if we find an InvokeVirtual.
+  //
+  // Whenever the intrinsic is marked as direct and we find an InvokeVirtual, a devirtualization
+  // failure occured. We might be in a situation where we have inlined a method that calls an
+  // intrinsic, but that method is in a different dex file on which we do not have a
+  // verified_method that would have helped the compiler driver sharpen the call. In that case,
+  // make sure that the intrinsic is actually for some final method (or in a final class), as
+  // otherwise the intrinsics setup is broken.
+  //
+  // For the last direction, we have intrinsics for virtual functions that will perform a check
+  // inline. If the precise type is known, however, the instruction will be sharpened to an
+  // InvokeStaticOrDirect.
   InvokeType intrinsic_type = GetIntrinsicInvokeType(intrinsic);
   InvokeType invoke_type = invoke->IsInvokeStaticOrDirect() ?
       invoke->AsInvokeStaticOrDirect()->GetInvokeType() :
@@ -343,8 +357,22 @@
   switch (intrinsic_type) {
     case kStatic:
       return (invoke_type == kStatic);
+
     case kDirect:
-      return (invoke_type == kDirect);
+      if (invoke_type == kDirect) {
+        return true;
+      }
+      if (invoke_type == kVirtual) {
+        ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+        ScopedObjectAccess soa(Thread::Current());
+        ArtMethod* art_method =
+            class_linker->FindDexCache(soa.Self(), dex_file)->GetResolvedMethod(
+                invoke->GetDexMethodIndex(), class_linker->GetImagePointerSize());
+        return art_method != nullptr &&
+            (art_method->IsFinal() || art_method->GetDeclaringClass()->IsFinal());
+      }
+      return false;
+
     case kVirtual:
       // Call might be devirtualized.
       return (invoke_type == kVirtual || invoke_type == kDirect);
@@ -364,17 +392,18 @@
       if (inst->IsInvoke()) {
         HInvoke* invoke = inst->AsInvoke();
         InlineMethod method;
-        DexFileMethodInliner* inliner =
-            driver_->GetMethodInlinerMap()->GetMethodInliner(&invoke->GetDexFile());
+        const DexFile& dex_file = invoke->GetDexFile();
+        DexFileMethodInliner* inliner = driver_->GetMethodInlinerMap()->GetMethodInliner(&dex_file);
         DCHECK(inliner != nullptr);
         if (inliner->IsIntrinsic(invoke->GetDexMethodIndex(), &method)) {
           Intrinsics intrinsic = GetIntrinsic(method, graph_->GetInstructionSet());
 
           if (intrinsic != Intrinsics::kNone) {
-            if (!CheckInvokeType(intrinsic, invoke)) {
+            if (!CheckInvokeType(intrinsic, invoke, dex_file)) {
               LOG(WARNING) << "Found an intrinsic with unexpected invoke type: "
-                           << intrinsic << " for "
-                           << PrettyMethod(invoke->GetDexMethodIndex(), invoke->GetDexFile());
+                  << intrinsic << " for "
+                  << PrettyMethod(invoke->GetDexMethodIndex(), invoke->GetDexFile())
+                  << invoke->DebugName();
             } else {
               invoke->SetIntrinsic(intrinsic, NeedsEnvironmentOrCache(intrinsic));
             }