| // Copyright 2009 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| #include <u.h> | |
| #include <libc.h> | |
| #include "go.h" | |
| #include "md5.h" | |
| #include "y.tab.h" | |
| #include "yerr.h" | |
| typedef struct Error Error; | |
| struct Error | |
| { | |
| int lineno; | |
| int seq; | |
| char *msg; | |
| }; | |
| static Error *err; | |
| static int nerr; | |
| static int merr; | |
| void | |
| errorexit(void) | |
| { | |
| flusherrors(); | |
| if(outfile) | |
| remove(outfile); | |
| exits("error"); | |
| } | |
| extern int yychar; | |
| int | |
| parserline(void) | |
| { | |
| if(yychar != 0 && yychar != -2) // parser has one symbol lookahead | |
| return prevlineno; | |
| return lineno; | |
| } | |
| static void | |
| adderr(int line, char *fmt, va_list arg) | |
| { | |
| Fmt f; | |
| Error *p; | |
| fmtstrinit(&f); | |
| fmtprint(&f, "%L: ", line); | |
| fmtvprint(&f, fmt, arg); | |
| fmtprint(&f, "\n"); | |
| if(nerr >= merr) { | |
| if(merr == 0) | |
| merr = 16; | |
| else | |
| merr *= 2; | |
| p = realloc(err, merr*sizeof err[0]); | |
| if(p == nil) { | |
| merr = nerr; | |
| flusherrors(); | |
| print("out of memory\n"); | |
| errorexit(); | |
| } | |
| err = p; | |
| } | |
| err[nerr].seq = nerr; | |
| err[nerr].lineno = line; | |
| err[nerr].msg = fmtstrflush(&f); | |
| nerr++; | |
| } | |
| static int | |
| errcmp(const void *va, const void *vb) | |
| { | |
| Error *a, *b; | |
| a = (Error*)va; | |
| b = (Error*)vb; | |
| if(a->lineno != b->lineno) | |
| return a->lineno - b->lineno; | |
| if(a->seq != b->seq) | |
| return a->seq - b->seq; | |
| return strcmp(a->msg, b->msg); | |
| } | |
| void | |
| flusherrors(void) | |
| { | |
| int i; | |
| if(nerr == 0) | |
| return; | |
| qsort(err, nerr, sizeof err[0], errcmp); | |
| for(i=0; i<nerr; i++) | |
| if(i==0 || strcmp(err[i].msg, err[i-1].msg) != 0) | |
| print("%s", err[i].msg); | |
| nerr = 0; | |
| } | |
| static void | |
| hcrash(void) | |
| { | |
| if(debug['h']) { | |
| flusherrors(); | |
| if(outfile) | |
| remove(outfile); | |
| *(volatile int*)0 = 0; | |
| } | |
| } | |
| void | |
| yyerrorl(int line, char *fmt, ...) | |
| { | |
| va_list arg; | |
| va_start(arg, fmt); | |
| adderr(line, fmt, arg); | |
| va_end(arg); | |
| hcrash(); | |
| nerrors++; | |
| if(nerrors >= 10 && !debug['e']) { | |
| flusherrors(); | |
| print("%L: too many errors\n", line); | |
| errorexit(); | |
| } | |
| } | |
| extern int yystate, yychar; | |
| void | |
| yyerror(char *fmt, ...) | |
| { | |
| int i; | |
| static int lastsyntax; | |
| va_list arg; | |
| char buf[512], *p; | |
| if(strncmp(fmt, "syntax error", 12) == 0) { | |
| nsyntaxerrors++; | |
| if(debug['x']) | |
| print("yyerror: yystate=%d yychar=%d\n", yystate, yychar); | |
| // only one syntax error per line | |
| if(lastsyntax == lexlineno) | |
| return; | |
| lastsyntax = lexlineno; | |
| if(strstr(fmt, "{ or {")) { | |
| // The grammar has { and LBRACE but both show up as {. | |
| // Rewrite syntax error referring to "{ or {" to say just "{". | |
| strecpy(buf, buf+sizeof buf, fmt); | |
| p = strstr(buf, "{ or {"); | |
| if(p) | |
| memmove(p+1, p+6, strlen(p+6)+1); | |
| fmt = buf; | |
| } | |
| // look for parse state-specific errors in list (see go.errors). | |
| for(i=0; i<nelem(yymsg); i++) { | |
| if(yymsg[i].yystate == yystate && yymsg[i].yychar == yychar) { | |
| yyerrorl(lexlineno, "syntax error: %s", yymsg[i].msg); | |
| return; | |
| } | |
| } | |
| // plain "syntax error" gets "near foo" added | |
| if(strcmp(fmt, "syntax error") == 0) { | |
| yyerrorl(lexlineno, "syntax error near %s", lexbuf); | |
| return; | |
| } | |
| // if bison says "syntax error, more info"; print "syntax error: more info". | |
| if(fmt[12] == ',') { | |
| yyerrorl(lexlineno, "syntax error:%s", fmt+13); | |
| return; | |
| } | |
| yyerrorl(lexlineno, "%s", fmt); | |
| return; | |
| } | |
| va_start(arg, fmt); | |
| adderr(parserline(), fmt, arg); | |
| va_end(arg); | |
| hcrash(); | |
| nerrors++; | |
| if(nerrors >= 10 && !debug['e']) { | |
| flusherrors(); | |
| print("%L: too many errors\n", parserline()); | |
| errorexit(); | |
| } | |
| } | |
| void | |
| warn(char *fmt, ...) | |
| { | |
| va_list arg; | |
| va_start(arg, fmt); | |
| adderr(parserline(), fmt, arg); | |
| va_end(arg); | |
| hcrash(); | |
| } | |
| void | |
| warnl(int line, char *fmt, ...) | |
| { | |
| va_list arg; | |
| va_start(arg, fmt); | |
| adderr(line, fmt, arg); | |
| va_end(arg); | |
| } | |
| void | |
| fatal(char *fmt, ...) | |
| { | |
| va_list arg; | |
| flusherrors(); | |
| print("%L: internal compiler error: ", lineno); | |
| va_start(arg, fmt); | |
| vfprint(1, fmt, arg); | |
| va_end(arg); | |
| print("\n"); | |
| // If this is a released compiler version, ask for a bug report. | |
| if(strncmp(getgoversion(), "release", 7) == 0) { | |
| print("\n"); | |
| print("Please file a bug report including a short program that triggers the error.\n"); | |
| print("http://code.google.com/p/go/issues/entry?template=compilerbug\n"); | |
| } | |
| hcrash(); | |
| errorexit(); | |
| } | |
| void | |
| linehist(char *file, int32 off, int relative) | |
| { | |
| Hist *h; | |
| char *cp; | |
| if(debug['i']) { | |
| if(file != nil) { | |
| if(off < 0) | |
| print("pragma %s", file); | |
| else | |
| if(off > 0) | |
| print("line %s", file); | |
| else | |
| print("import %s", file); | |
| } else | |
| print("end of import"); | |
| print(" at line %L\n", lexlineno); | |
| } | |
| if(off < 0 && file[0] != '/' && !relative) { | |
| cp = mal(strlen(file) + strlen(pathname) + 2); | |
| sprint(cp, "%s/%s", pathname, file); | |
| file = cp; | |
| } | |
| h = mal(sizeof(Hist)); | |
| h->name = file; | |
| h->line = lexlineno; | |
| h->offset = off; | |
| h->link = H; | |
| if(ehist == H) { | |
| hist = h; | |
| ehist = h; | |
| return; | |
| } | |
| ehist->link = h; | |
| ehist = h; | |
| } | |
| int32 | |
| setlineno(Node *n) | |
| { | |
| int32 lno; | |
| lno = lineno; | |
| if(n != N) | |
| switch(n->op) { | |
| case ONAME: | |
| case OTYPE: | |
| case OPACK: | |
| case OLITERAL: | |
| break; | |
| default: | |
| lineno = n->lineno; | |
| if(lineno == 0) { | |
| if(debug['K']) | |
| warn("setlineno: line 0"); | |
| lineno = lno; | |
| } | |
| } | |
| return lno; | |
| } | |
| uint32 | |
| stringhash(char *p) | |
| { | |
| int32 h; | |
| int c; | |
| h = 0; | |
| for(;;) { | |
| c = *p++; | |
| if(c == 0) | |
| break; | |
| h = h*PRIME1 + c; | |
| } | |
| if(h < 0) { | |
| h = -h; | |
| if(h < 0) | |
| h = 0; | |
| } | |
| return h; | |
| } | |
| Sym* | |
| lookup(char *name) | |
| { | |
| return pkglookup(name, localpkg); | |
| } | |
| Sym* | |
| pkglookup(char *name, Pkg *pkg) | |
| { | |
| Sym *s; | |
| uint32 h; | |
| int c; | |
| h = stringhash(name) % NHASH; | |
| c = name[0]; | |
| for(s = hash[h]; s != S; s = s->link) { | |
| if(s->name[0] != c || s->pkg != pkg) | |
| continue; | |
| if(strcmp(s->name, name) == 0) | |
| return s; | |
| } | |
| s = mal(sizeof(*s)); | |
| s->name = mal(strlen(name)+1); | |
| strcpy(s->name, name); | |
| s->pkg = pkg; | |
| s->link = hash[h]; | |
| hash[h] = s; | |
| s->lexical = LNAME; | |
| return s; | |
| } | |
| Sym* | |
| restrictlookup(char *name, Pkg *pkg) | |
| { | |
| if(!exportname(name) && pkg != localpkg) | |
| yyerror("cannot refer to unexported name %s.%s", pkg->name, name); | |
| return pkglookup(name, pkg); | |
| } | |
| // find all the exported symbols in package opkg | |
| // and make them available in the current package | |
| void | |
| importdot(Pkg *opkg, Node *pack) | |
| { | |
| Sym *s, *s1; | |
| uint32 h; | |
| int n; | |
| n = 0; | |
| for(h=0; h<NHASH; h++) { | |
| for(s = hash[h]; s != S; s = s->link) { | |
| if(s->pkg != opkg) | |
| continue; | |
| if(s->def == N) | |
| continue; | |
| if(!exportname(s->name) || utfrune(s->name, 0xb7)) // 0xb7 = center dot | |
| continue; | |
| s1 = lookup(s->name); | |
| if(s1->def != N) { | |
| redeclare(s1, "during import"); | |
| continue; | |
| } | |
| s1->def = s->def; | |
| s1->block = s->block; | |
| s1->def->pack = pack; | |
| n++; | |
| } | |
| } | |
| if(n == 0) { | |
| // can't possibly be used - there were no symbols | |
| yyerrorl(pack->lineno, "imported and not used: \"%Z\"", opkg->path); | |
| } | |
| } | |
| static void | |
| gethunk(void) | |
| { | |
| char *h; | |
| int32 nh; | |
| nh = NHUNK; | |
| if(thunk >= 10L*NHUNK) | |
| nh = 10L*NHUNK; | |
| h = (char*)malloc(nh); | |
| if(h == nil) { | |
| flusherrors(); | |
| yyerror("out of memory"); | |
| errorexit(); | |
| } | |
| hunk = h; | |
| nhunk = nh; | |
| thunk += nh; | |
| } | |
| void* | |
| mal(int32 n) | |
| { | |
| void *p; | |
| if(n >= NHUNK) { | |
| p = malloc(n); | |
| if(p == nil) { | |
| flusherrors(); | |
| yyerror("out of memory"); | |
| errorexit(); | |
| } | |
| memset(p, 0, n); | |
| return p; | |
| } | |
| while((uintptr)hunk & MAXALIGN) { | |
| hunk++; | |
| nhunk--; | |
| } | |
| if(nhunk < n) | |
| gethunk(); | |
| p = hunk; | |
| nhunk -= n; | |
| hunk += n; | |
| memset(p, 0, n); | |
| return p; | |
| } | |
| void* | |
| remal(void *p, int32 on, int32 n) | |
| { | |
| void *q; | |
| q = (uchar*)p + on; | |
| if(q != hunk || nhunk < n) { | |
| if(on+n >= NHUNK) { | |
| q = mal(on+n); | |
| memmove(q, p, on); | |
| return q; | |
| } | |
| if(nhunk < on+n) | |
| gethunk(); | |
| memmove(hunk, p, on); | |
| p = hunk; | |
| hunk += on; | |
| nhunk -= on; | |
| } | |
| hunk += n; | |
| nhunk -= n; | |
| return p; | |
| } | |
| Node* | |
| nod(int op, Node *nleft, Node *nright) | |
| { | |
| Node *n; | |
| n = mal(sizeof(*n)); | |
| n->op = op; | |
| n->left = nleft; | |
| n->right = nright; | |
| n->lineno = parserline(); | |
| n->xoffset = BADWIDTH; | |
| n->orig = n; | |
| n->curfn = curfn; | |
| return n; | |
| } | |
| int | |
| algtype(Type *t) | |
| { | |
| int a; | |
| if(issimple[t->etype] || isptr[t->etype] || | |
| t->etype == TCHAN || t->etype == TFUNC || t->etype == TMAP) { | |
| if(t->width == 1) | |
| a = AMEM8; | |
| else if(t->width == 2) | |
| a = AMEM16; | |
| else if(t->width == 4) | |
| a = AMEM32; | |
| else if(t->width == 8) | |
| a = AMEM64; | |
| else if(t->width == 16) | |
| a = AMEM128; | |
| else | |
| a = AMEM; // just bytes (int, ptr, etc) | |
| } else if(t->etype == TSTRING) | |
| a = ASTRING; // string | |
| else if(isnilinter(t)) | |
| a = ANILINTER; // nil interface | |
| else if(t->etype == TINTER) | |
| a = AINTER; // interface | |
| else if(isslice(t)) | |
| a = ASLICE; // slice | |
| else { | |
| if(t->width == 1) | |
| a = ANOEQ8; | |
| else if(t->width == 2) | |
| a = ANOEQ16; | |
| else if(t->width == 4) | |
| a = ANOEQ32; | |
| else if(t->width == 8) | |
| a = ANOEQ64; | |
| else if(t->width == 16) | |
| a = ANOEQ128; | |
| else | |
| a = ANOEQ; // just bytes, but no hash/eq | |
| } | |
| return a; | |
| } | |
| Type* | |
| maptype(Type *key, Type *val) | |
| { | |
| Type *t; | |
| if(key != nil) { | |
| switch(key->etype) { | |
| case TARRAY: | |
| case TSTRUCT: | |
| yyerror("invalid map key type %T", key); | |
| break; | |
| case TFORW: | |
| // map[key] used during definition of key. | |
| // postpone check until key is fully defined. | |
| // if there are multiple uses of map[key] | |
| // before key is fully defined, the error | |
| // will only be printed for the first one. | |
| // good enough. | |
| if(key->maplineno == 0) | |
| key->maplineno = lineno; | |
| break; | |
| } | |
| } | |
| t = typ(TMAP); | |
| t->down = key; | |
| t->type = val; | |
| return t; | |
| } | |
| Type* | |
| typ(int et) | |
| { | |
| Type *t; | |
| t = mal(sizeof(*t)); | |
| t->etype = et; | |
| t->width = BADWIDTH; | |
| t->lineno = lineno; | |
| t->orig = t; | |
| return t; | |
| } | |
| static int | |
| methcmp(const void *va, const void *vb) | |
| { | |
| Type *a, *b; | |
| int i; | |
| a = *(Type**)va; | |
| b = *(Type**)vb; | |
| i = strcmp(a->sym->name, b->sym->name); | |
| if(i != 0) | |
| return i; | |
| if(!exportname(a->sym->name)) { | |
| i = strcmp(a->sym->pkg->path->s, b->sym->pkg->path->s); | |
| if(i != 0) | |
| return i; | |
| } | |
| return 0; | |
| } | |
| Type* | |
| sortinter(Type *t) | |
| { | |
| Type *f; | |
| int i; | |
| Type **a; | |
| if(t->type == nil || t->type->down == nil) | |
| return t; | |
| i=0; | |
| for(f=t->type; f; f=f->down) | |
| i++; | |
| a = mal(i*sizeof f); | |
| i = 0; | |
| for(f=t->type; f; f=f->down) | |
| a[i++] = f; | |
| qsort(a, i, sizeof a[0], methcmp); | |
| while(i-- > 0) { | |
| a[i]->down = f; | |
| f = a[i]; | |
| } | |
| t->type = f; | |
| return t; | |
| } | |
| Node* | |
| nodintconst(int64 v) | |
| { | |
| Node *c; | |
| c = nod(OLITERAL, N, N); | |
| c->addable = 1; | |
| c->val.u.xval = mal(sizeof(*c->val.u.xval)); | |
| mpmovecfix(c->val.u.xval, v); | |
| c->val.ctype = CTINT; | |
| c->type = types[TIDEAL]; | |
| ullmancalc(c); | |
| return c; | |
| } | |
| Node* | |
| nodfltconst(Mpflt* v) | |
| { | |
| Node *c; | |
| c = nod(OLITERAL, N, N); | |
| c->addable = 1; | |
| c->val.u.fval = mal(sizeof(*c->val.u.fval)); | |
| mpmovefltflt(c->val.u.fval, v); | |
| c->val.ctype = CTFLT; | |
| c->type = types[TIDEAL]; | |
| ullmancalc(c); | |
| return c; | |
| } | |
| void | |
| nodconst(Node *n, Type *t, int64 v) | |
| { | |
| memset(n, 0, sizeof(*n)); | |
| n->op = OLITERAL; | |
| n->addable = 1; | |
| ullmancalc(n); | |
| n->val.u.xval = mal(sizeof(*n->val.u.xval)); | |
| mpmovecfix(n->val.u.xval, v); | |
| n->val.ctype = CTINT; | |
| n->type = t; | |
| if(isfloat[t->etype]) | |
| fatal("nodconst: bad type %T", t); | |
| } | |
| Node* | |
| nodnil(void) | |
| { | |
| Node *c; | |
| c = nodintconst(0); | |
| c->val.ctype = CTNIL; | |
| c->type = types[TNIL]; | |
| return c; | |
| } | |
| Node* | |
| nodbool(int b) | |
| { | |
| Node *c; | |
| c = nodintconst(0); | |
| c->val.ctype = CTBOOL; | |
| c->val.u.bval = b; | |
| c->type = idealbool; | |
| return c; | |
| } | |
| Type* | |
| aindex(Node *b, Type *t) | |
| { | |
| Type *r; | |
| int bound; | |
| bound = -1; // open bound | |
| typecheck(&b, Erv); | |
| if(b != nil) { | |
| switch(consttype(b)) { | |
| default: | |
| yyerror("array bound must be an integer expression"); | |
| break; | |
| case CTINT: | |
| bound = mpgetfix(b->val.u.xval); | |
| if(bound < 0) | |
| yyerror("array bound must be non negative"); | |
| break; | |
| } | |
| } | |
| // fixed array | |
| r = typ(TARRAY); | |
| r->type = t; | |
| r->bound = bound; | |
| return r; | |
| } | |
| Node* | |
| treecopy(Node *n) | |
| { | |
| Node *m; | |
| if(n == N) | |
| return N; | |
| switch(n->op) { | |
| default: | |
| m = nod(OXXX, N, N); | |
| *m = *n; | |
| m->left = treecopy(n->left); | |
| m->right = treecopy(n->right); | |
| m->list = listtreecopy(n->list); | |
| if(m->defn) | |
| abort(); | |
| break; | |
| case ONONAME: | |
| if(n->sym == lookup("iota")) { | |
| // Not sure yet whether this is the real iota, | |
| // but make a copy of the Node* just in case, | |
| // so that all the copies of this const definition | |
| // don't have the same iota value. | |
| m = nod(OXXX, N, N); | |
| *m = *n; | |
| m->iota = iota; | |
| break; | |
| } | |
| // fall through | |
| case ONAME: | |
| case OLITERAL: | |
| case OTYPE: | |
| m = n; | |
| break; | |
| } | |
| return m; | |
| } | |
| int | |
| isnil(Node *n) | |
| { | |
| if(n == N) | |
| return 0; | |
| if(n->op != OLITERAL) | |
| return 0; | |
| if(n->val.ctype != CTNIL) | |
| return 0; | |
| return 1; | |
| } | |
| int | |
| isptrto(Type *t, int et) | |
| { | |
| if(t == T) | |
| return 0; | |
| if(!isptr[t->etype]) | |
| return 0; | |
| t = t->type; | |
| if(t == T) | |
| return 0; | |
| if(t->etype != et) | |
| return 0; | |
| return 1; | |
| } | |
| int | |
| istype(Type *t, int et) | |
| { | |
| return t != T && t->etype == et; | |
| } | |
| int | |
| isfixedarray(Type *t) | |
| { | |
| return t != T && t->etype == TARRAY && t->bound >= 0; | |
| } | |
| int | |
| isslice(Type *t) | |
| { | |
| return t != T && t->etype == TARRAY && t->bound < 0; | |
| } | |
| int | |
| isblank(Node *n) | |
| { | |
| char *p; | |
| if(n == N || n->sym == S) | |
| return 0; | |
| p = n->sym->name; | |
| if(p == nil) | |
| return 0; | |
| return p[0] == '_' && p[1] == '\0'; | |
| } | |
| int | |
| isinter(Type *t) | |
| { | |
| return t != T && t->etype == TINTER; | |
| } | |
| int | |
| isnilinter(Type *t) | |
| { | |
| if(!isinter(t)) | |
| return 0; | |
| if(t->type != T) | |
| return 0; | |
| return 1; | |
| } | |
| int | |
| isideal(Type *t) | |
| { | |
| if(t == T) | |
| return 0; | |
| if(t == idealstring || t == idealbool) | |
| return 1; | |
| switch(t->etype) { | |
| case TNIL: | |
| case TIDEAL: | |
| return 1; | |
| } | |
| return 0; | |
| } | |
| /* | |
| * given receiver of type t (t == r or t == *r) | |
| * return type to hang methods off (r). | |
| */ | |
| Type* | |
| methtype(Type *t) | |
| { | |
| if(t == T) | |
| return T; | |
| // strip away pointer if it's there | |
| if(isptr[t->etype]) { | |
| if(t->sym != S) | |
| return T; | |
| t = t->type; | |
| if(t == T) | |
| return T; | |
| } | |
| // need a type name | |
| if(t->sym == S) | |
| return T; | |
| // check types | |
| if(!issimple[t->etype]) | |
| switch(t->etype) { | |
| default: | |
| return T; | |
| case TSTRUCT: | |
| case TARRAY: | |
| case TMAP: | |
| case TCHAN: | |
| case TSTRING: | |
| case TFUNC: | |
| break; | |
| } | |
| return t; | |
| } | |
| int | |
| cplxsubtype(int et) | |
| { | |
| switch(et) { | |
| case TCOMPLEX64: | |
| return TFLOAT32; | |
| case TCOMPLEX128: | |
| return TFLOAT64; | |
| } | |
| fatal("cplxsubtype: %E\n", et); | |
| return 0; | |
| } | |
| static int | |
| eqnote(Strlit *a, Strlit *b) | |
| { | |
| if(a == b) | |
| return 1; | |
| if(a == nil || b == nil) | |
| return 0; | |
| if(a->len != b->len) | |
| return 0; | |
| return memcmp(a->s, b->s, a->len) == 0; | |
| } | |
| // Return 1 if t1 and t2 are identical, following the spec rules. | |
| // | |
| // Any cyclic type must go through a named type, and if one is | |
| // named, it is only identical to the other if they are the same | |
| // pointer (t1 == t2), so there's no chance of chasing cycles | |
| // ad infinitum, so no need for a depth counter. | |
| int | |
| eqtype(Type *t1, Type *t2) | |
| { | |
| if(t1 == t2) | |
| return 1; | |
| if(t1 == T || t2 == T || t1->etype != t2->etype) | |
| return 0; | |
| if(t1->sym || t2->sym) { | |
| // Special case: we keep byte and uint8 separate | |
| // for error messages. Treat them as equal. | |
| switch(t1->etype) { | |
| case TUINT8: | |
| if((t1 == types[TUINT8] || t1 == bytetype) && (t2 == types[TUINT8] || t2 == bytetype)) | |
| return 1; | |
| break; | |
| case TINT: | |
| case TINT32: | |
| if((t1 == types[runetype->etype] || t1 == runetype) && (t2 == types[runetype->etype] || t2 == runetype)) | |
| return 1; | |
| break; | |
| } | |
| return 0; | |
| } | |
| switch(t1->etype) { | |
| case TINTER: | |
| case TSTRUCT: | |
| for(t1=t1->type, t2=t2->type; t1 && t2; t1=t1->down, t2=t2->down) { | |
| if(t1->etype != TFIELD || t2->etype != TFIELD) | |
| fatal("struct/interface missing field: %T %T", t1, t2); | |
| if(t1->sym != t2->sym || t1->embedded != t2->embedded || !eqtype(t1->type, t2->type) || !eqnote(t1->note, t2->note)) | |
| return 0; | |
| } | |
| return t1 == T && t2 == T; | |
| case TFUNC: | |
| // Loop over structs: receiver, in, out. | |
| for(t1=t1->type, t2=t2->type; t1 && t2; t1=t1->down, t2=t2->down) { | |
| Type *ta, *tb; | |
| if(t1->etype != TSTRUCT || t2->etype != TSTRUCT) | |
| fatal("func missing struct: %T %T", t1, t2); | |
| // Loop over fields in structs, ignoring argument names. | |
| for(ta=t1->type, tb=t2->type; ta && tb; ta=ta->down, tb=tb->down) { | |
| if(ta->etype != TFIELD || tb->etype != TFIELD) | |
| fatal("func struct missing field: %T %T", ta, tb); | |
| if(ta->isddd != tb->isddd || !eqtype(ta->type, tb->type)) | |
| return 0; | |
| } | |
| if(ta != T || tb != T) | |
| return 0; | |
| } | |
| return t1 == T && t2 == T; | |
| case TARRAY: | |
| if(t1->bound != t2->bound) | |
| return 0; | |
| break; | |
| case TCHAN: | |
| if(t1->chan != t2->chan) | |
| return 0; | |
| break; | |
| } | |
| return eqtype(t1->down, t2->down) && eqtype(t1->type, t2->type); | |
| } | |
| // Are t1 and t2 equal struct types when field names are ignored? | |
| // For deciding whether the result struct from g can be copied | |
| // directly when compiling f(g()). | |
| int | |
| eqtypenoname(Type *t1, Type *t2) | |
| { | |
| if(t1 == T || t2 == T || t1->etype != TSTRUCT || t2->etype != TSTRUCT) | |
| return 0; | |
| t1 = t1->type; | |
| t2 = t2->type; | |
| for(;;) { | |
| if(!eqtype(t1, t2)) | |
| return 0; | |
| if(t1 == T) | |
| return 1; | |
| t1 = t1->down; | |
| t2 = t2->down; | |
| } | |
| } | |
| // Is type src assignment compatible to type dst? | |
| // If so, return op code to use in conversion. | |
| // If not, return 0. | |
| // | |
| // It is the caller's responsibility to call exportassignok | |
| // to check for assignments to other packages' unexported fields, | |
| int | |
| assignop(Type *src, Type *dst, char **why) | |
| { | |
| Type *missing, *have; | |
| int ptr; | |
| if(why != nil) | |
| *why = ""; | |
| if(safemode && src != T && src->etype == TUNSAFEPTR) { | |
| yyerror("cannot use unsafe.Pointer"); | |
| errorexit(); | |
| } | |
| if(src == dst) | |
| return OCONVNOP; | |
| if(src == T || dst == T || src->etype == TFORW || dst->etype == TFORW || src->orig == T || dst->orig == T) | |
| return 0; | |
| // 1. src type is identical to dst. | |
| if(eqtype(src, dst)) | |
| return OCONVNOP; | |
| // 2. src and dst have identical underlying types | |
| // and either src or dst is not a named type or | |
| // both are interface types. | |
| if(eqtype(src->orig, dst->orig) && (src->sym == S || dst->sym == S || src->etype == TINTER)) | |
| return OCONVNOP; | |
| // 3. dst is an interface type and src implements dst. | |
| if(dst->etype == TINTER && src->etype != TNIL) { | |
| if(implements(src, dst, &missing, &have, &ptr)) | |
| return OCONVIFACE; | |
| // we'll have complained about this method anyway, supress spurious messages. | |
| if(have && have->sym == missing->sym && (have->type->broke || missing->type->broke)) | |
| return OCONVIFACE; | |
| if(why != nil) { | |
| if(isptrto(src, TINTER)) | |
| *why = smprint(":\n\t%T is pointer to interface, not interface", src); | |
| else if(have && have->sym == missing->sym) | |
| *why = smprint(":\n\t%T does not implement %T (wrong type for %S method)\n" | |
| "\t\thave %S%hhT\n\t\twant %S%hhT", src, dst, missing->sym, | |
| have->sym, have->type, missing->sym, missing->type); | |
| else if(ptr) | |
| *why = smprint(":\n\t%T does not implement %T (%S method requires pointer receiver)", | |
| src, dst, missing->sym); | |
| else if(have) | |
| *why = smprint(":\n\t%T does not implement %T (missing %S method)\n" | |
| "\t\thave %S%hhT\n\t\twant %S%hhT", src, dst, missing->sym, | |
| have->sym, have->type, missing->sym, missing->type); | |
| else | |
| *why = smprint(":\n\t%T does not implement %T (missing %S method)", | |
| src, dst, missing->sym); | |
| } | |
| return 0; | |
| } | |
| if(isptrto(dst, TINTER)) { | |
| if(why != nil) | |
| *why = smprint(":\n\t%T is pointer to interface, not interface", dst); | |
| return 0; | |
| } | |
| if(src->etype == TINTER && dst->etype != TBLANK) { | |
| if(why != nil) | |
| *why = ": need type assertion"; | |
| return 0; | |
| } | |
| // 4. src is a bidirectional channel value, dst is a channel type, | |
| // src and dst have identical element types, and | |
| // either src or dst is not a named type. | |
| if(src->etype == TCHAN && src->chan == Cboth && dst->etype == TCHAN) | |
| if(eqtype(src->type, dst->type) && (src->sym == S || dst->sym == S)) | |
| return OCONVNOP; | |
| // 5. src is the predeclared identifier nil and dst is a nillable type. | |
| if(src->etype == TNIL) { | |
| switch(dst->etype) { | |
| case TARRAY: | |
| if(dst->bound != -100) // not slice | |
| break; | |
| case TPTR32: | |
| case TPTR64: | |
| case TFUNC: | |
| case TMAP: | |
| case TCHAN: | |
| case TINTER: | |
| return OCONVNOP; | |
| } | |
| } | |
| // 6. rule about untyped constants - already converted by defaultlit. | |
| // 7. Any typed value can be assigned to the blank identifier. | |
| if(dst->etype == TBLANK) | |
| return OCONVNOP; | |
| return 0; | |
| } | |
| // Can we convert a value of type src to a value of type dst? | |
| // If so, return op code to use in conversion (maybe OCONVNOP). | |
| // If not, return 0. | |
| int | |
| convertop(Type *src, Type *dst, char **why) | |
| { | |
| int op; | |
| if(why != nil) | |
| *why = ""; | |
| if(src == dst) | |
| return OCONVNOP; | |
| if(src == T || dst == T) | |
| return 0; | |
| // 1. src can be assigned to dst. | |
| if((op = assignop(src, dst, why)) != 0) | |
| return op; | |
| // The rules for interfaces are no different in conversions | |
| // than assignments. If interfaces are involved, stop now | |
| // with the good message from assignop. | |
| // Otherwise clear the error. | |
| if(src->etype == TINTER || dst->etype == TINTER) | |
| return 0; | |
| if(why != nil) | |
| *why = ""; | |
| // 2. src and dst have identical underlying types. | |
| if(eqtype(src->orig, dst->orig)) | |
| return OCONVNOP; | |
| // 3. src and dst are unnamed pointer types | |
| // and their base types have identical underlying types. | |
| if(isptr[src->etype] && isptr[dst->etype] && src->sym == S && dst->sym == S) | |
| if(eqtype(src->type->orig, dst->type->orig)) | |
| return OCONVNOP; | |
| // 4. src and dst are both integer or floating point types. | |
| if((isint[src->etype] || isfloat[src->etype]) && (isint[dst->etype] || isfloat[dst->etype])) { | |
| if(simtype[src->etype] == simtype[dst->etype]) | |
| return OCONVNOP; | |
| return OCONV; | |
| } | |
| // 5. src and dst are both complex types. | |
| if(iscomplex[src->etype] && iscomplex[dst->etype]) { | |
| if(simtype[src->etype] == simtype[dst->etype]) | |
| return OCONVNOP; | |
| return OCONV; | |
| } | |
| // 6. src is an integer or has type []byte or []rune | |
| // and dst is a string type. | |
| if(isint[src->etype] && dst->etype == TSTRING) | |
| return ORUNESTR; | |
| if(isslice(src) && src->sym == nil && dst->etype == TSTRING) { | |
| if(eqtype(src->type, bytetype)) | |
| return OARRAYBYTESTR; | |
| if(eqtype(src->type, runetype)) | |
| return OARRAYRUNESTR; | |
| } | |
| // 7. src is a string and dst is []byte or []rune. | |
| // String to slice. | |
| if(src->etype == TSTRING && isslice(dst) && dst->sym == nil) { | |
| if(eqtype(dst->type, bytetype)) | |
| return OSTRARRAYBYTE; | |
| if(eqtype(dst->type, runetype)) | |
| return OSTRARRAYRUNE; | |
| } | |
| // 8. src is a pointer or uintptr and dst is unsafe.Pointer. | |
| if((isptr[src->etype] || src->etype == TUINTPTR) && dst->etype == TUNSAFEPTR) | |
| return OCONVNOP; | |
| // 9. src is unsafe.Pointer and dst is a pointer or uintptr. | |
| if(src->etype == TUNSAFEPTR && (isptr[dst->etype] || dst->etype == TUINTPTR)) | |
| return OCONVNOP; | |
| return 0; | |
| } | |
| // Convert node n for assignment to type t. | |
| Node* | |
| assignconv(Node *n, Type *t, char *context) | |
| { | |
| int op; | |
| Node *r, *old; | |
| char *why; | |
| if(n == N || n->type == T) | |
| return n; | |
| old = n; | |
| old->diag++; // silence errors about n; we'll issue one below | |
| defaultlit(&n, t); | |
| old->diag--; | |
| if(t->etype == TBLANK) | |
| return n; | |
| exportassignok(n->type, context); | |
| if(eqtype(n->type, t)) | |
| return n; | |
| op = assignop(n->type, t, &why); | |
| if(op == 0) { | |
| yyerror("cannot use %lN as type %T in %s%s", n, t, context, why); | |
| op = OCONV; | |
| } | |
| r = nod(op, n, N); | |
| r->type = t; | |
| r->typecheck = 1; | |
| r->implicit = 1; | |
| return r; | |
| } | |
| static int | |
| subtype(Type **stp, Type *t, int d) | |
| { | |
| Type *st; | |
| loop: | |
| st = *stp; | |
| if(st == T) | |
| return 0; | |
| d++; | |
| if(d >= 10) | |
| return 0; | |
| switch(st->etype) { | |
| default: | |
| return 0; | |
| case TPTR32: | |
| case TPTR64: | |
| case TCHAN: | |
| case TARRAY: | |
| stp = &st->type; | |
| goto loop; | |
| case TANY: | |
| if(!st->copyany) | |
| return 0; | |
| *stp = t; | |
| break; | |
| case TMAP: | |
| if(subtype(&st->down, t, d)) | |
| break; | |
| stp = &st->type; | |
| goto loop; | |
| case TFUNC: | |
| for(;;) { | |
| if(subtype(&st->type, t, d)) | |
| break; | |
| if(subtype(&st->type->down->down, t, d)) | |
| break; | |
| if(subtype(&st->type->down, t, d)) | |
| break; | |
| return 0; | |
| } | |
| break; | |
| case TSTRUCT: | |
| for(st=st->type; st!=T; st=st->down) | |
| if(subtype(&st->type, t, d)) | |
| return 1; | |
| return 0; | |
| } | |
| return 1; | |
| } | |
| /* | |
| * Is this a 64-bit type? | |
| */ | |
| int | |
| is64(Type *t) | |
| { | |
| if(t == T) | |
| return 0; | |
| switch(simtype[t->etype]) { | |
| case TINT64: | |
| case TUINT64: | |
| case TPTR64: | |
| return 1; | |
| } | |
| return 0; | |
| } | |
| /* | |
| * Is a conversion between t1 and t2 a no-op? | |
| */ | |
| int | |
| noconv(Type *t1, Type *t2) | |
| { | |
| int e1, e2; | |
| e1 = simtype[t1->etype]; | |
| e2 = simtype[t2->etype]; | |
| switch(e1) { | |
| case TINT8: | |
| case TUINT8: | |
| return e2 == TINT8 || e2 == TUINT8; | |
| case TINT16: | |
| case TUINT16: | |
| return e2 == TINT16 || e2 == TUINT16; | |
| case TINT32: | |
| case TUINT32: | |
| case TPTR32: | |
| return e2 == TINT32 || e2 == TUINT32 || e2 == TPTR32; | |
| case TINT64: | |
| case TUINT64: | |
| case TPTR64: | |
| return e2 == TINT64 || e2 == TUINT64 || e2 == TPTR64; | |
| case TFLOAT32: | |
| return e2 == TFLOAT32; | |
| case TFLOAT64: | |
| return e2 == TFLOAT64; | |
| } | |
| return 0; | |
| } | |
| void | |
| argtype(Node *on, Type *t) | |
| { | |
| dowidth(t); | |
| if(!subtype(&on->type, t, 0)) | |
| fatal("argtype: failed %N %T\n", on, t); | |
| } | |
| Type* | |
| shallow(Type *t) | |
| { | |
| Type *nt; | |
| if(t == T) | |
| return T; | |
| nt = typ(0); | |
| *nt = *t; | |
| if(t->orig == t) | |
| nt->orig = nt; | |
| return nt; | |
| } | |
| static Type* | |
| deep(Type *t) | |
| { | |
| Type *nt, *xt; | |
| if(t == T) | |
| return T; | |
| switch(t->etype) { | |
| default: | |
| nt = t; // share from here down | |
| break; | |
| case TANY: | |
| nt = shallow(t); | |
| nt->copyany = 1; | |
| break; | |
| case TPTR32: | |
| case TPTR64: | |
| case TCHAN: | |
| case TARRAY: | |
| nt = shallow(t); | |
| nt->type = deep(t->type); | |
| break; | |
| case TMAP: | |
| nt = shallow(t); | |
| nt->down = deep(t->down); | |
| nt->type = deep(t->type); | |
| break; | |
| case TFUNC: | |
| nt = shallow(t); | |
| nt->type = deep(t->type); | |
| nt->type->down = deep(t->type->down); | |
| nt->type->down->down = deep(t->type->down->down); | |
| break; | |
| case TSTRUCT: | |
| nt = shallow(t); | |
| nt->type = shallow(t->type); | |
| xt = nt->type; | |
| for(t=t->type; t!=T; t=t->down) { | |
| xt->type = deep(t->type); | |
| xt->down = shallow(t->down); | |
| xt = xt->down; | |
| } | |
| break; | |
| } | |
| return nt; | |
| } | |
| Node* | |
| syslook(char *name, int copy) | |
| { | |
| Sym *s; | |
| Node *n; | |
| s = pkglookup(name, runtimepkg); | |
| if(s == S || s->def == N) | |
| fatal("syslook: can't find runtime.%s", name); | |
| if(!copy) | |
| return s->def; | |
| n = nod(0, N, N); | |
| *n = *s->def; | |
| n->type = deep(s->def->type); | |
| return n; | |
| } | |
| /* | |
| * compute a hash value for type t. | |
| * if t is a method type, ignore the receiver | |
| * so that the hash can be used in interface checks. | |
| * %T already contains | |
| * all the necessary logic to generate a representation | |
| * of the type that completely describes it. | |
| * using smprint here avoids duplicating that code. | |
| * using md5 here is overkill, but i got tired of | |
| * accidental collisions making the runtime think | |
| * two types are equal when they really aren't. | |
| */ | |
| uint32 | |
| typehash(Type *t) | |
| { | |
| char *p; | |
| MD5 d; | |
| if(t->thistuple) { | |
| // hide method receiver from Tpretty | |
| t->thistuple = 0; | |
| p = smprint("%-uT", t); | |
| t->thistuple = 1; | |
| } else | |
| p = smprint("%-uT", t); | |
| //print("typehash: %s\n", p); | |
| md5reset(&d); | |
| md5write(&d, (uchar*)p, strlen(p)); | |
| free(p); | |
| return md5sum(&d); | |
| } | |
| Type* | |
| ptrto(Type *t) | |
| { | |
| Type *t1; | |
| if(tptr == 0) | |
| fatal("ptrto: no tptr"); | |
| t1 = typ(tptr); | |
| t1->type = t; | |
| t1->width = widthptr; | |
| t1->align = widthptr; | |
| return t1; | |
| } | |
| void | |
| frame(int context) | |
| { | |
| char *p; | |
| NodeList *l; | |
| Node *n; | |
| int flag; | |
| p = "stack"; | |
| l = nil; | |
| if(curfn) | |
| l = curfn->dcl; | |
| if(context) { | |
| p = "external"; | |
| l = externdcl; | |
| } | |
| flag = 1; | |
| for(; l; l=l->next) { | |
| n = l->n; | |
| switch(n->op) { | |
| case ONAME: | |
| if(flag) | |
| print("--- %s frame ---\n", p); | |
| print("%O %S G%d %T\n", n->op, n->sym, n->vargen, n->type); | |
| flag = 0; | |
| break; | |
| case OTYPE: | |
| if(flag) | |
| print("--- %s frame ---\n", p); | |
| print("%O %T\n", n->op, n->type); | |
| flag = 0; | |
| break; | |
| } | |
| } | |
| } | |
| /* | |
| * calculate sethi/ullman number | |
| * roughly how many registers needed to | |
| * compile a node. used to compile the | |
| * hardest side first to minimize registers. | |
| */ | |
| void | |
| ullmancalc(Node *n) | |
| { | |
| int ul, ur; | |
| if(n == N) | |
| return; | |
| switch(n->op) { | |
| case OREGISTER: | |
| case OLITERAL: | |
| case ONAME: | |
| ul = 1; | |
| if(n->class == PPARAMREF || (n->class & PHEAP)) | |
| ul++; | |
| goto out; | |
| case OCALL: | |
| case OCALLFUNC: | |
| case OCALLMETH: | |
| case OCALLINTER: | |
| ul = UINF; | |
| goto out; | |
| } | |
| ul = 1; | |
| if(n->left != N) | |
| ul = n->left->ullman; | |
| ur = 1; | |
| if(n->right != N) | |
| ur = n->right->ullman; | |
| if(ul == ur) | |
| ul += 1; | |
| if(ur > ul) | |
| ul = ur; | |
| out: | |
| n->ullman = ul; | |
| } | |
| void | |
| badtype(int o, Type *tl, Type *tr) | |
| { | |
| Fmt fmt; | |
| char *s; | |
| fmtstrinit(&fmt); | |
| if(tl != T) | |
| fmtprint(&fmt, "\n %T", tl); | |
| if(tr != T) | |
| fmtprint(&fmt, "\n %T", tr); | |
| // common mistake: *struct and *interface. | |
| if(tl && tr && isptr[tl->etype] && isptr[tr->etype]) { | |
| if(tl->type->etype == TSTRUCT && tr->type->etype == TINTER) | |
| fmtprint(&fmt, "\n (*struct vs *interface)"); | |
| else if(tl->type->etype == TINTER && tr->type->etype == TSTRUCT) | |
| fmtprint(&fmt, "\n (*interface vs *struct)"); | |
| } | |
| s = fmtstrflush(&fmt); | |
| yyerror("illegal types for operand: %O%s", o, s); | |
| } | |
| /* | |
| * iterator to walk a structure declaration | |
| */ | |
| Type* | |
| structfirst(Iter *s, Type **nn) | |
| { | |
| Type *n, *t; | |
| n = *nn; | |
| if(n == T) | |
| goto bad; | |
| switch(n->etype) { | |
| default: | |
| goto bad; | |
| case TSTRUCT: | |
| case TINTER: | |
| case TFUNC: | |
| break; | |
| } | |
| t = n->type; | |
| if(t == T) | |
| goto rnil; | |
| if(t->etype != TFIELD) | |
| fatal("structfirst: not field %T", t); | |
| s->t = t; | |
| return t; | |
| bad: | |
| fatal("structfirst: not struct %T", n); | |
| rnil: | |
| return T; | |
| } | |
| Type* | |
| structnext(Iter *s) | |
| { | |
| Type *n, *t; | |
| n = s->t; | |
| t = n->down; | |
| if(t == T) | |
| goto rnil; | |
| if(t->etype != TFIELD) | |
| goto bad; | |
| s->t = t; | |
| return t; | |
| bad: | |
| fatal("structnext: not struct %T", n); | |
| rnil: | |
| return T; | |
| } | |
| /* | |
| * iterator to this and inargs in a function | |
| */ | |
| Type* | |
| funcfirst(Iter *s, Type *t) | |
| { | |
| Type *fp; | |
| if(t == T) | |
| goto bad; | |
| if(t->etype != TFUNC) | |
| goto bad; | |
| s->tfunc = t; | |
| s->done = 0; | |
| fp = structfirst(s, getthis(t)); | |
| if(fp == T) { | |
| s->done = 1; | |
| fp = structfirst(s, getinarg(t)); | |
| } | |
| return fp; | |
| bad: | |
| fatal("funcfirst: not func %T", t); | |
| return T; | |
| } | |
| Type* | |
| funcnext(Iter *s) | |
| { | |
| Type *fp; | |
| fp = structnext(s); | |
| if(fp == T && !s->done) { | |
| s->done = 1; | |
| fp = structfirst(s, getinarg(s->tfunc)); | |
| } | |
| return fp; | |
| } | |
| Type** | |
| getthis(Type *t) | |
| { | |
| if(t->etype != TFUNC) | |
| fatal("getthis: not a func %T", t); | |
| return &t->type; | |
| } | |
| Type** | |
| getoutarg(Type *t) | |
| { | |
| if(t->etype != TFUNC) | |
| fatal("getoutarg: not a func %T", t); | |
| return &t->type->down; | |
| } | |
| Type** | |
| getinarg(Type *t) | |
| { | |
| if(t->etype != TFUNC) | |
| fatal("getinarg: not a func %T", t); | |
| return &t->type->down->down; | |
| } | |
| Type* | |
| getthisx(Type *t) | |
| { | |
| return *getthis(t); | |
| } | |
| Type* | |
| getoutargx(Type *t) | |
| { | |
| return *getoutarg(t); | |
| } | |
| Type* | |
| getinargx(Type *t) | |
| { | |
| return *getinarg(t); | |
| } | |
| /* | |
| * return !(op) | |
| * eg == <=> != | |
| */ | |
| int | |
| brcom(int a) | |
| { | |
| switch(a) { | |
| case OEQ: return ONE; | |
| case ONE: return OEQ; | |
| case OLT: return OGE; | |
| case OGT: return OLE; | |
| case OLE: return OGT; | |
| case OGE: return OLT; | |
| } | |
| fatal("brcom: no com for %A\n", a); | |
| return a; | |
| } | |
| /* | |
| * return reverse(op) | |
| * eg a op b <=> b r(op) a | |
| */ | |
| int | |
| brrev(int a) | |
| { | |
| switch(a) { | |
| case OEQ: return OEQ; | |
| case ONE: return ONE; | |
| case OLT: return OGT; | |
| case OGT: return OLT; | |
| case OLE: return OGE; | |
| case OGE: return OLE; | |
| } | |
| fatal("brcom: no rev for %A\n", a); | |
| return a; | |
| } | |
| /* | |
| * return side effect-free n, appending side effects to init. | |
| * result is assignable if n is. | |
| */ | |
| Node* | |
| safeexpr(Node *n, NodeList **init) | |
| { | |
| Node *l; | |
| Node *r; | |
| Node *a; | |
| if(n == N) | |
| return N; | |
| switch(n->op) { | |
| case ONAME: | |
| case OLITERAL: | |
| return n; | |
| case ODOT: | |
| l = safeexpr(n->left, init); | |
| if(l == n->left) | |
| return n; | |
| r = nod(OXXX, N, N); | |
| *r = *n; | |
| r->left = l; | |
| typecheck(&r, Erv); | |
| walkexpr(&r, init); | |
| return r; | |
| case ODOTPTR: | |
| case OIND: | |
| l = safeexpr(n->left, init); | |
| if(l == n->left) | |
| return n; | |
| a = nod(OXXX, N, N); | |
| *a = *n; | |
| a->left = l; | |
| walkexpr(&a, init); | |
| return a; | |
| case OINDEX: | |
| case OINDEXMAP: | |
| l = safeexpr(n->left, init); | |
| r = safeexpr(n->right, init); | |
| if(l == n->left && r == n->right) | |
| return n; | |
| a = nod(OXXX, N, N); | |
| *a = *n; | |
| a->left = l; | |
| a->right = r; | |
| walkexpr(&a, init); | |
| return a; | |
| } | |
| // make a copy; must not be used as an lvalue | |
| if(islvalue(n)) | |
| fatal("missing lvalue case in safeexpr: %N", n); | |
| return cheapexpr(n, init); | |
| } | |
| static Node* | |
| copyexpr(Node *n, Type *t, NodeList **init) | |
| { | |
| Node *a, *l; | |
| l = temp(t); | |
| a = nod(OAS, l, n); | |
| typecheck(&a, Etop); | |
| walkexpr(&a, init); | |
| *init = list(*init, a); | |
| return l; | |
| } | |
| /* | |
| * return side-effect free and cheap n, appending side effects to init. | |
| * result may not be assignable. | |
| */ | |
| Node* | |
| cheapexpr(Node *n, NodeList **init) | |
| { | |
| switch(n->op) { | |
| case ONAME: | |
| case OLITERAL: | |
| return n; | |
| } | |
| return copyexpr(n, n->type, init); | |
| } | |
| /* | |
| * return n in a local variable of type t if it is not already. | |
| */ | |
| Node* | |
| localexpr(Node *n, Type *t, NodeList **init) | |
| { | |
| if(n->op == ONAME && | |
| (n->class == PAUTO || n->class == PPARAM || n->class == PPARAMOUT) && | |
| convertop(n->type, t, nil) == OCONVNOP) | |
| return n; | |
| return copyexpr(n, t, init); | |
| } | |
| void | |
| setmaxarg(Type *t) | |
| { | |
| int32 w; | |
| dowidth(t); | |
| w = t->argwid; | |
| if(t->argwid >= MAXWIDTH) | |
| fatal("bad argwid %T", t); | |
| if(w > maxarg) | |
| maxarg = w; | |
| } | |
| /* | |
| * unicode-aware case-insensitive strcmp | |
| */ | |
| static int | |
| ucistrcmp(char *p, char *q) | |
| { | |
| Rune rp, rq; | |
| while(*p || *q) { | |
| if(*p == 0) | |
| return +1; | |
| if(*q == 0) | |
| return -1; | |
| p += chartorune(&rp, p); | |
| q += chartorune(&rq, q); | |
| rp = tolowerrune(rp); | |
| rq = tolowerrune(rq); | |
| if(rp < rq) | |
| return -1; | |
| if(rp > rq) | |
| return +1; | |
| } | |
| return 0; | |
| } | |
| /* | |
| * code to resolve elided DOTs | |
| * in embedded types | |
| */ | |
| // search depth 0 -- | |
| // return count of fields+methods | |
| // found with a given name | |
| static int | |
| lookdot0(Sym *s, Type *t, Type **save, int ignorecase) | |
| { | |
| Type *f, *u; | |
| int c; | |
| u = t; | |
| if(isptr[u->etype]) | |
| u = u->type; | |
| c = 0; | |
| if(u->etype == TSTRUCT || u->etype == TINTER) { | |
| for(f=u->type; f!=T; f=f->down) | |
| if(f->sym == s || (ignorecase && ucistrcmp(f->sym->name, s->name) == 0)) { | |
| if(save) | |
| *save = f; | |
| c++; | |
| } | |
| } | |
| u = methtype(t); | |
| if(u != T) { | |
| for(f=u->method; f!=T; f=f->down) | |
| if(f->embedded == 0 && (f->sym == s || (ignorecase && ucistrcmp(f->sym->name, s->name) == 0))) { | |
| if(save) | |
| *save = f; | |
| c++; | |
| } | |
| } | |
| return c; | |
| } | |
| // search depth d -- | |
| // return count of fields+methods | |
| // found at search depth. | |
| // answer is in dotlist array and | |
| // count of number of ways is returned. | |
| int | |
| adddot1(Sym *s, Type *t, int d, Type **save, int ignorecase) | |
| { | |
| Type *f, *u; | |
| int c, a; | |
| if(t->trecur) | |
| return 0; | |
| t->trecur = 1; | |
| if(d == 0) { | |
| c = lookdot0(s, t, save, ignorecase); | |
| goto out; | |
| } | |
| c = 0; | |
| u = t; | |
| if(isptr[u->etype]) | |
| u = u->type; | |
| if(u->etype != TSTRUCT && u->etype != TINTER) | |
| goto out; | |
| d--; | |
| for(f=u->type; f!=T; f=f->down) { | |
| if(!f->embedded) | |
| continue; | |
| if(f->sym == S) | |
| continue; | |
| a = adddot1(s, f->type, d, save, ignorecase); | |
| if(a != 0 && c == 0) | |
| dotlist[d].field = f; | |
| c += a; | |
| } | |
| out: | |
| t->trecur = 0; | |
| return c; | |
| } | |
| // in T.field | |
| // find missing fields that | |
| // will give shortest unique addressing. | |
| // modify the tree with missing type names. | |
| Node* | |
| adddot(Node *n) | |
| { | |
| Type *t; | |
| Sym *s; | |
| int c, d; | |
| typecheck(&n->left, Etype|Erv); | |
| t = n->left->type; | |
| if(t == T) | |
| goto ret; | |
| if(n->left->op == OTYPE) | |
| goto ret; | |
| if(n->right->op != ONAME) | |
| goto ret; | |
| s = n->right->sym; | |
| if(s == S) | |
| goto ret; | |
| for(d=0; d<nelem(dotlist); d++) { | |
| c = adddot1(s, t, d, nil, 0); | |
| if(c > 0) | |
| goto out; | |
| } | |
| goto ret; | |
| out: | |
| if(c > 1) | |
| yyerror("ambiguous DOT reference %T.%S", t, s); | |
| // rebuild elided dots | |
| for(c=d-1; c>=0; c--) | |
| n->left = nod(ODOT, n->left, newname(dotlist[c].field->sym)); | |
| ret: | |
| return n; | |
| } | |
| /* | |
| * code to help generate trampoline | |
| * functions for methods on embedded | |
| * subtypes. | |
| * these are approx the same as | |
| * the corresponding adddot routines | |
| * except that they expect to be called | |
| * with unique tasks and they return | |
| * the actual methods. | |
| */ | |
| typedef struct Symlink Symlink; | |
| struct Symlink | |
| { | |
| Type* field; | |
| uchar good; | |
| uchar followptr; | |
| Symlink* link; | |
| }; | |
| static Symlink* slist; | |
| static void | |
| expand0(Type *t, int followptr) | |
| { | |
| Type *f, *u; | |
| Symlink *sl; | |
| u = t; | |
| if(isptr[u->etype]) { | |
| followptr = 1; | |
| u = u->type; | |
| } | |
| if(u->etype == TINTER) { | |
| for(f=u->type; f!=T; f=f->down) { | |
| if(!exportname(f->sym->name) && f->sym->pkg != localpkg) | |
| continue; | |
| if(f->sym->flags & SymUniq) | |
| continue; | |
| f->sym->flags |= SymUniq; | |
| sl = mal(sizeof(*sl)); | |
| sl->field = f; | |
| sl->link = slist; | |
| sl->followptr = followptr; | |
| slist = sl; | |
| } | |
| return; | |
| } | |
| u = methtype(t); | |
| if(u != T) { | |
| for(f=u->method; f!=T; f=f->down) { | |
| if(!exportname(f->sym->name) && f->sym->pkg != localpkg) | |
| continue; | |
| if(f->sym->flags & SymUniq) | |
| continue; | |
| f->sym->flags |= SymUniq; | |
| sl = mal(sizeof(*sl)); | |
| sl->field = f; | |
| sl->link = slist; | |
| sl->followptr = followptr; | |
| slist = sl; | |
| } | |
| } | |
| } | |
| static void | |
| expand1(Type *t, int d, int followptr) | |
| { | |
| Type *f, *u; | |
| if(t->trecur) | |
| return; | |
| if(d == 0) | |
| return; | |
| t->trecur = 1; | |
| if(d != nelem(dotlist)-1) | |
| expand0(t, followptr); | |
| u = t; | |
| if(isptr[u->etype]) { | |
| followptr = 1; | |
| u = u->type; | |
| } | |
| if(u->etype != TSTRUCT && u->etype != TINTER) | |
| goto out; | |
| for(f=u->type; f!=T; f=f->down) { | |
| if(!f->embedded) | |
| continue; | |
| if(f->sym == S) | |
| continue; | |
| expand1(f->type, d-1, followptr); | |
| } | |
| out: | |
| t->trecur = 0; | |
| } | |
| void | |
| expandmeth(Sym *s, Type *t) | |
| { | |
| Symlink *sl; | |
| Type *f; | |
| int c, d; | |
| if(s == S) | |
| return; | |
| if(t == T || t->xmethod != nil) | |
| return; | |
| // mark top-level method symbols | |
| // so that expand1 doesn't consider them. | |
| for(f=t->method; f != nil; f=f->down) | |
| f->sym->flags |= SymUniq; | |
| // generate all reachable methods | |
| slist = nil; | |
| expand1(t, nelem(dotlist)-1, 0); | |
| // check each method to be uniquely reachable | |
| for(sl=slist; sl!=nil; sl=sl->link) { | |
| sl->field->sym->flags &= ~SymUniq; | |
| for(d=0; d<nelem(dotlist); d++) { | |
| c = adddot1(sl->field->sym, t, d, &f, 0); | |
| if(c == 0) | |
| continue; | |
| if(c == 1) { | |
| // addot1 may have dug out arbitrary fields, we only want methods. | |
| if(f->type->etype == TFUNC && f->type->thistuple > 0) { | |
| sl->good = 1; | |
| sl->field = f; | |
| } | |
| } | |
| break; | |
| } | |
| } | |
| for(f=t->method; f != nil; f=f->down) | |
| f->sym->flags &= ~SymUniq; | |
| t->xmethod = t->method; | |
| for(sl=slist; sl!=nil; sl=sl->link) { | |
| if(sl->good) { | |
| // add it to the base type method list | |
| f = typ(TFIELD); | |
| *f = *sl->field; | |
| f->embedded = 1; // needs a trampoline | |
| if(sl->followptr) | |
| f->embedded = 2; | |
| f->down = t->xmethod; | |
| t->xmethod = f; | |
| } | |
| } | |
| } | |
| /* | |
| * Given funarg struct list, return list of ODCLFIELD Node fn args. | |
| */ | |
| static NodeList* | |
| structargs(Type **tl, int mustname) | |
| { | |
| Iter savet; | |
| Node *a, *n; | |
| NodeList *args; | |
| Type *t; | |
| char buf[100]; | |
| int gen; | |
| args = nil; | |
| gen = 0; | |
| for(t = structfirst(&savet, tl); t != T; t = structnext(&savet)) { | |
| n = N; | |
| if(t->sym) | |
| n = newname(t->sym); | |
| else if(mustname) { | |
| // have to give it a name so we can refer to it in trampoline | |
| snprint(buf, sizeof buf, ".anon%d", gen++); | |
| n = newname(lookup(buf)); | |
| } | |
| a = nod(ODCLFIELD, n, typenod(t->type)); | |
| a->isddd = t->isddd; | |
| if(n != N) | |
| n->isddd = t->isddd; | |
| args = list(args, a); | |
| } | |
| return args; | |
| } | |
| /* | |
| * Generate a wrapper function to convert from | |
| * a receiver of type T to a receiver of type U. | |
| * That is, | |
| * | |
| * func (t T) M() { | |
| * ... | |
| * } | |
| * | |
| * already exists; this function generates | |
| * | |
| * func (u U) M() { | |
| * u.M() | |
| * } | |
| * | |
| * where the types T and U are such that u.M() is valid | |
| * and calls the T.M method. | |
| * The resulting function is for use in method tables. | |
| * | |
| * rcvr - U | |
| * method - M func (t T)(), a TFIELD type struct | |
| * newnam - the eventual mangled name of this function | |
| */ | |
| void | |
| genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface) | |
| { | |
| Node *this, *fn, *call, *n, *t, *pad; | |
| NodeList *l, *args, *in, *out; | |
| Type *tpad; | |
| int isddd; | |
| Val v; | |
| if(0 && debug['r']) | |
| print("genwrapper rcvrtype=%T method=%T newnam=%S\n", | |
| rcvr, method, newnam); | |
| lineno = 1; // less confusing than end of input | |
| dclcontext = PEXTERN; | |
| markdcl(); | |
| this = nod(ODCLFIELD, newname(lookup(".this")), typenod(rcvr)); | |
| this->left->ntype = this->right; | |
| in = structargs(getinarg(method->type), 1); | |
| out = structargs(getoutarg(method->type), 0); | |
| fn = nod(ODCLFUNC, N, N); | |
| fn->nname = newname(newnam); | |
| t = nod(OTFUNC, N, N); | |
| l = list1(this); | |
| if(iface && rcvr->width < types[tptr]->width) { | |
| // Building method for interface table and receiver | |
| // is smaller than the single pointer-sized word | |
| // that the interface call will pass in. | |
| // Add a dummy padding argument after the | |
| // receiver to make up the difference. | |
| tpad = typ(TARRAY); | |
| tpad->type = types[TUINT8]; | |
| tpad->bound = types[tptr]->width - rcvr->width; | |
| pad = nod(ODCLFIELD, newname(lookup(".pad")), typenod(tpad)); | |
| l = list(l, pad); | |
| } | |
| t->list = concat(l, in); | |
| t->rlist = out; | |
| fn->nname->ntype = t; | |
| funchdr(fn); | |
| // arg list | |
| args = nil; | |
| isddd = 0; | |
| for(l=in; l; l=l->next) { | |
| args = list(args, l->n->left); | |
| isddd = l->n->left->isddd; | |
| } | |
| // generate nil pointer check for better error | |
| if(isptr[rcvr->etype] && rcvr->type == getthisx(method->type)->type->type) { | |
| // generating wrapper from *T to T. | |
| n = nod(OIF, N, N); | |
| n->ntest = nod(OEQ, this->left, nodnil()); | |
| // these strings are already in the reflect tables, | |
| // so no space cost to use them here. | |
| l = nil; | |
| v.ctype = CTSTR; | |
| v.u.sval = strlit(rcvr->type->sym->pkg->name); // package name | |
| l = list(l, nodlit(v)); | |
| v.u.sval = strlit(rcvr->type->sym->name); // type name | |
| l = list(l, nodlit(v)); | |
| v.u.sval = strlit(method->sym->name); | |
| l = list(l, nodlit(v)); // method name | |
| call = nod(OCALL, syslook("panicwrap", 0), N); | |
| call->list = l; | |
| n->nbody = list1(call); | |
| fn->nbody = list(fn->nbody, n); | |
| } | |
| // generate call | |
| call = nod(OCALL, adddot(nod(OXDOT, this->left, newname(method->sym))), N); | |
| call->list = args; | |
| call->isddd = isddd; | |
| if(method->type->outtuple > 0) { | |
| n = nod(ORETURN, N, N); | |
| n->list = list1(call); | |
| call = n; | |
| } | |
| fn->nbody = list(fn->nbody, call); | |
| if(0 && debug['r']) | |
| dumplist("genwrapper body", fn->nbody); | |
| funcbody(fn); | |
| curfn = fn; | |
| typecheck(&fn, Etop); | |
| typechecklist(fn->nbody, Etop); | |
| curfn = nil; | |
| funccompile(fn, 0); | |
| } | |
| static Type* | |
| ifacelookdot(Sym *s, Type *t, int *followptr, int ignorecase) | |
| { | |
| int i, c, d; | |
| Type *m; | |
| *followptr = 0; | |
| if(t == T) | |
| return T; | |
| for(d=0; d<nelem(dotlist); d++) { | |
| c = adddot1(s, t, d, &m, ignorecase); | |
| if(c > 1) { | |
| yyerror("%T.%S is ambiguous", t, s); | |
| return T; | |
| } | |
| if(c == 1) { | |
| for(i=0; i<d; i++) { | |
| if(isptr[dotlist[i].field->type->etype]) { | |
| *followptr = 1; | |
| break; | |
| } | |
| } | |
| if(m->type->etype != TFUNC || m->type->thistuple == 0) { | |
| yyerror("%T.%S is a field, not a method", t, s); | |
| return T; | |
| } | |
| return m; | |
| } | |
| } | |
| return T; | |
| } | |
| int | |
| implements(Type *t, Type *iface, Type **m, Type **samename, int *ptr) | |
| { | |
| Type *t0, *im, *tm, *rcvr, *imtype; | |
| int followptr; | |
| t0 = t; | |
| if(t == T) | |
| return 0; | |
| // if this is too slow, | |
| // could sort these first | |
| // and then do one loop. | |
| if(t->etype == TINTER) { | |
| for(im=iface->type; im; im=im->down) { | |
| for(tm=t->type; tm; tm=tm->down) { | |
| if(tm->sym == im->sym) { | |
| if(eqtype(tm->type, im->type)) | |
| goto found; | |
| *m = im; | |
| *samename = tm; | |
| *ptr = 0; | |
| return 0; | |
| } | |
| } | |
| *m = im; | |
| *samename = nil; | |
| *ptr = 0; | |
| return 0; | |
| found:; | |
| } | |
| return 1; | |
| } | |
| t = methtype(t); | |
| if(t != T) | |
| expandmeth(t->sym, t); | |
| for(im=iface->type; im; im=im->down) { | |
| imtype = methodfunc(im->type, 0); | |
| tm = ifacelookdot(im->sym, t, &followptr, 0); | |
| if(tm == T || !eqtype(methodfunc(tm->type, 0), imtype)) { | |
| if(tm == T) | |
| tm = ifacelookdot(im->sym, t, &followptr, 1); | |
| *m = im; | |
| *samename = tm; | |
| *ptr = 0; | |
| return 0; | |
| } | |
| // if pointer receiver in method, | |
| // the method does not exist for value types. | |
| rcvr = getthisx(tm->type)->type->type; | |
| if(isptr[rcvr->etype] && !isptr[t0->etype] && !followptr && !isifacemethod(tm->type)) { | |
| if(0 && debug['r']) | |
| yyerror("interface pointer mismatch"); | |
| *m = im; | |
| *samename = nil; | |
| *ptr = 1; | |
| return 0; | |
| } | |
| } | |
| return 1; | |
| } | |
| /* | |
| * even simpler simtype; get rid of ptr, bool. | |
| * assuming that the front end has rejected | |
| * all the invalid conversions (like ptr -> bool) | |
| */ | |
| int | |
| simsimtype(Type *t) | |
| { | |
| int et; | |
| if(t == 0) | |
| return 0; | |
| et = simtype[t->etype]; | |
| switch(et) { | |
| case TPTR32: | |
| et = TUINT32; | |
| break; | |
| case TPTR64: | |
| et = TUINT64; | |
| break; | |
| case TBOOL: | |
| et = TUINT8; | |
| break; | |
| } | |
| return et; | |
| } | |
| NodeList* | |
| concat(NodeList *a, NodeList *b) | |
| { | |
| if(a == nil) | |
| return b; | |
| if(b == nil) | |
| return a; | |
| a->end->next = b; | |
| a->end = b->end; | |
| b->end = nil; | |
| return a; | |
| } | |
| NodeList* | |
| list1(Node *n) | |
| { | |
| NodeList *l; | |
| if(n == nil) | |
| return nil; | |
| if(n->op == OBLOCK && n->ninit == nil) { | |
| // Flatten list and steal storage. | |
| // Poison pointer to catch errant uses. | |
| l = n->list; | |
| n->list = (NodeList*)1; | |
| return l; | |
| } | |
| l = mal(sizeof *l); | |
| l->n = n; | |
| l->end = l; | |
| return l; | |
| } | |
| NodeList* | |
| list(NodeList *l, Node *n) | |
| { | |
| return concat(l, list1(n)); | |
| } | |
| void | |
| listsort(NodeList** l, int(*f)(Node*, Node*)) | |
| { | |
| NodeList *l1, *l2, *le; | |
| if(*l == nil || (*l)->next == nil) | |
| return; | |
| l1 = *l; | |
| l2 = *l; | |
| for(;;) { | |
| l2 = l2->next; | |
| if(l2 == nil) | |
| break; | |
| l2 = l2->next; | |
| if(l2 == nil) | |
| break; | |
| l1 = l1->next; | |
| } | |
| l2 = l1->next; | |
| l1->next = nil; | |
| l2->end = (*l)->end; | |
| (*l)->end = l1; | |
| l1 = *l; | |
| listsort(&l1, f); | |
| listsort(&l2, f); | |
| if((*f)(l1->n, l2->n) < 0) { | |
| *l = l1; | |
| } else { | |
| *l = l2; | |
| l2 = l1; | |
| l1 = *l; | |
| } | |
| // now l1 == *l; and l1 < l2 | |
| while ((l1 != nil) && (l2 != nil)) { | |
| while ((l1->next != nil) && (*f)(l1->next->n, l2->n) < 0) | |
| l1 = l1->next; | |
| // l1 is last one from l1 that is < l2 | |
| le = l1->next; // le is the rest of l1, first one that is >= l2 | |
| if(le != nil) | |
| le->end = (*l)->end; | |
| (*l)->end = l1; // cut *l at l1 | |
| *l = concat(*l, l2); // glue l2 to *l's tail | |
| l1 = l2; // l1 is the first element of *l that is < the new l2 | |
| l2 = le; // ... because l2 now is the old tail of l1 | |
| } | |
| *l = concat(*l, l2); // any remainder | |
| } | |
| NodeList* | |
| listtreecopy(NodeList *l) | |
| { | |
| NodeList *out; | |
| out = nil; | |
| for(; l; l=l->next) | |
| out = list(out, treecopy(l->n)); | |
| return out; | |
| } | |
| Node* | |
| liststmt(NodeList *l) | |
| { | |
| Node *n; | |
| n = nod(OBLOCK, N, N); | |
| n->list = l; | |
| if(l) | |
| n->lineno = l->n->lineno; | |
| return n; | |
| } | |
| /* | |
| * return nelem of list | |
| */ | |
| int | |
| count(NodeList *l) | |
| { | |
| int n; | |
| n = 0; | |
| for(; l; l=l->next) | |
| n++; | |
| return n; | |
| } | |
| /* | |
| * return nelem of list | |
| */ | |
| int | |
| structcount(Type *t) | |
| { | |
| int v; | |
| Iter s; | |
| v = 0; | |
| for(t = structfirst(&s, &t); t != T; t = structnext(&s)) | |
| v++; | |
| return v; | |
| } | |
| /* | |
| * return power of 2 of the constant | |
| * operand. -1 if it is not a power of 2. | |
| * 1000+ if it is a -(power of 2) | |
| */ | |
| int | |
| powtwo(Node *n) | |
| { | |
| uvlong v, b; | |
| int i; | |
| if(n == N || n->op != OLITERAL || n->type == T) | |
| goto no; | |
| if(!isint[n->type->etype]) | |
| goto no; | |
| v = mpgetfix(n->val.u.xval); | |
| b = 1ULL; | |
| for(i=0; i<64; i++) { | |
| if(b == v) | |
| return i; | |
| b = b<<1; | |
| } | |
| if(!issigned[n->type->etype]) | |
| goto no; | |
| v = -v; | |
| b = 1ULL; | |
| for(i=0; i<64; i++) { | |
| if(b == v) | |
| return i+1000; | |
| b = b<<1; | |
| } | |
| no: | |
| return -1; | |
| } | |
| /* | |
| * return the unsigned type for | |
| * a signed integer type. | |
| * returns T if input is not a | |
| * signed integer type. | |
| */ | |
| Type* | |
| tounsigned(Type *t) | |
| { | |
| // this is types[et+1], but not sure | |
| // that this relation is immutable | |
| switch(t->etype) { | |
| default: | |
| print("tounsigned: unknown type %T\n", t); | |
| t = T; | |
| break; | |
| case TINT: | |
| t = types[TUINT]; | |
| break; | |
| case TINT8: | |
| t = types[TUINT8]; | |
| break; | |
| case TINT16: | |
| t = types[TUINT16]; | |
| break; | |
| case TINT32: | |
| t = types[TUINT32]; | |
| break; | |
| case TINT64: | |
| t = types[TUINT64]; | |
| break; | |
| } | |
| return t; | |
| } | |
| /* | |
| * magic number for signed division | |
| * see hacker's delight chapter 10 | |
| */ | |
| void | |
| smagic(Magic *m) | |
| { | |
| int p; | |
| uint64 ad, anc, delta, q1, r1, q2, r2, t; | |
| uint64 mask, two31; | |
| m->bad = 0; | |
| switch(m->w) { | |
| default: | |
| m->bad = 1; | |
| return; | |
| case 8: | |
| mask = 0xffLL; | |
| break; | |
| case 16: | |
| mask = 0xffffLL; | |
| break; | |
| case 32: | |
| mask = 0xffffffffLL; | |
| break; | |
| case 64: | |
| mask = 0xffffffffffffffffLL; | |
| break; | |
| } | |
| two31 = mask ^ (mask>>1); | |
| p = m->w-1; | |
| ad = m->sd; | |
| if(m->sd < 0) | |
| ad = -m->sd; | |
| // bad denominators | |
| if(ad == 0 || ad == 1 || ad == two31) { | |
| m->bad = 1; | |
| return; | |
| } | |
| t = two31; | |
| ad &= mask; | |
| anc = t - 1 - t%ad; | |
| anc &= mask; | |
| q1 = two31/anc; | |
| r1 = two31 - q1*anc; | |
| q1 &= mask; | |
| r1 &= mask; | |
| q2 = two31/ad; | |
| r2 = two31 - q2*ad; | |
| q2 &= mask; | |
| r2 &= mask; | |
| for(;;) { | |
| p++; | |
| q1 <<= 1; | |
| r1 <<= 1; | |
| q1 &= mask; | |
| r1 &= mask; | |
| if(r1 >= anc) { | |
| q1++; | |
| r1 -= anc; | |
| q1 &= mask; | |
| r1 &= mask; | |
| } | |
| q2 <<= 1; | |
| r2 <<= 1; | |
| q2 &= mask; | |
| r2 &= mask; | |
| if(r2 >= ad) { | |
| q2++; | |
| r2 -= ad; | |
| q2 &= mask; | |
| r2 &= mask; | |
| } | |
| delta = ad - r2; | |
| delta &= mask; | |
| if(q1 < delta || (q1 == delta && r1 == 0)) { | |
| continue; | |
| } | |
| break; | |
| } | |
| m->sm = q2+1; | |
| if(m->sm & two31) | |
| m->sm |= ~mask; | |
| m->s = p-m->w; | |
| } | |
| /* | |
| * magic number for unsigned division | |
| * see hacker's delight chapter 10 | |
| */ | |
| void | |
| umagic(Magic *m) | |
| { | |
| int p; | |
| uint64 nc, delta, q1, r1, q2, r2; | |
| uint64 mask, two31; | |
| m->bad = 0; | |
| m->ua = 0; | |
| switch(m->w) { | |
| default: | |
| m->bad = 1; | |
| return; | |
| case 8: | |
| mask = 0xffLL; | |
| break; | |
| case 16: | |
| mask = 0xffffLL; | |
| break; | |
| case 32: | |
| mask = 0xffffffffLL; | |
| break; | |
| case 64: | |
| mask = 0xffffffffffffffffLL; | |
| break; | |
| } | |
| two31 = mask ^ (mask>>1); | |
| m->ud &= mask; | |
| if(m->ud == 0 || m->ud == two31) { | |
| m->bad = 1; | |
| return; | |
| } | |
| nc = mask - (-m->ud&mask)%m->ud; | |
| p = m->w-1; | |
| q1 = two31/nc; | |
| r1 = two31 - q1*nc; | |
| q1 &= mask; | |
| r1 &= mask; | |
| q2 = (two31-1) / m->ud; | |
| r2 = (two31-1) - q2*m->ud; | |
| q2 &= mask; | |
| r2 &= mask; | |
| for(;;) { | |
| p++; | |
| if(r1 >= nc-r1) { | |
| q1 <<= 1; | |
| q1++; | |
| r1 <<= 1; | |
| r1 -= nc; | |
| } else { | |
| q1 <<= 1; | |
| r1 <<= 1; | |
| } | |
| q1 &= mask; | |
| r1 &= mask; | |
| if(r2+1 >= m->ud-r2) { | |
| if(q2 >= two31-1) { | |
| m->ua = 1; | |
| } | |
| q2 <<= 1; | |
| q2++; | |
| r2 <<= 1; | |
| r2++; | |
| r2 -= m->ud; | |
| } else { | |
| if(q2 >= two31) { | |
| m->ua = 1; | |
| } | |
| q2 <<= 1; | |
| r2 <<= 1; | |
| r2++; | |
| } | |
| q2 &= mask; | |
| r2 &= mask; | |
| delta = m->ud - 1 - r2; | |
| delta &= mask; | |
| if(p < m->w+m->w) | |
| if(q1 < delta || (q1 == delta && r1 == 0)) { | |
| continue; | |
| } | |
| break; | |
| } | |
| m->um = q2+1; | |
| m->s = p-m->w; | |
| } | |
| Sym* | |
| ngotype(Node *n) | |
| { | |
| if(n->sym != S && n->realtype != T) | |
| if(strncmp(n->sym->name, "autotmp_", 8) != 0) | |
| if(strncmp(n->sym->name, "statictmp_", 8) != 0) | |
| return typename(n->realtype)->left->sym; | |
| return S; | |
| } | |
| /* | |
| * Convert raw string to the prefix that will be used in the symbol | |
| * table. All control characters, space, '%' and '"', as well as | |
| * non-7-bit clean bytes turn into %xx. The period needs escaping | |
| * only in the last segment of the path, and it makes for happier | |
| * users if we escape that as little as possible. | |
| * | |
| * If you edit this, edit ../ld/lib.c:/^pathtoprefix copy too. | |
| */ | |
| static char* | |
| pathtoprefix(char *s) | |
| { | |
| static char hex[] = "0123456789abcdef"; | |
| char *p, *r, *w, *l; | |
| int n; | |
| // find first character past the last slash, if any. | |
| l = s; | |
| for(r=s; *r; r++) | |
| if(*r == '/') | |
| l = r+1; | |
| // check for chars that need escaping | |
| n = 0; | |
| for(r=s; *r; r++) | |
| if(*r <= ' ' || (*r == '.' && r >= l) || *r == '%' || *r == '"' || *r >= 0x7f) | |
| n++; | |
| // quick exit | |
| if(n == 0) | |
| return s; | |
| // escape | |
| p = mal((r-s)+1+2*n); | |
| for(r=s, w=p; *r; r++) { | |
| if(*r <= ' ' || (*r == '.' && r >= l) || *r == '%' || *r == '"' || *r >= 0x7f) { | |
| *w++ = '%'; | |
| *w++ = hex[(*r>>4)&0xF]; | |
| *w++ = hex[*r&0xF]; | |
| } else | |
| *w++ = *r; | |
| } | |
| *w = '\0'; | |
| return p; | |
| } | |
| Pkg* | |
| mkpkg(Strlit *path) | |
| { | |
| Pkg *p; | |
| int h; | |
| if(strlen(path->s) != path->len) { | |
| yyerror("import path contains NUL byte"); | |
| errorexit(); | |
| } | |
| h = stringhash(path->s) & (nelem(phash)-1); | |
| for(p=phash[h]; p; p=p->link) | |
| if(p->path->len == path->len && memcmp(path->s, p->path->s, path->len) == 0) | |
| return p; | |
| p = mal(sizeof *p); | |
| p->path = path; | |
| p->prefix = pathtoprefix(path->s); | |
| p->link = phash[h]; | |
| phash[h] = p; | |
| return p; | |
| } | |
| Strlit* | |
| strlit(char *s) | |
| { | |
| Strlit *t; | |
| t = mal(sizeof *t + strlen(s)); | |
| strcpy(t->s, s); | |
| t->len = strlen(s); | |
| return t; | |
| } |