3 * sgen-toggleref.c: toggleref support for sgen
5 * Copyright 2011 Xamarin, Inc.
8 * Rodrigo Kumpera (kumpera@gmail.com)
10 * Permission is hereby granted, free of charge, to any person obtaining
11 * a copy of this software and associated documentation files (the
12 * "Software"), to deal in the Software without restriction, including
13 * without limitation the rights to use, copy, modify, merge, publish,
14 * distribute, sublicense, and/or sell copies of the Software, and to
15 * permit persons to whom the Software is furnished to do so, subject to
16 * the following conditions:
18 * The above copyright notice and this permission notice shall be
19 * included in all copies or substantial portions of the Software.
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 #include "sgen-toggleref.h"
39 /*only one of the two can be non null at a given time*/
45 static MonoToggleRefStatus (*toggleref_callback) (MonoObject *obj);
46 static MonoGCToggleRef *toggleref_array;
47 static int toggleref_array_size;
48 static int toggleref_array_capacity;
51 sgen_process_togglerefs (void)
54 int toggle_ref_counts [3] = { 0, 0, 0 };
56 DEBUG (4, fprintf (gc_debug_file, "Proccessing ToggleRefs %d\n", toggleref_array_size));
58 for (i = w = 0; i < toggleref_array_size; ++i) {
60 MonoGCToggleRef r = toggleref_array [i];
71 res = toggleref_callback (obj);
72 ++toggle_ref_counts [res];
74 case MONO_TOGGLE_REF_DROP:
76 case MONO_TOGGLE_REF_STRONG:
77 toggleref_array [w].strong_ref = obj;
78 toggleref_array [w].weak_ref = NULL;
81 case MONO_TOGGLE_REF_WEAK:
82 toggleref_array [w].strong_ref = NULL;
83 toggleref_array [w].weak_ref = obj;
87 g_assert_not_reached ();
91 toggleref_array_size = w;
93 DEBUG (4, fprintf (gc_debug_file, "Done Proccessing ToggleRefs dropped %d strong %d weak %d final size %d\n",
94 toggle_ref_counts [MONO_TOGGLE_REF_DROP],
95 toggle_ref_counts [MONO_TOGGLE_REF_STRONG],
96 toggle_ref_counts [MONO_TOGGLE_REF_WEAK],
101 sgen_scan_togglerefs (CopyOrMarkObjectFunc copy_func, char *start, char *end, SgenGrayQueue *queue)
105 DEBUG (4, fprintf (gc_debug_file, "Scanning ToggleRefs %d\n", toggleref_array_size));
107 for (i = 0; i < toggleref_array_size; ++i) {
108 if (toggleref_array [i].strong_ref) {
109 char *object = toggleref_array [i].strong_ref;
110 if (object >= start && object < end) {
111 DEBUG (6, fprintf (gc_debug_file, "\tcopying strong slot %d\n", i));
112 copy_func (&toggleref_array [i].strong_ref, queue);
114 } else if (toggleref_array [i].weak_ref) {
115 char *object = toggleref_array [i].weak_ref;
117 if (object >= start && object < end) {
118 if (sgen_gc_is_object_ready_for_finalization (object)) {
119 DEBUG (6, fprintf (gc_debug_file, "\tcleaning weak slot %d\n", i));
120 toggleref_array [i].weak_ref = NULL; /* We defer compaction to only happen on the callback step. */
122 DEBUG (6, fprintf (gc_debug_file, "\tkeeping weak slot %d\n", i));
123 copy_func (&toggleref_array [i].weak_ref, queue);
131 ensure_toggleref_capacity (int capacity)
133 if (!toggleref_array) {
134 toggleref_array_capacity = 32;
135 toggleref_array = sgen_alloc_internal_dynamic (
136 toggleref_array_capacity * sizeof (MonoGCToggleRef),
137 INTERNAL_MEM_TOGGLEREF_DATA,
140 if (toggleref_array_size + capacity >= toggleref_array_capacity) {
141 MonoGCToggleRef *tmp;
142 int old_capacity = toggleref_array_capacity;
143 while (toggleref_array_capacity < toggleref_array_size + capacity)
144 toggleref_array_size *= 2;
146 tmp = sgen_alloc_internal_dynamic (
147 toggleref_array_capacity * sizeof (MonoGCToggleRef),
148 INTERNAL_MEM_TOGGLEREF_DATA,
151 memcpy (tmp, toggleref_array, toggleref_array_size * sizeof (MonoGCToggleRef));
153 sgen_free_internal_dynamic (toggleref_array, old_capacity * sizeof (MonoGCToggleRef), INTERNAL_MEM_TOGGLEREF_DATA);
154 toggleref_array = tmp;
159 * mono_gc_toggleref_add:
160 * @object object to register for toggleref processing
161 * @strong_ref if true the object is registered with a strong ref, a weak one otherwise
163 * Register a given object for toggleref processing. It will be stored internally and the toggleref callback will be called
164 * on it until it returns MONO_TOGGLE_REF_DROP or is collected.
167 mono_gc_toggleref_add (MonoObject *object, mono_bool strong_ref)
169 if (!toggleref_callback)
172 DEBUG (4, fprintf (gc_debug_file, "Adding toggleref %p %d\n", object, strong_ref));
176 ensure_toggleref_capacity (1);
177 toggleref_array [toggleref_array_size].strong_ref = strong_ref ? object : NULL;
178 toggleref_array [toggleref_array_size].weak_ref = strong_ref ? NULL : object;
179 ++toggleref_array_size;
185 * mono_gc_toggleref_register_callback:
186 * @callback callback used to determine the new state of the given object.
188 * The callback must decide the status of a given object. It must return one of the values in the MONO_TOGGLE_REF_ enum.
189 * This function is called with the world running but with the GC locked. This means that you can do everything that doesn't
190 * require GC interaction. This includes, but not limited to, allocating objects, (de)registering for finalization, manipulating
191 *gchandles, storing to reference fields or interacting with other threads that might perform such operations.
194 mono_gc_toggleref_register_callback (MonoToggleRefStatus (*proccess_toggleref) (MonoObject *obj))
196 toggleref_callback = proccess_toggleref;