diff --git a/Test/objc_msgSend.m b/Test/objc_msgSend.m index 15f6be8..6270096 100644 --- a/Test/objc_msgSend.m +++ b/Test/objc_msgSend.m @@ -3,6 +3,7 @@ #include #include #include +#include id objc_msgSend(id, SEL, ...); @@ -38,6 +39,7 @@ int main(void) TestCls = objc_getClass("Test"); objc_msgSend(TestCls, @selector(nothing)); objc_msgSend(TestCls, @selector(missing)); + assert(0 == objc_msgSend(0, @selector(nothing))); id a = objc_msgSend(objc_getClass("Test"), @selector(foo)); assert((id)0x42 == a); a = objc_msgSend(TestCls, @selector(foo)); diff --git a/class.h b/class.h index 9ff3e43..3e2963e 100644 --- a/class.h +++ b/class.h @@ -274,7 +274,7 @@ static inline Class classForObject(id obj) { if (sizeof(Class) == 4) { - return SmallObjectClasses[1]; + return SmallObjectClasses[0]; } else { diff --git a/class_table.c b/class_table.c index 4694444..8feb1f4 100644 --- a/class_table.c +++ b/class_table.c @@ -431,6 +431,15 @@ BOOL objc_registerSmallObjectClass_np(Class class, uintptr_t mask) { return NO; } + if (sizeof(void*) == 4) + { + if (Nil == SmallObjectClasses[0]) + { + SmallObjectClasses[0] = class; + return YES; + } + return NO; + } if (Nil != SmallObjectClasses[mask]) { return NO; diff --git a/objc_msgSend.S b/objc_msgSend.S index e171d46..10e52f3 100644 --- a/objc_msgSend.S +++ b/objc_msgSend.S @@ -2,7 +2,8 @@ #include "objc_msgSend.x86-64.S" #elif __i386 #include "objc_msgSend.x86-32.S" +#elif __arm__ +#include "objc_msgSend.arm.S" #else -//#elif __arm__ #warning objc_msgSend() not implemented for your architecture #endif diff --git a/objc_msgSend.arm.S b/objc_msgSend.arm.S new file mode 100644 index 0000000..735c96b --- /dev/null +++ b/objc_msgSend.arm.S @@ -0,0 +1,98 @@ +#define DTABLE_OFFSET 32 +#define SMALLOBJ_MASK 1 +#define SHIFT_OFFSET 4 +#define DATA_OFFSET 12 +#define SLOT_OFFSET 16 +.syntax unified + +// Macro for testing: logs a register value to standard error +.macro LOG reg + push {r0-r3, ip,lr} + mov r0, \reg + bl logInt(PLT) + pop {r0-r3, ip,lr} +.endm + +.macro MSGSEND receiver, sel + teq \receiver, 0 + beq 4f // Skip everything if the receiver is nil + push {r4-r6} // We're going to use these three as + // scratch registers, so save them now + tst \receiver, SMALLOBJ_MASK // Sets Z if this is not a small int + + + ldrne r4, LSmallIntClass // Small Int class -> r4 if this is a small int + ldrne r4, [r4] + + ldreq r4, [\receiver] // Load class to r4 if not a small int + + ldr r4, [r4, #DTABLE_OFFSET] // Dtable -> r4 + + ldr r5, LUninstalledDtable // &uninstalled_dtable -> r5 + ldr r5, [r5] + + teq r4, r5 // If dtable == &uninstalled_dtable + beq 5f // Do a slow lookup + + ldr r5, [\sel] // selector->index -> r5 + + ldr r6, [r4, #SHIFT_OFFSET] // dtable->shift -> r6 + ldr r4, [r4, #DATA_OFFSET] // dtable->data -> r4 + + teq r6, #8 // If this is a small dtable, jump to the small dtable handlers + beq 1f + teq r6, #0 + beq 2f + + and r6, r5, #0xff0000 + ldr r4, [r4, r6, asr#14] +1: // dtable16 + and r6, r5, #0xff00 + ldr r4, [r4, r6, asr#6] +2: // dtable8 + and r6, r5, #0xff + ldr ip, [r4, r6, asl#2] + + teq ip, #0 // If the slot is nil + beq 5f // Go to the slow path and do the forwarding stuff + + ldr ip, [ip, #SLOT_OFFSET] // Load the method from the slot + +3: + pop {r4-r6} // Restore the saved callee-save registers + mov pc, ip + +4: // Nil receiver + mov r0, 0 + mov r1, 0 + mov pc, lr +5: // Slow lookup + push {r0-r3, lr} // Save anything that will be clobbered by the call + + push {\receiver} // &self, _cmd in arguments + mov r0, sp + mov r1, \sel + bl slowMsgLookup(PLT) + mov ip, r0 // IMP -> ip + + pop {r5} // restore (modified) self to r5 + pop {r0-r3, lr} // Load clobbered registers + mov \receiver, r5 + b 3b +.endm + +.globl objc_msgSend + .type objc_msgSend, %function +objc_msgSend: + MSGSEND r0, r1 +.globl objc_msgSend_sret + .type objc_msgSend_sret, %function +objc_msgSend_sret: + MSGSEND r1, r2 + +LSmallIntClass: + .long SmallObjectClasses + .align 2 +LUninstalledDtable: + .long uninstalled_dtable + .align 2 diff --git a/objc_msgSend.x86-32.S b/objc_msgSend.x86-32.S index 8eb6d97..c939f16 100644 --- a/objc_msgSend.x86-32.S +++ b/objc_msgSend.x86-32.S @@ -75,7 +75,6 @@ call __i686.get_pc_thunk.bx addl $_GLOBAL_OFFSET_TABLE_, %ebx mov SmallObjectClasses@GOT(%ebx), %eax - addl $4, %eax mov (%eax), %eax popl %ebx jmp 1b diff --git a/sendmsg2.c b/sendmsg2.c index 1c0d49b..67d7ada 100644 --- a/sendmsg2.c +++ b/sendmsg2.c @@ -110,9 +110,9 @@ IMP slowMsgLookup(id *receiver, SEL cmd) return objc_msg_lookup_sender(receiver, cmd, nil)->method; } -PRIVATE void logInt(long long a) +PRIVATE void logInt(void *a) { - fprintf(stderr, "Value: %llx\n", a); + fprintf(stderr, "Value: %p\n", a); } Slot_t (*objc_plane_lookup)(id *receiver, SEL op, id sender) =