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