Bug fix for control-flow construction involving nested loops.

Bug: 5884080
Change-Id: Ic2f42abae3e71f9c0729984902396f92902184a3
diff --git a/tests/083-jit-regressions/expected.txt b/tests/083-jit-regressions/expected.txt
index 1f30d21..4b9ad5b 100644
--- a/tests/083-jit-regressions/expected.txt
+++ b/tests/083-jit-regressions/expected.txt
@@ -1,3 +1,4 @@
 b2296099 passes
 b2302318 passes
 b2487514 passes
+b5884080 passes
diff --git a/tests/083-jit-regressions/info.txt b/tests/083-jit-regressions/info.txt
index b791aba..00c24ee 100644
--- a/tests/083-jit-regressions/info.txt
+++ b/tests/083-jit-regressions/info.txt
@@ -8,3 +8,4 @@
 2296099 JIT shift bug
 2302318 Crash during spin-on-suspend testing
 2487514 Missed exception in PriorityBlockingQueueTest.testToArray1_BadArg
+5884080 ICS JIT regression in nested loop formation
diff --git a/tests/083-jit-regressions/src/Main.java b/tests/083-jit-regressions/src/Main.java
index 1f1dee3..3b596db 100644
--- a/tests/083-jit-regressions/src/Main.java
+++ b/tests/083-jit-regressions/src/Main.java
@@ -24,6 +24,7 @@
         b2296099Test();
         b2302318Test();
         b2487514Test();
+        b5884080Test();
     }
 
     static void b2296099Test() throws Exception {
@@ -105,6 +106,26 @@
                                " (expecting 1000)");
         }
     }
+
+    static void b5884080Test() {
+        int vA = 1;
+
+        int l = 0;
+        do
+        {
+            int k = 0;
+            do
+                vA += 1;
+            while(++k < 100);
+        } while(++l < 1000);
+        if (vA == 100001) {
+            System.out.println("b5884080 passes");
+        }
+        else {
+            System.out.println("b5884080 fails: vA is " + vA +
+                               " (expecting 100001)");
+        }
+    }
 }
 
 class SpinThread extends Thread {
diff --git a/vm/compiler/Frontend.cpp b/vm/compiler/Frontend.cpp
index a36eedb..e0226e9 100644
--- a/vm/compiler/Frontend.cpp
+++ b/vm/compiler/Frontend.cpp
@@ -511,7 +511,8 @@
 /* Split an existing block from the specified code offset into two */
 static BasicBlock *splitBlock(CompilationUnit *cUnit,
                               unsigned int codeOffset,
-                              BasicBlock *origBlock)
+                              BasicBlock *origBlock,
+                              BasicBlock **immedPredBlockP)
 {
     MIR *insn = origBlock->firstMIRInsn;
     while (insn) {
@@ -573,16 +574,29 @@
 
     insn->prev->next = NULL;
     insn->prev = NULL;
+
+    /*
+     * Update the immediate predecessor block pointer so that outgoing edges
+     * can be applied to the proper block.
+     */
+    if (immedPredBlockP) {
+        assert(*immedPredBlockP == origBlock);
+        *immedPredBlockP = bottomBlock;
+    }
     return bottomBlock;
 }
 
 /*
  * Given a code offset, find out the block that starts with it. If the offset
- * is in the middle of an existing block, split it into two.
+ * is in the middle of an existing block, split it into two. If immedPredBlockP
+ * is non-null and is the block being split, update *immedPredBlockP to point
+ * to the bottom block so that outgoing edges can be setup properly (by the
+ * caller).
  */
 static BasicBlock *findBlock(CompilationUnit *cUnit,
                              unsigned int codeOffset,
-                             bool split, bool create)
+                             bool split, bool create,
+                             BasicBlock **immedPredBlockP)
 {
     GrowableList *blockList = &cUnit->blockList;
     BasicBlock *bb;
@@ -596,7 +610,9 @@
         if ((split == true) && (codeOffset > bb->startOffset) &&
             (bb->lastMIRInsn != NULL) &&
             (codeOffset <= bb->lastMIRInsn->offset)) {
-            BasicBlock *newBB = splitBlock(cUnit, codeOffset, bb);
+            BasicBlock *newBB = splitBlock(cUnit, codeOffset, bb,
+                                           bb == *immedPredBlockP ?
+                                               immedPredBlockP : NULL);
             return newBB;
         }
     }
