summaryrefslogtreecommitdiff
path: root/src/cmd/gc/reflect.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/gc/reflect.c')
-rw-r--r--src/cmd/gc/reflect.c939
1 files changed, 939 insertions, 0 deletions
diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c
new file mode 100644
index 000000000..810787d30
--- /dev/null
+++ b/src/cmd/gc/reflect.c
@@ -0,0 +1,939 @@
+// 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 "go.h"
+
+/*
+ * runtime interface and reflection data structures
+ */
+
+static NodeList* signatlist;
+static Sym* dtypesym(Type*);
+static Sym* weaktypesym(Type*);
+
+static int
+sigcmp(Sig *a, Sig *b)
+{
+ int i;
+
+ i = strcmp(a->name, b->name);
+ if(i != 0)
+ return i;
+ if(a->pkg == b->pkg)
+ return 0;
+ if(a->pkg == nil)
+ return -1;
+ if(b->pkg == nil)
+ return +1;
+ return strcmp(a->pkg->path->s, b->pkg->path->s);
+}
+
+static Sig*
+lsort(Sig *l, int(*f)(Sig*, Sig*))
+{
+ Sig *l1, *l2, *le;
+
+ if(l == 0 || l->link == 0)
+ return l;
+
+ l1 = l;
+ l2 = l;
+ for(;;) {
+ l2 = l2->link;
+ if(l2 == 0)
+ break;
+ l2 = l2->link;
+ if(l2 == 0)
+ break;
+ l1 = l1->link;
+ }
+
+ l2 = l1->link;
+ l1->link = 0;
+ l1 = lsort(l, f);
+ l2 = lsort(l2, f);
+
+ /* set up lead element */
+ if((*f)(l1, l2) < 0) {
+ l = l1;
+ l1 = l1->link;
+ } else {
+ l = l2;
+ l2 = l2->link;
+ }
+ le = l;
+
+ for(;;) {
+ if(l1 == 0) {
+ while(l2) {
+ le->link = l2;
+ le = l2;
+ l2 = l2->link;
+ }
+ le->link = 0;
+ break;
+ }
+ if(l2 == 0) {
+ while(l1) {
+ le->link = l1;
+ le = l1;
+ l1 = l1->link;
+ }
+ break;
+ }
+ if((*f)(l1, l2) < 0) {
+ le->link = l1;
+ le = l1;
+ l1 = l1->link;
+ } else {
+ le->link = l2;
+ le = l2;
+ l2 = l2->link;
+ }
+ }
+ le->link = 0;
+ return l;
+}
+
+/*
+ * f is method type, with receiver.
+ * return function type, receiver as first argument (or not).
+ */
+Type*
+methodfunc(Type *f, Type *receiver)
+{
+ NodeList *in, *out;
+ Node *d;
+ Type *t;
+
+ in = nil;
+ if(receiver) {
+ d = nod(ODCLFIELD, N, N);
+ d->type = receiver;
+ in = list(in, d);
+ }
+ for(t=getinargx(f)->type; t; t=t->down) {
+ d = nod(ODCLFIELD, N, N);
+ d->type = t->type;
+ d->isddd = t->isddd;
+ in = list(in, d);
+ }
+
+ out = nil;
+ for(t=getoutargx(f)->type; t; t=t->down) {
+ d = nod(ODCLFIELD, N, N);
+ d->type = t->type;
+ out = list(out, d);
+ }
+
+ return functype(N, in, out);
+}
+
+/*
+ * return methods of non-interface type t, sorted by name.
+ * generates stub functions as needed.
+ */
+static Sig*
+methods(Type *t)
+{
+ Type *f, *mt, *it, *this;
+ Sig *a, *b;
+ Sym *method;
+ Prog *oldlist;
+
+ // named method type
+ mt = methtype(t);
+ if(mt == T)
+ return nil;
+ expandmeth(mt->sym, mt);
+
+ // type stored in interface word
+ it = t;
+ if(it->width > widthptr)
+ it = ptrto(t);
+
+ // make list of methods for t,
+ // generating code if necessary.
+ a = nil;
+ oldlist = nil;
+ for(f=mt->xmethod; f; f=f->down) {
+ if(f->type->etype != TFUNC)
+ continue;
+ if(f->etype != TFIELD)
+ fatal("methods: not field");
+ method = f->sym;
+ if(method == nil)
+ continue;
+
+ // get receiver type for this particular method.
+ // if pointer receiver but non-pointer t and
+ // this is not an embedded pointer inside a struct,
+ // method does not apply.
+ this = getthisx(f->type)->type->type;
+ if(isptr[this->etype] && this->type == t)
+ continue;
+ if(isptr[this->etype] && !isptr[t->etype]
+ && f->embedded != 2 && !isifacemethod(f->type))
+ continue;
+
+ b = mal(sizeof(*b));
+ b->link = a;
+ a = b;
+
+ a->name = method->name;
+ if(!exportname(method->name)) {
+ if(method->pkg == nil)
+ fatal("methods: missing package");
+ a->pkg = method->pkg;
+ }
+ a->isym = methodsym(method, it, 1);
+ a->tsym = methodsym(method, t, 0);
+ a->type = methodfunc(f->type, t);
+ a->mtype = methodfunc(f->type, nil);
+
+ if(!(a->isym->flags & SymSiggen)) {
+ a->isym->flags |= SymSiggen;
+ if(!eqtype(this, it) || this->width < types[tptr]->width) {
+ if(oldlist == nil)
+ oldlist = pc;
+ // Is okay to call genwrapper here always,
+ // but we can generate more efficient code
+ // using genembedtramp if all that is necessary
+ // is a pointer adjustment and a JMP.
+ 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);
+ }
+ }
+
+ if(!(a->tsym->flags & SymSiggen)) {
+ a->tsym->flags |= SymSiggen;
+ if(!eqtype(this, t)) {
+ if(oldlist == nil)
+ oldlist = pc;
+ 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);
+ }
+ }
+ }
+
+ // restore data output
+ if(oldlist) {
+ // old list ended with AEND; change to ANOP
+ // so that the trampolines that follow can be found.
+ nopout(oldlist);
+
+ // start new data list
+ newplist();
+ }
+
+ return lsort(a, sigcmp);
+}
+
+/*
+ * return methods of interface type t, sorted by name.
+ */
+static Sig*
+imethods(Type *t)
+{
+ Sig *a, *all, *last;
+ Type *f;
+ Sym *method, *isym;
+ Prog *oldlist;
+
+ all = nil;
+ last = nil;
+ oldlist = nil;
+ for(f=t->type; f; f=f->down) {
+ if(f->etype != TFIELD)
+ fatal("imethods: not field");
+ if(f->type->etype != TFUNC || f->sym == nil)
+ continue;
+ method = f->sym;
+ a = mal(sizeof(*a));
+ a->name = method->name;
+ if(!exportname(method->name)) {
+ if(method->pkg == nil)
+ fatal("imethods: missing package");
+ a->pkg = method->pkg;
+ }
+ a->mtype = f->type;
+ a->offset = 0;
+ a->type = methodfunc(f->type, nil);
+
+ if(last && sigcmp(last, a) >= 0)
+ fatal("sigcmp vs sortinter %s %s", last->name, a->name);
+ if(last == nil)
+ all = a;
+ 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
+ // code can refer to it.
+ isym = methodsym(method, t, 0);
+ if(!(isym->flags & SymSiggen)) {
+ isym->flags |= SymSiggen;
+ if(oldlist == nil)
+ oldlist = pc;
+ genwrapper(t, f, isym, 0);
+ }
+ }
+
+ if(oldlist) {
+ // old list ended with AEND; change to ANOP
+ // so that the trampolines that follow can be found.
+ nopout(oldlist);
+
+ // start new data list
+ newplist();
+ }
+
+ return all;
+}
+
+static void
+dimportpath(Pkg *p)
+{
+ static Pkg *gopkg;
+ char *nam;
+ Node *n;
+
+ if(p->pathsym != S)
+ return;
+
+ if(gopkg == nil) {
+ gopkg = mkpkg(strlit("go"));
+ gopkg->name = "go";
+ }
+ nam = smprint("importpath.%s.", p->prefix);
+
+ n = nod(ONAME, N, N);
+ n->sym = pkglookup(nam, gopkg);
+ free(nam);
+ n->class = PEXTERN;
+ n->xoffset = 0;
+ p->pathsym = n->sym;
+
+ gdatastring(n, p->path);
+ ggloblsym(n->sym, types[TSTRING]->width, 1);
+}
+
+static int
+dgopkgpath(Sym *s, int ot, Pkg *pkg)
+{
+ if(pkg == nil)
+ return dgostringptr(s, ot, nil);
+
+ // Emit reference to go.importpath.""., which 6l will
+ // rewrite using the correct import path. Every package
+ // 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);
+ }
+
+ dimportpath(pkg);
+ return dsymptr(s, ot, pkg->pathsym, 0);
+}
+
+/*
+ * uncommonType
+ * ../../pkg/runtime/type.go:/uncommonType
+ */
+static int
+dextratype(Sym *sym, int off, Type *t, int ptroff)
+{
+ int ot, n;
+ Sym *s;
+ Sig *a, *m;
+
+ m = methods(t);
+ if(t->sym == nil && m == nil)
+ return off;
+
+ // fill in *extraType pointer in header
+ dsymptr(sym, ptroff, sym, off);
+
+ n = 0;
+ for(a=m; a; a=a->link) {
+ dtypesym(a->type);
+ n++;
+ }
+
+ ot = off;
+ s = sym;
+ if(t->sym) {
+ ot = dgostringptr(s, ot, t->sym->name);
+ if(t != types[t->etype])
+ ot = dgopkgpath(s, ot, t->sym->pkg);
+ else
+ ot = dgostringptr(s, ot, nil);
+ } else {
+ ot = dgostringptr(s, ot, nil);
+ ot = dgostringptr(s, ot, nil);
+ }
+
+ // slice header
+ ot = dsymptr(s, ot, s, ot + widthptr + 2*4);
+ ot = duint32(s, ot, n);
+ ot = duint32(s, ot, n);
+
+ // methods
+ for(a=m; a; a=a->link) {
+ // method
+ // ../../pkg/runtime/type.go:/method
+ ot = dgostringptr(s, ot, a->name);
+ ot = dgopkgpath(s, ot, a->pkg);
+ ot = dsymptr(s, ot, dtypesym(a->mtype), 0);
+ ot = dsymptr(s, ot, dtypesym(a->type), 0);
+ if(a->isym)
+ ot = dsymptr(s, ot, a->isym, 0);
+ else
+ ot = duintptr(s, ot, 0);
+ if(a->tsym)
+ ot = dsymptr(s, ot, a->tsym, 0);
+ else
+ ot = duintptr(s, ot, 0);
+ }
+
+ return ot;
+}
+
+enum {
+ KindBool = 1,
+ KindInt,
+ KindInt8,
+ KindInt16,
+ KindInt32,
+ KindInt64,
+ KindUint,
+ KindUint8,
+ KindUint16,
+ KindUint32,
+ KindUint64,
+ KindUintptr,
+ KindFloat32,
+ KindFloat64,
+ KindComplex64,
+ KindComplex128,
+ KindArray,
+ KindChan,
+ KindFunc,
+ KindInterface,
+ KindMap,
+ KindPtr,
+ KindSlice,
+ KindString,
+ KindStruct,
+ KindUnsafePointer,
+
+ KindNoPointers = 1<<7,
+};
+
+static int
+kinds[] =
+{
+ [TINT] = KindInt,
+ [TUINT] = KindUint,
+ [TINT8] = KindInt8,
+ [TUINT8] = KindUint8,
+ [TINT16] = KindInt16,
+ [TUINT16] = KindUint16,
+ [TINT32] = KindInt32,
+ [TUINT32] = KindUint32,
+ [TINT64] = KindInt64,
+ [TUINT64] = KindUint64,
+ [TUINTPTR] = KindUintptr,
+ [TFLOAT32] = KindFloat32,
+ [TFLOAT64] = KindFloat64,
+ [TBOOL] = KindBool,
+ [TSTRING] = KindString,
+ [TPTR32] = KindPtr,
+ [TPTR64] = KindPtr,
+ [TSTRUCT] = KindStruct,
+ [TINTER] = KindInterface,
+ [TCHAN] = KindChan,
+ [TMAP] = KindMap,
+ [TARRAY] = KindArray,
+ [TFUNC] = KindFunc,
+ [TCOMPLEX64] = KindComplex64,
+ [TCOMPLEX128] = KindComplex128,
+ [TUNSAFEPTR] = KindUnsafePointer,
+};
+
+static char*
+structnames[] =
+{
+ [TINT] = "*runtime.IntType",
+ [TUINT] = "*runtime.UintType",
+ [TINT8] = "*runtime.IntType",
+ [TUINT8] = "*runtime.UintType",
+ [TINT16] = "*runtime.IntType",
+ [TUINT16] = "*runtime.UintType",
+ [TINT32] = "*runtime.IntType",
+ [TUINT32] = "*runtime.UintType",
+ [TINT64] = "*runtime.IntType",
+ [TUINT64] = "*runtime.UintType",
+ [TUINTPTR] = "*runtime.UintType",
+ [TCOMPLEX64] = "*runtime.ComplexType",
+ [TCOMPLEX128] = "*runtime.ComplexType",
+ [TFLOAT32] = "*runtime.FloatType",
+ [TFLOAT64] = "*runtime.FloatType",
+ [TBOOL] = "*runtime.BoolType",
+ [TSTRING] = "*runtime.StringType",
+ [TUNSAFEPTR] = "*runtime.UnsafePointerType",
+
+ [TPTR32] = "*runtime.PtrType",
+ [TPTR64] = "*runtime.PtrType",
+ [TSTRUCT] = "*runtime.StructType",
+ [TINTER] = "*runtime.InterfaceType",
+ [TCHAN] = "*runtime.ChanType",
+ [TMAP] = "*runtime.MapType",
+ [TARRAY] = "*runtime.ArrayType",
+ [TFUNC] = "*runtime.FuncType",
+};
+
+static Sym*
+typestruct(Type *t)
+{
+ char *name;
+ int et;
+
+ et = t->etype;
+ if(et < 0 || et >= nelem(structnames) || (name = structnames[et]) == nil) {
+ fatal("typestruct %lT", t);
+ return nil; // silence gcc
+ }
+
+ if(isslice(t))
+ name = "*runtime.SliceType";
+
+ return pkglookup(name, typepkg);
+}
+
+static int
+haspointers(Type *t)
+{
+ Type *t1;
+
+ switch(t->etype) {
+ case TINT:
+ case TUINT:
+ case TINT8:
+ case TUINT8:
+ case TINT16:
+ case TUINT16:
+ case TINT32:
+ case TUINT32:
+ case TINT64:
+ case TUINT64:
+ case TUINTPTR:
+ case TFLOAT32:
+ case TFLOAT64:
+ case TBOOL:
+ return 0;
+ case TARRAY:
+ if(t->bound < 0) // slice
+ return 1;
+ return haspointers(t->type);
+ case TSTRUCT:
+ for(t1=t->type; t1!=T; t1=t1->down)
+ if(haspointers(t1->type))
+ return 1;
+ return 0;
+ case TSTRING:
+ case TPTR32:
+ case TPTR64:
+ case TUNSAFEPTR:
+ case TINTER:
+ case TCHAN:
+ case TMAP:
+ case TFUNC:
+ default:
+ return 1;
+ }
+}
+
+/*
+ * commonType
+ * ../../pkg/runtime/type.go:/commonType
+ */
+static int
+dcommontype(Sym *s, int ot, Type *t)
+{
+ int i;
+ Sym *sptr;
+ char *p;
+
+ dowidth(t);
+
+ sptr = nil;
+ if(t->sym != nil && !isptr[t->etype])
+ sptr = dtypesym(ptrto(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/runtime/type.go:/commonType
+ // actual type structure
+ // type commonType struct {
+ // size uintptr;
+ // hash uint32;
+ // alg uint8;
+ // align uint8;
+ // fieldAlign uint8;
+ // kind uint8;
+ // string *string;
+ // *extraType;
+ // ptrToThis *Type
+ // }
+ ot = duintptr(s, ot, t->width);
+ ot = duint32(s, ot, typehash(t));
+ ot = duint8(s, ot, algtype(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;
+ if(!haspointers(t))
+ i |= KindNoPointers;
+ ot = duint8(s, ot, i); // kind
+ longsymnames = 1;
+ p = smprint("%-T", t);
+ longsymnames = 0;
+ 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.
+ // otherwise linker will assume 0.
+ ot += widthptr;
+
+ ot = dsymptr(s, ot, sptr, 0); // ptrto type
+ return ot;
+}
+
+Sym*
+typesym(Type *t)
+{
+ char *p;
+ Sym *s;
+
+ p = smprint("%#-T", t);
+ s = pkglookup(p, typepkg);
+ free(p);
+ return s;
+}
+
+Node*
+typename(Type *t)
+{
+ Sym *s;
+ Node *n;
+
+ if(t == T || (isptr[t->etype] && t->type == T) || isideal(t))
+ fatal("typename %T", t);
+ s = typesym(t);
+ if(s->def == N) {
+ n = nod(ONAME, N, N);
+ n->sym = s;
+ n->type = types[TUINT8];
+ n->addable = 1;
+ n->ullman = 1;
+ n->class = PEXTERN;
+ n->xoffset = 0;
+ s->def = n;
+
+ signatlist = list(signatlist, typenod(t));
+ }
+
+ n = nod(OADDR, s->def, N);
+ n->type = ptrto(s->def->type);
+ n->addable = 1;
+ n->ullman = 2;
+ return n;
+}
+
+static Sym*
+weaktypesym(Type *t)
+{
+ char *p;
+ Sym *s;
+ static Pkg *weak;
+
+ if(weak == nil) {
+ weak = mkpkg(strlit("weak.type"));
+ weak->name = "weak.type";
+ weak->prefix = "weak.type"; // not weak%2etype
+ }
+
+ p = smprint("%#-T", t);
+ s = pkglookup(p, weak);
+ free(p);
+ return s;
+}
+
+static Sym*
+dtypesym(Type *t)
+{
+ int ot, xt, n, isddd, dupok;
+ Sym *s, *s1, *s2;
+ Sig *a, *m;
+ Type *t1, *tbase, *t2;
+
+ if(isideal(t))
+ fatal("dtypesym %T", t);
+
+ s = typesym(t);
+ if(s->flags & SymSiggen)
+ return s;
+ s->flags |= SymSiggen;
+
+ // special case (look for runtime below):
+ // when compiling package runtime,
+ // emit the type structures for int, float, etc.
+ tbase = t;
+ if(isptr[t->etype] && t->sym == S && t->type->sym != S)
+ tbase = t->type;
+ dupok = tbase->sym == S;
+
+ if(compiling_runtime && tbase == types[tbase->etype]) // int, float, etc
+ goto ok;
+
+ // named types from other files are defined only by those files
+ if(tbase->sym && !tbase->local)
+ return s;
+ if(isforw[tbase->etype])
+ return s;
+
+ok:
+ ot = 0;
+ xt = 0;
+ switch(t->etype) {
+ default:
+ ot = dcommontype(s, ot, t);
+ xt = ot - 2*widthptr;
+ break;
+
+ case TARRAY:
+ if(t->bound >= 0) {
+ // ../../pkg/runtime/type.go:/ArrayType
+ s1 = dtypesym(t->type);
+ t2 = typ(TARRAY);
+ t2->type = t->type;
+ t2->bound = -1; // slice
+ s2 = dtypesym(t2);
+ ot = dcommontype(s, ot, t);
+ xt = ot - 2*widthptr;
+ ot = dsymptr(s, ot, s1, 0);
+ ot = dsymptr(s, ot, s2, 0);
+ ot = duintptr(s, ot, t->bound);
+ } else {
+ // ../../pkg/runtime/type.go:/SliceType
+ s1 = dtypesym(t->type);
+ ot = dcommontype(s, ot, t);
+ xt = ot - 2*widthptr;
+ ot = dsymptr(s, ot, s1, 0);
+ }
+ break;
+
+ case TCHAN:
+ // ../../pkg/runtime/type.go:/ChanType
+ s1 = dtypesym(t->type);
+ ot = dcommontype(s, ot, t);
+ xt = ot - 2*widthptr;
+ ot = dsymptr(s, ot, s1, 0);
+ ot = duintptr(s, ot, t->chan);
+ break;
+
+ case TFUNC:
+ for(t1=getthisx(t)->type; t1; t1=t1->down)
+ dtypesym(t1->type);
+ isddd = 0;
+ for(t1=getinargx(t)->type; t1; t1=t1->down) {
+ isddd = t1->isddd;
+ dtypesym(t1->type);
+ }
+ for(t1=getoutargx(t)->type; t1; t1=t1->down)
+ dtypesym(t1->type);
+
+ ot = dcommontype(s, ot, t);
+ xt = ot - 2*widthptr;
+ ot = duint8(s, ot, isddd);
+
+ // two slice headers: in and out.
+ ot = rnd(ot, widthptr);
+ ot = dsymptr(s, ot, s, ot+2*(widthptr+2*4));
+ 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);
+
+ // slice data
+ for(t1=getthisx(t)->type; t1; t1=t1->down, n++)
+ ot = dsymptr(s, ot, dtypesym(t1->type), 0);
+ for(t1=getinargx(t)->type; t1; t1=t1->down, n++)
+ ot = dsymptr(s, ot, dtypesym(t1->type), 0);
+ for(t1=getoutargx(t)->type; t1; t1=t1->down, n++)
+ ot = dsymptr(s, ot, dtypesym(t1->type), 0);
+ break;
+
+ case TINTER:
+ m = imethods(t);
+ n = 0;
+ for(a=m; a; a=a->link) {
+ dtypesym(a->type);
+ n++;
+ }
+
+ // ../../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);
+ for(a=m; a; a=a->link) {
+ // ../../pkg/runtime/type.go:/imethod
+ ot = dgostringptr(s, ot, a->name);
+ ot = dgopkgpath(s, ot, a->pkg);
+ ot = dsymptr(s, ot, dtypesym(a->type), 0);
+ }
+ break;
+
+ case TMAP:
+ // ../../pkg/runtime/type.go:/MapType
+ s1 = dtypesym(t->down);
+ s2 = dtypesym(t->type);
+ ot = dcommontype(s, ot, t);
+ xt = ot - 2*widthptr;
+ ot = dsymptr(s, ot, s1, 0);
+ ot = dsymptr(s, ot, s2, 0);
+ break;
+
+ case TPTR32:
+ case TPTR64:
+ if(t->type->etype == TANY) {
+ // ../../pkg/runtime/type.go:/UnsafePointerType
+ ot = dcommontype(s, ot, t);
+ break;
+ }
+ // ../../pkg/runtime/type.go:/PtrType
+ s1 = dtypesym(t->type);
+ ot = dcommontype(s, ot, t);
+ xt = ot - 2*widthptr;
+ ot = dsymptr(s, ot, s1, 0);
+ break;
+
+ case TSTRUCT:
+ // ../../pkg/runtime/type.go:/StructType
+ // for security, only the exported fields.
+ n = 0;
+ for(t1=t->type; t1!=T; t1=t1->down) {
+ dtypesym(t1->type);
+ n++;
+ }
+ 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);
+ for(t1=t->type; t1!=T; t1=t1->down) {
+ // ../../pkg/runtime/type.go:/structField
+ if(t1->sym && !t1->embedded) {
+ ot = dgostringptr(s, ot, t1->sym->name);
+ if(exportname(t1->sym->name))
+ ot = dgostringptr(s, ot, nil);
+ else
+ ot = dgopkgpath(s, ot, t1->sym->pkg);
+ } else {
+ ot = dgostringptr(s, ot, nil);
+ ot = dgostringptr(s, ot, nil);
+ }
+ ot = dsymptr(s, ot, dtypesym(t1->type), 0);
+ ot = dgostrlitptr(s, ot, t1->note);
+ ot = duintptr(s, ot, t1->width); // field offset
+ }
+ break;
+ }
+ ot = dextratype(s, ot, t, xt);
+ ggloblsym(s, ot, dupok);
+ return s;
+}
+
+void
+dumptypestructs(void)
+{
+ int i;
+ NodeList *l;
+ Node *n;
+ Type *t;
+ Pkg *p;
+
+ // copy types from externdcl list to signatlist
+ for(l=externdcl; l; l=l->next) {
+ n = l->n;
+ if(n->op != OTYPE)
+ continue;
+ signatlist = list(signatlist, n);
+ }
+
+ // process signatlist
+ for(l=signatlist; l; l=l->next) {
+ n = l->n;
+ if(n->op != OTYPE)
+ continue;
+ t = n->type;
+ dtypesym(t);
+ if(t->sym)
+ dtypesym(ptrto(t));
+ }
+
+ // generate import strings for imported packages
+ for(i=0; i<nelem(phash); i++)
+ for(p=phash[i]; p; p=p->link)
+ if(p->direct)
+ dimportpath(p);
+
+ // do basic types if compiling package runtime.
+ // they have to be in at least one package,
+ // and runtime is always loaded implicitly,
+ // so this is as good as any.
+ // another possible choice would be package main,
+ // but using runtime means fewer copies in .6 files.
+ if(compiling_runtime) {
+ for(i=1; i<=TBOOL; i++)
+ dtypesym(ptrto(types[i]));
+ dtypesym(ptrto(types[TSTRING]));
+ dtypesym(ptrto(types[TUNSAFEPTR]));
+
+ // add paths for runtime and main, which 6l imports implicitly.
+ dimportpath(runtimepkg);
+ dimportpath(mkpkg(strlit("main")));
+ }
+}