Skip to content

Commit e710abe

Browse files
jonchamUnityAlex
authored andcommitted
Handle large number of GC roots (case 1191533).
Create mark procedure for pushing GC roots. If root count exceeds mark stack capacity, push roots in chunks.
1 parent 4e8aa34 commit e710abe

File tree

1 file changed

+64
-7
lines changed

1 file changed

+64
-7
lines changed

mono/metadata/boehm-gc.c

Lines changed: 64 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,12 @@ static void on_gc_heap_resize (GC_word new_size);
116116

117117
#define ELEMENT_CHUNK_SIZE 256
118118
#define VECTOR_PROC_INDEX 6
119+
120+
static unsigned GC_roots_proc_index;
121+
122+
static mse*
123+
GC_roots_proc (word* addr, mse* mark_stack_ptr, mse* mark_stack_limit, word env);
124+
119125
static mse * GC_gcj_vector_proc (word * addr, mse * mark_stack_ptr,
120126
mse * mark_stack_limit, word env)
121127
{
@@ -205,6 +211,7 @@ mono_gc_base_init (void)
205211

206212
GC_init_gcj_malloc (5, NULL);
207213
GC_init_gcj_vector (VECTOR_PROC_INDEX, GC_gcj_vector_proc);
214+
GC_roots_proc_index = GC_new_proc (GC_roots_proc);
208215
GC_allow_register_threads ();
209216

210217
params_opts = mono_gc_params_get();
@@ -685,12 +692,6 @@ mono_gc_deregister_root (char* addr)
685692
MONO_PROFILER_RAISE (gc_root_unregister, ((const mono_byte *) addr));
686693
}
687694

688-
static void
689-
push_root (gpointer key, gpointer value, gpointer user_data)
690-
{
691-
GC_push_all (key, value);
692-
}
693-
694695
static void
695696
push_handle_stack (HandleStack* stack)
696697
{
@@ -709,10 +710,66 @@ push_handle_stack (HandleStack* stack)
709710
}
710711
}
711712

713+
static mse*
714+
GC_roots_proc (word* addr, mse* mark_stack_ptr, mse* mark_stack_limit, word env)
715+
{
716+
GHashTableIter iter;
717+
guint size = g_hash_table_size (roots);
718+
g_hash_table_iter_init (&iter, roots);
719+
char* start;
720+
char* end;
721+
722+
word capacity = (word)(mark_stack_limit - mark_stack_ptr) - 1;
723+
word start_index = env;
724+
word remaining = size - start_index;
725+
word skip = start_index;
726+
727+
/* if we have more items than capacity, push remaining immediately. This allows pushed
728+
* items to be processed on top of stack before we process remainder. If we push remainder
729+
* at top, we have no mark stack space.
730+
*/
731+
if (remaining > capacity) {
732+
capacity--;
733+
mark_stack_ptr++;
734+
mark_stack_ptr->mse_descr.w = GC_MAKE_PROC (GC_roots_proc_index, (start_index + capacity) /* continue processing */);
735+
mark_stack_ptr->mse_start = (ptr_t)0;
736+
}
737+
738+
while (g_hash_table_iter_next (&iter, (void**)&start, (void**)&end) && capacity > 0) {
739+
void* bottom;
740+
void* top;
741+
742+
if (skip) {
743+
skip--;
744+
continue;
745+
}
746+
747+
/* taken from GC_push_all */
748+
bottom = (void*)(((word)start + ALIGNMENT - 1) & ~(ALIGNMENT - 1));
749+
top = (void*)((word)end & ~(ALIGNMENT - 1));
750+
751+
g_assert ((word)bottom < (word)top);
752+
753+
mark_stack_ptr++;
754+
755+
if ((word)mark_stack_ptr >= (word)mark_stack_limit) {
756+
g_error ("Unexpected mark stack overflow\n");
757+
}
758+
mark_stack_ptr->mse_start = (ptr_t)bottom;
759+
mark_stack_ptr->mse_descr.w = (word)top - (word)bottom;
760+
capacity--;
761+
}
762+
return mark_stack_ptr;
763+
}
764+
712765
static void
713766
mono_push_other_roots (void)
714767
{
715-
g_hash_table_foreach (roots, push_root, NULL);
768+
if (GC_roots_proc_index) {
769+
GC_mark_stack_top++;
770+
GC_mark_stack_top->mse_descr.w = GC_MAKE_PROC (GC_roots_proc_index, 0 /* continue processing */);
771+
GC_mark_stack_top->mse_start = (ptr_t)0;
772+
}
716773
FOREACH_THREAD_EXCLUDE (info, MONO_THREAD_INFO_FLAGS_NO_GC) {
717774
HandleStack* stack = info->handle_stack;
718775
if (stack)

0 commit comments

Comments
 (0)