Skip to content

Commit 4c9a372

Browse files
committed
runtime, cmd/internal/obj: get rid of rewindmorestack
In the function prologue, we emit a jump to the beginning of the function immediately after calling morestack. And in the runtime stack growing code, it decodes and emulates that jump. This emulation was necessary before we had per-PC SP deltas, since the traceback code assumed that the frame size was fixed for the whole function, except on the first instruction where it was 0. Since we now have per-PC SP deltas and PCDATA, we can correctly record that the frame size is 0. This makes the emulation unnecessary. This may be helpful for registerized calling convention, where there may be unspills of arguments after calling morestack. It also simplifies the runtime. Change-Id: I7ebee31eaee81795445b33f521ab6a79624c4ceb Reviewed-on: https://go-review.googlesource.com/30138 Reviewed-by: David Chase <[email protected]>
1 parent 56b7469 commit 4c9a372

File tree

13 files changed

+103
-147
lines changed

13 files changed

+103
-147
lines changed

src/cmd/internal/obj/arm/obj5.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -803,12 +803,24 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
803803
for last = ctxt.Cursym.Text; last.Link != nil; last = last.Link {
804804
}
805805

806+
// Now we are at the end of the function, but logically
807+
// we are still in function prologue. We need to fix the
808+
// SP data and PCDATA.
806809
spfix := obj.Appendp(ctxt, last)
807810
spfix.As = obj.ANOP
808811
spfix.Spadj = -framesize
809812

813+
pcdata := obj.Appendp(ctxt, spfix)
814+
pcdata.Lineno = ctxt.Cursym.Text.Lineno
815+
pcdata.Mode = ctxt.Cursym.Text.Mode
816+
pcdata.As = obj.APCDATA
817+
pcdata.From.Type = obj.TYPE_CONST
818+
pcdata.From.Offset = obj.PCDATA_StackMapIndex
819+
pcdata.To.Type = obj.TYPE_CONST
820+
pcdata.To.Offset = -1 // pcdata starts at -1 at function entry
821+
810822
// MOVW LR, R3
811-
movw := obj.Appendp(ctxt, spfix)
823+
movw := obj.Appendp(ctxt, pcdata)
812824
movw.As = AMOVW
813825
movw.From.Type = obj.TYPE_REG
814826
movw.From.Reg = REGLINK

src/cmd/internal/obj/arm64/obj7.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,12 +161,24 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
161161
for last = ctxt.Cursym.Text; last.Link != nil; last = last.Link {
162162
}
163163

164+
// Now we are at the end of the function, but logically
165+
// we are still in function prologue. We need to fix the
166+
// SP data and PCDATA.
164167
spfix := obj.Appendp(ctxt, last)
165168
spfix.As = obj.ANOP
166169
spfix.Spadj = -framesize
167170

171+
pcdata := obj.Appendp(ctxt, spfix)
172+
pcdata.Lineno = ctxt.Cursym.Text.Lineno
173+
pcdata.Mode = ctxt.Cursym.Text.Mode
174+
pcdata.As = obj.APCDATA
175+
pcdata.From.Type = obj.TYPE_CONST
176+
pcdata.From.Offset = obj.PCDATA_StackMapIndex
177+
pcdata.To.Type = obj.TYPE_CONST
178+
pcdata.To.Offset = -1 // pcdata starts at -1 at function entry
179+
168180
// MOV LR, R3
169-
movlr := obj.Appendp(ctxt, spfix)
181+
movlr := obj.Appendp(ctxt, pcdata)
170182
movlr.As = AMOVD
171183
movlr.From.Type = obj.TYPE_REG
172184
movlr.From.Reg = REGLINK

