1/*
2 * @APPLE_LICENSE_HEADER_START@
3 *
4 * Copyright (c) 2011 Apple Inc.  All Rights Reserved.
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23/********************************************************************
24 *
25 *  objc-msg-arm64.s - ARM64 code to support objc messaging
26 *
27 ********************************************************************/
28
29#ifdef __arm64__
30
31#include <arm/arch.h>
32
33
34// _objc_entryPoints and _objc_exitPoints are used by method dispatch
35// caching code to figure out whether any threads are actively
36// in the cache for dispatching.  The labels surround the asm code
37// that do cache lookups.  The tables are zero-terminated.
38.data
39.private_extern _objc_entryPoints
40_objc_entryPoints:
41	.quad   _cache_getImp
42	.quad   _objc_msgSend
43	.quad   _objc_msgSendSuper
44	.quad   _objc_msgSendSuper2
45	.quad   0
46
47.data
48.private_extern _objc_exitPoints
49_objc_exitPoints:
50	.quad   LExit_cache_getImp
51	.quad   LExit_objc_msgSend
52	.quad   LExit_objc_msgSendSuper
53	.quad   LExit_objc_msgSendSuper2
54	.quad   0
55
56
57/********************************************************************
58* List every exit insn from every messenger for debugger use.
59* Format:
60* (
61*   1 word instruction's address
62*   1 word type (ENTER or FAST_EXIT or SLOW_EXIT or NIL_EXIT)
63* )
64* 1 word zero
65*
66* ENTER is the start of a dispatcher
67* FAST_EXIT is method dispatch
68* SLOW_EXIT is uncached method lookup
69* NIL_EXIT is returning zero from a message sent to nil
70* These must match objc-gdb.h.
71********************************************************************/
72
73#define ENTER     1
74#define FAST_EXIT 2
75#define SLOW_EXIT 3
76#define NIL_EXIT  4
77
78.section __DATA,__objc_msg_break
79.globl _gdb_objc_messenger_breakpoints
80_gdb_objc_messenger_breakpoints:
81// contents populated by the macros below
82
83.macro MESSENGER_START
844:
85	.section __DATA,__objc_msg_break
86	.quad 4b
87	.quad ENTER
88	.text
89.endmacro
90.macro MESSENGER_END_FAST
914:
92	.section __DATA,__objc_msg_break
93	.quad 4b
94	.quad FAST_EXIT
95	.text
96.endmacro
97.macro MESSENGER_END_SLOW
984:
99	.section __DATA,__objc_msg_break
100	.quad 4b
101	.quad SLOW_EXIT
102	.text
103.endmacro
104.macro MESSENGER_END_NIL
1054:
106	.section __DATA,__objc_msg_break
107	.quad 4b
108	.quad NIL_EXIT
109	.text
110.endmacro
111
112
113/* objc_super parameter to sendSuper */
114#define RECEIVER         0
115#define CLASS            8
116
117/* Selected field offsets in class structure */
118#define SUPERCLASS       8
119#define CACHE            16
120
121/* Selected field offsets in isa field */
122#define ISA_MASK         0x00000001fffffff8
123
124/* Selected field offsets in method structure */
125#define METHOD_NAME      0
126#define METHOD_TYPES     8
127#define METHOD_IMP       16
128
129
130/********************************************************************
131 * ENTRY functionName
132 * STATIC_ENTRY functionName
133 * END_ENTRY functionName
134 ********************************************************************/
135
136.macro ENTRY /* name */
137	.text
138	.align 5
139	.globl    $0
140$0:
141.endmacro
142
143.macro STATIC_ENTRY /*name*/
144	.text
145	.align 5
146	.private_extern $0
147$0:
148.endmacro
149
150.macro END_ENTRY /* name */
151LExit$0:
152.endmacro
153
154
155/********************************************************************
156 *
157 * CacheLookup NORMAL|GETIMP
158 *
159 * Locate the implementation for a selector in a class method cache.
160 *
161 * Takes:
162 *	 x1 = selector
163 *	 x9 = class to be searched
164 *
165 * Kills:
166 * 	 x10,x11,x12, x16,x17
167 *
168 * On exit: (found) exits CacheLookup
169 *                  with x9 = class, x17 = IMP
170 *          (not found) jumps to LCacheMiss
171 *
172 ********************************************************************/
173
174#define NORMAL 0
175#define GETIMP 1
176
177.macro CacheHit
178	MESSENGER_END_FAST
179.if $0 == NORMAL
180	br	x17			// call imp
181.else
182	b	LGetImpHit
183.endif
184.endmacro
185
186.macro CheckMiss
187.if $0 == NORMAL			// miss if bucket->cls == 0
188	cbz	x16, __objc_msgSend_uncached_impcache
189.else
190	cbz	x16, LGetImpMiss
191.endif
192.endmacro
193
194.macro CacheLookup
195	// x1 = SEL, x9 = isa
196	ldp	x10, x11, [x9, #CACHE]	// x10 = buckets, x11 = occupied|mask
197	and	w12, w1, w11		// x12 = _cmd & mask
198	add	x12, x10, x12, LSL #4	// x12 = buckets + ((_cmd & mask)<<4)
199
200	ldp	x16, x17, [x12]		// {x16, x17} = *bucket
2011:	cmp	x16, x1			// if (bucket->sel != _cmd)
202	b.ne	2f			//     scan more
203	CacheHit $0			// call or return imp
204
2052:	// not hit: x12 = not-hit bucket
206	CheckMiss $0			// miss if bucket->cls == 0
207	cmp	x12, x10		// wrap if bucket == buckets
208	b.eq	3f
209	ldp	x16, x17, [x12, #-16]!	// {x16, x17} = *--bucket
210	b	1b			// loop
211
2123:	// wrap: x12 = first bucket, w11 = mask
213	add	x12, x12, w11, UXTW #4	// x12 = buckets+(mask<<4)
214
215	// clone scanning loop to crash instead of hang when cache is corrupt
216
217	ldp	x16, x17, [x12]		// {x16, x17} = *bucket
2181:	cmp	x16, x1			// if (bucket->sel != _cmd)
219	b.ne	2f			//     scan more
220	CacheHit $0			// call or return imp
221
2222:	// not hit: x12 = not-hit bucket
223	CheckMiss $0			// miss if bucket->cls == 0
224	cmp	x12, x10		// wrap if bucket == buckets
225	b.eq	3f
226	ldp	x16, x17, [x12, #-16]!	// {x16, x17} = *--bucket
227	b	1b			// loop
228
2293:	// double wrap - busted
230					// x0 = receiver
231					// x1 = SEL
232	mov	x2, x9			// x2 = isa
233
234.if $0 == GETIMP
235	mov	x0, #0
236	b	_cache_getImp_corrupt_cache_error
237.else
238	b	_objc_msgSend_corrupt_cache_error
239.endif
240
241.endmacro
242
243
244	.data
245	.align 3
246	.globl _objc_debug_taggedpointer_classes
247_objc_debug_taggedpointer_classes:
248	.fill 16, 8, 0
249
250	ENTRY _objc_msgSend
251	MESSENGER_START
252
253	cmp	x0, #0			// nil check and tagged pointer check
254	b.le	LNilOrTagged		//  (MSB tagged pointer looks negative)
255	ldr	x13, [x0]		// x13 = isa
256	and	x9, x13, #ISA_MASK	// x9 = class
257LGetIsaDone:
258	CacheLookup NORMAL		// calls imp or objc_msgSend_uncached
259
260LNilOrTagged:
261	b.eq	LReturnZero		// nil check
262
263	// tagged
264	adrp	x10, _objc_debug_taggedpointer_classes@PAGE
265	add	x10, x10, _objc_debug_taggedpointer_classes@PAGEOFF
266	ubfx	x11, x0, #60, #4
267	ldr	x9, [x10, x11, LSL #3]
268	b	LGetIsaDone
269
270LReturnZero:
271	// x0 is already zero
272	mov	x1, #0
273	movi	d0, #0
274	movi	d1, #0
275	movi	d2, #0
276	movi	d3, #0
277	MESSENGER_END_NIL
278	ret
279
280	END_ENTRY _objc_msgSend
281
282
283	ENTRY _objc_msgSendSuper
284	MESSENGER_START
285
286	ldr	x9, [x0, #CLASS]	// load class to search
287	ldr	x0, [x0, #RECEIVER]	// load real receiver
288	CacheLookup NORMAL		// calls imp or objc_msgSend_uncached
289
290	END_ENTRY _objc_msgSendSuper
291
292
293	ENTRY _objc_msgSendSuper2
294	MESSENGER_START
295
296	ldr	x9, [x0, #CLASS]
297	ldr	x9, [x9, #SUPERCLASS]	// load class to search
298	ldr	x0, [x0, #RECEIVER]	// load real receiver
299	CacheLookup NORMAL
300
301	END_ENTRY _objc_msgSendSuper2
302
303
304	ENTRY _objc_msgSend_noarg
305	b	_objc_msgSend
306	END_ENTRY _objc_msgSend_noarg
307
308
309	STATIC_ENTRY __objc_msgSend_uncached_impcache
310
311	// THIS IS NOT A CALLABLE C FUNCTION
312	// Out-of-band x9 is the class to search
313
314	MESSENGER_START
315
316	// push frame
317	stp	fp, lr, [sp, #-16]!
318	mov	fp, sp
319
320	MESSENGER_END_SLOW
321
322	// save parameter registers: x0..x8, q0..q7
323	sub	sp, sp, #(10*8 + 8*16)
324	stp	q0, q1, [sp, #(0*16)]
325	stp	q2, q3, [sp, #(2*16)]
326	stp	q4, q5, [sp, #(4*16)]
327	stp	q6, q7, [sp, #(6*16)]
328	stp	x0, x1, [sp, #(8*16+0*8)]
329	stp	x2, x3, [sp, #(8*16+2*8)]
330	stp	x4, x5, [sp, #(8*16+4*8)]
331	stp	x6, x7, [sp, #(8*16+6*8)]
332	str	x8,     [sp, #(8*16+8*8)]
333
334	// receiver and selector already in x0 and x1
335	mov	x2, x9
336	bl	__class_lookupMethodAndLoadCache3
337
338	// imp in x0
339	mov	x17, x0
340
341	// restore registers and return
342	ldp	q0, q1, [sp, #(0*16)]
343	ldp	q2, q3, [sp, #(2*16)]
344	ldp	q4, q5, [sp, #(4*16)]
345	ldp	q6, q7, [sp, #(6*16)]
346	ldp	x0, x1, [sp, #(8*16+0*8)]
347	ldp	x2, x3, [sp, #(8*16+2*8)]
348	ldp	x4, x5, [sp, #(8*16+4*8)]
349	ldp	x6, x7, [sp, #(8*16+6*8)]
350	ldr	x8,     [sp, #(8*16+8*8)]
351
352	mov	sp, fp
353	ldp	fp, lr, [sp], #16
354
355	br	x17
356
357	END_ENTRY __objc_msgSend_uncached_impcache
358
359
360.section __LD,__compact_unwind,regular,debug
361	.quad _objc_msgSend
362	.set LUnwind_objc_msgSend, LExit_objc_msgSend-_objc_msgSend
363	.long LUnwind_objc_msgSend
364	.long 0x02000000  // no frame, no SP adjustment
365	.quad 0	 // no personality
366	.quad 0  // no LSDA
367
368.section __LD,__compact_unwind,regular,debug
369	.quad _objc_msgSendSuper
370	.set LUnwind_objc_msgSendSuper, LExit_objc_msgSendSuper-_objc_msgSendSuper
371	.long LUnwind_objc_msgSendSuper
372	.long 0x02000000 // no frame, no SP adjustment
373	.quad 0	 // no personality
374	.quad 0  // no LSDA
375
376.section __LD,__compact_unwind,regular,debug
377	.quad _objc_msgSendSuper2
378	.set LUnwind_objc_msgSendSuper2, LExit_objc_msgSendSuper2-_objc_msgSendSuper2
379	.long LUnwind_objc_msgSendSuper2
380	.long 0x02000000  // no frame, no SP adjustment
381	.quad 0	 // no personality
382	.quad 0  // no LSDA
383
384.section __LD,__compact_unwind,regular,debug
385	.quad __objc_msgSend_uncached_impcache
386	.set LUnwind__objc_msgSend_uncached_impcache, LExit__objc_msgSend_uncached_impcache-__objc_msgSend_uncached_impcache
387	.long LUnwind__objc_msgSend_uncached_impcache
388	.long 0x04000000  // frame, no non-volatile registers saved
389	.quad 0	 // no personality
390	.quad 0  // no LSDA
391
392
393	STATIC_ENTRY _cache_getImp
394
395	and	x9, x0, #ISA_MASK
396	CacheLookup GETIMP
397
398LGetImpHit:
399	// imp in x17
400	// don't return msgSend_uncached
401	adrp	x16, __objc_msgSend_uncached_impcache@PAGE
402	add	x16, x16, __objc_msgSend_uncached_impcache@PAGEOFF
403	cmp	x16, x17
404	csel	x0, x17, xzr, ne	// if imp!=uncached then imp else 0
405	ret
406
407LGetImpMiss:
408	mov	x0, #0
409	ret
410
411	END_ENTRY _cache_getImp
412
413
414/********************************************************************
415*
416* id _objc_msgForward(id self, SEL _cmd,...);
417*
418* _objc_msgForward is the externally-callable
419*   function returned by things like method_getImplementation().
420* _objc_msgForward_impcache is the function pointer actually stored in
421*   method caches.
422*
423********************************************************************/
424
425	STATIC_ENTRY __objc_msgForward_impcache
426
427	MESSENGER_START
428	nop
429	MESSENGER_END_SLOW
430
431	// No stret specialization.
432	b	__objc_msgForward
433
434	END_ENTRY __objc_msgForward_impcache
435
436
437	ENTRY __objc_msgForward
438
439	adrp	x17, __objc_forward_handler@PAGE
440	ldr	x17, [x17, __objc_forward_handler@PAGEOFF]
441	br	x17
442
443	END_ENTRY __objc_msgForward
444
445
446	ENTRY _objc_msgSend_debug
447	b	_objc_msgSend
448	END_ENTRY _objc_msgSend_debug
449
450	ENTRY _objc_msgSendSuper2_debug
451	b	_objc_msgSendSuper2
452	END_ENTRY _objc_msgSendSuper2_debug
453
454
455	ENTRY _method_invoke
456	// x1 is method triplet instead of SEL
457	ldr	x17, [x1, #METHOD_IMP]
458	ldr	x1, [x1, #METHOD_NAME]
459	br	x17
460	END_ENTRY _method_invoke
461
462
463	STATIC_ENTRY __objc_ignored_method
464
465	// self is already in x0
466	ret
467
468	END_ENTRY __objc_ignored_method
469
470#endif
471