Fix the jni compiler's handling of byte and short return values in x86.

gcc uses byte/short operations to populate return values of these types,
so the sign extension is lost. The jni compiler needs to manually sign
extend the values again since they're treated like words in the system.

With this change, all the run_test tests are working.

Change-Id: If691087ebd79b0d608e44ff8273ed25d46dd6b4a
diff --git a/src/oat/jni/calling_convention.h b/src/oat/jni/calling_convention.h
index 7e42904..6feff0f 100644
--- a/src/oat/jni/calling_convention.h
+++ b/src/oat/jni/calling_convention.h
@@ -29,6 +29,10 @@
  public:
   bool IsReturnAReference() const { return shorty_[0] == 'L'; }
 
+  Primitive::Type GetReturnType() const {
+    return Primitive::GetType(shorty_[0]);
+  }
+
   size_t SizeOfReturnValue() const {
     size_t result = Primitive::ComponentSize(Primitive::GetType(shorty_[0]));
     if (result >= 1 && result < 4) {
diff --git a/src/oat/jni/jni_compiler.cc b/src/oat/jni/jni_compiler.cc
index a81d884..2491586 100644
--- a/src/oat/jni/jni_compiler.cc
+++ b/src/oat/jni/jni_compiler.cc
@@ -544,6 +544,9 @@
 
     __ DecreaseFrameSize(out_arg_size);
     jni_conv->ResetIterator(FrameOffset(0));
+  } else if (instruction_set == kX86 && (jni_conv->GetReturnType() == Primitive::kPrimByte ||
+                                         jni_conv->GetReturnType() == Primitive::kPrimShort)) {
+    __ SignExtend(jni_conv->ReturnRegister(), Primitive::ComponentSize(jni_conv->GetReturnType()));
   }
   DCHECK_EQ(mr_conv->SizeOfReturnValue(), jni_conv->SizeOfReturnValue());
   __ Move(mr_conv->ReturnRegister(), jni_conv->ReturnRegister(), mr_conv->SizeOfReturnValue());
diff --git a/src/oat/utils/arm/assembler_arm.cc b/src/oat/utils/arm/assembler_arm.cc
index 460e81b..e248d5f 100644
--- a/src/oat/utils/arm/assembler_arm.cc
+++ b/src/oat/utils/arm/assembler_arm.cc
@@ -1647,6 +1647,10 @@
   StoreToOffset(kStoreWord, SP, TR, thr_offs.Int32Value());
 }
 
+void ArmAssembler::SignExtend(ManagedRegister /*mreg*/, size_t /*size*/) {
+  UNIMPLEMENTED(FATAL) << "no sign extension necessary for arm";
+}
+
 void ArmAssembler::Move(ManagedRegister m_dst, ManagedRegister m_src, size_t /*size*/) {
   ArmManagedRegister dst = m_dst.AsArm();
   ArmManagedRegister src = m_src.AsArm();
diff --git a/src/oat/utils/arm/assembler_arm.h b/src/oat/utils/arm/assembler_arm.h
index e4ccfd8..ae7bfb4 100644
--- a/src/oat/utils/arm/assembler_arm.h
+++ b/src/oat/utils/arm/assembler_arm.h
@@ -516,6 +516,9 @@
 
   virtual void MemoryBarrier(ManagedRegister scratch);
 
+  // Sign extension
+  virtual void SignExtend(ManagedRegister mreg, size_t size);
+
   // Exploit fast access in managed code to Thread::Current()
   virtual void GetCurrentThread(ManagedRegister tr);
   virtual void GetCurrentThread(FrameOffset dest_offset,
diff --git a/src/oat/utils/assembler.h b/src/oat/utils/assembler.h
index 47f1ead..71f32c0 100644
--- a/src/oat/utils/assembler.h
+++ b/src/oat/utils/assembler.h
@@ -398,6 +398,9 @@
 
   virtual void MemoryBarrier(ManagedRegister scratch) = 0;
 
+  // Sign extension
+  virtual void SignExtend(ManagedRegister mreg, size_t size) = 0;
+
   // Exploit fast access in managed code to Thread::Current()
   virtual void GetCurrentThread(ManagedRegister tr) = 0;
   virtual void GetCurrentThread(FrameOffset dest_offset,
diff --git a/src/oat/utils/x86/assembler_x86.cc b/src/oat/utils/x86/assembler_x86.cc
index 569ec09..52535fd 100644
--- a/src/oat/utils/x86/assembler_x86.cc
+++ b/src/oat/utils/x86/assembler_x86.cc
@@ -1597,6 +1597,17 @@
   fs()->movl(dest.AsCpuRegister(), Address::Absolute(offs));
 }
 
+void X86Assembler::SignExtend(ManagedRegister mreg, size_t size) {
+  X86ManagedRegister reg = mreg.AsX86();
+  CHECK(size == 1 || size == 2) << size;
+  CHECK(reg.IsCpuRegister()) << reg;
+  if (size == 1) {
+    movsxb(reg.AsCpuRegister(), reg.AsByteRegister());
+  } else {
+    movsxw(reg.AsCpuRegister(), reg.AsCpuRegister());
+  }
+}
+
 void X86Assembler::Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) {
   X86ManagedRegister dest = mdest.AsX86();
   X86ManagedRegister src = msrc.AsX86();
diff --git a/src/oat/utils/x86/assembler_x86.h b/src/oat/utils/x86/assembler_x86.h
index 58acab2..d3600b0 100644
--- a/src/oat/utils/x86/assembler_x86.h
+++ b/src/oat/utils/x86/assembler_x86.h
@@ -550,6 +550,9 @@
 
   virtual void MemoryBarrier(ManagedRegister);
 
+  // Sign extension
+  virtual void SignExtend(ManagedRegister mreg, size_t size);
+
   // Exploit fast access in managed code to Thread::Current()
   virtual void GetCurrentThread(ManagedRegister tr);
   virtual void GetCurrentThread(FrameOffset dest_offset,
diff --git a/src/oat/utils/x86/managed_register_x86.h b/src/oat/utils/x86/managed_register_x86.h
index 33573f9..e45db53 100644
--- a/src/oat/utils/x86/managed_register_x86.h
+++ b/src/oat/utils/x86/managed_register_x86.h
@@ -87,6 +87,11 @@
 // There is a one-to-one mapping between ManagedRegister and register id.
 class X86ManagedRegister : public ManagedRegister {
  public:
+  ByteRegister AsByteRegister() const {
+    CHECK(IsCpuRegister());
+    return static_cast<ByteRegister>(id_);
+  }
+
   Register AsCpuRegister() const {
     CHECK(IsCpuRegister());
     return static_cast<Register>(id_);