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