1 #import <objc/runtime.h>
4 #import <objc/message.h>
7 typedef unsigned long objc_uinteger
;
8 typedef signed long objc_integer
;
10 typedef struct RefCountBucket
{
11 struct RefCountBucket
*next
;
18 objc_uinteger nBuckets
;
19 RefCountBucket
**buckets
;
22 static objc_lock RefCountLock
= 0;
24 static inline RefCountTable
*CreateRefCountTable() {
27 table
= malloc(sizeof(RefCountTable
));
29 table
->nBuckets
= 1024;
30 table
->buckets
= calloc(table
->nBuckets
, sizeof(RefCountBucket
*));
35 static inline RefCountBucket
*AllocBucketFromTable(RefCountTable
*table
) {
36 return malloc(sizeof(RefCountBucket
));
39 static inline void FreeBucketFromTable(RefCountTable
*table
, RefCountBucket
*bucket
) {
43 static inline objc_uinteger
hashObject(id ptr
) {
44 return (objc_uinteger
)ptr
>> 4;
47 static inline RefCountBucket
*XXHashGet(RefCountTable
*table
, id object
) {
48 objc_uinteger i
= hashObject(object
) % table
->nBuckets
;
49 RefCountBucket
*check
;
51 for(check
= table
->buckets
[i
]; check
!= NULL
; check
= check
->next
)
52 if(check
->object
== object
)
58 static inline void XXHashInsert(RefCountTable
*table
, RefCountBucket
*insert
) {
59 objc_uinteger hash
= hashObject(insert
->object
);
60 objc_uinteger i
= hash
% table
->nBuckets
;
62 if(table
->count
>= table
->nBuckets
) {
63 objc_integer oldnBuckets
= table
->nBuckets
;
64 RefCountBucket
**buckets
= table
->buckets
;
66 table
->nBuckets
= oldnBuckets
* 2;
67 table
->buckets
= calloc(table
->nBuckets
, sizeof(RefCountBucket
*));
68 for(i
= 0; i
< oldnBuckets
; i
++) {
69 RefCountBucket
*check
, *next
;
71 for(check
= buckets
[i
]; check
!= NULL
; check
= next
) {
72 objc_uinteger newi
= hashObject(check
->object
) % table
->nBuckets
;
74 check
->next
= table
->buckets
[newi
];
75 table
->buckets
[newi
] = check
;
79 i
= hash
% table
->nBuckets
;
82 insert
->next
= table
->buckets
[i
];
83 table
->buckets
[i
] = insert
;
87 static inline void XXHashRemove(RefCountTable
*table
, RefCountBucket
*remove
) {
88 objc_uinteger i
= hashObject(remove
->object
) % table
->nBuckets
;
89 RefCountBucket
*check
= table
->buckets
[i
], *prev
= check
;
91 for(; check
!= NULL
; check
= check
->next
) {
94 table
->buckets
[i
] = check
->next
;
96 prev
->next
= check
->next
;
98 FreeBucketFromTable(table
, check
);
106 static inline RefCountTable
*refTable(void) {
107 static RefCountTable
*refCountTable
= NULL
;
109 if(refCountTable
== NULL
)
110 refCountTable
= CreateRefCountTable();
112 return refCountTable
;
115 void objc_IncrementExtraRefCount(id object
) {
116 RefCountBucket
*refCount
;
117 RefCountTable
*table
= refTable();
119 objc_lock_lock(&RefCountLock
);
120 if((refCount
= XXHashGet(table
, object
)) == NULL
) {
121 refCount
= AllocBucketFromTable(table
);
122 refCount
->object
= object
;
124 XXHashInsert(refTable(), refCount
);
127 objc_lock_unlock(&RefCountLock
);
130 bool objc_DecrementExtraRefCountWasZero(id object
) {
132 RefCountBucket
*refCount
;
134 objc_lock_lock(&RefCountLock
);
135 if((refCount
= XXHashGet(refTable(), object
)) == NULL
)
139 if(refCount
->count
== 1)
140 XXHashRemove(refTable(), refCount
);
142 objc_lock_unlock(&RefCountLock
);
147 objc_uinteger
objc_ExtraRefCount(id object
) {
148 objc_uinteger result
= 1;
149 RefCountBucket
*refCount
;
151 objc_lock_lock(&RefCountLock
);
152 if((refCount
= XXHashGet(refTable(), object
)) != NULL
)
153 result
= refCount
->count
;
154 objc_lock_unlock(&RefCountLock
);
159 void object_incrementExternalRefCount(id value
) {
160 objc_IncrementExtraRefCount(value
);
163 bool object_decrementExternalRefCount(id value
) {
164 return objc_DecrementExtraRefCountWasZero(value
);
167 unsigned long object_externalRefCount(id value
) {
168 return objc_ExtraRefCount(value
);
171 id
objc_retain(id value
) {
172 objc_IncrementExtraRefCount(value
);
176 void objc_release(id value
) {
177 if(objc_DecrementExtraRefCountWasZero(value
)) {
178 static SEL selector
= NULL
;
181 selector
= sel_registerName("dealloc");
183 IMP dealloc
= objc_msg_lookup(value
, selector
);
185 dealloc(value
, selector
);
189 static objc_autoreleasepool
*objc_autoreleaseCurrentPool() {
190 return objc_tlsCurrent()->pool
;
193 static void objc_autoreleaseSetCurrentPool(objc_autoreleasepool
*pool
) {
194 objc_tlsCurrent()->pool
= pool
;
197 #define PAGESIZE 1024
199 void *objc_autoreleasePoolPush() {
200 objc_autoreleasepool
*current
= objc_autoreleaseCurrentPool();
201 objc_autoreleasepool
*pool
= malloc(sizeof(objc_autoreleasepool
));
203 pool
->_parent
= current
;
205 pool
->_pageCount
= 1;
206 pool
->_pages
= malloc(pool
->_pageCount
* sizeof(id
*));
207 pool
->_pages
[0] = malloc(PAGESIZE
* sizeof(id
));
211 current
->_childPool
= pool
;
212 pool
->_childPool
= NULL
;
214 objc_autoreleaseSetCurrentPool(pool
);
219 void objc_autoreleasePoolPop(void *poolX
) {
220 objc_autoreleasepool
*pool
= poolX
;
226 objc_autoreleasePoolPop(pool
->_childPool
);
228 for(i
= 0; i
< pool
->_nextSlot
; i
++) {
230 id object
= pool
->_pages
[i
/ PAGESIZE
][i
% PAGESIZE
];
232 objc_release(object
);
235 // NSLog("Exception while autoreleasing %@",localException);
239 for(i
= 0; i
< pool
->_pageCount
; i
++)
240 free(pool
->_pages
[i
]);
244 objc_autoreleaseSetCurrentPool(pool
->_parent
);
246 if(pool
->_parent
!= NULL
)
247 pool
->_parent
->_childPool
= NULL
;
252 void objc_autoreleaseNoPool(id object
) {
253 // NSCLog("autorelease pool is nil, leaking %x %s",object,object_getClassName(object));
256 void objc_autoreleasePoolAdd(objc_autoreleasepool
*pool
, id object
) {
257 if(pool
->_nextSlot
>= pool
->_pageCount
* PAGESIZE
) {
259 pool
->_pages
= realloc(pool
->_pages
, pool
->_pageCount
* sizeof(id
*));
260 pool
->_pages
[pool
->_pageCount
- 1] = malloc(PAGESIZE
* sizeof(id
));
263 pool
->_pages
[pool
->_nextSlot
/ PAGESIZE
][pool
->_nextSlot
% PAGESIZE
] = object
;
267 id
objc_autorelease(id object
) {
268 objc_autoreleasepool
*pool
= objc_autoreleaseCurrentPool();
271 objc_autoreleaseNoPool(object
);
275 objc_autoreleasePoolAdd(pool
, object
);