Merge "Re-enable large object space." into dalvik-dev
diff --git a/src/asm_support.h b/src/asm_support.h
index 470b81f..bda0b7c 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 4a07eba..725e710 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -2694,9 +2694,11 @@
 
   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 c96bb66..09c930a 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 @@
 
   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/dex2oat.cc b/src/dex2oat.cc
index ed7bd88..5c6b35e 100644
--- a/src/dex2oat.cc
+++ b/src/dex2oat.cc
@@ -531,7 +531,7 @@
       std::string message(# call); \
       message += " failed for "; \
       message += reason; \
-      Die(message); \
+      Fatal(message); \
     } \
   } while (false)
 
@@ -572,22 +572,31 @@
     return NULL;
   }
 
-  static void Warn(const std::string& message) {
-    // TODO: Switch to LOG(WARNING) when we can guarantee it won't prevent shutdown in error cases.
-    fprintf(stderr, "%s\n", message.c_str());
+  static void Message(char severity, const std::string& message) {
+    // TODO: Remove when we switch to LOG when we can guarantee it won't prevent shutdown in error cases.
+    fprintf(stderr, "dex2oat%s %c %d %d %s\n",
+            kIsDebugBuild ? "d" : "",
+            severity,
+            getpid(),
+            GetTid(),
+            message.c_str());
   }
 
-  static void Die(const std::string& message) {
-    // TODO: Switch to LOG(FATAL) when we can guarantee it won't prevent shutdown in error cases.
-    fprintf(stderr, "%s\n", message.c_str());
+  static void Warn(const std::string& message) {
+    Message('W', message);
+  }
+
+  static void Fatal(const std::string& message) {
+    Message('F', message);
     exit(1);
   }
 
   void Wait() {
     bool warning = true;
-    timespec warning_ts, timeout_ts;
     CHECK_GT(kWatchDogTimeoutSeconds, kWatchDogWarningSeconds);
+    timespec warning_ts;
     InitTimeSpec(true, CLOCK_REALTIME, kWatchDogWarningSeconds * 1000, 0, &warning_ts);
+    timespec timeout_ts;
     InitTimeSpec(true, CLOCK_REALTIME, kWatchDogTimeoutSeconds * 1000, 0, &timeout_ts);
     const char* reason = "dex2oat watch dog thread waiting";
     CHECK_WATCH_DOG_PTHREAD_CALL(pthread_mutex_lock, (&mutex_), reason);
@@ -603,22 +612,24 @@
           Warn(message.c_str());
           warning = false;
         } else {
-          Die(message.c_str());
+          Fatal(message.c_str());
         }
       } else if (rc != 0) {
         std::string message(StringPrintf("pthread_cond_timedwait failed: %s",
                                          strerror(errno)));
-        Die(message.c_str());
+        Fatal(message.c_str());
       }
     }
     CHECK_WATCH_DOG_PTHREAD_CALL(pthread_mutex_unlock, (&mutex_), reason);
   }
 
-  static const unsigned int kWatchDogWarningSeconds = 1 * 60;  // 1 minute.
-#ifdef ART_USE_PORTABLE_COMPILER
+  // When setting timeouts, keep in mind that the build server may not be as fast as your desktop.
+#if ART_USE_PORTABLE_COMPILER
+  static const unsigned int kWatchDogWarningSeconds =  2 * 60;  // 2 minutes.
   static const unsigned int kWatchDogTimeoutSeconds = 30 * 60;  // 25 minutes + buffer.
 #else
-  static const unsigned int kWatchDogTimeoutSeconds = 3 * 60;  // 2 minutes + buffer.
+  static const unsigned int kWatchDogWarningSeconds =  1 * 60;  // 1 minute.
+  static const unsigned int kWatchDogTimeoutSeconds =  6 * 60;  // 5 minutes + buffer.
 #endif
 
   bool is_watch_dog_enabled_;
