Initial ARM JNI compiler support.

Change-Id: I85183eec9a2645e6cb074b4b18bc6af800a77e06
diff --git a/src/jni_compiler_test.cc b/src/jni_compiler_test.cc
index 225ca5c..9c88c84 100644
--- a/src/jni_compiler_test.cc
+++ b/src/jni_compiler_test.cc
@@ -31,26 +31,47 @@
     thk_asm.movl(EDI, Address(ESP, 12));  // EDI = method
     thk_asm.pushl(Immediate(0));          // push pad
     thk_asm.pushl(Immediate(0));          // push pad
-    thk_asm.pushl(Address(ESP, 40));      // push pad  or jlong high
-    thk_asm.pushl(Address(ESP, 40));      // push jint or jlong low
-    thk_asm.pushl(Address(ESP, 40));      // push jint or jlong high
-    thk_asm.pushl(Address(ESP, 40));      // push jint or jlong low
-    thk_asm.pushl(Address(ESP, 40));      // push jobject
+    thk_asm.pushl(Address(ESP, 44));      // push pad  or jlong high
+    thk_asm.pushl(Address(ESP, 44));      // push jint or jlong low
+    thk_asm.pushl(Address(ESP, 44));      // push jint or jlong high
+    thk_asm.pushl(Address(ESP, 44));      // push jint or jlong low
+    thk_asm.pushl(Address(ESP, 44));      // push jobject
     thk_asm.call(EAX);                    // Continue in method->GetCode()
     thk_asm.addl(ESP, Immediate(28));     // pop arguments
     thk_asm.popl(EDI);                    // restore EDI
     thk_asm.ret();
+#elif defined(__arm__)
+    thk_asm.AddConstant(SP, -32);         // Build frame
+    thk_asm.StoreToOffset(kStoreWord, LR, SP, 28); // Spill link register
+    thk_asm.StoreToOffset(kStoreWord, R9, SP, 24); // Spill R9
+    thk_asm.mov(R12, ShifterOperand(R0)); // R12 = method->GetCode()
+    thk_asm.mov(R0,  ShifterOperand(R1)); // R0  = method
+    thk_asm.mov(R9,  ShifterOperand(R2)); // R9  = Thread::Current()
+    thk_asm.mov(R1,  ShifterOperand(R3)); // R1  = arg1 (jint/jlong low)
+    thk_asm.LoadFromOffset(kLoadWord, R3, SP, 44); // R3 = arg5 (pad/jlong high)
+    thk_asm.StoreToOffset(kStoreWord, R3, SP, 4);
+    thk_asm.LoadFromOffset(kLoadWord, R3, SP, 40); // R3 = arg4 (jint/jlong low)
+    thk_asm.StoreToOffset(kStoreWord, R3, SP, 0);
+    thk_asm.LoadFromOffset(kLoadWord, R3, SP, 36); // R3 = arg3 (jint/jlong high)
+    thk_asm.LoadFromOffset(kLoadWord, R2, SP, 32); // R2 = arg2 (jint/jlong high)
+    thk_asm.blx(R12);                     // Branch and link R12
+    thk_asm.LoadFromOffset(kLoadWord, LR, SP, 28); // Fill link register
+    thk_asm.LoadFromOffset(kLoadWord, R9, SP, 24); // Fill R9
+    thk_asm.AddConstant(SP, 32);          // Remove frame
+    thk_asm.mov(PC, ShifterOperand(LR));  // Return
 #else
-    LOG(FATAL) << "Unimplemented";
+#error Unimplemented
 #endif
     size_t cs = thk_asm.CodeSize();
     MemoryRegion code(thunk_, cs);
     thk_asm.FinalizeInstructions(code);
     thunk_entry1_ = reinterpret_cast<jint (*)(const void*, art::Method*,
-                                              jobject, jint, jint, jint)
+                                              Thread*, jobject, jint, jint,
+                                              jint)
                                     >(code.pointer());
     thunk_entry2_ = reinterpret_cast<jdouble (*)(const void*, art::Method*,
-                                                 jobject, jdouble, jdouble)
+                                                 Thread*, jobject, jdouble,
+                                                 jdouble)
                                     >(code.pointer());
   }
 
@@ -69,7 +90,8 @@
     EXPECT_EQ(0u, Thread::Current()->NumShbHandles());
     EXPECT_EQ(Thread::kRunnable, Thread::Current()->GetState());
     // perform call
-    result.i = (*thunk_entry1_)(method->GetCode(), method, a.l, b.i, c.i, d.i);
+    result.i = (*thunk_entry1_)(method->GetCode(), method, Thread::Current(),
+                                a.l, b.i, c.i, d.i);
     // sanity check post-call
     EXPECT_EQ(0u, Thread::Current()->NumShbHandles());
     EXPECT_EQ(Thread::kRunnable, Thread::Current()->GetState());
@@ -85,7 +107,8 @@
     EXPECT_EQ(0u, Thread::Current()->NumShbHandles());
     EXPECT_EQ(Thread::kRunnable, Thread::Current()->GetState());
     // perform call
-    result.d = (*thunk_entry2_)(method->GetCode(), method, a.l, b.d, c.d);
+    result.d = (*thunk_entry2_)(method->GetCode(), method, Thread::Current(),
+                                a.l, b.d, c.d);
     // sanity check post-call
     EXPECT_EQ(0u, Thread::Current()->NumShbHandles());
     EXPECT_EQ(Thread::kRunnable, Thread::Current()->GetState());
@@ -94,8 +117,10 @@
 
   void* thunk_;
   size_t thunk_code_size_;
-  jint (*thunk_entry1_)(const void*, Method*, jobject, jint, jint, jint);
-  jdouble (*thunk_entry2_)(const void*, Method*, jobject, jdouble, jdouble);
+  jint (*thunk_entry1_)(const void*, Method*, Thread*, jobject, jint, jint,
+                        jint);
+  jdouble (*thunk_entry2_)(const void*, Method*, Thread*, jobject, jdouble,
+                           jdouble);
 };
 
 int gJava_MyClass_foo_calls = 0;