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