Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions cl/caller_frame_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package cl

import (
"fmt"
"go/ast"
"go/importer"
"go/parser"
Expand Down Expand Up @@ -379,6 +380,8 @@ func owner() {
defer inspect()
defer deferredPanicLeaf()
panicLeaf()
repeatedPanicLeaf(nil, 0)
branchPanicLeaf(nil, 0, true)
}

func panicLeaf() {
Expand All @@ -393,6 +396,16 @@ func deferredPanicLeaf() {
_ = *p
}

func repeatedPanicLeaf(p *[1]int, i int) int {
//line repeated_panic_site.go:345
return p[i] + p[i]
}

func branchPanicLeaf(p *[1]int, i int, cond bool) int {
//line branch_panic_site.go:456
if cond { return p[i] }; return p[i]
}

//go:noinline
func pinnedPanicSite() {
var p *int
Expand All @@ -416,6 +429,21 @@ func pinnedPanicSite() {
t.Fatalf("recover-visible nil dereference is missing panic-site metadata %q:\n%s", want, ir)
}
}
countPCLine := func(symbol, file string, line int) (count int) {
want := fmt.Sprintf(`!"%s", !"%s", i32 %d`, symbol, file, line)
for _, row := range strings.Split(ir, "\n") {
if strings.Contains(row, `!{i32 1, i64 `) && strings.Contains(row, want) {
count++
}
}
return count
}
if got := countPCLine("example.com/foo.repeatedPanicLeaf", "repeated_panic_site.go", 345); got != 1 {
t.Fatalf("same-line panic sites in one basic block produced %d metadata records, want 1:\n%s", got, ir)
}
if got := countPCLine("example.com/foo.branchPanicLeaf", "branch_panic_site.go", 456); got != 2 {
t.Fatalf("same-line panic sites in separate basic blocks produced %d metadata records, want 2:\n%s", got, ir)
}
if strings.Contains(ir, `!"non_recover_site.go"`) {
t.Fatalf("ordinary pinned function unexpectedly received implicit panic-site metadata:\n%s", ir)
}
Expand Down
9 changes: 9 additions & 0 deletions cl/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,11 @@ type context struct {
runtimeCallerFuncs map[*ssa.Function]bool
panicSiteFuncs map[*ssa.Function]bool
pcLineSeq uint64
// The runtime PC-line table stores file and line, but not column. Keep the
// last emitted position within one SSA basic block so repeated checks for a
// single source line can share an anchor.
lastPCLineFile string
lastPCLineLine int

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional: the correctness of these dedup fields depends on two invariants — compileBlock resetting them at each block entry, and compilation being single-threaded. Both hold today, but a future refactor that parallelizes compilation would silently corrupt this shared state. Consider a one-line note here recording that dependency so the invariant is visible at the field declaration.

options Options
recoverSlots map[*ssa.Alloc]none
implicitDeferResults []llssa.Expr
Expand Down Expand Up @@ -893,6 +898,10 @@ func (p *context) debugParams(b llssa.Builder, f *ssa.Function) {
}

func (p *context) compileBlock(b llssa.Builder, block *ssa.BasicBlock, n int, doModInit bool) llssa.BasicBlock {
// A control-flow edge can enter this block without executing the preceding
// block's anchor, so deduplication must never cross a block boundary.
p.lastPCLineFile = ""
p.lastPCLineLine = 0
oldLocalBlock := p.locality.function.block
p.locality.function.block = block
defer func() { p.locality.function.block = oldLocalBlock }()
Expand Down
9 changes: 9 additions & 0 deletions cl/instr.go
Original file line number Diff line number Diff line change
Expand Up @@ -1971,6 +1971,15 @@ func (p *context) emitPCLineLabel(b llssa.Builder, pos token.Pos) {
if position.Line <= 0 || position.Filename == "" {
return
}
// Lookup uses the nearest preceding PC anchor. Within one basic block,
// another anchor for the same runtime-visible file and line cannot change
// the result, even when several implicit panic checks came from one Go
// expression.
if position.Filename == p.lastPCLineFile && position.Line == p.lastPCLineLine {
return
}
p.lastPCLineFile = position.Filename
p.lastPCLineLine = position.Line
p.pcLineSeq++
id := pcLineID(p.fn.Name(), p.pcLineSeq)
label := pcLineLabelName(id)
Expand Down
Loading