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 ********************************************************************/
66 /********************************************************************
67 * Data used by the ObjC runtime.
69 ********************************************************************/
72 ; Substitute receiver for messages sent to nil (usually also nil)
73 ; id _objc_nilReceiver
75 .globl __objc_nilReceiver
79 ; _objc_entryPoints and _objc_exitPoints are used by method dispatch
80 ; caching code to figure out whether any threads are actively
81 ; in the cache for dispatching. The labels surround the asm code
82 ; that do cache lookups. The tables are zero-terminated.
83 .globl _objc_entryPoints
86 .long __cache_getMethod
88 .long _objc_msgSend_stret
89 .long _objc_msgSendSuper
90 .long _objc_msgSendSuper_stret
91 .long _objc_msgSend_rtp
94 .globl _objc_exitPoints
99 .long LMsgSendStretExit
100 .long LMsgSendSuperExit
101 .long LMsgSendSuperStretExit
102 .long _objc_msgSend_rtp_exit
106 * Handcrafted dyld stubs for each external call.
107 * They should be converted into a local branch after linking. aB.
110 /* asm_help.h version is not what we want */
113 #if defined(__DYNAMIC__)
115 #define CALL_EXTERN(name) bl L ## name ## $stub
117 #define LAZY_PIC_FUNCTION_STUB(name) \
120 L ## name ## $stub: @\
121 .indirect_symbol name @\
123 bcl 20,31,L0$ ## name @\
126 addis r11,r11,ha16(L ## name ## $lazy_ptr-L0$ ## name) @\
128 lwz r12,lo16(L ## name ## $lazy_ptr-L0$ ## name)(r11) @\
130 addi r11,r11,lo16(L ## name ## $lazy_ptr-L0$ ## name) @\
133 .lazy_symbol_pointer @\
134 L ## name ## $lazy_ptr: @\
135 .indirect_symbol name @\
136 .long dyld_stub_binding_helper
138 #else /* __DYNAMIC__ */
140 #define CALL_EXTERN(name) bl name
142 #define LAZY_PIC_FUNCTION_STUB(name)
144 #endif /* __DYNAMIC__ */
146 ; _class_lookupMethodAndLoadCache
147 LAZY_PIC_FUNCTION_STUB(__class_lookupMethodAndLoadCache)
150 LAZY_PIC_FUNCTION_STUB(___objc_error) /* No stub needed */
154 LAZY_PIC_FUNCTION_STUB(mcount)
158 /********************************************************************
160 * Structure definitions.
162 ********************************************************************/
164 ; objc_super parameter to sendSuper
168 ; Selected field offsets in class structure
173 #define METHOD_NAME 0
179 #define BUCKETS 8 // variable length array
181 #if defined(OBJC_INSTRUMENTED)
182 ; Cache instrumentation data, follows buckets
184 #define hitProbes hitCount + 4
185 #define maxHitProbes hitProbes + 4
186 #define missCount maxHitProbes + 4
187 #define missProbes missCount + 4
188 #define maxMissProbes missProbes + 4
189 #define flushCount maxMissProbes + 4
190 #define flushedEntries flushCount + 4
193 /********************************************************************
197 ********************************************************************/
199 // In case the implementation is _objc_msgForward, indicate to it
200 // whether the method was invoked as a word-return or struct-return.
201 // The li instruction costs nothing because it fits into spare
202 // processor cycles. We choose to make the MsgSend indicator non-zero
203 // as r11 is already guaranteed non-zero for a cache hit (no li needed).
205 #define kFwdMsgSend 1
206 #define kFwdMsgSendStret 0
209 /********************************************************************
211 * Useful macros. Macros are used instead of subroutines, for speed.
213 ********************************************************************/
215 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
217 ; LOAD_STATIC_WORD targetReg, symbolName, LOCAL_SYMBOL | EXTERNAL_SYMBOL
219 ; Load the value of the named static data word.
221 ; Takes: targetReg - the register, other than r0, to load
222 ; symbolName - the name of the symbol
223 ; LOCAL_SYMBOL - symbol name used as-is
224 ; EXTERNAL_SYMBOL - symbol name gets nonlazy treatment
226 ; Eats: r0 and targetReg
227 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
229 ; Values to specify whether the symbols is plain or nonlazy
230 #define LOCAL_SYMBOL 0
231 #define EXTERNAL_SYMBOL 1
233 .macro LOAD_STATIC_WORD
235 #if defined(__DYNAMIC__)
237 bcl 20,31,1f ; 31 is cr7[so]
240 .if $2 == EXTERNAL_SYMBOL
241 addis $0,$0,ha16(L$1-1b)
242 lwz $0,lo16(L$1-1b)($0)
244 .elseif $2 == LOCAL_SYMBOL
245 addis $0,$0,ha16($1-1b)
246 lwz $0,lo16($1-1b)($0)
248 !!! Unknown symbol type !!!
257 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
259 ; LEA_STATIC_DATA targetReg, symbolName, LOCAL_SYMBOL | EXTERNAL_SYMBOL
261 ; Load the address of the named static data.
263 ; Takes: targetReg - the register, other than r0, to load
264 ; symbolName - the name of the symbol
265 ; LOCAL_SYMBOL - symbol is local to this module
266 ; EXTERNAL_SYMBOL - symbol is imported from another module
268 ; Eats: r0 and targetReg
269 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
271 .macro LEA_STATIC_DATA
272 #if defined(__DYNAMIC__)
274 bcl 20,31,1f ; 31 is cr7[so]
277 .if $2 == EXTERNAL_SYMBOL
278 addis $0,$0,ha16(L$1-1b)
279 lwz $0,lo16(L$1-1b)($0)
280 .elseif $2 == LOCAL_SYMBOL
281 addis $0,$0,ha16($1-1b)
282 addi $0,$0,lo16($1-1b)
284 !!! Unknown symbol type !!!
293 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
297 ; Assembly directives to begin an exported function.
298 ; We align on cache boundaries for these few functions.
300 ; Takes: functionName - name of the exported function
301 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
310 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
312 ; END_ENTRY functionName
314 ; Assembly directives to end an exported function. Just a placeholder,
315 ; a close-parenthesis for ENTRY, until it is needed for something.
317 ; Takes: functionName - name of the exported function
318 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
323 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
325 ; PLOCK scratchReg, lockName
327 ; Acquire named spinlock.
329 ; Takes: scratchReg - a register, other than r0, that can be mangled
330 ; lockName - the name of a static, aligned, 32-bit lock word
332 ; Eats: r0 and scratchReg
333 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
336 LEA_STATIC_DATA $0, $1, EXTERNAL_SYMBOL
337 b .+16 ; jump into loop at the reserving check
338 lwz r0,0($0) ; check with fast, less intrusive lwz versus lwarx
339 cmplwi r0,0 ; lock held?
340 bne .-8 ; if so, spin until it appears unlocked
341 lwarx r0,0,$0 ; get lock value, acquire memory reservation
342 cmplwi r0,0 ; lock held?
343 bne .-20 ; if locked, go spin waiting for unlock
344 li r0,1 ; get value that means locked
345 stwcx. r0,0,$0 ; store it iff reservation still holds
346 bne- .-20 ; if reservation was lost, go re-reserve
347 isync ; discard effects of prefetched instructions
350 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
352 ; PUNLOCK scratchReg, lockName
354 ; Release named spinlock.
356 ; Takes: scratchReg - a register, other than r0, that can be mangled
357 ; lockName - the name of a static, aligned, 32-bit lock word
359 ; Eats: r0 and scratchReg
360 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
363 sync ; force out changes before unlocking
364 LEA_STATIC_DATA $0, $1, EXTERNAL_SYMBOL
365 li r0,0 ; get value meaning "unlocked"
366 stw r0,0($0) ; unlock the lock
370 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
372 ; CacheLookup selectorRegister, cacheMissLabel
374 ; Locate the implementation for a selector in a class method cache.
377 ; $0 = register containing selector (r4 or r5 ONLY);
378 ; cacheMissLabel = label to branch to iff method is not cached
379 ; r12 = class whose cache is to be searched
381 ; On exit: (found) method triplet in r2, imp in r12, r11 is non-zero
382 ; (not found) jumps to cacheMissLabel
384 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
388 #if defined(OBJC_INSTRUMENTED)
389 ; when instrumented, we use r6 and r7
390 stw r6,36(r1) ; save r6 for use as cache pointer
391 stw r7,40(r1) ; save r7 for use as probe count
392 li r7,0 ; no probes so far!
395 lwz r2,CACHE(r12) ; cache = class->cache
396 stw r9,48(r1) ; save r9
398 #if defined(OBJC_INSTRUMENTED)
399 mr r6,r2 ; save cache pointer
402 lwz r11,MASK(r2) ; mask = cache->mask
403 addi r0,r2,BUCKETS ; buckets = cache->buckets
404 slwi r11,r11,2 ; r11 = mask << 2
405 and r9,$0,r11 ; bytes = sel & (mask<<2)
407 #if defined(OBJC_INSTRUMENTED)
411 ; r6 = cache, r7 = probeCount
412 lwz r9,MASK(r6) ; entryCount = mask + 1
414 slwi r9,r9,2 ; tableSize = entryCount * sizeof(entry)
415 addi r9,r9,BUCKETS ; offset = buckets + tableSize
416 add r11,r6,r9 ; cacheData = &cache->buckets[mask+1]
417 lwz r9,missCount(r11) ; cacheData->missCount += 1
419 stw r9,missCount(r11) ;
420 lwz r9,missProbes(r11) ; cacheData->missProbes += probeCount
422 stw r9,missProbes(r11) ;
423 lwz r9,maxMissProbes(r11) ; if (probeCount > cacheData->maxMissProbes)
424 cmplw r7,r9 ; maxMissProbes = probeCount
426 stw r7,maxMissProbes(r11) ;
428 lwz r6,36(r1) ; restore r6
429 lwz r7,40(r1) ; restore r7
431 b $1 ; goto cacheMissLabel
436 #if defined(OBJC_INSTRUMENTED)
437 addi r7,r7,1 ; probeCount += 1
440 lwzx r2,r9,r0 ; method = buckets[bytes/4]
441 addi r9,r9,4 ; bytes += 4
442 cmplwi r2,0 ; if (method == NULL)
443 #if defined(OBJC_INSTRUMENTED)
446 beq- $1 ; goto cacheMissLabel
449 lwz r12,METHOD_NAME(r2) ; name = method->method_name
450 and r9,r9,r11 ; bytes &= (mask<<2)
451 cmplw r12,$0 ; if (name != selector)
452 bne- LLoop_$0_$1 ; goto loop
454 ; cache hit, r2 == method triplet address
455 ; Return triplet in r2 and imp in r12
456 lwz r12,METHOD_IMP(r2) ; imp = method->method_imp
458 #if defined(OBJC_INSTRUMENTED)
459 ; r6 = cache, r7 = probeCount
460 lwz r9,MASK(r6) ; entryCount = mask + 1
462 slwi r9,r9,2 ; tableSize = entryCount * sizeof(entry)
463 addi r9,r9,BUCKETS ; offset = buckets + tableSize
464 add r11,r6,r9 ; cacheData = &cache->buckets[mask+1]
465 lwz r9,hitCount(r11) ; cache->hitCount += 1
467 stw r9,hitCount(r11) ;
468 lwz r9,hitProbes(r11) ; cache->hitProbes += probeCount
470 stw r9,hitProbes(r11) ;
471 lwz r9,maxHitProbes(r11) ; if (probeCount > cache->maxMissProbes)
472 cmplw r7,r9 ;maxMissProbes = probeCount
474 stw r7,maxHitProbes(r11) ;
476 lwz r6,36(r1) ; restore r6
477 lwz r7,40(r1) ; restore r7
480 lwz r9,48(r1) ; restore r9
484 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
486 ; CacheLookup cache locking - 2001-11-12
487 ; The collecting cache mechanism precludes the need for a cache lock
488 ; in objc_msgSend. The cost of the collecting cache is small: a few
489 ; K of memory for uncollected caches, and less than 1 ms per collection.
490 ; A large app will only run collection a few times.
491 ; Using the code below to lock the cache almost doubles messaging time,
492 ; costing several seconds of CPU across several minutes of operation.
493 ; The code below probably could be improved, but almost all of the
494 ; locking slowdown is in the sync and isync.
496 ; 40 million message test times (G4 1x667):
497 ; no lock 4.390u 0.030s 0:04.59 96.2% 0+0k 0+1io 0pf+0w
498 ; with lock 9.120u 0.010s 0:09.83 92.8% 0+0k 0+0io 0pf+0w
500 ;; LockCache mask_dest, cache
502 ; ; LOCKED mask is NEGATIVE
503 ; lwarx $0, mask, $1 ; mask = reserve(cache->mask)
505 ; blt .-8 ; try again if mask < 0
507 ; stwcx. r0, mask, $1 ; cache->mask = -mask ($0 keeps +mask)
508 ; bne .-20 ; try again if lost reserve
509 ; isync ; flush prefetched instructions after locking
512 ;; UnlockCache (mask<<2), cache
514 ; sync ; finish previous instructions before unlocking
515 ; srwi r0, $0, 2 ; r0 = (mask<<2) >> 2
516 ; stw r0, mask($1) ; cache->mask = +mask
519 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
522 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
525 ; MethodTableLookup WORD_RETURN | STRUCT_RETURN, MSG_SEND | MSG_SENDSUPER
527 ; Takes: WORD_RETURN (r3 is first parameter)
528 ; STRUCT_RETURN (r3 is structure return address, r4 is first parameter)
529 ; MSG_SEND (first parameter is receiver)
530 ; MSG_SENDSUPER (first parameter is address of objc_super structure)
532 ; Eats: r0, r2, r11, r12
533 ; On exit: restores r9 saved by CacheLookup
535 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
537 ; Values to specify to method lookup macros whether the return type of
538 ; the method is an integer or structure.
539 #define WORD_RETURN 0
540 #define STRUCT_RETURN 1
542 ; Values to specify to method lookup macros whether the return type of
543 ; the method is an integer or structure.
545 #define MSG_SENDSUPER 1
547 .macro MethodTableLookup
551 stw r3, 24(r1) ; save arguments
557 ; r9 was saved by CacheLookup
561 ; Save the FP parameter registers.
562 ; Note: If we (the compiler) could determine that no FP arguments were in use,
563 ; we could use a different variant of this macro and avoid the need to spill the FP
564 ; registers (provided the runtime uses no FP).
565 ; We still do not spill vector argument registers, for which we really should have an alternate
581 stwu r1,-56-(13*8)(r1) ; grow the stack. Must be 16-byte-aligned.
583 stwu r1,-64(r1) ; grow the stack. Must be 16-byte-aligned.
586 ; Pass parameters to __class_lookupMethodAndLoadCache. First parameter is
587 ; the class pointer. Second parameter is the selector. Where they come
588 ; from depends on who called us. In the int return case, the selector is
590 .if $0 == WORD_RETURN ; WORD_RETURN
591 .if $1 == MSG_SEND ; MSG_SEND
592 lwz r3,ISA(r3) ; class = receiver->isa
593 .else ; MSG_SENDSUPER
594 lwz r3,CLASS(r3) ; class = super->class
597 .else ; STRUCT_RETURN
598 .if $1 == MSG_SEND ; MSG_SEND
599 lwz r3,ISA(r4) ; class = receiver->isa
600 .else ; MSG_SENDSUPER
601 lwz r3,CLASS(r4) ; class = super->class
603 mr r4,r5 ; selector = selector
606 ; We code the call inline rather than using the CALL_EXTERN macro because
607 ; that leads to a lot of extra unnecessary and inefficient instructions.
608 CALL_EXTERN(__class_lookupMethodAndLoadCache)
610 mr r12,r3 ; copy implementation to r12
611 mtctr r3 ; copy imp to ctr
612 lwz r1,0(r1) ; restore the stack pointer
614 mtlr r0 ; restore return pc
618 ; Restore FP parameter registers
619 ; Note: If we (the compiler) could determine that no FP arguments were in use,
620 ; we could use a different variant of this macro and avoid the need to restore the FP
621 ; registers (provided the runtime uses no FP).
622 ; We still do not restore vector argument registers, for which we really should have an alternate
638 lwz r3, 24(r1) ; restore parameter registers
644 lwz r9, 48(r1) ; r9 was saved by CacheLookup
651 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
655 ; Macro to call mcount function in profiled builds.
657 ; NOTE: Makes sure to save/restore r11 and r12, even though they
658 ; are not defined to be volatile, because they are used during
661 ; Takes: lr Callers return PC
664 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
668 mflr r0 ; save return pc
671 stwu r1,-208(r1) ; push aligned areas, set stack link
673 stw r3, 56(r1) ; save all volatile registers
681 stw r11,88(r1) ; save r11 and r12, too
698 mr r3, r0 ; pass our callers address
702 lwz r3, 56(r1) ; restore all volatile registers
710 lwz r11,88(r1) ; restore r11 and r12, too
727 lwz r1,0(r1) ; restore the stack pointer
729 mtlr r0 ; restore return pc
734 /********************************************************************
735 * Method _cache_getMethod(Class cls, SEL sel, IMP objc_msgForward_imp)
737 * On entry: r3 = class whose cache is to be searched
738 * r4 = selector to search for
739 * r5 = _objc_msgForward IMP
741 * If found, returns method triplet pointer.
742 * If not found, returns NULL.
744 * NOTE: _cache_getMethod never returns any cache entry whose implementation
745 * is _objc_msgForward. It returns NULL instead. This prevents thread-
746 * safety and memory management bugs in _class_lookupMethodAndLoadCache.
747 * See _class_lookupMethodAndLoadCache for details.
749 * _objc_msgForward is passed as a parameter because it's more efficient
750 * to do the (PIC) lookup once in the caller than repeatedly here.
751 ********************************************************************/
753 ENTRY __cache_getMethod
754 ; do profiling if enabled
758 mr r12,r3 ; move class to r12 for CacheLookup
759 CacheLookup r4, LGetMethodMiss
761 ; cache hit, method triplet in r2 and imp in r12
762 cmplw r12, r5 ; check for _objc_msgForward
763 mr r3, r2 ; optimistically get the return value
764 bnelr ; Not _objc_msgForward, return the triplet address
767 li r3, 0 ; cache miss or _objc_msgForward, return nil
771 END_ENTRY __cache_getMethod
774 /********************************************************************
775 * IMP _cache_getImp(Class cls, SEL sel)
777 * On entry: r3 = class whose cache is to be searched
778 * r4 = selector to search for
780 * If found, returns method implementation.
781 * If not found, returns NULL.
782 ********************************************************************/
785 ; do profiling if enabled
789 mr r12,r3 ; move class to r12 for CacheLookup
790 CacheLookup r4, LGetImpMiss
792 ; cache hit, method triplet in r2 and imp in r12
793 mr r3, r12 ; return method imp address
797 ; cache miss, return nil
798 li r3, 0 ; return nil
802 END_ENTRY __cache_getImp
805 /********************************************************************
806 * id objc_msgSend(id self,
810 * On entry: r3 is the message receiver,
812 ********************************************************************/
814 ; WARNING - This code may be copied as is to the Objective-C runtime pages.
815 ; The code is copied by rtp_set_up_objc_msgSend() from the
816 ; beginning to the blr marker just prior to the cache miss code.
817 ; Do not add callouts, global variable accesses, or rearrange
818 ; the code without updating rtp_set_up_objc_msgSend.
820 ; Absolute symbols bounding the runtime page version of objc_msgSend.
821 _objc_msgSend_rtp = 0xfffeff00
822 _objc_msgSend_rtp_exit = 0xfffeff00+0x100
826 ; check whether receiver is nil or selector is to be ignored
827 cmplwi r3,0 ; receiver nil?
828 xoris r11,r4,((kIgnore>>16) & 0xffff) ; clear hi if equal to ignored
829 cmplwi cr1,r11,(kIgnore & 0xffff) ; selector is to be ignored?
830 beq- LMsgSendNilSelf ; if nil receiver, call handler or return nil
831 lwz r12,ISA(r3) ; class = receiver->isa
832 beqlr- cr1 ; if ignored selector, return self immediately
834 ; guaranteed non-nil entry point (disabled for now)
835 ; .globl _objc_msgSendNonNil
836 ; _objc_msgSendNonNil:
838 ; do profiling when enabled
841 ; receiver is non-nil: search the cache
843 ; class is already in r12
844 CacheLookup r4, LMsgSendCacheMiss
845 ; CacheLookup placed imp in r12
847 ; r11 guaranteed non-zero on exit from CacheLookup with a hit
848 // li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
851 ; WARNING - The first six instructions of LMsgSendNilSelf are
852 ; rewritten when objc_msgSend is copied to the runtime pages.
853 ; These instructions must be maintained AS IS unless the code in
854 ; rtp_set_up_objc_msgSend is also updated.
855 ; * `mflr r0` must not be changed (not even to use a different register)
856 ; * the load of _objc_nilReceiver value must remain six insns long
857 ; * the value of _objc_nilReceiver must continue to be loaded into r11
859 ; message sent to nil: redirect to nil receiver, if any
861 ; DO NOT CHANGE THE NEXT SIX INSTRUCTIONS - see note above
862 mflr r0 ; save return address
863 bcl 20,31,1f ; 31 is cr7[so]
865 addis r11,r11,ha16(__objc_nilReceiver-1b)
866 lwz r11,lo16(__objc_nilReceiver-1b)(r11)
867 mtlr r0 ; restore return address
868 ; DO NOT CHANGE THE PREVIOUS SIX INSTRUCTIONS - see note above
870 cmplwi r11,0 ; return nil if no new receiver
873 mr r3,r11 ; send to new receiver
874 lwz r12,ISA(r11) ; class = receiver->isa
877 ; WARNING - This blr marks the end of the copy to the ObjC runtime pages and
878 ; also marks the beginning of the cache miss code. Do not move
879 ; around without checking the ObjC runtime pages initialization code.
882 ; cache miss: go search the method lists
884 MethodTableLookup WORD_RETURN, MSG_SEND
885 li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
889 END_ENTRY _objc_msgSend
892 /********************************************************************
893 * struct_type objc_msgSend_stret(id self,
897 * objc_msgSend_stret is the struct-return form of msgSend.
898 * The ABI calls for r3 to be used as the address of the structure
899 * being returned, with the parameters in the succeeding registers.
901 * On entry: r3 is the address where the structure is returned,
902 * r4 is the message receiver,
904 ********************************************************************/
906 ENTRY _objc_msgSend_stret
907 ; check whether receiver is nil
908 cmplwi r4,0 ; receiver nil?
909 beq LMsgSendStretNilSelf ; if so, call handler or just return
911 ; guaranteed non-nil entry point (disabled for now)
912 ; .globl _objc_msgSendNonNil_stret
913 ; _objc_msgSendNonNil_stret:
915 ; do profiling when enabled
918 ; receiver is non-nil: search the cache
919 LMsgSendStretReceiverOk:
920 lwz r12, ISA(r4) ; class = receiver->isa
921 CacheLookup r5, LMsgSendStretCacheMiss
922 ; CacheLookup placed imp in r12
924 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
927 ; cache miss: go search the method lists
928 LMsgSendStretCacheMiss:
929 MethodTableLookup STRUCT_RETURN, MSG_SEND
930 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
933 ; message sent to nil: redirect to nil receiver, if any
934 LMsgSendStretNilSelf:
935 mflr r0 ; load new receiver
936 bcl 20,31,1f ; 31 is cr7[so]
938 addis r11,r11,ha16(__objc_nilReceiver-1b)
939 lwz r11,lo16(__objc_nilReceiver-1b)(r11)
942 cmplwi r11,0 ; return nil if no new receiver
945 mr r4,r11 ; send to new receiver
946 b LMsgSendStretReceiverOk
949 END_ENTRY _objc_msgSend_stret
952 /********************************************************************
953 * id objc_msgSendSuper(struct objc_super *super,
957 * struct objc_super {
961 ********************************************************************/
963 ENTRY _objc_msgSendSuper
964 ; do profiling when enabled
967 ; check whether selector is to be ignored
968 xoris r11,r4,((kIgnore>>16) & 0xffff) ; clear hi if to be ignored
969 cmplwi r11,(kIgnore & 0xffff) ; selector is to be ignored?
970 lwz r12,CLASS(r3) ; class = super->class
971 beq- LMsgSendSuperIgnored ; if ignored, return self
974 ; class is already in r12
975 CacheLookup r4, LMsgSendSuperCacheMiss
976 ; CacheLookup placed imp in r12
978 lwz r3,RECEIVER(r3) ; receiver is the first arg
979 ; r11 guaranteed non-zero after cache hit
980 ; li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
983 ; cache miss: go search the method lists
984 LMsgSendSuperCacheMiss:
985 MethodTableLookup WORD_RETURN, MSG_SENDSUPER
986 lwz r3,RECEIVER(r3) ; receiver is the first arg
987 li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
990 ; ignored selector: return self
991 LMsgSendSuperIgnored:
996 END_ENTRY _objc_msgSendSuper
999 /********************************************************************
1000 * struct_type objc_msgSendSuper_stret(objc_super *super,
1004 * struct objc_super {
1010 * objc_msgSendSuper_stret is the struct-return form of msgSendSuper.
1011 * The ABI calls for r3 to be used as the address of the structure
1012 * being returned, with the parameters in the succeeding registers.
1014 * On entry: r3 is the address to which to copy the returned structure,
1015 * r4 is the address of the objc_super structure,
1016 * r5 is the selector
1017 ********************************************************************/
1019 ENTRY _objc_msgSendSuper_stret
1020 ; do profiling when enabled
1024 lwz r12,CLASS(r4) ; class = super->class
1025 CacheLookup r5, LMsgSendSuperStretCacheMiss
1026 ; CacheLookup placed imp in r12
1028 lwz r4,RECEIVER(r4) ; receiver is the first arg
1029 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
1032 ; cache miss: go search the method lists
1033 LMsgSendSuperStretCacheMiss:
1034 MethodTableLookup STRUCT_RETURN, MSG_SENDSUPER
1035 lwz r4,RECEIVER(r4) ; receiver is the first arg
1036 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
1039 LMsgSendSuperStretExit:
1040 END_ENTRY _objc_msgSendSuper_stret
1043 /********************************************************************
1045 * Out-of-band parameter r11 indicates whether it was objc_msgSend or
1046 * objc_msgSend_stret that triggered the message forwarding. The
1048 * Iff r11 == kFwdMsgSend, it is the word-return (objc_msgSend) case,
1049 * and the interface is:
1051 * id _objc_msgForward(id self,
1055 * Iff r11 == kFwdMsgSendStret, it is the structure-return
1056 * (objc_msgSend_stret) case, and the interface is:
1058 * struct_type _objc_msgForward(id self,
1062 * There are numerous reasons why it is better to have one
1063 * _objc_msgForward, rather than adding _objc_msgForward_stret.
1064 * The best one is that _objc_msgForward is the method that
1065 * gets cached when respondsToMethod returns false, and it
1066 * wouldnt know which one to use.
1068 * Sends the message to a method having the signature
1070 * - forward:(SEL)sel :(marg_list)args;
1072 * But the marg_list is prepended with the 13 double precision
1073 * floating point registers that could be used as parameters into
1074 * the method (fortunately, the same registers are used for either
1075 * single or double precision floats). These registers are layed
1076 * down by _objc_msgForward, and picked up by _objc_msgSendv. So
1077 * the "marg_list" is actually:
1079 * typedef struct objc_sendv_margs {
1080 * double floatingPointArgs[13];
1081 * int linkageArea[6];
1082 * int registerArgs[8];
1083 * int stackArgs[variable];
1086 ********************************************************************/
1088 ; Location LFwdStr contains the string "forward::"
1089 ; Location LFwdSel contains a pointer to LFwdStr, that can be changed
1090 ; to point to another forward:: string for selector uniquing
1091 ; purposes. ALWAYS dereference LFwdSel to get to "forward::" !!
1092 .objc_meth_var_names
1094 LFwdStr: .ascii "forward::\0"
1098 LFwdSel: .long LFwdStr
1102 LUnkSelStr: .ascii "Does not recognize selector %s\0"
1104 ENTRY __objc_msgForward
1105 ; do profiling when enabled
1108 #if !defined(KERNEL)
1109 LOAD_STATIC_WORD r12, LFwdSel, LOCAL_SYMBOL ; get uniqued selector for "forward::"
1110 cmplwi r11,kFwdMsgSendStret ; via objc_msgSend or objc_msgSend_stret?
1111 beq LMsgForwardStretSel ; branch for objc_msgSend_stret
1112 cmplw r12,r4 ; if (sel == @selector (forward::))
1113 b LMsgForwardSelCmpDone ; check the result in common code
1114 LMsgForwardStretSel:
1115 cmplw r12,r5 ; if (sel == @selector (forward::))
1116 LMsgForwardSelCmpDone:
1117 beq LMsgForwardError ; goto error
1120 stw r0, 8(r1) ; save lr
1122 stw r3, 24(r1) ; put register arguments on stack for forwarding
1123 stw r4, 28(r1) ; (stack based args already follow this area)
1131 stfd f1, -104(r1) ; prepend floating point registers to marg_list
1145 cmplwi r11,kFwdMsgSendStret ; via objc_msgSend or objc_msgSend_stret?
1146 beq LMsgForwardStretParams ; branch for objc_msgSend_stret
1147 ; first arg (r3) remains self
1148 mr r5,r4 ; third arg is previous selector
1149 b LMsgForwardParamsDone
1151 LMsgForwardStretParams:
1152 mr r3,r4 ; first arg is self
1153 ; third arg (r5) remains previous selector
1154 LMsgForwardParamsDone:
1155 mr r4,r12 ; second arg is "forward::"
1156 subi r6,r1,13*8 ; fourth arg is &objc_sendv_margs
1158 stwu r1,-56-(13*8)(r1) ; push aligned linkage and parameter areas, set stack link
1159 bl _objc_msgSend ; [self forward:sel :objc_sendv_margs]
1160 addi r1,r1,56+13*8 ; deallocate linkage and parameters areas
1162 lwz r0,8(r1) ; restore lr
1166 ; call error handler with unrecognized selector message
1168 cmplwi r11,kFwdMsgSendStret ; via objc_msgSend or objc_msgSend_stret?
1169 bne LMsgForwardErrorParamsOK; branch for objc_msgSend
1170 mr r3,r4 ; first arg is self
1171 LMsgForwardErrorParamsOK:
1172 LEA_STATIC_DATA r4, LUnkSelStr, LOCAL_SYMBOL
1173 mr r5,r12 ; third arg is "forward::"
1174 CALL_EXTERN(___objc_error) ; never returns
1175 #endif /* !defined(KERNEL) */
1176 trap ; ___objc_error should never return
1177 ; _objc_msgForward is not for the kernel - kernel code ends up here
1179 END_ENTRY __objc_msgForward
1182 /********************************************************************
1183 * id objc_msgSendv(id self,
1185 * unsigned arg_size,
1186 * marg_list arg_frame);
1188 * But the marg_list is prepended with the 13 double precision
1189 * floating point registers that could be used as parameters into
1190 * the method (fortunately, the same registers are used for either
1191 * single or double precision floats). These registers are layed
1192 * down by _objc_msgForward, and picked up by _objc_msgSendv. So
1193 * the "marg_list" is actually:
1195 * typedef struct objc_sendv_margs {
1196 * double floatingPointArgs[13];
1197 * int linkageArea[6];
1198 * int registerArgs[8];
1199 * int stackArgs[variable];
1202 * arg_size is the number of bytes of parameters in registerArgs and
1203 * stackArgs combined (i.e. it is method_getSizeOfArguments(method)).
1204 * Specifically, it is NOT the overall arg_frame size, because that
1205 * would include the floatingPointArgs and linkageArea, which are
1206 * PowerPC-specific. This is consistent with the other architectures.
1207 ********************************************************************/
1209 ENTRY _objc_msgSendv
1211 #if !defined(KERNEL)
1212 ; do profiling when enabled
1216 stw r0,8(r1) ; save lr
1218 cmplwi r5,32 ; check parameter size against minimum
1219 ble+ LMsgSendvMinFrame ; is less than minimum, go use minimum
1220 mr r12,r1 ; remember current stack pointer
1221 sub r11,r1,r5 ; push parameter area
1222 rlwinm r1,r11,0,0,27 ; align stack pointer to 16 byte boundary
1223 stwu r12,-32(r1) ; push aligned linkage area, set stack link
1224 b LMsgSendvHaveFrame
1227 stwu r1,-64(r1) ; push aligned linkage and parameter areas, set stack link
1230 ; restore floating point register parameters from marg_list
1245 ; load the register based arguments from the marg_list
1246 ; the first two parameters are already in r3 and r4, respectively
1247 subi r0,r5,(2*4)-3 ; make word count from byte count rounded up to multiple of 4...
1248 srwi. r0,r0,2 ; ... and subtracting for params already in r3 and r4
1249 beq LMsgSendvSendIt ; branch if there are no parameters to load
1250 mtctr r0 ; counter = number of remaining words
1251 lwz r5,32+(13*8)(r6) ; load 3rd parameter
1252 bdz LMsgSendvSendIt ; decrement counter, branch if result is zero
1253 addi r11,r6,36+(13*8) ; switch to r11, because we are setting r6
1254 lwz r6,0(r11) ; load 4th parameter
1255 bdz LMsgSendvSendIt ; decrement counter, branch if result is zero
1256 lwz r7,4(r11) ; load 5th parameter
1257 bdz LMsgSendvSendIt ; decrement counter, branch if result is zero
1258 lwz r8,8(r11) ; load 6th parameter
1259 bdz LMsgSendvSendIt ; decrement counter, branch if result is zero
1260 lwz r9,12(r11) ; load 7th parameter
1261 bdz LMsgSendvSendIt ; decrement counter, branch if result is zero
1262 lwzu r10,16(r11) ; load 8th parameter, and update r11
1263 bdz LMsgSendvSendIt ; decrement counter, branch if result is zero
1265 ; copy the stack based arguments from the marg_list
1266 addi r12,r1,24+32-4 ; target = address of stack based parameters
1268 lwzu r0,4(r11) ; loop to copy remaining marg_list words to stack
1270 bdnz LMsgSendvArgLoop ; decrement counter, branch if still non-zero
1273 bl _objc_msgSend ; objc_msgSend (self, selector, ...)
1275 lwz r1,0(r1) ; restore stack pointer
1276 lwz r0,8(r1) ; restore lr
1280 trap ; _objc_msgSendv is not for the kernel
1283 END_ENTRY _objc_msgSendv
1286 /********************************************************************
1287 * struct_type objc_msgSendv_stret(id self,
1289 * unsigned arg_size,
1290 * marg_list arg_frame);
1292 * objc_msgSendv_stret is the struct-return form of msgSendv.
1293 * The ABI calls for r3 to be used as the address of the structure
1294 * being returned, with the parameters in the succeeding registers.
1296 * An equally correct way to prototype this routine is:
1298 * void objc_msgSendv_stret(void *structStorage,
1301 * unsigned arg_size,
1302 * marg_list arg_frame);
1304 * which is useful in, for example, message forwarding where the
1305 * structure-return address needs to be passed in.
1307 * The ABI for the two cases are identical.
1309 * On entry: r3 is the address in which the returned struct is put,
1310 * r4 is the message receiver,
1311 * r5 is the selector,
1312 * r6 is the size of the marg_list, in bytes,
1313 * r7 is the address of the marg_list
1314 ********************************************************************/
1316 ENTRY _objc_msgSendv_stret
1318 #if !defined(KERNEL)
1319 ; do profiling when enabled
1323 stw r0,8(r1) ; (save return pc)
1325 cmplwi r6,32 ; check parameter size against minimum
1326 ble+ LMsgSendvStretMinFrame ; is less than minimum, go use minimum
1327 mr r12,r1 ; remember current stack pointer
1328 sub r11,r1,r6 ; push parameter area
1329 rlwinm r1,r11,0,0,27 ; align stack pointer to 16 byte boundary
1330 stwu r12,-32(r1) ; push aligned linkage area, set stack link
1331 b LMsgSendvStretHaveFrame
1333 LMsgSendvStretMinFrame:
1334 stwu r1,-64(r1) ; push aligned linkage and parameter areas, set stack link
1336 LMsgSendvStretHaveFrame:
1337 ; restore floating point register parameters from marg_list
1352 ; load the register based arguments from the marg_list
1353 ; the structure return address and the first two parameters
1354 ; are already in r3, r4, and r5, respectively.
1355 ; NOTE: The callers r3 probably, but not necessarily, matches
1356 ; the r3 in the marg_list. That is, the struct-return
1357 ; storage used by the caller could be an intermediate buffer
1358 ; that will end up being copied into the original
1359 ; struct-return buffer (pointed to by the marg_listed r3).
1360 subi r0,r6,(3*4)-3 ; make word count from byte count rounded up to multiple of 4...
1361 srwi. r0,r0,2 ; ... and subtracting for params already in r3 and r4 and r5
1362 beq LMsgSendvStretSendIt ; branch if there are no parameters to load
1363 mtctr r0 ; counter = number of remaining words
1364 lwz r6,36+(13*8)(r7) ; load 4th parameter
1365 bdz LMsgSendvStretSendIt ; decrement counter, branch if result is zero
1366 addi r11,r7,40+(13*8) ; switch to r11, because we are setting r7
1367 lwz r7,0(r11) ; load 5th parameter
1368 bdz LMsgSendvStretSendIt ; decrement counter, branch if result is zero
1369 lwz r8,4(r11) ; load 6th parameter
1370 bdz LMsgSendvStretSendIt ; decrement counter, branch if result is zero
1371 lwz r9,8(r11) ; load 7th parameter
1372 bdz LMsgSendvStretSendIt ; decrement counter, branch if result is zero
1373 lwzu r10,12(r11) ; load 8th parameter, and update r11
1374 bdz LMsgSendvStretSendIt ; decrement counter, branch if result is zero
1376 ; copy the stack based arguments from the marg_list
1377 addi r12,r1,24+32-4 ; target = address of stack based parameters
1378 LMsgSendvStretArgLoop:
1379 lwzu r0,4(r11) ; loop to copy remaining marg_list words to stack
1381 bdnz LMsgSendvStretArgLoop ; decrement counter, branch if still non-zero
1383 LMsgSendvStretSendIt:
1384 bl _objc_msgSend_stret ; struct_type objc_msgSend_stret (self, selector, ...)
1386 lwz r1,0(r1) ; restore stack pointer
1387 lwz r0,8(r1) ; restore return pc
1391 trap ; _objc_msgSendv_stret is not for the kernel
1392 #endif /* !KERNEL */
1394 END_ENTRY _objc_msgSendv_stret
1397 // Special section containing a function pointer that dyld will call
1398 // when it loads new images.
1399 LAZY_PIC_FUNCTION_STUB(__objc_notify_images)
1401 .section __DATA,__image_notify
1402 .long L__objc_notify_images$stub