1 /**
2 * \file
3 * GC implementation using either the installed or included Boehm GC.
4 *
5 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
6 * Copyright 2004-2011 Novell, Inc (http://www.novell.com)
7 * Copyright 2011-2012 Xamarin, Inc (http://www.xamarin.com)
8 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
9 */
10
11 #include "config.h"
12
13 #include <string.h>
14
15 #define GC_I_HIDE_POINTERS
16 #include <mono/metadata/gc-internals.h>
17 #include <mono/metadata/mono-gc.h>
18 #include <mono/metadata/profiler-private.h>
19 #include <mono/metadata/class-internals.h>
20 #include <mono/metadata/method-builder.h>
21 #include <mono/metadata/opcodes.h>
22 #include <mono/metadata/domain-internals.h>
23 #include <mono/metadata/metadata-internals.h>
24 #include <mono/metadata/marshal.h>
25 #include <mono/metadata/runtime.h>
26 #include <mono/metadata/handle.h>
27 #include <mono/metadata/sgen-toggleref.h>
28 #include <mono/metadata/w32handle.h>
29 #include <mono/utils/atomic.h>
30 #include <mono/utils/mono-logger-internals.h>
31 #include <mono/utils/mono-memory-model.h>
32 #include <mono/utils/mono-time.h>
33 #include <mono/utils/mono-threads.h>
34 #include <mono/utils/dtrace.h>
35 #include <mono/utils/gc_wrapper.h>
36 #include <mono/utils/mono-os-mutex.h>
37 #include <mono/utils/mono-counters.h>
38 #include <mono/utils/mono-compiler.h>
39 #include <mono/utils/unlocked.h>
40
41 #if HAVE_BOEHM_GC
42
43 #undef TRUE
44 #undef FALSE
45 #define THREAD_LOCAL_ALLOC 1
46 #include "private/pthread_support.h"
47
48 #if defined(HOST_DARWIN) && defined(HAVE_PTHREAD_GET_STACKADDR_NP)
49 void *pthread_get_stackaddr_np(pthread_t);
50 #endif
51
52 #define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
53 /*Boehm max heap cannot be smaller than 16MB*/
54 #define MIN_BOEHM_MAX_HEAP_SIZE_IN_MB 16
55 #define MIN_BOEHM_MAX_HEAP_SIZE (MIN_BOEHM_MAX_HEAP_SIZE_IN_MB << 20)
56
57 static gboolean gc_initialized = FALSE;
58 static mono_mutex_t mono_gc_lock;
59
60 typedef void (*GC_push_other_roots_proc)(void);
61
62 static GC_push_other_roots_proc default_push_other_roots;
63 static GHashTable *roots;
64
65 static void
66 mono_push_other_roots(void);
67
68 static void
69 register_test_toggleref_callback (void);
70
71 #define BOEHM_GC_BIT_FINALIZER_AWARE 1
72 static MonoGCFinalizerCallbacks fin_callbacks;
73
74 /* GC Handles */
75
76 static mono_mutex_t handle_section;
77 #define lock_handles(handles) mono_os_mutex_lock (&handle_section)
78 #define unlock_handles(handles) mono_os_mutex_unlock (&handle_section)
79
80 typedef struct {
81 guint32 *bitmap;
82 gpointer *entries;
83 guint32 size;
84 guint8 type;
85 guint slot_hint : 24; /* starting slot for search in bitmap */
86 /* 2^16 appdomains should be enough for everyone (though I know I'll regret this in 20 years) */
87 /* we alloc this only for weak refs, since we can get the domain directly in the other cases */
88 guint16 *domain_ids;
89 } HandleData;
90
91 #define EMPTY_HANDLE_DATA(type) {NULL, NULL, 0, (type), 0, NULL}
92
93 /* weak and weak-track arrays will be allocated in malloc memory
94 */
95 static HandleData gc_handles [] = {
96 EMPTY_HANDLE_DATA (HANDLE_WEAK),
97 EMPTY_HANDLE_DATA (HANDLE_WEAK_TRACK),
98 EMPTY_HANDLE_DATA (HANDLE_NORMAL),
99 EMPTY_HANDLE_DATA (HANDLE_PINNED)
100 };
101
102 static void
mono_gc_warning(char * msg,GC_word arg)103 mono_gc_warning (char *msg, GC_word arg)
104 {
105 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_GC, msg, (unsigned long)arg);
106 }
107
108 static void on_gc_notification (GC_EventType event);
109 static void on_gc_heap_resize (size_t new_size);
110
111 void
mono_gc_base_init(void)112 mono_gc_base_init (void)
113 {
114 char *env;
115
116 if (gc_initialized)
117 return;
118
119 mono_counters_init ();
120
121 #ifndef HOST_WIN32
122 mono_w32handle_init ();
123 #endif
124
125 /*
126 * Handle the case when we are called from a thread different from the main thread,
127 * confusing libgc.
128 * FIXME: Move this to libgc where it belongs.
129 *
130 * we used to do this only when running on valgrind,
131 * but it happens also in other setups.
132 */
133 #if defined(HAVE_PTHREAD_GETATTR_NP) && defined(HAVE_PTHREAD_ATTR_GETSTACK)
134 {
135 size_t size;
136 void *sstart;
137 pthread_attr_t attr;
138 pthread_getattr_np (pthread_self (), &attr);
139 pthread_attr_getstack (&attr, &sstart, &size);
140 pthread_attr_destroy (&attr);
141 /*g_print ("stackbottom pth is: %p\n", (char*)sstart + size);*/
142 /* apparently with some linuxthreads implementations sstart can be NULL,
143 * fallback to the more imprecise method (bug# 78096).
144 */
145 if (sstart) {
146 GC_stackbottom = (char*)sstart + size;
147 } else {
148 int dummy;
149 gsize stack_bottom = (gsize)&dummy;
150 stack_bottom += 4095;
151 stack_bottom &= ~4095;
152 GC_stackbottom = (char*)stack_bottom;
153 }
154 }
155 #elif defined(HAVE_PTHREAD_GET_STACKSIZE_NP) && defined(HAVE_PTHREAD_GET_STACKADDR_NP)
156 GC_stackbottom = (char*)pthread_get_stackaddr_np (pthread_self ());
157 #elif defined(__OpenBSD__)
158 # include <pthread_np.h>
159 {
160 stack_t ss;
161 int rslt;
162
163 rslt = pthread_stackseg_np(pthread_self(), &ss);
164 g_assert (rslt == 0);
165
166 GC_stackbottom = (char*)ss.ss_sp;
167 }
168 #else
169 {
170 int dummy;
171 gsize stack_bottom = (gsize)&dummy;
172 stack_bottom += 4095;
173 stack_bottom &= ~4095;
174 /*g_print ("stackbottom is: %p\n", (char*)stack_bottom);*/
175 GC_stackbottom = (char*)stack_bottom;
176 }
177 #endif
178
179 roots = g_hash_table_new (NULL, NULL);
180 default_push_other_roots = GC_push_other_roots;
181 GC_push_other_roots = mono_push_other_roots;
182
183 #if !defined(HOST_ANDROID)
184 /* If GC_no_dls is set to true, GC_find_limit is not called. This causes a seg fault on Android. */
185 GC_no_dls = TRUE;
186 #endif
187 {
188 if ((env = g_getenv ("MONO_GC_DEBUG"))) {
189 char **opts = g_strsplit (env, ",", -1);
190 for (char **ptr = opts; ptr && *ptr; ptr ++) {
191 char *opt = *ptr;
192 if (!strcmp (opt, "do-not-finalize")) {
193 mono_do_not_finalize = 1;
194 } else if (!strcmp (opt, "log-finalizers")) {
195 log_finalizers = 1;
196 }
197 }
198 g_free (env);
199 }
200 }
201
202 GC_init ();
203
204 GC_set_warn_proc (mono_gc_warning);
205 GC_finalize_on_demand = 1;
206 GC_finalizer_notifier = mono_gc_finalize_notify;
207
208 GC_init_gcj_malloc (5, NULL);
209 GC_allow_register_threads ();
210
211 if ((env = g_getenv ("MONO_GC_PARAMS"))) {
212 char **ptr, **opts = g_strsplit (env, ",", -1);
213 for (ptr = opts; *ptr; ++ptr) {
214 char *opt = *ptr;
215 if (g_str_has_prefix (opt, "max-heap-size=")) {
216 size_t max_heap;
217
218 opt = strchr (opt, '=') + 1;
219 if (*opt && mono_gc_parse_environment_string_extract_number (opt, &max_heap)) {
220 if (max_heap < MIN_BOEHM_MAX_HEAP_SIZE) {
221 fprintf (stderr, "max-heap-size must be at least %dMb.\n", MIN_BOEHM_MAX_HEAP_SIZE_IN_MB);
222 exit (1);
223 }
224 GC_set_max_heap_size (max_heap);
225 } else {
226 fprintf (stderr, "max-heap-size must be an integer.\n");
227 exit (1);
228 }
229 continue;
230 } else if (g_str_has_prefix (opt, "toggleref-test")) {
231 register_test_toggleref_callback ();
232 continue;
233 } else {
234 /* Could be a parameter for sgen */
235 /*
236 fprintf (stderr, "MONO_GC_PARAMS must be a comma-delimited list of one or more of the following:\n");
237 fprintf (stderr, " max-heap-size=N (where N is an integer, possibly with a k, m or a g suffix)\n");
238 exit (1);
239 */
240 }
241 }
242 g_free (env);
243 g_strfreev (opts);
244 }
245
246 mono_thread_callbacks_init ();
247 mono_thread_info_init (sizeof (MonoThreadInfo));
248 mono_os_mutex_init (&mono_gc_lock);
249 mono_os_mutex_init_recursive (&handle_section);
250
251 mono_thread_info_attach ();
252
253 GC_set_on_collection_event (on_gc_notification);
254 GC_on_heap_resize = on_gc_heap_resize;
255
256 gc_initialized = TRUE;
257 }
258
259 void
mono_gc_base_cleanup(void)260 mono_gc_base_cleanup (void)
261 {
262 GC_finalizer_notifier = NULL;
263 }
264
265 /**
266 * mono_gc_collect:
267 * \param generation GC generation identifier
268 *
269 * Perform a garbage collection for the given generation, higher numbers
270 * mean usually older objects. Collecting a high-numbered generation
271 * implies collecting also the lower-numbered generations.
272 * The maximum value for \p generation can be retrieved with a call to
273 * \c mono_gc_max_generation, so this function is usually called as:
274 *
275 * <code>mono_gc_collect (mono_gc_max_generation ());</code>
276 */
277 void
mono_gc_collect(int generation)278 mono_gc_collect (int generation)
279 {
280 #ifndef DISABLE_PERFCOUNTERS
281 mono_atomic_inc_i32 (&mono_perfcounters->gc_induced);
282 #endif
283 GC_gcollect ();
284 }
285
286 /**
287 * mono_gc_max_generation:
288 *
289 * Get the maximum generation number used by the current garbage
290 * collector. The value will be 0 for the Boehm collector, 1 or more
291 * for the generational collectors.
292 *
293 * Returns: the maximum generation number.
294 */
295 int
mono_gc_max_generation(void)296 mono_gc_max_generation (void)
297 {
298 return 0;
299 }
300
301 /**
302 * mono_gc_get_generation:
303 * \param object a managed object
304 *
305 * Get the garbage collector's generation that \p object belongs to.
306 * Use this has a hint only.
307 *
308 * \returns a garbage collector generation number
309 */
310 int
mono_gc_get_generation(MonoObject * object)311 mono_gc_get_generation (MonoObject *object)
312 {
313 return 0;
314 }
315
316 /**
317 * mono_gc_collection_count:
318 * \param generation a GC generation number
319 *
320 * Get how many times a garbage collection has been performed
321 * for the given \p generation number.
322 *
323 * \returns the number of garbage collections
324 */
325 int
mono_gc_collection_count(int generation)326 mono_gc_collection_count (int generation)
327 {
328 return GC_gc_no;
329 }
330
331 /**
332 * mono_gc_add_memory_pressure:
333 * \param value amount of bytes
334 *
335 * Adjust the garbage collector's view of how many bytes of memory
336 * are indirectly referenced by managed objects (for example unmanaged
337 * memory holding image or other binary data).
338 * This is a hint only to the garbage collector algorithm.
339 * Note that negative amounts of p value will decrease the memory
340 * pressure.
341 */
342 void
mono_gc_add_memory_pressure(gint64 value)343 mono_gc_add_memory_pressure (gint64 value)
344 {
345 }
346
347 /**
348 * mono_gc_get_used_size:
349 *
350 * Get the approximate amount of memory used by managed objects.
351 *
352 * Returns: the amount of memory used in bytes
353 */
354 int64_t
mono_gc_get_used_size(void)355 mono_gc_get_used_size (void)
356 {
357 return GC_get_heap_size () - GC_get_free_bytes ();
358 }
359
360 /**
361 * mono_gc_get_heap_size:
362 *
363 * Get the amount of memory used by the garbage collector.
364 *
365 * Returns: the size of the heap in bytes
366 */
367 int64_t
mono_gc_get_heap_size(void)368 mono_gc_get_heap_size (void)
369 {
370 return GC_get_heap_size ();
371 }
372
373 gboolean
mono_gc_is_gc_thread(void)374 mono_gc_is_gc_thread (void)
375 {
376 return GC_thread_is_registered ();
377 }
378
379 gpointer
mono_gc_thread_attach(MonoThreadInfo * info)380 mono_gc_thread_attach (MonoThreadInfo* info)
381 {
382 struct GC_stack_base sb;
383 int res;
384
385 /* TODO: use GC_get_stack_base instead of baseptr. */
386 sb.mem_base = info->stack_end;
387 res = GC_register_my_thread (&sb);
388 if (res == GC_UNIMPLEMENTED)
389 return NULL; /* Cannot happen with GC v7+. */
390
391 info->handle_stack = mono_handle_stack_alloc ();
392
393 return info;
394 }
395
396 void
mono_gc_thread_detach_with_lock(MonoThreadInfo * p)397 mono_gc_thread_detach_with_lock (MonoThreadInfo *p)
398 {
399 MonoNativeThreadId tid;
400
401 tid = mono_thread_info_get_tid (p);
402
403 if (p->runtime_thread)
404 mono_threads_add_joinable_thread ((gpointer)tid);
405
406 mono_handle_stack_free (p->handle_stack);
407 p->handle_stack = NULL;
408 }
409
410 gboolean
mono_gc_thread_in_critical_region(MonoThreadInfo * info)411 mono_gc_thread_in_critical_region (MonoThreadInfo *info)
412 {
413 return FALSE;
414 }
415
416 gboolean
mono_object_is_alive(MonoObject * o)417 mono_object_is_alive (MonoObject* o)
418 {
419 return GC_is_marked ((ptr_t)o);
420 }
421
422 int
mono_gc_walk_heap(int flags,MonoGCReferences callback,void * data)423 mono_gc_walk_heap (int flags, MonoGCReferences callback, void *data)
424 {
425 return 1;
426 }
427
428 static gint64 gc_start_time;
429
430 static void
on_gc_notification(GC_EventType event)431 on_gc_notification (GC_EventType event)
432 {
433 MonoProfilerGCEvent e;
434
435 switch (event) {
436 case GC_EVENT_PRE_STOP_WORLD:
437 e = MONO_GC_EVENT_PRE_STOP_WORLD;
438 MONO_GC_WORLD_STOP_BEGIN ();
439 break;
440
441 case GC_EVENT_POST_STOP_WORLD:
442 e = MONO_GC_EVENT_POST_STOP_WORLD;
443 MONO_GC_WORLD_STOP_END ();
444 break;
445
446 case GC_EVENT_PRE_START_WORLD:
447 e = MONO_GC_EVENT_PRE_START_WORLD;
448 MONO_GC_WORLD_RESTART_BEGIN (1);
449 break;
450
451 case GC_EVENT_POST_START_WORLD:
452 e = MONO_GC_EVENT_POST_START_WORLD;
453 MONO_GC_WORLD_RESTART_END (1);
454 break;
455
456 case GC_EVENT_START:
457 e = MONO_GC_EVENT_START;
458 MONO_GC_BEGIN (1);
459 #ifndef DISABLE_PERFCOUNTERS
460 if (mono_perfcounters)
461 mono_atomic_inc_i32 (&mono_perfcounters->gc_collections0);
462 #endif
463 mono_atomic_inc_i32 (&gc_stats.major_gc_count);
464 gc_start_time = mono_100ns_ticks ();
465 break;
466
467 case GC_EVENT_END:
468 e = MONO_GC_EVENT_END;
469 MONO_GC_END (1);
470 #if defined(ENABLE_DTRACE) && defined(__sun__)
471 /* This works around a dtrace -G problem on Solaris.
472 Limit its actual use to when the probe is enabled. */
473 if (MONO_GC_END_ENABLED ())
474 sleep(0);
475 #endif
476
477 #ifndef DISABLE_PERFCOUNTERS
478 if (mono_perfcounters) {
479 guint64 heap_size = GC_get_heap_size ();
480 guint64 used_size = heap_size - GC_get_free_bytes ();
481 /* FIXME: change these to mono_atomic_store_i64 () */
482 UnlockedWrite64 (&mono_perfcounters->gc_total_bytes, used_size);
483 UnlockedWrite64 (&mono_perfcounters->gc_committed_bytes, heap_size);
484 UnlockedWrite64 (&mono_perfcounters->gc_reserved_bytes, heap_size);
485 UnlockedWrite64 (&mono_perfcounters->gc_gen0size, heap_size);
486 }
487 #endif
488 UnlockedAdd64 (&gc_stats.major_gc_time, mono_100ns_ticks () - gc_start_time);
489 mono_trace_message (MONO_TRACE_GC, "gc took %" G_GINT64_FORMAT " usecs", (mono_100ns_ticks () - gc_start_time) / 10);
490 break;
491 default:
492 break;
493 }
494
495 switch (event) {
496 case GC_EVENT_MARK_START:
497 case GC_EVENT_MARK_END:
498 case GC_EVENT_RECLAIM_START:
499 case GC_EVENT_RECLAIM_END:
500 break;
501 default:
502 MONO_PROFILER_RAISE (gc_event, (e, 0));
503 break;
504 }
505
506 switch (event) {
507 case GC_EVENT_PRE_STOP_WORLD:
508 mono_thread_info_suspend_lock ();
509 MONO_PROFILER_RAISE (gc_event, (MONO_GC_EVENT_PRE_STOP_WORLD_LOCKED, 0));
510 break;
511 case GC_EVENT_POST_START_WORLD:
512 mono_thread_info_suspend_unlock ();
513 MONO_PROFILER_RAISE (gc_event, (MONO_GC_EVENT_POST_START_WORLD_UNLOCKED, 0));
514 break;
515 default:
516 break;
517 }
518 }
519
520
521 static void
on_gc_heap_resize(size_t new_size)522 on_gc_heap_resize (size_t new_size)
523 {
524 guint64 heap_size = GC_get_heap_size ();
525 #ifndef DISABLE_PERFCOUNTERS
526 if (mono_perfcounters) {
527 /* FIXME: change these to mono_atomic_store_i64 () */
528 UnlockedWrite64 (&mono_perfcounters->gc_committed_bytes, heap_size);
529 UnlockedWrite64 (&mono_perfcounters->gc_reserved_bytes, heap_size);
530 UnlockedWrite64 (&mono_perfcounters->gc_gen0size, heap_size);
531 }
532 #endif
533
534 MONO_PROFILER_RAISE (gc_resize, (new_size));
535 }
536
537 typedef struct {
538 char *start;
539 char *end;
540 } RootData;
541
542 static gpointer
register_root(gpointer arg)543 register_root (gpointer arg)
544 {
545 RootData* root_data = arg;
546 g_hash_table_insert (roots, root_data->start, root_data->end);
547 return NULL;
548 }
549
550 int
mono_gc_register_root(char * start,size_t size,void * descr,MonoGCRootSource source,const char * msg)551 mono_gc_register_root (char *start, size_t size, void *descr, MonoGCRootSource source, const char *msg)
552 {
553 RootData root_data;
554 root_data.start = start;
555 /* Boehm root processing requires one byte past end of region to be scanned */
556 root_data.end = start + size + 1;
557 GC_call_with_alloc_lock (register_root, &root_data);
558
559 return TRUE;
560 }
561
562 int
mono_gc_register_root_wbarrier(char * start,size_t size,MonoGCDescriptor descr,MonoGCRootSource source,const char * msg)563 mono_gc_register_root_wbarrier (char *start, size_t size, MonoGCDescriptor descr, MonoGCRootSource source, const char *msg)
564 {
565 return mono_gc_register_root (start, size, descr, source, msg);
566 }
567
568 static gpointer
deregister_root(gpointer arg)569 deregister_root (gpointer arg)
570 {
571 gboolean removed = g_hash_table_remove (roots, arg);
572 g_assert (removed);
573 return NULL;
574 }
575
576 void
mono_gc_deregister_root(char * addr)577 mono_gc_deregister_root (char* addr)
578 {
579 GC_call_with_alloc_lock (deregister_root, addr);
580 }
581
582 static void
push_root(gpointer key,gpointer value,gpointer user_data)583 push_root (gpointer key, gpointer value, gpointer user_data)
584 {
585 GC_push_all (key, value);
586 }
587
588 static void
push_handle_stack(HandleStack * stack)589 push_handle_stack (HandleStack* stack)
590 {
591 HandleChunk *cur = stack->bottom;
592 HandleChunk *last = stack->top;
593
594 if (!cur)
595 return;
596
597 while (cur) {
598 if (cur->size > 0)
599 GC_push_all (cur->elems, (char*)(cur->elems + cur->size) + 1);
600 if (cur == last)
601 break;
602 cur = cur->next;
603 }
604 }
605
606 static void
mono_push_other_roots(void)607 mono_push_other_roots (void)
608 {
609 g_hash_table_foreach (roots, push_root, NULL);
610 FOREACH_THREAD (info) {
611 HandleStack* stack = (HandleStack*)info->handle_stack;
612 if (stack)
613 push_handle_stack (stack);
614 } FOREACH_THREAD_END
615 if (default_push_other_roots)
616 default_push_other_roots ();
617 }
618
619 static void
mono_gc_weak_link_add(void ** link_addr,MonoObject * obj,gboolean track)620 mono_gc_weak_link_add (void **link_addr, MonoObject *obj, gboolean track)
621 {
622 /* libgc requires that we use HIDE_POINTER... */
623 *link_addr = (void*)HIDE_POINTER (obj);
624 if (track)
625 GC_REGISTER_LONG_LINK (link_addr, obj);
626 else
627 GC_GENERAL_REGISTER_DISAPPEARING_LINK (link_addr, obj);
628 }
629
630 static void
mono_gc_weak_link_remove(void ** link_addr,gboolean track)631 mono_gc_weak_link_remove (void **link_addr, gboolean track)
632 {
633 if (track)
634 GC_unregister_long_link (link_addr);
635 else
636 GC_unregister_disappearing_link (link_addr);
637 *link_addr = NULL;
638 }
639
640 static gpointer
reveal_link(gpointer link_addr)641 reveal_link (gpointer link_addr)
642 {
643 void **link_a = (void **)link_addr;
644 return REVEAL_POINTER (*link_a);
645 }
646
647 static MonoObject *
mono_gc_weak_link_get(void ** link_addr)648 mono_gc_weak_link_get (void **link_addr)
649 {
650 MonoObject *obj = (MonoObject *)GC_call_with_alloc_lock (reveal_link, link_addr);
651 if (obj == (MonoObject *) -1)
652 return NULL;
653 return obj;
654 }
655
656 void*
mono_gc_make_descr_for_string(gsize * bitmap,int numbits)657 mono_gc_make_descr_for_string (gsize *bitmap, int numbits)
658 {
659 return mono_gc_make_descr_from_bitmap (bitmap, numbits);
660 }
661
662 void*
mono_gc_make_descr_for_object(gsize * bitmap,int numbits,size_t obj_size)663 mono_gc_make_descr_for_object (gsize *bitmap, int numbits, size_t obj_size)
664 {
665 return mono_gc_make_descr_from_bitmap (bitmap, numbits);
666 }
667
668 void*
mono_gc_make_descr_for_array(int vector,gsize * elem_bitmap,int numbits,size_t elem_size)669 mono_gc_make_descr_for_array (int vector, gsize *elem_bitmap, int numbits, size_t elem_size)
670 {
671 /* libgc has no usable support for arrays... */
672 return GC_NO_DESCRIPTOR;
673 }
674
675 void*
mono_gc_make_descr_from_bitmap(gsize * bitmap,int numbits)676 mono_gc_make_descr_from_bitmap (gsize *bitmap, int numbits)
677 {
678 /* It seems there are issues when the bitmap doesn't fit: play it safe */
679 if (numbits >= 30)
680 return GC_NO_DESCRIPTOR;
681 else
682 return (gpointer)GC_make_descriptor ((GC_bitmap)bitmap, numbits);
683 }
684
685 void*
mono_gc_make_vector_descr(void)686 mono_gc_make_vector_descr (void)
687 {
688 return NULL;
689 }
690
691 void*
mono_gc_make_root_descr_all_refs(int numbits)692 mono_gc_make_root_descr_all_refs (int numbits)
693 {
694 return NULL;
695 }
696
697 void*
mono_gc_alloc_fixed(size_t size,void * descr,MonoGCRootSource source,const char * msg)698 mono_gc_alloc_fixed (size_t size, void *descr, MonoGCRootSource source, const char *msg)
699 {
700 return GC_MALLOC_UNCOLLECTABLE (size);
701 }
702
703 void
mono_gc_free_fixed(void * addr)704 mono_gc_free_fixed (void* addr)
705 {
706 GC_FREE (addr);
707 }
708
709 void *
mono_gc_alloc_obj(MonoVTable * vtable,size_t size)710 mono_gc_alloc_obj (MonoVTable *vtable, size_t size)
711 {
712 MonoObject *obj;
713
714 if (!vtable->klass->has_references) {
715 obj = (MonoObject *)GC_MALLOC_ATOMIC (size);
716 if (G_UNLIKELY (!obj))
717 return NULL;
718
719 obj->vtable = vtable;
720 obj->synchronisation = NULL;
721
722 memset ((char *) obj + sizeof (MonoObject), 0, size - sizeof (MonoObject));
723 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
724 obj = (MonoObject *)GC_GCJ_MALLOC (size, vtable);
725 if (G_UNLIKELY (!obj))
726 return NULL;
727 } else {
728 obj = (MonoObject *)GC_MALLOC (size);
729 if (G_UNLIKELY (!obj))
730 return NULL;
731
732 obj->vtable = vtable;
733 }
734
735 if (G_UNLIKELY (mono_profiler_allocations_enabled ()))
736 MONO_PROFILER_RAISE (gc_allocation, (obj));
737
738 return obj;
739 }
740
741 void *
mono_gc_alloc_vector(MonoVTable * vtable,size_t size,uintptr_t max_length)742 mono_gc_alloc_vector (MonoVTable *vtable, size_t size, uintptr_t max_length)
743 {
744 MonoArray *obj;
745
746 if (!vtable->klass->has_references) {
747 obj = (MonoArray *)GC_MALLOC_ATOMIC (size);
748 if (G_UNLIKELY (!obj))
749 return NULL;
750
751 obj->obj.vtable = vtable;
752 obj->obj.synchronisation = NULL;
753
754 memset ((char *) obj + sizeof (MonoObject), 0, size - sizeof (MonoObject));
755 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
756 obj = (MonoArray *)GC_GCJ_MALLOC (size, vtable);
757 if (G_UNLIKELY (!obj))
758 return NULL;
759 } else {
760 obj = (MonoArray *)GC_MALLOC (size);
761 if (G_UNLIKELY (!obj))
762 return NULL;
763
764 obj->obj.vtable = vtable;
765 }
766
767 obj->max_length = max_length;
768
769 if (G_UNLIKELY (mono_profiler_allocations_enabled ()))
770 MONO_PROFILER_RAISE (gc_allocation, (&obj->obj));
771
772 return obj;
773 }
774
775 void *
mono_gc_alloc_array(MonoVTable * vtable,size_t size,uintptr_t max_length,uintptr_t bounds_size)776 mono_gc_alloc_array (MonoVTable *vtable, size_t size, uintptr_t max_length, uintptr_t bounds_size)
777 {
778 MonoArray *obj;
779
780 if (!vtable->klass->has_references) {
781 obj = (MonoArray *)GC_MALLOC_ATOMIC (size);
782 if (G_UNLIKELY (!obj))
783 return NULL;
784
785 obj->obj.vtable = vtable;
786 obj->obj.synchronisation = NULL;
787
788 memset ((char *) obj + sizeof (MonoObject), 0, size - sizeof (MonoObject));
789 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
790 obj = (MonoArray *)GC_GCJ_MALLOC (size, vtable);
791 if (G_UNLIKELY (!obj))
792 return NULL;
793 } else {
794 obj = (MonoArray *)GC_MALLOC (size);
795 if (G_UNLIKELY (!obj))
796 return NULL;
797
798 obj->obj.vtable = vtable;
799 }
800
801 obj->max_length = max_length;
802
803 if (bounds_size)
804 obj->bounds = (MonoArrayBounds *) ((char *) obj + size - bounds_size);
805
806 if (G_UNLIKELY (mono_profiler_allocations_enabled ()))
807 MONO_PROFILER_RAISE (gc_allocation, (&obj->obj));
808
809 return obj;
810 }
811
812 void *
mono_gc_alloc_string(MonoVTable * vtable,size_t size,gint32 len)813 mono_gc_alloc_string (MonoVTable *vtable, size_t size, gint32 len)
814 {
815 MonoString *obj = (MonoString *)GC_MALLOC_ATOMIC (size);
816 if (G_UNLIKELY (!obj))
817 return NULL;
818
819 obj->object.vtable = vtable;
820 obj->object.synchronisation = NULL;
821 obj->length = len;
822 obj->chars [len] = 0;
823
824 if (G_UNLIKELY (mono_profiler_allocations_enabled ()))
825 MONO_PROFILER_RAISE (gc_allocation, (&obj->object));
826
827 return obj;
828 }
829
830 void*
mono_gc_alloc_mature(MonoVTable * vtable,size_t size)831 mono_gc_alloc_mature (MonoVTable *vtable, size_t size)
832 {
833 return mono_gc_alloc_obj (vtable, size);
834 }
835
836 void*
mono_gc_alloc_pinned_obj(MonoVTable * vtable,size_t size)837 mono_gc_alloc_pinned_obj (MonoVTable *vtable, size_t size)
838 {
839 return mono_gc_alloc_obj (vtable, size);
840 }
841
842 int
mono_gc_invoke_finalizers(void)843 mono_gc_invoke_finalizers (void)
844 {
845 /* There is a bug in GC_invoke_finalizer () in versions <= 6.2alpha4:
846 * the 'mem_freed' variable is not initialized when there are no
847 * objects to finalize, which leads to strange behavior later on.
848 * The check is necessary to work around that bug.
849 */
850 if (GC_should_invoke_finalizers ())
851 return GC_invoke_finalizers ();
852 return 0;
853 }
854
855 MonoBoolean
mono_gc_pending_finalizers(void)856 mono_gc_pending_finalizers (void)
857 {
858 return GC_should_invoke_finalizers ();
859 }
860
861 void
mono_gc_wbarrier_set_field(MonoObject * obj,gpointer field_ptr,MonoObject * value)862 mono_gc_wbarrier_set_field (MonoObject *obj, gpointer field_ptr, MonoObject* value)
863 {
864 *(void**)field_ptr = value;
865 }
866
867 void
mono_gc_wbarrier_set_arrayref(MonoArray * arr,gpointer slot_ptr,MonoObject * value)868 mono_gc_wbarrier_set_arrayref (MonoArray *arr, gpointer slot_ptr, MonoObject* value)
869 {
870 *(void**)slot_ptr = value;
871 }
872
873 void
mono_gc_wbarrier_arrayref_copy(gpointer dest_ptr,gpointer src_ptr,int count)874 mono_gc_wbarrier_arrayref_copy (gpointer dest_ptr, gpointer src_ptr, int count)
875 {
876 mono_gc_memmove_aligned (dest_ptr, src_ptr, count * sizeof (gpointer));
877 }
878
879 void
mono_gc_wbarrier_generic_store(gpointer ptr,MonoObject * value)880 mono_gc_wbarrier_generic_store (gpointer ptr, MonoObject* value)
881 {
882 *(void**)ptr = value;
883 }
884
885 void
mono_gc_wbarrier_generic_store_atomic(gpointer ptr,MonoObject * value)886 mono_gc_wbarrier_generic_store_atomic (gpointer ptr, MonoObject *value)
887 {
888 mono_atomic_store_ptr ((volatile gpointer *)ptr, value);
889 }
890
891 void
mono_gc_wbarrier_generic_nostore(gpointer ptr)892 mono_gc_wbarrier_generic_nostore (gpointer ptr)
893 {
894 }
895
896 void
mono_gc_wbarrier_value_copy(gpointer dest,gpointer src,int count,MonoClass * klass)897 mono_gc_wbarrier_value_copy (gpointer dest, gpointer src, int count, MonoClass *klass)
898 {
899 mono_gc_memmove_atomic (dest, src, count * mono_class_value_size (klass, NULL));
900 }
901
902 void
mono_gc_wbarrier_object_copy(MonoObject * obj,MonoObject * src)903 mono_gc_wbarrier_object_copy (MonoObject* obj, MonoObject *src)
904 {
905 /* do not copy the sync state */
906 mono_gc_memmove_aligned ((char*)obj + sizeof (MonoObject), (char*)src + sizeof (MonoObject),
907 mono_object_class (obj)->instance_size - sizeof (MonoObject));
908 }
909
910 void
mono_gc_clear_domain(MonoDomain * domain)911 mono_gc_clear_domain (MonoDomain *domain)
912 {
913 }
914
915 void
mono_gc_suspend_finalizers(void)916 mono_gc_suspend_finalizers (void)
917 {
918 }
919
920 int
mono_gc_get_suspend_signal(void)921 mono_gc_get_suspend_signal (void)
922 {
923 return GC_get_suspend_signal ();
924 }
925
926 int
mono_gc_get_restart_signal(void)927 mono_gc_get_restart_signal (void)
928 {
929 return GC_get_thr_restart_signal ();
930 }
931
932 #if defined(USE_COMPILER_TLS) && defined(__linux__) && (defined(__i386__) || defined(__x86_64__))
933 extern __thread void* GC_thread_tls;
934 #include "metadata-internals.h"
935
936 static int
shift_amount(int v)937 shift_amount (int v)
938 {
939 int i = 0;
940 while (!(v & (1 << i)))
941 i++;
942 return i;
943 }
944
945 enum {
946 ATYPE_FREEPTR,
947 ATYPE_FREEPTR_FOR_BOX,
948 ATYPE_NORMAL,
949 ATYPE_GCJ,
950 ATYPE_STRING,
951 ATYPE_NUM
952 };
953
954 static MonoMethod*
create_allocator(int atype,int tls_key,gboolean slowpath)955 create_allocator (int atype, int tls_key, gboolean slowpath)
956 {
957 int index_var, bytes_var, my_fl_var, my_entry_var;
958 guint32 no_freelist_branch, not_small_enough_branch = 0;
959 guint32 size_overflow_branch = 0;
960 MonoMethodBuilder *mb;
961 MonoMethod *res;
962 MonoMethodSignature *csig;
963 const char *name = NULL;
964 WrapperInfo *info;
965
966 g_assert_not_reached ();
967
968 if (atype == ATYPE_FREEPTR) {
969 name = slowpath ? "SlowAllocPtrfree" : "AllocPtrfree";
970 } else if (atype == ATYPE_FREEPTR_FOR_BOX) {
971 name = slowpath ? "SlowAllocPtrfreeBox" : "AllocPtrfreeBox";
972 } else if (atype == ATYPE_NORMAL) {
973 name = slowpath ? "SlowAlloc" : "Alloc";
974 } else if (atype == ATYPE_GCJ) {
975 name = slowpath ? "SlowAllocGcj" : "AllocGcj";
976 } else if (atype == ATYPE_STRING) {
977 name = slowpath ? "SlowAllocString" : "AllocString";
978 } else {
979 g_assert_not_reached ();
980 }
981
982 csig = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
983
984 if (atype == ATYPE_STRING) {
985 csig->ret = &mono_defaults.string_class->byval_arg;
986 csig->params [0] = &mono_defaults.int_class->byval_arg;
987 csig->params [1] = &mono_defaults.int32_class->byval_arg;
988 } else {
989 csig->ret = &mono_defaults.object_class->byval_arg;
990 csig->params [0] = &mono_defaults.int_class->byval_arg;
991 csig->params [1] = &mono_defaults.int32_class->byval_arg;
992 }
993
994 mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_ALLOC);
995
996 if (slowpath)
997 goto always_slowpath;
998
999 bytes_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
1000 if (atype == ATYPE_STRING) {
1001 /* a string alloator method takes the args: (vtable, len) */
1002 /* bytes = (offsetof (MonoString, chars) + ((len + 1) * 2)); */
1003 mono_mb_emit_ldarg (mb, 1);
1004 mono_mb_emit_icon (mb, 1);
1005 mono_mb_emit_byte (mb, MONO_CEE_ADD);
1006 mono_mb_emit_icon (mb, 1);
1007 mono_mb_emit_byte (mb, MONO_CEE_SHL);
1008 // sizeof (MonoString) might include padding
1009 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoString, chars));
1010 mono_mb_emit_byte (mb, MONO_CEE_ADD);
1011 mono_mb_emit_stloc (mb, bytes_var);
1012 } else {
1013 mono_mb_emit_ldarg (mb, 1);
1014 mono_mb_emit_stloc (mb, bytes_var);
1015 }
1016
1017 /* this is needed for strings/arrays only as the other big types are never allocated with this method */
1018 if (atype == ATYPE_STRING) {
1019 /* check for size */
1020 /* if (!SMALL_ENOUGH (bytes)) jump slow_path;*/
1021 mono_mb_emit_ldloc (mb, bytes_var);
1022 mono_mb_emit_icon (mb, (NFREELISTS-1) * GRANULARITY);
1023 not_small_enough_branch = mono_mb_emit_short_branch (mb, MONO_CEE_BGT_UN_S);
1024 /* check for overflow */
1025 mono_mb_emit_ldloc (mb, bytes_var);
1026 mono_mb_emit_icon (mb, sizeof (MonoString));
1027 size_overflow_branch = mono_mb_emit_short_branch (mb, MONO_CEE_BLE_UN_S);
1028 }
1029
1030 /* int index = INDEX_FROM_BYTES(bytes); */
1031 index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
1032
1033 mono_mb_emit_ldloc (mb, bytes_var);
1034 mono_mb_emit_icon (mb, GRANULARITY - 1);
1035 mono_mb_emit_byte (mb, MONO_CEE_ADD);
1036 mono_mb_emit_icon (mb, shift_amount (GRANULARITY));
1037 mono_mb_emit_byte (mb, MONO_CEE_SHR_UN);
1038 mono_mb_emit_icon (mb, shift_amount (sizeof (gpointer)));
1039 mono_mb_emit_byte (mb, MONO_CEE_SHL);
1040 /* index var is already adjusted into bytes */
1041 mono_mb_emit_stloc (mb, index_var);
1042
1043 my_fl_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1044 my_entry_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1045 /* my_fl = ((GC_thread)tsd) -> ptrfree_freelists + index; */
1046 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1047 mono_mb_emit_byte (mb, 0x0D); /* CEE_MONO_TLS */
1048 mono_mb_emit_i4 (mb, tls_key);
1049 if (atype == ATYPE_FREEPTR || atype == ATYPE_FREEPTR_FOR_BOX || atype == ATYPE_STRING)
1050 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (struct GC_Thread_Rep, tlfs)
1051 + G_STRUCT_OFFSET (struct thread_local_freelists,
1052 ptrfree_freelists));
1053 else if (atype == ATYPE_NORMAL)
1054 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (struct GC_Thread_Rep, tlfs)
1055 + G_STRUCT_OFFSET (struct thread_local_freelists,
1056 normal_freelists));
1057 else if (atype == ATYPE_GCJ)
1058 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (struct GC_Thread_Rep, tlfs)
1059 + G_STRUCT_OFFSET (struct thread_local_freelists,
1060 gcj_freelists));
1061 else
1062 g_assert_not_reached ();
1063 mono_mb_emit_byte (mb, MONO_CEE_ADD);
1064 mono_mb_emit_ldloc (mb, index_var);
1065 mono_mb_emit_byte (mb, MONO_CEE_ADD);
1066 mono_mb_emit_stloc (mb, my_fl_var);
1067
1068 /* my_entry = *my_fl; */
1069 mono_mb_emit_ldloc (mb, my_fl_var);
1070 mono_mb_emit_byte (mb, MONO_CEE_LDIND_I);
1071 mono_mb_emit_stloc (mb, my_entry_var);
1072
1073 /* if (EXPECT((word)my_entry >= HBLKSIZE, 1)) { */
1074 mono_mb_emit_ldloc (mb, my_entry_var);
1075 mono_mb_emit_icon (mb, HBLKSIZE);
1076 no_freelist_branch = mono_mb_emit_short_branch (mb, MONO_CEE_BLT_UN_S);
1077
1078 /* ptr_t next = obj_link(my_entry); *my_fl = next; */
1079 mono_mb_emit_ldloc (mb, my_fl_var);
1080 mono_mb_emit_ldloc (mb, my_entry_var);
1081 mono_mb_emit_byte (mb, MONO_CEE_LDIND_I);
1082 mono_mb_emit_byte (mb, MONO_CEE_STIND_I);
1083
1084 /* set the vtable and clear the words in the object */
1085 mono_mb_emit_ldloc (mb, my_entry_var);
1086 mono_mb_emit_ldarg (mb, 0);
1087 mono_mb_emit_byte (mb, MONO_CEE_STIND_I);
1088
1089 if (atype == ATYPE_FREEPTR) {
1090 int start_var, end_var, start_loop;
1091 /* end = my_entry + bytes; start = my_entry + sizeof (gpointer);
1092 */
1093 start_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1094 end_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1095 mono_mb_emit_ldloc (mb, my_entry_var);
1096 mono_mb_emit_ldloc (mb, bytes_var);
1097 mono_mb_emit_byte (mb, MONO_CEE_ADD);
1098 mono_mb_emit_stloc (mb, end_var);
1099 mono_mb_emit_ldloc (mb, my_entry_var);
1100 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoObject, synchronisation));
1101 mono_mb_emit_byte (mb, MONO_CEE_ADD);
1102 mono_mb_emit_stloc (mb, start_var);
1103 /*
1104 * do {
1105 * *start++ = NULL;
1106 * } while (start < end);
1107 */
1108 start_loop = mono_mb_get_label (mb);
1109 mono_mb_emit_ldloc (mb, start_var);
1110 mono_mb_emit_icon (mb, 0);
1111 mono_mb_emit_byte (mb, MONO_CEE_STIND_I);
1112 mono_mb_emit_ldloc (mb, start_var);
1113 mono_mb_emit_icon (mb, sizeof (gpointer));
1114 mono_mb_emit_byte (mb, MONO_CEE_ADD);
1115 mono_mb_emit_stloc (mb, start_var);
1116
1117 mono_mb_emit_ldloc (mb, start_var);
1118 mono_mb_emit_ldloc (mb, end_var);
1119 mono_mb_emit_byte (mb, MONO_CEE_BLT_UN_S);
1120 mono_mb_emit_byte (mb, start_loop - (mono_mb_get_label (mb) + 1));
1121 } else if (atype == ATYPE_FREEPTR_FOR_BOX || atype == ATYPE_STRING) {
1122 /* need to clear just the sync pointer */
1123 mono_mb_emit_ldloc (mb, my_entry_var);
1124 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoObject, synchronisation));
1125 mono_mb_emit_byte (mb, MONO_CEE_ADD);
1126 mono_mb_emit_icon (mb, 0);
1127 mono_mb_emit_byte (mb, MONO_CEE_STIND_I);
1128 }
1129
1130 if (atype == ATYPE_STRING) {
1131 /* need to set length and clear the last char */
1132 /* s->length = len; */
1133 mono_mb_emit_ldloc (mb, my_entry_var);
1134 mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoString, length));
1135 mono_mb_emit_byte (mb, MONO_CEE_ADD);
1136 mono_mb_emit_ldarg (mb, 1);
1137 mono_mb_emit_byte (mb, MONO_CEE_STIND_I4);
1138 /* s->chars [len] = 0; */
1139 mono_mb_emit_ldloc (mb, my_entry_var);
1140 mono_mb_emit_ldloc (mb, bytes_var);
1141 mono_mb_emit_icon (mb, 2);
1142 mono_mb_emit_byte (mb, MONO_CEE_SUB);
1143 mono_mb_emit_byte (mb, MONO_CEE_ADD);
1144 mono_mb_emit_icon (mb, 0);
1145 mono_mb_emit_byte (mb, MONO_CEE_STIND_I2);
1146 }
1147
1148 /* return my_entry; */
1149 mono_mb_emit_ldloc (mb, my_entry_var);
1150 mono_mb_emit_byte (mb, MONO_CEE_RET);
1151
1152 mono_mb_patch_short_branch (mb, no_freelist_branch);
1153 if (not_small_enough_branch > 0)
1154 mono_mb_patch_short_branch (mb, not_small_enough_branch);
1155 if (size_overflow_branch > 0)
1156 mono_mb_patch_short_branch (mb, size_overflow_branch);
1157
1158 /* the slow path: we just call back into the runtime */
1159 always_slowpath:
1160 if (atype == ATYPE_STRING) {
1161 mono_mb_emit_ldarg (mb, 1);
1162 mono_mb_emit_icall (mb, ves_icall_string_alloc);
1163 } else {
1164 mono_mb_emit_ldarg (mb, 0);
1165 mono_mb_emit_icall (mb, ves_icall_object_new_specific);
1166 }
1167
1168 mono_mb_emit_byte (mb, MONO_CEE_RET);
1169
1170 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_NONE);
1171 info->d.alloc.gc_name = "boehm";
1172 info->d.alloc.alloc_type = atype;
1173 mb->init_locals = FALSE;
1174
1175 res = mono_mb_create (mb, csig, 8, info);
1176 mono_mb_free (mb);
1177
1178 return res;
1179 }
1180
1181 static MonoMethod* alloc_method_cache [ATYPE_NUM];
1182 static MonoMethod* slowpath_alloc_method_cache [ATYPE_NUM];
1183
1184 gboolean
mono_gc_is_critical_method(MonoMethod * method)1185 mono_gc_is_critical_method (MonoMethod *method)
1186 {
1187 int i;
1188
1189 for (i = 0; i < ATYPE_NUM; ++i)
1190 if (method == alloc_method_cache [i] || method == slowpath_alloc_method_cache [i])
1191 return TRUE;
1192
1193 return FALSE;
1194 }
1195
1196 /*
1197 * If possible, generate a managed method that can quickly allocate objects in class
1198 * @klass. The method will typically have an thread-local inline allocation sequence.
1199 * The signature of the called method is:
1200 * object allocate (MonoVTable *vtable)
1201 * The thread local alloc logic is taken from libgc/pthread_support.c.
1202 */
1203 MonoMethod*
mono_gc_get_managed_allocator(MonoClass * klass,gboolean for_box,gboolean known_instance_size)1204 mono_gc_get_managed_allocator (MonoClass *klass, gboolean for_box, gboolean known_instance_size)
1205 {
1206 int atype;
1207
1208 /*
1209 * Tls implementation changed, we jump to tls native getters/setters.
1210 * Is boehm managed allocator ok with this ? Do we even care ?
1211 */
1212 return NULL;
1213
1214 if (!SMALL_ENOUGH (klass->instance_size))
1215 return NULL;
1216 if (mono_class_has_finalizer (klass) || mono_class_is_marshalbyref (klass))
1217 return NULL;
1218 if (G_UNLIKELY (mono_profiler_allocations_enabled ()))
1219 return NULL;
1220 if (klass->rank)
1221 return NULL;
1222 if (mono_class_is_open_constructed_type (&klass->byval_arg))
1223 return NULL;
1224 if (klass->byval_arg.type == MONO_TYPE_STRING) {
1225 atype = ATYPE_STRING;
1226 } else if (!known_instance_size) {
1227 return NULL;
1228 } else if (!klass->has_references) {
1229 if (for_box)
1230 atype = ATYPE_FREEPTR_FOR_BOX;
1231 else
1232 atype = ATYPE_FREEPTR;
1233 } else {
1234 return NULL;
1235 /*
1236 * disabled because we currently do a runtime choice anyway, to
1237 * deal with multiple appdomains.
1238 if (vtable->gc_descr != GC_NO_DESCRIPTOR)
1239 atype = ATYPE_GCJ;
1240 else
1241 atype = ATYPE_NORMAL;
1242 */
1243 }
1244 return mono_gc_get_managed_allocator_by_type (atype, MANAGED_ALLOCATOR_REGULAR);
1245 }
1246
1247 MonoMethod*
mono_gc_get_managed_array_allocator(MonoClass * klass)1248 mono_gc_get_managed_array_allocator (MonoClass *klass)
1249 {
1250 return NULL;
1251 }
1252
1253 /**
1254 * mono_gc_get_managed_allocator_by_type:
1255 *
1256 * Return a managed allocator method corresponding to allocator type ATYPE.
1257 */
1258 MonoMethod*
mono_gc_get_managed_allocator_by_type(int atype,ManagedAllocatorVariant variant)1259 mono_gc_get_managed_allocator_by_type (int atype, ManagedAllocatorVariant variant)
1260 {
1261 MonoMethod *res;
1262 gboolean slowpath = variant != MANAGED_ALLOCATOR_REGULAR;
1263 MonoMethod **cache = slowpath ? slowpath_alloc_method_cache : alloc_method_cache;
1264
1265 return NULL;
1266
1267 res = cache [atype];
1268 if (res)
1269 return res;
1270
1271 res = create_allocator (atype, -1, slowpath);
1272 mono_os_mutex_lock (&mono_gc_lock);
1273 if (cache [atype]) {
1274 mono_free_method (res);
1275 res = cache [atype];
1276 } else {
1277 mono_memory_barrier ();
1278 cache [atype] = res;
1279 }
1280 mono_os_mutex_unlock (&mono_gc_lock);
1281 return res;
1282 }
1283
1284 guint32
mono_gc_get_managed_allocator_types(void)1285 mono_gc_get_managed_allocator_types (void)
1286 {
1287 return ATYPE_NUM;
1288 }
1289
1290 MonoMethod*
mono_gc_get_write_barrier(void)1291 mono_gc_get_write_barrier (void)
1292 {
1293 g_assert_not_reached ();
1294 return NULL;
1295 }
1296
1297 #else
1298
1299 gboolean
mono_gc_is_critical_method(MonoMethod * method)1300 mono_gc_is_critical_method (MonoMethod *method)
1301 {
1302 return FALSE;
1303 }
1304
1305 MonoMethod*
mono_gc_get_managed_allocator(MonoClass * klass,gboolean for_box,gboolean known_instance_size)1306 mono_gc_get_managed_allocator (MonoClass *klass, gboolean for_box, gboolean known_instance_size)
1307 {
1308 return NULL;
1309 }
1310
1311 MonoMethod*
mono_gc_get_managed_array_allocator(MonoClass * klass)1312 mono_gc_get_managed_array_allocator (MonoClass *klass)
1313 {
1314 return NULL;
1315 }
1316
1317 MonoMethod*
mono_gc_get_managed_allocator_by_type(int atype,ManagedAllocatorVariant variant)1318 mono_gc_get_managed_allocator_by_type (int atype, ManagedAllocatorVariant variant)
1319 {
1320 return NULL;
1321 }
1322
1323 guint32
mono_gc_get_managed_allocator_types(void)1324 mono_gc_get_managed_allocator_types (void)
1325 {
1326 return 0;
1327 }
1328
1329 MonoMethod*
mono_gc_get_write_barrier(void)1330 mono_gc_get_write_barrier (void)
1331 {
1332 g_assert_not_reached ();
1333 return NULL;
1334 }
1335
1336 #endif
1337
1338 MonoMethod*
mono_gc_get_specific_write_barrier(gboolean is_concurrent)1339 mono_gc_get_specific_write_barrier (gboolean is_concurrent)
1340 {
1341 g_assert_not_reached ();
1342 return NULL;
1343 }
1344
1345 int
mono_gc_get_aligned_size_for_allocator(int size)1346 mono_gc_get_aligned_size_for_allocator (int size)
1347 {
1348 return size;
1349 }
1350
1351 const char *
mono_gc_get_gc_name(void)1352 mono_gc_get_gc_name (void)
1353 {
1354 return "boehm";
1355 }
1356
1357 void*
mono_gc_invoke_with_gc_lock(MonoGCLockedCallbackFunc func,void * data)1358 mono_gc_invoke_with_gc_lock (MonoGCLockedCallbackFunc func, void *data)
1359 {
1360 return GC_call_with_alloc_lock (func, data);
1361 }
1362
1363 char*
mono_gc_get_description(void)1364 mono_gc_get_description (void)
1365 {
1366 return g_strdup (DEFAULT_GC_NAME);
1367 }
1368
1369 void
mono_gc_set_desktop_mode(void)1370 mono_gc_set_desktop_mode (void)
1371 {
1372 GC_dont_expand = 1;
1373 }
1374
1375 gboolean
mono_gc_is_moving(void)1376 mono_gc_is_moving (void)
1377 {
1378 return FALSE;
1379 }
1380
1381 gboolean
mono_gc_is_disabled(void)1382 mono_gc_is_disabled (void)
1383 {
1384 if (GC_dont_gc || g_hasenv ("GC_DONT_GC"))
1385 return TRUE;
1386 else
1387 return FALSE;
1388 }
1389
1390 void
mono_gc_wbarrier_range_copy(gpointer _dest,gpointer _src,int size)1391 mono_gc_wbarrier_range_copy (gpointer _dest, gpointer _src, int size)
1392 {
1393 g_assert_not_reached ();
1394 }
1395
1396 void*
mono_gc_get_range_copy_func(void)1397 mono_gc_get_range_copy_func (void)
1398 {
1399 return &mono_gc_wbarrier_range_copy;
1400 }
1401
1402 guint8*
mono_gc_get_card_table(int * shift_bits,gpointer * card_mask)1403 mono_gc_get_card_table (int *shift_bits, gpointer *card_mask)
1404 {
1405 g_assert_not_reached ();
1406 return NULL;
1407 }
1408
1409 gboolean
mono_gc_card_table_nursery_check(void)1410 mono_gc_card_table_nursery_check (void)
1411 {
1412 g_assert_not_reached ();
1413 return TRUE;
1414 }
1415
1416 void*
mono_gc_get_nursery(int * shift_bits,size_t * size)1417 mono_gc_get_nursery (int *shift_bits, size_t *size)
1418 {
1419 return NULL;
1420 }
1421
1422 gboolean
mono_gc_precise_stack_mark_enabled(void)1423 mono_gc_precise_stack_mark_enabled (void)
1424 {
1425 return FALSE;
1426 }
1427
1428 FILE *
mono_gc_get_logfile(void)1429 mono_gc_get_logfile (void)
1430 {
1431 return NULL;
1432 }
1433
1434 void
mono_gc_params_set(const char * options)1435 mono_gc_params_set (const char* options)
1436 {
1437 }
1438
1439 void
mono_gc_debug_set(const char * options)1440 mono_gc_debug_set (const char* options)
1441 {
1442 }
1443
1444 void
mono_gc_conservatively_scan_area(void * start,void * end)1445 mono_gc_conservatively_scan_area (void *start, void *end)
1446 {
1447 g_assert_not_reached ();
1448 }
1449
1450 void *
mono_gc_scan_object(void * obj,void * gc_data)1451 mono_gc_scan_object (void *obj, void *gc_data)
1452 {
1453 g_assert_not_reached ();
1454 return NULL;
1455 }
1456
1457 gsize*
mono_gc_get_bitmap_for_descr(void * descr,int * numbits)1458 mono_gc_get_bitmap_for_descr (void *descr, int *numbits)
1459 {
1460 g_assert_not_reached ();
1461 return NULL;
1462 }
1463
1464 void
mono_gc_set_gc_callbacks(MonoGCCallbacks * callbacks)1465 mono_gc_set_gc_callbacks (MonoGCCallbacks *callbacks)
1466 {
1467 }
1468
1469 void
mono_gc_set_stack_end(void * stack_end)1470 mono_gc_set_stack_end (void *stack_end)
1471 {
1472 }
1473
mono_gc_set_skip_thread(gboolean value)1474 void mono_gc_set_skip_thread (gboolean value)
1475 {
1476 }
1477
1478 void
mono_gc_register_for_finalization(MonoObject * obj,void * user_data)1479 mono_gc_register_for_finalization (MonoObject *obj, void *user_data)
1480 {
1481 guint offset = 0;
1482
1483 #ifndef GC_DEBUG
1484 /* This assertion is not valid when GC_DEBUG is defined */
1485 g_assert (GC_base (obj) == (char*)obj - offset);
1486 #endif
1487
1488 GC_REGISTER_FINALIZER_NO_ORDER ((char*)obj - offset, (GC_finalization_proc)user_data, GUINT_TO_POINTER (offset), NULL, NULL);
1489 }
1490
1491 #ifndef HOST_WIN32
1492 int
mono_gc_pthread_create(pthread_t * new_thread,const pthread_attr_t * attr,void * (* start_routine)(void *),void * arg)1493 mono_gc_pthread_create (pthread_t *new_thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg)
1494 {
1495 /* it is being replaced by GC_pthread_create on some
1496 * platforms, see libgc/include/gc_pthread_redirects.h */
1497 return pthread_create (new_thread, attr, start_routine, arg);
1498 }
1499 #endif
1500
1501 #ifdef HOST_WIN32
mono_gc_dllmain(HMODULE module_handle,DWORD reason,LPVOID reserved)1502 BOOL APIENTRY mono_gc_dllmain (HMODULE module_handle, DWORD reason, LPVOID reserved)
1503 {
1504 return GC_DllMain (module_handle, reason, reserved);
1505 }
1506 #endif
1507
1508 guint
mono_gc_get_vtable_bits(MonoClass * klass)1509 mono_gc_get_vtable_bits (MonoClass *klass)
1510 {
1511 if (fin_callbacks.is_class_finalization_aware) {
1512 if (fin_callbacks.is_class_finalization_aware (klass))
1513 return BOEHM_GC_BIT_FINALIZER_AWARE;
1514 }
1515 return 0;
1516 }
1517
1518 /*
1519 * mono_gc_register_altstack:
1520 *
1521 * Register the dimensions of the normal stack and altstack with the collector.
1522 * Currently, STACK/STACK_SIZE is only used when the thread is suspended while it is on an altstack.
1523 */
1524 void
mono_gc_register_altstack(gpointer stack,gint32 stack_size,gpointer altstack,gint32 altstack_size)1525 mono_gc_register_altstack (gpointer stack, gint32 stack_size, gpointer altstack, gint32 altstack_size)
1526 {
1527 GC_register_altstack (stack, stack_size, altstack, altstack_size);
1528 }
1529
1530 int
mono_gc_get_los_limit(void)1531 mono_gc_get_los_limit (void)
1532 {
1533 return G_MAXINT;
1534 }
1535
1536 void
mono_gc_set_string_length(MonoString * str,gint32 new_length)1537 mono_gc_set_string_length (MonoString *str, gint32 new_length)
1538 {
1539 mono_unichar2 *new_end = str->chars + new_length;
1540
1541 /* zero the discarded string. This null-delimits the string and allows
1542 * the space to be reclaimed by SGen. */
1543
1544 memset (new_end, 0, (str->length - new_length + 1) * sizeof (mono_unichar2));
1545 str->length = new_length;
1546 }
1547
1548 gboolean
mono_gc_user_markers_supported(void)1549 mono_gc_user_markers_supported (void)
1550 {
1551 return FALSE;
1552 }
1553
1554 void *
mono_gc_make_root_descr_user(MonoGCRootMarkFunc marker)1555 mono_gc_make_root_descr_user (MonoGCRootMarkFunc marker)
1556 {
1557 g_assert_not_reached ();
1558 return NULL;
1559 }
1560
1561 /* Toggleref support */
1562
1563 void
mono_gc_toggleref_add(MonoObject * object,mono_bool strong_ref)1564 mono_gc_toggleref_add (MonoObject *object, mono_bool strong_ref)
1565 {
1566 if (GC_toggleref_add ((GC_PTR)object, (int)strong_ref) != GC_SUCCESS)
1567 g_error ("GC_toggleref_add failed\n");
1568 }
1569
1570 void
mono_gc_toggleref_register_callback(MonoToggleRefStatus (* proccess_toggleref)(MonoObject * obj))1571 mono_gc_toggleref_register_callback (MonoToggleRefStatus (*proccess_toggleref) (MonoObject *obj))
1572 {
1573 GC_set_toggleref_func ((GC_ToggleRefStatus (*) (GC_PTR obj)) proccess_toggleref);
1574 }
1575
1576 /* Test support code */
1577
1578 static MonoToggleRefStatus
test_toggleref_callback(MonoObject * obj)1579 test_toggleref_callback (MonoObject *obj)
1580 {
1581 static MonoClassField *mono_toggleref_test_field;
1582 MonoToggleRefStatus status = MONO_TOGGLE_REF_DROP;
1583
1584 if (!mono_toggleref_test_field) {
1585 mono_toggleref_test_field = mono_class_get_field_from_name (mono_object_get_class (obj), "__test");
1586 g_assert (mono_toggleref_test_field);
1587 }
1588
1589 mono_field_get_value (obj, mono_toggleref_test_field, &status);
1590 printf ("toggleref-cb obj %d\n", status);
1591 return status;
1592 }
1593
1594 static void
register_test_toggleref_callback(void)1595 register_test_toggleref_callback (void)
1596 {
1597 mono_gc_toggleref_register_callback (test_toggleref_callback);
1598 }
1599
1600 static gboolean
is_finalization_aware(MonoObject * obj)1601 is_finalization_aware (MonoObject *obj)
1602 {
1603 MonoVTable *vt = obj->vtable;
1604 return (vt->gc_bits & BOEHM_GC_BIT_FINALIZER_AWARE) == BOEHM_GC_BIT_FINALIZER_AWARE;
1605 }
1606
1607 static void
fin_notifier(MonoObject * obj)1608 fin_notifier (MonoObject *obj)
1609 {
1610 if (is_finalization_aware (obj))
1611 fin_callbacks.object_queued_for_finalization (obj);
1612 }
1613
1614 void
mono_gc_register_finalizer_callbacks(MonoGCFinalizerCallbacks * callbacks)1615 mono_gc_register_finalizer_callbacks (MonoGCFinalizerCallbacks *callbacks)
1616 {
1617 if (callbacks->version != MONO_GC_FINALIZER_EXTENSION_VERSION)
1618 g_error ("Invalid finalizer callback version. Expected %d but got %d\n", MONO_GC_FINALIZER_EXTENSION_VERSION, callbacks->version);
1619
1620 fin_callbacks = *callbacks;
1621
1622 GC_set_await_finalize_proc ((void (*) (GC_PTR))fin_notifier);
1623 }
1624
1625 #define BITMAP_SIZE (sizeof (*((HandleData *)NULL)->bitmap) * CHAR_BIT)
1626
1627 static inline gboolean
slot_occupied(HandleData * handles,guint slot)1628 slot_occupied (HandleData *handles, guint slot) {
1629 return handles->bitmap [slot / BITMAP_SIZE] & (1 << (slot % BITMAP_SIZE));
1630 }
1631
1632 static inline void
vacate_slot(HandleData * handles,guint slot)1633 vacate_slot (HandleData *handles, guint slot) {
1634 handles->bitmap [slot / BITMAP_SIZE] &= ~(1 << (slot % BITMAP_SIZE));
1635 }
1636
1637 static inline void
occupy_slot(HandleData * handles,guint slot)1638 occupy_slot (HandleData *handles, guint slot) {
1639 handles->bitmap [slot / BITMAP_SIZE] |= 1 << (slot % BITMAP_SIZE);
1640 }
1641
1642 static int
find_first_unset(guint32 bitmap)1643 find_first_unset (guint32 bitmap)
1644 {
1645 int i;
1646 for (i = 0; i < 32; ++i) {
1647 if (!(bitmap & (1 << i)))
1648 return i;
1649 }
1650 return -1;
1651 }
1652
1653 static void
handle_data_alloc_entries(HandleData * handles)1654 handle_data_alloc_entries (HandleData *handles)
1655 {
1656 handles->size = 32;
1657 if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
1658 handles->entries = (void **)g_malloc0 (sizeof (*handles->entries) * handles->size);
1659 handles->domain_ids = (guint16 *)g_malloc0 (sizeof (*handles->domain_ids) * handles->size);
1660 } else {
1661 handles->entries = (void **)mono_gc_alloc_fixed (sizeof (*handles->entries) * handles->size, NULL, MONO_ROOT_SOURCE_GC_HANDLE, "gc handles table");
1662 }
1663 handles->bitmap = (guint32 *)g_malloc0 (handles->size / CHAR_BIT);
1664 }
1665
1666 static gint
handle_data_next_unset(HandleData * handles)1667 handle_data_next_unset (HandleData *handles)
1668 {
1669 gint slot;
1670 for (slot = handles->slot_hint; slot < handles->size / BITMAP_SIZE; ++slot) {
1671 if (handles->bitmap [slot] == 0xffffffff)
1672 continue;
1673 handles->slot_hint = slot;
1674 return find_first_unset (handles->bitmap [slot]);
1675 }
1676 return -1;
1677 }
1678
1679 static gint
handle_data_first_unset(HandleData * handles)1680 handle_data_first_unset (HandleData *handles)
1681 {
1682 gint slot;
1683 for (slot = 0; slot < handles->slot_hint; ++slot) {
1684 if (handles->bitmap [slot] == 0xffffffff)
1685 continue;
1686 handles->slot_hint = slot;
1687 return find_first_unset (handles->bitmap [slot]);
1688 }
1689 return -1;
1690 }
1691
1692 /* Returns the index of the current slot in the bitmap. */
1693 static void
handle_data_grow(HandleData * handles,gboolean track)1694 handle_data_grow (HandleData *handles, gboolean track)
1695 {
1696 guint32 *new_bitmap;
1697 guint32 new_size = handles->size * 2; /* always double: we memset to 0 based on this below */
1698
1699 /* resize and copy the bitmap */
1700 new_bitmap = (guint32 *)g_malloc0 (new_size / CHAR_BIT);
1701 memcpy (new_bitmap, handles->bitmap, handles->size / CHAR_BIT);
1702 g_free (handles->bitmap);
1703 handles->bitmap = new_bitmap;
1704
1705 /* resize and copy the entries */
1706 if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
1707 gpointer *entries;
1708 guint16 *domain_ids;
1709 gint i;
1710 domain_ids = (guint16 *)g_malloc0 (sizeof (*handles->domain_ids) * new_size);
1711 entries = (void **)g_malloc0 (sizeof (*handles->entries) * new_size);
1712 memcpy (domain_ids, handles->domain_ids, sizeof (*handles->domain_ids) * handles->size);
1713 for (i = 0; i < handles->size; ++i) {
1714 MonoObject *obj = mono_gc_weak_link_get (&(handles->entries [i]));
1715 if (obj) {
1716 mono_gc_weak_link_add (&(entries [i]), obj, track);
1717 mono_gc_weak_link_remove (&(handles->entries [i]), track);
1718 } else {
1719 g_assert (!handles->entries [i]);
1720 }
1721 }
1722 g_free (handles->entries);
1723 g_free (handles->domain_ids);
1724 handles->entries = entries;
1725 handles->domain_ids = domain_ids;
1726 } else {
1727 gpointer *entries;
1728 entries = (void **)mono_gc_alloc_fixed (sizeof (*handles->entries) * new_size, NULL, MONO_ROOT_SOURCE_GC_HANDLE, "gc handles table");
1729 mono_gc_memmove_aligned (entries, handles->entries, sizeof (*handles->entries) * handles->size);
1730 mono_gc_free_fixed (handles->entries);
1731 handles->entries = entries;
1732 }
1733 handles->slot_hint = handles->size / BITMAP_SIZE;
1734 handles->size = new_size;
1735 }
1736
1737 static guint32
alloc_handle(HandleData * handles,MonoObject * obj,gboolean track)1738 alloc_handle (HandleData *handles, MonoObject *obj, gboolean track)
1739 {
1740 gint slot, i;
1741 guint32 res;
1742 lock_handles (handles);
1743 if (!handles->size)
1744 handle_data_alloc_entries (handles);
1745 i = handle_data_next_unset (handles);
1746 if (i == -1 && handles->slot_hint != 0)
1747 i = handle_data_first_unset (handles);
1748 if (i == -1) {
1749 handle_data_grow (handles, track);
1750 i = 0;
1751 }
1752 slot = handles->slot_hint * BITMAP_SIZE + i;
1753 occupy_slot (handles, slot);
1754 handles->entries [slot] = NULL;
1755 if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
1756 /*FIXME, what to use when obj == null?*/
1757 handles->domain_ids [slot] = (obj ? mono_object_get_domain (obj) : mono_domain_get ())->domain_id;
1758 if (obj)
1759 mono_gc_weak_link_add (&(handles->entries [slot]), obj, track);
1760 } else {
1761 handles->entries [slot] = obj;
1762 }
1763
1764 #ifndef DISABLE_PERFCOUNTERS
1765 mono_atomic_inc_i32 (&mono_perfcounters->gc_num_handles);
1766 #endif
1767 unlock_handles (handles);
1768 res = MONO_GC_HANDLE (slot, handles->type);
1769 MONO_PROFILER_RAISE (gc_handle_created, (res, handles->type, obj));
1770 return res;
1771 }
1772
1773 /**
1774 * mono_gchandle_new:
1775 * \param obj managed object to get a handle for
1776 * \param pinned whether the object should be pinned
1777 *
1778 * This returns a handle that wraps the object, this is used to keep a
1779 * reference to a managed object from the unmanaged world and preventing the
1780 * object from being disposed.
1781 *
1782 * If \p pinned is false the address of the object can not be obtained, if it is
1783 * true the address of the object can be obtained. This will also pin the
1784 * object so it will not be possible by a moving garbage collector to move the
1785 * object.
1786 *
1787 * \returns a handle that can be used to access the object from
1788 * unmanaged code.
1789 */
1790 guint32
mono_gchandle_new(MonoObject * obj,gboolean pinned)1791 mono_gchandle_new (MonoObject *obj, gboolean pinned)
1792 {
1793 return alloc_handle (&gc_handles [pinned? HANDLE_PINNED: HANDLE_NORMAL], obj, FALSE);
1794 }
1795
1796 /**
1797 * mono_gchandle_new_weakref:
1798 * \param obj managed object to get a handle for
1799 * \param track_resurrection Determines how long to track the object, if this is set to TRUE, the object is tracked after finalization, if FALSE, the object is only tracked up until the point of finalization.
1800 *
1801 * This returns a weak handle that wraps the object, this is used to
1802 * keep a reference to a managed object from the unmanaged world.
1803 * Unlike the \c mono_gchandle_new the object can be reclaimed by the
1804 * garbage collector. In this case the value of the GCHandle will be
1805 * set to zero.
1806 *
1807 * If \p track_resurrection is TRUE the object will be tracked through
1808 * finalization and if the object is resurrected during the execution
1809 * of the finalizer, then the returned weakref will continue to hold
1810 * a reference to the object. If \p track_resurrection is FALSE, then
1811 * the weak reference's target will become NULL as soon as the object
1812 * is passed on to the finalizer.
1813 *
1814 * \returns a handle that can be used to access the object from
1815 * unmanaged code.
1816 */
1817 guint32
mono_gchandle_new_weakref(MonoObject * obj,gboolean track_resurrection)1818 mono_gchandle_new_weakref (MonoObject *obj, gboolean track_resurrection)
1819 {
1820 return alloc_handle (&gc_handles [track_resurrection? HANDLE_WEAK_TRACK: HANDLE_WEAK], obj, track_resurrection);
1821 }
1822
1823 /**
1824 * mono_gchandle_get_target:
1825 * \param gchandle a GCHandle's handle.
1826 *
1827 * The handle was previously created by calling \c mono_gchandle_new or
1828 * \c mono_gchandle_new_weakref.
1829 *
1830 * \returns A pointer to the \c MonoObject* represented by the handle or
1831 * NULL for a collected object if using a weakref handle.
1832 */
1833 MonoObject*
mono_gchandle_get_target(guint32 gchandle)1834 mono_gchandle_get_target (guint32 gchandle)
1835 {
1836 guint slot = MONO_GC_HANDLE_SLOT (gchandle);
1837 guint type = MONO_GC_HANDLE_TYPE (gchandle);
1838 HandleData *handles = &gc_handles [type];
1839 MonoObject *obj = NULL;
1840 if (type >= HANDLE_TYPE_MAX)
1841 return NULL;
1842
1843 lock_handles (handles);
1844 if (slot < handles->size && slot_occupied (handles, slot)) {
1845 if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
1846 obj = mono_gc_weak_link_get (&handles->entries [slot]);
1847 } else {
1848 obj = (MonoObject *)handles->entries [slot];
1849 }
1850 } else {
1851 /* print a warning? */
1852 }
1853 unlock_handles (handles);
1854 /*g_print ("get target of entry %d of type %d: %p\n", slot, handles->type, obj);*/
1855 return obj;
1856 }
1857
1858 void
mono_gchandle_set_target(guint32 gchandle,MonoObject * obj)1859 mono_gchandle_set_target (guint32 gchandle, MonoObject *obj)
1860 {
1861 guint slot = MONO_GC_HANDLE_SLOT (gchandle);
1862 guint type = MONO_GC_HANDLE_TYPE (gchandle);
1863 HandleData *handles = &gc_handles [type];
1864 MonoObject *old_obj = NULL;
1865
1866 g_assert (type < HANDLE_TYPE_MAX);
1867 lock_handles (handles);
1868 if (slot < handles->size && slot_occupied (handles, slot)) {
1869 if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
1870 old_obj = (MonoObject *)handles->entries [slot];
1871 if (handles->entries [slot])
1872 mono_gc_weak_link_remove (&handles->entries [slot], handles->type == HANDLE_WEAK_TRACK);
1873 if (obj)
1874 mono_gc_weak_link_add (&handles->entries [slot], obj, handles->type == HANDLE_WEAK_TRACK);
1875 /*FIXME, what to use when obj == null?*/
1876 handles->domain_ids [slot] = (obj ? mono_object_get_domain (obj) : mono_domain_get ())->domain_id;
1877 } else {
1878 handles->entries [slot] = obj;
1879 }
1880 } else {
1881 /* print a warning? */
1882 }
1883 /*g_print ("changed entry %d of type %d to object %p (in slot: %p)\n", slot, handles->type, obj, handles->entries [slot]);*/
1884 unlock_handles (handles);
1885 }
1886
1887 gboolean
mono_gc_is_null(void)1888 mono_gc_is_null (void)
1889 {
1890 return FALSE;
1891 }
1892
1893 /**
1894 * mono_gchandle_is_in_domain:
1895 * \param gchandle a GCHandle's handle.
1896 * \param domain An application domain.
1897 *
1898 * Use this function to determine if the \p gchandle points to an
1899 * object allocated in the specified \p domain.
1900 *
1901 * \returns TRUE if the object wrapped by the \p gchandle belongs to the specific \p domain.
1902 */
1903 gboolean
mono_gchandle_is_in_domain(guint32 gchandle,MonoDomain * domain)1904 mono_gchandle_is_in_domain (guint32 gchandle, MonoDomain *domain)
1905 {
1906 guint slot = MONO_GC_HANDLE_SLOT (gchandle);
1907 guint type = MONO_GC_HANDLE_TYPE (gchandle);
1908 HandleData *handles = &gc_handles [type];
1909 gboolean result = FALSE;
1910
1911 if (type >= HANDLE_TYPE_MAX)
1912 return FALSE;
1913
1914 lock_handles (handles);
1915 if (slot < handles->size && slot_occupied (handles, slot)) {
1916 if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
1917 result = domain->domain_id == handles->domain_ids [slot];
1918 } else {
1919 MonoObject *obj;
1920 obj = (MonoObject *)handles->entries [slot];
1921 if (obj == NULL)
1922 result = TRUE;
1923 else
1924 result = domain == mono_object_domain (obj);
1925 }
1926 } else {
1927 /* print a warning? */
1928 }
1929 unlock_handles (handles);
1930 return result;
1931 }
1932
1933 /**
1934 * mono_gchandle_free:
1935 * \param gchandle a GCHandle's handle.
1936 *
1937 * Frees the \p gchandle handle. If there are no outstanding
1938 * references, the garbage collector can reclaim the memory of the
1939 * object wrapped.
1940 */
1941 void
mono_gchandle_free(guint32 gchandle)1942 mono_gchandle_free (guint32 gchandle)
1943 {
1944 guint slot = MONO_GC_HANDLE_SLOT (gchandle);
1945 guint type = MONO_GC_HANDLE_TYPE (gchandle);
1946 HandleData *handles = &gc_handles [type];
1947 if (type >= HANDLE_TYPE_MAX)
1948 return;
1949
1950 lock_handles (handles);
1951 if (slot < handles->size && slot_occupied (handles, slot)) {
1952 if (MONO_GC_HANDLE_TYPE_IS_WEAK (handles->type)) {
1953 if (handles->entries [slot])
1954 mono_gc_weak_link_remove (&handles->entries [slot], handles->type == HANDLE_WEAK_TRACK);
1955 } else {
1956 handles->entries [slot] = NULL;
1957 }
1958 vacate_slot (handles, slot);
1959 } else {
1960 /* print a warning? */
1961 }
1962 #ifndef DISABLE_PERFCOUNTERS
1963 mono_atomic_dec_i32 (&mono_perfcounters->gc_num_handles);
1964 #endif
1965 /*g_print ("freed entry %d of type %d\n", slot, handles->type);*/
1966 unlock_handles (handles);
1967 MONO_PROFILER_RAISE (gc_handle_deleted, (gchandle, handles->type));
1968 }
1969
1970 /**
1971 * mono_gchandle_free_domain:
1972 * \param domain domain that is unloading
1973 *
1974 * Function used internally to cleanup any GC handle for objects belonging
1975 * to the specified domain during appdomain unload.
1976 */
1977 void
mono_gchandle_free_domain(MonoDomain * domain)1978 mono_gchandle_free_domain (MonoDomain *domain)
1979 {
1980 guint type;
1981
1982 for (type = HANDLE_TYPE_MIN; type < HANDLE_PINNED; ++type) {
1983 guint slot;
1984 HandleData *handles = &gc_handles [type];
1985 lock_handles (handles);
1986 for (slot = 0; slot < handles->size; ++slot) {
1987 if (!slot_occupied (handles, slot))
1988 continue;
1989 if (MONO_GC_HANDLE_TYPE_IS_WEAK (type)) {
1990 if (domain->domain_id == handles->domain_ids [slot]) {
1991 vacate_slot (handles, slot);
1992 if (handles->entries [slot])
1993 mono_gc_weak_link_remove (&handles->entries [slot], handles->type == HANDLE_WEAK_TRACK);
1994 }
1995 } else {
1996 if (handles->entries [slot] && mono_object_domain (handles->entries [slot]) == domain) {
1997 vacate_slot (handles, slot);
1998 handles->entries [slot] = NULL;
1999 }
2000 }
2001 }
2002 unlock_handles (handles);
2003 }
2004
2005 }
2006
2007 void
mono_gc_register_obj_with_weak_fields(void * obj)2008 mono_gc_register_obj_with_weak_fields (void *obj)
2009 {
2010 g_error ("Weak fields not supported by boehm gc");
2011 }
2012
2013 #else
2014
2015 MONO_EMPTY_SOURCE_FILE (boehm_gc);
2016 #endif /* no Boehm GC */
2017