]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/gc, cmd/ld: struct field tracking
authorRuss Cox <rsc@golang.org>
Fri, 2 Nov 2012 04:17:21 +0000 (00:17 -0400)
committerRuss Cox <rsc@golang.org>
Fri, 2 Nov 2012 04:17:21 +0000 (00:17 -0400)
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

36 files changed:
src/cmd/5a/lex.c
src/cmd/5g/gg.h
src/cmd/5g/gsubr.c
src/cmd/5l/5.out.h
src/cmd/5l/l.h
src/cmd/5l/obj.c
src/cmd/5l/optab.c
src/cmd/5l/span.c
src/cmd/6a/lex.c
src/cmd/6g/gg.h
src/cmd/6g/gsubr.c
src/cmd/6l/6.out.h
src/cmd/6l/l.h
src/cmd/6l/obj.c
src/cmd/6l/optab.c
src/cmd/8a/lex.c
src/cmd/8g/gg.h
src/cmd/8g/gsubr.c
src/cmd/8l/8.out.h
src/cmd/8l/l.h
src/cmd/8l/obj.c
src/cmd/8l/optab.c
src/cmd/gc/dcl.c
src/cmd/gc/export.c
src/cmd/gc/go.h
src/cmd/gc/go.y
src/cmd/gc/lex.c
src/cmd/gc/pgen.c
src/cmd/gc/reflect.c
src/cmd/gc/subr.c
src/cmd/gc/typecheck.c
src/cmd/gc/walk.c
src/cmd/gc/y.tab.c
src/cmd/ld/data.c
src/cmd/ld/go.c
src/cmd/ld/lib.h

index cc02879b76f1b98e59b3b95a87dbbbd32612ac93..fbce6b771dcb8a6a3f45badd4caaebddc9ecc8da 100644 (file)
@@ -413,6 +413,8 @@ struct
        "MULAWT",       LTYPEN, AMULAWT,
        "MULAWB",       LTYPEN, AMULAWB,
 
+       "USEFIELD",     LTYPEN, AUSEFIELD,
+
        0
 };
 
index 80a5605f0c5978b6cdf862e0547971adcc3b6155..ba9356edc3ca28076295fd9ac7682cb9e6a82be0 100644 (file)
@@ -142,6 +142,7 @@ void        datagostring(Strlit*, Addr*);
 void   split64(Node*, Node*, Node*);
 void   splitclean(void);
 Node*  ncon(uint32 i);
