ObjFW  Check-in [129f90b580]

Overview
Comment:Import and integrate ObjFW-RT.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | runtime
Files: files | file ages | folders
SHA3-256: 129f90b58058ce7d77b6b37ea493cc3949ebe245bf976ad2419155a4b6bfee20
User & Date: js on 2012-03-04 20:20:52
Other Links: branch diff | manifest | tags
Context
2012-03-04
20:24
Make Clang with -Wshorten-64-to-32 happy. check-in: 40fbc318bb user: js tags: runtime
20:20
Import and integrate ObjFW-RT. check-in: 129f90b580 user: js tags: runtime
19:42
Remove all code for the GNU runtime. check-in: 7f0b0c9811 user: js tags: runtime
Changes

Modified src/OFBlock.m from [41dec8a8ba] to [33e8ca2e9a].

20
21
22
23
24
25
26


27
28
29
30
31
32
33
#include <stdlib.h>
#include <string.h>

#include <assert.h>

#if defined(OF_APPLE_RUNTIME) && !defined(__OBJC2__)
# import <objc/runtime.h>


#endif

#import "OFBlock.h"

#import "OFAllocFailedException.h"
#import "OFInitializationFailedException.h"
#import "OFNotImplementedException.h"







>
>







20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <stdlib.h>
#include <string.h>

#include <assert.h>

#if defined(OF_APPLE_RUNTIME) && !defined(__OBJC2__)
# import <objc/runtime.h>
#elif defined(OBJFW_RUNTIME)
# import "runtime-private.h"
#endif

#import "OFBlock.h"

#import "OFAllocFailedException.h"
#import "OFInitializationFailedException.h"
#import "OFNotImplementedException.h"

Modified src/runtime/Makefile from [a23230bca1] to [6e57cb5c4b].

1
2
3
4
5













6
7
8


9
include ../../extra.mk

STATIC_PIC_LIB_NOINST = ${RUNTIME_LIB_A}
STATIC_LIB_NOINST = ${RUNTIME_A}














include ../../buildsys.mk

CPPFLAGS += -I. -I.. -I../..


LD = ${OBJC}





>
>
>
>
>
>
>
>
>
>
>
>
>



>
>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
include ../../extra.mk

STATIC_PIC_LIB_NOINST = ${RUNTIME_LIB_A}
STATIC_LIB_NOINST = ${RUNTIME_A}

SRCS = category.m		\
       class.m			\
       hashtable.m		\
       init.m			\
       lookup.m			\
       protocol.m		\
       selector.m		\
       sparsearray.m		\
       static-instances.m	\
       threading.m		\
       asm/amd64-elf/lookup.S	\
       asm/x86-elf/lookup.S

include ../../buildsys.mk

CPPFLAGS += -I. -I.. -I../..
AS = ${OBJC}
ASFLAGS = ${CPPFLAGS}
LD = ${OBJC}

Added src/runtime/asm/amd64-elf/lookup.S version [1fd16b224f].



















































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
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
/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#if defined(__x86_64__) && defined(__ELF__)

.intel_syntax noprefix
.globl objc_msg_lookup
.globl objc_msg_lookup_super

.section .text
objc_msg_lookup:
	test	rdi, rdi
	jz	ret_nil

	mov	r8, [rdi]
	mov	r8, [r8+64]

lookup:
	mov	rax, [rsi]
	movzx	ecx, ah
	movzx	edx, al
	shr	eax, 16

	mov	r8, [r8+rax*8]
	mov	r8, [r8+rcx*8]
	mov	rax, [r8+rdx*8]

	test	rax, rax
	jz	forward

	ret

forward:
	mov	rax, qword ptr objc_forward_handler@GOTPCREL[rip]
	jmp	[rax]

objc_msg_lookup_super:
	mov	rax, [rdi]
	test	rax, rax
	jz	ret_nil

	mov	r8, [rdi+8]
	mov	r8, [r8+64]
	mov	rdi, rax
	jmp	lookup

ret_nil:
	lea	rax, nil_method[rip]
	ret

nil_method:
	mov	rax, rdi
	ret

.type objc_msg_lookup, @function
.type objc_msg_lookup_super, @function
.size objc_msg_lookup, forward-objc_msg_lookup
.size objc_msg_lookup_super, ret_nil-objc_msg_lookup_super

#endif

Added src/runtime/asm/x86-elf/lookup.S version [213672a51c].



































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
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
/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#if defined(__i386__) && defined(__ELF__)

.intel_syntax noprefix
.globl objc_msg_lookup
.globl objc_msg_lookup_super

.section .text
objc_msg_lookup:
	mov	edx, [esp+4]
	test	edx, edx
	jz	ret_nil

	mov	edx, [edx]
	mov	edx, [edx+32]

lookup:
	mov	eax, [esp+8]

	movzx	ecx, byte ptr [eax+2]
	mov	edx, [edx+ecx*4]
	movzx	ecx, byte ptr [eax+1]
	mov	edx, [edx+ecx*4]
	movzx	ecx, byte ptr [eax]
	mov	eax, [edx+ecx*4]

	test	eax, eax
	jz	forward

	ret

forward:
	call	get_eip
.L1:
	add	eax, offset objc_forward_handler - offset .L1
	jmp	[eax]

objc_msg_lookup_super:
	mov	edx, [esp+4]
	cmp	dword ptr [edx], 0
	je	ret_nil

	mov	edx, [edx+4]
	mov	edx, [edx+32]
	jmp	lookup

ret_nil:
	call	get_eip
.L2:
	add	eax, offset nil_method - offset .L2
	ret

nil_method:
	mov	eax, [esp+4]
	ret

get_eip:
	mov	eax, dword ptr [esp]
	ret

.type objc_msg_lookup, @function
.type objc_msg_lookup_super, @function
.size objc_msg_lookup, forward-objc_msg_lookup
.size objc_msg_lookup_super, ret_nil-objc_msg_lookup_super

#endif

Added src/runtime/category.m version [aeaf0363b4].









































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#import "runtime.h"
#import "runtime-private.h"

static struct objc_hashtable *categories = NULL;

