mirror of
https://github.com/golang/go
synced 2024-09-04 23:44:16 +00:00
![Keith Randall](/assets/img/avatar_default.png)
We're allowed to remove a write barrier when both the old value in memory and the new value we're writing are not heap pointers. Improve both those checks a little bit. A pointer is known to not be a heap pointer if it is read from read-only memory. This sometimes happens for loads of pointers from string constants in read-only memory. Do a better job of tracking which parts of memory are known to be zero. Before we just kept track of a range of offsets in the most recently allocated object. For code that initializes the new object's fields in a nonstandard order, that tracking is imprecise. Instead, keep a bit map of the first 64 words of that object, so we can track precisely what we know to be zeroed. The new scheme is only precise up to the first 512 bytes of the object. After that, we'll use write barriers unnecessarily. Hopefully most initializers of large objects will use typedmemmove, which does only one write barrier check for the whole initialization. Fixes #34723 Update #21561 Change-Id: Idf6e1b7d525042fb67961302d4fc6f941393cac8 Reviewed-on: https://go-review.googlesource.com/c/go/+/199558 Run-TryBot: Keith Randall <khr@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Cherry Zhang <cherryyz@google.com>
71 lines
1 KiB
Go
71 lines
1 KiB
Go
// errorcheck -0 -d=wb
|
|
|
|
// Copyright 2019 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
// Make sure we don't introduce write barriers where we
|
|
// don't need them. These cases are writing pointers to
|
|
// globals to zeroed memory.
|
|
|
|
package main
|
|
|
|
func f1() []string {
|
|
return []string{"a"}
|
|
}
|
|
|
|
func f2() []string {
|
|
return []string{"a", "b"}
|
|
}
|
|
|
|
type T struct {
|
|
a [6]*int
|
|
}
|
|
|
|
func f3() *T {
|
|
t := new(T)
|
|
t.a[0] = &g
|
|
t.a[1] = &g
|
|
t.a[2] = &g
|
|
t.a[3] = &g
|
|
t.a[4] = &g
|
|
t.a[5] = &g
|
|
return t
|
|
}
|
|
|
|
func f4() *T {
|
|
t := new(T)
|
|
t.a[5] = &g
|
|
t.a[4] = &g
|
|
t.a[3] = &g
|
|
t.a[2] = &g
|
|
t.a[1] = &g
|
|
t.a[0] = &g
|
|
return t
|
|
}
|
|
|
|
func f5() *T {
|
|
t := new(T)
|
|
t.a[4] = &g
|
|
t.a[2] = &g
|
|
t.a[0] = &g
|
|
t.a[3] = &g
|
|
t.a[1] = &g
|
|
t.a[5] = &g
|
|
return t
|
|
}
|
|
|
|
type U struct {
|
|
a [65]*int
|
|
}
|
|
|
|
func f6() *U {
|
|
u := new(U)
|
|
u.a[63] = &g
|
|
// This offset is too large: we only track the first 64 pointers for zeroness.
|
|
u.a[64] = &g // ERROR "write barrier"
|
|
return u
|
|
}
|
|
|
|
var g int
|