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
46 /********************************************************************
47 * Data used by the ObjC runtime.
49 ********************************************************************/
52 // Substitute receiver for messages sent to nil (usually also nil)
53 // id _objc_nilReceiver
55 .globl __objc_nilReceiver
59 // _objc_entryPoints and _objc_exitPoints are used by objc
60 // to get the critical regions for which method caches
61 // cannot be garbage collected.
63 .globl _objc_entryPoints
66 .long __cache_getMethod
68 .long _objc_msgSend_stret
69 .long _objc_msgSendSuper
70 .long _objc_msgSendSuper_stret
73 .globl _objc_exitPoints
78 .long LMsgSendStretExit
79 .long LMsgSendSuperExit
80 .long LMsgSendSuperStretExit
84 #if defined(__DYNAMIC__)
87 * Thunk to retrieve PC.
88 * `call 1; 1: pop` sequence breaks any branch-prediction stack.
99 * Handcrafted dyld stubs for each external call.
100 * They should be converted into a local branch after linking. aB.
103 /* asm_help.h version is not what we want */
106 #if defined(__DYNAMIC__)
108 #define CALL_EXTERN(name) call L ## name ## $stub
110 #define LAZY_PIC_FUNCTION_STUB(name) \
113 L ## name ## $stub: ;\
114 .indirect_symbol name ;\
115 call L_get_pc_thunk.edx ;\
117 movl L ## name ## $lz-L0$ ## name(%edx),%ecx ;\
119 L ## name ## $stub_binder: ;\
120 lea L ## name ## $lz-L0$ ## name(%edx),%eax ;\
122 jmp dyld_stub_binding_helper ;\
125 .lazy_symbol_pointer ;\
127 .indirect_symbol name ;\
128 .long L ## name ## $stub_binder
130 #else /* __DYNAMIC__ */
132 #define CALL_EXTERN(name) call name
134 #define LAZY_PIC_FUNCTION_STUB(name)
136 #endif /* __DYNAMIC__ */
138 // _class_lookupMethodAndLoadCache
139 LAZY_PIC_FUNCTION_STUB(__class_lookupMethodAndLoadCache)
142 LAZY_PIC_FUNCTION_STUB(___objc_error) /* No stub needed */
146 LAZY_PIC_FUNCTION_STUB(mcount)
149 /********************************************************************
153 ********************************************************************/
155 // In case the implementation is _objc_msgForward, indicate to it
156 // whether the method was invoked as a word-return or struct-return.
157 // This flag is passed in a register that is caller-saved, and is
158 // not part of the parameter passing convention (i.e. it is "out of
159 // band"). This works because _objc_msgForward is only entered
160 // from here in the messenger.
165 /********************************************************************
169 ********************************************************************/
187 /********************************************************************
189 * Structure definitions.
191 ********************************************************************/
193 // objc_super parameter to sendSuper
197 // Selected field offsets in class structure
208 buckets = 8 // variable length array
210 #if defined(OBJC_INSTRUMENTED)
211 // Cache instrumentation data, follows buckets
213 hitProbes = hitCount + 4
214 maxHitProbes = hitProbes + 4
215 missCount = maxHitProbes + 4
216 missProbes = missCount + 4
217 maxMissProbes = missProbes + 4
218 flushCount = maxMissProbes + 4
219 flushedEntries = flushCount + 4
221 // Buckets in CacheHitHistogram and CacheMissHistogram
222 CACHE_HISTOGRAM_SIZE = 512
226 //////////////////////////////////////////////////////////////////////
228 // LOAD_STATIC_WORD targetReg, symbolName, LOCAL_SYMBOL | EXTERNAL_SYMBOL
230 // Load the value of the named static data word.
232 // Takes: targetReg - the register, other than r0, to load
233 // symbolName - the name of the symbol
234 // LOCAL_SYMBOL - symbol name used as-is
235 // EXTERNAL_SYMBOL - symbol name gets nonlazy treatment
237 // Eats: edx and targetReg
238 //////////////////////////////////////////////////////////////////////
240 // Values to specify whether the symbol is plain or nonlazy
244 .macro LOAD_STATIC_WORD
246 #if defined(__DYNAMIC__)
247 call L_get_pc_thunk.edx
249 .if $2 == EXTERNAL_SYMBOL
252 .elseif $2 == LOCAL_SYMBOL
255 !!! Unknown symbol type !!!
263 //////////////////////////////////////////////////////////////////////
265 // LEA_STATIC_DATA targetReg, symbolName, LOCAL_SYMBOL | EXTERNAL_SYMBOL
267 // Load the address of the named static data.
269 // Takes: targetReg - the register, other than edx, to load
270 // symbolName - the name of the symbol
271 // LOCAL_SYMBOL - symbol is local to this module
272 // EXTERNAL_SYMBOL - symbol is imported from another module
274 // Eats: edx and targetReg
275 //////////////////////////////////////////////////////////////////////
277 .macro LEA_STATIC_DATA
278 #if defined(__DYNAMIC__)
279 call L_get_pc_thunk.edx
281 .if $2 == EXTERNAL_SYMBOL
283 .elseif $2 == LOCAL_SYMBOL
286 !!! Unknown symbol type !!!
294 //////////////////////////////////////////////////////////////////////
296 // ENTRY functionName
298 // Assembly directives to begin an exported function.
300 // Takes: functionName - name of the exported function
301 //////////////////////////////////////////////////////////////////////
310 //////////////////////////////////////////////////////////////////////
312 // END_ENTRY functionName
314 // Assembly directives to end an exported function. Just a placeholder,
315 // a close-parenthesis for ENTRY, until it is needed for something.
317 // Takes: functionName - name of the exported function
318 //////////////////////////////////////////////////////////////////////
323 //////////////////////////////////////////////////////////////////////
325 // CALL_MCOUNTER counterName
327 // Allocate and maintain a counter for the call site.
329 // Takes: counterName - name of counter.
330 //////////////////////////////////////////////////////////////////////
336 LOAD_STATIC_WORD %eax, $0, LOCAL_SYMBOL
349 /////////////////////////////////////////////////////////////////////
352 // CacheLookup WORD_RETURN | STRUCT_RETURN, MSG_SEND | MSG_SENDSUPER | CACHE_GET, cacheMissLabel
354 // Locate the implementation for a selector in a class method cache.
356 // Takes: WORD_RETURN (first parameter is at sp+4)
357 // STRUCT_RETURN (struct address is at sp+4, first parameter at sp+8)
358 // MSG_SEND (first parameter is receiver)
359 // MSG_SENDSUPER (first parameter is address of objc_super structure)
360 // CACHE_GET (first parameter is class; return method triplet)
362 // cacheMissLabel = label to branch to iff method is not cached
364 // On exit: (found) MSG_SEND and MSG_SENDSUPER: return imp in eax
365 // (found) CACHE_GET: return method triplet in eax
366 // (not found) jumps to cacheMissLabel
368 /////////////////////////////////////////////////////////////////////
371 // Values to specify to method lookup macros whether the return type of
372 // the method is word or structure.
376 // Values to specify to method lookup macros whether the first argument
377 // is an object/class reference or a 'objc_super' structure.
378 MSG_SEND = 0 // first argument is receiver, search the isa
379 MSG_SENDSUPER = 1 // first argument is objc_super, search the class
380 CACHE_GET = 2 // first argument is class, search that class
384 // load variables and save caller registers.
385 // Overlapped to prevent AGI
386 .if $0 == WORD_RETURN // Regular word return
387 .if $1 == MSG_SEND // MSG_SEND
388 movl isa(%eax), %eax // class = self->isa
389 movl selector(%esp), %ecx // get selector
390 .elseif $1 == MSG_SENDSUPER // MSG_SENDSUPER
391 movl super(%esp), %eax // get objc_super address
392 movl class(%eax), %eax // class = caller->class
393 movl selector(%esp), %ecx // get selector
395 movl selector(%esp), %ecx // get selector - class already in eax
397 .else // Struct return
398 .if $1 == MSG_SEND // MSG_SEND (stret)
399 movl isa(%eax), %eax // class = self->isa
400 movl (selector_stret)(%esp), %ecx // get selector
401 .elseif $1 == MSG_SENDSUPER // MSG_SENDSUPER (stret)
402 movl super_stret(%esp), %eax // get objc_super address
403 movl class(%eax), %eax // class = caller->class
404 movl (selector_stret)(%esp), %ecx // get selector
406 !! This should not happen.
410 pushl %edi // save scratch register
411 movl cache(%eax), %eax // cache = class->cache
412 pushl %esi // save scratch register
414 #if defined(OBJC_INSTRUMENTED)
415 pushl %ebx // save non-volatile register
416 pushl %eax // save cache pointer
417 xorl %ebx, %ebx // probeCount = 0
419 leal buckets(%eax), %edi // buckets = &cache->buckets
420 movl mask(%eax), %esi // mask = cache->mask
421 movl %ecx, %edx // index = selector
422 #ifdef NO_MACRO_CONSTS
423 shrl $kTwo, %edx // index = selector >> 2
425 shrl $2, %edx // index = selector >> 2
428 // search the receiver's cache
429 LMsgSendProbeCache_$0_$1_$2:
430 #if defined(OBJC_INSTRUMENTED)
431 addl $kOne, %ebx // probeCount += 1
433 andl %esi, %edx // index &= mask
434 movl (%edi, %edx, 4), %eax // method = buckets[index]
436 testl %eax, %eax // check for end of bucket
437 je LMsgSendCacheMiss_$0_$1_$2 // go to cache miss code
438 cmpl method_name(%eax), %ecx // check for method name match
439 je LMsgSendCacheHit_$0_$1_$2 // go handle cache hit
440 addl $kOne, %edx // bump index ...
441 jmp LMsgSendProbeCache_$0_$1_$2 // ... and loop
443 // not found in cache: restore state and go to callers handler
444 LMsgSendCacheMiss_$0_$1_$2:
445 #if defined(OBJC_INSTRUMENTED)
446 popl %edx // retrieve cache pointer
447 movl mask(%edx), %esi // mask = cache->mask
448 testl %esi, %esi // a mask of zero is only for the...
449 je LMsgSendMissInstrumentDone_$0_$1_$2 // ... emptyCache, do not record anything
451 // locate and update the CacheInstrumentation structure
452 addl $kOne, %esi // entryCount = mask + 1
453 #ifdef NO_MACRO_CONSTS
454 shll $kTwo, %esi // tableSize = entryCount * sizeof(entry)
456 shll $2, %esi // tableSize = entryCount * sizeof(entry)
458 addl $buckets, %esi // offset = buckets + tableSize
459 addl %edx, %esi // cacheData = &cache->buckets[mask+1]
461 movl missCount(%esi), %edi //
463 movl %edi, missCount(%esi) // cacheData->missCount += 1
464 movl missProbes(%esi), %edi //
466 movl %edi, missProbes(%esi) // cacheData->missProbes += probeCount
467 movl maxMissProbes(%esi), %edi// if (cacheData->maxMissProbes < probeCount)
469 jge LMsgSendMaxMissProbeOK_$0_$1_$2 //
470 movl %ebx, maxMissProbes(%esi)// cacheData->maxMissProbes = probeCount
471 LMsgSendMaxMissProbeOK_$0_$1_$2:
473 // update cache miss probe histogram
474 cmpl $CACHE_HISTOGRAM_SIZE, %ebx // pin probeCount to max index
475 jl LMsgSendMissHistoIndexSet_$0_$1_$2
476 movl $(CACHE_HISTOGRAM_SIZE-1), %ebx
477 LMsgSendMissHistoIndexSet_$0_$1_$2:
478 LEA_STATIC_DATA %esi, _CacheMissHistogram, EXTERNAL_SYMBOL
479 #ifdef NO_MACRO_CONSTS
480 shll $kTwo, %ebx // convert probeCount to histogram index
482 shll $2, %ebx // convert probeCount to histogram index
484 addl %ebx, %esi // calculate &CacheMissHistogram[probeCount<<2]
485 movl 0(%esi), %edi // get current tally
487 movl %edi, 0(%esi) // tally += 1
488 LMsgSendMissInstrumentDone_$0_$1_$2:
489 popl %ebx // restore non-volatile register
492 .if $0 == WORD_RETURN // Regular word return
493 .if $1 == MSG_SEND // MSG_SEND
494 popl %esi // restore callers register
495 popl %edi // restore callers register
496 movl self(%esp), %eax // get messaged object
497 movl isa(%eax), %eax // get objects class
498 .elseif $1 == MSG_SENDSUPER // MSG_SENDSUPER
499 // replace "super" arg with "receiver"
500 movl super+8(%esp), %edi // get super structure
501 movl receiver(%edi), %esi // get messaged object
502 movl %esi, super+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 popl %esi // restore callers register
508 popl %edi // restore callers register
510 .else // Struct return
511 .if $1 == MSG_SEND // MSG_SEND (stret)
512 popl %esi // restore callers register
513 popl %edi // restore callers register
514 movl self_stret(%esp), %eax // get messaged object
515 movl isa(%eax), %eax // get objects class
516 .elseif $1 == MSG_SENDSUPER // MSG_SENDSUPER (stret)
517 // replace "super" arg with "receiver"
518 movl super_stret+8(%esp), %edi// get super structure
519 movl receiver(%edi), %esi // get messaged object
520 movl %esi, super_stret+8(%esp)// make it the first argument
521 movl class(%edi), %eax // get messaged class
522 popl %esi // restore callers register
523 popl %edi // restore callers register
525 !! This should not happen.
529 jmp $2 // go to callers handler
531 // eax points to matching cache entry
533 LMsgSendCacheHit_$0_$1_$2:
534 #if defined(OBJC_INSTRUMENTED)
535 popl %edx // retrieve cache pointer
536 movl mask(%edx), %esi // mask = cache->mask
537 testl %esi, %esi // a mask of zero is only for the...
538 je LMsgSendHitInstrumentDone_$0_$1_$2 // ... emptyCache, do not record anything
540 // locate and update the CacheInstrumentation structure
541 addl $kOne, %esi // entryCount = mask + 1
542 #ifdef NO_MACRO_CONSTS
543 shll $kTwo, %esi // tableSize = entryCount * sizeof(entry)
545 shll $2, %esi // tableSize = entryCount * sizeof(entry)
547 addl $buckets, %esi // offset = buckets + tableSize
548 addl %edx, %esi // cacheData = &cache->buckets[mask+1]
550 movl hitCount(%esi), %edi
552 movl %edi, hitCount(%esi) // cacheData->hitCount += 1
553 movl hitProbes(%esi), %edi
555 movl %edi, hitProbes(%esi) // cacheData->hitProbes += probeCount
556 movl maxHitProbes(%esi), %edi// if (cacheData->maxHitProbes < probeCount)
558 jge LMsgSendMaxHitProbeOK_$0_$1_$2
559 movl %ebx, maxHitProbes(%esi)// cacheData->maxHitProbes = probeCount
560 LMsgSendMaxHitProbeOK_$0_$1_$2:
562 // update cache hit probe histogram
563 cmpl $CACHE_HISTOGRAM_SIZE, %ebx // pin probeCount to max index
564 jl LMsgSendHitHistoIndexSet_$0_$1_$2
565 movl $(CACHE_HISTOGRAM_SIZE-1), %ebx
566 LMsgSendHitHistoIndexSet_$0_$1_$2:
567 LEA_STATIC_DATA %esi, _CacheHitHistogram, EXTERNAL_SYMBOL
568 #ifdef NO_MACRO_CONSTS
569 shll $kTwo, %ebx // convert probeCount to histogram index
571 shll $2, %ebx // convert probeCount to histogram index
573 addl %ebx, %esi // calculate &CacheHitHistogram[probeCount<<2]
574 movl 0(%esi), %edi // get current tally
576 movl %edi, 0(%esi) // tally += 1
577 LMsgSendHitInstrumentDone_$0_$1_$2:
578 popl %ebx // restore non-volatile register
581 // load implementation address, restore state, and we're done
583 // method triplet is already in eax
585 movl method_imp(%eax), %eax // imp = method->method_imp
588 .if $0 == WORD_RETURN // Regular word return
589 .if $1 == MSG_SENDSUPER // MSG_SENDSUPER
590 // replace "super" arg with "self"
591 movl super+8(%esp), %edi
592 movl receiver(%edi), %esi
593 movl %esi, super+8(%esp)
595 .else // Struct return
596 .if $1 == MSG_SENDSUPER // MSG_SENDSUPER (stret)
597 // replace "super" arg with "self"
598 movl super_stret+8(%esp), %edi
599 movl receiver(%edi), %esi
600 movl %esi, super_stret+8(%esp)
604 // restore caller registers
610 /////////////////////////////////////////////////////////////////////
612 // MethodTableLookup WORD_RETURN | STRUCT_RETURN, MSG_SEND | MSG_SENDSUPER
614 // Takes: WORD_RETURN (first parameter is at sp+4)
615 // STRUCT_RETURN (struct address is at sp+4, first parameter at sp+8)
616 // MSG_SEND (first parameter is receiver)
617 // MSG_SENDSUPER (first parameter is address of objc_super structure)
619 // Stack must be at 0xXXXXXXXc on entrance.
621 // On exit: Register parameters restored from CacheLookup
624 /////////////////////////////////////////////////////////////////////
626 .macro MethodTableLookup
628 #ifdef NO_MACRO_CONSTS
629 subl $kFour, %esp // 16-byte align the stack
631 subl $4, %esp // 16-byte align the stack
633 // push args (class, selector)
636 CALL_EXTERN(__class_lookupMethodAndLoadCache)
637 #ifdef NO_MACRO_CONSTS
638 addl $kTwelve, %esp // pop parameters and alignment
640 addl $12, %esp // pop parameters and alignment
645 /********************************************************************
646 * Method _cache_getMethod(Class cls, SEL sel, IMP objc_msgForward_imp)
648 * If found, returns method triplet pointer.
649 * If not found, returns NULL.
651 * NOTE: _cache_getMethod never returns any cache entry whose implementation
652 * is _objc_msgForward. It returns NULL instead. This prevents thread-
653 * safety and memory management bugs in _class_lookupMethodAndLoadCache.
654 * See _class_lookupMethodAndLoadCache for details.
656 * _objc_msgForward is passed as a parameter because it's more efficient
657 * to do the (PIC) lookup once in the caller than repeatedly here.
658 ********************************************************************/
660 ENTRY __cache_getMethod
662 // load the class into eax
663 movl self(%esp), %eax
666 CacheLookup WORD_RETURN, CACHE_GET, LGetMethodMiss
668 // cache hit, method triplet in %eax
669 movl first_arg(%esp), %ecx // check for _objc_msgForward
670 cmpl method_imp(%eax), %ecx
671 je LGetMethodMiss // if (imp==_objc_msgForward) return nil
672 ret // else return method triplet address
675 // cache miss, return nil
676 xorl %eax, %eax // zero %eax
680 END_ENTRY __cache_getMethod
683 /********************************************************************
684 * IMP _cache_getImp(Class cls, SEL sel)
686 * If found, returns method implementation.
687 * If not found, returns NULL.
688 ********************************************************************/
692 // load the class into eax
693 movl self(%esp), %eax
696 CacheLookup WORD_RETURN, CACHE_GET, LGetImpMiss
698 // cache hit, method triplet in %eax
699 movl method_imp(%eax), %eax // return method imp
703 // cache miss, return nil
704 xorl %eax, %eax // zero %eax
708 END_ENTRY __cache_getImp
711 /********************************************************************
713 * id objc_msgSend(id self, SEL _cmd,...);
715 ********************************************************************/
720 movl self(%esp), %eax
722 // check whether receiver is nil
726 // receiver is non-nil: search the cache
728 CacheLookup WORD_RETURN, MSG_SEND, LMsgSendCacheMiss
729 movl $kFwdMsgSend, %edx // flag word-return for _objc_msgForward
730 jmp *%eax // goto *imp
732 // cache miss: go search the method lists
734 MethodTableLookup WORD_RETURN, MSG_SEND
735 movl $kFwdMsgSend, %edx // flag word-return for _objc_msgForward
736 jmp *%eax // goto *imp
738 // message sent to nil: redirect to nil receiver, if any
740 call L_get_pc_thunk.edx // load new receiver
741 1: movl __objc_nilReceiver-1b(%edx),%eax
742 testl %eax, %eax // return nil if no new receiver
744 movl %eax, self(%esp) // send to new receiver
745 jmp LMsgSendReceiverOk
749 // guaranteed non-nil entry point (disabled for now)
750 // .globl _objc_msgSendNonNil
751 // _objc_msgSendNonNil:
752 // movl self(%esp), %eax
753 // jmp LMsgSendReceiverOk
756 END_ENTRY _objc_msgSend
758 /********************************************************************
760 * id objc_msgSendSuper(struct objc_super *super, SEL _cmd,...);
762 * struct objc_super {
766 ********************************************************************/
768 ENTRY _objc_msgSendSuper
771 movl super(%esp), %eax
773 // receiver is non-nil: search the cache
774 CacheLookup WORD_RETURN, MSG_SENDSUPER, LMsgSendSuperCacheMiss
775 movl $kFwdMsgSend, %edx // flag word-return for _objc_msgForward
776 jmp *%eax // goto *imp
778 // cache miss: go search the method lists
779 LMsgSendSuperCacheMiss:
780 MethodTableLookup WORD_RETURN, MSG_SENDSUPER
781 movl $kFwdMsgSend, %edx // flag word-return for _objc_msgForward
782 jmp *%eax // goto *imp
785 END_ENTRY _objc_msgSendSuper
787 /********************************************************************
788 * id objc_msgSendv(id self, SEL _cmd, unsigned size, marg_list frame);
791 * (sp+4) is the message receiver,
792 * (sp+8) is the selector,
793 * (sp+12) is the size of the marg_list, in bytes,
794 * (sp+16) is the address of the marg_list
796 ********************************************************************/
801 trap // _objc_msgSendv is not for the kernel
805 movl (marg_list+4)(%ebp), %edx
806 addl $8, %edx // skip self & selector
807 movl (marg_size+4)(%ebp), %ecx
808 subl $8, %ecx // skip self & selector
812 // %esp = %esp - (16 - ((numVariableArguments && 3) << 2))
813 movl %ecx, %eax // 16-byte align stack
822 movl 0(%edx, %ecx, 4), %eax
827 movl (selector+4)(%ebp), %ecx
829 movl (self+4)(%ebp),%ecx
837 END_ENTRY _objc_msgSendv
840 /********************************************************************
842 * void objc_msgSend_stret(void *st_addr , id self, SEL _cmd, ...);
845 * objc_msgSend_stret is the struct-return form of msgSend.
846 * The ABI calls for (sp+4) to be used as the address of the structure
847 * being returned, with the parameters in the succeeding locations.
849 * On entry: (sp+4)is the address where the structure is returned,
850 * (sp+8) is the message receiver,
851 * (sp+12) is the selector
852 ********************************************************************/
854 ENTRY _objc_msgSend_stret
857 movl self_stret(%esp), %eax
859 // check whether receiver is nil
861 je LMsgSendStretNilSelf
863 // receiver is non-nil: search the cache
864 LMsgSendStretReceiverOk:
865 CacheLookup STRUCT_RETURN, MSG_SEND, LMsgSendStretCacheMiss
866 movl $kFwdMsgSendStret, %edx // flag struct-return for _objc_msgForward
867 jmp *%eax // goto *imp
869 // cache miss: go search the method lists
870 LMsgSendStretCacheMiss:
871 MethodTableLookup STRUCT_RETURN, MSG_SEND
872 movl $kFwdMsgSendStret, %edx // flag struct-return for _objc_msgForward
873 jmp *%eax // goto *imp
875 // message sent to nil: redirect to nil receiver, if any
876 LMsgSendStretNilSelf:
877 call L_get_pc_thunk.edx // load new receiver
878 1: movl __objc_nilReceiver-1b(%edx),%eax
879 testl %eax, %eax // return nil if no new receiver
881 movl %eax, self_stret(%esp) // send to new receiver
882 jmp LMsgSendStretReceiverOk
884 ret $4 // pop struct return address (#2995932)
886 // guaranteed non-nil entry point (disabled for now)
887 // .globl _objc_msgSendNonNil_stret
888 // _objc_msgSendNonNil_stret:
890 // movl self_stret(%esp), %eax
891 // jmp LMsgSendStretReceiverOk
894 END_ENTRY _objc_msgSend_stret
896 /********************************************************************
898 * void objc_msgSendSuper_stret(void *st_addr, struct objc_super *super, SEL _cmd, ...);
900 * struct objc_super {
905 * objc_msgSendSuper_stret is the struct-return form of msgSendSuper.
906 * The ABI calls for (sp+4) to be used as the address of the structure
907 * being returned, with the parameters in the succeeding registers.
909 * On entry: (sp+4)is the address where the structure is returned,
910 * (sp+8) is the address of the objc_super structure,
911 * (sp+12) is the selector
913 ********************************************************************/
915 ENTRY _objc_msgSendSuper_stret
918 movl super_stret(%esp), %eax
920 // receiver is non-nil: search the cache
921 CacheLookup STRUCT_RETURN, MSG_SENDSUPER, LMsgSendSuperStretCacheMiss
922 movl $kFwdMsgSendStret, %edx // flag struct-return for _objc_msgForward
923 jmp *%eax // goto *imp
925 // cache miss: go search the method lists
926 LMsgSendSuperStretCacheMiss:
927 MethodTableLookup STRUCT_RETURN, MSG_SENDSUPER
928 movl $kFwdMsgSendStret, %edx // flag struct-return for _objc_msgForward
929 jmp *%eax // goto *imp
931 LMsgSendSuperStretExit:
932 END_ENTRY _objc_msgSendSuper_stret
935 /********************************************************************
936 * id objc_msgSendv_stret(void *st_addr, id self, SEL _cmd, unsigned size, marg_list frame);
938 * objc_msgSendv_stret is the struct-return form of msgSendv.
939 * The ABI calls for (sp+4) to be used as the address of the structure
940 * being returned, with the parameters in the succeeding locations.
942 * On entry: (sp+4) is the address in which the returned struct is put,
943 * (sp+8) is the message receiver,
944 * (sp+12) is the selector,
945 * (sp+16) is the size of the marg_list, in bytes,
946 * (sp+20) is the address of the marg_list
948 ********************************************************************/
950 ENTRY _objc_msgSendv_stret
953 trap // _objc_msgSendv_stret is not for the kernel
957 movl (marg_list_stret+4)(%ebp), %edx
958 addl $8, %edx // skip self & selector
959 movl (marg_size_stret+4)(%ebp), %ecx
960 subl $5, %ecx // skip self & selector
962 jle LMsgSendvStretArgsOK
964 movl %ecx, %eax // 16-byte align stack
970 LMsgSendvStretArgLoop:
972 movl 0(%edx, %ecx, 4), %eax
974 jg LMsgSendvStretArgLoop
976 LMsgSendvStretArgsOK:
977 movl (selector_stret+4)(%ebp), %ecx
979 movl (self_stret+4)(%ebp),%ecx
981 movl (struct_addr+4)(%ebp),%ecx
983 call _objc_msgSend_stret
989 END_ENTRY _objc_msgSendv_stret
992 /********************************************************************
994 * id _objc_msgForward(id self, SEL _cmd,...);
996 ********************************************************************/
998 // Location LFwdStr contains the string "forward::"
999 // Location LFwdSel contains a pointer to LFwdStr, that can be changed
1000 // to point to another forward:: string for selector uniquing
1001 // purposes. ALWAYS dereference LFwdSel to get to "forward::" !!
1002 .objc_meth_var_names
1004 LFwdStr:.ascii "forward::\0"
1008 LFwdSel:.long LFwdStr
1012 LUnkSelStr: .ascii "Does not recognize selector %s\0"
1014 ENTRY __objc_msgForward
1017 trap // _objc_msgForward is not for the kernel
1019 cmpl $kFwdMsgSendStret, %edx // check secret flag for word vs struct return
1020 je LForwardStretVersion // jump to struct return version...
1022 // non-stret version ...
1025 movl (selector+4)(%ebp), %eax
1026 #if defined(__DYNAMIC__)
1027 call L_get_pc_thunk.edx
1028 L__objc_msgForward$pic_base:
1029 leal LFwdSel-L__objc_msgForward$pic_base(%edx),%ecx
1036 subl $8, %esp // 16-byte align the stack
1037 leal (self+4)(%ebp), %ecx
1040 #if defined(__DYNAMIC__)
1041 movl LFwdSel-L__objc_msgForward$pic_base(%edx),%ecx
1046 pushl (self+4)(%ebp)
1052 // call error handler with unrecognized selector message
1055 subl $12, %esp // 16-byte align the stack
1056 #if defined(__DYNAMIC__)
1057 leal LFwdSel-L__objc_msgForward$pic_base(%edx),%eax
1059 leal LUnkSelStr-L__objc_msgForward$pic_base(%edx),%eax
1065 pushl (self+4)(%ebp)
1066 CALL_EXTERN(___objc_error) // volatile, will not return
1068 // ***** Stret version of function below
1069 // ***** offsets have been changed (by adding a word to make room for the
1070 // ***** structure, and labels have been changed to be unique.
1072 LForwardStretVersion:
1075 movl (selector_stret+4)(%ebp), %eax
1077 #if defined(__DYNAMIC__)
1078 call L_get_pc_thunk.edx
1079 L__objc_msgForwardStret$pic_base:
1080 leal LFwdSel-L__objc_msgForwardStret$pic_base(%edx),%ecx
1085 je LMsgForwardStretError
1087 subl $8, %esp // 16-byte align the stack
1088 leal (self_stret+4)(%ebp), %ecx
1091 #if defined(__DYNAMIC__)
1092 movl LFwdSel-L__objc_msgForwardStret$pic_base(%edx),%ecx
1097 pushl (self_stret+4)(%ebp)
1101 ret $4 // pop struct return address (#2995932)
1103 // call error handler with unrecognized selector message
1105 LMsgForwardStretError:
1106 subl $12, %esp // 16-byte align the stack
1107 #if defined(__DYNAMIC__)
1108 leal LFwdSel-L__objc_msgForwardStret$pic_base(%edx),%eax
1110 leal LUnkSelStr-L__objc_msgForwardStret$pic_base(%edx),%eax
1116 pushl (self_stret+4)(%ebp)
1117 CALL_EXTERN(___objc_error) // volatile, will not return
1119 #endif /* defined (KERNEL) */
1120 END_ENTRY __objc_msgForward
1123 // Special section containing a function pointer that dyld will call
1124 // when it loads new images.
1125 LAZY_PIC_FUNCTION_STUB(__objc_notify_images)
1127 .section __DATA,__image_notify
1128 .long L__objc_notify_images$stub