Implement on-stack replacement for MIPS32 and MIPS64
Change-Id: I4e589f0597b597adff95e1289f20deb2eab97e9b
diff --git a/runtime/arch/mips64/quick_entrypoints_mips64.S b/runtime/arch/mips64/quick_entrypoints_mips64.S
index f1e605a..f31b92a 100644
--- a/runtime/arch/mips64/quick_entrypoints_mips64.S
+++ b/runtime/arch/mips64/quick_entrypoints_mips64.S
@@ -358,6 +358,138 @@
.endm
/*
+ * On stack replacement stub.
+ * On entry:
+ * a0 = stack to copy
+ * a1 = size of stack
+ * a2 = pc to call
+ * a3 = JValue* result
+ * a4 = shorty
+ * a5 = thread
+ */
+ENTRY art_quick_osr_stub
+ move $t0, $sp # save stack pointer
+ daddiu $t1, $sp, -112 # reserve stack space
+ dsrl $t1, $t1, 4 # enforce 16 byte stack alignment
+ dsll $sp, $t1, 4 # update stack pointer
+
+ // Save callee general purpose registers, SP, T8(GP), RA, A3, and A4 (8x14 bytes)
+ sd $ra, 104($sp)
+ .cfi_rel_offset 31, 104
+ sd $s8, 96($sp)
+ .cfi_rel_offset 30, 96
+ sd $t0, 88($sp) # save original stack pointer stored in t0
+ .cfi_rel_offset 29, 88
+ sd $t8, 80($sp) # t8 holds caller's gp, now save it to the stack.
+ .cfi_rel_offset 28, 80 # Value from gp is pushed, so set the cfi offset accordingly.
+ sd $s7, 72($sp)
+ .cfi_rel_offset 23, 72
+ sd $s6, 64($sp)
+ .cfi_rel_offset 22, 64
+ sd $s5, 56($sp)
+ .cfi_rel_offset 21, 56
+ sd $s4, 48($sp)
+ .cfi_rel_offset 20, 48
+ sd $s3, 40($sp)
+ .cfi_rel_offset 19, 40
+ sd $s2, 32($sp)
+ .cfi_rel_offset 18, 32
+ sd $s1, 24($sp)
+ .cfi_rel_offset 17, 24
+ sd $s0, 16($sp)
+ .cfi_rel_offset 16, 16
+ sd $a4, 8($sp)
+ .cfi_rel_offset 8, 8
+ sd $a3, 0($sp)
+ .cfi_rel_offset 7, 0
+ move rSELF, $a5 # Save managed thread pointer into rSELF
+
+ daddiu $sp, $sp, -16
+ jal .Losr_entry
+ sd $zero, 0($sp) # Store null for ArtMethod* at bottom of frame
+ daddiu $sp, $sp, 16
+
+ // Restore return value address and shorty address
+ ld $a4, 8($sp) # shorty address
+ .cfi_restore 8
+ ld $a3, 0($sp) # result value address
+ .cfi_restore 7
+
+ lbu $t1, 0($a4) # load return type
+ li $t2, 'D' # put char 'D' into t2
+ beq $t1, $t2, .Losr_fp_result # branch if result type char == 'D'
+ li $t2, 'F' # put char 'F' into t2
+ beq $t1, $t2, .Losr_fp_result # branch if result type char == 'F'
+ nop
+ b .Losr_exit
+ dsrl $v1, $v0, 32 # put high half of result in v1
+.Losr_fp_result:
+ mfc1 $v0, $f0
+ mfhc1 $v1, $f0 # put high half of FP result in v1
+.Losr_exit:
+ sw $v0, 0($a3) # store low half of result
+ sw $v1, 4($a3) # store high half of result
+
+ // Restore callee registers
+ ld $ra, 104($sp)
+ .cfi_restore 31
+ ld $s8, 96($sp)
+ .cfi_restore 30
+ ld $t0, 88($sp) # save SP into t0 for now
+ .cfi_restore 29
+ ld $t8, 80($sp) # Restore gp back to it's temp storage.
+ .cfi_restore 28
+ ld $s7, 72($sp)
+ .cfi_restore 23
+ ld $s6, 64($sp)
+ .cfi_restore 22
+ ld $s5, 56($sp)
+ .cfi_restore 21
+ ld $s4, 48($sp)
+ .cfi_restore 20
+ ld $s3, 40($sp)
+ .cfi_restore 19
+ ld $s2, 32($sp)
+ .cfi_restore 18
+ ld $s1, 24($sp)
+ .cfi_restore 17
+ ld $s0, 16($sp)
+ .cfi_restore 16
+ jalr $zero, $ra
+ move $sp, $t0
+
+.Losr_entry:
+ dsubu $sp, $sp, $a1 # Reserve space for callee stack
+ daddiu $a1, $a1, -8
+ daddu $t0, $a1, $sp
+ sw $ra, 0($t0) # Store low half of RA per compiler ABI
+ dsrl $t1, $ra, 32
+ sw $t1, 4($t0) # Store high half of RA per compiler ABI
+
+ // Copy arguments into callee stack
+ // Use simple copy routine for now.
+ // 4 bytes per slot.
+ // a0 = source address
+ // a1 = args length in bytes (does not include 8 bytes for RA)
+ // sp = destination address
+ beqz $a1, .Losr_loop_exit
+ daddiu $a1, $a1, -4
+ daddu $t1, $a0, $a1
+ daddu $t2, $sp, $a1
+.Losr_loop_entry:
+ lw $t0, 0($t1)
+ daddiu $t1, $t1, -4
+ sw $t0, 0($t2)
+ bne $sp, $t2, .Losr_loop_entry
+ daddiu $t2, $t2, -4
+
+.Losr_loop_exit:
+ move $t9, $a2
+ jalr $zero, $t9 # Jump to the OSR entry point.
+ nop
+END art_quick_osr_stub
+
+ /*
* On entry $a0 is uint32_t* gprs_ and $a1 is uint32_t* fprs_
* FIXME: just guessing about the shape of the jmpbuf. Where will pc be?
*/