]> git.saurik.com Git - apple/objc4.git/blob - runtime/Messengers.subproj/objc-msg-arm.s
objc4-437.tar.gz
[apple/objc4.git] / runtime / Messengers.subproj / objc-msg-arm.s
1 /*
2 * @APPLE_LICENSE_HEADER_START@
3 *
4 * Copyright (c) 1999-2007 Apple Computer, Inc. All Rights Reserved.
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #ifdef __arm__
25
26 /********************************************************************
27 *
28 * objc-msg-arm.s - ARM code to support objc messaging
29 *
30 ********************************************************************/
31
32
33 #ifdef ARM11
34 #define MOVE cpy
35 #define MOVEEQ cpyeq
36 #define MOVENE cpyne
37 #else
38 #define MOVE mov
39 #define MOVEEQ moveq
40 #define MOVENE movne
41 #endif
42
43 #ifdef VFP_ARGS
44 #define SAVE_VFP fstmfdd sp!, {d0-d7}
45 #define RESTORE_VFP fldmfdd sp!, {d0-d7}
46 #else
47 #define SAVE_VFP /* empty */
48 #define RESTORE_VFP /* empty */
49 #endif
50
51
52 #if defined(__DYNAMIC__)
53 #define MI_EXTERN(var) \
54 .non_lazy_symbol_pointer ;\
55 L ## var ## __non_lazy_ptr: ;\
56 .indirect_symbol var ;\
57 .long 0
58 #else
59 #define MI_EXTERN(var) \
60 .globl var
61 #endif
62
63 #if defined(__DYNAMIC__)
64 #define MI_GET_ADDRESS(reg,var) \
65 ldr reg, 4f ;\
66 3: ldr reg, [pc, reg] ;\
67 b 5f ;\
68 4: .long L ## var ## __non_lazy_ptr - (3b + 8) ;\
69 5:
70 #else
71 #define MI_GET_ADDRESS(reg,var) \
72 ldr reg, 3f ;\
73 b 4f ;\
74 3: .long var ;\
75 4:
76 #endif
77
78 #if defined(__DYNAMIC__)
79 #define MI_BRANCH_EXTERNAL(var) \
80 MI_GET_ADDRESS(ip, var) ;\
81 bx ip
82 #else
83 #define MI_BRANCH_EXTERNAL(var) ;\
84 b var
85 #endif
86
87 #if defined(__DYNAMIC__)
88 #define MI_CALL_EXTERNAL(var) \
89 MI_GET_ADDRESS(ip,var) ;\
90 MOVE lr, pc ;\
91 bx ip
92 #else
93 #define MI_CALL_EXTERNAL(var) \
94 bl var
95 #endif
96
97
98 MI_EXTERN(__class_lookupMethodAndLoadCache)
99 MI_EXTERN(_FwdSel)
100 MI_EXTERN(___objc_error)
101 MI_EXTERN(__objc_forward_handler)
102 MI_EXTERN(__objc_forward_stret_handler)
103
104 #if 0
105 // Special section containing a function pointer that dyld will call
106 // when it loads new images.
107 MI_EXTERN(__objc_notify_images)
108 .text
109 .align 2
110 L__objc_notify_images:
111 MI_BRANCH_EXTERNAL(__objc_notify_images)
112
113 .section __DATA,__image_notify
114 .long L__objc_notify_images
115 #endif
116
117
118 # _objc_entryPoints and _objc_exitPoints are used by method dispatch
119 # caching code to figure out whether any threads are actively
120 # in the cache for dispatching. The labels surround the asm code
121 # that do cache lookups. The tables are zero-terminated.
122 .data
123 .globl _objc_entryPoints
124 _objc_entryPoints:
125 .long __cache_getImp
126 .long __cache_getMethod
127 .long _objc_msgSend
128 .long _objc_msgSend_stret
129 .long _objc_msgSendSuper
130 .long _objc_msgSendSuper_stret
131 .long 0
132
133 .data
134 .globl _objc_exitPoints
135 _objc_exitPoints:
136 .long LGetImpExit
137 .long LGetMethodExit
138 .long LMsgSendExit
139 .long LMsgSendStretExit
140 .long LMsgSendSuperExit
141 .long LMsgSendSuperStretExit
142 .long 0
143
144
145 /* objc_super parameter to sendSuper */
146 .set RECEIVER, 0
147 .set CLASS, 4
148
149 /* Selected field offsets in class structure */
150 .set ISA, 0
151 #if __OBJC2__
152 .set CACHE, 8
153 #else
154 .set CACHE, 32
155 #endif
156
157 /* Method descriptor */
158 .set METHOD_NAME, 0
159 .set METHOD_IMP, 8
160
161 /* Cache header */
162 .set MASK, 0
163 .set OCCUPIED, 4
164 .set BUCKETS, 8 /* variable length array */
165
166
167 #####################################################################
168 #
169 # ENTRY functionName
170 #
171 # Assembly directives to begin an exported function.
172 # We align on cache boundaries for these few functions.
173 #
174 # Takes: functionName - name of the exported function
175 #####################################################################
176
177 .macro ENTRY /* name */
178 .text
179 .align 2
180 .globl _$0
181 _$0:
182 .endmacro
183
184 #####################################################################
185 #
186 # END_ENTRY functionName
187 #
188 # Assembly directives to end an exported function. Just a placeholder,
189 # a close-parenthesis for ENTRY, until it is needed for something.
190 #
191 # Takes: functionName - name of the exported function
192 #####################################################################
193
194 .macro END_ENTRY /* name */
195 .endmacro
196
197
198 #####################################################################
199 #
200 # CacheLookup selectorRegister, cacheMissLabel
201 #
202 # Locate the implementation for a selector in a class method cache.
203 #
204 # Takes:
205 # v1 = class whose cache is to be searched
206 # $0 = register containing selector (a2 or a3 ONLY)
207 # cacheMissLabel = label to branch to iff method is not cached
208 #
209 # Kills:
210 # a4, v1, v2, v3, ip
211 #
212 # On exit: (found) method triplet in v1, imp in ip
213 # (not found) jumps to cacheMissLabel
214 #
215 #####################################################################
216
217 .macro CacheLookup /* selReg, missLabel */
218
219 ldr v2, [v1, #CACHE] /* cache = class->cache */
220 ldr v3, [v2, #MASK] /* mask = cache->mask */
221 add a4, v2, #BUCKETS /* buckets = &cache->buckets */
222 and v2, v3, $0, LSR #2 /* index = mask & (sel >> 2) */
223
224 /* search the cache */
225 /* a1=receiver, a2 or a3=sel, v2=index, v3=mask, a4=buckets, v1=method */
226 1:
227 ldr v1, [a4, v2, LSL #2] /* method = buckets[index] */
228 teq v1, #0 /* if (method == NULL) */
229 add v2, v2, #1 /* index++ */
230 beq $1 /* goto cacheMissLabel */
231
232 ldr ip, [v1, #METHOD_NAME] /* load method->method_name */
233 teq $0, ip /* if (method->method_name != sel) */
234 and v2, v2, v3 /* index &= mask */
235 bne 1b /* retry */
236
237 /* cache hit, v1 == method triplet address */
238 /* Return triplet in v1 and imp in ip */
239 ldr ip, [v1, #METHOD_IMP] /* imp = method->method_imp */
240
241 .endmacro
242
243
244 /********************************************************************
245 * Method _cache_getMethod(Class cls, SEL sel, IMP msgForward_internal_imp)
246 *
247 * On entry: a1 = class whose cache is to be searched
248 * a2 = selector to search for
249 * a3 = _objc_msgForward_internal IMP
250 *
251 * If found, returns method triplet pointer.
252 * If not found, returns NULL.
253 *
254 * NOTE: _cache_getMethod never returns any cache entry whose implementation
255 * is _objc_msgForward_internal. It returns NULL instead. This prevents thread-
256 * safety and memory management bugs in _class_lookupMethodAndLoadCache.
257 * See _class_lookupMethodAndLoadCache for details.
258 *
259 * _objc_msgForward_internal is passed as a parameter because it's more
260 * efficient to do the (PIC) lookup once in the caller than repeatedly here.
261 ********************************************************************/
262
263 ENTRY _cache_getMethod
264
265 # save registers and load class for CacheLookup
266 stmfd sp!, {a4,v1-v3,r7,lr}
267 add r7, sp, #16
268 MOVE v1, a1
269
270 # search the cache
271 CacheLookup a2, LGetMethodMiss
272
273 # cache hit, method triplet in v1 and imp in ip
274 teq ip, a3 /* check for _objc_msgForward_internal */
275 MOVEEQ a1, #1 /* return (Method)1 if forward */
276 MOVENE a1, v1 /* return triplet if not forward */
277 ldmfd sp!, {a4,v1-v3,r7,pc}
278
279 LGetMethodMiss:
280 MOVE a1, #0 /* return nil if cache miss */
281 ldmfd sp!, {a4,v1-v3,r7,pc}
282
283 LGetMethodExit:
284 END_ENTRY _cache_getMethod
285
286
287 /********************************************************************
288 * IMP _cache_getImp(Class cls, SEL sel)
289 *
290 * On entry: a1 = class whose cache is to be searched
291 * a2 = selector to search for
292 *
293 * If found, returns method implementation.
294 * If not found, returns NULL.
295 ********************************************************************/
296
297 ENTRY _cache_getImp
298
299 # save registers and load class for CacheLookup
300 stmfd sp!, {a4,v1-v3,r7,lr}
301 add r7, sp, #16
302 MOVE v1, a1
303
304 # search the cache
305 CacheLookup a2, LGetImpMiss
306
307 # cache hit, method triplet in v1 and imp in ip
308 MOVE a1, ip @ return imp
309 ldmfd sp!, {a4,v1-v3,r7,pc}
310
311 LGetImpMiss:
312 MOVE a1, #0 @ return nil if cache miss
313 ldmfd sp!, {a4,v1-v3,r7,pc}
314
315 LGetImpExit:
316 END_ENTRY _cache_getImp
317
318
319 /********************************************************************
320 * id objc_msgSend(id self,
321 * SEL op,
322 * ...)
323 *
324 * On entry: a1 is the message receiver,
325 * a2 is the selector
326 ********************************************************************/
327
328 ENTRY objc_msgSend
329 # check whether receiver is nil
330 teq a1, #0
331 moveq a2, #0
332 bxeq lr
333
334 # save registers and load receiver's class for CacheLookup
335 stmfd sp!, {a4,v1-v3}
336 ldr v1, [a1, #ISA]
337
338 # receiver is non-nil: search the cache
339 CacheLookup a2, LMsgSendCacheMiss
340
341 # cache hit (imp in ip) - prep for forwarding, restore registers and call
342 teq v1, v1 /* set nonstret (eq) */
343 ldmfd sp!, {a4,v1-v3}
344 bx ip
345
346 # cache miss: go search the method lists
347 LMsgSendCacheMiss:
348 ldmfd sp!, {a4,v1-v3}
349 b _objc_msgSend_uncached
350
351 LMsgSendExit:
352 END_ENTRY objc_msgSend
353
354
355 .text
356 .align 2
357 _objc_msgSend_uncached:
358
359 # Push stack frame
360 stmfd sp!, {a1-a4,r7,lr}
361 add r7, sp, #16
362 SAVE_VFP
363
364 # Load class and selector
365 ldr a1, [a1, #ISA] /* class = receiver->isa */
366 # MOVE a2, a2 /* selector already in a2 */
367
368 # Do the lookup
369 MI_CALL_EXTERNAL(__class_lookupMethodAndLoadCache)
370 MOVE ip, a1
371
372 # Prep for forwarding, Pop stack frame and call imp
373 teq v1, v1 /* set nonstret (eq) */
374 RESTORE_VFP
375 ldmfd sp!, {a1-a4,r7,lr}
376 bx ip
377
378
379 /********************************************************************
380 * struct_type objc_msgSend_stret(id self,
381 * SEL op,
382 * ...);
383 *
384 * objc_msgSend_stret is the struct-return form of msgSend.
385 * The ABI calls for a1 to be used as the address of the structure
386 * being returned, with the parameters in the succeeding registers.
387 *
388 * On entry: a1 is the address where the structure is returned,
389 * a2 is the message receiver,
390 * a3 is the selector
391 ********************************************************************/
392
393 ENTRY objc_msgSend_stret
394 # check whether receiver is nil
395 teq a2, #0
396 bxeq lr
397
398 # save registers and load receiver's class for CacheLookup
399 stmfd sp!, {a4,v1-v3}
400 ldr v1, [a2, #ISA]
401
402 # receiver is non-nil: search the cache
403 CacheLookup a3, LMsgSendStretCacheMiss
404
405 # cache hit (imp in ip) - prep for forwarding, restore registers and call
406 tst v1, v1 /* set stret (ne); v1 is nonzero (triplet) */
407 ldmfd sp!, {a4,v1-v3}
408 bx ip
409
410 # cache miss: go search the method lists
411 LMsgSendStretCacheMiss:
412 ldmfd sp!, {a4,v1-v3}
413 b _objc_msgSend_stret_uncached
414
415 LMsgSendStretExit:
416 END_ENTRY objc_msgSend_stret
417
418
419 .text
420 .align 2
421 _objc_msgSend_stret_uncached:
422
423 # Push stack frame
424 stmfd sp!, {a1-a4,r7,lr}
425 add r7, sp, #16
426 SAVE_VFP
427
428 # Load class and selector
429 ldr a1, [a2, #ISA] /* class = receiver->isa */
430 MOVE a2, a3 /* selector */
431
432 # Do the lookup
433 MI_CALL_EXTERNAL(__class_lookupMethodAndLoadCache)
434 MOVE ip, a1
435
436 # Prep for forwarding, pop stack frame and call imp
437 tst a1, a1 /* set stret (ne); a1 is nonzero (imp) */
438
439 RESTORE_VFP
440 ldmfd sp!, {a1-a4,r7,lr}
441 bx ip
442
443
444 /********************************************************************
445 * id objc_msgSendSuper(struct objc_super *super,
446 * SEL op,
447 * ...)
448 *
449 * struct objc_super {
450 * id receiver
451 * Class class
452 * }
453 ********************************************************************/
454
455 ENTRY objc_msgSendSuper2
456 @ objc_super->class is superclass of the class to search
457 ldr r12, [a1, #CLASS]
458 ldr r12, [r12, #4] @ r12 = cls->super_class
459 str r12, [a1, #CLASS]
460 b _objc_msgSendSuper
461 END_ENTRY
462
463 ENTRY objc_msgSendSuper
464
465 # save registers and load super class for CacheLookup
466 stmfd sp!, {a4,v1-v3}
467 ldr v1, [a1, #CLASS]
468
469 # search the cache
470 CacheLookup a2, LMsgSendSuperCacheMiss
471
472 # cache hit (imp in ip) - prep for forwarding, restore registers and call
473 teq v1, v1 /* set nonstret (eq) */
474 ldmfd sp!, {a4,v1-v3}
475 ldr a1, [a1, #RECEIVER] @ fetch real receiver
476 bx ip
477
478 # cache miss: go search the method lists
479 LMsgSendSuperCacheMiss:
480 ldmfd sp!, {a4,v1-v3}
481 b _objc_msgSendSuper_uncached
482
483 LMsgSendSuperExit:
484 END_ENTRY objc_msgSendSuper
485
486
487 .text
488 .align 2
489 _objc_msgSendSuper_uncached:
490
491 # Push stack frame
492 stmfd sp!, {a1-a4,r7,lr}
493 add r7, sp, #16
494 SAVE_VFP
495
496 # Load class and selector
497 ldr a1, [a1, #CLASS] /* class = super->class */
498 # MOVE a2, a2 /* selector already in a2 */
499
500 # Do the lookup
501 MI_CALL_EXTERNAL(__class_lookupMethodAndLoadCache)
502 MOVE ip, a1
503
504 # Prep for forwarding, pop stack frame and call imp
505 teq v1, v1 /* set nonstret (eq) */
506 RESTORE_VFP
507 ldmfd sp!, {a1-a4,r7,lr}
508 ldr a1, [a1, #RECEIVER] @ fetch real receiver
509 bx ip
510
511
512 /********************************************************************
513 * struct_type objc_msgSendSuper_stret(objc_super *super,
514 * SEL op,
515 * ...)
516 *
517 * struct objc_super {
518 * id receiver
519 * Class class
520 * }
521 *
522 *
523 * objc_msgSendSuper_stret is the struct-return form of msgSendSuper.
524 * The ABI calls for a1 to be used as the address of the structure
525 * being returned, with the parameters in the succeeding registers.
526 *
527 * On entry: a1 is the address to which to copy the returned structure,
528 * a2 is the address of the objc_super structure,
529 * a3 is the selector
530 ********************************************************************/
531
532 ENTRY objc_msgSendSuper2_stret
533 @ objc_super->class is superclass of the class to search
534 ldr r12, [a2, #CLASS]
535 ldr r12, [r12, #4] @ xx = cls->super_class
536 str r12, [a2, #CLASS]
537 b _objc_msgSendSuper_stret
538 END_ENTRY
539
540 ENTRY objc_msgSendSuper_stret
541
542 # save registers and load super class for CacheLookup
543 stmfd sp!, {a4,v1-v3}
544 ldr v1, [a2, #CLASS]
545
546 # search the cache
547 CacheLookup a3, LMsgSendSuperStretCacheMiss
548
549 # cache hit (imp in ip) - prep for forwarding, restore registers and call
550 tst v1, v1 /* set stret (ne); v1 is nonzero (triplet) */
551 ldmfd sp!, {a4,v1-v3}
552 ldr a2, [a2, #RECEIVER] @ fetch real receiver
553 bx ip
554
555 # cache miss: go search the method lists
556 LMsgSendSuperStretCacheMiss:
557 ldmfd sp!, {a4,v1-v3}
558 b _objc_msgSendSuper_stret_uncached
559
560 LMsgSendSuperStretExit:
561 END_ENTRY objc_msgSendSuper_stret
562
563
564 .text
565 .align 2
566 _objc_msgSendSuper_stret_uncached:
567
568 # Push stack frame
569 stmfd sp!, {a1-a4,r7,lr}
570 add r7, sp, #16
571 SAVE_VFP
572
573 # Load class and selector
574 ldr a1, [a2, #CLASS] /* class = super->class */
575 MOVE a2, a3 /* selector */
576
577 # Do the lookup
578 MI_CALL_EXTERNAL(__class_lookupMethodAndLoadCache)
579 MOVE ip, a1
580
581 # Prep for forwarding, pop stack frame and call imp
582 tst v1, v1 /* set stret (ne); v1 is nonzero (triplet) */
583
584 RESTORE_VFP
585 ldmfd sp!, {a1-a4,r7,lr}
586 ldr a2, [a2, #RECEIVER] @ fetch real receiver
587 bx ip
588
589
590 /********************************************************************
591 *
592 * id _objc_msgForward(id self,
593 * SEL sel,
594 * ...);
595 * struct_type _objc_msgForward_stret (id self,
596 * SEL sel,
597 * ...);
598 *
599 * Both _objc_msgForward and _objc_msgForward_stret
600 * send the message to a method having the signature:
601 *
602 * - forward:(SEL)sel :(marg_list)args;
603 *
604 * The marg_list's layout is:
605 * d0 <-- args
606 * d1
607 * d2 | increasing address
608 * d3 v
609 * d4
610 * d5
611 * d6
612 * d7
613 * a1
614 * a2
615 * a3
616 * a4
617 * stack args...
618 *
619 * typedef struct objc_sendv_margs {
620 * #ifdef VFP_ARGS
621 * double vfp[8];
622 * #endif
623 * int a[4];
624 * int stackArgs[...];
625 * };
626 *
627 ********************************************************************/
628
629 .data
630 .private_extern _FwdSel
631 _FwdSel:
632 .long 0
633
634 .private_extern __objc_forward_handler
635 __objc_forward_handler:
636 .long 0
637
638 .private_extern __objc_forward_stret_handler
639 __objc_forward_stret_handler:
640 .long 0
641
642
643 ENTRY _objc_msgForward_internal
644 .private_extern __objc_msgForward_internal
645 // Method cache version
646
647 // THIS IS NOT A CALLABLE C FUNCTION
648 // Out-of-band condition register is NE for stret, EQ otherwise.
649
650 bne __objc_msgForward_stret
651 b __objc_msgForward
652
653 END_ENTRY _objc_msgForward_internal
654
655
656 ENTRY _objc_msgForward
657 // Non-stret version
658
659 # check for user-installed forwarding handler
660 MI_GET_ADDRESS(ip, __objc_forward_handler)
661 ldr ip, [ip]
662 teq ip, #0
663 bxne ip
664
665 # build marg_list
666 stmfd sp!, {a1-a4} @ push args to marg_list
667 #ifdef VFP_ARGS
668 fstmfdd sp!, {d0-d7} @ push fp args to marg_list
669 #endif
670
671 # build forward::'s parameter list (self, forward::, original sel, marg_list)
672 # a1 already is self
673 MOVE a3, a2 @ original sel
674 MI_GET_ADDRESS(a2, _FwdSel) @ "forward::"
675 ldr a2, [a2]
676 MOVE a4, sp @ marg_list
677
678 # check for forwarding of forward:: itself
679 teq a2, a3
680 beq LMsgForwardError @ original sel == forward:: - give up
681
682 # push stack frame
683 str lr, [sp, #-(2*4)]! @ save lr and align stack
684
685 # send it
686 bl _objc_msgSend
687
688 # pop stack frame and return
689 ldr lr, [sp]
690 #ifdef VFP_ARGS
691 add sp, sp, #(4 + 4 + 4*4 + 8*8) @ skip lr, pad, a1..a4, d0..d7
692 #else
693 add sp, sp, #(4 + 4 + 4*4) @ skip lr, pad, a1..a4
694 #endif
695 bx lr
696
697 END_ENTRY _objc_msgForward
698
699
700 ENTRY _objc_msgForward_stret
701 // Struct-return version
702
703 # check for user-installed forwarding handler
704 MI_GET_ADDRESS(ip, __objc_forward_stret_handler)
705 ldr ip, [ip]
706 teq ip, #0
707 bxne ip
708
709 # build marg_list
710 stmfd sp!, {a1-a4} @ push args to marg_list
711 #ifdef VFP_ARGS
712 fstmfdd sp!, {d0-d7} @ push fp args to marg_list
713 #endif
714
715 # build forward::'s parameter list (self, forward::, original sel, marg_list)
716 MOVE a1, a2 @ self
717 MI_GET_ADDRESS(a2, _FwdSel) @ "forward::"
718 ldr a2, [a2]
719 # a3 is already original sel
720 MOVE a4, sp @ marg_list
721
722 # check for forwarding of forward:: itself
723 teq a2, a3
724 beq LMsgForwardError @ original sel == forward:: - give up
725
726 # push stack frame
727 str lr, [sp, #-(2*4)]! @ save lr and align stack
728
729 # send it
730 bl _objc_msgSend
731
732 # pop stack frame and return
733 ldr lr, [sp]
734 #ifdef VFP_ARGS
735 add sp, sp, #(4 + 4 + 4*4 + 8*8) @ skip lr, pad, a1..a4, d0..d7
736 #else
737 add sp, sp, #(4 + 4 + 4*4) @ skip lr, pad, a1..a4
738 #endif
739 bx lr
740
741 END_ENTRY _objc_msgForward_stret
742
743 LMsgForwardError:
744 # currently a1=self, a2=forward::, a3 = original sel, a4 = marg_list
745 # call __objc_error(self, format, original sel)
746 add a2, pc, #4 @ pc bias is 8 bytes
747 MI_CALL_EXTERNAL(___objc_error)
748 .ascii "Does not recognize selector %s\0"
749
750
751 /********************************************************************
752 * id objc_msgSendv(id self,
753 * SEL op,
754 * unsigned arg_size,
755 * marg_list arg_frame);
756 *
757 * typedef struct objc_sendv_margs {
758 * #ifdef VFP_ARGS
759 * double vfp[8];
760 * #endif
761 * int a[4];
762 * int stackArgs[...];
763 * };
764 *
765 * arg_frame is the number of bytes used in a[] plus stackArgs.
766 * It does not include vfp[].
767 *
768 ********************************************************************/
769
770 ENTRY objc_msgSendv
771
772 # Push stack frame
773 SAVE_VFP
774 stmfd sp!, {a4,v1-v3,r7,lr} @ a4 saved for stack alignment only
775 add r7, sp, #16
776
777 # save sendv's parameters
778 # self stays in a1
779 # sel stays in a2
780 MOVE v1, a3 @ v1 is arg count in bytes
781 MOVE v2, a4 @ v2 is marg_list
782
783 # load FP from marg_list
784 #ifdef VFP_ARGS
785 fldmfdd v2!, {d0-d7}
786 #endif
787
788 # load arg registers from marg_list
789 # v1 is remaining count, v2 is pointer into marg_list
790 # self already in a1
791 # sel already in a2
792 cmp v1, #12
793 ldrhs a3, [v2, #8] @ pop a3 if arg bytes is at least 12
794 ldrhi a4, [v2, #12] @ pop a4 if arg bytes is more than 12
795 subs v1, v1, #16 @ skip past register args
796 ble LMsgSendvCall @ call now if no args remain
797 add v2, v2, #16 @ skip past register args
798
799 # copy stack args from marg_list
800 # v1 is remaining bytes, v2 is pointer into marg_list, sp is pointer into stack
801 tst v1, #4
802 subne sp, sp, #4 @ push 4-byte pad if word count is odd
803
804 sub sp, sp, v1 @ move sp to end and copy backwards
805 @ (this preserves ABI's stack constraints)
806 LMsgSendvArgLoop:
807 subs v1, v1, #4
808 ldr v3, [v2, v1]
809 str v3, [sp, v1]
810 bne LMsgSendvArgLoop
811
812 LMsgSendvCall:
813 bl _objc_msgSend
814
815 # Pop stack frame and return
816 MOVE sp, r7
817 ldmfd sp!, {a4,v1-v3,r7,pc}
818 #ifdef VFP_ARGS
819 #error broken for vfp
820 #endif
821
822 END_ENTRY objc_msgSendv
823
824
825
826 /********************************************************************
827 * struct_type objc_msgSendv_stret(id self,
828 * SEL op,
829 * unsigned arg_size,
830 * marg_list arg_frame);
831 *
832 * typedef struct objc_sendv_margs {
833 * #ifdef VFP_ARGS
834 * double vfp[8];
835 * #endif
836 * int a[4];
837 * int stackArgs[...];
838 * };
839 *
840 * arg_frame is the number of bytes used in a[] plus stackArgs.
841 * It does not include vfp[].
842 ********************************************************************/
843
844 ENTRY objc_msgSendv_stret
845
846 # Push stack frame
847 stmfd sp!, {a4,v1-v3,r7,lr} @ a4 saved for stack alignment only
848 add r7, sp, #16
849 SAVE_VFP
850
851 # save sendv's parameters
852 # stret address stays in a1
853 # self stays in a2
854 # sel stays in a3
855 MOVE v1, a4 @ v1 is arg count in bytes
856 ldr v2, [r7, #24] @ v2 is marg_list
857
858 # load FP from marg_list
859 #ifdef VFP_ARGS
860 fldmfdd v2!, {d0-d7}
861 #endif
862
863 # load arg registers from marg_list
864 # v1 is remaining count, v2 is pointer into marg_list
865 # stret already in a1
866 # self already in a2
867 # sel already in a3
868 subs v1, v1, #16 @ skip past register args
869 ldrhs a4, [v2, #12] @ pop a4 if arg bytes is at least 16
870 beq LMsgSendvStretCall @ call now if no args remain
871 add v2, v2, #16 @ skip past register args
872
873 # copy stack args from marg_list
874 # v1 is remaining count, v2 is pointer into marg_list, sp is pointer into stack
875 tst v1, #4
876 subne sp, sp, #4 @ push 4-byte pad if word count is odd
877
878 sub sp, sp, v1 @ move pointers to end and copy backwards
879 @ (this preserves ABI's stack constraints)
880 LMsgSendvStretArgLoop:
881 subs v1, v1, #4
882 ldr v3, [v2, v1]
883 str v3, [sp, v1]
884 bne LMsgSendvStretArgLoop
885
886 LMsgSendvStretCall:
887 bl _objc_msgSend_stret
888
889 # Pop stack frame and return
890 MOVE sp, r7
891 ldmfd sp!, {a4,v1-v3,r7,pc}
892 #ifdef VFP_ARGS
893 #error broken for vfp
894 #endif
895
896 END_ENTRY objc_msgSendv_stret
897
898
899 ENTRY method_invoke
900 # a2 is method triplet instead of SEL
901 ldr ip, [a2, #METHOD_IMP]
902 ldr a2, [a2, #METHOD_NAME]
903 bx ip
904 END_ENTRY method_invoke
905
906
907 ENTRY method_invoke_stret
908 # a3 is method triplet instead of SEL
909 ldr ip, [a3, #METHOD_IMP]
910 ldr a3, [a3, #METHOD_NAME]
911 bx ip
912 END_ENTRY method_invoke_stret
913
914 #endif