github.com/alash3al/go@v0.0.0-20150827002835-d497eeb00540/src/cmd/compile/internal/gc/reflect.go (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  package gc
     6  
     7  import (
     8  	"cmd/internal/gcprog"
     9  	"cmd/internal/obj"
    10  	"fmt"
    11  	"os"
    12  )
    13  
    14  /*
    15   * runtime interface and reflection data structures
    16   */
    17  var signatlist *NodeList
    18  
    19  func sigcmp(a *Sig, b *Sig) int {
    20  	i := stringsCompare(a.name, b.name)
    21  	if i != 0 {
    22  		return i
    23  	}
    24  	if a.pkg == b.pkg {
    25  		return 0
    26  	}
    27  	if a.pkg == nil {
    28  		return -1
    29  	}
    30  	if b.pkg == nil {
    31  		return +1
    32  	}
    33  	return stringsCompare(a.pkg.Path, b.pkg.Path)
    34  }
    35  
    36  func lsort(l *Sig, f func(*Sig, *Sig) int) *Sig {
    37  	if l == nil || l.link == nil {
    38  		return l
    39  	}
    40  
    41  	l1 := l
    42  	l2 := l
    43  	for {
    44  		l2 = l2.link
    45  		if l2 == nil {
    46  			break
    47  		}
    48  		l2 = l2.link
    49  		if l2 == nil {
    50  			break
    51  		}
    52  		l1 = l1.link
    53  	}
    54  
    55  	l2 = l1.link
    56  	l1.link = nil
    57  	l1 = lsort(l, f)
    58  	l2 = lsort(l2, f)
    59  
    60  	/* set up lead element */
    61  	if f(l1, l2) < 0 {
    62  		l = l1
    63  		l1 = l1.link
    64  	} else {
    65  		l = l2
    66  		l2 = l2.link
    67  	}
    68  
    69  	le := l
    70  
    71  	for {
    72  		if l1 == nil {
    73  			for l2 != nil {
    74  				le.link = l2
    75  				le = l2
    76  				l2 = l2.link
    77  			}
    78  
    79  			le.link = nil
    80  			break
    81  		}
    82  
    83  		if l2 == nil {
    84  			for l1 != nil {
    85  				le.link = l1
    86  				le = l1
    87  				l1 = l1.link
    88  			}
    89  
    90  			break
    91  		}
    92  
    93  		if f(l1, l2) < 0 {
    94  			le.link = l1
    95  			le = l1
    96  			l1 = l1.link
    97  		} else {
    98  			le.link = l2
    99  			le = l2
   100  			l2 = l2.link
   101  		}
   102  	}
   103  
   104  	le.link = nil
   105  	return l
   106  }
   107  
   108  // Builds a type representing 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.go!
   113  const (
   114  	BUCKETSIZE = 8
   115  	MAXKEYSIZE = 128
   116  	MAXVALSIZE = 128
   117  )
   118  
   119  func makefield(name string, t *Type) *Type {
   120  	f := typ(TFIELD)
   121  	f.Type = t
   122  	f.Sym = new(Sym)
   123  	f.Sym.Name = name
   124  	return f
   125  }
   126  
   127  func mapbucket(t *Type) *Type {
   128  	if t.Bucket != nil {
   129  		return t.Bucket
   130  	}
   131  
   132  	bucket := typ(TSTRUCT)
   133  	keytype := t.Down
   134  	valtype := t.Type
   135  	dowidth(keytype)
   136  	dowidth(valtype)
   137  	if keytype.Width > MAXKEYSIZE {
   138  		keytype = Ptrto(keytype)
   139  	}
   140  	if valtype.Width > MAXVALSIZE {
   141  		valtype = Ptrto(valtype)
   142  	}
   143  
   144  	// The first field is: uint8 topbits[BUCKETSIZE].
   145  	arr := typ(TARRAY)
   146  
   147  	arr.Type = Types[TUINT8]
   148  	arr.Bound = BUCKETSIZE
   149  	field := make([]*Type, 0, 5)
   150  	field = append(field, makefield("topbits", arr))
   151  	arr = typ(TARRAY)
   152  	arr.Type = keytype
   153  	arr.Bound = BUCKETSIZE
   154  	field = append(field, makefield("keys", arr))
   155  	arr = typ(TARRAY)
   156  	arr.Type = valtype
   157  	arr.Bound = BUCKETSIZE
   158  	field = append(field, makefield("values", arr))
   159  
   160  	// Make sure the overflow pointer is the last memory in the struct,
   161  	// because the runtime assumes it can use size-ptrSize as the
   162  	// offset of the overflow pointer. We double-check that property
   163  	// below once the offsets and size are computed.
   164  	//
   165  	// BUCKETSIZE is 8, so the struct is aligned to 64 bits to this point.
   166  	// On 32-bit systems, the max alignment is 32-bit, and the
   167  	// overflow pointer will add another 32-bit field, and the struct
   168  	// will end with no padding.
   169  	// On 64-bit systems, the max alignment is 64-bit, and the
   170  	// overflow pointer will add another 64-bit field, and the struct
   171  	// will end with no padding.
   172  	// On nacl/amd64p32, however, the max alignment is 64-bit,
   173  	// but the overflow pointer will add only a 32-bit field,
   174  	// so if the struct needs 64-bit padding (because a key or value does)
   175  	// then it would end with an extra 32-bit padding field.
   176  	// Preempt that by emitting the padding here.
   177  	if int(t.Type.Align) > Widthptr || int(t.Down.Align) > Widthptr {
   178  		field = append(field, makefield("pad", Types[TUINTPTR]))
   179  	}
   180  
   181  	// If keys and values have no pointers, the map implementation
   182  	// can keep a list of overflow pointers on the side so that
   183  	// buckets can be marked as having no pointers.
   184  	// Arrange for the bucket to have no pointers by changing
   185  	// the type of the overflow field to uintptr in this case.
   186  	// See comment on hmap.overflow in ../../../../runtime/hashmap.go.
   187  	otyp := Ptrto(bucket)
   188  	if !haspointers(t.Type) && !haspointers(t.Down) && t.Type.Width <= MAXKEYSIZE && t.Down.Width <= MAXVALSIZE {
   189  		otyp = Types[TUINTPTR]
   190  	}
   191  	ovf := makefield("overflow", otyp)
   192  	field = append(field, ovf)
   193  
   194  	// link up fields
   195  	bucket.Noalg = 1
   196  	bucket.Local = t.Local
   197  	bucket.Type = field[0]
   198  	for n := int32(0); n < int32(len(field)-1); n++ {
   199  		field[n].Down = field[n+1]
   200  	}
   201  	field[len(field)-1].Down = nil
   202  	dowidth(bucket)
   203  
   204  	// Double-check that overflow field is final memory in struct,
   205  	// with no padding at end. See comment above.
   206  	if ovf.Width != bucket.Width-int64(Widthptr) {
   207  		Yyerror("bad math in mapbucket for %v", t)
   208  	}
   209  
   210  	t.Bucket = bucket
   211  
   212  	bucket.Map = t
   213  	return bucket
   214  }
   215  
   216  // Builds a type representing a Hmap structure for the given map type.
   217  // Make sure this stays in sync with ../../runtime/hashmap.go!
   218  func hmap(t *Type) *Type {
   219  	if t.Hmap != nil {
   220  		return t.Hmap
   221  	}
   222  
   223  	bucket := mapbucket(t)
   224  	var field [8]*Type
   225  	field[0] = makefield("count", Types[TINT])
   226  	field[1] = makefield("flags", Types[TUINT8])
   227  	field[2] = makefield("B", Types[TUINT8])
   228  	field[3] = makefield("hash0", Types[TUINT32])
   229  	field[4] = makefield("buckets", Ptrto(bucket))
   230  	field[5] = makefield("oldbuckets", Ptrto(bucket))
   231  	field[6] = makefield("nevacuate", Types[TUINTPTR])
   232  	field[7] = makefield("overflow", Types[TUNSAFEPTR])
   233  
   234  	h := typ(TSTRUCT)
   235  	h.Noalg = 1
   236  	h.Local = t.Local
   237  	h.Type = field[0]
   238  	for n := int32(0); n < int32(len(field)-1); n++ {
   239  		field[n].Down = field[n+1]
   240  	}
   241  	field[len(field)-1].Down = nil
   242  	dowidth(h)
   243  	t.Hmap = h
   244  	h.Map = t
   245  	return h
   246  }
   247  
   248  func hiter(t *Type) *Type {
   249  	if t.Hiter != nil {
   250  		return t.Hiter
   251  	}
   252  
   253  	// build a struct:
   254  	// hash_iter {
   255  	//    key *Key
   256  	//    val *Value
   257  	//    t *MapType
   258  	//    h *Hmap
   259  	//    buckets *Bucket
   260  	//    bptr *Bucket
   261  	//    overflow0 unsafe.Pointer
   262  	//    overflow1 unsafe.Pointer
   263  	//    startBucket uintptr
   264  	//    stuff uintptr
   265  	//    bucket uintptr
   266  	//    checkBucket uintptr
   267  	// }
   268  	// must match ../../runtime/hashmap.go:hash_iter.
   269  	var field [12]*Type
   270  	field[0] = makefield("key", Ptrto(t.Down))
   271  
   272  	field[1] = makefield("val", Ptrto(t.Type))
   273  	field[2] = makefield("t", Ptrto(Types[TUINT8]))
   274  	field[3] = makefield("h", Ptrto(hmap(t)))
   275  	field[4] = makefield("buckets", Ptrto(mapbucket(t)))
   276  	field[5] = makefield("bptr", Ptrto(mapbucket(t)))
   277  	field[6] = makefield("overflow0", Types[TUNSAFEPTR])
   278  	field[7] = makefield("overflow1", Types[TUNSAFEPTR])
   279  	field[8] = makefield("startBucket", Types[TUINTPTR])
   280  	field[9] = makefield("stuff", Types[TUINTPTR]) // offset+wrapped+B+I
   281  	field[10] = makefield("bucket", Types[TUINTPTR])
   282  	field[11] = makefield("checkBucket", Types[TUINTPTR])
   283  
   284  	// build iterator struct holding the above fields
   285  	i := typ(TSTRUCT)
   286  
   287  	i.Noalg = 1
   288  	i.Type = field[0]
   289  	for n := int32(0); n < int32(len(field)-1); n++ {
   290  		field[n].Down = field[n+1]
   291  	}
   292  	field[len(field)-1].Down = nil
   293  	dowidth(i)
   294  	if i.Width != int64(12*Widthptr) {
   295  		Yyerror("hash_iter size not correct %d %d", i.Width, 12*Widthptr)
   296  	}
   297  	t.Hiter = i
   298  	i.Map = t
   299  	return i
   300  }
   301  
   302  /*
   303   * f is method type, with receiver.
   304   * return function type, receiver as first argument (or not).
   305   */
   306  func methodfunc(f *Type, receiver *Type) *Type {
   307  	var in *NodeList
   308  	if receiver != nil {
   309  		d := Nod(ODCLFIELD, nil, nil)
   310  		d.Type = receiver
   311  		in = list(in, d)
   312  	}
   313  
   314  	var d *Node
   315  	for t := getinargx(f).Type; t != nil; t = t.Down {
   316  		d = Nod(ODCLFIELD, nil, nil)
   317  		d.Type = t.Type
   318  		d.Isddd = t.Isddd
   319  		in = list(in, d)
   320  	}
   321  
   322  	var out *NodeList
   323  	for t := getoutargx(f).Type; t != nil; t = t.Down {
   324  		d = Nod(ODCLFIELD, nil, nil)
   325  		d.Type = t.Type
   326  		out = list(out, d)
   327  	}
   328  
   329  	t := functype(nil, in, out)
   330  	if f.Nname != nil {
   331  		// Link to name of original method function.
   332  		t.Nname = f.Nname
   333  	}
   334  
   335  	return t
   336  }
   337  
   338  /*
   339   * return methods of non-interface type t, sorted by name.
   340   * generates stub functions as needed.
   341   */
   342  func methods(t *Type) *Sig {
   343  	// method type
   344  	mt := methtype(t, 0)
   345  
   346  	if mt == nil {
   347  		return nil
   348  	}
   349  	expandmeth(mt)
   350  
   351  	// type stored in interface word
   352  	it := t
   353  
   354  	if !isdirectiface(it) {
   355  		it = Ptrto(t)
   356  	}
   357  
   358  	// make list of methods for t,
   359  	// generating code if necessary.
   360  	var a *Sig
   361  
   362  	var this *Type
   363  	var b *Sig
   364  	var method *Sym
   365  	for f := mt.Xmethod; f != nil; f = f.Down {
   366  		if f.Etype != TFIELD {
   367  			Fatal("methods: not field %v", f)
   368  		}
   369  		if f.Type.Etype != TFUNC || f.Type.Thistuple == 0 {
   370  			Fatal("non-method on %v method %v %v\n", mt, f.Sym, f)
   371  		}
   372  		if getthisx(f.Type).Type == nil {
   373  			Fatal("receiver with no type on %v method %v %v\n", mt, f.Sym, f)
   374  		}
   375  		if f.Nointerface {
   376  			continue
   377  		}
   378  
   379  		method = f.Sym
   380  		if method == nil {
   381  			continue
   382  		}
   383  
   384  		// get receiver type for this particular method.
   385  		// if pointer receiver but non-pointer t and
   386  		// this is not an embedded pointer inside a struct,
   387  		// method does not apply.
   388  		this = getthisx(f.Type).Type.Type
   389  
   390  		if Isptr[this.Etype] && this.Type == t {
   391  			continue
   392  		}
   393  		if Isptr[this.Etype] && !Isptr[t.Etype] && f.Embedded != 2 && !isifacemethod(f.Type) {
   394  			continue
   395  		}
   396  
   397  		b = new(Sig)
   398  		b.link = a
   399  		a = b
   400  
   401  		a.name = method.Name
   402  		if !exportname(method.Name) {
   403  			if method.Pkg == nil {
   404  				Fatal("methods: missing package")
   405  			}
   406  			a.pkg = method.Pkg
   407  		}
   408  
   409  		a.isym = methodsym(method, it, 1)
   410  		a.tsym = methodsym(method, t, 0)
   411  		a.type_ = methodfunc(f.Type, t)
   412  		a.mtype = methodfunc(f.Type, nil)
   413  
   414  		if a.isym.Flags&SymSiggen == 0 {
   415  			a.isym.Flags |= SymSiggen
   416  			if !Eqtype(this, it) || this.Width < Types[Tptr].Width {
   417  				compiling_wrappers = 1
   418  				genwrapper(it, f, a.isym, 1)
   419  				compiling_wrappers = 0
   420  			}
   421  		}
   422  
   423  		if a.tsym.Flags&SymSiggen == 0 {
   424  			a.tsym.Flags |= SymSiggen
   425  			if !Eqtype(this, t) {
   426  				compiling_wrappers = 1
   427  				genwrapper(t, f, a.tsym, 0)
   428  				compiling_wrappers = 0
   429  			}
   430  		}
   431  	}
   432  
   433  	return lsort(a, sigcmp)
   434  }
   435  
   436  /*
   437   * return methods of interface type t, sorted by name.
   438   */
   439  func imethods(t *Type) *Sig {
   440  	var a *Sig
   441  	var method *Sym
   442  	var isym *Sym
   443  
   444  	var all *Sig
   445  	var last *Sig
   446  	for f := t.Type; f != nil; f = f.Down {
   447  		if f.Etype != TFIELD {
   448  			Fatal("imethods: not field")
   449  		}
   450  		if f.Type.Etype != TFUNC || f.Sym == nil {
   451  			continue
   452  		}
   453  		method = f.Sym
   454  		a = new(Sig)
   455  		a.name = method.Name
   456  		if !exportname(method.Name) {
   457  			if method.Pkg == nil {
   458  				Fatal("imethods: missing package")
   459  			}
   460  			a.pkg = method.Pkg
   461  		}
   462  
   463  		a.mtype = f.Type
   464  		a.offset = 0
   465  		a.type_ = methodfunc(f.Type, nil)
   466  
   467  		if last != nil && sigcmp(last, a) >= 0 {
   468  			Fatal("sigcmp vs sortinter %s %s", last.name, a.name)
   469  		}
   470  		if last == nil {
   471  			all = a
   472  		} else {
   473  			last.link = a
   474  		}
   475  		last = a
   476  
   477  		// Compiler can only refer to wrappers for non-blank methods.
   478  		if isblanksym(method) {
   479  			continue
   480  		}
   481  
   482  		// NOTE(rsc): Perhaps an oversight that
   483  		// IfaceType.Method is not in the reflect data.
   484  		// Generate the method body, so that compiled
   485  		// code can refer to it.
   486  		isym = methodsym(method, t, 0)
   487  
   488  		if isym.Flags&SymSiggen == 0 {
   489  			isym.Flags |= SymSiggen
   490  			genwrapper(t, f, isym, 0)
   491  		}
   492  	}
   493  
   494  	return all
   495  }
   496  
   497  var dimportpath_gopkg *Pkg
   498  
   499  func dimportpath(p *Pkg) {
   500  	if p.Pathsym != nil {
   501  		return
   502  	}
   503  
   504  	// If we are compiling the runtime package, there are two runtime packages around
   505  	// -- localpkg and Runtimepkg.  We don't want to produce import path symbols for
   506  	// both of them, so just produce one for localpkg.
   507  	if myimportpath == "runtime" && p == Runtimepkg {
   508  		return
   509  	}
   510  
   511  	if dimportpath_gopkg == nil {
   512  		dimportpath_gopkg = mkpkg("go")
   513  		dimportpath_gopkg.Name = "go"
   514  	}
   515  
   516  	nam := "importpath." + p.Prefix + "."
   517  
   518  	n := Nod(ONAME, nil, nil)
   519  	n.Sym = Pkglookup(nam, dimportpath_gopkg)
   520  
   521  	n.Class = PEXTERN
   522  	n.Xoffset = 0
   523  	p.Pathsym = n.Sym
   524  
   525  	if p == localpkg {
   526  		// Note: myimportpath != "", or else dgopkgpath won't call dimportpath.
   527  		gdatastring(n, myimportpath)
   528  	} else {
   529  		gdatastring(n, p.Path)
   530  	}
   531  	ggloblsym(n.Sym, int32(Types[TSTRING].Width), obj.DUPOK|obj.RODATA)
   532  }
   533  
   534  func dgopkgpath(s *Sym, ot int, pkg *Pkg) int {
   535  	if pkg == nil {
   536  		return dgostringptr(s, ot, "")
   537  	}
   538  
   539  	if pkg == localpkg && myimportpath == "" {
   540  		// If we don't know the full path of the package being compiled (i.e. -p
   541  		// was not passed on the compiler command line), emit reference to
   542  		// go.importpath.""., which 6l will rewrite using the correct import path.
   543  		// Every package that imports this one directly defines the symbol.
   544  		var ns *Sym
   545  
   546  		if ns == nil {
   547  			ns = Pkglookup("importpath.\"\".", mkpkg("go"))
   548  		}
   549  		return dsymptr(s, ot, ns, 0)
   550  	}
   551  
   552  	dimportpath(pkg)
   553  	return dsymptr(s, ot, pkg.Pathsym, 0)
   554  }
   555  
   556  /*
   557   * uncommonType
   558   * ../../runtime/type.go:/uncommonType
   559   */
   560  func dextratype(sym *Sym, off int, t *Type, ptroff int) int {
   561  	m := methods(t)
   562  	if t.Sym == nil && m == nil {
   563  		return off
   564  	}
   565  
   566  	// fill in *extraType pointer in header
   567  	off = int(Rnd(int64(off), int64(Widthptr)))
   568  
   569  	dsymptr(sym, ptroff, sym, off)
   570  
   571  	n := 0
   572  	for a := m; a != nil; a = a.link {
   573  		dtypesym(a.type_)
   574  		n++
   575  	}
   576  
   577  	ot := off
   578  	s := sym
   579  	if t.Sym != nil {
   580  		ot = dgostringptr(s, ot, t.Sym.Name)
   581  		if t != Types[t.Etype] && t != errortype {
   582  			ot = dgopkgpath(s, ot, t.Sym.Pkg)
   583  		} else {
   584  			ot = dgostringptr(s, ot, "")
   585  		}
   586  	} else {
   587  		ot = dgostringptr(s, ot, "")
   588  		ot = dgostringptr(s, ot, "")
   589  	}
   590  
   591  	// slice header
   592  	ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint)
   593  
   594  	ot = duintxx(s, ot, uint64(n), Widthint)
   595  	ot = duintxx(s, ot, uint64(n), Widthint)
   596  
   597  	// methods
   598  	for a := m; a != nil; a = a.link {
   599  		// method
   600  		// ../../runtime/type.go:/method
   601  		ot = dgostringptr(s, ot, a.name)
   602  
   603  		ot = dgopkgpath(s, ot, a.pkg)
   604  		ot = dsymptr(s, ot, dtypesym(a.mtype), 0)
   605  		ot = dsymptr(s, ot, dtypesym(a.type_), 0)
   606  		if a.isym != nil {
   607  			ot = dsymptr(s, ot, a.isym, 0)
   608  		} else {
   609  			ot = duintptr(s, ot, 0)
   610  		}
   611  		if a.tsym != nil {
   612  			ot = dsymptr(s, ot, a.tsym, 0)
   613  		} else {
   614  			ot = duintptr(s, ot, 0)
   615  		}
   616  	}
   617  
   618  	return ot
   619  }
   620  
   621  var kinds = []int{
   622  	TINT:        obj.KindInt,
   623  	TUINT:       obj.KindUint,
   624  	TINT8:       obj.KindInt8,
   625  	TUINT8:      obj.KindUint8,
   626  	TINT16:      obj.KindInt16,
   627  	TUINT16:     obj.KindUint16,
   628  	TINT32:      obj.KindInt32,
   629  	TUINT32:     obj.KindUint32,
   630  	TINT64:      obj.KindInt64,
   631  	TUINT64:     obj.KindUint64,
   632  	TUINTPTR:    obj.KindUintptr,
   633  	TFLOAT32:    obj.KindFloat32,
   634  	TFLOAT64:    obj.KindFloat64,
   635  	TBOOL:       obj.KindBool,
   636  	TSTRING:     obj.KindString,
   637  	TPTR32:      obj.KindPtr,
   638  	TPTR64:      obj.KindPtr,
   639  	TSTRUCT:     obj.KindStruct,
   640  	TINTER:      obj.KindInterface,
   641  	TCHAN:       obj.KindChan,
   642  	TMAP:        obj.KindMap,
   643  	TARRAY:      obj.KindArray,
   644  	TFUNC:       obj.KindFunc,
   645  	TCOMPLEX64:  obj.KindComplex64,
   646  	TCOMPLEX128: obj.KindComplex128,
   647  	TUNSAFEPTR:  obj.KindUnsafePointer,
   648  }
   649  
   650  func haspointers(t *Type) bool {
   651  	if t.Haspointers != 0 {
   652  		return t.Haspointers-1 != 0
   653  	}
   654  
   655  	var ret bool
   656  	switch t.Etype {
   657  	case TINT,
   658  		TUINT,
   659  		TINT8,
   660  		TUINT8,
   661  		TINT16,
   662  		TUINT16,
   663  		TINT32,
   664  		TUINT32,
   665  		TINT64,
   666  		TUINT64,
   667  		TUINTPTR,
   668  		TFLOAT32,
   669  		TFLOAT64,
   670  		TCOMPLEX64,
   671  		TCOMPLEX128,
   672  		TBOOL:
   673  		ret = false
   674  
   675  	case TARRAY:
   676  		if t.Bound < 0 { // slice
   677  			ret = true
   678  			break
   679  		}
   680  
   681  		if t.Bound == 0 { // empty array
   682  			ret = false
   683  			break
   684  		}
   685  
   686  		ret = haspointers(t.Type)
   687  
   688  	case TSTRUCT:
   689  		ret = false
   690  		for t1 := t.Type; t1 != nil; t1 = t1.Down {
   691  			if haspointers(t1.Type) {
   692  				ret = true
   693  				break
   694  			}
   695  		}
   696  
   697  	case TSTRING,
   698  		TPTR32,
   699  		TPTR64,
   700  		TUNSAFEPTR,
   701  		TINTER,
   702  		TCHAN,
   703  		TMAP,
   704  		TFUNC:
   705  		fallthrough
   706  	default:
   707  		ret = true
   708  
   709  	case TFIELD:
   710  		Fatal("haspointers: unexpected type, %v", t)
   711  	}
   712  
   713  	t.Haspointers = 1 + uint8(obj.Bool2int(ret))
   714  	return ret
   715  }
   716  
   717  // typeptrdata returns the length in bytes of the prefix of t
   718  // containing pointer data. Anything after this offset is scalar data.
   719  func typeptrdata(t *Type) int64 {
   720  	if !haspointers(t) {
   721  		return 0
   722  	}
   723  
   724  	switch t.Etype {
   725  	case TPTR32,
   726  		TPTR64,
   727  		TUNSAFEPTR,
   728  		TFUNC,
   729  		TCHAN,
   730  		TMAP:
   731  		return int64(Widthptr)
   732  
   733  	case TSTRING:
   734  		// struct { byte *str; intgo len; }
   735  		return int64(Widthptr)
   736  
   737  	case TINTER:
   738  		// struct { Itab *tab;	void *data; } or
   739  		// struct { Type *type; void *data; }
   740  		return 2 * int64(Widthptr)
   741  
   742  	case TARRAY:
   743  		if Isslice(t) {
   744  			// struct { byte *array; uintgo len; uintgo cap; }
   745  			return int64(Widthptr)
   746  		}
   747  		// haspointers already eliminated t.Bound == 0.
   748  		return (t.Bound-1)*t.Type.Width + typeptrdata(t.Type)
   749  
   750  	case TSTRUCT:
   751  		// Find the last field that has pointers.
   752  		var lastPtrField *Type
   753  		for t1 := t.Type; t1 != nil; t1 = t1.Down {
   754  			if haspointers(t1.Type) {
   755  				lastPtrField = t1
   756  			}
   757  		}
   758  		return lastPtrField.Width + typeptrdata(lastPtrField.Type)
   759  
   760  	default:
   761  		Fatal("typeptrdata: unexpected type, %v", t)
   762  		return 0
   763  	}
   764  }
   765  
   766  /*
   767   * commonType
   768   * ../../runtime/type.go:/commonType
   769   */
   770  
   771  var dcommontype_algarray *Sym
   772  
   773  func dcommontype(s *Sym, ot int, t *Type) int {
   774  	if ot != 0 {
   775  		Fatal("dcommontype %d", ot)
   776  	}
   777  
   778  	sizeofAlg := 2 * Widthptr
   779  	if dcommontype_algarray == nil {
   780  		dcommontype_algarray = Pkglookup("algarray", Runtimepkg)
   781  	}
   782  	dowidth(t)
   783  	alg := algtype(t)
   784  	var algsym *Sym
   785  	if alg < 0 || alg == AMEM {
   786  		algsym = dalgsym(t)
   787  	}
   788  
   789  	var sptr *Sym
   790  	tptr := Ptrto(t)
   791  	if !Isptr[t.Etype] && (t.Sym != nil || methods(tptr) != nil) {
   792  		sptr = dtypesym(tptr)
   793  	} else {
   794  		sptr = weaktypesym(tptr)
   795  	}
   796  
   797  	gcsym, useGCProg, ptrdata := dgcsym(t)
   798  
   799  	// ../../pkg/reflect/type.go:/^type.commonType
   800  	// actual type structure
   801  	//	type commonType struct {
   802  	//		size          uintptr
   803  	//		ptrsize       uintptr
   804  	//		hash          uint32
   805  	//		_             uint8
   806  	//		align         uint8
   807  	//		fieldAlign    uint8
   808  	//		kind          uint8
   809  	//		alg           unsafe.Pointer
   810  	//		gcdata        unsafe.Pointer
   811  	//		string        *string
   812  	//		*extraType
   813  	//		ptrToThis     *Type
   814  	//	}
   815  	ot = duintptr(s, ot, uint64(t.Width))
   816  	ot = duintptr(s, ot, uint64(ptrdata))
   817  
   818  	ot = duint32(s, ot, typehash(t))
   819  	ot = duint8(s, ot, 0) // unused
   820  
   821  	// runtime (and common sense) expects alignment to be a power of two.
   822  	i := int(t.Align)
   823  
   824  	if i == 0 {
   825  		i = 1
   826  	}
   827  	if i&(i-1) != 0 {
   828  		Fatal("invalid alignment %d for %v", t.Align, t)
   829  	}
   830  	ot = duint8(s, ot, t.Align) // align
   831  	ot = duint8(s, ot, t.Align) // fieldAlign
   832  
   833  	i = kinds[t.Etype]
   834  	if t.Etype == TARRAY && t.Bound < 0 {
   835  		i = obj.KindSlice
   836  	}
   837  	if !haspointers(t) {
   838  		i |= obj.KindNoPointers
   839  	}
   840  	if isdirectiface(t) {
   841  		i |= obj.KindDirectIface
   842  	}
   843  	if useGCProg {
   844  		i |= obj.KindGCProg
   845  	}
   846  	ot = duint8(s, ot, uint8(i)) // kind
   847  	if algsym == nil {
   848  		ot = dsymptr(s, ot, dcommontype_algarray, alg*sizeofAlg)
   849  	} else {
   850  		ot = dsymptr(s, ot, algsym, 0)
   851  	}
   852  	ot = dsymptr(s, ot, gcsym, 0)
   853  
   854  	p := Tconv(t, obj.FmtLeft|obj.FmtUnsigned)
   855  
   856  	//print("dcommontype: %s\n", p);
   857  	ot = dgostringptr(s, ot, p) // string
   858  
   859  	// skip pointer to extraType,
   860  	// which follows the rest of this type structure.
   861  	// caller will fill in if needed.
   862  	// otherwise linker will assume 0.
   863  	ot += Widthptr
   864  
   865  	ot = dsymptr(s, ot, sptr, 0) // ptrto type
   866  	return ot
   867  }
   868  
   869  func typesym(t *Type) *Sym {
   870  	return Pkglookup(Tconv(t, obj.FmtLeft), typepkg)
   871  }
   872  
   873  func tracksym(t *Type) *Sym {
   874  	return Pkglookup(Tconv(t.Outer, obj.FmtLeft)+"."+t.Sym.Name, trackpkg)
   875  }
   876  
   877  func typelinksym(t *Type) *Sym {
   878  	// %-uT is what the generated Type's string field says.
   879  	// It uses (ambiguous) package names instead of import paths.
   880  	// %-T is the complete, unambiguous type name.
   881  	// We want the types to end up sorted by string field,
   882  	// so use that first in the name, and then add :%-T to
   883  	// disambiguate. We use a tab character as the separator to
   884  	// ensure the types appear sorted by their string field. The
   885  	// names are a little long but they are discarded by the linker
   886  	// and do not end up in the symbol table of the final binary.
   887  	p := Tconv(t, obj.FmtLeft|obj.FmtUnsigned) + "\t" + Tconv(t, obj.FmtLeft)
   888  
   889  	s := Pkglookup(p, typelinkpkg)
   890  
   891  	//print("typelinksym: %s -> %+S\n", p, s);
   892  
   893  	return s
   894  }
   895  
   896  func typesymprefix(prefix string, t *Type) *Sym {
   897  	p := prefix + "." + Tconv(t, obj.FmtLeft)
   898  	s := Pkglookup(p, typepkg)
   899  
   900  	//print("algsym: %s -> %+S\n", p, s);
   901  
   902  	return s
   903  }
   904  
   905  func typenamesym(t *Type) *Sym {
   906  	if t == nil || (Isptr[t.Etype] && t.Type == nil) || isideal(t) {
   907  		Fatal("typename %v", t)
   908  	}
   909  	s := typesym(t)
   910  	if s.Def == nil {
   911  		n := Nod(ONAME, nil, nil)
   912  		n.Sym = s
   913  		n.Type = Types[TUINT8]
   914  		n.Addable = true
   915  		n.Ullman = 1
   916  		n.Class = PEXTERN
   917  		n.Xoffset = 0
   918  		n.Typecheck = 1
   919  		s.Def = n
   920  
   921  		signatlist = list(signatlist, typenod(t))
   922  	}
   923  
   924  	return s.Def.Sym
   925  }
   926  
   927  func typename(t *Type) *Node {
   928  	s := typenamesym(t)
   929  	n := Nod(OADDR, s.Def, nil)
   930  	n.Type = Ptrto(s.Def.Type)
   931  	n.Addable = true
   932  	n.Ullman = 2
   933  	n.Typecheck = 1
   934  	return n
   935  }
   936  
   937  func weaktypesym(t *Type) *Sym {
   938  	p := Tconv(t, obj.FmtLeft)
   939  	s := Pkglookup(p, weaktypepkg)
   940  
   941  	//print("weaktypesym: %s -> %+S\n", p, s);
   942  
   943  	return s
   944  }
   945  
   946  /*
   947   * Returns 1 if t has a reflexive equality operator.
   948   * That is, if x==x for all x of type t.
   949   */
   950  func isreflexive(t *Type) bool {
   951  	switch t.Etype {
   952  	case TBOOL,
   953  		TINT,
   954  		TUINT,
   955  		TINT8,
   956  		TUINT8,
   957  		TINT16,
   958  		TUINT16,
   959  		TINT32,
   960  		TUINT32,
   961  		TINT64,
   962  		TUINT64,
   963  		TUINTPTR,
   964  		TPTR32,
   965  		TPTR64,
   966  		TUNSAFEPTR,
   967  		TSTRING,
   968  		TCHAN:
   969  		return true
   970  
   971  	case TFLOAT32,
   972  		TFLOAT64,
   973  		TCOMPLEX64,
   974  		TCOMPLEX128,
   975  		TINTER:
   976  		return false
   977  
   978  	case TARRAY:
   979  		if Isslice(t) {
   980  			Fatal("slice can't be a map key: %v", t)
   981  		}
   982  		return isreflexive(t.Type)
   983  
   984  	case TSTRUCT:
   985  		for t1 := t.Type; t1 != nil; t1 = t1.Down {
   986  			if !isreflexive(t1.Type) {
   987  				return false
   988  			}
   989  		}
   990  
   991  		return true
   992  
   993  	default:
   994  		Fatal("bad type for map key: %v", t)
   995  		return false
   996  	}
   997  }
   998  
   999  func dtypesym(t *Type) *Sym {
  1000  	// Replace byte, rune aliases with real type.
  1001  	// They've been separate internally to make error messages
  1002  	// better, but we have to merge them in the reflect tables.
  1003  	if t == bytetype || t == runetype {
  1004  		t = Types[t.Etype]
  1005  	}
  1006  
  1007  	if isideal(t) {
  1008  		Fatal("dtypesym %v", t)
  1009  	}
  1010  
  1011  	s := typesym(t)
  1012  	if s.Flags&SymSiggen != 0 {
  1013  		return s
  1014  	}
  1015  	s.Flags |= SymSiggen
  1016  
  1017  	// special case (look for runtime below):
  1018  	// when compiling package runtime,
  1019  	// emit the type structures for int, float, etc.
  1020  	tbase := t
  1021  
  1022  	if Isptr[t.Etype] && t.Sym == nil && t.Type.Sym != nil {
  1023  		tbase = t.Type
  1024  	}
  1025  	dupok := 0
  1026  	if tbase.Sym == nil {
  1027  		dupok = obj.DUPOK
  1028  	}
  1029  
  1030  	if compiling_runtime != 0 && (tbase == Types[tbase.Etype] || tbase == bytetype || tbase == runetype || tbase == errortype) { // int, float, etc
  1031  		goto ok
  1032  	}
  1033  
  1034  	// named types from other files are defined only by those files
  1035  	if tbase.Sym != nil && !tbase.Local {
  1036  		return s
  1037  	}
  1038  	if isforw[tbase.Etype] {
  1039  		return s
  1040  	}
  1041  
  1042  ok:
  1043  	ot := 0
  1044  	xt := 0
  1045  	switch t.Etype {
  1046  	default:
  1047  		ot = dcommontype(s, ot, t)
  1048  		xt = ot - 2*Widthptr
  1049  
  1050  	case TARRAY:
  1051  		if t.Bound >= 0 {
  1052  			// ../../runtime/type.go:/ArrayType
  1053  			s1 := dtypesym(t.Type)
  1054  
  1055  			t2 := typ(TARRAY)
  1056  			t2.Type = t.Type
  1057  			t2.Bound = -1 // slice
  1058  			s2 := dtypesym(t2)
  1059  			ot = dcommontype(s, ot, t)
  1060  			xt = ot - 2*Widthptr
  1061  			ot = dsymptr(s, ot, s1, 0)
  1062  			ot = dsymptr(s, ot, s2, 0)
  1063  			ot = duintptr(s, ot, uint64(t.Bound))
  1064  		} else {
  1065  			// ../../runtime/type.go:/SliceType
  1066  			s1 := dtypesym(t.Type)
  1067  
  1068  			ot = dcommontype(s, ot, t)
  1069  			xt = ot - 2*Widthptr
  1070  			ot = dsymptr(s, ot, s1, 0)
  1071  		}
  1072  
  1073  		// ../../runtime/type.go:/ChanType
  1074  	case TCHAN:
  1075  		s1 := dtypesym(t.Type)
  1076  
  1077  		ot = dcommontype(s, ot, t)
  1078  		xt = ot - 2*Widthptr
  1079  		ot = dsymptr(s, ot, s1, 0)
  1080  		ot = duintptr(s, ot, uint64(t.Chan))
  1081  
  1082  	case TFUNC:
  1083  		for t1 := getthisx(t).Type; t1 != nil; t1 = t1.Down {
  1084  			dtypesym(t1.Type)
  1085  		}
  1086  		isddd := false
  1087  		for t1 := getinargx(t).Type; t1 != nil; t1 = t1.Down {
  1088  			isddd = t1.Isddd
  1089  			dtypesym(t1.Type)
  1090  		}
  1091  
  1092  		for t1 := getoutargx(t).Type; t1 != nil; t1 = t1.Down {
  1093  			dtypesym(t1.Type)
  1094  		}
  1095  
  1096  		ot = dcommontype(s, ot, t)
  1097  		xt = ot - 2*Widthptr
  1098  		ot = duint8(s, ot, uint8(obj.Bool2int(isddd)))
  1099  
  1100  		// two slice headers: in and out.
  1101  		ot = int(Rnd(int64(ot), int64(Widthptr)))
  1102  
  1103  		ot = dsymptr(s, ot, s, ot+2*(Widthptr+2*Widthint))
  1104  		n := t.Thistuple + t.Intuple
  1105  		ot = duintxx(s, ot, uint64(n), Widthint)
  1106  		ot = duintxx(s, ot, uint64(n), Widthint)
  1107  		ot = dsymptr(s, ot, s, ot+1*(Widthptr+2*Widthint)+n*Widthptr)
  1108  		ot = duintxx(s, ot, uint64(t.Outtuple), Widthint)
  1109  		ot = duintxx(s, ot, uint64(t.Outtuple), Widthint)
  1110  
  1111  		// slice data
  1112  		for t1 := getthisx(t).Type; t1 != nil; t1 = t1.Down {
  1113  			ot = dsymptr(s, ot, dtypesym(t1.Type), 0)
  1114  			n++
  1115  		}
  1116  		for t1 := getinargx(t).Type; t1 != nil; t1 = t1.Down {
  1117  			ot = dsymptr(s, ot, dtypesym(t1.Type), 0)
  1118  			n++
  1119  		}
  1120  		for t1 := getoutargx(t).Type; t1 != nil; t1 = t1.Down {
  1121  			ot = dsymptr(s, ot, dtypesym(t1.Type), 0)
  1122  			n++
  1123  		}
  1124  
  1125  	case TINTER:
  1126  		m := imethods(t)
  1127  		n := 0
  1128  		for a := m; a != nil; a = a.link {
  1129  			dtypesym(a.type_)
  1130  			n++
  1131  		}
  1132  
  1133  		// ../../runtime/type.go:/InterfaceType
  1134  		ot = dcommontype(s, ot, t)
  1135  
  1136  		xt = ot - 2*Widthptr
  1137  		ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint)
  1138  		ot = duintxx(s, ot, uint64(n), Widthint)
  1139  		ot = duintxx(s, ot, uint64(n), Widthint)
  1140  		for a := m; a != nil; a = a.link {
  1141  			// ../../runtime/type.go:/imethod
  1142  			ot = dgostringptr(s, ot, a.name)
  1143  
  1144  			ot = dgopkgpath(s, ot, a.pkg)
  1145  			ot = dsymptr(s, ot, dtypesym(a.type_), 0)
  1146  		}
  1147  
  1148  		// ../../runtime/type.go:/MapType
  1149  	case TMAP:
  1150  		s1 := dtypesym(t.Down)
  1151  
  1152  		s2 := dtypesym(t.Type)
  1153  		s3 := dtypesym(mapbucket(t))
  1154  		s4 := dtypesym(hmap(t))
  1155  		ot = dcommontype(s, ot, t)
  1156  		xt = ot - 2*Widthptr
  1157  		ot = dsymptr(s, ot, s1, 0)
  1158  		ot = dsymptr(s, ot, s2, 0)
  1159  		ot = dsymptr(s, ot, s3, 0)
  1160  		ot = dsymptr(s, ot, s4, 0)
  1161  		if t.Down.Width > MAXKEYSIZE {
  1162  			ot = duint8(s, ot, uint8(Widthptr))
  1163  			ot = duint8(s, ot, 1) // indirect
  1164  		} else {
  1165  			ot = duint8(s, ot, uint8(t.Down.Width))
  1166  			ot = duint8(s, ot, 0) // not indirect
  1167  		}
  1168  
  1169  		if t.Type.Width > MAXVALSIZE {
  1170  			ot = duint8(s, ot, uint8(Widthptr))
  1171  			ot = duint8(s, ot, 1) // indirect
  1172  		} else {
  1173  			ot = duint8(s, ot, uint8(t.Type.Width))
  1174  			ot = duint8(s, ot, 0) // not indirect
  1175  		}
  1176  
  1177  		ot = duint16(s, ot, uint16(mapbucket(t).Width))
  1178  		ot = duint8(s, ot, uint8(obj.Bool2int(isreflexive(t.Down))))
  1179  
  1180  	case TPTR32, TPTR64:
  1181  		if t.Type.Etype == TANY {
  1182  			// ../../runtime/type.go:/UnsafePointerType
  1183  			ot = dcommontype(s, ot, t)
  1184  
  1185  			break
  1186  		}
  1187  
  1188  		// ../../runtime/type.go:/PtrType
  1189  		s1 := dtypesym(t.Type)
  1190  
  1191  		ot = dcommontype(s, ot, t)
  1192  		xt = ot - 2*Widthptr
  1193  		ot = dsymptr(s, ot, s1, 0)
  1194  
  1195  		// ../../runtime/type.go:/StructType
  1196  	// for security, only the exported fields.
  1197  	case TSTRUCT:
  1198  		n := 0
  1199  
  1200  		for t1 := t.Type; t1 != nil; t1 = t1.Down {
  1201  			dtypesym(t1.Type)
  1202  			n++
  1203  		}
  1204  
  1205  		ot = dcommontype(s, ot, t)
  1206  		xt = ot - 2*Widthptr
  1207  		ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint)
  1208  		ot = duintxx(s, ot, uint64(n), Widthint)
  1209  		ot = duintxx(s, ot, uint64(n), Widthint)
  1210  		for t1 := t.Type; t1 != nil; t1 = t1.Down {
  1211  			// ../../runtime/type.go:/structField
  1212  			if t1.Sym != nil && t1.Embedded == 0 {
  1213  				ot = dgostringptr(s, ot, t1.Sym.Name)
  1214  				if exportname(t1.Sym.Name) {
  1215  					ot = dgostringptr(s, ot, "")
  1216  				} else {
  1217  					ot = dgopkgpath(s, ot, t1.Sym.Pkg)
  1218  				}
  1219  			} else {
  1220  				ot = dgostringptr(s, ot, "")
  1221  				if t1.Type.Sym != nil && t1.Type.Sym.Pkg == builtinpkg {
  1222  					ot = dgopkgpath(s, ot, localpkg)
  1223  				} else {
  1224  					ot = dgostringptr(s, ot, "")
  1225  				}
  1226  			}
  1227  
  1228  			ot = dsymptr(s, ot, dtypesym(t1.Type), 0)
  1229  			ot = dgostrlitptr(s, ot, t1.Note)
  1230  			ot = duintptr(s, ot, uint64(t1.Width)) // field offset
  1231  		}
  1232  	}
  1233  
  1234  	ot = dextratype(s, ot, t, xt)
  1235  	ggloblsym(s, int32(ot), int16(dupok|obj.RODATA))
  1236  
  1237  	// generate typelink.foo pointing at s = type.foo.
  1238  	// The linker will leave a table of all the typelinks for
  1239  	// types in the binary, so reflect can find them.
  1240  	// We only need the link for unnamed composites that
  1241  	// we want be able to find.
  1242  	if t.Sym == nil {
  1243  		switch t.Etype {
  1244  		case TPTR32, TPTR64:
  1245  			// The ptrto field of the type data cannot be relied on when
  1246  			// dynamic linking: a type T may be defined in a module that makes
  1247  			// no use of pointers to that type, but another module can contain
  1248  			// a package that imports the first one and does use *T pointers.
  1249  			// The second module will end up defining type data for *T and a
  1250  			// type.*T symbol pointing at it. It's important that calling
  1251  			// .PtrTo() on the reflect.Type for T returns this type data and
  1252  			// not some synthesized object, so we need reflect to be able to
  1253  			// find it!
  1254  			if !Ctxt.Flag_dynlink {
  1255  				break
  1256  			}
  1257  			fallthrough
  1258  		case TARRAY, TCHAN, TFUNC, TMAP:
  1259  			slink := typelinksym(t)
  1260  			dsymptr(slink, 0, s, 0)
  1261  			ggloblsym(slink, int32(Widthptr), int16(dupok|obj.RODATA))
  1262  		}
  1263  	}
  1264  
  1265  	return s
  1266  }
  1267  
  1268  func dumptypestructs() {
  1269  	var n *Node
  1270  
  1271  	// copy types from externdcl list to signatlist
  1272  	for l := externdcl; l != nil; l = l.Next {
  1273  		n = l.N
  1274  		if n.Op != OTYPE {
  1275  			continue
  1276  		}
  1277  		signatlist = list(signatlist, n)
  1278  	}
  1279  
  1280  	// process signatlist
  1281  	var t *Type
  1282  	for l := signatlist; l != nil; l = l.Next {
  1283  		n = l.N
  1284  		if n.Op != OTYPE {
  1285  			continue
  1286  		}
  1287  		t = n.Type
  1288  		dtypesym(t)
  1289  		if t.Sym != nil {
  1290  			dtypesym(Ptrto(t))
  1291  		}
  1292  	}
  1293  
  1294  	// generate import strings for imported packages
  1295  	for _, p := range pkgs {
  1296  		if p.Direct != 0 {
  1297  			dimportpath(p)
  1298  		}
  1299  	}
  1300  
  1301  	// do basic types if compiling package runtime.
  1302  	// they have to be in at least one package,
  1303  	// and runtime is always loaded implicitly,
  1304  	// so this is as good as any.
  1305  	// another possible choice would be package main,
  1306  	// but using runtime means fewer copies in .6 files.
  1307  	if compiling_runtime != 0 {
  1308  		for i := 1; i <= TBOOL; i++ {
  1309  			dtypesym(Ptrto(Types[i]))
  1310  		}
  1311  		dtypesym(Ptrto(Types[TSTRING]))
  1312  		dtypesym(Ptrto(Types[TUNSAFEPTR]))
  1313  
  1314  		// emit type structs for error and func(error) string.
  1315  		// The latter is the type of an auto-generated wrapper.
  1316  		dtypesym(Ptrto(errortype))
  1317  
  1318  		dtypesym(functype(nil, list1(Nod(ODCLFIELD, nil, typenod(errortype))), list1(Nod(ODCLFIELD, nil, typenod(Types[TSTRING])))))
  1319  
  1320  		// add paths for runtime and main, which 6l imports implicitly.
  1321  		dimportpath(Runtimepkg)
  1322  
  1323  		if flag_race != 0 {
  1324  			dimportpath(racepkg)
  1325  		}
  1326  		dimportpath(mkpkg("main"))
  1327  	}
  1328  }
  1329  
  1330  func dalgsym(t *Type) *Sym {
  1331  	var s *Sym
  1332  	var hashfunc *Sym
  1333  	var eqfunc *Sym
  1334  
  1335  	// dalgsym is only called for a type that needs an algorithm table,
  1336  	// which implies that the type is comparable (or else it would use ANOEQ).
  1337  
  1338  	if algtype(t) == AMEM {
  1339  		// we use one algorithm table for all AMEM types of a given size
  1340  		p := fmt.Sprintf(".alg%d", t.Width)
  1341  
  1342  		s = Pkglookup(p, typepkg)
  1343  
  1344  		if s.Flags&SymAlgGen != 0 {
  1345  			return s
  1346  		}
  1347  		s.Flags |= SymAlgGen
  1348  
  1349  		// make hash closure
  1350  		p = fmt.Sprintf(".hashfunc%d", t.Width)
  1351  
  1352  		hashfunc = Pkglookup(p, typepkg)
  1353  
  1354  		ot := 0
  1355  		ot = dsymptr(hashfunc, ot, Pkglookup("memhash_varlen", Runtimepkg), 0)
  1356  		ot = duintxx(hashfunc, ot, uint64(t.Width), Widthptr) // size encoded in closure
  1357  		ggloblsym(hashfunc, int32(ot), obj.DUPOK|obj.RODATA)
  1358  
  1359  		// make equality closure
  1360  		p = fmt.Sprintf(".eqfunc%d", t.Width)
  1361  
  1362  		eqfunc = Pkglookup(p, typepkg)
  1363  
  1364  		ot = 0
  1365  		ot = dsymptr(eqfunc, ot, Pkglookup("memequal_varlen", Runtimepkg), 0)
  1366  		ot = duintxx(eqfunc, ot, uint64(t.Width), Widthptr)
  1367  		ggloblsym(eqfunc, int32(ot), obj.DUPOK|obj.RODATA)
  1368  	} else {
  1369  		// generate an alg table specific to this type
  1370  		s = typesymprefix(".alg", t)
  1371  
  1372  		hash := typesymprefix(".hash", t)
  1373  		eq := typesymprefix(".eq", t)
  1374  		hashfunc = typesymprefix(".hashfunc", t)
  1375  		eqfunc = typesymprefix(".eqfunc", t)
  1376  
  1377  		genhash(hash, t)
  1378  		geneq(eq, t)
  1379  
  1380  		// make Go funcs (closures) for calling hash and equal from Go
  1381  		dsymptr(hashfunc, 0, hash, 0)
  1382  
  1383  		ggloblsym(hashfunc, int32(Widthptr), obj.DUPOK|obj.RODATA)
  1384  		dsymptr(eqfunc, 0, eq, 0)
  1385  		ggloblsym(eqfunc, int32(Widthptr), obj.DUPOK|obj.RODATA)
  1386  	}
  1387  
  1388  	// ../../runtime/alg.go:/typeAlg
  1389  	ot := 0
  1390  
  1391  	ot = dsymptr(s, ot, hashfunc, 0)
  1392  	ot = dsymptr(s, ot, eqfunc, 0)
  1393  	ggloblsym(s, int32(ot), obj.DUPOK|obj.RODATA)
  1394  	return s
  1395  }
  1396  
  1397  // maxPtrmaskBytes is the maximum length of a GC ptrmask bitmap,
  1398  // which holds 1-bit entries describing where pointers are in a given type.
  1399  // 16 bytes is enough to describe 128 pointer-sized words, 512 or 1024 bytes
  1400  // depending on the system. Above this length, the GC information is
  1401  // recorded as a GC program, which can express repetition compactly.
  1402  // In either form, the information is used by the runtime to initialize the
  1403  // heap bitmap, and for large types (like 128 or more words), they are
  1404  // roughly the same speed. GC programs are never much larger and often
  1405  // more compact. (If large arrays are involved, they can be arbitrarily more
  1406  // compact.)
  1407  //
  1408  // The cutoff must be large enough that any allocation large enough to
  1409  // use a GC program is large enough that it does not share heap bitmap
  1410  // bytes with any other objects, allowing the GC program execution to
  1411  // assume an aligned start and not use atomic operations. In the current
  1412  // runtime, this means all malloc size classes larger than the cutoff must
  1413  // be multiples of four words. On 32-bit systems that's 16 bytes, and
  1414  // all size classes >= 16 bytes are 16-byte aligned, so no real constraint.
  1415  // On 64-bit systems, that's 32 bytes, and 32-byte alignment is guaranteed
  1416  // for size classes >= 256 bytes. On a 64-bit sytem, 256 bytes allocated
  1417  // is 32 pointers, the bits for which fit in 4 bytes. So maxPtrmaskBytes
  1418  // must be >= 4.
  1419  //
  1420  // We used to use 16 because the GC programs do have some constant overhead
  1421  // to get started, and processing 128 pointers seems to be enough to
  1422  // amortize that overhead well.
  1423  //
  1424  // To make sure that the runtime's chansend can call typeBitsBulkBarrier,
  1425  // we raised the limit to 2048, so that even 32-bit systems are guaranteed to
  1426  // use bitmaps for objects up to 64 kB in size.
  1427  //
  1428  // Also known to reflect/type.go.
  1429  //
  1430  const maxPtrmaskBytes = 2048
  1431  
  1432  // dgcsym emits and returns a data symbol containing GC information for type t,
  1433  // along with a boolean reporting whether the UseGCProg bit should be set in
  1434  // the type kind, and the ptrdata field to record in the reflect type information.
  1435  func dgcsym(t *Type) (sym *Sym, useGCProg bool, ptrdata int64) {
  1436  	ptrdata = typeptrdata(t)
  1437  	if ptrdata/int64(Widthptr) <= maxPtrmaskBytes*8 {
  1438  		sym = dgcptrmask(t)
  1439  		return
  1440  	}
  1441  
  1442  	useGCProg = true
  1443  	sym, ptrdata = dgcprog(t)
  1444  	return
  1445  }
  1446  
  1447  // dgcptrmask emits and returns the symbol containing a pointer mask for type t.
  1448  func dgcptrmask(t *Type) *Sym {
  1449  	ptrmask := make([]byte, (typeptrdata(t)/int64(Widthptr)+7)/8)
  1450  	fillptrmask(t, ptrmask)
  1451  	p := fmt.Sprintf("gcbits.%x", ptrmask)
  1452  
  1453  	sym := Pkglookup(p, Runtimepkg)
  1454  	if sym.Flags&SymUniq == 0 {
  1455  		sym.Flags |= SymUniq
  1456  		for i, x := range ptrmask {
  1457  			duint8(sym, i, x)
  1458  		}
  1459  		ggloblsym(sym, int32(len(ptrmask)), obj.DUPOK|obj.RODATA|obj.LOCAL)
  1460  	}
  1461  	return sym
  1462  }
  1463  
  1464  // fillptrmask fills in ptrmask with 1s corresponding to the
  1465  // word offsets in t that hold pointers.
  1466  // ptrmask is assumed to fit at least typeptrdata(t)/Widthptr bits.
  1467  func fillptrmask(t *Type, ptrmask []byte) {
  1468  	for i := range ptrmask {
  1469  		ptrmask[i] = 0
  1470  	}
  1471  	if !haspointers(t) {
  1472  		return
  1473  	}
  1474  
  1475  	vec := bvalloc(8 * int32(len(ptrmask)))
  1476  	xoffset := int64(0)
  1477  	onebitwalktype1(t, &xoffset, vec)
  1478  
  1479  	nptr := typeptrdata(t) / int64(Widthptr)
  1480  	for i := int64(0); i < nptr; i++ {
  1481  		if bvget(vec, int32(i)) == 1 {
  1482  			ptrmask[i/8] |= 1 << (uint(i) % 8)
  1483  		}
  1484  	}
  1485  }
  1486  
  1487  // dgcprog emits and returns the symbol containing a GC program for type t
  1488  // along with the size of the data described by the program (in the range [typeptrdata(t), t.Width]).
  1489  // In practice, the size is typeptrdata(t) except for non-trivial arrays.
  1490  // For non-trivial arrays, the program describes the full t.Width size.
  1491  func dgcprog(t *Type) (*Sym, int64) {
  1492  	dowidth(t)
  1493  	if t.Width == BADWIDTH {
  1494  		Fatal("dgcprog: %v badwidth", t)
  1495  	}
  1496  	sym := typesymprefix(".gcprog", t)
  1497  	var p GCProg
  1498  	p.init(sym)
  1499  	p.emit(t, 0)
  1500  	offset := p.w.BitIndex() * int64(Widthptr)
  1501  	p.end()
  1502  	if ptrdata := typeptrdata(t); offset < ptrdata || offset > t.Width {
  1503  		Fatal("dgcprog: %v: offset=%d but ptrdata=%d size=%d", t, offset, ptrdata, t.Width)
  1504  	}
  1505  	return sym, offset
  1506  }
  1507  
  1508  type GCProg struct {
  1509  	sym    *Sym
  1510  	symoff int
  1511  	w      gcprog.Writer
  1512  }
  1513  
  1514  var Debug_gcprog int // set by -d gcprog
  1515  
  1516  func (p *GCProg) init(sym *Sym) {
  1517  	p.sym = sym
  1518  	p.symoff = 4 // first 4 bytes hold program length
  1519  	p.w.Init(p.writeByte)
  1520  	if Debug_gcprog > 0 {
  1521  		fmt.Fprintf(os.Stderr, "compile: start GCProg for %v\n", sym)
  1522  		p.w.Debug(os.Stderr)
  1523  	}
  1524  }
  1525  
  1526  func (p *GCProg) writeByte(x byte) {
  1527  	p.symoff = duint8(p.sym, p.symoff, x)
  1528  }
  1529  
  1530  func (p *GCProg) end() {
  1531  	p.w.End()
  1532  	duint32(p.sym, 0, uint32(p.symoff-4))
  1533  	ggloblsym(p.sym, int32(p.symoff), obj.DUPOK|obj.RODATA|obj.LOCAL)
  1534  	if Debug_gcprog > 0 {
  1535  		fmt.Fprintf(os.Stderr, "compile: end GCProg for %v\n", p.sym)
  1536  	}
  1537  }
  1538  
  1539  func (p *GCProg) emit(t *Type, offset int64) {
  1540  	dowidth(t)
  1541  	if !haspointers(t) {
  1542  		return
  1543  	}
  1544  	if t.Width == int64(Widthptr) {
  1545  		p.w.Ptr(offset / int64(Widthptr))
  1546  		return
  1547  	}
  1548  	switch t.Etype {
  1549  	default:
  1550  		Fatal("GCProg.emit: unexpected type %v", t)
  1551  
  1552  	case TSTRING:
  1553  		p.w.Ptr(offset / int64(Widthptr))
  1554  
  1555  	case TINTER:
  1556  		p.w.Ptr(offset / int64(Widthptr))
  1557  		p.w.Ptr(offset/int64(Widthptr) + 1)
  1558  
  1559  	case TARRAY:
  1560  		if Isslice(t) {
  1561  			p.w.Ptr(offset / int64(Widthptr))
  1562  			return
  1563  		}
  1564  		if t.Bound == 0 {
  1565  			// should have been handled by haspointers check above
  1566  			Fatal("GCProg.emit: empty array")
  1567  		}
  1568  
  1569  		// Flatten array-of-array-of-array to just a big array by multiplying counts.
  1570  		count := t.Bound
  1571  		elem := t.Type
  1572  		for Isfixedarray(elem) {
  1573  			count *= elem.Bound
  1574  			elem = elem.Type
  1575  		}
  1576  
  1577  		if !p.w.ShouldRepeat(elem.Width/int64(Widthptr), count) {
  1578  			// Cheaper to just emit the bits.
  1579  			for i := int64(0); i < count; i++ {
  1580  				p.emit(elem, offset+i*elem.Width)
  1581  			}
  1582  			return
  1583  		}
  1584  		p.emit(elem, offset)
  1585  		p.w.ZeroUntil((offset + elem.Width) / int64(Widthptr))
  1586  		p.w.Repeat(elem.Width/int64(Widthptr), count-1)
  1587  
  1588  	case TSTRUCT:
  1589  		for t1 := t.Type; t1 != nil; t1 = t1.Down {
  1590  			p.emit(t1.Type, offset+t1.Width)
  1591  		}
  1592  	}
  1593  }