ObjFW  Check-in [ef6d69931e]

Overview
Comment:Make style consistent between ObjFW and ObjFW_RT

ObjFW_RT used to be a separate project that followed the BSD style, as
it was written in pure C, while ObjFW's style is based on the BSD style
with changes to make it a better fit for Objective-C. This commit
changes ObjFW_RT to use the same style as ObjFW.

Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: ef6d69931e03206c9a3387231fb6bd26d643873cfb5524a2405da9da5abeabfe
User & Date: js on 2019-02-07 00:46:41
Other Links: manifest | tags
Context
2019-02-07
21:31
More style improvements check-in: 754bf24742 user: js tags: trunk
00:46
Make style consistent between ObjFW and ObjFW_RT check-in: ef6d69931e user: js tags: trunk
2019-02-03
19:19
Move a few URL methods from OFString to OFURL check-in: f19cde3a14 user: js tags: trunk
Changes

Modified src/OFIntrospection.m from [7aef2cee7c] to [cd6beb50c0].

35
36
37
38
39
40
41
42

43
44
45

46
47
48
49
50
51
52
35
36
37
38
39
40
41

42
43
44

45
46
47
48
49
50
51
52







-
+


-
+








#if defined(OF_OBJFW_RUNTIME)
- (instancetype)of_initWithMethod: (struct objc_method *)method
{
	self = [super init];

	@try {
		_selector = (SEL)&method->sel;
		_selector = (SEL)&method->selector;
		_name = [[OFString alloc]
		    initWithUTF8String: sel_getName(_selector)];
		_typeEncoding = method->sel.types;
		_typeEncoding = method->selector.typeEncoding;
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}
147
148
149
150
151
152
153
154

155
156
157
158
159
160
161
147
148
149
150
151
152
153

154
155
156
157
158
159
160
161







-
+







- (instancetype)of_initWithProperty: (struct objc_property *)property
{
	self = [super init];

	@try {
		_name = [[OFString alloc] initWithUTF8String: property->name];
		_attributes =
		    property->attributes | (property->extended_attributes << 8);
		    property->attributes | (property->extendedAttributes << 8);

		if (property->getter.name != NULL)
			_getter = [[OFString alloc]
			    initWithUTF8String: property->getter.name];
		if (property->setter.name != NULL)
			_setter = [[OFString alloc]
			    initWithUTF8String: property->setter.name];
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
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







-
+




-
+

-
+

-
-
+
+








-
+




-
+




-
-
+
+








- (instancetype)init
{
	OF_INVALID_INIT_METHOD
}

#if defined(OF_OBJFW_RUNTIME)
- (instancetype)of_initWithIvar: (struct objc_ivar *)ivar
- (instancetype)of_initWithIVar: (struct objc_ivar *)iVar
{
	self = [super init];

	@try {
		if (ivar->name != NULL)
		if (iVar->name != NULL)
			_name = [[OFString alloc]
			    initWithUTF8String: ivar->name];
			    initWithUTF8String: iVar->name];

		_typeEncoding = ivar->type;
		_offset = ivar->offset;
		_typeEncoding = iVar->typeEncoding;
		_offset = iVar->offset;
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}
#elif defined(OF_APPLE_RUNTIME)
- (instancetype)of_initWithIvar: (Ivar)ivar
- (instancetype)of_initWithIVar: (Ivar)iVar
{
	self = [super init];

	@try {
		const char *name = ivar_getName(ivar);
		const char *name = ivar_getName(iVar);

		if (name != NULL)
			_name = [[OFString alloc] initWithUTF8String: name];

		_typeEncoding = ivar_getTypeEncoding(ivar);
		_offset = ivar_getOffset(ivar);
		_typeEncoding = ivar_getTypeEncoding(iVar);
		_offset = ivar_getOffset(iVar);
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}
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
494
495
496
497

498
499
500
501
502
503
504
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
494
495
496

497
498
499
500
501
502
503
504







-
+










-
+











-
+







	@try {
#if defined(OF_OBJFW_RUNTIME)
		struct objc_method_list *methodList;
		struct objc_property_list *propertyList;
#elif defined(OF_APPLE_RUNTIME)
		Method *methodList;
		objc_property_t *propertyList;
		Ivar *ivarList;
		Ivar *iVarList;
		unsigned count;
#endif
		void *pool;

		_classMethods = [[OFMutableArray alloc] init];
		_instanceMethods = [[OFMutableArray alloc] init];
		_properties = [[OFMutableArray alloc] init];
		_instanceVariables = [[OFMutableArray alloc] init];

#if defined(OF_OBJFW_RUNTIME)
		for (methodList = object_getClass(class)->methodlist;
		for (methodList = object_getClass(class)->methodList;
		    methodList != NULL; methodList = methodList->next) {
			pool = objc_autoreleasePoolPush();

			for (unsigned int i = 0; i < methodList->count; i++)
				[_classMethods addObject: [[[OFMethod alloc]
				    of_initWithMethod:
				    &methodList->methods[i]] autorelease]];

			objc_autoreleasePoolPop(pool);
		}

		for (methodList = class->methodlist; methodList != NULL;
		for (methodList = class->methodList; methodList != NULL;
		    methodList = methodList->next) {
			pool = objc_autoreleasePoolPush();

			for (unsigned int i = 0; i < methodList->count; i++)
				[_instanceMethods addObject: [[[OFMethod alloc]
				    of_initWithMethod:
				    &methodList->methods[i]] autorelease]];
514
515
516
517
518
519
520
521

522
523
524

525
526
527
528


529
530
531
532
533
534
535
514
515
516
517
518
519
520

521
522
523

524
525
526


527
528
529
530
531
532
533
534
535







-
+


-
+


-
-
+
+







				[_properties addObject: [[[OFProperty alloc]
				    of_initWithProperty:
				    &propertyList->properties[i]] autorelease]];

			objc_autoreleasePoolPop(pool);
		}

		if (class->ivars != NULL) {
		if (class->iVars != NULL) {
			pool = objc_autoreleasePoolPush();

			for (unsigned int i = 0; i < class->ivars->count; i++)
			for (unsigned int i = 0; i < class->iVars->count; i++)
				[_instanceVariables addObject:
				    [[[OFInstanceVariable alloc]
				    of_initWithIvar:
				    &class->ivars->ivars[i]] autorelease]];
				    of_initWithIVar:
				    &class->iVars->iVars[i]] autorelease]];

			objc_autoreleasePoolPop(pool);
		}
#elif defined(OF_APPLE_RUNTIME)
		methodList = class_copyMethodList(object_getClass(class),
		    &count);
		@try {
569
570
571
572
573
574
575
576

577
578
579
580
581
582
583

584
585
586
587

588
589
590
591
592
593
594
569
570
571
572
573
574
575

576
577
578
579
580
581
582

583
584
585
586

587
588
589
590
591
592
593
594







-
+






-
+



-
+







				    autorelease]];

			objc_autoreleasePoolPop(pool);
		} @finally {
			free(propertyList);
		}

		ivarList = class_copyIvarList(class, &count);
		iVarList = class_copyIvarList(class, &count);
		@try {
			pool = objc_autoreleasePoolPush();

			for (unsigned int i = 0; i < count; i++)
				[_instanceVariables addObject:
				    [[[OFInstanceVariable alloc]
				    of_initWithIvar: ivarList[i]] autorelease]];
				    of_initWithIVar: iVarList[i]] autorelease]];

			objc_autoreleasePoolPop(pool);
		} @finally {
			free(ivarList);
			free(iVarList);
		}
#else
# error Invalid ObjC runtime!
#endif

		[_classMethods makeImmutable];
		[_instanceMethods makeImmutable];

Modified src/OFObject.m from [13c5a8d446] to [cd9c001f04].

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







-
-
-
-
-
+
+
+
+
+














-
-
-
-
+
+
+
+







{
	Class superclass = [self superclass];

	if ([self isSubclassOfClass: class])
		return;

#if defined(OF_OBJFW_RUNTIME)
	for (struct objc_method_list *methodlist =
	    object_getClass(class)->methodlist;
	    methodlist != NULL; methodlist = methodlist->next) {
		for (unsigned int i = 0; i < methodlist->count; i++) {
			SEL selector = (SEL)&methodlist->methods[i].sel;
	for (struct objc_method_list *methodList =
	    object_getClass(class)->methodList;
	    methodList != NULL; methodList = methodList->next) {
		for (unsigned int i = 0; i < methodList->count; i++) {
			SEL selector = (SEL)&methodList->methods[i].selector;

			/*
			 * Don't replace methods implemented in the receiving
			 * class.
			 */
			if ([self methodForSelector: selector] !=
			    [superclass methodForSelector: selector])
				continue;

			[self replaceClassMethod: selector
			     withMethodFromClass: class];
		}
	}

	for (struct objc_method_list *methodlist = class->methodlist;
	    methodlist != NULL; methodlist = methodlist->next) {
		for (unsigned int i = 0; i < methodlist->count; i++) {
			SEL selector = (SEL)&methodlist->methods[i].sel;
	for (struct objc_method_list *methodList = class->methodList;
	    methodList != NULL; methodList = methodList->next) {
		for (unsigned int i = 0; i < methodList->count; i++) {
			SEL selector = (SEL)&methodList->methods[i].selector;

			/*
			 * Don't replace methods implemented in the receiving
			 * class.
			 */
			if ([self instanceMethodForSelector: selector] !=
			    [superclass instanceMethodForSelector: selector])

Modified src/runtime/ObjFW_RT.h from [9b214e845e] to [eecb74dd6c].

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







-
-
-
-
-
-
+
+
+
+
+
+

-
-
-
+
+
+


















-
-
+
+








-
-
+
+









-
-
-
-
+
+
+
+





-
+





-
+








struct objc_class {
	Class _Nonnull isa;
	Class _Nullable superclass;
	const char *_Nonnull name;
	unsigned long version;
	unsigned long info;
	long instance_size;
	struct objc_ivar_list *_Nullable ivars;
	struct objc_method_list *_Nullable methodlist;
	struct objc_dtable *_Nonnull dtable;
	Class _Nullable *_Nullable subclass_list;
	void *_Nullable sibling_class;
	long instanceSize;
	struct objc_ivar_list *_Nullable iVars;
	struct objc_method_list *_Nullable methodList;
	struct objc_dtable *_Nonnull DTable;
	Class _Nullable *_Nullable subclassList;
	void *_Nullable siblingClass;
	struct objc_protocol_list *_Nullable protocols;
	void *_Nullable gc_object_type;
	unsigned long abi_version;
	int32_t *_Nonnull *_Nullable ivar_offsets;
	void *_Nullable GCObjectType;
	unsigned long ABIVersion;
	int32_t *_Nonnull *_Nullable iVarOffsets;
	struct objc_property_list *_Nullable properties;
};

enum objc_class_info {
	OBJC_CLASS_INFO_CLASS	    = 0x001,
	OBJC_CLASS_INFO_METACLASS   = 0x002,
	OBJC_CLASS_INFO_NEW_ABI	    = 0x010,
	OBJC_CLASS_INFO_SETUP	    = 0x100,
	OBJC_CLASS_INFO_LOADED	    = 0x200,
	OBJC_CLASS_INFO_DTABLE	    = 0x400,
	OBJC_CLASS_INFO_INITIALIZED = 0x800
};

struct objc_object {
	Class _Nonnull isa;
};

struct objc_selector {
	uintptr_t uid;
	const char *_Nullable types;
	uintptr_t UID;
	const char *_Nullable typeEncoding;
};

struct objc_super {
	id __unsafe_unretained _Nullable self;
	Class _Nonnull cls;
};

struct objc_method {
	struct objc_selector sel;
	IMP _Nonnull imp;
	struct objc_selector selector;
	IMP _Nonnull implementation;
};

struct objc_method_list {
	struct objc_method_list *_Nullable next;
	unsigned int count;
	struct objc_method methods[1];
};

struct objc_category {
	const char *_Nonnull category_name;
	const char *_Nonnull class_name;
	struct objc_method_list *_Nullable instance_methods;
	struct objc_method_list *_Nullable class_methods;
	const char *_Nonnull categoryName;
	const char *_Nonnull className;
	struct objc_method_list *_Nullable instanceMethods;
	struct objc_method_list *_Nullable classMethods;
	struct objc_protocol_list *_Nullable protocols;
};

struct objc_ivar {
	const char *_Nonnull name;
	const char *_Nonnull type;
	const char *_Nonnull typeEncoding;
	unsigned int offset;
};

struct objc_ivar_list {
	unsigned int count;
	struct objc_ivar ivars[1];
	struct objc_ivar iVars[1];
};

enum objc_property_attributes {
	OBJC_PROPERTY_READONLY	= 0x01,
	OBJC_PROPERTY_GETTER	= 0x02,
	OBJC_PROPERTY_ASSIGN	= 0x04,
	OBJC_PROPERTY_READWRITE	= 0x08,
160
161
162
163
164
165
166
167

168
169
170

171
172
173
174
175
176
177
160
161
162
163
164
165
166

167
168
169

170
171
172
173
174
175
176
177







-
+


-
+







	OBJC_PROPERTY_WEAK		=  0x8,
	OBJC_PROPERTY_STRONG		= 0x10,
	OBJC_PROPERTY_UNSAFE_UNRETAINED = 0x20
};

struct objc_property {
	const char *_Nonnull name;
	unsigned char attributes, extended_attributes;
	unsigned char attributes, extendedAttributes;
	struct {
		const char *_Nullable name;
		const char *_Nullable type;
		const char *_Nullable typeEncoding;
	} getter, setter;
};

struct objc_property_list {
	unsigned int count;
	struct objc_property_list *_Nullable next;
	struct objc_property properties[1];
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
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







-
-
-
+
+
+

















-
-
+
+

-
+

-
+

-
+
+




-
-
+
+
+
+

-
+

-
+

-
-
-
-
-
+
+
+
+
+
+



-
-
-
-
+
+
+
+
+





-
+











-
+

-
+

-
+

-
+







{
@public
#else
typedef struct {
#endif
	Class _Nonnull isa;
	const char *_Nonnull name;
	struct objc_protocol_list *_Nullable protocol_list;
	struct objc_abi_method_description_list *_Nullable instance_methods;
	struct objc_abi_method_description_list *_Nullable class_methods;
	struct objc_protocol_list *_Nullable protocolList;
	struct objc_abi_method_description_list *_Nullable instanceMethods;
	struct objc_abi_method_description_list *_Nullable classMethods;
#ifdef __OBJC__
}
@end
#else
} Protocol;
#endif

struct objc_protocol_list {
	struct objc_protocol_list *_Nullable next;
	long count;
	Protocol *__unsafe_unretained _Nonnull list[1];
};

#ifdef __cplusplus
extern "C" {
#endif
extern SEL _Nonnull sel_registerName(const char *_Nonnull name);
extern const char *_Nonnull sel_getName(SEL _Nonnull sel);
extern bool sel_isEqual(SEL _Nonnull sel1, SEL _Nonnull sel2);
extern const char *_Nonnull sel_getName(SEL _Nonnull selector);
extern bool sel_isEqual(SEL _Nonnull selector1, SEL _Nonnull selector2);
extern Class _Nonnull objc_allocateClassPair(Class _Nullable superclass,
    const char *_Nonnull name, size_t extra_bytes);
    const char *_Nonnull name, size_t extraBytes);
extern void objc_registerClassPair(Class _Nonnull cls);
extern unsigned int objc_getClassList(Class _Nonnull *_Nullable buf,
extern unsigned int objc_getClassList(Class _Nonnull *_Nullable buffer,
    unsigned int count);
extern Class _Nonnull *_Nonnull objc_copyClassList(unsigned int *_Nullable len);
extern Class _Nonnull *_Nonnull objc_copyClassList(
    unsigned int *_Nullable length);
extern bool class_isMetaClass(Class _Nullable cls);
extern const char *_Nullable class_getName(Class _Nullable cls);
extern Class _Nullable class_getSuperclass(Class _Nullable cls);
extern unsigned long class_getInstanceSize(Class _Nullable cls);
extern bool class_respondsToSelector(Class _Nullable cls, SEL _Nonnull sel);
extern bool class_conformsToProtocol(Class _Nullable cls, Protocol *_Nonnull p);
extern bool class_respondsToSelector(Class _Nullable cls,
    SEL _Nonnull selector);
extern bool class_conformsToProtocol(Class _Nullable cls,
    Protocol *_Nonnull protocol);
extern IMP _Nullable class_getMethodImplementation(Class _Nullable cls,
    SEL _Nonnull sel);
    SEL _Nonnull selector);
extern IMP _Nullable class_getMethodImplementation_stret(Class _Nullable cls,
    SEL _Nonnull sel);
    SEL _Nonnull selector);
extern const char *_Nullable class_getMethodTypeEncoding(Class _Nullable cls,
    SEL _Nonnull sel);
extern bool class_addMethod(Class _Nonnull cls, SEL _Nonnull sel,
    IMP _Nonnull imp, const char *_Nullable types);
extern IMP _Nullable class_replaceMethod(Class _Nonnull cls, SEL _Nonnull sel,
    IMP _Nonnull imp, const char *_Nullable types);
    SEL _Nonnull selector);
extern bool class_addMethod(Class _Nonnull cls, SEL _Nonnull selector,
    IMP _Nonnull implementation, const char *_Nullable typeEncoding);
extern IMP _Nullable class_replaceMethod(Class _Nonnull cls,
    SEL _Nonnull selector, IMP _Nonnull implementation,
    const char *_Nullable typeEncoding);
extern Class _Nullable object_getClass(id _Nullable object);
extern Class _Nullable object_setClass(id _Nullable object, Class _Nonnull cls);
extern const char *_Nullable object_getClassName(id _Nullable object);
extern const char *_Nonnull protocol_getName(Protocol *_Nonnull p);
extern bool protocol_isEqual(Protocol *_Nonnull a, Protocol *_Nonnull b);
extern bool protocol_conformsToProtocol(Protocol *_Nonnull a,
    Protocol *_Nonnull b);
extern const char *_Nonnull protocol_getName(Protocol *_Nonnull protocol);
extern bool protocol_isEqual(Protocol *_Nonnull protocol1,
    Protocol *_Nonnull protocol2);
extern bool protocol_conformsToProtocol(Protocol *_Nonnull protocol1,
    Protocol *_Nonnull protocol2);
extern void objc_exit(void);
extern _Nullable objc_uncaught_exception_handler
    objc_setUncaughtExceptionHandler(
    objc_uncaught_exception_handler _Nullable handler);
extern void objc_setForwardHandler(IMP _Nullable forward,
    IMP _Nullable forward_stret);
    IMP _Nullable stretForward);
extern void objc_setEnumerationMutationHandler(
    objc_enumeration_mutation_handler _Nullable handler);
extern void objc_zero_weak_references(id _Nonnull value);

/*
 * Used by the compiler, but can also be called manually.
 *
 * These declarations are also required to prevent Clang's implicit
 * declarations which include __declspec(dllimport) on Windows.
 */
extern void __objc_exec_class(void *_Nonnull module);
extern IMP _Nonnull objc_msg_lookup(id _Nullable object, SEL _Nonnull sel);
extern IMP _Nonnull objc_msg_lookup(id _Nullable object, SEL _Nonnull selector);
extern IMP _Nonnull objc_msg_lookup_stret(id _Nullable object,
    SEL _Nonnull sel);
    SEL _Nonnull selector);
extern IMP _Nonnull objc_msg_lookup_super(struct objc_super *_Nonnull super,
    SEL _Nonnull sel);
    SEL _Nonnull selector);
extern IMP _Nonnull objc_msg_lookup_super_stret(
    struct objc_super *_Nonnull super, SEL _Nonnull sel);
    struct objc_super *_Nonnull super, SEL _Nonnull selector);
extern Class _Nullable objc_lookUpClass(const char *_Nonnull name);
extern Class _Nullable objc_getClass(const char *_Nonnull name);
extern Class _Nonnull objc_getRequiredClass(const char *_Nonnull name);
extern Class _Nullable objc_lookup_class(const char *_Nonnull name);
extern Class _Nonnull objc_get_class(const char *_Nonnull name);
extern void objc_exception_throw(id _Nullable object);
extern int objc_sync_enter(id _Nullable object);
283
284
285
286
287
288
289
290

291
292

293
294
295
296
297
298
299
288
289
290
291
292
293
294

295
296

297
298
299
300
301
302
303
304







-
+

-
+







extern void objc_enumerationMutation(id _Nonnull object);
#ifndef OBJC_NO_PERSONALITY_DECLARATION
/*
 * No objfw-defs.h or config.h is available for the installed runtime headers,
 * so we don't know which exceptions we have.
 */
extern int __gnu_objc_personality_v0(int version, int actions,
    uint64_t ex_class, void *_Nonnull ex, void *_Nonnull ctx);
    uint64_t exClass, void *_Nonnull ex, void *_Nonnull ctx);
extern int __gnu_objc_personality_sj0(int version, int actions,
    uint64_t ex_class, void *_Nonnull ex, void *_Nonnull ctx);
    uint64_t exClass, void *_Nonnull ex, void *_Nonnull ctx);
