]>
Commit | Line | Data |
---|---|---|
b3962a83 A |
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 | */ | |
7af964d1 A |
23 | |
24 | #ifdef __x86_64__ | |
25 | ||
b3962a83 A |
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 | ||
b3962a83 A |
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 | |
8972963c | 45 | .private_extern __objc_nilReceiver |
b3962a83 A |
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 | ||
8972963c | 53 | .private_extern _objc_entryPoints |
b3962a83 A |
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 | |
8972963c A |
63 | .quad _objc_msgSendSuper2 |
64 | .quad _objc_msgSendSuper2_stret | |
b3962a83 A |
65 | .quad 0 |
66 | ||
8972963c | 67 | .private_extern _objc_exitPoints |
b3962a83 | 68 | _objc_exitPoints: |
8972963c A |
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 | |
b3962a83 A |
79 | .quad 0 |
80 | ||
81 | ||
82 | /******************************************************************** | |
8972963c A |
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 | /******************************************************************** | |
b3962a83 | 98 | * Names for parameter registers. |
b3962a83 A |
99 | ********************************************************************/ |
100 | ||
8972963c A |
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 | |
b3962a83 A |
114 | #define a6d r9d |
115 | ||
116 | ||
8972963c A |
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 | ||
b3962a83 A |
148 | /******************************************************************** |
149 | * | |
150 | * Structure definitions. | |
151 | * | |
152 | ********************************************************************/ | |
153 | ||
154 | // objc_super parameter to sendSuper | |
8972963c A |
155 | #define receiver 0 |
156 | #define class 8 | |
b3962a83 A |
157 | |
158 | // Selected field offsets in class structure | |
8972963c A |
159 | // #define isa 0 USE GetIsa INSTEAD |
160 | #define cache 16 | |
b3962a83 A |
161 | |
162 | // Method descriptor | |
8972963c A |
163 | #define method_name 0 |
164 | #define method_imp 16 | |
b3962a83 A |
165 | |
166 | // Cache header | |
8972963c A |
167 | #define mask 0 |
168 | #define occupied 8 | |
169 | #define buckets 16 | |
b3962a83 A |
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 | ||
b3962a83 A |
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 | |
8972963c A |
195 | .align 6, 0x90 |
196 | $0: | |
197 | .endmacro | |
198 | ||
199 | .macro STATIC_ENTRY | |
200 | .text | |
201 | .private_extern $0 | |
b3962a83 A |
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 | |
8972963c | 217 | LExit$0: |
b3962a83 A |
218 | .endmacro |
219 | ||
b3962a83 | 220 | |
7af964d1 A |
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 | |
b3962a83 A |
359 | .endmacro |
360 | ||
361 | ||
362 | ///////////////////////////////////////////////////////////////////// | |
363 | // | |
8972963c | 364 | // SaveRegisters caller |
b3962a83 A |
365 | // |
366 | // Pushes a stack frame and saves all registers that might contain | |
367 | // parameter values. | |
368 | // | |
8972963c A |
369 | // On entry: %0 = caller's symbol name for DWARF |
370 | // stack = ret | |
b3962a83 A |
371 | // |
372 | // On exit: | |
8972963c | 373 | // %rsp is 16-byte aligned |
b3962a83 A |
374 | // |
375 | ///////////////////////////////////////////////////////////////////// | |
7af964d1 | 376 | |
b3962a83 | 377 | .macro SaveRegisters |
8972963c A |
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) | |
b3962a83 A |
395 | .endmacro |
396 | ||
397 | ///////////////////////////////////////////////////////////////////// | |
398 | // | |
399 | // RestoreRegisters | |
400 | // | |
401 | // Pops a stack frame pushed by SaveRegisters | |
402 | // | |
8972963c A |
403 | // On entry: $0 = caller's symbol name for DWARF |
404 | // %rbp unchanged since SaveRegisters | |
b3962a83 A |
405 | // |
406 | // On exit: | |
8972963c | 407 | // stack = ret |
b3962a83 A |
408 | // |
409 | ///////////////////////////////////////////////////////////////////// | |
410 | ||
411 | .macro RestoreRegisters | |
8972963c A |
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 | |
b3962a83 A |
428 | .endmacro |
429 | ||
430 | ||
431 | ///////////////////////////////////////////////////////////////////// | |
432 | // | |
433 | // | |
8972963c | 434 | // CacheLookup return-type |
b3962a83 A |
435 | // |
436 | // Locate the implementation for a selector in a class method cache. | |
437 | // | |
438 | // Takes: | |
8972963c A |
439 | // $0 = NORMAL, FPRET, FP2RET, STRET |
440 | // a2 or a3 (STRET) = selector | |
b3962a83 | 441 | // %r11 = class whose cache is to be searched |
b3962a83 | 442 | // |
8972963c A |
443 | // On exit: (found) method in %r11, stack unchanged, eq/ne set for forwarding |
444 | // (not found) jumps to LCacheMiss, %rax on stack | |
445 | // | |
b3962a83 A |
446 | ///////////////////////////////////////////////////////////////////// |
447 | ||
b3962a83 A |
448 | .macro CacheLookup |
449 | ||
8972963c A |
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 | |
b3962a83 A |
457 | |
458 | // search the receiver's cache | |
459 | // r11 = method (soon) | |
8972963c A |
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++ | |
b3962a83 | 467 | testq %r11, %r11 // if (method == NULL) |
8972963c A |
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 | |
b3962a83 A |
475 | |
476 | // cache hit, r11 = method triplet | |
b3962a83 | 477 | // restore saved registers |
8972963c A |
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 | |
b3962a83 | 486 | |
b3962a83 A |
487 | .endmacro |
488 | ||
489 | ||
490 | ///////////////////////////////////////////////////////////////////// | |
491 | // | |
7af964d1 | 492 | // MethodTableLookup classRegister, selectorRegister, fn |
b3962a83 | 493 | // |
8972963c A |
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 | |
b3962a83 | 498 | // |
8972963c | 499 | // Stack: ret, rax (pushed by CacheLookup) |
b3962a83 | 500 | // |
8972963c | 501 | // On exit: pops registers pushed by CacheLookup |
b3962a83 A |
502 | // imp in %r11 |
503 | // | |
504 | ///////////////////////////////////////////////////////////////////// | |
505 | .macro MethodTableLookup | |
8972963c A |
506 | |
507 | pop %rax // saved by CacheLookup | |
508 | SaveRegisters $2 | |
b3962a83 | 509 | |
8972963c | 510 | // _class_lookupMethodAndLoadCache3(receiver, selector, class) |
b3962a83 | 511 | |
b3962a83 A |
512 | movq $0, %a1 |
513 | movq $1, %a2 | |
8972963c A |
514 | movq %r11, %a3 |
515 | call __class_lookupMethodAndLoadCache3 | |
b3962a83 A |
516 | |
517 | // IMP is now in %rax | |
518 | movq %rax, %r11 | |
519 | ||
7af964d1 | 520 | RestoreRegisters $2 |
b3962a83 A |
521 | |
522 | .endmacro | |
523 | ||
8972963c A |
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 | ||
b3962a83 A |
644 | |
645 | /******************************************************************** | |
7af964d1 | 646 | * Method _cache_getMethod(Class cls, SEL sel, IMP msgForward_internal_imp) |
b3962a83 A |
647 | * |
648 | * On entry: a1 = class whose cache is to be searched | |
649 | * a2 = selector to search for | |
7af964d1 | 650 | * a3 = _objc_msgForward_internal IMP |
b3962a83 A |
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 | |
7af964d1 A |
656 | * is _objc_msgForward_internal. It returns 1 instead. This prevents thread- |
657 | * thread-safety and memory management bugs in _class_lookupMethodAndLoadCache. | |
b3962a83 A |
658 | * See _class_lookupMethodAndLoadCache for details. |
659 | * | |
7af964d1 A |
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. | |
b3962a83 | 662 | ********************************************************************/ |
8972963c A |
663 | |
664 | STATIC_ENTRY __cache_getMethod | |
7af964d1 | 665 | DW_START __cache_getMethod |
b3962a83 A |
666 | |
667 | // do lookup | |
668 | movq %a1, %r11 // move class to r11 for CacheLookup | |
8972963c | 669 | CacheLookup NORMAL |
b3962a83 A |
670 | |
671 | // cache hit, method triplet in %r11 | |
8972963c A |
672 | cmpq method_imp(%r11), %a3 // if (imp==_objc_msgForward_internal) |
673 | je 1f // return (Method)1 | |
b3962a83 A |
674 | movq %r11, %rax // return method triplet address |
675 | ret | |
8972963c | 676 | 1: movl $1, %eax |
7af964d1 | 677 | ret |
b3962a83 | 678 | |
8972963c | 679 | LCacheMiss: |
b3962a83 | 680 | // cache miss, return nil |
8972963c A |
681 | pop %rax // pushed by CacheLookup |
682 | xorl %eax, %eax | |
b3962a83 A |
683 | ret |
684 | ||
685 | LGetMethodExit: | |
7af964d1 A |
686 | DW_END2 __cache_getMethod |
687 | END_ENTRY __cache_getMethod | |
b3962a83 A |
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 | ||
8972963c | 700 | STATIC_ENTRY __cache_getImp |
7af964d1 | 701 | DW_START __cache_getImp |
b3962a83 A |
702 | |
703 | // do lookup | |
704 | movq %a1, %r11 // move class to r11 for CacheLookup | |
8972963c | 705 | CacheLookup NORMAL |
b3962a83 A |
706 | |
707 | // cache hit, method triplet in %r11 | |
708 | movq method_imp(%r11), %rax // return method imp address | |
709 | ret | |
710 | ||
8972963c | 711 | LCacheMiss: |
b3962a83 | 712 | // cache miss, return nil |
8972963c A |
713 | pop %rax // pushed by CacheLookup |
714 | xorl %eax, %eax | |
b3962a83 A |
715 | ret |
716 | ||
717 | LGetImpExit: | |
7af964d1 A |
718 | DW_END2 __cache_getImp |
719 | END_ENTRY __cache_getImp | |
b3962a83 A |
720 | |
721 | ||
722 | /******************************************************************** | |
723 | * | |
724 | * id objc_msgSend(id self, SEL _cmd,...); | |
725 | * | |
726 | ********************************************************************/ | |
727 | ||
8972963c A |
728 | .data |
729 | .align 3 | |
730 | .private_extern __objc_tagged_isa_table | |
731 | __objc_tagged_isa_table: | |
732 | .fill 16, 8, 0 | |
733 | ||
b3962a83 | 734 | ENTRY _objc_msgSend |
7af964d1 | 735 | DW_START _objc_msgSend |
b3962a83 | 736 | |
8972963c | 737 | NilTest NORMAL |
b3962a83 | 738 | |
8972963c A |
739 | GetIsaFast NORMAL // r11 = self->isa |
740 | CacheLookup NORMAL // r11 = method, eq set (nonstret fwd) | |
741 | jmp *method_imp(%r11) // goto *imp | |
b3962a83 | 742 | |
8972963c | 743 | NilTestSupport NORMAL |
b3962a83 | 744 | |
8972963c | 745 | GetIsaSupport NORMAL |
b3962a83 | 746 | |
8972963c A |
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 | |
b3962a83 | 753 | |
7af964d1 | 754 | DW_END _objc_msgSend |
b3962a83 A |
755 | END_ENTRY _objc_msgSend |
756 | ||
757 | #if __OBJC2__ | |
758 | ENTRY _objc_msgSend_fixup | |
7af964d1 | 759 | DW_START _objc_msgSend_fixup |
b3962a83 | 760 | |
8972963c | 761 | NilTest NORMAL |
7af964d1 | 762 | |
8972963c A |
763 | SaveRegisters _objc_msgSend_fixup |
764 | ||
7af964d1 | 765 | // Dereference obj/isa/cache to crash before _objc_fixupMessageRef |
8972963c A |
766 | movq 8(%a2), %a6 // selector |
767 | GetIsa NORMAL // r11 = isa = *receiver | |
768 | movq cache(%r11), %a5 // cache = *isa | |
7af964d1 A |
769 | movq mask(%a5), %a4 // *cache |
770 | ||
b3962a83 A |
771 | // a1 = receiver |
772 | // a2 = address of message ref | |
773 | movq %a2, %a3 | |
8972963c | 774 | xorl %a2d, %a2d |
b3962a83 A |
775 | // __objc_fixupMessageRef(receiver, 0, ref) |
776 | call __objc_fixupMessageRef | |
777 | movq %rax, %r11 | |
7af964d1 A |
778 | |
779 | RestoreRegisters _objc_msgSend_fixup | |
b3962a83 A |
780 | |
781 | // imp is in r11 | |
782 | // Load _cmd from the message_ref | |
783 | movq 8(%a2), %a2 | |
7af964d1 | 784 | cmp %r11, %r11 // set nonstret (eq) for forwarding |
b3962a83 A |
785 | jmp *%r11 |
786 | ||
8972963c | 787 | NilTestSupport NORMAL |
b3962a83 | 788 | |
7af964d1 A |
789 | DW_END _objc_msgSend_fixup |
790 | END_ENTRY _objc_msgSend_fixup | |
b3962a83 A |
791 | |
792 | ||
8972963c | 793 | STATIC_ENTRY _objc_msgSend_fixedup |
b3962a83 A |
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 | |
7af964d1 | 812 | DW_START _objc_msgSendSuper |
b3962a83 | 813 | |
b3962a83 A |
814 | // search the cache (objc_super in %a1) |
815 | movq class(%a1), %r11 // class = objc_super->class | |
8972963c | 816 | CacheLookup NORMAL // r11 = method, eq set (nonstret fwd) |
b3962a83 | 817 | movq receiver(%a1), %a1 // load real receiver |
8972963c | 818 | jmp *method_imp(%r11) // goto *imp |
b3962a83 A |
819 | |
820 | // cache miss: go search the method lists | |
8972963c A |
821 | LCacheMiss: |
822 | movq receiver(%a1), %r10 | |
823 | movq class(%a1), %r11 | |
824 | MethodTableLookup %r10, %a2, _objc_msgSendSuper // r11 = IMP | |
b3962a83 | 825 | movq receiver(%a1), %a1 // load real receiver |
8972963c | 826 | cmp %r11, %r11 // set eq (nonstret) for forwarding |
b3962a83 | 827 | jmp *%r11 // goto *imp |
b3962a83 | 828 | |
7af964d1 | 829 | DW_END _objc_msgSendSuper |
b3962a83 A |
830 | END_ENTRY _objc_msgSendSuper |
831 | ||
8972963c A |
832 | |
833 | /******************************************************************** | |
834 | * id objc_msgSendSuper2 | |
835 | ********************************************************************/ | |
836 | ||
b3962a83 A |
837 | #if __OBJC2__ |
838 | ENTRY _objc_msgSendSuper2_fixup | |
7af964d1 | 839 | DW_START _objc_msgSendSuper2_fixup |
b3962a83 | 840 | |
8972963c | 841 | SaveRegisters _objc_msgSendSuper2_fixup |
b3962a83 A |
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 | |
7af964d1 | 850 | RestoreRegisters _objc_msgSendSuper2_fixup |
b3962a83 A |
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 | |
7af964d1 | 857 | cmp %r11, %r11 // set nonstret (eq) for forwarding |
b3962a83 A |
858 | jmp *%r11 |
859 | ||
7af964d1 A |
860 | DW_END _objc_msgSendSuper2_fixup |
861 | END_ENTRY _objc_msgSendSuper2_fixup | |
b3962a83 A |
862 | |
863 | ||
8972963c | 864 | STATIC_ENTRY _objc_msgSendSuper2_fixedup |
b3962a83 | 865 | movq 8(%a2), %a2 // load _cmd from message_ref |
8972963c | 866 | jmp _objc_msgSendSuper2 |
b3962a83 | 867 | END_ENTRY _objc_msgSendSuper2_fixedup |
7af964d1 A |
868 | |
869 | ||
870 | ENTRY _objc_msgSendSuper2 | |
8972963c | 871 | DW_START _objc_msgSendSuper2 |
7af964d1 | 872 | // objc_super->class is superclass of class to search |
8972963c A |
873 | |
874 | // search the cache (objc_super in %a1) | |
7af964d1 | 875 | movq class(%a1), %r11 // cls = objc_super->class |
8972963c A |
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 | |
b3962a83 A |
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 | |
7af964d1 | 904 | DW_START _objc_msgSend_fpret |
b3962a83 | 905 | |
8972963c | 906 | NilTest FPRET |
b3962a83 | 907 | |
8972963c A |
908 | GetIsaFast FPRET // r11 = self->isa |
909 | CacheLookup FPRET // r11 = method, eq set (nonstret fwd) | |
910 | jmp *method_imp(%r11) // goto *imp | |
b3962a83 | 911 | |
8972963c | 912 | NilTestSupport FPRET |
b3962a83 | 913 | |
8972963c | 914 | GetIsaSupport FPRET |
b3962a83 | 915 | |
8972963c A |
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 | |
b3962a83 | 922 | |
7af964d1 | 923 | DW_END _objc_msgSend_fpret |
b3962a83 A |
924 | END_ENTRY _objc_msgSend_fpret |
925 | ||
926 | #if __OBJC2__ | |
927 | ENTRY _objc_msgSend_fpret_fixup | |
7af964d1 | 928 | DW_START _objc_msgSend_fpret_fixup |
b3962a83 | 929 | |
8972963c | 930 | NilTest FPRET |
b3962a83 | 931 | |
8972963c | 932 | SaveRegisters _objc_msgSend_fpret_fixup |
7af964d1 A |
933 | |
934 | // Dereference obj/isa/cache to crash before _objc_fixupMessageRef | |
8972963c A |
935 | movq 8(%a2), %a6 // selector |
936 | GetIsa FPRET // r11 = isa = *receiver | |
937 | movq cache(%r11), %a5 // cache = *isa | |
7af964d1 A |
938 | movq mask(%a5), %a4 // *cache |
939 | ||
b3962a83 A |
940 | // a1 = receiver |
941 | // a2 = address of message ref | |
942 | movq %a2, %a3 | |
8972963c | 943 | xorl %a2d, %a2d |
b3962a83 A |
944 | // __objc_fixupMessageRef(receiver, 0, ref) |
945 | call __objc_fixupMessageRef | |
946 | movq %rax, %r11 | |
7af964d1 A |
947 | |
948 | RestoreRegisters _objc_msgSend_fpret_fixup | |
b3962a83 A |
949 | |
950 | // imp is in r11 | |
951 | // Load _cmd from the message_ref | |
952 | movq 8(%a2), %a2 | |
7af964d1 | 953 | cmp %r11, %r11 // set nonstret (eq) for forwarding |
b3962a83 A |
954 | jmp *%r11 |
955 | ||
8972963c | 956 | NilTestSupport FPRET |
b3962a83 | 957 | |
7af964d1 A |
958 | DW_END _objc_msgSend_fpret_fixup |
959 | END_ENTRY _objc_msgSend_fpret_fixup | |
b3962a83 A |
960 | |
961 | ||
8972963c | 962 | STATIC_ENTRY _objc_msgSend_fpret_fixedup |
b3962a83 A |
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 | |
7af964d1 | 978 | DW_START _objc_msgSend_fp2ret |
b3962a83 | 979 | |
8972963c | 980 | NilTest FP2RET |
b3962a83 | 981 | |
8972963c A |
982 | GetIsaFast FP2RET // r11 = self->isa |
983 | CacheLookup FP2RET // r11 = method, eq set (nonstret fwd) | |
984 | jmp *method_imp(%r11) // goto *imp | |
b3962a83 | 985 | |
8972963c A |
986 | NilTestSupport FP2RET |
987 | ||
988 | GetIsaSupport FP2RET | |
989 | ||
b3962a83 | 990 | // cache miss: go search the method lists |
8972963c A |
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 | |
b3962a83 A |
995 | jmp *%r11 // goto *imp |
996 | ||
7af964d1 | 997 | DW_END _objc_msgSend_fp2ret |
b3962a83 A |
998 | END_ENTRY _objc_msgSend_fp2ret |
999 | ||
1000 | #if __OBJC2__ | |
1001 | ENTRY _objc_msgSend_fp2ret_fixup | |
7af964d1 | 1002 | DW_START _objc_msgSend_fp2ret_fixup |
b3962a83 | 1003 | |
8972963c | 1004 | NilTest FP2RET |
b3962a83 | 1005 | |
8972963c | 1006 | SaveRegisters _objc_msgSend_fp2ret_fixup |
7af964d1 A |
1007 | |
1008 | // Dereference obj/isa/cache to crash before _objc_fixupMessageRef | |
8972963c A |
1009 | movq 8(%a2), %a6 // selector |
1010 | GetIsa FP2RET // r11 = isa = *receiver | |
1011 | movq cache(%r11), %a5 // cache = *isa | |
7af964d1 A |
1012 | movq mask(%a5), %a4 // *cache |
1013 | ||
b3962a83 A |
1014 | // a1 = receiver |
1015 | // a2 = address of message ref | |
1016 | movq %a2, %a3 | |
8972963c | 1017 | xorl %a2d, %a2d |
b3962a83 A |
1018 | // __objc_fixupMessageRef(receiver, 0, ref) |
1019 | call __objc_fixupMessageRef | |
1020 | movq %rax, %r11 | |
7af964d1 A |
1021 | |
1022 | RestoreRegisters _objc_msgSend_fp2ret_fixup | |
b3962a83 A |
1023 | |
1024 | // imp is in r11 | |
1025 | // Load _cmd from the message_ref | |
1026 | movq 8(%a2), %a2 | |
7af964d1 | 1027 | cmp %r11, %r11 // set nonstret (eq) for forwarding |
b3962a83 A |
1028 | jmp *%r11 |
1029 | ||
8972963c | 1030 | NilTestSupport FP2RET |
b3962a83 | 1031 | |
7af964d1 A |
1032 | DW_END _objc_msgSend_fp2ret_fixup |
1033 | END_ENTRY _objc_msgSend_fp2ret_fixup | |
b3962a83 A |
1034 | |
1035 | ||
8972963c | 1036 | STATIC_ENTRY _objc_msgSend_fp2ret_fixedup |
b3962a83 A |
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 | |
7af964d1 | 1058 | DW_START _objc_msgSend_stret |
b3962a83 | 1059 | |
8972963c A |
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 | |
b3962a83 A |
1069 | |
1070 | // cache miss: go search the method lists | |
8972963c A |
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 | |
7af964d1 | 1075 | jmp *%r11 // goto *imp |
b3962a83 | 1076 | |
7af964d1 | 1077 | DW_END _objc_msgSend_stret |
b3962a83 A |
1078 | END_ENTRY _objc_msgSend_stret |
1079 | ||
1080 | #if __OBJC2__ | |
1081 | ENTRY _objc_msgSend_stret_fixup | |
7af964d1 | 1082 | DW_START _objc_msgSend_stret_fixup |
b3962a83 | 1083 | |
8972963c | 1084 | NilTest STRET |
b3962a83 | 1085 | |
8972963c | 1086 | SaveRegisters _objc_msgSend_stret_fixup |
7af964d1 A |
1087 | |
1088 | // Dereference obj/isa/cache to crash before _objc_fixupMessageRef | |
8972963c A |
1089 | movq 8(%a3), %a6 // selector |
1090 | GetIsa STRET // r11 = isa = *receiver | |
1091 | movq cache(%r11), %a5 // cache = *isa | |
7af964d1 A |
1092 | movq mask(%a5), %a4 // *cache |
1093 | ||
b3962a83 A |
1094 | // a2 = receiver |
1095 | // a3 = address of message ref | |
1096 | movq %a2, %a1 | |
8972963c | 1097 | xorl %a2d, %a2d |
b3962a83 A |
1098 | // __objc_fixupMessageRef(receiver, 0, ref) |
1099 | call __objc_fixupMessageRef | |
1100 | movq %rax, %r11 | |
7af964d1 A |
1101 | |
1102 | RestoreRegisters _objc_msgSend_stret_fixup | |
b3962a83 A |
1103 | |
1104 | // imp is in r11 | |
1105 | // Load _cmd from the message_ref | |
1106 | movq 8(%a3), %a3 | |
7af964d1 A |
1107 | test %r11, %r11 // set stret (ne) for forward; r11!=0 |
1108 | jmp *%r11 // goto *imp | |
b3962a83 | 1109 | |
8972963c | 1110 | NilTestSupport STRET |
b3962a83 | 1111 | |
7af964d1 A |
1112 | DW_END _objc_msgSend_stret_fixup |
1113 | END_ENTRY _objc_msgSend_stret_fixup | |
b3962a83 A |
1114 | |
1115 | ||
8972963c | 1116 | STATIC_ENTRY _objc_msgSend_stret_fixedup |
b3962a83 A |
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 | |
7af964d1 | 1144 | DW_START _objc_msgSendSuper_stret |
b3962a83 A |
1145 | |
1146 | // search the cache (objc_super in %a2) | |
8972963c A |
1147 | movq class(%a2), %r11 // class = objc_super->class |
1148 | CacheLookup STRET // r11 = method, ne set (stret fwd) | |
7af964d1 | 1149 | movq receiver(%a2), %a2 // load real receiver |
8972963c | 1150 | jmp *method_imp(%r11) // goto *imp |
b3962a83 A |
1151 | |
1152 | // cache miss: go search the method lists | |
8972963c A |
1153 | LCacheMiss: |
1154 | movq receiver(%a2), %r10 | |
1155 | movq class(%a2), %r11 | |
1156 | MethodTableLookup %r10, %a3, _objc_msgSendSuper_stret // r11 = IMP | |
7af964d1 | 1157 | movq receiver(%a2), %a2 // load real receiver |
8972963c | 1158 | test %r11, %r11 // set ne (stret) for forward; r11!=0 |
7af964d1 | 1159 | jmp *%r11 // goto *imp |
b3962a83 | 1160 | |
7af964d1 | 1161 | DW_END _objc_msgSendSuper_stret |
b3962a83 A |
1162 | END_ENTRY _objc_msgSendSuper_stret |
1163 | ||
8972963c A |
1164 | |
1165 | /******************************************************************** | |
1166 | * id objc_msgSendSuper2_stret | |
1167 | ********************************************************************/ | |
1168 | ||
b3962a83 A |
1169 | #if __OBJC2__ |
1170 | ENTRY _objc_msgSendSuper2_stret_fixup | |
7af964d1 | 1171 | DW_START _objc_msgSendSuper2_stret_fixup |
b3962a83 | 1172 | |
8972963c | 1173 | SaveRegisters _objc_msgSendSuper2_stret_fixup |
b3962a83 A |
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 | |
7af964d1 | 1180 | RestoreRegisters _objc_msgSendSuper2_stret_fixup |
b3962a83 A |
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 | |
7af964d1 A |
1187 | test %r11, %r11 // set stret (ne) for forward; r11!=0 |
1188 | jmp *%r11 // goto *imp | |
b3962a83 | 1189 | |
7af964d1 A |
1190 | DW_END _objc_msgSendSuper2_stret_fixup |
1191 | END_ENTRY _objc_msgSendSuper2_stret_fixup | |
b3962a83 A |
1192 | |
1193 | ||
8972963c | 1194 | STATIC_ENTRY _objc_msgSendSuper2_stret_fixedup |
b3962a83 | 1195 | movq 8(%a3), %a3 // load _cmd from message_ref |
8972963c | 1196 | jmp _objc_msgSendSuper2_stret |
b3962a83 | 1197 | END_ENTRY _objc_msgSendSuper2_stret_fixedup |
7af964d1 A |
1198 | |
1199 | ||
8972963c A |
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 | |
b3962a83 A |
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 | ||
b3962a83 | 1252 | |
8972963c | 1253 | STATIC_ENTRY __objc_msgForward_internal |
7af964d1 A |
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. | |
b3962a83 | 1258 | |
7af964d1 A |
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 | |
b3962a83 A |
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 | |
8972963c | 1300 | // movq %r10, 0+LINK_AREA(%rsp) // static chain pointer == Pascal |
b3962a83 A |
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 | |
8972963c | 1325 | addq $ 8*16 + 6*8 + (4-1)*8, %rsp |
b3962a83 A |
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 | |
7af964d1 A |
1341 | // Struct-return version |
1342 | ||
b3962a83 A |
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 | |
8972963c | 1374 | // movq %r10, 0+LINK_AREA(%rsp) // static chain pointer == Pascal |
b3962a83 A |
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 | |
8972963c | 1399 | addq $ 8*16 + 6*8 + (4-1)*8, %rsp |
b3962a83 A |
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 | ||
8972963c A |
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 | ||
b3962a83 A |
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 | |
7af964d1 | 1460 | |
8972963c A |
1461 | |
1462 | STATIC_ENTRY __objc_ignored_method | |
1463 | ||
1464 | movq %a1, %rax | |
1465 | ret | |
1466 | ||
1467 | END_ENTRY __objc_ignored_method | |
1468 | ||
7af964d1 A |
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. | |
8972963c A |
1477 | * The instructions following LvtableTagTable are modified to |
1478 | * load the tagged isa table. | |
7af964d1 A |
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. | |
8972963c A |
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 | |
7af964d1 A |
1490 | * |
1491 | ********************************************************************/ | |
1492 | ||
1493 | .macro VTABLE /* byte-offset, name */ | |
1494 | ||
8972963c | 1495 | .align 6 |
7af964d1 A |
1496 | .private_extern _$1 |
1497 | _$1: | |
1498 | test %a1, %a1 | |
8972963c A |
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 | |
7af964d1 | 1506 | LvtableIndex_$1: |
8972963c A |
1507 | jmpq * $0 (%rax) // load imp (DO NOT CHANGE) |
1508 | ||
7af964d1 A |
1509 | LvtableReturnZero_$1: |
1510 | // integer registers only; not used for fpret / stret / etc | |
8972963c A |
1511 | xorl %eax, %eax |
1512 | // xorl %edx, %edx (see ABI WARNING) | |
7af964d1 | 1513 | ret |
8972963c | 1514 | |
7af964d1 | 1515 | nop |
8972963c A |
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: | |
7af964d1 A |
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 | ||
8972963c A |
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 | |
7af964d1 A |
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 | ||
8972963c | 1570 | STATIC_ENTRY _vtable_ignored |
7af964d1 A |
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 |