From ef40d9435b7e9631b6031f80854b1f8a6768f9de Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 20 Oct 2008 13:53:56 -0700 Subject: [PATCH] 6g: make sure methods end up immediately following the struct they are methods on. ar: eliminate duplicate definitions from __.PKGDEF. check that multiple .6 do not give different defs for same exported type/var/func/const. increase ar header name size from 16 to 64 bytes R=r DELTA=379 (333 added, 18 deleted, 28 changed) OCL=17477 CL=17481 --- include/ar.h | 2 +- src/cmd/ar/ar.c | 395 +++++++++++++++++++++++++++++++++++++++----- src/cmd/gc/export.c | 8 +- 3 files changed, 360 insertions(+), 45 deletions(-) diff --git a/include/ar.h b/include/ar.h index 529055d1419..b565ac90bf2 100644 --- a/include/ar.h +++ b/include/ar.h @@ -32,7 +32,7 @@ #define SARMAG 8 #define ARFMAG "`\n" -#define SARNAME 16 +#define SARNAME 64 struct ar_hdr { diff --git a/src/cmd/ar/ar.c b/src/cmd/ar/ar.c index 7985357b4ee..323103bcb17 100644 --- a/src/cmd/ar/ar.c +++ b/src/cmd/ar/ar.c @@ -126,8 +126,6 @@ int errors; Arfile *astart, *amiddle, *aend; /* Temp file control block pointers */ int allobj = 1; /* set when all members are object files of the same type */ int symdefsize; /* size of symdef file */ -int pkgdefsize; /* size of pkgdef data */ -char *pkgdata; /* pkgdef data */ char *pkgstmt; /* string "package foo" */ int dupfound; /* flag for duplicate symbol */ Hashchain *hash[NHASH]; /* hash table of text symbols */ @@ -143,7 +141,8 @@ void arcopy(Biobuf*, Arfile*, Armember*); int arcreate(char*); void arfree(Arfile*); void arinsert(Arfile*, Armember*); -char *armalloc(int); +void *armalloc(int); +char *arstrdup(char*); void armove(Biobuf*, Arfile*, Armember*); void arread(Biobuf*, Armember*, int); void arstream(int, Arfile*); @@ -151,8 +150,10 @@ int arwrite(int, Armember*); int bamatch(char*, char*); int duplicate(char*); Armember *getdir(Biobuf*); +void getpkgdef(char**, int*); int getspace(void); void install(char*, Arfile*, Arfile*, Arfile*, int); +void loadpkgdata(char*, int); void longt(Armember*); int match(int, char**); void mesg(int, char*); @@ -648,9 +649,7 @@ scanpkg(Biobuf *b, long size) long n; int c; long start, end, pkgsize; - char* data; - char* line; - char pkg[1024]; + char *data, *line, pkgbuf[1024], *pkg; int first; /* @@ -675,6 +674,7 @@ scanpkg(Biobuf *b, long size) return; foundstart: + pkg = nil; /* how big is it? */ first = 1; start = end = 0; @@ -683,10 +683,15 @@ foundstart: if (line == 0) goto bad; if (first && strstrn(line, Blinelen(b), "package ")) { - if (Blinelen(b) > sizeof(pkg)-1) + if (Blinelen(b) > sizeof(pkgbuf)-1) + goto bad; + memmove(pkgbuf, line, Blinelen(b)); + pkgbuf[Blinelen(b)] = '\0'; + pkg = pkgbuf; + while(*pkg == ' ' || *pkg == '\t') + pkg++; + if(strncmp(pkg, "package ", 8) != 0) goto bad; - memmove(pkg, line, Blinelen(b)); - pkg[Blinelen(b)] = '\0'; start = Boffset(b); // after package statement first = 0; continue; @@ -702,29 +707,24 @@ bad: foundend: if (start == 0 || end == 0) goto bad; - if (pkgdefsize == 0) { + if (pkgstmt == nil) { /* this is the first package */ - pkgstmt = armalloc(strlen(pkg)+1); - strcpy(pkgstmt, pkg); - pkgdefsize = 7 + 3 + strlen(pkg); /* "import\n$$\npackage foo\n" */ - pkgdata = armalloc(pkgdefsize); - sprint(pkgdata, "import\n$$\n%s", pkgstmt); + pkgstmt = arstrdup(pkg); } else { if (strcmp(pkg, pkgstmt) != 0) { fprint(2, "ar: inconsistent package name\n"); return; } } + pkgsize = end-start; - data = armalloc(pkgdefsize + pkgsize); /* should chain instead of reallocate */ - memmove(data, pkgdata, pkgdefsize); + data = armalloc(pkgsize); Bseek(b, start, 0); - if (Bread(b, data+pkgdefsize, pkgsize) != pkgsize) { + if (Bread(b, data, pkgsize) != pkgsize) { fprint(2, "ar: error reading package import section in %s\n", file); return; } - pkgdefsize += pkgsize; - pkgdata = data; + loadpkgdata(data, pkgsize); } /* @@ -740,11 +740,9 @@ objsym(Sym *s, void *p) if (s->type != 'T' && s->type != 'D') return; ap = (Arfile*)p; - as = (Arsymref*)armalloc(sizeof(Arsymref)); + as = armalloc(sizeof(Arsymref)); as->offset = ap->size; - n = strlen(s->name); - as->name = armalloc(n+1); - strcpy(as->name, s->name); + as->name = arstrdup(s->name); if(s->type == 'T' && duplicate(as->name)) { dupfound = 1; fprint(2, "duplicate text symbol: %s\n", as->name); @@ -753,6 +751,7 @@ objsym(Sym *s, void *p) return; } as->type = s->type; + n = strlen(s->name); symdefsize += 4+(n+1)+1; as->len = n; as->next = ap->sym; @@ -763,23 +762,32 @@ objsym(Sym *s, void *p) * Check the symbol table for duplicate text symbols */ int -duplicate(char *name) +hashstr(char *name) { - Hashchain *p; - char *cp; int h; + char *cp; h = 0; for(cp = name; *cp; h += *cp++) h *= 1119; if(h < 0) h = ~h; - h %= NHASH; + return h; +} + +int +duplicate(char *name) +{ + Hashchain *p; + char *cp; + int h; + + h = hashstr(name) % NHASH; for(p = hash[h]; p; p = p->next) if(strcmp(p->name, name) == 0) return 1; - p = (Hashchain*) armalloc(sizeof(Hashchain)); + p = armalloc(sizeof(Hashchain)); p->next = hash[h]; p->name = name; hash[h] = p; @@ -989,12 +997,16 @@ install(char *arname, Arfile *astart, Arfile *amiddle, Arfile *aend, int createf void rl(int fd) { - Biobuf b; char *cp; struct ar_hdr a; long len; int headlen; + char *pkgdefdata; + int pkgdefsize; + + pkgdefdata = nil; + pkgdefsize = 0; Binit(&b, fd, OWRITE); Bseek(&b,seek(fd,0,1), 0); @@ -1018,7 +1030,8 @@ rl(int fd) headlen = Boffset(&b); len += headlen; if (gflag) { - len += SAR_HDR + pkgdefsize + 3; /* +3 for "$$\n" */ + getpkgdef(&pkgdefdata, &pkgdefsize); + len += SAR_HDR + pkgdefsize; if (len & 1) len++; } @@ -1037,7 +1050,7 @@ rl(int fd) Bputc(&b, 0); if (gflag) { - len = pkgdefsize + 3; /* for "$$\n" at close */ + len = pkgdefsize; sprint(a.date, "%-12ld", time(0)); sprint(a.uid, "%-6d", 0); sprint(a.gid, "%-6d", 0); @@ -1051,9 +1064,7 @@ rl(int fd) if(HEADER_IO(Bwrite, &b, a)) wrerr(); - if (Bwrite(&b, pkgdata, pkgdefsize) != pkgdefsize) - wrerr(); - if (Bwrite(&b, "$$\n", 3) != 3) + if (Bwrite(&b, pkgdefdata, pkgdefsize) != pkgdefsize) wrerr(); if(len&0x01) Bputc(&b, 0); @@ -1242,7 +1253,7 @@ newtempfile(char *name) /* allocate a file control block */ { Arfile *ap; - ap = (Arfile *) armalloc(sizeof(Arfile)); + ap = armalloc(sizeof(Arfile)); ap->fname = name; return ap; } @@ -1250,7 +1261,7 @@ newtempfile(char *name) /* allocate a file control block */ Armember * newmember(void) /* allocate a member buffer */ { - return (Armember *)armalloc(sizeof(Armember)); + return armalloc(sizeof(Armember)); } void @@ -1368,11 +1379,11 @@ getspace(void) { fprint(2, "IN GETSPACE\n"); if (astart && astart->head && page(astart)) - return 1; + return 1; if (amiddle && amiddle->head && page(amiddle)) - return 1; + return 1; if (aend && aend->head && page(aend)) - return 1; + return 1; return 0; } @@ -1395,7 +1406,7 @@ arfree(Arfile *ap) /* free a member buffer */ * fails we try to reclaim space by spilling previously allocated * member buffers. */ -char * +void * armalloc(int n) { char *cp; @@ -1411,3 +1422,305 @@ armalloc(int n) exits("malloc"); return 0; } + +char * +arstrdup(char *s) +{ + char *t; + + t = armalloc(strlen(s) + 1); + strcpy(t, s); + return t; +} + + +/* + * package import data + */ +typedef struct Import Import; +struct Import +{ + Import *hash; // next in hash table + int export; // marked as export? + char *prefix; // "type", "var", "func", "const" + char *name; + char *def; + char *file; +}; +enum { + NIHASH = 1024 +}; +Import *ihash[NIHASH]; +int nimport; + +Import * +ilookup(char *name) +{ + int h; + Import *x; + + h = hashstr(name) % NIHASH; + for(x=ihash[h]; x; x=x->hash) + if(x->name[0] == name[0] && strcmp(x->name, name) == 0) + return x; + x = armalloc(sizeof *x); + x->name = name; + x->hash = ihash[h]; + ihash[h] = x; + nimport++; + return x; +} + +int parsemethod(char**, char*, char**); +int parsepkgdata(char**, char*, int*, char**, char**, char**); + +void +loadpkgdata(char *data, int len) +{ + int export; + char *p, *ep, *prefix, *name, *def; + Import *x; + + file = arstrdup(file); + p = data; + ep = data + len; + while(parsepkgdata(&p, ep, &export, &prefix, &name, &def) > 0) { + x = ilookup(name); + if(x->prefix == nil) { + x->prefix = prefix; + x->def = def; + x->file = file; + x->export = export; + } else { + if(strcmp(x->prefix, prefix) != 0) { + fprint(2, "ar: conflicting definitions for %s\n", name); + fprint(2, "%s:\t%s %s ...\n", x->file, x->prefix, name); + fprint(2, "%s:\t%s %s ...\n", file, prefix, name); + errors++; + } + else if(strcmp(x->def, def) != 0) { + fprint(2, "ar: conflicting definitions for %s\n", name); + fprint(2, "%s:\t%s %s %s\n", x->file, x->prefix, name, x->def); + fprint(2, "%s:\t%s %s %s\n", file, prefix, name, def); + errors++; + } + + // okay if some .6 say export and others don't. + // all it takes is one. + if(export) + x->export = 1; + } + } +} + +int +parsepkgdata(char **pp, char *ep, int *exportp, char **prefixp, char **namep, char **defp) +{ + char *p, *prefix, *name, *def, *edef, *meth; + int n; + + // skip white space + p = *pp; + while(p < ep && (*p == ' ' || *p == '\t')) + p++; + if(p == ep) + return 0; + + // [export ] + *exportp = 0; + if(p + 7 <= ep && strncmp(p, "export ", 7) == 0) { + *exportp = 1; + p += 7; + } + + // prefix: (var|type|func|const) + prefix = p; + + prefix = p; + if(p + 6 > ep) + return -1; + if(strncmp(p, "var ", 4) == 0) + p += 4; + else if(strncmp(p, "type ", 5) == 0) + p += 5; + else if(strncmp(p, "func ", 5) == 0) + p += 5; + else if(strncmp(p, "const ", 6) == 0) + p += 6; + else{ + fprint(2, "ar: confused in pkg data near <<%.20s>>\n", p); + errors++; + return -1; + } + p[-1] = '\0'; + + // name: a.b followed by space + name = p; + while(p < ep && *p != ' ') + p++; + if(p >= ep) + return -1; + *p++ = '\0'; + + // def: free form to new line + def = p; + while(p < ep && *p != '\n') + p++; + if(p >= ep) + return -1; + edef = p; + *p++ = '\0'; + + // include methods on successive lines in def of named type + while(parsemethod(&p, ep, &meth) > 0) { + *edef++ = '\n'; // overwrites '\0' + if(edef+1 > meth) { + // We want to indent methods with a single \t. + // 6g puts at least one char of indent before all method defs, + // so there will be room for the \t. If the method def wasn't + // indented we could do something more complicated, + // but for now just diagnose the problem and assume + // 6g will keep indenting for us. + fprint(2, "ar: %s: expected methods to be indented %p %p %.10s\n", file, edef, meth, meth); + errors++; + return -1; + } + *edef++ = '\t'; + n = strlen(meth); + memmove(edef, meth, n); + edef += n; + } + + // done + *pp = p; + *prefixp = prefix; + *namep = name; + *defp = def; + return 1; +} + +int +parsemethod(char **pp, char *ep, char **methp) +{ + char *p, *prefix, *name, *def; + int n; + + // skip white space + p = *pp; + while(p < ep && (*p == ' ' || *p == '\t')) + p++; + if(p == ep) + return 0; + + // if it says "func (", it's a method + if(p + 6 >= ep || strncmp(p, "func (", 6) != 0) + return 0; + + // definition to end of line + *methp = p; + while(p < ep && *p != '\n') + p++; + if(p >= ep) { + fprint(2, "ar: lost end of line in method definition\n"); + *pp = ep; + return -1; + } + *p++ = '\0'; + *pp = p; + return 1; +} + +int +importcmp(const void *va, const void *vb) +{ + Import *a, *b; + int i; + + a = *(Import**)va; + b = *(Import**)vb; + + i = strcmp(a->prefix, b->prefix); + if(i != 0) { + // rewrite so "type" comes first + if(strcmp(a->prefix, "type") == 0) + return -1; + if(strcmp(b->prefix, "type") == 0) + return 1; + return i; + } + return strcmp(a->name, b->name); +} + +char* +strappend(char *s, char *t) +{ + int n; + + n = strlen(t); + memmove(s, t, n); + return s+n; +} + +void +getpkgdef(char **datap, int *lenp) +{ + Fmt f; + int i, j, len; + char *data, *p, *ep; + Import **all, *x; + + // make a list of all the exports and count string sizes + all = armalloc(nimport*sizeof all[0]); + j = 0; + len = 7 + 3 + strlen(pkgstmt) + 1; // import\n$$\npkgstmt\n + for(i=0; ihash) { + all[j++] = x; + len += strlen(x->prefix) + 1 + + strlen(x->name) + 1 + + strlen(x->def) + 1; + if(x->export) + len += 7; + } + } + if(j != nimport) { + fprint(2, "ar: import count mismatch (internal error)\n"); + exits("oops"); + } + len += 3; // $$\n + + // sort exports (unnecessary but nicer to look at) + qsort(all, nimport, sizeof all[0], importcmp); + + // print them into buffer + data = armalloc(len); + + // import\n + // $$\n + // pkgstmt\n + p = data; + p = strappend(p, "import\n$$\n"); + p = strappend(p, pkgstmt); + p = strappend(p, "\n"); + for(i=0; iexport) + p = strappend(p, "export "); + p = strappend(p, x->prefix); + p = strappend(p, " "); + p = strappend(p, x->name); + p = strappend(p, " "); + p = strappend(p, x->def); + p = strappend(p, "\n"); + } + p = strappend(p, "$$\n"); + if(p != data+len) { + fprint(2, "ar: internal math error\n"); + exits("oops"); + } + + *datap = data; + *lenp = len; +} + diff --git a/src/cmd/gc/export.c b/src/cmd/gc/export.c index f5a9e918da8..4058d857df9 100644 --- a/src/cmd/gc/export.c +++ b/src/cmd/gc/export.c @@ -154,12 +154,14 @@ dumpsym(Sym *s) break; case LATYPE: case LBASETYPE: - dumpexporttype(s); - for(f=s->otype->method; f!=T; f=f->down) { + // TODO(rsc): sort methods by name + for(f=s->otype->method; f!=T; f=f->down) dumpprereq(f); + + dumpexporttype(s); + for(f=s->otype->method; f!=T; f=f->down) Bprint(bout, "\tfunc (%#T) %hS %#T\n", f->type->type->type, f->sym, f->type); - } break; case LNAME: dumpexportvar(s);