1// Copyright 2018 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5// Indexed package export. 6// 7// The indexed export data format is an evolution of the previous 8// binary export data format. Its chief contribution is introducing an 9// index table, which allows efficient random access of individual 10// declarations and inline function bodies. In turn, this allows 11// avoiding unnecessary work for compilation units that import large 12// packages. 13// 14// 15// The top-level data format is structured as: 16// 17// Header struct { 18// Tag byte // 'i' 19// Version uvarint 20// StringSize uvarint 21// DataSize uvarint 22// } 23// 24// Strings [StringSize]byte 25// Data [DataSize]byte 26// 27// MainIndex []struct{ 28// PkgPath stringOff 29// PkgName stringOff 30// PkgHeight uvarint 31// 32// Decls []struct{ 33// Name stringOff 34// Offset declOff 35// } 36// } 37// 38// Fingerprint [8]byte 39// 40// uvarint means a uint64 written out using uvarint encoding. 41// 42// []T means a uvarint followed by that many T objects. In other 43// words: 44// 45// Len uvarint 46// Elems [Len]T 47// 48// stringOff means a uvarint that indicates an offset within the 49// Strings section. At that offset is another uvarint, followed by 50// that many bytes, which form the string value. 51// 52// declOff means a uvarint that indicates an offset within the Data 53// section where the associated declaration can be found. 54// 55// 56// There are five kinds of declarations, distinguished by their first 57// byte: 58// 59// type Var struct { 60// Tag byte // 'V' 61// Pos Pos 62// Type typeOff 63// } 64// 65// type Func struct { 66// Tag byte // 'F' or 'G' 67// Pos Pos 68// TypeParams []typeOff // only present if Tag == 'G' 69// Signature Signature 70// } 71// 72// type Const struct { 73// Tag byte // 'C' 74// Pos Pos 75// Value Value 76// } 77// 78// type Type struct { 79// Tag byte // 'T' or 'U' 80// Pos Pos 81// TypeParams []typeOff // only present if Tag == 'U' 82// Underlying typeOff 83// 84// Methods []struct{ // omitted if Underlying is an interface type 85// Pos Pos 86// Name stringOff 87// Recv Param 88// Signature Signature 89// } 90// } 91// 92// type Alias struct { 93// Tag byte // 'A' 94// Pos Pos 95// Type typeOff 96// } 97// 98// // "Automatic" declaration of each typeparam 99// type TypeParam struct { 100// Tag byte // 'P' 101// Pos Pos 102// Implicit bool 103// Constraint typeOff 104// } 105// 106// typeOff means a uvarint that either indicates a predeclared type, 107// or an offset into the Data section. If the uvarint is less than 108// predeclReserved, then it indicates the index into the predeclared 109// types list (see predeclared in bexport.go for order). Otherwise, 110// subtracting predeclReserved yields the offset of a type descriptor. 111// 112// Value means a type, kind, and type-specific value. See 113// (*exportWriter).value for details. 114// 115// 116// There are twelve kinds of type descriptors, distinguished by an itag: 117// 118// type DefinedType struct { 119// Tag itag // definedType 120// Name stringOff 121// PkgPath stringOff 122// } 123// 124// type PointerType struct { 125// Tag itag // pointerType 126// Elem typeOff 127// } 128// 129// type SliceType struct { 130// Tag itag // sliceType 131// Elem typeOff 132// } 133// 134// type ArrayType struct { 135// Tag itag // arrayType 136// Len uint64 137// Elem typeOff 138// } 139// 140// type ChanType struct { 141// Tag itag // chanType 142// Dir uint64 // 1 RecvOnly; 2 SendOnly; 3 SendRecv 143// Elem typeOff 144// } 145// 146// type MapType struct { 147// Tag itag // mapType 148// Key typeOff 149// Elem typeOff 150// } 151// 152// type FuncType struct { 153// Tag itag // signatureType 154// PkgPath stringOff 155// Signature Signature 156// } 157// 158// type StructType struct { 159// Tag itag // structType 160// PkgPath stringOff 161// Fields []struct { 162// Pos Pos 163// Name stringOff 164// Type typeOff 165// Embedded bool 166// Note stringOff 167// } 168// } 169// 170// type InterfaceType struct { 171// Tag itag // interfaceType 172// PkgPath stringOff 173// Embeddeds []struct { 174// Pos Pos 175// Type typeOff 176// } 177// Methods []struct { 178// Pos Pos 179// Name stringOff 180// Signature Signature 181// } 182// } 183// 184// // Reference to a type param declaration 185// type TypeParamType struct { 186// Tag itag // typeParamType 187// Name stringOff 188// PkgPath stringOff 189// } 190// 191// // Instantiation of a generic type (like List[T2] or List[int]) 192// type InstanceType struct { 193// Tag itag // instanceType 194// Pos pos 195// TypeArgs []typeOff 196// BaseType typeOff 197// } 198// 199// type UnionType struct { 200// Tag itag // interfaceType 201// Terms []struct { 202// tilde bool 203// Type typeOff 204// } 205// } 206// 207// 208// 209// type Signature struct { 210// Params []Param 211// Results []Param 212// Variadic bool // omitted if Results is empty 213// } 214// 215// type Param struct { 216// Pos Pos 217// Name stringOff 218// Type typOff 219// } 220// 221// 222// Pos encodes a file:line:column triple, incorporating a simple delta 223// encoding scheme within a data object. See exportWriter.pos for 224// details. 225// 226// 227// Compiler-specific details. 228// 229// cmd/compile writes out a second index for inline bodies and also 230// appends additional compiler-specific details after declarations. 231// Third-party tools are not expected to depend on these details and 232// they're expected to change much more rapidly, so they're omitted 233// here. See exportWriter's varExt/funcExt/etc methods for details. 234 235package typecheck 236 237import ( 238 "bytes" 239 "crypto/md5" 240 "encoding/binary" 241 "fmt" 242 "go/constant" 243 "io" 244 "math/big" 245 "sort" 246 "strings" 247 248 "cmd/compile/internal/base" 249 "cmd/compile/internal/ir" 250 "cmd/compile/internal/types" 251 "cmd/internal/goobj" 252 "cmd/internal/src" 253) 254 255// Current indexed export format version. Increase with each format change. 256// 0: Go1.11 encoding 257// 1: added column details to Pos 258// 2: added information for generic function/types. The export of non-generic 259// functions/types remains largely backward-compatible. Breaking changes include: 260// - a 'kind' byte is added to constant values 261const ( 262 iexportVersionGo1_11 = 0 263 iexportVersionPosCol = 1 264 iexportVersionGenerics = 2 265 iexportVersionGo1_18 = 2 266 267 iexportVersionCurrent = 2 268) 269 270// predeclReserved is the number of type offsets reserved for types 271// implicitly declared in the universe block. 272const predeclReserved = 32 273 274// An itag distinguishes the kind of type that was written into the 275// indexed export format. 276type itag uint64 277 278const ( 279 // Types 280 definedType itag = iota 281 pointerType 282 sliceType 283 arrayType 284 chanType 285 mapType 286 signatureType 287 structType 288 interfaceType 289 typeParamType 290 instanceType // Instantiation of a generic type 291 unionType 292) 293 294const ( 295 debug = false 296 magic = 0x6742937dc293105 297) 298 299// WriteExports writes the indexed export format to out. If extensions 300// is true, then the compiler-only extensions are included. 301func WriteExports(out io.Writer, extensions bool) { 302 if extensions { 303 // If we're exporting inline bodies, invoke the crawler to mark 304 // which bodies to include. 305 crawlExports(Target.Exports) 306 } 307 308 p := iexporter{ 309 allPkgs: map[*types.Pkg]bool{}, 310 stringIndex: map[string]uint64{}, 311 declIndex: map[*types.Sym]uint64{}, 312 inlineIndex: map[*types.Sym]uint64{}, 313 typIndex: map[*types.Type]uint64{}, 314 extensions: extensions, 315 } 316 317 for i, pt := range predeclared() { 318 p.typIndex[pt] = uint64(i) 319 } 320 if len(p.typIndex) > predeclReserved { 321 base.Fatalf("too many predeclared types: %d > %d", len(p.typIndex), predeclReserved) 322 } 323 324 // Initialize work queue with exported declarations. 325 for _, n := range Target.Exports { 326 p.pushDecl(n) 327 } 328 329 // Loop until no more work. We use a queue because while 330 // writing out inline bodies, we may discover additional 331 // declarations that are needed. 332 for !p.declTodo.Empty() { 333 p.doDecl(p.declTodo.PopLeft()) 334 } 335 336 // Append indices to data0 section. 337 dataLen := uint64(p.data0.Len()) 338 w := p.newWriter() 339 w.writeIndex(p.declIndex, true) 340 w.writeIndex(p.inlineIndex, false) 341 w.flush() 342 343 if *base.Flag.LowerV { 344 fmt.Printf("export: hdr strings %v, data %v, index %v\n", p.strings.Len(), dataLen, p.data0.Len()) 345 } 346 347 // Assemble header. 348 var hdr intWriter 349 hdr.WriteByte('i') 350 hdr.uint64(iexportVersionCurrent) 351 hdr.uint64(uint64(p.strings.Len())) 352 hdr.uint64(dataLen) 353 354 // Flush output. 355 h := md5.New() 356 wr := io.MultiWriter(out, h) 357 io.Copy(wr, &hdr) 358 io.Copy(wr, &p.strings) 359 io.Copy(wr, &p.data0) 360 361 // Add fingerprint (used by linker object file). 362 // Attach this to the end, so tools (e.g. gcimporter) don't care. 363 copy(base.Ctxt.Fingerprint[:], h.Sum(nil)[:]) 364 out.Write(base.Ctxt.Fingerprint[:]) 365} 366 367// writeIndex writes out a symbol index. mainIndex indicates whether 368// we're writing out the main index, which is also read by 369// non-compiler tools and includes a complete package description 370// (i.e., name and height). 371func (w *exportWriter) writeIndex(index map[*types.Sym]uint64, mainIndex bool) { 372 // Build a map from packages to symbols from that package. 373 pkgSyms := map[*types.Pkg][]*types.Sym{} 374 375 // For the main index, make sure to include every package that 376 // we reference, even if we're not exporting (or reexporting) 377 // any symbols from it. 378 if mainIndex { 379 pkgSyms[types.LocalPkg] = nil 380 for pkg := range w.p.allPkgs { 381 pkgSyms[pkg] = nil 382 } 383 } 384 385 // Group symbols by package. 386 for sym := range index { 387 pkgSyms[sym.Pkg] = append(pkgSyms[sym.Pkg], sym) 388 } 389 390 // Sort packages by path. 391 var pkgs []*types.Pkg 392 for pkg := range pkgSyms { 393 pkgs = append(pkgs, pkg) 394 } 395 sort.Slice(pkgs, func(i, j int) bool { 396 return pkgs[i].Path < pkgs[j].Path 397 }) 398 399 w.uint64(uint64(len(pkgs))) 400 for _, pkg := range pkgs { 401 w.string(pkg.Path) 402 if mainIndex { 403 w.string(pkg.Name) 404 w.uint64(uint64(pkg.Height)) 405 } 406 407 // Sort symbols within a package by name. 408 syms := pkgSyms[pkg] 409 sort.Slice(syms, func(i, j int) bool { 410 return syms[i].Name < syms[j].Name 411 }) 412 413 w.uint64(uint64(len(syms))) 414 for _, sym := range syms { 415 w.string(sym.Name) 416 w.uint64(index[sym]) 417 } 418 } 419} 420 421type iexporter struct { 422 // allPkgs tracks all packages that have been referenced by 423 // the export data, so we can ensure to include them in the 424 // main index. 425 allPkgs map[*types.Pkg]bool 426 427 declTodo ir.NameQueue 428 429 strings intWriter 430 stringIndex map[string]uint64 431 432 data0 intWriter 433 declIndex map[*types.Sym]uint64 434 inlineIndex map[*types.Sym]uint64 435 typIndex map[*types.Type]uint64 436 437 extensions bool 438} 439 440// stringOff returns the offset of s within the string section. 441// If not already present, it's added to the end. 442func (p *iexporter) stringOff(s string) uint64 { 443 off, ok := p.stringIndex[s] 444 if !ok { 445 off = uint64(p.strings.Len()) 446 p.stringIndex[s] = off 447 448 if *base.Flag.LowerV { 449 fmt.Printf("export: str %v %.40q\n", off, s) 450 } 451 452 p.strings.uint64(uint64(len(s))) 453 p.strings.WriteString(s) 454 } 455 return off 456} 457 458// pushDecl adds n to the declaration work queue, if not already present. 459func (p *iexporter) pushDecl(n *ir.Name) { 460 if n.Sym() == nil || n.Sym().Def != n && n.Op() != ir.OTYPE { 461 base.Fatalf("weird Sym: %v, %v", n, n.Sym()) 462 } 463 464 // Don't export predeclared declarations. 465 if n.Sym().Pkg == types.BuiltinPkg || n.Sym().Pkg == types.UnsafePkg { 466 return 467 } 468 469 if _, ok := p.declIndex[n.Sym()]; ok { 470 return 471 } 472 473 p.declIndex[n.Sym()] = ^uint64(0) // mark n present in work queue 474 p.declTodo.PushRight(n) 475} 476 477// exportWriter handles writing out individual data section chunks. 478type exportWriter struct { 479 p *iexporter 480 481 data intWriter 482 currPkg *types.Pkg 483 prevFile string 484 prevLine int64 485 prevColumn int64 486 487 // dclIndex maps function-scoped declarations to an int used to refer to 488 // them later in the function. For local variables/params, the int is 489 // non-negative and in order of the appearance in the Func's Dcl list. For 490 // closure variables, the index is negative starting at -2. 491 dclIndex map[*ir.Name]int 492 maxDclIndex int 493 maxClosureVarIndex int 494} 495 496func (p *iexporter) doDecl(n *ir.Name) { 497 w := p.newWriter() 498 w.setPkg(n.Sym().Pkg, false) 499 500 switch n.Op() { 501 case ir.ONAME: 502 switch n.Class { 503 case ir.PEXTERN: 504 // Variable. 505 w.tag('V') 506 w.pos(n.Pos()) 507 w.typ(n.Type()) 508 if w.p.extensions { 509 w.varExt(n) 510 } 511 512 case ir.PFUNC: 513 if ir.IsMethod(n) { 514 base.Fatalf("unexpected method: %v", n) 515 } 516 517 // Function. 518 if n.Type().TParams().NumFields() == 0 { 519 w.tag('F') 520 } else { 521 w.tag('G') 522 } 523 w.pos(n.Pos()) 524 // The tparam list of the function type is the 525 // declaration of the type params. So, write out the type 526 // params right now. Then those type params will be 527 // referenced via their type offset (via typOff) in all 528 // other places in the signature and function that they 529 // are used. 530 if n.Type().TParams().NumFields() > 0 { 531 w.tparamList(n.Type().TParams().FieldSlice()) 532 } 533 w.signature(n.Type()) 534 if w.p.extensions { 535 w.funcExt(n) 536 } 537 538 default: 539 base.Fatalf("unexpected class: %v, %v", n, n.Class) 540 } 541 542 case ir.OLITERAL: 543 // TODO(mdempsky): Extend check to all declarations. 544 if n.Typecheck() == 0 { 545 base.FatalfAt(n.Pos(), "missed typecheck: %v", n) 546 } 547 548 // Constant. 549 w.tag('C') 550 w.pos(n.Pos()) 551 w.value(n.Type(), n.Val()) 552 if w.p.extensions { 553 w.constExt(n) 554 } 555 556 case ir.OTYPE: 557 if n.Type().IsTypeParam() && n.Type().Underlying() == n.Type() { 558 // Even though it has local scope, a typeparam requires a 559 // declaration via its package and unique name, because it 560 // may be referenced within its type bound during its own 561 // definition. 562 w.tag('P') 563 // A typeparam has a name, and has a type bound rather 564 // than an underlying type. 565 w.pos(n.Pos()) 566 if iexportVersionCurrent >= iexportVersionGo1_18 { 567 implicit := n.Type().Bound().IsImplicit() 568 w.bool(implicit) 569 } 570 w.typ(n.Type().Bound()) 571 break 572 } 573 574 if n.Alias() { 575 // Alias. 576 w.tag('A') 577 w.pos(n.Pos()) 578 w.typ(n.Type()) 579 break 580 } 581 582 // Defined type. 583 if len(n.Type().RParams()) == 0 { 584 w.tag('T') 585 } else { 586 w.tag('U') 587 } 588 w.pos(n.Pos()) 589 590 if len(n.Type().RParams()) > 0 { 591 // Export type parameters, if any, needed for this type 592 w.typeList(n.Type().RParams()) 593 } 594 595 underlying := n.Type().Underlying() 596 if underlying == types.ErrorType.Underlying() { 597 // For "type T error", use error as the 598 // underlying type instead of error's own 599 // underlying anonymous interface. This 600 // ensures consistency with how importers may 601 // declare error (e.g., go/types uses nil Pkg 602 // for predeclared objects). 603 underlying = types.ErrorType 604 } 605 if underlying == types.ComparableType.Underlying() { 606 // Do same for ComparableType as for ErrorType. 607 underlying = types.ComparableType 608 } 609 if base.Flag.G > 0 && underlying == types.AnyType.Underlying() { 610 // Do same for AnyType as for ErrorType. 611 underlying = types.AnyType 612 } 613 w.typ(underlying) 614 615 t := n.Type() 616 if t.IsInterface() { 617 if w.p.extensions { 618 w.typeExt(t) 619 } 620 break 621 } 622 623 // Sort methods, for consistency with types2. 624 methods := append([]*types.Field(nil), t.Methods().Slice()...) 625 if base.Debug.UnifiedQuirks != 0 { 626 sort.Sort(types.MethodsByName(methods)) 627 } 628 629 w.uint64(uint64(len(methods))) 630 for _, m := range methods { 631 w.pos(m.Pos) 632 w.selector(m.Sym) 633 w.param(m.Type.Recv()) 634 w.signature(m.Type) 635 } 636 637 if w.p.extensions { 638 w.typeExt(t) 639 for _, m := range methods { 640 w.methExt(m) 641 } 642 } 643 644 default: 645 base.Fatalf("unexpected node: %v", n) 646 } 647 648 w.finish("dcl", p.declIndex, n.Sym()) 649} 650 651func (w *exportWriter) tag(tag byte) { 652 w.data.WriteByte(tag) 653} 654 655func (w *exportWriter) finish(what string, index map[*types.Sym]uint64, sym *types.Sym) { 656 off := w.flush() 657 if *base.Flag.LowerV { 658 fmt.Printf("export: %v %v %v\n", what, off, sym) 659 } 660 index[sym] = off 661} 662 663func (p *iexporter) doInline(f *ir.Name) { 664 w := p.newWriter() 665 w.setPkg(fnpkg(f), false) 666 667 w.dclIndex = make(map[*ir.Name]int, len(f.Func.Inl.Dcl)) 668 w.funcBody(f.Func) 669 670 w.finish("inl", p.inlineIndex, f.Sym()) 671} 672 673func (w *exportWriter) pos(pos src.XPos) { 674 p := base.Ctxt.PosTable.Pos(pos) 675 file := p.Base().AbsFilename() 676 line := int64(p.RelLine()) 677 column := int64(p.RelCol()) 678 679 // Encode position relative to the last position: column 680 // delta, then line delta, then file name. We reserve the 681 // bottom bit of the column and line deltas to encode whether 682 // the remaining fields are present. 683 // 684 // Note: Because data objects may be read out of order (or not 685 // at all), we can only apply delta encoding within a single 686 // object. This is handled implicitly by tracking prevFile, 687 // prevLine, and prevColumn as fields of exportWriter. 688 689 deltaColumn := (column - w.prevColumn) << 1 690 deltaLine := (line - w.prevLine) << 1 691 692 if file != w.prevFile { 693 deltaLine |= 1 694 } 695 if deltaLine != 0 { 696 deltaColumn |= 1 697 } 698 699 w.int64(deltaColumn) 700 if deltaColumn&1 != 0 { 701 w.int64(deltaLine) 702 if deltaLine&1 != 0 { 703 w.string(file) 704 } 705 } 706 707 w.prevFile = file 708 w.prevLine = line 709 w.prevColumn = column 710} 711 712func (w *exportWriter) pkg(pkg *types.Pkg) { 713 // TODO(mdempsky): Add flag to types.Pkg to mark pseudo-packages. 714 if pkg == ir.Pkgs.Go { 715 base.Fatalf("export of pseudo-package: %q", pkg.Path) 716 } 717 718 // Ensure any referenced packages are declared in the main index. 719 w.p.allPkgs[pkg] = true 720 721 w.string(pkg.Path) 722} 723 724func (w *exportWriter) qualifiedIdent(n *ir.Name) { 725 // Ensure any referenced declarations are written out too. 726 w.p.pushDecl(n) 727 728 s := n.Sym() 729 w.string(s.Name) 730 w.pkg(s.Pkg) 731} 732 733func (w *exportWriter) selector(s *types.Sym) { 734 if w.currPkg == nil { 735 base.Fatalf("missing currPkg") 736 } 737 738 // If the selector being written is unexported, it comes with a package qualifier. 739 // If the selector being written is exported, it is not package-qualified. 740 // See the spec: https://golang.org/ref/spec#Uniqueness_of_identifiers 741 // As an optimization, we don't actually write the package every time - instead we 742 // call setPkg before a group of selectors (all of which must have the same package qualifier). 743 pkg := w.currPkg 744 if types.IsExported(s.Name) { 745 pkg = types.LocalPkg 746 } 747 if s.Pkg != pkg { 748 base.Fatalf("package mismatch in selector: %v in package %q, but want %q", s, s.Pkg.Path, pkg.Path) 749 } 750 751 w.string(s.Name) 752} 753 754func (w *exportWriter) typ(t *types.Type) { 755 w.data.uint64(w.p.typOff(t)) 756} 757 758// The "exotic" functions in this section encode a wider range of 759// items than the standard encoding functions above. These include 760// types that do not appear in declarations, only in code, such as 761// method types. These methods need to be separate from the standard 762// encoding functions because we don't want to modify the encoding 763// generated by the standard functions (because that exported 764// information is read by tools besides the compiler). 765 766// exoticType exports a type to the writer. 767func (w *exportWriter) exoticType(t *types.Type) { 768 switch { 769 case t == nil: 770 // Calls-as-statements have no type. 771 w.data.uint64(exoticTypeNil) 772 case t.IsStruct() && t.StructType().Funarg != types.FunargNone: 773 // These are weird structs for representing tuples of types returned 774 // by multi-return functions. 775 // They don't fit the standard struct type mold. For instance, 776 // they don't have any package info. 777 w.data.uint64(exoticTypeTuple) 778 w.uint64(uint64(t.StructType().Funarg)) 779 w.uint64(uint64(t.NumFields())) 780 for _, f := range t.FieldSlice() { 781 w.pos(f.Pos) 782 s := f.Sym 783 if s == nil { 784 w.uint64(0) 785 } else if s.Pkg == nil { 786 w.uint64(exoticTypeSymNoPkg) 787 w.string(s.Name) 788 } else { 789 w.uint64(exoticTypeSymWithPkg) 790 w.pkg(s.Pkg) 791 w.string(s.Name) 792 } 793 w.typ(f.Type) 794 if f.Embedded != 0 || f.Note != "" { 795 panic("extra info in funarg struct field") 796 } 797 } 798 case t.Kind() == types.TFUNC && t.Recv() != nil: 799 w.data.uint64(exoticTypeRecv) 800 // interface method types have a fake receiver type. 801 isFakeRecv := t.Recv().Type == types.FakeRecvType() 802 w.bool(isFakeRecv) 803 if !isFakeRecv { 804 w.exoticParam(t.Recv()) 805 } 806 w.exoticSignature(t) 807 808 default: 809 // A regular type. 810 w.data.uint64(exoticTypeRegular) 811 w.typ(t) 812 } 813} 814 815const ( 816 exoticTypeNil = iota 817 exoticTypeTuple 818 exoticTypeRecv 819 exoticTypeRegular 820) 821const ( 822 exoticTypeSymNil = iota 823 exoticTypeSymNoPkg 824 exoticTypeSymWithPkg 825) 826 827// Export a selector, but one whose package may not match 828// the package being compiled. This is a separate function 829// because the standard selector() serialization format is fixed 830// by the go/types reader. This one can only be used during 831// inline/generic body exporting. 832func (w *exportWriter) exoticSelector(s *types.Sym) { 833 pkg := w.currPkg 834 if types.IsExported(s.Name) { 835 pkg = types.LocalPkg 836 } 837 838 w.string(s.Name) 839 if s.Pkg == pkg { 840 w.uint64(0) 841 } else { 842 w.uint64(1) 843 w.pkg(s.Pkg) 844 } 845} 846 847func (w *exportWriter) exoticSignature(t *types.Type) { 848 hasPkg := t.Pkg() != nil 849 w.bool(hasPkg) 850 if hasPkg { 851 w.pkg(t.Pkg()) 852 } 853 w.exoticParamList(t.Params().FieldSlice()) 854 w.exoticParamList(t.Results().FieldSlice()) 855} 856 857func (w *exportWriter) exoticParamList(fs []*types.Field) { 858 w.uint64(uint64(len(fs))) 859 for _, f := range fs { 860 w.exoticParam(f) 861 } 862 863} 864func (w *exportWriter) exoticParam(f *types.Field) { 865 w.pos(f.Pos) 866 w.exoticSym(f.Sym) 867 w.uint64(uint64(f.Offset)) 868 w.exoticType(f.Type) 869 w.bool(f.IsDDD()) 870} 871 872func (w *exportWriter) exoticField(f *types.Field) { 873 w.pos(f.Pos) 874 w.exoticSym(f.Sym) 875 w.uint64(uint64(f.Offset)) 876 w.exoticType(f.Type) 877 w.string(f.Note) 878} 879 880func (w *exportWriter) exoticSym(s *types.Sym) { 881 if s == nil { 882 w.string("") 883 return 884 } 885 if s.Name == "" { 886 base.Fatalf("empty symbol name") 887 } 888 w.string(s.Name) 889 if !types.IsExported(s.Name) { 890 w.pkg(s.Pkg) 891 } 892} 893 894func (p *iexporter) newWriter() *exportWriter { 895 return &exportWriter{p: p} 896} 897 898func (w *exportWriter) flush() uint64 { 899 off := uint64(w.p.data0.Len()) 900 io.Copy(&w.p.data0, &w.data) 901 return off 902} 903 904func (p *iexporter) typOff(t *types.Type) uint64 { 905 off, ok := p.typIndex[t] 906 if !ok { 907 w := p.newWriter() 908 w.doTyp(t) 909 rawOff := w.flush() 910 if *base.Flag.LowerV { 911 fmt.Printf("export: typ %v %v\n", rawOff, t) 912 } 913 off = predeclReserved + rawOff 914 p.typIndex[t] = off 915 } 916 return off 917} 918 919func (w *exportWriter) startType(k itag) { 920 w.data.uint64(uint64(k)) 921} 922 923func (w *exportWriter) doTyp(t *types.Type) { 924 s := t.Sym() 925 if s != nil && t.OrigSym() != nil { 926 assert(base.Flag.G > 0) 927 // This is an instantiated type - could be a re-instantiation like 928 // Value[T2] or a full instantiation like Value[int]. 929 if strings.Index(s.Name, "[") < 0 { 930 base.Fatalf("incorrect name for instantiated type") 931 } 932 w.startType(instanceType) 933 w.pos(t.Pos()) 934 // Export the type arguments for the instantiated type. The 935 // instantiated type could be in a method header (e.g. "func (v 936 // *Value[T2]) set (...) { ... }"), so the type args are "new" 937 // typeparams. Or the instantiated type could be in a 938 // function/method body, so the type args are either concrete 939 // types or existing typeparams from the function/method header. 940 w.typeList(t.RParams()) 941 // Export a reference to the base type. 942 baseType := t.OrigSym().Def.(*ir.Name).Type() 943 w.typ(baseType) 944 return 945 } 946 947 // The 't.Underlying() == t' check is to confirm this is a base typeparam 948 // type, rather than a defined type with typeparam underlying type, like: 949 // type orderedAbs[T any] T 950 if t.IsTypeParam() && t.Underlying() == t { 951 assert(base.Flag.G > 0) 952 if s.Pkg == types.BuiltinPkg || s.Pkg == types.UnsafePkg { 953 base.Fatalf("builtin type missing from typIndex: %v", t) 954 } 955 // Write out the first use of a type param as a qualified ident. 956 // This will force a "declaration" of the type param. 957 w.startType(typeParamType) 958 w.qualifiedIdent(t.Obj().(*ir.Name)) 959 return 960 } 961 962 if s != nil { 963 if s.Pkg == types.BuiltinPkg || s.Pkg == types.UnsafePkg { 964 base.Fatalf("builtin type missing from typIndex: %v", t) 965 } 966 967 w.startType(definedType) 968 w.qualifiedIdent(t.Obj().(*ir.Name)) 969 return 970 } 971 972 switch t.Kind() { 973 case types.TPTR: 974 w.startType(pointerType) 975 w.typ(t.Elem()) 976 977 case types.TSLICE: 978 w.startType(sliceType) 979 w.typ(t.Elem()) 980 981 case types.TARRAY: 982 w.startType(arrayType) 983 w.uint64(uint64(t.NumElem())) 984 w.typ(t.Elem()) 985 986 case types.TCHAN: 987 w.startType(chanType) 988 w.uint64(uint64(t.ChanDir())) 989 w.typ(t.Elem()) 990 991 case types.TMAP: 992 w.startType(mapType) 993 w.typ(t.Key()) 994 w.typ(t.Elem()) 995 996 case types.TFUNC: 997 w.startType(signatureType) 998 w.setPkg(t.Pkg(), true) 999 w.signature(t) 1000 1001 case types.TSTRUCT: 1002 w.startType(structType) 1003 w.setPkg(t.Pkg(), true) 1004 1005 w.uint64(uint64(t.NumFields())) 1006 for _, f := range t.FieldSlice() { 1007 w.pos(f.Pos) 1008 w.selector(f.Sym) 1009 w.typ(f.Type) 1010 w.bool(f.Embedded != 0) 1011 w.string(f.Note) 1012 } 1013 1014 case types.TINTER: 1015 var embeddeds, methods []*types.Field 1016 for _, m := range t.Methods().Slice() { 1017 if m.Sym != nil { 1018 methods = append(methods, m) 1019 } else { 1020 embeddeds = append(embeddeds, m) 1021 } 1022 } 1023 1024 // Sort methods and embedded types, for consistency with types2. 1025 // Note: embedded types may be anonymous, and types2 sorts them 1026 // with sort.Stable too. 1027 if base.Debug.UnifiedQuirks != 0 { 1028 sort.Sort(types.MethodsByName(methods)) 1029 sort.Stable(types.EmbeddedsByName(embeddeds)) 1030 } 1031 1032 w.startType(interfaceType) 1033 w.setPkg(t.Pkg(), true) 1034 1035 w.uint64(uint64(len(embeddeds))) 1036 for _, f := range embeddeds { 1037 w.pos(f.Pos) 1038 w.typ(f.Type) 1039 } 1040 1041 w.uint64(uint64(len(methods))) 1042 for _, f := range methods { 1043 w.pos(f.Pos) 1044 w.selector(f.Sym) 1045 w.signature(f.Type) 1046 } 1047 1048 case types.TUNION: 1049 assert(base.Flag.G > 0) 1050 // TODO(danscales): possibly put out the tilde bools in more 1051 // compact form. 1052 w.startType(unionType) 1053 nt := t.NumTerms() 1054 w.uint64(uint64(nt)) 1055 for i := 0; i < nt; i++ { 1056 typ, tilde := t.Term(i) 1057 w.bool(tilde) 1058 w.typ(typ) 1059 } 1060 1061 default: 1062 base.Fatalf("unexpected type: %v", t) 1063 } 1064} 1065 1066func (w *exportWriter) setPkg(pkg *types.Pkg, write bool) { 1067 if pkg == types.NoPkg { 1068 base.Fatalf("missing pkg") 1069 } 1070 1071 if write { 1072 w.pkg(pkg) 1073 } 1074 1075 w.currPkg = pkg 1076} 1077 1078func (w *exportWriter) signature(t *types.Type) { 1079 w.paramList(t.Params().FieldSlice()) 1080 w.paramList(t.Results().FieldSlice()) 1081 if n := t.Params().NumFields(); n > 0 { 1082 w.bool(t.Params().Field(n - 1).IsDDD()) 1083 } 1084} 1085 1086func (w *exportWriter) typeList(ts []*types.Type) { 1087 w.uint64(uint64(len(ts))) 1088 for _, rparam := range ts { 1089 w.typ(rparam) 1090 } 1091} 1092 1093func (w *exportWriter) tparamList(fs []*types.Field) { 1094 w.uint64(uint64(len(fs))) 1095 for _, f := range fs { 1096 if !f.Type.IsTypeParam() { 1097 base.Fatalf("unexpected non-typeparam") 1098 } 1099 w.typ(f.Type) 1100 } 1101} 1102 1103func (w *exportWriter) paramList(fs []*types.Field) { 1104 w.uint64(uint64(len(fs))) 1105 for _, f := range fs { 1106 w.param(f) 1107 } 1108} 1109 1110func (w *exportWriter) param(f *types.Field) { 1111 w.pos(f.Pos) 1112 w.localIdent(types.OrigSym(f.Sym)) 1113 w.typ(f.Type) 1114} 1115 1116func constTypeOf(typ *types.Type) constant.Kind { 1117 switch typ { 1118 case types.UntypedInt, types.UntypedRune: 1119 return constant.Int 1120 case types.UntypedFloat: 1121 return constant.Float 1122 case types.UntypedComplex: 1123 return constant.Complex 1124 } 1125 1126 switch typ.Kind() { 1127 case types.TBOOL: 1128 return constant.Bool 1129 case types.TSTRING: 1130 return constant.String 1131 case types.TINT, types.TINT8, types.TINT16, types.TINT32, types.TINT64, 1132 types.TUINT, types.TUINT8, types.TUINT16, types.TUINT32, types.TUINT64, types.TUINTPTR: 1133 return constant.Int 1134 case types.TFLOAT32, types.TFLOAT64: 1135 return constant.Float 1136 case types.TCOMPLEX64, types.TCOMPLEX128: 1137 return constant.Complex 1138 } 1139 1140 base.Fatalf("unexpected constant type: %v", typ) 1141 return 0 1142} 1143 1144func (w *exportWriter) value(typ *types.Type, v constant.Value) { 1145 w.typ(typ) 1146 1147 if iexportVersionCurrent >= iexportVersionGo1_18 { 1148 w.int64(int64(v.Kind())) 1149 } 1150 1151 var kind constant.Kind 1152 var valType *types.Type 1153 1154 if typ.IsTypeParam() { 1155 kind = v.Kind() 1156 if iexportVersionCurrent < iexportVersionGo1_18 { 1157 // A constant will have a TYPEPARAM type if it appears in a place 1158 // where it must match that typeparam type (e.g. in a binary 1159 // operation with a variable of that typeparam type). If so, then 1160 // we must write out its actual constant kind as well, so its 1161 // constant val can be read in properly during import. 1162 w.int64(int64(kind)) 1163 } 1164 1165 switch kind { 1166 case constant.Int: 1167 valType = types.Types[types.TINT64] 1168 case constant.Float: 1169 valType = types.Types[types.TFLOAT64] 1170 case constant.Complex: 1171 valType = types.Types[types.TCOMPLEX128] 1172 } 1173 } else { 1174 ir.AssertValidTypeForConst(typ, v) 1175 kind = constTypeOf(typ) 1176 valType = typ 1177 } 1178 1179 // Each type has only one admissible constant representation, so we could 1180 // type switch directly on v.Kind() here. However, switching on the type 1181 // (in the non-typeparam case) increases symmetry with import logic and 1182 // provides a useful consistency check. 1183 1184 switch kind { 1185 case constant.Bool: 1186 w.bool(constant.BoolVal(v)) 1187 case constant.String: 1188 w.string(constant.StringVal(v)) 1189 case constant.Int: 1190 w.mpint(v, valType) 1191 case constant.Float: 1192 w.mpfloat(v, valType) 1193 case constant.Complex: 1194 w.mpfloat(constant.Real(v), valType) 1195 w.mpfloat(constant.Imag(v), valType) 1196 } 1197} 1198 1199func intSize(typ *types.Type) (signed bool, maxBytes uint) { 1200 if typ.IsUntyped() { 1201 return true, ir.ConstPrec / 8 1202 } 1203 1204 switch typ.Kind() { 1205 case types.TFLOAT32, types.TCOMPLEX64: 1206 return true, 3 1207 case types.TFLOAT64, types.TCOMPLEX128: 1208 return true, 7 1209 } 1210 1211 signed = typ.IsSigned() 1212 maxBytes = uint(typ.Size()) 1213 1214 // The go/types API doesn't expose sizes to importers, so they 1215 // don't know how big these types are. 1216 switch typ.Kind() { 1217 case types.TINT, types.TUINT, types.TUINTPTR: 1218 maxBytes = 8 1219 } 1220 1221 return 1222} 1223 1224// mpint exports a multi-precision integer. 1225// 1226// For unsigned types, small values are written out as a single 1227// byte. Larger values are written out as a length-prefixed big-endian 1228// byte string, where the length prefix is encoded as its complement. 1229// For example, bytes 0, 1, and 2 directly represent the integer 1230// values 0, 1, and 2; while bytes 255, 254, and 253 indicate a 1-, 1231// 2-, and 3-byte big-endian string follow. 1232// 1233// Encoding for signed types use the same general approach as for 1234// unsigned types, except small values use zig-zag encoding and the 1235// bottom bit of length prefix byte for large values is reserved as a 1236// sign bit. 1237// 1238// The exact boundary between small and large encodings varies 1239// according to the maximum number of bytes needed to encode a value 1240// of type typ. As a special case, 8-bit types are always encoded as a 1241// single byte. 1242func (w *exportWriter) mpint(x constant.Value, typ *types.Type) { 1243 signed, maxBytes := intSize(typ) 1244 1245 negative := constant.Sign(x) < 0 1246 if !signed && negative { 1247 base.Fatalf("negative unsigned integer; type %v, value %v", typ, x) 1248 } 1249 1250 b := constant.Bytes(x) // little endian 1251 for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 { 1252 b[i], b[j] = b[j], b[i] 1253 } 1254 1255 if len(b) > 0 && b[0] == 0 { 1256 base.Fatalf("leading zeros") 1257 } 1258 if uint(len(b)) > maxBytes { 1259 base.Fatalf("bad mpint length: %d > %d (type %v, value %v)", len(b), maxBytes, typ, x) 1260 } 1261 1262 maxSmall := 256 - maxBytes 1263 if signed { 1264 maxSmall = 256 - 2*maxBytes 1265 } 1266 if maxBytes == 1 { 1267 maxSmall = 256 1268 } 1269 1270 // Check if x can use small value encoding. 1271 if len(b) <= 1 { 1272 var ux uint 1273 if len(b) == 1 { 1274 ux = uint(b[0]) 1275 } 1276 if signed { 1277 ux <<= 1 1278 if negative { 1279 ux-- 1280 } 1281 } 1282 if ux < maxSmall { 1283 w.data.WriteByte(byte(ux)) 1284 return 1285 } 1286 } 1287 1288 n := 256 - uint(len(b)) 1289 if signed { 1290 n = 256 - 2*uint(len(b)) 1291 if negative { 1292 n |= 1 1293 } 1294 } 1295 if n < maxSmall || n >= 256 { 1296 base.Fatalf("encoding mistake: %d, %v, %v => %d", len(b), signed, negative, n) 1297 } 1298 1299 w.data.WriteByte(byte(n)) 1300 w.data.Write(b) 1301} 1302 1303// mpfloat exports a multi-precision floating point number. 1304// 1305// The number's value is decomposed into mantissa × 2**exponent, where 1306// mantissa is an integer. The value is written out as mantissa (as a 1307// multi-precision integer) and then the exponent, except exponent is 1308// omitted if mantissa is zero. 1309func (w *exportWriter) mpfloat(v constant.Value, typ *types.Type) { 1310 f := ir.BigFloat(v) 1311 if f.IsInf() { 1312 base.Fatalf("infinite constant") 1313 } 1314 1315 // Break into f = mant × 2**exp, with 0.5 <= mant < 1. 1316 var mant big.Float 1317 exp := int64(f.MantExp(&mant)) 1318 1319 // Scale so that mant is an integer. 1320 prec := mant.MinPrec() 1321 mant.SetMantExp(&mant, int(prec)) 1322 exp -= int64(prec) 1323 1324 manti, acc := mant.Int(nil) 1325 if acc != big.Exact { 1326 base.Fatalf("mantissa scaling failed for %f (%s)", f, acc) 1327 } 1328 w.mpint(constant.Make(manti), typ) 1329 if manti.Sign() != 0 { 1330 w.int64(exp) 1331 } 1332} 1333 1334func (w *exportWriter) mprat(v constant.Value) { 1335 r, ok := constant.Val(v).(*big.Rat) 1336 if !w.bool(ok) { 1337 return 1338 } 1339 // TODO(mdempsky): Come up with a more efficient binary 1340 // encoding before bumping iexportVersion to expose to 1341 // gcimporter. 1342 w.string(r.String()) 1343} 1344 1345func (w *exportWriter) bool(b bool) bool { 1346 var x uint64 1347 if b { 1348 x = 1 1349 } 1350 w.uint64(x) 1351 return b 1352} 1353 1354func (w *exportWriter) int64(x int64) { w.data.int64(x) } 1355func (w *exportWriter) uint64(x uint64) { w.data.uint64(x) } 1356func (w *exportWriter) string(s string) { w.uint64(w.p.stringOff(s)) } 1357 1358// Compiler-specific extensions. 1359 1360func (w *exportWriter) constExt(n *ir.Name) { 1361 // Internally, we now represent untyped float and complex 1362 // constants with infinite-precision rational numbers using 1363 // go/constant, but the "public" export data format known to 1364 // gcimporter only supports 512-bit floating point constants. 1365 // In case rationals turn out to be a bad idea and we want to 1366 // switch back to fixed-precision constants, for now we 1367 // continue writing out the 512-bit truncation in the public 1368 // data section, and write the exact, rational constant in the 1369 // compiler's extension data. Also, we only need to worry 1370 // about exporting rationals for declared constants, because 1371 // constants that appear in an expression will already have 1372 // been coerced to a concrete, fixed-precision type. 1373 // 1374 // Eventually, assuming we stick with using rationals, we 1375 // should bump iexportVersion to support rationals, and do the 1376 // whole gcimporter update song-and-dance. 1377 // 1378 // TODO(mdempsky): Prepare vocals for that. 1379 1380 switch n.Type() { 1381 case types.UntypedFloat: 1382 w.mprat(n.Val()) 1383 case types.UntypedComplex: 1384 v := n.Val() 1385 w.mprat(constant.Real(v)) 1386 w.mprat(constant.Imag(v)) 1387 } 1388} 1389 1390func (w *exportWriter) varExt(n *ir.Name) { 1391 w.linkname(n.Sym()) 1392 w.symIdx(n.Sym()) 1393} 1394 1395func (w *exportWriter) funcExt(n *ir.Name) { 1396 w.linkname(n.Sym()) 1397 w.symIdx(n.Sym()) 1398 1399 // Record definition ABI so cross-ABI calls can be direct. 1400 // This is important for the performance of calling some 1401 // common functions implemented in assembly (e.g., bytealg). 1402 w.uint64(uint64(n.Func.ABI)) 1403 1404 w.uint64(uint64(n.Func.Pragma)) 1405 1406 // Escape analysis. 1407 for _, fs := range &types.RecvsParams { 1408 for _, f := range fs(n.Type()).FieldSlice() { 1409 w.string(f.Note) 1410 } 1411 } 1412 1413 // Write out inline body or body of a generic function/method. 1414 if n.Type().HasTParam() && n.Func.Body != nil && n.Func.Inl == nil { 1415 base.FatalfAt(n.Pos(), "generic function is not marked inlineable") 1416 } 1417 if n.Func.Inl != nil { 1418 w.uint64(1 + uint64(n.Func.Inl.Cost)) 1419 w.bool(n.Func.Inl.CanDelayResults) 1420 if n.Func.ExportInline() || n.Type().HasTParam() { 1421 if n.Type().HasTParam() { 1422 // If this generic function/method is from another 1423 // package, but we didn't use for instantiation in 1424 // this package, we may not yet have imported it. 1425 ImportedBody(n.Func) 1426 } 1427 w.p.doInline(n) 1428 } 1429 1430 // Endlineno for inlined function. 1431 w.pos(n.Func.Endlineno) 1432 } else { 1433 w.uint64(0) 1434 } 1435} 1436 1437func (w *exportWriter) methExt(m *types.Field) { 1438 w.bool(m.Nointerface()) 1439 w.funcExt(m.Nname.(*ir.Name)) 1440} 1441 1442func (w *exportWriter) linkname(s *types.Sym) { 1443 w.string(s.Linkname) 1444} 1445 1446func (w *exportWriter) symIdx(s *types.Sym) { 1447 lsym := s.Linksym() 1448 if lsym.PkgIdx > goobj.PkgIdxSelf || (lsym.PkgIdx == goobj.PkgIdxInvalid && !lsym.Indexed()) || s.Linkname != "" { 1449 // Don't export index for non-package symbols, linkname'd symbols, 1450 // and symbols without an index. They can only be referenced by 1451 // name. 1452 w.int64(-1) 1453 } else { 1454 // For a defined symbol, export its index. 1455 // For re-exporting an imported symbol, pass its index through. 1456 w.int64(int64(lsym.SymIdx)) 1457 } 1458} 1459 1460func (w *exportWriter) typeExt(t *types.Type) { 1461 // Export whether this type is marked notinheap. 1462 w.bool(t.NotInHeap()) 1463 // For type T, export the index of type descriptor symbols of T and *T. 1464 if i, ok := typeSymIdx[t]; ok { 1465 w.int64(i[0]) 1466 w.int64(i[1]) 1467 return 1468 } 1469 w.symIdx(types.TypeSym(t)) 1470 w.symIdx(types.TypeSym(t.PtrTo())) 1471} 1472 1473// Inline bodies. 1474 1475func (w *exportWriter) writeNames(dcl []*ir.Name) { 1476 w.int64(int64(len(dcl))) 1477 for i, n := range dcl { 1478 w.pos(n.Pos()) 1479 w.localIdent(n.Sym()) 1480 w.typ(n.Type()) 1481 w.dclIndex[n] = w.maxDclIndex + i 1482 } 1483 w.maxDclIndex += len(dcl) 1484} 1485 1486func (w *exportWriter) funcBody(fn *ir.Func) { 1487 //fmt.Printf("Exporting %s\n", fn.Nname.Sym().Name) 1488 w.writeNames(fn.Inl.Dcl) 1489 1490 w.stmtList(fn.Inl.Body) 1491} 1492 1493func (w *exportWriter) stmtList(list []ir.Node) { 1494 for _, n := range list { 1495 w.node(n) 1496 } 1497 w.op(ir.OEND) 1498} 1499 1500func (w *exportWriter) node(n ir.Node) { 1501 if ir.OpPrec[n.Op()] < 0 { 1502 w.stmt(n) 1503 } else { 1504 w.expr(n) 1505 } 1506} 1507 1508func isNonEmptyAssign(n ir.Node) bool { 1509 switch n.Op() { 1510 case ir.OAS: 1511 if n.(*ir.AssignStmt).Y != nil { 1512 return true 1513 } 1514 case ir.OAS2, ir.OAS2DOTTYPE, ir.OAS2FUNC, ir.OAS2MAPR, ir.OAS2RECV: 1515 return true 1516 } 1517 return false 1518} 1519 1520// Caution: stmt will emit more than one node for statement nodes n that have a 1521// non-empty n.Ninit and where n is not a non-empty assignment or a node with a natural init 1522// section (such as in "if", "for", etc.). 1523func (w *exportWriter) stmt(n ir.Node) { 1524 if len(n.Init()) > 0 && !ir.StmtWithInit(n.Op()) && !isNonEmptyAssign(n) && n.Op() != ir.ORANGE { 1525 // can't use stmtList here since we don't want the final OEND 1526 for _, n := range n.Init() { 1527 w.stmt(n) 1528 } 1529 } 1530 1531 switch n.Op() { 1532 case ir.OBLOCK: 1533 // No OBLOCK in export data. 1534 // Inline content into this statement list, 1535 // like the init list above. 1536 // (At the moment neither the parser nor the typechecker 1537 // generate OBLOCK nodes except to denote an empty 1538 // function body, although that may change.) 1539 n := n.(*ir.BlockStmt) 1540 for _, n := range n.List { 1541 w.stmt(n) 1542 } 1543 1544 case ir.ODCL: 1545 n := n.(*ir.Decl) 1546 if ir.IsBlank(n.X) { 1547 return // blank declarations not useful to importers 1548 } 1549 w.op(ir.ODCL) 1550 w.localName(n.X) 1551 1552 case ir.OAS: 1553 // Don't export "v = <N>" initializing statements, hope they're always 1554 // preceded by the DCL which will be re-parsed and typecheck to reproduce 1555 // the "v = <N>" again. 1556 n := n.(*ir.AssignStmt) 1557 if n.Y != nil { 1558 w.op(ir.OAS) 1559 w.pos(n.Pos()) 1560 w.stmtList(n.Init()) 1561 w.expr(n.X) 1562 w.expr(n.Y) 1563 w.bool(n.Def) 1564 } 1565 1566 case ir.OASOP: 1567 n := n.(*ir.AssignOpStmt) 1568 w.op(ir.OASOP) 1569 w.pos(n.Pos()) 1570 w.op(n.AsOp) 1571 w.expr(n.X) 1572 if w.bool(!n.IncDec) { 1573 w.expr(n.Y) 1574 } 1575 1576 case ir.OAS2, ir.OAS2DOTTYPE, ir.OAS2FUNC, ir.OAS2MAPR, ir.OAS2RECV: 1577 n := n.(*ir.AssignListStmt) 1578 if go117ExportTypes { 1579 w.op(n.Op()) 1580 } else { 1581 w.op(ir.OAS2) 1582 } 1583 w.pos(n.Pos()) 1584 w.stmtList(n.Init()) 1585 w.exprList(n.Lhs) 1586 w.exprList(n.Rhs) 1587 w.bool(n.Def) 1588 1589 case ir.ORETURN: 1590 n := n.(*ir.ReturnStmt) 1591 w.op(ir.ORETURN) 1592 w.pos(n.Pos()) 1593 w.exprList(n.Results) 1594 1595 // case ORETJMP: 1596 // unreachable - generated by compiler for trampoline routines 1597 1598 case ir.OGO, ir.ODEFER: 1599 n := n.(*ir.GoDeferStmt) 1600 w.op(n.Op()) 1601 w.pos(n.Pos()) 1602 w.expr(n.Call) 1603 1604 case ir.OIF: 1605 n := n.(*ir.IfStmt) 1606 w.op(ir.OIF) 1607 w.pos(n.Pos()) 1608 w.stmtList(n.Init()) 1609 w.expr(n.Cond) 1610 w.stmtList(n.Body) 1611 w.stmtList(n.Else) 1612 1613 case ir.OFOR: 1614 n := n.(*ir.ForStmt) 1615 w.op(ir.OFOR) 1616 w.pos(n.Pos()) 1617 w.stmtList(n.Init()) 1618 w.exprsOrNil(n.Cond, n.Post) 1619 w.stmtList(n.Body) 1620 1621 case ir.ORANGE: 1622 n := n.(*ir.RangeStmt) 1623 w.op(ir.ORANGE) 1624 w.pos(n.Pos()) 1625 w.stmtList(n.Init()) 1626 w.exprsOrNil(n.Key, n.Value) 1627 w.expr(n.X) 1628 w.stmtList(n.Body) 1629 1630 case ir.OSELECT: 1631 n := n.(*ir.SelectStmt) 1632 w.op(n.Op()) 1633 w.pos(n.Pos()) 1634 w.stmtList(n.Init()) 1635 w.commList(n.Cases) 1636 1637 case ir.OSWITCH: 1638 n := n.(*ir.SwitchStmt) 1639 w.op(n.Op()) 1640 w.pos(n.Pos()) 1641 w.stmtList(n.Init()) 1642 w.exprsOrNil(n.Tag, nil) 1643 w.caseList(n.Cases, isNamedTypeSwitch(n.Tag)) 1644 1645 // case OCASE: 1646 // handled by caseList 1647 1648 case ir.OFALL: 1649 n := n.(*ir.BranchStmt) 1650 w.op(ir.OFALL) 1651 w.pos(n.Pos()) 1652 1653 case ir.OBREAK, ir.OCONTINUE, ir.OGOTO, ir.OLABEL: 1654 w.op(n.Op()) 1655 w.pos(n.Pos()) 1656 label := "" 1657 if sym := n.Sym(); sym != nil { 1658 label = sym.Name 1659 } 1660 w.string(label) 1661 1662 default: 1663 base.Fatalf("exporter: CANNOT EXPORT: %v\nPlease notify gri@\n", n.Op()) 1664 } 1665} 1666 1667func isNamedTypeSwitch(x ir.Node) bool { 1668 guard, ok := x.(*ir.TypeSwitchGuard) 1669 return ok && guard.Tag != nil 1670} 1671 1672func (w *exportWriter) caseList(cases []*ir.CaseClause, namedTypeSwitch bool) { 1673 w.uint64(uint64(len(cases))) 1674 for _, cas := range cases { 1675 w.pos(cas.Pos()) 1676 w.stmtList(cas.List) 1677 if namedTypeSwitch { 1678 w.localName(cas.Var) 1679 } 1680 w.stmtList(cas.Body) 1681 } 1682} 1683 1684func (w *exportWriter) commList(cases []*ir.CommClause) { 1685 w.uint64(uint64(len(cases))) 1686 for _, cas := range cases { 1687 w.pos(cas.Pos()) 1688 defaultCase := cas.Comm == nil 1689 w.bool(defaultCase) 1690 if !defaultCase { 1691 // Only call w.node for non-default cause (cas.Comm is non-nil) 1692 w.node(cas.Comm) 1693 } 1694 w.stmtList(cas.Body) 1695 } 1696} 1697 1698func (w *exportWriter) exprList(list ir.Nodes) { 1699 for _, n := range list { 1700 w.expr(n) 1701 } 1702 w.op(ir.OEND) 1703} 1704 1705func simplifyForExport(n ir.Node) ir.Node { 1706 switch n.Op() { 1707 case ir.OPAREN: 1708 n := n.(*ir.ParenExpr) 1709 return simplifyForExport(n.X) 1710 } 1711 return n 1712} 1713 1714func (w *exportWriter) expr(n ir.Node) { 1715 n = simplifyForExport(n) 1716 switch n.Op() { 1717 // expressions 1718 // (somewhat closely following the structure of exprfmt in fmt.go) 1719 case ir.ONIL: 1720 n := n.(*ir.NilExpr) 1721 // If n is a typeparam, it will have already been checked 1722 // for proper use by the types2 typechecker. 1723 if !n.Type().IsTypeParam() && !n.Type().HasNil() { 1724 base.Fatalf("unexpected type for nil: %v", n.Type()) 1725 } 1726 w.op(ir.ONIL) 1727 w.pos(n.Pos()) 1728 w.typ(n.Type()) 1729 1730 case ir.OLITERAL: 1731 w.op(ir.OLITERAL) 1732 if ir.HasUniquePos(n) { 1733 w.pos(n.Pos()) 1734 } else { 1735 w.pos(src.NoXPos) 1736 } 1737 w.value(n.Type(), n.Val()) 1738 1739 case ir.ONAME: 1740 // Package scope name. 1741 n := n.(*ir.Name) 1742 if (n.Class == ir.PEXTERN || n.Class == ir.PFUNC) && !ir.IsBlank(n) { 1743 w.op(ir.ONONAME) 1744 // Indicate that this is not an OKEY entry. 1745 w.bool(false) 1746 w.qualifiedIdent(n) 1747 if go117ExportTypes { 1748 w.typ(n.Type()) 1749 } 1750 break 1751 } 1752 1753 // Function scope name. 1754 // We don't need a type here, as the type will be provided at the 1755 // declaration of n. 1756 w.op(ir.ONAME) 1757 1758 // This handles the case where we haven't yet transformed a call 1759 // to a builtin, so we must write out the builtin as a name in the 1760 // builtin package. 1761 isBuiltin := n.BuiltinOp != ir.OXXX 1762 w.bool(isBuiltin) 1763 if isBuiltin { 1764 w.bool(n.Sym().Pkg == types.UnsafePkg) 1765 w.string(n.Sym().Name) 1766 break 1767 } 1768 w.localName(n) 1769 1770 case ir.ONONAME: 1771 w.op(ir.ONONAME) 1772 // This can only be for OKEY nodes in generic functions. Mark it 1773 // as a key entry. 1774 w.bool(true) 1775 s := n.Sym() 1776 w.string(s.Name) 1777 w.pkg(s.Pkg) 1778 if go117ExportTypes { 1779 w.typ(n.Type()) 1780 } 1781 1782 // case OPACK: 1783 // should have been resolved by typechecking - handled by default case 1784 1785 case ir.OTYPE: 1786 w.op(ir.OTYPE) 1787 w.typ(n.Type()) 1788 1789 case ir.ODYNAMICTYPE: 1790 n := n.(*ir.DynamicType) 1791 w.op(ir.ODYNAMICTYPE) 1792 w.pos(n.Pos()) 1793 w.expr(n.X) 1794 if n.ITab != nil { 1795 w.bool(true) 1796 w.expr(n.ITab) 1797 } else { 1798 w.bool(false) 1799 } 1800 w.typ(n.Type()) 1801 1802 case ir.OTYPESW: 1803 n := n.(*ir.TypeSwitchGuard) 1804 w.op(ir.OTYPESW) 1805 w.pos(n.Pos()) 1806 var s *types.Sym 1807 if n.Tag != nil { 1808 if n.Tag.Op() != ir.ONONAME { 1809 base.Fatalf("expected ONONAME, got %v", n.Tag) 1810 } 1811 s = n.Tag.Sym() 1812 } 1813 w.localIdent(s) // declared pseudo-variable, if any 1814 w.expr(n.X) 1815 1816 // case OTARRAY, OTMAP, OTCHAN, OTSTRUCT, OTINTER, OTFUNC: 1817 // should have been resolved by typechecking - handled by default case 1818 1819 case ir.OCLOSURE: 1820 n := n.(*ir.ClosureExpr) 1821 w.op(ir.OCLOSURE) 1822 w.pos(n.Pos()) 1823 w.signature(n.Type()) 1824 1825 // Write out id for the Outer of each conditional variable. The 1826 // conditional variable itself for this closure will be re-created 1827 // during import. 1828 w.int64(int64(len(n.Func.ClosureVars))) 1829 for i, cv := range n.Func.ClosureVars { 1830 w.pos(cv.Pos()) 1831 w.localName(cv.Outer) 1832 // Closure variable (which will be re-created during 1833 // import) is given via a negative id, starting at -2, 1834 // which is used to refer to it later in the function 1835 // during export. -1 represents blanks. 1836 w.dclIndex[cv] = -(i + 2) - w.maxClosureVarIndex 1837 } 1838 w.maxClosureVarIndex += len(n.Func.ClosureVars) 1839 1840 // like w.funcBody(n.Func), but not for .Inl 1841 w.writeNames(n.Func.Dcl) 1842 w.stmtList(n.Func.Body) 1843 1844 // case OCOMPLIT: 1845 // should have been resolved by typechecking - handled by default case 1846 1847 case ir.OPTRLIT: 1848 n := n.(*ir.AddrExpr) 1849 if go117ExportTypes { 1850 w.op(ir.OPTRLIT) 1851 } else { 1852 w.op(ir.OADDR) 1853 } 1854 w.pos(n.Pos()) 1855 w.expr(n.X) 1856 if go117ExportTypes { 1857 w.typ(n.Type()) 1858 } 1859 1860 case ir.OSTRUCTLIT: 1861 n := n.(*ir.CompLitExpr) 1862 w.op(ir.OSTRUCTLIT) 1863 w.pos(n.Pos()) 1864 w.typ(n.Type()) 1865 w.fieldList(n.List) // special handling of field names 1866 1867 case ir.OCOMPLIT, ir.OARRAYLIT, ir.OSLICELIT, ir.OMAPLIT: 1868 n := n.(*ir.CompLitExpr) 1869 if go117ExportTypes { 1870 w.op(n.Op()) 1871 } else { 1872 w.op(ir.OCOMPLIT) 1873 } 1874 w.pos(n.Pos()) 1875 w.typ(n.Type()) 1876 w.exprList(n.List) 1877 if go117ExportTypes && n.Op() == ir.OSLICELIT { 1878 w.uint64(uint64(n.Len)) 1879 } 1880 case ir.OKEY: 1881 n := n.(*ir.KeyExpr) 1882 w.op(ir.OKEY) 1883 w.pos(n.Pos()) 1884 w.expr(n.Key) 1885 w.expr(n.Value) 1886 1887 // case OSTRUCTKEY: 1888 // unreachable - handled in case OSTRUCTLIT by elemList 1889 1890 case ir.OXDOT, ir.ODOT, ir.ODOTPTR, ir.ODOTINTER, ir.ODOTMETH, ir.OMETHVALUE, ir.OMETHEXPR: 1891 n := n.(*ir.SelectorExpr) 1892 if go117ExportTypes { 1893 // For go117ExportTypes, we usually see all ops except 1894 // OXDOT, but we can see OXDOT for generic functions. 1895 w.op(n.Op()) 1896 } else { 1897 w.op(ir.OXDOT) 1898 } 1899 w.pos(n.Pos()) 1900 w.expr(n.X) 1901 w.exoticSelector(n.Sel) 1902 if go117ExportTypes { 1903 w.exoticType(n.Type()) 1904 if n.Op() == ir.OXDOT { 1905 // n.Selection for method references will be 1906 // reconstructed during import. 1907 w.bool(n.Selection != nil) 1908 } else if n.Op() == ir.ODOT || n.Op() == ir.ODOTPTR || n.Op() == ir.ODOTINTER { 1909 w.exoticField(n.Selection) 1910 } 1911 // n.Selection is not required for OMETHEXPR, ODOTMETH, and OMETHVALUE. It will 1912 // be reconstructed during import. n.Selection is computed during 1913 // transformDot() for OXDOT. 1914 } 1915 1916 case ir.ODOTTYPE, ir.ODOTTYPE2: 1917 n := n.(*ir.TypeAssertExpr) 1918 if go117ExportTypes { 1919 w.op(n.Op()) 1920 } else { 1921 w.op(ir.ODOTTYPE) 1922 } 1923 w.pos(n.Pos()) 1924 w.expr(n.X) 1925 w.typ(n.Type()) 1926 1927 case ir.ODYNAMICDOTTYPE, ir.ODYNAMICDOTTYPE2: 1928 n := n.(*ir.DynamicTypeAssertExpr) 1929 w.op(n.Op()) 1930 w.pos(n.Pos()) 1931 w.expr(n.X) 1932 w.expr(n.T) 1933 w.typ(n.Type()) 1934 1935 case ir.OINDEX, ir.OINDEXMAP: 1936 n := n.(*ir.IndexExpr) 1937 if go117ExportTypes { 1938 w.op(n.Op()) 1939 } else { 1940 w.op(ir.OINDEX) 1941 } 1942 w.pos(n.Pos()) 1943 w.expr(n.X) 1944 w.expr(n.Index) 1945 if go117ExportTypes { 1946 w.exoticType(n.Type()) 1947 if n.Op() == ir.OINDEXMAP { 1948 w.bool(n.Assigned) 1949 } 1950 } 1951 1952 case ir.OSLICE, ir.OSLICESTR, ir.OSLICEARR: 1953 n := n.(*ir.SliceExpr) 1954 if go117ExportTypes { 1955 w.op(n.Op()) 1956 } else { 1957 w.op(ir.OSLICE) 1958 } 1959 w.pos(n.Pos()) 1960 w.expr(n.X) 1961 w.exprsOrNil(n.Low, n.High) 1962 if go117ExportTypes { 1963 w.typ(n.Type()) 1964 } 1965 1966 case ir.OSLICE3, ir.OSLICE3ARR: 1967 n := n.(*ir.SliceExpr) 1968 if go117ExportTypes { 1969 w.op(n.Op()) 1970 } else { 1971 w.op(ir.OSLICE3) 1972 } 1973 w.pos(n.Pos()) 1974 w.expr(n.X) 1975 w.exprsOrNil(n.Low, n.High) 1976 w.expr(n.Max) 1977 if go117ExportTypes { 1978 w.typ(n.Type()) 1979 } 1980 1981 case ir.OCOPY, ir.OCOMPLEX, ir.OUNSAFEADD, ir.OUNSAFESLICE: 1982 // treated like other builtin calls (see e.g., OREAL) 1983 n := n.(*ir.BinaryExpr) 1984 w.op(n.Op()) 1985 w.pos(n.Pos()) 1986 w.expr(n.X) 1987 w.expr(n.Y) 1988 if go117ExportTypes { 1989 w.typ(n.Type()) 1990 } else { 1991 w.op(ir.OEND) 1992 } 1993 1994 case ir.OCONV, ir.OCONVIFACE, ir.OCONVIDATA, ir.OCONVNOP, ir.OBYTES2STR, ir.ORUNES2STR, ir.OSTR2BYTES, ir.OSTR2RUNES, ir.ORUNESTR, ir.OSLICE2ARRPTR: 1995 n := n.(*ir.ConvExpr) 1996 if go117ExportTypes { 1997 w.op(n.Op()) 1998 } else { 1999 w.op(ir.OCONV) 2000 } 2001 w.pos(n.Pos()) 2002 w.typ(n.Type()) 2003 w.expr(n.X) 2004 2005 case ir.OREAL, ir.OIMAG, ir.OCAP, ir.OCLOSE, ir.OLEN, ir.ONEW, ir.OPANIC: 2006 n := n.(*ir.UnaryExpr) 2007 w.op(n.Op()) 2008 w.pos(n.Pos()) 2009 w.expr(n.X) 2010 if go117ExportTypes { 2011 if n.Op() != ir.OPANIC { 2012 w.typ(n.Type()) 2013 } 2014 } else { 2015 w.op(ir.OEND) 2016 } 2017 2018 case ir.OAPPEND, ir.ODELETE, ir.ORECOVER, ir.OPRINT, ir.OPRINTN: 2019 n := n.(*ir.CallExpr) 2020 w.op(n.Op()) 2021 w.pos(n.Pos()) 2022 w.exprList(n.Args) // emits terminating OEND 2023 // only append() calls may contain '...' arguments 2024 if n.Op() == ir.OAPPEND { 2025 w.bool(n.IsDDD) 2026 } else if n.IsDDD { 2027 base.Fatalf("exporter: unexpected '...' with %v call", n.Op()) 2028 } 2029 if go117ExportTypes { 2030 if n.Op() != ir.ODELETE && n.Op() != ir.OPRINT && n.Op() != ir.OPRINTN { 2031 w.typ(n.Type()) 2032 } 2033 } 2034 2035 case ir.OCALL, ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER, ir.OGETG: 2036 n := n.(*ir.CallExpr) 2037 if go117ExportTypes { 2038 w.op(n.Op()) 2039 } else { 2040 w.op(ir.OCALL) 2041 } 2042 w.pos(n.Pos()) 2043 w.stmtList(n.Init()) 2044 w.expr(n.X) 2045 w.exprList(n.Args) 2046 w.bool(n.IsDDD) 2047 if go117ExportTypes { 2048 w.exoticType(n.Type()) 2049 } 2050 2051 case ir.OMAKEMAP, ir.OMAKECHAN, ir.OMAKESLICE: 2052 n := n.(*ir.MakeExpr) 2053 w.op(n.Op()) // must keep separate from OMAKE for importer 2054 w.pos(n.Pos()) 2055 w.typ(n.Type()) 2056 switch { 2057 default: 2058 // empty list 2059 w.op(ir.OEND) 2060 case n.Cap != nil: 2061 w.expr(n.Len) 2062 w.expr(n.Cap) 2063 w.op(ir.OEND) 2064 case n.Len != nil && (n.Op() == ir.OMAKESLICE || !n.Len.Type().IsUntyped()): 2065 // Note: the extra conditional exists because make(T) for 2066 // T a map or chan type, gets an untyped zero added as 2067 // an argument. Don't serialize that argument here. 2068 w.expr(n.Len) 2069 w.op(ir.OEND) 2070 case n.Len != nil && go117ExportTypes: 2071 w.expr(n.Len) 2072 w.op(ir.OEND) 2073 } 2074 2075 case ir.OLINKSYMOFFSET: 2076 n := n.(*ir.LinksymOffsetExpr) 2077 w.op(ir.OLINKSYMOFFSET) 2078 w.pos(n.Pos()) 2079 w.string(n.Linksym.Name) 2080 w.uint64(uint64(n.Offset_)) 2081 w.typ(n.Type()) 2082 2083 // unary expressions 2084 case ir.OPLUS, ir.ONEG, ir.OBITNOT, ir.ONOT, ir.ORECV, ir.OIDATA: 2085 n := n.(*ir.UnaryExpr) 2086 w.op(n.Op()) 2087 w.pos(n.Pos()) 2088 w.expr(n.X) 2089 if go117ExportTypes { 2090 w.typ(n.Type()) 2091 } 2092 2093 case ir.OADDR: 2094 n := n.(*ir.AddrExpr) 2095 w.op(n.Op()) 2096 w.pos(n.Pos()) 2097 w.expr(n.X) 2098 if go117ExportTypes { 2099 w.typ(n.Type()) 2100 } 2101 2102 case ir.ODEREF: 2103 n := n.(*ir.StarExpr) 2104 w.op(n.Op()) 2105 w.pos(n.Pos()) 2106 w.expr(n.X) 2107 if go117ExportTypes { 2108 w.typ(n.Type()) 2109 } 2110 2111 case ir.OSEND: 2112 n := n.(*ir.SendStmt) 2113 w.op(n.Op()) 2114 w.pos(n.Pos()) 2115 w.expr(n.Chan) 2116 w.expr(n.Value) 2117 2118 // binary expressions 2119 case ir.OADD, ir.OAND, ir.OANDNOT, ir.ODIV, ir.OEQ, ir.OGE, ir.OGT, ir.OLE, ir.OLT, 2120 ir.OLSH, ir.OMOD, ir.OMUL, ir.ONE, ir.OOR, ir.ORSH, ir.OSUB, ir.OXOR, ir.OEFACE: 2121 n := n.(*ir.BinaryExpr) 2122 w.op(n.Op()) 2123 w.pos(n.Pos()) 2124 w.expr(n.X) 2125 w.expr(n.Y) 2126 if go117ExportTypes { 2127 w.typ(n.Type()) 2128 } 2129 2130 case ir.OANDAND, ir.OOROR: 2131 n := n.(*ir.LogicalExpr) 2132 w.op(n.Op()) 2133 w.pos(n.Pos()) 2134 w.expr(n.X) 2135 w.expr(n.Y) 2136 if go117ExportTypes { 2137 w.typ(n.Type()) 2138 } 2139 2140 case ir.OADDSTR: 2141 n := n.(*ir.AddStringExpr) 2142 w.op(ir.OADDSTR) 2143 w.pos(n.Pos()) 2144 w.exprList(n.List) 2145 if go117ExportTypes { 2146 w.typ(n.Type()) 2147 } 2148 2149 case ir.ODCLCONST: 2150 // if exporting, DCLCONST should just be removed as its usage 2151 // has already been replaced with literals 2152 2153 case ir.OFUNCINST: 2154 n := n.(*ir.InstExpr) 2155 w.op(ir.OFUNCINST) 2156 w.pos(n.Pos()) 2157 w.expr(n.X) 2158 w.uint64(uint64(len(n.Targs))) 2159 for _, targ := range n.Targs { 2160 w.typ(targ.Type()) 2161 } 2162 if go117ExportTypes { 2163 w.typ(n.Type()) 2164 } 2165 2166 case ir.OSELRECV2: 2167 n := n.(*ir.AssignListStmt) 2168 w.op(ir.OSELRECV2) 2169 w.pos(n.Pos()) 2170 w.stmtList(n.Init()) 2171 w.exprList(n.Lhs) 2172 w.exprList(n.Rhs) 2173 w.bool(n.Def) 2174 2175 default: 2176 base.Fatalf("cannot export %v (%d) node\n"+ 2177 "\t==> please file an issue and assign to gri@", n.Op(), int(n.Op())) 2178 } 2179} 2180 2181func (w *exportWriter) op(op ir.Op) { 2182 if debug { 2183 w.uint64(magic) 2184 } 2185 w.uint64(uint64(op)) 2186} 2187 2188func (w *exportWriter) exprsOrNil(a, b ir.Node) { 2189 ab := 0 2190 if a != nil { 2191 ab |= 1 2192 } 2193 if b != nil { 2194 ab |= 2 2195 } 2196 w.uint64(uint64(ab)) 2197 if ab&1 != 0 { 2198 w.expr(a) 2199 } 2200 if ab&2 != 0 { 2201 w.node(b) 2202 } 2203} 2204 2205func (w *exportWriter) fieldList(list ir.Nodes) { 2206 w.uint64(uint64(len(list))) 2207 for _, n := range list { 2208 n := n.(*ir.StructKeyExpr) 2209 w.pos(n.Pos()) 2210 w.exoticField(n.Field) 2211 w.expr(n.Value) 2212 } 2213} 2214 2215func (w *exportWriter) localName(n *ir.Name) { 2216 if ir.IsBlank(n) { 2217 w.int64(-1) 2218 return 2219 } 2220 2221 i, ok := w.dclIndex[n] 2222 if !ok { 2223 base.FatalfAt(n.Pos(), "missing from dclIndex: %+v", n) 2224 } 2225 w.int64(int64(i)) 2226} 2227 2228func (w *exportWriter) localIdent(s *types.Sym) { 2229 if w.currPkg == nil { 2230 base.Fatalf("missing currPkg") 2231 } 2232 2233 // Anonymous parameters. 2234 if s == nil { 2235 w.string("") 2236 return 2237 } 2238 2239 name := s.Name 2240 if name == "_" { 2241 w.string("_") 2242 return 2243 } 2244 2245 // The name of autotmp variables isn't important; they just need to 2246 // be unique. To stabilize the export data, simply write out "$" as 2247 // a marker and let the importer generate its own unique name. 2248 if strings.HasPrefix(name, ".autotmp_") { 2249 w.string("$autotmp") 2250 return 2251 } 2252 2253 if i := strings.LastIndex(name, "."); i >= 0 && !strings.HasPrefix(name, LocalDictName) { 2254 base.Fatalf("unexpected dot in identifier: %v", name) 2255 } 2256 2257 if s.Pkg != w.currPkg { 2258 base.Fatalf("weird package in name: %v => %v from %q, not %q", s, name, s.Pkg.Path, w.currPkg.Path) 2259 } 2260 2261 w.string(name) 2262} 2263 2264type intWriter struct { 2265 bytes.Buffer 2266} 2267 2268func (w *intWriter) int64(x int64) { 2269 var buf [binary.MaxVarintLen64]byte 2270 n := binary.PutVarint(buf[:], x) 2271 w.Write(buf[:n]) 2272} 2273 2274func (w *intWriter) uint64(x uint64) { 2275 var buf [binary.MaxVarintLen64]byte 2276 n := binary.PutUvarint(buf[:], x) 2277 w.Write(buf[:n]) 2278} 2279 2280// If go117ExportTypes is true, then we write type information when 2281// exporting function bodies, so those function bodies don't need to 2282// be re-typechecked on import. 2283// This flag adds some other info to the serialized stream as well 2284// which was previously recomputed during typechecking, like 2285// specializing opcodes (e.g. OXDOT to ODOTPTR) and ancillary 2286// information (e.g. length field for OSLICELIT). 2287const go117ExportTypes = true 2288const Go117ExportTypes = go117ExportTypes 2289 2290// The name used for dictionary parameters or local variables. 2291const LocalDictName = ".dict" 2292