go/test/fixedbugs/bug346.go
Dmitry Vyukov c4ee44b7b9 cmd/gc: transform closure calls to function calls
Currently we always create context objects for closures that capture variables.
However, it is completely unnecessary for direct calls of closures
(whether it is func()(), defer func()() or go func()()).
This change transforms any OCALLFUNC(OCLOSURE) to normal function call.
Closed variables become function arguments.
This transformation is especially beneficial for go func(),
because we do not need to allocate context object on heap.
But it makes direct closure calls a bit faster as well (see BenchmarkClosureCall).

On implementation level it required to introduce yet another compiler pass.
However, the pass iterates only over xtop, so it should not be an issue.
Transformation consists of two parts: closure transformation and call site
transformation. We can't run these parts on different sides of escape analysis,
because tree state is inconsistent. We can do both parts during typecheck,
we don't know how to capture variables and don't have call site.
We can't do both parts during walk of OCALLFUNC, because we can walk
OCLOSURE body earlier.
So now capturevars pass only decides how to capture variables
(this info is required for escape analysis). New transformclosure
pass, that runs just before order/walk, does all transformations
of a closure. And later walk of OCALLFUNC(OCLOSURE) transforms call site.

benchmark                            old ns/op     new ns/op     delta
BenchmarkClosureCall                 4.89          3.09          -36.81%
BenchmarkCreateGoroutinesCapture     1634          1294          -20.81%

benchmark                            old allocs     new allocs     delta
BenchmarkCreateGoroutinesCapture     6              2              -66.67%

benchmark                            old bytes     new bytes     delta
BenchmarkCreateGoroutinesCapture     176           48            -72.73%

Change-Id: Ic85e1706e18c3235cc45b3c0c031a9c1cdb7a40e
Reviewed-on: https://go-review.googlesource.com/4050
Reviewed-by: Russ Cox <rsc@golang.org>
2015-02-13 12:12:18 +00:00

37 lines
743 B
Go

// run
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import "os"
func main() {
// Test unclosed closure.
{
x := 4
a, b, c, d := func(i int) (p int, q int, r int, s int) { return 1, i, 3, x }(2)
if a != 1 || b != 2 || c != 3 || d != 4 {
println("1# abcd: expected 1 2 3 4 got", a, b, c, d)
os.Exit(1)
}
}
// Test real closure.
{
x := 4
gf = func(i int) (p int, q int, r int, s int) { return 1, i, 3, x }
a, b, c, d := gf(2)
if a != 1 || b != 2 || c != 3 || d != 4 {
println("2# abcd: expected 1 2 3 4 got", a, b, c, d)
os.Exit(1)
}
}
}
var gf func(int) (int, int, int, int)