aboutsummaryrefslogtreecommitdiff
path: root/src/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'src/runtime')
-rw-r--r--src/runtime/arch1_amd64.go2
-rw-r--r--src/runtime/asm_amd64.s26
-rw-r--r--src/runtime/cgocall.go5
-rw-r--r--src/runtime/proc1.go3
-rw-r--r--src/runtime/runtime2.go1
-rw-r--r--src/runtime/stack1.go17
-rw-r--r--src/runtime/traceback.go6
7 files changed, 56 insertions, 4 deletions
diff --git a/src/runtime/arch1_amd64.go b/src/runtime/arch1_amd64.go
index 794b7f65c4..7a7f3e75fc 100644
--- a/src/runtime/arch1_amd64.go
+++ b/src/runtime/arch1_amd64.go
@@ -8,7 +8,7 @@ const (
thechar = '6'
_BigEndian = 0
_CacheLineSize = 64
- _RuntimeGogoBytes = 64 + (goos_plan9|goos_solaris|goos_windows)*16
+ _RuntimeGogoBytes = 80 + (goos_plan9|goos_solaris|goos_windows)*16
_PhysPageSize = 4096
_PCQuantum = 1
_Int64Align = 8
diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s
index b1bf4ca987..f09e5ae250 100644
--- a/src/runtime/asm_amd64.s
+++ b/src/runtime/asm_amd64.s
@@ -134,6 +134,7 @@ TEXT runtime·gosave(SB), NOSPLIT, $0-8
MOVQ BX, gobuf_pc(AX)
MOVQ $0, gobuf_ret(AX)
MOVQ $0, gobuf_ctxt(AX)
+ MOVQ BP, gobuf_bp(AX)
get_tls(CX)
MOVQ g(CX), BX
MOVQ BX, gobuf_g(AX)
@@ -150,9 +151,11 @@ TEXT runtime·gogo(SB), NOSPLIT, $0-8
MOVQ gobuf_sp(BX), SP // restore SP
MOVQ gobuf_ret(BX), AX
MOVQ gobuf_ctxt(BX), DX
+ MOVQ gobuf_bp(BX), BP
MOVQ $0, gobuf_sp(BX) // clear to help garbage collector
MOVQ $0, gobuf_ret(BX)
MOVQ $0, gobuf_ctxt(BX)
+ MOVQ $0, gobuf_bp(BX)
MOVQ gobuf_pc(BX), BX
JMP BX
@@ -170,6 +173,7 @@ TEXT runtime·mcall(SB), NOSPLIT, $0-8
LEAQ fn+0(FP), BX // caller's SP
MOVQ BX, (g_sched+gobuf_sp)(AX)
MOVQ AX, (g_sched+gobuf_g)(AX)
+ MOVQ BP, (g_sched+gobuf_bp)(AX)
// switch to m->g0 & its stack, call fn
MOVQ g(CX), BX
@@ -228,6 +232,7 @@ switch:
MOVQ SI, (g_sched+gobuf_pc)(AX)
MOVQ SP, (g_sched+gobuf_sp)(AX)
MOVQ AX, (g_sched+gobuf_g)(AX)
+ MOVQ BP, (g_sched+gobuf_bp)(AX)
// switch to g0
MOVQ DX, g(CX)
@@ -303,6 +308,7 @@ TEXT runtime·morestack(SB),NOSPLIT,$0-0
LEAQ 8(SP), AX // f's SP
MOVQ AX, (g_sched+gobuf_sp)(SI)
MOVQ DX, (g_sched+gobuf_ctxt)(SI)
+ MOVQ BP, (g_sched+gobuf_bp)(SI)
// Call newstack on m->g0's stack.
MOVQ m_g0(BX), BX
@@ -592,6 +598,7 @@ TEXT gosave<>(SB),NOSPLIT,$0
MOVQ R9, (g_sched+gobuf_sp)(R8)
MOVQ $0, (g_sched+gobuf_ret)(R8)
MOVQ $0, (g_sched+gobuf_ctxt)(R8)
+ MOVQ BP, (g_sched+gobuf_bp)(R8)
RET
// asmcgocall(void(*fn)(void*), void *arg)
@@ -747,17 +754,30 @@ havem:
MOVQ (g_sched+gobuf_sp)(SI), DI // prepare stack as DI
MOVQ (g_sched+gobuf_pc)(SI), BX
MOVQ BX, -8(DI)
- LEAQ -(8+8)(DI), SP
+ // Compute the size of the frame, including return PC and, if
+ // GOEXPERIMENT=framepointer, the saved based pointer
+ LEAQ x+0(FP), AX
+ SUBQ SP, AX
+ SUBQ AX, DI
+ MOVQ DI, SP
+
MOVQ R8, 0(SP)
CALL runtime·cgocallbackg(SB)
MOVQ 0(SP), R8
+ // Compute the size of the frame again. FP and SP have
+ // completely different values here than they did above,
+ // but only their difference matters.
+ LEAQ x+0(FP), AX
+ SUBQ SP, AX
+
// Restore g->sched (== m->curg->sched) from saved values.
get_tls(CX)
MOVQ g(CX), SI
- MOVQ 8(SP), BX
+ MOVQ SP, DI
+ ADDQ AX, DI
+ MOVQ -8(DI), BX
MOVQ BX, (g_sched+gobuf_pc)(SI)
- LEAQ (8+8)(SP), DI
MOVQ DI, (g_sched+gobuf_sp)(SI)
// Switch back to m->g0's stack and restore m->g0->sched.sp.
diff --git a/src/runtime/cgocall.go b/src/runtime/cgocall.go
index 96873cc2da..e7aeb7bee3 100644
--- a/src/runtime/cgocall.go
+++ b/src/runtime/cgocall.go
@@ -225,6 +225,11 @@ func cgocallbackg1() {
cb = (*args)(unsafe.Pointer(sp + 4*ptrSize))
case "amd64":
// On amd64, stack frame is one word, plus caller PC.
+ if framepointer_enabled {
+ // In this case, there's also saved BP.
+ cb = (*args)(unsafe.Pointer(sp + 3*ptrSize))
+ break
+ }
cb = (*args)(unsafe.Pointer(sp + 2*ptrSize))
case "386":
// On 386, stack frame is three words, plus caller PC.
diff --git a/src/runtime/proc1.go b/src/runtime/proc1.go
index 8f5aaa8630..31bbd0d366 100644
--- a/src/runtime/proc1.go
+++ b/src/runtime/proc1.go
@@ -113,6 +113,9 @@ func schedinit() {
sched.maxmcount = 10000
+ // Cache the framepointer experiment. This affects stack unwinding.
+ framepointer_enabled = haveexperiment("framepointer")
+
tracebackinit()
symtabinit()
stackinit()
diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go
index fd448901a6..e38d11a59d 100644
--- a/src/runtime/runtime2.go
+++ b/src/runtime/runtime2.go
@@ -125,6 +125,7 @@ type gobuf struct {
ctxt unsafe.Pointer // this has to be a pointer so that gc scans it
ret uintreg
lr uintptr
+ bp uintptr // for GOEXPERIMENT=framepointer
}
// Known to compiler.
diff --git a/src/runtime/stack1.go b/src/runtime/stack1.go
index 8ad331777c..1e9ccfebb5 100644
--- a/src/runtime/stack1.go
+++ b/src/runtime/stack1.go
@@ -46,6 +46,9 @@ var stackpoolmu mutex
var stackfreequeue stack
+// Cached value of haveexperiment("framepointer")
+var framepointer_enabled bool
+
func stackinit() {
if _StackCacheSize&_PageMask != 0 {
throw("cache size must be a multiple of page size")
@@ -308,6 +311,8 @@ var mapnames = []string{
// | args from caller |
// +------------------+ <- frame->argp
// | return address |
+// +------------------+
+// | caller's BP (*) | (*) if framepointer_enabled && varp < sp
// +------------------+ <- frame->varp
// | locals |
// +------------------+
@@ -460,6 +465,18 @@ func adjustframe(frame *stkframe, arg unsafe.Pointer) bool {
adjustpointers(unsafe.Pointer(frame.varp-size), &bv, adjinfo, f)
}
+ // Adjust saved base pointer if there is one.
+ if thechar == '6' && frame.argp-frame.varp == 2*ptrSize {
+ if !framepointer_enabled {
+ print("runtime: found space for saved base pointer, but no framepointer experiment")
+ throw("bad frame layout")
+ }
+ if stackDebug >= 3 {
+ print(" saved bp\n")
+ }
+ adjustpointer(adjinfo, unsafe.Pointer(frame.varp))
+ }
+
// Adjust arguments.
if frame.arglen > 0 {
var bv bitvector
diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go
index 499256f42d..c813453399 100644
--- a/src/runtime/traceback.go
+++ b/src/runtime/traceback.go
@@ -232,6 +232,12 @@ func gentraceback(pc0 uintptr, sp0 uintptr, lr0 uintptr, gp *g, skip int, pcbuf
frame.varp -= regSize
}
+ // If framepointer_enabled and there's a frame, then
+ // there's a saved bp here.
+ if GOARCH == "amd64" && frame.varp > frame.sp && framepointer_enabled {
+ frame.varp -= ptrSize
+ }
+
// Derive size of arguments.
// Most functions have a fixed-size argument block,
// so we can use metadata about the function f.