]>
Commit | Line | Data |
---|---|---|
13ba007e A |
1 | // testroot.i |
2 | // Implementation of class TestRoot | |
3 | // Include this file into your main test file to use it. | |
4 | ||
5 | #include "test.h" | |
6 | #include <dlfcn.h> | |
7 | #include <objc/objc-internal.h> | |
8 | ||
9 | atomic_int TestRootLoad; | |
10 | atomic_int TestRootInitialize; | |
11 | atomic_int TestRootAlloc; | |
12 | atomic_int TestRootAllocWithZone; | |
13 | atomic_int TestRootCopy; | |
14 | atomic_int TestRootCopyWithZone; | |
15 | atomic_int TestRootMutableCopy; | |
16 | atomic_int TestRootMutableCopyWithZone; | |
17 | atomic_int TestRootInit; | |
18 | atomic_int TestRootDealloc; | |
19 | atomic_int TestRootRetain; | |
20 | atomic_int TestRootRelease; | |
21 | atomic_int TestRootAutorelease; | |
22 | atomic_int TestRootRetainCount; | |
23 | atomic_int TestRootTryRetain; | |
24 | atomic_int TestRootIsDeallocating; | |
25 | atomic_int TestRootPlusRetain; | |
26 | atomic_int TestRootPlusRelease; | |
27 | atomic_int TestRootPlusAutorelease; | |
28 | atomic_int TestRootPlusRetainCount; | |
29 | ||
30 | ||
31 | @implementation TestRoot | |
32 | ||
33 | // These all use void* pending rdar://9310005. | |
34 | ||
35 | static void * | |
36 | retain_fn(void *self, SEL _cmd __unused) { | |
37 | atomic_fetch_add_explicit(&TestRootRetain, 1, memory_order_relaxed); | |
38 | void * (*fn)(void *) = (typeof(fn))_objc_rootRetain; | |
39 | return fn(self); | |
40 | } | |
41 | ||
42 | static void | |
43 | release_fn(void *self, SEL _cmd __unused) { | |
44 | atomic_fetch_add_explicit(&TestRootRelease, 1, memory_order_relaxed); | |
45 | void (*fn)(void *) = (typeof(fn))_objc_rootRelease; | |
46 | fn(self); | |
47 | } | |
48 | ||
49 | static void * | |
50 | autorelease_fn(void *self, SEL _cmd __unused) { | |
51 | atomic_fetch_add_explicit(&TestRootAutorelease, 1, memory_order_relaxed); | |
52 | void * (*fn)(void *) = (typeof(fn))_objc_rootAutorelease; | |
53 | return fn(self); | |
54 | } | |
55 | ||
56 | static unsigned long | |
57 | retaincount_fn(void *self, SEL _cmd __unused) { | |
58 | atomic_fetch_add_explicit(&TestRootRetainCount, 1, memory_order_relaxed); | |
59 | unsigned long (*fn)(void *) = (typeof(fn))_objc_rootRetainCount; | |
60 | return fn(self); | |
61 | } | |
62 | ||
63 | static void * | |
64 | copywithzone_fn(void *self, SEL _cmd __unused, void *zone) { | |
65 | atomic_fetch_add_explicit(&TestRootCopyWithZone, 1, memory_order_relaxed); | |
66 | void * (*fn)(void *, void *) = | |
67 | (typeof(fn))dlsym(RTLD_DEFAULT, "object_copy"); | |
68 | return fn(self, zone); | |
69 | } | |
70 | ||
71 | static void * | |
72 | plusretain_fn(void *self __unused, SEL _cmd __unused) { | |
73 | atomic_fetch_add_explicit(&TestRootPlusRetain, 1, memory_order_relaxed); | |
74 | return self; | |
75 | } | |
76 | ||
77 | static void | |
78 | plusrelease_fn(void *self __unused, SEL _cmd __unused) { | |
79 | atomic_fetch_add_explicit(&TestRootPlusRelease, 1, memory_order_relaxed); | |
80 | } | |
81 | ||
82 | static void * | |
83 | plusautorelease_fn(void *self, SEL _cmd __unused) { | |
84 | atomic_fetch_add_explicit(&TestRootPlusAutorelease, 1, memory_order_relaxed); | |
85 | return self; | |
86 | } | |
87 | ||
88 | static unsigned long | |
89 | plusretaincount_fn(void *self __unused, SEL _cmd __unused) { | |
90 | atomic_fetch_add_explicit(&TestRootPlusRetainCount, 1, memory_order_relaxed); | |
91 | return ULONG_MAX; | |
92 | } | |
93 | ||
94 | +(void) load { | |
95 | atomic_fetch_add_explicit(&TestRootLoad, 1, memory_order_relaxed); | |
96 | ||
97 | // install methods that ARC refuses to compile | |
98 | class_addMethod(self, sel_registerName("retain"), (IMP)retain_fn, ""); | |
99 | class_addMethod(self, sel_registerName("release"), (IMP)release_fn, ""); | |
100 | class_addMethod(self, sel_registerName("autorelease"), (IMP)autorelease_fn, ""); | |
101 | class_addMethod(self, sel_registerName("retainCount"), (IMP)retaincount_fn, ""); | |
102 | class_addMethod(self, sel_registerName("copyWithZone:"), (IMP)copywithzone_fn, ""); | |
103 | ||
104 | class_addMethod(object_getClass(self), sel_registerName("retain"), (IMP)plusretain_fn, ""); | |
105 | class_addMethod(object_getClass(self), sel_registerName("release"), (IMP)plusrelease_fn, ""); | |
106 | class_addMethod(object_getClass(self), sel_registerName("autorelease"), (IMP)plusautorelease_fn, ""); | |
107 | class_addMethod(object_getClass(self), sel_registerName("retainCount"), (IMP)plusretaincount_fn, ""); | |
108 | } | |
109 | ||
110 | ||
111 | +(void) initialize { | |
112 | atomic_fetch_add_explicit(&TestRootInitialize, 1, memory_order_relaxed); | |
113 | } | |
114 | ||
115 | -(id) self { | |
116 | return self; | |
117 | } | |
118 | ||
119 | +(Class) class { | |
120 | return self; | |
121 | } | |
122 | ||
123 | -(Class) class { | |
124 | return object_getClass(self); | |
125 | } | |
126 | ||
127 | +(Class) superclass { | |
128 | return class_getSuperclass(self); | |
129 | } | |
130 | ||
131 | -(Class) superclass { | |
132 | return class_getSuperclass([self class]); | |
133 | } | |
134 | ||
135 | +(id) new { | |
136 | return [[self alloc] init]; | |
137 | } | |
138 | ||
139 | +(id) alloc { | |
140 | atomic_fetch_add_explicit(&TestRootAlloc, 1, memory_order_relaxed); | |
141 | void * (*fn)(id __unsafe_unretained) = (typeof(fn))_objc_rootAlloc; | |
142 | return (__bridge_transfer id)(fn(self)); | |
143 | } | |
144 | ||
145 | +(id) allocWithZone:(void *)zone { | |
146 | atomic_fetch_add_explicit(&TestRootAllocWithZone, 1, memory_order_relaxed); | |
147 | void * (*fn)(id __unsafe_unretained, void *) = (typeof(fn))_objc_rootAllocWithZone; | |
148 | return (__bridge_transfer id)(fn(self, zone)); | |
149 | } | |
150 | ||
151 | +(id) copy { | |
152 | return self; | |
153 | } | |
154 | ||
155 | +(id) copyWithZone:(void *) __unused zone { | |
156 | return self; | |
157 | } | |
158 | ||
159 | -(id) copy { | |
160 | atomic_fetch_add_explicit(&TestRootCopy, 1, memory_order_relaxed); | |
161 | return [self copyWithZone:NULL]; | |
162 | } | |
163 | ||
164 | +(id) mutableCopyWithZone:(void *) __unused zone { | |
165 | fail("+mutableCopyWithZone: called"); | |
166 | } | |
167 | ||
168 | -(id) mutableCopy { | |
169 | atomic_fetch_add_explicit(&TestRootMutableCopy, 1, memory_order_relaxed); | |
170 | return [self mutableCopyWithZone:NULL]; | |
171 | } | |
172 | ||
173 | -(id) mutableCopyWithZone:(void *) __unused zone { | |
174 | atomic_fetch_add_explicit(&TestRootMutableCopyWithZone, 1, memory_order_relaxed); | |
175 | void * (*fn)(id __unsafe_unretained) = (typeof(fn))_objc_rootAlloc; | |
176 | return (__bridge_transfer id)(fn(object_getClass(self))); | |
177 | } | |
178 | ||
179 | -(id) init { | |
180 | atomic_fetch_add_explicit(&TestRootInit, 1, memory_order_relaxed); | |
181 | return _objc_rootInit(self); | |
182 | } | |
183 | ||
184 | +(void) dealloc { | |
185 | fail("+dealloc called"); | |
186 | } | |
187 | ||
188 | -(void) dealloc { | |
189 | atomic_fetch_add_explicit(&TestRootDealloc, 1, memory_order_relaxed); | |
190 | _objc_rootDealloc(self); | |
191 | } | |
192 | ||
193 | +(BOOL) _tryRetain { | |
194 | return YES; | |
195 | } | |
196 | ||
197 | -(BOOL) _tryRetain { | |
198 | atomic_fetch_add_explicit(&TestRootTryRetain, 1, memory_order_relaxed); | |
199 | return _objc_rootTryRetain(self); | |
200 | } | |
201 | ||
202 | +(BOOL) _isDeallocating { | |
203 | return NO; | |
204 | } | |
205 | ||
206 | -(BOOL) _isDeallocating { | |
207 | atomic_fetch_add_explicit(&TestRootIsDeallocating, 1, memory_order_relaxed); | |
208 | return _objc_rootIsDeallocating(self); | |
209 | } | |
210 | ||
211 | -(BOOL) allowsWeakReference { | |
212 | return ! [self _isDeallocating]; | |
213 | } | |
214 | ||
215 | -(BOOL) retainWeakReference { | |
216 | return [self _tryRetain]; | |
217 | } | |
218 | ||
219 | ||
220 | @end |