From: Ian Lance Taylor Date: Wed, 26 Nov 2025 06:44:11 +0000 (-0800) Subject: cmd/link, runtime: remove typelinks X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=481ab86aafe0cac177df793c9946c5ef2126137c;p=gostls13.git cmd/link, runtime: remove typelinks Instead of adding a typelinks section to a Go binary, mark the start and end of the typelinked type descriptors. The runtime can then step through the descriptors to find them all, rather than relying on the extra linker-generated offset list. The runtime steps through the type descriptors lazily, as many Go programs don't need the typelinks list at all. This reduces the size of cmd/go by 15K bytes, which isn't much but it's not nothing. A future CL will change the reflect package to use the type pointers directly rather than converting to offsets and then back to type pointers. For #6853 Change-Id: Id0af4ce81c5b1cea899fc92b6ff9d2db8ce4c267 Reviewed-on: https://go-review.googlesource.com/c/go/+/724261 Reviewed-by: Dmitri Shuralyov Reviewed-by: Keith Randall Reviewed-by: Keith Randall LUCI-TryBot-Result: Go LUCI Auto-Submit: Ian Lance Taylor --- diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go index 324007ea79..8a2b15ab24 100644 --- a/src/cmd/compile/internal/reflectdata/reflect.go +++ b/src/cmd/compile/internal/reflectdata/reflect.go @@ -756,6 +756,9 @@ func writeType(t *types.Type) *obj.LSym { // | method list, if any | dextratype // +--------------------------------+ - E + // runtime.moduleTypelinks is aware of this type layout, + // and must be changed if the layout change. + // UncommonType section is included if we have a name or a method. extra := t.Sym() != nil || len(methods(t)) != 0 diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index baf7dafce5..51163c2c8b 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -1535,6 +1535,10 @@ func fixZeroSizedSymbols(ctxt *Link) { types.SetSize(8) ldr.SetAttrSpecial(types.Sym(), false) + etypedesc := ldr.CreateSymForUpdate("runtime.etypedesc", 0) + etypedesc.SetType(sym.STYPE) + ldr.SetAttrSpecial(etypedesc.Sym(), false) + etypes := ldr.CreateSymForUpdate("runtime.etypes", 0) etypes.SetType(sym.STYPE) ldr.SetAttrSpecial(etypes.Sym(), false) @@ -2124,16 +2128,6 @@ func (state *dodataState) allocateDataSections(ctxt *Link) { xcoffUpdateOuterSize(ctxt, int64(sect.Length), sym.SPCLNTAB) } - /* typelink */ - sect = state.allocateNamedDataSection(segro, ".typelink", []sym.SymKind{sym.STYPELINK}, 04) - - typelink := ldr.CreateSymForUpdate("runtime.typelink", 0) - ldr.SetSymSect(typelink.Sym(), sect) - typelink.SetType(sym.SRODATA) - state.datsize += typelink.Size() - state.checkdatsize(sym.STYPELINK) - sect.Length = uint64(state.datsize) - sect.Vaddr - /* read-only ELF, Mach-O sections */ state.allocateSingleSymSections(segro, sym.SELFROSECT, sym.SRODATA, 04) @@ -2224,6 +2218,7 @@ func (state *dodataState) allocateDataSections(ctxt *Link) { sect = createRelroSect(".go.type", sym.STYPE) ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.types", 0), sect) + ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.etypedesc", 0), sect) ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.etypes", 0), sect) sect = createRelroSect(".go.func", sym.SGOFUNC) @@ -2358,39 +2353,107 @@ func (state *dodataState) dodataSect(ctxt *Link, symn sym.SymKind, syms []loader } zerobase = ldr.Lookup("runtime.zerobase", 0) + sortHeadTail := func(si, sj loader.Sym) (less bool, matched bool) { + switch { + case si == head, sj == tail: + return true, true + case sj == head, si == tail: + return false, true + } + return false, false + } + + sortFn := func(i, j int) bool { + si, sj := sl[i].sym, sl[j].sym + isz, jsz := sl[i].sz, sl[j].sz + if ret, matched := sortHeadTail(si, sj); matched { + return ret + } + if sortBySize { + switch { + // put zerobase right after all the zero-sized symbols, + // so zero-sized symbols have the same address as zerobase. + case si == zerobase: + return jsz != 0 // zerobase < nonzero-sized, zerobase > zero-sized + case sj == zerobase: + return isz == 0 // 0-sized < zerobase, nonzero-sized > zerobase + case isz != jsz: + return isz < jsz + } + } else { + iname := sl[i].name + jname := sl[j].name + if iname != jname { + return iname < jname + } + } + return si < sj // break ties by symbol number + } + // Perform the sort. - if symn != sym.SPCLNTAB { + switch symn { + case sym.SPCLNTAB: + // PCLNTAB was built internally, and already has the proper order. + + case sym.STYPE: + // Sort type descriptors with the typelink flag first, + // sorted by type string. The reflect package will use + // this to ensure that type descriptor pointers are unique. + + // Compute all the type strings we need once. + typelinkStrings := make(map[loader.Sym]string) + for _, s := range syms { + if ldr.IsTypelink(s) { + typelinkStrings[s] = decodetypeStr(ldr, ctxt.Arch, s) + } + } + sort.Slice(sl, func(i, j int) bool { si, sj := sl[i].sym, sl[j].sym - isz, jsz := sl[i].sz, sl[j].sz - switch { - case si == head, sj == tail: - return true - case sj == head, si == tail: - return false + + // Sort head and tail regardless of typelink. + if ret, matched := sortHeadTail(si, sj); matched { + return ret } - if sortBySize { - switch { - // put zerobase right after all the zero-sized symbols, - // so zero-sized symbols have the same address as zerobase. - case si == zerobase: - return jsz != 0 // zerobase < nonzero-sized, zerobase > zero-sized - case sj == zerobase: - return isz == 0 // 0-sized < zerobase, nonzero-sized > zerobase - case isz != jsz: - return isz < jsz - } - } else { - iname := sl[i].name - jname := sl[j].name - if iname != jname { - return iname < jname + + iTypestr, iIsTypelink := typelinkStrings[si] + jTypestr, jIsTypelink := typelinkStrings[sj] + + if iIsTypelink { + if jIsTypelink { + // typelink symbols sort by type string + return iTypestr < jTypestr } + + // typelink < non-typelink + return true + } else if jIsTypelink { + // non-typelink greater than typelink + return false } - return si < sj // break ties by symbol number + + // non-typelink symbols sort by size as usual + return sortFn(i, j) }) - } else { - // PCLNTAB was built internally, and already has the proper order. + + // Find the end of the typelink descriptors. + // The offset starts at 1 to match the increment in + // createRelroSect in allocateDataSections. + // TODO: This wastes some space. + offset := int64(1) + for i := range sl { + si := sl[i].sym + if _, isTypelink := typelinkStrings[si]; !isTypelink { + break + } + offset = Rnd(offset, int64(symalign(ldr, si))) + offset += sl[i].sz + } + + ldr.SetSymValue(ldr.LookupOrCreateSym("runtime.etypedesc", 0), offset) + + default: + sort.Slice(sl, sortFn) } // Set alignment, construct result @@ -3035,9 +3098,12 @@ func (ctxt *Link) address() []*sym.Segment { ctxt.xdefine("runtime.rodata", sym.SRODATA, int64(rodata.Vaddr)) ctxt.xdefine("runtime.erodata", sym.SRODATA, int64(rodata.Vaddr+rodata.Length)) ctxt.xdefine("runtime.types", sym.SRODATA, int64(types.Vaddr)) + // etypedesc was set to the offset from the symbol start in dodataSect. + s := ldr.Lookup("runtime.etypedesc", 0) + ctxt.xdefine("runtime.etypedesc", sym.SRODATA, int64(types.Vaddr+uint64(ldr.SymValue(s)))) ctxt.xdefine("runtime.etypes", sym.SRODATA, int64(types.Vaddr+types.Length)) - s := ldr.Lookup("runtime.gcdata", 0) + s = ldr.Lookup("runtime.gcdata", 0) ldr.SetAttrLocal(s, true) ctxt.xdefine("runtime.egcdata", sym.SRODATA, ldr.SymAddr(s)+ldr.SymSize(s)) ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.egcdata", 0), ldr.SymSect(s)) diff --git a/src/cmd/link/internal/ld/elf_test.go b/src/cmd/link/internal/ld/elf_test.go index c56d27f29e..0b3229e29c 100644 --- a/src/cmd/link/internal/ld/elf_test.go +++ b/src/cmd/link/internal/ld/elf_test.go @@ -408,8 +408,7 @@ func TestElfBindNow(t *testing.T) { } // This program is intended to be just big/complicated enough that -// we wind up with decent-sized .data.rel.ro.{typelink,itablink} -// sections. +// we wind up with a decent-sized .data.rel.ro.itablink section. const ifacecallsProg = ` package main diff --git a/src/cmd/link/internal/ld/symtab.go b/src/cmd/link/internal/ld/symtab.go index d2bd5d660c..d63a96d12b 100644 --- a/src/cmd/link/internal/ld/symtab.go +++ b/src/cmd/link/internal/ld/symtab.go @@ -433,6 +433,7 @@ func (ctxt *Link) symtab(pcln *pclntab) []sym.SymKind { ctxt.xdefine("runtime.rodata", sym.SRODATA, 0) ctxt.xdefine("runtime.erodata", sym.SRODATAEND, 0) ctxt.xdefine("runtime.types", sym.SRODATA, 0) + ctxt.xdefine("runtime.etypedesc", sym.SRODATA, 0) ctxt.xdefine("runtime.etypes", sym.SRODATA, 0) ctxt.xdefine("runtime.noptrdata", sym.SNOPTRDATA, 0) ctxt.xdefine("runtime.enoptrdata", sym.SNOPTRDATAEND, 0) @@ -618,6 +619,7 @@ func (ctxt *Link) symtab(pcln *pclntab) []sym.SymKind { moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.gcdata", 0)) moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.gcbss", 0)) moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.types", 0)) + moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.etypedesc", 0)) moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.etypes", 0)) moduledata.AddAddr(ctxt.Arch, ldr.Lookup("runtime.rodata", 0)) moduledata.AddAddr(ctxt.Arch, ldr.Lookup("go:func.*", 0)) @@ -661,11 +663,6 @@ func (ctxt *Link) symtab(pcln *pclntab) []sym.SymKind { // text section information slice(textsectionmapSym, uint64(nsections)) - // The typelinks slice - typelinkSym := ldr.Lookup("runtime.typelink", 0) - ntypelinks := uint64(ldr.SymSize(typelinkSym)) / 4 - slice(typelinkSym, ntypelinks) - // The itablinks slice itablinkSym := ldr.Lookup("runtime.itablink", 0) nitablinks := uint64(ldr.SymSize(itablinkSym)) / uint64(ctxt.Arch.PtrSize) diff --git a/src/cmd/link/internal/ld/typelink.go b/src/cmd/link/internal/ld/typelink.go index 966de5571c..d9217182dd 100644 --- a/src/cmd/link/internal/ld/typelink.go +++ b/src/cmd/link/internal/ld/typelink.go @@ -8,49 +8,20 @@ import ( "cmd/internal/objabi" "cmd/link/internal/loader" "cmd/link/internal/sym" - "slices" - "strings" ) -type typelinkSortKey struct { - TypeStr string - Type loader.Sym -} - -// typelink generates the typelink table which is used by reflect.typelinks(). -// Types that should be added to the typelinks table are marked with the -// MakeTypelink attribute by the compiler. +// typelink generates the itablink table which is used by runtime.itabInit. func (ctxt *Link) typelink() { ldr := ctxt.loader - var typelinks []typelinkSortKey var itabs []loader.Sym for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ { if !ldr.AttrReachable(s) { continue } - if ldr.IsTypelink(s) { - typelinks = append(typelinks, typelinkSortKey{decodetypeStr(ldr, ctxt.Arch, s), s}) - } else if ldr.IsItab(s) { + if ldr.IsItab(s) { itabs = append(itabs, s) } } - slices.SortFunc(typelinks, func(a, b typelinkSortKey) int { - return strings.Compare(a.TypeStr, b.TypeStr) - }) - - tl := ldr.CreateSymForUpdate("runtime.typelink", 0) - tl.SetType(sym.STYPELINK) - ldr.SetAttrLocal(tl.Sym(), true) - tl.SetSize(int64(4 * len(typelinks))) - tl.Grow(tl.Size()) - relocs := tl.AddRelocs(len(typelinks)) - for i, s := range typelinks { - r := relocs.At(i) - r.SetSym(s.Type) - r.SetOff(int32(i * 4)) - r.SetSiz(4) - r.SetType(objabi.R_ADDROFF) - } ptrsize := ctxt.Arch.PtrSize il := ldr.CreateSymForUpdate("runtime.itablink", 0) @@ -58,7 +29,7 @@ func (ctxt *Link) typelink() { ldr.SetAttrLocal(il.Sym(), true) il.SetSize(int64(ptrsize * len(itabs))) il.Grow(il.Size()) - relocs = il.AddRelocs(len(itabs)) + relocs := il.AddRelocs(len(itabs)) for i, s := range itabs { r := relocs.At(i) r.SetSym(s) diff --git a/src/cmd/link/internal/wasm/asm.go b/src/cmd/link/internal/wasm/asm.go index 5c25cc603b..7608d292e4 100644 --- a/src/cmd/link/internal/wasm/asm.go +++ b/src/cmd/link/internal/wasm/asm.go @@ -125,7 +125,6 @@ var dataSects []wasmDataSect func asmb(ctxt *ld.Link, ldr *loader.Loader) { sections := []*sym.Section{ ldr.SymSect(ldr.Lookup("runtime.rodata", 0)), - ldr.SymSect(ldr.Lookup("runtime.typelink", 0)), ldr.SymSect(ldr.Lookup("runtime.itablink", 0)), ldr.SymSect(ldr.Lookup("runtime.types", 0)), ldr.SymSect(ldr.Lookup("go:funcdesc", 0)), diff --git a/src/runtime/lockrank.go b/src/runtime/lockrank.go index 9e676bf8e3..0f30da9482 100644 --- a/src/runtime/lockrank.go +++ b/src/runtime/lockrank.go @@ -47,6 +47,7 @@ const ( lockRankRoot lockRankItab lockRankReflectOffs + lockRankTypelinks lockRankSynctest lockRankUserArenaState // TRACEGLOBAL @@ -127,6 +128,7 @@ var lockNames = []string{ lockRankRoot: "root", lockRankItab: "itab", lockRankReflectOffs: "reflectOffs", + lockRankTypelinks: "typelinks", lockRankSynctest: "synctest", lockRankUserArenaState: "userArenaState", lockRankTraceBuf: "traceBuf", @@ -214,31 +216,32 @@ var lockPartialOrder [][]lockRank = [][]lockRank{ lockRankRoot: {}, lockRankItab: {}, lockRankReflectOffs: {lockRankItab}, + lockRankTypelinks: {}, lockRankSynctest: {lockRankSysmon, lockRankScavenge, lockRankSweepWaiters, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankRoot, lockRankItab, lockRankReflectOffs}, lockRankUserArenaState: {}, lockRankTraceBuf: {lockRankSysmon, lockRankScavenge}, lockRankTraceStrings: {lockRankSysmon, lockRankScavenge, lockRankTraceBuf}, - lockRankFin: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, - lockRankSpanSetSpine: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, - lockRankMspanSpecial: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, - lockRankTraceTypeTab: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, - lockRankGcBitsArenas: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankMspanSpecial}, - lockRankProfInsert: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, - lockRankProfBlock: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, - lockRankProfMemActive: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, - lockRankProfMemFuture: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankProfMemActive}, - lockRankGscan: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankSynctest, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture}, - lockRankStackpool: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankSynctest, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan}, - lockRankStackLarge: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankSynctest, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan}, - lockRankHchanLeaf: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankSynctest, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankHchanLeaf}, - lockRankWbufSpans: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankSynctest, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan}, + lockRankFin: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankTypelinks, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, + lockRankSpanSetSpine: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankTypelinks, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, + lockRankMspanSpecial: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankTypelinks, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, + lockRankTraceTypeTab: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankTypelinks, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, + lockRankGcBitsArenas: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankTypelinks, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankMspanSpecial}, + lockRankProfInsert: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankTypelinks, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, + lockRankProfBlock: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankTypelinks, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, + lockRankProfMemActive: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankTypelinks, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, + lockRankProfMemFuture: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankTypelinks, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankProfMemActive}, + lockRankGscan: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankTypelinks, lockRankSynctest, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture}, + lockRankStackpool: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankTypelinks, lockRankSynctest, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan}, + lockRankStackLarge: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankTypelinks, lockRankSynctest, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan}, + lockRankHchanLeaf: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankTypelinks, lockRankSynctest, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankHchanLeaf}, + lockRankWbufSpans: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankTypelinks, lockRankSynctest, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan}, lockRankXRegAlloc: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched}, - lockRankSpanSPMCs: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankSynctest, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan}, - lockRankMheap: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankSynctest, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans}, - lockRankMheapSpecial: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankSynctest, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankMheap}, - lockRankGlobalAlloc: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankSynctest, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankXRegAlloc, lockRankSpanSPMCs, lockRankMheap, lockRankMheapSpecial}, - lockRankTrace: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankSynctest, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankMheap}, - lockRankTraceStackTab: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankSynctest, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankMheap, lockRankTrace}, + lockRankSpanSPMCs: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankTypelinks, lockRankSynctest, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan}, + lockRankMheap: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankTypelinks, lockRankSynctest, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans}, + lockRankMheapSpecial: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankTypelinks, lockRankSynctest, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankMheap}, + lockRankGlobalAlloc: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankTypelinks, lockRankSynctest, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankXRegAlloc, lockRankSpanSPMCs, lockRankMheap, lockRankMheapSpecial}, + lockRankTrace: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankTypelinks, lockRankSynctest, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankMheap}, + lockRankTraceStackTab: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankComputeMaxProcs, lockRankUpdateMaxProcsG, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankCleanupQueue, lockRankSweep, lockRankTestR, lockRankVgetrandom, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankTypelinks, lockRankSynctest, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankMheap, lockRankTrace}, lockRankPanic: {}, lockRankDeadlock: {lockRankPanic, lockRankDeadlock}, lockRankRaceFini: {lockRankPanic}, diff --git a/src/runtime/mklockrank.go b/src/runtime/mklockrank.go index 07b40396a5..46fd77332d 100644 --- a/src/runtime/mklockrank.go +++ b/src/runtime/mklockrank.go @@ -102,6 +102,10 @@ NONE < itab < reflectOffs; +# Typelinks +NONE +< typelinks; + # Synctest hchan, notifyList, @@ -138,6 +142,7 @@ allg, reflectOffs, timer, traceStrings, + typelinks, userArenaState, vgetrandom # Above MALLOC are things that can allocate memory. diff --git a/src/runtime/runtime1.go b/src/runtime/runtime1.go index 965ff8ab51..9b1dd585ca 100644 --- a/src/runtime/runtime1.go +++ b/src/runtime/runtime1.go @@ -630,11 +630,21 @@ func releasem(mp *m) { //go:linkname reflect_typelinks reflect.typelinks func reflect_typelinks() ([]unsafe.Pointer, [][]int32) { modules := activeModules() + + typesToOffsets := func(md *moduledata) []int32 { + types := moduleTypelinks(md) + ret := make([]int32, 0, len(types)) + for _, typ := range types { + ret = append(ret, int32(uintptr(unsafe.Pointer(typ))-md.types)) + } + return ret + } + sections := []unsafe.Pointer{unsafe.Pointer(modules[0].types)} - ret := [][]int32{modules[0].typelinks} + ret := [][]int32{typesToOffsets(modules[0])} for _, md := range modules[1:] { sections = append(sections, unsafe.Pointer(md.types)) - ret = append(ret, md.typelinks) + ret = append(ret, typesToOffsets(md)) } return sections, ret } diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go index 0581655530..5dbf7a9d31 100644 --- a/src/runtime/symtab.go +++ b/src/runtime/symtab.go @@ -412,20 +412,19 @@ type moduledata struct { findfunctab uintptr minpc, maxpc uintptr - text, etext uintptr - noptrdata, enoptrdata uintptr - data, edata uintptr - bss, ebss uintptr - noptrbss, enoptrbss uintptr - covctrs, ecovctrs uintptr - end, gcdata, gcbss uintptr - types, etypes uintptr - rodata uintptr - gofunc uintptr // go.func.* - epclntab uintptr + text, etext uintptr + noptrdata, enoptrdata uintptr + data, edata uintptr + bss, ebss uintptr + noptrbss, enoptrbss uintptr + covctrs, ecovctrs uintptr + end, gcdata, gcbss uintptr + types, etypedesc, etypes uintptr + rodata uintptr + gofunc uintptr // go.func.* + epclntab uintptr textsectmap []textsect - typelinks []int32 // offsets from types itablinks []*itab ptab []ptabEntry @@ -445,7 +444,7 @@ type moduledata struct { gcdatamask, gcbssmask bitvector - typemap map[typeOff]*_type // offset to *_rtype in previous module + typemap map[*_type]*_type // *_type to use from previous module next *moduledata } @@ -468,14 +467,14 @@ type modulehash struct { runtimehash *string } -// pinnedTypemaps are the map[typeOff]*_type from the moduledata objects. +// pinnedTypemaps are the map[*_type]*_type from the moduledata objects. // // These typemap objects are allocated at run time on the heap, but the // only direct reference to them is in the moduledata, created by the // linker and marked SNOPTRDATA so it is ignored by the GC. // // To make sure the map isn't collected, we keep a second reference here. -var pinnedTypemaps []map[typeOff]*_type +var pinnedTypemaps []map[*_type]*_type // aixStaticDataBase (used only on AIX) holds the unrelocated address // of the data section, set by the linker. diff --git a/src/runtime/type.go b/src/runtime/type.go index 9009119464..893c79404e 100644 --- a/src/runtime/type.go +++ b/src/runtime/type.go @@ -352,15 +352,16 @@ func resolveTypeOff(ptrInModule unsafe.Pointer, off typeOff) *_type { } return (*_type)(res) } - if t := md.typemap[off]; t != nil { + res := md.types + uintptr(off) + resType := (*_type)(unsafe.Pointer(res)) + if t := md.typemap[resType]; t != nil { return t } - res := md.types + uintptr(off) if res > md.etypes { println("runtime: typeOff", hex(off), "out of range", hex(md.types), "-", hex(md.etypes)) throw("runtime: type offset out of range") } - return (*_type)(unsafe.Pointer(res)) + return resType } func (t rtype) typeOff(off typeOff) *_type { @@ -435,22 +436,23 @@ func pkgPath(n name) string { // typelinksinit scans the types from extra modules and builds the // moduledata typemap used to de-duplicate type pointers. func typelinksinit() { + lockInit(&moduleToTypelinksLock, lockRankTypelinks) + if firstmoduledata.next == nil { return } - typehash := make(map[uint32][]*_type, len(firstmoduledata.typelinks)) modules := activeModules() prev := modules[0] + prevTypelinks := moduleTypelinks(modules[0]) + typehash := make(map[uint32][]*_type, len(prevTypelinks)) for _, md := range modules[1:] { // Collect types from the previous module into typehash. collect: - for _, tl := range prev.typelinks { - var t *_type - if prev.typemap == nil { - t = (*_type)(unsafe.Pointer(prev.types + uintptr(tl))) - } else { - t = prev.typemap[typeOff(tl)] + for _, tl := range prevTypelinks { + t := tl + if prev.typemap != nil { + t = prev.typemap[tl] } // Add to typehash if not seen before. tlist := typehash[t.Hash] @@ -462,30 +464,141 @@ func typelinksinit() { typehash[t.Hash] = append(tlist, t) } + mdTypelinks := moduleTypelinks(md) + if md.typemap == nil { // If any of this module's typelinks match a type from a // prior module, prefer that prior type by adding the offset // to this module's typemap. - tm := make(map[typeOff]*_type, len(md.typelinks)) + tm := make(map[*_type]*_type, len(mdTypelinks)) pinnedTypemaps = append(pinnedTypemaps, tm) md.typemap = tm - for _, tl := range md.typelinks { - t := (*_type)(unsafe.Pointer(md.types + uintptr(tl))) + for _, t := range mdTypelinks { + set := t for _, candidate := range typehash[t.Hash] { seen := map[_typePair]struct{}{} if typesEqual(t, candidate, seen) { - t = candidate + set = candidate break } } - md.typemap[typeOff(tl)] = t + md.typemap[t] = set } } prev = md + prevTypelinks = mdTypelinks } } +// moduleToTypelinks maps from moduledata to typelinks. +// We build this lazily as needed, since most programs do not need it. +var ( + moduleToTypelinks map[*moduledata][]*_type + moduleToTypelinksLock mutex +) + +// moduleTypelinks takes a moduledata and returns the type +// descriptors that the reflect package needs to know about. +// These are the typelinks. They are the types that the user +// can construct. This is used to ensure that we use a unique +// type descriptor for all types. The returned types are sorted +// by type string; the sorting is done by the linker. +// This slice is constructed as needed. +func moduleTypelinks(md *moduledata) []*_type { + lock(&moduleToTypelinksLock) + + if typelinks, ok := moduleToTypelinks[md]; ok { + unlock(&moduleToTypelinksLock) + return typelinks + } + + // Allocate a very rough estimate of the number of types. + ret := make([]*_type, 0, (md.etypedesc-md.types)/(2*unsafe.Sizeof(_type{}))) + + td := md.types + + // We have to increment by 1 to match the increment done in + // cmd/link/internal/data.go createRelroSect in allocateDataSections. + td++ + + for td < md.etypedesc { + // TODO: The fact that type descriptors are aligned to + // 0x20 does not make sense. + td = alignUp(td, 0x20) + + // This code must match the data structures built by + // cmd/compile/internal/reflectdata/reflect.go:writeType. + + typ := (*_type)(unsafe.Pointer(td)) + + ret = append(ret, typ) + + var typSize, add uintptr + switch typ.Kind_ { + case abi.Array: + typSize = unsafe.Sizeof(abi.ArrayType{}) + case abi.Chan: + typSize = unsafe.Sizeof(abi.ChanType{}) + case abi.Func: + typSize = unsafe.Sizeof(abi.FuncType{}) + ft := (*abi.FuncType)(unsafe.Pointer(typ)) + add = uintptr(ft.NumIn()+ft.NumOut()) * goarch.PtrSize + case abi.Interface: + typSize = unsafe.Sizeof(abi.InterfaceType{}) + it := (*abi.InterfaceType)(unsafe.Pointer(typ)) + add = uintptr(len(it.Methods)) * unsafe.Sizeof(abi.Imethod{}) + case abi.Map: + typSize = unsafe.Sizeof(abi.MapType{}) + case abi.Pointer: + typSize = unsafe.Sizeof(abi.PtrType{}) + case abi.Slice: + typSize = unsafe.Sizeof(abi.SliceType{}) + case abi.Struct: + typSize = unsafe.Sizeof(abi.StructType{}) + st := (*abi.StructType)(unsafe.Pointer(typ)) + add = uintptr(len(st.Fields)) * unsafe.Sizeof(abi.StructField{}) + + case abi.Bool, + abi.Int, abi.Int8, abi.Int16, abi.Int32, abi.Int64, + abi.Uint, abi.Uint8, abi.Uint16, abi.Uint32, abi.Uint64, abi.Uintptr, + abi.Float32, abi.Float64, + abi.Complex64, abi.Complex128, + abi.String, + abi.UnsafePointer: + + typSize = unsafe.Sizeof(_type{}) + + default: + println("type descriptor at", hex(td), "is kind", typ.Kind_) + throw("invalid type descriptor") + } + + td += typSize + + mcount := uintptr(0) + if typ.TFlag&abi.TFlagUncommon != 0 { + ut := (*abi.UncommonType)(unsafe.Pointer(td)) + mcount = uintptr(ut.Mcount) + td += unsafe.Sizeof(abi.UncommonType{}) + } + + td += add + + if mcount > 0 { + td += mcount * unsafe.Sizeof(abi.Method{}) + } + } + + if moduleToTypelinks == nil { + moduleToTypelinks = make(map[*moduledata][]*_type) + } + moduleToTypelinks[md] = ret + + unlock(&moduleToTypelinksLock) + return ret +} + type _typePair struct { t1 *_type t2 *_type