CFG rework for explicit exception edges

Previously, basic blocks were terminated by any Dalvik opcode
which might throw, and the exception edges were represented
as a list of successor basic blocks.  This resulted in a
SSA renaming bug: any Dalvik register definition caused by
a throwing instruction (such as IGET) would incorrectly be considered
to be visible across the exception edges.  For the Art compiler (and JIT)
this was a benign bug.  But for llvm, it means an invalid CFG.

The other problem this CL is addressing is the llvm bitcode requirement
that all exception edges be explicit.  Because we can't use
the llvm bitcode "invoke" (it doesn't match our exception handling),
all exception edges must be represented as explicit branches in the
bitcode (further contributing to the llvm bitcode bloat).

We split all potentially throwing instructions into two parts: a
check prologue followed by the body.  If there are any catch blocks
associated with the potentially throwing instruction, we make a call
to the intrinisc dex_lang_catch_targets().  Though it should never
expand into actual code, this intrinsic returns a switch key that
feeds into an immediately-following switch statement.  That switch
statement will include edges to all necessary catch blocks, with the
default target referencing the block conaining the "work" portion of
the pair.

Included in this CL are also fixes for .dot file generation
(previously there was an issue with non-unique block names), and an
enhancement to include the block number on Phi incoming arcs.

Also reworked dissasembly to use StringPrintf.

Note: the insertion of new basic blocks following computation of
depth-first-search order badly degrades code layout.  DFS order
computation can be expensive, so I'll be looking for a workaround
in a future CL to avoid a full dfs order regeneration.

With this CL, the device boots, all target tests pass, all methods
are converted to Greenland Bitcode and all well-formed converted methods
pass llvm's function validation pass without error or warning.

We still have some cts failures related to the verifier's
instruction rewriting to THROW_VERIFICATION_ERROR.  In those cases
we can have a malformed graph - but we still must be able to convert
it to legal llvm bitcode.  If executed, it will throw.

We'll detect that situation and bitcast these mismatches away in a
subsequent CL.

Change-Id: I9fa359c912e25ca6a75e2f69d0975126d0687c33
diff --git a/src/compiler/Compiler.h b/src/compiler/Compiler.h
index 088768b..af472b9 100644
--- a/src/compiler/Compiler.h
+++ b/src/compiler/Compiler.h
@@ -129,6 +129,7 @@
   kDebugCountOpcodes,
 #if defined(ART_USE_QUICK_COMPILER)
   kDebugDumpBitcodeFile,
+  kDebugVerifyBitcode,
 #endif
 };
 
diff --git a/src/compiler/CompilerIR.h b/src/compiler/CompilerIR.h
index 1ecf61a..43cfa2f 100644
--- a/src/compiler/CompilerIR.h
+++ b/src/compiler/CompilerIR.h
@@ -196,9 +196,10 @@
   kMirOpFusedCmpgDouble,
   kMirOpFusedCmpLong,
   kMirOpNop,
-  kMirOpNullNRangeUpCheck,
-  kMirOpNullNRangeDownCheck,
-  kMirOpLowerBound,
+  kMirOpNullCheck,
+  kMirOpRangeCheck,
+  kMirOpDivZeroCheck,
+  kMirOpCheck,
   kMirOpLast,
 };
 
@@ -245,12 +246,10 @@
   int optimizationFlags;
   int seqNum;
   union {
-    // Used by the inlined insn from the callee to find the mother method
-    const Method* calleeMethod;
-    // Used by the inlined invoke to find the class and method pointers
-    CallsiteInfo* callsiteInfo;
     // Used to quickly locate all Phi opcodes
     MIR* phiNext;
+    // Establish link between two halves of throwing instructions
+    MIR* throwInsn;
   } meta;
 };
 
@@ -278,7 +277,6 @@
   uint16_t nestingDepth;
   const Method* containingMethod;     // For blocks from the callee
   BBType blockType;
-  bool needFallThroughBranch;         // For blocks ended due to length limit
   bool isFallThroughFromInvoke;       // True means the block needs alignment
   MIR* firstMIRInsn;
   MIR* lastMIRInsn;
diff --git a/src/compiler/Dataflow.cc b/src/compiler/Dataflow.cc
index ca9d865..38d18ac 100644
--- a/src/compiler/Dataflow.cc
+++ b/src/compiler/Dataflow.cc
@@ -822,13 +822,16 @@
   // 107 MIR_NOP
   DF_NOP,
 
-  // 108 MIR_NULL_RANGE_UP_CHECK
+  // 108 MIR_NULL_CHECK
   0,
 
-  // 109 MIR_NULL_RANGE_DOWN_CHECK
+  // 109 MIR_RANGE_CHECK
   0,
 
-  // 110 MIR_LOWER_BOUND
+  // 110 MIR_DIV_ZERO_CHECK
+  0,
+
+  // 111 MIR_CHECK
   0,
 };
 
