Support inline dex data

Dx always places switch table and array data following executable
code.  However, embedding data inline appears to be legal - and
the Garmin Connect app does this.  Unknown is what tool generated
the odd dex code.  This CL reworks dex parsing to support inline data.

Further, a verification check to require a move-exception at
the beginning of catch regions is disabled.  Dalvik's verifier appears
to only require that if a move-exception exists, it must be at
the beginning of the catch.  If there is value to the check
requiring a move-exception, we'll need to enable it based on a
future dex version.

Change-Id: I80c78544993acb999f7c62d32479c3c8455b56cb
diff --git a/compiler/dex/mir_graph.cc b/compiler/dex/mir_graph.cc
index 264604c..76317aa 100644
--- a/compiler/dex/mir_graph.cc
+++ b/compiler/dex/mir_graph.cc
@@ -605,9 +605,6 @@
       opcode_count_[static_cast<int>(opcode)]++;
     }
 
-    /* Terminate when the data section is seen */
-    if (width == 0)
-      break;
 
     /* Possible simple method? */
     if (live_pattern) {
@@ -626,9 +623,6 @@
     pattern_pos++;
     }
 
-    AppendMIR(cur_block, insn);
-
-    code_ptr += width;
     int flags = Instruction::FlagsOf(insn->dalvikInsn.opcode);
 
     int df_flags = oat_data_flow_attributes_[insn->dalvikInsn.opcode];
@@ -637,6 +631,50 @@
       def_count_ += (df_flags & DF_A_WIDE) ? 2 : 1;
     }
 
+    // Check for inline data block signatures
+    if (opcode == Instruction::NOP) {
+      const uint16_t* tmp_code_ptr = code_ptr;
+      int tmp_width = 0;
+      uint16_t raw_instruction = *tmp_code_ptr;
+      bool embedded_data_block = true;
+      if (raw_instruction == 0x0000) {
+        // Could be an aligning nop - see if an embedded data block follows.
+        tmp_code_ptr++;
+        tmp_width++;
+        raw_instruction = *tmp_code_ptr;
+      }
+      if (raw_instruction == Instruction::kSparseSwitchSignature) {
+         tmp_width += (tmp_code_ptr[1] * 4) + 2;
+      } else if (raw_instruction == Instruction::kPackedSwitchSignature) {
+         tmp_width += (tmp_code_ptr[1] * 2) + 4;
+      } else if (raw_instruction == Instruction::kArrayDataSignature) {
+         int element_width = tmp_code_ptr[1];
+         int num_elements = tmp_code_ptr[2] + (tmp_code_ptr[3] << 16);
+         tmp_width += (((num_elements * element_width) + 1) / 2) + 4;
+      } else {
+        // Just a normal nop - process as usual.
+        embedded_data_block = false;
+        AppendMIR(cur_block, insn);
+      }
+      if (embedded_data_block) {
+        width = tmp_width;
+        DCHECK(cur_block->fall_through == NULL);
+        DCHECK(cur_block->taken == NULL);
+        // No fallthrough for this block
+        flags = 0;
+        df_flags = 0;
+        // If there's more code following, make sure there's a basic block to attach it to.
+        if ((code_ptr + width) < code_end) {
+          FindBlock(current_offset_ + width, /* split */ false, /* create */ true,
+                    /* immed_pred_block_p */ NULL);
+        }
+      }
+    } else {
+      AppendMIR(cur_block, insn);
+    }
+
+    code_ptr += width;
+
     if (flags & Instruction::kBranch) {
       cur_block = ProcessCanBranch(cur_block, insn, current_offset_,
                                    width, flags, code_ptr, code_end);
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 2bf78d8..53a8ed1 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -528,9 +528,13 @@
       }
       const Instruction* inst = Instruction::At(code_item_->insns_ + dex_pc);
       if (inst->Opcode() != Instruction::MOVE_EXCEPTION) {
+#if 0
+        // FIXME: this did not cause a hard failure w/ the Dalvik verifier, and code exists
+        // in the wild that trips this.  Restore the check based on future dex versioning.
         Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "exception handler doesn't start with move-exception ("
                                           << dex_pc << ")";
         return false;
+#endif
       }
       insn_flags_[dex_pc].SetBranchTarget();
       // Ensure exception types are resolved so that they don't need resolution to be delivered,