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