Commit d941b075 authored by Austin Clements's avatar Austin Clements

runtime: eliminate write barriers from persistentalloc

We're about to start tracking nowritebarrierrec through systemstack
calls, which will reveal write barriers in persistentalloc prohibited
by various callers.

The pointers manipulated by persistentalloc are always to off-heap
memory, so this removes these write barriers statically by introducing
a new go:notinheap type to represent generic off-heap memory.

Updates #22384.
For #22460.

Change-Id: Id449d9ebf145b14d55476a833e7f076b0d261d57
Reviewed-on: https://go-review.googlesource.com/72771
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarRick Hudson <rlh@golang.org>
parent 070cc8eb
...@@ -928,7 +928,7 @@ func nextSampleNoFP() int32 { ...@@ -928,7 +928,7 @@ func nextSampleNoFP() int32 {
} }
type persistentAlloc struct { type persistentAlloc struct {
base unsafe.Pointer base *notInHeap
off uintptr off uintptr
} }
...@@ -945,17 +945,17 @@ var globalAlloc struct { ...@@ -945,17 +945,17 @@ var globalAlloc struct {
// //
// Consider marking persistentalloc'd types go:notinheap. // Consider marking persistentalloc'd types go:notinheap.
func persistentalloc(size, align uintptr, sysStat *uint64) unsafe.Pointer { func persistentalloc(size, align uintptr, sysStat *uint64) unsafe.Pointer {
var p unsafe.Pointer var p *notInHeap
systemstack(func() { systemstack(func() {
p = persistentalloc1(size, align, sysStat) p = persistentalloc1(size, align, sysStat)
}) })
return p return unsafe.Pointer(p)
} }
// Must run on system stack because stack growth can (re)invoke it. // Must run on system stack because stack growth can (re)invoke it.
// See issue 9174. // See issue 9174.
//go:systemstack //go:systemstack
func persistentalloc1(size, align uintptr, sysStat *uint64) unsafe.Pointer { func persistentalloc1(size, align uintptr, sysStat *uint64) *notInHeap {
const ( const (
chunk = 256 << 10 chunk = 256 << 10
maxBlock = 64 << 10 // VM reservation granularity is 64K on windows maxBlock = 64 << 10 // VM reservation granularity is 64K on windows
...@@ -976,7 +976,7 @@ func persistentalloc1(size, align uintptr, sysStat *uint64) unsafe.Pointer { ...@@ -976,7 +976,7 @@ func persistentalloc1(size, align uintptr, sysStat *uint64) unsafe.Pointer {
} }
if size >= maxBlock { if size >= maxBlock {
return sysAlloc(size, sysStat) return (*notInHeap)(sysAlloc(size, sysStat))
} }
mp := acquirem() mp := acquirem()
...@@ -989,7 +989,7 @@ func persistentalloc1(size, align uintptr, sysStat *uint64) unsafe.Pointer { ...@@ -989,7 +989,7 @@ func persistentalloc1(size, align uintptr, sysStat *uint64) unsafe.Pointer {
} }
persistent.off = round(persistent.off, align) persistent.off = round(persistent.off, align)
if persistent.off+size > chunk || persistent.base == nil { if persistent.off+size > chunk || persistent.base == nil {
persistent.base = sysAlloc(chunk, &memstats.other_sys) persistent.base = (*notInHeap)(sysAlloc(chunk, &memstats.other_sys))
if persistent.base == nil { if persistent.base == nil {
if persistent == &globalAlloc.persistentAlloc { if persistent == &globalAlloc.persistentAlloc {
unlock(&globalAlloc.mutex) unlock(&globalAlloc.mutex)
...@@ -998,7 +998,7 @@ func persistentalloc1(size, align uintptr, sysStat *uint64) unsafe.Pointer { ...@@ -998,7 +998,7 @@ func persistentalloc1(size, align uintptr, sysStat *uint64) unsafe.Pointer {
} }
persistent.off = 0 persistent.off = 0
} }
p := add(persistent.base, persistent.off) p := persistent.base.add(persistent.off)
persistent.off += size persistent.off += size
releasem(mp) releasem(mp)
if persistent == &globalAlloc.persistentAlloc { if persistent == &globalAlloc.persistentAlloc {
...@@ -1011,3 +1011,19 @@ func persistentalloc1(size, align uintptr, sysStat *uint64) unsafe.Pointer { ...@@ -1011,3 +1011,19 @@ func persistentalloc1(size, align uintptr, sysStat *uint64) unsafe.Pointer {
} }
return p return p
} }
// notInHeap is off-heap memory allocated by a lower-level allocator
// like sysAlloc or persistentAlloc.
//
// In general, it's better to use real types marked as go:notinheap,
// but this serves as a generic type for situations where that isn't
// possible (like in the allocators).
//
// TODO: Use this as the return type of sysAlloc, persistentAlloc, etc?
//
//go:notinheap
type notInHeap struct{}
func (p *notInHeap) add(bytes uintptr) *notInHeap {
return (*notInHeap)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) + bytes))
}
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