mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile: fix write barrier coalescing
We can't coalesce a non-WB store with a subsequent Move, as the result of the store might be the source of the move. There's a simple codegen test. Not sure how we might do a real test, as all the repro's I've come up with are very expensive and unreliable. Fixes #71228 Change-Id: If18bf181a266b9b90964e2591cd2e61a7168371c Reviewed-on: https://go-review.googlesource.com/c/go/+/642197 Reviewed-by: Keith Randall <khr@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: David Chase <drchase@google.com>
This commit is contained in:
parent
19e923182e
commit
44a6f817ea
2 changed files with 40 additions and 0 deletions
|
|
@ -252,6 +252,7 @@ func writebarrier(f *Func) {
|
||||||
var start, end int
|
var start, end int
|
||||||
var nonPtrStores int
|
var nonPtrStores int
|
||||||
values := b.Values
|
values := b.Values
|
||||||
|
hasMove := false
|
||||||
FindSeq:
|
FindSeq:
|
||||||
for i := len(values) - 1; i >= 0; i-- {
|
for i := len(values) - 1; i >= 0; i-- {
|
||||||
w := values[i]
|
w := values[i]
|
||||||
|
|
@ -263,6 +264,9 @@ func writebarrier(f *Func) {
|
||||||
end = i + 1
|
end = i + 1
|
||||||
}
|
}
|
||||||
nonPtrStores = 0
|
nonPtrStores = 0
|
||||||
|
if w.Op == OpMoveWB {
|
||||||
|
hasMove = true
|
||||||
|
}
|
||||||
case OpVarDef, OpVarLive:
|
case OpVarDef, OpVarLive:
|
||||||
continue
|
continue
|
||||||
case OpStore:
|
case OpStore:
|
||||||
|
|
@ -273,6 +277,17 @@ func writebarrier(f *Func) {
|
||||||
if nonPtrStores > 2 {
|
if nonPtrStores > 2 {
|
||||||
break FindSeq
|
break FindSeq
|
||||||
}
|
}
|
||||||
|
if hasMove {
|
||||||
|
// We need to ensure that this store happens
|
||||||
|
// before we issue a wbMove, as the wbMove might
|
||||||
|
// use the result of this store as its source.
|
||||||
|
// Even though this store is not write-barrier
|
||||||
|
// eligible, it might nevertheless be the store
|
||||||
|
// of a pointer to the stack, which is then the
|
||||||
|
// source of the move.
|
||||||
|
// See issue 71228.
|
||||||
|
break FindSeq
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
if last == nil {
|
if last == nil {
|
||||||
continue
|
continue
|
||||||
|
|
|
||||||
|
|
@ -63,3 +63,28 @@ func trickyWriteNil(p *int, q **int) {
|
||||||
*q = p
|
*q = p
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type S struct {
|
||||||
|
a, b string
|
||||||
|
c *int
|
||||||
|
}
|
||||||
|
|
||||||
|
var g1, g2 *int
|
||||||
|
|
||||||
|
func issue71228(dst *S, ptr *int) {
|
||||||
|
// Make sure that the non-write-barrier write.
|
||||||
|
// "sp.c = ptr" happens before the large write
|
||||||
|
// barrier "*dst = *sp". We approximate testing
|
||||||
|
// that by ensuring that two global variable write
|
||||||
|
// barriers aren't combined.
|
||||||
|
_ = *dst
|
||||||
|
var s S
|
||||||
|
sp := &s
|
||||||
|
//amd64:`.*runtime[.]gcWriteBarrier1`
|
||||||
|
g1 = nil
|
||||||
|
sp.c = ptr // outside of any write barrier
|
||||||
|
//amd64:`.*runtime[.]gcWriteBarrier1`
|
||||||
|
g2 = nil
|
||||||
|
//amd64:`.*runtime[.]wbMove`
|
||||||
|
*dst = *sp
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue