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 74 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
74 commits
Select commit Hold shift + click to select a range
99827cf
cmd/compile: improve concrete type analysis for devirtualization
mateusz834 Feb 17, 2025
0335f86
handle ranges properly
mateusz834 Feb 17, 2025
84fbab4
add test case
mateusz834 Feb 17, 2025
6062d07
rework tests for chans
mateusz834 Feb 17, 2025
0409ba1
improve map tests
mateusz834 Feb 17, 2025
bb5b91b
update tests
mateusz834 Feb 17, 2025
20f7c25
update
mateusz834 Feb 17, 2025
5fa0efc
add two tests and comment
mateusz834 Feb 18, 2025
2202cee
more tests, debug messages
mateusz834 Feb 18, 2025
5af4076
remove testing todo
mateusz834 Feb 18, 2025
0c16a93
rename test file
mateusz834 Feb 18, 2025
762df05
typos
mateusz834 Feb 18, 2025
50ba79a
update
mateusz834 Feb 18, 2025
0cc39ff
add nil checks for devirtualized calls
mateusz834 Feb 18, 2025
53aad36
reword comment
mateusz834 Feb 18, 2025
e887901
remove todos
mateusz834 Feb 18, 2025
c9bf310
rename func
mateusz834 Feb 18, 2025
4995c4c
update comment
mateusz834 Feb 18, 2025
91f9297
keep proper line in nil panic
mateusz834 Feb 18, 2025
d449a95
update
mateusz834 Feb 18, 2025
ef1a343
add nil panic line number test
mateusz834 Feb 18, 2025
a40915a
update comment, add test case
mateusz834 Feb 18, 2025
650c6cd
make tests identical
mateusz834 Feb 18, 2025
d59bfb3
update comment
mateusz834 Feb 18, 2025
4874b46
add comment
mateusz834 Feb 18, 2025
7d5ff19
remove devirtualized bool
mateusz834 Feb 19, 2025
de9ca66
update
mateusz834 Feb 21, 2025
2efc319
add more test cases
mateusz834 Feb 22, 2025
0952833
code tweaks
mateusz834 Feb 22, 2025
be0df1a
update
mateusz834 Feb 23, 2025
a872113
simplify
mateusz834 Feb 24, 2025
d2911d9
handle properly booleans from v, ok
mateusz834 Feb 24, 2025
2057478
add noinline for newinliner
mateusz834 Feb 24, 2025
26c8c12
tmp
mateusz834 Feb 25, 2025
d099b81
update
mateusz834 Feb 25, 2025
2464ac8
update
mateusz834 Feb 25, 2025
8beaa22
update
mateusz834 Feb 25, 2025
9721d27
update
mateusz834 Feb 25, 2025
3b4a3dc
update
mateusz834 Feb 26, 2025
1ad6949
update
mateusz834 Feb 26, 2025
4a63574
update comments
mateusz834 Feb 26, 2025
03fb72e
update
mateusz834 Feb 26, 2025
7bfac15
update
mateusz834 Feb 26, 2025
f216b54
update
mateusz834 Feb 26, 2025
e4d294d
update
mateusz834 Feb 26, 2025
4d6ab6e
update
mateusz834 Feb 26, 2025
07b4fdc
update
mateusz834 Feb 26, 2025
d30e6cd
typos
mateusz834 Feb 26, 2025
f08082d
update
mateusz834 Feb 26, 2025
ee11747
remove testing debug flag
mateusz834 Feb 26, 2025
633f108
remove testing params
mateusz834 Feb 26, 2025
3651bfb
fix newinliner
mateusz834 Feb 26, 2025
9923235
update pprof test
mateusz834 Feb 26, 2025
996d6e6
few review comments resolved
mateusz834 Feb 27, 2025
29f5308
update
mateusz834 Feb 27, 2025
053b51d
update
mateusz834 Feb 27, 2025
a445213
typos, code move
mateusz834 Feb 28, 2025
feea6d3
additional test case
mateusz834 Feb 28, 2025
b079b60
fix tabs in comment
mateusz834 Feb 28, 2025
11ddd3e
removed added line
mateusz834 Feb 28, 2025
67b899c
add two tests
mateusz834 Feb 28, 2025
f33cdc3
add comment
mateusz834 Feb 28, 2025
cc370fb
fix newinliner
mateusz834 Feb 28, 2025
5635301
update
mateusz834 Feb 28, 2025
c4614e6
simplify
mateusz834 Feb 28, 2025
91951da
remove devirtState field
mateusz834 Feb 28, 2025
69f040d
update comment
mateusz834 Feb 28, 2025
36bcb8a
update
mateusz834 Feb 28, 2025
ac6e30b
minor tweaks
mateusz834 Mar 2, 2025
5286ef9
minor
mateusz834 Mar 2, 2025
8eea6a6
self assignments
mateusz834 Mar 3, 2025
1d45dfa
typo
mateusz834 Mar 3, 2025
7fea0a5
review update
mateusz834 Mar 11, 2025
2d12057
add noinline for newinliner
mateusz834 Mar 11, 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
461 changes: 450 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 @@ -5642,6 +5642,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 @@ -406,3 +406,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