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