#include "moar.h" /* Gets a stable identifier for an object, which will not change even if the * GC moves the object. */ MVMuint64 MVM_gc_object_id(MVMThreadContext *tc, MVMObject *obj) { MVMuint64 id; /* If it's already in the old generation, just use memory address, as * gen2 objects never move. */ if (obj->header.flags2 & MVM_CF_SECOND_GEN) { id = (uintptr_t)obj; } /* Otherwise, see if we already have a persistent object ID. */ else { uv_mutex_lock(&tc->instance->mutex_object_ids); if (obj->header.flags1 & MVM_CF_HAS_OBJECT_ID) { /* Has one, so just look up by address in the hash ID hash. */ struct MVMPtrHashEntry *entry = MVM_ptr_hash_fetch(tc, &tc->instance->object_ids, obj); assert(entry); id = entry->value; } else { /* Hasn't got one; allocate it a place in gen2 and make an entry * in the persistent object ID hash. */ id = (uintptr_t)MVM_gc_gen2_allocate_zeroed(tc->gen2, obj->header.size); MVM_ptr_hash_insert(tc, &tc->instance->object_ids, obj, id); obj->header.flags1 |= MVM_CF_HAS_OBJECT_ID; } uv_mutex_unlock(&tc->instance->mutex_object_ids); } return id; } /* If an object with an entry here lives long enough to be promoted to gen2, * this removes the hash entry for it and returns the pre-allocated gen2 * address. */ void * MVM_gc_object_id_use_allocation(MVMThreadContext *tc, MVMCollectable *item) { uv_mutex_lock(&tc->instance->mutex_object_ids); void *addr = (void *) MVM_ptr_hash_fetch_and_delete(tc, &tc->instance->object_ids, item); item->flags1 ^= MVM_CF_HAS_OBJECT_ID; uv_mutex_unlock(&tc->instance->mutex_object_ids); return addr; } /* Clears hash entry for a persistent object ID when an object dies in the * nursery. */ void MVM_gc_object_id_clear(MVMThreadContext *tc, MVMCollectable *item) { uv_mutex_lock(&tc->instance->mutex_object_ids); (void) MVM_ptr_hash_fetch_and_delete(tc, &tc->instance->object_ids, item); uv_mutex_unlock(&tc->instance->mutex_object_ids); }