mirror of https://github.com/golang/go.git
cmd/compile: simplify uninterruptable range check for write barriers
Make the load detection a bit clearer and more precise. In particular, for architectures which have to materialize the address using a separate instruction, we were using the address materialization instruction, not the load itself. Also apply the marking a bit less. We don't need to mark the load itself, only the instructions after the load. And we don't need to mark the WBend itself, only the instructions before it. Change-Id: Ie367a8023b003d5317b752d873bb385f931bb30e Reviewed-on: https://go-review.googlesource.com/c/go/+/499395 Reviewed-by: Cherry Mui <cherryyz@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Run-TryBot: Keith Randall <khr@golang.org> Reviewed-by: Keith Randall <khr@google.com>
This commit is contained in:
parent
d0964e172b
commit
c94f39a80e
|
|
@ -489,8 +489,6 @@ func (lv *liveness) markUnsafePoints() {
|
||||||
// m2 = store operation ... m1
|
// m2 = store operation ... m1
|
||||||
// m3 = store operation ... m2
|
// m3 = store operation ... m2
|
||||||
// m4 = WBend m3
|
// m4 = WBend m3
|
||||||
//
|
|
||||||
// (For now m2 and m3 won't be present.)
|
|
||||||
|
|
||||||
// Find first memory op in the block, which should be a Phi.
|
// Find first memory op in the block, which should be a Phi.
|
||||||
m := v
|
m := v
|
||||||
|
|
@ -535,39 +533,36 @@ func (lv *liveness) markUnsafePoints() {
|
||||||
var load *ssa.Value
|
var load *ssa.Value
|
||||||
v := decisionBlock.Controls[0]
|
v := decisionBlock.Controls[0]
|
||||||
for {
|
for {
|
||||||
|
if v.MemoryArg() != nil {
|
||||||
|
// Single instruction to load (and maybe compare) the write barrier flag.
|
||||||
if sym, ok := v.Aux.(*obj.LSym); ok && sym == ir.Syms.WriteBarrier {
|
if sym, ok := v.Aux.(*obj.LSym); ok && sym == ir.Syms.WriteBarrier {
|
||||||
load = v
|
load = v
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
switch v.Op {
|
// Some architectures have to materialize the address separate from
|
||||||
case ssa.Op386TESTL:
|
// the load.
|
||||||
// 386 lowers Neq32 to (TESTL cond cond),
|
if sym, ok := v.Args[0].Aux.(*obj.LSym); ok && sym == ir.Syms.WriteBarrier {
|
||||||
if v.Args[0] == v.Args[1] {
|
load = v
|
||||||
v = v.Args[0]
|
break
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
case ssa.Op386MOVLload, ssa.OpARM64MOVWUload, ssa.OpMIPS64MOVWUload, ssa.OpPPC64MOVWZload, ssa.OpWasmI64Load32U:
|
v.Fatalf("load of write barrier flag not from correct global: %s", v.LongString())
|
||||||
// Args[0] is the address of the write
|
|
||||||
// barrier control. Ignore Args[1],
|
|
||||||
// which is the mem operand.
|
|
||||||
// TODO: Just ignore mem operands?
|
|
||||||
v = v.Args[0]
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
// Common case: just flow backwards.
|
// Common case: just flow backwards.
|
||||||
if len(v.Args) != 1 {
|
if len(v.Args) == 1 || len(v.Args) == 2 && v.Args[0] == v.Args[1] {
|
||||||
v.Fatalf("write barrier control value has more than one argument: %s", v.LongString())
|
// Note: 386 lowers Neq32 to (TESTL cond cond),
|
||||||
}
|
|
||||||
v = v.Args[0]
|
v = v.Args[0]
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
v.Fatalf("write barrier control value has more than one argument: %s", v.LongString())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark everything after the load unsafe.
|
// Mark everything after the load unsafe.
|
||||||
found := false
|
found := false
|
||||||
for _, v := range decisionBlock.Values {
|
for _, v := range decisionBlock.Values {
|
||||||
found = found || v == load
|
|
||||||
if found {
|
if found {
|
||||||
lv.unsafePoints.Set(int32(v.ID))
|
lv.unsafePoints.Set(int32(v.ID))
|
||||||
}
|
}
|
||||||
|
found = found || v == load
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark the write barrier on/off blocks as unsafe.
|
// Mark the write barrier on/off blocks as unsafe.
|
||||||
|
|
@ -583,10 +578,10 @@ func (lv *liveness) markUnsafePoints() {
|
||||||
|
|
||||||
// Mark from the join point up to the WBend as unsafe.
|
// Mark from the join point up to the WBend as unsafe.
|
||||||
for _, v := range b.Values {
|
for _, v := range b.Values {
|
||||||
lv.unsafePoints.Set(int32(v.ID))
|
|
||||||
if v.Op == ssa.OpWBend {
|
if v.Op == ssa.OpWBend {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
lv.unsafePoints.Set(int32(v.ID))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue