#include "config.h"
#ifdef HAVE_SGEN_GC
-#include "metadata/sgen-gc.h"
-#include "metadata/sgen-protocol.h"
+#include "sgen/sgen-gc.h"
+#include "sgen/sgen-protocol.h"
#include "metadata/monitor.h"
-#include "metadata/sgen-layout-stats.h"
-#include "metadata/sgen-client.h"
-#include "metadata/sgen-cardtable.h"
-#include "metadata/sgen-pinning.h"
+#include "sgen/sgen-layout-stats.h"
+#include "sgen/sgen-client.h"
+#include "sgen/sgen-cardtable.h"
+#include "sgen/sgen-pinning.h"
#include "metadata/marshal.h"
#include "metadata/method-builder.h"
#include "metadata/abi-details.h"
#include "utils/mono-memory-model.h"
#include "utils/mono-logger-internal.h"
+#ifdef HEAVY_STATISTICS
+static guint64 stat_wbarrier_set_arrayref = 0;
+static guint64 stat_wbarrier_value_copy = 0;
+static guint64 stat_wbarrier_object_copy = 0;
+
+static guint64 los_marked_cards;
+static guint64 los_array_cards;
+static guint64 los_array_remsets;
+#endif
+
/* If set, mark stacks conservatively, even if precise marking is possible */
static gboolean conservative_stack_mark = FALSE;
/* If set, check that there are no references to the domain left at domain unload */
scan_object_for_binary_protocol_copy_wbarrier (gpointer dest, char *start, mword desc)
{
#define SCAN_OBJECT_NOVTABLE
-#include "sgen-scan-object.h"
+#include "sgen/sgen-scan-object.h"
}
#endif
HEAVY_STAT (++stat_wbarrier_object_copy);
- if (sgen_ptr_in_nursery (obj) || ptr_on_stack (obj)) {
+ if (sgen_ptr_in_nursery (obj) || ptr_on_stack (obj) || !SGEN_OBJECT_HAS_REFERENCES (src)) {
size = mono_object_class (obj)->instance_size;
mono_gc_memmove_aligned ((char*)obj + sizeof (MonoObject), (char*)src + sizeof (MonoObject),
size - sizeof (MonoObject));
if (!key || key == tombstone)
continue;
- SGEN_LOG (5, "[%td] key %p (%s) value %p (%s)", cur - mono_array_addr (array, Ephemeron, 0),
+ SGEN_LOG (5, "[%zd] key %p (%s) value %p (%s)", cur - mono_array_addr (array, Ephemeron, 0),
key, sgen_is_object_alive_for_current_gen (key) ? "reachable" : "unreachable",
cur->value, cur->value && sgen_is_object_alive_for_current_gen (cur->value) ? "reachable" : "unreachable");
if (!key || key == tombstone)
continue;
- SGEN_LOG (5, "[%td] key %p (%s) value %p (%s)", cur - mono_array_addr (array, Ephemeron, 0),
+ SGEN_LOG (5, "[%zd] key %p (%s) value %p (%s)", cur - mono_array_addr (array, Ephemeron, 0),
key, sgen_is_object_alive_for_current_gen (key) ? "reachable" : "unreachable",
cur->value, cur->value && sgen_is_object_alive_for_current_gen (cur->value) ? "reachable" : "unreachable");
* Allocation
*/
+static gboolean alloc_events = FALSE;
+
+void
+mono_gc_enable_alloc_events (void)
+{
+ alloc_events = TRUE;
+}
+
void*
mono_gc_alloc_obj (MonoVTable *vtable, size_t size)
{
- return sgen_alloc_obj (vtable, size);
+ MonoObject *obj = sgen_alloc_obj (vtable, size);
+
+ if (G_UNLIKELY (alloc_events))
+ mono_profiler_allocation (obj);
+
+ return obj;
}
void*
mono_gc_alloc_pinned_obj (MonoVTable *vtable, size_t size)
{
- return sgen_alloc_obj_pinned (vtable, size);
+ MonoObject *obj = sgen_alloc_obj_pinned (vtable, size);
+
+ if (G_UNLIKELY (alloc_events))
+ mono_profiler_allocation (obj);
+
+ return obj;
}
void*
mono_gc_alloc_mature (MonoVTable *vtable)
{
MonoObject *obj = sgen_alloc_obj_mature (vtable, vtable->klass->instance_size);
+
if (obj && G_UNLIKELY (obj->vtable->klass->has_finalize))
mono_object_register_finalizer (obj);
+
+ if (G_UNLIKELY (alloc_events))
+ mono_profiler_allocation (obj);
+
return obj;
}
*/
static MonoMethod* alloc_method_cache [ATYPE_NUM];
+static MonoMethod* slowpath_alloc_method_cache [ATYPE_NUM];
static gboolean use_managed_allocator = TRUE;
#ifdef MANAGED_ALLOCATION
* that they are executed atomically via the restart mechanism.
*/
static MonoMethod*
-create_allocator (int atype)
+create_allocator (int atype, gboolean slowpath)
{
int p_var, size_var;
guint32 slowpath_branch, max_size_branch;
MonoMethodSignature *csig;
static gboolean registered = FALSE;
int tlab_next_addr_var, new_next_var;
- int num_params, i;
const char *name = NULL;
AllocatorWrapperInfo *info;
+ int num_params, i;
if (!registered) {
mono_register_jit_icall (mono_gc_alloc_obj, "mono_gc_alloc_obj", mono_create_icall_signature ("object ptr int"), FALSE);
}
if (atype == ATYPE_SMALL) {
- num_params = 2;
- name = "AllocSmall";
+ name = slowpath ? "SlowAllocSmall" : "AllocSmall";
} else if (atype == ATYPE_NORMAL) {
- num_params = 1;
- name = "Alloc";
+ name = slowpath ? "SlowAlloc" : "Alloc";
} else if (atype == ATYPE_VECTOR) {
- num_params = 2;
- name = "AllocVector";
+ name = slowpath ? "SlowAllocVector" : "AllocVector";
} else if (atype == ATYPE_STRING) {
- num_params = 2;
- name = "AllocString";
+ name = slowpath ? "SlowAllocString" : "AllocString";
} else {
g_assert_not_reached ();
}
+ if (atype == ATYPE_NORMAL)
+ num_params = 1;
+ else
+ num_params = 2;
+
csig = mono_metadata_signature_alloc (mono_defaults.corlib, num_params);
if (atype == ATYPE_STRING) {
csig->ret = &mono_defaults.string_class->byval_arg;
csig->params [1] = &mono_defaults.int32_class->byval_arg;
} else {
csig->ret = &mono_defaults.object_class->byval_arg;
- for (i = 0; i < num_params; ++i)
+ for (i = 0; i < num_params; i++)
csig->params [i] = &mono_defaults.int_class->byval_arg;
}
mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_ALLOC);
#ifndef DISABLE_JIT
+ if (slowpath) {
+ switch (atype) {
+ case ATYPE_NORMAL:
+ case ATYPE_SMALL:
+ mono_mb_emit_ldarg (mb, 0);
+ mono_mb_emit_icall (mb, mono_object_new_specific);
+ break;
+ case ATYPE_VECTOR:
+ mono_mb_emit_ldarg (mb, 0);
+ mono_mb_emit_ldarg (mb, 1);
+ mono_mb_emit_icall (mb, mono_array_new_specific);
+ break;
+ case ATYPE_STRING:
+ mono_mb_emit_ldarg (mb, 1);
+ mono_mb_emit_icall (mb, mono_string_alloc);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ goto done;
+ }
+
size_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
if (atype == ATYPE_SMALL) {
/* size_var = size_arg */
/* return p */
mono_mb_emit_ldloc (mb, p_var);
+
+ done:
mono_mb_emit_byte (mb, CEE_RET);
#endif
return NULL;
if (known_instance_size && ALIGN_TO (klass->instance_size, SGEN_ALLOC_ALIGN) >= SGEN_MAX_SMALL_OBJ_SIZE)
return NULL;
- if (klass->has_finalize || mono_class_is_marshalbyref (klass) || (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 (klass->byval_arg.type == MONO_TYPE_STRING)
- return mono_gc_get_managed_allocator_by_type (ATYPE_STRING);
+ return mono_gc_get_managed_allocator_by_type (ATYPE_STRING, FALSE);
/* Generic classes have dynamic field and can go above MAX_SMALL_OBJ_SIZE. */
if (known_instance_size)
- return mono_gc_get_managed_allocator_by_type (ATYPE_SMALL);
+ return mono_gc_get_managed_allocator_by_type (ATYPE_SMALL, FALSE);
else
- return mono_gc_get_managed_allocator_by_type (ATYPE_NORMAL);
+ return mono_gc_get_managed_allocator_by_type (ATYPE_NORMAL, FALSE);
#else
return NULL;
#endif
return NULL;
g_assert (!mono_class_has_finalizer (klass) && !mono_class_is_marshalbyref (klass));
- return mono_gc_get_managed_allocator_by_type (ATYPE_VECTOR);
+ return mono_gc_get_managed_allocator_by_type (ATYPE_VECTOR, FALSE);
#else
return NULL;
#endif
}
MonoMethod*
-mono_gc_get_managed_allocator_by_type (int atype)
+mono_gc_get_managed_allocator_by_type (int atype, gboolean slowpath)
{
#ifdef MANAGED_ALLOCATION
MonoMethod *res;
+ MonoMethod **cache = slowpath ? slowpath_alloc_method_cache : alloc_method_cache;
if (!use_managed_allocator)
return NULL;
if (!mono_runtime_has_tls_get ())
return NULL;
- res = alloc_method_cache [atype];
+ res = cache [atype];
if (res)
return res;
- res = create_allocator (atype);
+ res = create_allocator (atype, slowpath);
LOCK_GC;
- if (alloc_method_cache [atype]) {
+ if (cache [atype]) {
mono_free_method (res);
- res = alloc_method_cache [atype];
+ res = cache [atype];
} else {
mono_memory_barrier ();
- alloc_method_cache [atype] = res;
+ cache [atype] = res;
}
UNLOCK_GC;
int i;
for (i = 0; i < ATYPE_NUM; ++i)
- if (method == alloc_method_cache [i])
+ if (method == alloc_method_cache [i] || method == slowpath_alloc_method_cache [i])
return TRUE;
return FALSE;
}
int i;
for (i = 0; i < ATYPE_NUM; ++i)
- if (alloc_method_cache [i])
+ if (alloc_method_cache [i] || slowpath_alloc_method_cache [i])
return TRUE;
return FALSE;
}
UNLOCK_GC;
done:
+ if (G_UNLIKELY (alloc_events))
+ mono_profiler_allocation (&arr->obj);
+
SGEN_ASSERT (6, SGEN_ALIGN_UP (size) == SGEN_ALIGN_UP (sgen_client_par_object_get_size ((GCVTable*)vtable, (GCObject*)arr)), "Vector has incorrect size.");
return arr;
}
UNLOCK_GC;
done:
+ if (G_UNLIKELY (alloc_events))
+ mono_profiler_allocation (&arr->obj);
+
SGEN_ASSERT (6, SGEN_ALIGN_UP (size) == SGEN_ALIGN_UP (sgen_client_par_object_get_size ((GCVTable*)vtable, (GCObject*)arr)), "Array has incorrect size.");
return arr;
}
/*This doesn't require fencing since EXIT_CRITICAL_REGION already does it for us*/
str->length = len;
EXIT_CRITICAL_REGION;
- return str;
+ goto done;
}
EXIT_CRITICAL_REGION;
#endif
UNLOCK_GC;
+ done:
+ if (G_UNLIKELY (alloc_events))
+ mono_profiler_allocation (&str->object);
+
return str;
}
{
mword desc = sgen_obj_get_descriptor (start);
-#include "sgen-scan-object.h"
+#include "sgen/sgen-scan-object.h"
}
static void
#ifdef USE_MONO_CTX
memset (&info->client_info.ctx, 0, sizeof (MonoContext));
#else
- memset (&info->client_info.regs, 0, sizeof (info->regs));
+ memset (&info->client_info.regs, 0, sizeof (info->client_info.regs));
#endif
if (mono_gc_get_gc_callbacks ()->thread_attach_func)
scan_area_arg_end = end_nursery;
FOREACH_THREAD (info) {
+ int skip_reason = 0;
if (info->client_info.skip) {
- SGEN_LOG (3, "Skipping dead thread %p, range: %p-%p, size: %td", info, info->client_info.stack_start, info->client_info.stack_end, (char*)info->client_info.stack_end - (char*)info->client_info.stack_start);
- continue;
+ SGEN_LOG (3, "Skipping dead thread %p, range: %p-%p, size: %zd", info, info->client_info.stack_start, info->client_info.stack_end, (char*)info->client_info.stack_end - (char*)info->client_info.stack_start);
+ skip_reason = 1;
+ } else if (info->client_info.gc_disabled) {
+ SGEN_LOG (3, "GC disabled for thread %p, range: %p-%p, size: %zd", info, info->client_info.stack_start, info->client_info.stack_end, (char*)info->client_info.stack_end - (char*)info->client_info.stack_start);
+ skip_reason = 2;
+ } else if (!mono_thread_info_is_live (info)) {
+ SGEN_LOG (3, "Skipping non-running thread %p, range: %p-%p, size: %zd (state %x)", info, info->client_info.stack_start, info->client_info.stack_end, (char*)info->client_info.stack_end - (char*)info->client_info.stack_start, info->client_info.info.thread_state);
+ skip_reason = 3;
}
- if (info->client_info.gc_disabled) {
- SGEN_LOG (3, "GC disabled for thread %p, range: %p-%p, size: %td", info, info->client_info.stack_start, info->client_info.stack_end, (char*)info->client_info.stack_end - (char*)info->client_info.stack_start);
- continue;
- }
- if (!mono_thread_info_is_live (info)) {
- SGEN_LOG (3, "Skipping non-running thread %p, range: %p-%p, size: %td (state %x)", info, info->client_info.stack_start, info->client_info.stack_end, (char*)info->client_info.stack_end - (char*)info->client_info.stack_start, info->client_info.info.thread_state);
+
+ binary_protocol_scan_stack ((gpointer)mono_thread_info_get_tid (info), info->client_info.stack_start, info->client_info.stack_end, skip_reason);
+
+ if (skip_reason)
continue;
- }
+
g_assert (info->client_info.suspend_done);
- SGEN_LOG (3, "Scanning thread %p, range: %p-%p, size: %td, pinned=%zd", info, info->client_info.stack_start, info->client_info.stack_end, (char*)info->client_info.stack_end - (char*)info->client_info.stack_start, sgen_get_pinned_count ());
+ SGEN_LOG (3, "Scanning thread %p, range: %p-%p, size: %zd, pinned=%zd", info, info->client_info.stack_start, info->client_info.stack_end, (char*)info->client_info.stack_end - (char*)info->client_info.stack_start, sgen_get_pinned_count ());
if (mono_gc_get_gc_callbacks ()->thread_mark_func && !conservative_stack_mark) {
mono_gc_get_gc_callbacks ()->thread_mark_func (info->client_info.runtime_data, info->client_info.stack_start, info->client_info.stack_end, precise, &ctx);
} else if (!precise) {
}
/*
- * Pthread intercept
+ * PThreads
*/
-#if USE_PTHREAD_INTERCEPT
-
+#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)
-{
- mono_thread_info_detach ();
- pthread_exit (retval);
- g_assert_not_reached ();
-}
-
-#endif /* USE_PTHREAD_INTERCEPT */
+#endif
/*
* Miscellaneous
cb.thread_attach = sgen_thread_attach;
cb.mono_method_is_critical = (gpointer)is_critical_method;
cb.mono_thread_in_critical_region = thread_in_critical_region;
-#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 (SgenThreadInfo));
sgen_bridge_print_gc_debug_usage ();
}
+
+gpointer
+sgen_client_get_provenance (void)
+{
+#ifdef SGEN_OBJECT_PROVENANCE
+ MonoGCCallbacks *cb = mono_gc_get_gc_callbacks ();
+ gpointer (*get_provenance_func) (void);
+ if (!cb)
+ return NULL;
+ get_provenance_func = cb->get_provenance_func;
+ if (get_provenance_func)
+ return get_provenance_func ();
+ return NULL;
+#else
+ return NULL;
+#endif
+}
+
+void
+sgen_client_describe_invalid_pointer (GCObject *ptr)
+{
+ sgen_bridge_describe_pointer (ptr);
+}
+
void
mono_gc_base_init (void)
{
mono_counters_init ();
+#ifdef HEAVY_STATISTICS
+ mono_counters_register ("los marked cards", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &los_marked_cards);
+ mono_counters_register ("los array cards scanned ", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &los_array_cards);
+ mono_counters_register ("los array remsets", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &los_array_remsets);
+
+ mono_counters_register ("WBarrier set arrayref", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_wbarrier_set_arrayref);
+ mono_counters_register ("WBarrier value copy", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_wbarrier_value_copy);
+ mono_counters_register ("WBarrier object copy", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_wbarrier_object_copy);
+#endif
+
sgen_gc_init ();
if (nursery_canaries_enabled ())
sgen_set_use_managed_allocator (FALSE);
}
+void
+mono_gc_base_cleanup (void)
+{
+}
+
+gboolean
+mono_gc_is_null (void)
+{
+ return FALSE;
+}
+
#endif