1
0
mirror of https://github.com/golang/go synced 2024-11-12 08:10:21 -07:00

cmd/gc: enable inlining in generated method wrappers.

Method calls on interfaces with large stored values
will call the pointer receiver method which may be
a wrapper over a method with value receiver.

This is particularly inefficient for very small bodies.
Inlining the wrapped method body saves a potentially expensive
function call.

benchmark                old ns/op    new ns/op    delta
BenchmarkSortString1K       802295       641387  -20.06%
BenchmarkSortInt1K          359914       238234  -33.81%
BenchmarkSortInt64K       35764226     22803078  -36.24%

Fixes #4707.

R=golang-dev, daniel.morsing, rsc
CC=golang-dev
https://golang.org/cl/7214044
This commit is contained in:
Rémy Oudompheng 2013-03-11 21:24:51 +01:00
parent 404e4a90cb
commit 386ad0ab90
3 changed files with 30 additions and 8 deletions

View File

@ -565,24 +565,31 @@ mkinlcall1(Node **np, Node *fn, int isddd)
inlretvars = nil; inlretvars = nil;
i = 0; i = 0;
// Make temp names to use instead of the originals // Make temp names to use instead of the originals
for(ll = dcl; ll; ll=ll->next) for(ll = dcl; ll; ll=ll->next) {
if(ll->n->class == PPARAMOUT) // return values handled below.
continue;
if(ll->n->op == ONAME) { if(ll->n->op == ONAME) {
ll->n->inlvar = inlvar(ll->n); ll->n->inlvar = inlvar(ll->n);
// Typecheck because inlvar is not necessarily a function parameter. // Typecheck because inlvar is not necessarily a function parameter.
typecheck(&ll->n->inlvar, Erv); typecheck(&ll->n->inlvar, Erv);
if ((ll->n->class&~PHEAP) != PAUTO) if ((ll->n->class&~PHEAP) != PAUTO)
ninit = list(ninit, nod(ODCL, ll->n->inlvar, N)); // otherwise gen won't emit the allocations for heapallocs ninit = list(ninit, nod(ODCL, ll->n->inlvar, N)); // otherwise gen won't emit the allocations for heapallocs
if (ll->n->class == PPARAMOUT) // we rely on the order being correct here
inlretvars = list(inlretvars, ll->n->inlvar);
} }
}
// anonymous return values, synthesize names for use in assignment that replaces return // temporaries for return values.
if(inlretvars == nil && fn->type->outtuple > 0) for(t = getoutargx(fn->type)->type; t; t = t->down) {
for(t = getoutargx(fn->type)->type; t; t = t->down) { if(t != T && t->nname != N && !isblank(t->nname)) {
m = inlvar(t->nname);
typecheck(&m, Erv);
t->nname->inlvar = m;
} else {
// anonymous return values, synthesize names for use in assignment that replaces return
m = retvar(t, i++); m = retvar(t, i++);
ninit = list(ninit, nod(ODCL, m, N));
inlretvars = list(inlretvars, m);
} }
ninit = list(ninit, nod(ODCL, m, N));
inlretvars = list(inlretvars, m);
}
// assign receiver. // assign receiver.
if(fn->type->thistuple && n->left->op == ODOTMETH) { if(fn->type->thistuple && n->left->op == ODOTMETH) {

View File

@ -16,6 +16,8 @@ static void dumpglobls(void);
void void
dumpobj(void) dumpobj(void)
{ {
NodeList *externs, *tmp;
bout = Bopen(outfile, OWRITE); bout = Bopen(outfile, OWRITE);
if(bout == nil) { if(bout == nil) {
flusherrors(); flusherrors();
@ -31,8 +33,20 @@ dumpobj(void)
outhist(bout); outhist(bout);
externs = nil;
if(externdcl != nil)
externs = externdcl->end;
dumpglobls(); dumpglobls();
dumptypestructs(); dumptypestructs();
// Dump extra globals.
tmp = externdcl;
if(externs != nil)
externdcl = externs->next;
dumpglobls();
externdcl = tmp;
dumpdata(); dumpdata();
dumpfuncs(); dumpfuncs();

View File

@ -2565,6 +2565,7 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface)
fn->dupok = 1; fn->dupok = 1;
typecheck(&fn, Etop); typecheck(&fn, Etop);
typechecklist(fn->nbody, Etop); typechecklist(fn->nbody, Etop);
inlcalls(fn);
curfn = nil; curfn = nil;
funccompile(fn, 0); funccompile(fn, 0);
} }