]> git.saurik.com Git - apple/objc4.git/blob - runtime/Messengers.subproj/objc-msg-x86_64.s
objc4-532.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 1*-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 L_dw_start_$0-. # FDE address start
313 .quad L_dw_len_$0 # FDE address range
314 .byte 0x0 # uleb128 0x0; Augmentation size
315
316 // DW_START: set by CIE
317
318 .if $1 == 1
319 // CacheLookup
320
321 // push
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
325 .byte 16
326
327 // pop
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
331 .byte 8
332
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
337 .byte 16
338
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
343 .byte 8
344
345 .endif
346
347 .if $2 == 1
348 // Save/RestoreRegisters or MethodTableLookup
349
350 // enter
351 .byte DW_CFA_advance_loc4
352 .if $1 == 1
353 .long L_dw_enter_$0 - L_dw_miss_pop_$0
354 .else
355 .long L_dw_enter_$0 - L_dw_start_$0
356 .endif
357 .byte DW_CFA_def_cfa_offset
358 .byte 16
359 .byte DW_CFA_offset | DW_rbp // rbp => 2*-8(CFA)
360 .byte 2
361 .byte DW_CFA_def_cfa_register // CFA = rbp+16 (offset unchanged)
362 .byte DW_rbp
363
364 // leave
365 .byte DW_CFA_advance_loc4
366 .long L_dw_leave_$0 - L_dw_enter_$0
367
368 .byte DW_CFA_same_value // rbp = original value
369 .byte DW_rbp
370 .byte DW_CFA_def_cfa // CFA = rsp+8
371 .byte DW_rsp
372 .byte 8
373
374 .endif
375
376 .align 3
377 LEFDE$0:
378 .text
379
380 .endmacro
381
382
383 // Start of function
384 .macro DW_START
385 L_dw_start_$0:
386 .endmacro
387
388 // After `push` in CacheLookup
389 .macro DW_PUSH
390 L_dw_push_$0:
391 .endmacro
392
393 // After `pop` in CacheLookup
394 .macro DW_POP
395 L_dw_pop_$0:
396 .endmacro
397
398 // After cache miss label
399 .macro DW_MISS
400 L_dw_miss_$0:
401 .endmacro
402
403 // After pop in MethodTableLookup
404 .macro DW_MISS_POP
405 L_dw_miss_pop_$0:
406 .endmacro
407
408 // After `enter` in SaveRegisters
409 .macro DW_ENTER
410 L_dw_enter_$0:
411 .endmacro
412
413 // After `leave` in RestoreRegisters
414 .macro DW_LEAVE
415 L_dw_leave_$0:
416 .endmacro
417
418 // End of function
419 // $1 == 1 iff you called CacheLookup
420 // $2 == 1 iff you called MethodTableLookup or Save/RestoreRegsters
421 .macro DW_END
422 .set L_dw_len_$0, . - L_dw_start_$0
423 EMIT_FDE $0, $1, $2
424 .endmacro
425
426
427 /////////////////////////////////////////////////////////////////////
428 //
429 // SaveRegisters caller
430 //
431 // Pushes a stack frame and saves all registers that might contain
432 // parameter values.
433 //
434 // On entry: %0 = caller's symbol name for DWARF
435 // stack = ret
436 //
437 // On exit:
438 // %rsp is 16-byte aligned
439 //
440 /////////////////////////////////////////////////////////////////////
441
442 .macro SaveRegisters
443 // These instructions must match the DWARF data in EMIT_FDE.
444
445 enter $$0x80+8, $$0 // +8 for alignment
446 DW_ENTER $0
447
448 movdqa %xmm0, -0x80(%rbp)
449 push %rax // might be xmm parameter count
450 movdqa %xmm1, -0x70(%rbp)
451 push %a1
452 movdqa %xmm2, -0x60(%rbp)
453 push %a2
454 movdqa %xmm3, -0x50(%rbp)
455 push %a3
456 movdqa %xmm4, -0x40(%rbp)
457 push %a4
458 movdqa %xmm5, -0x30(%rbp)
459 push %a5
460 movdqa %xmm6, -0x20(%rbp)
461 push %a6
462 movdqa %xmm7, -0x10(%rbp)
463
464 // These instructions must match the DWARF data in EMIT_FDE.
465 .endmacro
466
467 /////////////////////////////////////////////////////////////////////
468 //
469 // RestoreRegisters
470 //
471 // Pops a stack frame pushed by SaveRegisters
472 //
473 // On entry: $0 = caller's symbol name for DWARF
474 // %rbp unchanged since SaveRegisters
475 //
476 // On exit:
477 // stack = ret
478 //
479 /////////////////////////////////////////////////////////////////////
480
481 .macro RestoreRegisters
482 // These instructions must match the DWARF data in EMIT_FDE.
483
484 movdqa -0x80(%rbp), %xmm0
485 pop %a6
486 movdqa -0x70(%rbp), %xmm1
487 pop %a5
488 movdqa -0x60(%rbp), %xmm2
489 pop %a4
490 movdqa -0x50(%rbp), %xmm3
491 pop %a3
492 movdqa -0x40(%rbp), %xmm4
493 pop %a2
494 movdqa -0x30(%rbp), %xmm5
495 pop %a1
496 movdqa -0x20(%rbp), %xmm6
497 pop %rax
498 movdqa -0x10(%rbp), %xmm7
499
500 leave
501 DW_LEAVE $0
502
503 // These instructions must match the DWARF data in EMIT_FDE.
504 .endmacro
505
506
507 /////////////////////////////////////////////////////////////////////
508 //
509 //
510 // CacheLookup return-type, caller
511 //
512 // Locate the implementation for a selector in a class method cache.
513 //
514 // Takes:
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
519 //
520 // On exit: (found) method in %r11, stack unchanged, eq/ne set for forwarding
521 // (not found) jumps to LCacheMiss, %rax on stack
522 //
523 /////////////////////////////////////////////////////////////////////
524
525 .macro CacheLookup
526
527 push %rax
528 DW_PUSH $1
529
530 movq cache(%r11), %r10 // cache = class->cache
531 .if $0 != STRET
532 mov %a2d, %eax // index = sel
533 .else
534 mov %a3d, %eax // index = sel
535 .endif
536
537 // search the receiver's cache
538 // r11 = method (soon)
539 // eax = index
540 // r10 = cache
541 // a2 or a3 = sel
542 1:
543 andl mask(%r10), %eax // index &= mask
544 movq buckets(%r10, %rax, 8), %r11 // method = cache->buckets[index]
545 incl %eax // index++
546 testq %r11, %r11 // if (method == NULL)
547 je LCacheMiss_f // goto cacheMissLabel
548 .if $0 != STRET
549 cmpq method_name(%r11), %a2 // if (method_name != sel)
550 .else
551 cmpq method_name(%r11), %a3 // if (method_name != sel)
552 .endif
553 jne 1b // goto loop
554
555 // cache hit, r11 = method triplet
556 // restore saved registers
557 pop %rax
558 DW_POP $1
559
560 .if $0 != STRET
561 // eq (non-stret) flag already set above
562 .else
563 // set ne (stret) for forwarding; r11 != 0
564 test %r11, %r11
565 .endif
566
567 .endmacro
568
569
570 /////////////////////////////////////////////////////////////////////
571 //
572 // MethodTableLookup classRegister, selectorRegister, caller
573 //
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
578 //
579 // Stack: ret, rax (pushed by CacheLookup)
580 //
581 // On exit: pops registers pushed by CacheLookup
582 // imp in %r11
583 //
584 /////////////////////////////////////////////////////////////////////
585 .macro MethodTableLookup
586
587 pop %rax // saved by CacheLookup
588 DW_MISS_POP $2
589
590 SaveRegisters $2
591
592 // _class_lookupMethodAndLoadCache3(receiver, selector, class)
593
594 movq $0, %a1
595 movq $1, %a2
596 movq %r11, %a3
597 call __class_lookupMethodAndLoadCache3
598
599 // IMP is now in %rax
600 movq %rax, %r11
601
602 RestoreRegisters $2
603
604 .endmacro
605
606 /////////////////////////////////////////////////////////////////////
607 //
608 // GetIsa return-type
609 // GetIsaFast return-type
610 // GetIsaSupport return-type
611 //
612 // Sets r11 = obj->isa. Consults the tagged isa table if necessary.
613 //
614 // Takes: $0 = NORMAL or FPRET or FP2RET or STRET
615 // a1 or a2 (STRET) = receiver
616 //
617 // On exit: r11 = receiver->isa
618 // r10 is clobbered
619 //
620 /////////////////////////////////////////////////////////////////////
621
622 .macro GetIsa
623
624 .if $0 != STRET
625 testb $$1, %a1b
626 jnz 1f
627 movq (%a1), %r11
628 jmp 2f
629 1: movl %a1d, %r10d
630 .else
631 testb $$1, %a2b
632 jnz 1f
633 movq (%a2), %r11
634 jmp 2f
635 1: movl %a2d, %r10d
636 .endif
637 andl $$0xF, %r10d
638 leaq __objc_tagged_isa_table(%rip), %r11
639 movq (%r11, %r10, 8), %r11 // read isa from table
640 2:
641 .endmacro
642
643 .macro GetIsaFast
644 .if $0 != STRET
645 testb $$1, %a1b
646 .byte 0x2e // harmless branch hint prefix to align IFETCH blocks
647 jnz LGetIsaSlow_f
648 movq (%a1), %r11
649 .else
650 testb $$1, %a2b
651 .byte 0x2e // harmless branch hint prefix to align IFETCH blocks
652 jnz LGetIsaSlow_f
653 movq (%a2), %r11
654 .endif
655 LGetIsaDone:
656 .endmacro
657
658 .macro GetIsaSupport
659 LGetIsaSlow:
660 leaq __objc_tagged_isa_table(%rip), %r11
661 .if $0 != STRET
662 movl %a1d, %r10d
663 .else
664 movl %a2d, %r10d
665 .endif
666 andl $$0xF, %r10d
667 movq (%r11, %r10, 8), %r11 // read isa from table
668 jmp LGetIsaDone_b
669 .endmacro
670
671 /////////////////////////////////////////////////////////////////////
672 //
673 // NilTest return-type
674 //
675 // Takes: $0 = NORMAL or FPRET or FP2RET or STRET
676 // %a1 or %a2 (STRET) = receiver
677 //
678 // On exit: Loads non-nil receiver in %a1 or %a2 (STRET), or returns zero.
679 //
680 // NilTestSupport return-type
681 //
682 // Takes: $0 = NORMAL or FPRET or FP2RET or STRET
683 // %a1 or %a2 (STRET) = receiver
684 //
685 // On exit: Loads non-nil receiver in %a1 or %a2 (STRET), or returns zero.
686 //
687 /////////////////////////////////////////////////////////////////////
688
689 .macro NilTest
690 .if $0 != STRET
691 testq %a1, %a1
692 .else
693 testq %a2, %a2
694 .endif
695 jz LNilTestSlow_f
696 LNilTestDone:
697 .endmacro
698
699 .macro NilTestSupport
700 .align 3
701 LNilTestSlow:
702 .if $0 != STRET
703 movq __objc_nilReceiver(%rip), %a1
704 testq %a1, %a1 // if (receiver != nil)
705 .else
706 movq __objc_nilReceiver(%rip), %a2
707 testq %a2, %a2 // if (receiver != nil)
708 .endif
709 jne LNilTestDone_b // send to new receiver
710
711 .if $0 == FPRET
712 fldz
713 .elseif $0 == FP2RET
714 fldz
715 fldz
716 .endif
717 .if $0 != STRET
718 xorl %eax, %eax
719 xorl %edx, %edx
720 xorps %xmm0, %xmm0
721 xorps %xmm1, %xmm1
722 .endif
723 ret
724 .endmacro
725
726
727 /********************************************************************
728 * Method _cache_getMethod(Class cls, SEL sel, IMP msgForward_internal_imp)
729 *
730 * On entry: a1 = class whose cache is to be searched
731 * a2 = selector to search for
732 * a3 = _objc_msgForward_internal IMP
733 *
734 * If found, returns method triplet pointer.
735 * If not found, returns NULL.
736 *
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.
741 *
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 ********************************************************************/
745
746 STATIC_ENTRY __cache_getMethod
747 DW_START __cache_getMethod
748
749 // do lookup
750 movq %a1, %r11 // move class to r11 for CacheLookup
751 CacheLookup NORMAL, __cache_getMethod
752
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
757 ret
758 1: movl $1, %eax
759 ret
760
761 LCacheMiss:
762 // cache miss, return nil
763 DW_MISS __cache_getMethod
764 pop %rax // pushed by CacheLookup
765 DW_MISS_POP __cache_getMethod
766 xorl %eax, %eax
767 ret
768
769 LGetMethodExit:
770 DW_END __cache_getMethod, 1, 0
771 END_ENTRY __cache_getMethod
772
773
774 /********************************************************************
775 * IMP _cache_getImp(Class cls, SEL sel)
776 *
777 * On entry: a1 = class whose cache is to be searched
778 * a2 = selector to search for
779 *
780 * If found, returns method implementation.
781 * If not found, returns NULL.
782 ********************************************************************/
783
784 STATIC_ENTRY __cache_getImp
785 DW_START __cache_getImp
786
787 // do lookup
788 movq %a1, %r11 // move class to r11 for CacheLookup
789 CacheLookup NORMAL, __cache_getImp
790
791 // cache hit, method triplet in %r11
792 movq method_imp(%r11), %rax // return method imp address
793 ret
794
795 LCacheMiss:
796 // cache miss, return nil
797 DW_MISS __cache_getImp
798 pop %rax // pushed by CacheLookup
799 DW_MISS_POP __cache_getImp
800 xorl %eax, %eax
801 ret
802
803 LGetImpExit:
804 DW_END __cache_getImp, 1, 0
805 END_ENTRY __cache_getImp
806
807
808 /********************************************************************
809 *
810 * id objc_msgSend(id self, SEL _cmd,...);
811 *
812 ********************************************************************/
813
814 .data
815 .align 3
816 .private_extern __objc_tagged_isa_table
817 __objc_tagged_isa_table:
818 .fill 16, 8, 0
819
820 ENTRY _objc_msgSend
821 DW_START _objc_msgSend
822
823 NilTest NORMAL
824
825 GetIsaFast NORMAL // r11 = self->isa
826 CacheLookup NORMAL, _objc_msgSend // r11=method, eq set (nonstret fwd)
827 jmp *method_imp(%r11) // goto *imp
828
829 NilTestSupport NORMAL
830
831 GetIsaSupport NORMAL
832
833 // cache miss: go search the method lists
834 LCacheMiss:
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
840
841 DW_END _objc_msgSend, 1, 1
842 END_ENTRY _objc_msgSend
843
844 #if __OBJC2__
845 ENTRY _objc_msgSend_fixup
846 DW_START _objc_msgSend_fixup
847
848 NilTest NORMAL
849
850 SaveRegisters _objc_msgSend_fixup
851
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
857
858 // a1 = receiver
859 // a2 = address of message ref
860 movq %a2, %a3
861 xorl %a2d, %a2d
862 // __objc_fixupMessageRef(receiver, 0, ref)
863 call __objc_fixupMessageRef
864 movq %rax, %r11
865
866 RestoreRegisters _objc_msgSend_fixup
867
868 // imp is in r11
869 // Load _cmd from the message_ref
870 movq 8(%a2), %a2
871 cmp %r11, %r11 // set nonstret (eq) for forwarding
872 jmp *%r11
873
874 NilTestSupport NORMAL
875
876 DW_END _objc_msgSend_fixup, 0, 1
877 END_ENTRY _objc_msgSend_fixup
878
879
880 STATIC_ENTRY _objc_msgSend_fixedup
881 // Load _cmd from the message_ref
882 movq 8(%a2), %a2
883 jmp _objc_msgSend
884 END_ENTRY _objc_msgSend_fixedup
885 #endif
886
887
888 /********************************************************************
889 *
890 * id objc_msgSendSuper(struct objc_super *super, SEL _cmd,...);
891 *
892 * struct objc_super {
893 * id receiver;
894 * Class class;
895 * };
896 ********************************************************************/
897
898 ENTRY _objc_msgSendSuper
899 DW_START _objc_msgSendSuper
900
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
906
907 // cache miss: go search the method lists
908 LCacheMiss:
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
916
917 DW_END _objc_msgSendSuper, 1, 1
918 END_ENTRY _objc_msgSendSuper
919
920
921 /********************************************************************
922 * id objc_msgSendSuper2
923 ********************************************************************/
924
925 #if __OBJC2__
926 ENTRY _objc_msgSendSuper2_fixup
927 DW_START _objc_msgSendSuper2_fixup
928
929 SaveRegisters _objc_msgSendSuper2_fixup
930 // a1 = address of objc_super2
931 // a2 = address of message ref
932 movq %a2, %a3
933 movq %a1, %a2
934 movq receiver(%a1), %a1
935 // __objc_fixupMessageRef(receiver, objc_super, ref)
936 call __objc_fixupMessageRef
937 movq %rax, %r11
938 RestoreRegisters _objc_msgSendSuper2_fixup
939
940 // imp is in r11
941 // Load _cmd from the message_ref
942 movq 8(%a2), %a2
943 // Load receiver from objc_super2
944 movq receiver(%a1), %a1
945 cmp %r11, %r11 // set nonstret (eq) for forwarding
946 jmp *%r11
947
948 DW_END _objc_msgSendSuper2_fixup, 0, 1
949 END_ENTRY _objc_msgSendSuper2_fixup
950
951
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
956
957
958 ENTRY _objc_msgSendSuper2
959 DW_START _objc_msgSendSuper2
960 // objc_super->class is superclass of class to search
961
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
968
969 // cache miss: go search the method lists
970 LCacheMiss:
971 DW_MISS _objc_msgSendSuper2
972 movq receiver(%a1), %r10
973 movq class(%a1), %r11
974 movq 8(%r11), %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
979
980 DW_END _objc_msgSendSuper2, 1, 1
981 END_ENTRY _objc_msgSendSuper2
982 #endif
983
984
985 /********************************************************************
986 *
987 * double objc_msgSend_fpret(id self, SEL _cmd,...);
988 * Used for `long double` return only. `float` and `double` use objc_msgSend.
989 *
990 ********************************************************************/
991
992 ENTRY _objc_msgSend_fpret
993 DW_START _objc_msgSend_fpret
994
995 NilTest FPRET
996
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
1000
1001 NilTestSupport FPRET
1002
1003 GetIsaSupport FPRET
1004
1005 // cache miss: go search the method lists
1006 LCacheMiss:
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
1012
1013 DW_END _objc_msgSend_fpret, 1, 1
1014 END_ENTRY _objc_msgSend_fpret
1015
1016 #if __OBJC2__
1017 ENTRY _objc_msgSend_fpret_fixup
1018 DW_START _objc_msgSend_fpret_fixup
1019
1020 NilTest FPRET
1021
1022 SaveRegisters _objc_msgSend_fpret_fixup
1023
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
1029
1030 // a1 = receiver
1031 // a2 = address of message ref
1032 movq %a2, %a3
1033 xorl %a2d, %a2d
1034 // __objc_fixupMessageRef(receiver, 0, ref)
1035 call __objc_fixupMessageRef
1036 movq %rax, %r11
1037
1038 RestoreRegisters _objc_msgSend_fpret_fixup
1039
1040 // imp is in r11
1041 // Load _cmd from the message_ref
1042 movq 8(%a2), %a2
1043 cmp %r11, %r11 // set nonstret (eq) for forwarding
1044 jmp *%r11
1045
1046 NilTestSupport FPRET
1047
1048 DW_END _objc_msgSend_fpret_fixup, 0, 1
1049 END_ENTRY _objc_msgSend_fpret_fixup
1050
1051
1052 STATIC_ENTRY _objc_msgSend_fpret_fixedup
1053 // Load _cmd from the message_ref
1054 movq 8(%a2), %a2
1055 jmp _objc_msgSend_fpret
1056 END_ENTRY _objc_msgSend_fpret_fixedup
1057 #endif
1058
1059
1060 /********************************************************************
1061 *
1062 * double objc_msgSend_fp2ret(id self, SEL _cmd,...);
1063 * Used for `complex long double` return only.
1064 *
1065 ********************************************************************/
1066
1067 ENTRY _objc_msgSend_fp2ret
1068 DW_START _objc_msgSend_fp2ret
1069
1070 NilTest FP2RET
1071
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
1075
1076 NilTestSupport FP2RET
1077
1078 GetIsaSupport FP2RET
1079
1080 // cache miss: go search the method lists
1081 LCacheMiss:
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
1087
1088 DW_END _objc_msgSend_fp2ret, 1, 1
1089 END_ENTRY _objc_msgSend_fp2ret
1090
1091 #if __OBJC2__
1092 ENTRY _objc_msgSend_fp2ret_fixup
1093 DW_START _objc_msgSend_fp2ret_fixup
1094
1095 NilTest FP2RET
1096
1097 SaveRegisters _objc_msgSend_fp2ret_fixup
1098
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
1104
1105 // a1 = receiver
1106 // a2 = address of message ref
1107 movq %a2, %a3
1108 xorl %a2d, %a2d
1109 // __objc_fixupMessageRef(receiver, 0, ref)
1110 call __objc_fixupMessageRef
1111 movq %rax, %r11
1112
1113 RestoreRegisters _objc_msgSend_fp2ret_fixup
1114
1115 // imp is in r11
1116 // Load _cmd from the message_ref
1117 movq 8(%a2), %a2
1118 cmp %r11, %r11 // set nonstret (eq) for forwarding
1119 jmp *%r11
1120
1121 NilTestSupport FP2RET
1122
1123 DW_END _objc_msgSend_fp2ret_fixup, 0, 1
1124 END_ENTRY _objc_msgSend_fp2ret_fixup
1125
1126
1127 STATIC_ENTRY _objc_msgSend_fp2ret_fixedup
1128 // Load _cmd from the message_ref
1129 movq 8(%a2), %a2
1130 jmp _objc_msgSend_fp2ret
1131 END_ENTRY _objc_msgSend_fp2ret_fixedup
1132 #endif
1133
1134
1135 /********************************************************************
1136 *
1137 * void objc_msgSend_stret(void *st_addr, id self, SEL _cmd, ...);
1138 *
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.
1142 *
1143 * On entry: %a1 is the address where the structure is returned,
1144 * %a2 is the message receiver,
1145 * %a3 is the selector
1146 ********************************************************************/
1147
1148 ENTRY _objc_msgSend_stret
1149 DW_START _objc_msgSend_stret
1150
1151 NilTest STRET
1152
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
1156
1157 NilTestSupport STRET
1158
1159 GetIsaSupport STRET
1160
1161 // cache miss: go search the method lists
1162 LCacheMiss:
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
1168
1169 DW_END _objc_msgSend_stret, 1, 1
1170 END_ENTRY _objc_msgSend_stret
1171
1172 #if __OBJC2__
1173 ENTRY _objc_msgSend_stret_fixup
1174 DW_START _objc_msgSend_stret_fixup
1175
1176 NilTest STRET
1177
1178 SaveRegisters _objc_msgSend_stret_fixup
1179
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
1185
1186 // a2 = receiver
1187 // a3 = address of message ref
1188 movq %a2, %a1
1189 xorl %a2d, %a2d
1190 // __objc_fixupMessageRef(receiver, 0, ref)
1191 call __objc_fixupMessageRef
1192 movq %rax, %r11
1193
1194 RestoreRegisters _objc_msgSend_stret_fixup
1195
1196 // imp is in r11
1197 // Load _cmd from the message_ref
1198 movq 8(%a3), %a3
1199 test %r11, %r11 // set stret (ne) for forward; r11!=0
1200 jmp *%r11 // goto *imp
1201
1202 NilTestSupport STRET
1203
1204 DW_END _objc_msgSend_stret_fixup, 0, 1
1205 END_ENTRY _objc_msgSend_stret_fixup
1206
1207
1208 STATIC_ENTRY _objc_msgSend_stret_fixedup
1209 // Load _cmd from the message_ref
1210 movq 8(%a3), %a3
1211 jmp _objc_msgSend_stret
1212 END_ENTRY _objc_msgSend_stret_fixedup
1213 #endif
1214
1215
1216 /********************************************************************
1217 *
1218 * void objc_msgSendSuper_stret(void *st_addr, struct objc_super *super, SEL _cmd, ...);
1219 *
1220 * struct objc_super {
1221 * id receiver;
1222 * Class class;
1223 * };
1224 *
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.
1228 *
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
1232 *
1233 ********************************************************************/
1234
1235 ENTRY _objc_msgSendSuper_stret
1236 DW_START _objc_msgSendSuper_stret
1237
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
1243
1244 // cache miss: go search the method lists
1245 LCacheMiss:
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
1253
1254 DW_END _objc_msgSendSuper_stret, 1, 1
1255 END_ENTRY _objc_msgSendSuper_stret
1256
1257
1258 /********************************************************************
1259 * id objc_msgSendSuper2_stret
1260 ********************************************************************/
1261
1262 #if __OBJC2__
1263 ENTRY _objc_msgSendSuper2_stret_fixup
1264 DW_START _objc_msgSendSuper2_stret_fixup
1265
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
1272 movq %rax, %r11
1273 RestoreRegisters _objc_msgSendSuper2_stret_fixup
1274
1275 // imp is in r11
1276 // Load _cmd from the message_ref
1277 movq 8(%a3), %a3
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
1282
1283 DW_END _objc_msgSendSuper2_stret_fixup, 0, 1
1284 END_ENTRY _objc_msgSendSuper2_stret_fixup
1285
1286
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
1291
1292
1293 ENTRY _objc_msgSendSuper2_stret
1294 DW_START _objc_msgSendSuper2_stret
1295
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
1302
1303 // cache miss: go search the method lists
1304 LCacheMiss:
1305 DW_MISS _objc_msgSendSuper2_stret
1306 movq receiver(%a2), %r10
1307 movq class(%a2), %r11
1308 movq 8(%r11), %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
1313
1314 DW_END _objc_msgSendSuper2_stret, 1, 1
1315 END_ENTRY _objc_msgSendSuper2_stret
1316 #endif
1317
1318
1319 /********************************************************************
1320 *
1321 * id _objc_msgForward(id self, SEL _cmd,...);
1322 *
1323 ********************************************************************/
1324
1325 // _FwdSel is @selector(forward::), set up in map_images().
1326 // ALWAYS dereference _FwdSel to get to "forward::" !!
1327 .data
1328 .align 3
1329 .private_extern _FwdSel
1330 _FwdSel: .quad 0
1331
1332 .cstring
1333 .align 3
1334 LUnkSelStr: .ascii "Does not recognize selector %s (while forwarding %s)\0"
1335
1336 .data
1337 .align 3
1338 .private_extern __objc_forward_handler
1339 __objc_forward_handler: .quad 0
1340
1341 .data
1342 .align 3
1343 .private_extern __objc_forward_stret_handler
1344 __objc_forward_stret_handler: .quad 0
1345
1346
1347 STATIC_ENTRY __objc_msgForward_internal
1348 // Method cache version
1349
1350 // THIS IS NOT A CALLABLE C FUNCTION
1351 // Out-of-band condition register is NE for stret, EQ otherwise.
1352
1353 jne __objc_msgForward_stret
1354 jmp __objc_msgForward
1355
1356 END_ENTRY __objc_msgForward_internal
1357
1358
1359 ENTRY __objc_msgForward
1360 // Non-stret version
1361
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
1367 1:
1368 // No user handler
1369
1370 // Die if forwarding "forward::"
1371 cmpq %a2, _FwdSel(%rip)
1372 je LMsgForwardError
1373
1374 // Record current return address. It will be copied elsewhere in
1375 // the marg_list because this location is needed for register args
1376 movq (%rsp), %r11
1377
1378 // Push stack frame
1379 // Space for: fpArgs + regArgs + linkage - ret (already on stack)
1380 subq $ 8*16 + 6*8 + (4-1)*8, %rsp
1381
1382 // Save return address in linkage area.
1383 movq %r11, 16+LINK_AREA(%rsp)
1384
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)
1392
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
1397
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)
1407
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
1413
1414 call _objc_msgSend
1415
1416 // Retrieve return address from linkage area
1417 movq 16+LINK_AREA(%rsp), %r11
1418 // Pop stack frame
1419 addq $ 8*16 + 6*8 + (4-1)*8, %rsp
1420 // Put return address back
1421 movq %r11, (%rsp)
1422 ret
1423
1424 LMsgForwardError:
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
1431
1432 END_ENTRY __objc_msgForward
1433
1434
1435 ENTRY __objc_msgForward_stret
1436 // Struct-return version
1437
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
1443 1:
1444 // No user handler
1445 // Die if forwarding "forward::"
1446 cmpq %a3, _FwdSel(%rip)
1447 je LMsgForwardStretError
1448
1449 // Record current return address. It will be copied elsewhere in
1450 // the marg_list because this location is needed for register args
1451 movq (%rsp), %r11
1452
1453 // Push stack frame
1454 // Space for: fpArgs + regArgs + linkage - ret (already on stack)
1455 subq $ 8*16 + 6*8 + (4-1)*8, %rsp
1456
1457 // Save return address in linkage area.
1458 movq %r11, 16+LINK_AREA(%rsp)
1459
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)
1467
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
1472
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)
1482
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
1488
1489 call _objc_msgSend // forward:: is NOT struct-return
1490
1491 // Retrieve return address from linkage area
1492 movq 16+LINK_AREA(%rsp), %r11
1493 // Pop stack frame
1494 addq $ 8*16 + 6*8 + (4-1)*8, %rsp
1495 // Put return address back
1496 movq %r11, (%rsp)
1497 ret
1498
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
1506
1507 END_ENTRY __objc_msgForward_stret
1508
1509
1510 ENTRY _objc_msgSend_debug
1511 jmp _objc_msgSend
1512 END_ENTRY _objc_msgSend_debug
1513
1514 ENTRY _objc_msgSendSuper2_debug
1515 jmp _objc_msgSendSuper2
1516 END_ENTRY _objc_msgSendSuper2_debug
1517
1518 ENTRY _objc_msgSend_stret_debug
1519 jmp _objc_msgSend_stret
1520 END_ENTRY _objc_msgSend_stret_debug
1521
1522 ENTRY _objc_msgSendSuper2_stret_debug
1523 jmp _objc_msgSendSuper2_stret
1524 END_ENTRY _objc_msgSendSuper2_stret_debug
1525
1526 ENTRY _objc_msgSend_fpret_debug
1527 jmp _objc_msgSend_fpret
1528 END_ENTRY _objc_msgSend_fpret_debug
1529
1530 ENTRY _objc_msgSend_fp2ret_debug
1531 jmp _objc_msgSend_fp2ret
1532 END_ENTRY _objc_msgSend_fp2ret_debug
1533
1534
1535 ENTRY _objc_msgSend_noarg
1536 jmp _objc_msgSend
1537 END_ENTRY _objc_msgSend_noarg
1538
1539
1540 ENTRY _method_invoke
1541
1542 movq method_imp(%a2), %r11
1543 movq method_name(%a2), %a2
1544 jmp *%r11
1545
1546 END_ENTRY _method_invoke
1547
1548
1549 ENTRY _method_invoke_stret
1550
1551 movq method_imp(%a3), %r11
1552 movq method_name(%a3), %a3
1553 jmp *%r11
1554
1555 END_ENTRY _method_invoke_stret
1556
1557
1558 STATIC_ENTRY __objc_ignored_method
1559
1560 movq %a1, %rax
1561 ret
1562
1563 END_ENTRY __objc_ignored_method
1564
1565
1566 /********************************************************************
1567 *
1568 * id vtable_prototype(id self, message_ref *msg, ...)
1569 *
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.
1575 *
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.
1579 *
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
1586 *
1587 ********************************************************************/
1588
1589 .macro VTABLE /* byte-offset, name */
1590
1591 .align 6
1592 .private_extern _$1
1593 _$1:
1594 test %a1, %a1
1595 je LvtableReturnZero_$1 // nil check
1596 testl $$1, %a1d
1597 jne LvtableTaggedPointer_$1 // tag check
1598
1599 movq (%a1), %rax // load isa (see ABI WARNING)
1600 movq 24(%rax), %rax // load vtable
1601 movq 8(%a2), %a2 // load _cmd
1602 LvtableIndex_$1:
1603 jmpq * $0 (%rax) // load imp (DO NOT CHANGE)
1604
1605 LvtableReturnZero_$1:
1606 // integer registers only; not used for fpret / stret / etc
1607 xorl %eax, %eax
1608 // xorl %edx, %edx (see ABI WARNING)
1609 ret
1610
1611 nop
1612 LvtableTaggedPointer_$1:
1613 // extract isa (bits 1-2-3) from %a1, bit 0 is kept around for the heck of it
1614 movl %a1d, %eax
1615 andl $$0xF, %eax
1616 LvtableTagTable_$1:
1617 .if $0 == 0x7fff
1618 movq $$0x1122334455667788, %r10 // vtable_prototype (DO NOT CHANGE)
1619 .else
1620 leaq __objc_tagged_isa_table(%rip), %r10
1621 .endif
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
1626 LvtableIndex2_$1:
1627 jmpq * $0 (%rax) // load imp (DO NOT CHANGE)
1628
1629 LvtableEnd_$1:
1630
1631 .endmacro
1632
1633 .section __TEXT,__objc_codegen,regular
1634 VTABLE 0x7fff, vtable_prototype
1635
1636 .data
1637 .align 2
1638 .private_extern _vtable_prototype_size
1639 _vtable_prototype_size:
1640 .long LvtableEnd_vtable_prototype - _vtable_prototype
1641
1642 .private_extern _vtable_prototype_index_offset
1643 _vtable_prototype_index_offset:
1644 .long LvtableIndex_vtable_prototype - _vtable_prototype
1645
1646 .private_extern _vtable_prototype_index2_offset
1647 _vtable_prototype_index2_offset:
1648 .long LvtableIndex2_vtable_prototype - _vtable_prototype
1649
1650 .private_extern _vtable_prototype_tagtable_offset
1651 _vtable_prototype_tagtable_offset:
1652 .long LvtableTagTable_vtable_prototype - _vtable_prototype
1653
1654 .private_extern _vtable_prototype_tagtable_size
1655 _vtable_prototype_tagtable_size:
1656 .long LvtableTagTableEnd_vtable_prototype - LvtableTagTable_vtable_prototype
1657
1658 /********************************************************************
1659 *
1660 * id vtable_ignored(id self, message_ref *msg, ...)
1661 *
1662 * Vtable trampoline for GC-ignored selectors. Immediately returns self.
1663 *
1664 ********************************************************************/
1665
1666 STATIC_ENTRY _vtable_ignored
1667 movq %a1, %rax
1668 ret
1669
1670
1671 /********************************************************************
1672 *
1673 * id objc_msgSend_vtable<n>(id self, message_ref *msg, ...)
1674 *
1675 * Built-in expansions of vtable_prototype for the default vtable.
1676 *
1677 ********************************************************************/
1678
1679 .text
1680
1681 .align 4
1682 .private_extern _defaultVtableTrampolineDescriptors
1683 _defaultVtableTrampolineDescriptors:
1684 // objc_trampoline_header
1685 .short 16 // headerSize
1686 .short 8 // descSize
1687 .long 16 // descCount
1688 .quad 0 // next
1689
1690 // objc_trampoline_descriptor[16]
1691 .macro TDESC /* n */
1692 L_tdesc$0:
1693 .long _objc_msgSend_vtable$0 - L_tdesc$0
1694 .long (1<<0) + (1<<2) // MESSAGE and VTABLE
1695 .endmacro
1696
1697 TDESC 0
1698 TDESC 1
1699 TDESC 2
1700 TDESC 3
1701 TDESC 4
1702 TDESC 5
1703 TDESC 6
1704 TDESC 7
1705 TDESC 8
1706 TDESC 9
1707 TDESC 10
1708 TDESC 11
1709 TDESC 12
1710 TDESC 13
1711 TDESC 14
1712 TDESC 15
1713
1714 // trampoline code
1715 .align 4
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
1732
1733 #endif