ObjFW  Check-in [2b75f9e6a0]

Overview
Comment:runtime: Name things more consistently
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 2b75f9e6a0cd6c675c89b49e108bc65e8dd6138e54c3209ea1eeaa92dadbc3b1
User & Date: js on 2021-05-02 11:34:01
Other Links: manifest | tags
Context
2021-05-02
11:43
runtime: objc_unregisterClass: Get global lock check-in: ae80dcd8e0 user: js tags: trunk
11:34
runtime: Name things more consistently check-in: 2b75f9e6a0 user: js tags: trunk
09:40
Remove leftover files check-in: 25de908a52 user: js tags: trunk
Changes

Modified src/OFObject.h from [6b4d0acc99] to [256748162e].

625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
/**
 * @brief A method which is called when the class is unloaded from the runtime.
 *
 * Derived classes can override this to execute their own code when the class
 * is unloaded.
 *
 * @warning This is not supported by the Apple runtime and currently only
 *	    called by the ObjFW runtime when objc_unregister_class() or
 *	    objc_exit() has been called!
 *	    In the future, this might also be called by the ObjFW runtime when
 *	    the class is part of a plugin that has been unloaded.
 */
+ (void)unload;

/**
 * @brief A method which is called the moment before the first call to the class
 *	  is being made.
 *







|
<

|







625
626
627
628
629
630
631
632

633
634
635
636
637
638
639
640
641
/**
 * @brief A method which is called when the class is unloaded from the runtime.
 *
 * Derived classes can override this to execute their own code when the class
 * is unloaded.
 *
 * @warning This is not supported by the Apple runtime and currently only
 *	    called by the ObjFW runtime when @ref objc_deinit has been called!

 *	    In the future, this might also be called by the ObjFW runtime when
 *	    the class is part of a plugin that is being unloaded.
 */
+ (void)unload;

/**
 * @brief A method which is called the moment before the first call to the class
 *	  is being made.
 *

Modified src/runtime/ObjFWRT.h from [1456702210] to [4089c697eb].

142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
typedef id _Nullable (*IMP)(id _Nonnull object, SEL _Nonnull selector, ...);

/**
 * @brief A handler for uncaught exceptions.
 *
 * @param exception The exception which was not caught.
 */
typedef void (*objc_uncaught_exception_handler_t)(id _Nullable exception);

/**
 * @brief A handler for mutation during enumeration.
 *
 * @param object The object that was mutated during enumeration
 */
typedef void (*objc_enumeration_mutation_handler_t)(id _Nonnull object);

/**
 * @brief A struct representing a call to super.
 */
struct objc_super {
	/**
	 * @brief The object on which to perform the super call.







|






|







142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
typedef id _Nullable (*IMP)(id _Nonnull object, SEL _Nonnull selector, ...);

/**
 * @brief A handler for uncaught exceptions.
 *
 * @param exception The exception which was not caught.
 */
typedef void (*objc_uncaught_exception_handler)(id _Nullable exception);

/**
 * @brief A handler for mutation during enumeration.
 *
 * @param object The object that was mutated during enumeration
 */
typedef void (*objc_enumeration_mutation_handler)(id _Nonnull object);

/**
 * @brief A struct representing a call to super.
 */
struct objc_super {
	/**
	 * @brief The object on which to perform the super call.
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
 * @return A copy of the attribute value. You need to call `free()` on it when
 *	   done.
 */
extern char *_Nullable property_copyAttributeValue(
    objc_property_t _Nonnull property, const char *_Nonnull name);

/**
 * @brief Exits the Objective-C runtime.
 *
 * This frees all data structures used by the runtime, after which Objective-C
 * can no longer be used inside the current process. This is only useful for
 * debugging.
 */
extern void objc_exit(void);

/**
 * @brief Sets the handler for uncaught exceptions.
 *
 * @param handler The new handler for uncaught exceptions
 * @return The old handler for uncaught exceptions
 */
extern _Nullable objc_uncaught_exception_handler_t
    objc_setUncaughtExceptionHandler(
    objc_uncaught_exception_handler_t _Nullable handler);

/**
 * @brief Sets the forwarding handler for unimplemented methods.
 *
 * @param forward The forwarding handler for regular methods
 * @param stretForward The forwarding handler for methods using the struct
 *		       return ABI
 */
extern void objc_setForwardHandler(IMP _Nullable forward,
    IMP _Nullable stretForward);

/**
 * @brief Sets the handler for mutations during enumeration.
 *
 * @param handler The handler for mutations during enumeration
 */
extern void objc_setEnumerationMutationHandler(
    objc_enumeration_mutation_handler_t _Nullable handler);

/**
 * @brief Constructs an instance of the specified class in the specified array
 *	  of bytes.
 *
 * @param class_ The class of which to construct an instance
 * @param bytes An array of bytes of at least the length of the instance size.







|



|

|







|

|

















|







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
 * @return A copy of the attribute value. You need to call `free()` on it when
 *	   done.
 */
extern char *_Nullable property_copyAttributeValue(
    objc_property_t _Nonnull property, const char *_Nonnull name);

/**
 * @brief Deinitializes the Objective-C runtime.
 *
 * This frees all data structures used by the runtime, after which Objective-C
 * can no longer be used inside the current process. This is only useful for
 * debugging and tests.
 */
extern void objc_deinit(void);

/**
 * @brief Sets the handler for uncaught exceptions.
 *
 * @param handler The new handler for uncaught exceptions
 * @return The old handler for uncaught exceptions
 */
extern _Nullable objc_uncaught_exception_handler
    objc_setUncaughtExceptionHandler(
    objc_uncaught_exception_handler _Nullable handler);

/**
 * @brief Sets the forwarding handler for unimplemented methods.
 *
 * @param forward The forwarding handler for regular methods
 * @param stretForward The forwarding handler for methods using the struct
 *		       return ABI
 */
extern void objc_setForwardHandler(IMP _Nullable forward,
    IMP _Nullable stretForward);

/**
 * @brief Sets the handler for mutations during enumeration.
 *
 * @param handler The handler for mutations during enumeration
 */
extern void objc_setEnumerationMutationHandler(
    objc_enumeration_mutation_handler _Nullable handler);

/**
 * @brief Constructs an instance of the specified class in the specified array
 *	  of bytes.
 *
 * @param class_ The class of which to construct an instance
 * @param bytes An array of bytes of at least the length of the instance size.

Modified src/runtime/amiga-funcarray.inc from [674e168c3f] to [eca72c7d0a].

75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
(CONST_APTR)glue_protocol_getName,
(CONST_APTR)glue_protocol_isEqual,
(CONST_APTR)glue_protocol_conformsToProtocol,
(CONST_APTR)glue_objc_setUncaughtExceptionHandler,
(CONST_APTR)glue_objc_setForwardHandler,
(CONST_APTR)glue_objc_setEnumerationMutationHandler,
(CONST_APTR)glue_objc_constructInstance,
(CONST_APTR)glue_objc_exit,
(CONST_APTR)glue_class_copyIvarList,
(CONST_APTR)glue_ivar_getName,
(CONST_APTR)glue_ivar_getTypeEncoding,
(CONST_APTR)glue_ivar_getOffset,
(CONST_APTR)glue_class_copyMethodList,
(CONST_APTR)glue_method_getName,
(CONST_APTR)glue_method_getTypeEncoding,







|







75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
(CONST_APTR)glue_protocol_getName,
(CONST_APTR)glue_protocol_isEqual,
(CONST_APTR)glue_protocol_conformsToProtocol,
(CONST_APTR)glue_objc_setUncaughtExceptionHandler,
(CONST_APTR)glue_objc_setForwardHandler,
(CONST_APTR)glue_objc_setEnumerationMutationHandler,
(CONST_APTR)glue_objc_constructInstance,
(CONST_APTR)glue_objc_deinit,
(CONST_APTR)glue_class_copyIvarList,
(CONST_APTR)glue_ivar_getName,
(CONST_APTR)glue_ivar_getTypeEncoding,
(CONST_APTR)glue_ivar_getOffset,
(CONST_APTR)glue_class_copyMethodList,
(CONST_APTR)glue_method_getName,
(CONST_APTR)glue_method_getTypeEncoding,

Modified src/runtime/amiga-glue.h from [51945d63f3] to [2ca426ebf9].

84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
extern IMP _Nullable glue_class_replaceMethod PPC_PARAMS(Class _Nonnull class, SEL _Nonnull selector, IMP _Nonnull implementation, const char *_Nullable typeEncoding);
extern Class _Nullable glue_object_getClass PPC_PARAMS(id _Nullable object);
extern Class _Nullable glue_object_setClass PPC_PARAMS(id _Nullable object, Class _Nonnull class);
extern const char *_Nullable glue_object_getClassName PPC_PARAMS(id _Nullable object);
extern const char *_Nonnull glue_protocol_getName PPC_PARAMS(Protocol *_Nonnull protocol);
extern bool glue_protocol_isEqual PPC_PARAMS(Protocol *_Nonnull protocol1, Protocol *_Nonnull protocol2);
extern bool glue_protocol_conformsToProtocol PPC_PARAMS(Protocol *_Nonnull protocol1, Protocol *_Nonnull protocol2);
extern _Nullable objc_uncaught_exception_handler_t glue_objc_setUncaughtExceptionHandler PPC_PARAMS(objc_uncaught_exception_handler_t _Nullable handler);
extern void glue_objc_setForwardHandler PPC_PARAMS(IMP _Nullable forward, IMP _Nullable stretForward);
extern void glue_objc_setEnumerationMutationHandler PPC_PARAMS(objc_enumeration_mutation_handler_t _Nullable hadler);
extern id _Nullable glue_objc_constructInstance PPC_PARAMS(Class _Nullable class, void *_Nullable bytes);
extern void glue_objc_exit(void);
extern Ivar _Nullable *_Nullable glue_class_copyIvarList PPC_PARAMS(Class _Nullable class, unsigned int *_Nullable outCount);
extern const char *_Nonnull glue_ivar_getName PPC_PARAMS(Ivar _Nonnull ivar);
extern const char *_Nonnull glue_ivar_getTypeEncoding PPC_PARAMS(Ivar _Nonnull ivar);
extern ptrdiff_t glue_ivar_getOffset PPC_PARAMS(Ivar _Nonnull ivar);
extern Method _Nullable *_Nullable glue_class_copyMethodList PPC_PARAMS(Class _Nullable class, unsigned int *_Nullable outCount);
extern SEL _Nonnull glue_method_getName PPC_PARAMS(Method _Nonnull method);
extern const char *_Nullable glue_method_getTypeEncoding PPC_PARAMS(Method _Nonnull method);







|

|

|







84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
extern IMP _Nullable glue_class_replaceMethod PPC_PARAMS(Class _Nonnull class, SEL _Nonnull selector, IMP _Nonnull implementation, const char *_Nullable typeEncoding);
extern Class _Nullable glue_object_getClass PPC_PARAMS(id _Nullable object);
extern Class _Nullable glue_object_setClass PPC_PARAMS(id _Nullable object, Class _Nonnull class);
extern const char *_Nullable glue_object_getClassName PPC_PARAMS(id _Nullable object);
extern const char *_Nonnull glue_protocol_getName PPC_PARAMS(Protocol *_Nonnull protocol);
extern bool glue_protocol_isEqual PPC_PARAMS(Protocol *_Nonnull protocol1, Protocol *_Nonnull protocol2);
extern bool glue_protocol_conformsToProtocol PPC_PARAMS(Protocol *_Nonnull protocol1, Protocol *_Nonnull protocol2);
extern _Nullable objc_uncaught_exception_handler glue_objc_setUncaughtExceptionHandler PPC_PARAMS(objc_uncaught_exception_handler _Nullable handler);
extern void glue_objc_setForwardHandler PPC_PARAMS(IMP _Nullable forward, IMP _Nullable stretForward);
extern void glue_objc_setEnumerationMutationHandler PPC_PARAMS(objc_enumeration_mutation_handler _Nullable hadler);
extern id _Nullable glue_objc_constructInstance PPC_PARAMS(Class _Nullable class, void *_Nullable bytes);
extern void glue_objc_deinit(void);
extern Ivar _Nullable *_Nullable glue_class_copyIvarList PPC_PARAMS(Class _Nullable class, unsigned int *_Nullable outCount);
extern const char *_Nonnull glue_ivar_getName PPC_PARAMS(Ivar _Nonnull ivar);
extern const char *_Nonnull glue_ivar_getTypeEncoding PPC_PARAMS(Ivar _Nonnull ivar);
extern ptrdiff_t glue_ivar_getOffset PPC_PARAMS(Ivar _Nonnull ivar);
extern Method _Nullable *_Nullable glue_class_copyMethodList PPC_PARAMS(Class _Nullable class, unsigned int *_Nullable outCount);
extern SEL _Nonnull glue_method_getName PPC_PARAMS(Method _Nonnull method);
extern const char *_Nullable glue_method_getTypeEncoding PPC_PARAMS(Method _Nonnull method);

Modified src/runtime/amiga-glue.m from [fef86ecf8c] to [7d3bd6cbde].

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
{
	M68K_ARG(Protocol *_Nonnull, protocol1, a0)
	M68K_ARG(Protocol *_Nonnull, protocol2, a1)

	return protocol_conformsToProtocol(protocol1, protocol2);
}

_Nullable objc_uncaught_exception_handler_t __saveds
glue_objc_setUncaughtExceptionHandler PPC_PARAMS(objc_uncaught_exception_handler_t _Nullable handler)
{
	M68K_ARG(objc_uncaught_exception_handler_t _Nullable, handler, a0)

	return objc_setUncaughtExceptionHandler(handler);
}

void __saveds
glue_objc_setForwardHandler PPC_PARAMS(IMP _Nullable forward, IMP _Nullable stretForward)
{
	M68K_ARG(IMP _Nullable, forward, a0)
	M68K_ARG(IMP _Nullable, stretForward, a1)

	objc_setForwardHandler(forward, stretForward);
}

void __saveds
glue_objc_setEnumerationMutationHandler PPC_PARAMS(objc_enumeration_mutation_handler_t _Nullable hadler)
{
	M68K_ARG(objc_enumeration_mutation_handler_t _Nullable, hadler, a0)

	objc_setEnumerationMutationHandler(hadler);
}

id _Nullable __saveds
glue_objc_constructInstance PPC_PARAMS(Class _Nullable class, void *_Nullable bytes)
{
	M68K_ARG(Class _Nullable, class, a0)
	M68K_ARG(void *_Nullable, bytes, a1)

	return objc_constructInstance(class, bytes);
}

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

Ivar _Nullable *_Nullable __saveds
glue_class_copyIvarList PPC_PARAMS(Class _Nullable class, unsigned int *_Nullable outCount)
{
	M68K_ARG(Class _Nullable, class, a0)
	M68K_ARG(unsigned int *_Nullable, outCount, a1)







|
|

|














|

|














|

|







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
{
	M68K_ARG(Protocol *_Nonnull, protocol1, a0)
	M68K_ARG(Protocol *_Nonnull, protocol2, a1)

	return protocol_conformsToProtocol(protocol1, protocol2);
}

_Nullable objc_uncaught_exception_handler __saveds
glue_objc_setUncaughtExceptionHandler PPC_PARAMS(objc_uncaught_exception_handler _Nullable handler)
{
	M68K_ARG(objc_uncaught_exception_handler _Nullable, handler, a0)

	return objc_setUncaughtExceptionHandler(handler);
}

void __saveds
glue_objc_setForwardHandler PPC_PARAMS(IMP _Nullable forward, IMP _Nullable stretForward)
{
	M68K_ARG(IMP _Nullable, forward, a0)
	M68K_ARG(IMP _Nullable, stretForward, a1)

	objc_setForwardHandler(forward, stretForward);
}

void __saveds
glue_objc_setEnumerationMutationHandler PPC_PARAMS(objc_enumeration_mutation_handler _Nullable hadler)
{
	M68K_ARG(objc_enumeration_mutation_handler _Nullable, hadler, a0)

	objc_setEnumerationMutationHandler(hadler);
}

id _Nullable __saveds
glue_objc_constructInstance PPC_PARAMS(Class _Nullable class, void *_Nullable bytes)
{
	M68K_ARG(Class _Nullable, class, a0)
	M68K_ARG(void *_Nullable, bytes, a1)

	return objc_constructInstance(class, bytes);
}

void __saveds
glue_objc_deinit(void)
{
	objc_deinit();
}

Ivar _Nullable *_Nullable __saveds
glue_class_copyIvarList PPC_PARAMS(Class _Nullable class, unsigned int *_Nullable outCount)
{
	M68K_ARG(Class _Nullable, class, a0)
	M68K_ARG(unsigned int *_Nullable, outCount, a1)

Modified src/runtime/arc.m from [8ccdb1ee10] to [1147559114].

18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#import "ObjFWRT.h"
#import "private.h"

#ifdef OF_HAVE_THREADS
# import "OFPlainMutex.h"
#endif

struct weakref {
	id **locations;
	size_t count;
};

static struct objc_hashtable *hashtable;
#ifdef OF_HAVE_THREADS
static OFSpinlock spinlock;







|







18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#import "ObjFWRT.h"
#import "private.h"

#ifdef OF_HAVE_THREADS
# import "OFPlainMutex.h"
#endif

struct WeakRef {
	id **locations;
	size_t count;
};

static struct objc_hashtable *hashtable;
#ifdef OF_HAVE_THREADS
static OFSpinlock spinlock;
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127

	return value;
}

id
objc_storeWeak(id *object, id value)
{
	struct weakref *old;

#ifdef OF_HAVE_THREADS
	if (OFSpinlockLock(&spinlock) != 0)
		OBJC_ERROR("Failed to lock spinlock!");
#endif

	if (*object != nil &&







|







113
114
115
116
117
118
119
120
121
122
123
124
125
126
127

	return value;
}

id
objc_storeWeak(id *object, id value)
{
	struct WeakRef *old;

#ifdef OF_HAVE_THREADS
	if (OFSpinlockLock(&spinlock) != 0)
		OBJC_ERROR("Failed to lock spinlock!");
#endif

	if (*object != nil &&
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
				break;
			}
		}
	}

	if (value != nil && class_respondsToSelector(object_getClass(value),
	    @selector(allowsWeakReference)) && [value allowsWeakReference]) {
		struct weakref *ref = objc_hashtable_get(hashtable, value);

		if (ref == NULL) {
			if ((ref = calloc(1, sizeof(*ref))) == NULL)
				OBJC_ERROR("Not enough memory to allocate weak "
				    "reference!");

			objc_hashtable_set(hashtable, value, ref);







|







151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
				break;
			}
		}
	}

	if (value != nil && class_respondsToSelector(object_getClass(value),
	    @selector(allowsWeakReference)) && [value allowsWeakReference]) {
		struct WeakRef *ref = objc_hashtable_get(hashtable, value);

		if (ref == NULL) {
			if ((ref = calloc(1, sizeof(*ref))) == NULL)
				OBJC_ERROR("Not enough memory to allocate weak "
				    "reference!");

			objc_hashtable_set(hashtable, value, ref);
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
	return value;
}

id
objc_loadWeakRetained(id *object)
{
	id value = nil;
	struct weakref *ref;

#ifdef OF_HAVE_THREADS
	if (OFSpinlockLock(&spinlock) != 0)
		OBJC_ERROR("Failed to lock spinlock!");
#endif

	if (*object != nil &&







|







184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
	return value;
}

id
objc_loadWeakRetained(id *object)
{
	id value = nil;
	struct WeakRef *ref;

#ifdef OF_HAVE_THREADS
	if (OFSpinlockLock(&spinlock) != 0)
		OBJC_ERROR("Failed to lock spinlock!");
#endif

	if (*object != nil &&
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
{
	objc_release(objc_initWeak(dest, objc_loadWeakRetained(src)));
}

void
objc_moveWeak(id *dest, id *src)
{
	struct weakref *ref;

#ifdef OF_HAVE_THREADS
	if (OFSpinlockLock(&spinlock) != 0)
		OBJC_ERROR("Failed to lock spinlock!");
#endif

	if (*src != nil &&







|







235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
{
	objc_release(objc_initWeak(dest, objc_loadWeakRetained(src)));
}

void
objc_moveWeak(id *dest, id *src)
{
	struct WeakRef *ref;

#ifdef OF_HAVE_THREADS
	if (OFSpinlockLock(&spinlock) != 0)
		OBJC_ERROR("Failed to lock spinlock!");
#endif

	if (*src != nil &&
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
#ifdef OF_HAVE_THREADS
	if (OFSpinlockUnlock(&spinlock) != 0)
		OBJC_ERROR("Failed to unlock spinlock!");
#endif
}

void
objc_zero_weak_references(id value)
{
	struct weakref *ref;

#ifdef OF_HAVE_THREADS
	if (OFSpinlockLock(&spinlock) != 0)
		OBJC_ERROR("Failed to lock spinlock!");
#endif

	if ((ref = objc_hashtable_get(hashtable, value)) != NULL) {







|

|







262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
#ifdef OF_HAVE_THREADS
	if (OFSpinlockUnlock(&spinlock) != 0)
		OBJC_ERROR("Failed to unlock spinlock!");
#endif
}

void
objc_zeroWeakReferences(id value)
{
	struct WeakRef *ref;

#ifdef OF_HAVE_THREADS
	if (OFSpinlockLock(&spinlock) != 0)
		OBJC_ERROR("Failed to lock spinlock!");
#endif

	if ((ref = objc_hashtable_get(hashtable, value)) != NULL) {

Modified src/runtime/category.m from [e672c2edf4] to [5b97638d56].

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
registerSelectors(struct objc_category *category)
{
	struct objc_method_list *iter;
	unsigned int i;

	for (iter = category->instanceMethods; iter != NULL; iter = iter->next)
		for (i = 0; i < iter->count; i++)
			objc_register_selector(&iter->methods[i].selector);

	for (iter = category->classMethods; iter != NULL; iter = iter->next)
		for (i = 0; i < iter->count; i++)
			objc_register_selector(&iter->methods[i].selector);
}

static void
registerCategory(struct objc_category *category)
{
	struct objc_category **categories;
	Class class = objc_classname_to_class(category->className, false);

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

	categories = (struct objc_category **)objc_hashtable_get(
	    categoriesMap, category->className);

	if (categories != NULL) {
		struct objc_category **newCategories;
		size_t i;







|



|






|



|







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
registerSelectors(struct objc_category *category)
{
	struct objc_method_list *iter;
	unsigned int i;

	for (iter = category->instanceMethods; iter != NULL; iter = iter->next)
		for (i = 0; i < iter->count; i++)
			objc_registerSelector(&iter->methods[i].selector);

	for (iter = category->classMethods; iter != NULL; iter = iter->next)
		for (i = 0; i < iter->count; i++)
			objc_registerSelector(&iter->methods[i].selector);
}

static void
registerCategory(struct objc_category *category)
{
	struct objc_category **categories;
	Class class = objc_classnameToClass(category->className, false);

	if (categoriesMap == NULL)
		categoriesMap = objc_hashtable_new(
		    objc_string_hash, objc_string_equal, 2);

	categories = (struct objc_category **)objc_hashtable_get(
	    categoriesMap, category->className);

	if (categories != NULL) {
		struct objc_category **newCategories;
		size_t i;
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

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

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

		return;
	}

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

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

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

void
objc_register_all_categories(struct objc_symtab *symtab)
{
	struct objc_category **categories =
	    (struct objc_category **)symtab->defs + symtab->classDefsCount;

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

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

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

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

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

	objc_hashtable_free(categoriesMap);
	categoriesMap = NULL;
}







|
|














|
|




|











|









|











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

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

		if (class != Nil && class->info & OBJC_CLASS_INFO_SETUP) {
			objc_updateDTable(class);
			objc_updateDTable(class->isa);
		}

		return;
	}

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

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

	if (class != Nil && class->info & OBJC_CLASS_INFO_SETUP) {
		objc_updateDTable(class);
		objc_updateDTable(class->isa);
	}
}

void
objc_registerAllCategories(struct objc_symtab *symtab)
{
	struct objc_category **categories =
	    (struct objc_category **)symtab->defs + symtab->classDefsCount;

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

struct objc_category **
objc_categoriesForClass(Class class)
{
	if (categoriesMap == NULL)
		return NULL;

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

void
objc_unregisterAllCategories(void)
{
	if (categoriesMap == NULL)
		return;

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

	objc_hashtable_free(categoriesMap);
	categoriesMap = NULL;
}

Modified src/runtime/class.m from [93b6de8609] to [a72b4d25e1].

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
static struct objc_sparsearray *fastPath = NULL;

static void
registerClass(Class class)
{
	if (classes == NULL)
		classes = objc_hashtable_new(
		    objc_hash_string, objc_equal_string, 2);

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

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

	class->DTable = emptyDTable;
	class->isa->DTable = emptyDTable;

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

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

	if (classes == NULL) {
		objc_global_mutex_unlock();

		return NO;
	}

	objc_hashtable_set(classes, name, (Class)((uintptr_t)class | 1));

	objc_global_mutex_unlock();

	return YES;
}

static void
registerSelectors(Class class)
{
	struct objc_method_list *iter;
	unsigned int i;

	for (iter = class->methodList; iter != NULL; iter = iter->next)
		for (i = 0; i < iter->count; i++)
			objc_register_selector(&iter->methods[i].selector);
}

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

	if (classes == NULL)
		return Nil;

	/*







|






|
|








|


|






|












|



|







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
static struct objc_sparsearray *fastPath = NULL;

static void
registerClass(Class class)
{
	if (classes == NULL)
		classes = objc_hashtable_new(
		    objc_string_hash, objc_string_equal, 2);

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

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

	class->dTable = emptyDTable;
	class->isa->dTable = emptyDTable;

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

bool
class_registerAlias_np(Class class, const char *name)
{
	objc_globalMutex_lock();

	if (classes == NULL) {
		objc_globalMutex_unlock();

		return NO;
	}

	objc_hashtable_set(classes, name, (Class)((uintptr_t)class | 1));

	objc_globalMutex_unlock();

	return YES;
}

static void
registerSelectors(Class class)
{
	struct objc_method_list *iter;
	unsigned int i;

	for (iter = class->methodList; iter != NULL; iter = iter->next)
		for (i = 0; i < iter->count; i++)
			objc_registerSelector(&iter->methods[i].selector);
}

Class
objc_classnameToClass(const char *name, bool cache)
{
	Class class;

	if (classes == NULL)
		return Nil;

	/*
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
	if (cache && fastPath != NULL) {
		class = objc_sparsearray_get(fastPath, (uintptr_t)name);

		if (class != Nil)
			return class;
	}

	objc_global_mutex_lock();

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

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

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

	objc_global_mutex_unlock();

	return class;
}

static void
callSelector(Class class, SEL selector)
{







|









|







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
	if (cache && fastPath != NULL) {
		class = objc_sparsearray_get(fastPath, (uintptr_t)name);

		if (class != Nil)
			return class;
	}

	objc_globalMutex_lock();

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

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

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

	objc_globalMutex_unlock();

	return class;
}

static void
callSelector(Class class, SEL selector)
{
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

	callSelector(class, loadSel);

	class->info |= OBJC_CLASS_INFO_LOADED;
}

void
objc_update_dtable(Class class)
{
	struct objc_category **categories;

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

	if (class->DTable == emptyDTable)
		class->DTable = objc_dtable_new();

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

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

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

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

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

static void
addSubclass(Class class)
{
	size_t i;








|






|
|


|




|



|










|









|







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

	callSelector(class, loadSel);

	class->info |= OBJC_CLASS_INFO_LOADED;
}

void
objc_updateDTable(Class class)
{
	struct objc_category **categories;

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

	if (class->dTable == emptyDTable)
		class->dTable = objc_dtable_new();

	if (class->superclass != Nil)
		objc_dtable_copy(class->dTable, class->superclass->dTable);

	for (struct objc_method_list *methodList = class->methodList;
	    methodList != NULL; methodList = methodList->next)
		for (unsigned int i = 0; i < methodList->count; i++)
			objc_dtable_set(class->dTable,
			    (uint32_t)methodList->methods[i].selector.UID,
			    methodList->methods[i].implementation);

	if ((categories = objc_categoriesForClass(class)) != NULL) {
		for (unsigned int i = 0; categories[i] != NULL; i++) {
			struct objc_method_list *methodList =
			    (class->info & OBJC_CLASS_INFO_CLASS
			    ? categories[i]->instanceMethods
			    : categories[i]->classMethods);

			for (; methodList != NULL;
			    methodList = methodList->next)
				for (unsigned int j = 0;
				    j < methodList->count; j++)
					objc_dtable_set(class->dTable,
					    (uint32_t)methodList->methods[j]
					    .selector.UID,
					    methodList->methods[j]
					    .implementation);
		}
	}

	if (class->subclassList != NULL)
		for (Class *iter = class->subclassList; *iter != NULL; iter++)
			objc_updateDTable(*iter);
}

static void
addSubclass(Class class)
{
	size_t i;

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
		}
	} else
		for (unsigned int i = 0; i < class->ivars->count; i++)
			*class->ivarOffsets[i] = class->ivars->ivars[i].offset;
}

static void
setupClass(Class class)
{
	const char *superclassName;

	if (class->info & OBJC_CLASS_INFO_SETUP)
		return;

	superclassName = (const char *)class->superclass;
	if (superclassName != NULL) {
		Class super = objc_classname_to_class(superclassName, false);
		Class rootClass;

		if (super == Nil)
			return;

		setupClass(super);

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

		/*
		 * GCC sets class->isa->isa to the name of the root class,
		 * while Clang just sets it to Nil. Therefore always calculate







|








|





|







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
		}
	} else
		for (unsigned int i = 0; i < class->ivars->count; i++)
			*class->ivarOffsets[i] = class->ivars->ivars[i].offset;
}

static void
setUpClass(Class class)
{
	const char *superclassName;

	if (class->info & OBJC_CLASS_INFO_SETUP)
		return;

	superclassName = (const char *)class->superclass;
	if (superclassName != NULL) {
		Class super = objc_classnameToClass(superclassName, false);
		Class rootClass;

		if (super == Nil)
			return;

		setUpClass(super);

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

		/*
		 * GCC sets class->isa->isa to the name of the root class,
		 * while Clang just sets it to Nil. Therefore always calculate
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
	 */
	if (class->info & OBJC_CLASS_INFO_INITIALIZED)
		return;

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

