| | |
| | |
| | |
| |
|
| | package pkgbits |
| |
|
| | import ( |
| | "bytes" |
| | "crypto/sha256" |
| | "encoding/binary" |
| | "go/constant" |
| | "io" |
| | "math/big" |
| | "runtime" |
| | "strings" |
| | ) |
| |
|
| | |
| | |
| | type PkgEncoder struct { |
| | |
| | version Version |
| |
|
| | |
| | elems [numRelocs][]string |
| |
|
| | |
| | |
| | |
| | stringsIdx map[string]RelElemIdx |
| |
|
| | |
| | |
| | syncFrames int |
| | } |
| |
|
| | |
| | func (pw *PkgEncoder) SyncMarkers() bool { return pw.syncFrames >= 0 } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | func NewPkgEncoder(version Version, syncFrames int) PkgEncoder { |
| | return PkgEncoder{ |
| | version: version, |
| | stringsIdx: make(map[string]RelElemIdx), |
| | syncFrames: syncFrames, |
| | } |
| | } |
| |
|
| | |
| | |
| | func (pw *PkgEncoder) DumpTo(out0 io.Writer) (fingerprint [8]byte) { |
| | h := sha256.New() |
| | out := io.MultiWriter(out0, h) |
| |
|
| | writeUint32 := func(x uint32) { |
| | assert(binary.Write(out, binary.LittleEndian, x) == nil) |
| | } |
| |
|
| | writeUint32(uint32(pw.version)) |
| |
|
| | if pw.version.Has(Flags) { |
| | var flags uint32 |
| | if pw.SyncMarkers() { |
| | flags |= flagSyncMarkers |
| | } |
| | writeUint32(flags) |
| | } |
| |
|
| | |
| | |
| | var sum uint32 |
| | for _, elems := range &pw.elems { |
| | sum += uint32(len(elems)) |
| | writeUint32(sum) |
| | } |
| |
|
| | |
| | |
| | |
| | sum = 0 |
| | for _, elems := range &pw.elems { |
| | for _, elem := range elems { |
| | sum += uint32(len(elem)) |
| | writeUint32(sum) |
| | } |
| | } |
| |
|
| | |
| | for _, elems := range &pw.elems { |
| | for _, elem := range elems { |
| | _, err := io.WriteString(out, elem) |
| | assert(err == nil) |
| | } |
| | } |
| |
|
| | |
| | copy(fingerprint[:], h.Sum(nil)) |
| | _, err := out0.Write(fingerprint[:]) |
| | assert(err == nil) |
| |
|
| | return |
| | } |
| |
|
| | |
| | |
| | func (pw *PkgEncoder) StringIdx(s string) RelElemIdx { |
| | if idx, ok := pw.stringsIdx[s]; ok { |
| | assert(pw.elems[SectionString][idx] == s) |
| | return idx |
| | } |
| |
|
| | idx := RelElemIdx(len(pw.elems[SectionString])) |
| | pw.elems[SectionString] = append(pw.elems[SectionString], s) |
| | pw.stringsIdx[s] = idx |
| | return idx |
| | } |
| |
|
| | |
| | |
| | |
| | func (pw *PkgEncoder) NewEncoder(k SectionKind, marker SyncMarker) *Encoder { |
| | e := pw.NewEncoderRaw(k) |
| | e.Sync(marker) |
| | return e |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | func (pw *PkgEncoder) NewEncoderRaw(k SectionKind) *Encoder { |
| | idx := RelElemIdx(len(pw.elems[k])) |
| | pw.elems[k] = append(pw.elems[k], "") |
| |
|
| | return &Encoder{ |
| | p: pw, |
| | k: k, |
| | Idx: idx, |
| | } |
| | } |
| |
|
| | |
| | |
| | type Encoder struct { |
| | p *PkgEncoder |
| |
|
| | Relocs []RefTableEntry |
| | RelocMap map[RefTableEntry]uint32 |
| | Data bytes.Buffer |
| |
|
| | encodingRelocHeader bool |
| |
|
| | k SectionKind |
| | Idx RelElemIdx |
| | } |
| |
|
| | |
| | func (w *Encoder) Flush() RelElemIdx { |
| | var sb strings.Builder |
| |
|
| | |
| | var tmp bytes.Buffer |
| | io.Copy(&tmp, &w.Data) |
| |
|
| | |
| | |
| | |
| | if w.encodingRelocHeader { |
| | panic("encodingRelocHeader already true; recursive flush?") |
| | } |
| | w.encodingRelocHeader = true |
| | w.Sync(SyncRelocs) |
| | w.Len(len(w.Relocs)) |
| | for _, rEnt := range w.Relocs { |
| | w.Sync(SyncReloc) |
| | w.Len(int(rEnt.Kind)) |
| | w.Len(int(rEnt.Idx)) |
| | } |
| |
|
| | io.Copy(&sb, &w.Data) |
| | io.Copy(&sb, &tmp) |
| | w.p.elems[w.k][w.Idx] = sb.String() |
| |
|
| | return w.Idx |
| | } |
| |
|
| | func (w *Encoder) checkErr(err error) { |
| | if err != nil { |
| | panicf("unexpected encoding error: %v", err) |
| | } |
| | } |
| |
|
| | func (w *Encoder) rawUvarint(x uint64) { |
| | var buf [binary.MaxVarintLen64]byte |
| | n := binary.PutUvarint(buf[:], x) |
| | _, err := w.Data.Write(buf[:n]) |
| | w.checkErr(err) |
| | } |
| |
|
| | func (w *Encoder) rawVarint(x int64) { |
| | |
| | ux := uint64(x) << 1 |
| | if x < 0 { |
| | ux = ^ux |
| | } |
| |
|
| | w.rawUvarint(ux) |
| | } |
| |
|
| | func (w *Encoder) rawReloc(k SectionKind, idx RelElemIdx) int { |
| | e := RefTableEntry{k, idx} |
| | if w.RelocMap != nil { |
| | if i, ok := w.RelocMap[e]; ok { |
| | return int(i) |
| | } |
| | } else { |
| | w.RelocMap = make(map[RefTableEntry]uint32) |
| | } |
| |
|
| | i := len(w.Relocs) |
| | w.RelocMap[e] = uint32(i) |
| | w.Relocs = append(w.Relocs, e) |
| | return i |
| | } |
| |
|
| | func (w *Encoder) Sync(m SyncMarker) { |
| | if !w.p.SyncMarkers() { |
| | return |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | var frames []string |
| | if !w.encodingRelocHeader && w.p.syncFrames > 0 { |
| | pcs := make([]uintptr, w.p.syncFrames) |
| | n := runtime.Callers(2, pcs) |
| | frames = fmtFrames(pcs[:n]...) |
| | } |
| |
|
| | |
| | |
| | w.rawUvarint(uint64(m)) |
| | w.rawUvarint(uint64(len(frames))) |
| | for _, frame := range frames { |
| | w.rawUvarint(uint64(w.rawReloc(SectionString, w.p.StringIdx(frame)))) |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | func (w *Encoder) Bool(b bool) bool { |
| | w.Sync(SyncBool) |
| | var x byte |
| | if b { |
| | x = 1 |
| | } |
| | err := w.Data.WriteByte(x) |
| | w.checkErr(err) |
| | return b |
| | } |
| |
|
| | |
| | func (w *Encoder) Int64(x int64) { |
| | w.Sync(SyncInt64) |
| | w.rawVarint(x) |
| | } |
| |
|
| | |
| | func (w *Encoder) Uint64(x uint64) { |
| | w.Sync(SyncUint64) |
| | w.rawUvarint(x) |
| | } |
| |
|
| | |
| | func (w *Encoder) Len(x int) { assert(x >= 0); w.Uint64(uint64(x)) } |
| |
|
| | |
| | func (w *Encoder) Int(x int) { w.Int64(int64(x)) } |
| |
|
| | |
| | func (w *Encoder) Uint(x uint) { w.Uint64(uint64(x)) } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | func (w *Encoder) Reloc(k SectionKind, idx RelElemIdx) { |
| | w.Sync(SyncUseReloc) |
| | w.Len(w.rawReloc(k, idx)) |
| | } |
| |
|
| | |
| | func (w *Encoder) Code(c Code) { |
| | w.Sync(c.Marker()) |
| | w.Len(c.Value()) |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | func (w *Encoder) String(s string) { |
| | w.StringRef(w.p.StringIdx(s)) |
| | } |
| |
|
| | |
| | |
| | func (w *Encoder) StringRef(idx RelElemIdx) { |
| | w.Sync(SyncString) |
| | w.Reloc(SectionString, idx) |
| | } |
| |
|
| | |
| | |
| | func (w *Encoder) Strings(ss []string) { |
| | w.Len(len(ss)) |
| | for _, s := range ss { |
| | w.String(s) |
| | } |
| | } |
| |
|
| | |
| | |
| | func (w *Encoder) Value(val constant.Value) { |
| | w.Sync(SyncValue) |
| | if w.Bool(val.Kind() == constant.Complex) { |
| | w.scalar(constant.Real(val)) |
| | w.scalar(constant.Imag(val)) |
| | } else { |
| | w.scalar(val) |
| | } |
| | } |
| |
|
| | func (w *Encoder) scalar(val constant.Value) { |
| | switch v := constant.Val(val).(type) { |
| | default: |
| | panicf("unhandled %v (%v)", val, val.Kind()) |
| | case bool: |
| | w.Code(ValBool) |
| | w.Bool(v) |
| | case string: |
| | w.Code(ValString) |
| | w.String(v) |
| | case int64: |
| | w.Code(ValInt64) |
| | w.Int64(v) |
| | case *big.Int: |
| | w.Code(ValBigInt) |
| | w.bigInt(v) |
| | case *big.Rat: |
| | w.Code(ValBigRat) |
| | w.bigInt(v.Num()) |
| | w.bigInt(v.Denom()) |
| | case *big.Float: |
| | w.Code(ValBigFloat) |
| | w.bigFloat(v) |
| | } |
| | } |
| |
|
| | func (w *Encoder) bigInt(v *big.Int) { |
| | b := v.Bytes() |
| | w.String(string(b)) |
| | w.Bool(v.Sign() < 0) |
| | } |
| |
|
| | func (w *Encoder) bigFloat(v *big.Float) { |
| | b := v.Append(nil, 'p', -1) |
| | w.String(string(b)) |
| | } |
| |
|
| | |
| | func (w *Encoder) Version() Version { return w.p.version } |
| |
|