diff --git a/src/heap.cc b/src/heap.cc
index 30da10e..7ec6085 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"
@@ -1729,10 +1730,12 @@
 
 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 {
@@ -1765,10 +1768,12 @@
     // 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 195549a..1a571ec 100644
--- a/src/interpreter/interpreter.cc
+++ b/src/interpreter/interpreter.cc
@@ -54,13 +54,13 @@
 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 @@
     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 @@
     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 @@
     }
   } 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 @@
     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 @@
       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 @@
       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 @@
       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 @@
       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 @@
       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 @@
   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 @@
 }
 
 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 @@
     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 12da736..91816c9 100644
--- a/src/interpreter/interpreter.h
+++ b/src/interpreter/interpreter.h
@@ -34,7 +34,8 @@
 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 19c42ac..ecd0fb0 100644
--- a/src/invoke_arg_array_builder.h
+++ b/src/invoke_arg_array_builder.h
@@ -42,170 +42,240 @@
 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)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    for (size_t i = 1, offset = 0; i < shorty_len_; ++i, ++offset) {
-      switch (shorty_[i]) {
-        case 'Z':
-          arg_array_[offset].SetZ(va_arg(ap, jint));
-          break;
-        case 'B':
-          arg_array_[offset].SetB(va_arg(ap, jint));
-          break;
-        case 'C':
-          arg_array_[offset].SetC(va_arg(ap, jint));
-          break;
-        case 'S':
-          arg_array_[offset].SetS(va_arg(ap, jint));
-          break;
-        case 'I':
-          arg_array_[offset].SetI(va_arg(ap, jint));
-          break;
-        case 'F':
-          arg_array_[offset].SetF(va_arg(ap, jdouble));
-          break;
-        case 'L':
-          arg_array_[offset].SetL(soa.Decode<mirror::Object*>(va_arg(ap, jobject)));
-          break;
-        case 'D':
-          arg_array_[offset].SetD(va_arg(ap, jdouble));
-          break;
-        case 'J':
-          arg_array_[offset].SetJ(va_arg(ap, jlong));
-          break;
-      }
-    }
+  uint32_t GetNumBytes() {
+    return num_bytes_;
   }
 
-  void BuildArgArray(const ScopedObjectAccess& soa, jvalue* args)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    for (size_t i = 1, offset = 0; i < shorty_len_; ++i, ++offset) {
-      switch (shorty_[i]) {
-        case 'Z':
-          arg_array_[offset].SetZ(args[offset].z);
-          break;
-        case 'B':
-          arg_array_[offset].SetB(args[offset].b);
-          break;
-        case 'C':
-          arg_array_[offset].SetC(args[offset].c);
-          break;
-        case 'S':
-          arg_array_[offset].SetS(args[offset].s);
-          break;
-        case 'I':
-          arg_array_[offset].SetI(args[offset].i);
-          break;
-        case 'F':
-          arg_array_[offset].SetF(args[offset].f);
-          break;
-        case 'L':
-          arg_array_[offset].SetL(soa.Decode<mirror::Object*>(args[offset].l));
-          break;
-        case 'D':
-          arg_array_[offset].SetD(args[offset].d);
-          break;
-        case 'J':
-          arg_array_[offset].SetJ(args[offset].j);
-          break;
-      }
-    }
+  void Append(uint32_t value) {
+    arg_array_[num_bytes_ / 4] = value;
+    num_bytes_ += 4;
   }
 
