github.com/q45/go@v0.0.0-20151101211701-a4fb8c13db3f/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 // Based loosely on x/tools/go/importer. 7 // (see fmt.go, go.y as "documentation" for how to use/setup data structures) 8 // 9 // Use "-newexport" flag to enable. 10 11 // TODO(gri): 12 // - inlined functions 13 14 /* 15 Export data encoding: 16 17 The export data is a serialized description of the graph of exported 18 objects: constants, types, variables, and functions. Only types can 19 be re-exported and so we need to know which package they are coming 20 from. Therefore, packages are also part of the export graph. 21 22 The roots of the graph are the list of constants, variables, functions, 23 and eventually types. Types are written last because most of them will 24 be written as part of other objects which will reduce the number of 25 types that need to be written separately. 26 27 The graph is serialized in in-order fashion, starting with the roots. 28 Each object in the graph is serialized by writing its fields sequentially. 29 If the field is a pointer to another object, that object is serialized, 30 recursively. Otherwise the field is written. Non-pointer fields are all 31 encoded as either an integer or string value. 32 33 Only packages and types may be referred to more than once. When getting 34 to a package or type that was not serialized before, a number (index) is 35 assigned to it, starting at 0. In this case, the encoding starts with an 36 integer tag with a value < 0. The tag value indicates the kind of object 37 (package or type) that follows and that this is the first time that we 38 see this object. If the package or tag was already serialized, the encoding 39 starts with the respective package or type index >= 0. An importer can 40 trivially determine if a package or type needs to be read in for the first 41 time (tag < 0) and entered into the respective package or type table, or 42 if the package or type was seen already (index >= 0), in which case the 43 index is the table index where the respective object can be found. 44 45 Before exporting or importing, the type tables are populated with the 46 predeclared types (int, string, error, unsafe.Pointer, etc.). This way 47 they are automatically encoded with a known and fixed type index. 48 49 Encoding format: 50 51 The export data starts with a single byte indicating the encoding format 52 (compact, or with debugging information), followed by a version string 53 (so we can evolve the encoding if need be), the name of the imported 54 package, and a string containing platform-specific information for that 55 package. 56 57 After this header, the lists of objects follow. After the objects, platform- 58 specific data may be found which is not used strictly for type checking. 59 60 The encoding of objects is straight-forward: Constants, variables, and 61 functions start with their name, type, and possibly a value. Named types 62 record their name and package so that they can be canonicalized: If the 63 same type was imported before via another import, the importer must use 64 the previously imported type pointer so that we have exactly one version 65 (i.e., one pointer) for each named type (and read but discard the current 66 type encoding). Unnamed types simply encode their respective fields. 67 68 In the encoding, all lists (of objects, struct fields, methods, parameter 69 names, but also the bytes of a string, etc.) start with an integer which 70 is the length of the list. This permits an importer to allocate the right 71 amount of space to hold the list without the need to grow it later. 72 73 All integer values use a variable-length encoding for compact representation. 74 75 If debugFormat is set, each integer and string value is preceeded by a marker 76 and position information in the encoding. This mechanism permits an importer 77 to recognize immediately when it is out of sync. The importer recognizes this 78 mode automatically (i.e., it can import export data produced with debugging 79 support even if debugFormat is not set at the time of import). Using this mode 80 will massively increase the size of the export data (by a factor of 2 to 3) 81 and is only recommended for debugging. 82 83 The exporter and importer are completely symmetric in implementation: For 84 each encoding routine there is the 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 // debugging support 103 const ( 104 debugFormat = false // use debugging format for export data (emits a lot of additional data) 105 ) 106 107 const exportVersion = "v0" 108 109 // Set forceNewExport to force the use of the new export format - for testing on the build dashboard. 110 // TODO(gri) remove eventually 111 const forceNewExport = false 112 113 // Export writes the export data for localpkg to out and returns the number of bytes written. 114 func Export(out *obj.Biobuf, trace bool) int { 115 p := exporter{ 116 out: out, 117 pkgIndex: make(map[*Pkg]int), 118 typIndex: make(map[*Type]int), 119 trace: trace, 120 } 121 122 // write low-level encoding format 123 var format byte = 'c' // compact 124 if debugFormat { 125 format = 'd' 126 } 127 p.byte(format) 128 129 // --- generic export data --- 130 131 if p.trace { 132 p.tracef("\n--- generic export data ---\n") 133 if p.indent != 0 { 134 Fatalf("incorrect indentation %d", p.indent) 135 } 136 } 137 138 p.string(exportVersion) 139 if p.trace { 140 p.tracef("\n") 141 } 142 143 // populate type map with predeclared "known" types 144 predecl := predeclared() 145 for index, typ := range predecl { 146 p.typIndex[typ] = index 147 } 148 if len(p.typIndex) != len(predecl) { 149 Fatalf("duplicate entries in type map?") 150 } 151 152 // write package data 153 if localpkg.Path != "" { 154 Fatalf("local package path not empty: %q", localpkg.Path) 155 } 156 p.pkg(localpkg) 157 158 // write compiler-specific flags 159 // go.y:import_safety 160 { 161 var flags string 162 if safemode != 0 { 163 flags = "safe" 164 } 165 p.string(flags) 166 } 167 168 if p.trace { 169 p.tracef("\n") 170 } 171 172 // collect objects to export 173 var consts, vars, funcs []*Sym 174 var types []*Type 175 for _, n := range exportlist { 176 sym := n.Sym 177 // TODO(gri) Closures appear marked as exported. 178 // Investigate and determine if we need this. 179 if sym.Flags&SymExported != 0 { 180 continue 181 } 182 sym.Flags |= SymExported 183 184 // TODO(gri) Closures have dots in their names; 185 // e.g., TestFloatZeroValue.func1 in math/big tests. 186 // We may not need this eventually. See also comment 187 // on sym.Flags&SymExported test above. 188 if strings.Contains(sym.Name, ".") { 189 Fatalf("unexpected export symbol: %v", sym) 190 } 191 192 if sym.Flags&SymExport != 0 { 193 if sym.Def == nil { 194 Fatalf("unknown export symbol: %v", sym) 195 } 196 switch n := sym.Def; n.Op { 197 case OLITERAL: 198 // constant 199 typecheck(&n, Erv) 200 if n == nil || n.Op != OLITERAL { 201 Fatalf("dumpexportconst: oconst nil: %v", sym) 202 } 203 consts = append(consts, sym) 204 205 case ONAME: 206 // variable or function 207 typecheck(&n, Erv|Ecall) 208 if n == nil || n.Type == nil { 209 Fatalf("variable/function exported but not defined: %v", sym) 210 } 211 if n.Type.Etype == TFUNC && n.Class == PFUNC { 212 funcs = append(funcs, sym) 213 } else { 214 vars = append(vars, sym) 215 } 216 217 case OTYPE: 218 // named type 219 t := n.Type 220 if t.Etype == TFORW { 221 Fatalf("export of incomplete type %v", sym) 222 } 223 types = append(types, t) 224 225 default: 226 Fatalf("unexpected export symbol: %v %v", Oconv(int(n.Op), 0), sym) 227 } 228 } 229 } 230 exportlist = nil // match export.go use of exportlist 231 232 // for reproducible output 233 sort.Sort(symByName(consts)) 234 sort.Sort(symByName(vars)) 235 sort.Sort(symByName(funcs)) 236 // sort types later when we have fewer types left 237 238 // write consts 239 p.int(len(consts)) 240 for _, sym := range consts { 241 n := sym.Def 242 typ := n.Type // may or may not be specified 243 // Untyped (ideal) constants get their own type. This decouples 244 // the constant type from the encoding of the constant value. 245 if typ == nil || isideal(typ) { 246 typ = untype(n.Val().Ctype()) 247 } 248 249 p.string(sym.Name) 250 p.typ(typ) 251 p.value(n.Val()) 252 } 253 254 // write vars 255 p.int(len(vars)) 256 for _, sym := range vars { 257 p.string(sym.Name) 258 p.typ(sym.Def.Type) 259 } 260 261 // write funcs 262 p.int(len(funcs)) 263 for _, sym := range funcs { 264 p.string(sym.Name) 265 // The type can only be a signature for functions. However, by always 266 // writing the complete type specification (rather than just a signature) 267 // we keep the option open of sharing common signatures across multiple 268 // functions as a means to further compress the export data. 269 p.typ(sym.Def.Type) 270 p.int(p.collectInlined(sym.Def)) 271 } 272 273 // determine which types are still left to write and sort them 274 i := 0 275 for _, t := range types { 276 if _, ok := p.typIndex[t]; !ok { 277 types[i] = t 278 i++ 279 } 280 } 281 types = types[:i] 282 sort.Sort(typByName(types)) 283 284 // write types 285 p.int(len(types)) 286 for _, t := range types { 287 // Writing a type may further reduce the number of types 288 // that are left to be written, but at this point we don't 289 // care. 290 p.typ(t) 291 } 292 293 if p.trace { 294 p.tracef("\n") 295 } 296 297 // --- compiler-specific export data --- 298 299 if p.trace { 300 p.tracef("\n--- compiler specific export data ---\n") 301 if p.indent != 0 { 302 Fatalf("incorrect indentation") 303 } 304 } 305 306 // write inlined function bodies 307 p.int(len(p.inlined)) 308 for i, f := range p.inlined { 309 p.body(i, f) 310 } 311 312 if p.trace { 313 p.tracef("\n") 314 } 315 316 // --- end of export data --- 317 318 return p.written 319 } 320 321 type symByName []*Sym 322 323 func (a symByName) Len() int { return len(a) } 324 func (a symByName) Less(i, j int) bool { return a[i].Name < a[j].Name } 325 func (a symByName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 326 327 type typByName []*Type 328 329 func (a typByName) Len() int { return len(a) } 330 func (a typByName) Less(i, j int) bool { return a[i].Sym.Name < a[j].Sym.Name } 331 func (a typByName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 332 333 type exporter struct { 334 out *obj.Biobuf 335 pkgIndex map[*Pkg]int 336 typIndex map[*Type]int 337 inlined []*Func 338 339 written int // bytes written 340 indent int // for p.trace 341 trace bool 342 } 343 344 func (p *exporter) pkg(pkg *Pkg) { 345 if pkg == nil { 346 Fatalf("unexpected nil pkg") 347 } 348 349 // if we saw the package before, write its index (>= 0) 350 if i, ok := p.pkgIndex[pkg]; ok { 351 p.index('P', i) 352 return 353 } 354 355 // otherwise, remember the package, write the package tag (< 0) and package data 356 if p.trace { 357 p.tracef("P%d = { ", len(p.pkgIndex)) 358 defer p.tracef("} ") 359 } 360 p.pkgIndex[pkg] = len(p.pkgIndex) 361 362 p.tag(packageTag) 363 p.string(pkg.Name) 364 p.string(pkg.Path) 365 } 366 367 func (p *exporter) typ(t *Type) { 368 if t == nil { 369 Fatalf("nil type") 370 } 371 372 // Possible optimization: Anonymous pointer types *T where 373 // T is a named type are common. We could canonicalize all 374 // such types *T to a single type PT = *T. This would lead 375 // to at most one *T entry in typIndex, and all future *T's 376 // would be encoded as the respective index directly. Would 377 // save 1 byte (pointerTag) per *T and reduce the typIndex 378 // size (at the cost of a canonicalization map). We can do 379 // this later, without encoding format change. 380 381 // if we saw the type before, write its index (>= 0) 382 if i, ok := p.typIndex[t]; ok { 383 p.index('T', i) 384 return 385 } 386 387 // otherwise, remember the type, write the type tag (< 0) and type data 388 if p.trace { 389 p.tracef("T%d = {>\n", len(p.typIndex)) 390 defer p.tracef("<\n} ") 391 } 392 p.typIndex[t] = len(p.typIndex) 393 394 // pick off named types 395 if sym := t.Sym; sym != nil { 396 // Fields should be exported by p.field(). 397 if t.Etype == TFIELD { 398 Fatalf("printing a field/parameter with wrong function") 399 } 400 // Predeclared types should have been found in the type map. 401 if t.Orig == t { 402 Fatalf("predeclared type missing from type map?") 403 } 404 // TODO(gri) The assertion below seems incorrect (crashes during all.bash). 405 // Investigate. 406 /* 407 // we expect the respective definition to point to us 408 if sym.Def.Type != t { 409 Fatalf("type definition doesn't point to us?") 410 } 411 */ 412 413 p.tag(namedTag) 414 p.qualifiedName(sym) 415 416 // write underlying type 417 p.typ(t.Orig) 418 419 // interfaces don't have associated methods 420 if t.Orig.Etype == TINTER { 421 return 422 } 423 424 // sort methods for reproducible export format 425 // TODO(gri) Determine if they are already sorted 426 // in which case we can drop this step. 427 var methods []*Type 428 for m := t.Method; m != nil; m = m.Down { 429 methods = append(methods, m) 430 } 431 sort.Sort(methodbyname(methods)) 432 p.int(len(methods)) 433 434 if p.trace && t.Method != nil { 435 p.tracef("associated methods {>\n") 436 } 437 438 for _, m := range methods { 439 p.string(m.Sym.Name) 440 p.paramList(getthisx(m.Type)) 441 p.paramList(getinargx(m.Type)) 442 p.paramList(getoutargx(m.Type)) 443 p.int(p.collectInlined(m.Type.Nname)) 444 445 if p.trace && m.Down != nil { 446 p.tracef("\n") 447 } 448 } 449 450 if p.trace && t.Method != nil { 451 p.tracef("<\n} ") 452 } 453 454 return 455 } 456 457 // otherwise we have a type literal 458 switch t.Etype { 459 case TARRAY: 460 // TODO(gri) define named constant for the -100 461 if t.Bound >= 0 || t.Bound == -100 { 462 p.tag(arrayTag) 463 p.int64(t.Bound) 464 } else { 465 p.tag(sliceTag) 466 } 467 p.typ(t.Type) 468 469 case T_old_DARRAY: 470 // see p.param use of T_old_DARRAY 471 p.tag(dddTag) 472 p.typ(t.Type) 473 474 case TSTRUCT: 475 p.tag(structTag) 476 p.fieldList(t) 477 478 case TPTR32, TPTR64: // could use Tptr but these are constants 479 p.tag(pointerTag) 480 p.typ(t.Type) 481 482 case TFUNC: 483 p.tag(signatureTag) 484 p.paramList(getinargx(t)) 485 p.paramList(getoutargx(t)) 486 487 case TINTER: 488 p.tag(interfaceTag) 489 490 // gc doesn't separate between embedded interfaces 491 // and methods declared explicitly with an interface 492 p.int(0) // no embedded interfaces 493 p.methodList(t) 494 495 case TMAP: 496 p.tag(mapTag) 497 p.typ(t.Down) // key 498 p.typ(t.Type) // val 499 500 case TCHAN: 501 p.tag(chanTag) 502 p.int(int(t.Chan)) 503 p.typ(t.Type) 504 505 default: 506 Fatalf("unexpected type: %s (Etype = %d)", Tconv(t, 0), t.Etype) 507 } 508 } 509 510 func (p *exporter) qualifiedName(sym *Sym) { 511 p.string(sym.Name) 512 p.pkg(sym.Pkg) 513 } 514 515 func (p *exporter) fieldList(t *Type) { 516 if p.trace && t.Type != nil { 517 p.tracef("fields {>\n") 518 defer p.tracef("<\n} ") 519 } 520 521 p.int(countfield(t)) 522 for f := t.Type; f != nil; f = f.Down { 523 p.field(f) 524 if p.trace && f.Down != nil { 525 p.tracef("\n") 526 } 527 } 528 } 529 530 func (p *exporter) field(f *Type) { 531 if f.Etype != TFIELD { 532 Fatalf("field expected") 533 } 534 535 p.fieldName(f) 536 p.typ(f.Type) 537 p.note(f.Note) 538 } 539 540 func (p *exporter) note(n *string) { 541 var s string 542 if n != nil { 543 s = *n 544 } 545 p.string(s) 546 } 547 548 func (p *exporter) methodList(t *Type) { 549 if p.trace && t.Type != nil { 550 p.tracef("methods {>\n") 551 defer p.tracef("<\n} ") 552 } 553 554 p.int(countfield(t)) 555 for m := t.Type; m != nil; m = m.Down { 556 p.method(m) 557 if p.trace && m.Down != nil { 558 p.tracef("\n") 559 } 560 } 561 } 562 563 func (p *exporter) method(m *Type) { 564 if m.Etype != TFIELD { 565 Fatalf("method expected") 566 } 567 568 p.fieldName(m) 569 // TODO(gri) For functions signatures, we use p.typ() to export 570 // so we could share the same type with multiple functions. Do 571 // the same here, or never try to do this for functions. 572 p.paramList(getinargx(m.Type)) 573 p.paramList(getoutargx(m.Type)) 574 } 575 576 // fieldName is like qualifiedName but it doesn't record the package 577 // for blank (_) or exported names. 578 func (p *exporter) fieldName(t *Type) { 579 sym := t.Sym 580 581 var name string 582 if t.Embedded == 0 { 583 name = sym.Name 584 } else if bname := basetypeName(t); bname != "" && !exportname(bname) { 585 // anonymous field with unexported base type name: use "?" as field name 586 // (bname != "" per spec, but we are conservative in case of errors) 587 name = "?" 588 } 589 590 p.string(name) 591 if name == "?" || name != "_" && name != "" && !exportname(name) { 592 p.pkg(sym.Pkg) 593 } 594 } 595 596 func basetypeName(t *Type) string { 597 s := t.Sym 598 if s == nil && Isptr[t.Etype] { 599 s = t.Type.Sym // deref 600 } 601 if s != nil { 602 return s.Name 603 } 604 return "" 605 } 606 607 func (p *exporter) paramList(params *Type) { 608 if params.Etype != TSTRUCT || !params.Funarg { 609 Fatalf("parameter list expected") 610 } 611 612 // use negative length to indicate unnamed parameters 613 // (look at the first parameter only since either all 614 // names are present or all are absent) 615 n := countfield(params) 616 if n > 0 && parName(params.Type) == "" { 617 n = -n 618 } 619 p.int(n) 620 for q := params.Type; q != nil; q = q.Down { 621 p.param(q, n) 622 } 623 } 624 625 func (p *exporter) param(q *Type, n int) { 626 if q.Etype != TFIELD { 627 Fatalf("parameter expected") 628 } 629 t := q.Type 630 if q.Isddd { 631 // create a fake type to encode ... just for the p.typ call 632 // (T_old_DARRAY is not used anywhere else in the compiler, 633 // we use it here to communicate between p.param and p.typ.) 634 t = &Type{Etype: T_old_DARRAY, Type: t.Type} 635 } 636 p.typ(t) 637 if n > 0 { 638 p.string(parName(q)) 639 } 640 // TODO(gri) This is compiler-specific (escape info). 641 // Move into compiler-specific section eventually? 642 // (Not having escape info causes tests to fail, e.g. runtime GCInfoTest) 643 p.note(q.Note) 644 } 645 646 func parName(q *Type) string { 647 if q.Sym == nil { 648 return "" 649 } 650 name := q.Sym.Name 651 // undo gc-internal name mangling - we just need the source name 652 if len(name) > 0 && name[0] == '~' { 653 // name is ~b%d or ~r%d 654 switch name[1] { 655 case 'b': 656 return "_" 657 case 'r': 658 return "" 659 default: 660 Fatalf("unexpected parameter name: %s", name) 661 } 662 } 663 // undo gc-internal name specialization 664 if i := strings.Index(name, "ยท"); i > 0 { 665 name = name[:i] // cut off numbering 666 } 667 return name 668 } 669 670 func (p *exporter) value(x Val) { 671 if p.trace { 672 p.tracef("= ") 673 } 674 675 switch x := x.U.(type) { 676 case bool: 677 tag := falseTag 678 if x { 679 tag = trueTag 680 } 681 p.tag(tag) 682 683 case *Mpint: 684 if Mpcmpfixfix(Minintval[TINT64], x) <= 0 && Mpcmpfixfix(x, Maxintval[TINT64]) <= 0 { 685 // common case: x fits into an int64 - use compact encoding 686 p.tag(int64Tag) 687 p.int64(Mpgetfix(x)) 688 return 689 } 690 // uncommon case: large x - use float encoding 691 // (powers of 2 will be encoded efficiently with exponent) 692 p.tag(floatTag) 693 f := newMpflt() 694 Mpmovefixflt(f, x) 695 p.float(f) 696 697 case *Mpflt: 698 p.tag(floatTag) 699 p.float(x) 700 701 case *Mpcplx: 702 p.tag(complexTag) 703 p.float(&x.Real) 704 p.float(&x.Imag) 705 706 case string: 707 p.tag(stringTag) 708 p.string(x) 709 710 default: 711 Fatalf("unexpected value %v (%T)", x, x) 712 } 713 } 714 715 func (p *exporter) float(x *Mpflt) { 716 // extract sign (there is no -0) 717 f := &x.Val 718 sign := f.Sign() 719 if sign == 0 { 720 // x == 0 721 p.int(0) 722 return 723 } 724 // x != 0 725 726 // extract exponent such that 0.5 <= m < 1.0 727 var m big.Float 728 exp := f.MantExp(&m) 729 730 // extract mantissa as *big.Int 731 // - set exponent large enough so mant satisfies mant.IsInt() 732 // - get *big.Int from mant 733 m.SetMantExp(&m, int(m.MinPrec())) 734 mant, acc := m.Int(nil) 735 if acc != big.Exact { 736 Fatalf("internal error") 737 } 738 739 p.int(sign) 740 p.int(exp) 741 p.string(string(mant.Bytes())) 742 } 743 744 // ---------------------------------------------------------------------------- 745 // Inlined function bodies 746 747 // TODO(gri) This section is incomplete. At the moment nothing meaningful 748 // is written out for exported functions with inlined function bodies. 749 750 func (p *exporter) collectInlined(n *Node) int { 751 if n != nil && n.Func != nil && n.Func.Inl != nil { 752 // when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet. 753 // currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package 754 if Debug['l'] < 2 { 755 typecheckinl(n) 756 } 757 p.inlined = append(p.inlined, n.Func) 758 return len(p.inlined) - 1 // index >= 0 => inlined 759 } 760 return -1 // index < 0 => not inlined 761 } 762 763 func (p *exporter) body(i int, f *Func) { 764 p.int(i) 765 p.block(f.Inl) 766 } 767 768 func (p *exporter) block(list *NodeList) { 769 p.int(count(list)) 770 for q := list; q != nil; q = q.Next { 771 p.stmt(q.N) 772 } 773 } 774 775 func (p *exporter) stmt(n *Node) { 776 // TODO(gri) do something sensible here 777 p.string("body") 778 } 779 780 // ---------------------------------------------------------------------------- 781 // Low-level encoders 782 783 func (p *exporter) index(marker byte, index int) { 784 if index < 0 { 785 Fatalf("invalid index < 0") 786 } 787 if debugFormat { 788 p.marker('t') 789 } 790 if p.trace { 791 p.tracef("%c%d ", marker, index) 792 } 793 p.rawInt64(int64(index)) 794 } 795 796 func (p *exporter) tag(tag int) { 797 if tag >= 0 { 798 Fatalf("invalid tag >= 0") 799 } 800 if debugFormat { 801 p.marker('t') 802 } 803 if p.trace { 804 p.tracef("%s ", tagString[-tag]) 805 } 806 p.rawInt64(int64(tag)) 807 } 808 809 func (p *exporter) int(x int) { 810 p.int64(int64(x)) 811 } 812 813 func (p *exporter) int64(x int64) { 814 if debugFormat { 815 p.marker('i') 816 } 817 if p.trace { 818 p.tracef("%d ", x) 819 } 820 p.rawInt64(x) 821 } 822 823 func (p *exporter) string(s string) { 824 if debugFormat { 825 p.marker('s') 826 } 827 if p.trace { 828 p.tracef("%q ", s) 829 } 830 p.rawInt64(int64(len(s))) 831 for i := 0; i < len(s); i++ { 832 p.byte(s[i]) 833 } 834 } 835 836 // marker emits a marker byte and position information which makes 837 // it easy for a reader to detect if it is "out of sync". Used for 838 // debugFormat format only. 839 func (p *exporter) marker(m byte) { 840 p.byte(m) 841 p.rawInt64(int64(p.written)) 842 } 843 844 // rawInt64 should only be used by low-level encoders 845 func (p *exporter) rawInt64(x int64) { 846 var tmp [binary.MaxVarintLen64]byte 847 n := binary.PutVarint(tmp[:], x) 848 for i := 0; i < n; i++ { 849 p.byte(tmp[i]) 850 } 851 } 852 853 // byte is the bottleneck interface to write to p.out. 854 // byte escapes b as follows (any encoding does that 855 // hides '$'): 856 // 857 // '$' => '|' 'S' 858 // '|' => '|' '|' 859 // 860 // Necessary so other tools can find the end of the 861 // export data by searching for "$$". 862 func (p *exporter) byte(b byte) { 863 switch b { 864 case '$': 865 // write '$' as '|' 'S' 866 b = 'S' 867 fallthrough 868 case '|': 869 // write '|' as '|' '|' 870 obj.Bputc(p.out, '|') 871 p.written++ 872 } 873 obj.Bputc(p.out, b) 874 p.written++ 875 } 876 877 // tracef is like fmt.Printf but it rewrites the format string 878 // to take care of indentation. 879 func (p *exporter) tracef(format string, args ...interface{}) { 880 if strings.IndexAny(format, "<>\n") >= 0 { 881 var buf bytes.Buffer 882 for i := 0; i < len(format); i++ { 883 // no need to deal with runes 884 ch := format[i] 885 switch ch { 886 case '>': 887 p.indent++ 888 continue 889 case '<': 890 p.indent-- 891 continue 892 } 893 buf.WriteByte(ch) 894 if ch == '\n' { 895 for j := p.indent; j > 0; j-- { 896 buf.WriteString(". ") 897 } 898 } 899 } 900 format = buf.String() 901 } 902 fmt.Printf(format, args...) 903 } 904 905 // ---------------------------------------------------------------------------- 906 // Export format 907 908 // Tags. Must be < 0. 909 const ( 910 // Packages 911 packageTag = -(iota + 1) 912 913 // Types 914 namedTag 915 arrayTag 916 sliceTag 917 dddTag 918 structTag 919 pointerTag 920 signatureTag 921 interfaceTag 922 mapTag 923 chanTag 924 925 // Values 926 falseTag 927 trueTag 928 int64Tag 929 floatTag 930 fractionTag // not used by gc 931 complexTag 932 stringTag 933 ) 934 935 // Debugging support. 936 // (tagString is only used when tracing is enabled) 937 var tagString = [...]string{ 938 // Packages: 939 -packageTag: "package", 940 941 // Types: 942 -namedTag: "named type", 943 -arrayTag: "array", 944 -sliceTag: "slice", 945 -dddTag: "ddd", 946 -structTag: "struct", 947 -pointerTag: "pointer", 948 -signatureTag: "signature", 949 -interfaceTag: "interface", 950 -mapTag: "map", 951 -chanTag: "chan", 952 953 // Values: 954 -falseTag: "false", 955 -trueTag: "true", 956 -int64Tag: "int64", 957 -floatTag: "float", 958 -fractionTag: "fraction", 959 -complexTag: "complex", 960 -stringTag: "string", 961 } 962 963 // untype returns the "pseudo" untyped type for a Ctype (import/export use only). 964 // (we can't use an pre-initialized array because we must be sure all types are 965 // set up) 966 func untype(ctype Ctype) *Type { 967 switch ctype { 968 case CTINT: 969 return idealint 970 case CTRUNE: 971 return idealrune 972 case CTFLT: 973 return idealfloat 974 case CTCPLX: 975 return idealcomplex 976 case CTSTR: 977 return idealstring 978 case CTBOOL: 979 return idealbool 980 case CTNIL: 981 return Types[TNIL] 982 } 983 Fatalf("unknown Ctype") 984 return nil 985 } 986 987 var ( 988 idealint = typ(TIDEAL) 989 idealrune = typ(TIDEAL) 990 idealfloat = typ(TIDEAL) 991 idealcomplex = typ(TIDEAL) 992 ) 993 994 var predecl []*Type // initialized lazily 995 996 func predeclared() []*Type { 997 if predecl == nil { 998 // initialize lazily to be sure that all 999 // elements have been initialized before 1000 predecl = []*Type{ 1001 // basic types 1002 Types[TBOOL], 1003 Types[TINT], 1004 Types[TINT8], 1005 Types[TINT16], 1006 Types[TINT32], 1007 Types[TINT64], 1008 Types[TUINT], 1009 Types[TUINT8], 1010 Types[TUINT16], 1011 Types[TUINT32], 1012 Types[TUINT64], 1013 Types[TUINTPTR], 1014 Types[TFLOAT32], 1015 Types[TFLOAT64], 1016 Types[TCOMPLEX64], 1017 Types[TCOMPLEX128], 1018 Types[TSTRING], 1019 1020 // aliases 1021 bytetype, 1022 runetype, 1023 1024 // error 1025 errortype, 1026 1027 // untyped types 1028 untype(CTBOOL), 1029 untype(CTINT), 1030 untype(CTRUNE), 1031 untype(CTFLT), 1032 untype(CTCPLX), 1033 untype(CTSTR), 1034 untype(CTNIL), 1035 1036 // package unsafe 1037 Types[TUNSAFEPTR], 1038 } 1039 } 1040 return predecl 1041 }