Merge "Fail threads attaching during runtime shutdown." into dalvik-dev
diff --git a/src/compiler/codegen/GenCommon.cc b/src/compiler/codegen/GenCommon.cc
index 6868d0b..d948d2d 100644
--- a/src/compiler/codegen/GenCommon.cc
+++ b/src/compiler/codegen/GenCommon.cc
@@ -1784,13 +1784,11 @@
            RegLocation rlSrc1, RegLocation rlSrc2)
 {
   OpKind op = kOpBkpt;
-  bool callOut = false;
+  bool isDivRem = false;
   bool checkZero = false;
   bool unary = false;
   RegLocation rlResult;
   bool shiftOp = false;
-  int funcOffset;
-  int retReg = rRET0;
   switch (opcode) {
     case Instruction::NEG_INT:
       op = kOpNeg;
@@ -1816,18 +1814,14 @@
     case Instruction::DIV_INT_2ADDR:
       checkZero = true;
       op = kOpDiv;
-      callOut = true;
-      funcOffset = ENTRYPOINT_OFFSET(pIdivmod);
-      retReg = rRET0;
+      isDivRem = true;
       break;
     /* NOTE: returns in rARG1 */
     case Instruction::REM_INT:
     case Instruction::REM_INT_2ADDR:
       checkZero = true;
       op = kOpRem;
-      callOut = true;
-      funcOffset = ENTRYPOINT_OFFSET(pIdivmod);
-      retReg = rRET1;
+      isDivRem = true;
       break;
     case Instruction::AND_INT:
     case Instruction::AND_INT_2ADDR:
@@ -1860,7 +1854,7 @@
       LOG(FATAL) << "Invalid word arith op: " <<
         (int)opcode;
   }
-  if (!callOut) {
+  if (!isDivRem) {
     if (unary) {
       rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
       rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
@@ -1889,10 +1883,24 @@
     }
     storeValue(cUnit, rlDest, rlResult);
   } else {
+#if defined(TARGET_MIPS)
+    rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
+    if (checkZero) {
+        genNullCheck(cUnit, rlSrc2.sRegLow, rlSrc2.lowReg, 0);
+    }
+    newLIR4(cUnit, kMipsDiv, r_HI, r_LO, rlSrc1.lowReg, rlSrc2.lowReg);
+    rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
+    if (op == kOpDiv) {
+      newLIR2(cUnit, kMipsMflo, rlResult.lowReg, r_LO);
+    } else {
+      newLIR2(cUnit, kMipsMfhi, rlResult.lowReg, r_HI);
+    }
+#else
+    int funcOffset = ENTRYPOINT_OFFSET(pIdivmod);
     RegLocation rlResult;
     oatFlushAllRegs(cUnit);   /* Send everything to home location */
     loadValueDirectFixed(cUnit, rlSrc2, rARG1);
-#if !defined(TARGET_X86)
+#if defined(TARGET_ARM)
     int rTgt = loadHelper(cUnit, funcOffset);
 #endif
     loadValueDirectFixed(cUnit, rlSrc1, rARG0);
@@ -1900,17 +1908,18 @@
       genImmedCheck(cUnit, kCondEq, rARG1, 0, kThrowDivZero);
     }
     // NOTE: callout here is not a safepoint
-#if !defined(TARGET_X86)
+#if defined(TARGET_ARM)
     opReg(cUnit, kOpBlx, rTgt);
     oatFreeTemp(cUnit, rTgt);
 #else
     opThreadMem(cUnit, kOpBlx, funcOffset);
 #endif
-    if (retReg == rRET0)
+    if (op == kOpDiv)
       rlResult = oatGetReturn(cUnit, false);
     else
       rlResult = oatGetReturnAlt(cUnit);
     storeValue(cUnit, rlDest, rlResult);
+#endif
   }
   return false;
 }
@@ -2077,7 +2086,6 @@
   OpKind op = (OpKind)0;    /* Make gcc happy */
   int shiftOp = false;
   bool isDiv = false;
