Concurrent OSR used to work like this:
- When we decide to OSR at a loop entry, we create a compile job to have it compiled, mostly on the concurrent thread.
- In the meantime we continue with the function.
- Once the compile job is complete, we patch that loop entry to install the code.
- If we arrive at the loop entry again, the code is installed and we OSR into optimized code.
- As long as we don't arrive at the loop entry, the compile job is on-hold and holds onto memory.
- We may never arrive at that loop entry again. So to reduce the risk of memory leaks, we periodically purge on-hold OSR jobs.
In practise, concurrent OSR almost never helps, and we had a couple of pathological cases where the function to OSR is huge, has a few separate long-running loops. We decide to OSR for each of them, but miss the loop-reentry, and only return to a loop-entry when old OSR jobs have been purged. The complexity of all of this is just not worth the hassle.
Cheers,
Yang