#endif
extern id _Nullable objc_retain(id _Nullable object);
extern id _Nullable objc_retainBlock(id _Nullable block);
extern id _Nullable objc_retainAutorelease(id _Nullable object);
extern void objc_release(id _Nullable object);
extern id _Nullable objc_autorelease(id _Nullable object);
extern id _Nullable objc_autoreleaseReturnValue(id _Nullable object);

Modified src/runtime/ObjFW_RT.sfd from [781d1021e4] to [fb5bdffa34].

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










-
-
-
-
+
+
+
+













-
-
+
+




















-
-
-
+
+
+

-
-
+
+




-
+

-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+


-
+






==base _ObjFWRTBase
==basetype struct Library *
==libname objfw_rt.library
==bias 30
==public
* Functions that are only for the linklib.
bool objc_init_m68k(unsigned int version, struct objc_libc *libc, FILE *stdout, FILE *stdin)(d0,a0,a1,a2)
* These have a built-in declaration in the compiler that does not use the
* registers and thus always need glue.
void __objc_exec_class_m68k(void *_Nonnull module)(a0)
IMP _Nonnull objc_msg_lookup_m68k(id _Nullable obj, SEL _Nonnull sel)(a0,a1)
IMP _Nonnull objc_msg_lookup_stret_m68k(id _Nullable obj, SEL _Nonnull sel)(a0,a1)
IMP _Nonnull objc_msg_lookup_super_m68k(struct objc_super *_Nonnull super, SEL _Nonnull sel)(a0,a1)
IMP _Nonnull objc_msg_lookup_super_stret_m68k(struct objc_super *_Nonnull super, SEL _Nonnull sel)(a0,a1)
IMP _Nonnull objc_msg_lookup_m68k(id _Nullable object, SEL _Nonnull selector)(a0,a1)
IMP _Nonnull objc_msg_lookup_stret_m68k(id _Nullable object, SEL _Nonnull selector)(a0,a1)
IMP _Nonnull objc_msg_lookup_super_m68k(struct objc_super *_Nonnull super, SEL _Nonnull selector)(a0,a1)
IMP _Nonnull objc_msg_lookup_super_stret_m68k(struct objc_super *_Nonnull super, SEL _Nonnull selector)(a0,a1)
Class _Nullable objc_lookUpClass_m68k(const char *_Nonnull name)(a0)
Class _Nullable objc_getClass_m68k(const char *_Nonnull name)(a0)
Class _Nonnull objc_getRequiredClass_m68k(const char *_Nonnull name)(a0)
Class _Nullable objc_lookup_class_m68k(const char *_Nonnull name)(a0)
Class _Nonnull objc_get_class_m68k(const char *_Nonnull name)(a0)
void objc_exception_throw_m68k(id _Nonnull object)(a0)
int objc_sync_enter_m68k(id _Nullable object)(a0)
int objc_sync_exit_m68k(id _Nullable object)(a0)
id objc_getProperty_m68k(id _Nonnull self, SEL _Nonnull _cmd, ptrdiff_t offset, bool atomic)(a0,a1,d0,d1)
void objc_setProperty_m68k(id _Nonnull self, SEL _Nonnull _cmd, ptrdiff_t offset, id value, bool atomic, signed char copy)(a0,a1,d0,a2,d1,d2)
void objc_getPropertyStruct_m68k(void *_Nonnull dest, const void *_Nonnull src, ptrdiff_t size, bool atomic, bool strong)(a0,a1,d0,d1,d2)
void objc_setPropertyStruct_m68k(void *_Nonnull dest, const void *_Nonnull src, ptrdiff_t size, bool atomic, bool strong)(a0,a1,d0,d1,d2)
void objc_enumerationMutation_m68k(id _Nonnull obj)(a0)
int __gnu_objc_personality_v0_m68k(int version, int actions, uint64_t *_Nonnull ex_class, void *_Nonnull ex, void *_Nonnull ctx)(d0,d1,d2,a0,a1)
int __gnu_objc_personality_sj0_m68k(int version, int actions, uint64_t *_Nonnull ex_class, void *_Nonnull ex, void *_Nonnull ctx)(d0,d1,d2,a0,a1)
int __gnu_objc_personality_v0_m68k(int version, int actions, uint64_t *_Nonnull exClass, void *_Nonnull ex, void *_Nonnull ctx)(d0,d1,d2,a0,a1)
int __gnu_objc_personality_sj0_m68k(int version, int actions, uint64_t *_Nonnull exClass, void *_Nonnull ex, void *_Nonnull ctx)(d0,d1,d2,a0,a1)
id _Nullable objc_retain_m68k(id _Nullable object)(a0)
id _Nullable objc_retainBlock_m68k(id _Nullable block)(a0)
id _Nullable objc_retainAutorelease_m68k(id _Nullable object)(a0)
void objc_release_m68k(id _Nullable object)(a0)
id _Nullable objc_autorelease_m68k(id _Nullable object)(a0)
id _Nullable objc_autoreleaseReturnValue_m68k(id _Nullable object)(a0)
id _Nullable objc_retainAutoreleaseReturnValue_m68k(id _Nullable object)(a0)
id _Nullable objc_retainAutoreleasedReturnValue_m68k(id _Nullable object)(a0)
id _Nullable objc_storeStrong_m68k(id _Nullable *_Nonnull object, id _Nullable value)(a0/a1)
id _Nullable objc_storeWeak_m68k(id _Nullable *_Nonnull object, id _Nullable value)(a0,a1)
id _Nullable objc_loadWeakRetained_m68k(id _Nullable *_Nonnull object)(a0)
id _Nullable objc_initWeak_m68k(id _Nullable *_Nonnull object, id _Nullable value)(a0,a1)
void objc_destroyWeak_m68k(id _Nullable *_Nonnull object)(a0)
id _Nullable objc_loadWeak_m68k(id _Nullable *_Nonnull object)(a0)
void objc_copyWeak_m68k(id _Nullable *_Nonnull dest, id _Nullable *_Nonnull src)(a0,a1)
void objc_moveWeak_m68k(id _Nullable *_Nonnull dest, id _Nullable *_Nonnull src)(a0,a1)
* These only need glue on MorphOS. As none of them are functions that are used
* in hot paths, it's easier to also use the glue on AmigaOS 3, which also has
* the benefit of having all __saveds in a single place.
SEL _Nonnull sel_registerName_m68k(const char *_Nonnull name)(a0)
const char *_Nonnull sel_getName_m68k(SEL _Nonnull sel)(a0)
bool sel_isEqual_m68k(SEL _Nonnull sel1, SEL _Nonnull sel2)(a0,a1)
Class _Nonnull objc_allocateClassPair_m68k(Class _Nullable superclass, const char *_Nonnull name, size_t extra_bytes)(a0,a1,d0)
const char *_Nonnull sel_getName_m68k(SEL _Nonnull selector)(a0)
bool sel_isEqual_m68k(SEL _Nonnull selector1, SEL _Nonnull selector2)(a0,a1)
Class _Nonnull objc_allocateClassPair_m68k(Class _Nullable superclass, const char *_Nonnull name, size_t extraBytes)(a0,a1,d0)
void objc_registerClassPair_m68k(Class _Nonnull cls)(a0)
unsigned int objc_getClassList_m68k(Class _Nonnull *_Nullable buf, unsigned int count)(a0,d0)
Class _Nonnull *_Nonnull objc_copyClassList_m68k(unsigned int *_Nullable len)(a0)
unsigned int objc_getClassList_m68k(Class _Nonnull *_Nullable buffer, unsigned int count)(a0,d0)
Class _Nonnull *_Nonnull objc_copyClassList_m68k(unsigned int *_Nullable length)(a0)
bool class_isMetaClass_m68k(Class _Nullable cls)(a0)
const char *_Nullable class_getName_m68k(Class _Nullable cls)(a0)
Class _Nullable class_getSuperclass_m68k(Class _Nullable cls)(a0)
unsigned long class_getInstanceSize_m68k(Class _Nullable cls)(a0)
bool class_respondsToSelector_m68k(Class _Nullable cls, SEL _Nonnull sel)(a0,a1)
bool class_respondsToSelector_m68k(Class _Nullable cls, SEL _Nonnull selector)(a0,a1)
bool class_conformsToProtocol_m68k(Class _Nullable cls, Protocol *_Nonnull p)(a0,a1)
IMP _Nullable class_getMethodImplementation_m68k(Class _Nullable cls, SEL _Nonnull sel)(a0,a1)
IMP _Nullable class_getMethodImplementation_stret_m68k(Class _Nullable cls, SEL _Nonnull sel)(a0,a1)
const char *_Nullable class_getMethodTypeEncoding_m68k(Class _Nullable cls, SEL _Nonnull sel)(a0,a1)
bool class_addMethod_m68k(Class _Nonnull cls, SEL _Nonnull sel, IMP _Nonnull imp, const char *_Nullable types)(a0,a1,a2,a3)
IMP _Nullable class_replaceMethod_m68k(Class _Nonnull cls, SEL _Nonnull sel, IMP _Nonnull imp, const char *_Nullable types)(a0,a1,a2,a3)
Class _Nullable object_getClass_m68k(id _Nullable obj)(a0)
Class _Nullable object_setClass_m68k(id _Nullable obj, Class _Nonnull cls)(a0,a1)
const char *_Nullable object_getClassName_m68k(id _Nullable obj)(a0)
const char *_Nonnull protocol_getName_m68k(Protocol *_Nonnull p)(a0)
bool protocol_isEqual_m68k(Protocol *_Nonnull a, Protocol *_Nonnull b)(a0,a1)
bool protocol_conformsToProtocol_m68k(Protocol *_Nonnull a, Protocol *_Nonnull b)(a0,a1)
IMP _Nullable class_getMethodImplementation_m68k(Class _Nullable cls, SEL _Nonnull selector)(a0,a1)
IMP _Nullable class_getMethodImplementation_stret_m68k(Class _Nullable cls, SEL _Nonnull selector)(a0,a1)
const char *_Nullable class_getMethodTypeEncoding_m68k(Class _Nullable cls, SEL _Nonnull selector)(a0,a1)
bool class_addMethod_m68k(Class _Nonnull cls, SEL _Nonnull selector, IMP _Nonnull implementation, const char *_Nullable typeEncoding)(a0,a1,a2,a3)
IMP _Nullable class_replaceMethod_m68k(Class _Nonnull cls, SEL _Nonnull selector, IMP _Nonnull implementation, const char *_Nullable typeEncoding)(a0,a1,a2,a3)
Class _Nullable object_getClass_m68k(id _Nullable object)(a0)
Class _Nullable object_setClass_m68k(id _Nullable object, Class _Nonnull cls)(a0,a1)
const char *_Nullable object_getClassName_m68k(id _Nullable object)(a0)
const char *_Nonnull protocol_getName_m68k(Protocol *_Nonnull protocol)(a0)
bool protocol_isEqual_m68k(Protocol *_Nonnull protocol1, Protocol *_Nonnull protocol2)(a0,a1)
bool protocol_conformsToProtocol_m68k(Protocol *_Nonnull protocol1, Protocol *_Nonnull protocol2)(a0,a1)
void objc_exit_m68k(void)()
_Nullable objc_uncaught_exception_handler objc_setUncaughtExceptionHandler_m68k(objc_uncaught_exception_handler _Nullable handler)(a0)
void objc_setForwardHandler_m68k(IMP _Nullable forward, IMP _Nullable forward_stret)(a0,a1)
void objc_setForwardHandler_m68k(IMP _Nullable forward, IMP _Nullable stretForward)(a0,a1)
void objc_setEnumerationMutationHandler_m68k(objc_enumeration_mutation_handler _Nullable handler)(a0)
void objc_zero_weak_references_m68k(id _Nonnull value)(a0)
* SysV functions for MorphOS could be added here for performance. Having them
* in addition to the m68k functions allows m68k applications to call into the
* PPC library, while native code can use the SysV functions.
==end

Modified src/runtime/amiga-glue.m from [9ce1f82f2b] to [850cd5db39].

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







-
-
+
+

-
+





-
-
+
+

-
+






-
+

-
+






-
+

-
+








	__objc_exec_class(module);
}

IMP __saveds
objc_msg_lookup_m68k(void)
{
	OBJC_M68K_ARG(id, obj, a0)
	OBJC_M68K_ARG(SEL, sel, a1)
	OBJC_M68K_ARG(id, object, a0)
	OBJC_M68K_ARG(SEL, selector, a1)

	return objc_msg_lookup(obj, sel);
	return objc_msg_lookup(object, selector);
}

IMP __saveds
objc_msg_lookup_stret_m68k(void)
{
	OBJC_M68K_ARG(id, obj, a0)
	OBJC_M68K_ARG(SEL, sel, a1)
	OBJC_M68K_ARG(id, object, a0)
	OBJC_M68K_ARG(SEL, selector, a1)

	return objc_msg_lookup_stret(obj, sel);
	return objc_msg_lookup_stret(object, selector);
}

IMP __saveds
objc_msg_lookup_super_m68k(void)
{
	OBJC_M68K_ARG(struct objc_super *, super, a0)
	OBJC_M68K_ARG(SEL, sel, a1)
	OBJC_M68K_ARG(SEL, selector, a1)

	return objc_msg_lookup_super(super, sel);
	return objc_msg_lookup_super(super, selector);
}

IMP __saveds
objc_msg_lookup_super_stret_m68k(void)
{
	OBJC_M68K_ARG(struct objc_super *, super, a0)
	OBJC_M68K_ARG(SEL, sel, a1)
	OBJC_M68K_ARG(SEL, selector, a1)

	return objc_msg_lookup_super_stret(super, sel);
	return objc_msg_lookup_super_stret(super, selector);
}

Class __saveds
objc_lookUpClass_m68k(void)
{
	OBJC_M68K_ARG(const char *, name, a0)

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







-
+

-
+








-
+



-
+













-
+



-
+








	objc_setPropertyStruct(dest, src, size, atomic, strong);
}

void __saveds
objc_enumerationMutation_m68k(void)
{
	OBJC_M68K_ARG(id, obj, a0)
	OBJC_M68K_ARG(id, object, a0)

	objc_enumerationMutation(obj);
	objc_enumerationMutation(object);
}

int __saveds
__gnu_objc_personality_v0_m68k(void)
{
#ifndef HAVE_SJLJ_EXCEPTIONS
	OBJC_M68K_ARG(int, version, d0)
	OBJC_M68K_ARG(int, actions, d1)
	OBJC_M68K_ARG(uint64_t *, ex_class, d2)
	OBJC_M68K_ARG(uint64_t *, exClass, d2)
	OBJC_M68K_ARG(void *, ex, a0)
	OBJC_M68K_ARG(void *, ctx, a1)

	return __gnu_objc_personality_v0(version, actions, *ex_class, ex, ctx);
	return __gnu_objc_personality_v0(version, actions, *exClass, ex, ctx);
#else
	abort();

	OF_UNREACHABLE
#endif
}

int __saveds
__gnu_objc_personality_sj0_m68k(void)
{
#ifdef HAVE_SJLJ_EXCEPTIONS
	OBJC_M68K_ARG(int, version, d0)
	OBJC_M68K_ARG(int, actions, d1)
	OBJC_M68K_ARG(uint64_t *, ex_class, d2)
	OBJC_M68K_ARG(uint64_t *, exClass, d2)
	OBJC_M68K_ARG(void *, ex, a0)
	OBJC_M68K_ARG(void *, ctx, a1)

	return __gnu_objc_personality_sj0(version, actions, *ex_class, ex, ctx);
	return __gnu_objc_personality_sj0(version, actions, *exClass, ex, ctx);
#else
	abort();

	OF_UNREACHABLE
#endif
}

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







-
+

-
+





-
-
+
+

-
+







-
+

-
+













-
+


-
+





-
+

-
+








	return sel_registerName(name);
}

const char *__saveds
sel_getName_m68k(void)
{
	OBJC_M68K_ARG(SEL, sel, a0)
	OBJC_M68K_ARG(SEL, selector, a0)

	return sel_getName(sel);
	return sel_getName(selector);
}

bool __saveds
sel_isEqual_m68k(void)
{
	OBJC_M68K_ARG(SEL, sel1, a0)
	OBJC_M68K_ARG(SEL, sel2, a1)
	OBJC_M68K_ARG(SEL, selector1, a0)
	OBJC_M68K_ARG(SEL, selector2, a1)

	return sel_isEqual(sel1, sel2);
	return sel_isEqual(selector1, selector2);
}

Class __saveds
objc_allocateClassPair_m68k(void)
{
	OBJC_M68K_ARG(Class, superclass, a0)
	OBJC_M68K_ARG(const char *, name, a1)
	OBJC_M68K_ARG(size_t, extra_bytes, d0)
	OBJC_M68K_ARG(size_t, extraBytes, d0)

	return objc_allocateClassPair(superclass, name, extra_bytes);
	return objc_allocateClassPair(superclass, name, extraBytes);
}

void __saveds
objc_registerClassPair_m68k(void)
{
	OBJC_M68K_ARG(Class, cls, a0)

	objc_registerClassPair(cls);
}

unsigned int __saveds
objc_getClassList_m68k(void)
{
	OBJC_M68K_ARG(Class *, buf, a0)
	OBJC_M68K_ARG(Class *, buffer, a0)
	OBJC_M68K_ARG(unsigned int, count, d0)

	return objc_getClassList(buf, count);
	return objc_getClassList(buffer, count);
}

Class *__saveds
objc_copyClassList_m68k(void)
{
	OBJC_M68K_ARG(unsigned int *, len, a0)
	OBJC_M68K_ARG(unsigned int *, length, a0)

	return objc_copyClassList(len);
	return objc_copyClassList(length);
}

bool __saveds
class_isMetaClass_m68k(void)
{
	OBJC_M68K_ARG(Class, cls, a0)

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

494
495
496
497
498
499
500
501
502



503
504

505
506
507
508
509
510
511
512
513



514
515

516
517
518
519
520
521
522
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
494
495
496
497
498
499



500
501
502
503

504
505
506
507
508
509
510



511
512
513
514

515
516
517
518
519
520
521
522







-
+

-
+






-
+

-
+






-
+

-
+






-
+

-
+






-
+

-
+






-
-
-
+
+
+

-
+






-
-
-
+
+
+

-
+







	return class_getInstanceSize(cls);
}

bool __saveds
class_respondsToSelector_m68k(void)
{
	OBJC_M68K_ARG(Class, cls, a0)
	OBJC_M68K_ARG(SEL, sel, a1)
	OBJC_M68K_ARG(SEL, selector, a1)

	return class_respondsToSelector(cls, sel);
	return class_respondsToSelector(cls, selector);
}

bool __saveds
class_conformsToProtocol_m68k(void)
{
	OBJC_M68K_ARG(Class, cls, a0)
	OBJC_M68K_ARG(Protocol *, p, a1)
	OBJC_M68K_ARG(Protocol *, protocol, a1)

	return class_conformsToProtocol(cls, p);
	return class_conformsToProtocol(cls, protocol);
}

IMP __saveds
class_getMethodImplementation_m68k(void)
{
	OBJC_M68K_ARG(Class, cls, a0)
	OBJC_M68K_ARG(SEL, sel, a1)
	OBJC_M68K_ARG(SEL, selector, a1)

	return class_getMethodImplementation(cls, sel);
	return class_getMethodImplementation(cls, selector);
}

IMP __saveds
class_getMethodImplementation_stret_m68k(void)
{
	OBJC_M68K_ARG(Class, cls, a0)
	OBJC_M68K_ARG(SEL, sel, a1)
	OBJC_M68K_ARG(SEL, selector, a1)

	return class_getMethodImplementation_stret(cls, sel);
	return class_getMethodImplementation_stret(cls, selector);
}

const char *__saveds
class_getMethodTypeEncoding_m68k(void)
{
	OBJC_M68K_ARG(Class, cls, a0)
	OBJC_M68K_ARG(SEL, sel, a1)
	OBJC_M68K_ARG(SEL, selector, a1)

	return class_getMethodTypeEncoding(cls, sel);
	return class_getMethodTypeEncoding(cls, selector);
}