-  int funcOffset;
 
   switch (opcode) {
     case Instruction::RSUB_INT_LIT8:
@@ -2140,7 +2148,7 @@
     case Instruction::DIV_INT_LIT8:
     case Instruction::DIV_INT_LIT16:
     case Instruction::REM_INT_LIT8:
-    case Instruction::REM_INT_LIT16:
+    case Instruction::REM_INT_LIT16: {
       if (lit == 0) {
         genImmedCheck(cUnit, kCondAl, 0, 0, kThrowDivZero);
         return false;
@@ -2148,24 +2156,39 @@
       if (handleEasyDivide(cUnit, opcode, rlSrc, rlDest, lit)) {
         return false;
       }
-      oatFlushAllRegs(cUnit);   /* Everything to home location */
-      loadValueDirectFixed(cUnit, rlSrc, rARG0);
-      oatClobber(cUnit, rARG0);
-      funcOffset = ENTRYPOINT_OFFSET(pIdivmod);
       if ((opcode == Instruction::DIV_INT_LIT8) ||
           (opcode == Instruction::DIV_INT_LIT16)) {
         isDiv = true;
       } else {
         isDiv = false;
       }
+#if defined(TARGET_MIPS)
+      rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+      int tReg = oatAllocTemp(cUnit);
+      newLIR3(cUnit, kMipsAddiu, tReg, r_ZERO, lit);
+      newLIR4(cUnit, kMipsDiv, r_HI, r_LO, rlSrc.lowReg, tReg);
+      rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
+      if (isDiv) {
+        newLIR2(cUnit, kMipsMflo, rlResult.lowReg, r_LO);
+      } else {
+        newLIR2(cUnit, kMipsMfhi, rlResult.lowReg, r_HI);
+      }
+      oatFreeTemp(cUnit, tReg);
+#else
+      oatFlushAllRegs(cUnit);   /* Everything to home location */
+      loadValueDirectFixed(cUnit, rlSrc, rARG0);
+      oatClobber(cUnit, rARG0);
+      int funcOffset = ENTRYPOINT_OFFSET(pIdivmod);
       callRuntimeHelperRegImm(cUnit, funcOffset, rARG0, lit, false);
       if (isDiv)
         rlResult = oatGetReturn(cUnit, false);
       else
         rlResult = oatGetReturnAlt(cUnit);
+#endif
       storeValue(cUnit, rlDest, rlResult);
       return false;
       break;
+    }
     default:
       return true;
   }
diff --git a/src/compiler/codegen/mips/Assemble.cc b/src/compiler/codegen/mips/Assemble.cc
index 25e13d7..8c906cc 100644
--- a/src/compiler/codegen/mips/Assemble.cc
+++ b/src/compiler/codegen/mips/Assemble.cc
@@ -691,19 +691,19 @@
                      << (int)encoder->fieldLoc[i].kind;
       }
     }
-    // FIXME: need multi-endian handling here
-    cUnit->codeBuffer.push_back((bits >> 24) & 0xff);
-    cUnit->codeBuffer.push_back((bits >> 16) & 0xff);
-    cUnit->codeBuffer.push_back((bits >> 8) & 0xff);
+    // We only support little-endian MIPS.
     cUnit->codeBuffer.push_back(bits & 0xff);
+    cUnit->codeBuffer.push_back((bits >> 8) & 0xff);
+    cUnit->codeBuffer.push_back((bits >> 16) & 0xff);
+    cUnit->codeBuffer.push_back((bits >> 24) & 0xff);
     // TUNING: replace with proper delay slot handling
     if (encoder->size == 8) {
       const MipsEncodingMap *encoder = &EncodingMap[kMipsNop];
       u4 bits = encoder->skeleton;
-      cUnit->codeBuffer.push_back((bits >> 24) & 0xff);
-      cUnit->codeBuffer.push_back((bits >> 16) & 0xff);
-      cUnit->codeBuffer.push_back((bits >> 8) & 0xff);
       cUnit->codeBuffer.push_back(bits & 0xff);
+      cUnit->codeBuffer.push_back((bits >> 8) & 0xff);
+      cUnit->codeBuffer.push_back((bits >> 16) & 0xff);
+      cUnit->codeBuffer.push_back((bits >> 24) & 0xff);
     }
   }
   return res;
diff --git a/src/compiler/codegen/mips/MipsLIR.h b/src/compiler/codegen/mips/MipsLIR.h
index 0f6226f..ab4f844 100644
--- a/src/compiler/codegen/mips/MipsLIR.h
+++ b/src/compiler/codegen/mips/MipsLIR.h
@@ -147,14 +147,12 @@
 /* RegisterLocation templates return values (r_V0, or r_V0/r_V1) */
 #define LOC_C_RETURN {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1, r_V0, INVALID_REG, \
                       INVALID_SREG, INVALID_SREG}
