From cec07c4759e8af44ca77a2beb9312e4e30d1cc7a Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 13 Sep 2018 22:25:58 +0000 Subject: [PATCH] compiler, runtime: call gcWriteBarrier instead of writebarrierptr In 1.11 writebarrierptr is going away, so change the compiler to call gcWriteBarrier instead. We weren't using gcWriteBarrier before; adjust the implementation to use the putFast method. This revealed a problem in the kickoff function. When using cgo, kickoff can be called on the g0 of an m allocated by newExtraM. In that case the m will generally have a p, but systemstack may be called by wbBufFlush as part of flushing the write barrier buffer. At that point the buffer is full, so we can not do a write barrier. So adjust the existing code in kickoff so that in the case where we are g0, don't do any write barrier at all. Reviewed-on: https://go-review.googlesource.com/131395 From-SVN: r264295 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/runtime.def | 2 +- gcc/go/gofrontend/wb.cc | 6 +++--- libgo/go/runtime/mgc_gccgo.go | 12 ++++++------ libgo/go/runtime/proc.go | 35 ++++++++++++++++++++--------------- 5 files changed, 31 insertions(+), 26 deletions(-) diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 9a789b970e0..67ed6589ad1 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -82d7205ba9e5c1fe38fd24f89a45caf2e974975b +218c9159635e06e39ae43d0efe1ac1e694fead2e The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/gcc/go/gofrontend/runtime.def b/gcc/go/gofrontend/runtime.def index 1486cd85f27..ed759e80780 100644 --- a/gcc/go/gofrontend/runtime.def +++ b/gcc/go/gofrontend/runtime.def @@ -302,7 +302,7 @@ DEF_GO_RUNTIME(IFACEEFACEEQ, "runtime.ifaceefaceeq", P2(IFACE, EFACE), // Set *dst = src where dst is a pointer to a pointer and src is a pointer. -DEF_GO_RUNTIME(WRITEBARRIERPTR, "runtime.writebarrierptr", +DEF_GO_RUNTIME(GCWRITEBARRIER, "runtime.gcWriteBarrier", P2(POINTER, POINTER), R0()) // Set *dst = *src for an arbitrary type. diff --git a/gcc/go/gofrontend/wb.cc b/gcc/go/gofrontend/wb.cc index 4944b68fccf..4f84d9950f1 100644 --- a/gcc/go/gofrontend/wb.cc +++ b/gcc/go/gofrontend/wb.cc @@ -380,7 +380,7 @@ Gogo::propagate_writebarrierrec() // This is compatible with the definition in the runtime package. // // For types that are pointer shared (pointers, maps, chans, funcs), -// we replaced the call to typedmemmove with writebarrierptr(&A, B). +// we replaced the call to typedmemmove with gcWriteBarrier(&A, B). // As far as the GC is concerned, all pointers are the same, so it // doesn't need the type descriptor. // @@ -391,7 +391,7 @@ Gogo::propagate_writebarrierrec() // runtime package, so we could optimize by only testing it once // between function calls. // -// A slice could be handled with a call to writebarrierptr plus two +// A slice could be handled with a call to gcWriteBarrier plus two // integer moves. // Traverse the IR adding write barriers. @@ -824,7 +824,7 @@ Gogo::assign_with_write_barrier(Function* function, Block* enclosing, case Type::TYPE_MAP: case Type::TYPE_CHANNEL: // These types are all represented by a single pointer. - call = Runtime::make_call(Runtime::WRITEBARRIERPTR, loc, 2, lhs, rhs); + call = Runtime::make_call(Runtime::GCWRITEBARRIER, loc, 2, lhs, rhs); break; case Type::TYPE_STRING: diff --git a/libgo/go/runtime/mgc_gccgo.go b/libgo/go/runtime/mgc_gccgo.go index cf7780c37f4..b396d35146c 100644 --- a/libgo/go/runtime/mgc_gccgo.go +++ b/libgo/go/runtime/mgc_gccgo.go @@ -11,6 +11,11 @@ import ( "unsafe" ) +// For gccgo, use go:linkname to rename compiler-called functions to +// themselves, so that the compiler will export them. +// +//go:linkname gcWriteBarrier runtime.gcWriteBarrier + // gcRoot is a single GC root: a variable plus a ptrmask. //go:notinheap type gcRoot struct { @@ -188,12 +193,7 @@ func checkPreempt() { //go:nowritebarrier func gcWriteBarrier(dst *uintptr, src uintptr) { buf := &getg().m.p.ptr().wbBuf - next := buf.next - np := next + 2*sys.PtrSize - buf.next = np - *(*uintptr)(unsafe.Pointer(next)) = src - *(*uintptr)(unsafe.Pointer(next + sys.PtrSize)) = *dst - if np >= buf.end { + if !buf.putFast(src, *dst) { wbBufFlush(dst, src) } *dst = src diff --git a/libgo/go/runtime/proc.go b/libgo/go/runtime/proc.go index 12d7071c3c0..4fc45dd4f64 100644 --- a/libgo/go/runtime/proc.go +++ b/libgo/go/runtime/proc.go @@ -1146,24 +1146,29 @@ func kickoff() { fv := gp.entry param := gp.param - gp.entry = nil // When running on the g0 stack we can wind up here without a p, - // for example from mcall(exitsyscall0) in exitsyscall. - // Setting gp.param = nil will call a write barrier, and if - // there is no p that write barrier will crash. When called from - // mcall the gp.param value will be a *g, which we don't need to - // shade since we know it will be kept alive elsewhere. In that - // case clear the field using uintptr so that the write barrier - // does nothing. - if gp.m.p == 0 { - if gp == gp.m.g0 && gp.param == unsafe.Pointer(gp.m.curg) { - *(*uintptr)(unsafe.Pointer(&gp.param)) = 0 - } else { - throw("no p in kickoff") - } + // for example from mcall(exitsyscall0) in exitsyscall, in + // which case we can not run a write barrier. + // It is also possible for us to get here from the systemstack + // call in wbBufFlush, at which point the write barrier buffer + // is full and we can not run a write barrier. + // Setting gp.entry = nil or gp.param = nil will try to run a + // write barrier, so if we are on the g0 stack due to mcall + // (systemstack calls mcall) then clear the field using uintptr. + // This is OK when gp.param is gp.m.curg, as curg will be kept + // alive elsewhere, and gp.entry always points into g, or + // to a statically allocated value, or (in the case of mcall) + // to the stack. + if gp == gp.m.g0 && gp.param == unsafe.Pointer(gp.m.curg) { + *(*uintptr)(unsafe.Pointer(&gp.entry)) = 0 + *(*uintptr)(unsafe.Pointer(&gp.param)) = 0 + } else if gp.m.p == 0 { + throw("no p in kickoff") + } else { + gp.entry = nil + gp.param = nil } - gp.param = nil fv(param) goexit1() -- 2.30.2