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) ...@@ -104,18 +104,34 @@ reexportdep(Node *n)
if(!n) if(!n)
return; return;
// print("reexportdep %+hN\n", n);
switch(n->op) { switch(n->op) {
case ONAME: case ONAME:
switch(n->class&~PHEAP) { switch(n->class&~PHEAP) {
case PFUNC: case PFUNC:
// methods will be printed along with their type
if(!n->type || n->type->thistuple > 0)
break;
// fallthrough
case PEXTERN: case PEXTERN:
if (n->sym && n->sym->pkg != localpkg && n->sym->pkg != builtinpkg) if (n->sym && n->sym->pkg != localpkg && n->sym->pkg != builtinpkg)
exportlist = list(exportlist, n); exportlist = list(exportlist, n);
} }
break; break;
case OTYPE:
case OLITERAL: 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) if (n->sym && n->sym->pkg != localpkg && n->sym->pkg != builtinpkg)
exportlist = list(exportlist, n); exportlist = list(exportlist, n);
break; break;
...@@ -176,7 +192,7 @@ dumpexportvar(Sym *s) ...@@ -176,7 +192,7 @@ dumpexportvar(Sym *s)
Type *t; Type *t;
n = s->def; n = s->def;
typecheck(&n, Erv); typecheck(&n, Erv|Ecall);
if(n == N || n->type == T) { if(n == N || n->type == T) {
yyerror("variable exported but not defined: %S", s); yyerror("variable exported but not defined: %S", s);
return; return;
...@@ -187,6 +203,10 @@ dumpexportvar(Sym *s) ...@@ -187,6 +203,10 @@ dumpexportvar(Sym *s)
if(t->etype == TFUNC && n->class == PFUNC) { if(t->etype == TFUNC && n->class == PFUNC) {
if (n->inl) { 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); Bprint(bout, "\tfunc %#S%#hT { %#H }\n", s, t, n->inl);
reexportdeplist(n->inl); reexportdeplist(n->inl);
} else } else
...@@ -243,6 +263,10 @@ dumpexporttype(Type *t) ...@@ -243,6 +263,10 @@ dumpexporttype(Type *t)
for(i=0; i<n; i++) { for(i=0; i<n; i++) {
f = m[i]; f = m[i];
if (f->type->nname && f->type->nname->inl) { // nname was set by caninl 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); 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); reexportdeplist(f->type->nname->inl);
} else } else
...@@ -261,7 +285,7 @@ dumpsym(Sym *s) ...@@ -261,7 +285,7 @@ dumpsym(Sym *s)
yyerror("unknown export symbol: %S", s); yyerror("unknown export symbol: %S", s);
return; return;
} }
// print("dumpsym %O %+S\n", s->def->op, s);
dumppkg(s->pkg); dumppkg(s->pkg);
switch(s->def->op) { switch(s->def->op) {
......
...@@ -933,6 +933,7 @@ stmtfmt(Fmt *f, Node *n) ...@@ -933,6 +933,7 @@ stmtfmt(Fmt *f, Node *n)
static int opprec[] = { static int opprec[] = {
[OAPPEND] = 8, [OAPPEND] = 8,
[OARRAYBYTESTR] = 8, [OARRAYBYTESTR] = 8,
[OARRAYLIT] = 8,
[OCALLFUNC] = 8, [OCALLFUNC] = 8,
[OCALLINTER] = 8, [OCALLINTER] = 8,
[OCALLMETH] = 8, [OCALLMETH] = 8,
...@@ -947,6 +948,7 @@ static int opprec[] = { ...@@ -947,6 +948,7 @@ static int opprec[] = {
[OLITERAL] = 8, [OLITERAL] = 8,
[OMAKESLICE] = 8, [OMAKESLICE] = 8,
[OMAKE] = 8, [OMAKE] = 8,
[OMAPLIT] = 8,
[ONAME] = 8, [ONAME] = 8,
[ONEW] = 8, [ONEW] = 8,
[ONONAME] = 8, [ONONAME] = 8,
...@@ -957,10 +959,14 @@ static int opprec[] = { ...@@ -957,10 +959,14 @@ static int opprec[] = {
[OPRINT] = 8, [OPRINT] = 8,
[ORECV] = 8, [ORECV] = 8,
[ORUNESTR] = 8, [ORUNESTR] = 8,
[OTPAREN] = 8,
[OSTRUCTLIT] = 8, [OSTRUCTLIT] = 8,
[OMAPLIT] = 8, [OTARRAY] = 8,
[OARRAYLIT] = 8, [OTCHAN] = 8,
[OTFUNC] = 8,
[OTINTER] = 8,
[OTMAP] = 8,
[OTPAREN] = 8,
[OTSTRUCT] = 8,
[OINDEXMAP] = 8, [OINDEXMAP] = 8,
[OINDEX] = 8, [OINDEX] = 8,
...@@ -1291,7 +1297,13 @@ nodefmt(Fmt *f, Node *n) ...@@ -1291,7 +1297,13 @@ nodefmt(Fmt *f, Node *n)
Type *t; Type *t;
t = n->type; 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; n = n->orig;
if(f->flags&FmtLong && t != T) { if(f->flags&FmtLong && t != T) {
......
...@@ -996,6 +996,7 @@ Sym* renameinit(void); ...@@ -996,6 +996,7 @@ Sym* renameinit(void);
*/ */
void caninl(Node *fn); void caninl(Node *fn);
void inlcalls(Node *fn); void inlcalls(Node *fn);
void typecheckinl(Node *fn);
/* /*
* lex.c * lex.c
......
This diff is collapsed.
...@@ -337,20 +337,14 @@ main(int argc, char *argv[]) ...@@ -337,20 +337,14 @@ main(int argc, char *argv[])
errorexit(); errorexit();
// Phase 4: Inlining // Phase 4: Inlining
if (debug['l']) { // TODO only if debug['l'] > 1, otherwise lazily when used. if (debug['l'] > 1) {
// Typecheck imported function bodies // Typecheck imported function bodies if debug['l'] > 1,
for(l=importlist; l; l=l->next) { // otherwise lazily when used or re-exported.
if (l->n->inl == nil) for(l=importlist; l; l=l->next)
continue; if (l->n->inl) {
curfn = l->n; saveerrors();
saveerrors(); typecheckinl(l->n);
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(nsavederrors+nerrors) if(nsavederrors+nerrors)
errorexit(); errorexit();
...@@ -384,8 +378,11 @@ main(int argc, char *argv[]) ...@@ -384,8 +378,11 @@ main(int argc, char *argv[])
while(closures) { while(closures) {
l = closures; l = closures;
closures = nil; closures = nil;
for(; l; l=l->next) for(; l; l=l->next) {
if (debug['l'])
inlcalls(l->n);
funccompile(l->n, 1); funccompile(l->n, 1);
}
} }
// Phase 7: check external declarations. // 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