Fix handling of long arguments in unresolved and proxy stubs.

Change-Id: I4561230971ed31ee9af0ec5007e0d09b30781779
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index 4230cd3..964c646 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -320,7 +320,15 @@
   ClassLinker* linker = Runtime::Current()->GetClassLinker();
   const char* shorty = linker->MethodShorty(method_idx, *caller_sp);
   size_t shorty_len = strlen(shorty);
-  size_t args_in_regs = shorty_len < 3 ? shorty_len : 3;
+  size_t args_in_regs = 0;
+  for (size_t i = 1; i < shorty_len; i++) {
+    char c = shorty[i];
+    args_in_regs = args_in_regs + (c == 'J' || c == 'D' ? 2 : 1);
+    if (args_in_regs > 3) {
+      args_in_regs = 3;
+      break;
+    }
+  }
   bool is_static;
   if (type == Runtime::kUnknownMethod) {
     Method* caller = *caller_sp;
@@ -339,27 +347,36 @@
   } else {
     is_static = type == Runtime::kStaticMethod;
   }
-  // Handlerize references in registers
-  int cur_arg = 1;   // skip method_idx in R0, first arg is in R1
+  // Placing into local references incoming arguments from the caller's register arguments
+  size_t cur_arg = 1;   // skip method_idx in R0, first arg is in R1
   if (!is_static) {
     Object* obj = reinterpret_cast<Object*>(regs[cur_arg]);
     cur_arg++;
+    if (args_in_regs < 3) {
+      // If we thought we had fewer than 3 arguments in registers, account for the receiver
+      args_in_regs++;
+    }
     AddLocalReference<jobject>(env, obj);
   }
