mirror of
https://github.com/golang/go
synced 2024-11-24 08:10:09 -07:00
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
This commit is contained in:
parent
03a9872fe3
commit
ef40d9435b
@ -32,7 +32,7 @@
|
||||
#define SARMAG 8
|
||||
|
||||
#define ARFMAG "`\n"
|
||||
#define SARNAME 16
|
||||
#define SARNAME 64
|
||||
|
||||
struct ar_hdr
|
||||
{
|
||||
|
395
src/cmd/ar/ar.c
395
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; i<NHASH; i++) {
|
||||
for(x=ihash[i]; x; x=x->hash) {
|
||||
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; i<nimport; i++) {
|
||||
x = all[i];
|
||||
// [export] prefix name def\n
|
||||
if(x->export)
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user