Merged into single file, added assertions
[mono.git] / mono / metadata / sgen-toggleref.c
1 /*
2  *
3  * sgen-toggleref.c: toggleref support for sgen
4  *
5  * Copyright 2011 Xamarin, Inc.
6  *
7  * Author:
8  *  Rodrigo Kumpera (kumpera@gmail.com)
9  * 
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:
17  * 
18  * The above copyright notice and this permission notice shall be
19  * included in all copies or substantial portions of the Software.
20  * 
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.
28  */
29
30
31 #include "config.h"
32
33 #ifdef HAVE_SGEN_GC
34
35 #include "sgen-gc.h"
36 #include "sgen-toggleref.h"
37
38
39 /*only one of the two can be non null at a given time*/
40 typedef struct {
41         void *strong_ref;
42         void *weak_ref;
43 } MonoGCToggleRef;
44
45 static MonoToggleRefStatus (*toggleref_callback) (MonoObject *obj);
46 static MonoGCToggleRef *toggleref_array;
47 static int toggleref_array_size;
48 static int toggleref_array_capacity;
49
50 void
51 sgen_process_togglerefs (void)
52 {
53         int i, w;
54         int toggle_ref_counts [3] = { 0, 0, 0 };
55
56         DEBUG (4, fprintf (gc_debug_file, "Proccessing ToggleRefs %d\n", toggleref_array_size));
57
58         for (i = w = 0; i < toggleref_array_size; ++i) {
59                 int res;
60                 MonoGCToggleRef r = toggleref_array [i];
61
62                 MonoObject *obj;
63
64                 if (r.strong_ref)
65                         obj = r.strong_ref;
66                 else if (r.weak_ref)
67                         obj = r.weak_ref;
68                 else
69                         continue;
70
71                 res = toggleref_callback (obj);
72                 ++toggle_ref_counts [res];
73                 switch (res) {
74                 case MONO_TOGGLE_REF_DROP:
75                         break;
76                 case MONO_TOGGLE_REF_STRONG:
77                         toggleref_array [w].strong_ref = obj;
78                         toggleref_array [w].weak_ref = NULL;
79                         ++w;
80                         break;
81                 case MONO_TOGGLE_REF_WEAK:
82                         toggleref_array [w].strong_ref = NULL;
83                         toggleref_array [w].weak_ref = obj;
84                         ++w;
85                         break;
86                 default:
87                         g_assert_not_reached ();
88                 }
89         }
90
91         toggleref_array_size = w;
92
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],
97                 w));
98 }
99
100 void
101 sgen_scan_togglerefs (CopyOrMarkObjectFunc copy_func, char *start, char *end, SgenGrayQueue *queue)
102 {
103         int i;
104
105         DEBUG (4, fprintf (gc_debug_file, "Scanning ToggleRefs %d\n", toggleref_array_size));
106
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);
113                         }
114                 } else if (toggleref_array [i].weak_ref) {
115                         char *object = toggleref_array [i].weak_ref;
116
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. */
121                                 } else {
122                                         DEBUG (6, fprintf (gc_debug_file, "\tkeeping weak slot %d\n", i));
123                                         copy_func (&toggleref_array [i].weak_ref, queue);
124                                 }
125                         }
126                 }
127         }
128 }
129
130 static void
131 ensure_toggleref_capacity (int capacity)
132 {
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,
138                         TRUE);
139         }
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;
145
146                 tmp = sgen_alloc_internal_dynamic (
147                         toggleref_array_capacity * sizeof (MonoGCToggleRef),
148                         INTERNAL_MEM_TOGGLEREF_DATA,
149                         TRUE);
150
151                 memcpy (tmp, toggleref_array, toggleref_array_size * sizeof (MonoGCToggleRef));
152
153                 sgen_free_internal_dynamic (toggleref_array, old_capacity * sizeof (MonoGCToggleRef), INTERNAL_MEM_TOGGLEREF_DATA);
154                 toggleref_array = tmp;
155         }
156 }
157
158 /**
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
162  *
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.
165 */
166 void
167 mono_gc_toggleref_add (MonoObject *object, mono_bool strong_ref)
168 {
169         if (!toggleref_callback)
170                 return;
171
172         DEBUG (4, fprintf (gc_debug_file, "Adding toggleref %p %d\n", object, strong_ref));
173
174         sgen_gc_lock ();
175
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;
180
181         sgen_gc_unlock ();
182 }
183
184 /**
185  * mono_gc_toggleref_register_callback:
186  * @callback callback used to determine the new state of the given object.
187  *
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.
192  */
193 void
194 mono_gc_toggleref_register_callback (MonoToggleRefStatus (*proccess_toggleref) (MonoObject *obj))
195 {
196         toggleref_callback = proccess_toggleref;
197 }
198
199 #endif