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.

208 lines
7.0 KiB
ArmAsm

.set noreorder
# Some macros for n32 / n64 compatibility
#ifdef _ABI64
#define LP ld
#define SP sd
#else
#warning N32 is untested, O32 is unsupported.
#define LP lw
#define SP sw
#endif
.macro dump_and_crash reg
nop
move $a0, \reg
ld $25, %got_disp(logInt)($t8)
jalr $25
nop
lw $zero, ($zero)
.endm
// FIXME: CHERI needs (or, at least, strongly encourages) 32-byte aligned
// stacks.
#ifndef __mips_soft_float
#define SAVE_SIZE 136
#else
#define SAVE_SIZE 72
#endif
.macro MSGSEND receiver, sel
0:
.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.
beq \receiver, $0, 4f # If the receiver is nil, return nil
nop
lui $t8, %hi(%neg(%gp_rel(0b))) # Load the GOT address that we use for relocations into $t8
daddu $t8, $t8, $t9
daddiu $t8, $t8, %lo(%neg(%gp_rel(0b)))
andi $t0, \receiver, SMALLOBJ_MASK # Check if the receiver is a small object
bne $t0, $0, 6f # Get the small object class
nop
LP $t1, (\sel)
# By this point, we have a non-nil
# receiver that is a real pointer
LP $t0, (\receiver) # Load the class
1: # class loaded, stored in $t0
LP $t0, DTABLE_OFFSET($t0) # Load the dtable from the class
lw $t2, SHIFT_OFFSET($t0) # Load the shift (dtable size)
# $t0 = dtable, $t1 = sel index
daddi $t3, $t0, DATA_OFFSET # Compute the address of the start of the array
beq $0, $t2, 3f # If this is a small dtable, jump to the small dtable handlers
daddi $v0, $t2, -8
beq $0, $v0, 2f
lui $t2, 0x00ff # The mask for a big dtable won't fit in an and immediate
and $t2, $t2, $t1 # mask the selector
#ifdef _ABI64
dsrl $t2, $t2, 13 # Right shift 16, but then left shift by pointer size
#else
srl $t2, $t2, 14
#endif
dadd $t2, $t2, $t3
LP $t3, ($t2)
daddi $t3, $t3, DATA_OFFSET # Compute the address of the start of the array
2: # dtable16:
andi $t2, $t1, 0xff00 # mask the selector
#ifdef _ABI64
dsrl $t2, $t2, 5 # Right shift 8, but then left shift by pointer size
#else
srl $t2, $t2, 6
#endif
dadd $t2, $t2, $t3
LP $t3, ($t2)
daddi $t3, $t3, DATA_OFFSET # Compute the address of the start of the array
3: # dtable8:
andi $t2, $t1, 0xff # mask the selector
#ifdef _ABI64
dsll $t2, $t2, 3 # Left shift by pointer size
#else
sll $t2, $t2, 2
#endif
dadd $t2, $t2, $t3
LP $t3, ($t2)
beq $0, $t3, 5f # Nil slot - invoke some kind of forwarding mechanism
nop
LP $25, SLOT_OFFSET($t3)
jr $25
nop
4: # returnNil:
# All of the return registers are
# callee-save, so we can
# return 0 in both in the same code:
#ifndef __mips_soft_float
dmtc1 $0, $f0 # Return 0 as a floating point value (only if we're not a soft-float target)
dmtc1 $0, $f2
#endif
daddi $v0, $0, 0 # Return 0 as an integer
jr $ra
daddi $v1, $0, 0
5: # slowSend:
# Load the address of the slow lookup function now, so that we don't get
# pipeline stalls on the jump. This is more important on CHERI than proper
# MIPS implementations.
# Note: A better linker ought to be able to turn this into a single
# jump-immediate, so revisit this decision later...
LP $25, %got_disp(CDECL(slowMsgLookup))($t8)
daddiu $sp, $sp, -SAVE_SIZE # We need to preserve all registers that may contain arguments:
SP $a0, ($sp)
SP $a1, 8($sp)
SP $a2, 16($sp)
SP $a3, 24($sp)
SP $a4, 32($sp)
SP $a5, 40($sp)
SP $a6, 48($sp)
SP $a7, 56($sp)
SP $ra, 64($sp)
#ifndef __mips_soft_float
sdc1 $f12, 72($sp)
sdc1 $f13, 80($sp)
sdc1 $f14, 88($sp)
sdc1 $f15, 96($sp)
sdc1 $f16, 104($sp)
sdc1 $f17, 112($sp)
sdc1 $f18, 120($sp)
sdc1 $f19, 128($sp)
#endif
# We're (potentially) modifying the self argument with the lookup. Use the
# address of the stack save slot for the address so that when we reload it
# we get the old or new version automatically. Note that we must reload it
# anyway, because argument registers are not guaranteed to be preserved
# across calls.
.ifc "\receiver", "$a0"
daddiu $a0, $sp, 0 # replace self with &self in $a0
.else
daddiu $a0, $sp, 8 # replace sret pointer with &self in $a0
daddiu $a1, $a2, 0 # replace self with _cmd in $a1
.endif
.cfi_def_cfa_offset SAVE_SIZE
.cfi_offset 31, (64 - SAVE_SIZE)
jalr $25 # Call the slow lookup function
nop
move $25, $v0 # Move the return value to $25 for use with the call
LP $a0, ($sp) # Restore all of the arguments. Note
LP $a1, 8($sp) # that the receiver may have been
LP $a2, 16($sp) # modified during the call
LP $a3, 24($sp)
LP $a4, 32($sp)
LP $a5, 40($sp)
LP $a6, 48($sp)
LP $a7, 56($sp)
LP $ra, 64($sp)
#ifndef __mips_soft_float
ldc1 $f12, 72($sp)
ldc1 $f13, 80($sp)
ldc1 $f14, 88($sp)
ldc1 $f15, 96($sp)
ldc1 $f16, 104($sp)
ldc1 $f17, 112($sp)
ldc1 $f18, 120($sp)
ldc1 $f19, 128($sp)
#endif
jr $25
daddiu $sp, $sp, SAVE_SIZE
6: # smallObject:
#if _ABI64
dsll $t0, $t0, 3 # Convert tag to pointer offset
LP $t2, %got_disp(CDECL(SmallObjectClasses))($t8) # Load small object classes array address
daddu $t0, $t0, $t2 # Add the base address to the offset
b 1b # Return to the normal path
LP $t0, ($t0) # Load the class (in delay slot)
#else
b 1b
LP $t0, %got_disp(CDECL(SmallIntClass))($t8)
#endif
.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 $a0, $a1
.globl CDECL(objc_msgSend_stret)
TYPE_DIRECTIVE(CDECL(objc_msgSend_stret), @function)
CDECL(objc_msgSend_stret):
MSGSEND $a1, $a2