1 // Copyright 2016 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.
5 // Binary package export.
6 // This file was derived from $GOROOT/src/cmd/compile/internal/gc/bexport.go;
7 // see that file for specification of the format.
25 // If debugFormat is set, each integer and string value is preceded by a marker
26 // and position information in the encoding. This mechanism permits an importer
27 // to recognize immediately when it is out of sync. The importer recognizes this
28 // mode automatically (i.e., it can import export data produced with debugging
29 // support even if debugFormat is not set at the time of import). This mode will
30 // lead to massively larger export data (by a factor of 2 to 3) and should only
31 // be enabled during development and debugging.
33 // NOTE: This flag is the first flag to enable if importing dies because of
34 // (suspected) format errors, and whenever a change is made to the format.
35 const debugFormat = false // default: false
37 // If trace is set, debugging output is printed to std out.
38 const trace = false // default: false
40 // Current export format version. Increase with each format change.
41 // Note: The latest binary (non-indexed) export format is at version 6.
42 // This exporter is still at level 4, but it doesn't matter since
43 // the binary importer can handle older versions just fine.
44 // 6: package height (CL 105038) -- NOT IMPLEMENTED HERE
45 // 5: improved position encoding efficiency (issue 20080, CL 41619) -- NOT IMPLEMEMTED HERE
46 // 4: type name objects support type aliases, uses aliasTag
47 // 3: Go1.8 encoding (same as version 2, aliasTag defined but never used)
48 // 2: removed unused bool in ODCL export (compiler only)
49 // 1: header format change (more regular), export package for _ struct fields
51 const exportVersion = 4
53 // trackAllTypes enables cycle tracking for all types, not just named
54 // types. The existing compiler invariants assume that unnamed types
55 // that are not completely set up are not used, or else there are spurious
57 // If disabled, only named types are tracked, possibly leading to slightly
58 // less efficient encoding in rare cases. It also prevents the export of
59 // some corner-case type declarations (but those are not handled correctly
60 // with with the textual export format either).
61 // TODO(gri) enable and remove once issues caused by it are fixed
62 const trackAllTypes = false
64 type exporter struct {
68 // object -> index maps, indexed in order of serialization
69 strIndex map[string]int
70 pkgIndex map[*types.Package]int
71 typIndex map[types.Type]int
79 written int // bytes written
80 indent int // for trace
83 // internalError represents an error generated inside this package.
84 type internalError string
86 func (e internalError) Error() string { return "gcimporter: " + string(e) }
88 func internalErrorf(format string, args ...interface{}) error {
89 return internalError(fmt.Sprintf(format, args...))
92 // BExportData returns binary export data for pkg.
93 // If no file set is provided, position info will be missing.
94 func BExportData(fset *token.FileSet, pkg *types.Package) (b []byte, err error) {
96 if e := recover(); e != nil {
97 if ierr, ok := e.(internalError); ok {
101 // Not an internal error; panic again.
108 strIndex: map[string]int{"": 0}, // empty string is mapped to 0
109 pkgIndex: make(map[*types.Package]int),
110 typIndex: make(map[types.Type]int),
111 posInfoFormat: true, // TODO(gri) might become a flag, eventually
114 // write version info
115 // The version string must start with "version %d" where %d is the version
116 // number. Additional debugging information may follow after a blank; that
117 // text is ignored by the importer.
118 p.rawStringln(fmt.Sprintf("version %d", exportVersion))
123 p.rawStringln(debug) // cannot use p.bool since it's affected by debugFormat; also want to see this clearly
124 p.bool(trackAllTypes)
125 p.bool(p.posInfoFormat)
127 // --- generic export data ---
129 // populate type map with predeclared "known" types
130 for index, typ := range predeclared() {
131 p.typIndex[typ] = index
133 if len(p.typIndex) != len(predeclared()) {
134 return nil, internalError("duplicate entries in type map?")
137 // write package data
146 for _, name := range scope.Names() {
147 if !ast.IsExported(name) {
153 p.obj(scope.Lookup(name))
157 // indicate end of list
163 // for self-verification only (redundant)
170 // --- end of export data ---
172 return p.out.Bytes(), nil
175 func (p *exporter) pkg(pkg *types.Package, emptypath bool) {
177 panic(internalError("unexpected nil pkg"))
180 // if we saw the package before, write its index (>= 0)
181 if i, ok := p.pkgIndex[pkg]; ok {
186 // otherwise, remember the package, write the package tag (< 0) and package data
188 p.tracef("P%d = { ", len(p.pkgIndex))
191 p.pkgIndex[pkg] = len(p.pkgIndex)
202 func (p *exporter) obj(obj types.Object) {
203 switch obj := obj.(type) {
211 case *types.TypeName:
231 sig := obj.Type().(*types.Signature)
232 p.paramList(sig.Params(), sig.Variadic())
233 p.paramList(sig.Results(), false)
236 panic(internalErrorf("unexpected object %v (%T)", obj, obj))
240 func (p *exporter) pos(obj types.Object) {
241 if !p.posInfoFormat {
245 file, line := p.fileLine(obj)
246 if file == p.prevFile {
247 // common case: write line delta
248 // delta == 0 means different file or no line change
249 delta := line - p.prevLine
252 p.int(-1) // -1 means no file change
257 // Encode filename as length of common prefix with previous
258 // filename, followed by (possibly empty) suffix. Filenames
259 // frequently share path prefixes, so this can save a lot
260 // of space and make export data size less dependent on file
261 // path length. The suffix is unlikely to be empty because
262 // file names tend to end in ".go".
263 n := commonPrefixLen(p.prevFile, file)
265 p.string(file[n:]) // write suffix only
272 func (p *exporter) fileLine(obj types.Object) (file string, line int) {
274 pos := p.fset.Position(obj.Pos())
281 func commonPrefixLen(a, b string) int {
287 for i < len(a) && a[i] == b[i] {
293 func (p *exporter) qualifiedName(obj types.Object) {
295 p.pkg(obj.Pkg(), false)
298 func (p *exporter) typ(t types.Type) {
300 panic(internalError("nil type"))
303 // Possible optimization: Anonymous pointer types *T where
304 // T is a named type are common. We could canonicalize all
305 // such types *T to a single type PT = *T. This would lead
306 // to at most one *T entry in typIndex, and all future *T's
307 // would be encoded as the respective index directly. Would
308 // save 1 byte (pointerTag) per *T and reduce the typIndex
309 // size (at the cost of a canonicalization map). We can do
310 // this later, without encoding format change.
312 // if we saw the type before, write its index (>= 0)
313 if i, ok := p.typIndex[t]; ok {
318 // otherwise, remember the type, write the type tag (< 0) and type data
321 p.tracef("T%d = {>\n", len(p.typIndex))
322 defer p.tracef("<\n} ")
324 p.typIndex[t] = len(p.typIndex)
327 switch t := t.(type) {
330 // if we don't track all types, track named types now
331 p.typIndex[t] = len(p.typIndex)
336 p.qualifiedName(t.Obj())
337 p.typ(t.Underlying())
338 if !types.IsInterface(t) {
363 case *types.Signature:
365 p.paramList(t.Params(), t.Variadic())
366 p.paramList(t.Results(), false)
368 case *types.Interface:
379 p.int(int(3 - t.Dir())) // hack
383 panic(internalErrorf("unexpected type %T: %s", t, t))
387 func (p *exporter) assocMethods(named *types.Named) {
388 // Sort methods (for determinism).
389 var methods []*types.Func
390 for i := 0; i < named.NumMethods(); i++ {
391 methods = append(methods, named.Method(i))
393 sort.Sort(methodsByName(methods))
397 if trace && methods != nil {
398 p.tracef("associated methods {>\n")
401 for i, m := range methods {
410 p.pkg(m.Pkg(), false)
413 sig := m.Type().(*types.Signature)
414 p.paramList(types.NewTuple(sig.Recv()), false)
415 p.paramList(sig.Params(), sig.Variadic())
416 p.paramList(sig.Results(), false)
417 p.int(0) // dummy value for go:nointerface pragma - ignored by importer
420 if trace && methods != nil {
425 type methodsByName []*types.Func
427 func (x methodsByName) Len() int { return len(x) }
428 func (x methodsByName) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
429 func (x methodsByName) Less(i, j int) bool { return x[i].Name() < x[j].Name() }
431 func (p *exporter) fieldList(t *types.Struct) {
432 if trace && t.NumFields() > 0 {
433 p.tracef("fields {>\n")
434 defer p.tracef("<\n} ")
438 for i := 0; i < t.NumFields(); i++ {
447 func (p *exporter) field(f *types.Var) {
449 panic(internalError("field expected"))
457 func (p *exporter) iface(t *types.Interface) {
458 // TODO(gri): enable importer to load embedded interfaces,
459 // then emit Embeddeds and ExplicitMethods separately here.
464 p.tracef("methods {>\n")
465 defer p.tracef("<\n} ")
468 for i := 0; i < n; i++ {
472 p.method(t.Method(i))
476 func (p *exporter) method(m *types.Func) {
477 sig := m.Type().(*types.Signature)
478 if sig.Recv() == nil {
479 panic(internalError("method expected"))
484 if m.Name() != "_" && !ast.IsExported(m.Name()) {
485 p.pkg(m.Pkg(), false)
488 // interface method; no need to encode receiver.
489 p.paramList(sig.Params(), sig.Variadic())
490 p.paramList(sig.Results(), false)
493 func (p *exporter) fieldName(f *types.Var) {
497 // anonymous field - we distinguish between 3 cases:
498 // 1) field name matches base type name and is exported
499 // 2) field name matches base type name and is not exported
500 // 3) field name doesn't match base type name (alias name)
501 bname := basetypeName(f.Type())
503 if ast.IsExported(name) {
504 name = "" // 1) we don't need to know the field name or package
506 name = "?" // 2) use unexported name "?" to force package export
509 // 3) indicate alias and export name as is
510 // (this requires an extra "@" but this is a rare case)
516 if name != "" && !ast.IsExported(name) {
517 p.pkg(f.Pkg(), false)
521 func basetypeName(typ types.Type) string {
522 switch typ := deref(typ).(type) {
526 return typ.Obj().Name()
528 return "" // unnamed type
532 func (p *exporter) paramList(params *types.Tuple, variadic bool) {
533 // use negative length to indicate unnamed parameters
534 // (look at the first parameter only since either all
535 // names are present or all are absent)
537 if n > 0 && params.At(0).Name() == "" {
541 for i := 0; i < params.Len(); i++ {
544 if variadic && i == params.Len()-1 {
545 t = &dddSlice{t.(*types.Slice).Elem()}
552 p.pkg(q.Pkg(), false)
555 p.string("") // no compiler-specific info
559 func (p *exporter) value(x constant.Value) {
567 if constant.BoolVal(x) {
573 if v, exact := constant.Int64Val(x); exact {
574 // common case: x fits into an int64 - use compact encoding
579 // uncommon case: large x - use float encoding
580 // (powers of 2 will be encoded efficiently with exponent)
582 p.float(constant.ToFloat(x))
588 case constant.Complex:
590 p.float(constant.Real(x))
591 p.float(constant.Imag(x))
593 case constant.String:
595 p.string(constant.StringVal(x))
597 case constant.Unknown:
598 // package contains type errors
602 panic(internalErrorf("unexpected value %v (%T)", x, x))
606 func (p *exporter) float(x constant.Value) {
607 if x.Kind() != constant.Float {
608 panic(internalErrorf("unexpected constant %v, want float", x))
610 // extract sign (there is no -0)
611 sign := constant.Sign(x)
620 if v, exact := constant.Float64Val(x); exact {
623 } else if num, denom := constant.Num(x), constant.Denom(x); num.Kind() == constant.Int {
624 // TODO(gri): add big.Rat accessor to constant.Value.
626 f.SetRat(r.Quo(r, valueToRat(denom)))
628 // Value too large to represent as a fraction => inaccessible.
629 // TODO(gri): add big.Float accessor to constant.Value.
630 f.SetFloat64(math.MaxFloat64) // FIXME
633 // extract exponent such that 0.5 <= m < 1.0
637 // extract mantissa as *big.Int
638 // - set exponent large enough so mant satisfies mant.IsInt()
639 // - get *big.Int from mant
640 m.SetMantExp(&m, int(m.MinPrec()))
641 mant, acc := m.Int(nil)
642 if acc != big.Exact {
643 panic(internalError("internal error"))
648 p.string(string(mant.Bytes()))
651 func valueToRat(x constant.Value) *big.Rat {
652 // Convert little-endian to big-endian.
653 // I can't believe this is necessary.
654 bytes := constant.Bytes(x)
655 for i := 0; i < len(bytes)/2; i++ {
656 bytes[i], bytes[len(bytes)-1-i] = bytes[len(bytes)-1-i], bytes[i]
658 return new(big.Rat).SetInt(new(big.Int).SetBytes(bytes))
661 func (p *exporter) bool(b bool) bool {
664 defer p.tracef("= %v] ", b)
675 // ----------------------------------------------------------------------------
676 // Low-level encoders
678 func (p *exporter) index(marker byte, index int) {
680 panic(internalError("invalid index < 0"))
686 p.tracef("%c%d ", marker, index)
688 p.rawInt64(int64(index))
691 func (p *exporter) tag(tag int) {
693 panic(internalError("invalid tag >= 0"))
699 p.tracef("%s ", tagString[-tag])
701 p.rawInt64(int64(tag))
704 func (p *exporter) int(x int) {
708 func (p *exporter) int64(x int64) {
718 func (p *exporter) string(s string) {
725 // if we saw the string before, write its index (>= 0)
726 // (the empty string is mapped to 0)
727 if i, ok := p.strIndex[s]; ok {
731 // otherwise, remember string and write its negative length and bytes
732 p.strIndex[s] = len(p.strIndex)
733 p.rawInt64(-int64(len(s)))
734 for i := 0; i < len(s); i++ {
739 // marker emits a marker byte and position information which makes
740 // it easy for a reader to detect if it is "out of sync". Used for
741 // debugFormat format only.
742 func (p *exporter) marker(m byte) {
744 // Enable this for help tracking down the location
745 // of an incorrect marker when running in debugFormat.
747 p.tracef("#%d ", p.written)
749 p.rawInt64(int64(p.written))
752 // rawInt64 should only be used by low-level encoders.
753 func (p *exporter) rawInt64(x int64) {
754 var tmp [binary.MaxVarintLen64]byte
755 n := binary.PutVarint(tmp[:], x)
756 for i := 0; i < n; i++ {
761 // rawStringln should only be used to emit the initial version string.
762 func (p *exporter) rawStringln(s string) {
763 for i := 0; i < len(s); i++ {
769 // rawByte is the bottleneck interface to write to p.out.
770 // rawByte escapes b as follows (any encoding does that
776 // Necessary so other tools can find the end of the
777 // export data by searching for "$$".
778 // rawByte should only be used by low-level encoders.
779 func (p *exporter) rawByte(b byte) {
782 // write '$' as '|' 'S'
786 // write '|' as '|' '|'
794 // tracef is like fmt.Printf but it rewrites the format string
795 // to take care of indentation.
796 func (p *exporter) tracef(format string, args ...interface{}) {
797 if strings.ContainsAny(format, "<>\n") {
799 for i := 0; i < len(format); i++ {
800 // no need to deal with runes
812 for j := p.indent; j > 0; j-- {
813 buf.WriteString(". ")
817 format = buf.String()
819 fmt.Printf(format, args...)
822 // Debugging support.
823 // (tagString is only used when tracing is enabled)
824 var tagString = [...]string{
826 -packageTag: "package",
829 -namedTag: "named type",
833 -structTag: "struct",
834 -pointerTag: "pointer",
835 -signatureTag: "signature",
836 -interfaceTag: "interface",
845 -fractionTag: "fraction",
846 -complexTag: "complex",
847 -stringTag: "string",
848 -unknownTag: "unknown",