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
9int TestRootLoad = 0;
10int TestRootInitialize = 0;
11int TestRootAlloc = 0;
12int TestRootAllocWithZone = 0;
13int TestRootCopy = 0;
14int TestRootCopyWithZone = 0;
15int TestRootMutableCopy = 0;
16int TestRootMutableCopyWithZone = 0;
17int TestRootInit = 0;
18int TestRootDealloc = 0;
19int TestRootFinalize = 0;
20int TestRootRetain = 0;
21int TestRootRelease = 0;
22int TestRootAutorelease = 0;
23int TestRootRetainCount = 0;
24int TestRootTryRetain = 0;
25int TestRootIsDeallocating = 0;
26int TestRootPlusRetain = 0;
27int TestRootPlusRelease = 0;
28int TestRootPlusAutorelease = 0;
29int TestRootPlusRetainCount = 0;
30
31
32@implementation TestRoot
33
34// These all use void* pending rdar://9310005.
35
36static void *
37retain_fn(void *self, SEL _cmd __unused) {
38    OSAtomicIncrement32(&TestRootRetain);
39    void * (*fn)(void *) = (typeof(fn))_objc_rootRetain;
40    return fn(self);
41}
42
43static void
44release_fn(void *self, SEL _cmd __unused) {
45    OSAtomicIncrement32(&TestRootRelease);
46    void (*fn)(void *) = (typeof(fn))_objc_rootRelease;
47    fn(self);
48}
49
50static void *
51autorelease_fn(void *self, SEL _cmd __unused) {
52    OSAtomicIncrement32(&TestRootAutorelease);
53    void * (*fn)(void *) = (typeof(fn))_objc_rootAutorelease;
54    return fn(self);
55}
56
57static unsigned long
58retaincount_fn(void *self, SEL _cmd __unused) {
59    OSAtomicIncrement32(&TestRootRetainCount);
60    unsigned long (*fn)(void *) = (typeof(fn))_objc_rootRetainCount;
61    return fn(self);
62}
63
64static void *
65copywithzone_fn(void *self, SEL _cmd __unused, void *zone) {
66    OSAtomicIncrement32(&TestRootCopyWithZone);
67    void * (*fn)(void *, void *) = (typeof(fn))dlsym(RTLD_DEFAULT, "object_copy");
68    return fn(self, zone);
69}
70
71static void *
72plusretain_fn(void *self __unused, SEL _cmd __unused) {
73    OSAtomicIncrement32(&TestRootPlusRetain);
74    return self;
75}
76
77static void
78plusrelease_fn(void *self __unused, SEL _cmd __unused) {
79    OSAtomicIncrement32(&TestRootPlusRelease);
80}
81
82static void *
83plusautorelease_fn(void *self, SEL _cmd __unused) {
84    OSAtomicIncrement32(&TestRootPlusAutorelease);
85    return self;
86}
87
88static unsigned long
89plusretaincount_fn(void *self __unused, SEL _cmd __unused) {
90    OSAtomicIncrement32(&TestRootPlusRetainCount);
91    return ULONG_MAX;
92}
93
94+(void) load {
95    OSAtomicIncrement32(&TestRootLoad);
96
97    // install methods that ARR 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    OSAtomicIncrement32(&TestRootInitialize);
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    OSAtomicIncrement32(&TestRootAlloc);
141    void * (*fn)(id __unsafe_unretained) = (typeof(fn))_objc_rootAlloc;
142    return objc_retainedObject(fn(self));
143}
144
145+(id) allocWithZone:(void *)zone {
146    OSAtomicIncrement32(&TestRootAllocWithZone);
147    void * (*fn)(id __unsafe_unretained, void *) = (typeof(fn))_objc_rootAllocWithZone;
148    return objc_retainedObject(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    OSAtomicIncrement32(&TestRootCopy);
161    return [self copyWithZone:NULL];
162}
163
164+(id) mutableCopyWithZone:(void *) __unused zone {
165    fail("+mutableCopyWithZone: called");
166}
167
168-(id) mutableCopy {
169    OSAtomicIncrement32(&TestRootMutableCopy);
170    return [self mutableCopyWithZone:NULL];
171}
172
173-(id) mutableCopyWithZone:(void *) __unused zone {
174    OSAtomicIncrement32(&TestRootMutableCopyWithZone);
175    void * (*fn)(id __unsafe_unretained) = (typeof(fn))_objc_rootAlloc;
176    return objc_retainedObject(fn(object_getClass(self)));
177}
178
179-(id) init {
180    OSAtomicIncrement32(&TestRootInit);
181    return _objc_rootInit(self);
182}
183
184+(void) dealloc {
185    fail("+dealloc called");
186}
187
188-(void) dealloc {
189    OSAtomicIncrement32(&TestRootDealloc);
190    _objc_rootDealloc(self);
191}
192
193+(void) finalize {
194    fail("+finalize called");
195}
196
197-(void) finalize {
198    OSAtomicIncrement32(&TestRootFinalize);
199    _objc_rootFinalize(self);
200}
201
202+(BOOL) _tryRetain {
203    return YES;
204}
205
206-(BOOL) _tryRetain {
207    OSAtomicIncrement32(&TestRootTryRetain);
208    return _objc_rootTryRetain(self);
209}
210
211+(BOOL) _isDeallocating {
212    return NO;
213}
214
215-(BOOL) _isDeallocating {
216    OSAtomicIncrement32(&TestRootIsDeallocating);
217    return _objc_rootIsDeallocating(self);
218}
219
220-(BOOL) allowsWeakReference {
221    return ! [self _isDeallocating];
222}
223
224-(BOOL) retainWeakReference {
225    return [self _tryRetain];
226}
227
228
229@end
230