Fix the "mov R1, R2; mov R2, R3" bug in jni_compiler.

Should be "mov R2, R3; mov R1, R2" instead.

Change-Id: Ie5264c3fe38486781e09f54e1e6d1fdcf7a2d4e5
diff --git a/src/jni_compiler.cc b/src/jni_compiler.cc
index 79c6714..adc87da 100644
--- a/src/jni_compiler.cc
+++ b/src/jni_compiler.cc
@@ -155,17 +155,29 @@
   //    NB. we do this prior to materializing the JNIEnv* and static's jclass to
   //    give as many free registers for the shuffle as possible
   mr_conv.ResetIterator(FrameOffset(frame_size+out_arg_size));
-  jni_conv.ResetIterator(FrameOffset(out_arg_size));
-  jni_conv.Next();  // Skip JNIEnv*
-  if (is_static) {
-    jni_conv.Next();  // Skip Class for now
-  }
+  uint32_t args_count = 0;
   while (mr_conv.HasNext()) {
-    CHECK(jni_conv.HasNext());
-    CopyParameter(jni_asm, &mr_conv, &jni_conv, frame_size, out_arg_size);
+    args_count++;
     mr_conv.Next();
-    jni_conv.Next();
   }
+
+  // Do a backward pass over arguments, so that the generated code will be "mov
+  // R2, R3; mov R1, R2" instead of "mov R1, R2; mov R2, R3."
+  // TODO: A reverse iterator to improve readability.
+  for (uint32_t i = 0; i < args_count; ++i) {
+    mr_conv.ResetIterator(FrameOffset(frame_size+out_arg_size));
+    jni_conv.ResetIterator(FrameOffset(out_arg_size));
+    jni_conv.Next();  // Skip JNIEnv*
+    if (is_static) {
+      jni_conv.Next();  // Skip Class for now
+    }
+    for (uint32_t j = 0; j < args_count - i - 1; ++j) {
+      mr_conv.Next();
+      jni_conv.Next();
+    }
+    CopyParameter(jni_asm, &mr_conv, &jni_conv, frame_size, out_arg_size);
+  }
+
   if (is_static) {
     // Create argument for Class
     mr_conv.ResetIterator(FrameOffset(frame_size+out_arg_size));
diff --git a/src/jni_compiler_test.cc b/src/jni_compiler_test.cc
index 296d647..3ffc184 100644
--- a/src/jni_compiler_test.cc
+++ b/src/jni_compiler_test.cc
@@ -223,6 +223,29 @@
   EXPECT_EQ(7, gJava_MyClass_fooIOO_calls);
 }
 
+int gJava_MyClass_fooSII_calls = 0;
+jint Java_MyClass_fooSII(JNIEnv* env, jclass klass, jint x, jint y) {
+  EXPECT_EQ(1u, Thread::Current()->NumSirtReferences());
+  EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
+  EXPECT_EQ(Thread::Current()->GetJniEnv(), env);
+  EXPECT_TRUE(klass != NULL);
+  EXPECT_TRUE(env->IsInstanceOf(JniCompilerTest::jobj_, klass));
+  gJava_MyClass_fooSII_calls++;
+  return x + y;
+}
+
+
+TEST_F(JniCompilerTest, CompileAndRunStaticIntIntMethod) {
+  SetupForTest(true, "fooSII",
+               "(II)I",
+               reinterpret_cast<void*>(&Java_MyClass_fooSII));
+
+  EXPECT_EQ(0, gJava_MyClass_fooSII_calls);
+  jint result = env_->CallStaticIntMethod(jklass_, jmethod_, 20, 30);
+  EXPECT_EQ(50, result);
+  EXPECT_EQ(1, gJava_MyClass_fooSII_calls);
+}
+
 int gJava_MyClass_fooSIOO_calls = 0;
 jobject Java_MyClass_fooSIOO(JNIEnv* env, jclass klass, jint x, jobject y,
                              jobject z) {
diff --git a/test/MyClassNatives/MyClassNatives.java b/test/MyClassNatives/MyClassNatives.java
index f462363..0716bfa 100644
--- a/test/MyClassNatives/MyClassNatives.java
+++ b/test/MyClassNatives/MyClassNatives.java
@@ -8,5 +8,6 @@
     native double fooDD(double x, double y);
     native Object fooIOO(int x, Object y, Object z);
     static native Object fooSIOO(int x, Object y, Object z);
+    static native int fooSII(int x, int y);
     static synchronized native Object fooSSIOO(int x, Object y, Object z);
 }