From be56296ac6c20e55c41118fc08a369280bc4150d Mon Sep 17 00:00:00 2001 From: Akira TAGOH Date: Sun, 12 Nov 2006 14:29:16 +0000 Subject: * hieroglyph/hgmem.c (hg_mem_init): remove GAllocator initialization code. (hg_mem_finalize): remove GAllocator finalization code. (hg_mem_pool_destroy): use HgList instead of GList. (hg_mem_pool_is_own_object): likewise. (hg_mem_pool_save_snapshot): save an snapshot image to the list in pool. (hg_mem_pool_get_age_of_snapshot): new function. (_hg_mem_set_flags): new function. (hg_mem_add_root_node): use HgList instead of GList. (hg_mem_remove_root_node): likewise. (hg_mem_add_pool_reference): likewise. (hg_mem_remove_pool_reference): likewise. * hieroglyph/hgallocator-bfit.c (_hg_allocator_bfit_relocate): use HgList instead of GList. (_hg_allocator_bfit_real_set_flags): new function to avoid a fail of restoring a snapshot when the unused complex objects are freed after snapping shot, because snapshot image doesn't take care of mere complex objects. (_hg_allocator_bfit_real_garbage_collection): use HgList instead of GList. (_hg_allocator_bfit_real_restore_snapshot): take an argument to adjust the amount of objects for the fudge factor. * hieroglyph/hgmacros.h (HG_MEMOBJ_GET_SNAPSHOT_AGE): add a new macro. (HG_MEMOBJ_SET_SNAPSHOT_AGE): add a new macro. --- ChangeLog | 28 ++++++ hieroglyph/hgallocator-bfit.c | 210 ++++++++++++++++++++++++++------------- hieroglyph/hgallocator-private.h | 6 +- hieroglyph/hgmacros.h | 24 +++-- hieroglyph/hgmem.c | 89 ++++++++++++----- hieroglyph/hgmem.h | 8 +- hieroglyph/hgtypes.h | 15 ++- hieroglyph/operator.c | 2 +- hieroglyph/version.h.in | 2 +- hieroglyph/vm.c | 4 +- tests/snapshot.c | 30 +++++- 11 files changed, 305 insertions(+), 113 deletions(-) diff --git a/ChangeLog b/ChangeLog index 68a1515..5a5f6fd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,33 @@ 2006-11-12 Akira TAGOH + * hieroglyph/hgmem.c (hg_mem_init): remove GAllocator initialization + code. + (hg_mem_finalize): remove GAllocator finalization code. + (hg_mem_pool_destroy): use HgList instead of GList. + (hg_mem_pool_is_own_object): likewise. + (hg_mem_pool_save_snapshot): save an snapshot image to the list in pool. + (hg_mem_pool_get_age_of_snapshot): new function. + (_hg_mem_set_flags): new function. + (hg_mem_add_root_node): use HgList instead of GList. + (hg_mem_remove_root_node): likewise. + (hg_mem_add_pool_reference): likewise. + (hg_mem_remove_pool_reference): likewise. + + * hieroglyph/hgallocator-bfit.c (_hg_allocator_bfit_relocate): + use HgList instead of GList. + (_hg_allocator_bfit_real_set_flags): new function to avoid a fail of + restoring a snapshot when the unused complex objects are freed after + snapping shot, because snapshot image doesn't take care of mere + complex objects. + + (_hg_allocator_bfit_real_garbage_collection): + use HgList instead of GList. + (_hg_allocator_bfit_real_restore_snapshot): take an argument to adjust + the amount of objects for the fudge factor. + + * hieroglyph/hgmacros.h (HG_MEMOBJ_GET_SNAPSHOT_AGE): add a new macro. + (HG_MEMOBJ_SET_SNAPSHOT_AGE): add a new macro. + * hieroglyph/hglist.c (hg_list_length): fixed an infinite loop issue. (hg_list_remove): reimplement with iterator to be simplified. diff --git a/hieroglyph/hgallocator-bfit.c b/hieroglyph/hgallocator-bfit.c index b14c847..d7bd5c2 100644 --- a/hieroglyph/hgallocator-bfit.c +++ b/hieroglyph/hgallocator-bfit.c @@ -48,7 +48,7 @@ struct _HieroGlyphAllocatorBFitPrivate { HgBTree *free_block_tree; GPtrArray *heap2block_array; HgBTree *obj2block_tree; - gint age_of_snapshot; + guint n_complex_objects; }; struct _HieroGlyphMemBFitBlock { @@ -82,13 +82,16 @@ static void _hg_allocator_bfit_real_free (HgMemPool static gpointer _hg_allocator_bfit_real_resize (HgMemObject *object, gsize size); static gsize _hg_allocator_bfit_real_get_size (HgMemObject *object); +static void _hg_allocator_bfit_real_set_flags (HgMemObject *object, + guint flags); static gboolean _hg_allocator_bfit_real_garbage_collection(HgMemPool *pool); static void _hg_allocator_bfit_real_gc_mark (HgMemPool *pool); static gboolean _hg_allocator_bfit_real_is_safe_object (HgMemPool *pool, HgMemObject *object); static HgMemSnapshot *_hg_allocator_bfit_real_save_snapshot (HgMemPool *pool); static gboolean _hg_allocator_bfit_real_restore_snapshot (HgMemPool *pool, - HgMemSnapshot *snapshot); + HgMemSnapshot *snapshot, + guint adjuster); static void _hg_allocator_bfit_snapshot_real_free (gpointer data); static void _hg_allocator_bfit_snapshot_real_set_flags(gpointer data, guint flags); @@ -105,6 +108,7 @@ static HgAllocatorVTable __hg_allocator_bfit_vtable = { .free = _hg_allocator_bfit_real_free, .resize = _hg_allocator_bfit_real_resize, .get_size = _hg_allocator_bfit_real_get_size, + .set_flags = _hg_allocator_bfit_real_set_flags, .garbage_collection = _hg_allocator_bfit_real_garbage_collection, .gc_mark = _hg_allocator_bfit_real_gc_mark, .is_safe_object = _hg_allocator_bfit_real_is_safe_object, @@ -195,13 +199,13 @@ _hg_allocator_bfit_remove_block(HgAllocatorBFitPrivate *priv, HG_MEM_ALIGNMENT, aligned); if ((l = hg_btree_find(priv->free_block_tree, GSIZE_TO_POINTER (aligned))) == NULL) { - hg_log_warning("[BUG] there are no memory chunks sized %" G_GSIZE_FORMAT " (aligned size: %" G_GSIZE_FORMAT ".\n", + hg_log_warning("[BUG] there are no memory chunks sized %" G_GSIZE_FORMAT " (aligned size: %" G_GSIZE_FORMAT ".", block->length, aligned); } else { HgListIter iter = hg_list_find_iter(l, block); if (iter == NULL) { - hg_log_warning("[BUG] can't find a memory block %p (size: %" G_GSIZE_FORMAT ", aligned size: %" G_GSIZE_FORMAT ".\n", + hg_log_warning("[BUG] can't find a memory block %p (size: %" G_GSIZE_FORMAT ", aligned size: %" G_GSIZE_FORMAT ".", block, block->length, aligned); } else { l = hg_list_iter_delete_link(iter); @@ -346,43 +350,50 @@ _hg_allocator_bfit_relocate(HgMemPool *pool, { HgAllocatorBFitPrivate *priv = pool->allocator->private; gsize header_size = sizeof (HgMemObject); - GList *list, *reflist; HgMemObject *obj, *new_obj; HgObject *hobj; - gpointer p; + gpointer p, data; + HgListIter iter; if (pool->is_processing) return; pool->is_processing = TRUE; /* relocate the addresses in the root node */ - for (list = pool->root_node; list != NULL; list = g_list_next(list)) { - if ((gsize)list->data >= info->start && - (gsize)list->data <= info->end) { - list->data = (gpointer)((gsize)list->data + info->diff); - } else { - const HgObjectVTable const *vtable; - HgMemObject *obj; + if (pool->root_node) { + iter = hg_list_iter_new(pool->root_node); + do { + data = hg_list_iter_get_data(iter); + if ((gsize)data >= info->start && + (gsize)data <= info->end) { + hg_list_iter_set_data(iter, (gpointer)((gsize)data + info->diff)); + } else { + const HgObjectVTable const *vtable; + HgMemObject *obj; - /* object that is targetted for relocation will relocates - * their member variables later. so we need to ensure - * the relocation for others. - */ - hobj = (HgObject *)list->data; - hg_mem_get_object__inline(hobj, obj); - if (obj != NULL && HG_MEMOBJ_IS_HGOBJECT (obj) && - (vtable = hg_object_get_vtable(hobj)) != NULL && - vtable->relocate) { - vtable->relocate(hobj, info); + /* object that is targetted for relocation will relocates + * their member variables later. so we need to ensure + * the relocation for others. + */ + hobj = (HgObject *)data; + hg_mem_get_object__inline(hobj, obj); + if (obj != NULL && HG_MEMOBJ_IS_HGOBJECT (obj) && + (vtable = hg_object_get_vtable(hobj)) != NULL && + vtable->relocate) { + vtable->relocate(hobj, info); + } } - } + } while (hg_list_get_iter_next(pool->root_node, iter)); + hg_list_iter_free(iter); } /* relocate the addresses in another pool */ - for (reflist = pool->other_pool_ref_list; - reflist != NULL; - reflist = g_list_next(reflist)) { - /* recursively invoke relocate in another pool. */ - _hg_allocator_bfit_relocate(reflist->data, info); + if (pool->other_pool_ref_list) { + iter = hg_list_iter_new(pool->other_pool_ref_list); + do { + /* recursively invoke relocate in another pool. */ + _hg_allocator_bfit_relocate(hg_list_iter_get_data(iter), info); + } while (hg_list_get_iter_next(pool->other_pool_ref_list, iter)); + hg_list_iter_free(iter); } /* relocate the addresses in the stack */ for (p = _hg_stack_start; p > _hg_stack_end; p--) { @@ -444,7 +455,7 @@ _hg_allocator_bfit_real_initialize(HgMemPool *pool, priv->free_block_tree = hg_btree_new(BTREE_N_NODE); priv->heap2block_array = g_ptr_array_new(); priv->obj2block_tree = hg_btree_new(BTREE_N_NODE); - priv->age_of_snapshot = 0; + priv->n_complex_objects = 0; g_ptr_array_add(priv->heap2block_array, block); _hg_allocator_bfit_add_free_block(priv, block); @@ -573,6 +584,9 @@ _hg_allocator_bfit_real_alloc(HgMemPool *pool, HG_MEMOBJ_SET_HEAP_ID (obj, block->heap_id); if ((flags & HG_FL_HGOBJECT) != 0) HG_MEMOBJ_SET_HGOBJECT_ID (obj); + if ((flags & HG_FL_COMPLEX) != 0) + priv->n_complex_objects++; + HG_MEMOBJ_SET_SNAPSHOT_AGE (obj, hg_mem_pool_get_age_of_snapshot(pool)); HG_MEMOBJ_SET_FLAGS (obj, flags); hg_btree_add(priv->obj2block_tree, block->heap_fragment, block); @@ -605,6 +619,22 @@ _hg_allocator_bfit_real_free(HgMemPool *pool, data, block); return; } + if ((HG_MEMOBJ_GET_FLAGS (obj) & HG_FL_COMPLEX) == HG_FL_COMPLEX) { + guint8 age = HG_MEMOBJ_GET_SNAPSHOT_AGE (obj); + HgListIter iter; + + priv->n_complex_objects--; + if (pool->snapshot_list) { + iter = hg_list_iter_new(pool->snapshot_list); + do { + HgMemSnapshot *snap = hg_list_iter_get_data(iter); + + if (snap->age > age) + snap->private = GUINT_TO_POINTER (GPOINTER_TO_UINT (snap->private) - 1); + } while (hg_list_get_iter_next(pool->snapshot_list, iter)); + hg_list_iter_free(iter); + } + } hg_btree_remove(priv->obj2block_tree, block->heap_fragment); pool->used_heap_size -= block->length; _hg_allocator_bfit_add_free_block(priv, block); @@ -706,13 +736,27 @@ _hg_allocator_bfit_real_get_size(HgMemObject *object) return block->length; } +static void +_hg_allocator_bfit_real_set_flags(HgMemObject *object, + guint flags) +{ + HgAllocatorBFitPrivate *priv = object->pool->allocator->private; + + if ((flags & HG_FL_COMPLEX) == HG_FL_COMPLEX) { + if ((HG_MEMOBJ_GET_FLAGS (object) & HG_FL_COMPLEX) == 0) + priv->n_complex_objects++; + } else if ((HG_MEMOBJ_GET_FLAGS (object) & HG_FL_COMPLEX) == HG_FL_COMPLEX) { + priv->n_complex_objects--; + } +} + static gboolean _hg_allocator_bfit_real_garbage_collection(HgMemPool *pool) { HgAllocatorBFitPrivate *priv = pool->allocator->private; guint i; gboolean retval = FALSE; - GList *reflist; + HgListIter iter; #ifdef DEBUG guint total = 0, swept = 0; #endif /* DEBUG */ @@ -727,14 +771,16 @@ _hg_allocator_bfit_real_garbage_collection(HgMemPool *pool) pool->age_of_gc_mark++; if (!pool->destroyed) { /* increase an age of mark in another pool too */ - for (reflist = pool->other_pool_ref_list; - reflist != NULL; - reflist = g_list_next(reflist)) { - HgMemPool *p = reflist->data; + if (pool->other_pool_ref_list) { + iter = hg_list_iter_new(pool->other_pool_ref_list); + do { + HgMemPool *p = hg_list_iter_get_data(iter); - p->age_of_gc_mark++; - if (p->age_of_gc_mark == 0) p->age_of_gc_mark++; + if (p->age_of_gc_mark == 0) + p->age_of_gc_mark++; + } while (hg_list_get_iter_next(pool->other_pool_ref_list, iter)); + hg_list_iter_free(iter); } } hg_log_debug(DEBUG_GC, "starting GC for %s", pool->name); @@ -798,31 +844,42 @@ _hg_allocator_bfit_real_gc_mark(HgMemPool *pool) hg_log_debug(DEBUG_GC, "MARK AGE: %d (%s)", pool->age_of_gc_mark, pool->name); G_STMT_START { - GList *list, *reflist; + HgListIter iter; HgMemObject *obj; jmp_buf env; /* trace the root node */ - for (list = pool->root_node; list != NULL; list = g_list_next(list)) { - hg_mem_get_object__inline(list->data, obj); - if (obj == NULL) { - hg_log_warning("[BUG] Invalid object %p is in the root node.", list->data); - } else { - if (!hg_mem_is_gc_mark__inline(obj)) { - hg_mem_gc_mark__inline(obj); - hg_log_debug(DEBUG_GC, "MARK: %p (mem: %p age: %d) from root node.", obj->data, obj, HG_MEMOBJ_GET_MARK_AGE (obj)); + if (pool->root_node) { + iter = hg_list_iter_new(pool->root_node); + do { + gpointer p = hg_list_iter_get_data(iter); + + hg_mem_get_object__inline(p, obj); + if (obj == NULL) { + hg_log_warning("[BUG] Invalid object %p is in the root node.", + p); } else { - hg_log_debug(DEBUG_GC, "MARK[already]: %p (mem: %p age: %d) from root node.", obj->data, obj, HG_MEMOBJ_GET_MARK_AGE (obj)); + if (!hg_mem_is_gc_mark__inline(obj)) { + hg_mem_gc_mark__inline(obj); + hg_log_debug(DEBUG_GC, "MARK: %p (mem: %p age: %d) from root node.", obj->data, obj, HG_MEMOBJ_GET_MARK_AGE (obj)); + } else { + hg_log_debug(DEBUG_GC, "MARK[already]: %p (mem: %p age: %d) from root node.", obj->data, obj, HG_MEMOBJ_GET_MARK_AGE (obj)); + } } - } + } while (hg_list_get_iter_next(pool->root_node, iter)); + hg_list_iter_free(iter); } /* trace another pool */ - for (reflist = pool->other_pool_ref_list; - reflist != NULL; - reflist = g_list_next(reflist)) { - hg_log_debug(DEBUG_GC, "entering %s", ((HgMemPool *)reflist->data)->name); - ((HgMemPool *)reflist->data)->allocator->vtable->gc_mark(reflist->data); - hg_log_debug(DEBUG_GC, "leaving %s", ((HgMemPool *)reflist->data)->name); + if (pool->other_pool_ref_list) { + iter = hg_list_iter_new(pool->other_pool_ref_list); + do { + gpointer p = hg_list_iter_get_data(iter); + + hg_log_debug(DEBUG_GC, "entering %s", ((HgMemPool *)p)->name); + ((HgMemPool *)p)->allocator->vtable->gc_mark(p); + hg_log_debug(DEBUG_GC, "leaving %s", ((HgMemPool *)p)->name); + } while (hg_list_get_iter_next(pool->other_pool_ref_list, iter)); + hg_list_iter_free(iter); } /* trace in the registers */ setjmp(env); @@ -854,6 +911,14 @@ _hg_allocator_bfit_real_save_snapshot(HgMemPool *pool) guint i; hg_mem_garbage_collection(pool); + /* XXX: maybe need to improve this detection. + * right now the snapshot age depends on the order of releasing + * a snapshot image. need better to manage the age of snapshot. + */ + if (pool->snapshot_list && hg_list_length(pool->snapshot_list) >= 255) { + hg_log_warning("Too many snapshot are creating."); + return NULL; + } for (i = 0; i < pool->n_heaps; i++) { gpointer start, end, top; HgMemBFitBlock *block, *prev; @@ -862,12 +927,14 @@ _hg_allocator_bfit_real_save_snapshot(HgMemPool *pool) #define _is_targeted_block(_heap) \ ((HG_MEMOBJ_GET_FLAGS ((HgMemObject *)_heap) & \ HG_FL_RESTORABLE) == HG_FL_RESTORABLE) +#define _skip_non_restorable_block(_block) \ + while ((_block) != NULL && \ + ((_block)->in_use == 0 || \ + !_is_targeted_block ((_block)->heap_fragment))) \ + (_block) = (_block)->next; block = g_ptr_array_index(priv->heap2block_array, i); - while (block != NULL && - (block->in_use == 0 || - !_is_targeted_block (block->heap_fragment))) - block = block->next; + _skip_non_restorable_block(block); if (block != NULL) top = block->heap_fragment; @@ -889,10 +956,7 @@ _hg_allocator_bfit_real_save_snapshot(HgMemPool *pool) } prev_chunk = chunk; - while (block != NULL && - (block->in_use == 0 || - !_is_targeted_block (block->heap_fragment))) - block = block->next; + _skip_non_restorable_block(block); } g_ptr_array_add(heaps_list, beginning_of_chunk); } @@ -909,8 +973,10 @@ _hg_allocator_bfit_real_save_snapshot(HgMemPool *pool) retval->id = (gsize)pool; retval->heap_list = heaps_list; retval->n_heaps = pool->n_heaps; - retval->age = priv->age_of_snapshot++; + retval->age = ++pool->age_of_snapshot; + retval->private = GUINT_TO_POINTER (priv->n_complex_objects); +#undef _skip_non_restorable_block #undef _is_targeted_block return retval; @@ -918,14 +984,20 @@ _hg_allocator_bfit_real_save_snapshot(HgMemPool *pool) static gboolean _hg_allocator_bfit_real_restore_snapshot(HgMemPool *pool, - HgMemSnapshot *snapshot) + HgMemSnapshot *snapshot, + guint adjuster) { HgAllocatorBFitPrivate *priv = pool->allocator->private; gboolean retval = TRUE; gint i; + hg_mem_garbage_collection(pool); /* just ignore the older children snapshots */ - if (snapshot->age < priv->age_of_snapshot) { + if (snapshot->age <= hg_mem_pool_get_age_of_snapshot(pool)) { + if ((GPOINTER_TO_UINT (snapshot->private) + adjuster) != priv->n_complex_objects) { + hg_log_debug(DEBUG_SNAPSHOT, "there are complex objects being alive. [%u %u]", GPOINTER_TO_UINT (snapshot->private) + adjuster, priv->n_complex_objects); + return FALSE; + } for (i = 0; i < snapshot->n_heaps; i++) { HgSnapshotChunk *chunk = g_ptr_array_index(snapshot->heap_list, i), *tmp; HgMemBFitBlock *block = g_ptr_array_index(priv->heap2block_array, i); @@ -939,7 +1011,7 @@ _hg_allocator_bfit_real_restore_snapshot(HgMemPool *pool, _hg_bfit_snapshot_chunk_free(tmp); } } - priv->age_of_snapshot = snapshot->age; + pool->age_of_snapshot = snapshot->age; snapshot->n_heaps = 0; g_ptr_array_free(snapshot->heap_list, TRUE); @@ -947,7 +1019,6 @@ _hg_allocator_bfit_real_restore_snapshot(HgMemPool *pool, snapshot->age = 0; retval = TRUE; } - hg_mem_garbage_collection(pool); return retval; } @@ -959,6 +1030,11 @@ _hg_allocator_bfit_snapshot_real_free(gpointer data) HgMemSnapshot *snapshot = data; HgSnapshotChunk *chunk, *tmp; gint i; + HgMemObject *obj; + + hg_mem_get_object__inline(data, obj); + if (obj->pool->snapshot_list) + obj->pool->snapshot_list = hg_list_remove(obj->pool->snapshot_list, snapshot); if (snapshot->heap_list) { for (i = 0; i < snapshot->n_heaps; i++) { diff --git a/hieroglyph/hgallocator-private.h b/hieroglyph/hgallocator-private.h index bcd4cc7..d7f0ca2 100644 --- a/hieroglyph/hgallocator-private.h +++ b/hieroglyph/hgallocator-private.h @@ -57,12 +57,14 @@ struct _HieroGlyphMemPool { gsize total_heap_size; gsize used_heap_size; HgAllocator *allocator; - GList *root_node; - GList *other_pool_ref_list; + HgList *root_node; + HgList *other_pool_ref_list; + HgList *snapshot_list; guint access_mode; guint flags; gshort gc_threshold; guint8 age_of_gc_mark; + guint8 age_of_snapshot; gboolean destroyed : 1; gboolean periodical_gc : 1; gboolean gc_checked : 1; diff --git a/hieroglyph/hgmacros.h b/hieroglyph/hgmacros.h index 3b54fa5..c406bbb 100644 --- a/hieroglyph/hgmacros.h +++ b/hieroglyph/hgmacros.h @@ -53,31 +53,43 @@ G_BEGIN_DECLS /* HgMemObject */ #define HG_MEMOBJ_HEAP_ID_MASK 0xff000000 #define HG_MEMOBJ_MARK_AGE_MASK 0x00ff0000 -#define HG_MEMOBJ_HGOBJECT_MASK 0x00008000 -#define HG_MEMOBJ_FLAGS_MASK 0x00007fff +#define HG_MEMOBJ_SNAPSHOT_AGE_MASK 0x0000ff00 +#define HG_MEMOBJ_HGOBJECT_MASK 0x00000080 +#define HG_MEMOBJ_FLAGS_MASK 0x0000007f #define HG_MEMOBJ_GET_HEAP_ID(_obj) (((_obj)->flags & HG_MEMOBJ_HEAP_ID_MASK) >> 24) #define HG_MEMOBJ_SET_HEAP_ID(_obj, _id) \ ((_obj)->flags = (((_id) << 24) & HG_MEMOBJ_HEAP_ID_MASK) \ | (HG_MEMOBJ_GET_MARK_AGE (_obj) << 16) \ - | (HG_MEMOBJ_GET_HGOBJECT_ID (_obj) << 15) \ + | (HG_MEMOBJ_GET_SNAPSHOT_AGE (_obj) << 8) \ + | (HG_MEMOBJ_GET_HGOBJECT_ID (_obj) << 7) \ | HG_MEMOBJ_GET_FLAGS (_obj)) #define HG_MEMOBJ_GET_MARK_AGE(_obj) (((_obj)->flags & HG_MEMOBJ_MARK_AGE_MASK) >> 16) #define HG_MEMOBJ_SET_MARK_AGE(_obj, _age) \ ((_obj)->flags = (HG_MEMOBJ_GET_HEAP_ID (_obj) << 24) \ | (((_age) << 16) & HG_MEMOBJ_MARK_AGE_MASK) \ - | (HG_MEMOBJ_GET_HGOBJECT_ID (_obj) << 15) \ + | (HG_MEMOBJ_GET_SNAPSHOT_AGE (_obj) << 8) \ + | (HG_MEMOBJ_GET_HGOBJECT_ID (_obj) << 7) \ | HG_MEMOBJ_GET_FLAGS (_obj)) -#define HG_MEMOBJ_GET_HGOBJECT_ID(_obj) (((_obj)->flags & HG_MEMOBJ_HGOBJECT_MASK) >> 15) +#define HG_MEMOBJ_GET_SNAPSHOT_AGE(_obj) (((_obj)->flags & HG_MEMOBJ_SNAPSHOT_AGE_MASK) >> 8) +#define HG_MEMOBJ_SET_SNAPSHOT_AGE(_obj, _age) \ + ((_obj)->flags = (HG_MEMOBJ_GET_HEAP_ID (_obj) << 24) \ + | (HG_MEMOBJ_GET_MARK_AGE (_obj) << 16) \ + | (((_age) << 8) & HG_MEMOBJ_SNAPSHOT_AGE_MASK) \ + | (HG_MEMOBJ_GET_HGOBJECT_ID (_obj) << 7) \ + | HG_MEMOBJ_GET_FLAGS (_obj)) +#define HG_MEMOBJ_GET_HGOBJECT_ID(_obj) (((_obj)->flags & HG_MEMOBJ_HGOBJECT_MASK) >> 7) #define HG_MEMOBJ_SET_HGOBJECT_ID(_obj) \ ((_obj)->flags = (HG_MEMOBJ_GET_HEAP_ID (_obj) << 24) \ | (HG_MEMOBJ_GET_MARK_AGE (_obj) << 16) \ + | (HG_MEMOBJ_GET_SNAPSHOT_AGE (_obj) << 8) \ | HG_FL_HGOBJECT \ | HG_MEMOBJ_GET_FLAGS (_obj)) #define HG_MEMOBJ_GET_FLAGS(_obj) ((_obj)->flags & HG_MEMOBJ_FLAGS_MASK) #define HG_MEMOBJ_SET_FLAGS(_obj, _flags) \ ((_obj)->flags = (HG_MEMOBJ_GET_HEAP_ID (_obj) << 24) \ | (HG_MEMOBJ_GET_MARK_AGE (_obj) << 16) \ - | (HG_MEMOBJ_GET_HGOBJECT_ID (_obj) << 15) \ + | (HG_MEMOBJ_GET_SNAPSHOT_AGE (_obj) << 8) \ + | (HG_MEMOBJ_GET_HGOBJECT_ID (_obj) << 7) \ | ((_flags) & HG_MEMOBJ_FLAGS_MASK)) #define HG_MEMOBJ_INIT_FLAGS(_obj) (_obj)->flags = 0; #define HG_MEMOBJ_IS_HGOBJECT(_obj) (HG_MEMOBJ_GET_HGOBJECT_ID (_obj) == 1) diff --git a/hieroglyph/hgmem.c b/hieroglyph/hgmem.c index 10bca0d..e7b1266 100644 --- a/hieroglyph/hgmem.c +++ b/hieroglyph/hgmem.c @@ -29,6 +29,7 @@ #include #include #include "hgmem.h" +#include "ilist.h" #include "hgallocator-private.h" #include "hglog.h" @@ -37,7 +38,6 @@ gpointer _hg_stack_start = NULL; gpointer _hg_stack_end = NULL; static gboolean hg_mem_is_initialized = FALSE; -static GAllocator *hg_mem_g_list_allocator = NULL; static GHashTable *_hg_object_vtable_tree = NULL; static GPtrArray *_hg_object_vtable_array = NULL; @@ -180,10 +180,6 @@ hg_mem_init(void) g_return_if_fail (_hg_stack_start != NULL); if (!hg_mem_is_initialized) { - if (!hg_mem_g_list_allocator) { - hg_mem_g_list_allocator = g_allocator_new("Default GAllocator for GList", 128); - g_list_push_allocator(hg_mem_g_list_allocator); - } if (!_hg_object_vtable_tree) { _hg_object_vtable_tree = g_hash_table_new(NULL, g_direct_equal); if (_hg_object_vtable_tree == NULL) { @@ -200,11 +196,8 @@ void hg_mem_finalize(void) { if (hg_mem_is_initialized) { - g_list_pop_allocator(); - g_allocator_free(hg_mem_g_list_allocator); g_hash_table_destroy(_hg_object_vtable_tree); g_ptr_array_free(_hg_object_vtable_array, TRUE); - hg_mem_g_list_allocator = NULL; _hg_object_vtable_tree = NULL; _hg_object_vtable_array = NULL; hg_mem_is_initialized = FALSE; @@ -255,6 +248,7 @@ hg_mem_pool_new(HgAllocator *allocator, pool->allocator = allocator; pool->root_node = NULL; pool->other_pool_ref_list = NULL; + pool->snapshot_list = NULL; pool->periodical_gc = FALSE; pool->gc_checked = FALSE; pool->use_gc = TRUE; @@ -262,6 +256,7 @@ hg_mem_pool_new(HgAllocator *allocator, pool->is_collecting = FALSE; pool->gc_threshold = 50; pool->age_of_gc_mark = 0; + pool->age_of_snapshot = 0; allocator->used = TRUE; if (!allocator->vtable->initialize(pool, prealloc)) { _hg_mem_pool_free(pool); @@ -281,10 +276,13 @@ hg_mem_pool_destroy(HgMemPool *pool) pool->allocator->vtable->destroy(pool); } if (pool->root_node) { - g_list_free(pool->root_node); + hg_list_free(pool->root_node); } if (pool->other_pool_ref_list) { - g_list_free(pool->other_pool_ref_list); + hg_list_free(pool->other_pool_ref_list); + } + if (pool->snapshot_list) { + hg_list_free(pool->snapshot_list); } pool->allocator->used = FALSE; _hg_mem_pool_free(pool); @@ -411,6 +409,7 @@ hg_mem_pool_is_own_object(HgMemPool *pool, gpointer data) { HgMemObject *obj; + HgListIter iter; g_return_val_if_fail (pool != NULL, FALSE); @@ -419,8 +418,9 @@ hg_mem_pool_is_own_object(HgMemPool *pool, return TRUE; } hg_mem_get_object__inline(data, obj); - if (g_list_find(obj->pool->root_node, data) != NULL) { + if ((iter = hg_list_find_iter(obj->pool->root_node, data)) != NULL) { /* We privilege the object that is already in the root node */ + hg_list_iter_free(iter); return TRUE; } @@ -430,21 +430,37 @@ hg_mem_pool_is_own_object(HgMemPool *pool, HgMemSnapshot * hg_mem_pool_save_snapshot(HgMemPool *pool) { + HgMemSnapshot *retval; + g_return_val_if_fail (pool != NULL, NULL); g_return_val_if_fail (pool->allocator->vtable->save_snapshot != NULL, NULL); - return pool->allocator->vtable->save_snapshot(pool); + retval = pool->allocator->vtable->save_snapshot(pool); + if (pool->snapshot_list == NULL) + pool->snapshot_list = hg_list_new(); + pool->snapshot_list = hg_list_append(pool->snapshot_list, retval); + + return retval; +} + +guint8 +hg_mem_pool_get_age_of_snapshot(HgMemPool *pool) +{ + g_return_val_if_fail (pool != NULL, 0); + + return pool->age_of_snapshot; } gboolean hg_mem_pool_restore_snapshot(HgMemPool *pool, - HgMemSnapshot *snapshot) + HgMemSnapshot *snapshot, + guint adjuster) { g_return_val_if_fail (pool != NULL, FALSE); g_return_val_if_fail (snapshot != NULL, FALSE); g_return_val_if_fail (pool->allocator->vtable->restore_snapshot != NULL, FALSE); - return pool->allocator->vtable->restore_snapshot(pool, snapshot); + return pool->allocator->vtable->restore_snapshot(pool, snapshot, adjuster); } gboolean @@ -582,6 +598,15 @@ hg_mem_get_object_size(gpointer data) return obj->pool->allocator->vtable->get_size(obj); } +void +_hg_mem_set_flags(HgMemObject *object, + guint flags) +{ + if (object->pool->allocator->vtable->set_flags) + object->pool->allocator->vtable->set_flags(object, flags); + HG_MEMOBJ_SET_FLAGS (object, flags); +} + /* GC */ guint8 hg_mem_pool_get_age_of_mark(HgMemPool *pool) @@ -610,19 +635,19 @@ hg_mem_gc_mark_array_region(HgMemPool *pool, obj = hg_mem_get_object__inline_nocheck(*(gsize *)p); if (pool->allocator->vtable->is_safe_object(pool, obj)) { if (!hg_mem_is_gc_mark__inline(obj)) { - hg_log_debug(DEBUG_GC, "MARK: %p (mem: %p age: %d) from array region.\n", obj->data, obj, HG_MEMOBJ_GET_MARK_AGE (obj)); + hg_log_debug(DEBUG_GC, "MARK: %p (mem: %p age: %d) from array region.", obj->data, obj, HG_MEMOBJ_GET_MARK_AGE (obj)); hg_mem_gc_mark__inline(obj); } else { - hg_log_debug(DEBUG_GC, "MARK[already]: %p (mem: %p) from array region.\n", obj->data, obj); + hg_log_debug(DEBUG_GC, "MARK[already]: %p (mem: %p) from array region.", obj->data, obj); } } obj = p; if (pool->allocator->vtable->is_safe_object(pool, obj)) { if (!hg_mem_is_gc_mark__inline(obj)) { - hg_log_debug(DEBUG_GC, "MARK: %p (mem: %p) from array region.\n", obj->data, obj); + hg_log_debug(DEBUG_GC, "MARK: %p (mem: %p) from array region.", obj->data, obj); hg_mem_gc_mark__inline(obj); } else { - hg_log_debug(DEBUG_GC, "MARK[already]: %p (mem: %p) from array region.\n", obj->data, obj); + hg_log_debug(DEBUG_GC, "MARK[already]: %p (mem: %p) from array region.", obj->data, obj); } } } @@ -632,7 +657,9 @@ void hg_mem_add_root_node(HgMemPool *pool, gpointer data) { - pool->root_node = g_list_append(pool->root_node, data); + if (pool->root_node == NULL) + pool->root_node = hg_list_new(); + pool->root_node = hg_list_append(pool->root_node, data); } void @@ -647,20 +674,30 @@ hg_mem_remove_root_node(HgMemPool *pool, g_return_if_fail (obj != NULL); g_return_if_fail (_hg_mem_pool_is_own_memobject(pool, obj)); - pool->root_node = g_list_remove(pool->root_node, data); + pool->root_node = hg_list_remove(pool->root_node, data); } void hg_mem_add_pool_reference(HgMemPool *pool, HgMemPool *other_pool) { + HgListIter iter = NULL; + g_return_if_fail (pool != NULL); g_return_if_fail (other_pool != NULL); g_return_if_fail (pool != other_pool); /* to avoid the loop */ - if (g_list_find(pool->other_pool_ref_list, other_pool) == NULL) - pool->other_pool_ref_list = g_list_append(pool->other_pool_ref_list, - other_pool); + if (pool->other_pool_ref_list == NULL) { + pool->other_pool_ref_list = hg_list_new(); + pool->other_pool_ref_list = hg_list_append(pool->other_pool_ref_list, + other_pool); + } else { + if ((iter = hg_list_find_iter(pool->other_pool_ref_list, other_pool)) == NULL) + pool->other_pool_ref_list = hg_list_append(pool->other_pool_ref_list, + other_pool); + if (iter) + hg_list_iter_free(iter); + } } void @@ -670,7 +707,7 @@ hg_mem_remove_pool_reference(HgMemPool *pool, g_return_if_fail (pool != NULL); g_return_if_fail (other_pool != NULL); - pool->other_pool_ref_list = g_list_remove(pool->other_pool_ref_list, other_pool); + pool->other_pool_ref_list = hg_list_remove(pool->other_pool_ref_list, other_pool); } /* HgObject */ @@ -759,7 +796,7 @@ hg_object_get_vtable(HgObject *object) return NULL; } if (id > _hg_object_vtable_array->len) { - hg_log_warning("[BUG] Invalid vtable ID found: %p id: %d latest id: %u\n", + hg_log_warning("[BUG] Invalid vtable ID found: %p id: %d latest id: %u", object, id, _hg_object_vtable_array->len); return NULL; @@ -787,7 +824,7 @@ hg_object_set_vtable(HgObject *object, g_hash_table_insert(_hg_object_vtable_tree, (gpointer)vtable, GUINT_TO_POINTER (id)); } if (id > 255) { - hg_log_warning("[BUG] Invalid vtable ID found in tree: %p id %u\n", object, id); + hg_log_warning("[BUG] Invalid vtable ID found in tree: %p id %u", object, id); id = 0; } HG_OBJECT_SET_VTABLE_ID (object, id); diff --git a/hieroglyph/hgmem.h b/hieroglyph/hgmem.h index f25fa93..f9588d5 100644 --- a/hieroglyph/hgmem.h +++ b/hieroglyph/hgmem.h @@ -72,7 +72,9 @@ gboolean hg_mem_pool_is_own_object (HgMemPool *pool, gpointer data); HgMemSnapshot *hg_mem_pool_save_snapshot (HgMemPool *pool); gboolean hg_mem_pool_restore_snapshot (HgMemPool *pool, - HgMemSnapshot *snapshot); + HgMemSnapshot *snapshot, + guint adjuster); +guint8 hg_mem_pool_get_age_of_snapshot (HgMemPool *pool); gboolean hg_mem_garbage_collection (HgMemPool *pool); gpointer hg_mem_alloc (HgMemPool *pool, gsize size); @@ -87,6 +89,8 @@ gsize hg_mem_get_object_size (gpointer data); /* internal use */ gboolean _hg_mem_pool_is_own_memobject (HgMemPool *pool, HgMemObject *obj); +void _hg_mem_set_flags (HgMemObject *object, + guint flags); /* GC */ #define hg_mem_is_flags__inline(__obj__, __flags__) \ @@ -110,7 +114,7 @@ gboolean _hg_mem_pool_is_own_memobject (HgMemPool *pool, } else if ((__flags__) > HG_MEMOBJ_FLAGS_MASK) { \ g_warning("[BUG] Invalid flags to not be set by hg_mem_set_flags: (possibly hgobject id) %X", (__flags__)); \ } else { \ - HG_MEMOBJ_SET_FLAGS ((__obj__), (__flags__)); \ + _hg_mem_set_flags((__obj__), (__flags__)); \ } \ if ((__notify__) && \ HG_MEMOBJ_IS_HGOBJECT (__obj__) && \ diff --git a/hieroglyph/hgtypes.h b/hieroglyph/hgtypes.h index f9da6a9..19aa092 100644 --- a/hieroglyph/hgtypes.h +++ b/hieroglyph/hgtypes.h @@ -121,7 +121,15 @@ typedef enum { HG_FL_LOCK = 1 << 2, /* no infect */ HG_FL_COPYING = 1 << 3, /* no infect */ HG_FL_DEAD = 1 << 4, /* no infect */ - HG_FL_HGOBJECT = 1 << 15, /* mark for HgObject */ + HG_FL_HGOBJECT = 1 << 7, /* mark for HgObject */ + HG_FL_SNAPSHOT1 = 1 << 8, /* reserved for age of snapshot */ + HG_FL_SNAPSHOT2 = 1 << 9, /* reserved for age of snapshot */ + HG_FL_SNAPSHOT3 = 1 << 10, /* reserved for age of snapshot */ + HG_FL_SNAPSHOT4 = 1 << 11, /* reserved for age of snapshot */ + HG_FL_SNAPSHOT5 = 1 << 12, /* reserved for age of snapshot */ + HG_FL_SNAPSHOT6 = 1 << 13, /* reserved for age of snapshot */ + HG_FL_SNAPSHOT7 = 1 << 14, /* reserved for age of snapshot */ + HG_FL_SNAPSHOT8 = 1 << 15, /* reserved for age of snapshot */ HG_FL_MARK1 = 1 << 16, /* infect all child objects - reserved for age of mark */ HG_FL_MARK2 = 1 << 17, /* infect all child objects - reserved for age of mark */ HG_FL_MARK3 = 1 << 18, /* infect all child objects - reserved for age of mark */ @@ -311,13 +319,16 @@ struct _HieroGlyphAllocatorVTable { gpointer (* resize) (HgMemObject *object, gsize size); gsize (* get_size) (HgMemObject *object); + void (* set_flags) (HgMemObject *object, + guint flags); gboolean (* garbage_collection) (HgMemPool *pool); void (* gc_mark) (HgMemPool *pool); gboolean (* is_safe_object) (HgMemPool *pool, HgMemObject *object); HgMemSnapshot * (* save_snapshot) (HgMemPool *pool); gboolean (* restore_snapshot) (HgMemPool *pool, - HgMemSnapshot *snapshot); + HgMemSnapshot *snapshot, + guint adjuster); }; struct _HieroGlyphAllocator { diff --git a/hieroglyph/operator.c b/hieroglyph/operator.c index 7db1742..f1aa6db 100644 --- a/hieroglyph/operator.c +++ b/hieroglyph/operator.c @@ -5239,7 +5239,7 @@ G_STMT_START hg_vm_use_global_pool(vm, FALSE); pool = hg_vm_get_current_pool(vm); hg_vm_use_global_pool(vm, global_mode); - retval = hg_mem_pool_restore_snapshot(pool, snapshot); + retval = hg_mem_pool_restore_snapshot(pool, snapshot, 1); if (!retval) { _hg_operator_set_error(vm, op, VM_e_invalidrestore); break; diff --git a/hieroglyph/version.h.in b/hieroglyph/version.h.in index db1f2ba..a05355a 100644 --- a/hieroglyph/version.h.in +++ b/hieroglyph/version.h.in @@ -29,7 +29,7 @@ G_BEGIN_DECLS #define HIEROGLYPH_VERSION "@VERSION@" -#define HIEROGLYPH_UUID "be34594e-1d16-42e7-81fa-738241b37d81" +#define HIEROGLYPH_UUID "9f5ff491-6e50-4f27-a7d9-28e9abf35205" const char *__hg_rcsid G_GNUC_UNUSED = "$Rev$"; diff --git a/hieroglyph/vm.c b/hieroglyph/vm.c index ec1bd03..bd0b2b5 100644 --- a/hieroglyph/vm.c +++ b/hieroglyph/vm.c @@ -1006,12 +1006,12 @@ hg_vm_startjob(HgVM *vm, } if (g_list_length(vm->global_snapshot) > 0) { l = g_list_last(vm->global_snapshot); - hg_mem_pool_restore_snapshot(vm->global_pool, l->data); + hg_mem_pool_restore_snapshot(vm->global_pool, l->data, 0); vm->global_snapshot = g_list_delete_link(vm->global_snapshot, l); } if (g_list_length(vm->local_snapshot) > 0) { l = g_list_last(vm->local_snapshot); - hg_mem_pool_restore_snapshot(vm->local_pool, l->data); + hg_mem_pool_restore_snapshot(vm->local_pool, l->data, 0); vm->local_snapshot = g_list_delete_link(vm->local_snapshot, l); } diff --git a/tests/snapshot.c b/tests/snapshot.c index 259ab4f..83aff90 100644 --- a/tests/snapshot.c +++ b/tests/snapshot.c @@ -57,13 +57,13 @@ foo(void) node = hg_dict_lookup(dict, key); if (node == NULL || !HG_IS_VALUE_INTEGER (node) || HG_VALUE_GET_INTEGER (node) != 20) { - g_print("Failed to lookup dict."); + g_print("Failed to lookup dict.\n"); return 1; } g_print("restoring snapshot...\n"); - if (!hg_mem_pool_restore_snapshot(pool, snap)) { - g_print("Failed to restore from snapshot."); + if (!hg_mem_pool_restore_snapshot(pool, snap, 0)) { + g_print("Failed to restore from snapshot.\n"); return 1; } node = hg_array_index(array, 0); @@ -79,9 +79,31 @@ foo(void) node = hg_dict_lookup(dict, key); if (node == NULL || !HG_IS_VALUE_BOOLEAN (node) || HG_VALUE_GET_BOOLEAN (node) != TRUE) { - g_print("Failed to lookup dict after restoring."); + g_print("Failed to lookup dict after restoring.\n"); return 1; } + + /* stage 2 */ + g_print("creating snapshot...\n"); + snap = hg_mem_pool_save_snapshot(pool); + string = hg_string_new(pool, 32); + { + HgMemObject *obj; + + hg_mem_get_object__inline(string, obj); + hg_mem_set_lock(obj); + } + if (hg_mem_pool_restore_snapshot(pool, snap, 0)) { + g_print("shouldn't be successful restoring.\n"); + return 1; + } + hg_mem_free(string); + g_print("restoring snapshot...\n"); + if (!hg_mem_pool_restore_snapshot(pool, snap, 0)) { + g_print("Failed to restore from snapshot.\n"); + return 1; + } + hg_mem_pool_destroy(pool); hg_allocator_destroy(allocator); hg_value_node_finalize(); -- cgit v1.2.3