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