+void   gtrack(Sym*);
 
 /*
  * obj.c
index c4961b80c6f36bcc779100431ff0b28af26021c0..0ab335e0bcb813765335d0a3d2598d4ddbd24e2c 100644 (file)
@@ -225,6 +225,17 @@ ggloblsym(Sym *s, int32 width, int dupok, int 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
 isfat(Type *t)
 {
index b9b05257015f203548fb921a7ed24c860a26582d..c9870017772b4c49f57e0cced39794ebd35ced73 100644 (file)
@@ -195,6 +195,8 @@ enum        as
        AMULWB,
        AMULAWT,
        AMULAWB,
+       
+       AUSEFIELD,
 
        ALAST,
 };
index 36bf254e4656cd4760ba96393a90dd205e0a4a35..50531bb2092b334b63812b485d8985aaa1d1a2af 100644 (file)
@@ -153,6 +153,8 @@ struct      Sym
        Sym*    sub;    // in SSUB list
        Sym*    outer;  // container of sub
        Sym*    gotype;
+       Sym*    reachparent;
+       Sym*    queue;
        char*   file;
        char*   dynimpname;
        char*   dynimplib;
index 4c2603d28a06bc88fdb26aa3200032696781087e..74ac6ecb477b181259a02b3818c599365648d304 100644 (file)
@@ -147,6 +147,9 @@ main(int argc, char *argv[])
                val = EARGF(usage());
                addbuildinfo(val);
                break;
+       case 'k':
+               tracksym = EARGF(usage());
+               break;
        } ARGEND
 
        USED(argc);
index cb29cfd685068c925ee9c22b80e57cd5420d026d..9e95c096de2cfd80f8062d3e193a96150cf54d34 100644 (file)
@@ -242,5 +242,7 @@ Optab       optab[] =
        { AMULWT,       C_REG,  C_REG,  C_REG,          98, 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 },
 };
index 7614c40185eff5d304639461e23b89e040dac36b..59c0590b4713ecbb733003a3add213d0fb7920e2 100644 (file)
@@ -812,6 +812,7 @@ buildop(void)
                case AMOVM:
                case ARFE:
                case ATEXT:
+               case AUSEFIELD:
                case ACASE:
                case ABCASE:
                        break;
index 376a4b67e534e7f4b189d4fb38fa9d89d04f940e..d65802a201803a61495f5be64ed58ddadacf3434 100644 (file)
@@ -1014,7 +1014,8 @@ struct
        "AESDECLAST",   LTYPE3, AAESDECLAST,
        "AESIMC",       LTYPE3, AAESIMC,
        "AESKEYGENASSIST", LTYPEX, AAESKEYGENASSIST,
-       "PSHUFD", LTYPEX, APSHUFD,
+       "PSHUFD",       LTYPEX, APSHUFD,
+       "USEFIELD",     LTYPEN, AUSEFIELD,
 
        0
 };
index 65ea7a4aa75d6e670d0fd64518ae1e811200b602..4045e9a2e22a00952ccfc40952711dbad4304fac 100644 (file)
@@ -125,6 +125,7 @@ void        sudoclean(void);
 int    sudoaddable(int, Node*, Addr*);
 void   afunclit(Addr*);
 void   nodfconst(Node*, Type*, Mpflt*);
+void   gtrack(Sym*);
 
 /*
  * cplx.c
index 638ba4add694a870eee74841c5ed58b3368e9b96..b7ba420da198cb2764a1b09232e3a403d70ebda3 100644 (file)
@@ -205,6 +205,17 @@ ggloblnod(Node *nam, int32 width)
                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
 ggloblsym(Sym *s, int32 width, int dupok, int rodata)
 {
index 6acc1f459edb6e6b1a40939225d50afd72e4ca6d..3946861de458a74b5591e8ef97f3cf65b80369bb 100644 (file)
@@ -756,6 +756,8 @@ enum        as
        AAESKEYGENASSIST,
 
        APSHUFD,
+       
+       AUSEFIELD,
 
        ALAST
 };
index c2ae007790adbd3224df1750f8db571c8076c5eb..91926a13a01318b2b8d7824e819cd21e0b9cdd06 100644 (file)
@@ -158,6 +158,8 @@ struct      Sym
        Sym*    next;   // in text or data list
        Sym*    sub;    // in SSUB list
        Sym*    outer;  // container of sub
+       Sym*    reachparent;
+       Sym*    queue;
        vlong   value;
        vlong   size;
        Sym*    gotype;
index dad217cc86fb476dedbacf5dff1cb79c295b938d..08db03c4a3e8ba60de114eecc2d1ce85ad670556 100644 (file)
@@ -144,6 +144,9 @@ main(int argc, char *argv[])
                val = EARGF(usage());
                addbuildinfo(val);
                break;
+       case 'k':
+               tracksym = EARGF(usage());
+               break;
        } ARGEND
 
        if(argc != 1)
index e81c1eda0130a20ff809990e78f154b4ac2c08a6..4f8406637c91089ef333918e5336aa8198c21cc3 100644 (file)
@@ -1315,6 +1315,8 @@ Optab optab[] =
 
        { APSHUFD,      yaes2,  Pq,     0x70,(0) },
 
+       { AUSEFIELD,    ynop,   Px, 0,0 },
+
        { AEND },
        0
 };
index cebaa9e5f80dfbbe3d5635cc059aabc1f9777906..25c61d75c216e599219d118fa5cb79a1fdb0b3fe 100644 (file)
@@ -781,6 +781,7 @@ struct
        "UNPCKLPS",     LTYPE3, AUNPCKLPS,
        "XORPD",        LTYPE3, AXORPD,
        "XORPS",        LTYPE3, AXORPS,
+       "USEFIELD",     LTYPEN, AUSEFIELD,
 
        0
 };
index 09718855bd898cd5ae61e8e448b5c0d811dd63ca..e1d44c2300be868c175c4ae40e49f887a025b994 100644 (file)
@@ -147,6 +147,7 @@ void        afunclit(Addr*);
 void   split64(Node*, Node*, Node*);
 void   splitclean(void);
 void   nswap(Node*, Node*);
+void   gtrack(Sym*);
 
 /*
  * cplx.c
index a94086e7c167e50514a9b1a5c498389f462d725a..c5f6c22428be5b9244b1d1e83884ecd28a1a38c8 100644 (file)
@@ -224,6 +224,17 @@ ggloblsym(Sym *s, int32 width, int dupok, int 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
 isfat(Type *t)
 {
index 27040be8bfc95af4e3298ba21317ce8797a51458..6a2d46c62ed38a583fb939d64e6b78c879295739 100644 (file)
@@ -566,6 +566,8 @@ enum        as
        AUNPCKLPS,
        AXORPD,
        AXORPS,
+       
+       AUSEFIELD,
 
        ALAST
 };
index 8cf0fde3ac703ddaf7f40b442bb352482c8ba916..96b425874dc5e47124949117bebcaefdc03296bc 100644 (file)
@@ -143,6 +143,8 @@ struct      Sym
        Sym*    sub;    // in sub list
        Sym*    outer;  // container of sub
        Sym*    gotype;
+       Sym*    reachparent;
+       Sym*    queue;
        char*   file;
        char*   dynimpname;
        char*   dynimplib;
index 19e351d998569e69b113de43379687c63e412daf..eebf9fcfe59b2fe2d98136d015954bd7101bbca6 100644 (file)
@@ -149,6 +149,9 @@ main(int argc, char *argv[])
                val = EARGF(usage());
                addbuildinfo(val);
                break;
+       case 'k':
+               tracksym = EARGF(usage());
+               break;
        } ARGEND
 
        if(argc != 1)
index de87e22ecce04aa508c9341238ef19c91b4e035f..865871ce5ce8d323b4406e6e35fd5f89d4a2886d 100644 (file)
@@ -960,5 +960,7 @@ Optab optab[] =
        { AXORPD,       yxm,    Pe, 0x57 },
        { AXORPS,       yxm,    Pm, 0x57 },
 
+       { AUSEFIELD,    ynop,   Px, 0,0 },
+
        0
 };
index f7e52777fc269b417f3adce9587f0e4e71d480a3..d20f64357b639eedae9787fb17ba0956b994e24c 100644 (file)
@@ -1269,7 +1269,7 @@ methodname1(Node *n, Node *t)
  * n is fieldname, pa is base type, t is function type
  */
 void
-addmethod(Sym *sf, Type *t, int local)
+addmethod(Sym *sf, Type *t, int local, int nointerface)
 {
        Type *f, *d, *pa;
        Node *n;
@@ -1352,6 +1352,7 @@ addmethod(Sym *sf, Type *t, int local)
        }
 
        f = structfield(n);
+       f->nointerface = nointerface;
 
        // during import unexported method names should be in the type's package
        if(importpkg && f->sym && !exportname(f->sym->name) && f->sym->pkg != structpkg)
index 7f977874a1bfedff7e59e6d146e346fec9a5fa13..7db713e4818034212c720d522c3b0206dd170ecf 100644 (file)
@@ -278,6 +278,8 @@ dumpexporttype(Type *t)
                        // currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package
                        if(debug['l'] < 2)
                                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);
                        reexportdeplist(f->type->nname->inl);
                } else
index 06f6e34f3a78c8c783f97e75dda0ffaef66efc51..22718889a7c488b38163aa885364e1bd95983c0a 100644 (file)
@@ -137,6 +137,7 @@ typedef     struct  Label   Label;
 struct Type
 {
        uchar   etype;
+       uchar   nointerface;
        uchar   chan;
        uchar   trecur;         // to detect loops
        uchar   printed;
@@ -175,6 +176,7 @@ struct      Type
 
        // TFIELD
        Type*   down;           // next struct field, also key type in TMAP
+       Type*   outer;          // outer struct
        Strlit* note;           // literal string annotation
 
        // TARRAY
@@ -185,6 +187,9 @@ struct      Type
        
        // for TFORW, where to copy the eventual value to
        NodeList        *copyto;
+       
+       // for usefield
+       Node    *lastfn;
 };
 #define        T       ((Type*)0)
 
@@ -236,6 +241,7 @@ struct      Node
        NodeList*       rlist;
 
        uchar   op;
+       uchar   nointerface;
        uchar   ullman;         // sethi/ullman number
        uchar   addable;        // type of addressability - 0 is not addressable
        uchar   trecur;         // to detect loops
