Refactor DescribeVRegs to allow caching.

In oatdump we want to describe vregs at regular intervals and reverifying is
slow. Refactor MethodVerifier to allow this. Move instruction flags into its
own file so the complete type is visible to files other than method verifier.

Change-Id: I14d491e7376ab1d7117a9725847870ef1337803f
diff --git a/src/oat/runtime/support_deoptimize.cc b/src/oat/runtime/support_deoptimize.cc
index 0d88c52..c77d034 100644
--- a/src/oat/runtime/support_deoptimize.cc
+++ b/src/oat/runtime/support_deoptimize.cc
@@ -51,11 +51,10 @@
       CHECK(code_item != NULL);
       uint16_t num_regs =  code_item->registers_size_;
       shadow_frame_ = ShadowFrame::Create(num_regs, NULL, m, GetDexPc());
-      std::vector<int32_t> kinds =
-          verifier::MethodVerifier::DescribeVRegs(m->GetDexMethodIndex(), &mh.GetDexFile(),
-                                                  mh.GetDexCache(), mh.GetClassLoader(),
-                                                  mh.GetClassDefIndex(), code_item, m,
-                                                  m->GetAccessFlags(), GetDexPc());
+      std::vector<int32_t> kinds = DescribeVRegs(m->GetDexMethodIndex(), &mh.GetDexFile(),
+                                                 mh.GetDexCache(), mh.GetClassLoader(),
+                                                 mh.GetClassDefIndex(), code_item, m,
+                                                 m->GetAccessFlags(), GetDexPc());
       for(uint16_t reg = 0; reg < num_regs; reg++) {
         VRegKind kind = static_cast<VRegKind>(kinds.at(reg * 2));
         switch (kind) {
@@ -72,6 +71,22 @@
       }
       return false;  // Stop now we have built the shadow frame.
     }
+
+    std::vector<int32_t> DescribeVRegs(uint32_t dex_method_idx,
+                                       const DexFile* dex_file,
+                                       mirror::DexCache* dex_cache,
+                                       mirror::ClassLoader* class_loader,
+                                       uint32_t class_def_idx,
+                                       const DexFile::CodeItem* code_item,
+                                       mirror::AbstractMethod* method,
+                                       uint32_t method_access_flags, uint32_t dex_pc)
+        SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+      verifier::MethodVerifier verifier(dex_file, dex_cache, class_loader, class_def_idx, code_item,
+                                        dex_method_idx, method, method_access_flags, true);
+      verifier.Verify();
+      return verifier.DescribeVRegs(dex_pc);
+    }
+
     ShadowFrame* shadow_frame_;
     uint32_t runtime_frames_;
   } visitor(self, self->GetLongJumpContext());
