]> git.saurik.com Git - apple/objc4.git/blob - runtime/Messengers.subproj/objc-msg-ppc.s
objc4-208.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 * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.1 (the "License"). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24 /********************************************************************
25 *
26 * objc-msg-ppc.s - PowerPC code to support objc messaging.
27 *
28 * Copyright 1988-1996 NeXT Software, Inc.
29 *
30 * 8-Nov-2000 Laurent Ramontianu (ramontia@apple.com)
31 * Added "few args" params. to CacheLookup and MethodTableLookup
32 * Added the alternate entry points:
33 * objc_msgSendFew, objc_msgSendFew_stret,
34 * objc_msgSendSuperFew, objc_msgSendSuperFew_stret
35 *
36 * 18-Jun-97 David Harrison (harrison@apple.com)
37 * Restructured.
38 *
39 * 1-May-97 Umesh Vaishampayan (umeshv@NeXT.com)
40 * Incorporated locking code fixes from
41 * David Harrison (harrison@NeXT.com)
42 *
43 * 2-Apr-97 Umesh Vaishampayan (umeshv@NeXT.com)
44 * Incorporated changes for messenger with struct return
45 * Cleaned up the labels to use local labels
46 * Fixed bug in the msgSendSuper that did not do the locking.
47 *
48 * 31-Dec-96 Umesh Vaishampayan (umeshv@NeXT.com)
49 * Created from m98k.
50 ********************************************************************/
51
52 #if defined(OBJC_COLLECTING_CACHE)
53 ; _objc_entryPoints and _objc_exitPoints are used by method dispatch
54 ; caching code to figure out whether any threads are actively
55 ; in the cache for dispatching. The labels surround the asm code
56 ; that do cache lookups. The tables are zero-terminated.
57 .data
58 .globl _objc_entryPoints
59 _objc_entryPoints:
60 .long _objc_msgSend
61 .long _objc_msgSend_stret
62 .long _objc_msgSendSuper
63 .long _objc_msgSendSuper_stret
64 .long _objc_msgSendFew
65 .long _objc_msgSendFew_stret
66 .long _objc_msgSendSuperFew
67 .long _objc_msgSendSuperFew_stret
68 .long 0
69
70 .globl _objc_exitPoints
71 _objc_exitPoints:
72 .long LMsgSendExit
73 .long LMsgSendStretExit
74 .long LMsgSendSuperExit
75 .long LMsgSendSuperStretExit
76 .long LMsgSendFewExit
77 .long LMsgSendFewStretExit
78 .long LMsgSendSuperFewExit
79 .long LMsgSendSuperFewStretExit
80 .long 0
81 #endif
82
83 /********************************************************************
84 *
85 * Structure definitions.
86 *
87 ********************************************************************/
88
89 ; objc_super parameter to sendSuper
90 receiver = 0
91 class = 4
92
93 ; Selected field offsets in class structure
94 isa = 0
95 cache = 32
96
97 ; Method descriptor
98 method_name = 0
99 method_imp = 8
100
101 ; Cache header
102 mask = 0
103 occupied = 4
104 buckets = 8 // variable length array
105
106 #if defined(OBJC_INSTRUMENTED)
107 ; Cache instrumentation data, follows buckets
108 hitCount = 0
109 hitProbes = hitCount + 4
110 maxHitProbes = hitProbes + 4
111 missCount = maxHitProbes + 4
112 missProbes = missCount + 4
113 maxMissProbes = missProbes + 4
114 flushCount = maxMissProbes + 4
115 flushedEntries = flushCount + 4
116 #endif
117
118 /********************************************************************
119 *
120 * Constants.
121 *
122 ********************************************************************/
123
124 // In case the implementation is _objc_msgForward, indicate to it
125 // whether the method was invoked as a word-return or struct-return.
126 // The li instruction costs nothing because it fits into spare
127 // processor cycles.
128
129 kFwdMsgSend = 0
130 kFwdMsgSendStret = 1
131
132 /********************************************************************
133 *
134 * Useful macros. Macros are used instead of subroutines, for speed.
135 *
136 ********************************************************************/
137
138 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
139 ;
140 ; LOAD_STATIC_WORD targetReg, symbolName, LOCAL_SYMBOL | EXTERNAL_SYMBOL
141 ;
142 ; Load the value of the named static data word.
143 ;
144 ; Takes: targetReg - the register, other than r0, to load
145 ; symbolName - the name of the symbol
146 ; LOCAL_SYMBOL - symbol name used as-is
147 ; EXTERNAL_SYMBOL - symbol name gets nonlazy treatment
148 ;
149 ; Eats: r0 and targetReg
150 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
151
152 ; Values to specify whether the symbols is plain or nonlazy
153 LOCAL_SYMBOL = 0
154 EXTERNAL_SYMBOL = 1
155
156 .macro LOAD_STATIC_WORD
157
158 #if defined(__DYNAMIC__)
159 mflr r0
160 bl 1f
161 1: mflr $0
162 mtlr r0
163 .if $2 == EXTERNAL_SYMBOL
164 addis $0,$0,ha16(L$1-1b)
165 lwz $0,lo16(L$1-1b)($0)
166 lwz $0,0($0)
167 .elseif $2 == LOCAL_SYMBOL
168 addis $0,$0,ha16($1-1b)
169 lwz $0,lo16($1-1b)($0)
170 .else
171 !!! Unknown symbol type !!!
172 .endif
173 #else
174 lis $0,ha16($1)
175 lwz $0,lo16($1)($0)
176 #endif
177
178 .endmacro
179
180 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
181 ;
182 ; LEA_STATIC_DATA targetReg, symbolName, LOCAL_SYMBOL | EXTERNAL_SYMBOL
183 ;
184 ; Load the address of the named static data.
185 ;
186 ; Takes: targetReg - the register, other than r0, to load
187 ; symbolName - the name of the symbol
188 ; LOCAL_SYMBOL - symbol is local to this module
189 ; EXTERNAL_SYMBOL - symbol is imported from another module
190 ;
191 ; Eats: r0 and targetReg
192 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
193
194 .macro LEA_STATIC_DATA
195 #if defined(__DYNAMIC__)
196 mflr r0
197 bl 1f
198 1: mflr $0
199 mtlr r0
200 .if $2 == EXTERNAL_SYMBOL
201 addis $0,$0,ha16(L$1-1b)
202 lwz $0,lo16(L$1-1b)($0)
203 .elseif $2 == LOCAL_SYMBOL
204 addis $0,$0,ha16($1-1b)
205 addi $0,$0,lo16($1-1b)
206 .else
207 !!! Unknown symbol type !!!
208 .endif
209 #else
210 lis $0,hi16($1)
211 ori $0,$0,lo16($1)
212 #endif
213
214 .endmacro
215
216 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
217 ;
218 ; ENTRY functionName
219 ;
220 ; Assembly directives to begin an exported function.
221 ;
222 ; Takes: functionName - name of the exported function
223 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
224
225 .macro ENTRY
226 .text
227 .align 2
228 .globl $0
229 $0:
230 .endmacro
231
232 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
233 ;
234 ; END_ENTRY functionName
235 ;
236 ; Assembly directives to end an exported function. Just a placeholder,
237 ; a close-parenthesis for ENTRY, until it is needed for something.
238 ;
239 ; Takes: functionName - name of the exported function
240 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
241
242 .macro END_ENTRY
243 .endmacro
244
245 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
246 ;
247 ; PLOCK scratchReg, lockName
248 ;
249 ; Acquire named spinlock.
250 ;
251 ; Takes: scratchReg - a register, other than r0, that can be mangled
252 ; lockName - the name of a static, aligned, 32-bit lock word
253 ;
254 ; Eats: r0 and scratchReg
255 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
256
257 .macro PLOCK
258 LEA_STATIC_DATA $0, $1, EXTERNAL_SYMBOL
259 b .+16 ; jump into loop at the reserving check
260 lwz r0,0($0) ; check with fast, less intrusive lwz versus lwarx
261 cmplwi r0,0 ; lock held?
262 bne .-8 ; if so, spin until it appears unlocked
263 lwarx r0,0,$0 ; get lock value, acquire memory reservation
264 cmplwi r0,0 ; lock held?
265 bne .-20 ; if locked, go spin waiting for unlock
266 li r0,1 ; get value that means locked
267 sync ; PPC errata #7: Avoid address comparison qualification failure
268 stwcx. r0,0,$0 ; store it iff reservation still holds
269 bne- .-20 ; if reservation was lost, go re-reserve
270 isync ; discard effects of prefetched instructions
271 .endmacro
272
273 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
274 ;
275 ; PUNLOCK scratchReg, lockName
276 ;
277 ; Release named spinlock.
278 ;
279 ; Takes: scratchReg - a register, other than r0, that can be mangled
280 ; lockName - the name of a static, aligned, 32-bit lock word
281 ;
282 ; Eats: r0 and scratchReg
283 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
284
285 .macro PUNLOCK
286 sync ; force out changes before unlocking
287 LEA_STATIC_DATA $0, $1, EXTERNAL_SYMBOL
288 li r0,0 ; get value meaning "unlocked"
289 stw r0,0($0) ; unlock the lock
290 .endmacro
291
292
293 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
294 ;
295 ; CacheLookup WORD_RETURN | STRUCT_RETURN, MSG_SEND | MSG_SENDSUPER, cacheMissLabel, FEW_ARGS | MANY_ARGS
296 ;
297 ; Locate the implementation for a selector in a class method cache.
298 ;
299 ; Takes: WORD_RETURN (r3 is first parameter)
300 ; STRUCT_RETURN (r3 is structure return address, r4 is first parameter)
301 ; MSG_SEND (first parameter is receiver)
302 ; MSG_SENDSUPER (first parameter is address of objc_super structure)
303 ;
304 ; cacheMissLabel = label to branch to iff method is not cached
305 ;
306 ; Eats: r0, r11, r12
307 ; On exit: (found) imp in ctr register
308 ; (not found) jumps to cacheMissLabel
309 ;
310 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
311
312 ; Values to specify to method lookup macros whether the return type of
313 ; the method is an integer or structure.
314 WORD_RETURN = 0
315 STRUCT_RETURN = 1
316
317 ; Values to specify to method lookup macros whether the return type of
318 ; the method is an integer or structure.
319 MSG_SEND = 0
320 MSG_SENDSUPER = 1
321
322 ; Values to specify to method lookup macros whether this is a "few args" call or not
323 ; (number of args < 5 , including self and _cmd)
324 FEW_ARGS = 0
325 MANY_ARGS = 1
326
327 .macro CacheLookup
328
329 #if defined(OBJC_INSTRUMENTED)
330 ; when instrumented, we use r6 and r7
331 stw r6,36(r1) ; save r6 for use as cache pointer
332 stw r7,40(r1) ; save r7 for use as probe count
333 li r7,0 ; no probes so far!
334 #endif
335
336 stw r8,44(r1) ; save r8
337 .if $3 == MANY_ARGS
338 stw r9,48(r1) ; save r9 and r10
339 stw r10,52(r1) ;
340 .endif
341
342 ; locate the cache
343 .if $0 == WORD_RETURN ; WORD_RETURN
344
345 .if $1 == MSG_SEND ; MSG_SEND
346 lwz r12,isa(r3) ; class = receiver->isa
347 .else ; MSG_SENDSUPER
348 lwz r12,class(r3) ; class = super->class
349 .endif
350
351 .else
352 ; STRUCT_RETURN
353 .if $1 == MSG_SEND ; MSG_SEND
354 lwz r12,isa(r4) ; class = receiver->isa
355 .else ; MSG_SENDSUPER
356 lwz r12,class(r4) ; class = super->class
357 .endif
358
359 .endif
360
361 lwz r12,cache(r12) ; cache = class->cache
362 #if defined(OBJC_INSTRUMENTED)
363 mr r6,r12 ; save cache pointer
364 #endif
365 lwz r11,mask(r12) ; mask = cache->mask
366 addi r9,r12,buckets ; buckets = cache->buckets
367 .if $0 == WORD_RETURN ; WORD_RETURN
368 and r12,r4,r11 ; index = selector & mask
369 .else ; STRUCT_RETURN
370 and r12,r5,r11 ; index = selector & mask
371 .endif
372
373 #if defined(OBJC_INSTRUMENTED)
374 b LLoop_$0_$1_$2
375
376 LMiss_$0_$1_$2:
377 ; r6 = cache, r7 = probeCount
378 lwz r9,mask(r6) ; entryCount = mask + 1
379 addi r9,r9,1 ;
380 slwi r9,r9,2 ; tableSize = entryCount * sizeof(entry)
381 addi r9,r9,buckets ; offset = buckets + tableSize
382 add r8,r6,r9 ; cacheData = &cache->buckets[mask+1]
383 lwz r9,missCount(r8) ; cacheData->missCount += 1
384 addi r9,r9,1 ;
385 stw r9,missCount(r8) ;
386 lwz r9,missProbes(r8) ; cacheData->missProbes += probeCount
387 add r9,r9,r7 ;
388 stw r9,missProbes(r8) ;
389 lwz r9,maxMissProbes(r8) ; if (probeCount > cacheData->maxMissProbes)
390 cmplw r7,r9 ; maxMissProbes = probeCount
391 ble .+8 ;
392 stw r7,maxMissProbes(r8) ;
393
394 lwz r6,36(r1) ; restore r6
395 lwz r7,40(r1) ; restore r7
396
397 b $2 ; goto cacheMissLabel
398 #endif
399
400 ; search the cache
401 LLoop_$0_$1_$2:
402 #if defined(OBJC_INSTRUMENTED)
403 addi r7,r7,1 ; probeCount += 1
404 #endif
405 slwi r0,r12,2 ; convert word index into byte count
406 lwzx r10,r9,r0 ; method = cache->buckets[index]
407 cmplwi r10,0 ; if (method == NULL)
408 #if defined(OBJC_INSTRUMENTED)
409 beq LMiss_$0_$1_$2
410 #else
411 beq $2 ; goto cacheMissLabel
412 #endif
413
414 addi r12,r12,1 ; index += 1
415 lwz r8,method_name(r10) ; name = method->method_name
416 and r12,r12,r11 ; index &= mask
417 lwz r10,method_imp(r10) ; imp = method->method_imp
418 .if $0 == WORD_RETURN ; WORD_RETURN
419 cmplw r8,r4 ; if (name != selector)
420 .else ; STRUCT_RETURN
421 cmplw r8,r5 ; if (name != selector)
422 .endif
423 bne LLoop_$0_$1_$2 ; goto loop
424
425 ; cache hit, r10 == method implementation address
426 mr r12,r10 ; copy implementation to r12
427 mtctr r10 ; ctr = imp
428
429 #if defined(OBJC_INSTRUMENTED)
430 ; r6 = cache, r7 = probeCount
431 lwz r9,mask(r6) ; entryCount = mask + 1
432 addi r9,r9,1 ;
433 slwi r9,r9,2 ; tableSize = entryCount * sizeof(entry)
434 addi r9,r9,buckets ; offset = buckets + tableSize
435 add r8,r6,r9 ; cacheData = &cache->buckets[mask+1]
436 lwz r9,hitCount(r8) ; cache->hitCount += 1
437 addi r9,r9,1 ;
438 stw r9,hitCount(r8) ;
439 lwz r9,hitProbes(r8) ; cache->hitProbes += probeCount
440 add r9,r9,r7 ;
441 stw r9,hitProbes(r8) ;
442 lwz r9,maxHitProbes(r8) ; if (probeCount > cache->maxMissProbes)
443 cmplw r7,r9 ;maxMissProbes = probeCount
444 ble .+8 ;
445 stw r7,maxHitProbes(r8) ;
446
447 lwz r6,36(r1) ; restore r6
448 lwz r7,40(r1) ; restore r7
449 #endif
450
451 lwz r8,44(r1) ; restore r8
452 .if $3 == MANY_ARGS
453 lwz r9,48(r1) ; restore r9 and r10
454 lwz r10,52(r1) ;
455 .endif
456
457 .endmacro
458
459
460 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
461 ;
462 ;
463 ; MethodTableLookup WORD_RETURN | STRUCT_RETURN, MSG_SEND | MSG_SENDSUPER, FEW_ARGS | MANY_ARGS
464 ;
465 ; Takes: WORD_RETURN (r3 is first parameter)
466 ; STRUCT_RETURN (r3 is structure return address, r4 is first parameter)
467 ; MSG_SEND (first parameter is receiver)
468 ; MSG_SENDSUPER (first parameter is address of objc_super structure)
469 ;
470 ; Eats: r0, r11, r12
471 ; On exit: restores registers r8 and possibly, r9 and r10, saved by CacheLookup
472 ; imp in ctr
473 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
474
475 HAVE_CALL_EXTERN_lookupMethodAndLoadCache = 0
476
477 .macro MethodTableLookup
478 stw r3, 24(r1) ; save arguments
479 stw r4, 28(r1) ;
480 stw r5, 32(r1) ;
481 stw r6, 36(r1) ;
482 stw r7, 40(r1) ;
483 ; r8 and possibly, r9 and r10, were saved by CacheLookup
484
485 mflr r0 ; save lr
486 stw r0,8(r1) ;
487
488 #if defined(KERNEL)
489 stwu r1,-64(r1) ; grow the stack
490 #else
491
492 .if $2 == MANY_ARGS
493 stfd f13, -8(r1) ; save the fp parameter registers
494 stfd f12, -16(r1) ;
495 stfd f11, -24(r1) ;
496 stfd f10, -32(r1) ;
497 stfd f9, -40(r1) ;
498 stfd f8, -48(r1) ;
499 stfd f7, -56(r1) ;
500 stfd f6, -64(r1) ;
501 stfd f5, -72(r1) ;
502 .endif
503 stfd f4, -80(r1) ;
504 stfd f3, -88(r1) ;
505 stfd f2, -96(r1) ;
506 stfd f1, -104(r1) ;
507
508 stwu r1,-56-(13*8)(r1) ; grow the stack
509 #endif
510
511 ; Pass parameters to __class_lookupMethodAndLoadCache. First parameter is
512 ; the class pointer. Second parameter is the selector. Where they come
513 ; from depends on who called us. In the int return case, the selector is
514 ; already in r4.
515 .if $0 == WORD_RETURN ; WORD_RETURN
516 .if $1 == MSG_SEND ; MSG_SEND
517 lwz r3,isa(r3) ; class = receiver->isa
518 .else ; MSG_SENDSUPER
519 lwz r3,class(r3) ; class = super->class
520 .endif
521
522 .else ; STRUCT_RETURN
523 .if $1 == MSG_SEND ; MSG_SEND
524 lwz r3,isa(r4) ; class = receiver->isa
525 .else ; MSG_SENDSUPER
526 lwz r3,class(r4) ; class = super->class
527 .endif
528 mr r4,r5 ; selector = selector
529 .endif
530
531 .if HAVE_CALL_EXTERN_lookupMethodAndLoadCache == 0
532 HAVE_CALL_EXTERN_lookupMethodAndLoadCache = 1
533 CALL_EXTERN(__class_lookupMethodAndLoadCache)
534 .else
535 CALL_EXTERN_AGAIN(__class_lookupMethodAndLoadCache)
536 .endif
537
538 mr r12,r3 ; copy implementation to r12
539 mtctr r3 ; copy imp to ctr
540 lwz r1,0(r1) ; restore the stack pointer
541 lwz r0,8(r1) ;
542 mtlr r0 ; restore return pc
543
544 #if !defined(KERNEL)
545
546 .if $2 == MANY_ARGS
547 lfd f13, -8(r1) ; restore fp parameter registers
548 lfd f12, -16(r1) ;
549 lfd f11, -24(r1) ;
550 lfd f10, -32(r1) ;
551 lfd f9, -40(r1) ;
552 lfd f8, -48(r1) ;
553 lfd f7, -56(r1) ;
554 lfd f6, -64(r1) ;
555 lfd f5, -72(r1) ;
556 .endif
557 lfd f4, -80(r1) ;
558 lfd f3, -88(r1) ;
559 lfd f2, -96(r1) ;
560 lfd f1, -104(r1) ;
561 #endif
562
563 lwz r3, 24(r1) ; restore parameter registers
564 lwz r4, 28(r1) ;
565 lwz r5, 32(r1) ;
566 lwz r6, 36(r1) ;
567 lwz r7, 40(r1) ;
568
569 lwz r8, 44(r1) ; restore leftovers from CacheLookup...
570 .if $2 == MANY_ARGS
571 lwz r9, 48(r1) ;
572 lwz r10,52(r1) ;
573 .endif
574
575 .endmacro
576
577
578 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
579 ;
580 ; CALL_MCOUNT
581 ;
582 ; Macro to call mcount function in profiled builds.
583 ;
584 ; NOTE: Makes sure to save/restore r11 and r12, even though they
585 ; are not defined to be volatile, because they are used during
586 ; forwarding.
587 ;
588 ; Takes: lr Callers return PC
589 ;
590 ; Eats: r0
591 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
592
593 HAVE_CALL_EXTERN_mcount = 0
594
595 .macro CALL_MCOUNT
596 #if defined(PROFILE)
597 mflr r0 ; save return pc
598 stw r0,8(r1) ;
599
600 stwu r1,-208(r1) ; push aligned areas, set stack link
601
602 stw r3, 56(r1) ; save all volatile registers
603 stw r4, 60(r1) ;
604 stw r5, 64(r1) ;
605 stw r6, 68(r1) ;
606 stw r7, 72(r1) ;
607 stw r8, 76(r1) ;
608 stw r9, 80(r1) ;
609 stw r10,84(r1) ;
610 stw r11,88(r1) ; save r11 and r12, too
611 stw r12,92(r1) ;
612
613 stfd f1, 96(r1) ;
614 stfd f2, 104(r1) ;
615 stfd f3, 112(r1) ;
616 stfd f4, 120(r1) ;
617 stfd f5, 128(r1) ;
618 stfd f6, 136(r1) ;
619 stfd f7, 144(r1) ;
620 stfd f8, 152(r1) ;
621 stfd f9, 160(r1) ;
622 stfd f10, 168(r1) ;
623 stfd f11, 176(r1) ;
624 stfd f12, 184(r1) ;
625 stfd f13, 192(r1) ;
626
627 mflr r3 ; pass our callers address
628 .if HAVE_CALL_EXTERN_mcount == 0
629 HAVE_CALL_EXTERN_mcount = 1
630 CALL_EXTERN(mcount)
631 .else
632 CALL_EXTERN_AGAIN(mcount)
633 .endif
634
635 lwz r3, 56(r1) ; restore all volatile registers
636 lwz r4, 60(r1) ;
637 lwz r5, 64(r1) ;
638 lwz r6, 68(r1) ;
639 lwz r7, 72(r1) ;
640 lwz r8, 76(r1) ;
641 lwz r9, 80(r1) ;
642 lwz r10,84(r1) ;
643 lwz r11,88(r1) ; restore r11 and r12, too
644 lwz r12,92(r1) ;
645
646 lfd f1, 96(r1) ;
647 lfd f2, 104(r1) ;
648 lfd f3, 112(r1) ;
649 lfd f4, 120(r1) ;
650 lfd f5, 128(r1) ;
651 lfd f6, 136(r1) ;
652 lfd f7, 144(r1) ;
653 lfd f8, 152(r1) ;
654 lfd f9, 160(r1) ;
655 lfd f10, 168(r1) ;
656 lfd f11, 176(r1) ;
657 lfd f12, 184(r1) ;
658 lfd f13, 192(r1) ;
659
660 lwz r1,0(r1) ; restore the stack pointer
661 lwz r0,8(r1) ;
662 mtlr r0 ; restore return pc
663 #endif
664 .endmacro
665
666 /********************************************************************
667 * id objc_msgSend(id self,
668 * SEL op,
669 * ...);
670 *
671 * On entry: r3 is the message receiver,
672 * r4 is the selector
673 ********************************************************************/
674
675 #if defined(__DYNAMIC__)
676 /* Allocate reference to external static data */
677 .non_lazy_symbol_pointer
678 L__objc_msgNil:
679 .indirect_symbol __objc_msgNil
680 .long 0
681 .text
682 #endif
683
684 ENTRY _objc_msgSend
685 ; do profiling when enabled
686 CALL_MCOUNT
687
688 ; check whether receiver is nil
689 cmplwi r3,0 ; receiver nil?
690 beq LMsgSendNilSelf ; if so, call handler or return nil
691
692 #if !defined(OBJC_COLLECTING_CACHE)
693 ; check whether context is multithreaded
694 lis r11,ha16(__objc_multithread_mask)
695 lwz r11,lo16(__objc_multithread_mask)(r11)
696 cmplwi r11,0 ; objc_multithread_mask zero?
697 beq LMsgSendMT ; branch to the locking case
698 #endif
699
700 ; single threaded and receiver is non-nil: search the cache
701 CacheLookup WORD_RETURN, MSG_SEND, LMsgSendCacheMiss, MANY_ARGS
702 li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
703 bctr ; goto *imp;
704
705 ; cache miss: go search the method lists
706 LMsgSendCacheMiss:
707 MethodTableLookup WORD_RETURN, MSG_SEND, MANY_ARGS
708 li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
709 bctr ; goto *imp;
710
711 #if !defined(OBJC_COLLECTING_CACHE)
712 ; multithreaded: hold _messageLock while accessing cache
713 LMsgSendMT:
714 PLOCK r11, _messageLock
715 CacheLookup WORD_RETURN, MSG_SEND, LMsgSendMTCacheMiss, MANY_ARGS
716 PUNLOCK r11, _messageLock
717 li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
718 bctr ; goto *imp;
719
720 ; cache miss: go search the method lists
721 LMsgSendMTCacheMiss:
722 MethodTableLookup WORD_RETURN, MSG_SEND, MANY_ARGS
723 PUNLOCK r11, _messageLock
724 li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
725 bctr ; goto *imp;
726 #endif
727
728 ; message sent to nil object call: optional handler and return nil
729 LMsgSendNilSelf:
730 LOAD_STATIC_WORD r11, __objc_msgNil, EXTERNAL_SYMBOL
731 cmplwi r11,0 ; handler nil?
732 beqlr ; if no handler, return nil
733
734 mflr r0 ; save return pc
735 stw r0,8(r1) ;
736 subi r1,r1,64 ; allocate linkage area
737 mtctr r11 ;
738 bctrl ; call handler
739 addi r1,r1,64 ; deallocate linkage area
740 lwz r0,8(r1) ; restore return pc
741 mtlr r0 ;
742
743 li r3,0 ; re-zero return value, in case handler changed it
744 blr ; return to caller
745
746 LMsgSendExit:
747 END_ENTRY _objc_msgSend
748
749
750 /********************************************************************
751 * struct_type objc_msgSend_stret(id self,
752 * SEL op,
753 * ...);
754 *
755 * objc_msgSend_stret is the struct-return form of msgSend.
756 * The ABI calls for r3 to be used as the address of the structure
757 * being returned, with the parameters in the succeeding registers.
758 *
759 * On entry: r3 is the address where the structure is returned,
760 * r4 is the message receiver,
761 * r5 is the selector
762 ********************************************************************/
763
764 ENTRY _objc_msgSend_stret
765 ; do profiling when enabled
766 CALL_MCOUNT
767
768 ; check whether receiver is nil
769 cmplwi r4,0 ; receiver nil?
770 beq LMsgSendStretNilSelf ; if so, call handler or just return
771
772 #if !defined(OBJC_COLLECTING_CACHE)
773 ; check whether context is multithreaded
774 lis r11,ha16(__objc_multithread_mask)
775 lwz r11,lo16(__objc_multithread_mask)(r11)
776 cmplwi r11,0 ; objc_multithread_mask zero?
777 beq LMsgSendStretMT ; branch to the locking case
778 #endif
779
780 ; single threaded and receiver is non-nil: search the cache
781 CacheLookup STRUCT_RETURN, MSG_SEND, LMsgSendStretCacheMiss, MANY_ARGS
782 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
783 bctr ; goto *imp;
784
785 ; cache miss: go search the method lists
786 LMsgSendStretCacheMiss:
787 MethodTableLookup STRUCT_RETURN, MSG_SEND, MANY_ARGS
788 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
789 bctr ; goto *imp;
790
791 #if !defined(OBJC_COLLECTING_CACHE)
792 ; multithreaded: hold _messageLock while accessing cache
793 LMsgSendStretMT:
794 PLOCK r11, _messageLock
795 CacheLookup STRUCT_RETURN, MSG_SEND, LMsgSendStretMTCacheMiss, MANY_ARGS
796 PUNLOCK r11, _messageLock
797 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
798 bctr ; goto *imp;
799
800 ; cache miss: go search the method lists
801 LMsgSendStretMTCacheMiss:
802 MethodTableLookup STRUCT_RETURN, MSG_SEND, MANY_ARGS
803 PUNLOCK r11, _messageLock
804 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
805 bctr ; goto *imp;
806 #endif
807
808 ; message sent to nil object call optional handler and return nil
809 LMsgSendStretNilSelf:
810 LOAD_STATIC_WORD r11, __objc_msgNil, EXTERNAL_SYMBOL
811 cmplwi r11,0 ; handler nil?
812 beqlr ; if no handler, return
813
814 mflr r0 ; save return pc
815 stw r0,8(r1) ;
816 subi r1,r1,64 ; allocate linkage area
817 mr r3,r4 ; move self to r3
818 mr r4,r5 ; move SEL to r4
819 mtctr r11 ;
820 bctrl ; call handler
821 addi r1,r1,64 ; deallocate linkage area
822 lwz r0,8(r1) ; restore return pc
823 mtlr r0 ;
824
825 blr ; return to caller
826
827 LMsgSendStretExit:
828 END_ENTRY _objc_msgSend_stret
829
830
831 /********************************************************************
832 * id objc_msgSendSuper(struct objc_super *super,
833 * SEL op,
834 * ...);
835 *
836 * struct objc_super {
837 * id receiver;
838 * Class class;
839 * };
840 ********************************************************************/
841
842 ENTRY _objc_msgSendSuper
843 ; do profiling when enabled
844 CALL_MCOUNT
845
846 #if !defined(OBJC_COLLECTING_CACHE)
847 ; check whether context is multithreaded
848 lis r11,ha16(__objc_multithread_mask)
849 lwz r11,lo16(__objc_multithread_mask)(r11)
850 cmplwi r11,0 ; objc_multithread_mask zero?
851 beq LMsgSendSuperMT ; branch to the locking case
852 #endif
853
854 ; single threaded: search the cache
855 CacheLookup WORD_RETURN, MSG_SENDSUPER, LMsgSendSuperCacheMiss, MANY_ARGS
856 lwz r3,receiver(r3) ; receiver is the first arg
857 li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
858 bctr ; goto *imp;
859
860 ; cache miss: go search the method lists
861 LMsgSendSuperCacheMiss:
862 MethodTableLookup WORD_RETURN, MSG_SENDSUPER, MANY_ARGS
863 lwz r3,receiver(r3) ; receiver is the first arg
864 li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
865 bctr ; goto *imp;
866
867 #if !defined(OBJC_COLLECTING_CACHE)
868 ; multithreaded: hold _messageLock while accessing cache
869 LMsgSendSuperMT:
870 PLOCK r11, _messageLock
871 CacheLookup WORD_RETURN, MSG_SENDSUPER, LMsgSendSuperMTCacheMiss, MANY_ARGS
872 PUNLOCK r11, _messageLock
873 lwz r3,receiver(r3) ; receiver is the first arg
874 li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
875 bctr ; goto *imp;
876
877 ; cache miss: go search the method lists
878 LMsgSendSuperMTCacheMiss:
879 MethodTableLookup WORD_RETURN, MSG_SENDSUPER, MANY_ARGS
880 PUNLOCK r11, _messageLock
881 lwz r3,receiver(r3) ; receiver is the first arg
882 li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
883 bctr ; goto *imp;
884 #endif
885
886 LMsgSendSuperExit:
887 END_ENTRY _objc_msgSendSuper
888
889
890 /********************************************************************
891 * struct_type objc_msgSendSuper_stret(objc_super *super,
892 * SEL op,
893 * ...);
894 *
895 * struct objc_super {
896 * id receiver;
897 * Class class;
898 * };
899 *
900 *
901 * objc_msgSendSuper_stret is the struct-return form of msgSendSuper.
902 * The ABI calls for r3 to be used as the address of the structure
903 * being returned, with the parameters in the succeeding registers.
904 *
905 * On entry: r3 is the address to which to copy the returned structure,
906 * r4 is the address of the objc_super structure,
907 * r5 is the selector
908 ********************************************************************/
909
910 ENTRY _objc_msgSendSuper_stret
911 ; do profiling when enabled
912 CALL_MCOUNT
913
914 #if !defined(OBJC_COLLECTING_CACHE)
915 ; check whether context is multithreaded
916 lis r11,ha16(__objc_multithread_mask)
917 lwz r11,lo16(__objc_multithread_mask)(r11)
918 cmplwi r11,0 ; objc_multithread_mask zero?
919 beq LMsgSendSuperStretMT ; branch to the locking case
920 #endif
921
922 ; single threaded: search the cache
923 CacheLookup STRUCT_RETURN, MSG_SENDSUPER, LMsgSendSuperStretCacheMiss, MANY_ARGS
924 lwz r4,receiver(r4) ; receiver is the first arg
925 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
926 bctr ; goto *imp;
927
928 ; cache miss: go search the method lists
929 LMsgSendSuperStretCacheMiss:
930 MethodTableLookup STRUCT_RETURN, MSG_SENDSUPER, MANY_ARGS
931 lwz r4,receiver(r4) ; receiver is the first arg
932 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
933 bctr ; goto *imp;
934
935 #if !defined(OBJC_COLLECTING_CACHE)
936 ; multithreaded: hold _messageLock while accessing cache
937 LMsgSendSuperStretMT:
938 PLOCK r11, _messageLock
939 CacheLookup STRUCT_RETURN, MSG_SENDSUPER, LMsgSendSuperStretMTCacheMiss, MANY_ARGS
940 PUNLOCK r11, _messageLock
941 lwz r4,receiver(r4) ; receiver is the first arg
942 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
943 bctr ; goto *imp;
944
945 ; cache miss: go search the method lists
946 LMsgSendSuperStretMTCacheMiss:
947 MethodTableLookup STRUCT_RETURN, MSG_SENDSUPER, MANY_ARGS
948 PUNLOCK r11, _messageLock
949 lwz r4,receiver(r4) ; receiver is the first arg
950 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
951 bctr ; goto *imp;
952 #endif
953
954 LMsgSendSuperStretExit:
955 END_ENTRY _objc_msgSendSuper_stret
956
957
958 /********************************************************************
959 *
960 * Out-of-band parameter r11 indicates whether it was objc_msgSend or
961 * objc_msgSend_stret that triggered the message forwarding. The
962 *
963 * Iff r11 == kFwdMsgSend, it is the word-return (objc_msgSend) case,
964 * and the interface is:
965 *
966 * id _objc_msgForward(id self,
967 * SEL sel,
968 * ...);
969 *
970 * Iff r11 == kFwdMsgSendStret, it is the structure-return
971 * (objc_msgSend_stret) case, and the interface is:
972 *
973 * struct_type _objc_msgForward(id self,
974 * SEL sel,
975 * ...);
976 *
977 * There are numerous reasons why it is better to have one
978 * _objc_msgForward, rather than adding _objc_msgForward_stret.
979 * The best one is that _objc_msgForward is the method that
980 * gets cached when respondsToMethod returns false, and it
981 * wouldnt know which one to use.
982 *
983 * Sends the message to a method having the signature
984 *
985 * - forward:(SEL)sel :(marg_list)args;
986 *
987 * But the marg_list is prepended with the 13 double precision
988 * floating point registers that could be used as parameters into
989 * the method (fortunately, the same registers are used for either
990 * single or double precision floats). These registers are layed
991 * down by _objc_msgForward, and picked up by _objc_msgSendv. So
992 * the "marg_list" is actually:
993 *
994 * typedef struct objc_sendv_margs {
995 * double floatingPointArgs[13];
996 * int linkageArea[6];
997 * int registerArgs[8];
998 * int stackArgs[variable];
999 * };
1000 *
1001 ********************************************************************/
1002
1003 ; Location LFwdStr contains the string "forward::"
1004 ; Location LFwdSel contains a pointer to LFwdStr, that can be changed
1005 ; to point to another forward:: string for selector uniquing
1006 ; purposes. ALWAYS dereference LFwdSel to get to "forward::" !!
1007 .objc_meth_var_names
1008 .align 1
1009 LFwdStr: .ascii "forward::\0"
1010
1011 .objc_message_refs
1012 .align 2
1013 LFwdSel:.long LFwdStr
1014
1015 .cstring
1016 .align 1
1017 LUnkSelStr: .ascii "Does not recognize selector %s\0"
1018
1019 ENTRY __objc_msgForward
1020 ; do profiling when enabled
1021 CALL_MCOUNT
1022
1023 #if defined(KERNEL)
1024 trap ; _objc_msgForward is not for the kernel
1025 #else
1026 LOAD_STATIC_WORD r12, LFwdSel, LOCAL_SYMBOL ; get uniqued selector for "forward::"
1027 cmplwi r11,kFwdMsgSend ; via objc_msgSend or objc_msgSend_stret?
1028 bne LMsgForwardStretSel ; branch for objc_msgSend_stret
1029 cmplw r12,r4 ; if (sel == @selector (forward::))
1030 b LMsgForwardSelCmpDone ; check the result in common code
1031 LMsgForwardStretSel:
1032 cmplw r12,r5 ; if (sel == @selector (forward::))
1033 LMsgForwardSelCmpDone:
1034 beq LMsgForwardError ; goto error
1035
1036 mflr r0
1037 stw r0,8(r1) ; save lr
1038
1039 stw r3, 24(r1) ; put register arguments on stack for forwarding
1040 stw r4, 28(r1) ; (stack based args already follow this area)
1041 stw r5, 32(r1) ;
1042 stw r6, 36(r1) ;
1043 stw r7, 40(r1) ;
1044 stw r8, 44(r1)
1045 stw r9, 48(r1)
1046 stw r10,52(r1)
1047
1048 stfd f13, -8(r1) ; prepend floating point registers to marg_list
1049 stfd f12, -16(r1) ;
1050 stfd f11, -24(r1) ;
1051 stfd f10, -32(r1) ;
1052 stfd f9, -40(r1) ;
1053 stfd f8, -48(r1) ;
1054 stfd f7, -56(r1) ;
1055 stfd f6, -64(r1) ;
1056 stfd f5, -72(r1) ;
1057 stfd f4, -80(r1) ;
1058 stfd f3, -88(r1) ;
1059 stfd f2, -96(r1) ;
1060 stfd f1, -104(r1) ;
1061
1062 cmplwi r11,kFwdMsgSend ; via objc_msgSend or objc_msgSend_stret?
1063 bne LMsgForwardStretParams ; branch for objc_msgSend_stret
1064 ; first arg (r3) remains self
1065 mr r5,r4 ; third arg is previous selector
1066 b LMsgForwardParamsDone
1067 LMsgForwardStretParams:
1068 mr r3,r4 ; first arg is self
1069 ; third arg (r5) remains previous selector
1070 LMsgForwardParamsDone:
1071 mr r4,r12 ; second arg is "forward::"
1072 subi r6,r1,13*8 ; fourth arg is &objc_sendv_margs
1073
1074 stwu r1,-56-(13*8)(r1) ; push aligned linkage and parameter areas, set stack link
1075 bl _objc_msgSend ; [self forward:sel :objc_sendv_margs]
1076 addi r1,r1,56+13*8 ; deallocate linkage and parameters areas
1077
1078 lwz r0,8(r1) ; restore lr
1079 mtlr r0 ;
1080 blr ;
1081
1082 ; call error handler with unrecognized selector message
1083 LMsgForwardError:
1084 cmplwi r11,kFwdMsgSendStret ; via objc_msgSend or objc_msgSend_stret?
1085 bne LMsgForwardErrorParamsOK; branch for objc_msgSend
1086 mr r3,r4 ; first arg is self
1087 LMsgForwardErrorParamsOK:
1088 LEA_STATIC_DATA r4, LUnkSelStr, LOCAL_SYMBOL
1089 mr r5,r12 ; third arg is "forward::"
1090 CALL_EXTERN(___objc_error) ; never returns
1091 trap ; ___objc_error should never return
1092 #endif
1093
1094 END_ENTRY __objc_msgForward
1095
1096
1097 /********************************************************************
1098 * id objc_msgSendv(id self,
1099 * SEL op,
1100 * unsigned arg_size,
1101 * marg_list arg_frame);
1102 *
1103 * But the marg_list is prepended with the 13 double precision
1104 * floating point registers that could be used as parameters into
1105 * the method (fortunately, the same registers are used for either
1106 * single or double precision floats). These registers are layed
1107 * down by _objc_msgForward, and picked up by _objc_msgSendv. So
1108 * the "marg_list" is actually:
1109 *
1110 * typedef struct objc_sendv_margs {
1111 * double floatingPointArgs[13];
1112 * int linkageArea[6];
1113 * int registerArgs[8];
1114 * int stackArgs[variable];
1115 * };
1116 *
1117 * arg_size is the number of bytes of parameters in registerArgs and
1118 * stackArgs combined (i.e. it is method_getSizeOfArguments(method)).
1119 * Specifically, it is NOT the overall arg_frame size, because that
1120 * would include the floatingPointArgs and linkageArea, which are
1121 * PowerPC-specific. This is consistent with the other architectures.
1122 ********************************************************************/
1123
1124 ENTRY _objc_msgSendv
1125
1126 #if defined(KERNEL)
1127 trap ; _objc_msgSendv is not for the kernel
1128 #else
1129 ; do profiling when enabled
1130 CALL_MCOUNT
1131
1132 mflr r0
1133 stw r0,8(r1) ; save lr
1134
1135 cmplwi r5,32 ; check parameter size against minimum
1136 ble+ LMsgSendvMinFrame ; is less than minimum, go use minimum
1137 mr r12,r1 ; remember current stack pointer
1138 sub r11,r1,r5 ; push parameter area
1139 rlwinm r1,r11,0,0,27 ; align stack pointer to 16 byte boundary
1140 stwu r12,-32(r1) ; push aligned linkage area, set stack link
1141 b LMsgSendvHaveFrame
1142
1143 LMsgSendvMinFrame:
1144 stwu r1,-64(r1) ; push aligned linkage and parameter areas, set stack link
1145
1146 LMsgSendvHaveFrame:
1147 ; restore floating point register parameters from marg_list
1148 lfd f13,96(r6) ;
1149 lfd f12,88(r6) ;
1150 lfd f11,80(r6) ;
1151 lfd f10,72(r6) ;
1152 lfd f9,64(r6) ;
1153 lfd f8,56(r6) ;
1154 lfd f7,48(r6) ;
1155 lfd f6,40(r6) ;
1156 lfd f5,32(r6) ;
1157 lfd f4,24(r6) ;
1158 lfd f3,16(r6) ;
1159 lfd f2,8(r6) ;
1160 lfd f1,0(r6) ;
1161
1162 ; load the register based arguments from the marg_list
1163 ; the first two parameters are already in r3 and r4, respectively
1164 subi r0,r5,5 ; make word count from byte count rounded up to multiple of 4...
1165 srwi. r0,r0,2 ; ... and subtracting for params already in r3 and r4
1166 beq LMsgSendvSendIt ; branch if there are no parameters to load
1167 mtctr r0 ; counter = number of remaining words
1168 lwz r5,32+(13*8)(r6) ; load 3rd parameter
1169 bdz LMsgSendvSendIt ; decrement counter, branch if result is zero
1170 addi r11,r6,36+(13*8) ; switch to r11, because we are setting r6
1171 lwz r6,0(r11) ; load 4th parameter
1172 bdz LMsgSendvSendIt ; decrement counter, branch if result is zero
1173 lwz r7,4(r11) ; load 5th parameter
1174 bdz LMsgSendvSendIt ; decrement counter, branch if result is zero
1175 lwz r8,8(r11) ; load 6th parameter
1176 bdz LMsgSendvSendIt ; decrement counter, branch if result is zero
1177 lwz r9,12(r11) ; load 7th parameter
1178 bdz LMsgSendvSendIt ; decrement counter, branch if result is zero
1179 lwzu r10,16(r11) ; load 8th parameter, and update r11
1180 bdz LMsgSendvSendIt ; decrement counter, branch if result is zero
1181
1182 ; copy the stack based arguments from the marg_list
1183 addi r12,r1,24+32-4 ; target = address of stack based parameters
1184 LMsgSendvArgLoop:
1185 lwzu r0,4(r11) ; loop to copy remaining marg_list words to stack
1186 stwu r0,4(r12) ;
1187 bdnz LMsgSendvArgLoop ; decrement counter, branch if still non-zero
1188
1189 LMsgSendvSendIt:
1190 bl _objc_msgSend ; objc_msgSend (self, selector, ...)
1191
1192 lwz r1,0(r1) ; restore stack pointer
1193 lwz r0,8(r1) ; restore lr
1194 mtlr r0 ;
1195 blr ;
1196 #endif
1197
1198 END_ENTRY _objc_msgSendv
1199
1200
1201 /********************************************************************
1202 * struct_type objc_msgSendv_stret(id self,
1203 * SEL op,
1204 * unsigned arg_size,
1205 * marg_list arg_frame);
1206 *
1207 * objc_msgSendv_stret is the struct-return form of msgSendv.
1208 * The ABI calls for r3 to be used as the address of the structure
1209 * being returned, with the parameters in the succeeding registers.
1210 *
1211 * An equally correct way to prototype this routine is:
1212 *
1213 * void objc_msgSendv_stret(void *structStorage,
1214 * id self,
1215 * SEL op,
1216 * unsigned arg_size,
1217 * marg_list arg_frame);
1218 *
1219 * which is useful in, for example, message forwarding where the
1220 * structure-return address needs to be passed in.
1221 *
1222 * The ABI for the two cases are identical.
1223 *
1224 * On entry: r3 is the address in which the returned struct is put,
1225 * r4 is the message receiver,
1226 * r5 is the selector,
1227 * r6 is the size of the marg_list, in bytes,
1228 * r7 is the address of the marg_list
1229 ********************************************************************/
1230
1231 ENTRY _objc_msgSendv_stret
1232
1233 #if defined(KERNEL)
1234 trap ; _objc_msgSendv_stret is not for the kernel
1235 #else
1236 ; do profiling when enabled
1237 CALL_MCOUNT
1238
1239 mflr r0
1240 stw r0,8(r1) ; (save return pc)
1241
1242 cmplwi r6,32 ; check parameter size against minimum
1243 ble+ LMsgSendvStretMinFrame ; is less than minimum, go use minimum
1244 mr r12,r1 ; remember current stack pointer
1245 sub r11,r1,r6 ; push parameter area
1246 rlwinm r1,r11,0,0,27 ; align stack pointer to 16 byte boundary
1247 stwu r12,-32(r1) ; push aligned linkage area, set stack link
1248 b LMsgSendvStretHaveFrame
1249
1250 LMsgSendvStretMinFrame:
1251 stwu r1,-64(r1) ; push aligned linkage and parameter areas, set stack link
1252
1253 LMsgSendvStretHaveFrame:
1254 ; restore floating point register parameters from marg_list
1255 lfd f13,96(r7) ;
1256 lfd f12,88(r7) ;
1257 lfd f11,80(r7) ;
1258 lfd f10,72(r7) ;
1259 lfd f9,64(r7) ;
1260 lfd f8,56(r7) ;
1261 lfd f7,48(r7) ;
1262 lfd f6,40(r7) ;
1263 lfd f5,32(r7) ;
1264 lfd f4,24(r7) ;
1265 lfd f3,16(r7) ;
1266 lfd f2,8(r7) ;
1267 lfd f1,0(r7) ;
1268
1269 ; load the register based arguments from the marg_list
1270 ; the structure return address and the first two parameters
1271 ; are already in r3, r4, and r5, respectively.
1272 ; NOTE: The callers r3 probably, but not necessarily, matches
1273 ; the r3 in the marg_list. That is, the struct-return
1274 ; storage used by the caller could be an intermediate buffer
1275 ; that will end up being copied into the original
1276 ; struct-return buffer (pointed to by the marg_listed r3).
1277 subi r0,r6,5 ; make word count from byte count rounded up to multiple of 4...
1278 srwi. r0,r0,2 ; ... and subtracting for params already in r4 and r5
1279 beq LMsgSendvStretSendIt ; branch if there are no parameters to load
1280 mtctr r0 ; counter = number of remaining words
1281 lwz r6,36+(13*8)(r7) ; load 4th parameter
1282 bdz LMsgSendvStretSendIt ; decrement counter, branch if result is zero
1283 addi r11,r7,40+(13*8) ; switch to r11, because we are setting r7
1284 lwz r7,0(r11) ; load 5th parameter
1285 bdz LMsgSendvStretSendIt ; decrement counter, branch if result is zero
1286 lwz r8,4(r11) ; load 6th parameter
1287 bdz LMsgSendvStretSendIt ; decrement counter, branch if result is zero
1288 lwz r9,8(r11) ; load 7th parameter
1289 bdz LMsgSendvStretSendIt ; decrement counter, branch if result is zero
1290 lwzu r10,12(r11) ; load 8th parameter, and update r11
1291 bdz LMsgSendvStretSendIt ; decrement counter, branch if result is zero
1292
1293 ; copy the stack based arguments from the marg_list
1294 addi r12,r1,24+32-4 ; target = address of stack based parameters
1295 LMsgSendvStretArgLoop:
1296 lwzu r0,4(r11) ; loop to copy remaining marg_list words to stack
1297 stwu r0,4(r12) ;
1298 bdnz LMsgSendvStretArgLoop ; decrement counter, branch if still non-zero
1299
1300 LMsgSendvStretSendIt:
1301 bl _objc_msgSend_stret ; struct_type objc_msgSend_stret (self, selector, ...)
1302
1303 lwz r1,0(r1) ; restore stack pointer
1304 lwz r0,8(r1) ; restore return pc
1305 mtlr r0
1306 blr ; return
1307 #endif
1308
1309 END_ENTRY _objc_msgSendv_stret
1310
1311
1312 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1313 ;
1314 ; **************** THE "FEW" API ****************
1315 ;
1316 ; The "few args" apis; The compiler needs to be updated to generate calls to
1317 ; these functions, rather than to their counterparts, when the number of
1318 ; arguments to a method is < 6 (5 for struct returns).
1319 ;
1320 ; *************************************************
1321 ;
1322 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1323
1324 /********************************************************************
1325 * id objc_msgSendFew(id self,
1326 * SEL op,
1327 * ...);
1328 *
1329 * On entry: r3 is the message receiver,
1330 * r4 is the selector
1331 * + at most 3 args (ints or doubles)
1332 ********************************************************************/
1333
1334 ENTRY _objc_msgSendFew
1335 ; do profiling when enabled
1336 CALL_MCOUNT
1337
1338 ; check whether receiver is nil
1339 cmplwi r3,0 ; receiver nil?
1340 beq LMsgSendFewNilSelf ; if so, call handler or return nil
1341
1342 #if !defined(OBJC_COLLECTING_CACHE)
1343 ; check whether context is multithreaded
1344 lis r11,ha16(__objc_multithread_mask)
1345 lwz r11,lo16(__objc_multithread_mask)(r11)
1346 cmplwi r11,0 ; objc_multithread_mask zero?
1347 beq LMsgSendFewMT ; branch to the locking case
1348 #endif
1349
1350 ; single threaded and receiver is non-nil: search the cache
1351 CacheLookup WORD_RETURN, MSG_SEND, LMsgSendFewCacheMiss, FEW_ARGS
1352 li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
1353 bctr ; goto *imp;
1354
1355 ; cache miss: go search the method lists
1356 LMsgSendFewCacheMiss:
1357 MethodTableLookup WORD_RETURN, MSG_SEND, FEW_ARGS
1358 li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
1359 bctr ; goto *imp;
1360
1361 #if !defined(OBJC_COLLECTING_CACHE)
1362 ; multithreaded: hold _messageLock while accessing cache
1363 LMsgSendFewMT:
1364 PLOCK r11, _messageLock
1365 CacheLookup WORD_RETURN, MSG_SEND, LMsgSendFewMTCacheMiss, FEW_ARGS
1366 PUNLOCK r11, _messageLock
1367 li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
1368 bctr ; goto *imp;
1369
1370 ; cache miss: go search the method lists
1371 LMsgSendFewMTCacheMiss:
1372 MethodTableLookup WORD_RETURN, MSG_SEND, FEW_ARGS
1373 PUNLOCK r11, _messageLock
1374 li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
1375 bctr ; goto *imp;
1376 #endif
1377
1378 ; message sent to nil object call: optional handler and return nil
1379 LMsgSendFewNilSelf:
1380 LOAD_STATIC_WORD r11, __objc_msgNil, EXTERNAL_SYMBOL
1381 cmplwi r11,0 ; handler nil?
1382 beqlr ; if no handler, return nil
1383
1384 mflr r0 ; save return pc
1385 stw r0,8(r1) ;
1386 subi r1,r1,64 ; allocate linkage area
1387 mtctr r11 ;
1388 bctrl ; call handler
1389 addi r1,r1,64 ; deallocate linkage area
1390 lwz r0,8(r1) ; restore return pc
1391 mtlr r0 ;
1392
1393 li r3,0 ; re-zero return value, in case handler changed it
1394 blr ; return to caller
1395
1396 LMsgSendFewExit:
1397 END_ENTRY _objc_msgSendFew
1398
1399
1400 /********************************************************************
1401 * struct_type objc_msgSendFew_stret(id self,
1402 * SEL op,
1403 * ...);
1404 *
1405 * objc_msgSend_stret is the struct-return form of msgSend.
1406 * The ABI calls for r3 to be used as the address of the structure
1407 * being returned, with the parameters in the succeeding registers.
1408 *
1409 * On entry: r3 is the address where the structure is returned,
1410 * r4 is the message receiver,
1411 * r5 is the selector
1412 ********************************************************************/
1413
1414 ENTRY _objc_msgSendFew_stret
1415 ; do profiling when enabled
1416 CALL_MCOUNT
1417
1418 ; check whether receiver is nil
1419 cmplwi r4,0 ; receiver nil?
1420 beq LMsgSendFewStretNilSelf ; if so, call handler or just return
1421
1422 #if !defined(OBJC_COLLECTING_CACHE)
1423 ; check whether context is multithreaded
1424 lis r11,ha16(__objc_multithread_mask)
1425 lwz r11,lo16(__objc_multithread_mask)(r11)
1426 cmplwi r11,0 ; objc_multithread_mask zero?
1427 beq LMsgSendFewStretMT ; branch to the locking case
1428 #endif
1429
1430 ; single threaded and receiver is non-nil: search the cache
1431 CacheLookup STRUCT_RETURN, MSG_SEND, LMsgSendFewStretCacheMiss, FEW_ARGS
1432 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
1433 bctr ; goto *imp;
1434
1435 ; cache miss: go search the method lists
1436 LMsgSendFewStretCacheMiss:
1437 MethodTableLookup STRUCT_RETURN, MSG_SEND, FEW_ARGS
1438 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
1439 bctr ; goto *imp;
1440
1441 #if !defined(OBJC_COLLECTING_CACHE)
1442 ; multithreaded: hold _messageLock while accessing cache
1443 LMsgSendFewStretMT:
1444 PLOCK r11, _messageLock
1445 CacheLookup STRUCT_RETURN, MSG_SEND, LMsgSendFewStretMTCacheMiss, FEW_ARGS
1446 PUNLOCK r11, _messageLock
1447 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
1448 bctr ; goto *imp;
1449
1450 ; cache miss: go search the method lists
1451 LMsgSendFewStretMTCacheMiss:
1452 MethodTableLookup STRUCT_RETURN, MSG_SEND, FEW_ARGS
1453 PUNLOCK r11, _messageLock
1454 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
1455 bctr ; goto *imp;
1456 #endif
1457
1458 ; message sent to nil object call optional handler and return nil
1459 LMsgSendFewStretNilSelf:
1460 LOAD_STATIC_WORD r11, __objc_msgNil, EXTERNAL_SYMBOL
1461 cmplwi r11,0 ; handler nil?
1462 beqlr ; if no handler, return
1463
1464 mflr r0 ; save return pc
1465 stw r0,8(r1) ;
1466 subi r1,r1,64 ; allocate linkage area
1467 mr r3,r4 ; move self to r3
1468 mr r4,r5 ; move SEL to r4
1469 mtctr r11 ;
1470 bctrl ; call handler
1471 addi r1,r1,64 ; deallocate linkage area
1472 lwz r0,8(r1) ; restore return pc
1473 mtlr r0 ;
1474
1475 blr ; return to caller
1476
1477 LMsgSendFewStretExit:
1478 END_ENTRY _objc_msgSendFew_stret
1479
1480
1481 /********************************************************************
1482 * id objc_msgSendSuperFew(struct objc_super *super,
1483 * SEL op,
1484 * ...);
1485 *
1486 * struct objc_super {
1487 * id receiver;
1488 * Class class;
1489 * };
1490 ********************************************************************/
1491
1492 ENTRY _objc_msgSendSuperFew
1493 ; do profiling when enabled
1494 CALL_MCOUNT
1495
1496 #if !defined(OBJC_COLLECTING_CACHE)
1497 ; check whether context is multithreaded
1498 lis r11,ha16(__objc_multithread_mask)
1499 lwz r11,lo16(__objc_multithread_mask)(r11)
1500 cmplwi r11,0 ; objc_multithread_mask zero?
1501 beq LMsgSendSuperFewMT ; branch to the locking case
1502 #endif
1503
1504 ; single threaded: search the cache
1505 CacheLookup WORD_RETURN, MSG_SENDSUPER, LMsgSendSuperFewCacheMiss, FEW_ARGS
1506 lwz r3,receiver(r3) ; receiver is the first arg
1507 li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
1508 bctr ; goto *imp;
1509
1510 ; cache miss: go search the method lists
1511 LMsgSendSuperFewCacheMiss:
1512 MethodTableLookup WORD_RETURN, MSG_SENDSUPER, FEW_ARGS
1513 lwz r3,receiver(r3) ; receiver is the first arg
1514 li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
1515 bctr ; goto *imp;
1516
1517 #if !defined(OBJC_COLLECTING_CACHE)
1518 ; multithreaded: hold _messageLock while accessing cache
1519 LMsgSendSuperFewMT:
1520 PLOCK r11, _messageLock
1521 CacheLookup WORD_RETURN, MSG_SENDSUPER, LMsgSendSuperFewMTCacheMiss, FEW_ARGS
1522 PUNLOCK r11, _messageLock
1523 lwz r3,receiver(r3) ; receiver is the first arg
1524 li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
1525 bctr ; goto *imp;
1526
1527 ; cache miss: go search the method lists
1528 LMsgSendSuperFewMTCacheMiss:
1529 MethodTableLookup WORD_RETURN, MSG_SENDSUPER, FEW_ARGS
1530 PUNLOCK r11, _messageLock
1531 lwz r3,receiver(r3) ; receiver is the first arg
1532 li r11,kFwdMsgSend ; indicate word-return to _objc_msgForward
1533 bctr ; goto *imp;
1534 #endif
1535
1536 LMsgSendSuperFewExit:
1537 END_ENTRY _objc_msgSendSuperFew
1538
1539
1540 /********************************************************************
1541 * struct_type objc_msgSendSuperFew_stret(objc_super *super,
1542 * SEL op,
1543 * ...);
1544 *
1545 * struct objc_super {
1546 * id receiver;
1547 * Class class;
1548 * };
1549 *
1550 *
1551 * objc_msgSendSuper_stret is the struct-return form of msgSendSuper.
1552 * The ABI calls for r3 to be used as the address of the structure
1553 * being returned, with the parameters in the succeeding registers.
1554 *
1555 * On entry: r3 is the address to which to copy the returned structure,
1556 * r4 is the address of the objc_super structure,
1557 * r5 is the selector
1558 ********************************************************************/
1559
1560 ENTRY _objc_msgSendSuperFew_stret
1561 ; do profiling when enabled
1562 CALL_MCOUNT
1563
1564 #if !defined(OBJC_COLLECTING_CACHE)
1565 ; check whether context is multithreaded
1566 lis r11,ha16(__objc_multithread_mask)
1567 lwz r11,lo16(__objc_multithread_mask)(r11)
1568 cmplwi r11,0 ; objc_multithread_mask zero?
1569 beq LMsgSendSuperFewStretMT ; branch to the locking case
1570 #endif
1571
1572 ; single threaded: search the cache
1573 CacheLookup STRUCT_RETURN, MSG_SENDSUPER, LMsgSendSuperFewStretCacheMiss, FEW_ARGS
1574 lwz r4,receiver(r4) ; receiver is the first arg
1575 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
1576 bctr ; goto *imp;
1577
1578 ; cache miss: go search the method lists
1579 LMsgSendSuperFewStretCacheMiss:
1580 MethodTableLookup STRUCT_RETURN, MSG_SENDSUPER, FEW_ARGS
1581 lwz r4,receiver(r4) ; receiver is the first arg
1582 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
1583 bctr ; goto *imp;
1584
1585 #if !defined(OBJC_COLLECTING_CACHE)
1586 ; multithreaded: hold _messageLock while accessing cache
1587 LMsgSendSuperFewStretMT:
1588 PLOCK r11, _messageLock
1589 CacheLookup STRUCT_RETURN, MSG_SENDSUPER, LMsgSendSuperFewStretMTCacheMiss, FEW_ARGS
1590 PUNLOCK r11, _messageLock
1591 lwz r4,receiver(r4) ; receiver is the first arg
1592 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
1593 bctr ; goto *imp;
1594
1595 ; cache miss: go search the method lists
1596 LMsgSendSuperFewStretMTCacheMiss:
1597 MethodTableLookup STRUCT_RETURN, MSG_SENDSUPER, FEW_ARGS
1598 PUNLOCK r11, _messageLock
1599 lwz r4,receiver(r4) ; receiver is the first arg
1600 li r11,kFwdMsgSendStret ; indicate struct-return to _objc_msgForward
1601 bctr ; goto *imp;
1602 #endif
1603
1604 LMsgSendSuperFewStretExit:
1605 END_ENTRY _objc_msgSendSuperFew_stret
1606