ObjFW  Changes On Branch runtime

Changes In Branch runtime Excluding Merge-Ins

This is equivalent to a diff from 0db281bf03 to a230197b48

2012-07-03
15:50
Merge branch 'runtime' check-in: 4c4fdb3429 user: js tags: trunk
15:44
runtime: Add exception handling. Closed-Leaf check-in: a230197b48 user: js tags: runtime
2012-07-01
20:56
Reference OFConstantString in OFString. check-in: e810b8ab15 user: js tags: runtime
2012-06-11
23:08
Add OF_PATH_PARENT_DIR. check-in: bfd8f4cfec user: js tags: trunk
20:50
Merge branch 'master' into runtime check-in: 19a677b596 user: js tags: runtime
11:08
Improve -[OFNumber description]. check-in: 0db281bf03 user: js tags: trunk
2012-06-10
16:07
JSON: Make it possible to get the invalid line. check-in: 72c71c4eb2 user: js tags: trunk

Modified configure.ac from [8413d47c07] to [0661dee44a].

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
esac
AX_CHECK_COMPILER_FLAGS(-pipe, [OBJCFLAGS="$OBJCFLAGS -pipe"])
AX_CHECK_COMPILER_FLAGS(-fno-common, [OBJCFLAGS="$OBJCFLAGS -fno-common"])
AX_CHECK_COMPILER_FLAGS(-fno-constant-cfstrings, [
	OBJCFLAGS="$OBJCFLAGS -fno-constant-cfstrings"
	AC_SUBST(NO_CONST_CFSTRINGS, "-fno-constant-cfstrings")
])
AX_CHECK_COMPILER_FLAGS(-Wshorten-64-to-32, [
	old_OBJCFLAGS="$OBJCFLAGS"
	OBJCFLAGS="$OBJCFLAGS -Wshorten-64-to-32 -Werror"
	AC_TRY_COMPILE([
		#import <objc/objc-api.h>
	], [], [
		OBJCFLAGS="$old_OBJCFLAGS -Wshorten-64-to-32"
	], [
		OBJCFLAGS="$old_OBJCFLAGS"
	])
])
AX_CHECK_COMPILER_FLAGS(-Wsemicolon-before-method-body,
	[OBJCFLAGS="$OBJCFLAGS -Wsemicolon-before-method-body"])

AC_MSG_CHECKING(whether Objective C compiler supports fast enumeration)
AC_TRY_COMPILE([
	@protocol OFFastEnumeration
	- (int)countByEnumeratingWithState: (void*)state







|
<
|
<
<
<
<
<
<
<
<







33
34
35
36
37
38
39
40

41








42
43
44
45
46
47
48
esac
AX_CHECK_COMPILER_FLAGS(-pipe, [OBJCFLAGS="$OBJCFLAGS -pipe"])
AX_CHECK_COMPILER_FLAGS(-fno-common, [OBJCFLAGS="$OBJCFLAGS -fno-common"])
AX_CHECK_COMPILER_FLAGS(-fno-constant-cfstrings, [
	OBJCFLAGS="$OBJCFLAGS -fno-constant-cfstrings"
	AC_SUBST(NO_CONST_CFSTRINGS, "-fno-constant-cfstrings")
])
AX_CHECK_COMPILER_FLAGS(-Wshorten-64-to-32,

	[OBJCFLAGS="$OBJCFLAGS -Wshorten-64-to-32"])








AX_CHECK_COMPILER_FLAGS(-Wsemicolon-before-method-body,
	[OBJCFLAGS="$OBJCFLAGS -Wsemicolon-before-method-body"])

AC_MSG_CHECKING(whether Objective C compiler supports fast enumeration)
AC_TRY_COMPILE([
	@protocol OFFastEnumeration
	- (int)countByEnumeratingWithState: (void*)state
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
	AC_SUBST(OFBLOCKTESTS_M, "OFBlockTests.m")
	AC_MSG_RESULT(yes)
], [
	AC_MSG_RESULT(no)
	OBJCFLAGS="$old_OBJCFLAGS"
])

AC_CHECK_HEADERS([objfw-rt.h objc/objc.h])

test x"$ac_cv_header_objfw_rt_h" = x"yes" && objc_runtime="ObjFW-RT"

AC_MSG_CHECKING(which Objective C runtime we use)
AS_IF([test x"$ac_cv_header_objc_objc_h" = x"yes"], [
	dnl Only accept it if it's from gcc >= 4.7, as the one in 4.6 is buggy
	dnl when using the new API.
	AC_EGREP_CPP(yes, [
		#import <objc/objc.h>
		#if defined(__GNU_LIBOBJC__) && __GNU_LIBOBJC__ >= 20110608
		yes
		#endif
	], [
		test x"$objc_runtime" = x"" && objc_runtime="GNU"
	], [
		dnl TODO: This is ugly. Let's think of a better check.
		AC_EGREP_CPP(yes, [
			#import <objc/objc.h>
			#ifdef __objc_INCLUDE_GNU
			yes
			#endif
		], [
			test x"$objc_runtime" = x"" && objc_runtime="old GNU"
		], [
			objc_runtime="Apple"
		])
	])
])
AC_MSG_RESULT($objc_runtime)

case $objc_runtime in
	ObjFW-RT)
		AC_DEFINE(OF_OBJFW_RUNTIME, 1,
			[Whether we use the ObjFW runtime])
		AC_SUBST(GNU_RUNTIME, "-fgnu-runtime")
		OBJCFLAGS="$OBJCFLAGS -fgnu-runtime"

		AC_CHECK_LIB(objfw-rt, objc_msg_lookup, [
			LIBS="-lobjfw-rt $LIBS"
		], [
			AC_MSG_ERROR([libobjfw-rt not found!])
		])
		;;
	Apple)
		AC_DEFINE(OF_APPLE_RUNTIME, 1,
			[Whether we use the Apple ObjC runtime])

		AC_CHECK_LIB(objc, objc_msgSend, [
			LIBS="-lobjc $LIBS"
		], [
			AC_MSG_ERROR([libobjc not found!])
		])
		;;
	GNU)
		AC_DEFINE(OF_GNU_RUNTIME, 1,
			[Whether we use the GNU ObjC runtime])

		AC_CHECK_LIB(objc, objc_msg_lookup, [
			LIBS="-lobjc $LIBS"
		], [
			AC_MSG_ERROR([libobjc not found!])
		])
		;;
	"old GNU")
		AC_DEFINE(OF_OLD_GNU_RUNTIME, 1,
			[Whether we use the old GNU ObjC runtime])

		AC_CHECK_LIB(objc, objc_msg_lookup, [
			LIBS="-lobjc $LIBS"
		], [
			AC_MSG_ERROR([libobjc not found!])
		])
		;;
	*)
		AC_MSG_RESULT(none)
		AC_MSG_ERROR(No ObjC runtime found! Please install ObjFW-RT!)
		;;
esac

AC_CHECK_FUNC(objc_getProperty,, [
	AC_DEFINE(NEED_OBJC_PROPERTIES_INIT, 1,
		[Whether objc_properties_init needs to be called])
	AC_SUBST(OBJC_PROPERTIES_M, "objc_properties.m")
])

AC_CHECK_FUNC(objc_enumerationMutation, [
	AC_DEFINE(HAVE_OBJC_ENUMERATIONMUTATION, 1,
		[Whether we have objc_enumerationMutation])
])

AC_CHECK_TOOL(AR, ar)
AC_PROG_RANLIB
AC_ARG_ENABLE(shared,
	AS_HELP_STRING([--disable-shared], [do not build shared library]))
AS_IF([test x"$enable_shared" != x"no"], [
	BUILDSYS_SHARED_LIB
	AC_SUBST(OBJFW_SHARED_LIB, "${LIB_PREFIX}objfw${LIB_SUFFIX}")







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







115
116
117
118
119
120
121



























































































122
123
124
125
126
127
128
	AC_SUBST(OFBLOCKTESTS_M, "OFBlockTests.m")
	AC_MSG_RESULT(yes)
], [
	AC_MSG_RESULT(no)
	OBJCFLAGS="$old_OBJCFLAGS"
])




























































































AC_CHECK_TOOL(AR, ar)
AC_PROG_RANLIB
AC_ARG_ENABLE(shared,
	AS_HELP_STRING([--disable-shared], [do not build shared library]))
AS_IF([test x"$enable_shared" != x"no"], [
	BUILDSYS_SHARED_LIB
	AC_SUBST(OBJFW_SHARED_LIB, "${LIB_PREFIX}objfw${LIB_SUFFIX}")
240
241
242
243
244
245
246
247











































































































248
249
250
251

252
253


254
255
256
257
258
259
260
AS_IF([test x"$PLUGIN_SUFFIX" != x""], [
	AC_SUBST(OFPLUGIN_M, "OFPlugin.m")
	AC_SUBST(OFPLUGINTESTS_M, "OFPluginTests.m")
	AC_SUBST(TESTPLUGIN, "plugin")
	AC_DEFINE(OF_PLUGINS, 1, [Whether we have plugin support])
	AC_SUBST(OFPLUGINS_DEF, "-DOF_PLUGINS")
])












































































































case "$host_os" in
	darwin*)
		AC_SUBST(REEXPORT_LIBOBJC, ["-Wl,-reexport-lobjc"])
		AC_SUBST(LDFLAGS_REEXPORT, ["-Wl,-reexport-lobjfw"])

		AC_SUBST(MACH_ALIAS_LIST,
			 ["-Xarch_x86_64 -Wl,-alias_list,mach_alias_list"])


		;;
esac

AC_C_BIGENDIAN([
	AC_DEFINE(OF_BIG_ENDIAN, 1, [Whether we are big endian])
])









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


<

>
|
|
>
>







140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256

257
258
259
260
261
262
263
264
265
266
267
268
269
AS_IF([test x"$PLUGIN_SUFFIX" != x""], [
	AC_SUBST(OFPLUGIN_M, "OFPlugin.m")
	AC_SUBST(OFPLUGINTESTS_M, "OFPluginTests.m")
	AC_SUBST(TESTPLUGIN, "plugin")
	AC_DEFINE(OF_PLUGINS, 1, [Whether we have plugin support])
	AC_SUBST(OFPLUGINS_DEF, "-DOF_PLUGINS")
])

objc_runtime="ObjFW runtime"
AC_CHECK_HEADER(objc/objc.h)
AC_MSG_CHECKING(which Objective C runtime to use)
AC_ARG_ENABLE(runtime,
	AS_HELP_STRING([--enable-runtime], [use the included runtime]))
AC_ARG_ENABLE(seluid16,
	AS_HELP_STRING([--enable-seluid16],
		[use only 16 bit for selectors UIDs]))
AS_IF([test x"$enable_runtime" != x"yes"], [
	AS_IF([test x"$ac_cv_header_objc_objc_h" = x"yes"], [
		dnl TODO: This is ugly. Let's think of a better check.
		AC_EGREP_CPP(yes, [
			#import <objc/objc.h>
			#ifdef __objc_INCLUDE_GNU
			yes
			#endif
		], [
			dnl We don't want the GNU runtime
		], [
			objc_runtime="Apple runtime"
		])
	])
])
AC_MSG_RESULT($objc_runtime)

case $objc_runtime in
	"ObjFW runtime")
		AC_DEFINE(OF_OBJFW_RUNTIME, 1,
			[Whether we use the ObjFW runtime])
		GNU_RUNTIME="-fgnu-runtime"
		OBJCFLAGS="$OBJCFLAGS -fgnu-runtime"
		RUNTIME_FLAGS="-fgnu-runtime"

		AX_CHECK_COMPILER_FLAGS(-fno-objc-nonfragile-abi, [
			OBJCFLAGS="$OBJCFLAGS -fno-objc-nonfragile-abi"
			GNU_RUNTIME="$GNU_RUNTIME -fno-objc-nonfragile-abi"
		])
		AX_CHECK_COMPILER_FLAGS(-Wno-deprecated-objc-isa-usage,
			[OBJCFLAGS="$OBJCFLAGS -Wno-deprecated-objc-isa-usage"])

		AC_SUBST(GNU_RUNTIME)

		AC_SUBST(RUNTIME, "runtime")
		if test x"$enable_shared" != x"no"; then
			AC_SUBST(RUNTIME_LIB_A, "runtime.lib.a")
			AC_SUBST(RUNTIME_RUNTIME_LIB_A, "runtime/runtime.lib.a")
		fi
		if test x"$enable_static" = x"yes" \
		    -o x"$enable_shared" = x"no"; then
			AC_SUBST(RUNTIME_A, "runtime.a")
			AC_SUBST(RUNTIME_RUNTIME_A, "runtime/runtime.a")
		fi

		AC_EGREP_CPP(yes, [
			#if defined(__amd64__) || defined(__x86_64__)
			# ifdef __ELF__
			yes
			# endif
			#endif
		], [
			AC_SUBST(LOOKUP_S, lookup-amd64-elf.S)
			AC_DEFINE(OF_ASM_LOOKUP, 1,
				[Whether to use lookup in assembly])
		], [
			AC_EGREP_CPP(yes, [
				#if defined(__i386__) && defined(__ELF__)
				yes
				#endif
			], [
				AC_SUBST(LOOKUP_S, lookup-x86-elf.S)
				AC_DEFINE(OF_ASM_LOOKUP, 1,
					[Whether to use lookup in assembly])
			])
		])

		AC_EGREP_CPP(yes, [
			#if defined(__amd64__) && defined(__MACH__)
			yes
			#endif
		], [
			AC_SUBST(LOOKUP_S, lookup-amd64-macho.S)
			AC_DEFINE(OF_ASM_LOOKUP, 1,
				[Whether to use lookup in assembly])
		])

		AS_IF([test x"$enable_seluid16" = x"yes"], [
			AC_DEFINE(OF_SELUID16, 1,
				[Whether to use 16 bit selector UIDs])
		])
		;;
	"Apple runtime")
		AC_DEFINE(OF_APPLE_RUNTIME, 1,
			[Whether we use the Apple ObjC runtime])

		AC_CHECK_LIB(objc, objc_msgSend, [
			LIBS="-lobjc $LIBS"
		], [
			AC_MSG_ERROR([libobjc not found!])
		])
		;;
esac

AC_CHECK_FUNC(objc_enumerationMutation, [
	AC_DEFINE(HAVE_OBJC_ENUMERATIONMUTATION, 1,
		[Whether we have objc_enumerationMutation])
])

