Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd/compile/internal/devirtualize: improve concrete type analysis #71935

Open
wants to merge 72 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
adc9040
cmd/compile: improve concrete type analysis for devirtualization
mateusz834 Feb 17, 2025
7f741c8
handle ranges properly
mateusz834 Feb 17, 2025
9d642a1
add test case
mateusz834 Feb 17, 2025
aaa8340
rework tests for chans
mateusz834 Feb 17, 2025
0777896
improve map tests
mateusz834 Feb 17, 2025
66d8b70
update tests
mateusz834 Feb 17, 2025
aadd746
update
mateusz834 Feb 17, 2025
d8fd8b0
add two tests and comment
mateusz834 Feb 18, 2025
e7f1037
more tests, debug messages
mateusz834 Feb 18, 2025
5d0fea2
remove testing todo
mateusz834 Feb 18, 2025
574aa22
rename test file
mateusz834 Feb 18, 2025
8cb9f5c
typos
mateusz834 Feb 18, 2025
dd2db02
update
mateusz834 Feb 18, 2025
914b14b
add nil checks for devirtualized calls
mateusz834 Feb 18, 2025
94b4282
reword comment
mateusz834 Feb 18, 2025
68f4a05
remove todos
mateusz834 Feb 18, 2025
ff52b68
rename func
mateusz834 Feb 18, 2025
a4e5a80
update comment
mateusz834 Feb 18, 2025
784e17c
keep proper line in nil panic
mateusz834 Feb 18, 2025
87c65cf
update
mateusz834 Feb 18, 2025
45c60a5
add nil panic line number test
mateusz834 Feb 18, 2025
087c347
update comment, add test case
mateusz834 Feb 18, 2025
2a83334
make tests identical
mateusz834 Feb 18, 2025
c053608
update comment
mateusz834 Feb 18, 2025
7aade42
add comment
mateusz834 Feb 18, 2025
e4cf503
remove devirtualized bool
mateusz834 Feb 19, 2025
0c57c34
update
mateusz834 Feb 21, 2025
f22918d
add more test cases
mateusz834 Feb 22, 2025
372c5bb
code tweaks
mateusz834 Feb 22, 2025
2560a2c
update
mateusz834 Feb 23, 2025
a957ba9
simplify
mateusz834 Feb 24, 2025
92b33c0
handle properly booleans from v, ok
mateusz834 Feb 24, 2025
fc782d5
add noinline for newinliner
mateusz834 Feb 24, 2025
fadaf36
tmp
mateusz834 Feb 25, 2025
78c8155
update
mateusz834 Feb 25, 2025
7ed622f
update
mateusz834 Feb 25, 2025
0f70fc3
update
mateusz834 Feb 25, 2025
4e359fd
update
mateusz834 Feb 25, 2025
03fb863
update
mateusz834 Feb 26, 2025
893e387
update
mateusz834 Feb 26, 2025
e1a0b96
update comments
mateusz834 Feb 26, 2025
0f110ec
update
mateusz834 Feb 26, 2025
5d286a8
update
mateusz834 Feb 26, 2025
305832a
update
mateusz834 Feb 26, 2025
f01349a
update
mateusz834 Feb 26, 2025
7efcf29
update
mateusz834 Feb 26, 2025
9dcd042
update
mateusz834 Feb 26, 2025
3b2345c
typos
mateusz834 Feb 26, 2025
a65a6da
update
mateusz834 Feb 26, 2025
cb05e01
remove testing debug flag
mateusz834 Feb 26, 2025
71aa67a
remove testing params
mateusz834 Feb 26, 2025
f9ee31f
fix newinliner
mateusz834 Feb 26, 2025
48288b7
update pprof test
mateusz834 Feb 26, 2025
0535189
few review comments resolved
mateusz834 Feb 27, 2025
12dad1a
update
mateusz834 Feb 27, 2025
7daa5a3
update
mateusz834 Feb 27, 2025
78612a8
typos, code move
mateusz834 Feb 28, 2025
f96f793
additional test case
mateusz834 Feb 28, 2025
9f295d7
fix tabs in comment
mateusz834 Feb 28, 2025
3af6c18
removed added line
mateusz834 Feb 28, 2025
cb2a60e
add two tests
mateusz834 Feb 28, 2025
8863141
add comment
mateusz834 Feb 28, 2025
2f61524
fix newinliner
mateusz834 Feb 28, 2025
504bf50
update
mateusz834 Feb 28, 2025
c2a2804
simplify
mateusz834 Feb 28, 2025
5c78100
remove devirtState field
mateusz834 Feb 28, 2025
326f204
update comment
mateusz834 Feb 28, 2025
d17776d
update
mateusz834 Feb 28, 2025
5af4c71
minor tweaks
mateusz834 Mar 2, 2025
f82d9e4
minor
mateusz834 Mar 2, 2025
d6e3c35
self assignments
mateusz834 Mar 3, 2025
cf7322c
typo
mateusz834 Mar 3, 2025
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
451 changes: 440 additions & 11 deletions src/cmd/compile/internal/devirtualize/devirtualize.go

