2 * sgen-toggleref.c: toggleref support for sgen
5 * Rodrigo Kumpera (kumpera@gmail.com)
7 * Copyright 2011 Xamarin, Inc.
8 * Copyright (C) 2012 Xamarin Inc
10 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
17 #include "sgen/sgen-gc.h"
18 #include "sgen-toggleref.h"
19 #include "sgen/sgen-client.h"
22 /*only one of the two can be non null at a given time*/
28 static MonoToggleRefStatus (*toggleref_callback) (MonoObject *obj);
29 static MonoGCToggleRef *toggleref_array;
30 static int toggleref_array_size;
31 static int toggleref_array_capacity;
34 sgen_process_togglerefs (void)
37 int toggle_ref_counts [3] = { 0, 0, 0 };
39 SGEN_LOG (4, "Proccessing ToggleRefs %d", toggleref_array_size);
41 for (i = w = 0; i < toggleref_array_size; ++i) {
43 MonoGCToggleRef r = toggleref_array [i];
54 res = toggleref_callback (obj);
55 ++toggle_ref_counts [res];
57 case MONO_TOGGLE_REF_DROP:
59 case MONO_TOGGLE_REF_STRONG:
60 toggleref_array [w].strong_ref = obj;
61 toggleref_array [w].weak_ref = NULL;
64 case MONO_TOGGLE_REF_WEAK:
65 toggleref_array [w].strong_ref = NULL;
66 toggleref_array [w].weak_ref = obj;
70 g_assert_not_reached ();
74 toggleref_array_size = w;
76 SGEN_LOG (4, "Done Proccessing ToggleRefs dropped %d strong %d weak %d final size %d",
77 toggle_ref_counts [MONO_TOGGLE_REF_DROP],
78 toggle_ref_counts [MONO_TOGGLE_REF_STRONG],
79 toggle_ref_counts [MONO_TOGGLE_REF_WEAK],
83 void sgen_client_mark_togglerefs (char *start, char *end, ScanCopyContext ctx)
85 CopyOrMarkObjectFunc copy_func = ctx.ops->copy_or_mark_object;
86 SgenGrayQueue *queue = ctx.queue;
89 SGEN_LOG (4, "Marking ToggleRefs %d", toggleref_array_size);
91 for (i = 0; i < toggleref_array_size; ++i) {
92 if (toggleref_array [i].strong_ref) {
93 GCObject *object = toggleref_array [i].strong_ref;
94 if ((char*)object >= start && (char*)object < end) {
95 SGEN_LOG (6, "\tcopying strong slot %d", i);
96 copy_func (&toggleref_array [i].strong_ref, queue);
100 sgen_drain_gray_stack (ctx);
103 void sgen_client_clear_togglerefs (char *start, char *end, ScanCopyContext ctx)
105 CopyOrMarkObjectFunc copy_func = ctx.ops->copy_or_mark_object;
106 SgenGrayQueue *queue = ctx.queue;
109 SGEN_LOG (4, "Clearing ToggleRefs %d", toggleref_array_size);
111 for (i = 0; i < toggleref_array_size; ++i) {
112 if (toggleref_array [i].weak_ref) {
113 GCObject *object = toggleref_array [i].weak_ref;
115 if ((char*)object >= start && (char*)object < end) {
116 if (sgen_gc_is_object_ready_for_finalization (object)) {
117 SGEN_LOG (6, "\tcleaning weak slot %d", i);
118 toggleref_array [i].weak_ref = NULL; /* We defer compaction to only happen on the callback step. */
120 SGEN_LOG (6, "\tkeeping weak slot %d", i);
121 copy_func (&toggleref_array [i].weak_ref, queue);
126 sgen_drain_gray_stack (ctx);
130 ensure_toggleref_capacity (int capacity)
132 if (!toggleref_array) {
133 toggleref_array_capacity = 32;
134 toggleref_array = (MonoGCToggleRef *)sgen_alloc_internal_dynamic (
135 toggleref_array_capacity * sizeof (MonoGCToggleRef),
136 INTERNAL_MEM_TOGGLEREF_DATA,
139 if (toggleref_array_size + capacity >= toggleref_array_capacity) {
140 MonoGCToggleRef *tmp;
141 int old_capacity = toggleref_array_capacity;
142 while (toggleref_array_capacity < toggleref_array_size + capacity)
143 toggleref_array_capacity *= 2;
145 tmp = (MonoGCToggleRef *)sgen_alloc_internal_dynamic (
146 toggleref_array_capacity * sizeof (MonoGCToggleRef),
147 INTERNAL_MEM_TOGGLEREF_DATA,
150 memcpy (tmp, toggleref_array, toggleref_array_size * sizeof (MonoGCToggleRef));
152 sgen_free_internal_dynamic (toggleref_array, old_capacity * sizeof (MonoGCToggleRef), INTERNAL_MEM_TOGGLEREF_DATA);
153 toggleref_array = tmp;
158 * mono_gc_toggleref_add:
159 * @object object to register for toggleref processing
160 * @strong_ref if true the object is registered with a strong ref, a weak one otherwise
162 * Register a given object for toggleref processing. It will be stored internally and the toggleref callback will be called
163 * on it until it returns MONO_TOGGLE_REF_DROP or is collected.
166 mono_gc_toggleref_add (MonoObject *object, mono_bool strong_ref)
168 if (!toggleref_callback)
171 SGEN_LOG (4, "Adding toggleref %p %d", object, strong_ref);
175 ensure_toggleref_capacity (1);
176 toggleref_array [toggleref_array_size].strong_ref = strong_ref ? object : NULL;
177 toggleref_array [toggleref_array_size].weak_ref = strong_ref ? NULL : object;
178 ++toggleref_array_size;
184 * mono_gc_toggleref_register_callback:
185 * @callback callback used to determine the new state of the given object.
187 * The callback must decide the status of a given object. It must return one of the values in the MONO_TOGGLE_REF_ enum.
188 * This function is called with the world running but with the GC locked. This means that you can do everything that doesn't
189 * require GC interaction. This includes, but not limited to, allocating objects, (de)registering for finalization, manipulating
190 *gchandles, storing to reference fields or interacting with other threads that might perform such operations.
193 mono_gc_toggleref_register_callback (MonoToggleRefStatus (*proccess_toggleref) (MonoObject *obj))
195 toggleref_callback = proccess_toggleref;
198 static MonoToggleRefStatus
199 test_toggleref_callback (MonoObject *obj)
201 static MonoClassField *mono_toggleref_test_field;
202 MonoToggleRefStatus status = MONO_TOGGLE_REF_DROP;
204 if (!mono_toggleref_test_field) {
205 mono_toggleref_test_field = mono_class_get_field_from_name (mono_object_get_class (obj), "__test");
206 g_assert (mono_toggleref_test_field);
209 mono_field_get_value (obj, mono_toggleref_test_field, &status);
210 printf ("toggleref-cb obj %d\n", status);
215 sgen_register_test_toggleref_callback (void)
217 toggleref_callback = test_toggleref_callback;