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