Fix bug in long arguments for JNI on x86

Also add new unit test.
Change-Id: I226501dbfec6e207318d8063b5daf53b7b606ee4
diff --git a/src/assembler_x86.cc b/src/assembler_x86.cc
index 59fd33e..6334bd9 100644
--- a/src/assembler_x86.cc
+++ b/src/assembler_x86.cc
@@ -1410,6 +1410,11 @@
   } else if (src.IsCpuRegister()) {
     CHECK_EQ(4u, size);
     movl(Address(ESP, offs), src.AsCpuRegister());
+  } else if (src.IsRegisterPair()) {
+    CHECK_EQ(8u, size);
+    movl(Address(ESP, offs), src.AsRegisterPairLow());
+    movl(Address(ESP, FrameOffset(offs.Int32Value()+4)),
+         src.AsRegisterPairHigh());
   } else if (src.IsX87Register()) {
     if (size == 4) {
       fstps(Address(ESP, offs));
@@ -1459,6 +1464,10 @@
   } else if (dest.IsCpuRegister()) {
     CHECK_EQ(4u, size);
     movl(dest.AsCpuRegister(), Address(ESP, src));
+  } else if (dest.IsRegisterPair()) {
+    CHECK_EQ(8u, size);
+    movl(dest.AsRegisterPairLow(), Address(ESP, src));
+    movl(dest.AsRegisterPairHigh(), Address(ESP, FrameOffset(src.Int32Value()+4)));
   } else if (dest.IsX87Register()) {
     if (size == 4) {
       flds(Address(ESP, src));
diff --git a/src/jni_compiler_test.cc b/src/jni_compiler_test.cc
index 933970b..19f695d 100644
--- a/src/jni_compiler_test.cc
+++ b/src/jni_compiler_test.cc
@@ -143,6 +143,32 @@
   EXPECT_EQ(2, gJava_MyClass_fooII_calls);
 }
 
+int gJava_MyClass_fooJJ_calls = 0;
+jlong Java_MyClass_fooJJ(JNIEnv* env, jobject thisObj, jlong x, jlong y) {
+  EXPECT_EQ(1u, Thread::Current()->NumSirtReferences());
+  EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
+  EXPECT_EQ(Thread::Current()->GetJniEnv(), env);
+  EXPECT_TRUE(thisObj != NULL);
+  EXPECT_TRUE(env->IsInstanceOf(thisObj, JniCompilerTest::jklass_));
+  gJava_MyClass_fooJJ_calls++;
+  return x - y;  // non-commutative operator
+}
+
+TEST_F(JniCompilerTest, CompileAndRunLongLongMethod) {
+  SetupForTest(false, "fooJJ", "(JJ)J",
+               reinterpret_cast<void*>(&Java_MyClass_fooJJ));
+
+  EXPECT_EQ(0, gJava_MyClass_fooJJ_calls);
+  jlong a = 0x1234567890ABCDEFll;
+  jlong b = 0xFEDCBA0987654321ll;
+  jlong result = env_->CallNonvirtualLongMethod(jobj_, jklass_, jmethod_, a, b);
+  EXPECT_EQ(a - b, result);
+  EXPECT_EQ(1, gJava_MyClass_fooJJ_calls);
+  result = env_->CallNonvirtualLongMethod(jobj_, jklass_, jmethod_, b, a);
+  EXPECT_EQ(b - a, result);
+  EXPECT_EQ(2, gJava_MyClass_fooJJ_calls);
+}
+
 int gJava_MyClass_fooDD_calls = 0;
 jdouble Java_MyClass_fooDD(JNIEnv* env, jobject thisObj, jdouble x, jdouble y) {
   EXPECT_EQ(1u, Thread::Current()->NumSirtReferences());
@@ -444,13 +470,13 @@
   EXPECT_EQ(55, result);
 }
 
-jobject Java_MyClass_fooL(JNIEnv* env, jobject thisObj, jobject x) {
+jobject Java_MyClass_fooO(JNIEnv* env, jobject thisObj, jobject x) {
   return env->NewGlobalRef(x);
 }
 
 TEST_F(JniCompilerTest, DecodeJObject) {
-  SetupForTest(false, "fooL", "(Ljava/lang/Object;)Ljava/lang/Object;",
-               reinterpret_cast<void*>(&Java_MyClass_fooL));
+  SetupForTest(false, "fooO", "(Ljava/lang/Object;)Ljava/lang/Object;",
+               reinterpret_cast<void*>(&Java_MyClass_fooO));
   jobject result = env_->CallNonvirtualObjectMethod(jobj_, jklass_, jmethod_, jobj_);
   EXPECT_EQ(JNILocalRefType, env_->GetObjectRefType(result));
   EXPECT_TRUE(env_->IsSameObject(result, jobj_));
diff --git a/test/MyClassNatives/MyClassNatives.java b/test/MyClassNatives/MyClassNatives.java
index f8b81d4..e296684 100644
--- a/test/MyClassNatives/MyClassNatives.java
+++ b/test/MyClassNatives/MyClassNatives.java
@@ -5,7 +5,8 @@
     native void foo();
     native int fooI(int x);
     native int fooII(int x, int y);
-    native Object fooL(Object x);
+    native long fooJJ(long x, long y);
+    native Object fooO(Object x);
     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);