[metadata] Fix leaks when handling a few attributes (#16675)
[mono-project.git] / mono / metadata / sgen-toggleref.c
blob09f5cfa46ed3c1608ad2626e7ae38be559d1e88c
1 /**
2 * \file
3 * toggleref support for sgen
5 * Author:
6 * Rodrigo Kumpera (kumpera@gmail.com)
8 * Copyright 2011 Xamarin, Inc.
9 * Copyright (C) 2012 Xamarin Inc
11 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
14 #include "config.h"
16 #ifdef HAVE_SGEN_GC
18 #include "sgen/sgen-gc.h"
19 #include "sgen-toggleref.h"
20 #include "sgen/sgen-client.h"
23 /*only one of the two can be non null at a given time*/
24 typedef struct {
25 GCObject *strong_ref;
26 GCObject *weak_ref;
27 } MonoGCToggleRef;
29 static MonoToggleRefStatus (*toggleref_callback) (MonoObject *obj);
30 static MonoGCToggleRef *toggleref_array;
31 static int toggleref_array_size;
32 static int toggleref_array_capacity;
34 void
35 sgen_process_togglerefs (void)
37 int i, w;
38 int toggle_ref_counts [3] = { 0, 0, 0 };
40 SGEN_LOG (4, "Proccessing ToggleRefs %d", toggleref_array_size);
42 for (i = w = 0; i < toggleref_array_size; ++i) {
43 int res;
44 MonoGCToggleRef r = toggleref_array [i];
46 MonoObject *obj;
48 if (r.strong_ref)
49 obj = r.strong_ref;
50 else if (r.weak_ref)
51 obj = r.weak_ref;
52 else
53 continue;
55 res = toggleref_callback (obj);
56 ++toggle_ref_counts [res];
57 switch (res) {
58 case MONO_TOGGLE_REF_DROP:
59 break;
60 case MONO_TOGGLE_REF_STRONG:
61 toggleref_array [w].strong_ref = obj;
62 toggleref_array [w].weak_ref = NULL;
63 ++w;
64 break;
65 case MONO_TOGGLE_REF_WEAK:
66 toggleref_array [w].strong_ref = NULL;
67 toggleref_array [w].weak_ref = obj;
68 ++w;
69 break;
70 default:
71 g_assert_not_reached ();
75 toggleref_array_size = w;
77 SGEN_LOG (4, "Done Proccessing ToggleRefs dropped %d strong %d weak %d final size %d",
78 toggle_ref_counts [MONO_TOGGLE_REF_DROP],
79 toggle_ref_counts [MONO_TOGGLE_REF_STRONG],
80 toggle_ref_counts [MONO_TOGGLE_REF_WEAK],
81 w);
84 void sgen_client_mark_togglerefs (char *start, char *end, ScanCopyContext ctx)
86 CopyOrMarkObjectFunc copy_func = ctx.ops->copy_or_mark_object;
87 SgenGrayQueue *queue = ctx.queue;
88 int i;
90 SGEN_LOG (4, "Marking ToggleRefs %d", toggleref_array_size);
92 for (i = 0; i < toggleref_array_size; ++i) {
93 if (toggleref_array [i].strong_ref) {
94 GCObject *object = toggleref_array [i].strong_ref;
95 if ((char*)object >= start && (char*)object < end) {
96 SGEN_LOG (6, "\tcopying strong slot %d", i);
97 copy_func (&toggleref_array [i].strong_ref, queue);
101 sgen_drain_gray_stack (ctx);
104 void sgen_client_clear_togglerefs (char *start, char *end, ScanCopyContext ctx)
106 CopyOrMarkObjectFunc copy_func = ctx.ops->copy_or_mark_object;
107 SgenGrayQueue *queue = ctx.queue;
108 int i;
110 SGEN_LOG (4, "Clearing ToggleRefs %d", toggleref_array_size);
112 for (i = 0; i < toggleref_array_size; ++i) {
113 if (toggleref_array [i].weak_ref) {
114 GCObject *object = toggleref_array [i].weak_ref;
116 if ((char*)object >= start && (char*)object < end) {
117 if (sgen_gc_is_object_ready_for_finalization (object)) {
118 SGEN_LOG (6, "\tcleaning weak slot %d", i);
119 toggleref_array [i].weak_ref = NULL; /* We defer compaction to only happen on the callback step. */
120 } else {
121 SGEN_LOG (6, "\tkeeping weak slot %d", i);
122 copy_func (&toggleref_array [i].weak_ref, queue);
127 sgen_drain_gray_stack (ctx);
130 static void
131 ensure_toggleref_capacity (int capacity)
133 if (!toggleref_array) {
134 toggleref_array_capacity = 32;
135 toggleref_array = (MonoGCToggleRef *)sgen_alloc_internal_dynamic (
136 toggleref_array_capacity * sizeof (MonoGCToggleRef),
137 INTERNAL_MEM_TOGGLEREF_DATA,
138 TRUE);
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_capacity *= 2;
146 tmp = (MonoGCToggleRef *)sgen_alloc_internal_dynamic (
147 toggleref_array_capacity * sizeof (MonoGCToggleRef),
148 INTERNAL_MEM_TOGGLEREF_DATA,
149 TRUE);
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.
166 void
167 mono_gc_toggleref_add (MonoObject *object, mono_bool strong_ref)
169 if (!toggleref_callback)
170 return;
172 MONO_ENTER_GC_UNSAFE;
174 SGEN_LOG (4, "Adding toggleref %p %d", object, strong_ref);
176 sgen_gc_lock ();
178 ensure_toggleref_capacity (1);
179 toggleref_array [toggleref_array_size].strong_ref = strong_ref ? object : NULL;
180 toggleref_array [toggleref_array_size].weak_ref = strong_ref ? NULL : object;
181 ++toggleref_array_size;
183 sgen_gc_unlock ();
185 MONO_EXIT_GC_UNSAFE;
189 * mono_gc_toggleref_register_callback:
190 * \param callback callback used to determine the new state of the given object.
192 * The callback must decide the status of a given object. It must return one of the values in the \c MONO_TOGGLE_REF_ enum.
193 * This function is called with the world running but with the GC locked. This means that you can do everything that doesn't
194 * require GC interaction. This includes, but not limited to, allocating objects, (de)registering for finalization, manipulating
195 * gchandles, storing to reference fields or interacting with other threads that might perform such operations.
197 void
198 mono_gc_toggleref_register_callback (MonoToggleRefStatus (*proccess_toggleref) (MonoObject *obj))
200 toggleref_callback = proccess_toggleref;
203 static MonoToggleRefStatus
204 test_toggleref_callback (MonoObject *obj)
206 static MonoClassField *mono_toggleref_test_field;
207 MonoToggleRefStatus status = MONO_TOGGLE_REF_DROP;
209 if (!mono_toggleref_test_field) {
210 mono_toggleref_test_field = mono_class_get_field_from_name_full (mono_object_class (obj), "__test", NULL);
211 g_assert (mono_toggleref_test_field);
214 /* In coop mode, important to not call a helper that will pin obj! */
215 mono_field_get_value_internal (obj, mono_toggleref_test_field, &status);
216 printf ("toggleref-cb obj %d\n", status);
217 return status;
220 void
221 sgen_register_test_toggleref_callback (void)
223 toggleref_callback = test_toggleref_callback;
226 #endif