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; }
37 +(id)forward:(SEL)sel :(marg_list)margs {
38 (void)sel; (void)margs;
44 @interface Empty (Unimplemented)
50 +(uintptr_t)retainCount;
56 sel##Method = class_getClassMethod(cls, @selector(sel)); \
57 testassert(sel##Method); \
58 testassert(@selector(sel) == method_getName(sel##Method)); \
59 sel = method_getImplementation(sel##Method); \
63 static IMP ordinary, ordinary2, retain, release, autorelease, dealloc, retainCount;
64 static Method ordinaryMethod, ordinary2Method, retainMethod, releaseMethod, autoreleaseMethod, deallocMethod, retainCountMethod;
72 if (objc_collectingEnabled()) {
73 // i386 GC: all ignored selectors are identical
74 testassert(@selector(retain) == @selector(release) &&
75 @selector(retain) == @selector(autorelease) &&
76 @selector(retain) == @selector(dealloc) &&
77 @selector(retain) == @selector(retainCount) );
82 // x86_64 GC or no GC: all ignored selectors are distinct
83 testassert(@selector(retain) != @selector(release) &&
84 @selector(retain) != @selector(autorelease) &&
85 @selector(retain) != @selector(dealloc) &&
86 @selector(retain) != @selector(retainCount) );
89 // no ignored selector matches a real selector
90 testassert(@selector(ordinary) != @selector(retain) &&
91 @selector(ordinary) != @selector(release) &&
92 @selector(ordinary) != @selector(autorelease) &&
93 @selector(ordinary) != @selector(dealloc) &&
94 @selector(ordinary) != @selector(retainCount) );
104 if (objc_collectingEnabled()) {
105 // GC: all ignored selector IMPs are identical
106 testassert(retain == release &&
107 retain == autorelease &&
109 retain == retainCount );
112 // no GC: all ignored selector IMPs are distinct
113 testassert(retain != release &&
114 retain != autorelease &&
116 retain != retainCount );
119 // no ignored selector IMP matches a real selector IMP
120 testassert(ordinary != retain &&
121 ordinary != release &&
122 ordinary != autorelease &&
123 ordinary != dealloc &&
124 ordinary != retainCount );
126 // Test calls via method_invoke
128 idVal = ((id(*)(id, Method))method_invoke)(cls, ordinaryMethod);
129 testassert(state == 1);
130 testassert(idVal == cls);
133 idVal = ((id(*)(id, Method))method_invoke)(cls, retainMethod);
134 testassert(state == (objc_collectingEnabled() ? 0 : 2));
135 testassert(idVal == cls);
137 (void) ((void(*)(id, Method))method_invoke)(cls, releaseMethod);
138 testassert(state == (objc_collectingEnabled() ? 0 : 3));
140 idVal = ((id(*)(id, Method))method_invoke)(cls, autoreleaseMethod);
141 testassert(state == (objc_collectingEnabled() ? 0 : 4));
142 testassert(idVal == cls);
144 (void) ((void(*)(id, Method))method_invoke)(cls, deallocMethod);
145 testassert(state == (objc_collectingEnabled() ? 0 : 5));
147 intVal = ((uintptr_t(*)(id, Method))method_invoke)(cls, retainCountMethod);
148 testassert(state == (objc_collectingEnabled() ? 0 : 6));
149 testassert(intVal == (objc_collectingEnabled() ? (uintptr_t)cls : 6));
152 // Test calls via compiled objc_msgSend
155 idVal = [cls ordinary];
156 testassert(state == 1);
157 testassert(idVal == cls);
160 idVal = [cls retain];
161 testassert(state == (objc_collectingEnabled() ? 0 : 2));
162 testassert(idVal == cls);
164 (void) [cls release];
165 testassert(state == (objc_collectingEnabled() ? 0 : 3));
167 idVal = [cls autorelease];
168 testassert(state == (objc_collectingEnabled() ? 0 : 4));
169 testassert(idVal == cls);
171 (void) [cls dealloc];
172 testassert(state == (objc_collectingEnabled() ? 0 : 5));
174 intVal = [cls retainCount];
175 testassert(state == (objc_collectingEnabled() ? 0 : 6));
176 testassert(intVal == (objc_collectingEnabled() ? (uintptr_t)cls : 6));
178 // Test calls via handwritten objc_msgSend
181 idVal = ((id(*)(id,SEL))objc_msgSend)(cls, @selector(ordinary));
182 testassert(state == 1);
183 testassert(idVal == cls);
186 idVal = ((id(*)(id,SEL))objc_msgSend)(cls, @selector(retain));
187 testassert(state == (objc_collectingEnabled() ? 0 : 2));
188 testassert(idVal == cls);
190 (void) ((void(*)(id,SEL))objc_msgSend)(cls, @selector(release));
191 testassert(state == (objc_collectingEnabled() ? 0 : 3));
193 idVal = ((id(*)(id,SEL))objc_msgSend)(cls, @selector(autorelease));
194 testassert(state == (objc_collectingEnabled() ? 0 : 4));
195 testassert(idVal == cls);
197 (void) ((void(*)(id,SEL))objc_msgSend)(cls, @selector(dealloc));
198 testassert(state == (objc_collectingEnabled() ? 0 : 5));
200 intVal = ((uintptr_t(*)(id,SEL))objc_msgSend)(cls, @selector(retainCount));
201 testassert(state == (objc_collectingEnabled() ? 0 : 6));
202 testassert(intVal == (objc_collectingEnabled() ? (uintptr_t)cls : 6));
211 testassert(sel_registerName("retain") == @selector(retain));
212 testassert(sel_getUid("retain") == @selector(retain));
213 #if defined(__i386__)
214 if (objc_collectingEnabled()) {
215 // only i386's GC currently remaps these
216 testassert(0 == strcmp(sel_getName(@selector(retain)), "<ignored selector>"));
220 testassert(0 == strcmp(sel_getName(@selector(retain)), "retain"));
223 testassert(sel_isMapped(@selector(retain)));
234 if (objc_collectingEnabled()) {
235 // rdar://6200570 Method manipulation shouldn't affect ignored methods.
241 method_setImplementation(retainMethod, (IMP)1);
242 method_setImplementation(releaseMethod, (IMP)1);
243 method_setImplementation(autoreleaseMethod, (IMP)1);
244 method_setImplementation(deallocMethod, (IMP)1);
245 method_setImplementation(retainCountMethod, (IMP)1);
248 testassert(ordinary2 != retainCount);
249 method_exchangeImplementations(retainMethod, autoreleaseMethod);
250 method_exchangeImplementations(deallocMethod, releaseMethod);
251 method_exchangeImplementations(retainCountMethod, ordinary2Method);
253 // ordinary2 exchanged with ignored method is now ignored too
254 testassert(ordinary2 == retainCount);
256 // replace == replace existing
257 class_replaceMethod(cls, @selector(retain), (IMP)1, "");
258 class_replaceMethod(cls, @selector(release), (IMP)1, "");
259 class_replaceMethod(cls, @selector(autorelease), (IMP)1, "");
260 class_replaceMethod(cls, @selector(dealloc), (IMP)1, "");
261 class_replaceMethod(cls, @selector(retainCount), (IMP)1, "");
268 // replace == add override
269 class_replaceMethod(cls, @selector(retain), (IMP)1, "");
270 class_replaceMethod(cls, @selector(release), (IMP)1, "");
271 class_replaceMethod(cls, @selector(autorelease), (IMP)1, "");
272 class_replaceMethod(cls, @selector(dealloc), (IMP)1, "");
273 class_replaceMethod(cls, @selector(retainCount), (IMP)1, "");
280 class_addMethod(cls, @selector(retain), (IMP)1, "");
281 class_addMethod(cls, @selector(release), (IMP)1, "");
282 class_addMethod(cls, @selector(autorelease), (IMP)1, "");
283 class_addMethod(cls, @selector(dealloc), (IMP)1, "");
284 class_addMethod(cls, @selector(retainCount), (IMP)1, "");
288 // Test calls via objc_msgSend - ignored selectors are ignored
289 // under GC even if the class provides no implementation for them
290 if (objc_collectingEnabled()) {
298 idVal = [Empty retain];
299 testassert(state == 0);
300 testassert(idVal == cls);
302 (void) [Empty release];
303 testassert(state == 0);
305 idVal = [Empty autorelease];
306 testassert(state == 0);
307 testassert(idVal == cls);
309 (void) [Empty dealloc];
310 testassert(state == 0);
312 intVal = [Empty retainCount];
313 testassert(state == 0);
314 testassert(intVal == (uintptr_t)cls);
316 idVal = [Empty ordinary];
317 testassert(state == 1);
318 testassert(idVal == nil);
322 idVal = ((id(*)(id,SEL))objc_msgSend)(cls, @selector(retain));
323 testassert(state == 0);
324 testassert(idVal == cls);
326 (void) ((void(*)(id,SEL))objc_msgSend)(cls, @selector(release));
327 testassert(state == 0);
329 idVal = ((id(*)(id,SEL))objc_msgSend)(cls, @selector(autorelease));
330 testassert(state == 0);
331 testassert(idVal == cls);
333 (void) ((void(*)(id,SEL))objc_msgSend)(cls, @selector(dealloc));
334 testassert(state == 0);
336 intVal = ((uintptr_t(*)(id,SEL))objc_msgSend)(cls, @selector(retainCount));
337 testassert(state == 0);
338 testassert(intVal == (uintptr_t)cls);
340 idVal = ((id(*)(id,SEL))objc_msgSend)(cls, @selector(ordinary));
341 testassert(state == 1);
342 testassert(idVal == nil);