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