]> git.saurik.com Git - apple/objc4.git/blobdiff - runtime/Messengers.subproj/objc-msg-simulator-i386.s
objc4-709.1.tar.gz
[apple/objc4.git] / runtime / Messengers.subproj / objc-msg-simulator-i386.s
index 431a4839c525db39bd3ea6d2dbfd1f93faf56370..beb7ac5f6d1877cc4dc08709565c229548e7f6e6 100644 (file)
@@ -22,7 +22,7 @@
  */
 
 #include <TargetConditionals.h>
-#if defined(__i386__)  &&  TARGET_IPHONE_SIMULATOR
+#if defined(__i386__)  &&  TARGET_OS_SIMULATOR
 
 #include "objc-config.h"
 
@@ -32,6 +32,7 @@
 // to get the critical regions for which method caches 
 // cannot be garbage collected.
 
+.align 2
 .private_extern _objc_entryPoints
 _objc_entryPoints:
        .long   _cache_getImp
@@ -42,18 +43,28 @@ _objc_entryPoints:
        .long   _objc_msgSendSuper2
        .long   _objc_msgSendSuper_stret
        .long   _objc_msgSendSuper2_stret
+       .long   _objc_msgLookup
+       .long   _objc_msgLookup_fpret
+       .long   _objc_msgLookup_stret
+       .long   _objc_msgLookupSuper2
+       .long   _objc_msgLookupSuper2_stret
        .long   0
 
 .private_extern _objc_exitPoints
 _objc_exitPoints:
-       .long   LGetImpExit
-       .long   LMsgSendExit
-       .long   LMsgSendFpretExit
-       .long   LMsgSendStretExit
-       .long   LMsgSendSuperExit
-       .long   LMsgSendSuper2Exit
-       .long   LMsgSendSuperStretExit
-       .long   LMsgSendSuper2StretExit
+       .long   LExit_cache_getImp
+       .long   LExit_objc_msgSend
+       .long   LExit_objc_msgSend_fpret
+       .long   LExit_objc_msgSend_stret
+       .long   LExit_objc_msgSendSuper
+       .long   LExit_objc_msgSendSuper2
+       .long   LExit_objc_msgSendSuper_stret
+       .long   LExit_objc_msgSendSuper2_stret
+       .long   LExit_objc_msgLookup
+       .long   LExit_objc_msgLookup_fpret
+       .long   LExit_objc_msgLookup_stret
+       .long   LExit_objc_msgLookupSuper2
+       .long   LExit_objc_msgLookupSuper2_stret
        .long   0
 
 
@@ -138,12 +149,14 @@ _gdb_objc_messenger_breakpoints:
  * Macro parameters
  ********************************************************************/
 
+
 #define NORMAL 0
 #define FPRET 1
-#define GETIMP 3
-#define STRET 4
-#define SUPER 5
-#define SUPER_STRET 6
+#define STRET 2
+
+#define CALL 100
+#define GETIMP 101
+#define LOOKUP 102
 
 
 /********************************************************************
@@ -215,17 +228,38 @@ $0:
 //////////////////////////////////////////////////////////////////////
 
 .macro END_ENTRY
+LExit$0:
 .endmacro
 
 
+ /********************************************************************
+ * UNWIND name, flags
+ * Unwind info generation      
+ ********************************************************************/
+.macro UNWIND
+       .section __LD,__compact_unwind,regular,debug
+       .long $0
+       .set  LUnwind$0, LExit$0 - $0
+       .long LUnwind$0
+       .long $1
+       .long 0  /* no personality */
+       .long 0  /* no LSDA */
+       .text
+.endmacro
+
+#define NoFrame 0x02010000  // no frame, no SP adjustment except return address
+#define FrameWithNoSaves 0x01000000  // frame, no non-volatile saves
+
+
 /////////////////////////////////////////////////////////////////////
 //
-// CacheLookup return-type
+// CacheLookup return-type, caller
 //
 // Locate the implementation for a selector in a class method cache.
 //
 // Takes: 
-//       $0 = NORMAL, FPRET, STRET, SUPER, SUPER_STRET, GETIMP
+//       $0 = NORMAL, FPRET, STRET
+//       $1 = CALL, LOOKUP, GETIMP
 //       ecx = selector to search for
 //       edx = class to search
 //
@@ -240,43 +274,34 @@ $0:
        // CacheHit must always be preceded by a not-taken `jne` instruction
        // in case the imp is _objc_msgForward_impcache.
 
-.if $0 == GETIMP
+       // eax = found bucket
+       
+.if $1 == GETIMP
        movl    4(%eax), %eax           // return imp
-       call    4f
-4:     pop     %edx
-       leal    __objc_msgSend_uncached_impcache-4b(%edx), %edx
-       cmpl    %edx, %eax
-       jne     4f
-       xor     %eax, %eax              // don't return msgSend_uncached
-4:     ret
-.elseif $0 == NORMAL  ||  $0 == FPRET
+       ret
+
+.else
+
+.if $0 != STRET
        // eq already set for forwarding by `jne`
