summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Jeff Hao <jeffhao@google.com> 2013-02-27 17:57:33 -0800
committer Jeff Hao <jeffhao@google.com> 2013-03-15 14:18:28 -0700
commit5d9173014c1ca09f7249a6b07629aa37778b5f8f (patch)
tree80543dbe9af6795212373bb12532b638ff3b22f3
parentaed0716b9592bb3095cdfc4b111011f9ed74877d (diff)
Changes to remove need for compiled invoke stubs for quick.
ARM, x86, and MIPS implementation complete, though MIPS is untested. The ArgArray is changed to be a uint32_t array instead of a JValue array. Also, a separate result for float/double was needed for x86/MIPS. The invoke stubs are currently still there, but only used for portable. Change-Id: I0647f8d5d420cea61370e662e85bdc0c13b5e378
-rw-r--r--src/asm_support.h3
-rw-r--r--src/class_linker.cc6
-rw-r--r--src/debugger.cc13
-rw-r--r--src/heap.cc21
-rw-r--r--src/interpreter/interpreter.cc166
-rw-r--r--src/interpreter/interpreter.h3
-rw-r--r--src/invoke_arg_array_builder.h178
-rw-r--r--src/jni_internal.cc75
-rw-r--r--src/jni_internal.h5
-rw-r--r--src/jni_internal_test.cc683
-rw-r--r--src/mirror/abstract_method.cc104
-rw-r--r--src/mirror/abstract_method.h7
-rw-r--r--src/mirror/object_test.cc2
-rw-r--r--src/oat/runtime/arm/runtime_support_arm.S64
-rw-r--r--src/oat/runtime/mips/runtime_support_mips.S57
-rw-r--r--src/oat/runtime/x86/runtime_support_x86.S44
-rw-r--r--src/object_utils.h5
-rw-r--r--src/reflection.cc14
-rw-r--r--src/runtime.cc8
-rw-r--r--src/thread.cc7
20 files changed, 1002 insertions, 463 deletions
diff --git a/src/asm_support.h b/src/asm_support.h
index 470b81f23d..bda0b7c055 100644
--- a/src/asm_support.h
+++ b/src/asm_support.h
@@ -27,6 +27,9 @@
#define STRING_OFFSET_OFFSET 20
#define STRING_DATA_OFFSET 12
+// Offset of field Method::code_
+#define METHOD_CODE_OFFSET 32
+
#if defined(__arm__)
// Register holding suspend check count down.
#define rSUSPEND r4
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 4a07ebab2f..725e710a89 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -2694,9 +2694,11 @@ bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_run_clinit, boo
if (clinit != NULL) {
if (Runtime::Current()->IsStarted()) {
- clinit->Invoke(self, NULL, NULL, NULL);
+ JValue result;
+ JValue float_result;
+ clinit->Invoke(self, NULL, 0, &result, &float_result);
} else {
- art::interpreter::EnterInterpreterFromInvoke(self, clinit, NULL, NULL, NULL);
+ art::interpreter::EnterInterpreterFromInvoke(self, clinit, NULL, NULL, NULL, NULL);
}
}
diff --git a/src/debugger.cc b/src/debugger.cc
index c96bb66c22..09c930a374 100644
--- a/src/debugger.cc
+++ b/src/debugger.cc
@@ -26,6 +26,7 @@
#include "gc/card_table-inl.h"
#include "gc/large_object_space.h"
#include "gc/space.h"
+#include "invoke_arg_array_builder.h"
#include "jdwp/object_registry.h"
#include "mirror/abstract_method-inl.h"
#include "mirror/class.h"
@@ -2723,8 +2724,16 @@ void Dbg::ExecuteMethod(DebugInvokeReq* pReq) {
LOG(INFO) << "self=" << soa.Self() << " pReq->receiver_=" << pReq->receiver_ << " m=" << m
<< " #" << pReq->arg_count_ << " " << pReq->arg_values_;
- pReq->result_value = InvokeWithJValues(soa, pReq->receiver_, m,
- reinterpret_cast<JValue*>(pReq->arg_values_));
+
+ MethodHelper mh(m);
+ ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
+ arg_array.BuildArgArray(soa, pReq->receiver_, reinterpret_cast<jvalue*>(pReq->arg_values_));
+ JValue unused_result;
+ if (mh.IsReturnFloatOrDouble()) {
+ InvokeWithArgArray(soa, m, &arg_array, &unused_result, &pReq->result_value);
+ } else {
+ InvokeWithArgArray(soa, m, &arg_array, &pReq->result_value, &unused_result);
+ }
pReq->exception = gRegistry->Add(soa.Self()->GetException());
pReq->result_tag = BasicTagFromDescriptor(MethodHelper(m).GetShorty());
diff --git a/src/heap.cc b/src/heap.cc
index a3a3a287f5..311052bfab 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -40,6 +40,7 @@
#include "gc/mod_union_table-inl.h"
#include "gc/space.h"
#include "image.h"
+#include "invoke_arg_array_builder.h"
#include "mirror/class-inl.h"
#include "mirror/field-inl.h"
#include "mirror/object.h"
@@ -1730,10 +1731,12 @@ mirror::Object* Heap::DequeuePendingReference(mirror::Object** list) {
void Heap::AddFinalizerReference(Thread* self, mirror::Object* object) {
ScopedObjectAccess soa(self);
- JValue args[1];
- args[0].SetL(object);
- soa.DecodeMethod(WellKnownClasses::java_lang_ref_FinalizerReference_add)->Invoke(self, NULL, args,
- NULL);
+ JValue result;
+ JValue float_result;
+ ArgArray arg_array(NULL, 0);
+ arg_array.Append(reinterpret_cast<uint32_t>(object));
+ soa.DecodeMethod(WellKnownClasses::java_lang_ref_FinalizerReference_add)->Invoke(self,
+ arg_array.GetArray(), arg_array.GetNumBytes(), &result, &float_result);
}
size_t Heap::GetBytesAllocated() const {
@@ -1766,10 +1769,12 @@ void Heap::EnqueueClearedReferences(mirror::Object** cleared) {
// When a runtime isn't started there are no reference queues to care about so ignore.
if (LIKELY(Runtime::Current()->IsStarted())) {
ScopedObjectAccess soa(Thread::Current());
- JValue args[1];
- args[0].SetL(*cleared);
- soa.DecodeMethod(WellKnownClasses::java_lang_ref_ReferenceQueue_add)->Invoke(soa.Self(), NULL,
- args, NULL);
+ JValue result;
+ JValue float_result;
+ ArgArray arg_array(NULL, 0);
+ arg_array.Append(reinterpret_cast<uint32_t>(*cleared));
+ soa.DecodeMethod(WellKnownClasses::java_lang_ref_ReferenceQueue_add)->Invoke(soa.Self(),
+ arg_array.GetArray(), arg_array.GetNumBytes(), &result, &float_result);
}
*cleared = NULL;
}
diff --git a/src/interpreter/interpreter.cc b/src/interpreter/interpreter.cc
index 195549a3a0..1a571ecab1 100644
--- a/src/interpreter/interpreter.cc
+++ b/src/interpreter/interpreter.cc
@@ -54,13 +54,13 @@ static AbstractMethod* throw_method_ = NULL;
static uint32_t throw_dex_pc_ = 0;
static void UnstartedRuntimeInvoke(Thread* self, AbstractMethod* target_method,
- Object* receiver, JValue* args, JValue* result)
+ Object* receiver, uint32_t* args, JValue* result)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
// In a runtime that's not started we intercept certain methods to avoid complicated dependency
// problems in core libraries.
std::string name(PrettyMethod(target_method));
if (name == "java.lang.Class java.lang.Class.forName(java.lang.String)") {
- std::string descriptor(DotToDescriptor(args[0].GetL()->AsString()->ToModifiedUtf8().c_str()));
+ std::string descriptor(DotToDescriptor(reinterpret_cast<Object*>(args[0])->AsString()->ToModifiedUtf8().c_str()));
ClassLoader* class_loader = NULL; // shadow_frame.GetMethod()->GetDeclaringClass()->GetClassLoader();
Class* found = Runtime::Current()->GetClassLinker()->FindClass(descriptor.c_str(),
class_loader);
@@ -73,13 +73,13 @@ static void UnstartedRuntimeInvoke(Thread* self, AbstractMethod* target_method,
CHECK(c != NULL);
Object* obj = klass->AllocObject(self);
CHECK(obj != NULL);
- EnterInterpreterFromInvoke(self, c, obj, NULL, NULL);
+ EnterInterpreterFromInvoke(self, c, obj, NULL, NULL, NULL);
result->SetL(obj);
} else if (name == "java.lang.reflect.Field java.lang.Class.getDeclaredField(java.lang.String)") {
// Special managed code cut-out to allow field lookup in a un-started runtime that'd fail
// going the reflective Dex way.
Class* klass = receiver->AsClass();
- String* name = args[0].GetL()->AsString();
+ String* name = reinterpret_cast<Object*>(args[0])->AsString();
Field* found = NULL;
FieldHelper fh;
ObjectArray<Field>* fields = klass->GetIFields();
@@ -108,25 +108,25 @@ static void UnstartedRuntimeInvoke(Thread* self, AbstractMethod* target_method,
result->SetL(found);
} else if (name == "void java.lang.System.arraycopy(java.lang.Object, int, java.lang.Object, int, int)") {
// Special case array copying without initializing System.
- Class* ctype = args[0].GetL()->GetClass()->GetComponentType();
- jint srcPos = args[1].GetI();
- jint dstPos = args[3].GetI();
- jint length = args[4].GetI();
+ Class* ctype = reinterpret_cast<Object*>(args[0])->GetClass()->GetComponentType();
+ jint srcPos = args[1];
+ jint dstPos = args[3];
+ jint length = args[4];
if (!ctype->IsPrimitive()) {
- ObjectArray<Object>* src = args[0].GetL()->AsObjectArray<Object>();
- ObjectArray<Object>* dst = args[2].GetL()->AsObjectArray<Object>();
+ ObjectArray<Object>* src = reinterpret_cast<Object*>(args[0])->AsObjectArray<Object>();
+ ObjectArray<Object>* dst = reinterpret_cast<Object*>(args[2])->AsObjectArray<Object>();
for (jint i = 0; i < length; ++i) {
dst->Set(dstPos + i, src->Get(srcPos + i));
}
} else if (ctype->IsPrimitiveChar()) {
- CharArray* src = args[0].GetL()->AsCharArray();
- CharArray* dst = args[2].GetL()->AsCharArray();
+ CharArray* src = reinterpret_cast<Object*>(args[0])->AsCharArray();
+ CharArray* dst = reinterpret_cast<Object*>(args[2])->AsCharArray();
for (jint i = 0; i < length; ++i) {
dst->Set(dstPos + i, src->Get(srcPos + i));
}
} else if (ctype->IsPrimitiveInt()) {
- IntArray* src = args[0].GetL()->AsIntArray();
- IntArray* dst = args[2].GetL()->AsIntArray();
+ IntArray* src = reinterpret_cast<Object*>(args[0])->AsIntArray();
+ IntArray* dst = reinterpret_cast<Object*>(args[2])->AsIntArray();
for (jint i = 0; i < length; ++i) {
dst->Set(dstPos + i, src->Get(srcPos + i));
}
@@ -135,13 +135,13 @@ static void UnstartedRuntimeInvoke(Thread* self, AbstractMethod* target_method,
}
} else {
// Not special, continue with regular interpreter execution.
- EnterInterpreterFromInvoke(self, target_method, receiver, args, result);
+ EnterInterpreterFromInvoke(self, target_method, receiver, args, result, result);
}
}
// Hand select a number of methods to be run in a not yet started runtime without using JNI.
static void UnstartedRuntimeJni(Thread* self, AbstractMethod* method,
- Object* receiver, JValue* args, JValue* result)
+ Object* receiver, uint32_t* args, JValue* result)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
std::string name(PrettyMethod(method));
if (name == "java.lang.ClassLoader dalvik.system.VMStack.getCallingClassLoader()") {
@@ -151,55 +151,59 @@ static void UnstartedRuntimeJni(Thread* self, AbstractMethod* method,
visitor.WalkStack();
result->SetL(visitor.caller->GetDeclaringClass());
} else if (name == "double java.lang.Math.log(double)") {
- result->SetD(log(args[0].GetD()));
+ JValue value;
+ value.SetJ((static_cast<uint64_t>(args[1]) << 32) | args[0]);
+ result->SetD(log(value.GetD()));
} else if (name == "java.lang.String java.lang.Class.getNameNative()") {
result->SetL(receiver->AsClass()->ComputeName());
} else if (name == "int java.lang.Float.floatToRawIntBits(float)") {
- result->SetI(args[0].GetI());
+ result->SetI(args[0]);
} else if (name == "float java.lang.Float.intBitsToFloat(int)") {
- result->SetF(args[0].GetF());
+ result->SetI(args[0]);
} else if (name == "double java.lang.Math.exp(double)") {
- result->SetD(exp(args[0].GetD()));
+ JValue value;
+ value.SetJ((static_cast<uint64_t>(args[1]) << 32) | args[0]);
+ result->SetD(exp(value.GetD()));
} else if (name == "java.lang.Object java.lang.Object.internalClone()") {
result->SetL(receiver->Clone(self));
} else if (name == "void java.lang.Object.notifyAll()") {
receiver->NotifyAll(self);
} else if (name == "int java.lang.String.compareTo(java.lang.String)") {
- String* rhs = args[0].GetL()->AsString();
+ String* rhs = reinterpret_cast<Object*>(args[0])->AsString();
CHECK(rhs != NULL);
result->SetI(receiver->AsString()->CompareTo(rhs));
} else if (name == "java.lang.String java.lang.String.intern()") {
result->SetL(receiver->AsString()->Intern());
} else if (name == "int java.lang.String.fastIndexOf(int, int)") {
- result->SetI(receiver->AsString()->FastIndexOf(args[0].GetI(), args[1].GetI()));
+ result->SetI(receiver->AsString()->FastIndexOf(args[0], args[1]));
} else if (name == "java.lang.Object java.lang.reflect.Array.createMultiArray(java.lang.Class, int[])") {
- result->SetL(Array::CreateMultiArray(self, args[0].GetL()->AsClass(), args[1].GetL()->AsIntArray()));
+ result->SetL(Array::CreateMultiArray(self, reinterpret_cast<Object*>(args[0])->AsClass(), reinterpret_cast<Object*>(args[1])->AsIntArray()));
} else if (name == "java.lang.Object java.lang.Throwable.nativeFillInStackTrace()") {
ScopedObjectAccessUnchecked soa(self);
result->SetL(soa.Decode<Object*>(self->CreateInternalStackTrace(soa)));
} else if (name == "boolean java.nio.ByteOrder.isLittleEndian()") {
result->SetJ(JNI_TRUE);
} else if (name == "boolean sun.misc.Unsafe.compareAndSwapInt(java.lang.Object, long, int, int)") {
- Object* obj = args[0].GetL();
- jlong offset = args[1].GetJ();
- jint expectedValue = args[2].GetI();
- jint newValue = args[3].GetI();
+ Object* obj = reinterpret_cast<Object*>(args[0]);
+ jlong offset = (static_cast<uint64_t>(args[2]) << 32) | args[1];
+ jint expectedValue = args[3];
+ jint newValue = args[4];
byte* raw_addr = reinterpret_cast<byte*>(obj) + offset;
volatile int32_t* address = reinterpret_cast<volatile int32_t*>(raw_addr);
// Note: android_atomic_release_cas() returns 0 on success, not failure.
int r = android_atomic_release_cas(expectedValue, newValue, address);
result->SetZ(r == 0);
} else if (name == "void sun.misc.Unsafe.putObject(java.lang.Object, long, java.lang.Object)") {
- Object* obj = args[0].GetL();
- Object* newValue = args[2].GetL();
- obj->SetFieldObject(MemberOffset(args[1].GetJ()), newValue, false);
+ Object* obj = reinterpret_cast<Object*>(args[0]);
+ Object* newValue = reinterpret_cast<Object*>(args[3]);
+ obj->SetFieldObject(MemberOffset((static_cast<uint64_t>(args[2]) << 32) | args[1]), newValue, false);
} else {
LOG(FATAL) << "Attempt to invoke native method in non-started runtime: " << name;
}
}
static void InterpreterJni(Thread* self, AbstractMethod* method, StringPiece shorty,
- Object* receiver, JValue* args, JValue* result)
+ Object* receiver, uint32_t* args, JValue* result)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
// TODO: The following enters JNI code using a typedef-ed function rather than the JNI compiler,
// it should be removed and JNI compiled stubs used instead.
@@ -236,21 +240,21 @@ static void InterpreterJni(Thread* self, AbstractMethod* method, StringPiece sho
ScopedLocalRef<jclass> klass(soa.Env(),
soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
ScopedThreadStateChange tsc(self, kNative);
- result->SetB(fn(soa.Env(), klass.get(), args[0].GetI()));
+ result->SetB(fn(soa.Env(), klass.get(), args[0]));
} else if (shorty == "II") {
typedef jint (fnptr)(JNIEnv*, jclass, jint);
fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
ScopedLocalRef<jclass> klass(soa.Env(),
soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
ScopedThreadStateChange tsc(self, kNative);
- result->SetI(fn(soa.Env(), klass.get(), args[0].GetI()));
+ result->SetI(fn(soa.Env(), klass.get(), args[0]));
} else if (shorty == "LL") {
typedef jobject (fnptr)(JNIEnv*, jclass, jobject);
fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
ScopedLocalRef<jclass> klass(soa.Env(),
soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
ScopedLocalRef<jobject> arg0(soa.Env(),
- soa.AddLocalReference<jobject>(args[0].GetL()));
+ soa.AddLocalReference<jobject>(reinterpret_cast<Object*>(args[0])));
jobject jresult;
{
ScopedThreadStateChange tsc(self, kNative);
@@ -263,39 +267,39 @@ static void InterpreterJni(Thread* self, AbstractMethod* method, StringPiece sho
ScopedLocalRef<jclass> klass(soa.Env(),
soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
ScopedThreadStateChange tsc(self, kNative);
- result->SetI(fn(soa.Env(), klass.get(), args[0].GetI(), args[1].GetZ()));
+ result->SetI(fn(soa.Env(), klass.get(), args[0], args[1]));
} else if (shorty == "ILI") {
typedef jint (fnptr)(JNIEnv*, jclass, jobject, jint);
fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
ScopedLocalRef<jclass> klass(soa.Env(),
soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
ScopedLocalRef<jobject> arg0(soa.Env(),
- soa.AddLocalReference<jobject>(args[0].GetL()));
+ soa.AddLocalReference<jobject>(reinterpret_cast<Object*>(args[0])));
ScopedThreadStateChange tsc(self, kNative);
- result->SetI(fn(soa.Env(), klass.get(), arg0.get(), args[1].GetI()));
+ result->SetI(fn(soa.Env(), klass.get(), arg0.get(), args[1]));
} else if (shorty == "SIZ") {
typedef jshort (fnptr)(JNIEnv*, jclass, jint, jboolean);
fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
ScopedLocalRef<jclass> klass(soa.Env(),
soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
ScopedThreadStateChange tsc(self, kNative);
- result->SetS(fn(soa.Env(), klass.get(), args[0].GetI(), args[1].GetZ()));
+ result->SetS(fn(soa.Env(), klass.get(), args[0], args[1]));
} else if (shorty == "VIZ") {
typedef void (fnptr)(JNIEnv*, jclass, jint, jboolean);
fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
ScopedLocalRef<jclass> klass(soa.Env(),
soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
ScopedThreadStateChange tsc(self, kNative);
- fn(soa.Env(), klass.get(), args[0].GetI(), args[1].GetZ());
+ fn(soa.Env(), klass.get(), args[0], args[1]);
} else if (shorty == "ZLL") {
typedef jboolean (fnptr)(JNIEnv*, jclass, jobject, jobject);
fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
ScopedLocalRef<jclass> klass(soa.Env(),
soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
ScopedLocalRef<jobject> arg0(soa.Env(),
- soa.AddLocalReference<jobject>(args[0].GetL()));
+ soa.AddLocalReference<jobject>(reinterpret_cast<Object*>(args[0])));
ScopedLocalRef<jobject> arg1(soa.Env(),
- soa.AddLocalReference<jobject>(args[1].GetL()));
+ soa.AddLocalReference<jobject>(reinterpret_cast<Object*>(args[1])));
ScopedThreadStateChange tsc(self, kNative);
result->SetZ(fn(soa.Env(), klass.get(), arg0.get(), arg1.get()));
} else if (shorty == "ZILL") {
@@ -304,32 +308,31 @@ static void InterpreterJni(Thread* self, AbstractMethod* method, StringPiece sho
ScopedLocalRef<jclass> klass(soa.Env(),
soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
ScopedLocalRef<jobject> arg1(soa.Env(),
- soa.AddLocalReference<jobject>(args[1].GetL()));
+ soa.AddLocalReference<jobject>(reinterpret_cast<Object*>(args[1])));
ScopedLocalRef<jobject> arg2(soa.Env(),
- soa.AddLocalReference<jobject>(args[2].GetL()));
+ soa.AddLocalReference<jobject>(reinterpret_cast<Object*>(args[2])));
ScopedThreadStateChange tsc(self, kNative);
- result->SetZ(fn(soa.Env(), klass.get(), args[0].GetI(), arg1.get(), arg2.get()));
+ result->SetZ(fn(soa.Env(), klass.get(), args[0], arg1.get(), arg2.get()));
} else if (shorty == "VILII") {
typedef void (fnptr)(JNIEnv*, jclass, jint, jobject, jint, jint);
fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
ScopedLocalRef<jclass> klass(soa.Env(),
soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
ScopedLocalRef<jobject> arg1(soa.Env(),
- soa.AddLocalReference<jobject>(args[1].GetL()));
+ soa.AddLocalReference<jobject>(reinterpret_cast<Object*>(args[1])));
ScopedThreadStateChange tsc(self, kNative);
- fn(soa.Env(), klass.get(), args[0].GetI(), arg1.get(), args[2].GetI(), args[3].GetI());
+ fn(soa.Env(), klass.get(), args[0], arg1.get(), args[2], args[3]);
} else if (shorty == "VLILII") {
typedef void (fnptr)(JNIEnv*, jclass, jobject, jint, jobject, jint, jint);
fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
ScopedLocalRef<jclass> klass(soa.Env(),
soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
ScopedLocalRef<jobject> arg0(soa.Env(),
- soa.AddLocalReference<jobject>(args[0].GetL()));
+ soa.AddLocalReference<jobject>(reinterpret_cast<Object*>(args[0])));
ScopedLocalRef<jobject> arg2(soa.Env(),
- soa.AddLocalReference<jobject>(args[2].GetL()));
+ soa.AddLocalReference<jobject>(reinterpret_cast<Object*>(args[2])));
ScopedThreadStateChange tsc(self, kNative);
- fn(soa.Env(), klass.get(), arg0.get(), args[1].GetI(), arg2.get(), args[3].GetI(),
- args[4].GetI());
+ fn(soa.Env(), klass.get(), arg0.get(), args[1], arg2.get(), args[3], args[4]);
} else {
LOG(FATAL) << "Do something with static native method: " << PrettyMethod(method)
<< " shorty: " << shorty;
@@ -352,7 +355,7 @@ static void InterpreterJni(Thread* self, AbstractMethod* method, StringPiece sho
ScopedLocalRef<jobject> rcvr(soa.Env(),
soa.AddLocalReference<jobject>(receiver));
ScopedLocalRef<jobject> arg0(soa.Env(),
- soa.AddLocalReference<jobject>(args[0].GetL()));
+ soa.AddLocalReference<jobject>(reinterpret_cast<Object*>(args[0])));
jobject jresult;
{
ScopedThreadStateChange tsc(self, kNative);
@@ -367,7 +370,7 @@ static void InterpreterJni(Thread* self, AbstractMethod* method, StringPiece sho
ScopedLocalRef<jobject> rcvr(soa.Env(),
soa.AddLocalReference<jobject>(receiver));
ScopedThreadStateChange tsc(self, kNative);
- result->SetI(fn(soa.Env(), rcvr.get(), args[0].GetI(), args[1].GetI()));
+ result->SetI(fn(soa.Env(), rcvr.get(), args[0], args[1]));
} else {
LOG(FATAL) << "Do something with native method: " << PrettyMethod(method)
<< " shorty: " << shorty;
@@ -405,14 +408,25 @@ static void DoInvoke(Thread* self, MethodHelper& mh, ShadowFrame& shadow_frame,
mh.ChangeMethod(target_method);
ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
if (is_range) {
- arg_array.BuildArgArray(shadow_frame, dec_insn.vC + (type != kStatic ? 1 : 0));
+ arg_array.BuildArgArray(shadow_frame, receiver, dec_insn.vC + (type != kStatic ? 1 : 0));
} else {
- arg_array.BuildArgArray(shadow_frame, dec_insn.arg + (type != kStatic ? 1 : 0));
+ arg_array.BuildArgArray(shadow_frame, receiver, dec_insn.arg + (type != kStatic ? 1 : 0));
}
if (LIKELY(Runtime::Current()->IsStarted())) {
- target_method->Invoke(self, receiver, arg_array.get(), result);
+ JValue unused_result;
+ if (mh.IsReturnFloatOrDouble()) {
+ target_method->Invoke(self, arg_array.GetArray(), arg_array.GetNumBytes(),
+ &unused_result, result);
+ } else {
+ target_method->Invoke(self, arg_array.GetArray(), arg_array.GetNumBytes(),
+ result, &unused_result);
+ }
} else {
- UnstartedRuntimeInvoke(self, target_method, receiver, arg_array.get(), result);
+ uint32_t* args = arg_array.GetArray();
+ if (type != kStatic) {
+ args++;
+ }
+ UnstartedRuntimeInvoke(self, target_method, receiver, args, result);
}
mh.ChangeMethod(shadow_frame.GetMethod());
}
@@ -1792,7 +1806,7 @@ static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* c
}
void EnterInterpreterFromInvoke(Thread* self, AbstractMethod* method, Object* receiver,
- JValue* args, JValue* result) {
+ uint32_t* args, JValue* result, JValue* float_result) {
DCHECK_EQ(self, Thread::Current());
if (__builtin_frame_address(0) < self->GetStackEnd()) {
ThrowStackOverflowError(self);
@@ -1838,36 +1852,50 @@ void EnterInterpreterFromInvoke(Thread* self, AbstractMethod* method, Object* re
CHECK(method->GetDeclaringClass()->IsInitializing());
}
const char* shorty = mh.GetShorty();
- size_t arg_pos = 0;
- for (; cur_reg < num_regs; ++cur_reg, ++arg_pos) {
- DCHECK_LT(arg_pos + 1, mh.GetShortyLength());
- switch (shorty[arg_pos + 1]) {
+ for (size_t shorty_pos = 0, arg_pos = 0; cur_reg < num_regs; ++shorty_pos, ++arg_pos, cur_reg++) {
+ DCHECK_LT(shorty_pos + 1, mh.GetShortyLength());
+ switch (shorty[shorty_pos + 1]) {
case 'L': {
- Object* o = args[arg_pos].GetL();
+ Object* o = reinterpret_cast<Object*>(args[arg_pos]);
shadow_frame->SetVRegReference(cur_reg, o);
break;
}
- case 'J': case 'D':
- shadow_frame->SetVRegLong(cur_reg, args[arg_pos].GetJ());
+ case 'J': case 'D': {
+ uint64_t wide_value = (static_cast<uint64_t>(args[arg_pos + 1]) << 32) | args[arg_pos];
+ shadow_frame->SetVRegLong(cur_reg, wide_value);
cur_reg++;
+ arg_pos++;
break;
+ }
default:
- shadow_frame->SetVReg(cur_reg, args[arg_pos].GetI());
+ shadow_frame->SetVReg(cur_reg, args[arg_pos]);
break;
}
}
if (LIKELY(!method->IsNative())) {
JValue r = Execute(self, mh, code_item, *shadow_frame.get(), JValue());
- if (result != NULL) {
- *result = r;
+ if (result != NULL && float_result != NULL) {
+ if (mh.IsReturnFloatOrDouble()) {
+ *float_result = r;
+ } else {
+ *result = r;
+ }
}
} else {
// We don't expect to be asked to interpret native code (which is entered via a JNI compiler
// generated stub) except during testing and image writing.
if (!Runtime::Current()->IsStarted()) {
- UnstartedRuntimeJni(self, method, receiver, args, result);
+ if (mh.IsReturnFloatOrDouble()) {
+ UnstartedRuntimeJni(self, method, receiver, args, float_result);
+ } else {
+ UnstartedRuntimeJni(self, method, receiver, args, result);
+ }
} else {
- InterpreterJni(self, method, shorty, receiver, args, result);
+ if (mh.IsReturnFloatOrDouble()) {
+ InterpreterJni(self, method, shorty, receiver, args, float_result);
+ } else {
+ InterpreterJni(self, method, shorty, receiver, args, result);
+ }
}
}
self->PopShadowFrame();
diff --git a/src/interpreter/interpreter.h b/src/interpreter/interpreter.h
index 12da736253..91816c9c83 100644
--- a/src/interpreter/interpreter.h
+++ b/src/interpreter/interpreter.h
@@ -34,7 +34,8 @@ class Thread;
namespace interpreter {
extern void EnterInterpreterFromInvoke(Thread* self, mirror::AbstractMethod* method,
- mirror::Object* receiver, JValue* args, JValue* result)
+ mirror::Object* receiver, uint32_t* args,
+ JValue* result, JValue* float_result)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
extern JValue EnterInterpreterFromDeoptimize(Thread* self, ShadowFrame& shadow_frame,
diff --git a/src/invoke_arg_array_builder.h b/src/invoke_arg_array_builder.h
index 19c42ac9b8..ecd0fb07c3 100644
--- a/src/invoke_arg_array_builder.h
+++ b/src/invoke_arg_array_builder.h
@@ -42,170 +42,240 @@ static inline size_t NumArgArrayBytes(const char* shorty, uint32_t shorty_len) {
class ArgArray {
public:
explicit ArgArray(const char* shorty, uint32_t shorty_len)
- : shorty_(shorty), shorty_len_(shorty_len) {
- if (shorty_len - 1 < kSmallArgArraySize) {
+ : shorty_(shorty), shorty_len_(shorty_len), num_bytes_(0) {
+ // TODO: This code is conservative. The multiply by 2 is to handle the case where all args are
+ // doubles or longs. We could scan the shorty to use the arg array more often.
+ if (shorty_len * 2 <= kSmallArgArraySize) {
arg_array_ = small_arg_array_;
} else {
- large_arg_array_.reset(new JValue[shorty_len_ - 1]);
+ large_arg_array_.reset(new uint32_t[shorty_len_ * 2]);
arg_array_ = large_arg_array_.get();
}
}
- JValue* get() {
+ uint32_t* GetArray() {
return arg_array_;
}
- void BuildArgArray(const ScopedObjectAccess& soa, va_list ap)
+ uint32_t GetNumBytes() {
+ return num_bytes_;
+ }
+
+ void Append(uint32_t value) {
+ arg_array_[num_bytes_ / 4] = value;
+ num_bytes_ += 4;
+ }
+
+ void AppendWide(uint64_t value) {
+ arg_array_[num_bytes_ / 4] = value;
+ arg_array_[(num_bytes_ / 4) + 1] = value >> 32;
+ num_bytes_ += 8;
+ }
+
+ void BuildArgArray(const ScopedObjectAccess& soa, mirror::Object* receiver, va_list ap)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- for (size_t i = 1, offset = 0; i < shorty_len_; ++i, ++offset) {
+ // Set receiver if non-null (method is not static)
+ size_t offset = 0;
+ if (receiver != NULL) {
+ arg_array_[0] = reinterpret_cast<int32_t>(receiver);
+ offset++;
+ }
+ for (size_t i = 1; i < shorty_len_; ++i, ++offset) {
switch (shorty_[i]) {
case 'Z':
- arg_array_[offset].SetZ(va_arg(ap, jint));
+ arg_array_[offset] = va_arg(ap, jint);
break;
case 'B':
- arg_array_[offset].SetB(va_arg(ap, jint));
+ arg_array_[offset] = va_arg(ap, jint);
break;
case 'C':
- arg_array_[offset].SetC(va_arg(ap, jint));
+ arg_array_[offset] = va_arg(ap, jint);
break;
case 'S':
- arg_array_[offset].SetS(va_arg(ap, jint));
+ arg_array_[offset] = va_arg(ap, jint);
break;
case 'I':
- arg_array_[offset].SetI(va_arg(ap, jint));
+ arg_array_[offset] = va_arg(ap, jint);
break;
- case 'F':
- arg_array_[offset].SetF(va_arg(ap, jdouble));
+ case 'F': {
+ JValue value;
+ value.SetF(va_arg(ap, jdouble));
+ arg_array_[offset] = value.GetI();
break;
+ }
case 'L':
- arg_array_[offset].SetL(soa.Decode<mirror::Object*>(va_arg(ap, jobject)));
+ arg_array_[offset] = reinterpret_cast<int32_t>(soa.Decode<mirror::Object*>(va_arg(ap, jobject)));
break;
- case 'D':
- arg_array_[offset].SetD(va_arg(ap, jdouble));
+ case 'D': {
+ JValue value;
+ value.SetD(va_arg(ap, jdouble));
+ arg_array_[offset] = value.GetJ();
+ arg_array_[offset + 1] = value.GetJ() >> 32;
+ offset++;
break;
- case 'J':
- arg_array_[offset].SetJ(va_arg(ap, jlong));
+ }
+ case 'J': {
+ long long l = va_arg(ap, jlong);
+ arg_array_[offset] = l;
+ arg_array_[offset + 1] = l >> 32;
+ offset++;
break;
+ }
}
}
+ num_bytes_ += 4 * offset;
}
- void BuildArgArray(const ScopedObjectAccess& soa, jvalue* args)
+ void BuildArgArray(const ScopedObjectAccess& soa, mirror::Object* receiver, jvalue* args)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- for (size_t i = 1, offset = 0; i < shorty_len_; ++i, ++offset) {
+ // Set receiver if non-null (method is not static)
+ size_t offset = 0;
+ if (receiver != NULL) {
+ arg_array_[0] = reinterpret_cast<int32_t>(receiver);
+ offset++;
+ }
+ for (size_t i = 1, args_offset = 0; i < shorty_len_; ++i, ++offset, ++args_offset) {
switch (shorty_[i]) {
case 'Z':
- arg_array_[offset].SetZ(args[offset].z);
+ arg_array_[offset] = args[args_offset].z;
break;
case 'B':
- arg_array_[offset].SetB(args[offset].b);
+ arg_array_[offset] = args[args_offset].b;
break;
case 'C':
- arg_array_[offset].SetC(args[offset].c);
+ arg_array_[offset] = args[args_offset].c;
break;
case 'S':
- arg_array_[offset].SetS(args[offset].s);
+ arg_array_[offset] = args[args_offset].s;
break;
case 'I':
- arg_array_[offset].SetI(args[offset].i);
+ arg_array_[offset] = args[args_offset].i;
break;
case 'F':
- arg_array_[offset].SetF(args[offset].f);
+ arg_array_[offset] = args[args_offset].i;
break;
case 'L':
- arg_array_[offset].SetL(soa.Decode<mirror::Object*>(args[offset].l));
+ arg_array_[offset] = reinterpret_cast<int32_t>(soa.Decode<mirror::Object*>(args[args_offset].l));
break;
case 'D':
- arg_array_[offset].SetD(args[offset].d);
+ arg_array_[offset] = args[args_offset].j;
+ arg_array_[offset + 1] = args[args_offset].j >> 32;
+ offset++;
break;
case 'J':
- arg_array_[offset].SetJ(args[offset].j);
+ arg_array_[offset] = args[args_offset].j;
+ arg_array_[offset + 1] = args[args_offset].j >> 32;
+ offset++;
break;
}
}
+ num_bytes_ += 4 * offset;
}
- void BuildArgArray(const ShadowFrame& shadow_frame, uint32_t range_start)
+ void BuildArgArray(const ShadowFrame& shadow_frame, mirror::Object* receiver, uint32_t range_start)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- for (size_t i = 1, offset = 0; i < shorty_len_; ++i, ++offset) {
+ // Set receiver if non-null (method is not static)
+ size_t offset = 0;
+ if (receiver != NULL) {
+ arg_array_[0] = reinterpret_cast<int32_t>(receiver);
+ offset++;
+ }
+ for (size_t i = 1, reg_offset = 0; i < shorty_len_; ++i, ++offset, ++reg_offset) {
switch (shorty_[i]) {
case 'Z':
- arg_array_[i - 1].SetZ(shadow_frame.GetVReg(range_start + offset));
+ arg_array_[offset] = shadow_frame.GetVReg(range_start + reg_offset);
break;
case 'B':
- arg_array_[i - 1].SetB(shadow_frame.GetVReg(range_start + offset));
+ arg_array_[offset] = shadow_frame.GetVReg(range_start + reg_offset);
break;
case 'C':
- arg_array_[i - 1].SetC(shadow_frame.GetVReg(range_start + offset));
+ arg_array_[offset] = shadow_frame.GetVReg(range_start + reg_offset);
break;
case 'S':
- arg_array_[i - 1].SetS(shadow_frame.GetVReg(range_start + offset));
+ arg_array_[offset] = shadow_frame.GetVReg(range_start + reg_offset);
break;
case 'I':
- arg_array_[i - 1].SetI(shadow_frame.GetVReg(range_start + offset));
+ arg_array_[offset] = shadow_frame.GetVReg(range_start + reg_offset);
break;
case 'F':
- arg_array_[i - 1].SetF(shadow_frame.GetVRegFloat(range_start + offset));
+ arg_array_[offset] = shadow_frame.GetVReg(range_start + reg_offset);
break;
case 'L':
- arg_array_[i - 1].SetL(shadow_frame.GetVRegReference(range_start + offset));
+ arg_array_[offset] = reinterpret_cast<int32_t>(shadow_frame.GetVRegReference(range_start + reg_offset));
break;
case 'D':
- arg_array_[i - 1].SetD(shadow_frame.GetVRegDouble(range_start + offset));
+ arg_array_[offset] = shadow_frame.GetVRegLong(range_start + reg_offset);
+ arg_array_[offset + 1] = shadow_frame.GetVRegLong(range_start + reg_offset) >> 32;
+ reg_offset++;
offset++;
break;
case 'J':
- arg_array_[i - 1].SetJ(shadow_frame.GetVRegLong(range_start + offset));
+ arg_array_[offset] = shadow_frame.GetVRegLong(range_start + reg_offset);
+ arg_array_[offset + 1] = shadow_frame.GetVRegLong(range_start + reg_offset) >> 32;
+ reg_offset++;
offset++;
break;
}
}
+ num_bytes_ += 4 * offset;
}
- void BuildArgArray(const ShadowFrame& shadow_frame, const uint32_t* arg_regs)
+ void BuildArgArray(const ShadowFrame& shadow_frame, mirror::Object* receiver, const uint32_t* arg_regs)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- for (size_t i = 1, offset = 0; i < shorty_len_; ++i, ++offset) {
+ // Set receiver if non-null (method is not static)
+ size_t offset = 0;
+ if (receiver != NULL) {
+ arg_array_[0] = reinterpret_cast<int32_t>(receiver);
+ offset++;
+ }
+ for (size_t i = 1, reg_offset = 0; i < shorty_len_; ++i, ++offset, ++reg_offset) {
switch (shorty_[i]) {
case 'Z':
- arg_array_[i - 1].SetZ(shadow_frame.GetVReg(arg_regs[offset]));
+ arg_array_[offset] = shadow_frame.GetVReg(arg_regs[reg_offset]);
break;
case 'B':
- arg_array_[i - 1].SetB(shadow_frame.GetVReg(arg_regs[offset]));
+ arg_array_[offset] = shadow_frame.GetVReg(arg_regs[reg_offset]);
break;
case 'C':
- arg_array_[i - 1].SetC(shadow_frame.GetVReg(arg_regs[offset]));
+ arg_array_[offset] = shadow_frame.GetVReg(arg_regs[reg_offset]);
break;
case 'S':
- arg_array_[i - 1].SetS(shadow_frame.GetVReg(arg_regs[offset]));
+ arg_array_[offset] = shadow_frame.GetVReg(arg_regs[reg_offset]);
break;
case 'I':
- arg_array_[i - 1].SetI(shadow_frame.GetVReg(arg_regs[offset]));
+ arg_array_[offset] = shadow_frame.GetVReg(arg_regs[reg_offset]);
break;
case 'F':
- arg_array_[i - 1].SetF(shadow_frame.GetVRegFloat(arg_regs[offset]));
+ arg_array_[offset] = shadow_frame.GetVReg(arg_regs[reg_offset]);
break;
case 'L':
- arg_array_[i - 1].SetL(shadow_frame.GetVRegReference(arg_regs[offset]));
+ arg_array_[offset] = reinterpret_cast<int32_t>(shadow_frame.GetVRegReference(arg_regs[reg_offset]));
break;
case 'D':
- arg_array_[i - 1].SetD(shadow_frame.GetVRegDouble(arg_regs[offset]));
+ arg_array_[offset] = shadow_frame.GetVRegLong(arg_regs[reg_offset]);
+ arg_array_[offset + 1] = shadow_frame.GetVRegLong(arg_regs[reg_offset]) >> 32;
offset++;
+ reg_offset++;
break;
case 'J':
- arg_array_[i - 1].SetJ(shadow_frame.GetVRegLong(arg_regs[offset]));
+ arg_array_[offset] = shadow_frame.GetVRegLong(arg_regs[reg_offset]);
+ arg_array_[offset + 1] = shadow_frame.GetVRegLong(arg_regs[reg_offset]) >> 32;
offset++;
+ reg_offset++;
break;
}
}
+ num_bytes_ += 4 * offset;
}
private:
enum { kSmallArgArraySize = 16 };
const char* const shorty_;
const uint32_t shorty_len_;
- JValue* arg_array_;
- JValue small_arg_array_[kSmallArgArraySize];
- UniquePtr<JValue[]> large_arg_array_;
+ uint32_t num_bytes_;
+ uint32_t* arg_array_;
+ uint32_t small_arg_array_[kSmallArgArraySize];
+ UniquePtr<uint32_t[]> large_arg_array_;
};
} // namespace art
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index 887fcb4148..eabce2cb72 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -85,20 +85,19 @@ static jweak AddWeakGlobalReference(ScopedObjectAccess& soa, Object* obj)
return reinterpret_cast<jweak>(ref);
}
-static bool IsBadJniVersion(int version) {
- // We don't support JNI_VERSION_1_1. These are the only other valid versions.
- return version != JNI_VERSION_1_2 && version != JNI_VERSION_1_4 && version != JNI_VERSION_1_6;
-}
-
-static void CheckMethodArguments(AbstractMethod* m, JValue* args)
+static void CheckMethodArguments(AbstractMethod* m, uint32_t* args)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
MethodHelper mh(m);
const DexFile::TypeList* params = mh.GetParameterTypeList();
if (params == NULL) {
return; // No arguments so nothing to check.
}
+ uint32_t offset = 0;
uint32_t num_params = params->Size();
size_t error_count = 0;
+ if (!m->IsStatic()) {
+ offset = 1;
+ }
for (uint32_t i = 0; i < num_params; i++) {
uint16_t type_idx = params->GetTypeItem(i).type_idx_;
Class* param_type = mh.GetClassFromTypeIdx(type_idx);
@@ -112,12 +111,14 @@ static void CheckMethodArguments(AbstractMethod* m, JValue* args)
++error_count;
} else if (!param_type->IsPrimitive()) {
// TODO: check primitives are in range.
- Object* argument = args[i].GetL();
+ Object* argument = reinterpret_cast<Object*>(args[i + offset]);
if (argument != NULL && !argument->InstanceOf(param_type)) {
LOG(ERROR) << "JNI ERROR (app bug): attempt to pass an instance of "
<< PrettyTypeOf(argument) << " as argument " << (i + 1) << " to " << PrettyMethod(m);
++error_count;
}
+ } else if (param_type->IsPrimitiveLong() || param_type->IsPrimitiveDouble()) {
+ offset++;
}
}
if (error_count > 0) {
@@ -127,15 +128,13 @@ static void CheckMethodArguments(AbstractMethod* m, JValue* args)
}
}
-static JValue InvokeWithArgArray(const ScopedObjectAccess& soa, Object* receiver,
- AbstractMethod* method, JValue* args)
+void InvokeWithArgArray(const ScopedObjectAccess& soa, AbstractMethod* method,
+ ArgArray* arg_array, JValue* result, JValue* float_result)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
if (UNLIKELY(soa.Env()->check_jni)) {
- CheckMethodArguments(method, args);
+ CheckMethodArguments(method, arg_array->GetArray());
}
- JValue result;
- method->Invoke(soa.Self(), receiver, args, &result);
- return result;
+ method->Invoke(soa.Self(), arg_array->GetArray(), arg_array->GetNumBytes(), result, float_result);
}
static JValue InvokeWithVarArgs(const ScopedObjectAccess& soa, jobject obj,
@@ -144,9 +143,16 @@ static JValue InvokeWithVarArgs(const ScopedObjectAccess& soa, jobject obj,
Object* receiver = soa.Decode<Object*>(obj);
AbstractMethod* method = soa.DecodeMethod(mid);
MethodHelper mh(method);
+ JValue result;
+ JValue float_result;
ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
- arg_array.BuildArgArray(soa, args);
- return InvokeWithArgArray(soa, receiver, method, arg_array.get());
+ arg_array.BuildArgArray(soa, receiver, args);
+ InvokeWithArgArray(soa, method, &arg_array, &result, &float_result);
+ if (mh.IsReturnFloatOrDouble()) {
+ return float_result;
+ } else {
+ return result;
+ }
}
static AbstractMethod* FindVirtualMethod(Object* receiver, AbstractMethod* method)
@@ -160,9 +166,16 @@ static JValue InvokeVirtualOrInterfaceWithJValues(const ScopedObjectAccess& soa,
Object* receiver = soa.Decode<Object*>(obj);
AbstractMethod* method = FindVirtualMethod(receiver, soa.DecodeMethod(mid));
MethodHelper mh(method);
+ JValue result;
+ JValue float_result;
ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
- arg_array.BuildArgArray(soa, args);
- return InvokeWithArgArray(soa, receiver, method, arg_array.get());
+ arg_array.BuildArgArray(soa, receiver, args);
+ InvokeWithArgArray(soa, method, &arg_array, &result, &float_result);
+ if (mh.IsReturnFloatOrDouble()) {
+ return float_result;
+ } else {
+ return result;
+ }
}
static JValue InvokeVirtualOrInterfaceWithVarArgs(const ScopedObjectAccess& soa,
@@ -171,9 +184,16 @@ static JValue InvokeVirtualOrInterfaceWithVarArgs(const ScopedObjectAccess& soa,
Object* receiver = soa.Decode<Object*>(obj);
AbstractMethod* method = FindVirtualMethod(receiver, soa.DecodeMethod(mid));
MethodHelper mh(method);
+ JValue result;
+ JValue float_result;
ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
- arg_array.BuildArgArray(soa, args);
- return InvokeWithArgArray(soa, receiver, method, arg_array.get());
+ arg_array.BuildArgArray(soa, receiver, args);
+ InvokeWithArgArray(soa, method, &arg_array, &result, &float_result);
+ if (mh.IsReturnFloatOrDouble()) {
+ return float_result;
+ } else {
+ return result;
+ }
}
// Section 12.3.2 of the JNI spec describes JNI class descriptors. They're
@@ -570,15 +590,16 @@ JValue InvokeWithJValues(const ScopedObjectAccess& soa, jobject obj, jmethodID m
Object* receiver = soa.Decode<Object*>(obj);
AbstractMethod* method = soa.DecodeMethod(mid);
MethodHelper mh(method);
+ JValue result;
+ JValue float_result;
ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
- arg_array.BuildArgArray(soa, args);
- return InvokeWithArgArray(soa, receiver, method, arg_array.get());
-}
-
-JValue InvokeWithJValues(const ScopedObjectAccess& soa, Object* receiver, AbstractMethod* m,
- JValue* args)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- return InvokeWithArgArray(soa, receiver, m, args);
+ arg_array.BuildArgArray(soa, receiver, args);
+ InvokeWithArgArray(soa, method, &arg_array, &result, &float_result);
+ if (mh.IsReturnFloatOrDouble()) {
+ return float_result;
+ } else {
+ return result;
+ }
}
class JNI {
diff --git a/src/jni_internal.h b/src/jni_internal.h
index 9b773f3a6d..d4fc514ed6 100644
--- a/src/jni_internal.h
+++ b/src/jni_internal.h
@@ -42,6 +42,7 @@ class AbstractMethod;
class ClassLoader;
class Field;
}
+class ArgArray;
union JValue;
class Libraries;
class ScopedObjectAccess;
@@ -55,8 +56,8 @@ void RegisterNativeMethods(JNIEnv* env, const char* jni_class_name, const JNINat
JValue InvokeWithJValues(const ScopedObjectAccess&, jobject obj, jmethodID mid, jvalue* args)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-JValue InvokeWithJValues(const ScopedObjectAccess&, mirror::Object* receiver,
- mirror::AbstractMethod* m, JValue* args)
+void InvokeWithArgArray(const ScopedObjectAccess& soa, mirror::AbstractMethod* method,
+ ArgArray *arg_array, JValue* result, JValue* float_result)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
int ThrowNewException(JNIEnv* env, jclass exception_class, const char* msg, jobject cause);
diff --git a/src/jni_internal_test.cc b/src/jni_internal_test.cc
index 4b820f9126..b67b0fdfc0 100644
--- a/src/jni_internal_test.cc
+++ b/src/jni_internal_test.cc
@@ -20,6 +20,7 @@
#include <cmath>
#include "common_test.h"
+#include "invoke_arg_array_builder.h"
#include "mirror/abstract_method-inl.h"
#include "mirror/object_array-inl.h"
#include "ScopedLocalRef.h"
@@ -27,6 +28,9 @@
namespace art {
+extern "C" void art_quick_invoke_stub(const mirror::AbstractMethod*, uint32_t*, uint32_t,
+ Thread*, JValue*, JValue*);
+
class JniInternalTest : public CommonTest {
protected:
virtual void SetUp() {
@@ -72,10 +76,10 @@ class JniInternalTest : public CommonTest {
CommonTest::TearDown();
}
- mirror::AbstractMethod::InvokeStub* DoCompile(mirror::AbstractMethod*& method,
- mirror::Object*& receiver,
- bool is_static, const char* method_name,
- const char* method_signature)
+ void DoCompile(mirror::AbstractMethod*& method,
+ mirror::Object*& receiver,
+ bool is_static, const char* method_name,
+ const char* method_signature)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
const char* class_name = is_static ? "StaticLeafMethods" : "NonStaticLeafMethods";
jobject jclass_loader(LoadDex(class_name));
@@ -99,48 +103,57 @@ class JniInternalTest : public CommonTest {
CHECK(method != NULL);
receiver = (is_static ? NULL : c->AllocObject(self));
-
- mirror::AbstractMethod::InvokeStub* stub = method->GetInvokeStub();
- CHECK(stub != NULL);
-
- return stub;
}
void InvokeNopMethod(bool is_static) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
mirror::AbstractMethod* method;
mirror::Object* receiver;
- mirror::AbstractMethod::InvokeStub* stub = DoCompile(method, receiver, is_static, "nop", "()V");
- (*stub)(method, receiver, Thread::Current(), NULL, NULL);
+ DoCompile(method, receiver, is_static, "nop", "()V");
+
+ ArgArray arg_array(NULL, 0);
+ JValue result;
+ JValue float_result;
+
+ if (!is_static) {
+ arg_array.Append(reinterpret_cast<uint32_t>(receiver));
+ }
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
}
void InvokeIdentityByteMethod(bool is_static)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
mirror::AbstractMethod* method;
mirror::Object* receiver;
- mirror::AbstractMethod::InvokeStub* stub =
- DoCompile(method, receiver, is_static, "identity", "(B)B");
+ DoCompile(method, receiver, is_static, "identity", "(I)I");
- JValue args[1];
+ ArgArray arg_array(NULL, 0);
+ uint32_t* args = arg_array.GetArray();
JValue result;
+ JValue float_result;
+
+ if (!is_static) {
+ arg_array.Append(reinterpret_cast<uint32_t>(receiver));
+ args++;
+ }
- args[0].SetB(0);
+ arg_array.Append(0);
result.SetB(-1);
- (*stub)(method, receiver, Thread::Current(), args, &result);
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
EXPECT_EQ(0, result.GetB());
- args[0].SetB(-1);
+ args[0] = -1;
result.SetB(0);
- (*stub)(method, receiver, Thread::Current(), args, &result);
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
EXPECT_EQ(-1, result.GetB());
- args[0].SetB(SCHAR_MAX);
+ args[0] = SCHAR_MAX;
result.SetB(0);
- (*stub)(method, receiver, Thread::Current(), args, &result);
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
EXPECT_EQ(SCHAR_MAX, result.GetB());
- args[0].SetB(SCHAR_MIN);
+ args[0] = (SCHAR_MIN << 24) >> 24;
result.SetB(0);
- (*stub)(method, receiver, Thread::Current(), args, &result);
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
EXPECT_EQ(SCHAR_MIN, result.GetB());
}
@@ -148,30 +161,36 @@ class JniInternalTest : public CommonTest {
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
mirror::AbstractMethod* method;
mirror::Object* receiver;
- mirror::AbstractMethod::InvokeStub* stub =
- DoCompile(method, receiver, is_static, "identity", "(I)I");
+ DoCompile(method, receiver, is_static, "identity", "(I)I");
- JValue args[1];
+ ArgArray arg_array(NULL, 0);
+ uint32_t* args = arg_array.GetArray();
JValue result;
+ JValue float_result;
+
+ if (!is_static) {
+ arg_array.Append(reinterpret_cast<uint32_t>(receiver));
+ args++;
+ }
- args[0].SetI(0);
+ arg_array.Append(0);
result.SetI(-1);
- (*stub)(method, receiver, Thread::Current(), args, &result);
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
EXPECT_EQ(0, result.GetI());
- args[0].SetI(-1);
+ args[0] = -1;
result.SetI(0);
- (*stub)(method, receiver, Thread::Current(), args, &result);
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
EXPECT_EQ(-1, result.GetI());
- args[0].SetI(INT_MAX);
+ args[0] = INT_MAX;
result.SetI(0);
- (*stub)(method, receiver, Thread::Current(), args, &result);
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
EXPECT_EQ(INT_MAX, result.GetI());
- args[0].SetI(INT_MIN);
+ args[0] = INT_MIN;
result.SetI(0);
- (*stub)(method, receiver, Thread::Current(), args, &result);
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
EXPECT_EQ(INT_MIN, result.GetI());
}
@@ -179,70 +198,91 @@ class JniInternalTest : public CommonTest {
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
mirror::AbstractMethod* method;
mirror::Object* receiver;
- mirror::AbstractMethod::InvokeStub* stub =
- DoCompile(method, receiver, is_static, "identity", "(D)D");
+ DoCompile(method, receiver, is_static, "identity", "(D)D");
- JValue args[1];
+ ArgArray arg_array(NULL, 0);
+ uint32_t* args = arg_array.GetArray();
+ JValue value;
JValue result;
+ JValue float_result;
- args[0].SetD(0.0);
+ if (!is_static) {
+ arg_array.Append(reinterpret_cast<uint32_t>(receiver));
+ args++;
+ }
+
+ value.SetD(0.0);
+ arg_array.AppendWide(value.GetJ());
result.SetD(-1.0);
- (*stub)(method, receiver, Thread::Current(), args, &result);
- EXPECT_EQ(0.0, result.GetD());
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
+ EXPECT_EQ(0.0, float_result.GetD());
- args[0].SetD(-1.0);
+ value.SetD(-1.0);
+ args[0] = value.GetJ();
+ args[1] = value.GetJ() >> 32;
result.SetD(0.0);
- (*stub)(method, receiver, Thread::Current(), args, &result);
- EXPECT_EQ(-1.0, result.GetD());
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
+ EXPECT_EQ(-1.0, float_result.GetD());
- args[0].SetD(DBL_MAX);
+ value.SetD(DBL_MAX);
+ args[0] = value.GetJ();
+ args[1] = value.GetJ() >> 32;
result.SetD(0.0);
- (*stub)(method, receiver, Thread::Current(), args, &result);
- EXPECT_EQ(DBL_MAX, result.GetD());
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
+ EXPECT_EQ(DBL_MAX, float_result.GetD());
- args[0].SetD(DBL_MIN);
+ value.SetD(DBL_MIN);
+ args[0] = value.GetJ();
+ args[1] = value.GetJ() >> 32;
result.SetD(0.0);
- (*stub)(method, receiver, Thread::Current(), args, &result);
- EXPECT_EQ(DBL_MIN, result.GetD());
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
+ EXPECT_EQ(DBL_MIN, float_result.GetD());
}
void InvokeSumIntIntMethod(bool is_static)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
mirror::AbstractMethod* method;
mirror::Object* receiver;
- mirror::AbstractMethod::InvokeStub* stub =
- DoCompile(method, receiver, is_static, "sum", "(II)I");
+ DoCompile(method, receiver, is_static, "sum", "(II)I");
+ ArgArray arg_array(NULL, 0);
+ uint32_t* args = arg_array.GetArray();
JValue result;
+ JValue float_result;
+
+ if (!is_static) {
+ arg_array.Append(reinterpret_cast<uint32_t>(receiver));
+ args++;
+ }
+
+ arg_array.Append(0);
+ arg_array.Append(0);
result.SetI(-1);
- JValue args[2];
- args[0].SetI(0);
- args[1].SetI(0);
- (*stub)(method, NULL, Thread::Current(), args, &result);
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
EXPECT_EQ(0, result.GetI());
+ args[0] = 1;
+ args[1] = 2;
result.SetI(0);
- args[0].SetI(1);
- args[1].SetI(2);
- (*stub)(method, NULL, Thread::Current(), args, &result);
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
EXPECT_EQ(3, result.GetI());
+ args[0] = -2;
+ args[1] = 5;
result.SetI(0);
- args[0].SetI(-2);
- args[1].SetI(5);
- (*stub)(method, NULL, Thread::Current(), args, &result);
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
EXPECT_EQ(3, result.GetI());
+ args[0] = INT_MAX;
+ args[1] = INT_MIN;
result.SetI(1234);
- args[0].SetI(INT_MAX);
- args[1].SetI(INT_MIN);
- (*stub)(method, NULL, Thread::Current(), args, &result);
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
EXPECT_EQ(-1, result.GetI());
+ args[0] = INT_MAX;
+ args[1] = INT_MAX;
result.SetI(INT_MIN);
- args[0].SetI(INT_MAX);
- args[1].SetI(INT_MAX);
- (*stub)(method, NULL, Thread::Current(), args, &result);
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
EXPECT_EQ(-2, result.GetI());
}
@@ -250,44 +290,51 @@ class JniInternalTest : public CommonTest {
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
mirror::AbstractMethod* method;
mirror::Object* receiver;
- mirror::AbstractMethod::InvokeStub* stub =
- DoCompile(method, receiver, is_static, "sum", "(III)I");
+ DoCompile(method, receiver, is_static, "sum", "(III)I");
+ ArgArray arg_array(NULL, 0);
+ uint32_t* args = arg_array.GetArray();
JValue result;
+ JValue float_result;
+
+ if (!is_static) {
+ arg_array.Append(reinterpret_cast<uint32_t>(receiver));
+ args++;
+ }
+
+ arg_array.Append(0);
+ arg_array.Append(0);
+ arg_array.Append(0);
result.SetI(-1);
- JValue args[3];
- args[0].SetI(0);
- args[1].SetI(0);
- args[2].SetI(0);
- (*stub)(method, NULL, Thread::Current(), args, &result);
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
EXPECT_EQ(0, result.GetI());
+ args[0] = 1;
+ args[1] = 2;
+ args[2] = 3;
result.SetI(0);
- args[0].SetI(1);
- args[1].SetI(2);
- args[2].SetI(3);
- (*stub)(method, NULL, Thread::Current(), args, &result);
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
EXPECT_EQ(6, result.GetI());
+ args[0] = -1;
+ args[1] = 2;
+ args[2] = -3;
result.SetI(0);
- args[0].SetI(-1);
- args[1].SetI(2);
- args[2].SetI(-3);
- (*stub)(method, NULL, Thread::Current(), args, &result);
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
EXPECT_EQ(-2, result.GetI());
+ args[0] = INT_MAX;
+ args[1] = INT_MIN;
+ args[2] = INT_MAX;
result.SetI(1234);
- args[0].SetI(INT_MAX);
- args[1].SetI(INT_MIN);
- args[2].SetI(INT_MAX);
- (*stub)(method, NULL, Thread::Current(), args, &result);
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
EXPECT_EQ(2147483646, result.GetI());
+ args[0] = INT_MAX;
+ args[1] = INT_MAX;
+ args[2] = INT_MAX;
result.SetI(INT_MIN);
- args[0].SetI(INT_MAX);
- args[1].SetI(INT_MAX);
- args[2].SetI(INT_MAX);
- (*stub)(method, NULL, Thread::Current(), args, &result);
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
EXPECT_EQ(2147483645, result.GetI());
}
@@ -295,49 +342,56 @@ class JniInternalTest : public CommonTest {
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
mirror::AbstractMethod* method;
mirror::Object* receiver;
- mirror::AbstractMethod::InvokeStub* stub =
- DoCompile(method, receiver, is_static, "sum", "(IIII)I");
+ DoCompile(method, receiver, is_static, "sum", "(IIII)I");
+ ArgArray arg_array(NULL, 0);
+ uint32_t* args = arg_array.GetArray();
JValue result;
+ JValue float_result;
+
+ if (!is_static) {
+ arg_array.Append(reinterpret_cast<uint32_t>(receiver));
+ args++;
+ }
+
+ arg_array.Append(0);
+ arg_array.Append(0);
+ arg_array.Append(0);
+ arg_array.Append(0);
result.SetI(-1);
- JValue args[4];
- args[0].SetI(0);
- args[1].SetI(0);
- args[2].SetI(0);
- args[3].SetI(0);
- (*stub)(method, NULL, Thread::Current(), args, &result);
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
EXPECT_EQ(0, result.GetI());
+ args[0] = 1;
+ args[1] = 2;
+ args[2] = 3;
+ args[3] = 4;
result.SetI(0);
- args[0].SetI(1);
- args[1].SetI(2);
- args[2].SetI(3);
- args[3].SetI(4);
- (*stub)(method, NULL, Thread::Current(), args, &result);
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
EXPECT_EQ(10, result.GetI());
+ args[0] = -1;
+ args[1] = 2;
+ args[2] = -3;
+ args[3] = 4;
result.SetI(0);
- args[0].SetI(-1);
- args[1].SetI(2);
- args[2].SetI(-3);
- args[3].SetI(4);
- (*stub)(method, NULL, Thread::Current(), args, &result);
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
EXPECT_EQ(2, result.GetI());
+ args[0] = INT_MAX;
+ args[1] = INT_MIN;
+ args[2] = INT_MAX;
+ args[3] = INT_MIN;
result.SetI(1234);
- args[0].SetI(INT_MAX);
- args[1].SetI(INT_MIN);
- args[2].SetI(INT_MAX);
- args[3].SetI(INT_MIN);
- (*stub)(method, NULL, Thread::Current(), args, &result);
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
EXPECT_EQ(-2, result.GetI());
+ args[0] = INT_MAX;
+ args[1] = INT_MAX;
+ args[2] = INT_MAX;
+ args[3] = INT_MAX;
result.SetI(INT_MIN);
- args[0].SetI(INT_MAX);
- args[1].SetI(INT_MAX);
- args[2].SetI(INT_MAX);
- args[3].SetI(INT_MAX);
- (*stub)(method, NULL, Thread::Current(), args, &result);
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
EXPECT_EQ(-4, result.GetI());
}
@@ -345,54 +399,61 @@ class JniInternalTest : public CommonTest {
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
mirror::AbstractMethod* method;
mirror::Object* receiver;
- mirror::AbstractMethod::InvokeStub* stub =
- DoCompile(method, receiver, is_static, "sum", "(IIIII)I");
+ DoCompile(method, receiver, is_static, "sum", "(IIIII)I");
+ ArgArray arg_array(NULL, 0);
+ uint32_t* args = arg_array.GetArray();
JValue result;
+ JValue float_result;
+
+ if (!is_static) {
+ arg_array.Append(reinterpret_cast<uint32_t>(receiver));
+ args++;
+ }
+
+ arg_array.Append(0);
+ arg_array.Append(0);
+ arg_array.Append(0);
+ arg_array.Append(0);
+ arg_array.Append(0);
result.SetI(-1.0);
- JValue args[5];
- args[0].SetI(0);
- args[1].SetI(0);
- args[2].SetI(0);
- args[3].SetI(0);
- args[4].SetI(0);
- (*stub)(method, NULL, Thread::Current(), args, &result);
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
EXPECT_EQ(0, result.GetI());
+ args[0] = 1;
+ args[1] = 2;
+ args[2] = 3;
+ args[3] = 4;
+ args[4] = 5;
result.SetI(0);
- args[0].SetI(1);
- args[1].SetI(2);
- args[2].SetI(3);
- args[3].SetI(4);
- args[4].SetI(5);
- (*stub)(method, NULL, Thread::Current(), args, &result);
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
EXPECT_EQ(15, result.GetI());
+ args[0] = -1;
+ args[1] = 2;
+ args[2] = -3;
+ args[3] = 4;
+ args[4] = -5;
result.SetI(0);
- args[0].SetI(-1);
- args[1].SetI(2);
- args[2].SetI(-3);
- args[3].SetI(4);
- args[4].SetI(-5);
- (*stub)(method, NULL, Thread::Current(), args, &result);
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
EXPECT_EQ(-3, result.GetI());
+ args[0] = INT_MAX;
+ args[1] = INT_MIN;
+ args[2] = INT_MAX;
+ args[3] = INT_MIN;
+ args[4] = INT_MAX;
result.SetI(1234);
- args[0].SetI(INT_MAX);
- args[1].SetI(INT_MIN);
- args[2].SetI(INT_MAX);
- args[3].SetI(INT_MIN);
- args[4].SetI(INT_MAX);
- (*stub)(method, NULL, Thread::Current(), args, &result);
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
EXPECT_EQ(2147483645, result.GetI());
+ args[0] = INT_MAX;
+ args[1] = INT_MAX;
+ args[2] = INT_MAX;
+ args[3] = INT_MAX;
+ args[4] = INT_MAX;
result.SetI(INT_MIN);
- args[0].SetI(INT_MAX);
- args[1].SetI(INT_MAX);
- args[2].SetI(INT_MAX);
- args[3].SetI(INT_MAX);
- args[4].SetI(INT_MAX);
- (*stub)(method, NULL, Thread::Current(), args, &result);
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
EXPECT_EQ(2147483643, result.GetI());
}
@@ -400,146 +461,262 @@ class JniInternalTest : public CommonTest {
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
mirror::AbstractMethod* method;
mirror::Object* receiver;
- mirror::AbstractMethod::InvokeStub* stub =
- DoCompile(method, receiver, is_static, "sum", "(DD)D");
+ DoCompile(method, receiver, is_static, "sum", "(DD)D");
- JValue args[2];
+ ArgArray arg_array(NULL, 0);
+ uint32_t* args = arg_array.GetArray();
+ JValue value;
+ JValue value2;
JValue result;
+ JValue float_result;
- args[0].SetD(0.0);
- args[1].SetD(0.0);
- result.SetD(-1.0);
- (*stub)(method, NULL, Thread::Current(), args, &result);
- EXPECT_EQ(0.0, result.GetD());
+ if (!is_static) {
+ arg_array.Append(reinterpret_cast<uint32_t>(receiver));
+ args++;
+ }
- args[0].SetD(1.0);
- args[1].SetD(2.0);
+ value.SetD(0.0);
+ value2.SetD(0.0);
+ arg_array.AppendWide(value.GetJ());
+ arg_array.AppendWide(value2.GetJ());
+ result.SetD(-1.0);
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
+ EXPECT_EQ(0.0, float_result.GetD());
+
+ value.SetD(1.0);
+ value2.SetD(2.0);
+ args[0] = value.GetJ();
+ args[1] = value.GetJ() >> 32;
+ args[2] = value2.GetJ();
+ args[3] = value2.GetJ() >> 32;
result.SetD(0.0);
- (*stub)(method, NULL, Thread::Current(), args, &result);
- EXPECT_EQ(3.0, result.GetD());
-
- args[0].SetD(1.0);
- args[1].SetD(-2.0);
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
+ EXPECT_EQ(3.0, float_result.GetD());
+
+ value.SetD(1.0);
+ value2.SetD(-2.0);
+ args[0] = value.GetJ();
+ args[1] = value.GetJ() >> 32;
+ args[2] = value2.GetJ();
+ args[3] = value2.GetJ() >> 32;
result.SetD(0.0);
- (*stub)(method, NULL, Thread::Current(), args, &result);
- EXPECT_EQ(-1.0, result.GetD());
-
- args[0].SetD(DBL_MAX);
- args[1].SetD(DBL_MIN);
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
+ EXPECT_EQ(-1.0, float_result.GetD());
+
+ value.SetD(DBL_MAX);
+ value2.SetD(DBL_MIN);
+ args[0] = value.GetJ();
+ args[1] = value.GetJ() >> 32;
+ args[2] = value2.GetJ();
+ args[3] = value2.GetJ() >> 32;
result.SetD(0.0);
- (*stub)(method, NULL, Thread::Current(), args, &result);
- EXPECT_EQ(1.7976931348623157e308, result.GetD());
-
- args[0].SetD(DBL_MAX);
- args[1].SetD(DBL_MAX);
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
+ EXPECT_EQ(1.7976931348623157e308, float_result.GetD());
+
+ value.SetD(DBL_MAX);
+ value2.SetD(DBL_MAX);
+ args[0] = value.GetJ();
+ args[1] = value.GetJ() >> 32;
+ args[2] = value2.GetJ();
+ args[3] = value2.GetJ() >> 32;
result.SetD(0.0);
- (*stub)(method, NULL, Thread::Current(), args, &result);
- EXPECT_EQ(INFINITY, result.GetD());
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
+ EXPECT_EQ(INFINITY, float_result.GetD());
}
void InvokeSumDoubleDoubleDoubleMethod(bool is_static)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
mirror::AbstractMethod* method;
mirror::Object* receiver;
- mirror::AbstractMethod::InvokeStub* stub =
- DoCompile(method, receiver, is_static, "sum", "(DDD)D");
+ DoCompile(method, receiver, is_static, "sum", "(DDD)D");
- JValue args[3];
+ ArgArray arg_array(NULL, 0);
+ uint32_t* args = arg_array.GetArray();
+ JValue value;
+ JValue value2;
+ JValue value3;
JValue result;
+ JValue float_result;
- args[0].SetD(0.0);
- args[1].SetD(0.0);
- args[2].SetD(0.0);
- result.SetD(-1.0);
- (*stub)(method, NULL, Thread::Current(), args, &result);
- EXPECT_EQ(0.0, result.GetD());
+ if (!is_static) {
+ arg_array.Append(reinterpret_cast<uint32_t>(receiver));
+ args++;
+ }
- args[0].SetD(1.0);
- args[1].SetD(2.0);
- args[2].SetD(3.0);
+ value.SetD(0.0);
+ value2.SetD(0.0);
+ value3.SetD(0.0);
+ arg_array.AppendWide(value.GetJ());
+ arg_array.AppendWide(value2.GetJ());
+ arg_array.AppendWide(value3.GetJ());
+ result.SetD(-1.0);
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
+ EXPECT_EQ(0.0, float_result.GetD());
+
+ value.SetD(1.0);
+ value2.SetD(2.0);
+ value3.SetD(3.0);
+ args[0] = value.GetJ();
+ args[1] = value.GetJ() >> 32;
+ args[2] = value2.GetJ();
+ args[3] = value2.GetJ() >> 32;
+ args[4] = value3.GetJ();
+ args[5] = value3.GetJ() >> 32;
result.SetD(0.0);
- (*stub)(method, NULL, Thread::Current(), args, &result);
- EXPECT_EQ(6.0, result.GetD());
-
- args[0].SetD(1.0);
- args[1].SetD(-2.0);
- args[2].SetD(3.0);
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
+ EXPECT_EQ(6.0, float_result.GetD());
+
+ value.SetD(1.0);
+ value2.SetD(-2.0);
+ value3.SetD(3.0);
+ args[0] = value.GetJ();
+ args[1] = value.GetJ() >> 32;
+ args[2] = value2.GetJ();
+ args[3] = value2.GetJ() >> 32;
+ args[4] = value3.GetJ();
+ args[5] = value3.GetJ() >> 32;
result.SetD(0.0);
- (*stub)(method, NULL, Thread::Current(), args, &result);
- EXPECT_EQ(2.0, result.GetD());
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
+ EXPECT_EQ(2.0, float_result.GetD());
}
void InvokeSumDoubleDoubleDoubleDoubleMethod(bool is_static)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
mirror::AbstractMethod* method;
mirror::Object* receiver;
- mirror::AbstractMethod::InvokeStub* stub =
- DoCompile(method, receiver, is_static, "sum", "(DDDD)D");
-
- JValue args[4];
+ DoCompile(method, receiver, is_static, "sum", "(DDDD)D");
+
+ ArgArray arg_array(NULL, 0);
+ uint32_t* args = arg_array.GetArray();
+ JValue value;
+ JValue value2;
+ JValue value3;
+ JValue value4;
JValue result;
+ JValue float_result;
- args[0].SetD(0.0);
- args[1].SetD(0.0);
- args[2].SetD(0.0);
- args[3].SetD(0.0);
- result.SetD(-1.0);
- (*stub)(method, NULL, Thread::Current(), args, &result);
- EXPECT_EQ(0.0, result.GetD());
+ if (!is_static) {
+ arg_array.Append(reinterpret_cast<uint32_t>(receiver));
+ args++;
+ }
- args[0].SetD(1.0);
- args[1].SetD(2.0);
- args[2].SetD(3.0);
- args[3].SetD(4.0);
+ value.SetD(0.0);
+ value2.SetD(0.0);
+ value3.SetD(0.0);
+ value4.SetD(0.0);
+ arg_array.AppendWide(value.GetJ());
+ arg_array.AppendWide(value2.GetJ());
+ arg_array.AppendWide(value3.GetJ());
+ arg_array.AppendWide(value4.GetJ());
+ result.SetD(-1.0);
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
+ EXPECT_EQ(0.0, float_result.GetD());
+
+ value.SetD(1.0);
+ value2.SetD(2.0);
+ value3.SetD(3.0);
+ value4.SetD(4.0);
+ args[0] = value.GetJ();
+ args[1] = value.GetJ() >> 32;
+ args[2] = value2.GetJ();
+ args[3] = value2.GetJ() >> 32;
+ args[4] = value3.GetJ();
+ args[5] = value3.GetJ() >> 32;
+ args[6] = value4.GetJ();
+ args[7] = value4.GetJ() >> 32;
result.SetD(0.0);
- (*stub)(method, NULL, Thread::Current(), args, &result);
- EXPECT_EQ(10.0, result.GetD());
-
- args[0].SetD(1.0);
- args[1].SetD(-2.0);
- args[2].SetD(3.0);
- args[3].SetD(-4.0);
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
+ EXPECT_EQ(10.0, float_result.GetD());
+
+ value.SetD(1.0);
+ value2.SetD(-2.0);
+ value3.SetD(3.0);
+ value4.SetD(-4.0);
+ args[0] = value.GetJ();
+ args[1] = value.GetJ() >> 32;
+ args[2] = value2.GetJ();
+ args[3] = value2.GetJ() >> 32;
+ args[4] = value3.GetJ();
+ args[5] = value3.GetJ() >> 32;
+ args[6] = value4.GetJ();
+ args[7] = value4.GetJ() >> 32;
result.SetD(0.0);
- (*stub)(method, NULL, Thread::Current(), args, &result);
- EXPECT_EQ(-2.0, result.GetD());
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
+ EXPECT_EQ(-2.0, float_result.GetD());
}
void InvokeSumDoubleDoubleDoubleDoubleDoubleMethod(bool is_static)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
mirror::AbstractMethod* method;
mirror::Object* receiver;
- mirror::AbstractMethod::InvokeStub* stub =
- DoCompile(method, receiver, is_static, "sum", "(DDDDD)D");
-
- JValue args[5];
+ DoCompile(method, receiver, is_static, "sum", "(DDDDD)D");
+
+ ArgArray arg_array(NULL, 0);
+ uint32_t* args = arg_array.GetArray();
+ JValue value;
+ JValue value2;
+ JValue value3;
+ JValue value4;
+ JValue value5;
JValue result;
+ JValue float_result;
- args[0].SetD(0.0);
- args[1].SetD(0.0);
- args[2].SetD(0.0);
- args[3].SetD(0.0);
- args[4].SetD(0.0);
+ if (!is_static) {
+ arg_array.Append(reinterpret_cast<uint32_t>(receiver));
+ args++;
+ }
+
+ value.SetD(0.0);
+ value2.SetD(0.0);
+ value3.SetD(0.0);
+ value4.SetD(0.0);
+ value5.SetD(0.0);
+ arg_array.AppendWide(value.GetJ());
+ arg_array.AppendWide(value2.GetJ());
+ arg_array.AppendWide(value3.GetJ());
+ arg_array.AppendWide(value4.GetJ());
+ arg_array.AppendWide(value5.GetJ());
result.SetD(-1.0);
- (*stub)(method, NULL, Thread::Current(), args, &result);
- EXPECT_EQ(0.0, result.GetD());
-
- args[0].SetD(1.0);
- args[1].SetD(2.0);
- args[2].SetD(3.0);
- args[3].SetD(4.0);
- args[4].SetD(5.0);
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
+ EXPECT_EQ(0.0, float_result.GetD());
+
+ value.SetD(1.0);
+ value2.SetD(2.0);
+ value3.SetD(3.0);
+ value4.SetD(4.0);
+ value5.SetD(5.0);
+ args[0] = value.GetJ();
+ args[1] = value.GetJ() >> 32;
+ args[2] = value2.GetJ();
+ args[3] = value2.GetJ() >> 32;
+ args[4] = value3.GetJ();
+ args[5] = value3.GetJ() >> 32;
+ args[6] = value4.GetJ();
+ args[7] = value4.GetJ() >> 32;
+ args[8] = value5.GetJ();
+ args[9] = value5.GetJ() >> 32;
result.SetD(0.0);
- (*stub)(method, NULL, Thread::Current(), args, &result);
- EXPECT_EQ(15.0, result.GetD());
-
- args[0].SetD(1.0);
- args[1].SetD(-2.0);
- args[2].SetD(3.0);
- args[3].SetD(-4.0);
- args[4].SetD(5.0);
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
+ EXPECT_EQ(15.0, float_result.GetD());
+
+ value.SetD(1.0);
+ value2.SetD(-2.0);
+ value3.SetD(3.0);
+ value4.SetD(-4.0);
+ value5.SetD(5.0);
+ args[0] = value.GetJ();
+ args[1] = value.GetJ() >> 32;
+ args[2] = value2.GetJ();
+ args[3] = value2.GetJ() >> 32;
+ args[4] = value3.GetJ();
+ args[5] = value3.GetJ() >> 32;
+ args[6] = value4.GetJ();
+ args[7] = value4.GetJ() >> 32;
+ args[8] = value5.GetJ();
+ args[9] = value5.GetJ() >> 32;
result.SetD(0.0);
- (*stub)(method, NULL, Thread::Current(), args, &result);
- EXPECT_EQ(3.0, result.GetD());
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
+ EXPECT_EQ(3.0, float_result.GetD());
}
JavaVMExt* vm_;
@@ -1420,12 +1597,12 @@ TEST_F(JniInternalTest, StaticMainMethod) {
mirror::AbstractMethod* method = klass->FindDirectMethod("main", "([Ljava/lang/String;)V");
ASSERT_TRUE(method != NULL);
- mirror::AbstractMethod::InvokeStub* stub = method->GetInvokeStub();
-
- JValue args[1];
- args[0].SetL(NULL);
+ ArgArray arg_array(NULL, 0);
+ arg_array.Append(0);
+ JValue result;
+ JValue float_result;
- (*stub)(method, NULL, Thread::Current(), args, NULL);
+ (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
}
TEST_F(JniInternalTest, StaticNopMethod) {
diff --git a/src/mirror/abstract_method.cc b/src/mirror/abstract_method.cc
index 202fa2f07c..e185c9cb0a 100644
--- a/src/mirror/abstract_method.cc
+++ b/src/mirror/abstract_method.cc
@@ -31,6 +31,9 @@
namespace art {
namespace mirror {
+extern "C" void art_quick_invoke_stub(AbstractMethod*, uint32_t*, uint32_t,
+ Thread*, JValue*, JValue*);
+
// TODO: get global references for these
Class* AbstractMethod::java_lang_reflect_Constructor_ = NULL;
Class* AbstractMethod::java_lang_reflect_Method_ = NULL;
@@ -276,7 +279,8 @@ uint32_t AbstractMethod::FindCatchBlock(Class* exception_type, uint32_t dex_pc)
return DexFile::kDexNoIndex;
}
-void AbstractMethod::Invoke(Thread* self, Object* receiver, JValue* args, JValue* result) {
+void AbstractMethod::Invoke(Thread* self, uint32_t* args, uint32_t args_size, JValue* result,
+ JValue* float_result) {
if (kIsDebugBuild) {
self->AssertThreadSuspensionIsAllowable();
CHECK_EQ(kRunnable, self->GetState());
@@ -294,47 +298,83 @@ void AbstractMethod::Invoke(Thread* self, Object* receiver, JValue* args, JValue
LOG(INFO) << "Not invoking " << PrettyMethod(this) << " for a runtime that isn't started";
if (result != NULL) {
result->SetJ(0);
+ float_result->SetJ(0);
}
} else {
bool interpret = self->ReadFlag(kEnterInterpreter) && !IsNative() && !IsProxyMethod();
const bool kLogInvocationStartAndReturn = false;
- if (!interpret && GetCode() != NULL && stub != NULL) {
- if (kLogInvocationStartAndReturn) {
- LOG(INFO) << StringPrintf("Invoking '%s' code=%p stub=%p",
- PrettyMethod(this).c_str(), GetCode(), stub);
- }
- (*stub)(this, receiver, self, args, result);
- if (UNLIKELY(reinterpret_cast<int32_t>(self->GetException()) == -1)) {
- // Unusual case where we were running LLVM generated code and an
- // exception was thrown to force the activations to be removed from the
- // stack. Continue execution in the interpreter.
- JValue value;
- self->ClearException();
- ShadowFrame* shadow_frame = self->GetAndClearDeoptimizationShadowFrame(&value);
- self->SetTopOfShadowStack(shadow_frame);
- interpreter::EnterInterpreterFromLLVM(self, shadow_frame, result);
- }
- if (kLogInvocationStartAndReturn) {
- LOG(INFO) << StringPrintf("Returned '%s' code=%p stub=%p",
- PrettyMethod(this).c_str(), GetCode(), stub);
- }
- } else {
- const bool kInterpretMethodsWithNoCode = false;
- if (interpret || kInterpretMethodsWithNoCode) {
+ if (GetCode() != NULL) {
+ if (!interpret) {
if (kLogInvocationStartAndReturn) {
- LOG(INFO) << "Interpreting " << PrettyMethod(this) << "'";
+ LOG(INFO) << StringPrintf("Invoking '%s' code=%p stub=%p",
+ PrettyMethod(this).c_str(), GetCode(), stub);
+ }
+ // TODO: Temporary to keep portable working while stubs are removed from quick.
+#ifdef ART_USE_PORTABLE_COMPILER
+ MethodHelper mh(this);
+ const char* shorty = mh.GetShorty();
+ uint32_t shorty_len = mh.GetShortyLength();
+ UniquePtr<JValue[]> jvalue_args(new JValue[shorty_len - 1]);
+ Object* receiver = NULL;
+ uint32_t* ptr = args;
+ if (!this->IsStatic()) {
+ receiver = reinterpret_cast<Object*>(*ptr);
+ ptr++;
+ }
+ for (uint32_t i = 1; i < shorty_len; i++) {
+ if ((shorty[i] == 'J') || (shorty[i] == 'D')) {
+ jvalue_args[i - 1].SetJ(*((uint64_t*)ptr));
+ ptr++;
+ } else {
+ jvalue_args[i - 1].SetI(*ptr);
+ }
+ ptr++;
+ }
+ if (mh.IsReturnFloatOrDouble()) {
+ (*stub)(this, receiver, self, jvalue_args.get(), float_result);
+ } else {
+ (*stub)(this, receiver, self, jvalue_args.get(), result);
+ }
+#else
+ (*art_quick_invoke_stub)(this, args, args_size, self, result, float_result);
+#endif
+ if (UNLIKELY(reinterpret_cast<int32_t>(self->GetException()) == -1)) {
+ // Unusual case where we were running LLVM generated code and an
+ // exception was thrown to force the activations to be removed from the
+ // stack. Continue execution in the interpreter.
+ JValue value;
+ self->ClearException();
+ ShadowFrame* shadow_frame = self->GetAndClearDeoptimizationShadowFrame(&value);
+ self->SetTopOfShadowStack(shadow_frame);
+ interpreter::EnterInterpreterFromLLVM(self, shadow_frame, result);
}
- art::interpreter::EnterInterpreterFromInvoke(self, this, receiver, args, result);
if (kLogInvocationStartAndReturn) {
- LOG(INFO) << "Returned '" << PrettyMethod(this) << "'";
+ LOG(INFO) << StringPrintf("Returned '%s' code=%p stub=%p",
+ PrettyMethod(this).c_str(), GetCode(), stub);
}
} else {
- LOG(INFO) << "Not invoking '" << PrettyMethod(this)
- << "' code=" << reinterpret_cast<const void*>(GetCode())
- << " stub=" << reinterpret_cast<void*>(stub);
- if (result != NULL) {
- result->SetJ(0);
+ if (kLogInvocationStartAndReturn) {
+ LOG(INFO) << "Interpreting " << PrettyMethod(this) << "'";
+ }
+ if (this->IsStatic()) {
+ art::interpreter::EnterInterpreterFromInvoke(self, this, NULL, args,
+ result, float_result);
+ } else {
+ Object* receiver = reinterpret_cast<Object*>(args[0]);
+ art::interpreter::EnterInterpreterFromInvoke(self, this, receiver, args + 1,
+ result, float_result);
}
+ if (kLogInvocationStartAndReturn) {
+ LOG(INFO) << "Returned '" << PrettyMethod(this) << "'";
+ }
+ }
+ } else {
+ LOG(INFO) << "Not invoking '" << PrettyMethod(this)
+ << "' code=" << reinterpret_cast<const void*>(GetCode())
+ << " stub=" << reinterpret_cast<void*>(stub);
+ if (result != NULL) {
+ result->SetJ(0);
+ float_result->SetJ(0);
}
}
}
diff --git a/src/mirror/abstract_method.h b/src/mirror/abstract_method.h
index 1d57abb1d2..a489b1d06f 100644
--- a/src/mirror/abstract_method.h
+++ b/src/mirror/abstract_method.h
@@ -54,6 +54,10 @@ class MANAGED AbstractMethod : public Object {
return MemberOffset(OFFSETOF_MEMBER(AbstractMethod, declaring_class_));
}
+ static MemberOffset CodeOffset() {
+ return MemberOffset(OFFSETOF_MEMBER(AbstractMethod, code_));
+ }
+
uint32_t GetAccessFlags() const;
void SetAccessFlags(uint32_t new_access_flags) {
@@ -189,7 +193,8 @@ class MANAGED AbstractMethod : public Object {
// Find the method that this method overrides
AbstractMethod* FindOverriddenMethod() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void Invoke(Thread* self, Object* receiver, JValue* args, JValue* result)
+ void Invoke(Thread* self, uint32_t* args, uint32_t args_size, JValue* result,
+ JValue* float_result)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
const void* GetCode() const {
diff --git a/src/mirror/object_test.cc b/src/mirror/object_test.cc
index 29cf2f10a1..eed96bd9b7 100644
--- a/src/mirror/object_test.cc
+++ b/src/mirror/object_test.cc
@@ -74,6 +74,8 @@ TEST_F(ObjectTest, AsmConstants) {
ASSERT_EQ(STRING_COUNT_OFFSET, String::CountOffset().Int32Value());
ASSERT_EQ(STRING_OFFSET_OFFSET, String::OffsetOffset().Int32Value());
ASSERT_EQ(STRING_DATA_OFFSET, Array::DataOffset(sizeof(uint16_t)).Int32Value());
+
+ ASSERT_EQ(METHOD_CODE_OFFSET, AbstractMethod::CodeOffset().Int32Value());
}
TEST_F(ObjectTest, IsInSamePackage) {
diff --git a/src/oat/runtime/arm/runtime_support_arm.S b/src/oat/runtime/arm/runtime_support_arm.S
index 6067dd5406..bd3f45dd10 100644
--- a/src/oat/runtime/arm/runtime_support_arm.S
+++ b/src/oat/runtime/arm/runtime_support_arm.S
@@ -103,13 +103,16 @@
push {r1-r3, r5-r8, r10-r11, lr} @ 10 words of callee saves
.save {r1-r3, r5-r8, r10-r11, lr}
.cfi_adjust_cfa_offset 40
- .cfi_rel_offset r5, 0
- .cfi_rel_offset r6, 4
- .cfi_rel_offset r7, 8
- .cfi_rel_offset r8, 12
- .cfi_rel_offset r10, 16
- .cfi_rel_offset r11, 20
- .cfi_rel_offset lr, 24
+ .cfi_rel_offset r1, 0
+ .cfi_rel_offset r2, 4
+ .cfi_rel_offset r3, 8
+ .cfi_rel_offset r5, 12
+ .cfi_rel_offset r6, 16
+ .cfi_rel_offset r7, 20
+ .cfi_rel_offset r8, 24
+ .cfi_rel_offset r10, 28
+ .cfi_rel_offset r11, 32
+ .cfi_rel_offset lr, 36
sub sp, #8 @ 2 words of space, bottom word will hold Method*
.pad #8
.cfi_adjust_cfa_offset 8
@@ -244,6 +247,53 @@ INVOKE_TRAMPOLINE art_quick_invoke_super_trampoline_with_access_check, artInvoke
INVOKE_TRAMPOLINE art_quick_invoke_virtual_trampoline_with_access_check, artInvokeVirtualTrampolineWithAccessCheck
/*
+ * Invocation stub.
+ * On entry:
+ * r0 = method pointer
+ * r1 = argument array or NULL for no argument methods
+ * r2 = size of argument array in bytes
+ * r3 = (managed) thread pointer
+ * [sp] = JValue* result for non-floating point returns
+ * [sp + 4] = JValue* result for floating point returns
+ */
+ENTRY art_quick_invoke_stub
+ push {r0, r4, r5, r9, r11, lr} @ spill regs
+ .save {r0, r4, r5, r9, r11, lr}
+ .pad #24
+ .cfi_adjust_cfa_offset 24
+ .cfi_rel_offset r0, 0
+ .cfi_rel_offset r4, 4
+ .cfi_rel_offset r5, 8
+ .cfi_rel_offset r9, 12
+ .cfi_rel_offset r11, 16
+ .cfi_rel_offset lr, 20
+ mov r11, sp @ save the stack pointer
+ .cfi_def_cfa_register r11
+ mov r9, r3 @ move managed thread pointer into r9
+ mov r4, #SUSPEND_CHECK_INTERVAL @ reset r4 to suspend check interval
+ add r5, r2, #16 @ create space for method pointer in frame
+ and r5, #0xFFFFFFF8 @ align frame size to 16 bytes
+ sub sp, r5 @ reserve stack space for argument array
+ add r0, sp, #4 @ pass stack pointer + method ptr as dest for memcpy
+ bl memcpy @ memcpy (dest, src, bytes)
+ ldr r0, [r11] @ restore method*
+ ldr r1, [sp, #4] @ copy arg value for r1
+ ldr r2, [sp, #8] @ copy arg value for r2
+ ldr r3, [sp, #12] @ copy arg value for r3
+ mov ip, #0 @ set ip to 0
+ str ip, [sp] @ store NULL for method* at bottom of frame
+ ldr ip, [r0, #METHOD_CODE_OFFSET] @ get pointer to the code
+ blx ip @ call the method
+ add sp, r5 @ restore the stack
+ ldr ip, [sp, #24] @ load the result pointer
+ strd r0, [ip] @ store r0/r1 into result pointer
+ ldr ip, [sp, #28] @ load the floating point result pointer
+ strd r0, [ip] @ store r0/r1 into floating point result pointer
+ pop {r0, r4, r5, r9, r11, lr} @ restore spill regs
+ .cfi_adjust_cfa_offset -24
+ bx lr
+END art_quick_invoke_stub
+ /*
* On entry, r0 and r1 must be preserved, r2 is dex PC
*/
.extern artUpdateDebuggerFromCode
diff --git a/src/oat/runtime/mips/runtime_support_mips.S b/src/oat/runtime/mips/runtime_support_mips.S
index 56535b2ac2..cc41d145f3 100644
--- a/src/oat/runtime/mips/runtime_support_mips.S
+++ b/src/oat/runtime/mips/runtime_support_mips.S
@@ -427,6 +427,63 @@ INVOKE_TRAMPOLINE art_quick_invoke_super_trampoline_with_access_check, artInvoke
INVOKE_TRAMPOLINE art_quick_invoke_virtual_trampoline_with_access_check, artInvokeVirtualTrampolineWithAccessCheck
/*
+ * Invocation stub.
+ * On entry:
+ * a0 = method pointer
+ * a1 = argument array or NULL for no argument methods
+ * a2 = size of argument array in bytes
+ * a3 = (managed) thread pointer
+ * [sp + 16] = JValue* result for non-floating point returns
+ * [sp + 20] = JValue* result for floating point returns
+ */
+ENTRY art_quick_invoke_stub
+ GENERATE_GLOBAL_POINTER
+ sw $a0, 0($sp) # save out a0
+ addiu $sp, $sp, -16 # spill s0, s1, fp, ra
+ .cfi_adjust_cfa_offset 16
+ sw $ra, 12($sp)
+ .cfi_rel_offset 31, 12
+ sw $fp, 8($sp)
+ .cfi_rel_offset 30, 8
+ sw $s1, 4($sp)
+ .cfi_rel_offset 17, 4
+ sw $s0, 0($sp)
+ .cfi_rel_offset 16, 0
+ move $fp, $sp # save sp in fp
+ .cfi_def_cfa_register 30
+ move $s1, $a3 # move managed thread pointer into s1
+ addiu $s0, $zero, SUSPEND_CHECK_INTERVAL # reset s0 to suspend check interval
+ addiu $t0, $a2, 16 # create space for method pointer in frame
+ srl $t0, $t0, 3 # shift the frame size right 3
+ sll $t0, $t0, 3 # shift the frame size left 3 to align to 16 bytes
+ subu $sp, $sp, $t0 # reserve stack space for argument array
+ addiu $a0, $sp, 4 # pass stack pointer + method ptr as dest for memcpy
+ jal memcpy # (dest, src, bytes)
+ addiu $sp, $sp, -16 # make space for argument slots for memcpy
+ addiu $sp, $sp, 16 # restore stack after memcpy
+ lw $a0, 16($fp) # restore method*
+ lw $a1, 4($sp) # copy arg value for a1
+ lw $a2, 8($sp) # copy arg value for a2
+ lw $a3, 12($sp) # copy arg value for a3
+ lw $t9, METHOD_CODE_OFFSET($a0) # get pointer to the code
+ jalr $t9 # call the method
+ sw $zero, 0($sp) # store NULL for method* at bottom of frame
+ move $sp, $fp # restore the stack
+ lw $s0, 0($sp)
+ lw $s1, 4($sp)
+ lw $fp, 8($sp)
+ lw $ra, 12($sp)
+ addiu $sp, $sp, 16
+ .cfi_adjust_cfa_offset -16
+ lw $t0, 16($sp) # get result pointer
+ sw $v0, 0($t0) # store the result
+ sw $v1, 4($t0) # store the other half of the result
+ lw $t0, 20($sp) # get floating point result pointer
+ jr $ra
+ s.d $f0, 0($t0) # store floating point result
+END art_quick_invoke_stub
+
+ /*
* Entry point of native methods when JNI bug compatibility is enabled.
*/
.extern artWorkAroundAppJniBugs
diff --git a/src/oat/runtime/x86/runtime_support_x86.S b/src/oat/runtime/x86/runtime_support_x86.S
index 0ff69d9f4c..32d657d820 100644
--- a/src/oat/runtime/x86/runtime_support_x86.S
+++ b/src/oat/runtime/x86/runtime_support_x86.S
@@ -301,6 +301,50 @@ INVOKE_TRAMPOLINE art_quick_invoke_direct_trampoline_with_access_check, artInvok
INVOKE_TRAMPOLINE art_quick_invoke_super_trampoline_with_access_check, artInvokeSuperTrampolineWithAccessCheck
INVOKE_TRAMPOLINE art_quick_invoke_virtual_trampoline_with_access_check, artInvokeVirtualTrampolineWithAccessCheck
+ /*
+ * Invocation stub.
+ * On entry:
+ * [sp] = return address
+ * [sp + 4] = method pointer
+ * [sp + 8] = argument array or NULL for no argument methods
+ * [sp + 12] = size of argument array in bytes
+ * [sp + 16] = (managed) thread pointer
+ * [sp + 20] = JValue* result for non-floating point returns
+ * [sp + 24] = JValue* result for floating point returns
+ */
+DEFINE_FUNCTION art_quick_invoke_stub
+ PUSH ebp // save ebp
+ PUSH ebx // save ebx
+ mov %esp, %ebp // copy value of stack pointer into base pointer
+ .cfi_def_cfa_register ebp
+ mov 20(%ebp), %ebx // get arg array size
+ addl LITERAL(28), %ebx // reserve space for return addr, method*, ebx, and ebp in frame
+ andl LITERAL(0xFFFFFFF8), %ebx // align frame size to 16 bytes
+ subl LITERAL(12), %ebx // remove space for return address, ebx, and ebp
+ subl %ebx, %esp // reserve stack space for argument array
+ lea 4(%esp), %eax // use stack pointer + method ptr as dest for memcpy
+ pushl 20(%ebp) // push size of region to memcpy
+ pushl 16(%ebp) // push arg array as source of memcpy
+ pushl %eax // push stack pointer as destination of memcpy
+ call SYMBOL(memcpy) // (void*, const void*, size_t)
+ addl LITERAL(12), %esp // pop arguments to memcpy
+ movl LITERAL(0), (%esp) // store NULL for method*
+ mov 12(%ebp), %eax // move method pointer into eax
+ mov 4(%esp), %ecx // copy arg1 into ecx
+ mov 8(%esp), %edx // copy arg2 into edx
+ mov 12(%esp), %ebx // copy arg3 into ebx
+ call METHOD_CODE_OFFSET(%eax) // call the method
+ mov %ebp, %esp // restore stack pointer
+ POP ebx // pop ebx
+ POP ebp // pop ebp
+ mov 20(%esp), %ecx // get result pointer
+ mov %eax, (%ecx) // store the result
+ mov %edx, 4(%ecx) // store the other half of the result
+ mov 24(%esp), %ecx // get floating point result pointer
+ movsd %xmm0, (%ecx) // store the floating point result
+ ret
+END_FUNCTION art_quick_invoke_stub
+
MACRO3(NO_ARG_DOWNCALL, c_name, cxx_name, return_macro)
DEFINE_FUNCTION VAR(c_name, 0)
SETUP_REF_ONLY_CALLEE_SAVE_FRAME // save ref containing registers for GC
diff --git a/src/object_utils.h b/src/object_utils.h
index 18ad312de2..2c9f7a2c53 100644
--- a/src/object_utils.h
+++ b/src/object_utils.h
@@ -596,6 +596,11 @@ class MethodHelper {
return GetParamPrimitiveType(param) == Primitive::kPrimNot;
}
+ bool IsReturnFloatOrDouble() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ const char ret_shorty = GetReturnTypeDescriptor()[0];
+ return (ret_shorty == 'F') || (ret_shorty == 'D');
+ }
+
bool HasSameNameAndSignature(MethodHelper* other)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
if (GetDexCache() == other->GetDexCache()) {
diff --git a/src/reflection.cc b/src/reflection.cc
index d678ebdb63..addb5a3f1a 100644
--- a/src/reflection.cc
+++ b/src/reflection.cc
@@ -17,6 +17,7 @@
#include "reflection.h"
#include "class_linker.h"
+#include "invoke_arg_array_builder.h"
#include "jni_internal.h"
#include "mirror/abstract_method.h"
#include "mirror/abstract_method-inl.h"
@@ -243,9 +244,18 @@ mirror::Object* BoxPrimitive(Primitive::Type src_class, const JValue& value) {
if (kIsDebugBuild) {
CHECK_EQ(soa.Self()->GetState(), kRunnable);
}
- JValue args[1] = { value };
+
+ ArgArray arg_array(NULL, 0);
JValue result;
- soa.DecodeMethod(m)->Invoke(soa.Self(), NULL, args, &result);
+ JValue float_result;
+ if (src_class == Primitive::kPrimDouble || src_class == Primitive::kPrimLong) {
+ arg_array.AppendWide(value.GetJ());
+ } else {
+ arg_array.Append(value.GetI());
+ }
+
+ soa.DecodeMethod(m)->Invoke(soa.Self(), arg_array.GetArray(), arg_array.GetNumBytes(),
+ &result, &float_result);
return result.GetL();
}
diff --git a/src/runtime.cc b/src/runtime.cc
index 9b2dca72a4..1e7b000b54 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -39,6 +39,7 @@
#include "image.h"
#include "instrumentation.h"
#include "intern_table.h"
+#include "invoke_arg_array_builder.h"
#include "jni_internal.h"
#include "mirror/abstract_method-inl.h"
#include "mirror/array.h"
@@ -628,8 +629,11 @@ static void CreateSystemClassLoader() {
class_loader_class->FindDirectMethod("getSystemClassLoader", "()Ljava/lang/ClassLoader;");
CHECK(getSystemClassLoader != NULL);
- mirror::ClassLoader* class_loader =
- down_cast<mirror::ClassLoader*>(InvokeWithJValues(soa, NULL, getSystemClassLoader, NULL).GetL());
+ JValue result;
+ JValue float_result;
+ ArgArray arg_array(NULL, 0);
+ InvokeWithArgArray(soa, getSystemClassLoader, &arg_array, &result, &float_result);
+ mirror::ClassLoader* class_loader = down_cast<mirror::ClassLoader*>(result.GetL());
CHECK(class_loader != NULL);
soa.Self()->SetClassLoaderOverride(class_loader);
diff --git a/src/thread.cc b/src/thread.cc
index 394d2636b5..96e7a8ffac 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -37,6 +37,7 @@
#include "gc_map.h"
#include "gc/card_table-inl.h"
#include "heap.h"
+#include "invoke_arg_array_builder.h"
#include "jni_internal.h"
#include "mirror/abstract_method-inl.h"
#include "mirror/class-inl.h"
@@ -161,7 +162,11 @@ void* Thread::CreateCallback(void* arg) {
jmethodID mid = WellKnownClasses::java_lang_Thread_run;
mirror::AbstractMethod* m =
receiver->GetClass()->FindVirtualMethodForVirtualOrInterface(soa.DecodeMethod(mid));
- m->Invoke(self, receiver, NULL, NULL);
+ JValue result;
+ JValue float_result;
+ ArgArray arg_array(NULL, 0);
+ arg_array.Append(reinterpret_cast<uint32_t>(receiver));
+ m->Invoke(self, arg_array.GetArray(), arg_array.GetNumBytes(), &result, &float_result);
}
// Detach and delete self.
Runtime::Current()->GetThreadList()->Unregister(self);