mirror of
https://github.com/golang/go
synced 2024-10-02 22:25:08 +00:00
if take address of local, move to heap.
heuristic to not print bogus strings. fix one error message format. R=ken OCL=23849 CL=23851
This commit is contained in:
parent
699721a0ea
commit
391425ae55
|
@ -48,6 +48,11 @@ cgen(Node *n, Node *res)
|
|||
if(n->ullman > res->ullman) {
|
||||
regalloc(&n1, n->type, res);
|
||||
cgen(n, &n1);
|
||||
if(n1.ullman > res->ullman) {
|
||||
dump("n1", &n1);
|
||||
dump("res", res);
|
||||
fatal("loop in cgen");
|
||||
}
|
||||
cgen(&n1, res);
|
||||
regfree(&n1);
|
||||
goto ret;
|
||||
|
@ -198,6 +203,7 @@ cgen(Node *n, Node *res)
|
|||
case ODOTPTR:
|
||||
case OINDEX:
|
||||
case OIND:
|
||||
case ONAME: // PHEAP var
|
||||
igen(n, &n1, res);
|
||||
gmove(&n1, res);
|
||||
regfree(&n1);
|
||||
|
@ -517,6 +523,17 @@ agen(Node *n, Node *res)
|
|||
regfree(&n3);
|
||||
break;
|
||||
|
||||
case ONAME:
|
||||
// should only get here for heap vars
|
||||
if(!(n->class & PHEAP))
|
||||
fatal("agen: bad ONAME class %#x", n->class);
|
||||
cgen(n->heapaddr, res);
|
||||
if(n->xoffset != 0) {
|
||||
nodconst(&n1, types[TINT64], n->xoffset);
|
||||
gins(optoas(OADD, types[tptr]), &n1, res);
|
||||
}
|
||||
break;
|
||||
|
||||
case OIND:
|
||||
cgen(nl, res);
|
||||
break;
|
||||
|
|
|
@ -99,6 +99,7 @@ if(throwreturn == N) {
|
|||
// inarggen();
|
||||
|
||||
ginit();
|
||||
gen(curfn->enter, L);
|
||||
gen(curfn->nbody, L);
|
||||
gclean();
|
||||
checklabels();
|
||||
|
@ -151,6 +152,8 @@ allocparams(void)
|
|||
|
||||
dowidth(n->type);
|
||||
w = n->type->width;
|
||||
if(n->class & PHEAP)
|
||||
w = widthptr;
|
||||
stksize += w;
|
||||
stksize = rnd(stksize, w);
|
||||
|
||||
|
@ -345,6 +348,10 @@ loop:
|
|||
cgen_asop(n);
|
||||
break;
|
||||
|
||||
case ODCL:
|
||||
cgen_dcl(n->left);
|
||||
break;
|
||||
|
||||
case OAS:
|
||||
cgen_as(n->left, n->right);
|
||||
break;
|
||||
|
@ -1114,6 +1121,26 @@ ret:
|
|||
;
|
||||
}
|
||||
|
||||
/*
|
||||
* generate declaration.
|
||||
* nothing to do for on-stack automatics,
|
||||
* but might have to allocate heap copy
|
||||
* for escaped variables.
|
||||
*/
|
||||
void
|
||||
cgen_dcl(Node *n)
|
||||
{
|
||||
if(debug['g'])
|
||||
dump("\ncgen-dcl", n);
|
||||
if(n->op != ONAME) {
|
||||
dump("cgen_dcl", n);
|
||||
fatal("cgen_dcl");
|
||||
}
|
||||
if(!(n->class & PHEAP))
|
||||
return;
|
||||
cgen_as(n->heapaddr, n->alloc);
|
||||
}
|
||||
|
||||
/*
|
||||
* generate assignment:
|
||||
* nl = nr
|
||||
|
@ -1130,6 +1157,11 @@ cgen_as(Node *nl, Node *nr)
|
|||
if(nl == N)
|
||||
return;
|
||||
|
||||
if(debug['g']) {
|
||||
dump("cgen_as", nl);
|
||||
dump("cgen_as = ", nr);
|
||||
}
|
||||
|
||||
iszer = 0;
|
||||
if(nr == N || isnil(nr)) {
|
||||
if(nl->op == OLIST) {
|
||||
|
|
|
@ -158,6 +158,7 @@ void cgen_callret(Node*, Node*);
|
|||
void cgen_div(int, Node*, Node*, Node*);
|
||||
void cgen_bmul(int, Node*, Node*, Node*);
|
||||
void cgen_shift(int, Node*, Node*, Node*);
|
||||
void cgen_dcl(Node*);
|
||||
void genpanic(void);
|
||||
int needconvert(Type*, Type*);
|
||||
void genconv(Type*, Type*);
|
||||
|
|
|
@ -547,6 +547,7 @@ gmove(Node *f, Node *t)
|
|||
break;
|
||||
case PAUTO:
|
||||
case PPARAM:
|
||||
case PPARAMOUT:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -1046,6 +1047,15 @@ naddr(Node *n, Addr *a)
|
|||
a->offset = n->xoffset;
|
||||
break;
|
||||
|
||||
case OPARAM:
|
||||
// n->left is PHEAP ONAME for stack parameter.
|
||||
// compute address of actual parameter on stack.
|
||||
a->etype = n->left->type->etype;
|
||||
a->offset = n->xoffset;
|
||||
a->sym = n->left->sym;
|
||||
a->type = D_PARAM;
|
||||
break;
|
||||
|
||||
case ONAME:
|
||||
a->etype = 0;
|
||||
if(n->type != T)
|
||||
|
@ -1071,6 +1081,7 @@ naddr(Node *n, Addr *a)
|
|||
a->type = D_AUTO;
|
||||
break;
|
||||
case PPARAM:
|
||||
case PPARAMOUT:
|
||||
a->type = D_PARAM;
|
||||
break;
|
||||
}
|
||||
|
@ -1749,6 +1760,7 @@ tempname(Node *n, Type *t)
|
|||
n->class = PAUTO;
|
||||
n->addable = 1;
|
||||
n->ullman = 1;
|
||||
n->noescape = 1;
|
||||
|
||||
dowidth(t);
|
||||
w = t->width;
|
||||
|
|
|
@ -36,6 +36,7 @@ dodclvar(Node *n, Type *t)
|
|||
|
||||
addvar(n, t, dclcontext);
|
||||
autoexport(n->sym);
|
||||
addtop = list(addtop, nod(ODCL, n, N));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -434,7 +435,7 @@ funcargs(Type *ft)
|
|||
if(t->nname != N)
|
||||
t->nname->xoffset = t->width;
|
||||
if(t->nname != N) {
|
||||
addvar(t->nname, t->type, PPARAM);
|
||||
addvar(t->nname, t->type, PPARAMOUT);
|
||||
all |= 1;
|
||||
} else
|
||||
all |= 2;
|
||||
|
|
|
@ -180,12 +180,13 @@ struct Node
|
|||
uchar addable; // type of addressability - 0 is not addressable
|
||||
uchar trecur; // to detect loops
|
||||
uchar etype; // op for OASOP, etype for OTYPE, exclam for export
|
||||
uchar class; // PPARAM, PAUTO, PEXTERN
|
||||
uchar class; // PPARAM, PAUTO, PEXTERN, etc
|
||||
uchar method; // OCALLMETH name
|
||||
uchar iota; // OLITERAL made from iota
|
||||
uchar embedded; // ODCLFIELD embedded type
|
||||
uchar colas; // OAS resulting from :=
|
||||
uchar diag; // already printed error about this
|
||||
uchar noescape; // ONAME never move to heap
|
||||
|
||||
// most nodes
|
||||
Node* left;
|
||||
|
@ -206,10 +207,17 @@ struct Node
|
|||
|
||||
// func
|
||||
Node* nname;
|
||||
Node* enter;
|
||||
Node* exit;
|
||||
|
||||
// OLITERAL/OREGISTER
|
||||
Val val;
|
||||
|
||||
// ONAME func param with PHEAP
|
||||
Node* heapaddr; // temp holding heap address of param
|
||||
Node* stackparam; // OPARAM node referring to stack copy of param
|
||||
Node* alloc; // allocation call
|
||||
|
||||
Sym* osym; // import
|
||||
Sym* psym; // import
|
||||
Sym* sym; // various
|
||||
|
@ -287,7 +295,7 @@ enum
|
|||
|
||||
OTYPE, OCONST, OVAR, OIMPORT,
|
||||
|
||||
ONAME, ONONAME,
|
||||
ONAME, ONONAME, ODCL,
|
||||
ODOT, ODOTPTR, ODOTMETH, ODOTINTER,
|
||||
ODCLFUNC, ODCLFIELD, ODCLARG,
|
||||
OLIST, OCMP, OPTR, OARRAY, ORANGE,
|
||||
|
@ -312,7 +320,7 @@ enum
|
|||
OINDEX, OSLICE,
|
||||
ONOT, OCOM, OPLUS, OMINUS, OSEND, ORECV,
|
||||
OLITERAL, OREGISTER, OINDREG,
|
||||
OCONV, OCOMP, OKEY,
|
||||
OCONV, OCOMP, OKEY, OPARAM,
|
||||
OBAD,
|
||||
|
||||
OEXTEND, // 6g internal
|
||||
|
@ -405,6 +413,9 @@ enum
|
|||
PEXTERN, // declaration context
|
||||
PAUTO,
|
||||
PPARAM,
|
||||
PPARAMOUT,
|
||||
|
||||
PHEAP = 1<<7,
|
||||
};
|
||||
|
||||
enum
|
||||
|
@ -654,6 +665,7 @@ Node* treecopy(Node*);
|
|||
int isselect(Node*);
|
||||
void tempname(Node*, Type*);
|
||||
int iscomposite(Type*);
|
||||
Node* callnew(Type*);
|
||||
|
||||
Type** getthis(Type*);
|
||||
Type** getoutarg(Type*);
|
||||
|
@ -812,11 +824,13 @@ Node* reorder1(Node*);
|
|||
Node* reorder2(Node*);
|
||||
Node* reorder3(Node*);
|
||||
Node* reorder4(Node*);
|
||||
Node* structlit(Node*);
|
||||
Node* structlit(Node*, Node*);
|
||||
Node* arraylit(Node*);
|
||||
Node* maplit(Node*);
|
||||
Node* selectas(Node*, Node*);
|
||||
Node* old2new(Node*, Type*);
|
||||
void addrescapes(Node*);
|
||||
void heapmoves(void);
|
||||
|
||||
/*
|
||||
* const.c
|
||||
|
|
|
@ -278,6 +278,7 @@ Avardcl:
|
|||
dodclvar($$, $2);
|
||||
|
||||
$$ = nod(OAS, $$, N);
|
||||
addtotop($$);
|
||||
}
|
||||
|
||||
Bvardcl:
|
||||
|
@ -287,6 +288,7 @@ Bvardcl:
|
|||
dodclvar($$, $2);
|
||||
|
||||
$$ = nod(OAS, $$, N);
|
||||
addtotop($$);
|
||||
}
|
||||
| new_name_list_r type '=' expr_list
|
||||
{
|
||||
|
@ -478,6 +480,7 @@ complex_stmt:
|
|||
poptodcl();
|
||||
$$ = nod(OAS, selectas($2,$4), $4);
|
||||
$$ = nod(OXCASE, $$, N);
|
||||
addtotop($$);
|
||||
}
|
||||
| LDEFAULT ':'
|
||||
{
|
||||
|
|
|
@ -702,6 +702,8 @@ opnames[] =
|
|||
[OPANICN] = "PANICN",
|
||||
[OPRINT] = "PRINT",
|
||||
[OPRINTN] = "PRINTN",
|
||||
[OPARAM] = "PARAM",
|
||||
[ODCL] = "DCL",
|
||||
[OXXX] = "XXX",
|
||||
};
|
||||
|
||||
|
@ -877,6 +879,16 @@ Jconv(Fmt *fp)
|
|||
strncat(buf, buf1, sizeof(buf));
|
||||
}
|
||||
|
||||
if(n->class != 0) {
|
||||
snprint(buf1, sizeof(buf1), " class(%d)", n->class);
|
||||
strncat(buf, buf1, sizeof(buf));
|
||||
}
|
||||
|
||||
if(n->colas != 0) {
|
||||
snprint(buf1, sizeof(buf1), " colas(%d)", n->colas);
|
||||
strncat(buf, buf1, sizeof(buf));
|
||||
}
|
||||
|
||||
return fmtstrcpy(fp, buf);
|
||||
}
|
||||
|
||||
|
@ -2031,6 +2043,7 @@ ullmancalc(Node *n)
|
|||
return;
|
||||
|
||||
switch(n->op) {
|
||||
case OREGISTER:
|
||||
case OLITERAL:
|
||||
case ONAME:
|
||||
ul = 1;
|
||||
|
@ -2281,7 +2294,7 @@ Type**
|
|||
getthis(Type *t)
|
||||
{
|
||||
if(t->etype != TFUNC)
|
||||
fatal("getthis: not a func %N", t);
|
||||
fatal("getthis: not a func %T", t);
|
||||
return &t->type;
|
||||
}
|
||||
|
||||
|
@ -2289,7 +2302,7 @@ Type**
|
|||
getoutarg(Type *t)
|
||||
{
|
||||
if(t->etype != TFUNC)
|
||||
fatal("getoutarg: not a func %N", t);
|
||||
fatal("getoutarg: not a func %T", t);
|
||||
return &t->type->down;
|
||||
}
|
||||
|
||||
|
@ -2297,7 +2310,7 @@ Type**
|
|||
getinarg(Type *t)
|
||||
{
|
||||
if(t->etype != TFUNC)
|
||||
fatal("getinarg: not a func %N", t);
|
||||
fatal("getinarg: not a func %T", t);
|
||||
return &t->type->down->down;
|
||||
}
|
||||
|
||||
|
|
|
@ -65,13 +65,20 @@ walk(Node *fn)
|
|||
if(curfn->type->outtuple)
|
||||
if(walkret(curfn->nbody))
|
||||
yyerror("function ends without a return statement");
|
||||
if(addtop != N)
|
||||
if(addtop != N) {
|
||||
dump("addtop", addtop);
|
||||
fatal("addtop in walk");
|
||||
}
|
||||
walkstate(curfn->nbody);
|
||||
if(debug['W']) {
|
||||
snprint(s, sizeof(s), "after %S", curfn->nname->sym);
|
||||
snprint(s, sizeof(s), "after walk %S", curfn->nname->sym);
|
||||
dump(s, curfn->nbody);
|
||||
}
|
||||
heapmoves();
|
||||
if(debug['W'] && curfn->enter != N) {
|
||||
snprint(s, sizeof(s), "enter %S", curfn->nname->sym);
|
||||
dump(s, curfn->enter);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -125,6 +132,7 @@ loop:
|
|||
case OCALLMETH:
|
||||
case OCALLINTER:
|
||||
case OCALL:
|
||||
case ODCL:
|
||||
case OSEND:
|
||||
case ORECV:
|
||||
case OPRINT:
|
||||
|
@ -229,6 +237,9 @@ loop:
|
|||
fatal("walktype: switch 1 unknown op %N", n);
|
||||
goto ret;
|
||||
|
||||
case ODCL:
|
||||
goto ret;
|
||||
|
||||
case OLIST:
|
||||
case OKEY:
|
||||
walktype(n->left, top);
|
||||
|
@ -283,7 +294,8 @@ loop:
|
|||
case ONAME:
|
||||
if(top == Etop)
|
||||
goto nottop;
|
||||
n->addable = 1;
|
||||
if(!(n->class & PHEAP))
|
||||
n->addable = 1;
|
||||
if(n->type == T) {
|
||||
s = n->sym;
|
||||
if(s->undef == 0) {
|
||||
|
@ -681,7 +693,7 @@ loop:
|
|||
|
||||
// structure literal
|
||||
if(t->etype == TSTRUCT) {
|
||||
indir(n, structlit(n));
|
||||
indir(n, structlit(n, nil));
|
||||
goto ret;
|
||||
}
|
||||
|
||||
|
@ -996,32 +1008,20 @@ loop:
|
|||
// nvar := new(*Point);
|
||||
// *nvar = Point{1, 2};
|
||||
// and replace expression with nvar
|
||||
Node *nvar, *nas;
|
||||
|
||||
// TODO(rsc): might do a better job (fewer copies) later
|
||||
Node *nnew, *nvar, *nas;
|
||||
nvar = nod(OXXX, N, N);
|
||||
tempname(nvar, ptrto(n->left->type));
|
||||
|
||||
t = ptrto(n->left->type);
|
||||
walktype(n->left, Elv);
|
||||
if(n->left == N)
|
||||
goto ret;
|
||||
|
||||
nvar = nod(0, N, N);
|
||||
tempname(nvar, t);
|
||||
|
||||
nnew = nod(ONEW, N, N);
|
||||
nnew->type = n->left->type;
|
||||
nnew = newcompat(nnew);
|
||||
|
||||
nas = nod(OAS, nvar, nnew);
|
||||
addtop = list(addtop, nas);
|
||||
|
||||
nas = nod(OAS, nod(OIND, nvar, N), n->left);
|
||||
nas = nod(OAS, nvar, callnew(n->left->type));
|
||||
addtop = list(addtop, nas);
|
||||
|
||||
structlit(n->left, nvar);
|
||||
indir(n, nvar);
|
||||
goto ret;
|
||||
}
|
||||
walktype(n->left, Elv);
|
||||
addrescapes(n->left);
|
||||
if(n->left == N)
|
||||
goto ret;
|
||||
t = n->left->type;
|
||||
|
@ -1055,7 +1055,16 @@ loop:
|
|||
case ONEW:
|
||||
if(top != Erv)
|
||||
goto nottop;
|
||||
indir(n, newcompat(n));
|
||||
if(n->left != N) {
|
||||
yyerror("cannot new(%T, expr)", t);
|
||||
goto ret;
|
||||
}
|
||||
t = n->type;
|
||||
if(t == T || t->etype == TFUNC) {
|
||||
yyerror("cannot new(%T)", t);
|
||||
goto ret;
|
||||
}
|
||||
indir(n, callnew(t));
|
||||
goto ret;
|
||||
}
|
||||
|
||||
|
@ -1455,8 +1464,8 @@ void
|
|||
walkselect(Node *sel)
|
||||
{
|
||||
Iter iter;
|
||||
Node *n, *oc, *on, *r;
|
||||
Node *var, *bod, *res, *def;
|
||||
Node *n, *l, *oc, *on, *r;
|
||||
Node *var, *bod, *nbod, *res, *def;
|
||||
int count, op;
|
||||
int32 lno;
|
||||
|
||||
|
@ -1492,6 +1501,7 @@ walkselect(Node *sel)
|
|||
def = n;
|
||||
} else
|
||||
op = n->left->op;
|
||||
nbod = N;
|
||||
switch(op) {
|
||||
default:
|
||||
yyerror("select cases must be send, recv or default");
|
||||
|
@ -1499,14 +1509,32 @@ walkselect(Node *sel)
|
|||
|
||||
case OAS:
|
||||
// convert new syntax (a=recv(chan)) to (recv(a,chan))
|
||||
if(n->left->right == N || n->left->right->op != ORECV) {
|
||||
l = n->left;
|
||||
if(l->right == N || l->right->op != ORECV) {
|
||||
yyerror("select cases must be send, recv or default");
|
||||
break;
|
||||
}
|
||||
n->left->right->right = n->left->right->left;
|
||||
n->left->right->left = n->left->left;
|
||||
n->left = n->left->right;
|
||||
r = l->right; // rcv
|
||||
r->right = r->left;
|
||||
r->left = l->left;
|
||||
n->left = r;
|
||||
|
||||
// convert case x := foo: body
|
||||
// to case tmp := foo: x := tmp; body.
|
||||
// if x escapes and must be allocated
|
||||
// on the heap, this delays the allocation
|
||||
// until after the select has chosen this branch.
|
||||
if(n->ninit != N && n->ninit->op == ODCL) {
|
||||
on = nod(OXXX, N, N);
|
||||
tempname(on, l->left->type);
|
||||
on->sym = lookup("!tmpselect!");
|
||||
r->left = on;
|
||||
nbod = nod(OAS, l->left, on);
|
||||
nbod->ninit = n->ninit;
|
||||
n->ninit = N;
|
||||
}
|
||||
|
||||
// fall through
|
||||
case OSEND:
|
||||
case ORECV:
|
||||
if(oc != N) {
|
||||
|
@ -1516,10 +1544,8 @@ walkselect(Node *sel)
|
|||
oc = selcase(n, var);
|
||||
res = list(res, oc);
|
||||
break;
|
||||
|
||||
|
||||
}
|
||||
bod = N;
|
||||
bod = nbod;
|
||||
count++;
|
||||
break;
|
||||
}
|
||||
|
@ -1610,6 +1636,7 @@ lookdot(Node *n, Type *t)
|
|||
switch(op) {
|
||||
case OADDR:
|
||||
walktype(n->left, Elv);
|
||||
addrescapes(n->left);
|
||||
n->left = nod(OADDR, n->left, N);
|
||||
n->left->type = ptrto(tt);
|
||||
break;
|
||||
|
@ -1781,7 +1808,7 @@ sigtype(Type *st)
|
|||
* match a ... parameter into an
|
||||
* automatic structure.
|
||||
* then call the ... arg (interface)
|
||||
* with a pointer to the structure
|
||||
* with a pointer to the structure.
|
||||
*/
|
||||
Node*
|
||||
mkdotargs(Node *r, Node *rr, Iter *saver, Node *nn, Type *l, int fp)
|
||||
|
@ -1817,10 +1844,12 @@ mkdotargs(Node *r, Node *rr, Iter *saver, Node *nn, Type *l, int fp)
|
|||
|
||||
// make a named type for the struct
|
||||
st = sigtype(st);
|
||||
dowidth(st);
|
||||
|
||||
// now we have the size, make the struct
|
||||
var = nod(OXXX, N, N);
|
||||
tempname(var, st);
|
||||
var->sym = lookup(".ddd");
|
||||
|
||||
// assign the fields to the struct.
|
||||
// use addtop so that reorder1 doesn't reorder
|
||||
|
@ -1840,8 +1869,7 @@ mkdotargs(Node *r, Node *rr, Iter *saver, Node *nn, Type *l, int fp)
|
|||
}
|
||||
|
||||
// last thing is to put assignment
|
||||
// of a pointer to the structure to
|
||||
// the DDD parameter
|
||||
// of the structure to the DDD parameter
|
||||
a = nod(OAS, nodarg(l, fp), var);
|
||||
nn = list(convas(a), nn);
|
||||
|
||||
|
@ -2081,26 +2109,17 @@ makecompat(Node *n)
|
|||
}
|
||||
|
||||
Node*
|
||||
newcompat(Node *n)
|
||||
callnew(Type *t)
|
||||
{
|
||||
Node *r, *on;
|
||||
Type *t;
|
||||
|
||||
t = n->type;
|
||||
if(t != T && t->etype != TFUNC) {
|
||||
if(n->left != N)
|
||||
yyerror("cannot new(%T, expr)", t);
|
||||
dowidth(t);
|
||||
on = syslook("mal", 1);
|
||||
argtype(on, t);
|
||||
r = nodintconst(t->width);
|
||||
r = nod(OCALL, on, r);
|
||||
walktype(r, Erv);
|
||||
return r;
|
||||
}
|
||||
|
||||
yyerror("cannot new(%T)", t);
|
||||
return n;
|
||||
dowidth(t);
|
||||
on = syslook("mal", 1);
|
||||
argtype(on, t);
|
||||
r = nodintconst(t->width);
|
||||
r = nod(OCALL, on, r);
|
||||
walktype(r, Erv);
|
||||
return r;
|
||||
}
|
||||
|
||||
Node*
|
||||
|
@ -2648,6 +2667,7 @@ arrayop(Node *n, int top)
|
|||
r = a;
|
||||
|
||||
a = nod(OADDR, n->left, N); // old
|
||||
addrescapes(n->left);
|
||||
r = list(a, r);
|
||||
|
||||
on = syslook("arrays2d", 1);
|
||||
|
@ -2671,6 +2691,7 @@ arrayop(Node *n, int top)
|
|||
r = a;
|
||||
|
||||
a = nod(OADDR, n->right, N); // old
|
||||
addrescapes(n->right);
|
||||
r = list(a, r);
|
||||
|
||||
on = syslook("arrays2d", 1);
|
||||
|
@ -3171,6 +3192,7 @@ ary:
|
|||
n->nbody = list(n->nbody,
|
||||
nod(OAS, v, nod(OINDEX, m, hk)) );
|
||||
}
|
||||
addtotop(n);
|
||||
goto out;
|
||||
|
||||
map:
|
||||
|
@ -3457,18 +3479,20 @@ reorder4(Node *n)
|
|||
}
|
||||
|
||||
Node*
|
||||
structlit(Node *n)
|
||||
structlit(Node *n, Node *var)
|
||||
{
|
||||
Iter savel, saver;
|
||||
Type *l, *t;
|
||||
Node *var, *r, *a;
|
||||
Node *r, *a;
|
||||
|
||||
t = n->type;
|
||||
if(t->etype != TSTRUCT)
|
||||
fatal("structlit: not struct");
|
||||
|
||||
var = nod(OXXX, N, N);
|
||||
tempname(var, t);
|
||||
if(var == N) {
|
||||
var = nod(OXXX, N, N);
|
||||
tempname(var, t);
|
||||
}
|
||||
|
||||
l = structfirst(&savel, &n->type);
|
||||
r = listfirst(&saver, &n->left);
|
||||
|
@ -3488,6 +3512,7 @@ loop:
|
|||
|
||||
a = nod(ODOT, var, newname(l->sym));
|
||||
a = nod(OAS, a, r);
|
||||
walktype(a, Etop); // add any assignments in r to addtop
|
||||
addtop = list(addtop, a);
|
||||
|
||||
l = structnext(&savel);
|
||||
|
@ -3605,3 +3630,115 @@ loop:
|
|||
r = listnext(&saver);
|
||||
goto loop;
|
||||
}
|
||||
|
||||
/*
|
||||
* the address of n has been taken and might be used after
|
||||
* the current function returns. mark any local vars
|
||||
* as needing to move to the heap.
|
||||
*/
|
||||
static char *pnames[] = {
|
||||
[PAUTO] "auto",
|
||||
[PPARAM] "param",
|
||||
[PPARAMOUT] "param_out",
|
||||
};
|
||||
|
||||
void
|
||||
addrescapes(Node *n)
|
||||
{
|
||||
char buf[100];
|
||||
switch(n->op) {
|
||||
default:
|
||||
dump("addrescapes", n);
|
||||
break;
|
||||
|
||||
case ONAME:
|
||||
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:
|
||||
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) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
// create stack variable to hold pointer to heap
|
||||
n->heapaddr = nod(0, N, N);
|
||||
tempname(n->heapaddr, ptrto(n->type));
|
||||
snprint(buf, sizeof buf, "&%S", n->sym);
|
||||
n->heapaddr->sym = lookup(buf);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case OIND:
|
||||
case ODOTPTR:
|
||||
break;
|
||||
|
||||
case ODOT:
|
||||
case OINDEX:
|
||||
// ODOTPTR has already been
|
||||
// introduced, so these are the non-pointer
|
||||
// ODOT and OINDEX.
|
||||
addrescapes(n->left);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* walk through argin parameters.
|
||||
* generate and return code to allocate
|
||||
* copies of escaped parameters to the heap.
|
||||
*/
|
||||
Node*
|
||||
paramstoheap(Type **argin)
|
||||
{
|
||||
Type *t;
|
||||
Iter savet;
|
||||
Node *v, *nn;
|
||||
|
||||
nn = N;
|
||||
for(t = structfirst(&savet, argin); t != T; t = structnext(&savet)) {
|
||||
if(t->sym == S)
|
||||
continue;
|
||||
v = t->sym->oname;
|
||||
if(v == N || !(v->class & PHEAP))
|
||||
continue;
|
||||
|
||||
// generate allocation & copying code
|
||||
nn = list(nn, nod(OAS, v->heapaddr, v->alloc));
|
||||
nn = list(nn, nod(OAS, v, v->stackparam));
|
||||
}
|
||||
return nn;
|
||||
}
|
||||
|
||||
/*
|
||||
* take care of migrating any function in/out args
|
||||
* between the stack and the heap. adds code to
|
||||
* curfn's before and after lists.
|
||||
*/
|
||||
void
|
||||
heapmoves(void)
|
||||
{
|
||||
Node *nn;
|
||||
|
||||
nn = paramstoheap(getthis(curfn->type));
|
||||
nn = list(nn, paramstoheap(getinarg(curfn->type)));
|
||||
curfn->enter = list(curfn->enter, nn);
|
||||
}
|
||||
|
|
|
@ -237,8 +237,14 @@ sys·printpointer(void *p)
|
|||
void
|
||||
sys·printstring(string v)
|
||||
{
|
||||
if(v != nil)
|
||||
sys·write(1, v->str, v->len);
|
||||
extern int32 maxstring;
|
||||
|
||||
if(v != nil) {
|
||||
if(v->len > maxstring)
|
||||
sys·write(1, "[invalid string]", 16);
|
||||
else
|
||||
sys·write(1, v->str, v->len);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -17,6 +17,20 @@ findnull(byte *s)
|
|||
return l;
|
||||
}
|
||||
|
||||
int32 maxstring;
|
||||
|
||||
string
|
||||
gostringsize(int32 l)
|
||||
{
|
||||
string s;
|
||||
|
||||
s = mal(sizeof(s->len)+l+1);
|
||||
s->len = l;
|
||||
if(l > maxstring)
|
||||
maxstring = l;
|
||||
return s;
|
||||
}
|
||||
|
||||
string
|
||||
gostring(byte *str)
|
||||
{
|
||||
|
@ -24,8 +38,7 @@ gostring(byte *str)
|
|||
string s;
|
||||
|
||||
l = findnull(str);
|
||||
s = mal(sizeof(s->len)+l+1);
|
||||
s->len = l;
|
||||
s = gostringsize(l);
|
||||
mcpy(s->str, str, l+1);
|
||||
return s;
|
||||
}
|
||||
|
@ -46,8 +59,7 @@ sys·catstring(string s1, string s2, string s3)
|
|||
|
||||
l = s1->len + s2->len;
|
||||
|
||||
s3 = mal(sizeof(s3->len)+l);
|
||||
s3->len = l;
|
||||
s3 = gostringsize(l);
|
||||
mcpy(s3->str, s1->str, s1->len);
|
||||
mcpy(s3->str+s1->len, s2->str, s2->len);
|
||||
|
||||
|
@ -139,8 +151,7 @@ sys·slicestring(string si, int32 lindex, int32 hindex, string so)
|
|||
}
|
||||
|
||||
l = hindex-lindex;
|
||||
so = mal(sizeof(so->len)+l);
|
||||
so->len = l;
|
||||
so = gostringsize(l);
|
||||
mcpy(so->str, si->str+lindex, l);
|
||||
FLUSH(&so);
|
||||
}
|
||||
|
@ -164,7 +175,7 @@ sys·indexstring(string s, int32 i, byte b)
|
|||
void
|
||||
sys·intstring(int64 v, string s)
|
||||
{
|
||||
s = mal(sizeof(s->len)+8);
|
||||
s = gostringsize(8);
|
||||
s->len = runetochar(s->str, v);
|
||||
FLUSH(&s);
|
||||
}
|
||||
|
@ -172,8 +183,7 @@ sys·intstring(int64 v, string s)
|
|||
void
|
||||
sys·byteastring(byte *a, int32 l, string s)
|
||||
{
|
||||
s = mal(sizeof(s->len)+l);
|
||||
s->len = l;
|
||||
s = gostringsize(l);
|
||||
mcpy(s->str, a, l);
|
||||
FLUSH(&s);
|
||||
}
|
||||
|
@ -181,8 +191,7 @@ sys·byteastring(byte *a, int32 l, string s)
|
|||
void
|
||||
sys·arraystring(Array b, string s)
|
||||
{
|
||||
s = mal(sizeof(s->len)+b.nel);
|
||||
s->len = b.nel;
|
||||
s = gostringsize(b.nel);
|
||||
mcpy(s->str, b.array, s->len);
|
||||
FLUSH(&s);
|
||||
}
|
||||
|
|
175
test/escape.go
Normal file
175
test/escape.go
Normal file
|
@ -0,0 +1,175 @@
|
|||
// $G $D/$F.go && $L $F.$A && ./$A.out
|
||||
|
||||
// Copyright 2009 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
|
||||
|
||||
// check for correct heap-moving of escaped variables.
|
||||
// it is hard to check for the allocations, but it is easy
|
||||
// to check that if you call the function twice at the
|
||||
// same stack level, the pointers returned should be
|
||||
// different.
|
||||
|
||||
var bad = false
|
||||
|
||||
var allptr = make([]*int, 0, 100);
|
||||
|
||||
func noalias(p, q *int, s string) {
|
||||
n := len(allptr);
|
||||
*p = -(n+1);
|
||||
*q = -(n+2);
|
||||
allptr = allptr[0:n+2];
|
||||
allptr[n] = p;
|
||||
allptr[n+1] = q;
|
||||
n += 2;
|
||||
for i := 0; i < n; i++ {
|
||||
if allptr[i] != nil && *allptr[i] != -(i+1) {
|
||||
println("aliased pointers", -(i+1), *allptr[i], "after", s);
|
||||
allptr[i] = nil;
|
||||
bad = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func val(p, q *int, v int, s string) {
|
||||
if *p != v {
|
||||
println("wrong value want", v, "got", *p, "after", s);
|
||||
bad = true;
|
||||
}
|
||||
if *q != v+1 {
|
||||
println("wrong value want", v+1, "got", *q, "after", s);
|
||||
bad = true;
|
||||
}
|
||||
}
|
||||
|
||||
func chk(p, q *int, v int, s string) {
|
||||
val(p, q, v, s);
|
||||
noalias(p, q, s);
|
||||
}
|
||||
|
||||
func chkalias(p, q *int, v int, s string) {
|
||||
if p != q {
|
||||
println("want aliased pointers but got different after", s);
|
||||
}
|
||||
if *q != v+1 {
|
||||
println("wrong value want", v+1, "got", *q, "after", s);
|
||||
}
|
||||
}
|
||||
|
||||
func i_escapes(x int) *int {
|
||||
var i int;
|
||||
i = x;
|
||||
return &i;
|
||||
}
|
||||
|
||||
func j_escapes(x int) *int {
|
||||
var j int = x;
|
||||
j = x;
|
||||
return &j;
|
||||
}
|
||||
|
||||
func k_escapes(x int) *int {
|
||||
k := x;
|
||||
return &k;
|
||||
}
|
||||
|
||||
func in_escapes(x int) *int {
|
||||
return &x;
|
||||
}
|
||||
|
||||
func send(c chan int, x int) {
|
||||
c <- x;
|
||||
}
|
||||
|
||||
func select_escapes(x int) *int {
|
||||
c := make(chan int);
|
||||
go send(c, x);
|
||||
select {
|
||||
case req := <-c:
|
||||
return &req;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
func select_escapes1(x int, y int) (*int, *int) {
|
||||
c := make(chan int);
|
||||
var a [2]int;
|
||||
var p [2]*int;
|
||||
a[0] = x;
|
||||
a[1] = y;
|
||||
for i := 0; i < 2; i++ {
|
||||
go send(c, a[i]);
|
||||
select {
|
||||
case req := <-c:
|
||||
p[i] = &req;
|
||||
}
|
||||
}
|
||||
return p[0], p[1]
|
||||
}
|
||||
|
||||
func range_escapes(x int) *int {
|
||||
var a [1]int;
|
||||
a[0] = x;
|
||||
for k, v := range a {
|
||||
return &v;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
// *is* aliased
|
||||
func range_escapes2(x, y int) (*int, *int) {
|
||||
var a [2]int;
|
||||
var p [2]*int;
|
||||
a[0] = x;
|
||||
a[1] = y;
|
||||
for k, v := range a {
|
||||
p[k] = &v;
|
||||
}
|
||||
return p[0], p[1]
|
||||
}
|
||||
|
||||
// *is* aliased
|
||||
func for_escapes2(x int, y int) (*int, *int) {
|
||||
var p [2]*int;
|
||||
n := 0;
|
||||
for i := x; n < 2; i = y {
|
||||
p[n] = &i;
|
||||
n++;
|
||||
}
|
||||
return p[0], p[1]
|
||||
}
|
||||
|
||||
func main() {
|
||||
p, q := i_escapes(1), i_escapes(2);
|
||||
chk(p, q, 1, "i_escapes");
|
||||
|
||||
p, q = j_escapes(3), j_escapes(4);
|
||||
chk(p, q, 3, "j_escapes");
|
||||
|
||||
p, q = k_escapes(5), k_escapes(6);
|
||||
chk(p, q, 5, "k_escapes");
|
||||
|
||||
p, q = in_escapes(7), in_escapes(8);
|
||||
chk(p, q, 7, "in_escapes");
|
||||
|
||||
p, q = select_escapes(9), select_escapes(10);
|
||||
chk(p, q, 9, "select_escapes");
|
||||
|
||||
p, q = select_escapes1(11, 12);
|
||||
chk(p, q, 11, "select_escapes1");
|
||||
|
||||
p, q = range_escapes(13), range_escapes(14);
|
||||
chk(p, q, 13, "range_escapes");
|
||||
|
||||
p, q = range_escapes2(101, 102);
|
||||
chkalias(p, q, 101, "range_escapes2");
|
||||
|
||||
p, q = for_escapes2(103, 104);
|
||||
chkalias(p, q, 103, "for_escapes2");
|
||||
|
||||
if bad {
|
||||
panic("BUG: no escape");
|
||||
}
|
||||
}
|
17
test/escape1.go
Normal file
17
test/escape1.go
Normal file
|
@ -0,0 +1,17 @@
|
|||
// errchk $G $D/$F.go
|
||||
|
||||
// Copyright 2009 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
|
||||
|
||||
func out_escapes() (x int, p *int) {
|
||||
p = &x; // ERROR "address.*out parameter"
|
||||
return;
|
||||
}
|
||||
|
||||
func out_escapes() (x int, p *int) {
|
||||
return 2, &x; // ERROR "address.*out parameter"
|
||||
}
|
||||
|
|
@ -172,7 +172,7 @@ bugs/bug129.go:6: syscall is package, not var
|
|||
BUG129
|
||||
|
||||
=========== bugs/bug130.go
|
||||
bugs/bug130.go:14: fatal error: getoutarg: not a func RANGE
|
||||
bugs/bug130.go:14: fatal error: getoutarg: not a func *<T>
|
||||
BUG: should run
|
||||
|
||||
=========== bugs/bug131.go
|
||||
|
|
Loading…
Reference in a new issue