- Tune CanBeNull for HBoundType.
- Remove LoadClass when we know the class is loaded.
- Tune CanBeNull for StringInit.
Change-Id: I564ed33a506d65e991a514342bdfd1610bed0cf5
}
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.
}
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);
}
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);
+ }
}
}
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(); }
bound_type->SetReferenceTypeInfo(
ReferenceTypeInfo::Create(class_rti.GetTypeHandle(), /* is_exact */ false));
}
+ if (upper_can_be_null) {
+ bound_type->SetCanBeNull(obj->CanBeNull());
+ }
return bound_type;
}
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.
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");
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 {