diff options
author | Russ Cox <rsc@golang.org> | 2010-03-26 18:01:02 -0700 |
---|---|---|
committer | Russ Cox <rsc@golang.org> | 2010-03-26 18:01:02 -0700 |
commit | 564d135cebd96ee57a1351b53cc8bcc0aaba12b6 (patch) | |
tree | e5a03e10cafa59f726579395f85e30de69e0d1e1 /src | |
parent | 72bf519063879c7aa02cffc4045383d2671caf7f (diff) | |
download | golang-564d135cebd96ee57a1351b53cc8bcc0aaba12b6.tar.gz |
gc: allow taking address of out parameters
Fixes issue 186.
R=ken2
CC=golang-dev
http://codereview.appspot.com/793041
Diffstat (limited to 'src')
-rw-r--r-- | src/cmd/5g/ggen.c | 20 | ||||
-rw-r--r-- | src/cmd/6g/ggen.c | 27 | ||||
-rw-r--r-- | src/cmd/8g/ggen.c | 27 | ||||
-rw-r--r-- | src/cmd/gc/typecheck.c | 6 | ||||
-rw-r--r-- | src/cmd/gc/walk.c | 26 |
5 files changed, 95 insertions, 11 deletions
diff --git a/src/cmd/5g/ggen.c b/src/cmd/5g/ggen.c index e2313d85b..c60c05863 100644 --- a/src/cmd/5g/ggen.c +++ b/src/cmd/5g/ggen.c @@ -7,6 +7,8 @@ #include "gg.h" #include "opt.h" +static Prog *pret; + void compile(Node *fn) { @@ -65,6 +67,16 @@ compile(Node *fn) afunclit(&ptxt->from); genlist(curfn->enter); + + pret = nil; + if(hasdefer || curfn->exit) { + Prog *p1; + + p1 = gjmp(nil); + pret = gjmp(nil); + patch(p1, pc); + } + genlist(curfn->nbody); checklabels(); if(nerrors != 0) @@ -73,6 +85,14 @@ compile(Node *fn) if(curfn->type->outtuple != 0) ginscall(throwreturn, 0); + if(pret) + patch(pret, pc); + ginit(); + if(curfn->exit) + genlist(curfn->exit); + gclean(); + if(nerrors != 0) + goto ret; if(hasdefer) ginscall(deferreturn, 0); pc->as = ARET; // overwrite AEND diff --git a/src/cmd/6g/ggen.c b/src/cmd/6g/ggen.c index 99a4aea04..140020fda 100644 --- a/src/cmd/6g/ggen.c +++ b/src/cmd/6g/ggen.c @@ -7,6 +7,8 @@ #include "gg.h" #include "opt.h" +static Prog *pret; + void compile(Node *fn) { @@ -66,6 +68,16 @@ compile(Node *fn) ginit(); genlist(curfn->enter); + + pret = nil; + if(hasdefer || curfn->exit) { + Prog *p1; + + p1 = gjmp(nil); + pret = gjmp(nil); + patch(p1, pc); + } + genlist(curfn->nbody); gclean(); checklabels(); @@ -75,6 +87,14 @@ compile(Node *fn) if(curfn->type->outtuple != 0) ginscall(throwreturn, 0); + if(pret) + patch(pret, pc); + ginit(); + if(curfn->exit) + genlist(curfn->exit); + gclean(); + if(nerrors != 0) + goto ret; if(hasdefer) ginscall(deferreturn, 0); pc->as = ARET; // overwrite AEND @@ -325,9 +345,10 @@ void cgen_ret(Node *n) { genlist(n->list); // copy out args - if(hasdefer) - ginscall(deferreturn, 0); - gins(ARET, N, N); + if(hasdefer || curfn->exit) + gjmp(pret); + else + gins(ARET, N, N); } /* diff --git a/src/cmd/8g/ggen.c b/src/cmd/8g/ggen.c index 23177c240..468f67ae9 100644 --- a/src/cmd/8g/ggen.c +++ b/src/cmd/8g/ggen.c @@ -7,6 +7,8 @@ #include "gg.h" #include "opt.h" +static Prog *pret; + void compile(Node *fn) { @@ -66,6 +68,16 @@ compile(Node *fn) ginit(); genlist(curfn->enter); + + pret = nil; + if(hasdefer || curfn->exit) { + Prog *p1; + + p1 = gjmp(nil); + pret = gjmp(nil); + patch(p1, pc); + } + genlist(curfn->nbody); gclean(); checklabels(); @@ -75,6 +87,14 @@ compile(Node *fn) if(curfn->type->outtuple != 0) ginscall(throwreturn, 0); + if(pret) + patch(pret, pc); + ginit(); + if(curfn->exit) + genlist(curfn->exit); + gclean(); + if(nerrors != 0) + goto ret; if(hasdefer) ginscall(deferreturn, 0); pc->as = ARET; // overwrite AEND @@ -362,9 +382,10 @@ void cgen_ret(Node *n) { genlist(n->list); // copy out args - if(hasdefer) - ginscall(deferreturn, 0); - gins(ARET, N, N); + if(pret) + gjmp(pret); + else + gins(ARET, N, N); } /* diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c index d10bf8f74..c219ad8c5 100644 --- a/src/cmd/gc/typecheck.c +++ b/src/cmd/gc/typecheck.c @@ -1988,17 +1988,15 @@ addrescapes(Node *n) if(n->noescape) break; switch(n->class) { - case PPARAMOUT: - yyerror("cannot take address of out parameter %s", n->sym->name); - break; case PAUTO: case PPARAM: + case PPARAMOUT: // if func param, need separate temporary // to hold heap pointer. // the function type has already been checked // (we're in the function body) // so the param already has a valid xoffset. - if(n->class == PPARAM) { + if(n->class == PPARAM || n->class == PPARAMOUT) { // expression to refer to stack copy n->stackparam = nod(OPARAM, n, N); n->stackparam->type = n->type; diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c index 9c904f14c..fa6157bb0 100644 --- a/src/cmd/gc/walk.c +++ b/src/cmd/gc/walk.c @@ -2288,7 +2288,29 @@ paramstoheap(Type **argin) if(v->alloc == nil) v->alloc = callnew(v->type); nn = list(nn, nod(OAS, v->heapaddr, v->alloc)); - nn = list(nn, nod(OAS, v, v->stackparam)); + if((v->class & ~PHEAP) != PPARAMOUT) + nn = list(nn, nod(OAS, v, v->stackparam)); + } + return nn; +} + +/* + * walk through argout parameters copying back to stack + */ +NodeList* +returnsfromheap(Type **argin) +{ + Type *t; + Iter savet; + Node *v; + NodeList *nn; + + nn = nil; + for(t = structfirst(&savet, argin); t != T; t = structnext(&savet)) { + v = t->nname; + if(v == N || v->class != (PHEAP|PPARAMOUT)) + continue; + nn = list(nn, nod(OAS, v->stackparam, v)); } return nn; } @@ -2305,7 +2327,9 @@ heapmoves(void) nn = paramstoheap(getthis(curfn->type)); nn = concat(nn, paramstoheap(getinarg(curfn->type))); + nn = concat(nn, paramstoheap(getoutarg(curfn->type))); curfn->enter = concat(curfn->enter, nn); + curfn->exit = returnsfromheap(getoutarg(curfn->type)); } static Node* |