-  void BuildArgArray(const ShadowFrame& shadow_frame, uint32_t range_start)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    for (size_t i = 1, offset = 0; i < shorty_len_; ++i, ++offset) {
-      switch (shorty_[i]) {
-        case 'Z':
-          arg_array_[i - 1].SetZ(shadow_frame.GetVReg(range_start + offset));
-          break;
-        case 'B':
-          arg_array_[i - 1].SetB(shadow_frame.GetVReg(range_start + offset));
-          break;
-        case 'C':
-          arg_array_[i - 1].SetC(shadow_frame.GetVReg(range_start + offset));
-          break;
-        case 'S':
-          arg_array_[i - 1].SetS(shadow_frame.GetVReg(range_start + offset));
-          break;
-        case 'I':
-          arg_array_[i - 1].SetI(shadow_frame.GetVReg(range_start + offset));
-          break;
-        case 'F':
-          arg_array_[i - 1].SetF(shadow_frame.GetVRegFloat(range_start + offset));
-          break;
-        case 'L':
-          arg_array_[i - 1].SetL(shadow_frame.GetVRegReference(range_start + offset));
-          break;
-        case 'D':
-          arg_array_[i - 1].SetD(shadow_frame.GetVRegDouble(range_start + offset));
-          offset++;
-          break;
-        case 'J':
-          arg_array_[i - 1].SetJ(shadow_frame.GetVRegLong(range_start + offset));
-          offset++;
-          break;
-      }
-    }
+  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 ShadowFrame& shadow_frame, const uint32_t* arg_regs)
+  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_[i - 1].SetZ(shadow_frame.GetVReg(arg_regs[offset]));
+          arg_array_[offset] = va_arg(ap, jint);
           break;
         case 'B':
-          arg_array_[i - 1].SetB(shadow_frame.GetVReg(arg_regs[offset]));
+          arg_array_[offset] = va_arg(ap, jint);
           break;
         case 'C':
-          arg_array_[i - 1].SetC(shadow_frame.GetVReg(arg_regs[offset]));
+          arg_array_[offset] = va_arg(ap, jint);
           break;
         case 'S':
-          arg_array_[i - 1].SetS(shadow_frame.GetVReg(arg_regs[offset]));
+          arg_array_[offset] = va_arg(ap, jint);
           break;
         case 'I':
-          arg_array_[i - 1].SetI(shadow_frame.GetVReg(arg_regs[offset]));
+          arg_array_[offset] = va_arg(ap, jint);
+          break;
+        case 'F': {
+          JValue value;
+          value.SetF(va_arg(ap, jdouble));
+          arg_array_[offset] = value.GetI();
+          break;
+        }
+        case 'L':
+          arg_array_[offset] = reinterpret_cast<int32_t>(soa.Decode<mirror::Object*>(va_arg(ap, jobject)));
+          break;
+        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': {
+          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, mirror::Object* receiver, jvalue* args)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    // 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] = args[args_offset].z;
+          break;
+        case 'B':
+          arg_array_[offset] = args[args_offset].b;
+          break;
+        case 'C':
+          arg_array_[offset] = args[args_offset].c;
+          break;
+        case 'S':
+          arg_array_[offset] = args[args_offset].s;
+          break;
+        case 'I':
+          arg_array_[offset] = args[args_offset].i;
           break;
         case 'F':
-          arg_array_[i - 1].SetF(shadow_frame.GetVRegFloat(arg_regs[offset]));
+          arg_array_[offset] = args[args_offset].i;
           break;
         case 'L':
-          arg_array_[i - 1].SetL(shadow_frame.GetVRegReference(arg_regs[offset]));
+          arg_array_[offset] = reinterpret_cast<int32_t>(soa.Decode<mirror::Object*>(args[args_offset].l));
           break;
         case 'D':
-          arg_array_[i - 1].SetD(shadow_frame.GetVRegDouble(arg_regs[offset]));
+          arg_array_[offset] = args[args_offset].j;
+          arg_array_[offset + 1] = args[args_offset].j >> 32;
           offset++;
           break;
         case 'J':
