Browse Source

runtime: refactor markGlobals to findGlobals

Instead of markGlobals calling markRoots unconditionally (which doesn't
make sense for -gc=none and -gc=leaking), provide markRoots as a
callback function.

This is in preparation for -gc=boehm, where the previous design is even
more awkward and a callback makes far more sense.

I've tested the size impact using `make smoketest XTENSA=0`. There is
none, except for two cases:

  * One with `-opt=0` so const-propagation for the callback didn't take
    place.
  * One other on AVR, I don't know why but as it's only 16 bytes in a
    very specific case I'm going to assume it's just a random change in
    compiler output that caused a size difference.
pull/3896/head
Ayke van Laethem 1 year ago
committed by Ron Evans
parent
commit
4643401a1d
  1. 2
      src/runtime/gc_blocks.go
  2. 11
      src/runtime/gc_globals.go
  3. 4
      src/runtime/gc_leaking.go
  4. 4
      src/runtime/gc_none.go
  5. 6
      src/runtime/os_darwin.go
  6. 8
      src/runtime/os_linux.go
  7. 4
      src/runtime/os_windows.go
  8. 8
      src/runtime/runtime_nintendoswitch.go

2
src/runtime/gc_blocks.go

@ -420,7 +420,7 @@ func runGC() (freeBytes uintptr) {
// Mark phase: mark all reachable objects, recursively.
markStack()
markGlobals()
findGlobals(markRoots)
if baremetal && hasScheduler {
// Channel operations in interrupts may move task pointers around while we are marking.

11
src/runtime/gc_globals.go

@ -2,13 +2,14 @@
package runtime
// This file implements markGlobals for all the files that don't have a more
// specific implementation.
// This file implements findGlobals for all systems where the start and end of
// the globals section can be found through linker-defined symbols.
// markGlobals marks all globals, which are reachable by definition.
// findGlobals finds all globals (which are reachable by definition) and calls
// the callback for them.
//
// This implementation marks all globals conservatively and assumes it can use
// linker-defined symbols for the start and end of the .data section.
func markGlobals() {
markRoots(globalsStart, globalsEnd)
func findGlobals(found func(start, end uintptr)) {
found(globalsStart, globalsEnd)
}

4
src/runtime/gc_leaking.go

@ -100,7 +100,3 @@ func setHeapEnd(newHeapEnd uintptr) {
// enough.
heapEnd = newHeapEnd
}
func markRoots(start, end uintptr) {
// dummy, so that markGlobals will compile
}

4
src/runtime/gc_none.go

@ -37,7 +37,3 @@ func initHeap() {
func setHeapEnd(newHeapEnd uintptr) {
// Nothing to do here, this function is never actually called.
}
func markRoots(start, end uintptr) {
// dummy, so that markGlobals will compile
}

6
src/runtime/os_darwin.go

@ -54,12 +54,12 @@ type segmentLoadCommand struct {
//go:extern _mh_execute_header
var libc_mh_execute_header machHeader
// Mark global variables.
// Find global variables in .data/.bss sections.
// The MachO linker doesn't seem to provide symbols for the start and end of the
// data section. There is get_etext, get_edata, and get_end, but these are
// undocumented and don't work with ASLR (which is enabled by default).
// Therefore, read the MachO header directly.
func markGlobals() {
func findGlobals(found func(start, end uintptr)) {
// Here is a useful blog post to understand the MachO file format:
// https://h3adsh0tzz.com/2020/01/macho-file-format/
@ -103,7 +103,7 @@ func markGlobals() {
// This could be improved by only reading the memory areas
// covered by sections. That would reduce the amount of memory
// scanned a little bit (up to a single VM page).
markRoots(offset+cmd.vmaddr, offset+cmd.vmaddr+cmd.vmsize)
found(offset+cmd.vmaddr, offset+cmd.vmaddr+cmd.vmsize)
}
}

8
src/runtime/os_linux.go

@ -77,9 +77,9 @@ type elfProgramHeader32 struct {
//go:extern __ehdr_start
var ehdr_start elfHeader
// markGlobals marks all globals, which are reachable by definition.
// findGlobals finds globals in the .data/.bss sections.
// It parses the ELF program header to find writable segments.
func markGlobals() {
func findGlobals(found func(start, end uintptr)) {
// Relevant constants from the ELF specification.
// See: https://refspecs.linuxfoundation.org/elf/elf.pdf
const (
@ -99,14 +99,14 @@ func markGlobals() {
if header._type == PT_LOAD && header.flags&PF_W != 0 {
start := header.vaddr
end := start + header.memsz
markRoots(start, end)
found(start, end)
}
} else {
header := (*elfProgramHeader32)(headerPtr)
if header._type == PT_LOAD && header.flags&PF_W != 0 {
start := header.vaddr
end := start + header.memsz
markRoots(start, end)
found(start, end)
}
}
headerPtr = unsafe.Add(headerPtr, ehdr_start.phentsize)

4
src/runtime/os_windows.go

@ -52,7 +52,7 @@ var module *exeHeader
// around 160 bytes of amd64 instructions.
// Most of this function is based on the documentation in
// https://docs.microsoft.com/en-us/windows/win32/debug/pe-format.
func markGlobals() {
func findGlobals(found func(start, end uintptr)) {
// Constants used in this function.
const (
// https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulehandleexa
@ -85,7 +85,7 @@ func markGlobals() {
// Found a writable section. Scan the entire section for roots.
start := uintptr(unsafe.Pointer(module)) + uintptr(section.virtualAddress)
end := uintptr(unsafe.Pointer(module)) + uintptr(section.virtualAddress) + uintptr(section.virtualSize)
markRoots(start, end)
found(start, end)
}
section = (*peSection)(unsafe.Add(unsafe.Pointer(section), unsafe.Sizeof(peSection{})))
}

8
src/runtime/runtime_nintendoswitch.go

@ -245,17 +245,17 @@ var bssStartSymbol [0]byte
//go:extern __bss_end
var bssEndSymbol [0]byte
// Mark global variables.
// Find global variables.
// The linker script provides __*_start and __*_end symbols that can be used to
// scan the given sections. They are already aligned so don't need to be
// manually aligned here.
func markGlobals() {
func findGlobals(found func(start, end uintptr)) {
dataStart := uintptr(unsafe.Pointer(&dataStartSymbol))
dataEnd := uintptr(unsafe.Pointer(&dataEndSymbol))
markRoots(dataStart, dataEnd)
found(dataStart, dataEnd)
bssStart := uintptr(unsafe.Pointer(&bssStartSymbol))
bssEnd := uintptr(unsafe.Pointer(&bssEndSymbol))
markRoots(bssStart, bssEnd)
found(bssStart, bssEnd)
}
// getContextPtr returns the hblauncher context

Loading…
Cancel
Save