#include "mono/metadata/security-manager.h"
#include "mono/metadata/mono-debug-debugger.h"
#include <mono/metadata/gc-internal.h>
+#include <mono/metadata/verify-internals.h>
#include <mono/utils/strenc.h>
#include <mono/utils/mono-counters.h>
+#include <mono/utils/mono-error-internals.h>
+#include "cominterop.h"
#ifdef HAVE_BOEHM_GC
#define NEED_TO_ZERO_PTRFREE 1
/* Main thread */
static MonoThread *main_thread;
+/* Functions supplied by the runtime */
+static MonoRuntimeCallbacks callbacks;
+
/**
* mono_thread_set_main:
* @thread: thread to set as the main thread
mono_image_check_for_module_cctor (klass->image);
if (klass->image->has_module_cctor) {
MonoClass *module_klass = mono_class_get (klass->image, MONO_TOKEN_TYPE_DEF | 1);
- mono_runtime_class_init (mono_class_vtable (vtable->domain, module_klass));
+ MonoVTable *module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception);
+ if (!module_vtable)
+ return NULL;
+ mono_runtime_class_init (module_vtable);
}
}
method = mono_class_get_cctor (klass);
}
void
-mono_release_type_locks (MonoThread *thread)
+mono_release_type_locks (MonoInternalThread *thread)
{
mono_type_initialization_lock ();
g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
#error "MONO_IMT_SIZE cannot be larger than 32"
#endif
+void
+mono_install_callbacks (MonoRuntimeCallbacks *cbs)
+{
+ memcpy (&callbacks, cbs, sizeof (*cbs));
+}
+
+MonoRuntimeCallbacks*
+mono_get_runtime_callbacks (void)
+{
+ return &callbacks;
+}
+
void
mono_install_trampoline (MonoTrampoline func)
{
max_size = mono_class_data_size (class) / sizeof (gpointer);
else
max_size = class->instance_size / sizeof (gpointer);
- if (max_size >= size) {
- bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
+ if (max_size > size) {
+ g_assert (offset <= 0);
+ bitmap = g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
+ size = max_size;
}
+#ifdef HAVE_SGEN_GC
+ /*An Ephemeron cannot be marked by sgen*/
+ if (!static_fields && class->image == mono_defaults.corlib && !strcmp ("Ephemeron", class->name)) {
+ *max_set = 0;
+ memset (bitmap, 0, size / 8);
+ return bitmap;
+ }
+#endif
+
for (p = class; p != NULL; p = p->parent) {
gpointer iter = NULL;
while ((field = mono_class_get_fields (p, &iter))) {
if (field->type->byref)
break;
+ if (static_fields && field->offset == -1)
+ /* special static */
+ continue;
+
pos = field->offset / sizeof (gpointer);
pos += offset;
case MONO_TYPE_ARRAY:
g_assert ((field->offset % sizeof(gpointer)) == 0);
+ g_assert (pos < size || pos <= max_size);
bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
*max_set = MAX (*max_set, pos);
break;
case MONO_TYPE_CHAR:
break;
default:
- g_assert_not_reached ();
+ g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
break;
}
}
imt_trampoline = tramp_code;
}
-static gpointer vtable_trampoline = NULL;
-
-void
-mono_install_vtable_trampoline (gpointer tramp_code)
-{
- vtable_trampoline = tramp_code;
-}
-
#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
#define mix(a,b,c) { \
a -= c; a ^= rot(c, 4); c += b; \
c ^= b; c -= rot(b,24); \
}
+/*
+ * mono_method_get_imt_slot:
+ *
+ * The IMT slot is embedded into AOTed code, so this must return the same value
+ * for the same method across all executions. This means:
+ * - pointers shouldn't be used as hash values.
+ * - mono_metadata_str_hash () should be used for hashing strings.
+ */
guint32
mono_method_get_imt_slot (MonoMethod *method)
{
}
/* Initialize hashes */
- hashes [0] = g_str_hash (method->klass->name);
- hashes [1] = g_str_hash (method->klass->name_space);
- hashes [2] = g_str_hash (method->name);
+ hashes [0] = mono_metadata_str_hash (method->klass->name);
+ hashes [1] = mono_metadata_str_hash (method->klass->name_space);
+ hashes [2] = mono_metadata_str_hash (method->name);
hashes [3] = mono_metadata_type_hash (sig->ret);
for (i = 0; i < sig->param_count; i++) {
hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
}
-
+
/* Setup internal state */
a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
}
imt_builder [imt_slot] = entry;
#if DEBUG_IMT
- printf ("Added IMT slot for method (%p) %s.%s.%s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
- method, method->klass->name_space, method->klass->name,
- method->name, imt_slot, vtable_slot, entry->children);
+ {
+ char *method_name = mono_method_full_name (method, TRUE);
+ printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
+ method, method_name, imt_slot, vtable_slot, entry->children);
+ g_free (method_name);
+ }
#endif
}
static void
print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
if (e != NULL) {
+ MonoMethod *method = e->key;
printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
message,
num,
- e->method,
- e->method->klass->name_space,
- e->method->klass->name,
- e->method->name);
+ method,
+ method->klass->name_space,
+ method->klass->name,
+ method->name);
} else {
printf (" * %s: NULL\n", message);
}
MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
int method_count = 0;
gboolean record_method_count_for_max_collisions = FALSE;
- gboolean has_generic_virtual = FALSE;
+ gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
#if DEBUG_IMT
- printf ("Building IMT for class %s.%s\n", klass->name_space, klass->name);
+ printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
#endif
for (i = 0; i < klass->interface_offsets_count; ++i) {
MonoClass *iface = klass->interfaces_packed [i];
int interface_offset = klass->interface_offsets_packed [i];
- int method_slot_in_interface;
+ int method_slot_in_interface, vt_slot;
+
+ if (mono_class_has_variant_generic_params (iface))
+ has_variant_iface = TRUE;
+
+ vt_slot = interface_offset;
for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
MonoMethod *method;
* add_imt_builder_entry anyway.
*/
method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
- if (mono_method_get_imt_slot (method) != slot_num)
+ if (mono_method_get_imt_slot (method) != slot_num) {
+ vt_slot ++;
continue;
+ }
}
method = mono_class_get_method_by_index (iface, method_slot_in_interface);
if (method->is_generic) {
has_generic_virtual = TRUE;
+ vt_slot ++;
continue;
}
- add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
+
+ if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
+ add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
+ vt_slot ++;
+ }
}
}
if (extra_interfaces) {
MonoImtBuilderEntry *entry;
/* Link entries with imt_builder [i] */
- for (entry = entries; entry->next; entry = entry->next)
- ;
+ for (entry = entries; entry->next; entry = entry->next) {
+#if DEBUG_IMT
+ MonoMethod *method = (MonoMethod*)entry->key;
+ char *method_name = mono_method_full_name (method, TRUE);
+ printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
+ g_free (method_name);
+#endif
+ }
entry->next = imt_builder [i];
entries->children += imt_builder [i]->children + 1;
}
imt_builder [i] = entries;
}
- if (has_generic_virtual) {
+ if (has_generic_virtual || has_variant_iface) {
/*
* There might be collisions later when the the thunk is expanded.
*/
} else {
imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
}
- }
#if DEBUG_IMT
- printf ("initialize_imt_slot[%d]: %p\n", i, imt [i]);
+ printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
#endif
+ }
+
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) {
MonoImtBuilderEntry* entry = imt_builder [i];
while (entry != NULL) {
MonoImtBuilderEntry* next = entry->next;
- free (entry);
+ g_free (entry);
entry = next;
}
}
* entry points to the last element. That way appending and removing
* the first element are both O(1) operations.
*/
+#ifdef MONO_SMALL_CONFIG
+#define NUM_FREE_LISTS 6
+#else
#define NUM_FREE_LISTS 12
+#endif
#define FIRST_FREE_LIST_SIZE 64
#define MAX_WAIT_LENGTH 50
#define THUNK_THRESHOLD 10
/*
* get_generic_virtual_entries:
*
- * Return IMT entries for the generic virtual method instances for vtable slot
+ * Return IMT entries for the generic virtual method instances and
+ * variant interface methods for vtable slot
* VTABLE_SLOT.
*/
static MonoImtBuilderEntry*
* @code: the method's code
*
* Registers a call via unmanaged code to a generic virtual method
- * instantiation. If the number of calls reaches a threshold
+ * instantiation or variant interface method. If the number of calls reaches a threshold
* (THUNK_THRESHOLD), the method is added to the vtable slot's generic
* virtual method thunk.
*/
if (++gvc->count == THUNK_THRESHOLD) {
gpointer *old_thunk = *vtable_slot;
+ gpointer vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline ((gpointer*)vtable_slot - (gpointer*)vtable) : NULL;
if ((gpointer)vtable_slot < (gpointer)vtable)
/* Force the rebuild of the thunk at the next call */
mono_domain_unlock (domain);
}
-static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class);
+static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error);
/**
* mono_class_vtable:
*/
MonoVTable *
mono_class_vtable (MonoDomain *domain, MonoClass *class)
+{
+ return mono_class_vtable_full (domain, class, FALSE);
+}
+
+/**
+ * mono_class_vtable_full:
+ * @domain: the application domain
+ * @class: the class to initialize
+ * @raise_on_error if an exception should be raised on failure or not
+ *
+ * VTables are domain specific because we create domain specific code, and
+ * they contain the domain specific static class data.
+ */
+MonoVTable *
+mono_class_vtable_full (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
{
MonoClassRuntimeInfo *runtime_info;
g_assert (class);
+ if (class->exception_type) {
+ if (raise_on_error)
+ mono_raise_exception (mono_class_get_exception_for_failure (class));
+ return NULL;
+ }
+
/* this check can be inlined in jitted code, too */
runtime_info = class->runtime_info;
if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
return runtime_info->domain_vtables [domain->domain_id];
- if (class->exception_type)
- return NULL;
- return mono_class_create_runtime_vtable (domain, class);
+ return mono_class_create_runtime_vtable (domain, class, raise_on_error);
}
/**
}
static MonoVTable *
-mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
+mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
{
MonoVTable *vt;
MonoClassRuntimeInfo *runtime_info, *old_info;
return runtime_info->domain_vtables [domain->domain_id];
}
if (!class->inited || class->exception_type) {
- if (!mono_class_init (class) || class->exception_type){
- MonoException *exc;
+ if (!mono_class_init (class) || class->exception_type) {
mono_domain_unlock (domain);
mono_loader_unlock ();
- exc = mono_class_get_exception_for_failure (class);
- g_assert (exc);
- mono_raise_exception (exc);
+ if (raise_on_error)
+ mono_raise_exception (mono_class_get_exception_for_failure (class));
+ return NULL;
}
}
- mono_class_init (class);
+ /* Array types require that their element type be valid*/
+ if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
+ MonoClass *element_class = class->element_class;
+ if (!element_class->inited)
+ mono_class_init (element_class);
+
+ /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
+ if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
+ mono_class_setup_vtable (element_class);
+
+ if (element_class->exception_type != MONO_EXCEPTION_NONE) {
+ /*Can happen if element_class only got bad after mono_class_setup_vtable*/
+ if (class->exception_type == MONO_EXCEPTION_NONE)
+ mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ mono_domain_unlock (domain);
+ mono_loader_unlock ();
+ if (raise_on_error)
+ mono_raise_exception (mono_class_get_exception_for_failure (class));
+ return NULL;
+ }
+ }
/*
* For some classes, mono_class_init () already computed class->vtable_size, and
if (class->exception_type) {
mono_domain_unlock (domain);
mono_loader_unlock ();
+ if (raise_on_error)
+ mono_raise_exception (mono_class_get_exception_for_failure (class));
return NULL;
}
if (ARCH_USE_IMT) {
- vtable_size = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
+ vtable_size = MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
if (class->interface_offsets_count) {
imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
}
} else {
vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
- sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
+ MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
}
mono_stats.used_class_count++;
if (special_static != SPECIAL_STATIC_NONE) {
guint32 size, offset;
gint32 align;
+ gsize default_bitmap [4] = {0};
+ gsize *bitmap;
+ int max_set = 0;
+ MonoClass *fclass;
+ if (mono_type_is_reference (field->type)) {
+ default_bitmap [0] = 1;
+ max_set = 1;
+ bitmap = default_bitmap;
+ } else if (mono_type_is_struct (field->type)) {
+ fclass = mono_class_from_mono_type (field->type);
+ bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
+ } else {
+ default_bitmap [0] = 0;
+ max_set = 0;
+ bitmap = default_bitmap;
+ }
size = mono_type_size (field->type, &align);
- offset = mono_alloc_special_static_data (special_static, size, align);
+ offset = mono_alloc_special_static_data (special_static, size, align, bitmap, max_set);
if (!domain->special_static_fields)
domain->special_static_fields = g_hash_table_new (NULL, NULL);
g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
+ if (bitmap != default_bitmap)
+ g_free (bitmap);
+ /*
+ * This marks the field as special static to speed up the
+ * checks in mono_field_static_get/set_value ().
+ */
+ field->offset = -1;
continue;
}
}
}
}
- /* FIXME: class_vtable_hash is basically obsolete now: remove as soon
- * as we change the code in appdomain.c to invalidate vtables by
- * looking at the possible MonoClasses created for the domain.
+ /* class_vtable_array keeps an array of created vtables
*/
- g_hash_table_insert (domain->class_vtable_hash, class, vt);
+ g_ptr_array_add (domain->class_vtable_array, vt);
/* class->runtime_info is protected by the loader lock, both when
* it it enlarged and when it is stored info.
*/
/* this is a bounded memory retention issue: may want to
* handle it differently when we'll have a rcu-like system.
*/
- runtime_info = mono_image_alloc0 (class->image, sizeof (MonoClassRuntimeInfo) + new_size * sizeof (gpointer));
+ runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
runtime_info->max_domain = new_size - 1;
/* copy the stuff from the older info */
if (old_info) {
}
/* Initialize vtable */
- if (vtable_trampoline) {
+ if (callbacks.get_vtable_trampoline) {
// This also covers the AOT case
for (i = 0; i < class->vtable_size; ++i) {
- vt->vtable [i] = vtable_trampoline;
+ vt->vtable [i] = callbacks.get_vtable_trampoline (i);
}
} else {
mono_class_setup_vtable (class);
for (i = 0; i < class->vtable_size; ++i) {
MonoMethod *cm;
- if ((cm = class->vtable [i])) {
- if (mono_method_signature (cm)->generic_param_count)
- /* FIXME: Why is this needed ? */
- vt->vtable [i] = cm;
- else
- vt->vtable [i] = vtable_trampoline? vtable_trampoline: arch_create_jit_trampoline (cm);
- }
+ if ((cm = class->vtable [i]))
+ vt->vtable [i] = arch_create_jit_trampoline (cm);
}
}
mono_loader_unlock ();
/* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
- if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND)) {
- MonoException *exc = mono_class_get_exception_for_failure (class);
- g_assert (exc);
- mono_raise_exception (exc);
- }
+ if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
+ mono_raise_exception (mono_class_get_exception_for_failure (class));
/* make sure the parent is initialized */
+ /*FIXME shouldn't this fail the current type?*/
if (class->parent)
- mono_class_vtable (domain, class->parent);
+ mono_class_vtable_full (domain, class->parent, raise_on_error);
+ /*FIXME check for OOM*/
vt->type = mono_type_get_object (domain, &class->byval_arg);
+#if HAVE_SGEN_GC
+ if (mono_object_get_class (vt->type) != mono_defaults.monotype_class) {
+ static void *type_desc = NULL;
+
+ if (!type_desc) {
+ gsize bmap = 1;
+ type_desc = mono_gc_make_descr_from_bitmap (&bmap, 1);
+ }
+
+ /* This is unregistered in
+ unregister_vtable_reflection_type() in
+ domain.c. */
+ mono_gc_register_root ((char*)&vt->type, sizeof (gpointer), type_desc);
+ }
+#endif
if (class->contextbound)
vt->remote = 1;
else
static MonoVTable *
mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
{
+ MonoError error;
MonoVTable *vt, *pvt;
int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
MonoClass *k;
GSList *extra_interfaces = NULL;
MonoClass *class = remote_class->proxy_class;
gpointer *interface_offsets;
+ uint8_t *bitmap;
+ int bsize;
+
+#ifdef COMPRESSED_INTERFACE_BITMAP
+ int bcsize;
+#endif
vt = mono_class_vtable (domain, class);
+ g_assert (vt); /*FIXME property handle failure*/
max_interface_id = vt->max_interface_id;
/* Calculate vtable space for extra interfaces */
GPtrArray *ifaces;
int method_count;
+ /*FIXME test for interfaces with variant generic arguments*/
if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
continue; /* interface implemented by the class */
if (g_slist_find (extra_interfaces, iclass))
method_count = mono_class_num_methods (iclass);
- ifaces = mono_class_get_implemented_interfaces (iclass);
+ ifaces = mono_class_get_implemented_interfaces (iclass, &error);
+ g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
if (ifaces) {
for (i = 0; i < ifaces->len; ++i) {
MonoClass *ic = g_ptr_array_index (ifaces, i);
+ /*FIXME test for interfaces with variant generic arguments*/
if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
continue; /* interface implemented by the class */
if (g_slist_find (extra_interfaces, ic))
mono_stats.imt_number_of_tables++;
mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
- sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
+ MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
} else {
vtsize = sizeof (gpointer) * (max_interface_id + 1) +
- sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
+ MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
}
mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
else
pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
- memcpy (pvt, vt, sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer));
+ memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
pvt->klass = mono_defaults.transparent_proxy_class;
/* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
}
pvt->max_interface_id = max_interface_id;
- pvt->interface_bitmap = mono_domain_alloc0 (domain, sizeof (guint8) * (max_interface_id/8 + 1 ));
+ bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
+#ifdef COMPRESSED_INTERFACE_BITMAP
+ bitmap = g_malloc0 (bsize);
+#else
+ bitmap = mono_domain_alloc0 (domain, bsize);
+#endif
if (! ARCH_USE_IMT) {
/* initialize interface offsets */
}
for (i = 0; i < class->interface_offsets_count; ++i) {
int interface_id = class->interfaces_packed [i]->interface_id;
- pvt->interface_bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
+ bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
}
if (extra_interfaces) {
if (! ARCH_USE_IMT) {
interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
}
- pvt->interface_bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
+ bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
iter = NULL;
j = 0;
}
}
+#ifdef COMPRESSED_INTERFACE_BITMAP
+ bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
+ pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
+ mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
+ g_free (bitmap);
+#else
+ pvt->interface_bitmap = bitmap;
+#endif
return pvt;
}
* @class_name: name of the remote class
*
* Creates and initializes a MonoRemoteClass object for a remote type.
- *
+ *
+ * Can raise an exception on failure.
*/
MonoRemoteClass*
mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
{
+ MonoError error;
MonoRemoteClass *rc;
gpointer* key, *mp_key;
+ char *name;
key = create_remote_class_key (NULL, proxy_class);
return rc;
}
+ name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
+ if (!mono_error_ok (&error)) {
+ g_free (key);
+ mono_domain_unlock (domain);
+ mono_error_raise_exception (&error);
+ }
+
mp_key = copy_remote_class_key (domain, key);
g_free (key);
key = mp_key;
if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
- rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass) + sizeof(MonoClass*));
+ rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
rc->interface_count = 1;
rc->interfaces [0] = proxy_class;
rc->proxy_class = mono_defaults.marshalbyrefobject_class;
} else {
- rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass));
+ rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
rc->interface_count = 0;
rc->proxy_class = proxy_class;
}
rc->default_vtable = NULL;
rc->xdomain_vtable = NULL;
- rc->proxy_class_name = mono_string_to_utf8_mp (domain->mp, class_name);
+ rc->proxy_class_name = name;
mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
int i,j;
- rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * (remote_class->interface_count + 1));
+ rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
rc->proxy_class = remote_class->proxy_class;
rc->interface_count = remote_class->interface_count + 1;
rc->interfaces [j] = extra_class;
} else {
// Replace the old class. The interface array is the same
- rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * remote_class->interface_count);
+ rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
rc->proxy_class = extra_class;
rc->interface_count = remote_class->interface_count;
if (rc->interface_count > 0)
/* check method->slot is a valid index: perform isinstance? */
if (method->slot != -1) {
if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
- if (!is_proxy)
- res = vtable [mono_class_interface_offset (klass, method->klass) + method->slot];
+ if (!is_proxy) {
+ gboolean variance_used = FALSE;
+ int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
+ g_assert (iface_offset > 0);
+ res = vtable [iface_offset + method->slot];
+ }
} else {
res = vtable [method->slot];
}
/* generic methods demand invoke_with_check */
if (mono_method_signature (res)->generic_param_count)
res = mono_marshal_get_remoting_invoke_with_check (res);
- else
- res = mono_marshal_get_remoting_invoke (res);
+ else {
+#ifndef DISABLE_COM
+ if (klass == mono_defaults.com_object_class || klass->is_com_object)
+ res = mono_cominterop_get_invoke (res);
+ else
+#endif
+ res = mono_marshal_get_remoting_invoke (res);
+ }
} else {
if (method->is_inflated) {
/* Have to inflate the result */
MonoObject*
mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
{
+ MonoObject *result;
+
if (mono_runtime_get_no_exec ())
g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
- return default_mono_runtime_invoke (method, obj, params, exc);
+ if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
+ mono_profiler_method_start_invoke (method);
+
+ result = default_mono_runtime_invoke (method, obj, params, exc);
+
+ if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
+ mono_profiler_method_end_invoke (method);
+
+ return result;
}
/**
{
int t;
if (type->byref) {
+ /* object fields cannot be byref, so we don't need a
+ wbarrier here */
gpointer *p = (gpointer*)dest;
*p = value;
return;
t = mono_class_enum_basetype (type->data.klass)->type;
goto handle_enum;
} else {
- int size;
- size = mono_class_value_size (mono_class_from_mono_type (type), NULL);
+ MonoClass *class = mono_class_from_mono_type (type);
+ int size = mono_class_value_size (class, NULL);
if (value == NULL)
memset (dest, 0, size);
else
- memcpy (dest, value, size);
+ mono_gc_wbarrier_value_copy (dest, value, 1, class);
}
return;
case MONO_TYPE_GENERICINST:
g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
/* you cant set a constant! */
g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
-
- dest = (char*)vt->data + field->offset;
+
+ if (field->offset == -1) {
+ /* Special static */
+ gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
+ dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
+ } else {
+ dest = (char*)vt->data + field->offset;
+ }
set_value (field->type, dest, value, FALSE);
}
return vt->data;
}
+static guint8*
+mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
+{
+ guint8 *src;
+
+ if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
+ if (field->offset == -1) {
+ /* Special static */
+ gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
+ src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
+ } else {
+ src = (guint8*)vt->data + field->offset;
+ }
+ } else {
+ src = (guint8*)obj + field->offset;
+ }
+
+ return src;
+}
+
/**
* mono_field_get_value:
* @obj: Object instance
{
void *src;
+ g_assert (obj);
+
g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
src = (char*)obj + field->offset;
gchar *v;
gboolean is_static = FALSE;
gboolean is_ref = FALSE;
+ gboolean is_literal = FALSE;
switch (field->type->type) {
case MONO_TYPE_STRING:
is_ref = field->type->byref;
break;
case MONO_TYPE_GENERICINST:
- is_ref = !field->type->data.generic_class->container_class->valuetype;
+ is_ref = !mono_type_generic_inst_is_valuetype (field->type);
break;
default:
g_error ("type 0x%x not handled in "
return NULL;
}
+ if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
+ is_literal = TRUE;
+
if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
is_static = TRUE;
- vtable = mono_class_vtable (domain, field->parent);
- if (!vtable->initialized)
- mono_runtime_class_init (vtable);
+
+ if (!is_literal) {
+ vtable = mono_class_vtable (domain, field->parent);
+ if (!vtable) {
+ char *name = mono_type_get_full_name (field->parent);
+ /*FIXME extend this to use the MonoError api*/
+ g_warning ("Could not retrieve the vtable for type %s in mono_field_get_value_object", name);
+ g_free (name);
+ return NULL;
+ }
+ if (!vtable->initialized)
+ mono_runtime_class_init (vtable);
+ }
+ } else {
+ g_assert (obj);
}
if (is_ref) {
- if (is_static) {
+ if (is_literal) {
+ get_default_field_value (domain, field, &o);
+ } else if (is_static) {
mono_field_static_get_value (vtable, field, &o);
} else {
mono_field_get_value (obj, field, &o);
/* boxed value type */
klass = mono_class_from_mono_type (field->type);
+
+ if (mono_class_is_nullable (klass))
+ return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
+
o = mono_object_new (domain, klass);
v = ((gchar *) o) + sizeof (MonoObject);
- if (is_static) {
+
+ if (is_literal) {
+ get_default_field_value (domain, field, v);
+ } else if (is_static) {
mono_field_static_get_value (vtable, field, v);
} else {
mono_field_get_value (obj, field, v);
return;
}
- src = (char*)vt->data + field->offset;
+ if (field->offset == -1) {
+ /* Special static */
+ gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
+ src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
+ } else {
+ src = (char*)vt->data + field->offset;
+ }
set_value (field->type, value, src, TRUE);
}
g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
- if (value)
- memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
- else
+ if (value) {
+ if (param_class->has_references)
+ mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
+ else
+ memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
+ } else {
memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
+ }
}
/**
if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
MonoObject *o = mono_object_new (mono_domain_get (), param_class);
- memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
+ if (param_class->has_references)
+ mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
+ else
+ memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
return o;
}
else
/* This is called at runtime, so avoid the slower search in metadata */
mono_class_setup_methods (klass);
-
+ if (klass->exception_type)
+ return NULL;
im = mono_class_get_method_from_name (klass, "Invoke", -1);
g_assert (im);
return result;
}
+static MonoObject*
+serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
+{
+ static MonoMethod *serialize_method;
+
+ void *params [1];
+ MonoObject *array;
+
+ if (!serialize_method) {
+ MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
+ serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
+ }
+
+ if (!serialize_method) {
+ *failure = TRUE;
+ return NULL;
+ }
+
+ g_assert (!mono_object_class (obj)->marshalbyref);
+
+ params [0] = obj;
+ *exc = NULL;
+ array = mono_runtime_invoke (serialize_method, NULL, params, exc);
+ if (*exc)
+ *failure = TRUE;
+
+ return array;
+}
+
+static MonoObject*
+deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
+{
+ static MonoMethod *deserialize_method;
+
+ void *params [1];
+ MonoObject *result;
+
+ if (!deserialize_method) {
+ MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
+ deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
+ }
+ if (!deserialize_method) {
+ *failure = TRUE;
+ return NULL;
+ }
+
+ params [0] = obj;
+ *exc = NULL;
+ result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
+ if (*exc)
+ *failure = TRUE;
+
+ return result;
+}
+
+static MonoObject*
+make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
+{
+ static MonoMethod *get_proxy_method;
+
+ MonoDomain *domain = mono_domain_get ();
+ MonoRealProxy *real_proxy;
+ MonoReflectionType *reflection_type;
+ MonoTransparentProxy *transparent_proxy;
+
+ if (!get_proxy_method)
+ get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
+
+ g_assert (obj->vtable->klass->marshalbyref);
+
+ real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
+ reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
+
+ MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
+ MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
+
+ *exc = NULL;
+ transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
+ if (*exc)
+ *failure = TRUE;
+
+ return (MonoObject*) transparent_proxy;
+}
+
+/**
+ * mono_object_xdomain_representation
+ * @obj: an object
+ * @target_domain: a domain
+ * @exc: pointer to a MonoObject*
+ *
+ * Creates a representation of obj in the domain target_domain. This
+ * is either a copy of obj arrived through via serialization and
+ * deserialization or a proxy, depending on whether the object is
+ * serializable or marshal by ref. obj must not be in target_domain.
+ *
+ * If the object cannot be represented in target_domain, NULL is
+ * returned and *exc is set to an appropriate exception.
+ */
+MonoObject*
+mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
+{
+ MonoObject *deserialized = NULL;
+ gboolean failure = FALSE;
+
+ *exc = NULL;
+
+ if (mono_object_class (obj)->marshalbyref) {
+ deserialized = make_transparent_proxy (obj, &failure, exc);
+ } else {
+ MonoDomain *domain = mono_domain_get ();
+ MonoObject *serialized;
+
+ mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
+ serialized = serialize_object (obj, &failure, exc);
+ mono_domain_set_internal_with_options (target_domain, FALSE);
+ if (!failure)
+ deserialized = deserialize_object (serialized, &failure, exc);
+ if (domain != target_domain)
+ mono_domain_set_internal_with_options (domain, FALSE);
+ }
+
+ return deserialized;
+}
+
/* Used in call_unhandled_exception_delegate */
static MonoObject *
create_unhandled_exception_eventargs (MonoObject *exc)
call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
MonoObject *e = NULL;
gpointer pa [2];
+ MonoDomain *current_domain = mono_domain_get ();
+
+ if (domain != current_domain)
+ mono_domain_set_internal_with_options (domain, FALSE);
+
+ g_assert (domain == mono_object_domain (domain->domain));
+
+ if (mono_object_domain (exc) != domain) {
+ MonoObject *serialization_exc;
+
+ exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
+ if (!exc) {
+ if (serialization_exc) {
+ MonoObject *dummy;
+ exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
+ g_assert (exc);
+ } else {
+ exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
+ "System.Runtime.Serialization", "SerializationException",
+ "Could not serialize unhandled exception.");
+ }
+ }
+ }
+ g_assert (mono_object_domain (exc) == domain);
pa [0] = domain->domain;
pa [1] = create_unhandled_exception_eventargs (exc);
mono_runtime_delegate_invoke (delegate, pa, &e);
-
+
+ if (domain != current_domain)
+ mono_domain_set_internal_with_options (current_domain, FALSE);
+
if (e) {
- gchar *msg = mono_string_to_utf8 (((MonoException *) e)->message);
- g_warning ("exception inside UnhandledException handler: %s\n", msg);
- g_free (msg);
+ MonoError error;
+ gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
+ if (!mono_error_ok (&error)) {
+ g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
+ mono_error_cleanup (&error);
+ } else {
+ g_warning ("exception inside UnhandledException handler: %s\n", msg);
+ g_free (msg);
+ }
}
}
g_assert (field);
if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
- gboolean abort_process = (mono_thread_current () == main_thread) ||
+ gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
(mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
- if (current_domain != root_domain && (mono_framework_version () >= 2)) {
+ if (current_domain != root_domain) {
current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
} else {
current_appdomain_delegate = NULL;
}
}
-/*
+/**
+ * mono_runtime_exec_managed_code:
+ * @domain: Application domain
+ * @main_func: function to invoke from the execution thread
+ * @main_args: parameter to the main_func
+ *
* Launch a new thread to execute a function
*
* main_func is called back from the thread with main_args as the
int rval;
MonoCustomAttrInfo* cinfo;
gboolean has_stathread_attribute;
- MonoThread* thread = mono_thread_current ();
+ MonoInternalThread* thread = mono_thread_internal_current ();
g_assert (args);
}
if (has_stathread_attribute) {
thread->apartment_state = ThreadApartmentState_STA;
- } else if (mono_framework_version () == 1) {
- thread->apartment_state = ThreadApartmentState_Unknown;
} else {
thread->apartment_state = ThreadApartmentState_MTA;
}
else
t = &t->data.generic_class->container_class->byval_arg;
goto again;
+ case MONO_TYPE_PTR: {
+ MonoObject *arg;
+
+ /* The argument should be an IntPtr */
+ arg = mono_array_get (params, MonoObject*, i);
+ if (arg == NULL) {
+ pa [i] = NULL;
+ } else {
+ g_assert (arg->vtable->klass == mono_defaults.int_class);
+ pa [i] = ((MonoIntPtr*)arg)->m_value;
+ }
+ break;
+ }
default:
- g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
+ g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
}
}
}
if (!obj) {
obj = mono_object_new (mono_domain_get (), method->klass);
+ g_assert (obj); /*maybe we should raise a TLE instead?*/
if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
}
/* obj must be already unboxed if needed */
res = mono_runtime_invoke (method, obj, pa, exc);
+ if (sig->ret->type == MONO_TYPE_PTR) {
+ MonoClass *pointer_class;
+ static MonoMethod *box_method;
+ void *box_args [2];
+ MonoObject *box_exc;
+
+ /*
+ * The runtime-invoke wrapper returns a boxed IntPtr, need to
+ * convert it to a Pointer object.
+ */
+ pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
+ if (!box_method)
+ box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
+
+ g_assert (res->vtable->klass == mono_defaults.int_class);
+ box_args [0] = ((MonoIntPtr*)res)->m_value;
+ box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
+ res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
+ g_assert (!box_exc);
+ }
+
if (has_byref_nullables) {
/*
* The runtime invoke wrapper already converted byref nullables back,
* looked up using @klass. This will not invoke any constructors,
* so the consumer of this routine has to invoke any constructors on
* its own to initialize the object.
+ *
+ * It returns NULL on failure.
*/
MonoObject *
mono_object_new (MonoDomain *domain, MonoClass *klass)
{
+ MonoVTable *vtable;
+
MONO_ARCH_SAVE_REGS;
- return mono_object_new_specific (mono_class_vtable (domain, klass));
+ vtable = mono_class_vtable (domain, klass);
+ if (!vtable)
+ return NULL;
+ return mono_object_new_specific (vtable);
}
/**
mono_object_clone (MonoObject *obj)
{
MonoObject *o;
- int size;
+ int size = obj->vtable->klass->instance_size;
- size = obj->vtable->klass->instance_size;
o = mono_object_allocate (size, obj->vtable);
- /* do not copy the sync state */
- memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
-#ifdef HAVE_SGEN_GC
- if (obj->vtable->klass->has_references)
- mono_gc_wbarrier_object (o);
-#endif
+ if (obj->vtable->klass->has_references) {
+ mono_gc_wbarrier_object_copy (o, obj);
+ } else {
+ int size = obj->vtable->klass->instance_size;
+ /* do not copy the sync state */
+ memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
+ }
if (G_UNLIKELY (profile_allocs))
mono_profiler_allocation (o, obj->vtable->klass);
void
mono_array_full_copy (MonoArray *src, MonoArray *dest)
{
- mono_array_size_t size;
+ uintptr_t size;
MonoClass *klass = src->obj.vtable->klass;
MONO_ARCH_SAVE_REGS;
mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
{
MonoArray *o;
- mono_array_size_t size, i;
- mono_array_size_t *sizes;
+ uintptr_t size, i;
+ uintptr_t *sizes;
MonoClass *klass = array->obj.vtable->klass;
MONO_ARCH_SAVE_REGS;
return o;
}
- sizes = alloca (klass->rank * sizeof(mono_array_size_t) * 2);
+ sizes = alloca (klass->rank * sizeof(intptr_t) * 2);
size = mono_array_element_size (klass);
for (i = 0; i < klass->rank; ++i) {
sizes [i] = array->bounds [i].length;
size *= array->bounds [i].length;
sizes [i + klass->rank] = array->bounds [i].lower_bound;
}
- o = mono_array_new_full (domain, klass, sizes, sizes + klass->rank);
+ o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
#ifdef HAVE_SGEN_GC
if (klass->element_class->valuetype) {
if (klass->element_class->has_references)
((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
#endif
+gboolean
+mono_array_calc_byte_len (MonoClass *class, uintptr_t len, uintptr_t *res)
+{
+ uintptr_t byte_len;
+
+ byte_len = mono_array_element_size (class);
+ if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
+ return FALSE;
+ byte_len *= len;
+ if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
+ return FALSE;
+ byte_len += sizeof (MonoArray);
+
+ *res = byte_len;
+
+ return TRUE;
+}
+
/**
* mono_array_new_full:
* @domain: domain where the object is created
* lower bounds and type.
*/
MonoArray*
-mono_array_new_full (MonoDomain *domain, MonoClass *array_class, mono_array_size_t *lengths, mono_array_size_t *lower_bounds)
+mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
{
- mono_array_size_t byte_len, len, bounds_size;
+ uintptr_t byte_len, len, bounds_size;
MonoObject *o;
MonoArray *array;
+ MonoArrayBounds *bounds;
MonoVTable *vtable;
int i;
if (!array_class->inited)
mono_class_init (array_class);
- byte_len = mono_array_element_size (array_class);
len = 1;
/* A single dimensional array with a 0 lower bound is the same as an szarray */
}
}
- if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
+ if (!mono_array_calc_byte_len (array_class, len, &byte_len))
mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
- byte_len *= len;
- if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
- mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
- byte_len += sizeof (MonoArray);
+
if (bounds_size) {
/* align */
if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
* Following three lines almost taken from mono_object_new ():
* they need to be kept in sync.
*/
- vtable = mono_class_vtable (domain, array_class);
+ vtable = mono_class_vtable_full (domain, array_class, TRUE);
+#ifndef HAVE_SGEN_GC
if (!array_class->has_references) {
o = mono_object_allocate_ptrfree (byte_len, vtable);
#if NEED_TO_ZERO_PTRFREE
array->max_length = len;
if (bounds_size) {
- MonoArrayBounds *bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
+ bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
array->bounds = bounds;
+ }
+#else
+ if (bounds_size)
+ o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
+ else
+ o = mono_gc_alloc_vector (vtable, byte_len, len);
+ array = (MonoArray*)o;
+ mono_stats.new_object_count++;
+
+ bounds = array->bounds;
+#endif
+
+ if (bounds_size) {
for (i = 0; i < array_class->rank; ++i) {
bounds [i].length = lengths [i];
if (lower_bounds)
* This routine creates a new szarray with @n elements of type @eclass.
*/
MonoArray *
-mono_array_new (MonoDomain *domain, MonoClass *eclass, mono_array_size_t n)
+mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
{
MonoClass *ac;
ac = mono_array_class_get (eclass, 1);
g_assert (ac);
- return mono_array_new_specific (mono_class_vtable (domain, ac), n);
+ return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
}
/**
* can be sure about the domain it operates in.
*/
MonoArray *
-mono_array_new_specific (MonoVTable *vtable, mono_array_size_t n)
+mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
{
MonoObject *o;
MonoArray *ao;
- guint32 byte_len, elem_size;
+ uintptr_t byte_len;
MONO_ARCH_SAVE_REGS;
arith_overflow ();
return NULL;
}
-
- elem_size = mono_array_element_size (vtable->klass);
- if (CHECK_MUL_OVERFLOW_UN (n, elem_size)) {
- mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
- return NULL;
- }
- byte_len = n * elem_size;
- if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray))) {
+
+ if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
return NULL;
}
- byte_len += sizeof (MonoArray);
+#ifndef HAVE_SGEN_GC
if (!vtable->klass->has_references) {
o = mono_object_allocate_ptrfree (byte_len, vtable);
#if NEED_TO_ZERO_PTRFREE
ao = (MonoArray *)o;
ao->max_length = n;
+#else
+ o = mono_gc_alloc_vector (vtable, byte_len, n);
+ ao = (MonoArray*)o;
+ mono_stats.new_object_count++;
+#endif
+
if (G_UNLIKELY (profile_allocs))
mono_profiler_allocation (o, vtable->klass);
mono_gc_out_of_memory (-1);
vtable = mono_class_vtable (domain, mono_defaults.string_class);
+ g_assert (vtable);
+#ifndef HAVE_SGEN_GC
s = mono_object_allocate_ptrfree (size, vtable);
s->length = len;
+#else
+ s = mono_gc_alloc_string (vtable, size, len);
+#endif
#if NEED_TO_ZERO_PTRFREE
s->chars [len] = 0;
#endif
return mono_nullable_box (value, class);
vtable = mono_class_vtable (domain, class);
+ if (!vtable)
+ return NULL;
size = mono_class_instance_size (class);
res = mono_object_new_alloc_specific (vtable);
if (G_UNLIKELY (profile_allocs))
size = size - sizeof (MonoObject);
#ifdef HAVE_SGEN_GC
+ g_assert (size == mono_class_value_size (class, NULL));
mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
-#endif
-
+#else
#if NO_UNALIGNED_ACCESS
memcpy ((char *)res + sizeof (MonoObject), value, size);
#else
default:
memcpy ((char *)res + sizeof (MonoObject), value, size);
}
+#endif
#endif
if (class->has_finalize)
mono_object_register_finalizer (res);
void
mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
{
- int size = mono_class_value_size (klass, NULL);
mono_gc_wbarrier_value_copy (dest, src, 1, klass);
- memcpy (dest, src, size);
}
/*
{
int size = mono_array_element_size (dest->obj.vtable->klass);
char *d = mono_array_addr_with_size (dest, size, dest_idx);
+ g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
- memmove (d, src, size * count);
}
/**
if (!klass->inited)
mono_class_init (klass);
- if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)
+ if (klass->marshalbyref || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
return mono_object_isinst_mbyref (obj, klass);
if (!obj)
if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
return obj;
}
+
+ /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
+ if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
+ return obj;
} else {
MonoClass *oklass = vt->klass;
if ((oklass == mono_defaults.transparent_proxy_class))
{
MONO_ARCH_SAVE_REGS;
- if (image->dynamic)
- return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
- else
+ if (image->dynamic) {
+ MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
+ return str;
+ } else {
+ if (!mono_verifier_verify_string_signature (image, idx, NULL))
+ return NULL; /*FIXME we should probably be raising an exception here*/
return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
+ }
}
/**
const char *str = sig;
MonoString *o, *interned;
size_t len2;
-
+
len2 = mono_metadata_decode_blob_size (str, &str);
len2 >>= 1;
*
* Return the UTF8 representation for @s.
* the resulting buffer nedds to be freed with g_free().
+ *
+ * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
*/
char *
mono_string_to_utf8 (MonoString *s)
+{
+ MonoError error;
+ char *result = mono_string_to_utf8_checked (s, &error);
+
+ if (!mono_error_ok (&error))
+ mono_error_raise_exception (&error);
+ return result;
+}
+
+char *
+mono_string_to_utf8_checked (MonoString *s, MonoError *error)
{
long written = 0;
char *as;
- GError *error = NULL;
+ GError *gerror = NULL;
+
+ mono_error_init (error);
if (s == NULL)
return NULL;
if (!s->length)
return g_strdup ("");
- as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &error);
- if (error) {
- MonoException *exc = mono_get_exception_argument ("string", error->message);
- g_error_free (error);
- mono_raise_exception(exc);
+ as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
+ if (gerror) {
+ mono_error_set_argument (error, "string", "%s", gerror->message);
+ g_error_free (gerror);
+ return NULL;
}
/* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
if (s->length > written) {
* This is a temporary helper until our string implementation
* is reworked to always include the null terminating char.
*/
-gunichar2 *
+mono_unichar2*
mono_string_to_utf16 (MonoString *s)
{
char *as;
static char *
-mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s)
+mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, MonoError *error)
{
char *r;
char *mp_s;
int len;
- if (!mp && !image)
- return mono_string_to_utf8 (s);
-
- r = mono_string_to_utf8 (s);
- if (!r)
+ r = mono_string_to_utf8_checked (s, error);
+ if (!mono_error_ok (error))
return NULL;
+ if (!mp && !image)
+ return r;
+
len = strlen (r) + 1;
if (mp)
mp_s = mono_mempool_alloc (mp, len);
* Same as mono_string_to_utf8, but allocate the string from the image mempool.
*/
char *
-mono_string_to_utf8_image (MonoImage *image, MonoString *s)
+mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
{
- return mono_string_to_utf8_internal (NULL, image, s);
+ return mono_string_to_utf8_internal (NULL, image, s, error);
}
/**
* Same as mono_string_to_utf8, but allocate the string from a mempool.
*/
char *
-mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s)
+mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
{
- return mono_string_to_utf8_internal (mp, NULL, s);
+ return mono_string_to_utf8_internal (mp, NULL, s, error);
}
static void
* will point into the next function in the executable, not this one.
*/
- if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class)
- MONO_OBJECT_SETREF (mono_thread_current (), abort_exc, ex);
+ if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class) {
+ MonoInternalThread *thread = mono_thread_internal_current ();
+ g_assert (ex->object.vtable->domain == mono_domain_get ());
+ MONO_OBJECT_SETREF (thread, abort_exc, ex);
+ }
ex_handler (ex);
}
gpointer params [1];
static MonoMethod *handle_set;
- res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
+ res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
/* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
if (!handle_set)
- handle_set = mono_class_get_property_from_name (mono_defaults.waithandle_class, "Handle")->set;
+ handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
params [0] = &handle;
mono_runtime_invoke (handle_set, res, params, NULL);
static MonoClassField *f_safe_handle;
if (!f_os_handle && !f_safe_handle) {
- f_os_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "os_handle");
- f_safe_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "safe_wait_handle");
+ f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
+ f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
}
if (f_os_handle) {
void
mono_print_unhandled_exception (MonoObject *exc)
{
+ MonoError error;
char *message = (char *) "";
MonoString *str;
MonoMethod *method;
str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
if (str) {
- message = mono_string_to_utf8 (str);
- free_message = TRUE;
+ message = mono_string_to_utf8_checked (str, &error);
+ if (!mono_error_ok (&error)) {
+ mono_error_cleanup (&error);
+ message = (char *)"";
+ } else {
+ free_message = TRUE;
+ }
}
}
method = mono_marshal_get_remoting_invoke (method);
delegate->method_ptr = mono_compile_method (method);
MONO_OBJECT_SETREF (delegate, target, target);
- } else if (mono_method_signature (method)->hasthis && method->klass->valuetype) {
+ } else if (method && mono_method_signature (method)->hasthis && method->klass->valuetype) {
method = mono_marshal_get_unbox_wrapper (method);
delegate->method_ptr = mono_compile_method (method);
MONO_OBJECT_SETREF (delegate, target, target);
arg = mono_array_get (out_args, gpointer, j);
type = pt->type;
- switch (type) {
- case MONO_TYPE_VOID:
- g_assert_not_reached ();
- break;
- case MONO_TYPE_U1:
- case MONO_TYPE_I1:
- case MONO_TYPE_BOOLEAN:
- case MONO_TYPE_U2:
- case MONO_TYPE_I2:
- case MONO_TYPE_CHAR:
- case MONO_TYPE_U4:
- case MONO_TYPE_I4:
- case MONO_TYPE_I8:
- case MONO_TYPE_U8:
- case MONO_TYPE_R4:
- case MONO_TYPE_R8:
- case MONO_TYPE_VALUETYPE: {
+ g_assert (type != MONO_TYPE_VOID);
+
+ if (MONO_TYPE_IS_REFERENCE (pt)) {
+ mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
+ } else {
if (arg) {
- size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
- memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
- }
- else {
+ MonoClass *class = ((MonoObject*)arg)->vtable->klass;
+ size = mono_class_value_size (class, NULL);
+ if (class->has_references)
+ mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
+ else
+ memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
+ } else {
size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
memset (*((gpointer *)params [i]), 0, size);
}
- break;
- }
- case MONO_TYPE_STRING:
- case MONO_TYPE_CLASS:
- case MONO_TYPE_ARRAY:
- case MONO_TYPE_SZARRAY:
- case MONO_TYPE_OBJECT:
- **((MonoObject ***)params [i]) = (MonoObject *)arg;
- break;
- default:
- g_assert_not_reached ();
}
j++;
* mono_create_ftnptr:
*
* Given a function address, create a function descriptor for it.
- * This is only needed on IA64 and PPC64.
+ * This is only needed on some platforms.
*/
gpointer
mono_create_ftnptr (MonoDomain *domain, gpointer addr)
{
-#ifdef __ia64__
- gpointer *desc;
-
- desc = mono_domain_code_reserve (domain, 2 * sizeof (gpointer));
-
- desc [0] = addr;
- desc [1] = NULL;
-
- return desc;
-#elif defined(__ppc64__) || defined(__powerpc64__)
- gpointer *desc;
-
- desc = mono_domain_code_reserve (domain, 3 * sizeof (gpointer));
-
- desc [0] = addr;
- desc [1] = NULL;
- desc [2] = NULL;
-
- return desc;
-#else
- return addr;
-#endif
+ return callbacks.create_ftnptr (domain, addr);
}
/*
* mono_get_addr_from_ftnptr:
*
* Given a pointer to a function descriptor, return the function address.
- * This is only needed on IA64 and PPC64.
+ * This is only needed on some platforms.
*/
gpointer
mono_get_addr_from_ftnptr (gpointer descr)
{
-#if defined(__ia64__) || defined(__ppc64__) || defined(__powerpc64__)
- return *(gpointer*)descr;
-#else
- return descr;
-#endif
+ return callbacks.get_addr_from_ftnptr (descr);
}
-#if 0
/**
* mono_string_chars:
* @s: a MonoString
* Returns a pointer to the UCS16 characters stored in the MonoString
*/
gunichar2 *
-mono_string_chars(MonoString *s)
+mono_string_chars (MonoString *s)
{
- /* This method is here only for documentation extraction, this is a macro */
+ return s->chars;
}
/**
int
mono_string_length (MonoString *s)
{
- /* This method is here only for documentation extraction, this is a macro */
+ return s->length;
+}
+
+/**
+ * mono_array_length:
+ * @array: a MonoArray*
+ *
+ * Returns the total number of elements in the array. This works for
+ * both vectors and multidimensional arrays.
+ */
+uintptr_t
+mono_array_length (MonoArray *array)
+{
+ return array->max_length;
+}
+
+/**
+ * mono_array_addr_with_size:
+ * @array: a MonoArray*
+ * @size: size of the array elements
+ * @idx: index into the array
+ *
+ * Returns the address of the @idx element in the array.
+ */
+char*
+mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
+{
+ return ((char*)(array)->vector) + size * idx;
}
-#endif