#define mg_free(x) g_free(x)
#endif
-typedef struct _Slot Slot;
-
-struct _Slot {
- MonoObject *key;
- MonoObject *value;
-};
-
struct _MonoGHashTable {
GHashFunc hash_func;
GEqualFunc key_equal_func;
- Slot *table;
+ MonoObject **keys;
+ MonoObject **values;
int table_size;
int in_use;
GDestroyNotify value_destroy_func, key_destroy_func;
const char *msg;
};
-#ifdef HAVE_SGEN_GC
-static MonoGCDescriptor table_hash_descr = MONO_GC_DESCRIPTOR_NULL;
-
-static void mono_g_hash_mark (void *addr, MonoGCMarkFunc mark_func, void *gc_data);
-#endif
-
#if UNUSED
static gboolean
test_prime (int x)
/* We triple the table size at rehash time, similar with previous implementation */
#define HASH_TABLE_RESIZE_RATIO 3
+static inline void mono_g_hash_table_key_store (MonoGHashTable *hash, int slot, MonoObject* key)
+{
+ MonoObject **key_addr = &hash->keys [slot];
+ if (hash->gc_type & MONO_HASH_KEY_GC)
+ mono_gc_wbarrier_generic_store (key_addr, key);
+ else
+ *key_addr = key;
+}
+
+static inline void mono_g_hash_table_value_store (MonoGHashTable *hash, int slot, MonoObject* value)
+{
+ MonoObject **value_addr = &hash->values [slot];
+ if (hash->gc_type & MONO_HASH_VALUE_GC)
+ mono_gc_wbarrier_generic_store (value_addr, value);
+ else
+ *value_addr = value;
+}
+
/* Returns position of key or of an empty slot for it */
static inline int mono_g_hash_table_find_slot (MonoGHashTable *hash, const MonoObject *key)
{
guint i = ((*hash->hash_func) (key)) % hash->table_size;
GEqualFunc equal = hash->key_equal_func;
- while (hash->table [i].key && !(*equal) (hash->table [i].key, key)) {
+ while (hash->keys [i] && !(*equal) (hash->keys [i], key)) {
i++;
if (i == hash->table_size)
i = 0;
hash->key_equal_func = key_equal_func;
hash->table_size = g_spaced_primes_closest (1);
- hash->table = mg_new0 (Slot, hash->table_size);
+ hash->keys = mg_new0 (MonoObject*, hash->table_size);
+ hash->values = mg_new0 (MonoObject*, hash->table_size);
hash->gc_type = type;
hash->source = source;
g_error ("wrong type for gc hashtable");
#ifdef HAVE_SGEN_GC
- /*
- * We use a user defined marking function to avoid having to register a GC root for
- * each hash node.
- */
- if (!table_hash_descr)
- table_hash_descr = mono_gc_make_root_descr_user (mono_g_hash_mark);
- mono_gc_register_root_wbarrier ((char*)hash, sizeof (MonoGHashTable), table_hash_descr, source, msg);
+ if (hash->gc_type & MONO_HASH_KEY_GC)
+ mono_gc_register_root_wbarrier ((char*)hash->keys, sizeof (MonoObject*) * hash->table_size, mono_gc_make_vector_descr (), hash->source, hash->msg);
+ if (hash->gc_type & MONO_HASH_VALUE_GC)
+ mono_gc_register_root_wbarrier ((char*)hash->values, sizeof (MonoObject*) * hash->table_size, mono_gc_make_vector_descr (), hash->source, hash->msg);
#endif
return hash;
typedef struct {
MonoGHashTable *hash;
int new_size;
- Slot *table;
+ MonoObject **keys;
+ MonoObject **values;
} RehashData;
static void*
RehashData *data = (RehashData *)_data;
MonoGHashTable *hash = data->hash;
int current_size, i;
- Slot *old_table;
+ MonoObject **old_keys;
+ MonoObject **old_values;
current_size = hash->table_size;
hash->table_size = data->new_size;
- old_table = hash->table;
- hash->table = data->table;
+ old_keys = hash->keys;
+ old_values = hash->values;
+ hash->keys = data->keys;
+ hash->values = data->values;
for (i = 0; i < current_size; i++) {
- if (old_table [i].key) {
- int slot = mono_g_hash_table_find_slot (hash, old_table [i].key);
- hash->table [slot].key = old_table [i].key;
- hash->table [slot].value = old_table [i].value;
+ if (old_keys [i]) {
+ int slot = mono_g_hash_table_find_slot (hash, old_keys [i]);
+ mono_g_hash_table_key_store (hash, slot, old_keys [i]);
+ mono_g_hash_table_value_store (hash, slot, old_values [i]);
}
}
- return old_table;
+ return NULL;
}
static void
MONO_REQ_GC_UNSAFE_MODE; //we must run in unsafe mode to make rehash safe
RehashData data;
- void *old_table G_GNUC_UNUSED; /* unused on Boehm */
+ void *old_keys G_GNUC_UNUSED = hash->keys; /* unused on Boehm */
+ void *old_values G_GNUC_UNUSED = hash->values; /* unused on Boehm */
data.hash = hash;
/*
* to allow also for compaction.
*/
data.new_size = g_spaced_primes_closest (hash->in_use / HASH_TABLE_MAX_LOAD_FACTOR * HASH_TABLE_RESIZE_RATIO);
- data.table = mg_new0 (Slot, data.new_size);
+ data.keys = mg_new0 (MonoObject*, data.new_size);
+ data.values = mg_new0 (MonoObject*, data.new_size);
+
+#ifdef HAVE_SGEN_GC
+ if (hash->gc_type & MONO_HASH_KEY_GC)
+ mono_gc_register_root_wbarrier ((char*)data.keys, sizeof (MonoObject*) * data.new_size, mono_gc_make_vector_descr (), hash->source, hash->msg);
+ if (hash->gc_type & MONO_HASH_VALUE_GC)
+ mono_gc_register_root_wbarrier ((char*)data.values, sizeof (MonoObject*) * data.new_size, mono_gc_make_vector_descr (), hash->source, hash->msg);
+#endif
if (!mono_threads_is_coop_enabled ()) {
- old_table = mono_gc_invoke_with_gc_lock (do_rehash, &data);
+ mono_gc_invoke_with_gc_lock (do_rehash, &data);
} else {
/* We cannot be preempted */
- old_table = do_rehash (&data);
+ do_rehash (&data);
}
- mg_free (old_table);
+#ifdef HAVE_SGEN_GC
+ if (hash->gc_type & MONO_HASH_KEY_GC)
+ mono_gc_deregister_root ((char*)old_keys);
+ if (hash->gc_type & MONO_HASH_VALUE_GC)
+ mono_gc_deregister_root ((char*)old_values);
+#endif
+ mg_free (old_keys);
+ mg_free (old_values);
}
guint
slot = mono_g_hash_table_find_slot (hash, key);
- if (hash->table [slot].key) {
- *orig_key = hash->table [slot].key;
- *value = hash->table [slot].value;
+ if (hash->keys [slot]) {
+ *orig_key = hash->keys [slot];
+ *value = hash->values [slot];
return TRUE;
}
g_return_if_fail (func != NULL);
for (i = 0; i < hash->table_size; i++) {
- if (hash->table [i].key)
- (*func)(hash->table [i].key, hash->table [i].value, user_data);
+ if (hash->keys [i])
+ (*func)(hash->keys [i], hash->values [i], user_data);
}
}
g_return_val_if_fail (predicate != NULL, NULL);
for (i = 0; i < hash->table_size; i++) {
- if (hash->table [i].key && (*predicate)(hash->table [i].key, hash->table [i].value, user_data))
- return hash->table [i].value;
+ if (hash->keys [i] && (*predicate)(hash->keys [i], hash->values [i], user_data))
+ return hash->values [i];
}
return NULL;
}
g_return_val_if_fail (hash != NULL, FALSE);
slot = mono_g_hash_table_find_slot (hash, key);
- if (!hash->table [slot].key)
+ if (!hash->keys [slot])
return FALSE;
if (hash->key_destroy_func)
- (*hash->key_destroy_func)(hash->table [slot].key);
- hash->table [slot].key = NULL;
+ (*hash->key_destroy_func)(hash->keys [slot]);
+ hash->keys [slot] = NULL;
if (hash->value_destroy_func)
- (*hash->value_destroy_func)(hash->table [slot].value);
- hash->table [slot].value = NULL;
+ (*hash->value_destroy_func)(hash->values [slot]);
+ hash->values [slot] = NULL;
hash->in_use--;
/*
*/
last_clear_slot = slot;
slot = (slot + 1) % hash->table_size;
- while (hash->table [slot].key) {
- guint hashcode = ((*hash->hash_func)(hash->table [slot].key)) % hash->table_size;
+ while (hash->keys [slot]) {
+ guint hashcode = ((*hash->hash_func)(hash->keys [slot])) % hash->table_size;
/*
* We try to move the current element to last_clear_slot, but only if
* it brings it closer to its normal position (hashcode)
*/
if ((last_clear_slot < slot && (hashcode > slot || hashcode <= last_clear_slot)) ||
(last_clear_slot > slot && (hashcode > slot && hashcode <= last_clear_slot))) {
- hash->table [last_clear_slot].key = hash->table [slot].key;
- hash->table [last_clear_slot].value = hash->table [slot].value;
- hash->table [slot].key = NULL;
- hash->table [slot].value = NULL;
+ mono_g_hash_table_key_store (hash, last_clear_slot, hash->keys [slot]);
+ mono_g_hash_table_value_store (hash, last_clear_slot, hash->values [slot]);
+ hash->keys [slot] = NULL;
+ hash->values [slot] = NULL;
last_clear_slot = slot;
}
slot++;
g_return_val_if_fail (func != NULL, 0);
for (i = 0; i < hash->table_size; i++) {
- if (hash->table [i].key && (*func)(hash->table [i].key, hash->table [i].value, user_data)) {
- mono_g_hash_table_remove (hash, hash->table [i].key);
+ if (hash->keys [i] && (*func)(hash->keys [i], hash->values [i], user_data)) {
+ mono_g_hash_table_remove (hash, hash->keys [i]);
count++;
/* Retry current slot in case the removal shifted elements */
i--;
g_return_if_fail (hash != NULL);
#ifdef HAVE_SGEN_GC
- mono_gc_deregister_root ((char*)hash);
+ if (hash->gc_type & MONO_HASH_KEY_GC)
+ mono_gc_deregister_root ((char*)hash->keys);
+ if (hash->gc_type & MONO_HASH_VALUE_GC)
+ mono_gc_deregister_root ((char*)hash->values);
#endif
for (i = 0; i < hash->table_size; i++) {
- if (hash->table [i].key != NULL) {
+ if (hash->keys [i]) {
if (hash->key_destroy_func)
- (*hash->key_destroy_func)(hash->table [i].key);
+ (*hash->key_destroy_func)(hash->keys [i]);
if (hash->value_destroy_func)
- (*hash->value_destroy_func)(hash->table [i].value);
+ (*hash->value_destroy_func)(hash->values [i]);
}
}
- mg_free (hash->table);
+ mg_free (hash->keys);
+ mg_free (hash->values);
#ifdef HAVE_SGEN_GC
mg_free (hash);
#else
slot = mono_g_hash_table_find_slot (hash, key);
- if (hash->table [slot].key) {
+ if (hash->keys [slot]) {
if (replace) {
if (hash->key_destroy_func)
- (*hash->key_destroy_func)(hash->table [slot].key);
- hash->table [slot].key = (MonoObject *)key;
+ (*hash->key_destroy_func)(hash->keys [slot]);
+ mono_g_hash_table_key_store (hash, slot, (MonoObject*)key);
}
if (hash->value_destroy_func)
- (*hash->value_destroy_func) (hash->table [slot].value);
- hash->table [slot].value = (MonoObject *)value;
+ (*hash->value_destroy_func) (hash->values [slot]);
+ mono_g_hash_table_value_store (hash, slot, (MonoObject*)value);
} else {
- hash->table [slot].key = (MonoObject *)key;
- hash->table [slot].value = (MonoObject *)value;
+ mono_g_hash_table_key_store (hash, slot, (MonoObject*)key);
+ mono_g_hash_table_value_store (hash, slot, (MonoObject*)value);
hash->in_use++;
}
}
gboolean wrapped_around = FALSE;
while (TRUE) {
- if (hash->table [i].key) {
+ if (hash->keys [i]) {
chain_size++;
} else {
max_chain_size = MAX(max_chain_size, chain_size);
/* Rehash to a size that can fit the current elements */
printf ("Size: %d Table Size: %d Max Chain Length: %d\n", hash->in_use, hash->table_size, max_chain_size);
}
-
-#ifdef HAVE_SGEN_GC
-
-/* GC marker function */
-static void
-mono_g_hash_mark (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
-{
- MonoGHashTable *hash = (MonoGHashTable*)addr;
- int i;
-
- for (i = 0; i < hash->table_size; i++) {
- if (hash->gc_type & MONO_HASH_KEY_GC && hash->table [i].key)
- mark_func (&hash->table [i].key, gc_data);
- if (hash->gc_type & MONO_HASH_VALUE_GC && hash->table [i].value)
- mark_func (&hash->table [i].value, gc_data);
- }
-}
-
-#endif
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 */
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)