diff options
| -rw-r--r-- | compiler/optimizing/reference_type_propagation.cc | 27 | ||||
| -rw-r--r-- | runtime/mirror/class.cc | 12 | ||||
| -rw-r--r-- | runtime/mirror/class.h | 4 | ||||
| -rw-r--r-- | test/450-checker-types/src/Main.java | 53 | ||||
| -rw-r--r-- | test/549-checker-types-merge/expected.txt | 0 | ||||
| -rw-r--r-- | test/549-checker-types-merge/info.txt | 1 | ||||
| -rw-r--r-- | test/549-checker-types-merge/src/Main.java | 130 |
7 files changed, 191 insertions, 36 deletions
diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc index 3b78264727..0d05c49fc5 100644 --- a/compiler/optimizing/reference_type_propagation.cc +++ b/compiler/optimizing/reference_type_propagation.cc @@ -614,23 +614,36 @@ ReferenceTypeInfo ReferenceTypePropagation::MergeTypes(const ReferenceTypeInfo& } 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 3590586228..05a9039ae9 100644 --- a/runtime/mirror/class.cc +++ b/runtime/mirror/class.cc @@ -802,6 +802,18 @@ mirror::Class* Class::GetDirectInterface(Thread* self, Handle<mirror::Class> kla } } +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 19a84f2e7f..0ab5b97d72 100644 --- a/runtime/mirror/class.h +++ b/runtime/mirror/class.h @@ -657,6 +657,10 @@ class MANAGED Class FINAL : public Object { 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 cd5e5a7786..ec63057b68 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 @@ public class Main { 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(); + private Main getNull() { + return null; } - /// CHECK-START: Super Main.getSuper(boolean, SubclassA, SubclassB) reference_type_propagation (after) + private int mainField = 0; + + /// CHECK-START: SuperInterface Main.getWiderType(boolean, Interface, OtherInterface) 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) { + private SuperInterface getWiderType(boolean cond, Interface a, OtherInterface b) { return cond ? a : b; } - private Main getNull() { - return null; - } - - private int mainField = 0; + /// 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, 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: void Main.testInlinerWidensReturnType(boolean, Interface, OtherInterface) inliner (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: <<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 0000000000..e69de29bb2 --- /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 0000000000..f174e20993 --- /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 0000000000..dc27f10427 --- /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) { + } +} |