ObjFW  Check-in [b0594b769c]

Overview
Comment:runtime: Fix associated objects
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: b0594b769ce2c4daa60a0cbeaa60d48fcc60b946ec598cae68e8c277d6be1f70
User & Date: js on 2024-02-20 22:22:59
Other Links: manifest | tags
Context
2024-02-21
21:36
Document ObjFWTest check-in: 3c55b7ac50 user: js tags: trunk
2024-02-20
22:22
runtime: Fix associated objects check-in: b0594b769c user: js tags: trunk
22:07
OFKernelEventObserverTests: Fix missing release check-in: 89b96428b9 user: js tags: trunk
Changes

Modified src/runtime/association.m from [b558229b1e] to [b59c5c9746].

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
}