#include <mono/metadata/gc-internal.h>
#include <mono/utils/strenc.h>
#include <mono/utils/mono-counters.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
#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)
{
if (field->type->byref)
break;
+ if (static_fields && field->offset == -1)
+ /* special static */
+ continue;
+
pos = field->offset / sizeof (gpointer);
pos += offset;
return mono_string_new_size (mono_domain_get (), length);
}
-static void
+void
mono_class_compute_gc_descriptor (MonoClass *class)
{
int max_set = 0;
MonoImtBuilderEntry* entry = imt_builder [i];
while (entry != NULL) {
MonoImtBuilderEntry* next = entry->next;
- free (entry);
+ g_free (entry);
entry = next;
}
}
static int num_added = 0;
GenericVirtualCase *gvc, *list;
+ MonoImtBuilderEntry *entries;
+ int i;
+ GPtrArray *sorted;
mono_domain_lock (domain);
if (!domain->generic_virtual_cases)
if (++gvc->count == THUNK_THRESHOLD) {
gpointer *old_thunk = *vtable_slot;
- /* Force the rebuild of the thunk at the next call */
if ((gpointer)vtable_slot < (gpointer)vtable)
+ /* Force the rebuild of the thunk at the next call */
*vtable_slot = imt_trampoline;
- else
- *vtable_slot = vtable_trampoline;
+ else {
+ entries = get_generic_virtual_entries (domain, vtable_slot);
+
+ sorted = imt_sort_slot_entries (entries);
+
+ *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
+ vtable_trampoline);
+
+ while (entries) {
+ MonoImtBuilderEntry *next = entries->next;
+ g_free (entries);
+ entries = next;
+ }
+
+ for (i = 0; i < sorted->len; ++i)
+ g_free (g_ptr_array_index (sorted, i));
+ g_ptr_array_free (sorted, TRUE);
+ }
if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
invalidate_generic_virtual_thunk (domain, old_thunk);
}
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++;
bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
/*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
- statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set? max_set + 1: 0);
+ statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
mono_domain_add_class_static_data (domain, class, vt->data, NULL);
if (bitmap != default_bitmap)
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));
+ /*
+ * This marks the field as special static to speed up the
+ * checks in mono_field_static_get/set_value ().
+ */
+ field->offset = -1;
continue;
}
}
/* 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) {
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] = vtable_trampoline? vtable_trampoline: arch_create_jit_trampoline (cm);
}
}
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 */
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;
}
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)
/* 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 */
{
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);
- if (value == 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
+ } else {
memcpy (dest, value, size);
+ mono_gc_wbarrier_value_copy (dest, value, size, 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;
}
- 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);
}
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);
}
}
}
/* 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,
* 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) {
+ MonoThread *thread = mono_thread_current ();
+ g_assert (ex->object.vtable->domain == mono_domain_get ());
+ MONO_OBJECT_SETREF (thread, abort_exc, ex);
+ }
ex_handler (ex);
}
}
}
+
+static MonoObject*
+mono_runtime_capture_context (MonoDomain *domain)
+{
+ RuntimeInvokeFunction runtime_invoke;
+
+ if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
+ MonoMethod *method = mono_get_context_capture_method ();
+ MonoMethod *wrapper;
+ if (!method)
+ return NULL;
+ wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
+ domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
+ domain->capture_context_method = mono_compile_method (method);
+ }
+
+ runtime_invoke = domain->capture_context_runtime_invoke;
+
+ return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
+}
/**
* mono_async_result_new:
* @domain:domain where the object will be created.
mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
{
MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
- MonoMethod *method = mono_get_context_capture_method ();
-
+ MonoObject *context = mono_runtime_capture_context (domain);
/* we must capture the execution context from the original thread */
- if (method) {
- MONO_OBJECT_SETREF (res, execution_context, mono_runtime_invoke (method, NULL, NULL, NULL));
+ if (context) {
+ MONO_OBJECT_SETREF (res, execution_context, context);
/* note: result may be null if the flow is suppressed */
}
* 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