We are seeing an error where code that is generated with MJIT contains references to objects that have been moved. I believe this is due to a race condition in the compaction function.
gc_compact has two steps:
Run a full GC to pin objects
Compact / update references
Step one is executed with garbage_collect. garbage_collect calls gc_enter / gc_exit, these functions acquire a JIT lock and release a JIT lock. So a lock is held for the duration of step 1.
Step two is executed by gc_compact_after_gc. It also holds a JIT lock.
I believe the problem is that the JIT is free to execute between step 1 and step 2. It copies call cache values, but doesn't pin them when it copies them. So the compactor thinks it's OK to move the call cache even though it is not safe.
We need to hold a lock for the duration of garbage_collectand gc_compact_after_gc. This patch introduces a lock level which increments and decrements. The compaction function can increment and decrement the lock level and prevent MJIT from executing during both steps.
Use a lock level for a less granular lock.
We are seeing an error where code that is generated with MJIT contains
references to objects that have been moved. I believe this is due to a
race condition in the compaction function.
gc_compacthas two steps:Step one is executed with
garbage_collect.garbage_collectcallsgc_enter/gc_exit, these functions acquire a JIT lock and release aJIT lock. So a lock is held for the duration of step 1.
Step two is executed by
gc_compact_after_gc. It also holds a JITlock.
I believe the problem is that the JIT is free to execute between step 1
and step 2. It copies call cache values, but doesn't pin them when it
copies them. So the compactor thinks it's OK to move the call cache
even though it is not safe.
We need to hold a lock for the duration of
garbage_collectandgc_compact_after_gc. This patch introduces a lock level whichincrements and decrements. The compaction function can increment and
decrement the lock level and prevent MJIT from executing during both
steps.