#13450 fixed an issue when we are working with data derived from inside a GC reference, but not keeping the GC reference itself alive anymore, and we would end up reclaiming the object and its data before we were done working with the data. We fixed this by ~effectively tricking the compiler to think the GC reference is still live across the loop that processes the GC ref's data. But in some future world where we improve our constant phi removal pass and/or run it before safepoint spilling, that bandaid will stop working. The root problem is that the fix really is just that, a bandaid, and what we fundamentally need is to communicate to the compiler that some data is derived from this GC ref and that therefore that GC ref needs to be considered live while the data is live.
We could do this in a number of ways, some more or less hacky than others:
- Add a
derived_from_gc_ref: SecondaryMap<Value, PackedOption<Value>> map to FunctionBuilder that maps a GC-ref-derived value back to its GC ref. Use this in the safepoint spiller.
- Add an optional GC ref operand to loads/stores (or every instruction?) that only exists to keep the original GC ref alive while we are working with data derived from it.
- Add a
fake_use v0, v1, ... instruction that cannot be GVN'd or LICM'd which keeps its operand(s) alive.
I'm partial to (1). I think (2) effectively devolves into (1) but with the uses repeated (e.g. you have to have the ghost operand at every use site of the derived value(s) rather than just once in the SecondaryMap). I think (3) is probably the hackiest, and would also prevent DCE'ing code that would otherwise be DCE-able.
#13450 fixed an issue when we are working with data derived from inside a GC reference, but not keeping the GC reference itself alive anymore, and we would end up reclaiming the object and its data before we were done working with the data. We fixed this by ~effectively tricking the compiler to think the GC reference is still live across the loop that processes the GC ref's data. But in some future world where we improve our constant phi removal pass and/or run it before safepoint spilling, that bandaid will stop working. The root problem is that the fix really is just that, a bandaid, and what we fundamentally need is to communicate to the compiler that some data is derived from this GC ref and that therefore that GC ref needs to be considered live while the data is live.
We could do this in a number of ways, some more or less hacky than others:
derived_from_gc_ref: SecondaryMap<Value, PackedOption<Value>>map toFunctionBuilderthat maps a GC-ref-derived value back to its GC ref. Use this in the safepoint spiller.fake_use v0, v1, ...instruction that cannot be GVN'd or LICM'd which keeps its operand(s) alive.I'm partial to (1). I think (2) effectively devolves into (1) but with the uses repeated (e.g. you have to have the ghost operand at every use site of the derived value(s) rather than just once in the
SecondaryMap). I think (3) is probably the hackiest, and would also prevent DCE'ing code that would otherwise be DCE-able.