github.com/slayercat/go@v0.0.0-20170428012452-c51559813f61/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 // TODO(gri) enable and remove once issues caused by it are fixed 162 const trackAllTypes = false 163 164 type exporter struct { 165 out *bufio.Writer 166 167 // object -> index maps, indexed in order of serialization 168 strIndex map[string]int 169 pathIndex map[string]int 170 pkgIndex map[*types.Pkg]int 171 typIndex map[*types.Type]int 172 funcList []*Func 173 174 // position encoding 175 posInfoFormat bool 176 prevFile string 177 prevLine int 178 179 // debugging support 180 written int // bytes written 181 indent int // for p.trace 182 trace bool 183 } 184 185 // export writes the exportlist for localpkg to out and returns the number of bytes written. 186 func export(out *bufio.Writer, trace bool) int { 187 p := exporter{ 188 out: out, 189 strIndex: map[string]int{"": 0}, // empty string is mapped to 0 190 pathIndex: map[string]int{"": 0}, // empty path is mapped to 0 191 pkgIndex: make(map[*types.Pkg]int), 192 typIndex: make(map[*types.Type]int), 193 posInfoFormat: true, 194 trace: trace, 195 } 196 197 // write version info 198 // The version string must start with "version %d" where %d is the version 199 // number. Additional debugging information may follow after a blank; that 200 // text is ignored by the importer. 201 p.rawStringln(fmt.Sprintf("version %d", exportVersion)) 202 var debug string 203 if debugFormat { 204 debug = "debug" 205 } 206 p.rawStringln(debug) // cannot use p.bool since it's affected by debugFormat; also want to see this clearly 207 p.bool(trackAllTypes) 208 p.bool(p.posInfoFormat) 209 210 // --- generic export data --- 211 212 // populate type map with predeclared "known" types 213 predecl := predeclared() 214 for index, typ := range predecl { 215 p.typIndex[typ] = index 216 } 217 if len(p.typIndex) != len(predecl) { 218 Fatalf("exporter: duplicate entries in type map?") 219 } 220 221 // write package data 222 if localpkg.Path != "" { 223 Fatalf("exporter: local package path not empty: %q", localpkg.Path) 224 } 225 p.pkg(localpkg) 226 if p.trace { 227 p.tracef("\n") 228 } 229 230 // export objects 231 // 232 // First, export all exported (package-level) objects; i.e., all objects 233 // in the current exportlist. These objects represent all information 234 // required to import this package and type-check against it; i.e., this 235 // is the platform-independent export data. The format is generic in the 236 // sense that different compilers can use the same representation. 237 // 238 // During this first phase, more objects may be added to the exportlist 239 // (due to inlined function bodies and their dependencies). Export those 240 // objects in a second phase. That data is platform-specific as it depends 241 // on the inlining decisions of the compiler and the representation of the 242 // inlined function bodies. 243 244 // remember initial exportlist length 245 var numglobals = len(exportlist) 246 247 // Phase 1: Export objects in _current_ exportlist; exported objects at 248 // package level. 249 // Use range since we want to ignore objects added to exportlist during 250 // this phase. 251 objcount := 0 252 for _, n := range exportlist { 253 sym := n.Sym 254 255 if sym.Exported() { 256 continue 257 } 258 sym.SetExported(true) 259 260 // TODO(gri) Closures have dots in their names; 261 // e.g., TestFloatZeroValue.func1 in math/big tests. 262 if strings.Contains(sym.Name, ".") { 263 Fatalf("exporter: unexpected symbol: %v", sym) 264 } 265 266 if sym.Def == nil { 267 Fatalf("exporter: unknown export symbol: %v", sym) 268 } 269 270 // TODO(gri) Optimization: Probably worthwhile collecting 271 // long runs of constants and export them "in bulk" (saving 272 // tags and types, and making import faster). 273 274 if p.trace { 275 p.tracef("\n") 276 } 277 p.obj(sym) 278 objcount++ 279 } 280 281 // indicate end of list 282 if p.trace { 283 p.tracef("\n") 284 } 285 p.tag(endTag) 286 287 // for self-verification only (redundant) 288 p.int(objcount) 289 290 // --- compiler-specific export data --- 291 292 if p.trace { 293 p.tracef("\n--- compiler-specific export data ---\n[ ") 294 if p.indent != 0 { 295 Fatalf("exporter: incorrect indentation") 296 } 297 } 298 299 // write compiler-specific flags 300 if p.trace { 301 p.tracef("\n") 302 } 303 304 // Phase 2: Export objects added to exportlist during phase 1. 305 // Don't use range since exportlist may grow during this phase 306 // and we want to export all remaining objects. 307 objcount = 0 308 for i := numglobals; exportInlined && i < len(exportlist); i++ { 309 n := exportlist[i] 310 sym := n.Sym 311 312 // TODO(gri) The rest of this loop body is identical with 313 // the loop body above. Leave alone for now since there 314 // are different optimization opportunities, but factor 315 // eventually. 316 317 if sym.Exported() { 318 continue 319 } 320 sym.SetExported(true) 321 322 // TODO(gri) Closures have dots in their names; 323 // e.g., TestFloatZeroValue.func1 in math/big tests. 324 if strings.Contains(sym.Name, ".") { 325 Fatalf("exporter: unexpected symbol: %v", sym) 326 } 327 328 if sym.Def == nil { 329 Fatalf("exporter: unknown export symbol: %v", sym) 330 } 331 332 // TODO(gri) Optimization: Probably worthwhile collecting 333 // long runs of constants and export them "in bulk" (saving 334 // tags and types, and making import faster). 335 336 if p.trace { 337 p.tracef("\n") 338 } 339 340 if IsAlias(sym) { 341 Fatalf("exporter: unexpected type alias %v in inlined function body", sym) 342 } 343 344 p.obj(sym) 345 objcount++ 346 } 347 348 // indicate end of list 349 if p.trace { 350 p.tracef("\n") 351 } 352 p.tag(endTag) 353 354 // for self-verification only (redundant) 355 p.int(objcount) 356 357 // --- inlined function bodies --- 358 359 if p.trace { 360 p.tracef("\n--- inlined function bodies ---\n") 361 if p.indent != 0 { 362 Fatalf("exporter: incorrect indentation") 363 } 364 } 365 366 // write inlineable function bodies 367 objcount = 0 368 for i, f := range p.funcList { 369 if f != nil { 370 // function has inlineable body: 371 // write index and body 372 if p.trace { 373 p.tracef("\n----\nfunc { %#v }\n", f.Inl) 374 } 375 p.int(i) 376 p.stmtList(f.Inl) 377 if p.trace { 378 p.tracef("\n") 379 } 380 objcount++ 381 } 382 } 383 384 // indicate end of list 385 if p.trace { 386 p.tracef("\n") 387 } 388 p.int(-1) // invalid index terminates list 389 390 // for self-verification only (redundant) 391 p.int(objcount) 392 393 if p.trace { 394 p.tracef("\n--- end ---\n") 395 } 396 397 // --- end of export data --- 398 399 return p.written 400 } 401 402 func (p *exporter) pkg(pkg *types.Pkg) { 403 if pkg == nil { 404 Fatalf("exporter: unexpected nil pkg") 405 } 406 407 // if we saw the package before, write its index (>= 0) 408 if i, ok := p.pkgIndex[pkg]; ok { 409 p.index('P', i) 410 return 411 } 412 413 // otherwise, remember the package, write the package tag (< 0) and package data 414 if p.trace { 415 p.tracef("P%d = { ", len(p.pkgIndex)) 416 defer p.tracef("} ") 417 } 418 p.pkgIndex[pkg] = len(p.pkgIndex) 419 420 p.tag(packageTag) 421 p.string(pkg.Name) 422 p.path(pkg.Path) 423 } 424 425 func unidealType(typ *types.Type, val Val) *types.Type { 426 // Untyped (ideal) constants get their own type. This decouples 427 // the constant type from the encoding of the constant value. 428 if typ == nil || typ.IsUntyped() { 429 typ = untype(val.Ctype()) 430 } 431 return typ 432 } 433 434 func (p *exporter) obj(sym *types.Sym) { 435 // Exported objects may be from different packages because they 436 // may be re-exported via an exported alias or as dependencies in 437 // exported inlined function bodies. Thus, exported object names 438 // must be fully qualified. 439 // 440 // (This can only happen for aliased objects or during phase 2 441 // (exportInlined enabled) of object export. Unaliased Objects 442 // exported in phase 1 (compiler-indendepent objects) are by 443 // definition only the objects from the current package and not 444 // pulled in via inlined function bodies. In that case the package 445 // qualifier is not needed. Possible space optimization.) 446 447 n := asNode(sym.Def) 448 switch n.Op { 449 case OLITERAL: 450 // constant 451 // TODO(gri) determine if we need the typecheck call here 452 n = typecheck(n, Erv) 453 if n == nil || n.Op != OLITERAL { 454 Fatalf("exporter: dumpexportconst: oconst nil: %v", sym) 455 } 456 457 p.tag(constTag) 458 p.pos(n) 459 // TODO(gri) In inlined functions, constants are used directly 460 // so they should never occur as re-exported objects. We may 461 // not need the qualified name here. See also comment above. 462 // Possible space optimization. 463 p.qualifiedName(sym) 464 p.typ(unidealType(n.Type, n.Val())) 465 p.value(n.Val()) 466 467 case OTYPE: 468 // named type 469 t := n.Type 470 if t.Etype == TFORW { 471 Fatalf("exporter: export of incomplete type %v", sym) 472 } 473 474 if IsAlias(sym) { 475 p.tag(aliasTag) 476 p.pos(n) 477 p.qualifiedName(sym) 478 } else { 479 p.tag(typeTag) 480 } 481 p.typ(t) 482 483 case ONAME: 484 // variable or function 485 n = typecheck(n, Erv|Ecall) 486 if n == nil || n.Type == nil { 487 Fatalf("exporter: variable/function exported but not defined: %v", sym) 488 } 489 490 if n.Type.Etype == TFUNC && n.Class() == PFUNC { 491 // function 492 p.tag(funcTag) 493 p.pos(n) 494 p.qualifiedName(sym) 495 496 sig := asNode(sym.Def).Type 497 inlineable := isInlineable(asNode(sym.Def)) 498 499 p.paramList(sig.Params(), inlineable) 500 p.paramList(sig.Results(), inlineable) 501 502 var f *Func 503 if inlineable { 504 f = asNode(sym.Def).Func 505 reexportdeplist(f.Inl) 506 } 507 p.funcList = append(p.funcList, f) 508 } else { 509 // variable 510 p.tag(varTag) 511 p.pos(n) 512 p.qualifiedName(sym) 513 p.typ(asNode(sym.Def).Type) 514 } 515 516 default: 517 Fatalf("exporter: unexpected export symbol: %v %v", n.Op, sym) 518 } 519 } 520 521 // deltaNewFile is a magic line delta offset indicating a new file. 522 // We use -64 because it is rare; see issue 20080 and CL 41619. 523 // -64 is the smallest int that fits in a single byte as a varint. 524 const deltaNewFile = -64 525 526 func (p *exporter) pos(n *Node) { 527 if !p.posInfoFormat { 528 return 529 } 530 531 file, line := fileLine(n) 532 if file == p.prevFile { 533 // common case: write line delta 534 // delta == deltaNewFile means different file 535 // if the actual line delta is deltaNewFile, 536 // follow up with a negative int to indicate that. 537 // only non-negative ints can follow deltaNewFile 538 // when writing a new file. 539 delta := line - p.prevLine 540 p.int(delta) 541 if delta == deltaNewFile { 542 p.int(-1) // -1 means no file change 543 } 544 } else { 545 // different file 546 p.int(deltaNewFile) 547 p.int(line) // line >= 0 548 p.path(file) 549 p.prevFile = file 550 } 551 p.prevLine = line 552 } 553 554 func (p *exporter) path(s string) { 555 if i, ok := p.pathIndex[s]; ok { 556 p.index('p', i) // i >= 0 557 return 558 } 559 p.pathIndex[s] = len(p.pathIndex) 560 c := strings.Split(s, "/") 561 p.int(-len(c)) // -len(c) < 0 562 for _, x := range c { 563 p.string(x) 564 } 565 } 566 567 func fileLine(n *Node) (file string, line int) { 568 if n != nil { 569 pos := Ctxt.PosTable.Pos(n.Pos) 570 file = pos.Base().AbsFilename() 571 line = int(pos.RelLine()) 572 } 573 return 574 } 575 576 func isInlineable(n *Node) bool { 577 if exportInlined && n != nil && n.Func != nil && n.Func.Inl.Len() != 0 { 578 // when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet. 579 // currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package 580 if Debug['l'] < 2 { 581 typecheckinl(n) 582 } 583 return true 584 } 585 return false 586 } 587 588 var errorInterface *types.Type // lazily initialized 589 590 func (p *exporter) typ(t *types.Type) { 591 if t == nil { 592 Fatalf("exporter: nil type") 593 } 594 595 // Possible optimization: Anonymous pointer types *T where 596 // T is a named type are common. We could canonicalize all 597 // such types *T to a single type PT = *T. This would lead 598 // to at most one *T entry in typIndex, and all future *T's 599 // would be encoded as the respective index directly. Would 600 // save 1 byte (pointerTag) per *T and reduce the typIndex 601 // size (at the cost of a canonicalization map). We can do 602 // this later, without encoding format change. 603 604 // if we saw the type before, write its index (>= 0) 605 if i, ok := p.typIndex[t]; ok { 606 p.index('T', i) 607 return 608 } 609 610 // otherwise, remember the type, write the type tag (< 0) and type data 611 if trackAllTypes { 612 if p.trace { 613 p.tracef("T%d = {>\n", len(p.typIndex)) 614 defer p.tracef("<\n} ") 615 } 616 p.typIndex[t] = len(p.typIndex) 617 } 618 619 // pick off named types 620 if tsym := t.Sym; tsym != nil { 621 if !trackAllTypes { 622 // if we don't track all types, track named types now 623 p.typIndex[t] = len(p.typIndex) 624 } 625 626 // Predeclared types should have been found in the type map. 627 if t.Orig == t { 628 Fatalf("exporter: predeclared type missing from type map?") 629 } 630 631 n := typenod(t) 632 if n.Type != t { 633 Fatalf("exporter: named type definition incorrectly set up") 634 } 635 636 p.tag(namedTag) 637 p.pos(n) 638 p.qualifiedName(tsym) 639 640 // write underlying type 641 orig := t.Orig 642 if orig == types.Errortype { 643 // The error type is the only predeclared type which has 644 // a composite underlying type. When we encode that type, 645 // make sure to encode the underlying interface rather than 646 // the named type again. See also the comment in universe.go 647 // regarding the errortype and issue #15920. 648 if errorInterface == nil { 649 errorInterface = makeErrorInterface() 650 } 651 orig = errorInterface 652 } 653 p.typ(orig) 654 655 // interfaces don't have associated methods 656 if t.Orig.IsInterface() { 657 return 658 } 659 660 // sort methods for reproducible export format 661 // TODO(gri) Determine if they are already sorted 662 // in which case we can drop this step. 663 var methods []*types.Field 664 for _, m := range t.Methods().Slice() { 665 methods = append(methods, m) 666 } 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(f.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: name used as local variable in export. 1192 // _ becomes ~b%d internally; print as _ for export 1193 if n.Sym != nil && n.Sym.Name[0] == '~' && n.Sym.Name[1] == 'b' { 1194 p.op(ONAME) 1195 p.pos(n) 1196 p.string("_") // inlined and customized version of p.sym(n) 1197 break 1198 } 1199 1200 if n.Sym != nil && !isblank(n) && n.Name.Vargen > 0 { 1201 p.op(ONAME) 1202 p.pos(n) 1203 p.sym(n) 1204 break 1205 } 1206 1207 // Special case: explicit name of func (*T) method(...) is turned into pkg.(*T).method, 1208 // but for export, this should be rendered as (*pkg.T).meth. 1209 // These nodes have the special property that they are names with a left OTYPE and a right ONAME. 1210 if n.Left != nil && n.Left.Op == OTYPE && n.Right != nil && n.Right.Op == ONAME { 1211 p.op(OXDOT) 1212 p.pos(n) 1213 p.expr(n.Left) // n.Left.Op == OTYPE 1214 p.fieldSym(n.Right.Sym, true) 1215 break 1216 } 1217 1218 p.op(ONAME) 1219 p.pos(n) 1220 p.sym(n) 1221 1222 // case OPACK, ONONAME: 1223 // should have been resolved by typechecking - handled by default case 1224 1225 case OTYPE: 1226 p.op(OTYPE) 1227 p.pos(n) 1228 if p.bool(n.Type == nil) { 1229 p.sym(n) 1230 } else { 1231 p.typ(n.Type) 1232 } 1233 1234 // case OTARRAY, OTMAP, OTCHAN, OTSTRUCT, OTINTER, OTFUNC: 1235 // should have been resolved by typechecking - handled by default case 1236 1237 // case OCLOSURE: 1238 // unimplemented - handled by default case 1239 1240 // case OCOMPLIT: 1241 // should have been resolved by typechecking - handled by default case 1242 1243 case OPTRLIT: 1244 p.op(OPTRLIT) 1245 p.pos(n) 1246 p.expr(n.Left) 1247 p.bool(n.Implicit()) 1248 1249 case OSTRUCTLIT: 1250 p.op(OSTRUCTLIT) 1251 p.pos(n) 1252 p.typ(n.Type) 1253 p.elemList(n.List) // special handling of field names 1254 1255 case OARRAYLIT, OSLICELIT, OMAPLIT: 1256 p.op(OCOMPLIT) 1257 p.pos(n) 1258 p.typ(n.Type) 1259 p.exprList(n.List) 1260 1261 case OKEY: 1262 p.op(OKEY) 1263 p.pos(n) 1264 p.exprsOrNil(n.Left, n.Right) 1265 1266 // case OSTRUCTKEY: 1267 // unreachable - handled in case OSTRUCTLIT by elemList 1268 1269 // case OCALLPART: 1270 // unimplemented - handled by default case 1271 1272 case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH: 1273 p.op(OXDOT) 1274 p.pos(n) 1275 p.expr(n.Left) 1276 p.fieldSym(n.Sym, true) 1277 1278 case ODOTTYPE, ODOTTYPE2: 1279 p.op(ODOTTYPE) 1280 p.pos(n) 1281 p.expr(n.Left) 1282 p.typ(n.Type) 1283 1284 case OINDEX, OINDEXMAP: 1285 p.op(OINDEX) 1286 p.pos(n) 1287 p.expr(n.Left) 1288 p.expr(n.Right) 1289 1290 case OSLICE, OSLICESTR, OSLICEARR: 1291 p.op(OSLICE) 1292 p.pos(n) 1293 p.expr(n.Left) 1294 low, high, _ := n.SliceBounds() 1295 p.exprsOrNil(low, high) 1296 1297 case OSLICE3, OSLICE3ARR: 1298 p.op(OSLICE3) 1299 p.pos(n) 1300 p.expr(n.Left) 1301 low, high, max := n.SliceBounds() 1302 p.exprsOrNil(low, high) 1303 p.expr(max) 1304 1305 case OCOPY, OCOMPLEX: 1306 // treated like other builtin calls (see e.g., OREAL) 1307 p.op(op) 1308 p.pos(n) 1309 p.expr(n.Left) 1310 p.expr(n.Right) 1311 p.op(OEND) 1312 1313 case OCONV, OCONVIFACE, OCONVNOP, OARRAYBYTESTR, OARRAYRUNESTR, OSTRARRAYBYTE, OSTRARRAYRUNE, ORUNESTR: 1314 p.op(OCONV) 1315 p.pos(n) 1316 p.expr(n.Left) 1317 p.typ(n.Type) 1318 1319 case OREAL, OIMAG, OAPPEND, OCAP, OCLOSE, ODELETE, OLEN, OMAKE, ONEW, OPANIC, ORECOVER, OPRINT, OPRINTN: 1320 p.op(op) 1321 p.pos(n) 1322 if n.Left != nil { 1323 p.expr(n.Left) 1324 p.op(OEND) 1325 } else { 1326 p.exprList(n.List) // emits terminating OEND 1327 } 1328 // only append() calls may contain '...' arguments 1329 if op == OAPPEND { 1330 p.bool(n.Isddd()) 1331 } else if n.Isddd() { 1332 Fatalf("exporter: unexpected '...' with %s call", opnames[op]) 1333 } 1334 1335 case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER, OGETG: 1336 p.op(OCALL) 1337 p.pos(n) 1338 p.expr(n.Left) 1339 p.exprList(n.List) 1340 p.bool(n.Isddd()) 1341 1342 case OMAKEMAP, OMAKECHAN, OMAKESLICE: 1343 p.op(op) // must keep separate from OMAKE for importer 1344 p.pos(n) 1345 p.typ(n.Type) 1346 switch { 1347 default: 1348 // empty list 1349 p.op(OEND) 1350 case n.List.Len() != 0: // pre-typecheck 1351 p.exprList(n.List) // emits terminating OEND 1352 case n.Right != nil: 1353 p.expr(n.Left) 1354 p.expr(n.Right) 1355 p.op(OEND) 1356 case n.Left != nil && (n.Op == OMAKESLICE || !n.Left.Type.IsUntyped()): 1357 p.expr(n.Left) 1358 p.op(OEND) 1359 } 1360 1361 // unary expressions 1362 case OPLUS, OMINUS, OADDR, OCOM, OIND, ONOT, ORECV: 1363 p.op(op) 1364 p.pos(n) 1365 p.expr(n.Left) 1366 1367 // binary expressions 1368 case OADD, OAND, OANDAND, OANDNOT, ODIV, OEQ, OGE, OGT, OLE, OLT, 1369 OLSH, OMOD, OMUL, ONE, OOR, OOROR, ORSH, OSEND, OSUB, OXOR: 1370 p.op(op) 1371 p.pos(n) 1372 p.expr(n.Left) 1373 p.expr(n.Right) 1374 1375 case OADDSTR: 1376 p.op(OADDSTR) 1377 p.pos(n) 1378 p.exprList(n.List) 1379 1380 case OCMPSTR, OCMPIFACE: 1381 p.op(Op(n.Etype)) 1382 p.pos(n) 1383 p.expr(n.Left) 1384 p.expr(n.Right) 1385 1386 case ODCLCONST: 1387 // if exporting, DCLCONST should just be removed as its usage 1388 // has already been replaced with literals 1389 // TODO(gri) these should not be exported in the first place 1390 // TODO(gri) why is this considered an expression in fmt.go? 1391 p.op(ODCLCONST) 1392 p.pos(n) 1393 1394 default: 1395 Fatalf("cannot export %v (%d) node\n"+ 1396 "==> please file an issue and assign to gri@\n", n.Op, int(n.Op)) 1397 } 1398 } 1399 1400 // Caution: stmt will emit more than one node for statement nodes n that have a non-empty 1401 // n.Ninit and where n cannot have a natural init section (such as in "if", "for", etc.). 1402 func (p *exporter) stmt(n *Node) { 1403 if p.trace { 1404 p.tracef("( ") 1405 defer p.tracef(") ") 1406 } 1407 1408 if n.Ninit.Len() > 0 && !stmtwithinit(n.Op) { 1409 if p.trace { 1410 p.tracef("( /* Ninits */ ") 1411 } 1412 1413 // can't use stmtList here since we don't want the final OEND 1414 for _, n := range n.Ninit.Slice() { 1415 p.stmt(n) 1416 } 1417 1418 if p.trace { 1419 p.tracef(") ") 1420 } 1421 } 1422 1423 switch op := n.Op; op { 1424 case ODCL: 1425 p.op(ODCL) 1426 p.pos(n) 1427 p.sym(n.Left) 1428 p.typ(n.Left.Type) 1429 1430 // case ODCLFIELD: 1431 // unimplemented - handled by default case 1432 1433 case OAS: 1434 // Don't export "v = <N>" initializing statements, hope they're always 1435 // preceded by the DCL which will be re-parsed and typecheck to reproduce 1436 // the "v = <N>" again. 1437 if n.Right != nil { 1438 p.op(OAS) 1439 p.pos(n) 1440 p.expr(n.Left) 1441 p.expr(n.Right) 1442 } 1443 1444 case OASOP: 1445 p.op(OASOP) 1446 p.pos(n) 1447 p.int(int(n.Etype)) 1448 p.expr(n.Left) 1449 if p.bool(!n.Implicit()) { 1450 p.expr(n.Right) 1451 } 1452 1453 case OAS2, OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV: 1454 p.op(OAS2) 1455 p.pos(n) 1456 p.exprList(n.List) 1457 p.exprList(n.Rlist) 1458 1459 case ORETURN: 1460 p.op(ORETURN) 1461 p.pos(n) 1462 p.exprList(n.List) 1463 1464 // case ORETJMP: 1465 // unreachable - generated by compiler for trampolin routines 1466 1467 case OPROC, ODEFER: 1468 p.op(op) 1469 p.pos(n) 1470 p.expr(n.Left) 1471 1472 case OIF: 1473 p.op(OIF) 1474 p.pos(n) 1475 p.stmtList(n.Ninit) 1476 p.expr(n.Left) 1477 p.stmtList(n.Nbody) 1478 p.stmtList(n.Rlist) 1479 1480 case OFOR: 1481 p.op(OFOR) 1482 p.pos(n) 1483 p.stmtList(n.Ninit) 1484 p.exprsOrNil(n.Left, n.Right) 1485 p.stmtList(n.Nbody) 1486 1487 case ORANGE: 1488 p.op(ORANGE) 1489 p.pos(n) 1490 p.stmtList(n.List) 1491 p.expr(n.Right) 1492 p.stmtList(n.Nbody) 1493 1494 case OSELECT, OSWITCH: 1495 p.op(op) 1496 p.pos(n) 1497 p.stmtList(n.Ninit) 1498 p.exprsOrNil(n.Left, nil) 1499 p.stmtList(n.List) 1500 1501 case OCASE, OXCASE: 1502 p.op(OXCASE) 1503 p.pos(n) 1504 p.stmtList(n.List) 1505 p.stmtList(n.Nbody) 1506 1507 case OFALL, OXFALL: 1508 p.op(OXFALL) 1509 p.pos(n) 1510 1511 case OBREAK, OCONTINUE: 1512 p.op(op) 1513 p.pos(n) 1514 p.exprsOrNil(n.Left, nil) 1515 1516 case OEMPTY: 1517 // nothing to emit 1518 1519 case OGOTO, OLABEL: 1520 p.op(op) 1521 p.pos(n) 1522 p.expr(n.Left) 1523 1524 default: 1525 Fatalf("exporter: CANNOT EXPORT: %v\nPlease notify gri@\n", n.Op) 1526 } 1527 } 1528 1529 func (p *exporter) exprsOrNil(a, b *Node) { 1530 ab := 0 1531 if a != nil { 1532 ab |= 1 1533 } 1534 if b != nil { 1535 ab |= 2 1536 } 1537 p.int(ab) 1538 if ab&1 != 0 { 1539 p.expr(a) 1540 } 1541 if ab&2 != 0 { 1542 p.expr(b) 1543 } 1544 } 1545 1546 func (p *exporter) fieldSym(s *types.Sym, short bool) { 1547 name := s.Name 1548 1549 // remove leading "type." in method names ("(T).m" -> "m") 1550 if short { 1551 if i := strings.LastIndex(name, "."); i >= 0 { 1552 name = name[i+1:] 1553 } 1554 } 1555 1556 // we should never see a _ (blank) here - these are accessible ("read") fields 1557 // TODO(gri) can we assert this with an explicit check? 1558 p.string(name) 1559 if !exportname(name) { 1560 p.pkg(s.Pkg) 1561 } 1562 } 1563 1564 // sym must encode the _ (blank) identifier as a single string "_" since 1565 // encoding for some nodes is based on this assumption (e.g. ONAME nodes). 1566 func (p *exporter) sym(n *Node) { 1567 s := n.Sym 1568 if s.Pkg != nil { 1569 if len(s.Name) > 0 && s.Name[0] == '.' { 1570 Fatalf("exporter: exporting synthetic symbol %s", s.Name) 1571 } 1572 } 1573 1574 if p.trace { 1575 p.tracef("{ SYM ") 1576 defer p.tracef("} ") 1577 } 1578 1579 name := s.Name 1580 1581 // remove leading "type." in method names ("(T).m" -> "m") 1582 if i := strings.LastIndex(name, "."); i >= 0 { 1583 name = name[i+1:] 1584 } 1585 1586 if strings.Contains(name, "·") && n.Name.Vargen > 0 { 1587 Fatalf("exporter: unexpected · in symbol name") 1588 } 1589 1590 if i := n.Name.Vargen; i > 0 { 1591 name = fmt.Sprintf("%s·%d", name, i) 1592 } 1593 1594 p.string(name) 1595 if name != "_" { 1596 p.pkg(s.Pkg) 1597 } 1598 // Fixes issue #18167. 1599 p.string(s.Linkname) 1600 } 1601 1602 func (p *exporter) bool(b bool) bool { 1603 if p.trace { 1604 p.tracef("[") 1605 defer p.tracef("= %v] ", b) 1606 } 1607 1608 x := 0 1609 if b { 1610 x = 1 1611 } 1612 p.int(x) 1613 return b 1614 } 1615 1616 func (p *exporter) op(op Op) { 1617 if p.trace { 1618 p.tracef("[") 1619 defer p.tracef("= %v] ", op) 1620 } 1621 1622 p.int(int(op)) 1623 } 1624 1625 // ---------------------------------------------------------------------------- 1626 // Low-level encoders 1627 1628 func (p *exporter) index(marker byte, index int) { 1629 if index < 0 { 1630 Fatalf("exporter: invalid index < 0") 1631 } 1632 if debugFormat { 1633 p.marker('t') 1634 } 1635 if p.trace { 1636 p.tracef("%c%d ", marker, index) 1637 } 1638 p.rawInt64(int64(index)) 1639 } 1640 1641 func (p *exporter) tag(tag int) { 1642 if tag >= 0 { 1643 Fatalf("exporter: invalid tag >= 0") 1644 } 1645 if debugFormat { 1646 p.marker('t') 1647 } 1648 if p.trace { 1649 p.tracef("%s ", tagString[-tag]) 1650 } 1651 p.rawInt64(int64(tag)) 1652 } 1653 1654 func (p *exporter) int(x int) { 1655 p.int64(int64(x)) 1656 } 1657 1658 func (p *exporter) int64(x int64) { 1659 if debugFormat { 1660 p.marker('i') 1661 } 1662 if p.trace { 1663 p.tracef("%d ", x) 1664 } 1665 p.rawInt64(x) 1666 } 1667 1668 func (p *exporter) string(s string) { 1669 if debugFormat { 1670 p.marker('s') 1671 } 1672 if p.trace { 1673 p.tracef("%q ", s) 1674 } 1675 // if we saw the string before, write its index (>= 0) 1676 // (the empty string is mapped to 0) 1677 if i, ok := p.strIndex[s]; ok { 1678 p.rawInt64(int64(i)) 1679 return 1680 } 1681 // otherwise, remember string and write its negative length and bytes 1682 p.strIndex[s] = len(p.strIndex) 1683 p.rawInt64(-int64(len(s))) 1684 for i := 0; i < len(s); i++ { 1685 p.rawByte(s[i]) 1686 } 1687 } 1688 1689 // marker emits a marker byte and position information which makes 1690 // it easy for a reader to detect if it is "out of sync". Used only 1691 // if debugFormat is set. 1692 func (p *exporter) marker(m byte) { 1693 p.rawByte(m) 1694 // Uncomment this for help tracking down the location 1695 // of an incorrect marker when running in debugFormat. 1696 // if p.trace { 1697 // p.tracef("#%d ", p.written) 1698 // } 1699 p.rawInt64(int64(p.written)) 1700 } 1701 1702 // rawInt64 should only be used by low-level encoders. 1703 func (p *exporter) rawInt64(x int64) { 1704 var tmp [binary.MaxVarintLen64]byte 1705 n := binary.PutVarint(tmp[:], x) 1706 for i := 0; i < n; i++ { 1707 p.rawByte(tmp[i]) 1708 } 1709 } 1710 1711 // rawStringln should only be used to emit the initial version string. 1712 func (p *exporter) rawStringln(s string) { 1713 for i := 0; i < len(s); i++ { 1714 p.rawByte(s[i]) 1715 } 1716 p.rawByte('\n') 1717 } 1718 1719 // rawByte is the bottleneck interface to write to p.out. 1720 // rawByte escapes b as follows (any encoding does that 1721 // hides '$'): 1722 // 1723 // '$' => '|' 'S' 1724 // '|' => '|' '|' 1725 // 1726 // Necessary so other tools can find the end of the 1727 // export data by searching for "$$". 1728 // rawByte should only be used by low-level encoders. 1729 func (p *exporter) rawByte(b byte) { 1730 switch b { 1731 case '$': 1732 // write '$' as '|' 'S' 1733 b = 'S' 1734 fallthrough 1735 case '|': 1736 // write '|' as '|' '|' 1737 p.out.WriteByte('|') 1738 p.written++ 1739 } 1740 p.out.WriteByte(b) 1741 p.written++ 1742 } 1743 1744 // tracef is like fmt.Printf but it rewrites the format string 1745 // to take care of indentation. 1746 func (p *exporter) tracef(format string, args ...interface{}) { 1747 if strings.ContainsAny(format, "<>\n") { 1748 var buf bytes.Buffer 1749 for i := 0; i < len(format); i++ { 1750 // no need to deal with runes 1751 ch := format[i] 1752 switch ch { 1753 case '>': 1754 p.indent++ 1755 continue 1756 case '<': 1757 p.indent-- 1758 continue 1759 } 1760 buf.WriteByte(ch) 1761 if ch == '\n' { 1762 for j := p.indent; j > 0; j-- { 1763 buf.WriteString(". ") 1764 } 1765 } 1766 } 1767 format = buf.String() 1768 } 1769 fmt.Printf(format, args...) 1770 } 1771 1772 // ---------------------------------------------------------------------------- 1773 // Export format 1774 1775 // Tags. Must be < 0. 1776 const ( 1777 // Objects 1778 packageTag = -(iota + 1) 1779 constTag 1780 typeTag 1781 varTag 1782 funcTag 1783 endTag 1784 1785 // Types 1786 namedTag 1787 arrayTag 1788 sliceTag 1789 dddTag 1790 structTag 1791 pointerTag 1792 signatureTag 1793 interfaceTag 1794 mapTag 1795 chanTag 1796 1797 // Values 1798 falseTag 1799 trueTag 1800 int64Tag 1801 floatTag 1802 fractionTag // not used by gc 1803 complexTag 1804 stringTag 1805 nilTag 1806 unknownTag // not used by gc (only appears in packages with errors) 1807 1808 // Type aliases 1809 aliasTag 1810 ) 1811 1812 // Debugging support. 1813 // (tagString is only used when tracing is enabled) 1814 var tagString = [...]string{ 1815 // Objects 1816 -packageTag: "package", 1817 -constTag: "const", 1818 -typeTag: "type", 1819 -varTag: "var", 1820 -funcTag: "func", 1821 -endTag: "end", 1822 1823 // Types 1824 -namedTag: "named type", 1825 -arrayTag: "array", 1826 -sliceTag: "slice", 1827 -dddTag: "ddd", 1828 -structTag: "struct", 1829 -pointerTag: "pointer", 1830 -signatureTag: "signature", 1831 -interfaceTag: "interface", 1832 -mapTag: "map", 1833 -chanTag: "chan", 1834 1835 // Values 1836 -falseTag: "false", 1837 -trueTag: "true", 1838 -int64Tag: "int64", 1839 -floatTag: "float", 1840 -fractionTag: "fraction", 1841 -complexTag: "complex", 1842 -stringTag: "string", 1843 -nilTag: "nil", 1844 -unknownTag: "unknown", 1845 1846 // Type aliases 1847 -aliasTag: "alias", 1848 } 1849 1850 // untype returns the "pseudo" untyped type for a Ctype (import/export use only). 1851 // (we can't use an pre-initialized array because we must be sure all types are 1852 // set up) 1853 func untype(ctype Ctype) *types.Type { 1854 switch ctype { 1855 case CTINT: 1856 return types.Idealint 1857 case CTRUNE: 1858 return types.Idealrune 1859 case CTFLT: 1860 return types.Idealfloat 1861 case CTCPLX: 1862 return types.Idealcomplex 1863 case CTSTR: 1864 return types.Idealstring 1865 case CTBOOL: 1866 return types.Idealbool 1867 case CTNIL: 1868 return types.Types[TNIL] 1869 } 1870 Fatalf("exporter: unknown Ctype") 1871 return nil 1872 } 1873 1874 var predecl []*types.Type // initialized lazily 1875 1876 func predeclared() []*types.Type { 1877 if predecl == nil { 1878 // initialize lazily to be sure that all 1879 // elements have been initialized before 1880 predecl = []*types.Type{ 1881 // basic types 1882 types.Types[TBOOL], 1883 types.Types[TINT], 1884 types.Types[TINT8], 1885 types.Types[TINT16], 1886 types.Types[TINT32], 1887 types.Types[TINT64], 1888 types.Types[TUINT], 1889 types.Types[TUINT8], 1890 types.Types[TUINT16], 1891 types.Types[TUINT32], 1892 types.Types[TUINT64], 1893 types.Types[TUINTPTR], 1894 types.Types[TFLOAT32], 1895 types.Types[TFLOAT64], 1896 types.Types[TCOMPLEX64], 1897 types.Types[TCOMPLEX128], 1898 types.Types[TSTRING], 1899 1900 // basic type aliases 1901 types.Bytetype, 1902 types.Runetype, 1903 1904 // error 1905 types.Errortype, 1906 1907 // untyped types 1908 untype(CTBOOL), 1909 untype(CTINT), 1910 untype(CTRUNE), 1911 untype(CTFLT), 1912 untype(CTCPLX), 1913 untype(CTSTR), 1914 untype(CTNIL), 1915 1916 // package unsafe 1917 types.Types[TUNSAFEPTR], 1918 1919 // invalid type (package contains errors) 1920 types.Types[Txxx], 1921 1922 // any type, for builtin export data 1923 types.Types[TANY], 1924 } 1925 } 1926 return predecl 1927 }