Quick compiler:interpret on type mismatch

The Dex specification is a bit loose - particularly in regards
to types.  The Quick compiler, though, makes some assumptions
about types.  In particular, it doesn't expect to encounter the
use of a long or double virtual register pair that was defined
by two independent 32-bit operations.

dx does not create such patterns (at least in recent memory).
However, at least one such case exists in the wild.  The next
version of the Dex specification will add more type constraints
and formally disallow such cases.  Meanwhile, existing code will
be handled by identifying these cases an reverting to interpretation
for the offending method.

Fix for internal b/15616104

Change-Id: Ibe9c423be9a952ff58cf8d985aa164885b8dd2ae
diff --git a/compiler/dex/frontend.cc b/compiler/dex/frontend.cc
index 84e1a94..89b1a75 100644
--- a/compiler/dex/frontend.cc
+++ b/compiler/dex/frontend.cc
@@ -957,6 +957,10 @@
 
   CompiledMethod* result = NULL;
 
+  if (cu.mir_graph->PuntToInterpreter()) {
+    return NULL;
+  }
+
   cu.cg->Materialize();
 
   cu.NewTimingSplit("Dedupe");  /* deduping takes up the vast majority of time in GetCompiledMethod(). */
diff --git a/compiler/dex/mir_analysis.cc b/compiler/dex/mir_analysis.cc
index 2ec17de..1350665 100644
--- a/compiler/dex/mir_analysis.cc
+++ b/compiler/dex/mir_analysis.cc
@@ -1011,7 +1011,7 @@
   }
 
   // Contains a pattern we don't want to compile?
-  if (punt_to_interpreter_) {
+  if (PuntToInterpreter()) {
     return true;
   }
 
diff --git a/compiler/dex/mir_graph.h b/compiler/dex/mir_graph.h
index 27b8ca4..15c0aa4 100644
--- a/compiler/dex/mir_graph.h
+++ b/compiler/dex/mir_graph.h
@@ -958,6 +958,14 @@
   bool SetHigh(int index, bool is_high);
   bool SetHigh(int index);
 
+  bool PuntToInterpreter() {
+    return punt_to_interpreter_;
+  }
+
+  void SetPuntToInterpreter(bool val) {
+    punt_to_interpreter_ = val;
+  }
+
   char* GetDalvikDisassembly(const MIR* mir);
   void ReplaceSpecialChars(std::string& str);
   std::string GetSSAName(int ssa_reg);
diff --git a/compiler/dex/vreg_analysis.cc b/compiler/dex/vreg_analysis.cc
index c4af9cb..db383c4 100644
--- a/compiler/dex/vreg_analysis.cc
+++ b/compiler/dex/vreg_analysis.cc
@@ -123,6 +123,16 @@
  */
 bool MIRGraph::InferTypeAndSize(BasicBlock* bb, MIR* mir, bool changed) {
   SSARepresentation *ssa_rep = mir->ssa_rep;
+
+  /*
+   * The dex bytecode definition does not explicitly outlaw the definition of the same
+   * virtual register to be used in both a 32-bit and 64-bit pair context.  However, dx
+   * does not generate this pattern (at least recently).  Further, in the next revision of
+   * dex, we will forbid this.  To support the few cases in the wild, detect this pattern
+   * and punt to the interpreter.
+   */
+  bool type_mismatch = false;
+
   if (ssa_rep) {
     uint64_t attrs = GetDataFlowAttributes(mir);
     const int* uses = ssa_rep->uses;
@@ -145,6 +155,7 @@
       }
     }
 
+
     // Handles uses
     int next = 0;
     if (attrs & DF_UA) {
@@ -162,6 +173,7 @@
         SRegToVReg(uses[next + 1]));
         next += 2;
       } else {
+        type_mismatch |= reg_location_[uses[next]].wide;
         next++;
       }
     }
@@ -180,6 +192,7 @@
                              SRegToVReg(uses[next + 1]));
         next += 2;
       } else {
+        type_mismatch |= reg_location_[uses[next]].wide;
         next++;
       }
     }
@@ -196,6 +209,8 @@
         reg_location_[uses[next + 1]].high_word = true;
         DCHECK_EQ(SRegToVReg(uses[next])+1,
         SRegToVReg(uses[next + 1]));
+      } else {
+        type_mismatch |= reg_location_[uses[next]].wide;
       }
     }
 
@@ -205,6 +220,7 @@
         (mir->dalvikInsn.opcode == Instruction::RETURN_OBJECT)) {
       switch (cu_->shorty[0]) {
           case 'I':
+            type_mismatch |= reg_location_[uses[0]].wide;
             changed |= SetCore(uses[0]);
             break;
           case 'J':
@@ -215,6 +231,7 @@
             reg_location_[uses[1]].high_word = true;
             break;
           case 'F':
+            type_mismatch |= reg_location_[uses[0]].wide;
             changed |= SetFp(uses[0]);
             break;
           case 'D':
@@ -225,6 +242,7 @@
             reg_location_[uses[1]].high_word = true;
             break;
           case 'L':
+            type_mismatch |= reg_location_[uses[0]].wide;
             changed |= SetRef(uses[0]);
             break;
           default: break;
@@ -261,6 +279,7 @@
           (mir->dalvikInsn.opcode != Instruction::INVOKE_STATIC_RANGE))) {
         reg_location_[uses[next]].defined = true;
         reg_location_[uses[next]].ref = true;
+        type_mismatch |= reg_location_[uses[next]].wide;
         next++;
       }
       uint32_t cpos = 1;
@@ -286,12 +305,15 @@
               i++;
               break;
             case 'F':
+              type_mismatch |= reg_location_[uses[i]].wide;
               ssa_rep->fp_use[i] = true;
               break;
             case 'L':
+              type_mismatch |= reg_location_[uses[i]].wide;
               changed |= SetRef(uses[i]);
               break;
             default:
+              type_mismatch |= reg_location_[uses[i]].wide;
               changed |= SetCore(uses[i]);
               break;
           }
@@ -367,6 +389,12 @@
       }
     }
   }
+  if (type_mismatch) {
+    LOG(WARNING) << "Deprecated dex type mismatch, interpreting "
+                 << PrettyMethod(cu_->method_idx, *cu_->dex_file);
+    LOG(INFO) << "@ 0x" << std::hex << mir->offset;
+    SetPuntToInterpreter(true);
+  }
   return changed;
 }