1
0
mirror of https://github.com/golang/go synced 2024-11-20 03:04:40 -07:00

cmd/gc, cmd/ld: struct field tracking

This is an experiment in static analysis of Go programs
to understand which struct fields a program might use.
It is not part of the Go language specification, it must
be enabled explicitly when building the toolchain,
and it may be removed at any time.

After building the toolchain with GOEXPERIMENT=fieldtrack,
a specific field can be marked for tracking by including
`go:"track"` in the field tag:

        package pkg

        type T struct {
                F int `go:"track"`
                G int // untracked
        }

To simplify usage, only named struct types can have
tracked fields, and only exported fields can be tracked.

The implementation works by making each function begin
with a sequence of no-op USEFIELD instructions declaring
which tracked fields are accessed by a specific function.
After the linker's dead code elimination removes unused
functions, the fields referred to by the remaining
USEFIELD instructions are the ones reported as used by
the binary.

The -k option to the linker specifies the fully qualified
symbol name (such as my/pkg.list) of a string variable that
should be initialized with the field tracking information
for the program. The field tracking string is a sequence
of lines, each terminated by a \n and describing a single
tracked field referred to by the program. Each line is made
up of one or more tab-separated fields. The first field is
the name of the tracked field, fully qualified, as in
"my/pkg.T.F". Subsequent fields give a shortest path of
reverse references from that field to a global variable or
function, corresponding to one way in which the program
might reach that field.

A common source of false positives in field tracking is
types with large method sets, because a reference to the
type descriptor carries with it references to all methods.
To address this problem, the CL also introduces a comment
annotation

        //go:nointerface

that marks an upcoming method declaration as unavailable
for use in satisfying interfaces, both statically and
dynamically. Such a method is also invisible to package
reflect.

Again, all of this is disabled by default. It only turns on
if you have GOEXPERIMENT=fieldtrack set during make.bash.

R=iant, ken
CC=golang-dev
https://golang.org/cl/6749064
This commit is contained in:
Russ Cox 2012-11-02 00:17:21 -04:00
parent 84e20465fc
commit 3d40062c68
36 changed files with 415 additions and 190 deletions

View File

@ -413,6 +413,8 @@ struct
"MULAWT", LTYPEN, AMULAWT, "MULAWT", LTYPEN, AMULAWT,
"MULAWB", LTYPEN, AMULAWB, "MULAWB", LTYPEN, AMULAWB,
"USEFIELD", LTYPEN, AUSEFIELD,
0 0
}; };

View File

@ -142,6 +142,7 @@ void datagostring(Strlit*, Addr*);
void split64(Node*, Node*, Node*); void split64(Node*, Node*, Node*);
void splitclean(void); void splitclean(void);
Node* ncon(uint32 i); Node* ncon(uint32 i);
void gtrack(Sym*);
/* /*
* obj.c * obj.c

View File

@ -225,6 +225,17 @@ ggloblsym(Sym *s, int32 width, int dupok, int rodata)
p->reg |= RODATA; p->reg |= RODATA;
} }
void
gtrack(Sym *s)
{
Prog *p;
p = gins(AUSEFIELD, N, N);
p->from.type = D_OREG;
p->from.name = D_EXTERN;
p->from.sym = s;
}
int int
isfat(Type *t) isfat(Type *t)
{ {

View File

@ -195,6 +195,8 @@ enum as
AMULWB, AMULWB,
AMULAWT, AMULAWT,
AMULAWB, AMULAWB,
AUSEFIELD,
ALAST, ALAST,
}; };

View File

@ -153,6 +153,8 @@ struct Sym
Sym* sub; // in SSUB list Sym* sub; // in SSUB list
Sym* outer; // container of sub Sym* outer; // container of sub
Sym* gotype; Sym* gotype;
Sym* reachparent;
Sym* queue;
char* file; char* file;
char* dynimpname; char* dynimpname;
char* dynimplib; char* dynimplib;

View File

@ -147,6 +147,9 @@ main(int argc, char *argv[])
val = EARGF(usage()); val = EARGF(usage());
addbuildinfo(val); addbuildinfo(val);
break; break;
case 'k':
tracksym = EARGF(usage());
break;
} ARGEND } ARGEND
USED(argc); USED(argc);

View File

@ -242,5 +242,7 @@ Optab optab[] =
{ AMULWT, C_REG, C_REG, C_REG, 98, 4, 0 }, { AMULWT, C_REG, C_REG, C_REG, 98, 4, 0 },
{ AMULAWT, C_REG, C_REG, C_REGREG2, 99, 4, 0 }, { AMULAWT, C_REG, C_REG, C_REGREG2, 99, 4, 0 },
{ AUSEFIELD, C_ADDR, C_NONE, C_NONE, 0, 0, 0 },
{ AXXX, C_NONE, C_NONE, C_NONE, 0, 4, 0 }, { AXXX, C_NONE, C_NONE, C_NONE, 0, 4, 0 },
}; };

View File

@ -812,6 +812,7 @@ buildop(void)
case AMOVM: case AMOVM:
case ARFE: case ARFE:
case ATEXT: case ATEXT:
case AUSEFIELD:
case ACASE: case ACASE:
case ABCASE: case ABCASE:
break; break;

View File

@ -1014,7 +1014,8 @@ struct
"AESDECLAST", LTYPE3, AAESDECLAST, "AESDECLAST", LTYPE3, AAESDECLAST,
"AESIMC", LTYPE3, AAESIMC, "AESIMC", LTYPE3, AAESIMC,
"AESKEYGENASSIST", LTYPEX, AAESKEYGENASSIST, "AESKEYGENASSIST", LTYPEX, AAESKEYGENASSIST,
"PSHUFD", LTYPEX, APSHUFD, "PSHUFD", LTYPEX, APSHUFD,
"USEFIELD", LTYPEN, AUSEFIELD,
0 0
}; };

View File

@ -125,6 +125,7 @@ void sudoclean(void);
int sudoaddable(int, Node*, Addr*); int sudoaddable(int, Node*, Addr*);
void afunclit(Addr*); void afunclit(Addr*);
void nodfconst(Node*, Type*, Mpflt*); void nodfconst(Node*, Type*, Mpflt*);
void gtrack(Sym*);
/* /*
* cplx.c * cplx.c

View File

@ -205,6 +205,17 @@ ggloblnod(Node *nam, int32 width)
p->from.scale |= NOPTR; p->from.scale |= NOPTR;
} }
void
gtrack(Sym *s)
{
Prog *p;
p = gins(AUSEFIELD, N, N);
p->from.type = D_EXTERN;
p->from.index = D_NONE;
p->from.sym = s;
}
void void
ggloblsym(Sym *s, int32 width, int dupok, int rodata) ggloblsym(Sym *s, int32 width, int dupok, int rodata)
{ {

View File

@ -756,6 +756,8 @@ enum as
AAESKEYGENASSIST, AAESKEYGENASSIST,
APSHUFD, APSHUFD,
AUSEFIELD,
ALAST ALAST
}; };

View File

@ -158,6 +158,8 @@ struct Sym
Sym* next; // in text or data list Sym* next; // in text or data list
Sym* sub; // in SSUB list Sym* sub; // in SSUB list
Sym* outer; // container of sub Sym* outer; // container of sub
Sym* reachparent;
Sym* queue;
vlong value; vlong value;
vlong size; vlong size;
Sym* gotype; Sym* gotype;

View File

@ -144,6 +144,9 @@ main(int argc, char *argv[])
val = EARGF(usage()); val = EARGF(usage());
addbuildinfo(val); addbuildinfo(val);
break; break;
case 'k':
tracksym = EARGF(usage());
break;
} ARGEND } ARGEND
if(argc != 1) if(argc != 1)

View File

@ -1315,6 +1315,8 @@ Optab optab[] =
{ APSHUFD, yaes2, Pq, 0x70,(0) }, { APSHUFD, yaes2, Pq, 0x70,(0) },
{ AUSEFIELD, ynop, Px, 0,0 },
{ AEND }, { AEND },
0 0
}; };

View File

@ -781,6 +781,7 @@ struct
"UNPCKLPS", LTYPE3, AUNPCKLPS, "UNPCKLPS", LTYPE3, AUNPCKLPS,
"XORPD", LTYPE3, AXORPD, "XORPD", LTYPE3, AXORPD,
"XORPS", LTYPE3, AXORPS, "XORPS", LTYPE3, AXORPS,
"USEFIELD", LTYPEN, AUSEFIELD,
0 0
}; };

View File

@ -147,6 +147,7 @@ void afunclit(Addr*);
void split64(Node*, Node*, Node*); void split64(Node*, Node*, Node*);
void splitclean(void); void splitclean(void);
void nswap(Node*, Node*); void nswap(Node*, Node*);
void gtrack(Sym*);
/* /*
* cplx.c * cplx.c

View File

@ -224,6 +224,17 @@ ggloblsym(Sym *s, int32 width, int dupok, int rodata)
p->from.scale |= RODATA; p->from.scale |= RODATA;
} }
void
gtrack(Sym *s)
{
Prog *p;
p = gins(AUSEFIELD, N, N);
p->from.type = D_EXTERN;
p->from.index = D_NONE;
p->from.sym = s;
}
int int
isfat(Type *t) isfat(Type *t)
{ {

View File

@ -566,6 +566,8 @@ enum as
AUNPCKLPS, AUNPCKLPS,
AXORPD, AXORPD,
AXORPS, AXORPS,
AUSEFIELD,
ALAST ALAST
}; };

View File

@ -143,6 +143,8 @@ struct Sym
Sym* sub; // in sub list Sym* sub; // in sub list
Sym* outer; // container of sub Sym* outer; // container of sub
Sym* gotype; Sym* gotype;
Sym* reachparent;
Sym* queue;
char* file; char* file;
char* dynimpname; char* dynimpname;
char* dynimplib; char* dynimplib;

View File

@ -149,6 +149,9 @@ main(int argc, char *argv[])
val = EARGF(usage()); val = EARGF(usage());
addbuildinfo(val); addbuildinfo(val);
break; break;
case 'k':
tracksym = EARGF(usage());
break;
} ARGEND } ARGEND
if(argc != 1) if(argc != 1)

View File

@ -960,5 +960,7 @@ Optab optab[] =
{ AXORPD, yxm, Pe, 0x57 }, { AXORPD, yxm, Pe, 0x57 },
{ AXORPS, yxm, Pm, 0x57 }, { AXORPS, yxm, Pm, 0x57 },
{ AUSEFIELD, ynop, Px, 0,0 },
0 0
}; };

View File

@ -1269,7 +1269,7 @@ methodname1(Node *n, Node *t)
* n is fieldname, pa is base type, t is function type * n is fieldname, pa is base type, t is function type
*/ */
void void
addmethod(Sym *sf, Type *t, int local) addmethod(Sym *sf, Type *t, int local, int nointerface)
{ {
Type *f, *d, *pa; Type *f, *d, *pa;
Node *n; Node *n;
@ -1352,6 +1352,7 @@ addmethod(Sym *sf, Type *t, int local)
} }
f = structfield(n); f = structfield(n);
f->nointerface = nointerface;
// during import unexported method names should be in the type's package // during import unexported method names should be in the type's package
if(importpkg && f->sym && !exportname(f->sym->name) && f->sym->pkg != structpkg) if(importpkg && f->sym && !exportname(f->sym->name) && f->sym->pkg != structpkg)

