1/*
2 * @APPLE_LICENSE_HEADER_START@
3 *
4 * Copyright (c) 1999-2007 Apple Computer, 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-arm.s - ARM code to support objc messaging
26 *
27 ********************************************************************/
28
29#ifdef __arm__
30
31#include <arm/arch.h>
32
33#ifndef _ARM_ARCH_7
34#   error requires armv7
35#endif
36
37.syntax unified
38
39#define MI_EXTERN(var) \
40	.non_lazy_symbol_pointer                        ;\
41L ## var ## $$non_lazy_ptr:                              ;\
42	.indirect_symbol var                            ;\
43	.long 0
44
45#define MI_GET_EXTERN(reg,var)  \
46	movw	reg, :lower16:(L##var##$$non_lazy_ptr-4f-4)  ;\
47	movt	reg, :upper16:(L##var##$$non_lazy_ptr-4f-4)  ;\
484:	add	reg, pc                                     ;\
49	ldr	reg, [reg]
50
51#define MI_CALL_EXTERNAL(var)    \
52	MI_GET_EXTERN(r12,var)  ;\
53	blx     r12
54
55
56#define MI_GET_ADDRESS(reg,var)  \
57	movw	reg, :lower16:(var-4f-4)  ;\
58	movt	reg, :upper16:(var-4f-4)  ;\
594:	add	reg, pc                                     ;\
60
61
62MI_EXTERN(__class_lookupMethodAndLoadCache3)
63MI_EXTERN(___objc_error)
64
65
66// _objc_entryPoints and _objc_exitPoints are used by method dispatch
67// caching code to figure out whether any threads are actively
68// in the cache for dispatching.  The labels surround the asm code
69// that do cache lookups.  The tables are zero-terminated.
70.data
71.private_extern _objc_entryPoints
72_objc_entryPoints:
73	.long   _cache_getImp
74	.long   _objc_msgSend
75	.long   _objc_msgSend_stret
76	.long   _objc_msgSendSuper
77	.long   _objc_msgSendSuper_stret
78	.long   _objc_msgSendSuper2
79	.long   _objc_msgSendSuper2_stret
80	.long   0
81
82.data
83.private_extern _objc_exitPoints
84_objc_exitPoints:
85	.long   LGetImpExit
86	.long   LMsgSendExit
87	.long   LMsgSendStretExit
88	.long   LMsgSendSuperExit
89	.long   LMsgSendSuperStretExit
90	.long   LMsgSendSuper2Exit
91	.long   LMsgSendSuper2StretExit
92	.long   0
93
94
95/********************************************************************
96* List every exit insn from every messenger for debugger use.
97* Format:
98* (
99*   1 word instruction's address
100*   1 word type (ENTER or FAST_EXIT or SLOW_EXIT or NIL_EXIT)
101* )
102* 1 word zero
103*
104* ENTER is the start of a dispatcher
105* FAST_EXIT is method dispatch
106* SLOW_EXIT is uncached method lookup
107* NIL_EXIT is returning zero from a message sent to nil
108* These must match objc-gdb.h.
109********************************************************************/
110
111#define ENTER     1
112#define FAST_EXIT 2
113#define SLOW_EXIT 3
114#define NIL_EXIT  4
115
116.section __DATA,__objc_msg_break
117.globl _gdb_objc_messenger_breakpoints
118_gdb_objc_messenger_breakpoints:
119// contents populated by the macros below
120
121.macro MESSENGER_START
1224:
123	.section __DATA,__objc_msg_break
124	.long 4b
125	.long ENTER
126	.text
127.endmacro
128.macro MESSENGER_END_FAST
1294:
130	.section __DATA,__objc_msg_break
131	.long 4b
132	.long FAST_EXIT
133	.text
134.endmacro
135.macro MESSENGER_END_SLOW
1364:
137	.section __DATA,__objc_msg_break
138	.long 4b
139	.long SLOW_EXIT
140	.text
141.endmacro
142.macro MESSENGER_END_NIL
1434:
144	.section __DATA,__objc_msg_break
145	.long 4b
146	.long NIL_EXIT
147	.text
148.endmacro
149
150
151/********************************************************************
152 * Names for relative labels
153 * DO NOT USE THESE LABELS ELSEWHERE
154 * Reserved labels: 8: 9:
155 ********************************************************************/
156#define LCacheMiss 	8
157#define LCacheMiss_f 	8f
158#define LCacheMiss_b 	8b
159#define LNilReceiver 	9
160#define LNilReceiver_f 	9f
161#define LNilReceiver_b 	9b
162
163
164/********************************************************************
165 * Macro parameters
166 ********************************************************************/
167
168#define NORMAL 0
169#define FPRET 1
170#define FP2RET 2
171#define GETIMP 3
172#define STRET 4
173#define SUPER 5
174#define SUPER2 6
175#define SUPER_STRET 7
176#define SUPER2_STRET 8
177
178
179/********************************************************************
180 *
181 * Structure definitions.
182 *
183 ********************************************************************/
184
185/* objc_super parameter to sendSuper */
186#define RECEIVER         0
187#define CLASS            4
188
189/* Selected field offsets in class structure */
190#define ISA              0
191#define SUPERCLASS       4
192#define CACHE            8
193#define CACHE_MASK      12
194
195/* Selected field offsets in method structure */
196#define METHOD_NAME      0
197#define METHOD_TYPES     4
198#define METHOD_IMP       8
199
200
201//////////////////////////////////////////////////////////////////////
202//
203// ENTRY		functionName
204//
205// Assembly directives to begin an exported function.
206//
207// Takes: functionName - name of the exported function
208//////////////////////////////////////////////////////////////////////
209
210.macro ENTRY /* name */
211	.text
212	.thumb
213	.align 5
214	.globl    _$0
215	.thumb_func
216_$0:
217.endmacro
218
219.macro STATIC_ENTRY /*name*/
220	.text
221	.thumb
222	.align 5
223	.private_extern _$0
224	.thumb_func
225_$0:
226.endmacro
227
228
229//////////////////////////////////////////////////////////////////////
230//
231// END_ENTRY	functionName
232//
233// Assembly directives to end an exported function.  Just a placeholder,
234// a close-parenthesis for ENTRY, until it is needed for something.
235//
236// Takes: functionName - name of the exported function
237//////////////////////////////////////////////////////////////////////
238
239.macro END_ENTRY /* name */
240.endmacro
241
242
243/////////////////////////////////////////////////////////////////////
244//
245// CacheLookup	return-type
246//
247// Locate the implementation for a selector in a class's method cache.
248//
249// Takes:
250//	  $0 = NORMAL, STRET, SUPER, SUPER_STRET, SUPER2, SUPER2_STRET, GETIMP
251//	  r0 or r1 (STRET) = receiver
252//	  r1 or r2 (STRET) = selector
253//	  r9 = class to search in
254//
255// On exit: r9 and r12 clobbered
256//	    (found) calls or returns IMP, eq/ne/r9 set for forwarding
257//	    (not found) jumps to LCacheMiss
258//
259/////////////////////////////////////////////////////////////////////
260
261.macro CacheHit
262
263.if $0 == GETIMP
264	ldr	r0, [r9, #4]		// r0 = bucket->imp
265	MI_GET_ADDRESS(r1, __objc_msgSend_uncached_impcache)
266	teq	r0, r1
267	it	eq
268	moveq	r0, #0			// don't return msgSend_uncached
269	bx	lr			// return imp
270.elseif $0 == NORMAL
271	ldr	r12, [r9, #4]		// r12 = bucket->imp
272					// eq already set for nonstret forward
273	MESSENGER_END_FAST
274	bx	r12			// call imp
275.elseif $0 == STRET
276	ldr	r12, [r9, #4]		// r12 = bucket->imp
277	movs	r9, #1			// r9=1, Z=0 for stret forwarding
278	MESSENGER_END_FAST
279	bx	r12			// call imp
280.elseif $0 == SUPER
281	ldr	r12, [r9, #4]		// r12 = bucket->imp
282	ldr	r9, [r0, #CLASS]	// r9 = class to search for forwarding
283	ldr	r0, [r0, #RECEIVER]	// fetch real receiver
284	tst	r12, r12		// set ne for forwarding (r12!=0)
285	MESSENGER_END_FAST
286	bx	r12			// call imp
287.elseif $0 == SUPER2
288	ldr	r12, [r9, #4]		// r12 = bucket->imp
289	ldr	r9, [r0, #CLASS]
290	ldr	r9, [r9, #SUPERCLASS]	// r9 = class to search for forwarding
291	ldr	r0, [r0, #RECEIVER]	// fetch real receiver
292	tst	r12, r12		// set ne for forwarding (r12!=0)
293	MESSENGER_END_FAST
294	bx	r12			// call imp
295.elseif $0 == SUPER_STRET
296	ldr	r12, [r9, #4]		// r12 = bucket->imp
297	ldr	r9, [r1, #CLASS]	// r9 = class to search for forwarding
298	orr	r9, r9, #1		// r9 = class|1 for super_stret forward
299	ldr	r1, [r1, #RECEIVER]	// fetch real receiver
300	tst	r12, r12		// set ne for forwarding (r12!=0)
301	MESSENGER_END_FAST
302	bx	r12			// call imp
303.elseif $0 == SUPER2_STRET
304	ldr	r12, [r9, #4]		// r12 = bucket->imp
305	ldr	r9, [r1, #CLASS]	// r9 = class to search for forwarding
306	ldr	r9, [r9, #SUPERCLASS]	// r9 = class to search for forwarding
307	orr	r9, r9, #1		// r9 = class|1 for super_stret forward
308	ldr	r1, [r1, #RECEIVER]	// fetch real receiver
309	tst	r12, r12		// set ne for forwarding (r12!=0)
310	MESSENGER_END_FAST
311	bx	r12			// call imp
312.else
313.abort oops
314.endif
315
316.endmacro
317
318.macro CacheLookup
319
320	ldrh	r12, [r9, #CACHE_MASK]	// r12 = mask
321	ldr	r9, [r9, #CACHE]	// r9 = buckets
322.if $0 == STRET  ||  $0 == SUPER_STRET
323	and	r12, r12, r2		// r12 = index = SEL & mask
324.else
325	and	r12, r12, r1		// r12 = index = SEL & mask
326.endif
327	add	r9, r9, r12, LSL #3	// r9 = bucket = buckets+index*8
328	ldr	r12, [r9]		// r12 = bucket->sel
3292:
330.if $0 == STRET  ||  $0 == SUPER_STRET
331	teq	r12, r2
332.else
333	teq	r12, r1
334.endif
335	bne	1f
336	CacheHit $0
3371:
338	cmp	r12, #1
339	blo	LCacheMiss_f		// if (bucket->sel == 0) cache miss
340	it	eq			// if (bucket->sel == 1) cache wrap
341	ldreq	r9, [r9, #4]		// bucket->imp is before first bucket
342	ldr	r12, [r9, #8]!		// r12 = (++bucket)->sel
343	b	2b
344
345.endmacro
346
347
348/********************************************************************
349 * IMP cache_getImp(Class cls, SEL sel)
350 *
351 * On entry:    r0 = class whose cache is to be searched
352 *              r1 = selector to search for
353 *
354 * If found, returns method implementation.
355 * If not found, returns NULL.
356 ********************************************************************/
357
358	STATIC_ENTRY cache_getImp
359
360	mov	r9, r0
361	CacheLookup GETIMP		// returns IMP on success
362
363LCacheMiss:
364	mov     r0, #0          	// return nil if cache miss
365	bx	lr
366
367LGetImpExit:
368	END_ENTRY cache_getImp
369
370
371/********************************************************************
372 *
373 * id objc_msgSend(id self, SEL	_cmd,...);
374 *
375 ********************************************************************/
376
377	ENTRY objc_msgSend
378	MESSENGER_START
379
380	cbz	r0, LNilReceiver_f
381
382	ldr	r9, [r0]		// r9 = self->isa
383	CacheLookup NORMAL
384	// calls IMP or LCacheMiss
385
386LCacheMiss:
387	MESSENGER_END_SLOW
388	ldr	r9, [r0, #ISA]		// class = receiver->isa
389	b	__objc_msgSend_uncached
390
391LNilReceiver:
392	mov     r1, #0
393	MESSENGER_END_NIL
394	bx      lr
395
396LMsgSendExit:
397	END_ENTRY objc_msgSend
398
399
400/********************************************************************
401 * id		objc_msgSend_noarg(id self, SEL op)
402 *
403 * On entry: r0 is the message receiver,
404 *           r1 is the selector
405 ********************************************************************/
406
407	ENTRY objc_msgSend_noarg
408	b 	_objc_msgSend
409	END_ENTRY objc_msgSend_noarg
410
411
412/********************************************************************
413 * void objc_msgSend_stret(void *st_addr, id self, SEL op, ...);
414 *
415 * objc_msgSend_stret is the struct-return form of msgSend.
416 * The ABI calls for r0 to be used as the address of the structure
417 * being returned, with the parameters in the succeeding registers.
418 *
419 * On entry: r0 is the address where the structure is returned,
420 *           r1 is the message receiver,
421 *           r2 is the selector
422 ********************************************************************/
423
424	ENTRY objc_msgSend_stret
425	MESSENGER_START
426
427	cbz	r1, LNilReceiver_f
428
429	ldr	r9, [r1]		// r9 = self->isa
430	CacheLookup STRET
431	// calls IMP or LCacheMiss
432
433LCacheMiss:
434	MESSENGER_END_SLOW
435	ldr	r9, [r1]		// r9 = self->isa
436	b	__objc_msgSend_stret_uncached
437
438LNilReceiver:
439	MESSENGER_END_NIL
440	bx	lr
441
442LMsgSendStretExit:
443	END_ENTRY objc_msgSend_stret
444
445
446/********************************************************************
447 * id objc_msgSendSuper(struct objc_super *super, SEL op, ...)
448 *
449 * struct objc_super {
450 *     id receiver;
451 *     Class cls;	// the class to search
452 * }
453 ********************************************************************/
454
455	ENTRY objc_msgSendSuper
456	MESSENGER_START
457
458	ldr	r9, [r0, #CLASS]	// r9 = struct super->class
459	CacheLookup SUPER
460	// calls IMP or LCacheMiss
461
462LCacheMiss:
463	MESSENGER_END_SLOW
464	ldr	r9, [r0, #CLASS]	// r9 = struct super->class
465	ldr	r0, [r0, #RECEIVER]	// load real receiver
466	b	__objc_msgSend_uncached
467
468LMsgSendSuperExit:
469	END_ENTRY objc_msgSendSuper
470
471
472/********************************************************************
473 * id objc_msgSendSuper2(struct objc_super *super, SEL op, ...)
474 *
475 * struct objc_super {
476 *     id receiver;
477 *     Class cls;	// SUBCLASS of the class to search
478 * }
479 ********************************************************************/
480
481	ENTRY objc_msgSendSuper2
482	MESSENGER_START
483
484	ldr	r9, [r0, #CLASS]	// class = struct super->class
485	ldr     r9, [r9, #SUPERCLASS]   // class = class->superclass
486	CacheLookup SUPER2
487	// calls IMP or LCacheMiss
488
489LCacheMiss:
490	MESSENGER_END_SLOW
491	ldr	r9, [r0, #CLASS]	// class = struct super->class
492	ldr     r9, [r9, #SUPERCLASS]   // class = class->superclass
493	ldr	r0, [r0, #RECEIVER]	// load real receiver
494	b	__objc_msgSend_uncached
495
496LMsgSendSuper2Exit:
497	END_ENTRY objc_msgSendSuper2
498
499
500/********************************************************************
501 * void objc_msgSendSuper_stret(void *st_addr, objc_super *self, SEL op, ...);
502 *
503 * objc_msgSendSuper_stret is the struct-return form of msgSendSuper.
504 * The ABI calls for r0 to be used as the address of the structure
505 * being returned, with the parameters in the succeeding registers.
506 *
507 * On entry: r0 is the address where the structure is returned,
508 *           r1 is the address of the objc_super structure,
509 *           r2 is the selector
510 ********************************************************************/
511
512	ENTRY objc_msgSendSuper_stret
513	MESSENGER_START
514
515	ldr     r9, [r1, #CLASS]	// r9 = struct super->class
516	CacheLookup SUPER_STRET
517	// calls IMP or LCacheMiss
518
519LCacheMiss:
520	MESSENGER_END_SLOW
521	ldr     r9, [r1, #CLASS]	// r9 = struct super->class
522	ldr     r1, [r1, #RECEIVER]	// load real receiver
523	b	__objc_msgSend_stret_uncached
524
525LMsgSendSuperStretExit:
526	END_ENTRY objc_msgSendSuper_stret
527
528
529/********************************************************************
530 * id objc_msgSendSuper2_stret
531 ********************************************************************/
532
533	ENTRY objc_msgSendSuper2_stret
534	MESSENGER_START
535
536	ldr     r9, [r1, #CLASS]	// class = struct super->class
537	ldr     r9, [r9, #SUPERCLASS]	// class = class->superclass
538	CacheLookup SUPER2_STRET
539
540LCacheMiss:
541	MESSENGER_END_SLOW
542	ldr     r9, [r1, #CLASS]	// class = struct super->class
543	ldr     r9, [r9, #SUPERCLASS]	// class = class->superclass
544	ldr	r1, [r1, #RECEIVER]	// load real receiver
545	b	__objc_msgSend_stret_uncached
546
547LMsgSendSuper2StretExit:
548	END_ENTRY objc_msgSendSuper2_stret
549
550
551/********************************************************************
552 *
553 * _objc_msgSend_uncached_impcache
554 * Used to erase method cache entries in-place by
555 * bouncing them to the uncached lookup.
556 *
557 * _objc_msgSend_uncached
558 * _objc_msgSend_stret_uncached
559 * The uncached lookup.
560 *
561 ********************************************************************/
562
563	STATIC_ENTRY _objc_msgSend_uncached_impcache
564	// Method cache version
565
566	// THIS IS NOT A CALLABLE C FUNCTION
567	// Out-of-band Z is 0 (EQ) for normal, 1 (NE) for stret and/or super
568	// Out-of-band r9 is 1 for stret, cls for super, cls|1 for super_stret
569	// Note objc_msgForward_impcache uses the same parameters
570
571	MESSENGER_START
572	nop
573	MESSENGER_END_SLOW
574
575	ite	eq
576	ldreq	r9, [r0]		// normal: r9 = class = self->isa
577	tstne	r9, #1			// low bit clear?
578	beq	__objc_msgSend_uncached	// super: r9 is already the class
579					// stret or super_stret
580	eors	r9, r9, #1		// clear low bit
581	it	eq			// r9 now zero?
582	ldreq	r9, [r1]		// stret: r9 = class = self->isa
583					// super_stret: r9 is already the class
584	b	__objc_msgSend_stret_uncached
585
586	END_ENTRY _objc_msgSend_uncached_impcache
587
588
589	STATIC_ENTRY _objc_msgSend_uncached
590
591	// THIS IS NOT A CALLABLE C FUNCTION
592	// Out-of-band r9 is the class to search
593
594	stmfd	sp!, {r0-r3,r7,lr}
595	add     r7, sp, #16
596
597					// receiver already in r0
598					// selector already in r1
599	mov	r2, r9			// class to search
600
601	MI_CALL_EXTERNAL(__class_lookupMethodAndLoadCache3)
602	mov     r12, r0			// r12 = IMP
603
604	movs	r9, #0			// r9=0, Z=1 for nonstret forwarding
605	ldmfd	sp!, {r0-r3,r7,lr}
606	bx	r12
607
608	END_ENTRY _objc_msgSend_uncached
609
610
611	STATIC_ENTRY _objc_msgSend_stret_uncached
612
613	// THIS IS NOT A CALLABLE C FUNCTION
614	// Out-of-band r9 is the class to search
615
616	stmfd	sp!, {r0-r3,r7,lr}
617	add     r7, sp, #16
618
619	mov 	r0, r1			// receiver
620	mov 	r1, r2			// selector
621	mov	r2, r9			// class to search
622
623	MI_CALL_EXTERNAL(__class_lookupMethodAndLoadCache3)
624	mov     r12, r0			// r12 = IMP
625
626	movs	r9, #1			// r9=1, Z=0 for stret forwarding
627	ldmfd	sp!, {r0-r3,r7,lr}
628	bx	r12
629
630	END_ENTRY _objc_msgSend_stret_uncached
631
632
633/********************************************************************
634*
635* id _objc_msgForward(id self, SEL _cmd,...);
636*
637* _objc_msgForward and _objc_msgForward_stret are the externally-callable
638*   functions returned by things like method_getImplementation().
639* _objc_msgForward_impcache is the function pointer actually stored in
640*   method caches.
641*
642********************************************************************/
643
644	MI_EXTERN(__objc_forward_handler)
645	MI_EXTERN(__objc_forward_stret_handler)
646
647	STATIC_ENTRY   _objc_msgForward_impcache
648	// Method cache version
649
650	// THIS IS NOT A CALLABLE C FUNCTION
651	// Out-of-band Z is 0 (EQ) for normal, 1 (NE) for stret and/or super
652	// Out-of-band r9 is 1 for stret, cls for super, cls|1 for super_stret
653	// Note _objc_msgSend_uncached_impcache uses the same parameters
654
655	MESSENGER_START
656	nop
657	MESSENGER_END_SLOW
658
659	it	ne
660	tstne	r9, #1
661	beq	__objc_msgForward
662	b	__objc_msgForward_stret
663
664	END_ENTRY _objc_msgForward_impcache
665
666
667	ENTRY   _objc_msgForward
668	// Non-stret version
669
670	MI_GET_EXTERN(r12, __objc_forward_handler)
671	ldr	r12, [r12]
672	bx	r12
673
674	END_ENTRY _objc_msgForward
675
676
677	ENTRY   _objc_msgForward_stret
678	// Struct-return version
679
680	MI_GET_EXTERN(r12, __objc_forward_stret_handler)
681	ldr	r12, [r12]
682	bx	r12
683
684	END_ENTRY _objc_msgForward_stret
685
686
687	ENTRY objc_msgSend_debug
688	b	_objc_msgSend
689	END_ENTRY objc_msgSend_debug
690
691	ENTRY objc_msgSendSuper2_debug
692	b	_objc_msgSendSuper2
693	END_ENTRY objc_msgSendSuper2_debug
694
695	ENTRY objc_msgSend_stret_debug
696	b	_objc_msgSend_stret
697	END_ENTRY objc_msgSend_stret_debug
698
699	ENTRY objc_msgSendSuper2_stret_debug
700	b	_objc_msgSendSuper2_stret
701	END_ENTRY objc_msgSendSuper2_stret_debug
702
703
704	ENTRY method_invoke
705	// r1 is method triplet instead of SEL
706	ldr	r12, [r1, #METHOD_IMP]
707	ldr	r1, [r1, #METHOD_NAME]
708	bx	r12
709	END_ENTRY method_invoke
710
711
712	ENTRY method_invoke_stret
713	// r2 is method triplet instead of SEL
714	ldr	r12, [r2, #METHOD_IMP]
715	ldr	r2, [r2, #METHOD_NAME]
716	bx	r12
717	END_ENTRY method_invoke_stret
718
719
720	STATIC_ENTRY _objc_ignored_method
721
722	// self is already in a0
723	bx	lr
724
725	END_ENTRY _objc_ignored_method
726
727
728.section __DATA,__objc_msg_break
729.long 0
730.long 0
731
732#endif
733