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 ********************************************************************/
49 #if defined(__DYNAMIC__)
50 #define MI_EXTERN(var) \
51 .non_lazy_symbol_pointer ;\
52 L ## var ## __non_lazy_ptr: ;\
53 .indirect_symbol var ;\
56 #define MI_EXTERN(var) \
61 #if defined(__DYNAMIC__) && defined(THUMB)
62 #define MI_GET_ADDRESS(reg,var) \
64 3: add reg, pc, reg ;\
67 4: .long L ## var ## __non_lazy_ptr - (3b + 4) ;\
69 #elif defined(__DYNAMIC__)
70 #define MI_GET_ADDRESS(reg,var) \
72 3: ldr reg, [pc, reg] ;\
74 4: .long L ## var ## __non_lazy_ptr - (3b + 8) ;\
77 #define MI_GET_ADDRESS(reg,var) \
85 #if defined(__DYNAMIC__)
86 #define MI_BRANCH_EXTERNAL(var) \
87 MI_GET_ADDRESS(ip, var) ;\
90 #define MI_BRANCH_EXTERNAL(var) \
94 #if defined(__DYNAMIC__) && defined(THUMB)
95 #define MI_CALL_EXTERNAL(var) \
96 MI_GET_ADDRESS(ip,var) ;\
98 #elif defined(__DYNAMIC__)
99 #define MI_CALL_EXTERNAL(var) \
100 MI_GET_ADDRESS(ip,var) ;\
104 #define MI_CALL_EXTERNAL(var) \
109 MI_EXTERN(__class_lookupMethodAndLoadCache)
111 MI_EXTERN(___objc_error)
112 MI_EXTERN(__objc_forward_handler)
113 MI_EXTERN(__objc_forward_stret_handler)
116 // Special section containing a function pointer that dyld will call
117 // when it loads new images.
118 MI_EXTERN(__objc_notify_images)
121 L__objc_notify_images:
122 MI_BRANCH_EXTERNAL(__objc_notify_images)
124 .section __DATA,__image_notify
125 .long L__objc_notify_images
129 # _objc_entryPoints and _objc_exitPoints are used by method dispatch
130 # caching code to figure out whether any threads are actively
131 # in the cache for dispatching. The labels surround the asm code
132 # that do cache lookups. The tables are zero-terminated.
134 .private_extern _objc_entryPoints
137 .long __cache_getMethod
139 .long _objc_msgSend_noarg
140 .long _objc_msgSend_stret
141 .long _objc_msgSendSuper
142 .long _objc_msgSendSuper_stret
143 .long _objc_msgSendSuper2
144 .long _objc_msgSendSuper2_stret
148 .private_extern _objc_exitPoints
153 .long LMsgSendNoArgExit
154 .long LMsgSendStretExit
155 .long LMsgSendSuperExit
156 .long LMsgSendSuperStretExit
157 .long LMsgSendSuper2Exit
158 .long LMsgSendSuper2StretExit
162 /* objc_super parameter to sendSuper */
166 /* Selected field offsets in class structure */
171 /* Method descriptor */
179 .set BUCKETS, 8 /* variable length array */
182 #####################################################################
186 # Assembly directives to begin an exported function.
187 # We align on cache boundaries for these few functions.
189 # Takes: functionName - name of the exported function
190 #####################################################################
192 .macro ENTRY /* name */
205 .macro STATIC_ENTRY /*name*/
219 #####################################################################
221 # END_ENTRY functionName
223 # Assembly directives to end an exported function. Just a placeholder,
224 # a close-parenthesis for ENTRY, until it is needed for something.
226 # Takes: functionName - name of the exported function
227 #####################################################################
229 .macro END_ENTRY /* name */
233 #####################################################################
235 # CacheLookup selectorRegister, classReg, cacheMissLabel
237 # Locate the implementation for a selector in a class method cache.
240 # $0 = register containing selector (a2 or a3 ONLY)
241 # $1 = class whose cache is to be searched
242 # cacheMissLabel = label to branch to iff method is not cached
247 # On exit: (found) method triplet in $1, imp in ip
248 # (not found) jumps to cacheMissLabel
250 #####################################################################
252 .macro CacheLookup /* selReg, classReg, missLabel */
254 MOVE r9, $0, LSR #2 /* index = (sel >> 2) */
255 ldr a4, [$1, #CACHE] /* cache = class->cache */
256 add a4, a4, #BUCKETS /* buckets = &cache->buckets */
258 /* search the cache */
259 /* a1=receiver, a2 or a3=sel, r9=index, a4=buckets, $1=method */
261 ldr ip, [a4, #NEGMASK] /* mask = cache->mask */
262 and r9, r9, ip /* index &= mask */
263 ldr $1, [a4, r9, LSL #2] /* method = buckets[index] */
264 teq $1, #0 /* if (method == NULL) */
265 add r9, r9, #1 /* index++ */
266 beq $2 /* goto cacheMissLabel */
268 ldr ip, [$1, #METHOD_NAME] /* load method->method_name */
269 teq $0, ip /* if (method->method_name != sel) */
272 /* cache hit, $1 == method triplet address */
273 /* Return triplet in $1 and imp in ip */
274 ldr ip, [$1, #METHOD_IMP] /* imp = method->method_imp */
279 /********************************************************************
280 * Method _cache_getMethod(Class cls, SEL sel, IMP msgForward_internal_imp)
282 * On entry: a1 = class whose cache is to be searched
283 * a2 = selector to search for
284 * a3 = _objc_msgForward_internal IMP
286 * If found, returns method triplet pointer.
287 * If not found, returns NULL.
289 * NOTE: _cache_getMethod never returns any cache entry whose implementation
290 * is _objc_msgForward_internal. It returns NULL instead. This prevents thread-
291 * safety and memory management bugs in _class_lookupMethodAndLoadCache.
292 * See _class_lookupMethodAndLoadCache for details.
294 * _objc_msgForward_internal is passed as a parameter because it's more
295 * efficient to do the (PIC) lookup once in the caller than repeatedly here.
296 ********************************************************************/
298 STATIC_ENTRY _cache_getMethod
301 CacheLookup a2, a1, LGetMethodMiss
303 # cache hit, method triplet in a1 and imp in ip
304 teq ip, a3 /* check for _objc_msgForward_internal */
306 MOVEEQ a1, #1 /* return (Method)1 if forward */
307 /* else return triplet (already in a1) */
311 MOVE a1, #0 /* return nil if cache miss */
315 END_ENTRY _cache_getMethod
318 /********************************************************************
319 * IMP _cache_getImp(Class cls, SEL sel)
321 * On entry: a1 = class whose cache is to be searched
322 * a2 = selector to search for
324 * If found, returns method implementation.
325 * If not found, returns NULL.
326 ********************************************************************/
328 STATIC_ENTRY _cache_getImp
330 # save registers and load class for CacheLookup
333 CacheLookup a2, a1, LGetImpMiss
335 # cache hit, method triplet in a1 and imp in ip
336 MOVE a1, ip @ return imp
340 MOVE a1, #0 @ return nil if cache miss
344 END_ENTRY _cache_getImp
347 /********************************************************************
348 * id objc_msgSend(id self,
352 * On entry: a1 is the message receiver,
354 ********************************************************************/
357 # check whether receiver is nil
363 # save registers and load receiver's class for CacheLookup
367 # receiver is non-nil: search the cache
368 CacheLookup a2, v1, LMsgSendCacheMiss
370 # cache hit (imp in ip) and CacheLookup returns with nonstret (eq) set, restore registers and call
374 # cache miss: go search the method lists
377 b _objc_msgSend_uncached
380 END_ENTRY objc_msgSend
383 STATIC_ENTRY objc_msgSend_uncached
386 stmfd sp!, {a1-a4,r7,lr}
389 # Load class and selector
390 ldr a1, [a1, #ISA] /* class = receiver->isa */
391 # MOVE a2, a2 /* selector already in a2 */
394 MI_CALL_EXTERNAL(__class_lookupMethodAndLoadCache)
397 # Prep for forwarding, Pop stack frame and call imp
398 teq v1, v1 /* set nonstret (eq) */
399 ldmfd sp!, {a1-a4,r7,lr}
402 /********************************************************************
403 * id objc_msgSend_noarg(id self, SEL op)
405 * On entry: a1 is the message receiver,
407 ********************************************************************/
409 ENTRY objc_msgSend_noarg
410 # check whether receiver is nil
416 # load receiver's class for CacheLookup
419 # receiver is non-nil: search the cache
420 CacheLookup a2, a3, LMsgSendNoArgCacheMiss
422 # cache hit (imp in ip) and CacheLookup returns with nonstret (eq) set
425 # cache miss: go search the method lists
426 LMsgSendNoArgCacheMiss:
427 b _objc_msgSend_uncached
430 END_ENTRY objc_msgSend_noarg
433 /********************************************************************
434 * struct_type objc_msgSend_stret(id self,
438 * objc_msgSend_stret is the struct-return form of msgSend.
439 * The ABI calls for a1 to be used as the address of the structure
440 * being returned, with the parameters in the succeeding registers.
442 * On entry: a1 is the address where the structure is returned,
443 * a2 is the message receiver,
445 ********************************************************************/
447 ENTRY objc_msgSend_stret
448 # check whether receiver is nil
453 # save registers and load receiver's class for CacheLookup
457 # receiver is non-nil: search the cache
458 CacheLookup a3, v1, LMsgSendStretCacheMiss
460 # cache hit (imp in ip) - prep for forwarding, restore registers and call
461 tst v1, v1 /* set stret (ne); v1 is nonzero (triplet) */
465 # cache miss: go search the method lists
466 LMsgSendStretCacheMiss:
468 b _objc_msgSend_stret_uncached
471 END_ENTRY objc_msgSend_stret
474 STATIC_ENTRY objc_msgSend_stret_uncached
477 stmfd sp!, {a1-a4,r7,lr}
480 # Load class and selector
481 ldr a1, [a2, #ISA] /* class = receiver->isa */
482 MOVE a2, a3 /* selector */
485 MI_CALL_EXTERNAL(__class_lookupMethodAndLoadCache)
488 # Prep for forwarding, pop stack frame and call imp
489 tst a1, a1 /* set stret (ne); a1 is nonzero (imp) */
491 ldmfd sp!, {a1-a4,r7,lr}
495 /********************************************************************
496 * id objc_msgSendSuper(struct objc_super *super,
500 * struct objc_super {
504 ********************************************************************/
506 ENTRY objc_msgSendSuper
508 # save registers and load super class for CacheLookup
513 CacheLookup a2, v1, LMsgSendSuperCacheMiss
515 # cache hit (imp in ip) and CacheLookup returns with nonstret (eq) set, restore registers and call
517 ldr a1, [a1, #RECEIVER] @ fetch real receiver
520 # cache miss: go search the method lists
521 LMsgSendSuperCacheMiss:
523 b _objc_msgSendSuper_uncached
526 END_ENTRY objc_msgSendSuper
529 STATIC_ENTRY objc_msgSendSuper_uncached
532 stmfd sp!, {a1-a4,r7,lr}
535 # Load class and selector
536 ldr a1, [a1, #CLASS] /* class = super->class */
537 # MOVE a2, a2 /* selector already in a2 */
540 MI_CALL_EXTERNAL(__class_lookupMethodAndLoadCache)
543 # Prep for forwarding, pop stack frame and call imp
544 teq v1, v1 /* set nonstret (eq) */
545 ldmfd sp!, {a1-a4,r7,lr}
546 ldr a1, [a1, #RECEIVER] @ fetch real receiver
550 /********************************************************************
552 ********************************************************************/
554 ENTRY objc_msgSendSuper2
556 # save registers and load super class for CacheLookup
559 ldr v1, [v1, #SUPERCLASS]
562 CacheLookup a2, v1, LMsgSendSuper2CacheMiss
564 # cache hit (imp in ip) and CacheLookup returns with nonstret (eq) set, restore registers and call
566 ldr a1, [a1, #RECEIVER] @ fetch real receiver
569 # cache miss: go search the method lists
570 LMsgSendSuper2CacheMiss:
572 b _objc_msgSendSuper2_uncached
575 END_ENTRY objc_msgSendSuper2
578 STATIC_ENTRY objc_msgSendSuper2_uncached
581 stmfd sp!, {a1-a4,r7,lr}
584 # Load class and selector
585 ldr a1, [a1, #CLASS] /* class = super->class */
586 ldr a1, [a1, #SUPERCLASS] /* class = class->superclass */
587 # MOVE a2, a2 /* selector already in a2 */
590 MI_CALL_EXTERNAL(__class_lookupMethodAndLoadCache)
593 # Prep for forwarding, pop stack frame and call imp
594 teq v1, v1 /* set nonstret (eq) */
595 ldmfd sp!, {a1-a4,r7,lr}
596 ldr a1, [a1, #RECEIVER] @ fetch real receiver
600 /********************************************************************
601 * struct_type objc_msgSendSuper_stret(objc_super *super,
605 * struct objc_super {
611 * objc_msgSendSuper_stret is the struct-return form of msgSendSuper.
612 * The ABI calls for a1 to be used as the address of the structure
613 * being returned, with the parameters in the succeeding registers.
615 * On entry: a1 is the address to which to copy the returned structure,
616 * a2 is the address of the objc_super structure,
618 ********************************************************************/
620 ENTRY objc_msgSendSuper_stret
622 # save registers and load super class for CacheLookup
627 CacheLookup a3, v1, LMsgSendSuperStretCacheMiss
629 # cache hit (imp in ip) - prep for forwarding, restore registers and call
630 tst v1, v1 /* set stret (ne); v1 is nonzero (triplet) */
632 ldr a2, [a2, #RECEIVER] @ fetch real receiver
635 # cache miss: go search the method lists
636 LMsgSendSuperStretCacheMiss:
638 b _objc_msgSendSuper_stret_uncached
640 LMsgSendSuperStretExit:
641 END_ENTRY objc_msgSendSuper_stret
644 STATIC_ENTRY objc_msgSendSuper_stret_uncached
647 stmfd sp!, {a1-a4,r7,lr}
650 # Load class and selector
651 ldr a1, [a2, #CLASS] /* class = super->class */
652 MOVE a2, a3 /* selector */
655 MI_CALL_EXTERNAL(__class_lookupMethodAndLoadCache)
658 # Prep for forwarding, pop stack frame and call imp
659 tst v1, v1 /* set stret (ne); v1 is nonzero (triplet) */
661 ldmfd sp!, {a1-a4,r7,lr}
662 ldr a2, [a2, #RECEIVER] @ fetch real receiver
666 /********************************************************************
667 * id objc_msgSendSuper2_stret
668 ********************************************************************/
670 ENTRY objc_msgSendSuper2_stret
672 # save registers and load super class for CacheLookup
675 ldr v1, [v1, #SUPERCLASS]
678 CacheLookup a3, v1, LMsgSendSuper2StretCacheMiss
680 # cache hit (imp in ip) - prep for forwarding, restore registers and call
681 tst v1, v1 /* set stret (ne); v1 is nonzero (triplet) */
683 ldr a2, [a2, #RECEIVER] @ fetch real receiver
686 # cache miss: go search the method lists
687 LMsgSendSuper2StretCacheMiss:
689 b _objc_msgSendSuper2_stret_uncached
691 LMsgSendSuper2StretExit:
692 END_ENTRY objc_msgSendSuper2_stret
695 STATIC_ENTRY objc_msgSendSuper2_stret_uncached
698 stmfd sp!, {a1-a4,r7,lr}
701 # Load class and selector
702 ldr a1, [a2, #CLASS] /* class = super->class */
703 ldr a1, [a1, #SUPERCLASS] /* class = class->superclass */
704 MOVE a2, a3 /* selector */
707 MI_CALL_EXTERNAL(__class_lookupMethodAndLoadCache)
710 # Prep for forwarding, pop stack frame and call imp
711 tst v1, v1 /* set stret (ne); v1 is nonzero (triplet) */
713 ldmfd sp!, {a1-a4,r7,lr}
714 ldr a2, [a2, #RECEIVER] @ fetch real receiver
718 /********************************************************************
720 * id _objc_msgForward(id self,
723 * struct_type _objc_msgForward_stret (id self,
727 * Both _objc_msgForward and _objc_msgForward_stret
728 * send the message to a method having the signature:
730 * - forward:(SEL)sel :(marg_list)args;
732 * The marg_list's layout is:
735 * d2 | increasing address
747 * typedef struct objc_sendv_margs {
749 * int stackArgs[...];
752 ********************************************************************/
755 .private_extern _FwdSel
759 .private_extern __objc_forward_handler
760 __objc_forward_handler:
763 .private_extern __objc_forward_stret_handler
764 __objc_forward_stret_handler:
768 STATIC_ENTRY _objc_msgForward_internal
769 // Method cache version
771 // THIS IS NOT A CALLABLE C FUNCTION
772 // Out-of-band condition register is NE for stret, EQ otherwise.
774 bne __objc_msgForward_stret
777 END_ENTRY _objc_msgForward_internal
780 ENTRY _objc_msgForward
783 # check for user-installed forwarding handler
784 MI_GET_ADDRESS(ip, __objc_forward_handler)
791 stmfd sp!, {a1-a4} @ push args to marg_list
793 # build forward::'s parameter list (self, forward::, original sel, marg_list)
795 MOVE a3, a2 @ original sel
796 MI_GET_ADDRESS(a2, _FwdSel) @ "forward::"
798 MOVE a4, sp @ marg_list
800 # check for forwarding of forward:: itself
802 beq LMsgForwardError @ original sel == forward:: - give up
805 str lr, [sp, #-(2*4)]! @ save lr and align stack
810 # pop stack frame and return
812 add sp, sp, #(4 + 4 + 4*4) @ skip lr, pad, a1..a4
815 END_ENTRY _objc_msgForward
818 ENTRY _objc_msgForward_stret
819 // Struct-return version
821 # check for user-installed forwarding handler
822 MI_GET_ADDRESS(ip, __objc_forward_stret_handler)
829 stmfd sp!, {a1-a4} @ push args to marg_list
831 # build forward::'s parameter list (self, forward::, original sel, marg_list)
833 MI_GET_ADDRESS(a2, _FwdSel) @ "forward::"
835 # a3 is already original sel
836 MOVE a4, sp @ marg_list
838 # check for forwarding of forward:: itself
840 beq LMsgForwardError @ original sel == forward:: - give up
843 str lr, [sp, #-(2*4)]! @ save lr and align stack
848 # pop stack frame and return
850 add sp, sp, #(4 + 4 + 4*4) @ skip lr, pad, a1..a4
853 END_ENTRY _objc_msgForward_stret
856 # currently a1=self, a2=forward::, a3 = original sel, a4 = marg_list
857 # call __objc_error(self, format, original sel)
858 add a2, pc, #4 @ pc bias is 8 bytes
859 MI_CALL_EXTERNAL(___objc_error)
860 .ascii "Does not recognize selector %s\0"
863 ENTRY objc_msgSend_debug
865 END_ENTRY objc_msgSend_debug
867 ENTRY objc_msgSendSuper2_debug
868 b _objc_msgSendSuper2
869 END_ENTRY objc_msgSendSuper2_debug
871 ENTRY objc_msgSend_stret_debug
872 b _objc_msgSend_stret
873 END_ENTRY objc_msgSend_stret_debug
875 ENTRY objc_msgSendSuper2_stret_debug
876 b _objc_msgSendSuper2_stret
877 END_ENTRY objc_msgSendSuper2_stret_debug
881 # a2 is method triplet instead of SEL
882 ldr ip, [a2, #METHOD_IMP]
883 ldr a2, [a2, #METHOD_NAME]
885 END_ENTRY method_invoke
888 ENTRY method_invoke_stret
889 # a3 is method triplet instead of SEL
890 ldr ip, [a3, #METHOD_IMP]
891 ldr a3, [a3, #METHOD_NAME]
893 END_ENTRY method_invoke_stret
896 STATIC_ENTRY _objc_ignored_method
898 # self is already in a0
901 END_ENTRY _objc_ignored_method