[MIPS64] JNI Compiler: Sign-extend int function arguments

MIPS n64 ABI differs from arm64. Arguments smaller than the 8B stack
slot need to be sign-extended.

Use combination (lw,sd), instead of (lw,sw) for 4B values.

Change fixes software keyboard crash on mips64.

Bug: 21555893

(cherry picked from commit f652d605753f1387e7797461b47116c5dcdf928d)

Change-Id: I7574d37f6039e9e8c9e0047254be71d28d4c829a
diff --git a/compiler/jni/jni_compiler_test.cc b/compiler/jni/jni_compiler_test.cc
index e98e572..f3bda2f 100644
--- a/compiler/jni/jni_compiler_test.cc
+++ b/compiler/jni/jni_compiler_test.cc
@@ -165,6 +165,7 @@
   void StackArgsIntsFirstImpl();
   void StackArgsFloatsFirstImpl();
   void StackArgsMixedImpl();
+  void StackArgsSignExtendedMips64Impl();
 
   JNIEnv* env_;
   jmethodID jmethod_;
@@ -1715,4 +1716,49 @@
 
 JNI_TEST(StackArgsMixed)
 
+void Java_MyClassNatives_stackArgsSignExtendedMips64(JNIEnv*, jclass, jint i1, jint i2, jint i3,
+                                                     jint i4, jint i5, jint i6, jint i7, jint i8) {
+  EXPECT_EQ(i1, 1);
+  EXPECT_EQ(i2, 2);
+  EXPECT_EQ(i3, 3);
+  EXPECT_EQ(i4, 4);
+  EXPECT_EQ(i5, 5);
+  EXPECT_EQ(i6, 6);
+  EXPECT_EQ(i7, 7);
+  EXPECT_EQ(i8, -8);
+
+#if defined(__mips__) && defined(__LP64__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
+  // Mips64 ABI requires that arguments passed through stack be sign-extended 8B slots.
+  // First 8 arguments are passed through registers, check i7 and i8.
+  uint32_t stack1_high = *(&i7 + 1);
+  uint32_t stack2_high = *(&i8 + 1);
+
+  EXPECT_EQ(stack1_high, static_cast<uint32_t>(0));
+  EXPECT_EQ(stack2_high, static_cast<uint32_t>(0xffffffff));
+#else
+  LOG(INFO) << "Skipping stackArgsSignExtendedMips64 as there is nothing to be done on "
+            << kRuntimeISA;
+  // Force-print to std::cout so it's also outside the logcat.
+  std::cout << "Skipping stackArgsSignExtendedMips64 as there is nothing to be done on "
+            << kRuntimeISA << std::endl;
+#endif
+}
+
+void JniCompilerTest::StackArgsSignExtendedMips64Impl() {
+  SetUpForTest(true, "stackArgsSignExtendedMips64", "(IIIIIIII)V",
+               reinterpret_cast<void*>(&Java_MyClassNatives_stackArgsSignExtendedMips64));
+  jint i1 = 1;
+  jint i2 = 2;
+  jint i3 = 3;
+  jint i4 = 4;
+  jint i5 = 5;
+  jint i6 = 6;
+  jint i7 = 7;
+  jint i8 = -8;
+
+  env_->CallStaticVoidMethod(jklass_, jmethod_, i1, i2, i3, i4, i5, i6, i7, i8);
+}
+
+JNI_TEST(StackArgsSignExtendedMips64)
+
 }  // namespace art
diff --git a/compiler/utils/mips64/assembler_mips64.cc b/compiler/utils/mips64/assembler_mips64.cc
index a8b55d1..5e49b93 100644
--- a/compiler/utils/mips64/assembler_mips64.cc
+++ b/compiler/utils/mips64/assembler_mips64.cc
@@ -839,7 +839,7 @@
   CHECK(size == 4 || size == 8) << size;
   if (size == 4) {
     LoadFromOffset(kLoadWord, scratch.AsGpuRegister(), SP, src.Int32Value());
-    StoreToOffset(kStoreWord, scratch.AsGpuRegister(), SP, dest.Int32Value());
+    StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value());
   } else if (size == 8) {
     LoadFromOffset(kLoadDoubleword, scratch.AsGpuRegister(), SP, src.Int32Value());
     StoreToOffset(kStoreDoubleword, scratch.AsGpuRegister(), SP, dest.Int32Value());
@@ -855,7 +855,7 @@
   if (size == 4) {
     LoadFromOffset(kLoadWord, scratch, src_base.AsMips64().AsGpuRegister(),
                    src_offset.Int32Value());
-    StoreToOffset(kStoreWord, scratch, SP, dest.Int32Value());
+    StoreToOffset(kStoreDoubleword, scratch, SP, dest.Int32Value());
   } else if (size == 8) {
     LoadFromOffset(kLoadDoubleword, scratch, src_base.AsMips64().AsGpuRegister(),
                    src_offset.Int32Value());
@@ -871,7 +871,7 @@
   CHECK(size == 4 || size == 8) << size;
   if (size == 4) {
     LoadFromOffset(kLoadWord, scratch, SP, src.Int32Value());
-    StoreToOffset(kStoreWord, scratch, dest_base.AsMips64().AsGpuRegister(),
+    StoreToOffset(kStoreDoubleword, scratch, dest_base.AsMips64().AsGpuRegister(),
                   dest_offset.Int32Value());
   } else if (size == 8) {
     LoadFromOffset(kLoadDoubleword, scratch, SP, src.Int32Value());
@@ -894,7 +894,7 @@
   CHECK(size == 4 || size == 8) << size;
   if (size == 4) {
     LoadFromOffset(kLoadWord, scratch, src.AsMips64().AsGpuRegister(), src_offset.Int32Value());
-    StoreToOffset(kStoreWord, scratch, dest.AsMips64().AsGpuRegister(), dest_offset.Int32Value());
+    StoreToOffset(kStoreDoubleword, scratch, dest.AsMips64().AsGpuRegister(), dest_offset.Int32Value());
   } else if (size == 8) {
     LoadFromOffset(kLoadDoubleword, scratch, src.AsMips64().AsGpuRegister(),
                    src_offset.Int32Value());
diff --git a/test/MyClassNatives/MyClassNatives.java b/test/MyClassNatives/MyClassNatives.java
index 8b4a9a4..19c13f7 100644
--- a/test/MyClassNatives/MyClassNatives.java
+++ b/test/MyClassNatives/MyClassNatives.java
@@ -94,6 +94,9 @@
         float f4, int i5, float f5, int i6, float f6, int i7, float f7, int i8, float f8, int i9,
         float f9, int i10, float f10);
 
+    native static void stackArgsSignExtendedMips64(int i1, int i2, int i3, int i4, int i5, int i6,
+        int i7, int i8);
+
     static native double logD(double d);
     static native float logF(float f);
     static native boolean returnTrue();