Commit 97fd7d5f authored by Luuk van Dijk's avatar Luuk van Dijk

gc: inlining fixes

flag -l means: inlining on, -ll inline with early typecheck
-l lazily typechecks imports on use and re-export, nicer for debugging
-lm produces output suitable for errchk tests, repeated -mm... increases inl.c's verbosity
export processed constants, instead of originals
outparams get ->inlvar too, and initialized to zero
fix shared rlist bug, that lead to typecheck messing up the patched tree
properly handle non-method calls to methods T.meth(t, a...)
removed embryonic code to handle closures in inlined bodies
also inline calls inside closures (todo: move from phase 6b to 4)

Fixes #2579.

R=rsc
CC=golang-dev
https://golang.org/cl/5489106
parent 5032a7dc
......@@ -104,18 +104,34 @@ reexportdep(Node *n)
if(!n)
return;
// print("reexportdep %+hN\n", n);
switch(n->op) {
case ONAME:
switch(n->class&~PHEAP) {
case PFUNC:
// methods will be printed along with their type
if(!n->type || n->type->thistuple > 0)
break;
// fallthrough
case PEXTERN:
if (n->sym && n->sym->pkg != localpkg && n->sym->pkg != builtinpkg)
exportlist = list(exportlist, n);
}
break;
case OTYPE:
case OLITERAL:
t = n->type;
if(t != types[n->type->etype] && t != idealbool && t != idealstring) {
if(isptr[t->etype])
t = t->type;
if (t && t->sym && t->sym->def && t->sym->pkg != localpkg && t->sym->pkg != builtinpkg) {
// print("reexport literal type %+hN\n", t->sym->def);
exportlist = list(exportlist, t->sym->def);
}
}
// fallthrough
case OTYPE:
if (n->sym && n->sym->pkg != localpkg && n->sym->pkg != builtinpkg)
exportlist = list(exportlist, n);
break;
......@@ -176,7 +192,7 @@ dumpexportvar(Sym *s)
Type *t;
n = s->def;
typecheck(&n, Erv);
typecheck(&n, Erv|Ecall);
if(n == N || n->type == T) {
yyerror("variable exported but not defined: %S", s);
return;
......@@ -187,6 +203,10 @@ dumpexportvar(Sym *s)
if(t->etype == TFUNC && n->class == PFUNC) {
if (n->inl) {
// when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet.
// currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package
if(debug['l'] < 2)
typecheckinl(n);
Bprint(bout, "\tfunc %#S%#hT { %#H }\n", s, t, n->inl);
reexportdeplist(n->inl);
} else
......@@ -243,6 +263,10 @@ dumpexporttype(Type *t)
for(i=0; i<n; i++) {
f = m[i];
if (f->type->nname && f->type->nname->inl) { // nname was set by caninl
// when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet.
// currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package
if(debug['l'] < 2)
typecheckinl(f->type->nname);
Bprint(bout, "\tfunc (%#T) %#hhS%#hT { %#H }\n", getthisx(f->type)->type, f->sym, f->type, f->type->nname->inl);
reexportdeplist(f->type->nname->inl);
} else
......@@ -261,7 +285,7 @@ dumpsym(Sym *s)
yyerror("unknown export symbol: %S", s);
return;
}
// print("dumpsym %O %+S\n", s->def->op, s);
dumppkg(s->pkg);
switch(s->def->op) {
......
......@@ -933,6 +933,7 @@ stmtfmt(Fmt *f, Node *n)
static int opprec[] = {
[OAPPEND] = 8,
[OARRAYBYTESTR] = 8,
[OARRAYLIT] = 8,
[OCALLFUNC] = 8,
[OCALLINTER] = 8,
[OCALLMETH] = 8,
......@@ -947,6 +948,7 @@ static int opprec[] = {
[OLITERAL] = 8,
[OMAKESLICE] = 8,
[OMAKE] = 8,
[OMAPLIT] = 8,
[ONAME] = 8,
[ONEW] = 8,
[ONONAME] = 8,
......@@ -957,10 +959,14 @@ static int opprec[] = {
[OPRINT] = 8,
[ORECV] = 8,
[ORUNESTR] = 8,
[OTPAREN] = 8,
[OSTRUCTLIT] = 8,
[OMAPLIT] = 8,
[OARRAYLIT] = 8,
[OTARRAY] = 8,
[OTCHAN] = 8,
[OTFUNC] = 8,
[OTINTER] = 8,
[OTMAP] = 8,
[OTPAREN] = 8,
[OTSTRUCT] = 8,
[OINDEXMAP] = 8,
[OINDEX] = 8,
......@@ -1291,7 +1297,13 @@ nodefmt(Fmt *f, Node *n)
Type *t;
t = n->type;
if(n->orig != N)
if(n->orig == N)
fatal("node with no orig %N", n);
// we almost always want the original, except in export mode for literals
// this saves the importer some work, and avoids us having to redo some
// special casing for package unsafe
if(fmtmode != FExp || n->op != OLITERAL)
n = n->orig;
if(f->flags&FmtLong && t != T) {
......
......@@ -996,6 +996,7 @@ Sym* renameinit(void);
*/
void caninl(Node *fn);
void inlcalls(Node *fn);
void typecheckinl(Node *fn);
/*
* lex.c
......
This diff is collapsed.
......@@ -337,20 +337,14 @@ main(int argc, char *argv[])
errorexit();
// Phase 4: Inlining
if (debug['l']) { // TODO only if debug['l'] > 1, otherwise lazily when used.
// Typecheck imported function bodies
for(l=importlist; l; l=l->next) {
if (l->n->inl == nil)
continue;
curfn = l->n;
saveerrors();
importpkg = l->n->sym->pkg;
if (debug['l']>2)
print("typecheck import [%S] %lN { %#H }\n", l->n->sym, l->n, l->n->inl);
typechecklist(l->n->inl, Etop);
importpkg = nil;
}
curfn = nil;
if (debug['l'] > 1) {
// Typecheck imported function bodies if debug['l'] > 1,
// otherwise lazily when used or re-exported.
for(l=importlist; l; l=l->next)
if (l->n->inl) {
saveerrors();
typecheckinl(l->n);
}
if(nsavederrors+nerrors)
errorexit();
......@@ -384,8 +378,11 @@ main(int argc, char *argv[])
while(closures) {
l = closures;
closures = nil;
for(; l; l=l->next)
for(; l; l=l->next) {
if (debug['l'])
inlcalls(l->n);
funccompile(l->n, 1);
}
}
// Phase 7: check external declarations.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment