Index: configure.ac ================================================================== --- configure.ac +++ configure.ac @@ -204,12 +204,15 @@ yes # endif #endif ], [ AC_SUBST(LOOKUP_S, lookup-amd64-elf.S) + AC_SUBST(FORWARDING_S, forwarding-amd64-elf.S) AC_DEFINE(OF_ASM_LOOKUP, 1, [Whether to use assembly for lookup]) + AC_DEFINE(OF_HAVE_FORWARDING_TARGET_FOR_SELECTOR, 1, + [Whether we have forwardingTargetForSelector:]) ], [ AC_EGREP_CPP(yes, [ #if defined(__i386__) && defined(__ELF__) yes #endif @@ -269,11 +272,16 @@ LIBS="-lobjc $LIBS" ], [ AC_MSG_ERROR([libobjc not found!]) ]) - AC_SUBST(APPLE_FORWARDING_S, "apple-forwarding.S") + dnl We should check for PPC64, as this currently does not + dnl support forwardingTargetForSelector: as there is no test + dnl machine available. + AC_SUBST(FORWARDING_S, "apple-forwarding.S") + AC_DEFINE(OF_HAVE_FORWARDING_TARGET_FOR_SELECTOR, 1, + [Whether we have forwardingTargetForSelector:]) ;; esac AC_CHECK_FUNC(objc_constructInstance, [], [ AC_SUBST(INSTANCE_M, "instance.m") Index: extra.mk.in ================================================================== --- extra.mk.in +++ extra.mk.in @@ -16,10 +16,11 @@ BRIDGE = @BRIDGE@ EXCEPTIONS_A = @EXCEPTIONS_A@ EXCEPTIONS_EXCEPTIONS_A = @EXCEPTIONS_EXCEPTIONS_A@ EXCEPTIONS_EXCEPTIONS_LIB_A = @EXCEPTIONS_EXCEPTIONS_LIB_A@ EXCEPTIONS_LIB_A = @EXCEPTIONS_LIB_A@ +FORWARDING_S = @FORWARDING_S@ FOUNDATION_COMPAT_M = @FOUNDATION_COMPAT_M@ INSTANCE_M = @INSTANCE_M@ LOOKUP_S = @LOOKUP_S@ OFBLOCKTESTS_M = @OFBLOCKTESTS_M@ OFSTREAMOBSERVER_KQUEUE_M = @OFSTREAMOBSERVER_KQUEUE_M@ Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -114,12 +114,12 @@ ${OFSTREAMOBSERVER_KQUEUE_M} \ ${OFSTREAMOBSERVER_POLL_M} \ ${OFSTREAMOBSERVER_SELECT_M} \ OFString_UTF8.m \ OFTCPSocket+SOCKS5.m \ - ${APPLE_FORWARDING_S} \ ${ASPRINTF_M} \ + ${FORWARDING_S} \ ${FOUNDATION_COMPAT_M} \ iso_8859_15.m \ windows_1252.m OBJS_EXTRA = ${EXCEPTIONS_EXCEPTIONS_A} ${RUNTIME_RUNTIME_A} Index: src/OFObject.m ================================================================== --- src/OFObject.m +++ src/OFObject.m @@ -61,13 +61,23 @@ # import "atomic.h" #elif defined(OF_HAVE_THREADS) # import "threading.h" #endif -#if defined(OF_APPLE_RUNTIME) && !defined(__ppc64__) +#if defined(OF_HAVE_FORWARDING_TARGET_FOR_SELECTOR) extern id of_forward(id, SEL, ...); +# ifdef OF_APPLE_RUNTIME +/* + * Forwarding for methods returning structs only works with the Apple ABI, as + * with the GNU ABI, there is no way of knowing if a struct is returned and if + * so how. + * As forwardingTargetForSelector: only works for architectures for which + * assembly has been written anyway, it makes sense to switch to + * objc_msgSend(_{st,fp}ret) for those architectures to solve this problem. + */ extern struct stret of_forward_stret(id, SEL, ...); +# endif #endif struct pre_ivar { int32_t retainCount; struct pre_mem *firstMem, *lastMem; @@ -158,10 +168,20 @@ } return objc_msg_lookup(obj, sel); } } + +#ifdef OF_HAVE_FORWARDING_TARGET_FOR_SELECTOR + if (class_respondsToSelector(object_getClass(obj), + @selector(forwardingTargetForSelector:))) { + id target = [obj forwardingTargetForSelector: sel]; + + if (target != nil && target != obj) + return (IMP)of_forward; + } +#endif of_method_not_found(obj, sel); return NULL; } #endif ADDED src/forwarding-amd64-elf.S Index: src/forwarding-amd64-elf.S ================================================================== --- src/forwarding-amd64-elf.S +++ src/forwarding-amd64-elf.S @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +.globl of_forward + +.section .text +of_forward: + pushq %rbp + movq %rsp, %rbp + + /* Save all arguments */ + subq $0xC0, %rsp /* 16-byte alignment */ + movq %rax, 0xA8(%rsp) + movq %rdi, 0xA0(%rsp) + movq %rsi, 0x98(%rsp) + movq %rdx, 0x90(%rsp) + movq %rcx, 0x88(%rsp) + movq %r8, 0x80(%rsp) + movq %r9, 0x78(%rsp) + movd %xmm0, 0x70(%rsp) + movd %xmm1, 0x60(%rsp) + movd %xmm2, 0x50(%rsp) + movd %xmm3, 0x40(%rsp) + movd %xmm4, 0x30(%rsp) + movd %xmm5, 0x20(%rsp) + movd %xmm6, 0x10(%rsp) + movd %xmm7, (%rsp) + + leaq sel_forwardingTargetForSelector_(%rip), %rsi + call objc_msg_lookup@PLT + movq 0xA0(%rsp), %rdi + leaq sel_forwardingTargetForSelector_(%rip), %rsi + movq 0x98(%rsp), %rdx + call *%rax + movq %rax, 0xA0(%rsp) + + movq %rax, %rdi + movq 0x98(%rsp), %rsi + call objc_msg_lookup@PLT + movq %rax, %r11 + + /* Restore all arguments */ + movd (%rsp), %xmm7 + movd 0x10(%rsp), %xmm6 + movd 0x20(%rsp), %xmm5 + movd 0x30(%rsp), %xmm4 + movd 0x40(%rsp), %xmm3 + movd 0x50(%rsp), %xmm2 + movd 0x60(%rsp), %xmm1 + movd 0x70(%rsp), %xmm0 + movq 0x78(%rsp), %r9 + movq 0x80(%rsp), %r8 + movq 0x88(%rsp), %rcx + movq 0x90(%rsp), %rdx + movq 0x98(%rsp), %rsi + movq 0xA0(%rsp), %rdi + movq 0xA8(%rsp), %rax + + movq %rbp, %rsp + popq %rbp + + jmp *%r11 + +init: + leaq module(%rip), %rdi + call __objc_exec_class@PLT + ret + +.section .init_array + .quad init + +.section .rodata +str_forwardingTargetForSelector_: + .asciz "forwardingTargetForSelector:" + +.section .data +sel_forwardingTargetForSelector_: + .quad str_forwardingTargetForSelector_, 0 + .quad 0, 0 +symtab: + .quad 0, sel_forwardingTargetForSelector_ + .short 0, 0 + .long 0 + .quad 0 +module: + .quad 8, 32, 0, symtab + +.type of_forward, %function +.size of_forward, init-of_forward + +#ifdef __linux__ +.section .note.GNU-stack, "", %progbits +#endif Index: src/objfw-defs.h.in ================================================================== --- src/objfw-defs.h.in +++ src/objfw-defs.h.in @@ -2,10 +2,11 @@ #undef OF_BIG_ENDIAN #undef OF_FLOAT_BIG_ENDIAN #undef OF_HAVE_ASPRINTF #undef OF_HAVE_ATOMIC_OPS #undef OF_HAVE_COMPILER_TLS +#undef OF_HAVE_FORWARDING_TARGET_FOR_SELECTOR #undef OF_HAVE_GCC_ATOMIC_OPS #undef OF_HAVE_OSATOMIC #undef OF_HAVE_OSATOMIC_64 #undef OF_HAVE_PTHREADS #undef OF_HAVE_PLUGINS Index: src/runtime/lookup-amd64-elf.S ================================================================== --- src/runtime/lookup-amd64-elf.S +++ src/runtime/lookup-amd64-elf.S @@ -38,18 +38,14 @@ #endif movq (%r8,%rcx,8), %r8 movq (%r8,%rdx,8), %rax testq %rax, %rax - jz forward + jz objc_not_found_handler@PLT ret -forward: - movq objc_not_found_handler@GOTPCREL(%rip), %rax - jmp *%rax - objc_msg_lookup_super: movq (%rdi), %rax testq %rax, %rax jz ret_nil @@ -64,13 +60,13 @@ nil_method: movq %rdi, %rax ret -.type objc_msg_lookup, @function -.type objc_msg_lookup_super, @function -.size objc_msg_lookup, forward-objc_msg_lookup +.type objc_msg_lookup, %function +.type objc_msg_lookup_super, %function +.size objc_msg_lookup, objc_msg_lookup_super-objc_msg_lookup .size objc_msg_lookup_super, ret_nil-objc_msg_lookup_super #ifdef __linux__ .section .note.GNU-stack, "", %progbits #endif Index: src/runtime/lookup-ppc-elf.S ================================================================== --- src/runtime/lookup-ppc-elf.S +++ src/runtime/lookup-ppc-elf.S @@ -79,13 +79,13 @@ get_pc: mflr %r3 blr -.type objc_msg_lookup, @function -.type objc_msg_lookup_super, @function +.type objc_msg_lookup, %function +.type objc_msg_lookup_super, %function .size objc_msg_lookup, forward-objc_msg_lookup .size objc_msg_lookup_super, ret_nil-objc_msg_lookup_super #ifdef __linux__ .section .note.GNU-stack, "", %progbits #endif Index: src/runtime/lookup-x86-elf.S ================================================================== --- src/runtime/lookup-x86-elf.S +++ src/runtime/lookup-x86-elf.S @@ -72,13 +72,13 @@ get_eip: movl (%esp), %eax ret -.type objc_msg_lookup, @function -.type objc_msg_lookup_super, @function +.type objc_msg_lookup, %function +.type objc_msg_lookup_super, %function .size objc_msg_lookup, forward-objc_msg_lookup .size objc_msg_lookup_super, ret_nil-objc_msg_lookup_super #ifdef __linux__ .section .note.GNU-stack, "", %progbits #endif