case "$host_os" in
	darwin*)

		AC_SUBST(LDFLAGS_REEXPORT, ["-Wl,-reexport-lobjfw"])
		AS_IF([test x"$objc_runtime" = x"Apple runtime"], [
		       AC_SUBST(REEXPORT_LIBOBJC, ["-Wl,-reexport-lobjc"])
			tmp="-Xarch_x86_64 -Wl,-alias_list,mach_alias_list"
			AC_SUBST(MACH_ALIAS_LIST, $tmp)
		])
		;;
esac

AC_C_BIGENDIAN([
	AC_DEFINE(OF_BIG_ENDIAN, 1, [Whether we are big endian])
])

405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424

	AC_DEFINE(OF_THREADS, 1, [Whether we have threads])
	AC_SUBST(OFTHREAD_M, "OFThread.m")
	AC_SUBST(OFTHREADTESTS_M, "OFThreadTests.m")
	AC_SUBST(OFHTTPREQUESTTESTS_M, "OFHTTPRequestTests.m")
	AC_SUBST(THREADING_H, "threading.h")

	AC_CHECK_FUNC(objc_sync_enter,, [
		AC_SUBST(OBJC_SYNC_M, "objc_sync.m")
		AC_DEFINE(NEED_OBJC_SYNC_INIT, 1,
			[Whether objc_sync_init needs to be called])
	])

	atomic_ops="none"

	AC_MSG_CHECKING(whether we have an atomic ops assembly implementation)
	AC_EGREP_CPP(yes, [
		#if defined(__GNUC__) && (defined(__i386__) || \
		    defined(__amd64__) || defined(__x86_64__))
		yes







<
<
<
<
<
<







414
415
416
417
418
419
420






421
422
423
424
425
426
427

	AC_DEFINE(OF_THREADS, 1, [Whether we have threads])
	AC_SUBST(OFTHREAD_M, "OFThread.m")
	AC_SUBST(OFTHREADTESTS_M, "OFThreadTests.m")
	AC_SUBST(OFHTTPREQUESTTESTS_M, "OFHTTPRequestTests.m")
	AC_SUBST(THREADING_H, "threading.h")







	atomic_ops="none"

	AC_MSG_CHECKING(whether we have an atomic ops assembly implementation)
	AC_EGREP_CPP(yes, [
		#if defined(__GNUC__) && (defined(__i386__) || \
		    defined(__amd64__) || defined(__x86_64__))
		yes
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588

		AC_MSG_RESULT($have_threadsafe_getaddrinfo)
	])
], [
	AC_MSG_RESULT(no)
])

AS_IF([test x"$objc_runtime" = x"Apple"], [
	AC_CHECK_HEADER(Foundation/NSObject.h, [
		AC_SUBST(FOUNDATION_COMPAT_M, "foundation-compat.m")
	])
])

AS_IF([test x"$GOBJC" = x"yes"], [
	OBJCFLAGS="$OBJCFLAGS -Wwrite-strings -Wpointer-arith -Werror"







|







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

		AC_MSG_RESULT($have_threadsafe_getaddrinfo)
	])
], [
	AC_MSG_RESULT(no)
])

AS_IF([test x"$objc_runtime" = x"Apple runtime"], [
	AC_CHECK_HEADER(Foundation/NSObject.h, [
		AC_SUBST(FOUNDATION_COMPAT_M, "foundation-compat.m")
	])
])