static void
register_selectors(struct objc_abi_category *cat)
{
	struct objc_abi_method_list *ml;
	unsigned int i;

	for (ml = cat->instance_methods; ml != NULL; ml = ml->next)
		for (i = 0; i < ml->count; i++)
			objc_register_selector(
			    (struct objc_abi_selector*)&ml->methods[i]);

	for (ml = cat->class_methods; ml != NULL; ml = ml->next)
		for (i = 0; i < ml->count; i++)
			objc_register_selector(
			    (struct objc_abi_selector*)&ml->methods[i]);
}

static void
register_category(struct objc_abi_category *cat)
{
	struct objc_abi_category **cats;
	Class cls = objc_classname_to_class(cat->class_name);

	if (categories == NULL)
		categories = objc_hashtable_alloc(2);

	cats = (struct objc_abi_category**)objc_hashtable_get(categories,
	    cat->class_name);

	if (cats != NULL) {
		struct objc_abi_category **ncats;
		size_t i;

		for (i = 0; cats[i] != NULL; i++);

		if ((ncats = realloc(cats,
		    (i + 2) * sizeof(struct objc_abi_category*))) == NULL)
			ERROR("Not enough memory for category %s of class %s!",
			    cat->category_name, cat->class_name);

		ncats[i] = cat;
		ncats[i + 1] = NULL;
		objc_hashtable_set(categories, cat->class_name, ncats);

		if (cls != Nil && cls->info & OBJC_CLASS_INFO_INITIALIZED) {
			objc_update_dtable(cls);
			objc_update_dtable(cls->isa);
		}

		return;
	}

	if ((cats = malloc(2 * sizeof(struct objc_abi_category*))) == NULL)
		ERROR("Not enough memory for category %s of class %s!\n",
		    cat->category_name, cat->class_name);

	cats[0] = cat;
	cats[1] = NULL;
	objc_hashtable_set(categories, cat->class_name, cats);

	if (cls != Nil && cls->info & OBJC_CLASS_INFO_INITIALIZED) {
		objc_update_dtable(cls);
		objc_update_dtable(cls->isa);
	}
}

void
objc_register_all_categories(struct objc_abi_symtab *symtab)
{
	struct objc_abi_category **cats;
	size_t i;

	cats = (struct objc_abi_category**)symtab->defs + symtab->cls_def_cnt;

	for (i = 0; i < symtab->cat_def_cnt; i++) {
		register_selectors(cats[i]);
		register_category(cats[i]);
	}
}

struct objc_abi_category**
objc_categories_for_class(Class cls)
{
	if (categories == NULL)
		return NULL;

	return (struct objc_abi_category**)objc_hashtable_get(categories,
	    cls->name);
}

void
objc_free_all_categories(void)
{
	uint32_t i;

	if (categories == NULL)
		return;

	for (i = 0; i <= categories->last_idx; i++)
		if (categories->data[i] != NULL)
			free((void*)categories->data[i]->obj);

	objc_hashtable_free(categories);
	categories = NULL;
}

Added src/runtime/class.m version [df2c4cfdda].



























































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
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
156
157
158
159
160
161
162
163
164
165
166
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
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <assert.h>

#import "runtime.h"
#import "runtime-private.h"

@protocol BasicClass
+ (void)load;
+ (void)initialize;
@end

static struct objc_hashtable *classes = NULL;

static void
register_class(Class cls)
{
	if (classes == NULL)
		classes = objc_hashtable_alloc(2);

	objc_hashtable_set(classes, cls->name, cls);
}

static void
register_selectors(struct objc_abi_class *cls)
{
	struct objc_abi_method_list *ml;
	unsigned int i;

	for (ml = cls->methodlist; ml != NULL; ml = ml->next)
		for (i = 0; i < ml->count; i++)
			objc_register_selector(
			    (struct objc_abi_selector*)&ml->methods[i]);
}

static BOOL
has_load(struct objc_abi_class *cls)
{
	struct objc_abi_method_list *ml;
	unsigned int i;

	for (ml = cls->methodlist; ml != NULL; ml = ml->next)
		for (i = 0; i < ml->count; i++)
			if (!strcmp(ml->methods[i].name, "load"))
				return YES;

	return NO;
}

void
objc_update_dtable(Class cls)
{
	struct objc_abi_method_list *ml;
	struct objc_abi_category **cats;
	struct objc_sparsearray *dtable;
	unsigned int i;

	if (cls->superclass != Nil)
		dtable = objc_sparsearray_copy(cls->superclass->dtable);
	else
		dtable = objc_sparsearray_new();

	for (ml = cls->methodlist; ml != NULL; ml = ml->next)
		for (i = 0; i < ml->count; i++)
			objc_sparsearray_set(dtable,
			    (uintptr_t)ml->methods[i].name, ml->methods[i].imp);

	if ((cats = objc_categories_for_class(cls)) != NULL) {
		for (i = 0; cats[i] != NULL; i++) {
			unsigned int j;

			ml = (cls->info & OBJC_CLASS_INFO_CLASS ?
			    cats[i]->instance_methods : cats[i]->class_methods);

			for (; ml != NULL; ml = ml->next)
				for (j = 0; j < ml->count; j++)
					objc_sparsearray_set(dtable,
					    (uintptr_t)ml->methods[j].name,
					    ml->methods[j].imp);
		}
	}

	if (cls->dtable != NULL)
		objc_sparsearray_free_when_singlethreaded(cls->dtable);

	cls->dtable = dtable;

	if (cls->subclass_list != NULL)
		for (i = 0; cls->subclass_list[i] != NULL; i++)
			objc_update_dtable(cls->subclass_list[i]);
}

void
objc_register_all_classes(struct objc_abi_symtab *symtab)
{
	size_t i;

	for (i = 0; i < symtab->cls_def_cnt; i++)
		register_class((Class)symtab->defs[i]);

	for (i = 0; i < symtab->cls_def_cnt; i++) {
		struct objc_abi_class *cls;
		BOOL load;

		cls = (struct objc_abi_class*)symtab->defs[i];
		load = has_load(cls->metaclass);

		register_selectors(cls);
		register_selectors(cls->metaclass);

		if (load) {
			/* Sets up the dtable */
			assert(objc_get_class(cls->name) == (Class)cls);

			[(Class)cls load];
		}
	}
}

