#define GC_I_HIDE_POINTERS
#include <mono/metadata/gc-internal.h>
#include <mono/metadata/mono-gc.h>
-#include <mono/metadata/gc-internal.h>
#include <mono/metadata/profiler-private.h>
#include <mono/metadata/class-internals.h>
#include <mono/metadata/method-builder.h>
#include <mono/metadata/metadata-internals.h>
#include <mono/metadata/marshal.h>
#include <mono/metadata/runtime.h>
+#include <mono/utils/atomic.h>
#include <mono/utils/mono-logger-internal.h>
+#include <mono/utils/mono-memory-model.h>
#include <mono/utils/mono-time.h>
#include <mono/utils/mono-threads.h>
#include <mono/utils/dtrace.h>
#include <mono/utils/gc_wrapper.h>
+#include <mono/utils/mono-mutex.h>
#if HAVE_BOEHM_GC
#define MIN_BOEHM_MAX_HEAP_SIZE (MIN_BOEHM_MAX_HEAP_SIZE_IN_MB << 20)
static gboolean gc_initialized = FALSE;
+static mono_mutex_t mono_gc_lock;
static void*
boehm_thread_register (MonoThreadInfo* info, void *baseptr);
+static void
+boehm_thread_unregister (MonoThreadInfo *p);
static void
mono_gc_warning (char *msg, GC_word arg)
mono_gc_base_init (void)
{
MonoThreadInfoCallbacks cb;
- char *env;
+ const char *env;
+ int dummy;
if (gc_initialized)
return;
* we used to do this only when running on valgrind,
* but it happens also in other setups.
*/
-#if defined(HAVE_PTHREAD_GETATTR_NP) && defined(HAVE_PTHREAD_ATTR_GETSTACK)
+#if defined(HAVE_PTHREAD_GETATTR_NP) && defined(HAVE_PTHREAD_ATTR_GETSTACK) && !defined(__native_client__)
{
size_t size;
void *sstart;
GC_allow_register_threads();
#endif
- if ((env = getenv ("MONO_GC_PARAMS"))) {
+ if ((env = g_getenv ("MONO_GC_PARAMS"))) {
char **ptr, **opts = g_strsplit (env, ",", -1);
for (ptr = opts; *ptr; ++ptr) {
char *opt = *ptr;
memset (&cb, 0, sizeof (cb));
cb.thread_register = boehm_thread_register;
+ cb.thread_unregister = boehm_thread_unregister;
cb.mono_method_is_critical = (gpointer)mono_runtime_is_critical_method;
#ifndef HOST_WIN32
+ cb.thread_exit = mono_gc_pthread_exit;
cb.mono_gc_pthread_create = (gpointer)mono_gc_pthread_create;
#endif
mono_threads_init (&cb, sizeof (MonoThreadInfo));
+ mono_mutex_init (&mono_gc_lock);
+
+ mono_thread_info_attach (&dummy);
mono_gc_enable_events ();
gc_initialized = TRUE;
#endif
}
+static void
+boehm_thread_unregister (MonoThreadInfo *p)
+{
+ MonoNativeThreadId tid;
+
+ tid = mono_thread_info_get_tid (p);
+
+ mono_threads_add_joinable_thread ((gpointer)tid);
+}
+
gboolean
mono_object_is_alive (MonoObject* o)
{
/*
static int count;
count ++;
- if (count == atoi (getenv ("COUNT2")))
+ if (count == atoi (g_getenv ("COUNT2")))
printf ("HIT!\n");
- if (count > atoi (getenv ("COUNT2")))
+ if (count > atoi (g_getenv ("COUNT2")))
return GC_MALLOC (size);
*/
*(void**)ptr = value;
}
+void
+mono_gc_wbarrier_generic_store_atomic (gpointer ptr, MonoObject *value)
+{
+ InterlockedWritePointer (ptr, value);
+}
+
void
mono_gc_wbarrier_generic_nostore (gpointer ptr)
{
};
static MonoMethod*
-create_allocator (int atype, int offset)
+create_allocator (int atype, int tls_key)
{
int index_var, bytes_var, my_fl_var, my_entry_var;
guint32 no_freelist_branch, not_small_enough_branch = 0;
/* my_fl = ((GC_thread)tsd) -> ptrfree_freelists + index; */
mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
mono_mb_emit_byte (mb, 0x0D); /* CEE_MONO_TLS */
- mono_mb_emit_i4 (mb, offset);
+ mono_mb_emit_i4 (mb, tls_key);
if (atype == ATYPE_FREEPTR || atype == ATYPE_FREEPTR_FOR_BOX || atype == ATYPE_STRING)
mono_mb_emit_icon (mb, G_STRUCT_OFFSET (struct GC_Thread_Rep, ptrfree_freelists));
else if (atype == ATYPE_NORMAL)
*/
MonoMethod*
-mono_gc_get_managed_allocator (MonoVTable *vtable, gboolean for_box)
+mono_gc_get_managed_allocator (MonoClass *klass, gboolean for_box)
{
int offset = -1;
int atype;
- MonoClass *klass = vtable->klass;
MONO_THREAD_VAR_OFFSET (GC_thread_tls, offset);
/*g_print ("thread tls: %d\n", offset);*/
return NULL;
if (!SMALL_ENOUGH (klass->instance_size))
return NULL;
- if (mono_class_has_finalizer (klass) || klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
+ if (mono_class_has_finalizer (klass) || mono_class_is_marshalbyref (klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
return NULL;
if (klass->rank)
return NULL;
+ if (mono_class_is_open_constructed_type (&klass->byval_arg))
+ return NULL;
if (klass->byval_arg.type == MONO_TYPE_STRING) {
atype = ATYPE_STRING;
} else if (!klass->has_references) {
MonoMethod *res;
MONO_THREAD_VAR_OFFSET (GC_thread_tls, offset);
- mono_loader_lock ();
+ mono_tls_key_set_offset (TLS_KEY_BOEHM_GC_THREAD, offset);
+
res = alloc_method_cache [atype];
- if (!res)
- res = alloc_method_cache [atype] = create_allocator (atype, offset);
- mono_loader_unlock ();
+ if (res)
+ return res;
+
+ res = create_allocator (atype, TLS_KEY_BOEHM_GC_THREAD);
+ mono_mutex_lock (&mono_gc_lock);
+ if (alloc_method_cache [atype]) {
+ mono_free_method (res);
+ res = alloc_method_cache [atype];
+ } else {
+ mono_memory_barrier ();
+ alloc_method_cache [atype] = res;
+ }
+ mono_mutex_unlock (&mono_gc_lock);
return res;
}
}
MonoMethod*
-mono_gc_get_managed_allocator (MonoVTable *vtable, gboolean for_box)
+mono_gc_get_managed_allocator (MonoClass *klass, gboolean for_box)
{
return NULL;
}
{
}
+void
+mono_gc_register_for_finalization (MonoObject *obj, void *user_data)
+{
+ guint offset = 0;
+
+#ifndef GC_DEBUG
+ /* This assertion is not valid when GC_DEBUG is defined */
+ g_assert (GC_base (obj) == (char*)obj - offset);
+#endif
+
+ GC_REGISTER_FINALIZER_NO_ORDER ((char*)obj - offset, user_data, GUINT_TO_POINTER (offset), NULL, NULL);
+}
+
/*
* These will call the redefined versions in libgc.
*/