2 * Copyright (c) 1999-2007 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
23 /********************************************************************
24 ********************************************************************
26 ** objc-msg-x86_64.s - x86-64 code to support objc messaging.
28 ********************************************************************
29 ********************************************************************/
38 /********************************************************************
39 * Data used by the ObjC runtime.
41 ********************************************************************/
44 // Substitute receiver for messages sent to nil (usually also nil)
45 // id _objc_nilReceiver
47 .globl __objc_nilReceiver
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.
55 .globl _objc_entryPoints
58 .quad __cache_getMethod
60 .quad _objc_msgSend_fpret
61 .quad _objc_msgSend_fp2ret
62 .quad _objc_msgSend_stret
63 .quad _objc_msgSendSuper
64 .quad _objc_msgSendSuper_stret
67 .globl _objc_exitPoints
72 .quad LMsgSendFpretExit
73 .quad LMsgSendFp2retExit
74 .quad LMsgSendStretExit
75 .quad LMsgSendSuperExit
76 .quad LMsgSendSuperStretExit
80 /********************************************************************
82 * Names for parameter registers.
84 ********************************************************************/
95 /********************************************************************
97 * Structure definitions.
99 ********************************************************************/
101 // objc_super parameter to sendSuper
105 // Selected field offsets in class structure
120 buckets = 8 // variable length array
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
129 #define LINK_AREA (FP_AREA+8*16)
130 #define REG_AREA (LINK_AREA+4*8)
131 #define STACK_AREA (REG_AREA+6*8)
134 #if defined(OBJC_INSTRUMENTED)
135 // Cache instrumentation data, follows buckets
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
145 // Buckets in CacheHitHistogram and CacheMissHistogram
146 CACHE_HISTOGRAM_SIZE = 512
150 //////////////////////////////////////////////////////////////////////
152 // ENTRY functionName
154 // Assembly directives to begin an exported function.
156 // Takes: functionName - name of the exported function
157 //////////////////////////////////////////////////////////////////////
166 //////////////////////////////////////////////////////////////////////
168 // END_ENTRY functionName
170 // Assembly directives to end an exported function. Just a placeholder,
171 // a close-parenthesis for ENTRY, until it is needed for something.
173 // Takes: functionName - name of the exported function
174 //////////////////////////////////////////////////////////////////////
179 //////////////////////////////////////////////////////////////////////
183 // Calls mcount() profiling routine. Must be called immediately on
184 // function entry, before any prologue executes.
186 //////////////////////////////////////////////////////////////////////
190 // Current stack contents: ret
193 // Current stack contents: ret, rbp
201 /////////////////////////////////////////////////////////////////////
205 // Pushes a stack frame and saves all registers that might contain
209 // $0 = 0 if normal, 1 if CacheLookup already saved a4, a5, a6
213 // %rsp is 16-byte aligned
215 /////////////////////////////////////////////////////////////////////
243 // a4-a6 already saved by CacheLookup
248 movq %rax, -64(%rsp) // might be xmm parameter count
249 movq %r10, -72(%rsp) // fixme needed?
250 // movq pad, -80(%rsp)
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)
265 /////////////////////////////////////////////////////////////////////
269 // Pops a stack frame pushed by SaveRegisters
272 // %rsp is unchanged since SaveRegisters
277 /////////////////////////////////////////////////////////////////////
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
299 // movq -80(%rsp), pad
303 /////////////////////////////////////////////////////////////////////
306 // CacheLookup selectorRegister, cacheMissLabel, name
308 // Locate the implementation for a selector in a class method cache.
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
316 // On exit: (found) method triplet in %r11
317 // (not found) jumps to cacheMissLabel
320 /////////////////////////////////////////////////////////////////////
325 // load variables and save caller registers.
327 movq %a4, -32(%rsp) // save scratch registers in red zone
331 movq cache(%r11), %a4 // cache = class->cache
333 #if defined(OBJC_INSTRUMENTED)
334 pushl %ebx // save non-volatile register
335 pushl %eax // save cache pointer
336 xorl %ebx, %ebx // probeCount = 0
339 leaq buckets(%a4), %a5 // buckets = &cache->buckets
341 shlq $$3, %a6 // %a6 = cache->mask << 3
342 mov $0, %a4 // bytes = sel
343 andq %a6, %a4 // bytes &= (mask << 3)
345 // search the receiver's cache
346 // r11 = method (soon)
351 LMsgSendProbeCache_$1:
352 #if defined(OBJC_INSTRUMENTED)
353 addl $$1, %ebx // probeCount += 1
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
360 je $1 // goto cacheMissLabel
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
368 // cache hit, r11 = method triplet
369 #if defined(OBJC_INSTRUMENTED)
370 jmp LMsgSendInstrumentCacheHit_$1
371 LMsgSendCacheHit2_$1:
374 // restore saved registers
379 // Done. Only instrumentation follows.
381 #if defined(OBJC_INSTRUMENTED)
382 jmp LMsgSendCacheDone_$1
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
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]
396 movl hitCount(%esi), %edi
398 movl %edi, hitCount(%esi) // cacheData->hitCount += 1
399 movl hitProbes(%esi), %edi
401 movl %edi, hitProbes(%esi) // cacheData->hitProbes += probeCount
402 movl maxHitProbes(%esi), %edi// if (cacheData->maxHitProbes < probeCount)
404 jge LMsgSendMaxHitProbeOK_$1
405 movl %ebx, maxHitProbes(%esi)// cacheData->maxHitProbes = probeCount
406 LMsgSendMaxHitProbeOK_$1:
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
418 movl %edi, 0(%esi) // tally += 1
419 LMsgSendHitInstrumentDone_$1:
420 popl %ebx // restore non-volatile register
421 jmp LMsgSendCacheHit2_$1
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
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]
436 movl missCount(%esi), %edi //
438 movl %edi, missCount(%esi) // cacheData->missCount += 1
439 movl missProbes(%esi), %edi //
441 movl %edi, missProbes(%esi) // cacheData->missProbes += probeCount
442 movl maxMissProbes(%esi), %edi// if (cacheData->maxMissProbes < probeCount)
444 jge LMsgSendMaxMissProbeOK_$1 //
445 movl %ebx, maxMissProbes(%esi)// cacheData->maxMissProbes = probeCount
446 LMsgSendMaxMissProbeOK_$1:
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
458 movl %edi, 0(%esi) // tally += 1
459 LMsgSendMissInstrumentDone_$1:
460 popl %ebx // restore non-volatile register
463 LMsgSendCacheDone_$1:
470 /////////////////////////////////////////////////////////////////////
472 // MethodTableLookup classRegister, selectorRegister
474 // Takes: $0 = class to search (%a1 or %a2 or %r11 ONLY)
475 // $1 = selector to search for (%a2 or %a3 ONLY)
477 // Stack: ret (%rsp+0), pad, %a4, %a5, %a6 (saved by CacheLookup)
479 // On exit: restores registers saved by CacheLookup
482 /////////////////////////////////////////////////////////////////////
483 .macro MethodTableLookup
487 // _class_lookupMethodAndLoadCache(class, selector)
490 call __class_lookupMethodAndLoadCache
492 // IMP is now in %rax
500 /********************************************************************
501 * Method _cache_getMethod(Class cls, SEL sel, IMP objc_msgForward_imp)
503 * On entry: a1 = class whose cache is to be searched
504 * a2 = selector to search for
505 * a3 = _objc_msgForward IMP
507 * If found, returns method triplet pointer.
508 * If not found, returns NULL.
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.
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 ********************************************************************/
519 ENTRY __cache_getMethod
522 movq %a1, %r11 // move class to r11 for CacheLookup
523 CacheLookup %a2, LGetMethodMiss
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
532 // cache miss, return nil
533 xorq %rax, %rax // erase %rax
537 END_ENTRY __cache_getMethod
540 /********************************************************************
541 * IMP _cache_getImp(Class cls, SEL sel)
543 * On entry: a1 = class whose cache is to be searched
544 * a2 = selector to search for
546 * If found, returns method implementation.
547 * If not found, returns NULL.
548 ********************************************************************/
553 movq %a1, %r11 // move class to r11 for CacheLookup
554 CacheLookup %a2, LGetImpMiss
556 // cache hit, method triplet in %r11
557 movq method_imp(%r11), %rax // return method imp address
561 // cache miss, return nil
562 xorq %rax, %rax // erase %rax
566 END_ENTRY __cache_getImp
569 /********************************************************************
571 * id objc_msgSend(id self, SEL _cmd,...);
573 ********************************************************************/
578 // check whether selector is ignored
580 je LMsgSendReturnSelf // ignore and return self
582 // check whether receiver is nil
586 // receiver (in %a1) is non-nil: search the cache
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
594 // cache miss: go search the method lists
596 MethodTableLookup isa(%a1), %a2
597 // MethodTableLookup placed IMP in r11
598 jmp *%r11 // goto *imp
600 // message sent to nil: redirect to nil receiver, if any
602 movq __objc_nilReceiver(%rip), %a1
603 testq %a1, %a1 // if (receiver != nil)
604 jne LMsgSendReceiverOk // send to new receiver
606 // message sent to nil - return 0
618 END_ENTRY _objc_msgSend
621 ENTRY _objc_msgSend_fixup
624 je LMsgSendFixupNilSelf
628 // a2 = address of message ref
631 // __objc_fixupMessageRef(receiver, 0, ref)
632 call __objc_fixupMessageRef
637 // Load _cmd from the message_ref
641 LMsgSendFixupNilSelf:
642 // message sent to nil - return 0
649 END_ENTRY _objc_msgSend_fixup
652 ENTRY _objc_msgSend_fixedup
653 // Load _cmd from the message_ref
656 END_ENTRY _objc_msgSend_fixedup
660 /********************************************************************
662 * id objc_msgSendSuper(struct objc_super *super, SEL _cmd,...);
664 * struct objc_super {
668 ********************************************************************/
670 ENTRY _objc_msgSendSuper
673 // check whether selector is ignored
675 je LMsgSendSuperReturnSelf
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
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
692 LMsgSendSuperReturnSelf:
693 movq receiver(%a1), %rax
697 END_ENTRY _objc_msgSendSuper
700 ENTRY _objc_msgSendSuper2_fixup
703 // a1 = address of objc_super2
704 // a2 = address of message ref
707 movq receiver(%a1), %a1
708 // __objc_fixupMessageRef(receiver, objc_super, ref)
709 call __objc_fixupMessageRef
714 // Load _cmd from the message_ref
716 // Load receiver from objc_super2
717 movq receiver(%a1), %a1
720 END_ENTRY _objc_msgSendSuper2_fixup
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
735 /********************************************************************
737 * double objc_msgSend_fpret(id self, SEL _cmd,...);
738 * Used for `long double` return only. `float` and `double` use objc_msgSend.
740 ********************************************************************/
742 ENTRY _objc_msgSend_fpret
745 // check whether selector is ignored
747 je LMsgSendFpretReturnZero
749 // check whether receiver is nil
751 je LMsgSendFpretNilSelf
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
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
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
773 LMsgSendFpretReturnZero:
774 // Long double return.
776 // Clear int and float/double return too.
784 END_ENTRY _objc_msgSend_fpret
787 ENTRY _objc_msgSend_fpret_fixup
790 je LMsgSendFpretFixupNilSelf
794 // a2 = address of message ref
797 // __objc_fixupMessageRef(receiver, 0, ref)
798 call __objc_fixupMessageRef
803 // Load _cmd from the message_ref
807 LMsgSendFpretFixupNilSelf:
808 // Long double return.
810 // Clear int and float/double return too.
817 END_ENTRY _objc_msgSend_fpret_fixup
820 ENTRY _objc_msgSend_fpret_fixedup
821 // Load _cmd from the message_ref
823 jmp _objc_msgSend_fpret
824 END_ENTRY _objc_msgSend_fpret_fixedup
828 /********************************************************************
830 * double objc_msgSend_fp2ret(id self, SEL _cmd,...);
831 * Used for `complex long double` return only.
833 ********************************************************************/
835 ENTRY _objc_msgSend_fp2ret
838 // check whether selector is ignored
840 je LMsgSendFp2retReturnZero
842 // check whether receiver is nil
844 je LMsgSendFp2retNilSelf
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
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
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
866 LMsgSendFp2retReturnZero:
867 // complex long double return.
870 // Clear int and float/double return too.
878 END_ENTRY _objc_msgSend_fp2ret
881 ENTRY _objc_msgSend_fp2ret_fixup
884 je LMsgSendFp2retFixupNilSelf
888 // a2 = address of message ref
891 // __objc_fixupMessageRef(receiver, 0, ref)
892 call __objc_fixupMessageRef
897 // Load _cmd from the message_ref
901 LMsgSendFp2retFixupNilSelf:
902 // complex long double return.
905 // Clear int and float/double return too.
912 END_ENTRY _objc_msgSend_fp2ret_fixup
915 ENTRY _objc_msgSend_fp2ret_fixedup
916 // Load _cmd from the message_ref
918 jmp _objc_msgSend_fp2ret
919 END_ENTRY _objc_msgSend_fp2ret_fixedup
923 /********************************************************************
925 * void objc_msgSend_stret(void *st_addr, id self, SEL _cmd, ...);
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.
931 * On entry: %a1 is the address where the structure is returned,
932 * %a2 is the message receiver,
933 * %a3 is the selector
934 ********************************************************************/
936 ENTRY _objc_msgSend_stret
939 // check whether receiver is nil
941 je LMsgSendStretNilSelf
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
954 // cache miss: go search the method lists
955 LMsgSendStretCacheMiss:
956 MethodTableLookup isa(%a2), %a3
957 // MethodTableLookup placed IMP in r11
958 jmp LMsgSendStretCallImp
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
968 END_ENTRY _objc_msgSend_stret
971 ENTRY _objc_msgSend_stret_fixup
974 je LMsgSendStretFixupNilSelf
978 // a3 = address of message ref
981 // __objc_fixupMessageRef(receiver, 0, ref)
982 call __objc_fixupMessageRef
987 // Load _cmd from the message_ref
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
993 LMsgSendStretFixupNilSelf:
996 END_ENTRY _objc_msgSend_stret_fixup
999 ENTRY _objc_msgSend_stret_fixedup
1000 // Load _cmd from the message_ref
1002 jmp _objc_msgSend_stret
1003 END_ENTRY _objc_msgSend_stret_fixedup
1007 /********************************************************************
1009 * void objc_msgSendSuper_stret(void *st_addr, struct objc_super *super, SEL _cmd, ...);
1011 * struct objc_super {
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.
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
1024 ********************************************************************/
1026 ENTRY _objc_msgSendSuper_stret
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
1040 // cache miss: go search the method lists
1041 LMsgSendSuperStretCacheMiss:
1042 MethodTableLookup class(%a2), %a3
1043 // MethodTableLookup placed IMP in r11
1044 jmp LMsgSendSuperStretCallImp
1046 LMsgSendSuperStretExit:
1047 END_ENTRY _objc_msgSendSuper_stret
1050 ENTRY _objc_msgSendSuper2_stret_fixup
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
1062 // Load _cmd from the message_ref
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
1070 END_ENTRY _objc_msgSendSuper2_stret_fixup
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
1085 /********************************************************************
1087 * id _objc_msgForward(id self, SEL _cmd,...);
1089 ********************************************************************/
1091 // _FwdSel is @selector(forward::), set up in map_images().
1092 // ALWAYS dereference _FwdSel to get to "forward::" !!
1095 .private_extern _FwdSel
1100 LUnkSelStr: .ascii "Does not recognize selector %s\0"
1104 .private_extern __objc_forward_handler
1105 __objc_forward_handler: .quad 0
1109 .private_extern __objc_forward_stret_handler
1110 __objc_forward_stret_handler: .quad 0
1112 // GrP fixme don't know how to cmpq reg, _objc_msgForward
1113 L_objc_msgForward: .quad __objc_msgForward
1115 ENTRY __objc_msgForward
1117 // Non-struct return only!
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
1127 // Die if forwarding "forward::"
1128 cmpq %a2, _FwdSel(%rip)
1131 // Record current return address. It will be copied elsewhere in
1132 // the marg_list because this location is needed for register args
1136 // Space for: fpArgs + regArgs + linkage - ret (already on stack)
1137 subq $ 8*16 + 6*8 + (4-1)*8, %rsp
1139 // Save return address in linkage area.
1140 movq %r11, 16+LINK_AREA(%rsp)
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)
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
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)
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
1173 // Retrieve return address from linkage area
1174 movq 16+LINK_AREA(%rsp), %r11
1176 subq $ 8*16 + 6*8 + (4-1)*8, %rsp
1177 // Put return address back
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
1188 END_ENTRY __objc_msgForward
1191 ENTRY __objc_msgForward_stret
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
1200 // Die if forwarding "forward::"
1201 cmpq %a3, _FwdSel(%rip)
1202 je LMsgForwardStretError
1204 // Record current return address. It will be copied elsewhere in
1205 // the marg_list because this location is needed for register args
1209 // Space for: fpArgs + regArgs + linkage - ret (already on stack)
1210 subq $ 8*16 + 6*8 + (4-1)*8, %rsp
1212 // Save return address in linkage area.
1213 movq %r11, 16+LINK_AREA(%rsp)
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)
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
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)
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
1244 call _objc_msgSend // forward:: is NOT struct-return
1246 // Retrieve return address from linkage area
1247 movq 16+LINK_AREA(%rsp), %r11
1249 subq $ 8*16 + 6*8 + (4-1)*8, %rsp
1250 // Put return address back
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
1261 END_ENTRY __objc_msgForward_stret
1264 ENTRY _method_invoke
1266 movq method_imp(%a2), %r11
1267 movq method_name(%a2), %a2
1270 END_ENTRY _method_invoke
1273 ENTRY _method_invoke_stret
1275 movq method_imp(%a3), %r11
1276 movq method_name(%a3), %a3
1279 END_ENTRY _method_invoke_stret