Set "needFallThroughBranch" flag during block split.

Bonus changes:
* Add a undefined Thumb instruction between the last code block and the
  beginning of PC reconstruction cell to capture such codegen problem on
  the spot.
* Fix a loop formation problem to exclude nested loops.

Bug: 4320840
Change-Id: I49d3fbba0073d8c2d4a0b241258239cb952c6bdd
diff --git a/vm/compiler/Frontend.c b/vm/compiler/Frontend.c
index 1338acc..f8cd2f1 100644
--- a/vm/compiler/Frontend.c
+++ b/vm/compiler/Frontend.c
@@ -564,6 +564,7 @@
     }
 
     /* Handle the fallthrough path */
+    bottomBlock->needFallThroughBranch = origBlock->needFallThroughBranch;
     bottomBlock->fallThrough = origBlock->fallThrough;
     origBlock->fallThrough = bottomBlock;
     origBlock->needFallThroughBranch = true;
diff --git a/vm/compiler/Loop.c b/vm/compiler/Loop.c
index ba8714c..b99da7e 100644
--- a/vm/compiler/Loop.c
+++ b/vm/compiler/Loop.c
@@ -477,7 +477,23 @@
      */
     while (true) {
         /* Loop formed */
-        if (bodyBB->taken == firstBB || bodyBB->fallThrough == firstBB) break;
+        if (bodyBB->taken == firstBB) {
+            /* Check if the fallThrough edge will cause a nested loop */
+            if (bodyBB->fallThrough &&
+                dvmIsBitSet(cUnit->tempBlockV, bodyBB->fallThrough->id)) {
+                return false;
+            }
+            /* Single loop formed */
+            break;
+        } else if (bodyBB->fallThrough == firstBB) {
+            /* Check if the taken edge will cause a nested loop */
+            if (bodyBB->taken &&
+                dvmIsBitSet(cUnit->tempBlockV, bodyBB->taken->id)) {
+                return false;
+            }
+            /* Single loop formed */
+            break;
+        }
 
         /* Inner loops formed first - quit */
         if (bodyBB->fallThrough &&
diff --git a/vm/compiler/codegen/arm/ArmLIR.h b/vm/compiler/codegen/arm/ArmLIR.h
index c47c291..a187cfa 100644
--- a/vm/compiler/codegen/arm/ArmLIR.h
+++ b/vm/compiler/codegen/arm/ArmLIR.h
@@ -627,7 +627,7 @@
     kThumb2Dmb,          /* dmb [1111001110111111100011110101] option[3-0] */
     kThumb2LdrPcReln12,  /* ldr rd,[pc,-#imm12] [1111100011011111] rt[15-12]
                                   imm12[11-0] */
-
+    kThumbUndefined,     /* undefined [11011110xxxxxxxx] */
     kArmLast,
 } ArmOpcode;
 
diff --git a/vm/compiler/codegen/arm/Assemble.c b/vm/compiler/codegen/arm/Assemble.c
index 83fec33..7c22de7 100644
--- a/vm/compiler/codegen/arm/Assemble.c
+++ b/vm/compiler/codegen/arm/Assemble.c
@@ -881,6 +881,10 @@
                  kFmtUnused, -1, -1,
                  IS_BINARY_OP | REG_DEF0 | REG_USE_PC | IS_LOAD,
                  "ldr", "r!0d, [r15pc, -#!1d]", 2),
+    ENCODING_MAP(kThumbUndefined,       0xde00,
+                 kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, NO_OPERAND,
+                 "undefined", "", 1),
 };
 
 /*
diff --git a/vm/compiler/codegen/arm/CodegenDriver.c b/vm/compiler/codegen/arm/CodegenDriver.c
index 6060ab7..599df90 100644
--- a/vm/compiler/codegen/arm/CodegenDriver.c
+++ b/vm/compiler/codegen/arm/CodegenDriver.c
@@ -3896,6 +3896,15 @@
         (ArmLIR **) cUnit->pcReconstructionList.elemList;
     int numElems = cUnit->pcReconstructionList.numUsed;
     int i;
+
+    /*
+     * We should never reach here through fall-through code, so insert
+     * a bomb to signal troubles immediately.
+     */
+    if (numElems) {
+        newLIR0(cUnit, kThumbUndefined);
+    }
+
     for (i = 0; i < numElems; i++) {
         dvmCompilerAppendLIR(cUnit, (LIR *) pcrLabel[i]);
         /* r0 = dalvik PC */