1// Copyright 2018 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// Indexed package import. 6// See cmd/compile/internal/gc/iexport.go for the export data format. 7 8// This file is a copy of $GOROOT/src/go/internal/gcimporter/iimport.go. 9 10package gcimporter 11 12import ( 13 "bytes" 14 "encoding/binary" 15 "fmt" 16 "go/constant" 17 "go/token" 18 "go/types" 19 "io" 20 "sort" 21) 22 23type intReader struct { 24 *bytes.Reader 25 path string 26} 27 28func (r *intReader) int64() int64 { 29 i, err := binary.ReadVarint(r.Reader) 30 if err != nil { 31 errorf("import %q: read varint error: %v", r.path, err) 32 } 33 return i 34} 35 36func (r *intReader) uint64() uint64 { 37 i, err := binary.ReadUvarint(r.Reader) 38 if err != nil { 39 errorf("import %q: read varint error: %v", r.path, err) 40 } 41 return i 42} 43 44const predeclReserved = 32 45 46type itag uint64 47 48const ( 49 // Types 50 definedType itag = iota 51 pointerType 52 sliceType 53 arrayType 54 chanType 55 mapType 56 signatureType 57 structType 58 interfaceType 59) 60 61// IImportData imports a package from the serialized package data 62// and returns 0 and a reference to the package. 63// If the export data version is not recognized or the format is otherwise 64// compromised, an error is returned. 65func IImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (int, *types.Package, error) { 66 pkgs, err := iimportCommon(fset, imports, data, false, path) 67 if err != nil { 68 return 0, nil, err 69 } 70 return 0, pkgs[0], nil 71} 72 73// IImportBundle imports a set of packages from the serialized package bundle. 74func IImportBundle(fset *token.FileSet, imports map[string]*types.Package, data []byte) ([]*types.Package, error) { 75 return iimportCommon(fset, imports, data, true, "") 76} 77 78func iimportCommon(fset *token.FileSet, imports map[string]*types.Package, data []byte, bundle bool, path string) (pkgs []*types.Package, err error) { 79 const currentVersion = 1 80 version := int64(-1) 81 defer func() { 82 if e := recover(); e != nil { 83 if version > currentVersion { 84 err = fmt.Errorf("cannot import %q (%v), export data is newer version - update tool", path, e) 85 } else { 86 err = fmt.Errorf("cannot import %q (%v), possibly version skew - reinstall package", path, e) 87 } 88 } 89 }() 90 91 r := &intReader{bytes.NewReader(data), path} 92 93 if bundle { 94 bundleVersion := r.uint64() 95 switch bundleVersion { 96 case bundleVersion: 97 default: 98 errorf("unknown bundle format version %d", bundleVersion) 99 } 100 } 101 102 version = int64(r.uint64()) 103 switch version { 104 case currentVersion, 0: 105 default: 106 errorf("unknown iexport format version %d", version) 107 } 108 109 sLen := int64(r.uint64()) 110 dLen := int64(r.uint64()) 111 112 whence, _ := r.Seek(0, io.SeekCurrent) 113 stringData := data[whence : whence+sLen] 114 declData := data[whence+sLen : whence+sLen+dLen] 115 r.Seek(sLen+dLen, io.SeekCurrent) 116 117 p := iimporter{ 118 ipath: path, 119 version: int(version), 120 121 stringData: stringData, 122 stringCache: make(map[uint64]string), 123 pkgCache: make(map[uint64]*types.Package), 124 125 declData: declData, 126 pkgIndex: make(map[*types.Package]map[string]uint64), 127 typCache: make(map[uint64]types.Type), 128 129 fake: fakeFileSet{ 130 fset: fset, 131 files: make(map[string]*token.File), 132 }, 133 } 134 135 for i, pt := range predeclared() { 136 p.typCache[uint64(i)] = pt 137 } 138 139 pkgList := make([]*types.Package, r.uint64()) 140 for i := range pkgList { 141 pkgPathOff := r.uint64() 142 pkgPath := p.stringAt(pkgPathOff) 143 pkgName := p.stringAt(r.uint64()) 144 _ = r.uint64() // package height; unused by go/types 145 146 if pkgPath == "" { 147 pkgPath = path 148 } 149 pkg := imports[pkgPath] 150 if pkg == nil { 151 pkg = types.NewPackage(pkgPath, pkgName) 152 imports[pkgPath] = pkg 153 } else if pkg.Name() != pkgName { 154 errorf("conflicting names %s and %s for package %q", pkg.Name(), pkgName, path) 155 } 156 157 p.pkgCache[pkgPathOff] = pkg 158 159 nameIndex := make(map[string]uint64) 160 for nSyms := r.uint64(); nSyms > 0; nSyms-- { 161 name := p.stringAt(r.uint64()) 162 nameIndex[name] = r.uint64() 163 } 164 165 p.pkgIndex[pkg] = nameIndex 166 pkgList[i] = pkg 167 } 168 169 if bundle { 170 pkgs = make([]*types.Package, r.uint64()) 171 for i := range pkgs { 172 pkg := p.pkgAt(r.uint64()) 173 imps := make([]*types.Package, r.uint64()) 174 for j := range imps { 175 imps[j] = p.pkgAt(r.uint64()) 176 } 177 pkg.SetImports(imps) 178 pkgs[i] = pkg 179 } 180 } else { 181 if len(pkgList) == 0 { 182 errorf("no packages found for %s", path) 183 panic("unreachable") 184 } 185 pkgs = pkgList[:1] 186 187 // record all referenced packages as imports 188 list := append(([]*types.Package)(nil), pkgList[1:]...) 189 sort.Sort(byPath(list)) 190 pkgs[0].SetImports(list) 191 } 192 193 for _, pkg := range pkgs { 194 if pkg.Complete() { 195 continue 196 } 197 198 names := make([]string, 0, len(p.pkgIndex[pkg])) 199 for name := range p.pkgIndex[pkg] { 200 names = append(names, name) 201 } 202 sort.Strings(names) 203 for _, name := range names { 204 p.doDecl(pkg, name) 205 } 206 207 // package was imported completely and without errors 208 pkg.MarkComplete() 209 } 210 211 for _, typ := range p.interfaceList { 212 typ.Complete() 213 } 214 215 return pkgs, nil 216} 217 218type iimporter struct { 219 ipath string 220 version int 221 222 stringData []byte 223 stringCache map[uint64]string 224 pkgCache map[uint64]*types.Package 225 226 declData []byte 227 pkgIndex map[*types.Package]map[string]uint64 228 typCache map[uint64]types.Type 229 230 fake fakeFileSet 231 interfaceList []*types.Interface 232} 233 234func (p *iimporter) doDecl(pkg *types.Package, name string) { 235 // See if we've already imported this declaration. 236 if obj := pkg.Scope().Lookup(name); obj != nil { 237 return 238 } 239 240 off, ok := p.pkgIndex[pkg][name] 241 if !ok { 242 errorf("%v.%v not in index", pkg, name) 243 } 244 245 r := &importReader{p: p, currPkg: pkg} 246 r.declReader.Reset(p.declData[off:]) 247 248 r.obj(name) 249} 250 251func (p *iimporter) stringAt(off uint64) string { 252 if s, ok := p.stringCache[off]; ok { 253 return s 254 } 255 256 slen, n := binary.Uvarint(p.stringData[off:]) 257 if n <= 0 { 258 errorf("varint failed") 259 } 260 spos := off + uint64(n) 261 s := string(p.stringData[spos : spos+slen]) 262 p.stringCache[off] = s 263 return s 264} 265 266func (p *iimporter) pkgAt(off uint64) *types.Package { 267 if pkg, ok := p.pkgCache[off]; ok { 268 return pkg 269 } 270 path := p.stringAt(off) 271 errorf("missing package %q in %q", path, p.ipath) 272 return nil 273} 274 275func (p *iimporter) typAt(off uint64, base *types.Named) types.Type { 276 if t, ok := p.typCache[off]; ok && (base == nil || !isInterface(t)) { 277 return t 278 } 279 280 if off < predeclReserved { 281 errorf("predeclared type missing from cache: %v", off) 282 } 283 284 r := &importReader{p: p} 285 r.declReader.Reset(p.declData[off-predeclReserved:]) 286 t := r.doType(base) 287 288 if base == nil || !isInterface(t) { 289 p.typCache[off] = t 290 } 291 return t 292} 293 294type importReader struct { 295 p *iimporter 296 declReader bytes.Reader 297 currPkg *types.Package 298 prevFile string 299 prevLine int64 300 prevColumn int64 301} 302 303func (r *importReader) obj(name string) { 304 tag := r.byte() 305 pos := r.pos() 306 307 switch tag { 308 case 'A': 309 typ := r.typ() 310 311 r.declare(types.NewTypeName(pos, r.currPkg, name, typ)) 312 313 case 'C': 314 typ, val := r.value() 315 316 r.declare(types.NewConst(pos, r.currPkg, name, typ, val)) 317 318 case 'F': 319 sig := r.signature(nil) 320 321 r.declare(types.NewFunc(pos, r.currPkg, name, sig)) 322 323 case 'T': 324 // Types can be recursive. We need to setup a stub 325 // declaration before recursing. 326 obj := types.NewTypeName(pos, r.currPkg, name, nil) 327 named := types.NewNamed(obj, nil, nil) 328 r.declare(obj) 329 330 underlying := r.p.typAt(r.uint64(), named).Underlying() 331 named.SetUnderlying(underlying) 332 333 if !isInterface(underlying) { 334 for n := r.uint64(); n > 0; n-- { 335 mpos := r.pos() 336 mname := r.ident() 337 recv := r.param() 338 msig := r.signature(recv) 339 340 named.AddMethod(types.NewFunc(mpos, r.currPkg, mname, msig)) 341 } 342 } 343 344 case 'V': 345 typ := r.typ() 346 347 r.declare(types.NewVar(pos, r.currPkg, name, typ)) 348 349 default: 350 errorf("unexpected tag: %v", tag) 351 } 352} 353 354func (r *importReader) declare(obj types.Object) { 355 obj.Pkg().Scope().Insert(obj) 356} 357 358func (r *importReader) value() (typ types.Type, val constant.Value) { 359 typ = r.typ() 360 361 switch b := typ.Underlying().(*types.Basic); b.Info() & types.IsConstType { 362 case types.IsBoolean: 363 val = constant.MakeBool(r.bool()) 364 365 case types.IsString: 366 val = constant.MakeString(r.string()) 367 368 case types.IsInteger: 369 val = r.mpint(b) 370 371 case types.IsFloat: 372 val = r.mpfloat(b) 373 374 case types.IsComplex: 375 re := r.mpfloat(b) 376 im := r.mpfloat(b) 377 val = constant.BinaryOp(re, token.ADD, constant.MakeImag(im)) 378 379 default: 380 if b.Kind() == types.Invalid { 381 val = constant.MakeUnknown() 382 return 383 } 384 errorf("unexpected type %v", typ) // panics 385 panic("unreachable") 386 } 387 388 return 389} 390 391func intSize(b *types.Basic) (signed bool, maxBytes uint) { 392 if (b.Info() & types.IsUntyped) != 0 { 393 return true, 64 394 } 395 396 switch b.Kind() { 397 case types.Float32, types.Complex64: 398 return true, 3 399 case types.Float64, types.Complex128: 400 return true, 7 401 } 402 403 signed = (b.Info() & types.IsUnsigned) == 0 404 switch b.Kind() { 405 case types.Int8, types.Uint8: 406 maxBytes = 1 407 case types.Int16, types.Uint16: 408 maxBytes = 2 409 case types.Int32, types.Uint32: 410 maxBytes = 4 411 default: 412 maxBytes = 8 413 } 414 415 return 416} 417 418func (r *importReader) mpint(b *types.Basic) constant.Value { 419 signed, maxBytes := intSize(b) 420 421 maxSmall := 256 - maxBytes 422 if signed { 423 maxSmall = 256 - 2*maxBytes 424 } 425 if maxBytes == 1 { 426 maxSmall = 256 427 } 428 429 n, _ := r.declReader.ReadByte() 430 if uint(n) < maxSmall { 431 v := int64(n) 432 if signed { 433 v >>= 1 434 if n&1 != 0 { 435 v = ^v 436 } 437 } 438 return constant.MakeInt64(v) 439 } 440 441 v := -n 442 if signed { 443 v = -(n &^ 1) >> 1 444 } 445 if v < 1 || uint(v) > maxBytes { 446 errorf("weird decoding: %v, %v => %v", n, signed, v) 447 } 448 449 buf := make([]byte, v) 450 io.ReadFull(&r.declReader, buf) 451 452 // convert to little endian 453 // TODO(gri) go/constant should have a more direct conversion function 454 // (e.g., once it supports a big.Float based implementation) 455 for i, j := 0, len(buf)-1; i < j; i, j = i+1, j-1 { 456 buf[i], buf[j] = buf[j], buf[i] 457 } 458 459 x := constant.MakeFromBytes(buf) 460 if signed && n&1 != 0 { 461 x = constant.UnaryOp(token.SUB, x, 0) 462 } 463 return x 464} 465 466func (r *importReader) mpfloat(b *types.Basic) constant.Value { 467 x := r.mpint(b) 468 if constant.Sign(x) == 0 { 469 return x 470 } 471 472 exp := r.int64() 473 switch { 474 case exp > 0: 475 x = constant.Shift(x, token.SHL, uint(exp)) 476 // Ensure that the imported Kind is Float, else this constant may run into 477 // bitsize limits on overlarge integers. Eventually we can instead adopt 478 // the approach of CL 288632, but that CL relies on go/constant APIs that 479 // were introduced in go1.13. 480 // 481 // TODO(rFindley): sync the logic here with tip Go once we no longer 482 // support go1.12. 483 x = constant.ToFloat(x) 484 case exp < 0: 485 d := constant.Shift(constant.MakeInt64(1), token.SHL, uint(-exp)) 486 x = constant.BinaryOp(x, token.QUO, d) 487 } 488 return x 489} 490 491func (r *importReader) ident() string { 492 return r.string() 493} 494 495func (r *importReader) qualifiedIdent() (*types.Package, string) { 496 name := r.string() 497 pkg := r.pkg() 498 return pkg, name 499} 500 501func (r *importReader) pos() token.Pos { 502 if r.p.version >= 1 { 503 r.posv1() 504 } else { 505 r.posv0() 506 } 507 508 if r.prevFile == "" && r.prevLine == 0 && r.prevColumn == 0 { 509 return token.NoPos 510 } 511 return r.p.fake.pos(r.prevFile, int(r.prevLine), int(r.prevColumn)) 512} 513 514func (r *importReader) posv0() { 515 delta := r.int64() 516 if delta != deltaNewFile { 517 r.prevLine += delta 518 } else if l := r.int64(); l == -1 { 519 r.prevLine += deltaNewFile 520 } else { 521 r.prevFile = r.string() 522 r.prevLine = l 523 } 524} 525 526func (r *importReader) posv1() { 527 delta := r.int64() 528 r.prevColumn += delta >> 1 529 if delta&1 != 0 { 530 delta = r.int64() 531 r.prevLine += delta >> 1 532 if delta&1 != 0 { 533 r.prevFile = r.string() 534 } 535 } 536} 537 538func (r *importReader) typ() types.Type { 539 return r.p.typAt(r.uint64(), nil) 540} 541 542func isInterface(t types.Type) bool { 543 _, ok := t.(*types.Interface) 544 return ok 545} 546 547func (r *importReader) pkg() *types.Package { return r.p.pkgAt(r.uint64()) } 548func (r *importReader) string() string { return r.p.stringAt(r.uint64()) } 549 550func (r *importReader) doType(base *types.Named) types.Type { 551 switch k := r.kind(); k { 552 default: 553 errorf("unexpected kind tag in %q: %v", r.p.ipath, k) 554 return nil 555 556 case definedType: 557 pkg, name := r.qualifiedIdent() 558 r.p.doDecl(pkg, name) 559 return pkg.Scope().Lookup(name).(*types.TypeName).Type() 560 case pointerType: 561 return types.NewPointer(r.typ()) 562 case sliceType: 563 return types.NewSlice(r.typ()) 564 case arrayType: 565 n := r.uint64() 566 return types.NewArray(r.typ(), int64(n)) 567 case chanType: 568 dir := chanDir(int(r.uint64())) 569 return types.NewChan(dir, r.typ()) 570 case mapType: 571 return types.NewMap(r.typ(), r.typ()) 572 case signatureType: 573 r.currPkg = r.pkg() 574 return r.signature(nil) 575 576 case structType: 577 r.currPkg = r.pkg() 578 579 fields := make([]*types.Var, r.uint64()) 580 tags := make([]string, len(fields)) 581 for i := range fields { 582 fpos := r.pos() 583 fname := r.ident() 584 ftyp := r.typ() 585 emb := r.bool() 586 tag := r.string() 587 588 fields[i] = types.NewField(fpos, r.currPkg, fname, ftyp, emb) 589 tags[i] = tag 590 } 591 return types.NewStruct(fields, tags) 592 593 case interfaceType: 594 r.currPkg = r.pkg() 595 596 embeddeds := make([]types.Type, r.uint64()) 597 for i := range embeddeds { 598 _ = r.pos() 599 embeddeds[i] = r.typ() 600 } 601 602 methods := make([]*types.Func, r.uint64()) 603 for i := range methods { 604 mpos := r.pos() 605 mname := r.ident() 606 607 // TODO(mdempsky): Matches bimport.go, but I 608 // don't agree with this. 609 var recv *types.Var 610 if base != nil { 611 recv = types.NewVar(token.NoPos, r.currPkg, "", base) 612 } 613 614 msig := r.signature(recv) 615 methods[i] = types.NewFunc(mpos, r.currPkg, mname, msig) 616 } 617 618 typ := newInterface(methods, embeddeds) 619 r.p.interfaceList = append(r.p.interfaceList, typ) 620 return typ 621 } 622} 623 624func (r *importReader) kind() itag { 625 return itag(r.uint64()) 626} 627 628func (r *importReader) signature(recv *types.Var) *types.Signature { 629 params := r.paramList() 630 results := r.paramList() 631 variadic := params.Len() > 0 && r.bool() 632 return types.NewSignature(recv, params, results, variadic) 633} 634 635func (r *importReader) paramList() *types.Tuple { 636 xs := make([]*types.Var, r.uint64()) 637 for i := range xs { 638 xs[i] = r.param() 639 } 640 return types.NewTuple(xs...) 641} 642 643func (r *importReader) param() *types.Var { 644 pos := r.pos() 645 name := r.ident() 646 typ := r.typ() 647 return types.NewParam(pos, r.currPkg, name, typ) 648} 649 650func (r *importReader) bool() bool { 651 return r.uint64() != 0 652} 653 654func (r *importReader) int64() int64 { 655 n, err := binary.ReadVarint(&r.declReader) 656 if err != nil { 657 errorf("readVarint: %v", err) 658 } 659 return n 660} 661 662func (r *importReader) uint64() uint64 { 663 n, err := binary.ReadUvarint(&r.declReader) 664 if err != nil { 665 errorf("readUvarint: %v", err) 666 } 667 return n 668} 669 670func (r *importReader) byte() byte { 671 x, err := r.declReader.ReadByte() 672 if err != nil { 673 errorf("declReader.ReadByte: %v", err) 674 } 675 return x 676} 677