mirror of
https://github.com/golang/go.git
synced 2025-05-05 23:53:05 +00:00
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: Austin Clements <austin@google.com>
This commit is contained in:
parent
a4aa2e0c28
commit
3aa53b3135
@ -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 {
|
|||||||
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
|
|||||||
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) {
|
|||||||
"releasem",
|
"releasem",
|
||||||
"round",
|
"round",
|
||||||
"roundupsize",
|
"roundupsize",
|
||||||
"selectsize",
|
|
||||||
"stringStructOf",
|
"stringStructOf",
|
||||||
"subtract1",
|
"subtract1",
|
||||||
"subtractb",
|
"subtractb",
|
||||||
|
@ -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 {
|
|||||||
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 {
|
|||||||
// 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 {
|
|||||||
return init
|
return init
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keep in sync with src/runtime/select.go.
|
// bytePtrToIndex returns a Node representing "(*byte)(&n[i])".
|
||||||
func selecttype(size int64) *types.Type {
|
func bytePtrToIndex(n *Node, i int64) *Node {
|
||||||
// TODO(dvyukov): it's possible to generate Scase only once
|
s := nod(OCONVNOP, nod(OADDR, nod(OINDEX, n, nodintconst(i)), nil), nil)
|
||||||
// and then cache; and also cache Select per size.
|
s.Type = types.NewPtr(types.Types[TUINT8])
|
||||||
|
s = typecheck(s, Erv)
|
||||||
scase := tostruct([]*Node{
|
return s
|
||||||
namedfield("elem", types.NewPtr(types.Types[TUINT8])),
|
}
|
||||||
namedfield("chan", types.NewPtr(types.Types[TUINT8])),
|
|
||||||
namedfield("pc", types.Types[TUINTPTR]),
|
var scase *types.Type
|
||||||
namedfield("kind", types.Types[TUINT16]),
|
|
||||||
namedfield("receivedp", types.NewPtr(types.Types[TUINT8])),
|
// Keep in sync with src/runtime/select.go.
|
||||||
namedfield("releasetime", types.Types[TUINT64]),
|
func scasetype() *types.Type {
|
||||||
})
|
if scase == nil {
|
||||||
scase.SetNoalg(true)
|
scase = tostruct([]*Node{
|
||||||
|
namedfield("elem", types.NewPtr(types.Types[TUINT8])),
|
||||||
sel := tostruct([]*Node{
|
namedfield("chan", types.NewPtr(types.Types[TUINT8])),
|
||||||
namedfield("tcase", types.Types[TUINT16]),
|
namedfield("pc", types.Types[TUINTPTR]),
|
||||||
namedfield("ncase", types.Types[TUINT16]),
|
namedfield("kind", types.Types[TUINT16]),
|
||||||
namedfield("pollorder", types.NewPtr(types.Types[TUINT8])),
|
namedfield("receivedp", types.NewPtr(types.Types[TUINT8])),
|
||||||
namedfield("lockorder", types.NewPtr(types.Types[TUINT8])),
|
namedfield("releasetime", types.Types[TUINT64]),
|
||||||
namedfield("scase", types.NewArray(scase, size)),
|
})
|
||||||
namedfield("lockorderarr", types.NewArray(types.Types[TUINT16], size)),
|
scase.SetNoalg(true)
|
||||||
namedfield("pollorderarr", types.NewArray(types.Types[TUINT16], size)),
|
}
|
||||||
})
|
return scase
|
||||||
sel.SetNoalg(true)
|
|
||||||
|
|
||||||
return sel
|
|
||||||
}
|
}
|
||||||
|
@ -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 (
|
|||||||
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 (
|
|||||||
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() {
|
|||||||
|
|
||||||
// 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 {
|
|||||||
// 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 {
|
|||||||
|
|
||||||
// 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 {
|
|||||||
}
|
}
|
||||||
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 {
|
|||||||
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:
|
|||||||
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:
|
|||||||
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:
|
|||||||
// 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:
|
|||||||
}
|
}
|
||||||
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 (
|
|||||||
|
|
||||||
//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
|
|||||||
|
|
||||||
// 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 {
|
|||||||
// 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 {
|
|||||||
// 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) {
|
|||||||
// 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]+)+$"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user