aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/go/gofrontend/MERGE2
-rw-r--r--gcc/go/gofrontend/gogo.cc3
-rw-r--r--libgo/go/runtime/cgocall.go24
-rw-r--r--libgo/go/runtime/mbitmap.go26
-rw-r--r--libgo/go/runtime/mgc_gccgo.go92
-rw-r--r--libgo/go/runtime/proc.go1
6 files changed, 125 insertions, 23 deletions
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE
index 1afbcb4..ca47d87 100644
--- a/gcc/go/gofrontend/MERGE
+++ b/gcc/go/gofrontend/MERGE
@@ -1,4 +1,4 @@
-acf852f838e6b99f907d84648be853fa2c374393
+70bd9801911f8ed27df410d36a928166c37a68fd
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.
diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc
index c16b40e..dd6733f 100644
--- a/gcc/go/gofrontend/gogo.cc
+++ b/gcc/go/gofrontend/gogo.cc
@@ -1535,7 +1535,8 @@ Gogo::write_globals()
// Avoid putting runtime.gcRoots itself on the list.
if (this->compiling_runtime()
&& this->package_name() == "runtime"
- && Gogo::unpack_hidden_name(no->name()) == "gcRoots")
+ && (Gogo::unpack_hidden_name(no->name()) == "gcRoots"
+ || Gogo::unpack_hidden_name(no->name()) == "gcRootsIndex"))
;
else
var_gc.push_back(no);
diff --git a/libgo/go/runtime/cgocall.go b/libgo/go/runtime/cgocall.go
index d5794bc..67b2bce 100644
--- a/libgo/go/runtime/cgocall.go
+++ b/libgo/go/runtime/cgocall.go
@@ -243,17 +243,21 @@ func cgoCheckUnknownPointer(p unsafe.Pointer, msg string) (base, i uintptr) {
return
}
- roots := gcRoots
- for roots != nil {
- for j := 0; j < roots.count; j++ {
- pr := roots.roots[j]
- addr := uintptr(pr.decl)
- if cgoInRange(p, addr, addr+pr.size) {
- cgoCheckBits(pr.decl, pr.gcdata, 0, pr.ptrdata)
- return
- }
+ lo := 0
+ hi := len(gcRootsIndex)
+ for lo < hi {
+ m := lo + (hi-lo)/2
+ pr := gcRootsIndex[m]
+ addr := uintptr(pr.decl)
+ if cgoInRange(p, addr, addr+pr.size) {
+ cgoCheckBits(pr.decl, pr.gcdata, 0, pr.ptrdata)
+ return
+ }
+ if uintptr(p) < addr {
+ hi = m
+ } else {
+ lo = m + 1
}
- roots = roots.next
}
return
diff --git a/libgo/go/runtime/mbitmap.go b/libgo/go/runtime/mbitmap.go
index 191239a..c6c8e6a 100644
--- a/libgo/go/runtime/mbitmap.go
+++ b/libgo/go/runtime/mbitmap.go
@@ -575,19 +575,23 @@ func bulkBarrierPreWrite(dst, src, size uintptr) {
if !inheap(dst) {
// If dst is a global, use the data or BSS bitmaps to
// execute write barriers.
- roots := gcRoots
- for roots != nil {
- for i := 0; i < roots.count; i++ {
- pr := roots.roots[i]
- addr := uintptr(pr.decl)
- if addr <= dst && dst < addr+pr.size {
- if dst < addr+pr.ptrdata {
- bulkBarrierBitmap(dst, src, size, dst-addr, pr.gcdata)
- }
- return
+ lo := 0
+ hi := len(gcRootsIndex)
+ for lo < hi {
+ m := lo + (hi-lo)/2
+ pr := gcRootsIndex[m]
+ addr := uintptr(pr.decl)
+ if addr <= dst && dst < addr+pr.size {
+ if dst < addr+pr.ptrdata {
+ bulkBarrierBitmap(dst, src, size, dst-addr, pr.gcdata)
}
+ return
+ }
+ if dst < addr {
+ hi = m
+ } else {
+ lo = m + 1
}
- roots = roots.next
}
return
}
diff --git a/libgo/go/runtime/mgc_gccgo.go b/libgo/go/runtime/mgc_gccgo.go
index 107a70a..cf7780c 100644
--- a/libgo/go/runtime/mgc_gccgo.go
+++ b/libgo/go/runtime/mgc_gccgo.go
@@ -12,6 +12,7 @@ import (
)
// 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.
@@ -32,6 +33,97 @@ type gcRootList struct {
// 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 runtime.registerGCRoots
diff --git a/libgo/go/runtime/proc.go b/libgo/go/runtime/proc.go
index 4c217cc..74325e3 100644
--- a/libgo/go/runtime/proc.go
+++ b/libgo/go/runtime/proc.go
@@ -207,6 +207,7 @@ func main() {
fn := main_init // make an indirect call, as the linker doesn't know the address of the main package when laying down the runtime
fn()
+ createGcRootsIndex()
close(main_init_done)
needUnlock = false