You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
libobjc2/objc_msgSend.aarch64.S

227 lines
7.5 KiB
ArmAsm

#define ARGUMENT_SPILL_SIZE (8*10 + 8*16)
/* Windows ARM64 Exception Handling
*
* Structured Exception Handling (SEH) on Windows ARM64 differs from the x64
* implementation. Functions consist of a single prologue and zero or more
* epilogues. Instead of using offsets for the .seh* directives to manipulate the
* stack frame, each directive corresponds to a single instruction.
*
* This presents a challenge for our objc_msgSend function, which only modifies
* the stack when a slow lookup is needed (see label "5").
*
* To address this, we move the directive marking the start of a function deep
* into the msgSend body to prevent marking every instruction as ".seh_nop."
*
* For Windows:
* - EH_START(x): Start of function (no effect on Windows)
* - EH_END(x): End of function (no effect on Windows)
* - EH_START_AT_OFFSET(x): Mark Start of function (Delayed)
* - EH_END_AT_OFFSET(x): Mark End of function (Delayed)
* - EH_END_PROLOGUE: End of function prologue
* - EH_START_EPILOGUE: Start of function epilogue
* - EH_END_EPILOGUE: End of function epilogue
* - EH_SAVE_FP_LR(x): Save Frame Pointer and Link Register
* - EH_STACK_ALLOC(x): Stack allocation (inside prologue)
* - EH_ADD_FP(x): Add to Frame Pointer
* - EH_NOP: Mark instruction with no unwinding relevance
*
* For non-64-bit Windows systems or other platforms, these macros have no effect and can be used without causing issues.
*/
#ifdef _WIN32
# define EH_START
# define EH_END
# define EH_START_AT_OFFSET .seh_proc objc_msgSend
# define EH_END_AT_OFFSET .seh_endproc objc_msgSend
# define EH_END_PROLOGUE .seh_endprologue
# define EH_START_EPILOGUE .seh_startepilogue
# define EH_END_EPILOGUE .seh_endepilogue
# define EH_SAVE_FP_LR(x) .seh_save_fplr x
# define EH_STACK_ALLOC(x) .seh_stackalloc x
# define EH_ADD_FP(x) .seh_add_fp x
# define EH_NOP .seh_nop
#else
// Marks the real start and end of the function
# define EH_START .cfi_startproc
# define EH_END .cfi_endproc
// The following directives are either not
// needed or not available with CFI
# define EH_START_AT_OFFSET
# define EH_END_AT_OFFSET
# define EH_END_PROLOGUE
# define EH_START_EPILOGUE
# define EH_END_EPILOGUE
# define EH_SAVE_FP_LR(x)
# define EH_STACK_ALLOC(x)
# define EH_ADD_FP(x)
# define EH_NOP
#endif
.globl CDECL(objc_msgSend_fpret)
TYPE_DIRECTIVE(CDECL(objc_msgSend_fpret), %function)
.globl CDECL(objc_msgSend)
TYPE_DIRECTIVE(CDECL(objc_msgSend), %function)
.globl CDECL(objc_msgSend_stret)
TYPE_DIRECTIVE(CDECL(objc_msgSend_stret), %function)
CDECL(objc_msgSend):
CDECL(objc_msgSend_fpret):
CDECL(objc_msgSend_stret):
EH_START
cbz x0, 4f // Skip everything if the receiver is nil
// Jump to 6: if this is a small object
ubfx x9, x0, #0, #SMALLOBJ_BITS
cbnz x9, 6f
ldr x9, [x0] // Load class to x9 if not a small int
1:
ldr x9, [x9, #DTABLE_OFFSET] // Dtable -> x9
ldr w10, [x1] // selector->index -> x10
ldr w11, [x9, #SHIFT_OFFSET] // dtable->shift -> x11
cmp x11, #8 // If this is a small dtable, jump to the
// small dtable handlers
b.eq 2f
cbz x11, 3f
ubfx x11, x10, #16, #8 // Put byte 3 of the sel id in x12
add x11, x9, x11, lsl #3 // x11 = dtable address + dtable data offset
ldr x9, [x11, #DATA_OFFSET] // Load, adding in the data offset
2: // dtable16
ubfx x11, x10, #8, #8 // Put byte 2 of the sel id in x12
add x11, x9, x11, lsl #3 // x11 = dtable address + dtable data offset
ldr x9, [x11, #DATA_OFFSET] // Load, adding in the data offset
3: // dtable8
ubfx x11, x10, #0, #8 // Put low byte of the sel id in x12
add x11, x9, x11, lsl #3 // x11 = dtable address + dtable data offset
ldr x9, [x11, #DATA_OFFSET] // Load, adding in the data offset.
// Slot pointer is now in x9
cbz x9, 5f // If the slot is nil, go to the C path
ldr x9, [x9, #SLOT_OFFSET] // Load the method from the slot
br x9 // Tail-call the method
4: // Nil receiver
mov x0, #0
mov v0.d[0], x0
mov v0.d[1], x0
br lr
5: // Slow lookup
EH_START_AT_OFFSET
// Save anything that will be clobbered by
// the call.
// Note that we pre-index (see "!"), meaning
// that we adjust the sp before storing the pair
// of registers.
stp x0, x1, [sp, #-(ARGUMENT_SPILL_SIZE)]!
EH_STACK_ALLOC((ARGUMENT_SPILL_SIZE))
stp x2, x3, [sp, #16]
EH_NOP // The following instructions can be ignored by SEH
stp x4, x5, [sp, #32]
EH_NOP
stp x6, x7, [sp, #48]
EH_NOP
stp q0, q1, [sp, #64]
EH_NOP
stp q2, q3, [sp, #96]
EH_NOP
stp q4, q5, [sp, #128]
EH_NOP
stp q6, q7, [sp, #160]
EH_NOP
stp fp, lr, [sp, #192] // The order is arbitrary, except that
EH_SAVE_FP_LR(192) // fp and lr must be spilled together
add fp, sp, 192 // Adjust frame pointer
EH_ADD_FP(192)
stp x0, x8, [sp, #-16]! // it's convenient if x0 is spilled at sp
EH_STACK_ALLOC(16) // stp performed pre-indexing by sp-16
EH_END_PROLOGUE
#ifndef _WIN32
.cfi_def_cfa fp, 16
.cfi_offset fp, -16
.cfi_offset lr, -8
#endif
// We now have all argument registers, the link
// register and the receiver spilled on the
// stack, with sp containing
// the address of the receiver
mov x0, sp // &self, _cmd in arguments
mov x1, x1
bl CDECL(slowMsgLookup) // This is the only place where the EH directives
// have to be accurate...
mov x9, x0 // IMP -> x9
EH_START_EPILOGUE
ldp x0, x1, [sp, #16] // Reload spilled argument registers
EH_NOP
ldp x2, x3, [sp, #32]
EH_NOP
ldp x4, x5, [sp, #48]
EH_NOP
ldp x6, x7, [sp, #64]
EH_NOP
ldp q0, q1, [sp, #80]
EH_NOP
ldp q2, q3, [sp, #112]
EH_NOP
ldp q4, q5, [sp, #144]
EH_NOP
ldp q6, q7, [sp, #176]
EH_NOP
ldp fp, lr, [sp, #208]
EH_SAVE_FP_LR(208)
// Post-increment sp += ARGUMENT_SPILL_SIZE +16
ldp x0, x8, [sp], #(ARGUMENT_SPILL_SIZE + 16)
EH_STACK_ALLOC((ARGUMENT_SPILL_SIZE + 16))
EH_END_EPILOGUE
EH_END_AT_OFFSET
br x9
6:
// Load 63:12 of SmallObjectClasses address
// We use the CDECL macro as Windows prefixes
// cdecl conforming symbols with "_".
adrp x10, CDECL(SmallObjectClasses) // The macro handles this transparently.
// Add lower 12-bits of SmallObjectClasses address to x10
add x10, x10, :lo12:CDECL(SmallObjectClasses)
ldr x9, [x10, x9, lsl #3]
b 1b
EH_END
#ifdef _WIN32
.text
.def objc_msgSend;
.scl 2;
.type 32;
.endef
.def objc_msgSend_fpret;
.scl 2;
.type 32;
.endef
.def objc_msgSend_stret;
.scl 2;
.type 32;
.endef
.section .drectve,"yn"
.ascii " /EXPORT:objc_msgSend"
.ascii " /EXPORT:objc_msgSend_fpret"
.ascii " /EXPORT:objc_msgSend_stret"
#endif