forked from swiftlang/swift
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathobjc_ownership_conventions.swift
215 lines (198 loc) · 11.4 KB
/
objc_ownership_conventions.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
// RUN: %target-swift-frontend -sdk %S/Inputs -I %S/Inputs -enable-source-import %s -emit-silgen | %FileCheck %s
// REQUIRES: objc_interop
import gizmo
// CHECK-LABEL: sil hidden @_TF26objc_ownership_conventions5test3FT_CSo8NSObject
func test3() -> NSObject {
// initializer returns at +1
return Gizmo()
// CHECK: [[CTOR:%[0-9]+]] = function_ref @_TFCSo5GizmoC{{.*}} : $@convention(method) (@thick Gizmo.Type) -> @owned Optional<Gizmo>
// CHECK-NEXT: [[GIZMO_META:%[0-9]+]] = metatype $@thick Gizmo.Type
// CHECK-NEXT: [[GIZMO:%[0-9]+]] = apply [[CTOR]]([[GIZMO_META]]) : $@convention(method) (@thick Gizmo.Type) -> @owned Optional<Gizmo>
// CHECK: [[GIZMO_NS:%[0-9]+]] = upcast [[GIZMO:%[0-9]+]] : $Gizmo to $NSObject
// CHECK: return [[GIZMO_NS]] : $NSObject
// CHECK-LABEL: sil shared @_TFCSo5GizmoC{{.*}} : $@convention(method) (@thick Gizmo.Type) -> @owned Optional<Gizmo>
// alloc is implicitly ns_returns_retained
// init is implicitly ns_consumes_self and ns_returns_retained
// CHECK: bb0([[GIZMO_META:%[0-9]+]] : $@thick Gizmo.Type):
// CHECK-NEXT: [[GIZMO_META_OBJC:%[0-9]+]] = thick_to_objc_metatype [[GIZMO_META]] : $@thick Gizmo.Type to $@objc_metatype Gizmo.Type
// CHECK-NEXT: [[GIZMO:%[0-9]+]] = alloc_ref_dynamic [objc] [[GIZMO_META_OBJC]] : $@objc_metatype Gizmo.Type, $Gizmo
// CHECK-NEXT: // function_ref
// CHECK-NEXT: [[INIT_CTOR:%[0-9]+]] = function_ref @_TTOFCSo5Gizmoc{{.*}}
// CHECK-NEXT: [[RESULT:%[0-9]+]] = apply [[INIT_CTOR]]([[GIZMO]]) : $@convention(method) (@owned Gizmo) -> @owned Optional<Gizmo>
// CHECK-NEXT: return [[RESULT]] : $Optional<Gizmo>
}
// Normal message send with argument, no transfers.
// CHECK-LABEL: sil hidden @_TF26objc_ownership_conventions5test5
func test5(_ g: Gizmo) {
var g = g
Gizmo.inspect(g)
// CHECK: bb0([[ARG:%.*]] : $Gizmo):
// CHECK: [[GIZMO_BOX:%.*]] = alloc_box $<τ_0_0> { var τ_0_0 } <Gizmo>
// CHECK: [[GIZMO_BOX_PB:%.*]] = project_box [[GIZMO_BOX]]
// CHECK: [[ARG_COPY:%.*]] = copy_value [[ARG]]
// CHECK: store [[ARG_COPY]] to [init] [[GIZMO_BOX_PB]]
// CHECK: [[CLASS:%.*]] = metatype $@thick Gizmo.Type
// CHECK: [[METHOD:%.*]] = class_method [volatile] [[CLASS]] : {{.*}}, #Gizmo.inspect!1.foreign
// CHECK: [[OBJC_CLASS:%[0-9]+]] = thick_to_objc_metatype [[CLASS]] : $@thick Gizmo.Type to $@objc_metatype Gizmo.Type
// CHECK: [[V:%.*]] = load [copy] [[GIZMO_BOX_PB]]
// CHECK: [[G:%.*]] = enum $Optional<Gizmo>, #Optional.some!enumelt.1, [[V]]
// CHECK: apply [[METHOD]]([[G]], [[OBJC_CLASS]])
// CHECK: destroy_value [[G]]
// CHECK: destroy_value [[GIZMO_BOX]]
// CHECK: destroy_value [[ARG]]
}
// CHECK: } // end sil function '_TF26objc_ownership_conventions5test5{{.*}}'
// The argument to consume is __attribute__((ns_consumed)).
// CHECK-LABEL: sil hidden @_TF26objc_ownership_conventions5test6
func test6(_ g: Gizmo) {
var g = g
Gizmo.consume(g)
// CHECK: bb0([[ARG:%.*]] : $Gizmo):
// CHECK: [[GIZMO_BOX:%.*]] = alloc_box $<τ_0_0> { var τ_0_0 } <Gizmo>
// CHECK: [[GIZMO_BOX_PB:%.*]] = project_box [[GIZMO_BOX]]
// CHECK: [[ARG_COPY:%.*]] = copy_value [[ARG]]
// CHECK: store [[ARG_COPY]] to [init] [[GIZMO_BOX_PB]]
// CHECK: [[CLASS:%.*]] = metatype $@thick Gizmo.Type
// CHECK: [[METHOD:%.*]] = class_method [volatile] [[CLASS]] : {{.*}}, #Gizmo.consume!1.foreign
// CHECK: [[OBJC_CLASS:%.*]] = thick_to_objc_metatype [[CLASS]] : $@thick Gizmo.Type to $@objc_metatype Gizmo.Type
// CHECK: [[V:%.*]] = load [copy] [[GIZMO_BOX_PB]]
// CHECK: [[G:%.*]] = enum $Optional<Gizmo>, #Optional.some!enumelt.1, [[V]]
// CHECK: apply [[METHOD]]([[G]], [[OBJC_CLASS]])
// CHECK-NOT: destroy_value [[G]]
// CHECK: destroy_value [[GIZMO_BOX]]
// CHECK-NOT: destroy_value [[G]]
// CHECK: destroy_value [[ARG]]
// CHECK-NOT: destroy_value [[G]]
}
// CHECK: } // end sil function '_TF26objc_ownership_conventions5test6{{.*}}'
// fork is __attribute__((ns_consumes_self)).
// CHECK-LABEL: sil hidden @_TF26objc_ownership_conventions5test7
func test7(_ g: Gizmo) {
var g = g
g.fork()
// CHECK: bb0([[ARG:%.*]] : $Gizmo):
// CHECK: [[GIZMO_BOX:%.*]] = alloc_box $<τ_0_0> { var τ_0_0 } <Gizmo>
// CHECK: [[GIZMO_BOX_PB:%.*]] = project_box [[GIZMO_BOX]]
// CHECK: [[ARG_COPY:%.*]] = copy_value [[ARG]]
// CHECK: store [[ARG_COPY]] to [init] [[GIZMO_BOX_PB]]
// CHECK: [[G:%.*]] = load [copy] [[GIZMO_BOX_PB]]
// CHECK: [[METHOD:%.*]] = class_method [volatile] [[G]] : {{.*}}, #Gizmo.fork!1.foreign
// CHECK: apply [[METHOD]]([[G]])
// CHECK-NOT: destroy_value [[G]]
// CHECK: destroy_value [[GIZMO_BOX]]
// CHECK-NOT: destroy_value [[G]]
// CHECK: destroy_value [[ARG]]
// CHECK-NOT: destroy_value [[G]]
}
// CHECK: } // end sil function '_TF26objc_ownership_conventions5test7{{.*}}'
// clone is __attribute__((ns_returns_retained)).
// CHECK-LABEL: sil hidden @_TF26objc_ownership_conventions5test8
func test8(_ g: Gizmo) -> Gizmo {
return g.clone()
// CHECK: bb0([[G:%.*]] : $Gizmo):
// CHECK-NOT: copy_value
// CHECK: [[METHOD:%.*]] = class_method [volatile] [[G]] : {{.*}}, #Gizmo.clone!1.foreign
// CHECK-NOT: copy_value [[RESULT]]
// CHECK: [[RESULT:%.*]] = unchecked_enum_data
// CHECK-NOT: copy_value [[RESULT]]
// CHECK: return [[RESULT]]
}
// duplicate returns an autoreleased object at +0.
// CHECK-LABEL: sil hidden @_TF26objc_ownership_conventions5test9
func test9(_ g: Gizmo) -> Gizmo {
return g.duplicate()
// CHECK: bb0([[G:%.*]] : $Gizmo):
// CHECK-NOT: copy_value [[G:%0]]
// CHECK: [[METHOD:%.*]] = class_method [volatile] [[G]] : {{.*}}, #Gizmo.duplicate!1.foreign
// CHECK-NEXT: [[RESULT:%.*]] = apply [[METHOD]]([[G]])
// CHECK-NOT: copy_value [[RESULT]]
// CHECK: [[RESULT:%.*]] = unchecked_enum_data
// CHECK-NOT: copy_value [[RESULT]]
// CHECK: return [[RESULT]]
}
// CHECK-LABEL: sil hidden @_TF26objc_ownership_conventions6test10
func test10(_ g: Gizmo) -> AnyClass {
// CHECK: bb0([[G:%[0-9]+]] : $Gizmo):
// CHECK: [[G_COPY:%.*]] = copy_value [[G]]
// CHECK-NEXT: [[NS_G_COPY:%[0-9]+]] = upcast [[G_COPY]] : $Gizmo to $NSObject
// CHECK-NEXT: [[GETTER:%[0-9]+]] = class_method [volatile] [[NS_G_COPY]] : $NSObject, #NSObject.classProp!getter.1.foreign : (NSObject) -> () -> AnyObject.Type! , $@convention(objc_method) (NSObject) -> Optional<@objc_metatype AnyObject.Type>
// CHECK-NEXT: [[OPT_OBJC:%.*]] = apply [[GETTER]]([[NS_G_COPY]]) : $@convention(objc_method) (NSObject) -> Optional<@objc_metatype AnyObject.Type>
// CHECK: select_enum [[OPT_OBJC]]
// CHECK: [[OBJC:%.*]] = unchecked_enum_data [[OPT_OBJC]]
// CHECK-NEXT: [[THICK:%.*]] = objc_to_thick_metatype [[OBJC]]
// CHECK: [[T0:%.*]] = enum $Optional<@thick AnyObject.Type>, #Optional.some!enumelt.1, [[THICK]]
// CHECK: [[RES:%.*]] = unchecked_enum_data
// CHECK: destroy_value [[G_COPY]] : $Gizmo
// CHECK: destroy_value [[G]] : $Gizmo
// CHECK-NEXT: return [[RES]] : $@thick AnyObject.Type
return g.classProp
}
// CHECK-LABEL: sil hidden @_TF26objc_ownership_conventions6test11
func test11(_ g: Gizmo) -> AnyClass {
// CHECK: bb0([[G:%[0-9]+]] : $Gizmo):
// CHECK: [[G_COPY:%.*]] = copy_value [[G]]
// CHECK: [[NS_G_COPY:%[0-9]+]] = upcast [[G_COPY:%[0-9]+]] : $Gizmo to $NSObject
// CHECK: [[GETTER:%[0-9]+]] = class_method [volatile] [[NS_G_COPY]] : $NSObject, #NSObject.qualifiedClassProp!getter.1.foreign : (NSObject) -> () -> NSAnsing.Type! , $@convention(objc_method) (NSObject) -> Optional<@objc_metatype NSAnsing.Type>
// CHECK-NEXT: [[OPT_OBJC:%.*]] = apply [[GETTER]]([[NS_G_COPY]]) : $@convention(objc_method) (NSObject) -> Optional<@objc_metatype NSAnsing.Type>
// CHECK: select_enum [[OPT_OBJC]]
// CHECK: [[OBJC:%.*]] = unchecked_enum_data [[OPT_OBJC]]
// CHECK-NEXT: [[THICK:%.*]] = objc_to_thick_metatype [[OBJC]]
// CHECK: [[T0:%.*]] = enum $Optional<@thick NSAnsing.Type>, #Optional.some!enumelt.1, [[THICK]]
// CHECK: [[RES:%.*]] = unchecked_enum_data
// CHECK: [[OPENED:%.*]] = open_existential_metatype [[RES]]
// CHECK: [[RES_ANY:%.*]] = init_existential_metatype [[OPENED]]
// CHECK: destroy_value [[G_COPY]] : $Gizmo
// CHECK: destroy_value [[G]] : $Gizmo
// CHECK-NEXT: return [[RES_ANY]] : $@thick AnyObject.Type
return g.qualifiedClassProp
}
// ObjC blocks should have cdecl calling convention and follow C/ObjC
// ownership conventions, where the callee, arguments, and return are all +0.
// CHECK-LABEL: sil hidden @_TF26objc_ownership_conventions10applyBlock
func applyBlock(_ f: @convention(block) (Gizmo) -> Gizmo, x: Gizmo) -> Gizmo {
// CHECK: bb0([[BLOCK:%.*]] : $@convention(block) (Gizmo) -> @autoreleased Gizmo, [[ARG:%.*]] : $Gizmo):
// CHECK: [[BLOCK_COPY:%.*]] = copy_block [[BLOCK]]
// CHECK: [[BLOCK_COPY_COPY:%.*]] = copy_value [[BLOCK_COPY]]
// CHECK: [[RESULT:%.*]] = apply [[BLOCK_COPY_COPY]]([[ARG]])
// CHECK: destroy_value [[BLOCK_COPY_COPY]]
// CHECK: destroy_value [[ARG]]
// CHECK: destroy_value [[BLOCK_COPY]]
// CHECK: destroy_value [[BLOCK]]
// CHECK: return [[RESULT]]
return f(x)
}
// CHECK-LABEL: sil hidden @_TF26objc_ownership_conventions15maybeApplyBlock
func maybeApplyBlock(_ f: (@convention(block) (Gizmo) -> Gizmo)?, x: Gizmo) -> Gizmo? {
// CHECK: bb0([[BLOCK:%.*]] : $Optional<@convention(block) (Gizmo) -> @autoreleased Gizmo>, [[ARG:%.*]] : $Gizmo):
// CHECK: [[BLOCK_COPY:%.*]] = copy_block [[BLOCK]]
return f?(x)
}
func useInnerPointer(_ p: UnsafeMutableRawPointer) {}
// Handle inner-pointer methods by autoreleasing self after the call.
// CHECK-LABEL: sil hidden @_TF26objc_ownership_conventions18innerPointerMethodFCSo5GizmoT_ : $@convention(thin) (@owned Gizmo) -> () {
// CHECK: bb0([[ARG:%.*]] : $Gizmo):
// CHECK: [[USE:%.*]] = function_ref @_TF26objc_ownership_conventions15useInnerPointer
// CHECK: [[METHOD:%.*]] = class_method [volatile] [[ARG]] : $Gizmo, #Gizmo.getBytes!1.foreign : (Gizmo) -> () -> UnsafeMutableRawPointer , $@convention(objc_method) (Gizmo) -> @unowned_inner_pointer UnsafeMutableRawPointer
// CHECK: [[ARG_COPY:%.*]] = copy_value [[ARG]]
// SEMANTIC ARC TODO: The apply below /should/ be on ARG_COPY
// CHECK: [[PTR:%.*]] = apply [[METHOD]]([[ARG]])
// CHECK: autorelease_value [[ARG_COPY]]
// CHECK: apply [[USE]]([[PTR]])
// CHECK: destroy_value [[ARG]]
func innerPointerMethod(_ g: Gizmo) {
useInnerPointer(g.getBytes())
}
// CHECK-LABEL: sil hidden @_TF26objc_ownership_conventions20innerPointerPropertyFCSo5GizmoT_ : $@convention(thin) (@owned Gizmo) -> () {
// CHECK: bb0([[ARG:%.*]] : $Gizmo):
// CHECK: [[USE:%.*]] = function_ref @_TF26objc_ownership_conventions15useInnerPointer
// CHECK: [[METHOD:%.*]] = class_method [volatile] [[ARG]] : $Gizmo, #Gizmo.innerProperty!getter.1.foreign : (Gizmo) -> () -> UnsafeMutableRawPointer , $@convention(objc_method) (Gizmo) -> @unowned_inner_pointer UnsafeMutableRawPointer
// CHECK: [[ARG_COPY:%.*]] = copy_value [[ARG]]
// SEMANTIC ARC TODO: The apply below should be on ARG_COPY
// CHECK: [[PTR:%.*]] = apply [[METHOD]]([[ARG]])
// CHECK: autorelease_value [[ARG_COPY]]
// CHECK: apply [[USE]]([[PTR]])
// CHECK: destroy_value [[ARG]]
// CHECK: } // end sil function '_TF26objc_ownership_conventions20innerPointerPropertyFCSo5GizmoT_'
func innerPointerProperty(_ g: Gizmo) {
useInnerPointer(g.innerProperty)
}