@@ -284,7 +290,7 @@ struct      Node
        Node*   defn;   // ONAME: initializing assignment; OLABEL: labeled statement
        Node*   pack;   // real package for import . names
        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
        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*    weaktypepkg;    // weak references to runtime type info
 EXTERN Pkg*    unsafepkg;      // package unsafe
+EXTERN Pkg*    trackpkg;       // fake package for field tracking
 EXTERN Pkg*    phash[128];
 EXTERN int     tptr;           // either TPTR32 or TPTR64
 extern char*   runtimeimport;
@@ -929,6 +936,9 @@ EXTERN      int     typecheckok;
 EXTERN int     compiling_runtime;
 EXTERN int     compiling_wrappers;
 
+EXTERN int     nointerface;
+EXTERN int     fieldtrack_enabled;
+
 /*
  *     y.tab.c
  */
@@ -1004,7 +1014,7 @@ void      nodfconst(Node *n, Type *t, Mpflt* fval);
 /*
  *     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);
 NodeList*      checkarglist(NodeList *all, int input);
 Node*  colas(NodeList *left, NodeList *right, int32 lno);
@@ -1200,8 +1210,10 @@ void     dumptypestructs(void);
 Type*  methodfunc(Type *f, Type*);
 Node*  typename(Type *t);
 Sym*   typesym(Type *t);
+Sym*   tracksym(Type *t);
 Sym*   typesymprefix(char *prefix, Type *t);
 int    haspointers(Type *t);
+void   usefield(Node*);
 
 /*
  *     select.c
index e9dcd506e7aadc698dcbae23e7821966bdcc238e..0f2622c3b8655ca2f4f4225311fd71dd8ea9de7b 100644 (file)
@@ -1275,6 +1275,7 @@ fndcl:
                $$->nname = methodname1($$->shortname, rcvr->right);
                $$->nname->defn = $$;
                $$->nname->ntype = t;
+               $$->nname->nointerface = nointerface;
                declare($$->nname, PFUNC);
 
                funchdr($$);
@@ -1312,7 +1313,8 @@ hidden_fndcl:
                $$->type = functype($2->n, $6, $8);
 
                checkwidth($$->type);
-               addmethod($4, $$->type, 0);
+               addmethod($4, $$->type, 0, nointerface);
+               nointerface = 0;
                funchdr($$);
                
                // 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);
                if(nsyntaxerrors == 0)
                        testdclstack();
+               nointerface = 0;
        }
 
 vardcl_list:
index 920de6f6351cc95e7fd1e8d2742de9477ca6b48d..d31395c1d0c3e10755d61125e12f443113a590f2 100644 (file)
@@ -40,6 +40,7 @@ static struct {
        int *val;
 } exper[] = {
 //     {"rune32", &rune32},
+       {"fieldtrack", &fieldtrack_enabled},
        {nil, nil},
 };
 
@@ -199,9 +200,19 @@ main(int argc, char *argv[])
 
        localpkg = mkpkg(strlit(""));
        localpkg->prefix = "\"\"";
-
+       
+       // pseudo-package, for scoping
        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->name = "go.string";
        gostringpkg->prefix = "go.string";      // not go%2estring
@@ -210,18 +221,16 @@ main(int argc, char *argv[])
        itabpkg->name = "go.itab";
        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->name = "go.weak.type";
        weaktypepkg->prefix = "go.weak.type";  // not go%2eweak%2etype
 
-       unsafepkg = mkpkg(strlit("unsafe"));
-       unsafepkg->name = "unsafe";
+       trackpkg = mkpkg(strlit("go.track"));
+       trackpkg->name = "go.track";
+       trackpkg->prefix = "go.track";  // not go%2etrack
+
+       typepkg = mkpkg(strlit("type"));
+       typepkg->name = "type";
 
        goroot = getgoroot();
        goos = getgoos();
@@ -1443,7 +1452,12 @@ getlinepragma(void)
        char *cp, *ep, *linep;
        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();
                if(c != "line "[i])
                        goto out;
@@ -1491,6 +1505,20 @@ getlinepragma(void)
                }
        }
        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:
        return c;
index 46b763bf0900814ecd86b55a610f10174716bbd1..7be254fff173e2cab585e14164cf591afb706620 100644 (file)
@@ -83,6 +83,10 @@ compile(Node *fn)
        afunclit(&ptxt->from);
 
        ginit();
+
+       for(t=curfn->paramfld; t; t=t->down)
+               gtrack(tracksym(t->type));
+
        genlist(curfn->enter);
 
        retpc = nil;
@@ -115,6 +119,7 @@ compile(Node *fn)
        gclean();
        if(nerrors != 0)
                goto ret;
+
        pc->as = ARET;  // overwrite AEND
        pc->lineno = lineno;
 
index 8e4f0a4d276d124146b2604fcad61fd3c551fea8..00d6f5fe76bd340013f449528fd1486d862a0618 100644 (file)
@@ -172,6 +172,8 @@ methods(Type *t)
                        fatal("non-method on %T method %S %T\n", mt, f->sym, f);
                if (!getthisx(f->type)->type)
                        fatal("receiver with no type on %T method %S %T\n", mt, f->sym, f);
+               if(f->nointerface)
+                       continue;
 
                method = f->sym;
                if(method == nil)
@@ -622,6 +624,18 @@ typesym(Type *t)
        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*
 typesymprefix(char *prefix, Type *t)
 {
@@ -1155,4 +1169,3 @@ dgcsym(Type *t)
 
        return s;
 }
-
index 8409a442a0927df28e3de2c474447eb569f85fa0..142921153db3f93f51237495455e666daea8a5f5 100644 (file)
@@ -3040,7 +3040,7 @@ implements(Type *t, Type *iface, Type **m, Type **samename, int *ptr)
        for(im=iface->type; im; im=im->down) {
                imtype = methodfunc(im->type, 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)
                                tm = ifacelookdot(im->sym, t, &followptr, 1);
                        *m = im;
index 6f3449eec3cb34a4a5d294cba7dcfbd4a7ee884a..b109d3a119696285afa96f9bf06ed524ee6cea28 100644 (file)
@@ -1833,6 +1833,7 @@ lookdot(Node *n, Type *t, int dostrcmp)
                        fatal("lookdot badwidth %T %p", f1, f1);
                n->xoffset = f1->width;
                n->type = f1->type;
+               n->paramfld = f1;
                if(t->etype == TINTER) {
                        if(isptr[n->left->type->etype]) {
                                n->left = nod(OIND, n->left, N);        // implicitstar
@@ -2637,7 +2638,7 @@ typecheckfunc(Node *n)
        t->nname = n->nname;
        rcvr = getthisx(t)->type;
        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
index 9e6d57c860a9eadc0205f69a3e9d9bad907d0ba8..11c9c2f4352d907be5aed89efd6d23900aaba94f 100644 (file)
@@ -429,14 +429,19 @@ walkexpr(Node **np, NodeList **init)
        case OCOM:
        case OREAL:
        case OIMAG:
-       case ODOT:
-       case ODOTPTR:
        case ODOTMETH:
        case ODOTINTER:
        case OIND:
                walkexpr(&n->left, init);
                goto ret;
 
+       case ODOT:
+       case ODOTPTR:
+               usefield(n);
+               walkexpr(&n->left, init);
+               goto ret;
+               
+
        case OEFACE:
                walkexpr(&n->left, init);
                walkexpr(&n->right, init);
@@ -2897,3 +2902,44 @@ bounded(Node *n, int64 max)
        
        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;
+}
+
index 478b4634869e0a0e394fb987d2b1eaa9b1758041..b2ed8302eebcc2d30ba50e6d7847acb939159911 100644 (file)
@@ -674,21 +674,21 @@ static const yytype_uint16 yyrline[] =
     1098,  1099,  1100,  1101,  1107,  1108,  1111,  1114,  1115,  1116,
     1117,  1118,  1121,  1122,  1135,  1139,  1144,  1149,  1154,  1158,
     1159,  1162,  1168,  1175,  1181,  1188,  1194,  1205,  1216,  1245,
-    1284,  1309,  1326,  1335,  1338,  1346,  1350,  1354,  1361,  1367,
-    1372,  1384,  1387,  1395,  1396,  1402,  1403,  1409,  1413,  1419,
-    1420,  1426,  1430,  1436,  1459,  1464,  1470,  1476,  1483,  1492,
-    1501,  1516,  1522,  1527,  1531,  1538,  1551,  1552,  1558,  1564,
-    1567,  1571,  1577,  1580,  1589,  1592,  1593,  1597,  1598,  1604,
-    1605,  1606,  1607,  1608,  1610,  1609,  1624,  1629,  1633,  1637,
-    1641,  1645,  1650,  1669,  1675,  1683,  1687,  1693,  1697,  1703,
-    1707,  1713,  1717,  1726,  1730,  1734,  1738,  1744,  1747,  1755,
-    1756,  1758,  1759,  1762,  1765,  1768,  1771,  1774,  1777,  1780,
-    1783,  1786,  1789,  1792,  1795,  1798,  1801,  1807,  1811,  1815,
-    1819,  1823,  1827,  1847,  1854,  1865,  1866,  1867,  1870,  1871,
-    1874,  1878,  1888,  1892,  1896,  1900,  1904,  1908,  1912,  1918,
-    1924,  1932,  1940,  1946,  1953,  1969,  1987,  1991,  1997,  2000,
-    2003,  2007,  2017,  2021,  2036,  2044,  2045,  2057,  2058,  2061,
-    2065,  2071,  2075,  2081,  2085
+    1285,  1310,  1328,  1337,  1340,  1348,  1352,  1356,  1363,  1369,
+    1374,  1386,  1389,  1398,  1399,  1405,  1406,  1412,  1416,  1422,
+    1423,  1429,  1433,  1439,  1462,  1467,  1473,  1479,  1486,  1495,
+    1504,  1519,  1525,  1530,  1534,  1541,  1554,  1555,  1561,  1567,
+    1570,  1574,  1580,  1583,  1592,  1595,  1596,  1600,  1601,  1607,
+    1608,  1609,  1610,  1611,  1613,  1612,  1627,  1632,  1636,  1640,
+    1644,  1648,  1653,  1672,  1678,  1686,  1690,  1696,  1700,  1706,
+    1710,  1716,  1720,  1729,  1733,  1737,  1741,  1747,  1750,  1758,
+    1759,  1761,  1762,  1765,  1768,  1771,  1774,  1777,  1780,  1783,
+    1786,  1789,  1792,  1795,  1798,  1801,  1804,  1810,  1814,  1818,
+    1822,  1826,  1830,  1850,  1857,  1868,  1869,  1870,  1873,  1874,
+    1877,  1881,  1891,  1895,  1899,  1903,  1907,  1911,  1915,  1921,
+    1927,  1935,  1943,  1949,  1956,  1972,  1990,  1994,  2000,  2003,
+    2006,  2010,  2020,  2024,  2039,  2047,  2048,  2060,  2061,  2064,
+    2068,  2074,  2078,  2084,  2088
 };
 #endif
 
@@ -3731,6 +3731,7 @@ yyreduce:
                (yyval.node)->nname = methodname1((yyval.node)->shortname, rcvr->right);
                (yyval.node)->nname->defn = (yyval.node);
                (yyval.node)->nname->ntype = t;
+               (yyval.node)->nname->nointerface = nointerface;
                declare((yyval.node)->nname, PFUNC);
 
                funchdr((yyval.node));
@@ -3738,7 +3739,7 @@ yyreduce:
     break;
 
   case 200:
-#line 1285 "go.y"
+#line 1286 "go.y"
     {
                Sym *s;
                Type *t;
@@ -3766,13 +3767,14 @@ yyreduce:
     break;
 
   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)->type = functype((yyvsp[(2) - (8)].list)->n, (yyvsp[(6) - (8)].list), (yyvsp[(8) - (8)].list));
 
                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));
                
                // inl.c's inlnode in on a dotmeth node expects to find the inlineable body as
@@ -3784,7 +3786,7 @@ yyreduce:
     break;
 
   case 202:
-#line 1327 "go.y"
+#line 1329 "go.y"
     {
                (yyvsp[(3) - (5)].list) = checkarglist((yyvsp[(3) - (5)].list), 1);
                (yyval.node) = nod(OTFUNC, N, N);
@@ -3794,14 +3796,14 @@ yyreduce:
     break;
 
   case 203:
-#line 1335 "go.y"
+#line 1337 "go.y"
     {
                (yyval.list) = nil;
        }
     break;
 
   case 204:
-#line 1339 "go.y"
+#line 1341 "go.y"
     {
                (yyval.list) = (yyvsp[(2) - (3)].list);
                if((yyval.list) == nil)
@@ -3810,21 +3812,21 @@ yyreduce:
     break;
 
   case 205:
-#line 1347 "go.y"
+#line 1349 "go.y"
     {
                (yyval.list) = nil;
        }
     break;
 
   case 206:
-#line 1351 "go.y"
+#line 1353 "go.y"
     {
                (yyval.list) = list1(nod(ODCLFIELD, N, (yyvsp[(1) - (1)].node)));
        }
     break;
 
   case 207:
-#line 1355 "go.y"
+#line 1357 "go.y"
     {
                (yyvsp[(2) - (3)].list) = checkarglist((yyvsp[(2) - (3)].list), 0);
                (yyval.list) = (yyvsp[(2) - (3)].list);
@@ -3832,14 +3834,14 @@ yyreduce:
     break;
 
   case 208:
-#line 1362 "go.y"
+#line 1364 "go.y"
     {
                closurehdr((yyvsp[(1) - (1)].node));
        }
     break;
 
   case 209:
-#line 1368 "go.y"
+#line 1370 "go.y"
     {
                (yyval.node) = closurebody((yyvsp[(3) - (4)].list));
                fixlbrace((yyvsp[(2) - (4)].i));
@@ -3847,79 +3849,80 @@ yyreduce:
     break;
 
   case 210:
-#line 1373 "go.y"
+#line 1375 "go.y"
     {
                (yyval.node) = closurebody(nil);
        }
     break;
 
   case 211:
-#line 1384 "go.y"
+#line 1386 "go.y"
     {
                (yyval.list) = nil;
        }
     break;
 
   case 212:
-#line 1388 "go.y"
+#line 1390 "go.y"
     {
                (yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(2) - (3)].list));
                if(nsyntaxerrors == 0)
                        testdclstack();
+               nointerface = 0;
        }
     break;
 
   case 214:
-#line 1397 "go.y"
+#line 1400 "go.y"
     {
                (yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list));
        }
     break;
 
   case 216:
-#line 1404 "go.y"
+#line 1407 "go.y"
     {
                (yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list));
        }
     break;
 
   case 217:
-#line 1410 "go.y"
+#line 1413 "go.y"
     {
                (yyval.list) = list1((yyvsp[(1) - (1)].node));
        }
     break;
 
   case 218:
-#line 1414 "go.y"
+#line 1417 "go.y"
     {
                (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
        }
     break;
 
   case 220:
-#line 1421 "go.y"
+#line 1424 "go.y"
     {
                (yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list));
        }
     break;
 
   case 221:
-#line 1427 "go.y"
+#line 1430 "go.y"
     {
                (yyval.list) = list1((yyvsp[(1) - (1)].node));
        }
     break;
 
   case 222:
-#line 1431 "go.y"
+#line 1434 "go.y"
     {
                (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
        }
     break;
 
   case 223:
-#line 1437 "go.y"
+#line 1440 "go.y"
     {
                NodeList *l;
 
@@ -3945,7 +3948,7 @@ yyreduce:
     break;
 
   case 224:
-#line 1460 "go.y"
+#line 1463 "go.y"
     {
                (yyvsp[(1) - (2)].node)->val = (yyvsp[(2) - (2)].val);
                (yyval.list) = list1((yyvsp[(1) - (2)].node));
@@ -3953,7 +3956,7 @@ yyreduce:
     break;
 
   case 225:
-#line 1465 "go.y"
+#line 1468 "go.y"
     {
                (yyvsp[(2) - (4)].node)->val = (yyvsp[(4) - (4)].val);
                (yyval.list) = list1((yyvsp[(2) - (4)].node));
@@ -3962,7 +3965,7 @@ yyreduce:
     break;
 
   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)->val = (yyvsp[(3) - (3)].val);
@@ -3971,7 +3974,7 @@ yyreduce:
     break;
 
   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)->val = (yyvsp[(5) - (5)].val);
@@ -3981,7 +3984,7 @@ yyreduce:
     break;
 
   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)->val = (yyvsp[(5) - (5)].val);
@@ -3991,7 +3994,7 @@ yyreduce:
     break;
 
   case 229:
-#line 1493 "go.y"
+#line 1496 "go.y"
     {
                Node *n;
 
@@ -4003,7 +4006,7 @@ yyreduce:
     break;
 
   case 230:
-#line 1502 "go.y"
+#line 1505 "go.y"
     {
                Pkg *pkg;
 
@@ -4019,14 +4022,14 @@ yyreduce:
     break;
 
   case 231:
-#line 1517 "go.y"
+#line 1520 "go.y"
     {
                (yyval.node) = embedded((yyvsp[(1) - (1)].sym));
        }
     break;
 
   case 232:
-#line 1523 "go.y"
+#line 1526 "go.y"
     {
                (yyval.node) = nod(ODCLFIELD, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node));
                ifacedcl((yyval.node));
@@ -4034,14 +4037,14 @@ yyreduce:
     break;
 
   case 233:
-#line 1528 "go.y"
+#line 1531 "go.y"
     {
                (yyval.node) = nod(ODCLFIELD, N, oldname((yyvsp[(1) - (1)].sym)));
        }
     break;
 
   case 234:
-#line 1532 "go.y"
+#line 1535 "go.y"
     {
                (yyval.node) = nod(ODCLFIELD, N, oldname((yyvsp[(2) - (3)].sym)));
                yyerror("cannot parenthesize embedded type");
@@ -4049,7 +4052,7 @@ yyreduce:
     break;
 
   case 235:
-#line 1539 "go.y"
+#line 1542 "go.y"
     {
                // without func keyword
                (yyvsp[(2) - (4)].list) = checkarglist((yyvsp[(2) - (4)].list), 1);
@@ -4060,7 +4063,7 @@ yyreduce:
     break;
 
   case 237:
-#line 1553 "go.y"
+#line 1556 "go.y"
     {
                (yyval.node) = nod(ONONAME, N, N);
                (yyval.node)->sym = (yyvsp[(1) - (2)].sym);
@@ -4069,7 +4072,7 @@ yyreduce:
     break;
 
   case 238:
-#line 1559 "go.y"
+#line 1562 "go.y"
     {
                (yyval.node) = nod(ONONAME, N, N);
                (yyval.node)->sym = (yyvsp[(1) - (2)].sym);
@@ -4078,56 +4081,56 @@ yyreduce:
     break;
 
   case 240:
-#line 1568 "go.y"
+#line 1571 "go.y"
     {
                (yyval.list) = list1((yyvsp[(1) - (1)].node));
        }
     break;
 
   case 241:
-#line 1572 "go.y"
+#line 1575 "go.y"
     {
                (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
        }
     break;
 
   case 242:
-#line 1577 "go.y"
+#line 1580 "go.y"
     {
                (yyval.list) = nil;
        }
     break;
 
   case 243:
-#line 1581 "go.y"
+#line 1584 "go.y"
     {
                (yyval.list) = (yyvsp[(1) - (2)].list);
        }
     break;
 
   case 244:
-#line 1589 "go.y"
+#line 1592 "go.y"
     {
                (yyval.node) = N;
        }
     break;
 
   case 246:
-#line 1594 "go.y"
+#line 1597 "go.y"
     {
                (yyval.node) = liststmt((yyvsp[(1) - (1)].list));
        }
     break;
 
   case 248:
-#line 1599 "go.y"
+#line 1602 "go.y"
     {
                (yyval.node) = N;
        }
     break;
 
   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)->sym = dclstack;  // context, for goto restrictions
@@ -4135,7 +4138,7 @@ yyreduce:
     break;
 
   case 255:
-#line 1615 "go.y"
+#line 1618 "go.y"
     {
                NodeList *l;
 
@@ -4148,7 +4151,7 @@ yyreduce:
     break;
 
   case 256:
-#line 1625 "go.y"
+#line 1628 "go.y"
     {
                // will be converted to OFALL
                (yyval.node) = nod(OXFALL, N, N);
@@ -4156,35 +4159,35 @@ yyreduce:
     break;
 
   case 257:
-#line 1630 "go.y"
+#line 1633 "go.y"
     {
                (yyval.node) = nod(OBREAK, (yyvsp[(2) - (2)].node), N);
        }
     break;
 
   case 258:
-#line 1634 "go.y"
+#line 1637 "go.y"
     {
                (yyval.node) = nod(OCONTINUE, (yyvsp[(2) - (2)].node), N);
        }
     break;
 
   case 259:
-#line 1638 "go.y"
+#line 1641 "go.y"
     {
                (yyval.node) = nod(OPROC, (yyvsp[(2) - (2)].node), N);
        }
     break;
 
   case 260:
-#line 1642 "go.y"
+#line 1645 "go.y"
     {
                (yyval.node) = nod(ODEFER, (yyvsp[(2) - (2)].node), N);
        }
     break;
 
   case 261:
-#line 1646 "go.y"
+#line 1649 "go.y"
     {
                (yyval.node) = nod(OGOTO, (yyvsp[(2) - (2)].node), N);
                (yyval.node)->sym = dclstack;  // context, for goto restrictions
@@ -4192,7 +4195,7 @@ yyreduce:
     break;
 
   case 262:
-#line 1651 "go.y"
+#line 1654 "go.y"
     {
                (yyval.node) = nod(ORETURN, N, N);
                (yyval.node)->list = (yyvsp[(2) - (2)].list);
@@ -4212,7 +4215,7 @@ yyreduce:
     break;
 
   case 263:
-#line 1670 "go.y"
+#line 1673 "go.y"
     {
                (yyval.list) = nil;
                if((yyvsp[(1) - (1)].node) != N)
@@ -4221,7 +4224,7 @@ yyreduce:
     break;
 
   case 264:
-#line 1676 "go.y"
+#line 1679 "go.y"
     {
                (yyval.list) = (yyvsp[(1) - (3)].list);
                if((yyvsp[(3) - (3)].node) != N)
@@ -4230,189 +4233,189 @@ yyreduce:
     break;
 
   case 265:
-#line 1684 "go.y"
+#line 1687 "go.y"
     {
                (yyval.list) = list1((yyvsp[(1) - (1)].node));
        }
     break;
 
   case 266:
-#line 1688 "go.y"
+#line 1691 "go.y"
     {
                (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
        }
     break;
 
   case 267:
-#line 1694 "go.y"
+#line 1697 "go.y"
     {
                (yyval.list) = list1((yyvsp[(1) - (1)].node));
        }
     break;
 
   case 268:
-#line 1698 "go.y"
+#line 1701 "go.y"
     {
                (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
        }
     break;
 
   case 269:
-#line 1704 "go.y"
+#line 1707 "go.y"
     {
                (yyval.list) = list1((yyvsp[(1) - (1)].node));
        }
     break;
 
   case 270:
-#line 1708 "go.y"
+#line 1711 "go.y"
     {
                (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
        }
     break;
 
   case 271:
-#line 1714 "go.y"
+#line 1717 "go.y"
     {
                (yyval.list) = list1((yyvsp[(1) - (1)].node));
        }
     break;
 
   case 272:
-#line 1718 "go.y"
+#line 1721 "go.y"
     {
                (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
        }
     break;
 
   case 273:
-#line 1727 "go.y"
+#line 1730 "go.y"
     {
                (yyval.list) = list1((yyvsp[(1) - (1)].node));
        }
     break;
 
   case 274:
-#line 1731 "go.y"
+#line 1734 "go.y"
     {
                (yyval.list) = list1((yyvsp[(1) - (1)].node));
        }
     break;
 
   case 275:
-#line 1735 "go.y"
+#line 1738 "go.y"
     {
                (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
        }
     break;
 
   case 276:
-#line 1739 "go.y"
+#line 1742 "go.y"
     {
                (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
        }
     break;
 
   case 277:
-#line 1744 "go.y"
+#line 1747 "go.y"
     {
                (yyval.list) = nil;
        }
     break;
 
   case 278:
-#line 1748 "go.y"
+#line 1751 "go.y"
     {
                (yyval.list) = (yyvsp[(1) - (2)].list);
        }
     break;
 
   case 283:
-#line 1762 "go.y"
+#line 1765 "go.y"
     {
                (yyval.node) = N;
        }
     break;
 
   case 285:
-#line 1768 "go.y"
+#line 1771 "go.y"
     {
                (yyval.list) = nil;
        }
     break;
 
   case 287:
-#line 1774 "go.y"
+#line 1777 "go.y"
     {
                (yyval.node) = N;
        }
     break;
 
   case 289:
-#line 1780 "go.y"
+#line 1783 "go.y"
     {
                (yyval.list) = nil;
        }
     break;
 
   case 291:
-#line 1786 "go.y"
+#line 1789 "go.y"
     {
                (yyval.list) = nil;
        }
     break;
 
   case 293:
-#line 1792 "go.y"
+#line 1795 "go.y"
     {
                (yyval.list) = nil;
        }
     break;
 
   case 295:
-#line 1798 "go.y"
+#line 1801 "go.y"
     {
                (yyval.val).ctype = CTxxx;
        }
     break;
 
   case 297:
-#line 1808 "go.y"
+#line 1811 "go.y"
     {
                importimport((yyvsp[(2) - (4)].sym), (yyvsp[(3) - (4)].val).u.sval);
        }
     break;
 
   case 298:
-#line 1812 "go.y"
+#line 1815 "go.y"
     {
                importvar((yyvsp[(2) - (4)].sym), (yyvsp[(3) - (4)].type));
        }
     break;
 
   case 299:
-#line 1816 "go.y"
+#line 1819 "go.y"
     {
                importconst((yyvsp[(2) - (5)].sym), types[TIDEAL], (yyvsp[(4) - (5)].node));
        }
     break;
 
   case 300:
-#line 1820 "go.y"
+#line 1823 "go.y"
     {
                importconst((yyvsp[(2) - (6)].sym), (yyvsp[(3) - (6)].type), (yyvsp[(5) - (6)].node));
        }
     break;
 
   case 301:
-#line 1824 "go.y"
+#line 1827 "go.y"
     {
                importtype((yyvsp[(2) - (4)].type), (yyvsp[(3) - (4)].type));
        }
     break;
 
   case 302:
-#line 1828 "go.y"
+#line 1831 "go.y"
     {
                if((yyvsp[(2) - (4)].node) == N) {
                        dclcontext = PEXTERN;  // since we skip the funcbody below
@@ -4433,7 +4436,7 @@ yyreduce:
     break;
 
   case 303:
-#line 1848 "go.y"
+#line 1851 "go.y"
     {
                (yyval.sym) = (yyvsp[(1) - (1)].sym);
                structpkg = (yyval.sym)->pkg;
@@ -4441,7 +4444,7 @@ yyreduce:
     break;
 
   case 304:
-#line 1855 "go.y"
+#line 1858 "go.y"
     {
                (yyval.type) = pkgtype((yyvsp[(1) - (1)].sym));
                importsym((yyvsp[(1) - (1)].sym), OTYPE);
@@ -4449,14 +4452,14 @@ yyreduce:
     break;
 
   case 310:
-#line 1875 "go.y"
+#line 1878 "go.y"
     {
                (yyval.type) = pkgtype((yyvsp[(1) - (1)].sym));
        }
     break;
 
   case 311:
-#line 1879 "go.y"
+#line 1882 "go.y"
     {
                // predefined name like uint8
                (yyvsp[(1) - (1)].sym) = pkglookup((yyvsp[(1) - (1)].sym)->name, builtinpkg);
@@ -4469,49 +4472,49 @@ yyreduce:
     break;
 
   case 312:
-#line 1889 "go.y"
+#line 1892 "go.y"
     {
                (yyval.type) = aindex(N, (yyvsp[(3) - (3)].type));
        }
     break;
 
   case 313:
-#line 1893 "go.y"
+#line 1896 "go.y"
     {
                (yyval.type) = aindex(nodlit((yyvsp[(2) - (4)].val)), (yyvsp[(4) - (4)].type));
        }
     break;
 
   case 314:
-#line 1897 "go.y"
+#line 1900 "go.y"
     {
                (yyval.type) = maptype((yyvsp[(3) - (5)].type), (yyvsp[(5) - (5)].type));
        }
     break;
 
   case 315:
-#line 1901 "go.y"
+#line 1904 "go.y"
     {
                (yyval.type) = tostruct((yyvsp[(3) - (4)].list));
        }
     break;
 
   case 316:
-#line 1905 "go.y"
+#line 1908 "go.y"
     {
                (yyval.type) = tointerface((yyvsp[(3) - (4)].list));
        }
     break;
 
   case 317:
-#line 1909 "go.y"
+#line 1912 "go.y"
     {
                (yyval.type) = ptrto((yyvsp[(2) - (2)].type));
        }
     break;
 
   case 318:
-#line 1913 "go.y"
+#line 1916 "go.y"
     {
                (yyval.type) = typ(TCHAN);
                (yyval.type)->type = (yyvsp[(2) - (2)].type);
@@ -4520,7 +4523,7 @@ yyreduce:
     break;
 
   case 319:
-#line 1919 "go.y"
+#line 1922 "go.y"
     {
                (yyval.type) = typ(TCHAN);
                (yyval.type)->type = (yyvsp[(3) - (4)].type);
@@ -4529,7 +4532,7 @@ yyreduce:
     break;
 
   case 320:
-#line 1925 "go.y"
+#line 1928 "go.y"
     {
                (yyval.type) = typ(TCHAN);
                (yyval.type)->type = (yyvsp[(3) - (3)].type);
@@ -4538,7 +4541,7 @@ yyreduce:
     break;
 
   case 321:
-#line 1933 "go.y"
+#line 1936 "go.y"
     {
                (yyval.type) = typ(TCHAN);
                (yyval.type)->type = (yyvsp[(3) - (3)].type);
@@ -4547,14 +4550,14 @@ yyreduce:
     break;
 
   case 322:
-#line 1941 "go.y"
+#line 1944 "go.y"
     {
                (yyval.type) = functype(nil, (yyvsp[(3) - (5)].list), (yyvsp[(5) - (5)].list));
        }
     break;
 
   case 323:
-#line 1947 "go.y"
+#line 1950 "go.y"
     {
                (yyval.node) = nod(ODCLFIELD, N, typenod((yyvsp[(2) - (3)].type)));
                if((yyvsp[(1) - (3)].sym))
@@ -4564,7 +4567,7 @@ yyreduce:
     break;
 
   case 324:
-#line 1954 "go.y"
+#line 1957 "go.y"
     {
                Type *t;
        
@@ -4581,7 +4584,7 @@ yyreduce:
     break;
 
   case 325:
-#line 1970 "go.y"
+#line 1973 "go.y"
     {
                Sym *s;
 
@@ -4600,49 +4603,49 @@ yyreduce:
     break;
 
   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))));
        }
     break;
 
   case 327:
-#line 1992 "go.y"
+#line 1995 "go.y"
     {
                (yyval.node) = nod(ODCLFIELD, N, typenod((yyvsp[(1) - (1)].type)));
        }
     break;
 
   case 328:
-#line 1997 "go.y"
+#line 2000 "go.y"
     {
                (yyval.list) = nil;
        }
     break;
 
   case 330:
-#line 2004 "go.y"
+#line 2007 "go.y"
     {
                (yyval.list) = (yyvsp[(2) - (3)].list);
        }
     break;
 
   case 331:
-#line 2008 "go.y"
+#line 2011 "go.y"
     {
                (yyval.list) = list1(nod(ODCLFIELD, N, typenod((yyvsp[(1) - (1)].type))));
        }
     break;
 
   case 332:
-#line 2018 "go.y"
+#line 2021 "go.y"
     {
                (yyval.node) = nodlit((yyvsp[(1) - (1)].val));
        }
     break;
 
   case 333:
-#line 2022 "go.y"
+#line 2025 "go.y"
     {
                (yyval.node) = nodlit((yyvsp[(2) - (2)].val));
                switch((yyval.node)->val.ctype){
@@ -4660,7 +4663,7 @@ yyreduce:
     break;
 
   case 334:
-#line 2037 "go.y"
+#line 2040 "go.y"
     {
                (yyval.node) = oldname(pkglookup((yyvsp[(1) - (1)].sym)->name, builtinpkg));
                if((yyval.node)->op != OLITERAL)
@@ -4669,7 +4672,7 @@ yyreduce:
     break;
 
   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) {
                        (yyval.node) = (yyvsp[(2) - (5)].node);
@@ -4683,42 +4686,42 @@ yyreduce:
     break;
 
   case 339:
-#line 2062 "go.y"
+#line 2065 "go.y"
     {
                (yyval.list) = list1((yyvsp[(1) - (1)].node));
        }
     break;
 
   case 340:
-#line 2066 "go.y"
+#line 2069 "go.y"
     {
                (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
        }
     break;
 
   case 341:
-#line 2072 "go.y"
+#line 2075 "go.y"
     {
                (yyval.list) = list1((yyvsp[(1) - (1)].node));
        }
     break;
 
   case 342:
-#line 2076 "go.y"
+#line 2079 "go.y"
     {
                (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
        }
     break;
 
   case 343:
-#line 2082 "go.y"
+#line 2085 "go.y"
     {
                (yyval.list) = list1((yyvsp[(1) - (1)].node));
        }
     break;
 
   case 344:
-#line 2086 "go.y"
+#line 2089 "go.y"
     {
                (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
        }
@@ -4726,7 +4729,7 @@ yyreduce:
 
 
 /* Line 1267 of yacc.c.  */
