diff options
Diffstat (limited to 'src/cmd/gc/reflect.c')
-rw-r--r-- | src/cmd/gc/reflect.c | 378 |
1 files changed, 314 insertions, 64 deletions
diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c index 62759bcba..b8eb79938 100644 --- a/src/cmd/gc/reflect.c +++ b/src/cmd/gc/reflect.c @@ -5,6 +5,7 @@ #include <u.h> #include <libc.h> #include "go.h" +#include "../../pkg/runtime/mgc0.h" /* * runtime interface and reflection data structures @@ -14,12 +15,13 @@ static NodeList* signatlist; static Sym* dtypesym(Type*); static Sym* weaktypesym(Type*); static Sym* dalgsym(Type*); +static Sym* dgcsym(Type*); static int sigcmp(Sig *a, Sig *b) { int i; - + i = strcmp(a->name, b->name); if(i != 0) return i; @@ -130,7 +132,12 @@ methodfunc(Type *f, Type *receiver) out = list(out, d); } - return functype(N, in, out); + t = functype(N, in, out); + if(f->nname) { + // Link to name of original method function. + t->nname = f->nname; + } + return t; } /* @@ -165,6 +172,8 @@ methods(Type *t) fatal("non-method on %T method %S %T\n", mt, f->sym, f); if (!getthisx(f->type)->type) fatal("receiver with no type on %T method %S %T\n", mt, f->sym, f); + if(f->nointerface) + continue; method = f->sym; if(method == nil) @@ -203,22 +212,26 @@ methods(Type *t) // but we can generate more efficient code // using genembedtramp if all that is necessary // is a pointer adjustment and a JMP. + compiling_wrappers = 1; if(isptr[it->etype] && isptr[this->etype] && f->embedded && !isifacemethod(f->type)) genembedtramp(it, f, a->isym, 1); else genwrapper(it, f, a->isym, 1); + compiling_wrappers = 0; } } if(!(a->tsym->flags & SymSiggen)) { a->tsym->flags |= SymSiggen; if(!eqtype(this, t)) { + compiling_wrappers = 1; if(isptr[t->etype] && isptr[this->etype] && f->embedded && !isifacemethod(f->type)) genembedtramp(t, f, a->tsym, 0); else genwrapper(t, f, a->tsym, 0); + compiling_wrappers = 0; } } } @@ -262,12 +275,12 @@ imethods(Type *t) else last->link = a; last = a; - + // Compiler can only refer to wrappers for // named interface types. if(t->sym == S) continue; - + // NOTE(rsc): Perhaps an oversight that // IfaceType.Method is not in the reflect data. // Generate the method body, so that compiled @@ -287,7 +300,7 @@ dimportpath(Pkg *p) static Pkg *gopkg; char *nam; Node *n; - + if(p->pathsym != S) return; @@ -303,9 +316,9 @@ dimportpath(Pkg *p) n->class = PEXTERN; n->xoffset = 0; p->pathsym = n->sym; - + gdatastring(n, p->path); - ggloblsym(n->sym, types[TSTRING]->width, 1); + ggloblsym(n->sym, types[TSTRING]->width, 1, 1); } static int @@ -319,7 +332,7 @@ dgopkgpath(Sym *s, int ot, Pkg *pkg) // that imports this one directly defines the symbol. if(pkg == localpkg) { static Sym *ns; - + if(ns == nil) ns = pkglookup("importpath.\"\".", mkpkg(strlit("go"))); return dsymptr(s, ot, ns, 0); @@ -343,7 +356,7 @@ dextratype(Sym *sym, int off, Type *t, int ptroff) m = methods(t); if(t->sym == nil && m == nil) return off; - + // fill in *extraType pointer in header dsymptr(sym, ptroff, sym, off); @@ -367,9 +380,9 @@ dextratype(Sym *sym, int off, Type *t, int ptroff) } // slice header - ot = dsymptr(s, ot, s, ot + widthptr + 2*4); - ot = duint32(s, ot, n); - ot = duint32(s, ot, n); + ot = dsymptr(s, ot, s, ot + widthptr + 2*widthint); + ot = duintxx(s, ot, n, widthint); + ot = duintxx(s, ot, n, widthint); // methods for(a=m; a; a=a->link) { @@ -419,7 +432,7 @@ enum { KindString, KindStruct, KindUnsafePointer, - + KindNoPointers = 1<<7, }; @@ -454,19 +467,6 @@ kinds[] = [TUNSAFEPTR] = KindUnsafePointer, }; -static Sym* -typestruct(Type *t) -{ - // We use a weak reference to the reflect type - // to avoid requiring package reflect in every binary. - // If package reflect is available, the interface{} holding - // a runtime type will contain a *reflect.commonType. - // Otherwise it will use a nil type word but still be usable - // by package runtime (because we always use the memory - // after the interface value, not the interface value itself). - return pkglookup("*reflect.commonType", weaktypepkg); -} - int haspointers(Type *t) { @@ -521,6 +521,9 @@ dcommontype(Sym *s, int ot, Type *t) Sym *sptr, *algsym; static Sym *algarray; char *p; + + if(ot != 0) + fatal("dcommontype %d", ot); sizeofAlg = 4*widthptr; if(algarray == nil) @@ -536,31 +539,34 @@ dcommontype(Sym *s, int ot, Type *t) else sptr = weaktypesym(ptrto(t)); - // empty interface pointing at this type. - // all the references that we emit are *interface{}; - // they point here. - ot = rnd(ot, widthptr); - ot = dsymptr(s, ot, typestruct(t), 0); - ot = dsymptr(s, ot, s, 2*widthptr); - // ../../pkg/reflect/type.go:/^type.commonType // actual type structure // type commonType struct { - // size uintptr; - // hash uint32; - // alg uint8; - // align uint8; - // fieldAlign uint8; - // kind uint8; - // string *string; - // *extraType; - // ptrToThis *Type + // size uintptr + // hash uint32 + // _ uint8 + // align uint8 + // fieldAlign uint8 + // kind uint8 + // alg unsafe.Pointer + // gc unsafe.Pointer + // string *string + // *extraType + // ptrToThis *Type // } ot = duintptr(s, ot, t->width); ot = duint32(s, ot, typehash(t)); ot = duint8(s, ot, 0); // unused + + // runtime (and common sense) expects alignment to be a power of two. + i = t->align; + if(i == 0) + i = 1; + if((i&(i-1)) != 0) + fatal("invalid alignment %d for %T", t->align, t); ot = duint8(s, ot, t->align); // align ot = duint8(s, ot, t->align); // fieldAlign + i = kinds[t->etype]; if(t->etype == TARRAY && t->bound < 0) i = KindSlice; @@ -571,11 +577,12 @@ dcommontype(Sym *s, int ot, Type *t) ot = dsymptr(s, ot, algarray, alg*sizeofAlg); else ot = dsymptr(s, ot, algsym, 0); + ot = dsymptr(s, ot, dgcsym(t), 0); // gc p = smprint("%-uT", t); //print("dcommontype: %s\n", p); ot = dgostringptr(s, ot, p); // string free(p); - + // skip pointer to extraType, // which follows the rest of this type structure. // caller will fill in if needed. @@ -600,6 +607,39 @@ typesym(Type *t) } Sym* +tracksym(Type *t) +{ + char *p; + Sym *s; + + p = smprint("%-T.%s", t->outer, t->sym->name); + s = pkglookup(p, trackpkg); + free(p); + return s; +} + +Sym* +typelinksym(Type *t) +{ + char *p; + Sym *s; + + // %-uT is what the generated Type's string field says. + // It uses (ambiguous) package names instead of import paths. + // %-T is the complete, unambiguous type name. + // We want the types to end up sorted by string field, + // so use that first in the name, and then add :%-T to + // disambiguate. The names are a little long but they are + // discarded by the linker and do not end up in the symbol + // table of the final binary. + p = smprint("%-uT/%-T", t, t); + s = pkglookup(p, typelinkpkg); + //print("typelinksym: %s -> %+S\n", p, s); + free(p); + return s; +} + +Sym* typesymprefix(char *prefix, Type *t) { char *p; @@ -612,8 +652,8 @@ typesymprefix(char *prefix, Type *t) return s; } -Node* -typename(Type *t) +Sym* +typenamesym(Type *t) { Sym *s; Node *n; @@ -634,7 +674,16 @@ typename(Type *t) signatlist = list(signatlist, typenod(t)); } + return s->def->sym; +} + +Node* +typename(Type *t) +{ + Sym *s; + Node *n; + s = typenamesym(t); n = nod(OADDR, s->def, N); n->type = ptrto(s->def->type); n->addable = 1; @@ -660,10 +709,16 @@ static Sym* dtypesym(Type *t) { int ot, xt, n, isddd, dupok; - Sym *s, *s1, *s2; + Sym *s, *s1, *s2, *slink; Sig *a, *m; Type *t1, *tbase, *t2; + // Replace byte, rune aliases with real type. + // They've been separate internally to make error messages + // better, but we have to merge them in the reflect tables. + if(t == bytetype || t == runetype) + t = types[t->etype]; + if(isideal(t)) fatal("dtypesym %T", t); @@ -680,7 +735,7 @@ dtypesym(Type *t) tbase = t->type; dupok = tbase->sym == S; - if(compiling_runtime && + if(compiling_runtime && (tbase == types[tbase->etype] || tbase == bytetype || tbase == runetype || @@ -751,13 +806,13 @@ ok: // two slice headers: in and out. ot = rnd(ot, widthptr); - ot = dsymptr(s, ot, s, ot+2*(widthptr+2*4)); + ot = dsymptr(s, ot, s, ot+2*(widthptr+2*widthint)); n = t->thistuple + t->intuple; - ot = duint32(s, ot, n); - ot = duint32(s, ot, n); - ot = dsymptr(s, ot, s, ot+1*(widthptr+2*4)+n*widthptr); - ot = duint32(s, ot, t->outtuple); - ot = duint32(s, ot, t->outtuple); + ot = duintxx(s, ot, n, widthint); + ot = duintxx(s, ot, n, widthint); + ot = dsymptr(s, ot, s, ot+1*(widthptr+2*widthint)+n*widthptr); + ot = duintxx(s, ot, t->outtuple, widthint); + ot = duintxx(s, ot, t->outtuple, widthint); // slice data for(t1=getthisx(t)->type; t1; t1=t1->down, n++) @@ -779,9 +834,9 @@ ok: // ../../pkg/runtime/type.go:/InterfaceType ot = dcommontype(s, ot, t); xt = ot - 2*widthptr; - ot = dsymptr(s, ot, s, ot+widthptr+2*4); - ot = duint32(s, ot, n); - ot = duint32(s, ot, n); + ot = dsymptr(s, ot, s, ot+widthptr+2*widthint); + ot = duintxx(s, ot, n, widthint); + ot = duintxx(s, ot, n, widthint); for(a=m; a; a=a->link) { // ../../pkg/runtime/type.go:/imethod ot = dgostringptr(s, ot, a->name); @@ -824,9 +879,9 @@ ok: } ot = dcommontype(s, ot, t); xt = ot - 2*widthptr; - ot = dsymptr(s, ot, s, ot+widthptr+2*4); - ot = duint32(s, ot, n); - ot = duint32(s, ot, n); + ot = dsymptr(s, ot, s, ot+widthptr+2*widthint); + ot = duintxx(s, ot, n, widthint); + ot = duintxx(s, ot, n, widthint); for(t1=t->type; t1!=T; t1=t1->down) { // ../../pkg/runtime/type.go:/structField if(t1->sym && !t1->embedded) { @@ -837,7 +892,10 @@ ok: ot = dgopkgpath(s, ot, t1->sym->pkg); } else { ot = dgostringptr(s, ot, nil); - ot = dgostringptr(s, ot, nil); + if(t1->type->sym != S && t1->type->sym->pkg == builtinpkg) + ot = dgopkgpath(s, ot, localpkg); + else + ot = dgostringptr(s, ot, nil); } ot = dsymptr(s, ot, dtypesym(t1->type), 0); ot = dgostrlitptr(s, ot, t1->note); @@ -846,7 +904,24 @@ ok: break; } ot = dextratype(s, ot, t, xt); - ggloblsym(s, ot, dupok); + ggloblsym(s, ot, dupok, 1); + + // generate typelink.foo pointing at s = type.foo. + // The linker will leave a table of all the typelinks for + // types in the binary, so reflect can find them. + // We only need the link for unnamed composites that + // we want be able to find. + if(t->sym == S) { + switch(t->etype) { + case TARRAY: + case TCHAN: + case TMAP: + slink = typelinksym(t); + dsymptr(slink, 0, s, 0); + ggloblsym(slink, widthptr, dupok, 1); + } + } + return s; } @@ -899,12 +974,14 @@ dumptypestructs(void) // emit type structs for error and func(error) string. // The latter is the type of an auto-generated wrapper. dtypesym(ptrto(errortype)); - dtypesym(functype(nil, + dtypesym(functype(nil, list1(nod(ODCLFIELD, N, typenod(errortype))), list1(nod(ODCLFIELD, N, typenod(types[TSTRING]))))); - + // add paths for runtime and main, which 6l imports implicitly. dimportpath(runtimepkg); + if(flag_race) + dimportpath(racepkg); dimportpath(mkpkg(strlit("main"))); } } @@ -944,7 +1021,180 @@ dalgsym(Type *t) break; } - ggloblsym(s, ot, 1); + ggloblsym(s, ot, 1, 1); return s; } +static int +dgcsym1(Sym *s, int ot, Type *t, vlong *off, int stack_size) +{ + Type *t1; + vlong o, off2, fieldoffset; + + if(t->align > 0 && (*off % t->align) != 0) + fatal("dgcsym1: invalid initial alignment, %T", t); + + switch(t->etype) { + case TINT8: + case TUINT8: + case TINT16: + case TUINT16: + case TINT32: + case TUINT32: + case TINT64: + case TUINT64: + case TINT: + case TUINT: + case TUINTPTR: + case TBOOL: + case TFLOAT32: + case TFLOAT64: + case TCOMPLEX64: + case TCOMPLEX128: + *off += t->width; + break; + + case TPTR32: + case TPTR64: + if(*off % widthptr != 0) + fatal("dgcsym1: invalid alignment, %T", t); + if(!haspointers(t->type) || t->type->etype == TUINT8) { + ot = duintptr(s, ot, GC_APTR); + ot = duintptr(s, ot, *off); + } else { + ot = duintptr(s, ot, GC_PTR); + ot = duintptr(s, ot, *off); + ot = dsymptr(s, ot, dgcsym(t->type), 0); + } + *off += t->width; + break; + + case TCHAN: + case TUNSAFEPTR: + case TFUNC: + if(*off % widthptr != 0) + fatal("dgcsym1: invalid alignment, %T", t); + ot = duintptr(s, ot, GC_APTR); + ot = duintptr(s, ot, *off); + *off += t->width; + break; + + // struct Hmap* + case TMAP: + if(*off % widthptr != 0) + fatal("dgcsym1: invalid alignment, %T", t); + ot = duintptr(s, ot, GC_MAP_PTR); + ot = duintptr(s, ot, *off); + ot = dsymptr(s, ot, dtypesym(t), 0); + *off += t->width; + break; + + // struct { byte *str; int32 len; } + case TSTRING: + if(*off % widthptr != 0) + fatal("dgcsym1: invalid alignment, %T", t); + ot = duintptr(s, ot, GC_STRING); + ot = duintptr(s, ot, *off); + *off += t->width; + break; + + // struct { Itab* tab; void* data; } + // struct { Type* type; void* data; } // When isnilinter(t)==true + case TINTER: + if(*off % widthptr != 0) + fatal("dgcsym1: invalid alignment, %T", t); + if(isnilinter(t)) { + ot = duintptr(s, ot, GC_EFACE); + ot = duintptr(s, ot, *off); + } else { + ot = duintptr(s, ot, GC_IFACE); + ot = duintptr(s, ot, *off); + } + *off += t->width; + break; + + case TARRAY: + if(t->bound < -1) + fatal("dgcsym1: invalid bound, %T", t); + if(isslice(t)) { + // struct { byte* array; uint32 len; uint32 cap; } + if(*off % widthptr != 0) + fatal("dgcsym1: invalid alignment, %T", t); + if(t->type->width != 0) { + ot = duintptr(s, ot, GC_SLICE); + ot = duintptr(s, ot, *off); + ot = dsymptr(s, ot, dgcsym(t->type), 0); + } else { + ot = duintptr(s, ot, GC_APTR); + ot = duintptr(s, ot, *off); + } + *off += t->width; + } else { + if(t->bound < 1 || !haspointers(t->type)) { + *off += t->width; + } else if(t->bound == 1) { + ot = dgcsym1(s, ot, t->type, off, stack_size); // recursive call of dgcsym1 + } else { + if(stack_size < GC_STACK_CAPACITY) { + ot = duintptr(s, ot, GC_ARRAY_START); // a stack push during GC + ot = duintptr(s, ot, *off); + ot = duintptr(s, ot, t->bound); + ot = duintptr(s, ot, t->type->width); + off2 = 0; + ot = dgcsym1(s, ot, t->type, &off2, stack_size+1); // recursive call of dgcsym1 + ot = duintptr(s, ot, GC_ARRAY_NEXT); // a stack pop during GC + } else { + ot = duintptr(s, ot, GC_REGION); + ot = duintptr(s, ot, *off); + ot = duintptr(s, ot, t->width); + ot = dsymptr(s, ot, dgcsym(t), 0); + } + *off += t->width; + } + } + break; + + case TSTRUCT: + o = 0; + for(t1=t->type; t1!=T; t1=t1->down) { + fieldoffset = t1->width; + *off += fieldoffset - o; + ot = dgcsym1(s, ot, t1->type, off, stack_size); // recursive call of dgcsym1 + o = fieldoffset + t1->type->width; + } + *off += t->width - o; + break; + + default: + fatal("dgcsym1: unexpected type %T", t); + } + + return ot; +} + +static Sym* +dgcsym(Type *t) +{ + int ot; + vlong off; + Sym *s; + + s = typesymprefix(".gc", t); + if(s->flags & SymGcgen) + return s; + s->flags |= SymGcgen; + + ot = 0; + off = 0; + ot = duintptr(s, ot, t->width); + ot = dgcsym1(s, ot, t, &off, 0); + ot = duintptr(s, ot, GC_END); + ggloblsym(s, ot, 1, 1); + + if(t->align > 0) + off = rnd(off, t->align); + if(off != t->width) + fatal("dgcsym: off=%lld, size=%lld, type %T", off, t->width, t); + + return s; +} |