1
0
mirror of https://github.com/golang/go synced 2024-11-24 23:17:57 -07:00

gc: fix closure bug

Fixes #2056.

R=rsc
CC=golang-dev
https://golang.org/cl/4709042
This commit is contained in:
Luuk van Dijk 2011-07-14 18:13:39 +02:00
parent cbad580e9c
commit e8ff9a624f
3 changed files with 61 additions and 38 deletions

View File

@ -116,12 +116,11 @@ typecheckclosure(Node *func, int top)
} }
} }
Node* static Node*
walkclosure(Node *func, NodeList **init) makeclosure(Node *func, NodeList **init, int nowrap)
{ {
int narg; Node *xtype, *v, *addr, *xfunc;
Node *xtype, *v, *addr, *xfunc, *call, *clos; NodeList *l;
NodeList *l, *in;
static int closgen; static int closgen;
char *p; char *p;
@ -133,7 +132,6 @@ walkclosure(Node *func, NodeList **init)
// each closure variable has a corresponding // each closure variable has a corresponding
// address parameter. // address parameter.
narg = 0;
for(l=func->cvars; l; l=l->next) { for(l=func->cvars; l; l=l->next) {
v = l->n; v = l->n;
if(v->op == 0) if(v->op == 0)
@ -146,7 +144,6 @@ walkclosure(Node *func, NodeList **init)
addr->class = PPARAM; addr->class = PPARAM;
addr->addable = 1; addr->addable = 1;
addr->ullman = 1; addr->ullman = 1;
narg++;
v->heapaddr = addr; v->heapaddr = addr;
@ -154,7 +151,8 @@ walkclosure(Node *func, NodeList **init)
} }
// then a dummy arg where the closure's caller pc sits // then a dummy arg where the closure's caller pc sits
xtype->list = list(xtype->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR]))); if (!nowrap)
xtype->list = list(xtype->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
// then the function arguments // then the function arguments
xtype->list = concat(xtype->list, func->list); xtype->list = concat(xtype->list, func->list);
@ -176,15 +174,36 @@ walkclosure(Node *func, NodeList **init)
typecheck(&xfunc, Etop); typecheck(&xfunc, Etop);
closures = list(closures, xfunc); closures = list(closures, xfunc);
return xfunc;
}
Node*
walkclosure(Node *func, NodeList **init)
{
int narg;
Node *xtype, *xfunc, *call, *clos;
NodeList *l, *in;
/*
* wrap body in external function
* with extra closure parameters.
*/
// create the function
xfunc = makeclosure(func, init, 0);
xtype = xfunc->nname->ntype;
// prepare call of sys.closure that turns external func into func literal value. // prepare call of sys.closure that turns external func into func literal value.
clos = syslook("closure", 1); clos = syslook("closure", 1);
clos->type = T; clos->type = T;
clos->ntype = nod(OTFUNC, N, N); clos->ntype = nod(OTFUNC, N, N);
in = list1(nod(ODCLFIELD, N, typenod(types[TINT]))); // siz in = list1(nod(ODCLFIELD, N, typenod(types[TINT]))); // siz
in = list(in, nod(ODCLFIELD, N, xtype)); in = list(in, nod(ODCLFIELD, N, xtype));
narg = 0;
for(l=func->cvars; l; l=l->next) { for(l=func->cvars; l; l=l->next) {
if(l->n->op == 0) if(l->n->op == 0)
continue; continue;
narg++;
in = list(in, nod(ODCLFIELD, N, l->n->heapaddr->ntype)); in = list(in, nod(ODCLFIELD, N, l->n->heapaddr->ntype));
} }
clos->ntype->list = in; clos->ntype->list = in;
@ -211,33 +230,18 @@ walkclosure(Node *func, NodeList **init)
void void
walkcallclosure(Node *n, NodeList **init) walkcallclosure(Node *n, NodeList **init)
{ {
Node *z; if (n->op != OCALLFUNC || n->left->op != OCLOSURE) {
NodeList *ll, *cargs; dump("walkcallclosure", n);
fatal("abuse of walkcallclosure");
}
walkexpr(&n->left, init); // New arg list for n. First the closure-args
cargs = n->left // FUNC runtime.closure // and then the original parameter list.
->list // arguments n->list = concat(n->left->enter, n->list);
->next // skip first n->left = makeclosure(n->left, init, 1)->nname;
->next; // skip second dowidth(n->left->type);
n->type = getoutargx(n->left->type);
n->left = n->left // FUNC runtime.closure // for a single valued function, pull the field type out of the struct
->list // arguments if (n->type && n->type->type && !n->type->type->down)
->next // skip first n->type = n->type->type->type;
->n // AS (to indreg)
->right; // argument == the generated function
// New arg list for n. First the closure-args, stolen from
// runtime.closure's 3rd and following,
ll = nil;
for (; cargs; cargs = cargs->next)
ll = list(ll, cargs->n->right); // cargs->n is the OAS(INDREG, arg)
// then an extra zero, to fill the dummy return pointer slot,
z = nod(OXXX, N, N);
nodconst(z, types[TUINTPTR], 0);
z->typecheck = 1;
ll = list(ll, z);
// and finally the original parameter list.
n->list = concat(ll, n->list);
} }

View File

@ -494,9 +494,9 @@ walkexpr(Node **np, NodeList **init)
if(n->left->op == OCLOSURE) { if(n->left->op == OCLOSURE) {
walkcallclosure(n, init); walkcallclosure(n, init);
t = n->left->type; t = n->left->type;
} else }
walkexpr(&n->left, init);
walkexpr(&n->left, init);
walkexprlist(n->list, init); walkexprlist(n->list, init);
ll = ascompatte(n->op, n->isddd, getinarg(t), n->list, 0, init); ll = ascompatte(n->op, n->isddd, getinarg(t), n->list, 0, init);

19
test/fixedbugs/bug346.go Normal file
View File

@ -0,0 +1,19 @@
// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: issue2056
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import "os"
func main() {
x := 4
a, b, c, d := func(i int) (p int, q int, r int, s int) { return 1, i, 3, x }(2)
if a != 1 || b != 2 || c != 3 || d != 4 {
println("abcd: expected 1 2 3 4 got", a, b, c, d)
os.Exit(1)
}
}