]> git.saurik.com Git - apple/objc4.git/blob - test/customrr-nsobject.m
objc4-680.tar.gz
[apple/objc4.git] / test / customrr-nsobject.m
1 // This file is used in the customrr-nsobject-*.m tests
2
3 #include "test.h"
4 #include <objc/NSObject.h>
5
6 #if __OBJC2__
7 # define BYPASS 1
8 #else
9 // old ABI does not implement the optimization
10 # define BYPASS 0
11 #endif
12
13 static int Retains;
14 static int Releases;
15 static int Autoreleases;
16 static int PlusInitializes;
17 static int Allocs;
18 static int AllocWithZones;
19
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);
25
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); }
29
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); }
32
33 void HackPlusInitialize(id self __unused, SEL _cmd __unused) { PlusInitializes++; }
34
35
36 int main(int argc __unused, char **argv)
37 {
38 Class cls = objc_getClass("NSObject");
39 Method meth;
40
41 meth = class_getClassMethod(cls, @selector(initialize));
42 method_setImplementation(meth, (IMP)HackPlusInitialize);
43
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).
48
49 meth = class_getClassMethod(cls, @selector(allocWithZone:));
50 RealAllocWithZone = (typeof(RealAllocWithZone))method_getImplementation(meth);
51 #if SWIZZLE_AWZ
52 method_setImplementation(meth, (IMP)HackAllocWithZone);
53 #else
54 ((IMP *)meth)[2] = (IMP)HackAllocWithZone;
55 #endif
56
57 meth = class_getInstanceMethod(cls, @selector(release));
58 RealRelease = (typeof(RealRelease))method_getImplementation(meth);
59 #if SWIZZLE_RELEASE
60 method_setImplementation(meth, (IMP)HackRelease);
61 #else
62 ((IMP *)meth)[2] = (IMP)HackRelease;
63 #endif
64
65 // These other methods get hacked for counting purposes only
66
67 meth = class_getInstanceMethod(cls, @selector(retain));
68 RealRetain = (typeof(RealRetain))method_getImplementation(meth);
69 ((IMP *)meth)[2] = (IMP)HackRetain;
70
71 meth = class_getInstanceMethod(cls, @selector(autorelease));
72 RealAutorelease = (typeof(RealAutorelease))method_getImplementation(meth);
73 ((IMP *)meth)[2] = (IMP)HackAutorelease;
74
75 meth = class_getClassMethod(cls, @selector(alloc));
76 RealAlloc = (typeof(RealAlloc))method_getImplementation(meth);
77 ((IMP *)meth)[2] = (IMP)HackAlloc;
78
79 // Verify that the swizzles occurred before +initialize by provoking it now
80 testassert(PlusInitializes == 0);
81 [NSObject self];
82 testassert(PlusInitializes == 1);
83
84 #if !__OBJC2__
85 // hack: fool the expected output because old ABI doesn't optimize this
86 # if SWIZZLE_AWZ
87 fprintf(stderr, "objc[1234]: CUSTOM AWZ: NSObject (meta)\n");
88 # endif
89 # if SWIZZLE_RELEASE
90 fprintf(stderr, "objc[1234]: CUSTOM RR: NSObject\n");
91 # endif
92 #endif
93
94 id obj;
95
96 Allocs = 0;
97 AllocWithZones = 0;
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);
103 #else
104 testprintf("unswizzled AWZ should be bypassed\n");
105 testassert(Allocs == 0);
106 testassert(AllocWithZones == 0);
107 #endif
108
109 Allocs = 0;
110 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);
116 #else
117 testprintf("unswizzled AWZ should be bypassed\n");
118 testassert(Allocs == 1);
119 testassert(AllocWithZones == 0);
120 #endif
121
122 Retains = 0;
123 objc_retain(obj);
124 #if SWIZZLE_RELEASE || !BYPASS
125 testprintf("swizzled release should force retain\n");
126 testassert(Retains == 1);
127 #else
128 testprintf("unswizzled release should bypass retain\n");
129 testassert(Retains == 0);
130 #endif
131
132 Releases = 0;
133 Autoreleases = 0;
134 PUSH_POOL {
135 objc_autorelease(obj);
136 #if SWIZZLE_RELEASE || !BYPASS
137 testprintf("swizzled release should force autorelease\n");
138 testassert(Autoreleases == 1);
139 #else
140 testprintf("unswizzled release should bypass autorelease\n");
141 testassert(Autoreleases == 0);
142 #endif
143 } POP_POOL
144
145 #if SWIZZLE_RELEASE || !BYPASS
146 testprintf("swizzled release should be called\n");
147 testassert(Releases == 1);
148 #else
149 testprintf("unswizzled release should be bypassed\n");
150 testassert(Releases == 0);
151 #endif
152
153 succeed(basename(argv[0]));
154 }