1 // This file is used in the customrr-nsobject-*.m tests
4 #include <objc/NSObject.h>
9 // old ABI does not implement the optimization
15 static int Autoreleases;
16 static int PlusInitializes;
18 static int AllocWithZones;
20 id (*RealRetain)(id self, SEL _cmd);
21 void (*RealRelease)(id self, SEL _cmd);
22 id (*RealAutorelease)(id self, SEL _cmd);
23 id (*RealAlloc)(id self, SEL _cmd);
24 id (*RealAllocWithZone)(id self, SEL _cmd, void *zone);
26 id HackRetain(id self, SEL _cmd) { Retains++; return RealRetain(self, _cmd); }
27 void HackRelease(id self, SEL _cmd) { Releases++; return RealRelease(self, _cmd); }
28 id HackAutorelease(id self, SEL _cmd) { Autoreleases++; return RealAutorelease(self, _cmd); }
30 id HackAlloc(Class self, SEL _cmd) { Allocs++; return RealAlloc(self, _cmd); }
31 id HackAllocWithZone(Class self, SEL _cmd, void *zone) { AllocWithZones++; return RealAllocWithZone(self, _cmd, zone); }
33 void HackPlusInitialize(id self __unused, SEL _cmd __unused) { PlusInitializes++; }
36 int main(int argc __unused, char **argv)
38 Class cls = objc_getClass("NSObject");
41 meth = class_getClassMethod(cls, @selector(initialize));
42 method_setImplementation(meth, (IMP)HackPlusInitialize);
44 // We either swizzle the method normally (testing that it properly
45 // disables optimizations), or we hack the implementation into place
46 // behind objc's back (so we can see whether it got called with the
47 // optimizations still enabled).
49 meth = class_getClassMethod(cls, @selector(allocWithZone:));
50 RealAllocWithZone = (typeof(RealAllocWithZone))method_getImplementation(meth);
52 method_setImplementation(meth, (IMP)HackAllocWithZone);
54 ((IMP *)meth)[2] = (IMP)HackAllocWithZone;
57 meth = class_getInstanceMethod(cls, @selector(release));
58 RealRelease = (typeof(RealRelease))method_getImplementation(meth);
60 method_setImplementation(meth, (IMP)HackRelease);
62 ((IMP *)meth)[2] = (IMP)HackRelease;
65 // These other methods get hacked for counting purposes only
67 meth = class_getInstanceMethod(cls, @selector(retain));
68 RealRetain = (typeof(RealRetain))method_getImplementation(meth);
69 ((IMP *)meth)[2] = (IMP)HackRetain;
71 meth = class_getInstanceMethod(cls, @selector(autorelease));
72 RealAutorelease = (typeof(RealAutorelease))method_getImplementation(meth);
73 ((IMP *)meth)[2] = (IMP)HackAutorelease;
75 meth = class_getClassMethod(cls, @selector(alloc));
76 RealAlloc = (typeof(RealAlloc))method_getImplementation(meth);
77 ((IMP *)meth)[2] = (IMP)HackAlloc;
79 // Verify that the swizzles occurred before +initialize by provoking it now
80 testassert(PlusInitializes == 0);
82 testassert(PlusInitializes == 1);
85 // hack: fool the expected output because old ABI doesn't optimize this
87 fprintf(stderr, "objc[1234]: CUSTOM AWZ: NSObject (meta)\n");
90 fprintf(stderr, "objc[1234]: CUSTOM RR: NSObject\n");
98 obj = objc_alloc(cls);
99 #if SWIZZLE_AWZ || !BYPASS
100 testprintf("swizzled AWZ should be called\n");
101 testassert(Allocs == 1);
102 testassert(AllocWithZones == 1);
104 testprintf("unswizzled AWZ should be bypassed\n");
105 testassert(Allocs == 0);
106 testassert(AllocWithZones == 0);
111 obj = [NSObject alloc];
112 #if SWIZZLE_AWZ || !BYPASS
113 testprintf("swizzled AWZ should be called\n");
114 testassert(Allocs == 1);
115 testassert(AllocWithZones == 1);
117 testprintf("unswizzled AWZ should be bypassed\n");
118 testassert(Allocs == 1);
119 testassert(AllocWithZones == 0);
124 #if SWIZZLE_RELEASE || !BYPASS
125 testprintf("swizzled release should force retain\n");
126 testassert(Retains == 1);
128 testprintf("unswizzled release should bypass retain\n");
129 testassert(Retains == 0);
135 objc_autorelease(obj);
136 #if SWIZZLE_RELEASE || !BYPASS
137 testprintf("swizzled release should force autorelease\n");
138 testassert(Autoreleases == 1);
140 testprintf("unswizzled release should bypass autorelease\n");
141 testassert(Autoreleases == 0);
145 #if SWIZZLE_RELEASE || !BYPASS
146 testprintf("swizzled release should be called\n");
147 testassert(Releases == 1);
149 testprintf("unswizzled release should be bypassed\n");
150 testassert(Releases == 0);
153 succeed(basename(argv[0]));