Fix chaining offset mis-calculation for translations w/ large switch statements.

Bug: 2369821

There are 12 bytes of additional code after the 65th chaining cell. So if a
switch statement with more than that many cases is translated by the JIT, it
will run fine until the next unchaining event, which will patch the wrong code
and lead to all kinds of unexpected crashes.
diff --git a/vm/compiler/CompilerIR.h b/vm/compiler/CompilerIR.h
index 24e9b37..f5178d8 100644
--- a/vm/compiler/CompilerIR.h
+++ b/vm/compiler/CompilerIR.h
@@ -51,7 +51,9 @@
     kChainingCellInvokeSingleton,
     kChainingCellInvokePredicted,
     kChainingCellBackwardBranch,
-    kChainingCellLast,
+    kChainingCellGap,
+    /* Don't insert new fields between Gap and Last */
+    kChainingCellLast = kChainingCellGap + 1,
     kEntryBlock,
     kDalvikByteCode,
     kExitBlock,
@@ -61,7 +63,7 @@
 
 typedef struct ChainCellCounts {
     union {
-        u1 count[kChainingCellLast];
+        u1 count[kChainingCellLast]; /* include one more space for the gap # */
         u4 dummyForAlignment;
     } u;
 } ChainCellCounts;
@@ -149,8 +151,9 @@
     bool halveInstCount;
     bool executionCount;                // Add code to count trace executions
     bool hasLoop;
-    int numChainingCells[kChainingCellLast];
-    LIR *firstChainingLIR[kChainingCellLast];
+    int numChainingCells[kChainingCellGap];
+    LIR *firstChainingLIR[kChainingCellGap];
+    LIR *chainingCellBottom;
     struct RegisterPool *regPool;
     int optRound;                       // round number to tell an LIR's age
     JitInstructionSetType instructionSet;
