171 lines
4.9 KiB
Go
171 lines
4.9 KiB
Go
// Copyright 2016 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.
|
|
|
|
// gccgo-specific support for GC.
|
|
|
|
package runtime
|
|
|
|
import (
|
|
"internal/goarch"
|
|
"unsafe"
|
|
)
|
|
|
|
// For gccgo, use go:linkname to export compiler-called functions.
|
|
//
|
|
//go:linkname gcWriteBarrier
|
|
|
|
// gcRoot is a single GC root: a variable plus a ptrmask.
|
|
//go:notinheap
|
|
type gcRoot struct {
|
|
decl unsafe.Pointer // Pointer to variable.
|
|
size uintptr // Size of variable.
|
|
ptrdata uintptr // Length of gcdata.
|
|
gcdata *uint8 // Pointer mask.
|
|
}
|
|
|
|
// gcRootList is the set of GC roots for a package.
|
|
// The next field is used to put this all into a linked list.
|
|
// count gives the real length of the array.
|
|
type gcRootList struct {
|
|
next *gcRootList
|
|
count int
|
|
roots [1 << 26]gcRoot
|
|
}
|
|
|
|
// roots is the list of GC roots for the program.
|
|
// The compiler keeps this variable itself off the list.
|
|
var gcRoots *gcRootList
|
|
|
|
// Slice containing pointers to all reachable gcRoot's sorted by
|
|
// starting address (generated at init time from 'gcRoots').
|
|
// The compiler also keeps this variable itself off the list.
|
|
// The storage backing this slice is allocated via persistentalloc(), the
|
|
// idea being that we don't want to treat the slice itself as a global
|
|
// variable, since it points to things that don't need to be scanned
|
|
// themselves.
|
|
var gcRootsIndex []*gcRoot
|
|
|
|
// rootradixsort performs an in-place radix sort of the 'arr' rootptr slice.
|
|
// Note: not a stable sort, however we expect it to be called only on slices
|
|
// with no duplicate entries, so this should not matter.
|
|
func rootradixsort(arr []*gcRoot, lo, hi int, bit uint) {
|
|
// Partition the array into two bins based on the values at the
|
|
// specified bit position: 0's bin (grown from the left) and and
|
|
// 1's bin (grown from the right). We keep two boundary markers,
|
|
// the 0's boundary "zbb" (which grows to the right) and the 1's
|
|
// boundary "obb" (which grows to the left). At each step we
|
|
// examine the bit for the right-of-ZBB element: if it is zero, we
|
|
// leave it in place and move the ZBB to the right. If the bit is
|
|
// not zero, then we swap the ZBB and OBB elements and move the
|
|
// OBB to the left. When this is done, the two partitions are then
|
|
// sorted using the next lower bit.
|
|
|
|
// 0's bin boundary, initially set to before the first element
|
|
zbb := lo - 1
|
|
// 1's bin boundary, set to just beyond the last element
|
|
obb := hi + 1
|
|
// mask to pick up bit of interest
|
|
bmask := uintptr(1) << bit
|
|
|
|
for obb-zbb > 1 {
|
|
zbbval := uintptr(arr[zbb+1].decl) & bmask
|
|
if zbbval == 0 {
|
|
// Move zbb one to the right
|
|
zbb++
|
|
} else {
|
|
// Move obb one to the left and swap
|
|
arr[obb-1], arr[zbb+1] = arr[zbb+1], arr[obb-1]
|
|
obb--
|
|
}
|
|
}
|
|
|
|
if bit != 0 {
|
|
// NB: in most cases there is just a single partition to visit
|
|
// so if we wanted to reduce stack space we could check for this
|
|
// and insert a goto back up to the top.
|
|
if zbb-lo > 0 {
|
|
rootradixsort(arr, lo, zbb, bit-1)
|
|
}
|
|
if hi-obb > 0 {
|
|
rootradixsort(arr, obb, hi, bit-1)
|
|
}
|
|
}
|
|
}
|
|
|
|
//go:nowritebarrier
|
|
func createGcRootsIndex() {
|
|
// Count roots
|
|
nroots := 0
|
|
gcr := gcRoots
|
|
for gcr != nil {
|
|
nroots += gcr.count
|
|
gcr = gcr.next
|
|
}
|
|
|
|
// Construct the gcRootsIndex slice. Use non-heap storage for the array
|
|
// backing the slice.
|
|
sp := (*notInHeapSlice)(unsafe.Pointer(&gcRootsIndex))
|
|
sp.array = (*notInHeap)(persistentalloc1(goarch.PtrSize*uintptr(nroots), goarch.PtrSize, &memstats.other_sys))
|
|
if sp.array == nil {
|
|
throw("runtime: cannot allocate memory")
|
|
}
|
|
sp.len = nroots
|
|
sp.cap = nroots
|
|
|
|
// Populate the roots index slice
|
|
gcr = gcRoots
|
|
k := 0
|
|
for gcr != nil {
|
|
for i := 0; i < gcr.count; i++ {
|
|
gcRootsIndex[k] = &gcr.roots[i]
|
|
k++
|
|
}
|
|
gcr = gcr.next
|
|
}
|
|
|
|
// Sort it by starting address.
|
|
rootradixsort(gcRootsIndex, 0, nroots-1, goarch.PtrSize*8-1)
|
|
}
|
|
|
|
// registerGCRoots is called by compiler-generated code.
|
|
//go:linkname registerGCRoots
|
|
|
|
// registerGCRoots is called by init functions to register the GC
|
|
// roots for a package. The init functions are run sequentially at
|
|
// the start of the program, so no locking is needed.
|
|
func registerGCRoots(r *gcRootList) {
|
|
r.next = gcRoots
|
|
gcRoots = r
|
|
}
|
|
|
|
// checkPreempt is called when the preempt field in the running G is true.
|
|
// It preempts the goroutine if it is safe to do so.
|
|
// If preemptscan is true, this scans the stack for the garbage collector
|
|
// and carries on.
|
|
func checkPreempt() {
|
|
gp := getg()
|
|
if !gp.preempt || gp != gp.m.curg || !canPreemptM(gp.m) {
|
|
return
|
|
}
|
|
|
|
if gp.preemptStop {
|
|
mcall(preemptPark)
|
|
}
|
|
|
|
// Act like goroutine called runtime.Gosched.
|
|
mcall(gopreempt_m)
|
|
}
|
|
|
|
// gcWriteBarrier implements a write barrier. This is implemented in
|
|
// assembly in the gc library, but there is no special advantage to
|
|
// doing so with gccgo.
|
|
//go:nosplit
|
|
//go:nowritebarrier
|
|
func gcWriteBarrier(dst *uintptr, src uintptr) {
|
|
buf := &getg().m.p.ptr().wbBuf
|
|
if !buf.putFast(src, *dst) {
|
|
wbBufFlush(dst, src)
|
|
}
|
|
*dst = src
|
|
}
|