1
0
mirror of https://github.com/golang/go synced 2024-11-21 21:14:47 -07:00

cmd/compile,internal/runtime/maps: stack allocated maps and small alloc

The compiler will stack allocate the Map struct and initial group if
possible.

Stack maps are initialized inline without calling into the runtime.
Small heap allocated maps use makemap_small.

These are the same heuristics as existing maps.

For #54766.

Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest-swissmap
Change-Id: I6c371d1309716fd1c38a3212d417b3c76db5c9b9
Reviewed-on: https://go-review.googlesource.com/c/go/+/622042
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: Keith Randall <khr@google.com>
Auto-Submit: Michael Pratt <mpratt@google.com>
This commit is contained in:
Michael Pratt 2024-10-25 15:08:54 -04:00 committed by Gopher Robot
parent aefb173b0a
commit 63ba2b9d84
13 changed files with 366 additions and 382 deletions

View File

@ -129,6 +129,7 @@ func panicrangestate(state int)
// defer in range over func
func deferrangefunc() interface{}
func rand() uint64
func rand32() uint32
// *byte is really *runtime.Type

View File

@ -109,138 +109,139 @@ var runtimeDecls = [...]struct {
{"efaceeq", funcTag, 77},
{"panicrangestate", funcTag, 78},
{"deferrangefunc", funcTag, 79},
{"rand32", funcTag, 80},
{"makemap64", funcTag, 82},
{"makemap", funcTag, 83},
{"makemap_small", funcTag, 84},
{"mapaccess1", funcTag, 85},
{"mapaccess1_fast32", funcTag, 86},
{"mapaccess1_fast64", funcTag, 87},
{"mapaccess1_faststr", funcTag, 88},
{"mapaccess1_fat", funcTag, 89},
{"mapaccess2", funcTag, 90},
{"mapaccess2_fast32", funcTag, 91},
{"mapaccess2_fast64", funcTag, 92},
{"mapaccess2_faststr", funcTag, 93},
{"mapaccess2_fat", funcTag, 94},
{"mapassign", funcTag, 85},
{"mapassign_fast32", funcTag, 86},
{"mapassign_fast32ptr", funcTag, 95},
{"mapassign_fast64", funcTag, 87},
{"mapassign_fast64ptr", funcTag, 95},
{"mapassign_faststr", funcTag, 88},
{"mapiterinit", funcTag, 96},
{"mapdelete", funcTag, 96},
{"mapdelete_fast32", funcTag, 97},
{"mapdelete_fast64", funcTag, 98},
{"mapdelete_faststr", funcTag, 99},
{"mapiternext", funcTag, 100},
{"mapclear", funcTag, 101},
{"makechan64", funcTag, 103},
{"makechan", funcTag, 104},
{"chanrecv1", funcTag, 106},
{"chanrecv2", funcTag, 107},
{"chansend1", funcTag, 109},
{"closechan", funcTag, 110},
{"chanlen", funcTag, 111},
{"chancap", funcTag, 111},
{"writeBarrier", varTag, 113},
{"typedmemmove", funcTag, 114},
{"typedmemclr", funcTag, 115},
{"typedslicecopy", funcTag, 116},
{"selectnbsend", funcTag, 117},
{"selectnbrecv", funcTag, 118},
{"selectsetpc", funcTag, 119},
{"selectgo", funcTag, 120},
{"rand", funcTag, 80},
{"rand32", funcTag, 81},
{"makemap64", funcTag, 83},
{"makemap", funcTag, 84},
{"makemap_small", funcTag, 85},
{"mapaccess1", funcTag, 86},
{"mapaccess1_fast32", funcTag, 87},
{"mapaccess1_fast64", funcTag, 88},
{"mapaccess1_faststr", funcTag, 89},
{"mapaccess1_fat", funcTag, 90},
{"mapaccess2", funcTag, 91},
{"mapaccess2_fast32", funcTag, 92},
{"mapaccess2_fast64", funcTag, 93},
{"mapaccess2_faststr", funcTag, 94},
{"mapaccess2_fat", funcTag, 95},
{"mapassign", funcTag, 86},
{"mapassign_fast32", funcTag, 87},
{"mapassign_fast32ptr", funcTag, 96},
{"mapassign_fast64", funcTag, 88},
{"mapassign_fast64ptr", funcTag, 96},
{"mapassign_faststr", funcTag, 89},
{"mapiterinit", funcTag, 97},
{"mapdelete", funcTag, 97},
{"mapdelete_fast32", funcTag, 98},
{"mapdelete_fast64", funcTag, 99},
{"mapdelete_faststr", funcTag, 100},
{"mapiternext", funcTag, 101},
{"mapclear", funcTag, 102},
{"makechan64", funcTag, 104},
{"makechan", funcTag, 105},
{"chanrecv1", funcTag, 107},
{"chanrecv2", funcTag, 108},
{"chansend1", funcTag, 110},
{"closechan", funcTag, 111},
{"chanlen", funcTag, 112},
{"chancap", funcTag, 112},
{"writeBarrier", varTag, 114},
{"typedmemmove", funcTag, 115},
{"typedmemclr", funcTag, 116},
{"typedslicecopy", funcTag, 117},
{"selectnbsend", funcTag, 118},
{"selectnbrecv", funcTag, 119},
{"selectsetpc", funcTag, 120},
{"selectgo", funcTag, 121},
{"block", funcTag, 9},
{"makeslice", funcTag, 121},
{"makeslice64", funcTag, 122},
{"makeslicecopy", funcTag, 123},
{"growslice", funcTag, 125},
{"unsafeslicecheckptr", funcTag, 126},
{"makeslice", funcTag, 122},
{"makeslice64", funcTag, 123},
{"makeslicecopy", funcTag, 124},
{"growslice", funcTag, 126},
{"unsafeslicecheckptr", funcTag, 127},
{"panicunsafeslicelen", funcTag, 9},
{"panicunsafeslicenilptr", funcTag, 9},
{"unsafestringcheckptr", funcTag, 127},
{"unsafestringcheckptr", funcTag, 128},
{"panicunsafestringlen", funcTag, 9},
{"panicunsafestringnilptr", funcTag, 9},
{"memmove", funcTag, 128},
{"memclrNoHeapPointers", funcTag, 129},
{"memclrHasPointers", funcTag, 129},
{"memequal", funcTag, 130},
{"memequal0", funcTag, 131},
{"memequal8", funcTag, 131},
{"memequal16", funcTag, 131},
{"memequal32", funcTag, 131},
{"memequal64", funcTag, 131},
{"memequal128", funcTag, 131},
{"f32equal", funcTag, 132},
{"f64equal", funcTag, 132},
{"c64equal", funcTag, 132},
{"c128equal", funcTag, 132},
{"strequal", funcTag, 132},
{"interequal", funcTag, 132},
{"nilinterequal", funcTag, 132},
{"memhash", funcTag, 133},
{"memhash0", funcTag, 134},
{"memhash8", funcTag, 134},
{"memhash16", funcTag, 134},
{"memhash32", funcTag, 134},
{"memhash64", funcTag, 134},
{"memhash128", funcTag, 134},
{"f32hash", funcTag, 135},
{"f64hash", funcTag, 135},
{"c64hash", funcTag, 135},
{"c128hash", funcTag, 135},
{"strhash", funcTag, 135},
{"interhash", funcTag, 135},
{"nilinterhash", funcTag, 135},
{"int64div", funcTag, 136},
{"uint64div", funcTag, 137},
{"int64mod", funcTag, 136},
{"uint64mod", funcTag, 137},
{"float64toint64", funcTag, 138},
{"float64touint64", funcTag, 139},
{"float64touint32", funcTag, 140},
{"int64tofloat64", funcTag, 141},
{"int64tofloat32", funcTag, 143},
{"uint64tofloat64", funcTag, 144},
{"uint64tofloat32", funcTag, 145},
{"uint32tofloat64", funcTag, 146},
{"complex128div", funcTag, 147},
{"memmove", funcTag, 129},
{"memclrNoHeapPointers", funcTag, 130},
{"memclrHasPointers", funcTag, 130},
{"memequal", funcTag, 131},
{"memequal0", funcTag, 132},
{"memequal8", funcTag, 132},
{"memequal16", funcTag, 132},
{"memequal32", funcTag, 132},
{"memequal64", funcTag, 132},
{"memequal128", funcTag, 132},
{"f32equal", funcTag, 133},
{"f64equal", funcTag, 133},
{"c64equal", funcTag, 133},
{"c128equal", funcTag, 133},
{"strequal", funcTag, 133},
{"interequal", funcTag, 133},
{"nilinterequal", funcTag, 133},
{"memhash", funcTag, 134},
{"memhash0", funcTag, 135},
{"memhash8", funcTag, 135},
{"memhash16", funcTag, 135},
{"memhash32", funcTag, 135},
{"memhash64", funcTag, 135},
{"memhash128", funcTag, 135},
{"f32hash", funcTag, 136},
{"f64hash", funcTag, 136},
{"c64hash", funcTag, 136},
{"c128hash", funcTag, 136},
{"strhash", funcTag, 136},
{"interhash", funcTag, 136},
{"nilinterhash", funcTag, 136},
{"int64div", funcTag, 137},
{"uint64div", funcTag, 138},
{"int64mod", funcTag, 137},
{"uint64mod", funcTag, 138},
{"float64toint64", funcTag, 139},
{"float64touint64", funcTag, 140},
{"float64touint32", funcTag, 141},
{"int64tofloat64", funcTag, 142},
{"int64tofloat32", funcTag, 144},
{"uint64tofloat64", funcTag, 145},
{"uint64tofloat32", funcTag, 146},
{"uint32tofloat64", funcTag, 147},
{"complex128div", funcTag, 148},
{"racefuncenter", funcTag, 31},
{"racefuncexit", funcTag, 9},
{"raceread", funcTag, 31},
{"racewrite", funcTag, 31},
{"racereadrange", funcTag, 148},
{"racewriterange", funcTag, 148},
{"msanread", funcTag, 148},
{"msanwrite", funcTag, 148},
{"msanmove", funcTag, 149},
{"asanread", funcTag, 148},
{"asanwrite", funcTag, 148},
{"checkptrAlignment", funcTag, 150},
{"checkptrArithmetic", funcTag, 152},
{"libfuzzerTraceCmp1", funcTag, 153},
{"libfuzzerTraceCmp2", funcTag, 154},
{"libfuzzerTraceCmp4", funcTag, 155},
{"libfuzzerTraceCmp8", funcTag, 156},
{"libfuzzerTraceConstCmp1", funcTag, 153},
{"libfuzzerTraceConstCmp2", funcTag, 154},
{"libfuzzerTraceConstCmp4", funcTag, 155},
{"libfuzzerTraceConstCmp8", funcTag, 156},
{"libfuzzerHookStrCmp", funcTag, 157},
{"libfuzzerHookEqualFold", funcTag, 157},
{"addCovMeta", funcTag, 159},
{"racereadrange", funcTag, 149},
{"racewriterange", funcTag, 149},
{"msanread", funcTag, 149},
{"msanwrite", funcTag, 149},
{"msanmove", funcTag, 150},
{"asanread", funcTag, 149},
{"asanwrite", funcTag, 149},
{"checkptrAlignment", funcTag, 151},
{"checkptrArithmetic", funcTag, 153},
{"libfuzzerTraceCmp1", funcTag, 154},
{"libfuzzerTraceCmp2", funcTag, 155},
{"libfuzzerTraceCmp4", funcTag, 156},
{"libfuzzerTraceCmp8", funcTag, 157},
{"libfuzzerTraceConstCmp1", funcTag, 154},
{"libfuzzerTraceConstCmp2", funcTag, 155},
{"libfuzzerTraceConstCmp4", funcTag, 156},
{"libfuzzerTraceConstCmp8", funcTag, 157},
{"libfuzzerHookStrCmp", funcTag, 158},
{"libfuzzerHookEqualFold", funcTag, 158},
{"addCovMeta", funcTag, 160},
{"x86HasPOPCNT", varTag, 6},
{"x86HasSSE41", varTag, 6},
{"x86HasFMA", varTag, 6},
{"armHasVFPv4", varTag, 6},
{"arm64HasATOMICS", varTag, 6},
{"asanregisterglobals", funcTag, 129},
{"asanregisterglobals", funcTag, 130},
}
func runtimeTypes() []*types.Type {
var typs [160]*types.Type
var typs [161]*types.Type
typs[0] = types.ByteType
typs[1] = types.NewPtr(typs[0])
typs[2] = types.Types[types.TANY]
@ -321,86 +322,87 @@ func runtimeTypes() []*types.Type {
typs[77] = newSig(params(typs[76], typs[7], typs[7]), params(typs[6]))
typs[78] = newSig(params(typs[15]), nil)
typs[79] = newSig(nil, params(typs[10]))
typs[80] = newSig(nil, params(typs[65]))
typs[81] = types.NewMap(typs[2], typs[2])
typs[82] = newSig(params(typs[1], typs[22], typs[3]), params(typs[81]))
typs[83] = newSig(params(typs[1], typs[15], typs[3]), params(typs[81]))
typs[84] = newSig(nil, params(typs[81]))
typs[85] = newSig(params(typs[1], typs[81], typs[3]), params(typs[3]))
typs[86] = newSig(params(typs[1], typs[81], typs[65]), params(typs[3]))
typs[87] = newSig(params(typs[1], typs[81], typs[24]), params(typs[3]))
typs[88] = newSig(params(typs[1], typs[81], typs[28]), params(typs[3]))
typs[89] = newSig(params(typs[1], typs[81], typs[3], typs[1]), params(typs[3]))
typs[90] = newSig(params(typs[1], typs[81], typs[3]), params(typs[3], typs[6]))
typs[91] = newSig(params(typs[1], typs[81], typs[65]), params(typs[3], typs[6]))
typs[92] = newSig(params(typs[1], typs[81], typs[24]), params(typs[3], typs[6]))
typs[93] = newSig(params(typs[1], typs[81], typs[28]), params(typs[3], typs[6]))
typs[94] = newSig(params(typs[1], typs[81], typs[3], typs[1]), params(typs[3], typs[6]))
typs[95] = newSig(params(typs[1], typs[81], typs[7]), params(typs[3]))
typs[96] = newSig(params(typs[1], typs[81], typs[3]), nil)
typs[97] = newSig(params(typs[1], typs[81], typs[65]), nil)
typs[98] = newSig(params(typs[1], typs[81], typs[24]), nil)
typs[99] = newSig(params(typs[1], typs[81], typs[28]), nil)
typs[100] = newSig(params(typs[3]), nil)
typs[101] = newSig(params(typs[1], typs[81]), nil)
typs[102] = types.NewChan(typs[2], types.Cboth)
typs[103] = newSig(params(typs[1], typs[22]), params(typs[102]))
typs[104] = newSig(params(typs[1], typs[15]), params(typs[102]))
typs[105] = types.NewChan(typs[2], types.Crecv)
typs[106] = newSig(params(typs[105], typs[3]), nil)
typs[107] = newSig(params(typs[105], typs[3]), params(typs[6]))
typs[108] = types.NewChan(typs[2], types.Csend)
typs[109] = newSig(params(typs[108], typs[3]), nil)
typs[110] = newSig(params(typs[108]), nil)
typs[111] = newSig(params(typs[2]), params(typs[15]))
typs[112] = types.NewArray(typs[0], 3)
typs[113] = types.NewStruct([]*types.Field{types.NewField(src.NoXPos, Lookup("enabled"), typs[6]), types.NewField(src.NoXPos, Lookup("pad"), typs[112]), types.NewField(src.NoXPos, Lookup("cgo"), typs[6]), types.NewField(src.NoXPos, Lookup("alignme"), typs[24])})
typs[114] = newSig(params(typs[1], typs[3], typs[3]), nil)
typs[115] = newSig(params(typs[1], typs[3]), nil)
typs[116] = newSig(params(typs[1], typs[3], typs[15], typs[3], typs[15]), params(typs[15]))
typs[117] = newSig(params(typs[108], typs[3]), params(typs[6]))
typs[118] = newSig(params(typs[3], typs[105]), params(typs[6], typs[6]))
typs[119] = newSig(params(typs[76]), nil)
typs[120] = newSig(params(typs[1], typs[1], typs[76], typs[15], typs[15], typs[6]), params(typs[15], typs[6]))
typs[121] = newSig(params(typs[1], typs[15], typs[15]), params(typs[7]))
typs[122] = newSig(params(typs[1], typs[22], typs[22]), params(typs[7]))
typs[123] = newSig(params(typs[1], typs[15], typs[15], typs[7]), params(typs[7]))
typs[124] = types.NewSlice(typs[2])
typs[125] = newSig(params(typs[3], typs[15], typs[15], typs[15], typs[1]), params(typs[124]))
typs[126] = newSig(params(typs[1], typs[7], typs[22]), nil)
typs[127] = newSig(params(typs[7], typs[22]), nil)
typs[128] = newSig(params(typs[3], typs[3], typs[5]), nil)
typs[129] = newSig(params(typs[7], typs[5]), nil)
typs[130] = newSig(params(typs[3], typs[3], typs[5]), params(typs[6]))
typs[131] = newSig(params(typs[3], typs[3]), params(typs[6]))
typs[132] = newSig(params(typs[7], typs[7]), params(typs[6]))
typs[133] = newSig(params(typs[3], typs[5], typs[5]), params(typs[5]))
typs[134] = newSig(params(typs[7], typs[5]), params(typs[5]))
typs[135] = newSig(params(typs[3], typs[5]), params(typs[5]))
typs[136] = newSig(params(typs[22], typs[22]), params(typs[22]))
typs[137] = newSig(params(typs[24], typs[24]), params(typs[24]))
typs[138] = newSig(params(typs[20]), params(typs[22]))
typs[139] = newSig(params(typs[20]), params(typs[24]))
typs[140] = newSig(params(typs[20]), params(typs[65]))
typs[141] = newSig(params(typs[22]), params(typs[20]))
typs[142] = types.Types[types.TFLOAT32]
typs[143] = newSig(params(typs[22]), params(typs[142]))
typs[144] = newSig(params(typs[24]), params(typs[20]))
typs[145] = newSig(params(typs[24]), params(typs[142]))
typs[146] = newSig(params(typs[65]), params(typs[20]))
typs[147] = newSig(params(typs[26], typs[26]), params(typs[26]))
typs[148] = newSig(params(typs[5], typs[5]), nil)
typs[149] = newSig(params(typs[5], typs[5], typs[5]), nil)
typs[150] = newSig(params(typs[7], typs[1], typs[5]), nil)
typs[151] = types.NewSlice(typs[7])
typs[152] = newSig(params(typs[7], typs[151]), nil)
typs[153] = newSig(params(typs[69], typs[69], typs[17]), nil)
typs[154] = newSig(params(typs[63], typs[63], typs[17]), nil)
typs[155] = newSig(params(typs[65], typs[65], typs[17]), nil)
typs[156] = newSig(params(typs[24], typs[24], typs[17]), nil)
typs[157] = newSig(params(typs[28], typs[28], typs[17]), nil)
typs[158] = types.NewArray(typs[0], 16)
typs[159] = newSig(params(typs[7], typs[65], typs[158], typs[28], typs[15], typs[69], typs[69]), params(typs[65]))
typs[80] = newSig(nil, params(typs[24]))
typs[81] = newSig(nil, params(typs[65]))
typs[82] = types.NewMap(typs[2], typs[2])
typs[83] = newSig(params(typs[1], typs[22], typs[3]), params(typs[82]))
typs[84] = newSig(params(typs[1], typs[15], typs[3]), params(typs[82]))
typs[85] = newSig(nil, params(typs[82]))
typs[86] = newSig(params(typs[1], typs[82], typs[3]), params(typs[3]))
typs[87] = newSig(params(typs[1], typs[82], typs[65]), params(typs[3]))
typs[88] = newSig(params(typs[1], typs[82], typs[24]), params(typs[3]))
typs[89] = newSig(params(typs[1], typs[82], typs[28]), params(typs[3]))
typs[90] = newSig(params(typs[1], typs[82], typs[3], typs[1]), params(typs[3]))
typs[91] = newSig(params(typs[1], typs[82], typs[3]), params(typs[3], typs[6]))
typs[92] = newSig(params(typs[1], typs[82], typs[65]), params(typs[3], typs[6]))
typs[93] = newSig(params(typs[1], typs[82], typs[24]), params(typs[3], typs[6]))
typs[94] = newSig(params(typs[1], typs[82], typs[28]), params(typs[3], typs[6]))
typs[95] = newSig(params(typs[1], typs[82], typs[3], typs[1]), params(typs[3], typs[6]))
typs[96] = newSig(params(typs[1], typs[82], typs[7]), params(typs[3]))
typs[97] = newSig(params(typs[1], typs[82], typs[3]), nil)
typs[98] = newSig(params(typs[1], typs[82], typs[65]), nil)
typs[99] = newSig(params(typs[1], typs[82], typs[24]), nil)
typs[100] = newSig(params(typs[1], typs[82], typs[28]), nil)
typs[101] = newSig(params(typs[3]), nil)
typs[102] = newSig(params(typs[1], typs[82]), nil)
typs[103] = types.NewChan(typs[2], types.Cboth)
typs[104] = newSig(params(typs[1], typs[22]), params(typs[103]))
typs[105] = newSig(params(typs[1], typs[15]), params(typs[103]))
typs[106] = types.NewChan(typs[2], types.Crecv)
typs[107] = newSig(params(typs[106], typs[3]), nil)
typs[108] = newSig(params(typs[106], typs[3]), params(typs[6]))
typs[109] = types.NewChan(typs[2], types.Csend)
typs[110] = newSig(params(typs[109], typs[3]), nil)
typs[111] = newSig(params(typs[109]), nil)
typs[112] = newSig(params(typs[2]), params(typs[15]))
typs[113] = types.NewArray(typs[0], 3)
typs[114] = types.NewStruct([]*types.Field{types.NewField(src.NoXPos, Lookup("enabled"), typs[6]), types.NewField(src.NoXPos, Lookup("pad"), typs[113]), types.NewField(src.NoXPos, Lookup("cgo"), typs[6]), types.NewField(src.NoXPos, Lookup("alignme"), typs[24])})
typs[115] = newSig(params(typs[1], typs[3], typs[3]), nil)
typs[116] = newSig(params(typs[1], typs[3]), nil)
typs[117] = newSig(params(typs[1], typs[3], typs[15], typs[3], typs[15]), params(typs[15]))
typs[118] = newSig(params(typs[109], typs[3]), params(typs[6]))
typs[119] = newSig(params(typs[3], typs[106]), params(typs[6], typs[6]))
typs[120] = newSig(params(typs[76]), nil)
typs[121] = newSig(params(typs[1], typs[1], typs[76], typs[15], typs[15], typs[6]), params(typs[15], typs[6]))
typs[122] = newSig(params(typs[1], typs[15], typs[15]), params(typs[7]))
typs[123] = newSig(params(typs[1], typs[22], typs[22]), params(typs[7]))
typs[124] = newSig(params(typs[1], typs[15], typs[15], typs[7]), params(typs[7]))
typs[125] = types.NewSlice(typs[2])
typs[126] = newSig(params(typs[3], typs[15], typs[15], typs[15], typs[1]), params(typs[125]))
typs[127] = newSig(params(typs[1], typs[7], typs[22]), nil)
typs[128] = newSig(params(typs[7], typs[22]), nil)
typs[129] = newSig(params(typs[3], typs[3], typs[5]), nil)
typs[130] = newSig(params(typs[7], typs[5]), nil)
typs[131] = newSig(params(typs[3], typs[3], typs[5]), params(typs[6]))
typs[132] = newSig(params(typs[3], typs[3]), params(typs[6]))
typs[133] = newSig(params(typs[7], typs[7]), params(typs[6]))
typs[134] = newSig(params(typs[3], typs[5], typs[5]), params(typs[5]))
typs[135] = newSig(params(typs[7], typs[5]), params(typs[5]))
typs[136] = newSig(params(typs[3], typs[5]), params(typs[5]))
typs[137] = newSig(params(typs[22], typs[22]), params(typs[22]))
typs[138] = newSig(params(typs[24], typs[24]), params(typs[24]))
typs[139] = newSig(params(typs[20]), params(typs[22]))
typs[140] = newSig(params(typs[20]), params(typs[24]))
typs[141] = newSig(params(typs[20]), params(typs[65]))
typs[142] = newSig(params(typs[22]), params(typs[20]))
typs[143] = types.Types[types.TFLOAT32]
typs[144] = newSig(params(typs[22]), params(typs[143]))
typs[145] = newSig(params(typs[24]), params(typs[20]))
typs[146] = newSig(params(typs[24]), params(typs[143]))
typs[147] = newSig(params(typs[65]), params(typs[20]))
typs[148] = newSig(params(typs[26], typs[26]), params(typs[26]))
typs[149] = newSig(params(typs[5], typs[5]), nil)
typs[150] = newSig(params(typs[5], typs[5], typs[5]), nil)
typs[151] = newSig(params(typs[7], typs[1], typs[5]), nil)
typs[152] = types.NewSlice(typs[7])
typs[153] = newSig(params(typs[7], typs[152]), nil)
typs[154] = newSig(params(typs[69], typs[69], typs[17]), nil)
typs[155] = newSig(params(typs[63], typs[63], typs[17]), nil)
typs[156] = newSig(params(typs[65], typs[65], typs[17]), nil)
typs[157] = newSig(params(typs[24], typs[24], typs[17]), nil)
typs[158] = newSig(params(typs[28], typs[28], typs[17]), nil)
typs[159] = types.NewArray(typs[0], 16)
typs[160] = newSig(params(typs[7], typs[65], typs[159], typs[28], typs[15], typs[69], typs[69]), params(typs[65]))
return typs[:]
}

View File

@ -320,22 +320,90 @@ func walkMakeMap(n *ir.MakeExpr, init *ir.Nodes) ir.Node {
func walkMakeSwissMap(n *ir.MakeExpr, init *ir.Nodes) ir.Node {
t := n.Type()
hmapType := reflectdata.SwissMapType()
mapType := reflectdata.SwissMapType()
hint := n.Len
// var h *hmap
var h ir.Node
// var m *Map
var m ir.Node
if n.Esc() == ir.EscNone {
// Allocate hmap on stack.
// var hv hmap
// h = &hv
h = stackTempAddr(init, hmapType)
// var mv Map
// m = &mv
m = stackTempAddr(init, mapType)
// TODO(go.dev/issue/54766): Stack allocated table/groups.
} else {
h = typecheck.NodNil()
// Allocate one group pointed to by m.dirPtr on stack if hint
// is not larger than SwissMapGroupSlots. In case hint is
// larger, runtime.makemap will allocate on the heap.
// Maximum key and elem size is 128 bytes, larger objects
// are stored with an indirection. So max bucket size is 2048+eps.
if !ir.IsConst(hint, constant.Int) ||
constant.Compare(hint.Val(), token.LEQ, constant.MakeInt64(abi.SwissMapGroupSlots)) {
// In case hint is larger than SwissMapGroupSlots
// runtime.makemap will allocate on the heap, see
// #20184
//
// if hint <= abi.SwissMapGroupSlots {
// var gv group
// g = &gv
// g.ctrl = abi.SwissMapCtrlEmpty
// m.dirPtr = g
// }
nif := ir.NewIfStmt(base.Pos, ir.NewBinaryExpr(base.Pos, ir.OLE, hint, ir.NewInt(base.Pos, abi.SwissMapGroupSlots)), nil, nil)
nif.Likely = true
groupType := reflectdata.SwissMapGroupType(t)
// var gv group
// g = &gv
g := stackTempAddr(&nif.Body, groupType)
// Can't use ir.NewInt because bit 63 is set, which
// makes conversion to uint64 upset.
empty := ir.NewBasicLit(base.Pos, types.UntypedInt, constant.MakeUint64(abi.SwissMapCtrlEmpty))
// g.ctrl = abi.SwissMapCtrlEmpty
csym := groupType.Field(0).Sym // g.ctrl see reflectdata/map_swiss.go
ca := ir.NewAssignStmt(base.Pos, ir.NewSelectorExpr(base.Pos, ir.ODOT, g, csym), empty)
nif.Body.Append(ca)
// m.dirPtr = g
dsym := mapType.Field(2).Sym // m.dirPtr see reflectdata/map_swiss.go
na := ir.NewAssignStmt(base.Pos, ir.NewSelectorExpr(base.Pos, ir.ODOT, m, dsym), typecheck.ConvNop(g, types.Types[types.TUNSAFEPTR]))
nif.Body.Append(na)
appendWalkStmt(init, nif)
}
}
if ir.IsConst(hint, constant.Int) && constant.Compare(hint.Val(), token.LEQ, constant.MakeInt64(abi.SwissMapGroupSlots)) {
// Handling make(map[any]any) and
// make(map[any]any, hint) where hint <= abi.SwissMapGroupSlots
// specially allows for faster map initialization and
// improves binary size by using calls with fewer arguments.
// For hint <= abi.SwissMapGroupSlots no groups will be
// allocated by makemap. Therefore, no groups need to be
// allocated in this code path.
if n.Esc() == ir.EscNone {
// Only need to initialize m.seed since
// m map has been allocated on the stack already.
// m.seed = uintptr(rand())
rand := mkcall("rand", types.Types[types.TUINT64], init)
seedSym := mapType.Field(1).Sym // m.seed see reflectdata/map_swiss.go
appendWalkStmt(init, ir.NewAssignStmt(base.Pos, ir.NewSelectorExpr(base.Pos, ir.ODOT, m, seedSym), typecheck.Conv(rand, types.Types[types.TUINTPTR])))
return typecheck.ConvNop(m, t)
}
// Call runtime.makemap_small to allocate a
// map on the heap and initialize the map's seed field.
fn := typecheck.LookupRuntime("makemap_small", t.Key(), t.Elem())
return mkcall1(fn, n.Type(), init)
}
if n.Esc() != ir.EscNone {
m = typecheck.NodNil()
}
// Map initialization with a variable or large hint is
// more complicated. We therefore generate a call to
// runtime.makemap to initialize hmap and allocate the
@ -355,8 +423,8 @@ func walkMakeSwissMap(n *ir.MakeExpr, init *ir.Nodes) ir.Node {
argtype = types.Types[types.TINT]
}
fn := typecheck.LookupRuntime(fnname, hmapType, t.Key(), t.Elem())
return mkcall1(fn, n.Type(), init, reflectdata.MakeMapRType(base.Pos, n), typecheck.Conv(hint, argtype), h)
fn := typecheck.LookupRuntime(fnname, mapType, t.Key(), t.Elem())
return mkcall1(fn, n.Type(), init, reflectdata.MakeMapRType(base.Pos, n), typecheck.Conv(hint, argtype), m)
}
func walkMakeOldMap(n *ir.MakeExpr, init *ir.Nodes) ir.Node {
@ -422,7 +490,7 @@ func walkMakeOldMap(n *ir.MakeExpr, init *ir.Nodes) ir.Node {
appendWalkStmt(init, ir.NewAssignStmt(base.Pos, ir.NewSelectorExpr(base.Pos, ir.ODOT, h, hashsym), rand))
return typecheck.ConvNop(h, t)
}
// Call runtime.makehmap to allocate an
// Call runtime.makemap_small to allocate an
// hmap on the heap and initialize hmap's hash0 field.
fn := typecheck.LookupRuntime("makemap_small", t.Key(), t.Elem())
return mkcall1(fn, n.Type(), init)

View File

@ -21,6 +21,12 @@ const (
// Must fit in a uint8.
SwissMapMaxKeyBytes = 128
SwissMapMaxElemBytes = 128
ctrlEmpty = 0b10000000
bitsetLSB = 0x0101010101010101
// Value of control word with all empty slots.
SwissMapCtrlEmpty = bitsetLSB * uint64(ctrlEmpty)
)
type SwissMapType struct {

View File

@ -24,7 +24,7 @@ const maxAllocTest = 1 << 30
func NewTestMap[K comparable, V any](hint uintptr) (*Map, *abi.SwissMapType) {
mt := newTestMapType[K, V]()
return NewMap(mt, hint, maxAllocTest), mt
return NewMap(mt, hint, nil, maxAllocTest), mt
}
func (m *Map) TableCount() int {

View File

@ -246,71 +246,82 @@ func depthToShift(depth uint8) uint8 {
return 64 - depth
}
// If m is non-nil, it should be used rather than allocating.
//
// maxAlloc should be runtime.maxAlloc.
//
// TODO(prattmic): Put maxAlloc somewhere accessible.
func NewMap(mt *abi.SwissMapType, hint, maxAlloc uintptr) *Map {
func NewMap(mt *abi.SwissMapType, hint uintptr, m *Map, maxAlloc uintptr) *Map {
if m == nil {
m = new(Map)
}
m.seed = uintptr(rand())
if hint <= abi.SwissMapGroupSlots {
// A small map can fill all 8 slots, so no need to increase
// target capacity.
//
// In fact, since an 8 slot group is what the first assignment
// to an empty map would allocate anyway, it doesn't matter if
// we allocate here or on the first assignment.
//
// Thus we just return without allocating. (We'll save the
// allocation completely if no assignment comes.)
// Note that the compiler may have initialized m.dirPtr with a
// pointer to a stack-allocated group, in which case we already
// have a group. The control word is already initialized.
return m
}
// Full size map.
// Set initial capacity to hold hint entries without growing in the
// average case.
var targetCapacity uintptr
if hint <= abi.SwissMapGroupSlots {
// Small map can fill all 8 slots. We set the target to 0 here
// because an 8 slot small map is what the first assignment to
// an empty map will allocate anyway. Whether we allocate here
// or in the first assignment makes no difference. And if there
// is a chance that the caller won't write at all then it is
// better to delay.
targetCapacity = 0
} else {
targetCapacity = (hint * abi.SwissMapGroupSlots) / maxAvgGroupLoad
if targetCapacity < hint { // overflow
targetCapacity = 0
}
targetCapacity := (hint * abi.SwissMapGroupSlots) / maxAvgGroupLoad
if targetCapacity < hint { // overflow
return m // return an empty map.
}
dirSize := (uint64(targetCapacity) + maxTableCapacity - 1) / maxTableCapacity
dirSize, overflow := alignUpPow2(dirSize)
if overflow || dirSize > uint64(math.MaxUintptr) {
targetCapacity = 0
return m // return an empty map.
}
// Reject hints that are obviously too large.
groups, overflow := math.MulUintptr(uintptr(dirSize), maxTableCapacity)
if overflow {
targetCapacity = 0
return m // return an empty map.
} else {
mem, overflow := math.MulUintptr(groups, mt.Group.Size_)
if overflow || mem > maxAlloc {
targetCapacity = 0
return m // return an empty map.
}
}
globalDepth := uint8(sys.TrailingZeros64(dirSize))
if targetCapacity == 0 {
// TrailingZeros64 returns 64 for 0.
globalDepth = 0
m.globalDepth = uint8(sys.TrailingZeros64(dirSize))
m.globalShift = depthToShift(m.globalDepth)
directory := make([]*table, dirSize)
for i := range directory {
// TODO: Think more about initial table capacity.
directory[i] = newTable(mt, uint64(targetCapacity)/dirSize, i, m.globalDepth)
}
m := &Map{
seed: uintptr(rand()),
m.dirPtr = unsafe.Pointer(&directory[0])
m.dirLen = len(directory)
globalDepth: globalDepth,
globalShift: depthToShift(globalDepth),
}
if targetCapacity > 0 {
// Full map.
directory := make([]*table, dirSize)
for i := range directory {
// TODO: Think more about initial table capacity.
directory[i] = newTable(mt, uint64(targetCapacity)/dirSize, i, globalDepth)
}
m.dirPtr = unsafe.Pointer(&directory[0])
m.dirLen = len(directory)
}
return m
}
func NewEmptyMap() *Map {
m := new(Map)
m.seed = uintptr(rand())
// See comment in NewMap. No need to eager allocate a group.
return m
}
@ -623,6 +634,9 @@ func (m *Map) growToTable(typ *abi.SwissMapType) {
m.dirPtr = unsafe.Pointer(&directory[0])
m.dirLen = len(directory)
m.globalDepth = 0
m.globalShift = depthToShift(m.globalDepth)
}
func (m *Map) Delete(typ *abi.SwissMapType, key unsafe.Pointer) {

View File

@ -37,24 +37,23 @@ func makemap64(t *abi.SwissMapType, hint int64, m *maps.Map) *maps.Map {
}
// makemap_small implements Go map creation for make(map[k]v) and
// make(map[k]v, hint) when hint is known to be at most bucketCnt
// make(map[k]v, hint) when hint is known to be at most abi.SwissMapGroupSlots
// at compile time and the map needs to be allocated on the heap.
func makemap_small() *maps.Map {
panic("unimplemented")
return maps.NewEmptyMap()
}
// makemap implements Go map creation for make(map[k]v, hint).
// If the compiler has determined that the map or the first bucket
// can be created on the stack, h and/or bucket may be non-nil.
// If h != nil, the map can be created directly in h.
// If h.buckets != nil, bucket pointed to can be used as the first bucket.
// If the compiler has determined that the map or the first group
// can be created on the stack, m and optionally m.dirPtr may be non-nil.
// If m != nil, the map can be created directly in m.
// If m.dirPtr != nil, it points to a group usable for a small map.
func makemap(t *abi.SwissMapType, hint int, m *maps.Map) *maps.Map {
if hint < 0 {
hint = 0
}
// TODO: use existing m
return maps.NewMap(t, uintptr(hint), maxAlloc)
return maps.NewMap(t, uintptr(hint), m, maxAlloc)
}
// mapaccess1 returns a pointer to h[key]. Never returns nil, instead

View File

@ -659,6 +659,16 @@ func newT40() *T40 {
return &ret
}
func good40() {
ret := T40{} // ERROR "stack object ret T40$"
ret.m = make(map[int]int) // ERROR "live at call to rand(32)?: .autotmp_[0-9]+$" "stack object .autotmp_[0-9]+ (runtime.hmap|internal/runtime/maps.Map)$"
t := &ret
printnl() // ERROR "live at call to printnl: ret$"
// Note: ret is live at the printnl because the compiler moves &ret
// from before the printnl to after.
useT40(t)
}
func bad40() {
t := newT40()
_ = t

View File

@ -1,32 +0,0 @@
// errorcheckwithauto -0 -l -live -wb=0 -d=ssa/insert_resched_checks/off
//go:build !goexperiment.swissmap && !goexperiment.regabiargs
// For register ABI, liveness info changes slightly. See live_regabi.go.
// Copyright 2024 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// non-swissmap-specific tests for live.go
package main
func printnl()
type T40 struct {
m map[int]int
}
//go:noescape
func useT40(*T40)
func good40() {
ret := T40{} // ERROR "stack object ret T40$"
ret.m = make(map[int]int) // ERROR "live at call to rand32: .autotmp_[0-9]+$" "stack object .autotmp_[0-9]+ runtime.hmap$"
t := &ret
printnl() // ERROR "live at call to printnl: ret$"
// Note: ret is live at the printnl because the compiler moves &ret
// from before the printnl to after.
useT40(t)
}

View File

@ -657,6 +657,16 @@ func newT40() *T40 {
return &ret
}
func good40() {
ret := T40{} // ERROR "stack object ret T40$"
ret.m = make(map[int]int) // ERROR "live at call to rand(32)?: .autotmp_[0-9]+$" "stack object .autotmp_[0-9]+ (runtime.hmap|internal/runtime/maps.Map)$"
t := &ret
printnl() // ERROR "live at call to printnl: ret$"
// Note: ret is live at the printnl because the compiler moves &ret
// from before the printnl to after.
useT40(t)
}
func bad40() {
t := newT40()
_ = t

View File

@ -1,31 +0,0 @@
// errorcheckwithauto -0 -l -live -wb=0 -d=ssa/insert_resched_checks/off
//go:build !goexperiment.swissmap && ((amd64 && goexperiment.regabiargs) || (arm64 && goexperiment.regabiargs))
// Copyright 2024 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// non-swissmap-specific tests for live_regabi.go
// TODO(#54766): temporary while fast variants are disabled.
package main
func printnl()
type T40 struct {
m map[int]int
}
//go:noescape
func useT40(*T40)
func good40() {
ret := T40{} // ERROR "stack object ret T40$"
ret.m = make(map[int]int) // ERROR "live at call to rand32: .autotmp_[0-9]+$" "stack object .autotmp_[0-9]+ runtime.hmap$"
t := &ret
printnl() // ERROR "live at call to printnl: ret$"
// Note: ret is live at the printnl because the compiler moves &ret
// from before the printnl to after.
useT40(t)
}

View File

@ -1,31 +0,0 @@
// errorcheckwithauto -0 -l -live -wb=0 -d=ssa/insert_resched_checks/off
//go:build goexperiment.swissmap && ((amd64 && goexperiment.regabiargs) || (arm64 && goexperiment.regabiargs))
// Copyright 2024 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// swissmap-specific tests for live_regabi.go
// TODO(#54766): temporary while fast variants are disabled.
package main
func printnl()
type T40 struct {
m map[int]int
}
//go:noescape
func useT40(*T40)
func good40() {
ret := T40{} // ERROR "stack object ret T40$"
ret.m = make(map[int]int) // ERROR "stack object .autotmp_[0-9]+ internal/runtime/maps.Map$"
t := &ret
printnl() // ERROR "live at call to printnl: ret$"
// Note: ret is live at the printnl because the compiler moves &ret
// from before the printnl to after.
useT40(t)
}

View File

@ -1,32 +0,0 @@
// errorcheckwithauto -0 -l -live -wb=0 -d=ssa/insert_resched_checks/off
//go:build goexperiment.swissmap && !goexperiment.regabiargs
// For register ABI, liveness info changes slightly. See live_regabi.go.
// Copyright 2024 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// swissmap-specific tests for live.go
package main
func printnl()
type T40 struct {
m map[int]int
}
//go:noescape
func useT40(*T40)
func good40() {
ret := T40{} // ERROR "stack object ret T40$"
ret.m = make(map[int]int) // ERROR "stack object .autotmp_[0-9]+ internal/runtime/maps.Map$"
t := &ret
printnl() // ERROR "live at call to printnl: ret$"
// Note: ret is live at the printnl because the compiler moves &ret
// from before the printnl to after.
useT40(t)
}