-       MESSENGER_END_FAST
-       jmp     *4(%eax)                // call imp
-.elseif $0 == STRET
-       test    %eax, %eax              // set ne for stret forwarding
-       MESSENGER_END_FAST
-       jmp     *4(%eax)                // call imp
-.elseif $0 == SUPER    
-       // replace "super" arg with "receiver"
-       movl    super(%esp), %ecx       // get super structure
-       movl    receiver(%ecx), %ecx    // get messaged object
-       movl    %ecx, super(%esp)       // make it the first argument
-       cmp     %eax, %eax              // set eq for non-stret forwarding
-       MESSENGER_END_FAST
-       jmp     *4(%eax)                // call imp
-.elseif $0 == SUPER_STRET
-       // replace "super" arg with "receiver"
-       movl    super_stret(%esp), %ecx // get super structure
-       movl    receiver(%ecx), %ecx    // get messaged object
-       movl    %ecx, super_stret(%esp) // make it the first argument
+.else
        test    %eax, %eax              // set ne for stret forwarding
+.endif
+
+.if $1 == CALL
        MESSENGER_END_FAST
        jmp     *4(%eax)                // call imp
+
+.elseif $1 == LOOKUP
+       movl    4(%eax), %eax           // return imp
+       ret
+
 .else
 .abort oops
 .endif
 
+.endif
+
 .endmacro
 
 
@@ -289,81 +314,100 @@ $0:
        cmpl    (%eax), %ecx            // if (bucket->sel != SEL)
        jne     1f                      //     scan more
        // The `jne` above sets flags for CacheHit
-       CacheHit $0                     // call or return imp
+       CacheHit $0, $1                 // call or return imp
 
 1:
        // loop
        cmpl    $$1, (%eax)
-       je      3f                      // if (bucket->sel == 1) cache wrap
-       jb      LCacheMiss_f            // if (bucket->sel == 0) cache miss
+       jbe     3f                      // if (bucket->sel <= 1) wrap or miss
        
        addl    $$8, %eax               // bucket++
 2:
        cmpl    (%eax), %ecx            // if (bucket->sel != sel)
        jne     1b                      //     scan more
        // The `jne` above sets flags for CacheHit
-       CacheHit $0                     // call or return imp
+       CacheHit $0, $1                 // call or return imp
 
 3:     
+       // wrap or miss
+       jb      LCacheMiss_f            // if (bucket->sel < 1) cache miss
        // wrap
-       // eax is last bucket, bucket->imp is first bucket
-       movl    4(%eax), %eax
-       jmp     2b
+       movl    4(%eax), %eax           // bucket->imp is really first bucket
+       jmp     2f
+
+       // Clone scanning loop to miss instead of hang when cache is corrupt.
+       // The slow path may detect any corruption and halt later.
+
+1:
+       // loop
+       cmpq    $$1, (%eax)
+       jbe     3f                      // if (bucket->sel <= 1) wrap or miss
+       
+       addl    $$8, %eax               // bucket++
+2:
+       cmpl    (%eax), %ecx            // if (bucket->sel != sel)
+       jne     1b                      //     scan more
+       // The `jne` above sets flags for CacheHit
+       CacheHit $0, $1                 // call or return imp
 
+3:     
+       // double wrap or miss
+       jmp     LCacheMiss_f
+       
 .endmacro
 
 
 /////////////////////////////////////////////////////////////////////
 //
-// MethodTableLookup
+// MethodTableLookup NORMAL|STRET
 //
 // Takes:
-//       $0 = NORMAL, FPRET, STRET, SUPER, SUPER_STRET
-//       eax = receiver
-//       ecx = selector
+//       receiver (not struct objc_super) and selector on stack
 //       edx = class to search
 //
-// On exit: calls IMP, eq/ne set for forwarding
+// On exit: IMP in eax, eq/ne set for forwarding
 //
 /////////////////////////////////////////////////////////////////////
 
 .macro MethodTableLookup
-       MESSENGER_END_SLOW
        pushl   %ebp
        movl    %esp, %ebp
-       sub     $$12, %esp              // align stack
+
+       subl    $$(8+5*16), %esp
+
+.if $0 == NORMAL
+       movl    self+4(%ebp), %eax
+       movl    selector+4(%ebp), %ecx
+.else
+       movl    self_stret+4(%ebp), %eax
+       movl    selector_stret+4(%ebp), %ecx
+.endif
+       
+       movdqa  %xmm3, 4*16(%esp)
+       movdqa  %xmm2, 3*16(%esp)
+       movdqa  %xmm1, 2*16(%esp)
+       movdqa  %xmm0, 1*16(%esp)
        
-       pushl   %edx                    // class
-       pushl   %ecx                    // selector
-       pushl   %eax                    // receiver
+       movl    %edx, 8(%esp)           // class
+       movl    %ecx, 4(%esp)           // selector
+       movl    %eax, 0(%esp)           // receiver
        call    __class_lookupMethodAndLoadCache3
 
        // imp in eax
-       
-       leave
 