src/cmd/internal/obj/pcln.go

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,12 @@ func addvarint(ctxt *Link, d *Pcdata, val uint32) {
2525
// where func is the function, val is the current value, p is the instruction being
2626
// considered, and arg can be used to further parameterize valfunc.
2727
func funcpctab(ctxt *Link, dst *Pcdata, func_ *LSym, desc string, valfunc func(*Link, *LSym, int32, *Prog, int32, interface{}) int32, arg interface{}) {
28-
// To debug a specific function, uncomment second line and change name.
28+
// To debug a specific function, uncomment lines and change name.
2929
dbg := 0
3030

31-
//dbg = strcmp(func->name, "main.main") == 0;
32-
//dbg = strcmp(desc, "pctofile") == 0;
31+
//if func_.Name == "main.main" || desc == "pctospadj" {
32+
// dbg = 1
33+
//}
3334

3435
ctxt.Debugpcln += int32(dbg)
3536

@@ -214,9 +215,15 @@ func linkpcln(ctxt *Link, cursym *LSym) {
214215
npcdata := 0
215216
nfuncdata := 0
216217
for p := cursym.Text; p != nil; p = p.Link {
217-
if p.As == APCDATA && p.From.Offset >= int64(npcdata) {
218+
// Find the highest ID of any used PCDATA table. This ignores PCDATA table
219+
// that consist entirely of "-1", since that's the assumed default value.
220+
// From.Offset is table ID
221+
// To.Offset is data
222+
if p.As == APCDATA && p.From.Offset >= int64(npcdata) && p.To.Offset != -1 { // ignore -1 as we start at -1, if we only see -1, nothing changed
218223
npcdata = int(p.From.Offset + 1)
219224
}
225+
// Find the highest ID of any FUNCDATA table.
226+
// From.Offset is table ID
220227
if p.As == AFUNCDATA && p.From.Offset >= int64(nfuncdata) {
221228
nfuncdata = int(p.From.Offset + 1)
222229
}
@@ -243,7 +250,7 @@ func linkpcln(ctxt *Link, cursym *LSym) {
243250
havefunc[p.From.Offset/32] |= 1 << uint64(p.From.Offset%32)
244251
}
245252

246-
if p.As == APCDATA {
253+
if p.As == APCDATA && p.To.Offset != -1 {
247254
havepc[p.From.Offset/32] |= 1 << uint64(p.From.Offset%32)
248255
}
249256
}

src/cmd/internal/obj/ppc64/obj9.go

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -823,6 +823,8 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
823823
}
824824
*/
825825
func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
826+
p0 := p // save entry point, but skipping the two instructions setting R2 in shared mode
827+
826828
// MOVD g_stackguard(g), R3
827829
p = obj.Appendp(ctxt, p)
828830

@@ -953,6 +955,24 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
953955
morestacksym = obj.Linklookup(ctxt, "runtime.morestack", 0)
954956
}
955957

958+
if ctxt.Flag_shared {
959+
// In PPC64 PIC code, R2 is used as TOC pointer derived from R12
960+
// which is the address of function entry point when entering
961+
// the function. We need to preserve R2 across call to morestack.
962+
// Fortunately, in shared mode, 8(SP) and 16(SP) are reserved in
963+
// the caller's frame, but not used (0(SP) is caller's saved LR,
964+
// 24(SP) is caller's saved R2). Use 8(SP) to save this function's R2.
965+
966+
// MOVD R12, 8(SP)
967+
p = obj.Appendp(ctxt, p)
968+
p.As = AMOVD
969+
p.From.Type = obj.TYPE_REG
970+
p.From.Reg = REG_R2
971+
p.To.Type = obj.TYPE_MEM
972+
p.To.Reg = REGSP
973+
p.To.Offset = 8
974+
}
975+
956976
if ctxt.Flag_dynlink {
957977
// Avoid calling morestack via a PLT when dynamically linking. The
958978
// PLT stubs generated by the system linker on ppc64le when "std r2,
@@ -1000,12 +1020,23 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
10001020
p.To.Type = obj.TYPE_BRANCH
10011021
p.To.Sym = morestacksym
10021022
}
1023+
1024+
if ctxt.Flag_shared {
1025+
// MOVD 8(SP), R2
1026+
p = obj.Appendp(ctxt, p)
1027+
p.As = AMOVD
1028+
p.From.Type = obj.TYPE_MEM
1029+
p.From.Reg = REGSP
1030+
p.From.Offset = 8
1031+
p.To.Type = obj.TYPE_REG
1032+
p.To.Reg = REG_R2
1033+
}
1034+
10031035
// BR start
10041036
p = obj.Appendp(ctxt, p)
1005-
10061037
p.As = ABR
10071038
p.To.Type = obj.TYPE_BRANCH
1008-
p.Pcond = ctxt.Cursym.Text.Link
1039+
p.Pcond = p0.Link
10091040

10101041
// placeholder for q1's jump target
10111042
p = obj.Appendp(ctxt, p)

src/cmd/internal/obj/s390x/objz.go

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -599,7 +599,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
599599
}
600600
}
601601
if wasSplit {
602-
pLast = stacksplitPost(ctxt, pLast, pPre, pPreempt) // emit post part of split check
602+
pLast = stacksplitPost(ctxt, pLast, pPre, pPreempt, autosize) // emit post part of split check
603603
}
604604
}
605605

