GoPLS Viewer

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