-.if $0 == SUPER
-       // replace "super" arg with "receiver"
-       movl    super(%esp), %ecx       //  get super structure
-       movl    receiver(%ecx), %ecx    //  get messaged object
-       movl    %ecx, super(%esp)       //  make it the first argument
-.elseif $0 == SUPER_STRET
-       // replace "super" arg with "receiver"
-       movl    super_stret(%esp), %ecx //  get super structure
-       movl    receiver(%ecx), %ecx    //  get messaged object
-       movl    %ecx, super_stret(%esp) //  make it the first argument
-.endif
+       movdqa  4*16(%esp), %xmm3
+       movdqa  3*16(%esp), %xmm2
+       movdqa  2*16(%esp), %xmm1
+       movdqa  1*16(%esp), %xmm0
 
-.if $0 == STRET  ||  $0 == SUPER_STRET
-       // set ne (stret) for forwarding; eax != 0
-       test    %eax, %eax
-       jmp     *%eax           // call imp
+.if $0 == NORMAL
+       cmp     %eax, %eax      // set eq for nonstret forwarding
 .else
-       // set eq (non-stret) for forwarding
-       cmp     %eax, %eax
-       jmp     *%eax           // call imp
+       test    %eax, %eax      // set ne for stret forwarding
 .endif
 
+       leave
+
 .endmacro
 
 
@@ -377,7 +421,7 @@ $0:
 // On exit:    Loads non-nil receiver in eax and self(esp) or self_stret(esp),
 //             or returns zero.
 //
-// NilTestSupport return-type
+// NilTestReturnZero return-type
 //
 // Takes:      $0 = NORMAL or FPRET or STRET
 //             eax = receiver
@@ -385,33 +429,90 @@ $0:
 // On exit:    Loads non-nil receiver in eax and self(esp) or self_stret(esp),
 //             or returns zero.
 //
+// NilTestReturnIMP return-type
+//
+// Takes:      $0 = NORMAL or FPRET or STRET
+//             eax = receiver
+//
+// On exit:    Loads non-nil receiver in eax and self(esp) or self_stret(esp),
+//             or returns an IMP in eax that returns zero.
+//
 /////////////////////////////////////////////////////////////////////
 
+.macro ZeroReturn
+       xorl    %eax, %eax
+       xorl    %edx, %edx
+       xorps   %xmm0, %xmm0
+       xorps   %xmm1, %xmm1
+.endmacro
+
+.macro ZeroReturnFPRET
+       fldz
+.endmacro
+
+.macro ZeroReturnSTRET
+       // empty
+.endmacro
+
+       STATIC_ENTRY __objc_msgNil
+       ZeroReturn
+       ret
+       END_ENTRY __objc_msgNil
+
+       STATIC_ENTRY __objc_msgNil_fpret
+       ZeroReturnFPRET
+       ret
+       END_ENTRY __objc_msgNil_fpret
+
+       STATIC_ENTRY __objc_msgNil_stret
+       ZeroReturnSTRET
+       ret $4
+       END_ENTRY __objc_msgNil_stret
+
+
 .macro NilTest
        testl   %eax, %eax
        jz      LNilTestSlow_f
 LNilTestDone:
 .endmacro
 
-.macro NilTestSupport
+.macro NilTestReturnZero
        .align 3
 LNilTestSlow:
 
-.if $0 == FPRET
-       fldz
+.if $0 == NORMAL
+       ZeroReturn
        MESSENGER_END_NIL
        ret
-.elseif $0 == STRET
-       MESSENGER_END_NIL
-       ret $4
-.elseif $0 == NORMAL
-       // eax is already zero
-       xorl    %edx, %edx
-       xorps   %xmm0, %xmm0
-       xorps   %xmm1, %xmm1
+.elseif $0 == FPRET
+       ZeroReturnFPRET
        MESSENGER_END_NIL
        ret
+.elseif $0 == STRET
+       ZeroReturnSTRET
+       MESSENGER_END_NIL
+       ret $$4
+.else
+.abort oops
+.endif
+.endmacro
+
+.macro NilTestReturnIMP
+       .align 3
+LNilTestSlow:
+
+       call    1f
+1:     pop     %eax
+.if $0 == NORMAL
+       leal    __objc_msgNil-1b(%eax), %eax
+.elseif $0 == FPRET
+       leal    __objc_msgNil_fpret-1b(%eax), %eax
+.elseif $0 == STRET
+       leal    __objc_msgNil_stret-1b(%eax), %eax
+.else
+.abort oops
 .endif
+       ret
 .endmacro
 
 
@@ -422,31 +523,36 @@ LNilTestSlow:
  * If not found, returns NULL.
  ********************************************************************/
 
-       .private_extern _cache_getImp
-       ENTRY _cache_getImp
+       STATIC_ENTRY _cache_getImp
 
 // load the class and selector
        movl    selector(%esp), %ecx
        movl    self(%esp), %edx
 
-       CacheLookup GETIMP              // returns IMP on success
+       CacheLookup NORMAL, GETIMP      // returns IMP on success
 
 LCacheMiss:
 // cache miss, return nil
        xorl    %eax, %eax
        ret
 