AS_IF([test x"$GOBJC" = x"yes"], [
	OBJCFLAGS="$OBJCFLAGS -Wwrite-strings -Wpointer-arith -Werror"

Modified extra.mk.in from [c78962a205] to [21c2490513].

8
9
10
11
12
13
14

15
16
17
18
19
20
21
22
23
24
25
26
27
28





29
30
31
32
ATOMIC_H = @ATOMIC_H@
BIN_PREFIX = @BIN_PREFIX@
EXCEPTIONS_A = @EXCEPTIONS_A@
EXCEPTIONS_EXCEPTIONS_A = @EXCEPTIONS_EXCEPTIONS_A@
EXCEPTIONS_EXCEPTIONS_LIB_A = @EXCEPTIONS_EXCEPTIONS_LIB_A@
EXCEPTIONS_LIB_A = @EXCEPTIONS_LIB_A@
FOUNDATION_COMPAT_M = @FOUNDATION_COMPAT_M@

MACH_ALIAS_LIST = @MACH_ALIAS_LIST@
OFBLOCKTESTS_M = @OFBLOCKTESTS_M@
OBJC_PROPERTIES_M = @OBJC_PROPERTIES_M@
OBJC_SYNC_M = @OBJC_SYNC_M@
OFHTTPREQUESTTESTS_M = @OFHTTPREQUESTTESTS_M@
OFPLUGIN_M = @OFPLUGIN_M@
OFPLUGINTESTS_M = @OFPLUGINTESTS_M@
OFSTREAMOBSERVER_KQUEUE_M = @OFSTREAMOBSERVER_KQUEUE_M@
OFSTREAMOBSERVER_POLL_M = @OFSTREAMOBSERVER_POLL_M@
OFSTREAMOBSERVER_SELECT_M = @OFSTREAMOBSERVER_SELECT_M@
OFTHREAD_M = @OFTHREAD_M@
OFTHREADTESTS_M = @OFTHREADTESTS_M@
PROPERTIESTESTS_M = @PROPERTIESTESTS_M@
REEXPORT_LIBOBJC = @REEXPORT_LIBOBJC@





TESTPLUGIN = @TESTPLUGIN@
TESTS = @TESTS@
TEST_LAUNCHER = @TEST_LAUNCHER@
THREADING_H = @THREADING_H@







>














>
>
>
>
>




8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
ATOMIC_H = @ATOMIC_H@
BIN_PREFIX = @BIN_PREFIX@
EXCEPTIONS_A = @EXCEPTIONS_A@
EXCEPTIONS_EXCEPTIONS_A = @EXCEPTIONS_EXCEPTIONS_A@
EXCEPTIONS_EXCEPTIONS_LIB_A = @EXCEPTIONS_EXCEPTIONS_LIB_A@
EXCEPTIONS_LIB_A = @EXCEPTIONS_LIB_A@
FOUNDATION_COMPAT_M = @FOUNDATION_COMPAT_M@
LOOKUP_S = @LOOKUP_S@
MACH_ALIAS_LIST = @MACH_ALIAS_LIST@
OFBLOCKTESTS_M = @OFBLOCKTESTS_M@
OBJC_PROPERTIES_M = @OBJC_PROPERTIES_M@
OBJC_SYNC_M = @OBJC_SYNC_M@
OFHTTPREQUESTTESTS_M = @OFHTTPREQUESTTESTS_M@
OFPLUGIN_M = @OFPLUGIN_M@
OFPLUGINTESTS_M = @OFPLUGINTESTS_M@
OFSTREAMOBSERVER_KQUEUE_M = @OFSTREAMOBSERVER_KQUEUE_M@
OFSTREAMOBSERVER_POLL_M = @OFSTREAMOBSERVER_POLL_M@
OFSTREAMOBSERVER_SELECT_M = @OFSTREAMOBSERVER_SELECT_M@
OFTHREAD_M = @OFTHREAD_M@
OFTHREADTESTS_M = @OFTHREADTESTS_M@
PROPERTIESTESTS_M = @PROPERTIESTESTS_M@
REEXPORT_LIBOBJC = @REEXPORT_LIBOBJC@
RUNTIME = @RUNTIME@
RUNTIME_A = @RUNTIME_A@
RUNTIME_RUNTIME_A = @RUNTIME_RUNTIME_A@
RUNTIME_RUNTIME_LIB_A = @RUNTIME_RUNTIME_LIB_A@
RUNTIME_LIB_A = @RUNTIME_LIB_A@
TESTPLUGIN = @TESTPLUGIN@
TESTS = @TESTS@
TEST_LAUNCHER = @TEST_LAUNCHER@
THREADING_H = @THREADING_H@

Modified src/Makefile from [f5abc14455] to [dc55b4be53].

1
2
3
4
5
6
7
8
9
10
include ../extra.mk

SUBDIRS = exceptions

SHARED_LIB = ${OBJFW_SHARED_LIB}
STATIC_LIB = ${OBJFW_STATIC_LIB}
LIB_MAJOR = ${OBJFW_LIB_MAJOR}
LIB_MINOR = ${OBJFW_LIB_MINOR}

SRCS = OFApplication.m			\


|







1
2
3
4
5
6
7
8
9
10
include ../extra.mk

SUBDIRS = exceptions ${RUNTIME}

SHARED_LIB = ${OBJFW_SHARED_LIB}
STATIC_LIB = ${OBJFW_STATIC_LIB}
LIB_MAJOR = ${OBJFW_LIB_MAJOR}
LIB_MINOR = ${OBJFW_LIB_MINOR}

SRCS = OFApplication.m			\
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
	${OFSTREAMOBSERVER_POLL_M}	\
	${OFSTREAMOBSERVER_SELECT_M}	\
	OFString_UTF8.m			\
	OFTCPSocket+SOCKS5.m		\
	${ASPRINTF_M}			\
	${FOUNDATION_COMPAT_M}		\
	iso_8859_15.m			\
	windows_1252.m			\
	${OBJC_PROPERTIES_M}		\
	${OBJC_SYNC_M}

OBJS_EXTRA = ${EXCEPTIONS_EXCEPTIONS_A}
LIB_OBJS_EXTRA = ${EXCEPTIONS_EXCEPTIONS_LIB_A}

include ../buildsys.mk

CPPFLAGS += -I. -I.. -Iexceptions
LD = ${OBJC}
LDFLAGS += ${REEXPORT_LIBOBJC} ${MACH_ALIAS_LIST}







|
<
<

|
|



|


92
93
94
95
96
97
98
99


100
101
102
103
104
105
106
107
108
	${OFSTREAMOBSERVER_POLL_M}	\
	${OFSTREAMOBSERVER_SELECT_M}	\
	OFString_UTF8.m			\
	OFTCPSocket+SOCKS5.m		\
	${ASPRINTF_M}			\
	${FOUNDATION_COMPAT_M}		\
	iso_8859_15.m			\
	windows_1252.m



OBJS_EXTRA = ${EXCEPTIONS_EXCEPTIONS_A} ${RUNTIME_RUNTIME_A}
LIB_OBJS_EXTRA = ${EXCEPTIONS_EXCEPTIONS_LIB_A} ${RUNTIME_RUNTIME_LIB_A}

include ../buildsys.mk

CPPFLAGS += -I. -I.. -Iexceptions -Iruntime
LD = ${OBJC}
LDFLAGS += ${REEXPORT_LIBOBJC} ${MACH_ALIAS_LIST}

Modified src/OFBlock.m from [76c357f460] to [d9ed74f314].

20
21
22
23
24
25
26


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

#include <assert.h>

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


#endif

#import "OFBlock.h"

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







>
>







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

#include <assert.h>

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

#import "OFBlock.h"

#import "OFAllocFailedException.h"
#import "OFInitializationFailedException.h"
#import "OFNotImplementedException.h"
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
};

@protocol RetainRelease
- retain;
- (void)release;
@end

#if defined(OF_OBJFW_RUNTIME) || defined(OF_GNU_RUNTIME) || \
    defined(OF_OLD_GNU_RUNTIME)
struct objc_abi_class {
	struct objc_abi_metaclass *metaclass;
	const char *superclass, *name;
	unsigned long version, info, instance_size;
	void *ivars, *methodlist, *dtable, *subclass_list, *sibling_class;
	void *protocols, *gc_object_type;
	long abi_version;
	void *ivar_offsets, *properties;
};

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

#ifndef OF_OBJFW_RUNTIME
/* ObjFW-RT already defines those */
enum objc_abi_class_info {
	OBJC_CLASS_INFO_CLASS	  = 0x01,
	OBJC_CLASS_INFO_METACLASS = 0x02
};
#endif


extern void __objc_exec_class(void*);

/* Begin of ObjC module */
static struct objc_abi_metaclass _NSConcreteStackBlock_metaclass = {
	"OFBlock", "OFBlock", "OFStackBlock", 8, OBJC_CLASS_INFO_METACLASS,
	sizeof(struct objc_abi_class), NULL, NULL
};

struct objc_abi_class _NSConcreteStackBlock = {
	&_NSConcreteStackBlock_metaclass, "OFBlock", "OFStackBlock", 8,
	OBJC_CLASS_INFO_CLASS, sizeof(of_block_literal_t), NULL, NULL
};

static struct objc_abi_metaclass _NSConcreteGlobalBlock_metaclass = {
	"OFBlock", "OFBlock", "OFGlobalBlock", 8, OBJC_CLASS_INFO_METACLASS,
	sizeof(struct objc_abi_class), NULL, NULL
};

struct objc_abi_class _NSConcreteGlobalBlock = {
	&_NSConcreteGlobalBlock_metaclass, "OFBlock", "OFGlobalBlock",
	8, OBJC_CLASS_INFO_CLASS, sizeof(of_block_literal_t), NULL, NULL
};

static struct objc_abi_metaclass _NSConcreteMallocBlock_metaclass = {
	"OFBlock", "OFBlock", "OFMallocBlock", 8, OBJC_CLASS_INFO_METACLASS,
	sizeof(struct objc_abi_class), NULL, NULL
};

struct objc_abi_class _NSConcreteMallocBlock = {
	&_NSConcreteMallocBlock_metaclass, "OFBlock", "OFMallocBlock",
	8, OBJC_CLASS_INFO_CLASS, sizeof(of_block_literal_t), NULL, NULL
};

static struct {
	unsigned int unknown;
	struct objc_abi_selector *sel_refs;
	uint16_t cls_def_cnt, cat_def_cnt;
	void *defs[4];
} symtab = { 0, NULL, 3, 0, {


	&_NSConcreteStackBlock, &_NSConcreteGlobalBlock,
	&_NSConcreteMallocBlock, NULL

}};

static struct {
	unsigned long version, size;
	const char *name;
	void *symtab;
} module = { 8, sizeof(module), NULL, &symtab };


static void __attribute__((constructor))
constructor(void)
{
	__objc_exec_class(&module);
}
/* End of ObjC module */







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<

<






>
|


|
|
|







|
|
|







|
|
|












|
>
>
|
|
>
|

|
<
<
<
|
>







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

@protocol RetainRelease
- retain;
- (void)release;
@end






















#ifndef OF_OBJFW_RUNTIME

enum objc_abi_class_info {
	OBJC_CLASS_INFO_CLASS	  = 0x01,
	OBJC_CLASS_INFO_METACLASS = 0x02
};
#endif

#if defined(OF_OBJFW_RUNTIME)
extern void __objc_exec_class(struct objc_abi_module*);

/* Begin of ObjC module */
static struct objc_abi_class _NSConcreteStackBlock_metaclass = {
	(struct objc_abi_class*)(void*)"OFBlock", "OFBlock", "OFStackBlock", 8,
	OBJC_CLASS_INFO_METACLASS, sizeof(struct objc_abi_class), NULL, NULL
};

struct objc_abi_class _NSConcreteStackBlock = {
	&_NSConcreteStackBlock_metaclass, "OFBlock", "OFStackBlock", 8,
	OBJC_CLASS_INFO_CLASS, sizeof(of_block_literal_t), NULL, NULL
};

static struct objc_abi_class _NSConcreteGlobalBlock_metaclass = {
	(struct objc_abi_class*)(void*)"OFBlock", "OFBlock", "OFGlobalBlock", 8,
	OBJC_CLASS_INFO_METACLASS, sizeof(struct objc_abi_class), NULL, NULL
};

struct objc_abi_class _NSConcreteGlobalBlock = {
	&_NSConcreteGlobalBlock_metaclass, "OFBlock", "OFGlobalBlock",
	8, OBJC_CLASS_INFO_CLASS, sizeof(of_block_literal_t), NULL, NULL
};

static struct objc_abi_class _NSConcreteMallocBlock_metaclass = {
	(struct objc_abi_class*)(void*)"OFBlock", "OFBlock", "OFMallocBlock", 8,
	OBJC_CLASS_INFO_METACLASS, sizeof(struct objc_abi_class), NULL, NULL
};

struct objc_abi_class _NSConcreteMallocBlock = {
	&_NSConcreteMallocBlock_metaclass, "OFBlock", "OFMallocBlock",
	8, OBJC_CLASS_INFO_CLASS, sizeof(of_block_literal_t), NULL, NULL
};

static struct {
	unsigned int unknown;
	struct objc_abi_selector *sel_refs;
	uint16_t cls_def_cnt, cat_def_cnt;
	void *defs[4];
} symtab = {
	0, NULL, 3, 0,
	{
		&_NSConcreteStackBlock, &_NSConcreteGlobalBlock,
		&_NSConcreteMallocBlock, NULL
	}
};

static struct objc_abi_module module = {



	8, sizeof(module), NULL, (struct objc_abi_symtab*)&symtab
};

static void __attribute__((constructor))
constructor(void)
{
	__objc_exec_class(&module);
}
/* End of ObjC module */

Modified src/OFIntrospection.m from [3e6c8b04d5] to [e4635330ec].

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

#include "config.h"

#include <stdlib.h>

#if defined(OF_APPLE_RUNTIME) || defined(OF_GNU_RUNTIME)
# import <objc/runtime.h>
#elif defined(OF_OLD_GNU_RUNTIME)
# import <objc/objc-api.h>
#endif

#import "OFIntrospection.h"
#import "OFString.h"
#import "OFArray.h"
#import "OFAutoreleasePool.h"

#import "macros.h"

@implementation OFMethod
#if defined(OF_APPLE_RUNTIME) || defined(OF_GNU_RUNTIME)
- _initWithMethod: (Method)method
{
	self = [super init];

	@try {
		selector = method_getName(method);
		name = [[OFString alloc]
		    initWithCString: sel_getName(selector)
			   encoding: OF_STRING_ENCODING_ASCII];
		typeEncoding = method_getTypeEncoding(method);
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}
#elif defined(OF_OLD_GNU_RUNTIME)
- _initWithMethod: (Method_t)method
{
	self = [super init];

	@try {
		selector = method->method_name;
		name = [[OFString alloc]
		    initWithCString: sel_get_name(selector)
			   encoding: OF_STRING_ENCODING_ASCII];
		typeEncoding = method->method_types;
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}
#endif

- (void)dealloc
{
	[name release];







|

<
<










|















<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







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

#include "config.h"

#include <stdlib.h>

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


#endif

#import "OFIntrospection.h"
#import "OFString.h"
#import "OFArray.h"
#import "OFAutoreleasePool.h"

#import "macros.h"

@implementation OFMethod
#if defined(OF_APPLE_RUNTIME)
- _initWithMethod: (Method)method
{
	self = [super init];

	@try {
		selector = method_getName(method);
		name = [[OFString alloc]
		    initWithCString: sel_getName(selector)
			   encoding: OF_STRING_ENCODING_ASCII];
		typeEncoding = method_getTypeEncoding(method);
	} @catch (id e) {
		[self release];
		@throw e;
	}



















	return self;
}
#endif

- (void)dealloc
{
	[name release];
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
{
	return [OFString stringWithFormat: @"<OFMethod: %@ [%s]>",
					   name, typeEncoding];
}
@end

@implementation OFInstanceVariable
#if defined(OF_APPLE_RUNTIME) || defined(OF_GNU_RUNTIME)
- _initWithIvar: (Ivar)ivar
{
	self = [super init];

	@try {
		name = [[OFString alloc]
		    initWithCString: ivar_getName(ivar)
			   encoding: OF_STRING_ENCODING_ASCII];
		offset = ivar_getOffset(ivar);
		typeEncoding = ivar_getTypeEncoding(ivar);
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}
#elif defined(OF_OLD_GNU_RUNTIME)
- _initWithIvar: (Ivar_t)ivar
{
	self = [super init];

	@try {
		name = [[OFString alloc]
		    initWithCString: ivar->ivar_name
			   encoding: OF_STRING_ENCODING_ASCII];
		offset = ivar->ivar_offset;
		typeEncoding = ivar->ivar_type;
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}
#endif

- (void)dealloc
{
	[name release];







|















<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







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
{
	return [OFString stringWithFormat: @"<OFMethod: %@ [%s]>",
					   name, typeEncoding];
}
@end

@implementation OFInstanceVariable
#if defined(OF_APPLE_RUNTIME)
- _initWithIvar: (Ivar)ivar
{
	self = [super init];

	@try {
		name = [[OFString alloc]
		    initWithCString: ivar_getName(ivar)
			   encoding: OF_STRING_ENCODING_ASCII];
		offset = ivar_getOffset(ivar);
		typeEncoding = ivar_getTypeEncoding(ivar);
	} @catch (id e) {
		[self release];
		@throw e;
	}



















	return self;
}
#endif

- (void)dealloc
{
	[name release];
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
}
@end

#ifdef OF_HAVE_PROPERTIES
@implementation OFProperty
@synthesize name, attributes;

#if defined(OF_APPLE_RUNTIME) || defined(OF_GNU_RUNTIME)
- _initWithProperty: (objc_property_t)property
{
	self = [super init];

	@try {
		name = [[OFString alloc]
		    initWithCString: property_getName(property)







|







130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
}
@end

#ifdef OF_HAVE_PROPERTIES
@implementation OFProperty
@synthesize name, attributes;

#if defined(OF_APPLE_RUNTIME)
- _initWithProperty: (objc_property_t)property
{
	self = [super init];

	@try {
		name = [[OFString alloc]
		    initWithCString: property_getName(property)
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250

- initWithClass: (Class)class
{
	self = [super init];

	@try {
		OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
#if defined(OF_APPLE_RUNTIME) || defined(OF_GNU_RUNTIME)
		Method *methodList;
		Ivar *ivarList;
# ifdef OF_HAVE_PROPERTIES
		objc_property_t *propertyList;
# endif
		unsigned i, count;
#elif defined(OF_OLD_GNU_RUNTIME)
		MethodList_t methodList;
#endif

		classMethods = [[OFMutableArray alloc] init];
		instanceMethods = [[OFMutableArray alloc] init];
		instanceVariables = [[OFMutableArray alloc] init];
#ifdef OF_HAVE_PROPERTIES
		properties = [[OFMutableArray alloc] init];
#endif

#if defined(OF_APPLE_RUNTIME) || defined(OF_GNU_RUNTIME)
		methodList = class_copyMethodList(((OFObject*)class)->isa,
		    &count);
		@try {
			for (i = 0; i < count; i++) {
				[classMethods addObject: [[[OFMethod alloc]
				    _initWithMethod: methodList[i]]
				    autorelease]];







|






<
<









|







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

- initWithClass: (Class)class
{
	self = [super init];

	@try {
		OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
#if defined(OF_APPLE_RUNTIME)
		Method *methodList;
		Ivar *ivarList;
# ifdef OF_HAVE_PROPERTIES
		objc_property_t *propertyList;
# endif
		unsigned i, count;


#endif

		classMethods = [[OFMutableArray alloc] init];
		instanceMethods = [[OFMutableArray alloc] init];
		instanceVariables = [[OFMutableArray alloc] init];
#ifdef OF_HAVE_PROPERTIES
		properties = [[OFMutableArray alloc] init];
#endif

#if defined(OF_APPLE_RUNTIME)
		methodList = class_copyMethodList(((OFObject*)class)->isa,
		    &count);
		@try {
			for (i = 0; i < count; i++) {
				[classMethods addObject: [[[OFMethod alloc]
				    _initWithMethod: methodList[i]]
				    autorelease]];
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
				    _initWithProperty: propertyList[i]]
				    autorelease]];
				[pool releaseObjects];
			}
		} @finally {
			free(propertyList);
		}
#elif defined(OF_OLD_GNU_RUNTIME)
		for (methodList = class->class_pointer->methods;
		    methodList != NULL; methodList = methodList->method_next) {
			int i;

			for (i = 0; i < methodList->method_count; i++) {
				[classMethods addObject: [[[OFMethod alloc]
				    _initWithMethod:
				    &methodList->method_list[i]] autorelease]];
				[pool releaseObjects];
			}
		}

		for (methodList = class->methods; methodList != NULL;
		    methodList = methodList->method_next) {
			int i;

			for (i = 0; i < methodList->method_count; i++) {
				[instanceMethods addObject: [[[OFMethod alloc]
				    _initWithMethod:
				    &methodList->method_list[i]] autorelease]];
				[pool releaseObjects];
			}
		}

		if (class->ivars != NULL) {
			int i;

			for (i = 0; i < class->ivars->ivar_count; i++) {
				[instanceVariables addObject:
				    [[[OFInstanceVariable alloc]
				    _initWithIvar: class->ivars->ivar_list + i]
				    autorelease]];
				[pool releaseObjects];
			}
		}
#endif

		[classMethods makeImmutable];
		[instanceMethods makeImmutable];
		[instanceVariables makeImmutable];
#ifdef OF_HAVE_PROPERTIES
		[properties makeImmutable];







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







246
247
248
249
250
251
252




































253
254
255
256
257
258
259
				    _initWithProperty: propertyList[i]]
				    autorelease]];
				[pool releaseObjects];
			}
		} @finally {
			free(propertyList);
		}




































#endif

		[classMethods makeImmutable];
		[instanceMethods makeImmutable];
		[instanceVariables makeImmutable];
#ifdef OF_HAVE_PROPERTIES
		[properties makeImmutable];

Modified src/OFObject.h from [84660ce002] to [f1d13468c6].

24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#endif

#include <stddef.h>
#include <stdint.h>
#include <limits.h>

#ifdef OF_OBJFW_RUNTIME
# import <objfw-rt.h>
#else
# import <objc/objc.h>
#endif

#ifdef __has_feature
# if __has_feature(objc_bool)
#  undef YES







|







24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#endif

#include <stddef.h>
#include <stdint.h>
#include <limits.h>

#ifdef OF_OBJFW_RUNTIME
# import "runtime.h"
#else
# import <objc/objc.h>
#endif

#ifdef __has_feature
# if __has_feature(objc_bool)
#  undef YES

Modified src/OFObject.m from [7124c4f433] to [a5886ec856].

36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#import "OFMemoryNotPartOfObjectException.h"
#import "OFNotImplementedException.h"
#import "OFOutOfMemoryException.h"
#import "OFOutOfRangeException.h"

#import "macros.h"

#if (defined(OF_APPLE_RUNTIME) && __OBJC2__) || defined(OF_GNU_RUNTIME)
# import <objc/objc-exception.h>
#elif defined(OF_OBJFW_RUNTIME)
# import <objfw-rt.h>
#elif defined(OF_OLD_GNU_RUNTIME)
# import <objc/Protocol.h>
#endif

#ifdef _WIN32
# include <windows.h>
#endif

#import "OFString.h"







|


|
<
<







36
37
38
39
40
41
42
43
44
45
46


47
48
49
50
51
52
53
#import "OFMemoryNotPartOfObjectException.h"
#import "OFNotImplementedException.h"
#import "OFOutOfMemoryException.h"
#import "OFOutOfRangeException.h"

#import "macros.h"

#if defined(OF_APPLE_RUNTIME) && __OBJC2__
# import <objc/objc-exception.h>
#elif defined(OF_OBJFW_RUNTIME)
# import "runtime.h"


#endif

#ifdef _WIN32
# include <windows.h>
#endif

#import "OFString.h"
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
	(__BIGGEST_ALIGNMENT__ - 1)) & ~(__BIGGEST_ALIGNMENT__ - 1))
#define PRE_IVAR ((struct pre_ivar*)(void*)((char*)self - PRE_IVAR_ALIGN))

#define PRE_MEM_ALIGN ((sizeof(struct pre_mem) + \
	(__BIGGEST_ALIGNMENT__ - 1)) & ~(__BIGGEST_ALIGNMENT__ - 1))
#define PRE_MEM(mem) ((struct pre_mem*)(void*)((char*)mem - PRE_MEM_ALIGN))

#ifdef OF_OLD_GNU_RUNTIME
extern void __objc_update_dispatch_table_for_class(Class);
#endif

static struct {
	Class isa;
} alloc_failed_exception;
static Class autoreleasePool = Nil;

static SEL cxx_construct = NULL;
static SEL cxx_destruct = NULL;

size_t of_pagesize;
size_t of_num_cpus;

#ifdef NEED_OBJC_SYNC_INIT
extern BOOL objc_sync_init();
#endif

#ifdef NEED_OBJC_PROPERTIES_INIT
extern BOOL objc_properties_init();
#endif

#if (defined(OF_APPLE_RUNTIME) && __OBJC2__) || defined(OF_GNU_RUNTIME)
static void
uncaught_exception_handler(id exception)
{
	fprintf(stderr, "\nUnhandled exception:\n%s\n",
	    [[exception description] UTF8String]);
}
#endif







<
<
<
<











|

<
<
<



|







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
	(__BIGGEST_ALIGNMENT__ - 1)) & ~(__BIGGEST_ALIGNMENT__ - 1))
#define PRE_IVAR ((struct pre_ivar*)(void*)((char*)self - PRE_IVAR_ALIGN))

#define PRE_MEM_ALIGN ((sizeof(struct pre_mem) + \
	(__BIGGEST_ALIGNMENT__ - 1)) & ~(__BIGGEST_ALIGNMENT__ - 1))
#define PRE_MEM(mem) ((struct pre_mem*)(void*)((char*)mem - PRE_MEM_ALIGN))





static struct {
	Class isa;
} alloc_failed_exception;
static Class autoreleasePool = Nil;

static SEL cxx_construct = NULL;
static SEL cxx_destruct = NULL;

size_t of_pagesize;
size_t of_num_cpus;

#ifdef OF_OBJFW_RUNTIME
extern BOOL objc_sync_init();



extern BOOL objc_properties_init();
#endif

#if !defined(OF_APPLE_RUNTIME) || defined(__OBJC2__)
static void
uncaught_exception_handler(id exception)
{
	fprintf(stderr, "\nUnhandled exception:\n%s\n",
	    [[exception description] UTF8String]);
}
#endif
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
void
objc_enumerationMutation(id object)
{
	enumeration_mutation_handler(object);
}
#endif

#if defined(HAVE_OBJC_ENUMERATIONMUTATION) && defined(OF_OLD_GNU_RUNTIME)
extern void objc_setEnumerationMutationHandler(void(*handler)(id));
#endif

id
of_alloc_object(Class class, size_t extraSize, size_t extraAlignment,
    void **extra)
{
	OFObject *instance;
	size_t instanceSize;








<
<
<
<







116
117
118
119
120
121
122




123
124
125
126
127
128
129
void
objc_enumerationMutation(id object)
{
	enumeration_mutation_handler(object);
}
#endif





id
of_alloc_object(Class class, size_t extraSize, size_t extraAlignment,
    void **extra)
{
	OFObject *instance;
	size_t instanceSize;

182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
const char*
_NSPrintForDebugger(id object)
{
	return [[object description]
	    cStringWithEncoding: OF_STRING_ENCODING_NATIVE];
}

#ifdef OF_OLD_GNU_RUNTIME
static BOOL
protocol_conformsToProtocol(Protocol *a, Protocol *b)
{
	/*
	 * This function is an ugly workaround for a bug that only happens with
	 * Clang 2.9 together with the libobjc from GCC 4.6.
	 * Since the instance variables of Protocol are @private, we have to
	 * cast them to a struct here in order to access them.
	 */
	struct objc_protocol {
		Class isa;
		const char *protocol_name;
		struct objc_protocol_list *protocol_list;
	} *pa = (struct objc_protocol*)a, *pb = (struct objc_protocol*)b;
	struct objc_protocol_list *pl;
	size_t i;

	if (!strcmp(pa->protocol_name, pb->protocol_name))
		return YES;

	for (pl = pa->protocol_list; pl != NULL; pl = pl->next)
		for (i = 0; i < pl->count; i++)
			if (protocol_conformsToProtocol(pl->list[i], b))
				return YES;

	return NO;
}
#endif

/* References for static linking */
void _references_to_categories_of_OFObject(void)
{
	_OFObject_Serialization_reference = 1;
}

@implementation OFObject
+ (void)load
{
#ifdef NEED_OBJC_SYNC_INIT
	if (!objc_sync_init()) {
		fputs("Runtime error: objc_sync_init() failed!\n", stderr);
		abort();
	}
#endif

#ifdef NEED_OBJC_PROPERTIES_INIT
	if (!objc_properties_init()) {
		fputs("Runtime error: objc_properties_init() failed!\n",
		    stderr);
		abort();
	}
#endif

#if (defined(OF_APPLE_RUNTIME) && __OBJC2__) || defined(OF_GNU_RUNTIME)
	objc_setUncaughtExceptionHandler(uncaught_exception_handler);
#endif

#ifdef HAVE_OBJC_ENUMERATIONMUTATION
	objc_setEnumerationMutationHandler(enumeration_mutation_handler);
#endif








<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<









|




<

<







|







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
const char*
_NSPrintForDebugger(id object)
{
	return [[object description]
	    cStringWithEncoding: OF_STRING_ENCODING_NATIVE];
}































/* References for static linking */
void _references_to_categories_of_OFObject(void)
{
	_OFObject_Serialization_reference = 1;
}

@implementation OFObject
+ (void)load
{
#ifdef OF_OBJFW_RUNTIME
	if (!objc_sync_init()) {
		fputs("Runtime error: objc_sync_init() failed!\n", stderr);
		abort();
	}



	if (!objc_properties_init()) {
		fputs("Runtime error: objc_properties_init() failed!\n",
		    stderr);
		abort();
	}
#endif

#if !defined(OF_APPLE_RUNTIME) || defined(__OBJC2__)
	objc_setUncaughtExceptionHandler(uncaught_exception_handler);
#endif

#ifdef HAVE_OBJC_ENUMERATIONMUTATION
	objc_setEnumerationMutationHandler(enumeration_mutation_handler);
#endif

312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
+ (Class)superclass
{
	return class_getSuperclass(self);
}

+ (BOOL)instancesRespondToSelector: (SEL)selector
{
#ifdef OF_OLD_GNU_RUNTIME
	return class_get_instance_method(self, selector) != METHOD_NULL;
#else
	return class_respondsToSelector(self, selector);
#endif
}

+ (BOOL)conformsToProtocol: (Protocol*)protocol
{
#ifdef OF_OLD_GNU_RUNTIME
	Class c;
	struct objc_protocol_list *pl;
	size_t i;

	for (c = self; c != Nil; c = class_get_super_class(c))
		for (pl = c->protocols; pl != NULL; pl = pl->next)
			for (i = 0; i < pl->count; i++)
				if (protocol_conformsToProtocol(pl->list[i],
				    protocol))
					return YES;

	return NO;
#else
	Class c;

	for (c = self; c != Nil; c = class_getSuperclass(c))
		if (class_conformsToProtocol(c, protocol))
			return YES;

	return NO;
#endif
}

+ (IMP)instanceMethodForSelector: (SEL)selector
{
#if defined(OF_OBJFW_RUNTIME)
	return objc_get_instance_method(self, selector);
#elif defined(OF_OLD_GNU_RUNTIME)
	return method_get_imp(class_get_instance_method(self, selector));
#else
	return class_getMethodImplementation(self, selector);
#endif
}

+ (const char*)typeEncodingForInstanceSelector: (SEL)selector
{
#if defined(OF_OBJFW_RUNTIME)
	const char *ret;

	if ((ret = objc_get_type_encoding(self, selector)) == NULL)
		@throw [OFNotImplementedException exceptionWithClass: self
							    selector: selector];

	return ret;
#elif defined(OF_OLD_GNU_RUNTIME)
	Method_t m;

	if ((m = class_get_instance_method(self, selector)) == NULL ||
	    m->method_types == NULL)
		@throw [OFNotImplementedException exceptionWithClass: self
							    selector: selector];

	return m->method_types;
#else
	Method m;
	const char *ret;

	if ((m = class_getInstanceMethod(self, selector)) == NULL ||
	    (ret = method_getTypeEncoding(m)) == NULL)
		@throw [OFNotImplementedException exceptionWithClass: self







<
<
<

<




<
<
<
<
<
<
<
<
<
<
<
<
<
<







<




<
<
<
<
<

<












<
<
<
<
<
<
<
<
<







267
268
269
270
271
272
273



274

275
276
277
278














279
280
281
282
283
284
285

286
287
288
289





290

291
292
293
294
295
296
297
298
299
300
301
302









303
304
305
306
307
308
309
+ (Class)superclass
{
	return class_getSuperclass(self);
}

+ (BOOL)instancesRespondToSelector: (SEL)selector
{



	return class_respondsToSelector(self, selector);

}

+ (BOOL)conformsToProtocol: (Protocol*)protocol
{














	Class c;

	for (c = self; c != Nil; c = class_getSuperclass(c))
		if (class_conformsToProtocol(c, protocol))
			return YES;

	return NO;

}

+ (IMP)instanceMethodForSelector: (SEL)selector
{





	return class_getMethodImplementation(self, selector);

}

+ (const char*)typeEncodingForInstanceSelector: (SEL)selector
{
#if defined(OF_OBJFW_RUNTIME)
	const char *ret;

	if ((ret = objc_get_type_encoding(self, selector)) == NULL)
		@throw [OFNotImplementedException exceptionWithClass: self
							    selector: selector];

	return ret;









#else
	Method m;
	const char *ret;

	if ((m = class_getInstanceMethod(self, selector)) == NULL ||
	    (ret = method_getTypeEncoding(m)) == NULL)
		@throw [OFNotImplementedException exceptionWithClass: self
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
			      typeEncoding: typeEncoding];
}

+ (IMP)replaceInstanceMethod: (SEL)selector
	  withImplementation: (IMP)implementation
		typeEncoding: (const char*)typeEncoding
{
#if defined(OF_APPLE_RUNTIME) || defined(OF_GNU_RUNTIME)
	return class_replaceMethod(self, selector, implementation,
	    typeEncoding);
#elif defined(OF_OLD_GNU_RUNTIME)
	MethodList_t methodList;

	for (methodList = ((Class)self)->methods; methodList != NULL;
	    methodList = methodList->method_next) {
		int i;

		for (i = 0; i < methodList->method_count; i++) {
			if (sel_eq(methodList->method_list[i].method_name,
			    selector)) {
				IMP oldImp;
				oldImp = methodList->method_list[i].method_imp;

				methodList->method_list[i].method_imp =
				    implementation;

				__objc_update_dispatch_table_for_class(self);

				return oldImp;
			}
		}
	}

	if ((methodList = malloc(sizeof(*methodList))) == NULL)
		@throw [OFOutOfMemoryException
		    exceptionWithClass: self
			 requestedSize: sizeof(*methodList)];

	methodList->method_next = ((Class)self)->methods;
	methodList->method_count = 1;

	methodList->method_list[0].method_name = selector;
	methodList->method_list[0].method_types = typeEncoding;
	methodList->method_list[0].method_imp = implementation;

	((Class)self)->methods = methodList;

	__objc_update_dispatch_table_for_class(self);

	return (IMP)nil;
#else
	@throw [OFNotImplementedException exceptionWithClass: self
						    selector: _cmd];
#endif
}

+ (IMP)replaceClassMethod: (SEL)selector
       withImplementation: (IMP)implementation
	     typeEncoding: (const char*)typeEncoding
{
#if defined(OF_APPLE_RUNTIME) || defined(OF_GNU_RUNTIME)
	return class_replaceMethod(((OFObject*)self)->isa, selector,
	    implementation, typeEncoding);
#elif defined(OF_OLD_GNU_RUNTIME)
	MethodList_t methodList;

	for (methodList = ((Class)self->class_pointer)->methods;
	    methodList != NULL; methodList = methodList->method_next) {
		int i;

		for (i = 0; i < methodList->method_count; i++) {
			if (sel_eq(methodList->method_list[i].method_name,
			    selector)) {
				IMP oldImp;
				oldImp = methodList->method_list[i].method_imp;

				methodList->method_list[i].method_imp =
				    implementation;

				__objc_update_dispatch_table_for_class(
				    (Class)self->class_pointer);

				return oldImp;
			}
		}
	}

	if ((methodList = malloc(sizeof(*methodList))) == NULL)
		@throw [OFOutOfMemoryException
		    exceptionWithClass: self
			 requestedSize: sizeof(*methodList)];

	methodList->method_next = ((Class)self->class_pointer)->methods;
	methodList->method_count = 1;

	methodList->method_list[0].method_name = selector;
	methodList->method_list[0].method_types = typeEncoding;
	methodList->method_list[0].method_imp = implementation;

	((Class)self->class_pointer)->methods = methodList;

	__objc_update_dispatch_table_for_class((Class)self->class_pointer);

	return (IMP)nil;
#else
	@throw [OFNotImplementedException exceptionWithClass: self
						    selector: _cmd];
#endif
}

+ (void)inheritMethodsFromClass: (Class)class
{
	Class superclass = [self superclass];

	if ([self isSubclassOfClass: class])
		return;

#if defined(OF_APPLE_RUNTIME) || defined(OF_GNU_RUNTIME)
	Method *methodList;
	unsigned i, count;

	methodList = class_copyMethodList(((OFObject*)class)->isa, &count);
	@try {
		for (i = 0; i < count; i++) {
			SEL selector = method_getName(methodList[i]);







<


<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






<


<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<









|







346
347
348
349
350
351
352

353
354












































355
356
357
358
359
360

361
362













































363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
			      typeEncoding: typeEncoding];
}

+ (IMP)replaceInstanceMethod: (SEL)selector
	  withImplementation: (IMP)implementation
		typeEncoding: (const char*)typeEncoding
{

	return class_replaceMethod(self, selector, implementation,
	    typeEncoding);












































}

+ (IMP)replaceClassMethod: (SEL)selector
       withImplementation: (IMP)implementation
	     typeEncoding: (const char*)typeEncoding
{

	return class_replaceMethod(((OFObject*)self)->isa, selector,
	    implementation, typeEncoding);













































}

+ (void)inheritMethodsFromClass: (Class)class
{
	Class superclass = [self superclass];

	if ([self isSubclassOfClass: class])
		return;

#if defined(OF_APPLE_RUNTIME)
	Method *methodList;
	unsigned i, count;

	methodList = class_copyMethodList(((OFObject*)class)->isa, &count);
	@try {
		for (i = 0; i < count; i++) {
			SEL selector = method_getName(methodList[i]);
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632

			[self replaceInstanceMethod: selector
				withMethodFromClass: class];
		}
	} @finally {
		free(methodList);
	}
#elif defined(OF_OLD_GNU_RUNTIME)
	MethodList_t methodList;

	for (methodList = class->class_pointer->methods;
	    methodList != NULL; methodList = methodList->method_next) {
		int i;

		for (i = 0; i < methodList->method_count; i++) {
			SEL selector = methodList->method_list[i].method_name;

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

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

	for (methodList = class->methods; methodList != NULL;
	    methodList = methodList->method_next) {
		int i;

		for (i = 0; i < methodList->method_count; i++) {
			SEL selector = methodList->method_list[i].method_name;

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

			[self replaceInstanceMethod: selector
				withMethodFromClass: class];
		}
	}
#else
	@throw [OFNotImplementedException exceptionWithClass: self
						    selector: _cmd];
#endif

	[self inheritMethodsFromClass: [class superclass]];
}

- init
{







|
|

|
|


|
|













|
|


|
|












<
<
<







406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452



453
454
455
456
457
458
459

			[self replaceInstanceMethod: selector
				withMethodFromClass: class];
		}
	} @finally {
		free(methodList);
	}
#elif defined(OF_OBJFW_RUNTIME)
	struct objc_method_list *methodlist;

	for (methodlist = class->isa->methodlist;
	    methodlist != NULL; methodlist = methodlist->next) {
		int i;

		for (i = 0; i < methodlist->count; i++) {
			SEL selector = (SEL)&methodlist->methods[i].sel;

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

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

	for (methodlist = class->methodlist; methodlist != NULL;
	    methodlist = methodlist->next) {
		int i;

		for (i = 0; i < methodlist->count; i++) {
			SEL selector = (SEL)&methodlist->methods[i].sel;

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

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



#endif

	[self inheritMethodsFromClass: [class superclass]];
}

- init
{
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
- (BOOL)isMemberOfClass: (Class)class
{
	return (isa == class);
}

- (BOOL)respondsToSelector: (SEL)selector
{
#ifdef OF_OLD_GNU_RUNTIME
	if (object_is_instance(self))
		return class_get_instance_method(isa, selector) != METHOD_NULL;
	else
		return class_get_class_method(isa, selector) != METHOD_NULL;
#else
	return class_respondsToSelector(isa, selector);
#endif
}

- (BOOL)conformsToProtocol: (Protocol*)protocol
{
	return [isa conformsToProtocol: protocol];
}

- (IMP)methodForSelector: (SEL)selector
{
#if defined(OF_OBJFW_RUNTIME) || defined(OF_OLD_GNU_RUNTIME)
	return objc_msg_lookup(self, selector);
#else
	return class_getMethodImplementation(isa, selector);
#endif
}

- (id)performSelector: (SEL)selector
{
	id (*imp)(id, SEL) = (id(*)(id, SEL))[self methodForSelector: selector];

	return imp(self, selector);







<
<
<
<
<
<

<









<
<
<

<







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
- (BOOL)isMemberOfClass: (Class)class
{
	return (isa == class);
}

- (BOOL)respondsToSelector: (SEL)selector
{






	return class_respondsToSelector(isa, selector);

}

- (BOOL)conformsToProtocol: (Protocol*)protocol
{
	return [isa conformsToProtocol: protocol];
}

- (IMP)methodForSelector: (SEL)selector
{



	return class_getMethodImplementation(isa, selector);

}

- (id)performSelector: (SEL)selector
{
	id (*imp)(id, SEL) = (id(*)(id, SEL))[self methodForSelector: selector];

	return imp(self, selector);
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
	const char *ret;

	if ((ret = objc_get_type_encoding(isa, selector)) == NULL)
		@throw [OFNotImplementedException exceptionWithClass: isa
							    selector: selector];

	return ret;
#elif defined(OF_OLD_GNU_RUNTIME)
	Method_t m;

	if ((m = class_get_instance_method(isa, selector)) == NULL ||
	    m->method_types == NULL)
		@throw [OFNotImplementedException exceptionWithClass: isa
							    selector: selector];

	return m->method_types;
#else
	Method m;
	const char *ret;

	if ((m = class_getInstanceMethod(isa, selector)) == NULL ||
	    (ret = method_getTypeEncoding(m)) == NULL)
		@throw [OFNotImplementedException exceptionWithClass: isa







<
<
<
<
<
<
<
<
<







550
551
552
553
554
555
556









557
558
559
560
561
562
563
	const char *ret;

	if ((ret = objc_get_type_encoding(isa, selector)) == NULL)
		@throw [OFNotImplementedException exceptionWithClass: isa
							    selector: selector];

	return ret;









#else
	Method m;
	const char *ret;

	if ((m = class_getInstanceMethod(isa, selector)) == NULL ||
	    (ret = method_getTypeEncoding(m)) == NULL)
		@throw [OFNotImplementedException exceptionWithClass: isa
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
#endif
}

- autorelease
{
	/*
	 * Cache OFAutoreleasePool since class lookups are expensive with the
	 * GNU runtime.
	 */
	if (autoreleasePool == Nil)
		autoreleasePool = [OFAutoreleasePool class];

	[autoreleasePool addObject: self];

	return self;







|







748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
#endif
}

- autorelease
{
	/*
	 * Cache OFAutoreleasePool since class lookups are expensive with the
	 * GNU ABI.
	 */
	if (autoreleasePool == Nil)
		autoreleasePool = [OFAutoreleasePool class];

	[autoreleasePool addObject: self];

	return self;

Modified src/OFString.m from [a987125a46] to [e165bf4e50].

53
54
55
56
57
58
59





60
61
62
63
64
65
66
	_OFString_Hashing_reference = 1;
	_OFString_JSONValue_reference = 1;
	_OFString_Serialization_reference = 1;
	_OFString_URLEncoding_reference = 1;
	_OFString_XMLEscaping_reference = 1;
	_OFString_XMLUnescaping_reference = 1;
}






int
of_string_check_utf8(const char *cString, size_t cStringLength, size_t *length)
{
	size_t i, tmpLength = cStringLength;
	int UTF8 = 0;








>
>
>
>
>







53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
	_OFString_Hashing_reference = 1;
	_OFString_JSONValue_reference = 1;
	_OFString_Serialization_reference = 1;
	_OFString_URLEncoding_reference = 1;
	_OFString_XMLEscaping_reference = 1;
	_OFString_XMLUnescaping_reference = 1;
}

void _reference_to_OFConstantString(void)
{
	[OFConstantString class];
}

int
of_string_check_utf8(const char *cString, size_t cStringLength, size_t *length)
{
	size_t i, tmpLength = cStringLength;
	int UTF8 = 0;

Modified src/OFThread.m from [ee16dd390b] to [15c3b7304d].

23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#ifndef _WIN32
# include <unistd.h>
# include <sched.h>
#else
# include <windows.h>
#endif

#if defined(OF_GNU_RUNTIME) || defined(OF_OLD_GNU_RUNTIME)
# import <objc/thr.h>
#endif

#import "OFThread.h"
#import "OFList.h"
#import "OFDate.h"
#import "OFAutoreleasePool.h"

#import "OFConditionBroadcastFailedException.h"
#import "OFConditionSignalFailedException.h"







<
<
<
<







23
24
25
26
27
28
29




30
31
32
33
34
35
36
#ifndef _WIN32
# include <unistd.h>
# include <sched.h>
#else
# include <windows.h>
#endif





#import "OFThread.h"
#import "OFList.h"
#import "OFDate.h"
#import "OFAutoreleasePool.h"

#import "OFConditionBroadcastFailedException.h"
#import "OFConditionSignalFailedException.h"
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
static of_tlskey_t threadSelf;

static id
call_main(id object)
{
	OFThread *thread = (OFThread*)object;

#if defined(OF_GNU_RUNTIME) || defined(OF_OLD_GNU_RUNTIME)
	objc_thread_add();
#endif

	if (!of_tlskey_set(threadSelf, thread))
		@throw [OFInitializationFailedException
		    exceptionWithClass: [thread class]];

	/*
	 * Nasty workaround for thread implementations which can't return a
	 * value on join.







<
<
<
<







53
54
55
56
57
58
59




60
61
62
63
64
65
66
static of_tlskey_t threadSelf;

static id
call_main(id object)
{
	OFThread *thread = (OFThread*)object;





	if (!of_tlskey_set(threadSelf, thread))
		@throw [OFInitializationFailedException
		    exceptionWithClass: [thread class]];

	/*
	 * Nasty workaround for thread implementations which can't return a
	 * value on join.
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
	thread->running = OF_THREAD_WAITING_FOR_JOIN;

	[OFTLSKey callAllDestructors];
	[OFAutoreleasePool _releaseAll];

	[thread release];

#if defined(OF_GNU_RUNTIME) || defined(OF_OLD_GNU_RUNTIME)
	objc_thread_remove();
#endif

	return 0;
}

@implementation OFThread
#if defined(OF_HAVE_PROPERTIES) && defined(OF_HAVE_BLOCKS)
@synthesize block;
#endif







<
<
<
<







79
80
81
82
83
84
85




86
87
88
89
90
91
92
	thread->running = OF_THREAD_WAITING_FOR_JOIN;

	[OFTLSKey callAllDestructors];
	[OFAutoreleasePool _releaseAll];

	[thread release];





	return 0;
}

@implementation OFThread
#if defined(OF_HAVE_PROPERTIES) && defined(OF_HAVE_BLOCKS)
@synthesize block;
#endif
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
	}

	[OFTLSKey callAllDestructors];
	[OFAutoreleasePool _releaseAll];

	[thread release];

#if defined(OF_GNU_RUNTIME) || defined(OF_OLD_GNU_RUNTIME)
	objc_thread_remove();
#endif

	of_thread_exit();
}

- initWithObject: (id)object_
{
	self = [super init];








<
<
<
<







211
212
213
214
215
216
217




218
219
220
221
222
223
224
	}

	[OFTLSKey callAllDestructors];
	[OFAutoreleasePool _releaseAll];

	[thread release];





	of_thread_exit();
}

- initWithObject: (id)object_
{
	self = [super init];

Modified src/base64.h from [1cfc5e7ce8] to [86d7b49ac9].

20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# define __STDC_LIMIT_MACROS
#endif
#ifndef __STDC_CONSTANT_MACROS
# define __STDC_CONSTANT_MACROS
#endif

#ifdef OF_OBJFW_RUNTIME
# import <objfw-rt.h>
#else
# import <objc/objc.h>
#endif

@class OFString;
@class OFDataArray;








|







20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# define __STDC_LIMIT_MACROS
#endif
#ifndef __STDC_CONSTANT_MACROS
# define __STDC_CONSTANT_MACROS
#endif

#ifdef OF_OBJFW_RUNTIME
# import "runtime.h"
#else
# import <objc/objc.h>
#endif

@class OFString;
@class OFDataArray;

Modified src/exceptions/Makefile from [5ef5063419] to [9c19595da9].

56
57
58
59
60
61
62
63
64
       OFUnsupportedProtocolException.m		\
       OFWriteFailedException.m

INCLUDES = ${SRCS:.m=.h}

include ../../buildsys.mk

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







|

56
57
58
59
60
61
62
63
64
       OFUnsupportedProtocolException.m		\
       OFWriteFailedException.m

INCLUDES = ${SRCS:.m=.h}

include ../../buildsys.mk

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

Modified src/macros.h from [ef3c33f2fd] to [5266d93197].

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
 */

#import "OFObject.h"

#include <stddef.h>
#include <stdint.h>

#if defined(OF_APPLE_RUNTIME) || defined(OF_GNU_RUNTIME)
# import <objc/runtime.h>
#elif defined(OF_OLD_GNU_RUNTIME)
# import <objc/objc-api.h>
#endif

#ifdef _PSP
# define INTMAX_MAX LONG_LONG_MAX
#endif

#ifdef __GNUC__







|

<
<







15
16
17
18
19
20
21
22
23


24
25
26
27
28
29
30
 */

#import "OFObject.h"

#include <stddef.h>
#include <stdint.h>

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


#endif

#ifdef _PSP
# define INTMAX_MAX LONG_LONG_MAX
#endif

#ifdef __GNUC__
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
# elif defined(__ppc__) || defined(__PPC__)
#  define OF_PPC_ASM
# elif defined(__arm__) || defined(__ARM__)
#  define OF_ARM_ASM
# endif
#endif

#if defined(OF_OLD_GNU_RUNTIME) || defined(OF_OBJFW_RUNTIME)
# define objc_lookUpClass objc_lookup_class
#endif

#ifdef OF_OLD_GNU_RUNTIME
# define class_getInstanceSize class_get_instance_size
# define class_getName class_get_class_name
# define class_getSuperclass class_get_super_class
# define sel_getName sel_get_name
# define sel_registerName sel_get_uid
#endif

#ifndef _WIN32
# define OF_PATH_DELIMITER '/'
#else
# define OF_PATH_DELIMITER '\\'
#endif

extern id objc_getProperty(id, SEL, ptrdiff_t, BOOL);







|



<
<
<
<
<
<
<
<







75
76
77
78
79
80
81
82
83
84
85








86
87
88
89
90
91
92
# elif defined(__ppc__) || defined(__PPC__)
#  define OF_PPC_ASM
# elif defined(__arm__) || defined(__ARM__)
#  define OF_ARM_ASM
# endif
#endif

#ifdef OF_OBJFW_RUNTIME
# define objc_lookUpClass objc_lookup_class
#endif









#ifndef _WIN32
# define OF_PATH_DELIMITER '/'
#else
# define OF_PATH_DELIMITER '\\'
#endif

extern id objc_getProperty(id, SEL, ptrdiff_t, BOOL);

Deleted src/objc_properties.m version [d2cf97ab35].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

#include <assert.h>

#import "OFObject.h"

#ifdef OF_THREADS
# import "threading.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 of_spinlock_t spinlocks[NUM_SPINLOCKS];
#endif

BOOL
objc_properties_init(void)
{
#ifdef OF_THREADS
	size_t i;

	for (i = 0; i < NUM_SPINLOCKS; i++)
		if (!of_spinlock_new(&spinlocks[i]))
			return NO;
#endif

	return YES;
}

id
objc_getProperty(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic)
{
	if (atomic) {
		id *ptr = (id*)(void*)((char*)self + offset);
#ifdef OF_THREADS
		unsigned hash = SPINLOCK_HASH(ptr);

		assert(of_spinlock_lock(&spinlocks[hash]));

		@try {
			return [[*ptr retain] autorelease];
		} @finally {
			assert(of_spinlock_unlock(&spinlocks[hash]));
		}
#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_THREADS
		unsigned hash = SPINLOCK_HASH(ptr);

		assert(of_spinlock_lock(&spinlocks[hash]));

		@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_THREADS
		} @finally {
			assert(of_spinlock_unlock(&spinlocks[hash]));
		}
#endif

		return;
	}

	id *ptr = (id*)(void*)((char*)self + offset);
	id old = *ptr;

	switch (copy) {
	case 0:
		*ptr = [value retain];
		break;
	case 2:
		/*
		 * Apple uses this to indicate that the copy should be mutable.
		 * Please hit them for abusing a poor BOOL!
		 */
		*ptr = [value mutableCopy];
		break;
	default:
		*ptr = [value copy];
	}

	[old release];
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




















































































































































































































































Deleted src/objc_sync.m version [6d549f3b5e].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

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

#include <sys/types.h>

#ifdef OF_OBJFW_RUNTIME
# import <objfw-rt.h>
#else
# import <objc/objc.h>
#endif

#import "threading.h"

struct lock_s {
	id		 object;
	size_t		 count;
	size_t		 recursion;
	of_thread_t	 thread;
	of_mutex_t	 mutex;
};

static of_mutex_t mutex;
static struct lock_s *locks = NULL;
static ssize_t numLocks = 0;

#define SYNC_ERR(f)							\
	{								\
		fprintf(stderr, "WARNING: %s failed in line %d!\n"	\
		    "WARNING: This might result in a race "		\
		    "condition!\n", f, __LINE__);			\
		return 1;						\
	}

BOOL
objc_sync_init(void)
{
	return of_mutex_new(&mutex);
}

int
objc_sync_enter(id object)
{
	ssize_t i;

	if (object == nil)
		return 0;

	if (!of_mutex_lock(&mutex))
		SYNC_ERR("of_mutex_lock(&mutex)");

	for (i = numLocks - 1; i >= 0; i--) {
		if (locks[i].object == object) {
			if (of_thread_is_current(locks[i].thread))
				locks[i].recursion++;
			else {
				/* Make sure objc_sync_exit doesn't free it */
				locks[i].count++;

				/* Unlock so objc_sync_exit can return */
				if (!of_mutex_unlock(&mutex))
					SYNC_ERR("of_mutex_unlock(&mutex)");

				if (!of_mutex_lock(&locks[i].mutex)) {
					of_mutex_unlock(&mutex);
					SYNC_ERR(
					    "of_mutex_lock(&locks[i].mutex");
				}

				if (!of_mutex_lock(&mutex))
					SYNC_ERR("of_mutex_lock(&mutex)");

				assert(locks[i].recursion == 0);

				/* Update lock's active thread */
				locks[i].thread = of_thread_current();
			}

			if (!of_mutex_unlock(&mutex))
				SYNC_ERR("of_mutex_unlock(&mutex)");

			return 0;
		}
	}

	if (locks == NULL) {
		if ((locks = malloc(sizeof(struct lock_s))) == NULL) {
			of_mutex_unlock(&mutex);
			SYNC_ERR("malloc(...)");
		}
	} else {
		struct lock_s *new_locks;

		if ((new_locks = realloc(locks, (numLocks + 1) *
		    sizeof(struct lock_s))) == NULL) {
			of_mutex_unlock(&mutex);
			SYNC_ERR("realloc(...)");
		}

		locks = new_locks;
	}

	locks[numLocks].object = object;
	locks[numLocks].count = 1;
	locks[numLocks].recursion = 0;
	locks[numLocks].thread = of_thread_current();

	if (!of_mutex_new(&locks[numLocks].mutex)) {
		of_mutex_unlock(&mutex);
		SYNC_ERR("of_mutex_new(&locks[numLocks].mutex");
	}

	if (!of_mutex_lock(&locks[numLocks].mutex)) {
		of_mutex_unlock(&mutex);
		SYNC_ERR("of_mutex_lock(&locks[numLocks].mutex");
	}

	numLocks++;

	if (!of_mutex_unlock(&mutex))
		SYNC_ERR("of_mutex_unlock(&mutex)");

	return 0;
}

int
objc_sync_exit(id object)
{
	ssize_t i;

	if (object == nil)
		return 0;

	if (!of_mutex_lock(&mutex))
		SYNC_ERR("of_mutex_lock(&mutex)");

	for (i = numLocks - 1; i >= 0; i--) {
		if (locks[i].object == object) {
			if (locks[i].recursion > 0 &&
			    of_thread_is_current(locks[i].thread)) {
				locks[i].recursion--;

				if (!of_mutex_unlock(&mutex))
					SYNC_ERR("of_mutex_unlock(&mutex)");

				return 0;
			}

			if (!of_mutex_unlock(&locks[i].mutex)) {
				of_mutex_unlock(&mutex);
				SYNC_ERR("of_mutex_unlock(&locks[i].mutex)");
			}

			locks[i].count--;

			if (locks[i].count == 0) {
				struct lock_s *new_locks = NULL;

				if (!of_mutex_free(&locks[i].mutex)) {
					of_mutex_unlock(&mutex);
					SYNC_ERR(
					    "of_mutex_free(&locks[i].mutex");
				}

				numLocks--;
				locks[i] = locks[numLocks];

				if (numLocks == 0) {
					free(locks);
					new_locks = NULL;
				} else if ((new_locks = realloc(locks,
				    numLocks * sizeof(struct lock_s))) ==
				    NULL) {
					of_mutex_unlock(&mutex);
					SYNC_ERR("realloc(...)");
				}

				locks = new_locks;
			}

			if (!of_mutex_unlock(&mutex))
				SYNC_ERR("of_mutex_unlock(&mutex)");

			return 0;
		}
	}

	of_mutex_unlock(&mutex);
	SYNC_ERR("objc_sync_exit()");
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
































































































































































































































































































































































































































Added src/runtime/Makefile version [756512ba6a].























































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

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

SRCS = category.m		\
       class.m			\
       exception.m		\
       hashtable.m		\
       init.m			\
       lookup.m			\
       ${LOOKUP_S}		\
       property.m		\
       protocol.m		\
       selector.m		\
       sparsearray.m		\
       static-instances.m	\
       synchronized.m		\
       threading.m
INCLUDES = runtime.h

include ../../buildsys.mk

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

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









































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

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

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

static struct objc_hashtable *categories = NULL;

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

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

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

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

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

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

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

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

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

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

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

		return;
	}

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

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

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

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

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

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

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

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

void
objc_free_all_categories(void)
{
	uint32_t i;

	if (categories == NULL)
		return;

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

	objc_hashtable_free(categories);
	categories = NULL;
}

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























































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

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

#include <assert.h>

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

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

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

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

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

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

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

	objc_hashtable_set(classes, name, cls);

	return YES;
}

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

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

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

	if (classes == NULL)
		return Nil;

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

	return c;
}

static void
call_method(Class cls, const char *method)
{
	struct objc_method_list *ml;
	SEL selector;
	unsigned int i;

	selector = sel_registerName(method);

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

static BOOL
has_load(Class cls)
{
	struct objc_method_list *ml;
	SEL selector;
	unsigned int i;

	selector = sel_registerName("load");

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

	return NO;
}

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

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

	call_method(cls, "load");

	cls->info |= OBJC_CLASS_INFO_LOADED;
}

void
objc_update_dtable(Class cls)
{
	struct objc_method_list *ml;
	struct objc_category **cats;
	unsigned int i;

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

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

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

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

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

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

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

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

static void
add_subclass(Class cls)
{
	size_t i;

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

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

		return;
	}

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

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

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

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

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

	if (cls->info & OBJC_CLASS_INFO_SETUP)
		return;

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

		if (super == nil)
			return;

		setup_class(super);

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

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

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

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

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

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

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

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

	call_method(cls, "initialize");
}

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

	objc_global_mutex_lock();

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

	setup_class(cls);

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

	initialize_class(cls);

	objc_global_mutex_unlock();
}

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

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

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

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

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

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

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

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

	/* Process load queue */
	for (i = 0; i < load_queue_cnt; i++) {
		setup_class(load_queue[i]);

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

			load_queue_cnt--;

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

			load_queue[i] = load_queue[load_queue_cnt];

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

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

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

	if (cls == NULL)
		return Nil;

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

	objc_global_mutex_lock();

	setup_class(cls);

	objc_global_mutex_unlock();

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

	return cls;
}

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

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

	return cls;
}

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

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

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

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

	return NO;
}

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

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

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

	objc_global_mutex_lock();

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

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

	objc_global_mutex_unlock();

	return NULL;
}

IMP
class_replaceMethod(Class cls, SEL sel, IMP newimp, const char *types)
{
	struct objc_method_list *ml;
	struct objc_category **cats;
	unsigned int i;
	IMP oldimp;

	objc_global_mutex_lock();

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

				ml->methods[i].imp = newimp;
				objc_update_dtable(cls);

				objc_global_mutex_unlock();

				return oldimp;
			}
		}
	}

	if ((cats = objc_categories_for_class(cls)) != NULL) {
		for (; *cats != NULL; cats++) {
			if (cls->info & OBJC_CLASS_INFO_METACLASS)
				ml = (*cats)->class_methods;
			else
				ml = (*cats)->instance_methods;

			for (; ml != NULL; ml = ml->next) {
				for (i = 0; i < ml->count; i++) {
					if (ml->methods[i].sel.uid ==
					    sel->uid) {
						oldimp = ml->methods[i].imp;

						ml->methods[i].imp = newimp;
						objc_update_dtable(cls);

						objc_global_mutex_unlock();

						return oldimp;
					}
				}
			}
		}
	}

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

	ml->next = cls->methodlist;
	ml->count = 1;
	ml->methods[0].sel.uid = sel->uid;
	ml->methods[0].sel.types = types;
	ml->methods[0].imp = newimp;

	cls->methodlist = ml;

	objc_update_dtable(cls);

	objc_global_mutex_unlock();

	return (IMP)nil;
}

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

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

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

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

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

void
objc_free_all_classes(void)
{
	uint32_t i;

	if (classes == NULL)
		return;

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

	objc_hashtable_free(classes);
	classes = NULL;
}

Added src/runtime/exception.m version [c1024e0f89].















































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

#include <stdlib.h>

#import "runtime.h"

static const uint64_t objc_exception_class = 0x474E55434F424A43; /* GNUCOBJC */

#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_FATAL_PHASE1_ERROR	= 3,
	_URC_END_OF_STACK	= 5,
	_URC_HANDLER_FOUND	= 6,
	_URC_INSTALL_CONTEXT	= 7,
	_URC_CONTINUE_UNWIND	= 8
} _Unwind_Reason_Code;

struct objc_exception {
	struct _Unwind_Exception {
		uint64_t class;
		void (*cleanup)(_Unwind_Reason_Code, struct _Unwind_Exception*);
		/*
		 * The Itanium Exception ABI says to have those and never touch
		 * them.
		 */
		uintptr_t private1, private2;
	} exception;
	id object;
	uintptr_t landingpad;
	intptr_t filter;
};

struct lsda {
	uintptr_t region_start, landingpads_start;
	uint8_t typestable_enc;
	const uint8_t *typestable;
	uintptr_t typestable_base;
	uint8_t callsites_enc;
	const uint8_t *callsites, *actiontable;
};

extern _Unwind_Reason_Code _Unwind_RaiseException(struct _Unwind_Exception*);
extern void* _Unwind_GetLanguageSpecificData(struct _Unwind_Context*);
extern uint64_t _Unwind_GetRegionStart(struct _Unwind_Context*);
extern uint64_t _Unwind_GetDataRelBase(struct _Unwind_Context*);
extern uint64_t _Unwind_GetTextRelBase(struct _Unwind_Context*);
extern uint64_t _Unwind_GetIP(struct _Unwind_Context*);
extern void _Unwind_SetIP(struct _Unwind_Context*, uint64_t);
extern void _Unwind_SetGR(struct _Unwind_Context*, int, uint64_t);
extern void _Unwind_DeleteException(struct _Unwind_Exception*);

static objc_uncaught_exception_handler uncaught_exception_handler;

static inline uint64_t
read_leb128(const uint8_t **ptr, uint8_t *bits)
{
	uint64_t value = 0;
	uint8_t shift = 0;

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

	if (bits != NULL)
		*bits = shift;

	return value;
}

static uint64_t
read_uleb128(const uint8_t **ptr)
{
	return read_leb128(ptr, NULL);
}

static int64_t
read_sleb128(const uint8_t **ptr)
{
	uint8_t bits;
	int64_t value;

	value = read_leb128(ptr, &bits);

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

	return value;
}

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

	switch (enc & 0x70) {
	case DW_EH_PE_absptr:
	case DW_EH_PE_pcrel:
	case DW_EH_PE_aligned:
		return 0;
	case DW_EH_PE_funcrel:
		return _Unwind_GetRegionStart(ctx);
	case DW_EH_PE_datarel:
		return _Unwind_GetDataRelBase(ctx);
	case DW_EH_PE_textrel:
		return _Unwind_GetTextRelBase(ctx);
	}

	abort();
}

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

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

	abort();
}

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

	if (enc == DW_EH_PE_aligned)
		/* Not implemented */
		abort();

#define READ_TYPE(type, size)			\
	{					\
		value = *(type*)(void*)*ptr;	\
		*ptr += size;			\
		break;				\
	}

	switch (enc & 0x0F) {
	case DW_EH_PE_absptr:
		READ_TYPE(uintptr_t, sizeof(void*))
	case DW_EH_PE_uleb128:
		value = read_uleb128(ptr);
		break;
	case DW_EH_PE_udata2:
		READ_TYPE(uint16_t, 2)
	case DW_EH_PE_udata4:
		READ_TYPE(uint32_t, 4)
	case DW_EH_PE_udata8:
		READ_TYPE(uint64_t, 8)
	case DW_EH_PE_sleb128:
		value = read_sleb128(ptr);
		break;
	case DW_EH_PE_sdata2:
		READ_TYPE(int16_t, 2)
	case DW_EH_PE_sdata4:
		READ_TYPE(int32_t, 4)
	case DW_EH_PE_sdata8:
		READ_TYPE(int64_t, 8)
	default:
		abort();
	}

#undef READ_TYPE

	return value;
}

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

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

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

	return value;
}

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

	lsda->region_start = _Unwind_GetRegionStart(ctx);
	lsda->landingpads_start = lsda->region_start;
	lsda->typestable = 0;

	if ((landingpads_start_enc = *ptr++) != DW_EH_PE_omit)
		lsda->landingpads_start =
		    read_value(landingpads_start_enc, &ptr);

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

	lsda->typestable_base = get_base(ctx, lsda->typestable_enc);

	lsda->callsites_enc = *ptr++;
	callsites_size = read_uleb128(&ptr);
	lsda->callsites = ptr;

	lsda->actiontable = lsda->callsites + callsites_size;
}

static BOOL
find_callsite(struct _Unwind_Context *ctx, struct lsda *lsda,
    uintptr_t *landingpad, const uint8_t **actionrecords)
{
	uintptr_t ip = _Unwind_GetIP(ctx);
	const uint8_t *ptr;

	*landingpad = 0;
	*actionrecords = NULL;

	ptr = lsda->callsites;
	while (ptr < lsda->actiontable) {
		uintptr_t callsite_start, callsite_len, callsite_landingpad;
		uintptr_t callsite_action;

		callsite_start = lsda->region_start +
		    read_value(lsda->callsites_enc, &ptr);
		callsite_len = read_value(lsda->callsites_enc, &ptr);
		callsite_landingpad = read_value(lsda->callsites_enc, &ptr);
		callsite_action = read_uleb128(&ptr);

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

		if (callsite_start + callsite_len >= ip) {
			if (callsite_landingpad != 0)
				*landingpad = lsda->landingpads_start +
				    callsite_landingpad;
			if (callsite_action != 0)
				*actionrecords = lsda->actiontable +
				    callsite_action - 1;

			return YES;
		}
	}

	return NO;
}

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

	if (class == Nil)
		return YES;

	if (object == nil)
		return NO;

	for (iter = object->isa; iter != Nil; iter = class_getSuperclass(iter))
		if (iter == class)
			return YES;

	return NO;
}

static uint8_t
find_actionrecord(const uint8_t *actionrecords, struct lsda *lsda, int actions,
    BOOL foreign, struct objc_exception *e, intptr_t *filtervalue)
{
	uint8_t found = 0;
	const uint8_t *ptr;
	intptr_t filter, displacement;

	do {
		ptr = actionrecords;
		filter = read_sleb128(&ptr);

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

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

			i = filter * size_for_encoding(lsda->typestable_enc);
			tmp = lsda->typestable - i;
			c = read_value(lsda->typestable_enc, &tmp);
			c = resolve_value(c, lsda->typestable_enc,
			    lsda->typestable - i, lsda->typestable_base);

			class = (c != 0 ? objc_get_class((const char*)c) : Nil);

			if (class_matches(class, e->object)) {
				*filtervalue = filter;
				return (found | HANDLER_FOUND);
			}
		} else if (filter == 0)
			found |= CLEANUP_FOUND;
		else
			abort();
	} while (displacement != 0);

	return found;
}

_Unwind_Reason_Code
__gnu_objc_personality_v0(int version, int actions, uint64_t ex_class,
    struct _Unwind_Exception *ex, struct _Unwind_Context *ctx)
{
	struct objc_exception *e = (struct objc_exception*)ex;
	BOOL foreign = (ex_class != objc_exception_class);
	const uint8_t *lsda_addr, *actionrecords;
	struct lsda lsda;
	uintptr_t landingpad = 0;
	uint8_t found = 0;
	intptr_t filter = 0;

	if (version != 1)
		return _URC_FATAL_PHASE1_ERROR;

	if (ctx == NULL)
		abort();

	/*
	 * We already cached everything we found in phase 1, so we only need
	 * to install the context in phase 2.
	 */
	if (actions & _UA_HANDLER_FRAME && !foreign) {
		/*
		 * For handlers, reg #0 must be the exception's object and reg
		 * #1 the filter.
		 */
		_Unwind_SetGR(ctx, __builtin_eh_return_data_regno(0),
		    __builtin_extend_pointer(e->object));
		_Unwind_SetGR(ctx, __builtin_eh_return_data_regno(1),
		    e->filter);
		_Unwind_SetIP(ctx, e->landingpad);

		return _URC_INSTALL_CONTEXT;
	}

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

	read_lsda(ctx, lsda_addr, &lsda);

	if (!find_callsite(ctx, &lsda, &landingpad, &actionrecords))
		return _URC_CONTINUE_UNWIND;

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

	if (!found)
		return _URC_CONTINUE_UNWIND;

	if (actions & _UA_SEARCH_PHASE) {
		if (!(found & HANDLER_FOUND))
			return _URC_CONTINUE_UNWIND;

		/* Cache it so we don't have to search it again in phase 2 */
		if (!foreign) {
			e->landingpad = landingpad;
			e->filter = filter;
		}

		return _URC_HANDLER_FOUND;
	} else if (actions & _UA_CLEANUP_PHASE) {
		/* For cleanup, reg #0 must be the exception and reg #1 zero */
		_Unwind_SetGR(ctx, __builtin_eh_return_data_regno(0),
		    __builtin_extend_pointer(e));
		_Unwind_SetGR(ctx, __builtin_eh_return_data_regno(1), 0);
		_Unwind_SetIP(ctx, landingpad);

		return _URC_INSTALL_CONTEXT;
	}

	abort();
}

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

void
objc_exception_throw(id object)
{
	struct objc_exception *e;

	if ((e = malloc(sizeof(*e))) == NULL)
		abort();

	e->exception.class = objc_exception_class;
	e->exception.cleanup = cleanup;
	e->exception.private1 = e->exception.private2 = 0;
	e->object = object;

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

	abort();
}

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

	return old;
}

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

















































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

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

#include <assert.h>

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

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

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

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

	return hash;
}

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

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

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

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

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

	return h;
}

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

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

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

		assert(nsize > 0);

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

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

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

				last = nsize;

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

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

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

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

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

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

	last = h->last_idx + 1;

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

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

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

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

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

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

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

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

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

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

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

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

	return -1;
}

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

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

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

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

	if (idx < 0)
		return NULL;

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

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

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

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

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































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

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

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

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

	objc_global_mutex_unlock();
}

