1
0
mirror of https://github.com/golang/go synced 2024-07-01 07:56:09 +00:00

cmd/compile: optimize make+copy pattern to avoid memclr

match:
 m = make([]T, x); copy(m, s)
for pointer free T and x==len(s) rewrite to:
 m = mallocgc(x*elemsize(T), nil, false); memmove(&m, &s, x*elemsize(T))
otherwise rewrite to:
 m = makeslicecopy([]T, x, s)

This avoids memclear and shading of pointers in the newly created slice
before the copy.

With this CL "s" is only be allowed to bev a variable and not a more
complex expression. This restriction could be lifted in future versions
of this optimization when it can be proven that "s" is not referencing "m".

Triggers 450 times during make.bash..
Reduces go binary size by ~8 kbyte.

name                           old time/op  new time/op  delta
MakeSliceCopy/mallocmove/Byte  71.1ns ± 1%  65.8ns ± 0%  -7.49%  (p=0.000 n=10+9)
MakeSliceCopy/mallocmove/Int   71.2ns ± 1%  66.0ns ± 0%  -7.27%  (p=0.000 n=10+8)
MakeSliceCopy/mallocmove/Ptr    104ns ± 4%    99ns ± 1%  -5.13%  (p=0.000 n=10+10)
MakeSliceCopy/makecopy/Byte    70.3ns ± 0%  68.0ns ± 0%  -3.22%  (p=0.000 n=10+9)
MakeSliceCopy/makecopy/Int     70.3ns ± 0%  68.5ns ± 1%  -2.59%  (p=0.000 n=9+10)
MakeSliceCopy/makecopy/Ptr      102ns ± 0%    99ns ± 1%  -2.97%  (p=0.000 n=9+9)
MakeSliceCopy/nilappend/Byte   75.4ns ± 0%  74.9ns ± 2%  -0.63%  (p=0.015 n=9+9)
MakeSliceCopy/nilappend/Int    75.6ns ± 0%  76.4ns ± 3%    ~     (p=0.245 n=9+10)
MakeSliceCopy/nilappend/Ptr     107ns ± 0%   108ns ± 1%  +0.93%  (p=0.005 n=9+10)

Fixes #26252

Change-Id: Iec553dd1fef6ded16197216a472351c8799a8e71
Reviewed-on: https://go-review.googlesource.com/c/go/+/146719
Reviewed-by: Keith Randall <khr@golang.org>
Run-TryBot: Martin Möhrmann <moehrmann@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
Martin Möhrmann 2018-10-23 13:50:07 +02:00
parent 97240d546c
commit 6ed4661807
12 changed files with 1160 additions and 503 deletions

View File

