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_restartableRanges is 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.
110 .macro RestartableEntry
113 .short LLookupEnd$0 - LLookupStart$0
114 .short 0xffff // poor ol' armv7 doesn't support kernel based recovery
119 .private_extern _objc_restartableRanges
120 _objc_restartableRanges:
121 RestartableEntry _cache_getImp
122 RestartableEntry _objc_msgSend
123 RestartableEntry _objc_msgSend_stret
124 RestartableEntry _objc_msgSendSuper
125 RestartableEntry _objc_msgSendSuper_stret
126 RestartableEntry _objc_msgSendSuper2
127 RestartableEntry _objc_msgSendSuper2_stret
128 RestartableEntry _objc_msgLookup
129 RestartableEntry _objc_msgLookup_stret
130 RestartableEntry _objc_msgLookupSuper2
131 RestartableEntry _objc_msgLookupSuper2_stret
135 /********************************************************************
136 * Names for relative labels
137 * DO NOT USE THESE LABELS ELSEWHERE
138 * Reserved labels: 6: 7: 8: 9:
139 ********************************************************************/
140 // 6: used by CacheLookup
141 // 7: used by MI_GET_ADDRESS etc
142 // 8: used by CacheLookup
143 #define LNilReceiver 9
144 #define LNilReceiver_f 9f
145 #define LNilReceiver_b 9b
148 /********************************************************************
150 ********************************************************************/
156 /********************************************************************
158 * Structure definitions.
160 ********************************************************************/
162 /* objc_super parameter to sendSuper */
166 /* Selected field offsets in class structure */
170 #define CACHE_MASK 12
172 /* Field offsets in method cache bucket */
176 /* Selected field offsets in method structure */
177 #define METHOD_NAME 0
178 #define METHOD_TYPES 4
182 //////////////////////////////////////////////////////////////////////
184 // ENTRY functionName
186 // Assembly directives to begin an exported function.
188 // Takes: functionName - name of the exported function
189 //////////////////////////////////////////////////////////////////////
191 .macro ENTRY /* name */
200 .macro STATIC_ENTRY /*name*/
210 //////////////////////////////////////////////////////////////////////
212 // END_ENTRY functionName
214 // Assembly directives to end an exported function. Just a placeholder,
215 // a close-parenthesis for ENTRY, until it is needed for something.
217 // Takes: functionName - name of the exported function
218 //////////////////////////////////////////////////////////////////////
220 .macro END_ENTRY /* name */
225 //////////////////////////////////////////////////////////////////////
229 // Create a stack frame and save all argument registers in preparation
230 // for a function call.
231 //////////////////////////////////////////////////////////////////////
235 stmfd sp!, {r0-r3,r7,lr}
237 sub sp, #8 // align stack
243 //////////////////////////////////////////////////////////////////////
247 // Restore all argument registers and pop the stack frame created by
249 //////////////////////////////////////////////////////////////////////
254 add sp, #8 // align stack
255 ldmfd sp!, {r0-r3,r7,lr}
259 /////////////////////////////////////////////////////////////////////
261 // CacheLookup NORMAL|STRET <function>
262 // CacheLookup2 NORMAL|STRET <function>
264 // Locate the implementation for a selector in a class's method cache.
267 // $0 = NORMAL, STRET
268 // r0 or r1 (STRET) = receiver
269 // r1 or r2 (STRET) = selector
270 // r9 = class to search in
272 // On exit: r9 clobbered
273 // (found) continues after CacheLookup, IMP in r12, eq set
274 // (not found) continues after CacheLookup2
276 /////////////////////////////////////////////////////////////////////
282 // As soon as we're past the LLookupStart$1 label we may have loaded
283 // an invalid cache pointer or mask.
285 // When task_restartable_ranges_synchronize() is called,
286 // (or when a signal hits us) before we're past LLookupEnd$1,
287 // then our PC will be reset to LCacheMiss$1 which forcefully
288 // jumps to the cache-miss codepath.
290 // It is assumed that the CacheMiss codepath starts right at the end
291 // of CacheLookup2 and will re-setup the registers to meet the cache-miss
295 // The cache-miss is just returning NULL (setting r9 to 0)
298 // - r0 or r1 (STRET) contains the receiver
299 // - r1 or r2 (STRET) contains the selector
300 // - r9 contains the isa (reloaded from r0/r1)
301 // - other registers are set as per calling conventions
305 ldrh r12, [r9, #CACHE_MASK] // r12 = mask
306 ldr r9, [r9, #CACHE] // r9 = buckets
308 and r12, r12, r2 // r12 = index = SEL & mask
310 and r12, r12, r1 // r12 = index = SEL & mask
312 add r9, r9, r12, LSL #3 // r9 = bucket = buckets+index*8
313 ldr r12, [r9, #CACHED_SEL] // r12 = bucket->sel
321 ldr r12, [r9, #CACHED_IMP] // r12 = bucket->imp
324 tst r12, r12 // set ne for stret forwarding
326 // eq already set for nonstret forwarding by `teq` above
333 # error this code requires that SEL be at offset 0
337 blo LCacheMiss$1 // if (bucket->sel == 0) cache miss
338 it eq // if (bucket->sel == 1) cache wrap
339 ldreq r9, [r9, #CACHED_IMP] // bucket->imp is before first bucket
340 ldr r12, [r9, #8]! // r12 = (++bucket)->sel
348 /////////////////////////////////////////////////////////////////////
350 // GetClassFromIsa return-type
352 // Given an Isa, return the class for the Isa.
357 // On exit: r12 clobbered
358 // r9 contains the class for this Isa.
360 /////////////////////////////////////////////////////////////////////
361 .macro GetClassFromIsa
363 #if SUPPORT_INDEXED_ISA
364 // Note: We are doing a little wasted work here to load values we might not
365 // need. Branching turns out to be even worse when performance was measured.
366 MI_GET_ADDRESS(r12, _objc_indexed_classes)
367 tst.w r9, #ISA_INDEX_IS_NPI_MASK
369 ubfxne r9, r9, #ISA_INDEX_SHIFT, #ISA_INDEX_BITS
370 ldrne.w r9, [r12, r9, lsl #2]
376 /********************************************************************
377 * IMP cache_getImp(Class cls, SEL sel)
379 * On entry: r0 = class whose cache is to be searched
380 * r1 = selector to search for
382 * If found, returns method implementation.
383 * If not found, returns NULL.
384 ********************************************************************/
386 STATIC_ENTRY _cache_getImp
389 CacheLookup NORMAL, _cache_getImp
390 // cache hit, IMP in r12
394 CacheLookup2 GETIMP, _cache_getImp
395 // cache miss, return nil
399 END_ENTRY _cache_getImp
402 /********************************************************************
404 * id objc_msgSend(id self, SEL _cmd, ...);
405 * IMP objc_msgLookup(id self, SEL _cmd, ...);
407 * objc_msgLookup ABI:
408 * IMP returned in r12
409 * Forwarding returned in Z flag
410 * r9 reserved for our use but not used
412 ********************************************************************/
416 cbz r0, LNilReceiver_f
418 ldr r9, [r0] // r9 = self->isa
419 GetClassFromIsa // r9 = class
420 CacheLookup NORMAL, _objc_msgSend
421 // cache hit, IMP in r12, eq already set for nonstret forwarding
424 CacheLookup2 NORMAL, _objc_msgSend
426 ldr r9, [r0] // r9 = self->isa
427 GetClassFromIsa // r9 = class
428 b __objc_msgSend_uncached
431 // r0 is already zero
438 END_ENTRY _objc_msgSend
441 ENTRY _objc_msgLookup
443 cbz r0, LNilReceiver_f
445 ldr r9, [r0] // r9 = self->isa
446 GetClassFromIsa // r9 = class
447 CacheLookup NORMAL, _objc_msgLookup
448 // cache hit, IMP in r12, eq already set for nonstret forwarding
451 CacheLookup2 NORMAL, _objc_msgLookup
453 ldr r9, [r0] // r9 = self->isa
454 GetClassFromIsa // r9 = class
455 b __objc_msgLookup_uncached
458 MI_GET_ADDRESS(r12, __objc_msgNil)
461 END_ENTRY _objc_msgLookup
464 STATIC_ENTRY __objc_msgNil
466 // r0 is already zero
473 END_ENTRY __objc_msgNil
476 /********************************************************************
477 * void objc_msgSend_stret(void *st_addr, id self, SEL op, ...);
478 * IMP objc_msgLookup_stret(void *st_addr, id self, SEL op, ...);
480 * objc_msgSend_stret is the struct-return form of msgSend.
481 * The ABI calls for r0 to be used as the address of the structure
482 * being returned, with the parameters in the succeeding registers.
484 * On entry: r0 is the address where the structure is returned,
485 * r1 is the message receiver,
487 ********************************************************************/
489 ENTRY _objc_msgSend_stret
491 cbz r1, LNilReceiver_f
493 ldr r9, [r1] // r9 = self->isa
494 GetClassFromIsa // r9 = class
495 CacheLookup STRET, _objc_msgSend_stret
496 // cache hit, IMP in r12, ne already set for stret forwarding
499 CacheLookup2 STRET, _objc_msgSend_stret
501 ldr r9, [r1] // r9 = self->isa
502 GetClassFromIsa // r9 = class
503 b __objc_msgSend_stret_uncached
508 END_ENTRY _objc_msgSend_stret
511 ENTRY _objc_msgLookup_stret
513 cbz r1, LNilReceiver_f
515 ldr r9, [r1] // r9 = self->isa
516 GetClassFromIsa // r9 = class
517 CacheLookup STRET, _objc_msgLookup_stret
518 // cache hit, IMP in r12, ne already set for stret forwarding
521 CacheLookup2 STRET, _objc_msgLookup_stret
523 ldr r9, [r1] // r9 = self->isa
524 GetClassFromIsa // r9 = class
525 b __objc_msgLookup_stret_uncached
528 MI_GET_ADDRESS(r12, __objc_msgNil_stret)
531 END_ENTRY _objc_msgLookup_stret
534 STATIC_ENTRY __objc_msgNil_stret
538 END_ENTRY __objc_msgNil_stret
541 /********************************************************************
542 * id objc_msgSendSuper(struct objc_super *super, SEL op, ...)
544 * struct objc_super {
546 * Class cls; // the class to search
548 ********************************************************************/
550 ENTRY _objc_msgSendSuper
552 ldr r9, [r0, #CLASS] // r9 = struct super->class
553 CacheLookup NORMAL, _objc_msgSendSuper
554 // cache hit, IMP in r12, eq already set for nonstret forwarding
555 ldr r0, [r0, #RECEIVER] // load real receiver
558 CacheLookup2 NORMAL, _objc_msgSendSuper
560 ldr r9, [r0, #CLASS] // r9 = struct super->class
561 ldr r0, [r0, #RECEIVER] // load real receiver
562 b __objc_msgSend_uncached
564 END_ENTRY _objc_msgSendSuper
567 /********************************************************************
568 * id objc_msgSendSuper2(struct objc_super *super, SEL op, ...)
570 * struct objc_super {
572 * Class cls; // SUBCLASS of the class to search
574 ********************************************************************/
576 ENTRY _objc_msgSendSuper2
578 ldr r9, [r0, #CLASS] // class = struct super->class
579 ldr r9, [r9, #SUPERCLASS] // class = class->superclass
580 CacheLookup NORMAL, _objc_msgSendSuper2
581 // cache hit, IMP in r12, eq already set for nonstret forwarding
582 ldr r0, [r0, #RECEIVER] // load real receiver
585 CacheLookup2 NORMAL, _objc_msgSendSuper2
587 ldr r9, [r0, #CLASS] // class = struct super->class
588 ldr r9, [r9, #SUPERCLASS] // class = class->superclass
589 ldr r0, [r0, #RECEIVER] // load real receiver
590 b __objc_msgSend_uncached
592 END_ENTRY _objc_msgSendSuper2
595 ENTRY _objc_msgLookupSuper2
597 ldr r9, [r0, #CLASS] // class = struct super->class
598 ldr r9, [r9, #SUPERCLASS] // class = class->superclass
599 CacheLookup NORMAL, _objc_msgLookupSuper2
600 // cache hit, IMP in r12, eq already set for nonstret forwarding
601 ldr r0, [r0, #RECEIVER] // load real receiver
604 CacheLookup2 NORMAL, _objc_msgLookupSuper2
607 ldr r9, [r9, #SUPERCLASS] // r9 = class to search
608 ldr r0, [r0, #RECEIVER] // load real receiver
609 b __objc_msgLookup_uncached
611 END_ENTRY _objc_msgLookupSuper2
614 /********************************************************************
615 * void objc_msgSendSuper_stret(void *st_addr, objc_super *self, SEL op, ...);
617 * objc_msgSendSuper_stret is the struct-return form of msgSendSuper.
618 * The ABI calls for r0 to be used as the address of the structure
619 * being returned, with the parameters in the succeeding registers.
621 * On entry: r0 is the address where the structure is returned,
622 * r1 is the address of the objc_super structure,
624 ********************************************************************/
626 ENTRY _objc_msgSendSuper_stret
628 ldr r9, [r1, #CLASS] // r9 = struct super->class
629 CacheLookup STRET, _objc_msgSendSuper_stret
630 // cache hit, IMP in r12, ne already set for stret forwarding
631 ldr r1, [r1, #RECEIVER] // load real receiver
634 CacheLookup2 STRET, _objc_msgSendSuper_stret
636 ldr r9, [r1, #CLASS] // r9 = struct super->class
637 ldr r1, [r1, #RECEIVER] // load real receiver
638 b __objc_msgSend_stret_uncached
640 END_ENTRY _objc_msgSendSuper_stret
643 /********************************************************************
644 * id objc_msgSendSuper2_stret
645 ********************************************************************/
647 ENTRY _objc_msgSendSuper2_stret
649 ldr r9, [r1, #CLASS] // class = struct super->class
650 ldr r9, [r9, #SUPERCLASS] // class = class->superclass
651 CacheLookup STRET, _objc_msgSendSuper2_stret
652 // cache hit, IMP in r12, ne already set for stret forwarding
653 ldr r1, [r1, #RECEIVER] // load real receiver
656 CacheLookup2 STRET, _objc_msgSendSuper2_stret
658 ldr r9, [r1, #CLASS] // class = struct super->class
659 ldr r9, [r9, #SUPERCLASS] // class = class->superclass
660 ldr r1, [r1, #RECEIVER] // load real receiver
661 b __objc_msgSend_stret_uncached
663 END_ENTRY _objc_msgSendSuper2_stret
666 ENTRY _objc_msgLookupSuper2_stret
668 ldr r9, [r1, #CLASS] // class = struct super->class
669 ldr r9, [r9, #SUPERCLASS] // class = class->superclass
670 CacheLookup STRET, _objc_msgLookupSuper2_stret
671 // cache hit, IMP in r12, ne already set for stret forwarding
672 ldr r1, [r1, #RECEIVER] // load real receiver
675 CacheLookup2 STRET, _objc_msgLookupSuper2_stret
678 ldr r9, [r9, #SUPERCLASS] // r9 = class to search
679 ldr r1, [r1, #RECEIVER] // load real receiver
680 b __objc_msgLookup_stret_uncached
682 END_ENTRY _objc_msgLookupSuper2_stret
685 /////////////////////////////////////////////////////////////////////
687 // MethodTableLookup NORMAL|STRET
689 // Locate the implementation for a selector in a class's method lists.
692 // $0 = NORMAL, STRET
693 // r0 or r1 (STRET) = receiver
694 // r1 or r2 (STRET) = selector
695 // r9 = class to search in
697 // On exit: IMP in r12, eq/ne set for forwarding
699 /////////////////////////////////////////////////////////////////////
701 .macro MethodTableLookup
705 // lookUpImpOrForward(obj, sel, cls, LOOKUP_INITIALIZE | LOOKUP_RESOLVER)
707 // receiver already in r0
708 // selector already in r1
710 mov r0, r1 // receiver
711 mov r1, r2 // selector
713 mov r2, r9 // class to search
714 mov r3, #3 // LOOKUP_INITIALIZE | LOOKUP_INITIALIZE
715 blx _lookUpImpOrForward
716 mov r12, r0 // r12 = IMP
719 cmp r12, r12 // set eq for nonstret forwarding
721 tst r12, r12 // set ne for stret forwarding
729 /********************************************************************
731 * _objc_msgSend_uncached
732 * _objc_msgSend_stret_uncached
733 * _objc_msgLookup_uncached
734 * _objc_msgLookup_stret_uncached
735 * The uncached method lookup.
737 ********************************************************************/
739 STATIC_ENTRY __objc_msgSend_uncached
741 // THIS IS NOT A CALLABLE C FUNCTION
742 // Out-of-band r9 is the class to search
744 MethodTableLookup NORMAL // returns IMP in r12
747 END_ENTRY __objc_msgSend_uncached
750 STATIC_ENTRY __objc_msgSend_stret_uncached
752 // THIS IS NOT A CALLABLE C FUNCTION
753 // Out-of-band r9 is the class to search
755 MethodTableLookup STRET // returns IMP in r12
758 END_ENTRY __objc_msgSend_stret_uncached
761 STATIC_ENTRY __objc_msgLookup_uncached
763 // THIS IS NOT A CALLABLE C FUNCTION
764 // Out-of-band r9 is the class to search
766 MethodTableLookup NORMAL // returns IMP in r12
769 END_ENTRY __objc_msgLookup_uncached
772 STATIC_ENTRY __objc_msgLookup_stret_uncached
774 // THIS IS NOT A CALLABLE C FUNCTION
775 // Out-of-band r9 is the class to search
777 MethodTableLookup STRET // returns IMP in r12
780 END_ENTRY __objc_msgLookup_stret_uncached
783 /********************************************************************
785 * id _objc_msgForward(id self, SEL _cmd,...);
787 * _objc_msgForward and _objc_msgForward_stret are the externally-callable
788 * functions returned by things like method_getImplementation().
789 * _objc_msgForward_impcache is the function pointer actually stored in
792 ********************************************************************/
794 MI_EXTERN(__objc_forward_handler)
795 MI_EXTERN(__objc_forward_stret_handler)
797 STATIC_ENTRY __objc_msgForward_impcache
798 // Method cache version
800 // THIS IS NOT A CALLABLE C FUNCTION
801 // Out-of-band Z is 0 (EQ) for normal, 1 (NE) for stret
803 beq __objc_msgForward
804 b __objc_msgForward_stret
806 END_ENTRY __objc_msgForward_impcache
809 ENTRY __objc_msgForward
812 MI_GET_EXTERN(r12, __objc_forward_handler)
816 END_ENTRY __objc_msgForward
819 ENTRY __objc_msgForward_stret
820 // Struct-return version
822 MI_GET_EXTERN(r12, __objc_forward_stret_handler)
826 END_ENTRY __objc_msgForward_stret
829 ENTRY _objc_msgSend_noarg
831 END_ENTRY _objc_msgSend_noarg
833 ENTRY _objc_msgSend_debug
835 END_ENTRY _objc_msgSend_debug
837 ENTRY _objc_msgSendSuper2_debug
838 b _objc_msgSendSuper2
839 END_ENTRY _objc_msgSendSuper2_debug
841 ENTRY _objc_msgSend_stret_debug
842 b _objc_msgSend_stret
843 END_ENTRY _objc_msgSend_stret_debug
845 ENTRY _objc_msgSendSuper2_stret_debug
846 b _objc_msgSendSuper2_stret
847 END_ENTRY _objc_msgSendSuper2_stret_debug
852 // See if this is a small method.
854 bne.w L_method_invoke_small
856 // We can directly load the IMP from big methods.
857 // r1 is method triplet instead of SEL
858 ldr r12, [r1, #METHOD_IMP]
859 ldr r1, [r1, #METHOD_NAME]
862 L_method_invoke_small:
863 // Small methods require a call to handle swizzling.
866 bl __method_getImplementationAndName
874 END_ENTRY _method_invoke
877 ENTRY _method_invoke_stret
879 // See if this is a small method.
881 bne.w L_method_invoke_stret_small
883 // We can directly load the IMP from big methods.
884 // r2 is method triplet instead of SEL
885 ldr r12, [r2, #METHOD_IMP]
886 ldr r2, [r2, #METHOD_NAME]
889 L_method_invoke_stret_small:
890 // Small methods require a call to handle swizzling.
893 bl __method_getImplementationAndName
900 END_ENTRY _method_invoke_stret
903 .section __DATA,__objc_msg_break