Large diffs are not rendered by default.

37 changes: 21 additions & 16 deletions src/cmd/compile/internal/inline/interleaved/interleaved.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ func DevirtualizeAndInlinePackage(pkg *ir.Package, profile *pgoir.Profile) {
inlState := make(map[*ir.Func]*inlClosureState)
calleeUseCounts := make(map[*ir.Func]int)

var state devirtualize.State

// Pre-process all the functions, adding parentheses around call sites and starting their "inl state".
for _, fn := range typecheck.Target.Funcs {
bigCaller := base.Flag.LowerL != 0 && inline.IsBigFunc(fn)
Expand All @@ -58,7 +60,7 @@ func DevirtualizeAndInlinePackage(pkg *ir.Package, profile *pgoir.Profile) {

// Do a first pass at counting call sites.
for i := range s.parens {
s.resolve(i)
s.resolve(&state, i)
}
}

Expand Down Expand Up @@ -102,10 +104,11 @@ func DevirtualizeAndInlinePackage(pkg *ir.Package, profile *pgoir.Profile) {
for {
for i := l0; i < l1; i++ { // can't use "range parens" here
paren := s.parens[i]
if new := s.edit(i); new != nil {
if origCall, inlinedCall := s.edit(&state, i); inlinedCall != nil {
// Update AST and recursively mark nodes.
paren.X = new
ir.EditChildren(new, s.mark) // mark may append to parens
paren.X = inlinedCall
ir.EditChildren(inlinedCall, s.mark) // mark may append to parens
state.InlinedCall(s.fn, origCall, inlinedCall)
done = false
}
}
Expand All @@ -114,7 +117,7 @@ func DevirtualizeAndInlinePackage(pkg *ir.Package, profile *pgoir.Profile) {
break
}
for i := l0; i < l1; i++ {
s.resolve(i)
s.resolve(&state, i)
}

}
Expand Down Expand Up @@ -188,7 +191,7 @@ type inlClosureState struct {
// resolve attempts to resolve a call to a potentially inlineable callee
// and updates use counts on the callees. Returns the call site count
// for that callee.
func (s *inlClosureState) resolve(i int) (*ir.Func, int) {
func (s *inlClosureState) resolve(state *devirtualize.State, i int) (*ir.Func, int) {
p := s.parens[i]
if i < len(s.resolved) {
if callee := s.resolved[i]; callee != nil {
Expand All @@ -200,7 +203,7 @@ func (s *inlClosureState) resolve(i int) (*ir.Func, int) {
if !ok { // previously inlined
return nil, -1
}
devirtualize.StaticCall(call)
devirtualize.StaticCall(state, call)
if callee := inline.InlineCallTarget(s.fn, call, s.profile); callee != nil {
for len(s.resolved) <= i {
s.resolved = append(s.resolved, nil)
Expand All @@ -213,23 +216,23 @@ func (s *inlClosureState) resolve(i int) (*ir.Func, int) {
return nil, 0
}

func (s *inlClosureState) edit(i int) ir.Node {
func (s *inlClosureState) edit(state *devirtualize.State, i int) (*ir.CallExpr, *ir.InlinedCallExpr) {
n := s.parens[i].X
call, ok := n.(*ir.CallExpr)
if !ok {
return nil
return nil, nil
}
// This is redundant with earlier calls to
// resolve, but because things can change it
// must be re-checked.
callee, count := s.resolve(i)
callee, count := s.resolve(state, i)
if count <= 0 {
return nil
return nil, nil
}
if inlCall := inline.TryInlineCall(s.fn, call, s.bigCaller, s.profile, count == 1 && callee.ClosureParent != nil); inlCall != nil {
return inlCall
return call, inlCall
}
return nil
return nil, nil
}

// Mark inserts parentheses, and is called repeatedly.
Expand Down Expand Up @@ -338,16 +341,18 @@ func (s *inlClosureState) unparenthesize() {
// returns.
func (s *inlClosureState) fixpoint() bool {
changed := false
var state devirtualize.State
ir.WithFunc(s.fn, func() {
done := false
for !done {
done = true
for i := 0; i < len(s.parens); i++ { // can't use "range parens" here
paren := s.parens[i]
if new := s.edit(i); new != nil {
if origCall, inlinedCall := s.edit(&state, i); inlinedCall != nil {
// Update AST and recursively mark nodes.
paren.X = new
ir.EditChildren(new, s.mark) // mark may append to parens
paren.X = inlinedCall
ir.EditChildren(inlinedCall, s.mark) // mark may append to parens
state.InlinedCall(s.fn, origCall, inlinedCall)
done = false
changed = true
}
Expand Down
5 changes: 5 additions & 0 deletions src/cmd/compile/internal/ir/expr.go
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,11 @@ type TypeAssertExpr struct {

// An internal/abi.TypeAssert descriptor to pass to the runtime.
Descriptor *obj.LSym

// When set to true, if this assert would panic, then use a nil pointer panic
// instead of an interface conversion panic.
// It must not be set for type asserts using the commaok form.
UseNilPanic bool
}

func NewTypeAssertExpr(pos src.XPos, x Node, typ *types.Type) *TypeAssertExpr {
Expand Down
1 change: 1 addition & 0 deletions src/cmd/compile/internal/noder/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -2941,6 +2941,7 @@ func (r *reader) multiExpr() []ir.Node {
as.Def = true
for i := range results {
tmp := r.temp(pos, r.typ())
tmp.Defn = as
as.PtrInit().Append(ir.NewDecl(pos, ir.ODCL, tmp))
as.Lhs.Append(tmp)

Expand Down
19 changes: 19 additions & 0 deletions src/cmd/compile/internal/ssagen/ssa.go
Original file line number Diff line number Diff line change
Expand Up @@ -5625,6 +5625,25 @@ func (s *state) dottype(n *ir.TypeAssertExpr, commaok bool) (res, resok *ssa.Val
if n.ITab != nil {
targetItab = s.expr(n.ITab)
}

if n.UseNilPanic {
if commaok {
base.Fatalf("unexpected *ir.TypeAssertExpr with UseNilPanic == true && commaok == true")
}
if n.Type().IsInterface() {
// Currently we do not expect the compiler to emit type asserts with UseNilPanic, that assert to an interface type.
// If needed, this can be relaxed in the future, but for now we can assert that.
base.Fatalf("unexpected *ir.TypeAssertExpr with UseNilPanic == true && Type().IsInterface() == true")
}
typs := s.f.Config.Types
iface = s.newValue2(
ssa.OpIMake,
iface.Type,
s.nilCheck(s.newValue1(ssa.OpITab, typs.BytePtr, iface)),
s.newValue1(ssa.OpIData, typs.BytePtr, iface),
)
}

return s.dottype1(n.Pos(), n.X.Type(), n.Type(), iface, nil, target, targetItab, commaok, n.Descriptor)
}

Expand Down
14 changes: 14 additions & 0 deletions src/crypto/sha256/sha256_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -391,3 +391,17 @@ func BenchmarkHash1K(b *testing.B) {
func BenchmarkHash8K(b *testing.B) {
benchmarkSize(b, 8192)
}

func TestAllocatonsWithTypeAsserts(t *testing.T) {
cryptotest.SkipTestAllocations(t)
allocs := testing.AllocsPerRun(100, func() {
h := New()
h.Write([]byte{1, 2, 3})
marshaled, _ := h.(encoding.BinaryMarshaler).MarshalBinary()
marshaled, _ = h.(encoding.BinaryAppender).AppendBinary(marshaled[:0])
h.(encoding.BinaryUnmarshaler).UnmarshalBinary(marshaled)
})
if allocs != 0 {
t.Fatalf("allocs = %v; want = 0", allocs)
}
}
5 changes: 5 additions & 0 deletions src/runtime/pprof/pprof_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,11 @@ func (h inlineWrapper) dump(pcs []uintptr) {

func inlinedWrapperCallerDump(pcs []uintptr) {
var h inlineWrapperInterface

// Take the address of h, such that h.dump() call (below)
// does not get devirtualized by the compiler.
_ = &h

h = &inlineWrapper{}
h.dump(pcs)
}
Expand Down
Loading