-#define LOC_C_RETURN_FLOAT  LOC_C_RETURN
-#define LOC_C_RETURN_ALT {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1, r_V1, \
-                          INVALID_REG, INVALID_SREG, INVALID_SREG}
+#define LOC_C_RETURN_FLOAT {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1, r_FRESULT0, \
+                            INVALID_REG, INVALID_SREG, INVALID_SREG}
 #define LOC_C_RETURN_WIDE {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r_RESULT0, \
                            r_RESULT1, INVALID_SREG, INVALID_SREG}
-#define LOC_C_RETURN_WIDE_DOUBLE  LOC_C_RETURN_WIDE
-#define LOC_C_RETURN_WIDE_ALT {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r_FRESULT0,\
-                               r_FRESULT1, INVALID_SREG, INVALID_SREG}
+#define LOC_C_RETURN_WIDE_DOUBLE {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r_FRESULT0,\
+                                  r_FRESULT1, INVALID_SREG, INVALID_SREG}
 
 enum ResourceEncodingPos {
   kGPReg0   = 0,
diff --git a/src/compiler/codegen/mips/MipsRallocUtil.cc b/src/compiler/codegen/mips/MipsRallocUtil.cc
index 43fcc07..bd9f97e 100644
--- a/src/compiler/codegen/mips/MipsRallocUtil.cc
+++ b/src/compiler/codegen/mips/MipsRallocUtil.cc
@@ -138,20 +138,15 @@
 
 extern RegLocation oatGetReturnWideAlt(CompilationUnit* cUnit)
 {
-  RegLocation res = LOC_C_RETURN_WIDE_ALT;
-  oatClobber(cUnit, res.lowReg);
-  oatClobber(cUnit, res.highReg);
-  oatMarkInUse(cUnit, res.lowReg);
-  oatMarkInUse(cUnit, res.highReg);
-  oatMarkPair(cUnit, res.lowReg, res.highReg);
+  UNIMPLEMENTED(FATAL) << "No oatGetReturnWideAlt for MIPS";
+  RegLocation res = LOC_C_RETURN_WIDE;
   return res;
 }
 
 extern RegLocation oatGetReturnAlt(CompilationUnit* cUnit)
 {
-  RegLocation res = LOC_C_RETURN_ALT;
-  oatClobber(cUnit, res.lowReg);
-  oatMarkInUse(cUnit, res.lowReg);
+  UNIMPLEMENTED(FATAL) << "No oatGetReturnAlt for MIPS";
+  RegLocation res = LOC_C_RETURN;
   return res;
 }
 
diff --git a/src/disassembler_mips.cc b/src/disassembler_mips.cc
index f7d755a..ca9f6d7 100644
--- a/src/disassembler_mips.cc
+++ b/src/disassembler_mips.cc
@@ -164,9 +164,8 @@
 };
 
 static uint32_t ReadU32(const uint8_t* ptr) {
-  // TODO: MIPS is bi. how do we handle that?
-  return ptr[3] | (ptr[2] << 8) | (ptr[1] << 16) | (ptr[0] << 24);
-  //return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
+  // We only support little-endian MIPS.
+  return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
 }
 
 static void DumpMips(std::ostream& os, const uint8_t* instr_ptr) {
diff --git a/src/oat/runtime/mips/stub_mips.cc b/src/oat/runtime/mips/stub_mips.cc
index 4865c59..7b4c85e 100644
--- a/src/oat/runtime/mips/stub_mips.cc
+++ b/src/oat/runtime/mips/stub_mips.cc
@@ -41,19 +41,16 @@
   // Save callee saves and ready frame for exception delivery
   __ AddConstant(SP, SP, -64);
   __ StoreToOffset(kStoreWord, RA, SP, 60);
-  __ StoreToOffset(kStoreWord, T9, SP, 56);
-  __ StoreToOffset(kStoreWord, T8, SP, 52);
-  __ StoreToOffset(kStoreWord, T7, SP, 48);
-  __ StoreToOffset(kStoreWord, T6, SP, 44);
-  __ StoreToOffset(kStoreWord, T5, SP, 40);
-  __ StoreToOffset(kStoreWord, T4, SP, 36);
-  __ StoreToOffset(kStoreWord, T3, SP, 32);
-  __ StoreToOffset(kStoreWord, T2, SP, 28);
-  __ StoreToOffset(kStoreWord, T1, SP, 24);
-  __ StoreToOffset(kStoreWord, T0, SP, 20);
-  __ StoreToOffset(kStoreWord, A3, SP, 16);
-  __ StoreToOffset(kStoreWord, A2, SP, 12);
-  __ StoreToOffset(kStoreWord, A1, SP, 8);
+  __ StoreToOffset(kStoreWord, FP, SP, 56);
+  __ StoreToOffset(kStoreWord, S7, SP, 52);
+  __ StoreToOffset(kStoreWord, S6, SP, 48);
+  __ StoreToOffset(kStoreWord, S5, SP, 44);
+  __ StoreToOffset(kStoreWord, S4, SP, 40);
+  __ StoreToOffset(kStoreWord, S3, SP, 36);
+  __ StoreToOffset(kStoreWord, S2, SP, 32);
+  __ StoreToOffset(kStoreWord, A3, SP, 28);
+  __ StoreToOffset(kStoreWord, A2, SP, 24);
+  __ StoreToOffset(kStoreWord, A1, SP, 20);
 
   __ LoadFromOffset(kLoadWord, T9, S1,
                     ENTRYPOINT_OFFSET(pUnresolvedDirectMethodTrampolineFromCode));
@@ -63,19 +60,16 @@
   __ Jalr(T9); // Call to unresolved direct method trampoline (method_idx, sp, Thread*, is_static)
 
   // Restore registers which may have been modified by GC
-  __ LoadFromOffset(kLoadWord, A1, SP, 8);
-  __ LoadFromOffset(kLoadWord, A2, SP, 12);
-  __ LoadFromOffset(kLoadWord, A3, SP, 16);
-  __ LoadFromOffset(kLoadWord, T0, SP, 20);
-  __ LoadFromOffset(kLoadWord, T1, SP, 24);
-  __ LoadFromOffset(kLoadWord, T2, SP, 28);
-  __ LoadFromOffset(kLoadWord, T3, SP, 32);
-  __ LoadFromOffset(kLoadWord, T4, SP, 36);
-  __ LoadFromOffset(kLoadWord, T5, SP, 40);
-  __ LoadFromOffset(kLoadWord, T6, SP, 44);
-  __ LoadFromOffset(kLoadWord, T7, SP, 48);
-  __ LoadFromOffset(kLoadWord, T8, SP, 52);
-  __ LoadFromOffset(kLoadWord, T9, SP, 56);
+  __ LoadFromOffset(kLoadWord, A1, SP, 20);
+  __ LoadFromOffset(kLoadWord, A2, SP, 24);
+  __ LoadFromOffset(kLoadWord, A3, SP, 28);
+  __ LoadFromOffset(kLoadWord, S2, SP, 32);
+  __ LoadFromOffset(kLoadWord, S3, SP, 36);
+  __ LoadFromOffset(kLoadWord, S4, SP, 40);
+  __ LoadFromOffset(kLoadWord, S5, SP, 44);
+  __ LoadFromOffset(kLoadWord, S6, SP, 48);
+  __ LoadFromOffset(kLoadWord, S7, SP, 52);
+  __ LoadFromOffset(kLoadWord, FP, SP, 56);
   __ LoadFromOffset(kLoadWord, RA, SP, 60);
   __ AddConstant(SP, SP, 64);
 
@@ -133,16 +127,13 @@
   // Save callee saves and ready frame for exception delivery
   __ AddConstant(SP, SP, -48);
   __ StoreToOffset(kStoreWord, RA, SP, 44);
-  __ StoreToOffset(kStoreWord, T9, SP, 40);
-  __ StoreToOffset(kStoreWord, T8, SP, 36);
-  __ StoreToOffset(kStoreWord, T7, SP, 32);
-  __ StoreToOffset(kStoreWord, T6, SP, 28);
-  __ StoreToOffset(kStoreWord, T5, SP, 24);
-  __ StoreToOffset(kStoreWord, T4, SP, 20);
-  __ StoreToOffset(kStoreWord, T3, SP, 16);
-  __ StoreToOffset(kStoreWord, T2, SP, 12);
-  __ StoreToOffset(kStoreWord, T1, SP, 8);
-  __ StoreToOffset(kStoreWord, T0, SP, 4);
+  __ StoreToOffset(kStoreWord, FP, SP, 40);
+  __ StoreToOffset(kStoreWord, S7, SP, 36);
+  __ StoreToOffset(kStoreWord, S6, SP, 32);
+  __ StoreToOffset(kStoreWord, S5, SP, 28);
+  __ StoreToOffset(kStoreWord, S4, SP, 24);
+  __ StoreToOffset(kStoreWord, S3, SP, 20);
+  __ StoreToOffset(kStoreWord, S2, SP, 16);
 
   // A0 is the Method* already
   __ Move(A1, S1);  // Pass Thread::Current() in A1