]> git.saurik.com Git - apple/objc4.git/blob - test/taggedPointers.m
objc4-532.tar.gz
[apple/objc4.git] / test / taggedPointers.m
1 // TEST_CONFIG
2
3 #include "test.h"
4 #include <objc/runtime.h>
5 #include <objc/objc-internal.h>
6 #import <Foundation/NSObject.h>
7
8 #if __has_feature(objc_arc)
9
10 int main()
11 {
12 testwarn("rdar://11368528 confused by Foundation");
13 succeed(__FILE__);
14 }
15
16 #else
17
18 #if __OBJC2__ && __LP64__
19
20 static BOOL didIt;
21
22 #define TAG_VALUE(tagSlot, value) (objc_unretainedObject((void*)(1UL | (((uintptr_t)(tagSlot)) << 1) | (((uintptr_t)(value)) << 4))))
23
24 @interface WeakContainer : NSObject
25 {
26 @public
27 __weak id weaks[10000];
28 }
29 @end
30 @implementation WeakContainer
31 -(void) dealloc {
32 for (unsigned int i = 0; i < sizeof(weaks)/sizeof(weaks[0]); i++) {
33 testassert(weaks[i] == nil);
34 }
35 SUPER_DEALLOC();
36 }
37 -(void) finalize {
38 for (unsigned int i = 0; i < sizeof(weaks)/sizeof(weaks[0]); i++) {
39 testassert(weaks[i] == nil);
40 }
41 [super finalize];
42 }
43 @end
44
45 @interface TaggedBaseClass
46 @end
47
48 @implementation TaggedBaseClass
49 + (void) initialize {
50 }
51
52 - (void) instanceMethod {
53 didIt = YES;
54 }
55
56 - (uintptr_t) taggedValue {
57 return (uintptr_t)objc_unretainedPointer(self) >> 4;
58 }
59
60 - (struct stret) stret: (struct stret) aStruct {
61 return aStruct;
62 }
63
64 - (long double) fpret: (long double) aValue {
65 return aValue;
66 }
67
68
69 -(void) dealloc {
70 fail("TaggedBaseClass dealloc called!");
71 }
72
73 static void *
74 retain_fn(void *self, SEL _cmd __unused) {
75 void * (*fn)(void *) = (typeof(fn))_objc_rootRetain;
76 return fn(self);
77 }
78
79 static void
80 release_fn(void *self, SEL _cmd __unused) {
81 void (*fn)(void *) = (typeof(fn))_objc_rootRelease;
82 fn(self);
83 }
84
85 static void *
86 autorelease_fn(void *self, SEL _cmd __unused) {
87 void * (*fn)(void *) = (typeof(fn))_objc_rootAutorelease;
88 return fn(self);
89 }
90
91 static unsigned long
92 retaincount_fn(void *self, SEL _cmd __unused) {
93 unsigned long (*fn)(void *) = (typeof(fn))_objc_rootRetainCount;
94 return fn(self);
95 }
96
97 +(void) load {
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 }
103
104 @end
105
106 @interface TaggedSubclass: TaggedBaseClass
107 @end
108
109 @implementation TaggedSubclass
110
111 - (void) instanceMethod {
112 return [super instanceMethod];
113 }
114
115 - (uintptr_t) taggedValue {
116 return [super taggedValue];
117 }
118
119 - (struct stret) stret: (struct stret) aStruct {
120 return [super stret: aStruct];
121 }
122
123 - (long double) fpret: (long double) aValue {
124 return [super fpret: aValue];
125 }
126 @end
127
128 @interface TaggedNSObjectSubclass : NSObject
129 @end
130
131 @implementation TaggedNSObjectSubclass
132
133 - (void) instanceMethod {
134 didIt = YES;
135 }
136
137 - (uintptr_t) taggedValue {
138 return (uintptr_t)objc_unretainedPointer(self) >> 4;
139 }
140
141 - (struct stret) stret: (struct stret) aStruct {
142 return aStruct;
143 }
144
145 - (long double) fpret: (long double) aValue {
146 return aValue;
147 }
148 @end
149
150 void testGenericTaggedPointer(uint8_t tagSlot, const char *classname)
151 {
152 testprintf("%s\n", classname);
153
154 Class cls = objc_getClass(classname);
155 testassert(cls);
156
157 id taggedPointer = TAG_VALUE(tagSlot, 1234);
158 testassert(object_getClass(taggedPointer) == cls);
159 testassert([taggedPointer taggedValue] == 1234);
160
161 didIt = NO;
162 [taggedPointer instanceMethod];
163 testassert(didIt);
164
165 struct stret orig = STRET_RESULT;
166 testassert(stret_equal(orig, [taggedPointer stret: orig]));
167
168 long double value = 3.14156789;
169 testassert(value == [taggedPointer fpret: value]);
170
171 // Tagged pointers should bypass refcount tables and autorelease pools
172 // and weak reference tables
173 WeakContainer *w = [WeakContainer new];
174 leak_mark();
175 for (uintptr_t i = 0; i < sizeof(w->weaks)/sizeof(w->weaks[0]); i++) {
176 id o = TAG_VALUE(tagSlot, i);
177 testassert(object_getClass(o) == cls);
178
179 id result = WEAK_STORE(w->weaks[i], o);
180 testassert(result == o);
181 testassert(w->weaks[i] == o);
182
183 result = WEAK_LOAD(w->weaks[i]);
184 testassert(result == o);
185
186 if (!objc_collectingEnabled()) {
187 uintptr_t rc = _objc_rootRetainCount(o);
188 testassert(rc != 0);
189 _objc_rootRelease(o); testassert(_objc_rootRetainCount(o) == rc);
190 _objc_rootRelease(o); testassert(_objc_rootRetainCount(o) == rc);
191 _objc_rootRetain(o); testassert(_objc_rootRetainCount(o) == rc);
192 _objc_rootRetain(o); testassert(_objc_rootRetainCount(o) == rc);
193 _objc_rootRetain(o); testassert(_objc_rootRetainCount(o) == rc);
194 #if !__has_feature(objc_arc)
195 [o release]; testassert(_objc_rootRetainCount(o) == rc);
196 [o release]; testassert(_objc_rootRetainCount(o) == rc);
197 [o retain]; testassert(_objc_rootRetainCount(o) == rc);
198 [o retain]; testassert(_objc_rootRetainCount(o) == rc);
199 [o retain]; testassert(_objc_rootRetainCount(o) == rc);
200 objc_release(o); testassert(_objc_rootRetainCount(o) == rc);
201 objc_release(o); testassert(_objc_rootRetainCount(o) == rc);
202 objc_retain(o); testassert(_objc_rootRetainCount(o) == rc);
203 objc_retain(o); testassert(_objc_rootRetainCount(o) == rc);
204 objc_retain(o); testassert(_objc_rootRetainCount(o) == rc);
205 #endif
206 PUSH_POOL {
207 testassert(_objc_rootRetainCount(o) == rc);
208 _objc_rootAutorelease(o);
209 testassert(_objc_rootRetainCount(o) == rc);
210 #if !__has_feature(objc_arc)
211 [o autorelease];
212 testassert(_objc_rootRetainCount(o) == rc);
213 objc_autorelease(o);
214 testassert(_objc_rootRetainCount(o) == rc);
215 objc_retainAutorelease(o);
216 testassert(_objc_rootRetainCount(o) == rc);
217 objc_autoreleaseReturnValue(o);
218 testassert(_objc_rootRetainCount(o) == rc);
219 objc_retainAutoreleaseReturnValue(o);
220 testassert(_objc_rootRetainCount(o) == rc);
221 objc_retainAutoreleasedReturnValue(o);
222 testassert(_objc_rootRetainCount(o) == rc);
223 #endif
224 } POP_POOL;
225 testassert(_objc_rootRetainCount(o) == rc);
226 }
227 }
228 leak_check(0);
229 for (uintptr_t i = 0; i < 10000; i++) {
230 testassert(w->weaks[i] != NULL);
231 WEAK_STORE(w->weaks[i], NULL);
232 testassert(w->weaks[i] == NULL);
233 testassert(WEAK_LOAD(w->weaks[i]) == NULL);
234 }
235 RELEASE_VAR(w);
236 }
237
238 int main()
239 {
240 PUSH_POOL {
241 _objc_insert_tagged_isa(5, objc_getClass("TaggedBaseClass"));
242 testGenericTaggedPointer(5, "TaggedBaseClass");
243
244 _objc_insert_tagged_isa(2, objc_getClass("TaggedSubclass"));
245 testGenericTaggedPointer(2, "TaggedSubclass");
246
247 _objc_insert_tagged_isa(3, objc_getClass("TaggedNSObjectSubclass"));
248 testGenericTaggedPointer(3, "TaggedNSObjectSubclass");
249 } POP_POOL;
250
251 succeed(__FILE__);
252 }
253
254 // OBJC2 && __LP64__
255 #else
256 // not (OBJC2 && __LP64__)
257
258 // Tagged pointers not supported.
259
260 int main()
261 {
262 succeed(__FILE__);
263 }
264
265 #endif
266
267 #endif