aboutsummaryrefslogtreecommitdiff
path: root/libgo
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2017-09-14 03:57:18 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2017-09-14 03:57:18 +0000
commit022aa0ce5eebafe60f20245c8ff26b60a5074dfd (patch)
tree4cff4e3e7be2beb8a86e66e9f1d6346a9e55fb36 /libgo
parent0468f67f27f49972dcd77758284a2709bd9249fe (diff)
downloadgcc-022aa0ce5eebafe60f20245c8ff26b60a5074dfd.zip
gcc-022aa0ce5eebafe60f20245c8ff26b60a5074dfd.tar.gz
gcc-022aa0ce5eebafe60f20245c8ff26b60a5074dfd.tar.bz2
compiler, runtime: simplify select and channel operations
In preparation for upgrading libgo to the 1.9 release, this approximately incorporates https://golang.org/cl/37661 and https://golang.org/cl/38351. CL 37661 changed the gc compiler such that the select statement simply returns an integer which is then used as the argument for a switch. Since gccgo already worked that way, this just adjusts the switch code to look like the gc switch code by removing the explicit case index expression and calculating it from the order of calls to selectsend, selectrecv, and selectdefault. CL 38351 simplifies the channel code by not passing the unused channel type descriptor pointer. Reviewed-on: https://go-review.googlesource.com/62730 From-SVN: r252749
Diffstat (limited to 'libgo')
-rw-r--r--libgo/go/reflect/value.go8
-rw-r--r--libgo/go/runtime/chan.go43
-rw-r--r--libgo/go/runtime/select.go135
3 files changed, 78 insertions, 108 deletions
diff --git a/libgo/go/reflect/value.go b/libgo/go/reflect/value.go
index 208bb2f..8f6a93b 100644
--- a/libgo/go/reflect/value.go
+++ b/libgo/go/reflect/value.go
@@ -1160,7 +1160,7 @@ func (v Value) recv(nb bool) (val Value, ok bool) {
} else {
p = unsafe.Pointer(&val.ptr)
}
- selected, ok := chanrecv(v.typ, v.pointer(), nb, p)
+ selected, ok := chanrecv(v.pointer(), nb, p)
if !selected {
val = Value{}
}
@@ -1191,7 +1191,7 @@ func (v Value) send(x Value, nb bool) (selected bool) {
} else {
p = unsafe.Pointer(&x.ptr)
}
- return chansend(v.typ, v.pointer(), p, nb)
+ return chansend(v.pointer(), p, nb)
}
// Set assigns x to the value v.
@@ -2327,10 +2327,10 @@ func chanlen(ch unsafe.Pointer) int
// (due to the escapes() call in ValueOf).
//go:noescape
-func chanrecv(t *rtype, ch unsafe.Pointer, nb bool, val unsafe.Pointer) (selected, received bool)
+func chanrecv(ch unsafe.Pointer, nb bool, val unsafe.Pointer) (selected, received bool)
//go:noescape
-func chansend(t *rtype, ch unsafe.Pointer, val unsafe.Pointer, nb bool) bool
+func chansend(ch unsafe.Pointer, val unsafe.Pointer, nb bool) bool
func makechan(typ *rtype, size uint64) (ch unsafe.Pointer)
func makemap(t *rtype) (m unsafe.Pointer)
diff --git a/libgo/go/runtime/chan.go b/libgo/go/runtime/chan.go
index a9574dd..d2470bd 100644
--- a/libgo/go/runtime/chan.go
+++ b/libgo/go/runtime/chan.go
@@ -118,8 +118,8 @@ func chanbuf(c *hchan, i uint) unsafe.Pointer {
// entry point for c <- x from compiled code
//go:nosplit
-func chansend1(t *chantype, c *hchan, elem unsafe.Pointer) {
- chansend(t, c, elem, true, getcallerpc(unsafe.Pointer(&t)))
+func chansend1(c *hchan, elem unsafe.Pointer) {
+ chansend(c, elem, true, getcallerpc(unsafe.Pointer(&c)))
}
/*
@@ -134,14 +134,7 @@ func chansend1(t *chantype, c *hchan, elem unsafe.Pointer) {
* been closed. it is easiest to loop and re-run
* the operation; we'll see that it's now closed.
*/
-func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uintptr) bool {
- if raceenabled {
- raceReadObjectPC(t.elem, ep, callerpc, funcPC(chansend))
- }
- if msanenabled {
- msanread(ep, t.elem.size)
- }
-
+func chansend(c *hchan, ep unsafe.Pointer, block bool, callerpc uintptr) bool {
if c == nil {
if !block {
return false
@@ -400,13 +393,13 @@ func closechan(c *hchan) {
// entry points for <- c from compiled code
//go:nosplit
-func chanrecv1(t *chantype, c *hchan, elem unsafe.Pointer) {
- chanrecv(t, c, elem, true)
+func chanrecv1(c *hchan, elem unsafe.Pointer) {
+ chanrecv(c, elem, true)
}
//go:nosplit
-func chanrecv2(t *chantype, c *hchan, elem unsafe.Pointer) (received bool) {
- _, received = chanrecv(t, c, elem, true)
+func chanrecv2(c *hchan, elem unsafe.Pointer) (received bool) {
+ _, received = chanrecv(c, elem, true)
return
}
@@ -416,7 +409,7 @@ func chanrecv2(t *chantype, c *hchan, elem unsafe.Pointer) (received bool) {
// Otherwise, if c is closed, zeros *ep and returns (true, false).
// Otherwise, fills in *ep with an element and returns (true, true).
// A non-nil ep must point to the heap or the caller's stack.
-func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, received bool) {
+func chanrecv(c *hchan, ep unsafe.Pointer, block bool) (selected, received bool) {
// raceenabled: don't need to check ep, as it is always on the stack
// or is new memory allocated by reflect.
@@ -609,8 +602,8 @@ func recv(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func()) {
// ... bar
// }
//
-func selectnbsend(t *chantype, c *hchan, elem unsafe.Pointer) (selected bool) {
- return chansend(t, c, elem, false, getcallerpc(unsafe.Pointer(&t)))
+func selectnbsend(c *hchan, elem unsafe.Pointer) (selected bool) {
+ return chansend(c, elem, false, getcallerpc(unsafe.Pointer(&c)))
}
// compiler implements
@@ -630,8 +623,8 @@ func selectnbsend(t *chantype, c *hchan, elem unsafe.Pointer) (selected bool) {
// ... bar
// }
//
-func selectnbrecv(t *chantype, elem unsafe.Pointer, c *hchan) (selected bool) {
- selected, _ = chanrecv(t, c, elem, false)
+func selectnbrecv(elem unsafe.Pointer, c *hchan) (selected bool) {
+ selected, _ = chanrecv(c, elem, false)
return
}
@@ -652,20 +645,20 @@ func selectnbrecv(t *chantype, elem unsafe.Pointer, c *hchan) (selected bool) {
// ... bar
// }
//
-func selectnbrecv2(t *chantype, elem unsafe.Pointer, received *bool, c *hchan) (selected bool) {
+func selectnbrecv2(elem unsafe.Pointer, received *bool, c *hchan) (selected bool) {
// TODO(khr): just return 2 values from this function, now that it is in Go.
- selected, *received = chanrecv(t, c, elem, false)
+ selected, *received = chanrecv(c, elem, false)
return
}
//go:linkname reflect_chansend reflect.chansend
-func reflect_chansend(t *chantype, c *hchan, elem unsafe.Pointer, nb bool) (selected bool) {
- return chansend(t, c, elem, !nb, getcallerpc(unsafe.Pointer(&t)))
+func reflect_chansend(c *hchan, elem unsafe.Pointer, nb bool) (selected bool) {
+ return chansend(c, elem, !nb, getcallerpc(unsafe.Pointer(&c)))
}
//go:linkname reflect_chanrecv reflect.chanrecv
-func reflect_chanrecv(t *chantype, c *hchan, nb bool, elem unsafe.Pointer) (selected bool, received bool) {
- return chanrecv(t, c, elem, !nb)
+func reflect_chanrecv(c *hchan, nb bool, elem unsafe.Pointer) (selected bool, received bool) {
+ return chanrecv(c, elem, !nb)
}
//go:linkname reflect_chanlen reflect.chanlen
diff --git a/libgo/go/runtime/select.go b/libgo/go/runtime/select.go
index 62c4049..f0cad1b 100644
--- a/libgo/go/runtime/select.go
+++ b/libgo/go/runtime/select.go
@@ -18,14 +18,14 @@ import (
//go:linkname selectdefault runtime.selectdefault
//go:linkname selectsend runtime.selectsend
//go:linkname selectrecv runtime.selectrecv
-//go:linkname selectrecv2 runtime.selectrecv2
//go:linkname selectgo runtime.selectgo
-const (
- debugSelect = false
+const debugSelect = false
+const (
// scase.kind
- caseRecv = iota
+ caseNil = iota
+ caseRecv
caseSend
caseDefault
)
@@ -47,10 +47,9 @@ type hselect struct {
type scase struct {
elem unsafe.Pointer // data element
c *hchan // chan
- pc uintptr // return pc
+ pc uintptr // return pc (for race detector / msan)
kind uint16
- index uint16 // case index
- receivedp *bool // pointer to received bool (recv2)
+ receivedp *bool // pointer to received bool, if any
releasetime int64
}
@@ -88,88 +87,64 @@ func newselect(sel *hselect, selsize int64, size int32) {
}
}
-func selectsend(sel *hselect, c *hchan, elem unsafe.Pointer, index int32) {
- // nil cases do not compete
- if c != nil {
- selectsendImpl(sel, c, getcallerpc(unsafe.Pointer(&sel)), elem, index)
- }
- return
-}
-
-// cut in half to give stack a chance to split
-func selectsendImpl(sel *hselect, c *hchan, pc uintptr, elem unsafe.Pointer, index int32) {
+func selectsend(sel *hselect, c *hchan, elem unsafe.Pointer) {
+ pc := getcallerpc(unsafe.Pointer(&sel))
i := sel.ncase
if i >= sel.tcase {
throw("selectsend: too many cases")
}
sel.ncase = i + 1
+ if c == nil {
+ return
+ }
cas := (*scase)(add(unsafe.Pointer(&sel.scase), uintptr(i)*unsafe.Sizeof(sel.scase[0])))
cas.pc = pc
cas.c = c
- cas.index = uint16(index)
cas.kind = caseSend
cas.elem = elem
if debugSelect {
- print("selectsend s=", sel, " pc=", hex(cas.pc), " chan=", cas.c, " index=", cas.index, "\n")
- }
-}
-
-func selectrecv(sel *hselect, c *hchan, elem unsafe.Pointer, index int32) {
- // nil cases do not compete
- if c != nil {
- selectrecvImpl(sel, c, getcallerpc(unsafe.Pointer(&sel)), elem, nil, index)
+ print("selectsend s=", sel, " pc=", hex(cas.pc), " chan=", cas.c, "\n")
}
- return
}
-func selectrecv2(sel *hselect, c *hchan, elem unsafe.Pointer, received *bool, index int32) {
- // nil cases do not compete
- if c != nil {
- selectrecvImpl(sel, c, getcallerpc(unsafe.Pointer(&sel)), elem, received, index)
- }
- return
-}
-
-func selectrecvImpl(sel *hselect, c *hchan, pc uintptr, elem unsafe.Pointer, received *bool, index int32) {
+func selectrecv(sel *hselect, c *hchan, elem unsafe.Pointer, received *bool) {
+ pc := getcallerpc(unsafe.Pointer(&sel))
i := sel.ncase
if i >= sel.tcase {
throw("selectrecv: too many cases")
}
sel.ncase = i + 1
+ if c == nil {
+ return
+ }
cas := (*scase)(add(unsafe.Pointer(&sel.scase), uintptr(i)*unsafe.Sizeof(sel.scase[0])))
cas.pc = pc
cas.c = c
- cas.index = uint16(index)
cas.kind = caseRecv
cas.elem = elem
cas.receivedp = received
if debugSelect {
- print("selectrecv s=", sel, " pc=", hex(cas.pc), " chan=", cas.c, " index=", cas.index, "\n")
+ print("selectrecv s=", sel, " pc=", hex(cas.pc), " chan=", cas.c, "\n")
}
}
-func selectdefault(sel *hselect, index int32) {
- selectdefaultImpl(sel, getcallerpc(unsafe.Pointer(&sel)), index)
- return
-}
-
-func selectdefaultImpl(sel *hselect, callerpc uintptr, index int32) {
+func selectdefault(sel *hselect) {
+ pc := getcallerpc(unsafe.Pointer(&sel))
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 = callerpc
+ cas.pc = pc
cas.c = nil
- cas.index = uint16(index)
cas.kind = caseDefault
if debugSelect {
- print("selectdefault s=", sel, " pc=", hex(cas.pc), " index=", cas.index, "\n")
+ print("selectdefault s=", sel, " pc=", hex(cas.pc), "\n")
}
}
@@ -193,14 +168,11 @@ func selunlock(scases []scase, lockorder []uint16) {
// the G that calls select runnable again and schedules it for execution.
// When the G runs on another M, it locks all the locks and frees sel.
// Now if the first M touches sel, it will access freed memory.
- n := len(scases)
- r := 0
- // skip the default case
- if n > 0 && scases[lockorder[0]].c == nil {
- r = 1
- }
- for i := n - 1; i >= r; i-- {
+ for i := len(scases) - 1; i >= 0; i-- {
c := scases[lockorder[i]].c
+ if c == nil {
+ break
+ }
if i > 0 && c == scases[lockorder[i-1]].c {
continue // will unlock it on the next iteration
}
@@ -241,20 +213,15 @@ func block() {
// *sel is on the current goroutine's stack (regardless of any
// escaping in selectgo).
//
-// selectgo does not return. Instead, it overwrites its return PC and
-// returns directly to the triggered select case. Because of this, it
-// cannot appear at the top of a split stack.
-func selectgo(sel *hselect) int32 {
- _, index := selectgoImpl(sel)
- return int32(index)
-}
-
-// selectgoImpl returns scase.pc and scase.so for the select
-// case which fired.
-func selectgoImpl(sel *hselect) (uintptr, uint16) {
+// 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 {
if debugSelect {
print("select: sel=", sel, "\n")
}
+ if sel.ncase != sel.tcase {
+ throw("selectgo: case count mismatch")
+ }
scaseslice := slice{unsafe.Pointer(&sel.scase), int(sel.ncase), int(sel.ncase)}
scases := *(*[]scase)(unsafe.Pointer(&scaseslice))
@@ -347,13 +314,19 @@ func selectgoImpl(sel *hselect) (uintptr, uint16) {
loop:
// pass 1 - look for something already waiting
+ var dfli int
var dfl *scase
+ var casi int
var cas *scase
for i := 0; i < int(sel.ncase); i++ {
- cas = &scases[pollorder[i]]
+ casi = int(pollorder[i])
+ cas = &scases[casi]
c = cas.c
switch cas.kind {
+ case caseNil:
+ continue
+
case caseRecv:
sg = c.sendq.dequeue()
if sg != nil {
@@ -382,12 +355,14 @@ loop:
}
case caseDefault:
+ dfli = casi
dfl = cas
}
}
if dfl != nil {
selunlock(scases, lockorder)
+ casi = dfli
cas = dfl
goto retc
}
@@ -400,7 +375,11 @@ loop:
}
nextp = &gp.waiting
for _, casei := range lockorder {
- cas = &scases[casei]
+ casi = int(casei)
+ cas = &scases[casi]
+ if cas.kind == caseNil {
+ continue
+ }
c = cas.c
sg := acquireSudog()
sg.g = gp
@@ -494,6 +473,7 @@ loop:
// otherwise they stack up on quiet channels
// record the successful case, if any.
// We singly-linked up the SudoGs in lock order.
+ casi = -1
cas = nil
sglist = gp.waiting
// Clear all elem before unlinking from gp.waiting.
@@ -506,11 +486,15 @@ loop:
for _, casei := range lockorder {
k = &scases[casei]
+ if k.kind == caseNil {
+ continue
+ }
if sglist.releasetime > 0 {
k.releasetime = sglist.releasetime
}
if sg == sglist {
// sg has already been dequeued by the G that woke us up.
+ casi = int(casei)
cas = k
} else {
c = k.c
@@ -659,7 +643,7 @@ retc:
if cas.releasetime > 0 {
blockevent(cas.releasetime-t0, 2)
}
- return cas.pc, cas.index
+ return casi
sclose:
// send on closed channel
@@ -703,22 +687,15 @@ func reflect_rselect(cases []runtimeSelect) (chosen int, recvOK bool) {
rc := &cases[i]
switch rc.dir {
case selectDefault:
- selectdefaultImpl(sel, uintptr(i), 0)
+ selectdefault(sel)
case selectSend:
- if rc.ch == nil {
- break
- }
- selectsendImpl(sel, rc.ch, uintptr(i), rc.val, 0)
+ selectsend(sel, rc.ch, rc.val)
case selectRecv:
- if rc.ch == nil {
- break
- }
- selectrecvImpl(sel, rc.ch, uintptr(i), rc.val, r, 0)
+ selectrecv(sel, rc.ch, rc.val, r)
}
}
- pc, _ := selectgoImpl(sel)
- chosen = int(pc)
+ chosen = selectgo(sel)
recvOK = *r
return
}