3 * toggleref support for sgen
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.
18 #include "sgen/sgen-gc.h"
19 #include "sgen-toggleref.h"
20 #include "sgen/sgen-client.h"
22 #ifndef DISABLE_SGEN_TOGGLEREF
24 /*only one of the two can be non null at a given time*/
30 static MonoToggleRefStatus (*toggleref_callback
) (MonoObject
*obj
);
31 static MonoGCToggleRef
*toggleref_array
;
32 static int toggleref_array_size
;
33 static int toggleref_array_capacity
;
36 sgen_process_togglerefs (void)
39 int toggle_ref_counts
[3] = { 0, 0, 0 };
41 SGEN_LOG (4, "Proccessing ToggleRefs %d", toggleref_array_size
);
43 for (i
= w
= 0; i
< toggleref_array_size
; ++i
) {
45 MonoGCToggleRef r
= toggleref_array
[i
];
56 res
= toggleref_callback (obj
);
57 ++toggle_ref_counts
[res
];
59 case MONO_TOGGLE_REF_DROP
:
61 case MONO_TOGGLE_REF_STRONG
:
62 toggleref_array
[w
].strong_ref
= obj
;
63 toggleref_array
[w
].weak_ref
= NULL
;
66 case MONO_TOGGLE_REF_WEAK
:
67 toggleref_array
[w
].strong_ref
= NULL
;
68 toggleref_array
[w
].weak_ref
= obj
;
72 g_assert_not_reached ();
76 toggleref_array_size
= w
;
78 SGEN_LOG (4, "Done Proccessing ToggleRefs dropped %d strong %d weak %d final size %d",
79 toggle_ref_counts
[MONO_TOGGLE_REF_DROP
],
80 toggle_ref_counts
[MONO_TOGGLE_REF_STRONG
],
81 toggle_ref_counts
[MONO_TOGGLE_REF_WEAK
],
85 void sgen_client_mark_togglerefs (char *start
, char *end
, ScanCopyContext ctx
)
87 CopyOrMarkObjectFunc copy_func
= ctx
.ops
->copy_or_mark_object
;
88 SgenGrayQueue
*queue
= ctx
.queue
;
91 SGEN_LOG (4, "Marking ToggleRefs %d", toggleref_array_size
);
93 for (i
= 0; i
< toggleref_array_size
; ++i
) {
94 if (toggleref_array
[i
].strong_ref
) {
95 GCObject
*object
= toggleref_array
[i
].strong_ref
;
96 if ((char*)object
>= start
&& (char*)object
< end
) {
97 SGEN_LOG (6, "\tcopying strong slot %d", i
);
98 copy_func (&toggleref_array
[i
].strong_ref
, queue
);
102 sgen_drain_gray_stack (ctx
);
106 sgen_foreach_toggleref_root (void (*callback
)(MonoObject
*, gpointer
), gpointer data
)
109 for (i
= 0; i
< toggleref_array_size
; ++i
) {
110 if (toggleref_array
[i
].strong_ref
)
111 callback (toggleref_array
[i
].strong_ref
, data
);
115 void sgen_client_clear_togglerefs (char *start
, char *end
, ScanCopyContext ctx
)
117 CopyOrMarkObjectFunc copy_func
= ctx
.ops
->copy_or_mark_object
;
118 SgenGrayQueue
*queue
= ctx
.queue
;
121 SGEN_LOG (4, "Clearing ToggleRefs %d", toggleref_array_size
);
123 for (i
= 0; i
< toggleref_array_size
; ++i
) {
124 if (toggleref_array
[i
].weak_ref
) {
125 GCObject
*object
= toggleref_array
[i
].weak_ref
;
127 if ((char*)object
>= start
&& (char*)object
< end
) {
128 if (sgen_gc_is_object_ready_for_finalization (object
)) {
129 SGEN_LOG (6, "\tcleaning weak slot %d", i
);
130 toggleref_array
[i
].weak_ref
= NULL
; /* We defer compaction to only happen on the callback step. */
132 SGEN_LOG (6, "\tkeeping weak slot %d", i
);
133 copy_func (&toggleref_array
[i
].weak_ref
, queue
);
138 sgen_drain_gray_stack (ctx
);
142 ensure_toggleref_capacity (int capacity
)
144 if (!toggleref_array
) {
145 toggleref_array_capacity
= 32;
146 toggleref_array
= (MonoGCToggleRef
*)sgen_alloc_internal_dynamic (
147 toggleref_array_capacity
* sizeof (MonoGCToggleRef
),
148 INTERNAL_MEM_TOGGLEREF_DATA
,
151 if (toggleref_array_size
+ capacity
>= toggleref_array_capacity
) {
152 MonoGCToggleRef
*tmp
;
153 int old_capacity
= toggleref_array_capacity
;
154 while (toggleref_array_capacity
< toggleref_array_size
+ capacity
)
155 toggleref_array_capacity
*= 2;
157 tmp
= (MonoGCToggleRef
*)sgen_alloc_internal_dynamic (
158 toggleref_array_capacity
* sizeof (MonoGCToggleRef
),
159 INTERNAL_MEM_TOGGLEREF_DATA
,
162 memcpy (tmp
, toggleref_array
, toggleref_array_size
* sizeof (MonoGCToggleRef
));
164 sgen_free_internal_dynamic (toggleref_array
, old_capacity
* sizeof (MonoGCToggleRef
), INTERNAL_MEM_TOGGLEREF_DATA
);
165 toggleref_array
= tmp
;
170 * mono_gc_toggleref_add:
171 * @object object to register for toggleref processing
172 * @strong_ref if true the object is registered with a strong ref, a weak one otherwise
174 * Register a given object for toggleref processing. It will be stored internally and the toggleref callback will be called
175 * on it until it returns MONO_TOGGLE_REF_DROP or is collected.
178 mono_gc_toggleref_add (MonoObject
*object
, mono_bool strong_ref
)
180 if (!toggleref_callback
)
183 MONO_ENTER_GC_UNSAFE
;
185 SGEN_LOG (4, "Adding toggleref %p %d", object
, strong_ref
);
189 ensure_toggleref_capacity (1);
190 toggleref_array
[toggleref_array_size
].strong_ref
= strong_ref
? object
: NULL
;
191 toggleref_array
[toggleref_array_size
].weak_ref
= strong_ref
? NULL
: object
;
192 ++toggleref_array_size
;
200 * mono_gc_toggleref_register_callback:
201 * \param callback callback used to determine the new state of the given object.
203 * The callback must decide the status of a given object. It must return one of the values in the \c MONO_TOGGLE_REF_ enum.
204 * This function is called with the world running but with the GC locked. This means that you can do everything that doesn't
205 * require GC interaction. This includes, but not limited to, allocating objects, (de)registering for finalization, manipulating
206 * gchandles, storing to reference fields or interacting with other threads that might perform such operations.
209 mono_gc_toggleref_register_callback (MonoToggleRefStatus (*proccess_toggleref
) (MonoObject
*obj
))
211 toggleref_callback
= proccess_toggleref
;
214 static MonoToggleRefStatus
215 test_toggleref_callback (MonoObject
*obj
)
217 MonoToggleRefStatus status
= MONO_TOGGLE_REF_DROP
;
219 MONO_STATIC_POINTER_INIT (MonoClassField
, mono_toggleref_test_field
)
221 mono_toggleref_test_field
= mono_class_get_field_from_name_full (mono_object_class (obj
), "__test", NULL
);
222 g_assert (mono_toggleref_test_field
);
224 MONO_STATIC_POINTER_INIT_END (MonoClassField
, mono_toggleref_test_field
)
226 /* In coop mode, important to not call a helper that will pin obj! */
227 mono_field_get_value_internal (obj
, mono_toggleref_test_field
, &status
);
228 printf ("toggleref-cb obj %d\n", status
);
233 sgen_register_test_toggleref_callback (void)
235 toggleref_callback
= test_toggleref_callback
;
241 mono_gc_toggleref_register_callback (MonoToggleRefStatus (*proccess_toggleref
) (MonoObject
*obj
))
246 mono_gc_toggleref_add (MonoObject
*object
, mono_bool strong_ref
)