diff options
author | 2013-02-27 17:57:33 -0800 | |
---|---|---|
committer | 2013-03-15 14:18:28 -0700 | |
commit | 5d9173014c1ca09f7249a6b07629aa37778b5f8f (patch) | |
tree | 80543dbe9af6795212373bb12532b638ff3b22f3 | |
parent | aed0716b9592bb3095cdfc4b111011f9ed74877d (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.h | 3 | ||||
-rw-r--r-- | src/class_linker.cc | 6 | ||||
-rw-r--r-- | src/debugger.cc | 13 | ||||
-rw-r--r-- | src/heap.cc | 21 | ||||
-rw-r--r-- | src/interpreter/interpreter.cc | 166 | ||||
-rw-r--r-- | src/interpreter/interpreter.h | 3 | ||||
-rw-r--r-- | src/invoke_arg_array_builder.h | 178 | ||||
-rw-r--r-- | src/jni_internal.cc | 75 | ||||
-rw-r--r-- | src/jni_internal.h | 5 | ||||
-rw-r--r-- | src/jni_internal_test.cc | 683 | ||||
-rw-r--r-- | src/mirror/abstract_method.cc | 104 | ||||
-rw-r--r-- | src/mirror/abstract_method.h | 7 | ||||
-rw-r--r-- | src/mirror/object_test.cc | 2 | ||||
-rw-r--r-- | src/oat/runtime/arm/runtime_support_arm.S | 64 | ||||
-rw-r--r-- | src/oat/runtime/mips/runtime_support_mips.S | 57 | ||||
-rw-r--r-- | src/oat/runtime/x86/runtime_support_x86.S | 44 | ||||
-rw-r--r-- | src/object_utils.h | 5 | ||||
-rw-r--r-- | src/reflection.cc | 14 | ||||
-rw-r--r-- | src/runtime.cc | 8 | ||||
-rw-r--r-- | src/thread.cc | 7 |
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); |