bool __saveds
class_addMethod_m68k(void)
{
	OBJC_M68K_ARG(Class, cls, a0)
	OBJC_M68K_ARG(SEL, sel, a1)
	OBJC_M68K_ARG(IMP, imp, a2)
	OBJC_M68K_ARG(const char *, types, a3)
	OBJC_M68K_ARG(SEL, selector, a1)
	OBJC_M68K_ARG(IMP, implementation, a2)
	OBJC_M68K_ARG(const char *, typeEncoding, a3)

	return class_addMethod(cls, sel, imp, types);
	return class_addMethod(cls, selector, implementation, typeEncoding);
}

IMP __saveds
class_replaceMethod_m68k(void)
{
	OBJC_M68K_ARG(Class, cls, a0)
	OBJC_M68K_ARG(SEL, sel, a1)
	OBJC_M68K_ARG(IMP, imp, a2)
	OBJC_M68K_ARG(const char *, types, a3)
	OBJC_M68K_ARG(SEL, selector, a1)
	OBJC_M68K_ARG(IMP, implementation, a2)
	OBJC_M68K_ARG(const char *, typeEncoding, a3)

	return class_replaceMethod(cls, sel, imp, types);
	return class_replaceMethod(cls, selector, implementation, typeEncoding);
}

Class __saveds
object_getClass_m68k(void)
{
	OBJC_M68K_ARG(id, object, a0)

539
540
541
542
543
544
545
546

547
548

549
550
551
552
553
554
555


556
557

558
559
560
561
562
563
564


565
566

567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587

588
589

590
591
592
593
594
595
596
539
540
541
542
543
544
545

546
547

548
549
550
551
552
553


554
555
556

557
558
559
560
561
562


563
564
565

566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586

587
588

589
590
591
592
593
594
595
596







-
+

-
+





-
-
+
+

-
+





-
-
+
+

-
+




















-
+

-
+








	return object_getClassName(object);
}

const char *__saveds
protocol_getName_m68k(void)
{
	OBJC_M68K_ARG(Protocol *, p, a0)
	OBJC_M68K_ARG(Protocol *, protocol, a0)

	return protocol_getName(p);
	return protocol_getName(protocol);
}

bool __saveds
protocol_isEqual_m68k(void)
{
	OBJC_M68K_ARG(Protocol *, a, a0)
	OBJC_M68K_ARG(Protocol *, b, a1)
	OBJC_M68K_ARG(Protocol *, protocol1, a0)
	OBJC_M68K_ARG(Protocol *, protocol2, a1)

	return protocol_isEqual(a, b);
	return protocol_isEqual(protocol1, protocol2);
}

bool __saveds
protocol_conformsToProtocol_m68k(void)
{
	OBJC_M68K_ARG(Protocol *, a, a0)
	OBJC_M68K_ARG(Protocol *, b, a1)
	OBJC_M68K_ARG(Protocol *, protocol1, a0)
	OBJC_M68K_ARG(Protocol *, protocol2, a1)

	return protocol_conformsToProtocol(a, b);
	return protocol_conformsToProtocol(protocol1, protocol2);
}

void __saveds
objc_exit_m68k(void)
{
	objc_exit();
}

objc_uncaught_exception_handler __saveds
objc_setUncaughtExceptionHandler_m68k(void)
{
	OBJC_M68K_ARG(objc_uncaught_exception_handler, handler, a0)

	return objc_setUncaughtExceptionHandler(handler);
}

void __saveds
objc_setForwardHandler_m68k(void)
{
	OBJC_M68K_ARG(IMP, forward, a0)
	OBJC_M68K_ARG(IMP, forward_stret, a1)
	OBJC_M68K_ARG(IMP, stretForward, a1)

	objc_setForwardHandler(forward, forward_stret);
	objc_setForwardHandler(forward, stretForward);
}

void __saveds
objc_setEnumerationMutationHandler_m68k(void)
{
	OBJC_M68K_ARG(objc_enumeration_mutation_handler, handler, a0)

Modified src/runtime/amiga-library.m from [78eee437a1] to [9f8ec83747].

46
47
48
49
50
51
52
53

54
55

56
57
58
59
60
61
62
46
47
48
49
50
51
52

53
54

55
56
57
58
59
60
61
62







-
+

-
+







_start()
{
	return -1;
}

struct ObjFWRTBase {
	struct Library library;
	void *seg_list;
	void *segList;
	struct ObjFWRTBase *parent;
	char *data_seg;
	char *dataSeg;
	bool initialized;
};

#ifdef OF_AMIGAOS_M68K
extern uintptr_t __CTOR_LIST__[];
extern const void *_EH_FRAME_BEGINS__;
extern void *_EH_FRAME_OBJECTS__;
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
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







-
+

-
+




-
+





-
+



-
+



-
+

-
+




-
+








-
+




-
+



-
+

-
+




-
+





-
+



-
+




-
+
-




-
+





-
+



-
+

-
+










-
+







    "	blr\n"
    ".type __restore_r13, @function\n"
    ".size __restore_r13, .-__restore_r13"
);
#endif

static OF_INLINE char *
get_data_seg(void)
getDataSeg(void)
{
	char *data_seg;
	char *dataSeg;

#if defined(OF_AMIGAOS_M68K)
	__asm__ (
	    "move.l	#___a4_init, %0"
	    : "=r"(data_seg)
	    : "=r"(dataSeg)
	);
#elif defined(OF_MORPHOS)
	__asm__ (
	    "lis	%0, __r13_init@ha\n\t"
	    "la		%0, __r13_init@l(%0)"
	    : "=r"(data_seg)
	    : "=r"(dataSeg)
	);
#endif

	return data_seg;
	return dataSeg;
}

static OF_INLINE size_t
get_data_size(void)
getDataSize(void)
{
	size_t data_size;
	size_t dataSize;

#if defined(OF_AMIGAOS_M68K)
	__asm__ (
	    "move.l	#___data_size, %0"
	    : "=r"(data_size)
	    : "=r"(dataSize)
	);
#elif defined(OF_MORPHOS)
	__asm__ (
	    "lis	%0, __sdata_size@ha\n\t"
	    "la		%0, __sdata_size@l(%0)\n\t"
	    "lis	%%r9, __sbss_size@ha\n\t"
	    "la		%%r9, __sbss_size@l(%%r9)\n\t"
	    "add	%0, %0, %%r9"
	    : "=r"(data_size)
	    : "=r"(dataSize)
	    :: "r9"
	);
#endif

	return data_size;
	return dataSize;
}

static OF_INLINE size_t *
get_datadata_relocs(void)
getDataDataRelocs(void)
{
	size_t *datadata_relocs;
	size_t *dataDataRelocs;

#if defined(OF_AMIGAOS_M68K)
	__asm__ (
	    "move.l	#___datadata_relocs, %0"
	    : "=r"(datadata_relocs)
	    : "=r"(dataDataRelocs)
	);
#elif defined(OF_MORPHOS)
	__asm__ (
	    "lis	%0, __datadata_relocs@ha\n\t"
	    "la		%0, __datadata_relocs@l(%0)\n\t"
	    : "=r"(datadata_relocs)
	    : "=r"(dataDataRelocs)
	);
#endif

	return datadata_relocs;
	return dataDataRelocs;
}

static struct Library *
lib_init(struct ObjFWRTBase *base OBJC_M68K_REG(d0),
    void *seg_list OBJC_M68K_REG(a0),
    void *segList OBJC_M68K_REG(a0), struct ExecBase *sysBase OBJC_M68K_REG(a6))
    struct ExecBase *sys_base OBJC_M68K_REG(a6))
{
#if defined(OF_AMIGAOS_M68K)
	__asm__ __volatile__ (
	    "move.l	a6, _SysBase"
	    :: "a"(sys_base)
	    :: "a"(sysBase)
	);
#elif defined(OF_MORPHOS)
	__asm__ __volatile__ (
	    "lis	%%r9, SysBase@ha\n\t"
	    "stw	%0, SysBase@l(%%r9)"
	    :: "r"(sys_base) : "r9"
	    :: "r"(sysBase) : "r9"
	);
#endif

	base->seg_list = seg_list;
	base->segList = segList;
	base->parent = NULL;
	base->data_seg = get_data_seg();
	base->dataSeg = getDataSeg();

	return &base->library;
}

struct Library *__saveds
lib_open(void)
{
	OBJC_M68K_ARG(struct ObjFWRTBase *, base, a6)

	struct ObjFWRTBase *child;
	size_t data_size, *datadata_relocs;
	size_t dataSize, *dataDataRelocs;
	ptrdiff_t displacement;

	if (base->parent != NULL)
		return NULL;

	base->library.lib_OpenCnt++;
	base->library.lib_Flags &= ~LIBF_DELEXP;
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
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







-
+

-
+






-
+

-
-
+
+

-
-
+
+

-
+







-
+











-
+





-
+







	    base->library.lib_NegSize + base->library.lib_PosSize);

	child = (struct ObjFWRTBase *)
	    ((char *)child + base->library.lib_NegSize);
	child->library.lib_OpenCnt = 1;
	child->parent = base;

	data_size = get_data_size();
	dataSize = getDataSize();

	if ((child->data_seg = AllocMem(data_size, MEMF_ANY)) == NULL) {
	if ((child->dataSeg = AllocMem(dataSize, MEMF_ANY)) == NULL) {
		FreeMem((char *)child - child->library.lib_NegSize,
		    child->library.lib_NegSize + child->library.lib_PosSize);
		base->library.lib_OpenCnt--;
		return NULL;
	}

	memcpy(child->data_seg, base->data_seg - DATA_OFFSET, data_size);
	memcpy(child->dataSeg, base->dataSeg - DATA_OFFSET, dataSize);

	datadata_relocs = get_datadata_relocs();
	displacement = child->data_seg - (base->data_seg - DATA_OFFSET);
	dataDataRelocs = getDataDataRelocs();
	displacement = child->dataSeg - (base->dataSeg - DATA_OFFSET);

	for (size_t i = 1; i <= datadata_relocs[0]; i++)
		*(long *)(child->data_seg + datadata_relocs[i]) += displacement;
	for (size_t i = 1; i <= dataDataRelocs[0]; i++)
		*(long *)(child->dataSeg + dataDataRelocs[i]) += displacement;

	child->data_seg += DATA_OFFSET;
	child->dataSeg += DATA_OFFSET;

	return &child->library;
}

static void *
expunge(struct ObjFWRTBase *base)
{
	void *seg_list;
	void *segList;

	if (base->parent != NULL) {
		base->parent->library.lib_Flags |= LIBF_DELEXP;
		return 0;
	}

	if (base->library.lib_OpenCnt > 0) {
		base->library.lib_Flags |= LIBF_DELEXP;
		return 0;
	}

	seg_list = base->seg_list;
	segList = base->segList;

	Remove(&base->library.lib_Node);
	FreeMem((char *)base - base->library.lib_NegSize,
	    base->library.lib_NegSize + base->library.lib_PosSize);

	return seg_list;
	return segList;
}