@@ -775,10 +775,25 @@ func stacksplitPre(ctxt *obj.Link, p *obj.Prog, framesize int32) (*obj.Prog, *ob
775775
return p, q
776776
}
777777

778-
func stacksplitPost(ctxt *obj.Link, p *obj.Prog, pPre *obj.Prog, pPreempt *obj.Prog) *obj.Prog {
778+
func stacksplitPost(ctxt *obj.Link, p *obj.Prog, pPre *obj.Prog, pPreempt *obj.Prog, framesize int32) *obj.Prog {
779+
// Now we are at the end of the function, but logically
780+
// we are still in function prologue. We need to fix the
781+
// SP data and PCDATA.
782+
spfix := obj.Appendp(ctxt, p)
783+
spfix.As = obj.ANOP
784+
spfix.Spadj = -framesize
785+
786+
pcdata := obj.Appendp(ctxt, spfix)
787+
pcdata.Lineno = ctxt.Cursym.Text.Lineno
788+
pcdata.Mode = ctxt.Cursym.Text.Mode
789+
pcdata.As = obj.APCDATA
790+
pcdata.From.Type = obj.TYPE_CONST
791+
pcdata.From.Offset = obj.PCDATA_StackMapIndex
792+
pcdata.To.Type = obj.TYPE_CONST
793+
pcdata.To.Offset = -1 // pcdata starts at -1 at function entry
779794

780795
// MOVD LR, R5
781-
p = obj.Appendp(ctxt, p)
796+
p = obj.Appendp(ctxt, pcdata)
782797
pPre.Pcond = p
783798
p.As = AMOVD
784799
p.From.Type = obj.TYPE_REG

src/cmd/internal/obj/x86/obj6.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1113,11 +1113,23 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32, textarg int32) *ob
11131113
for last = ctxt.Cursym.Text; last.Link != nil; last = last.Link {
11141114
}
11151115

1116+
// Now we are at the end of the function, but logically
1117+
// we are still in function prologue. We need to fix the
1118+
// SP data and PCDATA.
11161119
spfix := obj.Appendp(ctxt, last)
11171120
spfix.As = obj.ANOP
11181121
spfix.Spadj = -framesize
11191122

1120-
call := obj.Appendp(ctxt, spfix)
1123+
pcdata := obj.Appendp(ctxt, spfix)
1124+
pcdata.Lineno = ctxt.Cursym.Text.Lineno
1125+
pcdata.Mode = ctxt.Cursym.Text.Mode
1126+
pcdata.As = obj.APCDATA
1127+
pcdata.From.Type = obj.TYPE_CONST
1128+
pcdata.From.Offset = obj.PCDATA_StackMapIndex
1129+
pcdata.To.Type = obj.TYPE_CONST
1130+
pcdata.To.Offset = -1 // pcdata starts at -1 at function entry
1131+
1132+
call := obj.Appendp(ctxt, pcdata)
11211133
call.Lineno = ctxt.Cursym.Text.Lineno
11221134
call.Mode = ctxt.Cursym.Text.Mode
11231135
call.As = obj.ACALL

src/runtime/stack.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -602,7 +602,7 @@ func adjustpointers(scanp unsafe.Pointer, cbv *bitvector, adjinfo *adjustinfo, f
602602
}
603603
if minp <= p && p < maxp {
604604
if stackDebug >= 3 {
605-
print("adjust ptr ", p, " ", funcname(f), "\n")
605+
print("adjust ptr ", hex(p), " ", funcname(f), "\n")
606606
}
607607
if useCAS {
608608
ppu := (*unsafe.Pointer)(unsafe.Pointer(pp))
@@ -957,7 +957,6 @@ func newstack() {
957957
thisg.m.morebuf.lr = 0
958958
thisg.m.morebuf.sp = 0
959959
thisg.m.morebuf.g = 0
960-
rewindmorestack(&gp.sched)
961960

962961
// NOTE: stackguard0 may change underfoot, if another thread
963962
// is about to try to preempt gp. Read it just once and use that same

src/runtime/sys_arm.go

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,22 +17,5 @@ func gostartcall(buf *gobuf, fn, ctxt unsafe.Pointer) {
1717
buf.ctxt = ctxt
1818
}
1919

20-
// Called to rewind context saved during morestack back to beginning of function.
21-
// To help us, the linker emits a jmp back to the beginning right after the
22-
// call to morestack. We just have to decode and apply that jump.
23-
func rewindmorestack(buf *gobuf) {
24-
var inst uint32
25-
if buf.pc&3 == 0 && buf.pc != 0 {
26-
inst = *(*uint32)(unsafe.Pointer(buf.pc))
27-
if inst>>24 == 0x9a || inst>>24 == 0xea {
28-
buf.pc += uintptr(int32(inst<<8)>>6) + 8
29-
return
30-
}
31-
}
32-
33-
print("runtime: pc=", hex(buf.pc), " ", hex(inst), "\n")
34-
throw("runtime: misuse of rewindmorestack")
35-
}
36-
3720
// for testing
3821
func usplit(x uint32) (q, r uint32)

src/runtime/sys_arm64.go

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,3 @@ func gostartcall(buf *gobuf, fn, ctxt unsafe.Pointer) {
1616
buf.pc = uintptr(fn)
1717
buf.ctxt = ctxt
1818
}
19-
20-
// Called to rewind context saved during morestack back to beginning of function.
21-
// To help us, the linker emits a jmp back to the beginning right after the
22-
// call to morestack. We just have to decode and apply that jump.
23-
func rewindmorestack(buf *gobuf) {
24-
var inst uint32
25-
if buf.pc&3 == 0 && buf.pc != 0 {
26-
inst = *(*uint32)(unsafe.Pointer(buf.pc))
27-
// section C3.2.6 Unconditional branch (immediate)
28-
if inst>>26 == 0x05 {
29-
buf.pc += uintptr(int32(inst<<6) >> 4)
30-
return
31-
}
32-
}
33-
34-
print("runtime: pc=", hex(buf.pc), " ", hex(inst), "\n")
35-
throw("runtime: misuse of rewindmorestack")
36-
}

src/runtime/sys_mips64x.go

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -18,26 +18,3 @@ func gostartcall(buf *gobuf, fn, ctxt unsafe.Pointer) {
1818
buf.pc = uintptr(fn)
1919
buf.ctxt = ctxt
2020
}
21-
22-
// Called to rewind context saved during morestack back to beginning of function.
23-
// To help us, the linker emits a jmp back to the beginning right after the
24-
// call to morestack. We just have to decode and apply that jump.
25-
func rewindmorestack(buf *gobuf) {
26-
var inst uint32
27-
if buf.pc&3 == 0 && buf.pc != 0 {
28-
inst = *(*uint32)(unsafe.Pointer(buf.pc))
29-
if inst>>26 == 2 { // JMP addr
30-
//print("runtime: rewind pc=", hex(buf.pc), " to pc=", hex(buf.pc &^ uintptr(1<<28-1) | uintptr((inst&^0xfc000000)<<2)), "\n");
31-
buf.pc &^= 1<<28 - 1
32-
buf.pc |= uintptr((inst &^ 0xfc000000) << 2)
33-
return
34-
}
35-
if inst>>16 == 0x1000 { // BEQ R0, R0, offset
36-
//print("runtime: rewind pc=", hex(buf.pc), " to pc=", hex(buf.pc + uintptr(int32(int16(inst&0xffff))<<2 + 4)), "\n");
37-
buf.pc += uintptr(int32(int16(inst&0xffff))<<2 + 4)
38-
return
39-
}
40-
}
41-
print("runtime: pc=", hex(buf.pc), " ", hex(inst), "\n")
42-
throw("runtime: misuse of rewindmorestack")
43-
}

src/runtime/sys_ppc64x.go

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,4 @@ func gostartcall(buf *gobuf, fn, ctxt unsafe.Pointer) {
1919
buf.ctxt = ctxt
2020
}
2121

22-
// Called to rewind context saved during morestack back to beginning of function.
23-
// To help us, the linker emits a jmp back to the beginning right after the
24-
// call to morestack. We just have to decode and apply that jump.
25-
func rewindmorestack(buf *gobuf) {
26-
var inst uint32
27-
if buf.pc&3 == 0 && buf.pc != 0 {
28-
inst = *(*uint32)(unsafe.Pointer(buf.pc))
29-
if inst>>26 == 18 && inst&3 == 0 {
30-
//print("runtime: rewind pc=", hex(buf.pc), " to pc=", hex(uintptr(buf.pc + int32(inst<<6)>>6)), "\n");
31-
buf.pc += uintptr(int32(inst<<6) >> 6)
32-
return
33-
}
34-
}
35-
print("runtime: pc=", hex(buf.pc), " ", hex(inst), "\n")
36-
throw("runtime: misuse of rewindmorestack")
37-
}
38-
3922
func prepGoExitFrame(sp uintptr)

src/runtime/sys_s390x.go

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -16,30 +16,3 @@ func gostartcall(buf *gobuf, fn, ctxt unsafe.Pointer) {
1616
buf.pc = uintptr(fn)
1717
buf.ctxt = ctxt
1818
}
19-
20-
// Called to rewind context saved during morestack back to beginning of function.
21-
// To help us, the linker emits a jmp back to the beginning right after the
22-
// call to morestack. We just have to decode and apply that jump.
23-
func rewindmorestack(buf *gobuf) {
24-
var inst uint64
25-
if buf.pc&1 == 0 && buf.pc != 0 {
26-
inst = *(*uint64)(unsafe.Pointer(buf.pc))
27-
switch inst >> 48 {
28-
case 0xa7f4: // BRC (branch relative on condition) instruction.
29-
inst >>= 32
30-
inst &= 0xFFFF
31-
offset := int64(int16(inst))
32-
offset <<= 1
33-
buf.pc += uintptr(offset)
34-
return
35-
case 0xc0f4: // BRCL (branch relative on condition long) instruction.
36-
inst >>= 16
37-
inst = inst & 0xFFFFFFFF
38-
inst = (inst << 1) & 0xFFFFFFFF
39-
buf.pc += uintptr(int32(inst))
40-
return
41-
}
42-
}
43-
print("runtime: pc=", hex(buf.pc), " ", hex(inst), "\n")
44-
throw("runtime: misuse of rewindmorestack")
45-
}

src/runtime/sys_x86.go

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -25,33 +25,3 @@ func gostartcall(buf *gobuf, fn, ctxt unsafe.Pointer) {
2525
buf.pc = uintptr(fn)
2626
buf.ctxt = ctxt
2727
}
28-
29-
// Called to rewind context saved during morestack back to beginning of function.
30-
// To help us, the linker emits a jmp back to the beginning right after the
31-
// call to morestack. We just have to decode and apply that jump.
32-
func rewindmorestack(buf *gobuf) {
33-
pc := (*[8]byte)(unsafe.Pointer(buf.pc))
34-
if pc[0] == 0xe9 { // jmp 4-byte offset
35-
buf.pc = buf.pc + 5 + uintptr(int64(*(*int32)(unsafe.Pointer(&pc[1]))))
36-
return
37-
}
38-
if pc[0] == 0xeb { // jmp 1-byte offset
39-
buf.pc = buf.pc + 2 + uintptr(int64(*(*int8)(unsafe.Pointer(&pc[1]))))
40-
return
41-
}
42-
if pc[0] == 0xcc {
43-
// This is a breakpoint inserted by gdb. We could use
44-
// runtime·findfunc to find the function. But if we
45-
// do that, then we will continue execution at the
46-
// function entry point, and we will not hit the gdb
47-
// breakpoint. So for this case we don't change
48-
// buf.pc, so that when we return we will execute
49-
// the jump instruction and carry on. This means that
50-
// stack unwinding may not work entirely correctly
51-
// (https://golang.org/issue/5723) but the user is
52-
// running under gdb anyhow.
53-
return
54-
}
55-
print("runtime: pc=", pc, " ", hex(pc[0]), " ", hex(pc[1]), " ", hex(pc[2]), " ", hex(pc[3]), " ", hex(pc[4]), "\n")
56-
throw("runtime: misuse of rewindmorestack")
57-
}

0 commit comments

Comments
 (0)