diff --git a/src/cmd/compile/internal/gc/builtin.go b/src/cmd/compile/internal/gc/builtin.go index bdc4974a7c..fa8ed0aaf0 100644 --- a/src/cmd/compile/internal/gc/builtin.go +++ b/src/cmd/compile/internal/gc/builtin.go @@ -111,49 +111,48 @@ var runtimeDecls = [...]struct { {"selectnbsend", funcTag, 87}, {"selectnbrecv", funcTag, 88}, {"selectnbrecv2", funcTag, 90}, - {"newselect", funcTag, 91}, - {"selectsend", funcTag, 92}, - {"selectrecv", funcTag, 93}, + {"selectsend", funcTag, 91}, + {"selectrecv", funcTag, 92}, {"selectdefault", funcTag, 55}, - {"selectgo", funcTag, 94}, + {"selectgo", funcTag, 93}, {"block", funcTag, 5}, - {"makeslice", funcTag, 96}, - {"makeslice64", funcTag, 97}, - {"growslice", funcTag, 98}, - {"memmove", funcTag, 99}, - {"memclrNoHeapPointers", funcTag, 100}, - {"memclrHasPointers", funcTag, 100}, - {"memequal", funcTag, 101}, - {"memequal8", funcTag, 102}, - {"memequal16", funcTag, 102}, - {"memequal32", funcTag, 102}, - {"memequal64", funcTag, 102}, - {"memequal128", funcTag, 102}, - {"int64div", funcTag, 103}, - {"uint64div", funcTag, 104}, - {"int64mod", funcTag, 103}, - {"uint64mod", funcTag, 104}, - {"float64toint64", funcTag, 105}, - {"float64touint64", funcTag, 106}, - {"float64touint32", funcTag, 107}, - {"int64tofloat64", funcTag, 108}, - {"uint64tofloat64", funcTag, 109}, - {"uint32tofloat64", funcTag, 110}, - {"complex128div", funcTag, 111}, - {"racefuncenter", funcTag, 112}, + {"makeslice", funcTag, 95}, + {"makeslice64", funcTag, 96}, + {"growslice", funcTag, 97}, + {"memmove", funcTag, 98}, + {"memclrNoHeapPointers", funcTag, 99}, + {"memclrHasPointers", funcTag, 99}, + {"memequal", funcTag, 100}, + {"memequal8", funcTag, 101}, + {"memequal16", funcTag, 101}, + {"memequal32", funcTag, 101}, + {"memequal64", funcTag, 101}, + {"memequal128", funcTag, 101}, + {"int64div", funcTag, 102}, + {"uint64div", funcTag, 103}, + {"int64mod", funcTag, 102}, + {"uint64mod", funcTag, 103}, + {"float64toint64", funcTag, 104}, + {"float64touint64", funcTag, 105}, + {"float64touint32", funcTag, 106}, + {"int64tofloat64", funcTag, 107}, + {"uint64tofloat64", funcTag, 108}, + {"uint32tofloat64", funcTag, 109}, + {"complex128div", funcTag, 110}, + {"racefuncenter", funcTag, 111}, {"racefuncexit", funcTag, 5}, - {"raceread", funcTag, 112}, - {"racewrite", funcTag, 112}, - {"racereadrange", funcTag, 113}, - {"racewriterange", funcTag, 113}, - {"msanread", funcTag, 113}, - {"msanwrite", funcTag, 113}, + {"raceread", funcTag, 111}, + {"racewrite", funcTag, 111}, + {"racereadrange", funcTag, 112}, + {"racewriterange", funcTag, 112}, + {"msanread", funcTag, 112}, + {"msanwrite", funcTag, 112}, {"support_popcnt", varTag, 11}, {"support_sse41", varTag, 11}, } func runtimeTypes() []*types.Type { - var typs [114]*types.Type + var typs [113]*types.Type typs[0] = types.Bytetype typs[1] = types.NewPtr(typs[0]) typs[2] = types.Types[TANY] @@ -245,28 +244,27 @@ func runtimeTypes() []*types.Type { typs[88] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[77])}, []*Node{anonfield(typs[11])}) typs[89] = types.NewPtr(typs[11]) typs[90] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[89]), anonfield(typs[77])}, []*Node{anonfield(typs[11])}) - typs[91] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[8])}, nil) - typs[92] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[80]), anonfield(typs[3])}, nil) - typs[93] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[77]), anonfield(typs[3]), anonfield(typs[89])}, nil) - typs[94] = functype(nil, []*Node{anonfield(typs[1])}, []*Node{anonfield(typs[32])}) - typs[95] = types.NewSlice(typs[2]) - typs[96] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[32]), anonfield(typs[32])}, []*Node{anonfield(typs[95])}) - typs[97] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[15])}, []*Node{anonfield(typs[95])}) - typs[98] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[95]), anonfield(typs[32])}, []*Node{anonfield(typs[95])}) - typs[99] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[48])}, nil) - typs[100] = functype(nil, []*Node{anonfield(typs[57]), anonfield(typs[48])}, nil) - typs[101] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[48])}, []*Node{anonfield(typs[11])}) - typs[102] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3])}, []*Node{anonfield(typs[11])}) - typs[103] = functype(nil, []*Node{anonfield(typs[15]), anonfield(typs[15])}, []*Node{anonfield(typs[15])}) - typs[104] = functype(nil, []*Node{anonfield(typs[17]), anonfield(typs[17])}, []*Node{anonfield(typs[17])}) - typs[105] = functype(nil, []*Node{anonfield(typs[13])}, []*Node{anonfield(typs[15])}) - typs[106] = functype(nil, []*Node{anonfield(typs[13])}, []*Node{anonfield(typs[17])}) - typs[107] = functype(nil, []*Node{anonfield(typs[13])}, []*Node{anonfield(typs[59])}) - typs[108] = functype(nil, []*Node{anonfield(typs[15])}, []*Node{anonfield(typs[13])}) - typs[109] = functype(nil, []*Node{anonfield(typs[17])}, []*Node{anonfield(typs[13])}) - typs[110] = functype(nil, []*Node{anonfield(typs[59])}, []*Node{anonfield(typs[13])}) - typs[111] = functype(nil, []*Node{anonfield(typs[19]), anonfield(typs[19])}, []*Node{anonfield(typs[19])}) - typs[112] = functype(nil, []*Node{anonfield(typs[48])}, nil) - typs[113] = functype(nil, []*Node{anonfield(typs[48]), anonfield(typs[48])}, nil) + typs[91] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[80]), anonfield(typs[3])}, nil) + typs[92] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[77]), anonfield(typs[3]), anonfield(typs[89])}, nil) + typs[93] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[32])}, []*Node{anonfield(typs[32])}) + typs[94] = types.NewSlice(typs[2]) + typs[95] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[32]), anonfield(typs[32])}, []*Node{anonfield(typs[94])}) + typs[96] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[15])}, []*Node{anonfield(typs[94])}) + typs[97] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[94]), anonfield(typs[32])}, []*Node{anonfield(typs[94])}) + typs[98] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[48])}, nil) + typs[99] = functype(nil, []*Node{anonfield(typs[57]), anonfield(typs[48])}, nil) + typs[100] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[48])}, []*Node{anonfield(typs[11])}) + typs[101] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3])}, []*Node{anonfield(typs[11])}) + typs[102] = functype(nil, []*Node{anonfield(typs[15]), anonfield(typs[15])}, []*Node{anonfield(typs[15])}) + typs[103] = functype(nil, []*Node{anonfield(typs[17]), anonfield(typs[17])}, []*Node{anonfield(typs[17])}) + typs[104] = functype(nil, []*Node{anonfield(typs[13])}, []*Node{anonfield(typs[15])}) + typs[105] = functype(nil, []*Node{anonfield(typs[13])}, []*Node{anonfield(typs[17])}) + typs[106] = functype(nil, []*Node{anonfield(typs[13])}, []*Node{anonfield(typs[59])}) + typs[107] = functype(nil, []*Node{anonfield(typs[15])}, []*Node{anonfield(typs[13])}) + typs[108] = functype(nil, []*Node{anonfield(typs[17])}, []*Node{anonfield(typs[13])}) + typs[109] = functype(nil, []*Node{anonfield(typs[59])}, []*Node{anonfield(typs[13])}) + typs[110] = functype(nil, []*Node{anonfield(typs[19]), anonfield(typs[19])}, []*Node{anonfield(typs[19])}) + typs[111] = functype(nil, []*Node{anonfield(typs[48])}, nil) + typs[112] = functype(nil, []*Node{anonfield(typs[48]), anonfield(typs[48])}, nil) return typs[:] } diff --git a/src/cmd/compile/internal/gc/builtin/runtime.go b/src/cmd/compile/internal/gc/builtin/runtime.go index 80294c8e0f..a4c8ce7ff9 100644 --- a/src/cmd/compile/internal/gc/builtin/runtime.go +++ b/src/cmd/compile/internal/gc/builtin/runtime.go @@ -145,11 +145,10 @@ func selectnbsend(hchan chan<- any, elem *any) bool func selectnbrecv(elem *any, hchan <-chan any) bool func selectnbrecv2(elem *any, received *bool, hchan <-chan any) bool -func newselect(sel *byte, selsize int64, size int32) -func selectsend(sel *byte, hchan chan<- any, elem *any) -func selectrecv(sel *byte, hchan <-chan any, elem *any, received *bool) -func selectdefault(sel *byte) -func selectgo(sel *byte) int +func selectsend(cas *byte, hchan chan<- any, elem *any) +func selectrecv(cas *byte, hchan <-chan any, elem *any, received *bool) +func selectdefault(cas *byte) +func selectgo(cas0 *byte, order0 *byte, ncases int) int func block() func makeslice(typ *byte, len int, cap int) (ary []any) diff --git a/src/cmd/compile/internal/gc/inl_test.go b/src/cmd/compile/internal/gc/inl_test.go index de877f6997..0225287866 100644 --- a/src/cmd/compile/internal/gc/inl_test.go +++ b/src/cmd/compile/internal/gc/inl_test.go @@ -60,7 +60,6 @@ func TestIntendedInlining(t *testing.T) { "releasem", "round", "roundupsize", - "selectsize", "stringStructOf", "subtract1", "subtractb", diff --git a/src/cmd/compile/internal/gc/select.go b/src/cmd/compile/internal/gc/select.go index a74677d560..0cc286eebd 100644 --- a/src/cmd/compile/internal/gc/select.go +++ b/src/cmd/compile/internal/gc/select.go @@ -251,22 +251,25 @@ func walkselectcases(cases *Nodes) []*Node { // generate sel-struct lineno = sellineno - selv := temp(selecttype(int64(n))) + selv := temp(types.NewArray(scasetype(), int64(n))) r := nod(OAS, selv, nil) r = typecheck(r, Etop) init = append(init, r) - var_ := conv(conv(nod(OADDR, selv, nil), types.Types[TUNSAFEPTR]), types.NewPtr(types.Types[TUINT8])) - r = mkcall("newselect", nil, nil, var_, nodintconst(selv.Type.Width), nodintconst(int64(n))) + + order := temp(types.NewArray(types.Types[TUINT16], 2*int64(n))) + r = nod(OAS, order, nil) r = typecheck(r, Etop) init = append(init, r) // register cases - for _, cas := range cases.Slice() { + for i, cas := range cases.Slice() { setlineno(cas) init = append(init, cas.Ninit.Slice()...) cas.Ninit.Set(nil) + s := bytePtrToIndex(selv, int64(i)) + var x *Node if n := cas.Left; n != nil { init = append(init, n.Ninit.Slice()...) @@ -275,18 +278,18 @@ func walkselectcases(cases *Nodes) []*Node { default: Fatalf("select %v", n.Op) case OSEND: - // selectsend(sel *byte, hchan *chan any, elem *any) - x = mkcall1(chanfn("selectsend", 2, n.Left.Type), nil, nil, var_, n.Left, n.Right) + // selectsend(cas *byte, hchan *chan any, elem *any) + x = mkcall1(chanfn("selectsend", 2, n.Left.Type), nil, nil, s, n.Left, n.Right) case OSELRECV: - // selectrecv(sel *byte, hchan *chan any, elem *any, received *bool) - x = mkcall1(chanfn("selectrecv", 2, n.Right.Left.Type), nil, nil, var_, n.Right.Left, n.Left, nodnil()) + // selectrecv(cas *byte, hchan *chan any, elem *any, received *bool) + x = mkcall1(chanfn("selectrecv", 2, n.Right.Left.Type), nil, nil, s, n.Right.Left, n.Left, nodnil()) case OSELRECV2: - // selectrecv(sel *byte, hchan *chan any, elem *any, received *bool) - x = mkcall1(chanfn("selectrecv", 2, n.Right.Left.Type), nil, nil, var_, n.Right.Left, n.Left, n.List.First()) + // selectrecv(cas *byte, hchan *chan any, elem *any, received *bool) + x = mkcall1(chanfn("selectrecv", 2, n.Right.Left.Type), nil, nil, s, n.Right.Left, n.Left, n.List.First()) } } else { - // selectdefault(sel *byte) - x = mkcall("selectdefault", nil, nil, var_) + // selectdefault(cas *byte) + x = mkcall("selectdefault", nil, nil, s) } init = append(init, x) @@ -295,12 +298,13 @@ func walkselectcases(cases *Nodes) []*Node { // run the select lineno = sellineno chosen := temp(types.Types[TINT]) - r = nod(OAS, chosen, mkcall("selectgo", types.Types[TINT], nil, var_)) + r = nod(OAS, chosen, mkcall("selectgo", types.Types[TINT], nil, bytePtrToIndex(selv, 0), bytePtrToIndex(order, 0), nodintconst(int64(n)))) r = typecheck(r, Etop) init = append(init, r) - // selv is no longer alive after selectgo. + // selv and order are no longer alive after selectgo. init = append(init, nod(OVARKILL, selv, nil)) + init = append(init, nod(OVARKILL, order, nil)) // dispatch cases for i, cas := range cases.Slice() { @@ -319,31 +323,28 @@ func walkselectcases(cases *Nodes) []*Node { return init } -// Keep in sync with src/runtime/select.go. -func selecttype(size int64) *types.Type { - // TODO(dvyukov): it's possible to generate Scase only once - // and then cache; and also cache Select per size. - - scase := tostruct([]*Node{ - namedfield("elem", types.NewPtr(types.Types[TUINT8])), - namedfield("chan", types.NewPtr(types.Types[TUINT8])), - namedfield("pc", types.Types[TUINTPTR]), - namedfield("kind", types.Types[TUINT16]), - namedfield("receivedp", types.NewPtr(types.Types[TUINT8])), - namedfield("releasetime", types.Types[TUINT64]), - }) - scase.SetNoalg(true) - - sel := tostruct([]*Node{ - namedfield("tcase", types.Types[TUINT16]), - namedfield("ncase", types.Types[TUINT16]), - namedfield("pollorder", types.NewPtr(types.Types[TUINT8])), - namedfield("lockorder", types.NewPtr(types.Types[TUINT8])), - namedfield("scase", types.NewArray(scase, size)), - namedfield("lockorderarr", types.NewArray(types.Types[TUINT16], size)), - namedfield("pollorderarr", types.NewArray(types.Types[TUINT16], size)), - }) - sel.SetNoalg(true) - - return sel +// bytePtrToIndex returns a Node representing "(*byte)(&n[i])". +func bytePtrToIndex(n *Node, i int64) *Node { + s := nod(OCONVNOP, nod(OADDR, nod(OINDEX, n, nodintconst(i)), nil), nil) + s.Type = types.NewPtr(types.Types[TUINT8]) + s = typecheck(s, Erv) + return s +} + +var scase *types.Type + +// Keep in sync with src/runtime/select.go. +func scasetype() *types.Type { + if scase == nil { + scase = tostruct([]*Node{ + namedfield("elem", types.NewPtr(types.Types[TUINT8])), + namedfield("chan", types.NewPtr(types.Types[TUINT8])), + namedfield("pc", types.Types[TUINTPTR]), + namedfield("kind", types.Types[TUINT16]), + namedfield("receivedp", types.NewPtr(types.Types[TUINT8])), + namedfield("releasetime", types.Types[TUINT64]), + }) + scase.SetNoalg(true) + } + return scase } diff --git a/src/runtime/select.go b/src/runtime/select.go index b59c096928..265f70ed9e 100644 --- a/src/runtime/select.go +++ b/src/runtime/select.go @@ -7,7 +7,6 @@ package runtime // This file contains the implementation of Go select statements. import ( - "runtime/internal/sys" "unsafe" ) @@ -21,20 +20,9 @@ const ( caseDefault ) -// Select statement header. -// Known to compiler. -// Changes here must also be made in src/cmd/internal/gc/select.go's selecttype. -type hselect struct { - tcase uint16 // total count of scase[] - ncase uint16 // currently filled scase[] - pollorder *uint16 // case poll order - lockorder *uint16 // channel lock order - scase [1]scase // one per case (in order of appearance) -} - // Select case descriptor. // Known to compiler. -// Changes here must also be made in src/cmd/internal/gc/select.go's selecttype. +// Changes here must also be made in src/cmd/internal/gc/select.go's scasetype. type scase struct { elem unsafe.Pointer // data element c *hchan // chan @@ -49,86 +37,42 @@ var ( chanrecvpc = funcPC(chanrecv) ) -func selectsize(size uintptr) uintptr { - selsize := unsafe.Sizeof(hselect{}) + - (size-1)*unsafe.Sizeof(hselect{}.scase[0]) + - size*unsafe.Sizeof(*hselect{}.lockorder) + - size*unsafe.Sizeof(*hselect{}.pollorder) - return round(selsize, sys.Int64Align) -} - -func newselect(sel *hselect, selsize int64, size int32) { - if selsize != int64(selectsize(uintptr(size))) { - print("runtime: bad select size ", selsize, ", want ", selectsize(uintptr(size)), "\n") - throw("bad select size") - } - sel.tcase = uint16(size) - sel.ncase = 0 - sel.lockorder = (*uint16)(add(unsafe.Pointer(&sel.scase), uintptr(size)*unsafe.Sizeof(hselect{}.scase[0]))) - sel.pollorder = (*uint16)(add(unsafe.Pointer(sel.lockorder), uintptr(size)*unsafe.Sizeof(*hselect{}.lockorder))) - - if debugSelect { - print("newselect s=", sel, " size=", size, "\n") - } -} - -func selectsend(sel *hselect, c *hchan, elem unsafe.Pointer) { - pc := getcallerpc() - i := sel.ncase - if i >= sel.tcase { - throw("selectsend: too many cases") - } - sel.ncase = i + 1 +func selectsend(cas *scase, c *hchan, elem unsafe.Pointer) { if c == nil { return } - cas := (*scase)(add(unsafe.Pointer(&sel.scase), uintptr(i)*unsafe.Sizeof(sel.scase[0]))) - cas.pc = pc + cas.pc = getcallerpc() cas.c = c cas.kind = caseSend cas.elem = elem if debugSelect { - print("selectsend s=", sel, " pc=", hex(cas.pc), " chan=", cas.c, "\n") + print("selectsend cas=", cas, " pc=", hex(cas.pc), " chan=", cas.c, "\n") } } -func selectrecv(sel *hselect, c *hchan, elem unsafe.Pointer, received *bool) { - pc := getcallerpc() - i := sel.ncase - if i >= sel.tcase { - throw("selectrecv: too many cases") - } - sel.ncase = i + 1 +func selectrecv(cas *scase, c *hchan, elem unsafe.Pointer, received *bool) { if c == nil { return } - cas := (*scase)(add(unsafe.Pointer(&sel.scase), uintptr(i)*unsafe.Sizeof(sel.scase[0]))) - cas.pc = pc + cas.pc = getcallerpc() cas.c = c cas.kind = caseRecv cas.elem = elem cas.receivedp = received if debugSelect { - print("selectrecv s=", sel, " pc=", hex(cas.pc), " chan=", cas.c, "\n") + print("selectrecv cas=", cas, " pc=", hex(cas.pc), " chan=", cas.c, "\n") } } -func selectdefault(sel *hselect) { - pc := getcallerpc() - i := sel.ncase - if i >= sel.tcase { - throw("selectdefault: too many cases") - } - sel.ncase = i + 1 - cas := (*scase)(add(unsafe.Pointer(&sel.scase), uintptr(i)*unsafe.Sizeof(sel.scase[0]))) - cas.pc = pc +func selectdefault(cas *scase) { + cas.pc = getcallerpc() cas.c = nil cas.kind = caseDefault if debugSelect { - print("selectdefault s=", sel, " pc=", hex(cas.pc), "\n") + print("selectdefault cas=", cas, " pc=", hex(cas.pc), "\n") } } @@ -194,26 +138,28 @@ func block() { // selectgo implements the select statement. // -// *sel is on the current goroutine's stack (regardless of any -// escaping in selectgo). +// cas0 points to an array of type [ncases]scase, and order0 points to +// an array of type [2*ncases]uint16. Both reside on the goroutine's +// stack (regardless of any escaping in selectgo). // // selectgo returns the index of the chosen scase, which matches the // ordinal position of its respective select{recv,send,default} call. -func selectgo(sel *hselect) int { +func selectgo(cas0 *scase, order0 *uint16, ncases int) int { if debugSelect { - print("select: sel=", sel, "\n") - } - if sel.ncase != sel.tcase { - throw("selectgo: case count mismatch") + print("select: cas0=", cas0, "\n") } - scaseslice := slice{unsafe.Pointer(&sel.scase), int(sel.ncase), int(sel.ncase)} - scases := *(*[]scase)(unsafe.Pointer(&scaseslice)) + cas1 := (*[1 << 16]scase)(unsafe.Pointer(cas0)) + order1 := (*[1 << 17]uint16)(unsafe.Pointer(order0)) + + scases := cas1[:ncases:ncases] + pollorder := order1[:ncases:ncases] + lockorder := order1[ncases:][:ncases:ncases] var t0 int64 if blockprofilerate > 0 { t0 = cputicks() - for i := 0; i < int(sel.ncase); i++ { + for i := 0; i < ncases; i++ { scases[i].releasetime = -1 } } @@ -227,9 +173,7 @@ func selectgo(sel *hselect) int { // optimizing (and needing to test). // generate permuted order - pollslice := slice{unsafe.Pointer(sel.pollorder), int(sel.ncase), int(sel.ncase)} - pollorder := *(*[]uint16)(unsafe.Pointer(&pollslice)) - for i := 1; i < int(sel.ncase); i++ { + for i := 1; i < ncases; i++ { j := fastrandn(uint32(i + 1)) pollorder[i] = pollorder[j] pollorder[j] = uint16(i) @@ -237,9 +181,7 @@ func selectgo(sel *hselect) int { // sort the cases by Hchan address to get the locking order. // simple heap sort, to guarantee n log n time and constant stack footprint. - lockslice := slice{unsafe.Pointer(sel.lockorder), int(sel.ncase), int(sel.ncase)} - lockorder := *(*[]uint16)(unsafe.Pointer(&lockslice)) - for i := 0; i < int(sel.ncase); i++ { + for i := 0; i < ncases; i++ { j := i // Start with the pollorder to permute cases on the same channel. c := scases[pollorder[i]].c @@ -250,7 +192,7 @@ func selectgo(sel *hselect) int { } lockorder[j] = pollorder[i] } - for i := int(sel.ncase) - 1; i >= 0; i-- { + for i := ncases - 1; i >= 0; i-- { o := lockorder[i] c := scases[o].c lockorder[i] = lockorder[0] @@ -273,7 +215,7 @@ func selectgo(sel *hselect) int { lockorder[j] = o } /* - for i := 0; i+1 < int(sel.ncase); i++ { + for i := 0; i+1 < ncases; i++ { if scases[lockorder[i]].c.sortkey() > scases[lockorder[i+1]].c.sortkey() { print("i=", i, " x=", lockorder[i], " y=", lockorder[i+1], "\n") throw("select: broken sort") @@ -301,7 +243,7 @@ loop: var dfl *scase var casi int var cas *scase - for i := 0; i < int(sel.ncase); i++ { + for i := 0; i < ncases; i++ { casi = int(pollorder[i]) cas = &scases[casi] c = cas.c @@ -454,7 +396,7 @@ loop: c = cas.c if debugSelect { - print("wait-return: sel=", sel, " c=", c, " cas=", cas, " kind=", cas.kind, "\n") + print("wait-return: cas0=", cas0, " c=", c, " cas=", cas, " kind=", cas.kind, "\n") } if cas.kind == caseRecv && cas.receivedp != nil { @@ -530,7 +472,7 @@ recv: // can receive from sleeping sender (sg) recv(c, sg, cas.elem, func() { selunlock(scases, lockorder) }, 2) if debugSelect { - print("syncrecv: sel=", sel, " c=", c, "\n") + print("syncrecv: cas0=", cas0, " c=", c, "\n") } if cas.receivedp != nil { *cas.receivedp = true @@ -561,7 +503,7 @@ send: } send(c, sg, cas.elem, func() { selunlock(scases, lockorder) }, 2) if debugSelect { - print("syncsend: sel=", sel, " c=", c, "\n") + print("syncsend: cas0=", cas0, " c=", c, "\n") } goto retc @@ -604,24 +546,25 @@ const ( //go:linkname reflect_rselect reflect.rselect func reflect_rselect(cases []runtimeSelect) (chosen int, recvOK bool) { - // flagNoScan is safe here, because all objects are also referenced from cases. - size := selectsize(uintptr(len(cases))) - sel := (*hselect)(mallocgc(size, nil, true)) - newselect(sel, int64(size), int32(len(cases))) + if len(cases) == 0 { + block() + } + sel := make([]scase, len(cases)) + order := make([]uint16, 2*len(cases)) r := new(bool) for i := range cases { rc := &cases[i] switch rc.dir { case selectDefault: - selectdefault(sel) + selectdefault(&sel[i]) case selectSend: - selectsend(sel, rc.ch, rc.val) + selectsend(&sel[i], rc.ch, rc.val) case selectRecv: - selectrecv(sel, rc.ch, rc.val, r) + selectrecv(&sel[i], rc.ch, rc.val, r) } } - chosen = selectgo(sel) + chosen = selectgo(&sel[0], &order[0], len(cases)) recvOK = *r return } diff --git a/test/live.go b/test/live.go index ecab83e276..43ef9bdad2 100644 --- a/test/live.go +++ b/test/live.go @@ -163,7 +163,7 @@ var b bool // this used to have a spurious "live at entry to f11a: ~r0" func f11a() *int { - select { // ERROR "live at call to newselect: .autotmp_[0-9]+$" "live at call to selectgo: .autotmp_[0-9]+$" + select { // ERROR "live at call to selectgo: .autotmp_[0-9]+$" case <-c: // ERROR "live at call to selectrecv: .autotmp_[0-9]+$" return nil case <-c: // ERROR "live at call to selectrecv: .autotmp_[0-9]+$" @@ -178,7 +178,7 @@ func f11b() *int { // get to the bottom of the function. // This used to have a spurious "live at call to printint: p". printint(1) // nothing live here! - select { // ERROR "live at call to newselect: .autotmp_[0-9]+$" "live at call to selectgo: .autotmp_[0-9]+$" + select { // ERROR "live at call to selectgo: .autotmp_[0-9]+$" case <-c: // ERROR "live at call to selectrecv: .autotmp_[0-9]+$" return nil case <-c: // ERROR "live at call to selectrecv: .autotmp_[0-9]+$" @@ -198,7 +198,7 @@ func f11c() *int { // Unlike previous, the cases in this select fall through, // so we can get to the println, so p is not dead. printint(1) // ERROR "live at call to printint: p$" - select { // ERROR "live at call to newselect: .autotmp_[0-9]+ p$" "live at call to selectgo: .autotmp_[0-9]+ p$" + select { // ERROR "live at call to selectgo: .autotmp_[0-9]+ p$" case <-c: // ERROR "live at call to selectrecv: .autotmp_[0-9]+ p$" case <-c: // ERROR "live at call to selectrecv: .autotmp_[0-9]+ p$" } @@ -589,7 +589,7 @@ func f38(b bool) { // we care that the println lines have no live variables // and therefore no output. if b { - select { // ERROR "live at call to newselect:( .autotmp_[0-9]+)+$" "live at call to selectgo:( .autotmp_[0-9]+)+$" + select { // ERROR "live at call to selectgo:( .autotmp_[0-9]+)+$" case <-fc38(): // ERROR "live at call to selectrecv:( .autotmp_[0-9]+)+$" printnl() case fc38() <- *fi38(1): // ERROR "live at call to fc38:( .autotmp_[0-9]+)+$" "live at call to fi38:( .autotmp_[0-9]+)+$" "live at call to selectsend:( .autotmp_[0-9]+)+$"