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