From 49e22fe6788aada2582f36fc219b0c47cf92c616 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Fri, 17 Jun 2022 01:28:14 +0200 Subject: [PATCH] runtime: load sp and pc inside tinygo_longjmp This is a small change to make it easier to support architectures that need to restore more than just the sp and pc registers. In particular, it is needed for the AVR architecture that needs to restore the frame pointer (Y register). --- src/runtime/asm_386.S | 5 +++-- src/runtime/asm_amd64.S | 10 +++++----- src/runtime/asm_amd64_windows.S | 10 +++++----- src/runtime/asm_arm.S | 2 ++ src/runtime/asm_arm64.S | 5 +++-- src/runtime/asm_riscv.S | 7 ++++--- src/runtime/panic.go | 4 ++-- 7 files changed, 24 insertions(+), 19 deletions(-) diff --git a/src/runtime/asm_386.S b/src/runtime/asm_386.S index 1854be6a0..faaa7c3a3 100644 --- a/src/runtime/asm_386.S +++ b/src/runtime/asm_386.S @@ -28,6 +28,7 @@ tinygo_scanCurrentStack: tinygo_longjmp: // Note: the code we jump to assumes eax is set to a non-zero value if we // jump from here. - movl 8(%esp), %eax // jumpPC (stash in volatile register) - movl 4(%esp), %esp // jumpSP + movl 4(%esp), %eax + movl 0(%eax), %esp // jumpSP + movl 4(%eax), %eax // jumpPC (stash in volatile register) jmpl *%eax diff --git a/src/runtime/asm_amd64.S b/src/runtime/asm_amd64.S index 2168a6f41..79f26ff59 100644 --- a/src/runtime/asm_amd64.S +++ b/src/runtime/asm_amd64.S @@ -37,11 +37,11 @@ tinygo_longjmp: .global _tinygo_longjmp _tinygo_longjmp: #endif - // Note: the code we jump to assumes rax is non-zero so we have to load it - // with some value here. - movq $1, %rax - movq %rdi, %rsp // jumpSP - jmpq *%rsi // jumpPC + // Note: the code we jump to assumes rax is set to a non-zero value if we + // jump from here, so we use rax as the temporary value for jumpPC. + movq 0(%rdi), %rsp // jumpSP + movq 8(%rdi), %rax // jumpPC + jmpq *%rax #ifdef __MACH__ // Darwin diff --git a/src/runtime/asm_amd64_windows.S b/src/runtime/asm_amd64_windows.S index 2e717baf9..190523979 100644 --- a/src/runtime/asm_amd64_windows.S +++ b/src/runtime/asm_amd64_windows.S @@ -24,8 +24,8 @@ tinygo_scanCurrentStack: .section .text.tinygo_longjmp,"ax" .global tinygo_longjmp tinygo_longjmp: - // Note: the code we jump to assumes rax is non-zero so we have to load it - // with some value here. - movq $1, %rax - movq %rcx, %rsp // jumpSP - jmpq *%rdx // jumpPC + // Note: the code we jump to assumes rax is set to a non-zero value if we + // jump from here, so we use rax as the temporary value for jumpPC. + movq 0(%rcx), %rsp // jumpSP + movq 8(%rcx), %rax // jumpPC + jmpq *%rax diff --git a/src/runtime/asm_arm.S b/src/runtime/asm_arm.S index d1de455c2..a0077b920 100644 --- a/src/runtime/asm_arm.S +++ b/src/runtime/asm_arm.S @@ -40,6 +40,8 @@ tinygo_longjmp: .cfi_startproc // Note: the code we jump to assumes r0 is set to a non-zero value if we // jump from here (which is conveniently already the case). + + ldm r0, {r0, r1} mov sp, r0 // jumpSP mov pc, r1 // jumpPC .cfi_endproc diff --git a/src/runtime/asm_arm64.S b/src/runtime/asm_arm64.S index 1eb26e8be..679f55fa1 100644 --- a/src/runtime/asm_arm64.S +++ b/src/runtime/asm_arm64.S @@ -43,5 +43,6 @@ tinygo_longjmp: #endif // Note: the code we jump to assumes x0 is set to a non-zero value if we // jump from here (which is conveniently already the case). - mov sp, x0 // jumpSP - br x1 // jumpPC + ldp x1, x2, [x0] // jumpSP, jumpPC + mov sp, x1 + br x2 diff --git a/src/runtime/asm_riscv.S b/src/runtime/asm_riscv.S index 9a99fbc4c..c028d6d53 100644 --- a/src/runtime/asm_riscv.S +++ b/src/runtime/asm_riscv.S @@ -46,6 +46,7 @@ tinygo_scanCurrentStack: .global tinygo_longjmp tinygo_longjmp: // Note: the code we jump to assumes a0 is non-zero, which is already the - // case because that's jumpSP (the stack pointer). - mv sp, a0 // jumpSP - jr a1 // jumpPC + // case because that's the defer frame pointer. + lw sp, 0(a0) // jumpSP + lw a1, REGSIZE(a0) // jumpPC + jr a1 diff --git a/src/runtime/panic.go b/src/runtime/panic.go index dda9e9a9b..143f53dfc 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -13,7 +13,7 @@ func trap() // Inline assembly stub. It is essentially C longjmp but modified a bit for the // purposes of TinyGo. It restores the stack pointer and jumps to the given pc. //export tinygo_longjmp -func tinygo_longjmp(sp, pc unsafe.Pointer) +func tinygo_longjmp(frame *task.DeferFrame) // Compiler intrinsic. // Returns whether recover is supported on the current architecture. @@ -26,7 +26,7 @@ func _panic(message interface{}) { if frame != nil { frame.PanicValue = message frame.Panicking = true - tinygo_longjmp(frame.JumpSP, frame.JumpPC) + tinygo_longjmp(frame) // unreachable } }