Allocate small arg arrays on the stack
Create a helper class to either keep in a short local array or allocate
the arg array. This benefits JNI methods with a small number of
arguments by avoiding an allocation.
Change-Id: I88a9ff6b7ff88b16021813650e9425697e934353
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index 04832c7..c447de8 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -116,24 +116,6 @@
return reinterpret_cast<T>(ref);
}
-size_t NumArgArrayBytes(const char* shorty) {
- size_t num_bytes = 0;
- size_t end = strlen(shorty);
- for (size_t i = 1; i < end; ++i) {
- char ch = shorty[i];
- if (ch == 'D' || ch == 'J') {
- num_bytes += 8;
- } else if (ch == 'L') {
- // Argument is a reference or an array. The shorty descriptor
- // does not distinguish between these types.
- num_bytes += sizeof(Object*);
- } else {
- num_bytes += 4;
- }
- }
- return num_bytes;
-}
-
// For external use.
template<typename T>
T Decode(JNIEnv* public_env, jobject obj) {
@@ -158,6 +140,150 @@
template String* Decode<String*>(JNIEnv*, jobject);
template Throwable* Decode<Throwable*>(JNIEnv*, jobject);
+size_t NumArgArrayBytes(const char* shorty, uint32_t shorty_len) {
+ size_t num_bytes = 0;
+ for (size_t i = 1; i < shorty_len; ++i) {
+ char ch = shorty[i];
+ if (ch == 'D' || ch == 'J') {
+ num_bytes += 8;
+ } else if (ch == 'L') {
+ // Argument is a reference or an array. The shorty descriptor
+ // does not distinguish between these types.
+ num_bytes += sizeof(Object*);
+ } else {
+ num_bytes += 4;
+ }
+ }
+ return num_bytes;
+}
+
+class ArgArray {
+ public:
+ explicit ArgArray(Method* method) {
+ MethodHelper mh(method);
+ shorty_ = mh.GetShorty();
+ shorty_len_ = mh.GetShortyLength();
+ size_t num_bytes = NumArgArrayBytes(shorty_, shorty_len_);
+ if (num_bytes < kSmallArgArraySizeInBytes) {
+ arg_array_ = small_arg_array_;
+ } else {
+ large_arg_array_.reset(new byte[num_bytes]);
+ arg_array_ = large_arg_array_.get();
+ }
+ }
+
+ byte* get() {
+ return arg_array_;
+ }
+
+ void BuildArgArray(JNIEnv* public_env, va_list ap) {
+ JNIEnvExt* env = reinterpret_cast<JNIEnvExt*>(public_env);
+ for (size_t i = 1, offset = 0; i < shorty_len_; ++i) {
+ switch (shorty_[i]) {
+ case 'Z':
+ case 'B':
+ case 'C':
+ case 'S':
+ case 'I':
+ *reinterpret_cast<int32_t*>(&arg_array_[offset]) = va_arg(ap, jint);
+ offset += 4;
+ break;
+ case 'F':
+ *reinterpret_cast<float*>(&arg_array_[offset]) = va_arg(ap, jdouble);
+ offset += 4;
+ break;
+ case 'L': {
+ Object* obj = DecodeObj(env, va_arg(ap, jobject));
+ *reinterpret_cast<Object**>(&arg_array_[offset]) = obj;
+ offset += sizeof(Object*);
+ break;
+ }
+ case 'D':
+ *reinterpret_cast<double*>(&arg_array_[offset]) = va_arg(ap, jdouble);
+ offset += 8;
+ break;
+ case 'J':
+ *reinterpret_cast<int64_t*>(&arg_array_[offset]) = va_arg(ap, jlong);
+ offset += 8;
+ break;
+ }
+ }
+ }
+
+ void BuildArgArray(JNIEnv* public_env, jvalue* args) {
+ JNIEnvExt* env = reinterpret_cast<JNIEnvExt*>(public_env);
+ for (size_t i = 1, offset = 0; i < shorty_len_; ++i) {
+ switch (shorty_[i]) {
+ case 'Z':
+ case 'B':
+ case 'C':
+ case 'S':
+ case 'I':
+ *reinterpret_cast<uint32_t*>(&arg_array_[offset]) = args[i - 1].i;
+ offset += 4;
+ break;
+ case 'F':
+ *reinterpret_cast<float*>(&arg_array_[offset]) = args[i - 1].f;
+ offset += 4;
+ break;
+ case 'L': {
+ Object* obj = DecodeObj(env, args[i - 1].l);
+ *reinterpret_cast<Object**>(&arg_array_[offset]) = obj;
+ offset += sizeof(Object*);
+ break;
+ }
+ case 'D':
+ *reinterpret_cast<double*>(&arg_array_[offset]) = args[i - 1].d;
+ offset += 8;
+ break;
+ case 'J':
+ *reinterpret_cast<uint64_t*>(&arg_array_[offset]) = args[i - 1].j;
+ offset += 8;
+ break;
+ }
+ }
+ }
+
+ void BuildArgArray(JValue* args) {
+ for (size_t i = 1, offset = 0; i < shorty_len_; ++i) {
+ switch (shorty_[i]) {
+ case 'Z':
+ case 'B':
+ case 'C':
+ case 'S':
+ case 'I':
+ *reinterpret_cast<uint32_t*>(&arg_array_[offset]) = args[i - 1].i;
+ offset += 4;
+ break;
+ case 'F':
+ *reinterpret_cast<float*>(&arg_array_[offset]) = args[i - 1].f;
+ offset += 4;
+ break;
+ case 'L':
+ *reinterpret_cast<Object**>(&arg_array_[offset]) = args[i - 1].l;
+ offset += sizeof(Object*);
+ break;
+ case 'D':
+ *reinterpret_cast<double*>(&arg_array_[offset]) = args[i - 1].d;
+ offset += 8;
+ break;
+ case 'J':
+ *reinterpret_cast<uint64_t*>(&arg_array_[offset]) = args[i - 1].j;
+ offset += 8;
+ break;
+ }
+ }
+ }
+
+ private:
+ enum { kSmallArgArraySizeInBytes = 48 };
+ const char* shorty_;
+ uint32_t shorty_len_;
+ byte* arg_array_;
+ byte small_arg_array_[kSmallArgArraySizeInBytes];
+ UniquePtr<byte[]> large_arg_array_;
+};
+
namespace {
jweak AddWeakGlobalReference(ScopedJniThreadState& ts, Object* obj) {
@@ -177,120 +303,6 @@
return reinterpret_cast<T>(ts.Self()->DecodeJObject(obj));
}
-static byte* CreateArgArray(JNIEnv* public_env, Method* method, va_list ap) {
- JNIEnvExt* env = reinterpret_cast<JNIEnvExt*>(public_env);
- const char* shorty = MethodHelper(method).GetShorty();
- size_t shorty_len = strlen(shorty);
- size_t num_bytes = NumArgArrayBytes(shorty);
- UniquePtr<byte[]> arg_array(new byte[num_bytes]);
- for (size_t i = 1, offset = 0; i < shorty_len; ++i) {
- switch (shorty[i]) {
- case 'Z':
- case 'B':
- case 'C':
- case 'S':
- case 'I':
- *reinterpret_cast<int32_t*>(&arg_array[offset]) = va_arg(ap, jint);
- offset += 4;
- break;
- case 'F':
- *reinterpret_cast<float*>(&arg_array[offset]) = va_arg(ap, jdouble);
- offset += 4;
- break;
- case 'L': {
- Object* obj = DecodeObj(env, va_arg(ap, jobject));
- *reinterpret_cast<Object**>(&arg_array[offset]) = obj;
- offset += sizeof(Object*);
- break;
- }
- case 'D':
- *reinterpret_cast<double*>(&arg_array[offset]) = va_arg(ap, jdouble);
- offset += 8;
- break;
- case 'J':
- *reinterpret_cast<int64_t*>(&arg_array[offset]) = va_arg(ap, jlong);
- offset += 8;
- break;
- }
- }
- return arg_array.release();
-}
-
-static byte* CreateArgArray(JNIEnv* public_env, Method* method, jvalue* args) {
- JNIEnvExt* env = reinterpret_cast<JNIEnvExt*>(public_env);
- const char* shorty = MethodHelper(method).GetShorty();
- size_t shorty_len = strlen(shorty);
- size_t num_bytes = NumArgArrayBytes(shorty);
- UniquePtr<byte[]> arg_array(new byte[num_bytes]);
- for (size_t i = 1, offset = 0; i < shorty_len; ++i) {
- switch (shorty[i]) {
- case 'Z':
- case 'B':
- case 'C':
- case 'S':
- case 'I':
- *reinterpret_cast<uint32_t*>(&arg_array[offset]) = args[i - 1].i;
- offset += 4;
- break;
- case 'F':
- *reinterpret_cast<float*>(&arg_array[offset]) = args[i - 1].f;
- offset += 4;
- break;
- case 'L': {
- Object* obj = DecodeObj(env, args[i - 1].l);
- *reinterpret_cast<Object**>(&arg_array[offset]) = obj;
- offset += sizeof(Object*);
- break;
- }
- case 'D':
- *reinterpret_cast<double*>(&arg_array[offset]) = args[i - 1].d;
- offset += 8;
- break;
- case 'J':
- *reinterpret_cast<uint64_t*>(&arg_array[offset]) = args[i - 1].j;
- offset += 8;
- break;
- }
- }
- return arg_array.release();
-}
-
-static byte* CreateArgArray(Method* method, JValue* args) {
- const char* shorty = MethodHelper(method).GetShorty();
- size_t shorty_len = strlen(shorty);
- size_t num_bytes = NumArgArrayBytes(shorty);
- UniquePtr<byte[]> arg_array(new byte[num_bytes]);
- for (size_t i = 1, offset = 0; i < shorty_len; ++i) {
- switch (shorty[i]) {
- case 'Z':
- case 'B':
- case 'C':
- case 'S':
- case 'I':
- *reinterpret_cast<uint32_t*>(&arg_array[offset]) = args[i - 1].i;
- offset += 4;
- break;
- case 'F':
- *reinterpret_cast<float*>(&arg_array[offset]) = args[i - 1].f;
- offset += 4;
- break;
- case 'L':
- *reinterpret_cast<Object**>(&arg_array[offset]) = args[i - 1].l;
- offset += sizeof(Object*);
- break;
- case 'D':
- *reinterpret_cast<double*>(&arg_array[offset]) = args[i - 1].d;
- offset += 8;
- break;
- case 'J':
- *reinterpret_cast<uint64_t*>(&arg_array[offset]) = args[i - 1].j;
- offset += 8;
- break;
- }
- }
- return arg_array.release();
-}
-
static JValue InvokeWithArgArray(JNIEnv* public_env, Object* receiver, Method* method, byte* args) {
JNIEnvExt* env = reinterpret_cast<JNIEnvExt*>(public_env);
JValue result;
@@ -302,7 +314,8 @@
JNIEnvExt* env = reinterpret_cast<JNIEnvExt*>(public_env);
Object* receiver = DecodeObj(env, obj);
Method* method = DecodeMethod(mid);
- UniquePtr<byte[]> arg_array(CreateArgArray(env, method, args));
+ ArgArray arg_array(method);
+ arg_array.BuildArgArray(env, args);
return InvokeWithArgArray(env, receiver, method, arg_array.get());
}
@@ -315,7 +328,8 @@
JNIEnvExt* env = reinterpret_cast<JNIEnvExt*>(public_env);
Object* receiver = DecodeObj(env, obj);
Method* method = FindVirtualMethod(receiver, DecodeMethod(mid));
- UniquePtr<byte[]> arg_array(CreateArgArray(env, method, args));
+ ArgArray arg_array(method);
+ arg_array.BuildArgArray(env, args);
return InvokeWithArgArray(env, receiver, method, arg_array.get());
}
@@ -324,7 +338,8 @@
JNIEnvExt* env = reinterpret_cast<JNIEnvExt*>(public_env);
Object* receiver = DecodeObj(env, obj);
Method* method = FindVirtualMethod(receiver, DecodeMethod(mid));
- UniquePtr<byte[]> arg_array(CreateArgArray(env, method, args));
+ ArgArray arg_array(method);
+ arg_array.BuildArgArray(env, args);
return InvokeWithArgArray(env, receiver, method, arg_array.get());
}
@@ -702,12 +717,14 @@
JNIEnvExt* env = reinterpret_cast<JNIEnvExt*>(public_env);
Object* receiver = Decode<Object*>(env, obj);
Method* method = DecodeMethod(mid);
- UniquePtr<byte[]> arg_array(CreateArgArray(env, method, args));
+ ArgArray arg_array(method);
+ arg_array.BuildArgArray(env, args);
return InvokeWithArgArray(env, receiver, method, arg_array.get());
}
JValue InvokeWithJValues(Thread* self, Object* receiver, Method* m, JValue* args) {
- UniquePtr<byte[]> arg_array(CreateArgArray(m, args));
+ ArgArray arg_array(m);
+ arg_array.BuildArgArray(args);
return InvokeWithArgArray(self->GetJniEnv(), receiver, m, arg_array.get());
}