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 /////////////////////////////////////////////////////////////////////
197 // CacheLookup return-type, caller
199 // Locate the implementation for a selector in a class method cache.
202 // $0 = NORMAL, FPRET, STRET
203 // $1 = CALL, LOOKUP, GETIMP
204 // ecx = selector to search for
205 // edx = class to search
207 // On exit: ecx clobbered
208 // (found) calls or returns IMP in eax, eq/ne set for forwarding
209 // (not found) jumps to LCacheMiss, class still in edx
211 /////////////////////////////////////////////////////////////////////
215 // CacheHit must always be preceded by a not-taken `jne` instruction
216 // in case the imp is _objc_msgForward_impcache.
218 // eax = found bucket
221 movl cached_imp(%eax), %eax // return imp
223 jz 9f // don't xor a nil imp
224 xorl %edx, %eax // xor the isa with the imp
230 xorl cached_imp(%eax), %edx // xor imp and isa
232 // ne already set for forwarding by `xor`
234 cmp %eax, %eax // set eq for stret forwarding
236 jmp *%edx // call imp
239 movl cached_imp(%eax), %eax // return imp
240 xorl %edx, %eax // xor isa into imp
254 movzwl cache_mask(%edx), %eax // eax = mask
255 andl %ecx, %eax // eax = SEL & mask
256 shll $$3, %eax // eax = offset = (SEL & mask) * 8
257 addl cache_buckets(%edx), %eax // eax = bucket = buckets+offset
258 cmpl cached_sel(%eax), %ecx // if (bucket->sel != SEL)
260 // The `jne` above sets flags for CacheHit
261 CacheHit $0, $1 // call or return imp
265 cmpl $$1, cached_sel(%eax)
266 jbe 3f // if (bucket->sel <= 1) wrap or miss
268 addl $$8, %eax // bucket++
270 cmpl cached_sel(%eax), %ecx // if (bucket->sel != sel)
272 // The `jne` above sets flags for CacheHit
273 CacheHit $0, $1 // call or return imp
277 jb LCacheMiss_f // if (bucket->sel < 1) cache miss
279 movl cached_imp(%eax), %eax // bucket->imp is really first bucket
282 // Clone scanning loop to miss instead of hang when cache is corrupt.
283 // The slow path may detect any corruption and halt later.
287 cmpl $$1, cached_sel(%eax)
288 jbe 3f // if (bucket->sel <= 1) wrap or miss
290 addl $$8, %eax // bucket++
292 cmpl cached_sel(%eax), %ecx // if (bucket->sel != sel)
294 // The `jne` above sets flags for CacheHit
295 CacheHit $0, $1 // call or return imp
298 // double wrap or miss
304 /////////////////////////////////////////////////////////////////////
306 // MethodTableLookup NORMAL|STRET
309 // receiver (not struct objc_super) and selector on stack
310 // edx = class to search
312 // On exit: IMP in eax, eq/ne set for forwarding
314 /////////////////////////////////////////////////////////////////////
316 .macro MethodTableLookup
320 subl $$(8+5*16), %esp
323 movl self+4(%ebp), %eax
324 movl selector+4(%ebp), %ecx
326 movl self_stret+4(%ebp), %eax
327 movl selector_stret+4(%ebp), %ecx
330 movdqa %xmm3, 4*16(%esp)
331 movdqa %xmm2, 3*16(%esp)
332 movdqa %xmm1, 2*16(%esp)
333 movdqa %xmm0, 1*16(%esp)
335 // lookUpImpOrForward(obj, sel, cls, LOOKUP_INITIALIZE | LOOKUP_RESOLVER)
336 movl $$3, 12(%esp) // LOOKUP_INITIALIZE | LOOKUP_RESOLVER
337 movl %edx, 8(%esp) // class
338 movl %ecx, 4(%esp) // selector
339 movl %eax, 0(%esp) // receiver
340 call _lookUpImpOrForward
344 movdqa 4*16(%esp), %xmm3
345 movdqa 3*16(%esp), %xmm2
346 movdqa 2*16(%esp), %xmm1
347 movdqa 1*16(%esp), %xmm0
350 test %eax, %eax // set ne for stret forwarding
352 cmp %eax, %eax // set eq for nonstret forwarding
360 /////////////////////////////////////////////////////////////////////
362 // NilTest return-type
364 // Takes: $0 = NORMAL or FPRET or STRET
367 // On exit: Loads non-nil receiver in eax and self(esp) or self_stret(esp),
370 // NilTestReturnZero return-type
372 // Takes: $0 = NORMAL or FPRET or STRET
375 // On exit: Loads non-nil receiver in eax and self(esp) or self_stret(esp),
378 // NilTestReturnIMP return-type
380 // Takes: $0 = NORMAL or FPRET or STRET
383 // On exit: Loads non-nil receiver in eax and self(esp) or self_stret(esp),
384 // or returns an IMP in eax that returns zero.
386 /////////////////////////////////////////////////////////////////////
395 .macro ZeroReturnFPRET
399 .macro ZeroReturnSTRET
403 STATIC_ENTRY __objc_msgNil
406 END_ENTRY __objc_msgNil
408 STATIC_ENTRY __objc_msgNil_fpret
411 END_ENTRY __objc_msgNil_fpret
413 STATIC_ENTRY __objc_msgNil_stret
416 END_ENTRY __objc_msgNil_stret
425 .macro NilTestReturnZero
443 .macro NilTestReturnIMP
450 leal __objc_msgNil-1b(%eax), %eax
452 leal __objc_msgNil_fpret-1b(%eax), %eax
454 leal __objc_msgNil_stret-1b(%eax), %eax
462 /********************************************************************
463 * IMP _cache_getImp(Class cls, SEL sel)
465 * If found, returns method implementation.
466 * If not found, returns NULL.
467 ********************************************************************/
469 STATIC_ENTRY _cache_getImp
471 // load the class and selector
472 movl selector(%esp), %ecx
473 movl self(%esp), %edx
475 CacheLookup NORMAL, GETIMP // returns IMP on success
478 // cache miss, return nil
482 END_ENTRY _cache_getImp
485 /********************************************************************
487 * id objc_msgSend(id self, SEL _cmd, ...);
488 * IMP objc_msgLookup(id self, SEL _cmd, ...);
490 * objc_msgLookup ABI:
491 * IMP returned in eax
492 * Forwarding returned in Z flag
493 * edx reserved for our use but not used
495 ********************************************************************/
498 UNWIND _objc_msgSend, NoFrame
500 movl selector(%esp), %ecx
501 movl self(%esp), %eax
505 movl isa(%eax), %edx // class = self->isa
506 CacheLookup NORMAL, CALL // calls IMP on success
508 NilTestReturnZero NORMAL
512 jmp __objc_msgSend_uncached
514 END_ENTRY _objc_msgSend
517 ENTRY _objc_msgLookup
518 UNWIND _objc_msgLookup, NoFrame
520 movl selector(%esp), %ecx
521 movl self(%esp), %eax
525 movl isa(%eax), %edx // class = self->isa
526 CacheLookup NORMAL, LOOKUP // returns IMP on success
528 NilTestReturnIMP NORMAL
532 jmp __objc_msgLookup_uncached
534 END_ENTRY _objc_msgLookup
537 /********************************************************************
539 * id objc_msgSendSuper(struct objc_super *super, SEL _cmd, ...);
541 ********************************************************************/
543 ENTRY _objc_msgSendSuper
544 UNWIND _objc_msgSendSuper, NoFrame
546 movl selector(%esp), %ecx
547 movl super(%esp), %eax // struct objc_super
548 movl class(%eax), %edx // struct objc_super->class
549 movl receiver(%eax), %eax // struct objc_super->receiver
550 movl %eax, super(%esp) // replace super arg with receiver
551 CacheLookup NORMAL, CALL // calls IMP on success
554 // class still in edx
555 jmp __objc_msgSend_uncached
557 END_ENTRY _objc_msgSendSuper
560 /********************************************************************
562 * id objc_msgSendSuper2(struct objc_super *super, SEL _cmd, ...);
563 * IMP objc_msgLookupSuper2(struct objc_super *super, SEL _cmd, ...);
565 ********************************************************************/
567 ENTRY _objc_msgSendSuper2
568 UNWIND _objc_msgSendSuper2, NoFrame
570 movl selector(%esp), %ecx
571 movl super(%esp), %eax // struct objc_super
572 movl class(%eax), %edx // struct objc_super->class
573 movl receiver(%eax), %eax // struct objc_super->receiver
574 movl %eax, super(%esp) // replace super arg with receiver
575 movl superclass(%edx), %edx // edx = objc_super->class->super_class
576 CacheLookup NORMAL, CALL // calls IMP on success
579 // class still in edx
580 jmp __objc_msgSend_uncached
582 END_ENTRY _objc_msgSendSuper2
585 ENTRY _objc_msgLookupSuper2
586 UNWIND _objc_msgLookupSuper2, NoFrame
588 movl selector(%esp), %ecx
589 movl super(%esp), %eax // struct objc_super
590 movl class(%eax), %edx // struct objc_super->class
591 movl receiver(%eax), %eax // struct objc_super->receiver
592 movl %eax, super(%esp) // replace super arg with receiver
593 movl superclass(%edx), %edx // edx = objc_super->class->super_class
594 CacheLookup NORMAL, LOOKUP // returns IMP on success
597 // class still in edx
598 jmp __objc_msgLookup_uncached
600 END_ENTRY _objc_msgLookupSuper2
603 /********************************************************************
605 * double objc_msgSend_fpret(id self, SEL _cmd, ...);
606 * IMP objc_msgLookup_fpret(id self, SEL _cmd, ...);
608 ********************************************************************/
610 ENTRY _objc_msgSend_fpret
611 UNWIND _objc_msgSend_fpret, NoFrame
613 movl selector(%esp), %ecx
614 movl self(%esp), %eax
618 movl isa(%eax), %edx // class = self->isa
619 CacheLookup FPRET, CALL // calls IMP on success
621 NilTestReturnZero FPRET
624 // class still in edx
625 jmp __objc_msgSend_uncached
627 END_ENTRY _objc_msgSend_fpret
630 ENTRY _objc_msgLookup_fpret
631 UNWIND _objc_msgLookup_fpret, NoFrame
633 movl selector(%esp), %ecx
634 movl self(%esp), %eax
638 movl isa(%eax), %edx // class = self->isa
639 CacheLookup FPRET, LOOKUP // returns IMP on success
641 NilTestReturnIMP FPRET
644 // class still in edx
645 jmp __objc_msgLookup_uncached
647 END_ENTRY _objc_msgLookup_fpret
650 /********************************************************************
652 * void objc_msgSend_stret(void *st_addr, id self, SEL _cmd, ...);
653 * IMP objc_msgLookup_stret(void *st_addr, id self, SEL _cmd, ...);
655 ********************************************************************/
657 ENTRY _objc_msgSend_stret
658 UNWIND _objc_msgSend_stret, NoFrame
660 movl selector_stret(%esp), %ecx
661 movl self_stret(%esp), %eax
665 movl isa(%eax), %edx // class = self->isa
666 CacheLookup STRET, CALL // calls IMP on success
668 NilTestReturnZero STRET
671 // class still in edx
672 jmp __objc_msgSend_stret_uncached
674 END_ENTRY _objc_msgSend_stret
677 ENTRY _objc_msgLookup_stret
678 UNWIND _objc_msgLookup_stret, NoFrame
680 movl selector_stret(%esp), %ecx
681 movl self_stret(%esp), %eax
685 movl isa(%eax), %edx // class = self->isa
686 CacheLookup STRET, LOOKUP // returns IMP on success
688 NilTestReturnIMP STRET
691 // class still in edx
692 jmp __objc_msgLookup_stret_uncached
694 END_ENTRY _objc_msgLookup_stret
697 /********************************************************************
699 * void objc_msgSendSuper_stret(void *st_addr, struct objc_super *super, SEL _cmd, ...);
701 ********************************************************************/
703 ENTRY _objc_msgSendSuper_stret
704 UNWIND _objc_msgSendSuper_stret, NoFrame
706 movl selector_stret(%esp), %ecx
707 movl super_stret(%esp), %eax // struct objc_super
708 movl class(%eax), %edx // struct objc_super->class
709 movl receiver(%eax), %eax // struct objc_super->receiver
710 movl %eax, super_stret(%esp) // replace super arg with receiver
711 CacheLookup STRET, CALL // calls IMP on success
714 // class still in edx
715 jmp __objc_msgSend_stret_uncached
717 END_ENTRY _objc_msgSendSuper_stret
720 /********************************************************************
722 * void objc_msgSendSuper2_stret(void *st_addr, struct objc_super *super, SEL _cmd, ...);
723 * IMP objc_msgLookupSuper2_stret(void *st_addr, struct objc_super *super, SEL _cmd, ...);
725 ********************************************************************/
727 ENTRY _objc_msgSendSuper2_stret
728 UNWIND _objc_msgSendSuper2_stret, NoFrame
730 movl selector_stret(%esp), %ecx
731 movl super_stret(%esp), %eax // struct objc_super
732 movl class(%eax), %edx // struct objc_super->class
733 movl receiver(%eax), %eax // struct objc_super->receiver
734 movl %eax, super_stret(%esp) // replace super arg with receiver
735 mov superclass(%edx), %edx // edx = objc_super->class->super_class
736 CacheLookup STRET, CALL // calls IMP on success
738 // cache miss: go search the method lists
740 // class still in edx
741 jmp __objc_msgSend_stret_uncached
743 END_ENTRY _objc_msgSendSuper2_stret
746 ENTRY _objc_msgLookupSuper2_stret
747 UNWIND _objc_msgLookupSuper2_stret, NoFrame
749 movl selector_stret(%esp), %ecx
750 movl super_stret(%esp), %eax // struct objc_super
751 movl class(%eax), %edx // struct objc_super->class
752 movl receiver(%eax), %eax // struct objc_super->receiver
753 movl %eax, super_stret(%esp) // replace super arg with receiver
754 mov superclass(%edx), %edx // edx = objc_super->class->super_class
755 CacheLookup STRET, LOOKUP // returns IMP on success
757 // cache miss: go search the method lists
759 // class still in edx
760 jmp __objc_msgLookup_stret_uncached
762 END_ENTRY _objc_msgLookupSuper2_stret
765 /********************************************************************
767 * _objc_msgSend_uncached
768 * _objc_msgSend_stret_uncached
769 * _objc_msgLookup_uncached
770 * _objc_msgLookup_stret_uncached
772 * The uncached method lookup.
774 ********************************************************************/
776 STATIC_ENTRY __objc_msgSend_uncached
777 UNWIND __objc_msgSend_uncached, FrameWithNoSaves
779 // THIS IS NOT A CALLABLE C FUNCTION
780 // Out-of-band edx is the searched class
782 // edx is already the class to search
783 MethodTableLookup NORMAL
784 jmp *%eax // call imp
786 END_ENTRY __objc_msgSend_uncached
789 STATIC_ENTRY __objc_msgSend_stret_uncached
790 UNWIND __objc_msgSend_stret_uncached, FrameWithNoSaves
792 // THIS IS NOT A CALLABLE C FUNCTION
793 // Out-of-band edx is the searched class
795 // edx is already the class to search
796 MethodTableLookup STRET
797 jmp *%eax // call imp
799 END_ENTRY __objc_msgSend_stret_uncached
802 STATIC_ENTRY __objc_msgLookup_uncached
803 UNWIND __objc_msgLookup_uncached, FrameWithNoSaves
805 // THIS IS NOT A CALLABLE C FUNCTION
806 // Out-of-band edx is the searched class
808 // edx is already the class to search
809 MethodTableLookup NORMAL // eax = IMP
812 END_ENTRY __objc_msgLookup_uncached
815 STATIC_ENTRY __objc_msgLookup_stret_uncached
816 UNWIND __objc_msgLookup_stret_uncached, FrameWithNoSaves
818 // THIS IS NOT A CALLABLE C FUNCTION
819 // Out-of-band edx is the searched class
821 // edx is already the class to search
822 MethodTableLookup STRET // eax = IMP
825 END_ENTRY __objc_msgLookup_stret_uncached
828 /********************************************************************
830 * id _objc_msgForward(id self, SEL _cmd,...);
832 * _objc_msgForward and _objc_msgForward_stret are the externally-callable
833 * functions returned by things like method_getImplementation().
834 * _objc_msgForward_impcache is the function pointer actually stored in
837 ********************************************************************/
839 .non_lazy_symbol_pointer
841 .indirect_symbol __objc_forward_handler
843 L_forward_stret_handler:
844 .indirect_symbol __objc_forward_stret_handler
847 STATIC_ENTRY __objc_msgForward_impcache
848 // Method cache version
850 // THIS IS NOT A CALLABLE C FUNCTION
851 // Out-of-band condition register is NE for stret, EQ otherwise.
853 je __objc_msgForward_stret
854 jmp __objc_msgForward
856 END_ENTRY _objc_msgForward_impcache
859 ENTRY __objc_msgForward
860 // Non-struct return version
864 movl L_forward_handler-1b(%edx), %edx
867 END_ENTRY __objc_msgForward
870 ENTRY __objc_msgForward_stret
871 // Struct return version
875 movl L_forward_stret_handler-1b(%edx), %edx
878 END_ENTRY __objc_msgForward_stret
881 ENTRY _objc_msgSend_debug
883 END_ENTRY _objc_msgSend_debug
885 ENTRY _objc_msgSendSuper2_debug
886 jmp _objc_msgSendSuper2
887 END_ENTRY _objc_msgSendSuper2_debug
889 ENTRY _objc_msgSend_stret_debug
890 jmp _objc_msgSend_stret
891 END_ENTRY _objc_msgSend_stret_debug
893 ENTRY _objc_msgSendSuper2_stret_debug
894 jmp _objc_msgSendSuper2_stret
895 END_ENTRY _objc_msgSendSuper2_stret_debug
897 ENTRY _objc_msgSend_fpret_debug
898 jmp _objc_msgSend_fpret
899 END_ENTRY _objc_msgSend_fpret_debug
902 ENTRY _objc_msgSend_noarg
904 END_ENTRY _objc_msgSend_noarg
909 movl selector(%esp), %ecx
910 movl method_name(%ecx), %edx
911 movl method_imp(%ecx), %eax
912 movl %edx, selector(%esp)
915 END_ENTRY _method_invoke
918 ENTRY _method_invoke_stret
920 movl selector_stret(%esp), %ecx
921 movl method_name(%ecx), %edx
922 movl method_imp(%ecx), %eax
923 movl %edx, selector_stret(%esp)
926 END_ENTRY _method_invoke_stret
929 .section __DATA,__objc_msg_break