2 * @APPLE_LICENSE_HEADER_START@
4 * Copyright (c) 1999-2007 Apple Computer, Inc. All Rights Reserved.
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
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.
21 * @APPLE_LICENSE_HEADER_END@
23 /********************************************************************
25 * objc-msg-arm.s - ARM code to support objc messaging
27 ********************************************************************/
34 # error requires armv7
37 // Set FP=1 on architectures that pass parameters in floating-point registers
50 # define FP_RETURN_ZERO \
64 # define FP_RETURN_ZERO
70 // Define SUPPORT_INDEXED_ISA for targets which store the class in the ISA as
71 // an index in to a class table.
72 // Note, keep this in sync with objc-config.h.
73 // FIXME: Remove this duplication. We should get this from objc-config.h.
74 #if __ARM_ARCH_7K__ >= 2
75 # define SUPPORT_INDEXED_ISA 1
77 # define SUPPORT_INDEXED_ISA 0
80 // Note, keep these in sync with objc-private.h
81 #define ISA_INDEX_IS_NPI 1
82 #define ISA_INDEX_MASK 0x0001FFFC
83 #define ISA_INDEX_SHIFT 2
84 #define ISA_INDEX_BITS 15
85 #define ISA_INDEX_COUNT (1 << ISA_INDEX_BITS)
86 #define ISA_INDEX_MAGIC_MASK 0x001E0001
87 #define ISA_INDEX_MAGIC_VALUE 0x001C0001
91 #define MI_EXTERN(var) \
92 .non_lazy_symbol_pointer ;\
93 L##var##$$non_lazy_ptr: ;\
94 .indirect_symbol var ;\
97 #define MI_GET_EXTERN(reg,var) \
98 movw reg, :lower16:(L##var##$$non_lazy_ptr-7f-4) ;\
99 movt reg, :upper16:(L##var##$$non_lazy_ptr-7f-4) ;\
103 #define MI_GET_ADDRESS(reg,var) \
104 movw reg, :lower16:(var-7f-4) ;\
105 movt reg, :upper16:(var-7f-4) ;\
111 #if SUPPORT_INDEXED_ISA
114 .globl _objc_indexed_classes
115 _objc_indexed_classes:
116 .fill ISA_INDEX_COUNT, 4, 0
122 // _objc_entryPoints and _objc_exitPoints are used by method dispatch
123 // caching code to figure out whether any threads are actively
124 // in the cache for dispatching. The labels surround the asm code
125 // that do cache lookups. The tables are zero-terminated.
128 .private_extern _objc_entryPoints
132 .long _objc_msgSend_stret
133 .long _objc_msgSendSuper
134 .long _objc_msgSendSuper_stret
135 .long _objc_msgSendSuper2
136 .long _objc_msgSendSuper2_stret
137 .long _objc_msgLookup
138 .long _objc_msgLookup_stret
139 .long _objc_msgLookupSuper2
140 .long _objc_msgLookupSuper2_stret
143 .private_extern _objc_exitPoints
145 .long LExit_cache_getImp
146 .long LExit_objc_msgSend
147 .long LExit_objc_msgSend_stret
148 .long LExit_objc_msgSendSuper
149 .long LExit_objc_msgSendSuper_stret
150 .long LExit_objc_msgSendSuper2
151 .long LExit_objc_msgSendSuper2_stret
152 .long LExit_objc_msgLookup
153 .long LExit_objc_msgLookup_stret
154 .long LExit_objc_msgLookupSuper2
155 .long LExit_objc_msgLookupSuper2_stret
159 /********************************************************************
160 * List every exit insn from every messenger for debugger use.
163 * 1 word instruction's address
164 * 1 word type (ENTER or FAST_EXIT or SLOW_EXIT or NIL_EXIT)
168 * ENTER is the start of a dispatcher
169 * FAST_EXIT is method dispatch
170 * SLOW_EXIT is uncached method lookup
171 * NIL_EXIT is returning zero from a message sent to nil
172 * These must match objc-gdb.h.
173 ********************************************************************/
180 .section __DATA,__objc_msg_break
181 .globl _gdb_objc_messenger_breakpoints
182 _gdb_objc_messenger_breakpoints:
183 // contents populated by the macros below
185 .macro MESSENGER_START
187 .section __DATA,__objc_msg_break
192 .macro MESSENGER_END_FAST
194 .section __DATA,__objc_msg_break
199 .macro MESSENGER_END_SLOW
201 .section __DATA,__objc_msg_break
206 .macro MESSENGER_END_NIL
208 .section __DATA,__objc_msg_break
215 /********************************************************************
216 * Names for relative labels
217 * DO NOT USE THESE LABELS ELSEWHERE
218 * Reserved labels: 6: 7: 8: 9:
219 ********************************************************************/
220 // 6: used by CacheLookup
221 // 7: used by MI_GET_ADDRESS etc and MESSENGER_START etc
222 // 8: used by CacheLookup
223 #define LNilReceiver 9
224 #define LNilReceiver_f 9f
225 #define LNilReceiver_b 9b
228 /********************************************************************
230 ********************************************************************/
236 /********************************************************************
238 * Structure definitions.
240 ********************************************************************/
242 /* objc_super parameter to sendSuper */
246 /* Selected field offsets in class structure */
250 #define CACHE_MASK 12
252 /* Selected field offsets in method structure */
253 #define METHOD_NAME 0
254 #define METHOD_TYPES 4
258 //////////////////////////////////////////////////////////////////////
260 // ENTRY functionName
262 // Assembly directives to begin an exported function.
264 // Takes: functionName - name of the exported function
265 //////////////////////////////////////////////////////////////////////
267 .macro ENTRY /* name */
276 .macro STATIC_ENTRY /*name*/
286 //////////////////////////////////////////////////////////////////////
288 // END_ENTRY functionName
290 // Assembly directives to end an exported function. Just a placeholder,
291 // a close-parenthesis for ENTRY, until it is needed for something.
293 // Takes: functionName - name of the exported function
294 //////////////////////////////////////////////////////////////////////
296 .macro END_ENTRY /* name */
301 /////////////////////////////////////////////////////////////////////
303 // CacheLookup NORMAL|STRET
304 // CacheLookup2 NORMAL|STRET
306 // Locate the implementation for a selector in a class's method cache.
309 // $0 = NORMAL, STRET
310 // r0 or r1 (STRET) = receiver
311 // r1 or r2 (STRET) = selector
312 // r9 = class to search in
314 // On exit: r9 clobbered
315 // (found) continues after CacheLookup, IMP in r12, eq set
316 // (not found) continues after CacheLookup2
318 /////////////////////////////////////////////////////////////////////
322 ldrh r12, [r9, #CACHE_MASK] // r12 = mask
323 ldr r9, [r9, #CACHE] // r9 = buckets
325 and r12, r12, r2 // r12 = index = SEL & mask
327 and r12, r12, r1 // r12 = index = SEL & mask
329 add r9, r9, r12, LSL #3 // r9 = bucket = buckets+index*8
330 ldr r12, [r9] // r12 = bucket->sel
338 ldr r12, [r9, #4] // r12 = bucket->imp
341 tst r12, r12 // set ne for stret forwarding
343 // eq already set for nonstret forwarding by `teq` above
352 blo 8f // if (bucket->sel == 0) cache miss
353 it eq // if (bucket->sel == 1) cache wrap
354 ldreq r9, [r9, #4] // bucket->imp is before first bucket
355 ldr r12, [r9, #8]! // r12 = (++bucket)->sel
361 /////////////////////////////////////////////////////////////////////
363 // GetClassFromIsa return-type
365 // Given an Isa, return the class for the Isa.
370 // On exit: r12 clobbered
371 // r9 contains the class for this Isa.
373 /////////////////////////////////////////////////////////////////////
374 .macro GetClassFromIsa
376 #if SUPPORT_INDEXED_ISA
377 // Note: We are doing a little wasted work here to load values we might not
378 // need. Branching turns out to be even worse when performance was measured.
379 MI_GET_ADDRESS(r12, _objc_indexed_classes)
380 tst.w r9, #ISA_INDEX_IS_NPI
382 ubfxne r9, r9, #ISA_INDEX_SHIFT, #ISA_INDEX_BITS
383 ldrne.w r9, [r12, r9, lsl #2]
389 /********************************************************************
390 * IMP cache_getImp(Class cls, SEL sel)
392 * On entry: r0 = class whose cache is to be searched
393 * r1 = selector to search for
395 * If found, returns method implementation.
396 * If not found, returns NULL.
397 ********************************************************************/
399 STATIC_ENTRY _cache_getImp
403 // cache hit, IMP in r12
408 // cache miss, return nil
412 END_ENTRY _cache_getImp
415 /********************************************************************
417 * id objc_msgSend(id self, SEL _cmd, ...);
418 * IMP objc_msgLookup(id self, SEL _cmd, ...);
420 * objc_msgLookup ABI:
421 * IMP returned in r12
422 * Forwarding returned in Z flag
423 * r9 reserved for our use but not used
425 ********************************************************************/
430 cbz r0, LNilReceiver_f
432 ldr r9, [r0] // r9 = self->isa
433 GetClassFromIsa // r9 = class
435 // cache hit, IMP in r12, eq already set for nonstret forwarding
441 ldr r9, [r0] // r9 = self->isa
442 GetClassFromIsa // r9 = class
444 b __objc_msgSend_uncached
447 // r0 is already zero
455 END_ENTRY _objc_msgSend
458 ENTRY _objc_msgLookup
460 cbz r0, LNilReceiver_f
462 ldr r9, [r0] // r9 = self->isa
463 GetClassFromIsa // r9 = class
465 // cache hit, IMP in r12, eq already set for nonstret forwarding
470 ldr r9, [r0] // r9 = self->isa
471 GetClassFromIsa // r9 = class
472 b __objc_msgLookup_uncached
475 MI_GET_ADDRESS(r12, __objc_msgNil)
478 END_ENTRY _objc_msgLookup
481 STATIC_ENTRY __objc_msgNil
483 // r0 is already zero
490 END_ENTRY __objc_msgNil
493 /********************************************************************
494 * void objc_msgSend_stret(void *st_addr, id self, SEL op, ...);
495 * IMP objc_msgLookup_stret(void *st_addr, id self, SEL op, ...);
497 * objc_msgSend_stret is the struct-return form of msgSend.
498 * The ABI calls for r0 to be used as the address of the structure
499 * being returned, with the parameters in the succeeding registers.
501 * On entry: r0 is the address where the structure is returned,
502 * r1 is the message receiver,
504 ********************************************************************/
506 ENTRY _objc_msgSend_stret
509 cbz r1, LNilReceiver_f
511 ldr r9, [r1] // r9 = self->isa
512 GetClassFromIsa // r9 = class
514 // cache hit, IMP in r12, ne already set for stret forwarding
520 ldr r9, [r1] // r9 = self->isa
521 GetClassFromIsa // r9 = class
523 b __objc_msgSend_stret_uncached
529 END_ENTRY _objc_msgSend_stret
532 ENTRY _objc_msgLookup_stret
534 cbz r1, LNilReceiver_f
536 ldr r9, [r1] // r9 = self->isa
537 GetClassFromIsa // r9 = class
539 // cache hit, IMP in r12, ne already set for stret forwarding
544 ldr r9, [r1] // r9 = self->isa
545 GetClassFromIsa // r9 = class
546 b __objc_msgLookup_stret_uncached
549 MI_GET_ADDRESS(r12, __objc_msgNil_stret)
552 END_ENTRY _objc_msgLookup_stret
555 STATIC_ENTRY __objc_msgNil_stret
559 END_ENTRY __objc_msgNil_stret
562 /********************************************************************
563 * id objc_msgSendSuper(struct objc_super *super, SEL op, ...)
565 * struct objc_super {
567 * Class cls; // the class to search
569 ********************************************************************/
571 ENTRY _objc_msgSendSuper
574 ldr r9, [r0, #CLASS] // r9 = struct super->class
576 // cache hit, IMP in r12, eq already set for nonstret forwarding
577 ldr r0, [r0, #RECEIVER] // load real receiver
583 ldr r9, [r0, #CLASS] // r9 = struct super->class
584 ldr r0, [r0, #RECEIVER] // load real receiver
586 b __objc_msgSend_uncached
588 END_ENTRY _objc_msgSendSuper
591 /********************************************************************
592 * id objc_msgSendSuper2(struct objc_super *super, SEL op, ...)
594 * struct objc_super {
596 * Class cls; // SUBCLASS of the class to search
598 ********************************************************************/
600 ENTRY _objc_msgSendSuper2
603 ldr r9, [r0, #CLASS] // class = struct super->class
604 ldr r9, [r9, #SUPERCLASS] // class = class->superclass
606 // cache hit, IMP in r12, eq already set for nonstret forwarding
607 ldr r0, [r0, #RECEIVER] // load real receiver
613 ldr r9, [r0, #CLASS] // class = struct super->class
614 ldr r9, [r9, #SUPERCLASS] // class = class->superclass
615 ldr r0, [r0, #RECEIVER] // load real receiver
617 b __objc_msgSend_uncached
619 END_ENTRY _objc_msgSendSuper2
622 ENTRY _objc_msgLookupSuper2
624 ldr r9, [r0, #CLASS] // class = struct super->class
625 ldr r9, [r9, #SUPERCLASS] // class = class->superclass
627 // cache hit, IMP in r12, eq already set for nonstret forwarding
628 ldr r0, [r0, #RECEIVER] // load real receiver
634 ldr r9, [r9, #SUPERCLASS] // r9 = class to search
635 ldr r0, [r0, #RECEIVER] // load real receiver
636 b __objc_msgLookup_uncached
638 END_ENTRY _objc_msgLookupSuper2
641 /********************************************************************
642 * void objc_msgSendSuper_stret(void *st_addr, objc_super *self, SEL op, ...);
644 * objc_msgSendSuper_stret is the struct-return form of msgSendSuper.
645 * The ABI calls for r0 to be used as the address of the structure
646 * being returned, with the parameters in the succeeding registers.
648 * On entry: r0 is the address where the structure is returned,
649 * r1 is the address of the objc_super structure,
651 ********************************************************************/
653 ENTRY _objc_msgSendSuper_stret
656 ldr r9, [r1, #CLASS] // r9 = struct super->class
658 // cache hit, IMP in r12, ne already set for stret forwarding
659 ldr r1, [r1, #RECEIVER] // load real receiver
665 ldr r9, [r1, #CLASS] // r9 = struct super->class
666 ldr r1, [r1, #RECEIVER] // load real receiver
668 b __objc_msgSend_stret_uncached
670 END_ENTRY _objc_msgSendSuper_stret
673 /********************************************************************
674 * id objc_msgSendSuper2_stret
675 ********************************************************************/
677 ENTRY _objc_msgSendSuper2_stret
680 ldr r9, [r1, #CLASS] // class = struct super->class
681 ldr r9, [r9, #SUPERCLASS] // class = class->superclass
683 // cache hit, IMP in r12, ne already set for stret forwarding
684 ldr r1, [r1, #RECEIVER] // load real receiver
690 ldr r9, [r1, #CLASS] // class = struct super->class
691 ldr r9, [r9, #SUPERCLASS] // class = class->superclass
692 ldr r1, [r1, #RECEIVER] // load real receiver
694 b __objc_msgSend_stret_uncached
696 END_ENTRY _objc_msgSendSuper2_stret
699 ENTRY _objc_msgLookupSuper2_stret
701 ldr r9, [r1, #CLASS] // class = struct super->class
702 ldr r9, [r9, #SUPERCLASS] // class = class->superclass
704 // cache hit, IMP in r12, ne already set for stret forwarding
705 ldr r1, [r1, #RECEIVER] // load real receiver
711 ldr r9, [r9, #SUPERCLASS] // r9 = class to search
712 ldr r1, [r1, #RECEIVER] // load real receiver
713 b __objc_msgLookup_stret_uncached
715 END_ENTRY _objc_msgLookupSuper2_stret
718 /////////////////////////////////////////////////////////////////////
720 // MethodTableLookup NORMAL|STRET
722 // Locate the implementation for a selector in a class's method lists.
725 // $0 = NORMAL, STRET
726 // r0 or r1 (STRET) = receiver
727 // r1 or r2 (STRET) = selector
728 // r9 = class to search in
730 // On exit: IMP in r12, eq/ne set for forwarding
732 /////////////////////////////////////////////////////////////////////
734 .macro MethodTableLookup
736 stmfd sp!, {r0-r3,r7,lr}
738 sub sp, #8 // align stack
742 // receiver already in r0
743 // selector already in r1
745 mov r0, r1 // receiver
746 mov r1, r2 // selector
748 mov r2, r9 // class to search
750 blx __class_lookupMethodAndLoadCache3
751 mov r12, r0 // r12 = IMP
754 cmp r12, r12 // set eq for nonstret forwarding
756 tst r12, r12 // set ne for stret forwarding
760 add sp, #8 // align stack
761 ldmfd sp!, {r0-r3,r7,lr}
766 /********************************************************************
768 * _objc_msgSend_uncached
769 * _objc_msgSend_stret_uncached
770 * _objc_msgLookup_uncached
771 * _objc_msgLookup_stret_uncached
772 * The uncached method lookup.
774 ********************************************************************/
776 STATIC_ENTRY __objc_msgSend_uncached
778 // THIS IS NOT A CALLABLE C FUNCTION
779 // Out-of-band r9 is the class to search
781 MethodTableLookup NORMAL // returns IMP in r12
784 END_ENTRY __objc_msgSend_uncached
787 STATIC_ENTRY __objc_msgSend_stret_uncached
789 // THIS IS NOT A CALLABLE C FUNCTION
790 // Out-of-band r9 is the class to search
792 MethodTableLookup STRET // returns IMP in r12
795 END_ENTRY __objc_msgSend_stret_uncached
798 STATIC_ENTRY __objc_msgLookup_uncached
800 // THIS IS NOT A CALLABLE C FUNCTION
801 // Out-of-band r9 is the class to search
803 MethodTableLookup NORMAL // returns IMP in r12
806 END_ENTRY __objc_msgLookup_uncached
809 STATIC_ENTRY __objc_msgLookup_stret_uncached
811 // THIS IS NOT A CALLABLE C FUNCTION
812 // Out-of-band r9 is the class to search
814 MethodTableLookup STRET // returns IMP in r12
817 END_ENTRY __objc_msgLookup_stret_uncached
820 /********************************************************************
822 * id _objc_msgForward(id self, SEL _cmd,...);
824 * _objc_msgForward and _objc_msgForward_stret are the externally-callable
825 * functions returned by things like method_getImplementation().
826 * _objc_msgForward_impcache is the function pointer actually stored in
829 ********************************************************************/
831 MI_EXTERN(__objc_forward_handler)
832 MI_EXTERN(__objc_forward_stret_handler)
834 STATIC_ENTRY __objc_msgForward_impcache
835 // Method cache version
837 // THIS IS NOT A CALLABLE C FUNCTION
838 // Out-of-band Z is 0 (EQ) for normal, 1 (NE) for stret
844 beq __objc_msgForward
845 b __objc_msgForward_stret
847 END_ENTRY __objc_msgForward_impcache
850 ENTRY __objc_msgForward
853 MI_GET_EXTERN(r12, __objc_forward_handler)
857 END_ENTRY __objc_msgForward
860 ENTRY __objc_msgForward_stret
861 // Struct-return version
863 MI_GET_EXTERN(r12, __objc_forward_stret_handler)
867 END_ENTRY __objc_msgForward_stret
870 ENTRY _objc_msgSend_noarg
872 END_ENTRY _objc_msgSend_noarg
874 ENTRY _objc_msgSend_debug
876 END_ENTRY _objc_msgSend_debug
878 ENTRY _objc_msgSendSuper2_debug
879 b _objc_msgSendSuper2
880 END_ENTRY _objc_msgSendSuper2_debug
882 ENTRY _objc_msgSend_stret_debug
883 b _objc_msgSend_stret
884 END_ENTRY _objc_msgSend_stret_debug
886 ENTRY _objc_msgSendSuper2_stret_debug
887 b _objc_msgSendSuper2_stret
888 END_ENTRY _objc_msgSendSuper2_stret_debug
892 // r1 is method triplet instead of SEL
893 ldr r12, [r1, #METHOD_IMP]
894 ldr r1, [r1, #METHOD_NAME]
896 END_ENTRY _method_invoke
899 ENTRY _method_invoke_stret
900 // r2 is method triplet instead of SEL
901 ldr r12, [r2, #METHOD_IMP]
902 ldr r2, [r2, #METHOD_NAME]
904 END_ENTRY _method_invoke_stret
907 .section __DATA,__objc_msg_break