1/* 2 * Copyright (c) 2010 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LLVM_LICENSE_HEADER@ 5 */ 6 7// 8// objc.m 9// libclosure 10// 11// Created by Blaine Garst on 3/10/08. 12// Copyright 2008 __MyCompanyName__. All rights reserved. 13// 14 15#import "driver.h" 16#import <Foundation/Foundation.h> 17//#import <Foundation/NSBlock.h> 18 19@interface TestObject : NSObject { 20@public 21 int refcount; 22 id aSlot; 23} 24- (int) testVerbosely:(int)verbose; 25- (void)doesSomethingWithClosure:(void (^)(void))aClosure; 26- (void)doesSomethingElseWithClosure:(void (^)(NSObject *))aClosure; 27 28- (void)updateIvar; 29 30@end 31 32@implementation TestObject 33- (void)doesSomethingWithClosure:(void (^)(void))aClosure { } 34- (void)doesSomethingElseWithClosure:(void (^)(NSObject *))aClosure { } 35 36- (id) retain { 37 ++refcount; 38 return self; 39} 40 41- (int)retainCounter { 42 return refcount + 1; 43} 44 45- (void) release { 46 if (refcount == 0) [self dealloc]; 47 else --refcount; 48} 49 50 51- (int) testVerbosely:(int)verbose 52 { 53 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 54 int errors = 0; 55 aSlot = [[NSObject alloc] init]; 56 57 int initialRetainCounter = [self retainCounter]; 58 59 void (^myClosure)(void) = ^{ 60 printf("[aSlot retainCount] == %d\n", [aSlot retainCount]); 61 }; 62 63 64 int afterClosureRetainCounter = [self retainCounter]; 65 66 //printf("%s", _Block_dump(myClosure)); 67 68 void (^myClosureCopy)(void) = Block_copy(myClosure); 69 70 int afterClosureCopyRetainCounter = [self retainCounter]; 71 72 if (afterClosureRetainCounter > initialRetainCounter) { 73 printf("testVerbosely: after closure, retain count is %d vs before %d\n", afterClosureRetainCounter, initialRetainCounter); 74 ++errors; 75 } 76 77 if (afterClosureCopyRetainCounter <= afterClosureRetainCounter) { 78 printf("testVerbosely: closure copy did not retain interior object\n"); 79 ++errors; 80 } 81 82 [aSlot release]; 83 aSlot = nil; 84 85 if (errors == 0 && verbose) printf("testVerbosely: objc import object test success\n"); 86 [pool drain]; 87 return errors; 88 89} 90 91- (void)updateIvar { 92 void (^myClosure)(void) = ^{ id tmp = aSlot; aSlot = nil; aSlot = tmp; }; 93 //void (^myClosure2)(void) = ^{ |aSlot| id tmp = aSlot; aSlot = nil; aSlot = tmp; }; 94} 95 96@end 97 98// can a Block update an ivar 99int test_objc3(int verbose) { 100 int errors = 0; 101 TestObject *to = [[TestObject alloc] init]; 102 return 0; 103} 104 105int test_objc2(int verbose) { 106 int errors = 0; 107 TestObject *to = [[TestObject alloc] init]; 108 109 errors += [to testVerbosely:verbose]; 110 [to release]; 111 return errors; 112} 113 114// byref object 115int test_objc1_1(int verbose) { 116 int errors = 0; 117#if FULL_CLOSURES 118 TestObject *to = [[TestObject alloc] init]; 119 120 // make sure a closure with to gets it retained on a copy 121 122 int initialRetainCounter = [to retainCounter]; 123 124 void (^myClosure)(void) = ^{ | to | 125 printf("[to retainCounter] == %d\n", [to retainCounter]); 126 }; 127 128 int afterClosureRetainCounter = [to retainCounter]; 129 130 void (^myClosureCopy)(void) = Block_copy(myClosure); 131 132 int afterClosureCopyRetainCounter = [to retainCounter]; 133 134 if (afterClosureRetainCounter > initialRetainCounter) { 135 printf("after closure, retain count is %d vs before %d\n", afterClosureRetainCounter, initialRetainCounter); 136 ++errors; 137 } 138 139 if (afterClosureCopyRetainCounter <= afterClosureRetainCounter) { 140 printf("closure copy did not retain interior object\n"); 141 ++errors; 142 } 143 144 [to release]; 145 146#endif 147 return errors; 148} 149 150int test_objc1(int verbose) { 151 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 152 int errors = 0; 153 TestObject *to = [[TestObject alloc] init]; 154 155 // make sure a closure with to gets it retained on a copy 156 157 int initialRetainCounter = [to retainCounter]; 158 159 void (^myClosure)(void) = ^{ 160 printf("[to retainCounter] == %d\n", [to retainCounter]); 161 }; 162 163 int afterClosureRetainCounter = [to retainCounter]; 164 165 void (^myClosureCopy)(void) = Block_copy(myClosure); 166 167 int afterClosureCopyRetainCounter = [to retainCounter]; 168 169 if (afterClosureRetainCounter > initialRetainCounter) { 170 printf("after closure, retain count is %d vs before %d\n", afterClosureRetainCounter, initialRetainCounter); 171 ++errors; 172 } 173 174 if (afterClosureCopyRetainCounter <= afterClosureRetainCounter) { 175 printf("closure copy did not retain interior object\n"); 176 ++errors; 177 } 178 179 [to release]; 180 [pool drain]; 181 182 return errors; 183} 184 185#if 0 186const char *_Block_dump(const void *block) { 187 struct Block_basic *closure = (struct Block_basic *)block; 188 static char buffer[256], *cp = buffer; 189 if (closure == NULL) { 190 sprintf(cp, "NULL passed to _Block_dump\n"); 191 return buffer; 192 } 193 if (closure->isa == NULL) { 194 cp += sprintf(cp, "isa: NULL\n"); 195 } 196 else if (closure->isa == _NSConcreteStackBlock) { 197 cp += sprintf(cp, "isa: stack Block (%p)\n", _NSConcreteStackBlock); 198 } 199 else if (closure->isa == _NSConcreteMallocBlock) { 200 cp += sprintf(cp, "isa: malloc heap Block\n"); 201 } 202 else if (closure->isa == _NSConcreteAutoBlock) { 203 cp += sprintf(cp, "isa: GC heap Block\n"); 204 } 205 else { 206 cp += sprintf(cp, "isa: %p\n", closure->isa); 207 } 208 cp += sprintf(cp, "flags:"); 209 if (closure->Block_flags & BLOCK_NEEDS_FREE) { 210 cp += sprintf(cp, " FREEME"); 211 } 212 if (closure->Block_flags & BLOCK_HAS_COPY_DISPOSE) { 213 cp += sprintf(cp, " HASHELP"); 214 } 215 if (closure->Block_flags & BLOCK_NO_COPY) { 216 cp += sprintf(cp, " HASBYREF"); 217 } 218 if (closure->Block_flags & BLOCK_IS_GC) { 219 cp += sprintf(cp, " ISGC"); 220 } 221 cp += sprintf(cp, "\nrefcount: %d\nsize: %d\n", closure->Block_flags & 0xfff, closure->Block_size); 222 cp += sprintf(cp, "invoke: %p\n", closure->Block_invoke); 223 return buffer; 224} 225#endif 226 227int test_stackObject(int verbose) { 228printf("testing stack object\n"); 229 //makesubclasses(); 230 void (^voidvoid)(void) = ^{ printf("hellow world\n"); }; 231 //_NSMakeBlockObject((const void *)voidvoid); 232 printf("before voidvoid copy: %s", _Block_dump(voidvoid)); 233 void (^voidvoidCopy)(void) = (void (^)(void))(void *)[(id)(void *)voidvoid copy]; 234 printf("after voidvoid copy, voidvoidCopy is %s", _Block_dump(voidvoidCopy)); 235 [(id)(void *)voidvoidCopy release]; 236printf("done testing stack object\n"); 237} 238 239 240int test_objc(int verbose) { 241 int errors = 0; 242 243 errors += test_objc1_1(verbose); 244 errors += test_objc1(verbose); 245 errors += test_objc2(verbose); 246 errors += test_objc3(verbose); 247#if NEWER_OBJC 248 errors += test_stackObject(verbose); 249#endif 250 if (errors == 0 && verbose) printf("objc import object test success\n"); 251 return errors; 252} 253