@@ -855,27 +858,29 @@
 char* oatGetDalvikDisassembly(CompilationUnit* cUnit,
                               const DecodedInstruction& insn, const char* note)
 {
-  char buffer[256];
-  Instruction::Code opcode = insn.opcode;
+  std::string str;
+  int opcode = insn.opcode;
   int dfAttributes = oatDataFlowAttributes[opcode];
   int flags;
   char* ret;
 
-  buffer[0] = 0;
-  if ((int)opcode >= (int)kMirOpFirst) {
-    if ((int)opcode == (int)kMirOpPhi) {
-      strcpy(buffer, "PHI");
+  if (opcode >= kMirOpFirst) {
+    if (opcode == kMirOpPhi) {
+      str.append("PHI");
+    } else if (opcode == kMirOpCheck) {
+      str.append("Check");
     } else {
-      sprintf(buffer, "Opcode %#x", opcode);
+      str.append(StringPrintf("Opcode %#x", opcode));
     }
     flags = 0;
   } else {
-    strcpy(buffer, Instruction::Name(opcode));
-    flags = Instruction::Flags(opcode);
+    str.append(Instruction::Name(insn.opcode));
+    flags = Instruction::Flags(insn.opcode);
   }
 
-  if (note)
-    strcat(buffer, note);
+  if (note) {
+    str.append(note);
+  }
 
   /* For branches, decode the instructions to print out the branch targets */
   if (flags & Instruction::kBranch) {
@@ -883,11 +888,11 @@
     int offset = 0;
     switch (dalvikFormat) {
       case Instruction::k21t:
-        snprintf(buffer + strlen(buffer), 256, " v%d,", insn.vA);
+        str.append(StringPrintf(" v%d,", insn.vA));
         offset = (int) insn.vB;
         break;
       case Instruction::k22t:
-        snprintf(buffer + strlen(buffer), 256, " v%d, v%d,", insn.vA, insn.vB);
+        str.append(StringPrintf(" v%d, v%d,", insn.vA, insn.vB));
         offset = (int) insn.vC;
         break;
       case Instruction::k10t:
@@ -899,45 +904,43 @@
         LOG(FATAL) << "Unexpected branch format " << (int)dalvikFormat
                    << " / opcode " << (int)opcode;
     }
-    snprintf(buffer + strlen(buffer), 256, " (%c%x)",
-             offset > 0 ? '+' : '-',
-             offset > 0 ? offset : -offset);
+    str.append(StringPrintf(" (%c%x)",
+                            offset > 0 ? '+' : '-',
+                            offset > 0 ? offset : -offset));
   } else if (dfAttributes & DF_FORMAT_35C) {
     unsigned int i;
     for (i = 0; i < insn.vA; i++) {
-      if (i != 0) strcat(buffer, ",");
-        snprintf(buffer + strlen(buffer), 256, " v%d", insn.arg[i]);
+      if (i != 0) str.append(",");
+      str.append(StringPrintf(" v%d", insn.arg[i]));
     }
   }
   else if (dfAttributes & DF_FORMAT_3RC) {
-    snprintf(buffer + strlen(buffer), 256,
-             " v%d..v%d", insn.vC, insn.vC + insn.vA - 1);
+    str.append(StringPrintf(" v%d..v%d", insn.vC, insn.vC + insn.vA - 1));
   } else {
     if (dfAttributes & DF_A_IS_REG) {
-      snprintf(buffer + strlen(buffer), 256, " v%d", insn.vA);
+      str.append(StringPrintf(" v%d", insn.vA));
     }
     if (dfAttributes & DF_B_IS_REG) {
-      snprintf(buffer + strlen(buffer), 256, ", v%d", insn.vB);
+      str.append(StringPrintf(", v%d", insn.vB));
     } else if ((int)opcode < (int)kMirOpFirst) {
-      snprintf(buffer + strlen(buffer), 256, ", (#%d)", insn.vB);
+      str.append(StringPrintf(", (#%d)", insn.vB));
     }
     if (dfAttributes & DF_C_IS_REG) {
-      snprintf(buffer + strlen(buffer), 256, ", v%d", insn.vC);
+      str.append(StringPrintf(", v%d", insn.vC));
     } else if ((int)opcode < (int)kMirOpFirst) {
-      snprintf(buffer + strlen(buffer), 256, ", (#%d)", insn.vC);
+      str.append(StringPrintf(", (#%d)", insn.vC));
     }
   }
-  int length = strlen(buffer) + 1;
+  int length = str.length() + 1;
   ret = (char*)oatNew(cUnit, length, false, kAllocDFInfo);
-  memcpy(ret, buffer, length);
+  strncpy(ret, str.c_str(), length);
   return ret;
 }
 
-char* getSSAName(const CompilationUnit* cUnit, int ssaReg, char* name)
+std::string getSSAName(const CompilationUnit* cUnit, int ssaReg)
 {
-  sprintf(name, "v%d_%d", SRegToVReg(cUnit, ssaReg),
-          SRegToSubscript(cUnit, ssaReg));
-  return name;
+  return StringPrintf("v%d_%d", SRegToVReg(cUnit, ssaReg),
+                     SRegToSubscript(cUnit, ssaReg));
 }
 
 /*
@@ -945,32 +948,38 @@
  */
 char* oatFullDisassembler(CompilationUnit* cUnit, const MIR* mir)
 {
-  char buffer[256];
-  char operand0[32], operand1[32];
+  std::string str;
   const DecodedInstruction* insn = &mir->dalvikInsn;
-  Instruction::Code opcode = insn->opcode;
+  int opcode = insn->opcode;
   int dfAttributes = oatDataFlowAttributes[opcode];
   char* ret;
   int length;
 
-  buffer[0] = 0;
-  if (static_cast<int>(opcode) >= static_cast<int>(kMirOpFirst)) {
-    if (static_cast<int>(opcode) == static_cast<int>(kMirOpPhi)) {
-      snprintf(buffer, 256, "PHI %s = (%s",
-               getSSAName(cUnit, mir->ssaRep->defs[0], operand0),
-               getSSAName(cUnit, mir->ssaRep->uses[0], operand1));
+  if (opcode >= kMirOpFirst) {
+    if (opcode == kMirOpPhi) {
+      int* incoming = (int*)mir->dalvikInsn.vB;
+      str.append(StringPrintf("PHI %s = (%s",
+                 getSSAName(cUnit, mir->ssaRep->defs[0]).c_str(),
+                 getSSAName(cUnit, mir->ssaRep->uses[0]).c_str()));
+      str.append(StringPrintf(":%d",incoming[0]));
       int i;
       for (i = 1; i < mir->ssaRep->numUses; i++) {
-        snprintf(buffer + strlen(buffer), 256, ", %s",
-        getSSAName(cUnit, mir->ssaRep->uses[i], operand0));
+        str.append(StringPrintf(", %s:%d",
+                                getSSAName(cUnit, mir->ssaRep->uses[i]).c_str(),
+                                incoming[i]));
       }
-      snprintf(buffer + strlen(buffer), 256, ")");
+      str.append(")");
+    } else if (opcode == kMirOpCheck) {
+      str.append("Check ");
+      str.append(Instruction::Name(mir->meta.throwInsn->dalvikInsn.opcode));
+    } else if (opcode == kMirOpNop) {
+      str.append("MirNop");
     } else {
-      sprintf(buffer, "Opcode %#x", opcode);
+      str.append(StringPrintf("Opcode %#x", opcode));
     }
     goto done;
   } else {
-    strcpy(buffer, Instruction::Name(opcode));
+    str.append(Instruction::Name(insn->opcode));
   }
 
   /* For branches, decode the instructions to print out the branch targets */
@@ -979,14 +988,14 @@
     int delta = 0;
     switch (dalvikFormat) {
       case Instruction::k21t:
-        snprintf(buffer + strlen(buffer), 256, " %s, ",
-                 getSSAName(cUnit, mir->ssaRep->uses[0], operand0));
+        str.append(StringPrintf(" %s, ",
+                   getSSAName(cUnit, mir->ssaRep->uses[0]).c_str()));
         delta = (int) insn->vB;
         break;
       case Instruction::k22t:
-        snprintf(buffer + strlen(buffer), 256, " %s, %s, ",
-                 getSSAName(cUnit, mir->ssaRep->uses[0], operand0),
-                 getSSAName(cUnit, mir->ssaRep->uses[1], operand1));
+        str.append(StringPrintf(" %s, %s, ",
+                 getSSAName(cUnit, mir->ssaRep->uses[0]).c_str(),
+                 getSSAName(cUnit, mir->ssaRep->uses[1]).c_str()));
         delta = (int) insn->vC;
         break;
       case Instruction::k10t:
@@ -997,54 +1006,53 @@
       default:
         LOG(FATAL) << "Unexpected branch format: " << (int)dalvikFormat;
       }
-      snprintf(buffer + strlen(buffer), 256, " %04x",
-               mir->offset + delta);
+      str.append(StringPrintf(" %04x", mir->offset + delta));
   } else if (dfAttributes & (DF_FORMAT_35C | DF_FORMAT_3RC)) {
     unsigned int i;
     for (i = 0; i < insn->vA; i++) {
-      if (i != 0) strcat(buffer, ",");
-        snprintf(buffer + strlen(buffer), 256, " %s",
-                 getSSAName(cUnit, mir->ssaRep->uses[i], operand0));
+      if (i != 0) str.append(",");
+        str.append(" ");
+        str.append(getSSAName(cUnit, mir->ssaRep->uses[i]));
     }
   } else {
     int udIdx;
     if (mir->ssaRep->numDefs) {
 
       for (udIdx = 0; udIdx < mir->ssaRep->numDefs; udIdx++) {
-        snprintf(buffer + strlen(buffer), 256, " %s",
-                 getSSAName(cUnit, mir->ssaRep->defs[udIdx], operand0));
+        str.append(" ");
+        str.append(getSSAName(cUnit, mir->ssaRep->defs[udIdx]));
       }
-      strcat(buffer, ",");
+      str.append(",");
     }
     if (mir->ssaRep->numUses) {
       /* No leading ',' for the first use */
-      snprintf(buffer + strlen(buffer), 256, " %s",
-               getSSAName(cUnit, mir->ssaRep->uses[0], operand0));
+      str.append(" ");
+      str.append(getSSAName(cUnit, mir->ssaRep->uses[0]));
       for (udIdx = 1; udIdx < mir->ssaRep->numUses; udIdx++) {
-        snprintf(buffer + strlen(buffer), 256, ", %s",
-                 getSSAName(cUnit, mir->ssaRep->uses[udIdx], operand0));
+        str.append(", ");
+        str.append(getSSAName(cUnit, mir->ssaRep->uses[udIdx]));
         }
       }
       if (static_cast<int>(opcode) < static_cast<int>(kMirOpFirst)) {
-        Instruction::Format dalvikFormat = Instruction::FormatOf(opcode);
+        Instruction::Format dalvikFormat = Instruction::FormatOf(insn->opcode);
         switch (dalvikFormat) {
           case Instruction::k11n:        // op vA, #+B
           case Instruction::k21s:        // op vAA, #+BBBB
           case Instruction::k21h:        // op vAA, #+BBBB00000[00000000]
           case Instruction::k31i:        // op vAA, #+BBBBBBBB
           case Instruction::k51l:        // op vAA, #+BBBBBBBBBBBBBBBB
-            snprintf(buffer + strlen(buffer), 256, " #%#x", insn->vB);
+            str.append(StringPrintf(" #%#x", insn->vB));
             break;
           case Instruction::k21c:        // op vAA, thing@BBBB
           case Instruction::k31c:        // op vAA, thing@BBBBBBBB
-            snprintf(buffer + strlen(buffer), 256, " @%#x", insn->vB);
+            str.append(StringPrintf(" @%#x", insn->vB));
             break;
           case Instruction::k22b:        // op vAA, vBB, #+CC
           case Instruction::k22s:        // op vA, vB, #+CCCC
-            snprintf(buffer + strlen(buffer), 256, " #%#x", insn->vC);
+            str.append(StringPrintf(" #%#x", insn->vC));
             break;
           case Instruction::k22c:        // op vA, vB, thing@CCCC
-            snprintf(buffer + strlen(buffer), 256, " @%#x", insn->vC);
+            str.append(StringPrintf(" @%#x", insn->vC));
             break;
           /* No need for special printing */
           default:
@@ -1054,44 +1062,38 @@
   }
 
 done:
-  length = strlen(buffer) + 1;
+  length = str.length() + 1;
   ret = (char*) oatNew(cUnit, length, false, kAllocDFInfo);
-  memcpy(ret, buffer, length);
+  strncpy(ret, str.c_str(), length);
   return ret;
 }
 
 char* oatGetSSAString(CompilationUnit* cUnit, SSARepresentation* ssaRep)
 {
-  char buffer[256];
+  std::string str;
   char* ret;
   int i;
 
-  buffer[0] = 0;
   for (i = 0; i < ssaRep->numDefs; i++) {
     int ssaReg = ssaRep->defs[i];
-    sprintf(buffer + strlen(buffer), "s%d(v%d_%d) ", ssaReg,
-            SRegToVReg(cUnit, ssaReg), SRegToSubscript(cUnit, ssaReg));
+    str.append(StringPrintf("s%d(v%d_%d) ", ssaReg,
+                            SRegToVReg(cUnit, ssaReg),
+                            SRegToSubscript(cUnit, ssaReg)));
   }
 
   if (ssaRep->numDefs) {
-    strcat(buffer, "<- ");
+    str.append("<- ");
   }
 
   for (i = 0; i < ssaRep->numUses; i++) {
-    int len = strlen(buffer);
     int ssaReg = ssaRep->uses[i];
-
-    if (snprintf(buffer + len, 250 - len, "s%d(v%d_%d) ", ssaReg,
-                 SRegToVReg(cUnit, ssaReg),
-                 SRegToSubscript(cUnit, ssaReg))) {
-      strcat(buffer, "...");
-      break;
-    }
+    str.append(StringPrintf("s%d(v%d_%d) ", ssaReg, SRegToVReg(cUnit, ssaReg),
+               SRegToSubscript(cUnit, ssaReg)));
   }
 
-  int length = strlen(buffer) + 1;
+  int length = str.length() + 1;
   ret = (char*)oatNew(cUnit, length, false, kAllocDFInfo);
-  memcpy(ret, buffer, length);
+  strncpy(ret, str.c_str(), length);
   return ret;
 }
 
@@ -1183,8 +1185,10 @@
   int ssaReg = cUnit->numSSARegs++;
   oatInsertGrowableList(cUnit, cUnit->ssaBaseVRegs, vReg);
   oatInsertGrowableList(cUnit, cUnit->ssaSubscripts, subscript);
-  char* name = (char*)oatNew(cUnit, SSA_NAME_MAX, true, kAllocDFInfo);
-  oatInsertGrowableList(cUnit, cUnit->ssaStrings, (intptr_t)getSSAName(cUnit, ssaReg, name));
+  std::string ssaName = getSSAName(cUnit, ssaReg);
+  char* name = (char*)oatNew(cUnit, ssaName.length() + 1, false, kAllocDFInfo);
+  strncpy(name, ssaName.c_str(), ssaName.length() + 1);
+  oatInsertGrowableList(cUnit, cUnit->ssaStrings, (intptr_t)name);
   DCHECK_EQ(cUnit->ssaBaseVRegs->numUsed, cUnit->ssaSubscripts->numUsed);
   return ssaReg;
 }
@@ -1492,8 +1496,10 @@
   for (i = 0; i < numDalvikReg; i++) {
     oatInsertGrowableList(cUnit, cUnit->ssaBaseVRegs, i);
     oatInsertGrowableList(cUnit, cUnit->ssaSubscripts, 0);
-    char* name = (char*)oatNew(cUnit, SSA_NAME_MAX, true, kAllocDFInfo);
-    oatInsertGrowableList(cUnit, cUnit->ssaStrings, (intptr_t)getSSAName(cUnit, i, name));
+    std::string ssaName = getSSAName(cUnit, i);
+    char* name = (char*)oatNew(cUnit, ssaName.length() + 1, true, kAllocDFInfo);
+    strncpy(name, ssaName.c_str(), ssaName.length() + 1);
+    oatInsertGrowableList(cUnit, cUnit->ssaStrings, (intptr_t)name);
   }
 
   /*
@@ -1687,14 +1693,14 @@
   BasicBlock* tbb = bb;
   mir = advanceMIR(cUnit, &tbb, mir, NULL, false);
   while (mir != NULL) {
+    int opcode = mir->dalvikInsn.opcode;
     if ((mir->dalvikInsn.opcode == Instruction::MOVE_RESULT) ||
         (mir->dalvikInsn.opcode == Instruction::MOVE_RESULT_OBJECT) ||
         (mir->dalvikInsn.opcode == Instruction::MOVE_RESULT_WIDE)) {
       break;
     }
     // Keep going if pseudo op, otherwise terminate
-    if (mir->dalvikInsn.opcode <
-        static_cast<Instruction::Code>(kNumPackedOpcodes)) {
+    if (opcode < kNumPackedOpcodes) {
       mir = NULL;
     } else {
       mir = advanceMIR(cUnit, &tbb, mir, NULL, false);
diff --git a/src/compiler/Frontend.cc b/src/compiler/Frontend.cc
index b68233b..6b45f0d 100644
--- a/src/compiler/Frontend.cc
+++ b/src/compiler/Frontend.cc
@@ -54,6 +54,7 @@
   //(1 << kDebugCountOpcodes) |
 #if defined(ART_USE_QUICK_COMPILER)
   //(1 << kDebugDumpBitcodeFile) |
+  //(1 << kDebugVerifyBitcode) |
 #endif
   0;
 
@@ -154,10 +155,8 @@
   }
 
   /* Handle the fallthrough path */
-  bottomBlock->needFallThroughBranch = origBlock->needFallThroughBranch;
   bottomBlock->fallThrough = origBlock->fallThrough;
   origBlock->fallThrough = bottomBlock;
-  origBlock->needFallThroughBranch = true;
   oatInsertGrowableList(cUnit, bottomBlock->predecessors,
                         (intptr_t)origBlock);
   if (bottomBlock->fallThrough) {
@@ -289,12 +288,12 @@
                                                               blockIdx);
     if (bb == NULL) break;
     if (bb->blockType == kEntryBlock) {
-      fprintf(file, "  entry [shape=Mdiamond];\n");
+      fprintf(file, "  entry_%d [shape=Mdiamond];\n", bb->id);
     } else if (bb->blockType == kExitBlock) {
-      fprintf(file, "  exit [shape=Mdiamond];\n");
+      fprintf(file, "  exit_%d [shape=Mdiamond];\n", bb->id);
     } else if (bb->blockType == kDalvikByteCode) {
-      fprintf(file, "  block%04x [shape=record,label = \"{ \\\n",
-              bb->startOffset);
+      fprintf(file, "  block%04x_%d [shape=record,label = \"{ \\\n",
+              bb->startOffset, bb->id);
       const MIR *mir;
         fprintf(file, "    {block id %d\\l}%s\\\n", bb->id,
                 bb->firstMIRInsn ? " | " : " ");
@@ -327,8 +326,8 @@
     }
 
     if (bb->successorBlockList.blockListType != kNotUsed) {
-      fprintf(file, "  succ%04x [shape=%s,label = \"{ \\\n",
-              bb->startOffset,
+      fprintf(file, "  succ%04x_%d [shape=%s,label = \"{ \\\n",
+              bb->startOffset, bb->id,
               (bb->successorBlockList.blockListType == kCatch) ?
                "Mrecord" : "record");
       GrowableListIterator iterator;
@@ -356,8 +355,8 @@
       fprintf(file, "  }\"];\n\n");
 
       oatGetBlockName(bb, blockName1);
-      fprintf(file, "  %s:s -> succ%04x:n [style=dashed]\n",
-              blockName1, bb->startOffset);
+      fprintf(file, "  %s:s -> succ%04x_%d:n [style=dashed]\n",
+              blockName1, bb->startOffset, bb->id);
 
       if (bb->successorBlockList.blockListType == kPackedSwitch ||
           bb->successorBlockList.blockListType == kSparseSwitch) {
@@ -374,8 +373,8 @@
           BasicBlock *destBlock = successorBlockInfo->block;
 
           oatGetBlockName(destBlock, blockName2);
-          fprintf(file, "  succ%04x:f%d:e -> %s:n\n", bb->startOffset,
-                  succId++, blockName2);
+          fprintf(file, "  succ%04x_%d:f%d:e -> %s:n\n", bb->startOffset,
+                  bb->id, succId++, blockName2);
         }
       }
     }
@@ -644,18 +643,20 @@
 }
 
 /* Process instructions with the kThrow flag */
-void processCanThrow(CompilationUnit* cUnit, BasicBlock* curBlock, MIR* insn,
-                     int curOffset, int width, int flags,
-                     ArenaBitVector* tryBlockAddr, const u2* codePtr,
-                     const u2* codeEnd)
+BasicBlock* processCanThrow(CompilationUnit* cUnit, BasicBlock* curBlock,
+                            MIR* insn, int curOffset, int width, int flags,
+                            ArenaBitVector* tryBlockAddr, const u2* codePtr,
+                            const u2* codeEnd)
 {
   const DexFile::CodeItem* code_item = cUnit->code_item;
+  bool inTryBlock = oatIsBitSet(tryBlockAddr, curOffset);
 
   /* In try block */
-  if (oatIsBitSet(tryBlockAddr, curOffset)) {
+  if (inTryBlock) {
     CatchHandlerIterator iterator(*code_item, curOffset);
 
     if (curBlock->successorBlockList.blockListType != kNotUsed) {
+      LOG(INFO) << PrettyMethod(cUnit->method_idx, *cUnit->dex_file);
       LOG(FATAL) << "Successor block list already in use: "
                  << (int)curBlock->successorBlockList.blockListType;
     }
@@ -688,37 +689,46 @@
     oatInsertGrowableList(cUnit, ehBlock->predecessors, (intptr_t)curBlock);
   }
 
-  /*
-   * Force the current block to terminate.
-   *
-   * Data may be present before codeEnd, so we need to parse it to know
-   * whether it is code or data.
-   */
-  if (codePtr < codeEnd) {
-    /* Create a fallthrough block for real instructions (incl. NOP) */
-    if (contentIsInsn(codePtr)) {
-      BasicBlock *fallthroughBlock = findBlock(cUnit,
-                                               curOffset + width,
-                                               /* split */
-                                               false,
-                                               /* create */
-                                               true,
-                                               /* immedPredBlockP */
-                                               NULL);
-      /*
-       * THROW is an unconditional branch.  NOTE:
-       * THROW_VERIFICATION_ERROR is also an unconditional
-       * branch, but we shouldn't treat it as such until we have
-       * a dead code elimination pass (which won't be important
-       * until inlining w/ constant propagation is implemented.
-       */
-      if (insn->dalvikInsn.opcode != Instruction::THROW) {
-        curBlock->fallThrough = fallthroughBlock;
-        oatInsertGrowableList(cUnit, fallthroughBlock->predecessors,
-                              (intptr_t)curBlock);
-      }
+  if (insn->dalvikInsn.opcode == Instruction::THROW){
+    if ((codePtr < codeEnd) && contentIsInsn(codePtr)) {
+      // Force creation of new block following THROW via side-effect
+      findBlock(cUnit, curOffset + width, /* split */ false,
+                /* create */ true, /* immedPredBlockP */ NULL);
+    }
+    if (!inTryBlock) {
+       // Don't split a THROW that can't rethrow - we're done.
+      return curBlock;
     }
   }
+
+  /*
+   * Split the potentially-throwing instruction into two parts.
+   * The first half will be a pseudo-op that captures the exception
+   * edges and terminates the basic block.  It always falls through.
+   * Then, create a new basic block that begins with the throwing instruction
+   * (minus exceptions).  Note: this new basic block must NOT be entered into
+   * the blockMap.  If the potentially-throwing instruction is the target of a
+   * future branch, we need to find the check psuedo half.  The new
+   * basic block containing the work portion of the instruction should
+   * only be entered via fallthrough from the block containing the
+   * pseudo exception edge MIR.  Note also that this new block is
+   * not automatically terminated after the work portion, and may
+   * contain following instructions.
+   */
+  BasicBlock *newBlock = oatNewBB(cUnit, kDalvikByteCode, cUnit->numBlocks++);
+  oatInsertGrowableList(cUnit, &cUnit->blockList, (intptr_t)newBlock);
+  newBlock->startOffset = insn->offset;
+  curBlock->fallThrough = newBlock;
+  oatInsertGrowableList(cUnit, newBlock->predecessors, (intptr_t)curBlock);
+  MIR* newInsn = (MIR*)oatNew(cUnit, sizeof(MIR), true, kAllocMIR);
+  *newInsn = *insn;
+  insn->dalvikInsn.opcode =
+      static_cast<Instruction::Code>(kMirOpCheck);
+  // Associate the two halves
+  insn->meta.throwInsn = newInsn;
+  newInsn->meta.throwInsn = insn;
+  oatAppendMIR(newBlock, newInsn);
+  return newBlock;
 }
 
 void oatInit(CompilationUnit* cUnit, const Compiler& compiler) {
@@ -763,15 +773,11 @@
   cUnit->numRegs = code_item->registers_size_ - cUnit->numIns;
   cUnit->numOuts = code_item->outs_size_;
 #if defined(ART_USE_QUICK_COMPILER)
-  // TODO: fix bug and remove this workaround
-  std::string methodName = PrettyMethod(method_idx, dex_file);
-  if ((methodName.find("gdata2.AndroidGDataClient.createAndExecuteMethod")
-      != std::string::npos) || (methodName.find("hG.a") != std::string::npos)
-      || (methodName.find("hT.a(hV, java.lang.String, java.lang.String, java")
-      != std::string::npos) || (methodName.find("AndroidHttpTransport.exchange")
-      != std::string::npos)) {
-    LOG(INFO) << "Skipping bitcode generation for " << methodName;
-  } else {
+  DCHECK((cUnit->instructionSet == kThumb2) ||
+         (cUnit->instructionSet == kX86) ||
+         (cUnit->instructionSet == kMips));
+  if (cUnit->instructionSet == kThumb2) {
+    // TODO: remove this once x86 is tested
     cUnit->genBitcode = true;
   }
 #endif
@@ -791,6 +797,7 @@
   }
 #if defined(ART_USE_QUICK_COMPILER)
   if (cUnit->genBitcode) {
+    //cUnit->enableDebug |= (1 << kDebugVerifyBitcode);
     //cUnit->printMe = true;
     //cUnit->enableDebug |= (1 << kDebugDumpBitcodeFile);
     // Disable non-safe optimizations for now
@@ -962,8 +969,8 @@
         }
       }
     } else if (flags & Instruction::kThrow) {
-      processCanThrow(cUnit.get(), curBlock, insn, curOffset, width, flags,
-                      tryBlockAddr, codePtr, codeEnd);
+      curBlock = processCanThrow(cUnit.get(), curBlock, insn, curOffset,
+                                 width, flags, tryBlockAddr, codePtr, codeEnd);
     } else if (flags & Instruction::kSwitch) {
       processCanSwitch(cUnit.get(), curBlock, insn, curOffset, width, flags);
     }
diff --git a/src/compiler/Ralloc.cc b/src/compiler/Ralloc.cc
index 500b1b2..f4e735a 100644
--- a/src/compiler/Ralloc.cc
+++ b/src/compiler/Ralloc.cc
@@ -89,20 +89,6 @@
   return false;
 }
 
-// Try to find the next move result which might have an FP target
-SSARepresentation* findFPMoveResult(MIR* mir)
-{
-  SSARepresentation* res = NULL;
-  for (; mir; mir = mir->next) {
-    if ((mir->dalvikInsn.opcode == Instruction::MOVE_RESULT) ||
-        (mir->dalvikInsn.opcode == Instruction::MOVE_RESULT_WIDE)) {
-      res = mir->ssaRep;
-      break;
-    }
-  }
-  return res;
-}
-
 /*
  * Infer types and sizes.  We don't need to track change on sizes,
  * as it doesn't propagate.  We're guaranteed at least one pass through
@@ -236,14 +222,12 @@
         const char* shorty = oatGetShortyFromTargetIdx(cUnit, target_idx);
         // Handle result type if floating point
         if ((shorty[0] == 'F') || (shorty[0] == 'D')) {
-          // Find move-result that consumes this result
-          SSARepresentation* tgtRep = findFPMoveResult(mir->next);
-          // Might be in next basic block
-          if (!tgtRep) {
-            tgtRep = findFPMoveResult(bb->fallThrough->firstMIRInsn);
-          }
+          MIR* moveResultMIR = oatFindMoveResult(cUnit, bb, mir);
           // Result might not be used at all, so no move-result
-          if (tgtRep) {
+          if (moveResultMIR && (moveResultMIR->dalvikInsn.opcode !=
+              Instruction::MOVE_RESULT_OBJECT)) {
+            SSARepresentation* tgtRep = moveResultMIR->ssaRep;
+            DCHECK(tgtRep != NULL);
             tgtRep->fpDef[0] = true;
             changed |= setFp(cUnit, tgtRep->defs[0], true);
             if (shorty[0] == 'D') {
diff --git a/src/compiler/Utility.cc b/src/compiler/Utility.cc
index 571208f..c865718 100644
--- a/src/compiler/Utility.cc
+++ b/src/compiler/Utility.cc
@@ -687,19 +687,20 @@
 {
   switch (bb->blockType) {
     case kEntryBlock:
-      snprintf(name, BLOCK_NAME_LEN, "entry");
+      snprintf(name, BLOCK_NAME_LEN, "entry_%d", bb->id);
       break;
     case kExitBlock:
-      snprintf(name, BLOCK_NAME_LEN, "exit");
+      snprintf(name, BLOCK_NAME_LEN, "exit_%d", bb->id);
       break;
     case kDalvikByteCode:
-      snprintf(name, BLOCK_NAME_LEN, "block%04x", bb->startOffset);
+      snprintf(name, BLOCK_NAME_LEN, "block%04x_%d", bb->startOffset, bb->id);
       break;
     case kExceptionHandling:
-      snprintf(name, BLOCK_NAME_LEN, "exception%04x", bb->startOffset);
+      snprintf(name, BLOCK_NAME_LEN, "exception%04x_%d", bb->startOffset,
+               bb->id);
       break;
     default:
-      snprintf(name, BLOCK_NAME_LEN, "??");
+      snprintf(name, BLOCK_NAME_LEN, "??_%d", bb->id);
       break;
   }
 }
diff --git a/src/compiler/codegen/MethodBitcode.cc b/src/compiler/codegen/MethodBitcode.cc
index 79501a4..b38ba77 100644
--- a/src/compiler/codegen/MethodBitcode.cc
+++ b/src/compiler/codegen/MethodBitcode.cc
@@ -51,7 +51,7 @@
   llvm::Value* placeholder = getLLVMValue(cUnit, sReg);
   if (placeholder == NULL) {
     // This can happen on instruction rewrite on verification failure
-    LOG(WARNING) << "Null placeholder - invalid CFG";
+    LOG(WARNING) << "Null placeholder";
     return;
   }
   placeholder->replaceAllUsesWith(val);
@@ -307,7 +307,6 @@
   llvm::Function* func = cUnit->intrinsic_helper->GetIntrinsicFunction(
       greenland::IntrinsicHelper::Throw);
   cUnit->irb->CreateCall(func, src);
-  cUnit->irb->CreateUnreachable();
 }
 
 void convertMonitorEnterExit(CompilationUnit* cUnit, int optFlags,
@@ -813,6 +812,15 @@
 
   bool objectDefinition = false;
 
+  if (cUnit->printMe) {
+    if ((int)opcode < kMirOpFirst) {
+      LOG(INFO) << ".. " << Instruction::Name(opcode) << " 0x"
+                << std::hex << (int)opcode;
+    } else {
+      LOG(INFO) << ".. opcode 0x" << std::hex << (int)opcode;
+    }
+  }
+
   /* Prep Src and Dest locations */
   int nextSreg = 0;
   int nextLoc = 0;
@@ -1293,10 +1301,24 @@
 
    case Instruction::THROW:
       convertThrow(cUnit, rlSrc[0]);
+      /*
+       * If this throw is standalone, terminate.
+       * If it might rethrow, force termination
+       * of the following block.
+       */
+      if (bb->fallThrough == NULL) {
+        cUnit->irb->CreateUnreachable();
+      } else {
+        bb->fallThrough->fallThrough = NULL;
+        bb->fallThrough->taken = NULL;
+      }
       break;
 
    case Instruction::THROW_VERIFICATION_ERROR:
       convertThrowVerificationError(cUnit, vA, vB);
+      UNIMPLEMENTED(WARNING) << "Need dead code elimination pass"
+                             << " - disabling bitcode verification";
+      cUnit->enableDebug &= ~(1 << kDebugVerifyBitcode);
       break;
 
     case Instruction::MOVE_RESULT_WIDE:
@@ -1307,7 +1329,8 @@
        * Instruction rewriting on verification failure can eliminate
        * the invoke that feeds this move0result.  It won't ever be reached,
        * so we can ignore it.
-       * TODO: verify that previous instruction if THROW_VERIFICATION_ERROR
+       * TODO: verify that previous instruction is THROW_VERIFICATION_ERROR,
+       * or better, add dead-code elimination.
        */
       UNIMPLEMENTED(WARNING) << "Need to verify previous inst was rewritten";
 #else
@@ -1650,6 +1673,13 @@
       UNIMPLEMENTED(WARNING) << "unimp kMirOpPhi";
       break;
     }
+    case kMirOpNop:
+      if ((mir == bb->lastMIRInsn) && (bb->taken == NULL) &&
+          (bb->fallThrough == NULL)) {
+        cUnit->irb->CreateUnreachable();
+      }
+      break;
+
 #if defined(TARGET_ARM)
     case kMirOpFusedCmplFloat:
       UNIMPLEMENTED(WARNING) << "unimp kMirOpFusedCmpFloat";
@@ -1721,6 +1751,16 @@
   cUnit->irb->SetInsertPoint(llvmBB);
   setDexOffset(cUnit, bb->startOffset);
 
+  if (cUnit->printMe) {
+    LOG(INFO) << "................................";
+    LOG(INFO) << "Block id " << bb->id;
+    if (llvmBB != NULL) {
+      LOG(INFO) << "label " << llvmBB->getName().str().c_str();
+    } else {
+      LOG(INFO) << "llvmBB is NULL";
+    }
+  }
+
   if (bb->blockType == kEntryBlock) {
     setMethodInfo(cUnit);
     bool *canBeRef = (bool*)  oatNew(cUnit, sizeof(bool) *
@@ -1760,8 +1800,6 @@
     /*
      * Because we're deferring null checking, delete the associated empty
      * exception block.
-     * TODO: add new block type for exception blocks that we generate
-     * greenland code for.
      */
     llvmBB->eraseFromParent();
     return false;
@@ -1771,8 +1809,9 @@
 
     setDexOffset(cUnit, mir->offset);
 
-    Instruction::Code dalvikOpcode = mir->dalvikInsn.opcode;
-    Instruction::Format dalvikFormat = Instruction::FormatOf(dalvikOpcode);
+    int opcode = mir->dalvikInsn.opcode;
+    Instruction::Format dalvikFormat =
+        Instruction::FormatOf(mir->dalvikInsn.opcode);
 
     /* If we're compiling for the debugger, generate an update callout */
     if (cUnit->genDebugger) {
@@ -1780,7 +1819,43 @@
       //genDebuggerUpdate(cUnit, mir->offset);
     }
 
-    if ((int)mir->dalvikInsn.opcode >= (int)kMirOpFirst) {
+    if (opcode == kMirOpCheck) {
+      // Combine check and work halves of throwing instruction.
+      MIR* workHalf = mir->meta.throwInsn;
+      mir->dalvikInsn.opcode = workHalf->dalvikInsn.opcode;
+      opcode = mir->dalvikInsn.opcode;
+      SSARepresentation* ssaRep = workHalf->ssaRep;
+      workHalf->ssaRep = mir->ssaRep;
+      mir->ssaRep = ssaRep;
+      workHalf->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpNop);
+      if (bb->successorBlockList.blockListType == kCatch) {
+        llvm::Function* intr = cUnit->intrinsic_helper->GetIntrinsicFunction(
+            greenland::IntrinsicHelper::CatchTargets);
+        llvm::Value* switchKey =
+            cUnit->irb->CreateCall(intr, cUnit->irb->getInt32(mir->offset));
+        GrowableListIterator iter;
+        oatGrowableListIteratorInit(&bb->successorBlockList.blocks, &iter);
+        // New basic block to use for work half
+        llvm::BasicBlock* workBB =
+            llvm::BasicBlock::Create(*cUnit->context, "", cUnit->func);
+        llvm::SwitchInst* sw =
+            cUnit->irb->CreateSwitch(switchKey, workBB,
+                                     bb->successorBlockList.blocks.numUsed);
+        while (true) {
+          SuccessorBlockInfo *successorBlockInfo =
+              (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iter);
+          if (successorBlockInfo == NULL) break;
+          llvm::BasicBlock *target =
+              getLLVMBlock(cUnit, successorBlockInfo->block->id);
+          int typeIndex = successorBlockInfo->key;
+          sw->addCase(cUnit->irb->getInt32(typeIndex), target);
+        }
+        llvmBB = workBB;
+        cUnit->irb->SetInsertPoint(llvmBB);
+      }
+    }
+
+    if (opcode >= kMirOpFirst) {
       convertExtendedMIR(cUnit, bb, mir, llvmBB);
       continue;
     }
@@ -1788,8 +1863,9 @@
     bool notHandled = convertMIRNode(cUnit, mir, bb, llvmBB,
                                      NULL /* labelList */);
     if (notHandled) {
+      Instruction::Code dalvikOpcode = static_cast<Instruction::Code>(opcode);
       LOG(WARNING) << StringPrintf("%#06x: Op %#x (%s) / Fmt %d not handled",
-                                   mir->offset, dalvikOpcode,
+                                   mir->offset, opcode,
                                    Instruction::Name(dalvikOpcode),
                                    dalvikFormat);
     }
@@ -1987,7 +2063,14 @@
   cUnit->irb->SetInsertPoint(cUnit->entryBB);
   cUnit->irb->CreateBr(cUnit->entryTargetBB);
 
-  //llvm::verifyFunction(*cUnit->func, llvm::PrintMessageAction);
+  if (cUnit->enableDebug & (1 << kDebugVerifyBitcode)) {
+     if (llvm::verifyFunction(*cUnit->func, llvm::PrintMessageAction)) {
+       LOG(INFO) << "Bitcode verification FAILED for "
+                 << PrettyMethod(cUnit->method_idx, *cUnit->dex_file)
+                 << " of size " << cUnit->insnsSize;
+       cUnit->enableDebug |= (1 << kDebugDumpBitcodeFile);
+     }
+  }
 
   if (cUnit->enableDebug & (1 << kDebugDumpBitcodeFile)) {
     // Write bitcode to file
@@ -3132,6 +3215,24 @@
               cvtShiftOp(cUnit, Instruction::USHR_INT, callInst);
               break;
 
+            case greenland::IntrinsicHelper::CatchTargets: {
+                llvm::SwitchInst* swInst =
+                    llvm::dyn_cast<llvm::SwitchInst>(nextIt);
+                DCHECK(swInst != NULL);
+                /*
+                 * Discard the edges and the following conditional branch.
+                 * Do a direct branch to the default target (which is the
+                 * "work" portion of the pair.
+                 * TODO: awful code layout - rework
+                 */
+                 llvm::BasicBlock* targetBB = swInst->getDefaultDest();
+                 DCHECK(targetBB != NULL);
+                 opUnconditionalBranch(cUnit,
+                                       cUnit->blockToLabelMap.Get(targetBB));
+                 ++it;
+              }
+              break;
+
             default:
               LOG(FATAL) << "Unexpected intrinsic " << (int)id << ", "
                          << cUnit->intrinsic_helper->GetName(id);
diff --git a/src/compiler/codegen/MethodCodegenDriver.cc b/src/compiler/codegen/MethodCodegenDriver.cc
index d49b329..3c5fb23 100644
--- a/src/compiler/codegen/MethodCodegenDriver.cc
+++ b/src/compiler/codegen/MethodCodegenDriver.cc
@@ -819,9 +819,10 @@
   "kMirFusedCmpgDouble",
   "kMirFusedCmpLong",
   "kMirNop",
-  "kMirOpNullNRangeUpCheck",
-  "kMirOpNullNRangeDownCheck",
-  "kMirOpLowerBound",
+  "kMirOpNullCheck",
+  "kMirOpRangeCheck",
+  "kMirOpDivZeroCheck",
+  "kMirOpCheck",
 };
 
 /* Extended MIR instructions like PHI */
@@ -958,7 +959,17 @@
       newLIR1(cUnit, kPseudoSSARep, (int) ssaString);
     }
 
-    if ((int)mir->dalvikInsn.opcode >= (int)kMirOpFirst) {
+    if ((int)dalvikOpcode == (int)kMirOpCheck) {
+      // Combine check and work halves of throwing instruction.
+      MIR* workHalf = mir->meta.throwInsn;
+      mir->dalvikInsn.opcode = workHalf->dalvikInsn.opcode;
+      SSARepresentation* ssaRep = workHalf->ssaRep;
+      workHalf->ssaRep = mir->ssaRep;
+      mir->ssaRep = ssaRep;
+      workHalf->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpNop);
+    }
+
+    if ((int)dalvikOpcode >= (int)kMirOpFirst) {
       handleExtendedMethodMIR(cUnit, bb, mir);
       continue;
     }
diff --git a/src/greenland/intrinsic_func_list.def b/src/greenland/intrinsic_func_list.def
index 0ebebb2..a0f64d6 100644
--- a/src/greenland/intrinsic_func_list.def
+++ b/src/greenland/intrinsic_func_list.def
@@ -66,11 +66,23 @@
 // Exception
 //----------------------------------------------------------------------------
 
+// Should not expand - introduces the catch targets for a potentially
+// throwing instruction.  The result is a switch key and this
+// instruction will be followed by a switch statement.  The catch
+// targets will be enumerated as cases of the switch, with the fallthrough
+// designating the block containing the potentially throwing instruction.
+// bool dex_lang_catch_targets(int dex_pc)
+_EVAL_DEF_INTRINSICS_FUNC(CatchTargets,
+                          dex_lang_catch_targets,
+                          kAttrReadOnly | kAttrNoThrow,
+                          kInt32Ty,
+                          _EXPAND_ARG1(kInt32ConstantTy))
+
 // JavaObject* dex_lang_get_current_exception()
 _EVAL_DEF_INTRINSICS_FUNC(GetException,
                           dex_lang_get_current_exception,
                           kAttrReadOnly | kAttrNoThrow,
-                           kJavaObjectTy,
+                          kJavaObjectTy,
                           _EXPAND_ARG0())
 
 // bool dex_lang_is_exception_pending()
@@ -1174,28 +1186,28 @@
                           kInt32Ty,
                           _EXPAND_ARG1(kInt32Ty))
 
-// int const_obj(int)
+// JavaObject* const_obj(int)
 _EVAL_DEF_INTRINSICS_FUNC(ConstObj,
                           dex_lang_const_obj,
                           kAttrReadOnly | kAttrNoThrow,
                           kJavaObjectTy,
                           _EXPAND_ARG1(kInt32Ty))
 
-// int const_long(long)
+// long const_long(long)
 _EVAL_DEF_INTRINSICS_FUNC(ConstLong,
                           dex_lang_const_long,
                           kAttrReadOnly | kAttrNoThrow,
                           kInt64Ty,
                           _EXPAND_ARG1(kInt64Ty))
 
-// int const_float(int)
+// float const_float(int)
 _EVAL_DEF_INTRINSICS_FUNC(ConstFloat,
                           dex_lang_const_Float,
                           kAttrReadOnly | kAttrNoThrow,
                           kFloatTy,
                           _EXPAND_ARG1(kInt32Ty))
 
-// int const_double(long)
+// double const_double(long)
 _EVAL_DEF_INTRINSICS_FUNC(ConstDouble,
                           dex_lang_const_Double,
                           kAttrReadOnly | kAttrNoThrow,