X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fboehm-gc.c;h=d7387ec7ba1e51531f85c4a2858865828ec111b2;hb=05c7cd052d0a1c3676414a119c1fa946daa5fc2d;hp=39d0f68413150090af608e084300dda4ec63d4c1;hpb=e2d1249a9729a2a0702086b41ec1491280680e42;p=mono.git diff --git a/mono/metadata/boehm-gc.c b/mono/metadata/boehm-gc.c index 39d0f684131..d7387ec7ba1 100644 --- a/mono/metadata/boehm-gc.c +++ b/mono/metadata/boehm-gc.c @@ -2,10 +2,14 @@ * boehm-gc.c: GC implementation using either the installed or included Boehm GC. * * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com) - * Copyright 2004-2009 Novell, Inc (http://www.novell.com) + * Copyright 2004-2011 Novell, Inc (http://www.novell.com) + * Copyright 2011 Xamarin, Inc (http://www.xamarin.com) */ #include "config.h" + +#include + #define GC_I_HIDE_POINTERS #include #include @@ -16,9 +20,13 @@ #include #include #include -#include +#include +#include +#include #include +#include #include +#include #if HAVE_BOEHM_GC @@ -30,9 +38,15 @@ #endif #define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH)) +/*Boehm max heap cannot be smaller than 16MB*/ +#define MIN_BOEHM_MAX_HEAP_SIZE_IN_MB 16 +#define MIN_BOEHM_MAX_HEAP_SIZE (MIN_BOEHM_MAX_HEAP_SIZE_IN_MB << 20) static gboolean gc_initialized = FALSE; +static void* +boehm_thread_register (MonoThreadInfo* info, void *baseptr); + static void mono_gc_warning (char *msg, GC_word arg) { @@ -42,6 +56,9 @@ mono_gc_warning (char *msg, GC_word arg) void mono_gc_base_init (void) { + MonoThreadInfoCallbacks cb; + char *env; + if (gc_initialized) return; @@ -84,6 +101,19 @@ mono_gc_base_init (void) } #elif defined(HAVE_PTHREAD_GET_STACKSIZE_NP) && defined(HAVE_PTHREAD_GET_STACKADDR_NP) GC_stackbottom = (char*)pthread_get_stackaddr_np (pthread_self ()); +#elif defined(__OpenBSD__) +# include + { + stack_t ss; + int rslt; + + rslt = pthread_stackseg_np(pthread_self(), &ss); + g_assert (rslt == 0); + + GC_stackbottom = (char*)ss.ss_sp; + } +#elif defined(__native_client__) + /* Do nothing, GC_stackbottom is set correctly in libgc */ #else { int dummy; @@ -95,7 +125,10 @@ mono_gc_base_init (void) } #endif +#if !defined(PLATFORM_ANDROID) + /* If GC_no_dls is set to true, GC_find_limit is not called. This causes a seg fault on Android. */ GC_no_dls = TRUE; +#endif GC_init (); GC_oom_fn = mono_gc_out_of_memory; GC_set_warn_proc (mono_gc_warning); @@ -105,10 +138,64 @@ mono_gc_base_init (void) #ifdef HAVE_GC_GCJ_MALLOC GC_init_gcj_malloc (5, NULL); #endif + +#ifdef HAVE_GC_ALLOW_REGISTER_THREADS + GC_allow_register_threads(); +#endif + + if ((env = getenv ("MONO_GC_PARAMS"))) { + char **ptr, **opts = g_strsplit (env, ",", -1); + for (ptr = opts; *ptr; ++ptr) { + char *opt = *ptr; + if (g_str_has_prefix (opt, "max-heap-size=")) { + glong max_heap; + + opt = strchr (opt, '=') + 1; + if (*opt && mono_gc_parse_environment_string_extract_number (opt, &max_heap)) { + if (max_heap < MIN_BOEHM_MAX_HEAP_SIZE) { + fprintf (stderr, "max-heap-size must be at least %dMb.\n", MIN_BOEHM_MAX_HEAP_SIZE_IN_MB); + exit (1); + } + GC_set_max_heap_size (max_heap); + } else { + fprintf (stderr, "max-heap-size must be an integer.\n"); + exit (1); + } + continue; + } else { + fprintf (stderr, "MONO_GC_PARAMS must be a comma-delimited list of one or more of the following:\n"); + fprintf (stderr, " max-heap-size=N (where N is an integer, possibly with a k, m or a g suffix)\n"); + exit (1); + } + } + g_strfreev (opts); + } + + memset (&cb, 0, sizeof (cb)); + cb.thread_register = boehm_thread_register; + cb.mono_method_is_critical = (gpointer)mono_runtime_is_critical_method; +#ifndef HOST_WIN32 + cb.mono_gc_pthread_create = (gpointer)mono_gc_pthread_create; +#endif + + mono_threads_init (&cb, sizeof (MonoThreadInfo)); + mono_gc_enable_events (); gc_initialized = TRUE; } +/** + * mono_gc_collect: + * @generation: GC generation identifier + * + * Perform a garbage collection for the given generation, higher numbers + * mean usually older objects. Collecting a high-numbered generation + * implies collecting also the lower-numbered generations. + * The maximum value for @generation can be retrieved with a call to + * mono_gc_max_generation(), so this function is usually called as: + * + * mono_gc_collect (mono_gc_max_generation ()); + */ void mono_gc_collect (int generation) { @@ -126,36 +213,88 @@ mono_gc_collect (int generation) #endif } +/** + * mono_gc_max_generation: + * + * Get the maximum generation number used by the current garbage + * collector. The value will be 0 for the Boehm collector, 1 or more + * for the generational collectors. + * + * Returns: the maximum generation number. + */ int mono_gc_max_generation (void) { return 0; } +/** + * mono_gc_get_generation: + * @object: a managed object + * + * Get the garbage collector's generation that @object belongs to. + * Use this has a hint only. + * + * Returns: a garbage collector generation number + */ int mono_gc_get_generation (MonoObject *object) { return 0; } +/** + * mono_gc_collection_count: + * @generation: a GC generation number + * + * Get how many times a garbage collection has been performed + * for the given @generation number. + * + * Returns: the number of garbage collections + */ int mono_gc_collection_count (int generation) { return GC_gc_no; } +/** + * mono_gc_add_memory_pressure: + * @value: amount of bytes + * + * Adjust the garbage collector's view of how many bytes of memory + * are indirectly referenced by managed objects (for example unmanaged + * memory holding image or other binary data). + * This is a hint only to the garbage collector algorithm. + * Note that negative amounts of @value will decrease the memory + * pressure. + */ void mono_gc_add_memory_pressure (gint64 value) { } -gint64 +/** + * mono_gc_get_used_size: + * + * Get the approximate amount of memory used by managed objects. + * + * Returns: the amount of memory used in bytes + */ +int64_t mono_gc_get_used_size (void) { return GC_get_heap_size () - GC_get_free_bytes (); } -gint64 +/** + * mono_gc_get_heap_size: + * + * Get the amount of memory used by the garbage collector. + * + * Returns: the size of the heap in bytes + */ +int64_t mono_gc_get_heap_size (void) { return GC_get_heap_size (); @@ -197,6 +336,12 @@ extern int GC_thread_register_foreign (void *base_addr); gboolean mono_gc_register_thread (void *baseptr) +{ + return mono_thread_info_attach (baseptr) != NULL; +} + +static void* +boehm_thread_register (MonoThreadInfo* info, void *baseptr) { #if GC_VERSION_MAJOR >= 7 struct GC_stack_base sb; @@ -213,16 +358,16 @@ mono_gc_register_thread (void *baseptr) res = GC_register_my_thread (&sb); if ((res != GC_SUCCESS) && (res != GC_DUPLICATE)) { g_warning ("GC_register_my_thread () failed.\n"); - return FALSE; + return NULL; } - return TRUE; + return info; #else if (mono_gc_is_gc_thread()) - return TRUE; -#if defined(USE_INCLUDED_LIBGC) && !defined(PLATFORM_WIN32) - return GC_thread_register_foreign (baseptr); + return info; +#if defined(USE_INCLUDED_LIBGC) && !defined(HOST_WIN32) + return GC_thread_register_foreign (baseptr) ? info : NULL; #else - return FALSE; + return NULL; #endif #endif } @@ -237,6 +382,12 @@ mono_object_is_alive (MonoObject* o) #endif } +int +mono_gc_walk_heap (int flags, MonoGCReferences callback, void *data) +{ + return 1; +} + #ifdef USE_INCLUDED_LIBGC static gint64 gc_start_time; @@ -244,30 +395,42 @@ static gint64 gc_start_time; static void on_gc_notification (GCEventType event) { - if (event == MONO_GC_EVENT_START) { - mono_perfcounters->gc_collections0++; + MonoGCEvent e = (MonoGCEvent)event; + + if (e == MONO_GC_EVENT_PRE_STOP_WORLD) + mono_thread_info_suspend_lock (); + else if (e == MONO_GC_EVENT_POST_START_WORLD) + mono_thread_info_suspend_unlock (); + + if (e == MONO_GC_EVENT_START) { + if (mono_perfcounters) + mono_perfcounters->gc_collections0++; mono_stats.major_gc_count ++; gc_start_time = mono_100ns_ticks (); - } else if (event == MONO_GC_EVENT_END) { - guint64 heap_size = GC_get_heap_size (); - guint64 used_size = heap_size - GC_get_free_bytes (); - mono_perfcounters->gc_total_bytes = used_size; - mono_perfcounters->gc_committed_bytes = heap_size; - mono_perfcounters->gc_reserved_bytes = heap_size; - mono_perfcounters->gc_gen0size = heap_size; + } else if (e == MONO_GC_EVENT_END) { + if (mono_perfcounters) { + guint64 heap_size = GC_get_heap_size (); + guint64 used_size = heap_size - GC_get_free_bytes (); + mono_perfcounters->gc_total_bytes = used_size; + mono_perfcounters->gc_committed_bytes = heap_size; + mono_perfcounters->gc_reserved_bytes = heap_size; + mono_perfcounters->gc_gen0size = heap_size; + } mono_stats.major_gc_time_usecs += (mono_100ns_ticks () - gc_start_time) / 10; mono_trace_message (MONO_TRACE_GC, "gc took %d usecs", (mono_100ns_ticks () - gc_start_time) / 10); } - mono_profiler_gc_event ((MonoGCEvent) event, 0); + mono_profiler_gc_event (e, 0); } static void on_gc_heap_resize (size_t new_size) { guint64 heap_size = GC_get_heap_size (); - mono_perfcounters->gc_committed_bytes = heap_size; - mono_perfcounters->gc_reserved_bytes = heap_size; - mono_perfcounters->gc_gen0size = heap_size; + if (mono_perfcounters) { + mono_perfcounters->gc_committed_bytes = heap_size; + mono_perfcounters->gc_reserved_bytes = heap_size; + mono_perfcounters->gc_gen0size = heap_size; + } mono_profiler_gc_heap_resize (new_size); } @@ -299,7 +462,7 @@ mono_gc_register_root (char *start, size_t size, void *descr) void mono_gc_deregister_root (char* addr) { -#ifndef PLATFORM_WIN32 +#ifndef HOST_WIN32 /* FIXME: libgc doesn't define this work win32 for some reason */ /* FIXME: No size info */ GC_remove_roots (addr, addr + sizeof (gpointer) + 1); @@ -321,10 +484,17 @@ mono_gc_weak_link_remove (void **link_addr) *link_addr = NULL; } +static gpointer +reveal_link (gpointer link_addr) +{ + void **link_a = link_addr; + return REVEAL_POINTER (*link_a); +} + MonoObject* mono_gc_weak_link_get (void **link_addr) { - MonoObject *obj = REVEAL_POINTER (*link_addr); + MonoObject *obj = GC_call_with_alloc_lock (reveal_link, link_addr); if (obj == (MonoObject *) -1) return NULL; return obj; @@ -363,6 +533,12 @@ mono_gc_make_descr_from_bitmap (gsize *bitmap, int numbits) #endif } +void* +mono_gc_make_root_descr_all_refs (int numbits) +{ + return NULL; +} + void* mono_gc_alloc_fixed (size_t size, void *descr) { @@ -425,7 +601,12 @@ add_weak_track_handle_internal (MonoDomain *domain, MonoObject *obj, guint32 gch void mono_gc_add_weak_track_handle (MonoObject *obj, guint32 handle) { - MonoDomain *domain = mono_domain_get (); + MonoDomain *domain; + + if (!obj) + return; + + domain = mono_object_get_domain (obj); mono_domain_finalizers_lock (domain); @@ -520,9 +701,9 @@ mono_gc_wbarrier_set_arrayref (MonoArray *arr, gpointer slot_ptr, MonoObject* va } void -mono_gc_wbarrier_arrayref_copy (MonoArray *arr, gpointer slot_ptr, int count) +mono_gc_wbarrier_arrayref_copy (gpointer dest_ptr, gpointer src_ptr, int count) { - /* no need to do anything */ + mono_gc_memmove (dest_ptr, src_ptr, count * sizeof (gpointer)); } void @@ -539,11 +720,15 @@ mono_gc_wbarrier_generic_nostore (gpointer ptr) void mono_gc_wbarrier_value_copy (gpointer dest, gpointer src, int count, MonoClass *klass) { + mono_gc_memmove (dest, src, count * mono_class_value_size (klass, NULL)); } void -mono_gc_wbarrier_object (MonoObject *object) +mono_gc_wbarrier_object_copy (MonoObject* obj, MonoObject *src) { + /* do not copy the sync state */ + mono_gc_memmove ((char*)obj + sizeof (MonoObject), (char*)src + sizeof (MonoObject), + mono_object_class (obj)->instance_size - sizeof (MonoObject)); } void @@ -551,6 +736,16 @@ mono_gc_clear_domain (MonoDomain *domain) { } +int +mono_gc_get_suspend_signal (void) +{ +#ifdef USE_INCLUDED_GC + return GC_get_suspend_signal (); +#else + return -1; +#endif +} + #if defined(USE_INCLUDED_LIBGC) && defined(USE_COMPILER_TLS) && defined(__linux__) && (defined(__i386__) || defined(__x86_64__)) extern __thread MONO_TLS_FAST void* GC_thread_tls; #include "metadata-internals.h" @@ -582,6 +777,7 @@ create_allocator (int atype, int offset) MonoMethodBuilder *mb; MonoMethod *res; MonoMethodSignature *csig; + AllocatorWrapperInfo *info; if (atype == ATYPE_STRING) { csig = mono_metadata_signature_alloc (mono_defaults.corlib, 2); @@ -769,11 +965,29 @@ create_allocator (int atype, int offset) res = mono_mb_create_method (mb, csig, 8); mono_mb_free (mb); mono_method_get_header (res)->init_locals = FALSE; + + info = mono_image_alloc0 (mono_defaults.corlib, sizeof (AllocatorWrapperInfo)); + info->gc_name = "boehm"; + info->alloc_type = atype; + mono_marshal_set_wrapper_info (res, info); + return res; } static MonoMethod* alloc_method_cache [ATYPE_NUM]; +static G_GNUC_UNUSED gboolean +mono_gc_is_critical_method (MonoMethod *method) +{ + int i; + + for (i = 0; i < ATYPE_NUM; ++i) + if (method == alloc_method_cache [i]) + return TRUE; + + return FALSE; +} + /* * If possible, generate a managed method that can quickly allocate objects in class * @klass. The method will typically have an thread-local inline allocation sequence. @@ -797,7 +1011,7 @@ mono_gc_get_managed_allocator (MonoVTable *vtable, gboolean for_box) return NULL; if (!SMALL_ENOUGH (klass->instance_size)) return NULL; - if (klass->has_finalize || klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS)) + if (mono_class_has_finalizer (klass) || klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS)) return NULL; if (klass->rank) return NULL; @@ -822,28 +1036,10 @@ mono_gc_get_managed_allocator (MonoVTable *vtable, gboolean for_box) return mono_gc_get_managed_allocator_by_type (atype); } -/** - * mono_gc_get_managed_allocator_id: - * - * Return a type for the managed allocator method MANAGED_ALLOC which can later be passed - * to mono_gc_get_managed_allocator_by_type () to get back this allocator method. This can be - * used by the AOT code to encode references to managed allocator methods. - */ -int -mono_gc_get_managed_allocator_type (MonoMethod *managed_alloc) +MonoMethod* +mono_gc_get_managed_array_allocator (MonoVTable *vtable, int rank) { - int i; - - mono_loader_lock (); - for (i = 0; i < ATYPE_NUM; ++i) { - if (alloc_method_cache [i] == managed_alloc) { - mono_loader_unlock (); - return i; - } - } - mono_loader_unlock (); - - return -1; + return NULL; } /** @@ -872,18 +1068,31 @@ mono_gc_get_managed_allocator_types (void) return ATYPE_NUM; } +MonoMethod* +mono_gc_get_write_barrier (void) +{ + g_assert_not_reached (); + return NULL; +} + #else +static G_GNUC_UNUSED gboolean +mono_gc_is_critical_method (MonoMethod *method) +{ + return FALSE; +} + MonoMethod* mono_gc_get_managed_allocator (MonoVTable *vtable, gboolean for_box) { return NULL; } -int -mono_gc_get_managed_allocator_type (MonoMethod *managed_alloc) +MonoMethod* +mono_gc_get_managed_array_allocator (MonoVTable *vtable, int rank) { - return -1; + return NULL; } MonoMethod* @@ -898,7 +1107,157 @@ mono_gc_get_managed_allocator_types (void) return 0; } +MonoMethod* +mono_gc_get_write_barrier (void) +{ + g_assert_not_reached (); + return NULL; +} + #endif -#endif /* no Boehm GC */ +const char * +mono_gc_get_gc_name (void) +{ + return "boehm"; +} +void* +mono_gc_invoke_with_gc_lock (MonoGCLockedCallbackFunc func, void *data) +{ + return GC_call_with_alloc_lock (func, data); +} + +char* +mono_gc_get_description (void) +{ + return g_strdup (DEFAULT_GC_NAME); +} + +void +mono_gc_set_desktop_mode (void) +{ + GC_dont_expand = 1; +} + +gboolean +mono_gc_is_moving (void) +{ + return FALSE; +} + +gboolean +mono_gc_is_disabled (void) +{ + if (GC_dont_gc || g_getenv ("GC_DONT_GC")) + return TRUE; + else + return FALSE; +} + +void +mono_gc_wbarrier_value_copy_bitmap (gpointer _dest, gpointer _src, int size, unsigned bitmap) +{ + g_assert_not_reached (); +} + + +guint8* +mono_gc_get_card_table (int *shift_bits, gpointer *card_mask) +{ + g_assert_not_reached (); + return NULL; +} + +void* +mono_gc_get_nursery (int *shift_bits, size_t *size) +{ + return NULL; +} + +void +mono_gc_set_current_thread_appdomain (MonoDomain *domain) +{ +} + +gboolean +mono_gc_precise_stack_mark_enabled (void) +{ + return FALSE; +} + +FILE * +mono_gc_get_logfile (void) +{ + return NULL; +} + +void +mono_gc_conservatively_scan_area (void *start, void *end) +{ + g_assert_not_reached (); +} + +void * +mono_gc_scan_object (void *obj) +{ + g_assert_not_reached (); + return NULL; +} + +gsize* +mono_gc_get_bitmap_for_descr (void *descr, int *numbits) +{ + g_assert_not_reached (); + return NULL; +} + +void +mono_gc_set_gc_callbacks (MonoGCCallbacks *callbacks) +{ +} + +/* + * These will call the redefined versions in libgc. + */ + +#ifndef HOST_WIN32 + +int +mono_gc_pthread_create (pthread_t *new_thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg) +{ + return pthread_create (new_thread, attr, start_routine, arg); +} + +int +mono_gc_pthread_join (pthread_t thread, void **retval) +{ + return pthread_join (thread, retval); +} + +int +mono_gc_pthread_detach (pthread_t thread) +{ + return pthread_detach (thread); +} + +void +mono_gc_pthread_exit (void *retval) +{ + pthread_exit (retval); +} + +#endif + +#ifdef HOST_WIN32 +BOOL APIENTRY mono_gc_dllmain (HMODULE module_handle, DWORD reason, LPVOID reserved) +{ +#ifdef USE_INCLUDED_LIBGC + return GC_DllMain (module_handle, reason, reserved); +#else + return TRUE; +#endif +} +#endif + +#endif /* no Boehm GC */