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