]> Cypherpunks repositories - gostls13.git/commitdiff
gc: elide call to runtime.closure for function literals called in-place.
authorLuuk van Dijk <lvd@golang.org>
Tue, 31 May 2011 18:52:21 +0000 (20:52 +0200)
committerLuuk van Dijk <lvd@golang.org>
Tue, 31 May 2011 18:52:21 +0000 (20:52 +0200)
before:
runtime_test.BenchmarkCallClosure        5000000               499 ns/op
runtime_test.BenchmarkCallClosure1       5000000               681 ns/op

after:
runtime_test.BenchmarkCallClosure       500000000                5 ns/op
runtime_test.BenchmarkCallClosure1       10000000              160 ns/op

R=rsc
CC=golang-dev
https://golang.org/cl/4515167

src/cmd/gc/closure.c
src/cmd/gc/go.h
src/cmd/gc/walk.c
src/pkg/runtime/closure_test.go [new file with mode: 0644]

index eb70143665349bf45aa243c5c46a84ecc3e0e6fc..091abde6224ed44c38149fbc8bc89688b1545970 100644 (file)
@@ -199,3 +199,41 @@ walkclosure(Node *func, NodeList **init)
        walkexpr(&call, init);
        return call;
 }
+
+// Special case for closures that get called in place.
+// Optimize runtime.closure(X, __func__xxxx_, .... ) away
+// to __func__xxxx_(Y ....).
+// On entry, expect n->op == OCALL, n->left->op == OCLOSURE.
+void
+walkcallclosure(Node *n, NodeList **init)
+{
+       Node *z;
+       NodeList *ll, *cargs;
+
+       walkexpr(&n->left, init);
+       cargs = n->left    // FUNC runtime.closure
+               ->list     // arguments
+               ->next     // skip first
+               ->next;    // skip second
+
+       n->left = n->left  // FUNC runtime.closure
+               ->list     // arguments
+               ->next     // skip first
+               ->n        // AS (to indreg) 
+               ->right;   // argument  == the generated function 
+
+       // New arg list for n. First the closure-args, stolen from
+       // runtime.closure's 3rd and following,
+       ll = nil;
+       for (; cargs; cargs = cargs->next)
+               ll = list(ll, cargs->n->right);  // cargs->n is the OAS(INDREG, arg)
+
+       // then an extra zero, to fill the dummy return pointer slot,
+       z = nod(OXXX, N, N);
+       nodconst(z, types[TUINTPTR], 0);
+       z->typecheck = 1;
+       ll = list(ll, z);
+
+       // and finally the original parameter list.
+       n->list = concat(ll, n->list);
+}
index 3f07befcbd47cd1121edd551120e7e1d297935a2..f4ca58b7379d9ee58195663bdafad3bfc18959d0 100644 (file)
@@ -817,6 +817,7 @@ Node*       closurebody(NodeList *body);
 void   closurehdr(Node *ntype);
 void   typecheckclosure(Node *func);
 Node*  walkclosure(Node *func, NodeList **init);
+void   walkcallclosure(Node *n, NodeList **init);
 
 /*
  *     const.c
index b3b400556c1f9d3310034dcf5d8d74dd45f1ec44..68885e65969516b68fb9b8c7be1129d1e83b2847 100644 (file)
@@ -770,8 +770,15 @@ walkexpr(Node **np, NodeList **init)
                t = n->left->type;
                if(n->list && n->list->n->op == OAS)
                        goto ret;
-               walkexpr(&n->left, init);
+
+               if(n->left->op == OCLOSURE) {
+                       walkcallclosure(n, init);
+                       t = n->left->type;
+               } else
+                       walkexpr(&n->left, init);
+
                walkexprlist(n->list, init);
+
                ll = ascompatte(n->op, n->isddd, getinarg(t), n->list, 0, init);
                n->list = reorder1(ll);
                if(isselect(n)) {
diff --git a/src/pkg/runtime/closure_test.go b/src/pkg/runtime/closure_test.go
new file mode 100644 (file)
index 0000000..199016f
--- /dev/null
@@ -0,0 +1,21 @@
+// 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 runtime_test
+
+import "testing"
+
+var s int
+
+func BenchmarkCallClosure(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               s += func(ii int) int { return 2 * ii }(i)
+       }
+}
+
+func BenchmarkCallClosure1(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               j := i
+               s += func(ii int) int { return 2*ii + j }(i)
+       }
+}