void
objc_exit(void)
{
	objc_global_mutex_lock();

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

	objc_global_mutex_unlock();
	objc_global_mutex_free();
}

Added src/runtime/lookup-amd64-elf.S version [a276d12e99].

















































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

.globl objc_msg_lookup
.globl objc_msg_lookup_super

.section .text
objc_msg_lookup:
	testq	%rdi, %rdi
	jz	ret_nil

	movq	(%rdi), %r8
	movq	64(%r8), %r8

lookup:
	movq	(%rsi), %rax
	movzbl	%ah, %ecx
	movzbl	%al, %edx
#ifndef OF_SELUID16
	shrl	$16, %eax

	movq	(%r8,%rax,8), %r8
#endif
	movq	(%r8,%rcx,8), %r8
	movq	(%r8,%rdx,8), %rax

	testq	%rax, %rax
	jz	forward

	ret

forward:
	movq	objc_not_found_handler@GOTPCREL(%rip), %rax
	jmp	*%rax

objc_msg_lookup_super:
	movq	(%rdi), %rax
	testq	%rax, %rax
	jz	ret_nil

	movq	8(%rdi), %r8
	movq	64(%r8), %r8
	movq	%rdi, %rax
	jmp	lookup

ret_nil:
	leaq	nil_method(%rip), %rax
	ret

