Improve nterp -> compiled code transitions.

Use an unused bit in the access flags of an ArtMethod (0x00200000) to store
the information a method only takes ints or references and returns an
int, a reference, or a long. This avoids the need to fetch the shorty in nterp
when doing a call.

Test: test.py
Test: 821-many-args
Bug: 112676029

Change-Id: Ie657ccf69c17c1097dc2a97f18e3093ef3be391b
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 2040263..745e7cf 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -3838,21 +3838,34 @@
     } else {
       dst->SetCodeItem(dst->GetDexFile()->GetCodeItem(method.GetCodeItemOffset()));
     }
-    bool has_all_references = true;
-    const char* shorty = dst->GetShorty();
-    for (size_t i = 1, e = strlen(shorty); i < e; ++i) {
-      if (shorty[i] != 'L') {
-        has_all_references = false;
-        break;
-      }
-    }
-    if (has_all_references) {
-      dst->SetNterpEntryPointFastPathFlag();
-    }
   } else {
     dst->SetDataPtrSize(nullptr, image_pointer_size_);
     DCHECK_EQ(method.GetCodeItemOffset(), 0u);
   }
+
+  // Set optimization flags related to the shorty.
+  const char* shorty = dst->GetShorty();
+  bool all_parameters_are_reference = true;
+  bool all_parameters_are_reference_or_int = true;
+  bool return_type_is_fp = (shorty[0] == 'F' || shorty[0] == 'D');
+
+  for (size_t i = 1, e = strlen(shorty); i < e; ++i) {
+    if (shorty[i] != 'L') {
+      all_parameters_are_reference = false;
+      if (shorty[i] == 'F' || shorty[i] == 'D' || shorty[i] == 'J') {
+        all_parameters_are_reference_or_int = false;
+        break;
+      }
+    }
+  }
+
+  if (!dst->IsNative() && all_parameters_are_reference) {
+    dst->SetNterpEntryPointFastPathFlag();
+  }
+
+  if (!return_type_is_fp && all_parameters_are_reference_or_int) {
+    dst->SetNterpInvokeFastPathFlag();
+  }
 }
 
 void ClassLinker::AppendToBootClassPath(Thread* self, const DexFile* dex_file) {