	objc_update_dtable(class);
	objc_update_dtable(class->isa);

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







|
|







347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
	 */
	if (class->info & OBJC_CLASS_INFO_INITIALIZED)
		return;

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

	objc_updateDTable(class);
	objc_updateDTable(class->isa);

	/*
	 * Set it first to prevent calling it recursively due to message sends
	 * in the initialize method
	 */
	class->info |= OBJC_CLASS_INFO_INITIALIZED;
	class->isa->info |= OBJC_CLASS_INFO_INITIALIZED;
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
		    objc_msg_lookup(class, initializeSel);

		initialize(class, initializeSel);
	}
}

void
objc_initialize_class(Class class)
{
	if (class->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 (class->info & OBJC_CLASS_INFO_INITIALIZED) {
		objc_global_mutex_unlock();
		return;
	}

	setupClass(class);

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

	initializeClass(class);

	objc_global_mutex_unlock();
}

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

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

			loadQueueCount--;

			if (loadQueueCount == 0) {







|




|







|



|


|





|






|







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
		    objc_msg_lookup(class, initializeSel);

		initialize(class, initializeSel);
	}
}

void
objc_initializeClass(Class class)
{
	if (class->info & OBJC_CLASS_INFO_INITIALIZED)
		return;

	objc_globalMutex_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 (class->info & OBJC_CLASS_INFO_INITIALIZED) {
		objc_globalMutex_unlock();
		return;
	}

	setUpClass(class);

	if (!(class->info & OBJC_CLASS_INFO_SETUP)) {
		objc_globalMutex_unlock();
		return;
	}

	initializeClass(class);

	objc_globalMutex_unlock();
}

static void
processLoadQueue()
{
	for (size_t i = 0; i < loadQueueCount; i++) {
		setUpClass(loadQueue[i]);

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

			loadQueueCount--;

			if (loadQueueCount == 0) {
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
			if (loadQueue == NULL)
				OBJC_ERROR("Not enough memory for load queue!");
		}
	}
}

void
objc_register_all_classes(struct objc_symtab *symtab)
{
	for (uint16_t i = 0; i < symtab->classDefsCount; i++) {
		Class class = (Class)symtab->defs[i];

		registerClass(class);
		registerSelectors(class);
		registerSelectors(class->isa);
	}

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

		if (hasLoad(class)) {
			setupClass(class);

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








|













|







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
			if (loadQueue == NULL)
				OBJC_ERROR("Not enough memory for load queue!");
		}
	}
}

void
objc_registerAllClasses(struct objc_symtab *symtab)
{
	for (uint16_t i = 0; i < symtab->classDefsCount; i++) {
		Class class = (Class)symtab->defs[i];

		registerClass(class);
		registerSelectors(class);
		registerSelectors(class->isa);
	}

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

		if (hasLoad(class)) {
			setUpClass(class);

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

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

	return class;
}

void
objc_registerClassPair(Class class)
{
	objc_global_mutex_lock();

	registerClass(class);

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

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

	if (hasLoad(class))
		callLoad(class);
	else
		class->info |= OBJC_CLASS_INFO_LOADED;

	processLoadQueue();

	objc_global_mutex_unlock();
}

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

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

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

	objc_global_mutex_lock();

	setupClass(class);

	objc_global_mutex_unlock();

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

	return class;
}








|


















|







|





|

|

|







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

	return class;
}

void
objc_registerClassPair(Class class)
{
	objc_globalMutex_lock();

	registerClass(class);

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

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

	if (hasLoad(class))
		callLoad(class);
	else
		class->info |= OBJC_CLASS_INFO_LOADED;

	processLoadQueue();

	objc_globalMutex_unlock();
}

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

	if ((class = objc_classnameToClass(name, true)) == NULL)
		return Nil;

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

	objc_globalMutex_lock();

	setUpClass(class);

	objc_globalMutex_unlock();

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

	return class;
}

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
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
	return objc_getRequiredClass(name);
}

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

	if (buffer == NULL)
		return classesCount;

	if (classesCount < count)
		count = classesCount;

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

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

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

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

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

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

		buffer[j++] = class;
	}

	objc_global_mutex_unlock();

	return j;
}

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

	objc_global_mutex_lock();

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

	count = objc_getClassList(ret, classesCount);
	OFEnsure(count == classesCount);

	ret[count] = Nil;

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

	objc_global_mutex_unlock();

	return ret;
}

bool
class_isMetaClass(Class class)
{







|












|

















|










|












|







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
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
	return objc_getRequiredClass(name);
}

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

	if (buffer == NULL)
		return classesCount;

	if (classesCount < count)
		count = classesCount;

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

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

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

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

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

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

		buffer[j++] = class;
	}

	objc_globalMutex_unlock();

	return j;
}

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

	objc_globalMutex_lock();

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

	count = objc_getClassList(ret, classesCount);
	OFEnsure(count == classesCount);

	ret[count] = Nil;

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

	objc_globalMutex_unlock();

	return ret;
}

bool
class_isMetaClass(Class class)
{
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
}

static struct objc_method *
getMethod(Class class, SEL selector)
{
	struct objc_category **categories;

	if ((categories = objc_categories_for_class(class)) != NULL) {
		for (; *categories != NULL; categories++) {
			struct objc_method_list *methodList =
			    (class->info & OBJC_CLASS_INFO_METACLASS
			    ? (*categories)->classMethods
			    : (*categories)->instanceMethods);

			for (; methodList != NULL;







|







722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
}

static struct objc_method *
getMethod(Class class, SEL selector)
{
	struct objc_category **categories;

	if ((categories = objc_categoriesForClass(class)) != NULL) {
		for (; *categories != NULL; categories++) {
			struct objc_method_list *methodList =
			    (class->info & OBJC_CLASS_INFO_METACLASS
			    ? (*categories)->classMethods
			    : (*categories)->instanceMethods);

			for (; methodList != NULL;
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

static void
addMethod(Class class, SEL selector, IMP implementation,
    const char *typeEncoding)
{
	struct objc_method_list *methodList;

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

	methodList->next = class->methodList;
	methodList->count = 1;
	methodList->methods[0].selector.UID = selector->UID;
	methodList->methods[0].selector.typeEncoding = typeEncoding;
	methodList->methods[0].implementation = implementation;

	class->methodList = methodList;

	objc_update_dtable(class);
}

Method
class_getInstanceMethod(Class class, SEL selector)
{
	Method method;
	Class superclass;

	if (class == Nil)
		return NULL;

	objc_global_mutex_lock();

	if ((method = getMethod(class, selector)) != NULL) {
		objc_global_mutex_unlock();
		return method;
	}

	superclass = class->superclass;

	objc_global_mutex_unlock();

	if (superclass != Nil)
		return class_getInstanceMethod(superclass, selector);

	return NULL;
}

bool
class_addMethod(Class class, SEL selector, IMP implementation,
    const char *typeEncoding)
{
	bool ret;

	objc_global_mutex_lock();

	if (getMethod(class, selector) == NULL) {
		addMethod(class, selector, implementation, typeEncoding);
		ret = true;
	} else
		ret = false;

	objc_global_mutex_unlock();

	return ret;
}

IMP
class_replaceMethod(Class class, SEL selector, IMP implementation,
    const char *typeEncoding)
{
	struct objc_method *method;
	IMP oldImplementation;

	objc_global_mutex_lock();

	if ((method = getMethod(class, selector)) != NULL) {
		oldImplementation = method->implementation;
		method->implementation = implementation;
		objc_update_dtable(class);
	} else {
		oldImplementation = NULL;
		addMethod(class, selector, implementation, typeEncoding);
	}

	objc_global_mutex_unlock();

	return oldImplementation;
}

Class
object_getClass(id object_)
{







|











|











|


|





|













|







|











|




|





|







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

static void
addMethod(Class class, SEL selector, IMP implementation,
    const char *typeEncoding)
{
	struct objc_method_list *methodList;

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

	methodList->next = class->methodList;
	methodList->count = 1;
	methodList->methods[0].selector.UID = selector->UID;
	methodList->methods[0].selector.typeEncoding = typeEncoding;
	methodList->methods[0].implementation = implementation;

	class->methodList = methodList;

	objc_updateDTable(class);
}

Method
class_getInstanceMethod(Class class, SEL selector)
{
	Method method;
	Class superclass;

	if (class == Nil)
		return NULL;

	objc_globalMutex_lock();

	if ((method = getMethod(class, selector)) != NULL) {
		objc_globalMutex_unlock();
		return method;
	}

	superclass = class->superclass;

	objc_globalMutex_unlock();

	if (superclass != Nil)
		return class_getInstanceMethod(superclass, selector);

	return NULL;
}

bool
class_addMethod(Class class, SEL selector, IMP implementation,
    const char *typeEncoding)
{
	bool ret;

	objc_globalMutex_lock();

	if (getMethod(class, selector) == NULL) {
		addMethod(class, selector, implementation, typeEncoding);
		ret = true;
	} else
		ret = false;

	objc_globalMutex_unlock();

	return ret;
}

IMP
class_replaceMethod(Class class, SEL selector, IMP implementation,
    const char *typeEncoding)
{
	struct objc_method *method;
	IMP oldImplementation;

	objc_globalMutex_lock();

	if ((method = getMethod(class, selector)) != NULL) {
		oldImplementation = method->implementation;
		method->implementation = implementation;
		objc_updateDTable(class);
	} else {
		oldImplementation = NULL;
		addMethod(class, selector, implementation, typeEncoding);
	}

	objc_globalMutex_unlock();

	return oldImplementation;
}

Class
object_getClass(id object_)
{
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
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
	}

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

	if (class->DTable != NULL && class->DTable != emptyDTable)
		objc_dtable_free(class->DTable);

	class->DTable = NULL;

	if ((class->info & OBJC_CLASS_INFO_SETUP) && class->superclass != Nil)
		class->superclass = (Class)class->superclass->name;

	class->info &= ~OBJC_CLASS_INFO_SETUP;
}

void
objc_unregister_class(Class class)
{
	static SEL unloadSel = NULL;

	if (unloadSel == NULL)
		unloadSel = sel_registerName("unload");

	while (class->subclassList != NULL && class->subclassList[0] != Nil)
		objc_unregister_class(class->subclassList[0]);

	if (class->info & OBJC_CLASS_INFO_LOADED)
		callSelector(class, unloadSel);

	objc_hashtable_delete(classes, class->name);

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

	unregisterClass(class);
	unregisterClass(class->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 *class = (Class)classes->data[i]->object;

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

			objc_unregister_class(class);

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







|
|

|








|







|














|






|





|







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
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
	}

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

	if (class->dTable != NULL && class->dTable != emptyDTable)
		objc_dtable_free(class->dTable);

	class->dTable = NULL;

	if ((class->info & OBJC_CLASS_INFO_SETUP) && class->superclass != Nil)
		class->superclass = (Class)class->superclass->name;

	class->info &= ~OBJC_CLASS_INFO_SETUP;
}

void
objc_unregisterClass(Class class)
{
	static SEL unloadSel = NULL;

	if (unloadSel == NULL)
		unloadSel = sel_registerName("unload");

	while (class->subclassList != NULL && class->subclassList[0] != Nil)
		objc_unregisterClass(class->subclassList[0]);

	if (class->info & OBJC_CLASS_INFO_LOADED)
		callSelector(class, unloadSel);

	objc_hashtable_delete(classes, class->name);

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

	unregisterClass(class);
	unregisterClass(class->isa);
}

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

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

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

			objc_unregisterClass(class);

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

Modified src/runtime/dtable.m from [d61b5652b8] to [fe23892d25].

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
static struct objc_dtable_level3 *emptyLevel3 = NULL;
#endif

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

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

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

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

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

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

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

	return DTable;
}

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







|



|
















|









|
|


|

|







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
static struct objc_dtable_level3 *emptyLevel3 = NULL;
#endif

static void
init(void)
{
	if ((emptyLevel2 = malloc(sizeof(*emptyLevel2))) == NULL)
		OBJC_ERROR("Not enough memory to allocate dispatch table!");

#ifdef OF_SELUID24
	if ((emptyLevel3 = malloc(sizeof(*emptyLevel3))) == NULL)
		OBJC_ERROR("Not enough memory to allocate dispatch table!");
#endif

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

struct objc_dtable *
objc_dtable_new(void)
{
	struct objc_dtable *dTable;

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

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

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

	return dTable;
}

void
objc_dtable_copy(struct objc_dtable *dest, struct objc_dtable *src)
{
	for (uint_fast16_t i = 0; i < 256; i++) {
		if (src->buckets[i] == emptyLevel2)
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
			objc_dtable_set(dest, idx, implementation);
		}
#endif
	}
}

void
objc_dtable_set(struct objc_dtable *DTable, uint32_t idx, IMP implementation)
{
#ifdef OF_SELUID24
	uint8_t i = idx >> 16;
	uint8_t j = idx >> 8;
	uint8_t k = idx;
#else
	uint8_t i = idx >> 8;
	uint8_t j = idx;
#endif

	if (DTable->buckets[i] == emptyLevel2) {
		struct objc_dtable_level2 *level2 = malloc(sizeof(*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] = emptyLevel3;
#else
			level2->buckets[l] = (IMP)0;
#endif

		DTable->buckets[i] = level2;
	}

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

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


		for (uint_fast16_t l = 0; l < 256; l++)
			level3->buckets[l] = (IMP)0;

		DTable->buckets[i]->buckets[j] = level3;
	}

	DTable->buckets[i]->buckets[j]->buckets[k] = implementation;
#else
	DTable->buckets[i]->buckets[j] = implementation;
#endif
}

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

#ifdef OF_SELUID24
		for (uint_fast16_t j = 0; j < 256; j++)
			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 (emptyLevel2 != NULL)
		free(emptyLevel2);







|










|



|
>








|



|



|
>




|


|

|




|


|




|
|


|


|







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
			objc_dtable_set(dest, idx, implementation);
		}
#endif
	}
}

void
objc_dtable_set(struct objc_dtable *dTable, uint32_t idx, IMP implementation)
{
#ifdef OF_SELUID24
	uint8_t i = idx >> 16;
	uint8_t j = idx >> 8;
	uint8_t k = idx;
#else
	uint8_t i = idx >> 8;
	uint8_t j = idx;
#endif

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

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

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

		dTable->buckets[i] = level2;
	}

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

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

		for (uint_fast16_t l = 0; l < 256; l++)
			level3->buckets[l] = (IMP)0;

		dTable->buckets[i]->buckets[j] = level3;
	}

	dTable->buckets[i]->buckets[j]->buckets[k] = implementation;
#else
	dTable->buckets[i]->buckets[j] = implementation;
#endif
}

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

#ifdef OF_SELUID24
		for (uint_fast16_t j = 0; j < 256; j++)
			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 (emptyLevel2 != NULL)
		free(emptyLevel2);

Modified src/runtime/exception.m from [814fd82d64] to [cb2a5e9390].

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
# define CALL_PERSONALITY(func) func(state, ex, ctx)
#endif

#define GNUCOBJC_EXCEPTION_CLASS UINT64_C(0x474E55434F424A43) /* GNUCOBJC */
#define GNUCCXX0_EXCEPTION_CLASS UINT64_C(0x474E5543432B2B00) /* GNUCC++\0 */
#define CLNGCXX0_EXCEPTION_CLASS UINT64_C(0x434C4E47432B2B00) /* CLNGC++\0 */

#define NUM_EMERGENCY_EXCEPTIONS 4


#define _UA_SEARCH_PHASE  0x01
#define _UA_CLEANUP_PHASE 0x02
#define _UA_HANDLER_FRAME 0x04
#define _UA_FORCE_UNWIND  0x08



#define DW_EH_PE_absptr	  0x00

#define DW_EH_PE_uleb128  0x01
#define DW_EH_PE_udata2	  0x02
#define DW_EH_PE_udata4	  0x03
#define DW_EH_PE_udata8	  0x04

#define DW_EH_PE_signed	  0x08
#define DW_EH_PE_sleb128  (DW_EH_PE_signed | DW_EH_PE_uleb128)
#define DW_EH_PE_sdata2	  (DW_EH_PE_signed | DW_EH_PE_udata2)
#define DW_EH_PE_sdata4	  (DW_EH_PE_signed | DW_EH_PE_udata4)
#define DW_EH_PE_sdata8	  (DW_EH_PE_signed | DW_EH_PE_udata8)

#define DW_EH_PE_pcrel	  0x10
#define DW_EH_PE_textrel  0x20
#define DW_EH_PE_datarel  0x30
#define DW_EH_PE_funcrel  0x40
#define DW_EH_PE_aligned  0x50

#define DW_EH_PE_indirect 0x80

#define DW_EH_PE_omit	  0xFF



#define CLEANUP_FOUND	  0x01
#define HANDLER_FOUND	  0x02


struct _Unwind_Context;

typedef enum {
	_URC_OK			= 0,
	_URC_FATAL_PHASE1_ERROR	= 3,
	_URC_END_OF_STACK	= 5,







|

>
|
|
|
|
>

>
|

|
|
|
|

|
|
|
|
|

|
|
|
|
|

|

|
>

>
|
|
>







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
# define CALL_PERSONALITY(func) func(state, ex, ctx)
#endif

#define GNUCOBJC_EXCEPTION_CLASS UINT64_C(0x474E55434F424A43) /* GNUCOBJC */
#define GNUCCXX0_EXCEPTION_CLASS UINT64_C(0x474E5543432B2B00) /* GNUCC++\0 */
#define CLNGCXX0_EXCEPTION_CLASS UINT64_C(0x434C4E47432B2B00) /* CLNGC++\0 */

#define numEmergencyExceptions 4

enum {
	_UA_SEARCH_PHASE  = 0x01,
	_UA_CLEANUP_PHASE = 0x02,
	_UA_HANDLER_FRAME = 0x04,
	_UA_FORCE_UNWIND  = 0x08
};

enum {
	DW_EH_PE_absptr	  = 0x00,

	DW_EH_PE_uleb128  = 0x01,
	DW_EH_PE_udata2	  = 0x02,
	DW_EH_PE_udata4	  = 0x03,
	DW_EH_PE_udata8	  = 0x04,

	DW_EH_PE_signed	  = 0x08,
	DW_EH_PE_sleb128  = (DW_EH_PE_signed | DW_EH_PE_uleb128),
	DW_EH_PE_sdata2	  = (DW_EH_PE_signed | DW_EH_PE_udata2),
	DW_EH_PE_sdata4	  = (DW_EH_PE_signed | DW_EH_PE_udata4),
	DW_EH_PE_sdata8	  = (DW_EH_PE_signed | DW_EH_PE_udata8),

	DW_EH_PE_pcrel	  = 0x10,
	DW_EH_PE_textrel  = 0x20,
	DW_EH_PE_datarel  = 0x30,
	DW_EH_PE_funcrel  = 0x40,
	DW_EH_PE_aligned  = 0x50,

	DW_EH_PE_indirect = 0x80,

	DW_EH_PE_omit	  = 0xFF
};

enum {
	CLEANUP_FOUND = 0x01,
	HANDLER_FOUND = 0x02
};

struct _Unwind_Context;

typedef enum {
	_URC_OK			= 0,
	_URC_FATAL_PHASE1_ERROR	= 3,
	_URC_END_OF_STACK	= 5,
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
	id object;
#ifndef HAVE_ARM_EHABI_EXCEPTIONS
	uintptr_t landingpad;
	intptr_t filter;
#endif
};

struct lsda {
	uintptr_t regionStart, landingpadsStart;
	uint8_t typesTableEnc;
	const uint8_t *typesTable;
	uintptr_t typesTableBase;
	uint8_t callsitesEnc;
	const uint8_t *callsites, *actionTable;
};







|







160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
	id object;
#ifndef HAVE_ARM_EHABI_EXCEPTIONS
	uintptr_t landingpad;
	intptr_t filter;
#endif
};

struct LSDA {
	uintptr_t regionStart, landingpadsStart;
	uint8_t typesTableEnc;
	const uint8_t *typesTable;
	uintptr_t typesTableBase;
	uint8_t callsitesEnc;
	const uint8_t *callsites, *actionTable;
};
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250

#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_t uncaughtExceptionHandler;
static struct objc_exception emergencyExceptions[NUM_EMERGENCY_EXCEPTIONS];
#ifdef OF_HAVE_THREADS
static OFSpinlock emergencyExceptionsSpinlock;

OF_CONSTRUCTOR()
{
	if (OFSpinlockNew(&emergencyExceptionsSpinlock) != 0)
		OBJC_ERROR("Cannot create spinlock!");







|
|







241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256

#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 uncaughtExceptionHandler;
static struct objc_exception emergencyExceptions[numEmergencyExceptions];
#ifdef OF_HAVE_THREADS
static OFSpinlock emergencyExceptionsSpinlock;

OF_CONSTRUCTOR()
{
	if (OFSpinlockNew(&emergencyExceptionsSpinlock) != 0)
		OBJC_ERROR("Cannot create spinlock!");
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
		value = *(uintptr_t *)(uintptr_t)value;

	return value;
}
#endif

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

	LSDA->regionStart = _Unwind_GetRegionStart(ctx);
	LSDA->landingpadsStart = LSDA->regionStart;
	LSDA->typesTable = NULL;







|







401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
		value = *(uintptr_t *)(uintptr_t)value;

	return value;
}
#endif

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

	LSDA->regionStart = _Unwind_GetRegionStart(ctx);
	LSDA->landingpadsStart = LSDA->regionStart;
	LSDA->typesTable = NULL;
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
	callsitesSize = (uintptr_t)readULEB128(&ptr);
	LSDA->callsites = ptr;

	LSDA->actionTable = LSDA->callsites + callsitesSize;
}