nil_method:
	movq	%rdi, %rax
	ret

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

Added src/runtime/lookup-amd64-macho.S version [09cb0dc88d].





































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

.globl _objc_msg_lookup
.globl _objc_msg_lookup_super

.section __TEXT, __text, regular, pure_instructions
_objc_msg_lookup:
	testq	%rdi, %rdi
	jz	ret_nil

	movq	(%rdi), %r8
	movq	64(%r8), %r8

lookup:
	movq	(%rsi), %rax
	movzbl	%ah, %ecx
	movzbl	%al, %edx
#ifndef OF_SELUID16
	shrl	$16, %eax

	movq	(%r8,%rax,8), %r8
#endif
	movq	(%r8,%rcx,8), %r8
	movq	(%r8,%rdx,8), %rax

	testq	%rax, %rax
	jz	forward

	ret

forward:
	jmp	_objc_not_found_handler

_objc_msg_lookup_super:
	movq	(%rdi), %rax
	testq	%rax, %rax
	jz	ret_nil

	movq	8(%rdi), %r8
	movq	64(%r8), %r8
	movq	%rdi, %rax
	jmp	lookup

ret_nil:
	leaq	nil_method(%rip), %rax
	ret

nil_method:
	movq	%rdi, %rax
	ret

Added src/runtime/lookup-x86-elf.S version [5b85918f20].

































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

