| // 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 ( |
| "runtime/internal/sys" |
| "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(sys.PtrSize*uintptr(nroots), sys.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, sys.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 |
| } |