diff --git a/src/cmd/compile/internal/typecheck/builtin.go b/src/cmd/compile/internal/typecheck/builtin.go index 833b17b414..3f177d9173 100644 --- a/src/cmd/compile/internal/typecheck/builtin.go +++ b/src/cmd/compile/internal/typecheck/builtin.go @@ -71,137 +71,135 @@ var runtimeDecls = [...]struct { {"slicecopy", funcTag, 54}, {"decoderune", funcTag, 55}, {"countrunes", funcTag, 56}, - {"convI2I", funcTag, 57}, - {"convT16", funcTag, 59}, - {"convT32", funcTag, 61}, - {"convT64", funcTag, 62}, - {"convTstring", funcTag, 63}, - {"convTslice", funcTag, 66}, - {"convT2E", funcTag, 67}, - {"convT2Enoptr", funcTag, 67}, - {"convT2I", funcTag, 67}, - {"convT2Inoptr", funcTag, 67}, - {"assertE2I", funcTag, 68}, - {"assertE2I2", funcTag, 57}, - {"assertI2I", funcTag, 68}, - {"assertI2I2", funcTag, 57}, - {"panicdottypeE", funcTag, 69}, - {"panicdottypeI", funcTag, 69}, - {"panicnildottype", funcTag, 70}, - {"ifaceeq", funcTag, 72}, - {"efaceeq", funcTag, 72}, - {"fastrand", funcTag, 73}, - {"makemap64", funcTag, 75}, - {"makemap", funcTag, 76}, - {"makemap_small", funcTag, 77}, - {"mapaccess1", funcTag, 78}, - {"mapaccess1_fast32", funcTag, 79}, - {"mapaccess1_fast64", funcTag, 80}, - {"mapaccess1_faststr", funcTag, 81}, - {"mapaccess1_fat", funcTag, 82}, - {"mapaccess2", funcTag, 83}, - {"mapaccess2_fast32", funcTag, 84}, - {"mapaccess2_fast64", funcTag, 85}, - {"mapaccess2_faststr", funcTag, 86}, - {"mapaccess2_fat", funcTag, 87}, - {"mapassign", funcTag, 78}, - {"mapassign_fast32", funcTag, 79}, - {"mapassign_fast32ptr", funcTag, 88}, - {"mapassign_fast64", funcTag, 80}, - {"mapassign_fast64ptr", funcTag, 88}, - {"mapassign_faststr", funcTag, 81}, - {"mapiterinit", funcTag, 89}, - {"mapdelete", funcTag, 89}, - {"mapdelete_fast32", funcTag, 90}, - {"mapdelete_fast64", funcTag, 91}, - {"mapdelete_faststr", funcTag, 92}, - {"mapiternext", funcTag, 93}, - {"mapclear", funcTag, 94}, - {"makechan64", funcTag, 96}, - {"makechan", funcTag, 97}, - {"chanrecv1", funcTag, 99}, - {"chanrecv2", funcTag, 100}, - {"chansend1", funcTag, 102}, + {"convI2I", funcTag, 58}, + {"convT", funcTag, 59}, + {"convTnoptr", funcTag, 59}, + {"convT16", funcTag, 61}, + {"convT32", funcTag, 63}, + {"convT64", funcTag, 64}, + {"convTstring", funcTag, 65}, + {"convTslice", funcTag, 68}, + {"assertE2I", funcTag, 69}, + {"assertE2I2", funcTag, 70}, + {"assertI2I", funcTag, 69}, + {"assertI2I2", funcTag, 70}, + {"panicdottypeE", funcTag, 71}, + {"panicdottypeI", funcTag, 71}, + {"panicnildottype", funcTag, 72}, + {"ifaceeq", funcTag, 73}, + {"efaceeq", funcTag, 73}, + {"fastrand", funcTag, 74}, + {"makemap64", funcTag, 76}, + {"makemap", funcTag, 77}, + {"makemap_small", funcTag, 78}, + {"mapaccess1", funcTag, 79}, + {"mapaccess1_fast32", funcTag, 80}, + {"mapaccess1_fast64", funcTag, 81}, + {"mapaccess1_faststr", funcTag, 82}, + {"mapaccess1_fat", funcTag, 83}, + {"mapaccess2", funcTag, 84}, + {"mapaccess2_fast32", funcTag, 85}, + {"mapaccess2_fast64", funcTag, 86}, + {"mapaccess2_faststr", funcTag, 87}, + {"mapaccess2_fat", funcTag, 88}, + {"mapassign", funcTag, 79}, + {"mapassign_fast32", funcTag, 80}, + {"mapassign_fast32ptr", funcTag, 89}, + {"mapassign_fast64", funcTag, 81}, + {"mapassign_fast64ptr", funcTag, 89}, + {"mapassign_faststr", funcTag, 82}, + {"mapiterinit", funcTag, 90}, + {"mapdelete", funcTag, 90}, + {"mapdelete_fast32", funcTag, 91}, + {"mapdelete_fast64", funcTag, 92}, + {"mapdelete_faststr", funcTag, 93}, + {"mapiternext", funcTag, 94}, + {"mapclear", funcTag, 95}, + {"makechan64", funcTag, 97}, + {"makechan", funcTag, 98}, + {"chanrecv1", funcTag, 100}, + {"chanrecv2", funcTag, 101}, + {"chansend1", funcTag, 103}, {"closechan", funcTag, 30}, - {"writeBarrier", varTag, 104}, - {"typedmemmove", funcTag, 105}, - {"typedmemclr", funcTag, 106}, - {"typedslicecopy", funcTag, 107}, - {"selectnbsend", funcTag, 108}, - {"selectnbrecv", funcTag, 109}, - {"selectsetpc", funcTag, 110}, - {"selectgo", funcTag, 111}, + {"writeBarrier", varTag, 105}, + {"typedmemmove", funcTag, 106}, + {"typedmemclr", funcTag, 107}, + {"typedslicecopy", funcTag, 108}, + {"selectnbsend", funcTag, 109}, + {"selectnbrecv", funcTag, 110}, + {"selectsetpc", funcTag, 111}, + {"selectgo", funcTag, 112}, {"block", funcTag, 9}, - {"makeslice", funcTag, 112}, - {"makeslice64", funcTag, 113}, - {"makeslicecopy", funcTag, 114}, - {"growslice", funcTag, 116}, - {"unsafeslice", funcTag, 117}, - {"unsafeslice64", funcTag, 118}, - {"unsafeslicecheckptr", funcTag, 118}, - {"memmove", funcTag, 119}, - {"memclrNoHeapPointers", funcTag, 120}, - {"memclrHasPointers", funcTag, 120}, - {"memequal", funcTag, 121}, - {"memequal0", funcTag, 122}, - {"memequal8", funcTag, 122}, - {"memequal16", funcTag, 122}, - {"memequal32", funcTag, 122}, - {"memequal64", funcTag, 122}, - {"memequal128", funcTag, 122}, - {"f32equal", funcTag, 123}, - {"f64equal", funcTag, 123}, - {"c64equal", funcTag, 123}, - {"c128equal", funcTag, 123}, - {"strequal", funcTag, 123}, - {"interequal", funcTag, 123}, - {"nilinterequal", funcTag, 123}, - {"memhash", funcTag, 124}, - {"memhash0", funcTag, 125}, - {"memhash8", funcTag, 125}, - {"memhash16", funcTag, 125}, - {"memhash32", funcTag, 125}, - {"memhash64", funcTag, 125}, - {"memhash128", funcTag, 125}, - {"f32hash", funcTag, 125}, - {"f64hash", funcTag, 125}, - {"c64hash", funcTag, 125}, - {"c128hash", funcTag, 125}, - {"strhash", funcTag, 125}, - {"interhash", funcTag, 125}, - {"nilinterhash", funcTag, 125}, - {"int64div", funcTag, 126}, - {"uint64div", funcTag, 127}, - {"int64mod", funcTag, 126}, - {"uint64mod", funcTag, 127}, - {"float64toint64", funcTag, 128}, - {"float64touint64", funcTag, 129}, - {"float64touint32", funcTag, 130}, - {"int64tofloat64", funcTag, 131}, - {"uint64tofloat64", funcTag, 132}, - {"uint32tofloat64", funcTag, 133}, - {"complex128div", funcTag, 134}, - {"getcallerpc", funcTag, 135}, - {"getcallersp", funcTag, 135}, + {"makeslice", funcTag, 113}, + {"makeslice64", funcTag, 114}, + {"makeslicecopy", funcTag, 115}, + {"growslice", funcTag, 117}, + {"unsafeslice", funcTag, 118}, + {"unsafeslice64", funcTag, 119}, + {"unsafeslicecheckptr", funcTag, 119}, + {"memmove", funcTag, 120}, + {"memclrNoHeapPointers", funcTag, 121}, + {"memclrHasPointers", funcTag, 121}, + {"memequal", funcTag, 122}, + {"memequal0", funcTag, 123}, + {"memequal8", funcTag, 123}, + {"memequal16", funcTag, 123}, + {"memequal32", funcTag, 123}, + {"memequal64", funcTag, 123}, + {"memequal128", funcTag, 123}, + {"f32equal", funcTag, 124}, + {"f64equal", funcTag, 124}, + {"c64equal", funcTag, 124}, + {"c128equal", funcTag, 124}, + {"strequal", funcTag, 124}, + {"interequal", funcTag, 124}, + {"nilinterequal", funcTag, 124}, + {"memhash", funcTag, 125}, + {"memhash0", funcTag, 126}, + {"memhash8", funcTag, 126}, + {"memhash16", funcTag, 126}, + {"memhash32", funcTag, 126}, + {"memhash64", funcTag, 126}, + {"memhash128", funcTag, 126}, + {"f32hash", funcTag, 126}, + {"f64hash", funcTag, 126}, + {"c64hash", funcTag, 126}, + {"c128hash", funcTag, 126}, + {"strhash", funcTag, 126}, + {"interhash", funcTag, 126}, + {"nilinterhash", funcTag, 126}, + {"int64div", funcTag, 127}, + {"uint64div", funcTag, 128}, + {"int64mod", funcTag, 127}, + {"uint64mod", funcTag, 128}, + {"float64toint64", funcTag, 129}, + {"float64touint64", funcTag, 130}, + {"float64touint32", funcTag, 131}, + {"int64tofloat64", funcTag, 132}, + {"uint64tofloat64", funcTag, 133}, + {"uint32tofloat64", funcTag, 134}, + {"complex128div", funcTag, 135}, + {"getcallerpc", funcTag, 136}, + {"getcallersp", funcTag, 136}, {"racefuncenter", funcTag, 31}, {"racefuncexit", funcTag, 9}, {"raceread", funcTag, 31}, {"racewrite", funcTag, 31}, - {"racereadrange", funcTag, 136}, - {"racewriterange", funcTag, 136}, - {"msanread", funcTag, 136}, - {"msanwrite", funcTag, 136}, - {"msanmove", funcTag, 137}, - {"checkptrAlignment", funcTag, 138}, - {"checkptrArithmetic", funcTag, 140}, - {"libfuzzerTraceCmp1", funcTag, 141}, - {"libfuzzerTraceCmp2", funcTag, 142}, - {"libfuzzerTraceCmp4", funcTag, 143}, - {"libfuzzerTraceCmp8", funcTag, 144}, - {"libfuzzerTraceConstCmp1", funcTag, 141}, - {"libfuzzerTraceConstCmp2", funcTag, 142}, - {"libfuzzerTraceConstCmp4", funcTag, 143}, - {"libfuzzerTraceConstCmp8", funcTag, 144}, + {"racereadrange", funcTag, 137}, + {"racewriterange", funcTag, 137}, + {"msanread", funcTag, 137}, + {"msanwrite", funcTag, 137}, + {"msanmove", funcTag, 138}, + {"checkptrAlignment", funcTag, 139}, + {"checkptrArithmetic", funcTag, 141}, + {"libfuzzerTraceCmp1", funcTag, 142}, + {"libfuzzerTraceCmp2", funcTag, 143}, + {"libfuzzerTraceCmp4", funcTag, 144}, + {"libfuzzerTraceCmp8", funcTag, 145}, + {"libfuzzerTraceConstCmp1", funcTag, 142}, + {"libfuzzerTraceConstCmp2", funcTag, 143}, + {"libfuzzerTraceConstCmp4", funcTag, 144}, + {"libfuzzerTraceConstCmp8", funcTag, 145}, {"x86HasPOPCNT", varTag, 6}, {"x86HasSSE41", varTag, 6}, {"x86HasFMA", varTag, 6}, @@ -224,7 +222,7 @@ func params(tlist ...*types.Type) []*types.Field { } func runtimeTypes() []*types.Type { - var typs [145]*types.Type + var typs [146]*types.Type typs[0] = types.ByteType typs[1] = types.NewPtr(typs[0]) 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[55] = newSig(params(typs[28], typs[15]), params(typs[46], typs[15])) typs[56] = newSig(params(typs[28]), params(typs[15])) - typs[57] = newSig(params(typs[1], typs[2]), params(typs[2])) - typs[58] = types.Types[types.TUINT16] - typs[59] = newSig(params(typs[58]), params(typs[7])) - typs[60] = types.Types[types.TUINT32] + typs[57] = types.NewPtr(typs[5]) + typs[58] = newSig(params(typs[1], typs[57]), params(typs[57])) + typs[59] = newSig(params(typs[1], typs[3]), params(typs[7])) + typs[60] = types.Types[types.TUINT16] typs[61] = newSig(params(typs[60]), params(typs[7])) - typs[62] = newSig(params(typs[24]), params(typs[7])) - typs[63] = newSig(params(typs[28]), params(typs[7])) - typs[64] = types.Types[types.TUINT8] - typs[65] = types.NewSlice(typs[64]) - typs[66] = newSig(params(typs[65]), params(typs[7])) - typs[67] = newSig(params(typs[1], typs[3]), params(typs[2])) - typs[68] = newSig(params(typs[1], typs[1]), params(typs[1])) - typs[69] = newSig(params(typs[1], typs[1], typs[1]), nil) - typs[70] = newSig(params(typs[1]), nil) - typs[71] = types.NewPtr(typs[5]) - typs[72] = newSig(params(typs[71], typs[7], typs[7]), params(typs[6])) - typs[73] = newSig(nil, params(typs[60])) - typs[74] = types.NewMap(typs[2], typs[2]) - typs[75] = newSig(params(typs[1], typs[22], typs[3]), params(typs[74])) - typs[76] = newSig(params(typs[1], typs[15], typs[3]), params(typs[74])) - typs[77] = newSig(nil, params(typs[74])) - typs[78] = newSig(params(typs[1], typs[74], typs[3]), params(typs[3])) - typs[79] = newSig(params(typs[1], typs[74], typs[60]), params(typs[3])) - typs[80] = newSig(params(typs[1], typs[74], typs[24]), params(typs[3])) - typs[81] = newSig(params(typs[1], typs[74], typs[28]), params(typs[3])) - typs[82] = newSig(params(typs[1], typs[74], typs[3], typs[1]), params(typs[3])) - typs[83] = newSig(params(typs[1], typs[74], typs[3]), params(typs[3], typs[6])) - typs[84] = newSig(params(typs[1], typs[74], typs[60]), params(typs[3], typs[6])) - typs[85] = newSig(params(typs[1], typs[74], typs[24]), params(typs[3], typs[6])) - typs[86] = newSig(params(typs[1], typs[74], typs[28]), params(typs[3], typs[6])) - typs[87] = newSig(params(typs[1], typs[74], typs[3], typs[1]), params(typs[3], typs[6])) - typs[88] = newSig(params(typs[1], typs[74], typs[7]), params(typs[3])) - typs[89] = newSig(params(typs[1], typs[74], typs[3]), nil) - typs[90] = newSig(params(typs[1], typs[74], typs[60]), nil) - typs[91] = newSig(params(typs[1], typs[74], typs[24]), nil) - typs[92] = newSig(params(typs[1], typs[74], typs[28]), nil) - typs[93] = newSig(params(typs[3]), nil) - typs[94] = newSig(params(typs[1], typs[74]), nil) - typs[95] = types.NewChan(typs[2], types.Cboth) - typs[96] = newSig(params(typs[1], typs[22]), params(typs[95])) - typs[97] = newSig(params(typs[1], typs[15]), params(typs[95])) - typs[98] = types.NewChan(typs[2], types.Crecv) - typs[99] = newSig(params(typs[98], typs[3]), nil) - typs[100] = newSig(params(typs[98], typs[3]), params(typs[6])) - typs[101] = types.NewChan(typs[2], types.Csend) - typs[102] = newSig(params(typs[101], typs[3]), nil) - typs[103] = types.NewArray(typs[0], 3) - 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[105] = newSig(params(typs[1], typs[3], typs[3]), nil) - typs[106] = newSig(params(typs[1], typs[3]), nil) - typs[107] = newSig(params(typs[1], typs[3], typs[15], typs[3], typs[15]), params(typs[15])) - typs[108] = newSig(params(typs[101], typs[3]), params(typs[6])) - typs[109] = newSig(params(typs[3], typs[98]), params(typs[6], typs[6])) - typs[110] = newSig(params(typs[71]), nil) - typs[111] = newSig(params(typs[1], typs[1], typs[71], typs[15], typs[15], typs[6]), params(typs[15], typs[6])) - typs[112] = newSig(params(typs[1], typs[15], typs[15]), params(typs[7])) - typs[113] = newSig(params(typs[1], typs[22], typs[22]), params(typs[7])) - typs[114] = newSig(params(typs[1], typs[15], typs[15], typs[7]), params(typs[7])) - typs[115] = types.NewSlice(typs[2]) - typs[116] = newSig(params(typs[1], typs[115], typs[15]), params(typs[115])) - typs[117] = newSig(params(typs[1], typs[7], typs[15]), nil) - typs[118] = newSig(params(typs[1], typs[7], typs[22]), nil) - typs[119] = newSig(params(typs[3], typs[3], typs[5]), nil) - typs[120] = newSig(params(typs[7], typs[5]), nil) - typs[121] = newSig(params(typs[3], typs[3], typs[5]), params(typs[6])) - typs[122] = newSig(params(typs[3], typs[3]), params(typs[6])) - typs[123] = newSig(params(typs[7], typs[7]), params(typs[6])) - typs[124] = newSig(params(typs[7], typs[5], typs[5]), params(typs[5])) - typs[125] = newSig(params(typs[7], typs[5]), params(typs[5])) - typs[126] = newSig(params(typs[22], typs[22]), params(typs[22])) - typs[127] = newSig(params(typs[24], typs[24]), params(typs[24])) - typs[128] = newSig(params(typs[20]), params(typs[22])) - typs[129] = newSig(params(typs[20]), params(typs[24])) - typs[130] = newSig(params(typs[20]), params(typs[60])) - typs[131] = newSig(params(typs[22]), params(typs[20])) - typs[132] = newSig(params(typs[24]), params(typs[20])) - typs[133] = newSig(params(typs[60]), params(typs[20])) - typs[134] = newSig(params(typs[26], typs[26]), params(typs[26])) - typs[135] = newSig(nil, params(typs[5])) - typs[136] = newSig(params(typs[5], typs[5]), nil) - typs[137] = newSig(params(typs[5], typs[5], typs[5]), nil) - typs[138] = newSig(params(typs[7], typs[1], typs[5]), nil) - typs[139] = types.NewSlice(typs[7]) - typs[140] = newSig(params(typs[7], typs[139]), nil) - typs[141] = newSig(params(typs[64], typs[64]), nil) - typs[142] = newSig(params(typs[58], typs[58]), nil) + typs[62] = types.Types[types.TUINT32] + typs[63] = newSig(params(typs[62]), params(typs[7])) + typs[64] = newSig(params(typs[24]), params(typs[7])) + typs[65] = newSig(params(typs[28]), params(typs[7])) + typs[66] = types.Types[types.TUINT8] + typs[67] = types.NewSlice(typs[66]) + typs[68] = newSig(params(typs[67]), params(typs[7])) + typs[69] = newSig(params(typs[1], typs[1]), params(typs[1])) + typs[70] = newSig(params(typs[1], typs[2]), params(typs[2])) + typs[71] = newSig(params(typs[1], typs[1], typs[1]), nil) + typs[72] = newSig(params(typs[1]), nil) + typs[73] = newSig(params(typs[57], typs[7], typs[7]), params(typs[6])) + typs[74] = newSig(nil, params(typs[62])) + typs[75] = types.NewMap(typs[2], typs[2]) + typs[76] = newSig(params(typs[1], typs[22], typs[3]), params(typs[75])) + typs[77] = newSig(params(typs[1], typs[15], typs[3]), params(typs[75])) + typs[78] = newSig(nil, params(typs[75])) + typs[79] = newSig(params(typs[1], typs[75], typs[3]), params(typs[3])) + typs[80] = newSig(params(typs[1], typs[75], typs[62]), params(typs[3])) + typs[81] = newSig(params(typs[1], typs[75], typs[24]), params(typs[3])) + typs[82] = newSig(params(typs[1], typs[75], typs[28]), params(typs[3])) + typs[83] = newSig(params(typs[1], typs[75], typs[3], typs[1]), params(typs[3])) + typs[84] = newSig(params(typs[1], typs[75], typs[3]), 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[75], typs[24]), 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[75], typs[3], typs[1]), params(typs[3], typs[6])) + typs[89] = newSig(params(typs[1], typs[75], typs[7]), params(typs[3])) + typs[90] = newSig(params(typs[1], typs[75], typs[3]), nil) + typs[91] = newSig(params(typs[1], typs[75], typs[62]), nil) + typs[92] = newSig(params(typs[1], typs[75], typs[24]), nil) + typs[93] = newSig(params(typs[1], typs[75], typs[28]), nil) + typs[94] = newSig(params(typs[3]), nil) + typs[95] = newSig(params(typs[1], typs[75]), nil) + typs[96] = types.NewChan(typs[2], types.Cboth) + typs[97] = newSig(params(typs[1], typs[22]), params(typs[96])) + typs[98] = newSig(params(typs[1], typs[15]), params(typs[96])) + typs[99] = types.NewChan(typs[2], types.Crecv) + typs[100] = newSig(params(typs[99], typs[3]), nil) + typs[101] = newSig(params(typs[99], typs[3]), params(typs[6])) + typs[102] = types.NewChan(typs[2], types.Csend) + typs[103] = newSig(params(typs[102], typs[3]), nil) + typs[104] = types.NewArray(typs[0], 3) + 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], typs[3]), nil) + typs[107] = newSig(params(typs[1], typs[3]), nil) + typs[108] = newSig(params(typs[1], typs[3], typs[15], typs[3], typs[15]), params(typs[15])) + typs[109] = newSig(params(typs[102], typs[3]), params(typs[6])) + typs[110] = newSig(params(typs[3], typs[99]), params(typs[6], typs[6])) + typs[111] = newSig(params(typs[57]), nil) + 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[15], typs[15]), params(typs[7])) + typs[114] = newSig(params(typs[1], typs[22], typs[22]), params(typs[7])) + typs[115] = newSig(params(typs[1], typs[15], typs[15], typs[7]), params(typs[7])) + typs[116] = types.NewSlice(typs[2]) + typs[117] = newSig(params(typs[1], typs[116], typs[15]), params(typs[116])) + typs[118] = newSig(params(typs[1], typs[7], typs[15]), nil) + typs[119] = newSig(params(typs[1], typs[7], typs[22]), nil) + typs[120] = newSig(params(typs[3], typs[3], typs[5]), nil) + typs[121] = newSig(params(typs[7], typs[5]), nil) + typs[122] = newSig(params(typs[3], typs[3], typs[5]), params(typs[6])) + typs[123] = newSig(params(typs[3], typs[3]), params(typs[6])) + typs[124] = newSig(params(typs[7], typs[7]), params(typs[6])) + typs[125] = newSig(params(typs[7], typs[5], typs[5]), params(typs[5])) + typs[126] = newSig(params(typs[7], typs[5]), params(typs[5])) + typs[127] = newSig(params(typs[22], typs[22]), params(typs[22])) + typs[128] = newSig(params(typs[24], typs[24]), params(typs[24])) + typs[129] = newSig(params(typs[20]), params(typs[22])) + typs[130] = newSig(params(typs[20]), params(typs[24])) + typs[131] = newSig(params(typs[20]), params(typs[62])) + typs[132] = newSig(params(typs[22]), params(typs[20])) + typs[133] = newSig(params(typs[24]), params(typs[20])) + typs[134] = newSig(params(typs[62]), params(typs[20])) + typs[135] = newSig(params(typs[26], typs[26]), params(typs[26])) + typs[136] = newSig(nil, params(typs[5])) + typs[137] = newSig(params(typs[5], typs[5]), nil) + typs[138] = newSig(params(typs[5], typs[5], typs[5]), nil) + typs[139] = newSig(params(typs[7], typs[1], typs[5]), nil) + typs[140] = types.NewSlice(typs[7]) + typs[141] = newSig(params(typs[7], typs[140]), nil) + typs[142] = newSig(params(typs[66], typs[66]), 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[:] } diff --git a/src/cmd/compile/internal/typecheck/builtin/runtime.go b/src/cmd/compile/internal/typecheck/builtin/runtime.go index 2b29ea3c08..605b904288 100644 --- a/src/cmd/compile/internal/typecheck/builtin/runtime.go +++ b/src/cmd/compile/internal/typecheck/builtin/runtime.go @@ -84,10 +84,15 @@ func decoderune(string, int) (retv rune, retk int) func countrunes(string) int // 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. -// These return only a data pointer. +// Convert non-interface type to the data word of a (empty or nonempty) interface. +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 // be used for a wider range of types, which have the same memory // 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 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) func assertE2I(inter *byte, typ *byte) *byte func assertE2I2(inter *byte, eface any) (ret any) diff --git a/src/cmd/compile/internal/walk/convert.go b/src/cmd/compile/internal/walk/convert.go index d15575f643..27a07ce4b6 100644 --- a/src/cmd/compile/internal/walk/convert.go +++ b/src/cmd/compile/internal/walk/convert.go @@ -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()) } -// walkConvInterface walks an OCONVIFACE or OCONVIDATA node. +// walkConvInterface walks an OCONVIFACE node. func walkConvInterface(n *ir.ConvExpr, init *ir.Nodes) ir.Node { n.X = walkExpr(n.X, init) fromType := n.X.Type() toType := n.Type() - if n.Op() == ir.OCONVIDATA { - // 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) { + if !fromType.IsInterface() && !ir.IsBlank(ir.CurFunc.Nname) { // skip unnamed functions (func _()) reflectdata.MarkTypeUsedInInterface(fromType, ir.CurFunc.LSym) } - // typeword generates the type word of the interface value. - typeword := func() ir.Node { + if !fromType.IsInterface() { + var typeWord ir.Node if toType.IsEmptyInterface() { - return reflectdata.TypePtr(fromType) + typeWord = reflectdata.TypePtr(fromType) + } else { + typeWord = reflectdata.ITabAddr(fromType, toType) } - return reflectdata.ITabAddr(fromType, toType) - } - - // 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 := ir.NewBinaryExpr(base.Pos, ir.OEFACE, typeWord, dataWord(n.X, init, n.Esc() != ir.EscNone)) l.SetType(toType) l.SetTypecheck(n.Typecheck()) 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, - // by using an existing addressable value identical to n.Left - // or creating one on the stack. + // Evaluate the input interface. + c := typecheck.Temp(fromType) + 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 switch { case fromType.Size() == 0: - // n.Left is zero-sized. Use zerobase. - cheapExpr(n.X, init) // Evaluate n.Left for side-effects. See issue 19246. + // n is zero-sized. Use zerobase. + cheapExpr(n, init) // Evaluate n for side-effects. See issue 19246. value = ir.NewLinksymExpr(base.Pos, ir.Syms.Zerobase, types.Types[types.TUINTPTR]) case fromType.IsBoolean() || (fromType.Size() == 1 && fromType.IsInteger()): - // n.Left is a bool/byte. Use staticuint64s[n.Left * 8] on little-endian - // and staticuint64s[n.Left * 8 + 7] on big-endian. - n.X = cheapExpr(n.X, init) - // byteindex widens n.Left so that the multiplication doesn't overflow. - index := ir.NewBinaryExpr(base.Pos, ir.OLSH, byteindex(n.X), ir.NewInt(3)) + // n is a bool/byte. Use staticuint64s[n * 8] on little-endian + // and staticuint64s[n * 8 + 7] on big-endian. + n = cheapExpr(n, init) + // byteindex widens n so that the multiplication doesn't overflow. + index := ir.NewBinaryExpr(base.Pos, ir.OLSH, byteindex(n), ir.NewInt(3)) if ssagen.Arch.LinkArch.ByteOrder == binary.BigEndian { 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.SetBounded(true) value = xe - case n.X.Op() == ir.ONAME && n.X.(*ir.Name).Class == ir.PEXTERN && n.X.(*ir.Name).Readonly(): - // n.Left is a readonly global; use it directly. - value = n.X - case !fromType.IsInterface() && n.Esc() == ir.EscNone && fromType.Width <= 1024: - // n.Left does not escape. Use a stack temporary initialized to n.Left. + case n.Op() == ir.ONAME && n.(*ir.Name).Class == ir.PEXTERN && n.(*ir.Name).Readonly(): + // n is a readonly global; use it directly. + value = n + case !escapes && fromType.Width <= 1024: + // n does not escape. Use a stack temporary initialized to n. 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 { - // Value is identical to n.Left. - // Construct the interface directly: {type/itab, &value}. - l := ir.NewBinaryExpr(base.Pos, ir.OEFACE, typeword(), typecheck.Expr(typecheck.NodAddr(value))) - l.SetType(toType) - l.SetTypecheck(n.Typecheck()) - return l + // The interface data word is &value. + return typecheck.Expr(typecheck.NodAddr(value)) } - // Implement interface to empty interface conversion. - // tmp = i.itab - // if tmp != nil { - // 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)) + // Time to do an allocation. We'll call into the runtime for that. + fnname, argType, needsaddr := dataWordFuncName(fromType) + fn := typecheck.LookupRuntime(fnname) - // Get the itab out of the interface. - tmp := typecheck.Temp(types.NewPtr(types.Types[types.TUINT8])) - init.Append(ir.NewAssignStmt(base.Pos, tmp, typecheck.Expr(ir.NewUnaryExpr(base.Pos, ir.OITAB, c)))) - - // Get the type out of the itab. - nif := ir.NewIfStmt(base.Pos, typecheck.Expr(ir.NewBinaryExpr(base.Pos, ir.ONE, tmp, typecheck.NodNil())), nil, nil) - nif.Body = []ir.Node{ir.NewAssignStmt(base.Pos, tmp, itabType(tmp))} - init.Append(nif) - - // Build the result. - 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. - e.SetTypecheck(1) - return e - } - - fnname, argType, needsaddr := convFuncName(fromType, toType) - - 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 + var args []ir.Node + if needsaddr { + // Types of large or unknown size are passed by reference. + // Orderexpr arranged for n 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(n) { + n = copyExpr(n, fromType, init) + } + fn = typecheck.SubstArgTypes(fn, fromType) + args = []ir.Node{reflectdata.TypePtr(fromType), typecheck.NodAddr(n)} + } else { + // Use a specialized conversion routine that takes the type being + // converted by value, not by pointer. + var arg ir.Node switch { case fromType == argType: // already in the right type, nothing to do + arg = n case fromType.Kind() == argType.Kind(), fromType.IsPtrShaped() && argType.IsPtrShaped(): // 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(): // 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: // unsafe cast through memory - arg = copyExpr(arg, arg.Type(), init) + arg = copyExpr(n, fromType, init) var addr ir.Node = typecheck.NodAddr(arg) addr = ir.NewConvExpr(n.Pos(), ir.OCONVNOP, argType.PtrTo(), addr) arg = ir.NewStarExpr(n.Pos(), addr) arg.SetType(argType) } - - 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 + args = []ir.Node{arg} } - - 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.Args = []ir.Node{tab, v} - return walkExpr(typecheck.Expr(call), init) + call.Args = args + 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. @@ -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])) } -// convFuncName builds the runtime function name for interface conversion. -// It also returns the argument type that the runtime function takes, and -// whether the function expects the data by address. -// Not all names are possible. For example, we never generate convE2E or convE2I. -func convFuncName(from, to *types.Type) (fnname string, argType *types.Type, needsaddr bool) { - tkind := to.Tie() - switch from.Tie() { - case 'I': - if tkind == 'I' { - return "convI2I", types.Types[types.TINTER], false - } - case 'T': +// dataWordFuncName returns the name of the function used to convert a value of type "from" +// to the data word of an interface. +// argType is the type the argument needs to be coerced to. +// needsaddr reports whether the value should be passed (needaddr==false) or its address (needsaddr==true). +func dataWordFuncName(from *types.Type) (fnname string, argType *types.Type, needsaddr bool) { + if from.IsInterface() { + base.Fatalf("can only handle non-interfaces") + } + switch { + case from.Size() == 2 && from.Align == 2: + return "convT16", types.Types[types.TUINT16], false + 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 { - case from.Size() == 2 && from.Align == 2: - return "convT16", types.Types[types.TUINT16], false - 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 { - 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 + 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 } } - 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 diff --git a/src/cmd/compile/internal/walk/expr.go b/src/cmd/compile/internal/walk/expr.go index f95b6f4639..26e225440a 100644 --- a/src/cmd/compile/internal/walk/expr.go +++ b/src/cmd/compile/internal/walk/expr.go @@ -212,10 +212,7 @@ func walkExpr1(n ir.Node, init *ir.Nodes) ir.Node { case ir.OCONVIDATA: n := n.(*ir.ConvExpr) - r := ir.NewUnaryExpr(n.Pos(), ir.OIDATA, walkConvInterface(n, init)) - r.SetType(types.Types[types.TUNSAFEPTR]) - r.SetTypecheck(1) - return r + return walkConvIData(n, init) case ir.OCONV, ir.OCONVNOP: n := n.(*ir.ConvExpr) diff --git a/src/cmd/compile/internal/walk/order.go b/src/cmd/compile/internal/walk/order.go index c5fd0c1e1d..6e336f565c 100644 --- a/src/cmd/compile/internal/walk/order.go +++ b/src/cmd/compile/internal/walk/order.go @@ -1166,11 +1166,7 @@ func (o *orderState) expr1(n, lhs ir.Node) ir.Node { if n.X.Type().IsInterface() { return n } - to := n.Type() - if n.Op() == ir.OCONVIDATA { - to = types.NewInterface(types.LocalPkg, nil) - } - if _, _, needsaddr := convFuncName(n.X.Type(), to); needsaddr || isStaticCompositeLiteral(n.X) { + if _, _, needsaddr := dataWordFuncName(n.X.Type()); needsaddr || isStaticCompositeLiteral(n.X) { // 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 // whose address we can put directly in an interface (see OCONVIFACE/OCONVIDATA case in walk). diff --git a/src/runtime/iface.go b/src/runtime/iface.go index 79a49c0dff..3d1d9d6ba1 100644 --- a/src/runtime/iface.go +++ b/src/runtime/iface.go @@ -316,20 +316,30 @@ var ( // The convXXX functions succeed on a nil input, whereas the assertXXX // 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 { - raceReadObjectPC(t, elem, getcallerpc(), abi.FuncPCABIInternal(convT2E)) + raceReadObjectPC(t, v, getcallerpc(), abi.FuncPCABIInternal(convT)) } if msanenabled { - msanread(elem, t.size) + msanread(v, t.size) } x := mallocgc(t.size, t, true) - // TODO: We allocate a zeroed object only to overwrite it with actual data. - // Figure out how to avoid zeroing. Also below in convT2Eslice, convT2I, convT2Islice. - typedmemmove(t, x, elem) - e._type = t - e.data = x - return + typedmemmove(t, x, v) + return x +} +func convTnoptr(t *_type, v unsafe.Pointer) unsafe.Pointer { + // TODO: maybe take size instead of type? + 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) { @@ -389,63 +399,16 @@ func convTslice(val []byte) (x unsafe.Pointer) { return } -func convT2Enoptr(t *_type, elem unsafe.Pointer) (e eface) { - if raceenabled { - raceReadObjectPC(t, elem, getcallerpc(), abi.FuncPCABIInternal(convT2Enoptr)) +// convI2I returns the new itab to be used for the destination value +// when converting a value with itab src to the dst interface. +func convI2I(dst *interfacetype, src *itab) *itab { + if src == nil { + return nil } - if msanenabled { - msanread(elem, t.size) + if src.inter == dst { + return src } - x := mallocgc(t.size, t, 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 + return getitab(dst, src._type, false) } func assertI2I(inter *interfacetype, tab *itab) *itab { diff --git a/test/devirt.go b/test/devirt.go index e0149d8229..d5c815222e 100644 --- a/test/devirt.go +++ b/test/devirt.go @@ -31,9 +31,8 @@ func main() { panic("not 3") } - // Can't do types that aren't "direct" interfaces (yet). r = indirectiface{3, 4, 5} - if r.Value() != 12 { + if r.Value() != 12 { // ERROR "de-virtualizing call$" panic("not 12") } } diff --git a/test/fixedbugs/issue20250.go b/test/fixedbugs/issue20250.go index 1a513bea56..aed7b25d1b 100644 --- a/test/fixedbugs/issue20250.go +++ b/test/fixedbugs/issue20250.go @@ -17,7 +17,7 @@ type T struct { func f(a T) { // ERROR "live at entry to f: a" var e interface{} // ERROR "stack object e interface \{\}$" 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. _ = e diff --git a/test/live.go b/test/live.go index 856e56f3d2..6130f7f069 100644 --- a/test/live.go +++ b/test/live.go @@ -144,8 +144,8 @@ var i9 interface{} func f9() bool { g8() 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$" - i9 = y // make y escape so the line above has to call convT2E + 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 convT return x != y } @@ -503,7 +503,7 @@ func f31(b1, b2, b3 bool) { g31(g18()) // ERROR "stack object .autotmp_[0-9]+ \[2\]string$" } 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 { panic(g18()) diff --git a/test/live_regabi.go b/test/live_regabi.go index d362ee287d..2883b83bae 100644 --- a/test/live_regabi.go +++ b/test/live_regabi.go @@ -139,8 +139,8 @@ var i9 interface{} func f9() bool { g8() 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$" - i9 = y // make y escape so the line above has to call convT2E + 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 convT return x != y } @@ -498,7 +498,7 @@ func f31(b1, b2, b3 bool) { g31(g18()) // ERROR "stack object .autotmp_[0-9]+ \[2\]string$" } 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 { panic(g18())