.globl objc_msg_lookup
.globl objc_msg_lookup_super

.section .text
objc_msg_lookup:
	movl	4(%esp), %edx
	testl	%edx, %edx
	jz	ret_nil

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

lookup:
	movl	8(%esp), %eax

#ifndef OF_SELUID16
	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	forward

	ret

forward:
	call	get_eip
.L1:
	addl	$objc_not_found_handler-.L1, %eax
	jmp	*%eax

objc_msg_lookup_super:
	movl	4(%esp), %edx
	cmpl	$0, (%edx)
	je	ret_nil

	movl	4(%edx), %edx
	movl	32(%edx), %edx
	jmp	lookup

ret_nil:
	call	get_eip
.L2:
	addl	$nil_method-.L2, %eax
	ret

nil_method:
	movl	4(%esp), %eax
	ret

get_eip:
	movl	(%esp), %eax
	ret

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

Added src/runtime/lookup.m version [584f60ba59].



























































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

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

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

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

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

		objc_initialize_class(cls);

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

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

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

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

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

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

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

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

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

	imp = objc_sparsearray_get(obj->isa->dtable, (uint32_t)sel->uid);

	if (imp == NULL)
		return objc_not_found_handler(obj, sel);

	return imp;
}

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

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

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

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

	return imp;
}
#endif