static void
add_subclass(Class cls)
{
	size_t i;

	if (cls->superclass->subclass_list == NULL) {
		if ((cls->superclass->subclass_list =
		    malloc(2 * sizeof(Class))) == NULL)
			ERROR("Not enough memory for subclass list of "
			    "class %s!", cls->superclass->name);

		cls->superclass->subclass_list[0] = cls;
		cls->superclass->subclass_list[1] = Nil;

		return;
	}

	for (i = 0; cls->superclass->subclass_list[i] != Nil; i++);

	cls->superclass->subclass_list =
	    realloc(cls->superclass->subclass_list, (i + 2) * sizeof(Class));

	if (cls->superclass->subclass_list == NULL)
		ERROR("Not enough memory for subclass list of class %s\n",
		    cls->superclass->name);

	cls->superclass->subclass_list[i] = cls;
	cls->superclass->subclass_list[i + 1] = Nil;
}

inline Class
objc_classname_to_class(const char *name)
{
	Class c;

	if (classes == NULL)
		return Nil;

	objc_global_mutex_lock();
	c = (Class)objc_hashtable_get(classes, name);
	objc_global_mutex_unlock();

	return c;
}

inline Class
objc_lookup_class(const char *name)
{
	Class cls = objc_classname_to_class(name);
	const char *superclass;

	if (cls == NULL)
		return Nil;

	if (cls->info & OBJC_CLASS_INFO_INITIALIZED)
		return cls;

	objc_global_mutex_lock();

	/*
	 * It's possible that two threads try to get a class at the same time.
	 * Make sure that the thread which held the lock did not already
	 * initialize it.
	 */
	if (cls->info & OBJC_CLASS_INFO_INITIALIZED) {
		objc_global_mutex_unlock();
		return cls;
	}

	if ((superclass = ((struct objc_abi_class*)cls)->superclass) != NULL) {
		if ((cls->superclass = objc_lookup_class(superclass)) == Nil)
			ERROR("Class %s not found, which is the superclass for "
			    "class %s!", superclass, cls->name);

		cls->isa->superclass = cls->superclass->isa;

		add_subclass(cls);
		add_subclass(cls->isa);
	} else if ((superclass = ((struct objc_abi_class*)cls->isa)->superclass)
	    != NULL) {
		if (strcmp(superclass, name))
			abort();

		cls->isa->superclass = cls;
	}

	objc_update_dtable(cls);
	objc_update_dtable(cls->isa);

	cls->info |= OBJC_CLASS_INFO_INITIALIZED;
	cls->isa->info |= OBJC_CLASS_INFO_INITIALIZED;

	if (class_respondsToSelector(cls->isa, @selector(initialize)))
		[cls initialize];

	objc_global_mutex_unlock();

	return cls;
}

Class
objc_get_class(const char *name)
{
	Class cls;

	if ((cls = objc_lookup_class(name)) == Nil)
		ERROR("Class %s not found!", name);

	return cls;
}

const char*
class_getName(Class cls)
{
	return cls->name;
}

Class
class_getSuperclass(Class cls)
{
	return cls->superclass;
}

BOOL
class_isKindOfClass(Class cls1, Class cls2)
{
	Class iter;

	for (iter = cls1; iter != Nil; iter = iter->superclass)
		if (iter == cls2)
			return YES;

	return NO;
}

unsigned long
class_getInstanceSize(Class cls)
{
	return cls->instance_size;
}

IMP
objc_get_class_method(Class cls, SEL sel)
{
	return objc_sparsearray_get(cls->isa->dtable, sel->uid);
}

IMP
objc_get_instance_method(Class cls, SEL sel)
{
	return objc_sparsearray_get(cls->dtable, sel->uid);
}

const char*
objc_get_type_encoding(Class cls, SEL sel)
{
	struct objc_abi_method_list *ml;
	struct objc_abi_category **cats;
	unsigned int i;

	objc_global_mutex_lock();

	for (ml = cls->isa->methodlist; ml != NULL; ml = ml->next) {
		for (i = 0; i < ml->count; i++) {
			if ((uintptr_t)ml->methods[i].name == sel->uid) {
				const char *ret = ml->methods[i].types;
				objc_global_mutex_unlock();
				return ret;
			}
		}
	}

	if ((cats = objc_categories_for_class(cls)) != NULL) {
		for (; *cats != NULL; cats++) {
			for (ml = (*cats)->class_methods; ml != NULL;
			    ml = ml->next) {
				for (i = 0; i < ml->count; i++) {
					if ((uintptr_t)ml->methods[i].name ==
					    sel->uid) {
						const char *ret =
						    ml->methods[i].types;
						objc_global_mutex_unlock();
						return ret;
					}
				}
			}
		}
	}

	objc_global_mutex_unlock();

	return NULL;
}

IMP
objc_replace_class_method(Class cls, SEL sel, IMP newimp)
{
	struct objc_abi_method_list *ml;
	struct objc_abi_category **cats;
	unsigned int i;
	BOOL replaced = NO;
	IMP oldimp = NULL;

	objc_global_mutex_lock();

	for (ml = cls->isa->methodlist; ml != NULL; ml = ml->next) {
		for (i = 0; i < ml->count; i++) {
			if ((uintptr_t)ml->methods[i].name == sel->uid) {
				oldimp = ml->methods[i].imp;
				ml->methods[i].imp = newimp;
				replaced = YES;
				break;
			}
		}
	}

	if ((cats = objc_categories_for_class(cls)) != NULL) {
		for (; *cats != NULL; cats++) {
			for (ml = (*cats)->class_methods; ml != NULL;
			    ml = ml->next) {
				for (i = 0; i < ml->count; i++) {
					if ((uintptr_t)ml->methods[i].name ==
					    sel->uid) {
						oldimp = ml->methods[i].imp;
						ml->methods[i].imp = newimp;
						replaced = YES;
						break;
					}
				}
			}
		}
	}

	if (!replaced) {
		/* FIXME: We need a way to free this at objc_exit() */
		if ((ml = malloc(sizeof(struct objc_abi_method_list))) == NULL)
			ERROR("Not enough memory to replace method!");

		ml->next = cls->isa->methodlist;
		ml->count = 1;
		ml->methods[0].name = (const char*)sel->uid;
		/* FIXME: We need to get the type from a superclass */
		ml->methods[0].types = sel->types;
		ml->methods[0].imp = newimp;

		cls->isa->methodlist = ml;
	}

	objc_update_dtable(cls->isa);

	objc_global_mutex_unlock();

	return oldimp;
}

