# Borrow checker with GC fallback?

**URL:** <https://discourse.julialang.org/t/borrow-checker-with-gc-fallback/111798>\
**Category:** Internals & Design\
**Created:** [March 19, 2024, 3:21am UTC](https://discourse.julialang.org/t/borrow-checker-with-gc-fallback/111798 "2024-03-19T03:21:18Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![Tarny\_GG\_Channie](https://avatars.discourse-cdn.com/v4/letter/t/3bc359/32.png) [@Tarny\_GG\_Channie](https://discourse.julialang.org/u/Tarny_GG_Channie)\
**Post date:** [March 19, 2024, 3:21am UTC](https://discourse.julialang.org/t/borrow-checker-with-gc-fallback/111798/1 "2024-03-19T03:21:18Z")

</div>

GC incurs some overhead. It’d be nice if we don’t have to GC everything. In some cases, we can detect exactly when the memory needs to be freed at compile time. If so, would it be a good idea? Julia is a language that wants to have a cake and eat it too.

---

<div class="post-metadata">

**Author:** ![Oscar\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oscar_smith/32/25343_2.png) [@Oscar\_Smith](https://discourse.julialang.org/u/Oscar_Smith)\
**Post date:** [March 19, 2024, 3:27am UTC](https://discourse.julialang.org/t/borrow-checker-with-gc-fallback/111798/2 "2024-03-19T03:27:31Z")

</div>

we already do this for everything except arrays, although the analysis isn’t interprocederal so it can miss some “obvious” cases

---

<div class="post-metadata">

**Author:** ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)\
**Post date:** [March 19, 2024, 9:05am UTC](https://discourse.julialang.org/t/borrow-checker-with-gc-fallback/111798/3 "2024-03-19T09:05:53Z")

</div>

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
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!](https://discourse.julialang.org/t/feature-request-unsafe-free/111767)

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [March 19, 2024, 2:20pm UTC](https://discourse.julialang.org/t/borrow-checker-with-gc-fallback/111798/4 "2024-03-19T14:20:04Z")

</div>

See the example I gave here:

> [@Eager finalization and smart pointers](https://discourse.julialang.org/t/eager-finalization-and-smart-pointers/92462/5):
>
> This simplified example looks promising. julia\> n::Int = 0 0 julia\> const safe\_free = Base.@assume\_effects :nothrow :notaskstate x-\>(global n += 1;Libc.free(x.ptr)) #3 (generic function with 1 method) julia\> mutable struct SafePointer ptr::Ptr{Int} end julia\> function f() for i in 1:100 s = SafePointer(Libc.malloc(sizeof(Int))) finalizer(safe\_free, s) end nothing end f (generic function with 1 method) ju…

---

<div class="post-metadata">

**Author:** ![vchuravy](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vchuravy/32/8_2.png) [@vchuravy](https://discourse.julialang.org/u/vchuravy)\
**Post date:** [March 19, 2024, 4:12pm UTC](https://discourse.julialang.org/t/borrow-checker-with-gc-fallback/111798/5 "2024-03-19T16:12:39Z")

</div>

> [@foobar\_lv2](#):
>
> 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!).

We have a pass `llvm-alloc-opt` that moves object from the heap to the stack. When we do this we eliminate the object, this leads to some limitations.

Firstly we don’t allocate a tag anymore so this also requires us to be able to “see” and thus forward all calls to `typeof`.

Furthermore the pass is function local (llvm) and does not take account IPO derived information. We have an IPO escape analysis but it has been challenging to wire up and add that IPO information to the LLVM pass.

One of the capabilities that we are missing is to allocate a full Julia object on the stack (including the tag) and have the GC understand this. This should be doable, but handling write barriers is a bit annoying.

We must guarantee that an alloca address is not escaped. If we have a write barrier and the parent is stack allocated we might accidentally push the address into the remset.

In order to handle that we would need to use one of the age/GC bits to represent “always young”/“ephemeral”.

So in order to level up escape analysis we need to improve the GC/runtime first.