-LGetImpExit:
        END_ENTRY _cache_getImp
 
 
 /********************************************************************
  *
- * id objc_msgSend(id self, SEL        _cmd,...);
+ * id objc_msgSend(id self, SEL _cmd, ...);
+ * IMP objc_msgLookup(id self, SEL _cmd, ...);
+ *
+ * objc_msgLookup ABI:
+ * IMP returned in eax
+ * Forwarding returned in Z flag
+ * edx reserved for our use but not used
  *
  ********************************************************************/
 
-       ENTRY   _objc_msgSend
+       ENTRY _objc_msgSend
+       UNWIND _objc_msgSend, NoFrame
        MESSENGER_START
        
        movl    selector(%esp), %ecx
@@ -455,76 +561,136 @@ LGetImpExit:
        NilTest NORMAL
 
        movl    isa(%eax), %edx         // class = self->isa
-       CacheLookup NORMAL              // calls IMP on success
+       CacheLookup NORMAL, CALL        // calls IMP on success
 
-       NilTestSupport NORMAL
+       NilTestReturnZero NORMAL
 
 LCacheMiss:
        // isa still in edx
+       MESSENGER_END_SLOW
+       jmp     __objc_msgSend_uncached
+
+       END_ENTRY _objc_msgSend
+
+
+       ENTRY _objc_msgLookup
+       UNWIND _objc_msgLookup, NoFrame
+       
        movl    selector(%esp), %ecx
        movl    self(%esp), %eax
-       MethodTableLookup NORMAL        // calls IMP
 
-LMsgSendExit:
-       END_ENTRY       _objc_msgSend
+       NilTest NORMAL
+
+       movl    isa(%eax), %edx         // class = self->isa
+       CacheLookup NORMAL, LOOKUP      // returns IMP on success
+
+       NilTestReturnIMP NORMAL
+
+LCacheMiss:
+       // isa still in edx
+       jmp     __objc_msgLookup_uncached
+
+       END_ENTRY _objc_msgLookup
 
 
 /********************************************************************
  *
- * id objc_msgSendSuper(struct objc_super *super, SEL _cmd,...);
+ * id objc_msgSendSuper(struct objc_super *super, SEL _cmd, ...);
+ * IMP objc_msgLookupSuper(struct objc_super *super, SEL _cmd, ...);
  *
- * struct objc_super {
- *             id      receiver;
- *             Class   class;
- * };
  ********************************************************************/
 
-       ENTRY   _objc_msgSendSuper
+       ENTRY _objc_msgSendSuper
+       UNWIND _objc_msgSendSuper, NoFrame
        MESSENGER_START
 
        movl    selector(%esp), %ecx
        movl    super(%esp), %eax       // struct objc_super
        movl    class(%eax), %edx       // struct objc_super->class
-       CacheLookup SUPER               // calls IMP on success
+       movl    receiver(%eax), %eax    // struct objc_super->receiver
+       movl    %eax, super(%esp)       // replace super arg with receiver
+       CacheLookup NORMAL, CALL        // calls IMP on success
 
 LCacheMiss:    
        // class still in edx
+       MESSENGER_END_SLOW
+       jmp     __objc_msgSend_uncached
+
+       END_ENTRY _objc_msgSendSuper
+
+
+
+       ENTRY _objc_msgLookupSuper
+       UNWIND _objc_msgLookupSuper, NoFrame
+
        movl    selector(%esp), %ecx
-       movl    super(%esp), %eax
-       movl    receiver(%eax), %eax
-       MethodTableLookup SUPER         // calls IMP
-       
-LMsgSendSuperExit:
-       END_ENTRY       _objc_msgSendSuper
+       movl    super(%esp), %eax       // struct objc_super
+       movl    class(%eax), %edx       // struct objc_super->class
+       movl    receiver(%eax), %eax    // struct objc_super->receiver
+       movl    %eax, super(%esp)       // replace super arg with receiver
+       CacheLookup NORMAL, LOOKUP      // returns IMP on success
 
+LCacheMiss:    
+       // class still in edx
+       jmp     __objc_msgLookup_uncached
+
+       END_ENTRY _objc_msgLookupSuper
+
+
+/********************************************************************
+ *
+ * id objc_msgSendSuper2(struct objc_super *super, SEL _cmd, ...);
+ * IMP objc_msgLookupSuper2(struct objc_super *super, SEL _cmd, ...);
+ *
+ ********************************************************************/
 
-       ENTRY   _objc_msgSendSuper2
+       ENTRY _objc_msgSendSuper2
+       UNWIND _objc_msgSendSuper2, NoFrame
        MESSENGER_START
 
        movl    selector(%esp), %ecx
        movl    super(%esp), %eax       // struct objc_super
-       movl    class(%eax), %eax       // struct objc_super->class
-       mov     superclass(%eax), %edx  // edx = objc_super->class->super_class
-       CacheLookup SUPER               // calls IMP on success
+       movl    class(%eax), %edx       // struct objc_super->class
+       movl    receiver(%eax), %eax    // struct objc_super->receiver
+       movl    %eax, super(%esp)       // replace super arg with receiver
+       movl    superclass(%edx), %edx  // edx = objc_super->class->super_class
+       CacheLookup NORMAL, CALL        // calls IMP on success
 
 LCacheMiss:
        // class still in edx