@ -10,325 +10,329 @@ var runtimeDecls = [...]struct {
typ int
}{
{"newobject", funcTag, 4},
{"panicdivide", funcTag, 5},
{"panicshift", funcTag, 5},
{"panicmakeslicelen", funcTag, 5},
{"panicmakeslicecap", funcTag, 5},
{"throwinit", funcTag, 5},
{"panicwrap", funcTag, 5},
{"gopanic", funcTag, 7},
{"gorecover", funcTag, 10},
{"goschedguarded", funcTag, 5},
{"goPanicIndex", funcTag, 12},
{"goPanicIndexU", funcTag, 14},
{"goPanicSliceAlen", funcTag, 12},
{"goPanicSliceAlenU", funcTag, 14},
{"goPanicSliceAcap", funcTag, 12},
{"goPanicSliceAcapU", funcTag, 14},
{"goPanicSliceB", funcTag, 12},
{"goPanicSliceBU", funcTag, 14},
{"goPanicSlice3Alen", funcTag, 12},
{"goPanicSlice3AlenU", funcTag, 14},
{"goPanicSlice3Acap", funcTag, 12},
{"goPanicSlice3AcapU", funcTag, 14},
{"goPanicSlice3B", funcTag, 12},
{"goPanicSlice3BU", funcTag, 14},
{"goPanicSlice3C", funcTag, 12},
{"goPanicSlice3CU", funcTag, 14},
{"printbool", funcTag, 16},
{"printfloat", funcTag, 18},
{"printint", funcTag, 20},
{"printhex", funcTag, 22},
{"printuint", funcTag, 22},
{"printcomplex", funcTag, 24},
{"printstring", funcTag, 26},
{"printpointer", funcTag, 27},
{"printiface", funcTag, 27},
{"printeface", funcTag, 27},
{"printslice", funcTag, 27},
{"printnl", funcTag, 5},
{"printsp", funcTag, 5},
{"printlock", funcTag, 5},
{"printunlock", funcTag, 5},
{"concatstring2", funcTag, 30},
{"concatstring3", funcTag, 31},
{"concatstring4", funcTag, 32},
{"concatstring5", funcTag, 33},
{"concatstrings", funcTag, 35},
{"cmpstring", funcTag, 36},
{"intstring", funcTag, 39},
{"slicebytetostring", funcTag, 40},
{"slicebytetostringtmp", funcTag, 41},
{"slicerunetostring", funcTag, 44},
{"stringtoslicebyte", funcTag, 46},
{"stringtoslicerune", funcTag, 49},
{"slicecopy", funcTag, 51},
{"slicestringcopy", funcTag, 52},
{"decoderune", funcTag, 53},
{"countrunes", funcTag, 54},
{"convI2I", funcTag, 55},
{"convT16", funcTag, 57},
{"convT32", funcTag, 57},
{"convT64", funcTag, 57},
{"convTstring", funcTag, 57},
{"convTslice", funcTag, 57},
{"convT2E", funcTag, 58},
{"convT2Enoptr", funcTag, 58},
{"convT2I", funcTag, 58},
{"convT2Inoptr", funcTag, 58},
{"assertE2I", funcTag, 55},
{"assertE2I2", funcTag, 59},
{"assertI2I", funcTag, 55},
{"assertI2I2", funcTag, 59},
{"panicdottypeE", funcTag, 60},
{"panicdottypeI", funcTag, 60},
{"panicnildottype", funcTag, 61},
{"ifaceeq", funcTag, 63},
{"efaceeq", funcTag, 63},
{"fastrand", funcTag, 65},
{"makemap64", funcTag, 67},
{"makemap", funcTag, 68},
{"makemap_small", funcTag, 69},
{"mapaccess1", funcTag, 70},
{"mapaccess1_fast32", funcTag, 71},
{"mapaccess1_fast64", funcTag, 71},
{"mapaccess1_faststr", funcTag, 71},
{"mapaccess1_fat", funcTag, 72},
{"mapaccess2", funcTag, 73},
{"mapaccess2_fast32", funcTag, 74},
{"mapaccess2_fast64", funcTag, 74},
{"mapaccess2_faststr", funcTag, 74},
{"mapaccess2_fat", funcTag, 75},
{"mapassign", funcTag, 70},
{"mapassign_fast32", funcTag, 71},
{"mapassign_fast32ptr", funcTag, 71},
{"mapassign_fast64", funcTag, 71},
{"mapassign_fast64ptr", funcTag, 71},
{"mapassign_faststr", funcTag, 71},
{"mapiterinit", funcTag, 76},
{"mapdelete", funcTag, 76},
{"mapdelete_fast32", funcTag, 77},
{"mapdelete_fast64", funcTag, 77},
{"mapdelete_faststr", funcTag, 77},
{"mapiternext", funcTag, 78},
{"mapclear", funcTag, 79},
{"makechan64", funcTag, 81},
{"makechan", funcTag, 82},
{"chanrecv1", funcTag, 84},
{"chanrecv2", funcTag, 85},
{"chansend1", funcTag, 87},
{"closechan", funcTag, 27},
{"writeBarrier", varTag, 89},
{"typedmemmove", funcTag, 90},
{"typedmemclr", funcTag, 91},
{"typedslicecopy", funcTag, 92},
{"selectnbsend", funcTag, 93},
{"selectnbrecv", funcTag, 94},
{"selectnbrecv2", funcTag, 96},
{"selectsetpc", funcTag, 61},
{"selectgo", funcTag, 97},
{"block", funcTag, 5},
{"makeslice", funcTag, 98},
{"makeslice64", funcTag, 99},
{"growslice", funcTag, 101},
{"memmove", funcTag, 102},
{"memclrNoHeapPointers", funcTag, 103},
{"memclrHasPointers", funcTag, 103},
{"memequal", funcTag, 104},
{"memequal0", funcTag, 105},
{"memequal8", funcTag, 105},
{"memequal16", funcTag, 105},
{"memequal32", funcTag, 105},
{"memequal64", funcTag, 105},
{"memequal128", funcTag, 105},
{"f32equal", funcTag, 106},
{"f64equal", funcTag, 106},
{"c64equal", funcTag, 106},
{"c128equal", funcTag, 106},
{"strequal", funcTag, 106},
{"interequal", funcTag, 106},
{"nilinterequal", funcTag, 106},
{"memhash", funcTag, 107},
{"memhash0", funcTag, 108},
{"memhash8", funcTag, 108},
{"memhash16", funcTag, 108},
{"memhash32", funcTag, 108},
{"memhash64", funcTag, 108},
{"memhash128", funcTag, 108},
{"f32hash", funcTag, 108},
{"f64hash", funcTag, 108},
{"c64hash", funcTag, 108},
{"c128hash", funcTag, 108},
{"strhash", funcTag, 108},
{"interhash", funcTag, 108},
{"nilinterhash", funcTag, 108},
{"int64div", funcTag, 109},
{"uint64div", funcTag, 110},
{"int64mod", funcTag, 109},
{"uint64mod", funcTag, 110},
{"float64toint64", funcTag, 111},
{"float64touint64", funcTag, 112},
{"float64touint32", funcTag, 113},
{"int64tofloat64", funcTag, 114},
{"uint64tofloat64", funcTag, 115},
{"uint32tofloat64", funcTag, 116},
{"complex128div", funcTag, 117},
{"racefuncenter", funcTag, 118},
{"racefuncenterfp", funcTag, 5},
{"racefuncexit", funcTag, 5},
{"raceread", funcTag, 118},
{"racewrite", funcTag, 118},
{"racereadrange", funcTag, 119},
{"racewriterange", funcTag, 119},
{"msanread", funcTag, 119},
{"msanwrite", funcTag, 119},
{"checkptrAlignment", funcTag, 120},
{"checkptrArithmetic", funcTag, 122},
{"libfuzzerTraceCmp1", funcTag, 124},
{"libfuzzerTraceCmp2", funcTag, 126},
{"libfuzzerTraceCmp4", funcTag, 127},
{"libfuzzerTraceCmp8", funcTag, 128},
{"libfuzzerTraceConstCmp1", funcTag, 124},
{"libfuzzerTraceConstCmp2", funcTag, 126},
{"libfuzzerTraceConstCmp4", funcTag, 127},
{"libfuzzerTraceConstCmp8", funcTag, 128},
{"x86HasPOPCNT", varTag, 15},
{"x86HasSSE41", varTag, 15},
{"x86HasFMA", varTag, 15},
{"armHasVFPv4", varTag, 15},
{"arm64HasATOMICS", varTag, 15},
{"mallocgc", funcTag, 8},
{"panicdivide", funcTag, 9},
{"panicshift", funcTag, 9},
{"panicmakeslicelen", funcTag, 9},
{"panicmakeslicecap", funcTag, 9},
{"throwinit", funcTag, 9},
{"panicwrap", funcTag, 9},
{"gopanic", funcTag, 11},
{"gorecover", funcTag, 14},
{"goschedguarded", funcTag, 9},
{"goPanicIndex", funcTag, 16},
{"goPanicIndexU", funcTag, 18},
{"goPanicSliceAlen", funcTag, 16},
{"goPanicSliceAlenU", funcTag, 18},
{"goPanicSliceAcap", funcTag, 16},
{"goPanicSliceAcapU", funcTag, 18},
{"goPanicSliceB", funcTag, 16},
{"goPanicSliceBU", funcTag, 18},
{"goPanicSlice3Alen", funcTag, 16},
{"goPanicSlice3AlenU", funcTag, 18},
{"goPanicSlice3Acap", funcTag, 16},
{"goPanicSlice3AcapU", funcTag, 18},
{"goPanicSlice3B", funcTag, 16},
{"goPanicSlice3BU", funcTag, 18},
{"goPanicSlice3C", funcTag, 16},
{"goPanicSlice3CU", funcTag, 18},
{"printbool", funcTag, 19},
{"printfloat", funcTag, 21},
{"printint", funcTag, 23},
{"printhex", funcTag, 25},
{"printuint", funcTag, 25},
{"printcomplex", funcTag, 27},
{"printstring", funcTag, 29},
{"printpointer", funcTag, 30},
{"printiface", funcTag, 30},
{"printeface", funcTag, 30},
{"printslice", funcTag, 30},
{"printnl", funcTag, 9},
{"printsp", funcTag, 9},
{"printlock", funcTag, 9},
{"printunlock", funcTag, 9},
{"concatstring2", funcTag, 33},
{"concatstring3", funcTag, 34},
{"concatstring4", funcTag, 35},
{"concatstring5", funcTag, 36},
{"concatstrings", funcTag, 38},
{"cmpstring", funcTag, 39},
{"intstring", funcTag, 42},
{"slicebytetostring", funcTag, 43},
{"slicebytetostringtmp", funcTag, 44},
{"slicerunetostring", funcTag, 47},
{"stringtoslicebyte", funcTag, 49},
{"stringtoslicerune", funcTag, 52},
{"slicecopy", funcTag, 53},
{"slicestringcopy", funcTag, 54},
{"decoderune", funcTag, 55},
{"countrunes", funcTag, 56},
{"convI2I", funcTag, 57},
{"convT16", funcTag, 58},
{"convT32", funcTag, 58},
{"convT64", funcTag, 58},
{"convTstring", funcTag, 58},
{"convTslice", funcTag, 58},
{"convT2E", funcTag, 59},
{"convT2Enoptr", funcTag, 59},
{"convT2I", funcTag, 59},
{"convT2Inoptr", funcTag, 59},
{"assertE2I", funcTag, 57},
{"assertE2I2", funcTag, 60},
{"assertI2I", funcTag, 57},
{"assertI2I2", funcTag, 60},
{"panicdottypeE", funcTag, 61},
{"panicdottypeI", funcTag, 61},
{"panicnildottype", funcTag, 62},
{"ifaceeq", funcTag, 64},
{"efaceeq", funcTag, 64},
{"fastrand", funcTag, 66},
{"makemap64", funcTag, 68},
{"makemap", funcTag, 69},
{"makemap_small", funcTag, 70},
{"mapaccess1", funcTag, 71},
{"mapaccess1_fast32", funcTag, 72},
{"mapaccess1_fast64", funcTag, 72},
{"mapaccess1_faststr", funcTag, 72},
{"mapaccess1_fat", funcTag, 73},
{"mapaccess2", funcTag, 74},
{"mapaccess2_fast32", funcTag, 75},
{"mapaccess2_fast64", funcTag, 75},
{"mapaccess2_faststr", funcTag, 75},
{"mapaccess2_fat", funcTag, 76},
{"mapassign", funcTag, 71},
{"mapassign_fast32", funcTag, 72},
{"mapassign_fast32ptr", funcTag, 72},
{"mapassign_fast64", funcTag, 72},
{"mapassign_fast64ptr", funcTag, 72},
{"mapassign_faststr", funcTag, 72},
{"mapiterinit", funcTag, 77},
{"mapdelete", funcTag, 77},
{"mapdelete_fast32", funcTag, 78},
{"mapdelete_fast64", funcTag, 78},
{"mapdelete_faststr", funcTag, 78},
{"mapiternext", funcTag, 79},
{"mapclear", funcTag, 80},
{"makechan64", funcTag, 82},
{"makechan", funcTag, 83},
{"chanrecv1", funcTag, 85},
{"chanrecv2", funcTag, 86},
{"chansend1", funcTag, 88},
{"closechan", funcTag, 30},
{"writeBarrier", varTag, 90},
{"typedmemmove", funcTag, 91},
{"typedmemclr", funcTag, 92},
{"typedslicecopy", funcTag, 93},
{"selectnbsend", funcTag, 94},
{"selectnbrecv", funcTag, 95},
{"selectnbrecv2", funcTag, 97},
{"selectsetpc", funcTag, 62},
{"selectgo", funcTag, 98},
{"block", funcTag, 9},
{"makeslice", funcTag, 99},
{"makeslice64", funcTag, 100},
{"makeslicecopy", funcTag, 101},
{"growslice", funcTag, 103},
{"memmove", funcTag, 104},
{"memclrNoHeapPointers", funcTag, 105},
{"memclrHasPointers", funcTag, 105},
{"memequal", funcTag, 106},
{"memequal0", funcTag, 107},
{"memequal8", funcTag, 107},
{"memequal16", funcTag, 107},
{"memequal32", funcTag, 107},
{"memequal64", funcTag, 107},
{"memequal128", funcTag, 107},
{"f32equal", funcTag, 108},
{"f64equal", funcTag, 108},
{"c64equal", funcTag, 108},
{"c128equal", funcTag, 108},
{"strequal", funcTag, 108},
{"interequal", funcTag, 108},
{"nilinterequal", funcTag, 108},
{"memhash", funcTag, 109},
{"memhash0", funcTag, 110},
{"memhash8", funcTag, 110},
{"memhash16", funcTag, 110},
{"memhash32", funcTag, 110},
{"memhash64", funcTag, 110},
{"memhash128", funcTag, 110},
{"f32hash", funcTag, 110},
{"f64hash", funcTag, 110},
{"c64hash", funcTag, 110},
{"c128hash", funcTag, 110},
{"strhash", funcTag, 110},
{"interhash", funcTag, 110},
{"nilinterhash", funcTag, 110},
{"int64div", funcTag, 111},
{"uint64div", funcTag, 112},
{"int64mod", funcTag, 111},
{"uint64mod", funcTag, 112},
{"float64toint64", funcTag, 113},
{"float64touint64", funcTag, 114},
{"float64touint32", funcTag, 115},
{"int64tofloat64", funcTag, 116},
{"uint64tofloat64", funcTag, 117},
{"uint32tofloat64", funcTag, 118},
{"complex128div", funcTag, 119},
{"racefuncenter", funcTag, 120},
{"racefuncenterfp", funcTag, 9},
{"racefuncexit", funcTag, 9},
{"raceread", funcTag, 120},
{"racewrite", funcTag, 120},
{"racereadrange", funcTag, 121},
{"racewriterange", funcTag, 121},
{"msanread", funcTag, 121},
{"msanwrite", funcTag, 121},
{"checkptrAlignment", funcTag, 122},
{"checkptrArithmetic", funcTag, 124},
{"libfuzzerTraceCmp1", funcTag, 126},
{"libfuzzerTraceCmp2", funcTag, 128},
{"libfuzzerTraceCmp4", funcTag, 129},
{"libfuzzerTraceCmp8", funcTag, 130},
{"libfuzzerTraceConstCmp1", funcTag, 126},
{"libfuzzerTraceConstCmp2", funcTag, 128},
{"libfuzzerTraceConstCmp4", funcTag, 129},
{"libfuzzerTraceConstCmp8", funcTag, 130},
{"x86HasPOPCNT", varTag, 6},
{"x86HasSSE41", varTag, 6},
{"x86HasFMA", varTag, 6},
{"armHasVFPv4", varTag, 6},
{"arm64HasATOMICS", varTag, 6},
}
func runtimeTypes() []*types.Type {
var typs [129]*types.Type
var typs [131]*types.Type
typs[0] = types.Bytetype
typs[1] = types.NewPtr(typs[0])
typs[2] = types.Types[TANY]
typs[3] = types.NewPtr(typs[2])
typs[4] = functype(nil, []*Node{anonfield(typs[1])}, []*Node{anonfield(typs[3])})
typs[5] = functype(nil, nil, nil)
typs[6] = types.Types[TINTER]
typs[7] = functype(nil, []*Node{anonfield(typs[6])}, nil)
typs[8] = types.Types[TINT32]
typs[9] = types.NewPtr(typs[8])
typs[10] = functype(nil, []*Node{anonfield(typs[9])}, []*Node{anonfield(typs[6])})
typs[11] = types.Types[TINT]
typs[12] = functype(nil, []*Node{anonfield(typs[11]), anonfield(typs[11])}, nil)
typs[13] = types.Types[TUINT]
typs[14] = functype(nil, []*Node{anonfield(typs[13]), anonfield(typs[11])}, nil)
typs[15] = types.Types[TBOOL]
typs[16] = functype(nil, []*Node{anonfield(typs[15])}, nil)
typs[17] = types.Types[TFLOAT64]
typs[18] = functype(nil, []*Node{anonfield(typs[17])}, nil)
typs[19] = types.Types[TINT64]
typs[20] = functype(nil, []*Node{anonfield(typs[19])}, nil)
typs[21] = types.Types[TUINT64]
typs[22] = functype(nil, []*Node{anonfield(typs[21])}, nil)
typs[23] = types.Types[TCOMPLEX128]
typs[24] = functype(nil, []*Node{anonfield(typs[23])}, nil)
typs[25] = types.Types[TSTRING]
typs[26] = functype(nil, []*Node{anonfield(typs[25])}, nil)
typs[27] = functype(nil, []*Node{anonfield(typs[2])}, nil)
typs[28] = types.NewArray(typs[0], 32)
typs[29] = types.NewPtr(typs[28])
typs[30] = functype(nil, []*Node{anonfield(typs[29]), anonfield(typs[25]), anonfield(typs[25])}, []*Node{anonfield(typs[25])})
typs[31] = functype(nil, []*Node{anonfield(typs[29]), anonfield(typs[25]), anonfield(typs[25]), anonfield(typs[25])}, []*Node{anonfield(typs[25])})
typs[32] = functype(nil, []*Node{anonfield(typs[29]), anonfield(typs[25]), anonfield(typs[25]), anonfield(typs[25]), anonfield(typs[25])}, []*Node{anonfield(typs[25])})
typs[33] = functype(nil, []*Node{anonfield(typs[29]), anonfield(typs[25]), anonfield(typs[25]), anonfield(typs[25]), anonfield(typs[25]), anonfield(typs[25])}, []*Node{anonfield(typs[25])})
typs[34] = types.NewSlice(typs[25])
typs[35] = functype(nil, []*Node{anonfield(typs[29]), anonfield(typs[34])}, []*Node{anonfield(typs[25])})
typs[36] = functype(nil, []*Node{anonfield(typs[25]), anonfield(typs[25])}, []*Node{anonfield(typs[11])})
typs[37] = types.NewArray(typs[0], 4)
typs[38] = types.NewPtr(typs[37])
typs[39] = functype(nil, []*Node{anonfield(typs[38]), anonfield(typs[19])}, []*Node{anonfield(typs[25])})
typs[40] = functype(nil, []*Node{anonfield(typs[29]), anonfield(typs[1]), anonfield(typs[11])}, []*Node{anonfield(typs[25])})
typs[41] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[11])}, []*Node{anonfield(typs[25])})
typs[42] = types.Runetype
typs[43] = types.NewSlice(typs[42])
typs[44] = functype(nil, []*Node{anonfield(typs[29]), anonfield(typs[43])}, []*Node{anonfield(typs[25])})
typs[45] = types.NewSlice(typs[0])
typs[46] = functype(nil, []*Node{anonfield(typs[29]), anonfield(typs[25])}, []*Node{anonfield(typs[45])})
typs[47] = types.NewArray(typs[42], 32)
typs[48] = types.NewPtr(typs[47])
typs[49] = functype(nil, []*Node{anonfield(typs[48]), anonfield(typs[25])}, []*Node{anonfield(typs[43])})
typs[50] = types.Types[TUINTPTR]
typs[51] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[11]), anonfield(typs[3]), anonfield(typs[11]), anonfield(typs[50])}, []*Node{anonfield(typs[11])})
typs[52] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[11]), anonfield(typs[25])}, []*Node{anonfield(typs[11])})
typs[53] = functype(nil, []*Node{anonfield(typs[25]), anonfield(typs[11])}, []*Node{anonfield(typs[42]), anonfield(typs[11])})
typs[54] = functype(nil, []*Node{anonfield(typs[25])}, []*Node{anonfield(typs[11])})
typs[55] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2])})
typs[56] = types.Types[TUNSAFEPTR]
typs[57] = functype(nil, []*Node{anonfield(typs[2])}, []*Node{anonfield(typs[56])})
typs[58] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, []*Node{anonfield(typs[2])})
typs[59] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2]), anonfield(typs[15])})
typs[60] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[1])}, nil)
typs[61] = functype(nil, []*Node{anonfield(typs[1])}, nil)
typs[62] = types.NewPtr(typs[50])
typs[63] = functype(nil, []*Node{anonfield(typs[62]), anonfield(typs[56]), anonfield(typs[56])}, []*Node{anonfield(typs[15])})
typs[64] = types.Types[TUINT32]
typs[65] = functype(nil, nil, []*Node{anonfield(typs[64])})
typs[66] = types.NewMap(typs[2], typs[2])
typs[67] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[19]), anonfield(typs[3])}, []*Node{anonfield(typs[66])})
typs[68] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[11]), anonfield(typs[3])}, []*Node{anonfield(typs[66])})
typs[69] = functype(nil, nil, []*Node{anonfield(typs[66])})
typs[70] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[3])}, []*Node{anonfield(typs[3])})
typs[71] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[2])}, []*Node{anonfield(typs[3])})
typs[72] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[3]), anonfield(typs[1])}, []*Node{anonfield(typs[3])})
typs[73] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[3])}, []*Node{anonfield(typs[3]), anonfield(typs[15])})
typs[74] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[2])}, []*Node{anonfield(typs[3]), anonfield(typs[15])})
typs[75] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[3]), anonfield(typs[1])}, []*Node{anonfield(typs[3]), anonfield(typs[15])})
typs[76] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[3])}, nil)
typs[77] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[2])}, nil)
typs[78] = functype(nil, []*Node{anonfield(typs[3])}, nil)
typs[79] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66])}, nil)
typs[80] = types.NewChan(typs[2], types.Cboth)
typs[81] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[19])}, []*Node{anonfield(typs[80])})
typs[82] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[11])}, []*Node{anonfield(typs[80])})
typs[83] = types.NewChan(typs[2], types.Crecv)
typs[84] = functype(nil, []*Node{anonfield(typs[83]), anonfield(typs[3])}, nil)
typs[85] = functype(nil, []*Node{anonfield(typs[83]), anonfield(typs[3])}, []*Node{anonfield(typs[15])})
typs[86] = types.NewChan(typs[2], types.Csend)
typs[87] = functype(nil, []*Node{anonfield(typs[86]), anonfield(typs[3])}, nil)
typs[88] = types.NewArray(typs[0], 3)
typs[89] = tostruct([]*Node{namedfield("enabled", typs[15]), namedfield("pad", typs[88]), namedfield("needed", typs[15]), namedfield("cgo", typs[15]), namedfield("alignme", typs[21])})
typs[90] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[3])}, nil)
typs[91] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, nil)
typs[92] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[11]), anonfield(typs[3]), anonfield(typs[11])}, []*Node{anonfield(typs[11])})
typs[93] = functype(nil, []*Node{anonfield(typs[86]), anonfield(typs[3])}, []*Node{anonfield(typs[15])})
typs[94] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[83])}, []*Node{anonfield(typs[15])})
typs[95] = types.NewPtr(typs[15])
typs[96] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[95]), anonfield(typs[83])}, []*Node{anonfield(typs[15])})
typs[97] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[11])}, []*Node{anonfield(typs[11]), anonfield(typs[15])})
typs[98] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[11]), anonfield(typs[11])}, []*Node{anonfield(typs[56])})
typs[99] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[19]), anonfield(typs[19])}, []*Node{anonfield(typs[56])})
typs[100] = types.NewSlice(typs[2])
typs[101] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[100]), anonfield(typs[11])}, []*Node{anonfield(typs[100])})
typs[102] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[50])}, nil)
typs[103] = functype(nil, []*Node{anonfield(typs[56]), anonfield(typs[50])}, nil)
typs[104] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[50])}, []*Node{anonfield(typs[15])})
typs[105] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3])}, []*Node{anonfield(typs[15])})
typs[106] = functype(nil, []*Node{anonfield(typs[56]), anonfield(typs[56])}, []*Node{anonfield(typs[15])})
typs[107] = functype(nil, []*Node{anonfield(typs[56]), anonfield(typs[50]), anonfield(typs[50])}, []*Node{anonfield(typs[50])})
typs[108] = functype(nil, []*Node{anonfield(typs[56]), anonfield(typs[50])}, []*Node{anonfield(typs[50])})
typs[109] = functype(nil, []*Node{anonfield(typs[19]), anonfield(typs[19])}, []*Node{anonfield(typs[19])})
typs[110] = functype(nil, []*Node{anonfield(typs[21]), anonfield(typs[21])}, []*Node{anonfield(typs[21])})
typs[111] = functype(nil, []*Node{anonfield(typs[17])}, []*Node{anonfield(typs[19])})
typs[112] = functype(nil, []*Node{anonfield(typs[17])}, []*Node{anonfield(typs[21])})
typs[113] = functype(nil, []*Node{anonfield(typs[17])}, []*Node{anonfield(typs[64])})
typs[114] = functype(nil, []*Node{anonfield(typs[19])}, []*Node{anonfield(typs[17])})
typs[115] = functype(nil, []*Node{anonfield(typs[21])}, []*Node{anonfield(typs[17])})
typs[116] = functype(nil, []*Node{anonfield(typs[64])}, []*Node{anonfield(typs[17])})
typs[117] = functype(nil, []*Node{anonfield(typs[23]), anonfield(typs[23])}, []*Node{anonfield(typs[23])})
typs[118] = functype(nil, []*Node{anonfield(typs[50])}, nil)
typs[119] = functype(nil, []*Node{anonfield(typs[50]), anonfield(typs[50])}, nil)
typs[120] = functype(nil, []*Node{anonfield(typs[56]), anonfield(typs[1]), anonfield(typs[50])}, nil)
typs[121] = types.NewSlice(typs[56])
typs[122] = functype(nil, []*Node{anonfield(typs[56]), anonfield(typs[121])}, nil)
typs[123] = types.Types[TUINT8]
typs[124] = functype(nil, []*Node{anonfield(typs[123]), anonfield(typs[123])}, nil)
typs[125] = types.Types[TUINT16]
typs[5] = types.Types[TUINTPTR]
typs[6] = types.Types[TBOOL]
typs[7] = types.Types[TUNSAFEPTR]
typs[8] = functype(nil, []*Node{anonfield(typs[5]), anonfield(typs[1]), anonfield(typs[6])}, []*Node{anonfield(typs[7])})
typs[9] = functype(nil, nil, nil)
typs[10] = types.Types[TINTER]
typs[11] = functype(nil, []*Node{anonfield(typs[10])}, nil)
typs[12] = types.Types[TINT32]
typs[13] = types.NewPtr(typs[12])
typs[14] = functype(nil, []*Node{anonfield(typs[13])}, []*Node{anonfield(typs[10])})
typs[15] = types.Types[TINT]
typs[16] = functype(nil, []*Node{anonfield(typs[15]), anonfield(typs[15])}, nil)
typs[17] = types.Types[TUINT]
typs[18] = functype(nil, []*Node{anonfield(typs[17]), anonfield(typs[15])}, nil)
typs[19] = functype(nil, []*Node{anonfield(typs[6])}, nil)
typs[20] = types.Types[TFLOAT64]
typs[21] = functype(nil, []*Node{anonfield(typs[20])}, nil)
typs[22] = types.Types[TINT64]
typs[23] = functype(nil, []*Node{anonfield(typs[22])}, nil)
typs[24] = types.Types[TUINT64]
typs[25] = functype(nil, []*Node{anonfield(typs[24])}, nil)
typs[26] = types.Types[TCOMPLEX128]
typs[27] = functype(nil, []*Node{anonfield(typs[26])}, nil)
typs[28] = types.Types[TSTRING]
typs[29] = functype(nil, []*Node{anonfield(typs[28])}, nil)
typs[30] = functype(nil, []*Node{anonfield(typs[2])}, nil)
typs[31] = types.NewArray(typs[0], 32)
typs[32] = types.NewPtr(typs[31])
typs[33] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
typs[34] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
typs[35] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
typs[36] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
typs[37] = types.NewSlice(typs[28])
typs[38] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[37])}, []*Node{anonfield(typs[28])})
typs[39] = functype(nil, []*Node{anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[15])})
typs[40] = types.NewArray(typs[0], 4)
typs[41] = types.NewPtr(typs[40])
typs[42] = functype(nil, []*Node{anonfield(typs[41]), anonfield(typs[22])}, []*Node{anonfield(typs[28])})
typs[43] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[28])})
typs[44] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[28])})
typs[45] = types.Runetype
typs[46] = types.NewSlice(typs[45])
typs[47] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[46])}, []*Node{anonfield(typs[28])})
typs[48] = types.NewSlice(typs[0])
typs[49] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[28])}, []*Node{anonfield(typs[48])})
typs[50] = types.NewArray(typs[45], 32)
typs[51] = types.NewPtr(typs[50])
typs[52] = functype(nil, []*Node{anonfield(typs[51]), anonfield(typs[28])}, []*Node{anonfield(typs[46])})
typs[53] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[15]), anonfield(typs[3]), anonfield(typs[15]), anonfield(typs[5])}, []*Node{anonfield(typs[15])})
typs[54] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[28])}, []*Node{anonfield(typs[15])})
typs[55] = functype(nil, []*Node{anonfield(typs[28]), anonfield(typs[15])}, []*Node{anonfield(typs[45]), anonfield(typs[15])})
typs[56] = functype(nil, []*Node{anonfield(typs[28])}, []*Node{anonfield(typs[15])})
typs[57] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2])})
typs[58] = functype(nil, []*Node{anonfield(typs[2])}, []*Node{anonfield(typs[7])})
typs[59] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, []*Node{anonfield(typs[2])})
typs[60] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2]), anonfield(typs[6])})
typs[61] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[1])}, nil)
typs[62] = functype(nil, []*Node{anonfield(typs[1])}, nil)
typs[63] = types.NewPtr(typs[5])
typs[64] = functype(nil, []*Node{anonfield(typs[63]), anonfield(typs[7]), anonfield(typs[7])}, []*Node{anonfield(typs[6])})
typs[65] = types.Types[TUINT32]
typs[66] = functype(nil, nil, []*Node{anonfield(typs[65])})
typs[67] = types.NewMap(typs[2], typs[2])
typs[68] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[22]), anonfield(typs[3])}, []*Node{anonfield(typs[67])})
typs[69] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[3])}, []*Node{anonfield(typs[67])})
typs[70] = functype(nil, nil, []*Node{anonfield(typs[67])})
typs[71] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3])}, []*Node{anonfield(typs[3])})
typs[72] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[2])}, []*Node{anonfield(typs[3])})
typs[73] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3]), anonfield(typs[1])}, []*Node{anonfield(typs[3])})
typs[74] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3])}, []*Node{anonfield(typs[3]), anonfield(typs[6])})
typs[75] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[2])}, []*Node{anonfield(typs[3]), anonfield(typs[6])})
typs[76] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3]), anonfield(typs[1])}, []*Node{anonfield(typs[3]), anonfield(typs[6])})
typs[77] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3])}, nil)
typs[78] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[2])}, nil)
typs[79] = functype(nil, []*Node{anonfield(typs[3])}, nil)
typs[80] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67])}, nil)
typs[81] = types.NewChan(typs[2], types.Cboth)
typs[82] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[22])}, []*Node{anonfield(typs[81])})
typs[83] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[81])})
typs[84] = types.NewChan(typs[2], types.Crecv)
typs[85] = functype(nil, []*Node{anonfield(typs[84]), anonfield(typs[3])}, nil)
typs[86] = functype(nil, []*Node{anonfield(typs[84]), anonfield(typs[3])}, []*Node{anonfield(typs[6])})
typs[87] = types.NewChan(typs[2], types.Csend)
typs[88] = functype(nil, []*Node{anonfield(typs[87]), anonfield(typs[3])}, nil)
typs[89] = types.NewArray(typs[0], 3)
typs[90] = tostruct([]*Node{namedfield("enabled", typs[6]), namedfield("pad", typs[89]), namedfield("needed", typs[6]), namedfield("cgo", typs[6]), namedfield("alignme", typs[24])})
typs[91] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[3])}, nil)
typs[92] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, nil)
typs[93] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[15]), anonfield(typs[3]), anonfield(typs[15])}, []*Node{anonfield(typs[15])})
typs[94] = functype(nil, []*Node{anonfield(typs[87]), anonfield(typs[3])}, []*Node{anonfield(typs[6])})
typs[95] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[84])}, []*Node{anonfield(typs[6])})
typs[96] = types.NewPtr(typs[6])
typs[97] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[96]), anonfield(typs[84])}, []*Node{anonfield(typs[6])})
typs[98] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[15]), anonfield(typs[6])})
typs[99] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[15])}, []*Node{anonfield(typs[7])})
typs[100] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[22]), anonfield(typs[22])}, []*Node{anonfield(typs[7])})
typs[101] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[15]), anonfield(typs[7])}, []*Node{anonfield(typs[7])})
typs[102] = types.NewSlice(typs[2])
typs[103] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[102]), anonfield(typs[15])}, []*Node{anonfield(typs[102])})
typs[104] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[5])}, nil)
typs[105] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[5])}, nil)
typs[106] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[5])}, []*Node{anonfield(typs[6])})
typs[107] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3])}, []*Node{anonfield(typs[6])})
typs[108] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[7])}, []*Node{anonfield(typs[6])})
typs[109] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[5]), anonfield(typs[5])}, []*Node{anonfield(typs[5])})
typs[110] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[5])}, []*Node{anonfield(typs[5])})
typs[111] = functype(nil, []*Node{anonfield(typs[22]), anonfield(typs[22])}, []*Node{anonfield(typs[22])})
typs[112] = functype(nil, []*Node{anonfield(typs[24]), anonfield(typs[24])}, []*Node{anonfield(typs[24])})
typs[113] = functype(nil, []*Node{anonfield(typs[20])}, []*Node{anonfield(typs[22])})
typs[114] = functype(nil, []*Node{anonfield(typs[20])}, []*Node{anonfield(typs[24])})
typs[115] = functype(nil, []*Node{anonfield(typs[20])}, []*Node{anonfield(typs[65])})
typs[116] = functype(nil, []*Node{anonfield(typs[22])}, []*Node{anonfield(typs[20])})
typs[117] = functype(nil, []*Node{anonfield(typs[24])}, []*Node{anonfield(typs[20])})
typs[118] = functype(nil, []*Node{anonfield(typs[65])}, []*Node{anonfield(typs[20])})
typs[119] = functype(nil, []*Node{anonfield(typs[26]), anonfield(typs[26])}, []*Node{anonfield(typs[26])})
typs[120] = functype(nil, []*Node{anonfield(typs[5])}, nil)
typs[121] = functype(nil, []*Node{anonfield(typs[5]), anonfield(typs[5])}, nil)
typs[122] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[1]), anonfield(typs[5])}, nil)
typs[123] = types.NewSlice(typs[7])
typs[124] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[123])}, nil)
typs[125] = types.Types[TUINT8]
typs[126] = functype(nil, []*Node{anonfield(typs[125]), anonfield(typs[125])}, nil)
typs[127] = functype(nil, []*Node{anonfield(typs[64]), anonfield(typs[64])}, nil)
typs[128] = functype(nil, []*Node{anonfield(typs[21]), anonfield(typs[21])}, nil)
typs[127] = types.Types[TUINT16]
typs[128] = functype(nil, []*Node{anonfield(typs[127]), anonfield(typs[127])}, nil)
typs[129] = functype(nil, []*Node{anonfield(typs[65]), anonfield(typs[65])}, nil)
typs[130] = functype(nil, []*Node{anonfield(typs[24]), anonfield(typs[24])}, nil)
return typs[:]
}

