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