+       MESSENGER_END_SLOW
+       jmp     __objc_msgSend_uncached
+
+       END_ENTRY _objc_msgSendSuper2
+
+
+       ENTRY _objc_msgLookupSuper2
+       UNWIND _objc_msgLookupSuper2, NoFrame
+
        movl    selector(%esp), %ecx
-       movl    super(%esp), %eax
-       movl    receiver(%eax), %eax
-       MethodTableLookup SUPER         // calls IMP
+       movl    super(%esp), %eax       // struct objc_super
+       movl    class(%eax), %edx       // struct objc_super->class
+       movl    receiver(%eax), %eax    // struct objc_super->receiver
+       movl    %eax, super(%esp)       // replace super arg with receiver
+       movl    superclass(%edx), %edx  // edx = objc_super->class->super_class
+       CacheLookup NORMAL, LOOKUP      // returns IMP on success
+
+LCacheMiss:
+       // class still in edx
+       jmp     __objc_msgLookup_uncached
 
-LMsgSendSuper2Exit:
-       END_ENTRY       _objc_msgSendSuper2
+       END_ENTRY _objc_msgLookupSuper2
 
 
 /********************************************************************
  *
- * double objc_msgSend_fpret(id self, SEL _cmd,...);
+ * double objc_msgSend_fpret(id self, SEL _cmd, ...);
+ * IMP objc_msgLookup_fpret(id self, SEL _cmd, ...);
  *
  ********************************************************************/
 
-       ENTRY   _objc_msgSend_fpret
+       ENTRY _objc_msgSend_fpret
+       UNWIND _objc_msgSend_fpret, NoFrame
        MESSENGER_START
 
        movl    selector(%esp), %ecx
@@ -533,35 +699,47 @@ LMsgSendSuper2Exit:
        NilTest FPRET
 
        movl    isa(%eax), %edx         // class = self->isa
-       CacheLookup FPRET               // calls IMP on success
+       CacheLookup FPRET, CALL         // calls IMP on success
 
-       NilTestSupport FPRET
+       NilTestReturnZero FPRET
        
 LCacheMiss:    
        // class still in edx
+       MESSENGER_END_SLOW
+       jmp     __objc_msgSend_uncached
+
+       END_ENTRY _objc_msgSend_fpret
+
+
+       ENTRY _objc_msgLookup_fpret
+       UNWIND _objc_msgLookup_fpret, NoFrame
+
        movl    selector(%esp), %ecx
        movl    self(%esp), %eax
-       MethodTableLookup FPRET         // calls IMP
 
-LMsgSendFpretExit:
-       END_ENTRY       _objc_msgSend_fpret
+       NilTest FPRET
+
+       movl    isa(%eax), %edx         // class = self->isa
+       CacheLookup FPRET, LOOKUP       // returns IMP on success
+
+       NilTestReturnIMP FPRET
+       
+LCacheMiss:    
+       // class still in edx
+       jmp     __objc_msgLookup_uncached
+
+       END_ENTRY _objc_msgLookup_fpret
        
 
 /********************************************************************
  *
- * void        objc_msgSend_stret(void *st_addr        , id self, SEL _cmd, ...);
- *
- *
- * objc_msgSend_stret is the struct-return form of msgSend.
- * The ABI calls for (sp+4) to be used as the address of the structure
- * being returned, with the parameters in the succeeding locations.
+ * void objc_msgSend_stret(void *st_addr, id self, SEL _cmd, ...);
+ * IMP objc_msgLookup_stret(void *st_addr, id self, SEL _cmd, ...);
  *
- * On entry:   (sp+4)is the address where the structure is returned,
- *             (sp+8) is the message receiver,
- *             (sp+12) is the selector
  ********************************************************************/
 
-       ENTRY   _objc_msgSend_stret
+       ENTRY _objc_msgSend_stret
+       UNWIND _objc_msgSend_stret, NoFrame
        MESSENGER_START
 
        movl    selector_stret(%esp), %ecx
@@ -570,161 +748,211 @@ LMsgSendFpretExit:
        NilTest STRET
 
        movl    isa(%eax), %edx         // class = self->isa
-       CacheLookup STRET               // calls IMP on success
+       CacheLookup STRET, CALL         // calls IMP on success
 
-       NilTestSupport STRET
+       NilTestReturnZero STRET
        
 LCacheMiss:
        // class still in edx
+       MESSENGER_END_SLOW
+       jmp     __objc_msgSend_stret_uncached
+
+       END_ENTRY _objc_msgSend_stret
+
+
+       ENTRY _objc_msgLookup_stret
+       UNWIND _objc_msgLookup_stret, NoFrame
+
        movl    selector_stret(%esp), %ecx
        movl    self_stret(%esp), %eax
-       MethodTableLookup STRET         // calls IMP
 
