2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.1 (the "License"). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
14 * The Original Code and all software distributed under the License are
15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
22 * @APPLE_LICENSE_HEADER_END@
24 /********************************************************************
26 * objc-msg-ppc.s - PowerPC code to support objc messaging.
28 * Copyright 1988-1996 NeXT Software, Inc.
30 * 8-Nov-2000 Laurent Ramontianu (ramontia@apple.com)
31 * Added "few args" params. to CacheLookup and MethodTableLookup
32 * Added the alternate entry points:
33 * objc_msgSendFew, objc_msgSendFew_stret,
34 * objc_msgSendSuperFew, objc_msgSendSuperFew_stret
36 * 18-Jun-97 David Harrison (harrison@apple.com)
39 * 1-May-97 Umesh Vaishampayan (umeshv@NeXT.com)
40 * Incorporated locking code fixes from
41 * David Harrison (harrison@NeXT.com)
43 * 2-Apr-97 Umesh Vaishampayan (umeshv@NeXT.com)
44 * Incorporated changes for messenger with struct return
45 * Cleaned up the labels to use local labels
46 * Fixed bug in the msgSendSuper that did not do the locking.
48 * 31-Dec-96 Umesh Vaishampayan (umeshv@NeXT.com)
50 ********************************************************************/
52 #if defined(OBJC_COLLECTING_CACHE)
53 ; _objc_entryPoints and _objc_exitPoints are used by method dispatch
54 ; caching code to figure out whether any threads are actively
55 ; in the cache for dispatching. The labels surround the asm code
56 ; that do cache lookups. The tables are zero-terminated.
58 .globl _objc_entryPoints
61 .long _objc_msgSend_stret
62 .long _objc_msgSendSuper
63 .long _objc_msgSendSuper_stret
64 .long _objc_msgSendFew
65 .long _objc_msgSendFew_stret
66 .long _objc_msgSendSuperFew
67 .long _objc_msgSendSuperFew_stret
70 .globl _objc_exitPoints
73 .long LMsgSendStretExit
74 .long LMsgSendSuperExit
75 .long LMsgSendSuperStretExit
77 .long LMsgSendFewStretExit
78 .long LMsgSendSuperFewExit
79 .long LMsgSendSuperFewStretExit
83 /********************************************************************
85 * Structure definitions.
87 ********************************************************************/
89 ; objc_super parameter to sendSuper
93 ; Selected field offsets in class structure
104 buckets = 8 // variable length array
106 #if defined(OBJC_INSTRUMENTED)
107 ; Cache instrumentation data, follows buckets
109 hitProbes = hitCount + 4
110 maxHitProbes = hitProbes + 4
111 missCount = maxHitProbes + 4
112 missProbes = missCount + 4
113 maxMissProbes = missProbes + 4
114 flushCount = maxMissProbes + 4
115 flushedEntries = flushCount + 4
118 /********************************************************************
122 ********************************************************************/
124 // In case the implementation is _objc_msgForward, indicate to it
125 // whether the method was invoked as a word-return or struct-return.
126 // The li instruction costs nothing because it fits into spare
132 /********************************************************************
134 * Useful macros. Macros are used instead of subroutines, for speed.
136 ********************************************************************/
138 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
140 ; LOAD_STATIC_WORD targetReg, symbolName, LOCAL_SYMBOL | EXTERNAL_SYMBOL
142 ; Load the value of the named static data word.
144 ; Takes: targetReg - the register, other than r0, to load
145 ; symbolName - the name of the symbol
146 ; LOCAL_SYMBOL - symbol name used as-is
147 ; EXTERNAL_SYMBOL - symbol name gets nonlazy treatment
149 ; Eats: r0 and targetReg
150 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
152 ; Values to specify whether the symbols is plain or nonlazy
156 .macro LOAD_STATIC_WORD
158 #if defined(__DYNAMIC__)
163 .if $2 == EXTERNAL_SYMBOL
164 addis $0,$0,ha16(L$1-1b)
165 lwz $0,lo16(L$1-1b)($0)
167 .elseif $2 == LOCAL_SYMBOL
168 addis $0,$0,ha16($1-1b)
169 lwz $0,lo16($1-1b)($0)
171 !!! Unknown symbol type !!!
180 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
182 ; LEA_STATIC_DATA targetReg, symbolName, LOCAL_SYMBOL | EXTERNAL_SYMBOL
184 ; Load the address of the named static data.
186 ; Takes: targetReg - the register, other than r0, to load
187 ; symbolName - the name of the symbol
188 ; LOCAL_SYMBOL - symbol is local to this module
189 ; EXTERNAL_SYMBOL - symbol is imported from another module
191 ; Eats: r0 and targetReg
192 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
194 .macro LEA_STATIC_DATA
195 #if defined(__DYNAMIC__)
200 .if $2 == EXTERNAL_SYMBOL
201 addis $0,$0,ha16(L$1-1b)
202 lwz $0,lo16(L$1-1b)($0)
203 .elseif $2 == LOCAL_SYMBOL
204 addis $0,$0,ha16($1-1b)
205 addi $0,$0,lo16($1-1b)
207 !!! Unknown symbol type !!!
216 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
220 ; Assembly directives to begin an exported function.
222 ; Takes: functionName - name of the exported function
223 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
232 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
234 ; END_ENTRY functionName
236 ; Assembly directives to end an exported function. Just a placeholder,
237 ; a close-parenthesis for ENTRY, until it is needed for something.
239 ; Takes: functionName - name of the exported function
240 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
245 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
247 ; PLOCK scratchReg, lockName
249 ; Acquire named spinlock.
251 ; Takes: scratchReg - a register, other than r0, that can be mangled
252 ; lockName - the name of a static, aligned, 32-bit lock word
254 ; Eats: r0 and scratchReg
255 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
258 LEA_STATIC_DATA $0, $1, EXTERNAL_SYMBOL
259 b .+16 ; jump into loop at the reserving check
260 lwz r0,0($0) ; check with fast, less intrusive lwz versus lwarx
261 cmplwi r0,0 ; lock held?
262 bne .-8 ; if so, spin until it appears unlocked
263 lwarx r0,0,$0 ; get lock value, acquire memory reservation
264 cmplwi r0,0 ; lock held?
265 bne .-20 ; if locked, go spin waiting for unlock
266 li r0,1 ; get value that means locked
267 sync ; PPC errata #7: Avoid address comparison qualification failure
268 stwcx. r0,0,$0 ; store it iff reservation still holds
269 bne- .-20 ; if reservation was lost, go re-reserve
270 isync ; discard effects of prefetched instructions
273 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
275 ; PUNLOCK scratchReg, lockName
277 ; Release named spinlock.
279 ; Takes: scratchReg - a register, other than r0, that can be mangled
280 ; lockName - the name of a static, aligned, 32-bit lock word
282 ; Eats: r0 and scratchReg
283 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
286 sync ; force out changes before unlocking
287 LEA_STATIC_DATA $0, $1, EXTERNAL_SYMBOL
288 li r0,0 ; get value meaning "unlocked"
289 stw r0,0($0) ; unlock the lock
293 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
295 ; CacheLookup WORD_RETURN | STRUCT_RETURN, MSG_SEND | MSG_SENDSUPER, cacheMissLabel, FEW_ARGS | MANY_ARGS
297 ; Locate the implementation for a selector in a class method cache.
299 ; Takes: WORD_RETURN (r3 is first parameter)
300 ; STRUCT_RETURN (r3 is structure return address, r4 is first parameter)
301 ; MSG_SEND (first parameter is receiver)
302 ; MSG_SENDSUPER (first parameter is address of objc_super structure)
304 ; cacheMissLabel = label to branch to iff method is not cached
307 ; On exit: (found) imp in ctr register
308 ; (not found) jumps to cacheMissLabel
310 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
312 ; Values to specify to method lookup macros whether the return type of
313 ; the method is an integer or structure.
317 ; Values to specify to method lookup macros whether the return type of
318 ; the method is an integer or structure.
322 ; Values to specify to method lookup macros whether this is a "few args" call or not
323 ; (number of args < 5 , including self and _cmd)
329 #if defined(OBJC_INSTRUMENTED)
330 ; when instrumented, we use r6 and r7
331 stw r6,36(r1) ; save r6 for use as cache pointer
332 stw r7,40(r1) ; save r7 for use as probe count
333 li r7,0 ; no probes so far!
336 stw r8,44(r1) ; save r8
338 stw r9,48(r1) ; save r9 and r10
343 .if $0 == WORD_RETURN ; WORD_RETURN
345 .if $1 == MSG_SEND ; MSG_SEND
346 lwz r12,isa(r3) ; class = receiver->isa
347 .else ; MSG_SENDSUPER
348 lwz r12,class(r3) ; class = super->class
353 .if $1 == MSG_SEND ; MSG_SEND
354 lwz r12,isa(r4) ; class = receiver->isa
355 .else ; MSG_SENDSUPER
356 lwz r12,class(r4) ; class = super->class
361 lwz r12,cache(r12) ; cache = class->cache
362 #if defined(OBJC_INSTRUMENTED)
363 mr r6,r12 ; save cache pointer
365 lwz r11,mask(r12) ; mask = cache->mask
366 addi r9,r12,buckets ; buckets = cache->buckets
367 .if $0 == WORD_RETURN ; WORD_RETURN
368 and r12,r4,r11 ; index = selector & mask
369 .else ; STRUCT_RETURN
370 and r12,r5,r11 ; index = selector & mask
373 #if defined(OBJC_INSTRUMENTED)
377 ; r6 = cache, r7 = probeCount
378 lwz r9,mask(r6) ; entryCount = mask + 1
380 slwi r9,r9,2 ; tableSize = entryCount * sizeof(entry)
381 addi r9,r9,buckets ; offset = buckets + tableSize
382 add r8,r6,r9 ; cacheData = &cache->buckets[mask+1]
383 lwz r9,missCount(r8) ; cacheData->missCount += 1
385 stw r9,missCount(r8) ;
386 lwz r9,missProbes(r8) ; cacheData->missProbes += probeCount
388 stw r9,missProbes(r8) ;
389 lwz r9,maxMissProbes(r8) ; if (probeCount > cacheData->maxMissProbes)
390 cmplw r7,r9 ; maxMissProbes = probeCount
392 stw r7,maxMissProbes(r8) ;
394 lwz r6,36(r1) ; restore r6
395 lwz r7,40(r1) ; restore r7
397 b $2 ; goto cacheMissLabel
402 #if defined(OBJC_INSTRUMENTED)
403 addi r7,r7,1 ; probeCount += 1
405 slwi r0,r12,2 ; convert word index into byte count
406 lwzx r10,r9,r0 ; method = cache->buckets[index]
407 cmplwi r10,0 ; if (method == NULL)
408 #if defined(OBJC_INSTRUMENTED)
411 beq $2 ; goto cacheMissLabel
414 addi r12,r12,1 ; index += 1
415 lwz r8,method_name(r10) ; name = method->method_name
416 and r12,r12,r11 ; index &= mask
417 lwz r10,method_imp(r10) ; imp = method->method_imp
418 .if $0 == WORD_RETURN ; WORD_RETURN
419 cmplw r8,r4 ; if (name != selector)
420 .else ; STRUCT_RETURN
421 cmplw r8,r5 ; if (name != selector)
423 bne LLoop_$0_$1_$2 ; goto loop
425 ; cache hit, r10 == method implementation address
426 mr r12,r10 ; copy implementation to r12
427 mtctr r10 ; ctr = imp
429 #if defined(OBJC_INSTRUMENTED)
430 ; r6 = cache, r7 = probeCount
431 lwz r9,mask(r6) ; entryCount = mask + 1
433 slwi r9,r9,2 ; tableSize = entryCount * sizeof(entry)
434 addi r9,r9,buckets ; offset = buckets + tableSize
435 add r8,r6,r9 ; cacheData = &cache->buckets[mask+1]
436 lwz r9,hitCount(r8) ; cache->hitCount += 1
438 stw r9,hitCount(r8) ;
439 lwz r9,hitProbes(r8) ; cache->hitProbes += probeCount
441 stw r9,hitProbes(r8) ;
442 lwz r9,maxHitProbes(r8) ; if (probeCount > cache->maxMissProbes)
443 cmplw r7,r9 ;maxMissProbes = probeCount
445 stw r7,maxHitProbes(r8) ;
447 lwz r6,36(r1) ; restore r6
448 lwz r7,40(r1) ; restore r7
451 lwz r8,44(r1) ; restore r8
453 lwz r9,48(r1) ; restore r9 and r10
460 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
463 ; MethodTableLookup WORD_RETURN | STRUCT_RETURN, MSG_SEND | MSG_SENDSUPER, FEW_ARGS | MANY_ARGS
465 ; Takes: WORD_RETURN (r3 is first parameter)
466 ; STRUCT_RETURN (r3 is structure return address, r4 is first parameter)
467 ; MSG_SEND (first parameter is receiver)
468 ; MSG_SENDSUPER (first parameter is address of objc_super structure)
471 ; On exit: restores registers r8 and possibly, r9 and r10, saved by CacheLookup
473 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
475 HAVE_CALL_EXTERN_lookupMethodAndLoadCache = 0
477 .macro MethodTableLookup
478 stw r3, 24(r1) ; save arguments
483 ; r8 and possibly, r9 and r10, were saved by CacheLookup
489 stwu r1,-64(r1) ; grow the stack
493 stfd f13, -8(r1) ; save the fp parameter registers
508 stwu r1,-56-(13*8)(r1) ; grow the stack
511 ; Pass parameters to __class_lookupMethodAndLoadCache. First parameter is
512 ; the class pointer. Second parameter is the selector. Where they come
513 ; from depends on who called us. In the int return case, the selector is
515 .if $0 == WORD_RETURN ; WORD_RETURN
516 .if $1 == MSG_SEND ; MSG_SEND
517 lwz r3,isa(r3) ; class = receiver->isa
518 .else ; MSG_SENDSUPER
519 lwz r3,class(r3) ; class = super->class
522 .else ; STRUCT_RETURN
523 .if $1 == MSG_SEND ; MSG_SEND
524 lwz r3,isa(r4) ; class = receiver->isa
525 .else ; MSG_SENDSUPER
526 lwz r3,class(r4) ; class = super->class
528 mr r4,r5 ; selector = selector
531 .if HAVE_CALL_EXTERN_lookupMethodAndLoadCache == 0
532 HAVE_CALL_EXTERN_lookupMethodAndLoadCache = 1
533 CALL_EXTERN(__class_lookupMethodAndLoadCache)
535 CALL_EXTERN_AGAIN(__class_lookupMethodAndLoadCache)
538 mr r12,r3 ; copy implementation to r12
539 mtctr r3 ; copy imp to ctr
540 lwz r1,0(r1) ; restore the stack pointer
542 mtlr r0 ; restore return pc
547 lfd f13, -8(r1) ; restore fp parameter registers
563 lwz r3, 24(r1) ; restore parameter registers
569 lwz r8, 44(r1) ; restore leftovers from CacheLookup...
578 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
582 ; Macro to call mcount function in profiled builds.
584 ; NOTE: Makes sure to save/restore r11 and r12, even though they
585 ; are not defined to be volatile, because they are used during
588 ; Takes: lr Callers return PC
591 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
593 HAVE_CALL_EXTERN_mcount = 0
597 mflr r0 ; save return pc
600 stwu r1,-208(r1) ; push aligned areas, set stack link
602 stw r3, 56(r1) ; save all volatile registers
610 stw r11,88(r1) ; save r11 and r12, too
627 mflr r3 ; pass our callers address
628 .if HAVE_CALL_EXTERN_mcount == 0
629 HAVE_CALL_EXTERN_mcount = 1
632 CALL_EXTERN_AGAIN(mcount)
635 lwz r3, 56(r1) ; restore all volatile registers
643 lwz r11,88(r1) ; restore r11 and r12, too
660 lwz r1,0(r1) ; restore the stack pointer
662 mtlr r0 ; restore return pc
666 /********************************************************************
667 * id objc_msgSend(id self,
671 * On entry: r3 is the message receiver,
673 ********************************************************************/
675 #if defined(__DYNAMIC__)
676 /* Allocate reference to external static data */
677 .non_lazy_symbol_pointer
679 .indirect_symbol __objc_msgNil
685 ; do profiling when enabled
688 ; check whether receiver is nil
689 cmplwi r3,0 ; receiver nil?
690 beq LMsgSendNilSelf ; if so, call handler or return nil
692 #if !defined(OBJC_COLLECTING_CACHE)
693 ; check whether context is multithreaded
694 lis r11,ha16(__objc_multithread_mask)
695 lwz r11,lo16(__objc_multithread_mask)(r11)
696 cmplwi r11,0 ; objc_multithread_mask zero?
697 beq LMsgSendMT ; branch to the locking case
700 ; single threaded and receiver is non-nil: search the cache
701 CacheLookup WORD_RETURN, MSG_SEND, LMsgSendCacheMiss, MANY_ARGS
702 li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
705 ; cache miss: go search the method lists
707 MethodTableLookup WORD_RETURN, MSG_SEND, MANY_ARGS
708 li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
711 #if !defined(OBJC_COLLECTING_CACHE)
712 ; multithreaded: hold _messageLock while accessing cache
714 PLOCK r11, _messageLock
715 CacheLookup WORD_RETURN, MSG_SEND, LMsgSendMTCacheMiss, MANY_ARGS
716 PUNLOCK r11, _messageLock
717 li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
720 ; cache miss: go search the method lists
722 MethodTableLookup WORD_RETURN, MSG_SEND, MANY_ARGS
723 PUNLOCK r11, _messageLock
724 li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
728 ; message sent to nil object call: optional handler and return nil
730 LOAD_STATIC_WORD r11, __objc_msgNil, EXTERNAL_SYMBOL
731 cmplwi r11,0 ; handler nil?
732 beqlr ; if no handler, return nil
734 mflr r0 ; save return pc
736 subi r1,r1,64 ; allocate linkage area
739 addi r1,r1,64 ; deallocate linkage area
740 lwz r0,8(r1) ; restore return pc
743 li r3,0 ; re-zero return value, in case handler changed it
744 blr ; return to caller
747 END_ENTRY _objc_msgSend
750 /********************************************************************
751 * struct_type objc_msgSend_stret(id self,
755 * objc_msgSend_stret is the struct-return form of msgSend.
756 * The ABI calls for r3 to be used as the address of the structure
757 * being returned, with the parameters in the succeeding registers.
759 * On entry: r3 is the address where the structure is returned,
760 * r4 is the message receiver,
762 ********************************************************************/
764 ENTRY _objc_msgSend_stret
765 ; do profiling when enabled
768 ; check whether receiver is nil
769 cmplwi r4,0 ; receiver nil?
770 beq LMsgSendStretNilSelf ; if so, call handler or just return
772 #if !defined(OBJC_COLLECTING_CACHE)
773 ; check whether context is multithreaded
774 lis r11,ha16(__objc_multithread_mask)
775 lwz r11,lo16(__objc_multithread_mask)(r11)
776 cmplwi r11,0 ; objc_multithread_mask zero?
777 beq LMsgSendStretMT ; branch to the locking case
780 ; single threaded and receiver is non-nil: search the cache
781 CacheLookup STRUCT_RETURN, MSG_SEND, LMsgSendStretCacheMiss, MANY_ARGS
782 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
785 ; cache miss: go search the method lists
786 LMsgSendStretCacheMiss:
787 MethodTableLookup STRUCT_RETURN, MSG_SEND, MANY_ARGS
788 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
791 #if !defined(OBJC_COLLECTING_CACHE)
792 ; multithreaded: hold _messageLock while accessing cache
794 PLOCK r11, _messageLock
795 CacheLookup STRUCT_RETURN, MSG_SEND, LMsgSendStretMTCacheMiss, MANY_ARGS
796 PUNLOCK r11, _messageLock
797 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
800 ; cache miss: go search the method lists
801 LMsgSendStretMTCacheMiss:
802 MethodTableLookup STRUCT_RETURN, MSG_SEND, MANY_ARGS
803 PUNLOCK r11, _messageLock
804 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
808 ; message sent to nil object call optional handler and return nil
809 LMsgSendStretNilSelf:
810 LOAD_STATIC_WORD r11, __objc_msgNil, EXTERNAL_SYMBOL
811 cmplwi r11,0 ; handler nil?
812 beqlr ; if no handler, return
814 mflr r0 ; save return pc
816 subi r1,r1,64 ; allocate linkage area
817 mr r3,r4 ; move self to r3
818 mr r4,r5 ; move SEL to r4
821 addi r1,r1,64 ; deallocate linkage area
822 lwz r0,8(r1) ; restore return pc
825 blr ; return to caller
828 END_ENTRY _objc_msgSend_stret
831 /********************************************************************
832 * id objc_msgSendSuper(struct objc_super *super,
836 * struct objc_super {
840 ********************************************************************/
842 ENTRY _objc_msgSendSuper
843 ; do profiling when enabled
846 #if !defined(OBJC_COLLECTING_CACHE)
847 ; check whether context is multithreaded
848 lis r11,ha16(__objc_multithread_mask)
849 lwz r11,lo16(__objc_multithread_mask)(r11)
850 cmplwi r11,0 ; objc_multithread_mask zero?
851 beq LMsgSendSuperMT ; branch to the locking case
854 ; single threaded: search the cache
855 CacheLookup WORD_RETURN, MSG_SENDSUPER, LMsgSendSuperCacheMiss, MANY_ARGS
856 lwz r3,receiver(r3) ; receiver is the first arg
857 li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
860 ; cache miss: go search the method lists
861 LMsgSendSuperCacheMiss:
862 MethodTableLookup WORD_RETURN, MSG_SENDSUPER, MANY_ARGS
863 lwz r3,receiver(r3) ; receiver is the first arg
864 li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
867 #if !defined(OBJC_COLLECTING_CACHE)
868 ; multithreaded: hold _messageLock while accessing cache
870 PLOCK r11, _messageLock
871 CacheLookup WORD_RETURN, MSG_SENDSUPER, LMsgSendSuperMTCacheMiss, MANY_ARGS
872 PUNLOCK r11, _messageLock
873 lwz r3,receiver(r3) ; receiver is the first arg
874 li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
877 ; cache miss: go search the method lists
878 LMsgSendSuperMTCacheMiss:
879 MethodTableLookup WORD_RETURN, MSG_SENDSUPER, MANY_ARGS
880 PUNLOCK r11, _messageLock
881 lwz r3,receiver(r3) ; receiver is the first arg
882 li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
887 END_ENTRY _objc_msgSendSuper
890 /********************************************************************
891 * struct_type objc_msgSendSuper_stret(objc_super *super,
895 * struct objc_super {
901 * objc_msgSendSuper_stret is the struct-return form of msgSendSuper.
902 * The ABI calls for r3 to be used as the address of the structure
903 * being returned, with the parameters in the succeeding registers.
905 * On entry: r3 is the address to which to copy the returned structure,
906 * r4 is the address of the objc_super structure,
908 ********************************************************************/
910 ENTRY _objc_msgSendSuper_stret
911 ; do profiling when enabled
914 #if !defined(OBJC_COLLECTING_CACHE)
915 ; check whether context is multithreaded
916 lis r11,ha16(__objc_multithread_mask)
917 lwz r11,lo16(__objc_multithread_mask)(r11)
918 cmplwi r11,0 ; objc_multithread_mask zero?
919 beq LMsgSendSuperStretMT ; branch to the locking case
922 ; single threaded: search the cache
923 CacheLookup STRUCT_RETURN, MSG_SENDSUPER, LMsgSendSuperStretCacheMiss, MANY_ARGS
924 lwz r4,receiver(r4) ; receiver is the first arg
925 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
928 ; cache miss: go search the method lists
929 LMsgSendSuperStretCacheMiss:
930 MethodTableLookup STRUCT_RETURN, MSG_SENDSUPER, MANY_ARGS
931 lwz r4,receiver(r4) ; receiver is the first arg
932 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
935 #if !defined(OBJC_COLLECTING_CACHE)
936 ; multithreaded: hold _messageLock while accessing cache
937 LMsgSendSuperStretMT:
938 PLOCK r11, _messageLock
939 CacheLookup STRUCT_RETURN, MSG_SENDSUPER, LMsgSendSuperStretMTCacheMiss, MANY_ARGS
940 PUNLOCK r11, _messageLock
941 lwz r4,receiver(r4) ; receiver is the first arg
942 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
945 ; cache miss: go search the method lists
946 LMsgSendSuperStretMTCacheMiss:
947 MethodTableLookup STRUCT_RETURN, MSG_SENDSUPER, MANY_ARGS
948 PUNLOCK r11, _messageLock
949 lwz r4,receiver(r4) ; receiver is the first arg
950 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
954 LMsgSendSuperStretExit:
955 END_ENTRY _objc_msgSendSuper_stret
958 /********************************************************************
960 * Out-of-band parameter r11 indicates whether it was objc_msgSend or
961 * objc_msgSend_stret that triggered the message forwarding. The
963 * Iff r11 == kFwdMsgSend, it is the word-return (objc_msgSend) case,
964 * and the interface is:
966 * id _objc_msgForward(id self,
970 * Iff r11 == kFwdMsgSendStret, it is the structure-return
971 * (objc_msgSend_stret) case, and the interface is:
973 * struct_type _objc_msgForward(id self,
977 * There are numerous reasons why it is better to have one
978 * _objc_msgForward, rather than adding _objc_msgForward_stret.
979 * The best one is that _objc_msgForward is the method that
980 * gets cached when respondsToMethod returns false, and it
981 * wouldnt know which one to use.
983 * Sends the message to a method having the signature
985 * - forward:(SEL)sel :(marg_list)args;
987 * But the marg_list is prepended with the 13 double precision
988 * floating point registers that could be used as parameters into
989 * the method (fortunately, the same registers are used for either
990 * single or double precision floats). These registers are layed
991 * down by _objc_msgForward, and picked up by _objc_msgSendv. So
992 * the "marg_list" is actually:
994 * typedef struct objc_sendv_margs {
995 * double floatingPointArgs[13];
996 * int linkageArea[6];
997 * int registerArgs[8];
998 * int stackArgs[variable];
1001 ********************************************************************/
1003 ; Location LFwdStr contains the string "forward::"
1004 ; Location LFwdSel contains a pointer to LFwdStr, that can be changed
1005 ; to point to another forward:: string for selector uniquing
1006 ; purposes. ALWAYS dereference LFwdSel to get to "forward::" !!
1007 .objc_meth_var_names
1009 LFwdStr: .ascii "forward::\0"
1013 LFwdSel:.long LFwdStr
1017 LUnkSelStr: .ascii "Does not recognize selector %s\0"
1019 ENTRY __objc_msgForward
1020 ; do profiling when enabled
1024 trap ; _objc_msgForward is not for the kernel
1026 LOAD_STATIC_WORD r12, LFwdSel, LOCAL_SYMBOL ; get uniqued selector for "forward::"
1027 cmplwi r11,kFwdMsgSend ; via objc_msgSend or objc_msgSend_stret?
1028 bne LMsgForwardStretSel ; branch for objc_msgSend_stret
1029 cmplw r12,r4 ; if (sel == @selector (forward::))
1030 b LMsgForwardSelCmpDone ; check the result in common code
1031 LMsgForwardStretSel:
1032 cmplw r12,r5 ; if (sel == @selector (forward::))
1033 LMsgForwardSelCmpDone:
1034 beq LMsgForwardError ; goto error
1037 stw r0,8(r1) ; save lr
1039 stw r3, 24(r1) ; put register arguments on stack for forwarding
1040 stw r4, 28(r1) ; (stack based args already follow this area)
1048 stfd f13, -8(r1) ; prepend floating point registers to marg_list
1062 cmplwi r11,kFwdMsgSend ; via objc_msgSend or objc_msgSend_stret?
1063 bne LMsgForwardStretParams ; branch for objc_msgSend_stret
1064 ; first arg (r3) remains self
1065 mr r5,r4 ; third arg is previous selector
1066 b LMsgForwardParamsDone
1067 LMsgForwardStretParams:
1068 mr r3,r4 ; first arg is self
1069 ; third arg (r5) remains previous selector
1070 LMsgForwardParamsDone:
1071 mr r4,r12 ; second arg is "forward::"
1072 subi r6,r1,13*8 ; fourth arg is &objc_sendv_margs
1074 stwu r1,-56-(13*8)(r1) ; push aligned linkage and parameter areas, set stack link
1075 bl _objc_msgSend ; [self forward:sel :objc_sendv_margs]
1076 addi r1,r1,56+13*8 ; deallocate linkage and parameters areas
1078 lwz r0,8(r1) ; restore lr
1082 ; call error handler with unrecognized selector message
1084 cmplwi r11,kFwdMsgSendStret ; via objc_msgSend or objc_msgSend_stret?
1085 bne LMsgForwardErrorParamsOK; branch for objc_msgSend
1086 mr r3,r4 ; first arg is self
1087 LMsgForwardErrorParamsOK:
1088 LEA_STATIC_DATA r4, LUnkSelStr, LOCAL_SYMBOL
1089 mr r5,r12 ; third arg is "forward::"
1090 CALL_EXTERN(___objc_error) ; never returns
1091 trap ; ___objc_error should never return
1094 END_ENTRY __objc_msgForward
1097 /********************************************************************
1098 * id objc_msgSendv(id self,
1100 * unsigned arg_size,
1101 * marg_list arg_frame);
1103 * But the marg_list is prepended with the 13 double precision
1104 * floating point registers that could be used as parameters into
1105 * the method (fortunately, the same registers are used for either
1106 * single or double precision floats). These registers are layed
1107 * down by _objc_msgForward, and picked up by _objc_msgSendv. So
1108 * the "marg_list" is actually:
1110 * typedef struct objc_sendv_margs {
1111 * double floatingPointArgs[13];
1112 * int linkageArea[6];
1113 * int registerArgs[8];
1114 * int stackArgs[variable];
1117 * arg_size is the number of bytes of parameters in registerArgs and
1118 * stackArgs combined (i.e. it is method_getSizeOfArguments(method)).
1119 * Specifically, it is NOT the overall arg_frame size, because that
1120 * would include the floatingPointArgs and linkageArea, which are
1121 * PowerPC-specific. This is consistent with the other architectures.
1122 ********************************************************************/
1124 ENTRY _objc_msgSendv
1127 trap ; _objc_msgSendv is not for the kernel
1129 ; do profiling when enabled
1133 stw r0,8(r1) ; save lr
1135 cmplwi r5,32 ; check parameter size against minimum
1136 ble+ LMsgSendvMinFrame ; is less than minimum, go use minimum
1137 mr r12,r1 ; remember current stack pointer
1138 sub r11,r1,r5 ; push parameter area
1139 rlwinm r1,r11,0,0,27 ; align stack pointer to 16 byte boundary
1140 stwu r12,-32(r1) ; push aligned linkage area, set stack link
1141 b LMsgSendvHaveFrame
1144 stwu r1,-64(r1) ; push aligned linkage and parameter areas, set stack link
1147 ; restore floating point register parameters from marg_list
1162 ; load the register based arguments from the marg_list
1163 ; the first two parameters are already in r3 and r4, respectively
1164 subi r0,r5,5 ; make word count from byte count rounded up to multiple of 4...
1165 srwi. r0,r0,2 ; ... and subtracting for params already in r3 and r4
1166 beq LMsgSendvSendIt ; branch if there are no parameters to load
1167 mtctr r0 ; counter = number of remaining words
1168 lwz r5,32+(13*8)(r6) ; load 3rd parameter
1169 bdz LMsgSendvSendIt ; decrement counter, branch if result is zero
1170 addi r11,r6,36+(13*8) ; switch to r11, because we are setting r6
1171 lwz r6,0(r11) ; load 4th parameter
1172 bdz LMsgSendvSendIt ; decrement counter, branch if result is zero
1173 lwz r7,4(r11) ; load 5th parameter
1174 bdz LMsgSendvSendIt ; decrement counter, branch if result is zero
1175 lwz r8,8(r11) ; load 6th parameter
1176 bdz LMsgSendvSendIt ; decrement counter, branch if result is zero
1177 lwz r9,12(r11) ; load 7th parameter
1178 bdz LMsgSendvSendIt ; decrement counter, branch if result is zero
1179 lwzu r10,16(r11) ; load 8th parameter, and update r11
1180 bdz LMsgSendvSendIt ; decrement counter, branch if result is zero
1182 ; copy the stack based arguments from the marg_list
1183 addi r12,r1,24+32-4 ; target = address of stack based parameters
1185 lwzu r0,4(r11) ; loop to copy remaining marg_list words to stack
1187 bdnz LMsgSendvArgLoop ; decrement counter, branch if still non-zero
1190 bl _objc_msgSend ; objc_msgSend (self, selector, ...)
1192 lwz r1,0(r1) ; restore stack pointer
1193 lwz r0,8(r1) ; restore lr
1198 END_ENTRY _objc_msgSendv
1201 /********************************************************************
1202 * struct_type objc_msgSendv_stret(id self,
1204 * unsigned arg_size,
1205 * marg_list arg_frame);
1207 * objc_msgSendv_stret is the struct-return form of msgSendv.
1208 * The ABI calls for r3 to be used as the address of the structure
1209 * being returned, with the parameters in the succeeding registers.
1211 * An equally correct way to prototype this routine is:
1213 * void objc_msgSendv_stret(void *structStorage,
1216 * unsigned arg_size,
1217 * marg_list arg_frame);
1219 * which is useful in, for example, message forwarding where the
1220 * structure-return address needs to be passed in.
1222 * The ABI for the two cases are identical.
1224 * On entry: r3 is the address in which the returned struct is put,
1225 * r4 is the message receiver,
1226 * r5 is the selector,
1227 * r6 is the size of the marg_list, in bytes,
1228 * r7 is the address of the marg_list
1229 ********************************************************************/
1231 ENTRY _objc_msgSendv_stret
1234 trap ; _objc_msgSendv_stret is not for the kernel
1236 ; do profiling when enabled
1240 stw r0,8(r1) ; (save return pc)
1242 cmplwi r6,32 ; check parameter size against minimum
1243 ble+ LMsgSendvStretMinFrame ; is less than minimum, go use minimum
1244 mr r12,r1 ; remember current stack pointer
1245 sub r11,r1,r6 ; push parameter area
1246 rlwinm r1,r11,0,0,27 ; align stack pointer to 16 byte boundary
1247 stwu r12,-32(r1) ; push aligned linkage area, set stack link
1248 b LMsgSendvStretHaveFrame
1250 LMsgSendvStretMinFrame:
1251 stwu r1,-64(r1) ; push aligned linkage and parameter areas, set stack link
1253 LMsgSendvStretHaveFrame:
1254 ; restore floating point register parameters from marg_list
1269 ; load the register based arguments from the marg_list
1270 ; the structure return address and the first two parameters
1271 ; are already in r3, r4, and r5, respectively.
1272 ; NOTE: The callers r3 probably, but not necessarily, matches
1273 ; the r3 in the marg_list. That is, the struct-return
1274 ; storage used by the caller could be an intermediate buffer
1275 ; that will end up being copied into the original
1276 ; struct-return buffer (pointed to by the marg_listed r3).
1277 subi r0,r6,5 ; make word count from byte count rounded up to multiple of 4...
1278 srwi. r0,r0,2 ; ... and subtracting for params already in r4 and r5
1279 beq LMsgSendvStretSendIt ; branch if there are no parameters to load
1280 mtctr r0 ; counter = number of remaining words
1281 lwz r6,36+(13*8)(r7) ; load 4th parameter
1282 bdz LMsgSendvStretSendIt ; decrement counter, branch if result is zero
1283 addi r11,r7,40+(13*8) ; switch to r11, because we are setting r7
1284 lwz r7,0(r11) ; load 5th parameter
1285 bdz LMsgSendvStretSendIt ; decrement counter, branch if result is zero
1286 lwz r8,4(r11) ; load 6th parameter
1287 bdz LMsgSendvStretSendIt ; decrement counter, branch if result is zero
1288 lwz r9,8(r11) ; load 7th parameter
1289 bdz LMsgSendvStretSendIt ; decrement counter, branch if result is zero
1290 lwzu r10,12(r11) ; load 8th parameter, and update r11
1291 bdz LMsgSendvStretSendIt ; decrement counter, branch if result is zero
1293 ; copy the stack based arguments from the marg_list
1294 addi r12,r1,24+32-4 ; target = address of stack based parameters
1295 LMsgSendvStretArgLoop:
1296 lwzu r0,4(r11) ; loop to copy remaining marg_list words to stack
1298 bdnz LMsgSendvStretArgLoop ; decrement counter, branch if still non-zero
1300 LMsgSendvStretSendIt:
1301 bl _objc_msgSend_stret ; struct_type objc_msgSend_stret (self, selector, ...)
1303 lwz r1,0(r1) ; restore stack pointer
1304 lwz r0,8(r1) ; restore return pc
1309 END_ENTRY _objc_msgSendv_stret
1312 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1314 ; **************** THE "FEW" API ****************
1316 ; The "few args" apis; The compiler needs to be updated to generate calls to
1317 ; these functions, rather than to their counterparts, when the number of
1318 ; arguments to a method is < 6 (5 for struct returns).
1320 ; *************************************************
1322 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1324 /********************************************************************
1325 * id objc_msgSendFew(id self,
1329 * On entry: r3 is the message receiver,
1330 * r4 is the selector
1331 * + at most 3 args (ints or doubles)
1332 ********************************************************************/
1334 ENTRY _objc_msgSendFew
1335 ; do profiling when enabled
1338 ; check whether receiver is nil
1339 cmplwi r3,0 ; receiver nil?
1340 beq LMsgSendFewNilSelf ; if so, call handler or return nil
1342 #if !defined(OBJC_COLLECTING_CACHE)
1343 ; check whether context is multithreaded
1344 lis r11,ha16(__objc_multithread_mask)
1345 lwz r11,lo16(__objc_multithread_mask)(r11)
1346 cmplwi r11,0 ; objc_multithread_mask zero?
1347 beq LMsgSendFewMT ; branch to the locking case
1350 ; single threaded and receiver is non-nil: search the cache
1351 CacheLookup WORD_RETURN, MSG_SEND, LMsgSendFewCacheMiss, FEW_ARGS
1352 li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
1355 ; cache miss: go search the method lists
1356 LMsgSendFewCacheMiss:
1357 MethodTableLookup WORD_RETURN, MSG_SEND, FEW_ARGS
1358 li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
1361 #if !defined(OBJC_COLLECTING_CACHE)
1362 ; multithreaded: hold _messageLock while accessing cache
1364 PLOCK r11, _messageLock
1365 CacheLookup WORD_RETURN, MSG_SEND, LMsgSendFewMTCacheMiss, FEW_ARGS
1366 PUNLOCK r11, _messageLock
1367 li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
1370 ; cache miss: go search the method lists
1371 LMsgSendFewMTCacheMiss:
1372 MethodTableLookup WORD_RETURN, MSG_SEND, FEW_ARGS
1373 PUNLOCK r11, _messageLock
1374 li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
1378 ; message sent to nil object call: optional handler and return nil
1380 LOAD_STATIC_WORD r11, __objc_msgNil, EXTERNAL_SYMBOL
1381 cmplwi r11,0 ; handler nil?
1382 beqlr ; if no handler, return nil
1384 mflr r0 ; save return pc
1386 subi r1,r1,64 ; allocate linkage area
1388 bctrl ; call handler
1389 addi r1,r1,64 ; deallocate linkage area
1390 lwz r0,8(r1) ; restore return pc
1393 li r3,0 ; re-zero return value, in case handler changed it
1394 blr ; return to caller
1397 END_ENTRY _objc_msgSendFew
1400 /********************************************************************
1401 * struct_type objc_msgSendFew_stret(id self,
1405 * objc_msgSend_stret is the struct-return form of msgSend.
1406 * The ABI calls for r3 to be used as the address of the structure
1407 * being returned, with the parameters in the succeeding registers.
1409 * On entry: r3 is the address where the structure is returned,
1410 * r4 is the message receiver,
1411 * r5 is the selector
1412 ********************************************************************/
1414 ENTRY _objc_msgSendFew_stret
1415 ; do profiling when enabled
1418 ; check whether receiver is nil
1419 cmplwi r4,0 ; receiver nil?
1420 beq LMsgSendFewStretNilSelf ; if so, call handler or just return
1422 #if !defined(OBJC_COLLECTING_CACHE)
1423 ; check whether context is multithreaded
1424 lis r11,ha16(__objc_multithread_mask)
1425 lwz r11,lo16(__objc_multithread_mask)(r11)
1426 cmplwi r11,0 ; objc_multithread_mask zero?
1427 beq LMsgSendFewStretMT ; branch to the locking case
1430 ; single threaded and receiver is non-nil: search the cache
1431 CacheLookup STRUCT_RETURN, MSG_SEND, LMsgSendFewStretCacheMiss, FEW_ARGS
1432 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
1435 ; cache miss: go search the method lists
1436 LMsgSendFewStretCacheMiss:
1437 MethodTableLookup STRUCT_RETURN, MSG_SEND, FEW_ARGS
1438 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
1441 #if !defined(OBJC_COLLECTING_CACHE)
1442 ; multithreaded: hold _messageLock while accessing cache
1444 PLOCK r11, _messageLock
1445 CacheLookup STRUCT_RETURN, MSG_SEND, LMsgSendFewStretMTCacheMiss, FEW_ARGS
1446 PUNLOCK r11, _messageLock
1447 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
1450 ; cache miss: go search the method lists
1451 LMsgSendFewStretMTCacheMiss:
1452 MethodTableLookup STRUCT_RETURN, MSG_SEND, FEW_ARGS
1453 PUNLOCK r11, _messageLock
1454 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
1458 ; message sent to nil object call optional handler and return nil
1459 LMsgSendFewStretNilSelf:
1460 LOAD_STATIC_WORD r11, __objc_msgNil, EXTERNAL_SYMBOL
1461 cmplwi r11,0 ; handler nil?
1462 beqlr ; if no handler, return
1464 mflr r0 ; save return pc
1466 subi r1,r1,64 ; allocate linkage area
1467 mr r3,r4 ; move self to r3
1468 mr r4,r5 ; move SEL to r4
1470 bctrl ; call handler
1471 addi r1,r1,64 ; deallocate linkage area
1472 lwz r0,8(r1) ; restore return pc
1475 blr ; return to caller
1477 LMsgSendFewStretExit:
1478 END_ENTRY _objc_msgSendFew_stret
1481 /********************************************************************
1482 * id objc_msgSendSuperFew(struct objc_super *super,
1486 * struct objc_super {
1490 ********************************************************************/
1492 ENTRY _objc_msgSendSuperFew
1493 ; do profiling when enabled
1496 #if !defined(OBJC_COLLECTING_CACHE)
1497 ; check whether context is multithreaded
1498 lis r11,ha16(__objc_multithread_mask)
1499 lwz r11,lo16(__objc_multithread_mask)(r11)
1500 cmplwi r11,0 ; objc_multithread_mask zero?
1501 beq LMsgSendSuperFewMT ; branch to the locking case
1504 ; single threaded: search the cache
1505 CacheLookup WORD_RETURN, MSG_SENDSUPER, LMsgSendSuperFewCacheMiss, FEW_ARGS
1506 lwz r3,receiver(r3) ; receiver is the first arg
1507 li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
1510 ; cache miss: go search the method lists
1511 LMsgSendSuperFewCacheMiss:
1512 MethodTableLookup WORD_RETURN, MSG_SENDSUPER, FEW_ARGS
1513 lwz r3,receiver(r3) ; receiver is the first arg
1514 li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
1517 #if !defined(OBJC_COLLECTING_CACHE)
1518 ; multithreaded: hold _messageLock while accessing cache
1520 PLOCK r11, _messageLock
1521 CacheLookup WORD_RETURN, MSG_SENDSUPER, LMsgSendSuperFewMTCacheMiss, FEW_ARGS
1522 PUNLOCK r11, _messageLock
1523 lwz r3,receiver(r3) ; receiver is the first arg
1524 li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
1527 ; cache miss: go search the method lists
1528 LMsgSendSuperFewMTCacheMiss:
1529 MethodTableLookup WORD_RETURN, MSG_SENDSUPER, FEW_ARGS
1530 PUNLOCK r11, _messageLock
1531 lwz r3,receiver(r3) ; receiver is the first arg
1532 li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
1536 LMsgSendSuperFewExit:
1537 END_ENTRY _objc_msgSendSuperFew
1540 /********************************************************************
1541 * struct_type objc_msgSendSuperFew_stret(objc_super *super,
1545 * struct objc_super {
1551 * objc_msgSendSuper_stret is the struct-return form of msgSendSuper.
1552 * The ABI calls for r3 to be used as the address of the structure
1553 * being returned, with the parameters in the succeeding registers.
1555 * On entry: r3 is the address to which to copy the returned structure,
1556 * r4 is the address of the objc_super structure,
1557 * r5 is the selector
1558 ********************************************************************/
1560 ENTRY _objc_msgSendSuperFew_stret
1561 ; do profiling when enabled
1564 #if !defined(OBJC_COLLECTING_CACHE)
1565 ; check whether context is multithreaded
1566 lis r11,ha16(__objc_multithread_mask)
1567 lwz r11,lo16(__objc_multithread_mask)(r11)
1568 cmplwi r11,0 ; objc_multithread_mask zero?
1569 beq LMsgSendSuperFewStretMT ; branch to the locking case
1572 ; single threaded: search the cache
1573 CacheLookup STRUCT_RETURN, MSG_SENDSUPER, LMsgSendSuperFewStretCacheMiss, FEW_ARGS
1574 lwz r4,receiver(r4) ; receiver is the first arg
1575 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
1578 ; cache miss: go search the method lists
1579 LMsgSendSuperFewStretCacheMiss:
1580 MethodTableLookup STRUCT_RETURN, MSG_SENDSUPER, FEW_ARGS
1581 lwz r4,receiver(r4) ; receiver is the first arg
1582 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
1585 #if !defined(OBJC_COLLECTING_CACHE)
1586 ; multithreaded: hold _messageLock while accessing cache
1587 LMsgSendSuperFewStretMT:
1588 PLOCK r11, _messageLock
1589 CacheLookup STRUCT_RETURN, MSG_SENDSUPER, LMsgSendSuperFewStretMTCacheMiss, FEW_ARGS
1590 PUNLOCK r11, _messageLock
1591 lwz r4,receiver(r4) ; receiver is the first arg
1592 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
1595 ; cache miss: go search the method lists
1596 LMsgSendSuperFewStretMTCacheMiss:
1597 MethodTableLookup STRUCT_RETURN, MSG_SENDSUPER, FEW_ARGS
1598 PUNLOCK r11, _messageLock
1599 lwz r4,receiver(r4) ; receiver is the first arg
1600 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
1604 LMsgSendSuperFewStretExit:
1605 END_ENTRY _objc_msgSendSuperFew_stret