]> git.saurik.com Git - apple/objc4.git/blob - runtime/Messengers.subproj/objc-msg-x86_64.s
objc4-371.tar.gz
[apple/objc4.git] / runtime / Messengers.subproj / objc-msg-x86_64.s
1 /*
2 * Copyright (c) 1999-2007 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 /********************************************************************
24 ********************************************************************
25 **
26 ** objc-msg-x86_64.s - x86-64 code to support objc messaging.
27 **
28 ********************************************************************
29 ********************************************************************/
30
31 #define __OBJC2__ 1
32
33 #undef OBJC_ASM
34 #define OBJC_ASM
35 #include "objc-rtp.h"
36
37
38 /********************************************************************
39 * Data used by the ObjC runtime.
40 *
41 ********************************************************************/
42
43 .data
44 // Substitute receiver for messages sent to nil (usually also nil)
45 // id _objc_nilReceiver
46 .align 4
47 .globl __objc_nilReceiver
48 __objc_nilReceiver:
49 .quad 0
50
51 // _objc_entryPoints and _objc_exitPoints are used by objc
52 // to get the critical regions for which method caches
53 // cannot be garbage collected.
54
55 .globl _objc_entryPoints
56 _objc_entryPoints:
57 .quad __cache_getImp
58 .quad __cache_getMethod
59 .quad _objc_msgSend
60 .quad _objc_msgSend_fpret
61 .quad _objc_msgSend_fp2ret
62 .quad _objc_msgSend_stret
63 .quad _objc_msgSendSuper
64 .quad _objc_msgSendSuper_stret
65 .quad 0
66
67 .globl _objc_exitPoints
68 _objc_exitPoints:
69 .quad LGetImpExit
70 .quad LGetMethodExit
71 .quad LMsgSendExit
72 .quad LMsgSendFpretExit
73 .quad LMsgSendFp2retExit
74 .quad LMsgSendStretExit
75 .quad LMsgSendSuperExit
76 .quad LMsgSendSuperStretExit
77 .quad 0
78
79
80 /********************************************************************
81 *
82 * Names for parameter registers.
83 *
84 ********************************************************************/
85
86 #define a1 rdi
87 #define a2 rsi
88 #define a3 rdx
89 #define a4 rcx
90 #define a5 r8
91 #define a6 r9
92 #define a6d r9d
93
94
95 /********************************************************************
96 *
97 * Structure definitions.
98 *
99 ********************************************************************/
100
101 // objc_super parameter to sendSuper
102 receiver = 0
103 class = 8
104
105 // Selected field offsets in class structure
106 isa = 0
107 #if __OBJC2__
108 cache = 16
109 #else
110 cache = 64
111 #endif
112
113 // Method descriptor
114 method_name = 0
115 method_imp = 16
116
117 // Cache header
118 mask = 0
119 occupied = 4
120 buckets = 8 // variable length array
121
122 // typedef struct {
123 // uint128_t floatingPointArgs[8]; // xmm0..xmm7
124 // long linkageArea[4]; // r10, rax, ebp, ret
125 // long registerArgs[6]; // a1..a6
126 // long stackArgs[0]; // variable-size
127 // } *marg_list;
128 #define FP_AREA 0
129 #define LINK_AREA (FP_AREA+8*16)
130 #define REG_AREA (LINK_AREA+4*8)
131 #define STACK_AREA (REG_AREA+6*8)
132
133
134 #if defined(OBJC_INSTRUMENTED)
135 // Cache instrumentation data, follows buckets
136 hitCount = 0
137 hitProbes = hitCount + 4
138 maxHitProbes = hitProbes + 4
139 missCount = maxHitProbes + 4
140 missProbes = missCount + 4
141 maxMissProbes = missProbes + 4
142 flushCount = maxMissProbes + 4
143 flushedEntries = flushCount + 4
144
145 // Buckets in CacheHitHistogram and CacheMissHistogram
146 CACHE_HISTOGRAM_SIZE = 512
147 #endif
148
149
150 //////////////////////////////////////////////////////////////////////
151 //
152 // ENTRY functionName
153 //
154 // Assembly directives to begin an exported function.
155 //
156 // Takes: functionName - name of the exported function
157 //////////////////////////////////////////////////////////////////////
158
159 .macro ENTRY
160 .text
161 .globl $0
162 .align 2, 0x90
163 $0:
164 .endmacro
165
166 //////////////////////////////////////////////////////////////////////
167 //
168 // END_ENTRY functionName
169 //
170 // Assembly directives to end an exported function. Just a placeholder,
171 // a close-parenthesis for ENTRY, until it is needed for something.
172 //
173 // Takes: functionName - name of the exported function
174 //////////////////////////////////////////////////////////////////////
175
176 .macro END_ENTRY
177 .endmacro
178
179 //////////////////////////////////////////////////////////////////////
180 //
181 // CALL_MCOUNTER
182 //
183 // Calls mcount() profiling routine. Must be called immediately on
184 // function entry, before any prologue executes.
185 //
186 //////////////////////////////////////////////////////////////////////
187
188 .macro CALL_MCOUNTER
189 #ifdef PROFILE
190 // Current stack contents: ret
191 pushq %rbp
192 movq %rsp,%rbp
193 // Current stack contents: ret, rbp
194 call mcount
195 movq %rbp,%rsp
196 popq %rbp
197 #endif
198 .endmacro
199
200
201 /////////////////////////////////////////////////////////////////////
202 //
203 // SaveRegisters
204 //
205 // Pushes a stack frame and saves all registers that might contain
206 // parameter values.
207 //
208 // On entry:
209 // $0 = 0 if normal, 1 if CacheLookup already saved a4, a5, a6
210 // stack = ret
211 //
212 // On exit:
213 // %rsp is 16-byte aligned
214 //
215 /////////////////////////////////////////////////////////////////////
216 /*
217 * old->ret 0 +208
218 * 16 ->rbp -8 +200
219 * a6 -16 +192
220 * a5 -24 +184
221 * a4 -32 +176
222 * a3 -40 +168
223 * a2 -48 +160
224 * a1 -56 +152
225 * rax -64 +144
226 * r10 -72 +136
227 * pad -80 +128
228 * xmm7 -88 +112
229 * xmm6 -104 +96
230 * xmm5 -120 +80
231 * xmm4 -136 +64
232 * xmm3 -152 +48
233 * xmm2 -168 +32
234 * xmm1 -184 +16
235 * new->xmm0 -200 +0
236 */
237 .macro SaveRegisters
238 .if $0 == 0
239 movq %a6, -16(%rsp)
240 movq %a5, -24(%rsp)
241 movq %a4, -32(%rsp)
242 .else
243 // a4-a6 already saved by CacheLookup
244 .endif
245 movq %a3, -40(%rsp)
246 movq %a2, -48(%rsp)
247 movq %a1, -56(%rsp)
248 movq %rax, -64(%rsp) // might be xmm parameter count
249 movq %r10, -72(%rsp) // fixme needed?
250 // movq pad, -80(%rsp)
251
252 subq $$ 128+88, %rsp
253
254 // stack is now 16-byte aligned
255 movdqa %xmm0, 0(%rsp)
256 movdqa %xmm1, 16(%rsp)
257 movdqa %xmm2, 32(%rsp)
258 movdqa %xmm3, 48(%rsp)
259 movdqa %xmm4, 64(%rsp)
260 movdqa %xmm5, 80(%rsp)
261 movdqa %xmm6, 96(%rsp)
262 movdqa %xmm7, 112(%rsp)
263 .endmacro
264
265 /////////////////////////////////////////////////////////////////////
266 //
267 // RestoreRegisters
268 //
269 // Pops a stack frame pushed by SaveRegisters
270 //
271 // On entry:
272 // %rsp is unchanged since SaveRegisters
273 //
274 // On exit:
275 // stack = ret
276 //
277 /////////////////////////////////////////////////////////////////////
278
279 .macro RestoreRegisters
280 movdqa 0(%rsp), %xmm0
281 movdqa 16(%rsp), %xmm1
282 movdqa 32(%rsp), %xmm2
283 movdqa 48(%rsp), %xmm3
284 movdqa 64(%rsp), %xmm4
285 movdqa 80(%rsp), %xmm5
286 movdqa 96(%rsp), %xmm6
287 movdqa 112(%rsp), %xmm7
288
289 addq $$ 128+88, %rsp
290
291 movq -16(%rsp), %a6
292 movq -24(%rsp), %a5
293 movq -32(%rsp), %a4
294 movq -40(%rsp), %a3
295 movq -48(%rsp), %a2
296 movq -56(%rsp), %a1
297 movq -64(%rsp), %rax
298 movq -72(%rsp), %r10
299 // movq -80(%rsp), pad
300 .endmacro
301
302
303 /////////////////////////////////////////////////////////////////////
304 //
305 //
306 // CacheLookup selectorRegister, cacheMissLabel, name
307 //
308 // Locate the implementation for a selector in a class method cache.
309 //
310 // Takes:
311 // $0 = register containing selector (%a1 or %a2 ONLY)
312 // cacheMissLabel = label to branch to iff method is not cached
313 // %r11 = class whose cache is to be searched
314 // stack = ret
315 //
316 // On exit: (found) method triplet in %r11
317 // (not found) jumps to cacheMissLabel
318 // stack = ret
319 //
320 /////////////////////////////////////////////////////////////////////
321
322
323 .macro CacheLookup
324
325 // load variables and save caller registers.
326
327 movq %a4, -32(%rsp) // save scratch registers in red zone
328 movq %a5, -24(%rsp)
329 movq %a6, -16(%rsp)
330
331 movq cache(%r11), %a4 // cache = class->cache
332
333 #if defined(OBJC_INSTRUMENTED)
334 pushl %ebx // save non-volatile register
335 pushl %eax // save cache pointer
336 xorl %ebx, %ebx // probeCount = 0
337 #endif
338
339 leaq buckets(%a4), %a5 // buckets = &cache->buckets
340 movl mask(%a4), %a6d
341 shlq $$3, %a6 // %a6 = cache->mask << 3
342 mov $0, %a4 // bytes = sel
343 andq %a6, %a4 // bytes &= (mask << 3)
344
345 // search the receiver's cache
346 // r11 = method (soon)
347 // a4 = bytes
348 // a5 = buckets
349 // a6 = mask << 3
350 // $0 = sel
351 LMsgSendProbeCache_$1:
352 #if defined(OBJC_INSTRUMENTED)
353 addl $$1, %ebx // probeCount += 1
354 #endif
355 movq (%a5, %a4, 1), %r11 // method = buckets[bytes/8]
356 testq %r11, %r11 // if (method == NULL)
357 #if defined(OBJC_INSTRUMENTED)
358 je LMsgSendCacheMiss_$1
359 #else
360 je $1 // goto cacheMissLabel
361 #endif
362
363 addq $$8, %a4 // bytes += 8
364 andq %a6, %a4 // bytes &= (mask << 3)
365 cmpq method_name(%r11), $0 // if (method_name != sel)
366 jne LMsgSendProbeCache_$1 // goto loop
367
368 // cache hit, r11 = method triplet
369 #if defined(OBJC_INSTRUMENTED)
370 jmp LMsgSendInstrumentCacheHit_$1
371 LMsgSendCacheHit2_$1:
372 #endif
373
374 // restore saved registers
375 movq -32(%rsp), %a4
376 movq -24(%rsp), %a5
377 movq -16(%rsp), %a6
378
379 // Done. Only instrumentation follows.
380
381 #if defined(OBJC_INSTRUMENTED)
382 jmp LMsgSendCacheDone_$1
383
384 LMsgSendInstrumentCacheHit_$1:
385 popl %edx // retrieve cache pointer
386 movl mask(%edx), %esi // mask = cache->mask
387 testl %esi, %esi // a mask of zero is only for the...
388 je LMsgSendHitInstrumentDone_$1 // ... emptyCache, do not record anything
389
390 // locate and update the CacheInstrumentation structure
391 addl $$1, %esi // entryCount = mask + 1
392 shll $$2, %esi // tableSize = entryCount * sizeof(entry)
393 addl $buckets, %esi // offset = buckets + tableSize
394 addl %edx, %esi // cacheData = &cache->buckets[mask+1]
395
396 movl hitCount(%esi), %edi
397 addl $$1, %edi
398 movl %edi, hitCount(%esi) // cacheData->hitCount += 1
399 movl hitProbes(%esi), %edi
400 addl %ebx, %edi
401 movl %edi, hitProbes(%esi) // cacheData->hitProbes += probeCount
402 movl maxHitProbes(%esi), %edi// if (cacheData->maxHitProbes < probeCount)
403 cmpl %ebx, %edi
404 jge LMsgSendMaxHitProbeOK_$1
405 movl %ebx, maxHitProbes(%esi)// cacheData->maxHitProbes = probeCount
406 LMsgSendMaxHitProbeOK_$1:
407
408 // update cache hit probe histogram
409 cmpl $CACHE_HISTOGRAM_SIZE, %ebx // pin probeCount to max index
410 jl LMsgSendHitHistoIndexSet_$1
411 movl $(CACHE_HISTOGRAM_SIZE-1), %ebx
412 LMsgSendHitHistoIndexSet_$1:
413 LEA_STATIC_DATA %esi, _CacheHitHistogram, EXTERNAL_SYMBOL
414 shll $$2, %ebx // convert probeCount to histogram index
415 addl %ebx, %esi // calculate &CacheHitHistogram[probeCount<<2]
416 movl 0(%esi), %edi // get current tally
417 addl $$1, %edi //
418 movl %edi, 0(%esi) // tally += 1
419 LMsgSendHitInstrumentDone_$1:
420 popl %ebx // restore non-volatile register
421 jmp LMsgSendCacheHit2_$1
422
423
424 LMsgSendCacheMiss_$1:
425 popl %edx // retrieve cache pointer
426 movl mask(%edx), %esi // mask = cache->mask
427 testl %esi, %esi // a mask of zero is only for the...
428 je LMsgSendMissInstrumentDone_$1 // ... emptyCache, do not record anything
429
430 // locate and update the CacheInstrumentation structure
431 addl $$1, %esi // entryCount = mask + 1
432 shll $$2, %esi // tableSize = entryCount * sizeof(entry)
433 addl $buckets, %esi // offset = buckets + tableSize
434 addl %edx, %esi // cacheData = &cache->buckets[mask+1]
435
436 movl missCount(%esi), %edi //
437 addl $$1, %edi //
438 movl %edi, missCount(%esi) // cacheData->missCount += 1
439 movl missProbes(%esi), %edi //
440 addl %ebx, %edi //
441 movl %edi, missProbes(%esi) // cacheData->missProbes += probeCount
442 movl maxMissProbes(%esi), %edi// if (cacheData->maxMissProbes < probeCount)
443 cmpl %ebx, %edi //
444 jge LMsgSendMaxMissProbeOK_$1 //
445 movl %ebx, maxMissProbes(%esi)// cacheData->maxMissProbes = probeCount
446 LMsgSendMaxMissProbeOK_$1:
447
448 // update cache miss probe histogram
449 cmpl $CACHE_HISTOGRAM_SIZE, %ebx // pin probeCount to max index
450 jl LMsgSendMissHistoIndexSet_$1
451 movl $(CACHE_HISTOGRAM_SIZE-1), %ebx
452 LMsgSendMissHistoIndexSet_$1:
453 LEA_STATIC_DATA %esi, _CacheMissHistogram, EXTERNAL_SYMBOL
454 shll $$2, %ebx // convert probeCount to histogram index
455 addl %ebx, %esi // calculate &CacheMissHistogram[probeCount<<2]
456 movl 0(%esi), %edi // get current tally
457 addl $$1, %edi //
458 movl %edi, 0(%esi) // tally += 1
459 LMsgSendMissInstrumentDone_$1:
460 popl %ebx // restore non-volatile register
461 jmp $0
462
463 LMsgSendCacheDone_$1:
464 #endif
465
466
467 .endmacro
468
469
470 /////////////////////////////////////////////////////////////////////
471 //
472 // MethodTableLookup classRegister, selectorRegister
473 //
474 // Takes: $0 = class to search (%a1 or %a2 or %r11 ONLY)
475 // $1 = selector to search for (%a2 or %a3 ONLY)
476 //
477 // Stack: ret (%rsp+0), pad, %a4, %a5, %a6 (saved by CacheLookup)
478 //
479 // On exit: restores registers saved by CacheLookup
480 // imp in %r11
481 //
482 /////////////////////////////////////////////////////////////////////
483 .macro MethodTableLookup
484
485 SaveRegisters 1
486
487 // _class_lookupMethodAndLoadCache(class, selector)
488 movq $0, %a1
489 movq $1, %a2
490 call __class_lookupMethodAndLoadCache
491
492 // IMP is now in %rax
493 movq %rax, %r11
494
495 RestoreRegisters
496
497 .endmacro
498
499
500 /********************************************************************
501 * Method _cache_getMethod(Class cls, SEL sel, IMP objc_msgForward_imp)
502 *
503 * On entry: a1 = class whose cache is to be searched
504 * a2 = selector to search for
505 * a3 = _objc_msgForward IMP
506 *
507 * If found, returns method triplet pointer.
508 * If not found, returns NULL.
509 *
510 * NOTE: _cache_getMethod never returns any cache entry whose implementation
511 * is _objc_msgForward. It returns NULL instead. This prevents thread-
512 * safety and memory management bugs in _class_lookupMethodAndLoadCache.
513 * See _class_lookupMethodAndLoadCache for details.
514 *
515 * _objc_msgForward is passed as a parameter because it's more efficient
516 * to do the (PIC) lookup once in the caller than repeatedly here.
517 ********************************************************************/
518
519 ENTRY __cache_getMethod
520
521 // do lookup
522 movq %a1, %r11 // move class to r11 for CacheLookup
523 CacheLookup %a2, LGetMethodMiss
524
525 // cache hit, method triplet in %r11
526 cmpq method_imp(%r11), %a3 // if (imp == _objc_msgForward)
527 je LGetMethodMiss // return nil
528 movq %r11, %rax // return method triplet address
529 ret
530
531 LGetMethodMiss:
532 // cache miss, return nil
533 xorq %rax, %rax // erase %rax
534 ret
535
536 LGetMethodExit:
537 END_ENTRY __cache_getMethod
538
539
540 /********************************************************************
541 * IMP _cache_getImp(Class cls, SEL sel)
542 *
543 * On entry: a1 = class whose cache is to be searched
544 * a2 = selector to search for
545 *
546 * If found, returns method implementation.
547 * If not found, returns NULL.
548 ********************************************************************/
549
550 ENTRY __cache_getImp
551
552 // do lookup
553 movq %a1, %r11 // move class to r11 for CacheLookup
554 CacheLookup %a2, LGetImpMiss
555
556 // cache hit, method triplet in %r11
557 movq method_imp(%r11), %rax // return method imp address
558 ret
559
560 LGetImpMiss:
561 // cache miss, return nil
562 xorq %rax, %rax // erase %rax
563 ret
564
565 LGetImpExit:
566 END_ENTRY __cache_getImp
567
568
569 /********************************************************************
570 *
571 * id objc_msgSend(id self, SEL _cmd,...);
572 *
573 ********************************************************************/
574
575 ENTRY _objc_msgSend
576 CALL_MCOUNTER
577
578 // check whether selector is ignored
579 cmpq $ kIgnore, %a2
580 je LMsgSendReturnSelf // ignore and return self
581
582 // check whether receiver is nil
583 testq %a1, %a1
584 je LMsgSendNilSelf
585
586 // receiver (in %a1) is non-nil: search the cache
587 LMsgSendReceiverOk:
588 movq isa(%a1), %r11 // class = self->isa
589 CacheLookup %a2, LMsgSendCacheMiss
590 // CacheLookup placed method in r11
591 movq method_imp(%r11), %r11
592 jmp *%r11 // goto *imp
593
594 // cache miss: go search the method lists
595 LMsgSendCacheMiss:
596 MethodTableLookup isa(%a1), %a2
597 // MethodTableLookup placed IMP in r11
598 jmp *%r11 // goto *imp
599
600 // message sent to nil: redirect to nil receiver, if any
601 LMsgSendNilSelf:
602 movq __objc_nilReceiver(%rip), %a1
603 testq %a1, %a1 // if (receiver != nil)
604 jne LMsgSendReceiverOk // send to new receiver
605
606 // message sent to nil - return 0
607 movq $0, %rax
608 movq $0, %rdx
609 xorps %xmm0, %xmm0
610 xorps %xmm1, %xmm1
611 ret
612
613 LMsgSendReturnSelf:
614 movq %a1, %rax
615 ret
616
617 LMsgSendExit:
618 END_ENTRY _objc_msgSend
619
620 #if __OBJC2__
621 ENTRY _objc_msgSend_fixup
622
623 testq %a1, %a1
624 je LMsgSendFixupNilSelf
625
626 SaveRegisters 0
627 // a1 = receiver
628 // a2 = address of message ref
629 movq %a2, %a3
630 movq $0, %a2
631 // __objc_fixupMessageRef(receiver, 0, ref)
632 call __objc_fixupMessageRef
633 movq %rax, %r11
634 RestoreRegisters
635
636 // imp is in r11
637 // Load _cmd from the message_ref
638 movq 8(%a2), %a2
639 jmp *%r11
640
641 LMsgSendFixupNilSelf:
642 // message sent to nil - return 0
643 movq $0, %rax
644 movq $0, %rdx
645 xorps %xmm0, %xmm0
646 xorps %xmm1, %xmm1
647 ret
648
649 END_ENTRY _objc_msgSend_fixup
650
651
652 ENTRY _objc_msgSend_fixedup
653 // Load _cmd from the message_ref
654 movq 8(%a2), %a2
655 jmp _objc_msgSend
656 END_ENTRY _objc_msgSend_fixedup
657 #endif
658
659
660 /********************************************************************
661 *
662 * id objc_msgSendSuper(struct objc_super *super, SEL _cmd,...);
663 *
664 * struct objc_super {
665 * id receiver;
666 * Class class;
667 * };
668 ********************************************************************/
669
670 ENTRY _objc_msgSendSuper
671 CALL_MCOUNTER
672
673 // check whether selector is ignored
674 cmpq $ kIgnore, %a2
675 je LMsgSendSuperReturnSelf
676
677 // search the cache (objc_super in %a1)
678 movq class(%a1), %r11 // class = objc_super->class
679 CacheLookup %a2, LMsgSendSuperCacheMiss
680 // CacheLookup placed method in r11
681 movq method_imp(%r11), %r11
682 movq receiver(%a1), %a1 // load real receiver
683 jmp *%r11 // goto *imp
684
685 // cache miss: go search the method lists
686 LMsgSendSuperCacheMiss:
687 MethodTableLookup class(%a1), %a2
688 // MethodTableLookup placed IMP in r11
689 movq receiver(%a1), %a1 // load real receiver
690 jmp *%r11 // goto *imp
691
692 LMsgSendSuperReturnSelf:
693 movq receiver(%a1), %rax
694 ret
695
696 LMsgSendSuperExit:
697 END_ENTRY _objc_msgSendSuper
698
699 #if __OBJC2__
700 ENTRY _objc_msgSendSuper2_fixup
701
702 SaveRegisters 0
703 // a1 = address of objc_super2
704 // a2 = address of message ref
705 movq %a2, %a3
706 movq %a1, %a2
707 movq receiver(%a1), %a1
708 // __objc_fixupMessageRef(receiver, objc_super, ref)
709 call __objc_fixupMessageRef
710 movq %rax, %r11
711 RestoreRegisters
712
713 // imp is in r11
714 // Load _cmd from the message_ref
715 movq 8(%a2), %a2
716 // Load receiver from objc_super2
717 movq receiver(%a1), %a1
718 jmp *%r11
719
720 END_ENTRY _objc_msgSendSuper2_fixup
721
722
723 ENTRY _objc_msgSendSuper2_fixedup
724 // objc_super->class is superclass of class to search
725 movq class(%a1), %r11 // cls = objc_super->class
726 movq 8(%a2), %a2 // load _cmd from message_ref
727 movq 8(%r11), %r11 // cls = cls->superclass
728 movq %r11, class(%a1)
729 // objc_super->class is now the class to search
730 jmp _objc_msgSendSuper
731 END_ENTRY _objc_msgSendSuper2_fixedup
732 #endif
733
734
735 /********************************************************************
736 *
737 * double objc_msgSend_fpret(id self, SEL _cmd,...);
738 * Used for `long double` return only. `float` and `double` use objc_msgSend.
739 *
740 ********************************************************************/
741
742 ENTRY _objc_msgSend_fpret
743 CALL_MCOUNTER
744
745 // check whether selector is ignored
746 cmpq $ kIgnore, %a2
747 je LMsgSendFpretReturnZero
748
749 // check whether receiver is nil
750 testq %a1, %a1
751 je LMsgSendFpretNilSelf
752
753 // receiver (in %a1) is non-nil: search the cache
754 LMsgSendFpretReceiverOk:
755 movq isa(%a1), %r11 // class = self->isa
756 CacheLookup %a2, LMsgSendFpretCacheMiss
757 // CacheLookup placed method in r11
758 movq method_imp(%r11), %r11
759 jmp *%r11 // goto *imp
760
761 // cache miss: go search the method lists
762 LMsgSendFpretCacheMiss:
763 MethodTableLookup isa(%a1), %a2
764 // MethodTableLookup placed IMP in r11
765 jmp *%r11 // goto *imp
766
767 // message sent to nil: redirect to nil receiver, if any
768 LMsgSendFpretNilSelf:
769 1: movq __objc_nilReceiver(%rip),%a1
770 testq %a1, %a1 // if (receiver != nil)
771 jne LMsgSendFpretReceiverOk // send to new receiver
772
773 LMsgSendFpretReturnZero:
774 // Long double return.
775 fldz
776 // Clear int and float/double return too.
777 movq $0, %rax
778 movq $0, %rdx
779 xorps %xmm0, %xmm0
780 xorps %xmm1, %xmm1
781 ret
782
783 LMsgSendFpretExit:
784 END_ENTRY _objc_msgSend_fpret
785
786 #if __OBJC2__
787 ENTRY _objc_msgSend_fpret_fixup
788
789 testq %a1, %a1
790 je LMsgSendFpretFixupNilSelf
791
792 SaveRegisters 0
793 // a1 = receiver
794 // a2 = address of message ref
795 movq %a2, %a3
796 movq $0, %a2
797 // __objc_fixupMessageRef(receiver, 0, ref)
798 call __objc_fixupMessageRef
799 movq %rax, %r11
800 RestoreRegisters
801
802 // imp is in r11
803 // Load _cmd from the message_ref
804 movq 8(%a2), %a2
805 jmp *%r11
806
807 LMsgSendFpretFixupNilSelf:
808 // Long double return.
809 fldz
810 // Clear int and float/double return too.
811 movq $0, %rax
812 movq $0, %rdx
813 xorps %xmm0, %xmm0
814 xorps %xmm1, %xmm1
815 ret
816
817 END_ENTRY _objc_msgSend_fpret_fixup
818
819
820 ENTRY _objc_msgSend_fpret_fixedup
821 // Load _cmd from the message_ref
822 movq 8(%a2), %a2
823 jmp _objc_msgSend_fpret
824 END_ENTRY _objc_msgSend_fpret_fixedup
825 #endif
826
827
828 /********************************************************************
829 *
830 * double objc_msgSend_fp2ret(id self, SEL _cmd,...);
831 * Used for `complex long double` return only.
832 *
833 ********************************************************************/
834
835 ENTRY _objc_msgSend_fp2ret
836 CALL_MCOUNTER
837
838 // check whether selector is ignored
839 cmpq $ kIgnore, %a2
840 je LMsgSendFp2retReturnZero
841
842 // check whether receiver is nil
843 testq %a1, %a1
844 je LMsgSendFp2retNilSelf
845
846 // receiver (in %a1) is non-nil: search the cache
847 LMsgSendFp2retReceiverOk:
848 movq isa(%a1), %r11 // class = self->isa
849 CacheLookup %a2, LMsgSendFp2retCacheMiss
850 // CacheLookup placed method in r11
851 movq method_imp(%r11), %r11
852 jmp *%r11 // goto *imp
853
854 // cache miss: go search the method lists
855 LMsgSendFp2retCacheMiss:
856 MethodTableLookup isa(%a1), %a2
857 // MethodTableLookup placed IMP in r11
858 jmp *%r11 // goto *imp
859
860 // message sent to nil: redirect to nil receiver, if any
861 LMsgSendFp2retNilSelf:
862 1: movq __objc_nilReceiver(%rip),%a1
863 testq %a1, %a1 // if (receiver != nil)
864 jne LMsgSendFp2retReceiverOk // send to new receiver
865
866 LMsgSendFp2retReturnZero:
867 // complex long double return.
868 fldz
869 fldz
870 // Clear int and float/double return too.
871 movq $0, %rax
872 movq $0, %rdx
873 xorps %xmm0, %xmm0
874 xorps %xmm1, %xmm1
875 ret
876
877 LMsgSendFp2retExit:
878 END_ENTRY _objc_msgSend_fp2ret
879
880 #if __OBJC2__
881 ENTRY _objc_msgSend_fp2ret_fixup
882
883 testq %a1, %a1
884 je LMsgSendFp2retFixupNilSelf
885
886 SaveRegisters 0
887 // a1 = receiver
888 // a2 = address of message ref
889 movq %a2, %a3
890 movq $0, %a2
891 // __objc_fixupMessageRef(receiver, 0, ref)
892 call __objc_fixupMessageRef
893 movq %rax, %r11
894 RestoreRegisters
895
896 // imp is in r11
897 // Load _cmd from the message_ref
898 movq 8(%a2), %a2
899 jmp *%r11
900
901 LMsgSendFp2retFixupNilSelf:
902 // complex long double return.
903 fldz
904 fldz
905 // Clear int and float/double return too.
906 movq $0, %rax
907 movq $0, %rdx
908 xorps %xmm0, %xmm0
909 xorps %xmm1, %xmm1
910 ret
911
912 END_ENTRY _objc_msgSend_fp2ret_fixup
913
914
915 ENTRY _objc_msgSend_fp2ret_fixedup
916 // Load _cmd from the message_ref
917 movq 8(%a2), %a2
918 jmp _objc_msgSend_fp2ret
919 END_ENTRY _objc_msgSend_fp2ret_fixedup
920 #endif
921
922
923 /********************************************************************
924 *
925 * void objc_msgSend_stret(void *st_addr, id self, SEL _cmd, ...);
926 *
927 * objc_msgSend_stret is the struct-return form of msgSend.
928 * The ABI calls for %a1 to be used as the address of the structure
929 * being returned, with the parameters in the succeeding locations.
930 *
931 * On entry: %a1 is the address where the structure is returned,
932 * %a2 is the message receiver,
933 * %a3 is the selector
934 ********************************************************************/
935
936 ENTRY _objc_msgSend_stret
937 CALL_MCOUNTER
938
939 // check whether receiver is nil
940 testq %a2, %a2
941 je LMsgSendStretNilSelf
942
943 // receiver (in %a2) is non-nil: search the cache
944 LMsgSendStretReceiverOk:
945 movq isa(%a2), %r11 // class = self->isa
946 CacheLookup %a3, LMsgSendStretCacheMiss
947 // CacheLookup placed method in %r11
948 movq method_imp(%r11), %r11
949 LMsgSendStretCallImp:
950 cmpq %r11, L_objc_msgForward(%rip) // if imp == _objc_msgForward
951 je __objc_msgForward_stret // call struct-returning fwd
952 jmp *%r11 // else goto *imp
953
954 // cache miss: go search the method lists
955 LMsgSendStretCacheMiss:
956 MethodTableLookup isa(%a2), %a3
957 // MethodTableLookup placed IMP in r11
958 jmp LMsgSendStretCallImp
959
960 // message sent to nil: redirect to nil receiver, if any
961 LMsgSendStretNilSelf:
962 movq __objc_nilReceiver(%rip), %a2
963 testq %a2, %a2 // if (receiver != nil)
964 jne LMsgSendStretReceiverOk // send to new receiver
965 ret // else just return
966
967 LMsgSendStretExit:
968 END_ENTRY _objc_msgSend_stret
969
970 #if __OBJC2__
971 ENTRY _objc_msgSend_stret_fixup
972
973 testq %a2, %a2
974 je LMsgSendStretFixupNilSelf
975
976 SaveRegisters 0
977 // a2 = receiver
978 // a3 = address of message ref
979 movq %a2, %a1
980 movq $0, %a2
981 // __objc_fixupMessageRef(receiver, 0, ref)
982 call __objc_fixupMessageRef
983 movq %rax, %r11
984 RestoreRegisters
985
986 // imp is in r11
987 // Load _cmd from the message_ref
988 movq 8(%a3), %a3
989 cmpq %r11, L_objc_msgForward(%rip) // if imp == _objc_msgForward
990 je __objc_msgForward_stret // call struct-returning fwd
991 jmp *%r11 // else goto *imp
992
993 LMsgSendStretFixupNilSelf:
994 ret
995
996 END_ENTRY _objc_msgSend_stret_fixup
997
998
999 ENTRY _objc_msgSend_stret_fixedup
1000 // Load _cmd from the message_ref
1001 movq 8(%a3), %a3
1002 jmp _objc_msgSend_stret
1003 END_ENTRY _objc_msgSend_stret_fixedup
1004 #endif
1005
1006
1007 /********************************************************************
1008 *
1009 * void objc_msgSendSuper_stret(void *st_addr, struct objc_super *super, SEL _cmd, ...);
1010 *
1011 * struct objc_super {
1012 * id receiver;
1013 * Class class;
1014 * };
1015 *
1016 * objc_msgSendSuper_stret is the struct-return form of msgSendSuper.
1017 * The ABI calls for (sp+4) to be used as the address of the structure
1018 * being returned, with the parameters in the succeeding registers.
1019 *
1020 * On entry: %a1 is the address where the structure is returned,
1021 * %a2 is the address of the objc_super structure,
1022 * %a3 is the selector
1023 *
1024 ********************************************************************/
1025
1026 ENTRY _objc_msgSendSuper_stret
1027 CALL_MCOUNTER
1028
1029 // search the cache (objc_super in %a2)
1030 movq class(%a2), %r11 // class = objc_super->class
1031 CacheLookup %a3, LMsgSendSuperStretCacheMiss
1032 // CacheLookup placed method in %r11
1033 movq method_imp(%r11), %r11
1034 LMsgSendSuperStretCallImp:
1035 movq receiver(%a2), %a2 // load real receiver
1036 cmpq %r11, L_objc_msgForward(%rip) // if imp == _objc_msgForward
1037 je __objc_msgForward_stret // call struct-returning fwd
1038 jmp *%r11 // else goto *imp
1039
1040 // cache miss: go search the method lists
1041 LMsgSendSuperStretCacheMiss:
1042 MethodTableLookup class(%a2), %a3
1043 // MethodTableLookup placed IMP in r11
1044 jmp LMsgSendSuperStretCallImp
1045
1046 LMsgSendSuperStretExit:
1047 END_ENTRY _objc_msgSendSuper_stret
1048
1049 #if __OBJC2__
1050 ENTRY _objc_msgSendSuper2_stret_fixup
1051
1052 SaveRegisters 0
1053 // a2 = address of objc_super2
1054 // a3 = address of message ref
1055 movq receiver(%a2), %a1
1056 // __objc_fixupMessageRef(receiver, objc_super, ref)
1057 call __objc_fixupMessageRef
1058 movq %rax, %r11
1059 RestoreRegisters
1060
1061 // imp is in r11
1062 // Load _cmd from the message_ref
1063 movq 8(%a3), %a3
1064 // Load receiver from objc_super2
1065 movq receiver(%a2), %a2
1066 cmpq %r11, L_objc_msgForward(%rip) // if imp == _objc_msgForward
1067 je __objc_msgForward_stret // call struct-returning fwd
1068 jmp *%r11 // else goto *imp
1069
1070 END_ENTRY _objc_msgSendSuper2_stret_fixup
1071
1072
1073 ENTRY _objc_msgSendSuper2_stret_fixedup
1074 // objc_super->class is superclass of class to search
1075 movq class(%a2), %r11 // cls = objc_super->class
1076 movq 8(%a3), %a3 // load _cmd from message_ref
1077 movq 8(%r11), %r11 // cls = cls->superclass
1078 movq %r11, class(%a2)
1079 // objc_super->class is now the class to search
1080 jmp _objc_msgSendSuper_stret
1081 END_ENTRY _objc_msgSendSuper2_stret_fixedup
1082 #endif
1083
1084
1085 /********************************************************************
1086 *
1087 * id _objc_msgForward(id self, SEL _cmd,...);
1088 *
1089 ********************************************************************/
1090
1091 // _FwdSel is @selector(forward::), set up in map_images().
1092 // ALWAYS dereference _FwdSel to get to "forward::" !!
1093 .data
1094 .align 3
1095 .private_extern _FwdSel
1096 _FwdSel: .quad 0
1097
1098 .cstring
1099 .align 3
1100 LUnkSelStr: .ascii "Does not recognize selector %s\0"
1101
1102 .data
1103 .align 3
1104 .private_extern __objc_forward_handler
1105 __objc_forward_handler: .quad 0
1106
1107 .data
1108 .align 3
1109 .private_extern __objc_forward_stret_handler
1110 __objc_forward_stret_handler: .quad 0
1111
1112 // GrP fixme don't know how to cmpq reg, _objc_msgForward
1113 L_objc_msgForward: .quad __objc_msgForward
1114
1115 ENTRY __objc_msgForward
1116
1117 // Non-struct return only!
1118
1119 // Call user handler, if any
1120 movq __objc_forward_handler(%rip), %r11
1121 testq %r11, %r11 // if (handler == NULL)
1122 je 1f // skip handler
1123 jmp *%r11 // else goto handler
1124 1:
1125 // No user handler
1126
1127 // Die if forwarding "forward::"
1128 cmpq %a2, _FwdSel(%rip)
1129 je LMsgForwardError
1130
1131 // Record current return address. It will be copied elsewhere in
1132 // the marg_list because this location is needed for register args
1133 movq (%rsp), %r11
1134
1135 // Push stack frame
1136 // Space for: fpArgs + regArgs + linkage - ret (already on stack)
1137 subq $ 8*16 + 6*8 + (4-1)*8, %rsp
1138
1139 // Save return address in linkage area.
1140 movq %r11, 16+LINK_AREA(%rsp)
1141
1142 // Save parameter registers
1143 movq %a1, 0+REG_AREA(%rsp)
1144 movq %a2, 8+REG_AREA(%rsp)
1145 movq %a3, 16+REG_AREA(%rsp)
1146 movq %a4, 24+REG_AREA(%rsp)
1147 movq %a5, 32+REG_AREA(%rsp)
1148 movq %a6, 40+REG_AREA(%rsp)
1149
1150 // Save side parameter registers
1151 movq %r10, 0+LINK_AREA(%rsp) // static chain (fixme needed?)
1152 movq %rax, 8+LINK_AREA(%rsp) // xmm count
1153 // 16+LINK_AREA is return address
1154
1155 // Save xmm registers
1156 movdqa %xmm0, 0+FP_AREA(%rsp)
1157 movdqa %xmm1, 16+FP_AREA(%rsp)
1158 movdqa %xmm2, 32+FP_AREA(%rsp)
1159 movdqa %xmm3, 48+FP_AREA(%rsp)
1160 movdqa %xmm4, 64+FP_AREA(%rsp)
1161 movdqa %xmm5, 80+FP_AREA(%rsp)
1162 movdqa %xmm6, 96+FP_AREA(%rsp)
1163 movdqa %xmm7, 112+FP_AREA(%rsp)
1164
1165 // Call [receiver forward:sel :margs]
1166 movq %rsp, %a4 // marg_list
1167 movq %a2, %a3 // sel
1168 movq _FwdSel(%rip), %a2 // forward::
1169 // %a1 is already the receiver
1170
1171 call _objc_msgSend
1172
1173 // Retrieve return address from linkage area
1174 movq 16+LINK_AREA(%rsp), %r11
1175 // Pop stack frame
1176 subq $ 8*16 + 6*8 + (4-1)*8, %rsp
1177 // Put return address back
1178 movq %r11, (%rsp)
1179 ret
1180
1181 LMsgForwardError:
1182 // Tail-call __objc_error(receiver, "unknown selector %s", "forward::")
1183 // %a1 is already the receiver
1184 leaq LUnkSelStr(%rip), %a2 // "unknown selector %s"
1185 movq _FwdSel(%rip), %a3 // forward::
1186 jmp ___objc_error // never returns
1187
1188 END_ENTRY __objc_msgForward
1189
1190
1191 ENTRY __objc_msgForward_stret
1192
1193 // Call user handler, if any
1194 movq __objc_forward_stret_handler(%rip), %r11
1195 testq %r11, %r11 // if (handler == NULL)
1196 je 1f // skip handler
1197 jmp *%r11 // else goto handler
1198 1:
1199 // No user handler
1200 // Die if forwarding "forward::"
1201 cmpq %a3, _FwdSel(%rip)
1202 je LMsgForwardStretError
1203
1204 // Record current return address. It will be copied elsewhere in
1205 // the marg_list because this location is needed for register args
1206 movq (%rsp), %r11
1207
1208 // Push stack frame
1209 // Space for: fpArgs + regArgs + linkage - ret (already on stack)
1210 subq $ 8*16 + 6*8 + (4-1)*8, %rsp
1211
1212 // Save return address in linkage area.
1213 movq %r11, 16+LINK_AREA(%rsp)
1214
1215 // Save parameter registers
1216 movq %a1, 0+REG_AREA(%rsp)
1217 movq %a2, 8+REG_AREA(%rsp)
1218 movq %a3, 16+REG_AREA(%rsp)
1219 movq %a4, 24+REG_AREA(%rsp)
1220 movq %a5, 32+REG_AREA(%rsp)
1221 movq %a6, 40+REG_AREA(%rsp)
1222
1223 // Save side parameter registers
1224 movq %r10, 0+LINK_AREA(%rsp) // static chain (fixme needed?)
1225 movq %rax, 8+LINK_AREA(%rsp) // xmm count
1226 // 16+LINK_AREA is return address
1227
1228 // Save xmm registers
1229 movdqa %xmm0, 0+FP_AREA(%rsp)
1230 movdqa %xmm1, 16+FP_AREA(%rsp)
1231 movdqa %xmm2, 32+FP_AREA(%rsp)
1232 movdqa %xmm3, 48+FP_AREA(%rsp)
1233 movdqa %xmm4, 64+FP_AREA(%rsp)
1234 movdqa %xmm5, 80+FP_AREA(%rsp)
1235 movdqa %xmm6, 96+FP_AREA(%rsp)
1236 movdqa %xmm7, 112+FP_AREA(%rsp)
1237
1238 // Call [receiver forward:sel :margs]
1239 movq %a2, %a1 // receiver
1240 movq _FwdSel(%rip), %a2 // forward::
1241 // %a3 is already the selector
1242 movq %rsp, %a4 // marg_list
1243
1244 call _objc_msgSend // forward:: is NOT struct-return
1245
1246 // Retrieve return address from linkage area
1247 movq 16+LINK_AREA(%rsp), %r11
1248 // Pop stack frame
1249 subq $ 8*16 + 6*8 + (4-1)*8, %rsp
1250 // Put return address back
1251 movq %r11, (%rsp)
1252 ret
1253
1254 LMsgForwardStretError:
1255 // Tail-call __objc_error(receiver, "unknown selector %s", "forward::")
1256 movq %a2, %a1 // receiver
1257 leaq LUnkSelStr(%rip), %a2 // "unknown selector %s"
1258 movq _FwdSel(%rip), %a3 // forward::
1259 jmp ___objc_error // never returns
1260
1261 END_ENTRY __objc_msgForward_stret
1262
1263
1264 ENTRY _method_invoke
1265
1266 movq method_imp(%a2), %r11
1267 movq method_name(%a2), %a2
1268 jmp *%r11
1269
1270 END_ENTRY _method_invoke
1271
1272
1273 ENTRY _method_invoke_stret
1274
1275 movq method_imp(%a3), %r11
1276 movq method_name(%a3), %a3
1277 jmp *%r11
1278
1279 END_ENTRY _method_invoke_stret