]>
Commit | Line | Data |
---|---|---|
8070259c 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 | */ | |
23 | ||
24 | #include <TargetConditionals.h> | |
25 | #if __x86_64__ && TARGET_IPHONE_SIMULATOR | |
26 | ||
27 | /******************************************************************** | |
28 | ******************************************************************** | |
29 | ** | |
30 | ** objc-msg-x86_64.s - x86-64 code to support objc messaging. | |
31 | ** | |
32 | ******************************************************************** | |
33 | ********************************************************************/ | |
34 | ||
35 | .data | |
36 | ||
37 | // _objc_entryPoints and _objc_exitPoints are used by objc | |
38 | // to get the critical regions for which method caches | |
39 | // cannot be garbage collected. | |
40 | ||
41 | .private_extern _objc_entryPoints | |
42 | _objc_entryPoints: | |
43 | .quad _cache_getImp | |
44 | .quad _objc_msgSend | |
45 | .quad _objc_msgSend_fpret | |
46 | .quad _objc_msgSend_fp2ret | |
47 | .quad _objc_msgSend_stret | |
48 | .quad _objc_msgSendSuper | |
49 | .quad _objc_msgSendSuper_stret | |
50 | .quad _objc_msgSendSuper2 | |
51 | .quad _objc_msgSendSuper2_stret | |
52 | .quad 0 | |
53 | ||
54 | .private_extern _objc_exitPoints | |
55 | _objc_exitPoints: | |
56 | .quad LExit_cache_getImp | |
57 | .quad LExit_objc_msgSend | |
58 | .quad LExit_objc_msgSend_fpret | |
59 | .quad LExit_objc_msgSend_fp2ret | |
60 | .quad LExit_objc_msgSend_stret | |
61 | .quad LExit_objc_msgSendSuper | |
62 | .quad LExit_objc_msgSendSuper_stret | |
63 | .quad LExit_objc_msgSendSuper2 | |
64 | .quad LExit_objc_msgSendSuper2_stret | |
65 | .quad 0 | |
66 | ||
67 | ||
68 | /******************************************************************** | |
69 | * List every exit insn from every messenger for debugger use. | |
70 | * Format: | |
71 | * ( | |
72 | * 1 word instruction's address | |
73 | * 1 word type (ENTER or FAST_EXIT or SLOW_EXIT or NIL_EXIT) | |
74 | * ) | |
75 | * 1 word zero | |
76 | * | |
77 | * ENTER is the start of a dispatcher | |
78 | * FAST_EXIT is method dispatch | |
79 | * SLOW_EXIT is uncached method lookup | |
80 | * NIL_EXIT is returning zero from a message sent to nil | |
81 | * These must match objc-gdb.h. | |
82 | ********************************************************************/ | |
83 | ||
84 | #define ENTER 1 | |
85 | #define FAST_EXIT 2 | |
86 | #define SLOW_EXIT 3 | |
87 | #define NIL_EXIT 4 | |
88 | ||
89 | .section __DATA,__objc_msg_break | |
90 | .globl _gdb_objc_messenger_breakpoints | |
91 | _gdb_objc_messenger_breakpoints: | |
92 | // contents populated by the macros below | |
93 | ||
94 | .macro MESSENGER_START | |
95 | 4: | |
96 | .section __DATA,__objc_msg_break | |
97 | .quad 4b | |
98 | .quad ENTER | |
99 | .text | |
100 | .endmacro | |
101 | .macro MESSENGER_END_FAST | |
102 | 4: | |
103 | .section __DATA,__objc_msg_break | |
104 | .quad 4b | |
105 | .quad FAST_EXIT | |
106 | .text | |
107 | .endmacro | |
108 | .macro MESSENGER_END_SLOW | |
109 | 4: | |
110 | .section __DATA,__objc_msg_break | |
111 | .quad 4b | |
112 | .quad SLOW_EXIT | |
113 | .text | |
114 | .endmacro | |
115 | .macro MESSENGER_END_NIL | |
116 | 4: | |
117 | .section __DATA,__objc_msg_break | |
118 | .quad 4b | |
119 | .quad NIL_EXIT | |
120 | .text | |
121 | .endmacro | |
122 | ||
123 | ||
124 | /******************************************************************** | |
125 | * Recommended multi-byte NOP instructions | |
126 | * (Intel 64 and IA-32 Architectures Software Developer's Manual Volume 2B) | |
127 | ********************************************************************/ | |
128 | #define nop1 .byte 0x90 | |
129 | #define nop2 .byte 0x66,0x90 | |
130 | #define nop3 .byte 0x0F,0x1F,0x00 | |
131 | #define nop4 .byte 0x0F,0x1F,0x40,0x00 | |
132 | #define nop5 .byte 0x0F,0x1F,0x44,0x00,0x00 | |
133 | #define nop6 .byte 0x66,0x0F,0x1F,0x44,0x00,0x00 | |
134 | #define nop7 .byte 0x0F,0x1F,0x80,0x00,0x00,0x00,0x00 | |
135 | #define nop8 .byte 0x0F,0x1F,0x84,0x00,0x00,0x00,0x00,0x00 | |
136 | #define nop9 .byte 0x66,0x0F,0x1F,0x84,0x00,0x00,0x00,0x00,0x00 | |
137 | ||
138 | ||
139 | /******************************************************************** | |
140 | * Names for parameter registers. | |
141 | ********************************************************************/ | |
142 | ||
143 | #define a1 rdi | |
144 | #define a1d edi | |
145 | #define a1b dil | |
146 | #define a2 rsi | |
147 | #define a2d esi | |
148 | #define a2b sil | |
149 | #define a3 rdx | |
150 | #define a3d edx | |
151 | #define a4 rcx | |
152 | #define a4d ecx | |
153 | #define a5 r8 | |
154 | #define a5d r8d | |
155 | #define a6 r9 | |
156 | #define a6d r9d | |
157 | ||
158 | ||
159 | /******************************************************************** | |
160 | * Names for relative labels | |
161 | * DO NOT USE THESE LABELS ELSEWHERE | |
162 | * Reserved labels: 6: 7: 8: 9: | |
163 | ********************************************************************/ | |
164 | #define LCacheMiss 6 | |
165 | #define LCacheMiss_f 6f | |
166 | #define LCacheMiss_b 6b | |
167 | #define LGetIsaDone 7 | |
168 | #define LGetIsaDone_f 7f | |
169 | #define LGetIsaDone_b 7b | |
170 | #define LNilOrTagged 8 | |
171 | #define LNilOrTagged_f 8f | |
172 | #define LNilOrTagged_b 8b | |
173 | #define LNil 9 | |
174 | #define LNil_f 9f | |
175 | #define LNil_b 9b | |
176 | ||
177 | /******************************************************************** | |
178 | * Macro parameters | |
179 | ********************************************************************/ | |
180 | ||
181 | #define NORMAL 0 | |
182 | #define FPRET 1 | |
183 | #define FP2RET 2 | |
184 | #define GETIMP 3 | |
185 | #define STRET 4 | |
186 | #define SUPER 5 | |
187 | #define SUPER_STRET 6 | |
188 | #define SUPER2 7 | |
189 | #define SUPER2_STRET 8 | |
190 | ||
191 | ||
192 | /******************************************************************** | |
193 | * | |
194 | * Structure definitions. | |
195 | * | |
196 | ********************************************************************/ | |
197 | ||
198 | // objc_super parameter to sendSuper | |
199 | #define receiver 0 | |
200 | #define class 8 | |
201 | ||
202 | // Selected field offsets in class structure | |
203 | // #define isa 0 USE GetIsa INSTEAD | |
204 | ||
205 | // Method descriptor | |
206 | #define method_name 0 | |
207 | #define method_imp 16 | |
208 | ||
209 | ||
210 | ////////////////////////////////////////////////////////////////////// | |
211 | // | |
212 | // ENTRY functionName | |
213 | // | |
214 | // Assembly directives to begin an exported function. | |
215 | // | |
216 | // Takes: functionName - name of the exported function | |
217 | ////////////////////////////////////////////////////////////////////// | |
218 | ||
219 | .macro ENTRY | |
220 | .text | |
221 | .globl $0 | |
222 | .align 6, 0x90 | |
223 | $0: | |
224 | .cfi_startproc | |
225 | .endmacro | |
226 | ||
227 | .macro STATIC_ENTRY | |
228 | .text | |
229 | .private_extern $0 | |
230 | .align 2, 0x90 | |
231 | $0: | |
232 | .cfi_startproc | |
233 | .endmacro | |
234 | ||
235 | ////////////////////////////////////////////////////////////////////// | |
236 | // | |
237 | // END_ENTRY functionName | |
238 | // | |
239 | // Assembly directives to end an exported function. Just a placeholder, | |
240 | // a close-parenthesis for ENTRY, until it is needed for something. | |
241 | // | |
242 | // Takes: functionName - name of the exported function | |
243 | ////////////////////////////////////////////////////////////////////// | |
244 | ||
245 | .macro END_ENTRY | |
246 | .cfi_endproc | |
247 | LExit$0: | |
248 | .endmacro | |
249 | ||
250 | ||
251 | ///////////////////////////////////////////////////////////////////// | |
252 | // | |
253 | // SaveRegisters | |
254 | // | |
255 | // Pushes a stack frame and saves all registers that might contain | |
256 | // parameter values. | |
257 | // | |
258 | // On entry: | |
259 | // stack = ret | |
260 | // | |
261 | // On exit: | |
262 | // %rsp is 16-byte aligned | |
263 | // | |
264 | ///////////////////////////////////////////////////////////////////// | |
265 | ||
266 | .macro SaveRegisters | |
267 | ||
268 | push %rbp | |
269 | .cfi_def_cfa_offset 16 | |
270 | .cfi_offset rbp, -16 | |
271 | ||
272 | mov %rsp, %rbp | |
273 | .cfi_def_cfa_register rbp | |
274 | ||
275 | sub $$0x80+8, %rsp // +8 for alignment | |
276 | ||
277 | movdqa %xmm0, -0x80(%rbp) | |
278 | push %rax // might be xmm parameter count | |
279 | movdqa %xmm1, -0x70(%rbp) | |
280 | push %a1 | |
281 | movdqa %xmm2, -0x60(%rbp) | |
282 | push %a2 | |
283 | movdqa %xmm3, -0x50(%rbp) | |
284 | push %a3 | |
285 | movdqa %xmm4, -0x40(%rbp) | |
286 | push %a4 | |
287 | movdqa %xmm5, -0x30(%rbp) | |
288 | push %a5 | |
289 | movdqa %xmm6, -0x20(%rbp) | |
290 | push %a6 | |
291 | movdqa %xmm7, -0x10(%rbp) | |
292 | ||
293 | .endmacro | |
294 | ||
295 | ///////////////////////////////////////////////////////////////////// | |
296 | // | |
297 | // RestoreRegisters | |
298 | // | |
299 | // Pops a stack frame pushed by SaveRegisters | |
300 | // | |
301 | // On entry: | |
302 | // %rbp unchanged since SaveRegisters | |
303 | // | |
304 | // On exit: | |
305 | // stack = ret | |
306 | // | |
307 | ///////////////////////////////////////////////////////////////////// | |
308 | ||
309 | .macro RestoreRegisters | |
310 | ||
311 | movdqa -0x80(%rbp), %xmm0 | |
312 | pop %a6 | |
313 | movdqa -0x70(%rbp), %xmm1 | |
314 | pop %a5 | |
315 | movdqa -0x60(%rbp), %xmm2 | |
316 | pop %a4 | |
317 | movdqa -0x50(%rbp), %xmm3 | |
318 | pop %a3 | |
319 | movdqa -0x40(%rbp), %xmm4 | |
320 | pop %a2 | |
321 | movdqa -0x30(%rbp), %xmm5 | |
322 | pop %a1 | |
323 | movdqa -0x20(%rbp), %xmm6 | |
324 | pop %rax | |
325 | movdqa -0x10(%rbp), %xmm7 | |
326 | ||
327 | leave | |
328 | .cfi_def_cfa rsp, 8 | |
329 | .cfi_same_value rbp | |
330 | ||
331 | .endmacro | |
332 | ||
333 | ||
334 | ///////////////////////////////////////////////////////////////////// | |
335 | // | |
336 | // CacheLookup return-type, caller | |
337 | // | |
338 | // Locate the implementation for a class in a selector's method cache. | |
339 | // | |
340 | // Takes: | |
341 | // $0 = NORMAL, FPRET, FP2RET, STRET, SUPER, SUPER_STRET, SUPER2, SUPER2_STRET, GETIMP | |
342 | // a2 or a3 (STRET) = selector a.k.a. cache | |
343 | // r11 = class to search | |
344 | // | |
345 | // On exit: r10 clobbered | |
346 | // (found) calls or returns IMP, eq/ne/r11 set for forwarding | |
347 | // (not found) jumps to LCacheMiss, class still in r11 | |
348 | // | |
349 | ///////////////////////////////////////////////////////////////////// | |
350 | ||
351 | .macro CacheHit | |
352 | ||
353 | // CacheHit must always be preceded by a not-taken `jne` instruction | |
354 | // in order to set the correct flags for _objc_msgForward_impcache. | |
355 | ||
356 | // r10 = found bucket | |
357 | ||
358 | .if $0 == GETIMP | |
359 | movq 8(%r10), %rax // return imp | |
360 | leaq __objc_msgSend_uncached_impcache(%rip), %r11 | |
361 | cmpq %rax, %r11 | |
362 | jne 4f | |
363 | xorl %eax, %eax // don't return msgSend_uncached | |
364 | 4: ret | |
365 | .elseif $0 == NORMAL || $0 == FPRET || $0 == FP2RET | |
366 | // eq already set for forwarding by `jne` | |
367 | MESSENGER_END_FAST | |
368 | jmp *8(%r10) // call imp | |
369 | ||
370 | .elseif $0 == SUPER | |
371 | movq receiver(%a1), %a1 // load real receiver | |
372 | cmp %r10, %r10 // set eq for non-stret forwarding | |
373 | MESSENGER_END_FAST | |
374 | jmp *8(%r10) // call imp | |
375 | ||
376 | .elseif $0 == SUPER2 | |
377 | movq receiver(%a1), %a1 // load real receiver | |
378 | cmp %r10, %r10 // set eq for non-stret forwarding | |
379 | MESSENGER_END_FAST | |
380 | jmp *8(%r10) // call imp | |
381 | ||
382 | .elseif $0 == STRET | |
383 | test %r10, %r10 // set ne for stret forwarding | |
384 | MESSENGER_END_FAST | |
385 | jmp *8(%r10) // call imp | |
386 | ||
387 | .elseif $0 == SUPER_STRET | |
388 | movq receiver(%a2), %a2 // load real receiver | |
389 | test %r10, %r10 // set ne for stret forwarding | |
390 | MESSENGER_END_FAST | |
391 | jmp *8(%r10) // call imp | |
392 | ||
393 | .elseif $0 == SUPER2_STRET | |
394 | movq receiver(%a2), %a2 // load real receiver | |
395 | test %r10, %r10 // set ne for stret forwarding | |
396 | MESSENGER_END_FAST | |
397 | jmp *8(%r10) // call imp | |
398 | .else | |
399 | .abort oops | |
400 | .endif | |
401 | ||
402 | .endmacro | |
403 | ||
404 | ||
405 | .macro CacheLookup | |
406 | .if $0 != STRET && $0 != SUPER_STRET && $0 != SUPER2_STRET | |
407 | movq %a2, %r10 // r10 = _cmd | |
408 | .else | |
409 | movq %a3, %r10 // r10 = _cmd | |
410 | .endif | |
411 | andl 24(%r11), %r10d // r10 = _cmd & class->cache.mask | |
412 | shlq $$4, %r10 // r10 = offset = (_cmd & mask)<<4 | |
413 | addq 16(%r11), %r10 // r10 = class->cache.buckets + offset | |
414 | ||
415 | .if $0 != STRET && $0 != SUPER_STRET && $0 != SUPER2_STRET | |
416 | cmpq (%r10), %a2 // if (bucket->sel != _cmd) | |
417 | .else | |
418 | cmpq (%r10), %a3 // if (bucket->sel != _cmd) | |
419 | .endif | |
420 | jne 1f // scan more | |
421 | // CacheHit must always be preceded by a not-taken `jne` instruction | |
422 | CacheHit $0 // call or return imp | |
423 | ||
424 | 1: | |
425 | // loop | |
426 | cmpq $$0, (%r10) | |
427 | je LCacheMiss_f // if (bucket->sel == 0) cache miss | |
428 | cmpq 16(%r11), %r10 | |
429 | je 3f // if (bucket == cache->buckets) wrap | |
430 | ||
431 | subq $$16, %r10 // bucket-- | |
432 | 2: | |
433 | .if $0 != STRET && $0 != SUPER_STRET && $0 != SUPER2_STRET | |
434 | cmpq (%r10), %a2 // if (bucket->sel != _cmd) | |
435 | .else | |
436 | cmpq (%r10), %a3 // if (bucket->sel != _cmd) | |
437 | .endif | |
438 | jne 1b // scan more | |
439 | // CacheHit must always be preceded by a not-taken `jne` instruction | |
440 | CacheHit $0 // call or return imp | |
441 | ||
442 | 3: | |
443 | // wrap | |
444 | movl 24(%r11), %r10d // r10 = mask a.k.a. last bucket index | |
445 | shlq $$4, %r10 // r10 = offset = mask<<4 | |
446 | addq 16(%r11), %r10 // r10 = &cache->buckets[mask] | |
447 | jmp 2f | |
448 | ||
449 | // clone scanning loop to crash instead of hang when cache is corrupt | |
450 | ||
451 | 1: | |
452 | // loop | |
453 | cmpq $$0, (%r10) | |
454 | je LCacheMiss_f // if (bucket->sel == 0) cache miss | |
455 | cmpq 16(%r11), %r10 | |
456 | je 3f // if (bucket == cache->buckets) wrap | |
457 | ||
458 | subq $$16, %r10 // bucket-- | |
459 | 2: | |
460 | .if $0 != STRET && $0 != SUPER_STRET && $0 != SUPER2_STRET | |
461 | cmpq (%r10), %a2 // if (bucket->sel != _cmd) | |
462 | .else | |
463 | cmpq (%r10), %a3 // if (bucket->sel != _cmd) | |
464 | .endif | |
465 | jne 1b // scan more | |
466 | // CacheHit must always be preceded by a not-taken `jne` instruction | |
467 | CacheHit $0 // call or return imp | |
468 | ||
469 | 3: | |
470 | // double wrap - busted | |
471 | .if $0 == STRET || $0 == SUPER_STRET || $0 == SUPER2_STRET | |
472 | movq %a2, %a1 | |
473 | movq %a3, %a2 | |
474 | .elseif $0 == GETIMP | |
475 | movq $$0, %a1 | |
476 | .endif | |
477 | // a1 = receiver | |
478 | // a2 = SEL | |
479 | movq %r11, %a3 // a3 = isa | |
480 | .if $0 == GETIMP | |
481 | jmp _cache_getImp_corrupt_cache_error | |
482 | .else | |
483 | jmp _objc_msgSend_corrupt_cache_error | |
484 | .endif | |
485 | ||
486 | .endmacro | |
487 | ||
488 | ||
489 | ///////////////////////////////////////////////////////////////////// | |
490 | // | |
491 | // MethodTableLookup classRegister, selectorRegister | |
492 | // | |
493 | // Takes: $0 = class to search (a1 or a2 or r10 ONLY) | |
494 | // $1 = selector to search for (a2 or a3 ONLY) | |
495 | // r11 = class to search | |
496 | // | |
497 | // On exit: imp in %r11 | |
498 | // | |
499 | ///////////////////////////////////////////////////////////////////// | |
500 | .macro MethodTableLookup | |
501 | ||
502 | MESSENGER_END_SLOW | |
503 | ||
504 | SaveRegisters | |
505 | ||
506 | // _class_lookupMethodAndLoadCache3(receiver, selector, class) | |
507 | ||
508 | movq $0, %a1 | |
509 | movq $1, %a2 | |
510 | movq %r11, %a3 | |
511 | call __class_lookupMethodAndLoadCache3 | |
512 | ||
513 | // IMP is now in %rax | |
514 | movq %rax, %r11 | |
515 | ||
516 | RestoreRegisters | |
517 | ||
518 | .endmacro | |
519 | ||
520 | ||
521 | ///////////////////////////////////////////////////////////////////// | |
522 | // | |
523 | // GetIsaCheckNil return-type | |
524 | // GetIsaSupport return-type | |
525 | // | |
526 | // Sets r11 = receiver->isa. | |
527 | // Looks up the real class if receiver is a tagged pointer object. | |
528 | // Returns zero if obj is nil. | |
529 | // | |
530 | // Takes: $0 = NORMAL or FPRET or FP2RET or STRET | |
531 | // a1 or a2 (STRET) = receiver | |
532 | // | |
533 | // On exit: r11 = receiver->isa | |
534 | // r10 is clobbered | |
535 | // | |
536 | ///////////////////////////////////////////////////////////////////// | |
537 | ||
538 | .macro GetIsaCheckNil | |
539 | .if $0 == SUPER || $0 == SUPER_STRET | |
540 | error super dispatch does not test for nil | |
541 | .endif | |
542 | ||
543 | .if $0 != STRET | |
544 | testq %a1, %a1 | |
545 | .else | |
546 | testq %a2, %a2 | |
547 | .endif | |
548 | jle LNilOrTagged_f // MSB tagged pointer looks negative | |
549 | ||
550 | .if $0 != STRET | |
551 | movq (%a1), %r11 // r11 = isa | |
552 | .else | |
553 | movq (%a2), %r11 // r11 = isa | |
554 | .endif | |
555 | ||
556 | LGetIsaDone: | |
557 | .endmacro | |
558 | ||
559 | ||
560 | .macro GetIsaSupport | |
561 | .align 3 | |
562 | LNilOrTagged: | |
563 | jz LNil_f // flags set by NilOrTaggedTest | |
564 | ||
565 | // tagged | |
566 | ||
567 | leaq _objc_debug_taggedpointer_classes(%rip), %r11 | |
568 | .if $0 != STRET | |
569 | movq %a1, %r10 | |
570 | .else | |
571 | movq %a2, %r10 | |
572 | .endif | |
573 | shrq $$60, %r10 | |
574 | movq (%r11, %r10, 8), %r11 // read isa from table | |
575 | jmp LGetIsaDone_b | |
576 | ||
577 | LNil: | |
578 | // nil | |
579 | ||
580 | .if $0 == FPRET | |
581 | fldz | |
582 | .elseif $0 == FP2RET | |
583 | fldz | |
584 | fldz | |
585 | .endif | |
586 | .if $0 == STRET | |
587 | movq %rdi, %rax | |
588 | .else | |
589 | xorl %eax, %eax | |
590 | xorl %edx, %edx | |
591 | xorps %xmm0, %xmm0 | |
592 | xorps %xmm1, %xmm1 | |
593 | .endif | |
594 | MESSENGER_END_NIL | |
595 | ret | |
596 | .endmacro | |
597 | ||
598 | ||
599 | /******************************************************************** | |
600 | * IMP cache_getImp(Class cls, SEL sel) | |
601 | * | |
602 | * On entry: a1 = class whose cache is to be searched | |
603 | * a2 = selector to search for | |
604 | * | |
605 | * If found, returns method implementation. | |
606 | * If not found, returns NULL. | |
607 | ********************************************************************/ | |
608 | ||
609 | STATIC_ENTRY _cache_getImp | |
610 | ||
611 | // do lookup | |
612 | movq %a1, %r11 // move class to r11 for CacheLookup | |
613 | CacheLookup GETIMP // returns IMP on success | |
614 | ||
615 | LCacheMiss: | |
616 | // cache miss, return nil | |
617 | xorl %eax, %eax | |
618 | ret | |
619 | ||
620 | LGetImpExit: | |
621 | END_ENTRY _cache_getImp | |
622 | ||
623 | ||
624 | /******************************************************************** | |
625 | * | |
626 | * id objc_msgSend(id self, SEL _cmd,...); | |
627 | * | |
628 | ********************************************************************/ | |
629 | ||
630 | .data | |
631 | .align 3 | |
632 | .globl _objc_debug_taggedpointer_classes | |
633 | _objc_debug_taggedpointer_classes: | |
634 | .fill 16, 8, 0 | |
635 | ||
636 | ENTRY _objc_msgSend | |
637 | MESSENGER_START | |
638 | ||
639 | GetIsaCheckNil NORMAL // r11 = self->isa, or return zero | |
640 | CacheLookup NORMAL // calls IMP on success | |
641 | ||
642 | GetIsaSupport NORMAL | |
643 | ||
644 | // cache miss: go search the method lists | |
645 | LCacheMiss: | |
646 | // isa still in r11 | |
647 | MethodTableLookup %a1, %a2 // r11 = IMP | |
648 | cmp %r11, %r11 // set eq (nonstret) for forwarding | |
649 | jmp *%r11 // goto *imp | |
650 | ||
651 | END_ENTRY _objc_msgSend | |
652 | ||
653 | ||
654 | ENTRY _objc_msgSend_fixup | |
655 | int3 | |
656 | END_ENTRY _objc_msgSend_fixup | |
657 | ||
658 | ||
659 | STATIC_ENTRY _objc_msgSend_fixedup | |
660 | // Load _cmd from the message_ref | |
661 | movq 8(%a2), %a2 | |
662 | jmp _objc_msgSend | |
663 | END_ENTRY _objc_msgSend_fixedup | |
664 | ||
665 | ||
666 | /******************************************************************** | |
667 | * | |
668 | * id objc_msgSendSuper(struct objc_super *super, SEL _cmd,...); | |
669 | * | |
670 | * struct objc_super { | |
671 | * id receiver; | |
672 | * Class class; | |
673 | * }; | |
674 | ********************************************************************/ | |
675 | ||
676 | ENTRY _objc_msgSendSuper | |
677 | MESSENGER_START | |
678 | ||
679 | // search the cache (objc_super in %a1) | |
680 | movq class(%a1), %r11 // class = objc_super->class | |
681 | CacheLookup SUPER // calls IMP on success | |
682 | ||
683 | // cache miss: go search the method lists | |
684 | LCacheMiss: | |
685 | // class still in r11 | |
686 | movq receiver(%a1), %r10 | |
687 | MethodTableLookup %r10, %a2 // r11 = IMP | |
688 | movq receiver(%a1), %a1 // load real receiver | |
689 | cmp %r11, %r11 // set eq (nonstret) for forwarding | |
690 | jmp *%r11 // goto *imp | |
691 | ||
692 | END_ENTRY _objc_msgSendSuper | |
693 | ||
694 | ||
695 | /******************************************************************** | |
696 | * id objc_msgSendSuper2 | |
697 | ********************************************************************/ | |
698 | ||
699 | ENTRY _objc_msgSendSuper2 | |
700 | MESSENGER_START | |
701 | ||
702 | // objc_super->class is superclass of class to search | |
703 | ||
704 | // search the cache (objc_super in %a1) | |
705 | movq class(%a1), %r11 // cls = objc_super->class | |
706 | movq 8(%r11), %r11 // cls = class->superclass | |
707 | CacheLookup SUPER2 // calls IMP on success | |
708 | ||
709 | // cache miss: go search the method lists | |
710 | LCacheMiss: | |
711 | // superclass still in r11 | |
712 | movq receiver(%a1), %r10 | |
713 | MethodTableLookup %r10, %a2 // r11 = IMP | |
714 | movq receiver(%a1), %a1 // load real receiver | |
715 | cmp %r11, %r11 // set eq (nonstret) for forwarding | |
716 | jmp *%r11 // goto *imp | |
717 | ||
718 | END_ENTRY _objc_msgSendSuper2 | |
719 | ||
720 | ||
721 | ENTRY _objc_msgSendSuper2_fixup | |
722 | int3 | |
723 | END_ENTRY _objc_msgSendSuper2_fixup | |
724 | ||
725 | ||
726 | STATIC_ENTRY _objc_msgSendSuper2_fixedup | |
727 | // Load _cmd from the message_ref | |
728 | movq 8(%a2), %a2 | |
729 | jmp _objc_msgSendSuper2 | |
730 | END_ENTRY _objc_msgSendSuper2_fixedup | |
731 | ||
732 | ||
733 | /******************************************************************** | |
734 | * | |
735 | * double objc_msgSend_fpret(id self, SEL _cmd,...); | |
736 | * Used for `long double` return only. `float` and `double` use objc_msgSend. | |
737 | * | |
738 | ********************************************************************/ | |
739 | ||
740 | ENTRY _objc_msgSend_fpret | |
741 | MESSENGER_START | |
742 | ||
743 | GetIsaCheckNil FPRET // r11 = self->isa, or return zero | |
744 | CacheLookup FPRET // calls IMP on success | |
745 | ||
746 | GetIsaSupport FPRET | |
747 | ||
748 | // cache miss: go search the method lists | |
749 | LCacheMiss: | |
750 | // isa still in r11 | |
751 | MethodTableLookup %a1, %a2 // r11 = IMP | |
752 | cmp %r11, %r11 // set eq (nonstret) for forwarding | |
753 | jmp *%r11 // goto *imp | |
754 | ||
755 | END_ENTRY _objc_msgSend_fpret | |
756 | ||
757 | ||
758 | ENTRY _objc_msgSend_fpret_fixup | |
759 | int3 | |
760 | END_ENTRY _objc_msgSend_fpret_fixup | |
761 | ||
762 | ||
763 | STATIC_ENTRY _objc_msgSend_fpret_fixedup | |
764 | // Load _cmd from the message_ref | |
765 | movq 8(%a2), %a2 | |
766 | jmp _objc_msgSend_fpret | |
767 | END_ENTRY _objc_msgSend_fpret_fixedup | |
768 | ||
769 | ||
770 | /******************************************************************** | |
771 | * | |
772 | * double objc_msgSend_fp2ret(id self, SEL _cmd,...); | |
773 | * Used for `complex long double` return only. | |
774 | * | |
775 | ********************************************************************/ | |
776 | ||
777 | ENTRY _objc_msgSend_fp2ret | |
778 | MESSENGER_START | |
779 | ||
780 | GetIsaCheckNil FP2RET // r11 = self->isa, or return zero | |
781 | CacheLookup FP2RET // calls IMP on success | |
782 | ||
783 | GetIsaSupport FP2RET | |
784 | ||
785 | // cache miss: go search the method lists | |
786 | LCacheMiss: | |
787 | // isa still in r11 | |
788 | MethodTableLookup %a1, %a2 // r11 = IMP | |
789 | cmp %r11, %r11 // set eq (nonstret) for forwarding | |
790 | jmp *%r11 // goto *imp | |
791 | ||
792 | END_ENTRY _objc_msgSend_fp2ret | |
793 | ||
794 | ||
795 | ENTRY _objc_msgSend_fp2ret_fixup | |
796 | int3 | |
797 | END_ENTRY _objc_msgSend_fp2ret_fixup | |
798 | ||
799 | ||
800 | STATIC_ENTRY _objc_msgSend_fp2ret_fixedup | |
801 | // Load _cmd from the message_ref | |
802 | movq 8(%a2), %a2 | |
803 | jmp _objc_msgSend_fp2ret | |
804 | END_ENTRY _objc_msgSend_fp2ret_fixedup | |
805 | ||
806 | ||
807 | /******************************************************************** | |
808 | * | |
809 | * void objc_msgSend_stret(void *st_addr, id self, SEL _cmd, ...); | |
810 | * | |
811 | * objc_msgSend_stret is the struct-return form of msgSend. | |
812 | * The ABI calls for %a1 to be used as the address of the structure | |
813 | * being returned, with the parameters in the succeeding locations. | |
814 | * | |
815 | * On entry: %a1 is the address where the structure is returned, | |
816 | * %a2 is the message receiver, | |
817 | * %a3 is the selector | |
818 | ********************************************************************/ | |
819 | ||
820 | ENTRY _objc_msgSend_stret | |
821 | MESSENGER_START | |
822 | ||
823 | GetIsaCheckNil STRET // r11 = self->isa, or return zero | |
824 | CacheLookup STRET // calls IMP on success | |
825 | ||
826 | GetIsaSupport STRET | |
827 | ||
828 | // cache miss: go search the method lists | |
829 | LCacheMiss: | |
830 | // isa still in r11 | |
831 | MethodTableLookup %a2, %a3 // r11 = IMP | |
832 | test %r11, %r11 // set ne (stret) for forward; r11!=0 | |
833 | jmp *%r11 // goto *imp | |
834 | ||
835 | END_ENTRY _objc_msgSend_stret | |
836 | ||
837 | ||
838 | ENTRY _objc_msgSend_stret_fixup | |
839 | int3 | |
840 | END_ENTRY _objc_msgSend_stret_fixup | |
841 | ||
842 | ||
843 | STATIC_ENTRY _objc_msgSend_stret_fixedup | |
844 | // Load _cmd from the message_ref | |
845 | movq 8(%a3), %a3 | |
846 | jmp _objc_msgSend_stret | |
847 | END_ENTRY _objc_msgSend_stret_fixedup | |
848 | ||
849 | ||
850 | /******************************************************************** | |
851 | * | |
852 | * void objc_msgSendSuper_stret(void *st_addr, struct objc_super *super, SEL _cmd, ...); | |
853 | * | |
854 | * struct objc_super { | |
855 | * id receiver; | |
856 | * Class class; | |
857 | * }; | |
858 | * | |
859 | * objc_msgSendSuper_stret is the struct-return form of msgSendSuper. | |
860 | * The ABI calls for (sp+4) to be used as the address of the structure | |
861 | * being returned, with the parameters in the succeeding registers. | |
862 | * | |
863 | * On entry: %a1 is the address where the structure is returned, | |
864 | * %a2 is the address of the objc_super structure, | |
865 | * %a3 is the selector | |
866 | * | |
867 | ********************************************************************/ | |
868 | ||
869 | ENTRY _objc_msgSendSuper_stret | |
870 | MESSENGER_START | |
871 | ||
872 | // search the cache (objc_super in %a2) | |
873 | movq class(%a2), %r11 // class = objc_super->class | |
874 | CacheLookup SUPER_STRET // calls IMP on success | |
875 | ||
876 | // cache miss: go search the method lists | |
877 | LCacheMiss: | |
878 | // class still in r11 | |
879 | movq receiver(%a2), %r10 | |
880 | MethodTableLookup %r10, %a3 // r11 = IMP | |
881 | movq receiver(%a2), %a2 // load real receiver | |
882 | test %r11, %r11 // set ne (stret) for forward; r11!=0 | |
883 | jmp *%r11 // goto *imp | |
884 | ||
885 | END_ENTRY _objc_msgSendSuper_stret | |
886 | ||
887 | ||
888 | /******************************************************************** | |
889 | * id objc_msgSendSuper2_stret | |
890 | ********************************************************************/ | |
891 | ||
892 | ENTRY _objc_msgSendSuper2_stret | |
893 | MESSENGER_START | |
894 | ||
895 | // search the cache (objc_super in %a2) | |
896 | movq class(%a2), %r11 // class = objc_super->class | |
897 | movq 8(%r11), %r11 // class = class->superclass | |
898 | CacheLookup SUPER2_STRET // calls IMP on success | |
899 | ||
900 | // cache miss: go search the method lists | |
901 | LCacheMiss: | |
902 | // superclass still in r11 | |
903 | movq receiver(%a2), %r10 | |
904 | MethodTableLookup %r10, %a3 // r11 = IMP | |
905 | movq receiver(%a2), %a2 // load real receiver | |
906 | test %r11, %r11 // set ne (stret) for forward; r11!=0 | |
907 | jmp *%r11 // goto *imp | |
908 | ||
909 | END_ENTRY _objc_msgSendSuper2_stret | |
910 | ||
911 | ||
912 | ENTRY _objc_msgSendSuper2_stret_fixup | |
913 | int3 | |
914 | END_ENTRY _objc_msgSendSuper2_stret_fixup | |
915 | ||
916 | ||
917 | STATIC_ENTRY _objc_msgSendSuper2_stret_fixedup | |
918 | // Load _cmd from the message_ref | |
919 | movq 8(%a3), %a3 | |
920 | jmp _objc_msgSendSuper2_stret | |
921 | END_ENTRY _objc_msgSendSuper2_stret_fixedup | |
922 | ||
923 | ||
924 | /******************************************************************** | |
925 | * | |
926 | * _objc_msgSend_uncached_impcache | |
927 | * _objc_msgSend_uncached | |
928 | * _objc_msgSend_stret_uncached | |
929 | * | |
930 | * Used to erase method cache entries in-place by | |
931 | * bouncing them to the uncached lookup. | |
932 | * | |
933 | ********************************************************************/ | |
934 | ||
935 | STATIC_ENTRY __objc_msgSend_uncached_impcache | |
936 | // Method cache version | |
937 | ||
938 | // THIS IS NOT A CALLABLE C FUNCTION | |
939 | // Out-of-band condition register is NE for stret, EQ otherwise. | |
940 | // Out-of-band r11 is the searched class | |
941 | ||
942 | MESSENGER_START | |
943 | nop | |
944 | MESSENGER_END_SLOW | |
945 | ||
946 | jne __objc_msgSend_stret_uncached | |
947 | jmp __objc_msgSend_uncached | |
948 | ||
949 | END_ENTRY __objc_msgSend_uncached_impcache | |
950 | ||
951 | ||
952 | STATIC_ENTRY __objc_msgSend_uncached | |
953 | ||
954 | // THIS IS NOT A CALLABLE C FUNCTION | |
955 | // Out-of-band r11 is the searched class | |
956 | ||
957 | // r11 is already the class to search | |
958 | MethodTableLookup %a1, %a2 // r11 = IMP | |
959 | cmp %r11, %r11 // set eq (nonstret) for forwarding | |
960 | jmp *%r11 // goto *imp | |
961 | ||
962 | END_ENTRY __objc_msgSend_uncached | |
963 | ||
964 | ||
965 | STATIC_ENTRY __objc_msgSend_stret_uncached | |
966 | // THIS IS NOT A CALLABLE C FUNCTION | |
967 | // Out-of-band r11 is the searched class | |
968 | ||
969 | // r11 is already the class to search | |
970 | MethodTableLookup %a2, %a3 // r11 = IMP | |
971 | test %r11, %r11 // set ne (stret) for forward; r11!=0 | |
972 | jmp *%r11 // goto *imp | |
973 | ||
974 | END_ENTRY __objc_msgSend_stret_uncached | |
975 | ||
976 | ||
977 | /******************************************************************** | |
978 | * | |
979 | * id _objc_msgForward(id self, SEL _cmd,...); | |
980 | * | |
981 | * _objc_msgForward and _objc_msgForward_stret are the externally-callable | |
982 | * functions returned by things like method_getImplementation(). | |
983 | * _objc_msgForward_impcache is the function pointer actually stored in | |
984 | * method caches. | |
985 | * | |
986 | ********************************************************************/ | |
987 | ||
988 | STATIC_ENTRY __objc_msgForward_impcache | |
989 | // Method cache version | |
990 | ||
991 | // THIS IS NOT A CALLABLE C FUNCTION | |
992 | // Out-of-band condition register is NE for stret, EQ otherwise. | |
993 | ||
994 | MESSENGER_START | |
995 | nop | |
996 | MESSENGER_END_SLOW | |
997 | ||
998 | jne __objc_msgForward_stret | |
999 | jmp __objc_msgForward | |
1000 | ||
1001 | END_ENTRY __objc_msgForward_impcache | |
1002 | ||
1003 | ||
1004 | ENTRY __objc_msgForward | |
1005 | // Non-stret version | |
1006 | ||
1007 | movq __objc_forward_handler(%rip), %r11 | |
1008 | jmp *%r11 | |
1009 | ||
1010 | END_ENTRY __objc_msgForward | |
1011 | ||
1012 | ||
1013 | ENTRY __objc_msgForward_stret | |
1014 | // Struct-return version | |
1015 | ||
1016 | movq __objc_forward_stret_handler(%rip), %r11 | |
1017 | jmp *%r11 | |
1018 | ||
1019 | END_ENTRY __objc_msgForward_stret | |
1020 | ||
1021 | ||
1022 | ENTRY _objc_msgSend_debug | |
1023 | jmp _objc_msgSend | |
1024 | END_ENTRY _objc_msgSend_debug | |
1025 | ||
1026 | ENTRY _objc_msgSendSuper2_debug | |
1027 | jmp _objc_msgSendSuper2 | |
1028 | END_ENTRY _objc_msgSendSuper2_debug | |
1029 | ||
1030 | ENTRY _objc_msgSend_stret_debug | |
1031 | jmp _objc_msgSend_stret | |
1032 | END_ENTRY _objc_msgSend_stret_debug | |
1033 | ||
1034 | ENTRY _objc_msgSendSuper2_stret_debug | |
1035 | jmp _objc_msgSendSuper2_stret | |
1036 | END_ENTRY _objc_msgSendSuper2_stret_debug | |
1037 | ||
1038 | ENTRY _objc_msgSend_fpret_debug | |
1039 | jmp _objc_msgSend_fpret | |
1040 | END_ENTRY _objc_msgSend_fpret_debug | |
1041 | ||
1042 | ENTRY _objc_msgSend_fp2ret_debug | |
1043 | jmp _objc_msgSend_fp2ret | |
1044 | END_ENTRY _objc_msgSend_fp2ret_debug | |
1045 | ||
1046 | ||
1047 | ENTRY _objc_msgSend_noarg | |
1048 | jmp _objc_msgSend | |
1049 | END_ENTRY _objc_msgSend_noarg | |
1050 | ||
1051 | ||
1052 | ENTRY _method_invoke | |
1053 | ||
1054 | movq method_imp(%a2), %r11 | |
1055 | movq method_name(%a2), %a2 | |
1056 | jmp *%r11 | |
1057 | ||
1058 | END_ENTRY _method_invoke | |
1059 | ||
1060 | ||
1061 | ENTRY _method_invoke_stret | |
1062 | ||
1063 | movq method_imp(%a3), %r11 | |
1064 | movq method_name(%a3), %a3 | |
1065 | jmp *%r11 | |
1066 | ||
1067 | END_ENTRY _method_invoke_stret | |
1068 | ||
1069 | ||
1070 | STATIC_ENTRY __objc_ignored_method | |
1071 | ||
1072 | movq %a1, %rax | |
1073 | ret | |
1074 | ||
1075 | END_ENTRY __objc_ignored_method | |
1076 | ||
1077 | ||
1078 | .section __DATA,__objc_msg_break | |
1079 | .quad 0 | |
1080 | .quad 0 | |
1081 | ||
1082 | #endif |