-#line 4731 "y.tab.c"
+#line 4734 "y.tab.c"
       default: break;
     }
   YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
@@ -4940,7 +4943,7 @@ yyreturn:
 }
 
 
-#line 2090 "go.y"
+#line 2093 "go.y"
 
 
 static void
index e551f72903049a8401b3548b72f13059298f5230..8fe1773047b19d8d0543dcfbad62b7bf5b81a239 100644 (file)
@@ -602,11 +602,15 @@ addstrdata(char *name, char *value)
        addstring(sp, value);
 
        s = lookup(name, 0);
+       s->size = 0;
        s->dupok = 1;
        addaddr(s, sp);
        adduint32(s, strlen(value));
        if(PtrSize == 8)
                adduint32(s, 0);  // round struct to pointer width
+
+       // in case reachability has already been computed
+       sp->reachable = s->reachable;
 }
 
 vlong
index aebb225b01f56df646ec14bf2f132c6dc081d6c2..81ae71d73627a5be78ae107af538ad1c75d6db97 100644 (file)
@@ -431,10 +431,16 @@ parsemethod(char **pp, char *ep, char **methp)
        if(p == ep)
                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(p + 6 >= ep || strncmp(p, "func (", 6) != 0)
-               return 0;
+       if(p + 6 < ep && strncmp(p, "func (", 6) == 0)
+               goto useline;
+       return 0;
 
