case ODOTPTR:
case OINDEX:
case OIND:
- case ONAME: // PHEAP var
+ case ONAME: // PHEAP or PPARAMREF var
igen(n, &n1, res);
gmove(&n1, res);
regfree(&n1);
break;
case ONAME:
- // should only get here for heap vars
- if(!(n->class & PHEAP))
+ // should only get here with names in this func.
+ 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);
+ }
cgen(n->heapaddr, res);
if(n->xoffset != 0) {
nodconst(&n1, types[TINT64], n->xoffset);
autodcl = dcl();
autodcl->back = autodcl;
- if(dclcontext != PEXTERN)
+ if(funcdepth == 0 && dclcontext != PEXTERN)
fatal("funchdr: dclcontext");
dclcontext = PAUTO;
markdcl();
funcargs(n->type);
-
}
void
Iter save;
int all;
+ funcdepth++;
+
// declare the this/in arguments
t = funcfirst(&save, ft);
while(t != T) {
if(dclcontext != PAUTO)
fatal("funcbody: dclcontext");
popdcl();
- dclcontext = PEXTERN;
+ funcdepth--;
+ if(funcdepth == 0)
+ 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
*/
// 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
dumpdcl(char *st)
{
s->offset = 0;
s->lexical = LNAME;
+ n->funcdepth = funcdepth;
n->type = t;
n->vargen = gen;
n->class = ctxt;
oldname(Sym *s)
{
Node *n;
+ Node *c;
n = s->oname;
if(n == N) {
n->addable = 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;
}
uchar colas; // OAS resulting from :=
uchar diag; // already printed error about this
uchar noescape; // ONAME never move to heap
+ uchar funcdepth;
// most nodes
Node* left;
Node* nname;
Node* enter;
Node* exit;
+ Node* cvars; // closure params
// OLITERAL/OREGISTER
Val val;
Node* stackparam; // OPARAM node referring to stack copy of param
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* psym; // import
Sym* sym; // various
PAUTO,
PPARAM,
PPARAMOUT,
+ PPARAMREF, // param passed by reference
PFUNC,
PHEAP = 1<<7,
EXTERN int exporting;
+EXTERN int funcdepth;
+
+EXTERN Node* funclit;
+
/*
* y.tab.c
*/
Node* variter(Node*, Type*, Node*);
void constiter(Node*, Type*, Node*);
+void funclit0(Type*);
+Node* funclit1(Type*, Node*);
+
/*
* export.c
*/
fnlitdcl:
fntype
{
- markdclstack(); // save dcl stack and revert to block0
+ markdcl();
$$ = $1;
- funcargs($$);
+ funclit0($$);
}
fnliteral:
fnlitdcl '{' ostmt_list '}'
{
- popdcl();
-
- 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);
- }
+ $$ = funclit1($1, $3);
}
fnbody:
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) {
snprint(buf1, sizeof(buf1), " class(%d)", n->class);
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);
}
case OLITERAL:
case ONAME:
ul = 1;
+ if(n->class == PPARAMREF || (n->class & PHEAP))
+ ul++;
goto out;
case OCALL:
case OCALLMETH:
func arrayslices(old *any, nel int, lb int, hb int, width int) (ary []any);
func arrays2d(old *any, nel int) (ary []any);
+func closure(); // has args, but compiler fills in
+
// used by go programs
func Breakpoint();
"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.arrays2d (old *any, nel int) (ary []any)\n"
+ "func sys.closure ()\n"
"func sys.Breakpoint ()\n"
"func sys.Reflect (i interface { }) (? uint64, ? string, ? bool)\n"
"func sys.Unreflect (? uint64, ? string, ? bool) (ret interface { })\n"
case ONAME:
if(top == Etop)
goto nottop;
- if(!(n->class & PHEAP))
+ if(!(n->class & PHEAP) && n->class != PPARAMREF)
n->addable = 1;
if(n->type == T) {
s = n->sym;
argtype(on, l->type); // any-1
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);
argtype(on, l->type); // any-1
break;
case PPARAM:
if(debug['E'])
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
// to hold heap pointer.
- if(n->class == PPARAM+PHEAP) {
+ if(n->class == PPARAM) {
// expression to refer to stack copy
n->stackparam = nod(OPARAM, n, N);
n->stackparam->type = n->type;
n->stackparam->addable = 1;
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
n->heapaddr = nod(0, N, N);
tempname(n->heapaddr, ptrto(n->type));
nn = N;
for(t = structfirst(&savet, argin); t != T; t = structnext(&savet)) {
- if(t->sym == S)
- continue;
- v = t->sym->oname;
+ v = t->nname;
if(v == N || !(v->class & PHEAP))
continue;