darling-libobjc2/objc_msgSend.x86-64.S

280 lines
9.0 KiB
ArmAsm

#define DTABLE_OFFSET 64
#define SMALLOBJ_MASK 7
#define SHIFT_OFFSET 4
#define DATA_OFFSET 16
#define SLOT_OFFSET 32
.macro MSGSEND receiver, sel
.cfi_startproc # Start emitting unwind data. We
# don't actually care about any of
# the stuff except the slow call,
# because that's the only one that
# can throw.
test \receiver, \receiver # If the receiver is nil
jz 4f # return nil
movq $SMALLOBJ_MASK, %r10 # Load the small object mask
test \receiver, %r10 # Check if the receiver is a small object
jnz 6f # Get the small object class
mov (\receiver), %r10 # Load the dtable from the class
1: # classLoaded
mov DTABLE_OFFSET(%r10), %r10 # Load the dtable from the class
push %r12
push %r13
mov (\sel), %r11 # Load the selector index
mov SHIFT_OFFSET(%r10), %r13 # Load the shift (dtable size)
mov DATA_OFFSET(%r10), %r12 # load the address of the start of the array
cmpl $8, %r13d # If this is a small dtable, jump to the small dtable handlers
je 2f
cmpl $0, %r13d
je 3f
mov %r11, %r13
and $0xff0000, %r13
shrl $13, %r13d # Right shift 16, but then left shift by 3 *sizeof(void*)
add %r13, %r12
mov (%r12), %r12
mov DATA_OFFSET(%r12), %r12
2: # dtable16:
mov %r11, %r13
and $0xff00, %r13
shrl $5, %r13d
add %r13, %r12
mov (%r12), %r12
mov DATA_OFFSET(%r12), %r12
3: # dtable8:
mov %r11, %r13
and $0xff, %r13
shll $3, %r13d
add %r13, %r12
mov (%r12), %r10
pop %r13
pop %r12
test %r10, %r10
jz 5f # Nil slot - invoke some kind of forwarding mechanism
mov SLOT_OFFSET(%r10), %r10
7:
#ifdef WITH_TRACING
push %r12
push %r13
push %r10
mov (\sel), %r11 # Load the selector index
lea tracing_dtable(%rip), %r10
mov (%r10), %r10
mov SHIFT_OFFSET(%r10), %r13 # Load the shift (dtable size)
mov DATA_OFFSET(%r10), %r12 # load the address of the start of the array
pop %r10
cmpl $8, %r13d # If this is a small dtable, jump to the small dtable handlers
je 10f
cmpl $0, %r13d
je 11f
mov %r11, %r13
and $0xff0000, %r13
shrl $13, %r13d # Right shift 16, but then left shift by 3 *sizeof(void*)
add %r13, %r12
mov (%r12), %r12
mov DATA_OFFSET(%r12), %r12
10: # dtable16:
mov %r11, %r13
and $0xff00, %r13
shrl $5, %r13d
add %r13, %r12
mov (%r12), %r12
mov DATA_OFFSET(%r12), %r12
11: # dtable8:
mov %r11, %r13
and $0xff, %r13
shll $3, %r13d
add %r13, %r12
mov (%r12), %r11
pop %r13
pop %r12
test %r11, %r11
jz 12f
push %rax # We need to preserve all registers that may contain arguments:
push %rdi
push %rsi
push %rdx
push %rcx
push %r8
push %r9
push %r10
push %r11
mov \receiver, %rdi # Arg 0 is receiver
mov \sel, %rsi # Arg 1 is selector
mov %r10, %rdx # Arg 2 is IMP
mov $0, %rcx # Arg 3 is entry / exit (0/1)
mov $0, %r8 # Arg 4 is return value (0 on entry)
call *%r11 # Call the tracing function
cmpq $0, %rax
jz 13f # If it returns 0, don't call the end-tracing function.
cmpq $1, %rax # If it returns 1, do call the tracing function
jne 14f # Any other value is an interposition
# function to call instead of the method
call pushTraceReturnStack # rax now contains a thread-local buffer for storing returns
pop %r11 # Restore all of the argument registers
pop %r10 # except rax, which we'll need before the call
pop %r9
pop %r8
pop %rcx
pop %rdx
pop %rsi
pop %rdi
mov \receiver, (%rax) # Store the receiver in TLS
mov \sel, 8(%rax) # Store the selector in TLS
mov %r10, 16(%rax) # Store the method in TLS
mov %r11, 24(%rax) # Store the tracing function in TLS
mov 8(%rsp), %r11 # r11 now contains the return address
mov %r11, 32(%rax) # Store the method-return address in TLS
pop %rax
pop %r11 # r11 now contains the return address, but we don't care
call *%r10 # Call the IMP. The stack should now be in the same state
# that it was on entry into this function
push %rax # Now we are free to clobber argument
push %rdx # registers, but we must preserve return registers...
call popTraceReturnStack # rax now contains a thread-local buffer for storing returns
push %rax # save the return value, because we'll need it after the tracing function call
mov (%rax), %rdi # Load the receiver into arg 0
mov 8(%rax), %rsi # Load the selector into arg 1
mov 16(%rax), %rdx # Load the IMP into arg 3
mov $1, %rcx # Arg 4 is 1 (tracing on exit)
mov %rax, %r8 # Arg 5 is the return result
mov 24(%rax), %r11 # Reload the address of the tracing function
call *%r11 # Call the tracing function
pop %rax # Reload the real return address
mov 32(%rax), %r11
pop %rdx # Reload saved values
pop %rax
jmp *%r11 # Simulate a return by jumping to the cached return address
13: # Skip tracing on exit and just tail-call the method
pop %r11
pop %r10
pop %r9
pop %r8
pop %rcx
pop %rdx
pop %rsi
pop %rdi
pop %rax
jmp *%r10
14:
mov %rax, %r10
pop %r9
pop %r9
pop %r9
pop %r8
pop %rcx
pop %rdx
pop %rsi
pop %rdi
pop %rax
12:
#endif // WITH_TRACING
jmp *%r10
4: # returnNil:
# Both of the return registers are
# callee-save on x86-64, so we can
# return 0 in both in the same code:
xor %rax, %rax # Return 0 as an integer
pxor %xmm0, %xmm0 # Return 0 as a floating point value
ret
5: # slowSend:
push %rax # We need to preserve all registers that may contain arguments:
push %rbx
push %rcx
push %r8
push %r9
sub $0x98, %rsp
movups %xmm0, 0x80(%rsp)
movups %xmm1, 0x70(%rsp)
movups %xmm2, 0x60(%rsp)
movups %xmm3, 0x50(%rsp)
movups %xmm4, 0x40(%rsp)
movups %xmm5, 0x30(%rsp)
movups %xmm6, 0x20(%rsp)
movups %xmm7, 0x10(%rsp)
#rdi rsi rdx
# We're (potentially) modifying the self argument with the lookup, so we don't want to be
.ifc "\receiver", "%rdi"
push %rdi
mov %rsp, %rdi
push %rsi # Save _cmd (not preserved across calls)
push %rdx
.else
push %rdi # Save the sret pointer
push %rsi # Save self where it can be modified
mov %rsp, %rdi
push %rdx
mov %rdx, %rsi # move _cmd to where the callee expects it to be
.endif
.cfi_adjust_cfa_offset 0xD8
call CDECL(slowMsgLookup) # Call the slow lookup function
mov %rax, %r10 # Load the returned IMP
pop %rdx
pop %rsi
pop %rdi
movups 0x80(%rsp), %xmm0
movups 0x70(%rsp), %xmm1
movups 0x60(%rsp), %xmm2
movups 0x50(%rsp), %xmm3
movups 0x40(%rsp), %xmm4
movups 0x30(%rsp), %xmm5
movups 0x20(%rsp), %xmm6
movups 0x10(%rsp), %xmm7
add $0x98, %rsp
pop %r9
pop %r8
pop %rcx
pop %rbx
pop %rax
jmp 7b
6: # smallObject:
and \receiver, %r10 # Find the small int type
shll $3, %r10d
lea CDECL(SmallObjectClasses)(%rip), %r11
add %r11, %r10
mov (%r10), %r10
jmp 1b
.cfi_endproc
.endm
.globl CDECL(objc_msgSend)
TYPE_DIRECTIVE(CDECL(objc_msgSend), @function)
.globl CDECL(objc_msgSend_fpret)
TYPE_DIRECTIVE(CDECL(objc_msgSend_fpret), @function)
CDECL(objc_msgSend_fpret):
CDECL(objc_msgSend):
MSGSEND %rdi, %rsi
.globl CDECL(objc_msgSend_stret)
TYPE_DIRECTIVE(CDECL(objc_msgSend_stret), @function)
CDECL(objc_msgSend_stret):
MSGSEND %rsi, %rdx