-// UNREVIEWED
-
// 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 pkgbits
+// A Code is an enum value that can be encoded into bitstreams.
+//
+// Code types are preferable for enum types, because they allow
+// Decoder to detect desyncs.
type Code interface {
+ // Marker returns the SyncMarker for the Code's dynamic type.
Marker() SyncMarker
+
+ // Value returns the Code's ordinal value.
Value() int
}
+// A CodeVal distinguishes among go/constant.Value encodings.
type CodeVal int
func (c CodeVal) Marker() SyncMarker { return SyncVal }
func (c CodeVal) Value() int { return int(c) }
+// Note: These values are public and cannot be changed without
+// updating the go/types importers.
+
const (
ValBool CodeVal = iota
ValString
ValBigFloat
)
+// A CodeType distinguishes among go/types.Type encodings.
type CodeType int
func (c CodeType) Marker() SyncMarker { return SyncType }
func (c CodeType) Value() int { return int(c) }
+// Note: These values are public and cannot be changed without
+// updating the go/types importers.
+
const (
TypeBasic CodeType = iota
TypeNamed
TypeTypeParam
)
+// A CodeObj distinguishes among go/types.Object encodings.
type CodeObj int
func (c CodeObj) Marker() SyncMarker { return SyncCodeObj }
func (c CodeObj) Value() int { return int(c) }
+// Note: These values are public and cannot be changed without
+// updating the go/types importers.
+
const (
ObjAlias CodeObj = iota
ObjConst
-// UNREVIEWED
-
// 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.
elemEndsEnds [numRelocs]uint32
}
+// PkgPath returns the package path for the package
+//
+// TODO(mdempsky): Remove; unneeded since CL 391014.
func (pr *PkgDecoder) PkgPath() string { return pr.pkgPath }
+// NewPkgDecoder returns a PkgDecoder initialized to read the Unified
+// IR export data from input. pkgPath is the package path for the
+// compilation unit that produced the export data.
+//
+// TODO(mdempsky): Remove pkgPath parameter; unneeded since CL 391014.
func NewPkgDecoder(pkgPath, input string) PkgDecoder {
pr := PkgDecoder{
pkgPath: pkgPath,
return pr.elemData[start:end]
}
+// StringIdx returns the string value for the given string index.
func (pr *PkgDecoder) StringIdx(idx int) string {
return pr.DataIdx(RelocString, idx)
}
+// NewDecoder returns a Decoder for the given (section, index) pair,
+// and decodes the given SyncMarker from the element bitstream.
func (pr *PkgDecoder) NewDecoder(k RelocKind, idx int, marker SyncMarker) Decoder {
r := pr.NewDecoderRaw(k, idx)
r.Sync(marker)
return r
}
+// NewDecoderRaw returns a Decoder for the given (section, index) pair.
+//
+// Most callers should use NewDecoder instead.
func (pr *PkgDecoder) NewDecoderRaw(k RelocKind, idx int) Decoder {
r := Decoder{
common: pr,
return e.Idx
}
+// Sync decodes a sync marker from the element bitstream and asserts
+// that it matches the expected marker.
+//
+// If EnableSync is false, then Sync is a no-op.
func (r *Decoder) Sync(mWant SyncMarker) {
if !EnableSync {
return
os.Exit(1)
}
+// Bool decodes and returns a bool value from the element bitstream.
func (r *Decoder) Bool() bool {
r.Sync(SyncBool)
x, err := r.Data.ReadByte()
return x != 0
}
+// Int64 decodes and returns an int64 value from the element bitstream.
func (r *Decoder) Int64() int64 {
r.Sync(SyncInt64)
return r.rawVarint()
}
+// Int64 decodes and returns a uint64 value from the element bitstream.
func (r *Decoder) Uint64() uint64 {
r.Sync(SyncUint64)
return r.rawUvarint()
}
-func (r *Decoder) Len() int { x := r.Uint64(); v := int(x); assert(uint64(v) == x); return v }
-func (r *Decoder) Int() int { x := r.Int64(); v := int(x); assert(int64(v) == x); return v }
+// Len decodes and returns a non-negative int value from the element bitstream.
+func (r *Decoder) Len() int { x := r.Uint64(); v := int(x); assert(uint64(v) == x); return v }
+
+// Int decodes and returns an int value from the element bitstream.
+func (r *Decoder) Int() int { x := r.Int64(); v := int(x); assert(int64(v) == x); return v }
+
+// Uint decodes and returns a uint value from the element bitstream.
func (r *Decoder) Uint() uint { x := r.Uint64(); v := uint(x); assert(uint64(v) == x); return v }
+// Code decodes a Code value from the element bitstream and returns
+// its ordinal value. It's the caller's responsibility to convert the
+// result to an appropriate Code type.
+//
// TODO(mdempsky): Ideally this method would have signature "Code[T
// Code] T" instead, but we don't allow generic methods and the
// compiler can't depend on generics yet anyway.
return r.Len()
}
+// Reloc decodes a relocation of expected section k from the element
+// bitstream and returns an index to the referenced element.
func (r *Decoder) Reloc(k RelocKind) int {
r.Sync(SyncUseReloc)
return r.rawReloc(k, r.Len())
}
+// String decodes and returns a string value from the element
+// bitstream.
func (r *Decoder) String() string {
r.Sync(SyncString)
return r.common.StringIdx(r.Reloc(RelocString))
}
+// Strings decodes and returns a variable-length slice of strings from
+// the element bitstream.
func (r *Decoder) Strings() []string {
res := make([]string, r.Len())
for i := range res {
return res
}
+// Value decodes and returns a constant.Value from the element
+// bitstream.
func (r *Decoder) Value() constant.Value {
r.Sync(SyncValue)
isComplex := r.Bool()
// TODO(mdempsky): These should probably be removed. I think they're a
// smell that the export data format is not yet quite right.
+// PeekPkgPath returns the package path for the specified package
+// index.
func (pr *PkgDecoder) PeekPkgPath(idx int) string {
r := pr.NewDecoder(RelocPkg, idx, SyncPkgDef)
path := r.String()
return path
}
+// PeekObj returns the package path, object name, and CodeObj for the
+// specified object index.
func (pr *PkgDecoder) PeekObj(idx int) (string, string, CodeObj) {
r := pr.NewDecoder(RelocName, idx, SyncObject1)
r.Sync(SyncSym)
-// UNREVIEWED
-
// 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.
elems [numRelocs][]string
// stringsIdx maps previously encoded strings to their index within
- // the RelocString section, to allow deduplication.
+ // the RelocString section, to allow deduplication. That is,
+ // elems[RelocString][stringsIdx[s]] == s (if present).
stringsIdx map[string]int
syncFrames int
}
+// 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.
func NewPkgEncoder(syncFrames int) PkgEncoder {
return PkgEncoder{
stringsIdx: make(map[string]int),
return
}
+// StringIdx adds a string value to the strings section, if not
+// already present, and returns its index.
func (pw *PkgEncoder) StringIdx(s string) int {
if idx, ok := pw.stringsIdx[s]; ok {
assert(pw.elems[RelocString][idx] == s)
return idx
}
+// 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 (pw *PkgEncoder) NewEncoder(k RelocKind, marker SyncMarker) Encoder {
e := pw.NewEncoderRaw(k)
e.Sync(marker)
return e
}
+// NewEncoderRaw returns an Encoder for a new element within the given
+// section.
+//
+// Most callers should use NewEncoder instead.
func (pw *PkgEncoder) NewEncoderRaw(k RelocKind) Encoder {
idx := len(pw.elems[k])
pw.elems[k] = append(pw.elems[k], "") // placeholder
p *PkgEncoder
Relocs []RelocEnt
- Data bytes.Buffer
+ Data bytes.Buffer // accumulated element bitstream data
encodingRelocHeader bool
k RelocKind
- Idx int
+ Idx int // index within relocation section
}
// Flush finalizes the element's bitstream and returns its Index.
w.encodingRelocHeader = true
w.Sync(SyncRelocs)
w.Len(len(w.Relocs))
- for _, rent := range w.Relocs {
+ for _, rEnt := range w.Relocs {
w.Sync(SyncReloc)
- w.Len(int(rent.Kind))
- w.Len(rent.Idx)
+ w.Len(int(rEnt.Kind))
+ w.Len(rEnt.Idx)
}
io.Copy(&sb, &w.Data)
}
func (w *Encoder) rawReloc(r RelocKind, idx int) int {
- // TODO(mdempsky): Use map for lookup.
- for i, rent := range w.Relocs {
- if rent.Kind == r && rent.Idx == idx {
+ // TODO(mdempsky): Use map for lookup; this takes quadratic time.
+ for i, rEnt := range w.Relocs {
+ if rEnt.Kind == r && rEnt.Idx == idx {
return i
}
}
}
}
+// 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 (w *Encoder) Bool(b bool) bool {
w.Sync(SyncBool)
var x byte
return b
}
+// Int64 encodes and writes an int64 value into the element bitstream.
func (w *Encoder) Int64(x int64) {
w.Sync(SyncInt64)
w.rawVarint(x)
}
+// Uint64 encodes and writes a uint64 value into the element bitstream.
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)) }
+// Len encodes and writes a non-negative int value into the element bitstream.
+func (w *Encoder) Len(x int) { assert(x >= 0); w.Uint64(uint64(x)) }
+
+// Int encodes and writes an int value into the element bitstream.
+func (w *Encoder) Int(x int) { w.Int64(int64(x)) }
+
+// Len encodes and writes a uint value into the element bitstream.
func (w *Encoder) Uint(x uint) { w.Uint64(uint64(x)) }
+// 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 (w *Encoder) Reloc(r RelocKind, idx int) {
w.Sync(SyncUseReloc)
w.Len(w.rawReloc(r, idx))
}
+// Code encodes and writes a Code value into the element bitstream.
func (w *Encoder) Code(c Code) {
w.Sync(c.Marker())
w.Len(c.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 (w *Encoder) String(s string) {
w.Sync(SyncString)
w.Reloc(RelocString, w.p.StringIdx(s))
}
+// Strings encodes and writes a variable-length slice of strings into
+// the element bitstream.
func (w *Encoder) Strings(ss []string) {
w.Len(len(ss))
for _, s := range ss {
}
}
+// Value encodes and writes a constant.Value into the element
+// bitstream.
func (w *Encoder) Value(val constant.Value) {
w.Sync(SyncValue)
if w.Bool(val.Kind() == constant.Complex) {
import "runtime"
+// walkFrames calls visit for each call frame represented by pcs.
+//
+// pcs should be a slice of PCs, as returned by runtime.Callers.
func walkFrames(pcs []uintptr, visit frameVisitor) {
if len(pcs) == 0 {
return
-// UNREVIEWED
-
// 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.
-// UNREVIEWED
-
// 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.
// Public markers (known to go/types importers).
// Low-level coding markers.
-
SyncEOF
SyncBool
SyncInt64