View File

@ -278,6 +278,8 @@ dumpexporttype(Type *t)
// currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package // currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package
if(debug['l'] < 2) if(debug['l'] < 2)
typecheckinl(f->type->nname); typecheckinl(f->type->nname);
if(f->nointerface)
Bprint(bout, "\t//go:nointerface\n");
Bprint(bout, "\tfunc (%#T) %#hhS%#hT { %#H }\n", getthisx(f->type)->type, f->sym, f->type, f->type->nname->inl); Bprint(bout, "\tfunc (%#T) %#hhS%#hT { %#H }\n", getthisx(f->type)->type, f->sym, f->type, f->type->nname->inl);
reexportdeplist(f->type->nname->inl); reexportdeplist(f->type->nname->inl);
} else } else

View File

@ -137,6 +137,7 @@ typedef struct Label Label;
struct Type struct Type
{ {
uchar etype; uchar etype;
uchar nointerface;
uchar chan; uchar chan;
uchar trecur; // to detect loops uchar trecur; // to detect loops
uchar printed; uchar printed;
@ -175,6 +176,7 @@ struct Type
// TFIELD // TFIELD
Type* down; // next struct field, also key type in TMAP Type* down; // next struct field, also key type in TMAP
Type* outer; // outer struct
Strlit* note; // literal string annotation Strlit* note; // literal string annotation
// TARRAY // TARRAY
@ -185,6 +187,9 @@ struct Type
// for TFORW, where to copy the eventual value to // for TFORW, where to copy the eventual value to
NodeList *copyto; NodeList *copyto;
// for usefield
Node *lastfn;
}; };
#define T ((Type*)0) #define T ((Type*)0)
@ -236,6 +241,7 @@ struct Node
NodeList* rlist; NodeList* rlist;
uchar op; uchar op;
uchar nointerface;
uchar ullman; // sethi/ullman number uchar ullman; // sethi/ullman number
uchar addable; // type of addressability - 0 is not addressable uchar addable; // type of addressability - 0 is not addressable
uchar trecur; // to detect loops uchar trecur; // to detect loops
@ -284,7 +290,7 @@ struct Node
Node* defn; // ONAME: initializing assignment; OLABEL: labeled statement Node* defn; // ONAME: initializing assignment; OLABEL: labeled statement
Node* pack; // real package for import . names Node* pack; // real package for import . names
Node* curfn; // function for local variables Node* curfn; // function for local variables
Type* paramfld; // TFIELD for this PPARAM Type* paramfld; // TFIELD for this PPARAM; also for ODOT, curfn
// ONAME func param with PHEAP // ONAME func param with PHEAP
Node* heapaddr; // temp holding heap address of param Node* heapaddr; // temp holding heap address of param
@ -849,6 +855,7 @@ EXTERN Pkg* stringpkg; // fake package for C strings
EXTERN Pkg* typepkg; // fake package for runtime type info EXTERN Pkg* typepkg; // fake package for runtime type info
EXTERN Pkg* weaktypepkg; // weak references to runtime type info EXTERN Pkg* weaktypepkg; // weak references to runtime type info
EXTERN Pkg* unsafepkg; // package unsafe EXTERN Pkg* unsafepkg; // package unsafe
EXTERN Pkg* trackpkg; // fake package for field tracking
EXTERN Pkg* phash[128]; EXTERN Pkg* phash[128];
EXTERN int tptr; // either TPTR32 or TPTR64 EXTERN int tptr; // either TPTR32 or TPTR64
extern char* runtimeimport; extern char* runtimeimport;
@ -929,6 +936,9 @@ EXTERN int typecheckok;
EXTERN int compiling_runtime; EXTERN int compiling_runtime;
EXTERN int compiling_wrappers; EXTERN int compiling_wrappers;
EXTERN int nointerface;
EXTERN int fieldtrack_enabled;
/* /*
* y.tab.c * y.tab.c
*/ */
@ -1004,7 +1014,7 @@ void nodfconst(Node *n, Type *t, Mpflt* fval);
/* /*
* dcl.c * dcl.c
*/ */
void addmethod(Sym *sf, Type *t, int local); void addmethod(Sym *sf, Type *t, int local, int nointerface);
void addvar(Node *n, Type *t, int ctxt); void addvar(Node *n, Type *t, int ctxt);
NodeList* checkarglist(NodeList *all, int input); NodeList* checkarglist(NodeList *all, int input);
Node* colas(NodeList *left, NodeList *right, int32 lno); Node* colas(NodeList *left, NodeList *right, int32 lno);
@ -1200,8 +1210,10 @@ void dumptypestructs(void);
Type* methodfunc(Type *f, Type*); Type* methodfunc(Type *f, Type*);
Node* typename(Type *t); Node* typename(Type *t);
Sym* typesym(Type *t); Sym* typesym(Type *t);
Sym* tracksym(Type *t);
Sym* typesymprefix(char *prefix, Type *t); Sym* typesymprefix(char *prefix, Type *t);
int haspointers(Type *t); int haspointers(Type *t);
void usefield(Node*);
/* /*
* select.c * select.c

View File

@ -1275,6 +1275,7 @@ fndcl:
$$->nname = methodname1($$->shortname, rcvr->right); $$->nname = methodname1($$->shortname, rcvr->right);
$$->nname->defn = $$; $$->nname->defn = $$;
$$->nname->ntype = t; $$->nname->ntype = t;
$$->nname->nointerface = nointerface;
declare($$->nname, PFUNC); declare($$->nname, PFUNC);
funchdr($$); funchdr($$);
@ -1312,7 +1313,8 @@ hidden_fndcl:
$$->type = functype($2->n, $6, $8); $$->type = functype($2->n, $6, $8);
checkwidth($$->type); checkwidth($$->type);
addmethod($4, $$->type, 0); addmethod($4, $$->type, 0, nointerface);
nointerface = 0;
funchdr($$); funchdr($$);
// inl.c's inlnode in on a dotmeth node expects to find the inlineable body as // inl.c's inlnode in on a dotmeth node expects to find the inlineable body as
@ -1389,6 +1391,7 @@ xdcl_list:
$$ = concat($1, $2); $$ = concat($1, $2);
if(nsyntaxerrors == 0) if(nsyntaxerrors == 0)
testdclstack(); testdclstack();
nointerface = 0;
} }
vardcl_list: vardcl_list:

View File

@ -40,6 +40,7 @@ static struct {
int *val; int *val;
} exper[] = { } exper[] = {
// {"rune32", &rune32}, // {"rune32", &rune32},
{"fieldtrack", &fieldtrack_enabled},
{nil, nil}, {nil, nil},
}; };
@ -199,9 +200,19 @@ main(int argc, char *argv[])
localpkg = mkpkg(strlit("")); localpkg = mkpkg(strlit(""));
localpkg->prefix = "\"\""; localpkg->prefix = "\"\"";
// pseudo-package, for scoping
builtinpkg = mkpkg(strlit("go.builtin")); builtinpkg = mkpkg(strlit("go.builtin"));
// pseudo-package, accessed by import "unsafe"
unsafepkg = mkpkg(strlit("unsafe"));
unsafepkg->name = "unsafe";
// real package, referred to by generated runtime calls
runtimepkg = mkpkg(strlit("runtime"));
runtimepkg->name = "runtime";
// pseudo-packages used in symbol tables
gostringpkg = mkpkg(strlit("go.string")); gostringpkg = mkpkg(strlit("go.string"));
gostringpkg->name = "go.string"; gostringpkg->name = "go.string";
gostringpkg->prefix = "go.string"; // not go%2estring gostringpkg->prefix = "go.string"; // not go%2estring
@ -210,18 +221,16 @@ main(int argc, char *argv[])
itabpkg->name = "go.itab"; itabpkg->name = "go.itab";
itabpkg->prefix = "go.itab"; // not go%2eitab itabpkg->prefix = "go.itab"; // not go%2eitab
runtimepkg = mkpkg(strlit("runtime"));
runtimepkg->name = "runtime";
typepkg = mkpkg(strlit("type"));
typepkg->name = "type";
weaktypepkg = mkpkg(strlit("go.weak.type")); weaktypepkg = mkpkg(strlit("go.weak.type"));
weaktypepkg->name = "go.weak.type"; weaktypepkg->name = "go.weak.type";
weaktypepkg->prefix = "go.weak.type"; // not go%2eweak%2etype weaktypepkg->prefix = "go.weak.type"; // not go%2eweak%2etype
unsafepkg = mkpkg(strlit("unsafe")); trackpkg = mkpkg(strlit("go.track"));
unsafepkg->name = "unsafe"; trackpkg->name = "go.track";
trackpkg->prefix = "go.track"; // not go%2etrack
typepkg = mkpkg(strlit("type"));
typepkg->name = "type";
goroot = getgoroot(); goroot = getgoroot();
goos = getgoos(); goos = getgoos();
@ -1443,7 +1452,12 @@ getlinepragma(void)
char *cp, *ep, *linep; char *cp, *ep, *linep;
Hist *h; Hist *h;
for(i=0; i<5; i++) { c = getr();
if(c == 'g' && fieldtrack_enabled)
goto go;
if(c != 'l')
goto out;
for(i=1; i<5; i++) {
c = getr(); c = getr();
if(c != "line "[i]) if(c != "line "[i])
goto out; goto out;
@ -1491,6 +1505,20 @@ getlinepragma(void)
} }
} }
linehist(strdup(lexbuf), n, 0); linehist(strdup(lexbuf), n, 0);
goto out;
go:
for(i=1; i<11; i++) {
c = getr();
if(c != "go:nointerface"[i])
goto out;
}
nointerface = 1;
for(;;) {
c = getr();
if(c == EOF || c == '\n')
break;
}
out: out:
return c; return c;

View File

@ -83,6 +83,10 @@ compile(Node *fn)
afunclit(&ptxt->from); afunclit(&ptxt->from);
ginit(); ginit();
for(t=curfn->paramfld; t; t=t->down)
gtrack(tracksym(t->type));
genlist(curfn->enter); genlist(curfn->enter);
retpc = nil; retpc = nil;
@ -115,6 +119,7 @@ compile(Node *fn)
gclean(); gclean();
if(nerrors != 0) if(nerrors != 0)
goto ret; goto ret;
pc->as = ARET; // overwrite AEND pc->as = ARET; // overwrite AEND
pc->lineno = lineno; pc->lineno = lineno;

View File

@ -172,6 +172,8 @@ methods(Type *t)
fatal("non-method on %T method %S %T\n", mt, f->sym, f); fatal("non-method on %T method %S %T\n", mt, f->sym, f);
if (!getthisx(f->type)->type) if (!getthisx(f->type)->type)
fatal("receiver with no type on %T method %S %T\n", mt, f->sym, f); fatal("receiver with no type on %T method %S %T\n", mt, f->sym, f);
if(f->nointerface)
continue;
method = f->sym; method = f->sym;
if(method == nil) if(method == nil)
@ -622,6 +624,18 @@ typesym(Type *t)
return s; return s;
} }
Sym*
tracksym(Type *t)
{
char *p;
Sym *s;
p = smprint("%-T.%s", t->outer, t->sym->name);
s = pkglookup(p, trackpkg);
free(p);
return s;
}
Sym* Sym*
typesymprefix(char *prefix, Type *t) typesymprefix(char *prefix, Type *t)
{ {
@ -1155,4 +1169,3 @@ dgcsym(Type *t)
return s; return s;
} }

View File

@ -3040,7 +3040,7 @@ implements(Type *t, Type *iface, Type **m, Type **samename, int *ptr)
for(im=iface->type; im; im=im->down) { for(im=iface->type; im; im=im->down) {
imtype = methodfunc(im->type, 0); imtype = methodfunc(im->type, 0);
tm = ifacelookdot(im->sym, t, &followptr, 0); tm = ifacelookdot(im->sym, t, &followptr, 0);
if(tm == T || !eqtype(methodfunc(tm->type, 0), imtype)) { if(tm == T || tm->nointerface || !eqtype(methodfunc(tm->type, 0), imtype)) {
if(tm == T) if(tm == T)
tm = ifacelookdot(im->sym, t, &followptr, 1); tm = ifacelookdot(im->sym, t, &followptr, 1);
*m = im; *m = im;

View File

@ -1833,6 +1833,7 @@ lookdot(Node *n, Type *t, int dostrcmp)
fatal("lookdot badwidth %T %p", f1, f1); fatal("lookdot badwidth %T %p", f1, f1);
n->xoffset = f1->width; n->xoffset = f1->width;
n->type = f1->type; n->type = f1->type;
n->paramfld = f1;
if(t->etype == TINTER) { if(t->etype == TINTER) {
if(isptr[n->left->type->etype]) { if(isptr[n->left->type->etype]) {
n->left = nod(OIND, n->left, N); // implicitstar n->left = nod(OIND, n->left, N); // implicitstar
@ -2637,7 +2638,7 @@ typecheckfunc(Node *n)
t->nname = n->nname; t->nname = n->nname;
rcvr = getthisx(t)->type; rcvr = getthisx(t)->type;
if(rcvr != nil && n->shortname != N && !isblank(n->shortname)) if(rcvr != nil && n->shortname != N && !isblank(n->shortname))
addmethod(n->shortname->sym, t, 1); addmethod(n->shortname->sym, t, 1, n->nname->nointerface);
} }
static void static void

View File

@ -429,14 +429,19 @@ walkexpr(Node **np, NodeList **init)
case OCOM: case OCOM:
case OREAL: case OREAL:
case OIMAG: case OIMAG:
case ODOT:
case ODOTPTR:
case ODOTMETH: case ODOTMETH:
case ODOTINTER: case ODOTINTER:
case OIND: case OIND:
walkexpr(&n->left, init); walkexpr(&n->left, init);
goto ret; goto ret;
case ODOT:
case ODOTPTR:
usefield(n);
walkexpr(&n->left, init);
goto ret;
case OEFACE: case OEFACE:
walkexpr(&n->left, init); walkexpr(&n->left, init);
walkexpr(&n->right, init); walkexpr(&n->right, init);
@ -2897,3 +2902,44 @@ bounded(Node *n, int64 max)
return 0; return 0;
} }
void
usefield(Node *n)
{
Type *field, *l;
if(!fieldtrack_enabled)
return;
switch(n->op) {
default:
fatal("usefield %O", n->op);
case ODOT:
case ODOTPTR:
break;
}
field = n->paramfld;
if(field == T)
fatal("usefield %T %S without paramfld", n->left->type, n->right->sym);
if(field->note == nil || strstr(field->note->s, "go:\"track\"") == nil)
return;
// dedup on list
if(field->lastfn == curfn)
return;
field->lastfn = curfn;
field->outer = n->left->type;
if(isptr[field->outer->etype])
field->outer = field->outer->type;
if(field->outer->sym == S)
yyerror("tracked field must be in named struct type");
if(!exportname(field->sym->name))
yyerror("tracked field must be exported (upper case)");
l = typ(0);
l->type = field;
l->down = curfn->paramfld;
curfn->paramfld = l;
}

View File

@ -674,21 +674,21 @@ static const yytype_uint16 yyrline[] =
1098, 1099, 1100, 1101, 1107, 1108, 1111, 1114, 1115, 1116, 1098, 1099, 1100, 1101, 1107, 1108, 1111, 1114, 1115, 1116,
1117, 1118, 1121, 1122, 1135, 1139, 1144, 1149, 1154, 1158, 1117, 1118, 1121, 1122, 1135, 1139, 1144, 1149, 1154, 1158,
1159, 1162, 1168, 1175, 1181, 1188, 1194, 1205, 1216, 1245, 1159, 1162, 1168, 1175, 1181, 1188, 1194, 1205, 1216, 1245,
1284, 1309, 1326, 1335, 1338, 1346, 1350, 1354, 1361, 1367, 1285, 1310, 1328, 1337, 1340, 1348, 1352, 1356, 1363, 1369,
1372, 1384, 1387, 1395, 1396, 1402, 1403, 1409, 1413, 1419, 1374, 1386, 1389, 1398, 1399, 1405, 1406, 1412, 1416, 1422,
1420, 1426, 1430, 1436, 1459, 1464, 1470, 1476, 1483, 1492, 1423, 1429, 1433, 1439, 1462, 1467, 1473, 1479, 1486, 1495,
1501, 1516, 1522, 1527, 1531, 1538, 1551, 1552, 1558, 1564, 1504, 1519, 1525, 1530, 1534, 1541, 1554, 1555, 1561, 1567,
1567, 1571, 1577, 1580, 1589, 1592, 1593, 1597, 1598, 1604, 1570, 1574, 1580, 1583, 1592, 1595, 1596, 1600, 1601, 1607,
1605, 1606, 1607, 1608, 1610, 1609, 1624, 1629, 1633, 1637, 1608, 1609, 1610, 1611, 1613, 1612, 1627, 1632, 1636, 1640,
1641, 1645, 1650, 1669, 1675, 1683, 1687, 1693, 1697, 1703, 1644, 1648, 1653, 1672, 1678, 1686, 1690, 1696, 1700, 1706,
1707, 1713, 1717, 1726, 1730, 1734, 1738, 1744, 1747, 1755, 1710, 1716, 1720, 1729, 1733, 1737, 1741, 1747, 1750, 1758,
1756, 1758, 1759, 1762, 1765, 1768, 1771, 1774, 1777, 1780, 1759, 1761, 1762, 1765, 1768, 1771, 1774, 1777, 1780, 1783,
1783, 1786, 1789, 1792, 1795, 1798, 1801, 1807, 1811, 1815, 1786, 1789, 1792, 1795, 1798, 1801, 1804, 1810, 1814, 1818,
1819, 1823, 1827, 1847, 1854, 1865, 1866, 1867, 1870, 1871, 1822, 1826, 1830, 1850, 1857, 1868, 1869, 1870, 1873, 1874,
1874, 1878, 1888, 1892, 1896, 1900, 1904, 1908, 1912, 1918, 1877, 1881, 1891, 1895, 1899, 1903, 1907, 1911, 1915, 1921,
1924, 1932, 1940, 1946, 1953, 1969, 1987, 1991, 1997, 2000, 1927, 1935, 1943, 1949, 1956, 1972, 1990, 1994, 2000, 2003,
2003, 2007, 2017, 2021, 2036, 2044, 2045, 2057, 2058, 2061, 2006, 2010, 2020, 2024, 2039, 2047, 2048, 2060, 2061, 2064,
2065, 2071, 2075, 2081, 2085 2068, 2074, 2078, 2084, 2088
}; };
#endif #endif
@ -3731,6 +3731,7 @@ yyreduce:
(yyval.node)->nname = methodname1((yyval.node)->shortname, rcvr->right); (yyval.node)->nname = methodname1((yyval.node)->shortname, rcvr->right);
(yyval.node)->nname->defn = (yyval.node); (yyval.node)->nname->defn = (yyval.node);
(yyval.node)->nname->ntype = t; (yyval.node)->nname->ntype = t;
(yyval.node)->nname->nointerface = nointerface;
declare((yyval.node)->nname, PFUNC); declare((yyval.node)->nname, PFUNC);
funchdr((yyval.node)); funchdr((yyval.node));
@ -3738,7 +3739,7 @@ yyreduce:
break; break;
case 200: case 200:
#line 1285 "go.y" #line 1286 "go.y"
{ {
Sym *s; Sym *s;
Type *t; Type *t;
@ -3766,13 +3767,14 @@ yyreduce:
break; break;
case 201: case 201:
#line 1310 "go.y" #line 1311 "go.y"
{ {
(yyval.node) = methodname1(newname((yyvsp[(4) - (8)].sym)), (yyvsp[(2) - (8)].list)->n->right); (yyval.node) = methodname1(newname((yyvsp[(4) - (8)].sym)), (yyvsp[(2) - (8)].list)->n->right);
(yyval.node)->type = functype((yyvsp[(2) - (8)].list)->n, (yyvsp[(6) - (8)].list), (yyvsp[(8) - (8)].list)); (yyval.node)->type = functype((yyvsp[(2) - (8)].list)->n, (yyvsp[(6) - (8)].list), (yyvsp[(8) - (8)].list));
checkwidth((yyval.node)->type); checkwidth((yyval.node)->type);
addmethod((yyvsp[(4) - (8)].sym), (yyval.node)->type, 0); addmethod((yyvsp[(4) - (8)].sym), (yyval.node)->type, 0, nointerface);
nointerface = 0;
funchdr((yyval.node)); funchdr((yyval.node));
// inl.c's inlnode in on a dotmeth node expects to find the inlineable body as // inl.c's inlnode in on a dotmeth node expects to find the inlineable body as
@ -3784,7 +3786,7 @@ yyreduce:
break; break;
case 202: case 202:
#line 1327 "go.y" #line 1329 "go.y"
{ {
(yyvsp[(3) - (5)].list) = checkarglist((yyvsp[(3) - (5)].list), 1); (yyvsp[(3) - (5)].list) = checkarglist((yyvsp[(3) - (5)].list), 1);
(yyval.node) = nod(OTFUNC, N, N); (yyval.node) = nod(OTFUNC, N, N);
@ -3794,14 +3796,14 @@ yyreduce:
break; break;
case 203: case 203:
#line 1335 "go.y" #line 1337 "go.y"
{ {
(yyval.list) = nil; (yyval.list) = nil;
} }
break; break;
case 204: case 204:
#line 1339 "go.y" #line 1341 "go.y"
{ {
(yyval.list) = (yyvsp[(2) - (3)].list); (yyval.list) = (yyvsp[(2) - (3)].list);
if((yyval.list) == nil) if((yyval.list) == nil)
@ -3810,21 +3812,21 @@ yyreduce:
break; break;
case 205: case 205:
#line 1347 "go.y" #line 1349 "go.y"
{ {
(yyval.list) = nil; (yyval.list) = nil;
} }
break; break;
case 206: case 206:
#line 1351 "go.y" #line 1353 "go.y"
{ {
(yyval.list) = list1(nod(ODCLFIELD, N, (yyvsp[(1) - (1)].node))); (yyval.list) = list1(nod(ODCLFIELD, N, (yyvsp[(1) - (1)].node)));
} }
break; break;
case 207: case 207:
#line 1355 "go.y" #line 1357 "go.y"
{ {
(yyvsp[(2) - (3)].list) = checkarglist((yyvsp[(2) - (3)].list), 0); (yyvsp[(2) - (3)].list) = checkarglist((yyvsp[(2) - (3)].list), 0);
(yyval.list) = (yyvsp[(2) - (3)].list); (yyval.list) = (yyvsp[(2) - (3)].list);
@ -3832,14 +3834,14 @@ yyreduce:
break; break;
case 208: case 208:
#line 1362 "go.y" #line 1364 "go.y"
{ {
closurehdr((yyvsp[(1) - (1)].node)); closurehdr((yyvsp[(1) - (1)].node));
} }
break; break;
case 209: case 209:
#line 1368 "go.y" #line 1370 "go.y"
{ {
(yyval.node) = closurebody((yyvsp[(3) - (4)].list)); (yyval.node) = closurebody((yyvsp[(3) - (4)].list));
fixlbrace((yyvsp[(2) - (4)].i)); fixlbrace((yyvsp[(2) - (4)].i));
@ -3847,79 +3849,80 @@ yyreduce:
break; break;
case 210: case 210:
#line 1373 "go.y" #line 1375 "go.y"
{ {
(yyval.node) = closurebody(nil); (yyval.node) = closurebody(nil);
} }
break; break;
case 211: case 211:
#line 1384 "go.y" #line 1386 "go.y"
{ {
(yyval.list) = nil; (yyval.list) = nil;
} }
break; break;
case 212: case 212:
#line 1388 "go.y" #line 1390 "go.y"
{ {
(yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(2) - (3)].list)); (yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(2) - (3)].list));
if(nsyntaxerrors == 0) if(nsyntaxerrors == 0)
testdclstack(); testdclstack();
nointerface = 0;
} }
break; break;
case 214: case 214:
#line 1397 "go.y" #line 1400 "go.y"
{ {
(yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list)); (yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list));
} }
break; break;
case 216: case 216:
#line 1404 "go.y" #line 1407 "go.y"
{ {
(yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list)); (yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list));
} }
break; break;
case 217: case 217:
#line 1410 "go.y" #line 1413 "go.y"
{ {
(yyval.list) = list1((yyvsp[(1) - (1)].node)); (yyval.list) = list1((yyvsp[(1) - (1)].node));
} }
break; break;
case 218: case 218:
#line 1414 "go.y" #line 1417 "go.y"
{ {
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
} }
break; break;
case 220: case 220:
#line 1421 "go.y" #line 1424 "go.y"
{ {
(yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list)); (yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list));
} }
break; break;
case 221: case 221:
#line 1427 "go.y" #line 1430 "go.y"
{ {
(yyval.list) = list1((yyvsp[(1) - (1)].node)); (yyval.list) = list1((yyvsp[(1) - (1)].node));
} }
break; break;
case 222: case 222:
#line 1431 "go.y" #line 1434 "go.y"
{ {
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
} }
break; break;
case 223: case 223:
#line 1437 "go.y" #line 1440 "go.y"
{ {
NodeList *l; NodeList *l;
@ -3945,7 +3948,7 @@ yyreduce:
break; break;
case 224: case 224:
#line 1460 "go.y" #line 1463 "go.y"
{ {
(yyvsp[(1) - (2)].node)->val = (yyvsp[(2) - (2)].val); (yyvsp[(1) - (2)].node)->val = (yyvsp[(2) - (2)].val);
(yyval.list) = list1((yyvsp[(1) - (2)].node)); (yyval.list) = list1((yyvsp[(1) - (2)].node));
@ -3953,7 +3956,7 @@ yyreduce:
break; break;
case 225: case 225:
#line 1465 "go.y" #line 1468 "go.y"
{ {
(yyvsp[(2) - (4)].node)->val = (yyvsp[(4) - (4)].val); (yyvsp[(2) - (4)].node)->val = (yyvsp[(4) - (4)].val);
(yyval.list) = list1((yyvsp[(2) - (4)].node)); (yyval.list) = list1((yyvsp[(2) - (4)].node));
@ -3962,7 +3965,7 @@ yyreduce:
break; break;
case 226: case 226:
#line 1471 "go.y" #line 1474 "go.y"
{ {
(yyvsp[(2) - (3)].node)->right = nod(OIND, (yyvsp[(2) - (3)].node)->right, N); (yyvsp[(2) - (3)].node)->right = nod(OIND, (yyvsp[(2) - (3)].node)->right, N);
(yyvsp[(2) - (3)].node)->val = (yyvsp[(3) - (3)].val); (yyvsp[(2) - (3)].node)->val = (yyvsp[(3) - (3)].val);
@ -3971,7 +3974,7 @@ yyreduce:
break; break;
case 227: case 227:
#line 1477 "go.y" #line 1480 "go.y"
{ {
(yyvsp[(3) - (5)].node)->right = nod(OIND, (yyvsp[(3) - (5)].node)->right, N); (yyvsp[(3) - (5)].node)->right = nod(OIND, (yyvsp[(3) - (5)].node)->right, N);
(yyvsp[(3) - (5)].node)->val = (yyvsp[(5) - (5)].val); (yyvsp[(3) - (5)].node)->val = (yyvsp[(5) - (5)].val);
@ -3981,7 +3984,7 @@ yyreduce:
break; break;
case 228: case 228:
#line 1484 "go.y" #line 1487 "go.y"
{ {
(yyvsp[(3) - (5)].node)->right = nod(OIND, (yyvsp[(3) - (5)].node)->right, N); (yyvsp[(3) - (5)].node)->right = nod(OIND, (yyvsp[(3) - (5)].node)->right, N);
(yyvsp[(3) - (5)].node)->val = (yyvsp[(5) - (5)].val); (yyvsp[(3) - (5)].node)->val = (yyvsp[(5) - (5)].val);
@ -3991,7 +3994,7 @@ yyreduce:
break; break;
case 229: case 229:
#line 1493 "go.y" #line 1496 "go.y"
{ {
Node *n; Node *n;
@ -4003,7 +4006,7 @@ yyreduce:
break; break;
case 230: case 230:
#line 1502 "go.y" #line 1505 "go.y"
{ {
Pkg *pkg; Pkg *pkg;
@ -4019,14 +4022,14 @@ yyreduce:
break; break;
case 231: case 231:
#line 1517 "go.y" #line 1520 "go.y"
{ {
(yyval.node) = embedded((yyvsp[(1) - (1)].sym)); (yyval.node) = embedded((yyvsp[(1) - (1)].sym));
} }
break; break;
case 232: case 232:
#line 1523 "go.y" #line 1526 "go.y"
{ {
(yyval.node) = nod(ODCLFIELD, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node)); (yyval.node) = nod(ODCLFIELD, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node));
ifacedcl((yyval.node)); ifacedcl((yyval.node));
@ -4034,14 +4037,14 @@ yyreduce:
break; break;
case 233: case 233:
#line 1528 "go.y" #line 1531 "go.y"
{ {
(yyval.node) = nod(ODCLFIELD, N, oldname((yyvsp[(1) - (1)].sym))); (yyval.node) = nod(ODCLFIELD, N, oldname((yyvsp[(1) - (1)].sym)));
} }
break; break;
case 234: case 234:
#line 1532 "go.y" #line 1535 "go.y"
{ {
(yyval.node) = nod(ODCLFIELD, N, oldname((yyvsp[(2) - (3)].sym))); (yyval.node) = nod(ODCLFIELD, N, oldname((yyvsp[(2) - (3)].sym)));
yyerror("cannot parenthesize embedded type"); yyerror("cannot parenthesize embedded type");
@ -4049,7 +4052,7 @@ yyreduce:
break; break;
case 235: case 235:
#line 1539 "go.y" #line 1542 "go.y"
{ {
// without func keyword // without func keyword
(yyvsp[(2) - (4)].list) = checkarglist((yyvsp[(2) - (4)].list), 1); (yyvsp[(2) - (4)].list) = checkarglist((yyvsp[(2) - (4)].list), 1);
@ -4060,7 +4063,7 @@ yyreduce:
break; break;
case 237: case 237:
#line 1553 "go.y" #line 1556 "go.y"
{ {
(yyval.node) = nod(ONONAME, N, N); (yyval.node) = nod(ONONAME, N, N);
(yyval.node)->sym = (yyvsp[(1) - (2)].sym); (yyval.node)->sym = (yyvsp[(1) - (2)].sym);
@ -4069,7 +4072,7 @@ yyreduce:
break; break;
case 238: case 238:
#line 1559 "go.y" #line 1562 "go.y"
{ {
(yyval.node) = nod(ONONAME, N, N); (yyval.node) = nod(ONONAME, N, N);
(yyval.node)->sym = (yyvsp[(1) - (2)].sym); (yyval.node)->sym = (yyvsp[(1) - (2)].sym);
@ -4078,56 +4081,56 @@ yyreduce:
break; break;
case 240: case 240:
#line 1568 "go.y" #line 1571 "go.y"
{ {
(yyval.list) = list1((yyvsp[(1) - (1)].node)); (yyval.list) = list1((yyvsp[(1) - (1)].node));
} }
break; break;
case 241: case 241:
#line 1572 "go.y" #line 1575 "go.y"
{ {
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
} }
break; break;
case 242: case 242:
#line 1577 "go.y" #line 1580 "go.y"
{ {
(yyval.list) = nil; (yyval.list) = nil;
} }
break; break;
case 243: case 243:
#line 1581 "go.y" #line 1584 "go.y"
{ {
(yyval.list) = (yyvsp[(1) - (2)].list); (yyval.list) = (yyvsp[(1) - (2)].list);
} }
break; break;
case 244: case 244:
#line 1589 "go.y" #line 1592 "go.y"
{ {
(yyval.node) = N; (yyval.node) = N;
} }
break; break;
case 246: case 246:
#line 1594 "go.y" #line 1597 "go.y"
{ {
(yyval.node) = liststmt((yyvsp[(1) - (1)].list)); (yyval.node) = liststmt((yyvsp[(1) - (1)].list));
} }
break; break;
case 248: case 248:
#line 1599 "go.y" #line 1602 "go.y"
{ {
(yyval.node) = N; (yyval.node) = N;
} }
break; break;
case 254: case 254:
#line 1610 "go.y" #line 1613 "go.y"
{ {
(yyvsp[(1) - (2)].node) = nod(OLABEL, (yyvsp[(1) - (2)].node), N); (yyvsp[(1) - (2)].node) = nod(OLABEL, (yyvsp[(1) - (2)].node), N);
(yyvsp[(1) - (2)].node)->sym = dclstack; // context, for goto restrictions (yyvsp[(1) - (2)].node)->sym = dclstack; // context, for goto restrictions
@ -4135,7 +4138,7 @@ yyreduce:
break; break;
case 255: case 255:
#line 1615 "go.y" #line 1618 "go.y"
{ {
NodeList *l; NodeList *l;
@ -4148,7 +4151,7 @@ yyreduce:
break; break;
case 256: case 256:
#line 1625 "go.y" #line 1628 "go.y"
{ {
// will be converted to OFALL // will be converted to OFALL
(yyval.node) = nod(OXFALL, N, N); (yyval.node) = nod(OXFALL, N, N);
@ -4156,35 +4159,35 @@ yyreduce:
break; break;
case 257: case 257:
#line 1630 "go.y" #line 1633 "go.y"
{ {
(yyval.node) = nod(OBREAK, (yyvsp[(2) - (2)].node), N); (yyval.node) = nod(OBREAK, (yyvsp[(2) - (2)].node), N);
} }
break; break;
case 258: case 258:
#line 1634 "go.y" #line 1637 "go.y"
{ {
(yyval.node) = nod(OCONTINUE, (yyvsp[(2) - (2)].node), N); (yyval.node) = nod(OCONTINUE, (yyvsp[(2) - (2)].node), N);
} }
break; break;
case 259: case 259:
#line 1638 "go.y" #line 1641 "go.y"
{ {
(yyval.node) = nod(OPROC, (yyvsp[(2) - (2)].node), N); (yyval.node) = nod(OPROC, (yyvsp[(2) - (2)].node), N);
} }
break; break;
case 260: case 260:
#line 1642 "go.y" #line 1645 "go.y"
{ {
(yyval.node) = nod(ODEFER, (yyvsp[(2) - (2)].node), N); (yyval.node) = nod(ODEFER, (yyvsp[(2) - (2)].node), N);
} }
break; break;
case 261: case 261:
#line 1646 "go.y" #line 1649 "go.y"
{ {
(yyval.node) = nod(OGOTO, (yyvsp[(2) - (2)].node), N); (yyval.node) = nod(OGOTO, (yyvsp[(2) - (2)].node), N);
(yyval.node)->sym = dclstack; // context, for goto restrictions (yyval.node)->sym = dclstack; // context, for goto restrictions
@ -4192,7 +4195,7 @@ yyreduce:
break; break;
case 262: case 262:
#line 1651 "go.y" #line 1654 "go.y"
{ {
(yyval.node) = nod(ORETURN, N, N); (yyval.node) = nod(ORETURN, N, N);
(yyval.node)->list = (yyvsp[(2) - (2)].list); (yyval.node)->list = (yyvsp[(2) - (2)].list);
@ -4212,7 +4215,7 @@ yyreduce:
break; break;
case 263: case 263:
#line 1670 "go.y" #line 1673 "go.y"
{ {
(yyval.list) = nil; (yyval.list) = nil;
if((yyvsp[(1) - (1)].node) != N) if((yyvsp[(1) - (1)].node) != N)
@ -4221,7 +4224,7 @@ yyreduce:
break; break;
case 264: case 264:
#line 1676 "go.y" #line 1679 "go.y"
{ {
(yyval.list) = (yyvsp[(1) - (3)].list); (yyval.list) = (yyvsp[(1) - (3)].list);
if((yyvsp[(3) - (3)].node) != N) if((yyvsp[(3) - (3)].node) != N)
@ -4230,189 +4233,189 @@ yyreduce:
break; break;
case 265: case 265:
#line 1684 "go.y" #line 1687 "go.y"
{ {
(yyval.list) = list1((yyvsp[(1) - (1)].node)); (yyval.list) = list1((yyvsp[(1) - (1)].node));
} }
break; break;
case 266: case 266:
#line 1688 "go.y" #line 1691 "go.y"
{ {
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
} }
break; break;
case 267: case 267:
#line 1694 "go.y" #line 1697 "go.y"
{ {
(yyval.list) = list1((yyvsp[(1) - (1)].node)); (yyval.list) = list1((yyvsp[(1) - (1)].node));
} }
break; break;
case 268: case 268:
#line 1698 "go.y" #line 1701 "go.y"
{ {
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
} }
break; break;
case 269: case 269:
#line 1704 "go.y" #line 1707 "go.y"
{ {
(yyval.list) = list1((yyvsp[(1) - (1)].node)); (yyval.list) = list1((yyvsp[(1) - (1)].node));
} }
break; break;
case 270: case 270:
#line 1708 "go.y" #line 1711 "go.y"
{ {
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
} }
break; break;
case 271: case 271:
#line 1714 "go.y" #line 1717 "go.y"
{ {
(yyval.list) = list1((yyvsp[(1) - (1)].node)); (yyval.list) = list1((yyvsp[(1) - (1)].node));
} }
break; break;
case 272: case 272:
#line 1718 "go.y" #line 1721 "go.y"
{ {
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
} }
break; break;
case 273: case 273:
#line 1727 "go.y" #line 1730 "go.y"
{ {
(yyval.list) = list1((yyvsp[(1) - (1)].node)); (yyval.list) = list1((yyvsp[(1) - (1)].node));
} }
break; break;
case 274: case 274:
#line 1731 "go.y" #line 1734 "go.y"
{ {
(yyval.list) = list1((yyvsp[(1) - (1)].node)); (yyval.list) = list1((yyvsp[(1) - (1)].node));
} }
break; break;
case 275: case 275:
#line 1735 "go.y" #line 1738 "go.y"
{ {
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
} }
break; break;
case 276: case 276:
#line 1739 "go.y" #line 1742 "go.y"
{ {
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
} }
break; break;
case 277: case 277:
#line 1744 "go.y" #line 1747 "go.y"
{ {
(yyval.list) = nil; (yyval.list) = nil;
} }
break; break;
case 278: case 278:
#line 1748 "go.y" #line 1751 "go.y"
{ {
(yyval.list) = (yyvsp[(1) - (2)].list); (yyval.list) = (yyvsp[(1) - (2)].list);
} }
break; break;
case 283: case 283:
#line 1762 "go.y" #line 1765 "go.y"
{ {
(yyval.node) = N; (yyval.node) = N;
} }
break; break;
case 285: case 285:
#line 1768 "go.y" #line 1771 "go.y"
{ {
(yyval.list) = nil; (yyval.list) = nil;
} }
break; break;
case 287: case 287:
#line 1774 "go.y" #line 1777 "go.y"
{ {
(yyval.node) = N; (yyval.node) = N;
} }
break; break;
case 289: case 289:
#line 1780 "go.y" #line 1783 "go.y"
{ {
(yyval.list) = nil; (yyval.list) = nil;
} }
break; break;
case 291: case 291:
#line 1786 "go.y" #line 1789 "go.y"
{ {
(yyval.list) = nil; (yyval.list) = nil;
} }
break; break;
case 293: case 293:
#line 1792 "go.y" #line 1795 "go.y"
{ {
(yyval.list) = nil; (yyval.list) = nil;
} }
break; break;
case 295: case 295:
#line 1798 "go.y" #line 1801 "go.y"
{ {
(yyval.val).ctype = CTxxx; (yyval.val).ctype = CTxxx;
} }
break; break;
case 297: case 297:
#line 1808 "go.y" #line 1811 "go.y"
{ {
importimport((yyvsp[(2) - (4)].sym), (yyvsp[(3) - (4)].val).u.sval); importimport((yyvsp[(2) - (4)].sym), (yyvsp[(3) - (4)].val).u.sval);
} }
break; break;
case 298: case 298:
#line 1812 "go.y" #line 1815 "go.y"
{ {
importvar((yyvsp[(2) - (4)].sym), (yyvsp[(3) - (4)].type)); importvar((yyvsp[(2) - (4)].sym), (yyvsp[(3) - (4)].type));
} }
break; break;
case 299: case 299:
#line 1816 "go.y" #line 1819 "go.y"
{ {
importconst((yyvsp[(2) - (5)].sym), types[TIDEAL], (yyvsp[(4) - (5)].node)); importconst((yyvsp[(2) - (5)].sym), types[TIDEAL], (yyvsp[(4) - (5)].node));
} }
break; break;
case 300: case 300:
#line 1820 "go.y" #line 1823 "go.y"
{ {
importconst((yyvsp[(2) - (6)].sym), (yyvsp[(3) - (6)].type), (yyvsp[(5) - (6)].node)); importconst((yyvsp[(2) - (6)].sym), (yyvsp[(3) - (6)].type), (yyvsp[(5) - (6)].node));
} }
break; break;
case 301: case 301:
#line 1824 "go.y" #line 1827 "go.y"
{ {
importtype((yyvsp[(2) - (4)].type), (yyvsp[(3) - (4)].type)); importtype((yyvsp[(2) - (4)].type), (yyvsp[(3) - (4)].type));
} }
break; break;
case 302: case 302:
#line 1828 "go.y" #line 1831 "go.y"
{ {
if((yyvsp[(2) - (4)].node) == N) { if((yyvsp[(2) - (4)].node) == N) {
dclcontext = PEXTERN; // since we skip the funcbody below dclcontext = PEXTERN; // since we skip the funcbody below
@ -4433,7 +4436,7 @@ yyreduce:
break; break;
case 303: case 303:
#line 1848 "go.y" #line 1851 "go.y"
{ {
(yyval.sym) = (yyvsp[(1) - (1)].sym); (yyval.sym) = (yyvsp[(1) - (1)].sym);
structpkg = (yyval.sym)->pkg; structpkg = (yyval.sym)->pkg;
@ -4441,7 +4444,7 @@ yyreduce:
break; break;
case 304: case 304:
#line 1855 "go.y" #line 1858 "go.y"
{ {
(yyval.type) = pkgtype((yyvsp[(1) - (1)].sym)); (yyval.type) = pkgtype((yyvsp[(1) - (1)].sym));
importsym((yyvsp[(1) - (1)].sym), OTYPE); importsym((yyvsp[(1) - (1)].sym), OTYPE);
@ -4449,14 +4452,14 @@ yyreduce:
break; break;
case 310: case 310:
#line 1875 "go.y" #line 1878 "go.y"
{ {
(yyval.type) = pkgtype((yyvsp[(1) - (1)].sym)); (yyval.type) = pkgtype((yyvsp[(1) - (1)].sym));
} }
break; break;
case 311: case 311:
#line 1879 "go.y" #line 1882 "go.y"
{ {
// predefined name like uint8 // predefined name like uint8
(yyvsp[(1) - (1)].sym) = pkglookup((yyvsp[(1) - (1)].sym)->name, builtinpkg); (yyvsp[(1) - (1)].sym) = pkglookup((yyvsp[(1) - (1)].sym)->name, builtinpkg);
@ -4469,49 +4472,49 @@ yyreduce:
break; break;
case 312: case 312:
#line 1889 "go.y" #line 1892 "go.y"
{ {
(yyval.type) = aindex(N, (yyvsp[(3) - (3)].type)); (yyval.type) = aindex(N, (yyvsp[(3) - (3)].type));
} }
break; break;
case 313: case 313:
#line 1893 "go.y" #line 1896 "go.y"
{ {
(yyval.type) = aindex(nodlit((yyvsp[(2) - (4)].val)), (yyvsp[(4) - (4)].type)); (yyval.type) = aindex(nodlit((yyvsp[(2) - (4)].val)), (yyvsp[(4) - (4)].type));
} }
break; break;
case 314: case 314:
#line 1897 "go.y" #line 1900 "go.y"
{ {
(yyval.type) = maptype((yyvsp[(3) - (5)].type), (yyvsp[(5) - (5)].type)); (yyval.type) = maptype((yyvsp[(3) - (5)].type), (yyvsp[(5) - (5)].type));
} }
break; break;
case 315: case 315:
#line 1901 "go.y" #line 1904 "go.y"
{ {
(yyval.type) = tostruct((yyvsp[(3) - (4)].list)); (yyval.type) = tostruct((yyvsp[(3) - (4)].list));
} }
break; break;
case 316: case 316:
#line 1905 "go.y" #line 1908 "go.y"
{ {
(yyval.type) = tointerface((yyvsp[(3) - (4)].list)); (yyval.type) = tointerface((yyvsp[(3) - (4)].list));
} }
break; break;
case 317: case 317:
#line 1909 "go.y" #line 1912 "go.y"
{ {
(yyval.type) = ptrto((yyvsp[(2) - (2)].type)); (yyval.type) = ptrto((yyvsp[(2) - (2)].type));
} }
break; break;
case 318: case 318:
#line 1913 "go.y" #line 1916 "go.y"
{ {
(yyval.type) = typ(TCHAN); (yyval.type) = typ(TCHAN);
(yyval.type)->type = (yyvsp[(2) - (2)].type); (yyval.type)->type = (yyvsp[(2) - (2)].type);
@ -4520,7 +4523,7 @@ yyreduce:
break; break;
case 319: case 319:
#line 1919 "go.y" #line 1922 "go.y"
{ {
(yyval.type) = typ(TCHAN); (yyval.type) = typ(TCHAN);
(yyval.type)->type = (yyvsp[(3) - (4)].type); (yyval.type)->type = (yyvsp[(3) - (4)].type);
@ -4529,7 +4532,7 @@ yyreduce:
break; break;
case 320: case 320:
#line 1925 "go.y" #line 1928 "go.y"
{ {
(yyval.type) = typ(TCHAN); (yyval.type) = typ(TCHAN);
(yyval.type)->type = (yyvsp[(3) - (3)].type); (yyval.type)->type = (yyvsp[(3) - (3)].type);
@ -4538,7 +4541,7 @@ yyreduce:
break; break;
case 321: case 321:
#line 1933 "go.y" #line 1936 "go.y"
{ {
(yyval.type) = typ(TCHAN); (yyval.type) = typ(TCHAN);
(yyval.type)->type = (yyvsp[(3) - (3)].type); (yyval.type)->type = (yyvsp[(3) - (3)].type);
@ -4547,14 +4550,14 @@ yyreduce:
break; break;
case 322: case 322:
#line 1941 "go.y" #line 1944 "go.y"
{ {
(yyval.type) = functype(nil, (yyvsp[(3) - (5)].list), (yyvsp[(5) - (5)].list)); (yyval.type) = functype(nil, (yyvsp[(3) - (5)].list), (yyvsp[(5) - (5)].list));
} }
break; break;
case 323: case 323:
#line 1947 "go.y" #line 1950 "go.y"
{ {
(yyval.node) = nod(ODCLFIELD, N, typenod((yyvsp[(2) - (3)].type))); (yyval.node) = nod(ODCLFIELD, N, typenod((yyvsp[(2) - (3)].type)));
if((yyvsp[(1) - (3)].sym)) if((yyvsp[(1) - (3)].sym))
@ -4564,7 +4567,7 @@ yyreduce:
break; break;
case 324: case 324:
#line 1954 "go.y" #line 1957 "go.y"
{ {
Type *t; Type *t;
@ -4581,7 +4584,7 @@ yyreduce:
break; break;
case 325: case 325:
#line 1970 "go.y" #line 1973 "go.y"
{ {
Sym *s; Sym *s;
@ -4600,49 +4603,49 @@ yyreduce:
break; break;
case 326: case 326:
#line 1988 "go.y" #line 1991 "go.y"
{ {
(yyval.node) = nod(ODCLFIELD, newname((yyvsp[(1) - (5)].sym)), typenod(functype(fakethis(), (yyvsp[(3) - (5)].list), (yyvsp[(5) - (5)].list)))); (yyval.node) = nod(ODCLFIELD, newname((yyvsp[(1) - (5)].sym)), typenod(functype(fakethis(), (yyvsp[(3) - (5)].list), (yyvsp[(5) - (5)].list))));
} }
break; break;
case 327: case 327:
#line 1992 "go.y" #line 1995 "go.y"
{ {
(yyval.node) = nod(ODCLFIELD, N, typenod((yyvsp[(1) - (1)].type))); (yyval.node) = nod(ODCLFIELD, N, typenod((yyvsp[(1) - (1)].type)));
} }
break; break;
case 328: case 328:
#line 1997 "go.y" #line 2000 "go.y"
{ {
(yyval.list) = nil; (yyval.list) = nil;
} }
break; break;
case 330: case 330:
#line 2004 "go.y" #line 2007 "go.y"
{ {
(yyval.list) = (yyvsp[(2) - (3)].list); (yyval.list) = (yyvsp[(2) - (3)].list);
} }
break; break;
case 331: case 331:
#line 2008 "go.y" #line 2011 "go.y"
{ {
(yyval.list) = list1(nod(ODCLFIELD, N, typenod((yyvsp[(1) - (1)].type)))); (yyval.list) = list1(nod(ODCLFIELD, N, typenod((yyvsp[(1) - (1)].type))));
} }
break; break;
case 332: case 332:
#line 2018 "go.y" #line 2021 "go.y"
{ {
(yyval.node) = nodlit((yyvsp[(1) - (1)].val)); (yyval.node) = nodlit((yyvsp[(1) - (1)].val));
} }
break; break;
case 333: case 333:
#line 2022 "go.y" #line 2025 "go.y"
{ {
(yyval.node) = nodlit((yyvsp[(2) - (2)].val)); (yyval.node) = nodlit((yyvsp[(2) - (2)].val));
switch((yyval.node)->val.ctype){ switch((yyval.node)->val.ctype){
@ -4660,7 +4663,7 @@ yyreduce:
break; break;
case 334: case 334:
#line 2037 "go.y" #line 2040 "go.y"
{ {
(yyval.node) = oldname(pkglookup((yyvsp[(1) - (1)].sym)->name, builtinpkg)); (yyval.node) = oldname(pkglookup((yyvsp[(1) - (1)].sym)->name, builtinpkg));
if((yyval.node)->op != OLITERAL) if((yyval.node)->op != OLITERAL)
@ -4669,7 +4672,7 @@ yyreduce:
break; break;
case 336: case 336:
#line 2046 "go.y" #line 2049 "go.y"
{ {
if((yyvsp[(2) - (5)].node)->val.ctype == CTRUNE && (yyvsp[(4) - (5)].node)->val.ctype == CTINT) { if((yyvsp[(2) - (5)].node)->val.ctype == CTRUNE && (yyvsp[(4) - (5)].node)->val.ctype == CTINT) {
(yyval.node) = (yyvsp[(2) - (5)].node); (yyval.node) = (yyvsp[(2) - (5)].node);
@ -4683,42 +4686,42 @@ yyreduce:
break; break;
case 339: case 339:
#line 2062 "go.y" #line 2065 "go.y"
{ {
(yyval.list) = list1((yyvsp[(1) - (1)].node)); (yyval.list) = list1((yyvsp[(1) - (1)].node));
} }
break; break;
case 340: case 340:
#line 2066 "go.y" #line 2069 "go.y"
{ {
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
} }
break; break;
case 341: case 341:
#line 2072 "go.y" #line 2075 "go.y"
{ {
(yyval.list) = list1((yyvsp[(1) - (1)].node)); (yyval.list) = list1((yyvsp[(1) - (1)].node));
} }
break; break;
case 342: case 342:
#line 2076 "go.y" #line 2079 "go.y"
{ {
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
} }
break; break;
case 343: case 343:
#line 2082 "go.y" #line 2085 "go.y"
{ {
(yyval.list) = list1((yyvsp[(1) - (1)].node)); (yyval.list) = list1((yyvsp[(1) - (1)].node));
} }
break; break;
case 344: case 344:
#line 2086 "go.y" #line 2089 "go.y"
{ {
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
} }
@ -4726,7 +4729,7 @@ yyreduce:
/* Line 1267 of yacc.c. */ /* Line 1267 of yacc.c. */
#line 4731 "y.tab.c" #line 4734 "y.tab.c"
default: break; default: break;
} }
YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
@ -4940,7 +4943,7 @@ yyreturn:
} }
#line 2090 "go.y" #line 2093 "go.y"
static void static void

