Fix various JNI compiler bugs/unimplementeds.

For both x86 and arm we were under computing the outgoing argument size.
For ARM the managed double/long passing had been assumed to be following AAPCS,
however, currently we split long/doubles across R1_R2 and R3 and the stack.
Add support for this in the managed register and jni compiler code.
Add test and various other clean ups to jni compiler code.

Change-Id: I4129076d052a8bce42304f5331b71aa3ac50210f
diff --git a/src/calling_convention_arm.cc b/src/calling_convention_arm.cc
index 78f0c6c..527ce5f 100644
--- a/src/calling_convention_arm.cc
+++ b/src/calling_convention_arm.cc
@@ -39,20 +39,25 @@
 }
 
 bool ManagedRuntimeCallingConvention::IsCurrentParamOnStack() {
-  return !IsCurrentParamInRegister();
+  if (itr_slots_ < 2) {
+    return false;
+  } else if (itr_slots_ > 2) {
+    return true;
+  } else {
+    // handle funny case of a long/double straddling registers and the stack
+    return GetMethod()->IsParamALongOrDouble(itr_args_);
+  }
 }
 
 static const Register kManagedArgumentRegisters[] = {
   R1, R2, R3
 };
 ManagedRegister ManagedRuntimeCallingConvention::CurrentParamRegister() {
-  CHECK_LT(itr_slots_, 3u); // Otherwise, should have gone through stack
+  CHECK(IsCurrentParamInRegister());
   const Method* method = GetMethod();
   if (method->IsParamALongOrDouble(itr_args_)) {
     if (itr_slots_ == 0) {
-      // return R1 to denote R1_R2
-      return ManagedRegister::FromCoreRegister(kManagedArgumentRegisters
-                                               [itr_slots_]);
+      return ManagedRegister::FromRegisterPair(R1_R2);
     } else if (itr_slots_ == 1) {
       return ManagedRegister::FromRegisterPair(R2_R3);
     } else {
@@ -67,10 +72,18 @@
 }
 
 FrameOffset ManagedRuntimeCallingConvention::CurrentParamStackOffset() {
-  CHECK_GE(itr_slots_, 3u);
-  return FrameOffset(displacement_.Int32Value() +   // displacement
-                     kPointerSize +                 // Method*
-                     (itr_slots_ * kPointerSize));  // offset into in args
+  CHECK(IsCurrentParamOnStack());
+  FrameOffset result =
+      FrameOffset(displacement_.Int32Value() +   // displacement
+                  kPointerSize +                 // Method*
+                  (itr_slots_ * kPointerSize));  // offset into in args
+  if (itr_slots_ == 2) {
+    // the odd spanning case, bump the offset to skip the first half of the
+    // input which is in a register
+    CHECK(IsCurrentParamInRegister());
+    result = FrameOffset(result.Int32Value() + 4);
+  }
+  return result;
 }
 
 // JNI calling convention
@@ -85,6 +98,20 @@
                  kStackAlignment);
 }
 
+size_t JniCallingConvention::OutArgSize() {
+  const Method* method = GetMethod();
+  size_t padding;  // padding to ensure longs and doubles are not split in AAPCS
+  if (method->IsStatic()) {
+    padding = (method->NumArgs() > 1) && !method->IsParamALongOrDouble(0) &&
+              method->IsParamALongOrDouble(1) ? 4 : 0;
+  } else {
+    padding = (method->NumArgs() > 2) && !method->IsParamALongOrDouble(1) &&
+              method->IsParamALongOrDouble(2) ? 4 : 0;
+  }
+  return RoundUp(NumberOfOutgoingStackArgs() * kPointerSize + padding,
+                 kStackAlignment);
+}
+
 size_t JniCallingConvention::ReturnPcOffset() {
   // Link register is always the last value spilled, skip forward one word for
   // the Method* then skip back one word to get the link register (ie +0)
@@ -160,7 +187,13 @@
 }
 
 size_t JniCallingConvention::NumberOfOutgoingStackArgs() {
-  return GetMethod()->NumArgs() + GetMethod()->NumLongOrDoubleArgs() - 2;
+  const Method* method = GetMethod();
+  size_t static_args = method->IsStatic() ? 1 : 0;  // count jclass
+  // regular argument parameters and this
+  size_t param_args = method->NumArgs() +
+                      method->NumLongOrDoubleArgs();
+  // count JNIEnv* less arguments in registers
+  return static_args + param_args + 1 - 4;
 }
 
 }  // namespace art