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