]> git.saurik.com Git - apple/objc4.git/blob - runtime/Messengers.subproj/objc-msg-ppc.s
objc4-437.tar.gz
[apple/objc4.git] / runtime / Messengers.subproj / objc-msg-ppc.s
1 /*
2 * Copyright (c) 1999-2007 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #ifdef __ppc__
25
26 /********************************************************************
27 *
28 * objc-msg-ppc.s - PowerPC code to support objc messaging.
29 *
30 * Copyright 1988-1996 NeXT Software, Inc.
31 *
32 * December 2002 Andy Belk (abelk at apple.com)
33 * Use r2 in the messenger - no longer need r10.
34 * Removed "few args" variants (no longer worth it, especially since gcc3 still
35 * doesn't generate code for them).
36 * Add NonNil entry points to objc_msgSend and objc_msgSend_stret.
37 * Align objc_msgSend et al on cache lines.
38 * Replace CALL_EXTERN references (which caused excess mflr/mtlr usage) with
39 * dyld-stub-compatible versions: shorter and become local branches within a dylib.
40 *
41 * 8-Nov-2000 Laurent Ramontianu (ramontia@apple.com)
42 * Added "few args" params. to CacheLookup and MethodTableLookup
43 * Added the alternate entry points:
44 * objc_msgSendFew, objc_msgSendFew_stret,
45 * objc_msgSendSuperFew, objc_msgSendSuperFew_stret
46 *
47 * 18-Jun-97 David Harrison (harrison@apple.com)
48 * Restructured.
49 *
50 * 1-May-97 Umesh Vaishampayan (umeshv@NeXT.com)
51 * Incorporated locking code fixes from
52 * David Harrison (harrison@NeXT.com)
53 *
54 * 2-Apr-97 Umesh Vaishampayan (umeshv@NeXT.com)
55 * Incorporated changes for messenger with struct return
56 * Cleaned up the labels to use local labels
57 * Fixed bug in the msgSendSuper that did not do the locking.
58 *
59 * 31-Dec-96 Umesh Vaishampayan (umeshv@NeXT.com)
60 * Created from m98k.
61 ********************************************************************/
62
63 #undef OBJC_ASM
64 #define OBJC_ASM
65 #include "objc-rtp.h"
66
67 /********************************************************************
68 * Data used by the ObjC runtime.
69 *
70 ********************************************************************/
71
72 .data
73 ; Substitute receiver for messages sent to nil (usually also nil)
74 ; id _objc_nilReceiver
75 .align 4
76 .private_extern __objc_nilReceiver
77 __objc_nilReceiver:
78 .long 0
79
80 ; _objc_entryPoints and _objc_exitPoints are used by method dispatch
81 ; caching code to figure out whether any threads are actively
82 ; in the cache for dispatching. The labels surround the asm code
83 ; that do cache lookups. The tables are zero-terminated.
84 .private_extern _objc_entryPoints
85 _objc_entryPoints:
86 .long __cache_getImp
87 .long __cache_getMethod
88 .long _objc_msgSend
89 .long _objc_msgSend_stret
90 .long _objc_msgSendSuper
91 .long _objc_msgSendSuper_stret
92 .long _objc_msgSend_rtp
93 .long 0
94
95 .private_extern _objc_exitPoints
96 _objc_exitPoints:
97 .long LGetImpExit
98 .long LGetMethodExit
99 .long LMsgSendExit
100 .long LMsgSendStretExit
101 .long LMsgSendSuperExit
102 .long LMsgSendSuperStretExit
103 .long _objc_msgSend_rtp_exit
104 .long 0
105
106 /*
107 * Handcrafted dyld stubs for each external call.
108 * They should be converted into a local branch after linking. aB.
109 */
110
111 /* asm_help.h version is not what we want */
112 #undef CALL_EXTERN
113
114 #if defined(__DYNAMIC__)
115
116 #define CALL_EXTERN(name) bl L ## name ## $stub
117
118 #define LAZY_PIC_FUNCTION_STUB(name) \
119 .data @\
120 .picsymbol_stub @\
121 L ## name ## $stub: @\
122 .indirect_symbol name @\
123 mflr r0 @\
124 bcl 20,31,L0$ ## name @\
125 L0$ ## name: @\
126 mflr r11 @\
127 addis r11,r11,ha16(L ## name ## $lazy_ptr-L0$ ## name) @\
128 mtlr r0 @\
129 lwz r12,lo16(L ## name ## $lazy_ptr-L0$ ## name)(r11) @\
130 mtctr r12 @\
131 addi r11,r11,lo16(L ## name ## $lazy_ptr-L0$ ## name) @\
132 bctr @\
133 .data @\
134 .lazy_symbol_pointer @\
135 L ## name ## $lazy_ptr: @\
136 .indirect_symbol name @\
137 .long dyld_stub_binding_helper
138
139 #else /* __DYNAMIC__ */
140
141 #define CALL_EXTERN(name) bl name
142
143 #define LAZY_PIC_FUNCTION_STUB(name)
144
145 #endif /* __DYNAMIC__ */
146
147 ; _class_lookupMethodAndLoadCache
148 LAZY_PIC_FUNCTION_STUB(__class_lookupMethodAndLoadCache)
149
150 ; __objc_error
151 LAZY_PIC_FUNCTION_STUB(___objc_error) /* No stub needed */
152
153 #if defined(PROFILE)
154 ; mcount
155 LAZY_PIC_FUNCTION_STUB(mcount)
156 #endif /* PROFILE */
157
158
159 /********************************************************************
160 *
161 * Structure definitions.
162 *
163 ********************************************************************/
164
165 ; objc_super parameter to sendSuper
166 #define RECEIVER 0
167 #define CLASS 4
168
169 ; Selected field offsets in class structure
170 #define ISA 0
171 #define CACHE 32
172
173 ; Method descriptor
174 #define METHOD_NAME 0
175 #define METHOD_IMP 8
176
177 ; Cache header
178 #define MASK 0
179 #define OCCUPIED 4
180 #define BUCKETS 8 // variable length array
181
182 #if defined(OBJC_INSTRUMENTED)
183 ; Cache instrumentation data, follows buckets
184 #define hitCount 0
185 #define hitProbes hitCount + 4
186 #define maxHitProbes hitProbes + 4
187 #define missCount maxHitProbes + 4
188 #define missProbes missCount + 4
189 #define maxMissProbes missProbes + 4
190 #define flushCount maxMissProbes + 4
191 #define flushedEntries flushCount + 4
192 #endif
193
194 /********************************************************************
195 *
196 * Constants.
197 *
198 ********************************************************************/
199
200 // In case the implementation is _objc_msgForward_internal, indicate to it
201 // whether the method was invoked as a word-return or struct-return.
202 // The li instruction costs nothing because it fits into spare
203 // processor cycles. We choose to make the MsgSend indicator non-zero
204 // as r11 is already guaranteed non-zero for a cache hit (no li needed).
205
206 #define kFwdMsgSend 1
207 #define kFwdMsgSendStret 0
208
209
210 /********************************************************************
211 *
212 * Useful macros. Macros are used instead of subroutines, for speed.
213 *
214 ********************************************************************/
215
216 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
217 ;
218 ; LOAD_STATIC_WORD targetReg, symbolName, LOCAL_SYMBOL | EXTERNAL_SYMBOL
219 ;
220 ; Load the value of the named static data word.
221 ;
222 ; Takes: targetReg - the register, other than r0, to load
223 ; symbolName - the name of the symbol
224 ; LOCAL_SYMBOL - symbol name used as-is
225 ; EXTERNAL_SYMBOL - symbol name gets nonlazy treatment
226 ;
227 ; Eats: r0 and targetReg
228 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
229
230 ; Values to specify whether the symbols is plain or nonlazy
231 #define LOCAL_SYMBOL 0
232 #define EXTERNAL_SYMBOL 1
233
234 .macro LOAD_STATIC_WORD
235
236 #if defined(__DYNAMIC__)
237 mflr r0
238 bcl 20,31,1f ; 31 is cr7[so]
239 1: mflr $0
240 mtlr r0
241 .if $2 == EXTERNAL_SYMBOL
242 addis $0,$0,ha16(L$1-1b)
243 lwz $0,lo16(L$1-1b)($0)
244 lwz $0,0($0)
245 .elseif $2 == LOCAL_SYMBOL
246 addis $0,$0,ha16($1-1b)
247 lwz $0,lo16($1-1b)($0)
248 .else
249 !!! Unknown symbol type !!!
250 .endif
251 #else
252 lis $0,ha16($1)
253 lwz $0,lo16($1)($0)
254 #endif
255
256 .endmacro
257
258 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
259 ;
260 ; LEA_STATIC_DATA targetReg, symbolName, LOCAL_SYMBOL | EXTERNAL_SYMBOL
261 ;
262 ; Load the address of the named static data.
263 ;
264 ; Takes: targetReg - the register, other than r0, to load
265 ; symbolName - the name of the symbol
266 ; LOCAL_SYMBOL - symbol is local to this module
267 ; EXTERNAL_SYMBOL - symbol is imported from another module
268 ;
269 ; Eats: r0 and targetReg
270 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
271
272 .macro LEA_STATIC_DATA
273 #if defined(__DYNAMIC__)
274 mflr r0
275 bcl 20,31,1f ; 31 is cr7[so]
276 1: mflr $0
277 mtlr r0
278 .if $2 == EXTERNAL_SYMBOL
279 addis $0,$0,ha16(L$1-1b)
280 lwz $0,lo16(L$1-1b)($0)
281 .elseif $2 == LOCAL_SYMBOL
282 addis $0,$0,ha16($1-1b)
283 addi $0,$0,lo16($1-1b)
284 .else
285 !!! Unknown symbol type !!!
286 .endif
287 #else
288 lis $0,hi16($1)
289 ori $0,$0,lo16($1)
290 #endif
291
292 .endmacro
293
294 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
295 ;
296 ; ENTRY functionName
297 ;
298 ; Assembly directives to begin an exported function.
299 ; We align on cache boundaries for these few functions.
300 ;
301 ; Takes: functionName - name of the exported function
302 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
303
304 .macro ENTRY
305 .text
306 .align 5
307 .globl $0
308 $0:
309 .endmacro
310
311 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
312 ;
313 ; END_ENTRY functionName
314 ;
315 ; Assembly directives to end an exported function. Just a placeholder,
316 ; a close-parenthesis for ENTRY, until it is needed for something.
317 ;
318 ; Takes: functionName - name of the exported function
319 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
320
321 .macro END_ENTRY
322 .endmacro
323
324 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
325 ;
326 ; PLOCK scratchReg, lockName
327 ;
328 ; Acquire named spinlock.
329 ;
330 ; Takes: scratchReg - a register, other than r0, that can be mangled
331 ; lockName - the name of a static, aligned, 32-bit lock word
332 ;
333 ; Eats: r0 and scratchReg
334 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
335
336 .macro PLOCK
337 LEA_STATIC_DATA $0, $1, EXTERNAL_SYMBOL
338 b .+16 ; jump into loop at the reserving check
339 lwz r0,0($0) ; check with fast, less intrusive lwz versus lwarx
340 cmplwi r0,0 ; lock held?
341 bne .-8 ; if so, spin until it appears unlocked
342 lwarx r0,0,$0 ; get lock value, acquire memory reservation
343 cmplwi r0,0 ; lock held?
344 bne .-20 ; if locked, go spin waiting for unlock
345 li r0,1 ; get value that means locked
346 stwcx. r0,0,$0 ; store it iff reservation still holds
347 bne- .-20 ; if reservation was lost, go re-reserve
348 isync ; discard effects of prefetched instructions
349 .endmacro
350
351 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
352 ;
353 ; PUNLOCK scratchReg, lockName
354 ;
355 ; Release named spinlock.
356 ;
357 ; Takes: scratchReg - a register, other than r0, that can be mangled
358 ; lockName - the name of a static, aligned, 32-bit lock word
359 ;
360 ; Eats: r0 and scratchReg
361 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
362
363 .macro PUNLOCK
364 sync ; force out changes before unlocking
365 LEA_STATIC_DATA $0, $1, EXTERNAL_SYMBOL
366 li r0,0 ; get value meaning "unlocked"
367 stw r0,0($0) ; unlock the lock
368 .endmacro
369
370
371 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
372 ;
373 ; CacheLookup selectorRegister, cacheMissLabel
374 ;
375 ; Locate the implementation for a selector in a class method cache.
376 ;
377 ; Takes:
378 ; $0 = register containing selector (r4 or r5 ONLY);
379 ; cacheMissLabel = label to branch to iff method is not cached
380 ; r12 = class whose cache is to be searched
381 ;
382 ; On exit: (found) method triplet in r2, imp in r12, r11 is non-zero
383 ; (not found) jumps to cacheMissLabel
384 ;
385 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
386
387 .macro CacheLookup
388
389 #if defined(OBJC_INSTRUMENTED)
390 ; when instrumented, we use r6 and r7
391 stw r6,36(r1) ; save r6 for use as cache pointer
392 stw r7,40(r1) ; save r7 for use as probe count
393 li r7,0 ; no probes so far!
394 #endif
395
396 lwz r2,CACHE(r12) ; cache = class->cache
397 stw r9,48(r1) ; save r9
398
399 #if defined(OBJC_INSTRUMENTED)
400 mr r6,r2 ; save cache pointer
401 #endif
402
403 lwz r11,MASK(r2) ; mask = cache->mask
404 addi r0,r2,BUCKETS ; buckets = cache->buckets
405 slwi r11,r11,2 ; r11 = mask << 2
406 and r9,$0,r11 ; bytes = sel & (mask<<2)
407
408 #if defined(OBJC_INSTRUMENTED)
409 b LLoop_$0_$1
410
411 LMiss_$0_$1:
412 ; r6 = cache, r7 = probeCount
413 lwz r9,MASK(r6) ; entryCount = mask + 1
414 addi r9,r9,1 ;
415 slwi r9,r9,2 ; tableSize = entryCount * sizeof(entry)
416 addi r9,r9,BUCKETS ; offset = buckets + tableSize
417 add r11,r6,r9 ; cacheData = &cache->buckets[mask+1]
418 lwz r9,missCount(r11) ; cacheData->missCount += 1
419 addi r9,r9,1 ;
420 stw r9,missCount(r11) ;
421 lwz r9,missProbes(r11) ; cacheData->missProbes += probeCount
422 add r9,r9,r7 ;
423 stw r9,missProbes(r11) ;
424 lwz r9,maxMissProbes(r11) ; if (probeCount > cacheData->maxMissProbes)
425 cmplw r7,r9 ; maxMissProbes = probeCount
426 ble .+8 ;
427 stw r7,maxMissProbes(r11) ;
428
429 lwz r6,36(r1) ; restore r6
430 lwz r7,40(r1) ; restore r7
431
432 b $1 ; goto cacheMissLabel
433 #endif
434
435 ; search the cache
436 LLoop_$0_$1:
437 #if defined(OBJC_INSTRUMENTED)
438 addi r7,r7,1 ; probeCount += 1
439 #endif
440
441 lwzx r2,r9,r0 ; method = buckets[bytes/4]
442 addi r9,r9,4 ; bytes += 4
443 cmplwi r2,0 ; if (method == NULL)
444 #if defined(OBJC_INSTRUMENTED)
445 beq- LMiss_$0_$1
446 #else
447 beq- $1 ; goto cacheMissLabel
448 #endif
449
450 lwz r12,METHOD_NAME(r2) ; name = method->method_name
451 and r9,r9,r11 ; bytes &= (mask<<2)
452 cmplw r12,$0 ; if (name != selector)
453 bne- LLoop_$0_$1 ; goto loop
454
455 ; cache hit, r2 == method triplet address
456 ; Return triplet in r2 and imp in r12
457 lwz r12,METHOD_IMP(r2) ; imp = method->method_imp
458
459 #if defined(OBJC_INSTRUMENTED)
460 ; r6 = cache, r7 = probeCount
461 lwz r9,MASK(r6) ; entryCount = mask + 1
462 addi r9,r9,1 ;
463 slwi r9,r9,2 ; tableSize = entryCount * sizeof(entry)
464 addi r9,r9,BUCKETS ; offset = buckets + tableSize
465 add r11,r6,r9 ; cacheData = &cache->buckets[mask+1]
466 lwz r9,hitCount(r11) ; cache->hitCount += 1
467 addi r9,r9,1 ;
468 stw r9,hitCount(r11) ;
469 lwz r9,hitProbes(r11) ; cache->hitProbes += probeCount
470 add r9,r9,r7 ;
471 stw r9,hitProbes(r11) ;
472 lwz r9,maxHitProbes(r11) ; if (probeCount > cache->maxMissProbes)
473 cmplw r7,r9 ;maxMissProbes = probeCount
474 ble .+8 ;
475 stw r7,maxHitProbes(r11) ;
476
477 lwz r6,36(r1) ; restore r6
478 lwz r7,40(r1) ; restore r7
479 #endif
480
481 lwz r9,48(r1) ; restore r9
482
483 .endmacro
484
485 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
486 ;
487 ; CacheLookup cache locking - 2001-11-12
488 ; The collecting cache mechanism precludes the need for a cache lock
489 ; in objc_msgSend. The cost of the collecting cache is small: a few
490 ; K of memory for uncollected caches, and less than 1 ms per collection.
491 ; A large app will only run collection a few times.
492 ; Using the code below to lock the cache almost doubles messaging time,
493 ; costing several seconds of CPU across several minutes of operation.
494 ; The code below probably could be improved, but almost all of the
495 ; locking slowdown is in the sync and isync.
496 ;
497 ; 40 million message test times (G4 1x667):
498 ; no lock 4.390u 0.030s 0:04.59 96.2% 0+0k 0+1io 0pf+0w
499 ; with lock 9.120u 0.010s 0:09.83 92.8% 0+0k 0+0io 0pf+0w
500 ;
501 ;; LockCache mask_dest, cache
502 ;.macro LockCache
503 ; ; LOCKED mask is NEGATIVE
504 ; lwarx $0, mask, $1 ; mask = reserve(cache->mask)
505 ; cmpwi $0, 0 ;
506 ; blt .-8 ; try again if mask < 0
507 ; neg r0, $0 ;
508 ; stwcx. r0, mask, $1 ; cache->mask = -mask ($0 keeps +mask)
509 ; bne .-20 ; try again if lost reserve
510 ; isync ; flush prefetched instructions after locking
511 ;.endmacro
512 ;
513 ;; UnlockCache (mask<<2), cache
514 ;.macro UnlockCache
515 ; sync ; finish previous instructions before unlocking
516 ; srwi r0, $0, 2 ; r0 = (mask<<2) >> 2
517 ; stw r0, mask($1) ; cache->mask = +mask
518 ;.endmacro
519 ;
520 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
521
522
523 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
524 ;
525 ;
526 ; MethodTableLookup WORD_RETURN | STRUCT_RETURN, MSG_SEND | MSG_SENDSUPER
527 ;
528 ; Takes: WORD_RETURN (r3 is first parameter)
529 ; STRUCT_RETURN (r3 is structure return address, r4 is first parameter)
530 ; MSG_SEND (first parameter is receiver)
531 ; MSG_SENDSUPER (first parameter is address of objc_super structure)
532 ;
533 ; Eats: r0, r2, r11, r12
534 ; On exit: restores r9 saved by CacheLookup
535 ; imp in ctr
536 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
537
538 ; Values to specify to method lookup macros whether the return type of
539 ; the method is an integer or structure.
540 #define WORD_RETURN 0
541 #define STRUCT_RETURN 1
542
543 ; Values to specify to method lookup macros whether the return type of
544 ; the method is an integer or structure.
545 #define MSG_SEND 0
546 #define MSG_SENDSUPER 1
547
548 .macro MethodTableLookup
549 mflr r0 ; save lr
550 stw r0, 8(r1) ;
551
552 stw r3, 24(r1) ; save arguments
553 stw r4, 28(r1) ;
554 stw r5, 32(r1) ;
555 stw r6, 36(r1) ;
556 stw r7, 40(r1) ;
557 stw r8, 44(r1) ;
558 ; r9 was saved by CacheLookup
559 stw r10, 52(r1) ;
560
561 #if !defined(KERNEL)
562 ; Save the FP parameter registers.
563 ; We do not spill vector argument registers. This is
564 ; harmless because vector parameters are unsupported.
565 stfd f1, -104(r1) ;
566 stfd f2, -96(r1) ;
567 stfd f3, -88(r1) ;
568 stfd f4, -80(r1) ;
569 stfd f5, -72(r1) ;
570 stfd f6, -64(r1) ;
571 stfd f7, -56(r1) ;
572 stfd f8, -48(r1) ;
573 stfd f9, -40(r1) ;
574 stfd f10, -32(r1) ;
575 stfd f11, -24(r1) ;
576 stfd f12, -16(r1) ;
577 stfd f13, -8(r1) ;
578
579 stwu r1,-56-(13*8)(r1) ; grow the stack. Must be 16-byte-aligned.
580 #else
581 stwu r1,-64(r1) ; grow the stack. Must be 16-byte-aligned.
582 #endif
583
584 ; Pass parameters to __class_lookupMethodAndLoadCache. First parameter is
585 ; the class pointer. Second parameter is the selector. Where they come
586 ; from depends on who called us. In the int return case, the selector is
587 ; already in r4.
588 .if $0 == WORD_RETURN ; WORD_RETURN
589 .if $1 == MSG_SEND ; MSG_SEND
590 lwz r3,ISA(r3) ; class = receiver->isa
591 .else ; MSG_SENDSUPER
592 lwz r3,CLASS(r3) ; class = super->class
593 .endif
594
595 .else ; STRUCT_RETURN
596 .if $1 == MSG_SEND ; MSG_SEND
597 lwz r3,ISA(r4) ; class = receiver->isa
598 .else ; MSG_SENDSUPER
599 lwz r3,CLASS(r4) ; class = super->class
600 .endif
601 mr r4,r5 ; selector = selector
602 .endif
603
604 ; We code the call inline rather than using the CALL_EXTERN macro because
605 ; that leads to a lot of extra unnecessary and inefficient instructions.
606 CALL_EXTERN(__class_lookupMethodAndLoadCache)
607
608 mr r12,r3 ; copy implementation to r12
609 mtctr r3 ; copy imp to ctr
610 lwz r1,0(r1) ; restore the stack pointer
611 lwz r0,8(r1) ;
612 mtlr r0 ; restore return pc
613
614 #if !defined(KERNEL)
615
616 ; Restore FP parameter registers
617 lfd f1, -104(r1) ;
618 lfd f2, -96(r1) ;
619 lfd f3, -88(r1) ;
620 lfd f4, -80(r1) ;
621 lfd f5, -72(r1) ;
622 lfd f6, -64(r1) ;
623 lfd f7, -56(r1) ;
624 lfd f8, -48(r1) ;
625 lfd f9, -40(r1) ;
626 lfd f10, -32(r1) ;
627 lfd f11, -24(r1) ;
628 lfd f12, -16(r1) ;
629 lfd f13, -8(r1) ;
630
631 lwz r3, 24(r1) ; restore parameter registers
632 lwz r4, 28(r1) ;
633 lwz r5, 32(r1) ;
634 lwz r6, 36(r1) ;
635 lwz r7, 40(r1) ;
636 lwz r8, 44(r1) ;
637 lwz r9, 48(r1) ; r9 was saved by CacheLookup
638 lwz r10, 52(r1) ;
639
640 #endif /* !KERNEL */
641
642 .endmacro
643
644 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
645 ;
646 ; CALL_MCOUNT
647 ;
648 ; Macro to call mcount function in profiled builds.
649 ;
650 ; NOTE: Makes sure to save/restore r11 and r12, even though they
651 ; are not defined to be volatile, because they are used during
652 ; forwarding.
653 ;
654 ; Takes: lr Callers return PC
655 ;
656 ; Eats: r0
657 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
658
659 .macro CALL_MCOUNT
660 #if defined(PROFILE)
661 mflr r0 ; save return pc
662 stw r0,8(r1) ;
663
664 stwu r1,-208(r1) ; push aligned areas, set stack link
665
666 stw r3, 56(r1) ; save all volatile registers
667 stw r4, 60(r1) ;
668 stw r5, 64(r1) ;
669 stw r6, 68(r1) ;
670 stw r7, 72(r1) ;
671 stw r8, 76(r1) ;
672 stw r9, 80(r1) ;
673 stw r10,84(r1) ;
674 stw r11,88(r1) ; save r11 and r12, too
675 stw r12,92(r1) ;
676
677 stfd f1, 96(r1) ;
678 stfd f2, 104(r1) ;
679 stfd f3, 112(r1) ;
680 stfd f4, 120(r1) ;
681 stfd f5, 128(r1) ;
682 stfd f6, 136(r1) ;
683 stfd f7, 144(r1) ;
684 stfd f8, 152(r1) ;
685 stfd f9, 160(r1) ;
686 stfd f10,168(r1) ;
687 stfd f11,176(r1) ;
688 stfd f12,184(r1) ;
689 stfd f13,192(r1) ;
690
691 mr r3, r0 ; pass our callers address
692
693 CALL_EXTERN(mcount)
694
695 lwz r3, 56(r1) ; restore all volatile registers
696 lwz r4, 60(r1) ;
697 lwz r5, 64(r1) ;
698 lwz r6, 68(r1) ;
699 lwz r7, 72(r1) ;
700 lwz r8, 76(r1) ;
701 lwz r9, 80(r1) ;
702 lwz r10,84(r1) ;
703 lwz r11,88(r1) ; restore r11 and r12, too
704 lwz r12,92(r1) ;
705
706 lfd f1, 96(r1) ;
707 lfd f2, 104(r1) ;
708 lfd f3, 112(r1) ;
709 lfd f4, 120(r1) ;
710 lfd f5, 128(r1) ;
711 lfd f6, 136(r1) ;
712 lfd f7, 144(r1) ;
713 lfd f8, 152(r1) ;
714 lfd f9, 160(r1) ;
715 lfd f10,168(r1) ;
716 lfd f11,176(r1) ;
717 lfd f12,184(r1) ;
718 lfd f13,192(r1) ;
719
720 lwz r1,0(r1) ; restore the stack pointer
721 lwz r0,8(r1) ;
722 mtlr r0 ; restore return pc
723 #endif
724 .endmacro
725
726
727 /********************************************************************
728 * Method _cache_getMethod(Class cls, SEL sel, IMP objc_msgForward_imp)
729 *
730 * On entry: r3 = class whose cache is to be searched
731 * r4 = selector to search for
732 * r5 = _objc_msgForward IMP
733 *
734 * If found, returns method triplet pointer.
735 * If not found, returns NULL.
736 *
737 * NOTE: _cache_getMethod never returns any cache entry whose implementation
738 * is _objc_msgForward. It returns (Method)1 instead. This prevents thread-
739 * safety and memory management bugs in _class_lookupMethodAndLoadCache.
740 * See _class_lookupMethodAndLoadCache for details.
741 *
742 * _objc_msgForward is passed as a parameter because it's more efficient
743 * to do the (PIC) lookup once in the caller than repeatedly here.
744 ********************************************************************/
745
746 .private_extern __cache_getMethod
747 ENTRY __cache_getMethod
748 ; do profiling if enabled
749 CALL_MCOUNT
750
751 ; do lookup
752 mr r12,r3 ; move class to r12 for CacheLookup
753 CacheLookup r4, LGetMethodMiss
754
755 ; cache hit, method triplet in r2 and imp in r12
756 cmplw r12, r5 ; check for _objc_msgForward
757 mr r3, r2 ; optimistically get the return value
758 bnelr ; Not _objc_msgForward, return the triplet address
759 li r3, 1 ; Is _objc_msgForward, return (Method)1
760 blr
761
762 LGetMethodMiss:
763 li r3, 0 ; cache miss or _objc_msgForward, return nil
764 blr
765
766 LGetMethodExit:
767 END_ENTRY __cache_getMethod
768
769
770 /********************************************************************
771 * IMP _cache_getImp(Class cls, SEL sel)
772 *
773 * On entry: r3 = class whose cache is to be searched
774 * r4 = selector to search for
775 *
776 * If found, returns method implementation.
777 * If not found, returns NULL.
778 ********************************************************************/
779
780 .private_extern __cache_getImp
781 ENTRY __cache_getImp
782 ; do profiling if enabled
783 CALL_MCOUNT
784
785 ; do lookup
786 mr r12,r3 ; move class to r12 for CacheLookup
787 CacheLookup r4, LGetImpMiss
788
789 ; cache hit, method triplet in r2 and imp in r12
790 mr r3, r12 ; return method imp address
791 blr
792
793 LGetImpMiss:
794 ; cache miss, return nil
795 li r3, 0 ; return nil
796 blr
797
798 LGetImpExit:
799 END_ENTRY __cache_getImp
800
801
802 /********************************************************************
803 * id objc_msgSend(id self,
804 * SEL op,
805 * ...);
806 *
807 * On entry: r3 is the message receiver,
808 * r4 is the selector
809 ********************************************************************/
810
811 ; WARNING - This code may be copied as is to the Objective-C runtime pages.
812 ; The code is copied by rtp_set_up_objc_msgSend() from the
813 ; beginning to the blr marker just prior to the cache miss code.
814 ; Do not add callouts, global variable accesses, or rearrange
815 ; the code without updating rtp_set_up_objc_msgSend.
816
817 ; Absolute symbols bounding the runtime page version of objc_msgSend.
818 _objc_msgSend_rtp = 0xfffeff00
819 _objc_msgSend_rtp_exit = 0xfffeff00+0x100
820
821 ENTRY _objc_msgSend_fixup_rtp
822 lwz r4, 4(r4) ; load _cmd from message_ref
823 b _objc_msgSend
824 END_ENTRY _objc_msgSend_fixup_rtp
825
826 ENTRY _objc_msgSend
827 ; check whether receiver is nil or selector is to be ignored
828 cmplwi r3,0 ; receiver nil?
829 xoris r11,r4,((kIgnore>>16) & 0xffff) ; clear hi if equal to ignored
830 cmplwi cr1,r11,(kIgnore & 0xffff) ; selector is to be ignored?
831 beq- LMsgSendNilSelf ; if nil receiver, call handler or return nil
832 lwz r12,ISA(r3) ; class = receiver->isa
833 beqlr- cr1 ; if ignored selector, return self immediately
834
835 ; guaranteed non-nil entry point (disabled for now)
836 ; .globl _objc_msgSendNonNil
837 ; _objc_msgSendNonNil:
838
839 ; do profiling when enabled
840 CALL_MCOUNT
841
842 ; receiver is non-nil: search the cache
843 LMsgSendReceiverOk:
844 ; class is already in r12
845 CacheLookup r4, LMsgSendCacheMiss
846 ; CacheLookup placed imp in r12
847 mtctr r12
848 ; r11 guaranteed non-zero on exit from CacheLookup with a hit
849 // li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
850 bctr ; goto *imp;
851
852 ; WARNING - The first six instructions of LMsgSendNilSelf are
853 ; rewritten when objc_msgSend is copied to the runtime pages.
854 ; These instructions must be maintained AS IS unless the code in
855 ; rtp_set_up_objc_msgSend is also updated.
856 ; * `mflr r0` must not be changed (not even to use a different register)
857 ; * the load of _objc_nilReceiver value must remain six insns long
858 ; * the value of _objc_nilReceiver must continue to be loaded into r11
859
860 ; message sent to nil: redirect to nil receiver, if any
861 LMsgSendNilSelf:
862 ; DO NOT CHANGE THE NEXT SIX INSTRUCTIONS - see note above
863 mflr r0 ; save return address
864 bcl 20,31,1f ; 31 is cr7[so]
865 1: mflr r11
866 addis r11,r11,ha16(__objc_nilReceiver-1b)
867 lwz r11,lo16(__objc_nilReceiver-1b)(r11)
868 mtlr r0 ; restore return address
869 ; DO NOT CHANGE THE PREVIOUS SIX INSTRUCTIONS - see note above
870
871 cmplwi r11,0 ; return nil if no new receiver
872 beq LMsgSendReturnZero
873
874 mr r3,r11 ; send to new receiver
875 lwz r12,ISA(r11) ; class = receiver->isa
876 b LMsgSendReceiverOk
877
878 LMsgSendReturnZero:
879 li r3, 0
880 li r4, 0
881 lis r12, ha16(kRTAddress_zero)
882 lfd f1, lo16(kRTAddress_zero)(r12)
883 lfd f2, lo16(kRTAddress_zero)(r12)
884
885 ; WARNING - This blr marks the end of the copy to the ObjC runtime pages and
886 ; also marks the beginning of the cache miss code. Do not move
887 ; around without checking the ObjC runtime pages initialization code.
888 blr
889
890 ; cache miss: go search the method lists
891 LMsgSendCacheMiss:
892 MethodTableLookup WORD_RETURN, MSG_SEND
893 li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
894 bctr ; goto *imp;
895
896 LMsgSendExit:
897 END_ENTRY _objc_msgSend
898
899 /********************************************************************
900 *
901 * double objc_msgSend_fpret(id self, SEL op, ...);
902 *
903 ********************************************************************/
904
905 ENTRY _objc_msgSend_fpret
906 b _objc_msgSend
907 END_ENTRY _objc_msgSend_fpret
908
909 /********************************************************************
910 * struct_type objc_msgSend_stret(id self,
911 * SEL op,
912 * ...);
913 *
914 * objc_msgSend_stret is the struct-return form of msgSend.
915 * The ABI calls for r3 to be used as the address of the structure
916 * being returned, with the parameters in the succeeding registers.
917 *
918 * On entry: r3 is the address where the structure is returned,
919 * r4 is the message receiver,
920 * r5 is the selector
921 ********************************************************************/
922
923 ENTRY _objc_msgSend_stret_fixup_rtp
924 lwz r5, 4(r5) ; load _cmd from message_ref
925 b _objc_msgSend_stret
926 END_ENTRY _objc_msgSend_stret_fixup_rtp
927
928 ENTRY _objc_msgSend_stret
929 ; check whether receiver is nil
930 cmplwi r4,0 ; receiver nil?
931 beq LMsgSendStretNilSelf ; if so, call handler or just return
932
933 ; guaranteed non-nil entry point (disabled for now)
934 ; .globl _objc_msgSendNonNil_stret
935 ; _objc_msgSendNonNil_stret:
936
937 ; do profiling when enabled
938 CALL_MCOUNT
939
940 ; receiver is non-nil: search the cache
941 LMsgSendStretReceiverOk:
942 lwz r12, ISA(r4) ; class = receiver->isa
943 CacheLookup r5, LMsgSendStretCacheMiss
944 ; CacheLookup placed imp in r12
945 mtctr r12
946 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
947 bctr ; goto *imp;
948
949 ; cache miss: go search the method lists
950 LMsgSendStretCacheMiss:
951 MethodTableLookup STRUCT_RETURN, MSG_SEND
952 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
953 bctr ; goto *imp;
954
955 ; message sent to nil: redirect to nil receiver, if any
956 LMsgSendStretNilSelf:
957 mflr r0 ; load new receiver
958 bcl 20,31,1f ; 31 is cr7[so]
959 1: mflr r11
960 addis r11,r11,ha16(__objc_nilReceiver-1b)
961 lwz r11,lo16(__objc_nilReceiver-1b)(r11)
962 mtlr r0
963
964 cmplwi r11,0 ; return if no new receiver
965 beqlr
966
967 mr r4,r11 ; send to new receiver
968 b LMsgSendStretReceiverOk
969
970 LMsgSendStretExit:
971 END_ENTRY _objc_msgSend_stret
972
973
974 /********************************************************************
975 * id objc_msgSendSuper(struct objc_super *super,
976 * SEL op,
977 * ...);
978 *
979 * struct objc_super {
980 * id receiver;
981 * Class class;
982 * };
983 ********************************************************************/
984
985 ENTRY _objc_msgSendSuper2_fixup_rtp
986 ; objc_super->class is superclass of the class to search
987 lwz r11, CLASS(r3)
988 lwz r4, 4(r4) ; load _cmd from message_ref
989 lwz r11, 4(r11) ; r11 = cls->super_class
990 stw r11, CLASS(r3)
991 b _objc_msgSendSuper
992 END_ENTRY _objc_msgSendSuper2_fixup_rtp
993
994 ENTRY _objc_msgSendSuper
995 ; do profiling when enabled
996 CALL_MCOUNT
997
998 ; check whether selector is to be ignored
999 xoris r11,r4,((kIgnore>>16) & 0xffff) ; clear hi if to be ignored
1000 cmplwi r11,(kIgnore & 0xffff) ; selector is to be ignored?
1001 lwz r12,CLASS(r3) ; class = super->class
1002 beq- LMsgSendSuperIgnored ; if ignored, return self
1003
1004 ; search the cache
1005 ; class is already in r12
1006 CacheLookup r4, LMsgSendSuperCacheMiss
1007 ; CacheLookup placed imp in r12
1008 mtctr r12
1009 lwz r3,RECEIVER(r3) ; receiver is the first arg
1010 ; r11 guaranteed non-zero after cache hit
1011 ; li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
1012 bctr ; goto *imp;
1013
1014 ; cache miss: go search the method lists
1015 LMsgSendSuperCacheMiss:
1016 MethodTableLookup WORD_RETURN, MSG_SENDSUPER
1017 lwz r3,RECEIVER(r3) ; receiver is the first arg
1018 li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
1019 bctr ; goto *imp;
1020
1021 ; ignored selector: return self
1022 LMsgSendSuperIgnored:
1023 lwz r3,RECEIVER(r3)
1024 blr
1025
1026 LMsgSendSuperExit:
1027 END_ENTRY _objc_msgSendSuper
1028
1029
1030 /********************************************************************
1031 * struct_type objc_msgSendSuper_stret(objc_super *super,
1032 * SEL op,
1033 * ...);
1034 *
1035 * struct objc_super {
1036 * id receiver;
1037 * Class class;
1038 * };
1039 *
1040 *
1041 * objc_msgSendSuper_stret is the struct-return form of msgSendSuper.
1042 * The ABI calls for r3 to be used as the address of the structure
1043 * being returned, with the parameters in the succeeding registers.
1044 *
1045 * On entry: r3 is the address to which to copy the returned structure,
1046 * r4 is the address of the objc_super structure,
1047 * r5 is the selector
1048 ********************************************************************/
1049
1050 ENTRY _objc_msgSendSuper2_stret_fixup_rtp
1051 ; objc_super->class is superclass of the class to search
1052 lwz r11, CLASS(r4)
1053 lwz r5, 4(r5) ; load _cmd from message_ref
1054 lwz r11, 4(r11) ; r11 = cls->super_class
1055 stw r11, CLASS(r4)
1056 b _objc_msgSendSuper_stret
1057 END_ENTRY _objc_msgSendSuper2_stret_fixup_rtp
1058
1059 ENTRY _objc_msgSendSuper_stret
1060 ; do profiling when enabled
1061 CALL_MCOUNT
1062
1063 ; search the cache
1064 lwz r12,CLASS(r4) ; class = super->class
1065 CacheLookup r5, LMsgSendSuperStretCacheMiss
1066 ; CacheLookup placed imp in r12
1067 mtctr r12
1068 lwz r4,RECEIVER(r4) ; receiver is the first arg
1069 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
1070 bctr ; goto *imp;
1071
1072 ; cache miss: go search the method lists
1073 LMsgSendSuperStretCacheMiss:
1074 MethodTableLookup STRUCT_RETURN, MSG_SENDSUPER
1075 lwz r4,RECEIVER(r4) ; receiver is the first arg
1076 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
1077 bctr ; goto *imp;
1078
1079 LMsgSendSuperStretExit:
1080 END_ENTRY _objc_msgSendSuper_stret
1081
1082
1083 /********************************************************************
1084 *
1085 * Out-of-band parameter r11 indicates whether it was objc_msgSend or
1086 * objc_msgSend_stret that triggered the message forwarding. The
1087 *
1088 * Iff r11 == kFwdMsgSend, it is the word-return (objc_msgSend) case,
1089 * and the interface is:
1090 *
1091 * id _objc_msgForward(id self,
1092 * SEL sel,
1093 * ...);
1094 *
1095 * Iff r11 == kFwdMsgSendStret, it is the structure-return
1096 * (objc_msgSend_stret) case, and the interface is:
1097 *
1098 * struct_type _objc_msgForward(id self,
1099 * SEL sel,
1100 * ...);
1101 *
1102 * There are numerous reasons why it is better to have one
1103 * _objc_msgForward, rather than adding _objc_msgForward_stret.
1104 * The best one is that _objc_msgForward is the method that
1105 * gets cached when respondsToMethod returns false, and it
1106 * wouldnt know which one to use.
1107 *
1108 * Sends the message to a method having the signature
1109 *
1110 * - forward:(SEL)sel :(marg_list)args;
1111 *
1112 * But the marg_list is prepended with the 13 double precision
1113 * floating point registers that could be used as parameters into
1114 * the method (fortunately, the same registers are used for either
1115 * single or double precision floats). These registers are layed
1116 * down by _objc_msgForward, and picked up by _objc_msgSendv. So
1117 * the "marg_list" is actually:
1118 *
1119 * typedef struct objc_sendv_margs {
1120 * double floatingPointArgs[13];
1121 * intptr_t linkageArea[6];
1122 * intptr_t registerArgs[8];
1123 * intptr_t stackArgs[variable];
1124 * };
1125 *
1126 ********************************************************************/
1127
1128 ; _FwdSel is @selector(forward::), set up in map_images().
1129 ; ALWAYS dereference _FwdSel to get to "forward::" !!
1130 .data
1131 .align 2
1132 .private_extern _FwdSel
1133 _FwdSel: .long 0
1134
1135 .cstring
1136 .align 2
1137 LUnkSelStr: .ascii "Does not recognize selector %s\0"
1138
1139 .data
1140 .align 2
1141 .private_extern __objc_forward_handler
1142 __objc_forward_handler: .long 0
1143
1144 .data
1145 .align 2
1146 .private_extern __objc_forward_stret_handler
1147 __objc_forward_stret_handler: .long 0
1148
1149
1150 ENTRY __objc_msgForward
1151 // Non-stret version
1152 li r11,kFwdMsgSend
1153 b __objc_msgForward_internal
1154 END_ENTRY _objc_msgForward
1155
1156 ENTRY __objc_msgForward_stret
1157 // Struct-return version
1158 li r11,kFwdMsgSendStret
1159 b __objc_msgForward_internal
1160 END_ENTRY _objc_msgForward_stret
1161
1162
1163 ENTRY __objc_msgForward_internal
1164 // Method cache version
1165
1166 // THIS IS NOT A CALLABLE C FUNCTION
1167 // Out-of-band register %r11 is zero for stret, nonzero otherwise
1168
1169 ; do profiling when enabled
1170 CALL_MCOUNT
1171
1172 ; Check return type (stret or not)
1173 cmplwi r11,kFwdMsgSendStret
1174 beq LMsgForwardStretSel
1175
1176 ; Non-stret return
1177 ; Call user handler, if any
1178 LOAD_STATIC_WORD r12, __objc_forward_handler, LOCAL_SYMBOL
1179 cmplwi r12, 0
1180 mtctr r12
1181 bnectr ; call _objc_forward_handler if not NULL
1182 ; No user handler
1183 mr r11, r3 ; r11 = receiver
1184 mr r12, r4 ; r12 = SEL
1185 b LMsgForwardSelCmp
1186
1187 LMsgForwardStretSel:
1188 ; Stret return
1189 ; Call user handler, if any
1190 LOAD_STATIC_WORD r12, __objc_forward_stret_handler, LOCAL_SYMBOL
1191 cmplwi r12, 0
1192 mtctr r12
1193 bnectr ; call _objc_forward_stret_handler if not NULL
1194 ; No user handler
1195 mr r11, r4 ; r11 = receiver
1196 mr r12, r5 ; r12 = SEL
1197
1198 LMsgForwardSelCmp:
1199 ; r11 is the receiver
1200 ; r12 is the selector
1201
1202 ; Die if forwarding "forward::"
1203 LOAD_STATIC_WORD r2, _FwdSel, LOCAL_SYMBOL
1204 cmplw r2, r12
1205 beq LMsgForwardError
1206
1207 ; Save registers to margs
1208 ; Link register
1209 mflr r0
1210 stw r0, 8(r1)
1211
1212 ; GPR parameters
1213 stw r3, 24(r1)
1214 stw r4, 28(r1)
1215 stw r5, 32(r1)
1216 stw r6, 36(r1)
1217 stw r7, 40(r1)
1218 stw r8, 44(r1)
1219 stw r9, 48(r1)
1220 stw r10,52(r1)
1221
1222 ; FP parameters
1223 stfd f1, -104(r1)
1224 stfd f2, -96(r1)
1225 stfd f3, -88(r1)
1226 stfd f4, -80(r1)
1227 stfd f5, -72(r1)
1228 stfd f6, -64(r1)
1229 stfd f7, -56(r1)
1230 stfd f8, -48(r1)
1231 stfd f9, -40(r1)
1232 stfd f10, -32(r1)
1233 stfd f11, -24(r1)
1234 stfd f12, -16(r1)
1235 stfd f13, -8(r1)
1236
1237 ; Call [receiver forward:sel :margs]
1238 mr r3, r11 ; receiver
1239 mr r4, r2 ; forward::
1240 mr r5, r12 ; sel
1241 subi r6,r1,13*8 ; &margs (on stack)
1242
1243 stwu r1,-56-(13*8)(r1) ; push stack frame
1244 bl _objc_msgSend ; [self forward:sel :objc_sendv_margs]
1245 addi r1,r1,56+13*8 ; pop stack frame
1246
1247 lwz r0,8(r1) ; restore lr
1248 mtlr r0 ;
1249 blr ;
1250
1251 LMsgForwardError:
1252 ; Call __objc_error(receiver, "unknown selector %s", "forward::")
1253 mr r3, r11
1254 LEA_STATIC_DATA r4, LUnkSelStr, LOCAL_SYMBOL
1255 mr r5, r2
1256 CALL_EXTERN(___objc_error) ; never returns
1257 trap
1258
1259 END_ENTRY __objc_msgForward_internal
1260
1261
1262 /********************************************************************
1263 * id objc_msgSendv(id self,
1264 * SEL op,
1265 * unsigned arg_size,
1266 * marg_list arg_frame);
1267 *
1268 * But the marg_list is prepended with the 13 double precision
1269 * floating point registers that could be used as parameters into
1270 * the method (fortunately, the same registers are used for either
1271 * single or double precision floats). These registers are layed
1272 * down by _objc_msgForward, and picked up by _objc_msgSendv. So
1273 * the "marg_list" is actually:
1274 *
1275 * typedef struct objc_sendv_margs {
1276 * double floatingPointArgs[13];
1277 * int linkageArea[6];
1278 * int registerArgs[8];
1279 * int stackArgs[variable];
1280 * };
1281 *
1282 * arg_size is the number of bytes of parameters in registerArgs and
1283 * stackArgs combined (i.e. it is method_getSizeOfArguments(method)).
1284 * Specifically, it is NOT the overall arg_frame size, because that
1285 * would include the floatingPointArgs and linkageArea, which are
1286 * PowerPC-specific. This is consistent with the other architectures.
1287 ********************************************************************/
1288
1289 ENTRY _objc_msgSendv
1290
1291 #if !defined(KERNEL)
1292 ; do profiling when enabled
1293 CALL_MCOUNT
1294
1295 mflr r0
1296 stw r0,8(r1) ; save lr
1297
1298 cmplwi r5,32 ; check parameter size against minimum
1299 ble+ LMsgSendvMinFrame ; is less than minimum, go use minimum
1300 mr r12,r1 ; remember current stack pointer
1301 sub r11,r1,r5 ; push parameter area
1302 rlwinm r1,r11,0,0,27 ; align stack pointer to 16 byte boundary
1303 stwu r12,-32(r1) ; push aligned linkage area, set stack link
1304 b LMsgSendvHaveFrame
1305
1306 LMsgSendvMinFrame:
1307 stwu r1,-64(r1) ; push aligned linkage and parameter areas, set stack link
1308
1309 LMsgSendvHaveFrame:
1310 ; restore floating point register parameters from marg_list
1311 lfd f1, 0(r6) ;
1312 lfd f2, 8(r6) ;
1313 lfd f3, 16(r6) ;
1314 lfd f4, 24(r6) ;
1315 lfd f5, 32(r6) ;
1316 lfd f6, 40(r6) ;
1317 lfd f7, 48(r6) ;
1318 lfd f8, 56(r6) ;
1319 lfd f9, 64(r6) ;
1320 lfd f10,72(r6) ;
1321 lfd f11,80(r6) ;
1322 lfd f12,88(r6) ;
1323 lfd f13,96(r6) ;
1324
1325 ; load the register based arguments from the marg_list
1326 ; the first two parameters are already in r3 and r4, respectively
1327 subi r0,r5,(2*4)-3 ; make word count from byte count rounded up to multiple of 4...
1328 srwi. r0,r0,2 ; ... and subtracting for params already in r3 and r4
1329 beq LMsgSendvSendIt ; branch if there are no parameters to load
1330 mtctr r0 ; counter = number of remaining words
1331 lwz r5,32+(13*8)(r6) ; load 3rd parameter
1332 bdz LMsgSendvSendIt ; decrement counter, branch if result is zero
1333 addi r11,r6,36+(13*8) ; switch to r11, because we are setting r6
1334 lwz r6,0(r11) ; load 4th parameter
1335 bdz LMsgSendvSendIt ; decrement counter, branch if result is zero
1336 lwz r7,4(r11) ; load 5th parameter
1337 bdz LMsgSendvSendIt ; decrement counter, branch if result is zero
1338 lwz r8,8(r11) ; load 6th parameter
1339 bdz LMsgSendvSendIt ; decrement counter, branch if result is zero
1340 lwz r9,12(r11) ; load 7th parameter
1341 bdz LMsgSendvSendIt ; decrement counter, branch if result is zero
1342 lwzu r10,16(r11) ; load 8th parameter, and update r11
1343 bdz LMsgSendvSendIt ; decrement counter, branch if result is zero
1344
1345 ; copy the stack based arguments from the marg_list
1346 addi r12,r1,24+32-4 ; target = address of stack based parameters
1347 LMsgSendvArgLoop:
1348 lwzu r0,4(r11) ; loop to copy remaining marg_list words to stack
1349 stwu r0,4(r12) ;
1350 bdnz LMsgSendvArgLoop ; decrement counter, branch if still non-zero
1351
1352 LMsgSendvSendIt:
1353 bl _objc_msgSend ; objc_msgSend (self, selector, ...)
1354
1355 lwz r1,0(r1) ; restore stack pointer
1356 lwz r0,8(r1) ; restore lr
1357 mtlr r0 ;
1358 blr ;
1359 #else
1360 trap ; _objc_msgSendv is not for the kernel
1361 #endif
1362
1363 END_ENTRY _objc_msgSendv
1364
1365 /********************************************************************
1366 * double objc_msgSendv_fpret(id self, SEL op, unsigned arg_size,
1367 * marg_list arg_frame);
1368 ********************************************************************/
1369
1370 ENTRY _objc_msgSendv_fpret
1371 b _objc_msgSendv
1372 END_ENTRY _objc_msgSendv_fpret
1373
1374 /********************************************************************
1375 * void objc_msgSendv_stret(void *structStorage,
1376 * id self,
1377 * SEL op,
1378 * unsigned arg_size,
1379 * marg_list arg_frame);
1380 *
1381 * objc_msgSendv_stret is the struct-return form of msgSendv.
1382 * This function does not use the struct-return ABI; instead, the
1383 * structure return address is passed as a normal parameter.
1384 * The two are functionally identical on ppc, but not on other architectures.
1385 *
1386 * On entry: r3 is the address in which the returned struct is put,
1387 * r4 is the message receiver,
1388 * r5 is the selector,
1389 * r6 is the size of the marg_list, in bytes,
1390 * r7 is the address of the marg_list
1391 ********************************************************************/
1392
1393 ENTRY _objc_msgSendv_stret
1394
1395 #if !defined(KERNEL)
1396 ; do profiling when enabled
1397 CALL_MCOUNT
1398
1399 mflr r0
1400 stw r0,8(r1) ; (save return pc)
1401
1402 cmplwi r6,32 ; check parameter size against minimum
1403 ble+ LMsgSendvStretMinFrame ; is less than minimum, go use minimum
1404 mr r12,r1 ; remember current stack pointer
1405 sub r11,r1,r6 ; push parameter area
1406 rlwinm r1,r11,0,0,27 ; align stack pointer to 16 byte boundary
1407 stwu r12,-32(r1) ; push aligned linkage area, set stack link
1408 b LMsgSendvStretHaveFrame
1409
1410 LMsgSendvStretMinFrame:
1411 stwu r1,-64(r1) ; push aligned linkage and parameter areas, set stack link
1412
1413 LMsgSendvStretHaveFrame:
1414 ; restore floating point register parameters from marg_list
1415 lfd f1,0(r7) ;
1416 lfd f2,8(r7) ;
1417 lfd f3,16(r7) ;
1418 lfd f4,24(r7) ;
1419 lfd f5,32(r7) ;
1420 lfd f6,40(r7) ;
1421 lfd f7,48(r7) ;
1422 lfd f8,56(r7) ;
1423 lfd f9,64(r7) ;
1424 lfd f10,72(r7) ;
1425 lfd f11,80(r7) ;
1426 lfd f12,88(r7) ;
1427 lfd f13,96(r7) ;
1428
1429 ; load the register based arguments from the marg_list
1430 ; the structure return address and the first two parameters
1431 ; are already in r3, r4, and r5, respectively.
1432 ; NOTE: The callers r3 probably, but not necessarily, matches
1433 ; the r3 in the marg_list. That is, the struct-return
1434 ; storage used by the caller could be an intermediate buffer
1435 ; that will end up being copied into the original
1436 ; struct-return buffer (pointed to by the marg_listed r3).
1437 subi r0,r6,(3*4)-3 ; make word count from byte count rounded up to multiple of 4...
1438 srwi. r0,r0,2 ; ... and subtracting for params already in r3 and r4 and r5
1439 beq LMsgSendvStretSendIt ; branch if there are no parameters to load
1440 mtctr r0 ; counter = number of remaining words
1441 lwz r6,36+(13*8)(r7) ; load 4th parameter
1442 bdz LMsgSendvStretSendIt ; decrement counter, branch if result is zero
1443 addi r11,r7,40+(13*8) ; switch to r11, because we are setting r7
1444 lwz r7,0(r11) ; load 5th parameter
1445 bdz LMsgSendvStretSendIt ; decrement counter, branch if result is zero
1446 lwz r8,4(r11) ; load 6th parameter
1447 bdz LMsgSendvStretSendIt ; decrement counter, branch if result is zero
1448 lwz r9,8(r11) ; load 7th parameter
1449 bdz LMsgSendvStretSendIt ; decrement counter, branch if result is zero
1450 lwzu r10,12(r11) ; load 8th parameter, and update r11
1451 bdz LMsgSendvStretSendIt ; decrement counter, branch if result is zero
1452
1453 ; copy the stack based arguments from the marg_list
1454 addi r12,r1,24+32-4 ; target = address of stack based parameters
1455 LMsgSendvStretArgLoop:
1456 lwzu r0,4(r11) ; loop to copy remaining marg_list words to stack
1457 stwu r0,4(r12) ;
1458 bdnz LMsgSendvStretArgLoop ; decrement counter, branch if still non-zero
1459
1460 LMsgSendvStretSendIt:
1461 bl _objc_msgSend_stret ; struct_type objc_msgSend_stret (self, selector, ...)
1462
1463 lwz r1,0(r1) ; restore stack pointer
1464 lwz r0,8(r1) ; restore return pc
1465 mtlr r0
1466 blr ; return
1467 #else /* KERNEL */
1468 trap ; _objc_msgSendv_stret is not for the kernel
1469 #endif /* !KERNEL */
1470
1471 END_ENTRY _objc_msgSendv_stret
1472
1473
1474 ENTRY _method_invoke
1475
1476 lwz r12, METHOD_IMP(r4)
1477 lwz r4, METHOD_NAME(r4)
1478 mtctr r12
1479 bctr
1480
1481 END_ENTRY _method_invoke
1482
1483
1484 ENTRY _method_invoke_stret
1485
1486 lwz r12, METHOD_IMP(r5)
1487 lwz r5, METHOD_NAME(r5)
1488 mtctr r12
1489 bctr
1490
1491 END_ENTRY _method_invoke_stret
1492
1493 #endif