github.com/rakyll/go@v0.0.0-20170216000551-64c02460d703/src/cmd/compile/internal/gc/bexport.go (about) 1 // Copyright 2015 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 // Binary package export. 6 7 /* 8 1) Export data encoding principles: 9 10 The export data is a serialized description of the graph of exported 11 "objects": constants, types, variables, and functions. Aliases may be 12 directly reexported, and unaliased types may be indirectly reexported 13 (as part of the type of a directly exported object). More generally, 14 objects referred to from inlined function bodies can be reexported. 15 We need to know which package declares these reexported objects, and 16 therefore packages are also part of the export graph. 17 18 The roots of the graph are two lists of objects. The 1st list (phase 1, 19 see Export) contains all objects that are exported at the package level. 20 These objects are the full representation of the package's API, and they 21 are the only information a platform-independent tool (e.g., go/types) 22 needs to know to type-check against a package. 23 24 The 2nd list of objects contains all objects referred to from exported 25 inlined function bodies. These objects are needed by the compiler to 26 make sense of the function bodies; the exact list contents are compiler- 27 specific. 28 29 Finally, the export data contains a list of representations for inlined 30 function bodies. The format of this representation is compiler specific. 31 32 The graph is serialized in in-order fashion, starting with the roots. 33 Each object in the graph is serialized by writing its fields sequentially. 34 If the field is a pointer to another object, that object is serialized in 35 place, recursively. Otherwise the field is written in place. Non-pointer 36 fields are all encoded as integer or string values. 37 38 Some objects (packages, types) may be referred to more than once. When 39 reaching an object that was not serialized before, an integer _index_ 40 is assigned to it, starting at 0. In this case, the encoding starts 41 with an integer _tag_ < 0. The tag value indicates the kind of object 42 that follows and that this is the first time that we see this object. 43 If the object was already serialized, the encoding is simply the object 44 index >= 0. An importer can trivially determine if an object needs to 45 be read in for the first time (tag < 0) and entered into the respective 46 object table, or if the object was seen already (index >= 0), in which 47 case the index is used to look up the object in the respective table. 48 49 Before exporting or importing, the type tables are populated with the 50 predeclared types (int, string, error, unsafe.Pointer, etc.). This way 51 they are automatically encoded with a known and fixed type index. 52 53 2) Encoding format: 54 55 The export data starts with two newline-terminated strings: a version 56 string and either an empty string, or "debug", when emitting the debug 57 format. These strings are followed by version-specific encoding options. 58 59 (The Go1.7 version starts with a couple of bytes specifying the format. 60 That format encoding is no longer used but is supported to avoid spurious 61 errors when importing old installed package files.) 62 63 This header is followed by the package object for the exported package, 64 two lists of objects, and the list of inlined function bodies. 65 66 The encoding of objects is straight-forward: Constants, variables, and 67 functions start with their name, type, and possibly a value. Named types 68 record their name and package so that they can be canonicalized: If the 69 same type was imported before via another import, the importer must use 70 the previously imported type pointer so that we have exactly one version 71 (i.e., one pointer) for each named type (and read but discard the current 72 type encoding). Unnamed types simply encode their respective fields. 73 Aliases are encoded starting with their name followed by the qualified 74 identifier denoting the original (aliased) object, which was exported 75 earlier. 76 77 In the encoding, some lists start with the list length. Some lists are 78 terminated with an end marker (usually for lists where we may not know 79 the length a priori). 80 81 Integers use variable-length encoding for compact representation. 82 83 Strings are canonicalized similar to objects that may occur multiple times: 84 If the string was exported already, it is represented by its index only. 85 Otherwise, the export data starts with the negative string length (negative, 86 so we can distinguish from string index), followed by the string bytes. 87 The empty string is mapped to index 0. (The initial format string is an 88 exception; it is encoded as the string bytes followed by a newline). 89 90 The exporter and importer are completely symmetric in implementation: For 91 each encoding routine there is a matching and symmetric decoding routine. 92 This symmetry makes it very easy to change or extend the format: If a new 93 field needs to be encoded, a symmetric change can be made to exporter and 94 importer. 95 96 3) Making changes to the encoding format: 97 98 Any change to the encoding format requires a respective change in the 99 exporter below and a corresponding symmetric change to the importer in 100 bimport.go. 101 102 Furthermore, it requires a corresponding change to go/internal/gcimporter 103 and golang.org/x/tools/go/gcimporter15. Changes to the latter must preserve 104 compatibility with both the last release of the compiler, and with the 105 corresponding compiler at tip. That change is necessarily more involved, 106 as it must switch based on the version number in the export data file. 107 108 It is recommended to turn on debugFormat temporarily when working on format 109 changes as it will help finding encoding/decoding inconsistencies quickly. 110 */ 111 112 package gc 113 114 import ( 115 "bufio" 116 "bytes" 117 "encoding/binary" 118 "fmt" 119 "math/big" 120 "sort" 121 "strings" 122 ) 123 124 // If debugFormat is set, each integer and string value is preceded by a marker 125 // and position information in the encoding. This mechanism permits an importer 126 // to recognize immediately when it is out of sync. The importer recognizes this 127 // mode automatically (i.e., it can import export data produced with debugging 128 // support even if debugFormat is not set at the time of import). This mode will 129 // lead to massively larger export data (by a factor of 2 to 3) and should only 130 // be enabled during development and debugging. 131 // 132 // NOTE: This flag is the first flag to enable if importing dies because of 133 // (suspected) format errors, and whenever a change is made to the format. 134 const debugFormat = false // default: false 135 136 // forceObjFileStability enforces additional constraints in export data 137 // and other parts of the compiler to eliminate object file differences 138 // only due to the choice of export format. 139 // TODO(gri) disable and remove once there is only one export format again 140 const forceObjFileStability = true 141 142 // Current export format version. Increase with each format change. 143 // 4: type name objects support type aliases, uses aliasTag 144 // 3: Go1.8 encoding (same as version 2, aliasTag defined but never used) 145 // 2: removed unused bool in ODCL export (compiler only) 146 // 1: header format change (more regular), export package for _ struct fields 147 // 0: Go1.7 encoding 148 const exportVersion = 4 149 150 // exportInlined enables the export of inlined function bodies and related 151 // dependencies. The compiler should work w/o any loss of functionality with 152 // the flag disabled, but the generated code will lose access to inlined 153 // function bodies across packages, leading to performance bugs. 154 // Leave for debugging. 155 const exportInlined = true // default: true 156 157 // trackAllTypes enables cycle tracking for all types, not just named 158 // types. The existing compiler invariants assume that unnamed types 159 // that are not completely set up are not used, or else there are spurious 160 // errors. 161 // If disabled, only named types are tracked, possibly leading to slightly 162 // less efficient encoding in rare cases. It also prevents the export of 163 // some corner-case type declarations (but those were not handled correctly 164 // with the former textual export format either). 165 // TODO(gri) enable and remove once issues caused by it are fixed 166 const trackAllTypes = false 167 168 type exporter struct { 169 out *bufio.Writer 170 171 // object -> index maps, indexed in order of serialization 172 strIndex map[string]int 173 pkgIndex map[*Pkg]int 174 typIndex map[*Type]int 175 funcList []*Func 176 177 // position encoding 178 posInfoFormat bool 179 prevFile string 180 prevLine int 181 182 // debugging support 183 written int // bytes written 184 indent int // for p.trace 185 trace bool 186 187 // work-around for issue #16369 only 188 nesting int // amount of "nesting" of interface types 189 } 190 191 // export writes the exportlist for localpkg to out and returns the number of bytes written. 192 func export(out *bufio.Writer, trace bool) int { 193 p := exporter{ 194 out: out, 195 strIndex: map[string]int{"": 0}, // empty string is mapped to 0 196 pkgIndex: make(map[*Pkg]int), 197 typIndex: make(map[*Type]int), 198 posInfoFormat: true, 199 trace: trace, 200 } 201 202 // write version info 203 // The version string must start with "version %d" where %d is the version 204 // number. Additional debugging information may follow after a blank; that 205 // text is ignored by the importer. 206 p.rawStringln(fmt.Sprintf("version %d", exportVersion)) 207 var debug string 208 if debugFormat { 209 debug = "debug" 210 } 211 p.rawStringln(debug) // cannot use p.bool since it's affected by debugFormat; also want to see this clearly 212 p.bool(trackAllTypes) 213 p.bool(p.posInfoFormat) 214 215 // --- generic export data --- 216 217 // populate type map with predeclared "known" types 218 predecl := predeclared() 219 for index, typ := range predecl { 220 p.typIndex[typ] = index 221 } 222 if len(p.typIndex) != len(predecl) { 223 Fatalf("exporter: duplicate entries in type map?") 224 } 225 226 // write package data 227 if localpkg.Path != "" { 228 Fatalf("exporter: local package path not empty: %q", localpkg.Path) 229 } 230 p.pkg(localpkg) 231 if p.trace { 232 p.tracef("\n") 233 } 234 235 // export objects 236 // 237 // First, export all exported (package-level) objects; i.e., all objects 238 // in the current exportlist. These objects represent all information 239 // required to import this package and type-check against it; i.e., this 240 // is the platform-independent export data. The format is generic in the 241 // sense that different compilers can use the same representation. 242 // 243 // During this first phase, more objects may be added to the exportlist 244 // (due to inlined function bodies and their dependencies). Export those 245 // objects in a second phase. That data is platform-specific as it depends 246 // on the inlining decisions of the compiler and the representation of the 247 // inlined function bodies. 248 249 // remember initial exportlist length 250 var numglobals = len(exportlist) 251 252 // Phase 1: Export objects in _current_ exportlist; exported objects at 253 // package level. 254 // Use range since we want to ignore objects added to exportlist during 255 // this phase. 256 objcount := 0 257 for _, n := range exportlist { 258 sym := n.Sym 259 260 if sym.Flags&SymExported != 0 { 261 continue 262 } 263 sym.Flags |= SymExported 264 265 // TODO(gri) Closures have dots in their names; 266 // e.g., TestFloatZeroValue.func1 in math/big tests. 267 if strings.Contains(sym.Name, ".") { 268 Fatalf("exporter: unexpected symbol: %v", sym) 269 } 270 271 // TODO(gri) Should we do this check? 272 // if sym.Flags&SymExport == 0 { 273 // continue 274 // } 275 276 if sym.Def == nil { 277 Fatalf("exporter: unknown export symbol: %v", sym) 278 } 279 280 // TODO(gri) Optimization: Probably worthwhile collecting 281 // long runs of constants and export them "in bulk" (saving 282 // tags and types, and making import faster). 283 284 if p.trace { 285 p.tracef("\n") 286 } 287 p.obj(sym) 288 objcount++ 289 } 290 291 // indicate end of list 292 if p.trace { 293 p.tracef("\n") 294 } 295 p.tag(endTag) 296 297 // for self-verification only (redundant) 298 p.int(objcount) 299 300 // --- compiler-specific export data --- 301 302 if p.trace { 303 p.tracef("\n--- compiler-specific export data ---\n[ ") 304 if p.indent != 0 { 305 Fatalf("exporter: incorrect indentation") 306 } 307 } 308 309 // write compiler-specific flags 310 if p.trace { 311 p.tracef("\n") 312 } 313 314 // Phase 2: Export objects added to exportlist during phase 1. 315 // Don't use range since exportlist may grow during this phase 316 // and we want to export all remaining objects. 317 objcount = 0 318 for i := numglobals; exportInlined && i < len(exportlist); i++ { 319 n := exportlist[i] 320 sym := n.Sym 321 322 // TODO(gri) The rest of this loop body is identical with 323 // the loop body above. Leave alone for now since there 324 // are different optimization opportunities, but factor 325 // eventually. 326 327 if sym.Flags&SymExported != 0 { 328 continue 329 } 330 sym.Flags |= SymExported 331 332 // TODO(gri) Closures have dots in their names; 333 // e.g., TestFloatZeroValue.func1 in math/big tests. 334 if strings.Contains(sym.Name, ".") { 335 Fatalf("exporter: unexpected symbol: %v", sym) 336 } 337 338 // TODO(gri) Should we do this check? 339 // if sym.Flags&SymExport == 0 { 340 // continue 341 // } 342 343 if sym.Def == nil { 344 Fatalf("exporter: unknown export symbol: %v", sym) 345 } 346 347 // TODO(gri) Optimization: Probably worthwhile collecting 348 // long runs of constants and export them "in bulk" (saving 349 // tags and types, and making import faster). 350 351 if p.trace { 352 p.tracef("\n") 353 } 354 355 if sym.isAlias() { 356 Fatalf("exporter: unexpected type alias %v in inlined function body", sym) 357 } 358 359 p.obj(sym) 360 objcount++ 361 } 362 363 // indicate end of list 364 if p.trace { 365 p.tracef("\n") 366 } 367 p.tag(endTag) 368 369 // for self-verification only (redundant) 370 p.int(objcount) 371 372 // --- inlined function bodies --- 373 374 if p.trace { 375 p.tracef("\n--- inlined function bodies ---\n") 376 if p.indent != 0 { 377 Fatalf("exporter: incorrect indentation") 378 } 379 } 380 381 // write inlineable function bodies 382 objcount = 0 383 for i, f := range p.funcList { 384 if f != nil { 385 // function has inlineable body: 386 // write index and body 387 if p.trace { 388 p.tracef("\n----\nfunc { %#v }\n", f.Inl) 389 } 390 p.int(i) 391 p.stmtList(f.Inl) 392 if p.trace { 393 p.tracef("\n") 394 } 395 objcount++ 396 } 397 } 398 399 // indicate end of list 400 if p.trace { 401 p.tracef("\n") 402 } 403 p.int(-1) // invalid index terminates list 404 405 // for self-verification only (redundant) 406 p.int(objcount) 407 408 if p.trace { 409 p.tracef("\n--- end ---\n") 410 } 411 412 // --- end of export data --- 413 414 return p.written 415 } 416 417 func (p *exporter) pkg(pkg *Pkg) { 418 if pkg == nil { 419 Fatalf("exporter: unexpected nil pkg") 420 } 421 422 // if we saw the package before, write its index (>= 0) 423 if i, ok := p.pkgIndex[pkg]; ok { 424 p.index('P', i) 425 return 426 } 427 428 // otherwise, remember the package, write the package tag (< 0) and package data 429 if p.trace { 430 p.tracef("P%d = { ", len(p.pkgIndex)) 431 defer p.tracef("} ") 432 } 433 p.pkgIndex[pkg] = len(p.pkgIndex) 434 435 p.tag(packageTag) 436 p.string(pkg.Name) 437 p.string(pkg.Path) 438 } 439 440 func unidealType(typ *Type, val Val) *Type { 441 // Untyped (ideal) constants get their own type. This decouples 442 // the constant type from the encoding of the constant value. 443 if typ == nil || typ.IsUntyped() { 444 typ = untype(val.Ctype()) 445 } 446 return typ 447 } 448 449 func (p *exporter) obj(sym *Sym) { 450 // Exported objects may be from different packages because they 451 // may be re-exported via an exported alias or as dependencies in 452 // exported inlined function bodies. Thus, exported object names 453 // must be fully qualified. 454 // 455 // (This can only happen for aliased objects or during phase 2 456 // (exportInlined enabled) of object export. Unaliased Objects 457 // exported in phase 1 (compiler-indendepent objects) are by 458 // definition only the objects from the current package and not 459 // pulled in via inlined function bodies. In that case the package 460 // qualifier is not needed. Possible space optimization.) 461 462 n := sym.Def 463 switch n.Op { 464 case OLITERAL: 465 // constant 466 // TODO(gri) determine if we need the typecheck call here 467 n = typecheck(n, Erv) 468 if n == nil || n.Op != OLITERAL { 469 Fatalf("exporter: dumpexportconst: oconst nil: %v", sym) 470 } 471 472 p.tag(constTag) 473 p.pos(n) 474 // TODO(gri) In inlined functions, constants are used directly 475 // so they should never occur as re-exported objects. We may 476 // not need the qualified name here. See also comment above. 477 // Possible space optimization. 478 p.qualifiedName(sym) 479 p.typ(unidealType(n.Type, n.Val())) 480 p.value(n.Val()) 481 482 case OTYPE: 483 // named type 484 t := n.Type 485 if t.Etype == TFORW { 486 Fatalf("exporter: export of incomplete type %v", sym) 487 } 488 489 if sym.isAlias() { 490 p.tag(aliasTag) 491 p.pos(n) 492 p.qualifiedName(sym) 493 } else { 494 p.tag(typeTag) 495 } 496 p.typ(t) 497 498 case ONAME: 499 // variable or function 500 n = typecheck(n, Erv|Ecall) 501 if n == nil || n.Type == nil { 502 Fatalf("exporter: variable/function exported but not defined: %v", sym) 503 } 504 505 if n.Type.Etype == TFUNC && n.Class == PFUNC { 506 // function 507 p.tag(funcTag) 508 p.pos(n) 509 p.qualifiedName(sym) 510 511 sig := sym.Def.Type 512 inlineable := isInlineable(sym.Def) 513 514 p.paramList(sig.Params(), inlineable) 515 p.paramList(sig.Results(), inlineable) 516 517 var f *Func 518 if inlineable { 519 f = sym.Def.Func 520 reexportdeplist(f.Inl) 521 } 522 p.funcList = append(p.funcList, f) 523 } else { 524 // variable 525 p.tag(varTag) 526 p.pos(n) 527 p.qualifiedName(sym) 528 p.typ(sym.Def.Type) 529 } 530 531 default: 532 Fatalf("exporter: unexpected export symbol: %v %v", n.Op, sym) 533 } 534 } 535 536 func (p *exporter) pos(n *Node) { 537 if !p.posInfoFormat { 538 return 539 } 540 541 file, line := fileLine(n) 542 if file == p.prevFile { 543 // common case: write line delta 544 // delta == 0 means different file or no line change 545 delta := line - p.prevLine 546 p.int(delta) 547 if delta == 0 { 548 p.int(-1) // -1 means no file change 549 } 550 } else { 551 // different file 552 p.int(0) 553 // Encode filename as length of common prefix with previous 554 // filename, followed by (possibly empty) suffix. Filenames 555 // frequently share path prefixes, so this can save a lot 556 // of space and make export data size less dependent on file 557 // path length. The suffix is unlikely to be empty because 558 // file names tend to end in ".go". 559 n := commonPrefixLen(p.prevFile, file) 560 p.int(n) // n >= 0 561 p.string(file[n:]) // write suffix only 562 p.prevFile = file 563 p.int(line) 564 } 565 p.prevLine = line 566 } 567 568 func fileLine(n *Node) (file string, line int) { 569 if n != nil { 570 pos := Ctxt.PosTable.Pos(n.Pos) 571 file = pos.AbsFilename() 572 line = int(pos.Line()) 573 } 574 return 575 } 576 577 func commonPrefixLen(a, b string) int { 578 if len(a) > len(b) { 579 a, b = b, a 580 } 581 // len(a) <= len(b) 582 i := 0 583 for i < len(a) && a[i] == b[i] { 584 i++ 585 } 586 return i 587 } 588 589 func isInlineable(n *Node) bool { 590 if exportInlined && n != nil && n.Func != nil && n.Func.Inl.Len() != 0 { 591 // when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet. 592 // currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package 593 if Debug['l'] < 2 { 594 typecheckinl(n) 595 } 596 return true 597 } 598 return false 599 } 600 601 var errorInterface *Type // lazily initialized 602 603 func (p *exporter) typ(t *Type) { 604 if t == nil { 605 Fatalf("exporter: nil type") 606 } 607 608 // Possible optimization: Anonymous pointer types *T where 609 // T is a named type are common. We could canonicalize all 610 // such types *T to a single type PT = *T. This would lead 611 // to at most one *T entry in typIndex, and all future *T's 612 // would be encoded as the respective index directly. Would 613 // save 1 byte (pointerTag) per *T and reduce the typIndex 614 // size (at the cost of a canonicalization map). We can do 615 // this later, without encoding format change. 616 617 // if we saw the type before, write its index (>= 0) 618 if i, ok := p.typIndex[t]; ok { 619 p.index('T', i) 620 return 621 } 622 623 // otherwise, remember the type, write the type tag (< 0) and type data 624 if trackAllTypes { 625 if p.trace { 626 p.tracef("T%d = {>\n", len(p.typIndex)) 627 defer p.tracef("<\n} ") 628 } 629 p.typIndex[t] = len(p.typIndex) 630 } 631 632 // pick off named types 633 if tsym := t.Sym; tsym != nil { 634 if !trackAllTypes { 635 // if we don't track all types, track named types now 636 p.typIndex[t] = len(p.typIndex) 637 } 638 639 // Predeclared types should have been found in the type map. 640 if t.Orig == t { 641 Fatalf("exporter: predeclared type missing from type map?") 642 } 643 644 n := typenod(t) 645 if n.Type != t { 646 Fatalf("exporter: named type definition incorrectly set up") 647 } 648 649 p.tag(namedTag) 650 p.pos(n) 651 p.qualifiedName(tsym) 652 653 // write underlying type 654 orig := t.Orig 655 if orig == errortype { 656 // The error type is the only predeclared type which has 657 // a composite underlying type. When we encode that type, 658 // make sure to encode the underlying interface rather than 659 // the named type again. See also the comment in universe.go 660 // regarding the errortype and issue #15920. 661 if errorInterface == nil { 662 errorInterface = makeErrorInterface() 663 } 664 orig = errorInterface 665 } 666 p.typ(orig) 667 668 // interfaces don't have associated methods 669 if t.Orig.IsInterface() { 670 return 671 } 672 673 // sort methods for reproducible export format 674 // TODO(gri) Determine if they are already sorted 675 // in which case we can drop this step. 676 var methods []*Field 677 for _, m := range t.Methods().Slice() { 678 methods = append(methods, m) 679 } 680 sort.Sort(methodbyname(methods)) 681 p.int(len(methods)) 682 683 if p.trace && len(methods) > 0 { 684 p.tracef("associated methods {>") 685 } 686 687 for _, m := range methods { 688 if p.trace { 689 p.tracef("\n") 690 } 691 if strings.Contains(m.Sym.Name, ".") { 692 Fatalf("invalid symbol name: %s (%v)", m.Sym.Name, m.Sym) 693 } 694 695 p.pos(m.Nname) 696 p.fieldSym(m.Sym, false) 697 698 sig := m.Type 699 mfn := sig.Nname() 700 inlineable := isInlineable(mfn) 701 702 p.paramList(sig.Recvs(), inlineable) 703 p.paramList(sig.Params(), inlineable) 704 p.paramList(sig.Results(), inlineable) 705 p.bool(m.Nointerface) // record go:nointerface pragma value (see also #16243) 706 707 var f *Func 708 if inlineable { 709 f = mfn.Func 710 reexportdeplist(f.Inl) 711 } 712 p.funcList = append(p.funcList, f) 713 } 714 715 if p.trace && len(methods) > 0 { 716 p.tracef("<\n} ") 717 } 718 719 return 720 } 721 722 // otherwise we have a type literal 723 switch t.Etype { 724 case TARRAY: 725 if t.isDDDArray() { 726 Fatalf("array bounds should be known at export time: %v", t) 727 } 728 p.tag(arrayTag) 729 p.int64(t.NumElem()) 730 p.typ(t.Elem()) 731 732 case TSLICE: 733 p.tag(sliceTag) 734 p.typ(t.Elem()) 735 736 case TDDDFIELD: 737 // see p.param use of TDDDFIELD 738 p.tag(dddTag) 739 p.typ(t.DDDField()) 740 741 case TSTRUCT: 742 p.tag(structTag) 743 p.fieldList(t) 744 745 case TPTR32, TPTR64: // could use Tptr but these are constants 746 p.tag(pointerTag) 747 p.typ(t.Elem()) 748 749 case TFUNC: 750 p.tag(signatureTag) 751 p.paramList(t.Params(), false) 752 p.paramList(t.Results(), false) 753 754 case TINTER: 755 p.tag(interfaceTag) 756 // gc doesn't separate between embedded interfaces 757 // and methods declared explicitly with an interface 758 p.int(0) // no embedded interfaces 759 760 // Because the compiler flattens interfaces containing 761 // embedded interfaces, it is possible to create interface 762 // types that recur through an unnamed type. 763 // If trackAllTypes is disabled, such recursion is not 764 // detected, leading to a stack overflow during export 765 // (issue #16369). 766 // As a crude work-around we terminate deep recursion 767 // through interface types with an empty interface and 768 // report an error. 769 // This will catch endless recursion, but is unlikely 770 // to trigger for valid, deeply nested types given the 771 // high threshold. 772 // It would be ok to continue without reporting an error 773 // since the export format is valid. But a subsequent 774 // import would import an incorrect type. The textual 775 // exporter does not report an error but importing the 776 // resulting package will lead to a syntax error during 777 // import. 778 // TODO(gri) remove this once we have a permanent fix 779 // for the issue. 780 if p.nesting > 100 { 781 p.int(0) // 0 methods to indicate empty interface 782 yyerrorl(t.Pos, "cannot export unnamed recursive interface") 783 break 784 } 785 786 p.nesting++ 787 p.methodList(t) 788 p.nesting-- 789 790 case TMAP: 791 p.tag(mapTag) 792 p.typ(t.Key()) 793 p.typ(t.Val()) 794 795 case TCHAN: 796 p.tag(chanTag) 797 p.int(int(t.ChanDir())) 798 p.typ(t.Elem()) 799 800 default: 801 Fatalf("exporter: unexpected type: %v (Etype = %d)", t, t.Etype) 802 } 803 } 804 805 func (p *exporter) qualifiedName(sym *Sym) { 806 p.string(sym.Name) 807 p.pkg(sym.Pkg) 808 } 809 810 func (p *exporter) fieldList(t *Type) { 811 if p.trace && t.NumFields() > 0 { 812 p.tracef("fields {>") 813 defer p.tracef("<\n} ") 814 } 815 816 p.int(t.NumFields()) 817 for _, f := range t.Fields().Slice() { 818 if p.trace { 819 p.tracef("\n") 820 } 821 p.field(f) 822 } 823 } 824 825 func (p *exporter) field(f *Field) { 826 p.pos(f.Nname) 827 p.fieldName(f) 828 p.typ(f.Type) 829 p.string(f.Note) 830 } 831 832 func (p *exporter) methodList(t *Type) { 833 if p.trace && t.NumFields() > 0 { 834 p.tracef("methods {>") 835 defer p.tracef("<\n} ") 836 } 837 838 p.int(t.NumFields()) 839 for _, m := range t.Fields().Slice() { 840 if p.trace { 841 p.tracef("\n") 842 } 843 p.method(m) 844 } 845 } 846 847 func (p *exporter) method(m *Field) { 848 p.pos(m.Nname) 849 p.methodName(m.Sym) 850 p.paramList(m.Type.Params(), false) 851 p.paramList(m.Type.Results(), false) 852 } 853 854 func (p *exporter) fieldName(t *Field) { 855 name := t.Sym.Name 856 if t.Embedded != 0 { 857 // anonymous field - we distinguish between 3 cases: 858 // 1) field name matches base type name and is exported 859 // 2) field name matches base type name and is not exported 860 // 3) field name doesn't match base type name (alias name) 861 bname := basetypeName(t.Type) 862 if name == bname { 863 if exportname(name) { 864 name = "" // 1) we don't need to know the field name or package 865 } else { 866 name = "?" // 2) use unexported name "?" to force package export 867 } 868 } else { 869 // 3) indicate alias and export name as is 870 // (this requires an extra "@" but this is a rare case) 871 p.string("@") 872 } 873 } 874 p.string(name) 875 if name != "" && !exportname(name) { 876 p.pkg(t.Sym.Pkg) 877 } 878 } 879 880 // methodName is like qualifiedName but it doesn't record the package for exported names. 881 func (p *exporter) methodName(sym *Sym) { 882 p.string(sym.Name) 883 if !exportname(sym.Name) { 884 p.pkg(sym.Pkg) 885 } 886 } 887 888 func basetypeName(t *Type) string { 889 s := t.Sym 890 if s == nil && t.IsPtr() { 891 s = t.Elem().Sym // deref 892 } 893 if s != nil { 894 return s.Name 895 } 896 return "" // unnamed type 897 } 898 899 func (p *exporter) paramList(params *Type, numbered bool) { 900 if !params.IsFuncArgStruct() { 901 Fatalf("exporter: parameter list expected") 902 } 903 904 // use negative length to indicate unnamed parameters 905 // (look at the first parameter only since either all 906 // names are present or all are absent) 907 // 908 // TODO(gri) If we don't have an exported function 909 // body, the parameter names are irrelevant for the 910 // compiler (though they may be of use for other tools). 911 // Possible space optimization. 912 n := params.NumFields() 913 if n > 0 && parName(params.Field(0), numbered) == "" { 914 n = -n 915 } 916 p.int(n) 917 for _, q := range params.Fields().Slice() { 918 p.param(q, n, numbered) 919 } 920 } 921 922 func (p *exporter) param(q *Field, n int, numbered bool) { 923 t := q.Type 924 if q.Isddd { 925 // create a fake type to encode ... just for the p.typ call 926 t = typDDDField(t.Elem()) 927 } 928 p.typ(t) 929 if n > 0 { 930 name := parName(q, numbered) 931 if name == "" { 932 // Sometimes we see an empty name even for n > 0. 933 // This appears to happen for interface methods 934 // with _ (blank) parameter names. Make sure we 935 // have a proper name and package so we don't crash 936 // during import (see also issue #15470). 937 // (parName uses "" instead of "?" as in fmt.go) 938 // TODO(gri) review parameter name encoding 939 name = "_" 940 } 941 p.string(name) 942 if name != "_" { 943 // Because of (re-)exported inlined functions 944 // the importpkg may not be the package to which this 945 // function (and thus its parameter) belongs. We need to 946 // supply the parameter package here. We need the package 947 // when the function is inlined so we can properly resolve 948 // the name. The _ (blank) parameter cannot be accessed, so 949 // we don't need to export a package. 950 // 951 // TODO(gri) This is compiler-specific. Try using importpkg 952 // here and then update the symbols if we find an inlined 953 // body only. Otherwise, the parameter name is ignored and 954 // the package doesn't matter. This would remove an int 955 // (likely 1 byte) for each named parameter. 956 p.pkg(q.Sym.Pkg) 957 } 958 } 959 // TODO(gri) This is compiler-specific (escape info). 960 // Move into compiler-specific section eventually? 961 // (Not having escape info causes tests to fail, e.g. runtime GCInfoTest) 962 p.string(q.Note) 963 } 964 965 func parName(f *Field, numbered bool) string { 966 s := f.Sym 967 if s == nil { 968 return "" 969 } 970 971 // Take the name from the original, lest we substituted it with ~r%d or ~b%d. 972 // ~r%d is a (formerly) unnamed result. 973 if f.Nname != nil { 974 if f.Nname.Orig != nil { 975 s = f.Nname.Orig.Sym 976 if s != nil && s.Name[0] == '~' { 977 if s.Name[1] == 'r' { // originally an unnamed result 978 return "" // s = nil 979 } else if s.Name[1] == 'b' { // originally the blank identifier _ 980 return "_" // belongs to localpkg 981 } 982 } 983 } else { 984 return "" // s = nil 985 } 986 } 987 988 if s == nil { 989 return "" 990 } 991 992 // print symbol with Vargen number or not as desired 993 name := s.Name 994 if strings.Contains(name, ".") { 995 Fatalf("invalid symbol name: %s", name) 996 } 997 998 // Functions that can be inlined use numbered parameters so we can distinguish them 999 // from other names in their context after inlining (i.e., the parameter numbering 1000 // is a form of parameter rewriting). See issue 4326 for an example and test case. 1001 if forceObjFileStability || numbered { 1002 if !strings.Contains(name, "·") && f.Nname != nil && f.Nname.Name != nil && f.Nname.Name.Vargen > 0 { 1003 name = fmt.Sprintf("%s·%d", name, f.Nname.Name.Vargen) // append Vargen 1004 } 1005 } else { 1006 if i := strings.Index(name, "·"); i > 0 { 1007 name = name[:i] // cut off Vargen 1008 } 1009 } 1010 return name 1011 } 1012 1013 func (p *exporter) value(x Val) { 1014 if p.trace { 1015 p.tracef("= ") 1016 } 1017 1018 switch x := x.U.(type) { 1019 case bool: 1020 tag := falseTag 1021 if x { 1022 tag = trueTag 1023 } 1024 p.tag(tag) 1025 1026 case *Mpint: 1027 if minintval[TINT64].Cmp(x) <= 0 && x.Cmp(maxintval[TINT64]) <= 0 { 1028 // common case: x fits into an int64 - use compact encoding 1029 p.tag(int64Tag) 1030 p.int64(x.Int64()) 1031 return 1032 } 1033 // uncommon case: large x - use float encoding 1034 // (powers of 2 will be encoded efficiently with exponent) 1035 f := newMpflt() 1036 f.SetInt(x) 1037 p.tag(floatTag) 1038 p.float(f) 1039 1040 case *Mpflt: 1041 p.tag(floatTag) 1042 p.float(x) 1043 1044 case *Mpcplx: 1045 p.tag(complexTag) 1046 p.float(&x.Real) 1047 p.float(&x.Imag) 1048 1049 case string: 1050 p.tag(stringTag) 1051 p.string(x) 1052 1053 case *NilVal: 1054 // not a constant but used in exported function bodies 1055 p.tag(nilTag) 1056 1057 default: 1058 Fatalf("exporter: unexpected value %v (%T)", x, x) 1059 } 1060 } 1061 1062 func (p *exporter) float(x *Mpflt) { 1063 // extract sign (there is no -0) 1064 f := &x.Val 1065 sign := f.Sign() 1066 if sign == 0 { 1067 // x == 0 1068 p.int(0) 1069 return 1070 } 1071 // x != 0 1072 1073 // extract exponent such that 0.5 <= m < 1.0 1074 var m big.Float 1075 exp := f.MantExp(&m) 1076 1077 // extract mantissa as *big.Int 1078 // - set exponent large enough so mant satisfies mant.IsInt() 1079 // - get *big.Int from mant 1080 m.SetMantExp(&m, int(m.MinPrec())) 1081 mant, acc := m.Int(nil) 1082 if acc != big.Exact { 1083 Fatalf("exporter: internal error") 1084 } 1085 1086 p.int(sign) 1087 p.int(exp) 1088 p.string(string(mant.Bytes())) 1089 } 1090 1091 // ---------------------------------------------------------------------------- 1092 // Inlined function bodies 1093 1094 // Approach: More or less closely follow what fmt.go is doing for FExp mode 1095 // but instead of emitting the information textually, emit the node tree in 1096 // binary form. 1097 1098 // TODO(gri) Improve tracing output. The current format is difficult to read. 1099 1100 // stmtList may emit more (or fewer) than len(list) nodes. 1101 func (p *exporter) stmtList(list Nodes) { 1102 if p.trace { 1103 if list.Len() == 0 { 1104 p.tracef("{}") 1105 } else { 1106 p.tracef("{>") 1107 defer p.tracef("<\n}") 1108 } 1109 } 1110 1111 for _, n := range list.Slice() { 1112 if p.trace { 1113 p.tracef("\n") 1114 } 1115 // TODO inlining produces expressions with ninits. we can't export these yet. 1116 // (from fmt.go:1461ff) 1117 if opprec[n.Op] < 0 { 1118 p.stmt(n) 1119 } else { 1120 p.expr(n) 1121 } 1122 } 1123 1124 p.op(OEND) 1125 } 1126 1127 func (p *exporter) exprList(list Nodes) { 1128 if p.trace { 1129 if list.Len() == 0 { 1130 p.tracef("{}") 1131 } else { 1132 p.tracef("{>") 1133 defer p.tracef("<\n}") 1134 } 1135 } 1136 1137 for _, n := range list.Slice() { 1138 if p.trace { 1139 p.tracef("\n") 1140 } 1141 p.expr(n) 1142 } 1143 1144 p.op(OEND) 1145 } 1146 1147 func (p *exporter) elemList(list Nodes) { 1148 if p.trace { 1149 p.tracef("[ ") 1150 } 1151 p.int(list.Len()) 1152 if p.trace { 1153 if list.Len() == 0 { 1154 p.tracef("] {}") 1155 } else { 1156 p.tracef("] {>") 1157 defer p.tracef("<\n}") 1158 } 1159 } 1160 1161 for _, n := range list.Slice() { 1162 if p.trace { 1163 p.tracef("\n") 1164 } 1165 p.fieldSym(n.Sym, false) 1166 p.expr(n.Left) 1167 } 1168 } 1169 1170 func (p *exporter) expr(n *Node) { 1171 if p.trace { 1172 p.tracef("( ") 1173 defer p.tracef(") ") 1174 } 1175 1176 // from nodefmt (fmt.go) 1177 // 1178 // nodefmt reverts nodes back to their original - we don't need to do 1179 // it because we are not bound to produce valid Go syntax when exporting 1180 // 1181 // if (fmtmode != FExp || n.Op != OLITERAL) && n.Orig != nil { 1182 // n = n.Orig 1183 // } 1184 1185 // from exprfmt (fmt.go) 1186 for n != nil && n.Implicit && (n.Op == OIND || n.Op == OADDR) { 1187 n = n.Left 1188 } 1189 1190 switch op := n.Op; op { 1191 // expressions 1192 // (somewhat closely following the structure of exprfmt in fmt.go) 1193 case OPAREN: 1194 p.expr(n.Left) // unparen 1195 1196 // case ODDDARG: 1197 // unimplemented - handled by default case 1198 1199 case OLITERAL: 1200 if n.Val().Ctype() == CTNIL && n.Orig != nil && n.Orig != n { 1201 p.expr(n.Orig) 1202 break 1203 } 1204 p.op(OLITERAL) 1205 p.typ(unidealType(n.Type, n.Val())) 1206 p.value(n.Val()) 1207 1208 case ONAME: 1209 // Special case: name used as local variable in export. 1210 // _ becomes ~b%d internally; print as _ for export 1211 if n.Sym != nil && n.Sym.Name[0] == '~' && n.Sym.Name[1] == 'b' { 1212 p.op(ONAME) 1213 p.string("_") // inlined and customized version of p.sym(n) 1214 break 1215 } 1216 1217 if n.Sym != nil && !isblank(n) && n.Name.Vargen > 0 { 1218 p.op(ONAME) 1219 p.sym(n) 1220 break 1221 } 1222 1223 // Special case: explicit name of func (*T) method(...) is turned into pkg.(*T).method, 1224 // but for export, this should be rendered as (*pkg.T).meth. 1225 // These nodes have the special property that they are names with a left OTYPE and a right ONAME. 1226 if n.Left != nil && n.Left.Op == OTYPE && n.Right != nil && n.Right.Op == ONAME { 1227 p.op(OXDOT) 1228 p.expr(n.Left) // n.Left.Op == OTYPE 1229 p.fieldSym(n.Right.Sym, true) 1230 break 1231 } 1232 1233 p.op(ONAME) 1234 p.sym(n) 1235 1236 // case OPACK, ONONAME: 1237 // should have been resolved by typechecking - handled by default case 1238 1239 case OTYPE: 1240 p.op(OTYPE) 1241 if p.bool(n.Type == nil) { 1242 p.sym(n) 1243 } else { 1244 p.typ(n.Type) 1245 } 1246 1247 // case OTARRAY, OTMAP, OTCHAN, OTSTRUCT, OTINTER, OTFUNC: 1248 // should have been resolved by typechecking - handled by default case 1249 1250 // case OCLOSURE: 1251 // unimplemented - handled by default case 1252 1253 // case OCOMPLIT: 1254 // should have been resolved by typechecking - handled by default case 1255 1256 case OPTRLIT: 1257 p.op(OPTRLIT) 1258 p.expr(n.Left) 1259 p.bool(n.Implicit) 1260 1261 case OSTRUCTLIT: 1262 p.op(OSTRUCTLIT) 1263 p.typ(n.Type) 1264 p.elemList(n.List) // special handling of field names 1265 1266 case OARRAYLIT, OSLICELIT, OMAPLIT: 1267 p.op(OCOMPLIT) 1268 p.typ(n.Type) 1269 p.exprList(n.List) 1270 1271 case OKEY: 1272 p.op(OKEY) 1273 p.exprsOrNil(n.Left, n.Right) 1274 1275 // case OSTRUCTKEY: 1276 // unreachable - handled in case OSTRUCTLIT by elemList 1277 1278 // case OCALLPART: 1279 // unimplemented - handled by default case 1280 1281 case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH: 1282 p.op(OXDOT) 1283 p.expr(n.Left) 1284 p.fieldSym(n.Sym, true) 1285 1286 case ODOTTYPE, ODOTTYPE2: 1287 p.op(ODOTTYPE) 1288 p.expr(n.Left) 1289 if p.bool(n.Right != nil) { 1290 p.expr(n.Right) 1291 } else { 1292 p.typ(n.Type) 1293 } 1294 1295 case OINDEX, OINDEXMAP: 1296 p.op(OINDEX) 1297 p.expr(n.Left) 1298 p.expr(n.Right) 1299 1300 case OSLICE, OSLICESTR, OSLICEARR: 1301 p.op(OSLICE) 1302 p.expr(n.Left) 1303 low, high, _ := n.SliceBounds() 1304 p.exprsOrNil(low, high) 1305 1306 case OSLICE3, OSLICE3ARR: 1307 p.op(OSLICE3) 1308 p.expr(n.Left) 1309 low, high, max := n.SliceBounds() 1310 p.exprsOrNil(low, high) 1311 p.expr(max) 1312 1313 case OCOPY, OCOMPLEX: 1314 // treated like other builtin calls (see e.g., OREAL) 1315 p.op(op) 1316 p.expr(n.Left) 1317 p.expr(n.Right) 1318 p.op(OEND) 1319 1320 case OCONV, OCONVIFACE, OCONVNOP, OARRAYBYTESTR, OARRAYRUNESTR, OSTRARRAYBYTE, OSTRARRAYRUNE, ORUNESTR: 1321 p.op(OCONV) 1322 p.typ(n.Type) 1323 if n.Left != nil { 1324 p.expr(n.Left) 1325 p.op(OEND) 1326 } else { 1327 p.exprList(n.List) // emits terminating OEND 1328 } 1329 1330 case OREAL, OIMAG, OAPPEND, OCAP, OCLOSE, ODELETE, OLEN, OMAKE, ONEW, OPANIC, ORECOVER, OPRINT, OPRINTN: 1331 p.op(op) 1332 if n.Left != nil { 1333 p.expr(n.Left) 1334 p.op(OEND) 1335 } else { 1336 p.exprList(n.List) // emits terminating OEND 1337 } 1338 // only append() calls may contain '...' arguments 1339 if op == OAPPEND { 1340 p.bool(n.Isddd) 1341 } else if n.Isddd { 1342 Fatalf("exporter: unexpected '...' with %s call", opnames[op]) 1343 } 1344 1345 case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER, OGETG: 1346 p.op(OCALL) 1347 p.expr(n.Left) 1348 p.exprList(n.List) 1349 p.bool(n.Isddd) 1350 1351 case OMAKEMAP, OMAKECHAN, OMAKESLICE: 1352 p.op(op) // must keep separate from OMAKE for importer 1353 p.typ(n.Type) 1354 switch { 1355 default: 1356 // empty list 1357 p.op(OEND) 1358 case n.List.Len() != 0: // pre-typecheck 1359 p.exprList(n.List) // emits terminating OEND 1360 case n.Right != nil: 1361 p.expr(n.Left) 1362 p.expr(n.Right) 1363 p.op(OEND) 1364 case n.Left != nil && (n.Op == OMAKESLICE || !n.Left.Type.IsUntyped()): 1365 p.expr(n.Left) 1366 p.op(OEND) 1367 } 1368 1369 // unary expressions 1370 case OPLUS, OMINUS, OADDR, OCOM, OIND, ONOT, ORECV: 1371 p.op(op) 1372 p.expr(n.Left) 1373 1374 // binary expressions 1375 case OADD, OAND, OANDAND, OANDNOT, ODIV, OEQ, OGE, OGT, OLE, OLT, 1376 OLSH, OMOD, OMUL, ONE, OOR, OOROR, ORSH, OSEND, OSUB, OXOR: 1377 p.op(op) 1378 p.expr(n.Left) 1379 p.expr(n.Right) 1380 1381 case OADDSTR: 1382 p.op(OADDSTR) 1383 p.exprList(n.List) 1384 1385 case OCMPSTR, OCMPIFACE: 1386 p.op(Op(n.Etype)) 1387 p.expr(n.Left) 1388 p.expr(n.Right) 1389 1390 case ODCLCONST: 1391 // if exporting, DCLCONST should just be removed as its usage 1392 // has already been replaced with literals 1393 // TODO(gri) these should not be exported in the first place 1394 // TODO(gri) why is this considered an expression in fmt.go? 1395 p.op(ODCLCONST) 1396 1397 default: 1398 Fatalf("cannot export %v (%d) node\n"+ 1399 "==> please file an issue and assign to gri@\n", n.Op, int(n.Op)) 1400 } 1401 } 1402 1403 // Caution: stmt will emit more than one node for statement nodes n that have a non-empty 1404 // n.Ninit and where n cannot have a natural init section (such as in "if", "for", etc.). 1405 func (p *exporter) stmt(n *Node) { 1406 if p.trace { 1407 p.tracef("( ") 1408 defer p.tracef(") ") 1409 } 1410 1411 if n.Ninit.Len() > 0 && !stmtwithinit(n.Op) { 1412 if p.trace { 1413 p.tracef("( /* Ninits */ ") 1414 } 1415 1416 // can't use stmtList here since we don't want the final OEND 1417 for _, n := range n.Ninit.Slice() { 1418 p.stmt(n) 1419 } 1420 1421 if p.trace { 1422 p.tracef(") ") 1423 } 1424 } 1425 1426 switch op := n.Op; op { 1427 case ODCL: 1428 p.op(ODCL) 1429 p.sym(n.Left) 1430 p.typ(n.Left.Type) 1431 1432 // case ODCLFIELD: 1433 // unimplemented - handled by default case 1434 1435 case OAS: 1436 // Don't export "v = <N>" initializing statements, hope they're always 1437 // preceded by the DCL which will be re-parsed and typecheck to reproduce 1438 // the "v = <N>" again. 1439 if n.Right != nil { 1440 p.op(OAS) 1441 p.expr(n.Left) 1442 p.expr(n.Right) 1443 } 1444 1445 case OASOP: 1446 p.op(OASOP) 1447 p.int(int(n.Etype)) 1448 p.expr(n.Left) 1449 if p.bool(!n.Implicit) { 1450 p.expr(n.Right) 1451 } 1452 1453 case OAS2, OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV: 1454 p.op(OAS2) 1455 p.exprList(n.List) 1456 p.exprList(n.Rlist) 1457 1458 case ORETURN: 1459 p.op(ORETURN) 1460 p.exprList(n.List) 1461 1462 // case ORETJMP: 1463 // unreachable - generated by compiler for trampolin routines 1464 1465 case OPROC, ODEFER: 1466 p.op(op) 1467 p.expr(n.Left) 1468 1469 case OIF: 1470 p.op(OIF) 1471 p.stmtList(n.Ninit) 1472 p.expr(n.Left) 1473 p.stmtList(n.Nbody) 1474 p.stmtList(n.Rlist) 1475 1476 case OFOR: 1477 p.op(OFOR) 1478 p.stmtList(n.Ninit) 1479 p.exprsOrNil(n.Left, n.Right) 1480 p.stmtList(n.Nbody) 1481 1482 case ORANGE: 1483 p.op(ORANGE) 1484 p.stmtList(n.List) 1485 p.expr(n.Right) 1486 p.stmtList(n.Nbody) 1487 1488 case OSELECT, OSWITCH: 1489 p.op(op) 1490 p.stmtList(n.Ninit) 1491 p.exprsOrNil(n.Left, nil) 1492 p.stmtList(n.List) 1493 1494 case OCASE, OXCASE: 1495 p.op(OXCASE) 1496 p.stmtList(n.List) 1497 p.stmtList(n.Nbody) 1498 1499 case OFALL, OXFALL: 1500 p.op(OXFALL) 1501 1502 case OBREAK, OCONTINUE: 1503 p.op(op) 1504 p.exprsOrNil(n.Left, nil) 1505 1506 case OEMPTY: 1507 // nothing to emit 1508 1509 case OGOTO, OLABEL: 1510 p.op(op) 1511 p.expr(n.Left) 1512 1513 default: 1514 Fatalf("exporter: CANNOT EXPORT: %v\nPlease notify gri@\n", n.Op) 1515 } 1516 } 1517 1518 func (p *exporter) exprsOrNil(a, b *Node) { 1519 ab := 0 1520 if a != nil { 1521 ab |= 1 1522 } 1523 if b != nil { 1524 ab |= 2 1525 } 1526 p.int(ab) 1527 if ab&1 != 0 { 1528 p.expr(a) 1529 } 1530 if ab&2 != 0 { 1531 p.expr(b) 1532 } 1533 } 1534 1535 func (p *exporter) fieldSym(s *Sym, short bool) { 1536 name := s.Name 1537 1538 // remove leading "type." in method names ("(T).m" -> "m") 1539 if short { 1540 if i := strings.LastIndex(name, "."); i >= 0 { 1541 name = name[i+1:] 1542 } 1543 } 1544 1545 // we should never see a _ (blank) here - these are accessible ("read") fields 1546 // TODO(gri) can we assert this with an explicit check? 1547 p.string(name) 1548 if !exportname(name) { 1549 p.pkg(s.Pkg) 1550 } 1551 } 1552 1553 // sym must encode the _ (blank) identifier as a single string "_" since 1554 // encoding for some nodes is based on this assumption (e.g. ONAME nodes). 1555 func (p *exporter) sym(n *Node) { 1556 s := n.Sym 1557 if s.Pkg != nil { 1558 if len(s.Name) > 0 && s.Name[0] == '.' { 1559 Fatalf("exporter: exporting synthetic symbol %s", s.Name) 1560 } 1561 } 1562 1563 if p.trace { 1564 p.tracef("{ SYM ") 1565 defer p.tracef("} ") 1566 } 1567 1568 name := s.Name 1569 1570 // remove leading "type." in method names ("(T).m" -> "m") 1571 if i := strings.LastIndex(name, "."); i >= 0 { 1572 name = name[i+1:] 1573 } 1574 1575 if strings.Contains(name, "·") && n.Name.Vargen > 0 { 1576 Fatalf("exporter: unexpected · in symbol name") 1577 } 1578 1579 if i := n.Name.Vargen; i > 0 { 1580 name = fmt.Sprintf("%s·%d", name, i) 1581 } 1582 1583 p.string(name) 1584 if name != "_" { 1585 p.pkg(s.Pkg) 1586 } 1587 // Fixes issue #18167. 1588 p.string(s.Linkname) 1589 } 1590 1591 func (p *exporter) bool(b bool) bool { 1592 if p.trace { 1593 p.tracef("[") 1594 defer p.tracef("= %v] ", b) 1595 } 1596 1597 x := 0 1598 if b { 1599 x = 1 1600 } 1601 p.int(x) 1602 return b 1603 } 1604 1605 func (p *exporter) op(op Op) { 1606 if p.trace { 1607 p.tracef("[") 1608 defer p.tracef("= %v] ", op) 1609 } 1610 1611 p.int(int(op)) 1612 } 1613 1614 // ---------------------------------------------------------------------------- 1615 // Low-level encoders 1616 1617 func (p *exporter) index(marker byte, index int) { 1618 if index < 0 { 1619 Fatalf("exporter: invalid index < 0") 1620 } 1621 if debugFormat { 1622 p.marker('t') 1623 } 1624 if p.trace { 1625 p.tracef("%c%d ", marker, index) 1626 } 1627 p.rawInt64(int64(index)) 1628 } 1629 1630 func (p *exporter) tag(tag int) { 1631 if tag >= 0 { 1632 Fatalf("exporter: invalid tag >= 0") 1633 } 1634 if debugFormat { 1635 p.marker('t') 1636 } 1637 if p.trace { 1638 p.tracef("%s ", tagString[-tag]) 1639 } 1640 p.rawInt64(int64(tag)) 1641 } 1642 1643 func (p *exporter) int(x int) { 1644 p.int64(int64(x)) 1645 } 1646 1647 func (p *exporter) int64(x int64) { 1648 if debugFormat { 1649 p.marker('i') 1650 } 1651 if p.trace { 1652 p.tracef("%d ", x) 1653 } 1654 p.rawInt64(x) 1655 } 1656 1657 func (p *exporter) string(s string) { 1658 if debugFormat { 1659 p.marker('s') 1660 } 1661 if p.trace { 1662 p.tracef("%q ", s) 1663 } 1664 // if we saw the string before, write its index (>= 0) 1665 // (the empty string is mapped to 0) 1666 if i, ok := p.strIndex[s]; ok { 1667 p.rawInt64(int64(i)) 1668 return 1669 } 1670 // otherwise, remember string and write its negative length and bytes 1671 p.strIndex[s] = len(p.strIndex) 1672 p.rawInt64(-int64(len(s))) 1673 for i := 0; i < len(s); i++ { 1674 p.rawByte(s[i]) 1675 } 1676 } 1677 1678 // marker emits a marker byte and position information which makes 1679 // it easy for a reader to detect if it is "out of sync". Used only 1680 // if debugFormat is set. 1681 func (p *exporter) marker(m byte) { 1682 p.rawByte(m) 1683 // Uncomment this for help tracking down the location 1684 // of an incorrect marker when running in debugFormat. 1685 // if p.trace { 1686 // p.tracef("#%d ", p.written) 1687 // } 1688 p.rawInt64(int64(p.written)) 1689 } 1690 1691 // rawInt64 should only be used by low-level encoders. 1692 func (p *exporter) rawInt64(x int64) { 1693 var tmp [binary.MaxVarintLen64]byte 1694 n := binary.PutVarint(tmp[:], x) 1695 for i := 0; i < n; i++ { 1696 p.rawByte(tmp[i]) 1697 } 1698 } 1699 1700 // rawStringln should only be used to emit the initial version string. 1701 func (p *exporter) rawStringln(s string) { 1702 for i := 0; i < len(s); i++ { 1703 p.rawByte(s[i]) 1704 } 1705 p.rawByte('\n') 1706 } 1707 1708 // rawByte is the bottleneck interface to write to p.out. 1709 // rawByte escapes b as follows (any encoding does that 1710 // hides '$'): 1711 // 1712 // '$' => '|' 'S' 1713 // '|' => '|' '|' 1714 // 1715 // Necessary so other tools can find the end of the 1716 // export data by searching for "$$". 1717 // rawByte should only be used by low-level encoders. 1718 func (p *exporter) rawByte(b byte) { 1719 switch b { 1720 case '$': 1721 // write '$' as '|' 'S' 1722 b = 'S' 1723 fallthrough 1724 case '|': 1725 // write '|' as '|' '|' 1726 p.out.WriteByte('|') 1727 p.written++ 1728 } 1729 p.out.WriteByte(b) 1730 p.written++ 1731 } 1732 1733 // tracef is like fmt.Printf but it rewrites the format string 1734 // to take care of indentation. 1735 func (p *exporter) tracef(format string, args ...interface{}) { 1736 if strings.ContainsAny(format, "<>\n") { 1737 var buf bytes.Buffer 1738 for i := 0; i < len(format); i++ { 1739 // no need to deal with runes 1740 ch := format[i] 1741 switch ch { 1742 case '>': 1743 p.indent++ 1744 continue 1745 case '<': 1746 p.indent-- 1747 continue 1748 } 1749 buf.WriteByte(ch) 1750 if ch == '\n' { 1751 for j := p.indent; j > 0; j-- { 1752 buf.WriteString(". ") 1753 } 1754 } 1755 } 1756 format = buf.String() 1757 } 1758 fmt.Printf(format, args...) 1759 } 1760 1761 // ---------------------------------------------------------------------------- 1762 // Export format 1763 1764 // Tags. Must be < 0. 1765 const ( 1766 // Objects 1767 packageTag = -(iota + 1) 1768 constTag 1769 typeTag 1770 varTag 1771 funcTag 1772 endTag 1773 1774 // Types 1775 namedTag 1776 arrayTag 1777 sliceTag 1778 dddTag 1779 structTag 1780 pointerTag 1781 signatureTag 1782 interfaceTag 1783 mapTag 1784 chanTag 1785 1786 // Values 1787 falseTag 1788 trueTag 1789 int64Tag 1790 floatTag 1791 fractionTag // not used by gc 1792 complexTag 1793 stringTag 1794 nilTag 1795 unknownTag // not used by gc (only appears in packages with errors) 1796 1797 // Type aliases 1798 aliasTag 1799 ) 1800 1801 // Debugging support. 1802 // (tagString is only used when tracing is enabled) 1803 var tagString = [...]string{ 1804 // Objects 1805 -packageTag: "package", 1806 -constTag: "const", 1807 -typeTag: "type", 1808 -varTag: "var", 1809 -funcTag: "func", 1810 -endTag: "end", 1811 1812 // Types 1813 -namedTag: "named type", 1814 -arrayTag: "array", 1815 -sliceTag: "slice", 1816 -dddTag: "ddd", 1817 -structTag: "struct", 1818 -pointerTag: "pointer", 1819 -signatureTag: "signature", 1820 -interfaceTag: "interface", 1821 -mapTag: "map", 1822 -chanTag: "chan", 1823 1824 // Values 1825 -falseTag: "false", 1826 -trueTag: "true", 1827 -int64Tag: "int64", 1828 -floatTag: "float", 1829 -fractionTag: "fraction", 1830 -complexTag: "complex", 1831 -stringTag: "string", 1832 -nilTag: "nil", 1833 -unknownTag: "unknown", 1834 1835 // Type aliases 1836 -aliasTag: "alias", 1837 } 1838 1839 // untype returns the "pseudo" untyped type for a Ctype (import/export use only). 1840 // (we can't use an pre-initialized array because we must be sure all types are 1841 // set up) 1842 func untype(ctype Ctype) *Type { 1843 switch ctype { 1844 case CTINT: 1845 return idealint 1846 case CTRUNE: 1847 return idealrune 1848 case CTFLT: 1849 return idealfloat 1850 case CTCPLX: 1851 return idealcomplex 1852 case CTSTR: 1853 return idealstring 1854 case CTBOOL: 1855 return idealbool 1856 case CTNIL: 1857 return Types[TNIL] 1858 } 1859 Fatalf("exporter: unknown Ctype") 1860 return nil 1861 } 1862 1863 var predecl []*Type // initialized lazily 1864 1865 func predeclared() []*Type { 1866 if predecl == nil { 1867 // initialize lazily to be sure that all 1868 // elements have been initialized before 1869 predecl = []*Type{ 1870 // basic types 1871 Types[TBOOL], 1872 Types[TINT], 1873 Types[TINT8], 1874 Types[TINT16], 1875 Types[TINT32], 1876 Types[TINT64], 1877 Types[TUINT], 1878 Types[TUINT8], 1879 Types[TUINT16], 1880 Types[TUINT32], 1881 Types[TUINT64], 1882 Types[TUINTPTR], 1883 Types[TFLOAT32], 1884 Types[TFLOAT64], 1885 Types[TCOMPLEX64], 1886 Types[TCOMPLEX128], 1887 Types[TSTRING], 1888 1889 // basic type aliases 1890 bytetype, 1891 runetype, 1892 1893 // error 1894 errortype, 1895 1896 // untyped types 1897 untype(CTBOOL), 1898 untype(CTINT), 1899 untype(CTRUNE), 1900 untype(CTFLT), 1901 untype(CTCPLX), 1902 untype(CTSTR), 1903 untype(CTNIL), 1904 1905 // package unsafe 1906 Types[TUNSAFEPTR], 1907 1908 // invalid type (package contains errors) 1909 Types[Txxx], 1910 1911 // any type, for builtin export data 1912 Types[TANY], 1913 } 1914 } 1915 return predecl 1916 }