diff options
| author | David Chase <drchase@google.com> | 2022-11-07 11:02:08 -0500 |
|---|---|---|
| committer | David Chase <drchase@google.com> | 2022-11-10 17:02:09 +0000 |
| commit | d33043d37dc8cc5d691ff590ebcd2fd42e356a66 (patch) | |
| tree | 3403828570725b1925a17a1431d2774f73ad2611 /src/cmd/compile/internal/base/hashdebug.go | |
| parent | 271f139f17c8ec5895bde52dac4056f99768e258 (diff) | |
| download | go-d33043d37dc8cc5d691ff590ebcd2fd42e356a66.tar.xz | |
cmd/compile: add ability to hash-debug on file:line, including inlining
Modified the fmahash gc debug flag to use this, and modified the
test to check for a hash match that includes inlining. Also
made the test non-short to ensure portability.
Note fma.go has been enhanced into an FMA test that requires
two separate FMAs in order to "fail"; if either one is 2-rounding,
then it "passes". (It neither passes nor fails here; its role
is to demonstrate that the FMAs are correctly reported; the
enhanced failure mode was discovered while testing the search
tool.)
Change-Id: I4e328e3654f442d498eac982135420abb59c5434
Reviewed-on: https://go-review.googlesource.com/c/go/+/448358
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
Run-TryBot: David Chase <drchase@google.com>
Diffstat (limited to 'src/cmd/compile/internal/base/hashdebug.go')
| -rw-r--r-- | src/cmd/compile/internal/base/hashdebug.go | 84 |
1 files changed, 78 insertions, 6 deletions
diff --git a/src/cmd/compile/internal/base/hashdebug.go b/src/cmd/compile/internal/base/hashdebug.go index 609f80393e..6c4821bbf6 100644 --- a/src/cmd/compile/internal/base/hashdebug.go +++ b/src/cmd/compile/internal/base/hashdebug.go @@ -5,7 +5,10 @@ package base import ( + "bytes" "cmd/internal/notsha256" + "cmd/internal/obj" + "cmd/internal/src" "fmt" "io" "os" @@ -27,13 +30,15 @@ type hashAndMask struct { } type HashDebug struct { - mu sync.Mutex - name string // base name of the flag/variable. + mu sync.Mutex // for logfile, posTmp, bytesTmp + name string // base name of the flag/variable. // what file (if any) receives the yes/no logging? // default is os.Stdout - logfile writeSyncer - matches []hashAndMask // A hash matches if one of these matches. - yes, no bool + logfile writeSyncer + posTmp []src.Pos + bytesTmp bytes.Buffer + matches []hashAndMask // A hash matches if one of these matches. + yes, no bool } // The default compiler-debugging HashDebug, for "-d=gossahash=..." @@ -152,7 +157,11 @@ func NewHashDebug(ev, s string, file writeSyncer) *HashDebug { } func hashOf(pkgAndName string, param uint64) uint64 { - hbytes := notsha256.Sum256([]byte(pkgAndName)) + return hashOfBytes([]byte(pkgAndName), param) +} + +func hashOfBytes(sbytes []byte, param uint64) uint64 { + hbytes := notsha256.Sum256(sbytes) hash := uint64(hbytes[7])<<56 + uint64(hbytes[6])<<48 + uint64(hbytes[5])<<40 + uint64(hbytes[4])<<32 + uint64(hbytes[3])<<24 + uint64(hbytes[2])<<16 + @@ -196,6 +205,7 @@ func (d *HashDebug) DebugHashMatchParam(pkgAndName string, param uint64) bool { if d.no { return false } + if d.yes { d.logDebugHashMatch(d.name, pkgAndName, "y", param) return true @@ -220,9 +230,71 @@ func (d *HashDebug) DebugHashMatchParam(pkgAndName string, param uint64) bool { return false } +// DebugHashMatchPos is similar to DebugHashMatchParam, but for hash computation +// it uses the source position including all inlining information instead of +// package name and path. The output trigger string is prefixed with "POS=" so +// that tools processing the output can reliably tell the difference. The mutex +// locking is also more frequent and more granular. +func (d *HashDebug) DebugHashMatchPos(ctxt *obj.Link, pos src.XPos) bool { + if d == nil { + return true + } + if d.no { + return false + } + d.mu.Lock() + defer d.mu.Unlock() + + b := d.bytesForPos(ctxt, pos) + + if d.yes { + d.logDebugHashMatchLocked(d.name, string(b), "y", 0) + return true + } + + hash := hashOfBytes(b, 0) + + for _, m := range d.matches { + if (m.hash^hash)&m.mask == 0 { + hstr := "" + if hash == 0 { + hstr = "0" + } else { + for ; hash != 0; hash = hash >> 1 { + hstr = string('0'+byte(hash&1)) + hstr + } + } + d.logDebugHashMatchLocked(m.name, "POS="+string(b), hstr, 0) + return true + } + } + return false +} + +// bytesForPos renders a position, including inlining, into d.bytesTmp +// and returns the byte array. d.mu must be locked. +func (d *HashDebug) bytesForPos(ctxt *obj.Link, pos src.XPos) []byte { + d.posTmp = ctxt.AllPos(pos, d.posTmp) + // Reverse posTmp to put outermost first. + b := &d.bytesTmp + b.Reset() + for i := len(d.posTmp) - 1; i >= 0; i-- { + p := &d.posTmp[i] + fmt.Fprintf(b, "%s:%d:%d", p.Filename(), p.Line(), p.Col()) + if i != 0 { + b.WriteByte(';') + } + } + return b.Bytes() +} + func (d *HashDebug) logDebugHashMatch(varname, name, hstr string, param uint64) { d.mu.Lock() defer d.mu.Unlock() + d.logDebugHashMatchLocked(varname, name, hstr, param) +} + +func (d *HashDebug) logDebugHashMatchLocked(varname, name, hstr string, param uint64) { file := d.logfile if file == nil { if tmpfile := os.Getenv("GSHS_LOGFILE"); tmpfile != "" { |
