1// TEST_CONFIG 2 3#include "test.h" 4#include <objc/runtime.h> 5#include <objc/objc-internal.h> 6#include <objc/objc-gdb.h> 7#include <dlfcn.h> 8#import <Foundation/NSObject.h> 9 10#if OBJC_HAVE_TAGGED_POINTERS 11 12#if !__OBJC2__ || !__x86_64__ 13#error wrong architecture for tagged pointers 14#endif 15 16static BOOL didIt; 17 18@interface WeakContainer : NSObject 19{ 20 @public 21 __weak id weaks[10000]; 22} 23@end 24@implementation WeakContainer 25-(void) dealloc { 26 for (unsigned int i = 0; i < sizeof(weaks)/sizeof(weaks[0]); i++) { 27 testassert(weaks[i] == nil); 28 } 29 SUPER_DEALLOC(); 30} 31-(void) finalize { 32 for (unsigned int i = 0; i < sizeof(weaks)/sizeof(weaks[0]); i++) { 33 testassert(weaks[i] == nil); 34 } 35 [super finalize]; 36} 37@end 38 39OBJC_ROOT_CLASS 40@interface TaggedBaseClass 41@end 42 43@implementation TaggedBaseClass 44+ (void) initialize { 45} 46 47- (void) instanceMethod { 48 didIt = YES; 49} 50 51- (uintptr_t) taggedValue { 52 return _objc_getTaggedPointerValue(objc_unretainedPointer(self)); 53} 54 55- (struct stret) stret: (struct stret) aStruct { 56 return aStruct; 57} 58 59- (long double) fpret: (long double) aValue { 60 return aValue; 61} 62 63 64-(void) dealloc { 65 fail("TaggedBaseClass dealloc called!"); 66} 67 68static void * 69retain_fn(void *self, SEL _cmd __unused) { 70 void * (*fn)(void *) = (typeof(fn))_objc_rootRetain; 71 return fn(self); 72} 73 74static void 75release_fn(void *self, SEL _cmd __unused) { 76 void (*fn)(void *) = (typeof(fn))_objc_rootRelease; 77 fn(self); 78} 79 80static void * 81autorelease_fn(void *self, SEL _cmd __unused) { 82 void * (*fn)(void *) = (typeof(fn))_objc_rootAutorelease; 83 return fn(self); 84} 85 86static unsigned long 87retaincount_fn(void *self, SEL _cmd __unused) { 88 unsigned long (*fn)(void *) = (typeof(fn))_objc_rootRetainCount; 89 return fn(self); 90} 91 92+(void) load { 93 class_addMethod(self, sel_registerName("retain"), (IMP)retain_fn, ""); 94 class_addMethod(self, sel_registerName("release"), (IMP)release_fn, ""); 95 class_addMethod(self, sel_registerName("autorelease"), (IMP)autorelease_fn, ""); 96 class_addMethod(self, sel_registerName("retainCount"), (IMP)retaincount_fn, ""); 97} 98 99@end 100 101@interface TaggedSubclass: TaggedBaseClass 102@end 103 104@implementation TaggedSubclass 105 106- (void) instanceMethod { 107 return [super instanceMethod]; 108} 109 110- (uintptr_t) taggedValue { 111 return [super taggedValue]; 112} 113 114- (struct stret) stret: (struct stret) aStruct { 115 return [super stret: aStruct]; 116} 117 118- (long double) fpret: (long double) aValue { 119 return [super fpret: aValue]; 120} 121@end 122 123@interface TaggedNSObjectSubclass : NSObject 124@end 125 126@implementation TaggedNSObjectSubclass 127 128- (void) instanceMethod { 129 didIt = YES; 130} 131 132- (uintptr_t) taggedValue { 133 return _objc_getTaggedPointerValue(objc_unretainedPointer(self)); 134} 135 136- (struct stret) stret: (struct stret) aStruct { 137 return aStruct; 138} 139 140- (long double) fpret: (long double) aValue { 141 return aValue; 142} 143@end 144 145void testGenericTaggedPointer(objc_tag_index_t tag, const char *classname) 146{ 147 testprintf("%s\n", classname); 148 149 Class cls = objc_getClass(classname); 150 testassert(cls); 151 152 void *taggedAddress = _objc_makeTaggedPointer(tag, 1234); 153 testassert(_objc_isTaggedPointer(taggedAddress)); 154 testassert(_objc_getTaggedPointerTag(taggedAddress) == tag); 155 testassert(_objc_getTaggedPointerValue(taggedAddress) == 1234); 156 157 testassert((uintptr_t)taggedAddress & objc_debug_taggedpointer_mask); 158 uintptr_t slot = ((uintptr_t)taggedAddress >> objc_debug_taggedpointer_slot_shift) & objc_debug_taggedpointer_slot_mask; 159 testassert(objc_debug_taggedpointer_classes[slot] == cls); 160 testassert((((uintptr_t)taggedAddress << objc_debug_taggedpointer_payload_lshift) >> objc_debug_taggedpointer_payload_rshift) == 1234); 161 162 id taggedPointer = objc_unretainedObject(taggedAddress); 163 testassert(object_getClass(taggedPointer) == cls); 164 testassert([taggedPointer taggedValue] == 1234); 165 166 didIt = NO; 167 [taggedPointer instanceMethod]; 168 testassert(didIt); 169 170 struct stret orig = STRET_RESULT; 171 testassert(stret_equal(orig, [taggedPointer stret: orig])); 172 173 long double value = 3.14156789; 174 testassert(value == [taggedPointer fpret: value]); 175 176 // Tagged pointers should bypass refcount tables and autorelease pools 177 // and weak reference tables 178 WeakContainer *w = [WeakContainer new]; 179#if !__has_feature(objc_arc) 180 // prime method caches before leak checking 181 [taggedPointer retain]; 182 [taggedPointer release]; 183 [taggedPointer autorelease]; 184#endif 185 leak_mark(); 186 for (uintptr_t i = 0; i < sizeof(w->weaks)/sizeof(w->weaks[0]); i++) { 187 id o = objc_unretainedObject(_objc_makeTaggedPointer(tag, i)); 188 testassert(object_getClass(o) == cls); 189 190 id result = WEAK_STORE(w->weaks[i], o); 191 testassert(result == o); 192 testassert(w->weaks[i] == o); 193 194 result = WEAK_LOAD(w->weaks[i]); 195 testassert(result == o); 196 197 if (!objc_collectingEnabled()) { 198 uintptr_t rc = _objc_rootRetainCount(o); 199 testassert(rc != 0); 200 _objc_rootRelease(o); testassert(_objc_rootRetainCount(o) == rc); 201 _objc_rootRelease(o); testassert(_objc_rootRetainCount(o) == rc); 202 _objc_rootRetain(o); testassert(_objc_rootRetainCount(o) == rc); 203 _objc_rootRetain(o); testassert(_objc_rootRetainCount(o) == rc); 204 _objc_rootRetain(o); testassert(_objc_rootRetainCount(o) == rc); 205#if !__has_feature(objc_arc) 206 [o release]; testassert(_objc_rootRetainCount(o) == rc); 207 [o release]; testassert(_objc_rootRetainCount(o) == rc); 208 [o retain]; testassert(_objc_rootRetainCount(o) == rc); 209 [o retain]; testassert(_objc_rootRetainCount(o) == rc); 210 [o retain]; testassert(_objc_rootRetainCount(o) == rc); 211 objc_release(o); testassert(_objc_rootRetainCount(o) == rc); 212 objc_release(o); testassert(_objc_rootRetainCount(o) == rc); 213 objc_retain(o); testassert(_objc_rootRetainCount(o) == rc); 214 objc_retain(o); testassert(_objc_rootRetainCount(o) == rc); 215 objc_retain(o); testassert(_objc_rootRetainCount(o) == rc); 216#endif 217 PUSH_POOL { 218 testassert(_objc_rootRetainCount(o) == rc); 219 _objc_rootAutorelease(o); 220 testassert(_objc_rootRetainCount(o) == rc); 221#if !__has_feature(objc_arc) 222 [o autorelease]; 223 testassert(_objc_rootRetainCount(o) == rc); 224 objc_autorelease(o); 225 testassert(_objc_rootRetainCount(o) == rc); 226 objc_retainAutorelease(o); 227 testassert(_objc_rootRetainCount(o) == rc); 228 objc_autoreleaseReturnValue(o); 229 testassert(_objc_rootRetainCount(o) == rc); 230 objc_retainAutoreleaseReturnValue(o); 231 testassert(_objc_rootRetainCount(o) == rc); 232 objc_retainAutoreleasedReturnValue(o); 233 testassert(_objc_rootRetainCount(o) == rc); 234#endif 235 } POP_POOL; 236 testassert(_objc_rootRetainCount(o) == rc); 237 } 238 } 239 leak_check(0); 240 for (uintptr_t i = 0; i < 10000; i++) { 241 testassert(w->weaks[i] != NULL); 242 WEAK_STORE(w->weaks[i], NULL); 243 testassert(w->weaks[i] == NULL); 244 testassert(WEAK_LOAD(w->weaks[i]) == NULL); 245 } 246 RELEASE_VAR(w); 247} 248 249int main() 250{ 251 testassert(objc_debug_taggedpointer_mask != 0); 252 testassert(_objc_taggedPointersEnabled()); 253 254 PUSH_POOL { 255 // Avoid CF's tagged pointer tags because of rdar://11368528 256 257 _objc_registerTaggedPointerClass(OBJC_TAG_1, 258 objc_getClass("TaggedBaseClass")); 259 testGenericTaggedPointer(OBJC_TAG_1, 260 "TaggedBaseClass"); 261 262 _objc_registerTaggedPointerClass(OBJC_TAG_7, 263 objc_getClass("TaggedSubclass")); 264 testGenericTaggedPointer(OBJC_TAG_7, 265 "TaggedSubclass"); 266 267 _objc_registerTaggedPointerClass(OBJC_TAG_NSManagedObjectID, 268 objc_getClass("TaggedNSObjectSubclass")); 269 testGenericTaggedPointer(OBJC_TAG_NSManagedObjectID, 270 "TaggedNSObjectSubclass"); 271 } POP_POOL; 272 273 succeed(__FILE__); 274} 275 276// OBJC_HAVE_TAGGED_POINTERS 277#else 278// not OBJC_HAVE_TAGGED_POINTERS 279 280// Tagged pointers not supported. 281 282int main() 283{ 284#if __OBJC2__ 285 testassert(objc_debug_taggedpointer_mask == 0); 286 testassert(!_objc_taggedPointersEnabled()); 287#else 288 testassert(!dlsym(RTLD_DEFAULT, "objc_debug_taggedpointer_mask")); 289#endif 290 291 succeed(__FILE__); 292} 293 294#endif 295