diff options
Diffstat (limited to 'src/cmd/gc')
-rw-r--r-- | src/cmd/gc/export.c | 41 | ||||
-rw-r--r-- | src/cmd/gc/go.h | 7 | ||||
-rw-r--r-- | src/cmd/gc/lex.c | 200 | ||||
-rw-r--r-- | src/cmd/gc/obj.c | 12 | ||||
-rw-r--r-- | src/cmd/gc/reflect.c | 6 | ||||
-rw-r--r-- | src/cmd/gc/subr.c | 46 |
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; } |