diff --git a/vm/compiler/codegen/arm/ArchUtility.c b/vm/compiler/codegen/arm/ArchUtility.c
index d8cac49..20b3f85 100644
--- a/vm/compiler/codegen/arm/ArchUtility.c
+++ b/vm/compiler/codegen/arm/ArchUtility.c
@@ -244,6 +244,9 @@
 
     /* Handle pseudo-ops individually, and all regular insns as a group */
     switch(lir->opCode) {
+        case kArmChainingCellBottom:
+            LOGD("-------- end of chaining cells (0x%04x)\n", offset);
+            break;
         case kArmPseudoBarrier:
             LOGD("-------- BARRIER");
             break;
diff --git a/vm/compiler/codegen/arm/ArmLIR.h b/vm/compiler/codegen/arm/ArmLIR.h
index 8772b79..3254ff7 100644
--- a/vm/compiler/codegen/arm/ArmLIR.h
+++ b/vm/compiler/codegen/arm/ArmLIR.h
@@ -296,6 +296,7 @@
  * Assemble.c.
  */
 typedef enum ArmOpCode {
+    kArmChainingCellBottom = -18,
     kArmPseudoBarrier = -17,
     kArmPseudoExtended = -16,
     kArmPseudoSSARep = -15,
diff --git a/vm/compiler/codegen/arm/Assemble.c b/vm/compiler/codegen/arm/Assemble.c
index 7444b3e..7c16ff9 100644
--- a/vm/compiler/codegen/arm/Assemble.c
+++ b/vm/compiler/codegen/arm/Assemble.c
@@ -1126,7 +1126,9 @@
  *   |  .                            .
  *   |  |                            |
  *   |  +----------------------------+
- *   +->| Chaining cell counts       |  -> 4 bytes, chain cell counts by type
+ *   |  | Gap for large switch stmt  |  -> # cases >= MAX_CHAINED_SWITCH_CASES
+ *   |  +----------------------------+
+ *   +->| Chaining cell counts       |  -> 8 bytes, chain cell counts by type
  *      +----------------------------+
  *      | Trace description          |  -> variable sized
  *      .                            .
@@ -1150,6 +1152,7 @@
     int i;
     ChainCellCounts chainCellCounts;
     int descSize = jitTraceDescriptionSize(cUnit->traceDesc);
+    int chainingCellGap;
 
     info->instructionSet = cUnit->instructionSet;
 
@@ -1175,6 +1178,13 @@
     /* Const values have to be word aligned */
     offset = (offset + 3) & ~3;
 
+    /*
+     * Get the gap (# of u4) between the offset of chaining cell count and
+     * the bottom of real chaining cells. If the translation has chaining
+     * cells, the gap is guaranteed to be multiples of 4.
+     */
+    chainingCellGap = (offset - cUnit->chainingCellBottom->offset) >> 2;
+
     /* Add space for chain cell counts & trace description */
     u4 chainCellOffset = offset;
     ArmLIR *chainCellOffsetLIR = (ArmLIR *) cUnit->chainCellOffsetLIR;
@@ -1243,9 +1253,13 @@
     gDvmJit.numCompilations++;
 
     /* Install the chaining cell counts */
-    for (i=0; i< kChainingCellLast; i++) {
+    for (i=0; i< kChainingCellGap; i++) {
         chainCellCounts.u.count[i] = cUnit->numChainingCells[i];
     }
+
+    /* Set the gap number in the chaining cell count structure */
+    chainCellCounts.u.count[kChainingCellGap] = chainingCellGap;
+
     memcpy((char*)cUnit->baseAddr + chainCellOffset, &chainCellCounts,
            sizeof(chainCellCounts));
 
@@ -1491,7 +1505,7 @@
     PredictedChainingCell *predChainCell;
 
     /* Get total count of chain cells */
-    for (i = 0, cellSize = 0; i < kChainingCellLast; i++) {
+    for (i = 0, cellSize = 0; i < kChainingCellGap; i++) {
         if (i != kChainingCellInvokePredicted) {
             cellSize += pChainCellCounts->u.count[i] * 2;
         } else {
@@ -1499,11 +1513,15 @@
         }
     }
 
+    if (cellSize == 0)
+        return (u4 *) pChainCellCounts;
+
     /* Locate the beginning of the chain cell region */
-    pStart = pChainCells = ((u4 *) pChainCellCounts) - cellSize;
+    pStart = pChainCells = ((u4 *) pChainCellCounts) - cellSize -
+             pChainCellCounts->u.count[kChainingCellGap];
 
     /* The cells are sorted in order - walk through them and reset */
-    for (i = 0; i < kChainingCellLast; i++) {
+    for (i = 0; i < kChainingCellGap; i++) {
         int elemSize = 2; /* Most chaining cell has two words */
         if (i == kChainingCellInvokePredicted) {
             elemSize = 4;
diff --git a/vm/compiler/codegen/arm/CodegenDriver.c b/vm/compiler/codegen/arm/CodegenDriver.c
index d6cb5d6..f92e347 100644
--- a/vm/compiler/codegen/arm/CodegenDriver.c
+++ b/vm/compiler/codegen/arm/CodegenDriver.c
@@ -3703,13 +3703,13 @@
     /* Used to hold the labels of each block */
     ArmLIR *labelList =
         dvmCompilerNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
-    GrowableList chainingListByType[kChainingCellLast];
+    GrowableList chainingListByType[kChainingCellGap];
     int i;
 
     /*
      * Initialize various types chaining lists.
      */
-    for (i = 0; i < kChainingCellLast; i++) {
+    for (i = 0; i < kChainingCellGap; i++) {
         dvmInitGrowableList(&chainingListByType[i], 2);
     }
 
@@ -3756,7 +3756,7 @@
 
         labelList[i].operands[0] = blockList[i]->startOffset;
 
-        if (blockList[i]->blockType >= kChainingCellLast) {
+        if (blockList[i]->blockType >= kChainingCellGap) {
             /*
              * Append the label pseudo LIR first. Chaining cells will be handled
              * separately afterwards.
@@ -4023,7 +4023,7 @@
     }
 
     /* Handle the chaining cells in predefined order */
-    for (i = 0; i < kChainingCellLast; i++) {
+    for (i = 0; i < kChainingCellGap; i++) {
         size_t j;
         int *blockIdList = (int *) chainingListByType[i].elemList;
 
@@ -4076,6 +4076,9 @@
         }
     }
 
+    /* Mark the bottom of chaining cells */
+    cUnit->chainingCellBottom = (LIR *) newLIR0(cUnit, kArmChainingCellBottom);
+
     /*
      * Generate the branch to the dvmJitToInterpNoChain entry point at the end
      * of all chaining cells for the overflow cases.
diff --git a/vm/compiler/codegen/arm/armv7-a/ArchVariant.c b/vm/compiler/codegen/arm/armv7-a/ArchVariant.c
index c08d7b2..cd8754c 100644
--- a/vm/compiler/codegen/arm/armv7-a/ArchVariant.c
+++ b/vm/compiler/codegen/arm/armv7-a/ArchVariant.c
@@ -47,12 +47,11 @@
     /* Target-specific configuration */
     gDvmJit.jitTableSize = 1 << 12; // 4096
     gDvmJit.jitTableMask = gDvmJit.jitTableSize - 1;
-    gDvmJit.threshold = 200;
+    gDvmJit.threshold = 40;
 
 #if defined(WITH_SELF_VERIFICATION)
-    /* Force into blocking, translate everything mode */
+    /* Force into blocking */
     gDvmJit.blockingMode = true;
-    gDvmJit.threshold = 5;
 #endif
 
     /* Codegen-specific assumptions */