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