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