Commit 0970c468 authored by Russ Cox's avatar Russ Cox

closures - 6g support

R=ken
OCL=24501
CL=24566
parent 0f4f2a61
...@@ -205,7 +205,7 @@ cgen(Node *n, Node *res) ...@@ -205,7 +205,7 @@ cgen(Node *n, Node *res)
case ODOTPTR: case ODOTPTR:
case OINDEX: case OINDEX:
case OIND: case OIND:
case ONAME: // PHEAP var case ONAME: // PHEAP or PPARAMREF var
igen(n, &n1, res); igen(n, &n1, res);
gmove(&n1, res); gmove(&n1, res);
regfree(&n1); regfree(&n1);
...@@ -526,9 +526,18 @@ agen(Node *n, Node *res) ...@@ -526,9 +526,18 @@ agen(Node *n, Node *res)
break; break;
case ONAME: case ONAME:
// should only get here for heap vars // should only get here with names in this func.
if(!(n->class & PHEAP)) if(n->funcdepth > 0 && n->funcdepth != funcdepth) {
dump("bad agen", n);
fatal("agen: bad ONAME funcdepth %d != %d",
n->funcdepth, funcdepth);
}
// should only get here for heap vars or paramref
if(!(n->class & PHEAP) && n->class != PPARAMREF) {
dump("bad agen", n);
fatal("agen: bad ONAME class %#x", n->class); fatal("agen: bad ONAME class %#x", n->class);
}
cgen(n->heapaddr, res); cgen(n->heapaddr, res);
if(n->xoffset != 0) { if(n->xoffset != 0) {
nodconst(&n1, types[TINT64], n->xoffset); nodconst(&n1, types[TINT64], n->xoffset);
......
...@@ -402,13 +402,12 @@ funchdr(Node *n) ...@@ -402,13 +402,12 @@ funchdr(Node *n)
autodcl = dcl(); autodcl = dcl();
autodcl->back = autodcl; autodcl->back = autodcl;
if(dclcontext != PEXTERN) if(funcdepth == 0 && dclcontext != PEXTERN)
fatal("funchdr: dclcontext"); fatal("funchdr: dclcontext");
dclcontext = PAUTO; dclcontext = PAUTO;
markdcl(); markdcl();
funcargs(n->type); funcargs(n->type);
} }
void void
...@@ -418,6 +417,8 @@ funcargs(Type *ft) ...@@ -418,6 +417,8 @@ funcargs(Type *ft)
Iter save; Iter save;
int all; int all;
funcdepth++;
// declare the this/in arguments // declare the this/in arguments
t = funcfirst(&save, ft); t = funcfirst(&save, ft);
while(t != T) { while(t != T) {
...@@ -466,9 +467,176 @@ funcbody(Node *n) ...@@ -466,9 +467,176 @@ funcbody(Node *n)
if(dclcontext != PAUTO) if(dclcontext != PAUTO)
fatal("funcbody: dclcontext"); fatal("funcbody: dclcontext");
popdcl(); popdcl();
funcdepth--;
if(funcdepth == 0)
dclcontext = PEXTERN; dclcontext = PEXTERN;
} }
void
funclit0(Type *t)
{
Node *n;
n = nod(OXXX, N, N);
n->outer = funclit;
funclit = n;
funcargs(t);
}
Node*
funclit1(Type *type, Node *body)
{
Node *func;
Node *a, *d, *f, *n, *args, *clos, *in, *out;
Type *ft, *t;
Iter save;
int narg, shift;
popdcl();
func = funclit;
funclit = func->outer;
// build up type of func f that we're going to compile.
// as we referred to variables from the outer function,
// we accumulated a list of PHEAP names in func.
//
narg = 0;
if(func->cvars == N)
ft = type;
else {
// add PHEAP versions as function arguments.
in = N;
for(a=listfirst(&save, &func->cvars); a; a=listnext(&save)) {
d = nod(ODCLFIELD, a, N);
d->type = ptrto(a->type);
in = list(in, d);
// while we're here, set up a->heapaddr for back end
n = nod(ONAME, N, N);
snprint(namebuf, sizeof namebuf, "&%s", a->sym->name);
n->sym = lookup(namebuf);
n->type = ptrto(a->type);
n->class = PPARAM;
n->xoffset = narg*types[tptr]->width;
n->addable = 1;
n->ullman = 1;
narg++;
a->heapaddr = n;
a->xoffset = 0;
// unlink from actual ONAME in symbol table
a->closure->closure = a->outer;
}
// add a dummy arg for the closure's caller pc
d = nod(ODCLFIELD, a, N);
d->type = types[TUINTPTR];
in = list(in, d);
// slide param offset to make room for ptrs above.
// narg+1 to skip over caller pc.
shift = (narg+1)*types[tptr]->width;
// now the original arguments.
for(t=structfirst(&save, getinarg(type)); t; t=structnext(&save)) {
d = nod(ODCLFIELD, t->nname, N);
d->type = t->type;
in = list(in, d);
a = t->nname;
if(a != N) {
if(a->stackparam != N)
a = a->stackparam;
a->xoffset += shift;
}
}
in = rev(in);
// out arguments
out = N;
for(t=structfirst(&save, getoutarg(type)); t; t=structnext(&save)) {
d = nod(ODCLFIELD, t->nname, N);
d->type = t->type;
out = list(out, d);
a = t->nname;
if(a != N) {
if(a->stackparam != N)
a = a->stackparam;
a->xoffset += shift;
}
}
out = rev(out);
ft = functype(N, in, out);
}
// declare function.
vargen++;
snprint(namebuf, sizeof(namebuf), "_f%.3ld", vargen);
f = newname(lookup(namebuf));
addvar(f, ft, PFUNC);
f->funcdepth = 0;
// compile function
n = nod(ODCLFUNC, N, N);
n->nname = f;
n->type = ft;
if(body == N)
body = nod(ORETURN, N, N);
n->nbody = body;
compile(n);
funcdepth--;
// if there's no closure, we can use f directly
if(func->cvars == N)
return f;
// build up type for this instance of the closure func.
in = N;
d = nod(ODCLFIELD, N, N); // siz
d->type = types[TINT];
in = list(in, d);
d = nod(ODCLFIELD, N, N); // f
d->type = ft;
in = list(in, d);
for(a=listfirst(&save, &func->cvars); a; a=listnext(&save)) {
d = nod(ODCLFIELD, N, N); // arg
d->type = ptrto(a->type);
in = list(in, d);
}
in = rev(in);
d = nod(ODCLFIELD, N, N);
d->type = type;
out = d;
clos = syslook("closure", 1);
clos->type = functype(N, in, out);
// literal expression is sys.closure(siz, f, arg0, arg1, ...)
// which builds a function that calls f after filling in arg0,
// arg1, ... for the PHEAP arguments above.
args = N;
if(narg*8 > 100)
yyerror("closure needs too many variables; runtime will reject it");
a = nodintconst(narg*8);
args = list(args, a); // siz
args = list(args, f); // f
for(a=listfirst(&save, &func->cvars); a; a=listnext(&save)) {
d = oldname(a->sym);
addrescapes(d);
args = list(args, nod(OADDR, d, N));
}
args = rev(args);
return nod(OCALL, clos, args);
}
/* /*
* turn a parsed struct into a type * turn a parsed struct into a type
*/ */
...@@ -657,28 +825,6 @@ markdcl(void) ...@@ -657,28 +825,6 @@ markdcl(void)
// print("markdcl\n"); // print("markdcl\n");
} }
void
markdclstack(void)
{
Sym *d, *s;
markdcl();
// copy the entire pop of the stack
// all the way back to block0.
// after this the symbol table is at
// block0 and popdcl will restore it.
for(d=dclstack; d!=S; d=d->link) {
if(d == b0stack)
break;
if(d->name != nil) {
s = pkglookup(d->name, d->package);
pushdcl(s);
dcopy(s, d);
}
}
}
void void
dumpdcl(char *st) dumpdcl(char *st)
{ {
...@@ -755,6 +901,7 @@ addvar(Node *n, Type *t, int ctxt) ...@@ -755,6 +901,7 @@ addvar(Node *n, Type *t, int ctxt)
s->offset = 0; s->offset = 0;
s->lexical = LNAME; s->lexical = LNAME;
n->funcdepth = funcdepth;
n->type = t; n->type = t;
n->vargen = gen; n->vargen = gen;
n->class = ctxt; n->class = ctxt;
...@@ -909,6 +1056,7 @@ Node* ...@@ -909,6 +1056,7 @@ Node*
oldname(Sym *s) oldname(Sym *s)
{ {
Node *n; Node *n;
Node *c;
n = s->oname; n = s->oname;
if(n == N) { if(n == N) {
...@@ -918,6 +1066,26 @@ oldname(Sym *s) ...@@ -918,6 +1066,26 @@ oldname(Sym *s)
n->addable = 1; n->addable = 1;
n->ullman = 1; n->ullman = 1;
} }
if(n->funcdepth > 0 && n->funcdepth != funcdepth) {
// inner func is referring to var
// in outer func.
if(n->closure == N || n->closure->funcdepth != funcdepth) {
// create new closure var.
c = nod(ONAME, N, N);
c->sym = s;
c->class = PPARAMREF;
c->type = n->type;
c->addable = 0;
c->ullman = 2;
c->funcdepth = funcdepth;
c->outer = n->closure;
n->closure = c;
c->closure = n;
funclit->cvars = list(c, funclit->cvars);
}
// return ref to closure var, not original
return n->closure;
}
return n; return n;
} }
......
...@@ -187,6 +187,7 @@ struct Node ...@@ -187,6 +187,7 @@ struct Node
uchar colas; // OAS resulting from := uchar colas; // OAS resulting from :=
uchar diag; // already printed error about this uchar diag; // already printed error about this
uchar noescape; // ONAME never move to heap uchar noescape; // ONAME never move to heap
uchar funcdepth;
// most nodes // most nodes
Node* left; Node* left;
...@@ -209,6 +210,7 @@ struct Node ...@@ -209,6 +210,7 @@ struct Node
Node* nname; Node* nname;
Node* enter; Node* enter;
Node* exit; Node* exit;
Node* cvars; // closure params
// OLITERAL/OREGISTER // OLITERAL/OREGISTER
Val val; Val val;
...@@ -218,6 +220,10 @@ struct Node ...@@ -218,6 +220,10 @@ struct Node
Node* stackparam; // OPARAM node referring to stack copy of param Node* stackparam; // OPARAM node referring to stack copy of param
Node* alloc; // allocation call Node* alloc; // allocation call
// ONAME closure param with PPARAMREF
Node* outer; // outer PPARAMREF in nested closure
Node* closure; // ONAME/PHEAP <-> ONAME/PPARAMREF
Sym* osym; // import Sym* osym; // import
Sym* psym; // import Sym* psym; // import
Sym* sym; // various Sym* sym; // various
...@@ -414,6 +420,7 @@ enum ...@@ -414,6 +420,7 @@ enum
PAUTO, PAUTO,
PPARAM, PPARAM,
PPARAMOUT, PPARAMOUT,
PPARAMREF, // param passed by reference
PFUNC, PFUNC,
PHEAP = 1<<7, PHEAP = 1<<7,
...@@ -527,6 +534,10 @@ EXTERN int32 thunk; ...@@ -527,6 +534,10 @@ EXTERN int32 thunk;
EXTERN int exporting; EXTERN int exporting;
EXTERN int funcdepth;
EXTERN Node* funclit;
/* /*
* y.tab.c * y.tab.c
*/ */
...@@ -750,6 +761,9 @@ Node* embedded(Sym*); ...@@ -750,6 +761,9 @@ Node* embedded(Sym*);
Node* variter(Node*, Type*, Node*); Node* variter(Node*, Type*, Node*);
void constiter(Node*, Type*, Node*); void constiter(Node*, Type*, Node*);
void funclit0(Type*);
Node* funclit1(Type*, Node*);
/* /*
* export.c * export.c
*/ */
......
...@@ -1245,33 +1245,15 @@ Bfntype: ...@@ -1245,33 +1245,15 @@ Bfntype:
fnlitdcl: fnlitdcl:
fntype fntype
{ {
markdclstack(); // save dcl stack and revert to block0 markdcl();
$$ = $1; $$ = $1;
funcargs($$); funclit0($$);
} }
fnliteral: fnliteral:
fnlitdcl '{' ostmt_list '}' fnlitdcl '{' ostmt_list '}'
{ {
popdcl(); $$ = funclit1($1, $3);
vargen++;
snprint(namebuf, sizeof(namebuf), "_f%.3ld", vargen);
$$ = newname(lookup(namebuf));
addvar($$, $1, PFUNC);
{
Node *n;
n = nod(ODCLFUNC, N, N);
n->nname = $$;
n->type = $1;
n->nbody = $3;
if(n->nbody == N)
n->nbody = nod(ORETURN, N, N);
compile(n);
}
} }
fnbody: fnbody:
......
...@@ -880,6 +880,11 @@ Jconv(Fmt *fp) ...@@ -880,6 +880,11 @@ Jconv(Fmt *fp)
strncat(buf, buf1, sizeof(buf)); strncat(buf, buf1, sizeof(buf));
} }
if(n->xoffset != 0) {
snprint(buf1, sizeof(buf1), " x(%lld)", n->xoffset);
strncat(buf, buf1, sizeof(buf));
}
if(n->class != 0) { if(n->class != 0) {
snprint(buf1, sizeof(buf1), " class(%d)", n->class); snprint(buf1, sizeof(buf1), " class(%d)", n->class);
strncat(buf, buf1, sizeof(buf)); strncat(buf, buf1, sizeof(buf));
...@@ -890,6 +895,12 @@ Jconv(Fmt *fp) ...@@ -890,6 +895,12 @@ Jconv(Fmt *fp)
strncat(buf, buf1, sizeof(buf)); strncat(buf, buf1, sizeof(buf));
} }
if(n->funcdepth != 0) {
snprint(buf1, sizeof(buf1), " f(%d)", n->funcdepth);
strncat(buf, buf1, sizeof(buf));
}
return fmtstrcpy(fp, buf); return fmtstrcpy(fp, buf);
} }
...@@ -2070,6 +2081,8 @@ ullmancalc(Node *n) ...@@ -2070,6 +2081,8 @@ ullmancalc(Node *n)
case OLITERAL: case OLITERAL:
case ONAME: case ONAME:
ul = 1; ul = 1;
if(n->class == PPARAMREF || (n->class & PHEAP))
ul++;
goto out; goto out;
case OCALL: case OCALL:
case OCALLMETH: case OCALLMETH:
......
...@@ -67,6 +67,8 @@ func arraysliced(old []any, lb int, hb int, width int) (ary []any); ...@@ -67,6 +67,8 @@ func arraysliced(old []any, lb int, hb int, width int) (ary []any);
func arrayslices(old *any, nel int, lb int, hb int, width int) (ary []any); func arrayslices(old *any, nel int, lb int, hb int, width int) (ary []any);
func arrays2d(old *any, nel int) (ary []any); func arrays2d(old *any, nel int) (ary []any);
func closure(); // has args, but compiler fills in
// used by go programs // used by go programs
func Breakpoint(); func Breakpoint();
......
...@@ -50,6 +50,7 @@ char *sysimport = ...@@ -50,6 +50,7 @@ char *sysimport =
"func sys.arraysliced (old []any, lb int, hb int, width int) (ary []any)\n" "func sys.arraysliced (old []any, lb int, hb int, width int) (ary []any)\n"
"func sys.arrayslices (old *any, nel int, lb int, hb int, width int) (ary []any)\n" "func sys.arrayslices (old *any, nel int, lb int, hb int, width int) (ary []any)\n"
"func sys.arrays2d (old *any, nel int) (ary []any)\n" "func sys.arrays2d (old *any, nel int) (ary []any)\n"
"func sys.closure ()\n"
"func sys.Breakpoint ()\n" "func sys.Breakpoint ()\n"
"func sys.Reflect (i interface { }) (? uint64, ? string, ? bool)\n" "func sys.Reflect (i interface { }) (? uint64, ? string, ? bool)\n"
"func sys.Unreflect (? uint64, ? string, ? bool) (ret interface { })\n" "func sys.Unreflect (? uint64, ? string, ? bool) (ret interface { })\n"
......
...@@ -294,7 +294,7 @@ loop: ...@@ -294,7 +294,7 @@ loop:
case ONAME: case ONAME:
if(top == Etop) if(top == Etop)
goto nottop; goto nottop;
if(!(n->class & PHEAP)) if(!(n->class & PHEAP) && n->class != PPARAMREF)
n->addable = 1; n->addable = 1;
if(n->type == T) { if(n->type == T) {
s = n->sym; s = n->sym;
...@@ -2022,7 +2022,10 @@ loop: ...@@ -2022,7 +2022,10 @@ loop:
argtype(on, l->type); // any-1 argtype(on, l->type); // any-1
break; break;
} }
if(isptr[l->type->etype] || l->type->etype == TCHAN || l->type->etype == TMAP) { if(isptr[l->type->etype]
|| l->type->etype == TCHAN
|| l->type->etype == TMAP
|| l->type->etype == TFUNC) {
on = syslook("printpointer", 1); on = syslook("printpointer", 1);
argtype(on, l->type); // any-1 argtype(on, l->type); // any-1
break; break;
...@@ -3668,22 +3671,22 @@ addrescapes(Node *n) ...@@ -3668,22 +3671,22 @@ addrescapes(Node *n)
case PPARAM: case PPARAM:
if(debug['E']) if(debug['E'])
print("%L %s %S escapes %p\n", n->lineno, pnames[n->class], n->sym, n); print("%L %s %S escapes %p\n", n->lineno, pnames[n->class], n->sym, n);
n->class |= PHEAP;
n->addable = 0;
n->ullman = 2;
n->alloc = callnew(n->type);
// if func param, need separate temporary // if func param, need separate temporary
// to hold heap pointer. // to hold heap pointer.
if(n->class == PPARAM+PHEAP) { if(n->class == PPARAM) {
// expression to refer to stack copy // expression to refer to stack copy
n->stackparam = nod(OPARAM, n, N); n->stackparam = nod(OPARAM, n, N);
n->stackparam->type = n->type; n->stackparam->type = n->type;
n->stackparam->addable = 1; n->stackparam->addable = 1;
n->stackparam->xoffset = n->xoffset; n->stackparam->xoffset = n->xoffset;
n->xoffset = 0;
} }
n->class |= PHEAP;
n->addable = 0;
n->ullman = 2;
n->alloc = callnew(n->type);
n->xoffset = 0;
// create stack variable to hold pointer to heap // create stack variable to hold pointer to heap
n->heapaddr = nod(0, N, N); n->heapaddr = nod(0, N, N);
tempname(n->heapaddr, ptrto(n->type)); tempname(n->heapaddr, ptrto(n->type));
...@@ -3721,9 +3724,7 @@ paramstoheap(Type **argin) ...@@ -3721,9 +3724,7 @@ paramstoheap(Type **argin)
nn = N; nn = N;
for(t = structfirst(&savet, argin); t != T; t = structnext(&savet)) { for(t = structfirst(&savet, argin); t != T; t = structnext(&savet)) {
if(t->sym == S) v = t->nname;
continue;
v = t->sym->oname;
if(v == N || !(v->class & PHEAP)) if(v == N || !(v->class & PHEAP))
continue; continue;
......
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