Skip to content

Commit 58c5c85

Browse files
committed
Merge pull request swiftlang#1159 from aschwaighofer/my-swift-2.2-branch
[Swift 2.2] Perform a dynamic method call if a class has objc ancestry in specula…
2 parents d16df7a + 7f43ad9 commit 58c5c85

File tree

2 files changed

+112
-0
lines changed

2 files changed

+112
-0
lines changed

lib/SILOptimizer/Transforms/SpeculativeDevirtualizer.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,12 @@ static bool isDefaultCaseKnown(ClassHierarchyAnalysis *CHA,
216216
if (CD->isFinal())
217217
return true;
218218

219+
// If the class has an @objc ancestry it can be dynamically subclassed and we
220+
// can't therefore statically know the default case.
221+
auto Ancestry = CD->checkObjCAncestry();
222+
if (Ancestry != ObjCClassKind::NonObjC)
223+
return false;
224+
219225
// Without an associated context we cannot perform any
220226
// access-based optimizations.
221227
if (!DC)
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
// RUN: %target-sil-opt -enable-sil-verify-all %s -specdevirt | FileCheck %s
2+
3+
sil_stage canonical
4+
5+
@objc class MyNSObject {}
6+
private class Base : MyNSObject {
7+
override init()
8+
@inline(never) func foo()
9+
}
10+
11+
private class Sub : Base {
12+
override init()
13+
@inline(never) override func foo()
14+
}
15+
16+
sil private [noinline] @_TBaseFooFun : $@convention(method) (@guaranteed Base) -> () {
17+
bb0(%0 : $Base):
18+
%1 = tuple()
19+
return %1 : $()
20+
}
21+
22+
sil private [noinline] @_TSubFooFun : $@convention(method) (@guaranteed Sub) -> () {
23+
bb0(%0 : $Sub):
24+
%1 = tuple()
25+
return %1 : $()
26+
}
27+
28+
sil_vtable Base {
29+
#Base.foo!1: _TBaseFooFun
30+
}
31+
32+
sil_vtable Sub {
33+
#Base.foo!1: _TSubFooFun
34+
}
35+
36+
sil @test_objc_ancestry : $@convention(thin) (@guaranteed Base) -> () {
37+
bb0(%0: $Base):
38+
%1 = class_method %0 : $Base, #Base.foo!1 : (Base) -> () -> () , $@convention(method) (@guaranteed Base) -> ()
39+
%2 = apply %1(%0) : $@convention(method) (@guaranteed Base) -> ()
40+
%3 = tuple()
41+
return %3 : $()
42+
}
43+
44+
// Make sure we leave the generic method call because an objc derived class can be extended at runtime.
45+
46+
// CHECK-LABEL: sil @test_objc_ancestry
47+
// CHECK: bb0
48+
// CHECK: [[METH:%.*]] = class_method %0 : $Base, #Base.foo!1 : (Base) -> () -> () , $@convention(method) (@guaranteed Base) -> ()
49+
// CHECK: checked_cast_br [exact] %0 : $Base to $Base, bb{{.*}}, bb[[CHECK2:[0-9]+]]
50+
// CHECK: bb[[CHECK2]]{{.*}}:
51+
// CHECK: checked_cast_br [exact] %0 : $Base to $Sub, bb{{.*}}, bb[[GENCALL:[0-9]+]]
52+
// CHECK: bb[[GENCALL]]{{.*}}:
53+
// CHECK: apply [[METH]]
54+
55+
struct MyValue {}
56+
57+
private class Generic<T> : MyNSObject {
58+
override init()
59+
}
60+
61+
private class Base2 : Generic<MyValue> {
62+
override init()
63+
@inline(never) func foo()
64+
}
65+
66+
private class Sub2 : Base2 {
67+
override init()
68+
@inline(never) override func foo()
69+
}
70+
71+
sil private [noinline] @_TBase2FooFun : $@convention(method) (@guaranteed Base2) -> () {
72+
bb0(%0 : $Base2):
73+
%1 = tuple()
74+
return %1 : $()
75+
}
76+
77+
sil private [noinline] @_TSub2FooFun : $@convention(method) (@guaranteed Sub2) -> () {
78+
bb0(%0 : $Sub2):
79+
%1 = tuple()
80+
return %1 : $()
81+
}
82+
83+
sil_vtable Base2 {
84+
#Base2.foo!1: _TBase2FooFun
85+
}
86+
87+
sil_vtable Sub2 {
88+
#Base2.foo!1: _TSub2FooFun
89+
}
90+
91+
sil @test_objc_ancestry2 : $@convention(thin) (@guaranteed Base2) -> () {
92+
bb0(%0: $Base2):
93+
%1 = class_method %0 : $Base2, #Base2.foo!1 : (Base2) -> () -> () , $@convention(method) (@guaranteed Base2) -> ()
94+
%2 = apply %1(%0) : $@convention(method) (@guaranteed Base2) -> ()
95+
%3 = tuple()
96+
return %3 : $()
97+
}
98+
99+
// CHECK-LABEL: sil @test_objc_ancestry2
100+
// CHECK: bb0
101+
// CHECK: [[METH:%.*]] = class_method %0 : $Base2, #Base2.foo!1 : (Base2) -> () -> () , $@convention(method) (@guaranteed Base2) -> ()
102+
// CHECK: checked_cast_br [exact] %0 : $Base2 to $Base2, bb{{.*}}, bb[[CHECK2:[0-9]+]]
103+
// CHECK: bb[[CHECK2]]{{.*}}:
104+
// CHECK: checked_cast_br [exact] %0 : $Base2 to $Sub2, bb{{.*}}, bb[[GENCALL:[0-9]+]]
105+
// CHECK: bb[[GENCALL]]{{.*}}:
106+
// CHECK: apply [[METH]]

0 commit comments

Comments
 (0)