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