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 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Library General Public
12 * License 2.0 as published by the Free Software Foundation;
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
19 * You should have received a copy of the GNU Library General Public
20 * License 2.0 along with this library; if not, write to the Free
21 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 #include "sgen-toggleref.h"
32 /*only one of the two can be non null at a given time*/
38 static MonoToggleRefStatus (*toggleref_callback) (MonoObject *obj);
39 static MonoGCToggleRef *toggleref_array;
40 static int toggleref_array_size;
41 static int toggleref_array_capacity;
44 sgen_process_togglerefs (void)
47 int toggle_ref_counts [3] = { 0, 0, 0 };
49 SGEN_LOG (4, "Proccessing ToggleRefs %d", toggleref_array_size);
51 for (i = w = 0; i < toggleref_array_size; ++i) {
53 MonoGCToggleRef r = toggleref_array [i];
64 res = toggleref_callback (obj);
65 ++toggle_ref_counts [res];
67 case MONO_TOGGLE_REF_DROP:
69 case MONO_TOGGLE_REF_STRONG:
70 toggleref_array [w].strong_ref = obj;
71 toggleref_array [w].weak_ref = NULL;
74 case MONO_TOGGLE_REF_WEAK:
75 toggleref_array [w].strong_ref = NULL;
76 toggleref_array [w].weak_ref = obj;
80 g_assert_not_reached ();
84 toggleref_array_size = w;
86 SGEN_LOG (4, "Done Proccessing ToggleRefs dropped %d strong %d weak %d final size %d",
87 toggle_ref_counts [MONO_TOGGLE_REF_DROP],
88 toggle_ref_counts [MONO_TOGGLE_REF_STRONG],
89 toggle_ref_counts [MONO_TOGGLE_REF_WEAK],
94 sgen_scan_togglerefs (CopyOrMarkObjectFunc copy_func, char *start, char *end, SgenGrayQueue *queue)
98 SGEN_LOG (4, "Scanning ToggleRefs %d", toggleref_array_size);
100 for (i = 0; i < toggleref_array_size; ++i) {
101 if (toggleref_array [i].strong_ref) {
102 char *object = toggleref_array [i].strong_ref;
103 if (object >= start && object < end) {
104 SGEN_LOG (6, "\tcopying strong slot %d", i);
105 copy_func (&toggleref_array [i].strong_ref, queue);
107 } else if (toggleref_array [i].weak_ref) {
108 char *object = toggleref_array [i].weak_ref;
110 if (object >= start && object < end) {
111 if (sgen_gc_is_object_ready_for_finalization (object)) {
112 SGEN_LOG (6, "\tcleaning weak slot %d", i);
113 toggleref_array [i].weak_ref = NULL; /* We defer compaction to only happen on the callback step. */
115 SGEN_LOG (6, "\tkeeping weak slot %d", i);
116 copy_func (&toggleref_array [i].weak_ref, queue);
124 ensure_toggleref_capacity (int capacity)
126 if (!toggleref_array) {
127 toggleref_array_capacity = 32;
128 toggleref_array = sgen_alloc_internal_dynamic (
129 toggleref_array_capacity * sizeof (MonoGCToggleRef),
130 INTERNAL_MEM_TOGGLEREF_DATA,
133 if (toggleref_array_size + capacity >= toggleref_array_capacity) {
134 MonoGCToggleRef *tmp;
135 int old_capacity = toggleref_array_capacity;
136 while (toggleref_array_capacity < toggleref_array_size + capacity)
137 toggleref_array_size *= 2;
139 tmp = sgen_alloc_internal_dynamic (
140 toggleref_array_capacity * sizeof (MonoGCToggleRef),
141 INTERNAL_MEM_TOGGLEREF_DATA,
144 memcpy (tmp, toggleref_array, toggleref_array_size * sizeof (MonoGCToggleRef));
146 sgen_free_internal_dynamic (toggleref_array, old_capacity * sizeof (MonoGCToggleRef), INTERNAL_MEM_TOGGLEREF_DATA);
147 toggleref_array = tmp;
152 * mono_gc_toggleref_add:
153 * @object object to register for toggleref processing
154 * @strong_ref if true the object is registered with a strong ref, a weak one otherwise
156 * Register a given object for toggleref processing. It will be stored internally and the toggleref callback will be called
157 * on it until it returns MONO_TOGGLE_REF_DROP or is collected.
160 mono_gc_toggleref_add (MonoObject *object, mono_bool strong_ref)
162 if (!toggleref_callback)
165 SGEN_LOG (4, "Adding toggleref %p %d", object, strong_ref);
169 ensure_toggleref_capacity (1);
170 toggleref_array [toggleref_array_size].strong_ref = strong_ref ? object : NULL;
171 toggleref_array [toggleref_array_size].weak_ref = strong_ref ? NULL : object;
172 ++toggleref_array_size;
178 * mono_gc_toggleref_register_callback:
179 * @callback callback used to determine the new state of the given object.
181 * The callback must decide the status of a given object. It must return one of the values in the MONO_TOGGLE_REF_ enum.
182 * This function is called with the world running but with the GC locked. This means that you can do everything that doesn't
183 * require GC interaction. This includes, but not limited to, allocating objects, (de)registering for finalization, manipulating
184 *gchandles, storing to reference fields or interacting with other threads that might perform such operations.
187 mono_gc_toggleref_register_callback (MonoToggleRefStatus (*proccess_toggleref) (MonoObject *obj))
189 toggleref_callback = proccess_toggleref;