IMP
objc_replace_instance_method(Class cls, SEL sel, IMP newimp)
{
	struct objc_abi_method_list *ml;
	struct objc_abi_category **cats;
	unsigned int i;
	BOOL replaced = NO;
	IMP oldimp = NULL;

	objc_global_mutex_lock();

	for (ml = cls->methodlist; ml != NULL; ml = ml->next) {
		for (i = 0; i < ml->count; i++) {
			if ((uintptr_t)ml->methods[i].name == sel->uid) {
				oldimp = ml->methods[i].imp;
				ml->methods[i].imp = newimp;
				replaced = YES;
				break;
			}
		}
	}

	if ((cats = objc_categories_for_class(cls)) != NULL) {
		for (; *cats != NULL; cats++) {
			for (ml = (*cats)->instance_methods; ml != NULL;
			    ml = ml->next) {
				for (i = 0; i < ml->count; i++) {
					if ((uintptr_t)ml->methods[i].name ==
					    sel->uid) {
						oldimp = ml->methods[i].imp;
						ml->methods[i].imp = newimp;
						replaced = YES;
						break;
					}
				}
			}
		}
	}

	if (!replaced) {
		/* FIXME: We need a way to free this at objc_exit() */
		if ((ml = malloc(sizeof(struct objc_abi_method_list))) == NULL)
			ERROR("Not enough memory to replace method!");

		ml->next = cls->methodlist;
		ml->count = 1;
		ml->methods[0].name = (const char*)sel->uid;
		/* FIXME: We need to get the type from a superclass */
		ml->methods[0].types = sel->types;
		ml->methods[0].imp = newimp;

		cls->methodlist = ml;
	}

	objc_update_dtable(cls);

	objc_global_mutex_unlock();

	return oldimp;
}

static void
free_class(Class rcls)
{
	struct objc_abi_class *cls = (struct objc_abi_class*)rcls;

	if (!(rcls->info & OBJC_CLASS_INFO_INITIALIZED))
		return;

	if (rcls->subclass_list != NULL) {
		free(rcls->subclass_list);
		rcls->subclass_list = NULL;
	}

	objc_sparsearray_free(rcls->dtable);
	rcls->dtable = NULL;

	if (rcls->superclass != Nil)
		cls->superclass = rcls->superclass->name;
}

void
objc_free_all_classes(void)
{
	uint32_t i;

	if (classes == NULL)
		return;

	for (i = 0; i <= classes->last_idx; i++) {
		if (classes->data[i] != NULL) {
			free_class((Class)classes->data[i]->obj);
			free_class(((Class)classes->data[i]->obj)->isa);
		}
	}

	objc_hashtable_free(classes);
	classes = NULL;
}

Added src/runtime/hashtable.m version [f05f1f70fa].

















































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
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
156
157
158
159
160
161
162
163
164
165
166
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
192
193
194
195
196
197
198
199
200
/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

#include <assert.h>

#import "runtime.h"
#import "runtime-private.h"

uint32_t
objc_hash_string(const char *str)
{
	uint32_t hash = 0;

	while (*str != 0) {
		hash += *str;
		hash += (hash << 10);
		hash ^= (hash >> 6);
		str++;
	}

	hash += (hash << 3);
	hash ^= (hash >> 11);
	hash += (hash << 15);

	return hash;
}

struct objc_hashtable*
objc_hashtable_alloc(uint32_t size)
{
	struct objc_hashtable *h;
	uint32_t i;

	if ((h = malloc(sizeof(struct objc_hashtable))) == NULL)
		ERROR("Not enough memory to allocate hash table!");

	h->count = 0;
	h->last_idx = size - 1;
	h->data = malloc(size * sizeof(struct objc_hashtable_bucket*));

	if (h->data == NULL)
		ERROR("Not enough memory to allocate hash table!");

	for (i = 0; i < size; i++)
		h->data[i] = NULL;

	return h;
}

static void
insert(struct objc_hashtable *h, const char *key, const void *obj)
{
	uint32_t i, hash, last;
	struct objc_hashtable_bucket *bucket;

	hash = objc_hash_string(key);
	assert(h->count + 1 <= UINT32_MAX / 4);

	if ((h->count + 1) * 4 / (h->last_idx + 1) >= 3) {
		struct objc_hashtable_bucket **ndata;
		uint32_t nsize = (h->last_idx + 1) << 1;

		assert(nsize > 0);

		ndata = malloc(nsize * sizeof(struct objc_hashtable_bucket*));
		if (ndata == NULL)
			ERROR("Not enough memory to insert into hash table!");

		for (i = 0; i < nsize; i++)
			ndata[i] = NULL;

		for (i = 0; i <= h->last_idx; i++) {
			if (h->data[i] != NULL) {
				uint32_t j;

				last = nsize;

				for (j = h->data[i]->hash & (nsize - 1);
				    j < last && ndata[j] != NULL; j++);

				if (j >= last) {
					last = h->data[i]->hash & (nsize - 1);

					for (j = 0; j < last &&
					    ndata[j] != NULL; j++);
				}

				if (j >= last)
					ERROR("No free bucket!");

				ndata[j] = h->data[i];
			}
		}

		free(h->data);
		h->data = ndata;
		h->last_idx = nsize - 1;
	}

	last = h->last_idx + 1;

	for (i = hash & h->last_idx; i < last && h->data[i] != NULL; i++);

	if (i >= last) {
		last = hash & h->last_idx;

		for (i = 0; i < last && h->data[i] != NULL; i++);
	}

	if (i >= last)
		ERROR("No free bucket!");

	if ((bucket = malloc(sizeof(struct objc_hashtable_bucket))) == NULL)
		ERROR("Not enough memory to allocate hash table bucket!");

	bucket->key = key;
	bucket->hash = hash;
	bucket->obj = obj;

	h->data[i] = bucket;
	h->count++;
}

