Exception and suspend count polling on JNI bridge return.

Change-Id: I0e5597fcbdcdb88100b18d63323e7ba8d27f13fe
diff --git a/src/assembler_x86.cc b/src/assembler_x86.cc
index 2b21463..a3d47e3 100644
--- a/src/assembler_x86.cc
+++ b/src/assembler_x86.cc
@@ -5,6 +5,7 @@
 #include "src/globals.h"
 #include "src/memory_region.h"
 #include "src/offsets.h"
+#include "src/thread.h"
 
 namespace art {
 
@@ -1396,10 +1397,19 @@
 
 // Store bytes from the given register onto the stack
 void Assembler::Store(FrameOffset offs, ManagedRegister src, size_t size) {
-  if (src.IsCpuRegister()) {
+  if (src.IsNoRegister()) {
+    CHECK_EQ(0u, size);
+  } else if (src.IsCpuRegister()) {
     CHECK_EQ(4u, size);
     movl(Address(ESP, offs), src.AsCpuRegister());
-  } else if (src.IsXmmRegister()) {
+  } else if (src.IsX87Register()) {
+    if (size == 4) {
+      fstps(Address(ESP, offs));
+    } else {
+      fstpl(Address(ESP, offs));
+    }
+  } else {
+    CHECK(src.IsXmmRegister());
     if (size == 4) {
       movss(Address(ESP, offs), src.AsXmmRegister());
     } else {
@@ -1437,12 +1447,24 @@
 }
 
 void Assembler::Load(ManagedRegister dest, FrameOffset src, size_t size) {
-  if (dest.IsCpuRegister()) {
+  if (dest.IsNoRegister()) {
+    CHECK_EQ(0u, size);
+  } else if (dest.IsCpuRegister()) {
     CHECK_EQ(4u, size);
     movl(dest.AsCpuRegister(), Address(ESP, src));
+  } else if (dest.IsX87Register()) {
+    if (size == 4) {
+      flds(Address(ESP, src));
+    } else {
+      fldl(Address(ESP, src));
+    }
   } else {
-    // TODO: x87, SSE
-    LOG(FATAL) << "Unimplemented";
+    CHECK(dest.IsXmmRegister());
+    if (size == 4) {
+      movss(dest.AsXmmRegister(), Address(ESP, src));
+    } else {
+      movsd(dest.AsXmmRegister(), Address(ESP, src));
+    }
   }
 }
 
@@ -1488,6 +1510,11 @@
   movl(Address::Absolute(thr_offs), scratch.AsCpuRegister());
 }
 
+void Assembler::StoreStackPointerToThread(ThreadOffset thr_offs) {
+  fs();
+  movl(Address::Absolute(thr_offs), ESP);
+}
+
 void Assembler::Move(ManagedRegister dest, ManagedRegister src) {
   if (!dest.Equals(src)) {
     if (dest.IsCpuRegister() && src.IsCpuRegister()) {
@@ -1579,4 +1606,57 @@
   // TODO: place reference map on call
 }
 
+// Generate code to check if Thread::Current()->suspend_count_ is non-zero
+// and branch to a SuspendSlowPath if it is. The SuspendSlowPath will continue
+// at the next instruction.
+void Assembler::SuspendPoll(ManagedRegister scratch, ManagedRegister return_reg,
+                            FrameOffset return_save_location,
+                            size_t return_size) {
+  SuspendCountSlowPath* slow =
+      new SuspendCountSlowPath(return_reg, return_save_location, return_size);
+  buffer_.EnqueueSlowPath(slow);
+  fs();
+  cmpl(Address::Absolute(Thread::SuspendCountOffset()), Immediate(0));
+  j(NOT_EQUAL, slow->Entry());
+  Bind(slow->Continuation());
+}
+void SuspendCountSlowPath::Emit(Assembler *sp_asm) {
+  sp_asm->Bind(&entry_);
+  // Save return value
+  sp_asm->Store(return_save_location_, return_register_, return_size_);
+  // Pass top of stack as argument
+  sp_asm->pushl(ESP);
+  sp_asm->fs();
+  sp_asm->call(Address::Absolute(Thread::SuspendCountEntryPointOffset()));
+  // Release argument
+  sp_asm->addl(ESP, Immediate(kPointerSize));
+  // Reload return value
+  sp_asm->Load(return_register_, return_save_location_, return_size_);
+  sp_asm->jmp(&continuation_);
+}
+
+// Generate code to check if Thread::Current()->exception_ is non-null
+// and branch to a ExceptionSlowPath if it is.
+void Assembler::ExceptionPoll(ManagedRegister scratch) {
+  ExceptionSlowPath* slow = new ExceptionSlowPath();
+  buffer_.EnqueueSlowPath(slow);
+  fs();
+  cmpl(Address::Absolute(Thread::ExceptionOffset()), Immediate(0));
+  j(NOT_EQUAL, slow->Entry());
+  Bind(slow->Continuation());
+}
+void ExceptionSlowPath::Emit(Assembler *sp_asm) {
+  sp_asm->Bind(&entry_);
+  // NB the return value is dead
+  // Pass top of stack as argument
+  sp_asm->pushl(ESP);
+  sp_asm->fs();
+  sp_asm->call(Address::Absolute(Thread::ExceptionEntryPointOffset()));
+  // TODO: this call should never return as it should make a long jump to
+  // the appropriate catch block
+  // Release argument
+  sp_asm->addl(ESP, Immediate(kPointerSize));
+  sp_asm->jmp(&continuation_);
+}
+
 }  // namespace art