-          arg_array_[i - 1].SetJ(shadow_frame.GetVRegLong(arg_regs[offset]));
+          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, mirror::Object* receiver, uint32_t range_start)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    // 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_[offset] = shadow_frame.GetVReg(range_start + reg_offset);
+          break;
+        case 'B':
+          arg_array_[offset] = shadow_frame.GetVReg(range_start + reg_offset);
+          break;
+        case 'C':
+          arg_array_[offset] = shadow_frame.GetVReg(range_start + reg_offset);
+          break;
+        case 'S':
+          arg_array_[offset] = shadow_frame.GetVReg(range_start + reg_offset);
+          break;
+        case 'I':
+          arg_array_[offset] = shadow_frame.GetVReg(range_start + reg_offset);
+          break;
+        case 'F':
+          arg_array_[offset] = shadow_frame.GetVReg(range_start + reg_offset);
+          break;
+        case 'L':
+          arg_array_[offset] = reinterpret_cast<int32_t>(shadow_frame.GetVRegReference(range_start + reg_offset));
+          break;
+        case 'D':
+          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_[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, mirror::Object* receiver, const uint32_t* arg_regs)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    // 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_[offset] = shadow_frame.GetVReg(arg_regs[reg_offset]);
+          break;
+        case 'B':
+          arg_array_[offset] = shadow_frame.GetVReg(arg_regs[reg_offset]);
+          break;
+        case 'C':
+          arg_array_[offset] = shadow_frame.GetVReg(arg_regs[reg_offset]);
+          break;
+        case 'S':
+          arg_array_[offset] = shadow_frame.GetVReg(arg_regs[reg_offset]);
+          break;
+        case 'I':
+          arg_array_[offset] = shadow_frame.GetVReg(arg_regs[reg_offset]);
+          break;
+        case 'F':
+          arg_array_[offset] = shadow_frame.GetVReg(arg_regs[reg_offset]);
+          break;
+        case 'L':
+          arg_array_[offset] = reinterpret_cast<int32_t>(shadow_frame.GetVRegReference(arg_regs[reg_offset]));
+          break;
+        case 'D':
+          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_[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 887fcb4..9cf12e0 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -90,15 +90,19 @@
   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 +116,14 @@
       ++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 +133,13 @@
   }
 }
 
-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 +148,16 @@
   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 +171,16 @@
   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 +189,16 @@
   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 +595,16 @@
   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 9b773f3..d4fc514 100644
--- a/src/jni_internal.h
+++ b/src/jni_internal.h
@@ -42,6 +42,7 @@
 class ClassLoader;
 class Field;
 }
+class ArgArray;
 union JValue;
 class Libraries;
 class ScopedObjectAccess;
@@ -55,8 +56,8 @@
 
 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 67020d8..5f7a6c8 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 "mirror/object-inl.h"
@@ -28,6 +29,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() {
@@ -73,10 +77,10 @@
     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));
@@ -100,48 +104,57 @@
     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;
 
-    args[0].SetB(0);
+    if (!is_static) {
+      arg_array.Append(reinterpret_cast<uint32_t>(receiver));
+      args++;
+    }
+
+    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());
   }
 
@@ -149,30 +162,36 @@
       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;
 
-    args[0].SetI(0);
+    if (!is_static) {
+      arg_array.Append(reinterpret_cast<uint32_t>(receiver));
+      args++;
+    }
+
+    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());
   }
 
@@ -180,70 +199,91 @@
       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());
   }
 
@@ -251,44 +291,51 @@
       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());
   }
 
@@ -296,49 +343,56 @@
       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());
   }
 
@@ -346,54 +400,61 @@
       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());
   }
 
@@ -401,146 +462,262 @@
       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);
+    if (!is_static) {
+      arg_array.Append(reinterpret_cast<uint32_t>(receiver));
+      args++;
+    }
+
+    value.SetD(0.0);
+    value2.SetD(0.0);
+    arg_array.AppendWide(value.GetJ());
+    arg_array.AppendWide(value2.GetJ());
     result.SetD(-1.0);
