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.
100 lines
4.1 KiB
ArmAsm
100 lines
4.1 KiB
ArmAsm
#define ARGUMENT_SPILL_SIZE (8*10 + 8*16)
|
|
.macro MSGSEND receiver, sel
|
|
.cfi_startproc
|
|
cbz \receiver, 4f // Skip everything if the receiver is nil
|
|
// Jump to 6: if this is a small object
|
|
ubfx x9, \receiver, #0, #SMALLOBJ_BITS
|
|
cbnz x9, 6f
|
|
|
|
ldr x9, [\receiver] // Load class to x9 if not a small int
|
|
1:
|
|
ldr x9, [x9, #DTABLE_OFFSET] // Dtable -> x9
|
|
ldr w10, [\sel] // 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
|
|
// Save anything that will be clobbered by
|
|
// the call
|
|
stp x0, x1, [sp, #-(ARGUMENT_SPILL_SIZE)]!
|
|
stp x2, x3, [sp, #16] // The order is arbitrary, except that
|
|
stp x4, x5, [sp, #32] // fp and lr must be spilled together and
|
|
stp x6, x7, [sp, #48] // it's convenient if \receiver is spilled at sp
|
|
stp q0, q1, [sp, #64]
|
|
stp q2, q3, [sp, #96]
|
|
stp q4, q5, [sp, #128]
|
|
stp q6, q7, [sp, #160]
|
|
stp fp, lr, [sp, #192]
|
|
add fp, sp, 192
|
|
stp \receiver, x8, [sp, #-16]!
|
|
.cfi_def_cfa fp, 16
|
|
.cfi_offset fp, -16
|
|
.cfi_offset lr, -8
|
|
// 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, \sel
|
|
bl CDECL(slowMsgLookup) // This is the only place where the CFI directives
|
|
// have to be accurate...
|
|
mov x9, x0 // IMP -> x9
|
|
ldp x0, x1, [sp, #16] // Reload spilled argument registers
|
|
ldp x2, x3, [sp, #32]
|
|
ldp x4, x5, [sp, #64]
|
|
ldp x6, x7, [sp, #64]
|
|
ldp q0, q1, [sp, #80]
|
|
ldp q2, q3, [sp, #112]
|
|
ldp q4, q5, [sp, #144]
|
|
ldp q6, q7, [sp, #176]
|
|
ldp fp, lr, [sp, #208]
|
|
ldp \receiver, x8, [sp], #(ARGUMENT_SPILL_SIZE + 16)
|
|
br x9
|
|
6:
|
|
adrp x10, :got:SmallObjectClasses
|
|
ldr x10, [x10, :got_lo12:SmallObjectClasses]
|
|
ldr x9, [x10, x9, lsl #3]
|
|
b 1b
|
|
.cfi_endproc
|
|
.endm
|
|
|
|
.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):
|
|
MSGSEND x0, x1
|
|
|