summaryrefslogtreecommitdiff
path: root/src/cmd/6l/go.c
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2009-03-31 00:20:07 -0700
committerRuss Cox <rsc@golang.org>2009-03-31 00:20:07 -0700
commitfd21f3e9459fc5ea52ade3608dcdbb5b37f95bc9 (patch)
tree54067b164aad36719d9c529a5a4220b710080d2c /src/cmd/6l/go.c
parent00407c2e3e23432ae43ce3282396836189120039 (diff)
downloadgolang-fd21f3e9459fc5ea52ade3608dcdbb5b37f95bc9.tar.gz
* move go-specific loader code
into gc directory, where it gets included as ../gc/ldbody this is similar to the assemblers including ../cc/lexbody and ../cc/macbody. * hook go-specific loader code into 8l. * make current 8.out.h and 6.out.h backward compatible with plan 9's versions. i had added some constants in the middle of enums and have now moved them to the end. this keeps us from invalidating old .8 and .6 files. not sure how much it really matters, but easy to do. R=r DELTA=1314 (667 added, 623 deleted, 24 changed) OCL=26938 CL=26941
Diffstat (limited to 'src/cmd/6l/go.c')
-rw-r--r--src/cmd/6l/go.c600
1 files changed, 1 insertions, 599 deletions
diff --git a/src/cmd/6l/go.c b/src/cmd/6l/go.c
index 961a3320b..82a216520 100644
--- a/src/cmd/6l/go.c
+++ b/src/cmd/6l/go.c
@@ -2,603 +2,5 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// go-specific
-
-// accumulate all type information from .6 files.
-// check for inconsistencies.
-// define gotypestrings variable if needed.
-// define gotypesigs variable if needed.
-
-// TODO:
-// include type info for non-exported types.
-// generate debugging section in binary.
-// once the dust settles, try to move some code to
-// libmach, so that other linkers and ar can share.
-// try to make this completely portable and shared
-// across linkers
-
#include "l.h"
-
-/*
- * 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
-};
-static Import *ihash[NIHASH];
-static int nimport;
-
-static int
-hashstr(char *name)
-{
- int h;
- char *cp;
-
- h = 0;
- for(cp = name; *cp; h += *cp++)
- h *= 1119;
- if(h < 0)
- h = ~h;
- return h;
-}
-
-static 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 = mal(sizeof *x);
- x->name = name;
- x->hash = ihash[h];
- ihash[h] = x;
- nimport++;
- return x;
-}
-
-char*
-gotypefor(char *name)
-{
- Import *x;
- char *s, *p;
-
- s = strdup(name);
- p = utfrune(s, 0xB7); // center dot
- if(p == nil)
- return nil;
- *p++ = '.';
- memmove(p, p+1, strlen(p));
- x = ilookup(s);
- free(s);
- if(x == nil || x->prefix == nil)
- return nil;
- if(strcmp(x->prefix, "var") != 0 && strcmp(x->prefix, "func") != 0)
- return nil;
- return x->def;
-}
-
-static void loadpkgdata(char*, char*, int);
-static int parsemethod(char**, char*, char**);
-static int parsepkgdata(char*, char**, char*, int*, char**, char**, char**);
-
-void
-ldpkg(Biobuf *f, int64 len, char *filename)
-{
- char *data, *p0, *p1;
-
- if(debug['g'])
- return;
-
- if((int)len != len) {
- fprint(2, "6l: too much pkg data in %s\n", filename);
- return;
- }
- data = mal(len);
- if(Bread(f, data, len) != len) {
- fprint(2, "6l: short pkg read %s\n", filename);
- return;
- }
-
- // first \n$$ marks beginning of exports - skip rest of line
- p0 = strstr(data, "\n$$");
- if(p0 == nil)
- return;
- p0 += 3;
- while(*p0 != '\n' && *p0 != '\0')
- p0++;
-
- // second marks end of exports / beginning of local data
- p1 = strstr(p0, "\n$$");
- if(p1 == nil) {
- fprint(2, "6l: cannot find end of exports in %s\n", filename);
- return;
- }
- while(*p0 == ' ' || *p0 == '\t' || *p0 == '\n')
- p0++;
- if(strncmp(p0, "package ", 8) != 0) {
- fprint(2, "6l: bad package section in %s\n", filename);
- return;
- }
- p0 += 8;
- while(*p0 == ' ' || *p0 == '\t' || *p0 == '\n')
- p0++;
- while(*p0 != ' ' && *p0 != '\t' && *p0 != '\n')
- p0++;
-
- loadpkgdata(filename, p0, p1 - p0);
-
- // local types begin where exports end.
- // skip rest of line after $$ we found above
- p0 = p1 + 3;
- while(*p0 != '\n' && *p0 != '\0')
- p0++;
-
- // local types end at next \n$$.
- p1 = strstr(p0, "\n$$");
- if(p1 == nil) {
- fprint(2, "6l: cannot find end of local types in %s\n", filename);
- return;
- }
-
- loadpkgdata(filename, p0, p1 - p0);
-}
-
-static void
-loadpkgdata(char *file, char *data, int len)
-{
- int export;
- char *p, *ep, *prefix, *name, *def;
- Import *x;
-
- file = strdup(file);
- p = data;
- ep = data + len;
- while(parsepkgdata(file, &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, "6l: 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);
- nerrors++;
- }
- else if(strcmp(x->def, def) != 0) {
- fprint(2, "6l: 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);
- nerrors++;
- }
-
- // okay if some .6 say export and others don't.
- // all it takes is one.
- if(export)
- x->export = 1;
- }
- }
-}
-
-static int
-parsepkgdata(char *file, 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 == '\n'))
- p++;
- if(p == ep || strncmp(p, "$$\n", 3) == 0)
- return 0;
-
- // [export|package ]
- *exportp = 0;
- if(p + 7 <= ep && strncmp(p, "export ", 7) == 0) {
- *exportp = 1;
- p += 7;
- }
- else if(p + 8 <= ep && strncmp(p, "package ", 8) == 0) {
- *exportp = 2;
- p += 8;
- }
-
- // 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, "6l: confused in pkg data near <<%.20s>>\n", p);
- nerrors++;
- 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, "6l: %s: expected methods to be indented %p %p %.10s\n",
- file, edef, meth, meth);
- nerrors++;
- return -1;
- }
- *edef++ = '\t';
- n = strlen(meth);
- memmove(edef, meth, n);
- edef += n;
- }
-
- // done
- *pp = p;
- *prefixp = prefix;
- *namep = name;
- *defp = def;
- return 1;
-}
-
-static int
-parsemethod(char **pp, char *ep, char **methp)
-{
- char *p;
-
- // 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, "6l: lost end of line in method definition\n");
- *pp = ep;
- return -1;
- }
- *p++ = '\0';
- *pp = p;
- return 1;
-}
-
-static int
-importcmp(const void *va, const void *vb)
-{
- Import *a, *b;
-
- a = *(Import**)va;
- b = *(Import**)vb;
- return strcmp(a->name, b->name);
-}
-
-static int
-symcmp(const void *va, const void *vb)
-{
- Sym *a, *b;
-
- a = *(Sym**)va;
- b = *(Sym**)vb;
- return strcmp(a->name, b->name);
-}
-
-// if there is an undefined reference to gotypestrings,
-// create it. c declaration is
-// extern char gotypestrings[];
-// ironically, gotypestrings is a c variable, because there
-// is no way to forward declare a string in go.
-void
-definetypestrings(void)
-{
- int i, j, len, n, w;
- char *p;
- Import **all, *x;
- Fmt f;
- Prog *prog;
- Sym *s;
-
- if(debug['g'])
- return;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f definetypestrings\n", cputime());
-
- s = lookup("gotypestrings", 0);
- if(s->type == 0)
- return;
- if(s->type != SXREF) {
- diag("gotypestrings already defined");
- return;
- }
- s->type = SDATA;
-
- // make a list of all the type exports
- n = 0;
- for(i=0; i<NIHASH; i++)
- for(x=ihash[i]; x; x=x->hash)
- if(strcmp(x->prefix, "type") == 0)
- n++;
- all = mal(n*sizeof all[0]);
- j = 0;
- for(i=0; i<NIHASH; i++)
- for(x=ihash[i]; x; x=x->hash)
- if(strcmp(x->prefix, "type") == 0)
- all[j++] = x;
-
- // sort them by name
- qsort(all, n, sizeof all[0], importcmp);
-
- // make a big go string containing all the types
- fmtstrinit(&f);
- fmtprint(&f, "xxxx"); // 4-byte length
- for(i=0; i<n; i++) {
- p = strchr(all[i]->def, '\n');
- if(p)
- len = p - all[i]->def;
- else
- len = strlen(all[i]->def);
- fmtprint(&f, "%s %.*s\n", all[i]->name, utfnlen(all[i]->def, len), all[i]->def);
- }
- p = fmtstrflush(&f);
- n = strlen(p);
- s->value = n;
-
- // go strings begin with 4-byte length.
- // amd64 is little-endian.
- len = n - 4;
- p[0] = len;
- p[1] = len >> 8;
- p[2] = len >> 16;
- p[3] = len >> 24;
-
- // have data, need to create linker representation.
- // linker stores big data as sequence of pieces
- // with int8 length, so break p into 100-byte chunks.
- // (had to add D_SBIG even to do that; the compiler
- // would have generated 8-byte chunks.)
- for(i=0; i<n; i+=100) {
- w = 100;
- if(w > n - i)
- w = n - i;
- prog = newdata(s, i, w, D_EXTERN);
- prog->to.type = D_SBIG;
- prog->to.sbig = p + i;
- }
-
- if(debug['v'])
- Bprint(&bso, "%5.2f typestrings %d\n", cputime(), n);
-}
-
-// if there is an undefined reference to gotypesigs, create it.
-// c declaration is
-// extern Sigt *gotypesigs[];
-// extern int ngotypesigs;
-// used by sys.unreflect runtime.
-void
-definetypesigs(void)
-{
- int i, j, n;
- Sym **all, *s, *x;
- Prog *prog;
-
- if(debug['g'])
- return;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f definetypesigs\n", cputime());
-
- s = lookup("gotypesigs", 0);
- if(s->type == 0)
- return;
- if(s->type != SXREF) {
- diag("gotypesigs already defined");
- return;
- }
- s->type = SDATA;
-
- // make a list of all the sigt symbols.
- n = 0;
- for(i=0; i<NHASH; i++)
- for(x = hash[i]; x; x=x->link)
- if(memcmp(x->name, "sigt·", 6) == 0 && x->type != Sxxx)
- n++;
- all = mal(n*sizeof all[0]);
- j = 0;
- for(i=0; i<NHASH; i++)
- for(x = hash[i]; x; x=x->link)
- if(memcmp(x->name, "sigt·", 6) == 0 && x->type != Sxxx)
- all[j++] = x;
-
- // sort them by name
- qsort(all, n, sizeof all[0], symcmp);
-
- // emit array as sequence of references.
- enum { PtrSize = 8 };
- for(i=0; i<n; i++) {
- prog = newdata(s, PtrSize*i, PtrSize, D_EXTERN);
- prog->to.type = D_ADDR;
- prog->to.index = D_EXTERN;
- prog->to.sym = all[i];
- }
- s->value = PtrSize*n;
- if(n == 0)
- s->value = 1; // must have non-zero size or 6l complains
-
- // emit count
- s = lookup("ngotypesigs", 0);
- s->type = SDATA;
- s->value = sizeof(int32);
- prog = newdata(s, 0, sizeof(int32), D_EXTERN);
- prog->to.offset = n;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f typesigs %d\n", cputime(), n);
-}
-
-int
-isinitfunc(Sym *s)
-{
- char *p;
-
- p = utfrune(s->name, 0xb7); // 0xb7 = '·'
- if(p == nil)
- return 0;
- if(memcmp(p, "·Init·", 8) == 0 || memcmp(p, "·init·", 8) == 0)
- return 1;
- return 0;
-}
-
-static void mark(Sym*);
-static int markdepth;
-
-static void
-markdata(Prog *p, Sym *s)
-{
- markdepth++;
- if(p != P && debug['v'] > 1)
- Bprint(&bso, "%d markdata %s\n", markdepth, s->name);
- for(; p != P; p=p->dlink)
- if(p->to.sym)
- mark(p->to.sym);
- markdepth--;
-}
-
-static void
-marktext(Prog *p)
-{
- if(p == P)
- return;
- if(p->as != ATEXT) {
- diag("marktext: %P", p);
- return;
- }
- markdepth++;
- if(debug['v'] > 1)
- Bprint(&bso, "%d marktext %s\n", markdepth, p->from.sym->name);
- for(p=p->link; p != P; p=p->link) {
- if(p->as == ATEXT || p->as == ADATA || p->as == AGLOBL)
- break;
- if(p->from.sym)
- mark(p->from.sym);
- if(p->to.sym)
- mark(p->to.sym);
- }
- markdepth--;
-}
-
-static void
-mark(Sym *s)
-{
- if(s == S || s->reachable)
- return;
- s->reachable = 1;
- if(s->text)
- marktext(s->text);
- if(s->data)
- markdata(s->data, s);
-}
-
-static void
-sweeplist(Prog **first, Prog **last)
-{
- int reachable;
- Prog *p, *q;
-
- reachable = 1;
- q = P;
- for(p=*first; p != P; p=p->link) {
- switch(p->as) {
- case ATEXT:
- case ADATA:
- case AGLOBL:
- reachable = p->from.sym->reachable;
- if(!reachable) {
- if(debug['v'] > 1)
- Bprint(&bso, "discard %s\n", p->from.sym->name);
- p->from.sym->type = Sxxx;
- }
- break;
- }
- if(reachable) {
- if(q == P)
- *first = p;
- else
- q->link = p;
- q = p;
- }
- }
- if(q == P)
- *first = P;
- else
- q->link = P;
- *last = q;
-}
-
-void
-deadcode(void)
-{
- if(debug['v'])
- Bprint(&bso, "%5.2f deadcode\n", cputime());
-
- mark(lookup(INITENTRY, 0));
- mark(lookup("sys·morestack", 0));
-
- sweeplist(&firstp, &lastp);
- sweeplist(&datap, &edatap);
-}
-
+#include "../ld/go.c"