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 * objc-msg-ppc64.s - PowerPC code to support objc messaging.
25 * Based on objc-msg-ppc.s, copyright 1988-1996 NeXT Software, Inc.
26 ********************************************************************/
34 /********************************************************************
35 * Data used by the ObjC runtime.
37 ********************************************************************/
40 ; Substitute receiver for messages sent to nil (usually also nil)
41 ; id _objc_nilReceiver
43 .private_extern __objc_nilReceiver
47 ; 8 bytes of zero, for floating-point zero return
51 ; _objc_entryPoints and _objc_exitPoints are used by method dispatch
52 ; caching code to figure out whether any threads are actively
53 ; in the cache for dispatching. The labels surround the asm code
54 ; that do cache lookups. The tables are zero-terminated.
55 .private_extern _objc_entryPoints
58 .quad __cache_getMethod
60 .quad _objc_msgSend_stret
61 .quad _objc_msgSendSuper
62 .quad _objc_msgSendSuper_stret
63 .quad _objc_msgSend_rtp
66 .private_extern _objc_exitPoints
71 .quad LMsgSendStretExit
72 .quad LMsgSendSuperExit
73 .quad LMsgSendSuperStretExit
74 .quad _objc_msgSend_rtp_exit
78 * Handcrafted dyld stubs for each external call.
79 * They should be converted into a local branch after linking. aB.
82 /* asm_help.h version is not what we want */
85 #define CALL_EXTERN(name) bl L ## name ## $stub
87 #define LAZY_PIC_FUNCTION_STUB(name) \
89 .section __TEXT, __picsymbol_stub, symbol_stubs, pure_instructions, 32 @\
90 L ## name ## $stub: @\
91 .indirect_symbol name @\
93 bcl 20,31,L0$ ## name @\
96 addis r11,r11,ha16(L ## name ## $lazy_ptr-L0$ ## name) @\
98 ldu r12,lo16(L ## name ## $lazy_ptr-L0$ ## name)(r11) @\
102 .lazy_symbol_pointer @\
103 L ## name ## $lazy_ptr: @\
104 .indirect_symbol name @\
105 .quad dyld_stub_binding_helper
107 ; _class_lookupMethodAndLoadCache
108 LAZY_PIC_FUNCTION_STUB(__class_lookupMethodAndLoadCache)
111 ; _objc_fixupMessageRef
112 LAZY_PIC_FUNCTION_STUB(__objc_fixupMessageRef)
116 LAZY_PIC_FUNCTION_STUB(___objc_error) /* No stub needed */
120 LAZY_PIC_FUNCTION_STUB(mcount)
124 /********************************************************************
126 * Structure definitions.
128 ********************************************************************/
130 ; objc_super parameter to sendSuper
134 ; Selected field offsets in class structure
143 #define METHOD_NAME 0
144 #define METHOD_IMP 16
149 #define BUCKETS 8 // variable length array
151 #if defined(OBJC_INSTRUMENTED)
152 ; Cache instrumentation data, follows buckets
154 #define hitProbes hitCount + 4
155 #define maxHitProbes hitProbes + 4
156 #define missCount maxHitProbes + 4
157 #define missProbes missCount + 4
158 #define maxMissProbes missProbes + 4
159 #define flushCount maxMissProbes + 4
160 #define flushedEntries flushCount + 4
163 /********************************************************************
167 ********************************************************************/
169 // In case the implementation is _objc_msgForward, indicate to it
170 // whether the method was invoked as a word-return or struct-return.
171 // The li instruction costs nothing because it fits into spare
172 // processor cycles. We choose to make the MsgSend indicator non-zero
173 // as r11 is already guaranteed non-zero for a cache hit (no li needed).
175 #define kFwdMsgSend 1
176 #define kFwdMsgSendStret 0
179 /********************************************************************
181 * Useful macros. Macros are used instead of subroutines, for speed.
183 ********************************************************************/
185 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
187 ; LOAD_STATIC_WORD targetReg, symbolName, LOCAL_SYMBOL | EXTERNAL_SYMBOL
189 ; Load the value of the named static data word.
191 ; Takes: targetReg - the register, other than r0, to load
192 ; symbolName - the name of the symbol
193 ; LOCAL_SYMBOL - symbol name used as-is
194 ; EXTERNAL_SYMBOL - symbol name gets nonlazy treatment
196 ; Eats: r0 and targetReg
197 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
199 ; Values to specify whether the symbols is plain or nonlazy
200 #define LOCAL_SYMBOL 0
201 #define EXTERNAL_SYMBOL 1
203 .macro LOAD_STATIC_WORD
206 bcl 20,31,1f ; 31 is cr7[so]
209 .if $2 == EXTERNAL_SYMBOL
210 addis $0,$0,ha16(L$1-1b)
211 ld $0,lo16(L$1-1b)($0)
213 .elseif $2 == LOCAL_SYMBOL
214 addis $0,$0,ha16($1-1b)
215 ld $0,lo16($1-1b)($0)
217 !!! Unknown symbol type !!!
222 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
224 ; LEA_STATIC_DATA targetReg, symbolName, LOCAL_SYMBOL | EXTERNAL_SYMBOL
226 ; Load the address of the named static data.
228 ; Takes: targetReg - the register, other than r0, to load
229 ; symbolName - the name of the symbol
230 ; LOCAL_SYMBOL - symbol is local to this module
231 ; EXTERNAL_SYMBOL - symbol is imported from another module
233 ; Eats: r0 and targetReg
234 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
236 .macro LEA_STATIC_DATA
238 bcl 20,31,1f ; 31 is cr7[so]
241 .if $2 == EXTERNAL_SYMBOL
242 addis $0,$0,ha16(L$1-1b)
243 ld $0,lo16(L$1-1b)($0)
244 .elseif $2 == LOCAL_SYMBOL
245 addis $0,$0,ha16($1-1b)
246 addi $0,$0,lo16($1-1b)
248 !!! Unknown symbol type !!!
253 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
257 ; Assembly directives to begin an exported function.
258 ; We align on cache boundaries for these few functions.
260 ; Takes: functionName - name of the exported function
261 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
270 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
272 ; END_ENTRY functionName
274 ; Assembly directives to end an exported function. Just a placeholder,
275 ; a close-parenthesis for ENTRY, until it is needed for something.
277 ; Takes: functionName - name of the exported function
278 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
284 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
286 ; FixupMessageRef receiver, super, ref
288 ; Look up a method and fix up a message ref.
291 ; receiver = receiver register
292 ; super = register address of objc_super2 struct or NULL
293 ; ref = message ref register
294 ; These arguments must use the REGx macros. Some combinations
301 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
303 ; $0 = receiver register
304 ; $1 = register address of objc_super2 struct, or NULL
305 ; $2 = message ref register
306 ; Returns imp in r12 and ctr.
307 ; 3,2,4 4,2,5 2,3,4 2,4,5
325 error unknown register
339 error unknown register
353 error unknown register
358 .macro FixupMessageRef
363 ; Save parameter registers
373 ; Save fp parameter registers
389 stdu r1,-120-(13*8)(r1) ; must be 16-byte aligned
391 .if REG5 != $1 & REG5 != $0 & REG4 != $0
395 .elseif REG3 != $1 & REG3 != $2 & REG4 != $2
400 error register collision
403 CALL_EXTERN(__objc_fixupMessageRef)
405 ; Save returned IMP in r12 and ctr
416 ; Restore fp parameter registers
431 ; Restore parameter registers
445 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
447 ; CacheLookup selectorRegister, cacheMissLabel
449 ; Locate the implementation for a selector in a class method cache.
452 ; $0 = register containing selector (r4 or r5 ONLY);
453 ; cacheMissLabel = label to branch to iff method is not cached
454 ; r12 = class whose cache is to be searched
456 ; On exit: (found) method triplet in r2, imp in r12, r11 is non-zero
457 ; (not found) jumps to cacheMissLabel
459 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
463 #if defined(OBJC_INSTRUMENTED)
464 ; when instrumented, we use r6 and r7
465 std r6,72(r1) ; save r6 for use as cache pointer
466 std r7,80(r1) ; save r7 for use as probe count
467 li r7,0 ; no probes so far!
470 ld r2,CACHE(r12) ; cache = class->cache
471 std r9,96(r1) ; save r9
473 #if defined(OBJC_INSTRUMENTED)
474 mr r6,r2 ; save cache pointer
477 lwz r11,MASK(r2) ; mask = cache->mask
478 addi r0,r2,BUCKETS ; buckets = cache->buckets
479 sldi r11,r11,3 ; r11 = mask << 3
480 and r9,$0,r11 ; bytes = sel & (mask<<3)
482 #if defined(OBJC_INSTRUMENTED)
486 ; r6 = cache, r7 = probeCount
487 lwz r9,MASK(r6) ; entryCount = mask + 1
489 sldi r9,r9,2 ; tableSize = entryCount * sizeof(entry)
490 addi r9,r9,BUCKETS ; offset = buckets + tableSize
491 add r11,r6,r9 ; cacheData = &cache->buckets[mask+1]
492 ld r9,missCount(r11) ; cacheData->missCount += 1
494 std r9,missCount(r11) ;
495 ld r9,missProbes(r11) ; cacheData->missProbes += probeCount
497 std r9,missProbes(r11) ;
498 ld r9,maxMissProbes(r11) ; if (probeCount > cacheData->maxMissProbes)
499 cmpld r7,r9 ; maxMissProbes = probeCount
501 std r7,maxMissProbes(r11) ;
503 ld r6,72(r1) ; restore r6
504 ld r7,80(r1) ; restore r7
506 b $1 ; goto cacheMissLabel
511 #if defined(OBJC_INSTRUMENTED)
512 addi r7,r7,1 ; probeCount += 1
515 ldx r2,r9,r0 ; method = buckets[bytes/8]
516 addi r9,r9,8 ; bytes += 8
517 cmpldi r2,0 ; if (method == NULL)
518 #if defined(OBJC_INSTRUMENTED)
521 beq- $1 ; goto cacheMissLabel
524 ld r12,METHOD_NAME(r2) ; name = method->method_name
525 and r9,r9,r11 ; bytes &= (mask<<3)
526 cmpld r12,$0 ; if (name != selector)
527 bne- LLoop_$0_$1 ; goto loop
529 ; cache hit, r2 == method triplet address
530 ; Return triplet in r2 and imp in r12
531 ld r12,METHOD_IMP(r2) ; imp = method->method_imp
533 #if defined(OBJC_INSTRUMENTED)
534 ; r6 = cache, r7 = probeCount
535 lwz r9,MASK(r6) ; entryCount = mask + 1
537 sldi r9,r9,2 ; tableSize = entryCount * sizeof(entry)
538 addi r9,r9,BUCKETS ; offset = buckets + tableSize
539 add r11,r6,r9 ; cacheData = &cache->buckets[mask+1]
540 lwz r9,hitCount(r11) ; cache->hitCount += 1
542 stw r9,hitCount(r11) ;
543 lwz r9,hitProbes(r11) ; cache->hitProbes += probeCount
545 stw r9,hitProbes(r11) ;
546 lwz r9,maxHitProbes(r11) ; if (probeCount > cache->maxMissProbes)
547 cmplw r7,r9 ;maxMissProbes = probeCount
549 stw r7,maxHitProbes(r11) ;
551 ld r6,72(r1) ; restore r6
552 ld r7,80(r1) ; restore r7
555 ld r9,96(r1) ; restore r9
559 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
561 ; CacheLookup cache locking - 2001-11-12
562 ; The collecting cache mechanism precludes the need for a cache lock
563 ; in objc_msgSend. The cost of the collecting cache is small: a few
564 ; K of memory for uncollected caches, and less than 1 ms per collection.
565 ; A large app will only run collection a few times.
566 ; Using the code below to lock the cache almost doubles messaging time,
567 ; costing several seconds of CPU across several minutes of operation.
568 ; The code below probably could be improved, but almost all of the
569 ; locking slowdown is in the sync and isync.
571 ; 40 million message test times (G4 1x667):
572 ; no lock 4.390u 0.030s 0:04.59 96.2% 0+0k 0+1io 0pf+0w
573 ; with lock 9.120u 0.010s 0:09.83 92.8% 0+0k 0+0io 0pf+0w
575 ;; LockCache mask_dest, cache
577 ; ; LOCKED mask is NEGATIVE
578 ; lwarx $0, mask, $1 ; mask = reserve(cache->mask)
580 ; blt .-8 ; try again if mask < 0
582 ; stwcx. r0, mask, $1 ; cache->mask = -mask ($0 keeps +mask)
583 ; bne .-20 ; try again if lost reserve
584 ; isync ; flush prefetched instructions after locking
587 ;; UnlockCache (mask<<2), cache
589 ; sync ; finish previous instructions before unlocking
590 ; srwi r0, $0, 2 ; r0 = (mask<<2) >> 2
591 ; stw r0, mask($1) ; cache->mask = +mask
594 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
597 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
600 ; MethodTableLookup WORD_RETURN | STRUCT_RETURN, MSG_SEND | MSG_SENDSUPER
602 ; Takes: WORD_RETURN (r3 is first parameter)
603 ; STRUCT_RETURN (r3 is structure return address, r4 is first parameter)
604 ; MSG_SEND (first parameter is receiver)
605 ; MSG_SENDSUPER (first parameter is address of objc_super structure)
607 ; Eats: r0, r2, r11, r12
608 ; On exit: restores r9 saved by CacheLookup
610 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
612 ; Values to specify to method lookup macros whether the return type of
613 ; the method is an integer or structure.
614 #define WORD_RETURN 0
615 #define STRUCT_RETURN 1
617 ; Values to specify to method lookup macros whether the return type of
618 ; the method is an integer or structure.
620 #define MSG_SENDSUPER 1
622 .macro MethodTableLookup
626 std r3, 48(r1) ; save arguments
632 ; r9 was saved by CacheLookup
635 ; Save the FP parameter registers.
636 ; We do not spill vector argument registers. This is
637 ; harmless because vector parameters are unsupported.
652 stdu r1,-120-(13*8)(r1) ; grow the stack. Must be 16-byte-aligned.
654 ; Pass parameters to __class_lookupMethodAndLoadCache. First parameter is
655 ; the class pointer. Second parameter is the selector. Where they come
656 ; from depends on who called us. In the int return case, the selector is
658 .if $0 == WORD_RETURN ; WORD_RETURN
659 .if $1 == MSG_SEND ; MSG_SEND
660 ld r3,ISA(r3) ; class = receiver->isa
661 .else ; MSG_SENDSUPER
662 ld r3,CLASS(r3) ; class = super->class
665 .else ; STRUCT_RETURN
666 .if $1 == MSG_SEND ; MSG_SEND
667 ld r3,ISA(r4) ; class = receiver->isa
668 .else ; MSG_SENDSUPER
669 ld r3,CLASS(r4) ; class = super->class
671 mr r4,r5 ; selector = selector
674 ; We code the call inline rather than using the CALL_EXTERN macro because
675 ; that leads to a lot of extra unnecessary and inefficient instructions.
676 CALL_EXTERN(__class_lookupMethodAndLoadCache)
678 mr r12,r3 ; copy implementation to r12
679 mtctr r3 ; copy imp to ctr
680 ld r1,0(r1) ; restore the stack pointer
682 mtlr r0 ; restore return pc
684 ; Restore FP parameter registers
699 ld r3, 48(r1) ; restore parameter registers
705 ld r9, 96(r1) ; r9 was saved by CacheLookup
710 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
714 ; Macro to call mcount function in profiled builds.
716 ; NOTE: Makes sure to save/restore r11 and r12, even though they
717 ; are not defined to be volatile, because they are used during
720 ; Takes: lr Callers return PC
723 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
727 mflr r0 ; save return pc
730 stdu r1,-304(r1) ; push aligned areas, set stack link
732 std r3, 112(r1) ; save all volatile registers
740 std r11,176(r1) ; save r11 and r12, too
757 mr r3, r0 ; pass our callers address
761 ld r3, 112(r1) ; restore all volatile registers
769 ld r11,176(r1) ; restore r11 and r12, too
786 ld r1, 0(r1) ; restore the stack pointer
788 mtlr r0 ; restore return pc
793 /********************************************************************
794 * Method _cache_getMethod(Class cls, SEL sel, IMP objc_msgForward_imp)
796 * On entry: r3 = class whose cache is to be searched
797 * r4 = selector to search for
798 * r5 = _objc_msgForward IMP
800 * If found, returns method triplet pointer.
801 * If not found, returns NULL.
803 * NOTE: _cache_getMethod never returns any cache entry whose implementation
804 * is _objc_msgForward. It returns NULL instead. This prevents thread-
805 * safety and memory management bugs in _class_lookupMethodAndLoadCache.
806 * See _class_lookupMethodAndLoadCache for details.
808 * _objc_msgForward is passed as a parameter because it's more efficient
809 * to do the (PIC) lookup once in the caller than repeatedly here.
810 ********************************************************************/
812 .private_extern __cache_getMethod
813 ENTRY __cache_getMethod
814 ; do profiling if enabled
818 mr r12,r3 ; move class to r12 for CacheLookup
819 CacheLookup r4, LGetMethodMiss
821 ; cache hit, method triplet in r2 and imp in r12
822 cmpld r12, r5 ; check for _objc_msgForward
823 mr r3, r2 ; optimistically get the return value
824 bnelr ; Not _objc_msgForward, return the triplet address
827 li r3, 0 ; cache miss or _objc_msgForward, return nil
831 END_ENTRY __cache_getMethod
834 /********************************************************************
835 * IMP _cache_getImp(Class cls, SEL sel)
837 * On entry: r3 = class whose cache is to be searched
838 * r4 = selector to search for
840 * If found, returns method implementation.
841 * If not found, returns NULL.
842 ********************************************************************/
844 .private_extern __cache_getImp
846 ; do profiling if enabled
850 mr r12,r3 ; move class to r12 for CacheLookup
851 CacheLookup r4, LGetImpMiss
853 ; cache hit, method triplet in r2 and imp in r12
854 mr r3, r12 ; return method imp address
858 ; cache miss, return nil
859 li r3, 0 ; return nil
863 END_ENTRY __cache_getImp
866 /********************************************************************
867 * id objc_msgSend(id self,
871 * On entry: r3 is the message receiver,
873 ********************************************************************/
875 ; WARNING - This code may be copied as is to the Objective-C runtime pages.
876 ; The code is copied by rtp_set_up_objc_msgSend() from the
877 ; beginning to the blr marker just prior to the cache miss code.
878 ; Do not add callouts, global variable accesses, or rearrange
879 ; the code without updating rtp_set_up_objc_msgSend.
881 ; Absolute symbols bounding the runtime page version of objc_msgSend.
882 _objc_msgSend_rtp = 0xfffffffffffeff00
883 _objc_msgSend_rtp_exit = 0xfffffffffffeff00+0x100
886 ; check whether receiver is nil or selector is to be ignored
887 cmpldi r3,0 ; receiver nil?
889 xoris r11, r11, ((~kIgnore >> 16) & 0xffff)
890 beq- LMsgSendNilSelf ; if nil receiver, call handler or return nil
891 ld r12,ISA(r3) ; class = receiver->isa
892 cmpldi r11, (~kIgnore & 0xffff)
893 beqlr- ; if ignored selector, return self immediately
895 ; guaranteed non-nil entry point (disabled for now)
896 ; .globl _objc_msgSendNonNil
897 ; _objc_msgSendNonNil:
899 ; do profiling when enabled
902 ; receiver is non-nil: search the cache
904 ; class is already in r12
905 CacheLookup r4, LMsgSendCacheMiss
906 ; CacheLookup placed imp in r12
908 ; r11 guaranteed non-zero on exit from CacheLookup with a hit
909 // li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
912 ; WARNING - The first six instructions of LMsgSendNilSelf are
913 ; rewritten when objc_msgSend is copied to the runtime pages.
914 ; These instructions must be maintained AS IS unless the code in
915 ; rtp_set_up_objc_msgSend is also updated.
916 ; * `mflr r0` must not be changed (not even to use a different register)
917 ; * the load of _objc_nilReceiver value must remain six insns long
918 ; * the value of _objc_nilReceiver must continue to be loaded into r11
920 ; message sent to nil: redirect to nil receiver, if any
922 ; DO NOT CHANGE THE NEXT SIX INSTRUCTIONS - see note above
923 mflr r0 ; save return address
924 bcl 20,31,1f ; 31 is cr7[so]
926 addis r11,r11,ha16(__objc_nilReceiver-1b)
927 ld r11,lo16(__objc_nilReceiver-1b)(r11)
928 mtlr r0 ; restore return address
929 ; DO NOT CHANGE THE PREVIOUS SIX INSTRUCTIONS - see note above
931 cmpldi r11,0 ; return nil if no new receiver
932 beq LMsgSendReturnZero
934 mr r3,r11 ; send to new receiver
935 ld r12,ISA(r11) ; class = receiver->isa
941 ; fixme this breaks RTP
942 LEA_STATIC_DATA r11, L_zero, LOCAL_SYMBOL
946 ; WARNING - This blr marks the end of the copy to the ObjC runtime pages and
947 ; also marks the beginning of the cache miss code. Do not move
948 ; around without checking the ObjC runtime pages initialization code.
951 ; cache miss: go search the method lists
953 MethodTableLookup WORD_RETURN, MSG_SEND
954 li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
958 END_ENTRY _objc_msgSend
962 ENTRY _objc_msgSend_fixup
966 beq- LMsgSendFixupNilSelf
969 ; r2 = 0 (not msgSend_super)
970 ; r4 = address of message ref
971 FixupMessageRef REG3, REG2, REG4
973 ; imp is in r12 and ctr
974 ; Load _cmd from the message_ref
976 ; Be ready for objc_msgForward
980 LMsgSendFixupNilSelf:
983 LEA_STATIC_DATA r11, L_zero, LOCAL_SYMBOL
988 END_ENTRY _objc_msgSend_fixup
991 ENTRY _objc_msgSend_fixedup
992 ; Load _cmd from the message_ref
995 END_ENTRY _objc_msgSend_fixedup
999 /********************************************************************
1001 * double objc_msgSend_fpret(id self, SEL op, ...);
1003 ********************************************************************/
1005 ENTRY _objc_msgSend_fpret
1007 END_ENTRY _objc_msgSend_fpret
1009 /********************************************************************
1010 * struct_type objc_msgSend_stret(id self,
1014 * objc_msgSend_stret is the struct-return form of msgSend.
1015 * The ABI calls for r3 to be used as the address of the structure
1016 * being returned, with the parameters in the succeeding registers.
1018 * On entry: r3 is the address where the structure is returned,
1019 * r4 is the message receiver,
1020 * r5 is the selector
1021 ********************************************************************/
1023 ENTRY _objc_msgSend_stret
1024 ; check whether receiver is nil
1025 cmpldi r4,0 ; receiver nil?
1026 beq LMsgSendStretNilSelf ; if so, call handler or just return
1028 ; guaranteed non-nil entry point (disabled for now)
1029 ; .globl _objc_msgSendNonNil_stret
1030 ; _objc_msgSendNonNil_stret:
1032 ; do profiling when enabled
1035 ; receiver is non-nil: search the cache
1036 LMsgSendStretReceiverOk:
1037 ld r12, ISA(r4) ; class = receiver->isa
1038 CacheLookup r5, LMsgSendStretCacheMiss
1039 ; CacheLookup placed imp in r12
1041 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
1044 ; cache miss: go search the method lists
1045 LMsgSendStretCacheMiss:
1046 MethodTableLookup STRUCT_RETURN, MSG_SEND
1047 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
1050 ; message sent to nil: redirect to nil receiver, if any
1051 LMsgSendStretNilSelf:
1052 mflr r0 ; load new receiver
1053 bcl 20,31,1f ; 31 is cr7[so]
1055 addis r11,r11,ha16(__objc_nilReceiver-1b)
1056 ld r11,lo16(__objc_nilReceiver-1b)(r11)
1059 cmpldi r11,0 ; return nil if no new receiver
1062 mr r4,r11 ; send to new receiver
1063 b LMsgSendStretReceiverOk
1066 END_ENTRY _objc_msgSend_stret
1070 ENTRY _objc_msgSend_stret_fixup
1074 beqlr- ; return if nil receiver
1077 ; r2 = 0 (not msgSend_super)
1078 ; r5 = address of message ref
1079 FixupMessageRef REG4, REG2, REG5
1081 ; imp is in r12 and ctr
1082 ; Load _cmd from the message_ref
1084 ; Be ready for objc_msgForward
1085 li r11, kFwdMsgSendStret
1088 END_ENTRY _objc_msgSend_stret_fixup
1091 ENTRY _objc_msgSend_stret_fixedup
1092 ; Load _cmd from the message_ref
1094 b _objc_msgSend_stret
1095 END_ENTRY _objc_msgSend_stret_fixedup
1099 /********************************************************************
1100 * id objc_msgSendSuper(struct objc_super *super,
1104 * struct objc_super {
1108 ********************************************************************/
1111 ENTRY _objc_msgSendSuper
1112 ; do profiling when enabled
1115 ; check whether selector is to be ignored
1117 xoris r11, r11, ((~kIgnore >> 16) & 0xffff)
1118 ld r12,CLASS(r3) ; class = super->class
1119 cmpldi r11, (~kIgnore & 0xffff)
1120 beqlr- ; if ignored selector, return self immediately
1123 ; class is already in r12
1124 CacheLookup r4, LMsgSendSuperCacheMiss
1125 ; CacheLookup placed imp in r12
1127 ld r3,RECEIVER(r3) ; receiver is the first arg
1128 ; r11 guaranteed non-zero after cache hit
1129 ; li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
1132 ; cache miss: go search the method lists
1133 LMsgSendSuperCacheMiss:
1134 MethodTableLookup WORD_RETURN, MSG_SENDSUPER
1135 ld r3,RECEIVER(r3) ; receiver is the first arg
1136 li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
1139 ; ignored selector: return self
1140 LMsgSendSuperIgnored:
1145 END_ENTRY _objc_msgSendSuper
1149 ENTRY _objc_msgSendSuper2_fixup
1154 ; r3 = address of objc_super2
1155 ; r4 = address of message ref
1156 FixupMessageRef REG2, REG3, REG4
1158 ; imp is in r12 and ctr
1159 ; Load _cmd from the message_ref
1161 ; Load receiver from objc_super2
1165 END_ENTRY _objc_msgSendSuper2_fixup
1168 ENTRY _objc_msgSendSuper2_fixedup
1169 ; objc_super->class is superclass of the class to search
1170 ld r11, CLASS(r3) ; cls = objc_super->class
1171 ld r4, 8(r4) ; load _cmd from message_ref
1172 ld r11, 8(r11) ; cls = cls->superclass
1173 std r11, CLASS(r3) ; objc_super->class = cls
1174 ; objc_super->class is now the class to search
1175 b _objc_msgSendSuper
1176 END_ENTRY _objc_msgSendSuper2_fixedup
1180 /********************************************************************
1181 * struct_type objc_msgSendSuper_stret(objc_super *super,
1185 * struct objc_super {
1191 * objc_msgSendSuper_stret is the struct-return form of msgSendSuper.
1192 * The ABI calls for r3 to be used as the address of the structure
1193 * being returned, with the parameters in the succeeding registers.
1195 * On entry: r3 is the address to which to copy the returned structure,
1196 * r4 is the address of the objc_super structure,
1197 * r5 is the selector
1198 ********************************************************************/
1200 ENTRY _objc_msgSendSuper_stret
1201 ; do profiling when enabled
1205 ld r12,CLASS(r4) ; class = super->class
1206 CacheLookup r5, LMsgSendSuperStretCacheMiss
1207 ; CacheLookup placed imp in r12
1209 ld r4,RECEIVER(r4) ; receiver is the first arg
1210 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
1213 ; cache miss: go search the method lists
1214 LMsgSendSuperStretCacheMiss:
1215 MethodTableLookup STRUCT_RETURN, MSG_SENDSUPER
1216 ld r4,RECEIVER(r4) ; receiver is the first arg
1217 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
1220 LMsgSendSuperStretExit:
1221 END_ENTRY _objc_msgSendSuper_stret
1225 ENTRY _objc_msgSendSuper2_stret_fixup
1230 ; r4 = address of objc_super2
1231 ; r5 = address of message ref
1232 FixupMessageRef REG2, REG4, REG5
1234 ; imp is in r12 and ctr
1235 ; Load _cmd from the message_ref
1237 ; Load receiver from objc_super2
1241 END_ENTRY _objc_msgSendSuper2_stret_fixup
1244 ENTRY _objc_msgSendSuper2_stret_fixedup
1245 ; objc_super->class is superclass of the class to search
1246 ld r11, CLASS(r4) ; cls = objc_super->class
1247 ld r5, 8(r5) ; load _cmd from message_ref
1248 ld r11, 8(r11) ; cls = cls->superclass
1249 std r11, CLASS(r4) ; objc_super->class = cls
1250 ; objc_super->class is now the class to search
1251 b _objc_msgSendSuper_stret
1252 END_ENTRY _objc_msgSendSuper2_stret_fixedup
1256 /********************************************************************
1258 * Out-of-band parameter r11 indicates whether it was objc_msgSend or
1259 * objc_msgSend_stret that triggered the message forwarding. The
1261 * Iff r11 == kFwdMsgSend, it is the word-return (objc_msgSend) case,
1262 * and the interface is:
1264 * id _objc_msgForward(id self,
1268 * Iff r11 == kFwdMsgSendStret, it is the structure-return
1269 * (objc_msgSend_stret) case, and the interface is:
1271 * struct_type _objc_msgForward(id self,
1275 * There are numerous reasons why it is better to have one
1276 * _objc_msgForward, rather than adding _objc_msgForward_stret.
1277 * The best one is that _objc_msgForward is the method that
1278 * gets cached when respondsToMethod returns false, and it
1279 * wouldnt know which one to use.
1281 * Sends the message to a method having the signature
1283 * - forward:(SEL)sel :(marg_list)args;
1285 * But the marg_list is prepended with the 13 double precision
1286 * floating point registers that could be used as parameters into
1287 * the method (fortunately, the same registers are used for either
1288 * single or double precision floats). These registers are layed
1289 * down by _objc_msgForward, and picked up by _objc_msgSendv. So
1290 * the "marg_list" is actually:
1292 * typedef struct objc_sendv_margs {
1293 * double floatingPointArgs[13];
1294 * intptr_t linkageArea[6];
1295 * intptr_t registerArgs[8];
1296 * intptr_t stackArgs[variable];
1299 ********************************************************************/
1301 ; _FwdSel is @selector(forward::), set up in map_images().
1302 ; ALWAYS dereference _FwdSel to get to "forward::" !!
1305 .private_extern _FwdSel
1310 LUnkSelStr: .ascii "Does not recognize selector %s\0"
1314 .private_extern __objc_forward_handler
1315 __objc_forward_handler: .quad 0
1319 .private_extern __objc_forward_stret_handler
1320 __objc_forward_stret_handler: .quad 0
1322 ENTRY __objc_msgForward
1323 ; do profiling when enabled
1326 ; Check return type (stret or not)
1327 cmpldi r11, kFwdMsgSendStret
1328 beq LMsgForwardStretSel
1331 ; Call user handler, if any
1332 LOAD_STATIC_WORD r12, __objc_forward_handler, LOCAL_SYMBOL
1335 bnectr ; call _objc_forward_handler if not NULL
1337 mr r11, r3 ; r11 = receiver
1338 mr r12, r4 ; r12 = SEL
1341 LMsgForwardStretSel:
1343 ; Call user handler, if any
1344 LOAD_STATIC_WORD r12, __objc_forward_stret_handler, LOCAL_SYMBOL
1347 bnectr ; call _objc_forward_stret_handler if not NULL
1349 mr r11, r4 ; r11 = receiver
1350 mr r12, r5 ; r12 = SEL
1353 ; r11 is the receiver
1354 ; r12 is the selector
1356 ; Die if forwarding "forward::"
1357 LOAD_STATIC_WORD r2, _FwdSel, LOCAL_SYMBOL
1359 beq LMsgForwardError
1361 ; Save registers to margs
1391 ; Call [receiver forward:sel :margs]
1392 mr r3, r11 ; receiver
1393 mr r4, r2 ; forward::
1395 subi r6,r1,13*8 ; &margs (on stack)
1397 stdu r1,-120-(13*8)(r1) ; push stack frame
1398 bl _objc_msgSend ; [self forward:sel :objc_sendv_margs]
1399 addi r1,r1,120+13*8 ; pop stack frame
1401 ld r0,16(r1) ; restore lr
1407 ; Call __objc_error(receiver, "unknown selector %s", "forward::")
1409 LEA_STATIC_DATA r4, LUnkSelStr, LOCAL_SYMBOL
1411 CALL_EXTERN(___objc_error) ; never returns
1414 END_ENTRY __objc_msgForward
1417 ENTRY _method_invoke
1419 ld r12, METHOD_IMP(r4)
1420 ld r4, METHOD_NAME(r4)
1424 END_ENTRY _method_invoke
1427 ENTRY _method_invoke_stret
1429 ld r12, METHOD_IMP(r5)
1430 ld r5, METHOD_NAME(r5)
1434 END_ENTRY _method_invoke_stret