]>
Commit | Line | Data |
---|---|---|
13ba007e A |
1 | // TEST_CONFIG MEM=mrc |
2 | // TEST_CFLAGS -Os | |
3 | ||
4 | #include "test.h" | |
5 | #include "testroot.i" | |
6 | ||
7 | #include <objc/objc-internal.h> | |
8 | #include <objc/objc-abi.h> | |
9 | #include <Foundation/Foundation.h> | |
10 | ||
11 | @interface TestObject : TestRoot @end | |
12 | @implementation TestObject @end | |
13 | ||
14 | ||
15 | // MAGIC and NOT_MAGIC each call two functions | |
16 | // with or without the magic instruction sequence, respectively. | |
17 | // | |
18 | // tmp = first(obj); | |
19 | // magic, or not; | |
20 | // tmp = second(tmp); | |
21 | ||
22 | #if __arm__ | |
23 | ||
24 | #define NOT_MAGIC(first, second) \ | |
25 | tmp = first(obj); \ | |
26 | asm volatile("mov r8, r8"); \ | |
27 | tmp = second(tmp); | |
28 | ||
29 | #define MAGIC(first, second) \ | |
30 | tmp = first(obj); \ | |
31 | asm volatile("mov r7, r7"); \ | |
32 | tmp = second(tmp); | |
33 | ||
34 | // arm | |
35 | #elif __arm64__ | |
36 | ||
37 | #define NOT_MAGIC(first, second) \ | |
38 | tmp = first(obj); \ | |
39 | asm volatile("mov x28, x28"); \ | |
40 | tmp = second(tmp); | |
41 | ||
42 | #define MAGIC(first, second) \ | |
43 | tmp = first(obj); \ | |
44 | asm volatile("mov x29, x29"); \ | |
45 | tmp = second(tmp); | |
46 | ||
47 | // arm64 | |
48 | #elif __x86_64__ | |
49 | ||
50 | #define NOT_MAGIC(first, second) \ | |
51 | tmp = first(obj); \ | |
52 | asm volatile("nop"); \ | |
53 | tmp = second(tmp); | |
54 | ||
55 | #define MAGIC(first, second) \ | |
56 | tmp = first(obj); \ | |
57 | tmp = second(tmp); | |
58 | ||
59 | // x86_64 | |
60 | #elif __i386__ | |
61 | ||
62 | #define NOT_MAGIC(first, second) \ | |
63 | tmp = first(obj); \ | |
64 | tmp = second(tmp); | |
65 | ||
66 | #define MAGIC(first, second) \ | |
67 | asm volatile("\n subl $16, %%esp" \ | |
68 | "\n movl %[obj], (%%esp)" \ | |
69 | "\n call _" #first \ | |
70 | "\n" \ | |
71 | "\n movl %%ebp, %%ebp" \ | |
72 | "\n" \ | |
73 | "\n movl %%eax, (%%esp)" \ | |
74 | "\n call _" #second \ | |
75 | "\n movl %%eax, %[tmp]" \ | |
76 | "\n addl $16, %%esp" \ | |
77 | : [tmp] "=r" (tmp) \ | |
78 | : [obj] "r" (obj) \ | |
79 | : "eax", "edx", "ecx", "cc", "memory") | |
80 | ||
81 | // i386 | |
82 | #else | |
83 | ||
84 | #error unknown architecture | |
85 | ||
86 | #endif | |
87 | ||
88 | ||
89 | int | |
90 | main() | |
91 | { | |
92 | TestObject *tmp, *obj; | |
93 | ||
94 | #ifdef __x86_64__ | |
95 | // need to get DYLD to resolve the stubs on x86 | |
96 | PUSH_POOL { | |
97 | TestObject *warm_up = [[TestObject alloc] init]; | |
98 | testassert(warm_up); | |
99 | warm_up = objc_retainAutoreleasedReturnValue(warm_up); | |
100 | warm_up = objc_unsafeClaimAutoreleasedReturnValue(warm_up); | |
101 | [warm_up release]; | |
102 | warm_up = nil; | |
103 | } POP_POOL; | |
104 | #endif | |
105 | ||
106 | testprintf(" Successful +1 -> +1 handshake\n"); | |
107 | ||
108 | PUSH_POOL { | |
109 | obj = [[TestObject alloc] init]; | |
110 | testassert(obj); | |
111 | ||
112 | TestRootRetain = 0; | |
113 | TestRootRelease = 0; | |
114 | TestRootAutorelease = 0; | |
115 | TestRootDealloc = 0; | |
116 | ||
117 | MAGIC(objc_autoreleaseReturnValue, | |
118 | objc_retainAutoreleasedReturnValue); | |
119 | ||
120 | testassert(TestRootDealloc == 0); | |
121 | testassert(TestRootRetain == 0); | |
122 | testassert(TestRootRelease == 0); | |
123 | testassert(TestRootAutorelease == 0); | |
124 | ||
125 | [tmp release]; | |
126 | testassert(TestRootDealloc == 1); | |
127 | testassert(TestRootRetain == 0); | |
128 | testassert(TestRootRelease == 1); | |
129 | testassert(TestRootAutorelease == 0); | |
130 | ||
131 | } POP_POOL; | |
132 | ||
133 | testprintf("Unsuccessful +1 -> +1 handshake\n"); | |
134 | ||
135 | PUSH_POOL { | |
136 | obj = [[TestObject alloc] init]; | |
137 | testassert(obj); | |
138 | ||
139 | TestRootRetain = 0; | |
140 | TestRootRelease = 0; | |
141 | TestRootAutorelease = 0; | |
142 | TestRootDealloc = 0; | |
143 | ||
144 | NOT_MAGIC(objc_autoreleaseReturnValue, | |
145 | objc_retainAutoreleasedReturnValue); | |
146 | ||
147 | testassert(TestRootDealloc == 0); | |
148 | testassert(TestRootRetain == 1); | |
149 | testassert(TestRootRelease == 0); | |
150 | testassert(TestRootAutorelease == 1); | |
151 | ||
152 | [tmp release]; | |
153 | testassert(TestRootDealloc == 0); | |
154 | testassert(TestRootRetain == 1); | |
155 | testassert(TestRootRelease == 1); | |
156 | testassert(TestRootAutorelease == 1); | |
157 | ||
158 | } POP_POOL; | |
159 | testassert(TestRootDealloc == 1); | |
160 | testassert(TestRootRetain == 1); | |
161 | testassert(TestRootRelease == 2); | |
162 | testassert(TestRootAutorelease == 1); | |
163 | ||
164 | ||
165 | testprintf(" Successful +0 -> +1 handshake\n"); | |
166 | ||
167 | PUSH_POOL { | |
168 | obj = [[TestObject alloc] init]; | |
169 | testassert(obj); | |
170 | ||
171 | TestRootRetain = 0; | |
172 | TestRootRelease = 0; | |
173 | TestRootAutorelease = 0; | |
174 | TestRootDealloc = 0; | |
175 | ||
176 | MAGIC(objc_retainAutoreleaseReturnValue, | |
177 | objc_retainAutoreleasedReturnValue); | |
178 | ||
179 | testassert(TestRootDealloc == 0); | |
180 | testassert(TestRootRetain == 1); | |
181 | testassert(TestRootRelease == 0); | |
182 | testassert(TestRootAutorelease == 0); | |
183 | ||
184 | [tmp release]; | |
185 | testassert(TestRootDealloc == 0); | |
186 | testassert(TestRootRetain == 1); | |
187 | testassert(TestRootRelease == 1); | |
188 | testassert(TestRootAutorelease == 0); | |
189 | ||
190 | [tmp release]; | |
191 | testassert(TestRootDealloc == 1); | |
192 | testassert(TestRootRetain == 1); | |
193 | testassert(TestRootRelease == 2); | |
194 | testassert(TestRootAutorelease == 0); | |
195 | ||
196 | } POP_POOL; | |
197 | ||
198 | testprintf("Unsuccessful +0 -> +1 handshake\n"); | |
199 | ||
200 | PUSH_POOL { | |
201 | obj = [[TestObject alloc] init]; | |
202 | testassert(obj); | |
203 | ||
204 | TestRootRetain = 0; | |
205 | TestRootRelease = 0; | |
206 | TestRootAutorelease = 0; | |
207 | TestRootDealloc = 0; | |
208 | ||
209 | NOT_MAGIC(objc_retainAutoreleaseReturnValue, | |
210 | objc_retainAutoreleasedReturnValue); | |
211 | ||
212 | testassert(TestRootDealloc == 0); | |
213 | testassert(TestRootRetain == 2); | |
214 | testassert(TestRootRelease == 0); | |
215 | testassert(TestRootAutorelease == 1); | |
216 | ||
217 | [tmp release]; | |
218 | testassert(TestRootDealloc == 0); | |
219 | testassert(TestRootRetain == 2); | |
220 | testassert(TestRootRelease == 1); | |
221 | testassert(TestRootAutorelease == 1); | |
222 | ||
223 | [tmp release]; | |
224 | testassert(TestRootDealloc == 0); | |
225 | testassert(TestRootRetain == 2); | |
226 | testassert(TestRootRelease == 2); | |
227 | testassert(TestRootAutorelease == 1); | |
228 | ||
229 | } POP_POOL; | |
230 | testassert(TestRootDealloc == 1); | |
231 | testassert(TestRootRetain == 2); | |
232 | testassert(TestRootRelease == 3); | |
233 | testassert(TestRootAutorelease == 1); | |
234 | ||
235 | ||
236 | testprintf(" Successful +1 -> +0 handshake\n"); | |
237 | ||
238 | PUSH_POOL { | |
239 | obj = [[[TestObject alloc] init] retain]; | |
240 | testassert(obj); | |
241 | ||
242 | TestRootRetain = 0; | |
243 | TestRootRelease = 0; | |
244 | TestRootAutorelease = 0; | |
245 | TestRootDealloc = 0; | |
246 | ||
247 | MAGIC(objc_autoreleaseReturnValue, | |
248 | objc_unsafeClaimAutoreleasedReturnValue); | |
249 | ||
250 | testassert(TestRootDealloc == 0); | |
251 | testassert(TestRootRetain == 0); | |
252 | testassert(TestRootRelease == 1); | |
253 | testassert(TestRootAutorelease == 0); | |
254 | ||
255 | [tmp release]; | |
256 | testassert(TestRootDealloc == 1); | |
257 | testassert(TestRootRetain == 0); | |
258 | testassert(TestRootRelease == 2); | |
259 | testassert(TestRootAutorelease == 0); | |
260 | ||
261 | } POP_POOL; | |
262 | ||
263 | testprintf("Unsuccessful +1 -> +0 handshake\n"); | |
264 | ||
265 | PUSH_POOL { | |
266 | obj = [[[TestObject alloc] init] retain]; | |
267 | testassert(obj); | |
268 | ||
269 | TestRootRetain = 0; | |
270 | TestRootRelease = 0; | |
271 | TestRootAutorelease = 0; | |
272 | TestRootDealloc = 0; | |
273 | ||
274 | NOT_MAGIC(objc_autoreleaseReturnValue, | |
275 | objc_unsafeClaimAutoreleasedReturnValue); | |
276 | ||
277 | testassert(TestRootDealloc == 0); | |
278 | testassert(TestRootRetain == 0); | |
279 | testassert(TestRootRelease == 0); | |
280 | testassert(TestRootAutorelease == 1); | |
281 | ||
282 | [tmp release]; | |
283 | testassert(TestRootDealloc == 0); | |
284 | testassert(TestRootRetain == 0); | |
285 | testassert(TestRootRelease == 1); | |
286 | testassert(TestRootAutorelease == 1); | |
287 | ||
288 | } POP_POOL; | |
289 | testassert(TestRootDealloc == 1); | |
290 | testassert(TestRootRetain == 0); | |
291 | testassert(TestRootRelease == 2); | |
292 | testassert(TestRootAutorelease == 1); | |
293 | ||
294 | ||
295 | testprintf(" Successful +0 -> +0 handshake\n"); | |
296 | ||
297 | PUSH_POOL { | |
298 | obj = [[TestObject alloc] init]; | |
299 | testassert(obj); | |
300 | ||
301 | TestRootRetain = 0; | |
302 | TestRootRelease = 0; | |
303 | TestRootAutorelease = 0; | |
304 | TestRootDealloc = 0; | |
305 | ||
306 | MAGIC(objc_retainAutoreleaseReturnValue, | |
307 | objc_unsafeClaimAutoreleasedReturnValue); | |
308 | ||
309 | testassert(TestRootDealloc == 0); | |
310 | testassert(TestRootRetain == 0); | |
311 | testassert(TestRootRelease == 0); | |
312 | testassert(TestRootAutorelease == 0); | |
313 | ||
314 | [tmp release]; | |
315 | testassert(TestRootDealloc == 1); | |
316 | testassert(TestRootRetain == 0); | |
317 | testassert(TestRootRelease == 1); | |
318 | testassert(TestRootAutorelease == 0); | |
319 | ||
320 | } POP_POOL; | |
321 | ||
322 | testprintf("Unsuccessful +0 -> +0 handshake\n"); | |
323 | ||
324 | PUSH_POOL { | |
325 | obj = [[TestObject alloc] init]; | |
326 | testassert(obj); | |
327 | ||
328 | TestRootRetain = 0; | |
329 | TestRootRelease = 0; | |
330 | TestRootAutorelease = 0; | |
331 | TestRootDealloc = 0; | |
332 | ||
333 | NOT_MAGIC(objc_retainAutoreleaseReturnValue, | |
334 | objc_unsafeClaimAutoreleasedReturnValue); | |
335 | ||
336 | testassert(TestRootDealloc == 0); | |
337 | testassert(TestRootRetain == 1); | |
338 | testassert(TestRootRelease == 0); | |
339 | testassert(TestRootAutorelease == 1); | |
340 | ||
341 | [tmp release]; | |
342 | testassert(TestRootDealloc == 0); | |
343 | testassert(TestRootRetain == 1); | |
344 | testassert(TestRootRelease == 1); | |
345 | testassert(TestRootAutorelease == 1); | |
346 | ||
347 | } POP_POOL; | |
348 | testassert(TestRootDealloc == 1); | |
349 | testassert(TestRootRetain == 1); | |
350 | testassert(TestRootRelease == 2); | |
351 | testassert(TestRootAutorelease == 1); | |
352 | ||
353 | succeed(__FILE__); | |
354 | ||
355 | return 0; | |
356 | } | |
357 |