ObjFW  Check-in [dcf845546a]

Overview
Comment:Initialize classes on the first dispatch.

This is no longer done in objc_msg_lookup() and thus allows direct class
references.

Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | runtime
Files: files | file ages | folders
SHA3-256: dcf845546af968e9326178974b0d5b225494bcb2ddd1595f9eb6279cbdd601f4
User & Date: js on 2012-05-09 13:55:09
Other Links: branch diff | manifest | tags
Context
2012-05-10
18:21
objc_hashtable_alloc() -> objc_hashtable_new(). check-in: 963db3089f user: js tags: runtime
2012-05-09
13:55
Initialize classes on the first dispatch. check-in: dcf845546a user: js tags: runtime
13:54
Better way of calling the forwarding handler. check-in: f5747ff94a user: js tags: runtime
Changes

Modified src/runtime/class.m from [886ace82f1] to [16b932ec92].

24
25
26
27
28
29
30

31
32
33
34
35
36
37
38






39
40
41
42
43
44
45

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

static struct objc_hashtable *classes = NULL;
static Class *load_queue = NULL;
static size_t load_queue_cnt = 0;


static void
register_class(struct objc_abi_class *cls)
{
	if (classes == NULL)
		classes = objc_hashtable_alloc(2);

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






}

BOOL
class_registerAlias_np(Class cls, const char *name)
{
	if (classes == NULL)
		return NO;







>








>
>
>
>
>
>







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

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

static struct objc_hashtable *classes = NULL;
static Class *load_queue = NULL;
static size_t load_queue_cnt = 0;
static struct objc_sparsearray *empty_dtable = NULL;

static void
register_class(struct objc_abi_class *cls)
{
	if (classes == NULL)
		classes = objc_hashtable_alloc(2);

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

	if (empty_dtable == NULL)
		empty_dtable = objc_sparsearray_new();

	cls->dtable = empty_dtable;
	cls->metaclass->dtable = empty_dtable;
}

BOOL
class_registerAlias_np(Class cls, const char *name)
{
	if (classes == NULL)
		return NO;
126
127
128
129
130
131
132



133
134
135
136
137
138
139
140
void
objc_update_dtable(Class cls)
{
	struct objc_method_list *ml;
	struct objc_category **cats;
	unsigned int i;




	if (cls->dtable == NULL)
		cls->dtable = objc_sparsearray_new();

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

	for (ml = cls->methodlist; ml != NULL; ml = ml->next)
		for (i = 0; i < ml->count; i++)







>
>
>
|







133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
void
objc_update_dtable(Class cls)
{
	struct objc_method_list *ml;
	struct objc_category **cats;
	unsigned int i;

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

	if (cls->dtable == empty_dtable)
		cls->dtable = objc_sparsearray_new();

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

	for (ml = cls->methodlist; ml != NULL; ml = ml->next)
		for (i = 0; i < ml->count; i++)
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
		cls->isa->superclass = super->isa;

		add_subclass(cls);
		add_subclass(cls->isa);
	} else
		cls->isa->superclass = cls;

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

	cls->info |= OBJC_CLASS_INFO_SETUP;
	cls->isa->info |= OBJC_CLASS_INFO_SETUP;
}

static void
initialize_class(Class cls)
{
	if (cls->info & OBJC_CLASS_INFO_INITIALIZED)
		return;

	if (cls->superclass)
		initialize_class(cls->superclass);

	/*
	 * Set it first to prevent calling it recursively due to message sends
	 * in the initialize method
	 */
	cls->info |= OBJC_CLASS_INFO_INITIALIZED;
	cls->isa->info |= OBJC_CLASS_INFO_INITIALIZED;




	call_method(cls, "initialize");
}































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

	for (i = 0; i < symtab->cls_def_cnt; i++) {







<
<
<




















>
>
>


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







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
		cls->isa->superclass = super->isa;

		add_subclass(cls);
		add_subclass(cls->isa);
	} else
		cls->isa->superclass = cls;




	cls->info |= OBJC_CLASS_INFO_SETUP;
	cls->isa->info |= OBJC_CLASS_INFO_SETUP;
}

static void
initialize_class(Class cls)
{
	if (cls->info & OBJC_CLASS_INFO_INITIALIZED)
		return;

	if (cls->superclass)
		initialize_class(cls->superclass);

	/*
	 * Set it first to prevent calling it recursively due to message sends
	 * in the initialize method
	 */
	cls->info |= OBJC_CLASS_INFO_INITIALIZED;
	cls->isa->info |= OBJC_CLASS_INFO_INITIALIZED;

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

	call_method(cls, "initialize");
}

void
objc_initialize_class(Class cls)
{
	if (cls->info & OBJC_CLASS_INFO_INITIALIZED)
		return;

	objc_global_mutex_lock();

	/*
	 * It's possible that two threads try to initialize 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;
	}

	setup_class(cls);

	if (!(cls->info & OBJC_CLASS_INFO_SETUP)) {
		objc_global_mutex_unlock();
		return;
	}

	initialize_class(cls);

	objc_global_mutex_unlock();
}

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

	for (i = 0; i < symtab->cls_def_cnt; i++) {
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
objc_lookup_class(const char *name)
{
	Class cls = objc_classname_to_class(name);

	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;
	}

	setup_class(cls);

	if (!(cls->info & OBJC_CLASS_INFO_SETUP)) {
		objc_global_mutex_unlock();
		return Nil;
	}

	initialize_class(cls);

	objc_global_mutex_unlock();

	return cls;
}

Class
objc_get_class(const char *name)
{







|




<
<
<
<
<
<
<
<
<
<


<
|
<
|
|
<
|
<







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
objc_lookup_class(const char *name)
{
	Class cls = objc_classname_to_class(name);

	if (cls == NULL)
		return Nil;

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

	objc_global_mutex_lock();











	setup_class(cls);


	objc_global_mutex_unlock();


	if (!(cls->info & OBJC_CLASS_INFO_SETUP))

		return Nil;


	return cls;
}

Class
objc_get_class(const char *name)
{

Modified src/runtime/lookup.m from [9ff82b2e4e] to [584f60ba59].

24
25
26
27
28
29
30























31
32
33
34
35
36
37
#import "macros.h"

IMP (*objc_forward_handler)(id, SEL) = NULL;

IMP
objc_not_found_handler(id obj, SEL sel)
{























	if (objc_forward_handler != NULL)
		return objc_forward_handler(obj, sel);

	ERROR("Selector %s is not implemented for class %s!",
	    sel_getName(sel), obj->isa->name);
}








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







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
#import "macros.h"

IMP (*objc_forward_handler)(id, SEL) = NULL;

IMP
objc_not_found_handler(id obj, SEL sel)
{
	if (!(obj->isa->info & OBJC_CLASS_INFO_INITIALIZED)) {
		BOOL is_class = obj->isa->info & OBJC_CLASS_INFO_METACLASS;
		Class cls = (is_class ? (Class)obj : obj->isa);

		objc_initialize_class(cls);

		if (!(cls->info & OBJC_CLASS_INFO_SETUP)) {
			if (is_class)
				return objc_msg_lookup(nil, sel);
			else
				ERROR("Could not dispatch message for "
				    "incomplete class %s!", cls->name);
		}

		/*
		 * We don't need to handle the case that super was called.
		 * The reason for this is that a call to super is not possible
		 * before a message to the class has been sent and it thus has
		 * been initialized together with its superclasses.
		 */
		return objc_msg_lookup(obj, sel);
	}

	if (objc_forward_handler != NULL)
		return objc_forward_handler(obj, sel);

	ERROR("Selector %s is not implemented for class %s!",
	    sel_getName(sel), obj->isa->name);
}

Modified src/runtime/runtime-private.h from [33a45d5cce] to [0a8ea1ad61].

137
138
139
140
141
142
143

144
145
146
147
148
149
150
	of_thread_t owner;
	int count;
} objc_mutex_t;

extern void objc_register_all_categories(struct objc_abi_symtab*);
extern struct objc_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*,







>







137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
	of_thread_t owner;
	int count;
} objc_mutex_t;

extern void objc_register_all_categories(struct objc_abi_symtab*);
extern struct objc_category** objc_categories_for_class(Class);
extern void objc_free_all_categories(void);
extern void objc_initialize_class(Class);
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*,