ART: Improve Constructor.newInstance

Special-case InvokeMethod to be constructor-specific so as to avoid
unnecessary and duplicate checks. Refactor for some code sharing.

Reduces Constructor.newInstance for Integer by approximately 15%
(ten runs of 10000000 invocations, reporting mean per invocation,
host x86-64 optimizing, perf stat numbers are for complete run
and do not exclude, for example, setup and prologue GC):

                   Before      After

(perf stat)
Instructions       2503.4      2149.8
Branches           450.8       384.4
Branch-misses      1.83        0.85

(time)
Time (ns)          335.17      278.58

Bug: 20269715
Test: mmma art
Test: m test-art-host
Change-Id: Id105e542a19d72efaace60ad39fcef5e42dde006
diff --git a/runtime/reflection.cc b/runtime/reflection.cc
index 9e9c33c..646de75 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -457,6 +457,64 @@
   method->Invoke(soa.Self(), args, arg_array->GetNumBytes(), result, shorty);
 }
 
+ALWAYS_INLINE
+bool CheckArgsForInvokeMethod(ArtMethod* np_method,
+                              ObjPtr<mirror::ObjectArray<mirror::Object>> objects)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  const DexFile::TypeList* classes = np_method->GetParameterTypeList();
+  uint32_t classes_size = (classes == nullptr) ? 0 : classes->Size();
+  uint32_t arg_count = (objects == nullptr) ? 0 : objects->GetLength();
+  if (UNLIKELY(arg_count != classes_size)) {
+    ThrowIllegalArgumentException(StringPrintf("Wrong number of arguments; expected %d, got %d",
+                                               classes_size, arg_count).c_str());
+    return false;
+  }
+  return true;
+}
+
+ALWAYS_INLINE
+bool InvokeMethodImpl(const ScopedObjectAccessAlreadyRunnable& soa,
+                      ArtMethod* m,
+                      ArtMethod* np_method,
+                      ObjPtr<mirror::Object> receiver,
+                      ObjPtr<mirror::ObjectArray<mirror::Object>> objects,
+                      const char** shorty,
+                      JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
+  // Invoke the method.
+  uint32_t shorty_len = 0;
+  *shorty = np_method->GetShorty(&shorty_len);
+  ArgArray arg_array(*shorty, shorty_len);
+  if (!arg_array.BuildArgArrayFromObjectArray(receiver, objects, np_method, soa.Self())) {
+    CHECK(soa.Self()->IsExceptionPending());
+    return false;
+  }
+
+  InvokeWithArgArray(soa, m, &arg_array, result, *shorty);
+
+  // Wrap any exception with "Ljava/lang/reflect/InvocationTargetException;" and return early.
+  if (soa.Self()->IsExceptionPending()) {
+    // If we get another exception when we are trying to wrap, then just use that instead.
+    ScopedLocalRef<jthrowable> th(soa.Env(), soa.Env()->ExceptionOccurred());
+    soa.Self()->ClearException();
+    jclass exception_class = soa.Env()->FindClass("java/lang/reflect/InvocationTargetException");
+    if (exception_class == nullptr) {
+      soa.Self()->AssertPendingException();
+      return false;
+    }
+    jmethodID mid = soa.Env()->GetMethodID(exception_class, "<init>", "(Ljava/lang/Throwable;)V");
+    CHECK(mid != nullptr);
+    jobject exception_instance = soa.Env()->NewObject(exception_class, mid, th.get());
+    if (exception_instance == nullptr) {
+      soa.Self()->AssertPendingException();
+      return false;
+    }
+    soa.Env()->Throw(reinterpret_cast<jthrowable>(exception_instance));
+    return false;
+  }
+
+  return true;
+}
+
 }  // anonymous namespace
 
 JValue InvokeWithVarArgs(const ScopedObjectAccessAlreadyRunnable& soa, jobject obj, jmethodID mid,
@@ -632,12 +690,7 @@
   ObjPtr<mirror::ObjectArray<mirror::Object>> objects =
       soa.Decode<mirror::ObjectArray<mirror::Object>>(javaArgs);
   auto* np_method = m->GetInterfaceMethodIfProxy(kRuntimePointerSize);
-  const DexFile::TypeList* classes = np_method->GetParameterTypeList();
-  uint32_t classes_size = (classes == nullptr) ? 0 : classes->Size();
-  uint32_t arg_count = (objects != nullptr) ? objects->GetLength() : 0;
-  if (arg_count != classes_size) {
-    ThrowIllegalArgumentException(StringPrintf("Wrong number of arguments; expected %d, got %d",
-                                               classes_size, arg_count).c_str());
+  if (!CheckArgsForInvokeMethod(np_method, objects)) {
     return nullptr;
   }
 
@@ -661,41 +714,56 @@
 
   // Invoke the method.
   JValue result;
-  uint32_t shorty_len = 0;
-  const char* shorty = np_method->GetShorty(&shorty_len);
-  ArgArray arg_array(shorty, shorty_len);
-  if (!arg_array.BuildArgArrayFromObjectArray(receiver, objects, np_method, soa.Self())) {
-    CHECK(soa.Self()->IsExceptionPending());
+  const char* shorty;
+  if (!InvokeMethodImpl(soa, m, np_method, receiver, objects, &shorty, &result)) {
     return nullptr;
   }
-
-  InvokeWithArgArray(soa, m, &arg_array, &result, shorty);
-
-  // Wrap any exception with "Ljava/lang/reflect/InvocationTargetException;" and return early.
-  if (soa.Self()->IsExceptionPending()) {
-    // If we get another exception when we are trying to wrap, then just use that instead.
-    ScopedLocalRef<jthrowable> th(soa.Env(), soa.Env()->ExceptionOccurred());
-    soa.Self()->ClearException();
-    jclass exception_class = soa.Env()->FindClass("java/lang/reflect/InvocationTargetException");
-    if (exception_class == nullptr) {
-      soa.Self()->AssertPendingException();
-      return nullptr;
-    }
-    jmethodID mid = soa.Env()->GetMethodID(exception_class, "<init>", "(Ljava/lang/Throwable;)V");
-    CHECK(mid != nullptr);
-    jobject exception_instance = soa.Env()->NewObject(exception_class, mid, th.get());
-    if (exception_instance == nullptr) {
-      soa.Self()->AssertPendingException();
-      return nullptr;
-    }
-    soa.Env()->Throw(reinterpret_cast<jthrowable>(exception_instance));
-    return nullptr;
-  }
-
-  // Box if necessary and return.
   return soa.AddLocalReference<jobject>(BoxPrimitive(Primitive::GetType(shorty[0]), result));
 }
 
+void InvokeConstructor(const ScopedObjectAccessAlreadyRunnable& soa,
+                       ArtMethod* constructor,
+                       ObjPtr<mirror::Object> receiver,
+                       jobject javaArgs) {
+  // We want to make sure that the stack is not within a small distance from the
+  // protected region in case we are calling into a leaf function whose stack
+  // check has been elided.
+  if (UNLIKELY(__builtin_frame_address(0) < soa.Self()->GetStackEndForInterpreter(true))) {
+    ThrowStackOverflowError(soa.Self());
+    return;
+  }
+
+  if (kIsDebugBuild) {
+    CHECK(constructor->IsConstructor());
+
+    ObjPtr<mirror::Class> declaring_class = constructor->GetDeclaringClass();
+    CHECK(declaring_class->IsInitialized());
+
+    // Calls to String.<init> should have been repplaced with with equivalent StringFactory calls.
+    CHECK(!declaring_class->IsStringClass());
+
+    // Check that the receiver is non-null and an instance of the field's declaring class.
+    CHECK(receiver != nullptr);
+    CHECK(VerifyObjectIsClass(receiver, declaring_class));
+    CHECK_EQ(constructor,
+             receiver->GetClass()->FindVirtualMethodForVirtualOrInterface(constructor,
+                                                                          kRuntimePointerSize));
+  }
+
+  // Get our arrays of arguments and their types, and check they're the same size.
+  ObjPtr<mirror::ObjectArray<mirror::Object>> objects =
+      soa.Decode<mirror::ObjectArray<mirror::Object>>(javaArgs);
+  ArtMethod* np_method = constructor->GetInterfaceMethodIfProxy(kRuntimePointerSize);
+  if (!CheckArgsForInvokeMethod(np_method, objects)) {
+    return;
+  }
+
+  // Invoke the constructor.
+  JValue result;
+  const char* shorty;
+  InvokeMethodImpl(soa, constructor, np_method, receiver, objects, &shorty, &result);
+}
+
 ObjPtr<mirror::Object> BoxPrimitive(Primitive::Type src_class, const JValue& value) {
   if (src_class == Primitive::kPrimNot) {
     return MakeObjPtr(value.GetL());