/* Functions for if the write barriers are hit. */ MVM_PUBLIC void MVM_gc_write_barrier_hit(MVMThreadContext *tc, MVMCollectable *update_root); MVM_PUBLIC void MVM_gc_write_barrier_hit_by(MVMThreadContext *tc, MVMCollectable *update_root, MVMCollectable *referenced); /* Ensures that if a generation 2 object comes to hold a reference to a * nursery object, then the generation 2 object becomes an inter-generational * root. */ MVM_STATIC_INLINE void MVM_gc_write_barrier(MVMThreadContext *tc, MVMCollectable *update_root, MVMCollectable *referenced) { if (((update_root->flags2 & MVM_CF_SECOND_GEN) && referenced && !(referenced->flags2 & MVM_CF_SECOND_GEN))) MVM_gc_write_barrier_hit_by(tc, update_root, referenced); } MVM_STATIC_INLINE void MVM_gc_write_barrier_no_update_referenced(MVMThreadContext *tc, MVMCollectable *update_root, MVMCollectable *referenced) { if (((update_root->flags2 & MVM_CF_SECOND_GEN) && referenced && !(referenced->flags2 & MVM_CF_SECOND_GEN))) MVM_gc_write_barrier_hit(tc, update_root); } /* Does an assignment, but makes sure the write barrier MVM_WB is applied * first. Takes the root object, the address within it we're writing to, and * the thing we're writing. Note that update_addr is not involved in the * write barrier. */ #if MVM_GC_DEBUG #define MVM_ASSIGN_REF(tc, update_root, update_addr, referenced) \ { \ void *_r = referenced; \ if (_r && ((MVMCollectable *)_r)->owner == 0) \ MVM_panic(1, "Invalid assignment (maybe of heap frame to stack frame?)"); \ MVM_ASSERT_NOT_FROMSPACE(tc, _r); \ MVM_gc_write_barrier(tc, update_root, (MVMCollectable *)_r); \ update_addr = _r; \ } #else #define MVM_ASSIGN_REF(tc, update_root, update_addr, referenced) \ { \ void *_r = referenced; \ MVM_gc_write_barrier(tc, update_root, (MVMCollectable *)_r); \ update_addr = _r; \ } #endif