Reference type propagation

- propagate reference types between instructions
- remove checked casts when possible
- add StackHandleScopeCollection to manage an arbitrary number of stack
handles (see comments)

Change-Id: I31200067c5e7375a5ea8e2f873c4374ebdb5ee60
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index cebde3b..c7b8343 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -18,8 +18,11 @@
 #define ART_COMPILER_OPTIMIZING_NODES_H_
 
 #include "entrypoints/quick/quick_entrypoints_enum.h"
+#include "handle.h"
+#include "handle_scope.h"
 #include "invoke_type.h"
 #include "locations.h"
+#include "mirror/class.h"
 #include "offsets.h"
 #include "primitive.h"
 #include "utils/arena_object.h"
@@ -871,6 +874,88 @@
   DISALLOW_COPY_AND_ASSIGN(HEnvironment);
 };
 
+class ReferenceTypeInfo : ValueObject {
+ public:
+  ReferenceTypeInfo() : is_exact_(false), is_top_(true) {}
+  ReferenceTypeInfo(Handle<mirror::Class> type_handle, bool is_exact) {
+    SetTypeHandle(type_handle, is_exact);
+  }
+
+  bool IsExact() const { return is_exact_; }
+  bool IsTop() const { return is_top_; }
+
+  Handle<mirror::Class> GetTypeHandle() const { return type_handle_; }
+
+  void SetTop() {
+    is_top_ = true;
+    type_handle_ = Handle<mirror::Class>();
+  }
+
+  void SetInexact() { is_exact_ = false; }
+
+  void SetTypeHandle(Handle<mirror::Class> type_handle, bool is_exact)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    is_exact_ =  is_exact;
+    if (type_handle->IsObjectClass()) {
+      is_top_ = true;
+      // Override the type handle to be consistent with the case when we get to
+      // Top but don't have the Object class available. It avoids having to guess
+      // what value the type_handle has when it's Top.
+      type_handle_ = Handle<mirror::Class>();
+    } else {
+      is_top_ = false;
+      type_handle_ = type_handle;
+    }
+  }
+
+  bool IsSupertypeOf(ReferenceTypeInfo rti) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    if (IsTop()) {
+      // Top (equivalent for java.lang.Object) is supertype of anything.
+      return true;
+    }
+    if (rti.IsTop()) {
+      // If we get here `this` is not Top() so it can't be a supertype.
+      return false;
+    }
+    return GetTypeHandle()->IsAssignableFrom(rti.GetTypeHandle().Get());
+  }
+
+  // Returns true if the type information provide the same amount of details.
+  // Note that it does not mean that the instructions have the same actual type
+  // (e.g. tops are equal but they can be the result of a merge).
+  bool IsEqual(ReferenceTypeInfo rti) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    if (IsExact() != rti.IsExact()) {
+      return false;
+    }
+    if (IsTop() && rti.IsTop()) {
+      // `Top` means java.lang.Object, so the types are equivalent.
+      return true;
+    }
+    if (IsTop() || rti.IsTop()) {
+      // If only one is top or object than they are not equivalent.
+      // NB: We need this extra check because the type_handle of `Top` is invalid
+      // and we cannot inspect its reference.
+      return false;
+    }
+
+    // Finally check the types.
+    return GetTypeHandle().Get() == rti.GetTypeHandle().Get();
+  }
+
+ private:
+  // The class of the object.
+  Handle<mirror::Class> type_handle_;
+  // Whether or not the type is exact or a superclass of the actual type.
+  bool is_exact_;
+  // A true value here means that the object type should be java.lang.Object.
+  // We don't have access to the corresponding mirror object every time so this
+  // flag acts as a substitute. When true, the TypeHandle refers to a null
+  // pointer and should not be used.
+  bool is_top_;
+};
+
+std::ostream& operator<<(std::ostream& os, const ReferenceTypeInfo& rhs);
+
 class HInstruction : public ArenaObject<kArenaAllocMisc> {
  public:
   explicit HInstruction(SideEffects side_effects)
@@ -928,6 +1013,12 @@
 
   virtual bool CanDoImplicitNullCheck() const { return false; }
 
+  void SetReferenceTypeInfo(ReferenceTypeInfo reference_type_info) {
+    reference_type_info_ = reference_type_info;
+  }
+
+  ReferenceTypeInfo GetReferenceTypeInfo() const { return reference_type_info_; }
+
   void AddUseAt(HInstruction* user, size_t index) {
     uses_.AddUse(user, index, GetBlock()->GetGraph()->GetArena());
   }
@@ -1072,6 +1163,9 @@
 
   const SideEffects side_effects_;
 
+  // TODO: for primitive types this should be marked as invalid.
+  ReferenceTypeInfo reference_type_info_;
+
   friend class HBasicBlock;
   friend class HGraph;
   friend class HInstructionList;
@@ -2684,6 +2778,20 @@
     return !is_referrers_class_;
   }
 
+  ReferenceTypeInfo GetLoadedClassRTI() {
+    return loaded_class_rti_;
+  }
+
+  void SetLoadedClassRTI(ReferenceTypeInfo rti) {
+    // Make sure we only set exact types (the loaded class should never be merged).
+    DCHECK(rti.IsExact());
+    loaded_class_rti_ = rti;
+  }
+
+  bool IsResolved() {
+    return loaded_class_rti_.IsExact();
+  }
+
   DECLARE_INSTRUCTION(LoadClass);
 
  private:
@@ -2694,6 +2802,8 @@
   // Used for code generation.
   bool generate_clinit_check_;
 
+  ReferenceTypeInfo loaded_class_rti_;
+
   DISALLOW_COPY_AND_ASSIGN(HLoadClass);
 };