diff --git a/mono/metadata/boehm-gc.c b/mono/metadata/boehm-gc.c index 71222459ce73..e663ee3a5079 100644 --- a/mono/metadata/boehm-gc.c +++ b/mono/metadata/boehm-gc.c @@ -63,11 +63,19 @@ static gboolean gc_strict_wbarriers = FALSE; static mono_mutex_t mono_gc_lock; static GC_push_other_roots_proc default_push_other_roots; -static GHashTable *roots; +static GHashTable* roots; +static GHashTable* late_handles; typedef struct ephemeron_node ephemeron_node; static ephemeron_node* ephemeron_list; +static OnThreadsSuspendedCallback s_on_threads_suspended; +static void* s_on_threads_suspended_arg; +static OnHandleFoundCallback s_on_handle_found; +static void* s_on_handle_found_arg; +static OnProcessCallback s_on_process; +static void* s_on_process_arg; + static void mono_push_other_roots(void); @@ -122,12 +130,12 @@ struct HandleData { gpointer entries[HANDLE_COUNT]; }; -#define GC_HANDLE_TYPE_IS_WEAK(x) ((x) <= HANDLE_WEAK_TRACK) +#define GC_HANDLE_TYPE_IS_WEAK(x) (((x) == HANDLE_WEAK) ||((x) == HANDLE_WEAK_TRACK) ||((x) == HANDLE_WEAK_FIELDS)) -#define MONO_GC_HANDLE_TYPE_IS_WEAK(x) ((x) <= HANDLE_WEAK_TRACK) +#define MONO_GC_HANDLE_TYPE_IS_WEAK(x) (((x) == HANDLE_WEAK) ||((x) == HANDLE_WEAK_TRACK) ||((x) == HANDLE_WEAK_FIELDS)) -static HandleData* gc_handles[4]; -static HandleData* gc_handles_free[4]; +static HandleData* gc_handles[HANDLE_TYPE_MAX]; +static HandleData* gc_handles_free[HANDLE_TYPE_MAX]; static void mono_gc_warning (char *msg, GC_word arg) @@ -202,6 +210,7 @@ mono_gc_base_init (void) #endif roots = g_hash_table_new (NULL, NULL); + late_handles = g_hash_table_new(NULL, NULL); default_push_other_roots = GC_get_push_other_roots (); GC_set_push_other_roots (mono_push_other_roots); GC_set_mark_stack_empty (mono_push_ephemerons); @@ -581,6 +590,8 @@ on_gc_notification (GC_EventType event) case GC_EVENT_POST_STOP_WORLD: e = MONO_GC_EVENT_POST_STOP_WORLD; MONO_GC_WORLD_STOP_END (); + if (s_on_threads_suspended) + s_on_threads_suspended(s_on_threads_suspended_arg); break; case GC_EVENT_PRE_START_WORLD: @@ -702,6 +713,30 @@ mono_gc_register_root (char *start, size_t size, void *descr, MonoGCRootSource s return TRUE; } +typedef struct { + gpointer *start; + size_t count; +} LateHandleData; + +static gpointer +register_late_handles(gpointer arg) +{ + RootData* root_data = (RootData*)arg; + g_hash_table_insert(late_handles, root_data->start, root_data->end); + return NULL; +} + +int +mono_gc_register_late_handles(gpointer* start, size_t count) +{ + LateHandleData root_data; + root_data.start = start; + root_data.count = count; + GC_call_with_alloc_lock(register_late_handles, &root_data); + //MONO_PROFILER_RAISE(gc_root_register, ((const mono_byte*)start, size, source, key, msg)); + return TRUE; +} + int mono_gc_register_root_wbarrier (char *start, size_t size, MonoGCDescriptor descr, MonoGCRootSource source, void *key, const char *msg) { @@ -1652,7 +1687,10 @@ handle_data_alloc_entries(int type) if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles->type)) { handles->domain_ids = (guint16 *)g_malloc0 (sizeof (*handles->domain_ids) * handles->size); } else { - mono_gc_register_root((char*) &handles->entries[0], HANDLE_COUNT * sizeof(gpointer), MONO_GC_DESCRIPTOR_NULL, MONO_ROOT_SOURCE_GC_HANDLE, NULL, "GC Handle Data"); + if (handles->type == HANDLE_LATE) + mono_gc_register_late_handles(&handles->entries[0], HANDLE_COUNT); + else + mono_gc_register_root((char*) &handles->entries[0], HANDLE_COUNT * sizeof(gpointer), MONO_GC_DESCRIPTOR_NULL, MONO_ROOT_SOURCE_GC_HANDLE, NULL, "GC Handle Data"); } handles->bitmap = (guint32 *)g_malloc0 (handles->size / CHAR_BIT); @@ -1801,6 +1839,12 @@ mono_gchandle_new_internal (MonoObject *obj, gboolean pinned) return alloc_handle (pinned? HANDLE_PINNED: HANDLE_NORMAL, obj, FALSE); } +MonoGCHandle +mono_gchandle_new_late_internal(MonoObject* obj) +{ + return alloc_handle(HANDLE_LATE, obj, FALSE); +} + /** * mono_gchandle_new_weakref_internal: * \param obj managed object to get a handle for @@ -2036,7 +2080,7 @@ mono_gchandle_free_domain (MonoDomain *domain) { guint type; - for (type = HANDLE_TYPE_MIN; type <= HANDLE_PINNED; ++type) { + for (type = HANDLE_TYPE_MIN; type < HANDLE_TYPE_MAX; ++type) { guint slot; HandleData *handles = gc_handles [type]; lock_handles (handles); @@ -2159,9 +2203,126 @@ mono_clear_ephemerons (void) } } +//LateHandleCallback s_late_handle_callback; +//void* s_late_handle_callback_user_data; + + + +void +mono_gc_collect_assets( + OnThreadsSuspendedCallback on_threads_suspended, void* on_threads_suspended_arg, + OnHandleFoundCallback on_handle_found, void* on_handle_found_arg, + OnProcessCallback on_process, void* on_process_arg) +{ + s_on_threads_suspended = on_threads_suspended; + s_on_threads_suspended_arg = on_threads_suspended_arg; + s_on_handle_found = on_handle_found; + s_on_handle_found_arg = on_handle_found_arg; + s_on_process = on_process; + s_on_process_arg = on_process_arg; + mono_gc_collect(mono_gc_max_generation()); + s_on_threads_suspended = NULL; + s_on_threads_suspended_arg = NULL; + s_on_handle_found = NULL; + s_on_handle_found_arg = NULL; + s_on_process = NULL; + s_on_process_arg = NULL; +} + +typedef struct { + struct GC_ms_entry* mark_stack_ptr; + struct GC_ms_entry* mark_stack_limit; +} MarkHandleData; + +MarkHandleData* s_mark_data; + + +void mono_gchandle_mark_object(MonoObject* obj) +{ + g_assert(s_mark_data); + s_mark_data->mark_stack_ptr = GC_mark_and_push(obj, s_mark_data->mark_stack_ptr, s_mark_data->mark_stack_limit, NULL); +} + static struct GC_ms_entry* mono_push_ephemerons (struct GC_ms_entry* mark_stack_ptr, struct GC_ms_entry* mark_stack_limit) { + struct GC_ms_entry* mark_stack_ptr_orig = mark_stack_ptr; + /* push late GC handles */ + if (s_on_handle_found) + { + GHashTableIter iter; + g_hash_table_iter_init(&iter, late_handles); + + gpointer key; + gpointer value; + + while (g_hash_table_iter_next(&iter, &key, &value)) { + /* process handles */ + gpointer* handles = key; + size_t length = (size_t)value; + for (size_t i = 0; i < length; ++i) { + MonoObject** handle = (MonoObject**)(handles + i); + MonoObject* object = *handle; + + if (!object) + continue; + + /* avoid objects we've already processed before */ + if ((size_t)object & 1) + continue; + + if (GC_is_marked(object)) { + s_on_handle_found(s_on_handle_found_arg, object); + + *handle = (MonoObject*)((size_t)object | 1); + } + } + } + } + + /* callback to allow client to process a batch of handles */ + if (s_on_process) { + MarkHandleData data; + data.mark_stack_ptr = mark_stack_ptr; + data.mark_stack_limit = mark_stack_limit; + s_mark_data = &data; + s_on_process(s_on_process_arg); + mark_stack_ptr = data.mark_stack_ptr; + s_mark_data = NULL; + } + + /* mark all handles, as we want to keep all targets alive like a strong handle */ + if (mark_stack_ptr_orig == mark_stack_ptr) { + GHashTableIter iter; + g_hash_table_iter_init(&iter, late_handles); + + gpointer key; + gpointer value; + + while (g_hash_table_iter_next(&iter, &key, &value)) { + /* process handles */ + gpointer* handles = key; + size_t length = (size_t)value; + for (size_t i = 0; i < length; ++i) { + MonoObject** handle = (MonoObject**)(handles + i); + + /* remove the bit we set to indicate processing */ + if ((size_t)*handle & 1) + *handle = (MonoObject*)((size_t)*handle & ~(size_t)1); + + MonoObject* object = *handle; + if (!object) + continue; + + mark_stack_ptr = GC_mark_and_push(object, mark_stack_ptr, mark_stack_limit, handle); + } + } + s_on_handle_found = NULL; + s_on_process = NULL; + s_on_threads_suspended = NULL; + } + + ephemeron_node* prev_node = NULL; ephemeron_node* current_node = NULL; @@ -2257,8 +2418,10 @@ mono_gc_strong_handle_foreach(GFunc func, gpointer user_data) lock_handles(handles); - for (gcHandleTypeIndex = HANDLE_NORMAL; gcHandleTypeIndex <= HANDLE_PINNED; gcHandleTypeIndex++) + for (gcHandleTypeIndex = HANDLE_TYPE_MIN; gcHandleTypeIndex < HANDLE_TYPE_MAX; gcHandleTypeIndex++) { + if (GC_HANDLE_TYPE_IS_WEAK(gcHandleTypeIndex)) + continue; HandleData* handles = gc_handles[gcHandleTypeIndex]; while (handles != NULL) { diff --git a/mono/metadata/external-only.c b/mono/metadata/external-only.c index a459e65c447c..d85274b54a55 100644 --- a/mono/metadata/external-only.c +++ b/mono/metadata/external-only.c @@ -51,6 +51,12 @@ mono_gchandle_new_v2 (MonoObject *obj, mono_bool pinned) MONO_EXTERNAL_ONLY_GC_UNSAFE (MonoGCHandle, mono_gchandle_new_internal (obj, pinned)); } +MonoGCHandle +mono_gchandle_new_late_v2(MonoObject* obj) +{ + MONO_EXTERNAL_ONLY_GC_UNSAFE(MonoGCHandle, mono_gchandle_new_late_internal(obj)); +} + /** * mono_gchandle_new_weakref: * \param obj managed object to get a handle for diff --git a/mono/metadata/object-internals.h b/mono/metadata/object-internals.h index 4f740b84b2a9..e0cfdff8c820 100644 --- a/mono/metadata/object-internals.h +++ b/mono/metadata/object-internals.h @@ -2372,6 +2372,9 @@ mono_runtime_get_aotid_arr (void); MonoGCHandle mono_gchandle_new_internal (MonoObject *obj, mono_bool pinned); +MonoGCHandle +mono_gchandle_new_late_internal(MonoObject* obj); + MonoGCHandle mono_gchandle_new_weakref_internal (MonoObject *obj, mono_bool track_resurrection); diff --git a/mono/metadata/object.h b/mono/metadata/object.h index 377e3fcd7e18..1812158147c8 100644 --- a/mono/metadata/object.h +++ b/mono/metadata/object.h @@ -376,10 +376,25 @@ MONO_API MONO_RT_EXTERNAL_ONLY void mono_gchandle_free (uint32_t UNITY_MONO_API MONO_RT_EXTERNAL_ONLY mono_bool mono_gchandle_is_in_domain (uint32_t gchandle, MonoDomain* domain); MONO_API MONO_RT_EXTERNAL_ONLY MonoGCHandle mono_gchandle_new_v2 (MonoObject *obj, mono_bool pinned); +MONO_API MONO_RT_EXTERNAL_ONLY MonoGCHandle mono_gchandle_new_late_v2 (MonoObject *obj); MONO_API MONO_RT_EXTERNAL_ONLY MonoGCHandle mono_gchandle_new_weakref_v2 (MonoObject *obj, mono_bool track_resurrection); MONO_API MONO_RT_EXTERNAL_ONLY MonoObject* mono_gchandle_get_target_v2 (MonoGCHandle gchandle); MONO_API MONO_RT_EXTERNAL_ONLY void mono_gchandle_free_v2 (MonoGCHandle gchandle); + +typedef void (*DoUnityProcessing)(void* handle); +typedef void (*LateHandleCallback)(MonoObject* obj, void* user_data); + +typedef void (*OnThreadsSuspendedCallback)(void* arg); +typedef void (*OnHandleFoundCallback)(void* arg, void* handle); +typedef void (*OnProcessCallback)(void* arg); +MONO_API MONO_RT_EXTERNAL_ONLY void mono_gc_collect_assets( + OnThreadsSuspendedCallback onThreadsSuspended, void* onThreadsSuspendedArg, + OnHandleFoundCallback onHandleFound, void* onHandleFoundArg, + OnProcessCallback onProcess, void* onProcessArg); + +MONO_API MONO_RT_EXTERNAL_ONLY void mono_gchandle_mark_object(MonoObject* obj); + /* make sure the gchandle was allocated for an object in domain */ UNITY_MONO_API MONO_RT_EXTERNAL_ONLY mono_bool mono_gchandle_is_in_domain_v2 (MonoGCHandle gchandle, MonoDomain* domain); diff --git a/mono/metadata/sgen-mono.c b/mono/metadata/sgen-mono.c index 0d925836ff6f..bc755ba0256e 100644 --- a/mono/metadata/sgen-mono.c +++ b/mono/metadata/sgen-mono.c @@ -2781,6 +2781,13 @@ mono_gchandle_new_internal (MonoObject *obj, gboolean pinned) return MONO_GC_HANDLE_FROM_UINT (sgen_gchandle_new (obj, pinned)); } +MonoGCHandle +mono_gchandle_new_late_internal(MonoObject* obj) +{ + g_assert_not_reached (); + return 0; +} + /** * mono_gchandle_new_weakref_internal: * \param obj managed object to get a handle for diff --git a/mono/sgen/gc-internal-agnostic.h b/mono/sgen/gc-internal-agnostic.h index 967568632a9e..0a1eb65f873f 100644 --- a/mono/sgen/gc-internal-agnostic.h +++ b/mono/sgen/gc-internal-agnostic.h @@ -53,6 +53,7 @@ typedef enum { HANDLE_NORMAL, HANDLE_PINNED, HANDLE_WEAK_FIELDS, + HANDLE_LATE, HANDLE_TYPE_MAX } GCHandleType;