Commit 54bb4dc3 authored by Russ Cox's avatar Russ Cox

runtime: use typed memmove (write barriers) for chan, map, interface content

Found with GODEBUG=wbshadow=2 mode.
Eventually that will run automatically, but right now
it still detects other missing write barriers.

Change-Id: Iea83d693480c2f3008b4e80d55821acff65970a6
Reviewed-on: https://go-review.googlesource.com/2277Reviewed-by: default avatarKeith Randall <khr@golang.org>
parent bcadab93
...@@ -146,7 +146,7 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin ...@@ -146,7 +146,7 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin
recvg := sg.g recvg := sg.g
if sg.elem != nil { if sg.elem != nil {
memmove(unsafe.Pointer(sg.elem), ep, uintptr(c.elemsize)) typedmemmove(c.elemtype, unsafe.Pointer(sg.elem), ep)
sg.elem = nil sg.elem = nil
} }
recvg.param = unsafe.Pointer(sg) recvg.param = unsafe.Pointer(sg)
...@@ -234,7 +234,7 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin ...@@ -234,7 +234,7 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin
raceacquire(chanbuf(c, c.sendx)) raceacquire(chanbuf(c, c.sendx))
racerelease(chanbuf(c, c.sendx)) racerelease(chanbuf(c, c.sendx))
} }
memmove(chanbuf(c, c.sendx), ep, uintptr(c.elemsize)) typedmemmove(c.elemtype, chanbuf(c, c.sendx), ep)
c.sendx++ c.sendx++
if c.sendx == c.dataqsiz { if c.sendx == c.dataqsiz {
c.sendx = 0 c.sendx = 0
...@@ -379,7 +379,7 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r ...@@ -379,7 +379,7 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r
unlock(&c.lock) unlock(&c.lock)
if ep != nil { if ep != nil {
memmove(ep, sg.elem, uintptr(c.elemsize)) typedmemmove(c.elemtype, ep, sg.elem)
} }
sg.elem = nil sg.elem = nil
gp := sg.g gp := sg.g
...@@ -484,7 +484,7 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r ...@@ -484,7 +484,7 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r
racerelease(chanbuf(c, c.recvx)) racerelease(chanbuf(c, c.recvx))
} }
if ep != nil { if ep != nil {
memmove(ep, chanbuf(c, c.recvx), uintptr(c.elemsize)) typedmemmove(c.elemtype, ep, chanbuf(c, c.recvx))
} }
memclr(chanbuf(c, c.recvx), uintptr(c.elemsize)) memclr(chanbuf(c, c.recvx), uintptr(c.elemsize))
......
...@@ -435,13 +435,13 @@ again: ...@@ -435,13 +435,13 @@ again:
continue continue
} }
// already have a mapping for key. Update it. // already have a mapping for key. Update it.
memmove(k2, key, uintptr(t.key.size)) typedmemmove(t.key, k2, key)
v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize)) v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
v2 := v v2 := v
if t.indirectvalue { if t.indirectvalue {
v2 = *((*unsafe.Pointer)(v2)) v2 = *((*unsafe.Pointer)(v2))
} }
memmove(v2, val, uintptr(t.elem.size)) typedmemmove(t.elem, v2, val)
return return
} }
ovf := b.overflow(t) ovf := b.overflow(t)
...@@ -486,8 +486,8 @@ again: ...@@ -486,8 +486,8 @@ again:
*(*unsafe.Pointer)(insertv) = vmem *(*unsafe.Pointer)(insertv) = vmem
insertv = vmem insertv = vmem
} }
memmove(insertk, key, uintptr(t.key.size)) typedmemmove(t.key, insertk, key)
memmove(insertv, val, uintptr(t.elem.size)) typedmemmove(t.elem, insertv, val)
*inserti = top *inserti = top
h.count++ h.count++
} }
...@@ -846,12 +846,12 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) { ...@@ -846,12 +846,12 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
if t.indirectkey { if t.indirectkey {
*(*unsafe.Pointer)(xk) = k2 // copy pointer *(*unsafe.Pointer)(xk) = k2 // copy pointer
} else { } else {
memmove(xk, k, uintptr(t.key.size)) // copy value typedmemmove(t.key, xk, k) // copy value
} }
if t.indirectvalue { if t.indirectvalue {
*(*unsafe.Pointer)(xv) = *(*unsafe.Pointer)(v) *(*unsafe.Pointer)(xv) = *(*unsafe.Pointer)(v)
} else { } else {
memmove(xv, v, uintptr(t.elem.size)) typedmemmove(t.elem, xv, v)
} }
xi++ xi++
xk = add(xk, uintptr(t.keysize)) xk = add(xk, uintptr(t.keysize))
...@@ -873,12 +873,12 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) { ...@@ -873,12 +873,12 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
if t.indirectkey { if t.indirectkey {
*(*unsafe.Pointer)(yk) = k2 *(*unsafe.Pointer)(yk) = k2
} else { } else {
memmove(yk, k, uintptr(t.key.size)) typedmemmove(t.key, yk, k)
} }
if t.indirectvalue { if t.indirectvalue {
*(*unsafe.Pointer)(yv) = *(*unsafe.Pointer)(v) *(*unsafe.Pointer)(yv) = *(*unsafe.Pointer)(v)
} else { } else {
memmove(yv, v, uintptr(t.elem.size)) typedmemmove(t.elem, yv, v)
} }
yi++ yi++
yk = add(yk, uintptr(t.keysize)) yk = add(yk, uintptr(t.keysize))
......
...@@ -132,16 +132,15 @@ func typ2Itab(t *_type, inter *interfacetype, cache **itab) *itab { ...@@ -132,16 +132,15 @@ func typ2Itab(t *_type, inter *interfacetype, cache **itab) *itab {
} }
func convT2E(t *_type, elem unsafe.Pointer) (e interface{}) { func convT2E(t *_type, elem unsafe.Pointer) (e interface{}) {
size := uintptr(t.size)
ep := (*eface)(unsafe.Pointer(&e)) ep := (*eface)(unsafe.Pointer(&e))
if isDirectIface(t) { if isDirectIface(t) {
ep._type = t ep._type = t
memmove(unsafe.Pointer(&ep.data), elem, size) typedmemmove(t, unsafe.Pointer(&ep.data), elem)
} else { } else {
x := newobject(t) x := newobject(t)
// TODO: We allocate a zeroed object only to overwrite it with // TODO: We allocate a zeroed object only to overwrite it with
// actual data. Figure out how to avoid zeroing. Also below in convT2I. // actual data. Figure out how to avoid zeroing. Also below in convT2I.
memmove(x, elem, size) typedmemmove(t, x, elem)
ep._type = t ep._type = t
ep.data = x ep.data = x
} }
...@@ -154,14 +153,13 @@ func convT2I(t *_type, inter *interfacetype, cache **itab, elem unsafe.Pointer) ...@@ -154,14 +153,13 @@ func convT2I(t *_type, inter *interfacetype, cache **itab, elem unsafe.Pointer)
tab = getitab(inter, t, false) tab = getitab(inter, t, false)
atomicstorep(unsafe.Pointer(cache), unsafe.Pointer(tab)) atomicstorep(unsafe.Pointer(cache), unsafe.Pointer(tab))
} }
size := uintptr(t.size)
pi := (*iface)(unsafe.Pointer(&i)) pi := (*iface)(unsafe.Pointer(&i))
if isDirectIface(t) { if isDirectIface(t) {
pi.tab = tab pi.tab = tab
memmove(unsafe.Pointer(&pi.data), elem, size) typedmemmove(t, unsafe.Pointer(&pi.data), elem)
} else { } else {
x := newobject(t) x := newobject(t)
memmove(x, elem, size) typedmemmove(t, x, elem)
pi.tab = tab pi.tab = tab
pi.data = x pi.data = x
} }
...@@ -180,11 +178,15 @@ func assertI2T(t *_type, i fInterface) (r struct{}) { ...@@ -180,11 +178,15 @@ func assertI2T(t *_type, i fInterface) (r struct{}) {
if tab._type != t { if tab._type != t {
panic(&TypeAssertionError{*tab.inter.typ._string, *tab._type._string, *t._string, ""}) panic(&TypeAssertionError{*tab.inter.typ._string, *tab._type._string, *t._string, ""})
} }
size := uintptr(t.size) // NOTE(rsc): If this changes to take a pointer argument
// instead of using &r, these calls need to change to be
// typedmemmove (the first can be just writebarrierptr).
// Until then, it is very important that no blocking operation
// happens between the memmove and the return.
if isDirectIface(t) { if isDirectIface(t) {
memmove(unsafe.Pointer(&r), unsafe.Pointer(&ip.data), size) memmove(unsafe.Pointer(&r), unsafe.Pointer(&ip.data), uintptr(t.size))
} else { } else {
memmove(unsafe.Pointer(&r), ip.data, size) memmove(unsafe.Pointer(&r), ip.data, uintptr(t.size))
} }
return return
} }
...@@ -192,19 +194,23 @@ func assertI2T(t *_type, i fInterface) (r struct{}) { ...@@ -192,19 +194,23 @@ func assertI2T(t *_type, i fInterface) (r struct{}) {
//go:nosplit //go:nosplit
func assertI2T2(t *_type, i fInterface) (r byte) { func assertI2T2(t *_type, i fInterface) (r byte) {
ip := (*iface)(unsafe.Pointer(&i)) ip := (*iface)(unsafe.Pointer(&i))
size := uintptr(t.size) ok := (*bool)(add(unsafe.Pointer(&r), uintptr(t.size)))
ok := (*bool)(add(unsafe.Pointer(&r), size))
tab := ip.tab tab := ip.tab
if tab == nil || tab._type != t { if tab == nil || tab._type != t {
*ok = false *ok = false
memclr(unsafe.Pointer(&r), size) memclr(unsafe.Pointer(&r), uintptr(t.size))
return return
} }
*ok = true *ok = true
// NOTE(rsc): If this changes to take a pointer argument
// instead of using &r, these calls need to change to be
// typedmemmove (the first can be just writebarrierptr).
// Until then, it is very important that no blocking operation
// happens between the memmove and the return.
if isDirectIface(t) { if isDirectIface(t) {
memmove(unsafe.Pointer(&r), unsafe.Pointer(&ip.data), size) memmove(unsafe.Pointer(&r), unsafe.Pointer(&ip.data), uintptr(t.size))
} else { } else {
memmove(unsafe.Pointer(&r), ip.data, size) memmove(unsafe.Pointer(&r), ip.data, uintptr(t.size))
} }
return return
} }
...@@ -224,11 +230,15 @@ func assertE2T(t *_type, e interface{}) (r struct{}) { ...@@ -224,11 +230,15 @@ func assertE2T(t *_type, e interface{}) (r struct{}) {
if ep._type != t { if ep._type != t {
panic(&TypeAssertionError{"", *ep._type._string, *t._string, ""}) panic(&TypeAssertionError{"", *ep._type._string, *t._string, ""})
} }
size := uintptr(t.size) // NOTE(rsc): If this changes to take a pointer argument
// instead of using &r, these calls need to change to be
// typedmemmove (the first can be just writebarrierptr).
// Until then, it is very important that no blocking operation
// happens between the memmove and the return.
if isDirectIface(t) { if isDirectIface(t) {
memmove(unsafe.Pointer(&r), unsafe.Pointer(&ep.data), size) memmove(unsafe.Pointer(&r), unsafe.Pointer(&ep.data), uintptr(t.size))
} else { } else {
memmove(unsafe.Pointer(&r), ep.data, size) memmove(unsafe.Pointer(&r), ep.data, uintptr(t.size))
} }
return return
} }
...@@ -244,6 +254,11 @@ func assertE2T2(t *_type, e interface{}) (r byte) { ...@@ -244,6 +254,11 @@ func assertE2T2(t *_type, e interface{}) (r byte) {
return return
} }
*ok = true *ok = true
// NOTE(rsc): If this changes to take a pointer argument
// instead of using &r, these calls need to change to be
// typedmemmove (the first can be just writebarrierptr).
// Until then, it is very important that no blocking operation
// happens between the memmove and the return.
if isDirectIface(t) { if isDirectIface(t) {
memmove(unsafe.Pointer(&r), unsafe.Pointer(&ep.data), size) memmove(unsafe.Pointer(&r), unsafe.Pointer(&ep.data), size)
} else { } else {
......
...@@ -304,8 +304,9 @@ func typedmemmove(typ *_type, dst, src unsafe.Pointer) { ...@@ -304,8 +304,9 @@ func typedmemmove(typ *_type, dst, src unsafe.Pointer) {
} else { } else {
*(*uintptr)(dst) = *(*uintptr)(src) *(*uintptr)(dst) = *(*uintptr)(src)
} }
dst = add(dst, ptrSize) // TODO(rsc): The noescape calls should be unnecessary.
src = add(src, ptrSize) dst = add(noescape(dst), ptrSize)
src = add(noescape(src), ptrSize)
if i+1 == nptr { if i+1 == nptr {
break break
} }
...@@ -315,8 +316,8 @@ func typedmemmove(typ *_type, dst, src unsafe.Pointer) { ...@@ -315,8 +316,8 @@ func typedmemmove(typ *_type, dst, src unsafe.Pointer) {
} else { } else {
*(*uintptr)(dst) = *(*uintptr)(src) *(*uintptr)(dst) = *(*uintptr)(src)
} }
dst = add(dst, ptrSize) dst = add(noescape(dst), ptrSize)
src = add(src, ptrSize) src = add(noescape(src), ptrSize)
} }
}) })
} }
......
...@@ -449,7 +449,7 @@ asyncrecv: ...@@ -449,7 +449,7 @@ asyncrecv:
*cas.receivedp = true *cas.receivedp = true
} }
if cas.elem != nil { if cas.elem != nil {
memmove(cas.elem, chanbuf(c, c.recvx), uintptr(c.elemsize)) typedmemmove(c.elemtype, cas.elem, chanbuf(c, c.recvx))
} }
memclr(chanbuf(c, c.recvx), uintptr(c.elemsize)) memclr(chanbuf(c, c.recvx), uintptr(c.elemsize))
c.recvx++ c.recvx++
...@@ -477,7 +477,7 @@ asyncsend: ...@@ -477,7 +477,7 @@ asyncsend:
racerelease(chanbuf(c, c.sendx)) racerelease(chanbuf(c, c.sendx))
raceReadObjectPC(c.elemtype, cas.elem, cas.pc, chansendpc) raceReadObjectPC(c.elemtype, cas.elem, cas.pc, chansendpc)
} }
memmove(chanbuf(c, c.sendx), cas.elem, uintptr(c.elemsize)) typedmemmove(c.elemtype, chanbuf(c, c.sendx), cas.elem)
c.sendx++ c.sendx++
if c.sendx == c.dataqsiz { if c.sendx == c.dataqsiz {
c.sendx = 0 c.sendx = 0
...@@ -512,7 +512,7 @@ syncrecv: ...@@ -512,7 +512,7 @@ syncrecv:
*cas.receivedp = true *cas.receivedp = true
} }
if cas.elem != nil { if cas.elem != nil {
memmove(cas.elem, sg.elem, uintptr(c.elemsize)) typedmemmove(c.elemtype, cas.elem, sg.elem)
} }
sg.elem = nil sg.elem = nil
gp = sg.g gp = sg.g
...@@ -548,7 +548,7 @@ syncsend: ...@@ -548,7 +548,7 @@ syncsend:
print("syncsend: sel=", sel, " c=", c, "\n") print("syncsend: sel=", sel, " c=", c, "\n")
} }
if sg.elem != nil { if sg.elem != nil {
memmove(sg.elem, cas.elem, uintptr(c.elemsize)) typedmemmove(c.elemtype, sg.elem, cas.elem)
} }
sg.elem = nil sg.elem = nil
gp = sg.g gp = sg.g
......
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