1
0
mirror of https://github.com/golang/go synced 2024-11-25 05:57:57 -07:00

gc: elide call to runtime.closure for function literals called in-place.

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
This commit is contained in:
Luuk van Dijk 2011-05-31 20:52:21 +02:00
parent 6216307e25
commit 9b82408f6d
4 changed files with 68 additions and 1 deletions

View File

@ -199,3 +199,41 @@ walkclosure(Node *func, NodeList **init)
walkexpr(&call, init); walkexpr(&call, init);
return call; 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);
}

View File

@ -817,6 +817,7 @@ Node* closurebody(NodeList *body);
void closurehdr(Node *ntype); void closurehdr(Node *ntype);
void typecheckclosure(Node *func); void typecheckclosure(Node *func);
Node* walkclosure(Node *func, NodeList **init); Node* walkclosure(Node *func, NodeList **init);
void walkcallclosure(Node *n, NodeList **init);
/* /*
* const.c * const.c

View File

@ -770,8 +770,15 @@ walkexpr(Node **np, NodeList **init)
t = n->left->type; t = n->left->type;
if(n->list && n->list->n->op == OAS) if(n->list && n->list->n->op == OAS)
goto ret; goto ret;
if(n->left->op == OCLOSURE) {
walkcallclosure(n, init);
t = n->left->type;
} else
walkexpr(&n->left, init); walkexpr(&n->left, init);
walkexprlist(n->list, init); walkexprlist(n->list, init);
ll = ascompatte(n->op, n->isddd, getinarg(t), n->list, 0, init); ll = ascompatte(n->op, n->isddd, getinarg(t), n->list, 0, init);
n->list = reorder1(ll); n->list = reorder1(ll);
if(isselect(n)) { if(isselect(n)) {

View File

@ -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)
}
}