github.com/v2fly/tools@v0.100.0/go/internal/gcimporter/iexport.go (about) 1 // Copyright 2019 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 binary package export. 6 // This file was derived from $GOROOT/src/cmd/compile/internal/gc/iexport.go; 7 // see that file for specification of the format. 8 9 package gcimporter 10 11 import ( 12 "bytes" 13 "encoding/binary" 14 "go/ast" 15 "go/constant" 16 "go/token" 17 "go/types" 18 "io" 19 "math/big" 20 "reflect" 21 "sort" 22 ) 23 24 // Current indexed export format version. Increase with each format change. 25 // 0: Go1.11 encoding 26 const iexportVersion = 0 27 28 // Current bundled export format version. Increase with each format change. 29 // 0: initial implementation 30 const bundleVersion = 0 31 32 // IExportData writes indexed export data for pkg to out. 33 // 34 // If no file set is provided, position info will be missing. 35 // The package path of the top-level package will not be recorded, 36 // so that calls to IImportData can override with a provided package path. 37 func IExportData(out io.Writer, fset *token.FileSet, pkg *types.Package) error { 38 return iexportCommon(out, fset, false, []*types.Package{pkg}) 39 } 40 41 // IExportBundle writes an indexed export bundle for pkgs to out. 42 func IExportBundle(out io.Writer, fset *token.FileSet, pkgs []*types.Package) error { 43 return iexportCommon(out, fset, true, pkgs) 44 } 45 46 func iexportCommon(out io.Writer, fset *token.FileSet, bundle bool, pkgs []*types.Package) (err error) { 47 defer func() { 48 if e := recover(); e != nil { 49 if ierr, ok := e.(internalError); ok { 50 err = ierr 51 return 52 } 53 // Not an internal error; panic again. 54 panic(e) 55 } 56 }() 57 58 p := iexporter{ 59 fset: fset, 60 allPkgs: map[*types.Package]bool{}, 61 stringIndex: map[string]uint64{}, 62 declIndex: map[types.Object]uint64{}, 63 typIndex: map[types.Type]uint64{}, 64 } 65 if !bundle { 66 p.localpkg = pkgs[0] 67 } 68 69 for i, pt := range predeclared() { 70 p.typIndex[pt] = uint64(i) 71 } 72 if len(p.typIndex) > predeclReserved { 73 panic(internalErrorf("too many predeclared types: %d > %d", len(p.typIndex), predeclReserved)) 74 } 75 76 // Initialize work queue with exported declarations. 77 for _, pkg := range pkgs { 78 scope := pkg.Scope() 79 for _, name := range scope.Names() { 80 if ast.IsExported(name) { 81 p.pushDecl(scope.Lookup(name)) 82 } 83 } 84 85 if bundle { 86 // Ensure pkg and its imports are included in the index. 87 p.allPkgs[pkg] = true 88 for _, imp := range pkg.Imports() { 89 p.allPkgs[imp] = true 90 } 91 } 92 } 93 94 // Loop until no more work. 95 for !p.declTodo.empty() { 96 p.doDecl(p.declTodo.popHead()) 97 } 98 99 // Append indices to data0 section. 100 dataLen := uint64(p.data0.Len()) 101 w := p.newWriter() 102 w.writeIndex(p.declIndex) 103 104 if bundle { 105 w.uint64(uint64(len(pkgs))) 106 for _, pkg := range pkgs { 107 w.pkg(pkg) 108 imps := pkg.Imports() 109 w.uint64(uint64(len(imps))) 110 for _, imp := range imps { 111 w.pkg(imp) 112 } 113 } 114 } 115 w.flush() 116 117 // Assemble header. 118 var hdr intWriter 119 if bundle { 120 hdr.uint64(bundleVersion) 121 } 122 hdr.uint64(iexportVersion) 123 hdr.uint64(uint64(p.strings.Len())) 124 hdr.uint64(dataLen) 125 126 // Flush output. 127 io.Copy(out, &hdr) 128 io.Copy(out, &p.strings) 129 io.Copy(out, &p.data0) 130 131 return nil 132 } 133 134 // writeIndex writes out an object index. mainIndex indicates whether 135 // we're writing out the main index, which is also read by 136 // non-compiler tools and includes a complete package description 137 // (i.e., name and height). 138 func (w *exportWriter) writeIndex(index map[types.Object]uint64) { 139 // Build a map from packages to objects from that package. 140 pkgObjs := map[*types.Package][]types.Object{} 141 142 // For the main index, make sure to include every package that 143 // we reference, even if we're not exporting (or reexporting) 144 // any symbols from it. 145 if w.p.localpkg != nil { 146 pkgObjs[w.p.localpkg] = nil 147 } 148 for pkg := range w.p.allPkgs { 149 pkgObjs[pkg] = nil 150 } 151 152 for obj := range index { 153 pkgObjs[obj.Pkg()] = append(pkgObjs[obj.Pkg()], obj) 154 } 155 156 var pkgs []*types.Package 157 for pkg, objs := range pkgObjs { 158 pkgs = append(pkgs, pkg) 159 160 sort.Slice(objs, func(i, j int) bool { 161 return objs[i].Name() < objs[j].Name() 162 }) 163 } 164 165 sort.Slice(pkgs, func(i, j int) bool { 166 return w.exportPath(pkgs[i]) < w.exportPath(pkgs[j]) 167 }) 168 169 w.uint64(uint64(len(pkgs))) 170 for _, pkg := range pkgs { 171 w.string(w.exportPath(pkg)) 172 w.string(pkg.Name()) 173 w.uint64(uint64(0)) // package height is not needed for go/types 174 175 objs := pkgObjs[pkg] 176 w.uint64(uint64(len(objs))) 177 for _, obj := range objs { 178 w.string(obj.Name()) 179 w.uint64(index[obj]) 180 } 181 } 182 } 183 184 type iexporter struct { 185 fset *token.FileSet 186 out *bytes.Buffer 187 188 localpkg *types.Package 189 190 // allPkgs tracks all packages that have been referenced by 191 // the export data, so we can ensure to include them in the 192 // main index. 193 allPkgs map[*types.Package]bool 194 195 declTodo objQueue 196 197 strings intWriter 198 stringIndex map[string]uint64 199 200 data0 intWriter 201 declIndex map[types.Object]uint64 202 typIndex map[types.Type]uint64 203 } 204 205 // stringOff returns the offset of s within the string section. 206 // If not already present, it's added to the end. 207 func (p *iexporter) stringOff(s string) uint64 { 208 off, ok := p.stringIndex[s] 209 if !ok { 210 off = uint64(p.strings.Len()) 211 p.stringIndex[s] = off 212 213 p.strings.uint64(uint64(len(s))) 214 p.strings.WriteString(s) 215 } 216 return off 217 } 218 219 // pushDecl adds n to the declaration work queue, if not already present. 220 func (p *iexporter) pushDecl(obj types.Object) { 221 // Package unsafe is known to the compiler and predeclared. 222 assert(obj.Pkg() != types.Unsafe) 223 224 if _, ok := p.declIndex[obj]; ok { 225 return 226 } 227 228 p.declIndex[obj] = ^uint64(0) // mark n present in work queue 229 p.declTodo.pushTail(obj) 230 } 231 232 // exportWriter handles writing out individual data section chunks. 233 type exportWriter struct { 234 p *iexporter 235 236 data intWriter 237 currPkg *types.Package 238 prevFile string 239 prevLine int64 240 } 241 242 func (w *exportWriter) exportPath(pkg *types.Package) string { 243 if pkg == w.p.localpkg { 244 return "" 245 } 246 return pkg.Path() 247 } 248 249 func (p *iexporter) doDecl(obj types.Object) { 250 w := p.newWriter() 251 w.setPkg(obj.Pkg(), false) 252 253 switch obj := obj.(type) { 254 case *types.Var: 255 w.tag('V') 256 w.pos(obj.Pos()) 257 w.typ(obj.Type(), obj.Pkg()) 258 259 case *types.Func: 260 sig, _ := obj.Type().(*types.Signature) 261 if sig.Recv() != nil { 262 panic(internalErrorf("unexpected method: %v", sig)) 263 } 264 w.tag('F') 265 w.pos(obj.Pos()) 266 w.signature(sig) 267 268 case *types.Const: 269 w.tag('C') 270 w.pos(obj.Pos()) 271 w.value(obj.Type(), obj.Val()) 272 273 case *types.TypeName: 274 if obj.IsAlias() { 275 w.tag('A') 276 w.pos(obj.Pos()) 277 w.typ(obj.Type(), obj.Pkg()) 278 break 279 } 280 281 // Defined type. 282 w.tag('T') 283 w.pos(obj.Pos()) 284 285 underlying := obj.Type().Underlying() 286 w.typ(underlying, obj.Pkg()) 287 288 t := obj.Type() 289 if types.IsInterface(t) { 290 break 291 } 292 293 named, ok := t.(*types.Named) 294 if !ok { 295 panic(internalErrorf("%s is not a defined type", t)) 296 } 297 298 n := named.NumMethods() 299 w.uint64(uint64(n)) 300 for i := 0; i < n; i++ { 301 m := named.Method(i) 302 w.pos(m.Pos()) 303 w.string(m.Name()) 304 sig, _ := m.Type().(*types.Signature) 305 w.param(sig.Recv()) 306 w.signature(sig) 307 } 308 309 default: 310 panic(internalErrorf("unexpected object: %v", obj)) 311 } 312 313 p.declIndex[obj] = w.flush() 314 } 315 316 func (w *exportWriter) tag(tag byte) { 317 w.data.WriteByte(tag) 318 } 319 320 func (w *exportWriter) pos(pos token.Pos) { 321 if w.p.fset == nil { 322 w.int64(0) 323 return 324 } 325 326 p := w.p.fset.Position(pos) 327 file := p.Filename 328 line := int64(p.Line) 329 330 // When file is the same as the last position (common case), 331 // we can save a few bytes by delta encoding just the line 332 // number. 333 // 334 // Note: Because data objects may be read out of order (or not 335 // at all), we can only apply delta encoding within a single 336 // object. This is handled implicitly by tracking prevFile and 337 // prevLine as fields of exportWriter. 338 339 if file == w.prevFile { 340 delta := line - w.prevLine 341 w.int64(delta) 342 if delta == deltaNewFile { 343 w.int64(-1) 344 } 345 } else { 346 w.int64(deltaNewFile) 347 w.int64(line) // line >= 0 348 w.string(file) 349 w.prevFile = file 350 } 351 w.prevLine = line 352 } 353 354 func (w *exportWriter) pkg(pkg *types.Package) { 355 // Ensure any referenced packages are declared in the main index. 356 w.p.allPkgs[pkg] = true 357 358 w.string(w.exportPath(pkg)) 359 } 360 361 func (w *exportWriter) qualifiedIdent(obj types.Object) { 362 // Ensure any referenced declarations are written out too. 363 w.p.pushDecl(obj) 364 365 w.string(obj.Name()) 366 w.pkg(obj.Pkg()) 367 } 368 369 func (w *exportWriter) typ(t types.Type, pkg *types.Package) { 370 w.data.uint64(w.p.typOff(t, pkg)) 371 } 372 373 func (p *iexporter) newWriter() *exportWriter { 374 return &exportWriter{p: p} 375 } 376 377 func (w *exportWriter) flush() uint64 { 378 off := uint64(w.p.data0.Len()) 379 io.Copy(&w.p.data0, &w.data) 380 return off 381 } 382 383 func (p *iexporter) typOff(t types.Type, pkg *types.Package) uint64 { 384 off, ok := p.typIndex[t] 385 if !ok { 386 w := p.newWriter() 387 w.doTyp(t, pkg) 388 off = predeclReserved + w.flush() 389 p.typIndex[t] = off 390 } 391 return off 392 } 393 394 func (w *exportWriter) startType(k itag) { 395 w.data.uint64(uint64(k)) 396 } 397 398 func (w *exportWriter) doTyp(t types.Type, pkg *types.Package) { 399 switch t := t.(type) { 400 case *types.Named: 401 w.startType(definedType) 402 w.qualifiedIdent(t.Obj()) 403 404 case *types.Pointer: 405 w.startType(pointerType) 406 w.typ(t.Elem(), pkg) 407 408 case *types.Slice: 409 w.startType(sliceType) 410 w.typ(t.Elem(), pkg) 411 412 case *types.Array: 413 w.startType(arrayType) 414 w.uint64(uint64(t.Len())) 415 w.typ(t.Elem(), pkg) 416 417 case *types.Chan: 418 w.startType(chanType) 419 // 1 RecvOnly; 2 SendOnly; 3 SendRecv 420 var dir uint64 421 switch t.Dir() { 422 case types.RecvOnly: 423 dir = 1 424 case types.SendOnly: 425 dir = 2 426 case types.SendRecv: 427 dir = 3 428 } 429 w.uint64(dir) 430 w.typ(t.Elem(), pkg) 431 432 case *types.Map: 433 w.startType(mapType) 434 w.typ(t.Key(), pkg) 435 w.typ(t.Elem(), pkg) 436 437 case *types.Signature: 438 w.startType(signatureType) 439 w.setPkg(pkg, true) 440 w.signature(t) 441 442 case *types.Struct: 443 w.startType(structType) 444 w.setPkg(pkg, true) 445 446 n := t.NumFields() 447 w.uint64(uint64(n)) 448 for i := 0; i < n; i++ { 449 f := t.Field(i) 450 w.pos(f.Pos()) 451 w.string(f.Name()) 452 w.typ(f.Type(), pkg) 453 w.bool(f.Anonymous()) 454 w.string(t.Tag(i)) // note (or tag) 455 } 456 457 case *types.Interface: 458 w.startType(interfaceType) 459 w.setPkg(pkg, true) 460 461 n := t.NumEmbeddeds() 462 w.uint64(uint64(n)) 463 for i := 0; i < n; i++ { 464 f := t.Embedded(i) 465 w.pos(f.Obj().Pos()) 466 w.typ(f.Obj().Type(), f.Obj().Pkg()) 467 } 468 469 n = t.NumExplicitMethods() 470 w.uint64(uint64(n)) 471 for i := 0; i < n; i++ { 472 m := t.ExplicitMethod(i) 473 w.pos(m.Pos()) 474 w.string(m.Name()) 475 sig, _ := m.Type().(*types.Signature) 476 w.signature(sig) 477 } 478 479 default: 480 panic(internalErrorf("unexpected type: %v, %v", t, reflect.TypeOf(t))) 481 } 482 } 483 484 func (w *exportWriter) setPkg(pkg *types.Package, write bool) { 485 if write { 486 w.pkg(pkg) 487 } 488 489 w.currPkg = pkg 490 } 491 492 func (w *exportWriter) signature(sig *types.Signature) { 493 w.paramList(sig.Params()) 494 w.paramList(sig.Results()) 495 if sig.Params().Len() > 0 { 496 w.bool(sig.Variadic()) 497 } 498 } 499 500 func (w *exportWriter) paramList(tup *types.Tuple) { 501 n := tup.Len() 502 w.uint64(uint64(n)) 503 for i := 0; i < n; i++ { 504 w.param(tup.At(i)) 505 } 506 } 507 508 func (w *exportWriter) param(obj types.Object) { 509 w.pos(obj.Pos()) 510 w.localIdent(obj) 511 w.typ(obj.Type(), obj.Pkg()) 512 } 513 514 func (w *exportWriter) value(typ types.Type, v constant.Value) { 515 w.typ(typ, nil) 516 517 switch b := typ.Underlying().(*types.Basic); b.Info() & types.IsConstType { 518 case types.IsBoolean: 519 w.bool(constant.BoolVal(v)) 520 case types.IsInteger: 521 var i big.Int 522 if i64, exact := constant.Int64Val(v); exact { 523 i.SetInt64(i64) 524 } else if ui64, exact := constant.Uint64Val(v); exact { 525 i.SetUint64(ui64) 526 } else { 527 i.SetString(v.ExactString(), 10) 528 } 529 w.mpint(&i, typ) 530 case types.IsFloat: 531 f := constantToFloat(v) 532 w.mpfloat(f, typ) 533 case types.IsComplex: 534 w.mpfloat(constantToFloat(constant.Real(v)), typ) 535 w.mpfloat(constantToFloat(constant.Imag(v)), typ) 536 case types.IsString: 537 w.string(constant.StringVal(v)) 538 default: 539 if b.Kind() == types.Invalid { 540 // package contains type errors 541 break 542 } 543 panic(internalErrorf("unexpected type %v (%v)", typ, typ.Underlying())) 544 } 545 } 546 547 // constantToFloat converts a constant.Value with kind constant.Float to a 548 // big.Float. 549 func constantToFloat(x constant.Value) *big.Float { 550 x = constant.ToFloat(x) 551 // Use the same floating-point precision (512) as cmd/compile 552 // (see Mpprec in cmd/compile/internal/gc/mpfloat.go). 553 const mpprec = 512 554 var f big.Float 555 f.SetPrec(mpprec) 556 if v, exact := constant.Float64Val(x); exact { 557 // float64 558 f.SetFloat64(v) 559 } else if num, denom := constant.Num(x), constant.Denom(x); num.Kind() == constant.Int { 560 // TODO(gri): add big.Rat accessor to constant.Value. 561 n := valueToRat(num) 562 d := valueToRat(denom) 563 f.SetRat(n.Quo(n, d)) 564 } else { 565 // Value too large to represent as a fraction => inaccessible. 566 // TODO(gri): add big.Float accessor to constant.Value. 567 _, ok := f.SetString(x.ExactString()) 568 assert(ok) 569 } 570 return &f 571 } 572 573 // mpint exports a multi-precision integer. 574 // 575 // For unsigned types, small values are written out as a single 576 // byte. Larger values are written out as a length-prefixed big-endian 577 // byte string, where the length prefix is encoded as its complement. 578 // For example, bytes 0, 1, and 2 directly represent the integer 579 // values 0, 1, and 2; while bytes 255, 254, and 253 indicate a 1-, 580 // 2-, and 3-byte big-endian string follow. 581 // 582 // Encoding for signed types use the same general approach as for 583 // unsigned types, except small values use zig-zag encoding and the 584 // bottom bit of length prefix byte for large values is reserved as a 585 // sign bit. 586 // 587 // The exact boundary between small and large encodings varies 588 // according to the maximum number of bytes needed to encode a value 589 // of type typ. As a special case, 8-bit types are always encoded as a 590 // single byte. 591 // 592 // TODO(mdempsky): Is this level of complexity really worthwhile? 593 func (w *exportWriter) mpint(x *big.Int, typ types.Type) { 594 basic, ok := typ.Underlying().(*types.Basic) 595 if !ok { 596 panic(internalErrorf("unexpected type %v (%T)", typ.Underlying(), typ.Underlying())) 597 } 598 599 signed, maxBytes := intSize(basic) 600 601 negative := x.Sign() < 0 602 if !signed && negative { 603 panic(internalErrorf("negative unsigned integer; type %v, value %v", typ, x)) 604 } 605 606 b := x.Bytes() 607 if len(b) > 0 && b[0] == 0 { 608 panic(internalErrorf("leading zeros")) 609 } 610 if uint(len(b)) > maxBytes { 611 panic(internalErrorf("bad mpint length: %d > %d (type %v, value %v)", len(b), maxBytes, typ, x)) 612 } 613 614 maxSmall := 256 - maxBytes 615 if signed { 616 maxSmall = 256 - 2*maxBytes 617 } 618 if maxBytes == 1 { 619 maxSmall = 256 620 } 621 622 // Check if x can use small value encoding. 623 if len(b) <= 1 { 624 var ux uint 625 if len(b) == 1 { 626 ux = uint(b[0]) 627 } 628 if signed { 629 ux <<= 1 630 if negative { 631 ux-- 632 } 633 } 634 if ux < maxSmall { 635 w.data.WriteByte(byte(ux)) 636 return 637 } 638 } 639 640 n := 256 - uint(len(b)) 641 if signed { 642 n = 256 - 2*uint(len(b)) 643 if negative { 644 n |= 1 645 } 646 } 647 if n < maxSmall || n >= 256 { 648 panic(internalErrorf("encoding mistake: %d, %v, %v => %d", len(b), signed, negative, n)) 649 } 650 651 w.data.WriteByte(byte(n)) 652 w.data.Write(b) 653 } 654 655 // mpfloat exports a multi-precision floating point number. 656 // 657 // The number's value is decomposed into mantissa × 2**exponent, where 658 // mantissa is an integer. The value is written out as mantissa (as a 659 // multi-precision integer) and then the exponent, except exponent is 660 // omitted if mantissa is zero. 661 func (w *exportWriter) mpfloat(f *big.Float, typ types.Type) { 662 if f.IsInf() { 663 panic("infinite constant") 664 } 665 666 // Break into f = mant × 2**exp, with 0.5 <= mant < 1. 667 var mant big.Float 668 exp := int64(f.MantExp(&mant)) 669 670 // Scale so that mant is an integer. 671 prec := mant.MinPrec() 672 mant.SetMantExp(&mant, int(prec)) 673 exp -= int64(prec) 674 675 manti, acc := mant.Int(nil) 676 if acc != big.Exact { 677 panic(internalErrorf("mantissa scaling failed for %f (%s)", f, acc)) 678 } 679 w.mpint(manti, typ) 680 if manti.Sign() != 0 { 681 w.int64(exp) 682 } 683 } 684 685 func (w *exportWriter) bool(b bool) bool { 686 var x uint64 687 if b { 688 x = 1 689 } 690 w.uint64(x) 691 return b 692 } 693 694 func (w *exportWriter) int64(x int64) { w.data.int64(x) } 695 func (w *exportWriter) uint64(x uint64) { w.data.uint64(x) } 696 func (w *exportWriter) string(s string) { w.uint64(w.p.stringOff(s)) } 697 698 func (w *exportWriter) localIdent(obj types.Object) { 699 // Anonymous parameters. 700 if obj == nil { 701 w.string("") 702 return 703 } 704 705 name := obj.Name() 706 if name == "_" { 707 w.string("_") 708 return 709 } 710 711 w.string(name) 712 } 713 714 type intWriter struct { 715 bytes.Buffer 716 } 717 718 func (w *intWriter) int64(x int64) { 719 var buf [binary.MaxVarintLen64]byte 720 n := binary.PutVarint(buf[:], x) 721 w.Write(buf[:n]) 722 } 723 724 func (w *intWriter) uint64(x uint64) { 725 var buf [binary.MaxVarintLen64]byte 726 n := binary.PutUvarint(buf[:], x) 727 w.Write(buf[:n]) 728 } 729 730 func assert(cond bool) { 731 if !cond { 732 panic("internal error: assertion failed") 733 } 734 } 735 736 // The below is copied from go/src/cmd/compile/internal/gc/syntax.go. 737 738 // objQueue is a FIFO queue of types.Object. The zero value of objQueue is 739 // a ready-to-use empty queue. 740 type objQueue struct { 741 ring []types.Object 742 head, tail int 743 } 744 745 // empty returns true if q contains no Nodes. 746 func (q *objQueue) empty() bool { 747 return q.head == q.tail 748 } 749 750 // pushTail appends n to the tail of the queue. 751 func (q *objQueue) pushTail(obj types.Object) { 752 if len(q.ring) == 0 { 753 q.ring = make([]types.Object, 16) 754 } else if q.head+len(q.ring) == q.tail { 755 // Grow the ring. 756 nring := make([]types.Object, len(q.ring)*2) 757 // Copy the old elements. 758 part := q.ring[q.head%len(q.ring):] 759 if q.tail-q.head <= len(part) { 760 part = part[:q.tail-q.head] 761 copy(nring, part) 762 } else { 763 pos := copy(nring, part) 764 copy(nring[pos:], q.ring[:q.tail%len(q.ring)]) 765 } 766 q.ring, q.head, q.tail = nring, 0, q.tail-q.head 767 } 768 769 q.ring[q.tail%len(q.ring)] = obj 770 q.tail++ 771 } 772 773 // popHead pops a node from the head of the queue. It panics if q is empty. 774 func (q *objQueue) popHead() types.Object { 775 if q.empty() { 776 panic("dequeue empty") 777 } 778 obj := q.ring[q.head%len(q.ring)] 779 q.head++ 780 return obj 781 }