Commit cec07c47 by Ian Lance Taylor

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
parent 38fab736
82d7205ba9e5c1fe38fd24f89a45caf2e974975b 218c9159635e06e39ae43d0efe1ac1e694fead2e
The first line of this file holds the git revision number of the last The first line of this file holds the git revision number of the last
merge done from the gofrontend repository. merge done from the gofrontend repository.
...@@ -302,7 +302,7 @@ DEF_GO_RUNTIME(IFACEEFACEEQ, "runtime.ifaceefaceeq", P2(IFACE, EFACE), ...@@ -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. // 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()) P2(POINTER, POINTER), R0())
// Set *dst = *src for an arbitrary type. // Set *dst = *src for an arbitrary type.
......
...@@ -380,7 +380,7 @@ Gogo::propagate_writebarrierrec() ...@@ -380,7 +380,7 @@ Gogo::propagate_writebarrierrec()
// This is compatible with the definition in the runtime package. // This is compatible with the definition in the runtime package.
// //
// For types that are pointer shared (pointers, maps, chans, funcs), // 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 // As far as the GC is concerned, all pointers are the same, so it
// doesn't need the type descriptor. // doesn't need the type descriptor.
// //
...@@ -391,7 +391,7 @@ Gogo::propagate_writebarrierrec() ...@@ -391,7 +391,7 @@ Gogo::propagate_writebarrierrec()
// runtime package, so we could optimize by only testing it once // runtime package, so we could optimize by only testing it once
// between function calls. // 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. // integer moves.
// Traverse the IR adding write barriers. // Traverse the IR adding write barriers.
...@@ -824,7 +824,7 @@ Gogo::assign_with_write_barrier(Function* function, Block* enclosing, ...@@ -824,7 +824,7 @@ Gogo::assign_with_write_barrier(Function* function, Block* enclosing,
case Type::TYPE_MAP: case Type::TYPE_MAP:
case Type::TYPE_CHANNEL: case Type::TYPE_CHANNEL:
// These types are all represented by a single pointer. // 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; break;
case Type::TYPE_STRING: case Type::TYPE_STRING:
......
...@@ -11,6 +11,11 @@ import ( ...@@ -11,6 +11,11 @@ import (
"unsafe" "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. // gcRoot is a single GC root: a variable plus a ptrmask.
//go:notinheap //go:notinheap
type gcRoot struct { type gcRoot struct {
...@@ -188,12 +193,7 @@ func checkPreempt() { ...@@ -188,12 +193,7 @@ func checkPreempt() {
//go:nowritebarrier //go:nowritebarrier
func gcWriteBarrier(dst *uintptr, src uintptr) { func gcWriteBarrier(dst *uintptr, src uintptr) {
buf := &getg().m.p.ptr().wbBuf buf := &getg().m.p.ptr().wbBuf
next := buf.next if !buf.putFast(src, *dst) {
np := next + 2*sys.PtrSize
buf.next = np
*(*uintptr)(unsafe.Pointer(next)) = src
*(*uintptr)(unsafe.Pointer(next + sys.PtrSize)) = *dst
if np >= buf.end {
wbBufFlush(dst, src) wbBufFlush(dst, src)
} }
*dst = src *dst = src
......
...@@ -1146,24 +1146,29 @@ func kickoff() { ...@@ -1146,24 +1146,29 @@ func kickoff() {
fv := gp.entry fv := gp.entry
param := gp.param param := gp.param
gp.entry = nil
// When running on the g0 stack we can wind up here without a p, // When running on the g0 stack we can wind up here without a p,
// for example from mcall(exitsyscall0) in exitsyscall. // for example from mcall(exitsyscall0) in exitsyscall, in
// Setting gp.param = nil will call a write barrier, and if // which case we can not run a write barrier.
// there is no p that write barrier will crash. When called from // It is also possible for us to get here from the systemstack
// mcall the gp.param value will be a *g, which we don't need to // call in wbBufFlush, at which point the write barrier buffer
// shade since we know it will be kept alive elsewhere. In that // is full and we can not run a write barrier.
// case clear the field using uintptr so that the write barrier // Setting gp.entry = nil or gp.param = nil will try to run a
// does nothing. // write barrier, so if we are on the g0 stack due to mcall
if gp.m.p == 0 { // (systemstack calls mcall) then clear the field using uintptr.
if gp == gp.m.g0 && gp.param == unsafe.Pointer(gp.m.curg) { // This is OK when gp.param is gp.m.curg, as curg will be kept
*(*uintptr)(unsafe.Pointer(&gp.param)) = 0 // alive elsewhere, and gp.entry always points into g, or
} else { // to a statically allocated value, or (in the case of mcall)
throw("no p in kickoff") // 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) fv(param)
goexit1() goexit1()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment