]> Cypherpunks repositories - gostls13.git/commitdiff
closures - 6g support
authorRuss Cox <rsc@golang.org>
Fri, 6 Feb 2009 21:47:10 +0000 (13:47 -0800)
committerRuss Cox <rsc@golang.org>
Fri, 6 Feb 2009 21:47:10 +0000 (13:47 -0800)
R=ken
OCL=24501
CL=24566

src/cmd/6g/cgen.c
src/cmd/gc/dcl.c
src/cmd/gc/go.h
src/cmd/gc/go.y
src/cmd/gc/subr.c
src/cmd/gc/sys.go
src/cmd/gc/sysimport.c
src/cmd/gc/walk.c

index 05dd256ffade408bef9bdfc0cddc5ffb75ecf154..b8bf0cfe75452ad149a56901e837303715329f45 100644 (file)
@@ -205,7 +205,7 @@ cgen(Node *n, Node *res)
        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);
@@ -526,9 +526,18 @@ agen(Node *n, Node *res)
                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);
index c13f78e5a218f8e54d78833e63521fa86baaa3ef..9f7244fc7ca347cf22253990a5d52c3c1f21bb03 100644 (file)
@@ -402,13 +402,12 @@ funchdr(Node *n)
        autodcl = dcl();
        autodcl->back = autodcl;
 
-       if(dclcontext != PEXTERN)
+       if(funcdepth == 0 && dclcontext != PEXTERN)
                fatal("funchdr: dclcontext");
 
        dclcontext = PAUTO;
        markdcl();
        funcargs(n->type);
-
 }
 
 void
@@ -418,6 +417,8 @@ funcargs(Type *ft)
        Iter save;
        int all;
 
+       funcdepth++;
+
        // declare the this/in arguments
        t = funcfirst(&save, ft);
        while(t != T) {
@@ -466,9 +467,176 @@ funcbody(Node *n)
        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
  */
@@ -657,28 +825,6 @@ markdcl(void)
 //             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)
 {
@@ -755,6 +901,7 @@ addvar(Node *n, Type *t, int ctxt)
        s->offset = 0;
        s->lexical = LNAME;
 
+       n->funcdepth = funcdepth;
        n->type = t;
        n->vargen = gen;
        n->class = ctxt;
@@ -909,6 +1056,7 @@ Node*
 oldname(Sym *s)
 {
        Node *n;
+       Node *c;
 
        n = s->oname;
        if(n == N) {
@@ -918,6 +1066,26 @@ oldname(Sym *s)
                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;
 }
 
index 6545d1e18ca39a253c635debd0036caf34844b6c..7b861d38c26a0e1510e369103faab1c5e1207c91 100644 (file)
@@ -187,6 +187,7 @@ struct      Node
        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;
@@ -209,6 +210,7 @@ struct      Node
        Node*   nname;
        Node*   enter;
        Node*   exit;
+       Node*   cvars;  // closure params
 
        // OLITERAL/OREGISTER
        Val     val;
@@ -218,6 +220,10 @@ struct     Node
        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
@@ -414,6 +420,7 @@ enum
        PAUTO,
        PPARAM,
        PPARAMOUT,
+       PPARAMREF,      // param passed by reference
        PFUNC,
 
        PHEAP = 1<<7,
@@ -527,6 +534,10 @@ EXTERN     int32   thunk;
 
 EXTERN int     exporting;
 
+EXTERN int     funcdepth;
+
+EXTERN Node*   funclit;
+
 /*
  *     y.tab.c
  */
@@ -750,6 +761,9 @@ Node*       embedded(Sym*);
 Node*  variter(Node*, Type*, Node*);
 void   constiter(Node*, Type*, Node*);
 
+void   funclit0(Type*);
+Node*  funclit1(Type*, Node*);
+
 /*
  *     export.c
  */
index e323276c8dc7b11dd6613b5521ed919f24c53060..5ed7ed09c9fa97fe37b9c96bfe7b3f2f2528428e 100644 (file)
@@ -1245,33 +1245,15 @@ Bfntype:
 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:
index 2df3fc168f57b3e07886a1868609d1ebb1a2febc..87bd2f20a9c02f1b86f3800dfeadbb1ea9507cb0 100644 (file)
@@ -880,6 +880,11 @@ Jconv(Fmt *fp)
                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));
@@ -890,6 +895,12 @@ Jconv(Fmt *fp)
                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);
 }
 
@@ -2070,6 +2081,8 @@ ullmancalc(Node *n)
        case OLITERAL:
        case ONAME:
                ul = 1;
+               if(n->class == PPARAMREF || (n->class & PHEAP))
+                       ul++;
                goto out;
        case OCALL:
        case OCALLMETH:
index dbe446cb7334445d8e6f90614f7598a53fabcc3c..b121456c38c8843f3306e682ec04d23b35f9ec47 100644 (file)
@@ -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   arrays2d(old *any, nel int) (ary []any);
 
+func   closure();      // has args, but compiler fills in
+
 // used by go programs
 
 func   Breakpoint();
index af4b2df7768836602b7d58f1331302ab2aadc81d..da12b6361ab1f32828c67858078a459df2f3a6bd 100644 (file)
@@ -50,6 +50,7 @@ char *sysimport =
        "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"
index b680cb07440c0088d41029cfa646eb6cbffe6c8e..73313ba20d22b390598f855f9df0b57f94b677ea 100644 (file)
@@ -294,7 +294,7 @@ loop:
        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;
@@ -2022,7 +2022,10 @@ loop:
                        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;
@@ -3668,22 +3671,22 @@ addrescapes(Node *n)
                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));
@@ -3721,9 +3724,7 @@ paramstoheap(Type **argin)
 
        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;