-LMsgSendStretExit:
-       END_ENTRY       _objc_msgSend_stret
+       NilTest STRET
+
+       movl    isa(%eax), %edx         // class = self->isa
+       CacheLookup STRET, LOOKUP       // returns IMP on success
+
+       NilTestReturnIMP STRET
+       
+LCacheMiss:
+       // class still in edx
+       jmp     __objc_msgLookup_stret_uncached
+
+       END_ENTRY _objc_msgLookup_stret
 
        
 /********************************************************************
  *
  * void objc_msgSendSuper_stret(void *st_addr, struct objc_super *super, SEL _cmd, ...);
- *
- * struct objc_super {
- *             id      receiver;
- *             Class   class;
- * };
- *
- * objc_msgSendSuper_stret is the struct-return form of msgSendSuper.
- * The ABI calls for (sp+4) to be used as the address of the structure
- * being returned, with the parameters in the succeeding registers.
- *
- * On entry:   (sp+4)is the address where the structure is returned,
- *             (sp+8) is the address of the objc_super structure,
- *             (sp+12) is the selector
+ * IMP objc_msgLookupSuper_stret(void *st_addr, struct objc_super *super, SEL _cmd, ...);
  *
  ********************************************************************/
 
-       ENTRY   _objc_msgSendSuper_stret
+       ENTRY _objc_msgSendSuper_stret
+       UNWIND _objc_msgSendSuper_stret, NoFrame
        MESSENGER_START
 
        movl    selector_stret(%esp), %ecx
        movl    super_stret(%esp), %eax // struct objc_super
        movl    class(%eax), %edx       // struct objc_super->class
-       CacheLookup SUPER_STRET         // calls IMP on success
+       movl    receiver(%eax), %eax    // struct objc_super->receiver
+       movl    %eax, super_stret(%esp) // replace super arg with receiver
+       CacheLookup STRET, CALL         // calls IMP on success
 
 LCacheMiss:
        // class still in edx
+       MESSENGER_END_SLOW
+       jmp     __objc_msgSend_stret_uncached
+
+       END_ENTRY _objc_msgSendSuper_stret
+
+
+       ENTRY _objc_msgLookupSuper_stret
+       UNWIND _objc_msgLookupSuper_stret, NoFrame
+
        movl    selector_stret(%esp), %ecx
-       movl    super_stret(%esp), %eax
-       movl    receiver(%eax), %eax
-       MethodTableLookup SUPER_STRET   // calls IMP
+       movl    super_stret(%esp), %eax // struct objc_super
+       movl    class(%eax), %edx       // struct objc_super->class
+       movl    receiver(%eax), %eax    // struct objc_super->receiver
+       movl    %eax, super_stret(%esp) // replace super arg with receiver
+       CacheLookup STRET, LOOKUP       // returns IMP on success
+
+LCacheMiss:
+       // class still in edx
+       jmp     __objc_msgLookup_stret_uncached
+
+       END_ENTRY _objc_msgLookupSuper_stret
 
-LMsgSendSuperStretExit:
-       END_ENTRY       _objc_msgSendSuper_stret
 
+/********************************************************************
+ *
+ * void objc_msgSendSuper2_stret(void *st_addr, struct objc_super *super, SEL _cmd, ...);
+ * IMP objc_msgLookupSuper2_stret(void *st_addr, struct objc_super *super, SEL _cmd, ...);
+ *
+ ********************************************************************/
 
-       ENTRY   _objc_msgSendSuper2_stret
+       ENTRY _objc_msgSendSuper2_stret
+       UNWIND _objc_msgSendSuper2_stret, NoFrame
        MESSENGER_START
 
        movl    selector_stret(%esp), %ecx
        movl    super_stret(%esp), %eax // struct objc_super
-       movl    class(%eax), %eax       // struct objc_super->class
-       mov     superclass(%eax), %edx  // edx = objc_super->class->super_class
-       CacheLookup SUPER_STRET         // calls IMP on success
+       movl    class(%eax), %edx       // struct objc_super->class
+       movl    receiver(%eax), %eax    // struct objc_super->receiver
+       movl    %eax, super_stret(%esp) // replace super arg with receiver
+       mov     superclass(%edx), %edx  // edx = objc_super->class->super_class
+       CacheLookup STRET, CALL         // calls IMP on success
 
 // cache miss: go search the method lists
 LCacheMiss:
        // class still in edx
+       MESSENGER_END_SLOW
+       jmp     __objc_msgSend_stret_uncached
+
+       END_ENTRY _objc_msgSendSuper2_stret
+
+
+       ENTRY _objc_msgLookupSuper2_stret
+       UNWIND _objc_msgLookupSuper2_stret, NoFrame
+
        movl    selector_stret(%esp), %ecx
-       movl    super_stret(%esp), %eax
-       movl    receiver(%eax), %eax
-       MethodTableLookup SUPER_STRET   // calls IMP
+       movl    super_stret(%esp), %eax // struct objc_super
+       movl    class(%eax), %edx       // struct objc_super->class
+       movl    receiver(%eax), %eax    // struct objc_super->receiver
+       movl    %eax, super_stret(%esp) // replace super arg with receiver
+       mov     superclass(%edx), %edx  // edx = objc_super->class->super_class
+       CacheLookup STRET, LOOKUP       // returns IMP on success
 
