|
|
#define DTABLE_OFFSET 64
|
|
|
#define SMALLOBJ_MASK 7
|
|
|
#define SHIFT_OFFSET 4
|
|
|
#define DATA_OFFSET 16
|
|
|
#define SLOT_OFFSET 32
|
|
|
.macro MSGSEND receiver, sel
|
|
|
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
|
|
|
cmpq uninstalled_dtable(%rip), %r10 # If this is not (yet) a valid dtable
|
|
|
je 5f # Do a slow lookup
|
|
|
|
|
|
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
|
|
|
jmp *%r10
|
|
|
4: # returnNil:
|
|
|
xor %rax, %rax
|
|
|
ret
|
|
|
5: # slowSend:
|
|
|
push %rax # We need to preserve all registers that may contain arguments:
|
|
|
push %rbx
|
|
|
push %rcx
|
|
|
push %rdx
|
|
|
push %r8
|
|
|
push %r9
|
|
|
|
|
|
# We're (potentially) modifying the self argument with the lookup, so we don't want to be
|
|
|
.ifc "\receiver", "%rdi"
|
|
|
push %rsi # Save _cmd (not preserved across calls)
|
|
|
.else
|
|
|
push %rdi # Save the sret pointer
|
|
|
mov \sel, %rsi # move _cmd to where the callee expects it to be
|
|
|
.endif
|
|
|
|
|
|
push \receiver # Store the receiver on the stack
|
|
|
mov %rsp, %rdi # First argument is &self
|
|
|
call slowMsgLookup # Call the slow lookup function
|
|
|
mov %rax, %r10 # Load the returned IMP
|
|
|
pop \receiver # Load the (potentially) new receiver
|
|
|
|
|
|
.if \receiver == %rdi
|
|
|
pop %rsi
|
|
|
.else
|
|
|
pop %rdi
|
|
|
.endif
|
|
|
|
|
|
pop %r9
|
|
|
pop %r8
|
|
|
pop %rdx
|
|
|
pop %rcx
|
|
|
pop %rbx
|
|
|
pop %rax
|
|
|
jmp *%r10
|
|
|
6: # smallObject:
|
|
|
and %rdi, %r10 # Find the small int type
|
|
|
shll $3, %r10d
|
|
|
lea SmallObjectClasses(%rip), %r11
|
|
|
add %r11, %r10
|
|
|
mov (%r10), %r10
|
|
|
jmp 1b
|
|
|
.endm
|
|
|
.globl objc_msgSend
|
|
|
.type objc_msgSend, @function
|
|
|
objc_msgSend:
|
|
|
MSGSEND %rdi, %rsi
|
|
|
.globl objc_msgSend_stret
|
|
|
.type objc_msgSend_stret, @function
|
|
|
objc_msgSend_stret:
|
|
|
MSGSEND %rsi, %rdx
|