1
0
mirror of https://github.com/golang/go synced 2024-11-23 22:10:04 -07:00

[dev.garbage] runtime: reduce stack footprint of write barriers

This is going to hurt a bit but we'll make it better later.
Now the race detector can be run again.

I added the write barrier optimizations from
CL 183020043 to try to make it hurt a little less.

TBR=rlh
CC=golang-codereviews
https://golang.org/cl/185070043
This commit is contained in:
Russ Cox 2014-12-05 16:47:50 -05:00
parent b537635a7f
commit fa6c54953c
2 changed files with 72 additions and 52 deletions

View File

@ -163,7 +163,7 @@ esac
# and only on amd64, and only when cgo is enabled. # and only on amd64, and only when cgo is enabled.
# Delayed until here so we know whether to try external linking. # Delayed until here so we know whether to try external linking.
# DISABLED until we get garbage collection working. # DISABLED until we get garbage collection working.
case "$GOHOSTOS-$GOOS-$GOARCH-$CGO_ENABLED-XXX-DISABLED" in case "$GOHOSTOS-$GOOS-$GOARCH-$CGO_ENABLED" in
linux-linux-amd64-1 | freebsd-freebsd-amd64-1 | darwin-darwin-amd64-1) linux-linux-amd64-1 | freebsd-freebsd-amd64-1 | darwin-darwin-amd64-1)
echo echo
echo '# Testing race detector.' echo '# Testing race detector.'

View File

@ -102,19 +102,25 @@ const (
_PoisonStack = 0x6868686868686868 & (1<<(8*ptrSize) - 1) _PoisonStack = 0x6868686868686868 & (1<<(8*ptrSize) - 1)
) )
func needwb() bool {
return gcphase == _GCmark || gcphase == _GCmarktermination
}
// NOTE: Really dst *unsafe.Pointer, src unsafe.Pointer, // NOTE: Really dst *unsafe.Pointer, src unsafe.Pointer,
// but if we do that, Go inserts a write barrier on *dst = src. // but if we do that, Go inserts a write barrier on *dst = src.
//go:nosplit //go:nosplit
func writebarrierptr(dst *uintptr, src uintptr) { func writebarrierptr(dst *uintptr, src uintptr) {
*dst = src *dst = src
writebarrierptr_nostore(dst, src) if needwb() {
writebarrierptr_nostore(dst, src)
}
} }
// Like writebarrierptr, but the store has already been applied. // Like writebarrierptr, but the store has already been applied.
// Do not reapply. // Do not reapply.
//go:nosplit //go:nosplit
func writebarrierptr_nostore(dst *uintptr, src uintptr) { func writebarrierptr_nostore(dst *uintptr, src uintptr) {
if getg() == nil { // very low-level startup if getg() == nil || !needwb() { // very low-level startup
return return
} }
@ -162,29 +168,36 @@ func writebarrieriface(dst *[2]uintptr, src [2]uintptr) {
//go:nosplit //go:nosplit
func writebarrierfat(typ *_type, dst, src unsafe.Pointer) { func writebarrierfat(typ *_type, dst, src unsafe.Pointer) {
mask := loadPtrMask(typ) if !needwb() {
nptr := typ.size / ptrSize memmove(dst, src, typ.size)
for i := uintptr(0); i < nptr; i += 2 { return
bits := mask[i/2]
if (bits>>2)&_BitsMask == _BitsPointer {
writebarrierptr((*uintptr)(dst), *(*uintptr)(src))
} else {
*(*uintptr)(dst) = *(*uintptr)(src)
}
dst = add(dst, ptrSize)
src = add(src, ptrSize)
if i+1 == nptr {
break
}
bits >>= 4
if (bits>>2)&_BitsMask == _BitsPointer {
writebarrierptr((*uintptr)(dst), *(*uintptr)(src))
} else {
*(*uintptr)(dst) = *(*uintptr)(src)
}
dst = add(dst, ptrSize)
src = add(src, ptrSize)
} }
systemstack(func() {
mask := loadPtrMask(typ)
nptr := typ.size / ptrSize
for i := uintptr(0); i < nptr; i += 2 {
bits := mask[i/2]
if (bits>>2)&_BitsMask == _BitsPointer {
writebarrierptr((*uintptr)(dst), *(*uintptr)(src))
} else {
*(*uintptr)(dst) = *(*uintptr)(src)
}
dst = add(dst, ptrSize)
src = add(src, ptrSize)
if i+1 == nptr {
break
}
bits >>= 4
if (bits>>2)&_BitsMask == _BitsPointer {
writebarrierptr((*uintptr)(dst), *(*uintptr)(src))
} else {
*(*uintptr)(dst) = *(*uintptr)(src)
}
dst = add(dst, ptrSize)
src = add(src, ptrSize)
}
})
} }
//go:nosplit //go:nosplit
@ -199,33 +212,40 @@ func writebarriercopy(typ *_type, dst, src slice) int {
dstp := unsafe.Pointer(dst.array) dstp := unsafe.Pointer(dst.array)
srcp := unsafe.Pointer(src.array) srcp := unsafe.Pointer(src.array)
if uintptr(srcp) < uintptr(dstp) && uintptr(srcp)+uintptr(n)*typ.size > uintptr(dstp) { if !needwb() {
// Overlap with src before dst. memmove(dstp, srcp, uintptr(n)*typ.size)
// Copy backward, being careful not to move dstp/srcp return int(n)
// out of the array they point into.
dstp = add(dstp, uintptr(n-1)*typ.size)
srcp = add(srcp, uintptr(n-1)*typ.size)
i := uint(0)
for {
writebarrierfat(typ, dstp, srcp)
if i++; i >= n {
break
}
dstp = add(dstp, -typ.size)
srcp = add(srcp, -typ.size)
}
} else {
// Copy forward, being careful not to move dstp/srcp
// out of the array they point into.
i := uint(0)
for {
writebarrierfat(typ, dstp, srcp)
if i++; i >= n {
break
}
dstp = add(dstp, typ.size)
srcp = add(srcp, typ.size)
}
} }
systemstack(func() {
if uintptr(srcp) < uintptr(dstp) && uintptr(srcp)+uintptr(n)*typ.size > uintptr(dstp) {
// Overlap with src before dst.
// Copy backward, being careful not to move dstp/srcp
// out of the array they point into.
dstp = add(dstp, uintptr(n-1)*typ.size)
srcp = add(srcp, uintptr(n-1)*typ.size)
i := uint(0)
for {
writebarrierfat(typ, dstp, srcp)
if i++; i >= n {
break
}
dstp = add(dstp, -typ.size)
srcp = add(srcp, -typ.size)
}
} else {
// Copy forward, being careful not to move dstp/srcp
// out of the array they point into.
i := uint(0)
for {
writebarrierfat(typ, dstp, srcp)
if i++; i >= n {
break
}
dstp = add(dstp, typ.size)
srcp = add(srcp, typ.size)
}
}
})
return int(n) return int(n)
} }