-  for(size_t i = 0; i < args_in_regs; i++) {
-    char c = shorty[i + 1];  // offset to skip return value
+  size_t shorty_index = 1;  // skip return value
+  // Iterate while arguments and arguments in registers (less 1 from cur_arg which is offset to skip
+  // R0)
+  while ((cur_arg - 1) < args_in_regs && shorty_index < shorty_len) {
+    char c = shorty[shorty_index];
+    shorty_index++;
     if (c == 'L') {
       Object* obj = reinterpret_cast<Object*>(regs[cur_arg]);
       AddLocalReference<jobject>(env, obj);
     }
     cur_arg = cur_arg + (c == 'J' || c == 'D' ? 2 : 1);
   }
-  // Handlerize references in out going arguments
-  for(size_t i = 3; i < (shorty_len - 1); i++) {
-    char c = shorty[i + 1];  // offset to skip return value
+  // Placing into local references incoming arguments from the caller's stack arguments
+  cur_arg += 5;  // skip LR, Method* and spills for R1 to R3
+  while (shorty_index < shorty_len) {
+    char c = shorty[shorty_index];
+    shorty_index++;
     if (c == 'L') {
-      // Plus 6 to skip args 1 to 3, LR and Method* plus the start offset of 3 to skip the spills
-      Object* obj = reinterpret_cast<Object*>(regs[i + 6]);
+      Object* obj = reinterpret_cast<Object*>(regs[cur_arg]);
       AddLocalReference<jobject>(env, obj);
     }
     cur_arg = cur_arg + (c == 'J' || c == 'D' ? 2 : 1);
@@ -805,39 +822,42 @@
   jobject rcvr_jobj = AddLocalReference<jobject>(env, receiver);
   jobject proxy_method_jobj = AddLocalReference<jobject>(env, proxy_method);
 
-  // Place incoming objects in local reference table, replacing original Object* with jobject
-  size_t num_args = proxy_method->NumArgs();
-  if (num_args > 1) {
-    if (proxy_method->IsParamAReference(1)) {
-      Object* obj = *reinterpret_cast<Object**>(stack_args);  // reference from r1
+  // Placing into local references incoming arguments from the caller's register arguments,
+  // replacing original Object* with jobject
+  const size_t num_params = proxy_method->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_method->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_method->IsParamAReference(param_index)) {
+      Object* obj = *reinterpret_cast<Object**>(stack_args + (cur_arg * kPointerSize));
       jobject jobj = AddLocalReference<jobject>(env, obj);
-      *reinterpret_cast<jobject*>(stack_args) = jobj;
+      *reinterpret_cast<jobject*>(stack_args + (cur_arg * kPointerSize)) = jobj;
     }
-    if (num_args > 2) {
-      if (proxy_method->IsParamAReference(2)) {
-        Object* obj = *reinterpret_cast<Object**>(stack_args + kPointerSize);  // reference from r2
-        jobject jobj = AddLocalReference<jobject>(env, obj);
-        *reinterpret_cast<jobject*>(stack_args + kPointerSize) = jobj;
-      }
-      // Possible out arguments are 7 words above the stack args:
-      // r2, r3, LR, Method*, r1 (spill), r2 (spill), r3 (spill)
-      size_t offset = 7 * kPointerSize;
-      for (size_t i = 3; i < num_args; i++) {
-        if (proxy_method->IsParamAReference(i)) {
-          // reference from caller's stack arguments
-          Object* obj = *reinterpret_cast<Object**>(stack_args + offset);
-          jobject jobj = AddLocalReference<jobject>(env, obj);
-          *reinterpret_cast<jobject*>(stack_args + offset) = jobj;
-        } else if (proxy_method->IsParamALongOrDouble(i)) {
-          offset += kPointerSize;
-        }
-        offset += kPointerSize;
-      }
+    cur_arg = cur_arg + (proxy_method->IsParamALongOrDouble(param_index) ? 2 : 1);
+    param_index++;
+  }
+  // Placing into local references incoming arguments from the caller's stack arguments
+  cur_arg += 5;  // skip LR, Method* and spills for R1 to R3
+  while (param_index < num_params) {
+    if (proxy_method->IsParamAReference(param_index)) {
+      Object* obj = *reinterpret_cast<Object**>(stack_args + (cur_arg * kPointerSize));
+      jobject jobj = AddLocalReference<jobject>(env, obj);
+      *reinterpret_cast<jobject*>(stack_args + (cur_arg * kPointerSize)) = jobj;
     }
+    cur_arg = cur_arg + (proxy_method->IsParamALongOrDouble(param_index) ? 2 : 1);
+    param_index++;
   }
   // Create args array
   ObjectArray<Object>* args =
-      Runtime::Current()->GetClassLinker()->AllocObjectArray<Object>(num_args - 1);
+      Runtime::Current()->GetClassLinker()->AllocObjectArray<Object>(num_params - 1);
   if(args == NULL) {
     CHECK(self->IsExceptionPending());
     return;
@@ -848,58 +868,54 @@
   args_jobj[1].l = proxy_method_jobj;
   args_jobj[2].l = AddLocalReference<jobjectArray>(env, args);
   // Box arguments
+  cur_arg = 0;  // reset 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_method->GetJavaParameterTypes();
-  if (num_args > 1) {
-    CHECK(param_types != NULL);
+  CHECK(param_types != NULL);
+  // Check number of parameter types agrees with number from the Method - less 1 for the receiver.
+  CHECK_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;
-    // Argument from r2
-    Class* param_type = param_types->Get(0);
     if (!param_type->IsPrimitive()) {
-      obj = self->DecodeJObject(*reinterpret_cast<jobject*>(stack_args));
+      obj = self->DecodeJObject(*reinterpret_cast<jobject*>(stack_args + (cur_arg * kPointerSize)));
     } else {
-      JValue val = *reinterpret_cast<JValue*>(stack_args);
+      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
+        // (7 = 2 reg args + LR + Method* + 3 arg reg spill slots)
+        uint64_t high_half = *reinterpret_cast<uint32_t*>(stack_args + (7 * kPointerSize));
+        val.j = (val.j & 0xFFFFFFFFull) | (high_half << 32);
+      }
       BoxPrimitive(env, param_type, val);
       if (self->IsExceptionPending()) {
         return;
       }
       obj = val.l;
     }
-    args->Set(0, obj);
-    if (num_args > 2) {
-      // Argument from r3
-      param_type = param_types->Get(1);
-      if (!param_type->IsPrimitive()) {
-        obj = self->DecodeJObject(*reinterpret_cast<jobject*>(stack_args + kPointerSize));
-      } else {
-        JValue val = *reinterpret_cast<JValue*>(stack_args + kPointerSize);
-        BoxPrimitive(env, param_type, val);
-        if (self->IsExceptionPending()) {
-          return;
-        }
-        obj = val.l;
+    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 += 5;  // skip LR, Method* and spills for R1 to R3
+  while (param_index < num_params) {
+    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(env, param_type, val);
+      if (self->IsExceptionPending()) {
+        return;
       }
-      args->Set(1, obj);
-      // Arguments are on the stack, again offset to out arguments is 7 words
-      size_t offset = 7 * kPointerSize;
-      for (size_t i = 3; i < num_args && !self->IsExceptionPending(); i++) {
-        param_type = param_types->Get(i - 1);
-        if (proxy_method->IsParamAReference(i)) {
-          obj = self->DecodeJObject(*reinterpret_cast<jobject*>(stack_args + offset));
-        } else {
-          JValue val = *reinterpret_cast<JValue*>(stack_args + offset);
-          BoxPrimitive(env, param_type, val);
-          if (self->IsExceptionPending()) {
-            return;
-          }
-          obj = val.l;
-          if (proxy_method->IsParamALongOrDouble(i)) {
-            offset += kPointerSize;
-          }
-        }
-        args->Set(i - 1, obj);
-        offset += kPointerSize;
-      }
+      obj = val.l;
     }
+    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
   static jmethodID inv_hand_invoke_mid = NULL;