static inline int64_t
index_for_key(struct objc_hashtable *h, const char *key)
{
	uint32_t i, hash;

	hash = objc_hash_string(key) & h->last_idx;

	for (i = hash; i <= h->last_idx && h->data[i] != NULL; i++)
		if (!strcmp(h->data[i]->key, key))
			return i;

	if (i <= h->last_idx)
		return -1;

	for (i = 0; i < hash && h->data[i] != NULL; i++)
		if (!strcmp(h->data[i]->key, key))
			return i;

	return -1;
}

void
objc_hashtable_set(struct objc_hashtable *h, const char *key, const void *obj)
{
	int64_t idx = index_for_key(h, key);

	if (idx < 0) {
		insert(h, key, obj);
		return;
	}

	h->data[idx]->obj = obj;
}

const void*
objc_hashtable_get(struct objc_hashtable *h, const char *key)
{
	int64_t idx = index_for_key(h, key);

	if (idx < 0)
		return NULL;

	return h->data[idx]->obj;
}

void
objc_hashtable_free(struct objc_hashtable *h)
{
	uint32_t i;

	for (i = 0; i <= h->last_idx; i++)
		if (h->data[i] != NULL)
			free(h->data[i]);

	free(h->data);
	free(h);
}

Added src/runtime/init.m version [67c36937da].































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
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
/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

#import "runtime.h"
#import "runtime-private.h"

void
__objc_exec_class(struct objc_abi_module *module)
{
	objc_global_mutex_lock();

	objc_register_all_selectors(module->symtab);
	objc_register_all_classes(module->symtab);
	objc_register_all_categories(module->symtab);
	objc_init_static_instances(module->symtab);

	objc_global_mutex_unlock();
}

void
objc_exit(void)
{
	objc_global_mutex_lock();

	objc_free_all_categories();
	objc_free_all_classes();
	objc_free_all_selectors();
	objc_sparsearray_cleanup();

	objc_global_mutex_unlock();
	objc_global_mutex_free();
}

Added src/runtime/lookup.m version [979591be16].



































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
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
/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

#include <stdio.h>
#include <stdlib.h>

#import  "runtime.h"
#import "runtime-private.h"
#import "macros.h"

static IMP not_found_handler(id, SEL);
IMP (*objc_forward_handler)(id, SEL) = not_found_handler;

static IMP
not_found_handler(id obj, SEL sel)
{
	ERROR("Selector %s is not implemented for class %s!",
	    sel_getName(sel), obj->isa->name);
}

BOOL
class_respondsToSelector(Class cls, SEL sel)
{
	if (cls == Nil)
		return NO;

	return (objc_sparsearray_get(cls->dtable, sel->uid) != NULL ? YES : NO);
}

#if !defined(__ELF__) || (!defined(OF_X86_ASM) && !defined(OF_AMD64_ASM))
static id
nil_method(id self, SEL _cmd)
{
	return nil;
}

IMP
objc_msg_lookup(id obj, SEL sel)
{
	IMP imp;

	if (obj == nil)
		return (IMP)nil_method;

	if ((imp = objc_sparsearray_get(obj->isa->dtable, sel->uid)) == NULL)
		return objc_forward_handler(obj, sel);

	return imp;
}

IMP
objc_msg_lookup_super(struct objc_abi_super *super, SEL sel)
{
	IMP imp;

	if (super->self == nil)
		return (IMP)nil_method;

	imp = objc_sparsearray_get(super->class->dtable, sel->uid);

	if (imp == NULL)
		return objc_forward_handler(super->self, sel);

	return imp;
}
#endif

Added src/runtime/protocol.m version [548197efb9].









































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
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
/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

#include <string.h>

#import "runtime.h"
#import "runtime-private.h"

@implementation Protocol
- (BOOL)_isImplementedByClass: (Class)cls
{
	struct objc_abi_protocol_list *pl;
	struct objc_abi_category **cats;
	long i, j;

	objc_global_mutex_lock();

	for (pl = cls->protocols; pl != NULL; pl = pl->next) {
		for (i = 0; i < pl->count; i++) {
			if (!strcmp(pl->list[i]->name, name)) {
				objc_global_mutex_unlock();
				return YES;
			}
		}
	}

	if ((cats = objc_categories_for_class(cls)) == NULL) {
		objc_global_mutex_unlock();
		return NO;
	}

	for (i = 0; cats[i] != NULL; i++) {
		for (pl = cats[i]->protocols; pl != NULL; pl = pl->next) {
			for (j = 0; j < pl->count; j++) {
				if (!strcmp(pl->list[j]->name, name)) {
					objc_global_mutex_unlock();
					return YES;
				}
			}
		}
	}

	objc_global_mutex_unlock();

	return NO;
}
@end

BOOL
class_conformsToProtocl(Class cls, Protocol *p)
{
	return [p _isImplementedByClass: cls];
}

Added src/runtime/runtime-private.h version [5494f2f715].























































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#import "threading.h"

struct objc_abi_class {
	struct objc_abi_class *metaclass;
	const char *superclass;
	const char *name;
	unsigned long version;
	unsigned long info;
	unsigned long instance_size;
	void *ivars;
	struct objc_abi_method_list *methodlist;
	void *dtable;
	void *subclass_list;
	void *sibling_class;
	void *protocols;
	void *gc_object_type;
	long abi_version;
	void *ivar_offsets;
	void *properties;
};

struct objc_abi_method {
	const char *name;
	const char *types;
	IMP imp;
};

struct objc_abi_method_list {
	struct objc_abi_method_list *next;
	unsigned int count;
	struct objc_abi_method methods[1];
};

struct objc_abi_selector {
	const char *name;
	const char *types;
};

struct objc_abi_category {
	const char *category_name;
	const char *class_name;
	struct objc_abi_method_list *instance_methods;
	struct objc_abi_method_list *class_methods;
	struct objc_abi_protocol_list *protocols;
};

struct objc_abi_super {
	id self;
	Class class;
};

