Skip to content

Commit bc87ed2

Browse files
author
theraven
committed
Implemented support for __weak with ARC.
ARC functions are all now exposed in a header, but not yet documented. See the ARC ABI spec for now: http://clang.llvm.org/docs/AutomaticReferenceCounting.html#runtime
1 parent 065531b commit bc87ed2

File tree

9 files changed

+230
-4
lines changed

9 files changed

+230
-4
lines changed

GNUmakefile

+1
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ ${LIBOBJC}_HEADER_FILES = \
7272
slot.h\
7373
objc.h\
7474
objc-api.h\
75+
objc-arc.h\
7576
objc-auto.h\
7677
toydispatch.h
7778
endif

arc.m

+182
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
#import "objc/blocks_runtime.h"
33
#import "nsobject.h"
44
#import "selector.h"
5+
#import "visibility.h"
6+
#import "objc/hooks.h"
7+
#import "objc/objc-arc.h"
58

69
static Class AutoreleasePool;
710
static IMP NewAutoreleasePool;
@@ -80,3 +83,182 @@ id objc_storeStrong(id *object, id value)
8083
[oldValue release];
8184
return value;
8285
}
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+
}

caps.c

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ static const int32_t caps =
1414
(1<<OBJC_CAP_NONFRAGILE_IVARS) |
1515
(1<<OBJC_DEVELOPER_MODE) |
1616
(1<<OBJC_CAP_REGISTERED_COMPATIBILITY_ALIASES) |
17+
(1<<OBJC_CAP_ARC) |
1718
#ifndef NO_OBJCXX
1819
(1<<OBJC_UNIFIED_EXCEPTION_MODEL) |
1920
#endif

hash_table.h

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <unistd.h>
2222
#include <string.h>
2323
#include <stdio.h>
24+
#include <stdlib.h>
2425

2526

2627
#ifdef ENABLE_GC

loader.c

+5-3
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,13 @@
1515
PRIVATE mutex_t runtime_mutex;
1616
LEGACY void *__objc_runtime_mutex = &runtime_mutex;
1717

18-
void init_selector_tables(void);
19-
void init_protocol_table(void);
18+
void init_alias_table(void);
19+
void init_arc(void);
2020
void init_class_tables(void);
2121
void init_dispatch_tables(void);
22-
void init_alias_table(void);
2322
void init_gc(void);
23+
void init_protocol_table(void);
24+
void init_selector_tables(void);
2425
void objc_send_load_message(Class class);
2526

2627
/* Number of threads that are alive. */
@@ -57,6 +58,7 @@ void __objc_exec_class(struct objc_module_abi_8 *module)
5758
init_class_tables();
5859
init_dispatch_tables();
5960
init_alias_table();
61+
init_arc();
6062
first_run = NO;
6163
}
6264

objc/capabilities.h

+5
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,11 @@ extern "C" {
8080
* alias as the argument.
8181
*/
8282
#define OBJC_CAP_REGISTERED_COMPATIBILITY_ALIASES 10
83+
/**
84+
* The runtime supports automatic reference counting, including support for
85+
* __weak references.
86+
*/
87+
#define OBJC_CAP_ARC 11
8388

8489
/**
8590
* Macro used to require the existence of a specific capability. This creates

objc/hooks.h

+8
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,11 @@ OBJC_HOOK Class (*_objc_class_for_boxing_foreign_exception)(int64_t exceptionCla
6464
*/
6565
extern struct objc_slot* (*_objc_selector_type_mismatch)(Class cls,
6666
SEL selector, struct objc_slot *result);
67+
68+
/**
69+
* Returns the object if it is not currently in the process of being
70+
* deallocated. Returns nil otherwise.
71+
*
72+
* This hook must be set for weak references to work with automatic reference counting.
73+
*/
74+
OBJC_HOOK id (*_objc_weak_load)(id object);

objc/objc-arc.h

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
id objc_autorelease(id obj);
2+
id objc_autoreleaseReturnValue(id obj);
3+
id objc_initWeak(id *object, id value);
4+
id objc_loadWeak(id* object);
5+
id objc_loadWeakRetained(id* obj);
6+
id objc_retain(id obj);
7+
id objc_retainAutorelease(id obj);
8+
id objc_retainAutoreleaseReturnValue(id obj);
9+
id objc_retainAutoreleasedReturnValue(id obj);
10+
id objc_retainBlock(id b);
11+
id objc_storeStrong(id *object, id value);
12+
id objc_storeWeak(id *addr, id obj);
13+
void *objc_autoreleasePoolPush(void);
14+
void objc_autoreleasePoolPop(void *pool);
15+
void objc_copyWeak(id *dest, id *src);
16+
void objc_destroyWeak(id* obj);
17+
void objc_moveWeak(id *dest, id *src);
18+
void objc_release(id obj);
19+
/**
20+
* Mark the object as about to begin deallocation. All subsequent reads of
21+
* weak pointers will return 0. This function should be called in -release,
22+
* before calling [self dealloc].
23+
*
24+
* Nonstandard extension.
25+
*/
26+
void objc_delete_weak_refs(id obj);

string_hash.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
__attribute__((unused))
88
static uint32_t string_hash(const char *str)
99
{
10-
uint32_t hash = 33;
10+
uint32_t hash = 0;
1111
int32_t c;
1212
while ((c = *str++))
1313
{

0 commit comments

Comments
 (0)