[dev.typeparams] cmd/compile: simplify interface conversions

Simplify the implementation of interface conversions in the compiler.
Don't pass fields that aren't needed (the data word, usually) to the runtime.

For generics, we need to put a dynamic type in an interface. The new
dataWord function is exactly what we need (the type word will come
from a dictionary).

Change-Id: Iade5de5c174854b65ad248f35c7893c603f7be3d
Reviewed-on: https://go-review.googlesource.com/c/go/+/340029
Trust: Keith Randall <khr@golang.org>
Trust: Dan Scales <danscales@google.com>
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Dan Scales <danscales@google.com>
This commit is contained in:
Keith Randall 2021-08-04 22:18:23 -07:00
parent d10a904712
commit 57668b84ff
10 changed files with 396 additions and 463 deletions

View file

@ -71,137 +71,135 @@ var runtimeDecls = [...]struct {
{"slicecopy", funcTag, 54}, {"slicecopy", funcTag, 54},
{"decoderune", funcTag, 55}, {"decoderune", funcTag, 55},
{"countrunes", funcTag, 56}, {"countrunes", funcTag, 56},
{"convI2I", funcTag, 57}, {"convI2I", funcTag, 58},
{"convT16", funcTag, 59}, {"convT", funcTag, 59},
{"convT32", funcTag, 61}, {"convTnoptr", funcTag, 59},
{"convT64", funcTag, 62}, {"convT16", funcTag, 61},
{"convTstring", funcTag, 63}, {"convT32", funcTag, 63},
{"convTslice", funcTag, 66}, {"convT64", funcTag, 64},
{"convT2E", funcTag, 67}, {"convTstring", funcTag, 65},
{"convT2Enoptr", funcTag, 67}, {"convTslice", funcTag, 68},
{"convT2I", funcTag, 67}, {"assertE2I", funcTag, 69},
{"convT2Inoptr", funcTag, 67}, {"assertE2I2", funcTag, 70},
{"assertE2I", funcTag, 68}, {"assertI2I", funcTag, 69},
{"assertE2I2", funcTag, 57}, {"assertI2I2", funcTag, 70},
{"assertI2I", funcTag, 68}, {"panicdottypeE", funcTag, 71},
{"assertI2I2", funcTag, 57}, {"panicdottypeI", funcTag, 71},
{"panicdottypeE", funcTag, 69}, {"panicnildottype", funcTag, 72},
{"panicdottypeI", funcTag, 69}, {"ifaceeq", funcTag, 73},
{"panicnildottype", funcTag, 70}, {"efaceeq", funcTag, 73},
{"ifaceeq", funcTag, 72}, {"fastrand", funcTag, 74},
{"efaceeq", funcTag, 72}, {"makemap64", funcTag, 76},
{"fastrand", funcTag, 73}, {"makemap", funcTag, 77},
{"makemap64", funcTag, 75}, {"makemap_small", funcTag, 78},
{"makemap", funcTag, 76}, {"mapaccess1", funcTag, 79},
{"makemap_small", funcTag, 77}, {"mapaccess1_fast32", funcTag, 80},
{"mapaccess1", funcTag, 78}, {"mapaccess1_fast64", funcTag, 81},
{"mapaccess1_fast32", funcTag, 79}, {"mapaccess1_faststr", funcTag, 82},
{"mapaccess1_fast64", funcTag, 80}, {"mapaccess1_fat", funcTag, 83},
{"mapaccess1_faststr", funcTag, 81}, {"mapaccess2", funcTag, 84},
{"mapaccess1_fat", funcTag, 82}, {"mapaccess2_fast32", funcTag, 85},
{"mapaccess2", funcTag, 83}, {"mapaccess2_fast64", funcTag, 86},
{"mapaccess2_fast32", funcTag, 84}, {"mapaccess2_faststr", funcTag, 87},
{"mapaccess2_fast64", funcTag, 85}, {"mapaccess2_fat", funcTag, 88},
{"mapaccess2_faststr", funcTag, 86}, {"mapassign", funcTag, 79},
{"mapaccess2_fat", funcTag, 87}, {"mapassign_fast32", funcTag, 80},
{"mapassign", funcTag, 78}, {"mapassign_fast32ptr", funcTag, 89},
{"mapassign_fast32", funcTag, 79}, {"mapassign_fast64", funcTag, 81},
{"mapassign_fast32ptr", funcTag, 88}, {"mapassign_fast64ptr", funcTag, 89},
{"mapassign_fast64", funcTag, 80}, {"mapassign_faststr", funcTag, 82},
{"mapassign_fast64ptr", funcTag, 88}, {"mapiterinit", funcTag, 90},
{"mapassign_faststr", funcTag, 81}, {"mapdelete", funcTag, 90},
{"mapiterinit", funcTag, 89}, {"mapdelete_fast32", funcTag, 91},
{"mapdelete", funcTag, 89}, {"mapdelete_fast64", funcTag, 92},
{"mapdelete_fast32", funcTag, 90}, {"mapdelete_faststr", funcTag, 93},
{"mapdelete_fast64", funcTag, 91}, {"mapiternext", funcTag, 94},
{"mapdelete_faststr", funcTag, 92}, {"mapclear", funcTag, 95},
{"mapiternext", funcTag, 93}, {"makechan64", funcTag, 97},
{"mapclear", funcTag, 94}, {"makechan", funcTag, 98},
{"makechan64", funcTag, 96}, {"chanrecv1", funcTag, 100},
{"makechan", funcTag, 97}, {"chanrecv2", funcTag, 101},
{"chanrecv1", funcTag, 99}, {"chansend1", funcTag, 103},
{"chanrecv2", funcTag, 100},
{"chansend1", funcTag, 102},
{"closechan", funcTag, 30}, {"closechan", funcTag, 30},
{"writeBarrier", varTag, 104}, {"writeBarrier", varTag, 105},
{"typedmemmove", funcTag, 105}, {"typedmemmove", funcTag, 106},
{"typedmemclr", funcTag, 106}, {"typedmemclr", funcTag, 107},
{"typedslicecopy", funcTag, 107}, {"typedslicecopy", funcTag, 108},
{"selectnbsend", funcTag, 108}, {"selectnbsend", funcTag, 109},
{"selectnbrecv", funcTag, 109}, {"selectnbrecv", funcTag, 110},
{"selectsetpc", funcTag, 110}, {"selectsetpc", funcTag, 111},
{"selectgo", funcTag, 111}, {"selectgo", funcTag, 112},
{"block", funcTag, 9}, {"block", funcTag, 9},
{"makeslice", funcTag, 112}, {"makeslice", funcTag, 113},
{"makeslice64", funcTag, 113}, {"makeslice64", funcTag, 114},
{"makeslicecopy", funcTag, 114}, {"makeslicecopy", funcTag, 115},
{"growslice", funcTag, 116}, {"growslice", funcTag, 117},
{"unsafeslice", funcTag, 117}, {"unsafeslice", funcTag, 118},
{"unsafeslice64", funcTag, 118}, {"unsafeslice64", funcTag, 119},
{"unsafeslicecheckptr", funcTag, 118}, {"unsafeslicecheckptr", funcTag, 119},
{"memmove", funcTag, 119}, {"memmove", funcTag, 120},
{"memclrNoHeapPointers", funcTag, 120}, {"memclrNoHeapPointers", funcTag, 121},
{"memclrHasPointers", funcTag, 120}, {"memclrHasPointers", funcTag, 121},
{"memequal", funcTag, 121}, {"memequal", funcTag, 122},
{"memequal0", funcTag, 122}, {"memequal0", funcTag, 123},
{"memequal8", funcTag, 122}, {"memequal8", funcTag, 123},
{"memequal16", funcTag, 122}, {"memequal16", funcTag, 123},
{"memequal32", funcTag, 122}, {"memequal32", funcTag, 123},
{"memequal64", funcTag, 122}, {"memequal64", funcTag, 123},
{"memequal128", funcTag, 122}, {"memequal128", funcTag, 123},
{"f32equal", funcTag, 123}, {"f32equal", funcTag, 124},
{"f64equal", funcTag, 123}, {"f64equal", funcTag, 124},
{"c64equal", funcTag, 123}, {"c64equal", funcTag, 124},
{"c128equal", funcTag, 123}, {"c128equal", funcTag, 124},
{"strequal", funcTag, 123}, {"strequal", funcTag, 124},
{"interequal", funcTag, 123}, {"interequal", funcTag, 124},
{"nilinterequal", funcTag, 123}, {"nilinterequal", funcTag, 124},
{"memhash", funcTag, 124}, {"memhash", funcTag, 125},
{"memhash0", funcTag, 125}, {"memhash0", funcTag, 126},
{"memhash8", funcTag, 125}, {"memhash8", funcTag, 126},
{"memhash16", funcTag, 125}, {"memhash16", funcTag, 126},
{"memhash32", funcTag, 125}, {"memhash32", funcTag, 126},
{"memhash64", funcTag, 125}, {"memhash64", funcTag, 126},
{"memhash128", funcTag, 125}, {"memhash128", funcTag, 126},
{"f32hash", funcTag, 125}, {"f32hash", funcTag, 126},
{"f64hash", funcTag, 125}, {"f64hash", funcTag, 126},
{"c64hash", funcTag, 125}, {"c64hash", funcTag, 126},
{"c128hash", funcTag, 125}, {"c128hash", funcTag, 126},
{"strhash", funcTag, 125}, {"strhash", funcTag, 126},
{"interhash", funcTag, 125}, {"interhash", funcTag, 126},
{"nilinterhash", funcTag, 125}, {"nilinterhash", funcTag, 126},
{"int64div", funcTag, 126}, {"int64div", funcTag, 127},
{"uint64div", funcTag, 127}, {"uint64div", funcTag, 128},
{"int64mod", funcTag, 126}, {"int64mod", funcTag, 127},
{"uint64mod", funcTag, 127}, {"uint64mod", funcTag, 128},
{"float64toint64", funcTag, 128}, {"float64toint64", funcTag, 129},
{"float64touint64", funcTag, 129}, {"float64touint64", funcTag, 130},
{"float64touint32", funcTag, 130}, {"float64touint32", funcTag, 131},
{"int64tofloat64", funcTag, 131}, {"int64tofloat64", funcTag, 132},
{"uint64tofloat64", funcTag, 132}, {"uint64tofloat64", funcTag, 133},
{"uint32tofloat64", funcTag, 133}, {"uint32tofloat64", funcTag, 134},
{"complex128div", funcTag, 134}, {"complex128div", funcTag, 135},
{"getcallerpc", funcTag, 135}, {"getcallerpc", funcTag, 136},
{"getcallersp", funcTag, 135}, {"getcallersp", funcTag, 136},
{"racefuncenter", funcTag, 31}, {"racefuncenter", funcTag, 31},
{"racefuncexit", funcTag, 9}, {"racefuncexit", funcTag, 9},
{"raceread", funcTag, 31}, {"raceread", funcTag, 31},
{"racewrite", funcTag, 31}, {"racewrite", funcTag, 31},
{"racereadrange", funcTag, 136}, {"racereadrange", funcTag, 137},
{"racewriterange", funcTag, 136}, {"racewriterange", funcTag, 137},
{"msanread", funcTag, 136}, {"msanread", funcTag, 137},
{"msanwrite", funcTag, 136}, {"msanwrite", funcTag, 137},
{"msanmove", funcTag, 137}, {"msanmove", funcTag, 138},
{"checkptrAlignment", funcTag, 138}, {"checkptrAlignment", funcTag, 139},
{"checkptrArithmetic", funcTag, 140}, {"checkptrArithmetic", funcTag, 141},
{"libfuzzerTraceCmp1", funcTag, 141}, {"libfuzzerTraceCmp1", funcTag, 142},
{"libfuzzerTraceCmp2", funcTag, 142}, {"libfuzzerTraceCmp2", funcTag, 143},
{"libfuzzerTraceCmp4", funcTag, 143}, {"libfuzzerTraceCmp4", funcTag, 144},
{"libfuzzerTraceCmp8", funcTag, 144}, {"libfuzzerTraceCmp8", funcTag, 145},
{"libfuzzerTraceConstCmp1", funcTag, 141}, {"libfuzzerTraceConstCmp1", funcTag, 142},
{"libfuzzerTraceConstCmp2", funcTag, 142}, {"libfuzzerTraceConstCmp2", funcTag, 143},
{"libfuzzerTraceConstCmp4", funcTag, 143}, {"libfuzzerTraceConstCmp4", funcTag, 144},
{"libfuzzerTraceConstCmp8", funcTag, 144}, {"libfuzzerTraceConstCmp8", funcTag, 145},
{"x86HasPOPCNT", varTag, 6}, {"x86HasPOPCNT", varTag, 6},
{"x86HasSSE41", varTag, 6}, {"x86HasSSE41", varTag, 6},
{"x86HasFMA", varTag, 6}, {"x86HasFMA", varTag, 6},
@ -224,7 +222,7 @@ func params(tlist ...*types.Type) []*types.Field {
} }
func runtimeTypes() []*types.Type { func runtimeTypes() []*types.Type {
var typs [145]*types.Type var typs [146]*types.Type
typs[0] = types.ByteType typs[0] = types.ByteType
typs[1] = types.NewPtr(typs[0]) typs[1] = types.NewPtr(typs[0])
typs[2] = types.Types[types.TANY] typs[2] = types.Types[types.TANY]
@ -282,93 +280,94 @@ func runtimeTypes() []*types.Type {
typs[54] = newSig(params(typs[3], typs[15], typs[3], typs[15], typs[5]), params(typs[15])) typs[54] = newSig(params(typs[3], typs[15], typs[3], typs[15], typs[5]), params(typs[15]))
typs[55] = newSig(params(typs[28], typs[15]), params(typs[46], typs[15])) typs[55] = newSig(params(typs[28], typs[15]), params(typs[46], typs[15]))
typs[56] = newSig(params(typs[28]), params(typs[15])) typs[56] = newSig(params(typs[28]), params(typs[15]))
typs[57] = newSig(params(typs[1], typs[2]), params(typs[2])) typs[57] = types.NewPtr(typs[5])
typs[58] = types.Types[types.TUINT16] typs[58] = newSig(params(typs[1], typs[57]), params(typs[57]))
typs[59] = newSig(params(typs[58]), params(typs[7])) typs[59] = newSig(params(typs[1], typs[3]), params(typs[7]))
typs[60] = types.Types[types.TUINT32] typs[60] = types.Types[types.TUINT16]
typs[61] = newSig(params(typs[60]), params(typs[7])) typs[61] = newSig(params(typs[60]), params(typs[7]))
typs[62] = newSig(params(typs[24]), params(typs[7])) typs[62] = types.Types[types.TUINT32]
typs[63] = newSig(params(typs[28]), params(typs[7])) typs[63] = newSig(params(typs[62]), params(typs[7]))
typs[64] = types.Types[types.TUINT8] typs[64] = newSig(params(typs[24]), params(typs[7]))
typs[65] = types.NewSlice(typs[64]) typs[65] = newSig(params(typs[28]), params(typs[7]))
typs[66] = newSig(params(typs[65]), params(typs[7])) typs[66] = types.Types[types.TUINT8]
typs[67] = newSig(params(typs[1], typs[3]), params(typs[2])) typs[67] = types.NewSlice(typs[66])
typs[68] = newSig(params(typs[1], typs[1]), params(typs[1])) typs[68] = newSig(params(typs[67]), params(typs[7]))
typs[69] = newSig(params(typs[1], typs[1], typs[1]), nil) typs[69] = newSig(params(typs[1], typs[1]), params(typs[1]))
typs[70] = newSig(params(typs[1]), nil) typs[70] = newSig(params(typs[1], typs[2]), params(typs[2]))
typs[71] = types.NewPtr(typs[5]) typs[71] = newSig(params(typs[1], typs[1], typs[1]), nil)
typs[72] = newSig(params(typs[71], typs[7], typs[7]), params(typs[6])) typs[72] = newSig(params(typs[1]), nil)
typs[73] = newSig(nil, params(typs[60])) typs[73] = newSig(params(typs[57], typs[7], typs[7]), params(typs[6]))
typs[74] = types.NewMap(typs[2], typs[2]) typs[74] = newSig(nil, params(typs[62]))
typs[75] = newSig(params(typs[1], typs[22], typs[3]), params(typs[74])) typs[75] = types.NewMap(typs[2], typs[2])
typs[76] = newSig(params(typs[1], typs[15], typs[3]), params(typs[74])) typs[76] = newSig(params(typs[1], typs[22], typs[3]), params(typs[75]))
typs[77] = newSig(nil, params(typs[74])) typs[77] = newSig(params(typs[1], typs[15], typs[3]), params(typs[75]))
typs[78] = newSig(params(typs[1], typs[74], typs[3]), params(typs[3])) typs[78] = newSig(nil, params(typs[75]))
typs[79] = newSig(params(typs[1], typs[74], typs[60]), params(typs[3])) typs[79] = newSig(params(typs[1], typs[75], typs[3]), params(typs[3]))
typs[80] = newSig(params(typs[1], typs[74], typs[24]), params(typs[3])) typs[80] = newSig(params(typs[1], typs[75], typs[62]), params(typs[3]))
typs[81] = newSig(params(typs[1], typs[74], typs[28]), params(typs[3])) typs[81] = newSig(params(typs[1], typs[75], typs[24]), params(typs[3]))
typs[82] = newSig(params(typs[1], typs[74], typs[3], typs[1]), params(typs[3])) typs[82] = newSig(params(typs[1], typs[75], typs[28]), params(typs[3]))
typs[83] = newSig(params(typs[1], typs[74], typs[3]), params(typs[3], typs[6])) typs[83] = newSig(params(typs[1], typs[75], typs[3], typs[1]), params(typs[3]))
typs[84] = newSig(params(typs[1], typs[74], typs[60]), params(typs[3], typs[6])) typs[84] = newSig(params(typs[1], typs[75], typs[3]), params(typs[3], typs[6]))
typs[85] = newSig(params(typs[1], typs[74], typs[24]), params(typs[3], typs[6])) typs[85] = newSig(params(typs[1], typs[75], typs[62]), params(typs[3], typs[6]))
typs[86] = newSig(params(typs[1], typs[74], typs[28]), params(typs[3], typs[6])) typs[86] = newSig(params(typs[1], typs[75], typs[24]), params(typs[3], typs[6]))
typs[87] = newSig(params(typs[1], typs[74], typs[3], typs[1]), params(typs[3], typs[6])) typs[87] = newSig(params(typs[1], typs[75], typs[28]), params(typs[3], typs[6]))
typs[88] = newSig(params(typs[1], typs[74], typs[7]), params(typs[3])) typs[88] = newSig(params(typs[1], typs[75], typs[3], typs[1]), params(typs[3], typs[6]))
typs[89] = newSig(params(typs[1], typs[74], typs[3]), nil) typs[89] = newSig(params(typs[1], typs[75], typs[7]), params(typs[3]))
typs[90] = newSig(params(typs[1], typs[74], typs[60]), nil) typs[90] = newSig(params(typs[1], typs[75], typs[3]), nil)
typs[91] = newSig(params(typs[1], typs[74], typs[24]), nil) typs[91] = newSig(params(typs[1], typs[75], typs[62]), nil)
typs[92] = newSig(params(typs[1], typs[74], typs[28]), nil) typs[92] = newSig(params(typs[1], typs[75], typs[24]), nil)
typs[93] = newSig(params(typs[3]), nil) typs[93] = newSig(params(typs[1], typs[75], typs[28]), nil)
typs[94] = newSig(params(typs[1], typs[74]), nil) typs[94] = newSig(params(typs[3]), nil)
typs[95] = types.NewChan(typs[2], types.Cboth) typs[95] = newSig(params(typs[1], typs[75]), nil)
typs[96] = newSig(params(typs[1], typs[22]), params(typs[95])) typs[96] = types.NewChan(typs[2], types.Cboth)
typs[97] = newSig(params(typs[1], typs[15]), params(typs[95])) typs[97] = newSig(params(typs[1], typs[22]), params(typs[96]))
typs[98] = types.NewChan(typs[2], types.Crecv) typs[98] = newSig(params(typs[1], typs[15]), params(typs[96]))
typs[99] = newSig(params(typs[98], typs[3]), nil) typs[99] = types.NewChan(typs[2], types.Crecv)
typs[100] = newSig(params(typs[98], typs[3]), params(typs[6])) typs[100] = newSig(params(typs[99], typs[3]), nil)
typs[101] = types.NewChan(typs[2], types.Csend) typs[101] = newSig(params(typs[99], typs[3]), params(typs[6]))
typs[102] = newSig(params(typs[101], typs[3]), nil) typs[102] = types.NewChan(typs[2], types.Csend)
typs[103] = types.NewArray(typs[0], 3) typs[103] = newSig(params(typs[102], typs[3]), nil)
typs[104] = types.NewStruct(types.NoPkg, []*types.Field{types.NewField(src.NoXPos, Lookup("enabled"), typs[6]), types.NewField(src.NoXPos, Lookup("pad"), typs[103]), types.NewField(src.NoXPos, Lookup("needed"), typs[6]), types.NewField(src.NoXPos, Lookup("cgo"), typs[6]), types.NewField(src.NoXPos, Lookup("alignme"), typs[24])}) typs[104] = types.NewArray(typs[0], 3)
typs[105] = newSig(params(typs[1], typs[3], typs[3]), nil) typs[105] = types.NewStruct(types.NoPkg, []*types.Field{types.NewField(src.NoXPos, Lookup("enabled"), typs[6]), types.NewField(src.NoXPos, Lookup("pad"), typs[104]), types.NewField(src.NoXPos, Lookup("needed"), typs[6]), types.NewField(src.NoXPos, Lookup("cgo"), typs[6]), types.NewField(src.NoXPos, Lookup("alignme"), typs[24])})
typs[106] = newSig(params(typs[1], typs[3]), nil) typs[106] = newSig(params(typs[1], typs[3], typs[3]), nil)
typs[107] = newSig(params(typs[1], typs[3], typs[15], typs[3], typs[15]), params(typs[15])) typs[107] = newSig(params(typs[1], typs[3]), nil)
typs[108] = newSig(params(typs[101], typs[3]), params(typs[6])) typs[108] = newSig(params(typs[1], typs[3], typs[15], typs[3], typs[15]), params(typs[15]))
typs[109] = newSig(params(typs[3], typs[98]), params(typs[6], typs[6])) typs[109] = newSig(params(typs[102], typs[3]), params(typs[6]))
typs[110] = newSig(params(typs[71]), nil) typs[110] = newSig(params(typs[3], typs[99]), params(typs[6], typs[6]))
typs[111] = newSig(params(typs[1], typs[1], typs[71], typs[15], typs[15], typs[6]), params(typs[15], typs[6])) typs[111] = newSig(params(typs[57]), nil)
typs[112] = newSig(params(typs[1], typs[15], typs[15]), params(typs[7])) typs[112] = newSig(params(typs[1], typs[1], typs[57], typs[15], typs[15], typs[6]), params(typs[15], typs[6]))
typs[113] = newSig(params(typs[1], typs[22], typs[22]), params(typs[7])) typs[113] = newSig(params(typs[1], typs[15], typs[15]), params(typs[7]))
typs[114] = newSig(params(typs[1], typs[15], typs[15], typs[7]), params(typs[7])) typs[114] = newSig(params(typs[1], typs[22], typs[22]), params(typs[7]))
typs[115] = types.NewSlice(typs[2]) typs[115] = newSig(params(typs[1], typs[15], typs[15], typs[7]), params(typs[7]))
typs[116] = newSig(params(typs[1], typs[115], typs[15]), params(typs[115])) typs[116] = types.NewSlice(typs[2])
typs[117] = newSig(params(typs[1], typs[7], typs[15]), nil) typs[117] = newSig(params(typs[1], typs[116], typs[15]), params(typs[116]))
typs[118] = newSig(params(typs[1], typs[7], typs[22]), nil) typs[118] = newSig(params(typs[1], typs[7], typs[15]), nil)
typs[119] = newSig(params(typs[3], typs[3], typs[5]), nil) typs[119] = newSig(params(typs[1], typs[7], typs[22]), nil)
typs[120] = newSig(params(typs[7], typs[5]), nil) typs[120] = newSig(params(typs[3], typs[3], typs[5]), nil)
typs[121] = newSig(params(typs[3], typs[3], typs[5]), params(typs[6])) typs[121] = newSig(params(typs[7], typs[5]), nil)
typs[122] = newSig(params(typs[3], typs[3]), params(typs[6])) typs[122] = newSig(params(typs[3], typs[3], typs[5]), params(typs[6]))
typs[123] = newSig(params(typs[7], typs[7]), params(typs[6])) typs[123] = newSig(params(typs[3], typs[3]), params(typs[6]))
typs[124] = newSig(params(typs[7], typs[5], typs[5]), params(typs[5])) typs[124] = newSig(params(typs[7], typs[7]), params(typs[6]))
typs[125] = newSig(params(typs[7], typs[5]), params(typs[5])) typs[125] = newSig(params(typs[7], typs[5], typs[5]), params(typs[5]))
typs[126] = newSig(params(typs[22], typs[22]), params(typs[22])) typs[126] = newSig(params(typs[7], typs[5]), params(typs[5]))
typs[127] = newSig(params(typs[24], typs[24]), params(typs[24])) typs[127] = newSig(params(typs[22], typs[22]), params(typs[22]))
typs[128] = newSig(params(typs[20]), params(typs[22])) typs[128] = newSig(params(typs[24], typs[24]), params(typs[24]))
typs[129] = newSig(params(typs[20]), params(typs[24])) typs[129] = newSig(params(typs[20]), params(typs[22]))
typs[130] = newSig(params(typs[20]), params(typs[60])) typs[130] = newSig(params(typs[20]), params(typs[24]))
typs[131] = newSig(params(typs[22]), params(typs[20])) typs[131] = newSig(params(typs[20]), params(typs[62]))
typs[132] = newSig(params(typs[24]), params(typs[20])) typs[132] = newSig(params(typs[22]), params(typs[20]))
typs[133] = newSig(params(typs[60]), params(typs[20])) typs[133] = newSig(params(typs[24]), params(typs[20]))
typs[134] = newSig(params(typs[26], typs[26]), params(typs[26])) typs[134] = newSig(params(typs[62]), params(typs[20]))
typs[135] = newSig(nil, params(typs[5])) typs[135] = newSig(params(typs[26], typs[26]), params(typs[26]))
typs[136] = newSig(params(typs[5], typs[5]), nil) typs[136] = newSig(nil, params(typs[5]))
typs[137] = newSig(params(typs[5], typs[5], typs[5]), nil) typs[137] = newSig(params(typs[5], typs[5]), nil)
typs[138] = newSig(params(typs[7], typs[1], typs[5]), nil) typs[138] = newSig(params(typs[5], typs[5], typs[5]), nil)
typs[139] = types.NewSlice(typs[7]) typs[139] = newSig(params(typs[7], typs[1], typs[5]), nil)
typs[140] = newSig(params(typs[7], typs[139]), nil) typs[140] = types.NewSlice(typs[7])
typs[141] = newSig(params(typs[64], typs[64]), nil) typs[141] = newSig(params(typs[7], typs[140]), nil)
typs[142] = newSig(params(typs[58], typs[58]), nil) typs[142] = newSig(params(typs[66], typs[66]), nil)
typs[143] = newSig(params(typs[60], typs[60]), nil) typs[143] = newSig(params(typs[60], typs[60]), nil)
typs[144] = newSig(params(typs[24], typs[24]), nil) typs[144] = newSig(params(typs[62], typs[62]), nil)
typs[145] = newSig(params(typs[24], typs[24]), nil)
return typs[:] return typs[:]
} }

View file

@ -84,10 +84,15 @@ func decoderune(string, int) (retv rune, retk int)
func countrunes(string) int func countrunes(string) int
// Non-empty-interface to non-empty-interface conversion. // Non-empty-interface to non-empty-interface conversion.
func convI2I(typ *byte, elem any) (ret any) func convI2I(typ *byte, itab *uintptr) (ret *uintptr)
// Specialized type-to-interface conversion. // Convert non-interface type to the data word of a (empty or nonempty) interface.
// These return only a data pointer. func convT(typ *byte, elem *any) unsafe.Pointer
// Same as convT, for types with no pointers in them.
func convTnoptr(typ *byte, elem *any) unsafe.Pointer
// Specialized versions of convT for specific types.
// These functions take concrete types in the runtime. But they may // These functions take concrete types in the runtime. But they may
// be used for a wider range of types, which have the same memory // be used for a wider range of types, which have the same memory
// layout as the parameter type. The compiler converts the // layout as the parameter type. The compiler converts the
@ -99,14 +104,6 @@ func convT64(val uint64) unsafe.Pointer
func convTstring(val string) unsafe.Pointer func convTstring(val string) unsafe.Pointer
func convTslice(val []uint8) unsafe.Pointer func convTslice(val []uint8) unsafe.Pointer
// Type to empty-interface conversion.
func convT2E(typ *byte, elem *any) (ret any)
func convT2Enoptr(typ *byte, elem *any) (ret any)
// Type to non-empty-interface conversion.
func convT2I(tab *byte, elem *any) (ret any)
func convT2Inoptr(tab *byte, elem *any) (ret any)
// interface type assertions x.(T) // interface type assertions x.(T)
func assertE2I(inter *byte, typ *byte) *byte func assertE2I(inter *byte, typ *byte) *byte
func assertE2I2(inter *byte, eface any) (ret any) func assertE2I2(inter *byte, eface any) (ret any)

View file

@ -39,56 +39,100 @@ func walkConv(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
return typecheck.Conv(mkcall(fn, types.Types[result], init, typecheck.Conv(n.X, types.Types[param])), n.Type()) return typecheck.Conv(mkcall(fn, types.Types[result], init, typecheck.Conv(n.X, types.Types[param])), n.Type())
} }
// walkConvInterface walks an OCONVIFACE or OCONVIDATA node. // walkConvInterface walks an OCONVIFACE node.
func walkConvInterface(n *ir.ConvExpr, init *ir.Nodes) ir.Node { func walkConvInterface(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
n.X = walkExpr(n.X, init) n.X = walkExpr(n.X, init)
fromType := n.X.Type() fromType := n.X.Type()
toType := n.Type() toType := n.Type()
if n.Op() == ir.OCONVIDATA { if !fromType.IsInterface() && !ir.IsBlank(ir.CurFunc.Nname) {
// Just convert to empty interface, to make it easy.
// The caller throws away the type word.
toType = types.NewInterface(types.LocalPkg, nil)
// Note: don't pass fromType to MarkTypeUsedInInterface because it is likely
// a shape type. The appropriate call to MarkTypeUsedInInterface will come
// when building the dictionary (from which the matching type word will come).
} else if !fromType.IsInterface() && !ir.IsBlank(ir.CurFunc.Nname) {
// skip unnamed functions (func _()) // skip unnamed functions (func _())
reflectdata.MarkTypeUsedInInterface(fromType, ir.CurFunc.LSym) reflectdata.MarkTypeUsedInInterface(fromType, ir.CurFunc.LSym)
} }
// typeword generates the type word of the interface value. if !fromType.IsInterface() {
typeword := func() ir.Node { var typeWord ir.Node
if toType.IsEmptyInterface() { if toType.IsEmptyInterface() {
return reflectdata.TypePtr(fromType) typeWord = reflectdata.TypePtr(fromType)
} else {
typeWord = reflectdata.ITabAddr(fromType, toType)
} }
return reflectdata.ITabAddr(fromType, toType) l := ir.NewBinaryExpr(base.Pos, ir.OEFACE, typeWord, dataWord(n.X, init, n.Esc() != ir.EscNone))
}
// Optimize convT2E or convT2I as a two-word copy when T is pointer-shaped.
if types.IsDirectIface(fromType) {
l := ir.NewBinaryExpr(base.Pos, ir.OEFACE, typeword(), n.X)
l.SetType(toType) l.SetType(toType)
l.SetTypecheck(n.Typecheck()) l.SetTypecheck(n.Typecheck())
return l return l
} }
if fromType.IsEmptyInterface() {
base.Fatalf("OCONVIFACE can't operate on an empty interface")
}
// Optimize convT2{E,I} for many cases in which T is not pointer-shaped, // Evaluate the input interface.
// by using an existing addressable value identical to n.Left c := typecheck.Temp(fromType)
// or creating one on the stack. init.Append(ir.NewAssignStmt(base.Pos, c, n.X))
// Grab its parts.
itab := ir.NewUnaryExpr(base.Pos, ir.OITAB, c)
itab.SetType(types.Types[types.TUINTPTR].PtrTo())
itab.SetTypecheck(1)
data := ir.NewUnaryExpr(base.Pos, ir.OIDATA, c)
data.SetType(types.Types[types.TUINT8].PtrTo()) // Type is generic pointer - we're just passing it through.
data.SetTypecheck(1)
var typeWord ir.Node
if toType.IsEmptyInterface() {
// Implement interface to empty interface conversion.
// res = itab
// if res != nil {
// res = res.type
// }
typeWord = typecheck.Temp(types.NewPtr(types.Types[types.TUINT8]))
init.Append(ir.NewAssignStmt(base.Pos, typeWord, itab))
nif := ir.NewIfStmt(base.Pos, typecheck.Expr(ir.NewBinaryExpr(base.Pos, ir.ONE, typeWord, typecheck.NodNil())), nil, nil)
nif.Body = []ir.Node{ir.NewAssignStmt(base.Pos, typeWord, itabType(typeWord))}
init.Append(nif)
} else {
// Must be converting I2I (more specific to less specific interface).
// res = convI2I(toType, itab)
fn := typecheck.LookupRuntime("convI2I")
types.CalcSize(fn.Type())
call := ir.NewCallExpr(base.Pos, ir.OCALL, fn, nil)
call.Args = []ir.Node{reflectdata.TypePtr(toType), itab}
typeWord = walkExpr(typecheck.Expr(call), init)
}
// Build the result.
// e = iface{typeWord, data}
e := ir.NewBinaryExpr(base.Pos, ir.OEFACE, typeWord, data)
e.SetType(toType) // assign type manually, typecheck doesn't understand OEFACE.
e.SetTypecheck(1)
return e
}
// Returns the data word (the second word) used to represent n in an interface.
// n must not be of interface type.
// esc describes whether the result escapes.
func dataWord(n ir.Node, init *ir.Nodes, escapes bool) ir.Node {
fromType := n.Type()
// If it's a pointer, it is its own representation.
if types.IsDirectIface(fromType) {
return n
}
// Try a bunch of cases to avoid an allocation.
var value ir.Node var value ir.Node
switch { switch {
case fromType.Size() == 0: case fromType.Size() == 0:
// n.Left is zero-sized. Use zerobase. // n is zero-sized. Use zerobase.
cheapExpr(n.X, init) // Evaluate n.Left for side-effects. See issue 19246. cheapExpr(n, init) // Evaluate n for side-effects. See issue 19246.
value = ir.NewLinksymExpr(base.Pos, ir.Syms.Zerobase, types.Types[types.TUINTPTR]) value = ir.NewLinksymExpr(base.Pos, ir.Syms.Zerobase, types.Types[types.TUINTPTR])
case fromType.IsBoolean() || (fromType.Size() == 1 && fromType.IsInteger()): case fromType.IsBoolean() || (fromType.Size() == 1 && fromType.IsInteger()):
// n.Left is a bool/byte. Use staticuint64s[n.Left * 8] on little-endian // n is a bool/byte. Use staticuint64s[n * 8] on little-endian
// and staticuint64s[n.Left * 8 + 7] on big-endian. // and staticuint64s[n * 8 + 7] on big-endian.
n.X = cheapExpr(n.X, init) n = cheapExpr(n, init)
// byteindex widens n.Left so that the multiplication doesn't overflow. // byteindex widens n so that the multiplication doesn't overflow.
index := ir.NewBinaryExpr(base.Pos, ir.OLSH, byteindex(n.X), ir.NewInt(3)) index := ir.NewBinaryExpr(base.Pos, ir.OLSH, byteindex(n), ir.NewInt(3))
if ssagen.Arch.LinkArch.ByteOrder == binary.BigEndian { if ssagen.Arch.LinkArch.ByteOrder == binary.BigEndian {
index = ir.NewBinaryExpr(base.Pos, ir.OADD, index, ir.NewInt(7)) index = ir.NewBinaryExpr(base.Pos, ir.OADD, index, ir.NewInt(7))
} }
@ -98,118 +142,71 @@ func walkConvInterface(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
xe := ir.NewIndexExpr(base.Pos, staticuint64s, index) xe := ir.NewIndexExpr(base.Pos, staticuint64s, index)
xe.SetBounded(true) xe.SetBounded(true)
value = xe value = xe
case n.X.Op() == ir.ONAME && n.X.(*ir.Name).Class == ir.PEXTERN && n.X.(*ir.Name).Readonly(): case n.Op() == ir.ONAME && n.(*ir.Name).Class == ir.PEXTERN && n.(*ir.Name).Readonly():
// n.Left is a readonly global; use it directly. // n is a readonly global; use it directly.
value = n.X value = n
case !fromType.IsInterface() && n.Esc() == ir.EscNone && fromType.Width <= 1024: case !escapes && fromType.Width <= 1024:
// n.Left does not escape. Use a stack temporary initialized to n.Left. // n does not escape. Use a stack temporary initialized to n.
value = typecheck.Temp(fromType) value = typecheck.Temp(fromType)
init.Append(typecheck.Stmt(ir.NewAssignStmt(base.Pos, value, n.X))) init.Append(typecheck.Stmt(ir.NewAssignStmt(base.Pos, value, n)))
} }
if value != nil { if value != nil {
// Value is identical to n.Left. // The interface data word is &value.
// Construct the interface directly: {type/itab, &value}. return typecheck.Expr(typecheck.NodAddr(value))
l := ir.NewBinaryExpr(base.Pos, ir.OEFACE, typeword(), typecheck.Expr(typecheck.NodAddr(value)))
l.SetType(toType)
l.SetTypecheck(n.Typecheck())
return l
} }
// Implement interface to empty interface conversion. // Time to do an allocation. We'll call into the runtime for that.
// tmp = i.itab fnname, argType, needsaddr := dataWordFuncName(fromType)
// if tmp != nil { fn := typecheck.LookupRuntime(fnname)
// tmp = tmp.type
// }
// e = iface{tmp, i.data}
if toType.IsEmptyInterface() && fromType.IsInterface() && !fromType.IsEmptyInterface() {
// Evaluate the input interface.
c := typecheck.Temp(fromType)
init.Append(ir.NewAssignStmt(base.Pos, c, n.X))
// Get the itab out of the interface. var args []ir.Node
tmp := typecheck.Temp(types.NewPtr(types.Types[types.TUINT8])) if needsaddr {
init.Append(ir.NewAssignStmt(base.Pos, tmp, typecheck.Expr(ir.NewUnaryExpr(base.Pos, ir.OITAB, c)))) // Types of large or unknown size are passed by reference.
// Orderexpr arranged for n to be a temporary for all
// Get the type out of the itab. // the conversions it could see. Comparison of an interface
nif := ir.NewIfStmt(base.Pos, typecheck.Expr(ir.NewBinaryExpr(base.Pos, ir.ONE, tmp, typecheck.NodNil())), nil, nil) // with a non-interface, especially in a switch on interface value
nif.Body = []ir.Node{ir.NewAssignStmt(base.Pos, tmp, itabType(tmp))} // with non-interface cases, is not visible to order.stmt, so we
init.Append(nif) // have to fall back on allocating a temp here.
if !ir.IsAddressable(n) {
// Build the result. n = copyExpr(n, fromType, init)
e := ir.NewBinaryExpr(base.Pos, ir.OEFACE, tmp, ifaceData(n.Pos(), c, types.NewPtr(types.Types[types.TUINT8]))) }
e.SetType(toType) // assign type manually, typecheck doesn't understand OEFACE. fn = typecheck.SubstArgTypes(fn, fromType)
e.SetTypecheck(1) args = []ir.Node{reflectdata.TypePtr(fromType), typecheck.NodAddr(n)}
return e } else {
} // Use a specialized conversion routine that takes the type being
// converted by value, not by pointer.
fnname, argType, needsaddr := convFuncName(fromType, toType) var arg ir.Node
if !needsaddr && !fromType.IsInterface() {
// Use a specialized conversion routine that only returns a data pointer.
// ptr = convT2X(val)
// e = iface{typ/tab, ptr}
fn := typecheck.LookupRuntime(fnname)
types.CalcSize(fromType)
arg := n.X
switch { switch {
case fromType == argType: case fromType == argType:
// already in the right type, nothing to do // already in the right type, nothing to do
arg = n
case fromType.Kind() == argType.Kind(), case fromType.Kind() == argType.Kind(),
fromType.IsPtrShaped() && argType.IsPtrShaped(): fromType.IsPtrShaped() && argType.IsPtrShaped():
// can directly convert (e.g. named type to underlying type, or one pointer to another) // can directly convert (e.g. named type to underlying type, or one pointer to another)
arg = ir.NewConvExpr(n.Pos(), ir.OCONVNOP, argType, arg) // TODO: never happens because pointers are directIface?
arg = ir.NewConvExpr(n.Pos(), ir.OCONVNOP, argType, n)
case fromType.IsInteger() && argType.IsInteger(): case fromType.IsInteger() && argType.IsInteger():
// can directly convert (e.g. int32 to uint32) // can directly convert (e.g. int32 to uint32)
arg = ir.NewConvExpr(n.Pos(), ir.OCONV, argType, arg) arg = ir.NewConvExpr(n.Pos(), ir.OCONV, argType, n)
default: default:
// unsafe cast through memory // unsafe cast through memory
arg = copyExpr(arg, arg.Type(), init) arg = copyExpr(n, fromType, init)
var addr ir.Node = typecheck.NodAddr(arg) var addr ir.Node = typecheck.NodAddr(arg)
addr = ir.NewConvExpr(n.Pos(), ir.OCONVNOP, argType.PtrTo(), addr) addr = ir.NewConvExpr(n.Pos(), ir.OCONVNOP, argType.PtrTo(), addr)
arg = ir.NewStarExpr(n.Pos(), addr) arg = ir.NewStarExpr(n.Pos(), addr)
arg.SetType(argType) arg.SetType(argType)
} }
args = []ir.Node{arg}
call := ir.NewCallExpr(base.Pos, ir.OCALL, fn, nil)
call.Args = []ir.Node{arg}
e := ir.NewBinaryExpr(base.Pos, ir.OEFACE, typeword(), safeExpr(walkExpr(typecheck.Expr(call), init), init))
e.SetType(toType)
e.SetTypecheck(1)
return e
} }
var tab ir.Node
if fromType.IsInterface() {
// convI2I
tab = reflectdata.TypePtr(toType)
} else {
// convT2x
tab = typeword()
}
v := n.X
if needsaddr {
// Types of large or unknown size are passed by reference.
// Orderexpr arranged for n.Left to be a temporary for all
// the conversions it could see. Comparison of an interface
// with a non-interface, especially in a switch on interface value
// with non-interface cases, is not visible to order.stmt, so we
// have to fall back on allocating a temp here.
if !ir.IsAddressable(v) {
v = copyExpr(v, v.Type(), init)
}
v = typecheck.NodAddr(v)
}
types.CalcSize(fromType)
fn := typecheck.LookupRuntime(fnname)
fn = typecheck.SubstArgTypes(fn, fromType, toType)
types.CalcSize(fn.Type())
call := ir.NewCallExpr(base.Pos, ir.OCALL, fn, nil) call := ir.NewCallExpr(base.Pos, ir.OCALL, fn, nil)
call.Args = []ir.Node{tab, v} call.Args = args
return walkExpr(typecheck.Expr(call), init) return safeExpr(walkExpr(typecheck.Expr(call), init), init)
}
// walkConvIData walks an OCONVIDATA node.
func walkConvIData(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
n.X = walkExpr(n.X, init)
return dataWord(n.X, init, n.Esc() != ir.EscNone)
} }
// walkBytesRunesToString walks an OBYTES2STR or ORUNES2STR node. // walkBytesRunesToString walks an OBYTES2STR or ORUNES2STR node.
@ -320,50 +317,35 @@ func walkStringToRunes(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
return mkcall("stringtoslicerune", n.Type(), init, a, typecheck.Conv(n.X, types.Types[types.TSTRING])) return mkcall("stringtoslicerune", n.Type(), init, a, typecheck.Conv(n.X, types.Types[types.TSTRING]))
} }
// convFuncName builds the runtime function name for interface conversion. // dataWordFuncName returns the name of the function used to convert a value of type "from"
// It also returns the argument type that the runtime function takes, and // to the data word of an interface.
// whether the function expects the data by address. // argType is the type the argument needs to be coerced to.
// Not all names are possible. For example, we never generate convE2E or convE2I. // needsaddr reports whether the value should be passed (needaddr==false) or its address (needsaddr==true).
func convFuncName(from, to *types.Type) (fnname string, argType *types.Type, needsaddr bool) { func dataWordFuncName(from *types.Type) (fnname string, argType *types.Type, needsaddr bool) {
tkind := to.Tie() if from.IsInterface() {
switch from.Tie() { base.Fatalf("can only handle non-interfaces")
case 'I': }
if tkind == 'I' { switch {
return "convI2I", types.Types[types.TINTER], false case from.Size() == 2 && from.Align == 2:
} return "convT16", types.Types[types.TUINT16], false
case 'T': case from.Size() == 4 && from.Align == 4 && !from.HasPointers():
return "convT32", types.Types[types.TUINT32], false
case from.Size() == 8 && from.Align == types.Types[types.TUINT64].Align && !from.HasPointers():
return "convT64", types.Types[types.TUINT64], false
}
if sc := from.SoleComponent(); sc != nil {
switch { switch {
case from.Size() == 2 && from.Align == 2: case sc.IsString():
return "convT16", types.Types[types.TUINT16], false return "convTstring", types.Types[types.TSTRING], false
case from.Size() == 4 && from.Align == 4 && !from.HasPointers(): case sc.IsSlice():
return "convT32", types.Types[types.TUINT32], false return "convTslice", types.NewSlice(types.Types[types.TUINT8]), false // the element type doesn't matter
case from.Size() == 8 && from.Align == types.Types[types.TUINT64].Align && !from.HasPointers():
return "convT64", types.Types[types.TUINT64], false
}
if sc := from.SoleComponent(); sc != nil {
switch {
case sc.IsString():
return "convTstring", types.Types[types.TSTRING], false
case sc.IsSlice():
return "convTslice", types.NewSlice(types.Types[types.TUINT8]), false // the element type doesn't matter
}
}
switch tkind {
case 'E':
if !from.HasPointers() {
return "convT2Enoptr", types.Types[types.TUNSAFEPTR], true
}
return "convT2E", types.Types[types.TUNSAFEPTR], true
case 'I':
if !from.HasPointers() {
return "convT2Inoptr", types.Types[types.TUNSAFEPTR], true
}
return "convT2I", types.Types[types.TUNSAFEPTR], true
} }
} }
base.Fatalf("unknown conv func %c2%c", from.Tie(), to.Tie())
panic("unreachable") if from.HasPointers() {
return "convT", types.Types[types.TUNSAFEPTR], true
}
return "convTnoptr", types.Types[types.TUNSAFEPTR], true
} }
// rtconvfn returns the parameter and result types that will be used by a // rtconvfn returns the parameter and result types that will be used by a