+useline:
        // definition to end of line
        *methp = p;
        while(p < ep && *p != '\n')
@@ -612,50 +618,56 @@ err:
        nerrors++;
 }
 
-static int markdepth;
+static Sym *markq;
+static Sym *emarkq;
 
 static void
-marktext(Sym *s)
+mark1(Sym *s, Sym *parent)
 {
-       Auto *a;
-       Prog *p;
-
-       if(s == S)
+       if(s == S || s->reachable)
                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--;
+       if(strncmp(s->name, "go.weak.", 8) == 0)
+               return;
+       s->reachable = 1;
+       s->reachparent = parent;
+       if(markq == nil)
+               markq = s;
+       else
+               emarkq->queue = s;
+       emarkq = s;
 }
 
 void
 mark(Sym *s)
 {
-       int i;
+       mark1(s, nil);
+}
 
-       if(s == S || s->reachable)
-               return;
-       if(strncmp(s->name, "go.weak.", 8) == 0)
-               return;
-       s->reachable = 1;
-       if(s->text)
-               marktext(s);
-       for(i=0; i<s->nr; i++)
-               mark(s->r[i].sym);
-       if(s->gotype)
-               mark(s->gotype);
-       if(s->sub)
-               mark(s->sub);
-       if(s->outer)
-               mark(s->outer);
+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*
@@ -712,8 +724,9 @@ void
 deadcode(void)
 {
        int i;
-       Sym *s, *last;
+       Sym *s, *last, *p;
        Auto *z;
+       Fmt fmt;
 
        if(debug['v'])
                Bprint(&bso, "%5.2f deadcode\n", cputime());
@@ -724,6 +737,8 @@ deadcode(void)
 
        for(i=0; i<ndynexp; i++)
                mark(dynexp[i]);
+
+       markflood();
        
        // remove dead text but keep file information (z symbols).
        last = nil;
@@ -756,6 +771,29 @@ deadcode(void)
                        s->reachable = 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
index 162e16180f10e0d15d8f68060eb2258051b895a7..c2bac601023bf4601498f7104583bc80848792d8 100644 (file)
@@ -132,6 +132,7 @@ EXTERN      char*   thestring;
 EXTERN int     ndynexp;
 EXTERN int     havedynamic;
 EXTERN int     iscgo;
+EXTERN char*   tracksym;
 
 EXTERN Segment segtext;
 EXTERN Segment segdata;