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