-/*
- * sgen-gc.c: Simple generational GC.
+/**
+ * \file
+ * Simple generational GC.
*
* Author:
* Paolo Molaro (lupus@ximian.com)
#include "mono/sgen/sgen-protocol.h"
#include "mono/sgen/sgen-memory-governor.h"
#include "mono/sgen/sgen-hash-table.h"
-#include "mono/sgen/sgen-cardtable.h"
#include "mono/sgen/sgen-pinning.h"
#include "mono/sgen/sgen-workers.h"
#include "mono/sgen/sgen-client.h"
gboolean
sgen_drain_gray_stack (ScanCopyContext ctx)
{
- ScanObjectFunc scan_func = ctx.ops->scan_object;
- SgenGrayQueue *queue = ctx.queue;
+ SGEN_ASSERT (0, ctx.ops->drain_gray_stack, "Why do we have a scan/copy context with a missing drain gray stack function?");
- if (ctx.ops->drain_gray_stack)
- return ctx.ops->drain_gray_stack (queue);
-
- for (;;) {
- GCObject *obj;
- SgenDescriptor desc;
- GRAY_OBJECT_DEQUEUE_PARALLEL (queue, &obj, &desc);
- if (!obj)
- return TRUE;
- SGEN_LOG (9, "Precise gray object scan %p (%s)", obj, sgen_client_vtable_get_name (SGEN_LOAD_VTABLE (obj)));
- scan_func (obj, desc, queue);
- }
- return FALSE;
+ return ctx.ops->drain_gray_stack (ctx.queue);
}
/*
precisely_scan_objects_from (void** start_root, void** end_root, char* n_start, char *n_end, SgenDescriptor desc, ScanCopyContext ctx)
{
CopyOrMarkObjectFunc copy_func = ctx.ops->copy_or_mark_object;
+ ScanPtrFieldFunc scan_field_func = ctx.ops->scan_ptr_field;
SgenGrayQueue *queue = ctx.queue;
switch (desc & ROOT_DESC_TYPE_MASK) {
}
break;
}
+ case ROOT_DESC_VECTOR: {
+ void **p;
+
+ for (p = start_root; p < end_root; p++) {
+ if (*p)
+ scan_field_func (NULL, (GCObject**)p, queue);
+ }
+ break;
+ }
case ROOT_DESC_USER: {
SgenUserRootMarkFunc marker = sgen_get_user_descriptor_func (desc);
marker (start_root, single_arg_user_copy_or_mark, &ctx);
scrrj->root_type = ROOT_TYPE_NORMAL;
sgen_workers_enqueue_job (&scrrj->scan_job.job, enqueue);
- scrrj = (ScanFromRegisteredRootsJob*)sgen_thread_pool_job_alloc ("scan from registered roots wbarrier", job_scan_from_registered_roots, sizeof (ScanFromRegisteredRootsJob));
- scrrj->scan_job.ops = ops;
- scrrj->scan_job.gc_thread_gray_queue = gc_thread_gray_queue;
- scrrj->heap_start = heap_start;
- scrrj->heap_end = heap_end;
- scrrj->root_type = ROOT_TYPE_WBARRIER;
- sgen_workers_enqueue_job (&scrrj->scan_job.job, enqueue);
+ if (current_collection_generation == GENERATION_OLD) {
+ /* During minors we scan the cardtable for these roots instead */
+ scrrj = (ScanFromRegisteredRootsJob*)sgen_thread_pool_job_alloc ("scan from registered roots wbarrier", job_scan_from_registered_roots, sizeof (ScanFromRegisteredRootsJob));
+ scrrj->scan_job.ops = ops;
+ scrrj->scan_job.gc_thread_gray_queue = gc_thread_gray_queue;
+ scrrj->heap_start = heap_start;
+ scrrj->heap_end = heap_end;
+ scrrj->root_type = ROOT_TYPE_WBARRIER;
+ sgen_workers_enqueue_job (&scrrj->scan_job.job, enqueue);
+ }
/* Threads */
SGEN_ASSERT (0, sgen_workers_all_done (), "Why are the workers not done when we start or finish a major collection?");
if (mode == COPY_OR_MARK_FROM_ROOTS_FINISH_CONCURRENT) {
+ sgen_workers_set_num_active_workers (0);
if (sgen_workers_have_idle_work ()) {
/*
* We force the finish of the worker with the new object ops context
* the roots.
*/
if (mode == COPY_OR_MARK_FROM_ROOTS_START_CONCURRENT) {
+ sgen_workers_set_num_active_workers (1);
gray_queue_redirect (gc_thread_gray_queue);
if (precleaning_enabled) {
sgen_workers_start_all_workers (object_ops_nopar, object_ops_par, workers_finish_callback);
UNLOCK_GC;
}
+void
+sgen_wbroots_iterate_live_block_ranges (sgen_cardtable_block_callback cb)
+{
+ void **start_root;
+ RootRecord *root;
+ SGEN_HASH_TABLE_FOREACH (&roots_hash [ROOT_TYPE_WBARRIER], void **, start_root, RootRecord *, root) {
+ cb ((mword)start_root, (mword)root->end_root - (mword)start_root);
+ } SGEN_HASH_TABLE_FOREACH_END;
+}
+
+/* Root equivalent of sgen_client_cardtable_scan_object */
+static void
+sgen_wbroot_scan_card_table (void** start_root, mword size, ScanCopyContext ctx)
+{
+ ScanPtrFieldFunc scan_field_func = ctx.ops->scan_ptr_field;
+ guint8 *card_data = sgen_card_table_get_card_scan_address ((mword)start_root);
+ guint8 *card_base = card_data;
+ mword card_count = sgen_card_table_number_of_cards_in_range ((mword)start_root, size);
+ guint8 *card_data_end = card_data + card_count;
+ mword extra_idx = 0;
+ char *obj_start = sgen_card_table_align_pointer (start_root);
+ char *obj_end = (char*)start_root + size;
+#ifdef SGEN_HAVE_OVERLAPPING_CARDS
+ guint8 *overflow_scan_end = NULL;
+#endif
+
+#ifdef SGEN_HAVE_OVERLAPPING_CARDS
+ /*Check for overflow and if so, setup to scan in two steps*/
+ if (card_data_end >= SGEN_SHADOW_CARDTABLE_END) {
+ overflow_scan_end = sgen_shadow_cardtable + (card_data_end - SGEN_SHADOW_CARDTABLE_END);
+ card_data_end = SGEN_SHADOW_CARDTABLE_END;
+ }
+
+LOOP_HEAD:
+#endif
+
+ card_data = sgen_find_next_card (card_data, card_data_end);
+
+ for (; card_data < card_data_end; card_data = sgen_find_next_card (card_data + 1, card_data_end)) {
+ size_t idx = (card_data - card_base) + extra_idx;
+ char *start = (char*)(obj_start + idx * CARD_SIZE_IN_BYTES);
+ char *card_end = start + CARD_SIZE_IN_BYTES;
+ char *elem = start, *first_elem = start;
+
+ /*
+ * Don't clean first and last card on 32bit systems since they
+ * may also be part from other roots.
+ */
+ if (card_data != card_base && card_data != (card_data_end - 1))
+ sgen_card_table_prepare_card_for_scanning (card_data);
+
+ card_end = MIN (card_end, obj_end);
+
+ if (elem < (char*)start_root)
+ first_elem = elem = (char*)start_root;
+
+ for (; elem < card_end; elem += SIZEOF_VOID_P) {
+ if (*(GCObject**)elem)
+ scan_field_func (NULL, (GCObject**)elem, ctx.queue);
+ }
+
+ binary_protocol_card_scan (first_elem, elem - first_elem);
+ }
+
+#ifdef SGEN_HAVE_OVERLAPPING_CARDS
+ if (overflow_scan_end) {
+ extra_idx = card_data - card_base;
+ card_base = card_data = sgen_shadow_cardtable;
+ card_data_end = overflow_scan_end;
+ overflow_scan_end = NULL;
+ goto LOOP_HEAD;
+ }
+#endif
+}
+
+void
+sgen_wbroots_scan_card_table (ScanCopyContext ctx)
+{
+ void **start_root;
+ RootRecord *root;
+
+ SGEN_HASH_TABLE_FOREACH (&roots_hash [ROOT_TYPE_WBARRIER], void **, start_root, RootRecord *, root) {
+ SGEN_ASSERT (0, (root->root_desc & ROOT_DESC_TYPE_MASK) == ROOT_DESC_VECTOR, "Unsupported root type");
+
+ sgen_wbroot_scan_card_table (start_root, (mword)root->end_root - (mword)start_root, ctx);
+ } SGEN_HASH_TABLE_FOREACH_END;
+}
+
/*
* ######################################################################
* ######## Thread handling (stop/start code)
* the conservative scan, otherwise by the remembered set scan.
*/
+/**
+ * mono_gc_wbarrier_arrayref_copy:
+ */
void
mono_gc_wbarrier_arrayref_copy (gpointer dest_ptr, gpointer src_ptr, int count)
{
remset.wbarrier_arrayref_copy (dest_ptr, src_ptr, count);
}
+/**
+ * mono_gc_wbarrier_generic_nostore:
+ */
void
mono_gc_wbarrier_generic_nostore (gpointer ptr)
{
remset.wbarrier_generic_nostore (ptr);
}
+/**
+ * mono_gc_wbarrier_generic_store:
+ */
void
mono_gc_wbarrier_generic_store (gpointer ptr, GCObject* value)
{
sgen_dummy_use (value);
}
-/* Same as mono_gc_wbarrier_generic_store () but performs the store
+/**
+ * mono_gc_wbarrier_generic_store_atomic:
+ * Same as \c mono_gc_wbarrier_generic_store but performs the store
* as an atomic operation with release semantics.
*/
void
sgen_client_init ();
if (!minor_collector_opt) {
- sgen_simple_nursery_init (&sgen_minor_collector);
+ sgen_simple_nursery_init (&sgen_minor_collector, FALSE);
} else {
if (!strcmp (minor_collector_opt, "simple")) {
use_simple_nursery:
- sgen_simple_nursery_init (&sgen_minor_collector);
+ sgen_simple_nursery_init (&sgen_minor_collector, FALSE);
+ } else if (!strcmp (minor_collector_opt, "simple-par")) {
+ sgen_simple_nursery_init (&sgen_minor_collector, TRUE);
} else if (!strcmp (minor_collector_opt, "split")) {
sgen_split_nursery_init (&sgen_minor_collector);
} else {