2 * Copyright (c) 1999-2007 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@
26 /********************************************************************
27 ********************************************************************
29 ** objc-msg-x86_64.s - x86-64 code to support objc messaging.
31 ********************************************************************
32 ********************************************************************/
36 /********************************************************************
37 * Data used by the ObjC runtime.
39 ********************************************************************/
42 // Substitute receiver for messages sent to nil (usually also nil)
43 // id _objc_nilReceiver
45 .private_extern __objc_nilReceiver
49 // _objc_entryPoints and _objc_exitPoints are used by objc
50 // to get the critical regions for which method caches
51 // cannot be garbage collected.
53 .private_extern _objc_entryPoints
56 .quad __cache_getMethod
58 .quad _objc_msgSend_fpret
59 .quad _objc_msgSend_fp2ret
60 .quad _objc_msgSend_stret
61 .quad _objc_msgSendSuper
62 .quad _objc_msgSendSuper_stret
63 .quad _objc_msgSendSuper2
64 .quad _objc_msgSendSuper2_stret
67 .private_extern _objc_exitPoints
69 .quad LExit__cache_getImp
70 .quad LExit__cache_getMethod
71 .quad LExit_objc_msgSend
72 .quad LExit_objc_msgSend_fpret
73 .quad LExit_objc_msgSend_fp2ret
74 .quad LExit_objc_msgSend_stret
75 .quad LExit_objc_msgSendSuper
76 .quad LExit_objc_msgSendSuper_stret
77 .quad LExit_objc_msgSendSuper2
78 .quad LExit_objc_msgSendSuper2_stret
82 /********************************************************************
83 * Recommended multi-byte NOP instructions
84 * (Intel 64 and IA-32 Architectures Software Developer's Manual Volume 2B)
85 ********************************************************************/
86 #define nop1 .byte 0x90
87 #define nop2 .byte 0x66,0x90
88 #define nop3 .byte 0x0F,0x1F,0x00
89 #define nop4 .byte 0x0F,0x1F,0x40,0x00
90 #define nop5 .byte 0x0F,0x1F,0x44,0x00,0x00
91 #define nop6 .byte 0x66,0x0F,0x1F,0x44,0x00,0x00
92 #define nop7 .byte 0x0F,0x1F,0x80,0x00,0x00,0x00,0x00
93 #define nop8 .byte 0x0F,0x1F,0x84,0x00,0x00,0x00,0x00,0x00
94 #define nop9 .byte 0x66,0x0F,0x1F,0x84,0x00,0x00,0x00,0x00,0x00
97 /********************************************************************
98 * Names for parameter registers.
99 ********************************************************************/
117 /********************************************************************
118 * Names for relative labels
119 * DO NOT USE THESE LABELS ELSEWHERE
120 * Reserved labels: 5: 6: 7: 8: 9:
121 ********************************************************************/
123 #define LCacheMiss_f 5f
124 #define LCacheMiss_b 5b
125 #define LNilTestDone 6
126 #define LNilTestDone_f 6f
127 #define LNilTestDone_b 6b
128 #define LNilTestSlow 7
129 #define LNilTestSlow_f 7f
130 #define LNilTestSlow_b 7b
131 #define LGetIsaDone 8
132 #define LGetIsaDone_f 8f
133 #define LGetIsaDone_b 8b
134 #define LGetIsaSlow 9
135 #define LGetIsaSlow_f 9f
136 #define LGetIsaSlow_b 9b
138 /********************************************************************
140 ********************************************************************/
148 /********************************************************************
150 * Structure definitions.
152 ********************************************************************/
154 // objc_super parameter to sendSuper
158 // Selected field offsets in class structure
159 // #define isa 0 USE GetIsa INSTEAD
163 #define method_name 0
164 #define method_imp 16
172 // uint128_t floatingPointArgs[8]; // xmm0..xmm7
173 // long linkageArea[4]; // r10, rax, ebp, ret
174 // long registerArgs[6]; // a1..a6
175 // long stackArgs[0]; // variable-size
178 #define LINK_AREA (FP_AREA+8*16)
179 #define REG_AREA (LINK_AREA+4*8)
180 #define STACK_AREA (REG_AREA+6*8)
183 //////////////////////////////////////////////////////////////////////
185 // ENTRY functionName
187 // Assembly directives to begin an exported function.
189 // Takes: functionName - name of the exported function
190 //////////////////////////////////////////////////////////////////////
206 //////////////////////////////////////////////////////////////////////
208 // END_ENTRY functionName
210 // Assembly directives to end an exported function. Just a placeholder,
211 // a close-parenthesis for ENTRY, until it is needed for something.
213 // Takes: functionName - name of the exported function
214 //////////////////////////////////////////////////////////////////////
222 These macros work for objc_msgSend variants and others that call
223 CacheLookup/MethodTableLookup or SaveRegisters/RestoreRegisters
224 without otherwise building a frame or clobbering callee-save registers
226 The macros build appropriate FDEs and tie them to the CIE.
229 #define DW_CFA_offset 0x80
230 #define DW_CFA_restore 0xc0
231 #define DW_CFA_advance_loc4 0x4
232 #define DW_CFA_same_value 0x8
233 #define DW_CFA_def_cfa 0xc
234 #define DW_CFA_def_cfa_register 0xd
235 #define DW_CFA_def_cfa_offset 0xe
236 #define DW_CFA_offset_extended_sf 0x11
237 #define DW_CFA_def_cfa_offset_sf 0x13
265 // 8-byte data multiplier
266 // 1-byte insn multiplier
267 // PC-relative everything
270 .section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support
272 .set L$set$0,LECIE1-LSCIE1
273 .long L$set$0 # Length of Common Information Entry
275 .long 0 # CIE Identifier Tag
276 .byte 0x3 # CIE Version
277 .ascii "zPR\0" # CIE Augmentation: size + personality + FDE encoding
278 .byte 0x1 # uleb128 0x1; CIE Code Alignment Factor
279 .byte 0x78 # sleb128 -0x8; CIE Data Alignment Factor
280 .byte 0x10 # CIE RA Column
281 .byte 0x6 # uleb128 0x1; Augmentation size
282 // Personality augmentation
284 .long ___objc_personality_v0+4@GOTPCREL
285 // FDE-encoding augmentation
287 // Prefix instructions
292 // RA is at 0(%rsp) aka -8(CFA)
293 .byte DW_CFA_offset | DW_ra
302 .section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support
308 .set LLENFDE$0, LEFDE$0-LASFDE$0
309 .long LLENFDE$0 # FDE Length
311 .long LASFDE$0-CIE # FDE CIE offset
312 .quad LF0$0-. # FDE address start
313 .quad LLEN$0 # FDE address range
314 .byte 0x0 # uleb128 0x0; Augmentation size
316 // DW_START: set by CIE
321 .byte DW_CFA_advance_loc4
323 .byte DW_CFA_def_cfa_offset
325 .byte DW_CFA_offset | DW_rbp
328 .byte DW_CFA_advance_loc4
330 .byte DW_CFA_def_cfa_register
348 .set LFLEN0$0, LF1$0-LF0$0
353 EMIT_FDE $0, LLEN$0, 1
358 EMIT_FDE $0, LLEN$0, 2
362 /////////////////////////////////////////////////////////////////////
364 // SaveRegisters caller
366 // Pushes a stack frame and saves all registers that might contain
369 // On entry: %0 = caller's symbol name for DWARF
373 // %rsp is 16-byte aligned
375 /////////////////////////////////////////////////////////////////////
379 enter $$0x80+8, $$0 // +8 for alignment
380 movdqa %xmm0, -0x80(%rbp)
381 push %rax // might be xmm parameter count
382 movdqa %xmm1, -0x70(%rbp)
384 movdqa %xmm2, -0x60(%rbp)
386 movdqa %xmm3, -0x50(%rbp)
388 movdqa %xmm4, -0x40(%rbp)
390 movdqa %xmm5, -0x30(%rbp)
392 movdqa %xmm6, -0x20(%rbp)
394 movdqa %xmm7, -0x10(%rbp)
397 /////////////////////////////////////////////////////////////////////
401 // Pops a stack frame pushed by SaveRegisters
403 // On entry: $0 = caller's symbol name for DWARF
404 // %rbp unchanged since SaveRegisters
409 /////////////////////////////////////////////////////////////////////
411 .macro RestoreRegisters
412 movdqa -0x80(%rbp), %xmm0
414 movdqa -0x70(%rbp), %xmm1
416 movdqa -0x60(%rbp), %xmm2
418 movdqa -0x50(%rbp), %xmm3
420 movdqa -0x40(%rbp), %xmm4
422 movdqa -0x30(%rbp), %xmm5
424 movdqa -0x20(%rbp), %xmm6
426 movdqa -0x10(%rbp), %xmm7
431 /////////////////////////////////////////////////////////////////////
434 // CacheLookup return-type
436 // Locate the implementation for a selector in a class method cache.
439 // $0 = NORMAL, FPRET, FP2RET, STRET
440 // a2 or a3 (STRET) = selector
441 // %r11 = class whose cache is to be searched
443 // On exit: (found) method in %r11, stack unchanged, eq/ne set for forwarding
444 // (not found) jumps to LCacheMiss, %rax on stack
446 /////////////////////////////////////////////////////////////////////
451 movq cache(%r11), %r10 // cache = class->cache
453 mov %a2d, %eax // index = sel
455 mov %a3d, %eax // index = sel
458 // search the receiver's cache
459 // r11 = method (soon)
464 andl mask(%r10), %eax // index &= mask
465 movq buckets(%r10, %rax, 8), %r11 // method = cache->buckets[index]
467 testq %r11, %r11 // if (method == NULL)
468 je LCacheMiss_f // goto cacheMissLabel
470 cmpq method_name(%r11), %a2 // if (method_name != sel)
472 cmpq method_name(%r11), %a3 // if (method_name != sel)
476 // cache hit, r11 = method triplet
477 // restore saved registers
481 // eq (non-stret) flag already set above
483 // set ne (stret) for forwarding; r11 != 0
490 /////////////////////////////////////////////////////////////////////
492 // MethodTableLookup classRegister, selectorRegister, fn
494 // Takes: $0 = class to search (a1 or a2 or r10 ONLY)
495 // $1 = selector to search for (a2 or a3 ONLY)
496 // $2 = caller's symbol name for DWARF
497 // r11 = class to search
499 // Stack: ret, rax (pushed by CacheLookup)
501 // On exit: pops registers pushed by CacheLookup
504 /////////////////////////////////////////////////////////////////////
505 .macro MethodTableLookup
507 pop %rax // saved by CacheLookup
510 // _class_lookupMethodAndLoadCache3(receiver, selector, class)
515 call __class_lookupMethodAndLoadCache3
517 // IMP is now in %rax
524 /////////////////////////////////////////////////////////////////////
526 // GetIsa return-type
527 // GetIsaFast return-type
528 // GetIsaSupport return-type
530 // Sets r11 = obj->isa. Consults the tagged isa table if necessary.
532 // Takes: $0 = NORMAL or FPRET or FP2RET or STRET
533 // a1 or a2 (STRET) = receiver
535 // On exit: r11 = receiver->isa
538 /////////////////////////////////////////////////////////////////////
556 leaq __objc_tagged_isa_table(%rip), %r11
557 movq (%r11, %r10, 8), %r11 // read isa from table
564 .byte 0x2e // harmless branch hint prefix to align IFETCH blocks
569 .byte 0x2e // harmless branch hint prefix to align IFETCH blocks
578 leaq __objc_tagged_isa_table(%rip), %r11
585 movq (%r11, %r10, 8), %r11 // read isa from table
589 /////////////////////////////////////////////////////////////////////
591 // NilTest return-type
593 // Takes: $0 = NORMAL or FPRET or FP2RET or STRET
594 // %a1 or %a2 (STRET) = receiver
596 // On exit: Loads non-nil receiver in %a1 or %a2 (STRET), or returns zero.
598 // NilTestSupport return-type
600 // Takes: $0 = NORMAL or FPRET or FP2RET or STRET
601 // %a1 or %a2 (STRET) = receiver
603 // On exit: Loads non-nil receiver in %a1 or %a2 (STRET), or returns zero.
605 /////////////////////////////////////////////////////////////////////
617 .macro NilTestSupport
621 movq __objc_nilReceiver(%rip), %a1
622 testq %a1, %a1 // if (receiver != nil)
624 movq __objc_nilReceiver(%rip), %a2
625 testq %a2, %a2 // if (receiver != nil)
627 jne LNilTestDone_b // send to new receiver
645 /********************************************************************
646 * Method _cache_getMethod(Class cls, SEL sel, IMP msgForward_internal_imp)
648 * On entry: a1 = class whose cache is to be searched
649 * a2 = selector to search for
650 * a3 = _objc_msgForward_internal IMP
652 * If found, returns method triplet pointer.
653 * If not found, returns NULL.
655 * NOTE: _cache_getMethod never returns any cache entry whose implementation
656 * is _objc_msgForward_internal. It returns 1 instead. This prevents thread-
657 * thread-safety and memory management bugs in _class_lookupMethodAndLoadCache.
658 * See _class_lookupMethodAndLoadCache for details.
660 * _objc_msgForward_internal is passed as a parameter because it's more
661 * efficient to do the (PIC) lookup once in the caller than repeatedly here.
662 ********************************************************************/
664 STATIC_ENTRY __cache_getMethod
665 DW_START __cache_getMethod
668 movq %a1, %r11 // move class to r11 for CacheLookup
671 // cache hit, method triplet in %r11
672 cmpq method_imp(%r11), %a3 // if (imp==_objc_msgForward_internal)
673 je 1f // return (Method)1
674 movq %r11, %rax // return method triplet address
680 // cache miss, return nil
681 pop %rax // pushed by CacheLookup
686 DW_END2 __cache_getMethod
687 END_ENTRY __cache_getMethod
690 /********************************************************************
691 * IMP _cache_getImp(Class cls, SEL sel)
693 * On entry: a1 = class whose cache is to be searched
694 * a2 = selector to search for
696 * If found, returns method implementation.
697 * If not found, returns NULL.
698 ********************************************************************/
700 STATIC_ENTRY __cache_getImp
701 DW_START __cache_getImp
704 movq %a1, %r11 // move class to r11 for CacheLookup
707 // cache hit, method triplet in %r11
708 movq method_imp(%r11), %rax // return method imp address
712 // cache miss, return nil
713 pop %rax // pushed by CacheLookup
718 DW_END2 __cache_getImp
719 END_ENTRY __cache_getImp
722 /********************************************************************
724 * id objc_msgSend(id self, SEL _cmd,...);
726 ********************************************************************/
730 .private_extern __objc_tagged_isa_table
731 __objc_tagged_isa_table:
735 DW_START _objc_msgSend
739 GetIsaFast NORMAL // r11 = self->isa
740 CacheLookup NORMAL // r11 = method, eq set (nonstret fwd)
741 jmp *method_imp(%r11) // goto *imp
743 NilTestSupport NORMAL
747 // cache miss: go search the method lists
749 GetIsa NORMAL // r11 = self->isa
750 MethodTableLookup %a1, %a2, _objc_msgSend // r11 = IMP
751 cmp %r11, %r11 // set eq (nonstret) for forwarding
752 jmp *%r11 // goto *imp
755 END_ENTRY _objc_msgSend
758 ENTRY _objc_msgSend_fixup
759 DW_START _objc_msgSend_fixup
763 SaveRegisters _objc_msgSend_fixup
765 // Dereference obj/isa/cache to crash before _objc_fixupMessageRef
766 movq 8(%a2), %a6 // selector
767 GetIsa NORMAL // r11 = isa = *receiver
768 movq cache(%r11), %a5 // cache = *isa
769 movq mask(%a5), %a4 // *cache
772 // a2 = address of message ref
775 // __objc_fixupMessageRef(receiver, 0, ref)
776 call __objc_fixupMessageRef
779 RestoreRegisters _objc_msgSend_fixup
782 // Load _cmd from the message_ref
784 cmp %r11, %r11 // set nonstret (eq) for forwarding
787 NilTestSupport NORMAL
789 DW_END _objc_msgSend_fixup
790 END_ENTRY _objc_msgSend_fixup
793 STATIC_ENTRY _objc_msgSend_fixedup
794 // Load _cmd from the message_ref
797 END_ENTRY _objc_msgSend_fixedup
801 /********************************************************************
803 * id objc_msgSendSuper(struct objc_super *super, SEL _cmd,...);
805 * struct objc_super {
809 ********************************************************************/
811 ENTRY _objc_msgSendSuper
812 DW_START _objc_msgSendSuper
814 // search the cache (objc_super in %a1)
815 movq class(%a1), %r11 // class = objc_super->class
816 CacheLookup NORMAL // r11 = method, eq set (nonstret fwd)
817 movq receiver(%a1), %a1 // load real receiver
818 jmp *method_imp(%r11) // goto *imp
820 // cache miss: go search the method lists
822 movq receiver(%a1), %r10
823 movq class(%a1), %r11
824 MethodTableLookup %r10, %a2, _objc_msgSendSuper // r11 = IMP
825 movq receiver(%a1), %a1 // load real receiver
826 cmp %r11, %r11 // set eq (nonstret) for forwarding
827 jmp *%r11 // goto *imp
829 DW_END _objc_msgSendSuper
830 END_ENTRY _objc_msgSendSuper
833 /********************************************************************
834 * id objc_msgSendSuper2
835 ********************************************************************/
838 ENTRY _objc_msgSendSuper2_fixup
839 DW_START _objc_msgSendSuper2_fixup
841 SaveRegisters _objc_msgSendSuper2_fixup
842 // a1 = address of objc_super2
843 // a2 = address of message ref
846 movq receiver(%a1), %a1
847 // __objc_fixupMessageRef(receiver, objc_super, ref)
848 call __objc_fixupMessageRef
850 RestoreRegisters _objc_msgSendSuper2_fixup
853 // Load _cmd from the message_ref
855 // Load receiver from objc_super2
856 movq receiver(%a1), %a1
857 cmp %r11, %r11 // set nonstret (eq) for forwarding
860 DW_END _objc_msgSendSuper2_fixup
861 END_ENTRY _objc_msgSendSuper2_fixup
864 STATIC_ENTRY _objc_msgSendSuper2_fixedup
865 movq 8(%a2), %a2 // load _cmd from message_ref
866 jmp _objc_msgSendSuper2
867 END_ENTRY _objc_msgSendSuper2_fixedup
870 ENTRY _objc_msgSendSuper2
871 DW_START _objc_msgSendSuper2
872 // objc_super->class is superclass of class to search
874 // search the cache (objc_super in %a1)
875 movq class(%a1), %r11 // cls = objc_super->class
876 movq 8(%r11), %r11 // cls = class->superclass
877 CacheLookup NORMAL // r11 = method, eq set (nonstret fwd)
878 movq receiver(%a1), %a1 // load real receiver
879 jmp *method_imp(%r11) // goto *imp
881 // cache miss: go search the method lists
883 movq receiver(%a1), %r10
884 movq class(%a1), %r11
886 MethodTableLookup %r10, %a2, _objc_msgSendSuper2 // r11 = IMP
887 movq receiver(%a1), %a1 // load real receiver
888 cmp %r11, %r11 // set eq (nonstret) for forwarding
889 jmp *%r11 // goto *imp
891 DW_END _objc_msgSendSuper2
892 END_ENTRY _objc_msgSendSuper2
896 /********************************************************************
898 * double objc_msgSend_fpret(id self, SEL _cmd,...);
899 * Used for `long double` return only. `float` and `double` use objc_msgSend.
901 ********************************************************************/
903 ENTRY _objc_msgSend_fpret
904 DW_START _objc_msgSend_fpret
908 GetIsaFast FPRET // r11 = self->isa
909 CacheLookup FPRET // r11 = method, eq set (nonstret fwd)
910 jmp *method_imp(%r11) // goto *imp
916 // cache miss: go search the method lists
918 GetIsa FPRET // r11 = self->isa
919 MethodTableLookup %a1, %a2, _objc_msgSend_fpret // r11 = IMP
920 cmp %r11, %r11 // set eq (nonstret) for forwarding
921 jmp *%r11 // goto *imp
923 DW_END _objc_msgSend_fpret
924 END_ENTRY _objc_msgSend_fpret
927 ENTRY _objc_msgSend_fpret_fixup
928 DW_START _objc_msgSend_fpret_fixup
932 SaveRegisters _objc_msgSend_fpret_fixup
934 // Dereference obj/isa/cache to crash before _objc_fixupMessageRef
935 movq 8(%a2), %a6 // selector
936 GetIsa FPRET // r11 = isa = *receiver
937 movq cache(%r11), %a5 // cache = *isa
938 movq mask(%a5), %a4 // *cache
941 // a2 = address of message ref
944 // __objc_fixupMessageRef(receiver, 0, ref)
945 call __objc_fixupMessageRef
948 RestoreRegisters _objc_msgSend_fpret_fixup
951 // Load _cmd from the message_ref
953 cmp %r11, %r11 // set nonstret (eq) for forwarding
958 DW_END _objc_msgSend_fpret_fixup
959 END_ENTRY _objc_msgSend_fpret_fixup
962 STATIC_ENTRY _objc_msgSend_fpret_fixedup
963 // Load _cmd from the message_ref
965 jmp _objc_msgSend_fpret
966 END_ENTRY _objc_msgSend_fpret_fixedup
970 /********************************************************************
972 * double objc_msgSend_fp2ret(id self, SEL _cmd,...);
973 * Used for `complex long double` return only.
975 ********************************************************************/
977 ENTRY _objc_msgSend_fp2ret
978 DW_START _objc_msgSend_fp2ret
982 GetIsaFast FP2RET // r11 = self->isa
983 CacheLookup FP2RET // r11 = method, eq set (nonstret fwd)
984 jmp *method_imp(%r11) // goto *imp
986 NilTestSupport FP2RET
990 // cache miss: go search the method lists
992 GetIsa FP2RET // r11 = self->isa
993 MethodTableLookup %a1, %a2, _objc_msgSend_fp2ret // r11 = IMP
994 cmp %r11, %r11 // set eq (nonstret) for forwarding
995 jmp *%r11 // goto *imp
997 DW_END _objc_msgSend_fp2ret
998 END_ENTRY _objc_msgSend_fp2ret
1001 ENTRY _objc_msgSend_fp2ret_fixup
1002 DW_START _objc_msgSend_fp2ret_fixup
1006 SaveRegisters _objc_msgSend_fp2ret_fixup
1008 // Dereference obj/isa/cache to crash before _objc_fixupMessageRef
1009 movq 8(%a2), %a6 // selector
1010 GetIsa FP2RET // r11 = isa = *receiver
1011 movq cache(%r11), %a5 // cache = *isa
1012 movq mask(%a5), %a4 // *cache
1015 // a2 = address of message ref
1018 // __objc_fixupMessageRef(receiver, 0, ref)
1019 call __objc_fixupMessageRef
1022 RestoreRegisters _objc_msgSend_fp2ret_fixup
1025 // Load _cmd from the message_ref
1027 cmp %r11, %r11 // set nonstret (eq) for forwarding
1030 NilTestSupport FP2RET
1032 DW_END _objc_msgSend_fp2ret_fixup
1033 END_ENTRY _objc_msgSend_fp2ret_fixup
1036 STATIC_ENTRY _objc_msgSend_fp2ret_fixedup
1037 // Load _cmd from the message_ref
1039 jmp _objc_msgSend_fp2ret
1040 END_ENTRY _objc_msgSend_fp2ret_fixedup
1044 /********************************************************************
1046 * void objc_msgSend_stret(void *st_addr, id self, SEL _cmd, ...);
1048 * objc_msgSend_stret is the struct-return form of msgSend.
1049 * The ABI calls for %a1 to be used as the address of the structure
1050 * being returned, with the parameters in the succeeding locations.
1052 * On entry: %a1 is the address where the structure is returned,
1053 * %a2 is the message receiver,
1054 * %a3 is the selector
1055 ********************************************************************/
1057 ENTRY _objc_msgSend_stret
1058 DW_START _objc_msgSend_stret
1062 GetIsaFast STRET // r11 = self->isa
1063 CacheLookup STRET // r11 = method, ne set (stret fwd)
1064 jmp *method_imp(%r11) // goto *imp
1066 NilTestSupport STRET
1070 // cache miss: go search the method lists
1072 GetIsa STRET // r11 = self->isa
1073 MethodTableLookup %a2, %a3, _objc_msgSend_stret // r11 = IMP
1074 test %r11, %r11 // set ne (stret) for forward; r11!=0
1075 jmp *%r11 // goto *imp
1077 DW_END _objc_msgSend_stret
1078 END_ENTRY _objc_msgSend_stret
1081 ENTRY _objc_msgSend_stret_fixup
1082 DW_START _objc_msgSend_stret_fixup
1086 SaveRegisters _objc_msgSend_stret_fixup
1088 // Dereference obj/isa/cache to crash before _objc_fixupMessageRef
1089 movq 8(%a3), %a6 // selector
1090 GetIsa STRET // r11 = isa = *receiver
1091 movq cache(%r11), %a5 // cache = *isa
1092 movq mask(%a5), %a4 // *cache
1095 // a3 = address of message ref
1098 // __objc_fixupMessageRef(receiver, 0, ref)
1099 call __objc_fixupMessageRef
1102 RestoreRegisters _objc_msgSend_stret_fixup
1105 // Load _cmd from the message_ref
1107 test %r11, %r11 // set stret (ne) for forward; r11!=0
1108 jmp *%r11 // goto *imp
1110 NilTestSupport STRET
1112 DW_END _objc_msgSend_stret_fixup
1113 END_ENTRY _objc_msgSend_stret_fixup
1116 STATIC_ENTRY _objc_msgSend_stret_fixedup
1117 // Load _cmd from the message_ref
1119 jmp _objc_msgSend_stret
1120 END_ENTRY _objc_msgSend_stret_fixedup
1124 /********************************************************************
1126 * void objc_msgSendSuper_stret(void *st_addr, struct objc_super *super, SEL _cmd, ...);
1128 * struct objc_super {
1133 * objc_msgSendSuper_stret is the struct-return form of msgSendSuper.
1134 * The ABI calls for (sp+4) to be used as the address of the structure
1135 * being returned, with the parameters in the succeeding registers.
1137 * On entry: %a1 is the address where the structure is returned,
1138 * %a2 is the address of the objc_super structure,
1139 * %a3 is the selector
1141 ********************************************************************/
1143 ENTRY _objc_msgSendSuper_stret
1144 DW_START _objc_msgSendSuper_stret
1146 // search the cache (objc_super in %a2)
1147 movq class(%a2), %r11 // class = objc_super->class
1148 CacheLookup STRET // r11 = method, ne set (stret fwd)
1149 movq receiver(%a2), %a2 // load real receiver
1150 jmp *method_imp(%r11) // goto *imp
1152 // cache miss: go search the method lists
1154 movq receiver(%a2), %r10
1155 movq class(%a2), %r11
1156 MethodTableLookup %r10, %a3, _objc_msgSendSuper_stret // r11 = IMP
1157 movq receiver(%a2), %a2 // load real receiver
1158 test %r11, %r11 // set ne (stret) for forward; r11!=0
1159 jmp *%r11 // goto *imp
1161 DW_END _objc_msgSendSuper_stret
1162 END_ENTRY _objc_msgSendSuper_stret
1165 /********************************************************************
1166 * id objc_msgSendSuper2_stret
1167 ********************************************************************/
1170 ENTRY _objc_msgSendSuper2_stret_fixup
1171 DW_START _objc_msgSendSuper2_stret_fixup
1173 SaveRegisters _objc_msgSendSuper2_stret_fixup
1174 // a2 = address of objc_super2
1175 // a3 = address of message ref
1176 movq receiver(%a2), %a1
1177 // __objc_fixupMessageRef(receiver, objc_super, ref)
1178 call __objc_fixupMessageRef
1180 RestoreRegisters _objc_msgSendSuper2_stret_fixup
1183 // Load _cmd from the message_ref
1185 // Load receiver from objc_super2
1186 movq receiver(%a2), %a2
1187 test %r11, %r11 // set stret (ne) for forward; r11!=0
1188 jmp *%r11 // goto *imp
1190 DW_END _objc_msgSendSuper2_stret_fixup
1191 END_ENTRY _objc_msgSendSuper2_stret_fixup
1194 STATIC_ENTRY _objc_msgSendSuper2_stret_fixedup
1195 movq 8(%a3), %a3 // load _cmd from message_ref
1196 jmp _objc_msgSendSuper2_stret
1197 END_ENTRY _objc_msgSendSuper2_stret_fixedup
1200 ENTRY _objc_msgSendSuper2_stret
1201 DW_START _objc_msgSendSuper2_stret
1203 // search the cache (objc_super in %a2)
1204 movq class(%a2), %r11 // class = objc_super->class
1205 movq 8(%r11), %r11 // class = class->super_class
1206 CacheLookup STRET // r11 = method, ne set (stret fwd)
1207 movq receiver(%a2), %a2 // load real receiver
1208 jmp *method_imp(%r11) // goto *imp
1210 // cache miss: go search the method lists
1212 movq receiver(%a2), %r10
1213 movq class(%a2), %r11
1215 MethodTableLookup %r10, %a3, _objc_msgSendSuper2_stret // r11 = IMP
1216 movq receiver(%a2), %a2 // load real receiver
1217 test %r11, %r11 // set ne (stret) for forward; r11!=0
1218 jmp *%r11 // goto *imp
1220 DW_END _objc_msgSendSuper2_stret
1221 END_ENTRY _objc_msgSendSuper2_stret
1225 /********************************************************************
1227 * id _objc_msgForward(id self, SEL _cmd,...);
1229 ********************************************************************/
1231 // _FwdSel is @selector(forward::), set up in map_images().
1232 // ALWAYS dereference _FwdSel to get to "forward::" !!
1235 .private_extern _FwdSel
1240 LUnkSelStr: .ascii "Does not recognize selector %s\0"
1244 .private_extern __objc_forward_handler
1245 __objc_forward_handler: .quad 0
1249 .private_extern __objc_forward_stret_handler
1250 __objc_forward_stret_handler: .quad 0
1253 STATIC_ENTRY __objc_msgForward_internal
1254 // Method cache version
1256 // THIS IS NOT A CALLABLE C FUNCTION
1257 // Out-of-band condition register is NE for stret, EQ otherwise.
1259 jne __objc_msgForward_stret
1260 jmp __objc_msgForward
1262 END_ENTRY __objc_msgForward_internal
1265 ENTRY __objc_msgForward
1266 // Non-stret version
1268 // Call user handler, if any
1269 movq __objc_forward_handler(%rip), %r11
1270 testq %r11, %r11 // if (handler == NULL)
1271 je 1f // skip handler
1272 jmp *%r11 // else goto handler
1276 // Die if forwarding "forward::"
1277 cmpq %a2, _FwdSel(%rip)
1280 // Record current return address. It will be copied elsewhere in
1281 // the marg_list because this location is needed for register args
1285 // Space for: fpArgs + regArgs + linkage - ret (already on stack)
1286 subq $ 8*16 + 6*8 + (4-1)*8, %rsp
1288 // Save return address in linkage area.
1289 movq %r11, 16+LINK_AREA(%rsp)
1291 // Save parameter registers
1292 movq %a1, 0+REG_AREA(%rsp)
1293 movq %a2, 8+REG_AREA(%rsp)
1294 movq %a3, 16+REG_AREA(%rsp)
1295 movq %a4, 24+REG_AREA(%rsp)
1296 movq %a5, 32+REG_AREA(%rsp)
1297 movq %a6, 40+REG_AREA(%rsp)
1299 // Save side parameter registers
1300 // movq %r10, 0+LINK_AREA(%rsp) // static chain pointer == Pascal
1301 movq %rax, 8+LINK_AREA(%rsp) // xmm count
1302 // 16+LINK_AREA is return address
1304 // Save xmm registers
1305 movdqa %xmm0, 0+FP_AREA(%rsp)
1306 movdqa %xmm1, 16+FP_AREA(%rsp)
1307 movdqa %xmm2, 32+FP_AREA(%rsp)
1308 movdqa %xmm3, 48+FP_AREA(%rsp)
1309 movdqa %xmm4, 64+FP_AREA(%rsp)
1310 movdqa %xmm5, 80+FP_AREA(%rsp)
1311 movdqa %xmm6, 96+FP_AREA(%rsp)
1312 movdqa %xmm7, 112+FP_AREA(%rsp)
1314 // Call [receiver forward:sel :margs]
1315 movq %rsp, %a4 // marg_list
1316 movq %a2, %a3 // sel
1317 movq _FwdSel(%rip), %a2 // forward::
1318 // %a1 is already the receiver
1322 // Retrieve return address from linkage area
1323 movq 16+LINK_AREA(%rsp), %r11
1325 addq $ 8*16 + 6*8 + (4-1)*8, %rsp
1326 // Put return address back
1331 // Tail-call __objc_error(receiver, "unknown selector %s", "forward::")
1332 // %a1 is already the receiver
1333 leaq LUnkSelStr(%rip), %a2 // "unknown selector %s"
1334 movq _FwdSel(%rip), %a3 // forward::
1335 jmp ___objc_error // never returns
1337 END_ENTRY __objc_msgForward
1340 ENTRY __objc_msgForward_stret
1341 // Struct-return version
1343 // Call user handler, if any
1344 movq __objc_forward_stret_handler(%rip), %r11
1345 testq %r11, %r11 // if (handler == NULL)
1346 je 1f // skip handler
1347 jmp *%r11 // else goto handler
1350 // Die if forwarding "forward::"
1351 cmpq %a3, _FwdSel(%rip)
1352 je LMsgForwardStretError
1354 // Record current return address. It will be copied elsewhere in
1355 // the marg_list because this location is needed for register args
1359 // Space for: fpArgs + regArgs + linkage - ret (already on stack)
1360 subq $ 8*16 + 6*8 + (4-1)*8, %rsp
1362 // Save return address in linkage area.
1363 movq %r11, 16+LINK_AREA(%rsp)
1365 // Save parameter registers
1366 movq %a1, 0+REG_AREA(%rsp)
1367 movq %a2, 8+REG_AREA(%rsp)
1368 movq %a3, 16+REG_AREA(%rsp)
1369 movq %a4, 24+REG_AREA(%rsp)
1370 movq %a5, 32+REG_AREA(%rsp)
1371 movq %a6, 40+REG_AREA(%rsp)
1373 // Save side parameter registers
1374 // movq %r10, 0+LINK_AREA(%rsp) // static chain pointer == Pascal
1375 movq %rax, 8+LINK_AREA(%rsp) // xmm count
1376 // 16+LINK_AREA is return address
1378 // Save xmm registers
1379 movdqa %xmm0, 0+FP_AREA(%rsp)
1380 movdqa %xmm1, 16+FP_AREA(%rsp)
1381 movdqa %xmm2, 32+FP_AREA(%rsp)
1382 movdqa %xmm3, 48+FP_AREA(%rsp)
1383 movdqa %xmm4, 64+FP_AREA(%rsp)
1384 movdqa %xmm5, 80+FP_AREA(%rsp)
1385 movdqa %xmm6, 96+FP_AREA(%rsp)
1386 movdqa %xmm7, 112+FP_AREA(%rsp)
1388 // Call [receiver forward:sel :margs]
1389 movq %a2, %a1 // receiver
1390 movq _FwdSel(%rip), %a2 // forward::
1391 // %a3 is already the selector
1392 movq %rsp, %a4 // marg_list
1394 call _objc_msgSend // forward:: is NOT struct-return
1396 // Retrieve return address from linkage area
1397 movq 16+LINK_AREA(%rsp), %r11
1399 addq $ 8*16 + 6*8 + (4-1)*8, %rsp
1400 // Put return address back
1404 LMsgForwardStretError:
1405 // Tail-call __objc_error(receiver, "unknown selector %s", "forward::")
1406 movq %a2, %a1 // receiver
1407 leaq LUnkSelStr(%rip), %a2 // "unknown selector %s"
1408 movq _FwdSel(%rip), %a3 // forward::
1409 jmp ___objc_error // never returns
1411 END_ENTRY __objc_msgForward_stret
1414 ENTRY _objc_msgSend_debug
1416 END_ENTRY _objc_msgSend_debug
1418 ENTRY _objc_msgSendSuper2_debug
1419 jmp _objc_msgSendSuper2
1420 END_ENTRY _objc_msgSendSuper2_debug
1422 ENTRY _objc_msgSend_stret_debug
1423 jmp _objc_msgSend_stret
1424 END_ENTRY _objc_msgSend_stret_debug
1426 ENTRY _objc_msgSendSuper2_stret_debug
1427 jmp _objc_msgSendSuper2_stret
1428 END_ENTRY _objc_msgSendSuper2_stret_debug
1430 ENTRY _objc_msgSend_fpret_debug
1431 jmp _objc_msgSend_fpret
1432 END_ENTRY _objc_msgSend_fpret_debug
1434 ENTRY _objc_msgSend_fp2ret_debug
1435 jmp _objc_msgSend_fp2ret
1436 END_ENTRY _objc_msgSend_fp2ret_debug
1439 ENTRY _objc_msgSend_noarg
1441 END_ENTRY _objc_msgSend_noarg
1444 ENTRY _method_invoke
1446 movq method_imp(%a2), %r11
1447 movq method_name(%a2), %a2
1450 END_ENTRY _method_invoke
1453 ENTRY _method_invoke_stret
1455 movq method_imp(%a3), %r11
1456 movq method_name(%a3), %a3
1459 END_ENTRY _method_invoke_stret
1462 STATIC_ENTRY __objc_ignored_method
1467 END_ENTRY __objc_ignored_method
1470 /********************************************************************
1472 * id vtable_prototype(id self, message_ref *msg, ...)
1474 * This code is copied to create vtable trampolines.
1475 * The instruction following LvtableIndex is modified to
1476 * insert each vtable index.
1477 * The instructions following LvtableTagTable are modified to
1478 * load the tagged isa table.
1480 * This code is placed in its own section to prevent dtrace from
1481 * instrumenting it. Otherwise, dtrace would insert an INT3, the
1482 * code would be copied, and the copied INT3 would cause a crash.
1484 * ABI WARNING ABI WARNING ABI WARNING ABI WARNING ABI WARNING
1485 * vtable_prototype steals %rax and does not clear %rdx on return
1486 * in order to precisely pack instructions into ifetch and cache lines
1487 * This means vtable dispatch must never be used for vararg calls
1488 * or very large return values.
1489 * ABI WARNING ABI WARNING ABI WARNING ABI WARNING ABI WARNING
1491 ********************************************************************/
1493 .macro VTABLE /* byte-offset, name */
1499 je LvtableReturnZero_$1 // nil check
1501 jne LvtableTaggedPointer_$1 // tag check
1503 movq (%a1), %rax // load isa (see ABI WARNING)
1504 movq 24(%rax), %rax // load vtable
1505 movq 8(%a2), %a2 // load _cmd
1507 jmpq * $0 (%rax) // load imp (DO NOT CHANGE)
1509 LvtableReturnZero_$1:
1510 // integer registers only; not used for fpret / stret / etc
1512 // xorl %edx, %edx (see ABI WARNING)
1516 LvtableTaggedPointer_$1:
1517 // extract isa (bits 1-2-3) from %a1, bit 0 is kept around for the heck of it
1522 movq $$0x1122334455667788, %r10 // vtable_prototype (DO NOT CHANGE)
1524 leaq __objc_tagged_isa_table(%rip), %r10
1526 LvtableTagTableEnd_$1:
1527 movq (%r10, %rax, 8), %r10 // load isa from table (see ABI WARNING
1528 movq 24(%r10), %rax // load vtable
1529 movq 8(%a2), %a2 // load _cmd
1531 jmpq * $0 (%rax) // load imp (DO NOT CHANGE)
1537 .section __TEXT,__objc_codegen,regular
1538 VTABLE 0x7fff, vtable_prototype
1542 .private_extern _vtable_prototype_size
1543 _vtable_prototype_size:
1544 .long LvtableEnd_vtable_prototype - _vtable_prototype
1546 .private_extern _vtable_prototype_index_offset
1547 _vtable_prototype_index_offset:
1548 .long LvtableIndex_vtable_prototype - _vtable_prototype
1550 .private_extern _vtable_prototype_index2_offset
1551 _vtable_prototype_index2_offset:
1552 .long LvtableIndex2_vtable_prototype - _vtable_prototype
1554 .private_extern _vtable_prototype_tagtable_offset
1555 _vtable_prototype_tagtable_offset:
1556 .long LvtableTagTable_vtable_prototype - _vtable_prototype
1558 .private_extern _vtable_prototype_tagtable_size
1559 _vtable_prototype_tagtable_size:
1560 .long LvtableTagTableEnd_vtable_prototype - LvtableTagTable_vtable_prototype
1562 /********************************************************************
1564 * id vtable_ignored(id self, message_ref *msg, ...)
1566 * Vtable trampoline for GC-ignored selectors. Immediately returns self.
1568 ********************************************************************/
1570 STATIC_ENTRY _vtable_ignored
1575 /********************************************************************
1577 * id objc_msgSend_vtable<n>(id self, message_ref *msg, ...)
1579 * Built-in expansions of vtable_prototype for the default vtable.
1581 ********************************************************************/
1586 .private_extern _defaultVtableTrampolineDescriptors
1587 _defaultVtableTrampolineDescriptors:
1588 // objc_trampoline_header
1589 .short 16 // headerSize
1590 .short 8 // descSize
1591 .long 16 // descCount
1594 // objc_trampoline_descriptor[16]
1595 .macro TDESC /* n */
1597 .long _objc_msgSend_vtable$0 - L_tdesc$0
1598 .long (1<<0) + (1<<2) // MESSAGE and VTABLE
1620 VTABLE 0*8, objc_msgSend_vtable0
1621 VTABLE 1*8, objc_msgSend_vtable1
1622 VTABLE 2*8, objc_msgSend_vtable2
1623 VTABLE 3*8, objc_msgSend_vtable3
1624 VTABLE 4*8, objc_msgSend_vtable4
1625 VTABLE 5*8, objc_msgSend_vtable5
1626 VTABLE 6*8, objc_msgSend_vtable6
1627 VTABLE 7*8, objc_msgSend_vtable7
1628 VTABLE 8*8, objc_msgSend_vtable8
1629 VTABLE 9*8, objc_msgSend_vtable9
1630 VTABLE 10*8, objc_msgSend_vtable10
1631 VTABLE 11*8, objc_msgSend_vtable11
1632 VTABLE 12*8, objc_msgSend_vtable12
1633 VTABLE 13*8, objc_msgSend_vtable13
1634 VTABLE 14*8, objc_msgSend_vtable14
1635 VTABLE 15*8, objc_msgSend_vtable15