I don’t think we do?
We do SROA, i.e. scalar-replacement-of-aggregates, and the scalar replacement lives in registers and maybe spills to the stack.
Afaiu we never do stack-alloc, where we know that the lifetime is bounded by the stackframe and we allocate a fully formed object on the stack (please correct me if if I’m wrong or this changed!).
Afaiu we don’t do eager deterministic de-alloc, i.e. the compiler never generates a matching free to the malloc / ijl_gc_pool_alloc.
An example is the following:
julia> @noinline g(r) = (r[] += 1);
julia> f(i)=begin r = Ref(i); g(r); r[] end
In a perfect world, g would have inferred effects that imply that r doesn’t leak. But we requested the function @noinline, so we cannot use scalar replacement.
So f could place the Ref on the stack instead of the heap; but it would still require an object header.
Or f could allocate the Ref on the heap, using jl_gc_pool_alloc and then free it upon return from g. But we don’t do that. (we are already paying the price of expensive allocations for non-compacting GC; might as well reap the benefits of opportunistic early free)
Related Feature request: unsafe_free!