Use imprecise constants at compilation time.

During veriifcation, we create constant types for the following instructions:
const/4, const/16, const and const/high16. We used to create "precise" constant
types for each constant we process in the method being verified. Though precise
constants are only useful for deoptimization which happens at runtime.

This CL now creates "imprecise" constant types at compilation time. Since it
reduces the number of constant types we create during verification, it should
also reduce the amount of time spent in verification at compilation time.

Bug: 12167380
Bug: 12126841
Change-Id: I70522c4133a74a533fc2d2cb8d4f49888e590828
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index f03cdcd..9a2de47 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -1432,6 +1432,9 @@
   UniquePtr<RegisterLine> branch_line;
   UniquePtr<RegisterLine> fallthrough_line;
 
+  // We need precise constant types only for deoptimization which happens at runtime.
+  const bool need_precise_constant = !Runtime::Current()->IsCompiler();
+
   switch (inst->Opcode()) {
     case Instruction::NOP:
       /*
@@ -1582,22 +1585,28 @@
       /* could be boolean, int, float, or a null reference */
     case Instruction::CONST_4: {
       int32_t val = static_cast<int32_t>(inst->VRegB_11n() << 28) >> 28;
-      work_line_->SetRegisterType(inst->VRegA_11n(), reg_types_.FromCat1Const(val, true));
+      work_line_->SetRegisterType(inst->VRegA_11n(),
+                                  DetermineCat1Constant(val, need_precise_constant));
       break;
     }
     case Instruction::CONST_16: {
       int16_t val = static_cast<int16_t>(inst->VRegB_21s());
-      work_line_->SetRegisterType(inst->VRegA_21s(), reg_types_.FromCat1Const(val, true));
+      work_line_->SetRegisterType(inst->VRegA_21s(),
+                                  DetermineCat1Constant(val, need_precise_constant));
       break;
     }
-    case Instruction::CONST:
+    case Instruction::CONST: {
+      int32_t val = inst->VRegB_31i();
       work_line_->SetRegisterType(inst->VRegA_31i(),
-                                  reg_types_.FromCat1Const(inst->VRegB_31i(), true));
+                                  DetermineCat1Constant(val, need_precise_constant));
       break;
-    case Instruction::CONST_HIGH16:
+    }
+    case Instruction::CONST_HIGH16: {
+      int32_t val = static_cast<int32_t>(inst->VRegB_21h() << 16);
       work_line_->SetRegisterType(inst->VRegA_21h(),
-                                  reg_types_.FromCat1Const(inst->VRegB_21h() << 16, true));
+                                  DetermineCat1Constant(val, need_precise_constant));
       break;
+    }
       /* could be long or double; resolved upon use */
     case Instruction::CONST_WIDE_16: {
       int64_t val = static_cast<int16_t>(inst->VRegB_21s());
@@ -3928,6 +3937,34 @@
   return result;
 }
 
+const RegType& MethodVerifier::DetermineCat1Constant(int32_t value, bool precise) {
+  if (precise) {
+    // Precise constant type.
+    return reg_types_.FromCat1Const(value, true);
+  } else {
+    // Imprecise constant type.
+    if (value < -32768) {
+      return reg_types_.IntConstant();
+    } else if (value < -128) {
+      return reg_types_.ShortConstant();
+    } else if (value < 0) {
+      return reg_types_.ByteConstant();
+    } else if (value == 0) {
+      return reg_types_.Zero();
+    } else if (value == 1) {
+      return reg_types_.One();
+    } else if (value < 128) {
+      return reg_types_.PosByteConstant();
+    } else if (value < 32768) {
+      return reg_types_.PosShortConstant();
+    } else if (value < 65536) {
+      return reg_types_.CharConstant();
+    } else {
+      return reg_types_.IntConstant();
+    }
+  }
+}
+
 void MethodVerifier::Init() {
   art::verifier::RegTypeCache::Init();
 }
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index ac36a7e..053cee5 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -610,6 +610,8 @@
 
   InstructionFlags* CurrentInsnFlags();
 
+  const RegType& DetermineCat1Constant(int32_t value, bool precise)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   RegTypeCache reg_types_;
 
diff --git a/runtime/verifier/reg_type_cache.cc b/runtime/verifier/reg_type_cache.cc
index 3d24414..c8a03d6 100644
--- a/runtime/verifier/reg_type_cache.cc
+++ b/runtime/verifier/reg_type_cache.cc
@@ -438,6 +438,13 @@
   return *down_cast<const ImpreciseConstType*>(&result);
 }
 
+const ImpreciseConstType& RegTypeCache::CharConstant() {
+  int32_t jchar_max = static_cast<int32_t>(std::numeric_limits<jchar>::max());
+  const ConstantType& result =  FromCat1Const(jchar_max, false);
+  DCHECK(result.IsImpreciseConstant());
+  return *down_cast<const ImpreciseConstType*>(&result);
+}
+
 const ImpreciseConstType& RegTypeCache::ShortConstant() {
   const ConstantType& result =  FromCat1Const(std::numeric_limits<jshort>::min(), false);
   DCHECK(result.IsImpreciseConstant());
@@ -450,6 +457,18 @@
   return *down_cast<const ImpreciseConstType*>(&result);
 }
 
+const ImpreciseConstType& RegTypeCache::PosByteConstant() {
+  const ConstantType& result = FromCat1Const(std::numeric_limits<jbyte>::max(), false);
+  DCHECK(result.IsImpreciseConstant());
+  return *down_cast<const ImpreciseConstType*>(&result);
+}
+
+const ImpreciseConstType& RegTypeCache::PosShortConstant() {
+  const ConstantType& result =  FromCat1Const(std::numeric_limits<jshort>::max(), false);
+  DCHECK(result.IsImpreciseConstant());
+  return *down_cast<const ImpreciseConstType*>(&result);
+}
+
 const UninitializedType& RegTypeCache::UninitializedThisArgument(const RegType& type) {
   UninitializedType* entry;
   const std::string& descriptor(type.GetDescriptor());
diff --git a/runtime/verifier/reg_type_cache.h b/runtime/verifier/reg_type_cache.h
index a811696..41bc8c9 100644
--- a/runtime/verifier/reg_type_cache.h
+++ b/runtime/verifier/reg_type_cache.h
@@ -77,9 +77,12 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     return From(NULL, "Ljava/lang/Throwable;", precise);
   }
-  const RegType& Zero() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  const ConstantType& Zero() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     return FromCat1Const(0, true);
   }
+  const ConstantType& One() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    return FromCat1Const(1, true);
+  }
   size_t GetCacheSize() {
     return entries_.size();
   }
@@ -133,8 +136,11 @@
   const RegType& FromUninitialized(const RegType& uninit_type)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   const ImpreciseConstType& ByteConstant() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  const ImpreciseConstType& CharConstant() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   const ImpreciseConstType& ShortConstant() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   const ImpreciseConstType& IntConstant() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  const ImpreciseConstType& PosByteConstant() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  const ImpreciseConstType& PosShortConstant() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   const RegType& GetComponentType(const RegType& array, mirror::ClassLoader* loader)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void Dump(std::ostream& os) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);