-    (*stub)(method, NULL, 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);
-    args[1].SetD(2.0);
+    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());
+    (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
+    EXPECT_EQ(3.0, float_result.GetD());
 
-    args[0].SetD(1.0);
-    args[1].SetD(-2.0);
+    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());
+    (*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);
-    args[1].SetD(DBL_MIN);
+    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());
+    (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
+    EXPECT_EQ(1.7976931348623157e308, float_result.GetD());
 
-    args[0].SetD(DBL_MAX);
-    args[1].SetD(DBL_MAX);
+    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);
+    if (!is_static) {
+      arg_array.Append(reinterpret_cast<uint32_t>(receiver));
+      args++;
+    }
+
+    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);
-    (*stub)(method, NULL, 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);
-    args[1].SetD(2.0);
-    args[2].SetD(3.0);
+    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());
+    (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
+    EXPECT_EQ(6.0, float_result.GetD());
 
-    args[0].SetD(1.0);
-    args[1].SetD(-2.0);
-    args[2].SetD(3.0);
+    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");
+    DoCompile(method, receiver, is_static, "sum", "(DDDD)D");
 
-    JValue args[4];
+    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);
+    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);
+    arg_array.AppendWide(value.GetJ());
+    arg_array.AppendWide(value2.GetJ());
+    arg_array.AppendWide(value3.GetJ());
+    arg_array.AppendWide(value4.GetJ());
     result.SetD(-1.0);
-    (*stub)(method, NULL, 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);
-    args[1].SetD(2.0);
-    args[2].SetD(3.0);
-    args[3].SetD(4.0);
+    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());
+    (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
+    EXPECT_EQ(10.0, float_result.GetD());
 
-    args[0].SetD(1.0);
-    args[1].SetD(-2.0);
-    args[2].SetD(3.0);
-    args[3].SetD(-4.0);
+    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");
+    DoCompile(method, receiver, is_static, "sum", "(DDDDD)D");
 
-    JValue args[5];
+    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());
+    (*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);
-    args[1].SetD(2.0);
-    args[2].SetD(3.0);
-    args[3].SetD(4.0);
-    args[4].SetD(5.0);
+    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());
+    (*art_quick_invoke_stub)(method, arg_array.GetArray(), arg_array.GetNumBytes(), Thread::Current(), &result, &float_result);
+    EXPECT_EQ(15.0, float_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);
+    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_;
@@ -1421,12 +1598,12 @@
   mirror::AbstractMethod* method = klass->FindDirectMethod("main", "([Ljava/lang/String;)V");
   ASSERT_TRUE(method != NULL);
 
-  mirror::AbstractMethod::InvokeStub* stub = method->GetInvokeStub();
+  ArgArray arg_array(NULL, 0);
+  arg_array.Append(0);
+  JValue result;
+  JValue float_result;
 
-  JValue args[1];
-  args[0].SetL(NULL);
-
-  (*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 202fa2f..e185c9c 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 @@
   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 @@
     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) << 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);
+        }
+        if (kLogInvocationStartAndReturn) {
+          LOG(INFO) << StringPrintf("Returned '%s' code=%p stub=%p",
+                                    PrettyMethod(this).c_str(), GetCode(), stub);
+        }
+      } else {
         if (kLogInvocationStartAndReturn) {
           LOG(INFO) << "Interpreting " << PrettyMethod(this) << "'";
         }
-        art::interpreter::EnterInterpreterFromInvoke(self, this, receiver, args, result);
+        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);
-        }
+      }
+    } 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 1d57abb..a489b1d 100644
--- a/src/mirror/abstract_method.h
+++ b/src/mirror/abstract_method.h
@@ -54,6 +54,10 @@
     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 @@
   // 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 29cf2f1..eed96bd 100644
--- a/src/mirror/object_test.cc
+++ b/src/mirror/object_test.cc
@@ -74,6 +74,8 @@
   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 6067dd5..bd3f45d 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_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 56535b2..480e5c8 100644
--- a/src/oat/runtime/mips/runtime_support_mips.S
+++ b/src/oat/runtime/mips/runtime_support_mips.S
@@ -427,6 +427,64 @@
 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
+    s.s   $f0, 0($t0)           # store floating point result
+    jr    $ra
+    s.s   $f1, 4($t0)           # store other half of 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 0ff69d9..32d657d 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_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 18ad312..2c9f7a2 100644
--- a/src/object_utils.h
+++ b/src/object_utils.h
@@ -596,6 +596,11 @@
     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 d678ebd..addb5a3 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 @@
   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 9b2dca7..1e7b000 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 @@
       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 94c437f..bf1f7f7 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 @@
     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);