github.com/jhump/golang-x-tools@v0.0.0-20220218190644-4958d6d39439/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/jhump/golang-x-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 assert(obj.Pkg() != types.Unsafe) 255 256 if _, ok := p.declIndex[obj]; ok { 257 return 258 } 259 260 p.declIndex[obj] = ^uint64(0) // mark obj present in work queue 261 p.declTodo.pushTail(obj) 262 } 263 264 // exportWriter handles writing out individual data section chunks. 265 type exportWriter struct { 266 p *iexporter 267 268 data intWriter 269 currPkg *types.Package 270 prevFile string 271 prevLine int64 272 prevColumn int64 273 } 274 275 func (w *exportWriter) exportPath(pkg *types.Package) string { 276 if pkg == w.p.localpkg { 277 return "" 278 } 279 return pkg.Path() 280 } 281 282 func (p *iexporter) doDecl(obj types.Object) { 283 if trace { 284 p.trace("exporting decl %v (%T)", obj, obj) 285 p.indent++ 286 defer func() { 287 p.indent-- 288 p.trace("=> %s", obj) 289 }() 290 } 291 w := p.newWriter() 292 w.setPkg(obj.Pkg(), false) 293 294 switch obj := obj.(type) { 295 case *types.Var: 296 w.tag('V') 297 w.pos(obj.Pos()) 298 w.typ(obj.Type(), obj.Pkg()) 299 300 case *types.Func: 301 sig, _ := obj.Type().(*types.Signature) 302 if sig.Recv() != nil { 303 panic(internalErrorf("unexpected method: %v", sig)) 304 } 305 306 // Function. 307 if typeparams.ForSignature(sig).Len() == 0 { 308 w.tag('F') 309 } else { 310 w.tag('G') 311 } 312 w.pos(obj.Pos()) 313 // The tparam list of the function type is the declaration of the type 314 // params. So, write out the type params right now. Then those type params 315 // will be referenced via their type offset (via typOff) in all other 316 // places in the signature and function where they are used. 317 // 318 // While importing the type parameters, tparamList computes and records 319 // their export name, so that it can be later used when writing the index. 320 if tparams := typeparams.ForSignature(sig); tparams.Len() > 0 { 321 w.tparamList(obj.Name(), tparams, obj.Pkg()) 322 } 323 w.signature(sig) 324 325 case *types.Const: 326 w.tag('C') 327 w.pos(obj.Pos()) 328 w.value(obj.Type(), obj.Val()) 329 330 case *types.TypeName: 331 t := obj.Type() 332 333 if tparam, ok := t.(*typeparams.TypeParam); ok { 334 w.tag('P') 335 w.pos(obj.Pos()) 336 constraint := tparam.Constraint() 337 if p.version >= iexportVersionGo1_18 { 338 implicit := false 339 if iface, _ := constraint.(*types.Interface); iface != nil { 340 implicit = typeparams.IsImplicit(iface) 341 } 342 w.bool(implicit) 343 } 344 w.typ(constraint, obj.Pkg()) 345 break 346 } 347 348 if obj.IsAlias() { 349 w.tag('A') 350 w.pos(obj.Pos()) 351 w.typ(t, obj.Pkg()) 352 break 353 } 354 355 // Defined type. 356 named, ok := t.(*types.Named) 357 if !ok { 358 panic(internalErrorf("%s is not a defined type", t)) 359 } 360 361 if typeparams.ForNamed(named).Len() == 0 { 362 w.tag('T') 363 } else { 364 w.tag('U') 365 } 366 w.pos(obj.Pos()) 367 368 if typeparams.ForNamed(named).Len() > 0 { 369 // While importing the type parameters, tparamList computes and records 370 // their export name, so that it can be later used when writing the index. 371 w.tparamList(obj.Name(), typeparams.ForNamed(named), obj.Pkg()) 372 } 373 374 underlying := obj.Type().Underlying() 375 w.typ(underlying, obj.Pkg()) 376 377 if types.IsInterface(t) { 378 break 379 } 380 381 n := named.NumMethods() 382 w.uint64(uint64(n)) 383 for i := 0; i < n; i++ { 384 m := named.Method(i) 385 w.pos(m.Pos()) 386 w.string(m.Name()) 387 sig, _ := m.Type().(*types.Signature) 388 389 // Receiver type parameters are type arguments of the receiver type, so 390 // their name must be qualified before exporting recv. 391 if rparams := typeparams.RecvTypeParams(sig); rparams.Len() > 0 { 392 prefix := obj.Name() + "." + m.Name() 393 for i := 0; i < rparams.Len(); i++ { 394 rparam := rparams.At(i) 395 name := tparamExportName(prefix, rparam) 396 w.p.tparamNames[rparam.Obj()] = name 397 } 398 } 399 w.param(sig.Recv()) 400 w.signature(sig) 401 } 402 403 default: 404 panic(internalErrorf("unexpected object: %v", obj)) 405 } 406 407 p.declIndex[obj] = w.flush() 408 } 409 410 func (w *exportWriter) tag(tag byte) { 411 w.data.WriteByte(tag) 412 } 413 414 func (w *exportWriter) pos(pos token.Pos) { 415 if w.p.version >= iexportVersionPosCol { 416 w.posV1(pos) 417 } else { 418 w.posV0(pos) 419 } 420 } 421 422 func (w *exportWriter) posV1(pos token.Pos) { 423 if w.p.fset == nil { 424 w.int64(0) 425 return 426 } 427 428 p := w.p.fset.Position(pos) 429 file := p.Filename 430 line := int64(p.Line) 431 column := int64(p.Column) 432 433 deltaColumn := (column - w.prevColumn) << 1 434 deltaLine := (line - w.prevLine) << 1 435 436 if file != w.prevFile { 437 deltaLine |= 1 438 } 439 if deltaLine != 0 { 440 deltaColumn |= 1 441 } 442 443 w.int64(deltaColumn) 444 if deltaColumn&1 != 0 { 445 w.int64(deltaLine) 446 if deltaLine&1 != 0 { 447 w.string(file) 448 } 449 } 450 451 w.prevFile = file 452 w.prevLine = line 453 w.prevColumn = column 454 } 455 456 func (w *exportWriter) posV0(pos token.Pos) { 457 if w.p.fset == nil { 458 w.int64(0) 459 return 460 } 461 462 p := w.p.fset.Position(pos) 463 file := p.Filename 464 line := int64(p.Line) 465 466 // When file is the same as the last position (common case), 467 // we can save a few bytes by delta encoding just the line 468 // number. 469 // 470 // Note: Because data objects may be read out of order (or not 471 // at all), we can only apply delta encoding within a single 472 // object. This is handled implicitly by tracking prevFile and 473 // prevLine as fields of exportWriter. 474 475 if file == w.prevFile { 476 delta := line - w.prevLine 477 w.int64(delta) 478 if delta == deltaNewFile { 479 w.int64(-1) 480 } 481 } else { 482 w.int64(deltaNewFile) 483 w.int64(line) // line >= 0 484 w.string(file) 485 w.prevFile = file 486 } 487 w.prevLine = line 488 } 489 490 func (w *exportWriter) pkg(pkg *types.Package) { 491 // Ensure any referenced packages are declared in the main index. 492 w.p.allPkgs[pkg] = true 493 494 w.string(w.exportPath(pkg)) 495 } 496 497 func (w *exportWriter) qualifiedIdent(obj types.Object) { 498 name := w.p.exportName(obj) 499 500 // Ensure any referenced declarations are written out too. 501 w.p.pushDecl(obj) 502 w.string(name) 503 w.pkg(obj.Pkg()) 504 } 505 506 func (w *exportWriter) typ(t types.Type, pkg *types.Package) { 507 w.data.uint64(w.p.typOff(t, pkg)) 508 } 509 510 func (p *iexporter) newWriter() *exportWriter { 511 return &exportWriter{p: p} 512 } 513 514 func (w *exportWriter) flush() uint64 { 515 off := uint64(w.p.data0.Len()) 516 io.Copy(&w.p.data0, &w.data) 517 return off 518 } 519 520 func (p *iexporter) typOff(t types.Type, pkg *types.Package) uint64 { 521 off, ok := p.typIndex[t] 522 if !ok { 523 w := p.newWriter() 524 w.doTyp(t, pkg) 525 off = predeclReserved + w.flush() 526 p.typIndex[t] = off 527 } 528 return off 529 } 530 531 func (w *exportWriter) startType(k itag) { 532 w.data.uint64(uint64(k)) 533 } 534 535 func (w *exportWriter) doTyp(t types.Type, pkg *types.Package) { 536 if trace { 537 w.p.trace("exporting type %s (%T)", t, t) 538 w.p.indent++ 539 defer func() { 540 w.p.indent-- 541 w.p.trace("=> %s", t) 542 }() 543 } 544 switch t := t.(type) { 545 case *types.Named: 546 if targs := typeparams.NamedTypeArgs(t); targs.Len() > 0 { 547 w.startType(instanceType) 548 // TODO(rfindley): investigate if this position is correct, and if it 549 // matters. 550 w.pos(t.Obj().Pos()) 551 w.typeList(targs, pkg) 552 w.typ(typeparams.NamedTypeOrigin(t), pkg) 553 return 554 } 555 w.startType(definedType) 556 w.qualifiedIdent(t.Obj()) 557 558 case *typeparams.TypeParam: 559 w.startType(typeParamType) 560 w.qualifiedIdent(t.Obj()) 561 562 case *types.Pointer: 563 w.startType(pointerType) 564 w.typ(t.Elem(), pkg) 565 566 case *types.Slice: 567 w.startType(sliceType) 568 w.typ(t.Elem(), pkg) 569 570 case *types.Array: 571 w.startType(arrayType) 572 w.uint64(uint64(t.Len())) 573 w.typ(t.Elem(), pkg) 574 575 case *types.Chan: 576 w.startType(chanType) 577 // 1 RecvOnly; 2 SendOnly; 3 SendRecv 578 var dir uint64 579 switch t.Dir() { 580 case types.RecvOnly: 581 dir = 1 582 case types.SendOnly: 583 dir = 2 584 case types.SendRecv: 585 dir = 3 586 } 587 w.uint64(dir) 588 w.typ(t.Elem(), pkg) 589 590 case *types.Map: 591 w.startType(mapType) 592 w.typ(t.Key(), pkg) 593 w.typ(t.Elem(), pkg) 594 595 case *types.Signature: 596 w.startType(signatureType) 597 w.setPkg(pkg, true) 598 w.signature(t) 599 600 case *types.Struct: 601 w.startType(structType) 602 w.setPkg(pkg, true) 603 604 n := t.NumFields() 605 w.uint64(uint64(n)) 606 for i := 0; i < n; i++ { 607 f := t.Field(i) 608 w.pos(f.Pos()) 609 w.string(f.Name()) 610 w.typ(f.Type(), pkg) 611 w.bool(f.Anonymous()) 612 w.string(t.Tag(i)) // note (or tag) 613 } 614 615 case *types.Interface: 616 w.startType(interfaceType) 617 w.setPkg(pkg, true) 618 619 n := t.NumEmbeddeds() 620 w.uint64(uint64(n)) 621 for i := 0; i < n; i++ { 622 ft := t.EmbeddedType(i) 623 tPkg := pkg 624 if named, _ := ft.(*types.Named); named != nil { 625 w.pos(named.Obj().Pos()) 626 } else { 627 w.pos(token.NoPos) 628 } 629 w.typ(ft, tPkg) 630 } 631 632 n = t.NumExplicitMethods() 633 w.uint64(uint64(n)) 634 for i := 0; i < n; i++ { 635 m := t.ExplicitMethod(i) 636 w.pos(m.Pos()) 637 w.string(m.Name()) 638 sig, _ := m.Type().(*types.Signature) 639 w.signature(sig) 640 } 641 642 case *typeparams.Union: 643 w.startType(unionType) 644 nt := t.Len() 645 w.uint64(uint64(nt)) 646 for i := 0; i < nt; i++ { 647 term := t.Term(i) 648 w.bool(term.Tilde()) 649 w.typ(term.Type(), pkg) 650 } 651 652 default: 653 panic(internalErrorf("unexpected type: %v, %v", t, reflect.TypeOf(t))) 654 } 655 } 656 657 func (w *exportWriter) setPkg(pkg *types.Package, write bool) { 658 if write { 659 w.pkg(pkg) 660 } 661 662 w.currPkg = pkg 663 } 664 665 func (w *exportWriter) signature(sig *types.Signature) { 666 w.paramList(sig.Params()) 667 w.paramList(sig.Results()) 668 if sig.Params().Len() > 0 { 669 w.bool(sig.Variadic()) 670 } 671 } 672 673 func (w *exportWriter) typeList(ts *typeparams.TypeList, pkg *types.Package) { 674 w.uint64(uint64(ts.Len())) 675 for i := 0; i < ts.Len(); i++ { 676 w.typ(ts.At(i), pkg) 677 } 678 } 679 680 func (w *exportWriter) tparamList(prefix string, list *typeparams.TypeParamList, pkg *types.Package) { 681 ll := uint64(list.Len()) 682 w.uint64(ll) 683 for i := 0; i < list.Len(); i++ { 684 tparam := list.At(i) 685 // Set the type parameter exportName before exporting its type. 686 exportName := tparamExportName(prefix, tparam) 687 w.p.tparamNames[tparam.Obj()] = exportName 688 w.typ(list.At(i), pkg) 689 } 690 } 691 692 const blankMarker = "$" 693 694 // tparamExportName returns the 'exported' name of a type parameter, which 695 // differs from its actual object name: it is prefixed with a qualifier, and 696 // blank type parameter names are disambiguated by their index in the type 697 // parameter list. 698 func tparamExportName(prefix string, tparam *typeparams.TypeParam) string { 699 assert(prefix != "") 700 name := tparam.Obj().Name() 701 if name == "_" { 702 name = blankMarker + strconv.Itoa(tparam.Index()) 703 } 704 return prefix + "." + name 705 } 706 707 // tparamName returns the real name of a type parameter, after stripping its 708 // qualifying prefix and reverting blank-name encoding. See tparamExportName 709 // for details. 710 func tparamName(exportName string) string { 711 // Remove the "path" from the type param name that makes it unique. 712 ix := strings.LastIndex(exportName, ".") 713 if ix < 0 { 714 errorf("malformed type parameter export name %s: missing prefix", exportName) 715 } 716 name := exportName[ix+1:] 717 if strings.HasPrefix(name, blankMarker) { 718 return "_" 719 } 720 return name 721 } 722 723 func (w *exportWriter) paramList(tup *types.Tuple) { 724 n := tup.Len() 725 w.uint64(uint64(n)) 726 for i := 0; i < n; i++ { 727 w.param(tup.At(i)) 728 } 729 } 730 731 func (w *exportWriter) param(obj types.Object) { 732 w.pos(obj.Pos()) 733 w.localIdent(obj) 734 w.typ(obj.Type(), obj.Pkg()) 735 } 736 737 func (w *exportWriter) value(typ types.Type, v constant.Value) { 738 w.typ(typ, nil) 739 if w.p.version >= iexportVersionGo1_18 { 740 w.int64(int64(v.Kind())) 741 } 742 743 switch b := typ.Underlying().(*types.Basic); b.Info() & types.IsConstType { 744 case types.IsBoolean: 745 w.bool(constant.BoolVal(v)) 746 case types.IsInteger: 747 var i big.Int 748 if i64, exact := constant.Int64Val(v); exact { 749 i.SetInt64(i64) 750 } else if ui64, exact := constant.Uint64Val(v); exact { 751 i.SetUint64(ui64) 752 } else { 753 i.SetString(v.ExactString(), 10) 754 } 755 w.mpint(&i, typ) 756 case types.IsFloat: 757 f := constantToFloat(v) 758 w.mpfloat(f, typ) 759 case types.IsComplex: 760 w.mpfloat(constantToFloat(constant.Real(v)), typ) 761 w.mpfloat(constantToFloat(constant.Imag(v)), typ) 762 case types.IsString: 763 w.string(constant.StringVal(v)) 764 default: 765 if b.Kind() == types.Invalid { 766 // package contains type errors 767 break 768 } 769 panic(internalErrorf("unexpected type %v (%v)", typ, typ.Underlying())) 770 } 771 } 772 773 // constantToFloat converts a constant.Value with kind constant.Float to a 774 // big.Float. 775 func constantToFloat(x constant.Value) *big.Float { 776 x = constant.ToFloat(x) 777 // Use the same floating-point precision (512) as cmd/compile 778 // (see Mpprec in cmd/compile/internal/gc/mpfloat.go). 779 const mpprec = 512 780 var f big.Float 781 f.SetPrec(mpprec) 782 if v, exact := constant.Float64Val(x); exact { 783 // float64 784 f.SetFloat64(v) 785 } else if num, denom := constant.Num(x), constant.Denom(x); num.Kind() == constant.Int { 786 // TODO(gri): add big.Rat accessor to constant.Value. 787 n := valueToRat(num) 788 d := valueToRat(denom) 789 f.SetRat(n.Quo(n, d)) 790 } else { 791 // Value too large to represent as a fraction => inaccessible. 792 // TODO(gri): add big.Float accessor to constant.Value. 793 _, ok := f.SetString(x.ExactString()) 794 assert(ok) 795 } 796 return &f 797 } 798 799 // mpint exports a multi-precision integer. 800 // 801 // For unsigned types, small values are written out as a single 802 // byte. Larger values are written out as a length-prefixed big-endian 803 // byte string, where the length prefix is encoded as its complement. 804 // For example, bytes 0, 1, and 2 directly represent the integer 805 // values 0, 1, and 2; while bytes 255, 254, and 253 indicate a 1-, 806 // 2-, and 3-byte big-endian string follow. 807 // 808 // Encoding for signed types use the same general approach as for 809 // unsigned types, except small values use zig-zag encoding and the 810 // bottom bit of length prefix byte for large values is reserved as a 811 // sign bit. 812 // 813 // The exact boundary between small and large encodings varies 814 // according to the maximum number of bytes needed to encode a value 815 // of type typ. As a special case, 8-bit types are always encoded as a 816 // single byte. 817 // 818 // TODO(mdempsky): Is this level of complexity really worthwhile? 819 func (w *exportWriter) mpint(x *big.Int, typ types.Type) { 820 basic, ok := typ.Underlying().(*types.Basic) 821 if !ok { 822 panic(internalErrorf("unexpected type %v (%T)", typ.Underlying(), typ.Underlying())) 823 } 824 825 signed, maxBytes := intSize(basic) 826 827 negative := x.Sign() < 0 828 if !signed && negative { 829 panic(internalErrorf("negative unsigned integer; type %v, value %v", typ, x)) 830 } 831 832 b := x.Bytes() 833 if len(b) > 0 && b[0] == 0 { 834 panic(internalErrorf("leading zeros")) 835 } 836 if uint(len(b)) > maxBytes { 837 panic(internalErrorf("bad mpint length: %d > %d (type %v, value %v)", len(b), maxBytes, typ, x)) 838 } 839 840 maxSmall := 256 - maxBytes 841 if signed { 842 maxSmall = 256 - 2*maxBytes 843 } 844 if maxBytes == 1 { 845 maxSmall = 256 846 } 847 848 // Check if x can use small value encoding. 849 if len(b) <= 1 { 850 var ux uint 851 if len(b) == 1 { 852 ux = uint(b[0]) 853 } 854 if signed { 855 ux <<= 1 856 if negative { 857 ux-- 858 } 859 } 860 if ux < maxSmall { 861 w.data.WriteByte(byte(ux)) 862 return 863 } 864 } 865 866 n := 256 - uint(len(b)) 867 if signed { 868 n = 256 - 2*uint(len(b)) 869 if negative { 870 n |= 1 871 } 872 } 873 if n < maxSmall || n >= 256 { 874 panic(internalErrorf("encoding mistake: %d, %v, %v => %d", len(b), signed, negative, n)) 875 } 876 877 w.data.WriteByte(byte(n)) 878 w.data.Write(b) 879 } 880 881 // mpfloat exports a multi-precision floating point number. 882 // 883 // The number's value is decomposed into mantissa × 2**exponent, where 884 // mantissa is an integer. The value is written out as mantissa (as a 885 // multi-precision integer) and then the exponent, except exponent is 886 // omitted if mantissa is zero. 887 func (w *exportWriter) mpfloat(f *big.Float, typ types.Type) { 888 if f.IsInf() { 889 panic("infinite constant") 890 } 891 892 // Break into f = mant × 2**exp, with 0.5 <= mant < 1. 893 var mant big.Float 894 exp := int64(f.MantExp(&mant)) 895 896 // Scale so that mant is an integer. 897 prec := mant.MinPrec() 898 mant.SetMantExp(&mant, int(prec)) 899 exp -= int64(prec) 900 901 manti, acc := mant.Int(nil) 902 if acc != big.Exact { 903 panic(internalErrorf("mantissa scaling failed for %f (%s)", f, acc)) 904 } 905 w.mpint(manti, typ) 906 if manti.Sign() != 0 { 907 w.int64(exp) 908 } 909 } 910 911 func (w *exportWriter) bool(b bool) bool { 912 var x uint64 913 if b { 914 x = 1 915 } 916 w.uint64(x) 917 return b 918 } 919 920 func (w *exportWriter) int64(x int64) { w.data.int64(x) } 921 func (w *exportWriter) uint64(x uint64) { w.data.uint64(x) } 922 func (w *exportWriter) string(s string) { w.uint64(w.p.stringOff(s)) } 923 924 func (w *exportWriter) localIdent(obj types.Object) { 925 // Anonymous parameters. 926 if obj == nil { 927 w.string("") 928 return 929 } 930 931 name := obj.Name() 932 if name == "_" { 933 w.string("_") 934 return 935 } 936 937 w.string(name) 938 } 939 940 type intWriter struct { 941 bytes.Buffer 942 } 943 944 func (w *intWriter) int64(x int64) { 945 var buf [binary.MaxVarintLen64]byte 946 n := binary.PutVarint(buf[:], x) 947 w.Write(buf[:n]) 948 } 949 950 func (w *intWriter) uint64(x uint64) { 951 var buf [binary.MaxVarintLen64]byte 952 n := binary.PutUvarint(buf[:], x) 953 w.Write(buf[:n]) 954 } 955 956 func assert(cond bool) { 957 if !cond { 958 panic("internal error: assertion failed") 959 } 960 } 961 962 // The below is copied from go/src/cmd/compile/internal/gc/syntax.go. 963 964 // objQueue is a FIFO queue of types.Object. The zero value of objQueue is 965 // a ready-to-use empty queue. 966 type objQueue struct { 967 ring []types.Object 968 head, tail int 969 } 970 971 // empty returns true if q contains no Nodes. 972 func (q *objQueue) empty() bool { 973 return q.head == q.tail 974 } 975 976 // pushTail appends n to the tail of the queue. 977 func (q *objQueue) pushTail(obj types.Object) { 978 if len(q.ring) == 0 { 979 q.ring = make([]types.Object, 16) 980 } else if q.head+len(q.ring) == q.tail { 981 // Grow the ring. 982 nring := make([]types.Object, len(q.ring)*2) 983 // Copy the old elements. 984 part := q.ring[q.head%len(q.ring):] 985 if q.tail-q.head <= len(part) { 986 part = part[:q.tail-q.head] 987 copy(nring, part) 988 } else { 989 pos := copy(nring, part) 990 copy(nring[pos:], q.ring[:q.tail%len(q.ring)]) 991 } 992 q.ring, q.head, q.tail = nring, 0, q.tail-q.head 993 } 994 995 q.ring[q.tail%len(q.ring)] = obj 996 q.tail++ 997 } 998 999 // popHead pops a node from the head of the queue. It panics if q is empty. 1000 func (q *objQueue) popHead() types.Object { 1001 if q.empty() { 1002 panic("dequeue empty") 1003 } 1004 obj := q.ring[q.head%len(q.ring)] 1005 q.head++ 1006 return obj 1007 }