Avoid useless EncodeArtMethod followed by DecodeArtMethod

In a handful of places we would perform an EncodeArtMethod to call a
reflection invoke function which would immediately Decode the method.
This could cause issues when using opaque-jni-ids:true since the
Encode can cause an OOM exception.

To avoid this (and because Encode and Decode are perfect inverses) we
changed the Invoke* reflection functions to also accept ArtMethod*s
directly and changed callers to use these functions when appropriate.

Test: (with child CL) ./test.py --host --jit --debuggable
Bug: 134162467
Change-Id: Id2f5b0f49a99405e238ce5b61a22ef9245e523a5
diff --git a/runtime/reflection.cc b/runtime/reflection.cc
index edd92da..3132951 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -514,9 +514,11 @@
 
 }  // anonymous namespace
 
-JValue InvokeWithVarArgs(const ScopedObjectAccessAlreadyRunnable& soa, jobject obj, jmethodID mid,
-                         va_list args)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
+template <>
+JValue InvokeWithVarArgs(const ScopedObjectAccessAlreadyRunnable& soa,
+                         jobject obj,
+                         ArtMethod* method,
+                         va_list args) REQUIRES_SHARED(Locks::mutator_lock_) {
   // 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.
@@ -524,8 +526,6 @@
     ThrowStackOverflowError(soa.Self());
     return JValue();
   }
-
-  ArtMethod* method = jni::DecodeArtMethod(mid);
   bool is_string_init = method->GetDeclaringClass()->IsStringClass() && method->IsConstructor();
   if (is_string_init) {
     // Replace calls to String.<init> with equivalent StringFactory call.
@@ -546,7 +546,19 @@
   return result;
 }
 
-JValue InvokeWithJValues(const ScopedObjectAccessAlreadyRunnable& soa, jobject obj, jmethodID mid,
+template <>
+JValue InvokeWithVarArgs(const ScopedObjectAccessAlreadyRunnable& soa,
+                         jobject obj,
+                         jmethodID mid,
+                         va_list args) REQUIRES_SHARED(Locks::mutator_lock_) {
+  DCHECK(mid != nullptr) << "Called with null jmethodID";
+  return InvokeWithVarArgs(soa, obj, jni::DecodeArtMethod(mid), args);
+}
+
+template <>
+JValue InvokeWithJValues(const ScopedObjectAccessAlreadyRunnable& soa,
+                         jobject obj,
+                         ArtMethod* method,
                          const jvalue* args) {
   // 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
@@ -555,8 +567,6 @@
     ThrowStackOverflowError(soa.Self());
     return JValue();
   }
-
-  ArtMethod* method = jni::DecodeArtMethod(mid);
   bool is_string_init = method->GetDeclaringClass()->IsStringClass() && method->IsConstructor();
   if (is_string_init) {
     // Replace calls to String.<init> with equivalent StringFactory call.
@@ -577,8 +587,20 @@
   return result;
 }
 
+template <>
+JValue InvokeWithJValues(const ScopedObjectAccessAlreadyRunnable& soa,
+                         jobject obj,
+                         jmethodID mid,
+                         const jvalue* args) {
+  DCHECK(mid != nullptr) << "Called with null jmethodID";
+  return InvokeWithJValues(soa, obj, jni::DecodeArtMethod(mid), args);
+}
+
+template <>
 JValue InvokeVirtualOrInterfaceWithJValues(const ScopedObjectAccessAlreadyRunnable& soa,
-                                           jobject obj, jmethodID mid, const jvalue* args) {
+                                           jobject obj,
+                                           ArtMethod* interface_method,
+                                           const jvalue* args) {
   // 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.
@@ -586,9 +608,8 @@
     ThrowStackOverflowError(soa.Self());
     return JValue();
   }
-
   ObjPtr<mirror::Object> receiver = soa.Decode<mirror::Object>(obj);
-  ArtMethod* method = FindVirtualMethod(receiver, jni::DecodeArtMethod(mid));
+  ArtMethod* method = FindVirtualMethod(receiver, interface_method);
   bool is_string_init = method->GetDeclaringClass()->IsStringClass() && method->IsConstructor();
   if (is_string_init) {
     // Replace calls to String.<init> with equivalent StringFactory call.
@@ -609,8 +630,20 @@
   return result;
 }
 
+template <>
+JValue InvokeVirtualOrInterfaceWithJValues(const ScopedObjectAccessAlreadyRunnable& soa,
+                                           jobject obj,
+                                           jmethodID mid,
+                                           const jvalue* args) {
+  DCHECK(mid != nullptr) << "Called with null jmethodID";
+  return InvokeVirtualOrInterfaceWithJValues(soa, obj, jni::DecodeArtMethod(mid), args);
+}
+
+template <>
 JValue InvokeVirtualOrInterfaceWithVarArgs(const ScopedObjectAccessAlreadyRunnable& soa,
-                                           jobject obj, jmethodID mid, va_list args) {
+                                           jobject obj,
+                                           ArtMethod* interface_method,
+                                           va_list args) {
   // 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.
@@ -620,7 +653,7 @@
   }
 
   ObjPtr<mirror::Object> receiver = soa.Decode<mirror::Object>(obj);
-  ArtMethod* method = FindVirtualMethod(receiver, jni::DecodeArtMethod(mid));
+  ArtMethod* method = FindVirtualMethod(receiver, interface_method);
   bool is_string_init = method->GetDeclaringClass()->IsStringClass() && method->IsConstructor();
   if (is_string_init) {
     // Replace calls to String.<init> with equivalent StringFactory call.
@@ -641,6 +674,15 @@
   return result;
 }
 
+template <>
+JValue InvokeVirtualOrInterfaceWithVarArgs(const ScopedObjectAccessAlreadyRunnable& soa,
+                                           jobject obj,
+                                           jmethodID mid,
+                                           va_list args) {
+  DCHECK(mid != nullptr) << "Called with null jmethodID";
+  return InvokeVirtualOrInterfaceWithVarArgs(soa, obj, jni::DecodeArtMethod(mid), args);
+}
+
 jobject InvokeMethod(const ScopedObjectAccessAlreadyRunnable& soa, jobject javaMethod,
                      jobject javaReceiver, jobject javaArgs, size_t num_frames) {
   // We want to make sure that the stack is not within a small distance from the