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