4 #include <objc/runtime.h>
5 #include <objc/objc-internal.h>
6 #import <Foundation/NSObject.h>
8 #if __has_feature(objc_arc)
12 testwarn("rdar://11368528 confused by Foundation");
18 #if __OBJC2__ && __LP64__
22 #define TAG_VALUE(tagSlot, value) (objc_unretainedObject((void*)(1UL | (((uintptr_t)(tagSlot)) << 1) | (((uintptr_t)(value)) << 4))))
24 @interface WeakContainer : NSObject
27 __weak id weaks[10000];
30 @implementation WeakContainer
32 for (unsigned int i = 0; i < sizeof(weaks)/sizeof(weaks[0]); i++) {
33 testassert(weaks[i] == nil);
38 for (unsigned int i = 0; i < sizeof(weaks)/sizeof(weaks[0]); i++) {
39 testassert(weaks[i] == nil);
45 @interface TaggedBaseClass
48 @implementation TaggedBaseClass
52 - (void) instanceMethod {
56 - (uintptr_t) taggedValue {
57 return (uintptr_t)objc_unretainedPointer(self) >> 4;
60 - (struct stret) stret: (struct stret) aStruct {
64 - (long double) fpret: (long double) aValue {
70 fail("TaggedBaseClass dealloc called!");
74 retain_fn(void *self, SEL _cmd __unused) {
75 void * (*fn)(void *) = (typeof(fn))_objc_rootRetain;
80 release_fn(void *self, SEL _cmd __unused) {
81 void (*fn)(void *) = (typeof(fn))_objc_rootRelease;
86 autorelease_fn(void *self, SEL _cmd __unused) {
87 void * (*fn)(void *) = (typeof(fn))_objc_rootAutorelease;
92 retaincount_fn(void *self, SEL _cmd __unused) {
93 unsigned long (*fn)(void *) = (typeof(fn))_objc_rootRetainCount;
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, "");
106 @interface TaggedSubclass: TaggedBaseClass
109 @implementation TaggedSubclass
111 - (void) instanceMethod {
112 return [super instanceMethod];
115 - (uintptr_t) taggedValue {
116 return [super taggedValue];
119 - (struct stret) stret: (struct stret) aStruct {
120 return [super stret: aStruct];
123 - (long double) fpret: (long double) aValue {
124 return [super fpret: aValue];
128 @interface TaggedNSObjectSubclass : NSObject
131 @implementation TaggedNSObjectSubclass
133 - (void) instanceMethod {
137 - (uintptr_t) taggedValue {
138 return (uintptr_t)objc_unretainedPointer(self) >> 4;
141 - (struct stret) stret: (struct stret) aStruct {
145 - (long double) fpret: (long double) aValue {
150 void testGenericTaggedPointer(uint8_t tagSlot, const char *classname)
152 testprintf("%s\n", classname);
154 Class cls = objc_getClass(classname);
157 id taggedPointer = TAG_VALUE(tagSlot, 1234);
158 testassert(object_getClass(taggedPointer) == cls);
159 testassert([taggedPointer taggedValue] == 1234);
162 [taggedPointer instanceMethod];
165 struct stret orig = STRET_RESULT;
166 testassert(stret_equal(orig, [taggedPointer stret: orig]));
168 long double value = 3.14156789;
169 testassert(value == [taggedPointer fpret: value]);
171 // Tagged pointers should bypass refcount tables and autorelease pools
172 // and weak reference tables
173 WeakContainer *w = [WeakContainer new];
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);
179 id result = WEAK_STORE(w->weaks[i], o);
180 testassert(result == o);
181 testassert(w->weaks[i] == o);
183 result = WEAK_LOAD(w->weaks[i]);
184 testassert(result == o);
186 if (!objc_collectingEnabled()) {
187 uintptr_t rc = _objc_rootRetainCount(o);
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);
207 testassert(_objc_rootRetainCount(o) == rc);
208 _objc_rootAutorelease(o);
209 testassert(_objc_rootRetainCount(o) == rc);
210 #if !__has_feature(objc_arc)
212 testassert(_objc_rootRetainCount(o) == rc);
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);
225 testassert(_objc_rootRetainCount(o) == rc);
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);
241 _objc_insert_tagged_isa(5, objc_getClass("TaggedBaseClass"));
242 testGenericTaggedPointer(5, "TaggedBaseClass");
244 _objc_insert_tagged_isa(2, objc_getClass("TaggedSubclass"));
245 testGenericTaggedPointer(2, "TaggedSubclass");
247 _objc_insert_tagged_isa(3, objc_getClass("TaggedNSObjectSubclass"));
248 testGenericTaggedPointer(3, "TaggedNSObjectSubclass");
256 // not (OBJC2 && __LP64__)
258 // Tagged pointers not supported.