static bool
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;

	*landingpad = 0;
	*actionRecords = NULL;







|







429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
	callsitesSize = (uintptr_t)readULEB128(&ptr);
	LSDA->callsites = ptr;

	LSDA->actionTable = LSDA->callsites + callsitesSize;
}

static bool
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;

	*landingpad = 0;
	*actionRecords = NULL;
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
		if (iter == class)
			return true;

	return false;
}

static uint8_t
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;







|







506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
		if (iter == class)
			return true;

	return false;
}

static uint8_t
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;
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
	}

	_Unwind_SetGR(ctx, 12, (uintptr_t)ex);
#endif
	struct objc_exception *e = (struct objc_exception *)ex;
	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 (exClass) {
#ifdef CXX_PERSONALITY







|







602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
	}

	_Unwind_SetGR(ctx, 12, (uintptr_t)ex);
#endif
	struct objc_exception *e = (struct objc_exception *)ex;
	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 (exClass) {
#ifdef CXX_PERSONALITY
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745

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

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

				break;
			}







|







737
738
739
740
741
742
743
744
745
746
747
748
749
750
751

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

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

				break;
			}
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780

	if (uncaughtExceptionHandler != NULL)
		uncaughtExceptionHandler(object);

	OBJC_ERROR("_Unwind_RaiseException() returned!");
}

objc_uncaught_exception_handler_t
objc_setUncaughtExceptionHandler(objc_uncaught_exception_handler_t handler)
{
	objc_uncaught_exception_handler_t old = uncaughtExceptionHandler;
	uncaughtExceptionHandler = handler;

	return old;
}

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







|
|

|







769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786

	if (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 = uncaughtExceptionHandler;
	uncaughtExceptionHandler = handler;

	return old;
}

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

Modified src/runtime/hashtable.m from [4ff03c1700] to [91acb00f82].

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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#import "ObjFWRT.h"
#import "private.h"

struct objc_hashtable_bucket objc_deleted_bucket;

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

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

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

	return hash;
}

bool
objc_equal_string(const void *ptr1, const void *ptr2)
{
	return (strcmp(ptr1, ptr2) == 0);
}

struct objc_hashtable *
objc_hashtable_new(uint32_t (*hash)(const void *),
    bool (*equal)(const void *, const void *), uint32_t size)







|


|



















|







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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#import "ObjFWRT.h"
#import "private.h"

struct objc_hashtable_bucket objc_deletedBucket;

uint32_t
objc_string_hash(const void *str_)
{
	const char *str = str_;
	uint32_t hash = 0;

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

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

	return hash;
}

bool
objc_string_equal(const void *ptr1, const void *ptr2)
{
	return (strcmp(ptr1, ptr2) == 0);
}

