aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/noder/decoder.go
diff options
context:
space:
mode:
authorMatthew Dempsky <mdempsky@google.com>2021-06-17 01:12:23 -0700
committerMatthew Dempsky <mdempsky@google.com>2021-06-18 06:33:12 +0000
commit54fe57bc22f7890810bbddae2499eda8d4acfaef (patch)
tree0c6feea28f614e9fc0eb06bbec30eb70f7b48cce /src/cmd/compile/internal/noder/decoder.go
parent78aa251ace316dc8175879f1ec50797f505cec99 (diff)
downloadgo-54fe57bc22f7890810bbddae2499eda8d4acfaef.tar.xz
[dev.typeparams] cmd/compile: record writer's stack at export data sync points
This CL extends the unified export data format's existing sync mechanism to save writer stacks, controlled by the -d=syncframes debug flag. This allows readers to provide more details when reporting desync errors, which should simplify development of the data format and the various reader/writer implementations. For example, CL 328051 updated reader and writer, but missed making a similar change to the linker (fix in CL 328054). Re-reviewing the CL in isolation after the failure, it was not immediately obvious what was going wrong. But the pair of stack traces below identifies exactly what happened: it should have updated linker.relocFuncExt to write out the new sync marker too. ``` data sync error: package "internal/abi", section 6, index 4, offset 536 found UseReloc, written at: /home/mdempsky/wd/go/src/cmd/compile/internal/noder/encoder.go:221: (*encoder).reloc +0x44 /home/mdempsky/wd/go/src/cmd/compile/internal/noder/linker.go:214: (*linker).relocFuncExt +0x580 /home/mdempsky/wd/go/src/cmd/compile/internal/noder/linker.go:233: (*linker).relocTypeExt +0x234 /home/mdempsky/wd/go/src/cmd/compile/internal/noder/linker.go:161: (*linker).relocObj +0x2198 /home/mdempsky/wd/go/src/cmd/compile/internal/noder/linker.go:64: (*linker).relocIdx +0x196 expected ImplicitTypes, reading at: /home/mdempsky/wd/go/src/cmd/compile/internal/noder/reader.go:796: (*reader).implicitTypes +0x36 /home/mdempsky/wd/go/src/cmd/compile/internal/noder/reader.go:810: (*reader).addBody +0x81 /home/mdempsky/wd/go/src/cmd/compile/internal/noder/reader.go:727: (*reader).funcExt +0x542 /home/mdempsky/wd/go/src/cmd/compile/internal/noder/reader.go:651: (*reader).method +0x324 /home/mdempsky/wd/go/src/cmd/compile/internal/noder/reader.go:557: (*pkgReader).objIdx +0x2704 ``` Change-Id: I911193edd2a965f81b7459f15fb613a773584685 Reviewed-on: https://go-review.googlesource.com/c/go/+/328909 Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Go Bot <gobot@golang.org> Trust: Matthew Dempsky <mdempsky@google.com> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com> Reviewed-by: Robert Griesemer <gri@golang.org>
Diffstat (limited to 'src/cmd/compile/internal/noder/decoder.go')
-rw-r--r--src/cmd/compile/internal/noder/decoder.go100
1 files changed, 79 insertions, 21 deletions
diff --git a/src/cmd/compile/internal/noder/decoder.go b/src/cmd/compile/internal/noder/decoder.go
index 023388875c..3dc61c6a69 100644
--- a/src/cmd/compile/internal/noder/decoder.go
+++ b/src/cmd/compile/internal/noder/decoder.go
@@ -13,6 +13,7 @@ import (
"go/token"
"math/big"
"os"
+ "runtime"
"strings"
"cmd/compile/internal/base"
@@ -131,17 +132,82 @@ func (r *decoder) checkErr(err error) {
}
}
-func (r *decoder) sync(m syncMarker) {
- if debug {
- pos, err0 := r.data.Seek(0, os.SEEK_CUR)
- x, err := r.data.ReadByte()
- r.checkErr(err)
- if x != byte(m) {
- // TODO(mdempsky): Revisit this error message, and make it more
- // useful (e.g., include r.p.pkgPath).
- base.Fatalf("data sync error: found %v at %v (%v) in (%v:%v), but expected %v", syncMarker(x), pos, err0, r.k, r.idx, m)
- }
+func (r *decoder) rawUvarint() uint64 {
+ x, err := binary.ReadUvarint(&r.data)
+ r.checkErr(err)
+ return x
+}
+
+func (r *decoder) rawVarint() int64 {
+ ux := r.rawUvarint()
+
+ // Zig-zag decode.
+ x := int64(ux >> 1)
+ if ux&1 != 0 {
+ x = ^x
+ }
+ return x
+}
+
+func (r *decoder) rawReloc(k reloc, idx int) int {
+ e := r.relocs[idx]
+ assert(e.kind == k)
+ return e.idx
+}
+
+func (r *decoder) sync(mWant syncMarker) {
+ if !enableSync {
+ return
+ }
+
+ pos, _ := r.data.Seek(0, os.SEEK_CUR) // TODO(mdempsky): io.SeekCurrent after #44505 is resolved
+ mHave := syncMarker(r.rawUvarint())
+ writerPCs := make([]int, r.rawUvarint())
+ for i := range writerPCs {
+ writerPCs[i] = int(r.rawUvarint())
+ }
+
+ if mHave == mWant {
+ return
+ }
+
+ // There's some tension here between printing:
+ //
+ // (1) full file paths that tools can recognize (e.g., so emacs
+ // hyperlinks the "file:line" text for easy navigation), or
+ //
+ // (2) short file paths that are easier for humans to read (e.g., by
+ // omitting redundant or irrelevant details, so it's easier to
+ // focus on the useful bits that remain).
+ //
+ // The current formatting favors the former, as it seems more
+ // helpful in practice. But perhaps the formatting could be improved
+ // to better address both concerns. For example, use relative file
+ // paths if they would be shorter, or rewrite file paths to contain
+ // "$GOROOT" (like objabi.AbsFile does) if tools can be taught how
+ // to reliably expand that again.
+
+ fmt.Printf("export data desync: package %q, section %v, index %v, offset %v\n", r.common.pkgPath, r.k, r.idx, pos)
+
+ fmt.Printf("\nfound %v, written at:\n", mHave)
+ if len(writerPCs) == 0 {
+ fmt.Printf("\t[stack trace unavailable; recompile package %q with -d=syncframes]\n", r.common.pkgPath)
}
+ for _, pc := range writerPCs {
+ fmt.Printf("\t%s\n", r.common.stringIdx(r.rawReloc(relocString, pc)))
+ }
+
+ fmt.Printf("\nexpected %v, reading at:\n", mWant)
+ var readerPCs [32]uintptr // TODO(mdempsky): Dynamically size?
+ n := runtime.Callers(2, readerPCs[:])
+ for _, pc := range fmtFrames(readerPCs[:n]...) {
+ fmt.Printf("\t%s\n", pc)
+ }
+
+ // We already printed a stack trace for the reader, so now we can
+ // simply exit. Printing a second one with panic or base.Fatalf
+ // would just be noise.
+ os.Exit(1)
}
func (r *decoder) bool() bool {
@@ -154,16 +220,12 @@ func (r *decoder) bool() bool {
func (r *decoder) int64() int64 {
r.sync(syncInt64)
- x, err := binary.ReadVarint(&r.data)
- r.checkErr(err)
- return x
+ return r.rawVarint()
}
func (r *decoder) uint64() uint64 {
r.sync(syncUint64)
- x, err := binary.ReadUvarint(&r.data)
- r.checkErr(err)
- return x
+ return r.rawUvarint()
}
func (r *decoder) len() int { x := r.uint64(); v := int(x); assert(uint64(v) == x); return v }
@@ -177,11 +239,7 @@ func (r *decoder) code(mark syncMarker) int {
func (r *decoder) reloc(k reloc) int {
r.sync(syncUseReloc)
- idx := r.len()
-
- e := r.relocs[idx]
- assert(e.kind == k)
- return e.idx
+ return r.rawReloc(k, r.len())
}
func (r *decoder) string() string {