// We call writebarrierfat only for values > 4 pointers long. See walk.go.
// TODO(mdempsky): writebarrierfat doesn't exist anymore, but removing that
// logic causes net/http's tests to become flaky; see CL 21242.
- if needwritebarrier(n.Left, n.Right) && n.Left.Type.Width > int64(4*Widthptr) && !isaddrokay(n.Right) {
+ if needwritebarrier(n.Left, n.Right) && n.Left.Type.Width > int64(4*Widthptr) && n.Right != nil && !isaddrokay(n.Right) {
m := n.Left
n.Left = ordertemp(m.Type, order, false)
a := nod(OAS, m, n.Left)
break
}
- if n.Right == nil || iszero(n.Right) && !instrumenting {
+ if n.Right == nil {
+ // TODO(austin): Check all "implicit zeroing"
break
}
return false
}
- // No write barrier for implicit zeroing.
- if r == nil {
- return false
- }
-
// No write barrier if this is a pointer to a go:notinheap
// type, since the write barrier's inheap(ptr) check will fail.
if l.Type.IsPtr() && l.Type.Elem().NotInHeap {
return false
}
+ // Implicit zeroing is still zeroing, so it needs write
+ // barriers. In practice, these are all to stack variables
+ // (even if isstack isn't smart enough to figure that out), so
+ // they'll be eliminated by the backend.
+ if r == nil {
+ return true
+ }
+
// Ignore no-op conversions when making decision.
// Ensures that xp = unsafe.Pointer(&x) is treated
// the same as xp = &x.
r = r.Left
}
- // No write barrier for zeroing or initialization to constant.
- if iszero(r) || r.Op == OLITERAL {
- return false
- }
-
- // No write barrier for storing static (read-only) data.
- if r.Op == ONAME && strings.HasPrefix(r.Sym.Name, "statictmp_") {
- return false
- }
+ // TODO: We can eliminate write barriers if we know *both* the
+ // current and new content of the slot must already be shaded.
+ // We know a pointer is shaded if it's nil, or points to
+ // static data, a global (variable or function), or the stack.
+ // The nil optimization could be particularly useful for
+ // writes to just-allocated objects. Unfortunately, knowing
+ // the "current" value of the slot requires flow analysis.
// No write barrier for storing address of stack values,
// which are guaranteed only to be written to the stack.
return false
}
- // No write barrier for storing address of global, which
- // is live no matter what.
- if r.Op == OADDR && r.Left.isGlobal() {
- return false
- }
-
- // No write barrier for storing global function, which is live
- // no matter what.
- if r.Op == ONAME && r.Class == PFUNC {
- return false
- }
-
// Otherwise, be conservative and use write barrier.
return true
}
}
func f17(x *T17) {
- // See golang.org/issue/13901
- x.f = f17 // no barrier
+ // Originally from golang.org/issue/13901, but the hybrid
+ // barrier requires both to have barriers.
+ x.f = f17 // ERROR "write barrier"
x.f = func(y *T17) { *y = *x } // ERROR "write barrier"
}
// Global -> heap pointer updates must have write barriers.
x21 = x // ERROR "write barrier"
y21.x = x // ERROR "write barrier"
- x21 = &z21 // no barrier
- y21.x = &z21 // no barrier
+ x21 = &z21 // ERROR "write barrier"
+ y21.x = &z21 // ERROR "write barrier"
y21 = struct{ x *int }{x} // ERROR "write barrier"
}