github.com/q45/go@v0.0.0-20151101211701-a4fb8c13db3f/src/cmd/compile/internal/gc/bexport.go (about)

     1  // Copyright 2015 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  // Binary package export.
     6  // Based loosely on x/tools/go/importer.
     7  // (see fmt.go, go.y as "documentation" for how to use/setup data structures)
     8  //
     9  // Use "-newexport" flag to enable.
    10  
    11  // TODO(gri):
    12  // - inlined functions
    13  
    14  /*
    15  Export data encoding:
    16  
    17  The export data is a serialized description of the graph of exported
    18  objects: constants, types, variables, and functions. Only types can
    19  be re-exported and so we need to know which package they are coming
    20  from. Therefore, packages are also part of the export graph.
    21  
    22  The roots of the graph are the list of constants, variables, functions,
    23  and eventually types. Types are written last because most of them will
    24  be written as part of other objects which will reduce the number of
    25  types that need to be written separately.
    26  
    27  The graph is serialized in in-order fashion, starting with the roots.
    28  Each object in the graph is serialized by writing its fields sequentially.
    29  If the field is a pointer to another object, that object is serialized,
    30  recursively. Otherwise the field is written. Non-pointer fields are all
    31  encoded as either an integer or string value.
    32  
    33  Only packages and types may be referred to more than once. When getting
    34  to a package or type that was not serialized before, a number (index) is
    35  assigned to it, starting at 0. In this case, the encoding starts with an
    36  integer tag with a value < 0. The tag value indicates the kind of object
    37  (package or type) that follows and that this is the first time that we
    38  see this object. If the package or tag was already serialized, the encoding
    39  starts with the respective package or type index >= 0. An importer can
    40  trivially determine if a package or type needs to be read in for the first
    41  time (tag < 0) and entered into the respective package or type table, or
    42  if the package or type was seen already (index >= 0), in which case the
    43  index is the table index where the respective object can be found.
    44  
    45  Before exporting or importing, the type tables are populated with the
    46  predeclared types (int, string, error, unsafe.Pointer, etc.). This way
    47  they are automatically encoded with a known and fixed type index.
    48  
    49  Encoding format:
    50  
    51  The export data starts with a single byte indicating the encoding format
    52  (compact, or with debugging information), followed by a version string
    53  (so we can evolve the encoding if need be), the name of the imported
    54  package, and a string containing platform-specific information for that
    55  package.
    56  
    57  After this header, the lists of objects follow. After the objects, platform-
    58  specific data may be found which is not used strictly for type checking.
    59  
    60  The encoding of objects is straight-forward: Constants, variables, and
    61  functions start with their name, type, and possibly a value. Named types
    62  record their name and package so that they can be canonicalized: If the
    63  same type was imported before via another import, the importer must use
    64  the previously imported type pointer so that we have exactly one version
    65  (i.e., one pointer) for each named type (and read but discard the current
    66  type encoding). Unnamed types simply encode their respective fields.
    67  
    68  In the encoding, all lists (of objects, struct fields, methods, parameter
    69  names, but also the bytes of a string, etc.) start with an integer which
    70  is the length of the list. This permits an importer to allocate the right
    71  amount of space to hold the list without the need to grow it later.
    72  
    73  All integer values use a variable-length encoding for compact representation.
    74  
    75  If debugFormat is set, each integer and string value is preceeded by a marker
    76  and position information in the encoding. This mechanism permits an importer
    77  to recognize immediately when it is out of sync. The importer recognizes this
    78  mode automatically (i.e., it can import export data produced with debugging
    79  support even if debugFormat is not set at the time of import). Using this mode
    80  will massively increase the size of the export data (by a factor of 2 to 3)
    81  and is only recommended for debugging.
    82  
    83  The exporter and importer are completely symmetric in implementation: For
    84  each encoding routine there is the matching and symmetric decoding routine.
    85  This symmetry makes it very easy to change or extend the format: If a new
    86  field needs to be encoded, a symmetric change can be made to exporter and
    87  importer.
    88  */
    89  
    90  package gc
    91  
    92  import (
    93  	"bytes"
    94  	"cmd/compile/internal/big"
    95  	"cmd/internal/obj"
    96  	"encoding/binary"
    97  	"fmt"
    98  	"sort"
    99  	"strings"
   100  )
   101  
   102  // debugging support
   103  const (
   104  	debugFormat = false // use debugging format for export data (emits a lot of additional data)
   105  )
   106  
   107  const exportVersion = "v0"
   108  
   109  // Set forceNewExport to force the use of the new export format - for testing on the build dashboard.
   110  // TODO(gri) remove eventually
   111  const forceNewExport = false
   112  
   113  // Export writes the export data for localpkg to out and returns the number of bytes written.
   114  func Export(out *obj.Biobuf, trace bool) int {
   115  	p := exporter{
   116  		out:      out,
   117  		pkgIndex: make(map[*Pkg]int),
   118  		typIndex: make(map[*Type]int),
   119  		trace:    trace,
   120  	}
   121  
   122  	// write low-level encoding format
   123  	var format byte = 'c' // compact
   124  	if debugFormat {
   125  		format = 'd'
   126  	}
   127  	p.byte(format)
   128  
   129  	// --- generic export data ---
   130  
   131  	if p.trace {
   132  		p.tracef("\n--- generic export data ---\n")
   133  		if p.indent != 0 {
   134  			Fatalf("incorrect indentation %d", p.indent)
   135  		}
   136  	}
   137  
   138  	p.string(exportVersion)
   139  	if p.trace {
   140  		p.tracef("\n")
   141  	}
   142  
   143  	// populate type map with predeclared "known" types
   144  	predecl := predeclared()
   145  	for index, typ := range predecl {
   146  		p.typIndex[typ] = index
   147  	}
   148  	if len(p.typIndex) != len(predecl) {
   149  		Fatalf("duplicate entries in type map?")
   150  	}
   151  
   152  	// write package data
   153  	if localpkg.Path != "" {
   154  		Fatalf("local package path not empty: %q", localpkg.Path)
   155  	}
   156  	p.pkg(localpkg)
   157  
   158  	// write compiler-specific flags
   159  	// go.y:import_safety
   160  	{
   161  		var flags string
   162  		if safemode != 0 {
   163  			flags = "safe"
   164  		}
   165  		p.string(flags)
   166  	}
   167  
   168  	if p.trace {
   169  		p.tracef("\n")
   170  	}
   171  
   172  	// collect objects to export
   173  	var consts, vars, funcs []*Sym
   174  	var types []*Type
   175  	for _, n := range exportlist {
   176  		sym := n.Sym
   177  		// TODO(gri) Closures appear marked as exported.
   178  		// Investigate and determine if we need this.
   179  		if sym.Flags&SymExported != 0 {
   180  			continue
   181  		}
   182  		sym.Flags |= SymExported
   183  
   184  		// TODO(gri) Closures have dots in their names;
   185  		// e.g., TestFloatZeroValue.func1 in math/big tests.
   186  		// We may not need this eventually. See also comment
   187  		// on sym.Flags&SymExported test above.
   188  		if strings.Contains(sym.Name, ".") {
   189  			Fatalf("unexpected export symbol: %v", sym)
   190  		}
   191  
   192  		if sym.Flags&SymExport != 0 {
   193  			if sym.Def == nil {
   194  				Fatalf("unknown export symbol: %v", sym)
   195  			}
   196  			switch n := sym.Def; n.Op {
   197  			case OLITERAL:
   198  				// constant
   199  				typecheck(&n, Erv)
   200  				if n == nil || n.Op != OLITERAL {
   201  					Fatalf("dumpexportconst: oconst nil: %v", sym)
   202  				}
   203  				consts = append(consts, sym)
   204  
   205  			case ONAME:
   206  				// variable or function
   207  				typecheck(&n, Erv|Ecall)
   208  				if n == nil || n.Type == nil {
   209  					Fatalf("variable/function exported but not defined: %v", sym)
   210  				}
   211  				if n.Type.Etype == TFUNC && n.Class == PFUNC {
   212  					funcs = append(funcs, sym)
   213  				} else {
   214  					vars = append(vars, sym)
   215  				}
   216  
   217  			case OTYPE:
   218  				// named type
   219  				t := n.Type
   220  				if t.Etype == TFORW {
   221  					Fatalf("export of incomplete type %v", sym)
   222  				}
   223  				types = append(types, t)
   224  
   225  			default:
   226  				Fatalf("unexpected export symbol: %v %v", Oconv(int(n.Op), 0), sym)
   227  			}
   228  		}
   229  	}
   230  	exportlist = nil // match export.go use of exportlist
   231  
   232  	// for reproducible output
   233  	sort.Sort(symByName(consts))
   234  	sort.Sort(symByName(vars))
   235  	sort.Sort(symByName(funcs))
   236  	// sort types later when we have fewer types left
   237  
   238  	// write consts
   239  	p.int(len(consts))
   240  	for _, sym := range consts {
   241  		n := sym.Def
   242  		typ := n.Type // may or may not be specified
   243  		// Untyped (ideal) constants get their own type. This decouples
   244  		// the constant type from the encoding of the constant value.
   245  		if typ == nil || isideal(typ) {
   246  			typ = untype(n.Val().Ctype())
   247  		}
   248  
   249  		p.string(sym.Name)
   250  		p.typ(typ)
   251  		p.value(n.Val())
   252  	}
   253  
   254  	// write vars
   255  	p.int(len(vars))
   256  	for _, sym := range vars {
   257  		p.string(sym.Name)
   258  		p.typ(sym.Def.Type)
   259  	}
   260  
   261  	// write funcs
   262  	p.int(len(funcs))
   263  	for _, sym := range funcs {
   264  		p.string(sym.Name)
   265  		// The type can only be a signature for functions. However, by always
   266  		// writing the complete type specification (rather than just a signature)
   267  		// we keep the option open of sharing common signatures across multiple
   268  		// functions as a means to further compress the export data.
   269  		p.typ(sym.Def.Type)
   270  		p.int(p.collectInlined(sym.Def))
   271  	}
   272  
   273  	// determine which types are still left to write and sort them
   274  	i := 0
   275  	for _, t := range types {
   276  		if _, ok := p.typIndex[t]; !ok {
   277  			types[i] = t
   278  			i++
   279  		}
   280  	}
   281  	types = types[:i]
   282  	sort.Sort(typByName(types))
   283  
   284  	// write types
   285  	p.int(len(types))
   286  	for _, t := range types {
   287  		// Writing a type may further reduce the number of types
   288  		// that are left to be written, but at this point we don't
   289  		// care.
   290  		p.typ(t)
   291  	}
   292  
   293  	if p.trace {
   294  		p.tracef("\n")
   295  	}
   296  
   297  	// --- compiler-specific export data ---
   298  
   299  	if p.trace {
   300  		p.tracef("\n--- compiler specific export data ---\n")
   301  		if p.indent != 0 {
   302  			Fatalf("incorrect indentation")
   303  		}
   304  	}
   305  
   306  	// write inlined function bodies
   307  	p.int(len(p.inlined))
   308  	for i, f := range p.inlined {
   309  		p.body(i, f)
   310  	}
   311  
   312  	if p.trace {
   313  		p.tracef("\n")
   314  	}
   315  
   316  	// --- end of export data ---
   317  
   318  	return p.written
   319  }
   320  
   321  type symByName []*Sym
   322  
   323  func (a symByName) Len() int           { return len(a) }
   324  func (a symByName) Less(i, j int) bool { return a[i].Name < a[j].Name }
   325  func (a symByName) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
   326  
   327  type typByName []*Type
   328  
   329  func (a typByName) Len() int           { return len(a) }
   330  func (a typByName) Less(i, j int) bool { return a[i].Sym.Name < a[j].Sym.Name }
   331  func (a typByName) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
   332  
   333  type exporter struct {
   334  	out      *obj.Biobuf
   335  	pkgIndex map[*Pkg]int
   336  	typIndex map[*Type]int
   337  	inlined  []*Func
   338  
   339  	written int // bytes written
   340  	indent  int // for p.trace
   341  	trace   bool
   342  }
   343  
   344  func (p *exporter) pkg(pkg *Pkg) {
   345  	if pkg == nil {
   346  		Fatalf("unexpected nil pkg")
   347  	}
   348  
   349  	// if we saw the package before, write its index (>= 0)
   350  	if i, ok := p.pkgIndex[pkg]; ok {
   351  		p.index('P', i)
   352  		return
   353  	}
   354  
   355  	// otherwise, remember the package, write the package tag (< 0) and package data
   356  	if p.trace {
   357  		p.tracef("P%d = { ", len(p.pkgIndex))
   358  		defer p.tracef("} ")
   359  	}
   360  	p.pkgIndex[pkg] = len(p.pkgIndex)
   361  
   362  	p.tag(packageTag)
   363  	p.string(pkg.Name)
   364  	p.string(pkg.Path)
   365  }
   366  
   367  func (p *exporter) typ(t *Type) {
   368  	if t == nil {
   369  		Fatalf("nil type")
   370  	}
   371  
   372  	// Possible optimization: Anonymous pointer types *T where
   373  	// T is a named type are common. We could canonicalize all
   374  	// such types *T to a single type PT = *T. This would lead
   375  	// to at most one *T entry in typIndex, and all future *T's
   376  	// would be encoded as the respective index directly. Would
   377  	// save 1 byte (pointerTag) per *T and reduce the typIndex
   378  	// size (at the cost of a canonicalization map). We can do
   379  	// this later, without encoding format change.
   380  
   381  	// if we saw the type before, write its index (>= 0)
   382  	if i, ok := p.typIndex[t]; ok {
   383  		p.index('T', i)
   384  		return
   385  	}
   386  
   387  	// otherwise, remember the type, write the type tag (< 0) and type data
   388  	if p.trace {
   389  		p.tracef("T%d = {>\n", len(p.typIndex))
   390  		defer p.tracef("<\n} ")
   391  	}
   392  	p.typIndex[t] = len(p.typIndex)
   393  
   394  	// pick off named types
   395  	if sym := t.Sym; sym != nil {
   396  		// Fields should be exported by p.field().
   397  		if t.Etype == TFIELD {
   398  			Fatalf("printing a field/parameter with wrong function")
   399  		}
   400  		// Predeclared types should have been found in the type map.
   401  		if t.Orig == t {
   402  			Fatalf("predeclared type missing from type map?")
   403  		}
   404  		// TODO(gri) The assertion below seems incorrect (crashes during all.bash).
   405  		// Investigate.
   406  		/*
   407  			// we expect the respective definition to point to us
   408  			if sym.Def.Type != t {
   409  				Fatalf("type definition doesn't point to us?")
   410  			}
   411  		*/
   412  
   413  		p.tag(namedTag)
   414  		p.qualifiedName(sym)
   415  
   416  		// write underlying type
   417  		p.typ(t.Orig)
   418  
   419  		// interfaces don't have associated methods
   420  		if t.Orig.Etype == TINTER {
   421  			return
   422  		}
   423  
   424  		// sort methods for reproducible export format
   425  		// TODO(gri) Determine if they are already sorted
   426  		// in which case we can drop this step.
   427  		var methods []*Type
   428  		for m := t.Method; m != nil; m = m.Down {
   429  			methods = append(methods, m)
   430  		}
   431  		sort.Sort(methodbyname(methods))
   432  		p.int(len(methods))
   433  
   434  		if p.trace && t.Method != nil {
   435  			p.tracef("associated methods {>\n")
   436  		}
   437  
   438  		for _, m := range methods {
   439  			p.string(m.Sym.Name)
   440  			p.paramList(getthisx(m.Type))
   441  			p.paramList(getinargx(m.Type))
   442  			p.paramList(getoutargx(m.Type))
   443  			p.int(p.collectInlined(m.Type.Nname))
   444  
   445  			if p.trace && m.Down != nil {
   446  				p.tracef("\n")
   447  			}
   448  		}
   449  
   450  		if p.trace && t.Method != nil {
   451  			p.tracef("<\n} ")
   452  		}
   453  
   454  		return
   455  	}
   456  
   457  	// otherwise we have a type literal
   458  	switch t.Etype {
   459  	case TARRAY:
   460  		// TODO(gri) define named constant for the -100
   461  		if t.Bound >= 0 || t.Bound == -100 {
   462  			p.tag(arrayTag)
   463  			p.int64(t.Bound)
   464  		} else {
   465  			p.tag(sliceTag)
   466  		}
   467  		p.typ(t.Type)
   468  
   469  	case T_old_DARRAY:
   470  		// see p.param use of T_old_DARRAY
   471  		p.tag(dddTag)
   472  		p.typ(t.Type)
   473  
   474  	case TSTRUCT:
   475  		p.tag(structTag)
   476  		p.fieldList(t)
   477  
   478  	case TPTR32, TPTR64: // could use Tptr but these are constants
   479  		p.tag(pointerTag)
   480  		p.typ(t.Type)
   481  
   482  	case TFUNC:
   483  		p.tag(signatureTag)
   484  		p.paramList(getinargx(t))
   485  		p.paramList(getoutargx(t))
   486  
   487  	case TINTER:
   488  		p.tag(interfaceTag)
   489  
   490  		// gc doesn't separate between embedded interfaces
   491  		// and methods declared explicitly with an interface
   492  		p.int(0) // no embedded interfaces
   493  		p.methodList(t)
   494  
   495  	case TMAP:
   496  		p.tag(mapTag)
   497  		p.typ(t.Down) // key
   498  		p.typ(t.Type) // val
   499  
   500  	case TCHAN:
   501  		p.tag(chanTag)
   502  		p.int(int(t.Chan))
   503  		p.typ(t.Type)
   504  
   505  	default:
   506  		Fatalf("unexpected type: %s (Etype = %d)", Tconv(t, 0), t.Etype)
   507  	}
   508  }
   509  
   510  func (p *exporter) qualifiedName(sym *Sym) {
   511  	p.string(sym.Name)
   512  	p.pkg(sym.Pkg)
   513  }
   514  
   515  func (p *exporter) fieldList(t *Type) {
   516  	if p.trace && t.Type != nil {
   517  		p.tracef("fields {>\n")
   518  		defer p.tracef("<\n} ")
   519  	}
   520  
   521  	p.int(countfield(t))
   522  	for f := t.Type; f != nil; f = f.Down {
   523  		p.field(f)
   524  		if p.trace && f.Down != nil {
   525  			p.tracef("\n")
   526  		}
   527  	}
   528  }
   529  
   530  func (p *exporter) field(f *Type) {
   531  	if f.Etype != TFIELD {
   532  		Fatalf("field expected")
   533  	}
   534  
   535  	p.fieldName(f)
   536  	p.typ(f.Type)
   537  	p.note(f.Note)
   538  }
   539  
   540  func (p *exporter) note(n *string) {
   541  	var s string
   542  	if n != nil {
   543  		s = *n
   544  	}
   545  	p.string(s)
   546  }
   547  
   548  func (p *exporter) methodList(t *Type) {
   549  	if p.trace && t.Type != nil {
   550  		p.tracef("methods {>\n")
   551  		defer p.tracef("<\n} ")
   552  	}
   553  
   554  	p.int(countfield(t))
   555  	for m := t.Type; m != nil; m = m.Down {
   556  		p.method(m)
   557  		if p.trace && m.Down != nil {
   558  			p.tracef("\n")
   559  		}
   560  	}
   561  }
   562  
   563  func (p *exporter) method(m *Type) {
   564  	if m.Etype != TFIELD {
   565  		Fatalf("method expected")
   566  	}
   567  
   568  	p.fieldName(m)
   569  	// TODO(gri) For functions signatures, we use p.typ() to export
   570  	// so we could share the same type with multiple functions. Do
   571  	// the same here, or never try to do this for functions.
   572  	p.paramList(getinargx(m.Type))
   573  	p.paramList(getoutargx(m.Type))
   574  }
   575  
   576  // fieldName is like qualifiedName but it doesn't record the package
   577  // for blank (_) or exported names.
   578  func (p *exporter) fieldName(t *Type) {
   579  	sym := t.Sym
   580  
   581  	var name string
   582  	if t.Embedded == 0 {
   583  		name = sym.Name
   584  	} else if bname := basetypeName(t); bname != "" && !exportname(bname) {
   585  		// anonymous field with unexported base type name: use "?" as field name
   586  		// (bname != "" per spec, but we are conservative in case of errors)
   587  		name = "?"
   588  	}
   589  
   590  	p.string(name)
   591  	if name == "?" || name != "_" && name != "" && !exportname(name) {
   592  		p.pkg(sym.Pkg)
   593  	}
   594  }
   595  
   596  func basetypeName(t *Type) string {
   597  	s := t.Sym
   598  	if s == nil && Isptr[t.Etype] {
   599  		s = t.Type.Sym // deref
   600  	}
   601  	if s != nil {
   602  		return s.Name
   603  	}
   604  	return ""
   605  }
   606  
   607  func (p *exporter) paramList(params *Type) {
   608  	if params.Etype != TSTRUCT || !params.Funarg {
   609  		Fatalf("parameter list expected")
   610  	}
   611  
   612  	// use negative length to indicate unnamed parameters
   613  	// (look at the first parameter only since either all
   614  	// names are present or all are absent)
   615  	n := countfield(params)
   616  	if n > 0 && parName(params.Type) == "" {
   617  		n = -n
   618  	}
   619  	p.int(n)
   620  	for q := params.Type; q != nil; q = q.Down {
   621  		p.param(q, n)
   622  	}
   623  }
   624  
   625  func (p *exporter) param(q *Type, n int) {
   626  	if q.Etype != TFIELD {
   627  		Fatalf("parameter expected")
   628  	}
   629  	t := q.Type
   630  	if q.Isddd {
   631  		// create a fake type to encode ... just for the p.typ call
   632  		// (T_old_DARRAY is not used anywhere else in the compiler,
   633  		// we use it here to communicate between p.param and p.typ.)
   634  		t = &Type{Etype: T_old_DARRAY, Type: t.Type}
   635  	}
   636  	p.typ(t)
   637  	if n > 0 {
   638  		p.string(parName(q))
   639  	}
   640  	// TODO(gri) This is compiler-specific (escape info).
   641  	// Move into compiler-specific section eventually?
   642  	// (Not having escape info causes tests to fail, e.g. runtime GCInfoTest)
   643  	p.note(q.Note)
   644  }
   645  
   646  func parName(q *Type) string {
   647  	if q.Sym == nil {
   648  		return ""
   649  	}
   650  	name := q.Sym.Name
   651  	// undo gc-internal name mangling - we just need the source name
   652  	if len(name) > 0 && name[0] == '~' {
   653  		// name is ~b%d or ~r%d
   654  		switch name[1] {
   655  		case 'b':
   656  			return "_"
   657  		case 'r':
   658  			return ""
   659  		default:
   660  			Fatalf("unexpected parameter name: %s", name)
   661  		}
   662  	}
   663  	// undo gc-internal name specialization
   664  	if i := strings.Index(name, "ยท"); i > 0 {
   665  		name = name[:i] // cut off numbering
   666  	}
   667  	return name
   668  }
   669  
   670  func (p *exporter) value(x Val) {
   671  	if p.trace {
   672  		p.tracef("= ")
   673  	}
   674  
   675  	switch x := x.U.(type) {
   676  	case bool:
   677  		tag := falseTag
   678  		if x {
   679  			tag = trueTag
   680  		}
   681  		p.tag(tag)
   682  
   683  	case *Mpint:
   684  		if Mpcmpfixfix(Minintval[TINT64], x) <= 0 && Mpcmpfixfix(x, Maxintval[TINT64]) <= 0 {
   685  			// common case: x fits into an int64 - use compact encoding
   686  			p.tag(int64Tag)
   687  			p.int64(Mpgetfix(x))
   688  			return
   689  		}
   690  		// uncommon case: large x - use float encoding
   691  		// (powers of 2 will be encoded efficiently with exponent)
   692  		p.tag(floatTag)
   693  		f := newMpflt()
   694  		Mpmovefixflt(f, x)
   695  		p.float(f)
   696  
   697  	case *Mpflt:
   698  		p.tag(floatTag)
   699  		p.float(x)
   700  
   701  	case *Mpcplx:
   702  		p.tag(complexTag)
   703  		p.float(&x.Real)
   704  		p.float(&x.Imag)
   705  
   706  	case string:
   707  		p.tag(stringTag)
   708  		p.string(x)
   709  
   710  	default:
   711  		Fatalf("unexpected value %v (%T)", x, x)
   712  	}
   713  }
   714  
   715  func (p *exporter) float(x *Mpflt) {
   716  	// extract sign (there is no -0)
   717  	f := &x.Val
   718  	sign := f.Sign()
   719  	if sign == 0 {
   720  		// x == 0
   721  		p.int(0)
   722  		return
   723  	}
   724  	// x != 0
   725  
   726  	// extract exponent such that 0.5 <= m < 1.0
   727  	var m big.Float
   728  	exp := f.MantExp(&m)
   729  
   730  	// extract mantissa as *big.Int
   731  	// - set exponent large enough so mant satisfies mant.IsInt()
   732  	// - get *big.Int from mant
   733  	m.SetMantExp(&m, int(m.MinPrec()))
   734  	mant, acc := m.Int(nil)
   735  	if acc != big.Exact {
   736  		Fatalf("internal error")
   737  	}
   738  
   739  	p.int(sign)
   740  	p.int(exp)
   741  	p.string(string(mant.Bytes()))
   742  }
   743  
   744  // ----------------------------------------------------------------------------
   745  // Inlined function bodies
   746  
   747  // TODO(gri) This section is incomplete. At the moment nothing meaningful
   748  // is written out for exported functions with inlined function bodies.
   749  
   750  func (p *exporter) collectInlined(n *Node) int {
   751  	if n != nil && n.Func != nil && n.Func.Inl != nil {
   752  		// when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet.
   753  		// currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package
   754  		if Debug['l'] < 2 {
   755  			typecheckinl(n)
   756  		}
   757  		p.inlined = append(p.inlined, n.Func)
   758  		return len(p.inlined) - 1 // index >= 0 => inlined
   759  	}
   760  	return -1 // index < 0 => not inlined
   761  }
   762  
   763  func (p *exporter) body(i int, f *Func) {
   764  	p.int(i)
   765  	p.block(f.Inl)
   766  }
   767  
   768  func (p *exporter) block(list *NodeList) {
   769  	p.int(count(list))
   770  	for q := list; q != nil; q = q.Next {
   771  		p.stmt(q.N)
   772  	}
   773  }
   774  
   775  func (p *exporter) stmt(n *Node) {
   776  	// TODO(gri) do something sensible here
   777  	p.string("body")
   778  }
   779  
   780  // ----------------------------------------------------------------------------
   781  // Low-level encoders
   782  
   783  func (p *exporter) index(marker byte, index int) {
   784  	if index < 0 {
   785  		Fatalf("invalid index < 0")
   786  	}
   787  	if debugFormat {
   788  		p.marker('t')
   789  	}
   790  	if p.trace {
   791  		p.tracef("%c%d ", marker, index)
   792  	}
   793  	p.rawInt64(int64(index))
   794  }
   795  
   796  func (p *exporter) tag(tag int) {
   797  	if tag >= 0 {
   798  		Fatalf("invalid tag >= 0")
   799  	}
   800  	if debugFormat {
   801  		p.marker('t')
   802  	}
   803  	if p.trace {
   804  		p.tracef("%s ", tagString[-tag])
   805  	}
   806  	p.rawInt64(int64(tag))
   807  }
   808  
   809  func (p *exporter) int(x int) {
   810  	p.int64(int64(x))
   811  }
   812  
   813  func (p *exporter) int64(x int64) {
   814  	if debugFormat {
   815  		p.marker('i')
   816  	}
   817  	if p.trace {
   818  		p.tracef("%d ", x)
   819  	}
   820  	p.rawInt64(x)
   821  }
   822  
   823  func (p *exporter) string(s string) {
   824  	if debugFormat {
   825  		p.marker('s')
   826  	}
   827  	if p.trace {
   828  		p.tracef("%q ", s)
   829  	}
   830  	p.rawInt64(int64(len(s)))
   831  	for i := 0; i < len(s); i++ {
   832  		p.byte(s[i])
   833  	}
   834  }
   835  
   836  // marker emits a marker byte and position information which makes
   837  // it easy for a reader to detect if it is "out of sync". Used for
   838  // debugFormat format only.
   839  func (p *exporter) marker(m byte) {
   840  	p.byte(m)
   841  	p.rawInt64(int64(p.written))
   842  }
   843  
   844  // rawInt64 should only be used by low-level encoders
   845  func (p *exporter) rawInt64(x int64) {
   846  	var tmp [binary.MaxVarintLen64]byte
   847  	n := binary.PutVarint(tmp[:], x)
   848  	for i := 0; i < n; i++ {
   849  		p.byte(tmp[i])
   850  	}
   851  }
   852  
   853  // byte is the bottleneck interface to write to p.out.
   854  // byte escapes b as follows (any encoding does that
   855  // hides '$'):
   856  //
   857  //	'$'  => '|' 'S'
   858  //	'|'  => '|' '|'
   859  //
   860  // Necessary so other tools can find the end of the
   861  // export data by searching for "$$".
   862  func (p *exporter) byte(b byte) {
   863  	switch b {
   864  	case '$':
   865  		// write '$' as '|' 'S'
   866  		b = 'S'
   867  		fallthrough
   868  	case '|':
   869  		// write '|' as '|' '|'
   870  		obj.Bputc(p.out, '|')
   871  		p.written++
   872  	}
   873  	obj.Bputc(p.out, b)
   874  	p.written++
   875  }
   876  
   877  // tracef is like fmt.Printf but it rewrites the format string
   878  // to take care of indentation.
   879  func (p *exporter) tracef(format string, args ...interface{}) {
   880  	if strings.IndexAny(format, "<>\n") >= 0 {
   881  		var buf bytes.Buffer
   882  		for i := 0; i < len(format); i++ {
   883  			// no need to deal with runes
   884  			ch := format[i]
   885  			switch ch {
   886  			case '>':
   887  				p.indent++
   888  				continue
   889  			case '<':
   890  				p.indent--
   891  				continue
   892  			}
   893  			buf.WriteByte(ch)
   894  			if ch == '\n' {
   895  				for j := p.indent; j > 0; j-- {
   896  					buf.WriteString(".  ")
   897  				}
   898  			}
   899  		}
   900  		format = buf.String()
   901  	}
   902  	fmt.Printf(format, args...)
   903  }
   904  
   905  // ----------------------------------------------------------------------------
   906  // Export format
   907  
   908  // Tags. Must be < 0.
   909  const (
   910  	// Packages
   911  	packageTag = -(iota + 1)
   912  
   913  	// Types
   914  	namedTag
   915  	arrayTag
   916  	sliceTag
   917  	dddTag
   918  	structTag
   919  	pointerTag
   920  	signatureTag
   921  	interfaceTag
   922  	mapTag
   923  	chanTag
   924  
   925  	// Values
   926  	falseTag
   927  	trueTag
   928  	int64Tag
   929  	floatTag
   930  	fractionTag // not used by gc
   931  	complexTag
   932  	stringTag
   933  )
   934  
   935  // Debugging support.
   936  // (tagString is only used when tracing is enabled)
   937  var tagString = [...]string{
   938  	// Packages:
   939  	-packageTag: "package",
   940  
   941  	// Types:
   942  	-namedTag:     "named type",
   943  	-arrayTag:     "array",
   944  	-sliceTag:     "slice",
   945  	-dddTag:       "ddd",
   946  	-structTag:    "struct",
   947  	-pointerTag:   "pointer",
   948  	-signatureTag: "signature",
   949  	-interfaceTag: "interface",
   950  	-mapTag:       "map",
   951  	-chanTag:      "chan",
   952  
   953  	// Values:
   954  	-falseTag:    "false",
   955  	-trueTag:     "true",
   956  	-int64Tag:    "int64",
   957  	-floatTag:    "float",
   958  	-fractionTag: "fraction",
   959  	-complexTag:  "complex",
   960  	-stringTag:   "string",
   961  }
   962  
   963  // untype returns the "pseudo" untyped type for a Ctype (import/export use only).
   964  // (we can't use an pre-initialized array because we must be sure all types are
   965  // set up)
   966  func untype(ctype Ctype) *Type {
   967  	switch ctype {
   968  	case CTINT:
   969  		return idealint
   970  	case CTRUNE:
   971  		return idealrune
   972  	case CTFLT:
   973  		return idealfloat
   974  	case CTCPLX:
   975  		return idealcomplex
   976  	case CTSTR:
   977  		return idealstring
   978  	case CTBOOL:
   979  		return idealbool
   980  	case CTNIL:
   981  		return Types[TNIL]
   982  	}
   983  	Fatalf("unknown Ctype")
   984  	return nil
   985  }
   986  
   987  var (
   988  	idealint     = typ(TIDEAL)
   989  	idealrune    = typ(TIDEAL)
   990  	idealfloat   = typ(TIDEAL)
   991  	idealcomplex = typ(TIDEAL)
   992  )
   993  
   994  var predecl []*Type // initialized lazily
   995  
   996  func predeclared() []*Type {
   997  	if predecl == nil {
   998  		// initialize lazily to be sure that all
   999  		// elements have been initialized before
  1000  		predecl = []*Type{
  1001  			// basic types
  1002  			Types[TBOOL],
  1003  			Types[TINT],
  1004  			Types[TINT8],
  1005  			Types[TINT16],
  1006  			Types[TINT32],
  1007  			Types[TINT64],
  1008  			Types[TUINT],
  1009  			Types[TUINT8],
  1010  			Types[TUINT16],
  1011  			Types[TUINT32],
  1012  			Types[TUINT64],
  1013  			Types[TUINTPTR],
  1014  			Types[TFLOAT32],
  1015  			Types[TFLOAT64],
  1016  			Types[TCOMPLEX64],
  1017  			Types[TCOMPLEX128],
  1018  			Types[TSTRING],
  1019  
  1020  			// aliases
  1021  			bytetype,
  1022  			runetype,
  1023  
  1024  			// error
  1025  			errortype,
  1026  
  1027  			// untyped types
  1028  			untype(CTBOOL),
  1029  			untype(CTINT),
  1030  			untype(CTRUNE),
  1031  			untype(CTFLT),
  1032  			untype(CTCPLX),
  1033  			untype(CTSTR),
  1034  			untype(CTNIL),
  1035  
  1036  			// package unsafe
  1037  			Types[TUNSAFEPTR],
  1038  		}
  1039  	}
  1040  	return predecl
  1041  }