Further proxy refactorings.

Factor the crawling of the quick stack arguments into a common visitor.
Factor the proxy invocation dispatch into common runtime support code,
fix numerous bugs relating to GC in the LLVM runtime support with this.
Clean up BoxPrimitive to not use an in argument as an out.

Change-Id: I7b12c8d88d5083614e480b8fb1d2f2ef7c0a51b7
diff --git a/src/oat/runtime/argument_visitor.h b/src/oat/runtime/argument_visitor.h
new file mode 100644
index 0000000..06256ca
--- /dev/null
+++ b/src/oat/runtime/argument_visitor.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_OAT_RUNTIME_ARGUMENT_VISITOR_H_
+#define ART_SRC_OAT_RUNTIME_ARGUMENT_VISITOR_H_
+
+#include "object_utils.h"
+
+namespace art {
+
+// Visits the arguments as saved to the stack by a Runtime::kRefAndArgs callee save frame.
+class ArgumentVisitor {
+ public:
+// Offset to first (not the Method*) argument in a Runtime::kRefAndArgs callee save frame.
+// Size of Runtime::kRefAndArgs callee save frame.
+// Size of Method* and register parameters in out stack arguments.
+#if defined(__arm__)
+#define CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 8
+#define CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 48
+#define STACK_ARG_SKIP 16
+#elif defined(__mips__)
+#define CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 4
+#define CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 48
+#define STACK_ARG_SKIP 16
+#elif defined(__i386__)
+#define CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 4
+#define CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 32
+#define STACK_ARG_SKIP 16
+#else
+#error "Unsupported architecture"
+#define CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 0
+#define CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 0
+#define STACK_ARG_SKIP 0
+#endif
+
+  ArgumentVisitor(MethodHelper& caller_mh, AbstractMethod** sp)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) :
+    caller_mh_(caller_mh),
+    args_in_regs_(ComputeArgsInRegs(caller_mh)),
+    num_params_(caller_mh.NumArgs()),
+    reg_args_(reinterpret_cast<byte*>(sp) + CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET),
+    stack_args_(reinterpret_cast<byte*>(sp) + CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE
+                + STACK_ARG_SKIP),
+    cur_args_(reg_args_),
+    cur_arg_index_(0),
+    param_index_(0),
+    is_split_long_or_double_(false) {
+  }
+
+  virtual ~ArgumentVisitor() {}
+
+  virtual void Visit() = 0;
+
+  bool IsParamAReference() const {
+    return caller_mh_.IsParamAReference(param_index_);
+  }
+
+  bool IsParamALongOrDouble() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    return caller_mh_.IsParamALongOrDouble(param_index_);
+  }
+
+  Primitive::Type GetParamPrimitiveType() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    return caller_mh_.GetParamPrimitiveType(param_index_);
+  }
+
+  byte* GetParamAddress() const {
+    return cur_args_ + (cur_arg_index_ * kPointerSize);
+  }
+
+  bool IsSplitLongOrDouble() const {
+    return is_split_long_or_double_;
+  }
+
+  uint64_t ReadSplitLongParam() const {
+    DCHECK(IsSplitLongOrDouble());
+    uint64_t low_half = *reinterpret_cast<uint32_t*>(GetParamAddress());
+    uint64_t high_half = *reinterpret_cast<uint32_t*>(stack_args_);
+    return (low_half & 0xffffffffULL) | (high_half << 32);
+
+  }
+
+  void VisitArguments() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    for (cur_arg_index_ = 0;  cur_arg_index_ < args_in_regs_ && param_index_ < num_params_; ) {
+      is_split_long_or_double_ = (cur_arg_index_ == 2) && IsParamALongOrDouble();
+      Visit();
+      cur_arg_index_ += (caller_mh_.IsParamALongOrDouble(param_index_) ? 2 : 1);
+      param_index_++;
+    }
+    cur_args_ = stack_args_;
+    cur_arg_index_ = is_split_long_or_double_ ? 1 : 0;
+    is_split_long_or_double_ = false;
+    while (param_index_ < num_params_) {
+      Visit();
+      cur_arg_index_ += (caller_mh_.IsParamALongOrDouble(param_index_) ? 2 : 1);
+      param_index_++;
+    }
+  }
+
+ private:
+  static size_t ComputeArgsInRegs(MethodHelper& mh) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    size_t args_in_regs = 0;
+    size_t num_params = mh.NumArgs();
+    for (size_t i = 0; i < num_params; i++) {
+      args_in_regs = args_in_regs + (mh.IsParamALongOrDouble(i) ? 2 : 1);
+      if (args_in_regs > 3) {
+        args_in_regs = 3;
+        break;
+      }
+    }
+    return args_in_regs;
+  }
+  MethodHelper& caller_mh_;
+  const size_t args_in_regs_;
+  const size_t num_params_;
+  byte* const reg_args_;
+  byte* const stack_args_;
+  byte* cur_args_;
+  size_t cur_arg_index_;
+  size_t param_index_;
+  // Does a 64bit parameter straddle the register and stack arguments?
+  bool is_split_long_or_double_;
+};
+
+}
+
+#endif  // ART_SRC_OAT_RUNTIME_ARGUMENT_VISITOR_H_
diff --git a/src/oat/runtime/arm/runtime_support_arm.S b/src/oat/runtime/arm/runtime_support_arm.S
index 7901c5f..dda1222 100644
--- a/src/oat/runtime/arm/runtime_support_arm.S
+++ b/src/oat/runtime/arm/runtime_support_arm.S
@@ -754,18 +754,18 @@
     .extern artProxyInvokeHandler
     /*
      * Called by managed code that is attempting to call a method on a proxy class. On entry
-     * r0 holds the proxy method; r1, r2 and r3 may contain arguments.
+     * r0 holds the proxy method and r1 holds the receiver; r2 and r3 may contain arguments. The
+     * frame size of the invoked proxy method agrees with a ref and args callee save frame.
      */
     ALIGN_FUNCTION_ENTRY
 art_proxy_invoke_handler:
     SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
     str     r0, [sp, #0]           @ place proxy method at bottom of frame
     mov     r2, r9                 @ pass Thread::Current
-    add     r3, sp, #12            @ pointer to r2/r3/LR/caller's Method**/out-args as second arg
-    blx     artProxyInvokeHandler  @ (Method* proxy method, receiver, Thread*, args...)
+    mov     r3, sp                 @ pass SP
+    blx     artProxyInvokeHandler  @ (Method* proxy method, receiver, Thread*, SP)
     ldr     r12, [r9, #THREAD_EXCEPTION_OFFSET]  @ load Thread::Current()->exception_
     ldr     lr,  [sp, #44]         @ restore lr
-    ldrd    r0,  [sp, #12]         @ load r0/r1 from r2/r3 that were overwritten with the out args
     add     sp,  #48               @ pop frame
     cmp     r12, #0                @ success if no exception is pending
     bxeq    lr                     @ return on success
diff --git a/src/oat/runtime/mips/runtime_support_mips.S b/src/oat/runtime/mips/runtime_support_mips.S
index 4484cde..efd3ede 100644
--- a/src/oat/runtime/mips/runtime_support_mips.S
+++ b/src/oat/runtime/mips/runtime_support_mips.S
@@ -853,11 +853,9 @@
     sw      $a0, 0($sp)            # place proxy method at bottom of frame
     move    $a2, rSELF             # pass Thread::Current
     jal     artProxyInvokeHandler  # (Method* proxy method, receiver, Thread*, args...)
-    addiu   $a3, $sp, 8            # pointer to a2/a3/ra/caller's Method**/out-args as second arg
+    move    $a3, $sp               # pass $sp
     lw      $t0, THREAD_EXCEPTION_OFFSET(rSELF) # load Thread::Current()->exception_
     lw      $ra, 44($sp)           # restore $ra
-    lw      $v0, 8($sp)
-    lw      $v1, 12($sp)
     bnez    $t0, 1f
     addiu   $sp, $sp, 48           # pop frame
     jr      $ra
diff --git a/src/oat/runtime/support_proxy.cc b/src/oat/runtime/support_proxy.cc
index 1fdab2a..5bf3cde 100644
--- a/src/oat/runtime/support_proxy.cc
+++ b/src/oat/runtime/support_proxy.cc
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include "argument_visitor.h"
 #include "object.h"
 #include "object_utils.h"
 #include "reflection.h"
@@ -24,42 +25,69 @@
 
 #include "ScopedLocalRef.h"
 
-#if defined(__arm__)
-#define SP_OFFSET_IN_BYTES 12
-#define FRAME_SIZE_IN_BYTES 48u
-#define ARG2_OFFSET_IN_WORDS 11 // offset to 3rd arg; skip callee saves, LR, Method* and out arg spills for OUT0 to OUT2
-#elif defined(__mips__)
-#define SP_OFFSET_IN_BYTES 8
-#define FRAME_SIZE_IN_BYTES 48u
-#define ARG2_OFFSET_IN_WORDS 12 // offset to 3rd arg; skip callee saves, LR, Method* and out arg spills for OUT0 to OUT2
-#elif defined(__i386__)
-#define SP_OFFSET_IN_BYTES 8
-#define FRAME_SIZE_IN_BYTES 32u
-#define ARG2_OFFSET_IN_WORDS 8 // offset to 3rd arg; skip callee saves, LR, Method* and out arg spills for OUT0 to OUT2
-#else
-#error "Unsupported architecture"
-#define SP_OFFSET_IN_BYTES 0
-#define FRAME_SIZE_IN_BYTES 0
-#define ARG2_OFFSET_IN_WORDS 0
-#endif
-
 namespace art {
 
+// Visits arguments on the stack placing them into the args vector, Object* arguments are converted
+// to jobjects.
+class BuildArgumentVisitor : public ArgumentVisitor {
+ public:
+  BuildArgumentVisitor(MethodHelper& caller_mh, AbstractMethod** sp,
+                       ScopedObjectAccessUnchecked& soa, std::vector<jvalue>& args) :
+    ArgumentVisitor(caller_mh, sp), soa_(soa), args_(args) {}
+
+  virtual void Visit() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    jvalue val;
+    Primitive::Type type = GetParamPrimitiveType();
+    switch (type) {
+      case Primitive::kPrimNot: {
+        Object* obj = *reinterpret_cast<Object**>(GetParamAddress());
+        val.l = soa_.AddLocalReference<jobject>(obj);
+        break;
+      }
+      case Primitive::kPrimLong:  // Fall-through.
+      case Primitive::kPrimDouble:
+        if (IsSplitLongOrDouble()) {
+          val.j = ReadSplitLongParam();
+        } else {
+          val.j = *reinterpret_cast<jlong*>(GetParamAddress());
+        }
+        break;
+      case Primitive::kPrimBoolean:
+      case Primitive::kPrimByte:
+      case Primitive::kPrimChar:
+      case Primitive::kPrimShort:
+      case Primitive::kPrimInt:
+      case Primitive::kPrimFloat:
+        val.i =  *reinterpret_cast<jint*>(GetParamAddress());
+        break;
+      case Primitive::kPrimVoid:
+        LOG(FATAL) << "UNREACHABLE";
+        val.j = 0;
+        break;
+    }
+    args_.push_back(val);
+  }
+
+ private:
+  ScopedObjectAccessUnchecked& soa_;
+  std::vector<jvalue>& args_;
+};
+
 // Handler for invocation on proxy methods. On entry a frame will exist for the proxy object method
-// which is responsible for recording callee save registers. We explicitly handlerize incoming
-// reference arguments (so they survive GC) and create a boxed argument array. Finally we invoke
-// the invocation handler which is a field within the proxy object receiver.
-extern "C" void artProxyInvokeHandler(AbstractMethod* proxy_method, Object* receiver,
-                                      Thread* self, byte* stack_args)
+// which is responsible for recording callee save registers. We explicitly place into jobjects the
+// incoming reference arguments (so they survive GC). We invoke the invocation handler, which is a
+// field within the proxy object, which will box the primitive arguments and deal with error cases.
+extern "C" uint64_t artProxyInvokeHandler(AbstractMethod* proxy_method, Object* receiver,
+                                          Thread* self, AbstractMethod** sp)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   // Ensure we don't get thread suspension until the object arguments are safely in jobjects.
   const char* old_cause =
       self->StartAssertNoThreadSuspension("Adding to IRT proxy object arguments");
   // Register the top of the managed stack, making stack crawlable.
-  AbstractMethod** proxy_sp = reinterpret_cast<AbstractMethod**>(stack_args - SP_OFFSET_IN_BYTES);
-  DCHECK_EQ(*proxy_sp, proxy_method);
-  self->SetTopOfStack(proxy_sp, 0);
-  DCHECK_EQ(proxy_method->GetFrameSizeInBytes(), FRAME_SIZE_IN_BYTES);
+  DCHECK_EQ(*sp, proxy_method);
+  self->SetTopOfStack(sp, 0);
+  DCHECK_EQ(proxy_method->GetFrameSizeInBytes(),
+            Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs)->GetFrameSizeInBytes());
   self->VerifyStack();
   // Start new JNI local reference state.
   JNIEnvExt* env = self->GetJniEnv();
@@ -67,173 +95,26 @@
   ScopedJniEnvLocalRefState env_state(env);
   // Create local ref. copies of proxy method and the receiver.
   jobject rcvr_jobj = soa.AddLocalReference<jobject>(receiver);
-  jobject proxy_method_jobj = soa.AddLocalReference<jobject>(proxy_method);
 
-  // Placing into local references incoming arguments from the caller's register arguments,
-  // replacing original Object* with jobject.
+  // Placing arguments into args vector and remove the receiver.
   MethodHelper proxy_mh(proxy_method);
-  const size_t num_params = proxy_mh.NumArgs();
-  size_t args_in_regs = 0;
-  for (size_t i = 1; i < num_params; i++) {  // skip receiver
-    args_in_regs = args_in_regs + (proxy_mh.IsParamALongOrDouble(i) ? 2 : 1);
-    if (args_in_regs > 2) {
-      args_in_regs = 2;
-      break;
-    }
-  }
-  size_t cur_arg = 0;  // current stack location to read
-  size_t param_index = 1;  // skip receiver
-  while (cur_arg < args_in_regs && param_index < num_params) {
-    if (proxy_mh.IsParamAReference(param_index)) {
-      Object* obj = *reinterpret_cast<Object**>(stack_args + (cur_arg * kPointerSize));
-      jobject jobj = soa.AddLocalReference<jobject>(obj);
-      *reinterpret_cast<jobject*>(stack_args + (cur_arg * kPointerSize)) = jobj;
-    }
-    cur_arg = cur_arg + (proxy_mh.IsParamALongOrDouble(param_index) ? 2 : 1);
-    param_index++;
-  }
-  // Placing into local references incoming arguments from the caller's stack arguments.
-  cur_arg += ARG2_OFFSET_IN_WORDS;
-  while (param_index < num_params) {
-    if (proxy_mh.IsParamAReference(param_index)) {
-      Object* obj = *reinterpret_cast<Object**>(stack_args + (cur_arg * kPointerSize));
-      jobject jobj = soa.AddLocalReference<jobject>(obj);
-      *reinterpret_cast<jobject*>(stack_args + (cur_arg * kPointerSize)) = jobj;
-    }
-    cur_arg = cur_arg + (proxy_mh.IsParamALongOrDouble(param_index) ? 2 : 1);
-    param_index++;
-  }
-  self->EndAssertNoThreadSuspension(old_cause);
-  // Sanity check writing the jobjects over the Object*s in place didn't damage the stack.
-  self->VerifyStack();
+  std::vector<jvalue> args;
+  BuildArgumentVisitor local_ref_visitor(proxy_mh, sp, soa, args);
+  local_ref_visitor.VisitArguments();
+  args.erase(args.begin());
 
-  // Set up arguments array and place in local IRT during boxing (which may allocate/GC).
-  jvalue args_jobj[3];
-  args_jobj[0].l = rcvr_jobj;
-  args_jobj[1].l = proxy_method_jobj;
-  // Args array, if no arguments then NULL (don't include receiver in argument count).
-  args_jobj[2].l = NULL;
-  ObjectArray<Object>* args = NULL;
-  if ((num_params - 1) > 0) {
-    args = Runtime::Current()->GetClassLinker()->AllocObjectArray<Object>(self, num_params - 1);
-    if (args == NULL) {
-      CHECK(self->IsExceptionPending());
-      return;
-    }
-    args_jobj[2].l = soa.AddLocalReference<jobjectArray>(args);
-  }
   // Convert proxy method into expected interface method.
   AbstractMethod* interface_method = proxy_method->FindOverriddenMethod();
   DCHECK(interface_method != NULL);
   DCHECK(!interface_method->IsProxyMethod()) << PrettyMethod(interface_method);
-  args_jobj[1].l = soa.AddLocalReference<jobject>(interface_method);
-  // Box primitive type arguments.
-  cur_arg = 0;  // Stack location to read to start.
-  // Reset index, will index into param type array which doesn't include the receiver.
-  param_index = 0;
-  ObjectArray<Class>* param_types = proxy_mh.GetParameterTypes(self);
-  if (param_types == NULL) {
-    CHECK(self->IsExceptionPending());
-    return;
-  }
-  // Check number of parameter types agrees with number from the Method - less 1 for the receiver.
-  DCHECK_EQ(static_cast<size_t>(param_types->GetLength()), num_params - 1);
-  while (cur_arg < args_in_regs && param_index < (num_params - 1)) {
-    Class* param_type = param_types->Get(param_index);
-    Object* obj;
-    if (!param_type->IsPrimitive()) {
-      obj = self->DecodeJObject(*reinterpret_cast<jobject*>(stack_args + (cur_arg * kPointerSize)));
-    } else {
-      JValue val = *reinterpret_cast<JValue*>(stack_args + (cur_arg * kPointerSize));
-      if (cur_arg == 1 && (param_type->IsPrimitiveLong() || param_type->IsPrimitiveDouble())) {
-        // long/double split over regs and stack, mask in high half from stack arguments.
-        uint64_t high_half =
-            *reinterpret_cast<uint32_t*>(stack_args + ((ARG2_OFFSET_IN_WORDS + 2) * kPointerSize));
-        val.SetJ((val.GetJ() & 0xffffffffULL) | (high_half << 32));
-      }
-      BoxPrimitive(param_type->GetPrimitiveType(), val);
-      if (self->IsExceptionPending()) {
-        return;
-      }
-      obj = val.GetL();
-    }
-    args->Set(param_index, obj);
-    cur_arg = cur_arg + (param_type->IsPrimitiveLong() || param_type->IsPrimitiveDouble() ? 2 : 1);
-    param_index++;
-  }
-  // Placing into local references incoming arguments from the caller's stack arguments.
-  cur_arg += ARG2_OFFSET_IN_WORDS;
-  while (param_index < (num_params - 1)) {
-    Class* param_type = param_types->Get(param_index);
-    Object* obj;
-    if (!param_type->IsPrimitive()) {
-      obj = self->DecodeJObject(*reinterpret_cast<jobject*>(stack_args + (cur_arg * kPointerSize)));
-    } else {
-      JValue val = *reinterpret_cast<JValue*>(stack_args + (cur_arg * kPointerSize));
-      BoxPrimitive(param_type->GetPrimitiveType(), val);
-      if (self->IsExceptionPending()) {
-        return;
-      }
-      obj = val.GetL();
-    }
-    args->Set(param_index, obj);
-    cur_arg = cur_arg + (param_type->IsPrimitiveLong() || param_type->IsPrimitiveDouble() ? 2 : 1);
-    param_index++;
-  }
-  // Get the InvocationHandler method and the field that holds it within the Proxy object.
-  DCHECK(env->IsInstanceOf(rcvr_jobj, WellKnownClasses::java_lang_reflect_Proxy));
-  jobject inv_hand = env->GetObjectField(rcvr_jobj, WellKnownClasses::java_lang_reflect_Proxy_h);
-  // Call InvocationHandler.invoke.
-  jobject result =
-      env->CallObjectMethodA(inv_hand, WellKnownClasses::java_lang_reflect_InvocationHandler_invoke,
-                             args_jobj);
-  // Place result in stack args.
-  if (!self->IsExceptionPending()) {
-    Object* result_ref = self->DecodeJObject(result);
-    if (result_ref != NULL) {
-      JValue result_unboxed;
-      bool unboxed_okay = UnboxPrimitiveForResult(result_ref, proxy_mh.GetReturnType(),
-                                                  result_unboxed);
-      if (!unboxed_okay) {
-        self->ClearException();
-        self->ThrowNewExceptionF("Ljava/lang/ClassCastException;",
-                                 "Couldn't convert result of type %s to %s",
-                                 PrettyTypeOf(result_ref).c_str(),
-                                 PrettyDescriptor(proxy_mh.GetReturnType()).c_str());
-        return;
-      }
-      *reinterpret_cast<JValue*>(stack_args) = result_unboxed;
-    } else {
-      *reinterpret_cast<jobject*>(stack_args) = NULL;
-    }
-  } else {
-    // In the case of checked exceptions that aren't declared, the exception must be wrapped by
-    // a UndeclaredThrowableException.
-    Throwable* exception = self->GetException();
-    if (exception->IsCheckedException()) {
-      SynthesizedProxyClass* proxy_class =
-          down_cast<SynthesizedProxyClass*>(proxy_method->GetDeclaringClass());
-      int throws_index = -1;
-      size_t num_virt_methods = proxy_class->NumVirtualMethods();
-      for (size_t i = 0; i < num_virt_methods; i++) {
-        if (proxy_class->GetVirtualMethod(i) == proxy_method) {
-          throws_index = i;
-          break;
-        }
-      }
-      CHECK_NE(throws_index, -1);
-      ObjectArray<Class>* declared_exceptions = proxy_class->GetThrows()->Get(throws_index);
-      Class* exception_class = exception->GetClass();
-      bool declares_exception = false;
-      for (int i = 0; i < declared_exceptions->GetLength() && !declares_exception; i++) {
-        Class* declared_exception = declared_exceptions->Get(i);
-        declares_exception = declared_exception->IsAssignableFrom(exception_class);
-      }
-      if (!declares_exception) {
-        self->ThrowNewWrappedException("Ljava/lang/reflect/UndeclaredThrowableException;", NULL);
-      }
-    }
-  }
+  jobject interface_method_jobj = soa.AddLocalReference<jobject>(interface_method);
+
+  // All naked Object*s should now be in jobjects, so its safe to go into the main invoke code
+  // that performs allocations.
+  self->EndAssertNoThreadSuspension(old_cause);
+  JValue result = InvokeProxyInvocationHandler(soa, proxy_mh.GetShorty(),
+                                               rcvr_jobj, interface_method_jobj, args);
+  return result.GetJ();
 }
 
 }  // namespace art
diff --git a/src/oat/runtime/x86/runtime_support_x86.S b/src/oat/runtime/x86/runtime_support_x86.S
index 379fcce..f2f9fa4 100644
--- a/src/oat/runtime/x86/runtime_support_x86.S
+++ b/src/oat/runtime/x86/runtime_support_x86.S
@@ -738,15 +738,14 @@
 
 DEFINE_FUNCTION art_proxy_invoke_handler
     SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME   // save frame
-    lea 8(%esp), %ebx             // pointer to r2/r3/LR/caller's Method**/out-args as second arg
-    pushl %ebx                    // pass args
+    pushl %esp                    // pass SP
     pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
     pushl %ecx                    // pass receiver
     pushl %eax                    // pass proxy method
-    call SYMBOL(artProxyInvokeHandler)     // (proxy method, receiver, Thread*, args...)
-    mov 24(%esp), %eax            // get ret0 which was written into r2 on the stack
-    mov 28(%esp), %edx            // get ret1 which was written into r3 on the stack
-    movsd 24(%esp), %xmm0         // get ret0/ret1 from stack for floating point
+    call SYMBOL(artProxyInvokeHandler) // (proxy method, receiver, Thread*, SP)
+    movd %eax, %xmm0              // place return value also into floating point return value
+    movd %edx, %xmm1
+    punpckldq %xmm1, %xmm0
     addl LITERAL(44), %esp        // pop arguments
     RETURN_OR_DELIVER_PENDING_EXCEPTION    // return or deliver exception