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/compiler.cc b/src/compiler.cc
index 34ef0e3..a51e5da 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -49,13 +49,13 @@
namespace arm {
ByteArray* CreateAbstractMethodErrorStub();
- CompiledInvokeStub* ArmCreateInvokeStub(bool is_static, const char* shorty);
+ CompiledInvokeStub* ArmCreateInvokeStub(bool is_static, const char* shorty, uint32_t shorty_len);
ByteArray* ArmCreateResolutionTrampoline(Runtime::TrampolineType type);
ByteArray* CreateJniDlsymLookupStub();
}
namespace x86 {
ByteArray* CreateAbstractMethodErrorStub();
- CompiledInvokeStub* X86CreateInvokeStub(bool is_static, const char* shorty);
+ CompiledInvokeStub* X86CreateInvokeStub(bool is_static, const char* shorty, uint32_t shorty_len);
ByteArray* X86CreateResolutionTrampoline(Runtime::TrampolineType type);
ByteArray* CreateJniDlsymLookupStub();
}
@@ -986,7 +986,8 @@
DCHECK(GetCompiledMethod(ref) != NULL) << PrettyMethod(method_idx, dex_file);
}
- const char* shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx));
+ uint32_t shorty_len;
+ const char* shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx), &shorty_len);
bool is_static = (access_flags & kAccStatic) != 0;
const CompiledInvokeStub* compiled_invoke_stub = FindInvokeStub(is_static, shorty);
if (compiled_invoke_stub == NULL) {
@@ -994,11 +995,11 @@
compiled_invoke_stub = compiler_llvm_->CreateInvokeStub(is_static, shorty);
#else
if (instruction_set_ == kX86) {
- compiled_invoke_stub = ::art::x86::X86CreateInvokeStub(is_static, shorty);
+ compiled_invoke_stub = ::art::x86::X86CreateInvokeStub(is_static, shorty, shorty_len);
} else {
CHECK(instruction_set_ == kArm || instruction_set_ == kThumb2);
// Generates invocation stub using ARM instruction set
- compiled_invoke_stub = ::art::arm::ArmCreateInvokeStub(is_static, shorty);
+ compiled_invoke_stub = ::art::arm::ArmCreateInvokeStub(is_static, shorty, shorty_len);
}
#endif
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());
}
diff --git a/src/jni_internal.h b/src/jni_internal.h
index f21b36a..79a7af9 100644
--- a/src/jni_internal.h
+++ b/src/jni_internal.h
@@ -75,7 +75,7 @@
return reinterpret_cast<jmethodID>(method);
}
-size_t NumArgArrayBytes(const char* shorty);
+size_t NumArgArrayBytes(const char* shorty, uint32_t shorty_len);
JValue InvokeWithJValues(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args);
JValue InvokeWithJValues(Thread* self, Object* receiver, Method* m, JValue* args);
diff --git a/src/jni_internal_arm.cc b/src/jni_internal_arm.cc
index d54d748..d5c2a25 100644
--- a/src/jni_internal_arm.cc
+++ b/src/jni_internal_arm.cc
@@ -43,11 +43,11 @@
// register and transfer arguments from the array into register and on
// the stack, if needed. On return, the thread register must be
// shuffled and the return value must be store into the result JValue.
-CompiledInvokeStub* ArmCreateInvokeStub(bool is_static, const char* shorty) {
+CompiledInvokeStub* ArmCreateInvokeStub(bool is_static, const char* shorty, uint32_t shorty_len) {
UniquePtr<ArmAssembler> assembler(
down_cast<ArmAssembler*>(Assembler::Create(kArm)));
#define __ assembler->
- size_t num_arg_array_bytes = NumArgArrayBytes(shorty);
+ size_t num_arg_array_bytes = NumArgArrayBytes(shorty, shorty_len);
// Size of frame - spill of R4,R9/LR + Method* + possible receiver + arg array
size_t unpadded_frame_size = (4 * kPointerSize) +
(is_static ? 0 : kPointerSize) +
diff --git a/src/jni_internal_x86.cc b/src/jni_internal_x86.cc
index cbc0095..403b37a 100644
--- a/src/jni_internal_x86.cc
+++ b/src/jni_internal_x86.cc
@@ -39,11 +39,11 @@
// "running" state the remaining responsibilities of this routine are
// to save the native registers and set up the managed registers. On
// return, the return value must be store into the result JValue.
-CompiledInvokeStub* X86CreateInvokeStub(bool is_static, const char* shorty) {
+CompiledInvokeStub* X86CreateInvokeStub(bool is_static, const char* shorty, uint32_t shorty_len) {
UniquePtr<X86Assembler> assembler(
down_cast<X86Assembler*>(Assembler::Create(kX86)));
#define __ assembler->
- size_t num_arg_array_bytes = NumArgArrayBytes(shorty);
+ size_t num_arg_array_bytes = NumArgArrayBytes(shorty, shorty_len);
// Size of frame - return address + Method* + possible receiver + arg array
size_t frame_size = (2 * kPointerSize) +
(is_static ? 0 : kPointerSize) +