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