ART: Fix crash with unreachable void check-cast

return-void
check-cast v0, V
return-void

The above code sequence will not be rejected for the check-cast of a
void type because the check-cast is not reachable. However, when
GenerateSafeCastSet() is called from the compiler, this will cause
IsAssignableFrom(Conflict, Undefined) to be called, as it scans for all
check-casts across the code, regardless of its reachableness.

RegType::AssignableFrom() has been changed to handle a Conflict type,
whereas previously this would break the check that the lhs type is a
ReferenceType.

Additionally, GenerateSafeCastSet has been changed to never assess
instructions that weren't visited during verification.

Included is a new test DEX file, 801-VoidCheckCast, that uses this code
sequence.

Change-Id: I600055ab670ee48a075ffa867b46d2e74f5aa9c0
Signed-off-by: Stephen Kyle <stephen.kyle@arm.com>
diff --git a/compiler/dex/verified_method.cc b/compiler/dex/verified_method.cc
index 9f0a696..17328c4 100644
--- a/compiler/dex/verified_method.cc
+++ b/compiler/dex/verified_method.cc
@@ -282,6 +282,10 @@
     Instruction::Code code = inst->Opcode();
     if ((code == Instruction::CHECK_CAST) || (code == Instruction::APUT_OBJECT)) {
       uint32_t dex_pc = inst->GetDexPc(code_item->insns_);
+      if (!method_verifier->GetInstructionFlags(dex_pc).IsVisited()) {
+        // Do not attempt to quicken this instruction, it's unreachable anyway.
+        continue;
+      }
       const verifier::RegisterLine* line = method_verifier->GetRegLine(dex_pc);
       bool is_safe_cast = false;
       if (code == Instruction::CHECK_CAST) {
diff --git a/runtime/verifier/reg_type-inl.h b/runtime/verifier/reg_type-inl.h
index 480ed40..f445132 100644
--- a/runtime/verifier/reg_type-inl.h
+++ b/runtime/verifier/reg_type-inl.h
@@ -81,6 +81,9 @@
       return rhs.IsLongTypes();
     } else if (lhs.IsDoubleLo()) {
       return rhs.IsDoubleTypes();
+    } else if (lhs.IsConflict()) {
+      LOG(WARNING) << "RegType::AssignableFrom lhs is Conflict!";
+      return false;
     } else {
       CHECK(lhs.IsReferenceTypes())
           << "Unexpected register type in IsAssignableFrom: '"
diff --git a/test/801-VoidCheckCast/classes.dex b/test/801-VoidCheckCast/classes.dex
new file mode 100644
index 0000000..e6f0f02
--- /dev/null
+++ b/test/801-VoidCheckCast/classes.dex
Binary files differ
diff --git a/test/801-VoidCheckCast/expected.txt b/test/801-VoidCheckCast/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/801-VoidCheckCast/expected.txt
diff --git a/test/801-VoidCheckCast/info.txt b/test/801-VoidCheckCast/info.txt
new file mode 100644
index 0000000..422f740
--- /dev/null
+++ b/test/801-VoidCheckCast/info.txt
@@ -0,0 +1,4 @@
+A test that is only available as a DEX binary.
+
+This tests that an attempt to use check-cast with the void type doesn't
+cause the compiler to crash.
diff --git a/test/etc/default-build b/test/etc/default-build
index ab859ec..6731ad3 100755
--- a/test/etc/default-build
+++ b/test/etc/default-build
@@ -17,6 +17,11 @@
 # Stop if something fails.
 set -e
 
+if [ -e classes.dex ]; then
+  zip $TEST_NAME.jar classes.dex
+  exit 0
+fi
+
 mkdir classes
 ${JAVAC} -d classes `find src -name '*.java'`