.syntax unified .fpu neon #if ((__ARM_ARCH >= 7) || defined (__ARM_ARCH_6T2__)) // If we're using a CPU that supports Thumb-2, use it. This makes the // objc_msgSend function 130 bytes instead of 176. The fast path drops from 108 // bytes to 82, meaning that it will fit in 3 32-byte i-cache lines, rather // than 4. For comparison, the i386 version is 119 for objc_msgSend and // another 117 for objc_msgSend_fpret (the two are the same on ARM), with 70 // bytes for the fast path.. .thumb .macro byte1 dst, src uxtb \dst, \src .endm .macro byte2 dst, src ubfx \dst, \src, #8, #8 .endm .macro byte3 dst, src ubfx \dst, \src, #16, #8 .endm #else .macro byte1 dst, src and \dst, \src, #0xff .endm .macro byte2 dst, src and \dst, \src, #0xff00 lsr \dst, \dst, 8 .endm .macro byte3 dst, src and \dst, \src, #0xff00 lsr \dst, \dst, 16 .endm #endif // 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 .fnstart teq \receiver, 0 beq 4f // Skip everything if the receiver is nil push {r4-r6} // We're going to use these three as .save {r4-r6} // scratch registers, so save them now. // These are callee-save, so the unwind library // must be able to restore them, so we need CFI // directives for them, but not for any other pushes tst \receiver, SMALLOBJ_MASK // Sets Z if this is not a small int itte ne 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, [\sel] // selector->index -> r5 ldr r6, [r4, #SHIFT_OFFSET] // dtable->shift -> r6 teq r6, #8 // If this is a small dtable, jump to the small dtable handlers beq 1f teq r6, #0 beq 2f byte3 r6, r5 // Put byte 3 of the sel id in r6 add r6, r4, r6, lsl #2 // r6 = dtable address + dtable data offset ldr r4, [r6, #DATA_OFFSET] // Load, adding in the data offset 1: // dtable16 byte2 r6, r5 // Put byte 2 of the sel id in r6 add r6, r4, r6, lsl #2 // r6 = dtable address + dtable data offset ldr r4, [r6, #DATA_OFFSET] // Load, adding in the data offset 2: // dtable8 byte1 r6, r5 // Low byte of sel id into r5 add r6, r4, r6, lsl #2 // r6 = dtable address + dtable data offset ldr ip, [r6, #DATA_OFFSET] // Load, adding in the data offset cmp ip, #0 // If the slot is nil ittt ne ldrne ip, [ip, #SLOT_OFFSET] // Load the method from the slot popne {r4-r6} // Restore the saved callee-save registers bxne ip 5: // Slow lookup push {r0-r4, lr} // Save anything that will be clobbered by the call .save {r0-r4, lr} #ifndef __SOFTFP__ vpush {q0-q3} .pad #64 #endif push {\receiver} // &self, _cmd in arguments .save {\receiver} mov r0, sp mov r1, \sel bl CDECL(slowMsgLookup)(PLT) // This is the only place where the CFI directives have to be accurate... mov ip, r0 // IMP -> ip pop {r5} // restore (modified) self to r5 #ifndef __SOFTFP__ vpop {q0-q3} #endif pop {r0-r4, lr} // Load clobbered registers mov \receiver, r5 pop {r4-r6} // Restore the saved callee-save registers bx ip 4: // Nil receiver mov r0, 0 mov r1, 0 #ifndef __SOFTFP__ # ifdef __ARM_NEON__ vmov.i64 d0, #0 // Return 0 as a float / double # else fmdrr d0, r0, r1 # endif #endif bx lr .fnend .endm .globl CDECL(objc_msgSend_fpret) TYPE_DIRECTIVE(CDECL(objc_msgSend_fpret), %function) .globl CDECL(objc_msgSend) TYPE_DIRECTIVE(CDECL(objc_msgSend), %function) CDECL(objc_msgSend): CDECL(objc_msgSend_fpret): MSGSEND r0, r1 .globl CDECL(objc_msgSend_stret) TYPE_DIRECTIVE(CDECL(objc_msgSend_stret), %function) CDECL(objc_msgSend_stret): MSGSEND r1, r2 LSmallIntClass: .long SmallObjectClasses .align 2