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