ART: Add null type to verifier

Add a null type to distinguish zero from null. This is an
infra-only change, as nothing will introduce null with this
commit, yet.

Bug: 22059710
Bug: 64683522
Bug: 69669661
Test: m test-art-host
Change-Id: Id2549a5aefefe9471d4bdbd2c8993395150947c6
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index c6ba2f7..978e51d 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -2237,7 +2237,7 @@
           Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "return-object not expected";
         } else {
           /* return_type is the *expected* return type, not register value */
-          DCHECK(!return_type.IsZero());
+          DCHECK(!return_type.IsZeroOrNull());
           DCHECK(!return_type.IsUninitializedReference());
           const uint32_t vregA = inst->VRegA_11x();
           const RegType& reg_type = work_line_->GetRegisterType(this, vregA);
@@ -2485,7 +2485,8 @@
     case Instruction::ARRAY_LENGTH: {
       const RegType& res_type = work_line_->GetRegisterType(this, inst->VRegB_12x());
       if (res_type.IsReferenceTypes()) {
-        if (!res_type.IsArrayTypes() && !res_type.IsZero()) {  // ie not an array or null
+        if (!res_type.IsArrayTypes() && !res_type.IsZeroOrNull()) {
+          // ie not an array or null
           Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "array-length on non-array " << res_type;
         } else {
           work_line_->SetRegisterType<LockOp::kClear>(this,
@@ -2592,7 +2593,7 @@
       /* Similar to the verification done for APUT */
       const RegType& array_type = work_line_->GetRegisterType(this, inst->VRegA_31t());
       /* array_type can be null if the reg type is Zero */
-      if (!array_type.IsZero()) {
+      if (!array_type.IsZeroOrNull()) {
         if (!array_type.IsArrayTypes()) {
           Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid fill-array-data with array type "
                                             << array_type;
@@ -2632,7 +2633,7 @@
       const RegType& reg_type1 = work_line_->GetRegisterType(this, inst->VRegA_22t());
       const RegType& reg_type2 = work_line_->GetRegisterType(this, inst->VRegB_22t());
       bool mismatch = false;
-      if (reg_type1.IsZero()) {  // zero then integral or reference expected
+      if (reg_type1.IsZeroOrNull()) {  // zero then integral or reference expected
         mismatch = !reg_type2.IsReferenceTypes() && !reg_type2.IsIntegralTypes();
       } else if (reg_type1.IsReferenceTypes()) {  // both references?
         mismatch = !reg_type2.IsReferenceTypes();
@@ -2717,7 +2718,7 @@
             !cast_type.IsUnresolvedTypes() && !orig_type.IsUnresolvedTypes() &&
             cast_type.HasClass() &&             // Could be conflict type, make sure it has a class.
             !cast_type.GetClass()->IsInterface() &&
-            (orig_type.IsZero() ||
+            (orig_type.IsZeroOrNull() ||
                 orig_type.IsStrictlyAssignableFrom(
                     cast_type.Merge(orig_type, &reg_types_, this), this))) {
           RegisterLine* update_line = RegisterLine::Create(code_item_accessor_.RegistersSize(),
@@ -3005,7 +3006,7 @@
           break;
 
         /* no null refs allowed (?) */
-        if (this_type.IsZero()) {
+        if (this_type.IsZeroOrNull()) {
           Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "unable to initialize null ref";
           break;
         }
@@ -3082,7 +3083,7 @@
        * interface or Object (see comments in RegType::JoinClass).
        */
       const RegType& this_type = work_line_->GetInvocationThis(this, inst);
-      if (this_type.IsZero()) {
+      if (this_type.IsZeroOrNull()) {
         /* null pointer always passes (and always fails at runtime) */
       } else {
         if (this_type.IsUninitializedTypes()) {
@@ -4081,7 +4082,7 @@
     const RegType& adjusted_type = is_init
                                        ? GetRegTypeCache()->FromUninitialized(actual_arg_type)
                                        : actual_arg_type;
-    if (method_type != METHOD_INTERFACE && !adjusted_type.IsZero()) {
+    if (method_type != METHOD_INTERFACE && !adjusted_type.IsZeroOrNull()) {
       const RegType* res_method_class;
       // Miranda methods have the declaring interface as their declaring class, not the abstract
       // class. It would be wrong to use this for the type check (interface type checks are
@@ -4454,7 +4455,7 @@
 
 bool MethodVerifier::CheckSignaturePolymorphicReceiver(const Instruction* inst) {
   const RegType& this_type = work_line_->GetInvocationThis(this, inst);
-  if (this_type.IsZero()) {
+  if (this_type.IsZeroOrNull()) {
     /* null pointer always passes (and always fails at run time) */
     return true;
   } else if (!this_type.IsNonZeroReferenceTypes()) {
@@ -4573,7 +4574,7 @@
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "'this' arg must be initialized";
     return nullptr;
   }
-  if (!actual_arg_type.IsZero()) {
+  if (!actual_arg_type.IsZeroOrNull()) {
     mirror::Class* klass = res_method->GetDeclaringClass();
     std::string temp;
     const RegType& res_method_class =
@@ -4689,7 +4690,7 @@
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Invalid reg type for array index (" << index_type << ")";
   } else {
     const RegType& array_type = work_line_->GetRegisterType(this, inst->VRegB_23x());
-    if (array_type.IsZero()) {
+    if (array_type.IsZeroOrNull()) {
       have_pending_runtime_throw_failure_ = true;
       // Null array class; this code path will fail at runtime. Infer a merge-able type from the
       // instruction type. TODO: have a proper notion of bottom here.
@@ -4804,7 +4805,7 @@
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Invalid reg type for array index (" << index_type << ")";
   } else {
     const RegType& array_type = work_line_->GetRegisterType(this, inst->VRegB_23x());
-    if (array_type.IsZero()) {
+    if (array_type.IsZeroOrNull()) {
       // Null array type; this code path will fail at runtime.
       // Still check that the given value matches the instruction's type.
       // Note: this is, as usual, complicated by the fact the the instruction isn't fully typed
@@ -4926,7 +4927,7 @@
     DCHECK(self_->IsExceptionPending());
     self_->ClearException();
     return nullptr;
-  } else if (obj_type.IsZero()) {
+  } else if (obj_type.IsZeroOrNull()) {
     // Cannot infer and check type, however, access will cause null pointer exception.
     // Fall through into a few last soft failure checks below.
   } else if (!obj_type.IsReferenceTypes()) {
diff --git a/runtime/verifier/reg_type-inl.h b/runtime/verifier/reg_type-inl.h
index 631c6bd..f719782 100644
--- a/runtime/verifier/reg_type-inl.h
+++ b/runtime/verifier/reg_type-inl.h
@@ -29,6 +29,8 @@
 namespace verifier {
 
 inline bool RegType::CanAccess(const RegType& other) const {
+  DCHECK(IsReferenceTypes());
+  DCHECK(!IsNull());
   if (Equals(other)) {
     return true;  // Trivial accessibility.
   } else {
@@ -45,9 +47,13 @@
 }
 
 inline bool RegType::CanAccessMember(ObjPtr<mirror::Class> klass, uint32_t access_flags) const {
+  DCHECK(IsReferenceTypes());
   if ((access_flags & kAccPublic) != 0) {
     return true;
   }
+  if (IsNull()) {
+    return true;
+  }
   if (!IsUnresolvedTypes()) {
     return GetClass()->CanAccessMember(klass, access_flags);
   } else {
@@ -92,7 +98,7 @@
         LOG(WARNING) << "RegType::AssignableFrom lhs is Conflict!";
         return false;
       case AssignmentType::kReference:
-        if (rhs.IsZero()) {
+        if (rhs.IsZeroOrNull()) {
           return true;  // All reference types can be assigned null.
         } else if (!rhs.IsReferenceTypes()) {
           return false;  // Expect rhs to be a reference type.
@@ -119,6 +125,7 @@
           return result;
         } else {
           // Unresolved types are only assignable for null and equality.
+          // Null cannot be the left-hand side.
           return false;
         }
       case AssignmentType::kNotAssignable:
@@ -199,6 +206,11 @@
   return instance_;
 }
 
+inline const NullType* NullType::GetInstance() {
+  DCHECK(instance_ != nullptr);
+  return instance_;
+}
+
 inline void* RegType::operator new(size_t size, ScopedArenaAllocator* allocator) {
   return allocator->Alloc(size, kArenaAllocMisc);
 }
diff --git a/runtime/verifier/reg_type.cc b/runtime/verifier/reg_type.cc
index 8df2e0f..309c374 100644
--- a/runtime/verifier/reg_type.cc
+++ b/runtime/verifier/reg_type.cc
@@ -51,6 +51,7 @@
 const DoubleLoType* DoubleLoType::instance_ = nullptr;
 const DoubleHiType* DoubleHiType::instance_ = nullptr;
 const IntegerType* IntegerType::instance_ = nullptr;
+const NullType* NullType::instance_ = nullptr;
 
 PrimitiveType::PrimitiveType(mirror::Class* klass, const StringPiece& descriptor, uint16_t cache_id)
     : RegType(klass, descriptor, cache_id) {
@@ -581,6 +582,10 @@
   return a.IsConstantTypes() ? b : a;
 }
 
+static const RegType& SelectNonConstant2(const RegType& a, const RegType& b) {
+  return a.IsConstantTypes() ? (b.IsZero() ? a : b) : a;
+}
+
 const RegType& RegType::Merge(const RegType& incoming_type,
                               RegTypeCache* reg_types,
                               MethodVerifier* verifier) const {
@@ -695,8 +700,8 @@
       // special. They may only ever be merged with themselves (must be taken care of by the
       // caller of Merge(), see the DCHECK on entry). So mark any other merge as conflicting here.
       return conflict;
-    } else if (IsZero() || incoming_type.IsZero()) {
-      return SelectNonConstant(*this, incoming_type);  // 0 MERGE ref => ref
+    } else if (IsZeroOrNull() || incoming_type.IsZeroOrNull()) {
+      return SelectNonConstant2(*this, incoming_type);  // 0 MERGE ref => ref
     } else if (IsJavaLangObject() || incoming_type.IsJavaLangObject()) {
       return reg_types->JavaLangObject(false);  // Object MERGE ref => Object
     } else if (IsUnresolvedTypes() || incoming_type.IsUnresolvedTypes()) {
@@ -965,6 +970,21 @@
   return cmp1.CanAssignArray(cmp2, reg_types, class_loader, verifier, soft_error);
 }
 
+const NullType* NullType::CreateInstance(mirror::Class* klass,
+                                         const StringPiece& descriptor,
+                                         uint16_t cache_id) {
+  CHECK(instance_ == nullptr);
+  instance_ = new NullType(klass, descriptor, cache_id);
+  return instance_;
+}
+
+void NullType::Destroy() {
+  if (NullType::instance_ != nullptr) {
+    delete instance_;
+    instance_ = nullptr;
+  }
+}
+
 
 }  // namespace verifier
 }  // namespace art
diff --git a/runtime/verifier/reg_type.h b/runtime/verifier/reg_type.h
index a2085a3..9055849 100644
--- a/runtime/verifier/reg_type.h
+++ b/runtime/verifier/reg_type.h
@@ -129,8 +129,12 @@
   virtual bool IsConstantShort() const { return false; }
   virtual bool IsOne() const { return false; }
   virtual bool IsZero() const { return false; }
+  virtual bool IsNull() const { return false; }
   bool IsReferenceTypes() const {
-    return IsNonZeroReferenceTypes() || IsZero();
+    return IsNonZeroReferenceTypes() || IsZero() || IsNull();
+  }
+  bool IsZeroOrNull() const {
+    return IsZero() || IsNull();
   }
   virtual bool IsNonZeroReferenceTypes() const { return false; }
   bool IsCategory1Types() const {
@@ -857,6 +861,46 @@
   }
 };
 
+// Special "null" type that captures the semantics of null / bottom.
+class NullType FINAL : public RegType {
+ public:
+  bool IsNull() const OVERRIDE {
+    return true;
+  }
+
+  // Get the singleton Null instance.
+  static const NullType* GetInstance() PURE;
+
+  // Create the singleton instance.
+  static const NullType* CreateInstance(mirror::Class* klass,
+                                        const StringPiece& descriptor,
+                                        uint16_t cache_id)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
+  static void Destroy();
+
+  std::string Dump() const OVERRIDE {
+    return "null";
+  }
+
+  AssignmentType GetAssignmentTypeImpl() const OVERRIDE {
+    return AssignmentType::kReference;
+  }
+
+  bool IsConstantTypes() const OVERRIDE {
+    return true;
+  }
+
+ private:
+  NullType(mirror::Class* klass, const StringPiece& descriptor, uint16_t cache_id)
+      REQUIRES_SHARED(Locks::mutator_lock_)
+      : RegType(klass, descriptor, cache_id) {
+    CheckConstructorInvariants(this);
+  }
+
+  static const NullType* instance_;
+};
+
 // Common parent of all uninitialized types. Uninitialized types are created by
 // "new" dex
 // instructions and must be passed to a constructor.
diff --git a/runtime/verifier/reg_type_cache-inl.h b/runtime/verifier/reg_type_cache-inl.h
index 197c976..61f34af 100644
--- a/runtime/verifier/reg_type_cache-inl.h
+++ b/runtime/verifier/reg_type_cache-inl.h
@@ -81,6 +81,9 @@
 inline const ConflictType& RegTypeCache::Conflict() {
   return *ConflictType::GetInstance();
 }
+inline const NullType& RegTypeCache::Null() {
+  return *NullType::GetInstance();
+}
 
 inline const ImpreciseConstType& RegTypeCache::ByteConstant() {
   const ConstantType& result = FromCat1Const(std::numeric_limits<jbyte>::min(), false);
diff --git a/runtime/verifier/reg_type_cache.cc b/runtime/verifier/reg_type_cache.cc
index 4808381..a3f08c8 100644
--- a/runtime/verifier/reg_type_cache.cc
+++ b/runtime/verifier/reg_type_cache.cc
@@ -56,6 +56,7 @@
   // Note: this must have the same order as CreatePrimitiveAndSmallConstantTypes.
   entries_.push_back(UndefinedType::GetInstance());
   entries_.push_back(ConflictType::GetInstance());
+  entries_.push_back(NullType::GetInstance());
   entries_.push_back(BooleanType::GetInstance());
   entries_.push_back(ByteType::GetInstance());
   entries_.push_back(ShortType::GetInstance());
@@ -307,6 +308,7 @@
     FloatType::Destroy();
     DoubleLoType::Destroy();
     DoubleHiType::Destroy();
+    NullType::Destroy();
     for (int32_t value = kMinSmallConstant; value <= kMaxSmallConstant; ++value) {
       const PreciseConstType* type = small_precise_constants_[value - kMinSmallConstant];
       delete type;
@@ -354,6 +356,7 @@
   };
   create_primitive_type_instance(TypeHelper<UndefinedType>(""));
   create_primitive_type_instance(TypeHelper<ConflictType>(""));
+  create_primitive_type_instance(TypeHelper<NullType>(""));
   create_primitive_type_instance(TypeHelper<BooleanType>("Z"));
   create_primitive_type_instance(TypeHelper<ByteType>("B"));
   create_primitive_type_instance(TypeHelper<ShortType>("S"));
diff --git a/runtime/verifier/reg_type_cache.h b/runtime/verifier/reg_type_cache.h
index 054a2af..5277676 100644
--- a/runtime/verifier/reg_type_cache.h
+++ b/runtime/verifier/reg_type_cache.h
@@ -49,6 +49,7 @@
 class LongHiType;
 class LongLoType;
 class MethodVerifier;
+class NullType;
 class PreciseConstType;
 class PreciseReferenceType;
 class RegType;
@@ -123,6 +124,7 @@
   const DoubleHiType& DoubleHi() REQUIRES_SHARED(Locks::mutator_lock_);
   const UndefinedType& Undefined() REQUIRES_SHARED(Locks::mutator_lock_);
   const ConflictType& Conflict();
+  const NullType& Null();
 
   const PreciseReferenceType& JavaLangClass() REQUIRES_SHARED(Locks::mutator_lock_);
   const PreciseReferenceType& JavaLangString() REQUIRES_SHARED(Locks::mutator_lock_);
@@ -180,7 +182,7 @@
                                                           kMinSmallConstant + 1];
 
   static constexpr size_t kNumPrimitivesAndSmallConstants =
-      12 + (kMaxSmallConstant - kMinSmallConstant + 1);
+      13 + (kMaxSmallConstant - kMinSmallConstant + 1);
 
   // Have the well known global primitives been created?
   static bool primitive_initialized_;
diff --git a/runtime/verifier/reg_type_test.cc b/runtime/verifier/reg_type_test.cc
index 6edeece..15a38f3 100644
--- a/runtime/verifier/reg_type_test.cc
+++ b/runtime/verifier/reg_type_test.cc
@@ -690,6 +690,8 @@
   //      |                              |               |        |         |        |         |
   //      |                              #---------------#--------#---------#--------#---------#
   //      |                                                       |
+  //      |                                                     null
+  //      |                                                       |
   //      #--------------------------#----------------------------#
   //                                 |
   //                                 0
@@ -707,6 +709,7 @@
 
   const RegType& conflict = cache.Conflict();
   const RegType& zero = cache.Zero();
+  const RegType& null = cache.Null();
   const RegType& int_type = cache.Integer();
 
   const RegType& obj = cache.JavaLangObject(false);
@@ -799,6 +802,7 @@
                                    plain_nonobj_arr_classes.begin(),
                                    plain_nonobj_arr_classes.end());
   all_minus_uninit_conflict.push_back(&zero);
+  all_minus_uninit_conflict.push_back(&null);
   all_minus_uninit_conflict.push_back(&obj);
 
   std::vector<const RegType*> all_minus_uninit;
@@ -853,10 +857,12 @@
     ADD_EDGE(int_type, conflict);
   }
 
+  ADD_EDGE(zero, null);
+
   // Unresolved.
   {
-    ADD_EDGE(zero, unresolved_a);
-    ADD_EDGE(zero, unresolved_b);
+    ADD_EDGE(null, unresolved_a);
+    ADD_EDGE(null, unresolved_b);
     ADD_EDGE(unresolved_a, unresolved_ab);
     ADD_EDGE(unresolved_b, unresolved_ab);
 
@@ -887,7 +893,7 @@
 
   // Classes.
   {
-    ADD_EDGE(zero, integer);
+    ADD_EDGE(null, integer);
     ADD_EDGE(integer, number);
     ADD_EDGE(number, obj);
   }
@@ -902,10 +908,10 @@
     ADD_EDGE(char_arr, obj);
     ADD_EDGE(byte_arr, obj);
 
-    ADD_EDGE(zero, integer_arr);
-    ADD_EDGE(zero, number_arr_arr);
-    ADD_EDGE(zero, char_arr);
-    ADD_EDGE(zero, byte_arr);
+    ADD_EDGE(null, integer_arr);
+    ADD_EDGE(null, number_arr_arr);
+    ADD_EDGE(null, char_arr);
+    ADD_EDGE(null, byte_arr);
   }
 
   // Primitive.