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.
28 #include "sgen/sgen-gc.h"
29 #include "sgen-toggleref.h"
30 #include "sgen/sgen-client.h"
33 /*only one of the two can be non null at a given time*/
39 static MonoToggleRefStatus (*toggleref_callback
) (MonoObject
*obj
);
40 static MonoGCToggleRef
*toggleref_array
;
41 static int toggleref_array_size
;
42 static int toggleref_array_capacity
;
45 sgen_process_togglerefs (void)
48 int toggle_ref_counts
[3] = { 0, 0, 0 };
50 SGEN_LOG (4, "Proccessing ToggleRefs %d", toggleref_array_size
);
52 for (i
= w
= 0; i
< toggleref_array_size
; ++i
) {
54 MonoGCToggleRef r
= toggleref_array
[i
];
65 res
= toggleref_callback (obj
);
66 ++toggle_ref_counts
[res
];
68 case MONO_TOGGLE_REF_DROP
:
70 case MONO_TOGGLE_REF_STRONG
:
71 toggleref_array
[w
].strong_ref
= obj
;
72 toggleref_array
[w
].weak_ref
= NULL
;
75 case MONO_TOGGLE_REF_WEAK
:
76 toggleref_array
[w
].strong_ref
= NULL
;
77 toggleref_array
[w
].weak_ref
= obj
;
81 g_assert_not_reached ();
85 toggleref_array_size
= w
;
87 SGEN_LOG (4, "Done Proccessing ToggleRefs dropped %d strong %d weak %d final size %d",
88 toggle_ref_counts
[MONO_TOGGLE_REF_DROP
],
89 toggle_ref_counts
[MONO_TOGGLE_REF_STRONG
],
90 toggle_ref_counts
[MONO_TOGGLE_REF_WEAK
],
94 void sgen_client_mark_togglerefs (char *start
, char *end
, ScanCopyContext ctx
)
96 CopyOrMarkObjectFunc copy_func
= ctx
.ops
->copy_or_mark_object
;
97 SgenGrayQueue
*queue
= ctx
.queue
;
100 SGEN_LOG (4, "Marking ToggleRefs %d", toggleref_array_size
);
102 for (i
= 0; i
< toggleref_array_size
; ++i
) {
103 if (toggleref_array
[i
].strong_ref
) {
104 GCObject
*object
= toggleref_array
[i
].strong_ref
;
105 if ((char*)object
>= start
&& (char*)object
< end
) {
106 SGEN_LOG (6, "\tcopying strong slot %d", i
);
107 copy_func (&toggleref_array
[i
].strong_ref
, queue
);
111 sgen_drain_gray_stack (-1, ctx
);
114 void sgen_client_clear_togglerefs (char *start
, char *end
, ScanCopyContext ctx
)
116 CopyOrMarkObjectFunc copy_func
= ctx
.ops
->copy_or_mark_object
;
117 SgenGrayQueue
*queue
= ctx
.queue
;
120 SGEN_LOG (4, "Clearing ToggleRefs %d", toggleref_array_size
);
122 for (i
= 0; i
< toggleref_array_size
; ++i
) {
123 if (toggleref_array
[i
].weak_ref
) {
124 GCObject
*object
= toggleref_array
[i
].weak_ref
;
126 if ((char*)object
>= start
&& (char*)object
< end
) {
127 if (sgen_gc_is_object_ready_for_finalization (object
)) {
128 SGEN_LOG (6, "\tcleaning weak slot %d", i
);
129 toggleref_array
[i
].weak_ref
= NULL
; /* We defer compaction to only happen on the callback step. */
131 SGEN_LOG (6, "\tkeeping weak slot %d", i
);
132 copy_func (&toggleref_array
[i
].weak_ref
, queue
);
137 sgen_drain_gray_stack (-1, ctx
);
141 ensure_toggleref_capacity (int capacity
)
143 if (!toggleref_array
) {
144 toggleref_array_capacity
= 32;
145 toggleref_array
= sgen_alloc_internal_dynamic (
146 toggleref_array_capacity
* sizeof (MonoGCToggleRef
),
147 INTERNAL_MEM_TOGGLEREF_DATA
,
150 if (toggleref_array_size
+ capacity
>= toggleref_array_capacity
) {
151 MonoGCToggleRef
*tmp
;
152 int old_capacity
= toggleref_array_capacity
;
153 while (toggleref_array_capacity
< toggleref_array_size
+ capacity
)
154 toggleref_array_capacity
*= 2;
156 tmp
= sgen_alloc_internal_dynamic (
157 toggleref_array_capacity
* sizeof (MonoGCToggleRef
),
158 INTERNAL_MEM_TOGGLEREF_DATA
,
161 memcpy (tmp
, toggleref_array
, toggleref_array_size
* sizeof (MonoGCToggleRef
));
163 sgen_free_internal_dynamic (toggleref_array
, old_capacity
* sizeof (MonoGCToggleRef
), INTERNAL_MEM_TOGGLEREF_DATA
);
164 toggleref_array
= tmp
;
169 * mono_gc_toggleref_add:
170 * @object object to register for toggleref processing
171 * @strong_ref if true the object is registered with a strong ref, a weak one otherwise
173 * Register a given object for toggleref processing. It will be stored internally and the toggleref callback will be called
174 * on it until it returns MONO_TOGGLE_REF_DROP or is collected.
177 mono_gc_toggleref_add (MonoObject
*object
, mono_bool strong_ref
)
179 if (!toggleref_callback
)
182 SGEN_LOG (4, "Adding toggleref %p %d", object
, strong_ref
);
186 ensure_toggleref_capacity (1);
187 toggleref_array
[toggleref_array_size
].strong_ref
= strong_ref
? object
: NULL
;
188 toggleref_array
[toggleref_array_size
].weak_ref
= strong_ref
? NULL
: object
;
189 ++toggleref_array_size
;
195 * mono_gc_toggleref_register_callback:
196 * @callback callback used to determine the new state of the given object.
198 * The callback must decide the status of a given object. It must return one of the values in the MONO_TOGGLE_REF_ enum.
199 * This function is called with the world running but with the GC locked. This means that you can do everything that doesn't
200 * require GC interaction. This includes, but not limited to, allocating objects, (de)registering for finalization, manipulating
201 *gchandles, storing to reference fields or interacting with other threads that might perform such operations.
204 mono_gc_toggleref_register_callback (MonoToggleRefStatus (*proccess_toggleref
) (MonoObject
*obj
))
206 toggleref_callback
= proccess_toggleref
;
209 static MonoToggleRefStatus
210 test_toggleref_callback (MonoObject
*obj
)
212 static MonoClassField
*mono_toggleref_test_field
;
213 int status
= MONO_TOGGLE_REF_DROP
;
215 if (!mono_toggleref_test_field
) {
216 mono_toggleref_test_field
= mono_class_get_field_from_name (mono_object_get_class (obj
), "__test");
217 g_assert (mono_toggleref_test_field
);
220 mono_field_get_value (obj
, mono_toggleref_test_field
, &status
);
221 printf ("toggleref-cb obj %d\n", status
);
226 sgen_register_test_toggleref_callback (void)
228 toggleref_callback
= test_toggleref_callback
;