Black Lives Matter. Support the Equal Justice Initiative.

Source file src/cmd/compile/internal/typecheck/iexport.go

Documentation: cmd/compile/internal/typecheck

     1  // Copyright 2018 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 package export.
     6  //
     7  // The indexed export data format is an evolution of the previous
     8  // binary export data format. Its chief contribution is introducing an
     9  // index table, which allows efficient random access of individual
    10  // declarations and inline function bodies. In turn, this allows
    11  // avoiding unnecessary work for compilation units that import large
    12  // packages.
    13  //
    14  //
    15  // The top-level data format is structured as:
    16  //
    17  //     Header struct {
    18  //         Tag        byte   // 'i'
    19  //         Version    uvarint
    20  //         StringSize uvarint
    21  //         DataSize   uvarint
    22  //     }
    23  //
    24  //     Strings [StringSize]byte
    25  //     Data    [DataSize]byte
    26  //
    27  //     MainIndex []struct{
    28  //         PkgPath   stringOff
    29  //         PkgName   stringOff
    30  //         PkgHeight uvarint
    31  //
    32  //         Decls []struct{
    33  //             Name   stringOff
    34  //             Offset declOff
    35  //         }
    36  //     }
    37  //
    38  //     Fingerprint [8]byte
    39  //
    40  // uvarint means a uint64 written out using uvarint encoding.
    41  //
    42  // []T means a uvarint followed by that many T objects. In other
    43  // words:
    44  //
    45  //     Len   uvarint
    46  //     Elems [Len]T
    47  //
    48  // stringOff means a uvarint that indicates an offset within the
    49  // Strings section. At that offset is another uvarint, followed by
    50  // that many bytes, which form the string value.
    51  //
    52  // declOff means a uvarint that indicates an offset within the Data
    53  // section where the associated declaration can be found.
    54  //
    55  //
    56  // There are five kinds of declarations, distinguished by their first
    57  // byte:
    58  //
    59  //     type Var struct {
    60  //         Tag  byte // 'V'
    61  //         Pos  Pos
    62  //         Type typeOff
    63  //     }
    64  //
    65  //     type Func struct {
    66  //         Tag       byte // 'F'
    67  //         Pos       Pos
    68  //         Signature Signature
    69  //     }
    70  //
    71  //     type Const struct {
    72  //         Tag   byte // 'C'
    73  //         Pos   Pos
    74  //         Value Value
    75  //     }
    76  //
    77  //     type Type struct {
    78  //         Tag        byte // 'T'
    79  //         Pos        Pos
    80  //         Underlying typeOff
    81  //
    82  //         Methods []struct{  // omitted if Underlying is an interface type
    83  //             Pos       Pos
    84  //             Name      stringOff
    85  //             Recv      Param
    86  //             Signature Signature
    87  //         }
    88  //     }
    89  //
    90  //     type Alias struct {
    91  //         Tag  byte // 'A'
    92  //         Pos  Pos
    93  //         Type typeOff
    94  //     }
    95  //
    96  //
    97  // typeOff means a uvarint that either indicates a predeclared type,
    98  // or an offset into the Data section. If the uvarint is less than
    99  // predeclReserved, then it indicates the index into the predeclared
   100  // types list (see predeclared in bexport.go for order). Otherwise,
   101  // subtracting predeclReserved yields the offset of a type descriptor.
   102  //
   103  // Value means a type and type-specific value. See
   104  // (*exportWriter).value for details.
   105  //
   106  //
   107  // There are nine kinds of type descriptors, distinguished by an itag:
   108  //
   109  //     type DefinedType struct {
   110  //         Tag     itag // definedType
   111  //         Name    stringOff
   112  //         PkgPath stringOff
   113  //     }
   114  //
   115  //     type PointerType struct {
   116  //         Tag  itag // pointerType
   117  //         Elem typeOff
   118  //     }
   119  //
   120  //     type SliceType struct {
   121  //         Tag  itag // sliceType
   122  //         Elem typeOff
   123  //     }
   124  //
   125  //     type ArrayType struct {
   126  //         Tag  itag // arrayType
   127  //         Len  uint64
   128  //         Elem typeOff
   129  //     }
   130  //
   131  //     type ChanType struct {
   132  //         Tag  itag   // chanType
   133  //         Dir  uint64 // 1 RecvOnly; 2 SendOnly; 3 SendRecv
   134  //         Elem typeOff
   135  //     }
   136  //
   137  //     type MapType struct {
   138  //         Tag  itag // mapType
   139  //         Key  typeOff
   140  //         Elem typeOff
   141  //     }
   142  //
   143  //     type FuncType struct {
   144  //         Tag       itag // signatureType
   145  //         PkgPath   stringOff
   146  //         Signature Signature
   147  //     }
   148  //
   149  //     type StructType struct {
   150  //         Tag     itag // structType
   151  //         PkgPath stringOff
   152  //         Fields []struct {
   153  //             Pos      Pos
   154  //             Name     stringOff
   155  //             Type     typeOff
   156  //             Embedded bool
   157  //             Note     stringOff
   158  //         }
   159  //     }
   160  //
   161  //     type InterfaceType struct {
   162  //         Tag     itag // interfaceType
   163  //         PkgPath stringOff
   164  //         Embeddeds []struct {
   165  //             Pos  Pos
   166  //             Type typeOff
   167  //         }
   168  //         Methods []struct {
   169  //             Pos       Pos
   170  //             Name      stringOff
   171  //             Signature Signature
   172  //         }
   173  //     }
   174  //
   175  //
   176  //     type Signature struct {
   177  //         Params   []Param
   178  //         Results  []Param
   179  //         Variadic bool  // omitted if Results is empty
   180  //     }
   181  //
   182  //     type Param struct {
   183  //         Pos  Pos
   184  //         Name stringOff
   185  //         Type typOff
   186  //     }
   187  //
   188  //
   189  // Pos encodes a file:line:column triple, incorporating a simple delta
   190  // encoding scheme within a data object. See exportWriter.pos for
   191  // details.
   192  //
   193  //
   194  // Compiler-specific details.
   195  //
   196  // cmd/compile writes out a second index for inline bodies and also
   197  // appends additional compiler-specific details after declarations.
   198  // Third-party tools are not expected to depend on these details and
   199  // they're expected to change much more rapidly, so they're omitted
   200  // here. See exportWriter's varExt/funcExt/etc methods for details.
   201  
   202  package typecheck
   203  
   204  import (
   205  	"bufio"
   206  	"bytes"
   207  	"crypto/md5"
   208  	"encoding/binary"
   209  	"fmt"
   210  	"go/constant"
   211  	"io"
   212  	"math/big"
   213  	"sort"
   214  	"strings"
   215  
   216  	"cmd/compile/internal/base"
   217  	"cmd/compile/internal/ir"
   218  	"cmd/compile/internal/types"
   219  	"cmd/internal/goobj"
   220  	"cmd/internal/src"
   221  )
   222  
   223  // Current indexed export format version. Increase with each format change.
   224  // 1: added column details to Pos
   225  // 0: Go1.11 encoding
   226  const iexportVersion = 1
   227  
   228  // predeclReserved is the number of type offsets reserved for types
   229  // implicitly declared in the universe block.
   230  const predeclReserved = 32
   231  
   232  // An itag distinguishes the kind of type that was written into the
   233  // indexed export format.
   234  type itag uint64
   235  
   236  const (
   237  	// Types
   238  	definedType itag = iota
   239  	pointerType
   240  	sliceType
   241  	arrayType
   242  	chanType
   243  	mapType
   244  	signatureType
   245  	structType
   246  	interfaceType
   247  )
   248  
   249  const (
   250  	debug = false
   251  	magic = 0x6742937dc293105
   252  )
   253  
   254  func WriteExports(out *bufio.Writer) {
   255  	p := iexporter{
   256  		allPkgs:     map[*types.Pkg]bool{},
   257  		stringIndex: map[string]uint64{},
   258  		declIndex:   map[*types.Sym]uint64{},
   259  		inlineIndex: map[*types.Sym]uint64{},
   260  		typIndex:    map[*types.Type]uint64{},
   261  	}
   262  
   263  	for i, pt := range predeclared() {
   264  		p.typIndex[pt] = uint64(i)
   265  	}
   266  	if len(p.typIndex) > predeclReserved {
   267  		base.Fatalf("too many predeclared types: %d > %d", len(p.typIndex), predeclReserved)
   268  	}
   269  
   270  	// Initialize work queue with exported declarations.
   271  	for _, n := range Target.Exports {
   272  		p.pushDecl(n)
   273  	}
   274  
   275  	// Loop until no more work. We use a queue because while
   276  	// writing out inline bodies, we may discover additional
   277  	// declarations that are needed.
   278  	for !p.declTodo.Empty() {
   279  		p.doDecl(p.declTodo.PopLeft())
   280  	}
   281  
   282  	// Append indices to data0 section.
   283  	dataLen := uint64(p.data0.Len())
   284  	w := p.newWriter()
   285  	w.writeIndex(p.declIndex, true)
   286  	w.writeIndex(p.inlineIndex, false)
   287  	w.flush()
   288  
   289  	if *base.Flag.LowerV {
   290  		fmt.Printf("export: hdr strings %v, data %v, index %v\n", p.strings.Len(), dataLen, p.data0.Len())
   291  	}
   292  
   293  	// Assemble header.
   294  	var hdr intWriter
   295  	hdr.WriteByte('i')
   296  	hdr.uint64(iexportVersion)
   297  	hdr.uint64(uint64(p.strings.Len()))
   298  	hdr.uint64(dataLen)
   299  
   300  	// Flush output.
   301  	h := md5.New()
   302  	wr := io.MultiWriter(out, h)
   303  	io.Copy(wr, &hdr)
   304  	io.Copy(wr, &p.strings)
   305  	io.Copy(wr, &p.data0)
   306  
   307  	// Add fingerprint (used by linker object file).
   308  	// Attach this to the end, so tools (e.g. gcimporter) don't care.
   309  	copy(base.Ctxt.Fingerprint[:], h.Sum(nil)[:])
   310  	out.Write(base.Ctxt.Fingerprint[:])
   311  }
   312  
   313  // writeIndex writes out a symbol index. mainIndex indicates whether
   314  // we're writing out the main index, which is also read by
   315  // non-compiler tools and includes a complete package description
   316  // (i.e., name and height).
   317  func (w *exportWriter) writeIndex(index map[*types.Sym]uint64, mainIndex bool) {
   318  	// Build a map from packages to symbols from that package.
   319  	pkgSyms := map[*types.Pkg][]*types.Sym{}
   320  
   321  	// For the main index, make sure to include every package that
   322  	// we reference, even if we're not exporting (or reexporting)
   323  	// any symbols from it.
   324  	if mainIndex {
   325  		pkgSyms[types.LocalPkg] = nil
   326  		for pkg := range w.p.allPkgs {
   327  			pkgSyms[pkg] = nil
   328  		}
   329  	}
   330  
   331  	// Group symbols by package.
   332  	for sym := range index {
   333  		pkgSyms[sym.Pkg] = append(pkgSyms[sym.Pkg], sym)
   334  	}
   335  
   336  	// Sort packages by path.
   337  	var pkgs []*types.Pkg
   338  	for pkg := range pkgSyms {
   339  		pkgs = append(pkgs, pkg)
   340  	}
   341  	sort.Slice(pkgs, func(i, j int) bool {
   342  		return pkgs[i].Path < pkgs[j].Path
   343  	})
   344  
   345  	w.uint64(uint64(len(pkgs)))
   346  	for _, pkg := range pkgs {
   347  		w.string(pkg.Path)
   348  		if mainIndex {
   349  			w.string(pkg.Name)
   350  			w.uint64(uint64(pkg.Height))
   351  		}
   352  
   353  		// Sort symbols within a package by name.
   354  		syms := pkgSyms[pkg]
   355  		sort.Slice(syms, func(i, j int) bool {
   356  			return syms[i].Name < syms[j].Name
   357  		})
   358  
   359  		w.uint64(uint64(len(syms)))
   360  		for _, sym := range syms {
   361  			w.string(sym.Name)
   362  			w.uint64(index[sym])
   363  		}
   364  	}
   365  }
   366  
   367  type iexporter struct {
   368  	// allPkgs tracks all packages that have been referenced by
   369  	// the export data, so we can ensure to include them in the
   370  	// main index.
   371  	allPkgs map[*types.Pkg]bool
   372  
   373  	declTodo ir.NameQueue
   374  
   375  	strings     intWriter
   376  	stringIndex map[string]uint64
   377  
   378  	data0       intWriter
   379  	declIndex   map[*types.Sym]uint64
   380  	inlineIndex map[*types.Sym]uint64
   381  	typIndex    map[*types.Type]uint64
   382  }
   383  
   384  // stringOff returns the offset of s within the string section.
   385  // If not already present, it's added to the end.
   386  func (p *iexporter) stringOff(s string) uint64 {
   387  	off, ok := p.stringIndex[s]
   388  	if !ok {
   389  		off = uint64(p.strings.Len())
   390  		p.stringIndex[s] = off
   391  
   392  		if *base.Flag.LowerV {
   393  			fmt.Printf("export: str %v %.40q\n", off, s)
   394  		}
   395  
   396  		p.strings.uint64(uint64(len(s)))
   397  		p.strings.WriteString(s)
   398  	}
   399  	return off
   400  }
   401  
   402  // pushDecl adds n to the declaration work queue, if not already present.
   403  func (p *iexporter) pushDecl(n *ir.Name) {
   404  	if n.Sym() == nil || n.Sym().Def != n && n.Op() != ir.OTYPE {
   405  		base.Fatalf("weird Sym: %v, %v", n, n.Sym())
   406  	}
   407  
   408  	// Don't export predeclared declarations.
   409  	if n.Sym().Pkg == types.BuiltinPkg || n.Sym().Pkg == ir.Pkgs.Unsafe {
   410  		return
   411  	}
   412  
   413  	if _, ok := p.declIndex[n.Sym()]; ok {
   414  		return
   415  	}
   416  
   417  	p.declIndex[n.Sym()] = ^uint64(0) // mark n present in work queue
   418  	p.declTodo.PushRight(n)
   419  }
   420  
   421  // exportWriter handles writing out individual data section chunks.
   422  type exportWriter struct {
   423  	p *iexporter
   424  
   425  	data       intWriter
   426  	currPkg    *types.Pkg
   427  	prevFile   string
   428  	prevLine   int64
   429  	prevColumn int64
   430  
   431  	// dclIndex maps function-scoped declarations to an int used to refer to
   432  	// them later in the function. For local variables/params, the int is
   433  	// non-negative and in order of the appearance in the Func's Dcl list. For
   434  	// closure variables, the index is negative starting at -2.
   435  	dclIndex           map[*ir.Name]int
   436  	maxDclIndex        int
   437  	maxClosureVarIndex int
   438  }
   439  
   440  func (p *iexporter) doDecl(n *ir.Name) {
   441  	w := p.newWriter()
   442  	w.setPkg(n.Sym().Pkg, false)
   443  
   444  	switch n.Op() {
   445  	case ir.ONAME:
   446  		switch n.Class {
   447  		case ir.PEXTERN:
   448  			// Variable.
   449  			w.tag('V')
   450  			w.pos(n.Pos())
   451  			w.typ(n.Type())
   452  			w.varExt(n)
   453  
   454  		case ir.PFUNC:
   455  			if ir.IsMethod(n) {
   456  				base.Fatalf("unexpected method: %v", n)
   457  			}
   458  
   459  			// Function.
   460  			w.tag('F')
   461  			w.pos(n.Pos())
   462  			w.signature(n.Type())
   463  			w.funcExt(n)
   464  
   465  		default:
   466  			base.Fatalf("unexpected class: %v, %v", n, n.Class)
   467  		}
   468  
   469  	case ir.OLITERAL:
   470  		// TODO(mdempsky): Extend check to all declarations.
   471  		if n.Typecheck() == 0 {
   472  			base.FatalfAt(n.Pos(), "missed typecheck: %v", n)
   473  		}
   474  
   475  		// Constant.
   476  		w.tag('C')
   477  		w.pos(n.Pos())
   478  		w.value(n.Type(), n.Val())
   479  		w.constExt(n)
   480  
   481  	case ir.OTYPE:
   482  		if types.IsDotAlias(n.Sym()) {
   483  			// Alias.
   484  			w.tag('A')
   485  			w.pos(n.Pos())
   486  			w.typ(n.Type())
   487  			break
   488  		}
   489  
   490  		// Defined type.
   491  		w.tag('T')
   492  		w.pos(n.Pos())
   493  
   494  		underlying := n.Type().Underlying()
   495  		if underlying == types.ErrorType.Underlying() {
   496  			// For "type T error", use error as the
   497  			// underlying type instead of error's own
   498  			// underlying anonymous interface. This
   499  			// ensures consistency with how importers may
   500  			// declare error (e.g., go/types uses nil Pkg
   501  			// for predeclared objects).
   502  			underlying = types.ErrorType
   503  		}
   504  		w.typ(underlying)
   505  
   506  		t := n.Type()
   507  		if t.IsInterface() {
   508  			w.typeExt(t)
   509  			break
   510  		}
   511  
   512  		ms := t.Methods()
   513  		w.uint64(uint64(ms.Len()))
   514  		for _, m := range ms.Slice() {
   515  			w.pos(m.Pos)
   516  			w.selector(m.Sym)
   517  			w.param(m.Type.Recv())
   518  			w.signature(m.Type)
   519  		}
   520  
   521  		w.typeExt(t)
   522  		for _, m := range ms.Slice() {
   523  			w.methExt(m)
   524  		}
   525  
   526  	default:
   527  		base.Fatalf("unexpected node: %v", n)
   528  	}
   529  
   530  	w.finish("dcl", p.declIndex, n.Sym())
   531  }
   532  
   533  func (w *exportWriter) tag(tag byte) {
   534  	w.data.WriteByte(tag)
   535  }
   536  
   537  func (w *exportWriter) finish(what string, index map[*types.Sym]uint64, sym *types.Sym) {
   538  	off := w.flush()
   539  	if *base.Flag.LowerV {
   540  		fmt.Printf("export: %v %v %v\n", what, off, sym)
   541  	}
   542  	index[sym] = off
   543  }
   544  
   545  func (p *iexporter) doInline(f *ir.Name) {
   546  	w := p.newWriter()
   547  	w.setPkg(fnpkg(f), false)
   548  
   549  	w.dclIndex = make(map[*ir.Name]int, len(f.Func.Inl.Dcl))
   550  	w.funcBody(f.Func)
   551  
   552  	w.finish("inl", p.inlineIndex, f.Sym())
   553  }
   554  
   555  func (w *exportWriter) pos(pos src.XPos) {
   556  	p := base.Ctxt.PosTable.Pos(pos)
   557  	file := p.Base().AbsFilename()
   558  	line := int64(p.RelLine())
   559  	column := int64(p.RelCol())
   560  
   561  	// Encode position relative to the last position: column
   562  	// delta, then line delta, then file name. We reserve the
   563  	// bottom bit of the column and line deltas to encode whether
   564  	// the remaining fields are present.
   565  	//
   566  	// Note: Because data objects may be read out of order (or not
   567  	// at all), we can only apply delta encoding within a single
   568  	// object. This is handled implicitly by tracking prevFile,
   569  	// prevLine, and prevColumn as fields of exportWriter.
   570  
   571  	deltaColumn := (column - w.prevColumn) << 1
   572  	deltaLine := (line - w.prevLine) << 1
   573  
   574  	if file != w.prevFile {
   575  		deltaLine |= 1
   576  	}
   577  	if deltaLine != 0 {
   578  		deltaColumn |= 1
   579  	}
   580  
   581  	w.int64(deltaColumn)
   582  	if deltaColumn&1 != 0 {
   583  		w.int64(deltaLine)
   584  		if deltaLine&1 != 0 {
   585  			w.string(file)
   586  		}
   587  	}
   588  
   589  	w.prevFile = file
   590  	w.prevLine = line
   591  	w.prevColumn = column
   592  }
   593  
   594  func (w *exportWriter) pkg(pkg *types.Pkg) {
   595  	// TODO(mdempsky): Add flag to types.Pkg to mark pseudo-packages.
   596  	if pkg == ir.Pkgs.Go {
   597  		base.Fatalf("export of pseudo-package: %q", pkg.Path)
   598  	}
   599  
   600  	// Ensure any referenced packages are declared in the main index.
   601  	w.p.allPkgs[pkg] = true
   602  
   603  	w.string(pkg.Path)
   604  }
   605  
   606  func (w *exportWriter) qualifiedIdent(n *ir.Name) {
   607  	// Ensure any referenced declarations are written out too.
   608  	w.p.pushDecl(n)
   609  
   610  	s := n.Sym()
   611  	w.string(s.Name)
   612  	w.pkg(s.Pkg)
   613  }
   614  
   615  func (w *exportWriter) selector(s *types.Sym) {
   616  	if w.currPkg == nil {
   617  		base.Fatalf("missing currPkg")
   618  	}
   619  
   620  	// If the selector being written is unexported, it comes with a package qualifier.
   621  	// If the selector being written is exported, it is not package-qualified.
   622  	// See the spec: https://golang.org/ref/spec#Uniqueness_of_identifiers
   623  	// As an optimization, we don't actually write the package every time - instead we
   624  	// call setPkg before a group of selectors (all of which must have the same package qualifier).
   625  	pkg := w.currPkg
   626  	if types.IsExported(s.Name) {
   627  		pkg = types.LocalPkg
   628  	}
   629  	if s.Pkg != pkg {
   630  		base.Fatalf("package mismatch in selector: %v in package %q, but want %q", s, s.Pkg.Path, pkg.Path)
   631  	}
   632  
   633  	w.string(s.Name)
   634  }
   635  
   636  func (w *exportWriter) typ(t *types.Type) {
   637  	w.data.uint64(w.p.typOff(t))
   638  }
   639  
   640  // The "exotic" functions in this section encode a wider range of
   641  // items than the standard encoding functions above. These include
   642  // types that do not appear in declarations, only in code, such as
   643  // method types. These methods need to be separate from the standard
   644  // encoding functions because we don't want to modify the encoding
   645  // generated by the standard functions (because that exported
   646  // information is read by tools besides the compiler).
   647  
   648  // exoticType exports a type to the writer.
   649  func (w *exportWriter) exoticType(t *types.Type) {
   650  	switch {
   651  	case t == nil:
   652  		// Calls-as-statements have no type.
   653  		w.data.uint64(exoticTypeNil)
   654  	case t.IsStruct() && t.StructType().Funarg != types.FunargNone:
   655  		// These are weird structs for representing tuples of types returned
   656  		// by multi-return functions.
   657  		// They don't fit the standard struct type mold. For instance,
   658  		// they don't have any package info.
   659  		w.data.uint64(exoticTypeTuple)
   660  		w.uint64(uint64(t.StructType().Funarg))
   661  		w.uint64(uint64(t.NumFields()))
   662  		for _, f := range t.FieldSlice() {
   663  			w.pos(f.Pos)
   664  			s := f.Sym
   665  			if s == nil {
   666  				w.uint64(0)
   667  			} else if s.Pkg == nil {
   668  				w.uint64(exoticTypeSymNoPkg)
   669  				w.string(s.Name)
   670  			} else {
   671  				w.uint64(exoticTypeSymWithPkg)
   672  				w.pkg(s.Pkg)
   673  				w.string(s.Name)
   674  			}
   675  			w.typ(f.Type)
   676  			if f.Embedded != 0 || f.Note != "" {
   677  				panic("extra info in funarg struct field")
   678  			}
   679  		}
   680  	case t.Kind() == types.TFUNC && t.Recv() != nil:
   681  		w.data.uint64(exoticTypeRecv)
   682  		// interface method types have a fake receiver type.
   683  		isFakeRecv := t.Recv().Type == types.FakeRecvType()
   684  		w.bool(isFakeRecv)
   685  		if !isFakeRecv {
   686  			w.exoticParam(t.Recv())
   687  		}
   688  		w.exoticSignature(t)
   689  
   690  	default:
   691  		// A regular type.
   692  		w.data.uint64(exoticTypeRegular)
   693  		w.typ(t)
   694  	}
   695  }
   696  
   697  const (
   698  	exoticTypeNil = iota
   699  	exoticTypeTuple
   700  	exoticTypeRecv
   701  	exoticTypeRegular
   702  )
   703  const (
   704  	exoticTypeSymNil = iota
   705  	exoticTypeSymNoPkg
   706  	exoticTypeSymWithPkg
   707  )
   708  
   709  // Export a selector, but one whose package may not match
   710  // the package being compiled. This is a separate function
   711  // because the standard selector() serialization format is fixed
   712  // by the go/types reader. This one can only be used during
   713  // inline/generic body exporting.
   714  func (w *exportWriter) exoticSelector(s *types.Sym) {
   715  	pkg := w.currPkg
   716  	if types.IsExported(s.Name) {
   717  		pkg = types.LocalPkg
   718  	}
   719  
   720  	w.string(s.Name)
   721  	if s.Pkg == pkg {
   722  		w.uint64(0)
   723  	} else {
   724  		w.uint64(1)
   725  		w.pkg(s.Pkg)
   726  	}
   727  }
   728  
   729  func (w *exportWriter) exoticSignature(t *types.Type) {
   730  	hasPkg := t.Pkg() != nil
   731  	w.bool(hasPkg)
   732  	if hasPkg {
   733  		w.pkg(t.Pkg())
   734  	}
   735  	w.exoticParamList(t.Params().FieldSlice())
   736  	w.exoticParamList(t.Results().FieldSlice())
   737  }
   738  
   739  func (w *exportWriter) exoticParamList(fs []*types.Field) {
   740  	w.uint64(uint64(len(fs)))
   741  	for _, f := range fs {
   742  		w.exoticParam(f)
   743  	}
   744  
   745  }
   746  func (w *exportWriter) exoticParam(f *types.Field) {
   747  	w.pos(f.Pos)
   748  	w.exoticSym(f.Sym)
   749  	w.uint64(uint64(f.Offset))
   750  	w.exoticType(f.Type)
   751  	w.bool(f.IsDDD())
   752  }
   753  
   754  func (w *exportWriter) exoticField(f *types.Field) {
   755  	w.pos(f.Pos)
   756  	w.exoticSym(f.Sym)
   757  	w.uint64(uint64(f.Offset))
   758  	w.exoticType(f.Type)
   759  	w.string(f.Note)
   760  }
   761  
   762  func (w *exportWriter) exoticSym(s *types.Sym) {
   763  	if s == nil {
   764  		w.string("")
   765  		return
   766  	}
   767  	if s.Name == "" {
   768  		base.Fatalf("empty symbol name")
   769  	}
   770  	w.string(s.Name)
   771  	if !types.IsExported(s.Name) {
   772  		w.pkg(s.Pkg)
   773  	}
   774  }
   775  
   776  func (p *iexporter) newWriter() *exportWriter {
   777  	return &exportWriter{p: p}
   778  }
   779  
   780  func (w *exportWriter) flush() uint64 {
   781  	off := uint64(w.p.data0.Len())
   782  	io.Copy(&w.p.data0, &w.data)
   783  	return off
   784  }
   785  
   786  func (p *iexporter) typOff(t *types.Type) uint64 {
   787  	off, ok := p.typIndex[t]
   788  	if !ok {
   789  		w := p.newWriter()
   790  		w.doTyp(t)
   791  		rawOff := w.flush()
   792  		if *base.Flag.LowerV {
   793  			fmt.Printf("export: typ %v %v\n", rawOff, t)
   794  		}
   795  		off = predeclReserved + rawOff
   796  		p.typIndex[t] = off
   797  	}
   798  	return off
   799  }
   800  
   801  func (w *exportWriter) startType(k itag) {
   802  	w.data.uint64(uint64(k))
   803  }
   804  
   805  func (w *exportWriter) doTyp(t *types.Type) {
   806  	if t.Sym() != nil {
   807  		if t.Sym().Pkg == types.BuiltinPkg || t.Sym().Pkg == ir.Pkgs.Unsafe {
   808  			base.Fatalf("builtin type missing from typIndex: %v", t)
   809  		}
   810  
   811  		w.startType(definedType)
   812  		w.qualifiedIdent(t.Obj().(*ir.Name))
   813  		return
   814  	}
   815  
   816  	switch t.Kind() {
   817  	case types.TPTR:
   818  		w.startType(pointerType)
   819  		w.typ(t.Elem())
   820  
   821  	case types.TSLICE:
   822  		w.startType(sliceType)
   823  		w.typ(t.Elem())
   824  
   825  	case types.TARRAY:
   826  		w.startType(arrayType)
   827  		w.uint64(uint64(t.NumElem()))
   828  		w.typ(t.Elem())
   829  
   830  	case types.TCHAN:
   831  		w.startType(chanType)
   832  		w.uint64(uint64(t.ChanDir()))
   833  		w.typ(t.Elem())
   834  
   835  	case types.TMAP:
   836  		w.startType(mapType)
   837  		w.typ(t.Key())
   838  		w.typ(t.Elem())
   839  
   840  	case types.TFUNC:
   841  		w.startType(signatureType)
   842  		w.setPkg(t.Pkg(), true)
   843  		w.signature(t)
   844  
   845  	case types.TSTRUCT:
   846  		w.startType(structType)
   847  		w.setPkg(t.Pkg(), true)
   848  
   849  		w.uint64(uint64(t.NumFields()))
   850  		for _, f := range t.FieldSlice() {
   851  			w.pos(f.Pos)
   852  			w.selector(f.Sym)
   853  			w.typ(f.Type)
   854  			w.bool(f.Embedded != 0)
   855  			w.string(f.Note)
   856  		}
   857  
   858  	case types.TINTER:
   859  		var embeddeds, methods []*types.Field
   860  		for _, m := range t.Methods().Slice() {
   861  			if m.Sym != nil {
   862  				methods = append(methods, m)
   863  			} else {
   864  				embeddeds = append(embeddeds, m)
   865  			}
   866  		}
   867  
   868  		w.startType(interfaceType)
   869  		w.setPkg(t.Pkg(), true)
   870  
   871  		w.uint64(uint64(len(embeddeds)))
   872  		for _, f := range embeddeds {
   873  			w.pos(f.Pos)
   874  			w.typ(f.Type)
   875  		}
   876  
   877  		w.uint64(uint64(len(methods)))
   878  		for _, f := range methods {
   879  			w.pos(f.Pos)
   880  			w.selector(f.Sym)
   881  			w.signature(f.Type)
   882  		}
   883  
   884  	default:
   885  		base.Fatalf("unexpected type: %v", t)
   886  	}
   887  }
   888  
   889  func (w *exportWriter) setPkg(pkg *types.Pkg, write bool) {
   890  	if pkg == types.NoPkg {
   891  		base.Fatalf("missing pkg")
   892  	}
   893  
   894  	if write {
   895  		w.pkg(pkg)
   896  	}
   897  
   898  	w.currPkg = pkg
   899  }
   900  
   901  func (w *exportWriter) signature(t *types.Type) {
   902  	w.paramList(t.Params().FieldSlice())
   903  	w.paramList(t.Results().FieldSlice())
   904  	if n := t.Params().NumFields(); n > 0 {
   905  		w.bool(t.Params().Field(n - 1).IsDDD())
   906  	}
   907  }
   908  
   909  func (w *exportWriter) paramList(fs []*types.Field) {
   910  	w.uint64(uint64(len(fs)))
   911  	for _, f := range fs {
   912  		w.param(f)
   913  	}
   914  }
   915  
   916  func (w *exportWriter) param(f *types.Field) {
   917  	w.pos(f.Pos)
   918  	w.localIdent(types.OrigSym(f.Sym))
   919  	w.typ(f.Type)
   920  }
   921  
   922  func constTypeOf(typ *types.Type) constant.Kind {
   923  	switch typ {
   924  	case types.UntypedInt, types.UntypedRune:
   925  		return constant.Int
   926  	case types.UntypedFloat:
   927  		return constant.Float
   928  	case types.UntypedComplex:
   929  		return constant.Complex
   930  	}
   931  
   932  	switch typ.Kind() {
   933  	case types.TBOOL:
   934  		return constant.Bool
   935  	case types.TSTRING:
   936  		return constant.String
   937  	case types.TINT, types.TINT8, types.TINT16, types.TINT32, types.TINT64,
   938  		types.TUINT, types.TUINT8, types.TUINT16, types.TUINT32, types.TUINT64, types.TUINTPTR:
   939  		return constant.Int
   940  	case types.TFLOAT32, types.TFLOAT64:
   941  		return constant.Float
   942  	case types.TCOMPLEX64, types.TCOMPLEX128:
   943  		return constant.Complex
   944  	}
   945  
   946  	base.Fatalf("unexpected constant type: %v", typ)
   947  	return 0
   948  }
   949  
   950  func (w *exportWriter) value(typ *types.Type, v constant.Value) {
   951  	ir.AssertValidTypeForConst(typ, v)
   952  	w.typ(typ)
   953  
   954  	// Each type has only one admissible constant representation,
   955  	// so we could type switch directly on v.U here. However,
   956  	// switching on the type increases symmetry with import logic
   957  	// and provides a useful consistency check.
   958  
   959  	switch constTypeOf(typ) {
   960  	case constant.Bool:
   961  		w.bool(constant.BoolVal(v))
   962  	case constant.String:
   963  		w.string(constant.StringVal(v))
   964  	case constant.Int:
   965  		w.mpint(v, typ)
   966  	case constant.Float:
   967  		w.mpfloat(v, typ)
   968  	case constant.Complex:
   969  		w.mpfloat(constant.Real(v), typ)
   970  		w.mpfloat(constant.Imag(v), typ)
   971  	}
   972  }
   973  
   974  func intSize(typ *types.Type) (signed bool, maxBytes uint) {
   975  	if typ.IsUntyped() {
   976  		return true, ir.ConstPrec / 8
   977  	}
   978  
   979  	switch typ.Kind() {
   980  	case types.TFLOAT32, types.TCOMPLEX64:
   981  		return true, 3
   982  	case types.TFLOAT64, types.TCOMPLEX128:
   983  		return true, 7
   984  	}
   985  
   986  	signed = typ.IsSigned()
   987  	maxBytes = uint(typ.Size())
   988  
   989  	// The go/types API doesn't expose sizes to importers, so they
   990  	// don't know how big these types are.
   991  	switch typ.Kind() {
   992  	case types.TINT, types.TUINT, types.TUINTPTR:
   993  		maxBytes = 8
   994  	}
   995  
   996  	return
   997  }
   998  
   999  // mpint exports a multi-precision integer.
  1000  //
  1001  // For unsigned types, small values are written out as a single
  1002  // byte. Larger values are written out as a length-prefixed big-endian
  1003  // byte string, where the length prefix is encoded as its complement.
  1004  // For example, bytes 0, 1, and 2 directly represent the integer
  1005  // values 0, 1, and 2; while bytes 255, 254, and 253 indicate a 1-,
  1006  // 2-, and 3-byte big-endian string follow.
  1007  //
  1008  // Encoding for signed types use the same general approach as for
  1009  // unsigned types, except small values use zig-zag encoding and the
  1010  // bottom bit of length prefix byte for large values is reserved as a
  1011  // sign bit.
  1012  //
  1013  // The exact boundary between small and large encodings varies
  1014  // according to the maximum number of bytes needed to encode a value
  1015  // of type typ. As a special case, 8-bit types are always encoded as a
  1016  // single byte.
  1017  func (w *exportWriter) mpint(x constant.Value, typ *types.Type) {
  1018  	signed, maxBytes := intSize(typ)
  1019  
  1020  	negative := constant.Sign(x) < 0
  1021  	if !signed && negative {
  1022  		base.Fatalf("negative unsigned integer; type %v, value %v", typ, x)
  1023  	}
  1024  
  1025  	b := constant.Bytes(x) // little endian
  1026  	for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 {
  1027  		b[i], b[j] = b[j], b[i]
  1028  	}
  1029  
  1030  	if len(b) > 0 && b[0] == 0 {
  1031  		base.Fatalf("leading zeros")
  1032  	}
  1033  	if uint(len(b)) > maxBytes {
  1034  		base.Fatalf("bad mpint length: %d > %d (type %v, value %v)", len(b), maxBytes, typ, x)
  1035  	}
  1036  
  1037  	maxSmall := 256 - maxBytes
  1038  	if signed {
  1039  		maxSmall = 256 - 2*maxBytes
  1040  	}
  1041  	if maxBytes == 1 {
  1042  		maxSmall = 256
  1043  	}
  1044  
  1045  	// Check if x can use small value encoding.
  1046  	if len(b) <= 1 {
  1047  		var ux uint
  1048  		if len(b) == 1 {
  1049  			ux = uint(b[0])
  1050  		}
  1051  		if signed {
  1052  			ux <<= 1
  1053  			if negative {
  1054  				ux--
  1055  			}
  1056  		}
  1057  		if ux < maxSmall {
  1058  			w.data.WriteByte(byte(ux))
  1059  			return
  1060  		}
  1061  	}
  1062  
  1063  	n := 256 - uint(len(b))
  1064  	if signed {
  1065  		n = 256 - 2*uint(len(b))
  1066  		if negative {
  1067  			n |= 1
  1068  		}
  1069  	}
  1070  	if n < maxSmall || n >= 256 {
  1071  		base.Fatalf("encoding mistake: %d, %v, %v => %d", len(b), signed, negative, n)
  1072  	}
  1073  
  1074  	w.data.WriteByte(byte(n))
  1075  	w.data.Write(b)
  1076  }
  1077  
  1078  // mpfloat exports a multi-precision floating point number.
  1079  //
  1080  // The number's value is decomposed into mantissa × 2**exponent, where
  1081  // mantissa is an integer. The value is written out as mantissa (as a
  1082  // multi-precision integer) and then the exponent, except exponent is
  1083  // omitted if mantissa is zero.
  1084  func (w *exportWriter) mpfloat(v constant.Value, typ *types.Type) {
  1085  	f := ir.BigFloat(v)
  1086  	if f.IsInf() {
  1087  		base.Fatalf("infinite constant")
  1088  	}
  1089  
  1090  	// Break into f = mant × 2**exp, with 0.5 <= mant < 1.
  1091  	var mant big.Float
  1092  	exp := int64(f.MantExp(&mant))
  1093  
  1094  	// Scale so that mant is an integer.
  1095  	prec := mant.MinPrec()
  1096  	mant.SetMantExp(&mant, int(prec))
  1097  	exp -= int64(prec)
  1098  
  1099  	manti, acc := mant.Int(nil)
  1100  	if acc != big.Exact {
  1101  		base.Fatalf("mantissa scaling failed for %f (%s)", f, acc)
  1102  	}
  1103  	w.mpint(constant.Make(manti), typ)
  1104  	if manti.Sign() != 0 {
  1105  		w.int64(exp)
  1106  	}
  1107  }
  1108  
  1109  func (w *exportWriter) mprat(v constant.Value) {
  1110  	r, ok := constant.Val(v).(*big.Rat)
  1111  	if !w.bool(ok) {
  1112  		return
  1113  	}
  1114  	// TODO(mdempsky): Come up with a more efficient binary
  1115  	// encoding before bumping iexportVersion to expose to
  1116  	// gcimporter.
  1117  	w.string(r.String())
  1118  }
  1119  
  1120  func (w *exportWriter) bool(b bool) bool {
  1121  	var x uint64
  1122  	if b {
  1123  		x = 1
  1124  	}
  1125  	w.uint64(x)
  1126  	return b
  1127  }
  1128  
  1129  func (w *exportWriter) int64(x int64)   { w.data.int64(x) }
  1130  func (w *exportWriter) uint64(x uint64) { w.data.uint64(x) }
  1131  func (w *exportWriter) string(s string) { w.uint64(w.p.stringOff(s)) }
  1132  
  1133  // Compiler-specific extensions.
  1134  
  1135  func (w *exportWriter) constExt(n *ir.Name) {
  1136  	// Internally, we now represent untyped float and complex
  1137  	// constants with infinite-precision rational numbers using
  1138  	// go/constant, but the "public" export data format known to
  1139  	// gcimporter only supports 512-bit floating point constants.
  1140  	// In case rationals turn out to be a bad idea and we want to
  1141  	// switch back to fixed-precision constants, for now we
  1142  	// continue writing out the 512-bit truncation in the public
  1143  	// data section, and write the exact, rational constant in the
  1144  	// compiler's extension data. Also, we only need to worry
  1145  	// about exporting rationals for declared constants, because
  1146  	// constants that appear in an expression will already have
  1147  	// been coerced to a concrete, fixed-precision type.
  1148  	//
  1149  	// Eventually, assuming we stick with using rationals, we
  1150  	// should bump iexportVersion to support rationals, and do the
  1151  	// whole gcimporter update song-and-dance.
  1152  	//
  1153  	// TODO(mdempsky): Prepare vocals for that.
  1154  
  1155  	switch n.Type() {
  1156  	case types.UntypedFloat:
  1157  		w.mprat(n.Val())
  1158  	case types.UntypedComplex:
  1159  		v := n.Val()
  1160  		w.mprat(constant.Real(v))
  1161  		w.mprat(constant.Imag(v))
  1162  	}
  1163  }
  1164  
  1165  func (w *exportWriter) varExt(n *ir.Name) {
  1166  	w.linkname(n.Sym())
  1167  	w.symIdx(n.Sym())
  1168  }
  1169  
  1170  func (w *exportWriter) funcExt(n *ir.Name) {
  1171  	w.linkname(n.Sym())
  1172  	w.symIdx(n.Sym())
  1173  
  1174  	// Record definition ABI so cross-ABI calls can be direct.
  1175  	// This is important for the performance of calling some
  1176  	// common functions implemented in assembly (e.g., bytealg).
  1177  	w.uint64(uint64(n.Func.ABI))
  1178  
  1179  	w.uint64(uint64(n.Func.Pragma))
  1180  
  1181  	// Escape analysis.
  1182  	for _, fs := range &types.RecvsParams {
  1183  		for _, f := range fs(n.Type()).FieldSlice() {
  1184  			w.string(f.Note)
  1185  		}
  1186  	}
  1187  
  1188  	// Inline body.
  1189  	if n.Func.Inl != nil {
  1190  		w.uint64(1 + uint64(n.Func.Inl.Cost))
  1191  		if n.Func.ExportInline() {
  1192  			w.p.doInline(n)
  1193  		}
  1194  
  1195  		// Endlineno for inlined function.
  1196  		w.pos(n.Func.Endlineno)
  1197  	} else {
  1198  		w.uint64(0)
  1199  	}
  1200  }
  1201  
  1202  func (w *exportWriter) methExt(m *types.Field) {
  1203  	w.bool(m.Nointerface())
  1204  	w.funcExt(m.Nname.(*ir.Name))
  1205  }
  1206  
  1207  func (w *exportWriter) linkname(s *types.Sym) {
  1208  	w.string(s.Linkname)
  1209  }
  1210  
  1211  func (w *exportWriter) symIdx(s *types.Sym) {
  1212  	lsym := s.Linksym()
  1213  	if lsym.PkgIdx > goobj.PkgIdxSelf || (lsym.PkgIdx == goobj.PkgIdxInvalid && !lsym.Indexed()) || s.Linkname != "" {
  1214  		// Don't export index for non-package symbols, linkname'd symbols,
  1215  		// and symbols without an index. They can only be referenced by
  1216  		// name.
  1217  		w.int64(-1)
  1218  	} else {
  1219  		// For a defined symbol, export its index.
  1220  		// For re-exporting an imported symbol, pass its index through.
  1221  		w.int64(int64(lsym.SymIdx))
  1222  	}
  1223  }
  1224  
  1225  func (w *exportWriter) typeExt(t *types.Type) {
  1226  	// Export whether this type is marked notinheap.
  1227  	w.bool(t.NotInHeap())
  1228  	// For type T, export the index of type descriptor symbols of T and *T.
  1229  	if i, ok := typeSymIdx[t]; ok {
  1230  		w.int64(i[0])
  1231  		w.int64(i[1])
  1232  		return
  1233  	}
  1234  	w.symIdx(types.TypeSym(t))
  1235  	w.symIdx(types.TypeSym(t.PtrTo()))
  1236  }
  1237  
  1238  // Inline bodies.
  1239  
  1240  func (w *exportWriter) writeNames(dcl []*ir.Name) {
  1241  	w.int64(int64(len(dcl)))
  1242  	for i, n := range dcl {
  1243  		w.pos(n.Pos())
  1244  		w.localIdent(n.Sym())
  1245  		w.typ(n.Type())
  1246  		w.dclIndex[n] = w.maxDclIndex + i
  1247  	}
  1248  	w.maxDclIndex += len(dcl)
  1249  }
  1250  
  1251  func (w *exportWriter) funcBody(fn *ir.Func) {
  1252  	//fmt.Printf("Exporting %s\n", fn.Nname.Sym().Name)
  1253  	w.writeNames(fn.Inl.Dcl)
  1254  
  1255  	w.stmtList(fn.Inl.Body)
  1256  }
  1257  
  1258  func (w *exportWriter) stmtList(list []ir.Node) {
  1259  	for _, n := range list {
  1260  		w.node(n)
  1261  	}
  1262  	w.op(ir.OEND)
  1263  }
  1264  
  1265  func (w *exportWriter) node(n ir.Node) {
  1266  	if ir.OpPrec[n.Op()] < 0 {
  1267  		w.stmt(n)
  1268  	} else {
  1269  		w.expr(n)
  1270  	}
  1271  }
  1272  
  1273  // Caution: stmt will emit more than one node for statement nodes n that have a non-empty
  1274  // n.Ninit and where n cannot have a natural init section (such as in "if", "for", etc.).
  1275  func (w *exportWriter) stmt(n ir.Node) {
  1276  	if len(n.Init()) > 0 && !ir.StmtWithInit(n.Op()) {
  1277  		// can't use stmtList here since we don't want the final OEND
  1278  		for _, n := range n.Init() {
  1279  			w.stmt(n)
  1280  		}
  1281  	}
  1282  
  1283  	switch n.Op() {
  1284  	case ir.OBLOCK:
  1285  		// No OBLOCK in export data.
  1286  		// Inline content into this statement list,
  1287  		// like the init list above.
  1288  		// (At the moment neither the parser nor the typechecker
  1289  		// generate OBLOCK nodes except to denote an empty
  1290  		// function body, although that may change.)
  1291  		n := n.(*ir.BlockStmt)
  1292  		for _, n := range n.List {
  1293  			w.stmt(n)
  1294  		}
  1295  
  1296  	case ir.ODCL:
  1297  		n := n.(*ir.Decl)
  1298  		if ir.IsBlank(n.X) {
  1299  			return // blank declarations not useful to importers
  1300  		}
  1301  		w.op(ir.ODCL)
  1302  		w.localName(n.X)
  1303  
  1304  	case ir.OAS:
  1305  		// Don't export "v = <N>" initializing statements, hope they're always
  1306  		// preceded by the DCL which will be re-parsed and typecheck to reproduce
  1307  		// the "v = <N>" again.
  1308  		n := n.(*ir.AssignStmt)
  1309  		if n.Y != nil {
  1310  			w.op(ir.OAS)
  1311  			w.pos(n.Pos())
  1312  			w.expr(n.X)
  1313  			w.expr(n.Y)
  1314  		}
  1315  
  1316  	case ir.OASOP:
  1317  		n := n.(*ir.AssignOpStmt)
  1318  		w.op(ir.OASOP)
  1319  		w.pos(n.Pos())
  1320  		w.op(n.AsOp)
  1321  		w.expr(n.X)
  1322  		if w.bool(!n.IncDec) {
  1323  			w.expr(n.Y)
  1324  		}
  1325  
  1326  	case ir.OAS2, ir.OAS2DOTTYPE, ir.OAS2FUNC, ir.OAS2MAPR, ir.OAS2RECV:
  1327  		n := n.(*ir.AssignListStmt)
  1328  		if go117ExportTypes {
  1329  			w.op(n.Op())
  1330  		} else {
  1331  			w.op(ir.OAS2)
  1332  		}
  1333  		w.pos(n.Pos())
  1334  		w.exprList(n.Lhs)
  1335  		w.exprList(n.Rhs)
  1336  
  1337  	case ir.ORETURN:
  1338  		n := n.(*ir.ReturnStmt)
  1339  		w.op(ir.ORETURN)
  1340  		w.pos(n.Pos())
  1341  		w.exprList(n.Results)
  1342  
  1343  	// case ORETJMP:
  1344  	// 	unreachable - generated by compiler for trampoline routines
  1345  
  1346  	case ir.OGO, ir.ODEFER:
  1347  		n := n.(*ir.GoDeferStmt)
  1348  		w.op(n.Op())
  1349  		w.pos(n.Pos())
  1350  		w.expr(n.Call)
  1351  
  1352  	case ir.OIF:
  1353  		n := n.(*ir.IfStmt)
  1354  		w.op(ir.OIF)
  1355  		w.pos(n.Pos())
  1356  		w.stmtList(n.Init())
  1357  		w.expr(n.Cond)
  1358  		w.stmtList(n.Body)
  1359  		w.stmtList(n.Else)
  1360  
  1361  	case ir.OFOR:
  1362  		n := n.(*ir.ForStmt)
  1363  		w.op(ir.OFOR)
  1364  		w.pos(n.Pos())
  1365  		w.stmtList(n.Init())
  1366  		w.exprsOrNil(n.Cond, n.Post)
  1367  		w.stmtList(n.Body)
  1368  
  1369  	case ir.ORANGE:
  1370  		n := n.(*ir.RangeStmt)
  1371  		w.op(ir.ORANGE)
  1372  		w.pos(n.Pos())
  1373  		w.exprsOrNil(n.Key, n.Value)
  1374  		w.expr(n.X)
  1375  		w.stmtList(n.Body)
  1376  
  1377  	case ir.OSELECT:
  1378  		n := n.(*ir.SelectStmt)
  1379  		w.op(n.Op())
  1380  		w.pos(n.Pos())
  1381  		w.stmtList(n.Init())
  1382  		w.commList(n.Cases)
  1383  
  1384  	case ir.OSWITCH:
  1385  		n := n.(*ir.SwitchStmt)
  1386  		w.op(n.Op())
  1387  		w.pos(n.Pos())
  1388  		w.stmtList(n.Init())
  1389  		w.exprsOrNil(n.Tag, nil)
  1390  		w.caseList(n.Cases, isNamedTypeSwitch(n.Tag))
  1391  
  1392  	// case OCASE:
  1393  	//	handled by caseList
  1394  
  1395  	case ir.OFALL:
  1396  		n := n.(*ir.BranchStmt)
  1397  		w.op(ir.OFALL)
  1398  		w.pos(n.Pos())
  1399  
  1400  	case ir.OBREAK, ir.OCONTINUE, ir.OGOTO, ir.OLABEL:
  1401  		w.op(n.Op())
  1402  		w.pos(n.Pos())
  1403  		label := ""
  1404  		if sym := n.Sym(); sym != nil {
  1405  			label = sym.Name
  1406  		}
  1407  		w.string(label)
  1408  
  1409  	default:
  1410  		base.Fatalf("exporter: CANNOT EXPORT: %v\nPlease notify gri@\n", n.Op())
  1411  	}
  1412  }
  1413  
  1414  func isNamedTypeSwitch(x ir.Node) bool {
  1415  	guard, ok := x.(*ir.TypeSwitchGuard)
  1416  	return ok && guard.Tag != nil
  1417  }
  1418  
  1419  func (w *exportWriter) caseList(cases []*ir.CaseClause, namedTypeSwitch bool) {
  1420  	w.uint64(uint64(len(cases)))
  1421  	for _, cas := range cases {
  1422  		w.pos(cas.Pos())
  1423  		w.stmtList(cas.List)
  1424  		if namedTypeSwitch {
  1425  			w.localName(cas.Var)
  1426  		}
  1427  		w.stmtList(cas.Body)
  1428  	}
  1429  }
  1430  
  1431  func (w *exportWriter) commList(cases []*ir.CommClause) {
  1432  	w.uint64(uint64(len(cases)))
  1433  	for _, cas := range cases {
  1434  		w.pos(cas.Pos())
  1435  		w.node(cas.Comm)
  1436  		w.stmtList(cas.Body)
  1437  	}
  1438  }
  1439  
  1440  func (w *exportWriter) exprList(list ir.Nodes) {
  1441  	for _, n := range list {
  1442  		w.expr(n)
  1443  	}
  1444  	w.op(ir.OEND)
  1445  }
  1446  
  1447  func simplifyForExport(n ir.Node) ir.Node {
  1448  	switch n.Op() {
  1449  	case ir.OPAREN:
  1450  		n := n.(*ir.ParenExpr)
  1451  		return simplifyForExport(n.X)
  1452  	}
  1453  	return n
  1454  }
  1455  
  1456  func (w *exportWriter) expr(n ir.Node) {
  1457  	n = simplifyForExport(n)
  1458  	switch n.Op() {
  1459  	// expressions
  1460  	// (somewhat closely following the structure of exprfmt in fmt.go)
  1461  	case ir.ONIL:
  1462  		n := n.(*ir.NilExpr)
  1463  		if !n.Type().HasNil() {
  1464  			base.Fatalf("unexpected type for nil: %v", n.Type())
  1465  		}
  1466  		w.op(ir.ONIL)
  1467  		w.pos(n.Pos())
  1468  		w.typ(n.Type())
  1469  
  1470  	case ir.OLITERAL:
  1471  		w.op(ir.OLITERAL)
  1472  		w.pos(n.Pos())
  1473  		w.value(n.Type(), n.Val())
  1474  
  1475  	case ir.ONAME:
  1476  		// Package scope name.
  1477  		n := n.(*ir.Name)
  1478  		if (n.Class == ir.PEXTERN || n.Class == ir.PFUNC) && !ir.IsBlank(n) {
  1479  			w.op(ir.ONONAME)
  1480  			w.qualifiedIdent(n)
  1481  			if go117ExportTypes {
  1482  				w.typ(n.Type())
  1483  			}
  1484  			break
  1485  		}
  1486  
  1487  		// Function scope name.
  1488  		// We don't need a type here, as the type will be provided at the
  1489  		// declaration of n.
  1490  		w.op(ir.ONAME)
  1491  		w.localName(n)
  1492  
  1493  	// case OPACK, ONONAME:
  1494  	// 	should have been resolved by typechecking - handled by default case
  1495  
  1496  	case ir.OTYPE:
  1497  		w.op(ir.OTYPE)
  1498  		w.typ(n.Type())
  1499  
  1500  	case ir.OTYPESW:
  1501  		n := n.(*ir.TypeSwitchGuard)
  1502  		w.op(ir.OTYPESW)
  1503  		w.pos(n.Pos())
  1504  		var s *types.Sym
  1505  		if n.Tag != nil {
  1506  			if n.Tag.Op() != ir.ONONAME {
  1507  				base.Fatalf("expected ONONAME, got %v", n.Tag)
  1508  			}
  1509  			s = n.Tag.Sym()
  1510  		}
  1511  		w.localIdent(s) // declared pseudo-variable, if any
  1512  		w.expr(n.X)
  1513  
  1514  	// case OTARRAY, OTMAP, OTCHAN, OTSTRUCT, OTINTER, OTFUNC:
  1515  	// 	should have been resolved by typechecking - handled by default case
  1516  
  1517  	case ir.OCLOSURE:
  1518  		n := n.(*ir.ClosureExpr)
  1519  		w.op(ir.OCLOSURE)
  1520  		w.pos(n.Pos())
  1521  		w.signature(n.Type())
  1522  
  1523  		// Write out id for the Outer of each conditional variable. The
  1524  		// conditional variable itself for this closure will be re-created
  1525  		// during import.
  1526  		w.int64(int64(len(n.Func.ClosureVars)))
  1527  		for i, cv := range n.Func.ClosureVars {
  1528  			w.pos(cv.Pos())
  1529  			w.localName(cv.Outer)
  1530  			// Closure variable (which will be re-created during
  1531  			// import) is given via a negative id, starting at -2,
  1532  			// which is used to refer to it later in the function
  1533  			// during export. -1 represents blanks.
  1534  			w.dclIndex[cv] = -(i + 2) - w.maxClosureVarIndex
  1535  		}
  1536  		w.maxClosureVarIndex += len(n.Func.ClosureVars)
  1537  
  1538  		// like w.funcBody(n.Func), but not for .Inl
  1539  		w.writeNames(n.Func.Dcl)
  1540  		w.stmtList(n.Func.Body)
  1541  
  1542  	// case OCOMPLIT:
  1543  	// 	should have been resolved by typechecking - handled by default case
  1544  
  1545  	case ir.OPTRLIT:
  1546  		n := n.(*ir.AddrExpr)
  1547  		if go117ExportTypes {
  1548  			w.op(ir.OPTRLIT)
  1549  		} else {
  1550  			w.op(ir.OADDR)
  1551  		}
  1552  		w.pos(n.Pos())
  1553  		w.expr(n.X)
  1554  		if go117ExportTypes {
  1555  			w.typ(n.Type())
  1556  		}
  1557  
  1558  	case ir.OSTRUCTLIT:
  1559  		n := n.(*ir.CompLitExpr)
  1560  		w.op(ir.OSTRUCTLIT)
  1561  		w.pos(n.Pos())
  1562  		w.typ(n.Type())
  1563  		w.fieldList(n.List) // special handling of field names
  1564  
  1565  	case ir.OARRAYLIT, ir.OSLICELIT, ir.OMAPLIT:
  1566  		n := n.(*ir.CompLitExpr)
  1567  		if go117ExportTypes {
  1568  			w.op(n.Op())
  1569  		} else {
  1570  			w.op(ir.OCOMPLIT)
  1571  		}
  1572  		w.pos(n.Pos())
  1573  		w.typ(n.Type())
  1574  		w.exprList(n.List)
  1575  		if go117ExportTypes && n.Op() == ir.OSLICELIT {
  1576  			w.uint64(uint64(n.Len))
  1577  		}
  1578  	case ir.OKEY:
  1579  		n := n.(*ir.KeyExpr)
  1580  		w.op(ir.OKEY)
  1581  		w.pos(n.Pos())
  1582  		w.expr(n.Key)
  1583  		w.expr(n.Value)
  1584  
  1585  	// case OSTRUCTKEY:
  1586  	//	unreachable - handled in case OSTRUCTLIT by elemList
  1587  
  1588  	case ir.OXDOT, ir.ODOT, ir.ODOTPTR, ir.ODOTINTER, ir.ODOTMETH, ir.OCALLPART, ir.OMETHEXPR:
  1589  		n := n.(*ir.SelectorExpr)
  1590  		if go117ExportTypes {
  1591  			if n.Op() == ir.OXDOT {
  1592  				base.Fatalf("shouldn't encounter XDOT  in new exporter")
  1593  			}
  1594  			w.op(n.Op())
  1595  		} else {
  1596  			w.op(ir.OXDOT)
  1597  		}
  1598  		w.pos(n.Pos())
  1599  		w.expr(n.X)
  1600  		w.exoticSelector(n.Sel)
  1601  		if go117ExportTypes {
  1602  			w.exoticType(n.Type())
  1603  			if n.Op() == ir.ODOT || n.Op() == ir.ODOTPTR || n.Op() == ir.ODOTINTER {
  1604  				w.exoticField(n.Selection)
  1605  			}
  1606  			// n.Selection is not required for OMETHEXPR, ODOTMETH, and OCALLPART. It will
  1607  			// be reconstructed during import.
  1608  		}
  1609  
  1610  	case ir.ODOTTYPE, ir.ODOTTYPE2:
  1611  		n := n.(*ir.TypeAssertExpr)
  1612  		if go117ExportTypes {
  1613  			w.op(n.Op())
  1614  		} else {
  1615  			w.op(ir.ODOTTYPE)
  1616  		}
  1617  		w.pos(n.Pos())
  1618  		w.expr(n.X)
  1619  		w.typ(n.Type())
  1620  
  1621  	case ir.OINDEX, ir.OINDEXMAP:
  1622  		n := n.(*ir.IndexExpr)
  1623  		if go117ExportTypes {
  1624  			w.op(n.Op())
  1625  		} else {
  1626  			w.op(ir.OINDEX)
  1627  		}
  1628  		w.pos(n.Pos())
  1629  		w.expr(n.X)
  1630  		w.expr(n.Index)
  1631  		if go117ExportTypes {
  1632  			w.typ(n.Type())
  1633  			if n.Op() == ir.OINDEXMAP {
  1634  				w.bool(n.Assigned)
  1635  			}
  1636  		}
  1637  
  1638  	case ir.OSLICE, ir.OSLICESTR, ir.OSLICEARR:
  1639  		n := n.(*ir.SliceExpr)
  1640  		if go117ExportTypes {
  1641  			w.op(n.Op())
  1642  		} else {
  1643  			w.op(ir.OSLICE)
  1644  		}
  1645  		w.pos(n.Pos())
  1646  		w.expr(n.X)
  1647  		w.exprsOrNil(n.Low, n.High)
  1648  		if go117ExportTypes {
  1649  			w.typ(n.Type())
  1650  		}
  1651  
  1652  	case ir.OSLICE3, ir.OSLICE3ARR:
  1653  		n := n.(*ir.SliceExpr)
  1654  		if go117ExportTypes {
  1655  			w.op(n.Op())
  1656  		} else {
  1657  			w.op(ir.OSLICE3)
  1658  		}
  1659  		w.pos(n.Pos())
  1660  		w.expr(n.X)
  1661  		w.exprsOrNil(n.Low, n.High)
  1662  		w.expr(n.Max)
  1663  		if go117ExportTypes {
  1664  			w.typ(n.Type())
  1665  		}
  1666  
  1667  	case ir.OCOPY, ir.OCOMPLEX, ir.OUNSAFEADD, ir.OUNSAFESLICE:
  1668  		// treated like other builtin calls (see e.g., OREAL)
  1669  		n := n.(*ir.BinaryExpr)
  1670  		w.op(n.Op())
  1671  		w.pos(n.Pos())
  1672  		w.expr(n.X)
  1673  		w.expr(n.Y)
  1674  		if go117ExportTypes {
  1675  			w.typ(n.Type())
  1676  		} else {
  1677  			w.op(ir.OEND)
  1678  		}
  1679  
  1680  	case ir.OCONV, ir.OCONVIFACE, ir.OCONVNOP, ir.OBYTES2STR, ir.ORUNES2STR, ir.OSTR2BYTES, ir.OSTR2RUNES, ir.ORUNESTR, ir.OSLICE2ARRPTR:
  1681  		n := n.(*ir.ConvExpr)
  1682  		if go117ExportTypes {
  1683  			w.op(n.Op())
  1684  		} else {
  1685  			w.op(ir.OCONV)
  1686  		}
  1687  		w.pos(n.Pos())
  1688  		w.typ(n.Type())
  1689  		w.expr(n.X)
  1690  
  1691  	case ir.OREAL, ir.OIMAG, ir.OCAP, ir.OCLOSE, ir.OLEN, ir.ONEW, ir.OPANIC:
  1692  		n := n.(*ir.UnaryExpr)
  1693  		w.op(n.Op())
  1694  		w.pos(n.Pos())
  1695  		w.expr(n.X)
  1696  		if go117ExportTypes {
  1697  			if n.Op() != ir.OPANIC {
  1698  				w.typ(n.Type())
  1699  			}
  1700  		} else {
  1701  			w.op(ir.OEND)
  1702  		}
  1703  
  1704  	case ir.OAPPEND, ir.ODELETE, ir.ORECOVER, ir.OPRINT, ir.OPRINTN:
  1705  		n := n.(*ir.CallExpr)
  1706  		w.op(n.Op())
  1707  		w.pos(n.Pos())
  1708  		w.exprList(n.Args) // emits terminating OEND
  1709  		// only append() calls may contain '...' arguments
  1710  		if n.Op() == ir.OAPPEND {
  1711  			w.bool(n.IsDDD)
  1712  		} else if n.IsDDD {
  1713  			base.Fatalf("exporter: unexpected '...' with %v call", n.Op())
  1714  		}
  1715  		if go117ExportTypes {
  1716  			if n.Op() != ir.ODELETE && n.Op() != ir.OPRINT && n.Op() != ir.OPRINTN {
  1717  				w.typ(n.Type())
  1718  			}
  1719  		}
  1720  
  1721  	case ir.OCALL, ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER, ir.OGETG:
  1722  		n := n.(*ir.CallExpr)
  1723  		if go117ExportTypes {
  1724  			w.op(n.Op())
  1725  		} else {
  1726  			w.op(ir.OCALL)
  1727  		}
  1728  		w.pos(n.Pos())
  1729  		w.stmtList(n.Init())
  1730  		w.expr(n.X)
  1731  		w.exprList(n.Args)
  1732  		w.bool(n.IsDDD)
  1733  		if go117ExportTypes {
  1734  			w.exoticType(n.Type())
  1735  			w.uint64(uint64(n.Use))
  1736  		}
  1737  
  1738  	case ir.OMAKEMAP, ir.OMAKECHAN, ir.OMAKESLICE:
  1739  		n := n.(*ir.MakeExpr)
  1740  		w.op(n.Op()) // must keep separate from OMAKE for importer
  1741  		w.pos(n.Pos())
  1742  		w.typ(n.Type())
  1743  		switch {
  1744  		default:
  1745  			// empty list
  1746  			w.op(ir.OEND)
  1747  		case n.Cap != nil:
  1748  			w.expr(n.Len)
  1749  			w.expr(n.Cap)
  1750  			w.op(ir.OEND)
  1751  		case n.Len != nil && (n.Op() == ir.OMAKESLICE || !n.Len.Type().IsUntyped()):
  1752  			// Note: the extra conditional exists because make(T) for
  1753  			// T a map or chan type, gets an untyped zero added as
  1754  			// an argument. Don't serialize that argument here.
  1755  			w.expr(n.Len)
  1756  			w.op(ir.OEND)
  1757  		case n.Len != nil && go117ExportTypes:
  1758  			w.expr(n.Len)
  1759  			w.op(ir.OEND)
  1760  		}
  1761  
  1762  	// unary expressions
  1763  	case ir.OPLUS, ir.ONEG, ir.OBITNOT, ir.ONOT, ir.ORECV:
  1764  		n := n.(*ir.UnaryExpr)
  1765  		w.op(n.Op())
  1766  		w.pos(n.Pos())
  1767  		w.expr(n.X)
  1768  		if go117ExportTypes {
  1769  			w.typ(n.Type())
  1770  		}
  1771  
  1772  	case ir.OADDR:
  1773  		n := n.(*ir.AddrExpr)
  1774  		w.op(n.Op())
  1775  		w.pos(n.Pos())
  1776  		w.expr(n.X)
  1777  		if go117ExportTypes {
  1778  			w.typ(n.Type())
  1779  		}
  1780  
  1781  	case ir.ODEREF:
  1782  		n := n.(*ir.StarExpr)
  1783  		w.op(n.Op())
  1784  		w.pos(n.Pos())
  1785  		w.expr(n.X)
  1786  		if go117ExportTypes {
  1787  			w.typ(n.Type())
  1788  		}
  1789  
  1790  	case ir.OSEND:
  1791  		n := n.(*ir.SendStmt)
  1792  		w.op(n.Op())
  1793  		w.pos(n.Pos())
  1794  		w.expr(n.Chan)
  1795  		w.expr(n.Value)
  1796  
  1797  	// binary expressions
  1798  	case ir.OADD, ir.OAND, ir.OANDNOT, ir.ODIV, ir.OEQ, ir.OGE, ir.OGT, ir.OLE, ir.OLT,
  1799  		ir.OLSH, ir.OMOD, ir.OMUL, ir.ONE, ir.OOR, ir.ORSH, ir.OSUB, ir.OXOR:
  1800  		n := n.(*ir.BinaryExpr)
  1801  		w.op(n.Op())
  1802  		w.pos(n.Pos())
  1803  		w.expr(n.X)
  1804  		w.expr(n.Y)
  1805  		if go117ExportTypes {
  1806  			w.typ(n.Type())
  1807  		}
  1808  
  1809  	case ir.OANDAND, ir.OOROR:
  1810  		n := n.(*ir.LogicalExpr)
  1811  		w.op(n.Op())
  1812  		w.pos(n.Pos())
  1813  		w.expr(n.X)
  1814  		w.expr(n.Y)
  1815  		if go117ExportTypes {
  1816  			w.typ(n.Type())
  1817  		}
  1818  
  1819  	case ir.OADDSTR:
  1820  		n := n.(*ir.AddStringExpr)
  1821  		w.op(ir.OADDSTR)
  1822  		w.pos(n.Pos())
  1823  		w.exprList(n.List)
  1824  		if go117ExportTypes {
  1825  			w.typ(n.Type())
  1826  		}
  1827  
  1828  	case ir.ODCLCONST:
  1829  		// if exporting, DCLCONST should just be removed as its usage
  1830  		// has already been replaced with literals
  1831  
  1832  	default:
  1833  		base.Fatalf("cannot export %v (%d) node\n"+
  1834  			"\t==> please file an issue and assign to gri@", n.Op(), int(n.Op()))
  1835  	}
  1836  }
  1837  
  1838  func (w *exportWriter) op(op ir.Op) {
  1839  	if debug {
  1840  		w.uint64(magic)
  1841  	}
  1842  	w.uint64(uint64(op))
  1843  }
  1844  
  1845  func (w *exportWriter) exprsOrNil(a, b ir.Node) {
  1846  	ab := 0
  1847  	if a != nil {
  1848  		ab |= 1
  1849  	}
  1850  	if b != nil {
  1851  		ab |= 2
  1852  	}
  1853  	w.uint64(uint64(ab))
  1854  	if ab&1 != 0 {
  1855  		w.expr(a)
  1856  	}
  1857  	if ab&2 != 0 {
  1858  		w.node(b)
  1859  	}
  1860  }
  1861  
  1862  func (w *exportWriter) fieldList(list ir.Nodes) {
  1863  	w.uint64(uint64(len(list)))
  1864  	for _, n := range list {
  1865  		n := n.(*ir.StructKeyExpr)
  1866  		w.pos(n.Pos())
  1867  		w.selector(n.Field)
  1868  		w.expr(n.Value)
  1869  		if go117ExportTypes {
  1870  			w.uint64(uint64(n.Offset))
  1871  		}
  1872  	}
  1873  }
  1874  
  1875  func (w *exportWriter) localName(n *ir.Name) {
  1876  	if ir.IsBlank(n) {
  1877  		w.int64(-1)
  1878  		return
  1879  	}
  1880  
  1881  	i, ok := w.dclIndex[n]
  1882  	if !ok {
  1883  		base.FatalfAt(n.Pos(), "missing from dclIndex: %+v", n)
  1884  	}
  1885  	w.int64(int64(i))
  1886  }
  1887  
  1888  func (w *exportWriter) localIdent(s *types.Sym) {
  1889  	if w.currPkg == nil {
  1890  		base.Fatalf("missing currPkg")
  1891  	}
  1892  
  1893  	// Anonymous parameters.
  1894  	if s == nil {
  1895  		w.string("")
  1896  		return
  1897  	}
  1898  
  1899  	name := s.Name
  1900  	if name == "_" {
  1901  		w.string("_")
  1902  		return
  1903  	}
  1904  
  1905  	// TODO(mdempsky): Fix autotmp hack.
  1906  	if i := strings.LastIndex(name, "."); i >= 0 && !strings.HasPrefix(name, ".autotmp_") {
  1907  		base.Fatalf("unexpected dot in identifier: %v", name)
  1908  	}
  1909  
  1910  	if s.Pkg != w.currPkg {
  1911  		base.Fatalf("weird package in name: %v => %v from %q, not %q", s, name, s.Pkg.Path, w.currPkg.Path)
  1912  	}
  1913  
  1914  	w.string(name)
  1915  }
  1916  
  1917  type intWriter struct {
  1918  	bytes.Buffer
  1919  }
  1920  
  1921  func (w *intWriter) int64(x int64) {
  1922  	var buf [binary.MaxVarintLen64]byte
  1923  	n := binary.PutVarint(buf[:], x)
  1924  	w.Write(buf[:n])
  1925  }
  1926  
  1927  func (w *intWriter) uint64(x uint64) {
  1928  	var buf [binary.MaxVarintLen64]byte
  1929  	n := binary.PutUvarint(buf[:], x)
  1930  	w.Write(buf[:n])
  1931  }
  1932  
  1933  // If go117ExportTypes is true, then we write type information when
  1934  // exporting function bodies, so those function bodies don't need to
  1935  // be re-typechecked on import.
  1936  // This flag adds some other info to the serialized stream as well
  1937  // which was previously recomputed during typechecking, like
  1938  // specializing opcodes (e.g. OXDOT to ODOTPTR) and ancillary
  1939  // information (e.g. length field for OSLICELIT).
  1940  const go117ExportTypes = true
  1941  const Go117ExportTypes = go117ExportTypes
  1942  

View as plain text