View File

@ -15,6 +15,7 @@ package runtime
import "unsafe"
func newobject(typ *byte) *any
func mallocgc(size uintptr, typ *byte, needszero bool) unsafe.Pointer
func panicdivide()
func panicshift()
func panicmakeslicelen()
@ -174,6 +175,7 @@ func block()
func makeslice(typ *byte, len int, cap int) unsafe.Pointer
func makeslice64(typ *byte, len int64, cap int64) unsafe.Pointer
func makeslicecopy(typ *byte, tolen int, fromlen int, from unsafe.Pointer) unsafe.Pointer
func growslice(typ *byte, old []any, cap int) (ary []any)
func memmove(to *any, frm *any, length uintptr)
func memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr)

View File

@ -1165,92 +1165,93 @@ func (n *Node) stmtfmt(s fmt.State, mode fmtMode) {
}
var opprec = []int{
OALIGNOF: 8,
OAPPEND: 8,
OBYTES2STR: 8,
OARRAYLIT: 8,
OSLICELIT: 8,
ORUNES2STR: 8,
OCALLFUNC: 8,
OCALLINTER: 8,
OCALLMETH: 8,
OCALL: 8,
OCAP: 8,
OCLOSE: 8,
OCONVIFACE: 8,
OCONVNOP: 8,
OCONV: 8,
OCOPY: 8,
ODELETE: 8,
OGETG: 8,
OLEN: 8,
OLITERAL: 8,
OMAKESLICE: 8,
OMAKE: 8,
OMAPLIT: 8,
ONAME: 8,
ONEW: 8,
ONONAME: 8,
OOFFSETOF: 8,
OPACK: 8,
OPANIC: 8,
OPAREN: 8,
OPRINTN: 8,
OPRINT: 8,
ORUNESTR: 8,
OSIZEOF: 8,
OSTR2BYTES: 8,
OSTR2RUNES: 8,
OSTRUCTLIT: 8,
OTARRAY: 8,
OTCHAN: 8,
OTFUNC: 8,
OTINTER: 8,
OTMAP: 8,
OTSTRUCT: 8,
OINDEXMAP: 8,
OINDEX: 8,
OSLICE: 8,
OSLICESTR: 8,
OSLICEARR: 8,
OSLICE3: 8,
OSLICE3ARR: 8,
OSLICEHEADER: 8,
ODOTINTER: 8,
ODOTMETH: 8,
ODOTPTR: 8,
ODOTTYPE2: 8,
ODOTTYPE: 8,
ODOT: 8,
OXDOT: 8,
OCALLPART: 8,
OPLUS: 7,
ONOT: 7,
OBITNOT: 7,
ONEG: 7,
OADDR: 7,
ODEREF: 7,
ORECV: 7,
OMUL: 6,
ODIV: 6,
OMOD: 6,
OLSH: 6,
ORSH: 6,
OAND: 6,
OANDNOT: 6,
OADD: 5,
OSUB: 5,
OOR: 5,
OXOR: 5,
OEQ: 4,
OLT: 4,
OLE: 4,
OGE: 4,
OGT: 4,
ONE: 4,
OSEND: 3,
OANDAND: 2,
OOROR: 1,
OALIGNOF: 8,
OAPPEND: 8,
OBYTES2STR: 8,
OARRAYLIT: 8,
OSLICELIT: 8,
ORUNES2STR: 8,
OCALLFUNC: 8,
OCALLINTER: 8,
OCALLMETH: 8,
OCALL: 8,
OCAP: 8,
OCLOSE: 8,
OCONVIFACE: 8,
OCONVNOP: 8,
OCONV: 8,
OCOPY: 8,
ODELETE: 8,
OGETG: 8,
OLEN: 8,
OLITERAL: 8,
OMAKESLICE: 8,
OMAKESLICECOPY: 8,
OMAKE: 8,
OMAPLIT: 8,
ONAME: 8,
ONEW: 8,
ONONAME: 8,
OOFFSETOF: 8,
OPACK: 8,
OPANIC: 8,
OPAREN: 8,
OPRINTN: 8,
OPRINT: 8,
ORUNESTR: 8,
OSIZEOF: 8,
OSTR2BYTES: 8,
OSTR2RUNES: 8,
OSTRUCTLIT: 8,
OTARRAY: 8,
OTCHAN: 8,
OTFUNC: 8,
OTINTER: 8,
OTMAP: 8,
OTSTRUCT: 8,
OINDEXMAP: 8,
OINDEX: 8,
OSLICE: 8,
OSLICESTR: 8,
OSLICEARR: 8,
OSLICE3: 8,
OSLICE3ARR: 8,
OSLICEHEADER: 8,
ODOTINTER: 8,
ODOTMETH: 8,
ODOTPTR: 8,
ODOTTYPE2: 8,
ODOTTYPE: 8,
ODOT: 8,
OXDOT: 8,
OCALLPART: 8,
OPLUS: 7,
ONOT: 7,
OBITNOT: 7,
ONEG: 7,
OADDR: 7,
ODEREF: 7,
ORECV: 7,
OMUL: 6,
ODIV: 6,
OMOD: 6,
OLSH: 6,
ORSH: 6,
OAND: 6,
OANDNOT: 6,
OADD: 5,
OSUB: 5,
OOR: 5,
OXOR: 5,
OEQ: 4,
OLT: 4,
OLE: 4,
OGE: 4,
OGT: 4,
ONE: 4,
OSEND: 3,
OANDAND: 2,
OOROR: 1,
// Statements handled by stmtfmt
OAS: -1,
@ -1572,6 +1573,9 @@ func (n *Node) exprfmt(s fmt.State, prec int, mode fmtMode) {
}
mode.Fprintf(s, "make(%v)", n.Type)
case OMAKESLICECOPY:
mode.Fprintf(s, "makeslicecopy(%v, %v, %v)", n.Type, n.Left, n.Right)
case OPLUS, ONEG, OADDR, OBITNOT, ODEREF, ONOT, ORECV:
// Unary
mode.Fprintf(s, "%#v", n.Op)

View File

@ -82,89 +82,90 @@ func _() {
_ = x[OMAKECHAN-71]
_ = x[OMAKEMAP-72]
_ = x[OMAKESLICE-73]
_ = x[OMUL-74]
_ = x[ODIV-75]
_ = x[OMOD-76]
_ = x[OLSH-77]
_ = x[ORSH-78]
_ = x[OAND-79]
_ = x[OANDNOT-80]
_ = x[ONEW-81]
_ = x[ONEWOBJ-82]
_ = x[ONOT-83]
_ = x[OBITNOT-84]
_ = x[OPLUS-85]
_ = x[ONEG-86]
_ = x[OOROR-87]
_ = x[OPANIC-88]
_ = x[OPRINT-89]
_ = x[OPRINTN-90]
_ = x[OPAREN-91]
_ = x[OSEND-92]
_ = x[OSLICE-93]
_ = x[OSLICEARR-94]
_ = x[OSLICESTR-95]
_ = x[OSLICE3-96]
_ = x[OSLICE3ARR-97]
_ = x[OSLICEHEADER-98]
_ = x[ORECOVER-99]
_ = x[ORECV-100]
_ = x[ORUNESTR-101]
_ = x[OSELRECV-102]
_ = x[OSELRECV2-103]
_ = x[OIOTA-104]
_ = x[OREAL-105]
_ = x[OIMAG-106]
_ = x[OCOMPLEX-107]
_ = x[OALIGNOF-108]
_ = x[OOFFSETOF-109]
_ = x[OSIZEOF-110]
_ = x[OBLOCK-111]
_ = x[OBREAK-112]
_ = x[OCASE-113]
_ = x[OCONTINUE-114]
_ = x[ODEFER-115]
_ = x[OEMPTY-116]
_ = x[OFALL-117]
_ = x[OFOR-118]
_ = x[OFORUNTIL-119]
_ = x[OGOTO-120]
_ = x[OIF-121]
_ = x[OLABEL-122]
_ = x[OGO-123]
_ = x[ORANGE-124]
_ = x[ORETURN-125]
_ = x[OSELECT-126]
_ = x[OSWITCH-127]
_ = x[OTYPESW-128]
_ = x[OTCHAN-129]
_ = x[OTMAP-130]
_ = x[OTSTRUCT-131]
_ = x[OTINTER-132]
_ = x[OTFUNC-133]
_ = x[OTARRAY-134]
_ = x[ODDD-135]
_ = x[OINLCALL-136]
_ = x[OEFACE-137]
_ = x[OITAB-138]
_ = x[OIDATA-139]
_ = x[OSPTR-140]
_ = x[OCLOSUREVAR-141]
_ = x[OCFUNC-142]
_ = x[OCHECKNIL-143]
_ = x[OVARDEF-144]
_ = x[OVARKILL-145]
_ = x[OVARLIVE-146]
_ = x[ORESULT-147]
_ = x[OINLMARK-148]
_ = x[ORETJMP-149]
_ = x[OGETG-150]
_ = x[OEND-151]
_ = x[OMAKESLICECOPY-74]
_ = x[OMUL-75]
_ = x[ODIV-76]
_ = x[OMOD-77]
_ = x[OLSH-78]
_ = x[ORSH-79]
_ = x[OAND-80]
_ = x[OANDNOT-81]
_ = x[ONEW-82]
_ = x[ONEWOBJ-83]
_ = x[ONOT-84]
_ = x[OBITNOT-85]
_ = x[OPLUS-86]
_ = x[ONEG-87]
_ = x[OOROR-88]
_ = x[OPANIC-89]
_ = x[OPRINT-90]
_ = x[OPRINTN-91]
_ = x[OPAREN-92]
_ = x[OSEND-93]
_ = x[OSLICE-94]
_ = x[OSLICEARR-95]
_ = x[OSLICESTR-96]
_ = x[OSLICE3-97]
_ = x[OSLICE3ARR-98]
_ = x[OSLICEHEADER-99]
_ = x[ORECOVER-100]
_ = x[ORECV-101]
_ = x[ORUNESTR-102]
_ = x[OSELRECV-103]
_ = x[OSELRECV2-104]
_ = x[OIOTA-105]
_ = x[OREAL-106]
_ = x[OIMAG-107]
_ = x[OCOMPLEX-108]
_ = x[OALIGNOF-109]
_ = x[OOFFSETOF-110]
_ = x[OSIZEOF-111]
_ = x[OBLOCK-112]
_ = x[OBREAK-113]
_ = x[OCASE-114]
_ = x[OCONTINUE-115]
_ = x[ODEFER-116]
_ = x[OEMPTY-117]
_ = x[OFALL-118]
_ = x[OFOR-119]
_ = x[OFORUNTIL-120]
_ = x[OGOTO-121]
_ = x[OIF-122]
_ = x[OLABEL-123]
_ = x[OGO-124]
_ = x[ORANGE-125]
_ = x[ORETURN-126]
_ = x[OSELECT-127]
_ = x[OSWITCH-128]
_ = x[OTYPESW-129]
_ = x[OTCHAN-130]
_ = x[OTMAP-131]
_ = x[OTSTRUCT-132]
_ = x[OTINTER-133]
_ = x[OTFUNC-134]
_ = x[OTARRAY-135]
_ = x[ODDD-136]
_ = x[OINLCALL-137]
_ = x[OEFACE-138]
_ = x[OITAB-139]
_ = x[OIDATA-140]
_ = x[OSPTR-141]
_ = x[OCLOSUREVAR-142]
_ = x[OCFUNC-143]
_ = x[OCHECKNIL-144]
_ = x[OVARDEF-145]
_ = x[OVARKILL-146]
_ = x[OVARLIVE-147]
_ = x[ORESULT-148]
_ = x[OINLMARK-149]
_ = x[ORETJMP-150]
_ = x[OGETG-151]
_ = x[OEND-152]
}
const _Op_name = "XXXNAMENONAMETYPEPACKLITERALADDSUBORXORADDSTRADDRANDANDAPPENDBYTES2STRBYTES2STRTMPRUNES2STRSTR2BYTESSTR2BYTESTMPSTR2RUNESASAS2AS2DOTTYPEAS2FUNCAS2MAPRAS2RECVASOPCALLCALLFUNCCALLMETHCALLINTERCALLPARTCAPCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVNOPCOPYDCLDCLFUNCDCLFIELDDCLCONSTDCLTYPEDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTDEREFINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMULDIVMODLSHRSHANDANDNOTNEWNEWOBJNOTBITNOTPLUSNEGORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRSLICEHEADERRECOVERRECVRUNESTRSELRECVSELRECV2IOTAREALIMAGCOMPLEXALIGNOFOFFSETOFSIZEOFBLOCKBREAKCASECONTINUEDEFEREMPTYFALLFORFORUNTILGOTOIFLABELGORANGERETURNSELECTSWITCHTYPESWTCHANTMAPTSTRUCTTINTERTFUNCTARRAYDDDINLCALLEFACEITABIDATASPTRCLOSUREVARCFUNCCHECKNILVARDEFVARKILLVARLIVERESULTINLMARKRETJMPGETGEND"
const _Op_name = "XXXNAMENONAMETYPEPACKLITERALADDSUBORXORADDSTRADDRANDANDAPPENDBYTES2STRBYTES2STRTMPRUNES2STRSTR2BYTESSTR2BYTESTMPSTR2RUNESASAS2AS2DOTTYPEAS2FUNCAS2MAPRAS2RECVASOPCALLCALLFUNCCALLMETHCALLINTERCALLPARTCAPCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVNOPCOPYDCLDCLFUNCDCLFIELDDCLCONSTDCLTYPEDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTDEREFINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMAKESLICECOPYMULDIVMODLSHRSHANDANDNOTNEWNEWOBJNOTBITNOTPLUSNEGORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRSLICEHEADERRECOVERRECVRUNESTRSELRECVSELRECV2IOTAREALIMAGCOMPLEXALIGNOFOFFSETOFSIZEOFBLOCKBREAKCASECONTINUEDEFEREMPTYFALLFORFORUNTILGOTOIFLABELGORANGERETURNSELECTSWITCHTYPESWTCHANTMAPTSTRUCTTINTERTFUNCTARRAYDDDINLCALLEFACEITABIDATASPTRCLOSUREVARCFUNCCHECKNILVARDEFVARKILLVARLIVERESULTINLMARKRETJMPGETGEND"
var _Op_index = [...]uint16{0, 3, 7, 13, 17, 21, 28, 31, 34, 36, 39, 45, 49, 55, 61, 70, 82, 91, 100, 112, 121, 123, 126, 136, 143, 150, 157, 161, 165, 173, 181, 190, 198, 201, 206, 213, 220, 226, 235, 243, 251, 257, 261, 270, 277, 281, 284, 291, 299, 307, 314, 320, 323, 329, 336, 344, 348, 355, 363, 365, 367, 369, 371, 373, 375, 380, 385, 393, 396, 405, 408, 412, 420, 427, 436, 439, 442, 445, 448, 451, 454, 460, 463, 469, 472, 478, 482, 485, 489, 494, 499, 505, 510, 514, 519, 527, 535, 541, 550, 561, 568, 572, 579, 586, 594, 598, 602, 606, 613, 620, 628, 634, 639, 644, 648, 656, 661, 666, 670, 673, 681, 685, 687, 692, 694, 699, 705, 711, 717, 723, 728, 732, 739, 745, 750, 756, 759, 766, 771, 775, 780, 784, 794, 799, 807, 813, 820, 827, 833, 840, 846, 850, 853}
var _Op_index = [...]uint16{0, 3, 7, 13, 17, 21, 28, 31, 34, 36, 39, 45, 49, 55, 61, 70, 82, 91, 100, 112, 121, 123, 126, 136, 143, 150, 157, 161, 165, 173, 181, 190, 198, 201, 206, 213, 220, 226, 235, 243, 251, 257, 261, 270, 277, 281, 284, 291, 299, 307, 314, 320, 323, 329, 336, 344, 348, 355, 363, 365, 367, 369, 371, 373, 375, 380, 385, 393, 396, 405, 408, 412, 420, 427, 436, 449, 452, 455, 458, 461, 464, 467, 473, 476, 482, 485, 491, 495, 498, 502, 507, 512, 518, 523, 527, 532, 540, 548, 554, 563, 574, 581, 585, 592, 599, 607, 611, 615, 619, 626, 633, 641, 647, 652, 657, 661, 669, 674, 679, 683, 686, 694, 698, 700, 705, 707, 712, 718, 724, 730, 736, 741, 745, 752, 758, 763, 769, 772, 779, 784, 788, 793, 797, 807, 812, 820, 826, 833, 840, 846, 853, 859, 863, 866}
func (i Op) String() string {
if i >= Op(len(_Op_index)-1) {

View File

@ -319,11 +319,82 @@ func (o *Order) cleanTemp(top ordermarker) {
// stmtList orders each of the statements in the list.
func (o *Order) stmtList(l Nodes) {
for _, n := range l.Slice() {
o.stmt(n)
s := l.Slice()
for i := range s {
orderMakeSliceCopy(s[i:])
o.stmt(s[i])
}
}
// orderMakeSliceCopy matches the pattern:
// m = OMAKESLICE([]T, x); OCOPY(m, s)
// and rewrites it to:
// m = OMAKESLICECOPY([]T, x, s); nil
func orderMakeSliceCopy(s []*Node) {
const go115makeslicecopy = true
if !go115makeslicecopy {
return
}
if Debug['N'] != 0 || instrumenting {
return
}
if len(s) < 2 {
return
}
asn := s[0]
copyn := s[1]
if asn == nil || asn.Op != OAS {
return
}
if asn.Left.Op != ONAME {
return
}
if asn.Left.isBlank() {
return
}
maken := asn.Right
if maken == nil || maken.Op != OMAKESLICE {
return
}
if maken.Esc == EscNone {
return
}
if maken.Left == nil || maken.Right != nil {
return
}
if copyn.Op != OCOPY {
return
}
if copyn.Left.Op != ONAME {
return
}
if asn.Left.Sym != copyn.Left.Sym {
return
}
if copyn.Right.Op != ONAME {
return
}
if copyn.Left.Sym == copyn.Right.Sym {
return
}
maken.Op = OMAKESLICECOPY
maken.Right = copyn.Right
// Set bounded when m = OMAKESLICE([]T, len(s)); OCOPY(m, s)
maken.SetBounded(maken.Left.Op == OLEN && samesafeexpr(maken.Left.Left, copyn.Right))
maken = typecheck(maken, ctxExpr)
s[1] = nil // remove separate copy call
return
}
// edge inserts coverage instrumentation for libfuzzer.
func (o *Order) edge() {
if Debug_libfuzzer == 0 {
@ -1150,6 +1221,7 @@ func (o *Order) expr(n, lhs *Node) *Node {
OMAKECHAN,
OMAKEMAP,
OMAKESLICE,
OMAKESLICECOPY,
ONEW,
OREAL,
ORECOVER,

View File

@ -208,12 +208,16 @@ func (n *Node) MarkNonNil() {
// SetBounded indicates whether operation n does not need safety checks.
// When n is an index or slice operation, n does not need bounds checks.
// When n is a dereferencing operation, n does not need nil checks.
// When n is a makeslice+copy operation, n does not need length and cap checks.
func (n *Node) SetBounded(b bool) {
switch n.Op {
case OINDEX, OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR, OSLICESTR:
// No bounds checks needed.
case ODOTPTR, ODEREF:
// No nil check needed.
case OMAKESLICECOPY:
// No length and cap checks needed
// since new slice and copied over slice data have same length.
default:
Fatalf("SetBounded(%v)", n)
}
@ -714,30 +718,38 @@ const (
ODCLCONST // const pi = 3.14
ODCLTYPE // type Int int or type Int = int
ODELETE // delete(Left, Right)
ODOT // Left.Sym (Left is of struct type)
ODOTPTR // Left.Sym (Left is of pointer to struct type)
ODOTMETH // Left.Sym (Left is non-interface, Right is method name)
ODOTINTER // Left.Sym (Left is interface, Right is method name)
OXDOT // Left.Sym (before rewrite to one of the preceding)
ODOTTYPE // Left.Right or Left.Type (.Right during parsing, .Type once resolved); after walk, .Right contains address of interface type descriptor and .Right.Right contains address of concrete type descriptor
ODOTTYPE2 // Left.Right or Left.Type (.Right during parsing, .Type once resolved; on rhs of OAS2DOTTYPE); after walk, .Right contains address of interface type descriptor
OEQ // Left == Right
ONE // Left != Right
OLT // Left < Right
OLE // Left <= Right
OGE // Left >= Right
OGT // Left > Right
ODEREF // *Left
OINDEX // Left[Right] (index of array or slice)
OINDEXMAP // Left[Right] (index of map)
OKEY // Left:Right (key:value in struct/array/map literal)
OSTRUCTKEY // Sym:Left (key:value in struct literal, after type checking)
OLEN // len(Left)
OMAKE // make(List) (before type checking converts to one of the following)
OMAKECHAN // make(Type, Left) (type is chan)
OMAKEMAP // make(Type, Left) (type is map)
OMAKESLICE // make(Type, Left, Right) (type is slice)
ODELETE // delete(Left, Right)
ODOT // Left.Sym (Left is of struct type)
ODOTPTR // Left.Sym (Left is of pointer to struct type)
ODOTMETH // Left.Sym (Left is non-interface, Right is method name)
ODOTINTER // Left.Sym (Left is interface, Right is method name)
OXDOT // Left.Sym (before rewrite to one of the preceding)
ODOTTYPE // Left.Right or Left.Type (.Right during parsing, .Type once resolved); after walk, .Right contains address of interface type descriptor and .Right.Right contains address of concrete type descriptor
ODOTTYPE2 // Left.Right or Left.Type (.Right during parsing, .Type once resolved; on rhs of OAS2DOTTYPE); after walk, .Right contains address of interface type descriptor
OEQ // Left == Right
ONE // Left != Right
OLT // Left < Right
OLE // Left <= Right
OGE // Left >= Right
OGT // Left > Right
ODEREF // *Left
OINDEX // Left[Right] (index of array or slice)
OINDEXMAP // Left[Right] (index of map)
OKEY // Left:Right (key:value in struct/array/map literal)
OSTRUCTKEY // Sym:Left (key:value in struct literal, after type checking)
OLEN // len(Left)
OMAKE // make(List) (before type checking converts to one of the following)
OMAKECHAN // make(Type, Left) (type is chan)
OMAKEMAP // make(Type, Left) (type is map)
OMAKESLICE // make(Type, Left, Right) (type is slice)
OMAKESLICECOPY // makeslicecopy(Type, Left, Right) (type is slice; Left is length and Right is the copied from slice)
// OMAKESLICECOPY is created by the order pass and corresponds to:
// s = make(Type, Left); copy(s, Right)
//
// Bounded can be set on the node when Left == len(Right) is known at compile time.
//
// This node is created so the walk pass can optimize this pattern which would
// otherwise be hard to detect after the order pass.
OMUL // Left * Right
ODIV // Left / Right
OMOD // Left % Right

View File

@ -1149,6 +1149,49 @@ func typecheck1(n *Node, top int) (res *Node) {
n.List.SetFirst(l)
n.List.SetSecond(c)
case OMAKESLICECOPY:
// Errors here are Fatalf instead of yyerror because only the compiler
// can construct an OMAKESLICECOPY node.
// Components used in OMAKESCLICECOPY that are supplied by parsed source code
// have already been typechecked in OMAKE and OCOPY earlier.
ok |= ctxExpr
t := n.Type
if t == nil {
Fatalf("no type specified for OMAKESLICECOPY")
}
if !t.IsSlice() {
Fatalf("invalid type %v for OMAKESLICECOPY", n.Type)
}
if n.Left == nil {
Fatalf("missing len argument for OMAKESLICECOPY")
}
if n.Right == nil {
Fatalf("missing slice argument to copy for OMAKESLICECOPY")
}
n.Left = typecheck(n.Left, ctxExpr)
n.Right = typecheck(n.Right, ctxExpr)
n.Left = defaultlit(n.Left, types.Types[TINT])
if !n.Left.Type.IsInteger() && n.Type.Etype != TIDEAL {
yyerror("non-integer len argument in OMAKESLICECOPY")
}
if Isconst(n.Left, CTINT) {
if n.Left.Val().U.(*Mpint).Cmp(maxintval[TINT]) > 0 {
Fatalf("len for OMAKESLICECOPY too large")
}
if n.Left.Int64() < 0 {
Fatalf("len for OMAKESLICECOPY must be non-negative")
}
}
case OSLICE, OSLICE3:
ok |= ctxExpr
n.Left = typecheck(n.Left, ctxExpr)

View File

@ -1390,6 +1390,63 @@ opswitch:
n = m
}
case OMAKESLICECOPY:
if n.Esc == EscNone {
Fatalf("OMAKESLICECOPY with EscNone: %v", n)
}
t := n.Type
if t.Elem().NotInHeap() {
Fatalf("%v is go:notinheap; heap allocation disallowed", t.Elem())
}
length := conv(n.Left, types.Types[TINT])
copylen := nod(OLEN, n.Right, nil)
copyptr := nod(OSPTR, n.Right, nil)
if !types.Haspointers(t.Elem()) && n.Bounded() {
// When len(to)==len(from) and elements have no pointers:
// replace make+copy with runtime.mallocgc+runtime.memmove.
// We do not check for overflow of len(to)*elem.Width here
// since len(from) is an existing checked slice capacity
// with same elem.Width for the from slice.
size := nod(OMUL, conv(length, types.Types[TUINTPTR]), conv(nodintconst(t.Elem().Width), types.Types[TUINTPTR]))
// instantiate mallocgc(size uintptr, typ *byte, needszero bool) unsafe.Pointer
fn := syslook("mallocgc")
sh := nod(OSLICEHEADER, nil, nil)
sh.Left = mkcall1(fn, types.Types[TUNSAFEPTR], init, size, nodnil(), nodbool(false))
sh.Left.MarkNonNil()
sh.List.Set2(length, length)
sh.Type = t
s := temp(t)
r := typecheck(nod(OAS, s, sh), ctxStmt)
r = walkexpr(r, init)
init.Append(r)
// instantiate memmove(to *any, frm *any, size uintptr)
fn = syslook("memmove")
fn = substArgTypes(fn, t.Elem(), t.Elem())
ncopy := mkcall1(fn, nil, init, nod(OSPTR, s, nil), copyptr, size)
ncopy = typecheck(ncopy, ctxStmt)
ncopy = walkexpr(ncopy, init)
init.Append(ncopy)
n = s
} else { // Replace make+copy with runtime.makeslicecopy.
// instantiate makeslicecopy(typ *byte, tolen int, fromlen int, from unsafe.Pointer) unsafe.Pointer
fn := syslook("makeslicecopy")
s := nod(OSLICEHEADER, nil, nil)
s.Left = mkcall1(fn, types.Types[TUNSAFEPTR], init, typename(t.Elem()), length, copylen, conv(copyptr, types.Types[TUNSAFEPTR]))
s.Left.MarkNonNil()
s.List.Set2(length, length)
s.Type = t
n = typecheck(s, ctxExpr)
n = walkexpr(n, init)
}
case ORUNESTR:
a := nodnil()
if n.Esc == EscNone {
@ -3772,6 +3829,9 @@ func candiscard(n *Node) bool {
// Difficult to tell what sizes are okay.
case OMAKESLICE:
return false
case OMAKESLICECOPY:
return false
}
if !candiscard(n.Left) || !candiscard(n.Right) || !candiscardlist(n.Ninit) || !candiscardlist(n.Nbody) || !candiscardlist(n.List) || !candiscardlist(n.Rlist) {

View File

@ -31,6 +31,55 @@ func panicmakeslicecap() {
panic(errorString("makeslice: cap out of range"))
}
// makeslicecopy allocates a slice of "tolen" elements of type "et",
// then copies "fromlen" elements of type "et" into that new allocation from "from".
func makeslicecopy(et *_type, tolen int, fromlen int, from unsafe.Pointer) unsafe.Pointer {
var tomem, copymem uintptr
if uintptr(tolen) > uintptr(fromlen) {
var overflow bool
tomem, overflow = math.MulUintptr(et.size, uintptr(tolen))
if overflow || tomem > maxAlloc || tolen < 0 {
panicmakeslicelen()
}
copymem = et.size * uintptr(fromlen)
} else {
// fromlen is a known good length providing and equal or greater than tolen,
// thereby making tolen a good slice length too as from and to slices have the
// same element width.
tomem = et.size * uintptr(tolen)
copymem = tomem
}
var to unsafe.Pointer
if et.ptrdata == 0 {
to = mallocgc(tomem, nil, false)
if copymem < tomem {
memclrNoHeapPointers(add(to, copymem), tomem-copymem)
}
} else {
// Note: can't use rawmem (which avoids zeroing of memory), because then GC can scan uninitialized memory.
to = mallocgc(tomem, et, true)
if writeBarrier.enabled {
// Only shade the pointers in old.array since we know the destination slice to
// only contains nil pointers because it has been cleared during alloc.
bulkBarrierPreWriteSrcOnly(uintptr(to), uintptr(from), copymem)
}
}
if raceenabled {
callerpc := getcallerpc()
pc := funcPC(makeslicecopy)
racereadrangepc(from, copymem, callerpc, pc)
}
if msanenabled {
msanread(from, copymem)
}
memmove(to, from, copymem)
return to
}
func makeslice(et *_type, len, cap int) unsafe.Pointer {
mem, overflow := math.MulUintptr(et.size, uintptr(cap))
if overflow || mem > maxAlloc || len < 0 || len > cap {

View File

@ -10,6 +10,84 @@ import (
const N = 20
func BenchmarkMakeSliceCopy(b *testing.B) {
const length = 32
var bytes = make([]byte, 8*length)
var ints = make([]int, length)
var ptrs = make([]*byte, length)
b.Run("mallocmove", func(b *testing.B) {
b.Run("Byte", func(b *testing.B) {
var x []byte
for i := 0; i < b.N; i++ {
x = make([]byte, len(bytes))
copy(x, bytes)
}
})
b.Run("Int", func(b *testing.B) {
var x []int
for i := 0; i < b.N; i++ {
x = make([]int, len(ints))
copy(x, ints)
}
})
b.Run("Ptr", func(b *testing.B) {
var x []*byte
for i := 0; i < b.N; i++ {
x = make([]*byte, len(ptrs))
copy(x, ptrs)
}
})
})
b.Run("makecopy", func(b *testing.B) {
b.Run("Byte", func(b *testing.B) {
var x []byte
for i := 0; i < b.N; i++ {
x = make([]byte, 8*length)
copy(x, bytes)
}
})
b.Run("Int", func(b *testing.B) {
var x []int
for i := 0; i < b.N; i++ {
x = make([]int, length)
copy(x, ints)
}
})
b.Run("Ptr", func(b *testing.B) {
var x []*byte
for i := 0; i < b.N; i++ {
x = make([]*byte, length)
copy(x, ptrs)
}
})
})
b.Run("nilappend", func(b *testing.B) {
b.Run("Byte", func(b *testing.B) {
var x []byte
for i := 0; i < b.N; i++ {
x = append([]byte(nil), bytes...)
_ = x
}
})
b.Run("Int", func(b *testing.B) {
var x []int
for i := 0; i < b.N; i++ {
x = append([]int(nil), ints...)
_ = x
}
})
b.Run("Ptr", func(b *testing.B) {
var x []*byte
for i := 0; i < b.N; i++ {
x = append([]*byte(nil), ptrs...)
_ = x
}
})
})
}
type (
struct24 struct{ a, b, c int64 }
struct32 struct{ a, b, c, d int64 }

View File

@ -104,6 +104,189 @@ func SliceExtensionInt64(s []int, l64 int64) []int {
return append(s, make([]int, l64)...)
}
// ------------------ //
// Make+Copy //
// ------------------ //
// Issue #26252 - avoid memclr for make+copy
func SliceMakeCopyLen(s []int) []int {
// amd64:`.*runtime\.mallocgc`
// amd64:`.*runtime\.memmove`
// amd64:-`.*runtime\.makeslice`
a := make([]int, len(s))
copy(a, s)
return a
}
func SliceMakeCopyLenPtr(s []*int) []*int {
// amd64:`.*runtime\.makeslicecopy`
// amd64:-`.*runtime\.makeslice\(`
// amd64:-`.*runtime\.typedslicecopy
a := make([]*int, len(s))
copy(a, s)
return a
}
func SliceMakeCopyConst(s []int) []int {
// amd64:`.*runtime\.makeslicecopy`
// amd64:-`.*runtime\.makeslice\(`
// amd64:-`.*runtime\.memmove`
a := make([]int, 4)
copy(a, s)
return a
}
func SliceMakeCopyConstPtr(s []*int) []*int {
// amd64:`.*runtime\.makeslicecopy`
// amd64:-`.*runtime\.makeslice\(`
// amd64:-`.*runtime\.typedslicecopy
a := make([]*int, 4)
copy(a, s)
return a
}
func SliceMakeCopyNoOptNoDeref(s []*int) []*int {
a := new([]*int)
// amd64:-`.*runtime\.makeslicecopy`
// amd64:`.*runtime\.makeslice\(`
*a = make([]*int, 4)
// amd64:-`.*runtime\.makeslicecopy`
// amd64:`.*runtime\.typedslicecopy`
copy(*a, s)
return *a
}
func SliceMakeCopyNoOptNoVar(s []*int) []*int {
a := make([][]*int, 1)
// amd64:-`.*runtime\.makeslicecopy`
// amd64:`.*runtime\.makeslice\(`
a[0] = make([]*int, 4)
// amd64:-`.*runtime\.makeslicecopy`
// amd64:`.*runtime\.typedslicecopy`
copy(a[0], s)
return a[0]
}
func SliceMakeCopyNoOptBlank(s []*int) []*int {
var a []*int
// amd64:-`.*runtime\.makeslicecopy`
_ = make([]*int, 4)
// amd64:-`.*runtime\.makeslicecopy`
// amd64:`.*runtime\.typedslicecopy`
copy(a, s)
return a
}
func SliceMakeCopyNoOptNoMake(s []*int) []*int {
// amd64:-`.*runtime\.makeslicecopy`
// amd64:-`.*runtime\.objectnew`
a := *new([]*int)
// amd64:-`.*runtime\.makeslicecopy`
// amd64:`.*runtime\.typedslicecopy`
copy(a, s)
return a
}
func SliceMakeCopyNoOptNoHeapAlloc(s []*int) int {
// amd64:-`.*runtime\.makeslicecopy`
a := make([]*int, 4)
// amd64:-`.*runtime\.makeslicecopy`
// amd64:`.*runtime\.typedslicecopy`
copy(a, s)
return cap(a)
}
func SliceMakeCopyNoOptNoCap(s []*int) []*int {
// amd64:-`.*runtime\.makeslicecopy`
// amd64:`.*runtime\.makeslice\(`
a := make([]*int, 0, 4)
// amd64:-`.*runtime\.makeslicecopy`
// amd64:`.*runtime\.typedslicecopy`
copy(a, s)
return a
}
func SliceMakeCopyNoOptNoCopy(s []*int) []*int {
copy := func(x, y []*int) {}
// amd64:-`.*runtime\.makeslicecopy`
// amd64:`.*runtime\.makeslice\(`
a := make([]*int, 4)
// amd64:-`.*runtime\.makeslicecopy`
copy(a, s)
return a
}
func SliceMakeCopyNoOptWrongOrder(s []*int) []*int {
// amd64:-`.*runtime\.makeslicecopy`
// amd64:`.*runtime\.makeslice\(`
a := make([]*int, 4)
// amd64:`.*runtime\.typedslicecopy`
// amd64:-`.*runtime\.makeslicecopy`
copy(s, a)
return a
}
func SliceMakeCopyNoOptWrongAssign(s []*int) []*int {
var a []*int
// amd64:-`.*runtime\.makeslicecopy`
// amd64:`.*runtime\.makeslice\(`
s = make([]*int, 4)
// amd64:`.*runtime\.typedslicecopy`
// amd64:-`.*runtime\.makeslicecopy`
copy(a, s)
return s
}
func SliceMakeCopyNoOptCopyLength(s []*int) (int, []*int) {
// amd64:-`.*runtime\.makeslicecopy`
// amd64:`.*runtime\.makeslice\(`
a := make([]*int, 4)
// amd64:`.*runtime\.typedslicecopy`
// amd64:-`.*runtime\.makeslicecopy`
n := copy(a, s)
return n, a
}
func SliceMakeCopyNoOptSelfCopy(s []*int) []*int {
// amd64:-`.*runtime\.makeslicecopy`
// amd64:`.*runtime\.makeslice\(`
a := make([]*int, 4)
// amd64:`.*runtime\.typedslicecopy`
// amd64:-`.*runtime\.makeslicecopy`
copy(a, a)
return a
}
func SliceMakeCopyNoOptTargetReference(s []*int) []*int {
// amd64:-`.*runtime\.makeslicecopy`
// amd64:`.*runtime\.makeslice\(`
a := make([]*int, 4)
// amd64:`.*runtime\.typedslicecopy`
// amd64:-`.*runtime\.makeslicecopy`
copy(a, s[:len(a)])
return a
}
func SliceMakeCopyNoOptCap(s []int) []int {
// amd64:-`.*runtime\.makeslicecopy`
// amd64:`.*runtime\.makeslice\(`
a := make([]int, len(s), 9)
// amd64:-`.*runtime\.makeslicecopy`
// amd64:`.*runtime\.memmove`
copy(a, s)
return a
}
func SliceMakeCopyNoMemmoveDifferentLen(s []int) []int {
// amd64:`.*runtime\.makeslicecopy`
// amd64:-`.*runtime\.memmove`
a := make([]int, len(s)-1)
// amd64:-`.*runtime\.memmove`
copy(a, s)
return a
}
// ---------------------- //
// Nil check of &s[0] //
// ---------------------- //

149
test/makeslice.go Normal file
View File

@ -0,0 +1,149 @@
// run
// Copyright 2013 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.
package main
import (
"strings"
"unsafe"
)
func main() {
n := -1
testInts(uint64(n))
testBytes(uint64(n))
var t *byte
if unsafe.Sizeof(t) == 8 {
// Test mem > maxAlloc
testInts(1 << 59)
// Test elem.size*cap overflow
testInts(1<<63 - 1)
testInts(1<<64 - 1)
testBytes(1<<64 - 1)
} else {
testInts(1<<31 - 1)
// Test elem.size*cap overflow
testInts(1<<32 - 1)
testBytes(1<<32 - 1)
}
}
func shouldPanic(str string, f func()) {
defer func() {
err := recover()
if err == nil {
panic("did not panic")
}
s := err.(error).Error()
if !strings.Contains(s, str) {
panic("got panic " + s + ", want " + str)
}
}()
f()
}
func testInts(n uint64) {
testMakeInts(n)
testMakeCopyInts(n)
testMakeInAppendInts(n)
}
func testBytes(n uint64) {
testMakeBytes(n)
testMakeCopyBytes(n)
testMakeInAppendBytes(n)
}
// Test make panics for given length or capacity n.
func testMakeInts(n uint64) {
type T []int
shouldPanic("len out of range", func() { _ = make(T, int(n)) })
shouldPanic("cap out of range", func() { _ = make(T, 0, int(n)) })
shouldPanic("len out of range", func() { _ = make(T, uint(n)) })
shouldPanic("cap out of range", func() { _ = make(T, 0, uint(n)) })
shouldPanic("len out of range", func() { _ = make(T, int64(n)) })
shouldPanic("cap out of range", func() { _ = make(T, 0, int64(n)) })
shouldPanic("len out of range", func() { _ = make(T, uint64(n)) })
shouldPanic("cap out of range", func() { _ = make(T, 0, uint64(n)) })
}
func testMakeBytes(n uint64) {
type T []byte
shouldPanic("len out of range", func() { _ = make(T, int(n)) })
shouldPanic("cap out of range", func() { _ = make(T, 0, int(n)) })
shouldPanic("len out of range", func() { _ = make(T, uint(n)) })
shouldPanic("cap out of range", func() { _ = make(T, 0, uint(n)) })
shouldPanic("len out of range", func() { _ = make(T, int64(n)) })
shouldPanic("cap out of range", func() { _ = make(T, 0, int64(n)) })
shouldPanic("len out of range", func() { _ = make(T, uint64(n)) })
shouldPanic("cap out of range", func() { _ = make(T, 0, uint64(n)) })
}
// Test make+copy panics since the gc compiler optimizes these
// to runtime.makeslicecopy calls.
func testMakeCopyInts(n uint64) {
type T []int
var c = make(T, 8)
shouldPanic("len out of range", func() { x := make(T, int(n)); copy(x, c) })
shouldPanic("cap out of range", func() { x := make(T, 0, int(n)); copy(x, c) })
shouldPanic("len out of range", func() { x := make(T, uint(n)); copy(x, c) })
shouldPanic("cap out of range", func() { x := make(T, 0, uint(n)); copy(x, c) })
shouldPanic("len out of range", func() { x := make(T, int64(n)); copy(x, c) })
shouldPanic("cap out of range", func() { x := make(T, 0, int64(n)); copy(x, c) })
shouldPanic("len out of range", func() { x := make(T, uint64(n)); copy(x, c) })
shouldPanic("cap out of range", func() { x := make(T, 0, uint64(n)); copy(x, c) })
}
func testMakeCopyBytes(n uint64) {
type T []byte
var c = make(T, 8)
shouldPanic("len out of range", func() { x := make(T, int(n)); copy(x, c) })
shouldPanic("cap out of range", func() { x := make(T, 0, int(n)); copy(x, c) })
shouldPanic("len out of range", func() { x := make(T, uint(n)); copy(x, c) })
shouldPanic("cap out of range", func() { x := make(T, 0, uint(n)); copy(x, c) })
shouldPanic("len out of range", func() { x := make(T, int64(n)); copy(x, c) })
shouldPanic("cap out of range", func() { x := make(T, 0, int64(n)); copy(x, c) })
shouldPanic("len out of range", func() { x := make(T, uint64(n)); copy(x, c) })
shouldPanic("cap out of range", func() { x := make(T, 0, uint64(n)); copy(x, c) })
}
// Test make in append panics for int slices since the gc compiler optimizes makes in appends.
func testMakeInAppendInts(n uint64) {
type T []int
for _, length := range []int{0, 1} {
t := make(T, length)
shouldPanic("len out of range", func() { _ = append(t, make(T, int(n))...) })
shouldPanic("cap out of range", func() { _ = append(t, make(T, 0, int(n))...) })
shouldPanic("len out of range", func() { _ = append(t, make(T, int64(n))...) })
shouldPanic("cap out of range", func() { _ = append(t, make(T, 0, int64(n))...) })
shouldPanic("len out of range", func() { _ = append(t, make(T, uint64(n))...) })
shouldPanic("cap out of range", func() { _ = append(t, make(T, 0, uint64(n))...) })
shouldPanic("len out of range", func() { _ = append(t, make(T, int(n))...) })
shouldPanic("cap out of range", func() { _ = append(t, make(T, 0, int(n))...) })
shouldPanic("len out of range", func() { _ = append(t, make(T, uint(n))...) })
shouldPanic("cap out of range", func() { _ = append(t, make(T, 0, uint(n))...) })
}
}
func testMakeInAppendBytes(n uint64) {
type T []byte
for _, length := range []int{0, 1} {
t := make(T, length)
shouldPanic("len out of range", func() { _ = append(t, make(T, int(n))...) })
shouldPanic("cap out of range", func() { _ = append(t, make(T, 0, int(n))...) })
shouldPanic("len out of range", func() { _ = append(t, make(T, uint(n))...) })
shouldPanic("cap out of range", func() { _ = append(t, make(T, 0, uint(n))...) })
shouldPanic("len out of range", func() { _ = append(t, make(T, int64(n))...) })
shouldPanic("cap out of range", func() { _ = append(t, make(T, 0, int64(n))...) })
shouldPanic("len out of range", func() { _ = append(t, make(T, uint64(n))...) })
shouldPanic("cap out of range", func() { _ = append(t, make(T, 0, uint64(n))...) })
}
}