#include <mono/utils/mono-threads-coop.h>
#include "cominterop.h"
#include <mono/utils/w32api.h>
+#include <mono/utils/unlocked.h>
static void
get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error);
type_initialization_hash = g_hash_table_new (NULL, NULL);
blocked_thread_hash = g_hash_table_new (NULL, NULL);
mono_os_mutex_init_recursive (&ldstr_section);
+ mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
}
void
size = max_size;
}
-#ifdef HAVE_SGEN_GC
- /*An Ephemeron cannot be marked by sgen*/
- if (!static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
+ /* An Ephemeron cannot be marked by sgen */
+ if (mono_gc_is_moving () && !static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
*max_set = 0;
memset (bitmap, 0, size / 8);
return bitmap;
}
-#endif
for (p = klass; p != NULL; p = p->parent) {
gpointer iter = NULL;
int max_set = 0;
gsize *bitmap;
gsize default_bitmap [4] = {0};
- static gboolean gcj_inited = FALSE;
MonoGCDescriptor gc_descr;
- if (!gcj_inited) {
- mono_loader_lock ();
-
- mono_register_jit_icall (ves_icall_object_new_fast, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
- mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
-
- gcj_inited = TRUE;
- mono_loader_unlock ();
- }
-
if (!klass->inited)
mono_class_init (klass);
sig = mono_method_signature (method);
hashes_count = sig->param_count + 4;
- hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
+ hashes_start = (guint32 *)g_malloc (hashes_count * sizeof (guint32));
hashes = hashes_start;
if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
if (imt_builder [imt_slot] != NULL) {
entry->children = imt_builder [imt_slot]->children + 1;
if (entry->children == 1) {
- mono_stats.imt_slots_with_collisions++;
+ UnlockedIncrement (&mono_stats.imt_slots_with_collisions);
*imt_collisions_bitmap |= (1 << imt_slot);
}
} else {
entry->children = 0;
- mono_stats.imt_used_slots++;
+ UnlockedIncrement (&mono_stats.imt_used_slots);
}
imt_builder [imt_slot] = entry;
#if DEBUG_IMT
MONO_REQ_GC_NEUTRAL_MODE;
int number_of_entries = entries->children + 1;
- MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
+ MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)g_malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
GPtrArray *result = g_ptr_array_new ();
MonoImtBuilderEntry *current_entry;
int i;
int i;
GSList *list_item;
guint32 imt_collisions_bitmap = 0;
- MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
+ MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)g_calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
int method_count = 0;
gboolean record_method_count_for_max_collisions = FALSE;
gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
if (imt_builder [i] != NULL) {
int methods_in_slot = imt_builder [i]->children + 1;
- if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
- mono_stats.imt_max_collisions_in_slot = methods_in_slot;
+ if (methods_in_slot > UnlockedRead (&mono_stats.imt_max_collisions_in_slot)) {
+ UnlockedWrite (&mono_stats.imt_max_collisions_in_slot, methods_in_slot);
record_method_count_for_max_collisions = TRUE;
}
method_count += methods_in_slot;
}
}
- mono_stats.imt_number_of_methods += method_count;
+ UnlockedAdd (&mono_stats.imt_number_of_methods, method_count);
if (record_method_count_for_max_collisions) {
- mono_stats.imt_method_count_when_max_collisions = method_count;
+ UnlockedWrite (&mono_stats.imt_method_count_when_max_collisions, method_count);
}
for (i = 0; i < MONO_IMT_SIZE; i++) {
if (klass->interface_offsets_count) {
imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
- mono_stats.imt_number_of_tables++;
- mono_stats.imt_tables_size += imt_table_bytes;
+ UnlockedIncrement (&mono_stats.imt_number_of_tables);
+ UnlockedAdd (&mono_stats.imt_tables_size, imt_table_bytes);
} else {
imt_table_bytes = 0;
}
vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
- mono_stats.used_class_count++;
- mono_stats.class_vtable_size += vtable_size;
+ UnlockedIncrement (&mono_stats.used_class_count);
+ UnlockedAdd (&mono_stats.class_vtable_size, vtable_size);
interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
vt->domain = domain;
mono_class_compute_gc_descriptor (klass);
- /*
- * We can't use typed allocation in the non-root domains, since the
- * collector needs the GC descriptor stored in the vtable even after
- * the mempool containing the vtable is destroyed when the domain is
- * unloaded. An alternative might be to allocate vtables in the GC
- * heap, but this does not seem to work (it leads to crashes inside
- * libgc). If that approach is tried, two gc descriptors need to be
- * allocated for each class: one for the root domain, and one for all
- * other domains. The second descriptor should contain a bit for the
- * vtable field in MonoObject, since we can no longer assume the
- * vtable is reachable by other roots after the appdomain is unloaded.
- */
-#ifdef HAVE_BOEHM_GC
- if (domain != mono_get_root_domain () && !mono_dont_free_domains)
+ /*
+ * For Boehm:
+ * We can't use typed allocation in the non-root domains, since the
+ * collector needs the GC descriptor stored in the vtable even after
+ * the mempool containing the vtable is destroyed when the domain is
+ * unloaded. An alternative might be to allocate vtables in the GC
+ * heap, but this does not seem to work (it leads to crashes inside
+ * libgc). If that approach is tried, two gc descriptors need to be
+ * allocated for each class: one for the root domain, and one for all
+ * other domains. The second descriptor should contain a bit for the
+ * vtable field in MonoObject, since we can no longer assume the
+ * vtable is reachable by other roots after the appdomain is unloaded.
+ */
+ if (!mono_gc_is_moving () && domain != mono_get_root_domain () && !mono_dont_free_domains)
vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
else
-#endif
vt->gc_descr = klass->gc_descr;
gc_bits = mono_gc_get_vtable_bits (klass);
vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
}
vt->has_static_fields = TRUE;
- mono_stats.class_static_data_size += class_size;
+ UnlockedAdd (&mono_stats.class_static_data_size, class_size);
}
iter = NULL;
}
#ifndef DISABLE_REMOTING
+/**
+ * mono_remote_class_is_interface_proxy:
+ * \param remote_class
+ *
+ * Returns TRUE if the given remote class is a proxying an interface (as
+ * opposed to a class deriving from MarshalByRefObject).
+ */
+gboolean
+mono_remote_class_is_interface_proxy (MonoRemoteClass *remote_class)
+{
+ /* This if condition is taking advantage of how mono_remote_class ()
+ * works: if that code changes, this needs to change too. */
+ return (remote_class->interface_count >= 1 &&
+ remote_class->proxy_class == mono_defaults.marshalbyrefobject_class);
+}
+
/**
* mono_class_proxy_vtable:
* \param domain the application domain
}
imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
- mono_stats.imt_number_of_tables++;
- mono_stats.imt_tables_size += imt_table_bytes;
+ UnlockedIncrement (&mono_stats.imt_number_of_tables);
+ UnlockedAdd (&mono_stats.imt_tables_size, imt_table_bytes);
vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
- mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
+ UnlockedAdd (&mono_stats.class_vtable_size, vtsize + extra_interface_vtsize);
interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
/* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
+ if (mono_remote_class_is_interface_proxy (remote_class)) {
+ /* If it's a transparent proxy for an interface, set the
+ * MonoVTable:type to the interface type, not the placeholder
+ * MarshalByRefObject class. This is used when mini JITs calls
+ * to Object.GetType ()
+ */
+ MonoType *itf_proxy_type = &remote_class->interfaces[0]->byval_arg;
+ pvt->type = mono_type_get_object_checked (domain, itf_proxy_type, error);
+ if (!is_ok (error))
+ goto failure;
+ }
+
/* initialize vtable */
mono_class_setup_vtable (klass);
for (i = 0; i < klass->vtable_size; ++i) {
key = mp_key;
if (mono_class_is_interface (proxy_class)) {
+ /* If we need to proxy an interface, we use this stylized
+ * representation (interface_count >= 1, proxy_class is
+ * MarshalByRefObject). The code in
+ * mono_remote_class_is_interface_proxy () depends on being
+ * able to detect that we're doing this, so if this
+ * representation changes, change GetType, too. */
rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
rc->interface_count = 1;
rc->interfaces [0] = proxy_class;
rc->xdomain_vtable = NULL;
rc->proxy_class_name = name;
#ifndef DISABLE_PERFCOUNTERS
- mono_perfcounters->loader_bytes += mono_string_length (MONO_HANDLE_RAW (class_name)) + 1;
+ InterlockedAdd (&mono_perfcounters->loader_bytes, mono_string_length (MONO_HANDLE_RAW (class_name)) + 1);
#endif
g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
error_init (error);
- if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
- mono_profiler_method_start_invoke (method);
+ MONO_PROFILER_RAISE (method_begin_invoke, (method));
result = callbacks.runtime_invoke (method, obj, params, exc, error);
- if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
- mono_profiler_method_end_invoke (method);
+ MONO_PROFILER_RAISE (method_end_invoke, (method));
if (!mono_error_ok (error))
return NULL;
}
}
+/*
+ * mono_nullable_init_from_handle:
+ * @buf: The nullable structure to initialize.
+ * @value: the value to initialize from
+ * @klass: the type for the object
+ *
+ * Initialize the nullable structure pointed to by @buf from @value which
+ * should be a boxed value type. The size of @buf should be able to hold
+ * as much data as the @klass->instance_size (which is the number of bytes
+ * that will be copies).
+ *
+ * Since Nullables have variable structure, we can not define a C
+ * structure for them.
+ */
+void
+mono_nullable_init_from_handle (guint8 *buf, MonoObjectHandle value, MonoClass *klass)
+{
+ MONO_REQ_GC_UNSAFE_MODE;
+
+ MonoClass *param_class = klass->cast_class;
+
+ mono_class_setup_fields (klass);
+ g_assert (klass->fields_inited);
+
+ g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
+ g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
+
+ *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = MONO_HANDLE_IS_NULL (value) ? 0 : 1;
+ if (!MONO_HANDLE_IS_NULL (value)) {
+ uint32_t value_gchandle = 0;
+ gpointer src = mono_object_handle_pin_unbox (value, &value_gchandle);
+ if (param_class->has_references)
+ mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), src, 1, param_class);
+ else
+ mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), src, mono_class_value_size (param_class, NULL));
+ mono_gchandle_free (value_gchandle);
+ } else {
+ mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
+ }
+}
+
+
+
/**
* mono_nullable_box:
* \param buf The buffer representing the data to be boxed
MonoObjectHandle current_appdomain_delegate = MONO_HANDLE_NEW (MonoObject, NULL);
MonoClass *klass = mono_handle_class (exc);
- if (mono_class_has_parent (klass, mono_defaults.threadabortexception_class))
+ /*
+ * AppDomainUnloadedException don't behave like unhandled exceptions unless thrown from
+ * a thread started in unmanaged world.
+ * https://msdn.microsoft.com/en-us/library/system.appdomainunloadedexception(v=vs.110).aspx#Anchor_6
+ */
+ if (klass == mono_defaults.threadabortexception_class ||
+ (klass == mono_class_get_appdomain_unloaded_exception_class () &&
+ mono_thread_info_current ()->runtime_thread))
return;
field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
MonoVTable *vtable;
- vtable = mono_class_vtable (domain, klass);
- g_assert (vtable); /* FIXME don't swallow the error */
+ vtable = mono_class_vtable_full (domain, klass, error);
+ if (!is_ok (error))
+ return NULL;
MonoObject *o = mono_object_new_specific_checked (vtable, error);
return o;
return o;
}
-MonoObject *
-ves_icall_object_new_fast (MonoVTable *vtable)
-{
- MonoError error;
- MonoObject *o = mono_object_new_fast_checked (vtable, &error);
- mono_error_set_pending_exception (&error);
-
- return o;
-}
-
MonoObject*
mono_object_new_mature (MonoVTable *vtable, MonoError *error)
{
return o;
}
-/**
- * mono_class_get_allocation_ftn:
- * \param vtable vtable
- * \param for_box the object will be used for boxing
- * \param pass_size_in_words Unused
- * \returns the allocation function appropriate for the given class.
- */
-void*
-mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
-{
- MONO_REQ_GC_NEUTRAL_MODE;
-
- *pass_size_in_words = FALSE;
-
- if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass))
- return ves_icall_object_new_specific;
-
- if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
-
- return ves_icall_object_new_fast;
-
- /*
- * FIXME: This is actually slower than ves_icall_object_new_fast, because
- * of the overhead of parameter passing.
- */
- /*
- *pass_size_in_words = TRUE;
-#ifdef GC_REDIRECT_TO_LOCAL
- return GC_local_gcj_fast_malloc;
-#else
- return GC_gcj_fast_malloc;
-#endif
- */
- }
-
- return ves_icall_object_new_specific;
-}
-
/**
* mono_object_new_from_token:
* \param image Context where the type_token is hosted
static void
array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size)
{
-#ifdef HAVE_SGEN_GC
- if (klass->element_class->valuetype) {
- if (klass->element_class->has_references)
- mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
- else
- mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
+ if (mono_gc_is_moving ()) {
+ if (klass->element_class->valuetype) {
+ if (klass->element_class->has_references)
+ mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
+ else
+ mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
+ } else {
+ mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
+ }
} else {
- mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
+ mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
}
-#else
- mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
-#endif
}
/**
size = size - sizeof (MonoObject);
-#ifdef HAVE_SGEN_GC
- g_assert (size == mono_class_value_size (klass, NULL));
- mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
-#else
+ if (mono_gc_is_moving ()) {
+ g_assert (size == mono_class_value_size (klass, NULL));
+ mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
+ } else {
#if NO_UNALIGNED_ACCESS
- mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
-#else
- switch (size) {
- case 1:
- *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
- break;
- case 2:
- *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
- break;
- case 4:
- *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
- break;
- case 8:
- *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
- break;
- default:
mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
- }
-#endif
+#else
+ switch (size) {
+ case 1:
+ *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
+ break;
+ case 2:
+ *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
+ break;
+ case 4:
+ *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
+ break;
+ case 8:
+ *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
+ break;
+ default:
+ mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
+ }
#endif
+ }
if (klass->has_finalize) {
mono_object_register_finalizer (res);
return_val_if_nok (error, NULL);
eh_callbacks.mono_raise_exception (ex);
}
+/**
+ * mono_raise_exception:
+ * \param ex exception object
+ * Signal the runtime that the exception \p ex has been raised in unmanaged code.
+ */
+void
+mono_reraise_exception (MonoException *ex)
+{
+ MONO_REQ_GC_UNSAFE_MODE;
+
+ /*
+ * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
+ * that will cause gcc to omit the function epilog, causing problems when
+ * the JIT tries to walk the stack, since the return address on the stack
+ * will point into the next function in the executable, not this one.
+ */
+ eh_callbacks.mono_reraise_exception (ex);
+}
+
void
mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
{
static MonoObject*
mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
{
+#ifdef HOST_WASM
+ return mono_runtime_invoke_checked (mono_get_context_capture_method (), NULL, NULL, error);
+#else
MONO_REQ_GC_UNSAFE_MODE;
RuntimeInvokeFunction runtime_invoke;
runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
+#endif
}
/**
* mono_async_result_new:
if (method)
MONO_HANDLE_SETVAL (delegate, method, MonoMethod*, method);
- mono_stats.delegate_creations++;
+ UnlockedIncrement (&mono_stats.delegate_creations);
#ifndef DISABLE_REMOTING
if (!MONO_HANDLE_IS_NULL (target) && mono_class_is_transparent_proxy (mono_handle_class (target))) {