]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: eliminate runtime.hselect
authorMatthew Dempsky <mdempsky@google.com>
Tue, 7 Mar 2017 21:44:53 +0000 (13:44 -0800)
committerMatthew Dempsky <mdempsky@google.com>
Tue, 1 May 2018 03:17:31 +0000 (03:17 +0000)
Now the registration phase looks like:

    var cases [4]runtime.scases
    var order [8]uint16
    selectsend(&cases[0], c1, &v1)
    selectrecv(&cases[1], c2, &v2, nil)
    selectrecv(&cases[2], c3, &v3, &ok)
    selectdefault(&cases[3])
    chosen := selectgo(&cases[0], &order[0], 4)

Primarily, this is just preparation for having the compiler open-code
selectsend, selectrecv, and selectdefault.

As a minor benefit, order can now be layed out separately on the stack
in the pointer-free segment, so it won't take up space in the
function's stack pointer maps.

Change-Id: I5552ba594201efd31fcb40084da20b42ea569a45
Reviewed-on: https://go-review.googlesource.com/37933
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
src/cmd/compile/internal/gc/builtin.go
src/cmd/compile/internal/gc/builtin/runtime.go
src/cmd/compile/internal/gc/inl_test.go
src/cmd/compile/internal/gc/select.go
src/runtime/select.go
test/live.go

index bdc4974a7c03f92ba543ef5e84098b849b4833f7..fa8ed0aaf014971797a6b460802a8eb529349e84 100644 (file)
@@ -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[:]
 }
index 80294c8e0fdcb8dc7a843e8e82ac2a26d8a10b95..a4c8ce7ff996e8c1c3279cf811d05ad001af20b3 100644 (file)
@@ -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)
index de877f6997b14422b2912db7e255bf10c4e58647..02252878660b79d90608b691513e0e67a56d2aa0 100644 (file)
@@ -60,7 +60,6 @@ func TestIntendedInlining(t *testing.T) {
                        "releasem",
                        "round",
                        "roundupsize",
-                       "selectsize",
                        "stringStructOf",
                        "subtract1",
                        "subtractb",
index a74677d5600a24b6aae843d287c20899d29e07e0..0cc286eebd60a65800eed2c763a1e02cbdb30d4c 100644 (file)
@@ -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
 }
 
+// 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 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
+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
 }
index b59c0969289289212f09f3b7237106cf1596e557..265f70ed9e4f8e48a0537ad773f220386c4713cd 100644 (file)
@@ -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
 }
index ecab83e276ae4d2e29844bc2c10a52e9f77772c7..43ef9bdad246a3129fb4eb8e4b821706a9508a0b 100644 (file)
@@ -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]+)+$"