Note [Invalid optimisation: shortcutting]
You might think that if we have something like
A's SRT = {B}
B's SRT = {X}
that we could replace the reference to B in A's SRT with X.
A's SRT = {X}
B's SRT = {X}
and thereby perhaps save a little work at runtime, because we don't
have to visit B.
But this is NOT valid.
Consider these cases:
0. B can't be a constructor, because constructors don't have SRTs
1. B is a CAF. This is the easy one. Obviously we want A's SRT to
point to B, so that it keeps B alive.
2. B is a function. This is the tricky one. The reason we can't
shortcut in this case is that we aren't allowed to resurrect static
objects for the reason described in Note [No static object resurrection].
We noticed this in #15544.
The particular case that cropped up when we tried this in #15544 was:
- A is a thunk
- B is a static function
- X is a CAF
- suppose we GC when A is alive, and B is not otherwise reachable.
- B is "collected", meaning that it doesn't make it onto the static
objects list during this GC, but nothing bad happens yet.
- Next, suppose we enter A, and then call B. (remember that A refers to B)
At the entry point to B, we GC. This puts B on the stack, as part of the
RET_FUN stack frame that gets pushed when we GC at a function entry point.
- This GC will now reach B
- But because B was previous "collected", it breaks the assumption
that static objects are never resurrected. See Note [STATIC_LINK
fields] in rts/sm/Storage.h for why this is bad.
- In practice, the GC thinks that B has already been visited, and so
doesn't visit X, and catastrophe ensues. References 1
- No static object resurrection GHC.Cmm.Info.Build
Referenced by 2
- GHC.Cmm.Info.Build call site
- SRTs GHC.Cmm.Info.Build