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@
26 /********************************************************************
28 * objc-msg-arm.s - ARM code to support objc messaging
30 ********************************************************************/
44 #define SAVE_VFP fstmfdd sp!, {d0-d7}
45 #define RESTORE_VFP fldmfdd sp!, {d0-d7}
47 #define SAVE_VFP /* empty */
48 #define RESTORE_VFP /* empty */
52 #if defined(__DYNAMIC__)
53 #define MI_EXTERN(var) \
54 .non_lazy_symbol_pointer ;\
55 L ## var ## __non_lazy_ptr: ;\
56 .indirect_symbol var ;\
59 #define MI_EXTERN(var) \
63 #if defined(__DYNAMIC__)
64 #define MI_GET_ADDRESS(reg,var) \
66 3: ldr reg, [pc, reg] ;\
68 4: .long L ## var ## __non_lazy_ptr - (3b + 8) ;\
71 #define MI_GET_ADDRESS(reg,var) \
78 #if defined(__DYNAMIC__)
79 #define MI_BRANCH_EXTERNAL(var) \
80 MI_GET_ADDRESS(ip, var) ;\
83 #define MI_BRANCH_EXTERNAL(var) ;\
87 #if defined(__DYNAMIC__)
88 #define MI_CALL_EXTERNAL(var) \
89 MI_GET_ADDRESS(ip,var) ;\
93 #define MI_CALL_EXTERNAL(var) \
98 MI_EXTERN(__class_lookupMethodAndLoadCache)
100 MI_EXTERN(___objc_error)
101 MI_EXTERN(__objc_forward_handler)
102 MI_EXTERN(__objc_forward_stret_handler)
105 // Special section containing a function pointer that dyld will call
106 // when it loads new images.
107 MI_EXTERN(__objc_notify_images)
110 L__objc_notify_images:
111 MI_BRANCH_EXTERNAL(__objc_notify_images)
113 .section __DATA,__image_notify
114 .long L__objc_notify_images
118 # _objc_entryPoints and _objc_exitPoints are used by method dispatch
119 # caching code to figure out whether any threads are actively
120 # in the cache for dispatching. The labels surround the asm code
121 # that do cache lookups. The tables are zero-terminated.
123 .globl _objc_entryPoints
126 .long __cache_getMethod
128 .long _objc_msgSend_stret
129 .long _objc_msgSendSuper
130 .long _objc_msgSendSuper_stret
134 .globl _objc_exitPoints
139 .long LMsgSendStretExit
140 .long LMsgSendSuperExit
141 .long LMsgSendSuperStretExit
145 /* objc_super parameter to sendSuper */
149 /* Selected field offsets in class structure */
157 /* Method descriptor */
164 .set BUCKETS, 8 /* variable length array */
167 #####################################################################
171 # Assembly directives to begin an exported function.
172 # We align on cache boundaries for these few functions.
174 # Takes: functionName - name of the exported function
175 #####################################################################
177 .macro ENTRY /* name */
184 #####################################################################
186 # END_ENTRY functionName
188 # Assembly directives to end an exported function. Just a placeholder,
189 # a close-parenthesis for ENTRY, until it is needed for something.
191 # Takes: functionName - name of the exported function
192 #####################################################################
194 .macro END_ENTRY /* name */
198 #####################################################################
200 # CacheLookup selectorRegister, cacheMissLabel
202 # Locate the implementation for a selector in a class method cache.
205 # v1 = class whose cache is to be searched
206 # $0 = register containing selector (a2 or a3 ONLY)
207 # cacheMissLabel = label to branch to iff method is not cached
212 # On exit: (found) method triplet in v1, imp in ip
213 # (not found) jumps to cacheMissLabel
215 #####################################################################
217 .macro CacheLookup /* selReg, missLabel */
219 ldr v2, [v1, #CACHE] /* cache = class->cache */
220 ldr v3, [v2, #MASK] /* mask = cache->mask */
221 add a4, v2, #BUCKETS /* buckets = &cache->buckets */
222 and v2, v3, $0, LSR #2 /* index = mask & (sel >> 2) */
224 /* search the cache */
225 /* a1=receiver, a2 or a3=sel, v2=index, v3=mask, a4=buckets, v1=method */
227 ldr v1, [a4, v2, LSL #2] /* method = buckets[index] */
228 teq v1, #0 /* if (method == NULL) */
229 add v2, v2, #1 /* index++ */
230 beq $1 /* goto cacheMissLabel */
232 ldr ip, [v1, #METHOD_NAME] /* load method->method_name */
233 teq $0, ip /* if (method->method_name != sel) */
234 and v2, v2, v3 /* index &= mask */
237 /* cache hit, v1 == method triplet address */
238 /* Return triplet in v1 and imp in ip */
239 ldr ip, [v1, #METHOD_IMP] /* imp = method->method_imp */
244 /********************************************************************
245 * Method _cache_getMethod(Class cls, SEL sel, IMP msgForward_internal_imp)
247 * On entry: a1 = class whose cache is to be searched
248 * a2 = selector to search for
249 * a3 = _objc_msgForward_internal IMP
251 * If found, returns method triplet pointer.
252 * If not found, returns NULL.
254 * NOTE: _cache_getMethod never returns any cache entry whose implementation
255 * is _objc_msgForward_internal. It returns NULL instead. This prevents thread-
256 * safety and memory management bugs in _class_lookupMethodAndLoadCache.
257 * See _class_lookupMethodAndLoadCache for details.
259 * _objc_msgForward_internal is passed as a parameter because it's more
260 * efficient to do the (PIC) lookup once in the caller than repeatedly here.
261 ********************************************************************/
263 ENTRY _cache_getMethod
265 # save registers and load class for CacheLookup
266 stmfd sp!, {a4,v1-v3,r7,lr}
271 CacheLookup a2, LGetMethodMiss
273 # cache hit, method triplet in v1 and imp in ip
274 teq ip, a3 /* check for _objc_msgForward_internal */
275 MOVEEQ a1, #1 /* return (Method)1 if forward */
276 MOVENE a1, v1 /* return triplet if not forward */
277 ldmfd sp!, {a4,v1-v3,r7,pc}
280 MOVE a1, #0 /* return nil if cache miss */
281 ldmfd sp!, {a4,v1-v3,r7,pc}
284 END_ENTRY _cache_getMethod
287 /********************************************************************
288 * IMP _cache_getImp(Class cls, SEL sel)
290 * On entry: a1 = class whose cache is to be searched
291 * a2 = selector to search for
293 * If found, returns method implementation.
294 * If not found, returns NULL.
295 ********************************************************************/
299 # save registers and load class for CacheLookup
300 stmfd sp!, {a4,v1-v3,r7,lr}
305 CacheLookup a2, LGetImpMiss
307 # cache hit, method triplet in v1 and imp in ip
308 MOVE a1, ip @ return imp
309 ldmfd sp!, {a4,v1-v3,r7,pc}
312 MOVE a1, #0 @ return nil if cache miss
313 ldmfd sp!, {a4,v1-v3,r7,pc}
316 END_ENTRY _cache_getImp
319 /********************************************************************
320 * id objc_msgSend(id self,
324 * On entry: a1 is the message receiver,
326 ********************************************************************/
329 # check whether receiver is nil
334 # save registers and load receiver's class for CacheLookup
335 stmfd sp!, {a4,v1-v3}
338 # receiver is non-nil: search the cache
339 CacheLookup a2, LMsgSendCacheMiss
341 # cache hit (imp in ip) - prep for forwarding, restore registers and call
342 teq v1, v1 /* set nonstret (eq) */
343 ldmfd sp!, {a4,v1-v3}
346 # cache miss: go search the method lists
348 ldmfd sp!, {a4,v1-v3}
349 b _objc_msgSend_uncached
352 END_ENTRY objc_msgSend
357 _objc_msgSend_uncached:
360 stmfd sp!, {a1-a4,r7,lr}
364 # Load class and selector
365 ldr a1, [a1, #ISA] /* class = receiver->isa */
366 # MOVE a2, a2 /* selector already in a2 */
369 MI_CALL_EXTERNAL(__class_lookupMethodAndLoadCache)
372 # Prep for forwarding, Pop stack frame and call imp
373 teq v1, v1 /* set nonstret (eq) */
375 ldmfd sp!, {a1-a4,r7,lr}
379 /********************************************************************
380 * struct_type objc_msgSend_stret(id self,
384 * objc_msgSend_stret is the struct-return form of msgSend.
385 * The ABI calls for a1 to be used as the address of the structure
386 * being returned, with the parameters in the succeeding registers.
388 * On entry: a1 is the address where the structure is returned,
389 * a2 is the message receiver,
391 ********************************************************************/
393 ENTRY objc_msgSend_stret
394 # check whether receiver is nil
398 # save registers and load receiver's class for CacheLookup
399 stmfd sp!, {a4,v1-v3}
402 # receiver is non-nil: search the cache
403 CacheLookup a3, LMsgSendStretCacheMiss
405 # cache hit (imp in ip) - prep for forwarding, restore registers and call
406 tst v1, v1 /* set stret (ne); v1 is nonzero (triplet) */
407 ldmfd sp!, {a4,v1-v3}
410 # cache miss: go search the method lists
411 LMsgSendStretCacheMiss:
412 ldmfd sp!, {a4,v1-v3}
413 b _objc_msgSend_stret_uncached
416 END_ENTRY objc_msgSend_stret
421 _objc_msgSend_stret_uncached:
424 stmfd sp!, {a1-a4,r7,lr}
428 # Load class and selector
429 ldr a1, [a2, #ISA] /* class = receiver->isa */
430 MOVE a2, a3 /* selector */
433 MI_CALL_EXTERNAL(__class_lookupMethodAndLoadCache)
436 # Prep for forwarding, pop stack frame and call imp
437 tst a1, a1 /* set stret (ne); a1 is nonzero (imp) */
440 ldmfd sp!, {a1-a4,r7,lr}
444 /********************************************************************
445 * id objc_msgSendSuper(struct objc_super *super,
449 * struct objc_super {
453 ********************************************************************/
455 ENTRY objc_msgSendSuper2
456 @ objc_super->class is superclass of the class to search
457 ldr r12, [a1, #CLASS]
458 ldr r12, [r12, #4] @ r12 = cls->super_class
459 str r12, [a1, #CLASS]
463 ENTRY objc_msgSendSuper
465 # save registers and load super class for CacheLookup
466 stmfd sp!, {a4,v1-v3}
470 CacheLookup a2, LMsgSendSuperCacheMiss
472 # cache hit (imp in ip) - prep for forwarding, restore registers and call
473 teq v1, v1 /* set nonstret (eq) */
474 ldmfd sp!, {a4,v1-v3}
475 ldr a1, [a1, #RECEIVER] @ fetch real receiver
478 # cache miss: go search the method lists
479 LMsgSendSuperCacheMiss:
480 ldmfd sp!, {a4,v1-v3}
481 b _objc_msgSendSuper_uncached
484 END_ENTRY objc_msgSendSuper
489 _objc_msgSendSuper_uncached:
492 stmfd sp!, {a1-a4,r7,lr}
496 # Load class and selector
497 ldr a1, [a1, #CLASS] /* class = super->class */
498 # MOVE a2, a2 /* selector already in a2 */
501 MI_CALL_EXTERNAL(__class_lookupMethodAndLoadCache)
504 # Prep for forwarding, pop stack frame and call imp
505 teq v1, v1 /* set nonstret (eq) */
507 ldmfd sp!, {a1-a4,r7,lr}
508 ldr a1, [a1, #RECEIVER] @ fetch real receiver
512 /********************************************************************
513 * struct_type objc_msgSendSuper_stret(objc_super *super,
517 * struct objc_super {
523 * objc_msgSendSuper_stret is the struct-return form of msgSendSuper.
524 * The ABI calls for a1 to be used as the address of the structure
525 * being returned, with the parameters in the succeeding registers.
527 * On entry: a1 is the address to which to copy the returned structure,
528 * a2 is the address of the objc_super structure,
530 ********************************************************************/
532 ENTRY objc_msgSendSuper2_stret
533 @ objc_super->class is superclass of the class to search
534 ldr r12, [a2, #CLASS]
535 ldr r12, [r12, #4] @ xx = cls->super_class
536 str r12, [a2, #CLASS]
537 b _objc_msgSendSuper_stret
540 ENTRY objc_msgSendSuper_stret
542 # save registers and load super class for CacheLookup
543 stmfd sp!, {a4,v1-v3}
547 CacheLookup a3, LMsgSendSuperStretCacheMiss
549 # cache hit (imp in ip) - prep for forwarding, restore registers and call
550 tst v1, v1 /* set stret (ne); v1 is nonzero (triplet) */
551 ldmfd sp!, {a4,v1-v3}
552 ldr a2, [a2, #RECEIVER] @ fetch real receiver
555 # cache miss: go search the method lists
556 LMsgSendSuperStretCacheMiss:
557 ldmfd sp!, {a4,v1-v3}
558 b _objc_msgSendSuper_stret_uncached
560 LMsgSendSuperStretExit:
561 END_ENTRY objc_msgSendSuper_stret
566 _objc_msgSendSuper_stret_uncached:
569 stmfd sp!, {a1-a4,r7,lr}
573 # Load class and selector
574 ldr a1, [a2, #CLASS] /* class = super->class */
575 MOVE a2, a3 /* selector */
578 MI_CALL_EXTERNAL(__class_lookupMethodAndLoadCache)
581 # Prep for forwarding, pop stack frame and call imp
582 tst v1, v1 /* set stret (ne); v1 is nonzero (triplet) */
585 ldmfd sp!, {a1-a4,r7,lr}
586 ldr a2, [a2, #RECEIVER] @ fetch real receiver
590 /********************************************************************
592 * id _objc_msgForward(id self,
595 * struct_type _objc_msgForward_stret (id self,
599 * Both _objc_msgForward and _objc_msgForward_stret
600 * send the message to a method having the signature:
602 * - forward:(SEL)sel :(marg_list)args;
604 * The marg_list's layout is:
607 * d2 | increasing address
619 * typedef struct objc_sendv_margs {
624 * int stackArgs[...];
627 ********************************************************************/
630 .private_extern _FwdSel
634 .private_extern __objc_forward_handler
635 __objc_forward_handler:
638 .private_extern __objc_forward_stret_handler
639 __objc_forward_stret_handler:
643 ENTRY _objc_msgForward_internal
644 .private_extern __objc_msgForward_internal
645 // Method cache version
647 // THIS IS NOT A CALLABLE C FUNCTION
648 // Out-of-band condition register is NE for stret, EQ otherwise.
650 bne __objc_msgForward_stret
653 END_ENTRY _objc_msgForward_internal
656 ENTRY _objc_msgForward
659 # check for user-installed forwarding handler
660 MI_GET_ADDRESS(ip, __objc_forward_handler)
666 stmfd sp!, {a1-a4} @ push args to marg_list
668 fstmfdd sp!, {d0-d7} @ push fp args to marg_list
671 # build forward::'s parameter list (self, forward::, original sel, marg_list)
673 MOVE a3, a2 @ original sel
674 MI_GET_ADDRESS(a2, _FwdSel) @ "forward::"
676 MOVE a4, sp @ marg_list
678 # check for forwarding of forward:: itself
680 beq LMsgForwardError @ original sel == forward:: - give up
683 str lr, [sp, #-(2*4)]! @ save lr and align stack
688 # pop stack frame and return
691 add sp, sp, #(4 + 4 + 4*4 + 8*8) @ skip lr, pad, a1..a4, d0..d7
693 add sp, sp, #(4 + 4 + 4*4) @ skip lr, pad, a1..a4
697 END_ENTRY _objc_msgForward
700 ENTRY _objc_msgForward_stret
701 // Struct-return version
703 # check for user-installed forwarding handler
704 MI_GET_ADDRESS(ip, __objc_forward_stret_handler)
710 stmfd sp!, {a1-a4} @ push args to marg_list
712 fstmfdd sp!, {d0-d7} @ push fp args to marg_list
715 # build forward::'s parameter list (self, forward::, original sel, marg_list)
717 MI_GET_ADDRESS(a2, _FwdSel) @ "forward::"
719 # a3 is already original sel
720 MOVE a4, sp @ marg_list
722 # check for forwarding of forward:: itself
724 beq LMsgForwardError @ original sel == forward:: - give up
727 str lr, [sp, #-(2*4)]! @ save lr and align stack
732 # pop stack frame and return
735 add sp, sp, #(4 + 4 + 4*4 + 8*8) @ skip lr, pad, a1..a4, d0..d7
737 add sp, sp, #(4 + 4 + 4*4) @ skip lr, pad, a1..a4
741 END_ENTRY _objc_msgForward_stret
744 # currently a1=self, a2=forward::, a3 = original sel, a4 = marg_list
745 # call __objc_error(self, format, original sel)
746 add a2, pc, #4 @ pc bias is 8 bytes
747 MI_CALL_EXTERNAL(___objc_error)
748 .ascii "Does not recognize selector %s\0"
751 /********************************************************************
752 * id objc_msgSendv(id self,
755 * marg_list arg_frame);
757 * typedef struct objc_sendv_margs {
762 * int stackArgs[...];
765 * arg_frame is the number of bytes used in a[] plus stackArgs.
766 * It does not include vfp[].
768 ********************************************************************/
774 stmfd sp!, {a4,v1-v3,r7,lr} @ a4 saved for stack alignment only
777 # save sendv's parameters
780 MOVE v1, a3 @ v1 is arg count in bytes
781 MOVE v2, a4 @ v2 is marg_list
783 # load FP from marg_list
788 # load arg registers from marg_list
789 # v1 is remaining count, v2 is pointer into marg_list
793 ldrhs a3, [v2, #8] @ pop a3 if arg bytes is at least 12
794 ldrhi a4, [v2, #12] @ pop a4 if arg bytes is more than 12
795 subs v1, v1, #16 @ skip past register args
796 ble LMsgSendvCall @ call now if no args remain
797 add v2, v2, #16 @ skip past register args
799 # copy stack args from marg_list
800 # v1 is remaining bytes, v2 is pointer into marg_list, sp is pointer into stack
802 subne sp, sp, #4 @ push 4-byte pad if word count is odd
804 sub sp, sp, v1 @ move sp to end and copy backwards
805 @ (this preserves ABI's stack constraints)
815 # Pop stack frame and return
817 ldmfd sp!, {a4,v1-v3,r7,pc}
819 #error broken for vfp
822 END_ENTRY objc_msgSendv
826 /********************************************************************
827 * struct_type objc_msgSendv_stret(id self,
830 * marg_list arg_frame);
832 * typedef struct objc_sendv_margs {
837 * int stackArgs[...];
840 * arg_frame is the number of bytes used in a[] plus stackArgs.
841 * It does not include vfp[].
842 ********************************************************************/
844 ENTRY objc_msgSendv_stret
847 stmfd sp!, {a4,v1-v3,r7,lr} @ a4 saved for stack alignment only
851 # save sendv's parameters
852 # stret address stays in a1
855 MOVE v1, a4 @ v1 is arg count in bytes
856 ldr v2, [r7, #24] @ v2 is marg_list
858 # load FP from marg_list
863 # load arg registers from marg_list
864 # v1 is remaining count, v2 is pointer into marg_list
865 # stret already in a1
868 subs v1, v1, #16 @ skip past register args
869 ldrhs a4, [v2, #12] @ pop a4 if arg bytes is at least 16
870 beq LMsgSendvStretCall @ call now if no args remain
871 add v2, v2, #16 @ skip past register args
873 # copy stack args from marg_list
874 # v1 is remaining count, v2 is pointer into marg_list, sp is pointer into stack
876 subne sp, sp, #4 @ push 4-byte pad if word count is odd
878 sub sp, sp, v1 @ move pointers to end and copy backwards
879 @ (this preserves ABI's stack constraints)
880 LMsgSendvStretArgLoop:
884 bne LMsgSendvStretArgLoop
887 bl _objc_msgSend_stret
889 # Pop stack frame and return
891 ldmfd sp!, {a4,v1-v3,r7,pc}
893 #error broken for vfp
896 END_ENTRY objc_msgSendv_stret
900 # a2 is method triplet instead of SEL
901 ldr ip, [a2, #METHOD_IMP]
902 ldr a2, [a2, #METHOD_NAME]
904 END_ENTRY method_invoke
907 ENTRY method_invoke_stret
908 # a3 is method triplet instead of SEL
909 ldr ip, [a3, #METHOD_IMP]
910 ldr a3, [a3, #METHOD_NAME]
912 END_ENTRY method_invoke_stret