]> git.saurik.com Git - apple/objc4.git/blob - runtime/Messengers.subproj/objc-msg-x86_64.s
objc4-493.9.tar.gz
[apple/objc4.git] / runtime / Messengers.subproj / objc-msg-x86_64.s
1 /*
2 * Copyright (c) 1999-2007 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #ifdef __x86_64__
25
26 /********************************************************************
27 ********************************************************************
28 **
29 ** objc-msg-x86_64.s - x86-64 code to support objc messaging.
30 **
31 ********************************************************************
32 ********************************************************************/
33
34 #define __OBJC2__ 1
35
36 /********************************************************************
37 * Data used by the ObjC runtime.
38 *
39 ********************************************************************/
40
41 .data
42 // Substitute receiver for messages sent to nil (usually also nil)
43 // id _objc_nilReceiver
44 .align 4
45 .private_extern __objc_nilReceiver
46 __objc_nilReceiver:
47 .quad 0
48
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.
52
53 .private_extern _objc_entryPoints
54 _objc_entryPoints:
55 .quad __cache_getImp
56 .quad __cache_getMethod
57 .quad _objc_msgSend
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
65 .quad 0
66
67 .private_extern _objc_exitPoints
68 _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
79 .quad 0
80
81
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
95
96
97 /********************************************************************
98 * Names for parameter registers.
99 ********************************************************************/
100
101 #define a1 rdi
102 #define a1d edi
103 #define a1b dil
104 #define a2 rsi
105 #define a2d esi
106 #define a2b sil
107 #define a3 rdx
108 #define a3d edx
109 #define a4 rcx
110 #define a4d ecx
111 #define a5 r8
112 #define a5d r8d
113 #define a6 r9
114 #define a6d r9d
115
116
117 /********************************************************************
118 * Names for relative labels
119 * DO NOT USE THESE LABELS ELSEWHERE
120 * Reserved labels: 5: 6: 7: 8: 9:
121 ********************************************************************/
122 #define LCacheMiss 5
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
137
138 /********************************************************************
139 * Macro parameters
140 ********************************************************************/
141
142 #define STRET -1
143 #define NORMAL 0
144 #define FPRET 1
145 #define FP2RET 2
146
147
148 /********************************************************************
149 *
150 * Structure definitions.
151 *
152 ********************************************************************/
153
154 // objc_super parameter to sendSuper
155 #define receiver 0
156 #define class 8
157
158 // Selected field offsets in class structure
159 // #define isa 0 USE GetIsa INSTEAD
160 #define cache 16
161
162 // Method descriptor
163 #define method_name 0
164 #define method_imp 16
165
166 // Cache header
167 #define mask 0
168 #define occupied 8
169 #define buckets 16
170
171 // typedef struct {
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
176 // } *marg_list;
177 #define FP_AREA 0
178 #define LINK_AREA (FP_AREA+8*16)
179 #define REG_AREA (LINK_AREA+4*8)
180 #define STACK_AREA (REG_AREA+6*8)
181
182
183 //////////////////////////////////////////////////////////////////////
184 //
185 // ENTRY functionName
186 //
187 // Assembly directives to begin an exported function.
188 //
189 // Takes: functionName - name of the exported function
190 //////////////////////////////////////////////////////////////////////
191
192 .macro ENTRY
193 .text
194 .globl $0
195 .align 6, 0x90
196 $0:
197 .endmacro
198
199 .macro STATIC_ENTRY
200 .text
201 .private_extern $0
202 .align 2, 0x90
203 $0:
204 .endmacro
205
206 //////////////////////////////////////////////////////////////////////
207 //
208 // END_ENTRY functionName
209 //
210 // Assembly directives to end an exported function. Just a placeholder,
211 // a close-parenthesis for ENTRY, until it is needed for something.
212 //
213 // Takes: functionName - name of the exported function
214 //////////////////////////////////////////////////////////////////////
215
216 .macro END_ENTRY
217 LExit$0:
218 .endmacro
219
220
221 /* DWARF support
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
225
226 The macros build appropriate FDEs and tie them to the CIE.
227 */
228
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
238 #define DW_rax 0
239 #define DW_rdx 1
240 #define DW_rcx 2
241 #define DW_rsi 4
242 #define DW_rdi 5
243 #define DW_rbp 6
244 #define DW_rsp 7
245 #define DW_r8 8
246 #define DW_r9 9
247 #define DW_r10 10
248 #define DW_ra 16
249 #define DW_xmm0 17
250 #define DW_xmm1 18
251 #define DW_xmm2 19
252 #define DW_xmm3 20
253 #define DW_xmm4 21
254 #define DW_xmm5 22
255 #define DW_xmm6 23
256 #define DW_xmm7 24
257 #define DW_a1 DW_rdi
258 #define DW_a2 DW_rsi
259 #define DW_a3 DW_rdx
260 #define DW_a4 DW_rcx
261 #define DW_a5 DW_r8
262 #define DW_a6 DW_r9
263
264 // CIE
265 // 8-byte data multiplier
266 // 1-byte insn multiplier
267 // PC-relative everything
268 // No prologue
269
270 .section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support
271 CIE:
272 .set L$set$0,LECIE1-LSCIE1
273 .long L$set$0 # Length of Common Information Entry
274 LSCIE1:
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
283 .byte 0x9b
284 .long ___objc_personality_v0+4@GOTPCREL
285 // FDE-encoding augmentation
286 .byte 0x10
287 // Prefix instructions
288 // CFA is %rsp+8
289 .byte DW_CFA_def_cfa
290 .byte DW_rsp
291 .byte 8
292 // RA is at 0(%rsp) aka -8(CFA)
293 .byte DW_CFA_offset | DW_ra
294 .byte 1
295
296 .align 3
297 LECIE1:
298
299
300 .macro EMIT_FDE
301
302 .section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support
303
304 // FDE header
305 .globl $0.eh
306 $0.eh:
307 LSFDE$0:
308 .set LLENFDE$0, LEFDE$0-LASFDE$0
309 .long LLENFDE$0 # FDE Length
310 LASFDE$0:
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
315
316 // DW_START: set by CIE
317
318 .if $2 == 1
319
320 // pushq %rbp
321 .byte DW_CFA_advance_loc4
322 .long LFLEN0$0+1
323 .byte DW_CFA_def_cfa_offset
324 .byte 16
325 .byte DW_CFA_offset | DW_rbp
326 .byte -16/-8
327 // movq %rsp, %rbp
328 .byte DW_CFA_advance_loc4
329 .long 3
330 .byte DW_CFA_def_cfa_register
331 .byte DW_rbp
332
333 .endif
334
335 .align 3
336 LEFDE$0:
337 .text
338
339 .endmacro
340
341
342 .macro DW_START
343 LF0$0:
344 .endmacro
345
346 .macro DW_FRAME
347 LF1$0:
348 .set LFLEN0$0, LF1$0-LF0$0
349 .endmacro
350
351 .macro DW_END
352 .set LLEN$0, .-LF0$0
353 EMIT_FDE $0, LLEN$0, 1
354 .endmacro
355
356 .macro DW_END2
357 .set LLEN$0, .-LF0$0
358 EMIT_FDE $0, LLEN$0, 2
359 .endmacro
360
361
362 /////////////////////////////////////////////////////////////////////
363 //
364 // SaveRegisters caller
365 //
366 // Pushes a stack frame and saves all registers that might contain
367 // parameter values.
368 //
369 // On entry: %0 = caller's symbol name for DWARF
370 // stack = ret
371 //
372 // On exit:
373 // %rsp is 16-byte aligned
374 //
375 /////////////////////////////////////////////////////////////////////
376
377 .macro SaveRegisters
378 DW_FRAME $0
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)
383 push %a1
384 movdqa %xmm2, -0x60(%rbp)
385 push %a2
386 movdqa %xmm3, -0x50(%rbp)
387 push %a3
388 movdqa %xmm4, -0x40(%rbp)
389 push %a4
390 movdqa %xmm5, -0x30(%rbp)
391 push %a5
392 movdqa %xmm6, -0x20(%rbp)
393 push %a6
394 movdqa %xmm7, -0x10(%rbp)
395 .endmacro
396
397 /////////////////////////////////////////////////////////////////////
398 //
399 // RestoreRegisters
400 //
401 // Pops a stack frame pushed by SaveRegisters
402 //
403 // On entry: $0 = caller's symbol name for DWARF
404 // %rbp unchanged since SaveRegisters
405 //
406 // On exit:
407 // stack = ret
408 //
409 /////////////////////////////////////////////////////////////////////
410
411 .macro RestoreRegisters
412 movdqa -0x80(%rbp), %xmm0
413 pop %a6
414 movdqa -0x70(%rbp), %xmm1
415 pop %a5
416 movdqa -0x60(%rbp), %xmm2
417 pop %a4
418 movdqa -0x50(%rbp), %xmm3
419 pop %a3
420 movdqa -0x40(%rbp), %xmm4
421 pop %a2
422 movdqa -0x30(%rbp), %xmm5
423 pop %a1
424 movdqa -0x20(%rbp), %xmm6
425 pop %rax
426 movdqa -0x10(%rbp), %xmm7
427 leave
428 .endmacro
429
430
431 /////////////////////////////////////////////////////////////////////
432 //
433 //
434 // CacheLookup return-type
435 //
436 // Locate the implementation for a selector in a class method cache.
437 //
438 // Takes:
439 // $0 = NORMAL, FPRET, FP2RET, STRET
440 // a2 or a3 (STRET) = selector
441 // %r11 = class whose cache is to be searched
442 //
443 // On exit: (found) method in %r11, stack unchanged, eq/ne set for forwarding
444 // (not found) jumps to LCacheMiss, %rax on stack
445 //
446 /////////////////////////////////////////////////////////////////////
447
448 .macro CacheLookup
449
450 push %rax
451 movq cache(%r11), %r10 // cache = class->cache
452 .if $0 != STRET
453 mov %a2d, %eax // index = sel
454 .else
455 mov %a3d, %eax // index = sel
456 .endif
457
458 // search the receiver's cache
459 // r11 = method (soon)
460 // eax = index
461 // r10 = cache
462 // a2 or a3 = sel
463 1:
464 andl mask(%r10), %eax // index &= mask
465 movq buckets(%r10, %rax, 8), %r11 // method = cache->buckets[index]
466 incl %eax // index++
467 testq %r11, %r11 // if (method == NULL)
468 je LCacheMiss_f // goto cacheMissLabel
469 .if $0 != STRET
470 cmpq method_name(%r11), %a2 // if (method_name != sel)
471 .else
472 cmpq method_name(%r11), %a3 // if (method_name != sel)
473 .endif
474 jne 1b // goto loop
475
476 // cache hit, r11 = method triplet
477 // restore saved registers
478 pop %rax
479
480 .if $0 != STRET
481 // eq (non-stret) flag already set above
482 .else
483 // set ne (stret) for forwarding; r11 != 0
484 test %r11, %r11
485 .endif
486
487 .endmacro
488
489
490 /////////////////////////////////////////////////////////////////////
491 //
492 // MethodTableLookup classRegister, selectorRegister, fn
493 //
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
498 //
499 // Stack: ret, rax (pushed by CacheLookup)
500 //
501 // On exit: pops registers pushed by CacheLookup
502 // imp in %r11
503 //
504 /////////////////////////////////////////////////////////////////////
505 .macro MethodTableLookup
506
507 pop %rax // saved by CacheLookup
508 SaveRegisters $2
509
510 // _class_lookupMethodAndLoadCache3(receiver, selector, class)
511
512 movq $0, %a1
513 movq $1, %a2
514 movq %r11, %a3
515 call __class_lookupMethodAndLoadCache3
516
517 // IMP is now in %rax
518 movq %rax, %r11
519
520 RestoreRegisters $2
521
522 .endmacro
523
524 /////////////////////////////////////////////////////////////////////
525 //
526 // GetIsa return-type
527 // GetIsaFast return-type
528 // GetIsaSupport return-type
529 //
530 // Sets r11 = obj->isa. Consults the tagged isa table if necessary.
531 //
532 // Takes: $0 = NORMAL or FPRET or FP2RET or STRET
533 // a1 or a2 (STRET) = receiver
534 //
535 // On exit: r11 = receiver->isa
536 // r10 is clobbered
537 //
538 /////////////////////////////////////////////////////////////////////
539
540 .macro GetIsa
541
542 .if $0 != STRET
543 testb $$1, %a1b
544 jnz 1f
545 movq (%a1), %r11
546 jmp 2f
547 1: movl %a1d, %r10d
548 .else
549 testb $$1, %a2b
550 jnz 1f
551 movq (%a2), %r11
552 jmp 2f
553 1: movl %a2d, %r10d
554 .endif
555 andl $$0xF, %r10d
556 leaq __objc_tagged_isa_table(%rip), %r11
557 movq (%r11, %r10, 8), %r11 // read isa from table
558 2:
559 .endmacro
560
561 .macro GetIsaFast
562 .if $0 != STRET
563 testb $$1, %a1b
564 .byte 0x2e // harmless branch hint prefix to align IFETCH blocks
565 jnz LGetIsaSlow_f
566 movq (%a1), %r11
567 .else
568 testb $$1, %a2b
569 .byte 0x2e // harmless branch hint prefix to align IFETCH blocks
570 jnz LGetIsaSlow_f
571 movq (%a2), %r11
572 .endif
573 LGetIsaDone:
574 .endmacro
575
576 .macro GetIsaSupport
577 LGetIsaSlow:
578 leaq __objc_tagged_isa_table(%rip), %r11
579 .if $0 != STRET
580 movl %a1d, %r10d
581 .else
582 movl %a2d, %r10d
583 .endif
584 andl $$0xF, %r10d
585 movq (%r11, %r10, 8), %r11 // read isa from table
586 jmp LGetIsaDone_b
587 .endmacro
588
589 /////////////////////////////////////////////////////////////////////
590 //
591 // NilTest return-type
592 //
593 // Takes: $0 = NORMAL or FPRET or FP2RET or STRET
594 // %a1 or %a2 (STRET) = receiver
595 //
596 // On exit: Loads non-nil receiver in %a1 or %a2 (STRET), or returns zero.
597 //
598 // NilTestSupport return-type
599 //
600 // Takes: $0 = NORMAL or FPRET or FP2RET or STRET
601 // %a1 or %a2 (STRET) = receiver
602 //
603 // On exit: Loads non-nil receiver in %a1 or %a2 (STRET), or returns zero.
604 //
605 /////////////////////////////////////////////////////////////////////
606
607 .macro NilTest
608 .if $0 != STRET
609 testq %a1, %a1
610 .else
611 testq %a2, %a2
612 .endif
613 jz LNilTestSlow_f
614 LNilTestDone:
615 .endmacro
616
617 .macro NilTestSupport
618 .align 3
619 LNilTestSlow:
620 .if $0 != STRET
621 movq __objc_nilReceiver(%rip), %a1
622 testq %a1, %a1 // if (receiver != nil)
623 .else
624 movq __objc_nilReceiver(%rip), %a2
625 testq %a2, %a2 // if (receiver != nil)
626 .endif
627 jne LNilTestDone_b // send to new receiver
628
629 .if $0 == FPRET
630 fldz
631 .elseif $0 == FP2RET
632 fldz
633 fldz
634 .endif
635 .if $0 != STRET
636 xorl %eax, %eax
637 xorl %edx, %edx
638 xorps %xmm0, %xmm0
639 xorps %xmm1, %xmm1
640 .endif
641 ret
642 .endmacro
643
644
645 /********************************************************************
646 * Method _cache_getMethod(Class cls, SEL sel, IMP msgForward_internal_imp)
647 *
648 * On entry: a1 = class whose cache is to be searched
649 * a2 = selector to search for
650 * a3 = _objc_msgForward_internal IMP
651 *
652 * If found, returns method triplet pointer.
653 * If not found, returns NULL.
654 *
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.
659 *
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 ********************************************************************/
663
664 STATIC_ENTRY __cache_getMethod
665 DW_START __cache_getMethod
666
667 // do lookup
668 movq %a1, %r11 // move class to r11 for CacheLookup
669 CacheLookup NORMAL
670
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
675 ret
676 1: movl $1, %eax
677 ret
678
679 LCacheMiss:
680 // cache miss, return nil
681 pop %rax // pushed by CacheLookup
682 xorl %eax, %eax
683 ret
684
685 LGetMethodExit:
686 DW_END2 __cache_getMethod
687 END_ENTRY __cache_getMethod
688
689
690 /********************************************************************
691 * IMP _cache_getImp(Class cls, SEL sel)
692 *
693 * On entry: a1 = class whose cache is to be searched
694 * a2 = selector to search for
695 *
696 * If found, returns method implementation.
697 * If not found, returns NULL.
698 ********************************************************************/
699
700 STATIC_ENTRY __cache_getImp
701 DW_START __cache_getImp
702
703 // do lookup
704 movq %a1, %r11 // move class to r11 for CacheLookup
705 CacheLookup NORMAL
706
707 // cache hit, method triplet in %r11
708 movq method_imp(%r11), %rax // return method imp address
709 ret
710
711 LCacheMiss:
712 // cache miss, return nil
713 pop %rax // pushed by CacheLookup
714 xorl %eax, %eax
715 ret
716
717 LGetImpExit:
718 DW_END2 __cache_getImp
719 END_ENTRY __cache_getImp
720
721
722 /********************************************************************
723 *
724 * id objc_msgSend(id self, SEL _cmd,...);
725 *
726 ********************************************************************/
727
728 .data
729 .align 3
730 .private_extern __objc_tagged_isa_table
731 __objc_tagged_isa_table:
732 .fill 16, 8, 0
733
734 ENTRY _objc_msgSend
735 DW_START _objc_msgSend
736
737 NilTest NORMAL
738
739 GetIsaFast NORMAL // r11 = self->isa
740 CacheLookup NORMAL // r11 = method, eq set (nonstret fwd)
741 jmp *method_imp(%r11) // goto *imp
742
743 NilTestSupport NORMAL
744
745 GetIsaSupport NORMAL
746
747 // cache miss: go search the method lists
748 LCacheMiss:
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
753
754 DW_END _objc_msgSend
755 END_ENTRY _objc_msgSend
756
757 #if __OBJC2__
758 ENTRY _objc_msgSend_fixup
759 DW_START _objc_msgSend_fixup
760
761 NilTest NORMAL
762
763 SaveRegisters _objc_msgSend_fixup
764
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
770
771 // a1 = receiver
772 // a2 = address of message ref
773 movq %a2, %a3
774 xorl %a2d, %a2d
775 // __objc_fixupMessageRef(receiver, 0, ref)
776 call __objc_fixupMessageRef
777 movq %rax, %r11
778
779 RestoreRegisters _objc_msgSend_fixup
780
781 // imp is in r11
782 // Load _cmd from the message_ref
783 movq 8(%a2), %a2
784 cmp %r11, %r11 // set nonstret (eq) for forwarding
785 jmp *%r11
786
787 NilTestSupport NORMAL
788
789 DW_END _objc_msgSend_fixup
790 END_ENTRY _objc_msgSend_fixup
791
792
793 STATIC_ENTRY _objc_msgSend_fixedup
794 // Load _cmd from the message_ref
795 movq 8(%a2), %a2
796 jmp _objc_msgSend
797 END_ENTRY _objc_msgSend_fixedup
798 #endif
799
800
801 /********************************************************************
802 *
803 * id objc_msgSendSuper(struct objc_super *super, SEL _cmd,...);
804 *
805 * struct objc_super {
806 * id receiver;
807 * Class class;
808 * };
809 ********************************************************************/
810
811 ENTRY _objc_msgSendSuper
812 DW_START _objc_msgSendSuper
813
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
819
820 // cache miss: go search the method lists
821 LCacheMiss:
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
828
829 DW_END _objc_msgSendSuper
830 END_ENTRY _objc_msgSendSuper
831
832
833 /********************************************************************
834 * id objc_msgSendSuper2
835 ********************************************************************/
836
837 #if __OBJC2__
838 ENTRY _objc_msgSendSuper2_fixup
839 DW_START _objc_msgSendSuper2_fixup
840
841 SaveRegisters _objc_msgSendSuper2_fixup
842 // a1 = address of objc_super2
843 // a2 = address of message ref
844 movq %a2, %a3
845 movq %a1, %a2
846 movq receiver(%a1), %a1
847 // __objc_fixupMessageRef(receiver, objc_super, ref)
848 call __objc_fixupMessageRef
849 movq %rax, %r11
850 RestoreRegisters _objc_msgSendSuper2_fixup
851
852 // imp is in r11
853 // Load _cmd from the message_ref
854 movq 8(%a2), %a2
855 // Load receiver from objc_super2
856 movq receiver(%a1), %a1
857 cmp %r11, %r11 // set nonstret (eq) for forwarding
858 jmp *%r11
859
860 DW_END _objc_msgSendSuper2_fixup
861 END_ENTRY _objc_msgSendSuper2_fixup
862
863
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
868
869
870 ENTRY _objc_msgSendSuper2
871 DW_START _objc_msgSendSuper2
872 // objc_super->class is superclass of class to search
873
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
880
881 // cache miss: go search the method lists
882 LCacheMiss:
883 movq receiver(%a1), %r10
884 movq class(%a1), %r11
885 movq 8(%r11), %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
890
891 DW_END _objc_msgSendSuper2
892 END_ENTRY _objc_msgSendSuper2
893 #endif
894
895
896 /********************************************************************
897 *
898 * double objc_msgSend_fpret(id self, SEL _cmd,...);
899 * Used for `long double` return only. `float` and `double` use objc_msgSend.
900 *
901 ********************************************************************/
902
903 ENTRY _objc_msgSend_fpret
904 DW_START _objc_msgSend_fpret
905
906 NilTest FPRET
907
908 GetIsaFast FPRET // r11 = self->isa
909 CacheLookup FPRET // r11 = method, eq set (nonstret fwd)
910 jmp *method_imp(%r11) // goto *imp
911
912 NilTestSupport FPRET
913
914 GetIsaSupport FPRET
915
916 // cache miss: go search the method lists
917 LCacheMiss:
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
922
923 DW_END _objc_msgSend_fpret
924 END_ENTRY _objc_msgSend_fpret
925
926 #if __OBJC2__
927 ENTRY _objc_msgSend_fpret_fixup
928 DW_START _objc_msgSend_fpret_fixup
929
930 NilTest FPRET
931
932 SaveRegisters _objc_msgSend_fpret_fixup
933
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
939
940 // a1 = receiver
941 // a2 = address of message ref
942 movq %a2, %a3
943 xorl %a2d, %a2d
944 // __objc_fixupMessageRef(receiver, 0, ref)
945 call __objc_fixupMessageRef
946 movq %rax, %r11
947
948 RestoreRegisters _objc_msgSend_fpret_fixup
949
950 // imp is in r11
951 // Load _cmd from the message_ref
952 movq 8(%a2), %a2
953 cmp %r11, %r11 // set nonstret (eq) for forwarding
954 jmp *%r11
955
956 NilTestSupport FPRET
957
958 DW_END _objc_msgSend_fpret_fixup
959 END_ENTRY _objc_msgSend_fpret_fixup
960
961
962 STATIC_ENTRY _objc_msgSend_fpret_fixedup
963 // Load _cmd from the message_ref
964 movq 8(%a2), %a2
965 jmp _objc_msgSend_fpret
966 END_ENTRY _objc_msgSend_fpret_fixedup
967 #endif
968
969
970 /********************************************************************
971 *
972 * double objc_msgSend_fp2ret(id self, SEL _cmd,...);
973 * Used for `complex long double` return only.
974 *
975 ********************************************************************/
976
977 ENTRY _objc_msgSend_fp2ret
978 DW_START _objc_msgSend_fp2ret
979
980 NilTest FP2RET
981
982 GetIsaFast FP2RET // r11 = self->isa
983 CacheLookup FP2RET // r11 = method, eq set (nonstret fwd)
984 jmp *method_imp(%r11) // goto *imp
985
986 NilTestSupport FP2RET
987
988 GetIsaSupport FP2RET
989
990 // cache miss: go search the method lists
991 LCacheMiss:
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
996
997 DW_END _objc_msgSend_fp2ret
998 END_ENTRY _objc_msgSend_fp2ret
999
1000 #if __OBJC2__
1001 ENTRY _objc_msgSend_fp2ret_fixup
1002 DW_START _objc_msgSend_fp2ret_fixup
1003
1004 NilTest FP2RET
1005
1006 SaveRegisters _objc_msgSend_fp2ret_fixup
1007
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
1013
1014 // a1 = receiver
1015 // a2 = address of message ref
1016 movq %a2, %a3
1017 xorl %a2d, %a2d
1018 // __objc_fixupMessageRef(receiver, 0, ref)
1019 call __objc_fixupMessageRef
1020 movq %rax, %r11
1021
1022 RestoreRegisters _objc_msgSend_fp2ret_fixup
1023
1024 // imp is in r11
1025 // Load _cmd from the message_ref
1026 movq 8(%a2), %a2
1027 cmp %r11, %r11 // set nonstret (eq) for forwarding
1028 jmp *%r11
1029
1030 NilTestSupport FP2RET
1031
1032 DW_END _objc_msgSend_fp2ret_fixup
1033 END_ENTRY _objc_msgSend_fp2ret_fixup
1034
1035
1036 STATIC_ENTRY _objc_msgSend_fp2ret_fixedup
1037 // Load _cmd from the message_ref
1038 movq 8(%a2), %a2
1039 jmp _objc_msgSend_fp2ret
1040 END_ENTRY _objc_msgSend_fp2ret_fixedup
1041 #endif
1042
1043
1044 /********************************************************************
1045 *
1046 * void objc_msgSend_stret(void *st_addr, id self, SEL _cmd, ...);
1047 *
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.
1051 *
1052 * On entry: %a1 is the address where the structure is returned,
1053 * %a2 is the message receiver,
1054 * %a3 is the selector
1055 ********************************************************************/
1056
1057 ENTRY _objc_msgSend_stret
1058 DW_START _objc_msgSend_stret
1059
1060 NilTest STRET
1061
1062 GetIsaFast STRET // r11 = self->isa
1063 CacheLookup STRET // r11 = method, ne set (stret fwd)
1064 jmp *method_imp(%r11) // goto *imp
1065
1066 NilTestSupport STRET
1067
1068 GetIsaSupport STRET
1069
1070 // cache miss: go search the method lists
1071 LCacheMiss:
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
1076
1077 DW_END _objc_msgSend_stret
1078 END_ENTRY _objc_msgSend_stret
1079
1080 #if __OBJC2__
1081 ENTRY _objc_msgSend_stret_fixup
1082 DW_START _objc_msgSend_stret_fixup
1083
1084 NilTest STRET
1085
1086 SaveRegisters _objc_msgSend_stret_fixup
1087
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
1093
1094 // a2 = receiver
1095 // a3 = address of message ref
1096 movq %a2, %a1
1097 xorl %a2d, %a2d
1098 // __objc_fixupMessageRef(receiver, 0, ref)
1099 call __objc_fixupMessageRef
1100 movq %rax, %r11
1101
1102 RestoreRegisters _objc_msgSend_stret_fixup
1103
1104 // imp is in r11
1105 // Load _cmd from the message_ref
1106 movq 8(%a3), %a3
1107 test %r11, %r11 // set stret (ne) for forward; r11!=0
1108 jmp *%r11 // goto *imp
1109
1110 NilTestSupport STRET
1111
1112 DW_END _objc_msgSend_stret_fixup
1113 END_ENTRY _objc_msgSend_stret_fixup
1114
1115
1116 STATIC_ENTRY _objc_msgSend_stret_fixedup
1117 // Load _cmd from the message_ref
1118 movq 8(%a3), %a3
1119 jmp _objc_msgSend_stret
1120 END_ENTRY _objc_msgSend_stret_fixedup
1121 #endif
1122
1123
1124 /********************************************************************
1125 *
1126 * void objc_msgSendSuper_stret(void *st_addr, struct objc_super *super, SEL _cmd, ...);
1127 *
1128 * struct objc_super {
1129 * id receiver;
1130 * Class class;
1131 * };
1132 *
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.
1136 *
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
1140 *
1141 ********************************************************************/
1142
1143 ENTRY _objc_msgSendSuper_stret
1144 DW_START _objc_msgSendSuper_stret
1145
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
1151
1152 // cache miss: go search the method lists
1153 LCacheMiss:
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
1160
1161 DW_END _objc_msgSendSuper_stret
1162 END_ENTRY _objc_msgSendSuper_stret
1163
1164
1165 /********************************************************************
1166 * id objc_msgSendSuper2_stret
1167 ********************************************************************/
1168
1169 #if __OBJC2__
1170 ENTRY _objc_msgSendSuper2_stret_fixup
1171 DW_START _objc_msgSendSuper2_stret_fixup
1172
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
1179 movq %rax, %r11
1180 RestoreRegisters _objc_msgSendSuper2_stret_fixup
1181
1182 // imp is in r11
1183 // Load _cmd from the message_ref
1184 movq 8(%a3), %a3
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
1189
1190 DW_END _objc_msgSendSuper2_stret_fixup
1191 END_ENTRY _objc_msgSendSuper2_stret_fixup
1192
1193
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
1198
1199
1200 ENTRY _objc_msgSendSuper2_stret
1201 DW_START _objc_msgSendSuper2_stret
1202
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
1209
1210 // cache miss: go search the method lists
1211 LCacheMiss:
1212 movq receiver(%a2), %r10
1213 movq class(%a2), %r11
1214 movq 8(%r11), %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
1219
1220 DW_END _objc_msgSendSuper2_stret
1221 END_ENTRY _objc_msgSendSuper2_stret
1222 #endif
1223
1224
1225 /********************************************************************
1226 *
1227 * id _objc_msgForward(id self, SEL _cmd,...);
1228 *
1229 ********************************************************************/
1230
1231 // _FwdSel is @selector(forward::), set up in map_images().
1232 // ALWAYS dereference _FwdSel to get to "forward::" !!
1233 .data
1234 .align 3
1235 .private_extern _FwdSel
1236 _FwdSel: .quad 0
1237
1238 .cstring
1239 .align 3
1240 LUnkSelStr: .ascii "Does not recognize selector %s\0"
1241
1242 .data
1243 .align 3
1244 .private_extern __objc_forward_handler
1245 __objc_forward_handler: .quad 0
1246
1247 .data
1248 .align 3
1249 .private_extern __objc_forward_stret_handler
1250 __objc_forward_stret_handler: .quad 0
1251
1252
1253 STATIC_ENTRY __objc_msgForward_internal
1254 // Method cache version
1255
1256 // THIS IS NOT A CALLABLE C FUNCTION
1257 // Out-of-band condition register is NE for stret, EQ otherwise.
1258
1259 jne __objc_msgForward_stret
1260 jmp __objc_msgForward
1261
1262 END_ENTRY __objc_msgForward_internal
1263
1264
1265 ENTRY __objc_msgForward
1266 // Non-stret version
1267
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
1273 1:
1274 // No user handler
1275
1276 // Die if forwarding "forward::"
1277 cmpq %a2, _FwdSel(%rip)
1278 je LMsgForwardError
1279
1280 // Record current return address. It will be copied elsewhere in
1281 // the marg_list because this location is needed for register args
1282 movq (%rsp), %r11
1283
1284 // Push stack frame
1285 // Space for: fpArgs + regArgs + linkage - ret (already on stack)
1286 subq $ 8*16 + 6*8 + (4-1)*8, %rsp
1287
1288 // Save return address in linkage area.
1289 movq %r11, 16+LINK_AREA(%rsp)
1290
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)
1298
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
1303
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)
1313
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
1319
1320 call _objc_msgSend
1321
1322 // Retrieve return address from linkage area
1323 movq 16+LINK_AREA(%rsp), %r11
1324 // Pop stack frame
1325 addq $ 8*16 + 6*8 + (4-1)*8, %rsp
1326 // Put return address back
1327 movq %r11, (%rsp)
1328 ret
1329
1330 LMsgForwardError:
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
1336
1337 END_ENTRY __objc_msgForward
1338
1339
1340 ENTRY __objc_msgForward_stret
1341 // Struct-return version
1342
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
1348 1:
1349 // No user handler
1350 // Die if forwarding "forward::"
1351 cmpq %a3, _FwdSel(%rip)
1352 je LMsgForwardStretError
1353
1354 // Record current return address. It will be copied elsewhere in
1355 // the marg_list because this location is needed for register args
1356 movq (%rsp), %r11
1357
1358 // Push stack frame
1359 // Space for: fpArgs + regArgs + linkage - ret (already on stack)
1360 subq $ 8*16 + 6*8 + (4-1)*8, %rsp
1361
1362 // Save return address in linkage area.
1363 movq %r11, 16+LINK_AREA(%rsp)
1364
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)
1372
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
1377
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)
1387
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
1393
1394 call _objc_msgSend // forward:: is NOT struct-return
1395
1396 // Retrieve return address from linkage area
1397 movq 16+LINK_AREA(%rsp), %r11
1398 // Pop stack frame
1399 addq $ 8*16 + 6*8 + (4-1)*8, %rsp
1400 // Put return address back
1401 movq %r11, (%rsp)
1402 ret
1403
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
1410
1411 END_ENTRY __objc_msgForward_stret
1412
1413
1414 ENTRY _objc_msgSend_debug
1415 jmp _objc_msgSend
1416 END_ENTRY _objc_msgSend_debug
1417
1418 ENTRY _objc_msgSendSuper2_debug
1419 jmp _objc_msgSendSuper2
1420 END_ENTRY _objc_msgSendSuper2_debug
1421
1422 ENTRY _objc_msgSend_stret_debug
1423 jmp _objc_msgSend_stret
1424 END_ENTRY _objc_msgSend_stret_debug
1425
1426 ENTRY _objc_msgSendSuper2_stret_debug
1427 jmp _objc_msgSendSuper2_stret
1428 END_ENTRY _objc_msgSendSuper2_stret_debug
1429
1430 ENTRY _objc_msgSend_fpret_debug
1431 jmp _objc_msgSend_fpret
1432 END_ENTRY _objc_msgSend_fpret_debug
1433
1434 ENTRY _objc_msgSend_fp2ret_debug
1435 jmp _objc_msgSend_fp2ret
1436 END_ENTRY _objc_msgSend_fp2ret_debug
1437
1438
1439 ENTRY _objc_msgSend_noarg
1440 jmp _objc_msgSend
1441 END_ENTRY _objc_msgSend_noarg
1442
1443
1444 ENTRY _method_invoke
1445
1446 movq method_imp(%a2), %r11
1447 movq method_name(%a2), %a2
1448 jmp *%r11
1449
1450 END_ENTRY _method_invoke
1451
1452
1453 ENTRY _method_invoke_stret
1454
1455 movq method_imp(%a3), %r11
1456 movq method_name(%a3), %a3
1457 jmp *%r11
1458
1459 END_ENTRY _method_invoke_stret
1460
1461
1462 STATIC_ENTRY __objc_ignored_method
1463
1464 movq %a1, %rax
1465 ret
1466
1467 END_ENTRY __objc_ignored_method
1468
1469
1470 /********************************************************************
1471 *
1472 * id vtable_prototype(id self, message_ref *msg, ...)
1473 *
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.
1479 *
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.
1483 *
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
1490 *
1491 ********************************************************************/
1492
1493 .macro VTABLE /* byte-offset, name */
1494
1495 .align 6
1496 .private_extern _$1
1497 _$1:
1498 test %a1, %a1
1499 je LvtableReturnZero_$1 // nil check
1500 testl $$1, %a1d
1501 jne LvtableTaggedPointer_$1 // tag check
1502
1503 movq (%a1), %rax // load isa (see ABI WARNING)
1504 movq 24(%rax), %rax // load vtable
1505 movq 8(%a2), %a2 // load _cmd
1506 LvtableIndex_$1:
1507 jmpq * $0 (%rax) // load imp (DO NOT CHANGE)
1508
1509 LvtableReturnZero_$1:
1510 // integer registers only; not used for fpret / stret / etc
1511 xorl %eax, %eax
1512 // xorl %edx, %edx (see ABI WARNING)
1513 ret
1514
1515 nop
1516 LvtableTaggedPointer_$1:
1517 // extract isa (bits 1-2-3) from %a1, bit 0 is kept around for the heck of it
1518 movl %a1d, %eax
1519 andl $$0xF, %eax
1520 LvtableTagTable_$1:
1521 .if $0 == 0x7fff
1522 movq $$0x1122334455667788, %r10 // vtable_prototype (DO NOT CHANGE)
1523 .else
1524 leaq __objc_tagged_isa_table(%rip), %r10
1525 .endif
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
1530 LvtableIndex2_$1:
1531 jmpq * $0 (%rax) // load imp (DO NOT CHANGE)
1532
1533 LvtableEnd_$1:
1534
1535 .endmacro
1536
1537 .section __TEXT,__objc_codegen,regular
1538 VTABLE 0x7fff, vtable_prototype
1539
1540 .data
1541 .align 2
1542 .private_extern _vtable_prototype_size
1543 _vtable_prototype_size:
1544 .long LvtableEnd_vtable_prototype - _vtable_prototype
1545
1546 .private_extern _vtable_prototype_index_offset
1547 _vtable_prototype_index_offset:
1548 .long LvtableIndex_vtable_prototype - _vtable_prototype
1549
1550 .private_extern _vtable_prototype_index2_offset
1551 _vtable_prototype_index2_offset:
1552 .long LvtableIndex2_vtable_prototype - _vtable_prototype
1553
1554 .private_extern _vtable_prototype_tagtable_offset
1555 _vtable_prototype_tagtable_offset:
1556 .long LvtableTagTable_vtable_prototype - _vtable_prototype
1557
1558 .private_extern _vtable_prototype_tagtable_size
1559 _vtable_prototype_tagtable_size:
1560 .long LvtableTagTableEnd_vtable_prototype - LvtableTagTable_vtable_prototype
1561
1562 /********************************************************************
1563 *
1564 * id vtable_ignored(id self, message_ref *msg, ...)
1565 *
1566 * Vtable trampoline for GC-ignored selectors. Immediately returns self.
1567 *
1568 ********************************************************************/
1569
1570 STATIC_ENTRY _vtable_ignored
1571 movq %a1, %rax
1572 ret
1573
1574
1575 /********************************************************************
1576 *
1577 * id objc_msgSend_vtable<n>(id self, message_ref *msg, ...)
1578 *
1579 * Built-in expansions of vtable_prototype for the default vtable.
1580 *
1581 ********************************************************************/
1582
1583 .text
1584
1585 .align 4
1586 .private_extern _defaultVtableTrampolineDescriptors
1587 _defaultVtableTrampolineDescriptors:
1588 // objc_trampoline_header
1589 .short 16 // headerSize
1590 .short 8 // descSize
1591 .long 16 // descCount
1592 .quad 0 // next
1593
1594 // objc_trampoline_descriptor[16]
1595 .macro TDESC /* n */
1596 L_tdesc$0:
1597 .long _objc_msgSend_vtable$0 - L_tdesc$0
1598 .long (1<<0) + (1<<2) // MESSAGE and VTABLE
1599 .endmacro
1600
1601 TDESC 0
1602 TDESC 1
1603 TDESC 2
1604 TDESC 3
1605 TDESC 4
1606 TDESC 5
1607 TDESC 6
1608 TDESC 7
1609 TDESC 8
1610 TDESC 9
1611 TDESC 10
1612 TDESC 11
1613 TDESC 12
1614 TDESC 13
1615 TDESC 14
1616 TDESC 15
1617
1618 // trampoline code
1619 .align 4
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
1636
1637 #endif