@@ -873,7 +889,9 @@
                       /* split */
                       false,
                       /* create */
-                      true);
+                      true,
+                      /* immedPredBlockP */
+                      NULL);
         }
 
         offset = dexCatchIteratorGetEndOffset(&iterator, pCode);
@@ -917,7 +935,9 @@
                                        /* split */
                                        true,
                                        /* create */
-                                       true);
+                                       true,
+                                       /* immedPredBlockP */
+                                       &curBlock);
     curBlock->taken = takenBlock;
     dvmCompilerSetBit(takenBlock->predecessors, curBlock->id);
 
@@ -939,7 +959,9 @@
                                                   */
                                                  true,
                                                  /* create */
-                                                 true);
+                                                 true,
+                                                 /* immedPredBlockP */
+                                                 &curBlock);
         curBlock->fallThrough = fallthroughBlock;
         dvmCompilerSetBit(fallthroughBlock->predecessors, curBlock->id);
     } else if (codePtr < codeEnd) {
@@ -949,7 +971,9 @@
                       /* split */
                       false,
                       /* create */
-                      true);
+                      true,
+                      /* immedPredBlockP */
+                      NULL);
         }
     }
 }
@@ -1013,7 +1037,9 @@
                                           /* split */
                                           true,
                                           /* create */
-                                          true);
+                                          true,
+                                          /* immedPredBlockP */
+                                          &curBlock);
         SuccessorBlockInfo *successorBlockInfo =
             (SuccessorBlockInfo *) dvmCompilerNew(sizeof(SuccessorBlockInfo),
                                                   false);
@@ -1031,7 +1057,9 @@
                                              /* split */
                                              false,
                                              /* create */
-                                             true);
+                                             true,
+                                             /* immedPredBlockP */
+                                             NULL);
     curBlock->fallThrough = fallthroughBlock;
     dvmCompilerSetBit(fallthroughBlock->predecessors, curBlock->id);
 }
@@ -1074,7 +1102,9 @@
                                                /* split */
                                                false,
                                                /* create */
-                                               false);
+                                               false,
+                                               /* immedPredBlockP */
+                                               NULL);
 
             SuccessorBlockInfo *successorBlockInfo =
               (SuccessorBlockInfo *) dvmCompilerNew(sizeof(SuccessorBlockInfo),
@@ -1108,7 +1138,9 @@
                                                      /* split */
                                                      false,
                                                      /* create */
-                                                     true);
+                                                     true,
+                                                     /* immedPredBlockP */
+                                                     NULL);
             /*
              * OP_THROW and OP_THROW_VERIFICATION_ERROR are unconditional
              * branches.
@@ -1226,7 +1258,9 @@
                               /* split */
                               false,
                               /* create */
-                              true);
+                              true,
+                              /* immedPredBlockP */
+                              NULL);
                 }
             }
         } else if (flags & kInstrCanThrow) {
@@ -1240,7 +1274,9 @@
                                           /* split */
                                           false,
                                           /* create */
-                                          false);
+                                          false,
+                                          /* immedPredBlockP */
+                                          NULL);
         if (nextBlock) {
             /*
              * The next instruction could be the target of a previously parsed
@@ -1380,7 +1416,9 @@
                                           /* split */
                                           false,
                                           /* create */
-                                          false);
+                                          false,
+                                          /* immedPredBlockP */
+                                          NULL);
         if (nextBlock) {
             /*
              * The next instruction could be the target of a previously parsed
diff --git a/vm/mterp/common/asm-constants.h b/vm/mterp/common/asm-constants.h
index bbc043c..e1a4df6 100644
--- a/vm/mterp/common/asm-constants.h
+++ b/vm/mterp/common/asm-constants.h
@@ -193,7 +193,7 @@
 MTERP_OFFSET(offThread_jniLocal_topCookie, \
                                 Thread, jniLocalRefTable.segmentState.all, 168)
 #if defined(WITH_SELF_VERIFICATION)
-MTERP_OFFSET(offThread_shadowSpace,       Thread, shadowSpace, 192)
+MTERP_OFFSET(offThread_shadowSpace,       Thread, shadowSpace, 188)
 #endif
 #else
 MTERP_OFFSET(offThread_jniLocal_topCookie, \