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