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