|
2 | 2 | #import "objc/blocks_runtime.h"
|
3 | 3 | #import "nsobject.h"
|
4 | 4 | #import "selector.h"
|
| 5 | +#import "visibility.h" |
| 6 | +#import "objc/hooks.h" |
| 7 | +#import "objc/objc-arc.h" |
5 | 8 |
|
6 | 9 | static Class AutoreleasePool;
|
7 | 10 | static IMP NewAutoreleasePool;
|
@@ -80,3 +83,182 @@ id objc_storeStrong(id *object, id value)
|
80 | 83 | [oldValue release];
|
81 | 84 | return value;
|
82 | 85 | }
|
| 86 | + |
| 87 | +//////////////////////////////////////////////////////////////////////////////// |
| 88 | +// Weak references |
| 89 | +//////////////////////////////////////////////////////////////////////////////// |
| 90 | + |
| 91 | +typedef struct objc_weak_ref |
| 92 | +{ |
| 93 | + id obj; |
| 94 | + id *ref[4]; |
| 95 | + struct objc_weak_ref *next; |
| 96 | +} WeakRef; |
| 97 | + |
| 98 | + |
| 99 | +static int weak_ref_compare(const id obj, const WeakRef weak_ref) |
| 100 | +{ |
| 101 | + return obj == weak_ref.obj; |
| 102 | +} |
| 103 | + |
| 104 | +static uint32_t ptr_hash(const void *ptr) |
| 105 | +{ |
| 106 | + // Bit-rotate right 4, since the lowest few bits in an object pointer will |
| 107 | + // always be 0, which is not so useful for a hash value |
| 108 | + return ((uintptr_t)ptr >> 4) | ((uintptr_t)ptr << ((sizeof(id) * 8) - 4)); |
| 109 | +} |
| 110 | +static int weak_ref_hash(const WeakRef weak_ref) |
| 111 | +{ |
| 112 | + return ptr_hash(weak_ref.obj); |
| 113 | +} |
| 114 | +static int weak_ref_is_null(const WeakRef weak_ref) |
| 115 | +{ |
| 116 | + return weak_ref.obj == NULL; |
| 117 | +} |
| 118 | +const static WeakRef NullWeakRef; |
| 119 | +#define MAP_TABLE_NAME weak_ref |
| 120 | +#define MAP_TABLE_COMPARE_FUNCTION weak_ref_compare |
| 121 | +#define MAP_TABLE_HASH_KEY ptr_hash |
| 122 | +#define MAP_TABLE_HASH_VALUE weak_ref_hash |
| 123 | +#define MAP_TABLE_HASH_VALUE weak_ref_hash |
| 124 | +#define MAP_TABLE_VALUE_TYPE struct objc_weak_ref |
| 125 | +#define MAP_TABLE_VALUE_NULL weak_ref_is_null |
| 126 | +#define MAP_TABLE_VALUE_PLACEHOLDER NullWeakRef |
| 127 | +#define MAP_TABLE_ACCESS_BY_REFERENCE 1 |
| 128 | +#define MAP_TABLE_SINGLE_THREAD 1 |
| 129 | +#define MAP_TABLE_NO_LOCK 1 |
| 130 | + |
| 131 | +#include "hash_table.h" |
| 132 | + |
| 133 | +static weak_ref_table *weakRefs; |
| 134 | +mutex_t weakRefLock; |
| 135 | + |
| 136 | +PRIVATE void init_arc(void) |
| 137 | +{ |
| 138 | + weak_ref_initialize(&weakRefs, 128); |
| 139 | + INIT_LOCK(weakRefLock); |
| 140 | +} |
| 141 | + |
| 142 | +id objc_storeWeak(id *addr, id obj) |
| 143 | +{ |
| 144 | + id old = *addr; |
| 145 | + LOCK_FOR_SCOPE(&weakRefLock); |
| 146 | + WeakRef *oldRef = weak_ref_table_get(weakRefs, old); |
| 147 | + while (NULL != oldRef) |
| 148 | + { |
| 149 | + for (int i=0 ; i<4 ; i++) |
| 150 | + { |
| 151 | + if (oldRef->ref[i] == addr) |
| 152 | + { |
| 153 | + oldRef->ref[i] = 0; |
| 154 | + oldRef = 0; |
| 155 | + break; |
| 156 | + } |
| 157 | + } |
| 158 | + } |
| 159 | + if (nil == obj) |
| 160 | + { |
| 161 | + *addr = obj; |
| 162 | + return nil; |
| 163 | + } |
| 164 | + obj = _objc_weak_load(obj); |
| 165 | + if (nil != obj) |
| 166 | + { |
| 167 | + WeakRef *ref = weak_ref_table_get(weakRefs, obj); |
| 168 | + while (NULL != ref) |
| 169 | + { |
| 170 | + for (int i=0 ; i<4 ; i++) |
| 171 | + { |
| 172 | + if (0 == ref->ref[i]) |
| 173 | + { |
| 174 | + ref->ref[i] = addr; |
| 175 | + return obj; |
| 176 | + } |
| 177 | + } |
| 178 | + if (ref->next == NULL) |
| 179 | + { |
| 180 | + break; |
| 181 | + } |
| 182 | + } |
| 183 | + if (NULL != ref) |
| 184 | + { |
| 185 | + ref->next = calloc(sizeof(WeakRef), 1); |
| 186 | + ref->next->ref[0] = addr; |
| 187 | + } |
| 188 | + else |
| 189 | + { |
| 190 | + WeakRef newRef = {0}; |
| 191 | + newRef.obj = obj; |
| 192 | + newRef.ref[0] = addr; |
| 193 | + weak_ref_insert(weakRefs, newRef); |
| 194 | + } |
| 195 | + } |
| 196 | + return obj; |
| 197 | +} |
| 198 | + |
| 199 | +static void zeroRefs(WeakRef *ref, BOOL shouldFree) |
| 200 | +{ |
| 201 | + if (NULL != ref->next) |
| 202 | + { |
| 203 | + zeroRefs(ref->next, YES); |
| 204 | + } |
| 205 | + for (int i=0 ; i<4 ; i++) |
| 206 | + { |
| 207 | + if (0 != ref->ref[i]) |
| 208 | + { |
| 209 | + *ref->ref[i] = 0; |
| 210 | + } |
| 211 | + } |
| 212 | + if (shouldFree) |
| 213 | + { |
| 214 | + free(ref); |
| 215 | + } |
| 216 | + else |
| 217 | + { |
| 218 | + memset(ref, 0, sizeof(WeakRef)); |
| 219 | + } |
| 220 | +} |
| 221 | + |
| 222 | +void objc_delete_weak_refs(id obj) |
| 223 | +{ |
| 224 | + LOCK_FOR_SCOPE(&weakRefLock); |
| 225 | + WeakRef *oldRef = weak_ref_table_get(weakRefs, obj); |
| 226 | + if (0 != oldRef) |
| 227 | + { |
| 228 | + zeroRefs(oldRef, NO); |
| 229 | + } |
| 230 | +} |
| 231 | + |
| 232 | +id objc_loadWeakRetained(id* obj) |
| 233 | +{ |
| 234 | + LOCK_FOR_SCOPE(&weakRefLock); |
| 235 | + return objc_retain(*obj); |
| 236 | +} |
| 237 | + |
| 238 | +id objc_loadWeak(id* object) |
| 239 | +{ |
| 240 | + return objc_autorelease(objc_loadWeakRetained(object)); |
| 241 | +} |
| 242 | + |
| 243 | +void objc_copyWeak(id *dest, id *src) |
| 244 | +{ |
| 245 | + objc_release(objc_initWeak(dest, objc_loadWeakRetained(src))); |
| 246 | +} |
| 247 | + |
| 248 | +void objc_moveWeak(id *dest, id *src) |
| 249 | +{ |
| 250 | + // FIXME: src can be zero'd here, removing the relationship between the |
| 251 | + // object and the pointer, which can be cheaper. |
| 252 | + objc_moveWeak(dest, src); |
| 253 | +} |
| 254 | + |
| 255 | +void objc_destroyWeak(id* obj) |
| 256 | +{ |
| 257 | + objc_storeWeak(obj, nil); |
| 258 | +} |
| 259 | + |
| 260 | +id objc_initWeak(id *object, id value) |
| 261 | +{ |
| 262 | + *object = nil; |
| 263 | + return objc_storeWeak(object, value); |
| 264 | +} |
0 commit comments