Fix JNI compiler frame size adjustments.

Bug: 16321952
Change-Id: I6f84a59c679e335e02a8e70944a5d0bc8d73f90b
diff --git a/compiler/jni/jni_compiler_test.cc b/compiler/jni/jni_compiler_test.cc
index b4d863b..995ea46 100644
--- a/compiler/jni/jni_compiler_test.cc
+++ b/compiler/jni/jni_compiler_test.cc
@@ -720,10 +720,33 @@
   EXPECT_EQ(result, 42);
 }
 
+int gJava_MyClassNatives_GetSinkProperties_calls = 0;
+jarray Java_MyClassNatives_GetSinkProperties(JNIEnv* env, jobject thisObj, jstring s) {
+  // 1 = thisObj
+  Thread* self = Thread::Current();
+  EXPECT_EQ(kNative, self->GetState());
+  Locks::mutator_lock_->AssertNotHeld(self);
+  EXPECT_EQ(self->GetJniEnv(), env);
+  EXPECT_TRUE(thisObj != nullptr);
+  EXPECT_TRUE(env->IsInstanceOf(thisObj, JniCompilerTest::jklass_));
+  EXPECT_EQ(s, nullptr);
+  gJava_MyClassNatives_GetSinkProperties_calls++;
+  ScopedObjectAccess soa(self);
+  EXPECT_EQ(2U, self->NumStackReferences());
+  EXPECT_TRUE(self->HoldsLock(soa.Decode<mirror::Object*>(thisObj)));
+  return nullptr;
+}
+
 TEST_F(JniCompilerTest, GetSinkPropertiesNative) {
   TEST_DISABLED_FOR_PORTABLE();
-  SetUpForTest(false, "getSinkPropertiesNative", "(Ljava/lang/String;)[Ljava/lang/Object;", nullptr);
-  // This space intentionally left blank. Just testing compilation succeeds.
+  SetUpForTest(false, "getSinkPropertiesNative", "(Ljava/lang/String;)[Ljava/lang/Object;",
+               reinterpret_cast<void*>(&Java_MyClassNatives_GetSinkProperties));
+
+  EXPECT_EQ(0, gJava_MyClassNatives_GetSinkProperties_calls);
+  jarray result = down_cast<jarray>(
+      env_->CallNonvirtualObjectMethod(jobj_, jklass_, jmethod_, nullptr));
+  EXPECT_EQ(nullptr, result);
+  EXPECT_EQ(1, gJava_MyClassNatives_GetSinkProperties_calls);
 }
 
 // This should return jclass, but we're imitating a bug pattern.
diff --git a/compiler/jni/quick/jni_compiler.cc b/compiler/jni/quick/jni_compiler.cc
index dec84f1..c38cfaf 100644
--- a/compiler/jni/quick/jni_compiler.cc
+++ b/compiler/jni/quick/jni_compiler.cc
@@ -183,9 +183,8 @@
 
   // 5. Move frame down to allow space for out going args.
   const size_t main_out_arg_size = main_jni_conv->OutArgSize();
-  const size_t end_out_arg_size = end_jni_conv->OutArgSize();
-  const size_t max_out_arg_size = std::max(main_out_arg_size, end_out_arg_size);
-  __ IncreaseFrameSize(max_out_arg_size);
+  size_t current_out_arg_size = main_out_arg_size;
+  __ IncreaseFrameSize(main_out_arg_size);
 
   // 6. Call into appropriate JniMethodStart passing Thread* so that transition out of Runnable
   //    can occur. The result is the saved JNI local state that is restored by the exit call. We
@@ -244,7 +243,7 @@
   //    NULL (which must be encoded as NULL).
   //    Note: 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+main_out_arg_size));
+  mr_conv->ResetIterator(FrameOffset(frame_size + main_out_arg_size));
   uint32_t args_count = 0;
   while (mr_conv->HasNext()) {
     args_count++;
@@ -270,7 +269,7 @@
   }
   if (is_static) {
     // Create argument for Class
-    mr_conv->ResetIterator(FrameOffset(frame_size+main_out_arg_size));
+    mr_conv->ResetIterator(FrameOffset(frame_size + main_out_arg_size));
     main_jni_conv->ResetIterator(FrameOffset(main_out_arg_size));
     main_jni_conv->Next();  // Skip JNIEnv*
     FrameOffset handle_scope_offset = main_jni_conv->CurrentParamHandleScopeEntryOffset();
@@ -333,10 +332,21 @@
       // Ensure doubles are 8-byte aligned for MIPS
       return_save_location = FrameOffset(return_save_location.Uint32Value() + kMipsPointerSize);
     }
-    CHECK_LT(return_save_location.Uint32Value(), frame_size+main_out_arg_size);
+    CHECK_LT(return_save_location.Uint32Value(), frame_size + main_out_arg_size);
     __ Store(return_save_location, main_jni_conv->ReturnRegister(), main_jni_conv->SizeOfReturnValue());
   }
 
+  // Increase frame size for out args if needed by the end_jni_conv.
+  const size_t end_out_arg_size = end_jni_conv->OutArgSize();
+  if (end_out_arg_size > current_out_arg_size) {
+    size_t out_arg_size_diff = end_out_arg_size - current_out_arg_size;
+    current_out_arg_size = end_out_arg_size;
+    __ IncreaseFrameSize(out_arg_size_diff);
+    saved_cookie_offset = FrameOffset(saved_cookie_offset.SizeValue() + out_arg_size_diff);
+    locked_object_handle_scope_offset =
+        FrameOffset(locked_object_handle_scope_offset.SizeValue() + out_arg_size_diff);
+    return_save_location = FrameOffset(return_save_location.SizeValue() + out_arg_size_diff);
+  }
   //     thread.
   end_jni_conv->ResetIterator(FrameOffset(end_out_arg_size));
   ThreadOffset<4> jni_end32(-1);
@@ -403,7 +413,7 @@
   }
 
   // 14. Move frame up now we're done with the out arg space.
-  __ DecreaseFrameSize(max_out_arg_size);
+  __ DecreaseFrameSize(current_out_arg_size);
 
   // 15. Process pending exceptions from JNI call or monitor exit.
   __ ExceptionPoll(main_jni_conv->InterproceduralScratchRegister(), 0);