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 ********************************************************************/
32 #include "objc-config.h"
36 # error requires armv7
39 // Set FP=1 on architectures that pass parameters in floating-point registers
52 # define FP_RETURN_ZERO \
66 # define FP_RETURN_ZERO
74 #define MI_EXTERN(var) \
75 .non_lazy_symbol_pointer ;\
76 L##var##$$non_lazy_ptr: ;\
77 .indirect_symbol var ;\
80 #define MI_GET_EXTERN(reg,var) \
81 movw reg, :lower16:(L##var##$$non_lazy_ptr-7f-4) ;\
82 movt reg, :upper16:(L##var##$$non_lazy_ptr-7f-4) ;\
86 #define MI_GET_ADDRESS(reg,var) \
87 movw reg, :lower16:(var-7f-4) ;\
88 movt reg, :upper16:(var-7f-4) ;\
94 #if SUPPORT_INDEXED_ISA
97 .globl _objc_indexed_classes
98 _objc_indexed_classes:
99 .fill ISA_INDEX_COUNT, 4, 0
105 // _objc_entryPoints and _objc_exitPoints are used by method dispatch
106 // caching code to figure out whether any threads are actively
107 // in the cache for dispatching. The labels surround the asm code
108 // that do cache lookups. The tables are zero-terminated.
111 .private_extern _objc_entryPoints
115 .long _objc_msgSend_stret
116 .long _objc_msgSendSuper
117 .long _objc_msgSendSuper_stret
118 .long _objc_msgSendSuper2
119 .long _objc_msgSendSuper2_stret
120 .long _objc_msgLookup
121 .long _objc_msgLookup_stret
122 .long _objc_msgLookupSuper2
123 .long _objc_msgLookupSuper2_stret
126 .private_extern _objc_exitPoints
128 .long LExit_cache_getImp
129 .long LExit_objc_msgSend
130 .long LExit_objc_msgSend_stret
131 .long LExit_objc_msgSendSuper
132 .long LExit_objc_msgSendSuper_stret
133 .long LExit_objc_msgSendSuper2
134 .long LExit_objc_msgSendSuper2_stret
135 .long LExit_objc_msgLookup
136 .long LExit_objc_msgLookup_stret
137 .long LExit_objc_msgLookupSuper2
138 .long LExit_objc_msgLookupSuper2_stret
142 /********************************************************************
143 * Names for relative labels
144 * DO NOT USE THESE LABELS ELSEWHERE
145 * Reserved labels: 6: 7: 8: 9:
146 ********************************************************************/
147 // 6: used by CacheLookup
148 // 7: used by MI_GET_ADDRESS etc
149 // 8: used by CacheLookup
150 #define LNilReceiver 9
151 #define LNilReceiver_f 9f
152 #define LNilReceiver_b 9b
155 /********************************************************************
157 ********************************************************************/
163 /********************************************************************
165 * Structure definitions.
167 ********************************************************************/
169 /* objc_super parameter to sendSuper */
173 /* Selected field offsets in class structure */
177 #define CACHE_MASK 12
179 /* Field offsets in method cache bucket */
183 /* Selected field offsets in method structure */
184 #define METHOD_NAME 0
185 #define METHOD_TYPES 4
189 //////////////////////////////////////////////////////////////////////
191 // ENTRY functionName
193 // Assembly directives to begin an exported function.
195 // Takes: functionName - name of the exported function
196 //////////////////////////////////////////////////////////////////////
198 .macro ENTRY /* name */
207 .macro STATIC_ENTRY /*name*/
217 //////////////////////////////////////////////////////////////////////
219 // END_ENTRY functionName
221 // Assembly directives to end an exported function. Just a placeholder,
222 // a close-parenthesis for ENTRY, until it is needed for something.
224 // Takes: functionName - name of the exported function
225 //////////////////////////////////////////////////////////////////////
227 .macro END_ENTRY /* name */
232 /////////////////////////////////////////////////////////////////////
234 // CacheLookup NORMAL|STRET
235 // CacheLookup2 NORMAL|STRET
237 // Locate the implementation for a selector in a class's method cache.
240 // $0 = NORMAL, STRET
241 // r0 or r1 (STRET) = receiver
242 // r1 or r2 (STRET) = selector
243 // r9 = class to search in
245 // On exit: r9 clobbered
246 // (found) continues after CacheLookup, IMP in r12, eq set
247 // (not found) continues after CacheLookup2
249 /////////////////////////////////////////////////////////////////////
253 ldrh r12, [r9, #CACHE_MASK] // r12 = mask
254 ldr r9, [r9, #CACHE] // r9 = buckets
256 and r12, r12, r2 // r12 = index = SEL & mask
258 and r12, r12, r1 // r12 = index = SEL & mask
260 add r9, r9, r12, LSL #3 // r9 = bucket = buckets+index*8
261 ldr r12, [r9, #CACHED_SEL] // r12 = bucket->sel
269 ldr r12, [r9, #CACHED_IMP] // r12 = bucket->imp
272 tst r12, r12 // set ne for stret forwarding
274 // eq already set for nonstret forwarding by `teq` above
281 # error this code requires that SEL be at offset 0
285 blo 8f // if (bucket->sel == 0) cache miss
286 it eq // if (bucket->sel == 1) cache wrap
287 ldreq r9, [r9, #CACHED_IMP] // bucket->imp is before first bucket
288 ldr r12, [r9, #8]! // r12 = (++bucket)->sel
294 /////////////////////////////////////////////////////////////////////
296 // GetClassFromIsa return-type
298 // Given an Isa, return the class for the Isa.
303 // On exit: r12 clobbered
304 // r9 contains the class for this Isa.
306 /////////////////////////////////////////////////////////////////////
307 .macro GetClassFromIsa
309 #if SUPPORT_INDEXED_ISA
310 // Note: We are doing a little wasted work here to load values we might not
311 // need. Branching turns out to be even worse when performance was measured.
312 MI_GET_ADDRESS(r12, _objc_indexed_classes)
313 tst.w r9, #ISA_INDEX_IS_NPI_MASK
315 ubfxne r9, r9, #ISA_INDEX_SHIFT, #ISA_INDEX_BITS
316 ldrne.w r9, [r12, r9, lsl #2]
322 /********************************************************************
323 * IMP cache_getImp(Class cls, SEL sel)
325 * On entry: r0 = class whose cache is to be searched
326 * r1 = selector to search for
328 * If found, returns method implementation.
329 * If not found, returns NULL.
330 ********************************************************************/
332 STATIC_ENTRY _cache_getImp
336 // cache hit, IMP in r12
341 // cache miss, return nil
345 END_ENTRY _cache_getImp
348 /********************************************************************
350 * id objc_msgSend(id self, SEL _cmd, ...);
351 * IMP objc_msgLookup(id self, SEL _cmd, ...);
353 * objc_msgLookup ABI:
354 * IMP returned in r12
355 * Forwarding returned in Z flag
356 * r9 reserved for our use but not used
358 ********************************************************************/
362 cbz r0, LNilReceiver_f
364 ldr r9, [r0] // r9 = self->isa
365 GetClassFromIsa // r9 = class
367 // cache hit, IMP in r12, eq already set for nonstret forwarding
372 ldr r9, [r0] // r9 = self->isa
373 GetClassFromIsa // r9 = class
374 b __objc_msgSend_uncached
377 // r0 is already zero
384 END_ENTRY _objc_msgSend
387 ENTRY _objc_msgLookup
389 cbz r0, LNilReceiver_f
391 ldr r9, [r0] // r9 = self->isa
392 GetClassFromIsa // r9 = class
394 // cache hit, IMP in r12, eq already set for nonstret forwarding
399 ldr r9, [r0] // r9 = self->isa
400 GetClassFromIsa // r9 = class
401 b __objc_msgLookup_uncached
404 MI_GET_ADDRESS(r12, __objc_msgNil)
407 END_ENTRY _objc_msgLookup
410 STATIC_ENTRY __objc_msgNil
412 // r0 is already zero
419 END_ENTRY __objc_msgNil
422 /********************************************************************
423 * void objc_msgSend_stret(void *st_addr, id self, SEL op, ...);
424 * IMP objc_msgLookup_stret(void *st_addr, id self, SEL op, ...);
426 * objc_msgSend_stret is the struct-return form of msgSend.
427 * The ABI calls for r0 to be used as the address of the structure
428 * being returned, with the parameters in the succeeding registers.
430 * On entry: r0 is the address where the structure is returned,
431 * r1 is the message receiver,
433 ********************************************************************/
435 ENTRY _objc_msgSend_stret
437 cbz r1, LNilReceiver_f
439 ldr r9, [r1] // r9 = self->isa
440 GetClassFromIsa // r9 = class
442 // cache hit, IMP in r12, ne already set for stret forwarding
447 ldr r9, [r1] // r9 = self->isa
448 GetClassFromIsa // r9 = class
449 b __objc_msgSend_stret_uncached
454 END_ENTRY _objc_msgSend_stret
457 ENTRY _objc_msgLookup_stret
459 cbz r1, LNilReceiver_f
461 ldr r9, [r1] // r9 = self->isa
462 GetClassFromIsa // r9 = class
464 // cache hit, IMP in r12, ne already set for stret forwarding
469 ldr r9, [r1] // r9 = self->isa
470 GetClassFromIsa // r9 = class
471 b __objc_msgLookup_stret_uncached
474 MI_GET_ADDRESS(r12, __objc_msgNil_stret)
477 END_ENTRY _objc_msgLookup_stret
480 STATIC_ENTRY __objc_msgNil_stret
484 END_ENTRY __objc_msgNil_stret
487 /********************************************************************
488 * id objc_msgSendSuper(struct objc_super *super, SEL op, ...)
490 * struct objc_super {
492 * Class cls; // the class to search
494 ********************************************************************/
496 ENTRY _objc_msgSendSuper
498 ldr r9, [r0, #CLASS] // r9 = struct super->class
500 // cache hit, IMP in r12, eq already set for nonstret forwarding
501 ldr r0, [r0, #RECEIVER] // load real receiver
506 ldr r9, [r0, #CLASS] // r9 = struct super->class
507 ldr r0, [r0, #RECEIVER] // load real receiver
508 b __objc_msgSend_uncached
510 END_ENTRY _objc_msgSendSuper
513 /********************************************************************
514 * id objc_msgSendSuper2(struct objc_super *super, SEL op, ...)
516 * struct objc_super {
518 * Class cls; // SUBCLASS of the class to search
520 ********************************************************************/
522 ENTRY _objc_msgSendSuper2
524 ldr r9, [r0, #CLASS] // class = struct super->class
525 ldr r9, [r9, #SUPERCLASS] // class = class->superclass
527 // cache hit, IMP in r12, eq already set for nonstret forwarding
528 ldr r0, [r0, #RECEIVER] // load real receiver
533 ldr r9, [r0, #CLASS] // class = struct super->class
534 ldr r9, [r9, #SUPERCLASS] // class = class->superclass
535 ldr r0, [r0, #RECEIVER] // load real receiver
536 b __objc_msgSend_uncached
538 END_ENTRY _objc_msgSendSuper2
541 ENTRY _objc_msgLookupSuper2
543 ldr r9, [r0, #CLASS] // class = struct super->class
544 ldr r9, [r9, #SUPERCLASS] // class = class->superclass
546 // cache hit, IMP in r12, eq already set for nonstret forwarding
547 ldr r0, [r0, #RECEIVER] // load real receiver
553 ldr r9, [r9, #SUPERCLASS] // r9 = class to search
554 ldr r0, [r0, #RECEIVER] // load real receiver
555 b __objc_msgLookup_uncached
557 END_ENTRY _objc_msgLookupSuper2
560 /********************************************************************
561 * void objc_msgSendSuper_stret(void *st_addr, objc_super *self, SEL op, ...);
563 * objc_msgSendSuper_stret is the struct-return form of msgSendSuper.
564 * The ABI calls for r0 to be used as the address of the structure
565 * being returned, with the parameters in the succeeding registers.
567 * On entry: r0 is the address where the structure is returned,
568 * r1 is the address of the objc_super structure,
570 ********************************************************************/
572 ENTRY _objc_msgSendSuper_stret
574 ldr r9, [r1, #CLASS] // r9 = struct super->class
576 // cache hit, IMP in r12, ne already set for stret forwarding
577 ldr r1, [r1, #RECEIVER] // load real receiver
582 ldr r9, [r1, #CLASS] // r9 = struct super->class
583 ldr r1, [r1, #RECEIVER] // load real receiver
584 b __objc_msgSend_stret_uncached
586 END_ENTRY _objc_msgSendSuper_stret
589 /********************************************************************
590 * id objc_msgSendSuper2_stret
591 ********************************************************************/
593 ENTRY _objc_msgSendSuper2_stret
595 ldr r9, [r1, #CLASS] // class = struct super->class
596 ldr r9, [r9, #SUPERCLASS] // class = class->superclass
598 // cache hit, IMP in r12, ne already set for stret forwarding
599 ldr r1, [r1, #RECEIVER] // load real receiver
604 ldr r9, [r1, #CLASS] // class = struct super->class
605 ldr r9, [r9, #SUPERCLASS] // class = class->superclass
606 ldr r1, [r1, #RECEIVER] // load real receiver
607 b __objc_msgSend_stret_uncached
609 END_ENTRY _objc_msgSendSuper2_stret
612 ENTRY _objc_msgLookupSuper2_stret
614 ldr r9, [r1, #CLASS] // class = struct super->class
615 ldr r9, [r9, #SUPERCLASS] // class = class->superclass
617 // cache hit, IMP in r12, ne already set for stret forwarding
618 ldr r1, [r1, #RECEIVER] // load real receiver
624 ldr r9, [r9, #SUPERCLASS] // r9 = class to search
625 ldr r1, [r1, #RECEIVER] // load real receiver
626 b __objc_msgLookup_stret_uncached
628 END_ENTRY _objc_msgLookupSuper2_stret
631 /////////////////////////////////////////////////////////////////////
633 // MethodTableLookup NORMAL|STRET
635 // Locate the implementation for a selector in a class's method lists.
638 // $0 = NORMAL, STRET
639 // r0 or r1 (STRET) = receiver
640 // r1 or r2 (STRET) = selector
641 // r9 = class to search in
643 // On exit: IMP in r12, eq/ne set for forwarding
645 /////////////////////////////////////////////////////////////////////
647 .macro MethodTableLookup
649 stmfd sp!, {r0-r3,r7,lr}
651 sub sp, #8 // align stack
655 // receiver already in r0
656 // selector already in r1
658 mov r0, r1 // receiver
659 mov r1, r2 // selector
661 mov r2, r9 // class to search
663 blx __class_lookupMethodAndLoadCache3
664 mov r12, r0 // r12 = IMP
667 cmp r12, r12 // set eq for nonstret forwarding
669 tst r12, r12 // set ne for stret forwarding
673 add sp, #8 // align stack
674 ldmfd sp!, {r0-r3,r7,lr}
679 /********************************************************************
681 * _objc_msgSend_uncached
682 * _objc_msgSend_stret_uncached
683 * _objc_msgLookup_uncached
684 * _objc_msgLookup_stret_uncached
685 * The uncached method lookup.
687 ********************************************************************/
689 STATIC_ENTRY __objc_msgSend_uncached
691 // THIS IS NOT A CALLABLE C FUNCTION
692 // Out-of-band r9 is the class to search
694 MethodTableLookup NORMAL // returns IMP in r12
697 END_ENTRY __objc_msgSend_uncached
700 STATIC_ENTRY __objc_msgSend_stret_uncached
702 // THIS IS NOT A CALLABLE C FUNCTION
703 // Out-of-band r9 is the class to search
705 MethodTableLookup STRET // returns IMP in r12
708 END_ENTRY __objc_msgSend_stret_uncached
711 STATIC_ENTRY __objc_msgLookup_uncached
713 // THIS IS NOT A CALLABLE C FUNCTION
714 // Out-of-band r9 is the class to search
716 MethodTableLookup NORMAL // returns IMP in r12
719 END_ENTRY __objc_msgLookup_uncached
722 STATIC_ENTRY __objc_msgLookup_stret_uncached
724 // THIS IS NOT A CALLABLE C FUNCTION
725 // Out-of-band r9 is the class to search
727 MethodTableLookup STRET // returns IMP in r12
730 END_ENTRY __objc_msgLookup_stret_uncached
733 /********************************************************************
735 * id _objc_msgForward(id self, SEL _cmd,...);
737 * _objc_msgForward and _objc_msgForward_stret are the externally-callable
738 * functions returned by things like method_getImplementation().
739 * _objc_msgForward_impcache is the function pointer actually stored in
742 ********************************************************************/
744 MI_EXTERN(__objc_forward_handler)
745 MI_EXTERN(__objc_forward_stret_handler)
747 STATIC_ENTRY __objc_msgForward_impcache
748 // Method cache version
750 // THIS IS NOT A CALLABLE C FUNCTION
751 // Out-of-band Z is 0 (EQ) for normal, 1 (NE) for stret
753 beq __objc_msgForward
754 b __objc_msgForward_stret
756 END_ENTRY __objc_msgForward_impcache
759 ENTRY __objc_msgForward
762 MI_GET_EXTERN(r12, __objc_forward_handler)
766 END_ENTRY __objc_msgForward
769 ENTRY __objc_msgForward_stret
770 // Struct-return version
772 MI_GET_EXTERN(r12, __objc_forward_stret_handler)
776 END_ENTRY __objc_msgForward_stret
779 ENTRY _objc_msgSend_noarg
781 END_ENTRY _objc_msgSend_noarg
783 ENTRY _objc_msgSend_debug
785 END_ENTRY _objc_msgSend_debug
787 ENTRY _objc_msgSendSuper2_debug
788 b _objc_msgSendSuper2
789 END_ENTRY _objc_msgSendSuper2_debug
791 ENTRY _objc_msgSend_stret_debug
792 b _objc_msgSend_stret
793 END_ENTRY _objc_msgSend_stret_debug
795 ENTRY _objc_msgSendSuper2_stret_debug
796 b _objc_msgSendSuper2_stret
797 END_ENTRY _objc_msgSendSuper2_stret_debug
801 // r1 is method triplet instead of SEL
802 ldr r12, [r1, #METHOD_IMP]
803 ldr r1, [r1, #METHOD_NAME]
805 END_ENTRY _method_invoke
808 ENTRY _method_invoke_stret
809 // r2 is method triplet instead of SEL
810 ldr r12, [r2, #METHOD_IMP]
811 ldr r2, [r2, #METHOD_NAME]
813 END_ENTRY _method_invoke_stret
816 .section __DATA,__objc_msg_break