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_entryPoints and _objc_exitPoints are used by objc
32 // to get the critical regions for which method caches
33 // cannot be garbage collected.
36 .private_extern _objc_entryPoints
40 .long _objc_msgSend_fpret
41 .long _objc_msgSend_stret
42 .long _objc_msgSendSuper
43 .long _objc_msgSendSuper2
44 .long _objc_msgSendSuper_stret
45 .long _objc_msgSendSuper2_stret
47 .long _objc_msgLookup_fpret
48 .long _objc_msgLookup_stret
49 .long _objc_msgLookupSuper2
50 .long _objc_msgLookupSuper2_stret
53 .private_extern _objc_exitPoints
55 .long LExit_cache_getImp
56 .long LExit_objc_msgSend
57 .long LExit_objc_msgSend_fpret
58 .long LExit_objc_msgSend_stret
59 .long LExit_objc_msgSendSuper
60 .long LExit_objc_msgSendSuper2
61 .long LExit_objc_msgSendSuper_stret
62 .long LExit_objc_msgSendSuper2_stret
63 .long LExit_objc_msgLookup
64 .long LExit_objc_msgLookup_fpret
65 .long LExit_objc_msgLookup_stret
66 .long LExit_objc_msgLookupSuper2
67 .long LExit_objc_msgLookupSuper2_stret
71 /********************************************************************
72 * Names for relative labels
73 * DO NOT USE THESE LABELS ELSEWHERE
74 * Reserved labels: 5: 6: 7: 8: 9:
75 ********************************************************************/
77 #define LCacheMiss_f 5f
78 #define LCacheMiss_b 5b
79 #define LNilTestDone 6
80 #define LNilTestDone_f 6f
81 #define LNilTestDone_b 6b
82 #define LNilTestSlow 7
83 #define LNilTestSlow_f 7f
84 #define LNilTestSlow_b 7b
86 #define LGetIsaDone_f 8f
87 #define LGetIsaDone_b 8b
89 #define LGetIsaSlow_f 9f
90 #define LGetIsaSlow_b 9b
92 /********************************************************************
94 ********************************************************************/
106 /********************************************************************
108 * Structure definitions.
110 ********************************************************************/
120 #define struct_addr 4
123 #define super_stret 8
124 #define selector_stret 12
125 #define marg_size_stret 16
126 #define marg_list_stret 20
128 // objc_super parameter to sendSuper
132 // Selected field offsets in class structure
135 #define cache_buckets 8
136 #define cache_mask 12
143 #define method_name 0
147 //////////////////////////////////////////////////////////////////////
149 // ENTRY functionName
151 // Assembly directives to begin an exported function.
153 // Takes: functionName - name of the exported function
154 //////////////////////////////////////////////////////////////////////
170 //////////////////////////////////////////////////////////////////////
172 // END_ENTRY functionName
174 // Assembly directives to end an exported function. Just a placeholder,
175 // a close-parenthesis for ENTRY, until it is needed for something.
177 // Takes: functionName - name of the exported function
178 //////////////////////////////////////////////////////////////////////
185 /********************************************************************
187 * Unwind info generation
188 ********************************************************************/
190 .section __LD,__compact_unwind,regular,debug
192 .set LUnwind$0, LExit$0 - $0
195 .long 0 /* no personality */
196 .long 0 /* no LSDA */
200 #define NoFrame 0x02010000 // no frame, no SP adjustment except return address
201 #define FrameWithNoSaves 0x01000000 // frame, no non-volatile saves
204 /////////////////////////////////////////////////////////////////////
206 // CacheLookup return-type, caller
208 // Locate the implementation for a selector in a class method cache.
211 // $0 = NORMAL, FPRET, STRET
212 // $1 = CALL, LOOKUP, GETIMP
213 // ecx = selector to search for
214 // edx = class to search
216 // On exit: ecx clobbered
217 // (found) calls or returns IMP in eax, eq/ne set for forwarding
218 // (not found) jumps to LCacheMiss, class still in edx
220 /////////////////////////////////////////////////////////////////////
224 // CacheHit must always be preceded by a not-taken `jne` instruction
225 // in case the imp is _objc_msgForward_impcache.
227 // eax = found bucket
230 movl cached_imp(%eax), %eax // return imp
236 // eq already set for forwarding by `jne`
238 test %eax, %eax // set ne for stret forwarding
242 jmp *cached_imp(%eax) // call imp
245 movl cached_imp(%eax), %eax // return imp
259 movzwl cache_mask(%edx), %eax // eax = mask
260 andl %ecx, %eax // eax = SEL & mask
261 shll $$3, %eax // eax = offset = (SEL & mask) * 8
262 addl cache_buckets(%edx), %eax // eax = bucket = buckets+offset
263 cmpl cached_sel(%eax), %ecx // if (bucket->sel != SEL)
265 // The `jne` above sets flags for CacheHit
266 CacheHit $0, $1 // call or return imp
270 cmpl $$1, cached_sel(%eax)
271 jbe 3f // if (bucket->sel <= 1) wrap or miss
273 addl $$8, %eax // bucket++
275 cmpl cached_sel(%eax), %ecx // if (bucket->sel != sel)
277 // The `jne` above sets flags for CacheHit
278 CacheHit $0, $1 // call or return imp
282 jb LCacheMiss_f // if (bucket->sel < 1) cache miss
284 movl cached_imp(%eax), %eax // bucket->imp is really first bucket
287 // Clone scanning loop to miss instead of hang when cache is corrupt.
288 // The slow path may detect any corruption and halt later.
292 cmpl $$1, cached_sel(%eax)
293 jbe 3f // if (bucket->sel <= 1) wrap or miss
295 addl $$8, %eax // bucket++
297 cmpl cached_sel(%eax), %ecx // if (bucket->sel != sel)
299 // The `jne` above sets flags for CacheHit
300 CacheHit $0, $1 // call or return imp
303 // double wrap or miss
309 /////////////////////////////////////////////////////////////////////
311 // MethodTableLookup NORMAL|STRET
314 // receiver (not struct objc_super) and selector on stack
315 // edx = class to search
317 // On exit: IMP in eax, eq/ne set for forwarding
319 /////////////////////////////////////////////////////////////////////
321 .macro MethodTableLookup
325 subl $$(8+5*16), %esp
328 movl self+4(%ebp), %eax
329 movl selector+4(%ebp), %ecx
331 movl self_stret+4(%ebp), %eax
332 movl selector_stret+4(%ebp), %ecx
335 movdqa %xmm3, 4*16(%esp)
336 movdqa %xmm2, 3*16(%esp)
337 movdqa %xmm1, 2*16(%esp)
338 movdqa %xmm0, 1*16(%esp)
340 movl %edx, 8(%esp) // class
341 movl %ecx, 4(%esp) // selector
342 movl %eax, 0(%esp) // receiver
343 call __class_lookupMethodAndLoadCache3
347 movdqa 4*16(%esp), %xmm3
348 movdqa 3*16(%esp), %xmm2
349 movdqa 2*16(%esp), %xmm1
350 movdqa 1*16(%esp), %xmm0
353 cmp %eax, %eax // set eq for nonstret forwarding
355 test %eax, %eax // set ne for stret forwarding
363 /////////////////////////////////////////////////////////////////////
365 // NilTest return-type
367 // Takes: $0 = NORMAL or FPRET or STRET
370 // On exit: Loads non-nil receiver in eax and self(esp) or self_stret(esp),
373 // NilTestReturnZero return-type
375 // Takes: $0 = NORMAL or FPRET or STRET
378 // On exit: Loads non-nil receiver in eax and self(esp) or self_stret(esp),
381 // NilTestReturnIMP return-type
383 // Takes: $0 = NORMAL or FPRET or STRET
386 // On exit: Loads non-nil receiver in eax and self(esp) or self_stret(esp),
387 // or returns an IMP in eax that returns zero.
389 /////////////////////////////////////////////////////////////////////
398 .macro ZeroReturnFPRET
402 .macro ZeroReturnSTRET
406 STATIC_ENTRY __objc_msgNil
409 END_ENTRY __objc_msgNil
411 STATIC_ENTRY __objc_msgNil_fpret
414 END_ENTRY __objc_msgNil_fpret
416 STATIC_ENTRY __objc_msgNil_stret
419 END_ENTRY __objc_msgNil_stret
428 .macro NilTestReturnZero
446 .macro NilTestReturnIMP
453 leal __objc_msgNil-1b(%eax), %eax
455 leal __objc_msgNil_fpret-1b(%eax), %eax
457 leal __objc_msgNil_stret-1b(%eax), %eax
465 /********************************************************************
466 * IMP _cache_getImp(Class cls, SEL sel)
468 * If found, returns method implementation.
469 * If not found, returns NULL.
470 ********************************************************************/
472 STATIC_ENTRY _cache_getImp
474 // load the class and selector
475 movl selector(%esp), %ecx
476 movl self(%esp), %edx
478 CacheLookup NORMAL, GETIMP // returns IMP on success
481 // cache miss, return nil
485 END_ENTRY _cache_getImp
488 /********************************************************************
490 * id objc_msgSend(id self, SEL _cmd, ...);
491 * IMP objc_msgLookup(id self, SEL _cmd, ...);
493 * objc_msgLookup ABI:
494 * IMP returned in eax
495 * Forwarding returned in Z flag
496 * edx reserved for our use but not used
498 ********************************************************************/
501 UNWIND _objc_msgSend, NoFrame
503 movl selector(%esp), %ecx
504 movl self(%esp), %eax
508 movl isa(%eax), %edx // class = self->isa
509 CacheLookup NORMAL, CALL // calls IMP on success
511 NilTestReturnZero NORMAL
515 jmp __objc_msgSend_uncached
517 END_ENTRY _objc_msgSend
520 ENTRY _objc_msgLookup
521 UNWIND _objc_msgLookup, NoFrame
523 movl selector(%esp), %ecx
524 movl self(%esp), %eax
528 movl isa(%eax), %edx // class = self->isa
529 CacheLookup NORMAL, LOOKUP // returns IMP on success
531 NilTestReturnIMP NORMAL
535 jmp __objc_msgLookup_uncached
537 END_ENTRY _objc_msgLookup
540 /********************************************************************
542 * id objc_msgSendSuper(struct objc_super *super, SEL _cmd, ...);
544 ********************************************************************/
546 ENTRY _objc_msgSendSuper
547 UNWIND _objc_msgSendSuper, NoFrame
549 movl selector(%esp), %ecx
550 movl super(%esp), %eax // struct objc_super
551 movl class(%eax), %edx // struct objc_super->class
552 movl receiver(%eax), %eax // struct objc_super->receiver
553 movl %eax, super(%esp) // replace super arg with receiver
554 CacheLookup NORMAL, CALL // calls IMP on success
557 // class still in edx
558 jmp __objc_msgSend_uncached
560 END_ENTRY _objc_msgSendSuper
563 /********************************************************************
565 * id objc_msgSendSuper2(struct objc_super *super, SEL _cmd, ...);
566 * IMP objc_msgLookupSuper2(struct objc_super *super, SEL _cmd, ...);
568 ********************************************************************/
570 ENTRY _objc_msgSendSuper2
571 UNWIND _objc_msgSendSuper2, NoFrame
573 movl selector(%esp), %ecx
574 movl super(%esp), %eax // struct objc_super
575 movl class(%eax), %edx // struct objc_super->class
576 movl receiver(%eax), %eax // struct objc_super->receiver
577 movl %eax, super(%esp) // replace super arg with receiver
578 movl superclass(%edx), %edx // edx = objc_super->class->super_class
579 CacheLookup NORMAL, CALL // calls IMP on success
582 // class still in edx
583 jmp __objc_msgSend_uncached
585 END_ENTRY _objc_msgSendSuper2
588 ENTRY _objc_msgLookupSuper2
589 UNWIND _objc_msgLookupSuper2, NoFrame
591 movl selector(%esp), %ecx
592 movl super(%esp), %eax // struct objc_super
593 movl class(%eax), %edx // struct objc_super->class
594 movl receiver(%eax), %eax // struct objc_super->receiver
595 movl %eax, super(%esp) // replace super arg with receiver
596 movl superclass(%edx), %edx // edx = objc_super->class->super_class
597 CacheLookup NORMAL, LOOKUP // returns IMP on success
600 // class still in edx
601 jmp __objc_msgLookup_uncached
603 END_ENTRY _objc_msgLookupSuper2
606 /********************************************************************
608 * double objc_msgSend_fpret(id self, SEL _cmd, ...);
609 * IMP objc_msgLookup_fpret(id self, SEL _cmd, ...);
611 ********************************************************************/
613 ENTRY _objc_msgSend_fpret
614 UNWIND _objc_msgSend_fpret, NoFrame
616 movl selector(%esp), %ecx
617 movl self(%esp), %eax
621 movl isa(%eax), %edx // class = self->isa
622 CacheLookup FPRET, CALL // calls IMP on success
624 NilTestReturnZero FPRET
627 // class still in edx
628 jmp __objc_msgSend_uncached
630 END_ENTRY _objc_msgSend_fpret
633 ENTRY _objc_msgLookup_fpret
634 UNWIND _objc_msgLookup_fpret, NoFrame
636 movl selector(%esp), %ecx
637 movl self(%esp), %eax
641 movl isa(%eax), %edx // class = self->isa
642 CacheLookup FPRET, LOOKUP // returns IMP on success
644 NilTestReturnIMP FPRET
647 // class still in edx
648 jmp __objc_msgLookup_uncached
650 END_ENTRY _objc_msgLookup_fpret
653 /********************************************************************
655 * void objc_msgSend_stret(void *st_addr, id self, SEL _cmd, ...);
656 * IMP objc_msgLookup_stret(void *st_addr, id self, SEL _cmd, ...);
658 ********************************************************************/
660 ENTRY _objc_msgSend_stret
661 UNWIND _objc_msgSend_stret, NoFrame
663 movl selector_stret(%esp), %ecx
664 movl self_stret(%esp), %eax
668 movl isa(%eax), %edx // class = self->isa
669 CacheLookup STRET, CALL // calls IMP on success
671 NilTestReturnZero STRET
674 // class still in edx
675 jmp __objc_msgSend_stret_uncached
677 END_ENTRY _objc_msgSend_stret
680 ENTRY _objc_msgLookup_stret
681 UNWIND _objc_msgLookup_stret, NoFrame
683 movl selector_stret(%esp), %ecx
684 movl self_stret(%esp), %eax
688 movl isa(%eax), %edx // class = self->isa
689 CacheLookup STRET, LOOKUP // returns IMP on success
691 NilTestReturnIMP STRET
694 // class still in edx
695 jmp __objc_msgLookup_stret_uncached
697 END_ENTRY _objc_msgLookup_stret
700 /********************************************************************
702 * void objc_msgSendSuper_stret(void *st_addr, struct objc_super *super, SEL _cmd, ...);
704 ********************************************************************/
706 ENTRY _objc_msgSendSuper_stret
707 UNWIND _objc_msgSendSuper_stret, NoFrame
709 movl selector_stret(%esp), %ecx
710 movl super_stret(%esp), %eax // struct objc_super
711 movl class(%eax), %edx // struct objc_super->class
712 movl receiver(%eax), %eax // struct objc_super->receiver
713 movl %eax, super_stret(%esp) // replace super arg with receiver
714 CacheLookup STRET, CALL // calls IMP on success
717 // class still in edx
718 jmp __objc_msgSend_stret_uncached
720 END_ENTRY _objc_msgSendSuper_stret
723 /********************************************************************
725 * void objc_msgSendSuper2_stret(void *st_addr, struct objc_super *super, SEL _cmd, ...);
726 * IMP objc_msgLookupSuper2_stret(void *st_addr, struct objc_super *super, SEL _cmd, ...);
728 ********************************************************************/
730 ENTRY _objc_msgSendSuper2_stret
731 UNWIND _objc_msgSendSuper2_stret, NoFrame
733 movl selector_stret(%esp), %ecx
734 movl super_stret(%esp), %eax // struct objc_super
735 movl class(%eax), %edx // struct objc_super->class
736 movl receiver(%eax), %eax // struct objc_super->receiver
737 movl %eax, super_stret(%esp) // replace super arg with receiver
738 mov superclass(%edx), %edx // edx = objc_super->class->super_class
739 CacheLookup STRET, CALL // calls IMP on success
741 // cache miss: go search the method lists
743 // class still in edx
744 jmp __objc_msgSend_stret_uncached
746 END_ENTRY _objc_msgSendSuper2_stret
749 ENTRY _objc_msgLookupSuper2_stret
750 UNWIND _objc_msgLookupSuper2_stret, NoFrame
752 movl selector_stret(%esp), %ecx
753 movl super_stret(%esp), %eax // struct objc_super
754 movl class(%eax), %edx // struct objc_super->class
755 movl receiver(%eax), %eax // struct objc_super->receiver
756 movl %eax, super_stret(%esp) // replace super arg with receiver
757 mov superclass(%edx), %edx // edx = objc_super->class->super_class
758 CacheLookup STRET, LOOKUP // returns IMP on success
760 // cache miss: go search the method lists
762 // class still in edx
763 jmp __objc_msgLookup_stret_uncached
765 END_ENTRY _objc_msgLookupSuper2_stret
768 /********************************************************************
770 * _objc_msgSend_uncached
771 * _objc_msgSend_stret_uncached
772 * _objc_msgLookup_uncached
773 * _objc_msgLookup_stret_uncached
775 * The uncached method lookup.
777 ********************************************************************/
779 STATIC_ENTRY __objc_msgSend_uncached
780 UNWIND __objc_msgSend_uncached, FrameWithNoSaves
782 // THIS IS NOT A CALLABLE C FUNCTION
783 // Out-of-band edx is the searched class
785 // edx is already the class to search
786 MethodTableLookup NORMAL
787 jmp *%eax // call imp
789 END_ENTRY __objc_msgSend_uncached
792 STATIC_ENTRY __objc_msgSend_stret_uncached
793 UNWIND __objc_msgSend_stret_uncached, FrameWithNoSaves
795 // THIS IS NOT A CALLABLE C FUNCTION
796 // Out-of-band edx is the searched class
798 // edx is already the class to search
799 MethodTableLookup STRET
800 jmp *%eax // call imp
802 END_ENTRY __objc_msgSend_stret_uncached
805 STATIC_ENTRY __objc_msgLookup_uncached
806 UNWIND __objc_msgLookup_uncached, FrameWithNoSaves
808 // THIS IS NOT A CALLABLE C FUNCTION
809 // Out-of-band edx is the searched class
811 // edx is already the class to search
812 MethodTableLookup NORMAL // eax = IMP
815 END_ENTRY __objc_msgLookup_uncached
818 STATIC_ENTRY __objc_msgLookup_stret_uncached
819 UNWIND __objc_msgLookup_stret_uncached, FrameWithNoSaves
821 // THIS IS NOT A CALLABLE C FUNCTION
822 // Out-of-band edx is the searched class
824 // edx is already the class to search
825 MethodTableLookup STRET // eax = IMP
828 END_ENTRY __objc_msgLookup_stret_uncached
831 /********************************************************************
833 * id _objc_msgForward(id self, SEL _cmd,...);
835 * _objc_msgForward and _objc_msgForward_stret are the externally-callable
836 * functions returned by things like method_getImplementation().
837 * _objc_msgForward_impcache is the function pointer actually stored in
840 ********************************************************************/
842 .non_lazy_symbol_pointer
844 .indirect_symbol __objc_forward_handler
846 L_forward_stret_handler:
847 .indirect_symbol __objc_forward_stret_handler
850 STATIC_ENTRY __objc_msgForward_impcache
851 // Method cache version
853 // THIS IS NOT A CALLABLE C FUNCTION
854 // Out-of-band condition register is NE for stret, EQ otherwise.
856 jne __objc_msgForward_stret
857 jmp __objc_msgForward
859 END_ENTRY _objc_msgForward_impcache
862 ENTRY __objc_msgForward
863 // Non-struct return version
867 movl L_forward_handler-1b(%edx), %edx
870 END_ENTRY __objc_msgForward
873 ENTRY __objc_msgForward_stret
874 // Struct return version
878 movl L_forward_stret_handler-1b(%edx), %edx
881 END_ENTRY __objc_msgForward_stret
884 ENTRY _objc_msgSend_debug
886 END_ENTRY _objc_msgSend_debug
888 ENTRY _objc_msgSendSuper2_debug
889 jmp _objc_msgSendSuper2
890 END_ENTRY _objc_msgSendSuper2_debug
892 ENTRY _objc_msgSend_stret_debug
893 jmp _objc_msgSend_stret
894 END_ENTRY _objc_msgSend_stret_debug
896 ENTRY _objc_msgSendSuper2_stret_debug
897 jmp _objc_msgSendSuper2_stret
898 END_ENTRY _objc_msgSendSuper2_stret_debug
900 ENTRY _objc_msgSend_fpret_debug
901 jmp _objc_msgSend_fpret
902 END_ENTRY _objc_msgSend_fpret_debug
905 ENTRY _objc_msgSend_noarg
907 END_ENTRY _objc_msgSend_noarg
912 movl selector(%esp), %ecx
913 movl method_name(%ecx), %edx
914 movl method_imp(%ecx), %eax
915 movl %edx, selector(%esp)
918 END_ENTRY _method_invoke
921 ENTRY _method_invoke_stret
923 movl selector_stret(%esp), %ecx
924 movl method_name(%ecx), %edx
925 movl method_imp(%ecx), %eax
926 movl %edx, selector_stret(%esp)
929 END_ENTRY _method_invoke_stret
932 .section __DATA,__objc_msg_break