Update PointConverter.cs
[mono.git] / mono / metadata / sgen-fin-weak-hash.c
1 /*
2  * sgen-fin-weak-hash.c: Finalizers and weak links.
3  *
4  * Author:
5  *      Paolo Molaro (lupus@ximian.com)
6  *  Rodrigo Kumpera (kumpera@gmail.com)
7  *
8  * Copyright 2005-2011 Novell, Inc (http://www.novell.com)
9  * Copyright 2011 Xamarin Inc (http://www.xamarin.com)
10  * Copyright 2011 Xamarin, Inc.
11  * Copyright (C) 2012 Xamarin Inc
12  *
13  * This library is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU Library General Public
15  * License 2.0 as published by the Free Software Foundation;
16  *
17  * This library is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * Library General Public License for more details.
21  *
22  * You should have received a copy of the GNU Library General Public
23  * License 2.0 along with this library; if not, write to the Free
24  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25  */
26
27 #include "config.h"
28 #ifdef HAVE_SGEN_GC
29
30 #include "metadata/sgen-gc.h"
31 #include "metadata/sgen-gray.h"
32 #include "metadata/sgen-protocol.h"
33 #include "utils/dtrace.h"
34
35 #define ptr_in_nursery sgen_ptr_in_nursery
36
37 typedef SgenGrayQueue GrayQueue;
38
39 int num_ready_finalizers = 0;
40 static int no_finalize = 0;
41
42 #define DISLINK_OBJECT(l)       (REVEAL_POINTER (*(void**)(l)))
43 #define DISLINK_TRACK(l)        ((~(gulong)(*(void**)(l))) & 1)
44
45 /*
46  * The finalizable hash has the object as the key, the 
47  * disappearing_link hash, has the link address as key.
48  *
49  * Copyright 2011 Xamarin Inc.
50  */
51
52 #define TAG_MASK ((mword)0x1)
53
54 static inline MonoObject*
55 tagged_object_get_object (MonoObject *object)
56 {
57         return (MonoObject*)(((mword)object) & ~TAG_MASK);
58 }
59
60 static inline int
61 tagged_object_get_tag (MonoObject *object)
62 {
63         return ((mword)object) & TAG_MASK;
64 }
65
66 static inline MonoObject*
67 tagged_object_apply (void *object, int tag_bits)
68 {
69        return (MonoObject*)((mword)object | (mword)tag_bits);
70 }
71
72 static int
73 tagged_object_hash (MonoObject *o)
74 {
75         return mono_object_hash (tagged_object_get_object (o));
76 }
77
78 static gboolean
79 tagged_object_equals (MonoObject *a, MonoObject *b)
80 {
81         return tagged_object_get_object (a) == tagged_object_get_object (b);
82 }
83
84 static SgenHashTable minor_finalizable_hash = SGEN_HASH_TABLE_INIT (INTERNAL_MEM_FIN_TABLE, INTERNAL_MEM_FINALIZE_ENTRY, 0, (GHashFunc)tagged_object_hash, (GEqualFunc)tagged_object_equals);
85 static SgenHashTable major_finalizable_hash = SGEN_HASH_TABLE_INIT (INTERNAL_MEM_FIN_TABLE, INTERNAL_MEM_FINALIZE_ENTRY, 0, (GHashFunc)tagged_object_hash, (GEqualFunc)tagged_object_equals);
86
87 static SgenHashTable*
88 get_finalize_entry_hash_table (int generation)
89 {
90         switch (generation) {
91         case GENERATION_NURSERY: return &minor_finalizable_hash;
92         case GENERATION_OLD: return &major_finalizable_hash;
93         default: g_assert_not_reached ();
94         }
95 }
96
97 #define BRIDGE_OBJECT_MARKED 0x1
98
99 /* LOCKING: requires that the GC lock is held */
100 void
101 sgen_mark_bridge_object (MonoObject *obj)
102 {
103         SgenHashTable *hash_table = get_finalize_entry_hash_table (ptr_in_nursery (obj) ? GENERATION_NURSERY : GENERATION_OLD);
104
105         sgen_hash_table_set_key (hash_table, obj, tagged_object_apply (obj, BRIDGE_OBJECT_MARKED));
106 }
107
108 /* LOCKING: requires that the GC lock is held */
109 void
110 sgen_collect_bridge_objects (int generation, ScanCopyContext ctx)
111 {
112         CopyOrMarkObjectFunc copy_func = ctx.copy_func;
113         GrayQueue *queue = ctx.queue;
114         SgenHashTable *hash_table = get_finalize_entry_hash_table (generation);
115         MonoObject *object;
116         gpointer dummy;
117         char *copy;
118
119         if (no_finalize)
120                 return;
121
122         SGEN_HASH_TABLE_FOREACH (hash_table, object, dummy) {
123                 int tag = tagged_object_get_tag (object);
124                 object = tagged_object_get_object (object);
125
126                 /* Bridge code told us to ignore this one */
127                 if (tag == BRIDGE_OBJECT_MARKED)
128                         continue;
129
130                 /* Object is a bridge object and major heap says it's dead  */
131                 if (major_collector.is_object_live ((char*)object))
132                         continue;
133
134                 /* Nursery says the object is dead. */
135                 if (!sgen_gc_is_object_ready_for_finalization (object))
136                         continue;
137
138                 if (!sgen_is_bridge_object (object))
139                         continue;
140
141                 copy = (char*)object;
142                 copy_func ((void**)&copy, queue);
143
144                 sgen_bridge_register_finalized_object ((MonoObject*)copy);
145                 
146                 if (hash_table == &minor_finalizable_hash && !ptr_in_nursery (copy)) {
147                         /* remove from the list */
148                         SGEN_HASH_TABLE_FOREACH_REMOVE (TRUE);
149
150                         /* insert it into the major hash */
151                         sgen_hash_table_replace (&major_finalizable_hash, tagged_object_apply (copy, tag), NULL, NULL);
152
153                         SGEN_LOG (5, "Promoting finalization of object %p (%s) (was at %p) to major table", copy, sgen_safe_name (copy), object);
154
155                         continue;
156                 } else {
157                         /* update pointer */
158                         SGEN_LOG (5, "Updating object for finalization: %p (%s) (was at %p)", copy, sgen_safe_name (copy), object);
159                         SGEN_HASH_TABLE_FOREACH_SET_KEY (tagged_object_apply (copy, tag));
160                 }
161         } SGEN_HASH_TABLE_FOREACH_END;
162 }
163
164
165 /* LOCKING: requires that the GC lock is held */
166 void
167 sgen_finalize_in_range (int generation, ScanCopyContext ctx)
168 {
169         CopyOrMarkObjectFunc copy_func = ctx.copy_func;
170         GrayQueue *queue = ctx.queue;
171         SgenHashTable *hash_table = get_finalize_entry_hash_table (generation);
172         MonoObject *object;
173         gpointer dummy;
174
175         if (no_finalize)
176                 return;
177         SGEN_HASH_TABLE_FOREACH (hash_table, object, dummy) {
178                 int tag = tagged_object_get_tag (object);
179                 object = tagged_object_get_object (object);
180                 if (!major_collector.is_object_live ((char*)object)) {
181                         gboolean is_fin_ready = sgen_gc_is_object_ready_for_finalization (object);
182                         MonoObject *copy = object;
183                         copy_func ((void**)&copy, queue);
184                         if (is_fin_ready) {
185                                 /* remove and put in fin_ready_list */
186                                 SGEN_HASH_TABLE_FOREACH_REMOVE (TRUE);
187                                 num_ready_finalizers++;
188                                 sgen_queue_finalization_entry (copy);
189                                 /* Make it survive */
190                                 SGEN_LOG (5, "Queueing object for finalization: %p (%s) (was at %p) (%d/%d)", copy, sgen_safe_name (copy), object, num_ready_finalizers, sgen_hash_table_num_entries (hash_table));
191                                 continue;
192                         } else {
193                                 if (hash_table == &minor_finalizable_hash && !ptr_in_nursery (copy)) {
194                                         /* remove from the list */
195                                         SGEN_HASH_TABLE_FOREACH_REMOVE (TRUE);
196
197                                         /* insert it into the major hash */
198                                         sgen_hash_table_replace (&major_finalizable_hash, tagged_object_apply (copy, tag), NULL, NULL);
199
200                                         SGEN_LOG (5, "Promoting finalization of object %p (%s) (was at %p) to major table", copy, sgen_safe_name (copy), object);
201
202                                         continue;
203                                 } else {
204                                         /* update pointer */
205                                         SGEN_LOG (5, "Updating object for finalization: %p (%s) (was at %p)", copy, sgen_safe_name (copy), object);
206                                         SGEN_HASH_TABLE_FOREACH_SET_KEY (tagged_object_apply (copy, tag));
207                                 }
208                         }
209                 }
210         } SGEN_HASH_TABLE_FOREACH_END;
211 }
212
213 /* LOCKING: requires that the GC lock is held */
214 static void
215 register_for_finalization (MonoObject *obj, void *user_data, int generation)
216 {
217         SgenHashTable *hash_table = get_finalize_entry_hash_table (generation);
218
219         if (no_finalize)
220                 return;
221
222         g_assert (user_data == NULL || user_data == mono_gc_run_finalize);
223
224         if (user_data) {
225                 if (sgen_hash_table_replace (hash_table, obj, NULL, NULL))
226                         SGEN_LOG (5, "Added finalizer for object: %p (%s) (%d) to %s table", obj, obj->vtable->klass->name, hash_table->num_entries, sgen_generation_name (generation));
227         } else {
228                 if (sgen_hash_table_remove (hash_table, obj, NULL))
229                         SGEN_LOG (5, "Removed finalizer for object: %p (%s) (%d)", obj, obj->vtable->klass->name, hash_table->num_entries);
230         }
231 }
232
233 #define STAGE_ENTRY_FREE        0
234 #define STAGE_ENTRY_BUSY        1
235 #define STAGE_ENTRY_USED        2
236
237 typedef struct {
238         gint32 state;
239         MonoObject *obj;
240         void *user_data;
241 } StageEntry;
242
243 #define NUM_FIN_STAGE_ENTRIES   1024
244
245 static volatile gint32 next_fin_stage_entry = 0;
246 static StageEntry fin_stage_entries [NUM_FIN_STAGE_ENTRIES];
247
248 /* LOCKING: requires that the GC lock is held */
249 static void
250 process_stage_entries (int num_entries, volatile gint32 *next_entry, StageEntry *entries, void (*process_func) (MonoObject*, void*))
251 {
252         int i;
253         int num_registered = 0;
254         int num_busy = 0;
255
256         for (i = 0; i < num_entries; ++i) {
257                 gint32 state = entries [i].state;
258
259                 if (state == STAGE_ENTRY_BUSY)
260                         ++num_busy;
261
262                 if (state != STAGE_ENTRY_USED ||
263                                 InterlockedCompareExchange (&entries [i].state, STAGE_ENTRY_BUSY, STAGE_ENTRY_USED) != STAGE_ENTRY_USED) {
264                         continue;
265                 }
266
267                 process_func (entries [i].obj, entries [i].user_data);
268
269                 entries [i].obj = NULL;
270                 entries [i].user_data = NULL;
271
272                 mono_memory_write_barrier ();
273
274                 entries [i].state = STAGE_ENTRY_FREE;
275
276                 ++num_registered;
277         }
278
279         *next_entry = 0;
280
281         /* g_print ("stage busy %d reg %d\n", num_busy, num_registered); */
282 }
283
284 static gboolean
285 add_stage_entry (int num_entries, volatile gint32 *next_entry, StageEntry *entries, MonoObject *obj, void *user_data)
286 {
287         gint32 index;
288
289         do {
290                 do {
291                         index = *next_entry;
292                         if (index >= num_entries)
293                                 return FALSE;
294                 } while (InterlockedCompareExchange (next_entry, index + 1, index) != index);
295
296                 /*
297                  * We don't need a write barrier here.  *next_entry is just a
298                  * help for finding an index, its value is irrelevant for
299                  * correctness.
300                  */
301         } while (entries [index].state != STAGE_ENTRY_FREE ||
302                         InterlockedCompareExchange (&entries [index].state, STAGE_ENTRY_BUSY, STAGE_ENTRY_FREE) != STAGE_ENTRY_FREE);
303
304         entries [index].obj = obj;
305         entries [index].user_data = user_data;
306
307         mono_memory_write_barrier ();
308
309         entries [index].state = STAGE_ENTRY_USED;
310
311         return TRUE;
312 }
313
314 /* LOCKING: requires that the GC lock is held */
315 static void
316 process_fin_stage_entry (MonoObject *obj, void *user_data)
317 {
318         if (ptr_in_nursery (obj))
319                 register_for_finalization (obj, user_data, GENERATION_NURSERY);
320         else
321                 register_for_finalization (obj, user_data, GENERATION_OLD);
322 }
323
324 /* LOCKING: requires that the GC lock is held */
325 void
326 sgen_process_fin_stage_entries (void)
327 {
328         process_stage_entries (NUM_FIN_STAGE_ENTRIES, &next_fin_stage_entry, fin_stage_entries, process_fin_stage_entry);
329 }
330
331 void
332 mono_gc_register_for_finalization (MonoObject *obj, void *user_data)
333 {
334         while (!add_stage_entry (NUM_FIN_STAGE_ENTRIES, &next_fin_stage_entry, fin_stage_entries, obj, user_data)) {
335                 LOCK_GC;
336                 sgen_process_fin_stage_entries ();
337                 UNLOCK_GC;
338         }
339 }
340
341 /* LOCKING: requires that the GC lock is held */
342 static int
343 finalizers_for_domain (MonoDomain *domain, MonoObject **out_array, int out_size,
344         SgenHashTable *hash_table)
345 {
346         MonoObject *object;
347         gpointer dummy;
348         int count;
349
350         if (no_finalize || !out_size || !out_array)
351                 return 0;
352         count = 0;
353         SGEN_HASH_TABLE_FOREACH (hash_table, object, dummy) {
354                 object = tagged_object_get_object (object);
355
356                 if (mono_object_domain (object) == domain) {
357                         /* remove and put in out_array */
358                         SGEN_HASH_TABLE_FOREACH_REMOVE (TRUE);
359                         out_array [count ++] = object;
360                         SGEN_LOG (5, "Collecting object for finalization: %p (%s) (%d/%d)", object, sgen_safe_name (object), num_ready_finalizers, sgen_hash_table_num_entries (hash_table));
361                         if (count == out_size)
362                                 return count;
363                         continue;
364                 }
365         } SGEN_HASH_TABLE_FOREACH_END;
366         return count;
367 }
368
369 /**
370  * mono_gc_finalizers_for_domain:
371  * @domain: the unloading appdomain
372  * @out_array: output array
373  * @out_size: size of output array
374  *
375  * Store inside @out_array up to @out_size objects that belong to the unloading
376  * appdomain @domain. Returns the number of stored items. Can be called repeteadly
377  * until it returns 0.
378  * The items are removed from the finalizer data structure, so the caller is supposed
379  * to finalize them.
380  * @out_array should be on the stack to allow the GC to know the objects are still alive.
381  */
382 int
383 mono_gc_finalizers_for_domain (MonoDomain *domain, MonoObject **out_array, int out_size)
384 {
385         int result;
386
387         LOCK_GC;
388         sgen_process_fin_stage_entries ();
389         result = finalizers_for_domain (domain, out_array, out_size, &minor_finalizable_hash);
390         if (result < out_size) {
391                 result += finalizers_for_domain (domain, out_array + result, out_size - result,
392                         &major_finalizable_hash);
393         }
394         UNLOCK_GC;
395
396         return result;
397 }
398
399 static SgenHashTable minor_disappearing_link_hash = SGEN_HASH_TABLE_INIT (INTERNAL_MEM_DISLINK_TABLE, INTERNAL_MEM_DISLINK, 0, mono_aligned_addr_hash, NULL);
400 static SgenHashTable major_disappearing_link_hash = SGEN_HASH_TABLE_INIT (INTERNAL_MEM_DISLINK_TABLE, INTERNAL_MEM_DISLINK, 0, mono_aligned_addr_hash, NULL);
401
402 static SgenHashTable*
403 get_dislink_hash_table (int generation)
404 {
405         switch (generation) {
406         case GENERATION_NURSERY: return &minor_disappearing_link_hash;
407         case GENERATION_OLD: return &major_disappearing_link_hash;
408         default: g_assert_not_reached ();
409         }
410 }
411
412 /* LOCKING: assumes the GC lock is held */
413 static void
414 add_or_remove_disappearing_link (MonoObject *obj, void **link, int generation)
415 {
416         SgenHashTable *hash_table = get_dislink_hash_table (generation);
417
418         if (!obj) {
419                 if (sgen_hash_table_remove (hash_table, link, NULL)) {
420                         SGEN_LOG (5, "Removed dislink %p (%d) from %s table",
421                                         link, hash_table->num_entries, sgen_generation_name (generation));
422                 }
423                 return;
424         }
425
426         sgen_hash_table_replace (hash_table, link, NULL, NULL);
427         SGEN_LOG (5, "Added dislink for object: %p (%s) at %p to %s table",
428                         obj, obj->vtable->klass->name, link, sgen_generation_name (generation));
429 }
430
431 /* LOCKING: requires that the GC lock is held */
432 void
433 sgen_null_link_in_range (int generation, gboolean before_finalization, ScanCopyContext ctx)
434 {
435         CopyOrMarkObjectFunc copy_func = ctx.copy_func;
436         GrayQueue *queue = ctx.queue;
437         void **link;
438         gpointer dummy;
439         SgenHashTable *hash = get_dislink_hash_table (generation);
440
441         SGEN_HASH_TABLE_FOREACH (hash, link, dummy) {
442                 char *object;
443                 gboolean track;
444
445                 /*
446                 We null a weak link before unregistering it, so it's possible that a thread is
447                 suspended right in between setting the content to null and staging the unregister.
448
449                 The rest of this code cannot handle null links as DISLINK_OBJECT (NULL) produces an invalid address.
450
451                 We should simply skip the entry as the staged removal will take place during the next GC.
452                 */
453                 if (!*link) {
454                         SGEN_LOG (5, "Dislink %p was externally nullified", link);
455                         continue;
456                 }
457
458                 track = DISLINK_TRACK (link);
459                 /*
460                  * Tracked references are processed after
461                  * finalization handling whereas standard weak
462                  * references are processed before.  If an
463                  * object is still not marked after finalization
464                  * handling it means that it either doesn't have
465                  * a finalizer or the finalizer has already run,
466                  * so we must null a tracking reference.
467                  */
468                 if (track != before_finalization) {
469                         object = DISLINK_OBJECT (link);
470                         /*
471                         We should guard against a null object been hidden. This can sometimes happen.
472                         */
473                         if (!object) {
474                                 SGEN_LOG (5, "Dislink %p with a hidden null object", link);
475                                 continue;
476                         }
477
478                         if (!major_collector.is_object_live (object)) {
479                                 if (sgen_gc_is_object_ready_for_finalization (object)) {
480                                         *link = NULL;
481                                         binary_protocol_dislink_update (link, NULL, 0);
482                                         SGEN_LOG (5, "Dislink nullified at %p to GCed object %p", link, object);
483                                         SGEN_HASH_TABLE_FOREACH_REMOVE (TRUE);
484                                         continue;
485                                 } else {
486                                         char *copy = object;
487                                         copy_func ((void**)&copy, queue);
488
489                                         /* Update pointer if it's moved.  If the object
490                                          * has been moved out of the nursery, we need to
491                                          * remove the link from the minor hash table to
492                                          * the major one.
493                                          *
494                                          * FIXME: what if an object is moved earlier?
495                                          */
496
497                                         if (hash == &minor_disappearing_link_hash && !ptr_in_nursery (copy)) {
498                                                 SGEN_HASH_TABLE_FOREACH_REMOVE (TRUE);
499
500                                                 g_assert (copy);
501                                                 *link = HIDE_POINTER (copy, track);
502                                                 add_or_remove_disappearing_link ((MonoObject*)copy, link, GENERATION_OLD);
503                                                 binary_protocol_dislink_update (link, copy, track);
504
505                                                 SGEN_LOG (5, "Upgraded dislink at %p to major because object %p moved to %p", link, object, copy);
506
507                                                 continue;
508                                         } else {
509                                                 *link = HIDE_POINTER (copy, track);
510                                                 binary_protocol_dislink_update (link, copy, track);
511                                                 SGEN_LOG (5, "Updated dislink at %p to %p", link, DISLINK_OBJECT (link));
512                                         }
513                                 }
514                         }
515                 }
516         } SGEN_HASH_TABLE_FOREACH_END;
517 }
518
519 /* LOCKING: requires that the GC lock is held */
520 void
521 sgen_null_links_for_domain (MonoDomain *domain, int generation)
522 {
523         void **link;
524         gpointer dummy;
525         SgenHashTable *hash = get_dislink_hash_table (generation);
526         SGEN_HASH_TABLE_FOREACH (hash, link, dummy) {
527                 char *object = DISLINK_OBJECT (link);
528                 if (*link && object && !((MonoObject*)object)->vtable) {
529                         gboolean free = TRUE;
530
531                         if (*link) {
532                                 *link = NULL;
533                                 binary_protocol_dislink_update (link, NULL, 0);
534                                 free = FALSE;
535                                 /*
536                                  * This can happen if finalizers are not ran, i.e. Environment.Exit ()
537                                  * is called from finalizer like in finalizer-abort.cs.
538                                  */
539                                 SGEN_LOG (5, "Disappearing link %p not freed", link);
540                         }
541
542                         SGEN_HASH_TABLE_FOREACH_REMOVE (free);
543
544                         continue;
545                 }
546         } SGEN_HASH_TABLE_FOREACH_END;
547 }
548
549 /* LOCKING: requires that the GC lock is held */
550 void
551 sgen_null_links_with_predicate (int generation, WeakLinkAlivePredicateFunc predicate, void *data)
552 {
553         void **link;
554         gpointer dummy;
555         SgenHashTable *hash = get_dislink_hash_table (generation);
556         SGEN_HASH_TABLE_FOREACH (hash, link, dummy) {
557                 char *object = DISLINK_OBJECT (link);
558                 mono_bool is_alive;
559
560                 if (!*link)
561                         continue;
562                 is_alive = predicate ((MonoObject*)object, data);
563
564                 if (!is_alive) {
565                         *link = NULL;
566                         binary_protocol_dislink_update (link, NULL, 0);
567                         SGEN_LOG (5, "Dislink nullified by predicate at %p to GCed object %p", link, object);
568                         SGEN_HASH_TABLE_FOREACH_REMOVE (TRUE);
569                         continue;
570                 }
571         } SGEN_HASH_TABLE_FOREACH_END;
572 }
573
574 void
575 sgen_remove_finalizers_for_domain (MonoDomain *domain, int generation)
576 {
577         SgenHashTable *hash_table = get_finalize_entry_hash_table (generation);
578         MonoObject *object;
579         gpointer dummy;
580
581         SGEN_HASH_TABLE_FOREACH (hash_table, object, dummy) {
582                 object = tagged_object_get_object (object);
583
584                 if (mono_object_domain (object) == domain) {
585                         SGEN_LOG (5, "Unregistering finalizer for object: %p (%s)", object, sgen_safe_name (object));
586
587                         SGEN_HASH_TABLE_FOREACH_REMOVE (TRUE);
588                         continue;
589                 }
590         } SGEN_HASH_TABLE_FOREACH_END;  
591 }
592
593 /* LOCKING: requires that the GC lock is held */
594 static void
595 process_dislink_stage_entry (MonoObject *obj, void *_link)
596 {
597         void **link = _link;
598
599         add_or_remove_disappearing_link (NULL, link, GENERATION_NURSERY);
600         add_or_remove_disappearing_link (NULL, link, GENERATION_OLD);
601         if (obj) {
602                 if (ptr_in_nursery (obj))
603                         add_or_remove_disappearing_link (obj, link, GENERATION_NURSERY);
604                 else
605                         add_or_remove_disappearing_link (obj, link, GENERATION_OLD);
606         }
607 }
608
609 #define NUM_DISLINK_STAGE_ENTRIES       1024
610
611 static volatile gint32 next_dislink_stage_entry = 0;
612 static StageEntry dislink_stage_entries [NUM_DISLINK_STAGE_ENTRIES];
613
614 /* LOCKING: requires that the GC lock is held */
615 void
616 sgen_process_dislink_stage_entries (void)
617 {
618         process_stage_entries (NUM_DISLINK_STAGE_ENTRIES, &next_dislink_stage_entry, dislink_stage_entries, process_dislink_stage_entry);
619 }
620
621 void
622 sgen_register_disappearing_link (MonoObject *obj, void **link, gboolean track, gboolean in_gc)
623 {
624
625 #ifdef ENABLE_DTRACE
626         if (MONO_GC_WEAK_UPDATE_ENABLED ()) {
627                 MonoVTable *vt = obj ? (MonoVTable*)SGEN_LOAD_VTABLE (obj) : NULL;
628                 MONO_GC_WEAK_UPDATE ((mword)link,
629                                 *link ? (mword)DISLINK_OBJECT (link) : (mword)0,
630                                 (mword)obj,
631                                 obj ? (mword)sgen_safe_object_get_size (obj) : (mword)0,
632                                 obj ? vt->klass->name_space : NULL,
633                                 obj ? vt->klass->name : NULL,
634                                 track ? 1 : 0);
635         }
636 #endif
637
638         if (obj)
639                 *link = HIDE_POINTER (obj, track);
640         else
641                 *link = NULL;
642
643         binary_protocol_dislink_update (link, obj, track);
644
645 #if 1
646         if (in_gc) {
647                 process_dislink_stage_entry (obj, link);
648         } else {
649                 while (!add_stage_entry (NUM_DISLINK_STAGE_ENTRIES, &next_dislink_stage_entry, dislink_stage_entries, obj, link)) {
650                         LOCK_GC;
651                         sgen_process_dislink_stage_entries ();
652                         UNLOCK_GC;
653                 }
654         }
655 #else
656         if (!in_gc)
657                 LOCK_GC;
658         process_dislink_stage_entry (obj, link);
659         if (!in_gc)
660                 UNLOCK_GC;
661 #endif
662 }
663
664 #endif /* HAVE_SGEN_GC */