Implement common super type in reference type propagation.
Currently only if both types are classes.
Change-Id: I06e98211ead56875a42bd17f099e319b107a50d4
diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc
index 3b78264..0d05c49 100644
--- a/compiler/optimizing/reference_type_propagation.cc
+++ b/compiler/optimizing/reference_type_propagation.cc
@@ -614,23 +614,36 @@
}
bool is_exact = a.IsExact() && b.IsExact();
- Handle<mirror::Class> type_handle;
+ ReferenceTypeInfo::TypeHandle result_type_handle;
+ ReferenceTypeInfo::TypeHandle a_type_handle = a.GetTypeHandle();
+ ReferenceTypeInfo::TypeHandle b_type_handle = b.GetTypeHandle();
+ bool a_is_interface = a_type_handle->IsInterface();
+ bool b_is_interface = b_type_handle->IsInterface();
if (a.GetTypeHandle().Get() == b.GetTypeHandle().Get()) {
- type_handle = a.GetTypeHandle();
+ result_type_handle = a_type_handle;
} else if (a.IsSupertypeOf(b)) {
- type_handle = a.GetTypeHandle();
+ result_type_handle = a_type_handle;
is_exact = false;
} else if (b.IsSupertypeOf(a)) {
- type_handle = b.GetTypeHandle();
+ result_type_handle = b_type_handle;
+ is_exact = false;
+ } else if (!a_is_interface && !b_is_interface) {
+ result_type_handle = handles_->NewHandle(a_type_handle->GetCommonSuperClass(b_type_handle));
is_exact = false;
} else {
- // TODO: Find the first common super class.
- type_handle = object_class_handle_;
+ // This can happen if:
+ // - both types are interfaces. TODO(calin): implement
+ // - one is an interface, the other a class, and the type does not implement the interface
+ // e.g:
+ // void foo(Interface i, boolean cond) {
+ // Object o = cond ? i : new Object();
+ // }
+ result_type_handle = object_class_handle_;
is_exact = false;
}
- return ReferenceTypeInfo::Create(type_handle, is_exact);
+ return ReferenceTypeInfo::Create(result_type_handle, is_exact);
}
static void UpdateArrayGet(HArrayGet* instr,
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index 91e1cec..9c2a887 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -802,6 +802,18 @@
}
}
+mirror::Class* Class::GetCommonSuperClass(Handle<Class> klass) {
+ DCHECK(klass.Get() != nullptr);
+ DCHECK(!klass->IsInterface());
+ DCHECK(!IsInterface());
+ mirror::Class* common_super_class = this;
+ while (!common_super_class->IsAssignableFrom(klass.Get())) {
+ common_super_class = common_super_class->GetSuperClass();
+ }
+ DCHECK(common_super_class != nullptr);
+ return common_super_class;
+}
+
const char* Class::GetSourceFile() {
const DexFile& dex_file = GetDexFile();
const DexFile::ClassDef* dex_class_def = GetClassDef();
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index c4339b9..3195f4f 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -657,6 +657,10 @@
ALWAYS_INLINE Class* GetSuperClass() SHARED_REQUIRES(Locks::mutator_lock_);
+ // Get first common super class. It will never return null.
+ // `This` and `klass` must be classes.
+ Class* GetCommonSuperClass(Handle<Class> klass) SHARED_REQUIRES(Locks::mutator_lock_);
+
void SetSuperClass(Class *new_super_class) SHARED_REQUIRES(Locks::mutator_lock_) {
// Super class is assigned once, except during class linker initialization.
Class* old_super_class = GetFieldObject<Class>(OFFSET_OF_OBJECT_MEMBER(Class, super_class_));
diff --git a/test/450-checker-types/src/Main.java b/test/450-checker-types/src/Main.java
index cd5e5a7..ec63057 100644
--- a/test/450-checker-types/src/Main.java
+++ b/test/450-checker-types/src/Main.java
@@ -14,17 +14,22 @@
* limitations under the License.
*/
-interface Interface {
+interface SuperInterface {
+ void superInterfaceMethod();
+}
+
+interface OtherInterface extends SuperInterface {
+}
+
+interface Interface extends SuperInterface {
void $noinline$f();
}
class Super implements Interface {
+ public void superInterfaceMethod() {}
public void $noinline$f() {
throw new RuntimeException();
}
-
- public int instanceField;
-
}
class SubclassA extends Super {
@@ -551,40 +556,30 @@
private void argumentCheck(Super s, double d, SubclassA a, Final f) {
}
- /// CHECK-START: Main Main.getMain(boolean) reference_type_propagation (after)
- /// CHECK: <<Phi:l\d+>> Phi klass:Main
- /// CHECK: Return [<<Phi>>]
- private Main getMain(boolean cond) {
- return cond ? null : new Main();
- }
-
- /// CHECK-START: Super Main.getSuper(boolean, SubclassA, SubclassB) reference_type_propagation (after)
- /// CHECK: <<Phi:l\d+>> Phi klass:java.lang.Object
- /// CHECK: Return [<<Phi>>]
- private Super getSuper(boolean cond, SubclassA a, SubclassB b) {
- return cond ? a : b;
- }
-
private Main getNull() {
return null;
}
private int mainField = 0;
- /// CHECK-START: void Main.testInlinerWidensReturnType(boolean, SubclassA, SubclassB) inliner (before)
- /// CHECK: <<Int:i\d+>> IntConstant 0
- /// CHECK: <<Invoke:l\d+>> InvokeStaticOrDirect klass:Super
- /// CHECK: <<NullCheck:l\d+>> NullCheck [<<Invoke>>] klass:Super exact:false
- /// CHECK: InstanceFieldSet [<<NullCheck>>,<<Int>>]
-
- /// CHECK-START: void Main.testInlinerWidensReturnType(boolean, SubclassA, SubclassB) inliner (after)
- /// CHECK: <<Int:i\d+>> IntConstant 0
+ /// CHECK-START: SuperInterface Main.getWiderType(boolean, Interface, OtherInterface) reference_type_propagation (after)
/// CHECK: <<Phi:l\d+>> Phi klass:java.lang.Object
- /// CHECK: <<NullCheck:l\d+>> NullCheck [<<Phi>>] klass:Super exact:false
- /// CHECK: InstanceFieldSet [<<NullCheck>>,<<Int>>]
- private void testInlinerWidensReturnType(boolean cond, SubclassA a, SubclassB b) {
- Super o = getSuper(cond, a, b);
- o.instanceField = 0;
+ /// CHECK: Return [<<Phi>>]
+ private SuperInterface getWiderType(boolean cond, Interface a, OtherInterface b) {
+ return cond ? a : b;
+ }
+
+ /// CHECK-START: void Main.testInlinerWidensReturnType(boolean, Interface, OtherInterface) inliner (before)
+ /// CHECK: <<Invoke:l\d+>> InvokeStaticOrDirect klass:SuperInterface
+ /// CHECK: <<NullCheck:l\d+>> NullCheck [<<Invoke>>] klass:SuperInterface exact:false
+ /// CHECK: InvokeInterface [<<NullCheck>>]
+
+ /// CHECK-START: void Main.testInlinerWidensReturnType(boolean, Interface, OtherInterface) inliner (after)
+ /// CHECK: <<Phi:l\d+>> Phi klass:java.lang.Object
+ /// CHECK: <<NullCheck:l\d+>> NullCheck [<<Phi>>] klass:SuperInterface exact:false
+ /// CHECK: InvokeInterface [<<NullCheck>>]
+ private void testInlinerWidensReturnType(boolean cond, Interface a, OtherInterface b) {
+ getWiderType(cond, a, b).superInterfaceMethod();
}
/// CHECK-START: void Main.testInlinerReturnsNull() inliner (before)
diff --git a/test/549-checker-types-merge/expected.txt b/test/549-checker-types-merge/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/549-checker-types-merge/expected.txt
diff --git a/test/549-checker-types-merge/info.txt b/test/549-checker-types-merge/info.txt
new file mode 100644
index 0000000..f174e20
--- /dev/null
+++ b/test/549-checker-types-merge/info.txt
@@ -0,0 +1 @@
+Checker test for testing the type merge during reference type propagation.
diff --git a/test/549-checker-types-merge/src/Main.java b/test/549-checker-types-merge/src/Main.java
new file mode 100644
index 0000000..dc27f10
--- /dev/null
+++ b/test/549-checker-types-merge/src/Main.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// To make it easier to follow the tests:
+// - all interfaces defined in this file extend InterfaceSuper (except InterfaceOtherSuper)
+// - all classes defined in this file extend ClassSuper (except ClassOtherSuper)
+
+interface InterfaceSuper {}
+interface InterfaceOtherSuper {}
+
+interface InterfaceA extends InterfaceSuper {}
+interface InterfaceB extends InterfaceSuper {}
+interface InterfaceExtendsA extends InterfaceA {}
+interface InterfaceExtendsB extends InterfaceB {}
+
+class ClassSuper {}
+class ClassOtherSuper {}
+
+class ClassA extends ClassSuper {}
+class ClassB extends ClassSuper {}
+class ClassExtendsA extends ClassA {}
+class ClassExtendsB extends ClassB {}
+
+class ClassImplementsInterfaceA extends ClassSuper implements InterfaceA {}
+
+public class Main {
+
+ /// CHECK-START: java.lang.Object Main.testMergeNullContant(boolean) reference_type_propagation (after)
+ /// CHECK: <<Phi:l\d+>> Phi klass:Main
+ /// CHECK: Return [<<Phi>>]
+ private Object testMergeNullContant(boolean cond) {
+ return cond ? null : new Main();
+ }
+
+ /// CHECK-START: java.lang.Object Main.testMergeClasses(boolean, ClassExtendsA, ClassExtendsB) reference_type_propagation (after)
+ /// CHECK: <<Phi:l\d+>> Phi klass:ClassSuper
+ /// CHECK: Return [<<Phi>>]
+ private Object testMergeClasses(boolean cond, ClassExtendsA a, ClassExtendsB b) {
+ // Different classes, have a common super type.
+ return cond ? a : b;
+ }
+
+ /// CHECK-START: java.lang.Object Main.testMergeClasses(boolean, ClassExtendsA, ClassSuper) reference_type_propagation (after)
+ /// CHECK: <<Phi:l\d+>> Phi klass:ClassSuper
+ /// CHECK: Return [<<Phi>>]
+ private Object testMergeClasses(boolean cond, ClassExtendsA a, ClassSuper b) {
+ // Different classes, one is the super type of the other.
+ return cond ? a : b;
+ }
+
+ /// CHECK-START: java.lang.Object Main.testMergeClasses(boolean, ClassSuper, ClassSuper) reference_type_propagation (after)
+ /// CHECK: <<Phi:l\d+>> Phi klass:ClassSuper
+ /// CHECK: Return [<<Phi>>]
+ private Object testMergeClasses(boolean cond, ClassSuper a, ClassSuper b) {
+ // Same classes.
+ return cond ? a : b;
+ }
+
+ /// CHECK-START: java.lang.Object Main.testMergeClasses(boolean, ClassOtherSuper, ClassSuper) reference_type_propagation (after)
+ /// CHECK: <<Phi:l\d+>> Phi klass:java.lang.Object
+ /// CHECK: Return [<<Phi>>]
+ private Object testMergeClasses(boolean cond, ClassOtherSuper a, ClassSuper b) {
+ // Different classes, have Object as the common super type.
+ return cond ? a : b;
+ }
+
+ /// CHECK-START: java.lang.Object Main.testMergeClassWithInterface(boolean, ClassImplementsInterfaceA, InterfaceSuper) reference_type_propagation (after)
+ /// CHECK: <<Phi:l\d+>> Phi klass:InterfaceSuper
+ /// CHECK: Return [<<Phi>>]
+ private Object testMergeClassWithInterface(boolean cond, ClassImplementsInterfaceA a, InterfaceSuper b) {
+ // Class implements interface.
+ return cond ? a : b;
+ }
+
+ /// CHECK-START: java.lang.Object Main.testMergeClassWithInterface(boolean, ClassSuper, InterfaceSuper) reference_type_propagation (after)
+ /// CHECK: <<Phi:l\d+>> Phi klass:java.lang.Object
+ /// CHECK: Return [<<Phi>>]
+ private Object testMergeClassWithInterface(boolean cond, ClassSuper a, InterfaceSuper b) {
+ // Class doesn't implement interface.
+ return cond ? a : b;
+ }
+
+ /// CHECK-START: java.lang.Object Main.testMergeInterfaces(boolean, InterfaceExtendsA, InterfaceSuper) reference_type_propagation (after)
+ /// CHECK: <<Phi:l\d+>> Phi klass:InterfaceSuper
+ /// CHECK: Return [<<Phi>>]
+ private Object testMergeInterfaces(boolean cond, InterfaceExtendsA a, InterfaceSuper b) {
+ // Different Interfaces, one implements the other.
+ return cond ? a : b;
+ }
+
+ /// CHECK-START: java.lang.Object Main.testMergeInterfaces(boolean, InterfaceSuper, InterfaceSuper) reference_type_propagation (after)
+ /// CHECK: <<Phi:l\d+>> Phi klass:InterfaceSuper
+ /// CHECK: Return [<<Phi>>]
+ private Object testMergeInterfaces(boolean cond, InterfaceSuper a, InterfaceSuper b) {
+ // Same interfaces.
+ return cond ? a : b;
+ }
+
+ /// CHECK-START: java.lang.Object Main.testMergeInterfaces(boolean, InterfaceExtendsA, InterfaceExtendsB) reference_type_propagation (after)
+ /// CHECK: <<Phi:l\d+>> Phi klass:java.lang.Object
+ /// CHECK: Return [<<Phi>>]
+ private Object testMergeInterfaces(boolean cond, InterfaceExtendsA a, InterfaceExtendsB b) {
+ // Different Interfaces, have a common super type.
+ return cond ? a : b;
+ }
+
+ /// CHECK-START: java.lang.Object Main.testMergeInterfaces(boolean, InterfaceSuper, InterfaceOtherSuper) reference_type_propagation (after)
+ /// CHECK: <<Phi:l\d+>> Phi klass:java.lang.Object
+ /// CHECK: Return [<<Phi>>]
+ private Object testMergeInterfaces(boolean cond, InterfaceSuper a, InterfaceOtherSuper b) {
+ // Different interfaces.
+ return cond ? a : b;
+ }
+
+ public static void main(String[] args) {
+ }
+}