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