github.com/cockroachdb/tools@v0.0.0-20230222021103-a6d27438930d/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 "fmt" 15 "go/constant" 16 "go/token" 17 "go/types" 18 "io" 19 "math/big" 20 "reflect" 21 "sort" 22 "strconv" 23 "strings" 24 25 "golang.org/x/tools/internal/tokeninternal" 26 "golang.org/x/tools/internal/typeparams" 27 ) 28 29 // IExportShallow encodes "shallow" export data for the specified package. 30 // 31 // No promises are made about the encoding other than that it can be 32 // decoded by the same version of IIExportShallow. If you plan to save 33 // export data in the file system, be sure to include a cryptographic 34 // digest of the executable in the key to avoid version skew. 35 func IExportShallow(fset *token.FileSet, pkg *types.Package) ([]byte, error) { 36 // In principle this operation can only fail if out.Write fails, 37 // but that's impossible for bytes.Buffer---and as a matter of 38 // fact iexportCommon doesn't even check for I/O errors. 39 // TODO(adonovan): handle I/O errors properly. 40 // TODO(adonovan): use byte slices throughout, avoiding copying. 41 const bundle, shallow = false, true 42 var out bytes.Buffer 43 err := iexportCommon(&out, fset, bundle, shallow, iexportVersion, []*types.Package{pkg}) 44 return out.Bytes(), err 45 } 46 47 // IImportShallow decodes "shallow" types.Package data encoded by IExportShallow 48 // in the same executable. This function cannot import data from 49 // cmd/compile or gcexportdata.Write. 50 func IImportShallow(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string, insert InsertType) (*types.Package, error) { 51 const bundle = false 52 pkgs, err := iimportCommon(fset, imports, data, bundle, path, insert) 53 if err != nil { 54 return nil, err 55 } 56 return pkgs[0], nil 57 } 58 59 // InsertType is the type of a function that creates a types.TypeName 60 // object for a named type and inserts it into the scope of the 61 // specified Package. 62 type InsertType = func(pkg *types.Package, name string) 63 64 // Current bundled export format version. Increase with each format change. 65 // 0: initial implementation 66 const bundleVersion = 0 67 68 // IExportData writes indexed export data for pkg to out. 69 // 70 // If no file set is provided, position info will be missing. 71 // The package path of the top-level package will not be recorded, 72 // so that calls to IImportData can override with a provided package path. 73 func IExportData(out io.Writer, fset *token.FileSet, pkg *types.Package) error { 74 const bundle, shallow = false, false 75 return iexportCommon(out, fset, bundle, shallow, iexportVersion, []*types.Package{pkg}) 76 } 77 78 // IExportBundle writes an indexed export bundle for pkgs to out. 79 func IExportBundle(out io.Writer, fset *token.FileSet, pkgs []*types.Package) error { 80 const bundle, shallow = true, false 81 return iexportCommon(out, fset, bundle, shallow, iexportVersion, pkgs) 82 } 83 84 func iexportCommon(out io.Writer, fset *token.FileSet, bundle, shallow bool, version int, pkgs []*types.Package) (err error) { 85 if !debug { 86 defer func() { 87 if e := recover(); e != nil { 88 if ierr, ok := e.(internalError); ok { 89 err = ierr 90 return 91 } 92 // Not an internal error; panic again. 93 panic(e) 94 } 95 }() 96 } 97 98 p := iexporter{ 99 fset: fset, 100 version: version, 101 shallow: shallow, 102 allPkgs: map[*types.Package]bool{}, 103 stringIndex: map[string]uint64{}, 104 declIndex: map[types.Object]uint64{}, 105 tparamNames: map[types.Object]string{}, 106 typIndex: map[types.Type]uint64{}, 107 } 108 if !bundle { 109 p.localpkg = pkgs[0] 110 } 111 112 for i, pt := range predeclared() { 113 p.typIndex[pt] = uint64(i) 114 } 115 if len(p.typIndex) > predeclReserved { 116 panic(internalErrorf("too many predeclared types: %d > %d", len(p.typIndex), predeclReserved)) 117 } 118 119 // Initialize work queue with exported declarations. 120 for _, pkg := range pkgs { 121 scope := pkg.Scope() 122 for _, name := range scope.Names() { 123 if token.IsExported(name) { 124 p.pushDecl(scope.Lookup(name)) 125 } 126 } 127 128 if bundle { 129 // Ensure pkg and its imports are included in the index. 130 p.allPkgs[pkg] = true 131 for _, imp := range pkg.Imports() { 132 p.allPkgs[imp] = true 133 } 134 } 135 } 136 137 // Loop until no more work. 138 for !p.declTodo.empty() { 139 p.doDecl(p.declTodo.popHead()) 140 } 141 142 // Produce index of offset of each file record in files. 143 var files intWriter 144 var fileOffset []uint64 // fileOffset[i] is offset in files of file encoded as i 145 if p.shallow { 146 fileOffset = make([]uint64, len(p.fileInfos)) 147 for i, info := range p.fileInfos { 148 fileOffset[i] = uint64(files.Len()) 149 p.encodeFile(&files, info.file, info.needed) 150 } 151 } 152 153 // Append indices to data0 section. 154 dataLen := uint64(p.data0.Len()) 155 w := p.newWriter() 156 w.writeIndex(p.declIndex) 157 158 if bundle { 159 w.uint64(uint64(len(pkgs))) 160 for _, pkg := range pkgs { 161 w.pkg(pkg) 162 imps := pkg.Imports() 163 w.uint64(uint64(len(imps))) 164 for _, imp := range imps { 165 w.pkg(imp) 166 } 167 } 168 } 169 w.flush() 170 171 // Assemble header. 172 var hdr intWriter 173 if bundle { 174 hdr.uint64(bundleVersion) 175 } 176 hdr.uint64(uint64(p.version)) 177 hdr.uint64(uint64(p.strings.Len())) 178 if p.shallow { 179 hdr.uint64(uint64(files.Len())) 180 hdr.uint64(uint64(len(fileOffset))) 181 for _, offset := range fileOffset { 182 hdr.uint64(offset) 183 } 184 } 185 hdr.uint64(dataLen) 186 187 // Flush output. 188 io.Copy(out, &hdr) 189 io.Copy(out, &p.strings) 190 if p.shallow { 191 io.Copy(out, &files) 192 } 193 io.Copy(out, &p.data0) 194 195 return nil 196 } 197 198 // encodeFile writes to w a representation of the file sufficient to 199 // faithfully restore position information about all needed offsets. 200 // Mutates the needed array. 201 func (p *iexporter) encodeFile(w *intWriter, file *token.File, needed []uint64) { 202 _ = needed[0] // precondition: needed is non-empty 203 204 w.uint64(p.stringOff(file.Name())) 205 206 size := uint64(file.Size()) 207 w.uint64(size) 208 209 // Sort the set of needed offsets. Duplicates are harmless. 210 sort.Slice(needed, func(i, j int) bool { return needed[i] < needed[j] }) 211 212 lines := tokeninternal.GetLines(file) // byte offset of each line start 213 w.uint64(uint64(len(lines))) 214 215 // Rather than record the entire array of line start offsets, 216 // we save only a sparse list of (index, offset) pairs for 217 // the start of each line that contains a needed position. 218 var sparse [][2]int // (index, offset) pairs 219 outer: 220 for i, lineStart := range lines { 221 lineEnd := size 222 if i < len(lines)-1 { 223 lineEnd = uint64(lines[i+1]) 224 } 225 // Does this line contains a needed offset? 226 if needed[0] < lineEnd { 227 sparse = append(sparse, [2]int{i, lineStart}) 228 for needed[0] < lineEnd { 229 needed = needed[1:] 230 if len(needed) == 0 { 231 break outer 232 } 233 } 234 } 235 } 236 237 // Delta-encode the columns. 238 w.uint64(uint64(len(sparse))) 239 var prev [2]int 240 for _, pair := range sparse { 241 w.uint64(uint64(pair[0] - prev[0])) 242 w.uint64(uint64(pair[1] - prev[1])) 243 prev = pair 244 } 245 } 246 247 // writeIndex writes out an object index. mainIndex indicates whether 248 // we're writing out the main index, which is also read by 249 // non-compiler tools and includes a complete package description 250 // (i.e., name and height). 251 func (w *exportWriter) writeIndex(index map[types.Object]uint64) { 252 type pkgObj struct { 253 obj types.Object 254 name string // qualified name; differs from obj.Name for type params 255 } 256 // Build a map from packages to objects from that package. 257 pkgObjs := map[*types.Package][]pkgObj{} 258 259 // For the main index, make sure to include every package that 260 // we reference, even if we're not exporting (or reexporting) 261 // any symbols from it. 262 if w.p.localpkg != nil { 263 pkgObjs[w.p.localpkg] = nil 264 } 265 for pkg := range w.p.allPkgs { 266 pkgObjs[pkg] = nil 267 } 268 269 for obj := range index { 270 name := w.p.exportName(obj) 271 pkgObjs[obj.Pkg()] = append(pkgObjs[obj.Pkg()], pkgObj{obj, name}) 272 } 273 274 var pkgs []*types.Package 275 for pkg, objs := range pkgObjs { 276 pkgs = append(pkgs, pkg) 277 278 sort.Slice(objs, func(i, j int) bool { 279 return objs[i].name < objs[j].name 280 }) 281 } 282 283 sort.Slice(pkgs, func(i, j int) bool { 284 return w.exportPath(pkgs[i]) < w.exportPath(pkgs[j]) 285 }) 286 287 w.uint64(uint64(len(pkgs))) 288 for _, pkg := range pkgs { 289 w.string(w.exportPath(pkg)) 290 w.string(pkg.Name()) 291 w.uint64(uint64(0)) // package height is not needed for go/types 292 293 objs := pkgObjs[pkg] 294 w.uint64(uint64(len(objs))) 295 for _, obj := range objs { 296 w.string(obj.name) 297 w.uint64(index[obj.obj]) 298 } 299 } 300 } 301 302 // exportName returns the 'exported' name of an object. It differs from 303 // obj.Name() only for type parameters (see tparamExportName for details). 304 func (p *iexporter) exportName(obj types.Object) (res string) { 305 if name := p.tparamNames[obj]; name != "" { 306 return name 307 } 308 return obj.Name() 309 } 310 311 type iexporter struct { 312 fset *token.FileSet 313 out *bytes.Buffer 314 version int 315 316 shallow bool // don't put types from other packages in the index 317 localpkg *types.Package // (nil in bundle mode) 318 319 // allPkgs tracks all packages that have been referenced by 320 // the export data, so we can ensure to include them in the 321 // main index. 322 allPkgs map[*types.Package]bool 323 324 declTodo objQueue 325 326 strings intWriter 327 stringIndex map[string]uint64 328 329 // In shallow mode, object positions are encoded as (file, offset). 330 // Each file is recorded as a line-number table. 331 // Only the lines of needed positions are saved faithfully. 332 fileInfo map[*token.File]uint64 // value is index in fileInfos 333 fileInfos []*filePositions 334 335 data0 intWriter 336 declIndex map[types.Object]uint64 337 tparamNames map[types.Object]string // typeparam->exported name 338 typIndex map[types.Type]uint64 339 340 indent int // for tracing support 341 } 342 343 type filePositions struct { 344 file *token.File 345 needed []uint64 // unordered list of needed file offsets 346 } 347 348 func (p *iexporter) trace(format string, args ...interface{}) { 349 if !trace { 350 // Call sites should also be guarded, but having this check here allows 351 // easily enabling/disabling debug trace statements. 352 return 353 } 354 fmt.Printf(strings.Repeat("..", p.indent)+format+"\n", args...) 355 } 356 357 // stringOff returns the offset of s within the string section. 358 // If not already present, it's added to the end. 359 func (p *iexporter) stringOff(s string) uint64 { 360 off, ok := p.stringIndex[s] 361 if !ok { 362 off = uint64(p.strings.Len()) 363 p.stringIndex[s] = off 364 365 p.strings.uint64(uint64(len(s))) 366 p.strings.WriteString(s) 367 } 368 return off 369 } 370 371 // fileIndexAndOffset returns the index of the token.File and the byte offset of pos within it. 372 func (p *iexporter) fileIndexAndOffset(file *token.File, pos token.Pos) (uint64, uint64) { 373 index, ok := p.fileInfo[file] 374 if !ok { 375 index = uint64(len(p.fileInfo)) 376 p.fileInfos = append(p.fileInfos, &filePositions{file: file}) 377 if p.fileInfo == nil { 378 p.fileInfo = make(map[*token.File]uint64) 379 } 380 p.fileInfo[file] = index 381 } 382 // Record each needed offset. 383 info := p.fileInfos[index] 384 offset := uint64(file.Offset(pos)) 385 info.needed = append(info.needed, offset) 386 387 return index, offset 388 } 389 390 // pushDecl adds n to the declaration work queue, if not already present. 391 func (p *iexporter) pushDecl(obj types.Object) { 392 // Package unsafe is known to the compiler and predeclared. 393 // Caller should not ask us to do export it. 394 if obj.Pkg() == types.Unsafe { 395 panic("cannot export package unsafe") 396 } 397 398 // Shallow export data: don't index decls from other packages. 399 if p.shallow && obj.Pkg() != p.localpkg { 400 return 401 } 402 403 if _, ok := p.declIndex[obj]; ok { 404 return 405 } 406 407 p.declIndex[obj] = ^uint64(0) // mark obj present in work queue 408 p.declTodo.pushTail(obj) 409 } 410 411 // exportWriter handles writing out individual data section chunks. 412 type exportWriter struct { 413 p *iexporter 414 415 data intWriter 416 currPkg *types.Package 417 prevFile string 418 prevLine int64 419 prevColumn int64 420 } 421 422 func (w *exportWriter) exportPath(pkg *types.Package) string { 423 if pkg == w.p.localpkg { 424 return "" 425 } 426 return pkg.Path() 427 } 428 429 func (p *iexporter) doDecl(obj types.Object) { 430 if trace { 431 p.trace("exporting decl %v (%T)", obj, obj) 432 p.indent++ 433 defer func() { 434 p.indent-- 435 p.trace("=> %s", obj) 436 }() 437 } 438 w := p.newWriter() 439 w.setPkg(obj.Pkg(), false) 440 441 switch obj := obj.(type) { 442 case *types.Var: 443 w.tag('V') 444 w.pos(obj.Pos()) 445 w.typ(obj.Type(), obj.Pkg()) 446 447 case *types.Func: 448 sig, _ := obj.Type().(*types.Signature) 449 if sig.Recv() != nil { 450 // We shouldn't see methods in the package scope, 451 // but the type checker may repair "func () F() {}" 452 // to "func (Invalid) F()" and then treat it like "func F()", 453 // so allow that. See golang/go#57729. 454 if sig.Recv().Type() != types.Typ[types.Invalid] { 455 panic(internalErrorf("unexpected method: %v", sig)) 456 } 457 } 458 459 // Function. 460 if typeparams.ForSignature(sig).Len() == 0 { 461 w.tag('F') 462 } else { 463 w.tag('G') 464 } 465 w.pos(obj.Pos()) 466 // The tparam list of the function type is the declaration of the type 467 // params. So, write out the type params right now. Then those type params 468 // will be referenced via their type offset (via typOff) in all other 469 // places in the signature and function where they are used. 470 // 471 // While importing the type parameters, tparamList computes and records 472 // their export name, so that it can be later used when writing the index. 473 if tparams := typeparams.ForSignature(sig); tparams.Len() > 0 { 474 w.tparamList(obj.Name(), tparams, obj.Pkg()) 475 } 476 w.signature(sig) 477 478 case *types.Const: 479 w.tag('C') 480 w.pos(obj.Pos()) 481 w.value(obj.Type(), obj.Val()) 482 483 case *types.TypeName: 484 t := obj.Type() 485 486 if tparam, ok := t.(*typeparams.TypeParam); ok { 487 w.tag('P') 488 w.pos(obj.Pos()) 489 constraint := tparam.Constraint() 490 if p.version >= iexportVersionGo1_18 { 491 implicit := false 492 if iface, _ := constraint.(*types.Interface); iface != nil { 493 implicit = typeparams.IsImplicit(iface) 494 } 495 w.bool(implicit) 496 } 497 w.typ(constraint, obj.Pkg()) 498 break 499 } 500 501 if obj.IsAlias() { 502 w.tag('A') 503 w.pos(obj.Pos()) 504 w.typ(t, obj.Pkg()) 505 break 506 } 507 508 // Defined type. 509 named, ok := t.(*types.Named) 510 if !ok { 511 panic(internalErrorf("%s is not a defined type", t)) 512 } 513 514 if typeparams.ForNamed(named).Len() == 0 { 515 w.tag('T') 516 } else { 517 w.tag('U') 518 } 519 w.pos(obj.Pos()) 520 521 if typeparams.ForNamed(named).Len() > 0 { 522 // While importing the type parameters, tparamList computes and records 523 // their export name, so that it can be later used when writing the index. 524 w.tparamList(obj.Name(), typeparams.ForNamed(named), obj.Pkg()) 525 } 526 527 underlying := obj.Type().Underlying() 528 w.typ(underlying, obj.Pkg()) 529 530 if types.IsInterface(t) { 531 break 532 } 533 534 n := named.NumMethods() 535 w.uint64(uint64(n)) 536 for i := 0; i < n; i++ { 537 m := named.Method(i) 538 w.pos(m.Pos()) 539 w.string(m.Name()) 540 sig, _ := m.Type().(*types.Signature) 541 542 // Receiver type parameters are type arguments of the receiver type, so 543 // their name must be qualified before exporting recv. 544 if rparams := typeparams.RecvTypeParams(sig); rparams.Len() > 0 { 545 prefix := obj.Name() + "." + m.Name() 546 for i := 0; i < rparams.Len(); i++ { 547 rparam := rparams.At(i) 548 name := tparamExportName(prefix, rparam) 549 w.p.tparamNames[rparam.Obj()] = name 550 } 551 } 552 w.param(sig.Recv()) 553 w.signature(sig) 554 } 555 556 default: 557 panic(internalErrorf("unexpected object: %v", obj)) 558 } 559 560 p.declIndex[obj] = w.flush() 561 } 562 563 func (w *exportWriter) tag(tag byte) { 564 w.data.WriteByte(tag) 565 } 566 567 func (w *exportWriter) pos(pos token.Pos) { 568 if w.p.shallow { 569 w.posV2(pos) 570 } else if w.p.version >= iexportVersionPosCol { 571 w.posV1(pos) 572 } else { 573 w.posV0(pos) 574 } 575 } 576 577 // posV2 encoding (used only in shallow mode) records positions as 578 // (file, offset), where file is the index in the token.File table 579 // (which records the file name and newline offsets) and offset is a 580 // byte offset. It effectively ignores //line directives. 581 func (w *exportWriter) posV2(pos token.Pos) { 582 if pos == token.NoPos { 583 w.uint64(0) 584 return 585 } 586 file := w.p.fset.File(pos) // fset must be non-nil 587 index, offset := w.p.fileIndexAndOffset(file, pos) 588 w.uint64(1 + index) 589 w.uint64(offset) 590 } 591 592 func (w *exportWriter) posV1(pos token.Pos) { 593 if w.p.fset == nil { 594 w.int64(0) 595 return 596 } 597 598 p := w.p.fset.Position(pos) 599 file := p.Filename 600 line := int64(p.Line) 601 column := int64(p.Column) 602 603 deltaColumn := (column - w.prevColumn) << 1 604 deltaLine := (line - w.prevLine) << 1 605 606 if file != w.prevFile { 607 deltaLine |= 1 608 } 609 if deltaLine != 0 { 610 deltaColumn |= 1 611 } 612 613 w.int64(deltaColumn) 614 if deltaColumn&1 != 0 { 615 w.int64(deltaLine) 616 if deltaLine&1 != 0 { 617 w.string(file) 618 } 619 } 620 621 w.prevFile = file 622 w.prevLine = line 623 w.prevColumn = column 624 } 625 626 func (w *exportWriter) posV0(pos token.Pos) { 627 if w.p.fset == nil { 628 w.int64(0) 629 return 630 } 631 632 p := w.p.fset.Position(pos) 633 file := p.Filename 634 line := int64(p.Line) 635 636 // When file is the same as the last position (common case), 637 // we can save a few bytes by delta encoding just the line 638 // number. 639 // 640 // Note: Because data objects may be read out of order (or not 641 // at all), we can only apply delta encoding within a single 642 // object. This is handled implicitly by tracking prevFile and 643 // prevLine as fields of exportWriter. 644 645 if file == w.prevFile { 646 delta := line - w.prevLine 647 w.int64(delta) 648 if delta == deltaNewFile { 649 w.int64(-1) 650 } 651 } else { 652 w.int64(deltaNewFile) 653 w.int64(line) // line >= 0 654 w.string(file) 655 w.prevFile = file 656 } 657 w.prevLine = line 658 } 659 660 func (w *exportWriter) pkg(pkg *types.Package) { 661 // Ensure any referenced packages are declared in the main index. 662 w.p.allPkgs[pkg] = true 663 664 w.string(w.exportPath(pkg)) 665 } 666 667 func (w *exportWriter) qualifiedType(obj *types.TypeName) { 668 name := w.p.exportName(obj) 669 670 // Ensure any referenced declarations are written out too. 671 w.p.pushDecl(obj) 672 w.string(name) 673 w.pkg(obj.Pkg()) 674 } 675 676 func (w *exportWriter) typ(t types.Type, pkg *types.Package) { 677 w.data.uint64(w.p.typOff(t, pkg)) 678 } 679 680 func (p *iexporter) newWriter() *exportWriter { 681 return &exportWriter{p: p} 682 } 683 684 func (w *exportWriter) flush() uint64 { 685 off := uint64(w.p.data0.Len()) 686 io.Copy(&w.p.data0, &w.data) 687 return off 688 } 689 690 func (p *iexporter) typOff(t types.Type, pkg *types.Package) uint64 { 691 off, ok := p.typIndex[t] 692 if !ok { 693 w := p.newWriter() 694 w.doTyp(t, pkg) 695 off = predeclReserved + w.flush() 696 p.typIndex[t] = off 697 } 698 return off 699 } 700 701 func (w *exportWriter) startType(k itag) { 702 w.data.uint64(uint64(k)) 703 } 704 705 func (w *exportWriter) doTyp(t types.Type, pkg *types.Package) { 706 if trace { 707 w.p.trace("exporting type %s (%T)", t, t) 708 w.p.indent++ 709 defer func() { 710 w.p.indent-- 711 w.p.trace("=> %s", t) 712 }() 713 } 714 switch t := t.(type) { 715 case *types.Named: 716 if targs := typeparams.NamedTypeArgs(t); targs.Len() > 0 { 717 w.startType(instanceType) 718 // TODO(rfindley): investigate if this position is correct, and if it 719 // matters. 720 w.pos(t.Obj().Pos()) 721 w.typeList(targs, pkg) 722 w.typ(typeparams.NamedTypeOrigin(t), pkg) 723 return 724 } 725 w.startType(definedType) 726 w.qualifiedType(t.Obj()) 727 728 case *typeparams.TypeParam: 729 w.startType(typeParamType) 730 w.qualifiedType(t.Obj()) 731 732 case *types.Pointer: 733 w.startType(pointerType) 734 w.typ(t.Elem(), pkg) 735 736 case *types.Slice: 737 w.startType(sliceType) 738 w.typ(t.Elem(), pkg) 739 740 case *types.Array: 741 w.startType(arrayType) 742 w.uint64(uint64(t.Len())) 743 w.typ(t.Elem(), pkg) 744 745 case *types.Chan: 746 w.startType(chanType) 747 // 1 RecvOnly; 2 SendOnly; 3 SendRecv 748 var dir uint64 749 switch t.Dir() { 750 case types.RecvOnly: 751 dir = 1 752 case types.SendOnly: 753 dir = 2 754 case types.SendRecv: 755 dir = 3 756 } 757 w.uint64(dir) 758 w.typ(t.Elem(), pkg) 759 760 case *types.Map: 761 w.startType(mapType) 762 w.typ(t.Key(), pkg) 763 w.typ(t.Elem(), pkg) 764 765 case *types.Signature: 766 w.startType(signatureType) 767 w.setPkg(pkg, true) 768 w.signature(t) 769 770 case *types.Struct: 771 w.startType(structType) 772 n := t.NumFields() 773 if n > 0 { 774 w.setPkg(t.Field(0).Pkg(), true) // qualifying package for field objects 775 } else { 776 w.setPkg(pkg, true) 777 } 778 w.uint64(uint64(n)) 779 for i := 0; i < n; i++ { 780 f := t.Field(i) 781 w.pos(f.Pos()) 782 w.string(f.Name()) // unexported fields implicitly qualified by prior setPkg 783 w.typ(f.Type(), pkg) 784 w.bool(f.Anonymous()) 785 w.string(t.Tag(i)) // note (or tag) 786 } 787 788 case *types.Interface: 789 w.startType(interfaceType) 790 w.setPkg(pkg, true) 791 792 n := t.NumEmbeddeds() 793 w.uint64(uint64(n)) 794 for i := 0; i < n; i++ { 795 ft := t.EmbeddedType(i) 796 tPkg := pkg 797 if named, _ := ft.(*types.Named); named != nil { 798 w.pos(named.Obj().Pos()) 799 } else { 800 w.pos(token.NoPos) 801 } 802 w.typ(ft, tPkg) 803 } 804 805 n = t.NumExplicitMethods() 806 w.uint64(uint64(n)) 807 for i := 0; i < n; i++ { 808 m := t.ExplicitMethod(i) 809 w.pos(m.Pos()) 810 w.string(m.Name()) 811 sig, _ := m.Type().(*types.Signature) 812 w.signature(sig) 813 } 814 815 case *typeparams.Union: 816 w.startType(unionType) 817 nt := t.Len() 818 w.uint64(uint64(nt)) 819 for i := 0; i < nt; i++ { 820 term := t.Term(i) 821 w.bool(term.Tilde()) 822 w.typ(term.Type(), pkg) 823 } 824 825 default: 826 panic(internalErrorf("unexpected type: %v, %v", t, reflect.TypeOf(t))) 827 } 828 } 829 830 func (w *exportWriter) setPkg(pkg *types.Package, write bool) { 831 if write { 832 w.pkg(pkg) 833 } 834 835 w.currPkg = pkg 836 } 837 838 func (w *exportWriter) signature(sig *types.Signature) { 839 w.paramList(sig.Params()) 840 w.paramList(sig.Results()) 841 if sig.Params().Len() > 0 { 842 w.bool(sig.Variadic()) 843 } 844 } 845 846 func (w *exportWriter) typeList(ts *typeparams.TypeList, pkg *types.Package) { 847 w.uint64(uint64(ts.Len())) 848 for i := 0; i < ts.Len(); i++ { 849 w.typ(ts.At(i), pkg) 850 } 851 } 852 853 func (w *exportWriter) tparamList(prefix string, list *typeparams.TypeParamList, pkg *types.Package) { 854 ll := uint64(list.Len()) 855 w.uint64(ll) 856 for i := 0; i < list.Len(); i++ { 857 tparam := list.At(i) 858 // Set the type parameter exportName before exporting its type. 859 exportName := tparamExportName(prefix, tparam) 860 w.p.tparamNames[tparam.Obj()] = exportName 861 w.typ(list.At(i), pkg) 862 } 863 } 864 865 const blankMarker = "$" 866 867 // tparamExportName returns the 'exported' name of a type parameter, which 868 // differs from its actual object name: it is prefixed with a qualifier, and 869 // blank type parameter names are disambiguated by their index in the type 870 // parameter list. 871 func tparamExportName(prefix string, tparam *typeparams.TypeParam) string { 872 assert(prefix != "") 873 name := tparam.Obj().Name() 874 if name == "_" { 875 name = blankMarker + strconv.Itoa(tparam.Index()) 876 } 877 return prefix + "." + name 878 } 879 880 // tparamName returns the real name of a type parameter, after stripping its 881 // qualifying prefix and reverting blank-name encoding. See tparamExportName 882 // for details. 883 func tparamName(exportName string) string { 884 // Remove the "path" from the type param name that makes it unique. 885 ix := strings.LastIndex(exportName, ".") 886 if ix < 0 { 887 errorf("malformed type parameter export name %s: missing prefix", exportName) 888 } 889 name := exportName[ix+1:] 890 if strings.HasPrefix(name, blankMarker) { 891 return "_" 892 } 893 return name 894 } 895 896 func (w *exportWriter) paramList(tup *types.Tuple) { 897 n := tup.Len() 898 w.uint64(uint64(n)) 899 for i := 0; i < n; i++ { 900 w.param(tup.At(i)) 901 } 902 } 903 904 func (w *exportWriter) param(obj types.Object) { 905 w.pos(obj.Pos()) 906 w.localIdent(obj) 907 w.typ(obj.Type(), obj.Pkg()) 908 } 909 910 func (w *exportWriter) value(typ types.Type, v constant.Value) { 911 w.typ(typ, nil) 912 if w.p.version >= iexportVersionGo1_18 { 913 w.int64(int64(v.Kind())) 914 } 915 916 switch b := typ.Underlying().(*types.Basic); b.Info() & types.IsConstType { 917 case types.IsBoolean: 918 w.bool(constant.BoolVal(v)) 919 case types.IsInteger: 920 var i big.Int 921 if i64, exact := constant.Int64Val(v); exact { 922 i.SetInt64(i64) 923 } else if ui64, exact := constant.Uint64Val(v); exact { 924 i.SetUint64(ui64) 925 } else { 926 i.SetString(v.ExactString(), 10) 927 } 928 w.mpint(&i, typ) 929 case types.IsFloat: 930 f := constantToFloat(v) 931 w.mpfloat(f, typ) 932 case types.IsComplex: 933 w.mpfloat(constantToFloat(constant.Real(v)), typ) 934 w.mpfloat(constantToFloat(constant.Imag(v)), typ) 935 case types.IsString: 936 w.string(constant.StringVal(v)) 937 default: 938 if b.Kind() == types.Invalid { 939 // package contains type errors 940 break 941 } 942 panic(internalErrorf("unexpected type %v (%v)", typ, typ.Underlying())) 943 } 944 } 945 946 // constantToFloat converts a constant.Value with kind constant.Float to a 947 // big.Float. 948 func constantToFloat(x constant.Value) *big.Float { 949 x = constant.ToFloat(x) 950 // Use the same floating-point precision (512) as cmd/compile 951 // (see Mpprec in cmd/compile/internal/gc/mpfloat.go). 952 const mpprec = 512 953 var f big.Float 954 f.SetPrec(mpprec) 955 if v, exact := constant.Float64Val(x); exact { 956 // float64 957 f.SetFloat64(v) 958 } else if num, denom := constant.Num(x), constant.Denom(x); num.Kind() == constant.Int { 959 // TODO(gri): add big.Rat accessor to constant.Value. 960 n := valueToRat(num) 961 d := valueToRat(denom) 962 f.SetRat(n.Quo(n, d)) 963 } else { 964 // Value too large to represent as a fraction => inaccessible. 965 // TODO(gri): add big.Float accessor to constant.Value. 966 _, ok := f.SetString(x.ExactString()) 967 assert(ok) 968 } 969 return &f 970 } 971 972 // mpint exports a multi-precision integer. 973 // 974 // For unsigned types, small values are written out as a single 975 // byte. Larger values are written out as a length-prefixed big-endian 976 // byte string, where the length prefix is encoded as its complement. 977 // For example, bytes 0, 1, and 2 directly represent the integer 978 // values 0, 1, and 2; while bytes 255, 254, and 253 indicate a 1-, 979 // 2-, and 3-byte big-endian string follow. 980 // 981 // Encoding for signed types use the same general approach as for 982 // unsigned types, except small values use zig-zag encoding and the 983 // bottom bit of length prefix byte for large values is reserved as a 984 // sign bit. 985 // 986 // The exact boundary between small and large encodings varies 987 // according to the maximum number of bytes needed to encode a value 988 // of type typ. As a special case, 8-bit types are always encoded as a 989 // single byte. 990 // 991 // TODO(mdempsky): Is this level of complexity really worthwhile? 992 func (w *exportWriter) mpint(x *big.Int, typ types.Type) { 993 basic, ok := typ.Underlying().(*types.Basic) 994 if !ok { 995 panic(internalErrorf("unexpected type %v (%T)", typ.Underlying(), typ.Underlying())) 996 } 997 998 signed, maxBytes := intSize(basic) 999 1000 negative := x.Sign() < 0 1001 if !signed && negative { 1002 panic(internalErrorf("negative unsigned integer; type %v, value %v", typ, x)) 1003 } 1004 1005 b := x.Bytes() 1006 if len(b) > 0 && b[0] == 0 { 1007 panic(internalErrorf("leading zeros")) 1008 } 1009 if uint(len(b)) > maxBytes { 1010 panic(internalErrorf("bad mpint length: %d > %d (type %v, value %v)", len(b), maxBytes, typ, x)) 1011 } 1012 1013 maxSmall := 256 - maxBytes 1014 if signed { 1015 maxSmall = 256 - 2*maxBytes 1016 } 1017 if maxBytes == 1 { 1018 maxSmall = 256 1019 } 1020 1021 // Check if x can use small value encoding. 1022 if len(b) <= 1 { 1023 var ux uint 1024 if len(b) == 1 { 1025 ux = uint(b[0]) 1026 } 1027 if signed { 1028 ux <<= 1 1029 if negative { 1030 ux-- 1031 } 1032 } 1033 if ux < maxSmall { 1034 w.data.WriteByte(byte(ux)) 1035 return 1036 } 1037 } 1038 1039 n := 256 - uint(len(b)) 1040 if signed { 1041 n = 256 - 2*uint(len(b)) 1042 if negative { 1043 n |= 1 1044 } 1045 } 1046 if n < maxSmall || n >= 256 { 1047 panic(internalErrorf("encoding mistake: %d, %v, %v => %d", len(b), signed, negative, n)) 1048 } 1049 1050 w.data.WriteByte(byte(n)) 1051 w.data.Write(b) 1052 } 1053 1054 // mpfloat exports a multi-precision floating point number. 1055 // 1056 // The number's value is decomposed into mantissa × 2**exponent, where 1057 // mantissa is an integer. The value is written out as mantissa (as a 1058 // multi-precision integer) and then the exponent, except exponent is 1059 // omitted if mantissa is zero. 1060 func (w *exportWriter) mpfloat(f *big.Float, typ types.Type) { 1061 if f.IsInf() { 1062 panic("infinite constant") 1063 } 1064 1065 // Break into f = mant × 2**exp, with 0.5 <= mant < 1. 1066 var mant big.Float 1067 exp := int64(f.MantExp(&mant)) 1068 1069 // Scale so that mant is an integer. 1070 prec := mant.MinPrec() 1071 mant.SetMantExp(&mant, int(prec)) 1072 exp -= int64(prec) 1073 1074 manti, acc := mant.Int(nil) 1075 if acc != big.Exact { 1076 panic(internalErrorf("mantissa scaling failed for %f (%s)", f, acc)) 1077 } 1078 w.mpint(manti, typ) 1079 if manti.Sign() != 0 { 1080 w.int64(exp) 1081 } 1082 } 1083 1084 func (w *exportWriter) bool(b bool) bool { 1085 var x uint64 1086 if b { 1087 x = 1 1088 } 1089 w.uint64(x) 1090 return b 1091 } 1092 1093 func (w *exportWriter) int64(x int64) { w.data.int64(x) } 1094 func (w *exportWriter) uint64(x uint64) { w.data.uint64(x) } 1095 func (w *exportWriter) string(s string) { w.uint64(w.p.stringOff(s)) } 1096 1097 func (w *exportWriter) localIdent(obj types.Object) { 1098 // Anonymous parameters. 1099 if obj == nil { 1100 w.string("") 1101 return 1102 } 1103 1104 name := obj.Name() 1105 if name == "_" { 1106 w.string("_") 1107 return 1108 } 1109 1110 w.string(name) 1111 } 1112 1113 type intWriter struct { 1114 bytes.Buffer 1115 } 1116 1117 func (w *intWriter) int64(x int64) { 1118 var buf [binary.MaxVarintLen64]byte 1119 n := binary.PutVarint(buf[:], x) 1120 w.Write(buf[:n]) 1121 } 1122 1123 func (w *intWriter) uint64(x uint64) { 1124 var buf [binary.MaxVarintLen64]byte 1125 n := binary.PutUvarint(buf[:], x) 1126 w.Write(buf[:n]) 1127 } 1128 1129 func assert(cond bool) { 1130 if !cond { 1131 panic("internal error: assertion failed") 1132 } 1133 } 1134 1135 // The below is copied from go/src/cmd/compile/internal/gc/syntax.go. 1136 1137 // objQueue is a FIFO queue of types.Object. The zero value of objQueue is 1138 // a ready-to-use empty queue. 1139 type objQueue struct { 1140 ring []types.Object 1141 head, tail int 1142 } 1143 1144 // empty returns true if q contains no Nodes. 1145 func (q *objQueue) empty() bool { 1146 return q.head == q.tail 1147 } 1148 1149 // pushTail appends n to the tail of the queue. 1150 func (q *objQueue) pushTail(obj types.Object) { 1151 if len(q.ring) == 0 { 1152 q.ring = make([]types.Object, 16) 1153 } else if q.head+len(q.ring) == q.tail { 1154 // Grow the ring. 1155 nring := make([]types.Object, len(q.ring)*2) 1156 // Copy the old elements. 1157 part := q.ring[q.head%len(q.ring):] 1158 if q.tail-q.head <= len(part) { 1159 part = part[:q.tail-q.head] 1160 copy(nring, part) 1161 } else { 1162 pos := copy(nring, part) 1163 copy(nring[pos:], q.ring[:q.tail%len(q.ring)]) 1164 } 1165 q.ring, q.head, q.tail = nring, 0, q.tail-q.head 1166 } 1167 1168 q.ring[q.tail%len(q.ring)] = obj 1169 q.tail++ 1170 } 1171 1172 // popHead pops a node from the head of the queue. It panics if q is empty. 1173 func (q *objQueue) popHead() types.Object { 1174 if q.empty() { 1175 panic("dequeue empty") 1176 } 1177 obj := q.ring[q.head%len(q.ring)] 1178 q.head++ 1179 return obj 1180 }