struct objc_abi_method_description {
	const char *name;
	const char *types;
};

struct objc_abi_method_description_list {
	int count;
	struct objc_abi_method_description list[1];
};

struct objc_abi_protocol_list {
	struct objc_abi_protocol_list *next;
	long count;
	Protocol *list[1];
};

struct objc_abi_static_instances {
	const char *class_name;
	id instances[1];
};

struct objc_abi_symtab {
	unsigned long unknown;
	struct objc_abi_selector *sel_refs;
	uint16_t cls_def_cnt;
	uint16_t cat_def_cnt;
	void *defs[1];
};

struct objc_abi_module {
	unsigned long version;	/* 9 = non-fragile */
	unsigned long size;
	const char *name;
	struct objc_abi_symtab *symtab;
};

struct objc_hashtable_bucket {
	const char *key;
	const void *obj;
	uint32_t hash;
};

struct objc_hashtable {
	uint32_t count;
	uint32_t last_idx;
	struct objc_hashtable_bucket **data;
};

struct objc_sparsearray {
	struct objc_sparsearray_level2 *buckets[256];
};

struct objc_sparsearray_level2 {
	struct objc_sparsearray_level3 *buckets[256];
	BOOL empty;
};

struct objc_sparsearray_level3 {
	const void *buckets[256];
	BOOL empty;
};

typedef struct {
	of_mutex_t mutex;
	of_thread_t owner;
	int count;
} objc_mutex_t;

extern void objc_register_all_categories(struct objc_abi_symtab*);
extern struct objc_abi_category** objc_categories_for_class(Class);
extern void objc_free_all_categories(void);
extern void objc_update_dtable(Class);
extern void objc_register_all_classes(struct objc_abi_symtab*);
extern Class objc_classname_to_class(const char*);
extern void objc_free_all_classes(void);
extern uint32_t objc_hash_string(const char*);
extern struct objc_hashtable* objc_hashtable_alloc(uint32_t);
extern void objc_hashtable_set(struct objc_hashtable*, const char*,
    const void*);
extern const void* objc_hashtable_get(struct objc_hashtable*, const char*);
extern void objc_hashtable_free(struct objc_hashtable *h);
extern BOOL objc_hashtable_warn_on_collision;
extern void objc_register_selector(struct objc_abi_selector*);
extern void objc_register_all_selectors(struct objc_abi_symtab*);
extern void objc_free_all_selectors(void);
extern struct objc_sparsearray* objc_sparsearray_new(void);
extern struct objc_sparsearray* objc_sparsearray_copy(struct objc_sparsearray*);
extern void objc_sparsearray_set(struct objc_sparsearray*, uint32_t,
    const void*);
extern void objc_sparsearray_free(struct objc_sparsearray*);
extern void objc_sparsearray_free_when_singlethreaded(struct objc_sparsearray*);
extern void objc_sparsearray_cleanup(void);
extern void objc_init_static_instances(struct objc_abi_symtab*);
extern void __objc_exec_class(struct objc_abi_module*);
extern BOOL objc_mutex_new(objc_mutex_t*);
extern BOOL objc_mutex_lock(objc_mutex_t*);
extern BOOL objc_mutex_unlock(objc_mutex_t*);
extern BOOL objc_mutex_free(objc_mutex_t*);
extern void objc_global_mutex_lock(void);
extern void objc_global_mutex_unlock(void);
extern void objc_global_mutex_free(void);
extern void objc_free_when_singlethreaded(void*);

static inline const void*
objc_sparsearray_get(const struct objc_sparsearray *s, uint32_t idx)
{
	uint8_t i = idx >> 16;
	uint8_t j = idx >>  8;
	uint8_t k = idx;

	return s->buckets[i]->buckets[j]->buckets[k];
}

#define ERROR(...)							\
	{								\
		fprintf(stderr, "[objc @ " __FILE__ ":%d] ", __LINE__);	\
		fprintf(stderr, __VA_ARGS__);				\
		fputs("\n", stderr);					\
		abort();						\
	}

Added src/runtime/runtime.h version [92e1b049bf].









































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
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
/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#ifndef __OBJFW_RUNTIME_H__
#define __OBJFW_RUNTIME_H__
#include <stdint.h>

typedef struct objc_class *Class;
typedef struct objc_object *id;
typedef const struct objc_selector *SEL;
typedef signed char BOOL;
typedef id (*IMP)(id, SEL, ...);

#ifdef __OBJC__
@interface Protocol
{
@private
	Class isa;
	const char *name;
	struct objc_abi_protocol_list *protocol_list;
	struct objc_abi_method_description_list *instance_methods;
	struct objc_abi_method_description_list *class_methods;
}
@end
#else
typedef const void Protocol;
#endif

struct objc_class {
	Class isa;
	Class superclass;
	const char *name;
	unsigned long version;
	unsigned long info;
	unsigned long instance_size;
	void *ivars;
	struct objc_abi_method_list *methodlist;
	struct objc_sparsearray *dtable;
	Class *subclass_list;
	void *sibling_class;
	struct objc_abi_protocol_list *protocols;
	void *gc_object_type;
	unsigned long abi_version;
	void *ivar_offsets;
	void *properties;
};

struct objc_object {
	Class isa;
};

struct objc_selector {
	uintptr_t uid;
	const char *types;
};

enum objc_abi_class_info {
	OBJC_CLASS_INFO_CLASS	    = 0x01,
	OBJC_CLASS_INFO_METACLASS   = 0x02,
	OBJC_CLASS_INFO_INITIALIZED = 0x04
};

#define Nil (Class)0
#define nil (id)0
#define YES (BOOL)1
#define NO  (BOOL)0

extern SEL sel_registerName(const char*);
extern const char* sel_getName(SEL);
extern Class objc_get_class(const char*);
extern Class objc_lookup_class(const char*);
extern const char* class_getName(Class);
extern Class class_getSuperclass(Class);
extern BOOL class_isKindOfClass(Class, Class);
extern unsigned long class_getInstanceSize(Class);
extern BOOL class_respondsToSelector(Class, SEL);
extern BOOL class_conformsToProtocol(Class, Protocol*);
extern IMP objc_get_class_method(Class, SEL);
extern IMP objc_get_instance_method(Class, SEL);
extern IMP objc_replace_class_method(Class, SEL, IMP);
extern IMP objc_replace_instance_method(Class, SEL, IMP);
extern const char* objc_get_type_encoding(Class, SEL);
extern IMP objc_msg_lookup(id, SEL);
extern void objc_thread_add(void);
extern void objc_thread_remove(void);
extern void objc_exit(void);
#endif

