Merge "Adjust art::HTypeConversion's side effects for MIPS64."
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index 931a1c3..df6e550 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -238,12 +238,19 @@
   }
 
   bool outcome;
-  if (TypeCheckHasKnownOutcome(check_cast->InputAt(1)->AsLoadClass(), object, &outcome)) {
+  HLoadClass* load_class = check_cast->InputAt(1)->AsLoadClass();
+  if (TypeCheckHasKnownOutcome(load_class, object, &outcome)) {
     if (outcome) {
       check_cast->GetBlock()->RemoveInstruction(check_cast);
       if (stats_ != nullptr) {
         stats_->RecordStat(MethodCompilationStat::kRemovedCheckedCast);
       }
+      if (!load_class->HasUses()) {
+        // We cannot rely on DCE to remove the class because the `HLoadClass` thinks it can throw.
+        // However, here we know that it cannot because the checkcast was successfull, hence
+        // the class was already loaded.
+        load_class->GetBlock()->RemoveInstruction(load_class);
+      }
     } else {
       // Don't do anything for exceptional cases for now. Ideally we should remove
       // all instructions and blocks this instruction dominates.
@@ -268,7 +275,8 @@
   }
 
   bool outcome;
-  if (TypeCheckHasKnownOutcome(instruction->InputAt(1)->AsLoadClass(), object, &outcome)) {
+  HLoadClass* load_class = instruction->InputAt(1)->AsLoadClass();
+  if (TypeCheckHasKnownOutcome(load_class, object, &outcome)) {
     if (outcome && can_be_null) {
       // Type test will succeed, we just need a null test.
       HNotEqual* test = new (graph->GetArena()) HNotEqual(graph->GetNullConstant(), object);
@@ -280,6 +288,12 @@
     }
     RecordSimplification();
     instruction->GetBlock()->RemoveInstruction(instruction);
+    if (outcome && !load_class->HasUses()) {
+      // We cannot rely on DCE to remove the class because the `HLoadClass` thinks it can throw.
+      // However, here we know that it cannot because the instanceof check was successfull, hence
+      // the class was already loaded.
+      load_class->GetBlock()->RemoveInstruction(load_class);
+    }
   }
 }
 
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index a7ff67e..0df5d6d 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -3031,6 +3031,10 @@
     return false;
   }
 
+  bool CanBeNull() const OVERRIDE {
+    return return_type_ == Primitive::kPrimNot && !IsStringInit();
+  }
+
   InvokeType GetInvokeType() const { return invoke_type_; }
   bool IsRecursive() const { return is_recursive_; }
   bool NeedsDexCache() const OVERRIDE { return !IsRecursive(); }
diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc
index d1c1134..1349df9 100644
--- a/compiler/optimizing/reference_type_propagation.cc
+++ b/compiler/optimizing/reference_type_propagation.cc
@@ -167,6 +167,9 @@
     bound_type->SetReferenceTypeInfo(
         ReferenceTypeInfo::Create(class_rti.GetTypeHandle(), /* is_exact */ false));
   }
+  if (upper_can_be_null) {
+    bound_type->SetCanBeNull(obj->CanBeNull());
+  }
   return bound_type;
 }
 
@@ -485,6 +488,10 @@
               true /* CheckCast succeeds for nulls. */);
           check_cast->GetBlock()->InsertInstructionAfter(bound_type, check_cast);
         } else {
+          // Update nullability of the existing bound type, which may not have known
+          // that its input was not null when it was being created.
+          bound_type = check_cast->GetNext()->AsBoundType();
+          bound_type->SetCanBeNull(obj->CanBeNull());
           // We already have a bound type on the position we would need to insert
           // the new one. The existing bound type should dominate all the users
           // (dchecked) so there's no need to continue.
diff --git a/test/494-checker-instanceof-tests/src/Main.java b/test/494-checker-instanceof-tests/src/Main.java
index bff9c72..2eac6c9 100644
--- a/test/494-checker-instanceof-tests/src/Main.java
+++ b/test/494-checker-instanceof-tests/src/Main.java
@@ -129,6 +129,26 @@
     return $inline$interfaceTypeTest(finalUnrelatedField);
   }
 
+  // Check that we remove the LoadClass instruction from the graph.
+  /// CHECK-START: boolean Main.knownTestWithLoadedClass() register (after)
+  /// CHECK-NOT: LoadClass
+  public static boolean knownTestWithLoadedClass() {
+    return new String() instanceof String;
+  }
+
+  // Check that we do not remove the LoadClass instruction from the graph.
+  /// CHECK-START: boolean Main.knownTestWithUnloadedClass() register (after)
+  /// CHECK: <<Const:i\d+>> IntConstant 0
+  /// CHECK:                LoadClass
+  /// CHECK:                Return [<<Const>>]
+  public static boolean knownTestWithUnloadedClass() {
+    return $inline$returnMain() instanceof String;
+  }
+
+  public static Object $inline$returnMain() {
+    return new Main();
+  }
+
   public static void expect(boolean expected, boolean actual) {
     if (expected != actual) {
       throw new Error("Unexpected result");
diff --git a/test/495-checker-checkcast-tests/src/Main.java b/test/495-checker-checkcast-tests/src/Main.java
index aa6d5a7..4b2bf09 100644
--- a/test/495-checker-checkcast-tests/src/Main.java
+++ b/test/495-checker-checkcast-tests/src/Main.java
@@ -112,6 +112,33 @@
     return $inline$interfaceTypeTest(finalUnrelatedField);
   }
 
+  /// CHECK-START: java.lang.String Main.knownTestWithLoadedClass() register (after)
+  /// CHECK-NOT: LoadClass
+  public static String knownTestWithLoadedClass() {
+    return (String)$inline$getString();
+  }
+
+  /// CHECK-START: Itf Main.knownTestWithUnloadedClass() register (after)
+  /// CHECK: LoadClass
+  public static Itf knownTestWithUnloadedClass() {
+    return (Itf)$inline$getString();
+  }
+
+  public static Object $inline$getString() {
+    return new String();
+  }
+
+  public static Object $inline$getMain() {
+    return new Main();
+  }
+
+  /// CHECK-START: void Main.nonNullBoundType() register (after)
+  /// CHECK-NOT: NullCheck
+  public static void nonNullBoundType() {
+    Main main = (Main)$inline$getMain();
+    main.getClass();
+  }
+
   public static void main(String[] args) {
     classTypeTestNull();
     try {