]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/link, runtime: remove typelinks
authorIan Lance Taylor <iant@golang.org>
Wed, 26 Nov 2025 06:44:11 +0000 (22:44 -0800)
committerGopher Robot <gobot@golang.org>
Tue, 27 Jan 2026 21:47:14 +0000 (13:47 -0800)
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 <dmitshur@google.com>
Reviewed-by: Keith Randall <khr@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Ian Lance Taylor <iant@golang.org>

src/cmd/compile/internal/reflectdata/reflect.go
src/cmd/link/internal/ld/data.go
src/cmd/link/internal/ld/elf_test.go
src/cmd/link/internal/ld/symtab.go
src/cmd/link/internal/ld/typelink.go
src/cmd/link/internal/wasm/asm.go
src/runtime/lockrank.go
src/runtime/mklockrank.go
src/runtime/runtime1.go
src/runtime/symtab.go
src/runtime/type.go

index 324007ea798f13a379206d5448186624af06d3d6..8a2b15ab24c94ee876fd9cfb6ebe097fbbf7b68e 100644 (file)
@@ -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
 
index baf7dafce572f86caecfcc1305768d8807cbbd8e..51163c2c8b73e875866a1ed02883c920f718d61b 100644 (file)
@@ -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))
index c56d27f29e459d39fc60f47f099281149847394c..0b3229e29cff64edc2b81a1bb77ded06f68ece9d 100644 (file)
@@ -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
 
index d2bd5d660c0d391d1c98d484d3ed5e97966ebbff..d63a96d12b502037b62786dc699b65347d2d8e2c 100644 (file)
@@ -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)
index 966de5571c3077853cfa2afbf35fe4b977a34481..d9217182ddeda2a41aff565b84eb413d26ec7aab 100644 (file)
@@ -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)
index 5c25cc603b6beb99e32240c81cf59cf861b095c3..7608d292e4fa30493e6156639111966be1a7bc78 100644 (file)
@@ -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)),
index 9e676bf8e35143ae9712226f9224e70439f19326..0f30da9482c6d66373cae37d743dde6e986b99ee 100644 (file)
@@ -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},
index 07b40396a51c7abcdd070146f3d9f62d65dd6cd7..46fd77332d3d6671b8167c92d27519a70d1f098a 100644 (file)
@@ -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.
index 965ff8ab5167d5f106ed6d153ee883c150fca4b4..9b1dd585cacc033862ae7c4eaf9ee93f6f6eecd7 100644 (file)
@@ -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
 }
index 058165553023411764fb2e2ed49539e23ebb1441..5dbf7a9d31c056c92144122d266ff4ba48d77c3c 100644 (file)
@@ -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.
index 9009119464c760812d735c96f6a4557db08a7bde..893c79404ea0e181d8f84531d2d8c4862139d343 100644 (file)
@@ -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