summaryrefslogtreecommitdiff
path: root/src/cmd/6l/go.c
diff options
context:
space:
mode:
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"