]>
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 | |
cd5f04f5 | 292 | // RA is at 0(%rsp) aka 1*-8(CFA) |
7af964d1 A |
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 | |
cd5f04f5 A |
312 | .quad L_dw_start_$0-. # FDE address start |
313 | .quad L_dw_len_$0 # FDE address range | |
7af964d1 A |
314 | .byte 0x0 # uleb128 0x0; Augmentation size |
315 | ||
316 | // DW_START: set by CIE | |
317 | ||
cd5f04f5 A |
318 | .if $1 == 1 |
319 | // CacheLookup | |
7af964d1 | 320 | |
cd5f04f5 | 321 | // push |
7af964d1 | 322 | .byte DW_CFA_advance_loc4 |
cd5f04f5 A |
323 | .long L_dw_push_$0 - L_dw_start_$0 |
324 | .byte DW_CFA_def_cfa_offset // CFA = rsp+16 | |
7af964d1 | 325 | .byte 16 |
cd5f04f5 A |
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 | |
7af964d1 | 351 | .byte DW_CFA_advance_loc4 |
cd5f04f5 A |
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) | |
7af964d1 | 362 | .byte DW_rbp |
cd5f04f5 A |
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 | |
7af964d1 A |
373 | |
374 | .endif | |
375 | ||
376 | .align 3 | |
377 | LEFDE$0: | |
378 | .text | |
379 | ||
380 | .endmacro | |
381 | ||
382 | ||
cd5f04f5 | 383 | // Start of function |
7af964d1 | 384 | .macro DW_START |
cd5f04f5 | 385 | L_dw_start_$0: |
7af964d1 | 386 | .endmacro |
cd5f04f5 A |
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: | |
7af964d1 A |
406 | .endmacro |
407 | ||
cd5f04f5 A |
408 | // After `enter` in SaveRegisters |
409 | .macro DW_ENTER | |
410 | L_dw_enter_$0: | |
7af964d1 A |
411 | .endmacro |
412 | ||
cd5f04f5 A |
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 | |
b3962a83 A |
424 | .endmacro |
425 | ||
426 | ||
427 | ///////////////////////////////////////////////////////////////////// | |
428 | // | |
8972963c | 429 | // SaveRegisters caller |
b3962a83 A |
430 | // |
431 | // Pushes a stack frame and saves all registers that might contain | |
432 | // parameter values. | |
433 | // | |
8972963c A |
434 | // On entry: %0 = caller's symbol name for DWARF |
435 | // stack = ret | |
b3962a83 A |
436 | // |
437 | // On exit: | |
8972963c | 438 | // %rsp is 16-byte aligned |
b3962a83 A |
439 | // |
440 | ///////////////////////////////////////////////////////////////////// | |
7af964d1 | 441 | |
b3962a83 | 442 | .macro SaveRegisters |
cd5f04f5 A |
443 | // These instructions must match the DWARF data in EMIT_FDE. |
444 | ||
8972963c | 445 | enter $$0x80+8, $$0 // +8 for alignment |
cd5f04f5 A |
446 | DW_ENTER $0 |
447 | ||
8972963c A |
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) | |
cd5f04f5 A |
463 | |
464 | // These instructions must match the DWARF data in EMIT_FDE. | |
b3962a83 A |
465 | .endmacro |
466 | ||
467 | ///////////////////////////////////////////////////////////////////// | |
468 | // | |
469 | // RestoreRegisters | |
470 | // | |
471 | // Pops a stack frame pushed by SaveRegisters | |
472 | // | |
8972963c A |
473 | // On entry: $0 = caller's symbol name for DWARF |
474 | // %rbp unchanged since SaveRegisters | |
b3962a83 A |
475 | // |
476 | // On exit: | |
8972963c | 477 | // stack = ret |
b3962a83 A |
478 | // |
479 | ///////////////////////////////////////////////////////////////////// | |
480 | ||
481 | .macro RestoreRegisters | |
cd5f04f5 A |
482 | // These instructions must match the DWARF data in EMIT_FDE. |
483 | ||
8972963c A |
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 | |
cd5f04f5 | 499 | |
8972963c | 500 | leave |
cd5f04f5 A |
501 | DW_LEAVE $0 |
502 | ||
503 | // These instructions must match the DWARF data in EMIT_FDE. | |
b3962a83 A |
504 | .endmacro |
505 | ||
506 | ||
507 | ///////////////////////////////////////////////////////////////////// | |
508 | // | |
509 | // | |
cd5f04f5 | 510 | // CacheLookup return-type, caller |
b3962a83 A |
511 | // |
512 | // Locate the implementation for a selector in a class method cache. | |
513 | // | |
514 | // Takes: | |
8972963c | 515 | // $0 = NORMAL, FPRET, FP2RET, STRET |
cd5f04f5 | 516 | // $1 = caller's symbol name for DWARF |
8972963c | 517 | // a2 or a3 (STRET) = selector |
b3962a83 | 518 | // %r11 = class whose cache is to be searched |
b3962a83 | 519 | // |
8972963c A |
520 | // On exit: (found) method in %r11, stack unchanged, eq/ne set for forwarding |
521 | // (not found) jumps to LCacheMiss, %rax on stack | |
522 | // | |
b3962a83 A |
523 | ///////////////////////////////////////////////////////////////////// |
524 | ||
b3962a83 A |
525 | .macro CacheLookup |
526 | ||
8972963c | 527 | push %rax |
cd5f04f5 A |
528 | DW_PUSH $1 |
529 | ||
8972963c A |
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 | |
b3962a83 A |
536 | |
537 | // search the receiver's cache | |
538 | // r11 = method (soon) | |
8972963c A |
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++ | |
b3962a83 | 546 | testq %r11, %r11 // if (method == NULL) |
8972963c A |
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 | |
b3962a83 A |
554 | |
555 | // cache hit, r11 = method triplet | |
b3962a83 | 556 | // restore saved registers |
8972963c | 557 | pop %rax |
cd5f04f5 | 558 | DW_POP $1 |
8972963c A |
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 | |
b3962a83 | 566 | |
b3962a83 A |
567 | .endmacro |
568 | ||
569 | ||
570 | ///////////////////////////////////////////////////////////////////// | |
571 | // | |
cd5f04f5 | 572 | // MethodTableLookup classRegister, selectorRegister, caller |
b3962a83 | 573 | // |
8972963c A |
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 | |
b3962a83 | 578 | // |
8972963c | 579 | // Stack: ret, rax (pushed by CacheLookup) |
b3962a83 | 580 | // |
8972963c | 581 | // On exit: pops registers pushed by CacheLookup |
b3962a83 A |
582 | // imp in %r11 |
583 | // | |
584 | ///////////////////////////////////////////////////////////////////// | |
585 | .macro MethodTableLookup | |
8972963c A |
586 | |
587 | pop %rax // saved by CacheLookup | |
cd5f04f5 A |
588 | DW_MISS_POP $2 |
589 | ||
8972963c | 590 | SaveRegisters $2 |
b3962a83 | 591 | |
8972963c | 592 | // _class_lookupMethodAndLoadCache3(receiver, selector, class) |
b3962a83 | 593 | |
b3962a83 A |
594 | movq $0, %a1 |
595 | movq $1, %a2 | |
8972963c A |
596 | movq %r11, %a3 |
597 | call __class_lookupMethodAndLoadCache3 | |
b3962a83 A |
598 | |
599 | // IMP is now in %rax | |
600 | movq %rax, %r11 | |
601 | ||
7af964d1 | 602 | RestoreRegisters $2 |
b3962a83 A |
603 | |
604 | .endmacro | |
605 | ||
8972963c A |
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 | ||
b3962a83 A |
726 | |
727 | /******************************************************************** | |
7af964d1 | 728 | * Method _cache_getMethod(Class cls, SEL sel, IMP msgForward_internal_imp) |
b3962a83 A |
729 | * |
730 | * On entry: a1 = class whose cache is to be searched | |
731 | * a2 = selector to search for | |
7af964d1 | 732 | * a3 = _objc_msgForward_internal IMP |
b3962a83 A |
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 | |
7af964d1 A |
738 | * is _objc_msgForward_internal. It returns 1 instead. This prevents thread- |
739 | * thread-safety and memory management bugs in _class_lookupMethodAndLoadCache. | |
b3962a83 A |
740 | * See _class_lookupMethodAndLoadCache for details. |
741 | * | |
7af964d1 A |
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. | |
b3962a83 | 744 | ********************************************************************/ |
8972963c A |
745 | |
746 | STATIC_ENTRY __cache_getMethod | |
7af964d1 | 747 | DW_START __cache_getMethod |
b3962a83 A |
748 | |
749 | // do lookup | |
750 | movq %a1, %r11 // move class to r11 for CacheLookup | |
cd5f04f5 | 751 | CacheLookup NORMAL, __cache_getMethod |
b3962a83 A |
752 | |
753 | // cache hit, method triplet in %r11 | |
8972963c A |
754 | cmpq method_imp(%r11), %a3 // if (imp==_objc_msgForward_internal) |
755 | je 1f // return (Method)1 | |
b3962a83 A |
756 | movq %r11, %rax // return method triplet address |
757 | ret | |
8972963c | 758 | 1: movl $1, %eax |
7af964d1 | 759 | ret |
b3962a83 | 760 | |
8972963c | 761 | LCacheMiss: |
b3962a83 | 762 | // cache miss, return nil |
cd5f04f5 | 763 | DW_MISS __cache_getMethod |
8972963c | 764 | pop %rax // pushed by CacheLookup |
cd5f04f5 | 765 | DW_MISS_POP __cache_getMethod |
8972963c | 766 | xorl %eax, %eax |
b3962a83 A |
767 | ret |
768 | ||
769 | LGetMethodExit: | |
cd5f04f5 | 770 | DW_END __cache_getMethod, 1, 0 |
7af964d1 | 771 | END_ENTRY __cache_getMethod |
b3962a83 A |
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 | ||
8972963c | 784 | STATIC_ENTRY __cache_getImp |
7af964d1 | 785 | DW_START __cache_getImp |
b3962a83 A |
786 | |
787 | // do lookup | |
788 | movq %a1, %r11 // move class to r11 for CacheLookup | |
cd5f04f5 | 789 | CacheLookup NORMAL, __cache_getImp |
b3962a83 A |
790 | |
791 | // cache hit, method triplet in %r11 | |
792 | movq method_imp(%r11), %rax // return method imp address | |
793 | ret | |
794 | ||
8972963c | 795 | LCacheMiss: |
b3962a83 | 796 | // cache miss, return nil |
cd5f04f5 | 797 | DW_MISS __cache_getImp |
8972963c | 798 | pop %rax // pushed by CacheLookup |
cd5f04f5 | 799 | DW_MISS_POP __cache_getImp |
8972963c | 800 | xorl %eax, %eax |
b3962a83 A |
801 | ret |
802 | ||
803 | LGetImpExit: | |
cd5f04f5 | 804 | DW_END __cache_getImp, 1, 0 |
7af964d1 | 805 | END_ENTRY __cache_getImp |
b3962a83 A |
806 | |
807 | ||
808 | /******************************************************************** | |
809 | * | |
810 | * id objc_msgSend(id self, SEL _cmd,...); | |
811 | * | |
812 | ********************************************************************/ | |
813 | ||
8972963c A |
814 | .data |
815 | .align 3 | |
816 | .private_extern __objc_tagged_isa_table | |
817 | __objc_tagged_isa_table: | |
818 | .fill 16, 8, 0 | |
819 | ||
b3962a83 | 820 | ENTRY _objc_msgSend |
7af964d1 | 821 | DW_START _objc_msgSend |
b3962a83 | 822 | |
8972963c | 823 | NilTest NORMAL |
b3962a83 | 824 | |
8972963c | 825 | GetIsaFast NORMAL // r11 = self->isa |
cd5f04f5 | 826 | CacheLookup NORMAL, _objc_msgSend // r11=method, eq set (nonstret fwd) |
8972963c | 827 | jmp *method_imp(%r11) // goto *imp |
b3962a83 | 828 | |
8972963c | 829 | NilTestSupport NORMAL |
b3962a83 | 830 | |
8972963c | 831 | GetIsaSupport NORMAL |
b3962a83 | 832 | |
8972963c A |
833 | // cache miss: go search the method lists |
834 | LCacheMiss: | |
cd5f04f5 | 835 | DW_MISS _objc_msgSend |
8972963c A |
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 | |
b3962a83 | 840 | |
cd5f04f5 | 841 | DW_END _objc_msgSend, 1, 1 |
b3962a83 A |
842 | END_ENTRY _objc_msgSend |
843 | ||
844 | #if __OBJC2__ | |
845 | ENTRY _objc_msgSend_fixup | |
7af964d1 | 846 | DW_START _objc_msgSend_fixup |
b3962a83 | 847 | |
8972963c | 848 | NilTest NORMAL |
7af964d1 | 849 | |
8972963c A |
850 | SaveRegisters _objc_msgSend_fixup |
851 | ||
7af964d1 | 852 | // Dereference obj/isa/cache to crash before _objc_fixupMessageRef |
8972963c A |
853 | movq 8(%a2), %a6 // selector |
854 | GetIsa NORMAL // r11 = isa = *receiver | |
855 | movq cache(%r11), %a5 // cache = *isa | |
7af964d1 A |
856 | movq mask(%a5), %a4 // *cache |
857 | ||
b3962a83 A |
858 | // a1 = receiver |
859 | // a2 = address of message ref | |
860 | movq %a2, %a3 | |
8972963c | 861 | xorl %a2d, %a2d |
b3962a83 A |
862 | // __objc_fixupMessageRef(receiver, 0, ref) |
863 | call __objc_fixupMessageRef | |
864 | movq %rax, %r11 | |
7af964d1 A |
865 | |
866 | RestoreRegisters _objc_msgSend_fixup | |
b3962a83 A |
867 | |
868 | // imp is in r11 | |
869 | // Load _cmd from the message_ref | |
870 | movq 8(%a2), %a2 | |
7af964d1 | 871 | cmp %r11, %r11 // set nonstret (eq) for forwarding |
b3962a83 A |
872 | jmp *%r11 |
873 | ||
8972963c | 874 | NilTestSupport NORMAL |
b3962a83 | 875 | |
cd5f04f5 | 876 | DW_END _objc_msgSend_fixup, 0, 1 |
7af964d1 | 877 | END_ENTRY _objc_msgSend_fixup |
b3962a83 A |
878 | |
879 | ||
8972963c | 880 | STATIC_ENTRY _objc_msgSend_fixedup |
b3962a83 A |
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 | |
7af964d1 | 899 | DW_START _objc_msgSendSuper |
b3962a83 | 900 | |
b3962a83 A |
901 | // search the cache (objc_super in %a1) |
902 | movq class(%a1), %r11 // class = objc_super->class | |
cd5f04f5 | 903 | CacheLookup NORMAL, _objc_msgSendSuper // r11 = method, eq set (nonstret fwd) |
b3962a83 | 904 | movq receiver(%a1), %a1 // load real receiver |
8972963c | 905 | jmp *method_imp(%r11) // goto *imp |
b3962a83 A |
906 | |
907 | // cache miss: go search the method lists | |
8972963c | 908 | LCacheMiss: |
cd5f04f5 | 909 | DW_MISS _objc_msgSendSuper |
8972963c A |
910 | movq receiver(%a1), %r10 |
911 | movq class(%a1), %r11 | |
912 | MethodTableLookup %r10, %a2, _objc_msgSendSuper // r11 = IMP | |
b3962a83 | 913 | movq receiver(%a1), %a1 // load real receiver |
8972963c | 914 | cmp %r11, %r11 // set eq (nonstret) for forwarding |
b3962a83 | 915 | jmp *%r11 // goto *imp |
b3962a83 | 916 | |
cd5f04f5 | 917 | DW_END _objc_msgSendSuper, 1, 1 |
b3962a83 A |
918 | END_ENTRY _objc_msgSendSuper |
919 | ||
8972963c A |
920 | |
921 | /******************************************************************** | |
922 | * id objc_msgSendSuper2 | |
923 | ********************************************************************/ | |
924 | ||
b3962a83 A |
925 | #if __OBJC2__ |
926 | ENTRY _objc_msgSendSuper2_fixup | |
7af964d1 | 927 | DW_START _objc_msgSendSuper2_fixup |
b3962a83 | 928 | |
8972963c | 929 | SaveRegisters _objc_msgSendSuper2_fixup |
b3962a83 A |
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 | |
7af964d1 | 938 | RestoreRegisters _objc_msgSendSuper2_fixup |
b3962a83 A |
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 | |
7af964d1 | 945 | cmp %r11, %r11 // set nonstret (eq) for forwarding |
b3962a83 A |
946 | jmp *%r11 |
947 | ||
cd5f04f5 | 948 | DW_END _objc_msgSendSuper2_fixup, 0, 1 |
7af964d1 | 949 | END_ENTRY _objc_msgSendSuper2_fixup |
b3962a83 A |
950 | |
951 | ||
8972963c | 952 | STATIC_ENTRY _objc_msgSendSuper2_fixedup |
b3962a83 | 953 | movq 8(%a2), %a2 // load _cmd from message_ref |
8972963c | 954 | jmp _objc_msgSendSuper2 |
b3962a83 | 955 | END_ENTRY _objc_msgSendSuper2_fixedup |
7af964d1 A |
956 | |
957 | ||
958 | ENTRY _objc_msgSendSuper2 | |
8972963c | 959 | DW_START _objc_msgSendSuper2 |
7af964d1 | 960 | // objc_super->class is superclass of class to search |
8972963c A |
961 | |
962 | // search the cache (objc_super in %a1) | |
7af964d1 | 963 | movq class(%a1), %r11 // cls = objc_super->class |
8972963c | 964 | movq 8(%r11), %r11 // cls = class->superclass |
cd5f04f5 | 965 | CacheLookup NORMAL, _objc_msgSendSuper2 // r11 = method, eq set (nonstret fwd) |
8972963c A |
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: | |
cd5f04f5 | 971 | DW_MISS _objc_msgSendSuper2 |
8972963c A |
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 | ||
cd5f04f5 | 980 | DW_END _objc_msgSendSuper2, 1, 1 |
8972963c | 981 | END_ENTRY _objc_msgSendSuper2 |
b3962a83 A |
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 | |
7af964d1 | 993 | DW_START _objc_msgSend_fpret |
b3962a83 | 994 | |
8972963c | 995 | NilTest FPRET |
b3962a83 | 996 | |
8972963c | 997 | GetIsaFast FPRET // r11 = self->isa |
cd5f04f5 | 998 | CacheLookup FPRET, _objc_msgSend_fpret // r11 = method, eq set (nonstret fwd) |
8972963c | 999 | jmp *method_imp(%r11) // goto *imp |
b3962a83 | 1000 | |
8972963c | 1001 | NilTestSupport FPRET |
b3962a83 | 1002 | |
8972963c | 1003 | GetIsaSupport FPRET |
b3962a83 | 1004 | |
8972963c A |
1005 | // cache miss: go search the method lists |
1006 | LCacheMiss: | |
cd5f04f5 | 1007 | DW_MISS _objc_msgSend_fpret |
8972963c A |
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 | |
b3962a83 | 1012 | |
cd5f04f5 | 1013 | DW_END _objc_msgSend_fpret, 1, 1 |
b3962a83 A |
1014 | END_ENTRY _objc_msgSend_fpret |
1015 | ||
1016 | #if __OBJC2__ | |
1017 | ENTRY _objc_msgSend_fpret_fixup | |
7af964d1 | 1018 | DW_START _objc_msgSend_fpret_fixup |
b3962a83 | 1019 | |
8972963c | 1020 | NilTest FPRET |
b3962a83 | 1021 | |
8972963c | 1022 | SaveRegisters _objc_msgSend_fpret_fixup |
7af964d1 A |
1023 | |
1024 | // Dereference obj/isa/cache to crash before _objc_fixupMessageRef | |
8972963c A |
1025 | movq 8(%a2), %a6 // selector |
1026 | GetIsa FPRET // r11 = isa = *receiver | |
1027 | movq cache(%r11), %a5 // cache = *isa | |
7af964d1 A |
1028 | movq mask(%a5), %a4 // *cache |
1029 | ||
b3962a83 A |
1030 | // a1 = receiver |
1031 | // a2 = address of message ref | |
1032 | movq %a2, %a3 | |
8972963c | 1033 | xorl %a2d, %a2d |
b3962a83 A |
1034 | // __objc_fixupMessageRef(receiver, 0, ref) |
1035 | call __objc_fixupMessageRef | |
1036 | movq %rax, %r11 | |
7af964d1 A |
1037 | |
1038 | RestoreRegisters _objc_msgSend_fpret_fixup | |
b3962a83 A |
1039 | |
1040 | // imp is in r11 | |
1041 | // Load _cmd from the message_ref | |
1042 | movq 8(%a2), %a2 | |
7af964d1 | 1043 | cmp %r11, %r11 // set nonstret (eq) for forwarding |
b3962a83 A |
1044 | jmp *%r11 |
1045 | ||
8972963c | 1046 | NilTestSupport FPRET |
b3962a83 | 1047 | |
cd5f04f5 | 1048 | DW_END _objc_msgSend_fpret_fixup, 0, 1 |
7af964d1 | 1049 | END_ENTRY _objc_msgSend_fpret_fixup |
b3962a83 A |
1050 | |
1051 | ||
8972963c | 1052 | STATIC_ENTRY _objc_msgSend_fpret_fixedup |
b3962a83 A |
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 | |
7af964d1 | 1068 | DW_START _objc_msgSend_fp2ret |
b3962a83 | 1069 | |
8972963c | 1070 | NilTest FP2RET |
b3962a83 | 1071 | |
8972963c | 1072 | GetIsaFast FP2RET // r11 = self->isa |
cd5f04f5 | 1073 | CacheLookup FP2RET, _objc_msgSend_fp2ret // r11 = method, eq set (nonstret fwd) |
8972963c | 1074 | jmp *method_imp(%r11) // goto *imp |
b3962a83 | 1075 | |
8972963c A |
1076 | NilTestSupport FP2RET |
1077 | ||
1078 | GetIsaSupport FP2RET | |
1079 | ||
b3962a83 | 1080 | // cache miss: go search the method lists |
8972963c | 1081 | LCacheMiss: |
cd5f04f5 | 1082 | DW_MISS _objc_msgSend_fp2ret |
8972963c A |
1083 | GetIsa FP2RET // r11 = self->isa |
1084 | MethodTableLookup %a1, %a2, _objc_msgSend_fp2ret // r11 = IMP | |
1085 | cmp %r11, %r11 // set eq (nonstret) for forwarding | |
b3962a83 A |
1086 | jmp *%r11 // goto *imp |
1087 | ||
cd5f04f5 | 1088 | DW_END _objc_msgSend_fp2ret, 1, 1 |
b3962a83 A |
1089 | END_ENTRY _objc_msgSend_fp2ret |
1090 | ||
1091 | #if __OBJC2__ | |
1092 | ENTRY _objc_msgSend_fp2ret_fixup | |
7af964d1 | 1093 | DW_START _objc_msgSend_fp2ret_fixup |
b3962a83 | 1094 | |
8972963c | 1095 | NilTest FP2RET |
b3962a83 | 1096 | |
8972963c | 1097 | SaveRegisters _objc_msgSend_fp2ret_fixup |
7af964d1 A |
1098 | |
1099 | // Dereference obj/isa/cache to crash before _objc_fixupMessageRef | |
8972963c A |
1100 | movq 8(%a2), %a6 // selector |
1101 | GetIsa FP2RET // r11 = isa = *receiver | |
1102 | movq cache(%r11), %a5 // cache = *isa | |
7af964d1 A |
1103 | movq mask(%a5), %a4 // *cache |
1104 | ||
b3962a83 A |
1105 | // a1 = receiver |
1106 | // a2 = address of message ref | |
1107 | movq %a2, %a3 | |
8972963c | 1108 | xorl %a2d, %a2d |
b3962a83 A |
1109 | // __objc_fixupMessageRef(receiver, 0, ref) |
1110 | call __objc_fixupMessageRef | |
1111 | movq %rax, %r11 | |
7af964d1 A |
1112 | |
1113 | RestoreRegisters _objc_msgSend_fp2ret_fixup | |
b3962a83 A |
1114 | |
1115 | // imp is in r11 | |
1116 | // Load _cmd from the message_ref | |
1117 | movq 8(%a2), %a2 | |
7af964d1 | 1118 | cmp %r11, %r11 // set nonstret (eq) for forwarding |
b3962a83 A |
1119 | jmp *%r11 |
1120 | ||
8972963c | 1121 | NilTestSupport FP2RET |
b3962a83 | 1122 | |
cd5f04f5 | 1123 | DW_END _objc_msgSend_fp2ret_fixup, 0, 1 |
7af964d1 | 1124 | END_ENTRY _objc_msgSend_fp2ret_fixup |
b3962a83 A |
1125 | |
1126 | ||
8972963c | 1127 | STATIC_ENTRY _objc_msgSend_fp2ret_fixedup |
b3962a83 A |
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 | |
7af964d1 | 1149 | DW_START _objc_msgSend_stret |
b3962a83 | 1150 | |
8972963c A |
1151 | NilTest STRET |
1152 | ||
1153 | GetIsaFast STRET // r11 = self->isa | |
cd5f04f5 | 1154 | CacheLookup STRET, _objc_msgSend_stret // r11 = method, ne set (stret fwd) |
8972963c A |
1155 | jmp *method_imp(%r11) // goto *imp |
1156 | ||
1157 | NilTestSupport STRET | |
1158 | ||
1159 | GetIsaSupport STRET | |
b3962a83 A |
1160 | |
1161 | // cache miss: go search the method lists | |
8972963c | 1162 | LCacheMiss: |
cd5f04f5 | 1163 | DW_MISS _objc_msgSend_stret |
8972963c A |
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 | |
7af964d1 | 1167 | jmp *%r11 // goto *imp |
b3962a83 | 1168 | |
cd5f04f5 | 1169 | DW_END _objc_msgSend_stret, 1, 1 |
b3962a83 A |
1170 | END_ENTRY _objc_msgSend_stret |
1171 | ||
1172 | #if __OBJC2__ | |
1173 | ENTRY _objc_msgSend_stret_fixup | |
7af964d1 | 1174 | DW_START _objc_msgSend_stret_fixup |
b3962a83 | 1175 | |
8972963c | 1176 | NilTest STRET |
b3962a83 | 1177 | |
8972963c | 1178 | SaveRegisters _objc_msgSend_stret_fixup |
7af964d1 A |
1179 | |
1180 | // Dereference obj/isa/cache to crash before _objc_fixupMessageRef | |
8972963c A |
1181 | movq 8(%a3), %a6 // selector |
1182 | GetIsa STRET // r11 = isa = *receiver | |
1183 | movq cache(%r11), %a5 // cache = *isa | |
7af964d1 A |
1184 | movq mask(%a5), %a4 // *cache |
1185 | ||
b3962a83 A |
1186 | // a2 = receiver |
1187 | // a3 = address of message ref | |
1188 | movq %a2, %a1 | |
8972963c | 1189 | xorl %a2d, %a2d |
b3962a83 A |
1190 | // __objc_fixupMessageRef(receiver, 0, ref) |
1191 | call __objc_fixupMessageRef | |
1192 | movq %rax, %r11 | |
7af964d1 A |
1193 | |
1194 | RestoreRegisters _objc_msgSend_stret_fixup | |
b3962a83 A |
1195 | |
1196 | // imp is in r11 | |
1197 | // Load _cmd from the message_ref | |
1198 | movq 8(%a3), %a3 | |
7af964d1 A |
1199 | test %r11, %r11 // set stret (ne) for forward; r11!=0 |
1200 | jmp *%r11 // goto *imp | |
b3962a83 | 1201 | |
8972963c | 1202 | NilTestSupport STRET |
b3962a83 | 1203 | |
cd5f04f5 | 1204 | DW_END _objc_msgSend_stret_fixup, 0, 1 |
7af964d1 | 1205 | END_ENTRY _objc_msgSend_stret_fixup |
b3962a83 A |
1206 | |
1207 | ||
8972963c | 1208 | STATIC_ENTRY _objc_msgSend_stret_fixedup |
b3962a83 A |
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 | |
7af964d1 | 1236 | DW_START _objc_msgSendSuper_stret |
b3962a83 A |
1237 | |
1238 | // search the cache (objc_super in %a2) | |
8972963c | 1239 | movq class(%a2), %r11 // class = objc_super->class |
cd5f04f5 | 1240 | CacheLookup STRET, _objc_msgSendSuper_stret // r11 = method, ne set (stret fwd) |
7af964d1 | 1241 | movq receiver(%a2), %a2 // load real receiver |
8972963c | 1242 | jmp *method_imp(%r11) // goto *imp |
b3962a83 A |
1243 | |
1244 | // cache miss: go search the method lists | |
8972963c | 1245 | LCacheMiss: |
cd5f04f5 | 1246 | DW_MISS _objc_msgSendSuper_stret |
8972963c A |
1247 | movq receiver(%a2), %r10 |
1248 | movq class(%a2), %r11 | |
1249 | MethodTableLookup %r10, %a3, _objc_msgSendSuper_stret // r11 = IMP | |
7af964d1 | 1250 | movq receiver(%a2), %a2 // load real receiver |
8972963c | 1251 | test %r11, %r11 // set ne (stret) for forward; r11!=0 |
7af964d1 | 1252 | jmp *%r11 // goto *imp |
b3962a83 | 1253 | |
cd5f04f5 | 1254 | DW_END _objc_msgSendSuper_stret, 1, 1 |
b3962a83 A |
1255 | END_ENTRY _objc_msgSendSuper_stret |
1256 | ||
8972963c A |
1257 | |
1258 | /******************************************************************** | |
1259 | * id objc_msgSendSuper2_stret | |
1260 | ********************************************************************/ | |
1261 | ||
b3962a83 A |
1262 | #if __OBJC2__ |
1263 | ENTRY _objc_msgSendSuper2_stret_fixup | |
7af964d1 | 1264 | DW_START _objc_msgSendSuper2_stret_fixup |
b3962a83 | 1265 | |
8972963c | 1266 | SaveRegisters _objc_msgSendSuper2_stret_fixup |
b3962a83 A |
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 | |
7af964d1 | 1273 | RestoreRegisters _objc_msgSendSuper2_stret_fixup |
b3962a83 A |
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 | |
7af964d1 A |
1280 | test %r11, %r11 // set stret (ne) for forward; r11!=0 |
1281 | jmp *%r11 // goto *imp | |
b3962a83 | 1282 | |
cd5f04f5 | 1283 | DW_END _objc_msgSendSuper2_stret_fixup, 0, 1 |
7af964d1 | 1284 | END_ENTRY _objc_msgSendSuper2_stret_fixup |
b3962a83 A |
1285 | |
1286 | ||
8972963c | 1287 | STATIC_ENTRY _objc_msgSendSuper2_stret_fixedup |
b3962a83 | 1288 | movq 8(%a3), %a3 // load _cmd from message_ref |
8972963c | 1289 | jmp _objc_msgSendSuper2_stret |
b3962a83 | 1290 | END_ENTRY _objc_msgSendSuper2_stret_fixedup |
7af964d1 A |
1291 | |
1292 | ||
8972963c A |
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 | |
cd5f04f5 | 1299 | CacheLookup STRET, _objc_msgSendSuper2_stret // r11 = method, ne set (stret fwd) |
8972963c A |
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: | |
cd5f04f5 | 1305 | DW_MISS _objc_msgSendSuper2_stret |
8972963c A |
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 | ||
cd5f04f5 | 1314 | DW_END _objc_msgSendSuper2_stret, 1, 1 |
8972963c | 1315 | END_ENTRY _objc_msgSendSuper2_stret |
b3962a83 A |
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 | |
cd5f04f5 | 1334 | LUnkSelStr: .ascii "Does not recognize selector %s (while forwarding %s)\0" |
b3962a83 A |
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 | ||
b3962a83 | 1346 | |
8972963c | 1347 | STATIC_ENTRY __objc_msgForward_internal |
7af964d1 A |
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. | |
b3962a83 | 1352 | |
7af964d1 A |
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 | |
b3962a83 A |
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 | |
8972963c | 1394 | // movq %r10, 0+LINK_AREA(%rsp) // static chain pointer == Pascal |
b3962a83 A |
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 | |
8972963c | 1419 | addq $ 8*16 + 6*8 + (4-1)*8, %rsp |
b3962a83 A |
1420 | // Put return address back |
1421 | movq %r11, (%rsp) | |
1422 | ret | |
1423 | ||
1424 | LMsgForwardError: | |
cd5f04f5 | 1425 | // Tail-call __objc_error(receiver, "unknown selector %s %s", "forward::", forwardedSel) |
b3962a83 | 1426 | // %a1 is already the receiver |
cd5f04f5 A |
1427 | movq %a3, %a4 // the forwarded selector |
1428 | leaq LUnkSelStr(%rip), %a2 // "unknown selector %s %s" | |
b3962a83 A |
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 | |
7af964d1 A |
1436 | // Struct-return version |
1437 | ||
b3962a83 A |
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 | |
8972963c | 1469 | // movq %r10, 0+LINK_AREA(%rsp) // static chain pointer == Pascal |
b3962a83 A |
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 | |
8972963c | 1494 | addq $ 8*16 + 6*8 + (4-1)*8, %rsp |
b3962a83 A |
1495 | // Put return address back |
1496 | movq %r11, (%rsp) | |
1497 | ret | |
1498 | ||
1499 | LMsgForwardStretError: | |
cd5f04f5 A |
1500 | // Tail-call __objc_error(receiver, "unknown selector %s %s", "forward::", forwardedSel) |
1501 | // %a4 is already the forwarded selector | |
b3962a83 | 1502 | movq %a2, %a1 // receiver |
cd5f04f5 | 1503 | leaq LUnkSelStr(%rip), %a2 // "unknown selector %s %s" |
b3962a83 A |
1504 | movq _FwdSel(%rip), %a3 // forward:: |
1505 | jmp ___objc_error // never returns | |
1506 | ||
1507 | END_ENTRY __objc_msgForward_stret | |
1508 | ||
1509 | ||
8972963c A |
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 | ||
b3962a83 A |
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 | |
7af964d1 | 1556 | |
8972963c A |
1557 | |
1558 | STATIC_ENTRY __objc_ignored_method | |
1559 | ||
1560 | movq %a1, %rax | |
1561 | ret | |
1562 | ||
1563 | END_ENTRY __objc_ignored_method | |
1564 | ||
7af964d1 A |
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. | |
8972963c A |
1573 | * The instructions following LvtableTagTable are modified to |
1574 | * load the tagged isa table. | |
7af964d1 A |
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. | |
8972963c A |
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 | |
7af964d1 A |
1586 | * |
1587 | ********************************************************************/ | |
1588 | ||
1589 | .macro VTABLE /* byte-offset, name */ | |
1590 | ||
8972963c | 1591 | .align 6 |
7af964d1 A |
1592 | .private_extern _$1 |
1593 | _$1: | |
1594 | test %a1, %a1 | |
8972963c A |
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 | |
7af964d1 | 1602 | LvtableIndex_$1: |
8972963c A |
1603 | jmpq * $0 (%rax) // load imp (DO NOT CHANGE) |
1604 | ||
7af964d1 A |
1605 | LvtableReturnZero_$1: |
1606 | // integer registers only; not used for fpret / stret / etc | |
8972963c A |
1607 | xorl %eax, %eax |
1608 | // xorl %edx, %edx (see ABI WARNING) | |
7af964d1 | 1609 | ret |
8972963c | 1610 | |
7af964d1 | 1611 | nop |
8972963c A |
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: | |
7af964d1 A |
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 | ||
8972963c A |
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 | |
7af964d1 A |
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 | ||
8972963c | 1666 | STATIC_ENTRY _vtable_ignored |
7af964d1 A |
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 |