diff --git a/src/oatdump.cc b/src/oatdump.cc
index 3fe62bc..4063d70 100644
--- a/src/oatdump.cc
+++ b/src/oatdump.cc
@@ -585,14 +585,22 @@
                         uint32_t dex_method_idx, const DexFile* dex_file,
                         uint32_t class_def_idx, const DexFile::CodeItem* code_item,
                         uint32_t method_access_flags, uint32_t dex_pc) {
+    static UniquePtr<verifier::MethodVerifier> verifier;
+    static const DexFile* verified_dex_file = NULL;
+    static uint32_t verified_dex_method_idx = DexFile::kDexNoIndex;
+    if (dex_file != verified_dex_file || verified_dex_method_idx != dex_method_idx) {
+      ScopedObjectAccess soa(Thread::Current());
+      mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(*dex_file);
+      mirror::ClassLoader* class_loader = NULL;
+      verifier.reset(new verifier::MethodVerifier(dex_file, dex_cache, class_loader, class_def_idx,
+                                                  code_item, dex_method_idx, NULL,
+                                                  method_access_flags, true));
+      verifier->Verify();
+      verified_dex_file = dex_file;
+      verified_dex_method_idx = dex_method_idx;
+    }
+    std::vector<int32_t> kinds = verifier->DescribeVRegs(dex_pc);
     bool first = true;
-    ScopedObjectAccess soa(Thread::Current());
-    mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(*dex_file);
-    mirror::ClassLoader* class_loader = NULL;
-    std::vector<int32_t> kinds =
-        verifier::MethodVerifier::DescribeVRegs(dex_method_idx, dex_file, dex_cache,
-                                                class_loader, class_def_idx, code_item, NULL,
-                                                method_access_flags, dex_pc);
     for (size_t reg = 0; reg < code_item->registers_size_; reg++) {
       VRegKind kind = static_cast<VRegKind>(kinds.at(reg * 2));
       if (kind != kUndefined) {
diff --git a/src/verifier/instruction_flags.cc b/src/verifier/instruction_flags.cc
new file mode 100644
index 0000000..823edde
--- /dev/null
+++ b/src/verifier/instruction_flags.cc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "instruction_flags.h"
+
+#include <string.h>
+
+namespace art {
+namespace verifier {
+
+std::string InstructionFlags::ToString() const {
+  char encoding[6];
+  if (!IsOpcode()) {
+    strncpy(encoding, "XXXXX", sizeof(encoding));
+  } else {
+    strncpy(encoding, "-----", sizeof(encoding));
+    if (IsInTry())        encoding[kInTry] = 'T';
+    if (IsBranchTarget()) encoding[kBranchTarget] = 'B';
+    if (IsGcPoint())      encoding[kGcPoint] = 'G';
+    if (IsVisited())      encoding[kVisited] = 'V';
+    if (IsChanged())      encoding[kChanged] = 'C';
+  }
+  return encoding;
+}
+
+}  // namespace verifier
+}  // namespace art
diff --git a/src/verifier/instruction_flags.h b/src/verifier/instruction_flags.h
new file mode 100644
index 0000000..7f0d240
--- /dev/null
+++ b/src/verifier/instruction_flags.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_VERIFIER_METHOD_INSTRUCTION_FLAGS_H_
+#define ART_SRC_VERIFIER_METHOD_INSTRUCTION_FLAGS_H_
+
+#include "base/logging.h"
+
+#include <stdint.h>
+#include <string>
+
+namespace art {
+namespace verifier {
+
+class InstructionFlags {
+ public:
+  InstructionFlags() : length_(0), flags_(0) {}
+
+  void SetLengthInCodeUnits(size_t length) {
+    DCHECK_LT(length, 65536u);
+    length_ = length;
+  }
+  size_t GetLengthInCodeUnits() {
+    return length_;
+  }
+  bool IsOpcode() const {
+    return length_ != 0;
+  }
+
+  void SetInTry() {
+    flags_ |= 1 << kInTry;
+  }
+  void ClearInTry() {
+    flags_ &= ~(1 << kInTry);
+  }
+  bool IsInTry() const {
+    return (flags_ & (1 << kInTry)) != 0;
+  }
+
+  void SetBranchTarget() {
+    flags_ |= 1 << kBranchTarget;
+  }
+  void ClearBranchTarget() {
+    flags_ &= ~(1 << kBranchTarget);
+  }
+  bool IsBranchTarget() const {
+    return (flags_ & (1 << kBranchTarget)) != 0;
+  }
+
+  void SetGcPoint() {
+    flags_ |= 1 << kGcPoint;
+  }
+  void ClearGcPoint() {
+    flags_ &= ~(1 << kGcPoint);
+  }
+  bool IsGcPoint() const {
+    return (flags_ & (1 << kGcPoint)) != 0;
+  }
+
+  void SetVisited() {
+    flags_ |= 1 << kVisited;
+  }
+  void ClearVisited() {
+    flags_ &= ~(1 << kVisited);
+  }
+  bool IsVisited() const {
+    return (flags_ & (1 << kVisited)) != 0;
+  }
+
+  void SetChanged() {
+    flags_ |= 1 << kChanged;
+  }
+  void ClearChanged() {
+    flags_ &= ~(1 << kChanged);
+  }
+  bool IsChanged() const {
+    return (flags_ & (1 << kChanged)) != 0;
+  }
+
+  bool IsVisitedOrChanged() const {
+    return IsVisited() || IsChanged();
+  }
+
+  std::string ToString() const;
+
+ private:
+  enum {
+    kInTry,
+    kBranchTarget,
+    kGcPoint,
+    kVisited,
+    kChanged,
+  };
+
+  // Size of instruction in code units.
+  uint16_t length_;
+  uint8_t flags_;
+};
+
+}  // namespace verifier
+}  // namespace art
+
+#endif  // ART_SRC_VERIFIER_METHOD_INSTRUCTION_FLAGS_H_
diff --git a/src/verifier/method_verifier.cc b/src/verifier/method_verifier.cc
index bcac374..56344cf 100644
--- a/src/verifier/method_verifier.cc
+++ b/src/verifier/method_verifier.cc
@@ -50,105 +50,7 @@
 
 static const bool gDebugVerify = false;
 
-class InsnFlags {
- public:
-  InsnFlags() : length_(0), flags_(0) {}
-
-  void SetLengthInCodeUnits(size_t length) {
-    CHECK_LT(length, 65536u);
-    length_ = length;
-  }
-  size_t GetLengthInCodeUnits() {
-    return length_;
-  }
-  bool IsOpcode() const {
-    return length_ != 0;
-  }
-
-  void SetInTry() {
-    flags_ |= 1 << kInTry;
-  }
-  void ClearInTry() {
-    flags_ &= ~(1 << kInTry);
-  }
-  bool IsInTry() const {
-    return (flags_ & (1 << kInTry)) != 0;
-  }
-
-  void SetBranchTarget() {
-    flags_ |= 1 << kBranchTarget;
-  }
-  void ClearBranchTarget() {
-    flags_ &= ~(1 << kBranchTarget);
-  }
-  bool IsBranchTarget() const {
-    return (flags_ & (1 << kBranchTarget)) != 0;
-  }
-
-  void SetGcPoint() {
-    flags_ |= 1 << kGcPoint;
-  }
-  void ClearGcPoint() {
-    flags_ &= ~(1 << kGcPoint);
-  }
-  bool IsGcPoint() const {
-    return (flags_ & (1 << kGcPoint)) != 0;
-  }
-
-  void SetVisited() {
-    flags_ |= 1 << kVisited;
-  }
-  void ClearVisited() {
-    flags_ &= ~(1 << kVisited);
-  }
-  bool IsVisited() const {
-    return (flags_ & (1 << kVisited)) != 0;
-  }
-
-  void SetChanged() {
-    flags_ |= 1 << kChanged;
-  }
-  void ClearChanged() {
-    flags_ &= ~(1 << kChanged);
-  }
-  bool IsChanged() const {
-    return (flags_ & (1 << kChanged)) != 0;
-  }
-
-  bool IsVisitedOrChanged() const {
-    return IsVisited() || IsChanged();
-  }
-
-  std::string Dump() {
-    char encoding[6];
-    if (!IsOpcode()) {
-      strncpy(encoding, "XXXXX", sizeof(encoding));
-    } else {
-      strncpy(encoding, "-----", sizeof(encoding));
-      if (IsInTry())        encoding[kInTry] = 'T';
-      if (IsBranchTarget()) encoding[kBranchTarget] = 'B';
-      if (IsGcPoint())      encoding[kGcPoint] = 'G';
-      if (IsVisited())      encoding[kVisited] = 'V';
-      if (IsChanged())      encoding[kChanged] = 'C';
-    }
-    return std::string(encoding);
-  }
-
- private:
-  enum {
-    kInTry,
-    kBranchTarget,
-    kGcPoint,
-    kVisited,
-    kChanged,
-  };
-
-  // Size of instruction in code units
-  uint16_t length_;
-  uint8_t flags_;
-};
-
-void PcToRegisterLineTable::Init(RegisterTrackingMode mode, InsnFlags* flags,
+void PcToRegisterLineTable::Init(RegisterTrackingMode mode, InstructionFlags* flags,
                                  uint32_t insns_size, uint16_t registers_size,
                                  MethodVerifier* verifier) {
   DCHECK_GT(insns_size, 0U);
@@ -357,20 +259,6 @@
   verifier.Dump(os);
 }
 
-std::vector<int32_t> MethodVerifier::DescribeVRegs(uint32_t dex_method_idx,
-                                                   const DexFile* dex_file,
-                                                   mirror::DexCache* dex_cache,
-                                                   mirror::ClassLoader* class_loader,
-                                                   uint32_t class_def_idx,
-                                                   const DexFile::CodeItem* code_item,
-                                                   mirror::AbstractMethod* method,
-                                                   uint32_t method_access_flags, uint32_t dex_pc) {
-  MethodVerifier verifier(dex_file, dex_cache, class_loader, class_def_idx, code_item,
-                          dex_method_idx, method, method_access_flags, true);
-  verifier.Verify();
-  return verifier.DescribeVRegs(dex_pc);
-}
-
 MethodVerifier::MethodVerifier(const DexFile* dex_file, mirror::DexCache* dex_cache,
                                mirror::ClassLoader* class_loader, uint32_t class_def_idx,
                                const DexFile::CodeItem* code_item,
@@ -435,7 +323,7 @@
     return false;
   }
   // Allocate and initialize an array to hold instruction data.
-  insn_flags_.reset(new InsnFlags[code_item_->insns_size_in_code_units_]());
+  insn_flags_.reset(new InstructionFlags[code_item_->insns_size_in_code_units_]());
   // Run through the instructions and see if the width checks out.
   bool result = ComputeWidthsAndCountOps();
   // Flag instructions guarded by a "try" block and check exception handlers.
@@ -1109,7 +997,7 @@
     if (reg_line != NULL) {
       indent_os << reg_line->Dump() << "\n";
     }
-    indent_os << StringPrintf("0x%04zx", dex_pc) << ": " << insn_flags_[dex_pc].Dump() << " ";
+    indent_os << StringPrintf("0x%04zx", dex_pc) << ": " << insn_flags_[dex_pc].ToString() << " ";
     const bool kDumpHexOfInstruction = false;
     if (kDumpHexOfInstruction) {
       indent_os << inst->DumpHex(5) << " ";
@@ -3228,7 +3116,7 @@
   return true;
 }
 
-InsnFlags* MethodVerifier::CurrentInsnFlags() {
+InstructionFlags* MethodVerifier::CurrentInsnFlags() {
   return &insn_flags_[work_insn_idx_];
 }
 
@@ -3421,7 +3309,7 @@
       result.push_back(kUndefined);
       result.push_back(0);
     } else {
-      CHECK(type.IsNonZeroReferenceTypes()) << type;
+      CHECK(type.IsNonZeroReferenceTypes());
       result.push_back(kReferenceVReg);
       result.push_back(0);
     }
diff --git a/src/verifier/method_verifier.h b/src/verifier/method_verifier.h
index a36a1f9..4939217 100644
--- a/src/verifier/method_verifier.h
+++ b/src/verifier/method_verifier.h
@@ -17,8 +17,6 @@
 #ifndef ART_SRC_VERIFIER_METHOD_VERIFIER_H_
 #define ART_SRC_VERIFIER_METHOD_VERIFIER_H_
 
-#include <deque>
-#include <limits>
 #include <set>
 #include <vector>
 
@@ -28,6 +26,7 @@
 #include "compiler.h"
 #include "dex_file.h"
 #include "dex_instruction.h"
+#include "instruction_flags.h"
 #include "mirror/object.h"
 #include "reg_type.h"
 #include "reg_type_cache.h"
@@ -48,7 +47,6 @@
 namespace verifier {
 
 class MethodVerifier;
-class InsnFlags;
 class DexPcToReferenceMap;
 
 /*
@@ -125,7 +123,7 @@
   // Initialize the RegisterTable. Every instruction address can have a different set of information
   // about what's in which register, but for verification purposes we only need to store it at
   // branch target addresses (because we merge into that).
-  void Init(RegisterTrackingMode mode, InsnFlags* flags, uint32_t insns_size,
+  void Init(RegisterTrackingMode mode, InstructionFlags* flags, uint32_t insns_size,
             uint16_t registers_size, MethodVerifier* verifier);
 
   RegisterLine* GetLine(size_t idx) {
@@ -147,7 +145,6 @@
 #if defined(ART_USE_LLVM_COMPILER)
   typedef greenland::InferredRegCategoryMap InferredRegCategoryMap;
 #endif
-
  public:
   enum FailureKind {
     kNoFailure,
@@ -169,15 +166,6 @@
                                   mirror::AbstractMethod* method, uint32_t method_access_flags)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  static std::vector<int32_t> DescribeVRegs(uint32_t dex_method_idx,
-                                            const DexFile* dex_file, mirror::DexCache* dex_cache,
-                                            mirror::ClassLoader* class_loader,
-                                            uint32_t class_def_idx,
-                                            const DexFile::CodeItem* code_item,
-                                            mirror::AbstractMethod* method,
-                                            uint32_t method_access_flags, uint32_t dex_pc)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
   uint8_t EncodePcToReferenceMapData() const;
 
   uint32_t DexFileVersion() const {
@@ -228,14 +216,21 @@
     return can_load_classes_;
   }
 
- private:
-  explicit MethodVerifier(const DexFile* dex_file, mirror::DexCache* dex_cache,
-                          mirror::ClassLoader* class_loader, uint32_t class_def_idx,
-                          const DexFile::CodeItem* code_item,
-                          uint32_t method_idx, mirror::AbstractMethod* method, uint32_t access_flags,
-                          bool can_load_classes)
+  MethodVerifier(const DexFile* dex_file, mirror::DexCache* dex_cache,
+                 mirror::ClassLoader* class_loader, uint32_t class_def_idx,
+                 const DexFile::CodeItem* code_item,
+                 uint32_t method_idx, mirror::AbstractMethod* method,
+                 uint32_t access_flags, bool can_load_classes)
           SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  // Run verification on the method. Returns true if verification completes and false if the input
+  // has an irrecoverable corruption.
+  bool Verify() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  // Describe VRegs at the given dex pc.
+  std::vector<int32_t> DescribeVRegs(uint32_t dex_pc);
+
+ private:
   // Adds the given string to the beginning of the last failure message.
   void PrependToLastFailMessage(std::string);
 
@@ -260,10 +255,6 @@
                                   mirror::AbstractMethod* method, uint32_t method_access_flags)
           SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  // Run verification on the method. Returns true if verification completes and false if the input
-  // has an irrecoverable corruption.
-  bool Verify() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
   void FindLocksAtDexPc() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   /*
@@ -597,10 +588,7 @@
   // Compute sizes for GC map data
   void ComputeGcMapSizes(size_t* gc_points, size_t* ref_bitmap_bits, size_t* log2_max_gc_pc);
 
-  // Describe VRegs at the given dex pc.
-  std::vector<int32_t> DescribeVRegs(uint32_t dex_pc) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
-  InsnFlags* CurrentInsnFlags();
+  InstructionFlags* CurrentInsnFlags();
 
   // All the GC maps that the verifier has created
   typedef SafeMap<const Compiler::MethodReference, const std::vector<uint8_t>*> DexGcMapTable;
@@ -652,7 +640,8 @@
   mirror::ClassLoader* class_loader_ GUARDED_BY(Locks::mutator_lock_);
   uint32_t class_def_idx_;  // The class def index of the declaring class of the method.
   const DexFile::CodeItem* code_item_;  // The code item containing the code for the method.
-  UniquePtr<InsnFlags[]> insn_flags_;  // Instruction widths and flags, one entry per code unit.
+  // Instruction widths and flags, one entry per code unit.
+  UniquePtr<InstructionFlags[]> insn_flags_;
 
   // The dex PC of a FindLocksAtDexPc request, -1 otherwise.
   uint32_t interesting_dex_pc_;