Commit 6ed3fa65 authored by Russ Cox's avatar Russ Cox

gc: introduce rune

R=ken, r
CC=golang-dev
https://golang.org/cl/5293046
parent f4568882
...@@ -44,6 +44,8 @@ OFILES=\ ...@@ -44,6 +44,8 @@ OFILES=\
walk.$O\ walk.$O\
y1.tab.$O\ y1.tab.$O\
HOST_CFLAGS+=-DGOEXPERIMENT='"$(GOEXPERIMENT)"'
NOINSTALL=1 NOINSTALL=1
include ../../Make.clib include ../../Make.clib
......
...@@ -31,11 +31,11 @@ char *runtimeimport = ...@@ -31,11 +31,11 @@ char *runtimeimport =
"func @\"\".slicestring1 (? string, ? int) string\n" "func @\"\".slicestring1 (? string, ? int) string\n"
"func @\"\".intstring (? int64) string\n" "func @\"\".intstring (? int64) string\n"
"func @\"\".slicebytetostring (? []byte) string\n" "func @\"\".slicebytetostring (? []byte) string\n"
"func @\"\".sliceinttostring (? []int) string\n" "func @\"\".slicerunetostring (? []rune) string\n"
"func @\"\".stringtoslicebyte (? string) []byte\n" "func @\"\".stringtoslicebyte (? string) []byte\n"
"func @\"\".stringtosliceint (? string) []int\n" "func @\"\".stringtoslicerune (? string) []rune\n"
"func @\"\".stringiter (? string, ? int) int\n" "func @\"\".stringiter (? string, ? int) int\n"
"func @\"\".stringiter2 (? string, ? int) (retk int, retv int)\n" "func @\"\".stringiter2 (? string, ? int) (retk int, retv rune)\n"
"func @\"\".slicecopy (to any, fr any, wid uint32) int\n" "func @\"\".slicecopy (to any, fr any, wid uint32) int\n"
"func @\"\".slicestringcopy (to any, fr any) int\n" "func @\"\".slicestringcopy (to any, fr any) int\n"
"func @\"\".convI2E (elem any) any\n" "func @\"\".convI2E (elem any) any\n"
......
...@@ -94,7 +94,7 @@ dumpprereq(Type *t) ...@@ -94,7 +94,7 @@ dumpprereq(Type *t)
if(t == T) if(t == T)
return; return;
if(t->printed || t == types[t->etype] || t == bytetype) if(t->printed || t == types[t->etype] || t == bytetype || t == runetype)
return; return;
t->printed = 1; t->printed = 1;
......
...@@ -785,6 +785,7 @@ EXTERN Type* types[NTYPE]; ...@@ -785,6 +785,7 @@ EXTERN Type* types[NTYPE];
EXTERN Type* idealstring; EXTERN Type* idealstring;
EXTERN Type* idealbool; EXTERN Type* idealbool;
EXTERN Type* bytetype; EXTERN Type* bytetype;
EXTERN Type* runetype;
EXTERN uchar simtype[NTYPE]; EXTERN uchar simtype[NTYPE];
EXTERN uchar isptr[NTYPE]; EXTERN uchar isptr[NTYPE];
EXTERN uchar isforw[NTYPE]; EXTERN uchar isforw[NTYPE];
...@@ -840,6 +841,7 @@ EXTERN Node* nblank; ...@@ -840,6 +841,7 @@ EXTERN Node* nblank;
extern int thechar; extern int thechar;
extern char* thestring; extern char* thestring;
EXTERN char* hunk; EXTERN char* hunk;
EXTERN int32 nhunk; EXTERN int32 nhunk;
EXTERN int32 thunk; EXTERN int32 thunk;
...@@ -854,6 +856,8 @@ EXTERN int packagequotes; ...@@ -854,6 +856,8 @@ EXTERN int packagequotes;
EXTERN int longsymnames; EXTERN int longsymnames;
EXTERN int compiling_runtime; EXTERN int compiling_runtime;
EXTERN int rune32;
/* /*
* y.tab.c * y.tab.c
*/ */
...@@ -1009,6 +1013,7 @@ Node* renameinit(Node *n); ...@@ -1009,6 +1013,7 @@ Node* renameinit(Node *n);
void cannedimports(char *file, char *cp); void cannedimports(char *file, char *cp);
void importfile(Val *f, int line); void importfile(Val *f, int line);
char* lexname(int lex); char* lexname(int lex);
char* expstring(void);
void mkpackage(char* pkgname); void mkpackage(char* pkgname);
void unimportfile(void); void unimportfile(void);
int32 yylex(void); int32 yylex(void);
......
...@@ -30,6 +30,60 @@ static void addidir(char*); ...@@ -30,6 +30,60 @@ static void addidir(char*);
static int getlinepragma(void); static int getlinepragma(void);
static char *goos, *goarch, *goroot; static char *goos, *goarch, *goroot;
// Compiler experiments.
// These are controlled by the GCEXPERIMENT environment
// variable recorded when the compiler is built.
static struct {
char *name;
int *val;
} exper[] = {
{"rune32", &rune32},
};
static void
addexp(char *s)
{
int i;
for(i=0; i<nelem(exper); i++) {
if(strcmp(exper[i].name, s) == 0) {
*exper[i].val = 1;
return;
}
}
print("unknown experiment %s\n", s);
exits("unknown experiment");
}
static void
setexp(void)
{
char *f[20];
int i, nf;
// The makefile #defines GOEXPERIMENT for us.
nf = getfields(GOEXPERIMENT, f, nelem(f), 1, ",");
for(i=0; i<nf; i++)
addexp(f[i]);
}
char*
expstring(void)
{
int i;
static char buf[512];
strcpy(buf, "X");
for(i=0; i<nelem(exper); i++)
if(*exper[i].val)
seprint(buf+strlen(buf), buf+sizeof buf, ",%s", exper[i].name);
if(strlen(buf) == 1)
strcpy(buf, "X,none");
buf[1] = ':';
return buf;
}
// Our own isdigit, isspace, isalpha, isalnum that take care // Our own isdigit, isspace, isalpha, isalnum that take care
// of EOF and other out of range arguments. // of EOF and other out of range arguments.
static int static int
...@@ -94,7 +148,7 @@ usage(void) ...@@ -94,7 +148,7 @@ usage(void)
print(" -u disable package unsafe\n"); print(" -u disable package unsafe\n");
print(" -w print the parse tree after typing\n"); print(" -w print the parse tree after typing\n");
print(" -x print lex tokens\n"); print(" -x print lex tokens\n");
exits(0); exits("usage");
} }
void void
...@@ -145,6 +199,8 @@ main(int argc, char *argv[]) ...@@ -145,6 +199,8 @@ main(int argc, char *argv[])
goos = getgoos(); goos = getgoos();
goarch = thestring; goarch = thestring;
setexp();
outfile = nil; outfile = nil;
ARGBEGIN { ARGBEGIN {
default: default:
...@@ -170,7 +226,10 @@ main(int argc, char *argv[]) ...@@ -170,7 +226,10 @@ main(int argc, char *argv[])
break; break;
case 'V': case 'V':
print("%cg version %s\n", thechar, getgoversion()); p = expstring();
if(strcmp(p, "X:none") == 0)
p = "";
print("%cg version %s%s%s%s\n", thechar, getgoversion(), *p ? " " : "", p);
exits(0); exits(0);
} ARGEND } ARGEND
...@@ -540,7 +599,7 @@ importfile(Val *f, int line) ...@@ -540,7 +599,7 @@ importfile(Val *f, int line)
yyerror("import %s: not a go object file", file); yyerror("import %s: not a go object file", file);
errorexit(); errorexit();
} }
q = smprint("%s %s %s", getgoos(), thestring, getgoversion()); q = smprint("%s %s %s %s", getgoos(), thestring, getgoversion(), expstring());
if(strcmp(p+10, q) != 0) { if(strcmp(p+10, q) != 0) {
yyerror("import %s: object is [%s] expected [%s]", file, p+10, q); yyerror("import %s: object is [%s] expected [%s]", file, p+10, q);
errorexit(); errorexit();
...@@ -1720,6 +1779,18 @@ lexinit1(void) ...@@ -1720,6 +1779,18 @@ lexinit1(void)
s1 = pkglookup("byte", builtinpkg); s1 = pkglookup("byte", builtinpkg);
s1->lexical = LNAME; s1->lexical = LNAME;
s1->def = typenod(bytetype); s1->def = typenod(bytetype);
// rune alias
s = lookup("rune");
s->lexical = LNAME;
if(rune32)
runetype = typ(TINT32);
else
runetype = typ(TINT);
runetype->sym = s;
s1 = pkglookup("rune", builtinpkg);
s1->lexical = LNAME;
s1->def = typenod(runetype);
} }
static void static void
...@@ -1761,6 +1832,10 @@ lexfini(void) ...@@ -1761,6 +1832,10 @@ lexfini(void)
if(s->def == N) if(s->def == N)
s->def = typenod(bytetype); s->def = typenod(bytetype);
s = lookup("rune");
if(s->def == N)
s->def = typenod(runetype);
types[TNIL] = typ(TNIL); types[TNIL] = typ(TNIL);
s = lookup("nil"); s = lookup("nil");
if(s->def == N) { if(s->def == N) {
......
...@@ -23,7 +23,7 @@ dumpobj(void) ...@@ -23,7 +23,7 @@ dumpobj(void)
errorexit(); errorexit();
} }
Bprint(bout, "go object %s %s %s\n", getgoos(), thestring, getgoversion()); Bprint(bout, "go object %s %s %s %s\n", getgoos(), thestring, getgoversion(), expstring());
Bprint(bout, " exports automatically generated from\n"); Bprint(bout, " exports automatically generated from\n");
Bprint(bout, " %s in package \"%s\"\n", curio.infile, localpkg->name); Bprint(bout, " %s in package \"%s\"\n", curio.infile, localpkg->name);
dumpexport(); dumpexport();
......
...@@ -54,7 +54,7 @@ typecheckrange(Node *n) ...@@ -54,7 +54,7 @@ typecheckrange(Node *n)
case TSTRING: case TSTRING:
t1 = types[TINT]; t1 = types[TINT];
t2 = types[TINT]; t2 = runetype;
break; break;
} }
...@@ -216,7 +216,7 @@ walkrange(Node *n) ...@@ -216,7 +216,7 @@ walkrange(Node *n)
if(v2 == N) if(v2 == N)
a = nod(OAS, hv1, mkcall("stringiter", types[TINT], nil, ha, hv1)); a = nod(OAS, hv1, mkcall("stringiter", types[TINT], nil, ha, hv1));
else { else {
hv2 = temp(types[TINT]); hv2 = temp(runetype);
a = nod(OAS2, N, N); a = nod(OAS2, N, N);
a->list = list(list1(hv1), hv2); a->list = list(list1(hv1), hv2);
fn = syslook("stringiter2", 0); fn = syslook("stringiter2", 0);
......
...@@ -692,7 +692,7 @@ dtypesym(Type *t) ...@@ -692,7 +692,7 @@ dtypesym(Type *t)
tbase = t->type; tbase = t->type;
dupok = tbase->sym == S; dupok = tbase->sym == S;
if(compiling_runtime && (tbase == types[tbase->etype] || tbase == bytetype)) // int, float, etc if(compiling_runtime && (tbase == types[tbase->etype] || tbase == bytetype || tbase == runetype)) // int, float, etc
goto ok; goto ok;
// named types from other files are defined only by those files // named types from other files are defined only by those files
......
...@@ -47,11 +47,11 @@ func slicestring(string, int, int) string ...@@ -47,11 +47,11 @@ func slicestring(string, int, int) string
func slicestring1(string, int) string func slicestring1(string, int) string
func intstring(int64) string func intstring(int64) string
func slicebytetostring([]byte) string func slicebytetostring([]byte) string
func sliceinttostring([]int) string func slicerunetostring([]rune) string
func stringtoslicebyte(string) []byte func stringtoslicebyte(string) []byte
func stringtosliceint(string) []int func stringtoslicerune(string) []rune
func stringiter(string, int) int func stringiter(string, int) int
func stringiter2(string, int) (retk int, retv int) func stringiter2(string, int) (retk int, retv rune)
func slicecopy(to any, fr any, wid uint32) int func slicecopy(to any, fr any, wid uint32) int
func slicestringcopy(to any, fr any) int func slicestringcopy(to any, fr any) int
......
...@@ -1285,13 +1285,15 @@ Tpretty(Fmt *fp, Type *t) ...@@ -1285,13 +1285,15 @@ Tpretty(Fmt *fp, Type *t)
// called from typesym // called from typesym
if(t == bytetype) if(t == bytetype)
t = types[bytetype->etype]; t = types[bytetype->etype];
if(t == runetype)
t = types[runetype->etype];
} }
if(t->etype != TFIELD if(t->etype != TFIELD
&& t->sym != S && t->sym != S
&& !(fp->flags&FmtLong)) { && !(fp->flags&FmtLong)) {
s = t->sym; s = t->sym;
if((t == types[t->etype] && t->etype != TUNSAFEPTR) || t == bytetype) if((t == types[t->etype] && t->etype != TUNSAFEPTR) || t == bytetype || t == runetype)
return fmtprint(fp, "%s", s->name); return fmtprint(fp, "%s", s->name);
if(exporting) { if(exporting) {
if(fp->flags & FmtShort) if(fp->flags & FmtShort)
...@@ -1875,6 +1877,11 @@ eqtype(Type *t1, Type *t2) ...@@ -1875,6 +1877,11 @@ eqtype(Type *t1, Type *t2)
if((t1 == types[TUINT8] || t1 == bytetype) && (t2 == types[TUINT8] || t2 == bytetype)) if((t1 == types[TUINT8] || t1 == bytetype) && (t2 == types[TUINT8] || t2 == bytetype))
return 1; return 1;
break; break;
case TINT:
case TINT32:
if((t1 == types[runetype->etype] || t1 == runetype) && (t2 == types[runetype->etype] || t2 == runetype))
return 1;
break;
} }
return 0; return 0;
} }
...@@ -2100,7 +2107,7 @@ convertop(Type *src, Type *dst, char **why) ...@@ -2100,7 +2107,7 @@ convertop(Type *src, Type *dst, char **why)
return OCONV; return OCONV;
} }
// 6. src is an integer or has type []byte or []int // 6. src is an integer or has type []byte or []rune
// and dst is a string type. // and dst is a string type.
if(isint[src->etype] && dst->etype == TSTRING) if(isint[src->etype] && dst->etype == TSTRING)
return ORUNESTR; return ORUNESTR;
...@@ -2108,16 +2115,16 @@ convertop(Type *src, Type *dst, char **why) ...@@ -2108,16 +2115,16 @@ convertop(Type *src, Type *dst, char **why)
if(isslice(src) && src->sym == nil && dst->etype == TSTRING) { if(isslice(src) && src->sym == nil && dst->etype == TSTRING) {
if(eqtype(src->type, bytetype)) if(eqtype(src->type, bytetype))
return OARRAYBYTESTR; return OARRAYBYTESTR;
if(eqtype(src->type, types[TINT])) if(eqtype(src->type, runetype))
return OARRAYRUNESTR; return OARRAYRUNESTR;
} }
// 7. src is a string and dst is []byte or []int. // 7. src is a string and dst is []byte or []rune.
// String to slice. // String to slice.
if(src->etype == TSTRING && isslice(dst) && dst->sym == nil) { if(src->etype == TSTRING && isslice(dst) && dst->sym == nil) {
if(eqtype(dst->type, bytetype)) if(eqtype(dst->type, bytetype))
return OSTRARRAYBYTE; return OSTRARRAYBYTE;
if(eqtype(dst->type, types[TINT])) if(eqtype(dst->type, runetype))
return OSTRARRAYRUNE; return OSTRARRAYRUNE;
} }
......
...@@ -2469,7 +2469,7 @@ stringtoarraylit(Node **np) ...@@ -2469,7 +2469,7 @@ stringtoarraylit(Node **np)
while(p < ep) while(p < ep)
l = list(l, nod(OKEY, nodintconst(i++), nodintconst((uchar)*p++))); l = list(l, nod(OKEY, nodintconst(i++), nodintconst((uchar)*p++)));
} else { } else {
// utf-8 []int // utf-8 []rune
while(p < ep) { while(p < ep) {
p += chartorune(&r, p); p += chartorune(&r, p);
l = list(l, nod(OKEY, nodintconst(i++), nodintconst(r))); l = list(l, nod(OKEY, nodintconst(i++), nodintconst(r)));
......
...@@ -1151,8 +1151,8 @@ walkexpr(Node **np, NodeList **init) ...@@ -1151,8 +1151,8 @@ walkexpr(Node **np, NodeList **init)
goto ret; goto ret;
case OARRAYRUNESTR: case OARRAYRUNESTR:
// sliceinttostring([]int) string; // slicerunetostring([]rune) string;
n = mkcall("sliceinttostring", n->type, init, n->left); n = mkcall("slicerunetostring", n->type, init, n->left);
goto ret; goto ret;
case OSTRARRAYBYTE: case OSTRARRAYBYTE:
...@@ -1161,8 +1161,8 @@ walkexpr(Node **np, NodeList **init) ...@@ -1161,8 +1161,8 @@ walkexpr(Node **np, NodeList **init)
goto ret; goto ret;
case OSTRARRAYRUNE: case OSTRARRAYRUNE:
// stringtosliceint(string) []int // stringtoslicerune(string) []rune
n = mkcall("stringtosliceint", n->type, init, n->left); n = mkcall("stringtoslicerune", n->type, init, n->left);
goto ret; goto ret;
case OCMPIFACE: case OCMPIFACE:
......
...@@ -611,6 +611,43 @@ qcmd(char *arname, int count, char **files) ...@@ -611,6 +611,43 @@ qcmd(char *arname, int count, char **files)
close(fd); close(fd);
} }
/*
* does the object header line p match the last one we saw?
* update *lastp if it gets more specific.
*/
int
matchhdr(char *p, char **lastp)
{
int n;
char *last;
// no information?
last = *lastp;
if(last == nil) {
*lastp = strdup(p);
return 1;
}
// identical match?
if(strcmp(last, p) == 0)
return 1;
// last has extra fields
n = strlen(p);
if(n < strlen(last) && last[n] == ' ')
return 1;
// p has extra fields - save in last
n = strlen(last);
if(n < strlen(p) && p[n] == ' ') {
free(last);
*lastp = strdup(p);
return 1;
}
return 0;
}
/* /*
* extract the symbol references from an object file * extract the symbol references from an object file
*/ */
...@@ -670,19 +707,24 @@ scanobj(Biobuf *b, Arfile *ap, long size) ...@@ -670,19 +707,24 @@ scanobj(Biobuf *b, Arfile *ap, long size)
return; return;
} }
if ((lastobj >= 0 && obj != lastobj) || (objhdr != nil && strcmp(p, objhdr) != 0)) { if (!matchhdr(p, &objhdr)) {
fprint(2, "gopack: inconsistent object file %s\n", file); fprint(2, "gopack: inconsistent object file %s: [%s] vs [%s]\n", file, p, objhdr);
errors++; errors++;
allobj = 0; allobj = 0;
free(p); free(p);
return; return;
} }
lastobj = obj;
if(objhdr == nil)
objhdr = p;
else
free(p); free(p);
// Old check. Should be impossible since objhdrs match, but keep the check anyway.
if (lastobj >= 0 && obj != lastobj) {
fprint(2, "gopack: inconsistent object file %s\n", file);
errors++;
allobj = 0;
return;
}
lastobj = obj;
if (!readar(b, obj, offset+size, 0)) { if (!readar(b, obj, offset+size, 0)) {
fprint(2, "gopack: invalid symbol reference in file %s\n", file); fprint(2, "gopack: invalid symbol reference in file %s\n", file);
errors++; errors++;
......
...@@ -46,6 +46,7 @@ static int cout = -1; ...@@ -46,6 +46,7 @@ static int cout = -1;
char* goroot; char* goroot;
char* goarch; char* goarch;
char* goos; char* goos;
char* theline;
void void
Lflag(char *arg) Lflag(char *arg)
...@@ -478,12 +479,31 @@ ldobj(Biobuf *f, char *pkg, int64 len, char *pn, int whence) ...@@ -478,12 +479,31 @@ ldobj(Biobuf *f, char *pkg, int64 len, char *pn, int whence)
diag("%s: not an object file", pn); diag("%s: not an object file", pn);
return; return;
} }
t = smprint("%s %s %s", getgoos(), thestring, getgoversion());
if(strcmp(line+10, t) != 0 && !debug['f']) { // First, check that the basic goos, string, and version match.
t = smprint("%s %s %s ", getgoos(), thestring, getgoversion());
line[n] = ' ';
if(strncmp(line+10, t, strlen(t)) != 0 && !debug['f']) {
line[n] = '\0';
diag("%s: object is [%s] expected [%s]", pn, line+10, t); diag("%s: object is [%s] expected [%s]", pn, line+10, t);
free(t); free(t);
return; return;
} }
// Second, check that longer lines match each other exactly,
// so that the Go compiler and write additional information
// that must be the same from run to run.
line[n] = '\0';
if(n-10 > strlen(t)) {
if(theline == nil)
theline = strdup(line+10);
else if(strcmp(theline, line+10) != 0) {
line[n] = '\0';
diag("%s: object is [%s] expected [%s]", pn, line+10, theline);
free(t);
return;
}
}
free(t); free(t);
line[n] = '\n'; line[n] = '\n';
......
...@@ -278,7 +278,7 @@ func stringtoslicebyte(s String) (b Slice) { ...@@ -278,7 +278,7 @@ func stringtoslicebyte(s String) (b Slice) {
runtime·memmove(b.array, s.str, s.len); runtime·memmove(b.array, s.str, s.len);
} }
func sliceinttostring(b Slice) (s String) { func slicerunetostring(b Slice) (s String) {
int32 siz1, siz2, i; int32 siz1, siz2, i;
int32 *a; int32 *a;
byte dum[8]; byte dum[8];
...@@ -301,13 +301,13 @@ func sliceinttostring(b Slice) (s String) { ...@@ -301,13 +301,13 @@ func sliceinttostring(b Slice) (s String) {
s.str[s.len] = 0; s.str[s.len] = 0;
} }
func stringtosliceint(s String) (b Slice) { func stringtoslicerune(s String) (b Slice) {
int32 n; int32 n;
int32 dum, *r; int32 dum, *r;
uint8 *p, *ep; uint8 *p, *ep;
// two passes. // two passes.
// unlike sliceinttostring, no race because strings are immutable. // unlike slicerunetostring, no race because strings are immutable.
p = s.str; p = s.str;
ep = s.str+s.len; ep = s.str+s.len;
n = 0; n = 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment