14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
*/
#include "config.h"
#import "ObjFWRT.h"
#import "private.h"
#ifdef OF_HAVE_THREADS
# import "OFPlainMutex.h"
# define numSpinlocks 8 /* needs to be a power of 2 */
static OFSpinlock spinlocks[numSpinlocks];
static OF_INLINE size_t
spinlockSlot(id object)
{
return ((size_t)((uintptr_t)object >> 4) & (numSpinlocks - 1));
}
#endif
struct Association {
id object;
objc_associationPolicy policy;
};
static struct objc_hashtable *hashtable;
static uint32_t
hash(const void *object)
{
return (uint32_t)(uintptr_t)object;
}
static bool
equal(const void *object1, const void *object2)
{
return (object1 == object2);
}
OF_CONSTRUCTOR()
{
hashtable = objc_hashtable_new(hash, equal, 2);
#ifdef OF_HAVE_THREADS
for (size_t i = 0; i < numSpinlocks; i++)
if (OFSpinlockNew(&spinlocks[i]) != 0)
OBJC_ERROR("Failed to create spinlocks!");
#endif
}
void
objc_setAssociatedObject(id object, const void *key, id value,
objc_associationPolicy policy)
{
#ifdef OF_HAVE_THREADS
size_t slot;
#endif
switch (policy) {
case OBJC_ASSOCIATION_ASSIGN:
break;
case OBJC_ASSOCIATION_RETAIN:
case OBJC_ASSOCIATION_RETAIN_NONATOMIC:
value = [value retain];
break;
case OBJC_ASSOCIATION_COPY:
case OBJC_ASSOCIATION_COPY_NONATOMIC:
value = [value copy];
break;
default:
/* Don't know what to do, so do nothing. */
return;
}
#ifdef OF_HAVE_THREADS
slot = spinlockSlot(object);
if (OFSpinlockLock(&spinlocks[slot]) != 0)
OBJC_ERROR("Failed to lock spinlock!");
@try {
#endif
struct objc_hashtable *objectHashtable;
struct Association *association;
objectHashtable = objc_hashtable_get(hashtable, object);
if (objectHashtable == NULL) {
objectHashtable = objc_hashtable_new(hash, equal, 2);
objc_hashtable_set(hashtable, object, objectHashtable);
}
association = objc_hashtable_get(objectHashtable, key);
if (association != NULL) {
switch (association->policy) {
case OBJC_ASSOCIATION_RETAIN:
case OBJC_ASSOCIATION_RETAIN_NONATOMIC:
|
<
<
<
<
<
<
<
<
<
<
<
<
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
|
<
<
>
<
<
<
|
>
|
|
>
|
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
*/
#include "config.h"
#import "ObjFWRT.h"
#import "private.h"
struct Association {
id object;
objc_associationPolicy policy;
};
#ifdef OF_HAVE_THREADS
# define numSlots 8 /* needs to be a power of 2 */
# import "OFPlainMutex.h"
static OFSpinlock spinlocks[numSlots];
#else
# define numSlots 1
#endif
static struct objc_hashtable *hashtables[numSlots];
static OF_INLINE size_t
slotForObject(id object)
{
return ((size_t)((uintptr_t)object >> 4) & (numSlots - 1));
}
static uint32_t
hash(const void *object)
{
return (uint32_t)(uintptr_t)object;
}
static bool
equal(const void *object1, const void *object2)
{
return (object1 == object2);
}
OF_CONSTRUCTOR()
{
for (size_t i = 0; i < numSlots; i++) {
hashtables[i] = objc_hashtable_new(hash, equal, 2);
#ifdef OF_HAVE_THREADS
if (OFSpinlockNew(&spinlocks[i]) != 0)
OBJC_ERROR("Failed to create spinlocks!");
#endif
}
}
void
objc_setAssociatedObject(id object, const void *key, id value,
objc_associationPolicy policy)
{
size_t slot;
switch (policy) {
case OBJC_ASSOCIATION_ASSIGN:
break;
case OBJC_ASSOCIATION_RETAIN:
case OBJC_ASSOCIATION_RETAIN_NONATOMIC:
value = [value retain];
break;
case OBJC_ASSOCIATION_COPY:
case OBJC_ASSOCIATION_COPY_NONATOMIC:
value = [value copy];
break;
default:
/* Don't know what to do, so do nothing. */
return;
}
slot = slotForObject(object);
#ifdef OF_HAVE_THREADS
if (OFSpinlockLock(&spinlocks[slot]) != 0)
OBJC_ERROR("Failed to lock spinlock!");
@try {
#endif
struct objc_hashtable *objectHashtable;
struct Association *association;
objectHashtable = objc_hashtable_get(hashtables[slot], object);
if (objectHashtable == NULL) {
objectHashtable = objc_hashtable_new(hash, equal, 2);
objc_hashtable_set(hashtables[slot], object,
objectHashtable);
}
association = objc_hashtable_get(objectHashtable, key);
if (association != NULL) {
switch (association->policy) {
case OBJC_ASSOCIATION_RETAIN:
case OBJC_ASSOCIATION_RETAIN_NONATOMIC:
|
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
|
}
#endif
}
id
objc_getAssociatedObject(id object, const void *key)
{
#ifdef OF_HAVE_THREADS
size_t slot = spinlockSlot(object);
if (OFSpinlockLock(&spinlocks[slot]) != 0)
OBJC_ERROR("Failed to lock spinlock!");
@try {
#endif
struct objc_hashtable *objectHashtable;
struct Association *association;
objectHashtable = objc_hashtable_get(hashtable, object);
if (objectHashtable == NULL)
return nil;
association = objc_hashtable_get(objectHashtable, key);
if (association == NULL)
return nil;
|
<
|
>
|
|
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
|
}
#endif
}
id
objc_getAssociatedObject(id object, const void *key)
{
size_t slot = slotForObject(object);
#ifdef OF_HAVE_THREADS
if (OFSpinlockLock(&spinlocks[slot]) != 0)
OBJC_ERROR("Failed to lock spinlock!");
@try {
#endif
struct objc_hashtable *objectHashtable;
struct Association *association;
objectHashtable = objc_hashtable_get(hashtables[slot], object);
if (objectHashtable == NULL)
return nil;
association = objc_hashtable_get(objectHashtable, key);
if (association == NULL)
return nil;
|
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
|
}
#endif
}
void
objc_removeAssociatedObjects(id object)
{
#ifdef OF_HAVE_THREADS
size_t slot = spinlockSlot(object);
if (OFSpinlockLock(&spinlocks[slot]) != 0)
OBJC_ERROR("Failed to lock spinlock!");
@try {
#endif
struct objc_hashtable *objectHashtable;
objectHashtable = objc_hashtable_get(hashtable, object);
if (objectHashtable == NULL)
return;
for (uint32_t i = 0; i < objectHashtable->size; i++) {
struct Association *association;
if (objectHashtable->data[i] == NULL ||
|
<
|
>
|
|
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
|
}
#endif
}
void
objc_removeAssociatedObjects(id object)
{
size_t slot = slotForObject(object);
#ifdef OF_HAVE_THREADS
if (OFSpinlockLock(&spinlocks[slot]) != 0)
OBJC_ERROR("Failed to lock spinlock!");
@try {
#endif
struct objc_hashtable *objectHashtable;
objectHashtable = objc_hashtable_get(hashtables[slot], object);
if (objectHashtable == NULL)
return;
for (uint32_t i = 0; i < objectHashtable->size; i++) {
struct Association *association;
if (objectHashtable->data[i] == NULL ||
|
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
|
default:
break;
}
free(association);
}
objc_hashtable_delete(hashtable, object);
#ifdef OF_HAVE_THREADS
} @finally {
if (OFSpinlockUnlock(&spinlocks[slot]) != 0)
OBJC_ERROR("Failed to unlock spinlock!");
}
#endif
}
|
|
>
|
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
|
default:
break;
}
free(association);
}
objc_hashtable_delete(hashtables[slot], object);
objc_hashtable_free(objectHashtable);
#ifdef OF_HAVE_THREADS
} @finally {
if (OFSpinlockUnlock(&spinlocks[slot]) != 0)
OBJC_ERROR("Failed to unlock spinlock!");
}
#endif
}
|