Added src/runtime/property.m version [343585f1c5].























































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

#include <string.h>

#include <assert.h>

#import "OFObject.h"

#ifdef OF_THREADS
# import "threading.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 of_spinlock_t spinlocks[NUM_SPINLOCKS];
#endif

BOOL
objc_properties_init(void)
{
#ifdef OF_THREADS
	size_t i;

	for (i = 0; i < NUM_SPINLOCKS; i++)
		if (!of_spinlock_new(&spinlocks[i]))
			return NO;
#endif

	return YES;
}

id
objc_getProperty(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic)
{
	if (atomic) {
		id *ptr = (id*)(void*)((char*)self + offset);
#ifdef OF_THREADS
		unsigned hash = SPINLOCK_HASH(ptr);

		assert(of_spinlock_lock(&spinlocks[hash]));

		@try {
			return [[*ptr retain] autorelease];
		} @finally {
			assert(of_spinlock_unlock(&spinlocks[hash]));
		}
#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_THREADS
		unsigned hash = SPINLOCK_HASH(ptr);

		assert(of_spinlock_lock(&spinlocks[hash]));

		@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_THREADS
		} @finally {
			assert(of_spinlock_unlock(&spinlocks[hash]));
		}
#endif

		return;
	}

	id *ptr = (id*)(void*)((char*)self + offset);
	id old = *ptr;

	switch (copy) {
	case 0:
		*ptr = [value retain];
		break;
	case 2:
		/*
		 * Apple uses this to indicate that the copy should be mutable.
		 * Please hit them for abusing a poor BOOL!
		 */
		*ptr = [value mutableCopy];
		break;
	default:
		*ptr = [value copy];
	}

	[old release];
}

