1 // TEST_CONFIG MEM=mrc,gc
2 // TEST_CFLAGS -Wno-deprecated-declarations
5 #include <objc/runtime.h>
6 #include <objc/message.h>
7 #include <objc/objc-auto.h>
11 @interface Super { id isa; } @end
13 +(id)class { return self; }
16 +(id)ordinary { state = 1; return self; }
17 +(id)ordinary2 { testassert(0); }
18 +(id)retain { state = 2; return self; }
19 +(void)release { state = 3; }
20 +(id)autorelease { state = 4; return self; }
21 +(void)dealloc { state = 5; }
22 +(uintptr_t)retainCount { state = 6; return 6; }
25 @interface Sub : Super @end
26 @implementation Sub @end
28 @interface Sub2 : Super @end
29 @implementation Sub2 @end
31 @interface Empty { id isa; } @end
33 +(id)class { return self; }
35 +(id)forward:(SEL)sel :(marg_list)margs {
36 (void)sel; (void)margs;
42 @interface Empty (Unimplemented)
48 +(uintptr_t)retainCount;
54 sel##Method = class_getClassMethod(cls, @selector(sel)); \
55 testassert(sel##Method); \
56 testassert(@selector(sel) == method_getName(sel##Method)); \
57 sel = method_getImplementation(sel##Method); \
61 static IMP ordinary, ordinary2, retain, release, autorelease, dealloc, retainCount;
62 static Method ordinaryMethod, ordinary2Method, retainMethod, releaseMethod, autoreleaseMethod, deallocMethod, retainCountMethod;
70 if (objc_collectingEnabled()) {
71 // i386 GC: all ignored selectors are identical
72 testassert(@selector(retain) == @selector(release) &&
73 @selector(retain) == @selector(autorelease) &&
74 @selector(retain) == @selector(dealloc) &&
75 @selector(retain) == @selector(retainCount) );
80 // x86_64 GC or no GC: all ignored selectors are distinct
81 testassert(@selector(retain) != @selector(release) &&
82 @selector(retain) != @selector(autorelease) &&
83 @selector(retain) != @selector(dealloc) &&
84 @selector(retain) != @selector(retainCount) );
87 // no ignored selector matches a real selector
88 testassert(@selector(ordinary) != @selector(retain) &&
89 @selector(ordinary) != @selector(release) &&
90 @selector(ordinary) != @selector(autorelease) &&
91 @selector(ordinary) != @selector(dealloc) &&
92 @selector(ordinary) != @selector(retainCount) );
102 if (objc_collectingEnabled()) {
103 // GC: all ignored selector IMPs are identical
104 testassert(retain == release &&
105 retain == autorelease &&
107 retain == retainCount );
110 // no GC: all ignored selector IMPs are distinct
111 testassert(retain != release &&
112 retain != autorelease &&
114 retain != retainCount );
117 // no ignored selector IMP matches a real selector IMP
118 testassert(ordinary != retain &&
119 ordinary != release &&
120 ordinary != autorelease &&
121 ordinary != dealloc &&
122 ordinary != retainCount );
124 // Test calls via method_invoke
126 idVal = ((id(*)(id, Method))method_invoke)(cls, ordinaryMethod);
127 testassert(state == 1);
128 testassert(idVal == cls);
131 idVal = ((id(*)(id, Method))method_invoke)(cls, retainMethod);
132 testassert(state == (objc_collectingEnabled() ? 0 : 2));
133 testassert(idVal == cls);
135 (void) ((void(*)(id, Method))method_invoke)(cls, releaseMethod);
136 testassert(state == (objc_collectingEnabled() ? 0 : 3));
138 idVal = ((id(*)(id, Method))method_invoke)(cls, autoreleaseMethod);
139 testassert(state == (objc_collectingEnabled() ? 0 : 4));
140 testassert(idVal == cls);
142 (void) ((void(*)(id, Method))method_invoke)(cls, deallocMethod);
143 testassert(state == (objc_collectingEnabled() ? 0 : 5));
145 intVal = ((uintptr_t(*)(id, Method))method_invoke)(cls, retainCountMethod);
146 testassert(state == (objc_collectingEnabled() ? 0 : 6));
147 testassert(intVal == (objc_collectingEnabled() ? (uintptr_t)cls : 6));
150 // Test calls via compiled objc_msgSend
153 idVal = [cls ordinary];
154 testassert(state == 1);
155 testassert(idVal == cls);
158 idVal = [cls retain];
159 testassert(state == (objc_collectingEnabled() ? 0 : 2));
160 testassert(idVal == cls);
162 (void) [cls release];
163 testassert(state == (objc_collectingEnabled() ? 0 : 3));
165 idVal = [cls autorelease];
166 testassert(state == (objc_collectingEnabled() ? 0 : 4));
167 testassert(idVal == cls);
169 (void) [cls dealloc];
170 testassert(state == (objc_collectingEnabled() ? 0 : 5));
172 intVal = [cls retainCount];
173 testassert(state == (objc_collectingEnabled() ? 0 : 6));
174 testassert(intVal == (objc_collectingEnabled() ? (uintptr_t)cls : 6));
176 // Test calls via handwritten objc_msgSend
179 idVal = ((id(*)(id,SEL))objc_msgSend)(cls, @selector(ordinary));
180 testassert(state == 1);
181 testassert(idVal == cls);
184 idVal = ((id(*)(id,SEL))objc_msgSend)(cls, @selector(retain));
185 testassert(state == (objc_collectingEnabled() ? 0 : 2));
186 testassert(idVal == cls);
188 (void) ((void(*)(id,SEL))objc_msgSend)(cls, @selector(release));
189 testassert(state == (objc_collectingEnabled() ? 0 : 3));
191 idVal = ((id(*)(id,SEL))objc_msgSend)(cls, @selector(autorelease));
192 testassert(state == (objc_collectingEnabled() ? 0 : 4));
193 testassert(idVal == cls);
195 (void) ((void(*)(id,SEL))objc_msgSend)(cls, @selector(dealloc));
196 testassert(state == (objc_collectingEnabled() ? 0 : 5));
198 intVal = ((uintptr_t(*)(id,SEL))objc_msgSend)(cls, @selector(retainCount));
199 testassert(state == (objc_collectingEnabled() ? 0 : 6));
200 testassert(intVal == (objc_collectingEnabled() ? (uintptr_t)cls : 6));
209 testassert(sel_registerName("retain") == @selector(retain));
210 testassert(sel_getUid("retain") == @selector(retain));
211 #if defined(__i386__)
212 if (objc_collectingEnabled()) {
213 // only i386's GC currently remaps these
214 testassert(0 == strcmp(sel_getName(@selector(retain)), "<ignored selector>"));
218 testassert(0 == strcmp(sel_getName(@selector(retain)), "retain"));
221 testassert(sel_isMapped(@selector(retain)));
232 if (objc_collectingEnabled()) {
233 // rdar://6200570 Method manipulation shouldn't affect ignored methods.
239 method_setImplementation(retainMethod, (IMP)1);
240 method_setImplementation(releaseMethod, (IMP)1);
241 method_setImplementation(autoreleaseMethod, (IMP)1);
242 method_setImplementation(deallocMethod, (IMP)1);
243 method_setImplementation(retainCountMethod, (IMP)1);
246 testassert(ordinary2 != retainCount);
247 method_exchangeImplementations(retainMethod, autoreleaseMethod);
248 method_exchangeImplementations(deallocMethod, releaseMethod);
249 method_exchangeImplementations(retainCountMethod, ordinary2Method);
251 // ordinary2 exchanged with ignored method is now ignored too
252 testassert(ordinary2 == retainCount);
254 // replace == replace existing
255 class_replaceMethod(cls, @selector(retain), (IMP)1, "");
256 class_replaceMethod(cls, @selector(release), (IMP)1, "");
257 class_replaceMethod(cls, @selector(autorelease), (IMP)1, "");
258 class_replaceMethod(cls, @selector(dealloc), (IMP)1, "");
259 class_replaceMethod(cls, @selector(retainCount), (IMP)1, "");
266 // replace == add override
267 class_replaceMethod(cls, @selector(retain), (IMP)1, "");
268 class_replaceMethod(cls, @selector(release), (IMP)1, "");
269 class_replaceMethod(cls, @selector(autorelease), (IMP)1, "");
270 class_replaceMethod(cls, @selector(dealloc), (IMP)1, "");
271 class_replaceMethod(cls, @selector(retainCount), (IMP)1, "");
278 class_addMethod(cls, @selector(retain), (IMP)1, "");
279 class_addMethod(cls, @selector(release), (IMP)1, "");
280 class_addMethod(cls, @selector(autorelease), (IMP)1, "");
281 class_addMethod(cls, @selector(dealloc), (IMP)1, "");
282 class_addMethod(cls, @selector(retainCount), (IMP)1, "");
286 // Test calls via objc_msgSend - ignored selectors are ignored
287 // under GC even if the class provides no implementation for them
288 if (objc_collectingEnabled()) {
296 idVal = [Empty retain];
297 testassert(state == 0);
298 testassert(idVal == cls);
300 (void) [Empty release];
301 testassert(state == 0);
303 idVal = [Empty autorelease];
304 testassert(state == 0);
305 testassert(idVal == cls);
307 (void) [Empty dealloc];
308 testassert(state == 0);
310 intVal = [Empty retainCount];
311 testassert(state == 0);
312 testassert(intVal == (uintptr_t)cls);
314 idVal = [Empty ordinary];
315 testassert(state == 1);
316 testassert(idVal == nil);
320 idVal = ((id(*)(id,SEL))objc_msgSend)(cls, @selector(retain));
321 testassert(state == 0);
322 testassert(idVal == cls);
324 (void) ((void(*)(id,SEL))objc_msgSend)(cls, @selector(release));
325 testassert(state == 0);
327 idVal = ((id(*)(id,SEL))objc_msgSend)(cls, @selector(autorelease));
328 testassert(state == 0);
329 testassert(idVal == cls);
331 (void) ((void(*)(id,SEL))objc_msgSend)(cls, @selector(dealloc));
332 testassert(state == 0);
334 intVal = ((uintptr_t(*)(id,SEL))objc_msgSend)(cls, @selector(retainCount));
335 testassert(state == 0);
336 testassert(intVal == (uintptr_t)cls);
338 idVal = ((id(*)(id,SEL))objc_msgSend)(cls, @selector(ordinary));
339 testassert(state == 1);
340 testassert(idVal == nil);