x86: Fix CriticalNative argument spilling in JNI stubs.

Do not move incoming stack arguments before we have spilled
the scratch register ECX.

Fix JniCompilerTest to initialize classes early so that we
really test what we were supposed to. This exposed the x86
bug fixed here.

Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Bug: 172332525
Change-Id: I7c06c8ccf18f5f66772c70f6a9a9a314668ce70d
diff --git a/compiler/jni/jni_compiler_test.cc b/compiler/jni/jni_compiler_test.cc
index 4d40418..3ee7e0e 100644
--- a/compiler/jni/jni_compiler_test.cc
+++ b/compiler/jni/jni_compiler_test.cc
@@ -246,15 +246,23 @@
                       const char* method_name,
                       const char* method_sig) {
     ScopedObjectAccess soa(Thread::Current());
-    StackHandleScope<1> hs(soa.Self());
+    StackHandleScope<2> hs(soa.Self());
     Handle<mirror::ClassLoader> loader(
         hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader)));
     // Compile the native method before starting the runtime
-    ObjPtr<mirror::Class> c = class_linker_->FindClass(soa.Self(), "LMyClassNatives;", loader);
+    Handle<mirror::Class> c =
+        hs.NewHandle(class_linker_->FindClass(soa.Self(), "LMyClassNatives;", loader));
     const auto pointer_size = class_linker_->GetImagePointerSize();
     ArtMethod* method = c->FindClassMethod(method_name, method_sig, pointer_size);
     ASSERT_TRUE(method != nullptr) << method_name << " " << method_sig;
     ASSERT_EQ(direct, method->IsDirect()) << method_name << " " << method_sig;
+    if (direct) {
+      // Class initialization could replace the entrypoint, so force
+      // the initialization before we set up the entrypoint below.
+      class_linker_->EnsureInitialized(
+          soa.Self(), c, /*can_init_fields=*/ true, /*can_init_parents=*/ true);
+      class_linker_->MakeInitializedClassesVisiblyInitialized(soa.Self(), /*wait=*/ true);
+    }
     if (check_generic_jni_) {
       method->SetEntryPointFromQuickCompiledCode(class_linker_->GetRuntimeQuickGenericJniStub());
     } else {
diff --git a/compiler/utils/x86/jni_macro_assembler_x86.cc b/compiler/utils/x86/jni_macro_assembler_x86.cc
index 67ec93d..2c7902b 100644
--- a/compiler/utils/x86/jni_macro_assembler_x86.cc
+++ b/compiler/utils/x86/jni_macro_assembler_x86.cc
@@ -308,18 +308,28 @@
     const ArgumentLocation& src = srcs[i];
     const ArgumentLocation& dest = dests[i];
     DCHECK_EQ(src.GetSize(), dest.GetSize());
-    if (UNLIKELY(dest.IsRegister())) {
-      // Native ABI has only stack arguments but we may pass one "hidden arg" in register.
-      CHECK(!found_hidden_arg);
-      found_hidden_arg = true;
-      CHECK(src.IsRegister());
-      Move(dest.GetRegister(), src.GetRegister(), dest.GetSize());
-    } else {
-      if (src.IsRegister()) {
-        Store(dest.GetFrameOffset(), src.GetRegister(), dest.GetSize());
+    if (src.IsRegister()) {
+      if (UNLIKELY(dest.IsRegister())) {
+        // Native ABI has only stack arguments but we may pass one "hidden arg" in register.
+        CHECK(!found_hidden_arg);
+        found_hidden_arg = true;
+        DCHECK(
+            !dest.GetRegister().Equals(X86ManagedRegister::FromCpuRegister(GetScratchRegister())));
+        Move(dest.GetRegister(), src.GetRegister(), dest.GetSize());
       } else {
-        Copy(dest.GetFrameOffset(), src.GetFrameOffset(), dest.GetSize());
+        Store(dest.GetFrameOffset(), src.GetRegister(), dest.GetSize());
       }
+    } else {
+      // Delay copying until we have spilled all registers, including the scratch register ECX.
+    }
+  }
+  for (size_t i = 0, arg_count = srcs.size(); i != arg_count; ++i) {
+    const ArgumentLocation& src = srcs[i];
+    const ArgumentLocation& dest = dests[i];
+    DCHECK_EQ(src.GetSize(), dest.GetSize());
+    if (!src.IsRegister()) {
+      DCHECK(!dest.IsRegister());
+      Copy(dest.GetFrameOffset(), src.GetFrameOffset(), dest.GetSize());
     }
   }
 }