/* 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_THREADS
		unsigned hash = SPINLOCK_HASH(src);

		assert(of_spinlock_lock(&spinlocks[hash]));
#endif

		memcpy(dest, src, size);

#ifdef OF_THREADS
		assert(of_spinlock_unlock(&spinlocks[hash]));
#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_THREADS
		unsigned hash = SPINLOCK_HASH(src);

		assert(of_spinlock_lock(&spinlocks[hash]));
#endif

		memcpy(dest, src, size);

#ifdef OF_THREADS
		assert(of_spinlock_unlock(&spinlocks[hash]));
#endif

		return;
	}

	memcpy(dest, src, size);
}

Added src/runtime/protocol.m version [c72a2fb5f7].





















































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

#include <string.h>

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

@implementation Protocol
@end

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

inline BOOL
protocol_isEqual(Protocol *a, Protocol *b)
{
	return !strcmp(protocol_getName(a), protocol_getName(b));
}

BOOL
protocol_conformsToProtocol(Protocol *a, Protocol *b)
{
	struct objc_protocol_list *pl;
	size_t i;

	if (protocol_isEqual(a, b))
		return YES;

	for (pl = a->protocol_list; pl != NULL; pl = pl->next)
		for (i = 0; i < pl->count; i++)
			if (protocol_conformsToProtocol(pl->list[i], b))
				return YES;

	return NO;
}

BOOL
class_conformsToProtocol(Class cls, Protocol *p)
{
	struct objc_protocol_list *pl;
	struct objc_category **cats;
	long i, j;

	for (pl = cls->protocols; pl != NULL; pl = pl->next)
		for (i = 0; i < pl->count; i++)
			if (protocol_conformsToProtocol(pl->list[i], p))
				return YES;

	objc_global_mutex_lock();

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

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

	objc_global_mutex_unlock();

	return NO;
}

Added src/runtime/runtime-private.h version [3a008110cb].



















































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#import "threading.h"

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

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

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

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

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

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

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

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

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

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

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

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

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

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

struct objc_sparsearray_level3 {
	const void *buckets[256];
	BOOL empty;
};
#else
struct objc_sparsearray_level2 {
	const void *buckets[256];
	BOOL empty;
};
#endif


enum objc_abi_class_info {
	OBJC_CLASS_INFO_CLASS	    = 0x001,
	OBJC_CLASS_INFO_METACLASS   = 0x002,
	OBJC_CLASS_INFO_SETUP	    = 0x100,
	OBJC_CLASS_INFO_LOADED	    = 0x200,
	OBJC_CLASS_INFO_INITIALIZED = 0x400
};

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

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

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

	return (void*)s->buckets[i]->buckets[j]->buckets[k];
#else
	uint8_t i = idx >> 8;
	uint8_t j = idx;

	return (void*)s->buckets[i]->buckets[j];
#endif
}

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

Added src/runtime/runtime.h version [37bafc00ae].

















































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

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

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

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

struct objc_object {
	Class isa;
};

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

struct objc_super {
	id self;
	Class class;
};

struct objc_method {
	struct objc_selector sel;
	IMP imp;
};

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

struct objc_category {
	const char *category_name;
	const char *class_name;
	struct objc_method_list *instance_methods;
	struct objc_method_list *class_methods;
	struct objc_protocol_list *protocols;
};

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

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

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

typedef void (*objc_uncaught_exception_handler)(id);

extern SEL sel_registerName(const char*);
extern const char* sel_getName(SEL);
extern BOOL sel_isEqual(SEL, SEL);
extern Class objc_get_class(const char*);
extern Class objc_lookup_class(const char*);
extern const char* class_getName(Class);
extern Class class_getSuperclass(Class);
extern BOOL class_isKindOfClass(Class, Class);
extern unsigned long class_getInstanceSize(Class);
extern BOOL class_respondsToSelector(Class, SEL);
extern BOOL class_conformsToProtocol(Class, Protocol*);
extern IMP class_getMethodImplementation(Class, SEL);
extern IMP class_replaceMethod(Class, SEL, IMP, const char*);
extern const char* objc_get_type_encoding(Class, SEL);
extern IMP objc_msg_lookup(id, SEL);
extern IMP objc_msg_lookup_super(struct objc_super*, SEL);
extern const char* protocol_getName(Protocol*);
extern BOOL protocol_isEqual(Protocol*, Protocol*);
extern BOOL protocol_conformsToProtocol(Protocol*, Protocol*);
extern void objc_thread_add(void);
extern void objc_thread_remove(void);
extern void objc_exit(void);
extern objc_uncaught_exception_handler objc_setUncaughtExceptionHandler(
    objc_uncaught_exception_handler);

#endif

Added src/runtime/selector.m version [ce39c495db].































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

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

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

#ifndef OF_SELUID16
# define SEL_MAX 0xFFFFFF
#else
# define SEL_MAX 0xFFFF
#endif

static struct objc_hashtable *selectors = NULL;
static uint32_t selectors_cnt = 0;
static struct objc_sparsearray *selector_names = NULL;

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

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

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

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

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

	objc_hashtable_set(selectors, name, rsel);
	objc_sparsearray_set(selector_names, (uint32_t)rsel->uid, name);
}

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

	if ((rsel = objc_hashtable_get(selectors, name)) != NULL)
		return (SEL)rsel;

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

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

	sel->types = NULL;

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

	return (SEL)sel;
}

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

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

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

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

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

	return ret;
}

BOOL
sel_isEqual(SEL sel1, SEL sel2)
{
	return sel1->uid == sel2->uid;
}

void
objc_free_all_selectors(void)
{
	objc_hashtable_free(selectors);
	objc_sparsearray_free(selector_names);

	selectors = NULL;
	selectors_cnt = 0;
	selector_names = NULL;
}

Added src/runtime/sparsearray.m version [921b7b3d3d].



































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

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

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

static struct objc_sparsearray_level2 *empty_level2 = NULL;
#ifndef OF_SELUID16
static struct objc_sparsearray_level3 *empty_level3 = NULL;
#endif

static void
init(void)
{
	uint_fast16_t i;

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

	empty_level2->empty = YES;

#ifndef OF_SELUID16
	empty_level3 = malloc(sizeof(struct objc_sparsearray_level3));
	if (empty_level3 == NULL)
		ERROR("Not enough memory to allocate sparse array!");

	empty_level3->empty = YES;
#endif

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

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

#ifndef OF_SELUID16
	if (empty_level2 == NULL || empty_level3 == NULL)
		init();
#else
	if (empty_level2 == NULL)
		init();
#endif

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

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

	return s;
}

void
objc_sparsearray_copy(struct objc_sparsearray *dst,
    struct objc_sparsearray *src)
{
	uint_fast16_t i, j;
#ifndef OF_SELUID16
	uint_fast16_t k;
#endif
	uint32_t idx;

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

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

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

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

				if (obj == NULL)
					continue;

				idx = (uint32_t)((i << 16) | (j << 8) | k);
				objc_sparsearray_set(dst, idx, obj);
			}
		}
#else
		for (j = 0; j < 256; j++) {
			const void *obj;

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

			if (obj == NULL)
				continue;

			idx = (i << 8) | j;
			objc_sparsearray_set(dst, idx, obj);
		}
#endif
	}
}

void
objc_sparsearray_set(struct objc_sparsearray *s, uint32_t idx, const void *obj)
{
#ifndef OF_SELUID16
	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 (s->buckets[i]->empty) {
		struct objc_sparsearray_level2 *t;
		uint_fast16_t l;

		t = malloc(sizeof(struct objc_sparsearray_level2));

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

		t->empty = NO;

		for (l = 0; l < 256; l++)
#ifndef OF_SELUID16
			t->buckets[l] = empty_level3;
#else
			t->buckets[l] = NULL;
#endif

		s->buckets[i] = t;
	}

#ifndef OF_SELUID16
	if (s->buckets[i]->buckets[j]->empty) {
		struct objc_sparsearray_level3 *t;
		uint_fast16_t l;

		t = malloc(sizeof(struct objc_sparsearray_level3));

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

		t->empty = NO;

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

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

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

void
objc_sparsearray_free(struct objc_sparsearray *s)
{
	uint_fast16_t i;
#ifndef OF_SELUID16
	uint_fast16_t j;
#endif

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

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

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

	free(s);
}

void
objc_sparsearray_cleanup(void)
{
	if (empty_level2 != NULL)
		free(empty_level2);
#ifndef OF_SELUID16
	if (empty_level3 != NULL)
		free(empty_level3);
#endif

	empty_level2 = NULL;
#ifndef OF_SELUID16
	empty_level3 = NULL;
#endif
}

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



































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

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

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

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

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

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

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

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

			static_instances_cnt--;

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

			static_instances[i] =
			    static_instances[static_instances_cnt];

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

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

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

	if (si == NULL)
		return;

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

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

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

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

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

Added src/runtime/synchronized.m version [60cb02c7ef].























































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

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

#include <sys/types.h>

#import "runtime.h"
#import "threading.h"

struct lock_s {
	id		 object;
	size_t		 count;
	size_t		 recursion;
	of_thread_t	 thread;
	of_mutex_t	 mutex;
};

static of_mutex_t mutex;
static struct lock_s *locks = NULL;
static ssize_t numLocks = 0;

#define SYNC_ERR(f)							\
	{								\
		fprintf(stderr, "WARNING: %s failed in line %d!\n"	\
		    "WARNING: This might result in a race "		\
		    "condition!\n", f, __LINE__);			\
		return 1;						\
	}

BOOL
objc_sync_init(void)
{
	return of_mutex_new(&mutex);
}

int
objc_sync_enter(id object)
{
	ssize_t i;

	if (object == nil)
		return 0;

	if (!of_mutex_lock(&mutex))
		SYNC_ERR("of_mutex_lock(&mutex)");

	for (i = numLocks - 1; i >= 0; i--) {
		if (locks[i].object == object) {
			if (of_thread_is_current(locks[i].thread))
				locks[i].recursion++;
			else {
				/* Make sure objc_sync_exit doesn't free it */
				locks[i].count++;

				/* Unlock so objc_sync_exit can return */
				if (!of_mutex_unlock(&mutex))
					SYNC_ERR("of_mutex_unlock(&mutex)");

				if (!of_mutex_lock(&locks[i].mutex)) {
					of_mutex_unlock(&mutex);
					SYNC_ERR(
					    "of_mutex_lock(&locks[i].mutex");
				}

				if (!of_mutex_lock(&mutex))
					SYNC_ERR("of_mutex_lock(&mutex)");

				assert(locks[i].recursion == 0);

				/* Update lock's active thread */
				locks[i].thread = of_thread_current();
			}

			if (!of_mutex_unlock(&mutex))
				SYNC_ERR("of_mutex_unlock(&mutex)");

			return 0;
		}
	}

	if (locks == NULL) {
		if ((locks = malloc(sizeof(struct lock_s))) == NULL) {
			of_mutex_unlock(&mutex);
			SYNC_ERR("malloc(...)");
		}
	} else {
		struct lock_s *new_locks;

		if ((new_locks = realloc(locks, (numLocks + 1) *
		    sizeof(struct lock_s))) == NULL) {
			of_mutex_unlock(&mutex);
			SYNC_ERR("realloc(...)");
		}

		locks = new_locks;
	}

	locks[numLocks].object = object;
	locks[numLocks].count = 1;
	locks[numLocks].recursion = 0;
	locks[numLocks].thread = of_thread_current();

	if (!of_mutex_new(&locks[numLocks].mutex)) {
		of_mutex_unlock(&mutex);
		SYNC_ERR("of_mutex_new(&locks[numLocks].mutex");
	}

	if (!of_mutex_lock(&locks[numLocks].mutex)) {
		of_mutex_unlock(&mutex);
		SYNC_ERR("of_mutex_lock(&locks[numLocks].mutex");
	}

	numLocks++;

	if (!of_mutex_unlock(&mutex))
		SYNC_ERR("of_mutex_unlock(&mutex)");

	return 0;
}

int
objc_sync_exit(id object)
{
	ssize_t i;

	if (object == nil)
		return 0;

	if (!of_mutex_lock(&mutex))
		SYNC_ERR("of_mutex_lock(&mutex)");

	for (i = numLocks - 1; i >= 0; i--) {
		if (locks[i].object == object) {
			if (locks[i].recursion > 0 &&
			    of_thread_is_current(locks[i].thread)) {
				locks[i].recursion--;

				if (!of_mutex_unlock(&mutex))
					SYNC_ERR("of_mutex_unlock(&mutex)");

				return 0;
			}

			if (!of_mutex_unlock(&locks[i].mutex)) {
				of_mutex_unlock(&mutex);
				SYNC_ERR("of_mutex_unlock(&locks[i].mutex)");
			}

			locks[i].count--;

			if (locks[i].count == 0) {
				struct lock_s *new_locks = NULL;

				if (!of_mutex_free(&locks[i].mutex)) {
					of_mutex_unlock(&mutex);
					SYNC_ERR(
					    "of_mutex_free(&locks[i].mutex");
				}

				numLocks--;
				locks[i] = locks[numLocks];

				if (numLocks == 0) {
					free(locks);
					new_locks = NULL;
				} else if ((new_locks = realloc(locks,
				    numLocks * sizeof(struct lock_s))) ==
				    NULL) {
					of_mutex_unlock(&mutex);
					SYNC_ERR("realloc(...)");
				}

				locks = new_locks;
			}

			if (!of_mutex_unlock(&mutex))
				SYNC_ERR("of_mutex_unlock(&mutex)");

			return 0;
		}
	}

	of_mutex_unlock(&mutex);
	SYNC_ERR("objc_sync_exit()");
}

Added src/runtime/threading.m version [92014702e9].













































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

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

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

static objc_mutex_t global_mutex;
static BOOL global_mutex_init = NO;

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

	mutex->count = 0;

	return YES;
}

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

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

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

	return YES;
}

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

	return YES;
}

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

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

	global_mutex_init = YES;
}

void
objc_global_mutex_lock(void)
{
	if (!global_mutex_init)
		objc_global_mutex_new();

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

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

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

Modified tests/Makefile from [8bfcb02596] to [e4f2bfe9b1].

83
84
85
86
87
88
89
90
91
92
	psp-fixup-imports ${PROG_NOINST}
	mksfo "ObjFW Tests" PARAM.SFO
	psp-strip ${PROG_NOINST}
	pack-pbp $@ PARAM.SFO NULL NULL NULL NULL NULL ${PROG_NOINST} NULL

include ../buildsys.mk

CPPFLAGS += -I../src -I../src/exceptions -I.. -DSTDOUT
LIBS := -L../src -lobjfw ${LIBS}
LD = ${OBJC}







|


83
84
85
86
87
88
89
90
91
92
	psp-fixup-imports ${PROG_NOINST}
	mksfo "ObjFW Tests" PARAM.SFO
	psp-strip ${PROG_NOINST}
	pack-pbp $@ PARAM.SFO NULL NULL NULL NULL NULL ${PROG_NOINST} NULL

include ../buildsys.mk

CPPFLAGS += -I../src -I../src/exceptions -I../src/runtime -I.. -DSTDOUT
LIBS := -L../src -lobjfw ${LIBS}
LD = ${OBJC}

Modified tests/OFBlockTests.m from [2ade830512] to [b8c56f759a].

17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include "config.h"

#import "OFBlock.h"
#import "OFString.h"
#import "OFAutoreleasePool.h"

#if defined(OF_OBJFW_RUNTIME)
# include <objfw-rt.h>
#elif defined(OF_APPLE_RUNTIME) || defined(OF_GNU_RUNTIME)
# include <objc/runtime.h>
#elif defined(OF_OLD_GNU_RUNTIME)
# include <objc/objc-api.h>
#endif
#if defined(OF_OLD_GNU_RUNTIME) || defined(OF_OBJFW_RUNTIME)
# define objc_getClass objc_get_class
#endif

#import "TestsAppDelegate.h"

static OFString *module = @"OFBlock";








|
|

<
<

|







17
18
19
20
21
22
23
24
25
26


27
28
29
30
31
32
33
34
35
#include "config.h"

#import "OFBlock.h"
#import "OFString.h"
#import "OFAutoreleasePool.h"

#if defined(OF_OBJFW_RUNTIME)
# include "runtime.h"
#elif defined(OF_APPLE_RUNTIME)
# include <objc/runtime.h>


#endif
#ifdef OF_OBJFW_RUNTIME
# define objc_getClass objc_get_class
#endif

#import "TestsAppDelegate.h"

static OFString *module = @"OFBlock";

Modified tests/plugin/Makefile from [9a218c4a65] to [49897d6981].

1
2
3
4
5
6
7
8
9
PLUGIN_NOINST = TestPlugin${PLUGIN_SUFFIX}
SRCS = TestPlugin.m

include ../../buildsys.mk
include ../../extra.mk

CPPFLAGS += -I../.. -I../../src
LIBS := -L../../src -lobjfw ${LIBS}
LD = ${OBJC}






|


1
2
3
4
5
6
7
8
9
PLUGIN_NOINST = TestPlugin${PLUGIN_SUFFIX}
SRCS = TestPlugin.m

include ../../buildsys.mk
include ../../extra.mk

CPPFLAGS += -I../.. -I../../src -I../../src/runtime
LIBS := -L../../src -lobjfw ${LIBS}
LD = ${OBJC}