2 * Copyright (c) 1999-2007 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
23 /********************************************************************
24 ********************************************************************
26 ** objc-msg-i386.s - i386 code to support objc messaging.
28 ********************************************************************
29 ********************************************************************/
36 /********************************************************************
37 * Data used by the ObjC runtime.
39 ********************************************************************/
42 // Substitute receiver for messages sent to nil (usually also nil)
43 // id _objc_nilReceiver
45 .private_extern __objc_nilReceiver
49 // _objc_entryPoints and _objc_exitPoints are used by objc
50 // to get the critical regions for which method caches
51 // cannot be garbage collected.
53 .private_extern _objc_entryPoints
56 .long __cache_getMethod
58 .long _objc_msgSend_fpret
59 .long _objc_msgSend_stret
60 .long _objc_msgSendSuper
61 .long _objc_msgSendSuper_stret
64 .private_extern _objc_exitPoints
69 .long LMsgSendFpretExit
70 .long LMsgSendStretExit
71 .long LMsgSendSuperExit
72 .long LMsgSendSuperStretExit
77 * Handcrafted dyld stubs for each external call.
78 * They should be converted into a local branch after linking. aB.
81 /* asm_help.h version is not what we want */
84 #if defined(__DYNAMIC__)
86 #define CALL_EXTERN(name) call L ## name ## $stub
88 #define LAZY_PIC_FUNCTION_STUB(name) \
91 L ## name ## $stub: ;\
92 .indirect_symbol name ;\
96 movl L ## name ## $lz-L0$ ## name(%edx),%ecx ;\
98 L ## name ## $stub_binder: ;\
99 lea L ## name ## $lz-L0$ ## name(%edx),%eax ;\
101 jmp dyld_stub_binding_helper ;\
103 .lazy_symbol_pointer ;\
105 .indirect_symbol name ;\
106 .long L ## name ## $stub_binder
108 #else /* __DYNAMIC__ */
110 #define CALL_EXTERN(name) call name
112 #define LAZY_PIC_FUNCTION_STUB(name)
114 #endif /* __DYNAMIC__ */
116 // _class_lookupMethodAndLoadCache
117 LAZY_PIC_FUNCTION_STUB(__class_lookupMethodAndLoadCache)
120 LAZY_PIC_FUNCTION_STUB(___objc_error) /* No stub needed */
124 LAZY_PIC_FUNCTION_STUB(mcount)
127 /********************************************************************
131 ********************************************************************/
133 // In case the implementation is _objc_msgForward, indicate to it
134 // whether the method was invoked as a word-return or struct-return.
135 // This flag is passed in a register that is caller-saved, and is
136 // not part of the parameter passing convention (i.e. it is "out of
137 // band"). This works because _objc_msgForward is only entered
138 // from here in the messenger.
143 /********************************************************************
147 ********************************************************************/
165 /********************************************************************
167 * Structure definitions.
169 ********************************************************************/
171 // objc_super parameter to sendSuper
175 // Selected field offsets in class structure
186 buckets = 8 // variable length array
188 #if defined(OBJC_INSTRUMENTED)
189 // Cache instrumentation data, follows buckets
191 hitProbes = hitCount + 4
192 maxHitProbes = hitProbes + 4
193 missCount = maxHitProbes + 4
194 missProbes = missCount + 4
195 maxMissProbes = missProbes + 4
196 flushCount = maxMissProbes + 4
197 flushedEntries = flushCount + 4
199 // Buckets in CacheHitHistogram and CacheMissHistogram
200 CACHE_HISTOGRAM_SIZE = 512
204 //////////////////////////////////////////////////////////////////////
206 // LOAD_STATIC_WORD targetReg, symbolName, LOCAL_SYMBOL | EXTERNAL_SYMBOL
208 // Load the value of the named static data word.
210 // Takes: targetReg - the register, other than r0, to load
211 // symbolName - the name of the symbol
212 // LOCAL_SYMBOL - symbol name used as-is
213 // EXTERNAL_SYMBOL - symbol name gets nonlazy treatment
215 // Eats: edx and targetReg
216 //////////////////////////////////////////////////////////////////////
218 // Values to specify whether the symbol is plain or nonlazy
222 .macro LOAD_STATIC_WORD
224 #if defined(__DYNAMIC__)
227 .if $2 == EXTERNAL_SYMBOL
230 .elseif $2 == LOCAL_SYMBOL
233 !!! Unknown symbol type !!!
241 //////////////////////////////////////////////////////////////////////
243 // LEA_STATIC_DATA targetReg, symbolName, LOCAL_SYMBOL | EXTERNAL_SYMBOL
245 // Load the address of the named static data.
247 // Takes: targetReg - the register, other than edx, to load
248 // symbolName - the name of the symbol
249 // LOCAL_SYMBOL - symbol is local to this module
250 // EXTERNAL_SYMBOL - symbol is imported from another module
252 // Eats: edx and targetReg
253 //////////////////////////////////////////////////////////////////////
255 .macro LEA_STATIC_DATA
256 #if defined(__DYNAMIC__)
259 .if $2 == EXTERNAL_SYMBOL
261 .elseif $2 == LOCAL_SYMBOL
264 !!! Unknown symbol type !!!
272 //////////////////////////////////////////////////////////////////////
274 // ENTRY functionName
276 // Assembly directives to begin an exported function.
278 // Takes: functionName - name of the exported function
279 //////////////////////////////////////////////////////////////////////
288 //////////////////////////////////////////////////////////////////////
290 // END_ENTRY functionName
292 // Assembly directives to end an exported function. Just a placeholder,
293 // a close-parenthesis for ENTRY, until it is needed for something.
295 // Takes: functionName - name of the exported function
296 //////////////////////////////////////////////////////////////////////
301 //////////////////////////////////////////////////////////////////////
305 // Calls mcount() profiling routine. Must be called immediately on
306 // function entry, before any prologue executes.
308 //////////////////////////////////////////////////////////////////////
312 // Current stack contents: ret
316 // Current stack contents: ret, ebp, pad, pad
324 /////////////////////////////////////////////////////////////////////
327 // CacheLookup WORD_RETURN | STRUCT_RETURN, MSG_SEND | MSG_SENDSUPER | CACHE_GET, cacheMissLabel
329 // Locate the implementation for a selector in a class method cache.
331 // Takes: WORD_RETURN (first parameter is at sp+4)
332 // STRUCT_RETURN (struct address is at sp+4, first parameter at sp+8)
333 // MSG_SEND (first parameter is receiver)
334 // MSG_SENDSUPER (first parameter is address of objc_super structure)
335 // CACHE_GET (first parameter is class; return method triplet)
337 // class to search in %edx
339 // cacheMissLabel = label to branch to iff method is not cached
341 // On exit: (found) MSG_SEND and MSG_SENDSUPER: return imp in eax
342 // (found) CACHE_GET: return method triplet in eax
343 // (not found) jumps to cacheMissLabel
345 /////////////////////////////////////////////////////////////////////
348 // Values to specify to method lookup macros whether the return type of
349 // the method is word or structure.
353 // Values to specify to method lookup macros whether the first argument
354 // is an object/class reference or a 'objc_super' structure.
355 MSG_SEND = 0 // first argument is receiver, search the isa
356 MSG_SENDSUPER = 1 // first argument is objc_super, search the class
357 CACHE_GET = 2 // first argument is class, search that class
361 // load variables and save caller registers.
363 pushl %edi // save scratch register
364 movl cache(%edx), %edi // cache = class->cache
365 pushl %esi // save scratch register
367 #if defined(OBJC_INSTRUMENTED)
368 pushl %ebx // save non-volatile register
369 pushl %eax // save cache pointer
370 xorl %ebx, %ebx // probeCount = 0
372 movl mask(%edi), %esi // mask = cache->mask
373 leal buckets(%edi), %edi // buckets = &cache->buckets
374 movl %ecx, %edx // index = selector
375 shrl $$2, %edx // index = selector >> 2
377 // search the receiver's cache
378 LMsgSendProbeCache_$0_$1_$2:
379 #if defined(OBJC_INSTRUMENTED)
380 addl $$1, %ebx // probeCount += 1
382 andl %esi, %edx // index &= mask
383 movl (%edi, %edx, 4), %eax // method = buckets[index]
385 testl %eax, %eax // check for end of bucket
386 je LMsgSendCacheMiss_$0_$1_$2 // go to cache miss code
387 cmpl method_name(%eax), %ecx // check for method name match
388 je LMsgSendCacheHit_$0_$1_$2 // go handle cache hit
389 addl $$1, %edx // bump index ...
390 jmp LMsgSendProbeCache_$0_$1_$2 // ... and loop
392 // not found in cache: restore state and go to callers handler
393 LMsgSendCacheMiss_$0_$1_$2:
394 #if defined(OBJC_INSTRUMENTED)
395 popl %edx // retrieve cache pointer
396 movl mask(%edx), %esi // mask = cache->mask
397 testl %esi, %esi // a mask of zero is only for the...
398 je LMsgSendMissInstrumentDone_$0_$1_$2 // ... emptyCache, do not record anything
400 // locate and update the CacheInstrumentation structure
401 addl $$1, %esi // entryCount = mask + 1
402 shll $$2, %esi // tableSize = entryCount * sizeof(entry)
403 addl $buckets, %esi // offset = buckets + tableSize
404 addl %edx, %esi // cacheData = &cache->buckets[mask+1]
406 movl missCount(%esi), %edi //
408 movl %edi, missCount(%esi) // cacheData->missCount += 1
409 movl missProbes(%esi), %edi //
411 movl %edi, missProbes(%esi) // cacheData->missProbes += probeCount
412 movl maxMissProbes(%esi), %edi// if (cacheData->maxMissProbes < probeCount)
414 jge LMsgSendMaxMissProbeOK_$0_$1_$2 //
415 movl %ebx, maxMissProbes(%esi)// cacheData->maxMissProbes = probeCount
416 LMsgSendMaxMissProbeOK_$0_$1_$2:
418 // update cache miss probe histogram
419 cmpl $CACHE_HISTOGRAM_SIZE, %ebx // pin probeCount to max index
420 jl LMsgSendMissHistoIndexSet_$0_$1_$2
421 movl $(CACHE_HISTOGRAM_SIZE-1), %ebx
422 LMsgSendMissHistoIndexSet_$0_$1_$2:
423 LEA_STATIC_DATA %esi, _CacheMissHistogram, EXTERNAL_SYMBOL
424 shll $$2, %ebx // convert probeCount to histogram index
425 addl %ebx, %esi // calculate &CacheMissHistogram[probeCount<<2]
426 movl 0(%esi), %edi // get current tally
428 movl %edi, 0(%esi) // tally += 1
429 LMsgSendMissInstrumentDone_$0_$1_$2:
430 popl %ebx // restore non-volatile register
433 .if $0 == WORD_RETURN // Regular word return
434 .if $1 == MSG_SEND // MSG_SEND
435 popl %esi // restore callers register
436 popl %edi // restore callers register
437 movl self(%esp), %eax // get messaged object
438 movl isa(%eax), %eax // get objects class
439 .elseif $1 == MSG_SENDSUPER // MSG_SENDSUPER
440 // replace "super" arg with "receiver"
441 movl super+8(%esp), %edi // get super structure
442 movl receiver(%edi), %esi // get messaged object
443 movl %esi, super+8(%esp) // make it the first argument
444 movl class(%edi), %eax // get messaged class
445 popl %esi // restore callers register
446 popl %edi // restore callers register
448 popl %esi // restore callers register
449 popl %edi // restore callers register
451 .else // Struct return
452 .if $1 == MSG_SEND // MSG_SEND (stret)
453 popl %esi // restore callers register
454 popl %edi // restore callers register
455 movl self_stret(%esp), %eax // get messaged object
456 movl isa(%eax), %eax // get objects class
457 .elseif $1 == MSG_SENDSUPER // MSG_SENDSUPER (stret)
458 // replace "super" arg with "receiver"
459 movl super_stret+8(%esp), %edi// get super structure
460 movl receiver(%edi), %esi // get messaged object
461 movl %esi, super_stret+8(%esp)// make it the first argument
462 movl class(%edi), %eax // get messaged class
463 popl %esi // restore callers register
464 popl %edi // restore callers register
466 !! This should not happen.
470 jmp $2 // go to callers handler
472 // eax points to matching cache entry
474 LMsgSendCacheHit_$0_$1_$2:
475 #if defined(OBJC_INSTRUMENTED)
476 popl %edx // retrieve cache pointer
477 movl mask(%edx), %esi // mask = cache->mask
478 testl %esi, %esi // a mask of zero is only for the...
479 je LMsgSendHitInstrumentDone_$0_$1_$2 // ... emptyCache, do not record anything
481 // locate and update the CacheInstrumentation structure
482 addl $$1, %esi // entryCount = mask + 1
483 shll $$2, %esi // tableSize = entryCount * sizeof(entry)
484 addl $buckets, %esi // offset = buckets + tableSize
485 addl %edx, %esi // cacheData = &cache->buckets[mask+1]
487 movl hitCount(%esi), %edi
489 movl %edi, hitCount(%esi) // cacheData->hitCount += 1
490 movl hitProbes(%esi), %edi
492 movl %edi, hitProbes(%esi) // cacheData->hitProbes += probeCount
493 movl maxHitProbes(%esi), %edi// if (cacheData->maxHitProbes < probeCount)
495 jge LMsgSendMaxHitProbeOK_$0_$1_$2
496 movl %ebx, maxHitProbes(%esi)// cacheData->maxHitProbes = probeCount
497 LMsgSendMaxHitProbeOK_$0_$1_$2:
499 // update cache hit probe histogram
500 cmpl $CACHE_HISTOGRAM_SIZE, %ebx // pin probeCount to max index
501 jl LMsgSendHitHistoIndexSet_$0_$1_$2
502 movl $(CACHE_HISTOGRAM_SIZE-1), %ebx
503 LMsgSendHitHistoIndexSet_$0_$1_$2:
504 LEA_STATIC_DATA %esi, _CacheHitHistogram, EXTERNAL_SYMBOL
505 shll $$2, %ebx // convert probeCount to histogram index
506 addl %ebx, %esi // calculate &CacheHitHistogram[probeCount<<2]
507 movl 0(%esi), %edi // get current tally
509 movl %edi, 0(%esi) // tally += 1
510 LMsgSendHitInstrumentDone_$0_$1_$2:
511 popl %ebx // restore non-volatile register
514 // load implementation address, restore state, and we're done
516 // method triplet is already in eax
518 movl method_imp(%eax), %eax // imp = method->method_imp
521 .if $0 == WORD_RETURN // Regular word return
522 .if $1 == MSG_SENDSUPER // MSG_SENDSUPER
523 // replace "super" arg with "self"
524 movl super+8(%esp), %edi
525 movl receiver(%edi), %esi
526 movl %esi, super+8(%esp)
528 .else // Struct return
529 .if $1 == MSG_SENDSUPER // MSG_SENDSUPER (stret)
530 // replace "super" arg with "self"
531 movl super_stret+8(%esp), %edi
532 movl receiver(%edi), %esi
533 movl %esi, super_stret+8(%esp)
537 // restore caller registers
543 /////////////////////////////////////////////////////////////////////
545 // MethodTableLookup WORD_RETURN | STRUCT_RETURN, MSG_SEND | MSG_SENDSUPER
547 // Takes: WORD_RETURN (first parameter is at sp+4)
548 // STRUCT_RETURN (struct address is at sp+4, first parameter at sp+8)
549 // MSG_SEND (first parameter is receiver)
550 // MSG_SENDSUPER (first parameter is address of objc_super structure)
552 // Stack must be at 0xXXXXXXXc on entrance.
554 // On exit: Register parameters restored from CacheLookup
557 /////////////////////////////////////////////////////////////////////
559 .macro MethodTableLookup
561 subl $$4, %esp // 16-byte align the stack
562 // push args (class, selector)
565 CALL_EXTERN(__class_lookupMethodAndLoadCache)
566 addl $$12, %esp // pop parameters and alignment
570 /********************************************************************
571 * Method _cache_getMethod(Class cls, SEL sel, IMP objc_msgForward_imp)
573 * If found, returns method triplet pointer.
574 * If not found, returns NULL.
576 * NOTE: _cache_getMethod never returns any cache entry whose implementation
577 * is _objc_msgForward. It returns NULL instead. This prevents thread-
578 * safety and memory management bugs in _class_lookupMethodAndLoadCache.
579 * See _class_lookupMethodAndLoadCache for details.
581 * _objc_msgForward is passed as a parameter because it's more efficient
582 * to do the (PIC) lookup once in the caller than repeatedly here.
583 ********************************************************************/
585 .private_extern __cache_getMethod
586 ENTRY __cache_getMethod
588 // load the class and selector
589 movl selector(%esp), %ecx
590 movl self(%esp), %edx
593 CacheLookup WORD_RETURN, CACHE_GET, LGetMethodMiss
595 // cache hit, method triplet in %eax
596 movl first_arg(%esp), %ecx // check for _objc_msgForward
597 cmpl method_imp(%eax), %ecx
598 je LGetMethodMiss // if (imp==_objc_msgForward) return nil
599 ret // else return method triplet address
602 // cache miss, return nil
603 xorl %eax, %eax // zero %eax
607 END_ENTRY __cache_getMethod
610 /********************************************************************
611 * IMP _cache_getImp(Class cls, SEL sel)
613 * If found, returns method implementation.
614 * If not found, returns NULL.
615 ********************************************************************/
617 .private_extern __cache_getImp
620 // load the class and selector
621 movl selector(%esp), %ecx
622 movl self(%esp), %edx
625 CacheLookup WORD_RETURN, CACHE_GET, LGetImpMiss
627 // cache hit, method triplet in %eax
628 movl method_imp(%eax), %eax // return method imp
632 // cache miss, return nil
633 xorl %eax, %eax // zero %eax
637 END_ENTRY __cache_getImp
640 /********************************************************************
642 * id objc_msgSend(id self, SEL _cmd,...);
644 ********************************************************************/
646 ENTRY _objc_msgSend_fixup_rtp
647 // selector(%esp) is address of message ref instead of SEL
648 movl selector(%esp), %edx
650 movl %ecx, selector(%esp) // convert selector
652 END_ENTRY _objc_msgSend_fixup_rtp
657 // load receiver and selector
658 movl selector(%esp), %ecx
659 movl self(%esp), %eax
661 // check whether selector is ignored
663 je LMsgSendDone // return self from %eax
665 // check whether receiver is nil
669 // receiver (in %eax) is non-nil: search the cache
671 movl isa(%eax), %edx // class = self->isa
672 CacheLookup WORD_RETURN, MSG_SEND, LMsgSendCacheMiss
673 movl $kFwdMsgSend, %edx // flag word-return for _objc_msgForward
674 jmp *%eax // goto *imp
676 // cache miss: go search the method lists
678 MethodTableLookup WORD_RETURN, MSG_SEND
679 movl $kFwdMsgSend, %edx // flag word-return for _objc_msgForward
680 jmp *%eax // goto *imp
682 // message sent to nil: redirect to nil receiver, if any
684 call 1f // load new receiver
686 movl __objc_nilReceiver-1b(%edx),%eax
687 testl %eax, %eax // return nil if no new receiver
688 je LMsgSendReturnZero
689 movl %eax, self(%esp) // send to new receiver
690 jmp LMsgSendReceiverOk // receiver must be in %eax
692 // %eax is already zero
697 // guaranteed non-nil entry point (disabled for now)
698 // .globl _objc_msgSendNonNil
699 // _objc_msgSendNonNil:
700 // movl self(%esp), %eax
701 // jmp LMsgSendReceiverOk
704 END_ENTRY _objc_msgSend
706 /********************************************************************
708 * id objc_msgSendSuper(struct objc_super *super, SEL _cmd,...);
710 * struct objc_super {
714 ********************************************************************/
716 ENTRY _objc_msgSendSuper2_fixup_rtp
717 // super(%esp) is objc_super struct with subclass instead of superclass
718 mov super(%esp), %edx // edx = objc_super
719 mov class(%edx), %eax // eax = objc_super->class
720 mov 4(%eax), %eax // eax = objc_super->class->super_class
721 mov %eax, class(%edx) // objc_super->class = eax
722 // selector(%esp) is address of message ref instead of SEL
723 mov selector(%esp), %eax
725 mov %eax, selector(%esp)
726 jmp _objc_msgSendSuper
727 END_ENTRY _objc_msgSendSuper2_fixedup_rtp
729 ENTRY _objc_msgSendSuper
732 // load selector and class to search
733 movl super(%esp), %eax // struct objc_super
734 movl selector(%esp), %ecx
735 movl class(%eax), %edx // struct objc_super->class
737 // check whether selector is ignored
739 je LMsgSendSuperIgnored // return self from %eax
741 // search the cache (class in %edx)
742 CacheLookup WORD_RETURN, MSG_SENDSUPER, LMsgSendSuperCacheMiss
743 movl $kFwdMsgSend, %edx // flag word-return for _objc_msgForward
744 jmp *%eax // goto *imp
746 // cache miss: go search the method lists
747 LMsgSendSuperCacheMiss:
748 MethodTableLookup WORD_RETURN, MSG_SENDSUPER
749 movl $kFwdMsgSend, %edx // flag word-return for _objc_msgForward
750 jmp *%eax // goto *imp
752 // ignored selector: return self
753 LMsgSendSuperIgnored:
754 movl super(%esp), %eax
755 movl receiver(%eax), %eax
759 END_ENTRY _objc_msgSendSuper
761 /********************************************************************
762 * id objc_msgSendv(id self, SEL _cmd, unsigned size, marg_list frame);
765 * (sp+4) is the message receiver,
766 * (sp+8) is the selector,
767 * (sp+12) is the size of the marg_list, in bytes,
768 * (sp+16) is the address of the marg_list
770 ********************************************************************/
775 trap // _objc_msgSendv is not for the kernel
779 // stack is currently aligned assuming no extra arguments
780 movl (marg_list+4)(%ebp), %edx
781 addl $8, %edx // skip self & selector
782 movl (marg_size+4)(%ebp), %ecx
783 subl $8, %ecx // skip self & selector
787 // %esp = %esp - (16 - ((numVariableArguments & 3) << 2))
788 movl %ecx, %eax // 16-byte align stack
796 movl 0(%edx, %ecx, 4), %eax
801 movl (selector+4)(%ebp), %ecx
803 movl (self+4)(%ebp),%ecx
811 END_ENTRY _objc_msgSendv
813 /********************************************************************
815 * double objc_msgSend_fpret(id self, SEL _cmd,...);
817 ********************************************************************/
819 ENTRY _objc_msgSend_fpret_fixup_rtp
820 // selector(%esp) is address of message ref instead of SEL
821 movl selector(%esp), %edx
823 movl %ecx, selector(%esp) // convert selector
824 jmp _objc_msgSend_fpret
825 END_ENTRY _objc_msgSend_fpret_fixup_rtp
827 ENTRY _objc_msgSend_fpret
830 // load receiver and selector
831 movl selector(%esp), %ecx
832 movl self(%esp), %eax
834 // check whether selector is ignored
836 je LMsgSendFpretDone // return self from %eax
838 // check whether receiver is nil
840 je LMsgSendFpretNilSelf
842 // receiver (in %eax) is non-nil: search the cache
843 LMsgSendFpretReceiverOk:
844 movl isa(%eax), %edx // class = self->isa
845 CacheLookup WORD_RETURN, MSG_SEND, LMsgSendFpretCacheMiss
846 movl $kFwdMsgSend, %edx // flag word-return for _objc_msgForward
847 jmp *%eax // goto *imp
849 // cache miss: go search the method lists
850 LMsgSendFpretCacheMiss:
851 MethodTableLookup WORD_RETURN, MSG_SEND
852 movl $kFwdMsgSend, %edx // flag word-return for _objc_msgForward
853 jmp *%eax // goto *imp
855 // message sent to nil: redirect to nil receiver, if any
856 LMsgSendFpretNilSelf:
857 call 1f // load new receiver
859 movl __objc_nilReceiver-1b(%edx),%eax
860 testl %eax, %eax // return zero if no new receiver
861 je LMsgSendFpretReturnZero
862 movl %eax, self(%esp) // send to new receiver
863 jmp LMsgSendFpretReceiverOk // receiver must be in %eax
864 LMsgSendFpretReturnZero:
870 END_ENTRY _objc_msgSend_fpret
872 /********************************************************************
873 * double objc_msgSendv_fpret(id self, SEL _cmd, unsigned size, marg_list frame);
876 * (sp+4) is the message receiver,
877 * (sp+8) is the selector,
878 * (sp+12) is the size of the marg_list, in bytes,
879 * (sp+16) is the address of the marg_list
881 ********************************************************************/
883 ENTRY _objc_msgSendv_fpret
886 trap // _objc_msgSendv is not for the kernel
890 // stack is currently aligned assuming no extra arguments
891 movl (marg_list+4)(%ebp), %edx
892 addl $8, %edx // skip self & selector
893 movl (marg_size+4)(%ebp), %ecx
894 subl $8, %ecx // skip self & selector
896 je LMsgSendvFpretArgsOK
898 // %esp = %esp - (16 - ((numVariableArguments & 3) << 2))
899 movl %ecx, %eax // 16-byte align stack
905 LMsgSendvFpretArgLoop:
907 movl 0(%edx, %ecx, 4), %eax
909 jg LMsgSendvFpretArgLoop
911 LMsgSendvFpretArgsOK:
912 movl (selector+4)(%ebp), %ecx
914 movl (self+4)(%ebp),%ecx
916 call _objc_msgSend_fpret
922 END_ENTRY _objc_msgSendv_fpret
924 /********************************************************************
926 * void objc_msgSend_stret(void *st_addr , id self, SEL _cmd, ...);
929 * objc_msgSend_stret is the struct-return form of msgSend.
930 * The ABI calls for (sp+4) to be used as the address of the structure
931 * being returned, with the parameters in the succeeding locations.
933 * On entry: (sp+4)is the address where the structure is returned,
934 * (sp+8) is the message receiver,
935 * (sp+12) is the selector
936 ********************************************************************/
938 ENTRY _objc_msgSend_stret_fixup_rtp
939 // selector_stret(%esp) is address of message ref instead of SEL
940 movl selector_stret(%esp), %edx
942 movl %ecx, selector_stret(%esp) // convert selector
943 jmp _objc_msgSend_stret
944 END_ENTRY _objc_msgSend_stret_fixup_rtp
946 ENTRY _objc_msgSend_stret
949 // load receiver and selector
950 movl self_stret(%esp), %eax
951 movl (selector_stret)(%esp), %ecx
953 // check whether receiver is nil
955 je LMsgSendStretNilSelf
957 // receiver (in %eax) is non-nil: search the cache
958 LMsgSendStretReceiverOk:
959 movl isa(%eax), %edx // class = self->isa
960 CacheLookup STRUCT_RETURN, MSG_SEND, LMsgSendStretCacheMiss
961 movl $kFwdMsgSendStret, %edx // flag struct-return for _objc_msgForward
962 jmp *%eax // goto *imp
964 // cache miss: go search the method lists
965 LMsgSendStretCacheMiss:
966 MethodTableLookup STRUCT_RETURN, MSG_SEND
967 movl $kFwdMsgSendStret, %edx // flag struct-return for _objc_msgForward
968 jmp *%eax // goto *imp
970 // message sent to nil: redirect to nil receiver, if any
971 LMsgSendStretNilSelf:
972 call 1f // load new receiver
974 movl __objc_nilReceiver-1b(%edx),%eax
975 testl %eax, %eax // return nil if no new receiver
977 movl %eax, self_stret(%esp) // send to new receiver
978 jmp LMsgSendStretReceiverOk // receiver must be in %eax
980 ret $4 // pop struct return address (#2995932)
982 // guaranteed non-nil entry point (disabled for now)
983 // .globl _objc_msgSendNonNil_stret
984 // _objc_msgSendNonNil_stret:
986 // movl self_stret(%esp), %eax
987 // jmp LMsgSendStretReceiverOk
990 END_ENTRY _objc_msgSend_stret
992 /********************************************************************
994 * void objc_msgSendSuper_stret(void *st_addr, struct objc_super *super, SEL _cmd, ...);
996 * struct objc_super {
1001 * objc_msgSendSuper_stret is the struct-return form of msgSendSuper.
1002 * The ABI calls for (sp+4) to be used as the address of the structure
1003 * being returned, with the parameters in the succeeding registers.
1005 * On entry: (sp+4)is the address where the structure is returned,
1006 * (sp+8) is the address of the objc_super structure,
1007 * (sp+12) is the selector
1009 ********************************************************************/
1011 ENTRY _objc_msgSendSuper2_stret_fixup_rtp
1012 // super_stret(%esp) is objc_super with subclass instead of superclass
1013 mov super_stret(%esp), %edx // edx = objc_super
1014 mov class(%edx), %eax // eax = objc_super->class
1015 mov 4(%eax), %eax // eax = objc_super->class->super_class
1016 mov %eax, class(%edx) // objc_super->class = eax
1017 // selector_stret(%esp) is address of message ref instead of SEL
1018 mov selector_stret(%esp), %eax
1020 mov %eax, selector_stret(%esp)
1021 jmp _objc_msgSendSuper_stret
1022 END_ENTRY _objc_msgSendSuper2_stret_fixedup_rtp
1024 ENTRY _objc_msgSendSuper_stret
1027 // load selector and class to search
1028 movl super_stret(%esp), %eax // struct objc_super
1029 movl (selector_stret)(%esp), %ecx // get selector
1030 movl class(%eax), %edx // struct objc_super->class
1032 // search the cache (class in %edx)
1033 CacheLookup STRUCT_RETURN, MSG_SENDSUPER, LMsgSendSuperStretCacheMiss
1034 movl $kFwdMsgSendStret, %edx // flag struct-return for _objc_msgForward
1035 jmp *%eax // goto *imp
1037 // cache miss: go search the method lists
1038 LMsgSendSuperStretCacheMiss:
1039 MethodTableLookup STRUCT_RETURN, MSG_SENDSUPER
1040 movl $kFwdMsgSendStret, %edx // flag struct-return for _objc_msgForward
1041 jmp *%eax // goto *imp
1043 LMsgSendSuperStretExit:
1044 END_ENTRY _objc_msgSendSuper_stret
1047 /********************************************************************
1048 * void objc_msgSendv_stret(void *st_addr, id self, SEL _cmd, unsigned size, marg_list frame);
1050 * objc_msgSendv_stret is the struct-return form of msgSendv.
1051 * This function does not use the struct-return ABI; instead, the
1052 * structure return address is passed as a normal parameter.
1054 * On entry: (sp+4) is the address in which the returned struct is put,
1055 * (sp+8) is the message receiver,
1056 * (sp+12) is the selector,
1057 * (sp+16) is the size of the marg_list, in bytes,
1058 * (sp+20) is the address of the marg_list
1060 ********************************************************************/
1062 ENTRY _objc_msgSendv_stret
1065 trap // _objc_msgSendv_stret is not for the kernel
1069 subl $12, %esp // align stack assuming no extra arguments
1070 movl (marg_list_stret+4)(%ebp), %edx
1071 addl $8, %edx // skip self & selector
1072 movl (marg_size_stret+4)(%ebp), %ecx
1073 subl $5, %ecx // skip self & selector
1075 jle LMsgSendvStretArgsOK
1077 // %esp = %esp - (16 - ((numVariableArguments & 3) << 2))
1078 movl %ecx, %eax // 16-byte align stack
1084 LMsgSendvStretArgLoop:
1086 movl 0(%edx, %ecx, 4), %eax
1088 jg LMsgSendvStretArgLoop
1090 LMsgSendvStretArgsOK:
1091 movl (selector_stret+4)(%ebp), %ecx
1093 movl (self_stret+4)(%ebp),%ecx
1095 movl (struct_addr+4)(%ebp),%ecx
1097 call _objc_msgSend_stret
1103 END_ENTRY _objc_msgSendv_stret
1106 /********************************************************************
1108 * id _objc_msgForward(id self, SEL _cmd,...);
1110 ********************************************************************/
1112 // _FwdSel is @selector(forward::), set up in map_images().
1113 // ALWAYS dereference _FwdSel to get to "forward::" !!
1116 .private_extern _FwdSel
1121 LUnkSelStr: .ascii "Does not recognize selector %s\0"
1125 .private_extern __objc_forward_handler
1126 __objc_forward_handler: .long 0
1130 .private_extern __objc_forward_stret_handler
1131 __objc_forward_stret_handler: .long 0
1134 ENTRY __objc_msgForward
1136 // Check return type (stret or not)
1137 cmpl $kFwdMsgSendStret, %edx
1140 // Get PIC base into %edx
1141 call L__objc_msgForward$pic_base
1142 L__objc_msgForward$pic_base:
1145 // Non-struct return
1147 // Call user handler, if any
1148 movl __objc_forward_handler-L__objc_msgForward$pic_base(%edx),%ecx
1149 testl %ecx, %ecx // if not NULL
1150 je 1f // skip to default handler
1151 jmp *%ecx // call __objc_forward_handler
1158 // Die if forwarding "forward::"
1159 movl (selector+4)(%ebp), %eax
1160 movl _FwdSel-L__objc_msgForward$pic_base(%edx),%ecx
1164 // Call [receiver forward:sel :margs]
1165 subl $8, %esp // 16-byte align the stack
1166 leal (self+4)(%ebp), %ecx
1167 pushl %ecx // &margs
1169 movl _FwdSel-L__objc_msgForward$pic_base(%edx),%ecx
1170 pushl %ecx // forward::
1171 pushl (self+4)(%ebp) // receiver
1180 // Call __objc_error(receiver, "unknown selector %s", "forward::")
1181 subl $12, %esp // 16-byte align the stack
1182 movl _FwdSel-L__objc_msgForward$pic_base(%edx),%eax
1184 leal LUnkSelStr-L__objc_msgForward$pic_base(%edx),%eax
1186 pushl (self+4)(%ebp)
1187 CALL_EXTERN(___objc_error) // never returns
1193 // Get PIC base into %edx
1194 call L__objc_msgForwardStret$pic_base
1195 L__objc_msgForwardStret$pic_base:
1198 // Call user handler, if any
1199 movl __objc_forward_stret_handler-L__objc_msgForwardStret$pic_base(%edx), %ecx
1200 testl %ecx, %ecx // if not NULL
1201 je 1f // skip to default handler
1202 jmp *%ecx // call __objc_forward_stret_handler
1209 // Die if forwarding "forward::"
1210 movl (selector_stret+4)(%ebp), %eax
1211 movl _FwdSel-L__objc_msgForwardStret$pic_base(%edx), %ecx
1213 je LMsgForwardStretError
1215 // Call [receiver forward:sel :margs]
1216 subl $8, %esp // 16-byte align the stack
1217 leal (self_stret+4)(%ebp), %ecx
1218 pushl %ecx // &margs
1220 movl _FwdSel-L__objc_msgForwardStret$pic_base(%edx),%ecx
1221 pushl %ecx // forward::
1222 pushl (self_stret+4)(%ebp) // receiver
1228 ret $4 // pop struct return address (#2995932)
1230 LMsgForwardStretError:
1231 // Call __objc_error(receiver, "unknown selector %s", "forward::")
1232 subl $12, %esp // 16-byte align the stack
1233 leal _FwdSel-L__objc_msgForwardStret$pic_base(%edx),%eax
1235 leal LUnkSelStr-L__objc_msgForwardStret$pic_base(%edx),%eax
1237 pushl (self_stret+4)(%ebp)
1238 CALL_EXTERN(___objc_error) // never returns
1240 END_ENTRY __objc_msgForward
1243 ENTRY _method_invoke
1245 movl selector(%esp), %ecx
1246 movl method_name(%ecx), %edx
1247 movl method_imp(%ecx), %eax
1248 movl %edx, selector(%esp)
1251 END_ENTRY _method_invoke
1254 ENTRY _method_invoke_stret
1256 movl selector_stret(%esp), %ecx
1257 movl method_name(%ecx), %edx
1258 movl method_imp(%ecx), %eax
1259 movl %edx, selector_stret(%esp)
1262 END_ENTRY _method_invoke_stret