github.com/bgentry/go@v0.0.0-20150121062915-6cf5a733d54d/src/cmd/gc/reflect.c (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  #include <u.h>
     6  #include <libc.h>
     7  #include "go.h"
     8  #include "../ld/textflag.h"
     9  #include "../../runtime/mgc0.h"
    10  #include "../../runtime/typekind.h"
    11  
    12  /*
    13   * runtime interface and reflection data structures
    14   */
    15  
    16  static	NodeList*	signatlist;
    17  static	Sym*	dtypesym(Type*);
    18  static	Sym*	weaktypesym(Type*);
    19  static	Sym*	dalgsym(Type*);
    20  static	int	usegcprog(Type*);
    21  static	void	gengcprog(Type*, Sym**, Sym**);
    22  static	void	gengcmask(Type*, uint8[16]);
    23  
    24  static int
    25  sigcmp(Sig *a, Sig *b)
    26  {
    27  	int i;
    28  
    29  	i = strcmp(a->name, b->name);
    30  	if(i != 0)
    31  		return i;
    32  	if(a->pkg == b->pkg)
    33  		return 0;
    34  	if(a->pkg == nil)
    35  		return -1;
    36  	if(b->pkg == nil)
    37  		return +1;
    38  	return strcmp(a->pkg->path->s, b->pkg->path->s);
    39  }
    40  
    41  static Sig*
    42  lsort(Sig *l, int(*f)(Sig*, Sig*))
    43  {
    44  	Sig *l1, *l2, *le;
    45  
    46  	if(l == 0 || l->link == 0)
    47  		return l;
    48  
    49  	l1 = l;
    50  	l2 = l;
    51  	for(;;) {
    52  		l2 = l2->link;
    53  		if(l2 == 0)
    54  			break;
    55  		l2 = l2->link;
    56  		if(l2 == 0)
    57  			break;
    58  		l1 = l1->link;
    59  	}
    60  
    61  	l2 = l1->link;
    62  	l1->link = 0;
    63  	l1 = lsort(l, f);
    64  	l2 = lsort(l2, f);
    65  
    66  	/* set up lead element */
    67  	if((*f)(l1, l2) < 0) {
    68  		l = l1;
    69  		l1 = l1->link;
    70  	} else {
    71  		l = l2;
    72  		l2 = l2->link;
    73  	}
    74  	le = l;
    75  
    76  	for(;;) {
    77  		if(l1 == 0) {
    78  			while(l2) {
    79  				le->link = l2;
    80  				le = l2;
    81  				l2 = l2->link;
    82  			}
    83  			le->link = 0;
    84  			break;
    85  		}
    86  		if(l2 == 0) {
    87  			while(l1) {
    88  				le->link = l1;
    89  				le = l1;
    90  				l1 = l1->link;
    91  			}
    92  			break;
    93  		}
    94  		if((*f)(l1, l2) < 0) {
    95  			le->link = l1;
    96  			le = l1;
    97  			l1 = l1->link;
    98  		} else {
    99  			le->link = l2;
   100  			le = l2;
   101  			l2 = l2->link;
   102  		}
   103  	}
   104  	le->link = 0;
   105  	return l;
   106  }
   107  
   108  // Builds a type respresenting a Bucket structure for
   109  // the given map type.  This type is not visible to users -
   110  // we include only enough information to generate a correct GC
   111  // program for it.
   112  // Make sure this stays in sync with ../../runtime/hashmap.c!
   113  enum {
   114  	BUCKETSIZE = 8,
   115  	MAXKEYSIZE = 128,
   116  	MAXVALSIZE = 128,
   117  };
   118  
   119  static Type*
   120  mapbucket(Type *t)
   121  {
   122  	Type *keytype, *valtype;
   123  	Type *bucket;
   124  	Type *overflowfield, *keysfield, *valuesfield;
   125  	int32 offset;
   126  
   127  	if(t->bucket != T)
   128  		return t->bucket;
   129  
   130  	keytype = t->down;
   131  	valtype = t->type;
   132  	dowidth(keytype);
   133  	dowidth(valtype);
   134  	if(keytype->width > MAXKEYSIZE)
   135  		keytype = ptrto(keytype);
   136  	if(valtype->width > MAXVALSIZE)
   137  		valtype = ptrto(valtype);
   138  
   139  	bucket = typ(TSTRUCT);
   140  	bucket->noalg = 1;
   141  
   142  	// The first field is: uint8 topbits[BUCKETSIZE].
   143  	// We don't need to encode it as GC doesn't care about it.
   144  	offset = BUCKETSIZE * 1;
   145  
   146  	keysfield = typ(TFIELD);
   147  	keysfield->type = typ(TARRAY);
   148  	keysfield->type->type = keytype;
   149  	keysfield->type->bound = BUCKETSIZE;
   150  	keysfield->type->width = BUCKETSIZE * keytype->width;
   151  	keysfield->width = offset;
   152  	keysfield->sym = mal(sizeof(Sym));
   153  	keysfield->sym->name = "keys";
   154  	offset += BUCKETSIZE * keytype->width;
   155  
   156  	valuesfield = typ(TFIELD);
   157  	valuesfield->type = typ(TARRAY);
   158  	valuesfield->type->type = valtype;
   159  	valuesfield->type->bound = BUCKETSIZE;
   160  	valuesfield->type->width = BUCKETSIZE * valtype->width;
   161  	valuesfield->width = offset;
   162  	valuesfield->sym = mal(sizeof(Sym));
   163  	valuesfield->sym->name = "values";
   164  	offset += BUCKETSIZE * valtype->width;
   165  
   166  	overflowfield = typ(TFIELD);
   167  	overflowfield->type = ptrto(bucket);
   168  	overflowfield->width = offset;         // "width" is offset in structure
   169  	overflowfield->sym = mal(sizeof(Sym)); // not important but needs to be set to give this type a name
   170  	overflowfield->sym->name = "overflow";
   171  	offset += widthptr;
   172  	
   173  	// Pad to the native integer alignment.
   174  	// This is usually the same as widthptr; the exception (as usual) is nacl/amd64.
   175  	if(widthreg > widthptr)
   176  		offset += widthreg - widthptr;
   177  
   178  	// link up fields
   179  	bucket->type = keysfield;
   180  	keysfield->down = valuesfield;
   181  	valuesfield->down = overflowfield;
   182  	overflowfield->down = T;
   183  
   184  	bucket->width = offset;
   185  	bucket->local = t->local;
   186  	t->bucket = bucket;
   187  	bucket->map = t;
   188  	return bucket;
   189  }
   190  
   191  // Builds a type respresenting a Hmap structure for
   192  // the given map type.  This type is not visible to users -
   193  // we include only enough information to generate a correct GC
   194  // program for it.
   195  // Make sure this stays in sync with ../../runtime/hashmap.go!
   196  static Type*
   197  hmap(Type *t)
   198  {
   199  	Type *h, *bucket;
   200  	Type *bucketsfield, *oldbucketsfield;
   201  	int32 offset;
   202  
   203  	if(t->hmap != T)
   204  		return t->hmap;
   205  
   206  	bucket = mapbucket(t);
   207  	h = typ(TSTRUCT);
   208  	h->noalg = 1;
   209  
   210  	offset = widthint; // count
   211  	offset += 4;       // flags
   212  	offset += 4;       // hash0
   213  	offset += 1;       // B
   214  	offset = (offset + widthptr - 1) / widthptr * widthptr;
   215  	
   216  	bucketsfield = typ(TFIELD);
   217  	bucketsfield->type = ptrto(bucket);
   218  	bucketsfield->width = offset;
   219  	bucketsfield->sym = mal(sizeof(Sym));
   220  	bucketsfield->sym->name = "buckets";
   221  	offset += widthptr;
   222  
   223  	oldbucketsfield = typ(TFIELD);
   224  	oldbucketsfield->type = ptrto(bucket);
   225  	oldbucketsfield->width = offset;
   226  	oldbucketsfield->sym = mal(sizeof(Sym));
   227  	oldbucketsfield->sym->name = "oldbuckets";
   228  	offset += widthptr;
   229  
   230  	offset += widthptr; // nevacuate (last field in Hmap)
   231  
   232  	// link up fields
   233  	h->type = bucketsfield;
   234  	bucketsfield->down = oldbucketsfield;
   235  	oldbucketsfield->down = T;
   236  
   237  	h->width = offset;
   238  	h->local = t->local;
   239  	t->hmap = h;
   240  	h->map = t;
   241  	return h;
   242  }
   243  
   244  Type*
   245  hiter(Type *t)
   246  {
   247  	int32 n, off;
   248  	Type *field[7];
   249  	Type *i;
   250  
   251  	if(t->hiter != T)
   252  		return t->hiter;
   253  
   254  	// build a struct:
   255  	// hash_iter {
   256  	//    key *Key
   257  	//    val *Value
   258  	//    t *MapType
   259  	//    h *Hmap
   260  	//    buckets *Bucket
   261  	//    bptr *Bucket
   262  	//    other [4]uintptr
   263  	// }
   264  	// must match ../../runtime/hashmap.c:hash_iter.
   265  	field[0] = typ(TFIELD);
   266  	field[0]->type = ptrto(t->down);
   267  	field[0]->sym = mal(sizeof(Sym));
   268  	field[0]->sym->name = "key";
   269  	
   270  	field[1] = typ(TFIELD);
   271  	field[1]->type = ptrto(t->type);
   272  	field[1]->sym = mal(sizeof(Sym));
   273  	field[1]->sym->name = "val";
   274  	
   275  	field[2] = typ(TFIELD);
   276  	field[2]->type = ptrto(types[TUINT8]); // TODO: is there a Type type?
   277  	field[2]->sym = mal(sizeof(Sym));
   278  	field[2]->sym->name = "t";
   279  	
   280  	field[3] = typ(TFIELD);
   281  	field[3]->type = ptrto(hmap(t));
   282  	field[3]->sym = mal(sizeof(Sym));
   283  	field[3]->sym->name = "h";
   284  	
   285  	field[4] = typ(TFIELD);
   286  	field[4]->type = ptrto(mapbucket(t));
   287  	field[4]->sym = mal(sizeof(Sym));
   288  	field[4]->sym->name = "buckets";
   289  	
   290  	field[5] = typ(TFIELD);
   291  	field[5]->type = ptrto(mapbucket(t));
   292  	field[5]->sym = mal(sizeof(Sym));
   293  	field[5]->sym->name = "bptr";
   294  	
   295  	// all other non-pointer fields
   296  	field[6] = typ(TFIELD);
   297  	field[6]->type = typ(TARRAY);
   298  	field[6]->type->type = types[TUINTPTR];
   299  	field[6]->type->bound = 4;
   300  	field[6]->type->width = 4 * widthptr;
   301  	field[6]->sym = mal(sizeof(Sym));
   302  	field[6]->sym->name = "other";
   303  	
   304  	// build iterator struct holding the above fields
   305  	i = typ(TSTRUCT);
   306  	i->noalg = 1;
   307  	i->type = field[0];
   308  	off = 0;
   309  	for(n = 0; n < 6; n++) {
   310  		field[n]->down = field[n+1];
   311  		field[n]->width = off;
   312  		off += field[n]->type->width;
   313  	}
   314  	field[6]->down = T;
   315  	off += field[6]->type->width;
   316  	if(off != 10 * widthptr)
   317  		yyerror("hash_iter size not correct %d %d", off, 10 * widthptr);
   318  	t->hiter = i;
   319  	i->map = t;
   320  	return i;
   321  }
   322  
   323  /*
   324   * f is method type, with receiver.
   325   * return function type, receiver as first argument (or not).
   326   */
   327  Type*
   328  methodfunc(Type *f, Type *receiver)
   329  {
   330  	NodeList *in, *out;
   331  	Node *d;
   332  	Type *t;
   333  
   334  	in = nil;
   335  	if(receiver) {
   336  		d = nod(ODCLFIELD, N, N);
   337  		d->type = receiver;
   338  		in = list(in, d);
   339  	}
   340  	for(t=getinargx(f)->type; t; t=t->down) {
   341  		d = nod(ODCLFIELD, N, N);
   342  		d->type = t->type;
   343  		d->isddd = t->isddd;
   344  		in = list(in, d);
   345  	}
   346  
   347  	out = nil;
   348  	for(t=getoutargx(f)->type; t; t=t->down) {
   349  		d = nod(ODCLFIELD, N, N);
   350  		d->type = t->type;
   351  		out = list(out, d);
   352  	}
   353  
   354  	t = functype(N, in, out);
   355  	if(f->nname) {
   356  		// Link to name of original method function.
   357  		t->nname = f->nname;
   358  	}
   359  	return t;
   360  }
   361  
   362  /*
   363   * return methods of non-interface type t, sorted by name.
   364   * generates stub functions as needed.
   365   */
   366  static Sig*
   367  methods(Type *t)
   368  {
   369  	Type *f, *mt, *it, *this;
   370  	Sig *a, *b;
   371  	Sym *method;
   372  
   373  	// method type
   374  	mt = methtype(t, 0);
   375  	if(mt == T)
   376  		return nil;
   377  	expandmeth(mt);
   378  
   379  	// type stored in interface word
   380  	it = t;
   381  	if(!isdirectiface(it))
   382  		it = ptrto(t);
   383  
   384  	// make list of methods for t,
   385  	// generating code if necessary.
   386  	a = nil;
   387  	for(f=mt->xmethod; f; f=f->down) {
   388  		if(f->etype != TFIELD)
   389  			fatal("methods: not field %T", f);
   390  		if (f->type->etype != TFUNC || f->type->thistuple == 0)
   391  			fatal("non-method on %T method %S %T\n", mt, f->sym, f);
   392  		if (!getthisx(f->type)->type)
   393  			fatal("receiver with no type on %T method %S %T\n", mt, f->sym, f);
   394  		if(f->nointerface)
   395  			continue;
   396  
   397  		method = f->sym;
   398  		if(method == nil)
   399  			continue;
   400  
   401  		// get receiver type for this particular method.
   402  		// if pointer receiver but non-pointer t and
   403  		// this is not an embedded pointer inside a struct,
   404  		// method does not apply.
   405  		this = getthisx(f->type)->type->type;
   406  		if(isptr[this->etype] && this->type == t)
   407  			continue;
   408  		if(isptr[this->etype] && !isptr[t->etype]
   409  		&& f->embedded != 2 && !isifacemethod(f->type))
   410  			continue;
   411  
   412  		b = mal(sizeof(*b));
   413  		b->link = a;
   414  		a = b;
   415  
   416  		a->name = method->name;
   417  		if(!exportname(method->name)) {
   418  			if(method->pkg == nil)
   419  				fatal("methods: missing package");
   420  			a->pkg = method->pkg;
   421  		}
   422  		a->isym = methodsym(method, it, 1);
   423  		a->tsym = methodsym(method, t, 0);
   424  		a->type = methodfunc(f->type, t);
   425  		a->mtype = methodfunc(f->type, nil);
   426  
   427  		if(!(a->isym->flags & SymSiggen)) {
   428  			a->isym->flags |= SymSiggen;
   429  			if(!eqtype(this, it) || this->width < types[tptr]->width) {
   430  				compiling_wrappers = 1;
   431  				genwrapper(it, f, a->isym, 1);
   432  				compiling_wrappers = 0;
   433  			}
   434  		}
   435  
   436  		if(!(a->tsym->flags & SymSiggen)) {
   437  			a->tsym->flags |= SymSiggen;
   438  			if(!eqtype(this, t)) {
   439  				compiling_wrappers = 1;
   440  				genwrapper(t, f, a->tsym, 0);
   441  				compiling_wrappers = 0;
   442  			}
   443  		}
   444  	}
   445  
   446  	return lsort(a, sigcmp);
   447  }
   448  
   449  /*
   450   * return methods of interface type t, sorted by name.
   451   */
   452  static Sig*
   453  imethods(Type *t)
   454  {
   455  	Sig *a, *all, *last;
   456  	Type *f;
   457  	Sym *method, *isym;
   458  
   459  	all = nil;
   460  	last = nil;
   461  	for(f=t->type; f; f=f->down) {
   462  		if(f->etype != TFIELD)
   463  			fatal("imethods: not field");
   464  		if(f->type->etype != TFUNC || f->sym == nil)
   465  			continue;
   466  		method = f->sym;
   467  		a = mal(sizeof(*a));
   468  		a->name = method->name;
   469  		if(!exportname(method->name)) {
   470  			if(method->pkg == nil)
   471  				fatal("imethods: missing package");
   472  			a->pkg = method->pkg;
   473  		}
   474  		a->mtype = f->type;
   475  		a->offset = 0;
   476  		a->type = methodfunc(f->type, nil);
   477  
   478  		if(last && sigcmp(last, a) >= 0)
   479  			fatal("sigcmp vs sortinter %s %s", last->name, a->name);
   480  		if(last == nil)
   481  			all = a;
   482  		else
   483  			last->link = a;
   484  		last = a;
   485  
   486  		// Compiler can only refer to wrappers for non-blank methods.
   487  		if(isblanksym(method))
   488  			continue;
   489  
   490  		// NOTE(rsc): Perhaps an oversight that
   491  		// IfaceType.Method is not in the reflect data.
   492  		// Generate the method body, so that compiled
   493  		// code can refer to it.
   494  		isym = methodsym(method, t, 0);
   495  		if(!(isym->flags & SymSiggen)) {
   496  			isym->flags |= SymSiggen;
   497  			genwrapper(t, f, isym, 0);
   498  		}
   499  	}
   500  	return all;
   501  }
   502  
   503  static void
   504  dimportpath(Pkg *p)
   505  {
   506  	static Pkg *gopkg;
   507  	char *nam;
   508  	Node *n;
   509  
   510  	if(p->pathsym != S)
   511  		return;
   512  
   513  	if(gopkg == nil) {
   514  		gopkg = mkpkg(strlit("go"));
   515  		gopkg->name = "go";
   516  	}
   517  	nam = smprint("importpath.%s.", p->prefix);
   518  
   519  	n = nod(ONAME, N, N);
   520  	n->sym = pkglookup(nam, gopkg);
   521  	free(nam);
   522  	n->class = PEXTERN;
   523  	n->xoffset = 0;
   524  	p->pathsym = n->sym;
   525  
   526  	gdatastring(n, p->path);
   527  	ggloblsym(n->sym, types[TSTRING]->width, DUPOK|RODATA);
   528  }
   529  
   530  static int
   531  dgopkgpath(Sym *s, int ot, Pkg *pkg)
   532  {
   533  	if(pkg == nil)
   534  		return dgostringptr(s, ot, nil);
   535  
   536  	// Emit reference to go.importpath.""., which 6l will
   537  	// rewrite using the correct import path.  Every package
   538  	// that imports this one directly defines the symbol.
   539  	if(pkg == localpkg) {
   540  		static Sym *ns;
   541  
   542  		if(ns == nil)
   543  			ns = pkglookup("importpath.\"\".", mkpkg(strlit("go")));
   544  		return dsymptr(s, ot, ns, 0);
   545  	}
   546  
   547  	dimportpath(pkg);
   548  	return dsymptr(s, ot, pkg->pathsym, 0);
   549  }
   550  
   551  /*
   552   * uncommonType
   553   * ../../runtime/type.go:/uncommonType
   554   */
   555  static int
   556  dextratype(Sym *sym, int off, Type *t, int ptroff)
   557  {
   558  	int ot, n;
   559  	Sym *s;
   560  	Sig *a, *m;
   561  
   562  	m = methods(t);
   563  	if(t->sym == nil && m == nil)
   564  		return off;
   565  
   566  	// fill in *extraType pointer in header
   567  	off = rnd(off, widthptr);
   568  	dsymptr(sym, ptroff, sym, off);
   569  
   570  	n = 0;
   571  	for(a=m; a; a=a->link) {
   572  		dtypesym(a->type);
   573  		n++;
   574  	}
   575  
   576  	ot = off;
   577  	s = sym;
   578  	if(t->sym) {
   579  		ot = dgostringptr(s, ot, t->sym->name);
   580  		if(t != types[t->etype] && t != errortype)
   581  			ot = dgopkgpath(s, ot, t->sym->pkg);
   582  		else
   583  			ot = dgostringptr(s, ot, nil);
   584  	} else {
   585  		ot = dgostringptr(s, ot, nil);
   586  		ot = dgostringptr(s, ot, nil);
   587  	}
   588  
   589  	// slice header
   590  	ot = dsymptr(s, ot, s, ot + widthptr + 2*widthint);
   591  	ot = duintxx(s, ot, n, widthint);
   592  	ot = duintxx(s, ot, n, widthint);
   593  
   594  	// methods
   595  	for(a=m; a; a=a->link) {
   596  		// method
   597  		// ../../runtime/type.go:/method
   598  		ot = dgostringptr(s, ot, a->name);
   599  		ot = dgopkgpath(s, ot, a->pkg);
   600  		ot = dsymptr(s, ot, dtypesym(a->mtype), 0);
   601  		ot = dsymptr(s, ot, dtypesym(a->type), 0);
   602  		if(a->isym)
   603  			ot = dsymptr(s, ot, a->isym, 0);
   604  		else
   605  			ot = duintptr(s, ot, 0);
   606  		if(a->tsym)
   607  			ot = dsymptr(s, ot, a->tsym, 0);
   608  		else
   609  			ot = duintptr(s, ot, 0);
   610  	}
   611  
   612  	return ot;
   613  }
   614  
   615  static int
   616  kinds[] =
   617  {
   618  	[TINT]		= KindInt,
   619  	[TUINT]		= KindUint,
   620  	[TINT8]		= KindInt8,
   621  	[TUINT8]	= KindUint8,
   622  	[TINT16]	= KindInt16,
   623  	[TUINT16]	= KindUint16,
   624  	[TINT32]	= KindInt32,
   625  	[TUINT32]	= KindUint32,
   626  	[TINT64]	= KindInt64,
   627  	[TUINT64]	= KindUint64,
   628  	[TUINTPTR]	= KindUintptr,
   629  	[TFLOAT32]	= KindFloat32,
   630  	[TFLOAT64]	= KindFloat64,
   631  	[TBOOL]		= KindBool,
   632  	[TSTRING]		= KindString,
   633  	[TPTR32]		= KindPtr,
   634  	[TPTR64]		= KindPtr,
   635  	[TSTRUCT]	= KindStruct,
   636  	[TINTER]		= KindInterface,
   637  	[TCHAN]		= KindChan,
   638  	[TMAP]		= KindMap,
   639  	[TARRAY]		= KindArray,
   640  	[TFUNC]		= KindFunc,
   641  	[TCOMPLEX64]	= KindComplex64,
   642  	[TCOMPLEX128]	= KindComplex128,
   643  	[TUNSAFEPTR]	= KindUnsafePointer,
   644  };
   645  
   646  int
   647  haspointers(Type *t)
   648  {
   649  	Type *t1;
   650  	int ret;
   651  
   652  	if(t->haspointers != 0)
   653  		return t->haspointers - 1;
   654  
   655  	switch(t->etype) {
   656  	case TINT:
   657  	case TUINT:
   658  	case TINT8:
   659  	case TUINT8:
   660  	case TINT16:
   661  	case TUINT16:
   662  	case TINT32:
   663  	case TUINT32:
   664  	case TINT64:
   665  	case TUINT64:
   666  	case TUINTPTR:
   667  	case TFLOAT32:
   668  	case TFLOAT64:
   669  	case TCOMPLEX64:
   670  	case TCOMPLEX128:
   671  	case TBOOL:
   672  		ret = 0;
   673  		break;
   674  	case TARRAY:
   675  		if(t->bound < 0) {	// slice
   676  			ret = 1;
   677  			break;
   678  		}
   679  		if(t->bound == 0) {	// empty array
   680  			ret = 0;
   681  			break;
   682  		}
   683  		ret = haspointers(t->type);
   684  		break;
   685  	case TSTRUCT:
   686  		ret = 0;
   687  		for(t1=t->type; t1!=T; t1=t1->down) {
   688  			if(haspointers(t1->type)) {
   689  				ret = 1;
   690  				break;
   691  			}
   692  		}
   693  		break;
   694  	case TSTRING:
   695  	case TPTR32:
   696  	case TPTR64:
   697  	case TUNSAFEPTR:
   698  	case TINTER:
   699  	case TCHAN:
   700  	case TMAP:
   701  	case TFUNC:
   702  	default:
   703  		ret = 1;
   704  		break;
   705  	}
   706  	
   707  	t->haspointers = 1+ret;
   708  	return ret;
   709  }
   710  
   711  /*
   712   * commonType
   713   * ../../runtime/type.go:/commonType
   714   */
   715  static int
   716  dcommontype(Sym *s, int ot, Type *t)
   717  {
   718  	int i, alg, sizeofAlg, gcprog;
   719  	Sym *sptr, *algsym, *zero, *gcprog0, *gcprog1, *sbits;
   720  	uint8 gcmask[16];
   721  	static Sym *algarray;
   722  	uint64 x1, x2;
   723  	char *p;
   724  	
   725  	if(ot != 0)
   726  		fatal("dcommontype %d", ot);
   727  
   728  	sizeofAlg = 2*widthptr;
   729  	if(algarray == nil)
   730  		algarray = pkglookup("algarray", runtimepkg);
   731  	dowidth(t);
   732  	alg = algtype(t);
   733  	algsym = S;
   734  	if(alg < 0 || alg == AMEM)
   735  		algsym = dalgsym(t);
   736  
   737  	if(t->sym != nil && !isptr[t->etype])
   738  		sptr = dtypesym(ptrto(t));
   739  	else
   740  		sptr = weaktypesym(ptrto(t));
   741  
   742  	// All (non-reflect-allocated) Types share the same zero object.
   743  	// Each place in the compiler where a pointer to the zero object
   744  	// might be returned by a runtime call (map access return value,
   745  	// 2-arg type cast) declares the size of the zerovalue it needs.
   746  	// The linker magically takes the max of all the sizes.
   747  	zero = pkglookup("zerovalue", runtimepkg);
   748  
   749  	// We use size 0 here so we get the pointer to the zero value,
   750  	// but don't allocate space for the zero value unless we need it.
   751  	// TODO: how do we get this symbol into bss?  We really want
   752  	// a read-only bss, but I don't think such a thing exists.
   753  
   754  	// ../../pkg/reflect/type.go:/^type.commonType
   755  	// actual type structure
   756  	//	type commonType struct {
   757  	//		size          uintptr
   758  	//		hash          uint32
   759  	//		_             uint8
   760  	//		align         uint8
   761  	//		fieldAlign    uint8
   762  	//		kind          uint8
   763  	//		alg           unsafe.Pointer
   764  	//		gc            unsafe.Pointer
   765  	//		string        *string
   766  	//		*extraType
   767  	//		ptrToThis     *Type
   768  	//		zero          unsafe.Pointer
   769  	//	}
   770  	ot = duintptr(s, ot, t->width);
   771  	ot = duint32(s, ot, typehash(t));
   772  	ot = duint8(s, ot, 0);	// unused
   773  
   774  	// runtime (and common sense) expects alignment to be a power of two.
   775  	i = t->align;
   776  	if(i == 0)
   777  		i = 1;
   778  	if((i&(i-1)) != 0)
   779  		fatal("invalid alignment %d for %T", t->align, t);
   780  	ot = duint8(s, ot, t->align);	// align
   781  	ot = duint8(s, ot, t->align);	// fieldAlign
   782  
   783  	gcprog = usegcprog(t);
   784  	i = kinds[t->etype];
   785  	if(t->etype == TARRAY && t->bound < 0)
   786  		i = KindSlice;
   787  	if(!haspointers(t))
   788  		i |= KindNoPointers;
   789  	if(isdirectiface(t))
   790  		i |= KindDirectIface;
   791  	if(gcprog)
   792  		i |= KindGCProg;
   793  	ot = duint8(s, ot, i);  // kind
   794  	if(algsym == S)
   795  		ot = dsymptr(s, ot, algarray, alg*sizeofAlg);
   796  	else
   797  		ot = dsymptr(s, ot, algsym, 0);
   798  	// gc
   799  	if(gcprog) {
   800  		gengcprog(t, &gcprog0, &gcprog1);
   801  		if(gcprog0 != S)
   802  			ot = dsymptr(s, ot, gcprog0, 0);
   803  		else
   804  			ot = duintptr(s, ot, 0);
   805  		ot = dsymptr(s, ot, gcprog1, 0);
   806  	} else {
   807  		gengcmask(t, gcmask);
   808  		x1 = 0;
   809  		for(i=0; i<8; i++)
   810  			x1 = x1<<8 | gcmask[i];
   811  		if(widthptr == 4) {
   812  			p = smprint("gcbits.%#016llux", x1);
   813  		} else {
   814  			x2 = 0;
   815  			for(i=0; i<8; i++)
   816  				x2 = x2<<8 | gcmask[i+8];
   817  			p = smprint("gcbits.%#016llux%016llux", x1, x2);
   818  		}
   819  		sbits = pkglookup(p, runtimepkg);
   820  		if((sbits->flags & SymUniq) == 0) {
   821  			sbits->flags |= SymUniq;
   822  			for(i = 0; i < 2*widthptr; i++)
   823  				duint8(sbits, i, gcmask[i]);
   824  			ggloblsym(sbits, 2*widthptr, DUPOK|RODATA);
   825  		}
   826  		ot = dsymptr(s, ot, sbits, 0);
   827  		ot = duintptr(s, ot, 0);
   828  	}
   829  	p = smprint("%-uT", t);
   830  	//print("dcommontype: %s\n", p);
   831  	ot = dgostringptr(s, ot, p);	// string
   832  	free(p);
   833  
   834  	// skip pointer to extraType,
   835  	// which follows the rest of this type structure.
   836  	// caller will fill in if needed.
   837  	// otherwise linker will assume 0.
   838  	ot += widthptr;
   839  
   840  	ot = dsymptr(s, ot, sptr, 0);  // ptrto type
   841  	ot = dsymptr(s, ot, zero, 0);  // ptr to zero value
   842  	return ot;
   843  }
   844  
   845  Sym*
   846  typesym(Type *t)
   847  {
   848  	char *p;
   849  	Sym *s;
   850  
   851  	p = smprint("%-T", t);
   852  	s = pkglookup(p, typepkg);
   853  	//print("typesym: %s -> %+S\n", p, s);
   854  	free(p);
   855  	return s;
   856  }
   857  
   858  Sym*
   859  tracksym(Type *t)
   860  {
   861  	char *p;
   862  	Sym *s;
   863  
   864  	p = smprint("%-T.%s", t->outer, t->sym->name);
   865  	s = pkglookup(p, trackpkg);
   866  	free(p);
   867  	return s;
   868  }
   869  
   870  Sym*
   871  typelinksym(Type *t)
   872  {
   873  	char *p;
   874  	Sym *s;
   875  
   876  	// %-uT is what the generated Type's string field says.
   877  	// It uses (ambiguous) package names instead of import paths.
   878  	// %-T is the complete, unambiguous type name.
   879  	// We want the types to end up sorted by string field,
   880  	// so use that first in the name, and then add :%-T to
   881  	// disambiguate. The names are a little long but they are
   882  	// discarded by the linker and do not end up in the symbol
   883  	// table of the final binary.
   884  	p = smprint("%-uT/%-T", t, t);
   885  	s = pkglookup(p, typelinkpkg);
   886  	//print("typelinksym: %s -> %+S\n", p, s);
   887  	free(p);
   888  	return s;
   889  }
   890  
   891  Sym*
   892  typesymprefix(char *prefix, Type *t)
   893  {
   894  	char *p;
   895  	Sym *s;
   896  
   897  	p = smprint("%s.%-T", prefix, t);
   898  	s = pkglookup(p, typepkg);
   899  	//print("algsym: %s -> %+S\n", p, s);
   900  	free(p);
   901  	return s;
   902  }
   903  
   904  Sym*
   905  typenamesym(Type *t)
   906  {
   907  	Sym *s;
   908  	Node *n;
   909  
   910  	if(t == T || (isptr[t->etype] && t->type == T) || isideal(t))
   911  		fatal("typename %T", t);
   912  	s = typesym(t);
   913  	if(s->def == N) {
   914  		n = nod(ONAME, N, N);
   915  		n->sym = s;
   916  		n->type = types[TUINT8];
   917  		n->addable = 1;
   918  		n->ullman = 1;
   919  		n->class = PEXTERN;
   920  		n->xoffset = 0;
   921  		n->typecheck = 1;
   922  		s->def = n;
   923  
   924  		signatlist = list(signatlist, typenod(t));
   925  	}
   926  	return s->def->sym;
   927  }
   928  
   929  Node*
   930  typename(Type *t)
   931  {
   932  	Sym *s;
   933  	Node *n;
   934  
   935  	s = typenamesym(t);
   936  	n = nod(OADDR, s->def, N);
   937  	n->type = ptrto(s->def->type);
   938  	n->addable = 1;
   939  	n->ullman = 2;
   940  	n->typecheck = 1;
   941  	return n;
   942  }
   943  
   944  static Sym*
   945  weaktypesym(Type *t)
   946  {
   947  	char *p;
   948  	Sym *s;
   949  
   950  	p = smprint("%-T", t);
   951  	s = pkglookup(p, weaktypepkg);
   952  	//print("weaktypesym: %s -> %+S\n", p, s);
   953  	free(p);
   954  	return s;
   955  }
   956  
   957  /*
   958   * Returns 1 if t has a reflexive equality operator.
   959   * That is, if x==x for all x of type t.
   960   */
   961  static int
   962  isreflexive(Type *t)
   963  {
   964  	Type *t1;
   965  	switch(t->etype) {
   966  		case TBOOL:
   967  		case TINT:
   968  		case TUINT:
   969  		case TINT8:
   970  		case TUINT8:
   971  		case TINT16:
   972  		case TUINT16:
   973  		case TINT32:
   974  		case TUINT32:
   975  		case TINT64:
   976  		case TUINT64:
   977  		case TUINTPTR:
   978  		case TPTR32:
   979  		case TPTR64:
   980  		case TUNSAFEPTR:
   981  		case TSTRING:
   982  		case TCHAN:
   983  			return 1;
   984  		case TFLOAT32:
   985  		case TFLOAT64:
   986  		case TCOMPLEX64:
   987  		case TCOMPLEX128:
   988  		case TINTER:
   989  			return 0;
   990  		case TARRAY:
   991  			if(isslice(t))
   992  				fatal("slice can't be a map key: %T", t);
   993  			return isreflexive(t->type);
   994  		case TSTRUCT:
   995  			for(t1=t->type; t1!=T; t1=t1->down) {
   996  				if(!isreflexive(t1->type))
   997  					return 0;
   998  			}
   999  			return 1;
  1000  		default:
  1001  			fatal("bad type for map key: %T", t);
  1002  			return 0;
  1003  	}
  1004  }
  1005  
  1006  static Sym*
  1007  dtypesym(Type *t)
  1008  {
  1009  	int ot, xt, n, isddd, dupok;
  1010  	Sym *s, *s1, *s2, *s3, *s4, *slink;
  1011  	Sig *a, *m;
  1012  	Type *t1, *tbase, *t2;
  1013  
  1014  	// Replace byte, rune aliases with real type.
  1015  	// They've been separate internally to make error messages
  1016  	// better, but we have to merge them in the reflect tables.
  1017  	if(t == bytetype || t == runetype)
  1018  		t = types[t->etype];
  1019  
  1020  	if(isideal(t))
  1021  		fatal("dtypesym %T", t);
  1022  
  1023  	s = typesym(t);
  1024  	if(s->flags & SymSiggen)
  1025  		return s;
  1026  	s->flags |= SymSiggen;
  1027  
  1028  	// special case (look for runtime below):
  1029  	// when compiling package runtime,
  1030  	// emit the type structures for int, float, etc.
  1031  	tbase = t;
  1032  	if(isptr[t->etype] && t->sym == S && t->type->sym != S)
  1033  		tbase = t->type;
  1034  	dupok = 0;
  1035  	if(tbase->sym == S)
  1036  		dupok = DUPOK;
  1037  
  1038  	if(compiling_runtime &&
  1039  			(tbase == types[tbase->etype] ||
  1040  			tbase == bytetype ||
  1041  			tbase == runetype ||
  1042  			tbase == errortype)) { // int, float, etc
  1043  		goto ok;
  1044  	}
  1045  
  1046  	// named types from other files are defined only by those files
  1047  	if(tbase->sym && !tbase->local)
  1048  		return s;
  1049  	if(isforw[tbase->etype])
  1050  		return s;
  1051  
  1052  ok:
  1053  	ot = 0;
  1054  	xt = 0;
  1055  	switch(t->etype) {
  1056  	default:
  1057  		ot = dcommontype(s, ot, t);
  1058  		xt = ot - 3*widthptr;
  1059  		break;
  1060  
  1061  	case TARRAY:
  1062  		if(t->bound >= 0) {
  1063  			// ../../runtime/type.go:/ArrayType
  1064  			s1 = dtypesym(t->type);
  1065  			t2 = typ(TARRAY);
  1066  			t2->type = t->type;
  1067  			t2->bound = -1;  // slice
  1068  			s2 = dtypesym(t2);
  1069  			ot = dcommontype(s, ot, t);
  1070  			xt = ot - 3*widthptr;
  1071  			ot = dsymptr(s, ot, s1, 0);
  1072  			ot = dsymptr(s, ot, s2, 0);
  1073  			ot = duintptr(s, ot, t->bound);
  1074  		} else {
  1075  			// ../../runtime/type.go:/SliceType
  1076  			s1 = dtypesym(t->type);
  1077  			ot = dcommontype(s, ot, t);
  1078  			xt = ot - 3*widthptr;
  1079  			ot = dsymptr(s, ot, s1, 0);
  1080  		}
  1081  		break;
  1082  
  1083  	case TCHAN:
  1084  		// ../../runtime/type.go:/ChanType
  1085  		s1 = dtypesym(t->type);
  1086  		ot = dcommontype(s, ot, t);
  1087  		xt = ot - 3*widthptr;
  1088  		ot = dsymptr(s, ot, s1, 0);
  1089  		ot = duintptr(s, ot, t->chan);
  1090  		break;
  1091  
  1092  	case TFUNC:
  1093  		for(t1=getthisx(t)->type; t1; t1=t1->down)
  1094  			dtypesym(t1->type);
  1095  		isddd = 0;
  1096  		for(t1=getinargx(t)->type; t1; t1=t1->down) {
  1097  			isddd = t1->isddd;
  1098  			dtypesym(t1->type);
  1099  		}
  1100  		for(t1=getoutargx(t)->type; t1; t1=t1->down)
  1101  			dtypesym(t1->type);
  1102  
  1103  		ot = dcommontype(s, ot, t);
  1104  		xt = ot - 3*widthptr;
  1105  		ot = duint8(s, ot, isddd);
  1106  
  1107  		// two slice headers: in and out.
  1108  		ot = rnd(ot, widthptr);
  1109  		ot = dsymptr(s, ot, s, ot+2*(widthptr+2*widthint));
  1110  		n = t->thistuple + t->intuple;
  1111  		ot = duintxx(s, ot, n, widthint);
  1112  		ot = duintxx(s, ot, n, widthint);
  1113  		ot = dsymptr(s, ot, s, ot+1*(widthptr+2*widthint)+n*widthptr);
  1114  		ot = duintxx(s, ot, t->outtuple, widthint);
  1115  		ot = duintxx(s, ot, t->outtuple, widthint);
  1116  
  1117  		// slice data
  1118  		for(t1=getthisx(t)->type; t1; t1=t1->down, n++)
  1119  			ot = dsymptr(s, ot, dtypesym(t1->type), 0);
  1120  		for(t1=getinargx(t)->type; t1; t1=t1->down, n++)
  1121  			ot = dsymptr(s, ot, dtypesym(t1->type), 0);
  1122  		for(t1=getoutargx(t)->type; t1; t1=t1->down, n++)
  1123  			ot = dsymptr(s, ot, dtypesym(t1->type), 0);
  1124  		break;
  1125  
  1126  	case TINTER:
  1127  		m = imethods(t);
  1128  		n = 0;
  1129  		for(a=m; a; a=a->link) {
  1130  			dtypesym(a->type);
  1131  			n++;
  1132  		}
  1133  
  1134  		// ../../runtime/type.go:/InterfaceType
  1135  		ot = dcommontype(s, ot, t);
  1136  		xt = ot - 3*widthptr;
  1137  		ot = dsymptr(s, ot, s, ot+widthptr+2*widthint);
  1138  		ot = duintxx(s, ot, n, widthint);
  1139  		ot = duintxx(s, ot, n, widthint);
  1140  		for(a=m; a; a=a->link) {
  1141  			// ../../runtime/type.go:/imethod
  1142  			ot = dgostringptr(s, ot, a->name);
  1143  			ot = dgopkgpath(s, ot, a->pkg);
  1144  			ot = dsymptr(s, ot, dtypesym(a->type), 0);
  1145  		}
  1146  		break;
  1147  
  1148  	case TMAP:
  1149  		// ../../runtime/type.go:/MapType
  1150  		s1 = dtypesym(t->down);
  1151  		s2 = dtypesym(t->type);
  1152  		s3 = dtypesym(mapbucket(t));
  1153  		s4 = dtypesym(hmap(t));
  1154  		ot = dcommontype(s, ot, t);
  1155  		xt = ot - 3*widthptr;
  1156  		ot = dsymptr(s, ot, s1, 0);
  1157  		ot = dsymptr(s, ot, s2, 0);
  1158  		ot = dsymptr(s, ot, s3, 0);
  1159  		ot = dsymptr(s, ot, s4, 0);
  1160  		if(t->down->width > MAXKEYSIZE) {
  1161  			ot = duint8(s, ot, widthptr);
  1162  			ot = duint8(s, ot, 1); // indirect
  1163  		} else {
  1164  			ot = duint8(s, ot, t->down->width);
  1165  			ot = duint8(s, ot, 0); // not indirect
  1166  		}
  1167  		if(t->type->width > MAXVALSIZE) {
  1168  			ot = duint8(s, ot, widthptr);
  1169  			ot = duint8(s, ot, 1); // indirect
  1170  		} else {
  1171  			ot = duint8(s, ot, t->type->width);
  1172  			ot = duint8(s, ot, 0); // not indirect
  1173  		}
  1174  		ot = duint16(s, ot, mapbucket(t)->width);
  1175                  ot = duint8(s, ot, isreflexive(t->down));
  1176  		break;
  1177  
  1178  	case TPTR32:
  1179  	case TPTR64:
  1180  		if(t->type->etype == TANY) {
  1181  			// ../../runtime/type.go:/UnsafePointerType
  1182  			ot = dcommontype(s, ot, t);
  1183  			break;
  1184  		}
  1185  		// ../../runtime/type.go:/PtrType
  1186  		s1 = dtypesym(t->type);
  1187  		ot = dcommontype(s, ot, t);
  1188  		xt = ot - 3*widthptr;
  1189  		ot = dsymptr(s, ot, s1, 0);
  1190  		break;
  1191  
  1192  	case TSTRUCT:
  1193  		// ../../runtime/type.go:/StructType
  1194  		// for security, only the exported fields.
  1195  		n = 0;
  1196  		for(t1=t->type; t1!=T; t1=t1->down) {
  1197  			dtypesym(t1->type);
  1198  			n++;
  1199  		}
  1200  		ot = dcommontype(s, ot, t);
  1201  		xt = ot - 3*widthptr;
  1202  		ot = dsymptr(s, ot, s, ot+widthptr+2*widthint);
  1203  		ot = duintxx(s, ot, n, widthint);
  1204  		ot = duintxx(s, ot, n, widthint);
  1205  		for(t1=t->type; t1!=T; t1=t1->down) {
  1206  			// ../../runtime/type.go:/structField
  1207  			if(t1->sym && !t1->embedded) {
  1208  				ot = dgostringptr(s, ot, t1->sym->name);
  1209  				if(exportname(t1->sym->name))
  1210  					ot = dgostringptr(s, ot, nil);
  1211  				else
  1212  					ot = dgopkgpath(s, ot, t1->sym->pkg);
  1213  			} else {
  1214  				ot = dgostringptr(s, ot, nil);
  1215  				if(t1->type->sym != S && t1->type->sym->pkg == builtinpkg)
  1216  					ot = dgopkgpath(s, ot, localpkg);
  1217  				else
  1218  					ot = dgostringptr(s, ot, nil);
  1219  			}
  1220  			ot = dsymptr(s, ot, dtypesym(t1->type), 0);
  1221  			ot = dgostrlitptr(s, ot, t1->note);
  1222  			ot = duintptr(s, ot, t1->width);	// field offset
  1223  		}
  1224  		break;
  1225  	}
  1226  	ot = dextratype(s, ot, t, xt);
  1227  	ggloblsym(s, ot, dupok|RODATA);
  1228  
  1229  	// generate typelink.foo pointing at s = type.foo.
  1230  	// The linker will leave a table of all the typelinks for
  1231  	// types in the binary, so reflect can find them.
  1232  	// We only need the link for unnamed composites that
  1233  	// we want be able to find.
  1234  	if(t->sym == S) {
  1235  		switch(t->etype) {
  1236  		case TARRAY:
  1237  		case TCHAN:
  1238  		case TMAP:
  1239  			slink = typelinksym(t);
  1240  			dsymptr(slink, 0, s, 0);
  1241  			ggloblsym(slink, widthptr, dupok|RODATA);
  1242  		}
  1243  	}
  1244  
  1245  	return s;
  1246  }
  1247  
  1248  void
  1249  dumptypestructs(void)
  1250  {
  1251  	int i;
  1252  	NodeList *l;
  1253  	Node *n;
  1254  	Type *t;
  1255  	Pkg *p;
  1256  
  1257  	// copy types from externdcl list to signatlist
  1258  	for(l=externdcl; l; l=l->next) {
  1259  		n = l->n;
  1260  		if(n->op != OTYPE)
  1261  			continue;
  1262  		signatlist = list(signatlist, n);
  1263  	}
  1264  
  1265  	// process signatlist
  1266  	for(l=signatlist; l; l=l->next) {
  1267  		n = l->n;
  1268  		if(n->op != OTYPE)
  1269  			continue;
  1270  		t = n->type;
  1271  		dtypesym(t);
  1272  		if(t->sym)
  1273  			dtypesym(ptrto(t));
  1274  	}
  1275  
  1276  	// generate import strings for imported packages
  1277  	for(i=0; i<nelem(phash); i++)
  1278  		for(p=phash[i]; p; p=p->link)
  1279  			if(p->direct)
  1280  				dimportpath(p);
  1281  
  1282  	// do basic types if compiling package runtime.
  1283  	// they have to be in at least one package,
  1284  	// and runtime is always loaded implicitly,
  1285  	// so this is as good as any.
  1286  	// another possible choice would be package main,
  1287  	// but using runtime means fewer copies in .6 files.
  1288  	if(compiling_runtime) {
  1289  		for(i=1; i<=TBOOL; i++)
  1290  			dtypesym(ptrto(types[i]));
  1291  		dtypesym(ptrto(types[TSTRING]));
  1292  		dtypesym(ptrto(types[TUNSAFEPTR]));
  1293  
  1294  		// emit type structs for error and func(error) string.
  1295  		// The latter is the type of an auto-generated wrapper.
  1296  		dtypesym(ptrto(errortype));
  1297  		dtypesym(functype(nil,
  1298  			list1(nod(ODCLFIELD, N, typenod(errortype))),
  1299  			list1(nod(ODCLFIELD, N, typenod(types[TSTRING])))));
  1300  
  1301  		// add paths for runtime and main, which 6l imports implicitly.
  1302  		dimportpath(runtimepkg);
  1303  		if(flag_race)
  1304  			dimportpath(racepkg);
  1305  		dimportpath(mkpkg(strlit("main")));
  1306  	}
  1307  }
  1308  
  1309  static Sym*
  1310  dalgsym(Type *t)
  1311  {
  1312  	int ot;
  1313  	Sym *s, *hash, *hashfunc, *eq, *eqfunc;
  1314  	char *p;
  1315  
  1316  	// dalgsym is only called for a type that needs an algorithm table,
  1317  	// which implies that the type is comparable (or else it would use ANOEQ).
  1318  
  1319  	if(algtype(t) == AMEM) {
  1320  		// we use one algorithm table for all AMEM types of a given size
  1321  		p = smprint(".alg%lld", t->width);
  1322  		s = pkglookup(p, typepkg);
  1323  		free(p);
  1324  		if(s->flags & SymAlgGen)
  1325  			return s;
  1326  		s->flags |= SymAlgGen;
  1327  
  1328  		// make hash closure
  1329  		p = smprint(".hashfunc%lld", t->width);
  1330  		hashfunc = pkglookup(p, typepkg);
  1331  		free(p);
  1332  		ot = 0;
  1333  		ot = dsymptr(hashfunc, ot, pkglookup("memhash_varlen", runtimepkg), 0);
  1334  		ot = duintxx(hashfunc, ot, t->width, widthptr); // size encoded in closure
  1335  		ggloblsym(hashfunc, ot, DUPOK|RODATA);
  1336  
  1337  		// make equality closure
  1338  		p = smprint(".eqfunc%lld", t->width);
  1339  		eqfunc = pkglookup(p, typepkg);
  1340  		free(p);
  1341  		ot = 0;
  1342  		ot = dsymptr(eqfunc, ot, pkglookup("memequal_varlen", runtimepkg), 0);
  1343  		ot = duintxx(eqfunc, ot, t->width, widthptr);
  1344  		ggloblsym(eqfunc, ot, DUPOK|RODATA);
  1345  	} else {
  1346  		// generate an alg table specific to this type
  1347  		s = typesymprefix(".alg", t);
  1348  		hash = typesymprefix(".hash", t);
  1349  		eq = typesymprefix(".eq", t);
  1350  		hashfunc = typesymprefix(".hashfunc", t);
  1351  		eqfunc = typesymprefix(".eqfunc", t);
  1352  
  1353  		genhash(hash, t);
  1354  		geneq(eq, t);
  1355  
  1356  		// make Go funcs (closures) for calling hash and equal from Go
  1357  		dsymptr(hashfunc, 0, hash, 0);
  1358  		ggloblsym(hashfunc, widthptr, DUPOK|RODATA);
  1359  		dsymptr(eqfunc, 0, eq, 0);
  1360  		ggloblsym(eqfunc, widthptr, DUPOK|RODATA);
  1361  	}
  1362  	// ../../runtime/alg.go:/typeAlg
  1363  	ot = 0;
  1364  	ot = dsymptr(s, ot, hashfunc, 0);
  1365  	ot = dsymptr(s, ot, eqfunc, 0);
  1366  	ggloblsym(s, ot, DUPOK|RODATA);
  1367  	return s;
  1368  }
  1369  
  1370  static int
  1371  usegcprog(Type *t)
  1372  {
  1373  	vlong size, nptr;
  1374  
  1375  	if(!haspointers(t))
  1376  		return 0;
  1377  	if(t->width == BADWIDTH)
  1378  		dowidth(t);
  1379  	// Calculate size of the unrolled GC mask.
  1380  	nptr = (t->width+widthptr-1)/widthptr;
  1381  	size = nptr;
  1382  	if(size%2)
  1383  		size *= 2;	// repeated
  1384  	size = size*gcBits/8;	// 4 bits per word
  1385  	// Decide whether to use unrolled GC mask or GC program.
  1386  	// We could use a more elaborate condition, but this seems to work well in practice.
  1387  	// For small objects GC program can't give significant reduction.
  1388  	// While large objects usually contain arrays; and even if it don't
  1389  	// the program uses 2-bits per word while mask uses 4-bits per word,
  1390  	// so the program is still smaller.
  1391  	return size > 2*widthptr;
  1392  }
  1393  
  1394  // Generates sparse GC bitmask (4 bits per word).
  1395  static void
  1396  gengcmask(Type *t, uint8 gcmask[16])
  1397  {
  1398  	Bvec *vec;
  1399  	vlong xoffset, nptr, i, j;
  1400  	int  half;
  1401  	uint8 bits, *pos;
  1402  
  1403  	memset(gcmask, 0, 16);
  1404  	if(!haspointers(t))
  1405  		return;
  1406  
  1407  	// Generate compact mask as stacks use.
  1408  	xoffset = 0;
  1409  	vec = bvalloc(2*widthptr*8);
  1410  	twobitwalktype1(t, &xoffset, vec);
  1411  
  1412  	// Unfold the mask for the GC bitmap format:
  1413  	// 4 bits per word, 2 high bits encode pointer info.
  1414  	pos = (uint8*)gcmask;
  1415  	nptr = (t->width+widthptr-1)/widthptr;
  1416  	half = 0;
  1417  	// If number of words is odd, repeat the mask.
  1418  	// This makes simpler handling of arrays in runtime.
  1419  	for(j=0; j<=(nptr%2); j++) {
  1420  		for(i=0; i<nptr; i++) {
  1421  			bits = bvget(vec, i*BitsPerPointer) | bvget(vec, i*BitsPerPointer+1)<<1;
  1422  			// Some fake types (e.g. Hmap) has missing fileds.
  1423  			// twobitwalktype1 generates BitsDead for that holes,
  1424  			// replace BitsDead with BitsScalar.
  1425  			if(bits == BitsDead)
  1426  				bits = BitsScalar;
  1427  			bits <<= 2;
  1428  			if(half)
  1429  				bits <<= 4;
  1430  			*pos |= bits;
  1431  			half = !half;
  1432  			if(!half)
  1433  				pos++;
  1434  		}
  1435  	}
  1436  }
  1437  
  1438  // Helper object for generation of GC programs.
  1439  typedef struct ProgGen ProgGen;
  1440  struct ProgGen
  1441  {
  1442  	Sym*	s;
  1443  	int32	datasize;
  1444  	uint8	data[256/PointersPerByte];
  1445  	vlong	ot;
  1446  };
  1447  
  1448  static void
  1449  proggeninit(ProgGen *g, Sym *s)
  1450  {
  1451  	g->s = s;
  1452  	g->datasize = 0;
  1453  	g->ot = 0;
  1454  	memset(g->data, 0, sizeof(g->data));
  1455  }
  1456  
  1457  static void
  1458  proggenemit(ProgGen *g, uint8 v)
  1459  {
  1460  	g->ot = duint8(g->s, g->ot, v);
  1461  }
  1462  
  1463  // Emits insData block from g->data.
  1464  static void
  1465  proggendataflush(ProgGen *g)
  1466  {
  1467  	int32 i, s;
  1468  
  1469  	if(g->datasize == 0)
  1470  		return;
  1471  	proggenemit(g, insData);
  1472  	proggenemit(g, g->datasize);
  1473  	s = (g->datasize + PointersPerByte - 1)/PointersPerByte;
  1474  	for(i = 0; i < s; i++)
  1475  		proggenemit(g, g->data[i]);
  1476  	g->datasize = 0;
  1477  	memset(g->data, 0, sizeof(g->data));
  1478  }
  1479  
  1480  static void
  1481  proggendata(ProgGen *g, uint8 d)
  1482  {
  1483  	g->data[g->datasize/PointersPerByte] |= d << ((g->datasize%PointersPerByte)*BitsPerPointer);
  1484  	g->datasize++;
  1485  	if(g->datasize == 255)
  1486  		proggendataflush(g);
  1487  }
  1488  
  1489  // Skip v bytes due to alignment, etc.
  1490  static void
  1491  proggenskip(ProgGen *g, vlong off, vlong v)
  1492  {
  1493  	vlong i;
  1494  
  1495  	for(i = off; i < off+v; i++) {
  1496  		if((i%widthptr) == 0)
  1497  			proggendata(g, BitsScalar);
  1498  	}
  1499  }
  1500  
  1501  // Emit insArray instruction.
  1502  static void
  1503  proggenarray(ProgGen *g, vlong len)
  1504  {
  1505  	int32 i;
  1506  
  1507  	proggendataflush(g);
  1508  	proggenemit(g, insArray);
  1509  	for(i = 0; i < widthptr; i++, len >>= 8)
  1510  		proggenemit(g, len);
  1511  }
  1512  
  1513  static void
  1514  proggenarrayend(ProgGen *g)
  1515  {
  1516  	proggendataflush(g);
  1517  	proggenemit(g, insArrayEnd);
  1518  }
  1519  
  1520  static vlong
  1521  proggenfini(ProgGen *g)
  1522  {
  1523  	proggendataflush(g);
  1524  	proggenemit(g, insEnd);
  1525  	return g->ot;
  1526  }
  1527  
  1528  static void gengcprog1(ProgGen *g, Type *t, vlong *xoffset);
  1529  
  1530  // Generates GC program for large types.
  1531  static void
  1532  gengcprog(Type *t, Sym **pgc0, Sym **pgc1)
  1533  {
  1534  	Sym *gc0, *gc1;
  1535  	vlong nptr, size, ot, xoffset;
  1536  	ProgGen g;
  1537  
  1538  	nptr = (t->width+widthptr-1)/widthptr;
  1539  	size = nptr;
  1540  	if(size%2)
  1541  		size *= 2;	// repeated twice
  1542  	size = size*PointersPerByte/8;	// 4 bits per word
  1543  	size++;	// unroll flag in the beginning, used by runtime (see runtime.markallocated)
  1544  	// emity space in BSS for unrolled program
  1545  	*pgc0 = S;
  1546  	// Don't generate it if it's too large, runtime will unroll directly into GC bitmap.
  1547  	if(size <= MaxGCMask) {
  1548  		gc0 = typesymprefix(".gc", t);
  1549  		ggloblsym(gc0, size, DUPOK|NOPTR);
  1550  		*pgc0 = gc0;
  1551  	}
  1552  
  1553  	// program in RODATA
  1554  	gc1 = typesymprefix(".gcprog", t);
  1555  	proggeninit(&g, gc1);
  1556  	xoffset = 0;
  1557  	gengcprog1(&g, t, &xoffset);
  1558  	ot = proggenfini(&g);
  1559  	ggloblsym(gc1, ot, DUPOK|RODATA);
  1560  	*pgc1 = gc1;
  1561  }
  1562  
  1563  // Recursively walks type t and writes GC program into g.
  1564  static void
  1565  gengcprog1(ProgGen *g, Type *t, vlong *xoffset)
  1566  {
  1567  	vlong fieldoffset, i, o, n;
  1568  	Type *t1;
  1569  
  1570  	switch(t->etype) {
  1571  	case TINT8:
  1572  	case TUINT8:
  1573  	case TINT16:
  1574  	case TUINT16:
  1575  	case TINT32:
  1576  	case TUINT32:
  1577  	case TINT64:
  1578  	case TUINT64:
  1579  	case TINT:
  1580  	case TUINT:
  1581  	case TUINTPTR:
  1582  	case TBOOL:
  1583  	case TFLOAT32:
  1584  	case TFLOAT64:
  1585  	case TCOMPLEX64:
  1586  	case TCOMPLEX128:
  1587  		proggenskip(g, *xoffset, t->width);
  1588  		*xoffset += t->width;
  1589  		break;
  1590  	case TPTR32:
  1591  	case TPTR64:
  1592  	case TUNSAFEPTR:
  1593  	case TFUNC:
  1594  	case TCHAN:
  1595  	case TMAP:
  1596  		proggendata(g, BitsPointer);
  1597  		*xoffset += t->width;
  1598  		break;
  1599  	case TSTRING:
  1600  		proggendata(g, BitsPointer);
  1601  		proggendata(g, BitsScalar);
  1602  		*xoffset += t->width;
  1603  		break;
  1604  	case TINTER:
  1605  		// Assuming IfacePointerOnly=1.
  1606  		proggendata(g, BitsPointer);
  1607  		proggendata(g, BitsPointer);
  1608  		*xoffset += t->width;
  1609  		break;
  1610  	case TARRAY:
  1611  		if(isslice(t)) {
  1612  			proggendata(g, BitsPointer);
  1613  			proggendata(g, BitsScalar);
  1614  			proggendata(g, BitsScalar);
  1615  		} else {
  1616  			t1 = t->type;
  1617  			if(t1->width == 0) {
  1618  				// ignore
  1619  			} if(t->bound <= 1 || t->bound*t1->width < 32*widthptr) {
  1620  				for(i = 0; i < t->bound; i++)
  1621  					gengcprog1(g, t1, xoffset);
  1622  			} else if(!haspointers(t1)) {
  1623  				n = t->width;
  1624  				n -= -*xoffset&(widthptr-1); // skip to next ptr boundary
  1625  				proggenarray(g, (n+widthptr-1)/widthptr);
  1626  				proggendata(g, BitsScalar);
  1627  				proggenarrayend(g);
  1628  				*xoffset -= (n+widthptr-1)/widthptr*widthptr - t->width;
  1629  			} else {
  1630  				proggenarray(g, t->bound);
  1631  				gengcprog1(g, t1, xoffset);
  1632  				*xoffset += (t->bound-1)*t1->width;
  1633  				proggenarrayend(g);
  1634  			}
  1635  		}
  1636  		break;
  1637  	case TSTRUCT:
  1638  		o = 0;
  1639  		for(t1 = t->type; t1 != T; t1 = t1->down) {
  1640  			fieldoffset = t1->width;
  1641  			proggenskip(g, *xoffset, fieldoffset - o);
  1642  			*xoffset += fieldoffset - o;
  1643  			gengcprog1(g, t1->type, xoffset);
  1644  			o = fieldoffset + t1->type->width;
  1645  		}
  1646  		proggenskip(g, *xoffset, t->width - o);
  1647  		*xoffset += t->width - o;
  1648  		break;
  1649  	default:
  1650  		fatal("gengcprog1: unexpected type, %T", t);
  1651  	}
  1652  }