Merge "Use regular JNI for initializing the boxing types." into dalvik-dev
diff --git a/src/asm_support.h b/src/asm_support.h
index 6eda4bf..097ab7a 100644
--- a/src/asm_support.h
+++ b/src/asm_support.h
@@ -3,9 +3,16 @@
 #ifndef ART_SRC_ASM_SUPPORT_H_
 #define ART_SRC_ASM_SUPPORT_H_
 
+#if defined(__arm__)
+#define rSUSPEND r4
+#define rSELF r9
+#define rLR r14
+#define SUSPEND_CHECK_INTERVAL (1000)
+#endif
+
 #if defined(__i386__)
 // Offset of field Thread::self_ verified in InitCpu
-#define THREAD_SELF_OFFSET 0x161
+#define THREAD_SELF_OFFSET 0x165
 #endif
 
 #endif  // ART_SRC_ASM_SUPPORT_H_
diff --git a/src/compiler/CompilerIR.h b/src/compiler/CompilerIR.h
index b697292..0965c14 100644
--- a/src/compiler/CompilerIR.h
+++ b/src/compiler/CompilerIR.h
@@ -87,6 +87,7 @@
     kMIRInlined,                        // Invoke is inlined (ie dead)
     kMIRInlinedPred,                    // Invoke is inlined via prediction
     kMIRCallee,                         // Instruction is inlined from callee
+    kMIRIgnoreSuspendCheck,
 } MIROptimizationFlagPositons;
 
 #define MIR_IGNORE_NULL_CHECK           (1 << kMIRIgnoreNullCheck)
@@ -96,6 +97,7 @@
 #define MIR_INLINED                     (1 << kMIRInlined)
 #define MIR_INLINED_PRED                (1 << kMIRInlinedPred)
 #define MIR_CALLEE                      (1 << kMIRCallee)
+#define MIR_IGNORE_SUSPEND_CHECK        (1 << kMIRIgnoreSuspendCheck)
 
 typedef struct CallsiteInfo {
     const char* classDescriptor;
@@ -239,6 +241,7 @@
     GrowableList dfsOrder;
     GrowableList domPostOrderTraversal;
     GrowableList throwLaunchpads;
+    GrowableList suspendLaunchpads;
     ArenaBitVector* tryBlockAddr;
     ArenaBitVector** defBlockMatrix;    // numDalvikRegister x numBlocks
     ArenaBitVector* tempBlockV;
diff --git a/src/compiler/Dataflow.cc b/src/compiler/Dataflow.cc
index 827470e..d4b5339 100644
--- a/src/compiler/Dataflow.cc
+++ b/src/compiler/Dataflow.cc
@@ -2405,6 +2405,10 @@
             if (predBBIdx == -1) break;
             predBB = (BasicBlock*)oatGrowableListGetElement(
                 blockList, predBBIdx);
+            if ((predBB->dataFlowInfo == NULL) ||
+                (predBB->dataFlowInfo->endingNullCheckV == NULL)) {
+                continue;
+            }
             oatIntersectBitVectors(cUnit->tempSSARegisterV,
                 cUnit->tempSSARegisterV,
                 predBB->dataFlowInfo->endingNullCheckV);
diff --git a/src/compiler/Frontend.cc b/src/compiler/Frontend.cc
index fdcce9c..6a01e36 100644
--- a/src/compiler/Frontend.cc
+++ b/src/compiler/Frontend.cc
@@ -725,6 +725,9 @@
     /* Intialize the throwLaunchpads list */
     oatInitGrowableList(&cUnit.throwLaunchpads, 4);
 
+    /* Intialize the suspendLaunchpads list */
+    oatInitGrowableList(&cUnit.suspendLaunchpads, 4);
+
     /* Allocate the bit-vector to track the beginning of basic blocks */
     ArenaBitVector *tryBlockAddr = oatAllocBitVector(cUnit.insnsSize,
                                                      true /* expandable */);
diff --git a/src/compiler/SSATransformation.cc b/src/compiler/SSATransformation.cc
index dea1971..1a488bb 100644
--- a/src/compiler/SSATransformation.cc
+++ b/src/compiler/SSATransformation.cc
@@ -247,7 +247,9 @@
         BasicBlock* predBB = (BasicBlock* ) oatGrowableListGetElement(
                                  blockList, predIdx);
         /* tempBlockV = tempBlockV ^ dominators */
-        oatIntersectBitVectors(tempBlockV, tempBlockV, predBB->dominators);
+        if (predBB->dominators != NULL) {
+            oatIntersectBitVectors(tempBlockV, tempBlockV, predBB->dominators);
+        }
     }
     oatSetBit(tempBlockV, bb->id);
     if (oatCompareBitVectors(tempBlockV, bb->dominators)) {
@@ -452,7 +454,9 @@
                     (BasicBlock* ) oatGrowableListGetElement(blockList, idx);
 
                 /* Merge the dominance frontier to tmpBlocks */
-                oatUnifyBitVectors(tmpBlocks, tmpBlocks, defBB->domFrontier);
+                if (defBB->domFrontier != NULL) {
+                    oatUnifyBitVectors(tmpBlocks, tmpBlocks, defBB->domFrontier);
+                }
             }
             if (oatCompareBitVectors(phiBlocks, tmpBlocks)) {
                 change = true;
diff --git a/src/compiler/Utility.cc b/src/compiler/Utility.cc
index 7d3a887..7b99966 100644
--- a/src/compiler/Utility.cc
+++ b/src/compiler/Utility.cc
@@ -373,8 +373,9 @@
 bool oatIntersectBitVectors(ArenaBitVector* dest, const ArenaBitVector* src1,
                             const ArenaBitVector* src2)
 {
-    if (src2 == NULL ||
-        dest->storageSize != src1->storageSize ||
+    DCHECK(src1 != NULL);
+    DCHECK(src2 != NULL);
+    if (dest->storageSize != src1->storageSize ||
         dest->storageSize != src2->storageSize ||
         dest->expandable != src1->expandable ||
         dest->expandable != src2->expandable)
@@ -393,8 +394,9 @@
 bool oatUnifyBitVectors(ArenaBitVector* dest, const ArenaBitVector* src1,
                         const ArenaBitVector* src2)
 {
-    if (src2 == NULL ||
-        dest->storageSize != src1->storageSize ||
+    DCHECK(src1 != NULL);
+    DCHECK(src2 != NULL);
+    if (dest->storageSize != src1->storageSize ||
         dest->storageSize != src2->storageSize ||
         dest->expandable != src1->expandable ||
         dest->expandable != src2->expandable)
diff --git a/src/compiler/codegen/arm/ArchUtility.cc b/src/compiler/codegen/arm/ArchUtility.cc
index 1d6bb41..45e1b19 100644
--- a/src/compiler/codegen/arm/ArchUtility.cc
+++ b/src/compiler/codegen/arm/ArchUtility.cc
@@ -354,6 +354,9 @@
         case kArmPseudoThrowTarget:
             LOG(INFO) << "LT" << (intptr_t)lir << ":";
             break;
+        case kArmPseudoSuspendTarget:
+            LOG(INFO) << "LS" << (intptr_t)lir << ":";
+            break;
         case kArmPseudoCaseLabel:
             LOG(INFO) << "LC" << (intptr_t)lir << ": Case target 0x" <<
                 std::hex << lir->operands[0] << "|" << std::dec <<
diff --git a/src/compiler/codegen/arm/ArmLIR.h b/src/compiler/codegen/arm/ArmLIR.h
index 07e2e97..e436eea 100644
--- a/src/compiler/codegen/arm/ArmLIR.h
+++ b/src/compiler/codegen/arm/ArmLIR.h
@@ -28,7 +28,7 @@
  *        pointer in r0 as a hidden arg0. Otherwise used as codegen scratch
  *        registers.
  * r0-r1: As in C/C++ r0 is 32-bit return register and r0/r1 is 64-bit
- * r4   : Callee save (promotion target)
+ * r4   : (rSUSPEND) is reserved (suspend check assist)
  * r5   : Callee save (promotion target)
  * r6   : Callee save (promotion target)
  * r7   : Callee save (promotion target)
@@ -243,7 +243,7 @@
 
 /*
  * Annotate special-purpose core registers:
- *   - VM: r4PC, r5FP, and r6SELF
+ *   - VM: r6SELF
  *   - ARM architecture: r13sp, r14lr, and r15pc
  *
  * rPC, rFP, and rSELF are for architecture-independent code to use.
@@ -253,7 +253,7 @@
     r1     = 1,
     r2     = 2,
     r3     = 3,
-    r4     = 4,
+    rSUSPEND = 4,
     r5     = 5,
     r6     = 6,
     r7     = 7,
@@ -366,6 +366,7 @@
  * Assemble.c.
  */
 typedef enum ArmOpcode {
+    kArmPseudoSuspendTarget = -15,
     kArmPseudoThrowTarget = -14,
     kArmPseudoCaseLabel = -13,
     kArmPseudoMethodEntry = -12,
diff --git a/src/compiler/codegen/arm/MethodCodegenDriver.cc b/src/compiler/codegen/arm/MethodCodegenDriver.cc
index 8dc388c..41053a2 100644
--- a/src/compiler/codegen/arm/MethodCodegenDriver.cc
+++ b/src/compiler/codegen/arm/MethodCodegenDriver.cc
@@ -849,6 +849,8 @@
         loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pMemcpy), rLR);
         loadConstant(cUnit, r2, (numArgs - 3) * 4);
         callNoUnwindHelper(cUnit, rLR);
+        // Restore Method*
+        loadCurrMethodDirect(cUnit, r0);
     } else {
         // Use vldm/vstm pair using r3 as a temp
         int regsLeft = std::min(numArgs - 3, 16);
@@ -1111,10 +1113,12 @@
 
         case OP_RETURN:
         case OP_RETURN_OBJECT:
+            genSuspendPoll(cUnit, mir);
             storeValue(cUnit, retLoc, rlSrc[0]);
             break;
 
         case OP_RETURN_WIDE:
+            genSuspendPoll(cUnit, mir);
             rlDest = retLocWide;
             rlDest.fp = rlSrc[0].fp;
             storeValueWide(cUnit, rlDest, rlSrc[0]);
@@ -1275,11 +1279,8 @@
         case OP_GOTO:
         case OP_GOTO_16:
         case OP_GOTO_32:
-            // TUNING: add MIR flag to disable when unnecessary
-            bool backwardBranch;
-            backwardBranch = (bb->taken->startOffset <= mir->offset);
-            if (backwardBranch) {
-                genSuspendPoll(cUnit, mir);
+            if (bb->taken->startOffset <= mir->offset) {
+                genSuspendTest(cUnit, mir);
             }
             genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
             break;
@@ -1313,7 +1314,7 @@
             ArmConditionCode cond;
             backwardBranch = (bb->taken->startOffset <= mir->offset);
             if (backwardBranch) {
-                genSuspendPoll(cUnit, mir);
+                genSuspendTest(cUnit, mir);
             }
             rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
             rlSrc[1] = loadValue(cUnit, rlSrc[1], kCoreReg);
@@ -1356,7 +1357,7 @@
             ArmConditionCode cond;
             backwardBranch = (bb->taken->startOffset <= mir->offset);
             if (backwardBranch) {
-                genSuspendPoll(cUnit, mir);
+                genSuspendTest(cUnit, mir);
             }
             rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
             opRegImm(cUnit, kOpCmp, rlSrc[0].lowReg, 0);
@@ -1997,6 +1998,27 @@
     }
 }
 
+static void handleSuspendLaunchpads(CompilationUnit *cUnit)
+{
+    ArmLIR** suspendLabel =
+        (ArmLIR **) cUnit->suspendLaunchpads.elemList;
+    int numElems = cUnit->suspendLaunchpads.numUsed;
+
+    for (int i = 0; i < numElems; i++) {
+        /* TUNING: move suspend count load into helper */
+        ArmLIR* lab = suspendLabel[i];
+        ArmLIR* resumeLab = (ArmLIR*)lab->operands[0];
+        cUnit->currentDalvikOffset = lab->operands[1];
+        oatAppendLIR(cUnit, (LIR *)lab);
+        loadWordDisp(cUnit, rSELF,
+                     OFFSETOF_MEMBER(Thread, pTestSuspendFromCode), rLR);
+        loadWordDisp(cUnit, rSELF,
+            art::Thread::SuspendCountOffset().Int32Value(), rSUSPEND);
+        opReg(cUnit, kOpBlx, rLR);
+        genUnconditionalBranch(cUnit, resumeLab);
+    }
+}
+
 static void handleThrowLaunchpads(CompilationUnit *cUnit)
 {
     ArmLIR** throwLabel =
@@ -2082,9 +2104,11 @@
 
     oatDataFlowAnalysisDispatcher(cUnit, methodBlockCodeGen,
                                   kPreOrderDFSTraversal, false /* Iterative */);
-    removeRedundantBranches(cUnit);
+    handleSuspendLaunchpads(cUnit);
 
     handleThrowLaunchpads(cUnit);
+
+    removeRedundantBranches(cUnit);
 }
 
 /* Common initialization routine for an architecture family */
diff --git a/src/compiler/codegen/arm/Thumb2/Factory.cc b/src/compiler/codegen/arm/Thumb2/Factory.cc
index 254802d..9321753 100644
--- a/src/compiler/codegen/arm/Thumb2/Factory.cc
+++ b/src/compiler/codegen/arm/Thumb2/Factory.cc
@@ -22,9 +22,9 @@
  *
  */
 
-static int coreRegs[] = {r0, r1, r2, r3, r4, r5, r6, r7, rSELF, r8, r10, r11,
-                         r12, rSP, rLR, rPC};
-static int reservedRegs[] = {rSELF, rSP, rLR, rPC};
+static int coreRegs[] = {r0, r1, r2, r3, rSUSPEND, r5, r6, r7, rSELF, r8, r10,
+                         r11, r12, rSP, rLR, rPC};
+static int reservedRegs[] = {rSUSPEND, rSELF, rSP, rLR, rPC};
 static int fpRegs[] = {fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7,
                        fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15,
                        fr16, fr17, fr18, fr19, fr20, fr21, fr22, fr23,
diff --git a/src/compiler/codegen/arm/Thumb2/Gen.cc b/src/compiler/codegen/arm/Thumb2/Gen.cc
index 2404ca7..76d8b45 100644
--- a/src/compiler/codegen/arm/Thumb2/Gen.cc
+++ b/src/compiler/codegen/arm/Thumb2/Gen.cc
@@ -1683,9 +1683,31 @@
     return false;
 }
 
+/* Check if we need to check for pending suspend request */
+static void genSuspendTest(CompilationUnit* cUnit, MIR* mir)
+{
+    if (mir->optimizationFlags & MIR_IGNORE_SUSPEND_CHECK) {
+        return;
+    }
+    newLIR2(cUnit, kThumbSubRI8, rSUSPEND, 1);
+    ArmLIR* branch = opCondBranch(cUnit, kArmCondEq);
+    ArmLIR* retLab = newLIR0(cUnit, kArmPseudoTargetLabel);
+    retLab->defMask = ENCODE_ALL;
+    ArmLIR* target = (ArmLIR*)oatNew(sizeof(ArmLIR), true);
+    target->generic.dalvikOffset = cUnit->currentDalvikOffset;
+    target->opcode = kArmPseudoSuspendTarget;
+    target->operands[0] = (intptr_t)retLab;
+    target->operands[1] = mir->offset;
+    branch->generic.target = (LIR*)target;
+    oatInsertGrowableList(&cUnit->suspendLaunchpads, (intptr_t)target);
+}
+
 /* Check for pending suspend request.  */
 static void genSuspendPoll(CompilationUnit* cUnit, MIR* mir)
 {
+    if (mir->optimizationFlags & MIR_IGNORE_SUSPEND_CHECK) {
+        return;
+    }
     oatLockCallTemps(cUnit);   // Explicit register usage
     int rSuspendCount = r1;
     ArmLIR* ld;
diff --git a/src/jni_internal_arm.cc b/src/jni_internal_arm.cc
index 65dc380..8ba5717 100644
--- a/src/jni_internal_arm.cc
+++ b/src/jni_internal_arm.cc
@@ -31,21 +31,21 @@
   UniquePtr<ArmAssembler> assembler(
       down_cast<ArmAssembler*>(Assembler::Create(kArm)));
 #define __ assembler->
-  // Size of frame - spill of R9/LR + Method* + possible receiver + arg array
-  size_t unpadded_frame_size = (3 * kPointerSize) +
+  // Size of frame - spill of R4,R9/LR + Method* + possible receiver + arg array
+  size_t unpadded_frame_size = (4 * kPointerSize) +
                                (method->IsStatic() ? 0 : kPointerSize) +
                                method->NumArgArrayBytes();
   size_t frame_size = RoundUp(unpadded_frame_size, kStackAlignment);
 
-  // Spill R9 and LR
-  RegList save = (1 << R9);
+  // Spill R4,R9 and LR
+  RegList save = (1 << R9) | (1 << R4);
   __ PushList(save | (1 << LR));
 
   // Move the managed thread pointer into R9.
   __ mov(R9, ShifterOperand(R2));
 
-  // Move frame down for arguments less 2 pushed values above
-  __ AddConstant(SP, -frame_size + (2 * kPointerSize));
+  // Move frame down for arguments less 3 pushed values above
+  __ AddConstant(SP, -frame_size + (3 * kPointerSize));
 
   // Can either get 3 or 2 arguments into registers
   size_t reg_bytes = (method->IsStatic() ? 3 : 2) * kPointerSize;
@@ -112,10 +112,10 @@
     }
   }
 
-  // Remove the frame less the spilled R9 and LR
-  __ AddConstant(SP, frame_size - (2 * kPointerSize));
+  // Remove the frame less the spilled R4, R9 and LR
+  __ AddConstant(SP, frame_size - (3 * kPointerSize));
 
-  // Pop R9 and the LR into PC
+  // Pop R4, R9 and the LR into PC
   __ PopList(save | (1 << PC));
   // TODO: store native_entry in the stub table
   ByteArray* code = ByteArray::Alloc(assembler->CodeSize());
diff --git a/src/runtime_support.S b/src/runtime_support.S
index 24883fc..6522243 100644
--- a/src/runtime_support.S
+++ b/src/runtime_support.S
@@ -159,6 +159,23 @@
     mov     r1, r1, lsr r2              @  r1<- r1 >>> r2
     bx      lr
 
+    .balign 4
+    .global art_test_suspend
+    .extern artCheckSuspendFromCode
+art_test_suspend:
+    /*
+     * Check to see if there's a pending suspend request on our thread.
+     * reset rSUSPEND to SUSPEND_CHECK_INTERVAL.
+     * On entry, rSUSPEND holds the suspend request value
+     * [TUNING: move load of suspend check value into this stub.
+     */
+    cmp    rSUSPEND, #0
+    mov    rSUSPEND, #SUSPEND_CHECK_INTERVAL
+    bxeq   rLR
+    mov    r0, rSELF
+    b      artCheckSuspendFromCode
+
+
 #endif
 
 #if defined(__i386__)
diff --git a/src/runtime_support.h b/src/runtime_support.h
index d421fcc..ed047c9 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -15,6 +15,7 @@
   extern "C" void art_throw_div_zero_from_code();
   extern "C" void art_throw_array_bounds_from_code(int32_t index, int32_t limit);
   extern "C" void art_invoke_interface_trampoline(void*, void*, void*, void*);
+  extern "C" void art_test_suspend();
 
   /* Conversions */
   extern "C" float __aeabi_i2f(int op1);             // OP_INT_TO_FLOAT
diff --git a/src/thread.cc b/src/thread.cc
index d86a0c5..8ab10af 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -178,7 +178,7 @@
   // TODO: throw and unwind on failure.
 }
 
-void CheckSuspendFromCode(Thread* thread) {
+extern "C" void artCheckSuspendFromCode(Thread* thread) {
   Runtime::Current()->GetThreadList()->FullSuspendCheck(thread);
 }
 
@@ -367,6 +367,7 @@
   pThrowArrayBoundsFromCode = art_throw_array_bounds_from_code;
   pThrowDivZeroFromCode = art_throw_div_zero_from_code;
   pInvokeInterfaceTrampoline = art_invoke_interface_trampoline;
+  pTestSuspendFromCode = art_test_suspend;
 #endif
   pDeliverException = art_deliver_exception;
   pF2l = F2L;
@@ -391,7 +392,7 @@
   pLockObjectFromCode = LockObjectFromCode;
   pUnlockObjectFromCode = UnlockObjectFromCode;
   pFindInstanceFieldFromCode = Field::FindInstanceFieldFromCode;
-  pCheckSuspendFromCode = CheckSuspendFromCode;
+  pCheckSuspendFromCode = artCheckSuspendFromCode;
   pStackOverflowFromCode = StackOverflowFromCode;
   pThrowVerificationErrorFromCode = ThrowVerificationErrorFromCode;
   pThrowNegArraySizeFromCode = ThrowNegArraySizeFromCode;
diff --git a/src/thread.h b/src/thread.h
index 03f3ef6..212abdc 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -224,6 +224,7 @@
   StaticStorageBase* (*pInitializeStaticStorage)(uint32_t, const Method*);
   Field* (*pFindInstanceFieldFromCode)(uint32_t, const Method*);
   void (*pCheckSuspendFromCode)(Thread*);
+  void (*pTestSuspendFromCode)();
   void (*pStackOverflowFromCode)(Method*);
   void (*pThrowNullPointerFromCode)();
   void (*pThrowArrayBoundsFromCode)(int32_t, int32_t);