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@
26 /********************************************************************
28 * objc-msg-ppc.s - PowerPC code to support objc messaging.
30 * Copyright 1988-1996 NeXT Software, Inc.
32 * December 2002 Andy Belk (abelk at apple.com)
33 * Use r2 in the messenger - no longer need r10.
34 * Removed "few args" variants (no longer worth it, especially since gcc3 still
35 * doesn't generate code for them).
36 * Add NonNil entry points to objc_msgSend and objc_msgSend_stret.
37 * Align objc_msgSend et al on cache lines.
38 * Replace CALL_EXTERN references (which caused excess mflr/mtlr usage) with
39 * dyld-stub-compatible versions: shorter and become local branches within a dylib.
41 * 8-Nov-2000 Laurent Ramontianu (ramontia@apple.com)
42 * Added "few args" params. to CacheLookup and MethodTableLookup
43 * Added the alternate entry points:
44 * objc_msgSendFew, objc_msgSendFew_stret,
45 * objc_msgSendSuperFew, objc_msgSendSuperFew_stret
47 * 18-Jun-97 David Harrison (harrison@apple.com)
50 * 1-May-97 Umesh Vaishampayan (umeshv@NeXT.com)
51 * Incorporated locking code fixes from
52 * David Harrison (harrison@NeXT.com)
54 * 2-Apr-97 Umesh Vaishampayan (umeshv@NeXT.com)
55 * Incorporated changes for messenger with struct return
56 * Cleaned up the labels to use local labels
57 * Fixed bug in the msgSendSuper that did not do the locking.
59 * 31-Dec-96 Umesh Vaishampayan (umeshv@NeXT.com)
61 ********************************************************************/
67 /********************************************************************
68 * Data used by the ObjC runtime.
70 ********************************************************************/
73 ; Substitute receiver for messages sent to nil (usually also nil)
74 ; id _objc_nilReceiver
76 .private_extern __objc_nilReceiver
80 ; _objc_entryPoints and _objc_exitPoints are used by method dispatch
81 ; caching code to figure out whether any threads are actively
82 ; in the cache for dispatching. The labels surround the asm code
83 ; that do cache lookups. The tables are zero-terminated.
84 .private_extern _objc_entryPoints
87 .long __cache_getMethod
89 .long _objc_msgSend_stret
90 .long _objc_msgSendSuper
91 .long _objc_msgSendSuper_stret
92 .long _objc_msgSend_rtp
95 .private_extern _objc_exitPoints
100 .long LMsgSendStretExit
101 .long LMsgSendSuperExit
102 .long LMsgSendSuperStretExit
103 .long _objc_msgSend_rtp_exit
107 * Handcrafted dyld stubs for each external call.
108 * They should be converted into a local branch after linking. aB.
111 /* asm_help.h version is not what we want */
114 #if defined(__DYNAMIC__)
116 #define CALL_EXTERN(name) bl L ## name ## $stub
118 #define LAZY_PIC_FUNCTION_STUB(name) \
121 L ## name ## $stub: @\
122 .indirect_symbol name @\
124 bcl 20,31,L0$ ## name @\
127 addis r11,r11,ha16(L ## name ## $lazy_ptr-L0$ ## name) @\
129 lwz r12,lo16(L ## name ## $lazy_ptr-L0$ ## name)(r11) @\
131 addi r11,r11,lo16(L ## name ## $lazy_ptr-L0$ ## name) @\
134 .lazy_symbol_pointer @\
135 L ## name ## $lazy_ptr: @\
136 .indirect_symbol name @\
137 .long dyld_stub_binding_helper
139 #else /* __DYNAMIC__ */
141 #define CALL_EXTERN(name) bl name
143 #define LAZY_PIC_FUNCTION_STUB(name)
145 #endif /* __DYNAMIC__ */
147 ; _class_lookupMethodAndLoadCache
148 LAZY_PIC_FUNCTION_STUB(__class_lookupMethodAndLoadCache)
151 LAZY_PIC_FUNCTION_STUB(___objc_error) /* No stub needed */
155 LAZY_PIC_FUNCTION_STUB(mcount)
159 /********************************************************************
161 * Structure definitions.
163 ********************************************************************/
165 ; objc_super parameter to sendSuper
169 ; Selected field offsets in class structure
174 #define METHOD_NAME 0
180 #define BUCKETS 8 // variable length array
182 #if defined(OBJC_INSTRUMENTED)
183 ; Cache instrumentation data, follows buckets
185 #define hitProbes hitCount + 4
186 #define maxHitProbes hitProbes + 4
187 #define missCount maxHitProbes + 4
188 #define missProbes missCount + 4
189 #define maxMissProbes missProbes + 4
190 #define flushCount maxMissProbes + 4
191 #define flushedEntries flushCount + 4
194 /********************************************************************
198 ********************************************************************/
200 // In case the implementation is _objc_msgForward_internal, indicate to it
201 // whether the method was invoked as a word-return or struct-return.
202 // The li instruction costs nothing because it fits into spare
203 // processor cycles. We choose to make the MsgSend indicator non-zero
204 // as r11 is already guaranteed non-zero for a cache hit (no li needed).
206 #define kFwdMsgSend 1
207 #define kFwdMsgSendStret 0
210 /********************************************************************
212 * Useful macros. Macros are used instead of subroutines, for speed.
214 ********************************************************************/
216 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
218 ; LOAD_STATIC_WORD targetReg, symbolName, LOCAL_SYMBOL | EXTERNAL_SYMBOL
220 ; Load the value of the named static data word.
222 ; Takes: targetReg - the register, other than r0, to load
223 ; symbolName - the name of the symbol
224 ; LOCAL_SYMBOL - symbol name used as-is
225 ; EXTERNAL_SYMBOL - symbol name gets nonlazy treatment
227 ; Eats: r0 and targetReg
228 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
230 ; Values to specify whether the symbols is plain or nonlazy
231 #define LOCAL_SYMBOL 0
232 #define EXTERNAL_SYMBOL 1
234 .macro LOAD_STATIC_WORD
236 #if defined(__DYNAMIC__)
238 bcl 20,31,1f ; 31 is cr7[so]
241 .if $2 == EXTERNAL_SYMBOL
242 addis $0,$0,ha16(L$1-1b)
243 lwz $0,lo16(L$1-1b)($0)
245 .elseif $2 == LOCAL_SYMBOL
246 addis $0,$0,ha16($1-1b)
247 lwz $0,lo16($1-1b)($0)
249 !!! Unknown symbol type !!!
258 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
260 ; LEA_STATIC_DATA targetReg, symbolName, LOCAL_SYMBOL | EXTERNAL_SYMBOL
262 ; Load the address of the named static data.
264 ; Takes: targetReg - the register, other than r0, to load
265 ; symbolName - the name of the symbol
266 ; LOCAL_SYMBOL - symbol is local to this module
267 ; EXTERNAL_SYMBOL - symbol is imported from another module
269 ; Eats: r0 and targetReg
270 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
272 .macro LEA_STATIC_DATA
273 #if defined(__DYNAMIC__)
275 bcl 20,31,1f ; 31 is cr7[so]
278 .if $2 == EXTERNAL_SYMBOL
279 addis $0,$0,ha16(L$1-1b)
280 lwz $0,lo16(L$1-1b)($0)
281 .elseif $2 == LOCAL_SYMBOL
282 addis $0,$0,ha16($1-1b)
283 addi $0,$0,lo16($1-1b)
285 !!! Unknown symbol type !!!
294 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
298 ; Assembly directives to begin an exported function.
299 ; We align on cache boundaries for these few functions.
301 ; Takes: functionName - name of the exported function
302 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
311 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
313 ; END_ENTRY functionName
315 ; Assembly directives to end an exported function. Just a placeholder,
316 ; a close-parenthesis for ENTRY, until it is needed for something.
318 ; Takes: functionName - name of the exported function
319 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
324 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
326 ; PLOCK scratchReg, lockName
328 ; Acquire named spinlock.
330 ; Takes: scratchReg - a register, other than r0, that can be mangled
331 ; lockName - the name of a static, aligned, 32-bit lock word
333 ; Eats: r0 and scratchReg
334 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
337 LEA_STATIC_DATA $0, $1, EXTERNAL_SYMBOL
338 b .+16 ; jump into loop at the reserving check
339 lwz r0,0($0) ; check with fast, less intrusive lwz versus lwarx
340 cmplwi r0,0 ; lock held?
341 bne .-8 ; if so, spin until it appears unlocked
342 lwarx r0,0,$0 ; get lock value, acquire memory reservation
343 cmplwi r0,0 ; lock held?
344 bne .-20 ; if locked, go spin waiting for unlock
345 li r0,1 ; get value that means locked
346 stwcx. r0,0,$0 ; store it iff reservation still holds
347 bne- .-20 ; if reservation was lost, go re-reserve
348 isync ; discard effects of prefetched instructions
351 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
353 ; PUNLOCK scratchReg, lockName
355 ; Release named spinlock.
357 ; Takes: scratchReg - a register, other than r0, that can be mangled
358 ; lockName - the name of a static, aligned, 32-bit lock word
360 ; Eats: r0 and scratchReg
361 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
364 sync ; force out changes before unlocking
365 LEA_STATIC_DATA $0, $1, EXTERNAL_SYMBOL
366 li r0,0 ; get value meaning "unlocked"
367 stw r0,0($0) ; unlock the lock
371 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
373 ; CacheLookup selectorRegister, cacheMissLabel
375 ; Locate the implementation for a selector in a class method cache.
378 ; $0 = register containing selector (r4 or r5 ONLY);
379 ; cacheMissLabel = label to branch to iff method is not cached
380 ; r12 = class whose cache is to be searched
382 ; On exit: (found) method triplet in r2, imp in r12, r11 is non-zero
383 ; (not found) jumps to cacheMissLabel
385 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
389 #if defined(OBJC_INSTRUMENTED)
390 ; when instrumented, we use r6 and r7
391 stw r6,36(r1) ; save r6 for use as cache pointer
392 stw r7,40(r1) ; save r7 for use as probe count
393 li r7,0 ; no probes so far!
396 lwz r2,CACHE(r12) ; cache = class->cache
397 stw r9,48(r1) ; save r9
399 #if defined(OBJC_INSTRUMENTED)
400 mr r6,r2 ; save cache pointer
403 lwz r11,MASK(r2) ; mask = cache->mask
404 addi r0,r2,BUCKETS ; buckets = cache->buckets
405 slwi r11,r11,2 ; r11 = mask << 2
406 and r9,$0,r11 ; bytes = sel & (mask<<2)
408 #if defined(OBJC_INSTRUMENTED)
412 ; r6 = cache, r7 = probeCount
413 lwz r9,MASK(r6) ; entryCount = mask + 1
415 slwi r9,r9,2 ; tableSize = entryCount * sizeof(entry)
416 addi r9,r9,BUCKETS ; offset = buckets + tableSize
417 add r11,r6,r9 ; cacheData = &cache->buckets[mask+1]
418 lwz r9,missCount(r11) ; cacheData->missCount += 1
420 stw r9,missCount(r11) ;
421 lwz r9,missProbes(r11) ; cacheData->missProbes += probeCount
423 stw r9,missProbes(r11) ;
424 lwz r9,maxMissProbes(r11) ; if (probeCount > cacheData->maxMissProbes)
425 cmplw r7,r9 ; maxMissProbes = probeCount
427 stw r7,maxMissProbes(r11) ;
429 lwz r6,36(r1) ; restore r6
430 lwz r7,40(r1) ; restore r7
432 b $1 ; goto cacheMissLabel
437 #if defined(OBJC_INSTRUMENTED)
438 addi r7,r7,1 ; probeCount += 1
441 lwzx r2,r9,r0 ; method = buckets[bytes/4]
442 addi r9,r9,4 ; bytes += 4
443 cmplwi r2,0 ; if (method == NULL)
444 #if defined(OBJC_INSTRUMENTED)
447 beq- $1 ; goto cacheMissLabel
450 lwz r12,METHOD_NAME(r2) ; name = method->method_name
451 and r9,r9,r11 ; bytes &= (mask<<2)
452 cmplw r12,$0 ; if (name != selector)
453 bne- LLoop_$0_$1 ; goto loop
455 ; cache hit, r2 == method triplet address
456 ; Return triplet in r2 and imp in r12
457 lwz r12,METHOD_IMP(r2) ; imp = method->method_imp
459 #if defined(OBJC_INSTRUMENTED)
460 ; r6 = cache, r7 = probeCount
461 lwz r9,MASK(r6) ; entryCount = mask + 1
463 slwi r9,r9,2 ; tableSize = entryCount * sizeof(entry)
464 addi r9,r9,BUCKETS ; offset = buckets + tableSize
465 add r11,r6,r9 ; cacheData = &cache->buckets[mask+1]
466 lwz r9,hitCount(r11) ; cache->hitCount += 1
468 stw r9,hitCount(r11) ;
469 lwz r9,hitProbes(r11) ; cache->hitProbes += probeCount
471 stw r9,hitProbes(r11) ;
472 lwz r9,maxHitProbes(r11) ; if (probeCount > cache->maxMissProbes)
473 cmplw r7,r9 ;maxMissProbes = probeCount
475 stw r7,maxHitProbes(r11) ;
477 lwz r6,36(r1) ; restore r6
478 lwz r7,40(r1) ; restore r7
481 lwz r9,48(r1) ; restore r9
485 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
487 ; CacheLookup cache locking - 2001-11-12
488 ; The collecting cache mechanism precludes the need for a cache lock
489 ; in objc_msgSend. The cost of the collecting cache is small: a few
490 ; K of memory for uncollected caches, and less than 1 ms per collection.
491 ; A large app will only run collection a few times.
492 ; Using the code below to lock the cache almost doubles messaging time,
493 ; costing several seconds of CPU across several minutes of operation.
494 ; The code below probably could be improved, but almost all of the
495 ; locking slowdown is in the sync and isync.
497 ; 40 million message test times (G4 1x667):
498 ; no lock 4.390u 0.030s 0:04.59 96.2% 0+0k 0+1io 0pf+0w
499 ; with lock 9.120u 0.010s 0:09.83 92.8% 0+0k 0+0io 0pf+0w
501 ;; LockCache mask_dest, cache
503 ; ; LOCKED mask is NEGATIVE
504 ; lwarx $0, mask, $1 ; mask = reserve(cache->mask)
506 ; blt .-8 ; try again if mask < 0
508 ; stwcx. r0, mask, $1 ; cache->mask = -mask ($0 keeps +mask)
509 ; bne .-20 ; try again if lost reserve
510 ; isync ; flush prefetched instructions after locking
513 ;; UnlockCache (mask<<2), cache
515 ; sync ; finish previous instructions before unlocking
516 ; srwi r0, $0, 2 ; r0 = (mask<<2) >> 2
517 ; stw r0, mask($1) ; cache->mask = +mask
520 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
523 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
526 ; MethodTableLookup WORD_RETURN | STRUCT_RETURN, MSG_SEND | MSG_SENDSUPER
528 ; Takes: WORD_RETURN (r3 is first parameter)
529 ; STRUCT_RETURN (r3 is structure return address, r4 is first parameter)
530 ; MSG_SEND (first parameter is receiver)
531 ; MSG_SENDSUPER (first parameter is address of objc_super structure)
533 ; Eats: r0, r2, r11, r12
534 ; On exit: restores r9 saved by CacheLookup
536 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
538 ; Values to specify to method lookup macros whether the return type of
539 ; the method is an integer or structure.
540 #define WORD_RETURN 0
541 #define STRUCT_RETURN 1
543 ; Values to specify to method lookup macros whether the return type of
544 ; the method is an integer or structure.
546 #define MSG_SENDSUPER 1
548 .macro MethodTableLookup
552 stw r3, 24(r1) ; save arguments
558 ; r9 was saved by CacheLookup
562 ; Save the FP parameter registers.
563 ; We do not spill vector argument registers. This is
564 ; harmless because vector parameters are unsupported.
579 stwu r1,-56-(13*8)(r1) ; grow the stack. Must be 16-byte-aligned.
581 stwu r1,-64(r1) ; grow the stack. Must be 16-byte-aligned.
584 ; Pass parameters to __class_lookupMethodAndLoadCache. First parameter is
585 ; the class pointer. Second parameter is the selector. Where they come
586 ; from depends on who called us. In the int return case, the selector is
588 .if $0 == WORD_RETURN ; WORD_RETURN
589 .if $1 == MSG_SEND ; MSG_SEND
590 lwz r3,ISA(r3) ; class = receiver->isa
591 .else ; MSG_SENDSUPER
592 lwz r3,CLASS(r3) ; class = super->class
595 .else ; STRUCT_RETURN
596 .if $1 == MSG_SEND ; MSG_SEND
597 lwz r3,ISA(r4) ; class = receiver->isa
598 .else ; MSG_SENDSUPER
599 lwz r3,CLASS(r4) ; class = super->class
601 mr r4,r5 ; selector = selector
604 ; We code the call inline rather than using the CALL_EXTERN macro because
605 ; that leads to a lot of extra unnecessary and inefficient instructions.
606 CALL_EXTERN(__class_lookupMethodAndLoadCache)
608 mr r12,r3 ; copy implementation to r12
609 mtctr r3 ; copy imp to ctr
610 lwz r1,0(r1) ; restore the stack pointer
612 mtlr r0 ; restore return pc
616 ; Restore FP parameter registers
631 lwz r3, 24(r1) ; restore parameter registers
637 lwz r9, 48(r1) ; r9 was saved by CacheLookup
644 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
648 ; Macro to call mcount function in profiled builds.
650 ; NOTE: Makes sure to save/restore r11 and r12, even though they
651 ; are not defined to be volatile, because they are used during
654 ; Takes: lr Callers return PC
657 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
661 mflr r0 ; save return pc
664 stwu r1,-208(r1) ; push aligned areas, set stack link
666 stw r3, 56(r1) ; save all volatile registers
674 stw r11,88(r1) ; save r11 and r12, too
691 mr r3, r0 ; pass our callers address
695 lwz r3, 56(r1) ; restore all volatile registers
703 lwz r11,88(r1) ; restore r11 and r12, too
720 lwz r1,0(r1) ; restore the stack pointer
722 mtlr r0 ; restore return pc
727 /********************************************************************
728 * Method _cache_getMethod(Class cls, SEL sel, IMP objc_msgForward_imp)
730 * On entry: r3 = class whose cache is to be searched
731 * r4 = selector to search for
732 * r5 = _objc_msgForward IMP
734 * If found, returns method triplet pointer.
735 * If not found, returns NULL.
737 * NOTE: _cache_getMethod never returns any cache entry whose implementation
738 * is _objc_msgForward. It returns (Method)1 instead. This prevents thread-
739 * safety and memory management bugs in _class_lookupMethodAndLoadCache.
740 * See _class_lookupMethodAndLoadCache for details.
742 * _objc_msgForward is passed as a parameter because it's more efficient
743 * to do the (PIC) lookup once in the caller than repeatedly here.
744 ********************************************************************/
746 .private_extern __cache_getMethod
747 ENTRY __cache_getMethod
748 ; do profiling if enabled
752 mr r12,r3 ; move class to r12 for CacheLookup
753 CacheLookup r4, LGetMethodMiss
755 ; cache hit, method triplet in r2 and imp in r12
756 cmplw r12, r5 ; check for _objc_msgForward
757 mr r3, r2 ; optimistically get the return value
758 bnelr ; Not _objc_msgForward, return the triplet address
759 li r3, 1 ; Is _objc_msgForward, return (Method)1
763 li r3, 0 ; cache miss or _objc_msgForward, return nil
767 END_ENTRY __cache_getMethod
770 /********************************************************************
771 * IMP _cache_getImp(Class cls, SEL sel)
773 * On entry: r3 = class whose cache is to be searched
774 * r4 = selector to search for
776 * If found, returns method implementation.
777 * If not found, returns NULL.
778 ********************************************************************/
780 .private_extern __cache_getImp
782 ; do profiling if enabled
786 mr r12,r3 ; move class to r12 for CacheLookup
787 CacheLookup r4, LGetImpMiss
789 ; cache hit, method triplet in r2 and imp in r12
790 mr r3, r12 ; return method imp address
794 ; cache miss, return nil
795 li r3, 0 ; return nil
799 END_ENTRY __cache_getImp
802 /********************************************************************
803 * id objc_msgSend(id self,
807 * On entry: r3 is the message receiver,
809 ********************************************************************/
811 ; WARNING - This code may be copied as is to the Objective-C runtime pages.
812 ; The code is copied by rtp_set_up_objc_msgSend() from the
813 ; beginning to the blr marker just prior to the cache miss code.
814 ; Do not add callouts, global variable accesses, or rearrange
815 ; the code without updating rtp_set_up_objc_msgSend.
817 ; Absolute symbols bounding the runtime page version of objc_msgSend.
818 _objc_msgSend_rtp = 0xfffeff00
819 _objc_msgSend_rtp_exit = 0xfffeff00+0x100
821 ENTRY _objc_msgSend_fixup_rtp
822 lwz r4, 4(r4) ; load _cmd from message_ref
824 END_ENTRY _objc_msgSend_fixup_rtp
827 ; check whether receiver is nil or selector is to be ignored
828 cmplwi r3,0 ; receiver nil?
829 xoris r11,r4,((kIgnore>>16) & 0xffff) ; clear hi if equal to ignored
830 cmplwi cr1,r11,(kIgnore & 0xffff) ; selector is to be ignored?
831 beq- LMsgSendNilSelf ; if nil receiver, call handler or return nil
832 lwz r12,ISA(r3) ; class = receiver->isa
833 beqlr- cr1 ; if ignored selector, return self immediately
835 ; guaranteed non-nil entry point (disabled for now)
836 ; .globl _objc_msgSendNonNil
837 ; _objc_msgSendNonNil:
839 ; do profiling when enabled
842 ; receiver is non-nil: search the cache
844 ; class is already in r12
845 CacheLookup r4, LMsgSendCacheMiss
846 ; CacheLookup placed imp in r12
848 ; r11 guaranteed non-zero on exit from CacheLookup with a hit
849 // li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
852 ; WARNING - The first six instructions of LMsgSendNilSelf are
853 ; rewritten when objc_msgSend is copied to the runtime pages.
854 ; These instructions must be maintained AS IS unless the code in
855 ; rtp_set_up_objc_msgSend is also updated.
856 ; * `mflr r0` must not be changed (not even to use a different register)
857 ; * the load of _objc_nilReceiver value must remain six insns long
858 ; * the value of _objc_nilReceiver must continue to be loaded into r11
860 ; message sent to nil: redirect to nil receiver, if any
862 ; DO NOT CHANGE THE NEXT SIX INSTRUCTIONS - see note above
863 mflr r0 ; save return address
864 bcl 20,31,1f ; 31 is cr7[so]
866 addis r11,r11,ha16(__objc_nilReceiver-1b)
867 lwz r11,lo16(__objc_nilReceiver-1b)(r11)
868 mtlr r0 ; restore return address
869 ; DO NOT CHANGE THE PREVIOUS SIX INSTRUCTIONS - see note above
871 cmplwi r11,0 ; return nil if no new receiver
872 beq LMsgSendReturnZero
874 mr r3,r11 ; send to new receiver
875 lwz r12,ISA(r11) ; class = receiver->isa
881 lis r12, ha16(kRTAddress_zero)
882 lfd f1, lo16(kRTAddress_zero)(r12)
883 lfd f2, lo16(kRTAddress_zero)(r12)
885 ; WARNING - This blr marks the end of the copy to the ObjC runtime pages and
886 ; also marks the beginning of the cache miss code. Do not move
887 ; around without checking the ObjC runtime pages initialization code.
890 ; cache miss: go search the method lists
892 MethodTableLookup WORD_RETURN, MSG_SEND
893 li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
897 END_ENTRY _objc_msgSend
899 /********************************************************************
901 * double objc_msgSend_fpret(id self, SEL op, ...);
903 ********************************************************************/
905 ENTRY _objc_msgSend_fpret
907 END_ENTRY _objc_msgSend_fpret
909 /********************************************************************
910 * struct_type objc_msgSend_stret(id self,
914 * objc_msgSend_stret is the struct-return form of msgSend.
915 * The ABI calls for r3 to be used as the address of the structure
916 * being returned, with the parameters in the succeeding registers.
918 * On entry: r3 is the address where the structure is returned,
919 * r4 is the message receiver,
921 ********************************************************************/
923 ENTRY _objc_msgSend_stret_fixup_rtp
924 lwz r5, 4(r5) ; load _cmd from message_ref
925 b _objc_msgSend_stret
926 END_ENTRY _objc_msgSend_stret_fixup_rtp
928 ENTRY _objc_msgSend_stret
929 ; check whether receiver is nil
930 cmplwi r4,0 ; receiver nil?
931 beq LMsgSendStretNilSelf ; if so, call handler or just return
933 ; guaranteed non-nil entry point (disabled for now)
934 ; .globl _objc_msgSendNonNil_stret
935 ; _objc_msgSendNonNil_stret:
937 ; do profiling when enabled
940 ; receiver is non-nil: search the cache
941 LMsgSendStretReceiverOk:
942 lwz r12, ISA(r4) ; class = receiver->isa
943 CacheLookup r5, LMsgSendStretCacheMiss
944 ; CacheLookup placed imp in r12
946 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
949 ; cache miss: go search the method lists
950 LMsgSendStretCacheMiss:
951 MethodTableLookup STRUCT_RETURN, MSG_SEND
952 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
955 ; message sent to nil: redirect to nil receiver, if any
956 LMsgSendStretNilSelf:
957 mflr r0 ; load new receiver
958 bcl 20,31,1f ; 31 is cr7[so]
960 addis r11,r11,ha16(__objc_nilReceiver-1b)
961 lwz r11,lo16(__objc_nilReceiver-1b)(r11)
964 cmplwi r11,0 ; return if no new receiver
967 mr r4,r11 ; send to new receiver
968 b LMsgSendStretReceiverOk
971 END_ENTRY _objc_msgSend_stret
974 /********************************************************************
975 * id objc_msgSendSuper(struct objc_super *super,
979 * struct objc_super {
983 ********************************************************************/
985 ENTRY _objc_msgSendSuper2_fixup_rtp
986 ; objc_super->class is superclass of the class to search
988 lwz r4, 4(r4) ; load _cmd from message_ref
989 lwz r11, 4(r11) ; r11 = cls->super_class
992 END_ENTRY _objc_msgSendSuper2_fixup_rtp
994 ENTRY _objc_msgSendSuper
995 ; do profiling when enabled
998 ; check whether selector is to be ignored
999 xoris r11,r4,((kIgnore>>16) & 0xffff) ; clear hi if to be ignored
1000 cmplwi r11,(kIgnore & 0xffff) ; selector is to be ignored?
1001 lwz r12,CLASS(r3) ; class = super->class
1002 beq- LMsgSendSuperIgnored ; if ignored, return self
1005 ; class is already in r12
1006 CacheLookup r4, LMsgSendSuperCacheMiss
1007 ; CacheLookup placed imp in r12
1009 lwz r3,RECEIVER(r3) ; receiver is the first arg
1010 ; r11 guaranteed non-zero after cache hit
1011 ; li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
1014 ; cache miss: go search the method lists
1015 LMsgSendSuperCacheMiss:
1016 MethodTableLookup WORD_RETURN, MSG_SENDSUPER
1017 lwz r3,RECEIVER(r3) ; receiver is the first arg
1018 li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
1021 ; ignored selector: return self
1022 LMsgSendSuperIgnored:
1027 END_ENTRY _objc_msgSendSuper
1030 /********************************************************************
1031 * struct_type objc_msgSendSuper_stret(objc_super *super,
1035 * struct objc_super {
1041 * objc_msgSendSuper_stret is the struct-return form of msgSendSuper.
1042 * The ABI calls for r3 to be used as the address of the structure
1043 * being returned, with the parameters in the succeeding registers.
1045 * On entry: r3 is the address to which to copy the returned structure,
1046 * r4 is the address of the objc_super structure,
1047 * r5 is the selector
1048 ********************************************************************/
1050 ENTRY _objc_msgSendSuper2_stret_fixup_rtp
1051 ; objc_super->class is superclass of the class to search
1053 lwz r5, 4(r5) ; load _cmd from message_ref
1054 lwz r11, 4(r11) ; r11 = cls->super_class
1056 b _objc_msgSendSuper_stret
1057 END_ENTRY _objc_msgSendSuper2_stret_fixup_rtp
1059 ENTRY _objc_msgSendSuper_stret
1060 ; do profiling when enabled
1064 lwz r12,CLASS(r4) ; class = super->class
1065 CacheLookup r5, LMsgSendSuperStretCacheMiss
1066 ; CacheLookup placed imp in r12
1068 lwz r4,RECEIVER(r4) ; receiver is the first arg
1069 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
1072 ; cache miss: go search the method lists
1073 LMsgSendSuperStretCacheMiss:
1074 MethodTableLookup STRUCT_RETURN, MSG_SENDSUPER
1075 lwz r4,RECEIVER(r4) ; receiver is the first arg
1076 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
1079 LMsgSendSuperStretExit:
1080 END_ENTRY _objc_msgSendSuper_stret
1083 /********************************************************************
1085 * Out-of-band parameter r11 indicates whether it was objc_msgSend or
1086 * objc_msgSend_stret that triggered the message forwarding. The
1088 * Iff r11 == kFwdMsgSend, it is the word-return (objc_msgSend) case,
1089 * and the interface is:
1091 * id _objc_msgForward(id self,
1095 * Iff r11 == kFwdMsgSendStret, it is the structure-return
1096 * (objc_msgSend_stret) case, and the interface is:
1098 * struct_type _objc_msgForward(id self,
1102 * There are numerous reasons why it is better to have one
1103 * _objc_msgForward, rather than adding _objc_msgForward_stret.
1104 * The best one is that _objc_msgForward is the method that
1105 * gets cached when respondsToMethod returns false, and it
1106 * wouldnt know which one to use.
1108 * Sends the message to a method having the signature
1110 * - forward:(SEL)sel :(marg_list)args;
1112 * But the marg_list is prepended with the 13 double precision
1113 * floating point registers that could be used as parameters into
1114 * the method (fortunately, the same registers are used for either
1115 * single or double precision floats). These registers are layed
1116 * down by _objc_msgForward, and picked up by _objc_msgSendv. So
1117 * the "marg_list" is actually:
1119 * typedef struct objc_sendv_margs {
1120 * double floatingPointArgs[13];
1121 * intptr_t linkageArea[6];
1122 * intptr_t registerArgs[8];
1123 * intptr_t stackArgs[variable];
1126 ********************************************************************/
1128 ; _FwdSel is @selector(forward::), set up in map_images().
1129 ; ALWAYS dereference _FwdSel to get to "forward::" !!
1132 .private_extern _FwdSel
1137 LUnkSelStr: .ascii "Does not recognize selector %s\0"
1141 .private_extern __objc_forward_handler
1142 __objc_forward_handler: .long 0
1146 .private_extern __objc_forward_stret_handler
1147 __objc_forward_stret_handler: .long 0
1150 ENTRY __objc_msgForward
1151 // Non-stret version
1153 b __objc_msgForward_internal
1154 END_ENTRY _objc_msgForward
1156 ENTRY __objc_msgForward_stret
1157 // Struct-return version
1158 li r11,kFwdMsgSendStret
1159 b __objc_msgForward_internal
1160 END_ENTRY _objc_msgForward_stret
1163 ENTRY __objc_msgForward_internal
1164 // Method cache version
1166 // THIS IS NOT A CALLABLE C FUNCTION
1167 // Out-of-band register %r11 is zero for stret, nonzero otherwise
1169 ; do profiling when enabled
1172 ; Check return type (stret or not)
1173 cmplwi r11,kFwdMsgSendStret
1174 beq LMsgForwardStretSel
1177 ; Call user handler, if any
1178 LOAD_STATIC_WORD r12, __objc_forward_handler, LOCAL_SYMBOL
1181 bnectr ; call _objc_forward_handler if not NULL
1183 mr r11, r3 ; r11 = receiver
1184 mr r12, r4 ; r12 = SEL
1187 LMsgForwardStretSel:
1189 ; Call user handler, if any
1190 LOAD_STATIC_WORD r12, __objc_forward_stret_handler, LOCAL_SYMBOL
1193 bnectr ; call _objc_forward_stret_handler if not NULL
1195 mr r11, r4 ; r11 = receiver
1196 mr r12, r5 ; r12 = SEL
1199 ; r11 is the receiver
1200 ; r12 is the selector
1202 ; Die if forwarding "forward::"
1203 LOAD_STATIC_WORD r2, _FwdSel, LOCAL_SYMBOL
1205 beq LMsgForwardError
1207 ; Save registers to margs
1237 ; Call [receiver forward:sel :margs]
1238 mr r3, r11 ; receiver
1239 mr r4, r2 ; forward::
1241 subi r6,r1,13*8 ; &margs (on stack)
1243 stwu r1,-56-(13*8)(r1) ; push stack frame
1244 bl _objc_msgSend ; [self forward:sel :objc_sendv_margs]
1245 addi r1,r1,56+13*8 ; pop stack frame
1247 lwz r0,8(r1) ; restore lr
1252 ; Call __objc_error(receiver, "unknown selector %s", "forward::")
1254 LEA_STATIC_DATA r4, LUnkSelStr, LOCAL_SYMBOL
1256 CALL_EXTERN(___objc_error) ; never returns
1259 END_ENTRY __objc_msgForward_internal
1262 /********************************************************************
1263 * id objc_msgSendv(id self,
1265 * unsigned arg_size,
1266 * marg_list arg_frame);
1268 * But the marg_list is prepended with the 13 double precision
1269 * floating point registers that could be used as parameters into
1270 * the method (fortunately, the same registers are used for either
1271 * single or double precision floats). These registers are layed
1272 * down by _objc_msgForward, and picked up by _objc_msgSendv. So
1273 * the "marg_list" is actually:
1275 * typedef struct objc_sendv_margs {
1276 * double floatingPointArgs[13];
1277 * int linkageArea[6];
1278 * int registerArgs[8];
1279 * int stackArgs[variable];
1282 * arg_size is the number of bytes of parameters in registerArgs and
1283 * stackArgs combined (i.e. it is method_getSizeOfArguments(method)).
1284 * Specifically, it is NOT the overall arg_frame size, because that
1285 * would include the floatingPointArgs and linkageArea, which are
1286 * PowerPC-specific. This is consistent with the other architectures.
1287 ********************************************************************/
1289 ENTRY _objc_msgSendv
1291 #if !defined(KERNEL)
1292 ; do profiling when enabled
1296 stw r0,8(r1) ; save lr
1298 cmplwi r5,32 ; check parameter size against minimum
1299 ble+ LMsgSendvMinFrame ; is less than minimum, go use minimum
1300 mr r12,r1 ; remember current stack pointer
1301 sub r11,r1,r5 ; push parameter area
1302 rlwinm r1,r11,0,0,27 ; align stack pointer to 16 byte boundary
1303 stwu r12,-32(r1) ; push aligned linkage area, set stack link
1304 b LMsgSendvHaveFrame
1307 stwu r1,-64(r1) ; push aligned linkage and parameter areas, set stack link
1310 ; restore floating point register parameters from marg_list
1325 ; load the register based arguments from the marg_list
1326 ; the first two parameters are already in r3 and r4, respectively
1327 subi r0,r5,(2*4)-3 ; make word count from byte count rounded up to multiple of 4...
1328 srwi. r0,r0,2 ; ... and subtracting for params already in r3 and r4
1329 beq LMsgSendvSendIt ; branch if there are no parameters to load
1330 mtctr r0 ; counter = number of remaining words
1331 lwz r5,32+(13*8)(r6) ; load 3rd parameter
1332 bdz LMsgSendvSendIt ; decrement counter, branch if result is zero
1333 addi r11,r6,36+(13*8) ; switch to r11, because we are setting r6
1334 lwz r6,0(r11) ; load 4th parameter
1335 bdz LMsgSendvSendIt ; decrement counter, branch if result is zero
1336 lwz r7,4(r11) ; load 5th parameter
1337 bdz LMsgSendvSendIt ; decrement counter, branch if result is zero
1338 lwz r8,8(r11) ; load 6th parameter
1339 bdz LMsgSendvSendIt ; decrement counter, branch if result is zero
1340 lwz r9,12(r11) ; load 7th parameter
1341 bdz LMsgSendvSendIt ; decrement counter, branch if result is zero
1342 lwzu r10,16(r11) ; load 8th parameter, and update r11
1343 bdz LMsgSendvSendIt ; decrement counter, branch if result is zero
1345 ; copy the stack based arguments from the marg_list
1346 addi r12,r1,24+32-4 ; target = address of stack based parameters
1348 lwzu r0,4(r11) ; loop to copy remaining marg_list words to stack
1350 bdnz LMsgSendvArgLoop ; decrement counter, branch if still non-zero
1353 bl _objc_msgSend ; objc_msgSend (self, selector, ...)
1355 lwz r1,0(r1) ; restore stack pointer
1356 lwz r0,8(r1) ; restore lr
1360 trap ; _objc_msgSendv is not for the kernel
1363 END_ENTRY _objc_msgSendv
1365 /********************************************************************
1366 * double objc_msgSendv_fpret(id self, SEL op, unsigned arg_size,
1367 * marg_list arg_frame);
1368 ********************************************************************/
1370 ENTRY _objc_msgSendv_fpret
1372 END_ENTRY _objc_msgSendv_fpret
1374 /********************************************************************
1375 * void objc_msgSendv_stret(void *structStorage,
1378 * unsigned arg_size,
1379 * marg_list arg_frame);
1381 * objc_msgSendv_stret is the struct-return form of msgSendv.
1382 * This function does not use the struct-return ABI; instead, the
1383 * structure return address is passed as a normal parameter.
1384 * The two are functionally identical on ppc, but not on other architectures.
1386 * On entry: r3 is the address in which the returned struct is put,
1387 * r4 is the message receiver,
1388 * r5 is the selector,
1389 * r6 is the size of the marg_list, in bytes,
1390 * r7 is the address of the marg_list
1391 ********************************************************************/
1393 ENTRY _objc_msgSendv_stret
1395 #if !defined(KERNEL)
1396 ; do profiling when enabled
1400 stw r0,8(r1) ; (save return pc)
1402 cmplwi r6,32 ; check parameter size against minimum
1403 ble+ LMsgSendvStretMinFrame ; is less than minimum, go use minimum
1404 mr r12,r1 ; remember current stack pointer
1405 sub r11,r1,r6 ; push parameter area
1406 rlwinm r1,r11,0,0,27 ; align stack pointer to 16 byte boundary
1407 stwu r12,-32(r1) ; push aligned linkage area, set stack link
1408 b LMsgSendvStretHaveFrame
1410 LMsgSendvStretMinFrame:
1411 stwu r1,-64(r1) ; push aligned linkage and parameter areas, set stack link
1413 LMsgSendvStretHaveFrame:
1414 ; restore floating point register parameters from marg_list
1429 ; load the register based arguments from the marg_list
1430 ; the structure return address and the first two parameters
1431 ; are already in r3, r4, and r5, respectively.
1432 ; NOTE: The callers r3 probably, but not necessarily, matches
1433 ; the r3 in the marg_list. That is, the struct-return
1434 ; storage used by the caller could be an intermediate buffer
1435 ; that will end up being copied into the original
1436 ; struct-return buffer (pointed to by the marg_listed r3).
1437 subi r0,r6,(3*4)-3 ; make word count from byte count rounded up to multiple of 4...
1438 srwi. r0,r0,2 ; ... and subtracting for params already in r3 and r4 and r5
1439 beq LMsgSendvStretSendIt ; branch if there are no parameters to load
1440 mtctr r0 ; counter = number of remaining words
1441 lwz r6,36+(13*8)(r7) ; load 4th parameter
1442 bdz LMsgSendvStretSendIt ; decrement counter, branch if result is zero
1443 addi r11,r7,40+(13*8) ; switch to r11, because we are setting r7
1444 lwz r7,0(r11) ; load 5th parameter
1445 bdz LMsgSendvStretSendIt ; decrement counter, branch if result is zero
1446 lwz r8,4(r11) ; load 6th parameter
1447 bdz LMsgSendvStretSendIt ; decrement counter, branch if result is zero
1448 lwz r9,8(r11) ; load 7th parameter
1449 bdz LMsgSendvStretSendIt ; decrement counter, branch if result is zero
1450 lwzu r10,12(r11) ; load 8th parameter, and update r11
1451 bdz LMsgSendvStretSendIt ; decrement counter, branch if result is zero
1453 ; copy the stack based arguments from the marg_list
1454 addi r12,r1,24+32-4 ; target = address of stack based parameters
1455 LMsgSendvStretArgLoop:
1456 lwzu r0,4(r11) ; loop to copy remaining marg_list words to stack
1458 bdnz LMsgSendvStretArgLoop ; decrement counter, branch if still non-zero
1460 LMsgSendvStretSendIt:
1461 bl _objc_msgSend_stret ; struct_type objc_msgSend_stret (self, selector, ...)
1463 lwz r1,0(r1) ; restore stack pointer
1464 lwz r0,8(r1) ; restore return pc
1468 trap ; _objc_msgSendv_stret is not for the kernel
1469 #endif /* !KERNEL */
1471 END_ENTRY _objc_msgSendv_stret
1474 ENTRY _method_invoke
1476 lwz r12, METHOD_IMP(r4)
1477 lwz r4, METHOD_NAME(r4)
1481 END_ENTRY _method_invoke
1484 ENTRY _method_invoke_stret
1486 lwz r12, METHOD_IMP(r5)
1487 lwz r5, METHOD_NAME(r5)
1491 END_ENTRY _method_invoke_stret