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 1*-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 L_dw_start_$0-. # FDE address start
313 .quad L_dw_len_$0 # FDE address range
314 .byte 0x0 # uleb128 0x0; Augmentation size
316 // DW_START: set by CIE
322 .byte DW_CFA_advance_loc4
323 .long L_dw_push_$0 - L_dw_start_$0
324 .byte DW_CFA_def_cfa_offset // CFA = rsp+16
328 .byte DW_CFA_advance_loc4
329 .long L_dw_pop_$0 - L_dw_push_$0
330 .byte DW_CFA_def_cfa_offset // CFA = rsp+8
333 // cache miss: push is back in effect
334 .byte DW_CFA_advance_loc4
335 .long L_dw_miss_$0 - L_dw_pop_$0
336 .byte DW_CFA_def_cfa_offset // CFA = rsp+16
339 // pop during cache miss
340 .byte DW_CFA_advance_loc4
341 .long L_dw_miss_pop_$0 - L_dw_miss_$0
342 .byte DW_CFA_def_cfa_offset // CFA = rsp+8
348 // Save/RestoreRegisters or MethodTableLookup
351 .byte DW_CFA_advance_loc4
353 .long L_dw_enter_$0 - L_dw_miss_pop_$0
355 .long L_dw_enter_$0 - L_dw_start_$0
357 .byte DW_CFA_def_cfa_offset
359 .byte DW_CFA_offset | DW_rbp // rbp => 2*-8(CFA)
361 .byte DW_CFA_def_cfa_register // CFA = rbp+16 (offset unchanged)
365 .byte DW_CFA_advance_loc4
366 .long L_dw_leave_$0 - L_dw_enter_$0
368 .byte DW_CFA_same_value // rbp = original value
370 .byte DW_CFA_def_cfa // CFA = rsp+8
388 // After `push` in CacheLookup
393 // After `pop` in CacheLookup
398 // After cache miss label
403 // After pop in MethodTableLookup
408 // After `enter` in SaveRegisters
413 // After `leave` in RestoreRegisters
419 // $1 == 1 iff you called CacheLookup
420 // $2 == 1 iff you called MethodTableLookup or Save/RestoreRegsters
422 .set L_dw_len_$0, . - L_dw_start_$0
427 /////////////////////////////////////////////////////////////////////
429 // SaveRegisters caller
431 // Pushes a stack frame and saves all registers that might contain
434 // On entry: %0 = caller's symbol name for DWARF
438 // %rsp is 16-byte aligned
440 /////////////////////////////////////////////////////////////////////
443 // These instructions must match the DWARF data in EMIT_FDE.
445 enter $$0x80+8, $$0 // +8 for alignment
448 movdqa %xmm0, -0x80(%rbp)
449 push %rax // might be xmm parameter count
450 movdqa %xmm1, -0x70(%rbp)
452 movdqa %xmm2, -0x60(%rbp)
454 movdqa %xmm3, -0x50(%rbp)
456 movdqa %xmm4, -0x40(%rbp)
458 movdqa %xmm5, -0x30(%rbp)
460 movdqa %xmm6, -0x20(%rbp)
462 movdqa %xmm7, -0x10(%rbp)
464 // These instructions must match the DWARF data in EMIT_FDE.
467 /////////////////////////////////////////////////////////////////////
471 // Pops a stack frame pushed by SaveRegisters
473 // On entry: $0 = caller's symbol name for DWARF
474 // %rbp unchanged since SaveRegisters
479 /////////////////////////////////////////////////////////////////////
481 .macro RestoreRegisters
482 // These instructions must match the DWARF data in EMIT_FDE.
484 movdqa -0x80(%rbp), %xmm0
486 movdqa -0x70(%rbp), %xmm1
488 movdqa -0x60(%rbp), %xmm2
490 movdqa -0x50(%rbp), %xmm3
492 movdqa -0x40(%rbp), %xmm4
494 movdqa -0x30(%rbp), %xmm5
496 movdqa -0x20(%rbp), %xmm6
498 movdqa -0x10(%rbp), %xmm7
503 // These instructions must match the DWARF data in EMIT_FDE.
507 /////////////////////////////////////////////////////////////////////
510 // CacheLookup return-type, caller
512 // Locate the implementation for a selector in a class method cache.
515 // $0 = NORMAL, FPRET, FP2RET, STRET
516 // $1 = caller's symbol name for DWARF
517 // a2 or a3 (STRET) = selector
518 // %r11 = class whose cache is to be searched
520 // On exit: (found) method in %r11, stack unchanged, eq/ne set for forwarding
521 // (not found) jumps to LCacheMiss, %rax on stack
523 /////////////////////////////////////////////////////////////////////
530 movq cache(%r11), %r10 // cache = class->cache
532 mov %a2d, %eax // index = sel
534 mov %a3d, %eax // index = sel
537 // search the receiver's cache
538 // r11 = method (soon)
543 andl mask(%r10), %eax // index &= mask
544 movq buckets(%r10, %rax, 8), %r11 // method = cache->buckets[index]
546 testq %r11, %r11 // if (method == NULL)
547 je LCacheMiss_f // goto cacheMissLabel
549 cmpq method_name(%r11), %a2 // if (method_name != sel)
551 cmpq method_name(%r11), %a3 // if (method_name != sel)
555 // cache hit, r11 = method triplet
556 // restore saved registers
561 // eq (non-stret) flag already set above
563 // set ne (stret) for forwarding; r11 != 0
570 /////////////////////////////////////////////////////////////////////
572 // MethodTableLookup classRegister, selectorRegister, caller
574 // Takes: $0 = class to search (a1 or a2 or r10 ONLY)
575 // $1 = selector to search for (a2 or a3 ONLY)
576 // $2 = caller's symbol name for DWARF
577 // r11 = class to search
579 // Stack: ret, rax (pushed by CacheLookup)
581 // On exit: pops registers pushed by CacheLookup
584 /////////////////////////////////////////////////////////////////////
585 .macro MethodTableLookup
587 pop %rax // saved by CacheLookup
592 // _class_lookupMethodAndLoadCache3(receiver, selector, class)
597 call __class_lookupMethodAndLoadCache3
599 // IMP is now in %rax
606 /////////////////////////////////////////////////////////////////////
608 // GetIsa return-type
609 // GetIsaFast return-type
610 // GetIsaSupport return-type
612 // Sets r11 = obj->isa. Consults the tagged isa table if necessary.
614 // Takes: $0 = NORMAL or FPRET or FP2RET or STRET
615 // a1 or a2 (STRET) = receiver
617 // On exit: r11 = receiver->isa
620 /////////////////////////////////////////////////////////////////////
638 leaq __objc_tagged_isa_table(%rip), %r11
639 movq (%r11, %r10, 8), %r11 // read isa from table
646 .byte 0x2e // harmless branch hint prefix to align IFETCH blocks
651 .byte 0x2e // harmless branch hint prefix to align IFETCH blocks
660 leaq __objc_tagged_isa_table(%rip), %r11
667 movq (%r11, %r10, 8), %r11 // read isa from table
671 /////////////////////////////////////////////////////////////////////
673 // NilTest return-type
675 // Takes: $0 = NORMAL or FPRET or FP2RET or STRET
676 // %a1 or %a2 (STRET) = receiver
678 // On exit: Loads non-nil receiver in %a1 or %a2 (STRET), or returns zero.
680 // NilTestSupport return-type
682 // Takes: $0 = NORMAL or FPRET or FP2RET or STRET
683 // %a1 or %a2 (STRET) = receiver
685 // On exit: Loads non-nil receiver in %a1 or %a2 (STRET), or returns zero.
687 /////////////////////////////////////////////////////////////////////
699 .macro NilTestSupport
703 movq __objc_nilReceiver(%rip), %a1
704 testq %a1, %a1 // if (receiver != nil)
706 movq __objc_nilReceiver(%rip), %a2
707 testq %a2, %a2 // if (receiver != nil)
709 jne LNilTestDone_b // send to new receiver
727 /********************************************************************
728 * Method _cache_getMethod(Class cls, SEL sel, IMP msgForward_internal_imp)
730 * On entry: a1 = class whose cache is to be searched
731 * a2 = selector to search for
732 * a3 = _objc_msgForward_internal IMP
734 * If found, returns method triplet pointer.
735 * If not found, returns NULL.
737 * NOTE: _cache_getMethod never returns any cache entry whose implementation
738 * is _objc_msgForward_internal. It returns 1 instead. This prevents thread-
739 * thread-safety and memory management bugs in _class_lookupMethodAndLoadCache.
740 * See _class_lookupMethodAndLoadCache for details.
742 * _objc_msgForward_internal is passed as a parameter because it's more
743 * efficient to do the (PIC) lookup once in the caller than repeatedly here.
744 ********************************************************************/
746 STATIC_ENTRY __cache_getMethod
747 DW_START __cache_getMethod
750 movq %a1, %r11 // move class to r11 for CacheLookup
751 CacheLookup NORMAL, __cache_getMethod
753 // cache hit, method triplet in %r11
754 cmpq method_imp(%r11), %a3 // if (imp==_objc_msgForward_internal)
755 je 1f // return (Method)1
756 movq %r11, %rax // return method triplet address
762 // cache miss, return nil
763 DW_MISS __cache_getMethod
764 pop %rax // pushed by CacheLookup
765 DW_MISS_POP __cache_getMethod
770 DW_END __cache_getMethod, 1, 0
771 END_ENTRY __cache_getMethod
774 /********************************************************************
775 * IMP _cache_getImp(Class cls, SEL sel)
777 * On entry: a1 = class whose cache is to be searched
778 * a2 = selector to search for
780 * If found, returns method implementation.
781 * If not found, returns NULL.
782 ********************************************************************/
784 STATIC_ENTRY __cache_getImp
785 DW_START __cache_getImp
788 movq %a1, %r11 // move class to r11 for CacheLookup
789 CacheLookup NORMAL, __cache_getImp
791 // cache hit, method triplet in %r11
792 movq method_imp(%r11), %rax // return method imp address
796 // cache miss, return nil
797 DW_MISS __cache_getImp
798 pop %rax // pushed by CacheLookup
799 DW_MISS_POP __cache_getImp
804 DW_END __cache_getImp, 1, 0
805 END_ENTRY __cache_getImp
808 /********************************************************************
810 * id objc_msgSend(id self, SEL _cmd,...);
812 ********************************************************************/
816 .private_extern __objc_tagged_isa_table
817 __objc_tagged_isa_table:
821 DW_START _objc_msgSend
825 GetIsaFast NORMAL // r11 = self->isa
826 CacheLookup NORMAL, _objc_msgSend // r11=method, eq set (nonstret fwd)
827 jmp *method_imp(%r11) // goto *imp
829 NilTestSupport NORMAL
833 // cache miss: go search the method lists
835 DW_MISS _objc_msgSend
836 GetIsa NORMAL // r11 = self->isa
837 MethodTableLookup %a1, %a2, _objc_msgSend // r11 = IMP
838 cmp %r11, %r11 // set eq (nonstret) for forwarding
839 jmp *%r11 // goto *imp
841 DW_END _objc_msgSend, 1, 1
842 END_ENTRY _objc_msgSend
845 ENTRY _objc_msgSend_fixup
846 DW_START _objc_msgSend_fixup
850 SaveRegisters _objc_msgSend_fixup
852 // Dereference obj/isa/cache to crash before _objc_fixupMessageRef
853 movq 8(%a2), %a6 // selector
854 GetIsa NORMAL // r11 = isa = *receiver
855 movq cache(%r11), %a5 // cache = *isa
856 movq mask(%a5), %a4 // *cache
859 // a2 = address of message ref
862 // __objc_fixupMessageRef(receiver, 0, ref)
863 call __objc_fixupMessageRef
866 RestoreRegisters _objc_msgSend_fixup
869 // Load _cmd from the message_ref
871 cmp %r11, %r11 // set nonstret (eq) for forwarding
874 NilTestSupport NORMAL
876 DW_END _objc_msgSend_fixup, 0, 1
877 END_ENTRY _objc_msgSend_fixup
880 STATIC_ENTRY _objc_msgSend_fixedup
881 // Load _cmd from the message_ref
884 END_ENTRY _objc_msgSend_fixedup
888 /********************************************************************
890 * id objc_msgSendSuper(struct objc_super *super, SEL _cmd,...);
892 * struct objc_super {
896 ********************************************************************/
898 ENTRY _objc_msgSendSuper
899 DW_START _objc_msgSendSuper
901 // search the cache (objc_super in %a1)
902 movq class(%a1), %r11 // class = objc_super->class
903 CacheLookup NORMAL, _objc_msgSendSuper // r11 = method, eq set (nonstret fwd)
904 movq receiver(%a1), %a1 // load real receiver
905 jmp *method_imp(%r11) // goto *imp
907 // cache miss: go search the method lists
909 DW_MISS _objc_msgSendSuper
910 movq receiver(%a1), %r10
911 movq class(%a1), %r11
912 MethodTableLookup %r10, %a2, _objc_msgSendSuper // r11 = IMP
913 movq receiver(%a1), %a1 // load real receiver
914 cmp %r11, %r11 // set eq (nonstret) for forwarding
915 jmp *%r11 // goto *imp
917 DW_END _objc_msgSendSuper, 1, 1
918 END_ENTRY _objc_msgSendSuper
921 /********************************************************************
922 * id objc_msgSendSuper2
923 ********************************************************************/
926 ENTRY _objc_msgSendSuper2_fixup
927 DW_START _objc_msgSendSuper2_fixup
929 SaveRegisters _objc_msgSendSuper2_fixup
930 // a1 = address of objc_super2
931 // a2 = address of message ref
934 movq receiver(%a1), %a1
935 // __objc_fixupMessageRef(receiver, objc_super, ref)
936 call __objc_fixupMessageRef
938 RestoreRegisters _objc_msgSendSuper2_fixup
941 // Load _cmd from the message_ref
943 // Load receiver from objc_super2
944 movq receiver(%a1), %a1
945 cmp %r11, %r11 // set nonstret (eq) for forwarding
948 DW_END _objc_msgSendSuper2_fixup, 0, 1
949 END_ENTRY _objc_msgSendSuper2_fixup
952 STATIC_ENTRY _objc_msgSendSuper2_fixedup
953 movq 8(%a2), %a2 // load _cmd from message_ref
954 jmp _objc_msgSendSuper2
955 END_ENTRY _objc_msgSendSuper2_fixedup
958 ENTRY _objc_msgSendSuper2
959 DW_START _objc_msgSendSuper2
960 // objc_super->class is superclass of class to search
962 // search the cache (objc_super in %a1)
963 movq class(%a1), %r11 // cls = objc_super->class
964 movq 8(%r11), %r11 // cls = class->superclass
965 CacheLookup NORMAL, _objc_msgSendSuper2 // r11 = method, eq set (nonstret fwd)
966 movq receiver(%a1), %a1 // load real receiver
967 jmp *method_imp(%r11) // goto *imp
969 // cache miss: go search the method lists
971 DW_MISS _objc_msgSendSuper2
972 movq receiver(%a1), %r10
973 movq class(%a1), %r11
975 MethodTableLookup %r10, %a2, _objc_msgSendSuper2 // r11 = IMP
976 movq receiver(%a1), %a1 // load real receiver
977 cmp %r11, %r11 // set eq (nonstret) for forwarding
978 jmp *%r11 // goto *imp
980 DW_END _objc_msgSendSuper2, 1, 1
981 END_ENTRY _objc_msgSendSuper2
985 /********************************************************************
987 * double objc_msgSend_fpret(id self, SEL _cmd,...);
988 * Used for `long double` return only. `float` and `double` use objc_msgSend.
990 ********************************************************************/
992 ENTRY _objc_msgSend_fpret
993 DW_START _objc_msgSend_fpret
997 GetIsaFast FPRET // r11 = self->isa
998 CacheLookup FPRET, _objc_msgSend_fpret // r11 = method, eq set (nonstret fwd)
999 jmp *method_imp(%r11) // goto *imp
1001 NilTestSupport FPRET
1005 // cache miss: go search the method lists
1007 DW_MISS _objc_msgSend_fpret
1008 GetIsa FPRET // r11 = self->isa
1009 MethodTableLookup %a1, %a2, _objc_msgSend_fpret // r11 = IMP
1010 cmp %r11, %r11 // set eq (nonstret) for forwarding
1011 jmp *%r11 // goto *imp
1013 DW_END _objc_msgSend_fpret, 1, 1
1014 END_ENTRY _objc_msgSend_fpret
1017 ENTRY _objc_msgSend_fpret_fixup
1018 DW_START _objc_msgSend_fpret_fixup
1022 SaveRegisters _objc_msgSend_fpret_fixup
1024 // Dereference obj/isa/cache to crash before _objc_fixupMessageRef
1025 movq 8(%a2), %a6 // selector
1026 GetIsa FPRET // r11 = isa = *receiver
1027 movq cache(%r11), %a5 // cache = *isa
1028 movq mask(%a5), %a4 // *cache
1031 // a2 = address of message ref
1034 // __objc_fixupMessageRef(receiver, 0, ref)
1035 call __objc_fixupMessageRef
1038 RestoreRegisters _objc_msgSend_fpret_fixup
1041 // Load _cmd from the message_ref
1043 cmp %r11, %r11 // set nonstret (eq) for forwarding
1046 NilTestSupport FPRET
1048 DW_END _objc_msgSend_fpret_fixup, 0, 1
1049 END_ENTRY _objc_msgSend_fpret_fixup
1052 STATIC_ENTRY _objc_msgSend_fpret_fixedup
1053 // Load _cmd from the message_ref
1055 jmp _objc_msgSend_fpret
1056 END_ENTRY _objc_msgSend_fpret_fixedup
1060 /********************************************************************
1062 * double objc_msgSend_fp2ret(id self, SEL _cmd,...);
1063 * Used for `complex long double` return only.
1065 ********************************************************************/
1067 ENTRY _objc_msgSend_fp2ret
1068 DW_START _objc_msgSend_fp2ret
1072 GetIsaFast FP2RET // r11 = self->isa
1073 CacheLookup FP2RET, _objc_msgSend_fp2ret // r11 = method, eq set (nonstret fwd)
1074 jmp *method_imp(%r11) // goto *imp
1076 NilTestSupport FP2RET
1078 GetIsaSupport FP2RET
1080 // cache miss: go search the method lists
1082 DW_MISS _objc_msgSend_fp2ret
1083 GetIsa FP2RET // r11 = self->isa
1084 MethodTableLookup %a1, %a2, _objc_msgSend_fp2ret // r11 = IMP
1085 cmp %r11, %r11 // set eq (nonstret) for forwarding
1086 jmp *%r11 // goto *imp
1088 DW_END _objc_msgSend_fp2ret, 1, 1
1089 END_ENTRY _objc_msgSend_fp2ret
1092 ENTRY _objc_msgSend_fp2ret_fixup
1093 DW_START _objc_msgSend_fp2ret_fixup
1097 SaveRegisters _objc_msgSend_fp2ret_fixup
1099 // Dereference obj/isa/cache to crash before _objc_fixupMessageRef
1100 movq 8(%a2), %a6 // selector
1101 GetIsa FP2RET // r11 = isa = *receiver
1102 movq cache(%r11), %a5 // cache = *isa
1103 movq mask(%a5), %a4 // *cache
1106 // a2 = address of message ref
1109 // __objc_fixupMessageRef(receiver, 0, ref)
1110 call __objc_fixupMessageRef
1113 RestoreRegisters _objc_msgSend_fp2ret_fixup
1116 // Load _cmd from the message_ref
1118 cmp %r11, %r11 // set nonstret (eq) for forwarding
1121 NilTestSupport FP2RET
1123 DW_END _objc_msgSend_fp2ret_fixup, 0, 1
1124 END_ENTRY _objc_msgSend_fp2ret_fixup
1127 STATIC_ENTRY _objc_msgSend_fp2ret_fixedup
1128 // Load _cmd from the message_ref
1130 jmp _objc_msgSend_fp2ret
1131 END_ENTRY _objc_msgSend_fp2ret_fixedup
1135 /********************************************************************
1137 * void objc_msgSend_stret(void *st_addr, id self, SEL _cmd, ...);
1139 * objc_msgSend_stret is the struct-return form of msgSend.
1140 * The ABI calls for %a1 to be used as the address of the structure
1141 * being returned, with the parameters in the succeeding locations.
1143 * On entry: %a1 is the address where the structure is returned,
1144 * %a2 is the message receiver,
1145 * %a3 is the selector
1146 ********************************************************************/
1148 ENTRY _objc_msgSend_stret
1149 DW_START _objc_msgSend_stret
1153 GetIsaFast STRET // r11 = self->isa
1154 CacheLookup STRET, _objc_msgSend_stret // r11 = method, ne set (stret fwd)
1155 jmp *method_imp(%r11) // goto *imp
1157 NilTestSupport STRET
1161 // cache miss: go search the method lists
1163 DW_MISS _objc_msgSend_stret
1164 GetIsa STRET // r11 = self->isa
1165 MethodTableLookup %a2, %a3, _objc_msgSend_stret // r11 = IMP
1166 test %r11, %r11 // set ne (stret) for forward; r11!=0
1167 jmp *%r11 // goto *imp
1169 DW_END _objc_msgSend_stret, 1, 1
1170 END_ENTRY _objc_msgSend_stret
1173 ENTRY _objc_msgSend_stret_fixup
1174 DW_START _objc_msgSend_stret_fixup
1178 SaveRegisters _objc_msgSend_stret_fixup
1180 // Dereference obj/isa/cache to crash before _objc_fixupMessageRef
1181 movq 8(%a3), %a6 // selector
1182 GetIsa STRET // r11 = isa = *receiver
1183 movq cache(%r11), %a5 // cache = *isa
1184 movq mask(%a5), %a4 // *cache
1187 // a3 = address of message ref
1190 // __objc_fixupMessageRef(receiver, 0, ref)
1191 call __objc_fixupMessageRef
1194 RestoreRegisters _objc_msgSend_stret_fixup
1197 // Load _cmd from the message_ref
1199 test %r11, %r11 // set stret (ne) for forward; r11!=0
1200 jmp *%r11 // goto *imp
1202 NilTestSupport STRET
1204 DW_END _objc_msgSend_stret_fixup, 0, 1
1205 END_ENTRY _objc_msgSend_stret_fixup
1208 STATIC_ENTRY _objc_msgSend_stret_fixedup
1209 // Load _cmd from the message_ref
1211 jmp _objc_msgSend_stret
1212 END_ENTRY _objc_msgSend_stret_fixedup
1216 /********************************************************************
1218 * void objc_msgSendSuper_stret(void *st_addr, struct objc_super *super, SEL _cmd, ...);
1220 * struct objc_super {
1225 * objc_msgSendSuper_stret is the struct-return form of msgSendSuper.
1226 * The ABI calls for (sp+4) to be used as the address of the structure
1227 * being returned, with the parameters in the succeeding registers.
1229 * On entry: %a1 is the address where the structure is returned,
1230 * %a2 is the address of the objc_super structure,
1231 * %a3 is the selector
1233 ********************************************************************/
1235 ENTRY _objc_msgSendSuper_stret
1236 DW_START _objc_msgSendSuper_stret
1238 // search the cache (objc_super in %a2)
1239 movq class(%a2), %r11 // class = objc_super->class
1240 CacheLookup STRET, _objc_msgSendSuper_stret // r11 = method, ne set (stret fwd)
1241 movq receiver(%a2), %a2 // load real receiver
1242 jmp *method_imp(%r11) // goto *imp
1244 // cache miss: go search the method lists
1246 DW_MISS _objc_msgSendSuper_stret
1247 movq receiver(%a2), %r10
1248 movq class(%a2), %r11
1249 MethodTableLookup %r10, %a3, _objc_msgSendSuper_stret // r11 = IMP
1250 movq receiver(%a2), %a2 // load real receiver
1251 test %r11, %r11 // set ne (stret) for forward; r11!=0
1252 jmp *%r11 // goto *imp
1254 DW_END _objc_msgSendSuper_stret, 1, 1
1255 END_ENTRY _objc_msgSendSuper_stret
1258 /********************************************************************
1259 * id objc_msgSendSuper2_stret
1260 ********************************************************************/
1263 ENTRY _objc_msgSendSuper2_stret_fixup
1264 DW_START _objc_msgSendSuper2_stret_fixup
1266 SaveRegisters _objc_msgSendSuper2_stret_fixup
1267 // a2 = address of objc_super2
1268 // a3 = address of message ref
1269 movq receiver(%a2), %a1
1270 // __objc_fixupMessageRef(receiver, objc_super, ref)
1271 call __objc_fixupMessageRef
1273 RestoreRegisters _objc_msgSendSuper2_stret_fixup
1276 // Load _cmd from the message_ref
1278 // Load receiver from objc_super2
1279 movq receiver(%a2), %a2
1280 test %r11, %r11 // set stret (ne) for forward; r11!=0
1281 jmp *%r11 // goto *imp
1283 DW_END _objc_msgSendSuper2_stret_fixup, 0, 1
1284 END_ENTRY _objc_msgSendSuper2_stret_fixup
1287 STATIC_ENTRY _objc_msgSendSuper2_stret_fixedup
1288 movq 8(%a3), %a3 // load _cmd from message_ref
1289 jmp _objc_msgSendSuper2_stret
1290 END_ENTRY _objc_msgSendSuper2_stret_fixedup
1293 ENTRY _objc_msgSendSuper2_stret
1294 DW_START _objc_msgSendSuper2_stret
1296 // search the cache (objc_super in %a2)
1297 movq class(%a2), %r11 // class = objc_super->class
1298 movq 8(%r11), %r11 // class = class->super_class
1299 CacheLookup STRET, _objc_msgSendSuper2_stret // r11 = method, ne set (stret fwd)
1300 movq receiver(%a2), %a2 // load real receiver
1301 jmp *method_imp(%r11) // goto *imp
1303 // cache miss: go search the method lists
1305 DW_MISS _objc_msgSendSuper2_stret
1306 movq receiver(%a2), %r10
1307 movq class(%a2), %r11
1309 MethodTableLookup %r10, %a3, _objc_msgSendSuper2_stret // r11 = IMP
1310 movq receiver(%a2), %a2 // load real receiver
1311 test %r11, %r11 // set ne (stret) for forward; r11!=0
1312 jmp *%r11 // goto *imp
1314 DW_END _objc_msgSendSuper2_stret, 1, 1
1315 END_ENTRY _objc_msgSendSuper2_stret
1319 /********************************************************************
1321 * id _objc_msgForward(id self, SEL _cmd,...);
1323 ********************************************************************/
1325 // _FwdSel is @selector(forward::), set up in map_images().
1326 // ALWAYS dereference _FwdSel to get to "forward::" !!
1329 .private_extern _FwdSel
1334 LUnkSelStr: .ascii "Does not recognize selector %s (while forwarding %s)\0"
1338 .private_extern __objc_forward_handler
1339 __objc_forward_handler: .quad 0
1343 .private_extern __objc_forward_stret_handler
1344 __objc_forward_stret_handler: .quad 0
1347 STATIC_ENTRY __objc_msgForward_internal
1348 // Method cache version
1350 // THIS IS NOT A CALLABLE C FUNCTION
1351 // Out-of-band condition register is NE for stret, EQ otherwise.
1353 jne __objc_msgForward_stret
1354 jmp __objc_msgForward
1356 END_ENTRY __objc_msgForward_internal
1359 ENTRY __objc_msgForward
1360 // Non-stret version
1362 // Call user handler, if any
1363 movq __objc_forward_handler(%rip), %r11
1364 testq %r11, %r11 // if (handler == NULL)
1365 je 1f // skip handler
1366 jmp *%r11 // else goto handler
1370 // Die if forwarding "forward::"
1371 cmpq %a2, _FwdSel(%rip)
1374 // Record current return address. It will be copied elsewhere in
1375 // the marg_list because this location is needed for register args
1379 // Space for: fpArgs + regArgs + linkage - ret (already on stack)
1380 subq $ 8*16 + 6*8 + (4-1)*8, %rsp
1382 // Save return address in linkage area.
1383 movq %r11, 16+LINK_AREA(%rsp)
1385 // Save parameter registers
1386 movq %a1, 0+REG_AREA(%rsp)
1387 movq %a2, 8+REG_AREA(%rsp)
1388 movq %a3, 16+REG_AREA(%rsp)
1389 movq %a4, 24+REG_AREA(%rsp)
1390 movq %a5, 32+REG_AREA(%rsp)
1391 movq %a6, 40+REG_AREA(%rsp)
1393 // Save side parameter registers
1394 // movq %r10, 0+LINK_AREA(%rsp) // static chain pointer == Pascal
1395 movq %rax, 8+LINK_AREA(%rsp) // xmm count
1396 // 16+LINK_AREA is return address
1398 // Save xmm registers
1399 movdqa %xmm0, 0+FP_AREA(%rsp)
1400 movdqa %xmm1, 16+FP_AREA(%rsp)
1401 movdqa %xmm2, 32+FP_AREA(%rsp)
1402 movdqa %xmm3, 48+FP_AREA(%rsp)
1403 movdqa %xmm4, 64+FP_AREA(%rsp)
1404 movdqa %xmm5, 80+FP_AREA(%rsp)
1405 movdqa %xmm6, 96+FP_AREA(%rsp)
1406 movdqa %xmm7, 112+FP_AREA(%rsp)
1408 // Call [receiver forward:sel :margs]
1409 movq %rsp, %a4 // marg_list
1410 movq %a2, %a3 // sel
1411 movq _FwdSel(%rip), %a2 // forward::
1412 // %a1 is already the receiver
1416 // Retrieve return address from linkage area
1417 movq 16+LINK_AREA(%rsp), %r11
1419 addq $ 8*16 + 6*8 + (4-1)*8, %rsp
1420 // Put return address back
1425 // Tail-call __objc_error(receiver, "unknown selector %s %s", "forward::", forwardedSel)
1426 // %a1 is already the receiver
1427 movq %a3, %a4 // the forwarded selector
1428 leaq LUnkSelStr(%rip), %a2 // "unknown selector %s %s"
1429 movq _FwdSel(%rip), %a3 // forward::
1430 jmp ___objc_error // never returns
1432 END_ENTRY __objc_msgForward
1435 ENTRY __objc_msgForward_stret
1436 // Struct-return version
1438 // Call user handler, if any
1439 movq __objc_forward_stret_handler(%rip), %r11
1440 testq %r11, %r11 // if (handler == NULL)
1441 je 1f // skip handler
1442 jmp *%r11 // else goto handler
1445 // Die if forwarding "forward::"
1446 cmpq %a3, _FwdSel(%rip)
1447 je LMsgForwardStretError
1449 // Record current return address. It will be copied elsewhere in
1450 // the marg_list because this location is needed for register args
1454 // Space for: fpArgs + regArgs + linkage - ret (already on stack)
1455 subq $ 8*16 + 6*8 + (4-1)*8, %rsp
1457 // Save return address in linkage area.
1458 movq %r11, 16+LINK_AREA(%rsp)
1460 // Save parameter registers
1461 movq %a1, 0+REG_AREA(%rsp)
1462 movq %a2, 8+REG_AREA(%rsp)
1463 movq %a3, 16+REG_AREA(%rsp)
1464 movq %a4, 24+REG_AREA(%rsp)
1465 movq %a5, 32+REG_AREA(%rsp)
1466 movq %a6, 40+REG_AREA(%rsp)
1468 // Save side parameter registers
1469 // movq %r10, 0+LINK_AREA(%rsp) // static chain pointer == Pascal
1470 movq %rax, 8+LINK_AREA(%rsp) // xmm count
1471 // 16+LINK_AREA is return address
1473 // Save xmm registers
1474 movdqa %xmm0, 0+FP_AREA(%rsp)
1475 movdqa %xmm1, 16+FP_AREA(%rsp)
1476 movdqa %xmm2, 32+FP_AREA(%rsp)
1477 movdqa %xmm3, 48+FP_AREA(%rsp)
1478 movdqa %xmm4, 64+FP_AREA(%rsp)
1479 movdqa %xmm5, 80+FP_AREA(%rsp)
1480 movdqa %xmm6, 96+FP_AREA(%rsp)
1481 movdqa %xmm7, 112+FP_AREA(%rsp)
1483 // Call [receiver forward:sel :margs]
1484 movq %a2, %a1 // receiver
1485 movq _FwdSel(%rip), %a2 // forward::
1486 // %a3 is already the selector
1487 movq %rsp, %a4 // marg_list
1489 call _objc_msgSend // forward:: is NOT struct-return
1491 // Retrieve return address from linkage area
1492 movq 16+LINK_AREA(%rsp), %r11
1494 addq $ 8*16 + 6*8 + (4-1)*8, %rsp
1495 // Put return address back
1499 LMsgForwardStretError:
1500 // Tail-call __objc_error(receiver, "unknown selector %s %s", "forward::", forwardedSel)
1501 // %a4 is already the forwarded selector
1502 movq %a2, %a1 // receiver
1503 leaq LUnkSelStr(%rip), %a2 // "unknown selector %s %s"
1504 movq _FwdSel(%rip), %a3 // forward::
1505 jmp ___objc_error // never returns
1507 END_ENTRY __objc_msgForward_stret
1510 ENTRY _objc_msgSend_debug
1512 END_ENTRY _objc_msgSend_debug
1514 ENTRY _objc_msgSendSuper2_debug
1515 jmp _objc_msgSendSuper2
1516 END_ENTRY _objc_msgSendSuper2_debug
1518 ENTRY _objc_msgSend_stret_debug
1519 jmp _objc_msgSend_stret
1520 END_ENTRY _objc_msgSend_stret_debug
1522 ENTRY _objc_msgSendSuper2_stret_debug
1523 jmp _objc_msgSendSuper2_stret
1524 END_ENTRY _objc_msgSendSuper2_stret_debug
1526 ENTRY _objc_msgSend_fpret_debug
1527 jmp _objc_msgSend_fpret
1528 END_ENTRY _objc_msgSend_fpret_debug
1530 ENTRY _objc_msgSend_fp2ret_debug
1531 jmp _objc_msgSend_fp2ret
1532 END_ENTRY _objc_msgSend_fp2ret_debug
1535 ENTRY _objc_msgSend_noarg
1537 END_ENTRY _objc_msgSend_noarg
1540 ENTRY _method_invoke
1542 movq method_imp(%a2), %r11
1543 movq method_name(%a2), %a2
1546 END_ENTRY _method_invoke
1549 ENTRY _method_invoke_stret
1551 movq method_imp(%a3), %r11
1552 movq method_name(%a3), %a3
1555 END_ENTRY _method_invoke_stret
1558 STATIC_ENTRY __objc_ignored_method
1563 END_ENTRY __objc_ignored_method
1566 /********************************************************************
1568 * id vtable_prototype(id self, message_ref *msg, ...)
1570 * This code is copied to create vtable trampolines.
1571 * The instruction following LvtableIndex is modified to
1572 * insert each vtable index.
1573 * The instructions following LvtableTagTable are modified to
1574 * load the tagged isa table.
1576 * This code is placed in its own section to prevent dtrace from
1577 * instrumenting it. Otherwise, dtrace would insert an INT3, the
1578 * code would be copied, and the copied INT3 would cause a crash.
1580 * ABI WARNING ABI WARNING ABI WARNING ABI WARNING ABI WARNING
1581 * vtable_prototype steals %rax and does not clear %rdx on return
1582 * in order to precisely pack instructions into ifetch and cache lines
1583 * This means vtable dispatch must never be used for vararg calls
1584 * or very large return values.
1585 * ABI WARNING ABI WARNING ABI WARNING ABI WARNING ABI WARNING
1587 ********************************************************************/
1589 .macro VTABLE /* byte-offset, name */
1595 je LvtableReturnZero_$1 // nil check
1597 jne LvtableTaggedPointer_$1 // tag check
1599 movq (%a1), %rax // load isa (see ABI WARNING)
1600 movq 24(%rax), %rax // load vtable
1601 movq 8(%a2), %a2 // load _cmd
1603 jmpq * $0 (%rax) // load imp (DO NOT CHANGE)
1605 LvtableReturnZero_$1:
1606 // integer registers only; not used for fpret / stret / etc
1608 // xorl %edx, %edx (see ABI WARNING)
1612 LvtableTaggedPointer_$1:
1613 // extract isa (bits 1-2-3) from %a1, bit 0 is kept around for the heck of it
1618 movq $$0x1122334455667788, %r10 // vtable_prototype (DO NOT CHANGE)
1620 leaq __objc_tagged_isa_table(%rip), %r10
1622 LvtableTagTableEnd_$1:
1623 movq (%r10, %rax, 8), %r10 // load isa from table (see ABI WARNING
1624 movq 24(%r10), %rax // load vtable
1625 movq 8(%a2), %a2 // load _cmd
1627 jmpq * $0 (%rax) // load imp (DO NOT CHANGE)
1633 .section __TEXT,__objc_codegen,regular
1634 VTABLE 0x7fff, vtable_prototype
1638 .private_extern _vtable_prototype_size
1639 _vtable_prototype_size:
1640 .long LvtableEnd_vtable_prototype - _vtable_prototype
1642 .private_extern _vtable_prototype_index_offset
1643 _vtable_prototype_index_offset:
1644 .long LvtableIndex_vtable_prototype - _vtable_prototype
1646 .private_extern _vtable_prototype_index2_offset
1647 _vtable_prototype_index2_offset:
1648 .long LvtableIndex2_vtable_prototype - _vtable_prototype
1650 .private_extern _vtable_prototype_tagtable_offset
1651 _vtable_prototype_tagtable_offset:
1652 .long LvtableTagTable_vtable_prototype - _vtable_prototype
1654 .private_extern _vtable_prototype_tagtable_size
1655 _vtable_prototype_tagtable_size:
1656 .long LvtableTagTableEnd_vtable_prototype - LvtableTagTable_vtable_prototype
1658 /********************************************************************
1660 * id vtable_ignored(id self, message_ref *msg, ...)
1662 * Vtable trampoline for GC-ignored selectors. Immediately returns self.
1664 ********************************************************************/
1666 STATIC_ENTRY _vtable_ignored
1671 /********************************************************************
1673 * id objc_msgSend_vtable<n>(id self, message_ref *msg, ...)
1675 * Built-in expansions of vtable_prototype for the default vtable.
1677 ********************************************************************/
1682 .private_extern _defaultVtableTrampolineDescriptors
1683 _defaultVtableTrampolineDescriptors:
1684 // objc_trampoline_header
1685 .short 16 // headerSize
1686 .short 8 // descSize
1687 .long 16 // descCount
1690 // objc_trampoline_descriptor[16]
1691 .macro TDESC /* n */
1693 .long _objc_msgSend_vtable$0 - L_tdesc$0
1694 .long (1<<0) + (1<<2) // MESSAGE and VTABLE
1716 VTABLE 0*8, objc_msgSend_vtable0
1717 VTABLE 1*8, objc_msgSend_vtable1
1718 VTABLE 2*8, objc_msgSend_vtable2
1719 VTABLE 3*8, objc_msgSend_vtable3
1720 VTABLE 4*8, objc_msgSend_vtable4
1721 VTABLE 5*8, objc_msgSend_vtable5
1722 VTABLE 6*8, objc_msgSend_vtable6
1723 VTABLE 7*8, objc_msgSend_vtable7
1724 VTABLE 8*8, objc_msgSend_vtable8
1725 VTABLE 9*8, objc_msgSend_vtable9
1726 VTABLE 10*8, objc_msgSend_vtable10
1727 VTABLE 11*8, objc_msgSend_vtable11
1728 VTABLE 12*8, objc_msgSend_vtable12
1729 VTABLE 13*8, objc_msgSend_vtable13
1730 VTABLE 14*8, objc_msgSend_vtable14
1731 VTABLE 15*8, objc_msgSend_vtable15