Verifier clean up.

This is the first part in trying to move to a more rigorous mode of
asserting the validity of garbage collection maps.
In the bring over of the verifier from Dalvik a large class had been
created where all of the Dalvik/Dex functions were static methods of
that class. This rewrite introduces 3 key classes, Verifier that
orchestrates the verification of a method, RegisterLine which describes
the types associated with registers for a particular PC and RegType
which describes the current type of a register within a line. The
functionality is brought over from Dalvik but cleaned up to not do
things like goto. Failing within the verifier is also cleaned up. By
virtue of having stateful objects the interfaces between different
aspects of the verifier are greatly simplified.
To save space, RegTypes are cached upto a maximum possible 2^16, and
given an Id. As the number of RegTypes is typically small this means
that we have a full OO implementation but at a lower space cost than the
current convention that uses botched together enum values requiring
32bits of storage in a RegisterLine rather than 16bits (ie half the
space requirement per register in a register line). To make use of
this space more rigorous monitor verification is brought back, and
ultimately I think we can work around bug 3215458 with richer RegTypes
that are aware of literal objects.
The code removes short cuts that had been added to Dalvik's verifier and
appear illegitimate, it also fixes a large number of bugs in the
description of the verifier.
Where possible the spaghetti of code is replaced with straight line
if-then-elsif.. code that clearly follows the ordering semantics of the
specification. The code is also aiming toward having a more type
rigorous description of the verification process, and when this isn't
possible following the description convention of the specification.

Change-Id: Id25b742018a2ad5ea95687973cca610d7e19513c
diff --git a/src/dex_instruction.cc b/src/dex_instruction.cc
index 4db8846..eb8e96e 100644
--- a/src/dex_instruction.cc
+++ b/src/dex_instruction.cc
@@ -2,6 +2,9 @@
 
 #include "dex_instruction.h"
 
+#include "dex_file.h"
+#include <iomanip>
+
 namespace art {
 
 const char* const Instruction::kInstructionNames[] = {
@@ -191,7 +194,7 @@
   }
 }
 
-size_t Instruction::Size() const {
+size_t Instruction::SizeInCodeUnits() const {
   const uint16_t* insns = reinterpret_cast<const uint16_t*>(this);
   if (*insns == kPackedSwitchSignature) {
     return (4 + insns[1] * 2);
@@ -246,9 +249,81 @@
 }
 
 const Instruction* Instruction::Next() const {
-  size_t current_size = Size() * sizeof(uint16_t);
+  size_t current_size_in_bytes = SizeInCodeUnits() * sizeof(uint16_t);
   const uint8_t* ptr = reinterpret_cast<const uint8_t*>(this);
-  return reinterpret_cast<const Instruction*>(ptr + current_size);
+  return reinterpret_cast<const Instruction*>(ptr + current_size_in_bytes);
+}
+
+void Instruction::DumpHex(std::ostream& os, size_t code_units) const {
+  size_t inst_length = SizeInCodeUnits();
+  if (inst_length > code_units) {
+    inst_length = code_units;
+  }
+  const uint16_t* insn = reinterpret_cast<const uint16_t*>(this);
+  for (size_t i = 0; i < inst_length; i++) {
+    os << "0x" << StringPrintf("0x%04X", insn[i]) << " ";
+  }
+  for (size_t i = inst_length; i < code_units; i++) {
+    os << "       ";
+  }
+}
+
+void Instruction::Dump(std::ostream& os, const DexFile* file) const {
+  DecodedInstruction insn(this);
+  const char* opcode = kInstructionNames[insn.opcode_];
+  switch (Format()) {
+    case k10x: os << opcode; break;
+    case k12x: os << opcode << " v" << insn.vA_ << ", v" << insn.vB_; break;
+    case k11n: os << opcode << " v" << insn.vA_ << ", #+" << insn.vB_; break;
+    case k11x: os << opcode << " v" << insn.vA_; break;
+    case k10t: os << opcode << " +" << (int)insn.vA_; break;
+    case k20bc: os << opcode << " " << insn.vA_ << ", kind@" << insn.vB_; break;
+    case k20t: os << opcode << " +" << (int)insn.vA_; break;
+    case k22x: os << opcode << " v" << insn.vA_ << ", v" << insn.vB_; break;
+    case k21t: os << opcode << " v" << insn.vA_ << ", +" << insn.vB_; break;
+    case k21s: os << opcode << " v" << insn.vA_ << ", #+" << insn.vB_; break;
+    case k21h: os << opcode << " v" << insn.vA_ << ", #+" << insn.vB_ << "00000[00000000]"; break;
+    case k21c: os << opcode << " " << insn.vA_ << ", thing@" << insn.vB_; break;
+    case k23x: os << opcode << " v" << insn.vA_ << ", v" << insn.vB_ << ", v" << insn.vC_; break;
+    case k22b: os << opcode << " v" << insn.vA_ << ", v" << insn.vB_ << ", #+" << insn.vC_; break;
+    case k22t: os << opcode << " v" << insn.vA_ << ", v" << insn.vB_ << ", +" << insn.vC_; break;
+    case k22s: os << opcode << " v" << insn.vA_ << ", v" << insn.vB_ << ", #+" << insn.vC_; break;
+    case k22c: os << opcode << " v" << insn.vA_ << ", v" << insn.vB_ << ", thing@" << insn.vC_; break;
+    case k32x: os << opcode << " v" << insn.vA_ << ", v" << insn.vB_; break;
+    case k30t: os << opcode << " +" << (int)insn.vA_; break;
+    case k31t: os << opcode << " v" << insn.vA_ << ", +" << insn.vB_; break;
+    case k31i: os << opcode << " v" << insn.vA_ << ", #+" << insn.vB_; break;
+    case k31c: os << opcode << " v" << insn.vA_ << ", thing@" << insn.vB_; break;
+    case k35c: {
+      switch (insn.opcode_) {
+        case INVOKE_VIRTUAL:
+        case INVOKE_SUPER:
+        case INVOKE_DIRECT:
+        case INVOKE_STATIC:
+        case INVOKE_INTERFACE:
+          if (file != NULL) {
+            const DexFile::MethodId& meth_id = file->GetMethodId(insn.vB_);
+            os << opcode << " {v" << insn.arg_[0] << ", v" << insn.arg_[1] << ", v" << insn.arg_[2]
+                         << ", v" << insn.arg_[3] << ", v" << insn.arg_[4] << "}, "
+                         << file->GetMethodName(meth_id) << file->GetMethodSignature(meth_id)
+                         << " // method@" << insn.vB_;
+            break;
+          }  // else fall-through
+        default:
+          os << opcode << " {v" << insn.arg_[0] << ", v" << insn.arg_[1] << ", v" << insn.arg_[2]
+                       << ", v" << insn.arg_[3] << ", v" << insn.arg_[4] << "}, thing@" << insn.vB_;
+          break;
+      }
+      break;
+    }
+    case k3rc: os << opcode << " {v" << insn.vC_ << " .. v" << (insn.vC_+ insn.vA_ - 1) << "}, method@" << insn.vB_; break;
+    case k51l: os << opcode << " v" << insn.vA_ << ", #+" << insn.vB_; break;
+  }
+}
+
+std::ostream& operator<<(std::ostream& os, const Instruction& rhs) {
+  rhs.Dump(os, NULL);
+  return os;
 }
 
 }  // namespace art