Support inline dex data, take 2

Allow switch and array data blocks to appear interspersed
with Dex code (rather than just at the end).

Bug 10040419

Change-Id: Ia2850070f0e702381eb402f604d675e5a0b101de
diff --git a/compiler/dex/mir_graph.cc b/compiler/dex/mir_graph.cc
index 6b010ed..86f6ee5 100644
--- a/compiler/dex/mir_graph.cc
+++ b/compiler/dex/mir_graph.cc
@@ -116,25 +116,10 @@
   STLDeleteElements(&m_units_);
 }
 
-bool MIRGraph::ContentIsInsn(const uint16_t* code_ptr) {
-  uint16_t instr = *code_ptr;
-  Instruction::Code opcode = static_cast<Instruction::Code>(instr & 0xff);
-  /*
-   * Since the low 8-bit in metadata may look like NOP, we need to check
-   * both the low and whole sub-word to determine whether it is code or data.
-   */
-  return (opcode != Instruction::NOP || instr == 0);
-}
-
 /*
  * Parse an instruction, return the length of the instruction
  */
 int MIRGraph::ParseInsn(const uint16_t* code_ptr, DecodedInstruction* decoded_instruction) {
-  // Don't parse instruction data
-  if (!ContentIsInsn(code_ptr)) {
-    return 0;
-  }
-
   const Instruction* instruction = Instruction::At(code_ptr);
   *decoded_instruction = DecodedInstruction(instruction);
 
@@ -349,11 +334,8 @@
     cur_block->fall_through = fallthrough_block;
     fallthrough_block->predecessors->Insert(cur_block);
   } else if (code_ptr < code_end) {
-    /* Create a fallthrough block for real instructions (incl. NOP) */
-    if (ContentIsInsn(code_ptr)) {
-      FindBlock(cur_offset + width, /* split */ false, /* create */ true,
+    FindBlock(cur_offset + width, /* split */ false, /* create */ true,
                 /* immed_pred_block_p */ NULL);
-    }
   }
   return cur_block;
 }
@@ -478,7 +460,7 @@
 
   if (insn->dalvikInsn.opcode == Instruction::THROW) {
     cur_block->explicit_throw = true;
-    if ((code_ptr < code_end) && ContentIsInsn(code_ptr)) {
+    if (code_ptr < code_end) {
       // Force creation of new block following THROW via side-effect
       FindBlock(cur_offset + width, /* split */ false, /* create */ true,
                 /* immed_pred_block_p */ NULL);
@@ -605,9 +587,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 +605,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 +613,33 @@
       def_count_ += (df_flags & DF_A_WIDE) ? 2 : 1;
     }
 
+    // Check for inline data block signatures
+    if (opcode == Instruction::NOP) {
+      // A simple NOP will have a width of 1 at this point, embedded data NOP > 1.
+      if ((width == 1) && ((current_offset_ & 0x1) == 0x1) && ((code_end - code_ptr) > 1)) {
+        // Could be an aligning nop.  If an embedded data NOP follows, treat pair as single unit.
+        uint16_t following_raw_instruction = code_ptr[1];
+        if ((following_raw_instruction == Instruction::kSparseSwitchSignature) ||
+            (following_raw_instruction == Instruction::kPackedSwitchSignature) ||
+            (following_raw_instruction == Instruction::kArrayDataSignature)) {
+          width += Instruction::At(code_ptr + 1)->SizeInCodeUnits();
+        }
+      }
+      if (width == 1) {
+        // It is a simple nop - treat normally.
+        AppendMIR(cur_block, insn);
+      } else {
+        DCHECK(cur_block->fall_through == NULL);
+        DCHECK(cur_block->taken == NULL);
+        // Unreachable instruction, mark for no continuation.
+        flags &= ~Instruction::kContinue;
+      }
+    } 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);
@@ -653,10 +656,8 @@
          * Create a fallthrough block for real instructions
          * (incl. NOP).
          */
-        if (ContentIsInsn(code_ptr)) {
-            FindBlock(current_offset_ + width, /* split */ false, /* create */ true,
-                      /* immed_pred_block_p */ NULL);
-        }
+         FindBlock(current_offset_ + width, /* split */ false, /* create */ true,
+                   /* immed_pred_block_p */ NULL);
       }
     } else if (flags & Instruction::kThrow) {
       cur_block = ProcessCanThrow(cur_block, insn, current_offset_, width, flags, try_block_addr_,
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index aa6b29c..acb6557 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -526,12 +526,6 @@
         Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "exception handler starts at bad address (" << dex_pc << ")";
         return false;
       }
-      const Instruction* inst = Instruction::At(code_item_->insns_ + dex_pc);
-      if (inst->Opcode() != Instruction::MOVE_EXCEPTION) {
-        Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "exception handler doesn't start with move-exception ("
-                                          << dex_pc << ")";
-        return false;
-      }
       insn_flags_[dex_pc].SetBranchTarget();
       // Ensure exception types are resolved so that they don't need resolution to be delivered,
       // unresolved exception types will be ignored by exception delivery