222 lines
6.2 KiB
C
222 lines
6.2 KiB
C
/**
|
|
* \file
|
|
* toggleref support for sgen
|
|
*
|
|
* Author:
|
|
* Rodrigo Kumpera (kumpera@gmail.com)
|
|
*
|
|
* Copyright 2011 Xamarin, Inc.
|
|
* Copyright (C) 2012 Xamarin Inc
|
|
*
|
|
* Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#ifdef HAVE_SGEN_GC
|
|
|
|
#include "sgen/sgen-gc.h"
|
|
#include "sgen-toggleref.h"
|
|
#include "sgen/sgen-client.h"
|
|
|
|
|
|
/*only one of the two can be non null at a given time*/
|
|
typedef struct {
|
|
GCObject *strong_ref;
|
|
GCObject *weak_ref;
|
|
} MonoGCToggleRef;
|
|
|
|
static MonoToggleRefStatus (*toggleref_callback) (MonoObject *obj);
|
|
static MonoGCToggleRef *toggleref_array;
|
|
static int toggleref_array_size;
|
|
static int toggleref_array_capacity;
|
|
|
|
void
|
|
sgen_process_togglerefs (void)
|
|
{
|
|
int i, w;
|
|
int toggle_ref_counts [3] = { 0, 0, 0 };
|
|
|
|
SGEN_LOG (4, "Proccessing ToggleRefs %d", toggleref_array_size);
|
|
|
|
for (i = w = 0; i < toggleref_array_size; ++i) {
|
|
int res;
|
|
MonoGCToggleRef r = toggleref_array [i];
|
|
|
|
MonoObject *obj;
|
|
|
|
if (r.strong_ref)
|
|
obj = r.strong_ref;
|
|
else if (r.weak_ref)
|
|
obj = r.weak_ref;
|
|
else
|
|
continue;
|
|
|
|
res = toggleref_callback (obj);
|
|
++toggle_ref_counts [res];
|
|
switch (res) {
|
|
case MONO_TOGGLE_REF_DROP:
|
|
break;
|
|
case MONO_TOGGLE_REF_STRONG:
|
|
toggleref_array [w].strong_ref = obj;
|
|
toggleref_array [w].weak_ref = NULL;
|
|
++w;
|
|
break;
|
|
case MONO_TOGGLE_REF_WEAK:
|
|
toggleref_array [w].strong_ref = NULL;
|
|
toggleref_array [w].weak_ref = obj;
|
|
++w;
|
|
break;
|
|
default:
|
|
g_assert_not_reached ();
|
|
}
|
|
}
|
|
|
|
toggleref_array_size = w;
|
|
|
|
SGEN_LOG (4, "Done Proccessing ToggleRefs dropped %d strong %d weak %d final size %d",
|
|
toggle_ref_counts [MONO_TOGGLE_REF_DROP],
|
|
toggle_ref_counts [MONO_TOGGLE_REF_STRONG],
|
|
toggle_ref_counts [MONO_TOGGLE_REF_WEAK],
|
|
w);
|
|
}
|
|
|
|
void sgen_client_mark_togglerefs (char *start, char *end, ScanCopyContext ctx)
|
|
{
|
|
CopyOrMarkObjectFunc copy_func = ctx.ops->copy_or_mark_object;
|
|
SgenGrayQueue *queue = ctx.queue;
|
|
int i;
|
|
|
|
SGEN_LOG (4, "Marking ToggleRefs %d", toggleref_array_size);
|
|
|
|
for (i = 0; i < toggleref_array_size; ++i) {
|
|
if (toggleref_array [i].strong_ref) {
|
|
GCObject *object = toggleref_array [i].strong_ref;
|
|
if ((char*)object >= start && (char*)object < end) {
|
|
SGEN_LOG (6, "\tcopying strong slot %d", i);
|
|
copy_func (&toggleref_array [i].strong_ref, queue);
|
|
}
|
|
}
|
|
}
|
|
sgen_drain_gray_stack (ctx);
|
|
}
|
|
|
|
void sgen_client_clear_togglerefs (char *start, char *end, ScanCopyContext ctx)
|
|
{
|
|
CopyOrMarkObjectFunc copy_func = ctx.ops->copy_or_mark_object;
|
|
SgenGrayQueue *queue = ctx.queue;
|
|
int i;
|
|
|
|
SGEN_LOG (4, "Clearing ToggleRefs %d", toggleref_array_size);
|
|
|
|
for (i = 0; i < toggleref_array_size; ++i) {
|
|
if (toggleref_array [i].weak_ref) {
|
|
GCObject *object = toggleref_array [i].weak_ref;
|
|
|
|
if ((char*)object >= start && (char*)object < end) {
|
|
if (sgen_gc_is_object_ready_for_finalization (object)) {
|
|
SGEN_LOG (6, "\tcleaning weak slot %d", i);
|
|
toggleref_array [i].weak_ref = NULL; /* We defer compaction to only happen on the callback step. */
|
|
} else {
|
|
SGEN_LOG (6, "\tkeeping weak slot %d", i);
|
|
copy_func (&toggleref_array [i].weak_ref, queue);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
sgen_drain_gray_stack (ctx);
|
|
}
|
|
|
|
static void
|
|
ensure_toggleref_capacity (int capacity)
|
|
{
|
|
if (!toggleref_array) {
|
|
toggleref_array_capacity = 32;
|
|
toggleref_array = (MonoGCToggleRef *)sgen_alloc_internal_dynamic (
|
|
toggleref_array_capacity * sizeof (MonoGCToggleRef),
|
|
INTERNAL_MEM_TOGGLEREF_DATA,
|
|
TRUE);
|
|
}
|
|
if (toggleref_array_size + capacity >= toggleref_array_capacity) {
|
|
MonoGCToggleRef *tmp;
|
|
int old_capacity = toggleref_array_capacity;
|
|
while (toggleref_array_capacity < toggleref_array_size + capacity)
|
|
toggleref_array_capacity *= 2;
|
|
|
|
tmp = (MonoGCToggleRef *)sgen_alloc_internal_dynamic (
|
|
toggleref_array_capacity * sizeof (MonoGCToggleRef),
|
|
INTERNAL_MEM_TOGGLEREF_DATA,
|
|
TRUE);
|
|
|
|
memcpy (tmp, toggleref_array, toggleref_array_size * sizeof (MonoGCToggleRef));
|
|
|
|
sgen_free_internal_dynamic (toggleref_array, old_capacity * sizeof (MonoGCToggleRef), INTERNAL_MEM_TOGGLEREF_DATA);
|
|
toggleref_array = tmp;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* mono_gc_toggleref_add:
|
|
* @object object to register for toggleref processing
|
|
* @strong_ref if true the object is registered with a strong ref, a weak one otherwise
|
|
*
|
|
* Register a given object for toggleref processing. It will be stored internally and the toggleref callback will be called
|
|
* on it until it returns MONO_TOGGLE_REF_DROP or is collected.
|
|
*/
|
|
void
|
|
mono_gc_toggleref_add (MonoObject *object, mono_bool strong_ref)
|
|
{
|
|
if (!toggleref_callback)
|
|
return;
|
|
|
|
SGEN_LOG (4, "Adding toggleref %p %d", object, strong_ref);
|
|
|
|
sgen_gc_lock ();
|
|
|
|
ensure_toggleref_capacity (1);
|
|
toggleref_array [toggleref_array_size].strong_ref = strong_ref ? object : NULL;
|
|
toggleref_array [toggleref_array_size].weak_ref = strong_ref ? NULL : object;
|
|
++toggleref_array_size;
|
|
|
|
sgen_gc_unlock ();
|
|
}
|
|
|
|
/**
|
|
* mono_gc_toggleref_register_callback:
|
|
* \param callback callback used to determine the new state of the given object.
|
|
*
|
|
* The callback must decide the status of a given object. It must return one of the values in the \c MONO_TOGGLE_REF_ enum.
|
|
* This function is called with the world running but with the GC locked. This means that you can do everything that doesn't
|
|
* require GC interaction. This includes, but not limited to, allocating objects, (de)registering for finalization, manipulating
|
|
* gchandles, storing to reference fields or interacting with other threads that might perform such operations.
|
|
*/
|
|
void
|
|
mono_gc_toggleref_register_callback (MonoToggleRefStatus (*proccess_toggleref) (MonoObject *obj))
|
|
{
|
|
toggleref_callback = proccess_toggleref;
|
|
}
|
|
|
|
static MonoToggleRefStatus
|
|
test_toggleref_callback (MonoObject *obj)
|
|
{
|
|
static MonoClassField *mono_toggleref_test_field;
|
|
MonoToggleRefStatus status = MONO_TOGGLE_REF_DROP;
|
|
|
|
if (!mono_toggleref_test_field) {
|
|
mono_toggleref_test_field = mono_class_get_field_from_name (mono_object_get_class (obj), "__test");
|
|
g_assert (mono_toggleref_test_field);
|
|
}
|
|
|
|
mono_field_get_value (obj, mono_toggleref_test_field, &status);
|
|
printf ("toggleref-cb obj %d\n", status);
|
|
return status;
|
|
}
|
|
|
|
void
|
|
sgen_register_test_toggleref_callback (void)
|
|
{
|
|
toggleref_callback = test_toggleref_callback;
|
|
}
|
|
|
|
#endif
|