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