summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAkira TAGOH <akira@tagoh.org>2006-11-12 14:29:16 +0000
committerAkira TAGOH <akira@tagoh.org>2006-11-12 14:29:16 +0000
commitbe56296ac6c20e55c41118fc08a369280bc4150d (patch)
tree89ce911ce89fc07ae1e4b6ca8a25c2e44e532b1f
parentefc5c92b3698f17f31cbc225ee06d9729e683600 (diff)
* 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.
-rw-r--r--ChangeLog28
-rw-r--r--hieroglyph/hgallocator-bfit.c210
-rw-r--r--hieroglyph/hgallocator-private.h6
-rw-r--r--hieroglyph/hgmacros.h24
-rw-r--r--hieroglyph/hgmem.c89
-rw-r--r--hieroglyph/hgmem.h8
-rw-r--r--hieroglyph/hgtypes.h15
-rw-r--r--hieroglyph/operator.c2
-rw-r--r--hieroglyph/version.h.in2
-rw-r--r--hieroglyph/vm.c4
-rw-r--r--tests/snapshot.c30
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 <at@gclab.org>
+ * 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 <fcntl.h>
#include <unistd.h>
#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();