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