Skip to content

Commit

Permalink
runtime: refactor markGlobals to findGlobals
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
aykevl committed Sep 1, 2023
1 parent dc44988 commit 0b33e17
Show file tree
Hide file tree
Showing 8 changed files with 20 additions and 27 deletions.
2 changes: 1 addition & 1 deletion src/runtime/gc_blocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
11 changes: 6 additions & 5 deletions src/runtime/gc_globals.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 changes: 0 additions & 4 deletions src/runtime/gc_leaking.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,3 @@ func setHeapEnd(newHeapEnd uintptr) {
// enough.
heapEnd = newHeapEnd
}

func markRoots(start, end uintptr) {
// dummy, so that markGlobals will compile
}
4 changes: 0 additions & 4 deletions src/runtime/gc_none.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 changes: 3 additions & 3 deletions src/runtime/os_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -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/

Expand Down Expand Up @@ -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)
}
}

Expand Down
8 changes: 4 additions & 4 deletions src/runtime/os_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand All @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions src/runtime/os_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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{})))
}
Expand Down
8 changes: 4 additions & 4 deletions src/runtime/runtime_nintendoswitch.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 0b33e17

Please sign in to comment.