github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/x/tools/go/gcimporter15/bexport.go (about) 1 // Copyright 2016 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 // +build go1.6 6 7 // Binary package export. 8 // This file was derived from $GOROOT/src/cmd/compile/internal/gc/bexport.go; 9 // see that file for specification of the format. 10 11 package gcimporter 12 13 import ( 14 "bytes" 15 "encoding/binary" 16 "fmt" 17 "go/ast" 18 "go/constant" 19 "go/token" 20 "go/types" 21 "log" 22 "math" 23 "math/big" 24 "sort" 25 "strings" 26 ) 27 28 // If debugFormat is set, each integer and string value is preceded by a marker 29 // and position information in the encoding. This mechanism permits an importer 30 // to recognize immediately when it is out of sync. The importer recognizes this 31 // mode automatically (i.e., it can import export data produced with debugging 32 // support even if debugFormat is not set at the time of import). This mode will 33 // lead to massively larger export data (by a factor of 2 to 3) and should only 34 // be enabled during development and debugging. 35 // 36 // NOTE: This flag is the first flag to enable if importing dies because of 37 // (suspected) format errors, and whenever a change is made to the format. 38 const debugFormat = false // default: false 39 40 // If trace is set, debugging output is printed to std out. 41 const trace = false // default: false 42 43 const exportVersion = "v0" 44 45 // trackAllTypes enables cycle tracking for all types, not just named 46 // types. The existing compiler invariants assume that unnamed types 47 // that are not completely set up are not used, or else there are spurious 48 // errors. 49 // If disabled, only named types are tracked, possibly leading to slightly 50 // less efficient encoding in rare cases. It also prevents the export of 51 // some corner-case type declarations (but those are not handled correctly 52 // with with the textual export format either). 53 // TODO(gri) enable and remove once issues caused by it are fixed 54 const trackAllTypes = false 55 56 type exporter struct { 57 fset *token.FileSet 58 out bytes.Buffer 59 60 // object -> index maps, indexed in order of serialization 61 strIndex map[string]int 62 pkgIndex map[*types.Package]int 63 typIndex map[types.Type]int 64 65 // position encoding 66 posInfoFormat bool 67 prevFile string 68 prevLine int 69 70 // debugging support 71 written int // bytes written 72 indent int // for trace 73 } 74 75 // BExportData returns binary export data for pkg. 76 // If no file set is provided, position info will be missing. 77 func BExportData(fset *token.FileSet, pkg *types.Package) []byte { 78 p := exporter{ 79 fset: fset, 80 strIndex: map[string]int{"": 0}, // empty string is mapped to 0 81 pkgIndex: make(map[*types.Package]int), 82 typIndex: make(map[types.Type]int), 83 posInfoFormat: true, // TODO(gri) might become a flag, eventually 84 } 85 86 // first byte indicates low-level encoding format 87 var format byte = 'c' // compact 88 if debugFormat { 89 format = 'd' 90 } 91 p.rawByte(format) 92 93 format = 'n' // track named types only 94 if trackAllTypes { 95 format = 'a' 96 } 97 p.rawByte(format) 98 99 // posInfo exported or not? 100 p.bool(p.posInfoFormat) 101 102 // --- generic export data --- 103 104 if trace { 105 p.tracef("\n--- generic export data ---\n") 106 if p.indent != 0 { 107 log.Fatalf("gcimporter: incorrect indentation %d", p.indent) 108 } 109 } 110 111 if trace { 112 p.tracef("version = ") 113 } 114 p.string(exportVersion) 115 if trace { 116 p.tracef("\n") 117 } 118 119 // populate type map with predeclared "known" types 120 for index, typ := range predeclared { 121 p.typIndex[typ] = index 122 } 123 if len(p.typIndex) != len(predeclared) { 124 log.Fatalf("gcimporter: duplicate entries in type map?") 125 } 126 127 // write package data 128 p.pkg(pkg, true) 129 if trace { 130 p.tracef("\n") 131 } 132 133 // write objects 134 objcount := 0 135 scope := pkg.Scope() 136 for _, name := range scope.Names() { 137 if !ast.IsExported(name) { 138 continue 139 } 140 if trace { 141 p.tracef("\n") 142 } 143 p.obj(scope.Lookup(name)) 144 objcount++ 145 } 146 147 // indicate end of list 148 if trace { 149 p.tracef("\n") 150 } 151 p.tag(endTag) 152 153 // for self-verification only (redundant) 154 p.int(objcount) 155 156 if trace { 157 p.tracef("\n") 158 } 159 160 // --- end of export data --- 161 162 return p.out.Bytes() 163 } 164 165 func (p *exporter) pkg(pkg *types.Package, emptypath bool) { 166 if pkg == nil { 167 log.Fatalf("gcimporter: unexpected nil pkg") 168 } 169 170 // if we saw the package before, write its index (>= 0) 171 if i, ok := p.pkgIndex[pkg]; ok { 172 p.index('P', i) 173 return 174 } 175 176 // otherwise, remember the package, write the package tag (< 0) and package data 177 if trace { 178 p.tracef("P%d = { ", len(p.pkgIndex)) 179 defer p.tracef("} ") 180 } 181 p.pkgIndex[pkg] = len(p.pkgIndex) 182 183 p.tag(packageTag) 184 p.string(pkg.Name()) 185 if emptypath { 186 p.string("") 187 } else { 188 p.string(pkg.Path()) 189 } 190 } 191 192 func (p *exporter) obj(obj types.Object) { 193 switch obj := obj.(type) { 194 case *types.Const: 195 p.tag(constTag) 196 p.pos(obj) 197 p.qualifiedName(obj) 198 p.typ(obj.Type()) 199 p.value(obj.Val()) 200 201 case *types.TypeName: 202 p.tag(typeTag) 203 p.typ(obj.Type()) 204 205 case *types.Var: 206 p.tag(varTag) 207 p.pos(obj) 208 p.qualifiedName(obj) 209 p.typ(obj.Type()) 210 211 case *types.Func: 212 p.tag(funcTag) 213 p.pos(obj) 214 p.qualifiedName(obj) 215 sig := obj.Type().(*types.Signature) 216 p.paramList(sig.Params(), sig.Variadic()) 217 p.paramList(sig.Results(), false) 218 219 default: 220 log.Fatalf("gcimporter: unexpected object %v (%T)", obj, obj) 221 } 222 } 223 224 func (p *exporter) pos(obj types.Object) { 225 if !p.posInfoFormat { 226 return 227 } 228 229 file, line := p.fileLine(obj) 230 if file == p.prevFile { 231 // common case: write line delta 232 // delta == 0 means different file or no line change 233 delta := line - p.prevLine 234 p.int(delta) 235 if delta == 0 { 236 p.int(-1) // -1 means no file change 237 } 238 } else { 239 // different file 240 p.int(0) 241 // Encode filename as length of common prefix with previous 242 // filename, followed by (possibly empty) suffix. Filenames 243 // frequently share path prefixes, so this can save a lot 244 // of space and make export data size less dependent on file 245 // path length. The suffix is unlikely to be empty because 246 // file names tend to end in ".go". 247 n := commonPrefixLen(p.prevFile, file) 248 p.int(n) // n >= 0 249 p.string(file[n:]) // write suffix only 250 p.prevFile = file 251 p.int(line) 252 } 253 p.prevLine = line 254 } 255 256 func (p *exporter) fileLine(obj types.Object) (file string, line int) { 257 if p.fset != nil { 258 pos := p.fset.Position(obj.Pos()) 259 file = pos.Filename 260 line = pos.Line 261 } 262 return 263 } 264 265 func commonPrefixLen(a, b string) int { 266 if len(a) > len(b) { 267 a, b = b, a 268 } 269 // len(a) <= len(b) 270 i := 0 271 for i < len(a) && a[i] == b[i] { 272 i++ 273 } 274 return i 275 } 276 277 func (p *exporter) qualifiedName(obj types.Object) { 278 p.string(obj.Name()) 279 p.pkg(obj.Pkg(), false) 280 } 281 282 func (p *exporter) typ(t types.Type) { 283 if t == nil { 284 log.Fatalf("gcimporter: nil type") 285 } 286 287 // Possible optimization: Anonymous pointer types *T where 288 // T is a named type are common. We could canonicalize all 289 // such types *T to a single type PT = *T. This would lead 290 // to at most one *T entry in typIndex, and all future *T's 291 // would be encoded as the respective index directly. Would 292 // save 1 byte (pointerTag) per *T and reduce the typIndex 293 // size (at the cost of a canonicalization map). We can do 294 // this later, without encoding format change. 295 296 // if we saw the type before, write its index (>= 0) 297 if i, ok := p.typIndex[t]; ok { 298 p.index('T', i) 299 return 300 } 301 302 // otherwise, remember the type, write the type tag (< 0) and type data 303 if trackAllTypes { 304 if trace { 305 p.tracef("T%d = {>\n", len(p.typIndex)) 306 defer p.tracef("<\n} ") 307 } 308 p.typIndex[t] = len(p.typIndex) 309 } 310 311 switch t := t.(type) { 312 case *types.Named: 313 if !trackAllTypes { 314 // if we don't track all types, track named types now 315 p.typIndex[t] = len(p.typIndex) 316 } 317 318 p.tag(namedTag) 319 p.pos(t.Obj()) 320 p.qualifiedName(t.Obj()) 321 p.typ(t.Underlying()) 322 if !types.IsInterface(t) { 323 p.assocMethods(t) 324 } 325 326 case *types.Array: 327 p.tag(arrayTag) 328 p.int64(t.Len()) 329 p.typ(t.Elem()) 330 331 case *types.Slice: 332 p.tag(sliceTag) 333 p.typ(t.Elem()) 334 335 case *dddSlice: 336 p.tag(dddTag) 337 p.typ(t.elem) 338 339 case *types.Struct: 340 p.tag(structTag) 341 p.fieldList(t) 342 343 case *types.Pointer: 344 p.tag(pointerTag) 345 p.typ(t.Elem()) 346 347 case *types.Signature: 348 p.tag(signatureTag) 349 p.paramList(t.Params(), t.Variadic()) 350 p.paramList(t.Results(), false) 351 352 case *types.Interface: 353 p.tag(interfaceTag) 354 p.iface(t) 355 356 case *types.Map: 357 p.tag(mapTag) 358 p.typ(t.Key()) 359 p.typ(t.Elem()) 360 361 case *types.Chan: 362 p.tag(chanTag) 363 p.int(int(3 - t.Dir())) // hack 364 p.typ(t.Elem()) 365 366 default: 367 log.Fatalf("gcimporter: unexpected type %T: %s", t, t) 368 } 369 } 370 371 func (p *exporter) assocMethods(named *types.Named) { 372 // Sort methods (for determinism). 373 var methods []*types.Func 374 for i := 0; i < named.NumMethods(); i++ { 375 methods = append(methods, named.Method(i)) 376 } 377 sort.Sort(methodsByName(methods)) 378 379 p.int(len(methods)) 380 381 if trace && methods != nil { 382 p.tracef("associated methods {>\n") 383 } 384 385 for i, m := range methods { 386 if trace && i > 0 { 387 p.tracef("\n") 388 } 389 390 p.pos(m) 391 name := m.Name() 392 p.string(name) 393 if !exported(name) { 394 p.pkg(m.Pkg(), false) 395 } 396 397 sig := m.Type().(*types.Signature) 398 p.paramList(types.NewTuple(sig.Recv()), false) 399 p.paramList(sig.Params(), sig.Variadic()) 400 p.paramList(sig.Results(), false) 401 } 402 403 if trace && methods != nil { 404 p.tracef("<\n} ") 405 } 406 } 407 408 type methodsByName []*types.Func 409 410 func (x methodsByName) Len() int { return len(x) } 411 func (x methodsByName) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 412 func (x methodsByName) Less(i, j int) bool { return x[i].Name() < x[j].Name() } 413 414 func (p *exporter) fieldList(t *types.Struct) { 415 if trace && t.NumFields() > 0 { 416 p.tracef("fields {>\n") 417 defer p.tracef("<\n} ") 418 } 419 420 p.int(t.NumFields()) 421 for i := 0; i < t.NumFields(); i++ { 422 if trace && i > 0 { 423 p.tracef("\n") 424 } 425 p.field(t.Field(i)) 426 p.string(t.Tag(i)) 427 } 428 } 429 430 func (p *exporter) field(f *types.Var) { 431 if !f.IsField() { 432 log.Fatalf("gcimporter: field expected") 433 } 434 435 p.pos(f) 436 p.fieldName(f) 437 p.typ(f.Type()) 438 } 439 440 func (p *exporter) iface(t *types.Interface) { 441 // TODO(gri): enable importer to load embedded interfaces, 442 // then emit Embeddeds and ExplicitMethods separately here. 443 p.int(0) 444 445 n := t.NumMethods() 446 if trace && n > 0 { 447 p.tracef("methods {>\n") 448 defer p.tracef("<\n} ") 449 } 450 p.int(n) 451 for i := 0; i < n; i++ { 452 if trace && i > 0 { 453 p.tracef("\n") 454 } 455 p.method(t.Method(i)) 456 } 457 } 458 459 func (p *exporter) method(m *types.Func) { 460 sig := m.Type().(*types.Signature) 461 if sig.Recv() == nil { 462 log.Fatalf("gcimporter: method expected") 463 } 464 465 p.pos(m) 466 p.string(m.Name()) 467 if m.Name() != "_" && !ast.IsExported(m.Name()) { 468 p.pkg(m.Pkg(), false) 469 } 470 471 // interface method; no need to encode receiver. 472 p.paramList(sig.Params(), sig.Variadic()) 473 p.paramList(sig.Results(), false) 474 } 475 476 // fieldName is like qualifiedName but it doesn't record the package 477 // for blank (_) or exported names. 478 func (p *exporter) fieldName(f *types.Var) { 479 name := f.Name() 480 481 // anonymous field with unexported base type name: use "?" as field name 482 // (bname != "" per spec, but we are conservative in case of errors) 483 if f.Anonymous() { 484 base := f.Type() 485 if ptr, ok := base.(*types.Pointer); ok { 486 base = ptr.Elem() 487 } 488 if named, ok := base.(*types.Named); ok && !named.Obj().Exported() { 489 name = "?" 490 } 491 } 492 493 p.string(name) 494 if name == "?" || name != "_" && !f.Exported() { 495 p.pkg(f.Pkg(), false) 496 } 497 } 498 499 func (p *exporter) paramList(params *types.Tuple, variadic bool) { 500 // use negative length to indicate unnamed parameters 501 // (look at the first parameter only since either all 502 // names are present or all are absent) 503 n := params.Len() 504 if n > 0 && params.At(0).Name() == "" { 505 n = -n 506 } 507 p.int(n) 508 for i := 0; i < params.Len(); i++ { 509 q := params.At(i) 510 t := q.Type() 511 if variadic && i == params.Len()-1 { 512 t = &dddSlice{t.(*types.Slice).Elem()} 513 } 514 p.typ(t) 515 if n > 0 { 516 name := q.Name() 517 p.string(name) 518 if name != "_" { 519 p.pkg(q.Pkg(), false) 520 } 521 } 522 p.string("") // no compiler-specific info 523 } 524 } 525 526 func (p *exporter) value(x constant.Value) { 527 if trace { 528 p.tracef("= ") 529 } 530 531 switch x.Kind() { 532 case constant.Bool: 533 tag := falseTag 534 if constant.BoolVal(x) { 535 tag = trueTag 536 } 537 p.tag(tag) 538 539 case constant.Int: 540 if v, exact := constant.Int64Val(x); exact { 541 // common case: x fits into an int64 - use compact encoding 542 p.tag(int64Tag) 543 p.int64(v) 544 return 545 } 546 // uncommon case: large x - use float encoding 547 // (powers of 2 will be encoded efficiently with exponent) 548 p.tag(floatTag) 549 p.float(constant.ToFloat(x)) 550 551 case constant.Float: 552 p.tag(floatTag) 553 p.float(x) 554 555 case constant.Complex: 556 p.tag(complexTag) 557 p.float(constant.Real(x)) 558 p.float(constant.Imag(x)) 559 560 case constant.String: 561 p.tag(stringTag) 562 p.string(constant.StringVal(x)) 563 564 case constant.Unknown: 565 // package contains type errors 566 p.tag(unknownTag) 567 568 default: 569 log.Fatalf("gcimporter: unexpected value %v (%T)", x, x) 570 } 571 } 572 573 func (p *exporter) float(x constant.Value) { 574 if x.Kind() != constant.Float { 575 log.Fatalf("gcimporter: unexpected constant %v, want float", x) 576 } 577 // extract sign (there is no -0) 578 sign := constant.Sign(x) 579 if sign == 0 { 580 // x == 0 581 p.int(0) 582 return 583 } 584 // x != 0 585 586 var f big.Float 587 if v, exact := constant.Float64Val(x); exact { 588 // float64 589 f.SetFloat64(v) 590 } else if num, denom := constant.Num(x), constant.Denom(x); num.Kind() == constant.Int { 591 // TODO(gri): add big.Rat accessor to constant.Value. 592 r := valueToRat(num) 593 f.SetRat(r.Quo(r, valueToRat(denom))) 594 } else { 595 // Value too large to represent as a fraction => inaccessible. 596 // TODO(gri): add big.Float accessor to constant.Value. 597 f.SetFloat64(math.MaxFloat64) // FIXME 598 } 599 600 // extract exponent such that 0.5 <= m < 1.0 601 var m big.Float 602 exp := f.MantExp(&m) 603 604 // extract mantissa as *big.Int 605 // - set exponent large enough so mant satisfies mant.IsInt() 606 // - get *big.Int from mant 607 m.SetMantExp(&m, int(m.MinPrec())) 608 mant, acc := m.Int(nil) 609 if acc != big.Exact { 610 log.Fatalf("gcimporter: internal error") 611 } 612 613 p.int(sign) 614 p.int(exp) 615 p.string(string(mant.Bytes())) 616 } 617 618 func valueToRat(x constant.Value) *big.Rat { 619 // Convert little-endian to big-endian. 620 // I can't believe this is necessary. 621 bytes := constant.Bytes(x) 622 for i := 0; i < len(bytes)/2; i++ { 623 bytes[i], bytes[len(bytes)-1-i] = bytes[len(bytes)-1-i], bytes[i] 624 } 625 return new(big.Rat).SetInt(new(big.Int).SetBytes(bytes)) 626 } 627 628 func (p *exporter) bool(b bool) bool { 629 if trace { 630 p.tracef("[") 631 defer p.tracef("= %v] ", b) 632 } 633 634 x := 0 635 if b { 636 x = 1 637 } 638 p.int(x) 639 return b 640 } 641 642 // ---------------------------------------------------------------------------- 643 // Low-level encoders 644 645 func (p *exporter) index(marker byte, index int) { 646 if index < 0 { 647 log.Fatalf("gcimporter: invalid index < 0") 648 } 649 if debugFormat { 650 p.marker('t') 651 } 652 if trace { 653 p.tracef("%c%d ", marker, index) 654 } 655 p.rawInt64(int64(index)) 656 } 657 658 func (p *exporter) tag(tag int) { 659 if tag >= 0 { 660 log.Fatalf("gcimporter: invalid tag >= 0") 661 } 662 if debugFormat { 663 p.marker('t') 664 } 665 if trace { 666 p.tracef("%s ", tagString[-tag]) 667 } 668 p.rawInt64(int64(tag)) 669 } 670 671 func (p *exporter) int(x int) { 672 p.int64(int64(x)) 673 } 674 675 func (p *exporter) int64(x int64) { 676 if debugFormat { 677 p.marker('i') 678 } 679 if trace { 680 p.tracef("%d ", x) 681 } 682 p.rawInt64(x) 683 } 684 685 func (p *exporter) string(s string) { 686 if debugFormat { 687 p.marker('s') 688 } 689 if trace { 690 p.tracef("%q ", s) 691 } 692 // if we saw the string before, write its index (>= 0) 693 // (the empty string is mapped to 0) 694 if i, ok := p.strIndex[s]; ok { 695 p.rawInt64(int64(i)) 696 return 697 } 698 // otherwise, remember string and write its negative length and bytes 699 p.strIndex[s] = len(p.strIndex) 700 p.rawInt64(-int64(len(s))) 701 for i := 0; i < len(s); i++ { 702 p.rawByte(s[i]) 703 } 704 } 705 706 // marker emits a marker byte and position information which makes 707 // it easy for a reader to detect if it is "out of sync". Used for 708 // debugFormat format only. 709 func (p *exporter) marker(m byte) { 710 p.rawByte(m) 711 // Enable this for help tracking down the location 712 // of an incorrect marker when running in debugFormat. 713 if false && trace { 714 p.tracef("#%d ", p.written) 715 } 716 p.rawInt64(int64(p.written)) 717 } 718 719 // rawInt64 should only be used by low-level encoders 720 func (p *exporter) rawInt64(x int64) { 721 var tmp [binary.MaxVarintLen64]byte 722 n := binary.PutVarint(tmp[:], x) 723 for i := 0; i < n; i++ { 724 p.rawByte(tmp[i]) 725 } 726 } 727 728 // rawByte is the bottleneck interface to write to p.out. 729 // rawByte escapes b as follows (any encoding does that 730 // hides '$'): 731 // 732 // '$' => '|' 'S' 733 // '|' => '|' '|' 734 // 735 // Necessary so other tools can find the end of the 736 // export data by searching for "$$". 737 // rawByte should only be used by low-level encoders. 738 func (p *exporter) rawByte(b byte) { 739 switch b { 740 case '$': 741 // write '$' as '|' 'S' 742 b = 'S' 743 fallthrough 744 case '|': 745 // write '|' as '|' '|' 746 p.out.WriteByte('|') 747 p.written++ 748 } 749 p.out.WriteByte(b) 750 p.written++ 751 } 752 753 // tracef is like fmt.Printf but it rewrites the format string 754 // to take care of indentation. 755 func (p *exporter) tracef(format string, args ...interface{}) { 756 if strings.IndexAny(format, "<>\n") >= 0 { 757 var buf bytes.Buffer 758 for i := 0; i < len(format); i++ { 759 // no need to deal with runes 760 ch := format[i] 761 switch ch { 762 case '>': 763 p.indent++ 764 continue 765 case '<': 766 p.indent-- 767 continue 768 } 769 buf.WriteByte(ch) 770 if ch == '\n' { 771 for j := p.indent; j > 0; j-- { 772 buf.WriteString(". ") 773 } 774 } 775 } 776 format = buf.String() 777 } 778 fmt.Printf(format, args...) 779 } 780 781 // Debugging support. 782 // (tagString is only used when tracing is enabled) 783 var tagString = [...]string{ 784 // Packages: 785 -packageTag: "package", 786 787 // Types: 788 -namedTag: "named type", 789 -arrayTag: "array", 790 -sliceTag: "slice", 791 -dddTag: "ddd", 792 -structTag: "struct", 793 -pointerTag: "pointer", 794 -signatureTag: "signature", 795 -interfaceTag: "interface", 796 -mapTag: "map", 797 -chanTag: "chan", 798 799 // Values: 800 -falseTag: "false", 801 -trueTag: "true", 802 -int64Tag: "int64", 803 -floatTag: "float", 804 -fractionTag: "fraction", 805 -complexTag: "complex", 806 -stringTag: "string", 807 -unknownTag: "unknown", 808 }