Commit 3aa53b31 authored by Matthew Dempsky's avatar Matthew Dempsky

runtime: eliminate runtime.hselect

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