static void *__saveds
lib_expunge(void)
{
	OBJC_M68K_ARG(struct ObjFWRTBase *, base, a6)

352
353
354
355
356
357
358
359

360
361
362
363
364
365
366
351
352
353
354
355
356
357

358
359
360
361
362
363
364
365







-
+







			for (size_t i = 1; i <= (size_t)_EH_FRAME_BEGINS__; i++)
				libc.__deregister_frame_info(
				    (&_EH_FRAME_BEGINS__)[i]);
#endif

		parent = base->parent;

		FreeMem(base->data_seg - DATA_OFFSET, get_data_size());
		FreeMem(base->dataSeg - DATA_OFFSET, getDataSize());
		FreeMem((char *)base - base->library.lib_NegSize,
		    base->library.lib_NegSize + base->library.lib_PosSize);

		base = parent;
	}

	if (--base->library.lib_OpenCnt == 0 &&
554
555
556
557
558
559
560
561

562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582




583
584
585


586
587
588

589
590
591
592
593
594
595
553
554
555
556
557
558
559

560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577




578
579
580
581
582


583
584
585
586

587
588
589
590
591
592
593
594







-
+

















-
-
-
-
+
+
+
+

-
-
+
+


-
+







{
	libc._Unwind_Resume(ex);
}
#endif

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
static CONST_APTR function_table[] = {
static CONST_APTR functionTable[] = {
#ifdef OF_MORPHOS
	(CONST_APTR)FUNCARRAY_BEGIN,
	(CONST_APTR)FUNCARRAY_32BIT_NATIVE,
#endif
	(CONST_APTR)lib_open,
	(CONST_APTR)lib_close,
	(CONST_APTR)lib_expunge,
	(CONST_APTR)lib_null,
#include "amiga-library-functable.inc"
	(CONST_APTR)-1,
#ifdef OF_MORPHOS
	(CONST_APTR)FUNCARRAY_END
#endif
};
#pragma GCC diagnostic pop

static struct {
	ULONG data_size;
	CONST_APTR *function_table;
	ULONG *data_table;
	struct Library *(*init_func)(
	ULONG dataSize;
	CONST_APTR *functionTable;
	ULONG *dataTable;
	struct Library *(*initFunc)(
	    struct ObjFWRTBase *base OBJC_M68K_REG(d0),
	    void *seg_list OBJC_M68K_REG(a0),
	    struct ExecBase *exec_base OBJC_M68K_REG(a6));
	    void *segList OBJC_M68K_REG(a0),
	    struct ExecBase *execBase OBJC_M68K_REG(a6));
} init_table = {
	sizeof(struct ObjFWRTBase),
	function_table,
	functionTable,
	NULL,
	lib_init
};

struct Resident resident = {
	.rt_MatchWord = RTC_MATCHWORD,
	.rt_MatchTag = &resident,

Modified src/runtime/arc.m from [979b29ef70] to [7827e43c55].

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







-
+





-
+






-
+








static struct objc_hashtable *hashtable;
#ifdef OF_HAVE_THREADS
static of_spinlock_t spinlock;
#endif

static uint32_t
obj_hash(const void *obj)
hash(const void *obj)
{
	return (uint32_t)(uintptr_t)obj;
}

static bool
obj_equal(const void *obj1, const void *obj2)
equal(const void *obj1, const void *obj2)
{
	return (obj1 == obj2);
}

OF_CONSTRUCTOR()
{
	hashtable = objc_hashtable_new(obj_hash, obj_equal, 2);
	hashtable = objc_hashtable_new(hash, equal, 2);

#ifdef OF_HAVE_THREADS
	if (!of_spinlock_new(&spinlock))
		OBJC_ERROR("Failed to create spinlock!")
#endif
}

Modified src/runtime/category.m from [35a70014d0] to [ca01b62fa9].

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







-
+


-
+

-
-
-
-
-
+
+
+
+
+
+

-
-
-
-
-
+
+
+
+
+



-
+

-
-
+
+

-
-
+
+


-
-
+
+

-
-
+
+


-
+

-
+


-
+
+

-
-
-
+
+
+
+









+
-
+

-
+

-
-
-
+
+
+










-
-
+
+

-
-
-
+
+
+






-
+


-
+






-
+


-
-
-
+
+
+

-
-
+
+

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

#import "ObjFW_RT.h"
#import "private.h"

static struct objc_hashtable *categories = NULL;
static struct objc_hashtable *categoriesMap = NULL;

static void
register_selectors(struct objc_abi_category *cat)
registerSelectors(struct objc_abi_category *category)
{
	for (struct objc_abi_method_list *ml = cat->instance_methods;
	    ml != NULL; ml = ml->next)
		for (unsigned int i = 0; i < ml->count; i++)
			objc_register_selector(
			    (struct objc_abi_selector *)&ml->methods[i]);
	for (struct objc_abi_method_list *methodList =
	    category->instanceMethods; methodList != NULL;
	    methodList = methodList->next)
		for (unsigned int i = 0; i < methodList->count; i++)
			objc_register_selector((struct objc_abi_selector *)
			    &methodList->methods[i]);

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

static void
register_category(struct objc_abi_category *cat)
registerCategory(struct objc_abi_category *category)
{
	struct objc_abi_category **cats;
	Class cls = objc_classname_to_class(cat->class_name, false);
	struct objc_abi_category **categories;
	Class cls = objc_classname_to_class(category->className, false);

	if (categories == NULL)
		categories = objc_hashtable_new(
	if (categoriesMap == NULL)
		categoriesMap = objc_hashtable_new(
		    objc_hash_string, objc_equal_string, 2);

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

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

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

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

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

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

		return;
	}

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

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

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

void
objc_register_all_categories(struct objc_abi_symtab *symtab)
{
	struct objc_abi_category **cats =
	    (struct objc_abi_category **)symtab->defs + symtab->cls_def_cnt;
	struct objc_abi_category **categories =
	    (struct objc_abi_category **)symtab->defs + symtab->classDefsCount;

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

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

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

void
objc_unregister_all_categories(void)
{
	if (categories == NULL)
	if (categoriesMap == NULL)
		return;

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

	objc_hashtable_free(categories);
	categories = NULL;
	objc_hashtable_free(categoriesMap);
	categoriesMap = NULL;
}

Modified src/runtime/class.m from [241b0f4d77] to [66376a6ccb].

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







-
-
-
-
-
-
+
+
+
+
+
+


-
+







-
-
+
+

-
-
+
+


-
+







#include <string.h>
#include <limits.h>

#import "ObjFW_RT.h"
#import "private.h"

static struct objc_hashtable *classes = NULL;
static unsigned classes_cnt = 0;
static Class *load_queue = NULL;
static size_t load_queue_cnt = 0;
static struct objc_dtable *empty_dtable = NULL;
static unsigned lookups_till_fast_path = 128;
static struct objc_sparsearray *fast_path = NULL;
static unsigned classesCount = 0;
static Class *loadQueue = NULL;
static size_t loadQueueCount = 0;
static struct objc_dtable *emptyDTable = NULL;
static unsigned lookupsUntilFastPath = 128;
static struct objc_sparsearray *fastPath = NULL;

static void
register_class(struct objc_abi_class *cls)
registerClass(struct objc_abi_class *cls)
{
	if (classes == NULL)
		classes = objc_hashtable_new(
		    objc_hash_string, objc_equal_string, 2);

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

	if (empty_dtable == NULL)
		empty_dtable = objc_dtable_new();
	if (emptyDTable == NULL)
		emptyDTable = objc_dtable_new();

	cls->dtable = empty_dtable;
	cls->metaclass->dtable = empty_dtable;
	cls->DTable = emptyDTable;
	cls->metaclass->DTable = emptyDTable;

	if (strcmp(cls->name, "Protocol") != 0)
		classes_cnt++;
		classesCount++;
}

bool
class_registerAlias_np(Class cls, const char *name)
{
	objc_global_mutex_lock();

67
68
69
70
71
72
73
74

75
76

77
78
79
80
81





82
83
84
85
86
87
88
67
68
69
70
71
72
73

74
75

76
77




78
79
80
81
82
83
84
85
86
87
88
89







-
+

-
+

-
-
-
-
+
+
+
+
+








	objc_global_mutex_unlock();

	return YES;
}

static void
register_selectors(struct objc_abi_class *cls)
registerSelectors(struct objc_abi_class *cls)
{
	struct objc_abi_method_list *ml;
	struct objc_abi_method_list *methodList;

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

Class
objc_classname_to_class(const char *name, bool cache)
{
	Class cls;

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
494
495
496
497
498

499
500
501
502
503
504
505
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
494
495
496
497
498
499
500
501
502
503
504
505

506
507
508
509
510
511
512
513







-
-
+
+









-
-
+
+

-
-
+
+







-
+



-
-
-
-
-
-
+
+
+
+
+
+
+



-
+



-
-
-
-
+
+
+
+
+






-
+





-
+

-
+







-
-
+




-
-
+
+


-
+

-
-
-
-
-
+
+
+
+
+
+

-
-
-
-
+
+
+
+
+
+

-
-
-
-
-
+
+
+
+
+
+
+
+



-
-
+
+




-
+



-
-
+
+




-
-
+
+




-
+

-
-
+
+

-
+



-
-
+
+




-
+




-
+


-
+


-
+

-
-
-
-
-
-
+
+
+
+
+
+



-
-
+
+



-
+












-
+







-
-
+
+



-
+






-
+





-
+














-
+




















-
+






-
+





-
+

-
-
+
+

-
-
+
+

-
+

-
-
-
+
+
+



-
+

-
-
+
+

-
+








-
+



-
-
-
+
+
+


-
+


-
-
+
+


-
+

-
-
+
+

-
+



-
+





-
+



-
+




-
+











-
-
+
+








-
-
+
+









-
+


-
-
+
+





-
-
+
+



-
+

















-
+







	 *
	 * Runtime internal usage does not use the fast path and does not count
	 * as a call into objc_classname_to_class(). The reason for this is
	 * that if the runtime calls into objc_classname_to_class(), it already
	 * has the lock and thus the performance gain would be small, but it
	 * would waste memory.
	 */
	if (cache && fast_path != NULL) {
		cls = objc_sparsearray_get(fast_path, (uintptr_t)name);
	if (cache && fastPath != NULL) {
		cls = objc_sparsearray_get(fastPath, (uintptr_t)name);

		if (cls != Nil)
			return cls;
	}

	objc_global_mutex_lock();

	cls = (Class)((uintptr_t)objc_hashtable_get(classes, name) & ~1);

	if (cache && fast_path == NULL && --lookups_till_fast_path == 0)
		fast_path = objc_sparsearray_new(sizeof(uintptr_t));
	if (cache && fastPath == NULL && --lookupsUntilFastPath == 0)
		fastPath = objc_sparsearray_new(sizeof(uintptr_t));

	if (cache && fast_path != NULL)
		objc_sparsearray_set(fast_path, (uintptr_t)name, cls);
	if (cache && fastPath != NULL)
		objc_sparsearray_set(fastPath, (uintptr_t)name, cls);

	objc_global_mutex_unlock();

	return cls;
}

static void
call_method(Class cls, const char *method)
callMethod(Class cls, const char *method)
{
	SEL selector = sel_registerName(method);

	for (struct objc_method_list *ml = cls->isa->methodlist;
	    ml != NULL; ml = ml->next)
		for (unsigned int i = 0; i < ml->count; i++)
			if (sel_isEqual((SEL)&ml->methods[i].sel, selector))
				((void (*)(id, SEL))ml->methods[i].imp)(cls,
				    selector);
	for (struct objc_method_list *methodList = cls->isa->methodList;
	    methodList != NULL; methodList = methodList->next)
		for (unsigned int i = 0; i < methodList->count; i++)
			if (sel_isEqual((SEL)&methodList->methods[i].selector,
			    selector))
				((void (*)(id, SEL))methodList->methods[i]
				    .implementation)(cls, selector);
}

static bool
has_load(Class cls)
hasLoad(Class cls)
{
	SEL selector = sel_registerName("load");

	for (struct objc_method_list *ml = cls->isa->methodlist;
	    ml != NULL; ml = ml->next)
		for (size_t i = 0; i < ml->count; i++)
			if (sel_isEqual((SEL)&ml->methods[i].sel, selector))
	for (struct objc_method_list *methodList = cls->isa->methodList;
	    methodList != NULL; methodList = methodList->next)
		for (size_t i = 0; i < methodList->count; i++)
			if (sel_isEqual((SEL)&methodList->methods[i].selector,
			    selector))
				return true;

	return false;
}

static void
call_load(Class cls)
callLoad(Class cls)
{
	if (cls->info & OBJC_CLASS_INFO_LOADED)
		return;

	if (cls->superclass != Nil)
		call_load(cls->superclass);
		callLoad(cls->superclass);

	call_method(cls, "load");
	callMethod(cls, "load");

	cls->info |= OBJC_CLASS_INFO_LOADED;
}

void
objc_update_dtable(Class cls)
{
	struct objc_method_list *ml;
	struct objc_category **cats;
	struct objc_category **categories;

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

	if (cls->dtable == empty_dtable)
		cls->dtable = objc_dtable_new();
	if (cls->DTable == emptyDTable)
		cls->DTable = objc_dtable_new();

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

	for (ml = cls->methodlist; ml != NULL; ml = ml->next)
		for (unsigned int i = 0; i < ml->count; i++)
			objc_dtable_set(cls->dtable,
			    (uint32_t)ml->methods[i].sel.uid,
			    ml->methods[i].imp);
	for (struct objc_method_list *methodList = cls->methodList;
	    methodList != NULL; methodList = methodList->next)
		for (unsigned int i = 0; i < methodList->count; i++)
			objc_dtable_set(cls->DTable,
			    (uint32_t)methodList->methods[i].selector.UID,
			    methodList->methods[i].implementation);

	if ((cats = objc_categories_for_class(cls)) != NULL) {
		for (unsigned int i = 0; cats[i] != NULL; i++) {
			ml = (cls->info & OBJC_CLASS_INFO_CLASS ?
			    cats[i]->instance_methods : cats[i]->class_methods);
	if ((categories = objc_categories_for_class(cls)) != NULL) {
		for (unsigned int i = 0; categories[i] != NULL; i++) {
			struct objc_method_list *methodList =
			    (cls->info & OBJC_CLASS_INFO_CLASS
			    ? categories[i]->instanceMethods
			    : categories[i]->classMethods);

			for (; ml != NULL; ml = ml->next)
				for (unsigned int j = 0; j < ml->count; j++)
					objc_dtable_set(cls->dtable,
					    (uint32_t)ml->methods[j].sel.uid,
					    ml->methods[j].imp);
			for (; methodList != NULL;
			    methodList = methodList->next)
				for (unsigned int j = 0;
				    j < methodList->count; j++)
					objc_dtable_set(cls->DTable, (uint32_t)
					    methodList->methods[j].selector.UID,
					    methodList->methods[j]
					    .implementation);
		}
	}

	if (cls->subclass_list != NULL)
		for (Class *iter = cls->subclass_list; *iter != NULL; iter++)
	if (cls->subclassList != NULL)
		for (Class *iter = cls->subclassList; *iter != NULL; iter++)
			objc_update_dtable(*iter);
}

static void
add_subclass(Class cls)
addSubclass(Class cls)
{
	size_t i;

	if (cls->superclass->subclass_list == NULL) {
		if ((cls->superclass->subclass_list =
	if (cls->superclass->subclassList == NULL) {
		if ((cls->superclass->subclassList =
		    malloc(2 * sizeof(Class))) == NULL)
			OBJC_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;
		cls->superclass->subclassList[0] = cls;
		cls->superclass->subclassList[1] = Nil;

		return;
	}

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

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

	if (cls->superclass->subclass_list == NULL)
	if (cls->superclass->subclassList == NULL)
		OBJC_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;
	cls->superclass->subclassList[i] = cls;
	cls->superclass->subclassList[i + 1] = Nil;
}


static void
update_ivar_offsets(Class cls)
updateIVarOffsets(Class cls)
{
	if (!(cls->info & OBJC_CLASS_INFO_NEW_ABI))
		return;

	if (cls->instance_size > 0)
	if (cls->instanceSize > 0)
		return;

	cls->instance_size = -cls->instance_size;
	cls->instanceSize = -cls->instanceSize;

	if (cls->superclass != Nil) {
		cls->instance_size += cls->superclass->instance_size;
		cls->instanceSize += cls->superclass->instanceSize;

		if (cls->ivars != NULL) {
			for (unsigned int i = 0; i < cls->ivars->count; i++) {
				cls->ivars->ivars[i].offset +=
				    cls->superclass->instance_size;
				*cls->ivar_offsets[i] =
				    cls->ivars->ivars[i].offset;
		if (cls->iVars != NULL) {
			for (unsigned int i = 0; i < cls->iVars->count; i++) {
				cls->iVars->iVars[i].offset +=
				    cls->superclass->instanceSize;
				*cls->iVarOffsets[i] =
				    cls->iVars->iVars[i].offset;
			}
		}
	} else
		for (unsigned int i = 0; i < cls->ivars->count; i++)
			*cls->ivar_offsets[i] = cls->ivars->ivars[i].offset;
		for (unsigned int i = 0; i < cls->iVars->count; i++)
			*cls->iVarOffsets[i] = cls->iVars->iVars[i].offset;
}

static void
setup_class(Class cls)
setupClass(Class cls)
{
	const char *superclass;

	if (cls->info & OBJC_CLASS_INFO_SETUP)
		return;

	if ((superclass = ((struct objc_abi_class *)cls)->superclass) != NULL) {
		Class super = objc_classname_to_class(superclass, false);

		if (super == Nil)
			return;

		setup_class(super);
		setupClass(super);

		if (!(super->info & OBJC_CLASS_INFO_SETUP))
			return;

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

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

	update_ivar_offsets(cls);
	updateIVarOffsets(cls);

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

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

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

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

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

	/*
	 * 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");
	callMethod(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);
	setupClass(cls);

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

	initialize_class(cls);
	initializeClass(cls);

	objc_global_mutex_unlock();
}

static void
process_load_queue()
processLoadQueue()
{
	for (size_t i = 0; i < load_queue_cnt; i++) {
		setup_class(load_queue[i]);
	for (size_t i = 0; i < loadQueueCount; i++) {
		setupClass(loadQueue[i]);

		if (load_queue[i]->info & OBJC_CLASS_INFO_SETUP) {
			call_load(load_queue[i]);
		if (loadQueue[i]->info & OBJC_CLASS_INFO_SETUP) {
			callLoad(loadQueue[i]);

			load_queue_cnt--;
			loadQueueCount--;

			if (load_queue_cnt == 0) {
				free(load_queue);
				load_queue = NULL;
			if (loadQueueCount == 0) {
				free(loadQueue);
				loadQueue = NULL;
				continue;
			}

			load_queue[i] = load_queue[load_queue_cnt];
			loadQueue[i] = loadQueue[loadQueueCount];

			load_queue = realloc(load_queue,
			    sizeof(Class) * load_queue_cnt);
			loadQueue = realloc(loadQueue,
			    sizeof(Class) * loadQueueCount);

			if (load_queue == NULL)
			if (loadQueue == NULL)
				OBJC_ERROR("Not enough memory for load queue!");
		}
	}
}

void
objc_register_all_classes(struct objc_abi_symtab *symtab)
{
	for (uint16_t i = 0; i < symtab->cls_def_cnt; i++) {
	for (uint16_t i = 0; i < symtab->classDefsCount; i++) {
		struct objc_abi_class *cls =
		    (struct objc_abi_class *)symtab->defs[i];

		register_class(cls);
		register_selectors(cls);
		register_selectors(cls->metaclass);
		registerClass(cls);
		registerSelectors(cls);
		registerSelectors(cls->metaclass);
	}

	for (uint16_t i = 0; i < symtab->cls_def_cnt; i++) {
	for (uint16_t i = 0; i < symtab->classDefsCount; i++) {
		Class cls = (Class)symtab->defs[i];

		if (has_load(cls)) {
			setup_class(cls);
		if (hasLoad(cls)) {
			setupClass(cls);

			if (cls->info & OBJC_CLASS_INFO_SETUP)
				call_load(cls);
				callLoad(cls);
			else {
				load_queue = realloc(load_queue,
				    sizeof(Class) * (load_queue_cnt + 1));
				loadQueue = realloc(loadQueue,
				    sizeof(Class) * (loadQueueCount + 1));

				if (load_queue == NULL)
				if (loadQueue == NULL)
					OBJC_ERROR("Not enough memory for load "
					    "queue!");

				load_queue[load_queue_cnt++] = cls;
				loadQueue[loadQueueCount++] = cls;
			}
		} else
			cls->info |= OBJC_CLASS_INFO_LOADED;
	}

	process_load_queue();
	processLoadQueue();
}

Class
objc_allocateClassPair(Class superclass, const char *name, size_t extra_bytes)
objc_allocateClassPair(Class superclass, const char *name, size_t extraBytes)
{
	struct objc_class *cls, *metaclass;
	Class iter, rootclass = Nil;

	if (extra_bytes > LONG_MAX)
	if (extraBytes > LONG_MAX)
		OBJC_ERROR("extra_bytes out of range!")

	if ((cls = calloc(1, sizeof(*cls))) == NULL ||
	    (metaclass = calloc(1, sizeof(*cls))) == NULL)
		OBJC_ERROR("Not enough memory to allocate class pair for class "
		    "%s!", name)

	cls->isa = metaclass;
	cls->superclass = superclass;
	cls->name = name;
	cls->info = OBJC_CLASS_INFO_CLASS;
	cls->instance_size = (superclass != Nil ?
	    superclass->instance_size : 0) + (long)extra_bytes;
	cls->instanceSize = (superclass != Nil ?
	    superclass->instanceSize : 0) + (long)extraBytes;

	for (iter = superclass; iter != Nil; iter = iter->superclass)
		rootclass = iter;

	metaclass->isa = (rootclass != Nil ? rootclass->isa : cls);
	metaclass->superclass = (superclass != Nil ? superclass->isa : Nil);
	metaclass->name = name;
	metaclass->info = OBJC_CLASS_INFO_CLASS;
	metaclass->instance_size = (superclass != Nil ?
	    superclass->isa->instance_size : 0) + (long)extra_bytes;
	metaclass->instanceSize = (superclass != Nil ?
	    superclass->isa->instanceSize : 0) + (long)extraBytes;

	return cls;
}

void
objc_registerClassPair(Class cls)
{
	objc_global_mutex_lock();

	register_class((struct objc_abi_class *)cls);
	registerClass((struct objc_abi_class *)cls);

	if (cls->superclass != Nil) {
		add_subclass(cls);
		add_subclass(cls->isa);
		addSubclass(cls);
		addSubclass(cls->isa);
	}

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

	if (has_load(cls))
		call_load(cls);
	if (hasLoad(cls))
		callLoad(cls);
	else
		cls->info |= OBJC_CLASS_INFO_LOADED;

	process_load_queue();
	processLoadQueue();

	objc_global_mutex_unlock();
}

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

	if ((cls = objc_classname_to_class(name, true)) == NULL)
		return Nil;

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

	objc_global_mutex_lock();

	setup_class(cls);
	setupClass(cls);

	objc_global_mutex_unlock();

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

	return cls;
531
532
533
534
535
536
537
538

539
540
541
542
543
544


545
546
547


548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564

565
566
567
568
569

570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585

586
587
588
589


590
591
592
593
594
595
596
539
540
541
542
543
544
545

546
547
548
549
550


551
552
553


554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571

572
573
574
575
576

577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592

593
594
595


596
597
598
599
600
601
602
603
604







-
+




-
-
+
+

-
-
+
+
















-
+




-
+















-
+


-
-
+
+







Class
objc_get_class(const char *name)
{
	return objc_getRequiredClass(name);
}

unsigned int
objc_getClassList(Class *buf, unsigned int count)
objc_getClassList(Class *buffer, unsigned int count)
{
	unsigned int j;
	objc_global_mutex_lock();

	if (buf == NULL)
		return classes_cnt;
	if (buffer == NULL)
		return classesCount;

	if (classes_cnt < count)
		count = classes_cnt;
	if (classesCount < count)
		count = classesCount;

	j = 0;
	for (uint32_t i = 0; i < classes->size; i++) {
		void *cls;

		if (j >= count) {
			objc_global_mutex_unlock();
			return j;
		}

		if (classes->data[i] == NULL)
			continue;

		if (strcmp(classes->data[i]->key, "Protocol") == 0)
			continue;

		cls = (Class)classes->data[i]->obj;
		cls = (Class)classes->data[i]->object;

		if (cls == Nil || (uintptr_t)cls & 1)
			continue;

		buf[j++] = cls;
		buffer[j++] = cls;
	}

	objc_global_mutex_unlock();

	return j;
}

Class *
objc_copyClassList(unsigned int *len)
{
	Class *ret;
	unsigned int count;

	objc_global_mutex_lock();

	if ((ret = malloc((classes_cnt + 1) * sizeof(Class))) == NULL)
	if ((ret = malloc((classesCount + 1) * sizeof(Class))) == NULL)
		OBJC_ERROR("Failed to allocate memory for class list!");

	count = objc_getClassList(ret, classes_cnt);
	OF_ENSURE(count == classes_cnt);
	count = objc_getClassList(ret, classesCount);
	OF_ENSURE(count == classesCount);

	ret[count] = Nil;

	if (len != NULL)
		*len = count;

	objc_global_mutex_unlock();
627
628
629
630
631
632
633
634

635
636
637
638

639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658

659
660
661
662

663
664
665
666
667
668
669
670
671
672
673
674
675
676

677
678
679
680

681
682
683

684
685
686
687
688





689
690

691
692
693
694
695
696








697
698
699
700
701
702
703






704
705
706
707
708
709

710
711

712
713
714

715
716
717
718
719
720
721





722
723

724
725
726
727
728
729

730
731
732
733
734
735
736
737
738
739


740
741
742
743
744
745
746
747

748
749
750
751
752
753


754
755
756
757
758
759
760


761
762
763
764
765
766
767
768
769
770
771


772
773
774

775
776
777
778
779
780



781
782
783
784


785
786
787
788
789

790
791
792
793

794
795

796
797

798
799
800

801
802

803
804
805
806

807
808

809
810
811

812
813
814

815
816
817


818
819
820
821
822
823
824
825
826
827
828
829

830
831
832
833

834
835

836
837
838
839

840
841
842
843
844
845
846
847
848

849
850
851
852

853
854

855
856
857
858
859
860



861
862
863
864


865
866

867
868
869
870
871
872
873
874
875
876
877
878


879
880
881

882
883
884
885
886

887
888
889


890
891
892
893
894
895
896
897
898
899
900
901

902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920

921
922
923
924



925
926
927
928


929
930
931
932
635
636
637
638
639
640
641

642
643
644
645

646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665

666
667
668
669

670
671
672
673
674
675
676
677
678
679
680
681
682
683

684
685
686
687

688
689


690
691




692
693
694
695
696


697
698





699
700
701
702
703
704
705
706
707
708
709




710
711
712
713
714
715
716
717
718
719
720

721
722

723
724
725

726
727
728





729
730
731
732
733
734

735
736
737
738
739
740

741
742
743
744
745
746
747
748
749


750
751
752
753
754
755
756
757
758

759
760
761
762
763
764

765
766
767
768
769
770
771


772
773
774
775
776
777
778
779
780
781
782
783

784
785
786
787

788
789
790
791



792
793
794
795
796


797
798
799
800
801
802

803
804
805
806

807
808

809
810

811
812
813

814
815

816
817
818
819

820
821

822
823
824

825
826
827

828
829


830
831
832
833
834
835
836
837
838
839
840
841
842

843
844
845
846

847


848
849
850
851

852
853
854
855
856
857
858
859
860

861
862
863
864

865
866

867
868
869
870



871
872
873
874
875


876
877
878

879
880
881
882
883
884
885
886
887
888
889


890
891
892
893

894
895
896
897
898

899
900


901
902
903
904
905
906
907
908
909
910
911
912
913

914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932

933
934



935
936
937
938
939


940
941
942
943
944
945







-
+



-
+



















-
+



-
+













-
+



-
+

-
-
+

-
-
-
-
+
+
+
+
+
-
-
+

-
-
-
-
-
+
+
+
+
+
+
+
+



-
-
-
-
+
+
+
+
+
+





-
+

-
+


-
+


-
-
-
-
-
+
+
+
+
+

-
+





-
+








-
-
+
+







-
+





-
+
+





-
-
+
+










-
+
+


-
+



-
-
-
+
+
+


-
-
+
+




-
+



-
+

-
+

-
+


-
+

-
+



-
+

-
+


-
+


-
+

-
-
+
+











-
+



-
+
-
-
+



-
+








-
+



-
+

-
+



-
-
-
+
+
+


-
-
+
+

-
+










-
-
+
+


-
+




-
+

-
-
+
+











-
+


















-
+

-
-
-
+
+
+


-
-
+
+





unsigned long
class_getInstanceSize(Class cls)
{
	if (cls == Nil)
		return 0;

	return cls->instance_size;
	return cls->instanceSize;
}

IMP
class_getMethodImplementation(Class cls, SEL sel)
class_getMethodImplementation(Class cls, SEL selector)
{
	/*
	 * We use a dummy object here so that the normal lookup is used, even
	 * though we don't have an object. Doing so is safe, as objc_msg_lookup
	 * does not access the object, but only its class.
	 *
	 * Just looking it up in the dispatch table could result in returning
	 * NULL instead of the forwarding handler, it would also mean
	 * +[resolveClassMethod:] / +[resolveInstanceMethod:] would not be
	 * called.
	 */
	struct {
		Class isa;
	} dummy;

	if (cls == Nil)
		return NULL;

	dummy.isa = cls;
	return objc_msg_lookup((id)&dummy, sel);
	return objc_msg_lookup((id)&dummy, selector);
}

IMP
class_getMethodImplementation_stret(Class cls, SEL sel)
class_getMethodImplementation_stret(Class cls, SEL selector)
{
	/*
	 * Same as above, but use objc_msg_lookup_stret instead, so that the
	 * correct forwarding handler is returned.
	 */
	struct {
		Class isa;
	} dummy;

	if (cls == Nil)
		return NULL;

	dummy.isa = cls;
	return objc_msg_lookup_stret((id)&dummy, sel);
	return objc_msg_lookup_stret((id)&dummy, selector);
}

static struct objc_method *
get_method(Class cls, SEL sel)
getMethod(Class cls, SEL selector)
{
	struct objc_method_list *ml;
	struct objc_category **cats;
	struct objc_category **categories;

	if ((cats = objc_categories_for_class(cls)) != NULL) {
		for (; *cats != NULL; cats++) {
			if (cls->info & OBJC_CLASS_INFO_METACLASS)
				ml = (*cats)->class_methods;
	if ((categories = objc_categories_for_class(cls)) != NULL) {
		for (; *categories != NULL; categories++) {
			struct objc_method_list *methodList =
			    (cls->info & OBJC_CLASS_INFO_METACLASS
			    ? (*categories)->classMethods
			else
				ml = (*cats)->instance_methods;
			    : (*categories)->instanceMethods);

			for (; ml != NULL; ml = ml->next)
				for (unsigned int i = 0; i < ml->count; i++)
					if (sel_isEqual(
					    (SEL)&ml->methods[i].sel, sel))
						return &ml->methods[i];
			for (; methodList != NULL;
			    methodList = methodList->next)
				for (unsigned int i = 0;
				    i < methodList->count; i++)
					if (sel_isEqual((SEL)
					    &methodList->methods[i].selector,
					    selector))
						return &methodList->methods[i];
		}
	}

	for (ml = cls->methodlist; ml != NULL; ml = ml->next)
		for (unsigned int i = 0; i < ml->count; i++)
			if (sel_isEqual((SEL)&ml->methods[i].sel, sel))
				return &ml->methods[i];
	for (struct objc_method_list *methodList = cls->methodList;
	    methodList != NULL; methodList = methodList->next)
		for (unsigned int i = 0; i < methodList->count; i++)
			if (sel_isEqual((SEL)&methodList->methods[i].selector,
			    selector))
				return &methodList->methods[i];

	return NULL;
}

static void
add_method(Class cls, SEL sel, IMP imp, const char *types)
addMethod(Class cls, SEL selector, IMP implementation, const char *typeEncoding)
{
	struct objc_method_list *ml;
	struct objc_method_list *methodList;

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

	ml->next = cls->methodlist;
	ml->count = 1;
	ml->methods[0].sel.uid = sel->uid;
	ml->methods[0].sel.types = types;
	ml->methods[0].imp = imp;
	methodList->next = cls->methodList;
	methodList->count = 1;
	methodList->methods[0].selector.UID = selector->UID;
	methodList->methods[0].selector.typeEncoding = typeEncoding;
	methodList->methods[0].implementation = implementation;

	cls->methodlist = ml;
	cls->methodList = methodList;

	objc_update_dtable(cls);
}

const char *
class_getMethodTypeEncoding(Class cls, SEL sel)
class_getMethodTypeEncoding(Class cls, SEL selector)
{
	struct objc_method *method;

	if (cls == Nil)
		return NULL;

	objc_global_mutex_lock();

	if ((method = get_method(cls, sel)) != NULL) {
		const char *ret = method->sel.types;
	if ((method = getMethod(cls, selector)) != NULL) {
		const char *ret = method->selector.typeEncoding;
		objc_global_mutex_unlock();
		return ret;
	}

	objc_global_mutex_unlock();

	if (cls->superclass != Nil)
		return class_getMethodTypeEncoding(cls->superclass, sel);
		return class_getMethodTypeEncoding(cls->superclass, selector);

	return NULL;
}

bool
class_addMethod(Class cls, SEL sel, IMP imp, const char *types)
class_addMethod(Class cls, SEL selector, IMP implementation,
    const char *typeEncoding)
{
	bool ret;

	objc_global_mutex_lock();

	if (get_method(cls, sel) == NULL) {
		add_method(cls, sel, imp, types);
	if (getMethod(cls, selector) == NULL) {
		addMethod(cls, selector, implementation, typeEncoding);
		ret = true;
	} else
		ret = false;

	objc_global_mutex_unlock();

	return ret;
}

IMP
class_replaceMethod(Class cls, SEL sel, IMP newimp, const char *types)
class_replaceMethod(Class cls, SEL selector, IMP implementation,
    const char *typeEncoding)
{
	struct objc_method *method;
	IMP oldimp;
	IMP oldImplementation;

	objc_global_mutex_lock();

	if ((method = get_method(cls, sel)) != NULL) {
		oldimp = method->imp;
		method->imp = newimp;
	if ((method = getMethod(cls, selector)) != NULL) {
		oldImplementation = method->implementation;
		method->implementation = implementation;
		objc_update_dtable(cls);
	} else {
		oldimp = NULL;
		add_method(cls, sel, newimp, types);
		oldImplementation = NULL;
		addMethod(cls, selector, implementation, typeEncoding);
	}

	objc_global_mutex_unlock();

	return oldimp;
	return oldImplementation;
}

Class
object_getClass(id obj_)
object_getClass(id object_)
{
	struct objc_object *obj;
	struct objc_object *object;

	if (obj_ == nil)
	if (object_ == nil)
		return Nil;

	obj = (struct objc_object *)obj_;
	object = (struct objc_object *)object_;

	return obj->isa;
	return object->isa;
}

Class
object_setClass(id obj_, Class cls)
object_setClass(id object_, Class cls)
{
	struct objc_object *obj;
	struct objc_object *object;
	Class old;

	if (obj_ == nil)
	if (object_ == nil)
		return Nil;

	obj = (struct objc_object *)obj_;
	object = (struct objc_object *)object_;

	old = obj->isa;
	obj->isa = cls;
	old = object->isa;
	object->isa = cls;

	return old;
}

const char *
object_getClassName(id obj)
{
	return class_getName(object_getClass(obj));
}

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

	if ((rcls->info & OBJC_CLASS_INFO_SETUP) &&
	if ((rcls->info & OBJC_CLASS_INFO_SETUP) && rcls->superclass != Nil &&
	    rcls->superclass != Nil &&
	    rcls->superclass->subclass_list != NULL) {
	    rcls->superclass->subclassList != NULL) {
		size_t i = SIZE_MAX, count = 0;
		Class *tmp;

		for (tmp = rcls->superclass->subclass_list;
		for (tmp = rcls->superclass->subclassList;
		    *tmp != Nil; tmp++) {
			if (*tmp == rcls)
				i = count;

			count++;
		}

		if (count > 0 && i < SIZE_MAX) {
			tmp = rcls->superclass->subclass_list;
			tmp = rcls->superclass->subclassList;
			tmp[i] = tmp[count - 1];
			tmp[count - 1] = NULL;

			if ((tmp = realloc(rcls->superclass->subclass_list,
			if ((tmp = realloc(rcls->superclass->subclassList,
			    count * sizeof(Class))) != NULL)
				rcls->superclass->subclass_list = tmp;
				rcls->superclass->subclassList = tmp;
		}
	}

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

	if (rcls->dtable != NULL && rcls->dtable != empty_dtable)
		objc_dtable_free(rcls->dtable);
	if (rcls->DTable != NULL && rcls->DTable != emptyDTable)
		objc_dtable_free(rcls->DTable);

	rcls->dtable = NULL;
	rcls->DTable = NULL;

	if ((rcls->info & OBJC_CLASS_INFO_SETUP) && rcls->superclass != Nil)
		cls->superclass = rcls->superclass->name;

	rcls->info &= ~OBJC_CLASS_INFO_SETUP;
}

void
objc_unregister_class(Class cls)
{
	while (cls->subclass_list != NULL && cls->subclass_list[0] != Nil)
		objc_unregister_class(cls->subclass_list[0]);
	while (cls->subclassList != NULL && cls->subclassList[0] != Nil)
		objc_unregister_class(cls->subclassList[0]);

	if (cls->info & OBJC_CLASS_INFO_LOADED)
		call_method(cls, "unload");
		callMethod(cls, "unload");

	objc_hashtable_delete(classes, cls->name);

	if (strcmp(class_getName(cls), "Protocol") != 0)
		classes_cnt--;
		classesCount--;

	unregister_class(cls);
	unregister_class(cls->isa);
	unregisterClass(cls);
	unregisterClass(cls->isa);
}

void
objc_unregister_all_classes(void)
{
	if (classes == NULL)
		return;

	for (uint32_t i = 0; i < classes->size; i++) {
		if (classes->data[i] != NULL &&
		    classes->data[i] != &objc_deleted_bucket) {
			void *cls = (Class)classes->data[i]->obj;
			void *cls = (Class)classes->data[i]->object;

			if (cls == Nil || (uintptr_t)cls & 1)
				continue;

			objc_unregister_class(cls);

			/*
			 * The table might have been resized, so go back to the
			 * start again.
			 *
			 * Due to the i++ in the for loop, we need to set it to
			 * UINT32_MAX so that it will get increased at the end
			 * of the loop and thus become 0.
			 */
			i = UINT32_MAX;
		}
	}

	OF_ENSURE(classes_cnt == 0);
	OF_ENSURE(classesCount == 0);

	if (empty_dtable != NULL) {
		objc_dtable_free(empty_dtable);
		empty_dtable = NULL;
	if (emptyDTable != NULL) {
		objc_dtable_free(emptyDTable);
		emptyDTable = NULL;
	}

	objc_sparsearray_free(fast_path);
	fast_path = NULL;
	objc_sparsearray_free(fastPath);
	fastPath = NULL;

	objc_hashtable_free(classes);
	classes = NULL;
}

Modified src/runtime/dtable.m from [cfecc15e99] to [1fc547de44].

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







-
+

-
+





-
+
-



-
+
-





-
-
+
+



-
+






-
+


-
+


-
+



-
+



-
+

-
+






-
+




-
+








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

#import "ObjFW_RT.h"
#import "private.h"

static struct objc_dtable_level2 *empty_level2 = NULL;
static struct objc_dtable_level2 *emptyLevel2 = NULL;
#ifdef OF_SELUID24
static struct objc_dtable_level3 *empty_level3 = NULL;
static struct objc_dtable_level3 *emptyLevel3 = NULL;
#endif

static void
init(void)
{
	empty_level2 = malloc(sizeof(struct objc_dtable_level2));
	if ((emptyLevel2 = malloc(sizeof(struct objc_dtable_level2))) == NULL)
	if (empty_level2 == NULL)
		OBJC_ERROR("Not enough memory to allocate dtable!");

#ifdef OF_SELUID24
	empty_level3 = malloc(sizeof(struct objc_dtable_level3));
	if ((emptyLevel3 = malloc(sizeof(struct objc_dtable_level3))) == NULL)
	if (empty_level3 == NULL)
		OBJC_ERROR("Not enough memory to allocate dtable!");
#endif

#ifdef OF_SELUID24
	for (uint_fast16_t i = 0; i < 256; i++) {
		empty_level2->buckets[i] = empty_level3;
		empty_level3->buckets[i] = (IMP)0;
		emptyLevel2->buckets[i] = emptyLevel3;
		emptyLevel3->buckets[i] = (IMP)0;
	}
#else
	for (uint_fast16_t i = 0; i < 256; i++)
		empty_level2->buckets[i] = (IMP)0;
		emptyLevel2->buckets[i] = (IMP)0;
#endif
}

struct objc_dtable *
objc_dtable_new(void)
{
	struct objc_dtable *dtable;
	struct objc_dtable *DTable;

#ifdef OF_SELUID24
	if (empty_level2 == NULL || empty_level3 == NULL)
	if (emptyLevel2 == NULL || emptyLevel3 == NULL)
		init();
#else
	if (empty_level2 == NULL)
	if (emptyLevel2 == NULL)
		init();
#endif

	if ((dtable = malloc(sizeof(struct objc_dtable))) == NULL)
	if ((DTable = malloc(sizeof(struct objc_dtable))) == NULL)
		OBJC_ERROR("Not enough memory to allocate dtable!");

	for (uint_fast16_t i = 0; i < 256; i++)
		dtable->buckets[i] = empty_level2;
		DTable->buckets[i] = emptyLevel2;

	return dtable;
	return DTable;
}

void
objc_dtable_copy(struct objc_dtable *dst, struct objc_dtable *src)
{
	for (uint_fast16_t i = 0; i < 256; i++) {
		if (src->buckets[i] == empty_level2)
		if (src->buckets[i] == emptyLevel2)
			continue;

#ifdef OF_SELUID24
		for (uint_fast16_t j = 0; j < 256; j++) {
			if (src->buckets[i]->buckets[j] == empty_level3)
			if (src->buckets[i]->buckets[j] == emptyLevel3)
				continue;

			for (uint_fast16_t k = 0; k < 256; k++) {
				IMP obj;
				uint32_t idx;

				obj = src->buckets[i]->buckets[j]->buckets[k];
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
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







-
+








-
+








-
+







	uint8_t j = idx >> 8;
	uint8_t k = idx;
#else
	uint8_t i = idx >> 8;
	uint8_t j = idx;
#endif

	if (dtable->buckets[i] == empty_level2) {
	if (dtable->buckets[i] == emptyLevel2) {
		struct objc_dtable_level2 *level2 =
		    malloc(sizeof(struct objc_dtable_level2));

		if (level2 == NULL)
			OBJC_ERROR("Not enough memory to insert into dtable!");

		for (uint_fast16_t l = 0; l < 256; l++)
#ifdef OF_SELUID24
			level2->buckets[l] = empty_level3;
			level2->buckets[l] = emptyLevel3;
#else
			level2->buckets[l] = (IMP)0;
#endif

		dtable->buckets[i] = level2;
	}

#ifdef OF_SELUID24
	if (dtable->buckets[i]->buckets[j] == empty_level3) {
	if (dtable->buckets[i]->buckets[j] == emptyLevel3) {
		struct objc_dtable_level3 *level3 =
		    malloc(sizeof(struct objc_dtable_level3));

		if (level3 == NULL)
			OBJC_ERROR("Not enough memory to insert into dtable!");

		for (uint_fast16_t l = 0; l < 256; l++)
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
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







-
+




-
+












-
-
+
+

-
-
+
+


-
+

-
+


#endif
}

void
objc_dtable_free(struct objc_dtable *dtable)
{
	for (uint_fast16_t i = 0; i < 256; i++) {
		if (dtable->buckets[i] == empty_level2)
		if (dtable->buckets[i] == emptyLevel2)
			continue;

#ifdef OF_SELUID24
		for (uint_fast16_t j = 0; j < 256; j++)
			if (dtable->buckets[i]->buckets[j] != empty_level3)
			if (dtable->buckets[i]->buckets[j] != emptyLevel3)
				free(dtable->buckets[i]->buckets[j]);
#endif

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

	free(dtable);
}

void
objc_dtable_cleanup(void)
{
	if (empty_level2 != NULL)
		free(empty_level2);
	if (emptyLevel2 != NULL)
		free(emptyLevel2);
#ifdef OF_SELUID24
	if (empty_level3 != NULL)
		free(empty_level3);
	if (emptyLevel3 != NULL)
		free(emptyLevel3);
#endif

	empty_level2 = NULL;
	emptyLevel2 = NULL;
#ifdef OF_SELUID24
	empty_level3 = NULL;
	emptyLevel3 = NULL;
#endif
}

Modified src/runtime/exception.m from [eb9e1d7c01] to [3d1d7d2d6b].

52
53
54
55
56
57
58
59

60
61

62
63
64
65
66
67
68
52
53
54
55
56
57
58

59
60

61
62
63
64
65
66
67
68







-
+

-
+







#if defined(OF_ARM) && !defined(__ARM_DWARF_EH__)
# define HAVE_ARM_EHABI_EXCEPTIONS
#endif

#ifndef HAVE_ARM_EHABI_EXCEPTIONS
# define PERSONALITY_FUNC(func)						\
	_Unwind_Reason_Code						\
	func(int version, int actions, uint64_t ex_class,		\
	func(int version, int actions, uint64_t exClass,		\
	    struct _Unwind_Exception *ex, struct _Unwind_Context *ctx)
# define CALL_PERSONALITY(func) func(version, actions, ex_class, ex, ctx)
# define CALL_PERSONALITY(func) func(version, actions, exClass, ex, ctx)
#else
# define PERSONALITY_FUNC(func)						\
	_Unwind_Reason_Code						\
	func(uint32_t state, struct _Unwind_Exception *ex,		\
	    struct _Unwind_Context *ctx)
# define CALL_PERSONALITY(func) func(state, ex, ctx)
#endif
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
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







-
+


-
-
+
+

-
-
+
+





-
+











-
-
-
-
-
-
+
+
+
+
+
+







		uint64_t private[6];
# endif
#else
		/* From "Exception Handling ABI for the ARM(R) Architecture" */
		struct {
			uint32_t reserved1, reserved2, reserved3, reserved4;
			uint32_t reserved;
		} unwinder_cache;
		} unwinderCache;
		struct {
			uint32_t sp;
			uint32_t bitpattern[5];
		} barrier_cache;
			uint32_t bitPattern[5];
		} barrierCache;
		struct {
			uint32_t bitpattern[4];
		} cleanup_cache;
			uint32_t bitPattern[4];
		} cleanupCache;
		struct {
			uint32_t fnstart;
			uint32_t *ehtp;
			uint32_t additional;
			uint32_t reserved1;
		} pr_cache;
		} PRCache;
		long long int : 0;
#endif
	} exception;
	id object;
#ifndef HAVE_ARM_EHABI_EXCEPTIONS
	uintptr_t landingpad;
	intptr_t filter;
#endif
};

struct lsda {
	uintptr_t region_start, landingpads_start;
	uint8_t typestable_enc;
	const uint8_t *typestable;
	uintptr_t typestable_base;
	uint8_t callsites_enc;
	const uint8_t *callsites, *actiontable;
	uintptr_t regionStart, landingpadsStart;
	uint8_t typesTableEnc;
	const uint8_t *typesTable;
	uintptr_t typesTableBase;
	uint8_t callsitesEnc;
	const uint8_t *callsites, *actionTable;
};

extern _Unwind_Reason_Code _Unwind_RaiseException(struct _Unwind_Exception *);
extern void _Unwind_DeleteException(struct _Unwind_Exception *);
extern void *_Unwind_GetLanguageSpecificData(struct _Unwind_Context *);
extern uintptr_t _Unwind_GetRegionStart(struct _Unwind_Context *);
#ifdef HAVE__UNWIND_GETDATARELBASE
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
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







-
+


-
+










-
+

-
+




















-
-
+
+

-
+



-
+





-
+














-
+

-
+



-
-
+
+








-
+







		if (__gnu_unwind_frame(ex, ctx) != _URC_OK)	\
			return _URC_FAILURE;			\
								\
		return _URC_CONTINUE_UNWIND;			\
	}

static inline uintptr_t
_Unwind_GetGR(struct _Unwind_Context *ctx, int regno)
_Unwind_GetGR(struct _Unwind_Context *ctx, int regNo)
{
	uintptr_t value;
	_Unwind_VRS_Get(ctx, 0, regno, 0, &value);
	_Unwind_VRS_Get(ctx, 0, regNo, 0, &value);
	return value;
}

static inline uintptr_t
_Unwind_GetIP(struct _Unwind_Context *ctx)
{
	return _Unwind_GetGR(ctx, 15) & ~1;
}

static inline void
_Unwind_SetGR(struct _Unwind_Context *ctx, int regno, uintptr_t value)
_Unwind_SetGR(struct _Unwind_Context *ctx, int regNo, uintptr_t value)
{
	_Unwind_VRS_Set(ctx, 0, regno, 0, &value);
	_Unwind_VRS_Set(ctx, 0, regNo, 0, &value);
}

static inline void
_Unwind_SetIP(struct _Unwind_Context *ctx, uintptr_t value)
{
	uintptr_t thumb = _Unwind_GetGR(ctx, 15) & 1;
	_Unwind_SetGR(ctx, 15, (value | thumb));
}
#endif

#ifdef CXX_PERSONALITY
static PERSONALITY_FUNC(cxx_personality) OF_WEAK_REF(CXX_PERSONALITY_STR);
#endif

#ifdef HAVE_SEH_EXCEPTIONS
extern EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD, void *,
    PCONTEXT, PDISPATCHER_CONTEXT, _Unwind_Reason_Code (*)(int, int, uint64_t,
    struct _Unwind_Exception *, struct _Unwind_Context *));
#endif

static objc_uncaught_exception_handler uncaught_exception_handler;
static struct objc_exception emergency_exceptions[NUM_EMERGENCY_EXCEPTIONS];
static objc_uncaught_exception_handler uncaughtExceptionHandler;
static struct objc_exception emergencyExceptions[NUM_EMERGENCY_EXCEPTIONS];
#ifdef OF_HAVE_THREADS
static of_spinlock_t emergency_exceptions_spinlock;
static of_spinlock_t emergencyExceptionsSpinlock;

OF_CONSTRUCTOR()
{
	if (!of_spinlock_new(&emergency_exceptions_spinlock))
	if (!of_spinlock_new(&emergencyExceptionsSpinlock))
		OBJC_ERROR("Cannot create spinlock!")
}
#endif

static uint64_t
read_uleb128(const uint8_t **ptr)
readULEB128(const uint8_t **ptr)
{
	uint64_t value = 0;
	uint8_t shift = 0;

	do {
		value |= (**ptr & 0x7F) << shift;
		(*ptr)++;
		shift += 7;
	} while (*(*ptr - 1) & 0x80);

	return value;
}

static int64_t
read_sleb128(const uint8_t **ptr)
readSLEB128(const uint8_t **ptr)
{
	const uint8_t *oldptr = *ptr;
	const uint8_t *oldPtr = *ptr;
	uint8_t bits;
	int64_t value;

	value = read_uleb128(ptr);
	bits = (*ptr - oldptr) * 7;
	value = readULEB128(ptr);
	bits = (*ptr - oldPtr) * 7;

	if (bits < 64 && value & (1 << (bits - 1)))
		value |= -(1 << bits);

	return value;
}

static uintptr_t
get_base(struct _Unwind_Context *ctx, uint8_t enc)
getBase(struct _Unwind_Context *ctx, uint8_t enc)
{
	if (enc == DW_EH_PE_omit)
		return 0;

	switch (enc & 0x70) {
	case DW_EH_PE_absptr:
	case DW_EH_PE_pcrel:
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
494
495
496
497
498
499
500
501
502
503
504


505
506
507
508
509
510
511


512
513
514

515
516
517
518
519
520



521
522
523
524
525
526
527
528
529
530
531
532
533
534
535





536
537

538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557


558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576

577
578
579
580
581
582
583
584
585

586
587
588
589
590
591
592
593
594
595
596
597
598
599



600
601
602
603
604
605

606
607
608
609
610
611
612
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
494
495
496
497
498
499
500
501
502


503
504
505
506
507
508
509


510
511
512
513

514
515
516
517



518
519
520
521
522
523
524
525
526
527
528
529
530





531
532
533
534
535
536

537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555


556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575

576
577
578
579
580
581
582
583
584

585
586
587
588
589
590
591
592
593
594
595
596



597
598
599
600
601
602
603
604

605
606
607
608
609
610
611
612







-
+



















-
+











-
+






-
+








-
+

















-
+














-
+

-
-
+
+

-
-
-
+
+
+

-
-
-
+
+
+

-
-
-
+
+
+


-
+

-
-
-
+
+
+

-
+



-
-
+
+

-
-
+
+


-
+


-
-
-
+
+
+

-
-
-
-
-
-
+
+
+
+
+
+


-
+


-
-
-
-
-
-
-
+
+
+
+
+
+
+







-
+





-
-
+
+


-
-
-
+
+
+






-
+


















-
-
+
+





-
-
+
+


-
+



-
-
-
+
+
+










-
-
-
-
-
+
+
+
+
+

-
+


















-
-
+
+


















-
+








-
+











-
-
-
+
+
+





-
+







#endif
	}

	OBJC_ERROR("Unknown encoding!")
}

static size_t
size_for_encoding(uint8_t enc)
sizeForEncoding(uint8_t enc)
{
	if (enc == DW_EH_PE_omit)
		return 0;

	switch (enc & 0x07) {
	case DW_EH_PE_absptr:
		return sizeof(void *);
	case DW_EH_PE_udata2:
		return 2;
	case DW_EH_PE_udata4:
		return 4;
	case DW_EH_PE_udata8:
		return 8;
	}

	OBJC_ERROR("Unknown encoding!")
}

static uint64_t
read_value(uint8_t enc, const uint8_t **ptr)
readValue(uint8_t enc, const uint8_t **ptr)
{
	uint64_t value;

	if (enc == DW_EH_PE_aligned)
		OBJC_ERROR("DW_EH_PE_aligned is not implemented!")

#define READ(type)					\
	{						\
		type tmp;				\
		memcpy(&tmp, *ptr, sizeof(type));	\
		value = tmp;				\
		*ptr += size_for_encoding(enc);		\
		*ptr += sizeForEncoding(enc);		\
		break;					\
	}
	switch (enc & 0x0F) {
	case DW_EH_PE_absptr:
		READ(uintptr_t)
	case DW_EH_PE_uleb128:
		value = read_uleb128(ptr);
		value = readULEB128(ptr);
		break;
	case DW_EH_PE_udata2:
		READ(uint16_t)
	case DW_EH_PE_udata4:
		READ(uint32_t)
	case DW_EH_PE_udata8:
		READ(uint64_t)
	case DW_EH_PE_sleb128:
		value = read_sleb128(ptr);
		value = readSLEB128(ptr);
		break;
	case DW_EH_PE_sdata2:
		READ(int16_t)
	case DW_EH_PE_sdata4:
		READ(int32_t)
	case DW_EH_PE_sdata8:
		READ(int64_t)
	default:
		OBJC_ERROR("Unknown encoding!")
	}
#undef READ

	return value;
}

#ifndef HAVE_ARM_EHABI_EXCEPTIONS
static uint64_t
resolve_value(uint64_t value, uint8_t enc, const uint8_t *start, uint64_t base)
resolveValue(uint64_t value, uint8_t enc, const uint8_t *start, uint64_t base)
{
	if (value == 0)
		return 0;

	value += ((enc & 0x70) == DW_EH_PE_pcrel ? (uintptr_t)start : base);

	if (enc & DW_EH_PE_indirect)
		value = *(uintptr_t *)(uintptr_t)value;

	return value;
}
#endif

static void
read_lsda(struct _Unwind_Context *ctx, const uint8_t *ptr, struct lsda *lsda)
readLSDA(struct _Unwind_Context *ctx, const uint8_t *ptr, struct lsda *LSDA)
{
	uint8_t landingpads_start_enc;
	uintptr_t callsites_size;
	uint8_t landingpadsStartEnc;
	uintptr_t callsitesSize;

	lsda->region_start = _Unwind_GetRegionStart(ctx);
	lsda->landingpads_start = lsda->region_start;
	lsda->typestable = NULL;
	LSDA->regionStart = _Unwind_GetRegionStart(ctx);
	LSDA->landingpadsStart = LSDA->regionStart;
	LSDA->typesTable = NULL;

	if ((landingpads_start_enc = *ptr++) != DW_EH_PE_omit)
		lsda->landingpads_start =
		    (uintptr_t)read_value(landingpads_start_enc, &ptr);
	if ((landingpadsStartEnc = *ptr++) != DW_EH_PE_omit)
		LSDA->landingpadsStart =
		    (uintptr_t)readValue(landingpadsStartEnc, &ptr);

	if ((lsda->typestable_enc = *ptr++) != DW_EH_PE_omit) {
		uintptr_t tmp = (uintptr_t)read_uleb128(&ptr);
		lsda->typestable = ptr + tmp;
	if ((LSDA->typesTableEnc = *ptr++) != DW_EH_PE_omit) {
		uintptr_t tmp = (uintptr_t)readULEB128(&ptr);
		LSDA->typesTable = ptr + tmp;
	}

	lsda->typestable_base = get_base(ctx, lsda->typestable_enc);
	LSDA->typesTableBase = getBase(ctx, LSDA->typesTableEnc);

	lsda->callsites_enc = *ptr++;
	callsites_size = (uintptr_t)read_uleb128(&ptr);
	lsda->callsites = ptr;
	LSDA->callsitesEnc = *ptr++;
	callsitesSize = (uintptr_t)readULEB128(&ptr);
	LSDA->callsites = ptr;

	lsda->actiontable = lsda->callsites + callsites_size;
	LSDA->actionTable = LSDA->callsites + callsitesSize;
}

static bool
find_callsite(struct _Unwind_Context *ctx, struct lsda *lsda,
    uintptr_t *landingpad, const uint8_t **actionrecords)
findCallsite(struct _Unwind_Context *ctx, struct lsda *LSDA,
    uintptr_t *landingpad, const uint8_t **actionRecords)
{
	uintptr_t ip = _Unwind_GetIP(ctx);
	const uint8_t *ptr = lsda->callsites;
	uintptr_t IP = _Unwind_GetIP(ctx);
	const uint8_t *ptr = LSDA->callsites;

	*landingpad = 0;
	*actionrecords = NULL;
	*actionRecords = NULL;

#ifndef HAVE_SJLJ_EXCEPTIONS
	while (ptr < lsda->actiontable) {
		uintptr_t callsite_start, callsite_len, callsite_landingpad;
		uintptr_t callsite_action;
	while (ptr < LSDA->actionTable) {
		uintptr_t callsiteStart, callsiteLength, callsiteLandingpad;
		uintptr_t callsiteAction;

		callsite_start = lsda->region_start +
		    (uintptr_t)read_value(lsda->callsites_enc, &ptr);
		callsite_len = (uintptr_t)read_value(lsda->callsites_enc, &ptr);
		callsite_landingpad =
		    (uintptr_t)read_value(lsda->callsites_enc, &ptr);
		callsite_action = (uintptr_t)read_uleb128(&ptr);
		callsiteStart = LSDA->regionStart +
		    (uintptr_t)readValue(LSDA->callsitesEnc, &ptr);
		callsiteLength = (uintptr_t)readValue(LSDA->callsitesEnc, &ptr);
		callsiteLandingpad =
		    (uintptr_t)readValue(LSDA->callsitesEnc, &ptr);
		callsiteAction = (uintptr_t)readULEB128(&ptr);

		/* We can stop if we passed IP, as the table is sorted */
		if (callsite_start >= ip)
		if (callsiteStart >= IP)
			break;

		if (callsite_start + callsite_len >= ip) {
			if (callsite_landingpad != 0)
				*landingpad = lsda->landingpads_start +
				    callsite_landingpad;
			if (callsite_action != 0)
				*actionrecords = lsda->actiontable +
				    callsite_action - 1;
		if (callsiteStart + callsiteLength >= IP) {
			if (callsiteLandingpad != 0)
				*landingpad = LSDA->landingpadsStart +
				    callsiteLandingpad;
			if (callsiteAction != 0)
				*actionRecords = LSDA->actionTable +
				    callsiteAction - 1;

			return true;
		}
	}

	return false;
#else
	uintptr_t callsite_landingpad, callsite_action;
	uintptr_t callsiteLandingpad, callsiteAction;

	if ((intptr_t)ip < 1)
		return false;

	do {
		callsite_landingpad = (uintptr_t)read_uleb128(&ptr);
		callsite_action = (uintptr_t)read_uleb128(&ptr);
		callsiteLandingpad = (uintptr_t)readULEB128(&ptr);
		callsiteAction = (uintptr_t)readULEB128(&ptr);
	} while (--ip > 1);

	*landingpad = callsite_landingpad + 1;
	if (callsite_action != 0)
		*actionrecords = lsda->actiontable + callsite_action - 1;
	*landingpad = callsiteLandingpad + 1;
	if (callsiteAction != 0)
		*actionRecords = LSDA->actionTable + callsiteAction - 1;

	return true;
#endif
}

static bool
class_matches(Class class, id object)
classMatches(Class class, id object)
{
	Class iter;

	if (class == Nil)
		return true;

	if (object == nil)
		return false;

	for (iter = object_getClass(object); iter != Nil;
	    iter = class_getSuperclass(iter))
		if (iter == class)
			return true;

	return false;
}

static uint8_t
find_actionrecord(const uint8_t *actionrecords, struct lsda *lsda, int actions,
    bool foreign, struct objc_exception *e, intptr_t *filtervalue)
findActionRecord(const uint8_t *actionRecords, struct lsda *LSDA, int actions,
    bool foreign, struct objc_exception *e, intptr_t *filterPtr)
{
	const uint8_t *ptr;
	intptr_t filter, displacement;

	do {
		ptr = actionrecords;
		filter = (intptr_t)read_sleb128(&ptr);
		ptr = actionRecords;
		filter = (intptr_t)readSLEB128(&ptr);

		/*
		 * Get the next action record. Since read_sleb128 modifies ptr,
		 * Get the next action record. Since readSLEB128() modifies ptr,
		 * we first set the actionrecord to the current ptr and then
		 * add the displacement.
		 */
		actionrecords = ptr;
		displacement = (intptr_t)read_sleb128(&ptr);
		actionrecords += displacement;
		actionRecords = ptr;
		displacement = (intptr_t)readSLEB128(&ptr);
		actionRecords += displacement;

		if (filter > 0 && !(actions & _UA_FORCE_UNWIND) && !foreign) {
			Class class;
			const char *className;
			uintptr_t c;
			const uint8_t *tmp;

#ifndef HAVE_ARM_EHABI_EXCEPTIONS
			uintptr_t i;

			i = filter * size_for_encoding(lsda->typestable_enc);
			tmp = lsda->typestable - i;
			c = (uintptr_t)read_value(lsda->typestable_enc, &tmp);
			c = (uintptr_t)resolve_value(c, lsda->typestable_enc,
			    lsda->typestable - i, lsda->typestable_base);
			i = filter * sizeForEncoding(LSDA->typesTableEnc);
			tmp = LSDA->typesTable - i;
			c = (uintptr_t)readValue(LSDA->typesTableEnc, &tmp);
			c = (uintptr_t)resolveValue(c, LSDA->typesTableEnc,
			    LSDA->typesTable - i, LSDA->typesTableBase);
#else
			tmp = lsda->typestable - (filter * 4);
			tmp = LSDA->typesTable - (filter * 4);
			c = *(uintptr_t *)(void *)tmp;

			if (c != 0) {
				c += (uintptr_t)tmp;
# if defined(OF_LINUX) || defined(OF_NETBSD)
				c = *(uintptr_t *)c;
# endif
			}
#endif

			className = (const char *)c;

			if (className != NULL && *className != '\0' &&
			    strcmp(className, "@id") != 0)
				class = objc_getRequiredClass(className);
			else
				class = Nil;

			if (class_matches(class, e->object)) {
				*filtervalue = filter;
			if (classMatches(class, e->object)) {
				*filterPtr = filter;
				return HANDLER_FOUND;
			}
		} else if (filter == 0)
			return CLEANUP_FOUND;
		else if (filter < 0)
			OBJC_ERROR("Invalid filter!")
	} while (displacement != 0);

	return 0;
}

#ifdef HAVE_SEH_EXCEPTIONS
static
#endif
PERSONALITY_FUNC(PERSONALITY)
{
#ifdef HAVE_ARM_EHABI_EXCEPTIONS
	int version = 1;
	uint64_t ex_class = ex->class;
	uint64_t exClass = ex->class;
	int actions;

	switch (state) {
	case 0:	/* _US_VIRTUAL_UNWIND_FRAME */
		actions = _UA_SEARCH_PHASE;
		break;
	case 1:	/* _US_UNWIND_FRAME_STARTING */
		actions = _UA_CLEANUP_PHASE;
		if ((ex->barrier_cache.sp == _Unwind_GetGR(ctx, 13)) != 0)
		if ((ex->barrierCache.sp == _Unwind_GetGR(ctx, 13)) != 0)
			actions |= _UA_HANDLER_FRAME;
		break;
	case 2:	/* _US_UNWIND_FRAME_RESUME */
		CONTINUE_UNWIND;
	default:
		return _URC_FAILURE;
	}

	_Unwind_SetGR(ctx, 12, (uintptr_t)ex);
#endif
	struct objc_exception *e = (struct objc_exception *)ex;
	bool foreign = (ex_class != GNUCOBJC_EXCEPTION_CLASS);
	const uint8_t *lsda_addr, *actionrecords;
	struct lsda lsda;
	bool foreign = (exClass != GNUCOBJC_EXCEPTION_CLASS);
	const uint8_t *LSDAAddr, *actionRecords;
	struct lsda LSDA;
	uintptr_t landingpad = 0;
	uint8_t found = 0;
	intptr_t filter = 0;

	if (foreign) {
		switch (ex_class) {
		switch (exClass) {
#ifdef CXX_PERSONALITY
		case GNUCCXX0_EXCEPTION_CLASS:
		case CLNGCXX0_EXCEPTION_CLASS:
			if (cxx_personality != NULL)
				return CALL_PERSONALITY(cxx_personality);
			break;
#endif
634
635
636
637
638
639
640
641
642


643
644
645
646
647
648
649
650
651

652
653
654

655
656

657
658
659
660


661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679



680
681
682
683
684
685
686
634
635
636
637
638
639
640


641
642
643
644
645
646
647
648
649
650

651
652
653

654
655

656
657
658


659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676



677
678
679
680
681
682
683
684
685
686







-
-
+
+








-
+


-
+

-
+


-
-
+
+
















-
-
-
+
+
+







		    (uintptr_t)e->object);
#ifndef HAVE_ARM_EHABI_EXCEPTIONS
		_Unwind_SetGR(ctx, __builtin_eh_return_data_regno(1),
		    e->filter);
		_Unwind_SetIP(ctx, e->landingpad);
#else
		_Unwind_SetGR(ctx, __builtin_eh_return_data_regno(1),
		    ex->barrier_cache.bitpattern[1]);
		_Unwind_SetIP(ctx, ex->barrier_cache.bitpattern[3]);
		    ex->barrierCache.bitPattern[1]);
		_Unwind_SetIP(ctx, ex->barrierCache.bitPattern[3]);
#endif

		_Unwind_DeleteException(ex);

		return _URC_INSTALL_CONTEXT;
	}

	/* No LSDA -> nothing to handle */
	if ((lsda_addr = _Unwind_GetLanguageSpecificData(ctx)) == NULL)
	if ((LSDAAddr = _Unwind_GetLanguageSpecificData(ctx)) == NULL)
		CONTINUE_UNWIND;

	read_lsda(ctx, lsda_addr, &lsda);
	readLSDA(ctx, LSDAAddr, &LSDA);

	if (!find_callsite(ctx, &lsda, &landingpad, &actionrecords))
	if (!findCallsite(ctx, &LSDA, &landingpad, &actionRecords))
		CONTINUE_UNWIND;

	if (landingpad != 0 && actionrecords != NULL)
		found = find_actionrecord(actionrecords, &lsda, actions,
	if (landingpad != 0 && actionRecords != NULL)
		found = findActionRecord(actionRecords, &LSDA, actions,
		    foreign, e, &filter);
	else if (landingpad != 0)
		found = CLEANUP_FOUND;

	if (found == 0)
		CONTINUE_UNWIND;

	if (actions & _UA_SEARCH_PHASE) {
		if (!(found & HANDLER_FOUND) || foreign)
			CONTINUE_UNWIND;

		/* Cache it so we don't have to search it again in phase 2 */
#ifndef HAVE_ARM_EHABI_EXCEPTIONS
		e->landingpad = landingpad;
		e->filter = filter;
#else
		ex->barrier_cache.sp = _Unwind_GetGR(ctx, 13);
		ex->barrier_cache.bitpattern[1] = filter;
		ex->barrier_cache.bitpattern[3] = landingpad;
		ex->barrierCache.sp = _Unwind_GetGR(ctx, 13);
		ex->barrierCache.bitPattern[1] = filter;
		ex->barrierCache.bitPattern[3] = landingpad;
#endif

		return _URC_HANDLER_FOUND;
	} else if (actions & _UA_CLEANUP_PHASE) {
		if (!(found & CLEANUP_FOUND))
			CONTINUE_UNWIND;

698
699
700
701
702
703
704

705

706
707
708

709
710
711
712
713
714
715

716
717
718
719
720
721
722
723
724
725
726
727
728

729
730
731
732
733
734


735
736
737
738
739
740
741
742
743

744
745
746
747
748
749
750
751
752


753
754
755
756
757


758
759
760
761
762
763
764
765
766


767
768
769
770
771
772
773
698
699
700
701
702
703
704
705

706
707
708

709
710
711
712
713
714
715

716
717
718
719
720
721
722
723
724
725
726
727
728

729
730
731
732
733


734
735
736
737
738
739
740
741
742
743

744
745
746
747
748
749
750
751
752

753
754
755
756
757


758
759
760
761
762
763
764
765
766


767
768
769
770
771
772
773
774
775







+
-
+


-
+






-
+












-
+




-
-
+
+








-
+








-
+
+



-
-
+
+







-
-
+
+







static void
cleanup(_Unwind_Reason_Code reason, struct _Unwind_Exception *ex)
{
	free(ex);
}

static void
emergencyExceptionCleanup(_Unwind_Reason_Code reason,
cleanup_emergency(_Unwind_Reason_Code reason, struct _Unwind_Exception *ex)
    struct _Unwind_Exception *ex)
{
#ifdef OF_HAVE_THREADS
	if (!of_spinlock_lock(&emergency_exceptions_spinlock))
	if (!of_spinlock_lock(&emergencyExceptionsSpinlock))
		OBJC_ERROR("Cannot lock spinlock!");
#endif

	ex->class = 0;

#ifdef OF_HAVE_THREADS
	if (!of_spinlock_unlock(&emergency_exceptions_spinlock))
	if (!of_spinlock_unlock(&emergencyExceptionsSpinlock))
		OBJC_ERROR("Cannot unlock spinlock!");
#endif
}

void
objc_exception_throw(id object)
{
	struct objc_exception *e = calloc(1, sizeof(*e));
	bool emergency = false;

	if (e == NULL) {
#ifdef OF_HAVE_THREADS
		if (!of_spinlock_lock(&emergency_exceptions_spinlock))
		if (!of_spinlock_lock(&emergencyExceptionsSpinlock))
			OBJC_ERROR("Cannot lock spinlock!");
#endif

		for (uint_fast8_t i = 0; i < NUM_EMERGENCY_EXCEPTIONS; i++) {
			if (emergency_exceptions[i].exception.class == 0) {
				e = &emergency_exceptions[i];
			if (emergencyExceptions[i].exception.class == 0) {
				e = &emergencyExceptions[i];
				e->exception.class = GNUCOBJC_EXCEPTION_CLASS;
				emergency = true;

				break;
			}
		}

#ifdef OF_HAVE_THREADS
		if (!of_spinlock_unlock(&emergency_exceptions_spinlock))
		if (!of_spinlock_unlock(&emergencyExceptionsSpinlock))
			OBJC_ERROR("Cannot lock spinlock!");
#endif
	}

	if (e == NULL)
		OBJC_ERROR("Not enough memory to allocate exception!")

	e->exception.class = GNUCOBJC_EXCEPTION_CLASS;
	e->exception.cleanup = (emergency ? cleanup_emergency : cleanup);
	e->exception.cleanup = (emergency
	    ? emergencyExceptionCleanup : cleanup);
	e->object = object;

	if (_Unwind_RaiseException(&e->exception) == _URC_END_OF_STACK &&
	    uncaught_exception_handler != NULL)
		uncaught_exception_handler(object);
	    uncaughtExceptionHandler != NULL)
		uncaughtExceptionHandler(object);

	OBJC_ERROR("_Unwind_RaiseException() returned!")
}

objc_uncaught_exception_handler
objc_setUncaughtExceptionHandler(objc_uncaught_exception_handler handler)
{
	objc_uncaught_exception_handler old = uncaught_exception_handler;
	uncaught_exception_handler = handler;
	objc_uncaught_exception_handler old = uncaughtExceptionHandler;
	uncaughtExceptionHandler = handler;

	return old;
}

#ifdef HAVE_SEH_EXCEPTIONS
typedef EXCEPTION_DISPOSITION (*seh_personality_fn)(PEXCEPTION_RECORD, void *,
    PCONTEXT, PDISPATCHER_CONTEXT);

Modified src/runtime/hashtable.m from [0f765c0951] to [e12d752357].

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







-
-
+
+










-
+

-
+



-
+


-
+







-
+

-
-
+
+


-
+

-
+
+





-
+




-
-
+
+



-
+








	return table;
}

static void
resize(struct objc_hashtable *table, uint32_t count)
{
	uint32_t fullness, nsize;
	struct objc_hashtable_bucket **ndata;
	uint32_t fullness, newSize;
	struct objc_hashtable_bucket **newData;

	if (count > UINT32_MAX / sizeof(*table->data) || count > UINT32_MAX / 8)
		OBJC_ERROR("Integer overflow!");

	fullness = count * 8 / table->size;

	if (fullness >= 6) {
		if (table->size > UINT32_MAX / 2)
			return;

		nsize = table->size * 2;
		newSize = table->size * 2;
	} else if (fullness <= 1)
		nsize = table->size / 2;
		newSize = table->size / 2;
	else
		return;

	if (count < table->count && nsize < 16)
	if (count < table->count && newSize < 16)
		return;

	if ((ndata = calloc(nsize, sizeof(sizeof(*ndata)))) == NULL)
	if ((newData = calloc(newSize, sizeof(sizeof(*newData)))) == NULL)
		OBJC_ERROR("Not enough memory to resize hash table!");

	for (uint32_t i = 0; i < table->size; i++) {
		if (table->data[i] != NULL &&
		    table->data[i] != &objc_deleted_bucket) {
			uint32_t j, last;

			last = nsize;
			last = newSize;

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

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

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

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

			ndata[j] = table->data[i];
			newData[j] = table->data[i];
		}
	}

	free(table->data);
	table->data = ndata;
	table->size = nsize;
	table->data = newData;
	table->size = newSize;
}

static inline bool
index_for_key(struct objc_hashtable *table, const void *key, uint32_t *idx)
indexForKey(struct objc_hashtable *table, const void *key, uint32_t *idx)
{
	uint32_t i, hash;

	hash = table->hash(key) & (table->size - 1);

	for (i = hash; i < table->size && table->data[i] != NULL; i++) {
		if (table->data[i] == &objc_deleted_bucket)
162
163
164
165
166
167
168
169

170
171
172
173
174
175


176
177
178
179
180
181
182
163
164
165
166
167
168
169

170
171
172
173
174


175
176
177
178
179
180
181
182
183







-
+




-
-
+
+







	}

	return false;
}

void
objc_hashtable_set(struct objc_hashtable *table, const void *key,
    const void *obj)
    const void *object)
{
	uint32_t i, hash, last;
	struct objc_hashtable_bucket *bucket;

	if (index_for_key(table, key, &i)) {
		table->data[i]->obj = obj;
	if (indexForKey(table, key, &i)) {
		table->data[i]->object = object;
		return;
	}

	resize(table, table->count + 1);

	hash = table->hash(key);
	last = table->size;
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
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







-
+










-
+


-
+







-
+







		OBJC_ERROR("No free bucket!");

	if ((bucket = malloc(sizeof(*bucket))) == NULL)
		OBJC_ERROR("Not enough memory to allocate hash table bucket!");

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

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

void *
objc_hashtable_get(struct objc_hashtable *table, const void *key)
{
	uint32_t idx;

	if (!index_for_key(table, key, &idx))
	if (!indexForKey(table, key, &idx))
		return NULL;

	return (void *)table->data[idx]->obj;
	return (void *)table->data[idx]->object;
}

void
objc_hashtable_delete(struct objc_hashtable *table, const void *key)
{
	uint32_t idx;

	if (!index_for_key(table, key, &idx))
	if (!indexForKey(table, key, &idx))
		return;

	free(table->data[idx]);
	table->data[idx] = &objc_deleted_bucket;

	table->count--;
	resize(table, table->count);

Modified src/runtime/linklib/linklib.m from [dd93d6e841] to [f03a29b448].

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







-
+

-
+
+
+
+
+
+
+



-
+

-
+



-
-
-
-
-
-
-
+

-
+







	 */
	ctor();

	__objc_exec_class_m68k(module);
}

IMP
objc_msg_lookup(id obj, SEL sel)
objc_msg_lookup(id object, SEL selector)
{
	return objc_msg_lookup_m68k(obj, sel);
	return objc_msg_lookup_m68k(object, selector);
}

IMP
objc_msg_lookup_stret(id object, SEL selector)
{
	return objc_msg_lookup_stret_m68k(object, selector);
}

IMP
objc_msg_lookup_stret(id obj, SEL sel)
objc_msg_lookup_super(struct objc_super *super, SEL selector)
{
	return objc_msg_lookup_stret_m68k(obj, sel);
	return objc_msg_lookup_super_m68k(super, selector);
}

IMP
objc_msg_lookup_super(struct objc_super *super, SEL sel)
{
	return objc_msg_lookup_super_m68k(super, sel);
}

IMP
objc_msg_lookup_super_stret(struct objc_super *super, SEL sel)
objc_msg_lookup_super_stret(struct objc_super *super, SEL selector)
{
	return objc_msg_lookup_super_stret_m68k(super, sel);
	return objc_msg_lookup_super_stret_m68k(super, selector);
}

Class
objc_lookUpClass(const char *name)
{
	return objc_lookUpClass_m68k(name);
}
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
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







-
+


-
+




-
+


-
+











-
+

-
+



-
+

-
+



-
+

-
+









-
+

-
+



-
+

-
+







#endif

	OF_UNREACHABLE
}

#ifdef HAVE_SJLJ_EXCEPTIONS
int
__gnu_objc_personality_sj0(int version, int actions, uint64_t ex_class,
__gnu_objc_personality_sj0(int version, int actions, uint64_t exClass,
    void *ex, void *ctx)
{
	return __gnu_objc_personality_sj0_m68k(version, actions, &ex_class,
	return __gnu_objc_personality_sj0_m68k(version, actions, &exClass,
	    ex, ctx);
}
#else
int
__gnu_objc_personality_v0(int version, int actions, uint64_t ex_class,
__gnu_objc_personality_v0(int version, int actions, uint64_t exClass,
    void *ex, void *ctx)
{
	return __gnu_objc_personality_v0_m68k(version, actions, &ex_class,
	return __gnu_objc_personality_v0_m68k(version, actions, &exClass,
	    ex, ctx);
}
#endif

SEL
sel_registerName(const char *name)
{
	return sel_registerName_m68k(name);
}

const char *
sel_getName(SEL sel)
sel_getName(SEL selector)
{
	return sel_getName_m68k(sel);
	return sel_getName_m68k(selector);
}

bool
sel_isEqual(SEL sel1, SEL sel2)
sel_isEqual(SEL selector1, SEL selector2)
{
	return sel_isEqual_m68k(sel1, sel2);
	return sel_isEqual_m68k(selector1, selector2);
}

Class
objc_allocateClassPair(Class superclass, const char *name, size_t extra_bytes)
objc_allocateClassPair(Class superclass, const char *name, size_t extraBytes)
{
	return objc_allocateClassPair_m68k(superclass, name, extra_bytes);
	return objc_allocateClassPair_m68k(superclass, name, extraBytes);
}

void
objc_registerClassPair(Class cls)
{
	objc_registerClassPair_m68k(cls);
}

unsigned int
objc_getClassList(Class *buf, unsigned int count)
objc_getClassList(Class *buffer, unsigned int count)
{
	return objc_getClassList_m68k(buf, count);
	return objc_getClassList_m68k(buffer, count);
}

Class *
objc_copyClassList(unsigned int *len)
objc_copyClassList(unsigned int *length)
{
	return objc_copyClassList_m68k(len);
	return objc_copyClassList_m68k(length);
}

bool
class_isMetaClass(Class cls)
{
	return class_isMetaClass_m68k(cls);
}
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
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







-
+

-
+



-
+

-
+



-
+

-
+



-
+

-
+



-
+

-
+



-
+
+

-
+
+



-
+
+

-
+
+







unsigned long
class_getInstanceSize(Class cls)
{
	return class_getInstanceSize_m68k(cls);
}

bool
class_respondsToSelector(Class cls, SEL sel)
class_respondsToSelector(Class cls, SEL selector)
{
	return class_respondsToSelector_m68k(cls, sel);
	return class_respondsToSelector_m68k(cls, selector);
}

bool
class_conformsToProtocol(Class cls, Protocol *p)
class_conformsToProtocol(Class cls, Protocol *protocol)
{
	return class_conformsToProtocol_m68k(cls, p);
	return class_conformsToProtocol_m68k(cls, protocol);
}

IMP
class_getMethodImplementation(Class cls, SEL sel)
class_getMethodImplementation(Class cls, SEL selector)
{
	return class_getMethodImplementation_m68k(cls, sel);
	return class_getMethodImplementation_m68k(cls, selector);
}

IMP
class_getMethodImplementation_stret(Class cls, SEL sel)
class_getMethodImplementation_stret(Class cls, SEL selector)
{
	return class_getMethodImplementation_stret_m68k(cls, sel);
	return class_getMethodImplementation_stret_m68k(cls, selector);
}

const char *
class_getMethodTypeEncoding(Class cls, SEL sel)
class_getMethodTypeEncoding(Class cls, SEL selector)
{
	return class_getMethodTypeEncoding_m68k(cls, sel);
	return class_getMethodTypeEncoding_m68k(cls, selector);
}

bool
class_addMethod(Class cls, SEL sel, IMP imp, const char *types)
class_addMethod(Class cls, SEL selector, IMP implementation,
    const char *typeEncoding)
{
	return class_addMethod_m68k(cls, sel, imp, types);
	return class_addMethod_m68k(cls, selector, implementation,
	    typeEncoding);
}

IMP
class_replaceMethod(Class cls, SEL sel, IMP imp, const char *types)
class_replaceMethod(Class cls, SEL selector, IMP implementation,
    const char *typeEncoding)
{
	return class_replaceMethod_m68k(cls, sel, imp, types);
	return class_replaceMethod_m68k(cls, selector, implementation,
	    typeEncoding);
}

Class
object_getClass(id object)
{
	return object_getClass_m68k(object);
}
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
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







-
+

-
+



-
+

-
+



-
+

-
+















-
+

-
+













const char *
object_getClassName(id object)
{
	return object_getClassName_m68k(object);
}

const char *
protocol_getName(Protocol *p)
protocol_getName(Protocol *protocol)
{
	return protocol_getName_m68k(p);
	return protocol_getName_m68k(protocol);
}

bool
protocol_isEqual(Protocol *a, Protocol *b)
protocol_isEqual(Protocol *protocol1, Protocol *protocol2)
{
	return protocol_isEqual_m68k(a, b);
	return protocol_isEqual_m68k(protocol1, protocol2);
}

bool
protocol_conformsToProtocol(Protocol *a, Protocol *b)
protocol_conformsToProtocol(Protocol *protocol1, Protocol *protocol2)
{
	return protocol_conformsToProtocol_m68k(a, b);
	return protocol_conformsToProtocol_m68k(protocol1, protocol2);
}

void
objc_exit(void)
{
	objc_exit_m68k();
}

objc_uncaught_exception_handler
objc_setUncaughtExceptionHandler(objc_uncaught_exception_handler handler)
{
	return objc_setUncaughtExceptionHandler_m68k(handler);
}

void
objc_setForwardHandler(IMP forward, IMP forward_stret)
objc_setForwardHandler(IMP forward, IMP stretForward)
{
	objc_setForwardHandler_m68k(forward, forward_stret);
	objc_setForwardHandler_m68k(forward, stretForward);
}

void
objc_setEnumerationMutationHandler(objc_enumeration_mutation_handler handler)
{
	objc_setEnumerationMutationHandler_m68k(handler);
}

void
objc_zero_weak_references(id value)
{
	objc_zero_weak_references_m68k(value);
}

Modified src/runtime/lookup.m from [dc384327e0] to [5c7645fb2a].

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







-
-
+
+


-
+
+


-
-
+
+


+
-
+

-
-
+
+
+













-
+



-
-
+
+



-
-
+
+


-
+
+

-
+


-
-
+
+

-
+

-
-
+
+


-
-
+
+

-
+







-
+
+



-
+

-
-
+
+



-
+

-
-
+
+



-
+

-
-
+
+



-
+




-
+
+




-
+





-
+



-
-
+
+

-
+
+


-
+





-
+

-
+



-
+

-
+



-
-
+
+




-
+

-
+


-
+





-
+

-
+



-
+

-
+


	Class isa;
}

+ (bool)resolveClassMethod: (SEL)selector;
+ (bool)resolveInstanceMethod: (SEL)selector;
@end

static IMP forward_handler = (IMP)0;
static IMP forward_handler_stret = (IMP)0;
static IMP forwardHandler = (IMP)0;
static IMP stretForwardHandler = (IMP)0;

static IMP
common_method_not_found(id obj, SEL sel, IMP (*lookup)(id, SEL), IMP forward)
commonMethodNotFound(id object, SEL selector, IMP (*lookup)(id, SEL),
    IMP forward)
{
	/*
	 * obj might be a dummy object (see class_getMethodImplementation), so
	 * don't access obj directly unless it's a class!
	 * object might be a dummy object (see class_getMethodImplementation),
	 * so don't access object directly unless it's a class!
	 */

	bool isClass =
	bool is_class = object_getClass(obj)->info & OBJC_CLASS_INFO_METACLASS;
	    object_getClass(object)->info & OBJC_CLASS_INFO_METACLASS;

	if (!(object_getClass(obj)->info & OBJC_CLASS_INFO_INITIALIZED)) {
		Class cls = (is_class ? (Class)obj : object_getClass(obj));
	if (!(object_getClass(object)->info & OBJC_CLASS_INFO_INITIALIZED)) {
		Class cls = (isClass
		    ? (Class)object : object_getClass(object));

		objc_initialize_class(cls);

		if (!(cls->info & OBJC_CLASS_INFO_SETUP))
			OBJC_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 lookup(obj, sel);
		return lookup(object, selector);
	}

	/* Try resolveClassMethod: / resolveInstanceMethod: */
	if (class_isMetaClass(object_getClass(obj))) {
		Class cls = object_getClass(obj);
	if (class_isMetaClass(object_getClass(object))) {
		Class cls = object_getClass(object);

		if (class_respondsToSelector(cls,
		    @selector(resolveClassMethod:)) &&
		    [obj resolveClassMethod: sel]) {
			if (!class_respondsToSelector(cls, sel))
		    [object resolveClassMethod: selector]) {
			if (!class_respondsToSelector(cls, selector))
				OBJC_ERROR("[%s resolveClassMethod: %s] "
				    "returned true without adding the method!",
				    class_getName(obj), sel_getName(sel));
				    class_getName(object),
				    sel_getName(selector));

			return lookup(obj, sel);
			return lookup(object, selector);
		}
	} else {
		Class cls = object_getClass(obj);
		Class metacls = object_getClass(cls);
		Class cls = object_getClass(object);
		Class metaclass = object_getClass(cls);

		if (class_respondsToSelector(metacls,
		if (class_respondsToSelector(metaclass,
		    @selector(resolveInstanceMethod:)) &&
		    [cls resolveInstanceMethod: sel]) {
			if (!class_respondsToSelector(cls, sel))
		    [cls resolveInstanceMethod: selector]) {
			if (!class_respondsToSelector(cls, selector))
				OBJC_ERROR("[%s resolveInstanceMethod: %s] "
				    "returned true without adding the method!",
				    class_getName(object_getClass(obj)),
				    sel_getName(sel));
				    class_getName(object_getClass(object)),
				    sel_getName(selector));

			return lookup(obj, sel);
			return lookup(object, selector);
		}
	}

	if (forward != (IMP)0)
		return forward;

	OBJC_ERROR("Selector %c[%s] is not implemented for class %s!",
	    (is_class ? '+' : '-'), sel_getName(sel), object_getClassName(obj));
	    (isClass ? '+' : '-'), sel_getName(selector),
	    object_getClassName(object));
}

IMP
objc_method_not_found(id obj, SEL sel)
objc_method_not_found(id object, SEL selector)
{
	return common_method_not_found(obj, sel, objc_msg_lookup,
	    forward_handler);
	return commonMethodNotFound(object, selector, objc_msg_lookup,
	    forwardHandler);
}

IMP
objc_method_not_found_stret(id obj, SEL sel)
objc_method_not_found_stret(id object, SEL selector)
{
	return common_method_not_found(obj, sel, objc_msg_lookup_stret,
	    forward_handler_stret);
	return commonMethodNotFound(object, selector, objc_msg_lookup_stret,
	    stretForwardHandler);
}

void
objc_setForwardHandler(IMP forward, IMP forward_stret)
objc_setForwardHandler(IMP forward, IMP stretForward)
{
	forward_handler = forward;
	forward_handler_stret = forward_stret;
	forwardHandler = forward;
	stretForwardHandler = stretForward;
}

bool
class_respondsToSelector(Class cls, SEL sel)
class_respondsToSelector(Class cls, SEL selector)
{
	if (cls == Nil)
		return false;

	return (objc_dtable_get(cls->dtable, (uint32_t)sel->uid) != (IMP)0);
	return (objc_dtable_get(cls->DTable,
	    (uint32_t)selector->UID) != (IMP)0);
}

#ifndef OF_ASM_LOOKUP
static id
nil_method(id self, SEL _cmd)
nilMethod(id self, SEL _cmd)
{
	return nil;
}

static OF_INLINE IMP
common_lookup(id obj, SEL sel, IMP (*not_found)(id, SEL))
commonLookup(id object, SEL selector, IMP (*notFound)(id, SEL))
{
	IMP imp;

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

	imp = objc_dtable_get(object_getClass(obj)->dtable, (uint32_t)sel->uid);
	imp = objc_dtable_get(object_getClass(object)->DTable,
	    (uint32_t)selector->UID);

	if (imp == (IMP)0)
		return not_found(obj, sel);
		return notFound(object, selector);

	return imp;
}

IMP
objc_msg_lookup(id obj, SEL sel)
objc_msg_lookup(id object, SEL selector)
{
	return common_lookup(obj, sel, objc_method_not_found);
	return commonLookup(object, selector, objc_method_not_found);
}

IMP
objc_msg_lookup_stret(id obj, SEL sel)
objc_msg_lookup_stret(id object, SEL selector)
{
	return common_lookup(obj, sel, objc_method_not_found_stret);
	return commonLookup(object, selector, objc_method_not_found_stret);
}

static OF_INLINE IMP
common_lookup_super(struct objc_super *super, SEL sel,
    IMP (*not_found)(id, SEL))
commonSuperLookup(struct objc_super *super, SEL selector,
    IMP (*notFound)(id, SEL))
{
	IMP imp;

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

	imp = objc_dtable_get(super->cls->dtable, (uint32_t)sel->uid);
	imp = objc_dtable_get(super->cls->DTable, (uint32_t)selector->UID);

	if (imp == (IMP)0)
		return not_found(super->self, sel);
		return notFound(super->self, selector);

	return imp;
}

IMP
objc_msg_lookup_super(struct objc_super *super, SEL sel)
objc_msg_lookup_super(struct objc_super *super, SEL selector)
{
	return common_lookup_super(super, sel, objc_method_not_found);
	return commonSuperLookup(super, selector, objc_method_not_found);
}

IMP
objc_msg_lookup_super_stret(struct objc_super *super, SEL sel)
objc_msg_lookup_super_stret(struct objc_super *super, SEL selector)
{
	return common_lookup_super(super, sel, objc_method_not_found_stret);
	return commonSuperLookup(super, selector, objc_method_not_found_stret);
}
#endif

Modified src/runtime/misc.m from [eb872870de] to [ec4648bae1].

19
20
21
22
23
24
25
26

27
28
29

30
31
32


33
34
35
36
37
38
39
40

41
19
20
21
22
23
24
25

26
27
28

29
30


31
32
33
34
35
36
37
38
39

40
41







-
+


-
+

-
-
+
+







-
+


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

#include "ObjFW_RT.h"
#include "private.h"

static objc_enumeration_mutation_handler enumeration_mutation_handler = NULL;
static objc_enumeration_mutation_handler enumerationMutationHandler = NULL;

void
objc_enumerationMutation(id obj)
objc_enumerationMutation(id object)
{
	if (enumeration_mutation_handler != NULL)
		enumeration_mutation_handler(obj);
	if (enumerationMutationHandler != NULL)
		enumerationMutationHandler(object);
	else
		OBJC_ERROR("Object was mutated during enumeration!");
}

void
objc_setEnumerationMutationHandler(objc_enumeration_mutation_handler handler)
{
	enumeration_mutation_handler = handler;
	enumerationMutationHandler = handler;
}

Modified src/runtime/private.h from [a8dbb85724] to [69f97ea107].

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







-
-
-
-
-
-
+
+
+
+
+
+

-
-
-
+
+
+





-
+



-
-
+
+









-
-
-
-
+
+
+
+





-
+








-
+





-
-
-
+
+
+











-
+















-
+








struct objc_abi_class {
	struct objc_abi_class *_Nonnull metaclass;
	const char *_Nullable superclass;
	const char *_Nonnull name;
	unsigned long version;
	unsigned long info;
	long instance_size;
	void *_Nullable ivars;
	struct objc_abi_method_list *_Nullable methodlist;
	void *_Nullable dtable;
	void *_Nullable subclass_list;
	void *_Nullable sibling_class;
	long instanceSize;
	void *_Nullable iVars;
	struct objc_abi_method_list *_Nullable methodList;
	void *_Nullable DTable;
	void *_Nullable subclassList;
	void *_Nullable siblingClass;
	void *_Nullable protocols;
	void *_Nullable gc_object_type;
	long abi_version;
	int32_t *_Nonnull *_Nullable ivar_offsets;
	void *_Nullable GCObjectType;
	long ABIVersion;
	int32_t *_Nonnull *_Nullable iVarOffsets;
	void *_Nullable properties;
};

struct objc_abi_selector {
	const char *_Nonnull name;
	const char *_Nullable types;
	const char *_Nullable typeEncoding;
};

struct objc_abi_method {
	struct objc_abi_selector sel;
	IMP _Nonnull imp;
	struct objc_abi_selector selector;
	IMP _Nonnull implementation;
};

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

struct objc_abi_category {
	const char *_Nonnull category_name;
	const char *_Nonnull class_name;
	struct objc_abi_method_list *_Nullable instance_methods;
	struct objc_abi_method_list *_Nullable class_methods;
	const char *_Nonnull categoryName;
	const char *_Nonnull className;
	struct objc_abi_method_list *_Nullable instanceMethods;
	struct objc_abi_method_list *_Nullable classMethods;
	struct objc_protocol_list *_Nullable protocols;
};

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

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

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

struct objc_abi_symtab {
	unsigned long unknown;
	struct objc_abi_selector *_Nullable sel_refs;
	uint16_t cls_def_cnt;
	uint16_t cat_def_cnt;
	struct objc_abi_selector *_Nullable selectorRefs;
	uint16_t classDefsCount;
	uint16_t categoryDefsCount;
	void *_Nonnull defs[1];
};

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

struct objc_hashtable_bucket {
	const void *_Nonnull key, *_Nonnull obj;
	const void *_Nonnull key, *_Nonnull object;
	uint32_t hash;
};

struct objc_hashtable {
	uint32_t (*_Nonnull hash)(const void *_Nonnull key);
	bool (*_Nonnull equal)(const void *_Nonnull key1,
	    const void *_Nonnull key2);
	uint32_t count, size;
	struct objc_hashtable_bucket *_Nonnull *_Nullable data;
};

struct objc_sparsearray {
	struct objc_sparsearray_data {
		void *_Nullable next[256];
	} *_Nonnull data;
	uint8_t index_size;
	uint8_t indexSize;
};

struct objc_dtable {
	struct objc_dtable_level2 {
#ifdef OF_SELUID24
		struct objc_dtable_level3 {
			IMP _Nullable buckets[256];

Modified src/runtime/protocol.m from [b358c4c8b1] to [5ec5a018d6].

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







-
+

-
+



-
+

-
+
+



-
+

-
+


-
-
-
-
+
+
+
+
+






-
+

-
+




-
-
-
-
+
+
+
+
+




-
+




-
-
-
-
+
+
+
+
+

-
+











#import "ObjFW_RT.h"
#import "private.h"

@implementation Protocol
@end

const char *
protocol_getName(Protocol *p)
protocol_getName(Protocol *protocol)
{
	return p->name;
	return protocol->name;
}

bool
protocol_isEqual(Protocol *a, Protocol *b)
protocol_isEqual(Protocol *protocol1, Protocol *protocol2)
{
	return (strcmp(protocol_getName(a), protocol_getName(b)) == 0);
	return (strcmp(protocol_getName(protocol1),
	    protocol_getName(protocol2)) == 0);
}

bool
protocol_conformsToProtocol(Protocol *a, Protocol *b)
protocol_conformsToProtocol(Protocol *protocol1, Protocol *protocol2)
{
	if (protocol_isEqual(a, b))
	if (protocol_isEqual(protocol1, protocol2))
		return true;

	for (struct objc_protocol_list *pl = a->protocol_list;
	    pl != NULL; pl = pl->next)
		for (long i = 0; i < pl->count; i++)
			if (protocol_conformsToProtocol(pl->list[i], b))
	for (struct objc_protocol_list *protocolList = protocol1->protocolList;
	    protocolList != NULL; protocolList = protocolList->next)
		for (long i = 0; i < protocolList->count; i++)
			if (protocol_conformsToProtocol(protocolList->list[i],
			    protocol2))
				return true;

	return false;
}

bool
class_conformsToProtocol(Class cls, Protocol *p)
class_conformsToProtocol(Class cls, Protocol *protocol)
{
	struct objc_category **cats;
	struct objc_category **categories;

	if (cls == Nil)
		return false;

	for (struct objc_protocol_list *pl = cls->protocols;
	    pl != NULL; pl = pl->next)
		for (long i = 0; i < pl->count; i++)
			if (protocol_conformsToProtocol(pl->list[i], p))
	for (struct objc_protocol_list *protocolList = cls->protocols;
	    protocolList != NULL; protocolList = protocolList->next)
		for (long i = 0; i < protocolList->count; i++)
			if (protocol_conformsToProtocol(protocolList->list[i],
			    protocol))
				return true;

	objc_global_mutex_lock();

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

	for (long i = 0; cats[i] != NULL; i++) {
		for (struct objc_protocol_list *pl = cats[i]->protocols;
		    pl != NULL; pl = pl->next) {
			for (long j = 0; j < pl->count; j++) {
	for (long i = 0; categories[i] != NULL; i++) {
		for (struct objc_protocol_list *protocolList =
		    categories[i]->protocols; protocolList != NULL;
		    protocolList = protocolList->next) {
			for (long j = 0; j < protocolList->count; j++) {
				if (protocol_conformsToProtocol(
				    pl->list[j], p)) {
				    protocolList->list[j], protocol)) {
					objc_global_mutex_unlock();
					return true;
				}
			}
		}
	}

	objc_global_mutex_unlock();

	return false;
}

Modified src/runtime/selector.m from [739d0a98ef] to [6c2deedb05].

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







-
-
-
-
+
+
+
+







-
+






-
+



-
-
+
+



-
+


-
+







# define SEL_SIZE 3
#else
# define SEL_MAX 0xFFFF
# define SEL_SIZE 2
#endif

static struct objc_hashtable *selectors = NULL;
static uint32_t selectors_cnt = 0;
static struct objc_sparsearray *selector_names = NULL;
static void **free_list = NULL;
static size_t free_list_cnt = 0;
static uint32_t selectorsCount = 0;
static struct objc_sparsearray *selectorNames = NULL;
static void **freeList = NULL;
static size_t freeListCount = 0;

void
objc_register_selector(struct objc_abi_selector *sel)
{
	struct objc_selector *rsel;
	const char *name;

	if (selectors_cnt > SEL_MAX)
	if (selectorsCount > SEL_MAX)
		OBJC_ERROR("Out of selector slots!");

	if (selectors == NULL)
		selectors = objc_hashtable_new(
		    objc_hash_string, objc_equal_string, 2);
	else if ((rsel = objc_hashtable_get(selectors, sel->name)) != NULL) {
		((struct objc_selector *)sel)->uid = rsel->uid;
		((struct objc_selector *)sel)->UID = rsel->UID;
		return;
	}

	if (selector_names == NULL)
		selector_names = objc_sparsearray_new(SEL_SIZE);
	if (selectorNames == NULL)
		selectorNames = objc_sparsearray_new(SEL_SIZE);

	name = sel->name;
	rsel = (struct objc_selector *)sel;
	rsel->uid = selectors_cnt++;
	rsel->UID = selectorsCount++;

	objc_hashtable_set(selectors, name, rsel);
	objc_sparsearray_set(selector_names, (uint32_t)rsel->uid, (void *)name);
	objc_sparsearray_set(selectorNames, (uint32_t)rsel->UID, (void *)name);
}

SEL
sel_registerName(const char *name)
{
	const struct objc_abi_selector *rsel;
	struct objc_abi_selector *sel;
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
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







-
+

-
-
+
+


-
-
+
+












-
+


-
+




-
+




-
+






-
+

-
+






-
+

-
-
-
+
+
+

-
+



-
-
-
-
+
+
+
+


	if ((sel = malloc(sizeof(struct objc_abi_selector))) == NULL)
		OBJC_ERROR("Not enough memory to allocate selector!");

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

	sel->types = NULL;
	sel->typeEncoding = NULL;

	if ((free_list = realloc(free_list,
	    sizeof(void *) * (free_list_cnt + 2))) == NULL)
	if ((freeList = realloc(freeList,
	    sizeof(void *) * (freeListCount + 2))) == NULL)
		OBJC_ERROR("Not enough memory to allocate selector!");

	free_list[free_list_cnt++] = sel;
	free_list[free_list_cnt++] = (char *)sel->name;
	freeList[freeListCount++] = sel;
	freeList[freeListCount++] = (char *)sel->name;

	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)
	if (symtab->selectorRefs == NULL)
		return;

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

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

	objc_global_mutex_lock();
	ret = objc_sparsearray_get(selector_names, (uint32_t)sel->uid);
	ret = objc_sparsearray_get(selectorNames, (uint32_t)selector->UID);
	objc_global_mutex_unlock();

	return ret;
}

bool
sel_isEqual(SEL sel1, SEL sel2)
sel_isEqual(SEL selector1, SEL selector2)
{
	return (sel1->uid == sel2->uid);
	return (selector1->UID == selector2->UID);
}

void
objc_unregister_all_selectors(void)
{
	objc_hashtable_free(selectors);
	objc_sparsearray_free(selector_names);
	objc_sparsearray_free(selectorNames);

	if (free_list != NULL) {
		for (size_t i = 0; i < free_list_cnt; i++)
			free(free_list[i]);
	if (freeList != NULL) {
		for (size_t i = 0; i < freeListCount; i++)
			free(freeList[i]);

		free(free_list);
		free(freeList);
	}

	selectors = NULL;
	selectors_cnt = 0;
	selector_names = NULL;
	free_list = NULL;
	free_list_cnt = 0;
	selectorsCount = 0;
	selectorNames = NULL;
	freeList = NULL;
	freeListCount = 0;
}

Modified src/runtime/sparsearray.m from [391fc24950] to [4f833eac9f].

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







-
+









-
+









-
+

-
+














-
+

-
+














-
+





-
+







-
+


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

#import "ObjFW_RT.h"
#import "private.h"

struct objc_sparsearray *
objc_sparsearray_new(uint8_t index_size)
objc_sparsearray_new(uint8_t indexSize)
{
	struct objc_sparsearray *sparsearray;

	if ((sparsearray = calloc(1, sizeof(*sparsearray))) == NULL)
		OBJC_ERROR("Failed to allocate memory for sparse array!");

	if ((sparsearray->data = calloc(1, sizeof(*sparsearray->data))) == NULL)
		OBJC_ERROR("Failed to allocate memory for sparse array!");

	sparsearray->index_size = index_size;
	sparsearray->indexSize = indexSize;

	return sparsearray;
}

void *
objc_sparsearray_get(struct objc_sparsearray *sparsearray, uintptr_t idx)
{
	struct objc_sparsearray_data *iter = sparsearray->data;

	for (uint8_t i = 0; i < sparsearray->index_size - 1; i++) {
	for (uint8_t i = 0; i < sparsearray->indexSize - 1; i++) {
		uintptr_t j =
		    (idx >> ((sparsearray->index_size - i - 1) * 8)) & 0xFF;
		    (idx >> ((sparsearray->indexSize - i - 1) * 8)) & 0xFF;

		if ((iter = iter->next[j]) == NULL)
			return NULL;
	}

	return iter->next[idx & 0xFF];
}

void
objc_sparsearray_set(struct objc_sparsearray *sparsearray, uintptr_t idx,
    void *value)
{
	struct objc_sparsearray_data *iter = sparsearray->data;

	for (uint8_t i = 0; i < sparsearray->index_size - 1; i++) {
	for (uint8_t i = 0; i < sparsearray->indexSize - 1; i++) {
		uintptr_t j =
		    (idx >> ((sparsearray->index_size - i - 1) * 8)) & 0xFF;
		    (idx >> ((sparsearray->indexSize - i - 1) * 8)) & 0xFF;

		if (iter->next[j] == NULL)
			if ((iter->next[j] = calloc(1,
			    sizeof(struct objc_sparsearray_data))) == NULL)
				OBJC_ERROR("Failed to allocate memory for "
				    "sparse array!");

		iter = iter->next[j];
	}

	iter->next[idx & 0xFF] = value;
}

static void
free_sparsearray_data(struct objc_sparsearray_data *data, uint8_t depth)
freeSparsearrayData(struct objc_sparsearray_data *data, uint8_t depth)
{
	if (data == NULL || depth == 0)
		return;

	for (uint_fast16_t i = 0; i < 256; i++)
		free_sparsearray_data(data->next[i], depth - 1);
		freeSparsearrayData(data->next[i], depth - 1);

	free(data);
}

void
objc_sparsearray_free(struct objc_sparsearray *sparsearray)
{
	free_sparsearray_data(sparsearray->data, sparsearray->index_size);
	freeSparsearrayData(sparsearray->data, sparsearray->indexSize);
	free(sparsearray);
}

Modified src/runtime/static-instances.m from [46b4e85118] to [e9f2e9fced].

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







-
-
+
+




-
+


-
-
+
+
+


-
+



-
+

-
-
-
+
+
+



-
-
+
+

-
+

-
+

-
+











-
-
+
+

-
+


-
-
+
+


-
+



-
+

-
+

-
+



+
-
+







-
-
-
+
+
+


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

#import "ObjFW_RT.h"
#import "private.h"

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

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

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

		if (cls != Nil) {
			for (id *instances = static_instances[i]->instances;
			for (id *instances = staticInstancesList[i]->instances;
			    *instances != nil; instances++)
				object_setClass(*instances, cls);

			static_instances_cnt--;
			staticInstancesCount--;

			if (static_instances_cnt == 0) {
				free(static_instances);
				static_instances = NULL;
			if (staticInstancesCount == 0) {
				free(staticInstancesList);
				staticInstancesList = NULL;
				break;
			}

			static_instances[i] =
			    static_instances[static_instances_cnt];
			staticInstancesList[i] =
			    staticInstancesList[staticInstancesCount];

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

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

			/*
			 * We moved the last entry to the current index,
			 * therefore we need to run again for the current index.
			 */
			i--;
		}
	}

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

	if (si == NULL)
	if (staticInstances == NULL)
		return;

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

		if (cls != Nil) {
			for (id *instances = (*si)->instances;
			for (id *instances = (*staticInstances)->instances;
			    *instances != nil; instances++)
				object_setClass(*instances, cls);
		} else {
			static_instances = realloc(static_instances,
			staticInstancesList = realloc(staticInstancesList,
			    sizeof(struct objc_abi_static_instances *) *
			    (static_instances_cnt + 1));
			    (staticInstancesCount + 1));

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

			staticInstancesList[staticInstancesCount++] =
			static_instances[static_instances_cnt++] = *si;
			    *staticInstances;
		}
	}
}

void
objc_forget_pending_static_instances()
{
	free(static_instances);
	static_instances = NULL;
	static_instances_cnt = 0;
	free(staticInstancesList);
	staticInstancesList = NULL;
	staticInstancesCount = 0;
}

Modified src/runtime/threading.m from [5f55cac459] to [7a03675ae5].

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







-
+




-
+









-
+






-
+


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

#import "ObjFW_RT.h"
#import "private.h"
#import "threading.h"

static of_rmutex_t global_mutex;
static of_rmutex_t globalMutex;

static void
init(void)
{
	if (!of_rmutex_new(&global_mutex))
	if (!of_rmutex_new(&globalMutex))
		OBJC_ERROR("Failed to create global mutex!");
}

void
objc_global_mutex_lock(void)
{
	static of_once_t once_control = OF_ONCE_INIT;
	of_once(&once_control, init);

	if (!of_rmutex_lock(&global_mutex))
	if (!of_rmutex_lock(&globalMutex))
		OBJC_ERROR("Failed to lock global mutex!");
}

void
objc_global_mutex_unlock(void)
{
	if (!of_rmutex_unlock(&global_mutex))
	if (!of_rmutex_unlock(&globalMutex))
		OBJC_ERROR("Failed to unlock global mutex!");
}