Added src/runtime/selector.m version [8b3f8d4a11].















































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
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
109
110
111
112
113
114
115
116
117
118
119
/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#import "runtime.h"
#import "runtime-private.h"

static struct objc_sparsearray *selectors = NULL;

void
objc_register_selector(struct objc_abi_selector *sel)
{
	uint32_t hash, last;
	struct objc_selector *rsel = (struct objc_selector*)sel;
	const char *name;

	if (selectors == NULL)
		selectors = objc_sparsearray_new();

	hash = objc_hash_string(sel->name) >> 8;

	while (hash <= 0xFFFFFF &&
	    (name = objc_sparsearray_get(selectors, hash)) != NULL) {
		if (!strcmp(name, sel->name)) {
			rsel->uid = hash;
			return;
		}

		hash++;
	}

	if (hash > 0xFFFFFF) {
		last = hash;
		hash = 0;

		while (hash < last &&
		    (name = objc_sparsearray_get(selectors, hash)) != NULL) {
			if (!strcmp(name, sel->name)) {
				rsel->uid = hash;
				return;
			}

			hash++;
		}
	}

	objc_sparsearray_set(selectors, hash, (void*)sel->name);
	rsel->uid = hash;
}

SEL
sel_registerName(const char *name)
{
	struct objc_abi_selector *sel;

	/* FIXME: Free on objc_exit() */
	if ((sel = malloc(sizeof(struct objc_abi_selector))) == NULL)
		ERROR("Not enough memory to allocate selector!");

	if ((sel->name = strdup(name)) == NULL)
		ERROR("Not enough memory to allocate selector!");

	sel->types = NULL;

	objc_global_mutex_lock();
	objc_register_selector(sel);
	objc_global_mutex_unlock();

	return (SEL)sel;
}

void
objc_register_all_selectors(struct objc_abi_symtab *symtab)
{
	struct objc_abi_selector *sel;

	if (symtab->sel_refs == NULL)
		return;

	for (sel = symtab->sel_refs; sel->name != NULL; sel++)
		objc_register_selector(sel);
}

const char*
sel_getName(SEL sel)
{
	const char *ret;

	objc_global_mutex_lock();
	ret = objc_sparsearray_get(selectors, sel->uid);
	objc_global_mutex_unlock();

	return ret;
}

void
objc_free_all_selectors(void)
{
	objc_sparsearray_free(selectors);
	selectors = NULL;
}

Added src/runtime/sparsearray.m version [71ecf956f3].



































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
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
156
157
158
159
160
161
162
163
164
165
166
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
192
193
/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

#include <stdio.h>
#include <stdlib.h>

#import "runtime.h"
#import "runtime-private.h"

static struct objc_sparsearray_level2 *empty_level2 = NULL;
static struct objc_sparsearray_level3 *empty_level3 = NULL;

static void
init(void)
{
	size_t i;

	empty_level2 = malloc(sizeof(struct objc_sparsearray_level2));
	empty_level3 = malloc(sizeof(struct objc_sparsearray_level3));

	if (empty_level2 == NULL || empty_level3 == NULL)
		ERROR("Not enough memory to allocate sparse array!");

	empty_level2->empty = YES;
	empty_level3->empty = YES;

	for (i = 0; i < 256; i++) {
		empty_level2->buckets[i] = empty_level3;
		empty_level3->buckets[i] = NULL;
	}
}

struct objc_sparsearray*
objc_sparsearray_new(void)
{
	struct objc_sparsearray *s;
	size_t i;

	if (empty_level2 == NULL || empty_level3 == NULL)
		init();

	if ((s = malloc(sizeof(struct objc_sparsearray))) == NULL)
		ERROR("Not enough memory to allocate sparse array!");

	for (i = 0; i < 256; i++)
		s->buckets[i] = empty_level2;

	return s;
}

struct objc_sparsearray*
objc_sparsearray_copy(struct objc_sparsearray *src)
{
	struct objc_sparsearray *dst;
	size_t i, j, k;
	uint32_t idx;

	dst = objc_sparsearray_new();

	for (i = 0; i < 256; i++) {
		if (src->buckets[i]->empty)
			continue;

		for (j = 0; j < 256; j++) {
			if (src->buckets[i]->buckets[j]->empty)
				continue;

			for (k = 0; k < 256; k++) {
				const void *obj;

				obj = src->buckets[i]->buckets[j]->buckets[k];

				if (obj == NULL)
					continue;

				idx = (i << 16) | (j << 8) | k;
				objc_sparsearray_set(dst, idx, obj);
			}
		}
	}

	return dst;
}

void
objc_sparsearray_set(struct objc_sparsearray *s, uint32_t idx, const void *obj)
{
	uint8_t i = idx >> 16;
	uint8_t j = idx >>  8;
	uint8_t k = idx;

	if (s->buckets[i]->empty) {
		struct objc_sparsearray_level2 *t;
		size_t l;

		t = malloc(sizeof(struct objc_sparsearray_level2));

		if (t == NULL)
			ERROR("Not enough memory to insert into sparse array!");

		t->empty = NO;

		for (l = 0; l < 256; l++)
			t->buckets[l] = empty_level3;

		s->buckets[i] = t;
	}

	if (s->buckets[i]->buckets[j]->empty) {
		struct objc_sparsearray_level3 *t;
		size_t l;

		t = malloc(sizeof(struct objc_sparsearray_level3));

		if (t == NULL)
			ERROR("Not enough memory to insert into sparse array!");

		t->empty = NO;

		for (l = 0; l < 256; l++)
			t->buckets[l] = NULL;

		s->buckets[i]->buckets[j] = t;
	}

	s->buckets[i]->buckets[j]->buckets[k] = obj;
}

