Merge "Fix bug in JNI compiler AAPCS padding calculation" into dalvik-dev
diff --git a/src/calling_convention_arm.cc b/src/calling_convention_arm.cc
index 1a5b92f..0ada85a 100644
--- a/src/calling_convention_arm.cc
+++ b/src/calling_convention_arm.cc
@@ -115,15 +115,18 @@
 ArmJniCallingConvention::ArmJniCallingConvention(bool is_static, bool is_synchronized,
                                                  const char* shorty)
     : JniCallingConvention(is_static, is_synchronized, shorty) {
-  // Compute padding to ensure longs and doubles are not split in AAPCS
-  // TODO: in terms of outgoing argument size this may be overly generous
-  // due to padding appearing in the registers
+  // Compute padding to ensure longs and doubles are not split in AAPCS. Ignore the 'this' jobject
+  // or jclass for static methods and the JNIEnv. We start at the aligned register r2.
   size_t padding = 0;
-  size_t check = IsStatic() ? 1 : 0;
-  for (size_t i = 0; i < NumArgs(); i++) {
-    if (((i & 1) == check) && IsParamALongOrDouble(i)) {
-      padding += 4;
+  for (size_t cur_arg = IsStatic() ? 0 : 1, cur_reg = 2; cur_arg < NumArgs(); cur_arg++) {
+    if (IsParamALongOrDouble(cur_arg)) {
+      if ((cur_reg & 1) != 0) {
+        padding += 4;
+        cur_reg++;  // additional bump to ensure alignment
+      }
+      cur_reg++;  // additional bump to skip extra long word
     }
+    cur_reg++;  // bump the iterator for every argument
   }
   padding_ = padding;
 
@@ -205,8 +208,9 @@
 
 FrameOffset ArmJniCallingConvention::CurrentParamStackOffset() {
   CHECK_GE(itr_slots_, 4u);
-  return FrameOffset(displacement_.Int32Value() - OutArgSize()
-                     + ((itr_slots_ - 4) * kPointerSize));
+  size_t offset = displacement_.Int32Value() - OutArgSize() + ((itr_slots_ - 4) * kPointerSize);
+  CHECK_LT(offset, OutArgSize());
+  return FrameOffset(offset);
 }
 
 size_t ArmJniCallingConvention::NumberOfOutgoingStackArgs() {
diff --git a/src/jni_compiler_test.cc b/src/jni_compiler_test.cc
index 2166d37..fd7574d 100644
--- a/src/jni_compiler_test.cc
+++ b/src/jni_compiler_test.cc
@@ -622,4 +622,22 @@
   EXPECT_EQ(result, JNI_TRUE);
 }
 
+jint my_gettext(JNIEnv* env, jclass klass, jlong val1, jobject obj1, jlong val2, jobject obj2) {
+  EXPECT_TRUE(env->IsInstanceOf(JniCompilerTest::jobj_, klass));
+  EXPECT_TRUE(env->IsSameObject(JniCompilerTest::jobj_, obj1));
+  EXPECT_TRUE(env->IsSameObject(JniCompilerTest::jobj_, obj2));
+  EXPECT_EQ(0x12345678ABCDEF88ll, val1);
+  EXPECT_EQ(0x7FEDCBA987654321ll, val2);
+  return 42;
+}
+
+TEST_F(JniCompilerTest, GetText) {
+  SirtRef<ClassLoader> class_loader(LoadDex("MyClassNatives"));
+  SetupForTest(class_loader.get(), true, "getText", "(JLjava/lang/Object;JLjava/lang/Object;)I",
+               reinterpret_cast<void*>(&my_gettext));
+  jint result = env_->CallStaticIntMethod(jklass_, jmethod_, 0x12345678ABCDEF88ll, jobj_,
+                                          0x7FEDCBA987654321ll, jobj_);
+  EXPECT_EQ(result, 42);
+}
+
 }  // namespace art
diff --git a/test/MyClassNatives/MyClassNatives.java b/test/MyClassNatives/MyClassNatives.java
index 55ec0bd..4987373 100644
--- a/test/MyClassNatives/MyClassNatives.java
+++ b/test/MyClassNatives/MyClassNatives.java
@@ -31,4 +31,5 @@
     static synchronized native Object fooSSIOO(int x, Object y, Object z);
     static native void arraycopy(Object src, int src_pos, Object dst, int dst_pos, int length);
     native boolean compareAndSwapInt(Object obj, long offset, int expected, int newval);
+    static native int getText(long val1, Object obj1, long val2, Object obj2);
 }