// Copyright 2021 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package pkgbitsimport ()// currentVersion is the current version number.//// - v0: initial prototype//// - v1: adds the flags uint32 word//// TODO(mdempsky): For the next version bump:// - remove the legacy "has init" bool from the public root// - remove obj's "derived func instance" boolconst currentVersion uint32 = 1// A PkgEncoder provides methods for encoding a package's Unified IR// export data.typePkgEncoderstruct {// elems holds the bitstream for previously encoded elements. elems [numRelocs][]string// stringsIdx maps previously encoded strings to their index within // the RelocString section, to allow deduplication. That is, // elems[RelocString][stringsIdx[s]] == s (if present). stringsIdx map[string]Index// syncFrames is the number of frames to write at each sync // marker. A negative value means sync markers are omitted. syncFrames int}// SyncMarkers reports whether pw uses sync markers.func ( *PkgEncoder) () bool { return .syncFrames >= 0 }// NewPkgEncoder returns an initialized PkgEncoder.//// syncFrames is the number of caller frames that should be serialized// at Sync points. Serializing additional frames results in larger// export data files, but can help diagnosing desync errors in// higher-level Unified IR reader/writer code. If syncFrames is// negative, then sync markers are omitted entirely.func ( int) PkgEncoder {returnPkgEncoder{stringsIdx: make(map[string]Index),syncFrames: , }}// DumpTo writes the package's encoded data to out0 and returns the// package fingerprint.func ( *PkgEncoder) ( io.Writer) ( [8]byte) { := md5.New() := io.MultiWriter(, ) := func( uint32) {assert(binary.Write(, binary.LittleEndian, ) == nil) } (currentVersion)varuint32if .SyncMarkers() { |= flagSyncMarkers } ()// Write elemEndsEnds.varuint32for , := range &.elems { += uint32(len()) () }// Write elemEnds. = 0for , := range &.elems {for , := range { += uint32(len()) () } }// Write elemData.for , := range &.elems {for , := range { , := io.WriteString(, )assert( == nil) } }// Write fingerprint.copy([:], .Sum(nil)) , := .Write([:])assert( == nil)return}// StringIdx adds a string value to the strings section, if not// already present, and returns its index.func ( *PkgEncoder) ( string) Index {if , := .stringsIdx[]; {assert(.elems[RelocString][] == )return } := Index(len(.elems[RelocString])) .elems[RelocString] = append(.elems[RelocString], ) .stringsIdx[] = return}// NewEncoder returns an Encoder for a new element within the given// section, and encodes the given SyncMarker as the start of the// element bitstream.func ( *PkgEncoder) ( RelocKind, SyncMarker) Encoder { := .NewEncoderRaw() .Sync()return}// NewEncoderRaw returns an Encoder for a new element within the given// section.//// Most callers should use NewEncoder instead.func ( *PkgEncoder) ( RelocKind) Encoder { := Index(len(.elems[])) .elems[] = append(.elems[], "") // placeholderreturnEncoder{p: ,k: ,Idx: , }}// An Encoder provides methods for encoding an individual element's// bitstream data.typeEncoderstruct { p *PkgEncoder Relocs []RelocEnt RelocMap map[RelocEnt]uint32 Data bytes.Buffer// accumulated element bitstream data encodingRelocHeader bool k RelocKind Idx Index// index within relocation section}// Flush finalizes the element's bitstream and returns its Index.func ( *Encoder) () Index {varstrings.Builder// Backup the data so we write the relocations at the front.varbytes.Bufferio.Copy(&, &.Data)// TODO(mdempsky): Consider writing these out separately so they're // easier to strip, along with function bodies, so that we can prune // down to just the data that's relevant to go/types.if .encodingRelocHeader {panic("encodingRelocHeader already true; recursive flush?") } .encodingRelocHeader = true .Sync(SyncRelocs) .Len(len(.Relocs))for , := range .Relocs { .Sync(SyncReloc) .Len(int(.Kind)) .Len(int(.Idx)) }io.Copy(&, &.Data)io.Copy(&, &) .p.elems[.k][.Idx] = .String()return .Idx}func ( *Encoder) ( error) {if != nil {errorf("unexpected encoding error: %v", ) }}func ( *Encoder) ( uint64) {var [binary.MaxVarintLen64]byte := binary.PutUvarint([:], ) , := .Data.Write([:]) .checkErr()}func ( *Encoder) ( int64) {// Zig-zag encode. := uint64() << 1if < 0 { = ^ } .rawUvarint()}func ( *Encoder) ( RelocKind, Index) int { := RelocEnt{, }if .RelocMap != nil {if , := .RelocMap[]; {returnint() } } else { .RelocMap = make(map[RelocEnt]uint32) } := len(.Relocs) .RelocMap[] = uint32() .Relocs = append(.Relocs, )return}func ( *Encoder) ( SyncMarker) {if !.p.SyncMarkers() {return }// Writing out stack frame string references requires working // relocations, but writing out the relocations themselves involves // sync markers. To prevent infinite recursion, we simply trim the // stack frame for sync markers within the relocation header.var []stringif !.encodingRelocHeader && .p.syncFrames > 0 { := make([]uintptr, .p.syncFrames) := runtime.Callers(2, ) = fmtFrames([:]...) }// TODO(mdempsky): Save space by writing out stack frames as a // linked list so we can share common stack frames. .rawUvarint(uint64()) .rawUvarint(uint64(len()))for , := range { .rawUvarint(uint64(.rawReloc(RelocString, .p.StringIdx()))) }}// Bool encodes and writes a bool value into the element bitstream,// and then returns the bool value.//// For simple, 2-alternative encodings, the idiomatic way to call Bool// is something like://// if w.Bool(x != 0) {// // alternative #1// } else {// // alternative #2// }//// For multi-alternative encodings, use Code instead.func ( *Encoder) ( bool) bool { .Sync(SyncBool)varbyteif { = 1 } := .Data.WriteByte() .checkErr()return}// Int64 encodes and writes an int64 value into the element bitstream.func ( *Encoder) ( int64) { .Sync(SyncInt64) .rawVarint()}// Uint64 encodes and writes a uint64 value into the element bitstream.func ( *Encoder) ( uint64) { .Sync(SyncUint64) .rawUvarint()}// Len encodes and writes a non-negative int value into the element bitstream.func ( *Encoder) ( int) { assert( >= 0); .Uint64(uint64()) }// Int encodes and writes an int value into the element bitstream.func ( *Encoder) ( int) { .Int64(int64()) }// Len encodes and writes a uint value into the element bitstream.func ( *Encoder) ( uint) { .Uint64(uint64()) }// Reloc encodes and writes a relocation for the given (section,// index) pair into the element bitstream.//// Note: Only the index is formally written into the element// bitstream, so bitstream decoders must know from context which// section an encoded relocation refers to.func ( *Encoder) ( RelocKind, Index) { .Sync(SyncUseReloc) .Len(.rawReloc(, ))}// Code encodes and writes a Code value into the element bitstream.func ( *Encoder) ( Code) { .Sync(.Marker()) .Len(.Value())}// String encodes and writes a string value into the element// bitstream.//// Internally, strings are deduplicated by adding them to the strings// section (if not already present), and then writing a relocation// into the element bitstream.func ( *Encoder) ( string) { .StringRef(.p.StringIdx())}// StringRef writes a reference to the given index, which must be a// previously encoded string value.func ( *Encoder) ( Index) { .Sync(SyncString) .Reloc(RelocString, )}// Strings encodes and writes a variable-length slice of strings into// the element bitstream.func ( *Encoder) ( []string) { .Len(len())for , := range { .String() }}// Value encodes and writes a constant.Value into the element// bitstream.func ( *Encoder) ( constant.Value) { .Sync(SyncValue)if .Bool(.Kind() == constant.Complex) { .scalar(constant.Real()) .scalar(constant.Imag()) } else { .scalar() }}func ( *Encoder) ( constant.Value) {switch v := constant.Val().(type) {default:errorf("unhandled %v (%v)", , .Kind())casebool: .Code(ValBool) .Bool()casestring: .Code(ValString) .String()caseint64: .Code(ValInt64) .Int64()case *big.Int: .Code(ValBigInt) .bigInt()case *big.Rat: .Code(ValBigRat) .bigInt(.Num()) .bigInt(.Denom())case *big.Float: .Code(ValBigFloat) .bigFloat() }}func ( *Encoder) ( *big.Int) { := .Bytes() .String(string()) // TODO: More efficient encoding. .Bool(.Sign() < 0)}func ( *Encoder) ( *big.Float) { := .Append(nil, 'p', -1) .String(string()) // TODO: More efficient encoding.}
The pages are generated with Goldsv0.7.0-preview. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.