Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
179 changes: 171 additions & 8 deletions mono/metadata/boehm-gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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) {
Expand Down
6 changes: 6 additions & 0 deletions mono/metadata/external-only.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions mono/metadata/object-internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
15 changes: 15 additions & 0 deletions mono/metadata/object.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
7 changes: 7 additions & 0 deletions mono/metadata/sgen-mono.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions mono/sgen/gc-internal-agnostic.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ typedef enum {
HANDLE_NORMAL,
HANDLE_PINNED,
HANDLE_WEAK_FIELDS,
HANDLE_LATE,
HANDLE_TYPE_MAX
} GCHandleType;

Expand Down