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