void
objc_sparsearray_free(struct objc_sparsearray *s)
{
	size_t i, j;

	for (i = 0; i < 256; i++) {
		if (s->buckets[i]->empty)
			continue;

		for (j = 0; j < 256; j++)
			if (!s->buckets[i]->buckets[j]->empty)
				free(s->buckets[i]->buckets[j]);

		free(s->buckets[i]);
	}

	free(s);
}

void
objc_sparsearray_free_when_singlethreaded(struct objc_sparsearray *s)
{
	size_t i, j;

	for (i = 0; i < 256; i++) {
		if (s->buckets[i]->empty)
			continue;

		for (j = 0; j < 256; j++)
			if (!s->buckets[i]->buckets[j]->empty)
				objc_free_when_singlethreaded(
				    s->buckets[i]->buckets[j]);

		objc_free_when_singlethreaded(s->buckets[i]);
	}

	objc_free_when_singlethreaded(s);
}

void
objc_sparsearray_cleanup(void)
{
	if (empty_level2 != NULL)
		free(empty_level2);
	if (empty_level3 != NULL)
		free(empty_level3);

	empty_level2 = NULL;
	empty_level3 = NULL;
}

Added src/runtime/static-instances.m version [af522385e4].



































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
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
/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

#include <stdio.h>
#include <stdlib.h>

#import "runtime.h"
#import "runtime-private.h"

static struct objc_abi_static_instances **static_instances = NULL;
static size_t static_instances_cnt = 0;

void
objc_init_static_instances(struct objc_abi_symtab *symtab)
{
	struct objc_abi_static_instances **si;
	size_t i;

	/* Check if the class for a static instance became available */
	for (i = 0; i < static_instances_cnt; i++) {
		Class cls = objc_lookup_class(static_instances[i]->class_name);

		if (cls != Nil) {
			id *instances;

			for (instances = static_instances[i]->instances;
			    *instances != nil; instances++)
				(*instances)->isa = cls;

			static_instances_cnt--;

			if (static_instances_cnt == 0) {
				free(static_instances);
				static_instances = NULL;
				continue;
			}

			static_instances[i] =
			    static_instances[static_instances_cnt];

			static_instances = realloc(static_instances,
			    sizeof(struct objc_abi_static_instances*) *
			    static_instances_cnt);

			if (static_instances == NULL)
				ERROR("Not enough memory for list of static "
				    "instances!");
		}
	}

	si = (struct objc_abi_static_instances**)
	    symtab->defs[symtab->cls_def_cnt + symtab->cat_def_cnt];

	if (si == NULL)
		return;

	for (; *si != NULL; si++) {
		Class cls = objc_lookup_class((*si)->class_name);

		if (cls != Nil) {
			id *instances;

			for (instances = (*si)->instances; *instances != nil;
			    instances++)
				(*instances)->isa = cls;
		} else {
			if (static_instances == NULL)
				static_instances = malloc(sizeof(
				    struct objc_abi_static_instances*));
			else
				static_instances = realloc(static_instances,
				    sizeof(struct objc_abi_static_instances*) *
				    (static_instances_cnt + 1));

			if (static_instances == NULL)
				ERROR("Not enough memory for list of static "
				    "instances!");

			static_instances[static_instances_cnt++] = *si;
		}
	}
}

Added src/runtime/threading.m version [0fa31c9691].

















































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

#include <stdio.h>
#include <stdlib.h>

#import "runtime.h"
#import "runtime-private.h"

static objc_mutex_t global_mutex;
static int num_threads = 1;
static void **free_queue = NULL;
static size_t free_queue_cnt = 0;

BOOL
objc_mutex_new(objc_mutex_t *mutex)
{
	if (of_mutex_new(&mutex->mutex ))
		return NO;

	mutex->count = 0;

	return YES;
}

BOOL
objc_mutex_lock(objc_mutex_t *mutex)
{
	if (mutex->count > 0 && of_thread_is_current(mutex->owner)) {
		mutex->count++;
		return YES;
	}

	if (!of_mutex_lock(&mutex->mutex))
		return NO;

	mutex->owner = of_thread_current();
	mutex->count++;

	return YES;
}

BOOL
objc_mutex_unlock(objc_mutex_t *mutex)
{
	if (--mutex->count == 0)
		return of_mutex_unlock(&mutex->mutex);

	return YES;
}

BOOL
objc_mutex_free(objc_mutex_t *mutex)
{
	return of_mutex_free(&mutex->mutex);
}

static void __attribute__((constructor))
objc_global_mutex_new(void)
{
	if (!objc_mutex_new(&global_mutex))
		ERROR("Failed to create global mutex!");
}

void
objc_global_mutex_lock(void)
{
	if (!objc_mutex_lock(&global_mutex))
		ERROR("Failed to lock global mutex!");
}

void
objc_global_mutex_unlock(void)
{
	if (!objc_mutex_unlock(&global_mutex))
		ERROR("Failed to unlock global mutex!");
}

void
objc_global_mutex_free(void)
{
	if (!objc_mutex_free(&global_mutex))
		ERROR("Failed to free global mutex!");
}

void
objc_thread_add(void)
{
	/*
	 * If some class is being initialized, we want to wait for it, thus
	 * we use the global lock instead of atomic operations.
	 */
	objc_global_mutex_lock();
	num_threads++;
	objc_global_mutex_unlock();
}

void
objc_thread_remove(void)
{
	size_t i;

	objc_global_mutex_lock();

	if (free_queue != NULL) {
		for (i = 0; i < free_queue_cnt; i++)
			free(free_queue[i]);

		free(free_queue);

		free_queue = NULL;
		free_queue_cnt = 0;
	}

	num_threads--;
	objc_global_mutex_unlock();
}

void
objc_free_when_singlethreaded(void *ptr)
{
	if (num_threads == 1) {
		free(ptr);
		return;
	}

	if (free_queue == NULL)
		free_queue = malloc(sizeof(void*));
	else
		free_queue = realloc(free_queue, sizeof(void*) *
		    (free_queue_cnt + 1));

	if (free_queue == NULL)
		ERROR("Not enough memory for queue of pointers to free!");

	free_queue[free_queue_cnt++] = ptr;
}