2 * Copyright (c) 1999-2009 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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@
24 #include <TargetConditionals.h>
25 #if defined(__i386__) && TARGET_OS_SIMULATOR
27 #include "objc-config.h"
31 // _objc_restartableRanges is used by method dispatch
32 // to get the critical regions for which method caches
33 // cannot be garbage collected.
35 .macro RestartableEntry
39 .short 0xffff // The simulator doesn't support kernel based recovery
44 .private_extern _objc_restartableRanges
45 _objc_restartableRanges:
46 RestartableEntry _cache_getImp
47 RestartableEntry _objc_msgSend
48 RestartableEntry _objc_msgSend_fpret
49 RestartableEntry _objc_msgSend_stret
50 RestartableEntry _objc_msgSendSuper
51 RestartableEntry _objc_msgSendSuper2
52 RestartableEntry _objc_msgSendSuper_stret
53 RestartableEntry _objc_msgSendSuper2_stret
54 RestartableEntry _objc_msgLookup
55 RestartableEntry _objc_msgLookup_fpret
56 RestartableEntry _objc_msgLookup_stret
57 RestartableEntry _objc_msgLookupSuper2
58 RestartableEntry _objc_msgLookupSuper2_stret
62 /********************************************************************
63 * Names for relative labels
64 * DO NOT USE THESE LABELS ELSEWHERE
65 * Reserved labels: 5: 6: 7: 8: 9:
66 ********************************************************************/
68 #define LCacheMiss_f 5f
69 #define LCacheMiss_b 5b
70 #define LNilTestDone 6
71 #define LNilTestDone_f 6f
72 #define LNilTestDone_b 6b
73 #define LNilTestSlow 7
74 #define LNilTestSlow_f 7f
75 #define LNilTestSlow_b 7b
77 #define LGetIsaDone_f 8f
78 #define LGetIsaDone_b 8b
80 #define LGetIsaSlow_f 9f
81 #define LGetIsaSlow_b 9b
83 /********************************************************************
85 ********************************************************************/
97 /********************************************************************
99 * Structure definitions.
101 ********************************************************************/
111 #define struct_addr 4
114 #define super_stret 8
115 #define selector_stret 12
116 #define marg_size_stret 16
117 #define marg_list_stret 20
119 // objc_super parameter to sendSuper
123 // Selected field offsets in class structure
126 #define cache_buckets 8
127 #define cache_mask 12
134 #define method_name 0
138 //////////////////////////////////////////////////////////////////////
140 // ENTRY functionName
142 // Assembly directives to begin an exported function.
144 // Takes: functionName - name of the exported function
145 //////////////////////////////////////////////////////////////////////
161 //////////////////////////////////////////////////////////////////////
163 // END_ENTRY functionName
165 // Assembly directives to end an exported function. Just a placeholder,
166 // a close-parenthesis for ENTRY, until it is needed for something.
168 // Takes: functionName - name of the exported function
169 //////////////////////////////////////////////////////////////////////
176 /********************************************************************
178 * Unwind info generation
179 ********************************************************************/
181 .section __LD,__compact_unwind,regular,debug
183 .set LUnwind$0, LExit$0 - $0
186 .long 0 /* no personality */
187 .long 0 /* no LSDA */
191 #define NoFrame 0x02010000 // no frame, no SP adjustment except return address
192 #define FrameWithNoSaves 0x01000000 // frame, no non-volatile saves
195 //////////////////////////////////////////////////////////////////////
199 // Create a stack frame and save all argument registers in preparation
200 // for a function call.
201 //////////////////////////////////////////////////////////////////////
208 subl $$(8+5*16), %esp
210 movdqa %xmm3, 4*16(%esp)
211 movdqa %xmm2, 3*16(%esp)
212 movdqa %xmm1, 2*16(%esp)
213 movdqa %xmm0, 1*16(%esp)
218 //////////////////////////////////////////////////////////////////////
222 // Restore all argument registers and pop the stack frame created by
224 //////////////////////////////////////////////////////////////////////
228 movdqa 4*16(%esp), %xmm3
229 movdqa 3*16(%esp), %xmm2
230 movdqa 2*16(%esp), %xmm1
231 movdqa 1*16(%esp), %xmm0
236 /////////////////////////////////////////////////////////////////////
238 // CacheLookup return-type, caller
240 // Locate the implementation for a selector in a class method cache.
243 // $0 = NORMAL, FPRET, STRET
244 // $1 = CALL, LOOKUP, GETIMP
245 // ecx = selector to search for
246 // edx = class to search
248 // On exit: ecx clobbered
249 // (found) calls or returns IMP in eax, eq/ne set for forwarding
250 // (not found) jumps to LCacheMiss, class still in edx
252 /////////////////////////////////////////////////////////////////////
256 // CacheHit must always be preceded by a not-taken `jne` instruction
257 // in case the imp is _objc_msgForward_impcache.
259 // eax = found bucket
262 movl cached_imp(%eax), %eax // return imp
264 jz 9f // don't xor a nil imp
265 xorl %edx, %eax // xor the isa with the imp
271 xorl cached_imp(%eax), %edx // xor imp and isa
273 // ne already set for forwarding by `xor`
275 cmp %eax, %eax // set eq for stret forwarding
277 jmp *%edx // call imp
280 movl cached_imp(%eax), %eax // return imp
281 xorl %edx, %eax // xor isa into imp
295 movzwl cache_mask(%edx), %eax // eax = mask
296 andl %ecx, %eax // eax = SEL & mask
297 shll $$3, %eax // eax = offset = (SEL & mask) * 8
298 addl cache_buckets(%edx), %eax // eax = bucket = buckets+offset
299 cmpl cached_sel(%eax), %ecx // if (bucket->sel != SEL)
301 // The `jne` above sets flags for CacheHit
302 CacheHit $0, $1 // call or return imp
306 cmpl $$1, cached_sel(%eax)
307 jbe 3f // if (bucket->sel <= 1) wrap or miss
309 addl $$8, %eax // bucket++
311 cmpl cached_sel(%eax), %ecx // if (bucket->sel != sel)
313 // The `jne` above sets flags for CacheHit
314 CacheHit $0, $1 // call or return imp
318 jb LCacheMiss_f // if (bucket->sel < 1) cache miss
320 movl cached_imp(%eax), %eax // bucket->imp is really first bucket
323 // Clone scanning loop to miss instead of hang when cache is corrupt.
324 // The slow path may detect any corruption and halt later.
328 cmpl $$1, cached_sel(%eax)
329 jbe 3f // if (bucket->sel <= 1) wrap or miss
331 addl $$8, %eax // bucket++
333 cmpl cached_sel(%eax), %ecx // if (bucket->sel != sel)
335 // The `jne` above sets flags for CacheHit
336 CacheHit $0, $1 // call or return imp
339 // double wrap or miss
345 /////////////////////////////////////////////////////////////////////
347 // MethodTableLookup NORMAL|STRET
350 // receiver (not struct objc_super) and selector on stack
351 // edx = class to search
353 // On exit: IMP in eax, eq/ne set for forwarding
355 /////////////////////////////////////////////////////////////////////
357 .macro MethodTableLookup
361 movl self+4(%ebp), %eax
362 movl selector+4(%ebp), %ecx
364 movl self_stret+4(%ebp), %eax
365 movl selector_stret+4(%ebp), %ecx
368 // lookUpImpOrForward(obj, sel, cls, LOOKUP_INITIALIZE | LOOKUP_RESOLVER)
369 movl $$3, 12(%esp) // LOOKUP_INITIALIZE | LOOKUP_RESOLVER
370 movl %edx, 8(%esp) // class
371 movl %ecx, 4(%esp) // selector
372 movl %eax, 0(%esp) // receiver
373 call _lookUpImpOrForward
378 test %eax, %eax // set ne for stret forwarding
380 cmp %eax, %eax // set eq for nonstret forwarding
388 /////////////////////////////////////////////////////////////////////
390 // NilTest return-type
392 // Takes: $0 = NORMAL or FPRET or STRET
395 // On exit: Loads non-nil receiver in eax and self(esp) or self_stret(esp),
398 // NilTestReturnZero return-type
400 // Takes: $0 = NORMAL or FPRET or STRET
403 // On exit: Loads non-nil receiver in eax and self(esp) or self_stret(esp),
406 // NilTestReturnIMP return-type
408 // Takes: $0 = NORMAL or FPRET or STRET
411 // On exit: Loads non-nil receiver in eax and self(esp) or self_stret(esp),
412 // or returns an IMP in eax that returns zero.
414 /////////////////////////////////////////////////////////////////////
423 .macro ZeroReturnFPRET
427 .macro ZeroReturnSTRET
431 STATIC_ENTRY __objc_msgNil
434 END_ENTRY __objc_msgNil
436 STATIC_ENTRY __objc_msgNil_fpret
439 END_ENTRY __objc_msgNil_fpret
441 STATIC_ENTRY __objc_msgNil_stret
444 END_ENTRY __objc_msgNil_stret
453 .macro NilTestReturnZero
471 .macro NilTestReturnIMP
478 leal __objc_msgNil-1b(%eax), %eax
480 leal __objc_msgNil_fpret-1b(%eax), %eax
482 leal __objc_msgNil_stret-1b(%eax), %eax
490 /********************************************************************
491 * IMP _cache_getImp(Class cls, SEL sel)
493 * If found, returns method implementation.
494 * If not found, returns NULL.
495 ********************************************************************/
497 STATIC_ENTRY _cache_getImp
499 // load the class and selector
500 movl selector(%esp), %ecx
501 movl self(%esp), %edx
503 CacheLookup NORMAL, GETIMP // returns IMP on success
506 // cache miss, return nil
510 END_ENTRY _cache_getImp
513 /********************************************************************
515 * id objc_msgSend(id self, SEL _cmd, ...);
516 * IMP objc_msgLookup(id self, SEL _cmd, ...);
518 * objc_msgLookup ABI:
519 * IMP returned in eax
520 * Forwarding returned in Z flag
521 * edx reserved for our use but not used
523 ********************************************************************/
526 UNWIND _objc_msgSend, NoFrame
528 movl selector(%esp), %ecx
529 movl self(%esp), %eax
533 movl isa(%eax), %edx // class = self->isa
534 CacheLookup NORMAL, CALL // calls IMP on success
536 NilTestReturnZero NORMAL
540 jmp __objc_msgSend_uncached
542 END_ENTRY _objc_msgSend
545 ENTRY _objc_msgLookup
546 UNWIND _objc_msgLookup, NoFrame
548 movl selector(%esp), %ecx
549 movl self(%esp), %eax
553 movl isa(%eax), %edx // class = self->isa
554 CacheLookup NORMAL, LOOKUP // returns IMP on success
556 NilTestReturnIMP NORMAL
560 jmp __objc_msgLookup_uncached
562 END_ENTRY _objc_msgLookup
565 /********************************************************************
567 * id objc_msgSendSuper(struct objc_super *super, SEL _cmd, ...);
569 ********************************************************************/
571 ENTRY _objc_msgSendSuper
572 UNWIND _objc_msgSendSuper, NoFrame
574 movl selector(%esp), %ecx
575 movl super(%esp), %eax // struct objc_super
576 movl class(%eax), %edx // struct objc_super->class
577 movl receiver(%eax), %eax // struct objc_super->receiver
578 movl %eax, super(%esp) // replace super arg with receiver
579 CacheLookup NORMAL, CALL // calls IMP on success
582 // class still in edx
583 jmp __objc_msgSend_uncached
585 END_ENTRY _objc_msgSendSuper
588 /********************************************************************
590 * id objc_msgSendSuper2(struct objc_super *super, SEL _cmd, ...);
591 * IMP objc_msgLookupSuper2(struct objc_super *super, SEL _cmd, ...);
593 ********************************************************************/
595 ENTRY _objc_msgSendSuper2
596 UNWIND _objc_msgSendSuper2, NoFrame
598 movl selector(%esp), %ecx
599 movl super(%esp), %eax // struct objc_super
600 movl class(%eax), %edx // struct objc_super->class
601 movl receiver(%eax), %eax // struct objc_super->receiver
602 movl %eax, super(%esp) // replace super arg with receiver
603 movl superclass(%edx), %edx // edx = objc_super->class->super_class
604 CacheLookup NORMAL, CALL // calls IMP on success
607 // class still in edx
608 jmp __objc_msgSend_uncached
610 END_ENTRY _objc_msgSendSuper2
613 ENTRY _objc_msgLookupSuper2
614 UNWIND _objc_msgLookupSuper2, NoFrame
616 movl selector(%esp), %ecx
617 movl super(%esp), %eax // struct objc_super
618 movl class(%eax), %edx // struct objc_super->class
619 movl receiver(%eax), %eax // struct objc_super->receiver
620 movl %eax, super(%esp) // replace super arg with receiver
621 movl superclass(%edx), %edx // edx = objc_super->class->super_class
622 CacheLookup NORMAL, LOOKUP // returns IMP on success
625 // class still in edx
626 jmp __objc_msgLookup_uncached
628 END_ENTRY _objc_msgLookupSuper2
631 /********************************************************************
633 * double objc_msgSend_fpret(id self, SEL _cmd, ...);
634 * IMP objc_msgLookup_fpret(id self, SEL _cmd, ...);
636 ********************************************************************/
638 ENTRY _objc_msgSend_fpret
639 UNWIND _objc_msgSend_fpret, NoFrame
641 movl selector(%esp), %ecx
642 movl self(%esp), %eax
646 movl isa(%eax), %edx // class = self->isa
647 CacheLookup FPRET, CALL // calls IMP on success
649 NilTestReturnZero FPRET
652 // class still in edx
653 jmp __objc_msgSend_uncached
655 END_ENTRY _objc_msgSend_fpret
658 ENTRY _objc_msgLookup_fpret
659 UNWIND _objc_msgLookup_fpret, NoFrame
661 movl selector(%esp), %ecx
662 movl self(%esp), %eax
666 movl isa(%eax), %edx // class = self->isa
667 CacheLookup FPRET, LOOKUP // returns IMP on success
669 NilTestReturnIMP FPRET
672 // class still in edx
673 jmp __objc_msgLookup_uncached
675 END_ENTRY _objc_msgLookup_fpret
678 /********************************************************************
680 * void objc_msgSend_stret(void *st_addr, id self, SEL _cmd, ...);
681 * IMP objc_msgLookup_stret(void *st_addr, id self, SEL _cmd, ...);
683 ********************************************************************/
685 ENTRY _objc_msgSend_stret
686 UNWIND _objc_msgSend_stret, NoFrame
688 movl selector_stret(%esp), %ecx
689 movl self_stret(%esp), %eax
693 movl isa(%eax), %edx // class = self->isa
694 CacheLookup STRET, CALL // calls IMP on success
696 NilTestReturnZero STRET
699 // class still in edx
700 jmp __objc_msgSend_stret_uncached
702 END_ENTRY _objc_msgSend_stret
705 ENTRY _objc_msgLookup_stret
706 UNWIND _objc_msgLookup_stret, NoFrame
708 movl selector_stret(%esp), %ecx
709 movl self_stret(%esp), %eax
713 movl isa(%eax), %edx // class = self->isa
714 CacheLookup STRET, LOOKUP // returns IMP on success
716 NilTestReturnIMP STRET
719 // class still in edx
720 jmp __objc_msgLookup_stret_uncached
722 END_ENTRY _objc_msgLookup_stret
725 /********************************************************************
727 * void objc_msgSendSuper_stret(void *st_addr, struct objc_super *super, SEL _cmd, ...);
729 ********************************************************************/
731 ENTRY _objc_msgSendSuper_stret
732 UNWIND _objc_msgSendSuper_stret, NoFrame
734 movl selector_stret(%esp), %ecx
735 movl super_stret(%esp), %eax // struct objc_super
736 movl class(%eax), %edx // struct objc_super->class
737 movl receiver(%eax), %eax // struct objc_super->receiver
738 movl %eax, super_stret(%esp) // replace super arg with receiver
739 CacheLookup STRET, CALL // calls IMP on success
742 // class still in edx
743 jmp __objc_msgSend_stret_uncached
745 END_ENTRY _objc_msgSendSuper_stret
748 /********************************************************************
750 * void objc_msgSendSuper2_stret(void *st_addr, struct objc_super *super, SEL _cmd, ...);
751 * IMP objc_msgLookupSuper2_stret(void *st_addr, struct objc_super *super, SEL _cmd, ...);
753 ********************************************************************/
755 ENTRY _objc_msgSendSuper2_stret
756 UNWIND _objc_msgSendSuper2_stret, NoFrame
758 movl selector_stret(%esp), %ecx
759 movl super_stret(%esp), %eax // struct objc_super
760 movl class(%eax), %edx // struct objc_super->class
761 movl receiver(%eax), %eax // struct objc_super->receiver
762 movl %eax, super_stret(%esp) // replace super arg with receiver
763 mov superclass(%edx), %edx // edx = objc_super->class->super_class
764 CacheLookup STRET, CALL // calls IMP on success
766 // cache miss: go search the method lists
768 // class still in edx
769 jmp __objc_msgSend_stret_uncached
771 END_ENTRY _objc_msgSendSuper2_stret
774 ENTRY _objc_msgLookupSuper2_stret
775 UNWIND _objc_msgLookupSuper2_stret, NoFrame
777 movl selector_stret(%esp), %ecx
778 movl super_stret(%esp), %eax // struct objc_super
779 movl class(%eax), %edx // struct objc_super->class
780 movl receiver(%eax), %eax // struct objc_super->receiver
781 movl %eax, super_stret(%esp) // replace super arg with receiver
782 mov superclass(%edx), %edx // edx = objc_super->class->super_class
783 CacheLookup STRET, LOOKUP // returns IMP on success
785 // cache miss: go search the method lists
787 // class still in edx
788 jmp __objc_msgLookup_stret_uncached
790 END_ENTRY _objc_msgLookupSuper2_stret
793 /********************************************************************
795 * _objc_msgSend_uncached
796 * _objc_msgSend_stret_uncached
797 * _objc_msgLookup_uncached
798 * _objc_msgLookup_stret_uncached
800 * The uncached method lookup.
802 ********************************************************************/
804 STATIC_ENTRY __objc_msgSend_uncached
805 UNWIND __objc_msgSend_uncached, FrameWithNoSaves
807 // THIS IS NOT A CALLABLE C FUNCTION
808 // Out-of-band edx is the searched class
810 // edx is already the class to search
811 MethodTableLookup NORMAL
812 jmp *%eax // call imp
814 END_ENTRY __objc_msgSend_uncached
817 STATIC_ENTRY __objc_msgSend_stret_uncached
818 UNWIND __objc_msgSend_stret_uncached, FrameWithNoSaves
820 // THIS IS NOT A CALLABLE C FUNCTION
821 // Out-of-band edx is the searched class
823 // edx is already the class to search
824 MethodTableLookup STRET
825 jmp *%eax // call imp
827 END_ENTRY __objc_msgSend_stret_uncached
830 STATIC_ENTRY __objc_msgLookup_uncached
831 UNWIND __objc_msgLookup_uncached, FrameWithNoSaves
833 // THIS IS NOT A CALLABLE C FUNCTION
834 // Out-of-band edx is the searched class
836 // edx is already the class to search
837 MethodTableLookup NORMAL // eax = IMP
840 END_ENTRY __objc_msgLookup_uncached
843 STATIC_ENTRY __objc_msgLookup_stret_uncached
844 UNWIND __objc_msgLookup_stret_uncached, FrameWithNoSaves
846 // THIS IS NOT A CALLABLE C FUNCTION
847 // Out-of-band edx is the searched class
849 // edx is already the class to search
850 MethodTableLookup STRET // eax = IMP
853 END_ENTRY __objc_msgLookup_stret_uncached
856 /********************************************************************
858 * id _objc_msgForward(id self, SEL _cmd,...);
860 * _objc_msgForward and _objc_msgForward_stret are the externally-callable
861 * functions returned by things like method_getImplementation().
862 * _objc_msgForward_impcache is the function pointer actually stored in
865 ********************************************************************/
867 .non_lazy_symbol_pointer
869 .indirect_symbol __objc_forward_handler
871 L_forward_stret_handler:
872 .indirect_symbol __objc_forward_stret_handler
875 STATIC_ENTRY __objc_msgForward_impcache
876 // Method cache version
878 // THIS IS NOT A CALLABLE C FUNCTION
879 // Out-of-band condition register is NE for stret, EQ otherwise.
881 je __objc_msgForward_stret
882 jmp __objc_msgForward
884 END_ENTRY _objc_msgForward_impcache
887 ENTRY __objc_msgForward
888 // Non-struct return version
892 movl L_forward_handler-1b(%edx), %edx
895 END_ENTRY __objc_msgForward
898 ENTRY __objc_msgForward_stret
899 // Struct return version
903 movl L_forward_stret_handler-1b(%edx), %edx
906 END_ENTRY __objc_msgForward_stret
909 ENTRY _objc_msgSend_debug
911 END_ENTRY _objc_msgSend_debug
913 ENTRY _objc_msgSendSuper2_debug
914 jmp _objc_msgSendSuper2
915 END_ENTRY _objc_msgSendSuper2_debug
917 ENTRY _objc_msgSend_stret_debug
918 jmp _objc_msgSend_stret
919 END_ENTRY _objc_msgSend_stret_debug
921 ENTRY _objc_msgSendSuper2_stret_debug
922 jmp _objc_msgSendSuper2_stret
923 END_ENTRY _objc_msgSendSuper2_stret_debug
925 ENTRY _objc_msgSend_fpret_debug
926 jmp _objc_msgSend_fpret
927 END_ENTRY _objc_msgSend_fpret_debug
930 ENTRY _objc_msgSend_noarg
932 END_ENTRY _objc_msgSend_noarg
937 // See if this is a small method.
938 testb $1, selector(%esp)
939 jnz L_method_invoke_small
941 // We can directly load the IMP from big methods.
942 movl selector(%esp), %ecx
943 movl method_name(%ecx), %edx
944 movl method_imp(%ecx), %eax
945 movl %edx, selector(%esp)
948 L_method_invoke_small:
949 // Small methods require a call to handle swizzling.
952 movl selector+4(%ebp), %eax
954 call __method_getImplementationAndName
956 movl %edx, selector(%esp)
959 END_ENTRY _method_invoke
962 ENTRY _method_invoke_stret
964 // See if this is a small method.
965 testb $1, selector_stret(%esp)
966 jnz L_method_invoke_stret_small
968 // We can directly load the IMP from big methods.
969 movl selector_stret(%esp), %ecx
970 movl method_name(%ecx), %edx
971 movl method_imp(%ecx), %eax
972 movl %edx, selector_stret(%esp)
975 L_method_invoke_stret_small:
976 // Small methods require a call to handle swizzling.
979 movl selector_stret+4(%ebp), %eax
981 call __method_getImplementationAndName
983 movl %edx, selector_stret(%esp)
986 END_ENTRY _method_invoke_stret
989 .section __DATA,__objc_msg_break