Live data from Hacker News

Go's escape analysis and why my function return worked

bonniesimon.in

71–76 of 76 posts

Re: Go's escape analysis and why my function return worked

#71
post #70
post #69

Earlier quoted context omitted.

Your https://news.ycombinator.com/item?id=46234206 relies on escape analysis though, right? Escape analysis is the reason your `x` is on the heap. Because it escaped. Otherwise it'd be on the stack.[1] Now if by "semantics of the code" you mean "just pretend everything is on the heap, and you won't need to think about escape analysis", then sure. Now in terms of what actually happens, your code triggers escape analys…

Escape analysis clearly isn’t part of the semantics of Go. For that to be the case, the language standard would have to specify exactly which values are guaranteed to be stack allocated. In reality, this depends on size thresholds which can vary from platform to platform or between different versions of the Go compiler. Is the following non-escaping array value stack allocated? func pointless() byte { var a byte[1024…

While you are of course 100% correct, in the context of discussing escape analysis I find it odd to say that it's essentially not "real".

Like any optimization, it makes sense to talk about what "will" happen, even if a language (or a specific compiler) makes no specific promises.

Escape analysis enables an optimization.

I think I understand you to be saying that "escape analysis" is not why returning a pointer to a local works in Go, but it's what allows some variables to be on the stack, despite the ability to return pointers to other "local" variables.

Or similar to how the compiler can allow "a * 6" to never use a mul instruction, but just two shifts and an add.

Which is probably a better way to think about it.

> So clearly you don’t need to think about the details of escape analysis to understand what your code does

Right. To circle back to the context: Yeah, OP thought this was due to escape analysis, and that's why it worked. No, it's just a detail about why other code does something else. (but not really, because OP returned the slice by value)

So I suppose it's more correct to say that we were never discussing escape analysis at all. An escape analysis post would be talking about allocation counts and memory fragmentation, not "why does this work?".

Claude (per OPs post) led them astray.

Re: Go's escape analysis and why my function return worked

#72

Earlier quoted context omitted.

> Go won’t put large allocations on the stack even if escape analysis would permit it Depends what you mean by “large”. As of 1.24 Go will put slices several KB into the stack frame: make([]byte, 65536) Goes on the stack if it does not escape (you can see Go request a large stack frame) make([]byte, 65537) goes on the heap (Go calls runtime.makeslice). Interestingly arrays have a different limit: they respect MaxStac…

There is a option -smallframes that seems to be intended for conservative use cases. Below are the related configs and a test at what point they escape (+1). // -smallframes // ir.MaxStackVarSize = 64 * 1024 // ir.MaxImplicitStackVarSize = 16 * 1024 a := [64 * 1024 +1]byte{} b := make([]byte, 0, 16 * 1024 +1) // default // MaxStackVarSize = int64(128 * 1024) // MaxImplicitStackVarSize = int64(64 * 1024) c := [128 * 1…

> Not sure how to verify this, but the assumption you can allocate megabytes on the stack seems wrong.

    []byte{N: 0}

Re: Go's escape analysis and why my function return worked

#73

Earlier quoted context omitted.

There is a option -smallframes that seems to be intended for conservative use cases. Below are the related configs and a test at what point they escape (+1). // -smallframes // ir.MaxStackVarSize = 64 * 1024 // ir.MaxImplicitStackVarSize = 16 * 1024 a := [64 * 1024 +1]byte{} b := make([]byte, 0, 16 * 1024 +1) // default // MaxStackVarSize = int64(128 * 1024) // MaxImplicitStackVarSize = int64(64 * 1024) c := [128 * 1…

> Not sure how to verify this, but the assumption you can allocate megabytes on the stack seems wrong. []byte{N: 0}

[deleted]

Re: Go's escape analysis and why my function return worked

#74

Earlier quoted context omitted.

There is a option -smallframes that seems to be intended for conservative use cases. Below are the related configs and a test at what point they escape (+1). // -smallframes // ir.MaxStackVarSize = 64 * 1024 // ir.MaxImplicitStackVarSize = 16 * 1024 a := [64 * 1024 +1]byte{} b := make([]byte, 0, 16 * 1024 +1) // default // MaxStackVarSize = int64(128 * 1024) // MaxImplicitStackVarSize = int64(64 * 1024) c := [128 * 1…

> Not sure how to verify this, but the assumption you can allocate megabytes on the stack seems wrong. []byte{N: 0}

doesn't make sense.

Re: Go's escape analysis and why my function return worked

#75

Earlier quoted context omitted.

> Not sure how to verify this, but the assumption you can allocate megabytes on the stack seems wrong. []byte{N: 0}

doesn't make sense.

And yet it does: https://godbolt.org/z/h9GW5v3YK

And creates an on-stack slice whose size is only limited by Go's 1GB limit on individual stack frames: https://godbolt.org/z/rKzo8jre6 https://godbolt.org/z/don99e9cn

Re: Go's escape analysis and why my function return worked

#76

Earlier quoted context omitted.

doesn't make sense.

And yet it does: https://godbolt.org/z/h9GW5v3YK And creates an on-stack slice whose size is only limited by Go's 1GB limit on individual stack frames: https://godbolt.org/z/rKzo8jre6 https://godbolt.org/z/don99e9cn

Yea with more context it suddenly makes sense :p

Interesting, [...] syntax works here as expected. So escape analysis simply doesn't look at the element list.

Post reply on HN