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