View file

@ -212,10 +212,7 @@ func walkExpr1(n ir.Node, init *ir.Nodes) ir.Node {
case ir.OCONVIDATA: case ir.OCONVIDATA:
n := n.(*ir.ConvExpr) n := n.(*ir.ConvExpr)
r := ir.NewUnaryExpr(n.Pos(), ir.OIDATA, walkConvInterface(n, init)) return walkConvIData(n, init)
r.SetType(types.Types[types.TUNSAFEPTR])
r.SetTypecheck(1)
return r
case ir.OCONV, ir.OCONVNOP: case ir.OCONV, ir.OCONVNOP:
n := n.(*ir.ConvExpr) n := n.(*ir.ConvExpr)

View file

@ -1166,11 +1166,7 @@ func (o *orderState) expr1(n, lhs ir.Node) ir.Node {
if n.X.Type().IsInterface() { if n.X.Type().IsInterface() {
return n return n
} }
to := n.Type() if _, _, needsaddr := dataWordFuncName(n.X.Type()); needsaddr || isStaticCompositeLiteral(n.X) {
if n.Op() == ir.OCONVIDATA {
to = types.NewInterface(types.LocalPkg, nil)
}
if _, _, needsaddr := convFuncName(n.X.Type(), to); needsaddr || isStaticCompositeLiteral(n.X) {
// Need a temp if we need to pass the address to the conversion function. // Need a temp if we need to pass the address to the conversion function.
// We also process static composite literal node here, making a named static global // We also process static composite literal node here, making a named static global
// whose address we can put directly in an interface (see OCONVIFACE/OCONVIDATA case in walk). // whose address we can put directly in an interface (see OCONVIFACE/OCONVIDATA case in walk).

View file

@ -316,20 +316,30 @@ var (
// The convXXX functions succeed on a nil input, whereas the assertXXX // The convXXX functions succeed on a nil input, whereas the assertXXX
// functions fail on a nil input. // functions fail on a nil input.
func convT2E(t *_type, elem unsafe.Pointer) (e eface) { // convT converts a value of type t, which is pointed to by v, to a pointer that can
// be used as the second word of an interface value.
func convT(t *_type, v unsafe.Pointer) unsafe.Pointer {
if raceenabled { if raceenabled {
raceReadObjectPC(t, elem, getcallerpc(), abi.FuncPCABIInternal(convT2E)) raceReadObjectPC(t, v, getcallerpc(), abi.FuncPCABIInternal(convT))
} }
if msanenabled { if msanenabled {
msanread(elem, t.size) msanread(v, t.size)
} }
x := mallocgc(t.size, t, true) x := mallocgc(t.size, t, true)
// TODO: We allocate a zeroed object only to overwrite it with actual data. typedmemmove(t, x, v)
// Figure out how to avoid zeroing. Also below in convT2Eslice, convT2I, convT2Islice. return x
typedmemmove(t, x, elem) }
e._type = t func convTnoptr(t *_type, v unsafe.Pointer) unsafe.Pointer {
e.data = x // TODO: maybe take size instead of type?
return if raceenabled {
raceReadObjectPC(t, v, getcallerpc(), abi.FuncPCABIInternal(convTnoptr))
}
if msanenabled {
msanread(v, t.size)
}
x := mallocgc(t.size, t, false)
memmove(x, v, t.size)
return x
} }
func convT16(val uint16) (x unsafe.Pointer) { func convT16(val uint16) (x unsafe.Pointer) {
@ -389,63 +399,16 @@ func convTslice(val []byte) (x unsafe.Pointer) {
return return
} }
func convT2Enoptr(t *_type, elem unsafe.Pointer) (e eface) { // convI2I returns the new itab to be used for the destination value
if raceenabled { // when converting a value with itab src to the dst interface.
raceReadObjectPC(t, elem, getcallerpc(), abi.FuncPCABIInternal(convT2Enoptr)) func convI2I(dst *interfacetype, src *itab) *itab {
if src == nil {
return nil
} }
if msanenabled { if src.inter == dst {
msanread(elem, t.size) return src
} }
x := mallocgc(t.size, t, false) return getitab(dst, src._type, false)
memmove(x, elem, t.size)
e._type = t
e.data = x
return
}
func convT2I(tab *itab, elem unsafe.Pointer) (i iface) {
t := tab._type
if raceenabled {
raceReadObjectPC(t, elem, getcallerpc(), abi.FuncPCABIInternal(convT2I))
}
if msanenabled {
msanread(elem, t.size)
}
x := mallocgc(t.size, t, true)
typedmemmove(t, x, elem)
i.tab = tab
i.data = x
return
}
func convT2Inoptr(tab *itab, elem unsafe.Pointer) (i iface) {
t := tab._type
if raceenabled {
raceReadObjectPC(t, elem, getcallerpc(), abi.FuncPCABIInternal(convT2Inoptr))
}
if msanenabled {
msanread(elem, t.size)
}
x := mallocgc(t.size, t, false)
memmove(x, elem, t.size)
i.tab = tab
i.data = x
return
}
func convI2I(inter *interfacetype, i iface) (r iface) {
tab := i.tab
if tab == nil {
return
}
if tab.inter == inter {
r.tab = tab
r.data = i.data
return
}
r.tab = getitab(inter, tab._type, false)
r.data = i.data
return
} }
func assertI2I(inter *interfacetype, tab *itab) *itab { func assertI2I(inter *interfacetype, tab *itab) *itab {

View file

@ -31,9 +31,8 @@ func main() {
panic("not 3") panic("not 3")
} }
// Can't do types that aren't "direct" interfaces (yet).
r = indirectiface{3, 4, 5} r = indirectiface{3, 4, 5}
if r.Value() != 12 { if r.Value() != 12 { // ERROR "de-virtualizing call$"
panic("not 12") panic("not 12")
} }
} }

View file

@ -17,7 +17,7 @@ type T struct {
func f(a T) { // ERROR "live at entry to f: a" func f(a T) { // ERROR "live at entry to f: a"
var e interface{} // ERROR "stack object e interface \{\}$" var e interface{} // ERROR "stack object e interface \{\}$"
func() { // ERROR "live at entry to f.func1: a &e" func() { // ERROR "live at entry to f.func1: a &e"
e = a.s // ERROR "live at call to convT2E: &e" "stack object a T$" e = a.s // ERROR "live at call to convT: &e" "stack object a T$"
}() }()
// Before the fix, both a and e were live at the previous line. // Before the fix, both a and e were live at the previous line.
_ = e _ = e

View file

@ -144,8 +144,8 @@ var i9 interface{}
func f9() bool { func f9() bool {
g8() g8()
x := i9 x := i9
y := interface{}(g18()) // ERROR "live at call to convT2E: x.data$" "live at call to g18: x.data$" "stack object .autotmp_[0-9]+ \[2\]string$" y := interface{}(g18()) // ERROR "live at call to convT: x.data$" "live at call to g18: x.data$" "stack object .autotmp_[0-9]+ \[2\]string$"
i9 = y // make y escape so the line above has to call convT2E i9 = y // make y escape so the line above has to call convT
return x != y return x != y
} }
@ -503,7 +503,7 @@ func f31(b1, b2, b3 bool) {
g31(g18()) // ERROR "stack object .autotmp_[0-9]+ \[2\]string$" g31(g18()) // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
} }
if b2 { if b2 {
h31(g18()) // ERROR "live at call to convT2E: .autotmp_[0-9]+$" "live at call to newobject: .autotmp_[0-9]+$" h31(g18()) // ERROR "live at call to convT: .autotmp_[0-9]+$" "live at call to newobject: .autotmp_[0-9]+$"
} }
if b3 { if b3 {
panic(g18()) panic(g18())

View file

@ -139,8 +139,8 @@ var i9 interface{}
func f9() bool { func f9() bool {
g8() g8()
x := i9 x := i9
y := interface{}(g18()) // ERROR "live at call to convT2E: x.data$" "live at call to g18: x.data$" "stack object .autotmp_[0-9]+ \[2\]string$" y := interface{}(g18()) // ERROR "live at call to convT: x.data$" "live at call to g18: x.data$" "stack object .autotmp_[0-9]+ \[2\]string$"
i9 = y // make y escape so the line above has to call convT2E i9 = y // make y escape so the line above has to call convT
return x != y return x != y
} }
@ -498,7 +498,7 @@ func f31(b1, b2, b3 bool) {
g31(g18()) // ERROR "stack object .autotmp_[0-9]+ \[2\]string$" g31(g18()) // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
} }
if b2 { if b2 {
h31(g18()) // ERROR "live at call to convT2E: .autotmp_[0-9]+$" "live at call to newobject: .autotmp_[0-9]+$" h31(g18()) // ERROR "live at call to convT: .autotmp_[0-9]+$" "live at call to newobject: .autotmp_[0-9]+$"
} }
if b3 { if b3 {
panic(g18()) panic(g18())