Skip to content

Commit b6753ba

Browse files
rscgopherbot
authored andcommitted
cmd/compile: compile len(ch) as call to runtime.chanlen
An upcoming CL will give this call more to do. For now, separate out the compiler change that stops inlining the computation. Change-Id: I4c5cbd84a0694b306191bff38cc6ea2d69458d7d Reviewed-on: https://go-review.googlesource.com/c/go/+/564556 Auto-Submit: Russ Cox <[email protected]> Reviewed-by: Matthew Dempsky <[email protected]> Reviewed-by: Cuong Manh Le <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
1 parent 370c8e9 commit b6753ba

File tree

6 files changed

+163
-142
lines changed

6 files changed

+163
-142
lines changed

src/cmd/compile/internal/ssagen/ssa.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6349,6 +6349,9 @@ func (s *state) referenceTypeBuiltin(n *ir.UnaryExpr, x *ssa.Value) *ssa.Value {
63496349
if !n.X.Type().IsMap() && !n.X.Type().IsChan() {
63506350
s.Fatalf("node must be a map or a channel")
63516351
}
6352+
if n.X.Type().IsChan() && n.Op() == ir.OLEN {
6353+
s.Fatalf("cannot inline len(chan)") // must use runtime.chanlen now
6354+
}
63526355
// if n == nil {
63536356
// return 0
63546357
// } else {

src/cmd/compile/internal/typecheck/_builtin/coverage.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// license that can be found in the LICENSE file.
44

55
// NOTE: If you change this file you must run "go generate"
6+
// in cmd/compile/internal/typecheck
67
// to update builtin.go. This is not done automatically
78
// to avoid depending on having a working compiler binary.
89

src/cmd/compile/internal/typecheck/_builtin/runtime.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// license that can be found in the LICENSE file.
44

55
// NOTE: If you change this file you must run "go generate"
6+
// in cmd/compile/internal/typecheck
67
// to update builtin.go. This is not done automatically
78
// to avoid depending on having a working compiler binary.
89

@@ -158,7 +159,8 @@ func makechan(chanType *byte, size int) (hchan chan any)
158159
func chanrecv1(hchan <-chan any, elem *any)
159160
func chanrecv2(hchan <-chan any, elem *any) bool
160161
func chansend1(hchan chan<- any, elem *any)
161-
func closechan(hchan any)
162+
func closechan(hchan chan<- any)
163+
func chanlen(hchan any) int
162164

163165
var writeBarrier struct {
164166
enabled bool

src/cmd/compile/internal/typecheck/builtin.go

Lines changed: 135 additions & 132 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/cmd/compile/internal/walk/builtin.go

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -153,9 +153,7 @@ func walkClear(n *ir.UnaryExpr) ir.Node {
153153

154154
// walkClose walks an OCLOSE node.
155155
func walkClose(n *ir.UnaryExpr, init *ir.Nodes) ir.Node {
156-
// cannot use chanfn - closechan takes any, not chan any
157-
fn := typecheck.LookupRuntime("closechan", n.X.Type())
158-
return mkcall1(fn, nil, init, n.X)
156+
return mkcall1(chanfn("closechan", 1, n.X.Type()), nil, init, n.X)
159157
}
160158

161159
// Lower copy(a, b) to a memmove call or a runtime call.
@@ -263,6 +261,12 @@ func walkLenCap(n *ir.UnaryExpr, init *ir.Nodes) ir.Node {
263261
_, len := backingArrayPtrLen(cheapExpr(conv.X, init))
264262
return len
265263
}
264+
if isChanLen(n) {
265+
// cannot use chanfn - closechan takes any, not chan any,
266+
// because it accepts both send-only and recv-only channels.
267+
fn := typecheck.LookupRuntime("chanlen", n.X.Type())
268+
return mkcall1(fn, n.Type(), init, n.X)
269+
}
266270

267271
n.X = walkExpr(n.X, init)
268272

@@ -887,3 +891,10 @@ func isByteCount(n ir.Node) bool {
887891
return base.Flag.N == 0 && !base.Flag.Cfg.Instrumenting && n.Op() == ir.OLEN &&
888892
(n.(*ir.UnaryExpr).X.Op() == ir.OBYTES2STR || n.(*ir.UnaryExpr).X.Op() == ir.OBYTES2STRTMP)
889893
}
894+
895+
// isChanLen reports whether n is of the form len(c) for a channel c.
896+
// Note that this does not check for -n or instrumenting because this
897+
// is a correctness rewrite, not an optimization.
898+
func isChanLen(n ir.Node) bool {
899+
return n.Op() == ir.OLEN && n.(*ir.UnaryExpr).X.Type().IsChan()
900+
}

src/runtime/chan.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -724,20 +724,21 @@ func reflect_chanrecv(c *hchan, nb bool, elem unsafe.Pointer) (selected bool, re
724724
return chanrecv(c, elem, !nb)
725725
}
726726

727-
//go:linkname reflect_chanlen reflect.chanlen
728-
func reflect_chanlen(c *hchan) int {
727+
func chanlen(c *hchan) int {
729728
if c == nil {
730729
return 0
731730
}
732731
return int(c.qcount)
733732
}
734733

734+
//go:linkname reflect_chanlen reflect.chanlen
735+
func reflect_chanlen(c *hchan) int {
736+
return chanlen(c)
737+
}
738+
735739
//go:linkname reflectlite_chanlen internal/reflectlite.chanlen
736740
func reflectlite_chanlen(c *hchan) int {
737-
if c == nil {
738-
return 0
739-
}
740-
return int(c.qcount)
741+
return chanlen(c)
741742
}
742743

743744
//go:linkname reflect_chancap reflect.chancap

0 commit comments

Comments
 (0)