* alloc.c (GC_mercury_callback_reachable_object): Remove.
* include/gc.h (GC_mercury_callback_reachable_object): Likewise.
* include/private/gc_priv.h (GC_mercury_enumerate_reachable_objects):
Likewise.
* alloc.c (GC_finish_collection): Do not call
GC_mercury_enumerate_reachable_objects.
* include/gc_mark.h (GC_reachable_object_proc): New public typedef.
* include/gc_mark.h (GC_enumerate_reachable_objects_inner): New API
function declaration.
* reclaim.c (enumerate_reachable_s): New struct type.
* reclaim.c (GC_mercury_do_enumerate_reachable_objects): Rename to
GC_do_enumerate_reachable_objects; replace while() with for(); use 2nd
argument to pass client callback and custom data; call client callback
(passed via the argument) instead of
GC_mercury_callback_reachable_object; pass object size in bytes
instead of words to client callback.
* reclaim.c (GC_mercury_enumerate_reachable_objects): Rename to
GC_enumerate_reachable_objects_inner; decorate with GC_API/GC_CALL;
add 2 arguments (client callback and custom data); remove assertion
for GC_mercury_callback_reachable_object; add assertion for acquired
lock.
* tests/test.c: Include gc_mark.h unconditionally.
* tests/test.c (reachable_objs_counter,
reachable_objs_count_enumerator): New function.
* tests/test.c (check_heap_stats): New local variable "obj_count";
invoke GC_call_with_alloc_lock(reachable_objs_count_enumerator);
print final number of reachable objects.
word GC_gc_no = 0;
-void (*GC_mercury_callback_reachable_object)(GC_word *, size_t) = NULL;
- /* Callbacks for mercury to notify */
- /* the runtime of certain events */
-
#ifndef GC_DISABLE_INCREMENTAL
GC_INNER int GC_incremental = 0; /* By default, stop the world. */
#endif
}
# endif
COND_DUMP;
- if (GC_mercury_callback_reachable_object) {
- GC_mercury_enumerate_reachable_objects();
- }
if (GC_find_leak) {
/* Mark all objects on the free list. All objects should be */
/* marked when we're done. */
GC_API void GC_CALL GC_set_time_limit(unsigned long);
GC_API unsigned long GC_CALL GC_get_time_limit(void);
-GC_API void (*GC_mercury_callback_reachable_object)(GC_word *, size_t);
- /* This object on the heap is reachable. */
-
/* Public procedures */
/* Set whether the GC will allocate executable memory pages or not. */
GC_API void GC_CALL GC_set_push_other_roots(GC_push_other_roots_proc);
GC_API GC_push_other_roots_proc GC_CALL GC_get_push_other_roots(void);
+/* Walk the GC heap visiting all reachable objects. Assume the caller */
+/* holds the allocation lock. Object base pointer, object size and */
+/* client custom data are passed to the callback (holding the lock). */
+typedef void (GC_CALLBACK *GC_reachable_object_proc)(void * /* obj */,
+ size_t /* bytes */,
+ void * /* client_data */);
+GC_API void GC_CALL GC_enumerate_reachable_objects_inner(
+ GC_reachable_object_proc,
+ void * /* client_data */) GC_ATTR_NONNULL(1);
+
#ifdef __cplusplus
} /* end of extern "C" */
#endif
extern word GC_fo_entries; /* should be visible in extra/MacOS.c */
-GC_INNER void GC_mercury_enumerate_reachable_objects(void);
-
#ifdef KEEP_BACK_PTRS
GC_INNER void GC_store_back_pointer(ptr_t source, ptr_t dest);
GC_INNER void GC_marked_for_finalization(ptr_t dest);
}
#endif /* !EAGER_SWEEP && ENABLE_DISCLAIM */
-STATIC void GC_mercury_do_enumerate_reachable_objects(struct hblk *hbp,
- word dummy)
+struct enumerate_reachable_s {
+ GC_reachable_object_proc proc;
+ void *client_data;
+};
+
+STATIC void GC_do_enumerate_reachable_objects(struct hblk *hbp, word ped)
{
- struct hblkhdr * hhdr = HDR(hbp);
- size_t sz = hhdr -> hb_sz;
- size_t bit_no;
- char *p, *plim;
+ struct hblkhdr *hhdr = HDR(hbp);
+ size_t sz = hhdr -> hb_sz;
+ size_t bit_no;
+ char *p, *plim;
- if (GC_block_empty(hhdr)) {
- return;
- }
+ if (GC_block_empty(hhdr)) {
+ return;
+ }
- p = hbp->hb_body;
- bit_no = 0;
- if (sz > MAXOBJBYTES) { /* one big object */
- plim = p;
- } else {
- plim = hbp->hb_body + HBLKSIZE - sz;
- }
- /* Go through all words in block. */
- while (p <= plim) {
- if (mark_bit_from_hdr(hhdr, bit_no)) {
- GC_mercury_callback_reachable_object((GC_word *)p,
- BYTES_TO_WORDS(sz));
- }
- bit_no += MARK_BIT_OFFSET(sz);
- p += sz;
+ p = hbp->hb_body;
+ if (sz > MAXOBJBYTES) { /* one big object */
+ plim = p;
+ } else {
+ plim = hbp->hb_body + HBLKSIZE - sz;
+ }
+ /* Go through all words in block. */
+ for (bit_no = 0; p <= plim; bit_no += MARK_BIT_OFFSET(sz), p += sz) {
+ if (mark_bit_from_hdr(hhdr, bit_no)) {
+ ((struct enumerate_reachable_s *)ped)->proc(p, sz,
+ ((struct enumerate_reachable_s *)ped)->client_data);
}
+ }
}
-GC_INNER void GC_mercury_enumerate_reachable_objects(void)
+GC_API void GC_CALL GC_enumerate_reachable_objects_inner(
+ GC_reachable_object_proc proc,
+ void *client_data)
{
- GC_ASSERT(GC_mercury_callback_reachable_object);
- GC_apply_to_all_blocks(GC_mercury_do_enumerate_reachable_objects, (word)0);
+ struct enumerate_reachable_s ed;
+
+ GC_ASSERT(I_HOLD_LOCK());
+ ed.proc = proc;
+ ed.client_data = client_data;
+ GC_apply_to_all_blocks(GC_do_enumerate_reachable_objects, (word)&ed);
}
}
# endif
+#include "gc_mark.h"
+
#ifdef GC_GCJ_SUPPORT
-#include "gc_mark.h"
#include "gc_gcj.h"
/* The following struct emulates the vtable in gcj. */
GC_log_printf("Finished %p\n", (void *)&start_time);
}
+void GC_CALLBACK reachable_objs_counter(void *obj, size_t size,
+ void *pcounter)
+{
+ if (0 == size) {
+ GC_printf("Reachable object has zero size\n");
+ FAIL;
+ }
+ if (GC_base(obj) != obj) {
+ GC_printf("Invalid reachable object base passed by enumerator: %p\n",
+ obj);
+ FAIL;
+ }
+ if (GC_size(obj) != size) {
+ GC_printf("Invalid reachable object size passed by enumerator: %lu\n",
+ (unsigned long)size);
+ FAIL;
+ }
+ (*(unsigned *)pcounter)++;
+}
+
+void * GC_CALLBACK reachable_objs_count_enumerator(void *pcounter)
+{
+ GC_enumerate_reachable_objects_inner(reachable_objs_counter, pcounter);
+ return NULL;
+}
+
#define NUMBER_ROUND_UP(v, bound) ((((v) + (bound) - 1) / (bound)) * (bound))
void check_heap_stats(void)
int late_finalize_count = 0;
# endif
# endif
+ unsigned obj_count = 0;
# ifdef VERY_SMALL_CONFIG
/* The upper bounds are a guess, which has been empirically */
FAIL;
}
}
+ (void)GC_call_with_alloc_lock(reachable_objs_count_enumerator,
+ &obj_count);
GC_printf("Completed %u tests\n", n_tests);
GC_printf("Allocated %d collectable objects\n", collectable_count);
GC_printf("Allocated %d uncollectable objects\n",
(unsigned long)max_heap_sz);
FAIL;
}
+ GC_printf("Final number of reachable objects is %u\n", obj_count);
# ifndef GC_GET_HEAP_USAGE_NOT_NEEDED
/* Get global counters (just to check the functions work). */