summaryrefslogtreecommitdiff
path: root/src/cmd/gc
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/gc')
-rw-r--r--src/cmd/gc/export.c41
-rw-r--r--src/cmd/gc/go.h7
-rw-r--r--src/cmd/gc/lex.c200
-rw-r--r--src/cmd/gc/obj.c12
-rw-r--r--src/cmd/gc/reflect.c6
-rw-r--r--src/cmd/gc/subr.c46
6 files changed, 278 insertions, 34 deletions
diff --git a/src/cmd/gc/export.c b/src/cmd/gc/export.c
index da5984ceb..aeee55236 100644
--- a/src/cmd/gc/export.c
+++ b/src/cmd/gc/export.c
@@ -7,6 +7,8 @@
#include "go.h"
#include "y.tab.h"
+static NodeList *asmlist;
+
static void dumpexporttype(Type *t);
// Mark n's symbol as exported
@@ -68,6 +70,11 @@ autoexport(Node *n, int ctxt)
// -A is for cmd/gc/mkbuiltin script, so export everything
if(debug['A'] || exportname(n->sym->name) || initname(n->sym->name))
exportsym(n);
+ if(asmhdr && n->sym->pkg == localpkg && !(n->sym->flags & SymAsm)) {
+ n->sym->flags |= SymAsm;
+ asmlist = list(asmlist, n);
+ }
+
}
static void
@@ -519,3 +526,37 @@ importtype(Type *pt, Type *t)
if(debug['E'])
print("import type %T %lT\n", pt, t);
}
+
+void
+dumpasmhdr(void)
+{
+ Biobuf *b;
+ NodeList *l;
+ Node *n;
+ Type *t;
+
+ b = Bopen(asmhdr, OWRITE);
+ if(b == nil)
+ fatal("open %s: %r", asmhdr);
+ Bprint(b, "// generated by %cg -asmhdr from package %s\n\n", thechar, localpkg->name);
+ for(l=asmlist; l; l=l->next) {
+ n = l->n;
+ if(isblanksym(n->sym))
+ continue;
+ switch(n->op) {
+ case OLITERAL:
+ Bprint(b, "#define const_%s %#V\n", n->sym->name, &n->val);
+ break;
+ case OTYPE:
+ t = n->type;
+ if(t->etype != TSTRUCT || t->map != T || t->funarg)
+ break;
+ for(t=t->type; t != T; t=t->down)
+ if(!isblanksym(t->sym))
+ Bprint(b, "#define %s_%s %d\n", n->sym->name, t->sym->name, (int)t->width);
+ break;
+ }
+ }
+
+ Bterm(b);
+}
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
index c695c5bf3..5236305f8 100644
--- a/src/cmd/gc/go.h
+++ b/src/cmd/gc/go.h
@@ -382,6 +382,7 @@ enum
SymExported = 1<<2, // already written out by export
SymUniq = 1<<3,
SymSiggen = 1<<4,
+ SymAsm = 1<<5,
};
struct Sym
@@ -393,6 +394,7 @@ struct Sym
int32 npkg; // number of imported packages with this name
uint32 uniqgen;
Pkg* importdef; // where imported definition was found
+ char* linkname; // link name
// saved and restored by dcopy
Pkg* pkg;
@@ -860,6 +862,8 @@ EXTERN int32 lexlineno;
EXTERN int32 lineno;
EXTERN int32 prevlineno;
+EXTERN Fmt pragcgobuf;
+
EXTERN char* infile;
EXTERN char* outfile;
EXTERN Biobuf* bout;
@@ -890,6 +894,7 @@ EXTERN Pkg* typelinkpkg; // fake package for runtime type info (data)
EXTERN Pkg* weaktypepkg; // weak references to runtime type info
EXTERN Pkg* unsafepkg; // package unsafe
EXTERN Pkg* trackpkg; // fake package for field tracking
+EXTERN Pkg* rawpkg; // fake package for raw symbol names
EXTERN Pkg* phash[128];
EXTERN int tptr; // either TPTR32 or TPTR64
extern char* runtimeimport;
@@ -897,6 +902,7 @@ extern char* unsafeimport;
EXTERN char* myimportpath;
EXTERN Idir* idirs;
EXTERN char* localimport;
+EXTERN char* asmhdr;
EXTERN Type* types[NTYPE];
EXTERN Type* idealstring;
@@ -1147,6 +1153,7 @@ void escapes(NodeList*);
*/
void autoexport(Node *n, int ctxt);
void dumpexport(void);
+void dumpasmhdr(void);
int exportname(char *s);
void exportsym(Node *n);
void importconst(Sym *s, Type *t, Node *n);
diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c
index 523ba37aa..2bd7adfb6 100644
--- a/src/cmd/gc/lex.c
+++ b/src/cmd/gc/lex.c
@@ -17,6 +17,8 @@ extern int yychar;
int yyprev;
int yylast;
+static int imported_unsafe;
+
static void lexinit(void);
static void lexinit1(void);
static void lexfini(void);
@@ -271,6 +273,9 @@ main(int argc, char *argv[])
flag_largemodel = 1;
setexp();
+
+ fmtstrinit(&pragcgobuf);
+ quotefmtinstall();
outfile = nil;
flagcount("+", "compiling runtime", &compiling_runtime);
@@ -289,6 +294,7 @@ main(int argc, char *argv[])
flagcount("S", "print assembly listing", &debug['S']);
flagfn0("V", "print compiler version", doversion);
flagcount("W", "debug parse tree after type checking", &debug['W']);
+ flagstr("asmhdr", "file: write assembly header to named file", &asmhdr);
flagcount("complete", "compiling complete package (no C or assembly)", &pure_go);
flagstr("d", "list: print debug information about items in list", &debugstr);
flagcount("e", "no limit on number of errors reported", &debug['e']);
@@ -403,6 +409,8 @@ main(int argc, char *argv[])
block = 1;
iota = -1000000;
+
+ imported_unsafe = 0;
yyparse();
if(nsyntaxerrors != 0)
@@ -509,6 +517,9 @@ main(int argc, char *argv[])
errorexit();
dumpobj();
+
+ if(asmhdr)
+ dumpasmhdr();
if(nerrors+nsavederrors)
errorexit();
@@ -724,6 +735,7 @@ importfile(Val *f, int line)
}
importpkg = mkpkg(f->u.sval);
cannedimports("unsafe.6", unsafeimport);
+ imported_unsafe = 1;
return;
}
@@ -1501,6 +1513,20 @@ caseout:
return LLITERAL;
}
+static void pragcgo(char*);
+
+static int
+more(char **pp)
+{
+ char *p;
+
+ p = *pp;
+ while(yy_isspace(*p))
+ p++;
+ *pp = p;
+ return *p != '\0';
+}
+
/*
* read and interpret syntax that looks like
* //line parse.y:15
@@ -1583,9 +1609,39 @@ go:
*cp++ = c;
}
*cp = 0;
+
+ if(strncmp(lexbuf, "go:cgo_", 7) == 0)
+ pragcgo(lexbuf);
+
ep = strchr(lexbuf, ' ');
if(ep != nil)
*ep = 0;
+
+ if(strcmp(lexbuf, "go:linkname") == 0) {
+ if(!imported_unsafe)
+ yyerror("//go:linkname only allowed in Go files that import \"unsafe\"");
+ if(ep == nil) {
+ yyerror("usage: //go:linkname localname linkname");
+ goto out;
+ }
+ cp = ep+1;
+ while(yy_isspace(*cp))
+ cp++;
+ ep = strchr(cp, ' ');
+ if(ep == nil) {
+ yyerror("usage: //go:linkname localname linkname");
+ goto out;
+ }
+ *ep++ = 0;
+ while(yy_isspace(*ep))
+ ep++;
+ if(*ep == 0) {
+ yyerror("usage: //go:linkname localname linkname");
+ goto out;
+ }
+ lookup(cp)->linkname = strdup(ep);
+ goto out;
+ }
if(strcmp(lexbuf, "go:nointerface") == 0 && fieldtrack_enabled) {
nointerface = 1;
@@ -1604,6 +1660,150 @@ out:
return c;
}
+static char*
+getimpsym(char **pp)
+{
+ char *p, *start;
+
+ more(pp); // skip spaces
+
+ p = *pp;
+ if(*p == '\0' || *p == '"')
+ return nil;
+
+ start = p;
+ while(*p != '\0' && !yy_isspace(*p) && *p != '"')
+ p++;
+ if(*p != '\0')
+ *p++ = '\0';
+
+ *pp = p;
+ return start;
+}
+
+static char*
+getquoted(char **pp)
+{
+ char *p, *start;
+
+ more(pp); // skip spaces
+
+ p = *pp;
+ if(*p != '"')
+ return nil;
+ p++;
+
+ start = p;
+ while(*p != '"') {
+ if(*p == '\0')
+ return nil;
+ p++;
+ }
+ *p++ = '\0';
+ *pp = p;
+ return start;
+}
+
+// Copied nearly verbatim from the C compiler's #pragma parser.
+// TODO: Rewrite more cleanly once the compiler is written in Go.
+static void
+pragcgo(char *text)
+{
+ char *local, *remote, *p, *q, *verb;
+
+ for(q=text; *q != '\0' && *q != ' '; q++)
+ ;
+ if(*q == ' ')
+ *q++ = '\0';
+
+ verb = text+3; // skip "go:"
+
+ if(strcmp(verb, "cgo_dynamic_linker") == 0 || strcmp(verb, "dynlinker") == 0) {
+ p = getquoted(&q);
+ if(p == nil)
+ goto err1;
+ fmtprint(&pragcgobuf, "cgo_dynamic_linker %q\n", p);
+ goto out;
+
+ err1:
+ yyerror("usage: //go:cgo_dynamic_linker \"path\"");
+ goto out;
+ }
+
+ if(strcmp(verb, "dynexport") == 0)
+ verb = "cgo_export_dynamic";
+ if(strcmp(verb, "cgo_export_static") == 0 || strcmp(verb, "cgo_export_dynamic") == 0) {
+ local = getimpsym(&q);
+ if(local == nil)
+ goto err2;
+ if(!more(&q)) {
+ fmtprint(&pragcgobuf, "%s %q\n", verb, local);
+ goto out;
+ }
+ remote = getimpsym(&q);
+ if(remote == nil)
+ goto err2;
+ fmtprint(&pragcgobuf, "%s %q %q\n", verb, local, remote);
+ goto out;
+
+ err2:
+ yyerror("usage: //go:%s local [remote]", verb);
+ goto out;
+ }
+
+ if(strcmp(verb, "cgo_import_dynamic") == 0 || strcmp(verb, "dynimport") == 0) {
+ local = getimpsym(&q);
+ if(local == nil)
+ goto err3;
+ if(!more(&q)) {
+ fmtprint(&pragcgobuf, "cgo_import_dynamic %q\n", local);
+ goto out;
+ }
+ remote = getimpsym(&q);
+ if(remote == nil)
+ goto err3;
+ if(!more(&q)) {
+ fmtprint(&pragcgobuf, "cgo_import_dynamic %q %q\n", local, remote);
+ goto out;
+ }
+ p = getquoted(&q);
+ if(p == nil)
+ goto err3;
+ fmtprint(&pragcgobuf, "cgo_import_dynamic %q %q %q\n", local, remote, p);
+ goto out;
+
+ err3:
+ yyerror("usage: //go:cgo_import_dynamic local [remote [\"library\"]]");
+ goto out;
+ }
+
+ if(strcmp(verb, "cgo_import_static") == 0) {
+ local = getimpsym(&q);
+ if(local == nil || more(&q))
+ goto err4;
+ fmtprint(&pragcgobuf, "cgo_import_static %q\n", local);
+ goto out;
+
+ err4:
+ yyerror("usage: //go:cgo_import_static local");
+ goto out;
+ }
+
+ if(strcmp(verb, "cgo_ldflag") == 0) {
+ p = getquoted(&q);
+ if(p == nil)
+ goto err5;
+ fmtprint(&pragcgobuf, "cgo_ldflag %q\n", p);
+ goto out;
+
+ err5:
+ yyerror("usage: //go:cgo_ldflag \"arg\"");
+ goto out;
+ }
+
+out:;
+}
+
int32
yylex(void)
{
diff --git a/src/cmd/gc/obj.c b/src/cmd/gc/obj.c
index b752a13ce..7e4e97854 100644
--- a/src/cmd/gc/obj.c
+++ b/src/cmd/gc/obj.c
@@ -67,6 +67,16 @@ dumpobj(void)
startobj = Boffset(bout);
Bprint(bout, "go object %s %s %s %s\n", getgoos(), getgoarch(), getgoversion(), expstring());
}
+
+ if(pragcgobuf.to > pragcgobuf.start) {
+ if(writearchive) {
+ // write empty export section; must be before cgo section
+ Bprint(bout, "\n$$\n\n$$\n\n");
+ }
+ Bprint(bout, "\n$$ // cgo\n");
+ Bprint(bout, "%s\n$$\n\n", fmtstrflush(&pragcgobuf));
+ }
+
Bprint(bout, "\n!\n");
@@ -153,6 +163,8 @@ linksym(Sym *s)
return s->lsym;
if(isblanksym(s))
s->lsym = linklookup(ctxt, "_", 0);
+ else if(s->linkname != nil)
+ s->lsym = linklookup(ctxt, s->linkname, 0);
else {
p = smprint("%s.%s", s->pkg->prefix, s->name);
s->lsym = linklookup(ctxt, p, 0);
diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c
index 0f8802abc..4155953be 100644
--- a/src/cmd/gc/reflect.c
+++ b/src/cmd/gc/reflect.c
@@ -1318,7 +1318,7 @@ gengcmask(Type *t, uint8 gcmask[16])
{
Bvec *vec;
vlong xoffset, nptr, i, j;
- int half, mw;
+ int half;
uint8 bits, *pos;
memset(gcmask, 0, 16);
@@ -1335,7 +1335,6 @@ gengcmask(Type *t, uint8 gcmask[16])
pos = (uint8*)gcmask;
nptr = (t->width+widthptr-1)/widthptr;
half = 0;
- mw = 0;
// If number of words is odd, repeat the mask.
// This makes simpler handling of arrays in runtime.
for(j=0; j<=(nptr%2); j++) {
@@ -1344,9 +1343,8 @@ gengcmask(Type *t, uint8 gcmask[16])
// Some fake types (e.g. Hmap) has missing fileds.
// twobitwalktype1 generates BitsDead for that holes,
// replace BitsDead with BitsScalar.
- if(!mw && bits == BitsDead)
+ if(bits == BitsDead)
bits = BitsScalar;
- mw = !mw && bits == BitsMultiWord;
bits <<= 2;
if(half)
bits <<= 4;
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
index c3bc5af3b..5e369b695 100644
--- a/src/cmd/gc/subr.c
+++ b/src/cmd/gc/subr.c
@@ -3802,39 +3802,25 @@ checknil(Node *x, NodeList **init)
/*
* Can this type be stored directly in an interface word?
+ * Yes, if the representation is a single pointer.
*/
int
isdirectiface(Type *t)
{
- // Setting IfacePointerOnly = 1 changes the
- // interface representation so that the data word
- // in an interface value must always be a pointer.
- // Setting it to 0 uses the original representation,
- // where the data word can hold a pointer or any
- // non-pointer value no bigger than a pointer.
- enum {
- IfacePointerOnly = 1,
- };
-
- if(IfacePointerOnly) {
- switch(t->etype) {
- case TPTR32:
- case TPTR64:
- case TCHAN:
- case TMAP:
- case TFUNC:
- case TUNSAFEPTR:
- return 1;
- case TARRAY:
- // Array of 1 direct iface type can be direct.
- return t->bound == 1 && isdirectiface(t->type);
- case TSTRUCT:
- // Struct with 1 field of direct iface type can be direct.
- return t->type != T && t->type->down == T && isdirectiface(t->type->type);
- }
- return 0;
+ switch(t->etype) {
+ case TPTR32:
+ case TPTR64:
+ case TCHAN:
+ case TMAP:
+ case TFUNC:
+ case TUNSAFEPTR:
+ return 1;
+ case TARRAY:
+ // Array of 1 direct iface type can be direct.
+ return t->bound == 1 && isdirectiface(t->type);
+ case TSTRUCT:
+ // Struct with 1 field of direct iface type can be direct.
+ return t->type != T && t->type->down == T && isdirectiface(t->type->type);
}
-
- dowidth(t);
- return t->width <= widthptr;
+ return 0;
}