struct objc_hashtable *
objc_hashtable_new(uint32_t (*hash)(const void *),
    bool (*equal)(const void *, const void *), uint32_t size)
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
		return;

	if ((newData = calloc(newSize, 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 = newSize;

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








|







99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
		return;

	if ((newData = calloc(newSize, 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_deletedBucket) {
			uint32_t j, last;

			last = newSize;

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

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
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)
			continue;

		if (table->equal(table->data[i]->key, key)) {
			*idx = i;
			return true;
		}
	}

	if (i < table->size)
		return false;

	for (i = 0; i < hash && table->data[i] != NULL; i++) {
		if (table->data[i] == &objc_deleted_bucket)
			continue;

		if (table->equal(table->data[i]->key, key)) {
			*idx = i;
			return true;
		}
	}







|












|







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
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_deletedBucket)
			continue;

		if (table->equal(table->data[i]->key, key)) {
			*idx = i;
			return true;
		}
	}

	if (i < table->size)
		return false;

	for (i = 0; i < hash && table->data[i] != NULL; i++) {
		if (table->data[i] == &objc_deletedBucket)
			continue;

		if (table->equal(table->data[i]->key, key)) {
			*idx = i;
			return true;
		}
	}
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197

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

	hash = table->hash(key);
	last = table->size;

	for (i = hash & (table->size - 1); i < last && table->data[i] != NULL &&
	    table->data[i] != &objc_deleted_bucket; i++);

	if (i >= last) {
		last = hash & (table->size - 1);

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

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

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







|





|







177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197

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

	hash = table->hash(key);
	last = table->size;

	for (i = hash & (table->size - 1); i < last && table->data[i] != NULL &&
	    table->data[i] != &objc_deletedBucket; i++);

	if (i >= last) {
		last = hash & (table->size - 1);

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

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

	if ((bucket = malloc(sizeof(*bucket))) == NULL)
		OBJC_ERROR("Not enough memory to allocate hash table bucket!");
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
{
	uint32_t idx;

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

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

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

void
objc_hashtable_free(struct objc_hashtable *table)
{
	for (uint32_t i = 0; i < table->size; i++)
		if (table->data[i] != NULL &&
		    table->data[i] != &objc_deleted_bucket)
			free(table->data[i]);

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







|










|





220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
{
	uint32_t idx;

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

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

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

void
objc_hashtable_free(struct objc_hashtable *table)
{
	for (uint32_t i = 0; i < table->size; i++)
		if (table->data[i] != NULL &&
		    table->data[i] != &objc_deletedBucket)
			free(table->data[i]);

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

Modified src/runtime/init.m from [b626330f56] to [930fe22400].

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

#import "ObjFWRT.h"
#import "private.h"

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

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

	objc_global_mutex_unlock();
}

void
objc_exit(void)
{
	objc_global_mutex_lock();

	objc_unregister_all_categories();
	objc_unregister_all_classes();
	objc_unregister_all_selectors();
	objc_forget_pending_static_instances();
	objc_dtable_cleanup();

	objc_global_mutex_unlock();
}







|

|
|
|
|

|



|

|

|
|
|
|


|

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

#import "ObjFWRT.h"
#import "private.h"

void
__objc_exec_class(struct objc_module *module)
{
	objc_globalMutex_lock();

	objc_registerAllSelectors(module->symtab);
	objc_registerAllClasses(module->symtab);
	objc_registerAllCategories(module->symtab);
	objc_initStaticInstances(module->symtab);

	objc_globalMutex_unlock();
}

void
objc_deinit(void)
{
	objc_globalMutex_lock();

	objc_unregisterAllCategories();
	objc_unregisterAllClasses();
	objc_unregisterAllSelectors();
	objc_forgetPendingStaticInstances();
	objc_dtable_cleanup();

	objc_globalMutex_unlock();
}

Modified src/runtime/instance.m from [c5fcd18398] to [3d0ab38eff].

77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
	Class class;
	void (*last)(id, SEL) = NULL;

	if (object == nil)
		return NULL;

#ifdef OF_OBJFW_RUNTIME
	objc_zero_weak_references(object);
#endif

	if (destructSelector == NULL)
		destructSelector = sel_registerName(".cxx_destruct");

	for (class = object_getClass(object); class != Nil;
	    class = class_getSuperclass(class)) {







|







77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
	Class class;
	void (*last)(id, SEL) = NULL;

	if (object == nil)
		return NULL;

#ifdef OF_OBJFW_RUNTIME
	objc_zeroWeakReferences(object);
#endif

	if (destructSelector == NULL)
		destructSelector = sel_registerName(".cxx_destruct");

	for (class = object_getClass(object); class != Nil;
	    class = class_getSuperclass(class)) {

Modified src/runtime/ivar.m from [3e8ec570e1] to [22d1127488].

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
	if (class == Nil) {
		if (outCount != NULL)
			*outCount = 0;

		return NULL;
	}

	objc_global_mutex_lock();

	count = (class->ivars != NULL ? class->ivars->count : 0);

	if (count == 0) {
		if (outCount != NULL)
			*outCount = 0;

		objc_global_mutex_unlock();
		return NULL;
	}

	if ((ivars = malloc((count + 1) * sizeof(Ivar))) == NULL)
		OBJC_ERROR("Not enough memory to copy ivars");

	for (unsigned int i = 0; i < count; i++)
		ivars[i] = &class->ivars->ivars[i];
	ivars[count] = NULL;

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

	objc_global_mutex_unlock();

	return ivars;
}

const char *
ivar_getName(Ivar ivar)
{







|







|













|







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
	if (class == Nil) {
		if (outCount != NULL)
			*outCount = 0;

		return NULL;
	}

	objc_globalMutex_lock();

	count = (class->ivars != NULL ? class->ivars->count : 0);

	if (count == 0) {
		if (outCount != NULL)
			*outCount = 0;

		objc_globalMutex_unlock();
		return NULL;
	}

	if ((ivars = malloc((count + 1) * sizeof(Ivar))) == NULL)
		OBJC_ERROR("Not enough memory to copy ivars");

	for (unsigned int i = 0; i < count; i++)
		ivars[i] = &class->ivars->ivars[i];
	ivars[count] = NULL;

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

	objc_globalMutex_unlock();

	return ivars;
}

const char *
ivar_getName(Ivar ivar)
{

Modified src/runtime/library.xml from [99fa55d924] to [f6565586a9].

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
    <argument name='protocol2' type='Protocol *_Nonnull' m68k-reg='a1'/>
  </function>
  <function name='protocol_conformsToProtocol' return-type='bool'>
    <argument name='protocol1' type='Protocol *_Nonnull' m68k-reg='a0'/>
    <argument name='protocol2' type='Protocol *_Nonnull' m68k-reg='a1'/>
  </function>
  <function name='objc_setUncaughtExceptionHandler'
            return-type='_Nullable objc_uncaught_exception_handler_t'>
    <argument name='handler' type='objc_uncaught_exception_handler_t _Nullable'
              m68k-reg='a0'/>
  </function>
  <function name='objc_setForwardHandler'>
    <argument name='forward' type='IMP _Nullable' m68k-reg='a0'/>
    <argument name='stretForward' type='IMP _Nullable' m68k-reg='a1'/>
  </function>
  <function name='objc_setEnumerationMutationHandler'>
    <argument name='hadler' type='objc_enumeration_mutation_handler_t _Nullable'
              m68k-reg='a0'/>
  </function>
  <function name='objc_constructInstance' return-type='id _Nullable'>
    <argument name='class' type='Class _Nullable' m68k-reg='a0'/>
    <argument name='bytes' type='void *_Nullable' m68k-reg='a1'/>
  </function>
  <function name='objc_exit'/>
  <function name='class_copyIvarList' return-type='Ivar _Nullable *_Nullable'>
    <argument name='class' type='Class _Nullable' m68k-reg='a0'/>
    <argument name='outCount' type='unsigned int *_Nullable' m68k-reg='a1'/>
  </function>
  <function name='ivar_getName' return-type='const char *_Nonnull'>
    <argument name='ivar' type='Ivar _Nonnull' m68k-reg='a0'/>
  </function>







|
|







|






|







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
    <argument name='protocol2' type='Protocol *_Nonnull' m68k-reg='a1'/>
  </function>
  <function name='protocol_conformsToProtocol' return-type='bool'>
    <argument name='protocol1' type='Protocol *_Nonnull' m68k-reg='a0'/>
    <argument name='protocol2' type='Protocol *_Nonnull' m68k-reg='a1'/>
  </function>
  <function name='objc_setUncaughtExceptionHandler'
            return-type='_Nullable objc_uncaught_exception_handler'>
    <argument name='handler' type='objc_uncaught_exception_handler _Nullable'
              m68k-reg='a0'/>
  </function>
  <function name='objc_setForwardHandler'>
    <argument name='forward' type='IMP _Nullable' m68k-reg='a0'/>
    <argument name='stretForward' type='IMP _Nullable' m68k-reg='a1'/>
  </function>
  <function name='objc_setEnumerationMutationHandler'>
    <argument name='hadler' type='objc_enumeration_mutation_handler _Nullable'
              m68k-reg='a0'/>
  </function>
  <function name='objc_constructInstance' return-type='id _Nullable'>
    <argument name='class' type='Class _Nullable' m68k-reg='a0'/>
    <argument name='bytes' type='void *_Nullable' m68k-reg='a1'/>
  </function>
  <function name='objc_deinit'/>
  <function name='class_copyIvarList' return-type='Ivar _Nullable *_Nullable'>
    <argument name='class' type='Class _Nullable' m68k-reg='a0'/>
    <argument name='outCount' type='unsigned int *_Nullable' m68k-reg='a1'/>
  </function>
  <function name='ivar_getName' return-type='const char *_Nonnull'>
    <argument name='ivar' type='Ivar _Nonnull' m68k-reg='a0'/>
  </function>

Modified src/runtime/linklib/linklib.m from [e1e21b28b9] to [9056a4e93e].

1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
	    :: "r"(ObjFWRTBase) : "r12"
	);

	return __extension__ ((bool (*)(Protocol *_Nonnull, Protocol *_Nonnull))*(void **)(((uintptr_t)ObjFWRTBase) - 382))(protocol1, protocol2);
#endif
}

_Nullable objc_uncaught_exception_handler_t
objc_setUncaughtExceptionHandler(objc_uncaught_exception_handler_t _Nullable handler)
{
#if defined(OF_AMIGAOS_M68K)
	register struct Library *a6 __asm__("a6") = ObjFWRTBase;
	(void)a6;
	return ((_Nullable objc_uncaught_exception_handler_t (*)(objc_uncaught_exception_handler_t _Nullable __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 390))(handler);
#elif defined(OF_MORPHOS)
	__asm__ __volatile__ (
	    "mr		%%r12, %0"
	    :: "r"(ObjFWRTBase) : "r12"
	);

	return __extension__ ((_Nullable objc_uncaught_exception_handler_t (*)(objc_uncaught_exception_handler_t _Nullable))*(void **)(((uintptr_t)ObjFWRTBase) - 388))(handler);
#endif
}

void
objc_setForwardHandler(IMP _Nullable forward, IMP _Nullable stretForward)
{
#if defined(OF_AMIGAOS_M68K)







|
|




|






|







1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
	    :: "r"(ObjFWRTBase) : "r12"
	);

	return __extension__ ((bool (*)(Protocol *_Nonnull, Protocol *_Nonnull))*(void **)(((uintptr_t)ObjFWRTBase) - 382))(protocol1, protocol2);
#endif
}

_Nullable objc_uncaught_exception_handler
objc_setUncaughtExceptionHandler(objc_uncaught_exception_handler _Nullable handler)
{
#if defined(OF_AMIGAOS_M68K)
	register struct Library *a6 __asm__("a6") = ObjFWRTBase;
	(void)a6;
	return ((_Nullable objc_uncaught_exception_handler (*)(objc_uncaught_exception_handler _Nullable __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 390))(handler);
#elif defined(OF_MORPHOS)
	__asm__ __volatile__ (
	    "mr		%%r12, %0"
	    :: "r"(ObjFWRTBase) : "r12"
	);

	return __extension__ ((_Nullable objc_uncaught_exception_handler (*)(objc_uncaught_exception_handler _Nullable))*(void **)(((uintptr_t)ObjFWRTBase) - 388))(handler);
#endif
}

void
objc_setForwardHandler(IMP _Nullable forward, IMP _Nullable stretForward)
{
#if defined(OF_AMIGAOS_M68K)
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
	);

	__extension__ ((void (*)(IMP _Nullable, IMP _Nullable))*(void **)(((uintptr_t)ObjFWRTBase) - 394))(forward, stretForward);
#endif
}

void
objc_setEnumerationMutationHandler(objc_enumeration_mutation_handler_t _Nullable hadler)
{
#if defined(OF_AMIGAOS_M68K)
	register struct Library *a6 __asm__("a6") = ObjFWRTBase;
	(void)a6;
	((void (*)(objc_enumeration_mutation_handler_t _Nullable __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 402))(hadler);
#elif defined(OF_MORPHOS)
	__asm__ __volatile__ (
	    "mr		%%r12, %0"
	    :: "r"(ObjFWRTBase) : "r12"
	);

	__extension__ ((void (*)(objc_enumeration_mutation_handler_t _Nullable))*(void **)(((uintptr_t)ObjFWRTBase) - 400))(hadler);
#endif
}

id _Nullable
objc_constructInstance(Class _Nullable class, void *_Nullable bytes)
{
#if defined(OF_AMIGAOS_M68K)







|




|






|







1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
	);

	__extension__ ((void (*)(IMP _Nullable, IMP _Nullable))*(void **)(((uintptr_t)ObjFWRTBase) - 394))(forward, stretForward);
#endif
}

void
objc_setEnumerationMutationHandler(objc_enumeration_mutation_handler _Nullable hadler)
{
#if defined(OF_AMIGAOS_M68K)
	register struct Library *a6 __asm__("a6") = ObjFWRTBase;
	(void)a6;
	((void (*)(objc_enumeration_mutation_handler _Nullable __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 402))(hadler);
#elif defined(OF_MORPHOS)
	__asm__ __volatile__ (
	    "mr		%%r12, %0"
	    :: "r"(ObjFWRTBase) : "r12"
	);

	__extension__ ((void (*)(objc_enumeration_mutation_handler _Nullable))*(void **)(((uintptr_t)ObjFWRTBase) - 400))(hadler);
#endif
}

id _Nullable
objc_constructInstance(Class _Nullable class, void *_Nullable bytes)
{
#if defined(OF_AMIGAOS_M68K)
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
	);

	return __extension__ ((id _Nullable (*)(Class _Nullable, void *_Nullable))*(void **)(((uintptr_t)ObjFWRTBase) - 406))(class, bytes);
#endif
}

void
objc_exit()
{
#if defined(OF_AMIGAOS_M68K)
	register struct Library *a6 __asm__("a6") = ObjFWRTBase;
	(void)a6;
	((void (*)())(((uintptr_t)ObjFWRTBase) - 414))();
#elif defined(OF_MORPHOS)
	__asm__ __volatile__ (







|







1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
	);

	return __extension__ ((id _Nullable (*)(Class _Nullable, void *_Nullable))*(void **)(((uintptr_t)ObjFWRTBase) - 406))(class, bytes);
#endif
}

void
objc_deinit()
{
#if defined(OF_AMIGAOS_M68K)
	register struct Library *a6 __asm__("a6") = ObjFWRTBase;
	(void)a6;
	((void (*)())(((uintptr_t)ObjFWRTBase) - 414))();
#elif defined(OF_MORPHOS)
	__asm__ __volatile__ (

Modified src/runtime/lookup-asm/lookup-asm-arm-elf.S from [7443d47cf7] to [40d58a6394].

19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

.globl objc_msg_lookup
.globl objc_msg_lookup_stret
.globl objc_msg_lookup_super
.globl objc_msg_lookup_super_stret

.section .text
.macro generate_lookup name not_found
\name:
	cmp	r0, #0
	beq	ret_nil

	tst	r0, #1
	bne	.Ltagged_pointer_\name

	ldr	r2, [r0, #0]
	ldr	r2, [r2, #32]

.Lmain_\name:
#ifndef OF_BIG_ENDIAN
# ifdef OF_SELUID24







|


|


|







19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

.globl objc_msg_lookup
.globl objc_msg_lookup_stret
.globl objc_msg_lookup_super
.globl objc_msg_lookup_super_stret

.section .text
.macro GENERATE_LOOKUP name notFound
\name:
	cmp	r0, #0
	beq	returnNilMethod

	tst	r0, #1
	bne	.LtaggedPointer_\name

	ldr	r2, [r0, #0]
	ldr	r2, [r2, #32]

.Lmain_\name:
#ifndef OF_BIG_ENDIAN
# ifdef OF_SELUID24
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
	ldrb	r3, [r1, #2]
	ldr	r2, [r2, r3, lsl #2]
	ldrb	r3, [r1, #3]
	ldr	r2, [r2, r3, lsl #2]
#endif

	cmp	r2, #0
	beq	\not_found(PLT)

	mov	r0, r2
	bx	lr

.Ltagged_pointer_\name:
	ldr	r2, .Lgot$indirect_.Ltagged_pointer_\name
	add	r2, pc, r2

	ldr	r3, .Lgot$indirect_.Ltagged_pointer_\name+4
	ldr	r3, [r2, r3]
	ldr	r3, [r3]
	eor	r0, r0, r3
	and	r0, r0, #0xE
	lsl	r0, r0, #1

	ldr	r3, .Lgot$indirect_.Ltagged_pointer_\name+8
	ldr	r3, [r2, r3]
	ldr	r2, [r3, r0]
	ldr	r2, [r2, #32]

	b	.Lmain_\name
.type \name, %function
.size \name, .-\name

.Lgot$indirect_.Ltagged_pointer_\name:
	.long	_GLOBAL_OFFSET_TABLE_-(.Ltagged_pointer_\name+12)
	.long	objc_tagged_pointer_secret(GOT)
	.long	objc_tagged_pointer_classes(GOT)
.endm

.macro generate_lookup_super name lookup
\name:
	mov	r2, r0
	ldr	r0, [r0, #0]
	cmp	r0, #0
	beq	ret_nil

	ldr	r2, [r2, #4]
	ldr	r2, [r2, #32]

	b	.Lmain_\lookup
.type \name, %function
.size \name, .-\name
.endm

generate_lookup objc_msg_lookup objc_method_not_found
generate_lookup objc_msg_lookup_stret objc_method_not_found_stret
generate_lookup_super objc_msg_lookup_super objc_msg_lookup
generate_lookup_super objc_msg_lookup_super_stret objc_msg_lookup_stret

ret_nil:
	adr	r0, nil_method
	bx	lr

nil_method:
	mov	r0, #0
	bx	lr

#ifdef OF_LINUX
.section .note.GNU-stack, "", %progbits
#endif







|




|
|


|






|








|
|
|
|


|




|









|
|
|
|

|
|


|






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
	ldrb	r3, [r1, #2]
	ldr	r2, [r2, r3, lsl #2]
	ldrb	r3, [r1, #3]
	ldr	r2, [r2, r3, lsl #2]
#endif

	cmp	r2, #0
	beq	\notFound(PLT)

	mov	r0, r2
	bx	lr

.LtaggedPointer_\name:
	ldr	r2, .Lgot$indirect_.LtaggedPointer_\name
	add	r2, pc, r2

	ldr	r3, .Lgot$indirect_.LtaggedPointer_\name+4
	ldr	r3, [r2, r3]
	ldr	r3, [r3]
	eor	r0, r0, r3
	and	r0, r0, #0xE
	lsl	r0, r0, #1

	ldr	r3, .Lgot$indirect_.LtaggedPointer_\name+8
	ldr	r3, [r2, r3]
	ldr	r2, [r3, r0]
	ldr	r2, [r2, #32]

	b	.Lmain_\name
.type \name, %function
.size \name, .-\name

.Lgot$indirect_.LtaggedPointer_\name:
	.long	_GLOBAL_OFFSET_TABLE_-(.LtaggedPointer_\name+12)
	.long	objc_taggedPointerSecret(GOT)
	.long	objc_taggedPointerClasses(GOT)
.endm

.macro GENERATE_LOOKUP_SUPER name lookup
\name:
	mov	r2, r0
	ldr	r0, [r0, #0]
	cmp	r0, #0
	beq	returnNilMethod

	ldr	r2, [r2, #4]
	ldr	r2, [r2, #32]

	b	.Lmain_\lookup
.type \name, %function
.size \name, .-\name
.endm

GENERATE_LOOKUP objc_msg_lookup objc_methodNotFound
GENERATE_LOOKUP objc_msg_lookup_stret objc_methodNotFound_stret
GENERATE_LOOKUP_SUPER objc_msg_lookup_super objc_msg_lookup
GENERATE_LOOKUP_SUPER objc_msg_lookup_super_stret objc_msg_lookup_stret

returnNilMethod:
	adr	r0, nilMethod
	bx	lr

nilMethod:
	mov	r0, #0
	bx	lr

#ifdef OF_LINUX
.section .note.GNU-stack, "", %progbits
#endif

Modified src/runtime/lookup-asm/lookup-asm-arm64-elf.S from [7551faefd3] to [77601b6969].

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

.globl objc_msg_lookup
.globl objc_msg_lookup_stret
.globl objc_msg_lookup_super
.globl objc_msg_lookup_super_stret

.section .text
.macro generate_lookup name not_found
\name:
	cbz	x0, ret_nil

	tst	x0, #1
	b.ne	.Ltagged_pointer_\name

	ldr	x2, [x0]
	ldr	x2, [x2, #64]

.Lmain_\name:
#ifdef OF_SELUID24
	ldrb	w3, [x1, #2]
	ldr	x2, [x2, x3, lsl #3]
#endif
	ldrb	w3, [x1, #1]
	ldr	x2, [x2, x3, lsl #3]
	ldrb	w3, [x1]
	ldr	x2, [x2, x3, lsl #3]

	cbz	x2, \not_found

	mov	x0, x2
	ret

.Ltagged_pointer_\name:
	adrp	x2, :got:objc_tagged_pointer_secret
	ldr	x2, [x2, #:got_lo12:objc_tagged_pointer_secret]
	ldr	x2, [x2]
	eor	x0, x0, x2
	and	x0, x0, #0xE
	lsl	x0, x0, #2

	adrp	x2, :got:objc_tagged_pointer_classes
	ldr	x2, [x2, #:got_lo12:objc_tagged_pointer_classes]
	ldr	x2, [x2, x0]
	ldr	x2, [x2, #64]

	b	.Lmain_\name
.type \name, %function
.size \name, .-\name
.endm

.macro generate_lookup_super name lookup
\name:
	mov	x2, x0
	ldr	x0, [x0]
	cbz	x0, ret_nil

	ldr	x2, [x2, #8]
	ldr	x2, [x2, #64]

	b	.Lmain_\lookup
.type \name, %function
.size \name, .-\name
.endm

generate_lookup objc_msg_lookup objc_method_not_found
generate_lookup objc_msg_lookup_stret objc_method_not_found_stret
generate_lookup_super objc_msg_lookup_super objc_msg_lookup
generate_lookup_super objc_msg_lookup_super_stret objc_msg_lookup_stret

ret_nil:
	adr	x0, nil_method
	ret

nil_method:
	mov	x0, #0
	ret

#ifdef OF_LINUX
.section .note.GNU-stack, "", %progbits
#endif







|

|


|














|




|
|
|





|
|








|



|









|
|
|
|

|
|


|






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

.globl objc_msg_lookup
.globl objc_msg_lookup_stret
.globl objc_msg_lookup_super
.globl objc_msg_lookup_super_stret

.section .text
.macro GENERATE_LOOKUP name notFound
\name:
	cbz	x0, returnNilMethod

	tst	x0, #1
	b.ne	.LtaggedPointer_\name

	ldr	x2, [x0]
	ldr	x2, [x2, #64]

.Lmain_\name:
#ifdef OF_SELUID24
	ldrb	w3, [x1, #2]
	ldr	x2, [x2, x3, lsl #3]
#endif
	ldrb	w3, [x1, #1]
	ldr	x2, [x2, x3, lsl #3]
	ldrb	w3, [x1]
	ldr	x2, [x2, x3, lsl #3]

	cbz	x2, \notFound

	mov	x0, x2
	ret

.LtaggedPointer_\name:
	adrp	x2, :got:objc_taggedPointerSecret
	ldr	x2, [x2, #:got_lo12:objc_taggedPointerSecret]
	ldr	x2, [x2]
	eor	x0, x0, x2
	and	x0, x0, #0xE
	lsl	x0, x0, #2

	adrp	x2, :got:objc_taggedPointerClasses
	ldr	x2, [x2, #:got_lo12:objc_taggedPointerClasses]
	ldr	x2, [x2, x0]
	ldr	x2, [x2, #64]

	b	.Lmain_\name
.type \name, %function
.size \name, .-\name
.endm

.macro GENERATE_LOOKUP_SUPER name lookup
\name:
	mov	x2, x0
	ldr	x0, [x0]
	cbz	x0, returnNilMethod

	ldr	x2, [x2, #8]
	ldr	x2, [x2, #64]

	b	.Lmain_\lookup
.type \name, %function
.size \name, .-\name
.endm

GENERATE_LOOKUP objc_msg_lookup objc_methodNotFound
GENERATE_LOOKUP objc_msg_lookup_stret objc_methodNotFound_stret
GENERATE_LOOKUP_SUPER objc_msg_lookup_super objc_msg_lookup
GENERATE_LOOKUP_SUPER objc_msg_lookup_super_stret objc_msg_lookup_stret

returnNilMethod:
	adr	x0, nilMethod
	ret

nilMethod:
	mov	x0, #0
	ret

#ifdef OF_LINUX
.section .note.GNU-stack, "", %progbits
#endif

Modified src/runtime/lookup-asm/lookup-asm-mips-elf.S from [b2c0fd7a36] to [16aa30af7f].

19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

.globl objc_msg_lookup
.globl objc_msg_lookup_stret
.globl objc_msg_lookup_super
.globl objc_msg_lookup_super_stret

.section .text
.macro generate_lookup name not_found
\name:
	beqz	$a0, 0f

	andi	$t0, $a0, 1
	bnez	$t0, .Ltagged_pointer_\name

	lw	$t0, 0($a0)
	lw	$t0, 32($t0)

.Lmain_\name:
#ifdef OF_BIG_ENDIAN
# ifdef OF_SELUID24







|




|







19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

.globl objc_msg_lookup
.globl objc_msg_lookup_stret
.globl objc_msg_lookup_super
.globl objc_msg_lookup_super_stret

.section .text
.macro GENERATE_LOOKUP name notFound
\name:
	beqz	$a0, 0f

	andi	$t0, $a0, 1
	bnez	$t0, .LtaggedPointer_\name

	lw	$t0, 0($a0)
	lw	$t0, 32($t0)

.Lmain_\name:
#ifdef OF_BIG_ENDIAN
# ifdef OF_SELUID24
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
	lw	$t0, 0($t0)
	addu	$t0, $t0, $t3
	lw	$t0, 0($t0)

#ifdef OF_PIC
	beqz	$t0, 1f
#else
	beqz	$t0, \not_found
#endif

	move	$v0, $t0
	jr	$ra

0:
#ifdef OF_PIC
	addiu	$v0, $t9, nil_method-\name
#else
	la	$v0, nil_method
#endif
	jr	$ra

#ifdef OF_PIC
1:
	lui	$gp, %hi(_gp_disp)
	addiu	$gp, $gp, %lo(_gp_disp)
	addu	$gp, $gp, $t9
	addiu	$gp, $gp, 1b-\name

	lw	$t9, %call16(\not_found)($gp)
	jr	$t9
#endif

.Ltagged_pointer_\name:
#ifdef OF_PIC
0:
	lui	$gp, %hi(_gp_disp)
	addiu	$gp, $gp, %lo(_gp_disp)
	addu	$gp, $gp, $t9
	addiu	$gp, $gp, 0b-\name

	lw	$t0, %got(objc_tagged_pointer_secret)($gp)
#else
	la	$t0, objc_tagged_pointer_secret
#endif
	lw	$t0, 0($t0)
	xor	$t0, $a0, $t0
	and	$t0, $t0, 0xE
	sll	$t0, $t0, 1

#ifdef OF_PIC
	lw	$t1, %got(objc_tagged_pointer_classes)($gp)
#else
	la	$t1, objc_tagged_pointer_classes
#endif
	addu	$t0, $t1, $t0
	ld	$t0, ($t0)
	ld	$t0, 32($t0)

	b	.Lmain_\name
.type \name, %function
.size \name, .-\name
.endm

.macro generate_lookup_super name lookup
\name:
	move	$t0, $a0
	lw	$a0, 0($a0)
	beqz	$a0, 0f

	lw	$t0, 4($t0)
	lw	$t0, 32($t0)

	addiu	$t9, $t9, \lookup-\name
	b	.Lmain_\lookup

0:
#ifdef OF_PIC
	addiu	$v0, $t9, nil_method-\name
#else
	la	$v0, nil_method
#endif
	jr	$ra
.type \name, %function
.size \name, .-\name
.endm

generate_lookup objc_msg_lookup objc_method_not_found
generate_lookup objc_msg_lookup_stret objc_method_not_found_stret
generate_lookup_super objc_msg_lookup_super objc_msg_lookup
generate_lookup_super objc_msg_lookup_super_stret objc_msg_lookup_stret

nil_method:
	move	$v0, $zero
	jr	$ra

#ifdef OF_LINUX
.section .note.GNU-stack, "", %progbits
#endif







|







|

|










|



|







|

|







|

|










|













|

|






|
|
|
|

|






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
	lw	$t0, 0($t0)
	addu	$t0, $t0, $t3
	lw	$t0, 0($t0)

#ifdef OF_PIC
	beqz	$t0, 1f
#else
	beqz	$t0, \notFound
#endif

	move	$v0, $t0
	jr	$ra

0:
#ifdef OF_PIC
	addiu	$v0, $t9, nilMethod-\name
#else
	la	$v0, nilMethod
#endif
	jr	$ra

#ifdef OF_PIC
1:
	lui	$gp, %hi(_gp_disp)
	addiu	$gp, $gp, %lo(_gp_disp)
	addu	$gp, $gp, $t9
	addiu	$gp, $gp, 1b-\name

	lw	$t9, %call16(\notFound)($gp)
	jr	$t9
#endif

.LtaggedPointer_\name:
#ifdef OF_PIC
0:
	lui	$gp, %hi(_gp_disp)
	addiu	$gp, $gp, %lo(_gp_disp)
	addu	$gp, $gp, $t9
	addiu	$gp, $gp, 0b-\name

	lw	$t0, %got(objc_taggedPointerSecret)($gp)
#else
	la	$t0, objc_taggedPointerSecret
#endif
	lw	$t0, 0($t0)
	xor	$t0, $a0, $t0
	and	$t0, $t0, 0xE
	sll	$t0, $t0, 1

#ifdef OF_PIC
	lw	$t1, %got(objc_taggedPointerClasses)($gp)
#else
	la	$t1, objc_taggedPointerClasses
#endif
	addu	$t0, $t1, $t0
	ld	$t0, ($t0)
	ld	$t0, 32($t0)

	b	.Lmain_\name
.type \name, %function
.size \name, .-\name
.endm

.macro GENERATE_LOOKUP_SUPER name lookup
\name:
	move	$t0, $a0
	lw	$a0, 0($a0)
	beqz	$a0, 0f

	lw	$t0, 4($t0)
	lw	$t0, 32($t0)

	addiu	$t9, $t9, \lookup-\name
	b	.Lmain_\lookup

0:
#ifdef OF_PIC
	addiu	$v0, $t9, nilMethod-\name
#else
	la	$v0, nilMethod
#endif
	jr	$ra
.type \name, %function
.size \name, .-\name
.endm

GENERATE_LOOKUP objc_msg_lookup objc_methodNotFound
GENERATE_LOOKUP objc_msg_lookup_stret objc_methodNotFound_stret
GENERATE_LOOKUP_SUPER objc_msg_lookup_super objc_msg_lookup
GENERATE_LOOKUP_SUPER objc_msg_lookup_super_stret objc_msg_lookup_stret

nilMethod:
	move	$v0, $zero
	jr	$ra

#ifdef OF_LINUX
.section .note.GNU-stack, "", %progbits
#endif

Modified src/runtime/lookup-asm/lookup-asm-mips64-n64-elf.S from [34f3dd7a14] to [6719050384].

19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

.globl objc_msg_lookup
.globl objc_msg_lookup_stret
.globl objc_msg_lookup_super
.globl objc_msg_lookup_super_stret

.section .text
.macro generate_lookup name not_found
\name:
	beqz	$a0, 0f

	andi	$t0, $a0, 1
	bnez	$t0, .Ltagged_pointer_\name

	ld	$t0, ($a0)
	ld	$t0, 64($t0)

.Lmain_\name:
#ifdef OF_BIG_ENDIAN
# ifdef OF_SELUID24







|




|







19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

.globl objc_msg_lookup
.globl objc_msg_lookup_stret
.globl objc_msg_lookup_super
.globl objc_msg_lookup_super_stret

.section .text
.macro GENERATE_LOOKUP name notFound
\name:
	beqz	$a0, 0f

	andi	$t0, $a0, 1
	bnez	$t0, .LtaggedPointer_\name

	ld	$t0, ($a0)
	ld	$t0, 64($t0)

.Lmain_\name:
#ifdef OF_BIG_ENDIAN
# ifdef OF_SELUID24
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
	move	$v0, $t0
	jr	$ra

0:
	lui	$v0, %hi(%neg(%gp_rel(\name)))
	daddiu	$v0, $v0, %lo(%neg(%gp_rel(\name)))
	daddu	$v0, $v0, $t9
	ld	$v0, %got_disp(nil_method)($v0)
	jr	$ra

1:
	lui	$t0, %hi(%neg(%gp_rel(\name)))
	daddiu	$t0, $t0, %lo(%neg(%gp_rel(\name)))
	daddu	$t0, $t0, $t9
	ld	$t9, %got_disp(\not_found)($t0)
	jr	$t9

.Ltagged_pointer_\name:
	lui	$t0, %hi(%neg(%gp_rel(\name)))
	daddiu	$t0, $t0, %lo(%neg(%gp_rel(\name)))
	daddu	$t0, $t0, $t9

	ld	$t1, %got_disp(objc_tagged_pointer_secret)($t0)
	ld	$t1, 0($t1)
	xor	$t1, $a0, $t1
	and	$t1, $t1, 0xE
	dsll	$t1, $t1, 2

	ld	$t0, %got_disp(objc_tagged_pointer_classes)($t0)
	daddu	$t0, $t0, $t1
	ld	$t0, ($t0)
	ld	$t0, 64($t0)

	b	.Lmain_\name
.type \name, %function
.size \name, .-\name
.endm

.macro generate_lookup_super name lookup
\name:
	move	$t0, $a0
	ld	$a0, ($a0)
	beqz	$a0, 0f

	ld	$t0, 8($t0)
	ld	$t0, 64($t0)

	daddiu	$t9, $t9, \lookup-\name
	b	.Lmain_\lookup

0:
	lui	$v0, %hi(%neg(%gp_rel(\name)))
	daddiu	$v0, $v0, %lo(%neg(%gp_rel(\name)))
	daddu	$v0, $v0, $t9
	ld	$v0, %got_disp(nil_method)($v0)
	jr	$ra
.type \name, %function
.size \name, .-\name
.endm

generate_lookup objc_msg_lookup objc_method_not_found
generate_lookup objc_msg_lookup_stret objc_method_not_found_stret
generate_lookup_super objc_msg_lookup_super objc_msg_lookup
generate_lookup_super objc_msg_lookup_super_stret objc_msg_lookup_stret

nil_method:
	move	$v0, $zero
	jr	$ra

#ifdef OF_LINUX
.section .note.GNU-stack, "", %progbits
#endif







|






|


|




|





|









|















|





|
|
|
|

|






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
	move	$v0, $t0
	jr	$ra

0:
	lui	$v0, %hi(%neg(%gp_rel(\name)))
	daddiu	$v0, $v0, %lo(%neg(%gp_rel(\name)))
	daddu	$v0, $v0, $t9
	ld	$v0, %got_disp(nilMethod)($v0)
	jr	$ra

1:
	lui	$t0, %hi(%neg(%gp_rel(\name)))
	daddiu	$t0, $t0, %lo(%neg(%gp_rel(\name)))
	daddu	$t0, $t0, $t9
	ld	$t9, %got_disp(\notFound)($t0)
	jr	$t9

.LtaggedPointer_\name:
	lui	$t0, %hi(%neg(%gp_rel(\name)))
	daddiu	$t0, $t0, %lo(%neg(%gp_rel(\name)))
	daddu	$t0, $t0, $t9

	ld	$t1, %got_disp(objc_taggedPointerSecret)($t0)
	ld	$t1, 0($t1)
	xor	$t1, $a0, $t1
	and	$t1, $t1, 0xE
	dsll	$t1, $t1, 2

	ld	$t0, %got_disp(objc_taggedPointerClasses)($t0)
	daddu	$t0, $t0, $t1
	ld	$t0, ($t0)
	ld	$t0, 64($t0)

	b	.Lmain_\name
.type \name, %function
.size \name, .-\name
.endm

.macro GENERATE_LOOKUP_SUPER name lookup
\name:
	move	$t0, $a0
	ld	$a0, ($a0)
	beqz	$a0, 0f

	ld	$t0, 8($t0)
	ld	$t0, 64($t0)

	daddiu	$t9, $t9, \lookup-\name
	b	.Lmain_\lookup

0:
	lui	$v0, %hi(%neg(%gp_rel(\name)))
	daddiu	$v0, $v0, %lo(%neg(%gp_rel(\name)))
	daddu	$v0, $v0, $t9
	ld	$v0, %got_disp(nilMethod)($v0)
	jr	$ra
.type \name, %function
.size \name, .-\name
.endm

GENERATE_LOOKUP objc_msg_lookup objc_methodNotFound
GENERATE_LOOKUP objc_msg_lookup_stret objc_methodNotFound_stret
GENERATE_LOOKUP_SUPER objc_msg_lookup_super objc_msg_lookup
GENERATE_LOOKUP_SUPER objc_msg_lookup_super_stret objc_msg_lookup_stret

nilMethod:
	move	$v0, $zero
	jr	$ra

#ifdef OF_LINUX
.section .note.GNU-stack, "", %progbits
#endif

Modified src/runtime/lookup-asm/lookup-asm-powerpc-elf.S from [e20fe0b40d] to [7227a38be1].

19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

.globl objc_msg_lookup
.globl objc_msg_lookup_stret
.globl objc_msg_lookup_super
.globl objc_msg_lookup_super_stret

.section .text
.macro generate_lookup name not_found
\name:
	cmpwi	%r3, 0
	beq-	ret_nil

	andi.	%r0, %r3, 1
	bne-	.Ltagged_pointer_\name

	lwz	%r5, 0(%r3)
	lwz	%r5, 32(%r5)

.Lmain_\name:
	lwz	%r8, 0(%r4)
#ifdef OF_SELUID24







|


|


|







19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

.globl objc_msg_lookup
.globl objc_msg_lookup_stret
.globl objc_msg_lookup_super
.globl objc_msg_lookup_super_stret

.section .text
.macro GENERATE_LOOKUP name notFound
\name:
	cmpwi	%r3, 0
	beq-	returnNilMethod

	andi.	%r0, %r3, 1
	bne-	.LtaggedPointer_\name

	lwz	%r5, 0(%r3)
	lwz	%r5, 32(%r5)

.Lmain_\name:
	lwz	%r8, 0(%r4)
#ifdef OF_SELUID24
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

	bl	0f
0:
	mflr	%r30
	addis	%r30, %r30, .Lbiased_got2-0b@ha
	addi	%r30, %r30, .Lbiased_got2-0b@l

	lwz	%r0, .Lgot_\not_found-.Lbiased_got2(%r30)
	mtctr	%r0

	lwz	%r30, 8(%r1)
	lwz	%r0, 20(%r1)
	addi	%r1, %r1, 16
	mtlr	%r0

	bctr
#else
	b	\not_found
#endif

.Ltagged_pointer_\name:
#if defined(OF_PIC)
	mflr	%r7
	bl	0f
0:
	mflr	%r6
	mtlr	%r7
	addis	%r6, %r6, .Lbiased_got2-0b@ha
	addi	%r6, %r6, .Lbiased_got2-0b@l

	lwz	%r5, .Lgot_objc_tagged_pointer_secret-.Lbiased_got2(%r6)
	lwz	%r5, 0(%r5)
#elif defined(OF_BASEREL)
	addis	%r5, %r13, objc_tagged_pointer_secret@drel@ha
	lwz	%r5, objc_tagged_pointer_secret@drel@l(%r5)
#else
	lis	%r5, objc_tagged_pointer_secret@ha
	lwz	%r5, objc_tagged_pointer_secret@l(%r5)
#endif
	xor	%r5, %r3, %r5
	rlwinm	%r5, %r5, 1, 0x1C

#if defined(OF_PIC)
	lwz	%r6, .Lgot_objc_tagged_pointer_classes-.Lbiased_got2(%r6)
#elif defined(OF_BASEREL)
	addis	%r6, %r13, objc_tagged_pointer_classes@drel@ha
	addi	%r6, %r6, objc_tagged_pointer_classes@drel@l
#else
	lis	%r6, objc_tagged_pointer_classes@ha
	addi	%r6, %r6, objc_tagged_pointer_classes@l
#endif
	lwzx	%r5, %r6, %r5
	lwz	%r5, 32(%r5)

	b	.Lmain_\name
.type \name, @function
.size \name, .-\name
.endm

.macro generate_lookup_super name lookup
\name:
	mr	%r5, %r3
	lwz	%r3, 0(%r3)
	cmpwi	%r3, 0
	beq-	ret_nil

	lwz	%r5, 4(%r5)
	lwz	%r5, 32(%r5)

	b	.Lmain_\lookup
.type \name, @function
.size \name, .-\name
.endm

generate_lookup objc_msg_lookup objc_method_not_found
generate_lookup objc_msg_lookup_stret objc_method_not_found_stret
generate_lookup_super objc_msg_lookup_super objc_msg_lookup
generate_lookup_super objc_msg_lookup_super_stret objc_msg_lookup_stret

ret_nil:
	mflr	%r0
	bl	get_pc
	mtlr	%r0
0:
	addi	%r3, %r3, nil_method-0b
	blr

nil_method:
	li	%r3, 0
	blr

get_pc:
	mflr	%r3
	blr

#ifdef OF_PIC
.section .got2, "aw"
.Lbiased_got2 = .+0x8000
.Lgot_objc_method_not_found:
	.long objc_method_not_found
.Lgot_objc_method_not_found_stret:
	.long objc_method_not_found_stret
.Lgot_objc_tagged_pointer_secret:
	.long objc_tagged_pointer_secret
.Lgot_objc_tagged_pointer_classes:
	.long objc_tagged_pointer_classes
#endif

#ifdef OF_LINUX
.section .note.GNU-stack, "", @progbits
#endif







|









|


|









|


|
|

|
|





|

|
|

|
|









|




|









|
|
|
|

|

|


|


|



|






|
|
|
|
|
|
|
|





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

	bl	0f
0:
	mflr	%r30
	addis	%r30, %r30, .Lbiased_got2-0b@ha
	addi	%r30, %r30, .Lbiased_got2-0b@l

	lwz	%r0, .Lgot_\notFound-.Lbiased_got2(%r30)
	mtctr	%r0

	lwz	%r30, 8(%r1)
	lwz	%r0, 20(%r1)
	addi	%r1, %r1, 16
	mtlr	%r0

	bctr
#else
	b	\notFound
#endif

.LtaggedPointer_\name:
#if defined(OF_PIC)
	mflr	%r7
	bl	0f
0:
	mflr	%r6
	mtlr	%r7
	addis	%r6, %r6, .Lbiased_got2-0b@ha
	addi	%r6, %r6, .Lbiased_got2-0b@l

	lwz	%r5, .Lgot_objc_taggedPointerSecret-.Lbiased_got2(%r6)
	lwz	%r5, 0(%r5)
#elif defined(OF_BASEREL)
	addis	%r5, %r13, objc_taggedPointerSecret@drel@ha
	lwz	%r5, objc_taggedPointerSecret@drel@l(%r5)
#else
	lis	%r5, objc_taggedPointerSecret@ha
	lwz	%r5, objc_taggedPointerSecret@l(%r5)
#endif
	xor	%r5, %r3, %r5
	rlwinm	%r5, %r5, 1, 0x1C

#if defined(OF_PIC)
	lwz	%r6, .Lgot_objc_taggedPointerClasses-.Lbiased_got2(%r6)
#elif defined(OF_BASEREL)
	addis	%r6, %r13, objc_taggedPointerClasses@drel@ha
	addi	%r6, %r6, objc_taggedPointerClasses@drel@l
#else
	lis	%r6, objc_taggedPointerClasses@ha
	addi	%r6, %r6, objc_taggedPointerClasses@l
#endif
	lwzx	%r5, %r6, %r5
	lwz	%r5, 32(%r5)

	b	.Lmain_\name
.type \name, @function
.size \name, .-\name
.endm

.macro GENERATE_LOOKUP_SUPER name lookup
\name:
	mr	%r5, %r3
	lwz	%r3, 0(%r3)
	cmpwi	%r3, 0
	beq-	returnNilMethod

	lwz	%r5, 4(%r5)
	lwz	%r5, 32(%r5)

	b	.Lmain_\lookup
.type \name, @function
.size \name, .-\name
.endm

GENERATE_LOOKUP objc_msg_lookup objc_methodNotFound
GENERATE_LOOKUP objc_msg_lookup_stret objc_methodNotFound_stret
GENERATE_LOOKUP_SUPER objc_msg_lookup_super objc_msg_lookup
GENERATE_LOOKUP_SUPER objc_msg_lookup_super_stret objc_msg_lookup_stret

returnNilMethod:
	mflr	%r0
	bl	getPC
	mtlr	%r0
0:
	addi	%r3, %r3, nilMethod-0b
	blr

nilMethod:
	li	%r3, 0
	blr

getPC:
	mflr	%r3
	blr

#ifdef OF_PIC
.section .got2, "aw"
.Lbiased_got2 = .+0x8000
.Lgot_objc_methodNotFound:
	.long objc_methodNotFound
.Lgot_objc_methodNotFound_stret:
	.long objc_methodNotFound_stret
.Lgot_objc_taggedPointerSecret:
	.long objc_taggedPointerSecret
.Lgot_objc_taggedPointerClasses:
	.long objc_taggedPointerClasses
#endif

#ifdef OF_LINUX
.section .note.GNU-stack, "", @progbits
#endif

Modified src/runtime/lookup-asm/lookup-asm-sparc-elf.S from [97ba2c63db] to [c6e8c65e49].

19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

.globl objc_msg_lookup
.globl objc_msg_lookup_stret
.globl objc_msg_lookup_super
.globl objc_msg_lookup_super_stret

.section .text
.macro generate_lookup name not_found
\name:
	tst	%o0
	bz	ret_nil
	 btst	1, %o0
	bnz	.Ltagged_pointer_\name	
	 nop

	ld	[%o0], %o2
	ld	[%o2 + 32], %o2

.Lmain_\name:
#ifdef OF_SELUID24







|


|

|







19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

.globl objc_msg_lookup
.globl objc_msg_lookup_stret
.globl objc_msg_lookup_super
.globl objc_msg_lookup_super_stret

.section .text
.macro GENERATE_LOOKUP name notFound
\name:
	tst	%o0
	bz	returnNilMethod
	 btst	1, %o0
	bnz	.LtaggedPointer_\name	
	 nop

	ld	[%o0], %o2
	ld	[%o2 + 32], %o2

.Lmain_\name:
#ifdef OF_SELUID24
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
	 nop

	retl
	 mov	%o2, %o0

0:
	mov	%o7, %g1
	call	\not_found
	 mov	%g1, %o7

.Ltagged_pointer_\name:
#ifdef OF_PIC
	mov	%o7, %g1
	sethi	%hi(_GLOBAL_OFFSET_TABLE_ - 4), %o3
	call	0f
	 or	%o3, %lo(_GLOBAL_OFFSET_TABLE_ + 4), %o3
0:
	add	%o7, %o3, %o3
	mov	%g1, %o7
#endif

	sethi	%hi(objc_tagged_pointer_secret), %o2
	or	%o2, %lo(objc_tagged_pointer_secret), %o2
#ifdef OF_PIC
	ld	[%o3 + %o2], %o2
#endif
	ld	[%o2], %o2
	xor	%o0, %o2, %o0
	and	%o0, 0xE, %o0
	sll	%o0, 1, %o0

	sethi	%hi(objc_tagged_pointer_classes), %o2
	or	%o2, %lo(objc_tagged_pointer_classes), %o2
#ifdef OF_PIC
	ld	[%o3 + %o2], %o2
#endif

	ld	[%o2 + %o0], %o2
	ba	.Lmain_\name
	 ld	[%o2 + 32], %o2
.type \name, %function
.size \name, .-\name
.endm

.macro generate_lookup_super name lookup
\name:
	mov	%o0, %o2
	ld	[%o0], %o0
	cmp	%o0, 0
	be	ret_nil
	 nop

	ld	[%o2 + 4], %o2
	ba	.Lmain_\lookup
	 ld	[%o2 + 32], %o2
.type \name, %function
.size \name, .-\name
.endm

generate_lookup objc_msg_lookup objc_method_not_found
generate_lookup objc_msg_lookup_stret objc_method_not_found_stret
generate_lookup_super objc_msg_lookup_super objc_msg_lookup
generate_lookup_super objc_msg_lookup_super_stret objc_msg_lookup_stret

ret_nil:
#ifdef OF_PIC
	mov	%o7, %g1

	sethi	%hi(_GLOBAL_OFFSET_TABLE_ - 4), %o1
	call	0f
	 add	%o1, %lo(_GLOBAL_OFFSET_TABLE_ + 4), %o1
0:
	add	%o7, %o1, %o1

	sethi	%hi(nil_method), %o0
	or	%o0, %lo(nil_method), %o0

	jmpl	%g1 + 8, %g0
	 ld	[%o1 + %o0], %o0
#else
	sethi	%hi(nil_method), %o0
	retl
	 or	%o0, %lo(nil_method), %o0
#endif

nil_method:
	retl
	 clr	%o0

#ifdef OF_LINUX
.section .note.GNU-stack, "", %progbits
#endif







|


|










|
|








|
|











|




|









|
|
|
|

|









|
|




|

|


|






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
	 nop

	retl
	 mov	%o2, %o0

0:
	mov	%o7, %g1
	call	\notFound
	 mov	%g1, %o7

.LtaggedPointer_\name:
#ifdef OF_PIC
	mov	%o7, %g1
	sethi	%hi(_GLOBAL_OFFSET_TABLE_ - 4), %o3
	call	0f
	 or	%o3, %lo(_GLOBAL_OFFSET_TABLE_ + 4), %o3
0:
	add	%o7, %o3, %o3
	mov	%g1, %o7
#endif

	sethi	%hi(objc_taggedPointerSecret), %o2
	or	%o2, %lo(objc_taggedPointerSecret), %o2
#ifdef OF_PIC
	ld	[%o3 + %o2], %o2
#endif
	ld	[%o2], %o2
	xor	%o0, %o2, %o0
	and	%o0, 0xE, %o0
	sll	%o0, 1, %o0

	sethi	%hi(objc_taggedPointerClasses), %o2
	or	%o2, %lo(objc_taggedPointerClasses), %o2
#ifdef OF_PIC
	ld	[%o3 + %o2], %o2
#endif

	ld	[%o2 + %o0], %o2
	ba	.Lmain_\name
	 ld	[%o2 + 32], %o2
.type \name, %function
.size \name, .-\name
.endm

.macro GENERATE_LOOKUP_SUPER name lookup
\name:
	mov	%o0, %o2
	ld	[%o0], %o0
	cmp	%o0, 0
	be	returnNilMethod
	 nop

	ld	[%o2 + 4], %o2
	ba	.Lmain_\lookup
	 ld	[%o2 + 32], %o2
.type \name, %function
.size \name, .-\name
.endm

GENERATE_LOOKUP objc_msg_lookup objc_methodNotFound
GENERATE_LOOKUP objc_msg_lookup_stret objc_methodNotFound_stret
GENERATE_LOOKUP_SUPER objc_msg_lookup_super objc_msg_lookup
GENERATE_LOOKUP_SUPER objc_msg_lookup_super_stret objc_msg_lookup_stret

returnNilMethod:
#ifdef OF_PIC
	mov	%o7, %g1

	sethi	%hi(_GLOBAL_OFFSET_TABLE_ - 4), %o1
	call	0f
	 add	%o1, %lo(_GLOBAL_OFFSET_TABLE_ + 4), %o1
0:
	add	%o7, %o1, %o1

	sethi	%hi(nilMethod), %o0
	or	%o0, %lo(nilMethod), %o0

	jmpl	%g1 + 8, %g0
	 ld	[%o1 + %o0], %o0
#else
	sethi	%hi(nilMethod), %o0
	retl
	 or	%o0, %lo(nilMethod), %o0
#endif

nilMethod:
	retl
	 clr	%o0

#ifdef OF_LINUX
.section .note.GNU-stack, "", %progbits
#endif

Modified src/runtime/lookup-asm/lookup-asm-sparc64-elf.S from [f2aa28d73c] to [ddfe4e7ce8].

19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

.globl objc_msg_lookup
.globl objc_msg_lookup_stret
.globl objc_msg_lookup_super
.globl objc_msg_lookup_super_stret

.section .text
.macro generate_lookup name not_found
\name:
	brz,pn	%o0, ret_nil
	 and	%o0, 1, %o2
	brnz,pn	%o2, .Ltagged_pointer_\name
	 nop

	ldx	[%o0], %o2
	ldx	[%o2 + 64], %o2

.Lmain_\name:
#ifdef OF_SELUID24







|

|

|







19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

.globl objc_msg_lookup
.globl objc_msg_lookup_stret
.globl objc_msg_lookup_super
.globl objc_msg_lookup_super_stret

.section .text
.macro GENERATE_LOOKUP name notFound
\name:
	brz,pn	%o0, returnNilMethod
	 and	%o0, 1, %o2
	brnz,pn	%o2, .LtaggedPointer_\name
	 nop

	ldx	[%o0], %o2
	ldx	[%o2 + 64], %o2

.Lmain_\name:
#ifdef OF_SELUID24
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
	 nop

	retl
	 mov	%o2, %o0

0:
	mov	%o7, %g1
	call	\not_found
	 mov	%g1, %o7

.Ltagged_pointer_\name:
#ifdef OF_PIC
	mov	%o7, %g1
	sethi	%hi(_GLOBAL_OFFSET_TABLE_ - 4), %o3
	call	0f
	 or	%o3, %lo(_GLOBAL_OFFSET_TABLE_ + 4), %o3
0:
	add	%o7, %o3, %o3
	mov	%g1, %o7
#endif

	sethi	%hi(objc_tagged_pointer_secret), %o2
	or	%o2, %lo(objc_tagged_pointer_secret), %o2
#ifdef OF_PIC
	ldx	[%o3 + %o2], %o2
#endif
	ldx	[%o2], %o2
	xor	%o0, %o2, %o0
	and	%o0, 0xE, %o0
	sll	%o0, 2, %o0

	sethi	%hi(objc_tagged_pointer_classes), %o2
	or	%o2, %lo(objc_tagged_pointer_classes), %o2
#ifdef OF_PIC
	ldx	[%o3 + %o2], %o2
#endif

	ldx	[%o2 + %o0], %o2
	ba	.Lmain_\name
	 ldx	[%o2 + 64], %o2
.type \name, %function
.size \name, .-\name
.endm

.macro generate_lookup_super name lookup
\name:
	mov	%o0, %o2
	ldx	[%o0], %o0
	brz,pn	%o0, ret_nil
	 nop

	ldx	[%o2 + 8], %o2
	ba	.Lmain_\lookup
	 ldx	[%o2 + 64], %o2
.type \name, %function
.size \name, .-\name
.endm

generate_lookup objc_msg_lookup objc_method_not_found
generate_lookup objc_msg_lookup_stret objc_method_not_found_stret
generate_lookup_super objc_msg_lookup_super objc_msg_lookup
generate_lookup_super objc_msg_lookup_super_stret objc_msg_lookup_stret

ret_nil:
#ifdef OF_PIC
	mov	%o7, %g1

	sethi	%hi(_GLOBAL_OFFSET_TABLE_ - 4), %o1
	call	0f
	 or	%o1, %lo(_GLOBAL_OFFSET_TABLE_ + 4), %o1
0:
	add	%o7, %o1, %o1

	sethi	%hi(nil_method), %o0
	or	%o0, %lo(nil_method), %o0

	jmpl	%g1 + 8, %g0
	 ldx	[%o1 + %o0], %o0
#else
	sethi	%hi(nil_method), %o0
	retl
	 or	%o0, %lo(nil_method), %o0
#endif

nil_method:
	retl
	 clr	%o0

#ifdef OF_LINUX
.section .note.GNU-stack, "", %progbits
#endif







|


|










|
|








|
|











|



|









|
|
|
|

|









|
|




|

|


|






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
	 nop

	retl
	 mov	%o2, %o0

0:
	mov	%o7, %g1
	call	\notFound
	 mov	%g1, %o7

.LtaggedPointer_\name:
#ifdef OF_PIC
	mov	%o7, %g1
	sethi	%hi(_GLOBAL_OFFSET_TABLE_ - 4), %o3
	call	0f
	 or	%o3, %lo(_GLOBAL_OFFSET_TABLE_ + 4), %o3
0:
	add	%o7, %o3, %o3
	mov	%g1, %o7
#endif

	sethi	%hi(objc_taggedPointerSecret), %o2
	or	%o2, %lo(objc_taggedPointerSecret), %o2
#ifdef OF_PIC
	ldx	[%o3 + %o2], %o2
#endif
	ldx	[%o2], %o2
	xor	%o0, %o2, %o0
	and	%o0, 0xE, %o0
	sll	%o0, 2, %o0

	sethi	%hi(objc_taggedPointerClasses), %o2
	or	%o2, %lo(objc_taggedPointerClasses), %o2
#ifdef OF_PIC
	ldx	[%o3 + %o2], %o2
#endif

	ldx	[%o2 + %o0], %o2
	ba	.Lmain_\name
	 ldx	[%o2 + 64], %o2
.type \name, %function
.size \name, .-\name
.endm

.macro GENERATE_LOOKUP_SUPER name lookup
\name:
	mov	%o0, %o2
	ldx	[%o0], %o0
	brz,pn	%o0, returnNilMethod
	 nop

	ldx	[%o2 + 8], %o2
	ba	.Lmain_\lookup
	 ldx	[%o2 + 64], %o2
.type \name, %function
.size \name, .-\name
.endm

GENERATE_LOOKUP objc_msg_lookup objc_methodNotFound
GENERATE_LOOKUP objc_msg_lookup_stret objc_methodNotFound_stret
GENERATE_LOOKUP_SUPER objc_msg_lookup_super objc_msg_lookup
GENERATE_LOOKUP_SUPER objc_msg_lookup_super_stret objc_msg_lookup_stret

returnNilMethod:
#ifdef OF_PIC
	mov	%o7, %g1

	sethi	%hi(_GLOBAL_OFFSET_TABLE_ - 4), %o1
	call	0f
	 or	%o1, %lo(_GLOBAL_OFFSET_TABLE_ + 4), %o1
0:
	add	%o7, %o1, %o1

	sethi	%hi(nilMethod), %o0
	or	%o0, %lo(nilMethod), %o0

	jmpl	%g1 + 8, %g0
	 ldx	[%o1 + %o0], %o0
#else
	sethi	%hi(nilMethod), %o0
	retl
	 or	%o0, %lo(nilMethod), %o0
#endif

nilMethod:
	retl
	 clr	%o0

#ifdef OF_LINUX
.section .note.GNU-stack, "", %progbits
#endif

Modified src/runtime/lookup-asm/lookup-asm-x86-elf.S from [89119220a2] to [584c3797d2].

19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

.globl objc_msg_lookup
.globl objc_msg_lookup_stret
.globl objc_msg_lookup_super
.globl objc_msg_lookup_super_stret

.section .text
.macro generate_lookup name not_found
\name:
	movl	4(%esp), %edx
	testl	%edx, %edx
	jz	ret_nil

	testb	$1, %dl
	jnz	.Ltagged_pointer_\name

	movl	(%edx), %edx
	movl	32(%edx), %edx

.Lmain_\name:
	movl	8(%esp), %eax








|



|


|







19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

.globl objc_msg_lookup
.globl objc_msg_lookup_stret
.globl objc_msg_lookup_super
.globl objc_msg_lookup_super_stret

.section .text
.macro GENERATE_LOOKUP name notFound
\name:
	movl	4(%esp), %edx
	testl	%edx, %edx
	jz	returnNilMethod

	testb	$1, %dl
	jnz	.LtaggedPointer_\name

	movl	(%edx), %edx
	movl	32(%edx), %edx

.Lmain_\name:
	movl	8(%esp), %eax

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

	testl	%eax, %eax
	jz	0f

	ret

0:
	call	get_eip
	addl	$_GLOBAL_OFFSET_TABLE_, %eax
	lea	\not_found@GOTOFF(%eax), %eax
	jmp	*%eax

.Ltagged_pointer_\name:
	call	get_eip
	addl	$_GLOBAL_OFFSET_TABLE_, %eax

	leal	objc_tagged_pointer_secret@GOTOFF(%eax), %ecx
	xorl	(%ecx), %edx
	andb	$0xE, %dl
	movzbl	%dl, %edx

	leal	objc_tagged_pointer_classes@GOTOFF(%eax), %eax
	movl	(%eax,%edx,2), %edx
	movl	32(%edx), %edx

	jmp	.Lmain_\name
.type \name, %function
.size \name, .-\name
.endm

.macro generate_lookup_super name lookup
\name:
	movl	4(%esp), %edx
	movl	(%edx), %eax
	testl	%eax, %eax
	jz	ret_nil

	movl	%eax, 4(%esp)
	mov	4(%edx), %edx
	mov	32(%edx), %edx
	jmp	.Lmain_\lookup
.type \name, %function
.size \name, .-\name
.endm

generate_lookup objc_msg_lookup objc_method_not_found
generate_lookup objc_msg_lookup_stret objc_method_not_found_stret
generate_lookup_super objc_msg_lookup_super objc_msg_lookup
generate_lookup_super objc_msg_lookup_super_stret objc_msg_lookup_stret

ret_nil:
	call	get_eip
	addl	$_GLOBAL_OFFSET_TABLE_, %eax
	leal	nil_method@GOTOFF(%eax), %eax
	ret

nil_method:
	xorl	%eax, %eax
	ret

get_eip:
	movl	(%esp), %eax
	ret

#ifdef OF_LINUX
.section .note.GNU-stack, "", %progbits
#endif







|

|


|
|


|




|








|




|









|
|
|
|

|
|

|


|



|






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

	testl	%eax, %eax
	jz	0f

	ret

0:
	call	getEIP
	addl	$_GLOBAL_OFFSET_TABLE_, %eax
	lea	\notFound@GOTOFF(%eax), %eax
	jmp	*%eax

.LtaggedPointer_\name:
	call	getEIP
	addl	$_GLOBAL_OFFSET_TABLE_, %eax

	leal	objc_taggedPointerSecret@GOTOFF(%eax), %ecx
	xorl	(%ecx), %edx
	andb	$0xE, %dl
	movzbl	%dl, %edx

	leal	objc_taggedPointerClasses@GOTOFF(%eax), %eax
	movl	(%eax,%edx,2), %edx
	movl	32(%edx), %edx

	jmp	.Lmain_\name
.type \name, %function
.size \name, .-\name
.endm

.macro GENERATE_LOOKUP_SUPER name lookup
\name:
	movl	4(%esp), %edx
	movl	(%edx), %eax
	testl	%eax, %eax
	jz	returnNilMethod

	movl	%eax, 4(%esp)
	mov	4(%edx), %edx
	mov	32(%edx), %edx
	jmp	.Lmain_\lookup
.type \name, %function
.size \name, .-\name
.endm

GENERATE_LOOKUP objc_msg_lookup objc_methodNotFound
GENERATE_LOOKUP objc_msg_lookup_stret objc_methodNotFound_stret
GENERATE_LOOKUP_SUPER objc_msg_lookup_super objc_msg_lookup
GENERATE_LOOKUP_SUPER objc_msg_lookup_super_stret objc_msg_lookup_stret

returnNilMethod:
	call	getEIP
	addl	$_GLOBAL_OFFSET_TABLE_, %eax
	leal	nilMethod@GOTOFF(%eax), %eax
	ret

nilMethod:
	xorl	%eax, %eax
	ret

getEIP:
	movl	(%esp), %eax
	ret

#ifdef OF_LINUX
.section .note.GNU-stack, "", %progbits
#endif

Modified src/runtime/lookup-asm/lookup-asm-x86-win32.S from [e53fa327a6] to [82a8f4610f].

17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96

.globl _objc_msg_lookup
.globl _objc_msg_lookup_stret
.globl _objc_msg_lookup_super
.globl _objc_msg_lookup_super_stret

.section .text
.macro generate_lookup name not_found
\name:
	movl	4(%esp), %edx
	testl	%edx, %edx
	jz	ret_nil

	testb	$1, %dl
	jnz	.Ltagged_pointer_\name

	movl	(%edx), %edx
	movl	32(%edx), %edx

.Lmain_\name:
	movl	8(%esp), %eax

#ifdef OF_SELUID24
	movzbl	2(%eax), %ecx
	movl	(%edx,%ecx,4), %edx
#endif
	movzbl	1(%eax), %ecx
	movl	(%edx,%ecx,4), %edx
	movzbl	(%eax), %ecx
	movl	(%edx,%ecx,4), %eax

	testl	%eax, %eax
	jz	\not_found

	ret

.Ltagged_pointer_\name:
	xorl	_objc_tagged_pointer_secret, %edx
	andb	$0xE, %dl
	movzbl	%dl, %edx

	movl	_objc_tagged_pointer_classes(,%edx,2), %edx
	movl	32(%edx), %edx

	jmp	.Lmain_\name
.def \name
.scl 2
.type 32
.endef
.endm

.macro generate_lookup_super name lookup
\name:
	movl	4(%esp), %edx
	movl	(%edx), %eax
	test	%eax, %eax
	jz	ret_nil

	movl	%eax, 4(%esp)
	movl	4(%edx), %edx
	movl	32(%edx), %edx
	jmp	.Lmain_\lookup
.def \name
.scl 2
.type 32
.endef
.endm

generate_lookup _objc_msg_lookup _objc_method_not_found
generate_lookup _objc_msg_lookup_stret _objc_method_not_found_stret
generate_lookup_super _objc_msg_lookup_super _objc_msg_lookup
generate_lookup_super _objc_msg_lookup_super_stret _objc_msg_lookup_stret

ret_nil:
	movl	$nil_method, %eax
	ret

nil_method:
	xorl	%eax, %eax
	ret







|



|


|

















|



|
|



|









|




|











|
|
|
|

|
|


|


17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96

.globl _objc_msg_lookup
.globl _objc_msg_lookup_stret
.globl _objc_msg_lookup_super
.globl _objc_msg_lookup_super_stret

.section .text
.macro GENERATE_LOOKUP name notFound
\name:
	movl	4(%esp), %edx
	testl	%edx, %edx
	jz	returnNilMethod

	testb	$1, %dl
	jnz	.LtaggedPointer_\name

	movl	(%edx), %edx
	movl	32(%edx), %edx

.Lmain_\name:
	movl	8(%esp), %eax

#ifdef OF_SELUID24
	movzbl	2(%eax), %ecx
	movl	(%edx,%ecx,4), %edx
#endif
	movzbl	1(%eax), %ecx
	movl	(%edx,%ecx,4), %edx
	movzbl	(%eax), %ecx
	movl	(%edx,%ecx,4), %eax

	testl	%eax, %eax
	jz	\notFound

	ret

.LtaggedPointer_\name:
	xorl	_objc_taggedPointerSecret, %edx
	andb	$0xE, %dl
	movzbl	%dl, %edx

	movl	_objc_taggedPointerClasses(,%edx,2), %edx
	movl	32(%edx), %edx

	jmp	.Lmain_\name
.def \name
.scl 2
.type 32
.endef
.endm

.macro GENERATE_LOOKUP_SUPER name lookup
\name:
	movl	4(%esp), %edx
	movl	(%edx), %eax
	test	%eax, %eax
	jz	returnNilMethod

	movl	%eax, 4(%esp)
	movl	4(%edx), %edx
	movl	32(%edx), %edx
	jmp	.Lmain_\lookup
.def \name
.scl 2
.type 32
.endef
.endm

GENERATE_LOOKUP _objc_msg_lookup _objc_methodNotFound
GENERATE_LOOKUP _objc_msg_lookup_stret _objc_methodNotFound_stret
GENERATE_LOOKUP_SUPER _objc_msg_lookup_super _objc_msg_lookup
GENERATE_LOOKUP_SUPER _objc_msg_lookup_super_stret _objc_msg_lookup_stret

returnNilMethod:
	movl	$nilMethod, %eax
	ret

nilMethod:
	xorl	%eax, %eax
	ret

Modified src/runtime/lookup-asm/lookup-asm-x86_64-elf.S from [e0cdb81196] to [a4b34307ef].

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

.globl objc_msg_lookup
.globl objc_msg_lookup_stret
.globl objc_msg_lookup_super
.globl objc_msg_lookup_super_stret

.section .text
.macro generate_lookup name not_found
\name:
	testq	%rdi, %rdi
	jz	ret_nil

	testb	$1, %dil
	jnz	.Ltagged_pointer_\name

	movq	(%rdi), %r8
	movq	64(%r8), %r8

.Lmain_\name:
	movq	(%rsi), %rax
	movzbl	%ah, %ecx
	movzbl	%al, %edx
#ifdef OF_SELUID24
	shrl	$16, %eax

	movq	(%r8,%rax,8), %r8
#endif
	movq	(%r8,%rcx,8), %r8
	movq	(%r8,%rdx,8), %rax

	testq	%rax, %rax
	jz	\not_found@PLT

	ret

.Ltagged_pointer_\name:
	movq	objc_tagged_pointer_secret@GOTPCREL(%rip), %rax
	xorq	(%rax), %rdi
	andb	$0xE, %dil
	movzbl	%dil, %r8d

	movq	objc_tagged_pointer_classes@GOTPCREL(%rip), %rax
	movq	(%rax,%r8,4), %r8
	movq	64(%r8), %r8

	jmp	.Lmain_\name
.type \name, %function
.size \name, .-\name
.endm

.macro generate_lookup_super name lookup
\name:
	movq	%rdi, %r8
	movq	(%rdi), %rdi
	testq	%rdi, %rdi
	jz	ret_nil

	movq	8(%r8), %r8
	movq	64(%r8), %r8
	jmp	.Lmain_\lookup
.type \name, %function
.size \name, .-\name
.endm

generate_lookup objc_msg_lookup objc_method_not_found
generate_lookup objc_msg_lookup_stret objc_method_not_found_stret
generate_lookup_super objc_msg_lookup_super objc_msg_lookup
generate_lookup_super objc_msg_lookup_super_stret objc_msg_lookup_stret

ret_nil:
	leaq	nil_method(%rip), %rax
	ret

nil_method:
	xorq	%rax, %rax
	ret

#ifdef OF_LINUX
.section .note.GNU-stack, "", %progbits
#endif







|


|


|

















|



|
|




|








|




|








|
|
|
|

|
|


|






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

.globl objc_msg_lookup
.globl objc_msg_lookup_stret
.globl objc_msg_lookup_super
.globl objc_msg_lookup_super_stret

.section .text
.macro GENERATE_LOOKUP name notFound
\name:
	testq	%rdi, %rdi
	jz	returnNilMethod

	testb	$1, %dil
	jnz	.LtaggedPointer_\name

	movq	(%rdi), %r8
	movq	64(%r8), %r8

.Lmain_\name:
	movq	(%rsi), %rax
	movzbl	%ah, %ecx
	movzbl	%al, %edx
#ifdef OF_SELUID24
	shrl	$16, %eax

	movq	(%r8,%rax,8), %r8
#endif
	movq	(%r8,%rcx,8), %r8
	movq	(%r8,%rdx,8), %rax

	testq	%rax, %rax
	jz	\notFound@PLT

	ret

.LtaggedPointer_\name:
	movq	objc_taggedPointerSecret@GOTPCREL(%rip), %rax
	xorq	(%rax), %rdi
	andb	$0xE, %dil
	movzbl	%dil, %r8d

	movq	objc_taggedPointerClasses@GOTPCREL(%rip), %rax
	movq	(%rax,%r8,4), %r8
	movq	64(%r8), %r8

	jmp	.Lmain_\name
.type \name, %function
.size \name, .-\name
.endm

.macro GENERATE_LOOKUP_SUPER name lookup
\name:
	movq	%rdi, %r8
	movq	(%rdi), %rdi
	testq	%rdi, %rdi
	jz	returnNilMethod

	movq	8(%r8), %r8
	movq	64(%r8), %r8
	jmp	.Lmain_\lookup
.type \name, %function
.size \name, .-\name
.endm

GENERATE_LOOKUP objc_msg_lookup objc_methodNotFound
GENERATE_LOOKUP objc_msg_lookup_stret objc_methodNotFound_stret
GENERATE_LOOKUP_SUPER objc_msg_lookup_super objc_msg_lookup
GENERATE_LOOKUP_SUPER objc_msg_lookup_super_stret objc_msg_lookup_stret

returnNilMethod:
	leaq	nilMethod(%rip), %rax
	ret

nilMethod:
	xorq	%rax, %rax
	ret

#ifdef OF_LINUX
.section .note.GNU-stack, "", %progbits
#endif

Modified src/runtime/lookup-asm/lookup-asm-x86_64-macho.S from [30cd6d5c1f] to [75f4b5e2f7].

17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

.globl _objc_msg_lookup
.globl _objc_msg_lookup_stret
.globl _objc_msg_lookup_super
.globl _objc_msg_lookup_super_stret

.section __TEXT, __text, regular, pure_instructions
.macro generate_lookup
$0:
	testq	%rdi, %rdi
	jz	ret_nil

	testb	$$1, %dil
	jnz	Ltagged_pointer_$0

	movq	(%rdi), %r8
	movq	64(%r8), %r8

Lmain_$0:
	movq	(%rsi), %rax
	movzbl	%ah, %ecx







|


|


|







17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

.globl _objc_msg_lookup
.globl _objc_msg_lookup_stret
.globl _objc_msg_lookup_super
.globl _objc_msg_lookup_super_stret

.section __TEXT, __text, regular, pure_instructions
.macro GENERATE_LOOKUP
$0:
	testq	%rdi, %rdi
	jz	returnNilMethod

	testb	$$1, %dil
	jnz	LtaggedPointer_$0

	movq	(%rdi), %r8
	movq	64(%r8), %r8

Lmain_$0:
	movq	(%rsi), %rax
	movzbl	%ah, %ecx
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
	movq	(%r8,%rdx,8), %rax

	testq	%rax, %rax
	jz	$1

	ret

Ltagged_pointer_$0:
	movq	_objc_tagged_pointer_secret@GOTPCREL(%rip), %rax
	xorq	(%rax), %rdi
	andb	$$0xE, %dil
	movzbl	%dil, %r8d

	movq	_objc_tagged_pointer_classes@GOTPCREL(%rip), %rax
	movq	(%rax,%r8,4), %r8
	movq	64(%r8), %r8

	jmp	Lmain_$0
.endmacro

.macro generate_lookup_super
$0:
	movq	%rdi, %r8
	movq	(%rdi), %rdi
	testq	%rdi, %rdi
	jz	ret_nil

	movq	8(%r8), %r8
	movq	64(%r8), %r8
	jmp	Lmain_$1
.endmacro

generate_lookup _objc_msg_lookup, _objc_method_not_found
generate_lookup _objc_msg_lookup_stret, _objc_method_not_found_stret
generate_lookup_super _objc_msg_lookup_super, _objc_msg_lookup
generate_lookup_super _objc_msg_lookup_super_stret, _objc_msg_lookup_stret

ret_nil:
	leaq	nil_method(%rip), %rax
	ret

nil_method:
	xorq	%rax, %rax
	ret







|
|




|






|




|






|
|
|
|

|
|


|


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
	movq	(%r8,%rdx,8), %rax

	testq	%rax, %rax
	jz	$1

	ret

LtaggedPointer_$0:
	movq	_objc_taggedPointerSecret@GOTPCREL(%rip), %rax
	xorq	(%rax), %rdi
	andb	$$0xE, %dil
	movzbl	%dil, %r8d

	movq	_objc_taggedPointerClasses@GOTPCREL(%rip), %rax
	movq	(%rax,%r8,4), %r8
	movq	64(%r8), %r8

	jmp	Lmain_$0
.endmacro

.macro GENERATE_LOOKUP_SUPER
$0:
	movq	%rdi, %r8
	movq	(%rdi), %rdi
	testq	%rdi, %rdi
	jz	returnNilMethod

	movq	8(%r8), %r8
	movq	64(%r8), %r8
	jmp	Lmain_$1
.endmacro

GENERATE_LOOKUP _objc_msg_lookup, _objc_methodNotFound
GENERATE_LOOKUP _objc_msg_lookup_stret, _objc_methodNotFound_stret
GENERATE_LOOKUP_SUPER _objc_msg_lookup_super, _objc_msg_lookup
GENERATE_LOOKUP_SUPER _objc_msg_lookup_super_stret, _objc_msg_lookup_stret

returnNilMethod:
	leaq	nilMethod(%rip), %rax
	ret

nilMethod:
	xorq	%rax, %rax
	ret

Modified src/runtime/lookup-asm/lookup-asm-x86_64-win64.S from [57823d1901] to [bc3f6ee83e].

17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

.globl objc_msg_lookup
.globl objc_msg_lookup_stret
.globl objc_msg_lookup_super
.globl objc_msg_lookup_super_stret

.section .text
.macro generate_lookup name not_found
\name:
	testq	%rcx, %rcx
	jz	ret_nil

	testb	$1, %cl
	jnz	.Ltagged_pointer_\name

	movq	(%rcx), %r8
	movq	56(%r8), %r8

.Lmain_\name:
	movq	%rcx, %r10
	movq	%rdx, %r11







|


|


|







17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

.globl objc_msg_lookup
.globl objc_msg_lookup_stret
.globl objc_msg_lookup_super
.globl objc_msg_lookup_super_stret

.section .text
.macro GENERATE_LOOKUP name notFound
\name:
	testq	%rcx, %rcx
	jz	returnNilMethod

	testb	$1, %cl
	jnz	.LtaggedPointer_\name

	movq	(%rcx), %r8
	movq	56(%r8), %r8

.Lmain_\name:
	movq	%rcx, %r10
	movq	%rdx, %r11
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
	jz	0f

	ret

0:
	movq	%r10, %rcx
	movq	%r11, %rdx
	jmp	\not_found

.Ltagged_pointer_\name:
	xorq	objc_tagged_pointer_secret(%rip), %rcx
	andb	$0xE, %cl
	movzbl	%cl, %r8d

	leaq	objc_tagged_pointer_classes(%rip), %rax
	movq	(%rax,%r8,4), %r8
	movq	56(%r8), %r8

	jmp	.Lmain_\name
.def \name
.scl 2
.type 32
.endef
.endm

.macro generate_lookup_super name lookup
\name:
	movq	%rcx, %r8
	movq	(%rcx), %rcx
	testq	%rcx, %rcx
	jz	ret_nil

	movq	8(%r8), %r8
	movq	56(%r8), %r8
	jmp	.Lmain_\lookup
.def \name
.scl 2
.type 32
.endef
.endm

generate_lookup objc_msg_lookup objc_method_not_found
generate_lookup objc_msg_lookup_stret objc_method_not_found_stret
generate_lookup_super objc_msg_lookup_super objc_msg_lookup
generate_lookup_super objc_msg_lookup_super_stret objc_msg_lookup_stret

ret_nil:
	leaq	nil_method(%rip), %rax
	ret

nil_method:
	xorq	%rax, %rax
	ret







|

|
|



|










|




|










|
|
|
|

|
|


|


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
	jz	0f

	ret

0:
	movq	%r10, %rcx
	movq	%r11, %rdx
	jmp	\notFound

.LtaggedPointer_\name:
	xorq	objc_taggedPointerSecret(%rip), %rcx
	andb	$0xE, %cl
	movzbl	%cl, %r8d

	leaq	objc_taggedPointerClasses(%rip), %rax
	movq	(%rax,%r8,4), %r8
	movq	56(%r8), %r8

	jmp	.Lmain_\name
.def \name
.scl 2
.type 32
.endef
.endm

.macro GENERATE_LOOKUP_SUPER name lookup
\name:
	movq	%rcx, %r8
	movq	(%rcx), %rcx
	testq	%rcx, %rcx
	jz	returnNilMethod

	movq	8(%r8), %r8
	movq	56(%r8), %r8
	jmp	.Lmain_\lookup
.def \name
.scl 2
.type 32
.endef
.endm

GENERATE_LOOKUP objc_msg_lookup objc_methodNotFound
GENERATE_LOOKUP objc_msg_lookup_stret objc_methodNotFound_stret
GENERATE_LOOKUP_SUPER objc_msg_lookup_super objc_msg_lookup
GENERATE_LOOKUP_SUPER objc_msg_lookup_super_stret objc_msg_lookup_stret

returnNilMethod:
	leaq	nilMethod(%rip), %rax
	ret

nilMethod:
	xorq	%rax, %rax
	ret

Modified src/runtime/lookup.m from [041b8ab433] to [d4c41afde5].

37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
	bool isClass =
	    object_getClass(object)->info & OBJC_CLASS_INFO_METACLASS;

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

		objc_initialize_class(class);

		if (!(class->info & OBJC_CLASS_INFO_SETUP))
			OBJC_ERROR("Could not dispatch message for incomplete "
			    "class %s!", class_getName(class));

		/*
		 * We don't need to handle the case that super was called.







|







37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
	bool isClass =
	    object_getClass(object)->info & OBJC_CLASS_INFO_METACLASS;

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

		objc_initializeClass(class);

		if (!(class->info & OBJC_CLASS_INFO_SETUP))
			OBJC_ERROR("Could not dispatch message for incomplete "
			    "class %s!", class_getName(class));

		/*
		 * We don't need to handle the case that super was called.
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

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

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

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

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

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

	return (objc_dtable_get(class->DTable,
	    (uint32_t)selector->UID) != (IMP)0);
}

#ifndef OF_ASM_LOOKUP
static id
nilMethod(id self, SEL _cmd)
{







|






|


















|







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

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

IMP
objc_methodNotFound(id object, SEL selector)
{
	return commonMethodNotFound(object, selector, objc_msg_lookup,
	    forwardHandler);
}

IMP
objc_methodNotFound_stret(id object, SEL selector)
{
	return commonMethodNotFound(object, selector, objc_msg_lookup_stret,
	    stretForwardHandler);
}

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

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

	return (objc_dtable_get(class->dTable,
	    (uint32_t)selector->UID) != (IMP)0);
}

#ifndef OF_ASM_LOOKUP
static id
nilMethod(id self, SEL _cmd)
{

Modified src/runtime/method.m from [be8bb331cc] to [f36033e5e6].

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
	if (class == Nil) {
		if (outCount != NULL)
			*outCount = 0;

		return NULL;
	}

	objc_global_mutex_lock();

	count = 0;
	for (iter = class->methodList; iter != NULL; iter = iter->next)
		count += iter->count;

	if (count == 0) {
		if (outCount != NULL)
			*outCount = 0;

		objc_global_mutex_unlock();
		return NULL;
	}

	if ((methods = malloc((count + 1) * sizeof(Method))) == NULL)
		OBJC_ERROR("Not enough memory to copy methods");

	i = 0;
	for (iter = class->methodList; iter != NULL; iter = iter->next)
		for (unsigned int j = 0; j < iter->count; j++)
			methods[i++] = &iter->methods[j];
	OFEnsure(i == count);
	methods[count] = NULL;

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

	objc_global_mutex_unlock();

	return methods;
}

SEL
method_getName(Method method)
{







|









|
















|







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
	if (class == Nil) {
		if (outCount != NULL)
			*outCount = 0;

		return NULL;
	}

	objc_globalMutex_lock();

	count = 0;
	for (iter = class->methodList; iter != NULL; iter = iter->next)
		count += iter->count;

	if (count == 0) {
		if (outCount != NULL)
			*outCount = 0;

		objc_globalMutex_unlock();
		return NULL;
	}

	if ((methods = malloc((count + 1) * sizeof(Method))) == NULL)
		OBJC_ERROR("Not enough memory to copy methods");

	i = 0;
	for (iter = class->methodList; iter != NULL; iter = iter->next)
		for (unsigned int j = 0; j < iter->count; j++)
			methods[i++] = &iter->methods[j];
	OFEnsure(i == count);
	methods[count] = NULL;

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

	objc_globalMutex_unlock();

	return methods;
}

SEL
method_getName(Method method)
{

Modified src/runtime/misc.m from [60d087e2ac] to [45165f1a7f].

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 __NOLIBBASE__
# define Class IntuitionClass
# include <proto/intuition.h>
# undef Class
# undef __NOLIBBASE__
#endif

static objc_enumeration_mutation_handler_t enumerationMutationHandler = NULL;

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

void
objc_setEnumerationMutationHandler(objc_enumeration_mutation_handler_t handler)
{
	enumerationMutationHandler = handler;
}

void
objc_error(const char *title, const char *format, ...)
{
#if defined(OF_WINDOWS) || defined(OF_AMIGAOS)
# define BUF_LEN 512
	char message[BUF_LEN];
	int status;
	va_list args;

	va_start(args, format);
	status = vsnprintf(message, BUF_LEN, format, args);
	if (status <= 0 || status >= BUF_LEN)
		message[0] = '\0';
	va_end(args);
# undef BUF_LEN
#endif

#if defined(OF_WINDOWS)
	fprintf(stderr, "[%s] %s\n", title, message);







|











|








|
|




|
|







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 __NOLIBBASE__
# define Class IntuitionClass
# include <proto/intuition.h>
# undef Class
# undef __NOLIBBASE__
#endif

static objc_enumeration_mutation_handler enumerationMutationHandler = NULL;

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

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

void
objc_error(const char *title, const char *format, ...)
{
#if defined(OF_WINDOWS) || defined(OF_AMIGAOS)
# define messageLen 512
	char message[messageLen];
	int status;
	va_list args;

	va_start(args, format);
	status = vsnprintf(message, messageLen, format, args);
	if (status <= 0 || status >= messageLen)
		message[0] = '\0';
	va_end(args);
# undef BUF_LEN
#endif

#if defined(OF_WINDOWS)
	fprintf(stderr, "[%s] %s\n", title, message);

Modified src/runtime/private.h from [13fad70e4b] to [133858e63f].

36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
	Class _Nullable superclass;
	const char *_Nonnull name;
	unsigned long version;
	unsigned long info;
	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 GCObjectType;
	unsigned long ABIVersion;
	int32_t *_Nonnull *_Nullable ivarOffsets;
	struct objc_property_list *_Nullable propertyList;







|







36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
	Class _Nullable superclass;
	const char *_Nonnull name;
	unsigned long version;
	unsigned long info;
	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 GCObjectType;
	unsigned long ABIVersion;
	int32_t *_Nonnull *_Nullable ivarOffsets;
	struct objc_property_list *_Nullable propertyList;
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
	struct objc_hashtable_bucket *_Nonnull *_Nullable data;
};

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

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







|







197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
	struct objc_hashtable_bucket *_Nonnull *_Nullable data;
};

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

struct objc_dtable {
	struct objc_dtable_level2 {
#ifdef OF_SELUID24
		struct objc_dtable_level3 {
			IMP _Nullable buckets[256];
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
	__gnu_objc_personality_sj0(version, actions, *exClass, ex, ctx)
# else
#  define __gnu_objc_personality(version, actions, exClass, ex, ctx)	\
	__gnu_objc_personality_v0(version, actions, *exClass, ex, ctx)
# endif
#endif

extern void objc_register_all_categories(struct objc_symtab *_Nonnull);
extern struct objc_category *_Nullable *_Nullable
    objc_categories_for_class(Class _Nonnull);
extern void objc_unregister_all_categories(void);
extern void objc_initialize_class(Class _Nonnull);
extern void objc_update_dtable(Class _Nonnull);
extern void objc_register_all_classes(struct objc_symtab *_Nonnull);
extern Class _Nullable objc_classname_to_class(const char *_Nonnull, bool);
extern void objc_unregister_class(Class _Nonnull);
extern void objc_unregister_all_classes(void);
extern uint32_t objc_hash_string(const void *_Nonnull);
extern bool objc_equal_string(const void *_Nonnull, const void *_Nonnull);
extern struct objc_hashtable *_Nonnull objc_hashtable_new(
    objc_hashtable_hash_func, objc_hashtable_equal_func, uint32_t);
extern struct objc_hashtable_bucket objc_deleted_bucket;
extern void objc_hashtable_set(struct objc_hashtable *_Nonnull,
    const void *_Nonnull, const void *_Nonnull);
extern void *_Nullable objc_hashtable_get(struct objc_hashtable *_Nonnull,
    const void *_Nonnull);
extern void objc_hashtable_delete(struct objc_hashtable *_Nonnull,
    const void *_Nonnull);
extern void objc_hashtable_free(struct objc_hashtable *_Nonnull);
extern void objc_register_selector(struct objc_selector *_Nonnull);
extern void objc_register_all_selectors(struct objc_symtab *_Nonnull);
extern void objc_unregister_all_selectors(void);
extern struct objc_sparsearray *_Nonnull objc_sparsearray_new(uint8_t);
extern void *_Nullable objc_sparsearray_get(struct objc_sparsearray *_Nonnull,
    uintptr_t);
extern void objc_sparsearray_set(struct objc_sparsearray *_Nonnull, uintptr_t,
    void *_Nullable);
extern void objc_sparsearray_free(struct objc_sparsearray *_Nonnull);
extern struct objc_dtable *_Nonnull objc_dtable_new(void);
extern void objc_dtable_copy(struct objc_dtable *_Nonnull,
    struct objc_dtable *_Nonnull);
extern void objc_dtable_set(struct objc_dtable *_Nonnull, uint32_t,
    IMP _Nullable);
extern void objc_dtable_free(struct objc_dtable *_Nonnull);
extern void objc_dtable_cleanup(void);
extern void objc_init_static_instances(struct objc_symtab *_Nonnull);
extern void objc_forget_pending_static_instances(void);
extern void objc_zero_weak_references(id _Nonnull);
extern Class _Nullable object_getTaggedPointerClass(id _Nonnull);
#ifdef OF_HAVE_THREADS
extern void objc_global_mutex_lock(void);
extern void objc_global_mutex_unlock(void);
extern void objc_global_mutex_free(void);
#else
# define objc_global_mutex_lock()
# define objc_global_mutex_unlock()
# define objc_global_mutex_free()
#endif
extern char *_Nullable objc_strdup(const char *_Nonnull string);

static inline IMP _Nullable
objc_dtable_get(const struct objc_dtable *_Nonnull dtable, uint32_t idx)
{
#ifdef OF_SELUID24







|

|
|
|
|
|
|
|
|
|
|


|







|
|
|













|
|
|


|
|
|

|
|
|







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
	__gnu_objc_personality_sj0(version, actions, *exClass, ex, ctx)
# else
#  define __gnu_objc_personality(version, actions, exClass, ex, ctx)	\
	__gnu_objc_personality_v0(version, actions, *exClass, ex, ctx)
# endif
#endif

extern void objc_registerAllCategories(struct objc_symtab *_Nonnull);
extern struct objc_category *_Nullable *_Nullable
    objc_categoriesForClass(Class _Nonnull);
extern void objc_unregisterAllCategories(void);
extern void objc_initializeClass(Class _Nonnull);
extern void objc_updateDTable(Class _Nonnull);
extern void objc_registerAllClasses(struct objc_symtab *_Nonnull);
extern Class _Nullable objc_classnameToClass(const char *_Nonnull, bool);
extern void objc_unregisterClass(Class _Nonnull);
extern void objc_unregisterAllClasses(void);
extern uint32_t objc_string_hash(const void *_Nonnull);
extern bool objc_string_equal(const void *_Nonnull, const void *_Nonnull);
extern struct objc_hashtable *_Nonnull objc_hashtable_new(
    objc_hashtable_hash_func, objc_hashtable_equal_func, uint32_t);
extern struct objc_hashtable_bucket objc_deletedBucket;
extern void objc_hashtable_set(struct objc_hashtable *_Nonnull,
    const void *_Nonnull, const void *_Nonnull);
extern void *_Nullable objc_hashtable_get(struct objc_hashtable *_Nonnull,
    const void *_Nonnull);
extern void objc_hashtable_delete(struct objc_hashtable *_Nonnull,
    const void *_Nonnull);
extern void objc_hashtable_free(struct objc_hashtable *_Nonnull);
extern void objc_registerSelector(struct objc_selector *_Nonnull);
extern void objc_registerAllSelectors(struct objc_symtab *_Nonnull);
extern void objc_unregisterAllSelectors(void);
extern struct objc_sparsearray *_Nonnull objc_sparsearray_new(uint8_t);
extern void *_Nullable objc_sparsearray_get(struct objc_sparsearray *_Nonnull,
    uintptr_t);
extern void objc_sparsearray_set(struct objc_sparsearray *_Nonnull, uintptr_t,
    void *_Nullable);
extern void objc_sparsearray_free(struct objc_sparsearray *_Nonnull);
extern struct objc_dtable *_Nonnull objc_dtable_new(void);
extern void objc_dtable_copy(struct objc_dtable *_Nonnull,
    struct objc_dtable *_Nonnull);
extern void objc_dtable_set(struct objc_dtable *_Nonnull, uint32_t,
    IMP _Nullable);
extern void objc_dtable_free(struct objc_dtable *_Nonnull);
extern void objc_dtable_cleanup(void);
extern void objc_initStaticInstances(struct objc_symtab *_Nonnull);
extern void objc_forgetPendingStaticInstances(void);
extern void objc_zeroWeakReferences(id _Nonnull);
extern Class _Nullable object_getTaggedPointerClass(id _Nonnull);
#ifdef OF_HAVE_THREADS
extern void objc_globalMutex_lock(void);
extern void objc_globalMutex_unlock(void);
extern void objc_globalMutex_free(void);
#else
# define objc_globalMutex_lock()
# define objc_globalMutex_unlock()
# define objc_globalMutex_free()
#endif
extern char *_Nullable objc_strdup(const char *_Nonnull string);

static inline IMP _Nullable
objc_dtable_get(const struct objc_dtable *_Nonnull dtable, uint32_t idx)
{
#ifdef OF_SELUID24

Modified src/runtime/property.m from [34b7870e2a] to [4164734943].

18
19
20
21
22
23
24
25
26
27






28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#include <string.h>

#import "ObjFWRT.h"
#import "private.h"

#ifdef OF_HAVE_THREADS
# import "OFPlainMutex.h"
# define NUM_SPINLOCKS 8	/* needs to be a power of 2 */
# define SPINLOCK_HASH(p) ((unsigned)((uintptr_t)p >> 4) & (NUM_SPINLOCKS - 1))
static OFSpinlock spinlocks[NUM_SPINLOCKS];






#endif

#ifdef OF_HAVE_THREADS
OF_CONSTRUCTOR()
{
	for (size_t i = 0; i < NUM_SPINLOCKS; i++)
		if (OFSpinlockNew(&spinlocks[i]) != 0)
			OBJC_ERROR("Failed to initialize spinlocks!");
}
#endif

id
objc_getProperty(id self, SEL _cmd, ptrdiff_t offset, bool atomic)
{
	if (atomic) {
		id *ptr = (id *)(void *)((char *)self + offset);
#ifdef OF_HAVE_THREADS
		unsigned hash = SPINLOCK_HASH(ptr);

		OFEnsure(OFSpinlockLock(&spinlocks[hash]) == 0);
		@try {
			return [[*ptr retain] autorelease];
		} @finally {
			OFEnsure(OFSpinlockUnlock(&spinlocks[hash]) == 0);
		}
#else
		return [[*ptr retain] autorelease];
#endif
	}

	return *(id *)(void *)((char *)self + offset);
}

void
objc_setProperty(id self, SEL _cmd, ptrdiff_t offset, id value, bool atomic,
    signed char copy)
{
	if (atomic) {
		id *ptr = (id *)(void *)((char *)self + offset);
#ifdef OF_HAVE_THREADS
		unsigned hash = SPINLOCK_HASH(ptr);

		OFEnsure(OFSpinlockLock(&spinlocks[hash]) == 0);
		@try {
#endif
			id old = *ptr;

			switch (copy) {
			case 0:
				*ptr = [value retain];
				break;
			case 2:
				*ptr = [value mutableCopy];
				break;
			default:
				*ptr = [value copy];
			}

			[old release];
#ifdef OF_HAVE_THREADS
		} @finally {
			OFEnsure(OFSpinlockUnlock(&spinlocks[hash]) == 0);
		}
#endif

		return;
	}

	id *ptr = (id *)(void *)((char *)self + offset);







|
<
|
>
>
>
>
>
>





|











|

|



|
















|

|


















|







18
19
20
21
22
23
24
25

26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#include <string.h>

#import "ObjFWRT.h"
#import "private.h"

#ifdef OF_HAVE_THREADS
# import "OFPlainMutex.h"
# define numSpinlocks 8	/* needs to be a power of 2 */

static OFSpinlock spinlocks[numSpinlocks];

static OF_INLINE size_t
spinlockSlot(const void *ptr)
{
	return ((size_t)((uintptr_t)ptr >> 4) & (numSpinlocks - 1));
}
#endif

#ifdef OF_HAVE_THREADS
OF_CONSTRUCTOR()
{
	for (size_t i = 0; i < numSpinlocks; i++)
		if (OFSpinlockNew(&spinlocks[i]) != 0)
			OBJC_ERROR("Failed to initialize spinlocks!");
}
#endif

id
objc_getProperty(id self, SEL _cmd, ptrdiff_t offset, bool atomic)
{
	if (atomic) {
		id *ptr = (id *)(void *)((char *)self + offset);
#ifdef OF_HAVE_THREADS
		size_t slot = spinlockSlot(ptr);

		OFEnsure(OFSpinlockLock(&spinlocks[slot]) == 0);
		@try {
			return [[*ptr retain] autorelease];
		} @finally {
			OFEnsure(OFSpinlockUnlock(&spinlocks[slot]) == 0);
		}
#else
		return [[*ptr retain] autorelease];
#endif
	}

	return *(id *)(void *)((char *)self + offset);
}

void
objc_setProperty(id self, SEL _cmd, ptrdiff_t offset, id value, bool atomic,
    signed char copy)
{
	if (atomic) {
		id *ptr = (id *)(void *)((char *)self + offset);
#ifdef OF_HAVE_THREADS
		size_t slot = spinlockSlot(ptr);

		OFEnsure(OFSpinlockLock(&spinlocks[slot]) == 0);
		@try {
#endif
			id old = *ptr;

			switch (copy) {
			case 0:
				*ptr = [value retain];
				break;
			case 2:
				*ptr = [value mutableCopy];
				break;
			default:
				*ptr = [value copy];
			}

			[old release];
#ifdef OF_HAVE_THREADS
		} @finally {
			OFEnsure(OFSpinlockUnlock(&spinlocks[slot]) == 0);
		}
#endif

		return;
	}

	id *ptr = (id *)(void *)((char *)self + offset);
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
/* The following methods are only required for GCC >= 4.6 */
void
objc_getPropertyStruct(void *dest, const void *src, ptrdiff_t size, bool atomic,
    bool strong)
{
	if (atomic) {
#ifdef OF_HAVE_THREADS
		unsigned hash = SPINLOCK_HASH(src);

		OFEnsure(OFSpinlockLock(&spinlocks[hash]) == 0);
#endif
		memcpy(dest, src, size);
#ifdef OF_HAVE_THREADS
		OFEnsure(OFSpinlockUnlock(&spinlocks[hash]) == 0);
#endif

		return;
	}

	memcpy(dest, src, size);
}

void
objc_setPropertyStruct(void *dest, const void *src, ptrdiff_t size, bool atomic,
    bool strong)
{
	if (atomic) {
#ifdef OF_HAVE_THREADS
		unsigned hash = SPINLOCK_HASH(src);

		OFEnsure(OFSpinlockLock(&spinlocks[hash]) == 0);
#endif
		memcpy(dest, src, size);
#ifdef OF_HAVE_THREADS
		OFEnsure(OFSpinlockUnlock(&spinlocks[hash]) == 0);
#endif

		return;
	}

	memcpy(dest, src, size);
}







|

|



|














|

|



|







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
/* The following methods are only required for GCC >= 4.6 */
void
objc_getPropertyStruct(void *dest, const void *src, ptrdiff_t size, bool atomic,
    bool strong)
{
	if (atomic) {
#ifdef OF_HAVE_THREADS
		size_t slot = spinlockSlot(src);

		OFEnsure(OFSpinlockLock(&spinlocks[slot]) == 0);
#endif
		memcpy(dest, src, size);
#ifdef OF_HAVE_THREADS
		OFEnsure(OFSpinlockUnlock(&spinlocks[slot]) == 0);
#endif

		return;
	}

	memcpy(dest, src, size);
}

void
objc_setPropertyStruct(void *dest, const void *src, ptrdiff_t size, bool atomic,
    bool strong)
{
	if (atomic) {
#ifdef OF_HAVE_THREADS
		size_t slot = spinlockSlot(src);

		OFEnsure(OFSpinlockLock(&spinlocks[slot]) == 0);
#endif
		memcpy(dest, src, size);
#ifdef OF_HAVE_THREADS
		OFEnsure(OFSpinlockUnlock(&spinlocks[slot]) == 0);
#endif

		return;
	}

	memcpy(dest, src, size);
}
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
	if (class == Nil) {
		if (outCount != NULL)
			*outCount = 0;

		return NULL;
	}

	objc_global_mutex_lock();

	count = 0;
	if (class->info & OBJC_CLASS_INFO_NEW_ABI)
		for (iter = class->propertyList; iter != NULL;
		    iter = iter->next)
			count += iter->count;

	if (count == 0) {
		if (outCount != NULL)
			*outCount = 0;

		objc_global_mutex_unlock();
		return NULL;
	}

	properties = malloc((count + 1) * sizeof(objc_property_t));
	if (properties == NULL)
		OBJC_ERROR("Not enough memory to copy properties");

	i = 0;
	for (iter = class->propertyList; iter != NULL; iter = iter->next)
		for (unsigned int j = 0; j < iter->count; j++)
			properties[i++] = &iter->properties[j];
	OFEnsure(i == count);
	properties[count] = NULL;

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

	objc_global_mutex_unlock();

	return properties;
}

const char *
property_getName(objc_property_t property)
{







|











|

















|







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
	if (class == Nil) {
		if (outCount != NULL)
			*outCount = 0;

		return NULL;
	}

	objc_globalMutex_lock();

	count = 0;
	if (class->info & OBJC_CLASS_INFO_NEW_ABI)
		for (iter = class->propertyList; iter != NULL;
		    iter = iter->next)
			count += iter->count;

	if (count == 0) {
		if (outCount != NULL)
			*outCount = 0;

		objc_globalMutex_unlock();
		return NULL;
	}

	properties = malloc((count + 1) * sizeof(objc_property_t));
	if (properties == NULL)
		OBJC_ERROR("Not enough memory to copy properties");

	i = 0;
	for (iter = class->propertyList; iter != NULL; iter = iter->next)
		for (unsigned int j = 0; j < iter->count; j++)
			properties[i++] = &iter->properties[j];
	OFEnsure(i == count);
	properties[count] = NULL;

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

	objc_globalMutex_unlock();

	return properties;
}

const char *
property_getName(objc_property_t property)
{

Modified src/runtime/protocol.m from [7bac61bcb9] to [375dff745f].

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
	for (struct objc_protocol_list *protocolList = class->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 ((categories = objc_categories_for_class(class)) == NULL) {
		objc_global_mutex_unlock();
		return false;
	}

	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(
				    protocolList->list[j], protocol)) {
					objc_global_mutex_unlock();
					return true;
				}
			}
		}
	}

	objc_global_mutex_unlock();

	return false;
}







|

|
|










|






|



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
	for (struct objc_protocol_list *protocolList = class->protocols;
	    protocolList != NULL; protocolList = protocolList->next)
		for (long i = 0; i < protocolList->count; i++)
			if (protocol_conformsToProtocol(protocolList->list[i],
			    protocol))
				return true;

	objc_globalMutex_lock();

	if ((categories = objc_categoriesForClass(class)) == NULL) {
		objc_globalMutex_unlock();
		return false;
	}

	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(
				    protocolList->list[j], protocol)) {
					objc_globalMutex_unlock();
					return true;
				}
			}
		}
	}

	objc_globalMutex_unlock();

	return false;
}

Modified src/runtime/selector.m from [7cee0dae00] to [5e713d47e2].

21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142

#import "ObjFWRT.h"
#import "private.h"

#import "macros.h"

#ifdef OF_SELUID24
# define SEL_MAX 0xFFFFFF
# define SEL_SIZE 3
#else
# define SEL_MAX 0xFFFF
# define SEL_SIZE 2
#endif

static struct objc_hashtable *selectors = NULL;
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_selector *selector)
{
	SEL existingSelector;
	const char *name;

	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 ((existingSelector = objc_hashtable_get(selectors,
	    (const char *)selector->UID)) != NULL) {
		selector->UID = existingSelector->UID;
		return;
	}

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

	name = (const char *)selector->UID;
	selector->UID = selectorsCount++;

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

SEL
sel_registerName(const char *name)
{
	struct objc_selector *selector;

	objc_global_mutex_lock();

	if (selectors != NULL &&
	    (selector = objc_hashtable_get(selectors, name)) != NULL) {
		objc_global_mutex_unlock();
		return (SEL)selector;
	}

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

	if ((selector->UID = (uintptr_t)objc_strdup(name)) == 0)
		OBJC_ERROR("Not enough memory to allocate selector!");

	selector->typeEncoding = NULL;

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

	freeList[freeListCount++] = selector;
	freeList[freeListCount++] = (char *)selector->UID;

	objc_register_selector(selector);

	objc_global_mutex_unlock();
	return (SEL)selector;
}

void
objc_register_all_selectors(struct objc_symtab *symtab)
{
	struct objc_selector *selector;

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

	for (selector = symtab->selectorRefs; selector->UID != 0; selector++)
		objc_register_selector(selector);
}

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

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

	return ret;
}

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

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

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







|
|

|
|









|




|




|







|














|



|


















|

|




|







|







|

|











|







21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142

#import "ObjFWRT.h"
#import "private.h"

#import "macros.h"

#ifdef OF_SELUID24
static const uint32_t maxSel = 0xFFFFFF;
static const uint8_t selLevels = 3;
#else
static const uint32_t maxSel = 0xFFFF;
static const uint8_t selLevels = 2;
#endif

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

void
objc_registerSelector(struct objc_selector *selector)
{
	SEL existingSelector;
	const char *name;

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

	if (selectors == NULL)
		selectors = objc_hashtable_new(
		    objc_string_hash, objc_string_equal, 2);
	else if ((existingSelector = objc_hashtable_get(selectors,
	    (const char *)selector->UID)) != NULL) {
		selector->UID = existingSelector->UID;
		return;
	}

	if (selectorNames == NULL)
		selectorNames = objc_sparsearray_new(selLevels);

	name = (const char *)selector->UID;
	selector->UID = selectorsCount++;

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

SEL
sel_registerName(const char *name)
{
	struct objc_selector *selector;

	objc_globalMutex_lock();

	if (selectors != NULL &&
	    (selector = objc_hashtable_get(selectors, name)) != NULL) {
		objc_globalMutex_unlock();
		return (SEL)selector;
	}

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

	if ((selector->UID = (uintptr_t)objc_strdup(name)) == 0)
		OBJC_ERROR("Not enough memory to allocate selector!");

	selector->typeEncoding = NULL;

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

	freeList[freeListCount++] = selector;
	freeList[freeListCount++] = (char *)selector->UID;

	objc_registerSelector(selector);

	objc_globalMutex_unlock();
	return (SEL)selector;
}

void
objc_registerAllSelectors(struct objc_symtab *symtab)
{
	struct objc_selector *selector;

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

	for (selector = symtab->selectorRefs; selector->UID != 0; selector++)
		objc_registerSelector(selector);
}

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

	objc_globalMutex_lock();
	ret = objc_sparsearray_get(selectorNames, (uint32_t)selector->UID);
	objc_globalMutex_unlock();

	return ret;
}

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

void
objc_unregisterAllSelectors(void)
{
	objc_hashtable_free(selectors);
	objc_sparsearray_free(selectorNames);

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

Modified src/runtime/sparsearray.m from [dc25cc4021] to [ac31f7403e].

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
#include <stdio.h>
#include <stdlib.h>

#import "ObjFWRT.h"
#import "private.h"

struct objc_sparsearray *
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->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->indexSize - 1; i++) {
		uintptr_t j =
		    (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->indexSize - 1; i++) {
		uintptr_t j =
		    (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!");








|









|









|

|














|

|







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
#include <stdio.h>
#include <stdlib.h>

#import "ObjFWRT.h"
#import "private.h"

struct objc_sparsearray *
objc_sparsearray_new(uint8_t levels)
{
	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->levels = levels;

	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->levels - 1; i++) {
		uintptr_t j =
		    (idx >> ((sparsearray->levels - 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->levels - 1; i++) {
		uintptr_t j =
		    (idx >> ((sparsearray->levels - 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!");

86
87
88
89
90
91
92
93
94
95

	free(data);
}

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







|


86
87
88
89
90
91
92
93
94
95

	free(data);
}

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

Modified src/runtime/static-instances.m from [9308a0dd6f] to [5b5e1b3d9a].

21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#import "ObjFWRT.h"
#import "private.h"

static struct objc_static_instances **staticInstancesList = NULL;
static size_t staticInstancesCount = 0;

void
objc_init_static_instances(struct objc_symtab *symtab)
{
	struct objc_static_instances **staticInstances;

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







|







21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#import "ObjFWRT.h"
#import "private.h"

static struct objc_static_instances **staticInstancesList = NULL;
static size_t staticInstancesCount = 0;

void
objc_initStaticInstances(struct objc_symtab *symtab)
{
	struct objc_static_instances **staticInstances;

	/* Check if the class for a static instance became available */
	for (size_t i = 0; i < staticInstancesCount; i++) {
		Class class = objc_lookUpClass(
		    staticInstancesList[i]->className);
91
92
93
94
95
96
97
98
99
100
101
102
103
			staticInstancesList[staticInstancesCount++] =
			    *staticInstances;
		}
	}
}

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







|





91
92
93
94
95
96
97
98
99
100
101
102
103
			staticInstancesList[staticInstancesCount++] =
			    *staticInstances;
		}
	}
}

void
objc_forgetPendingStaticInstances()
{
	free(staticInstancesList);
	staticInstancesList = NULL;
	staticInstancesCount = 0;
}

Modified src/runtime/synchronized.m from [90a59dedf3] to [0c53071c1e].

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

#import "ObjFWRT.h"
#import "private.h"

#ifdef OF_HAVE_THREADS
# import "OFPlainMutex.h"

static struct lock {
	id object;
	int count;
	OFPlainRecursiveMutex rmutex;
	struct lock *next;
} *locks = NULL;

static OFPlainMutex mutex;

OF_CONSTRUCTOR()
{
	if (OFPlainMutexNew(&mutex) != 0)
		OBJC_ERROR("Failed to create mutex!");
}
#endif

int
objc_sync_enter(id object)
{
	if (object == nil)
		return 0;

#ifdef OF_HAVE_THREADS
	struct lock *lock;

	if (OFPlainMutexLock(&mutex) != 0)
		OBJC_ERROR("Failed to lock mutex!");

	/* Look if we already have a lock */
	for (lock = locks; lock != NULL; lock = lock->next) {
		if (lock->object != object)







|



|


















|







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

#import "ObjFWRT.h"
#import "private.h"

#ifdef OF_HAVE_THREADS
# import "OFPlainMutex.h"

static struct Lock {
	id object;
	int count;
	OFPlainRecursiveMutex rmutex;
	struct Lock *next;
} *locks = NULL;

static OFPlainMutex mutex;

OF_CONSTRUCTOR()
{
	if (OFPlainMutexNew(&mutex) != 0)
		OBJC_ERROR("Failed to create mutex!");
}
#endif

int
objc_sync_enter(id object)
{
	if (object == nil)
		return 0;

#ifdef OF_HAVE_THREADS
	struct Lock *lock;

	if (OFPlainMutexLock(&mutex) != 0)
		OBJC_ERROR("Failed to lock mutex!");

	/* Look if we already have a lock */
	for (lock = locks; lock != NULL; lock = lock->next) {
		if (lock->object != object)
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
int
objc_sync_exit(id object)
{
	if (object == nil)
		return 0;

#ifdef OF_HAVE_THREADS
	struct lock *lock, *last = NULL;

	if (OFPlainMutexLock(&mutex) != 0)
		OBJC_ERROR("Failed to lock mutex!");

	for (lock = locks; lock != NULL; lock = lock->next) {
		if (lock->object != object) {
			last = lock;







|







94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
int
objc_sync_exit(id object)
{
	if (object == nil)
		return 0;

#ifdef OF_HAVE_THREADS
	struct Lock *lock, *last = NULL;

	if (OFPlainMutexLock(&mutex) != 0)
		OBJC_ERROR("Failed to lock mutex!");

	for (lock = locks; lock != NULL; lock = lock->next) {
		if (lock->object != object) {
			last = lock;

Modified src/runtime/tagged-pointer.m from [a6a4aa7d0f] to [84026d482b].

13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
 * file.
 */

#import "ObjFWRT.h"

#import "private.h"

#define TAGGED_POINTER_BITS 4
#define NUM_TAGGED_POINTER_CLASSES (1 << (TAGGED_POINTER_BITS - 1))

Class objc_tagged_pointer_classes[NUM_TAGGED_POINTER_CLASSES];
static int taggedPointerClassesCount;
uintptr_t objc_tagged_pointer_secret;

void
objc_setTaggedPointerSecret(uintptr_t secret)
{
	objc_tagged_pointer_secret = secret & ~(uintptr_t)1;
}

int
objc_registerTaggedPointerClass(Class class)
{
	int i;

	objc_global_mutex_lock();

	if (taggedPointerClassesCount == NUM_TAGGED_POINTER_CLASSES) {
		objc_global_mutex_unlock();
		return -1;
	}

	i = taggedPointerClassesCount++;
	objc_tagged_pointer_classes[i] = class;

	objc_global_mutex_unlock();

	return i;
}

bool
object_isTaggedPointer(id object)
{
	uintptr_t pointer = (uintptr_t)object;

	return pointer & 1;
}

Class
object_getTaggedPointerClass(id object)
{
	uintptr_t pointer = (uintptr_t)object ^ objc_tagged_pointer_secret;

	pointer &= (1 << TAGGED_POINTER_BITS) - 1;
	pointer >>= 1;

	if (pointer >= NUM_TAGGED_POINTER_CLASSES)
		return Nil;

	return objc_tagged_pointer_classes[pointer];
}

uintptr_t
object_getTaggedPointerValue(id object)
{
	uintptr_t pointer = (uintptr_t)object ^ objc_tagged_pointer_secret;

	pointer >>= TAGGED_POINTER_BITS;

	return pointer;
}

id
objc_createTaggedPointer(int class, uintptr_t value)
{
	uintptr_t pointer;

	if (class < 0 || class >= NUM_TAGGED_POINTER_CLASSES)
		return nil;

	if (value > (UINTPTR_MAX >> TAGGED_POINTER_BITS))
		return nil;

	pointer = (class << 1) | 1;
	pointer |= (value << TAGGED_POINTER_BITS);

	return (id)(pointer ^ objc_tagged_pointer_secret);
}







|
|

|

|




|







|

|
|




|

|















|

|


|


|





|

|









|


|



|

|

13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
 * file.
 */

#import "ObjFWRT.h"

#import "private.h"

#define numTaggedPointerBits 4
#define maxNumTaggedPointerClasses (1 << (numTaggedPointerBits - 1))

Class objc_taggedPointerClasses[maxNumTaggedPointerClasses];
static int taggedPointerClassesCount;
uintptr_t objc_taggedPointerSecret;

void
objc_setTaggedPointerSecret(uintptr_t secret)
{
	objc_taggedPointerSecret = secret & ~(uintptr_t)1;
}

int
objc_registerTaggedPointerClass(Class class)
{
	int i;

	objc_globalMutex_lock();

	if (taggedPointerClassesCount == maxNumTaggedPointerClasses) {
		objc_globalMutex_unlock();
		return -1;
	}

	i = taggedPointerClassesCount++;
	objc_taggedPointerClasses[i] = class;

	objc_globalMutex_unlock();

	return i;
}

bool
object_isTaggedPointer(id object)
{
	uintptr_t pointer = (uintptr_t)object;

	return pointer & 1;
}

Class
object_getTaggedPointerClass(id object)
{
	uintptr_t pointer = (uintptr_t)object ^ objc_taggedPointerSecret;

	pointer &= (1 << numTaggedPointerBits) - 1;
	pointer >>= 1;

	if (pointer >= maxNumTaggedPointerClasses)
		return Nil;

	return objc_taggedPointerClasses[pointer];
}

uintptr_t
object_getTaggedPointerValue(id object)
{
	uintptr_t pointer = (uintptr_t)object ^ objc_taggedPointerSecret;

	pointer >>= numTaggedPointerBits;

	return pointer;
}

id
objc_createTaggedPointer(int class, uintptr_t value)
{
	uintptr_t pointer;

	if (class < 0 || class >= maxNumTaggedPointerClasses)
		return nil;

	if (value > (UINTPTR_MAX >> numTaggedPointerBits))
		return nil;

	pointer = (class << 1) | 1;
	pointer |= (value << numTaggedPointerBits);

	return (id)(pointer ^ objc_taggedPointerSecret);
}

Modified src/runtime/threading.m from [34d13c2d7f] to [9fcf574ba3].

30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
init(void)
{
	if (OFPlainRecursiveMutexNew(&globalMutex) != 0)
		OBJC_ERROR("Failed to create global mutex!");
}

void
objc_global_mutex_lock(void)
{
	static OFOnceControl onceControl = OFOnceControlInitValue;
	OFOnce(&onceControl, init);

	if (OFPlainRecursiveMutexLock(&globalMutex) != 0)
		OBJC_ERROR("Failed to lock global mutex!");
}

void
objc_global_mutex_unlock(void)
{
	if (OFPlainRecursiveMutexUnlock(&globalMutex) != 0)
		OBJC_ERROR("Failed to unlock global mutex!");
}







|









|




30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
init(void)
{
	if (OFPlainRecursiveMutexNew(&globalMutex) != 0)
		OBJC_ERROR("Failed to create global mutex!");
}

void
objc_globalMutex_lock(void)
{
	static OFOnceControl onceControl = OFOnceControlInitValue;
	OFOnce(&onceControl, init);

	if (OFPlainRecursiveMutexLock(&globalMutex) != 0)
		OBJC_ERROR("Failed to lock global mutex!");
}

void
objc_globalMutex_unlock(void)
{
	if (OFPlainRecursiveMutexUnlock(&globalMutex) != 0)
		OBJC_ERROR("Failed to unlock global mutex!");
}

Modified tests/TestsAppDelegate.m from [c47240e9e7] to [6f59a3820f].

81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#endif

#if defined(OF_OBJFW_RUNTIME) && !defined(OF_WINDOWS) && !defined(OF_AMIGAOS)
	/*
	 * This does not work on Win32 if ObjFW is built as a DLL.
	 *
	 * On AmigaOS, some destructors need to be able to send messages.
	 * Calling objc_exit() via atexit() would result in the runtime being
	 * destructed before for the destructors ran.
	 */
	atexit(objc_exit);
#endif

	/* We need deterministic hashes for tests */
	OFHashSeed = 0;

#ifdef OF_WII
	GXRModeObj *rmode;







|


|







81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#endif

#if defined(OF_OBJFW_RUNTIME) && !defined(OF_WINDOWS) && !defined(OF_AMIGAOS)
	/*
	 * This does not work on Win32 if ObjFW is built as a DLL.
	 *
	 * On AmigaOS, some destructors need to be able to send messages.
	 * Calling objc_deinit() via atexit() would result in the runtime being
	 * destructed before for the destructors ran.
	 */
	atexit(objc_deinit);
#endif

	/* We need deterministic hashes for tests */
	OFHashSeed = 0;

#ifdef OF_WII
	GXRModeObj *rmode;

Modified tests/plugin/TestPlugin.m from [c395596363] to [37c0de4e88].

24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
{
	Class class = objc_getClass("TestPlugin");

	if (class == Nil)
		/*
		 * musl has broken dlclose(): Instead of calling the destructor
		 * on dlclose(), they call it on exit(). This of course means
		 * that our tests might have already called objc_exit() and the
		 * class is already gone.
		 */
		return;

	objc_unregister_class(class);
}
#endif

@implementation TestPlugin
- (int)test: (int)num
{
	return num * 2;







|
|



|







24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
{
	Class class = objc_getClass("TestPlugin");

	if (class == Nil)
		/*
		 * musl has broken dlclose(): Instead of calling the destructor
		 * on dlclose(), they call it on exit(). This of course means
                 * that our tests might have already called objc_deinit() and
                 * the class is already gone.
		 */
		return;

	objc_unregisterClass(class);
}
#endif

@implementation TestPlugin
- (int)test: (int)num
{
	return num * 2;