View File

@ -602,11 +602,15 @@ addstrdata(char *name, char *value)
addstring(sp, value); addstring(sp, value);
s = lookup(name, 0); s = lookup(name, 0);
s->size = 0;
s->dupok = 1; s->dupok = 1;
addaddr(s, sp); addaddr(s, sp);
adduint32(s, strlen(value)); adduint32(s, strlen(value));
if(PtrSize == 8) if(PtrSize == 8)
adduint32(s, 0); // round struct to pointer width adduint32(s, 0); // round struct to pointer width
// in case reachability has already been computed
sp->reachable = s->reachable;
} }
vlong vlong

View File

@ -431,10 +431,16 @@ parsemethod(char **pp, char *ep, char **methp)
if(p == ep) if(p == ep)
return 0; return 0;
// might be a comment about the method
if(p + 2 < ep && strncmp(p, "//", 2) == 0)
goto useline;
// if it says "func (", it's a method // if it says "func (", it's a method
if(p + 6 >= ep || strncmp(p, "func (", 6) != 0) if(p + 6 < ep && strncmp(p, "func (", 6) == 0)
return 0; goto useline;
return 0;
useline:
// definition to end of line // definition to end of line
*methp = p; *methp = p;
while(p < ep && *p != '\n') while(p < ep && *p != '\n')
@ -612,50 +618,56 @@ err:
nerrors++; nerrors++;
} }
static int markdepth; static Sym *markq;
static Sym *emarkq;
static void static void
marktext(Sym *s) mark1(Sym *s, Sym *parent)
{ {
Auto *a;
Prog *p;
if(s == S)
return;
markdepth++;
if(debug['v'] > 1)
Bprint(&bso, "%d marktext %s\n", markdepth, s->name);
for(a=s->autom; a; a=a->link)
mark(a->gotype);
for(p=s->text; p != P; p=p->link) {
if(p->from.sym)
mark(p->from.sym);
if(p->to.sym)
mark(p->to.sym);
}
markdepth--;
}
void
mark(Sym *s)
{
int i;
if(s == S || s->reachable) if(s == S || s->reachable)
return; return;
if(strncmp(s->name, "go.weak.", 8) == 0) if(strncmp(s->name, "go.weak.", 8) == 0)
return; return;
s->reachable = 1; s->reachable = 1;
if(s->text) s->reachparent = parent;
marktext(s); if(markq == nil)
for(i=0; i<s->nr; i++) markq = s;
mark(s->r[i].sym); else
if(s->gotype) emarkq->queue = s;
mark(s->gotype); emarkq = s;
if(s->sub) }
mark(s->sub);
if(s->outer) void
mark(s->outer); mark(Sym *s)
{
mark1(s, nil);
}
static void
markflood(void)
{
Auto *a;
Prog *p;
Sym *s;
int i;
for(s=markq; s!=S; s=s->queue) {
if(s->text) {
if(debug['v'] > 1)
Bprint(&bso, "marktext %s\n", s->name);
for(a=s->autom; a; a=a->link)
mark1(a->gotype, s);
for(p=s->text; p != P; p=p->link) {
mark1(p->from.sym, s);
mark1(p->to.sym, s);
}
}
for(i=0; i<s->nr; i++)
mark1(s->r[i].sym, s);
mark1(s->gotype, s);
mark1(s->sub, s);
mark1(s->outer, s);
}
} }
static char* static char*
@ -712,8 +724,9 @@ void
deadcode(void) deadcode(void)
{ {
int i; int i;
Sym *s, *last; Sym *s, *last, *p;
Auto *z; Auto *z;
Fmt fmt;
if(debug['v']) if(debug['v'])
Bprint(&bso, "%5.2f deadcode\n", cputime()); Bprint(&bso, "%5.2f deadcode\n", cputime());
@ -724,6 +737,8 @@ deadcode(void)
for(i=0; i<ndynexp; i++) for(i=0; i<ndynexp; i++)
mark(dynexp[i]); mark(dynexp[i]);
markflood();
// remove dead text but keep file information (z symbols). // remove dead text but keep file information (z symbols).
last = nil; last = nil;
@ -756,6 +771,29 @@ deadcode(void)
s->reachable = 1; s->reachable = 1;
s->hide = 1; s->hide = 1;
} }
// record field tracking references
fmtstrinit(&fmt);
for(s = allsym; s != S; s = s->allsym) {
if(strncmp(s->name, "go.track.", 9) == 0) {
s->special = 1; // do not lay out in data segment
s->hide = 1;
if(s->reachable) {
fmtprint(&fmt, "%s", s->name+9);
for(p=s->reachparent; p; p=p->reachparent)
fmtprint(&fmt, "\t%s", p->name);
fmtprint(&fmt, "\n");
}
s->type = SCONST;
s->value = 0;
}
}
if(tracksym == nil)
return;
s = lookup(tracksym, 0);
if(!s->reachable)
return;
addstrdata(tracksym, fmtstrflush(&fmt));
} }
void void

View File

@ -132,6 +132,7 @@ EXTERN char* thestring;
EXTERN int ndynexp; EXTERN int ndynexp;
EXTERN int havedynamic; EXTERN int havedynamic;
EXTERN int iscgo; EXTERN int iscgo;
EXTERN char* tracksym;
EXTERN Segment segtext; EXTERN Segment segtext;
EXTERN Segment segdata; EXTERN Segment segdata;