* Author:
* Paolo Molaro (lupus@ximian.com)
*
- * (C) 2002 Ximian, Inc. http://www.ximian.com
+ * Copyright 2002-2003 Ximian, Inc (http://www.ximian.com)
+ * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
*
*/
#include "config.h"
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#endif
+
#include "object.h"
#include "loader.h"
#include "cil-coff.h"
MonoClass *ret_class = NULL;
int loc_array=0, loc_return=0, loc_serialized_exc=0;
MonoExceptionClause *main_clause;
- MonoMethodHeader *header;
int pos, pos_leave;
gboolean copy_return;
mono_mb_emit_byte (mb, CEE_RET);
+ mono_mb_set_clauses (mb, 1, main_clause);
+
res = mono_remoting_mb_create_and_cache (method, mb, csig, csig->param_count + 16);
mono_mb_free (mb);
- header = ((MonoMethodNormal *)res)->header;
- header->num_clauses = 1;
- header->clauses = main_clause;
-
return res;
}
if (callvirt) {
// From mono_mb_create_and_cache
+ mb->skip_visibility = 1;
newm = mono_mb_create_method (mb, sig, sig->param_count + 16);
- newm->skip_visibility = 1;
/*We perform double checked locking, so must fence before publishing*/
mono_memory_barrier ();
mono_marshal_lock ();
mono_free_method (newm);
}
} else {
+ mb->skip_visibility = 1;
res = mono_mb_create_and_cache (cache, sig, mb, sig, sig->param_count + 16);
- res->skip_visibility = 1;
}
mono_mb_free (mb);
{
MonoMethodSignature *sig, *csig, *callsig;
MonoExceptionClause *clause;
- MonoMethodHeader *header;
MonoMethodBuilder *mb;
GHashTable *cache = NULL;
MonoClass *target_klass;
int i, pos, posna;
char *name;
gboolean need_direct_wrapper = FALSE;
+ int *tmp_nullable_locals;
g_assert (method);
res = mono_marshal_find_in_cache (cache, method);
if (res)
return res;
-
+
if (method->klass->rank && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
(method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
/*
}
}
+ /* Vtypes/nullables/Byrefs cause too many problems */
+ for (i = 0; i < callsig->param_count; ++i) {
+ if (MONO_TYPE_ISSTRUCT (callsig->params [i]) || callsig->params [i]->byref)
+ need_direct_wrapper = TRUE;
+ }
+
/*
* We try to share runtime invoke wrappers between different methods but have to
* be careful about methods whose klass has a type cctor, since putting the wrapper
}
}
+ tmp_nullable_locals = g_new0 (int, sig->param_count);
+
for (i = 0; i < sig->param_count; i++) {
MonoType *t = sig->params [i];
int type;
if (t->byref) {
mono_mb_emit_byte (mb, CEE_LDIND_I);
+ /* A Nullable<T> type don't have a boxed form, it's either null or a boxed T.
+ * So to make this work we unbox it to a local variablee and push a reference to that.
+ */
+ if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t))) {
+ tmp_nullable_locals [i] = mono_mb_add_local (mb, &mono_class_from_mono_type (t)->byval_arg);
+
+ mono_mb_emit_op (mb, CEE_UNBOX_ANY, mono_class_from_mono_type (t));
+ mono_mb_emit_stloc (mb, tmp_nullable_locals [i]);
+ mono_mb_emit_ldloc_addr (mb, tmp_nullable_locals [i]);
+ }
continue;
}
}
mono_mb_emit_stloc (mb, 0);
+
+ /* Convert back nullable-byref arguments */
+ for (i = 0; i < sig->param_count; i++) {
+ MonoType *t = sig->params [i];
+
+ /*
+ * Box the result and put it back into the array, the caller will have
+ * to obtain it from there.
+ */
+ if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t))) {
+ mono_mb_emit_ldarg (mb, 1);
+ mono_mb_emit_icon (mb, sizeof (gpointer) * i);
+ mono_mb_emit_byte (mb, CEE_ADD);
+
+ mono_mb_emit_ldloc (mb, tmp_nullable_locals [i]);
+ mono_mb_emit_op (mb, CEE_BOX, mono_class_from_mono_type (t));
+
+ mono_mb_emit_byte (mb, CEE_STIND_REF);
+ }
+ }
pos = mono_mb_emit_branch (mb, CEE_LEAVE);
clause->handler_len = mono_mb_get_pos (mb) - clause->handler_offset;
+ mono_mb_set_clauses (mb, 1, clause);
+
/* return result */
mono_mb_patch_branch (mb, pos);
mono_mb_emit_ldloc (mb, 0);
mono_mb_emit_byte (mb, CEE_RET);
if (need_direct_wrapper) {
+ mb->skip_visibility = 1;
res = mono_mb_create_and_cache (cache, method, mb, csig, sig->param_count + 16);
} else {
/* taken from mono_mb_create_and_cache */
mono_mb_free (mb);
- header = ((MonoMethodNormal *)res)->header;
- header->num_clauses = 1;
- header->clauses = clause;
-
return res;
}
mono_mb_emit_op (mb, CEE_CALL, method);
mono_mb_emit_byte (mb, CEE_RET);
+ mb->skip_visibility = TRUE;
res = mono_mb_create_and_cache (cache, method, mb, mono_method_signature (method),
sig->param_count + sig->hasthis + 4);
- res->skip_visibility = TRUE;
res->flags = method->flags;
mono_mb_free (mb);
mono_mb_emit_ldloc (mb, conv_arg);
mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed);
mono_mb_emit_byte (mb, CEE_STIND_REF);
- } else {
+ } else if (t->attrs & PARAM_ATTRIBUTE_OUT) {
mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
mono_mb_emit_op (mb, CEE_CALL, get_instance);
switch (action) {
case MARSHAL_ACTION_CONV_IN:
- if (MONO_TYPE_ISSTRUCT (t->data.type)) {
+ if (MONO_TYPE_ISSTRUCT (t->data.type) && !mono_class_from_mono_type (t->data.type)->blittable) {
char *msg = g_strdup_printf ("Can not marshal 'parameter #%d': Pointers can not reference marshaled structures. Use byref instead.", argnum + 1);
mono_mb_emit_exception_marshal_directive (m->mb, msg);
}
static MonoMethod *enter_method, *exit_method, *gettypefromhandle_method;
MonoMethodSignature *sig;
MonoExceptionClause *clause;
- MonoMethodHeader *header;
MonoMethodBuilder *mb;
MonoMethod *res;
GHashTable *cache;
mono_loader_unlock ();
clause->flags = MONO_EXCEPTION_CLAUSE_FINALLY;
+ mono_loader_lock ();
+
if (!enter_method) {
MonoMethodDesc *desc;
mono_method_desc_free (desc);
}
+ mono_loader_unlock ();
+
/* Push this or the type object */
if (method->flags & METHOD_ATTRIBUTE_STATIC) {
/* We have special handling for this in the JIT */
mono_mb_emit_ldloc (mb, ret_local);
mono_mb_emit_byte (mb, CEE_RET);
+ mono_mb_set_clauses (mb, 1, clause);
+
res = mono_mb_create_and_cache (cache, method,
mb, sig, sig->param_count + 16);
mono_mb_free (mb);
- header = ((MonoMethodNormal *)res)->header;
- header->num_clauses = 1;
- header->clauses = clause;
-
return res;
}
return ret;
}
-MonoMethod*
-mono_marshal_get_write_barrier (void)
-{
- static MonoMethod* ret = NULL;
- MonoMethodSignature *sig;
- MonoMethodBuilder *mb;
- int max_stack = 2;
-
- if (ret)
- return ret;
-
- mb = mono_mb_new (mono_defaults.object_class, "writebarrier", MONO_WRAPPER_WRITE_BARRIER);
-
- sig = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
-
- /* void writebarrier (MonoObject** addr, MonoObject* obj) */
- sig->ret = &mono_defaults.void_class->byval_arg;
- sig->params [0] = &mono_defaults.object_class->this_arg;
- sig->params [1] = &mono_defaults.object_class->byval_arg;
-
- /* just the store right now: add an hook for the GC to use, maybe something
- * that can be used for stelemref as well
- * We need a write barrier variant to be used with struct copies as well, though
- * there are also other approaches possible, like writing a wrapper specific to
- * the struct or to the reference pattern in the struct...
- * Depending on the GC, we may want variants that take the object we store to
- * when it is available.
- */
- mono_mb_emit_ldarg (mb, 0);
- mono_mb_emit_ldarg (mb, 1);
- mono_mb_emit_icall (mb, mono_gc_wbarrier_generic_store);
- /*mono_mb_emit_byte (mb, CEE_STIND_REF);*/
-
- mono_mb_emit_byte (mb, CEE_RET);
-
- ret = mono_mb_create_method (mb, sig, max_stack);
- mono_mb_free (mb);
- return ret;
-}
-
void*
mono_marshal_alloc (gulong size)
{
if (!object)
return NULL;
+ mono_init_com_types ();
+
if (cominterop_object_is_rcw (object)) {
MonoClass *klass = NULL;
MonoRealProxy* real_proxy = NULL;
ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject* object)
{
#ifndef DISABLE_COM
+ mono_init_com_types ();
+
return cominterop_get_idispatch_for_object (object);
#else
g_assert_not_reached ();
info->native_size &= ~(min_align - 1);
}
+ info->min_align = min_align;
+
/* Update the class's blittable info, if the layouts don't match */
if (info->native_size != mono_class_value_size (klass, NULL))
klass->blittable = FALSE;
}
if (align)
- *align = klass->min_align;
+ *align = klass->marshal_info->min_align;
return klass->marshal_info->native_size;
}
mono_mb_emit_managed_call (mb, method, NULL);
mono_mb_emit_byte (mb, CEE_RET);
- res = mono_mb_create_method (mb, csig, csig->param_count + 16);
-
/* We can corlib internal methods */
- res->skip_visibility = TRUE;
+ mb->skip_visibility = TRUE;
+
+ res = mono_mb_create_method (mb, csig, csig->param_count + 16);
mono_mb_free (mb);
mspecs [0] = NULL;
}
+ /* skip visiblity since we call internal methods */
+ mb->skip_visibility = TRUE;
+
cominterop_setup_marshal_context (&m, adjust_method);
m.mb = mb;
mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, NULL);
mono_marshal_unlock ();
mono_loader_unlock ();
- /* skip visiblity since we call internal methods */
- wrapper_method->skip_visibility = TRUE;
-
vtable [vtable_index--] = mono_compile_method (wrapper_method);
MonoMarshalSpec **mspecs;
MonoMethodSignature *sig, *sig_native;
MonoExceptionClause *main_clause = NULL;
- MonoMethodHeader *header;
int pos_leave;
int hr = 0;
int i;
main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
/* end catch */
+ mono_mb_set_clauses (mb, 1, main_clause);
+
mono_mb_patch_branch (mb, pos_leave);
mono_mb_emit_ldloc (mb, hr);
mono_metadata_free_marshal_spec (mspecs [i]);
g_free (mspecs);
- if (!preserve_sig) {
- header = ((MonoMethodNormal *)res)->header;
- header->num_clauses = 1;
- header->clauses = main_clause;
- }
-
return res;
}
MonoMethodBuilder *mb;
MonoMethodSignature *sig, *csig;
MonoExceptionClause *clause;
- MonoMethodHeader *header;
MonoImage *image;
MonoClass *klass;
GHashTable *cache;
clause->handler_len = mono_mb_get_pos (mb) - clause->handler_offset;
+ mono_mb_set_clauses (mb, 1, clause);
+
mono_mb_patch_branch (mb, pos_leave);
/* end-try */
res = mono_mb_create_and_cache (cache, method, mb, csig, param_count + 16);
mono_mb_free (mb);
- header = ((MonoMethodNormal *)res)->header;
- header->num_clauses = 1;
- header->clauses = clause;
-
return res;
}
+
+/*
+ * mono_marshal_free_dynamic_wrappers:
+ *
+ * Free wrappers of the dynamic method METHOD.
+ */
+void
+mono_marshal_free_dynamic_wrappers (MonoMethod *method)
+{
+ g_assert (method->dynamic);
+
+ mono_marshal_lock ();
+ /*
+ * FIXME: We currently leak the wrappers. Freeing them would be tricky as
+ * they could be shared with other methods ?
+ */
+ if (method->klass->image->runtime_invoke_direct_cache)
+ g_hash_table_remove (method->klass->image->runtime_invoke_direct_cache, method);
+ mono_marshal_unlock ();
+}