2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
25 /********************************************************************
27 * objc-msg-ppc.s - PowerPC code to support objc messaging.
29 * Copyright 1988-1996 NeXT Software, Inc.
31 * December 2002 Andy Belk (abelk at apple.com)
32 * Use r2 in the messenger - no longer need r10.
33 * Removed "few args" variants (no longer worth it, especially since gcc3 still
34 * doesn't generate code for them).
35 * Add NonNil entry points to objc_msgSend and objc_msgSend_stret.
36 * Align objc_msgSend et al on cache lines.
37 * Replace CALL_EXTERN references (which caused excess mflr/mtlr usage) with
38 * dyld-stub-compatible versions: shorter and become local branches within a dylib.
40 * 8-Nov-2000 Laurent Ramontianu (ramontia@apple.com)
41 * Added "few args" params. to CacheLookup and MethodTableLookup
42 * Added the alternate entry points:
43 * objc_msgSendFew, objc_msgSendFew_stret,
44 * objc_msgSendSuperFew, objc_msgSendSuperFew_stret
46 * 18-Jun-97 David Harrison (harrison@apple.com)
49 * 1-May-97 Umesh Vaishampayan (umeshv@NeXT.com)
50 * Incorporated locking code fixes from
51 * David Harrison (harrison@NeXT.com)
53 * 2-Apr-97 Umesh Vaishampayan (umeshv@NeXT.com)
54 * Incorporated changes for messenger with struct return
55 * Cleaned up the labels to use local labels
56 * Fixed bug in the msgSendSuper that did not do the locking.
58 * 31-Dec-96 Umesh Vaishampayan (umeshv@NeXT.com)
60 ********************************************************************/
62 /********************************************************************
63 * Data used by the ObjC runtime.
65 ********************************************************************/
68 ; Substitute receiver for messages sent to nil (usually also nil)
69 ; id _objc_nilReceiver
71 .globl __objc_nilReceiver
75 ; _objc_entryPoints and _objc_exitPoints are used by method dispatch
76 ; caching code to figure out whether any threads are actively
77 ; in the cache for dispatching. The labels surround the asm code
78 ; that do cache lookups. The tables are zero-terminated.
79 .globl _objc_entryPoints
82 .long __cache_getMethod
84 .long _objc_msgSend_stret
85 .long _objc_msgSendSuper
86 .long _objc_msgSendSuper_stret
89 .globl _objc_exitPoints
94 .long LMsgSendStretExit
95 .long LMsgSendSuperExit
96 .long LMsgSendSuperStretExit
100 * Handcrafted dyld stubs for each external call.
101 * They should be converted into a local branch after linking. aB.
104 /* asm_help.h version is not what we want */
107 #if defined(__DYNAMIC__)
109 #define CALL_EXTERN(name) bl L ## name ## $stub
111 #define LAZY_PIC_FUNCTION_STUB(name) \
114 L ## name ## $stub: @\
115 .indirect_symbol name @\
117 bcl 20,31,L0$ ## name @\
120 addis r11,r11,ha16(L ## name ## $lazy_ptr-L0$ ## name) @\
122 lwz r12,lo16(L ## name ## $lazy_ptr-L0$ ## name)(r11) @\
124 addi r11,r11,lo16(L ## name ## $lazy_ptr-L0$ ## name) @\
127 .lazy_symbol_pointer @\
128 L ## name ## $lazy_ptr: @\
129 .indirect_symbol name @\
130 .long dyld_stub_binding_helper
132 #else /* __DYNAMIC__ */
134 #define CALL_EXTERN(name) bl name
136 #define LAZY_PIC_FUNCTION_STUB(name)
138 #endif /* __DYNAMIC__ */
140 ; _class_lookupMethodAndLoadCache
141 LAZY_PIC_FUNCTION_STUB(__class_lookupMethodAndLoadCache)
144 LAZY_PIC_FUNCTION_STUB(___objc_error) /* No stub needed */
148 LAZY_PIC_FUNCTION_STUB(mcount)
152 /********************************************************************
154 * Structure definitions.
156 ********************************************************************/
158 ; objc_super parameter to sendSuper
162 ; Selected field offsets in class structure
167 #define METHOD_NAME 0
173 #define BUCKETS 8 // variable length array
175 #if defined(OBJC_INSTRUMENTED)
176 ; Cache instrumentation data, follows buckets
178 #define hitProbes hitCount + 4
179 #define maxHitProbes hitProbes + 4
180 #define missCount maxHitProbes + 4
181 #define missProbes missCount + 4
182 #define maxMissProbes missProbes + 4
183 #define flushCount maxMissProbes + 4
184 #define flushedEntries flushCount + 4
187 /********************************************************************
191 ********************************************************************/
193 // In case the implementation is _objc_msgForward, indicate to it
194 // whether the method was invoked as a word-return or struct-return.
195 // The li instruction costs nothing because it fits into spare
196 // processor cycles. We choose to make the MsgSend indicator non-zero
197 // as r11 is already guaranteed non-zero for a cache hit (no li needed).
199 #define kFwdMsgSend 1
200 #define kFwdMsgSendStret 0
202 /********************************************************************
204 * Useful macros. Macros are used instead of subroutines, for speed.
206 ********************************************************************/
208 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
210 ; LOAD_STATIC_WORD targetReg, symbolName, LOCAL_SYMBOL | EXTERNAL_SYMBOL
212 ; Load the value of the named static data word.
214 ; Takes: targetReg - the register, other than r0, to load
215 ; symbolName - the name of the symbol
216 ; LOCAL_SYMBOL - symbol name used as-is
217 ; EXTERNAL_SYMBOL - symbol name gets nonlazy treatment
219 ; Eats: r0 and targetReg
220 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
222 ; Values to specify whether the symbols is plain or nonlazy
223 #define LOCAL_SYMBOL 0
224 #define EXTERNAL_SYMBOL 1
226 .macro LOAD_STATIC_WORD
228 #if defined(__DYNAMIC__)
230 bcl 20,31,1f ; 31 is cr7[so]
233 .if $2 == EXTERNAL_SYMBOL
234 addis $0,$0,ha16(L$1-1b)
235 lwz $0,lo16(L$1-1b)($0)
237 .elseif $2 == LOCAL_SYMBOL
238 addis $0,$0,ha16($1-1b)
239 lwz $0,lo16($1-1b)($0)
241 !!! Unknown symbol type !!!
250 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
252 ; LEA_STATIC_DATA targetReg, symbolName, LOCAL_SYMBOL | EXTERNAL_SYMBOL
254 ; Load the address of the named static data.
256 ; Takes: targetReg - the register, other than r0, to load
257 ; symbolName - the name of the symbol
258 ; LOCAL_SYMBOL - symbol is local to this module
259 ; EXTERNAL_SYMBOL - symbol is imported from another module
261 ; Eats: r0 and targetReg
262 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
264 .macro LEA_STATIC_DATA
265 #if defined(__DYNAMIC__)
267 bcl 20,31,1f ; 31 is cr7[so]
270 .if $2 == EXTERNAL_SYMBOL
271 addis $0,$0,ha16(L$1-1b)
272 lwz $0,lo16(L$1-1b)($0)
273 .elseif $2 == LOCAL_SYMBOL
274 addis $0,$0,ha16($1-1b)
275 addi $0,$0,lo16($1-1b)
277 !!! Unknown symbol type !!!
286 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
290 ; Assembly directives to begin an exported function.
291 ; We align on cache boundaries for these few functions.
293 ; Takes: functionName - name of the exported function
294 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
303 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
305 ; END_ENTRY functionName
307 ; Assembly directives to end an exported function. Just a placeholder,
308 ; a close-parenthesis for ENTRY, until it is needed for something.
310 ; Takes: functionName - name of the exported function
311 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
316 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
318 ; PLOCK scratchReg, lockName
320 ; Acquire named spinlock.
322 ; Takes: scratchReg - a register, other than r0, that can be mangled
323 ; lockName - the name of a static, aligned, 32-bit lock word
325 ; Eats: r0 and scratchReg
326 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
329 LEA_STATIC_DATA $0, $1, EXTERNAL_SYMBOL
330 b .+16 ; jump into loop at the reserving check
331 lwz r0,0($0) ; check with fast, less intrusive lwz versus lwarx
332 cmplwi r0,0 ; lock held?
333 bne .-8 ; if so, spin until it appears unlocked
334 lwarx r0,0,$0 ; get lock value, acquire memory reservation
335 cmplwi r0,0 ; lock held?
336 bne .-20 ; if locked, go spin waiting for unlock
337 li r0,1 ; get value that means locked
338 stwcx. r0,0,$0 ; store it iff reservation still holds
339 bne- .-20 ; if reservation was lost, go re-reserve
340 isync ; discard effects of prefetched instructions
343 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
345 ; PUNLOCK scratchReg, lockName
347 ; Release named spinlock.
349 ; Takes: scratchReg - a register, other than r0, that can be mangled
350 ; lockName - the name of a static, aligned, 32-bit lock word
352 ; Eats: r0 and scratchReg
353 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
356 sync ; force out changes before unlocking
357 LEA_STATIC_DATA $0, $1, EXTERNAL_SYMBOL
358 li r0,0 ; get value meaning "unlocked"
359 stw r0,0($0) ; unlock the lock
363 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
365 ; CacheLookup WORD_RETURN | STRUCT_RETURN, MSG_SEND | MSG_SENDSUPER | CACHE_GET, cacheMissLabel
367 ; Locate the implementation for a selector in a class method cache.
369 ; Takes: WORD_RETURN (r3 is first parameter)
370 ; STRUCT_RETURN (r3 is structure return address, r4 is first parameter)
371 ; MSG_SEND (first parameter is receiver)
372 ; MSG_SENDSUPER (first parameter is address of objc_super structure)
373 ; CACHE_GET (first parameter is class; return method triplet)
375 ; cacheMissLabel = label to branch to iff method is not cached
378 ; On exit: (found) MSG_SEND and MSG_SENDSUPER: return imp in r12 and ctr
379 ; (found) CACHE_GET: return method triplet in r12
380 ; (not found) jumps to cacheMissLabel
382 ; For MSG_SEND and MSG_SENDSUPER, the messenger jumps to the imp
383 ; in ctr. The same imp in r12 is used by the method itself for its
384 ; relative addressing. This saves the usual "jump to next line and
385 ; fetch link register" construct inside the method.
387 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
389 ; Values to specify to method lookup macros whether the return type of
390 ; the method is an integer or structure.
391 #define WORD_RETURN 0
392 #define STRUCT_RETURN 1
394 ; Values to specify to method lookup macros whether the return type of
395 ; the method is an integer or structure.
397 #define MSG_SENDSUPER 1
402 #if defined(OBJC_INSTRUMENTED)
403 ; when instrumented, we use r6 and r7
404 stw r6,36(r1) ; save r6 for use as cache pointer
405 stw r7,40(r1) ; save r7 for use as probe count
406 li r7,0 ; no probes so far!
409 .if $1 == CACHE_GET ; Only WORD_RETURN applies
410 lwz r12,CACHE(r3) ; cache = class->cache (class = 1st parameter)
413 .if $0 == WORD_RETURN ; WORD_RETURN
415 .if $1 == MSG_SEND ; MSG_SEND
416 lwz r12,ISA(r3) ; class = receiver->isa
417 .elseif $1 == MSG_SENDSUPER ; MSG_SENDSUPER
418 lwz r12,CLASS(r3) ; class = super->class
420 trap ; Should not happen
423 .else ; STRUCT_RETURN
425 .if $1 == MSG_SEND ; MSG_SEND
426 lwz r12,ISA(r4) ; class = receiver->isa
427 .elseif $1 == MSG_SENDSUPER ; MSG_SENDSUPER
428 lwz r12,CLASS(r4) ; class = super->class
430 trap ; Should not happen
435 lwz r12,CACHE(r12) ; cache = class->cache
439 stw r9,48(r1) ; save r9
441 #if defined(OBJC_INSTRUMENTED)
442 mr r6,r12 ; save cache pointer
444 lwz r11,MASK(r12) ; mask = cache->mask
446 addi r9,r12,BUCKETS ; buckets = cache->buckets
447 slwi r11,r11,2 ; r11 = mask << 2
448 .if $0 == WORD_RETURN ; WORD_RETURN
449 and r12,r4,r11 ; bytes = sel & (mask<<2)
450 .else ; STRUCT_RETURN
451 and r12,r5,r11 ; bytes = sel & (mask<<2)
454 #if defined(OBJC_INSTRUMENTED)
458 ; r6 = cache, r7 = probeCount
459 lwz r9,MASK(r6) ; entryCount = mask + 1
461 slwi r9,r9,2 ; tableSize = entryCount * sizeof(entry)
462 addi r9,r9,BUCKETS ; offset = buckets + tableSize
463 add r11,r6,r9 ; cacheData = &cache->buckets[mask+1]
464 lwz r9,missCount(r11) ; cacheData->missCount += 1
466 stw r9,missCount(r11) ;
467 lwz r9,missProbes(r11) ; cacheData->missProbes += probeCount
469 stw r9,missProbes(r11) ;
470 lwz r9,maxMissProbes(r11) ; if (probeCount > cacheData->maxMissProbes)
471 cmplw r7,r9 ; maxMissProbes = probeCount
473 stw r7,maxMissProbes(r11) ;
475 lwz r6,36(r1) ; restore r6
476 lwz r7,40(r1) ; restore r7
478 b $2 ; goto cacheMissLabel
483 #if defined(OBJC_INSTRUMENTED)
484 addi r7,r7,1 ; probeCount += 1
487 lwzx r2,r9,r12 ; method = buckets[bytes/4]
488 addi r12,r12,4 ; bytes += 4
489 cmplwi r2,0 ; if (method == NULL)
490 #if defined(OBJC_INSTRUMENTED)
493 beq $2 ; goto cacheMissLabel
496 lwz r0,METHOD_NAME(r2) ; name = method->method_name
497 and r12,r12,r11 ; bytes &= (mask<<2)
498 .if $0 == WORD_RETURN ; WORD_RETURN
499 cmplw r0,r4 ; if (name != selector)
500 .else ; STRUCT_RETURN
501 cmplw r0,r5 ; if (name != selector)
503 bne LLoop_$0_$1_$2 ; goto loop
505 ; cache hit, r2 == method triplet address
507 ; return method triplet in r12
508 ; N.B. A better way to do this is have CACHE_GET swap the use of r12 and r2.
511 ; return method imp in ctr and r12
512 lwz r12,METHOD_IMP(r2) ; imp = method->method_imp (in r12)
513 mtctr r12 ; ctr = imp
516 #if defined(OBJC_INSTRUMENTED)
517 ; r6 = cache, r7 = probeCount
518 lwz r9,MASK(r6) ; entryCount = mask + 1
520 slwi r9,r9,2 ; tableSize = entryCount * sizeof(entry)
521 addi r9,r9,BUCKETS ; offset = buckets + tableSize
522 add r11,r6,r9 ; cacheData = &cache->buckets[mask+1]
523 lwz r9,hitCount(r11) ; cache->hitCount += 1
525 stw r9,hitCount(r11) ;
526 lwz r9,hitProbes(r11) ; cache->hitProbes += probeCount
528 stw r9,hitProbes(r11) ;
529 lwz r9,maxHitProbes(r11) ; if (probeCount > cache->maxMissProbes)
530 cmplw r7,r9 ;maxMissProbes = probeCount
532 stw r7,maxHitProbes(r11) ;
534 lwz r6,36(r1) ; restore r6
535 lwz r7,40(r1) ; restore r7
538 lwz r9,48(r1) ; restore r9
542 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
544 ; CacheLookup cache locking - 2001-11-12
545 ; The collecting cache mechanism precludes the need for a cache lock
546 ; in objc_msgSend. The cost of the collecting cache is small: a few
547 ; K of memory for uncollected caches, and less than 1 ms per collection.
548 ; A large app will only run collection a few times.
549 ; Using the code below to lock the cache almost doubles messaging time,
550 ; costing several seconds of CPU across several minutes of operation.
551 ; The code below probably could be improved, but almost all of the
552 ; locking slowdown is in the sync and isync.
554 ; 40 million message test times (G4 1x667):
555 ; no lock 4.390u 0.030s 0:04.59 96.2% 0+0k 0+1io 0pf+0w
556 ; with lock 9.120u 0.010s 0:09.83 92.8% 0+0k 0+0io 0pf+0w
558 ;; LockCache mask_dest, cache
560 ; ; LOCKED mask is NEGATIVE
561 ; lwarx $0, mask, $1 ; mask = reserve(cache->mask)
563 ; blt .-8 ; try again if mask < 0
565 ; stwcx. r0, mask, $1 ; cache->mask = -mask ($0 keeps +mask)
566 ; bne .-20 ; try again if lost reserve
567 ; isync ; flush prefetched instructions after locking
570 ;; UnlockCache (mask<<2), cache
572 ; sync ; finish previous instructions before unlocking
573 ; srwi r0, $0, 2 ; r0 = (mask<<2) >> 2
574 ; stw r0, mask($1) ; cache->mask = +mask
577 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
580 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
583 ; MethodTableLookup WORD_RETURN | STRUCT_RETURN, MSG_SEND | MSG_SENDSUPER
585 ; Takes: WORD_RETURN (r3 is first parameter)
586 ; STRUCT_RETURN (r3 is structure return address, r4 is first parameter)
587 ; MSG_SEND (first parameter is receiver)
588 ; MSG_SENDSUPER (first parameter is address of objc_super structure)
590 ; Eats: r0, r2, r11, r12
591 ; On exit: restores r9 saved by CacheLookup
593 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
595 .macro MethodTableLookup
599 stw r3, 24(r1) ; save arguments
605 ; r9 was saved by CacheLookup
609 ; Save the FP parameter registers.
610 ; Note: If we (the compiler) could determine that no FP arguments were in use,
611 ; we could use a different variant of this macro and avoid the need to spill the FP
612 ; registers (provided the runtime uses no FP).
613 ; We still do not spill vector argument registers, for which we really should have an alternate
629 stwu r1,-56-(13*8)(r1) ; grow the stack. Must be 16-byte-aligned.
631 stwu r1,-64(r1) ; grow the stack. Must be 16-byte-aligned.
634 ; Pass parameters to __class_lookupMethodAndLoadCache. First parameter is
635 ; the class pointer. Second parameter is the selector. Where they come
636 ; from depends on who called us. In the int return case, the selector is
638 .if $0 == WORD_RETURN ; WORD_RETURN
639 .if $1 == MSG_SEND ; MSG_SEND
640 lwz r3,ISA(r3) ; class = receiver->isa
641 .else ; MSG_SENDSUPER
642 lwz r3,CLASS(r3) ; class = super->class
645 .else ; STRUCT_RETURN
646 .if $1 == MSG_SEND ; MSG_SEND
647 lwz r3,ISA(r4) ; class = receiver->isa
648 .else ; MSG_SENDSUPER
649 lwz r3,CLASS(r4) ; class = super->class
651 mr r4,r5 ; selector = selector
654 ; We code the call inline rather than using the CALL_EXTERN macro because
655 ; that leads to a lot of extra unnecessary and inefficient instructions.
656 CALL_EXTERN(__class_lookupMethodAndLoadCache)
658 mr r12,r3 ; copy implementation to r12
659 mtctr r3 ; copy imp to ctr
660 lwz r1,0(r1) ; restore the stack pointer
662 mtlr r0 ; restore return pc
666 ; Restore FP parameter registers
667 ; Note: If we (the compiler) could determine that no FP arguments were in use,
668 ; we could use a different variant of this macro and avoid the need to restore the FP
669 ; registers (provided the runtime uses no FP).
670 ; We still do not restore vector argument registers, for which we really should have an alternate
686 lwz r3, 24(r1) ; restore parameter registers
692 lwz r9, 48(r1) ; r9 was saved by CacheLookup
699 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
703 ; Macro to call mcount function in profiled builds.
705 ; NOTE: Makes sure to save/restore r11 and r12, even though they
706 ; are not defined to be volatile, because they are used during
709 ; Takes: lr Callers return PC
712 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
716 mflr r0 ; save return pc
719 stwu r1,-208(r1) ; push aligned areas, set stack link
721 stw r3, 56(r1) ; save all volatile registers
729 stw r11,88(r1) ; save r11 and r12, too
746 mr r3, r0 ; pass our callers address
750 lwz r3, 56(r1) ; restore all volatile registers
758 lwz r11,88(r1) ; restore r11 and r12, too
775 lwz r1,0(r1) ; restore the stack pointer
777 mtlr r0 ; restore return pc
782 /********************************************************************
783 * Method _cache_getMethod(Class cls, SEL sel, IMP objc_msgForward_imp)
785 * On entry: r3 = class whose cache is to be searched
786 * r4 = selector to search for
787 * r5 = _objc_msgForward IMP
789 * If found, returns method triplet pointer.
790 * If not found, returns NULL.
792 * NOTE: _cache_getMethod never returns any cache entry whose implementation
793 * is _objc_msgForward. It returns NULL instead. This prevents thread-
794 * safety and memory management bugs in _class_lookupMethodAndLoadCache.
795 * See _class_lookupMethodAndLoadCache for details.
797 * _objc_msgForward is passed as a parameter because it's more efficient
798 * to do the (PIC) lookup once in the caller than repeatedly here.
799 ********************************************************************/
801 ENTRY __cache_getMethod
802 ; do profiling if enabled
806 CacheLookup WORD_RETURN, CACHE_GET, LGetMethodMiss
808 ; cache hit, method triplet in r12
809 lwz r11, METHOD_IMP(r12) ; get the imp
810 cmplw r11, r5 ; check for _objc_msgForward
811 mr r3, r12 ; optimistically get the return value
812 bnelr ; Not _objc_msgForward, return the triplet address
815 li r3, 0 ; cache miss or _objc_msgForward, return nil
819 END_ENTRY __cache_getMethod
822 /********************************************************************
823 * IMP _cache_getImp(Class cls, SEL sel)
825 * On entry: r3 = class whose cache is to be searched
826 * r4 = selector to search for
828 * If found, returns method implementation.
829 * If not found, returns NULL.
830 ********************************************************************/
833 ; do profiling if enabled
837 CacheLookup WORD_RETURN, CACHE_GET, LGetImpMiss
839 ; cache hit, method triplet in r12
840 lwz r3, METHOD_IMP(r12) ; return method imp address
844 ; cache miss, return nil
845 li r3, 0 ; return nil
849 END_ENTRY __cache_getImp
852 /********************************************************************
853 * id objc_msgSend(id self,
857 * On entry: r3 is the message receiver,
859 ********************************************************************/
862 ; check whether receiver is nil
863 cmplwi r3,0 ; receiver nil?
864 beq- LMsgSendNilSelf ; if so, call handler or return nil
866 ; guaranteed non-nil entry point (disabled for now)
867 ; .globl _objc_msgSendNonNil
868 ; _objc_msgSendNonNil:
870 ; do profiling when enabled
873 ; receiver is non-nil: search the cache
875 CacheLookup WORD_RETURN, MSG_SEND, LMsgSendCacheMiss
876 ; r11 guaranteed non-zero on exit from CacheLookup with a hit
877 // li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
880 ; cache miss: go search the method lists
882 MethodTableLookup WORD_RETURN, MSG_SEND
883 li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
886 ; message sent to nil: redirect to nil receiver, if any
888 mflr r0 ; load new receiver
889 bcl 20,31,1f ; 31 is cr7[so]
891 addis r11,r11,ha16(__objc_nilReceiver-1b)
892 lwz r11,lo16(__objc_nilReceiver-1b)(r11)
895 cmplwi r11,0 ; return nil if no new receiver
898 mr r3,r11 ; send to new receiver
902 END_ENTRY _objc_msgSend
905 /********************************************************************
906 * struct_type objc_msgSend_stret(id self,
910 * objc_msgSend_stret is the struct-return form of msgSend.
911 * The ABI calls for r3 to be used as the address of the structure
912 * being returned, with the parameters in the succeeding registers.
914 * On entry: r3 is the address where the structure is returned,
915 * r4 is the message receiver,
917 ********************************************************************/
919 ENTRY _objc_msgSend_stret
920 ; check whether receiver is nil
921 cmplwi r4,0 ; receiver nil?
922 beq LMsgSendStretNilSelf ; if so, call handler or just return
924 ; guaranteed non-nil entry point (disabled for now)
925 ; .globl _objc_msgSendNonNil_stret
926 ; _objc_msgSendNonNil_stret:
928 ; do profiling when enabled
931 ; receiver is non-nil: search the cache
932 LMsgSendStretReceiverOk:
933 CacheLookup STRUCT_RETURN, MSG_SEND, LMsgSendStretCacheMiss
934 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
937 ; cache miss: go search the method lists
938 LMsgSendStretCacheMiss:
939 MethodTableLookup STRUCT_RETURN, MSG_SEND
940 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
943 ; message sent to nil: redirect to nil receiver, if any
944 LMsgSendStretNilSelf:
945 mflr r0 ; load new receiver
946 bcl 20,31,1f ; 31 is cr7[so]
948 addis r11,r11,ha16(__objc_nilReceiver-1b)
949 lwz r11,lo16(__objc_nilReceiver-1b)(r11)
952 cmplwi r11,0 ; return nil if no new receiver
955 mr r4,r11 ; send to new receiver
956 b LMsgSendStretReceiverOk
959 END_ENTRY _objc_msgSend_stret
962 /********************************************************************
963 * id objc_msgSendSuper(struct objc_super *super,
967 * struct objc_super {
971 ********************************************************************/
973 ENTRY _objc_msgSendSuper
974 ; do profiling when enabled
978 CacheLookup WORD_RETURN, MSG_SENDSUPER, LMsgSendSuperCacheMiss
979 lwz r3,RECEIVER(r3) ; receiver is the first arg
980 ; r11 guaranteed non-zero after cache hit
981 ; li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
984 ; cache miss: go search the method lists
985 LMsgSendSuperCacheMiss:
986 MethodTableLookup WORD_RETURN, MSG_SENDSUPER
987 lwz r3,RECEIVER(r3) ; receiver is the first arg
988 li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
992 END_ENTRY _objc_msgSendSuper
995 /********************************************************************
996 * struct_type objc_msgSendSuper_stret(objc_super *super,
1000 * struct objc_super {
1006 * objc_msgSendSuper_stret is the struct-return form of msgSendSuper.
1007 * The ABI calls for r3 to be used as the address of the structure
1008 * being returned, with the parameters in the succeeding registers.
1010 * On entry: r3 is the address to which to copy the returned structure,
1011 * r4 is the address of the objc_super structure,
1012 * r5 is the selector
1013 ********************************************************************/
1015 ENTRY _objc_msgSendSuper_stret
1016 ; do profiling when enabled
1020 CacheLookup STRUCT_RETURN, MSG_SENDSUPER, LMsgSendSuperStretCacheMiss
1021 lwz r4,RECEIVER(r4) ; receiver is the first arg
1022 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
1025 ; cache miss: go search the method lists
1026 LMsgSendSuperStretCacheMiss:
1027 MethodTableLookup STRUCT_RETURN, MSG_SENDSUPER
1028 lwz r4,RECEIVER(r4) ; receiver is the first arg
1029 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
1032 LMsgSendSuperStretExit:
1033 END_ENTRY _objc_msgSendSuper_stret
1036 /********************************************************************
1038 * Out-of-band parameter r11 indicates whether it was objc_msgSend or
1039 * objc_msgSend_stret that triggered the message forwarding. The
1041 * Iff r11 == kFwdMsgSend, it is the word-return (objc_msgSend) case,
1042 * and the interface is:
1044 * id _objc_msgForward(id self,
1048 * Iff r11 == kFwdMsgSendStret, it is the structure-return
1049 * (objc_msgSend_stret) case, and the interface is:
1051 * struct_type _objc_msgForward(id self,
1055 * There are numerous reasons why it is better to have one
1056 * _objc_msgForward, rather than adding _objc_msgForward_stret.
1057 * The best one is that _objc_msgForward is the method that
1058 * gets cached when respondsToMethod returns false, and it
1059 * wouldnt know which one to use.
1061 * Sends the message to a method having the signature
1063 * - forward:(SEL)sel :(marg_list)args;
1065 * But the marg_list is prepended with the 13 double precision
1066 * floating point registers that could be used as parameters into
1067 * the method (fortunately, the same registers are used for either
1068 * single or double precision floats). These registers are layed
1069 * down by _objc_msgForward, and picked up by _objc_msgSendv. So
1070 * the "marg_list" is actually:
1072 * typedef struct objc_sendv_margs {
1073 * double floatingPointArgs[13];
1074 * int linkageArea[6];
1075 * int registerArgs[8];
1076 * int stackArgs[variable];
1079 ********************************************************************/
1081 ; Location LFwdStr contains the string "forward::"
1082 ; Location LFwdSel contains a pointer to LFwdStr, that can be changed
1083 ; to point to another forward:: string for selector uniquing
1084 ; purposes. ALWAYS dereference LFwdSel to get to "forward::" !!
1085 .objc_meth_var_names
1087 LFwdStr: .ascii "forward::\0"
1091 LFwdSel: .long LFwdStr
1095 LUnkSelStr: .ascii "Does not recognize selector %s\0"
1097 ENTRY __objc_msgForward
1098 ; do profiling when enabled
1101 #if !defined(KERNEL)
1102 LOAD_STATIC_WORD r12, LFwdSel, LOCAL_SYMBOL ; get uniqued selector for "forward::"
1103 cmplwi r11,kFwdMsgSendStret ; via objc_msgSend or objc_msgSend_stret?
1104 beq LMsgForwardStretSel ; branch for objc_msgSend_stret
1105 cmplw r12,r4 ; if (sel == @selector (forward::))
1106 b LMsgForwardSelCmpDone ; check the result in common code
1107 LMsgForwardStretSel:
1108 cmplw r12,r5 ; if (sel == @selector (forward::))
1109 LMsgForwardSelCmpDone:
1110 beq LMsgForwardError ; goto error
1113 stw r0, 8(r1) ; save lr
1115 stw r3, 24(r1) ; put register arguments on stack for forwarding
1116 stw r4, 28(r1) ; (stack based args already follow this area)
1124 stfd f1, -104(r1) ; prepend floating point registers to marg_list
1138 cmplwi r11,kFwdMsgSendStret ; via objc_msgSend or objc_msgSend_stret?
1139 beq LMsgForwardStretParams ; branch for objc_msgSend_stret
1140 ; first arg (r3) remains self
1141 mr r5,r4 ; third arg is previous selector
1142 b LMsgForwardParamsDone
1144 LMsgForwardStretParams:
1145 mr r3,r4 ; first arg is self
1146 ; third arg (r5) remains previous selector
1147 LMsgForwardParamsDone:
1148 mr r4,r12 ; second arg is "forward::"
1149 subi r6,r1,13*8 ; fourth arg is &objc_sendv_margs
1151 stwu r1,-56-(13*8)(r1) ; push aligned linkage and parameter areas, set stack link
1152 bl _objc_msgSend ; [self forward:sel :objc_sendv_margs]
1153 addi r1,r1,56+13*8 ; deallocate linkage and parameters areas
1155 lwz r0,8(r1) ; restore lr
1159 ; call error handler with unrecognized selector message
1161 cmplwi r11,kFwdMsgSendStret ; via objc_msgSend or objc_msgSend_stret?
1162 bne LMsgForwardErrorParamsOK; branch for objc_msgSend
1163 mr r3,r4 ; first arg is self
1164 LMsgForwardErrorParamsOK:
1165 LEA_STATIC_DATA r4, LUnkSelStr, LOCAL_SYMBOL
1166 mr r5,r12 ; third arg is "forward::"
1167 CALL_EXTERN(___objc_error) ; never returns
1168 #endif /* !defined(KERNEL) */
1169 trap ; ___objc_error should never return
1170 ; _objc_msgForward is not for the kernel - kernel code ends up here
1172 END_ENTRY __objc_msgForward
1175 /********************************************************************
1176 * id objc_msgSendv(id self,
1178 * unsigned arg_size,
1179 * marg_list arg_frame);
1181 * But the marg_list is prepended with the 13 double precision
1182 * floating point registers that could be used as parameters into
1183 * the method (fortunately, the same registers are used for either
1184 * single or double precision floats). These registers are layed
1185 * down by _objc_msgForward, and picked up by _objc_msgSendv. So
1186 * the "marg_list" is actually:
1188 * typedef struct objc_sendv_margs {
1189 * double floatingPointArgs[13];
1190 * int linkageArea[6];
1191 * int registerArgs[8];
1192 * int stackArgs[variable];
1195 * arg_size is the number of bytes of parameters in registerArgs and
1196 * stackArgs combined (i.e. it is method_getSizeOfArguments(method)).
1197 * Specifically, it is NOT the overall arg_frame size, because that
1198 * would include the floatingPointArgs and linkageArea, which are
1199 * PowerPC-specific. This is consistent with the other architectures.
1200 ********************************************************************/
1202 ENTRY _objc_msgSendv
1204 #if !defined(KERNEL)
1205 ; do profiling when enabled
1209 stw r0,8(r1) ; save lr
1211 cmplwi r5,32 ; check parameter size against minimum
1212 ble+ LMsgSendvMinFrame ; is less than minimum, go use minimum
1213 mr r12,r1 ; remember current stack pointer
1214 sub r11,r1,r5 ; push parameter area
1215 rlwinm r1,r11,0,0,27 ; align stack pointer to 16 byte boundary
1216 stwu r12,-32(r1) ; push aligned linkage area, set stack link
1217 b LMsgSendvHaveFrame
1220 stwu r1,-64(r1) ; push aligned linkage and parameter areas, set stack link
1223 ; restore floating point register parameters from marg_list
1238 ; load the register based arguments from the marg_list
1239 ; the first two parameters are already in r3 and r4, respectively
1240 subi r0,r5,(2*4)-3 ; make word count from byte count rounded up to multiple of 4...
1241 srwi. r0,r0,2 ; ... and subtracting for params already in r3 and r4
1242 beq LMsgSendvSendIt ; branch if there are no parameters to load
1243 mtctr r0 ; counter = number of remaining words
1244 lwz r5,32+(13*8)(r6) ; load 3rd parameter
1245 bdz LMsgSendvSendIt ; decrement counter, branch if result is zero
1246 addi r11,r6,36+(13*8) ; switch to r11, because we are setting r6
1247 lwz r6,0(r11) ; load 4th parameter
1248 bdz LMsgSendvSendIt ; decrement counter, branch if result is zero
1249 lwz r7,4(r11) ; load 5th parameter
1250 bdz LMsgSendvSendIt ; decrement counter, branch if result is zero
1251 lwz r8,8(r11) ; load 6th parameter
1252 bdz LMsgSendvSendIt ; decrement counter, branch if result is zero
1253 lwz r9,12(r11) ; load 7th parameter
1254 bdz LMsgSendvSendIt ; decrement counter, branch if result is zero
1255 lwzu r10,16(r11) ; load 8th parameter, and update r11
1256 bdz LMsgSendvSendIt ; decrement counter, branch if result is zero
1258 ; copy the stack based arguments from the marg_list
1259 addi r12,r1,24+32-4 ; target = address of stack based parameters
1261 lwzu r0,4(r11) ; loop to copy remaining marg_list words to stack
1263 bdnz LMsgSendvArgLoop ; decrement counter, branch if still non-zero
1266 bl _objc_msgSend ; objc_msgSend (self, selector, ...)
1268 lwz r1,0(r1) ; restore stack pointer
1269 lwz r0,8(r1) ; restore lr
1273 trap ; _objc_msgSendv is not for the kernel
1276 END_ENTRY _objc_msgSendv
1279 /********************************************************************
1280 * struct_type objc_msgSendv_stret(id self,
1282 * unsigned arg_size,
1283 * marg_list arg_frame);
1285 * objc_msgSendv_stret is the struct-return form of msgSendv.
1286 * The ABI calls for r3 to be used as the address of the structure
1287 * being returned, with the parameters in the succeeding registers.
1289 * An equally correct way to prototype this routine is:
1291 * void objc_msgSendv_stret(void *structStorage,
1294 * unsigned arg_size,
1295 * marg_list arg_frame);
1297 * which is useful in, for example, message forwarding where the
1298 * structure-return address needs to be passed in.
1300 * The ABI for the two cases are identical.
1302 * On entry: r3 is the address in which the returned struct is put,
1303 * r4 is the message receiver,
1304 * r5 is the selector,
1305 * r6 is the size of the marg_list, in bytes,
1306 * r7 is the address of the marg_list
1307 ********************************************************************/
1309 ENTRY _objc_msgSendv_stret
1311 #if !defined(KERNEL)
1312 ; do profiling when enabled
1316 stw r0,8(r1) ; (save return pc)
1318 cmplwi r6,32 ; check parameter size against minimum
1319 ble+ LMsgSendvStretMinFrame ; is less than minimum, go use minimum
1320 mr r12,r1 ; remember current stack pointer
1321 sub r11,r1,r6 ; push parameter area
1322 rlwinm r1,r11,0,0,27 ; align stack pointer to 16 byte boundary
1323 stwu r12,-32(r1) ; push aligned linkage area, set stack link
1324 b LMsgSendvStretHaveFrame
1326 LMsgSendvStretMinFrame:
1327 stwu r1,-64(r1) ; push aligned linkage and parameter areas, set stack link
1329 LMsgSendvStretHaveFrame:
1330 ; restore floating point register parameters from marg_list
1345 ; load the register based arguments from the marg_list
1346 ; the structure return address and the first two parameters
1347 ; are already in r3, r4, and r5, respectively.
1348 ; NOTE: The callers r3 probably, but not necessarily, matches
1349 ; the r3 in the marg_list. That is, the struct-return
1350 ; storage used by the caller could be an intermediate buffer
1351 ; that will end up being copied into the original
1352 ; struct-return buffer (pointed to by the marg_listed r3).
1353 subi r0,r6,(3*4)-3 ; make word count from byte count rounded up to multiple of 4...
1354 srwi. r0,r0,2 ; ... and subtracting for params already in r3 and r4 and r5
1355 beq LMsgSendvStretSendIt ; branch if there are no parameters to load
1356 mtctr r0 ; counter = number of remaining words
1357 lwz r6,36+(13*8)(r7) ; load 4th parameter
1358 bdz LMsgSendvStretSendIt ; decrement counter, branch if result is zero
1359 addi r11,r7,40+(13*8) ; switch to r11, because we are setting r7
1360 lwz r7,0(r11) ; load 5th parameter
1361 bdz LMsgSendvStretSendIt ; decrement counter, branch if result is zero
1362 lwz r8,4(r11) ; load 6th parameter
1363 bdz LMsgSendvStretSendIt ; decrement counter, branch if result is zero
1364 lwz r9,8(r11) ; load 7th parameter
1365 bdz LMsgSendvStretSendIt ; decrement counter, branch if result is zero
1366 lwzu r10,12(r11) ; load 8th parameter, and update r11
1367 bdz LMsgSendvStretSendIt ; decrement counter, branch if result is zero
1369 ; copy the stack based arguments from the marg_list
1370 addi r12,r1,24+32-4 ; target = address of stack based parameters
1371 LMsgSendvStretArgLoop:
1372 lwzu r0,4(r11) ; loop to copy remaining marg_list words to stack
1374 bdnz LMsgSendvStretArgLoop ; decrement counter, branch if still non-zero
1376 LMsgSendvStretSendIt:
1377 bl _objc_msgSend_stret ; struct_type objc_msgSend_stret (self, selector, ...)
1379 lwz r1,0(r1) ; restore stack pointer
1380 lwz r0,8(r1) ; restore return pc
1384 trap ; _objc_msgSendv_stret is not for the kernel
1385 #endif /* !KERNEL */
1387 END_ENTRY _objc_msgSendv_stret