github.com/4ad/go@v0.0.0-20161219182952-69a12818b605/src/go/internal/gcimporter/bimport.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 package gcimporter 6 7 import ( 8 "encoding/binary" 9 "fmt" 10 "go/constant" 11 "go/token" 12 "go/types" 13 "sort" 14 "strings" 15 "unicode" 16 "unicode/utf8" 17 ) 18 19 type importer struct { 20 imports map[string]*types.Package 21 data []byte 22 path string 23 buf []byte // for reading strings 24 version string 25 26 // object lists 27 strList []string // in order of appearance 28 pkgList []*types.Package // in order of appearance 29 typList []types.Type // in order of appearance 30 trackAllTypes bool 31 32 // position encoding 33 posInfoFormat bool 34 prevFile string 35 prevLine int 36 37 // debugging support 38 debugFormat bool 39 read int // bytes read 40 } 41 42 // BImportData imports a package from the serialized package data 43 // and returns the number of bytes consumed and a reference to the package. 44 // If data is obviously malformed, an error is returned but in 45 // general it is not recommended to call BImportData on untrusted data. 46 func BImportData(imports map[string]*types.Package, data []byte, path string) (int, *types.Package, error) { 47 p := importer{ 48 imports: imports, 49 data: data, 50 path: path, 51 strList: []string{""}, // empty string is mapped to 0 52 } 53 54 // read low-level encoding format 55 switch format := p.rawByte(); format { 56 case 'c': 57 // compact format - nothing to do 58 case 'd': 59 p.debugFormat = true 60 default: 61 return p.read, nil, fmt.Errorf("invalid encoding format in export data: got %q; want 'c' or 'd'", format) 62 } 63 64 p.trackAllTypes = p.rawByte() == 'a' 65 66 p.posInfoFormat = p.int() != 0 67 68 // --- generic export data --- 69 70 p.version = p.string() 71 if p.version != "v0" && p.version != "v1" { 72 return p.read, nil, fmt.Errorf("unknown export data version: %s", p.version) 73 } 74 75 // populate typList with predeclared "known" types 76 p.typList = append(p.typList, predeclared...) 77 78 // read package data 79 pkg := p.pkg() 80 81 // read objects of phase 1 only (see cmd/compiler/internal/gc/bexport.go) 82 objcount := 0 83 for { 84 tag := p.tagOrIndex() 85 if tag == endTag { 86 break 87 } 88 p.obj(tag) 89 objcount++ 90 } 91 92 // self-verification 93 if count := p.int(); count != objcount { 94 panic(fmt.Sprintf("got %d objects; want %d", objcount, count)) 95 } 96 97 // ignore compiler-specific import data 98 99 // complete interfaces 100 for _, typ := range p.typList { 101 // If we only record named types (!p.trackAllTypes), 102 // we must check the underlying types here. If we 103 // track all types, the Underlying() method call is 104 // not needed. 105 // TODO(gri) Remove if p.trackAllTypes is gone. 106 if it, ok := typ.Underlying().(*types.Interface); ok { 107 it.Complete() 108 } 109 } 110 111 // record all referenced packages as imports 112 list := append(([]*types.Package)(nil), p.pkgList[1:]...) 113 sort.Sort(byPath(list)) 114 pkg.SetImports(list) 115 116 // package was imported completely and without errors 117 pkg.MarkComplete() 118 119 return p.read, pkg, nil 120 } 121 122 func (p *importer) pkg() *types.Package { 123 // if the package was seen before, i is its index (>= 0) 124 i := p.tagOrIndex() 125 if i >= 0 { 126 return p.pkgList[i] 127 } 128 129 // otherwise, i is the package tag (< 0) 130 if i != packageTag { 131 panic(fmt.Sprintf("unexpected package tag %d", i)) 132 } 133 134 // read package data 135 name := p.string() 136 path := p.string() 137 138 // we should never see an empty package name 139 if name == "" { 140 panic("empty package name in import") 141 } 142 143 // an empty path denotes the package we are currently importing; 144 // it must be the first package we see 145 if (path == "") != (len(p.pkgList) == 0) { 146 panic(fmt.Sprintf("package path %q for pkg index %d", path, len(p.pkgList))) 147 } 148 149 // if the package was imported before, use that one; otherwise create a new one 150 if path == "" { 151 path = p.path 152 } 153 pkg := p.imports[path] 154 if pkg == nil { 155 pkg = types.NewPackage(path, name) 156 p.imports[path] = pkg 157 } else if pkg.Name() != name { 158 panic(fmt.Sprintf("conflicting names %s and %s for package %q", pkg.Name(), name, path)) 159 } 160 p.pkgList = append(p.pkgList, pkg) 161 162 return pkg 163 } 164 165 func (p *importer) declare(obj types.Object) { 166 pkg := obj.Pkg() 167 if alt := pkg.Scope().Insert(obj); alt != nil { 168 // This could only trigger if we import a (non-type) object a second time. 169 // This should never happen because 1) we only import a package once; and 170 // b) we ignore compiler-specific export data which may contain functions 171 // whose inlined function bodies refer to other functions that were already 172 // imported. 173 // (See also the comment in cmd/compile/internal/gc/bimport.go importer.obj, 174 // switch case importing functions). 175 panic(fmt.Sprintf("inconsistent import:\n\t%v\npreviously imported as:\n\t%v\n", alt, obj)) 176 } 177 } 178 179 func (p *importer) obj(tag int) { 180 switch tag { 181 case constTag: 182 p.pos() 183 pkg, name := p.qualifiedName() 184 typ := p.typ(nil) 185 val := p.value() 186 p.declare(types.NewConst(token.NoPos, pkg, name, typ, val)) 187 188 case typeTag: 189 _ = p.typ(nil) 190 191 case varTag: 192 p.pos() 193 pkg, name := p.qualifiedName() 194 typ := p.typ(nil) 195 p.declare(types.NewVar(token.NoPos, pkg, name, typ)) 196 197 case funcTag: 198 p.pos() 199 pkg, name := p.qualifiedName() 200 params, isddd := p.paramList() 201 result, _ := p.paramList() 202 sig := types.NewSignature(nil, params, result, isddd) 203 p.declare(types.NewFunc(token.NoPos, pkg, name, sig)) 204 205 default: 206 panic(fmt.Sprintf("unexpected object tag %d", tag)) 207 } 208 } 209 210 func (p *importer) pos() { 211 if !p.posInfoFormat { 212 return 213 } 214 215 file := p.prevFile 216 line := p.prevLine 217 if delta := p.int(); delta != 0 { 218 // line changed 219 line += delta 220 } else if n := p.int(); n >= 0 { 221 // file changed 222 file = p.prevFile[:n] + p.string() 223 p.prevFile = file 224 line = p.int() 225 } 226 p.prevLine = line 227 228 // TODO(gri) register new position 229 } 230 231 func (p *importer) qualifiedName() (pkg *types.Package, name string) { 232 name = p.string() 233 pkg = p.pkg() 234 return 235 } 236 237 func (p *importer) record(t types.Type) { 238 p.typList = append(p.typList, t) 239 } 240 241 // A dddSlice is a types.Type representing ...T parameters. 242 // It only appears for parameter types and does not escape 243 // the importer. 244 type dddSlice struct { 245 elem types.Type 246 } 247 248 func (t *dddSlice) Underlying() types.Type { return t } 249 func (t *dddSlice) String() string { return "..." + t.elem.String() } 250 251 // parent is the package which declared the type; parent == nil means 252 // the package currently imported. The parent package is needed for 253 // exported struct fields and interface methods which don't contain 254 // explicit package information in the export data. 255 func (p *importer) typ(parent *types.Package) types.Type { 256 // if the type was seen before, i is its index (>= 0) 257 i := p.tagOrIndex() 258 if i >= 0 { 259 return p.typList[i] 260 } 261 262 // otherwise, i is the type tag (< 0) 263 switch i { 264 case namedTag: 265 // read type object 266 p.pos() 267 parent, name := p.qualifiedName() 268 scope := parent.Scope() 269 obj := scope.Lookup(name) 270 271 // if the object doesn't exist yet, create and insert it 272 if obj == nil { 273 obj = types.NewTypeName(token.NoPos, parent, name, nil) 274 scope.Insert(obj) 275 } 276 277 if _, ok := obj.(*types.TypeName); !ok { 278 panic(fmt.Sprintf("pkg = %s, name = %s => %s", parent, name, obj)) 279 } 280 281 // associate new named type with obj if it doesn't exist yet 282 t0 := types.NewNamed(obj.(*types.TypeName), nil, nil) 283 284 // but record the existing type, if any 285 t := obj.Type().(*types.Named) 286 p.record(t) 287 288 // read underlying type 289 t0.SetUnderlying(p.typ(parent)) 290 291 // interfaces don't have associated methods 292 if types.IsInterface(t0) { 293 return t 294 } 295 296 // read associated methods 297 for i := p.int(); i > 0; i-- { 298 // TODO(gri) replace this with something closer to fieldName 299 p.pos() 300 name := p.string() 301 if !exported(name) { 302 p.pkg() 303 } 304 305 recv, _ := p.paramList() // TODO(gri) do we need a full param list for the receiver? 306 params, isddd := p.paramList() 307 result, _ := p.paramList() 308 309 if p.version == "v1" { 310 p.int() // nointerface flag - discarded 311 } 312 313 sig := types.NewSignature(recv.At(0), params, result, isddd) 314 t0.AddMethod(types.NewFunc(token.NoPos, parent, name, sig)) 315 } 316 317 return t 318 319 case arrayTag: 320 t := new(types.Array) 321 if p.trackAllTypes { 322 p.record(t) 323 } 324 325 n := p.int64() 326 *t = *types.NewArray(p.typ(parent), n) 327 return t 328 329 case sliceTag: 330 t := new(types.Slice) 331 if p.trackAllTypes { 332 p.record(t) 333 } 334 335 *t = *types.NewSlice(p.typ(parent)) 336 return t 337 338 case dddTag: 339 t := new(dddSlice) 340 if p.trackAllTypes { 341 p.record(t) 342 } 343 344 t.elem = p.typ(parent) 345 return t 346 347 case structTag: 348 t := new(types.Struct) 349 if p.trackAllTypes { 350 p.record(t) 351 } 352 353 *t = *types.NewStruct(p.fieldList(parent)) 354 return t 355 356 case pointerTag: 357 t := new(types.Pointer) 358 if p.trackAllTypes { 359 p.record(t) 360 } 361 362 *t = *types.NewPointer(p.typ(parent)) 363 return t 364 365 case signatureTag: 366 t := new(types.Signature) 367 if p.trackAllTypes { 368 p.record(t) 369 } 370 371 params, isddd := p.paramList() 372 result, _ := p.paramList() 373 *t = *types.NewSignature(nil, params, result, isddd) 374 return t 375 376 case interfaceTag: 377 // Create a dummy entry in the type list. This is safe because we 378 // cannot expect the interface type to appear in a cycle, as any 379 // such cycle must contain a named type which would have been 380 // first defined earlier. 381 n := len(p.typList) 382 if p.trackAllTypes { 383 p.record(nil) 384 } 385 386 // no embedded interfaces with gc compiler 387 if p.int() != 0 { 388 panic("unexpected embedded interface") 389 } 390 391 t := types.NewInterface(p.methodList(parent), nil) 392 if p.trackAllTypes { 393 p.typList[n] = t 394 } 395 return t 396 397 case mapTag: 398 t := new(types.Map) 399 if p.trackAllTypes { 400 p.record(t) 401 } 402 403 key := p.typ(parent) 404 val := p.typ(parent) 405 *t = *types.NewMap(key, val) 406 return t 407 408 case chanTag: 409 t := new(types.Chan) 410 if p.trackAllTypes { 411 p.record(t) 412 } 413 414 var dir types.ChanDir 415 // tag values must match the constants in cmd/compile/internal/gc/go.go 416 switch d := p.int(); d { 417 case 1 /* Crecv */ : 418 dir = types.RecvOnly 419 case 2 /* Csend */ : 420 dir = types.SendOnly 421 case 3 /* Cboth */ : 422 dir = types.SendRecv 423 default: 424 panic(fmt.Sprintf("unexpected channel dir %d", d)) 425 } 426 val := p.typ(parent) 427 *t = *types.NewChan(dir, val) 428 return t 429 430 default: 431 panic(fmt.Sprintf("unexpected type tag %d", i)) 432 } 433 } 434 435 func (p *importer) fieldList(parent *types.Package) (fields []*types.Var, tags []string) { 436 if n := p.int(); n > 0 { 437 fields = make([]*types.Var, n) 438 tags = make([]string, n) 439 for i := range fields { 440 fields[i] = p.field(parent) 441 tags[i] = p.string() 442 } 443 } 444 return 445 } 446 447 func (p *importer) field(parent *types.Package) *types.Var { 448 p.pos() 449 pkg, name := p.fieldName(parent) 450 typ := p.typ(parent) 451 452 anonymous := false 453 if name == "" { 454 // anonymous field - typ must be T or *T and T must be a type name 455 switch typ := deref(typ).(type) { 456 case *types.Basic: // basic types are named types 457 pkg = nil // // objects defined in Universe scope have no package 458 name = typ.Name() 459 case *types.Named: 460 name = typ.Obj().Name() 461 default: 462 panic("anonymous field expected") 463 } 464 anonymous = true 465 } 466 467 return types.NewField(token.NoPos, pkg, name, typ, anonymous) 468 } 469 470 func (p *importer) methodList(parent *types.Package) (methods []*types.Func) { 471 if n := p.int(); n > 0 { 472 methods = make([]*types.Func, n) 473 for i := range methods { 474 methods[i] = p.method(parent) 475 } 476 } 477 return 478 } 479 480 func (p *importer) method(parent *types.Package) *types.Func { 481 p.pos() 482 pkg, name := p.fieldName(parent) 483 params, isddd := p.paramList() 484 result, _ := p.paramList() 485 sig := types.NewSignature(nil, params, result, isddd) 486 return types.NewFunc(token.NoPos, pkg, name, sig) 487 } 488 489 func (p *importer) fieldName(parent *types.Package) (*types.Package, string) { 490 pkg := parent 491 if pkg == nil { 492 // use the imported package instead 493 pkg = p.pkgList[0] 494 } 495 name := p.string() 496 if name == "" { 497 return pkg, "" // anonymous 498 } 499 if name == "?" || name != "_" && !exported(name) { 500 // explicitly qualified field 501 if name == "?" { 502 name = "" // anonymous 503 } 504 pkg = p.pkg() 505 } 506 return pkg, name 507 } 508 509 func (p *importer) paramList() (*types.Tuple, bool) { 510 n := p.int() 511 if n == 0 { 512 return nil, false 513 } 514 // negative length indicates unnamed parameters 515 named := true 516 if n < 0 { 517 n = -n 518 named = false 519 } 520 // n > 0 521 params := make([]*types.Var, n) 522 isddd := false 523 for i := range params { 524 params[i], isddd = p.param(named) 525 } 526 return types.NewTuple(params...), isddd 527 } 528 529 func (p *importer) param(named bool) (*types.Var, bool) { 530 t := p.typ(nil) 531 td, isddd := t.(*dddSlice) 532 if isddd { 533 t = types.NewSlice(td.elem) 534 } 535 536 var pkg *types.Package 537 var name string 538 if named { 539 name = p.string() 540 if name == "" { 541 panic("expected named parameter") 542 } 543 if name != "_" { 544 pkg = p.pkg() 545 } 546 if i := strings.Index(name, "ยท"); i > 0 { 547 name = name[:i] // cut off gc-specific parameter numbering 548 } 549 } 550 551 // read and discard compiler-specific info 552 p.string() 553 554 return types.NewVar(token.NoPos, pkg, name, t), isddd 555 } 556 557 func exported(name string) bool { 558 ch, _ := utf8.DecodeRuneInString(name) 559 return unicode.IsUpper(ch) 560 } 561 562 func (p *importer) value() constant.Value { 563 switch tag := p.tagOrIndex(); tag { 564 case falseTag: 565 return constant.MakeBool(false) 566 case trueTag: 567 return constant.MakeBool(true) 568 case int64Tag: 569 return constant.MakeInt64(p.int64()) 570 case floatTag: 571 return p.float() 572 case complexTag: 573 re := p.float() 574 im := p.float() 575 return constant.BinaryOp(re, token.ADD, constant.MakeImag(im)) 576 case stringTag: 577 return constant.MakeString(p.string()) 578 default: 579 panic(fmt.Sprintf("unexpected value tag %d", tag)) 580 } 581 } 582 583 func (p *importer) float() constant.Value { 584 sign := p.int() 585 if sign == 0 { 586 return constant.MakeInt64(0) 587 } 588 589 exp := p.int() 590 mant := []byte(p.string()) // big endian 591 592 // remove leading 0's if any 593 for len(mant) > 0 && mant[0] == 0 { 594 mant = mant[1:] 595 } 596 597 // convert to little endian 598 // TODO(gri) go/constant should have a more direct conversion function 599 // (e.g., once it supports a big.Float based implementation) 600 for i, j := 0, len(mant)-1; i < j; i, j = i+1, j-1 { 601 mant[i], mant[j] = mant[j], mant[i] 602 } 603 604 // adjust exponent (constant.MakeFromBytes creates an integer value, 605 // but mant represents the mantissa bits such that 0.5 <= mant < 1.0) 606 exp -= len(mant) << 3 607 if len(mant) > 0 { 608 for msd := mant[len(mant)-1]; msd&0x80 == 0; msd <<= 1 { 609 exp++ 610 } 611 } 612 613 x := constant.MakeFromBytes(mant) 614 switch { 615 case exp < 0: 616 d := constant.Shift(constant.MakeInt64(1), token.SHL, uint(-exp)) 617 x = constant.BinaryOp(x, token.QUO, d) 618 case exp > 0: 619 x = constant.Shift(x, token.SHL, uint(exp)) 620 } 621 622 if sign < 0 { 623 x = constant.UnaryOp(token.SUB, x, 0) 624 } 625 return x 626 } 627 628 // ---------------------------------------------------------------------------- 629 // Low-level decoders 630 631 func (p *importer) tagOrIndex() int { 632 if p.debugFormat { 633 p.marker('t') 634 } 635 636 return int(p.rawInt64()) 637 } 638 639 func (p *importer) int() int { 640 x := p.int64() 641 if int64(int(x)) != x { 642 panic("exported integer too large") 643 } 644 return int(x) 645 } 646 647 func (p *importer) int64() int64 { 648 if p.debugFormat { 649 p.marker('i') 650 } 651 652 return p.rawInt64() 653 } 654 655 func (p *importer) string() string { 656 if p.debugFormat { 657 p.marker('s') 658 } 659 // if the string was seen before, i is its index (>= 0) 660 // (the empty string is at index 0) 661 i := p.rawInt64() 662 if i >= 0 { 663 return p.strList[i] 664 } 665 // otherwise, i is the negative string length (< 0) 666 if n := int(-i); n <= cap(p.buf) { 667 p.buf = p.buf[:n] 668 } else { 669 p.buf = make([]byte, n) 670 } 671 for i := range p.buf { 672 p.buf[i] = p.rawByte() 673 } 674 s := string(p.buf) 675 p.strList = append(p.strList, s) 676 return s 677 } 678 679 func (p *importer) marker(want byte) { 680 if got := p.rawByte(); got != want { 681 panic(fmt.Sprintf("incorrect marker: got %c; want %c (pos = %d)", got, want, p.read)) 682 } 683 684 pos := p.read 685 if n := int(p.rawInt64()); n != pos { 686 panic(fmt.Sprintf("incorrect position: got %d; want %d", n, pos)) 687 } 688 } 689 690 // rawInt64 should only be used by low-level decoders 691 func (p *importer) rawInt64() int64 { 692 i, err := binary.ReadVarint(p) 693 if err != nil { 694 panic(fmt.Sprintf("read error: %v", err)) 695 } 696 return i 697 } 698 699 // needed for binary.ReadVarint in rawInt64 700 func (p *importer) ReadByte() (byte, error) { 701 return p.rawByte(), nil 702 } 703 704 // byte is the bottleneck interface for reading p.data. 705 // It unescapes '|' 'S' to '$' and '|' '|' to '|'. 706 // rawByte should only be used by low-level decoders. 707 func (p *importer) rawByte() byte { 708 b := p.data[0] 709 r := 1 710 if b == '|' { 711 b = p.data[1] 712 r = 2 713 switch b { 714 case 'S': 715 b = '$' 716 case '|': 717 // nothing to do 718 default: 719 panic("unexpected escape sequence in export data") 720 } 721 } 722 p.data = p.data[r:] 723 p.read += r 724 return b 725 726 } 727 728 // ---------------------------------------------------------------------------- 729 // Export format 730 731 // Tags. Must be < 0. 732 const ( 733 // Objects 734 packageTag = -(iota + 1) 735 constTag 736 typeTag 737 varTag 738 funcTag 739 endTag 740 741 // Types 742 namedTag 743 arrayTag 744 sliceTag 745 dddTag 746 structTag 747 pointerTag 748 signatureTag 749 interfaceTag 750 mapTag 751 chanTag 752 753 // Values 754 falseTag 755 trueTag 756 int64Tag 757 floatTag 758 fractionTag // not used by gc 759 complexTag 760 stringTag 761 unknownTag // not used by gc (only appears in packages with errors) 762 ) 763 764 var predeclared = []types.Type{ 765 // basic types 766 types.Typ[types.Bool], 767 types.Typ[types.Int], 768 types.Typ[types.Int8], 769 types.Typ[types.Int16], 770 types.Typ[types.Int32], 771 types.Typ[types.Int64], 772 types.Typ[types.Uint], 773 types.Typ[types.Uint8], 774 types.Typ[types.Uint16], 775 types.Typ[types.Uint32], 776 types.Typ[types.Uint64], 777 types.Typ[types.Uintptr], 778 types.Typ[types.Float32], 779 types.Typ[types.Float64], 780 types.Typ[types.Complex64], 781 types.Typ[types.Complex128], 782 types.Typ[types.String], 783 784 // aliases 785 types.Universe.Lookup("byte").Type(), 786 types.Universe.Lookup("rune").Type(), 787 788 // error 789 types.Universe.Lookup("error").Type(), 790 791 // untyped types 792 types.Typ[types.UntypedBool], 793 types.Typ[types.UntypedInt], 794 types.Typ[types.UntypedRune], 795 types.Typ[types.UntypedFloat], 796 types.Typ[types.UntypedComplex], 797 types.Typ[types.UntypedString], 798 types.Typ[types.UntypedNil], 799 800 // package unsafe 801 types.Typ[types.UnsafePointer], 802 803 // invalid type 804 types.Typ[types.Invalid], // only appears in packages with errors 805 806 // used internally by gc; never used by this package or in .a files 807 anyType{}, 808 } 809 810 type anyType struct{} 811 812 func (t anyType) Underlying() types.Type { return t } 813 func (t anyType) String() string { return "any" }