-LMsgSendSuper2StretExit:
-       END_ENTRY       _objc_msgSendSuper2_stret
+// cache miss: go search the method lists
+LCacheMiss:
+       // class still in edx
+       jmp     __objc_msgLookup_stret_uncached
+
+       END_ENTRY _objc_msgLookupSuper2_stret
 
 
 /********************************************************************
  *
- * _objc_msgSend_uncached_impcache
  * _objc_msgSend_uncached
  * _objc_msgSend_stret_uncached
- * 
- * Used to erase method cache entries in-place by 
- * bouncing them to the uncached lookup.
+ * _objc_msgLookup_uncached
+ * _objc_msgLookup_stret_uncached
+ *
+ * The uncached method lookup.
  *
  ********************************************************************/
-       
-       STATIC_ENTRY __objc_msgSend_uncached_impcache
-       // Method cache version
-
-       // THIS IS NOT A CALLABLE C FUNCTION
-       // Out-of-band condition register is NE for stret, EQ otherwise.
-       // Out-of-band edx is the searched class
-
-       MESSENGER_START
-       nop
-       MESSENGER_END_SLOW
-       
-       jne     __objc_msgSend_stret_uncached
-       jmp     __objc_msgSend_uncached
-
-       END_ENTRY __objc_msgSend_uncached_impcache
-
 
        STATIC_ENTRY __objc_msgSend_uncached
+       UNWIND __objc_msgSend_uncached, FrameWithNoSaves
 
        // THIS IS NOT A CALLABLE C FUNCTION
        // Out-of-band edx is the searched class
 
        // edx is already the class to search
-       movl    selector(%esp), %ecx
-       MethodTableLookup NORMAL        // calls IMP
+       MethodTableLookup NORMAL
+       jmp     *%eax           // call imp
 
        END_ENTRY __objc_msgSend_uncached
 
        
        STATIC_ENTRY __objc_msgSend_stret_uncached
+       UNWIND __objc_msgSend_stret_uncached, FrameWithNoSaves
 
        // THIS IS NOT A CALLABLE C FUNCTION
        // Out-of-band edx is the searched class
 
        // edx is already the class to search
-       movl    selector_stret(%esp), %ecx
-       MethodTableLookup STRET         // calls IMP
+       MethodTableLookup STRET
+       jmp     *%eax           // call imp
 
        END_ENTRY __objc_msgSend_stret_uncached
 
 
-/********************************************************************
- *
- * id _objc_msgForward(id self, SEL _cmd,...);
- *
- ********************************************************************/
+       STATIC_ENTRY __objc_msgLookup_uncached
+       UNWIND __objc_msgLookup_uncached, FrameWithNoSaves
+
+       // THIS IS NOT A CALLABLE C FUNCTION
+       // Out-of-band edx is the searched class
+
+       // edx is already the class to search
+       MethodTableLookup NORMAL        // eax = IMP
+       ret
 
-// _FwdSel is @selector(forward::), set up in map_images().
-// ALWAYS dereference _FwdSel to get to "forward::" !!
-       .data
-       .align 2
-       .private_extern _FwdSel
-_FwdSel: .long 0
+       END_ENTRY __objc_msgLookup_uncached
 
+       
+       STATIC_ENTRY __objc_msgLookup_stret_uncached
+       UNWIND __objc_msgLookup_stret_uncached, FrameWithNoSaves
 
-       .cstring
-       .align 2
-LUnkSelStr: .ascii "Does not recognize selector %s\0"
+       // THIS IS NOT A CALLABLE C FUNCTION
+       // Out-of-band edx is the searched class
 
-       .data
-       .align 2
-       .private_extern __objc_forward_handler
-__objc_forward_handler:        .long 0
+       // edx is already the class to search
+       MethodTableLookup STRET         // eax = IMP
+       ret
 
-       .data
-       .align 2
-       .private_extern __objc_forward_stret_handler
-__objc_forward_stret_handler:  .long 0
+       END_ENTRY __objc_msgLookup_stret_uncached
 
-       ENTRY   __objc_msgForward_impcache
-       .private_extern __objc_msgForward_impcache
+
+/********************************************************************
+*
+* id _objc_msgForward(id self, SEL _cmd,...);
+*
+* _objc_msgForward and _objc_msgForward_stret are the externally-callable
+*   functions returned by things like method_getImplementation().
+* _objc_msgForward_impcache is the function pointer actually stored in
+*   method caches.
+*
+********************************************************************/
+
+       .non_lazy_symbol_pointer
+L_forward_handler:
+       .indirect_symbol __objc_forward_handler
+       .long 0
+L_forward_stret_handler:
+       .indirect_symbol __objc_forward_stret_handler
+       .long 0
+
+       STATIC_ENTRY __objc_msgForward_impcache
        // Method cache version
        
        // THIS IS NOT A CALLABLE C FUNCTION
@@ -737,113 +965,29 @@ __objc_forward_stret_handler:    .long 0
        jne     __objc_msgForward_stret
        jmp     __objc_msgForward
        
