2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
25 /********************************************************************
26 ********************************************************************
28 ** objc-msg-i386.s - i386 code to support objc messaging.
30 ********************************************************************
31 ********************************************************************/
33 // The assembler syntax for an immediate value is the same as the
34 // syntax for a macro argument number (dollar sign followed by the
35 // digits). Argument number wins in this ambiguity. Until the
36 // assembler is fixed we have to find another way.
37 #define NO_MACRO_CONSTS
38 #ifdef NO_MACRO_CONSTS
43 /********************************************************************
44 * Data used by the ObjC runtime.
46 ********************************************************************/
49 // Substitute receiver for messages sent to nil (usually also nil)
50 // id _objc_nilReceiver
52 .globl __objc_nilReceiver
56 // _objc_entryPoints and _objc_exitPoints are used by objc
57 // to get the critical regions for which method caches
58 // cannot be garbage collected.
60 .globl _objc_entryPoints
63 .long __cache_getMethod
65 .long _objc_msgSend_stret
66 .long _objc_msgSendSuper
67 .long _objc_msgSendSuper_stret
70 .globl _objc_exitPoints
75 .long LMsgSendStretExit
76 .long LMsgSendSuperExit
77 .long LMsgSendSuperStretExit
81 * Handcrafted dyld stubs for each external call.
82 * They should be converted into a local branch after linking. aB.
85 /* asm_help.h version is not what we want */
88 #if defined(__DYNAMIC__)
90 #define CALL_EXTERN(name) call L ## name ## $stub
92 #define LAZY_PIC_FUNCTION_STUB(name) \
95 L ## name ## $stub: ;\
96 .indirect_symbol name ;\
100 movl L ## name ## $lz-L0$ ## name(%eax),%edx ;\
102 L ## name ## $stub_binder: ;\
103 lea L ## name ## $lz-L0$ ## name(%eax),%eax ;\
105 jmp dyld_stub_binding_helper ;\
107 .lazy_symbol_pointer ;\
109 .indirect_symbol name ;\
110 .long L ## name ## $stub_binder
112 #else /* __DYNAMIC__ */
114 #define CALL_EXTERN(name) call name
116 #define LAZY_PIC_FUNCTION_STUB(name)
118 #endif /* __DYNAMIC__ */
120 // _class_lookupMethodAndLoadCache
121 LAZY_PIC_FUNCTION_STUB(__class_lookupMethodAndLoadCache)
124 LAZY_PIC_FUNCTION_STUB(___objc_error) /* No stub needed */
128 LAZY_PIC_FUNCTION_STUB(mcount)
131 /********************************************************************
135 ********************************************************************/
137 // In case the implementation is _objc_msgForward, indicate to it
138 // whether the method was invoked as a word-return or struct-return.
139 // This flag is passed in a register that is caller-saved, and is
140 // not part of the parameter passing convention (i.e. it is "out of
141 // band"). This works because _objc_msgForward is only entered
142 // from here in the messenger.
147 /********************************************************************
151 ********************************************************************/
169 /********************************************************************
171 * Structure definitions.
173 ********************************************************************/
175 // objc_super parameter to sendSuper
179 // Selected field offsets in class structure
190 buckets = 8 // variable length array
192 #if defined(OBJC_INSTRUMENTED)
193 // Cache instrumentation data, follows buckets
195 hitProbes = hitCount + 4
196 maxHitProbes = hitProbes + 4
197 missCount = maxHitProbes + 4
198 missProbes = missCount + 4
199 maxMissProbes = missProbes + 4
200 flushCount = maxMissProbes + 4
201 flushedEntries = flushCount + 4
203 // Buckets in CacheHitHistogram and CacheMissHistogram
204 CACHE_HISTOGRAM_SIZE = 512
208 //////////////////////////////////////////////////////////////////////
210 // LOAD_STATIC_WORD targetReg, symbolName, LOCAL_SYMBOL | EXTERNAL_SYMBOL
212 // Load the value of the named static data word.
214 // Takes: targetReg - the register, other than r0, to load
215 // symbolName - the name of the symbol
216 // LOCAL_SYMBOL - symbol name used as-is
217 // EXTERNAL_SYMBOL - symbol name gets nonlazy treatment
219 // Eats: edx and targetReg
220 //////////////////////////////////////////////////////////////////////
222 // Values to specify whether the symbol is plain or nonlazy
226 .macro LOAD_STATIC_WORD
228 #if defined(__DYNAMIC__)
231 .if $2 == EXTERNAL_SYMBOL
234 .elseif $2 == LOCAL_SYMBOL
237 !!! Unknown symbol type !!!
245 //////////////////////////////////////////////////////////////////////
247 // LEA_STATIC_DATA targetReg, symbolName, LOCAL_SYMBOL | EXTERNAL_SYMBOL
249 // Load the address of the named static data.
251 // Takes: targetReg - the register, other than edx, to load
252 // symbolName - the name of the symbol
253 // LOCAL_SYMBOL - symbol is local to this module
254 // EXTERNAL_SYMBOL - symbol is imported from another module
256 // Eats: edx and targetReg
257 //////////////////////////////////////////////////////////////////////
259 .macro LEA_STATIC_DATA
260 #if defined(__DYNAMIC__)
263 .if $2 == EXTERNAL_SYMBOL
265 .elseif $2 == LOCAL_SYMBOL
268 !!! Unknown symbol type !!!
276 //////////////////////////////////////////////////////////////////////
278 // ENTRY functionName
280 // Assembly directives to begin an exported function.
282 // Takes: functionName - name of the exported function
283 //////////////////////////////////////////////////////////////////////
292 //////////////////////////////////////////////////////////////////////
294 // END_ENTRY functionName
296 // Assembly directives to end an exported function. Just a placeholder,
297 // a close-parenthesis for ENTRY, until it is needed for something.
299 // Takes: functionName - name of the exported function
300 //////////////////////////////////////////////////////////////////////
305 //////////////////////////////////////////////////////////////////////
307 // CALL_MCOUNTER counterName
309 // Allocate and maintain a counter for the call site.
311 // Takes: counterName - name of counter.
312 //////////////////////////////////////////////////////////////////////
318 LOAD_STATIC_WORD %eax, $0, LOCAL_SYMBOL
331 /////////////////////////////////////////////////////////////////////
334 // CacheLookup WORD_RETURN | STRUCT_RETURN, MSG_SEND | MSG_SENDSUPER | CACHE_GET, cacheMissLabel
336 // Locate the implementation for a selector in a class method cache.
338 // Takes: WORD_RETURN (first parameter is at sp+4)
339 // STRUCT_RETURN (struct address is at sp+4, first parameter at sp+8)
340 // MSG_SEND (first parameter is receiver)
341 // MSG_SENDSUPER (first parameter is address of objc_super structure)
342 // CACHE_GET (first parameter is class; return method triplet)
344 // cacheMissLabel = label to branch to iff method is not cached
346 // On exit: (found) MSG_SEND and MSG_SENDSUPER: return imp in eax
347 // (found) CACHE_GET: return method triplet in eax
348 // (not found) jumps to cacheMissLabel
350 /////////////////////////////////////////////////////////////////////
353 // Values to specify to method lookup macros whether the return type of
354 // the method is word or structure.
358 // Values to specify to method lookup macros whether the first argument
359 // is an object/class reference or a 'objc_super' structure.
360 MSG_SEND = 0 // first argument is receiver, search the isa
361 MSG_SENDSUPER = 1 // first argument is objc_super, search the class
362 CACHE_GET = 2 // first argument is class, search that class
366 // load variables and save caller registers.
367 // Overlapped to prevent AGI
368 .if $0 == WORD_RETURN // Regular word return
369 .if $1 == MSG_SEND // MSG_SEND
370 movl isa(%eax), %eax // class = self->isa
371 movl selector(%esp), %ecx // get selector
372 .elseif $1 == MSG_SENDSUPER // MSG_SENDSUPER
373 movl super(%esp), %eax // get objc_super address
374 movl class(%eax), %eax // class = caller->class
375 movl selector(%esp), %ecx // get selector
377 movl selector(%esp), %ecx // get selector - class already in eax
379 .else // Struct return
380 .if $1 == MSG_SEND // MSG_SEND (stret)
381 movl isa(%eax), %eax // class = self->isa
382 movl (selector_stret)(%esp), %ecx // get selector
383 .elseif $1 == MSG_SENDSUPER // MSG_SENDSUPER (stret)
384 movl super_stret(%esp), %eax // get objc_super address
385 movl class(%eax), %eax // class = caller->class
386 movl (selector_stret)(%esp), %ecx // get selector
388 !! This should not happen.
392 pushl %edi // save scratch register
393 movl cache(%eax), %eax // cache = class->cache
394 pushl %esi // save scratch register
396 #if defined(OBJC_INSTRUMENTED)
397 pushl %ebx // save non-volatile register
398 pushl %eax // save cache pointer
399 xorl %ebx, %ebx // probeCount = 0
401 leal buckets(%eax), %edi // buckets = &cache->buckets
402 movl mask(%eax), %esi // mask = cache->mask
403 movl %ecx, %edx // index = selector
404 #ifdef NO_MACRO_CONSTS
405 shrl $kTwo, %edx // index = selector >> 2
407 shrl $2, %edx // index = selector >> 2
410 // search the receiver's cache
411 LMsgSendProbeCache_$0_$1_$2:
412 #if defined(OBJC_INSTRUMENTED)
413 inc %ebx // probeCount += 1
415 andl %esi, %edx // index &= mask
416 movl (%edi, %edx, 4), %eax // method = buckets[index]
418 testl %eax, %eax // check for end of bucket
419 je LMsgSendCacheMiss_$0_$1_$2 // go to cache miss code
420 cmpl method_name(%eax), %ecx // check for method name match
421 je LMsgSendCacheHit_$0_$1_$2 // go handle cache hit
422 inc %edx // bump index ...
423 jmp LMsgSendProbeCache_$0_$1_$2 // ... and loop
425 // not found in cache: restore state and go to callers handler
426 LMsgSendCacheMiss_$0_$1_$2:
427 #if defined(OBJC_INSTRUMENTED)
428 popl %edx // retrieve cache pointer
429 movl mask(%edx), %esi // mask = cache->mask
430 testl %esi, %esi // a mask of zero is only for the...
431 je LMsgSendMissInstrumentDone_$0_$1_$2 // ... emptyCache, do not record anything
433 // locate and update the CacheInstrumentation structure
434 inc %esi // entryCount = mask + 1
435 #ifdef NO_MACRO_CONSTS
436 shll $kTwo, %esi // tableSize = entryCount * sizeof(entry)
438 shll $2, %esi // tableSize = entryCount * sizeof(entry)
440 addl $buckets, %esi // offset = buckets + tableSize
441 addl %edx, %esi // cacheData = &cache->buckets[mask+1]
443 movl missCount(%esi), %edi //
445 movl %edi, missCount(%esi) // cacheData->missCount += 1
446 movl missProbes(%esi), %edi //
448 movl %edi, missProbes(%esi) // cacheData->missProbes += probeCount
449 movl maxMissProbes(%esi), %edi// if (cacheData->maxMissProbes < probeCount)
451 jge LMsgSendMaxMissProbeOK_$0_$1_$2 //
452 movl %ebx, maxMissProbes(%esi)// cacheData->maxMissProbes = probeCount
453 LMsgSendMaxMissProbeOK_$0_$1_$2:
455 // update cache miss probe histogram
456 cmpl $CACHE_HISTOGRAM_SIZE, %ebx // pin probeCount to max index
457 jl LMsgSendMissHistoIndexSet_$0_$1_$2
458 movl $(CACHE_HISTOGRAM_SIZE-1), %ebx
459 LMsgSendMissHistoIndexSet_$0_$1_$2:
460 LEA_STATIC_DATA %esi, _CacheMissHistogram, EXTERNAL_SYMBOL
461 #ifdef NO_MACRO_CONSTS
462 shll $kTwo, %ebx // convert probeCount to histogram index
464 shll $2, %ebx // convert probeCount to histogram index
466 addl %ebx, %esi // calculate &CacheMissHistogram[probeCount<<2]
467 movl 0(%esi), %edi // get current tally
469 movl %edi, 0(%esi) // tally += 1
470 LMsgSendMissInstrumentDone_$0_$1_$2:
471 popl %ebx // restore non-volatile register
474 .if $0 == WORD_RETURN // Regular word return
475 .if $1 == MSG_SEND // MSG_SEND
476 popl %esi // restore callers register
477 popl %edi // restore callers register
478 movl self(%esp), %eax // get messaged object
479 movl isa(%eax), %eax // get objects class
480 .elseif $1 == MSG_SENDSUPER // MSG_SENDSUPER
481 // replace "super" arg with "receiver"
482 movl super+8(%esp), %edi // get super structure
483 movl receiver(%edi), %esi // get messaged object
484 movl %esi, super+8(%esp) // make it the first argument
485 movl class(%edi), %eax // get messaged class
486 popl %esi // restore callers register
487 popl %edi // restore callers register
489 popl %esi // restore callers register
490 popl %edi // restore callers register
492 .else // Struct return
493 .if $1 == MSG_SEND // MSG_SEND (stret)
494 popl %esi // restore callers register
495 popl %edi // restore callers register
496 movl self_stret(%esp), %eax // get messaged object
497 movl isa(%eax), %eax // get objects class
498 .elseif $1 == MSG_SENDSUPER // MSG_SENDSUPER (stret)
499 // replace "super" arg with "receiver"
500 movl super_stret+8(%esp), %edi// get super structure
501 movl receiver(%edi), %esi // get messaged object
502 movl %esi, super_stret+8(%esp)// make it the first argument
503 movl class(%edi), %eax // get messaged class
504 popl %esi // restore callers register
505 popl %edi // restore callers register
507 !! This should not happen.
511 jmp $2 // go to callers handler
513 // eax points to matching cache entry
515 LMsgSendCacheHit_$0_$1_$2:
516 #if defined(OBJC_INSTRUMENTED)
517 popl %edx // retrieve cache pointer
518 movl mask(%edx), %esi // mask = cache->mask
519 testl %esi, %esi // a mask of zero is only for the...
520 je LMsgSendHitInstrumentDone_$0_$1_$2 // ... emptyCache, do not record anything
522 // locate and update the CacheInstrumentation structure
523 inc %esi // entryCount = mask + 1
524 #ifdef NO_MACRO_CONSTS
525 shll $kTwo, %esi // tableSize = entryCount * sizeof(entry)
527 shll $2, %esi // tableSize = entryCount * sizeof(entry)
529 addl $buckets, %esi // offset = buckets + tableSize
530 addl %edx, %esi // cacheData = &cache->buckets[mask+1]
532 movl hitCount(%esi), %edi
534 movl %edi, hitCount(%esi) // cacheData->hitCount += 1
535 movl hitProbes(%esi), %edi
537 movl %edi, hitProbes(%esi) // cacheData->hitProbes += probeCount
538 movl maxHitProbes(%esi), %edi// if (cacheData->maxHitProbes < probeCount)
540 jge LMsgSendMaxHitProbeOK_$0_$1_$2
541 movl %ebx, maxHitProbes(%esi)// cacheData->maxHitProbes = probeCount
542 LMsgSendMaxHitProbeOK_$0_$1_$2:
544 // update cache hit probe histogram
545 cmpl $CACHE_HISTOGRAM_SIZE, %ebx // pin probeCount to max index
546 jl LMsgSendHitHistoIndexSet_$0_$1_$2
547 movl $(CACHE_HISTOGRAM_SIZE-1), %ebx
548 LMsgSendHitHistoIndexSet_$0_$1_$2:
549 LEA_STATIC_DATA %esi, _CacheHitHistogram, EXTERNAL_SYMBOL
550 #ifdef NO_MACRO_CONSTS
551 shll $kTwo, %ebx // convert probeCount to histogram index
553 shll $2, %ebx // convert probeCount to histogram index
555 addl %ebx, %esi // calculate &CacheHitHistogram[probeCount<<2]
556 movl 0(%esi), %edi // get current tally
558 movl %edi, 0(%esi) // tally += 1
559 LMsgSendHitInstrumentDone_$0_$1_$2:
560 popl %ebx // restore non-volatile register
563 // load implementation address, restore state, and we're done
565 // method triplet is already in eax
567 movl method_imp(%eax), %eax // imp = method->method_imp
570 .if $0 == WORD_RETURN // Regular word return
571 .if $1 == MSG_SENDSUPER // MSG_SENDSUPER
572 // replace "super" arg with "self"
573 movl super+8(%esp), %edi
574 movl receiver(%edi), %esi
575 movl %esi, super+8(%esp)
577 .else // Struct return
578 .if $1 == MSG_SENDSUPER // MSG_SENDSUPER (stret)
579 // replace "super" arg with "self"
580 movl super_stret+8(%esp), %edi
581 movl receiver(%edi), %esi
582 movl %esi, super_stret+8(%esp)
586 // restore caller registers
592 /////////////////////////////////////////////////////////////////////
594 // MethodTableLookup WORD_RETURN | STRUCT_RETURN, MSG_SEND | MSG_SENDSUPER
596 // Takes: WORD_RETURN (first parameter is at sp+4)
597 // STRUCT_RETURN (struct address is at sp+4, first parameter at sp+8)
598 // MSG_SEND (first parameter is receiver)
599 // MSG_SENDSUPER (first parameter is address of objc_super structure)
601 // On exit: Register parameters restored from CacheLookup
604 /////////////////////////////////////////////////////////////////////
606 .macro MethodTableLookup
608 // push args (class, selector)
611 CALL_EXTERN(__class_lookupMethodAndLoadCache)
612 #ifdef NO_MACRO_CONSTS
613 addl $kEight, %esp // pop parameters
615 addl $8, %esp // pop parameters
620 /********************************************************************
621 * Method _cache_getMethod(Class cls, SEL sel, IMP objc_msgForward_imp)
623 * If found, returns method triplet pointer.
624 * If not found, returns NULL.
626 * NOTE: _cache_getMethod never returns any cache entry whose implementation
627 * is _objc_msgForward. It returns NULL instead. This prevents thread-
628 * safety and memory management bugs in _class_lookupMethodAndLoadCache.
629 * See _class_lookupMethodAndLoadCache for details.
631 * _objc_msgForward is passed as a parameter because it's more efficient
632 * to do the (PIC) lookup once in the caller than repeatedly here.
633 ********************************************************************/
635 ENTRY __cache_getMethod
637 // load the class into eax
638 movl self(%esp), %eax
641 CacheLookup WORD_RETURN, CACHE_GET, LGetMethodMiss
643 // cache hit, method triplet in %eax
644 movl first_arg(%esp), %ecx // check for _objc_msgForward
645 cmpl method_imp(%eax), %ecx
646 je LGetMethodMiss // if (imp==_objc_msgForward) return nil
647 ret // else return method triplet address
650 // cache miss, return nil
651 xorl %eax, %eax // zero %eax
655 END_ENTRY __cache_getMethod
658 /********************************************************************
659 * IMP _cache_getImp(Class cls, SEL sel)
661 * If found, returns method implementation.
662 * If not found, returns NULL.
663 ********************************************************************/
667 // load the class into eax
668 movl self(%esp), %eax
671 CacheLookup WORD_RETURN, CACHE_GET, LGetImpMiss
673 // cache hit, method triplet in %eax
674 movl method_imp(%eax), %eax // return method imp
678 // cache miss, return nil
679 xorl %eax, %eax // zero %eax
683 END_ENTRY __cache_getImp
686 /********************************************************************
688 * id objc_msgSend(id self, SEL _cmd,...);
690 ********************************************************************/
695 movl self(%esp), %eax
697 // check whether receiver is nil
701 // receiver is non-nil: search the cache
703 CacheLookup WORD_RETURN, MSG_SEND, LMsgSendCacheMiss
704 movl $kFwdMsgSend, %edx // flag word-return for _objc_msgForward
705 jmp *%eax // goto *imp
707 // cache miss: go search the method lists
709 MethodTableLookup WORD_RETURN, MSG_SEND
710 movl $kFwdMsgSend, %edx // flag word-return for _objc_msgForward
711 jmp *%eax // goto *imp
713 // message sent to nil: redirect to nil receiver, if any
715 call 1f // load new receiver
717 movl __objc_nilReceiver-1b(%edx),%eax
718 testl %eax, %eax // return nil if no new receiver
720 movl %eax, self(%esp) // send to new receiver
721 jmp LMsgSendReceiverOk
725 // guaranteed non-nil entry point (disabled for now)
726 // .globl _objc_msgSendNonNil
727 // _objc_msgSendNonNil:
728 // movl self(%esp), %eax
729 // jmp LMsgSendReceiverOk
732 END_ENTRY _objc_msgSend
734 /********************************************************************
736 * id objc_msgSendSuper(struct objc_super *super, SEL _cmd,...);
738 * struct objc_super {
742 ********************************************************************/
744 ENTRY _objc_msgSendSuper
747 movl super(%esp), %eax
749 // receiver is non-nil: search the cache
750 CacheLookup WORD_RETURN, MSG_SENDSUPER, LMsgSendSuperCacheMiss
751 movl $kFwdMsgSend, %edx // flag word-return for _objc_msgForward
752 jmp *%eax // goto *imp
754 // cache miss: go search the method lists
755 LMsgSendSuperCacheMiss:
756 MethodTableLookup WORD_RETURN, MSG_SENDSUPER
757 movl $kFwdMsgSend, %edx // flag word-return for _objc_msgForward
758 jmp *%eax // goto *imp
761 END_ENTRY _objc_msgSendSuper
763 /********************************************************************
764 * id objc_msgSendv(id self, SEL _cmd, unsigned size, marg_list frame);
767 * (sp+4) is the message receiver,
768 * (sp+8) is the selector,
769 * (sp+12) is the size of the marg_list, in bytes,
770 * (sp+16) is the address of the marg_list
772 ********************************************************************/
777 trap // _objc_msgSendv is not for the kernel
781 movl (marg_list+4)(%ebp), %edx
782 addl $8, %edx // skip self & selector
783 movl (marg_size+4)(%ebp), %ecx
784 subl $5, %ecx // skip self & selector
789 movl 0(%edx, %ecx, 4), %eax
794 movl (selector+4)(%ebp), %ecx
796 movl (self+4)(%ebp),%ecx
804 END_ENTRY _objc_msgSendv
807 /********************************************************************
809 * void objc_msgSend_stret(void *st_addr , id self, SEL _cmd, ...);
812 * objc_msgSend_stret is the struct-return form of msgSend.
813 * The ABI calls for (sp+4) to be used as the address of the structure
814 * being returned, with the parameters in the succeeding locations.
816 * On entry: (sp+4)is the address where the structure is returned,
817 * (sp+8) is the message receiver,
818 * (sp+12) is the selector
819 ********************************************************************/
821 ENTRY _objc_msgSend_stret
824 movl self_stret(%esp), %eax
826 // check whether receiver is nil
828 je LMsgSendStretNilSelf
830 // receiver is non-nil: search the cache
831 LMsgSendStretReceiverOk:
832 CacheLookup STRUCT_RETURN, MSG_SEND, LMsgSendStretCacheMiss
833 movl $kFwdMsgSendStret, %edx // flag struct-return for _objc_msgForward
834 jmp *%eax // goto *imp
836 // cache miss: go search the method lists
837 LMsgSendStretCacheMiss:
838 MethodTableLookup STRUCT_RETURN, MSG_SEND
839 movl $kFwdMsgSendStret, %edx // flag struct-return for _objc_msgForward
840 jmp *%eax // goto *imp
842 // message sent to nil: redirect to nil receiver, if any
843 LMsgSendStretNilSelf:
844 call 1f // load new receiver
846 movl __objc_nilReceiver-1b(%edx),%eax
847 testl %eax, %eax // return nil if no new receiver
849 movl %eax, self_stret(%esp) // send to new receiver
850 jmp LMsgSendStretReceiverOk
852 ret $4 // pop struct return address (#2995932)
854 // guaranteed non-nil entry point (disabled for now)
855 // .globl _objc_msgSendNonNil_stret
856 // _objc_msgSendNonNil_stret:
858 // movl self_stret(%esp), %eax
859 // jmp LMsgSendStretReceiverOk
862 END_ENTRY _objc_msgSend_stret
864 /********************************************************************
866 * void objc_msgSendSuper_stret(void *st_addr, struct objc_super *super, SEL _cmd, ...);
868 * struct objc_super {
873 * objc_msgSendSuper_stret is the struct-return form of msgSendSuper.
874 * The ABI calls for (sp+4) to be used as the address of the structure
875 * being returned, with the parameters in the succeeding registers.
877 * On entry: (sp+4)is the address where the structure is returned,
878 * (sp+8) is the address of the objc_super structure,
879 * (sp+12) is the selector
881 ********************************************************************/
883 ENTRY _objc_msgSendSuper_stret
886 movl super_stret(%esp), %eax
888 // receiver is non-nil: search the cache
889 CacheLookup STRUCT_RETURN, MSG_SENDSUPER, LMsgSendSuperStretCacheMiss
890 movl $kFwdMsgSendStret, %edx // flag struct-return for _objc_msgForward
891 jmp *%eax // goto *imp
893 // cache miss: go search the method lists
894 LMsgSendSuperStretCacheMiss:
895 MethodTableLookup STRUCT_RETURN, MSG_SENDSUPER
896 movl $kFwdMsgSendStret, %edx // flag struct-return for _objc_msgForward
897 jmp *%eax // goto *imp
899 LMsgSendSuperStretExit:
900 END_ENTRY _objc_msgSendSuper_stret
903 /********************************************************************
904 * id objc_msgSendv_stret(void *st_addr, id self, SEL _cmd, unsigned size, marg_list frame);
906 * objc_msgSendv_stret is the struct-return form of msgSendv.
907 * The ABI calls for (sp+4) to be used as the address of the structure
908 * being returned, with the parameters in the succeeding locations.
910 * On entry: (sp+4) is the address in which the returned struct is put,
911 * (sp+8) is the message receiver,
912 * (sp+12) is the selector,
913 * (sp+16) is the size of the marg_list, in bytes,
914 * (sp+20) is the address of the marg_list
916 ********************************************************************/
918 ENTRY _objc_msgSendv_stret
921 trap // _objc_msgSendv_stret is not for the kernel
925 movl (marg_list_stret+4)(%ebp), %edx
926 addl $8, %edx // skip self & selector
927 movl (marg_size_stret+4)(%ebp), %ecx
928 subl $5, %ecx // skip self & selector
930 jle LMsgSendvStretArgsOK
931 LMsgSendvStretArgLoop:
933 movl 0(%edx, %ecx, 4), %eax
935 jg LMsgSendvStretArgLoop
937 LMsgSendvStretArgsOK:
938 movl (selector_stret+4)(%ebp), %ecx
940 movl (self_stret+4)(%ebp),%ecx
942 movl (struct_addr+4)(%ebp),%ecx
944 call _objc_msgSend_stret
950 END_ENTRY _objc_msgSendv_stret
953 /********************************************************************
955 * id _objc_msgForward(id self, SEL _cmd,...);
957 ********************************************************************/
959 // Location LFwdStr contains the string "forward::"
960 // Location LFwdSel contains a pointer to LFwdStr, that can be changed
961 // to point to another forward:: string for selector uniquing
962 // purposes. ALWAYS dereference LFwdSel to get to "forward::" !!
965 LFwdStr:.ascii "forward::\0"
969 LFwdSel:.long LFwdStr
973 LUnkSelStr: .ascii "Does not recognize selector %s\0"
975 ENTRY __objc_msgForward
978 trap // _objc_msgForward is not for the kernel
980 cmpl $kFwdMsgSendStret, %edx // check secret flag for word vs struct return
981 je LForwardStretVersion // jump to struct return version...
983 // non-stret version ...
986 movl (selector+4)(%esp), %eax
987 #if defined(__DYNAMIC__)
988 call L__objc_msgForward$pic_base
989 L__objc_msgForward$pic_base:
991 leal LFwdSel-L__objc_msgForward$pic_base(%edx),%ecx
998 leal (self+4)(%esp), %ecx
1001 #if defined(__DYNAMIC__)
1002 movl LFwdSel-L__objc_msgForward$pic_base(%edx),%ecx
1007 pushl (self+16)(%esp)
1013 // call error handler with unrecognized selector message
1016 #if defined(__DYNAMIC__)
1017 leal LFwdSel-L__objc_msgForward$pic_base(%edx),%eax
1019 leal LUnkSelStr-L__objc_msgForward$pic_base(%edx),%eax
1025 pushl (self+12)(%esp)
1026 CALL_EXTERN(___objc_error) // volatile, will not return
1028 // ***** Stret version of function below
1029 // ***** offsets have been changed (by adding a word to make room for the
1030 // ***** structure, and labels have been changed to be unique.
1032 LForwardStretVersion:
1035 movl (selector_stret+4)(%esp), %eax
1037 #if defined(__DYNAMIC__)
1038 call L__objc_msgForwardStret$pic_base
1039 L__objc_msgForwardStret$pic_base:
1041 leal LFwdSel-L__objc_msgForwardStret$pic_base(%edx),%ecx
1046 je LMsgForwardStretError
1048 leal (self_stret+4)(%esp), %ecx
1051 #if defined(__DYNAMIC__)
1052 movl LFwdSel-L__objc_msgForwardStret$pic_base(%edx),%ecx
1057 pushl (self_stret+16)(%esp)
1061 ret $4 // pop struct return address (#2995932)
1063 // call error handler with unrecognized selector message
1065 LMsgForwardStretError:
1066 #if defined(__DYNAMIC__)
1067 leal LFwdSel-L__objc_msgForwardStret$pic_base(%edx),%eax
1069 leal LUnkSelStr-L__objc_msgForwardStret$pic_base(%edx),%eax
1075 pushl (self_stret+12)(%esp)
1076 CALL_EXTERN(___objc_error) // volatile, will not return
1078 #endif /* defined (KERNEL) */
1079 END_ENTRY __objc_msgForward