golang / go

The Go programming language
https://go.dev
BSD 3-Clause "New" or "Revised" License
124.01k stars 17.67k forks source link

cmd/compile: esc.go fails to mark anonymous receiver parameters as non-escaping #24305

Open mdempsky opened 6 years ago

mdempsky commented 6 years ago
package p

type T struct { x int }

//go:noinline
func (*T) M() {}  

//go:noinline
func (_ *T) N() {}

func f() {
        var t T
        t.M()
        t.N()
        (*T).M(&t)
        (*T).N(&t)
}

Compiling the above code with "go tool compile -m" outputs:

a.go:13:3: t escapes to heap
a.go:12:6: moved to heap: t
a.go:14:3: t escapes to heap
a.go:15:9: &t escapes to heap
a.go:16:9: &t escapes to heap

This doesn't happen if the receiver parameters are given a proper name, or if the receiver parameters are turned into normal parameters (i.e., changing the methods into functions).

The direct calls (t.M() and t.N()) are because (*EscState).esctag's unnamed parameter loop only touches fn.Type.Params(), not fn.Type.Recvs().

The indirect calls ((*T).M(&t) and (*T).N(&t)) appear to be because esc.go just doesn't look for esc tags for methods called as functions.

gopherbot commented 6 years ago

Change https://golang.org/cl/99335 mentions this issue: cmd/compile: mark anonymous receiver parameters as non-escaping

dr2chase commented 6 years ago

This looks fixed. Any problems with closing?

mdempsky commented 6 years ago

This is half fixed. (*T).M(&t) and (*T).N(&t) still escape.

dr2chase commented 6 years ago

Still for 1.11, or do we put off to 1.12?

dr2chase commented 6 years ago

Doesn't this have the obvious user workaround of applying the local purely local rewrite of (*T).M(&t) into (&t).M(), which can actually be written t.M()?

I'd like to postpone this to unplanned.

mdempsky commented 5 years ago

Still an issue with newescape.

gopherbot commented 4 years ago

Change https://golang.org/cl/248217 mentions this issue: cmd/compile: mark receiver in indirect calls as non-escaping