-       END_ENTRY       _objc_msgForward_impcache
+       END_ENTRY _objc_msgForward_impcache
 
        
-       ENTRY   __objc_msgForward
+       ENTRY __objc_msgForward
        // Non-struct return version
 
-       // Get PIC base into %edx
-       call    L__objc_msgForward$pic_base
-L__objc_msgForward$pic_base:
-       popl    %edx
-       
-       // Call user handler, if any
-       movl    __objc_forward_handler-L__objc_msgForward$pic_base(%edx),%ecx
-       testl   %ecx, %ecx              // if not NULL
-       je      1f                      //   skip to default handler
-       jmp     *%ecx                   // call __objc_forward_handler
-1:     
-       // No user handler
-       // Push stack frame
-       pushl   %ebp
-       movl    %esp, %ebp
-       
-       // Die if forwarding "forward::"
-       movl    (selector+4)(%ebp), %eax
-       movl    _FwdSel-L__objc_msgForward$pic_base(%edx),%ecx
-       cmpl    %ecx, %eax
-       je      LMsgForwardError
-
-       // Call [receiver forward:sel :margs]
-       subl    $8, %esp                // 16-byte align the stack
-       leal    (self+4)(%ebp), %ecx
-       pushl   %ecx                    // &margs
-       pushl   %eax                    // sel
-       movl    _FwdSel-L__objc_msgForward$pic_base(%edx),%ecx
-       pushl   %ecx                    // forward::
-       pushl   (self+4)(%ebp)          // receiver
-       
-       call    _objc_msgSend
-       
-       movl    %ebp, %esp
-       popl    %ebp
-       ret
-
-LMsgForwardError:
-       // Call __objc_error(receiver, "unknown selector %s", "forward::")
-       subl    $12, %esp               // 16-byte align the stack
-       movl    _FwdSel-L__objc_msgForward$pic_base(%edx),%eax
-       pushl   %eax
-       leal    LUnkSelStr-L__objc_msgForward$pic_base(%edx),%eax
-       pushl   %eax
-       pushl   (self+4)(%ebp)
-       call    ___objc_error   // never returns
+       call    1f
+1:     popl    %edx
+       movl    L_forward_handler-1b(%edx), %edx
+       jmp     *(%edx)
 
-       END_ENTRY       __objc_msgForward
+       END_ENTRY __objc_msgForward
 
 
-       ENTRY   __objc_msgForward_stret
+       ENTRY __objc_msgForward_stret
        // Struct return version
 
-       // Get PIC base into %edx
-       call    L__objc_msgForwardStret$pic_base
-L__objc_msgForwardStret$pic_base:
-       popl    %edx
-
-       // Call user handler, if any
-       movl    __objc_forward_stret_handler-L__objc_msgForwardStret$pic_base(%edx), %ecx
-       testl   %ecx, %ecx              // if not NULL
-       je      1f                      //   skip to default handler
-       jmp     *%ecx                   // call __objc_forward_stret_handler
-1:     
-       // No user handler
-       // Push stack frame
-       pushl   %ebp
-       movl    %esp, %ebp
-
-       // Die if forwarding "forward::"
-       movl    selector_stret+4(%ebp), %eax
-       movl    _FwdSel-L__objc_msgForwardStret$pic_base(%edx), %ecx
-       cmpl    %ecx, %eax
-       je      LMsgForwardStretError
-
-       // Call [receiver forward:sel :margs]
-       subl    $8, %esp                // 16-byte align the stack
-       leal    (self_stret+4)(%ebp), %ecx
-       pushl   %ecx                    // &margs
-       pushl   %eax                    // sel
-       movl    _FwdSel-L__objc_msgForwardStret$pic_base(%edx),%ecx
-       pushl   %ecx                    // forward::
-       pushl   (self_stret+4)(%ebp)    // receiver
-       
-       call    _objc_msgSend
-       
-       movl    %ebp, %esp
-       popl    %ebp
-       ret     $4                      // pop struct return address (#2995932)
-
-LMsgForwardStretError:
-       // Call __objc_error(receiver, "unknown selector %s", "forward::")
-       subl    $12, %esp               // 16-byte align the stack
-       leal    _FwdSel-L__objc_msgForwardStret$pic_base(%edx),%eax
-       pushl   %eax
-       leal    LUnkSelStr-L__objc_msgForwardStret$pic_base(%edx),%eax
-       pushl   %eax
-       pushl   (self_stret+4)(%ebp)
-       call    ___objc_error   // never returns
+       call    1f
+1:     popl    %edx
+       movl    L_forward_stret_handler-1b(%edx), %edx
+       jmp     *(%edx)
 
-       END_ENTRY       __objc_msgForward_stret
+       END_ENTRY __objc_msgForward_stret
 
 
        ENTRY _objc_msgSend_debug
@@ -892,15 +1036,6 @@ LMsgForwardStretError:
        jmp     *%eax
        
        END_ENTRY _method_invoke_stret
-
-#if !defined(NDEBUG)
-       STATIC_ENTRY __objc_ignored_method
-       
-       movl    self(%esp), %eax
-       ret
-       
-       END_ENTRY __objc_ignored_method
-#endif
        
 
 .section __DATA,__objc_msg_break