github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/go/internal/gcimporter/iexport.go (about)

     1  // Copyright 2019 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  // Indexed binary package export.
     6  // This file was derived from $GOROOT/src/cmd/compile/internal/gc/iexport.go;
     7  // see that file for specification of the format.
     8  
     9  package gcimporter
    10  
    11  import (
    12  	"bytes"
    13  	"encoding/binary"
    14  	"fmt"
    15  	"go/ast"
    16  	"go/constant"
    17  	"go/token"
    18  	"go/types"
    19  	"io"
    20  	"math/big"
    21  	"reflect"
    22  	"sort"
    23  	"strconv"
    24  	"strings"
    25  
    26  	"github.com/powerman/golang-tools/internal/typeparams"
    27  )
    28  
    29  // Current bundled export format version. Increase with each format change.
    30  // 0: initial implementation
    31  const bundleVersion = 0
    32  
    33  // IExportData writes indexed export data for pkg to out.
    34  //
    35  // If no file set is provided, position info will be missing.
    36  // The package path of the top-level package will not be recorded,
    37  // so that calls to IImportData can override with a provided package path.
    38  func IExportData(out io.Writer, fset *token.FileSet, pkg *types.Package) error {
    39  	return iexportCommon(out, fset, false, iexportVersion, []*types.Package{pkg})
    40  }
    41  
    42  // IExportBundle writes an indexed export bundle for pkgs to out.
    43  func IExportBundle(out io.Writer, fset *token.FileSet, pkgs []*types.Package) error {
    44  	return iexportCommon(out, fset, true, iexportVersion, pkgs)
    45  }
    46  
    47  func iexportCommon(out io.Writer, fset *token.FileSet, bundle bool, version int, pkgs []*types.Package) (err error) {
    48  	if !debug {
    49  		defer func() {
    50  			if e := recover(); e != nil {
    51  				if ierr, ok := e.(internalError); ok {
    52  					err = ierr
    53  					return
    54  				}
    55  				// Not an internal error; panic again.
    56  				panic(e)
    57  			}
    58  		}()
    59  	}
    60  
    61  	p := iexporter{
    62  		fset:        fset,
    63  		version:     version,
    64  		allPkgs:     map[*types.Package]bool{},
    65  		stringIndex: map[string]uint64{},
    66  		declIndex:   map[types.Object]uint64{},
    67  		tparamNames: map[types.Object]string{},
    68  		typIndex:    map[types.Type]uint64{},
    69  	}
    70  	if !bundle {
    71  		p.localpkg = pkgs[0]
    72  	}
    73  
    74  	for i, pt := range predeclared() {
    75  		p.typIndex[pt] = uint64(i)
    76  	}
    77  	if len(p.typIndex) > predeclReserved {
    78  		panic(internalErrorf("too many predeclared types: %d > %d", len(p.typIndex), predeclReserved))
    79  	}
    80  
    81  	// Initialize work queue with exported declarations.
    82  	for _, pkg := range pkgs {
    83  		scope := pkg.Scope()
    84  		for _, name := range scope.Names() {
    85  			if ast.IsExported(name) {
    86  				p.pushDecl(scope.Lookup(name))
    87  			}
    88  		}
    89  
    90  		if bundle {
    91  			// Ensure pkg and its imports are included in the index.
    92  			p.allPkgs[pkg] = true
    93  			for _, imp := range pkg.Imports() {
    94  				p.allPkgs[imp] = true
    95  			}
    96  		}
    97  	}
    98  
    99  	// Loop until no more work.
   100  	for !p.declTodo.empty() {
   101  		p.doDecl(p.declTodo.popHead())
   102  	}
   103  
   104  	// Append indices to data0 section.
   105  	dataLen := uint64(p.data0.Len())
   106  	w := p.newWriter()
   107  	w.writeIndex(p.declIndex)
   108  
   109  	if bundle {
   110  		w.uint64(uint64(len(pkgs)))
   111  		for _, pkg := range pkgs {
   112  			w.pkg(pkg)
   113  			imps := pkg.Imports()
   114  			w.uint64(uint64(len(imps)))
   115  			for _, imp := range imps {
   116  				w.pkg(imp)
   117  			}
   118  		}
   119  	}
   120  	w.flush()
   121  
   122  	// Assemble header.
   123  	var hdr intWriter
   124  	if bundle {
   125  		hdr.uint64(bundleVersion)
   126  	}
   127  	hdr.uint64(uint64(p.version))
   128  	hdr.uint64(uint64(p.strings.Len()))
   129  	hdr.uint64(dataLen)
   130  
   131  	// Flush output.
   132  	io.Copy(out, &hdr)
   133  	io.Copy(out, &p.strings)
   134  	io.Copy(out, &p.data0)
   135  
   136  	return nil
   137  }
   138  
   139  // writeIndex writes out an object index. mainIndex indicates whether
   140  // we're writing out the main index, which is also read by
   141  // non-compiler tools and includes a complete package description
   142  // (i.e., name and height).
   143  func (w *exportWriter) writeIndex(index map[types.Object]uint64) {
   144  	type pkgObj struct {
   145  		obj  types.Object
   146  		name string // qualified name; differs from obj.Name for type params
   147  	}
   148  	// Build a map from packages to objects from that package.
   149  	pkgObjs := map[*types.Package][]pkgObj{}
   150  
   151  	// For the main index, make sure to include every package that
   152  	// we reference, even if we're not exporting (or reexporting)
   153  	// any symbols from it.
   154  	if w.p.localpkg != nil {
   155  		pkgObjs[w.p.localpkg] = nil
   156  	}
   157  	for pkg := range w.p.allPkgs {
   158  		pkgObjs[pkg] = nil
   159  	}
   160  
   161  	for obj := range index {
   162  		name := w.p.exportName(obj)
   163  		pkgObjs[obj.Pkg()] = append(pkgObjs[obj.Pkg()], pkgObj{obj, name})
   164  	}
   165  
   166  	var pkgs []*types.Package
   167  	for pkg, objs := range pkgObjs {
   168  		pkgs = append(pkgs, pkg)
   169  
   170  		sort.Slice(objs, func(i, j int) bool {
   171  			return objs[i].name < objs[j].name
   172  		})
   173  	}
   174  
   175  	sort.Slice(pkgs, func(i, j int) bool {
   176  		return w.exportPath(pkgs[i]) < w.exportPath(pkgs[j])
   177  	})
   178  
   179  	w.uint64(uint64(len(pkgs)))
   180  	for _, pkg := range pkgs {
   181  		w.string(w.exportPath(pkg))
   182  		w.string(pkg.Name())
   183  		w.uint64(uint64(0)) // package height is not needed for go/types
   184  
   185  		objs := pkgObjs[pkg]
   186  		w.uint64(uint64(len(objs)))
   187  		for _, obj := range objs {
   188  			w.string(obj.name)
   189  			w.uint64(index[obj.obj])
   190  		}
   191  	}
   192  }
   193  
   194  // exportName returns the 'exported' name of an object. It differs from
   195  // obj.Name() only for type parameters (see tparamExportName for details).
   196  func (p *iexporter) exportName(obj types.Object) (res string) {
   197  	if name := p.tparamNames[obj]; name != "" {
   198  		return name
   199  	}
   200  	return obj.Name()
   201  }
   202  
   203  type iexporter struct {
   204  	fset    *token.FileSet
   205  	out     *bytes.Buffer
   206  	version int
   207  
   208  	localpkg *types.Package
   209  
   210  	// allPkgs tracks all packages that have been referenced by
   211  	// the export data, so we can ensure to include them in the
   212  	// main index.
   213  	allPkgs map[*types.Package]bool
   214  
   215  	declTodo objQueue
   216  
   217  	strings     intWriter
   218  	stringIndex map[string]uint64
   219  
   220  	data0       intWriter
   221  	declIndex   map[types.Object]uint64
   222  	tparamNames map[types.Object]string // typeparam->exported name
   223  	typIndex    map[types.Type]uint64
   224  
   225  	indent int // for tracing support
   226  }
   227  
   228  func (p *iexporter) trace(format string, args ...interface{}) {
   229  	if !trace {
   230  		// Call sites should also be guarded, but having this check here allows
   231  		// easily enabling/disabling debug trace statements.
   232  		return
   233  	}
   234  	fmt.Printf(strings.Repeat("..", p.indent)+format+"\n", args...)
   235  }
   236  
   237  // stringOff returns the offset of s within the string section.
   238  // If not already present, it's added to the end.
   239  func (p *iexporter) stringOff(s string) uint64 {
   240  	off, ok := p.stringIndex[s]
   241  	if !ok {
   242  		off = uint64(p.strings.Len())
   243  		p.stringIndex[s] = off
   244  
   245  		p.strings.uint64(uint64(len(s)))
   246  		p.strings.WriteString(s)
   247  	}
   248  	return off
   249  }
   250  
   251  // pushDecl adds n to the declaration work queue, if not already present.
   252  func (p *iexporter) pushDecl(obj types.Object) {
   253  	// Package unsafe is known to the compiler and predeclared.
   254  	// Caller should not ask us to do export it.
   255  	if obj.Pkg() == types.Unsafe {
   256  		panic("cannot export package unsafe")
   257  	}
   258  
   259  	if _, ok := p.declIndex[obj]; ok {
   260  		return
   261  	}
   262  
   263  	p.declIndex[obj] = ^uint64(0) // mark obj present in work queue
   264  	p.declTodo.pushTail(obj)
   265  }
   266  
   267  // exportWriter handles writing out individual data section chunks.
   268  type exportWriter struct {
   269  	p *iexporter
   270  
   271  	data       intWriter
   272  	currPkg    *types.Package
   273  	prevFile   string
   274  	prevLine   int64
   275  	prevColumn int64
   276  }
   277  
   278  func (w *exportWriter) exportPath(pkg *types.Package) string {
   279  	if pkg == w.p.localpkg {
   280  		return ""
   281  	}
   282  	return pkg.Path()
   283  }
   284  
   285  func (p *iexporter) doDecl(obj types.Object) {
   286  	if trace {
   287  		p.trace("exporting decl %v (%T)", obj, obj)
   288  		p.indent++
   289  		defer func() {
   290  			p.indent--
   291  			p.trace("=> %s", obj)
   292  		}()
   293  	}
   294  	w := p.newWriter()
   295  	w.setPkg(obj.Pkg(), false)
   296  
   297  	switch obj := obj.(type) {
   298  	case *types.Var:
   299  		w.tag('V')
   300  		w.pos(obj.Pos())
   301  		w.typ(obj.Type(), obj.Pkg())
   302  
   303  	case *types.Func:
   304  		sig, _ := obj.Type().(*types.Signature)
   305  		if sig.Recv() != nil {
   306  			panic(internalErrorf("unexpected method: %v", sig))
   307  		}
   308  
   309  		// Function.
   310  		if typeparams.ForSignature(sig).Len() == 0 {
   311  			w.tag('F')
   312  		} else {
   313  			w.tag('G')
   314  		}
   315  		w.pos(obj.Pos())
   316  		// The tparam list of the function type is the declaration of the type
   317  		// params. So, write out the type params right now. Then those type params
   318  		// will be referenced via their type offset (via typOff) in all other
   319  		// places in the signature and function where they are used.
   320  		//
   321  		// While importing the type parameters, tparamList computes and records
   322  		// their export name, so that it can be later used when writing the index.
   323  		if tparams := typeparams.ForSignature(sig); tparams.Len() > 0 {
   324  			w.tparamList(obj.Name(), tparams, obj.Pkg())
   325  		}
   326  		w.signature(sig)
   327  
   328  	case *types.Const:
   329  		w.tag('C')
   330  		w.pos(obj.Pos())
   331  		w.value(obj.Type(), obj.Val())
   332  
   333  	case *types.TypeName:
   334  		t := obj.Type()
   335  
   336  		if tparam, ok := t.(*typeparams.TypeParam); ok {
   337  			w.tag('P')
   338  			w.pos(obj.Pos())
   339  			constraint := tparam.Constraint()
   340  			if p.version >= iexportVersionGo1_18 {
   341  				implicit := false
   342  				if iface, _ := constraint.(*types.Interface); iface != nil {
   343  					implicit = typeparams.IsImplicit(iface)
   344  				}
   345  				w.bool(implicit)
   346  			}
   347  			w.typ(constraint, obj.Pkg())
   348  			break
   349  		}
   350  
   351  		if obj.IsAlias() {
   352  			w.tag('A')
   353  			w.pos(obj.Pos())
   354  			w.typ(t, obj.Pkg())
   355  			break
   356  		}
   357  
   358  		// Defined type.
   359  		named, ok := t.(*types.Named)
   360  		if !ok {
   361  			panic(internalErrorf("%s is not a defined type", t))
   362  		}
   363  
   364  		if typeparams.ForNamed(named).Len() == 0 {
   365  			w.tag('T')
   366  		} else {
   367  			w.tag('U')
   368  		}
   369  		w.pos(obj.Pos())
   370  
   371  		if typeparams.ForNamed(named).Len() > 0 {
   372  			// While importing the type parameters, tparamList computes and records
   373  			// their export name, so that it can be later used when writing the index.
   374  			w.tparamList(obj.Name(), typeparams.ForNamed(named), obj.Pkg())
   375  		}
   376  
   377  		underlying := obj.Type().Underlying()
   378  		w.typ(underlying, obj.Pkg())
   379  
   380  		if types.IsInterface(t) {
   381  			break
   382  		}
   383  
   384  		n := named.NumMethods()
   385  		w.uint64(uint64(n))
   386  		for i := 0; i < n; i++ {
   387  			m := named.Method(i)
   388  			w.pos(m.Pos())
   389  			w.string(m.Name())
   390  			sig, _ := m.Type().(*types.Signature)
   391  
   392  			// Receiver type parameters are type arguments of the receiver type, so
   393  			// their name must be qualified before exporting recv.
   394  			if rparams := typeparams.RecvTypeParams(sig); rparams.Len() > 0 {
   395  				prefix := obj.Name() + "." + m.Name()
   396  				for i := 0; i < rparams.Len(); i++ {
   397  					rparam := rparams.At(i)
   398  					name := tparamExportName(prefix, rparam)
   399  					w.p.tparamNames[rparam.Obj()] = name
   400  				}
   401  			}
   402  			w.param(sig.Recv())
   403  			w.signature(sig)
   404  		}
   405  
   406  	default:
   407  		panic(internalErrorf("unexpected object: %v", obj))
   408  	}
   409  
   410  	p.declIndex[obj] = w.flush()
   411  }
   412  
   413  func (w *exportWriter) tag(tag byte) {
   414  	w.data.WriteByte(tag)
   415  }
   416  
   417  func (w *exportWriter) pos(pos token.Pos) {
   418  	if w.p.version >= iexportVersionPosCol {
   419  		w.posV1(pos)
   420  	} else {
   421  		w.posV0(pos)
   422  	}
   423  }
   424  
   425  func (w *exportWriter) posV1(pos token.Pos) {
   426  	if w.p.fset == nil {
   427  		w.int64(0)
   428  		return
   429  	}
   430  
   431  	p := w.p.fset.Position(pos)
   432  	file := p.Filename
   433  	line := int64(p.Line)
   434  	column := int64(p.Column)
   435  
   436  	deltaColumn := (column - w.prevColumn) << 1
   437  	deltaLine := (line - w.prevLine) << 1
   438  
   439  	if file != w.prevFile {
   440  		deltaLine |= 1
   441  	}
   442  	if deltaLine != 0 {
   443  		deltaColumn |= 1
   444  	}
   445  
   446  	w.int64(deltaColumn)
   447  	if deltaColumn&1 != 0 {
   448  		w.int64(deltaLine)
   449  		if deltaLine&1 != 0 {
   450  			w.string(file)
   451  		}
   452  	}
   453  
   454  	w.prevFile = file
   455  	w.prevLine = line
   456  	w.prevColumn = column
   457  }
   458  
   459  func (w *exportWriter) posV0(pos token.Pos) {
   460  	if w.p.fset == nil {
   461  		w.int64(0)
   462  		return
   463  	}
   464  
   465  	p := w.p.fset.Position(pos)
   466  	file := p.Filename
   467  	line := int64(p.Line)
   468  
   469  	// When file is the same as the last position (common case),
   470  	// we can save a few bytes by delta encoding just the line
   471  	// number.
   472  	//
   473  	// Note: Because data objects may be read out of order (or not
   474  	// at all), we can only apply delta encoding within a single
   475  	// object. This is handled implicitly by tracking prevFile and
   476  	// prevLine as fields of exportWriter.
   477  
   478  	if file == w.prevFile {
   479  		delta := line - w.prevLine
   480  		w.int64(delta)
   481  		if delta == deltaNewFile {
   482  			w.int64(-1)
   483  		}
   484  	} else {
   485  		w.int64(deltaNewFile)
   486  		w.int64(line) // line >= 0
   487  		w.string(file)
   488  		w.prevFile = file
   489  	}
   490  	w.prevLine = line
   491  }
   492  
   493  func (w *exportWriter) pkg(pkg *types.Package) {
   494  	// Ensure any referenced packages are declared in the main index.
   495  	w.p.allPkgs[pkg] = true
   496  
   497  	w.string(w.exportPath(pkg))
   498  }
   499  
   500  func (w *exportWriter) qualifiedIdent(obj types.Object) {
   501  	name := w.p.exportName(obj)
   502  
   503  	// Ensure any referenced declarations are written out too.
   504  	w.p.pushDecl(obj)
   505  	w.string(name)
   506  	w.pkg(obj.Pkg())
   507  }
   508  
   509  func (w *exportWriter) typ(t types.Type, pkg *types.Package) {
   510  	w.data.uint64(w.p.typOff(t, pkg))
   511  }
   512  
   513  func (p *iexporter) newWriter() *exportWriter {
   514  	return &exportWriter{p: p}
   515  }
   516  
   517  func (w *exportWriter) flush() uint64 {
   518  	off := uint64(w.p.data0.Len())
   519  	io.Copy(&w.p.data0, &w.data)
   520  	return off
   521  }
   522  
   523  func (p *iexporter) typOff(t types.Type, pkg *types.Package) uint64 {
   524  	off, ok := p.typIndex[t]
   525  	if !ok {
   526  		w := p.newWriter()
   527  		w.doTyp(t, pkg)
   528  		off = predeclReserved + w.flush()
   529  		p.typIndex[t] = off
   530  	}
   531  	return off
   532  }
   533  
   534  func (w *exportWriter) startType(k itag) {
   535  	w.data.uint64(uint64(k))
   536  }
   537  
   538  func (w *exportWriter) doTyp(t types.Type, pkg *types.Package) {
   539  	if trace {
   540  		w.p.trace("exporting type %s (%T)", t, t)
   541  		w.p.indent++
   542  		defer func() {
   543  			w.p.indent--
   544  			w.p.trace("=> %s", t)
   545  		}()
   546  	}
   547  	switch t := t.(type) {
   548  	case *types.Named:
   549  		if targs := typeparams.NamedTypeArgs(t); targs.Len() > 0 {
   550  			w.startType(instanceType)
   551  			// TODO(rfindley): investigate if this position is correct, and if it
   552  			// matters.
   553  			w.pos(t.Obj().Pos())
   554  			w.typeList(targs, pkg)
   555  			w.typ(typeparams.NamedTypeOrigin(t), pkg)
   556  			return
   557  		}
   558  		w.startType(definedType)
   559  		w.qualifiedIdent(t.Obj())
   560  
   561  	case *typeparams.TypeParam:
   562  		w.startType(typeParamType)
   563  		w.qualifiedIdent(t.Obj())
   564  
   565  	case *types.Pointer:
   566  		w.startType(pointerType)
   567  		w.typ(t.Elem(), pkg)
   568  
   569  	case *types.Slice:
   570  		w.startType(sliceType)
   571  		w.typ(t.Elem(), pkg)
   572  
   573  	case *types.Array:
   574  		w.startType(arrayType)
   575  		w.uint64(uint64(t.Len()))
   576  		w.typ(t.Elem(), pkg)
   577  
   578  	case *types.Chan:
   579  		w.startType(chanType)
   580  		// 1 RecvOnly; 2 SendOnly; 3 SendRecv
   581  		var dir uint64
   582  		switch t.Dir() {
   583  		case types.RecvOnly:
   584  			dir = 1
   585  		case types.SendOnly:
   586  			dir = 2
   587  		case types.SendRecv:
   588  			dir = 3
   589  		}
   590  		w.uint64(dir)
   591  		w.typ(t.Elem(), pkg)
   592  
   593  	case *types.Map:
   594  		w.startType(mapType)
   595  		w.typ(t.Key(), pkg)
   596  		w.typ(t.Elem(), pkg)
   597  
   598  	case *types.Signature:
   599  		w.startType(signatureType)
   600  		w.setPkg(pkg, true)
   601  		w.signature(t)
   602  
   603  	case *types.Struct:
   604  		w.startType(structType)
   605  		w.setPkg(pkg, true)
   606  
   607  		n := t.NumFields()
   608  		w.uint64(uint64(n))
   609  		for i := 0; i < n; i++ {
   610  			f := t.Field(i)
   611  			w.pos(f.Pos())
   612  			w.string(f.Name())
   613  			w.typ(f.Type(), pkg)
   614  			w.bool(f.Anonymous())
   615  			w.string(t.Tag(i)) // note (or tag)
   616  		}
   617  
   618  	case *types.Interface:
   619  		w.startType(interfaceType)
   620  		w.setPkg(pkg, true)
   621  
   622  		n := t.NumEmbeddeds()
   623  		w.uint64(uint64(n))
   624  		for i := 0; i < n; i++ {
   625  			ft := t.EmbeddedType(i)
   626  			tPkg := pkg
   627  			if named, _ := ft.(*types.Named); named != nil {
   628  				w.pos(named.Obj().Pos())
   629  			} else {
   630  				w.pos(token.NoPos)
   631  			}
   632  			w.typ(ft, tPkg)
   633  		}
   634  
   635  		n = t.NumExplicitMethods()
   636  		w.uint64(uint64(n))
   637  		for i := 0; i < n; i++ {
   638  			m := t.ExplicitMethod(i)
   639  			w.pos(m.Pos())
   640  			w.string(m.Name())
   641  			sig, _ := m.Type().(*types.Signature)
   642  			w.signature(sig)
   643  		}
   644  
   645  	case *typeparams.Union:
   646  		w.startType(unionType)
   647  		nt := t.Len()
   648  		w.uint64(uint64(nt))
   649  		for i := 0; i < nt; i++ {
   650  			term := t.Term(i)
   651  			w.bool(term.Tilde())
   652  			w.typ(term.Type(), pkg)
   653  		}
   654  
   655  	default:
   656  		panic(internalErrorf("unexpected type: %v, %v", t, reflect.TypeOf(t)))
   657  	}
   658  }
   659  
   660  func (w *exportWriter) setPkg(pkg *types.Package, write bool) {
   661  	if write {
   662  		w.pkg(pkg)
   663  	}
   664  
   665  	w.currPkg = pkg
   666  }
   667  
   668  func (w *exportWriter) signature(sig *types.Signature) {
   669  	w.paramList(sig.Params())
   670  	w.paramList(sig.Results())
   671  	if sig.Params().Len() > 0 {
   672  		w.bool(sig.Variadic())
   673  	}
   674  }
   675  
   676  func (w *exportWriter) typeList(ts *typeparams.TypeList, pkg *types.Package) {
   677  	w.uint64(uint64(ts.Len()))
   678  	for i := 0; i < ts.Len(); i++ {
   679  		w.typ(ts.At(i), pkg)
   680  	}
   681  }
   682  
   683  func (w *exportWriter) tparamList(prefix string, list *typeparams.TypeParamList, pkg *types.Package) {
   684  	ll := uint64(list.Len())
   685  	w.uint64(ll)
   686  	for i := 0; i < list.Len(); i++ {
   687  		tparam := list.At(i)
   688  		// Set the type parameter exportName before exporting its type.
   689  		exportName := tparamExportName(prefix, tparam)
   690  		w.p.tparamNames[tparam.Obj()] = exportName
   691  		w.typ(list.At(i), pkg)
   692  	}
   693  }
   694  
   695  const blankMarker = "$"
   696  
   697  // tparamExportName returns the 'exported' name of a type parameter, which
   698  // differs from its actual object name: it is prefixed with a qualifier, and
   699  // blank type parameter names are disambiguated by their index in the type
   700  // parameter list.
   701  func tparamExportName(prefix string, tparam *typeparams.TypeParam) string {
   702  	assert(prefix != "")
   703  	name := tparam.Obj().Name()
   704  	if name == "_" {
   705  		name = blankMarker + strconv.Itoa(tparam.Index())
   706  	}
   707  	return prefix + "." + name
   708  }
   709  
   710  // tparamName returns the real name of a type parameter, after stripping its
   711  // qualifying prefix and reverting blank-name encoding. See tparamExportName
   712  // for details.
   713  func tparamName(exportName string) string {
   714  	// Remove the "path" from the type param name that makes it unique.
   715  	ix := strings.LastIndex(exportName, ".")
   716  	if ix < 0 {
   717  		errorf("malformed type parameter export name %s: missing prefix", exportName)
   718  	}
   719  	name := exportName[ix+1:]
   720  	if strings.HasPrefix(name, blankMarker) {
   721  		return "_"
   722  	}
   723  	return name
   724  }
   725  
   726  func (w *exportWriter) paramList(tup *types.Tuple) {
   727  	n := tup.Len()
   728  	w.uint64(uint64(n))
   729  	for i := 0; i < n; i++ {
   730  		w.param(tup.At(i))
   731  	}
   732  }
   733  
   734  func (w *exportWriter) param(obj types.Object) {
   735  	w.pos(obj.Pos())
   736  	w.localIdent(obj)
   737  	w.typ(obj.Type(), obj.Pkg())
   738  }
   739  
   740  func (w *exportWriter) value(typ types.Type, v constant.Value) {
   741  	w.typ(typ, nil)
   742  	if w.p.version >= iexportVersionGo1_18 {
   743  		w.int64(int64(v.Kind()))
   744  	}
   745  
   746  	switch b := typ.Underlying().(*types.Basic); b.Info() & types.IsConstType {
   747  	case types.IsBoolean:
   748  		w.bool(constant.BoolVal(v))
   749  	case types.IsInteger:
   750  		var i big.Int
   751  		if i64, exact := constant.Int64Val(v); exact {
   752  			i.SetInt64(i64)
   753  		} else if ui64, exact := constant.Uint64Val(v); exact {
   754  			i.SetUint64(ui64)
   755  		} else {
   756  			i.SetString(v.ExactString(), 10)
   757  		}
   758  		w.mpint(&i, typ)
   759  	case types.IsFloat:
   760  		f := constantToFloat(v)
   761  		w.mpfloat(f, typ)
   762  	case types.IsComplex:
   763  		w.mpfloat(constantToFloat(constant.Real(v)), typ)
   764  		w.mpfloat(constantToFloat(constant.Imag(v)), typ)
   765  	case types.IsString:
   766  		w.string(constant.StringVal(v))
   767  	default:
   768  		if b.Kind() == types.Invalid {
   769  			// package contains type errors
   770  			break
   771  		}
   772  		panic(internalErrorf("unexpected type %v (%v)", typ, typ.Underlying()))
   773  	}
   774  }
   775  
   776  // constantToFloat converts a constant.Value with kind constant.Float to a
   777  // big.Float.
   778  func constantToFloat(x constant.Value) *big.Float {
   779  	x = constant.ToFloat(x)
   780  	// Use the same floating-point precision (512) as cmd/compile
   781  	// (see Mpprec in cmd/compile/internal/gc/mpfloat.go).
   782  	const mpprec = 512
   783  	var f big.Float
   784  	f.SetPrec(mpprec)
   785  	if v, exact := constant.Float64Val(x); exact {
   786  		// float64
   787  		f.SetFloat64(v)
   788  	} else if num, denom := constant.Num(x), constant.Denom(x); num.Kind() == constant.Int {
   789  		// TODO(gri): add big.Rat accessor to constant.Value.
   790  		n := valueToRat(num)
   791  		d := valueToRat(denom)
   792  		f.SetRat(n.Quo(n, d))
   793  	} else {
   794  		// Value too large to represent as a fraction => inaccessible.
   795  		// TODO(gri): add big.Float accessor to constant.Value.
   796  		_, ok := f.SetString(x.ExactString())
   797  		assert(ok)
   798  	}
   799  	return &f
   800  }
   801  
   802  // mpint exports a multi-precision integer.
   803  //
   804  // For unsigned types, small values are written out as a single
   805  // byte. Larger values are written out as a length-prefixed big-endian
   806  // byte string, where the length prefix is encoded as its complement.
   807  // For example, bytes 0, 1, and 2 directly represent the integer
   808  // values 0, 1, and 2; while bytes 255, 254, and 253 indicate a 1-,
   809  // 2-, and 3-byte big-endian string follow.
   810  //
   811  // Encoding for signed types use the same general approach as for
   812  // unsigned types, except small values use zig-zag encoding and the
   813  // bottom bit of length prefix byte for large values is reserved as a
   814  // sign bit.
   815  //
   816  // The exact boundary between small and large encodings varies
   817  // according to the maximum number of bytes needed to encode a value
   818  // of type typ. As a special case, 8-bit types are always encoded as a
   819  // single byte.
   820  //
   821  // TODO(mdempsky): Is this level of complexity really worthwhile?
   822  func (w *exportWriter) mpint(x *big.Int, typ types.Type) {
   823  	basic, ok := typ.Underlying().(*types.Basic)
   824  	if !ok {
   825  		panic(internalErrorf("unexpected type %v (%T)", typ.Underlying(), typ.Underlying()))
   826  	}
   827  
   828  	signed, maxBytes := intSize(basic)
   829  
   830  	negative := x.Sign() < 0
   831  	if !signed && negative {
   832  		panic(internalErrorf("negative unsigned integer; type %v, value %v", typ, x))
   833  	}
   834  
   835  	b := x.Bytes()
   836  	if len(b) > 0 && b[0] == 0 {
   837  		panic(internalErrorf("leading zeros"))
   838  	}
   839  	if uint(len(b)) > maxBytes {
   840  		panic(internalErrorf("bad mpint length: %d > %d (type %v, value %v)", len(b), maxBytes, typ, x))
   841  	}
   842  
   843  	maxSmall := 256 - maxBytes
   844  	if signed {
   845  		maxSmall = 256 - 2*maxBytes
   846  	}
   847  	if maxBytes == 1 {
   848  		maxSmall = 256
   849  	}
   850  
   851  	// Check if x can use small value encoding.
   852  	if len(b) <= 1 {
   853  		var ux uint
   854  		if len(b) == 1 {
   855  			ux = uint(b[0])
   856  		}
   857  		if signed {
   858  			ux <<= 1
   859  			if negative {
   860  				ux--
   861  			}
   862  		}
   863  		if ux < maxSmall {
   864  			w.data.WriteByte(byte(ux))
   865  			return
   866  		}
   867  	}
   868  
   869  	n := 256 - uint(len(b))
   870  	if signed {
   871  		n = 256 - 2*uint(len(b))
   872  		if negative {
   873  			n |= 1
   874  		}
   875  	}
   876  	if n < maxSmall || n >= 256 {
   877  		panic(internalErrorf("encoding mistake: %d, %v, %v => %d", len(b), signed, negative, n))
   878  	}
   879  
   880  	w.data.WriteByte(byte(n))
   881  	w.data.Write(b)
   882  }
   883  
   884  // mpfloat exports a multi-precision floating point number.
   885  //
   886  // The number's value is decomposed into mantissa × 2**exponent, where
   887  // mantissa is an integer. The value is written out as mantissa (as a
   888  // multi-precision integer) and then the exponent, except exponent is
   889  // omitted if mantissa is zero.
   890  func (w *exportWriter) mpfloat(f *big.Float, typ types.Type) {
   891  	if f.IsInf() {
   892  		panic("infinite constant")
   893  	}
   894  
   895  	// Break into f = mant × 2**exp, with 0.5 <= mant < 1.
   896  	var mant big.Float
   897  	exp := int64(f.MantExp(&mant))
   898  
   899  	// Scale so that mant is an integer.
   900  	prec := mant.MinPrec()
   901  	mant.SetMantExp(&mant, int(prec))
   902  	exp -= int64(prec)
   903  
   904  	manti, acc := mant.Int(nil)
   905  	if acc != big.Exact {
   906  		panic(internalErrorf("mantissa scaling failed for %f (%s)", f, acc))
   907  	}
   908  	w.mpint(manti, typ)
   909  	if manti.Sign() != 0 {
   910  		w.int64(exp)
   911  	}
   912  }
   913  
   914  func (w *exportWriter) bool(b bool) bool {
   915  	var x uint64
   916  	if b {
   917  		x = 1
   918  	}
   919  	w.uint64(x)
   920  	return b
   921  }
   922  
   923  func (w *exportWriter) int64(x int64)   { w.data.int64(x) }
   924  func (w *exportWriter) uint64(x uint64) { w.data.uint64(x) }
   925  func (w *exportWriter) string(s string) { w.uint64(w.p.stringOff(s)) }
   926  
   927  func (w *exportWriter) localIdent(obj types.Object) {
   928  	// Anonymous parameters.
   929  	if obj == nil {
   930  		w.string("")
   931  		return
   932  	}
   933  
   934  	name := obj.Name()
   935  	if name == "_" {
   936  		w.string("_")
   937  		return
   938  	}
   939  
   940  	w.string(name)
   941  }
   942  
   943  type intWriter struct {
   944  	bytes.Buffer
   945  }
   946  
   947  func (w *intWriter) int64(x int64) {
   948  	var buf [binary.MaxVarintLen64]byte
   949  	n := binary.PutVarint(buf[:], x)
   950  	w.Write(buf[:n])
   951  }
   952  
   953  func (w *intWriter) uint64(x uint64) {
   954  	var buf [binary.MaxVarintLen64]byte
   955  	n := binary.PutUvarint(buf[:], x)
   956  	w.Write(buf[:n])
   957  }
   958  
   959  func assert(cond bool) {
   960  	if !cond {
   961  		panic("internal error: assertion failed")
   962  	}
   963  }
   964  
   965  // The below is copied from go/src/cmd/compile/internal/gc/syntax.go.
   966  
   967  // objQueue is a FIFO queue of types.Object. The zero value of objQueue is
   968  // a ready-to-use empty queue.
   969  type objQueue struct {
   970  	ring       []types.Object
   971  	head, tail int
   972  }
   973  
   974  // empty returns true if q contains no Nodes.
   975  func (q *objQueue) empty() bool {
   976  	return q.head == q.tail
   977  }
   978  
   979  // pushTail appends n to the tail of the queue.
   980  func (q *objQueue) pushTail(obj types.Object) {
   981  	if len(q.ring) == 0 {
   982  		q.ring = make([]types.Object, 16)
   983  	} else if q.head+len(q.ring) == q.tail {
   984  		// Grow the ring.
   985  		nring := make([]types.Object, len(q.ring)*2)
   986  		// Copy the old elements.
   987  		part := q.ring[q.head%len(q.ring):]
   988  		if q.tail-q.head <= len(part) {
   989  			part = part[:q.tail-q.head]
   990  			copy(nring, part)
   991  		} else {
   992  			pos := copy(nring, part)
   993  			copy(nring[pos:], q.ring[:q.tail%len(q.ring)])
   994  		}
   995  		q.ring, q.head, q.tail = nring, 0, q.tail-q.head
   996  	}
   997  
   998  	q.ring[q.tail%len(q.ring)] = obj
   999  	q.tail++
  1000  }
  1001  
  1002  // popHead pops a node from the head of the queue. It panics if q is empty.
  1003  func (q *objQueue) popHead() types.Object {
  1004  	if q.empty() {
  1005  		panic("dequeue empty")
  1006  	}
  1007  	obj := q.ring[q.head%len(q.ring)]
  1008  	q.head++
  1009  	return obj
  1010  }