1/* 2 * Copyright (c) 2009 Apple Inc. All rights reserved. 3 * 4 * @APPLE_APACHE_LICENSE_HEADER_START@ 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 * 18 * @APPLE_APACHE_LICENSE_HEADER_END@ 19 */ 20// 21// cfdata.m 22// gctests 23// 24// Created by Blaine Garst on 11/13/08. 25// Copyright 2008 Apple. All rights reserved. 26// 27 28// CONFIG GC -C99 29 30 31#import <Foundation/Foundation.h> 32#import <CoreFoundation/CFData.h> 33#include <malloc/malloc.h> 34 35 36@interface TestObject : NSObject { 37 __strong CFDataRef subject; 38 __strong CFMutableDataRef mutableSubject; 39 40 __strong CFDataRef subjectCopy; 41 __strong CFMutableDataRef mutableSubjectCopy; 42 43 __strong CFMutableDataRef subjectMutableCopy; 44 __strong CFMutableDataRef mutableSubjectMutableCopy; 45 46} 47 48- init; 49 50@end 51 52@interface TestTestObject : TestObject { 53 bool shouldDealloc; 54 __strong void *backingData; 55} 56@end 57 58 59@implementation TestObject 60- (void) makeCopies { 61 CFIndex size = 32*sizeof(void *); 62 subjectCopy = CFDataCreateCopy(NULL, subject); 63 mutableSubjectCopy = CFDataCreateMutableCopy(NULL, size, mutableSubject); 64 65 subjectMutableCopy = CFDataCreateMutableCopy(NULL, size, subject); 66 mutableSubjectMutableCopy = CFDataCreateMutableCopy(NULL, size, mutableSubject); 67} 68 69- (void)makeCollectable { 70 CFMakeCollectable(subjectCopy); 71 CFMakeCollectable(mutableSubjectCopy); 72 CFMakeCollectable(subjectMutableCopy); 73 CFMakeCollectable(mutableSubjectMutableCopy); 74 CFMakeCollectable(subject); 75 CFMakeCollectable(mutableSubject); 76} 77 78- (void)grow { 79 CFIndex size = 32*sizeof(void *); 80 CFDataSetLength(mutableSubjectCopy, 2*size); 81 CFDataSetLength(subjectMutableCopy, 2*size); 82 CFDataSetLength(mutableSubjectMutableCopy, 2*size); 83 CFDataSetLength(mutableSubject, 2*size); 84} 85 86- (void)dealloc { 87 CFRelease(subjectCopy); 88 CFRelease(mutableSubjectCopy); 89 CFRelease(subjectMutableCopy); 90 CFRelease(mutableSubjectMutableCopy); 91 CFRelease(subject); 92 CFRelease(mutableSubject); 93 [super dealloc]; 94} 95 96- init { 97 id buffer[32]; 98 for (int i = 0; i < 32; ++i) 99 buffer[i] = self; 100 CFIndex size = sizeof(void *)*32; 101 if (!subject) subject = CFDataCreate(NULL, (uint8_t *)buffer, size); 102 mutableSubject = CFDataCreateMutable(NULL, size); 103 const UInt8 *bytes = CFDataGetBytePtr((CFMutableDataRef)mutableSubject); 104 memcpy((void *)bytes, buffer, size); 105 106 [self makeCopies]; 107 [self makeCollectable]; 108 [self grow]; 109 return self; 110} 111 112 113bool allSame(void *value, void **items, int nitems) { 114 for (int i = 0; i < nitems; ++i) 115 if (items[i] != value) return false; 116 return true; 117} 118 119- (void)test { 120 bool result = true; 121 CFIndex count = CFDataGetLength(subject)/sizeof(void *); 122 result = result && allSame(self, (void **)CFDataGetBytePtr(subject), count); 123 result = result && allSame(self, (void **)CFDataGetBytePtr(mutableSubject), count); 124 result = result && allSame(self, (void **)CFDataGetBytePtr(subjectCopy), count); 125 result = result && allSame(self, (void **)CFDataGetBytePtr(mutableSubjectCopy), count); 126 result = result && allSame(self, (void **)CFDataGetBytePtr(subjectMutableCopy), count); 127 result = result && allSame(self, (void **)CFDataGetBytePtr(mutableSubjectMutableCopy), count); 128 if (!result) { 129 printf("Data changed!\n"); 130 exit(1); 131 } 132} 133 134@end 135 136@implementation TestTestObject 137 138- (void)allocateBacking:(CFIndex)size { 139 backingData = malloc_zone_malloc((malloc_zone_t*)NSDefaultMallocZone(), size); 140} 141 142- init { 143 id buffer[32]; 144 for (int i = 0; i < 32; ++i) 145 buffer[i] = self; 146 CFIndex size = sizeof(void *)*32; 147 [self allocateBacking:size]; 148 149 memcpy(backingData, buffer, size); 150 subject = CFDataCreateWithBytesNoCopy(NULL, (const UInt8*)backingData, size, NULL); 151 //if ([NSGarbageCollector defaultCollector]) printf("backing data %p held by %p\n", backingData, subject); 152 return [super init]; 153} 154- initExplicit { 155 id buffer[32]; 156 for (int i = 0; i < 32; ++i) 157 buffer[i] = self; 158 CFIndex size = sizeof(void *)*32; 159 [self allocateBacking:size]; 160 memcpy(backingData, buffer, size); 161 // explicitly use kCFAllocatorDefault 162 subject = CFDataCreateWithBytesNoCopy(NULL, (const UInt8*)backingData, size, kCFAllocatorDefault); 163 //if ([NSGarbageCollector defaultCollector]) printf("backing data %p held by %p\n", backingData, subject); 164 return [super init]; 165} 166- initOwned { 167 id buffer[32]; 168 for (int i = 0; i < 32; ++i) 169 buffer[i] = self; 170 CFIndex size = sizeof(void *)*32; 171 [self allocateBacking:size]; 172 memcpy(backingData, buffer, size); 173 // explicitly use kCFAllocatorNull to say that the memory is owned elsewhere 174 subject = CFDataCreateWithBytesNoCopy(NULL, (const UInt8*)backingData, size, kCFAllocatorNull); 175 shouldDealloc = true; 176 //if ([NSGarbageCollector defaultCollector]) printf("backing data %p held by %p, will dealloc\n", backingData, subject); 177 return [super init]; 178} 179- (void) dealloc { 180 if (shouldDealloc) free(backingData); 181 [super dealloc]; 182} 183- (void) finalize { 184 if (shouldDealloc) free(backingData); 185 [super finalize]; 186} 187@end 188 189#define LOOPS 100 190 191void testLoop() { 192 NSMutableArray *array = [[NSMutableArray alloc] init]; 193 194 for (int i = 0; i < LOOPS; ++i) { 195 TestObject *to = [[TestObject alloc] init]; 196 [array addObject:to]; 197 [to release]; 198 } 199 for (int i = 0; i < LOOPS; ++i) { 200 TestTestObject *to = [[TestTestObject alloc] init]; 201 [array addObject:to]; 202 [to release]; 203 } 204 205 for (int i = 0; i < LOOPS; ++i) { 206 TestTestObject *to = [[TestTestObject alloc] initExplicit]; 207 [array addObject:to]; 208 [to release]; 209 } 210 211 for (int i = 0; i < LOOPS; ++i) { 212 TestTestObject *to = [[TestTestObject alloc] initOwned]; 213 [array addObject:to]; 214 [to release]; 215 } 216 217 [array release]; 218 NSGarbageCollector *collector = [NSGarbageCollector defaultCollector]; 219 [collector collectIfNeeded]; 220 [collector collectExhaustively]; 221} 222 223 224int main(int argc, char *argv[]) { 225 NSAutoreleasePool *pool = [NSAutoreleasePool new]; 226 for (int i = 0; i < (1+LOOPS); ++i) { // just enough for GC to not find things on the stack 227 testLoop(); 228 //printf("iteration %d done\n", i); 229 } 230 [pool drain]; 231 printf("%s: Success\n", argv[0]); 232 return 0; 233} 234