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>
12 @interface Super { id isa; } @end
14 +(id)class { return self; }
17 +(id)ordinary { state = 1; return self; }
18 +(id)ordinary2 { testassert(0); }
19 +(id)retain { state = 2; return self; }
20 +(void)release { state = 3; }
21 +(id)autorelease { state = 4; return self; }
22 +(void)dealloc { state = 5; }
23 +(uintptr_t)retainCount { state = 6; return 6; }
26 @interface Sub : Super @end
27 @implementation Sub @end
29 @interface Sub2 : Super @end
30 @implementation Sub2 @end
33 @interface Empty { id isa; } @end
35 +(id)class { return self; }
39 void *forward_handler(id obj, SEL _cmd) {
40 testassert(obj == [Empty class]);
41 testassert(_cmd == @selector(ordinary));
46 @interface Empty (Unimplemented)
52 +(uintptr_t)retainCount;
58 sel##Method = class_getClassMethod(cls, @selector(sel)); \
59 testassert(sel##Method); \
60 testassert(@selector(sel) == method_getName(sel##Method)); \
61 sel = method_getImplementation(sel##Method); \
65 static IMP ordinary, ordinary2, retain, release, autorelease, dealloc, retainCount;
66 static Method ordinaryMethod, ordinary2Method, retainMethod, releaseMethod, autoreleaseMethod, deallocMethod, retainCountMethod;
74 if (objc_collectingEnabled()) {
75 // i386 GC: all ignored selectors are identical
76 testassert(@selector(retain) == @selector(release) &&
77 @selector(retain) == @selector(autorelease) &&
78 @selector(retain) == @selector(dealloc) &&
79 @selector(retain) == @selector(retainCount) );
84 // x86_64 GC or no GC: all ignored selectors are distinct
85 testassert(@selector(retain) != @selector(release) &&
86 @selector(retain) != @selector(autorelease) &&
87 @selector(retain) != @selector(dealloc) &&
88 @selector(retain) != @selector(retainCount) );
91 // no ignored selector matches a real selector
92 testassert(@selector(ordinary) != @selector(retain) &&
93 @selector(ordinary) != @selector(release) &&
94 @selector(ordinary) != @selector(autorelease) &&
95 @selector(ordinary) != @selector(dealloc) &&
96 @selector(ordinary) != @selector(retainCount) );
106 if (objc_collectingEnabled()) {
107 // GC: all ignored selector IMPs are identical
108 testassert(retain == release &&
109 retain == autorelease &&
111 retain == retainCount );
114 // no GC: all ignored selector IMPs are distinct
115 testassert(retain != release &&
116 retain != autorelease &&
118 retain != retainCount );
121 // no ignored selector IMP matches a real selector IMP
122 testassert(ordinary != retain &&
123 ordinary != release &&
124 ordinary != autorelease &&
125 ordinary != dealloc &&
126 ordinary != retainCount );
128 // Test calls via method_invoke
130 idVal = ((id(*)(id, Method))method_invoke)(cls, ordinaryMethod);
131 testassert(state == 1);
132 testassert(idVal == cls);
135 idVal = ((id(*)(id, Method))method_invoke)(cls, retainMethod);
136 testassert(state == (objc_collectingEnabled() ? 0 : 2));
137 testassert(idVal == cls);
139 (void) ((void(*)(id, Method))method_invoke)(cls, releaseMethod);
140 testassert(state == (objc_collectingEnabled() ? 0 : 3));
142 idVal = ((id(*)(id, Method))method_invoke)(cls, autoreleaseMethod);
143 testassert(state == (objc_collectingEnabled() ? 0 : 4));
144 testassert(idVal == cls);
146 (void) ((void(*)(id, Method))method_invoke)(cls, deallocMethod);
147 testassert(state == (objc_collectingEnabled() ? 0 : 5));
149 intVal = ((uintptr_t(*)(id, Method))method_invoke)(cls, retainCountMethod);
150 testassert(state == (objc_collectingEnabled() ? 0 : 6));
151 testassert(intVal == (objc_collectingEnabled() ? (uintptr_t)cls : 6));
154 // Test calls via compiled objc_msgSend
157 idVal = [cls ordinary];
158 testassert(state == 1);
159 testassert(idVal == cls);
162 idVal = [cls retain];
163 testassert(state == (objc_collectingEnabled() ? 0 : 2));
164 testassert(idVal == cls);
166 (void) [cls release];
167 testassert(state == (objc_collectingEnabled() ? 0 : 3));
169 idVal = [cls autorelease];
170 testassert(state == (objc_collectingEnabled() ? 0 : 4));
171 testassert(idVal == cls);
173 (void) [cls dealloc];
174 testassert(state == (objc_collectingEnabled() ? 0 : 5));
176 intVal = [cls retainCount];
177 testassert(state == (objc_collectingEnabled() ? 0 : 6));
178 testassert(intVal == (objc_collectingEnabled() ? (uintptr_t)cls : 6));
180 // Test calls via handwritten objc_msgSend
183 idVal = ((id(*)(id,SEL))objc_msgSend)(cls, @selector(ordinary));
184 testassert(state == 1);
185 testassert(idVal == cls);
188 idVal = ((id(*)(id,SEL))objc_msgSend)(cls, @selector(retain));
189 testassert(state == (objc_collectingEnabled() ? 0 : 2));
190 testassert(idVal == cls);
192 (void) ((void(*)(id,SEL))objc_msgSend)(cls, @selector(release));
193 testassert(state == (objc_collectingEnabled() ? 0 : 3));
195 idVal = ((id(*)(id,SEL))objc_msgSend)(cls, @selector(autorelease));
196 testassert(state == (objc_collectingEnabled() ? 0 : 4));
197 testassert(idVal == cls);
199 (void) ((void(*)(id,SEL))objc_msgSend)(cls, @selector(dealloc));
200 testassert(state == (objc_collectingEnabled() ? 0 : 5));
202 intVal = ((uintptr_t(*)(id,SEL))objc_msgSend)(cls, @selector(retainCount));
203 testassert(state == (objc_collectingEnabled() ? 0 : 6));
204 testassert(intVal == (objc_collectingEnabled() ? (uintptr_t)cls : 6));
211 objc_setForwardHandler((void*)&forward_handler, nil);
215 testassert(sel_registerName("retain") == @selector(retain));
216 testassert(sel_getUid("retain") == @selector(retain));
217 #if defined(__i386__)
218 if (objc_collectingEnabled()) {
219 // only i386's GC currently remaps these
220 testassert(0 == strcmp(sel_getName(@selector(retain)), "<ignored selector>"));
224 testassert(0 == strcmp(sel_getName(@selector(retain)), "retain"));
227 testassert(sel_isMapped(@selector(retain)));
238 if (objc_collectingEnabled()) {
239 // rdar://6200570 Method manipulation shouldn't affect ignored methods.
245 method_setImplementation(retainMethod, (IMP)1);
246 method_setImplementation(releaseMethod, (IMP)1);
247 method_setImplementation(autoreleaseMethod, (IMP)1);
248 method_setImplementation(deallocMethod, (IMP)1);
249 method_setImplementation(retainCountMethod, (IMP)1);
252 testassert(ordinary2 != retainCount);
253 method_exchangeImplementations(retainMethod, autoreleaseMethod);
254 method_exchangeImplementations(deallocMethod, releaseMethod);
255 method_exchangeImplementations(retainCountMethod, ordinary2Method);
257 // ordinary2 exchanged with ignored method is now ignored too
258 testassert(ordinary2 == retainCount);
260 // replace == replace existing
261 class_replaceMethod(cls, @selector(retain), (IMP)1, "");
262 class_replaceMethod(cls, @selector(release), (IMP)1, "");
263 class_replaceMethod(cls, @selector(autorelease), (IMP)1, "");
264 class_replaceMethod(cls, @selector(dealloc), (IMP)1, "");
265 class_replaceMethod(cls, @selector(retainCount), (IMP)1, "");
272 // replace == add override
273 class_replaceMethod(cls, @selector(retain), (IMP)1, "");
274 class_replaceMethod(cls, @selector(release), (IMP)1, "");
275 class_replaceMethod(cls, @selector(autorelease), (IMP)1, "");
276 class_replaceMethod(cls, @selector(dealloc), (IMP)1, "");
277 class_replaceMethod(cls, @selector(retainCount), (IMP)1, "");
284 class_addMethod(cls, @selector(retain), (IMP)1, "");
285 class_addMethod(cls, @selector(release), (IMP)1, "");
286 class_addMethod(cls, @selector(autorelease), (IMP)1, "");
287 class_addMethod(cls, @selector(dealloc), (IMP)1, "");
288 class_addMethod(cls, @selector(retainCount), (IMP)1, "");
292 // Test calls via objc_msgSend - ignored selectors are ignored
293 // under GC even if the class provides no implementation for them
294 if (objc_collectingEnabled()) {
302 idVal = [Empty retain];
303 testassert(state == 0);
304 testassert(idVal == cls);
306 (void) [Empty release];
307 testassert(state == 0);
309 idVal = [Empty autorelease];
310 testassert(state == 0);
311 testassert(idVal == cls);
313 (void) [Empty dealloc];
314 testassert(state == 0);
316 intVal = [Empty retainCount];
317 testassert(state == 0);
318 testassert(intVal == (uintptr_t)cls);
320 idVal = [Empty ordinary];
321 testassert(state == 1);
322 testassert(idVal == nil);
326 idVal = ((id(*)(id,SEL))objc_msgSend)(cls, @selector(retain));
327 testassert(state == 0);
328 testassert(idVal == cls);
330 (void) ((void(*)(id,SEL))objc_msgSend)(cls, @selector(release));
331 testassert(state == 0);
333 idVal = ((id(*)(id,SEL))objc_msgSend)(cls, @selector(autorelease));
334 testassert(state == 0);
335 testassert(idVal == cls);
337 (void) ((void(*)(id,SEL))objc_msgSend)(cls, @selector(dealloc));
338 testassert(state == 0);
340 intVal = ((uintptr_t(*)(id,SEL))objc_msgSend)(cls, @selector(retainCount));
341 testassert(state == 0);
342 testassert(intVal == (uintptr_t)cls);
344 idVal = ((id(*)(id,SEL))objc_msgSend)(cls, @selector(ordinary));
345 testassert(state == 1);
346 testassert(idVal == nil);