};
#endif
-/* This mutex protects the various marshalling related caches in MonoImage */
+/*
+ * This mutex protects the various marshalling related caches in MonoImage
+ * and a few other data structures static to this file.
+ * Note that when this lock is held it is not possible to take other runtime
+ * locks like the loader lock.
+ */
#define mono_marshal_lock() EnterCriticalSection (&marshal_mutex)
#define mono_marshal_unlock() LeaveCriticalSection (&marshal_mutex)
static CRITICAL_SECTION marshal_mutex;
+/* This mutex protects the various cominterop related caches in MonoImage */
+#define mono_cominterop_lock() EnterCriticalSection (&cominterop_mutex)
+#define mono_cominterop_unlock() LeaveCriticalSection (&cominterop_mutex)
+static CRITICAL_SECTION cominterop_mutex;
+
/* Maps wrapper methods to the methods they wrap */
static GHashTable *wrapper_hash;
static void
mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func);
+static void init_safe_handle (void);
+
+/* MonoMethod pointers to SafeHandle::DangerousAddRef and ::DangerousRelease */
+static MonoMethod *sh_dangerous_add_ref;
+static MonoMethod *sh_dangerous_release;
+
+
+static void
+init_safe_handle ()
+{
+ sh_dangerous_add_ref = mono_class_get_method_from_name (
+ mono_defaults.safehandle_class, "DangerousAddRef", 1);
+ sh_dangerous_release = mono_class_get_method_from_name (
+ mono_defaults.safehandle_class, "DangerousRelease", 0);
+}
+
static void
register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
{
return sig;
}
+/* Begin COM Interop related stuff until seperate file */
+
+
+/* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
+#ifdef PLATFORM_WIN32
+#define STDCALL __stdcall
+#else
+#define STDCALL
+#endif
+
+/* Upon creation of a CCW, only allocate a weak handle and set the
+ * reference count to 0. If the unmanaged client code decides to addref and
+ * hold onto the CCW, I then allocate a strong handle. Once the reference count
+ * goes back to 0, convert back to a weak handle.
+ */
+typedef struct {
+ guint32 ref_count;
+ guint32 gc_handle;
+ GHashTable* vtable_hash;
+} MonoCCW;
+
+/* This type is the actual pointer passed to unmanaged code
+ * to represent a COM interface.
+ */
+typedef struct {
+ gpointer vtable;
+ MonoCCW* ccw;
+} MonoCCWInterface;
+
+/* IUnknown */
+static int STDCALL cominterop_ccw_addref (MonoCCWInterface* ccwe);
+
+static int STDCALL cominterop_ccw_release (MonoCCWInterface* ccwe);
+
+static int STDCALL cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv);
+
+/* IDispatch */
+static int STDCALL cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo);
+
+static int STDCALL cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo);
+
+static int STDCALL cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
+ gunichar2** rgszNames, guint32 cNames,
+ guint32 lcid, gint32 *rgDispId);
+
+static int STDCALL cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
+ gpointer riid, guint32 lcid,
+ guint16 wFlags, gpointer pDispParams,
+ gpointer pVarResult, gpointer pExcepInfo,
+ guint32 *puArgErr);
+
+static MonoMethod *
+cominterop_get_managed_wrapper_adjusted (MonoMethod *method);
+
+static gpointer
+cominterop_get_ccw (MonoObject* object, MonoClass* itf);
+
+static MonoObject*
+cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify);
+
/**
- * signature_cominterop:
- * @image: a image
- * @sig: managed method signature
+ * cominterop_method_signature:
+ * @method: a method
*
* Returns: the corresponding unmanaged method signature for a managed COM
* method.
*/
static MonoMethodSignature*
-signature_cominterop (MonoImage *image, MonoMethodSignature *sig)
+cominterop_method_signature (MonoMethod* method)
{
MonoMethodSignature *res;
+ MonoImage *image = method->klass->image;
+ MonoMethodSignature *sig = mono_method_signature (method);
+ gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
int sigsize;
int i;
int param_count = sig->param_count + 1; // convert this arg into IntPtr arg
- if (!MONO_TYPE_IS_VOID (sig->ret))
+ if (!preserve_sig &&!MONO_TYPE_IS_VOID (sig->ret))
param_count++;
sigsize = sizeof (MonoMethodSignature) + ((param_count - MONO_ZERO_LEN_ARRAY) * sizeof (MonoType *));
// first arg is interface pointer
res->params[0] = &mono_defaults.int_class->byval_arg;
- // last arg is return type
- if (!MONO_TYPE_IS_VOID (sig->ret)) {
- res->params[param_count-1] = mono_metadata_type_dup_mp (image, sig->ret);
- res->params[param_count-1]->byref = 1;
- res->params[param_count-1]->attrs = PARAM_ATTRIBUTE_OUT;
+ if (preserve_sig) {
+ res->ret = sig->ret;
+ }
+ else {
+ // last arg is return type
+ if (!MONO_TYPE_IS_VOID (sig->ret)) {
+ res->params[param_count-1] = mono_metadata_type_dup_mp (image, sig->ret);
+ res->params[param_count-1]->byref = 1;
+ res->params[param_count-1]->attrs = PARAM_ATTRIBUTE_OUT;
+ }
+
+ // return type is always int32 (HRESULT)
+ res->ret = &mono_defaults.int32_class->byval_arg;
}
// no pinvoke
// set param_count
res->param_count = param_count;
- // return type is always int32 (HRESULT)
- res->ret = &mono_defaults.int32_class->byval_arg;
-
// STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM
#ifdef PLATFORM_WIN32
res->call_convention = MONO_CALL_STDCALL;
return (klass && klass == mono_defaults.com_interop_proxy_class);
}
+static int
+cominterop_get_com_slot_begin (MonoClass* klass)
+{
+ static MonoClass *interface_type_attribute = NULL;
+ MonoCustomAttrInfo *cinfo = NULL;
+ MonoInterfaceTypeAttribute* itf_attr = NULL;
+
+ if (!interface_type_attribute)
+ interface_type_attribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "InterfaceTypeAttribute");
+ cinfo = mono_custom_attrs_from_class (klass);
+ if (cinfo) {
+ itf_attr = (MonoInterfaceTypeAttribute*)mono_custom_attrs_get_attr (cinfo, interface_type_attribute);
+ if (!cinfo->cached)
+ mono_custom_attrs_free (cinfo);
+ }
+
+ if (itf_attr && itf_attr->intType == 1)
+ return 3; /* 3 methods in IUnknown*/
+ else
+ return 7; /* 7 methods in IDispatch*/
+}
+
/**
* cominterop_get_com_slot_for_method:
* @method: a method
static int
cominterop_get_com_slot_for_method (MonoMethod* method)
{
- static MonoClass *interface_type_attribute = NULL;
- MonoInterfaceTypeAttribute* itf_attr = NULL;
- MonoCustomAttrInfo *cinfo = NULL;
- guint32 offset = 7;
guint32 slot = method->slot;
- GPtrArray *ifaces;
- MonoClass *ic = NULL;
- int i;
+ MonoClass *ic = method->klass;
- ifaces = mono_class_get_implemented_interfaces (method->klass);
- if (ifaces) {
- int offset;
- for (i = 0; i < ifaces->len; ++i) {
- ic = g_ptr_array_index (ifaces, i);
- offset = method->klass->interface_offsets[ic->interface_id];
- if (method->slot >= offset && method->slot < offset + ic->method.count) {
- slot -= offset;
- break;
+ /* if method is on a class, we need to look up interface method exists on */
+ if (!MONO_CLASS_IS_INTERFACE(method->klass)) {
+ GPtrArray *ifaces = mono_class_get_implemented_interfaces (method->klass);
+ if (ifaces) {
+ int i;
+ for (i = 0; i < ifaces->len; ++i) {
+ int offset;
+ ic = g_ptr_array_index (ifaces, i);
+ offset = mono_class_interface_offset (method->klass, ic);
+ if (method->slot >= offset && method->slot < offset + ic->method.count) {
+ slot -= offset;
+ break;
+ }
+ ic = NULL;
}
+ g_ptr_array_free (ifaces, TRUE);
}
- g_ptr_array_free (ifaces, TRUE);
}
- if (!ic)
- ic = method->klass;
-
g_assert (ic);
g_assert (MONO_CLASS_IS_INTERFACE (ic));
- if (!interface_type_attribute)
- interface_type_attribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "InterfaceTypeAttribute");
- cinfo = mono_custom_attrs_from_class (ic);
- if (cinfo) {
- itf_attr = (MonoInterfaceTypeAttribute*)mono_custom_attrs_get_attr (cinfo, interface_type_attribute);
- if (!cinfo->cached)
- mono_custom_attrs_free (cinfo);
- }
-
- if (itf_attr && itf_attr->intType == 1)
- offset = 3; /* 3 methods in IUnknown*/
- else
- offset = 7; /* 7 methods in IDispatch*/
-
- return slot + offset;
+ return slot + cominterop_get_com_slot_begin (ic);
}
/**
static MonoReflectionType*
cominterop_get_method_interface (MonoMethod* method)
{
- GPtrArray *ifaces;
MonoType* t = NULL;
- MonoClass *ic = NULL;
- int i;
MonoReflectionType* rt = NULL;
+ MonoClass *ic = method->klass;
- ifaces = mono_class_get_implemented_interfaces (method->klass);
- if (ifaces) {
- int offset;
- for (i = 0; i < ifaces->len; ++i) {
- ic = g_ptr_array_index (ifaces, i);
- offset = method->klass->interface_offsets[ic->interface_id];
- if (method->slot >= offset && method->slot < offset + ic->method.count)
- break;
- ic = NULL;
+ /* if method is on a class, we need to look up interface method exists on */
+ if (!MONO_CLASS_IS_INTERFACE(method->klass)) {
+ GPtrArray *ifaces = mono_class_get_implemented_interfaces (method->klass);
+ if (ifaces) {
+ int i;
+ for (i = 0; i < ifaces->len; ++i) {
+ int offset;
+ ic = g_ptr_array_index (ifaces, i);
+ offset = mono_class_interface_offset (method->klass, ic);
+ if (method->slot >= offset && method->slot < offset + ic->method.count)
+ break;
+ ic = NULL;
+ }
+ g_ptr_array_free (ifaces, TRUE);
}
- g_ptr_array_free (ifaces, TRUE);
}
- if (!ic)
- ic = method->klass;
-
g_assert (ic);
g_assert (MONO_CLASS_IS_INTERFACE (ic));
return rt;
}
+static int
+cominterop_get_hresult_for_exception (MonoException* exc)
+{
+ int hr = 0;
+ return hr;
+}
+
void
mono_marshal_init (void)
{
if (!module_initialized) {
module_initialized = TRUE;
InitializeCriticalSection (&marshal_mutex);
+ InitializeCriticalSection (&cominterop_mutex);
wrapper_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
last_error_tls_id = TlsAlloc ();
load_type_info_tls_id = TlsAlloc ();
register_icall (cominterop_get_method_interface, "cominterop_get_method_interface", "object ptr", FALSE);
register_icall (cominterop_get_function_pointer, "cominterop_get_function_pointer", "ptr ptr int32", FALSE);
register_icall (cominterop_object_is_rcw, "cominterop_object_is_rcw", "int32 object", FALSE);
+ register_icall (cominterop_get_ccw, "cominterop_get_ccw", "ptr object ptr", FALSE);
+ register_icall (cominterop_get_ccw_object, "cominterop_get_ccw_object", "object ptr int32", FALSE);
+ register_icall (cominterop_get_hresult_for_exception, "cominterop_get_hresult_for_exception", "int32 object", FALSE);
}
}
TlsFree (load_type_info_tls_id);
TlsFree (last_error_tls_id);
DeleteCriticalSection (&marshal_mutex);
+ DeleteCriticalSection (&cominterop_mutex);
}
MonoClass *byte_array_class;
// Add the delegate to the delegate hash table
delegate_hash_table_add (delegate);
- /* when the object is collected, collect the dunamic method, too */
+ /* when the object is collected, collect the dynamic method, too */
mono_object_register_finalizer ((MonoObject*)delegate);
return delegate->delegate_trampoline;
}
+/*
+ * this hash table maps from a delegate trampoline object to a weak reference
+ * of the delegate. As an optimizations with a non-moving GC we store the
+ * object pointer itself, otherwise we use a GC handle.
+ */
static GHashTable *delegate_hash_table;
static GHashTable *
static void
delegate_hash_table_remove (MonoDelegate *d)
{
+#ifdef HAVE_MOVING_COLLECTOR
+ guint32 gchandle;
+#endif
mono_marshal_lock ();
if (delegate_hash_table == NULL)
delegate_hash_table = delegate_hash_table_new ();
+#ifdef HAVE_MOVING_COLLECTOR
+ gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (delegate_hash_table, d->delegate_trampoline));
+#endif
g_hash_table_remove (delegate_hash_table, d->delegate_trampoline);
mono_marshal_unlock ();
+#ifdef HAVE_MOVING_COLLECTOR
+ mono_gchandle_free (gchandle);
+#endif
}
-void
+static void
delegate_hash_table_add (MonoDelegate *d)
{
+#ifdef HAVE_MOVING_COLLECTOR
+ guint32 gchandle = mono_gchandle_new_weakref ((MonoObject*)d, FALSE);
+#endif
mono_marshal_lock ();
if (delegate_hash_table == NULL)
delegate_hash_table = delegate_hash_table_new ();
+#ifdef HAVE_MOVING_COLLECTOR
+ g_hash_table_insert (delegate_hash_table, d->delegate_trampoline, GUINT_TO_POINTER (gchandle));
+#else
g_hash_table_insert (delegate_hash_table, d->delegate_trampoline, d);
+#endif
mono_marshal_unlock ();
}
MonoDelegate*
mono_ftnptr_to_delegate (MonoClass *klass, gpointer ftn)
{
+#ifdef HAVE_MOVING_COLLECTOR
+ guint32 gchandle;
+#endif
MonoDelegate *d;
mono_marshal_lock ();
if (delegate_hash_table == NULL)
delegate_hash_table = delegate_hash_table_new ();
+#ifdef HAVE_MOVING_COLLECTOR
+ gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (delegate_hash_table, ftn));
+ mono_marshal_unlock ();
+ if (gchandle)
+ d = (MonoDelegate*)mono_gchandle_get_target (gchandle);
+ else
+ d = NULL;
+#else
d = g_hash_table_lookup (delegate_hash_table, ftn);
mono_marshal_unlock ();
+#endif
if (d == NULL) {
/* This is a native function, so construct a delegate for it */
static MonoClass *UnmanagedFunctionPointerAttribute;
memcpy (native_arr, as, MIN (strlen (as), elnum));
g_free (as);
- }
- else
+ } else {
g_assert_not_reached ();
+ }
}
void
g_free (ut);
}
+/*
+ * FIXME: This routine does not seem to do what it seems to do
+ * the @text is never copied into the string builder
+ */
void
mono_string_utf16_to_builder (MonoStringBuilder *sb, gunichar2 *text)
{
sb->length = len;
}
+/**
+ * mono_string_builder_to_utf8:
+ * @sb: the string builder
+ *
+ * Converts to utf8 the contents of the MonoStringBuilder.
+ *
+ * Returns: a utf8 string with the contents of the StringBuilder.
+ *
+ * The return value must be released with g_free.
+ */
gpointer
mono_string_builder_to_utf8 (MonoStringBuilder *sb)
{
tmp = g_utf16_to_utf8 (mono_string_chars (sb->str), sb->length, NULL, res, &error);
if (error) {
g_error_free (error);
+ mono_marshal_free (res);
mono_raise_exception (mono_get_exception_execution_engine ("Failed to convert StringBuilder from utf16 to utf8"));
- }
- else {
+ } else {
memcpy (res, tmp, sb->length + 1);
g_free (tmp);
}
return res;
}
+/**
+ * mono_string_builder_to_utf16:
+ * @sb: the string builder
+ *
+ * Converts to utf16 the contents of the MonoStringBuilder.
+ *
+ * Returns: a utf16 string with the contents of the StringBuilder.
+ *
+ * The return value must not be freed.
+ */
gpointer
mono_string_builder_to_utf16 (MonoStringBuilder *sb)
{
g_error_free (error);
mono_raise_exception(exc);
return NULL;
- }
- else {
+ } else {
as = CoTaskMemAlloc (len + 1);
memcpy (as, tmp, len + 1);
+ g_free (tmp);
return as;
}
#else
return NULL;
return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
#else
- g_error ("UnmanagedMarshal.BStr is not implemented.");
- return NULL;
+ int slen = mono_string_length (string_obj);
+ char *ret = g_malloc (slen * 2 + 4 + 2);
+ if (ret == NULL)
+ return NULL;
+ memcpy (ret + 4, mono_string_chars (string_obj), slen * 2);
+ * ((guint32 *) ret) = slen * 2;
+ ret [4 + slen * 2] = 0;
+ ret [5 + slen * 2] = 0;
+
+ return ret + 4;
#endif
}
return NULL;
return mono_string_new_utf16 (mono_domain_get (), bstr, SysStringLen (bstr));
#else
- g_error ("UnmanagedMarshal.BStr is not implemented.");
- return NULL;
+ return mono_string_new_utf16 (mono_domain_get (), bstr, *(guint32 *)((char *)bstr - 4));
#endif
}
#ifdef PLATFORM_WIN32
SysFreeString ((BSTR)bstr);
#else
- g_error ("Free BSTR is not implemented.");
+ g_free (((char *)bstr) - 4);
#endif
}
+/**
+ * mono_string_to_byvalstr:
+ * @dst: Where to store the null-terminated utf8 decoded string.
+ * @src: the MonoString to copy.
+ * @size: the maximum number of bytes to copy.
+ *
+ * Copies the MonoString pointed to by @src as a utf8 string
+ * into @dst, it copies at most @size bytes into the destination.
+ */
void
mono_string_to_byvalstr (gpointer dst, MonoString *src, int size)
{
g_assert (size > 0);
memset (dst, 0, size);
-
if (!src)
return;
s = mono_string_to_utf8 (src);
len = MIN (size, strlen (s));
+ if (len >= size)
+ len--;
memcpy (dst, s, len);
g_free (s);
-
- *((char *)dst + size - 1) = 0;
}
+/**
+ * mono_string_to_byvalwstr:
+ * @dst: Where to store the null-terminated utf16 decoded string.
+ * @src: the MonoString to copy.
+ * @size: the maximum number of bytes to copy.
+ *
+ * Copies the MonoString pointed to by @src as a utf16 string into
+ * @dst, it copies at most @size bytes into the destination (including
+ * a terminating 16-bit zero terminator).
+ */
void
mono_string_to_byvalwstr (gpointer dst, MonoString *src, int size)
{
}
len = MIN (size, (mono_string_length (src)));
- memcpy (dst, mono_string_chars (src), len * 2);
-
- *((gunichar2 *)dst + len - 1) = 0;
+ memcpy (dst, mono_string_chars (src), size * 2);
+ if (size <= mono_string_length (src))
+ len--;
+ *((gunichar2 *) dst + len) = 0;
}
void
* Create a MonoMethod from this method builder.
* Returns: the newly created method.
*
- * LOCKING: Assumes the loader lock is held.
+ * LOCKING: Takes the loader lock.
*/
MonoMethod *
mono_mb_create_method (MonoMethodBuilder *mb, MonoMethodSignature *signature, int max_stack)
mp = mb->method->klass->image->mempool;
+ mono_loader_lock ();
if (mb->dynamic) {
method = mb->method;
header->code_size = mb->pos;
header->num_locals = mb->locals;
+ header->init_locals = TRUE;
mw = (MonoMethodWrapper*) mb->method;
i = g_list_length (mw->method_data);
printf ("%s\n", mono_disasm_code (&marshal_dh, method, mb->code, mb->code + mb->pos));
#endif
+ mono_loader_unlock ();
return method;
}
mono_mb_emit_byte (mb, CEE_STIND_REF);
break;
case MONO_MARSHAL_CONV_STR_LPTSTR:
+ mono_mb_emit_ldloc (mb, 1);
+ mono_mb_emit_ldloc (mb, 0);
+ mono_mb_emit_byte (mb, CEE_LDIND_I);
+#ifdef PLATFORM_WIN32
+ mono_mb_emit_icall (mb, mono_string_from_utf16);
+#else
+ mono_mb_emit_icall (mb, mono_string_new_wrapper);
+#endif
+ mono_mb_emit_byte (mb, CEE_STIND_REF);
+ break;
case MONO_MARSHAL_CONV_STR_LPSTR:
mono_mb_emit_ldloc (mb, 1);
mono_mb_emit_ldloc (mb, 0);
static MonoMethod* com_interop_proxy_get_proxy = NULL;
static MonoMethod* get_transparent_proxy = NULL;
int real_proxy;
- guint32 pos_failed = 0;
- MonoClass *klass = mono_class_from_mono_type (type);
+ guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
+ MonoClass *klass = NULL;
+
+ /* COM types are initialized lazily */
+ mono_init_com_types ();
+
+ klass = mono_class_from_mono_type (type);
mono_mb_emit_ldloc (mb, 1);
mono_mb_emit_byte (mb, CEE_LDNULL);
mono_mb_emit_ldloc (mb, 0);
mono_mb_emit_byte (mb, CEE_LDIND_I);
- pos_failed = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
+ pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
+
+ /* load dst to store later */
+ mono_mb_emit_ldloc (mb, 1);
+
+ mono_mb_emit_ldloc (mb, 0);
+ mono_mb_emit_byte (mb, CEE_LDIND_I);
+ mono_mb_emit_icon (mb, TRUE);
+ mono_mb_emit_icall (mb, cominterop_get_ccw_object);
+ pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
if (!com_interop_proxy_class)
com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
mono_mb_emit_ptr (mb, &mono_defaults.com_object_class->byval_arg);
mono_mb_emit_icall (mb, type_from_handle);
mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
- mono_mb_emit_stloc (mb, real_proxy);
-
-
- mono_mb_emit_ldloc (mb, 1);
- mono_mb_emit_ldloc (mb, real_proxy);
mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
- if (klass && klass != mono_defaults.object_class)
+ if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
+ g_assert (klass);
+ mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
+ }
+ mono_mb_emit_byte (mb, CEE_STIND_REF);
+ pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
+
+ /* is already managed object */
+ mono_mb_patch_short_branch (mb, pos_ccw);
+ mono_mb_emit_ldloc (mb, 0);
+ mono_mb_emit_byte (mb, CEE_LDIND_I);
+ mono_mb_emit_icon (mb, TRUE);
+ mono_mb_emit_icall (mb, cominterop_get_ccw_object);
+
+ if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
+ g_assert (klass);
mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
+ }
mono_mb_emit_byte (mb, CEE_STIND_REF);
- // case if null
- mono_mb_patch_short_branch (mb, pos_failed);
+ mono_mb_patch_short_branch (mb, pos_end);
+ /* case if null */
+ mono_mb_patch_short_branch (mb, pos_null);
+ break;
+ }
+
+ case MONO_MARSHAL_CONV_SAFEHANDLE: {
+ /*
+ * Passing SafeHandles as ref does not allow the unmanaged code
+ * to change the SafeHandle value. If the value is changed,
+ * we should issue a diagnostic exception (NotSupportedException)
+ * that informs the user that changes to handles in unmanaged code
+ * is not supported.
+ *
+ * Since we currently have no access to the original
+ * SafeHandle that was used during the marshalling,
+ * for now we just ignore this, and ignore/discard any
+ * changes that might have happened to the handle.
+ */
+ break;
+ }
+
+ case MONO_MARSHAL_CONV_HANDLEREF: {
+ /*
+ * Passing HandleRefs in a struct that is ref()ed does not
+ * copy the values back to the HandleRef
+ */
break;
}
+
case MONO_MARSHAL_CONV_STR_BSTR:
case MONO_MARSHAL_CONV_STR_ANSIBSTR:
case MONO_MARSHAL_CONV_STR_TBSTR:
case MONO_MARSHAL_CONV_LPSTR_STR:
return mono_string_new_wrapper;
case MONO_MARSHAL_CONV_STR_LPTSTR:
+#ifdef PLATFORM_WIN32
+ return mono_marshal_string_to_utf16;
+#else
+ return mono_string_to_lpstr;
+#endif
case MONO_MARSHAL_CONV_STR_LPSTR:
return mono_string_to_lpstr;
case MONO_MARSHAL_CONV_STR_BSTR:
case MONO_MARSHAL_CONV_STR_ANSIBSTR:
return mono_string_to_ansibstr;
case MONO_MARSHAL_CONV_SB_LPSTR:
+ return mono_string_builder_to_utf8;
case MONO_MARSHAL_CONV_SB_LPTSTR:
+#ifdef PLATFORM_WIN32
+ return mono_string_builder_to_utf16;
+#else
return mono_string_builder_to_utf8;
+#endif
case MONO_MARSHAL_CONV_SB_LPWSTR:
return mono_string_builder_to_utf16;
case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
case MONO_MARSHAL_CONV_FTN_DEL:
return mono_ftnptr_to_delegate;
case MONO_MARSHAL_CONV_LPSTR_SB:
+ return mono_string_utf8_to_builder;
case MONO_MARSHAL_CONV_LPTSTR_SB:
+#ifdef PLATFORM_WIN32
+ return mono_string_utf16_to_builder;
+#else
return mono_string_utf8_to_builder;
+#endif
case MONO_MARSHAL_CONV_LPWSTR_SB:
return mono_string_utf16_to_builder;
case MONO_MARSHAL_FREE_ARRAY:
case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: {
- guint32 pos_failed = 0, pos_rcw = 0;
- char * msg;
+ guint32 pos_null = 0, pos_rcw = 0, pos_end = 0;
+
+ /* COM types are initialized lazily */
+ mono_init_com_types ();
+
mono_mb_emit_ldloc (mb, 1);
- //mono_mb_emit_ldloc (mb, 0);
- mono_mb_emit_ptr (mb, 0);
- //mono_mb_emit_byte (mb, CEE_LDIND_U1);
+ mono_mb_emit_icon (mb, 0);
+ mono_mb_emit_byte (mb, CEE_CONV_U);
mono_mb_emit_byte (mb, CEE_STIND_I);
mono_mb_emit_ldloc (mb, 0);
mono_mb_emit_byte (mb, CEE_LDIND_REF);
// if null just break, dst was already inited to 0
- pos_failed = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
+ pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
mono_mb_emit_ldloc (mb, 0);
mono_mb_emit_byte (mb, CEE_LDIND_REF);
mono_mb_emit_managed_call (mb, idispatch->get, NULL);
}
else {
+ g_assert_not_reached ();
}
mono_mb_emit_byte (mb, CEE_STIND_I);
+ pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
// if not rcw
mono_mb_patch_short_branch (mb, pos_rcw);
- msg = g_strdup ("Marshalling of COM Callable Wrappers is not yet implemented.");
- mono_mb_emit_exception_marshal_directive (mb, msg);
+ /* load dst to store later */
+ mono_mb_emit_ldloc (mb, 1);
+ /* load src */
+ mono_mb_emit_ldloc (mb, 0);
+ mono_mb_emit_byte (mb, CEE_LDIND_REF);
+
+ if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE)
+ mono_mb_emit_ptr (mb, mono_type_get_class (type));
+ else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN)
+ mono_mb_emit_ptr (mb, mono_defaults.iunknown_class);
+ else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH)
+ mono_mb_emit_ptr (mb, mono_defaults.idispatch_class);
+ else
+ g_assert_not_reached ();
+ mono_mb_emit_icall (mb, cominterop_get_ccw);
+ mono_mb_emit_byte (mb, CEE_STIND_I);
+
+ mono_mb_patch_short_branch (mb, pos_end);
+ mono_mb_patch_short_branch (mb, pos_null);
+ break;
+ }
- // case if null
- mono_mb_patch_short_branch (mb, pos_failed);
+ case MONO_MARSHAL_CONV_SAFEHANDLE: {
+ int dar_release_slot, pos;
+
+ dar_release_slot = mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
+
+ /*
+ * The following is ifdefed-out, because I have no way of doing the
+ * DangerousRelease when destroying the structure
+ */
+#if 0
+ /* set release = false */
+ mono_mb_emit_icon (mb, 0);
+ mono_mb_emit_stloc (mb, dar_release_slot);
+ if (!sh_dangerous_add_ref)
+ init_safe_handle ();
+
+ /* safehandle.DangerousAddRef (ref release) */
+ mono_mb_emit_ldloc (mb, 0); /* the source */
+ mono_mb_emit_byte (mb, CEE_LDIND_I);
+ mono_mb_emit_ldloc_addr (mb, dar_release_slot);
+ mono_mb_emit_managed_call (mb, sh_dangerous_add_ref, NULL);
+#endif
+ mono_mb_emit_ldloc (mb, 0);
+ mono_mb_emit_byte (mb, CEE_LDIND_I);
+ pos = mono_mb_emit_branch (mb, CEE_BRTRUE);
+ mono_mb_emit_exception (mb, "ArgumentNullException", NULL);
+ mono_mb_patch_branch (mb, pos);
+
+ /* Pull the handle field from SafeHandle */
+ mono_mb_emit_ldloc (mb, 1);
+ mono_mb_emit_ldloc (mb, 0);
+ mono_mb_emit_byte (mb, CEE_LDIND_I);
+ mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoSafeHandle, handle));
+ mono_mb_emit_byte (mb, CEE_LDIND_I);
+ mono_mb_emit_byte (mb, CEE_STIND_I);
break;
}
+
+ case MONO_MARSHAL_CONV_HANDLEREF: {
+ mono_mb_emit_ldloc (mb, 1);
+ mono_mb_emit_ldloc (mb, 0);
+ mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoHandleRef, handle));
+ mono_mb_emit_byte (mb, CEE_ADD);
+ mono_mb_emit_byte (mb, CEE_LDIND_I);
+ mono_mb_emit_byte (mb, CEE_STIND_I);
+ break;
+ }
+
default: {
char *msg = g_strdup_printf ("marshalling conversion %d not implemented", conv);
MonoException *exc = mono_get_exception_not_implemented (msg);
usize = info->fields [i + 1].offset - info->fields [i].offset;
}
- /*
- * FIXME: Should really check for usize==0 and msize>0, but we apply
- * the layout to the managed structure as well.
- */
- if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) && (usize == 0)) {
- if (MONO_TYPE_IS_REFERENCE (info->fields [i].field->type) || ((!last_field && MONO_TYPE_IS_REFERENCE (info->fields [i + 1].field->type))))
- g_error ("Type %s which has an [ExplicitLayout] attribute cannot have a reference field at the same offset as another field.", mono_type_full_name (&klass->byval_arg));
- }
-
- if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT)
- g_error ("Type %s which is passed to unmanaged code must have a StructLayout attribute", mono_type_full_name (&klass->byval_arg));
-
- switch (conv) {
+ if (klass != mono_defaults.safehandle_class){
+ /*
+ * FIXME: Should really check for usize==0 and msize>0, but we apply
+ * the layout to the managed structure as well.
+ */
+
+ if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) && (usize == 0)) {
+ if (MONO_TYPE_IS_REFERENCE (info->fields [i].field->type) ||
+ ((!last_field && MONO_TYPE_IS_REFERENCE (info->fields [i + 1].field->type))))
+ g_error ("Type %s which has an [ExplicitLayout] attribute cannot have a "
+ "reference field at the same offset as another field.",
+ mono_type_full_name (&klass->byval_arg));
+ }
+
+ if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT)
+ g_error ("Type %s which is passed to unmanaged code must have a StructLayout attribute",
+ mono_type_full_name (&klass->byval_arg));
+
+ }
+
+ switch (conv) {
case MONO_MARSHAL_CONV_NONE: {
int t;
break;
}
case MONO_TYPE_OBJECT: {
+ mono_init_com_types ();
if (to_object) {
static MonoMethod *variant_clear = NULL;
static MonoMethod *get_object_for_native_variant = NULL;
+
if (!variant_clear)
variant_clear = mono_class_get_method_from_name (mono_defaults.variant_class, "Clear", 0);
if (!get_object_for_native_variant)
}
else {
static MonoMethod *get_native_variant_for_object = NULL;
+
if (!get_native_variant_for_object)
get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
break;
}
- default:
+ default:
g_warning ("marshaling type %02x not implemented", ftype->type);
g_assert_not_reached ();
}
msg = mono_method_call_message_new (mono_marshal_method_from_wrapper (method), params, NULL, &async_callback, &state);
handle = CreateEvent (NULL, TRUE, FALSE, NULL);
+ g_assert(handle != NULL);
ares = mono_async_result_new (mono_domain_get (), handle, state, handle, NULL);
MONO_OBJECT_SETREF (ares, async_delegate, (MonoObject *)delegate);
MONO_OBJECT_SETREF (ares, async_callback, (MonoObject *)async_callback);
{
MonoMethod *res;
- mono_loader_lock ();
mono_marshal_lock ();
res = g_hash_table_lookup (cache, key);
+ mono_marshal_unlock ();
if (!res) {
- /* This does not acquire any locks */
- res = mono_mb_create_method (mb, sig, max_stack);
- g_hash_table_insert (cache, key, res);
- g_hash_table_insert (wrapper_hash, res, key);
+ MonoMethod *newm;
+ newm = mono_mb_create_method (mb, sig, max_stack);
+ mono_marshal_lock ();
+ res = g_hash_table_lookup (cache, key);
+ if (!res) {
+ res = newm;
+ g_hash_table_insert (cache, key, res);
+ g_hash_table_insert (wrapper_hash, res, key);
+ mono_marshal_unlock ();
+ } else {
+ mono_marshal_unlock ();
+ mono_free_method (newm);
+ }
}
- mono_marshal_unlock ();
- mono_loader_unlock ();
return res;
}
case MONO_WRAPPER_XDOMAIN_DISPATCH: res = wrps->xdomain_dispatch; break;
}
}
-
+
+ /* it is important to do the unlock after the load from wrps, since in
+ * mono_remoting_mb_create_and_cache () we drop the marshal lock to be able
+ * to take the loader lock and some other thread may set the fields.
+ */
mono_marshal_unlock ();
return res;
}
MonoRemotingMethods *wrps;
GHashTable *cache = key->klass->image->remoting_invoke_cache;
- mono_loader_lock ();
mono_marshal_lock ();
wrps = g_hash_table_lookup (cache, key);
if (!wrps) {
case MONO_WRAPPER_XDOMAIN_DISPATCH: res = &wrps->xdomain_dispatch; break;
default: g_assert_not_reached (); break;
}
-
+ mono_marshal_unlock ();
+
if (*res == NULL) {
- /* This does not acquire any locks */
- *res = mono_mb_create_method (mb, sig, max_stack);
- g_hash_table_insert (wrapper_hash, *res, key);
+ MonoMethod *newm;
+ newm = mono_mb_create_method (mb, sig, max_stack);
+
+ mono_marshal_lock ();
+ if (!*res) {
+ *res = newm;
+ g_hash_table_insert (wrapper_hash, *res, key);
+ mono_marshal_unlock ();
+ } else {
+ mono_marshal_unlock ();
+ mono_free_method (newm);
+ }
}
- mono_marshal_unlock ();
- mono_loader_unlock ();
-
return *res;
}
ares = mono_array_get (msg->args, gpointer, sig->param_count - 1);
g_assert (ares);
+ if (ares->async_delegate != (MonoObject*)delegate && mono_get_runtime_info ()->framework_version [0] >= '2') {
+ mono_raise_exception (mono_get_exception_invalid_operation (
+ "The IAsyncResult object provided does not match this delegate."));
+ return NULL;
+ }
+
if (delegate->target && mono_object_class (delegate->target) == mono_defaults.transparent_proxy_class) {
MonoTransparentProxy* tp = (MonoTransparentProxy *)delegate->target;
msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
msg->call_type = CallType_EndInvoke;
MONO_OBJECT_SETREF (msg, async_result, ares);
res = mono_remoting_invoke ((MonoObject *)tp->rp, msg, &exc, &out_args);
- }
- else
+ } else {
res = mono_thread_pool_finish (ares, &out_args, &exc);
+ }
if (exc) {
if (((MonoException*)exc)->stack_trace) {
// create unmanaged wrapper
mb_native = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
- sig_native = signature_cominterop (method->klass->image, sig);
+ sig_native = cominterop_method_signature (method);
mspecs = g_new (MonoMarshalSpec*, sig_native->param_count+1);
memset (mspecs, 0, sizeof(MonoMarshalSpec*)*(sig_native->param_count+1));
// first arg is IntPtr for interface
mspecs[1] = NULL;
- // move return spec to last param
- if (!MONO_TYPE_IS_VOID (sig->ret))
- mspecs[sig_native->param_count] = mspecs[0];
+ if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG)) {
+ // move return spec to last param
+ if (!MONO_TYPE_IS_VOID (sig->ret))
+ mspecs[sig_native->param_count] = mspecs[0];
- mspecs[0] = NULL;
+ mspecs[0] = NULL;
+ }
mono_marshal_emit_native_wrapper(mono_defaults.corlib, mb_native, sig_native, piinfo, mspecs, piinfo->addr);
- mono_loader_lock ();
- mono_marshal_lock ();
res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16);
- mono_marshal_unlock ();
- mono_loader_unlock ();
mono_mb_free (mb_native);
if ((res = mono_marshal_find_in_cache (cache, method)))
return res;
+ mono_init_com_types ();
+
sig = mono_method_signature (method);
mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
static MonoMethod * ThrowExceptionForHR = NULL;
static MonoMethod * GetInterface = NULL;
MonoMethod *adjusted_method;
- int hr;
int retval = 0;
int ptr_this;
int i;
+ gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
if (!GetInterface)
GetInterface = mono_class_get_method_from_name (mono_defaults.com_object_class, "GetInterface", 1);
// add local variables
- hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
ptr_this = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
if (!MONO_TYPE_IS_VOID (sig->ret))
retval = mono_mb_add_local (mb, sig->ret);
mono_mb_emit_ldarg (mb, i);
// push managed return value as byref last argument
- if (!MONO_TYPE_IS_VOID (sig->ret))
+ if (!MONO_TYPE_IS_VOID (sig->ret) && !preserve_sig)
mono_mb_emit_ldloc_addr (mb, retval);
adjusted_method = cominterop_get_native_wrapper_adjusted (method);
mono_mb_emit_managed_call (mb, adjusted_method, NULL);
- // store HRESULT to check
- mono_mb_emit_stloc (mb, hr);
-
- if (!ThrowExceptionForHR)
- ThrowExceptionForHR = mono_class_get_method_from_name (mono_defaults.marshal_class, "ThrowExceptionForHR", 1);
- mono_mb_emit_ldloc (mb, hr);
- mono_mb_emit_managed_call (mb, ThrowExceptionForHR, NULL);
+ if (!preserve_sig) {
+ if (!ThrowExceptionForHR)
+ ThrowExceptionForHR = mono_class_get_method_from_name (mono_defaults.marshal_class, "ThrowExceptionForHR", 1);
+ mono_mb_emit_managed_call (mb, ThrowExceptionForHR, NULL);
- // load return value managed is expecting
- if (!MONO_TYPE_IS_VOID (sig->ret))
- mono_mb_emit_ldloc (mb, retval);
+ // load return value managed is expecting
+ if (!MONO_TYPE_IS_VOID (sig->ret))
+ mono_mb_emit_ldloc (mb, retval);
+ }
mono_mb_emit_byte (mb, CEE_RET);
}
return res;
}
+/* Maps a managed object to its unmanaged representation
+ * i.e. it's COM Callable Wrapper (CCW).
+ * Key: MonoObject*
+ * Value: MonoCCW*
+ */
+static GHashTable* ccw_hash = NULL;
+
+/* Maps a CCW interface to it's containing CCW.
+ * Note that a CCW support many interfaces.
+ * Key: MonoCCW*
+ * Value: MonoCCWInterface*
+ */
+static GHashTable* ccw_interface_hash = NULL;
+
+/* Maps the IUnknown value of a RCW to
+ * it's MonoComInteropProxy*.
+ * Key: void*
+ * Value: gchandle
+ */
+static GHashTable* rcw_hash = NULL;
MonoMethod *
mono_marshal_get_remoting_invoke (MonoMethod *method)
}
}
- if (mono_class_from_mono_type (t) == mono_defaults.stringbuilder_class)
- return MONO_MARSHAL_COPY;
-
return MONO_MARSHAL_SERIALIZE;
}
if (method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)
return method;
- sig = signature_no_pinvoke (method);
-
/* we cant remote methods without this pointer */
- g_assert (sig->hasthis);
+ g_assert (mono_method_signature (method)->hasthis);
if ((res = mono_marshal_remoting_find_in_cache (method, MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)))
return res;
+ sig = signature_no_pinvoke (method);
+
mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK);
for (i = 0; i <= sig->param_count; i++)
MonoMethodBuilder *mb;
MonoMethod *res;
GHashTable *cache;
- int pos0, pos1;
+ int pos0;
char *name;
g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class &&
mono_mb_emit_byte (mb, CEE_LDIND_I );
mono_mb_emit_op (mb, CEE_CALLI, sig);
- pos1 = mono_mb_emit_branch (mb, CEE_BR);
+ mono_mb_emit_byte (mb, CEE_RET);
/* else [target == null] call this->method_ptr static */
mono_mb_patch_branch (mb, pos0);
mono_mb_emit_byte (mb, CEE_LDIND_I );
mono_mb_emit_op (mb, CEE_CALLI, static_sig);
- /* return */
- mono_mb_patch_branch (mb, pos1);
mono_mb_emit_byte (mb, CEE_RET);
res = mono_mb_create_and_cache (cache, sig,
}
typedef struct {
- MonoMethod *ctor;
+ MonoMethodSignature *ctor_sig;
MonoMethodSignature *sig;
} CtorSigPair;
+/* protected by the marshal lock, contains CtorSigPair pointers */
+static GSList *strsig_list = NULL;
+
+static MonoMethodSignature *
+lookup_string_ctor_signature (MonoMethodSignature *sig)
+{
+ MonoMethodSignature *callsig;
+ CtorSigPair *cs;
+ GSList *item;
+
+ mono_marshal_lock ();
+ callsig = NULL;
+ for (item = strsig_list; item; item = item->next) {
+ cs = item->data;
+ /* mono_metadata_signature_equal () is safe to call with the marshal lock
+ * because it is lock-free.
+ */
+ if (mono_metadata_signature_equal (sig, cs->ctor_sig)) {
+ callsig = cs->sig;
+ break;
+ }
+ }
+ mono_marshal_unlock ();
+ return callsig;
+}
+
+static MonoMethodSignature *
+add_string_ctor_signature (MonoMethod *method)
+{
+ MonoMethodSignature *callsig;
+ CtorSigPair *cs;
+
+ callsig = signature_dup (method->klass->image, mono_method_signature (method));
+ callsig->ret = &mono_defaults.string_class->byval_arg;
+ cs = g_new (CtorSigPair, 1);
+ cs->sig = callsig;
+ cs->ctor_sig = mono_method_signature (method);
+ mono_marshal_lock ();
+ strsig_list = g_slist_prepend (strsig_list, cs);
+ mono_marshal_unlock ();
+ return callsig;
+}
/*
* generates IL code for the runtime invoke function
GHashTable *cache = NULL;
MonoClass *target_klass;
MonoMethod *res = NULL;
- GSList *item;
static MonoString *string_dummy = NULL;
static MonoMethodSignature *dealy_abort_sig = NULL;
int i, pos, posna;
g_assert (method);
- target_klass = method->klass;
-
- mono_marshal_lock ();
-
if (method->string_ctor) {
- static GSList *strsig_list = NULL;
- CtorSigPair *cs;
-
- callsig = NULL;
- for (item = strsig_list; item; item = item->next) {
- cs = item->data;
- if (mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cs->ctor))) {
- callsig = cs->sig;
- break;
- }
- }
- if (!callsig) {
- callsig = signature_dup (method->klass->image, mono_method_signature (method));
- callsig->ret = &mono_defaults.string_class->byval_arg;
- cs = g_new (CtorSigPair, 1);
- cs->sig = callsig;
- cs->ctor = method;
- strsig_list = g_slist_prepend (strsig_list, cs);
- }
+ callsig = lookup_string_ctor_signature (mono_method_signature (method));
+ if (!callsig)
+ callsig = add_string_ctor_signature (method);
} else {
if (method->klass->valuetype && mono_method_signature (method)->hasthis) {
/*
}
}
- cache = method->klass->image->runtime_invoke_cache;
+ target_klass = mono_defaults.object_class;
+ /*
+ * if types in the signature belong to non-mscorlib, we cache only
+ * in the method image
+ */
+ if (mono_class_from_mono_type (callsig->ret)->image != mono_defaults.corlib) {
+ target_klass = method->klass;
+ } else {
+ for (i = 0; i < callsig->param_count; i++) {
+ if (mono_class_from_mono_type (callsig->params [i])->image != mono_defaults.corlib) {
+ target_klass = method->klass;
+ break;
+ }
+ }
+ }
+ cache = target_klass->image->runtime_invoke_cache;
/* from mono_marshal_find_in_cache */
+ mono_marshal_lock ();
res = g_hash_table_lookup (cache, callsig);
mono_marshal_unlock ();
dealy_abort_sig->pinvoke = 0;
}
- target_klass = mono_defaults.object_class;
-
/* to make it work with our special string constructors */
if (!string_dummy) {
MONO_GC_REGISTER_ROOT (string_dummy);
sig = mono_method_signature (method);
- csig = mono_metadata_signature_alloc (method->klass->image, 4);
+ csig = mono_metadata_signature_alloc (target_klass->image, 4);
csig->ret = &mono_defaults.object_class->byval_arg;
if (method->klass->valuetype && mono_method_signature (method)->hasthis)
/* fall through */
case MONO_TYPE_VALUETYPE:
- if (t->data.klass->enumtype) {
+ if (type == MONO_TYPE_VALUETYPE && t->data.klass->enumtype) {
type = t->data.klass->enum_basetype->type;
goto handle_enum;
}
mono_mb_emit_byte (mb, CEE_RET);
/* taken from mono_mb_create_and_cache */
- mono_loader_lock ();
mono_marshal_lock ();
-
res = g_hash_table_lookup (cache, callsig);
+ mono_marshal_unlock ();
+
/* Somebody may have created it before us */
if (!res) {
- res = mono_mb_create_method (mb, csig, sig->param_count + 16);
- g_hash_table_insert (cache, callsig, res);
- g_hash_table_insert (wrapper_hash, res, callsig);
+ MonoMethod *newm;
+ newm = mono_mb_create_method (mb, csig, sig->param_count + 16);
+
+ mono_marshal_lock ();
+ res = g_hash_table_lookup (cache, callsig);
+ if (!res) {
+ res = newm;
+ g_hash_table_insert (cache, callsig, res);
+ g_hash_table_insert (wrapper_hash, res, callsig);
+ } else {
+ mono_free_method (newm);
+ }
+ mono_marshal_unlock ();
}
- mono_marshal_unlock ();
- mono_loader_unlock ();
/* end mono_mb_create_and_cache */
mono_mb_free (mb);
} EmitMarshalContext;
typedef enum {
+ /*
+ * This is invoked to convert arguments from the current types to
+ * the underlying types expected by the platform routine. If required,
+ * the methods create a temporary variable with the proper type, and return
+ * the location for it (either the passed argument, or the newly allocated
+ * local slot).
+ */
MARSHAL_ACTION_CONV_IN,
+
+ /*
+ * This operation is called to push the actual value that was optionally
+ * converted on the first stage
+ */
MARSHAL_ACTION_PUSH,
+
+ /*
+ * Convert byref arguments back or free resources allocated during the
+ * CONV_IN stage
+ */
MARSHAL_ACTION_CONV_OUT,
+
+ /*
+ * The result from the unmanaged call is at the top of the stack when
+ * this action is invoked. The result should be stored in the
+ * third local variable slot.
+ */
MARSHAL_ACTION_CONV_RESULT,
+
MARSHAL_ACTION_MANAGED_CONV_IN,
MARSHAL_ACTION_MANAGED_CONV_OUT,
MARSHAL_ACTION_MANAGED_CONV_RESULT
break;
case MARSHAL_ACTION_MANAGED_CONV_IN:
- if (t->byref) {
- conv_arg = 0;
- break;
- }
-
conv_arg = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
mono_mb_emit_byte (mb, CEE_LDNULL);
/* Check for null */
mono_mb_emit_ldarg (mb, argnum);
+ if (t->byref)
+ mono_mb_emit_byte (mb, CEE_LDIND_I);
pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
mono_mb_emit_op (mb, CEE_CALL, get_instance);
mono_mb_emit_ldarg (mb, argnum);
+ if (t->byref)
+ mono_mb_emit_byte (mb, CEE_LDIND_I);
mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed);
mono_mb_emit_stloc (mb, conv_arg);
break;
case MARSHAL_ACTION_MANAGED_CONV_OUT:
- g_assert (!t->byref);
/* Check for null */
mono_mb_emit_ldloc (mb, conv_arg);
pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
+ if (t->byref) {
+ mono_mb_emit_ldarg (mb, argnum);
+
+ mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
+
+ mono_mb_emit_op (mb, CEE_CALL, get_instance);
+
+ mono_mb_emit_ldloc (mb, conv_arg);
+ mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_managed_to_native);
+ mono_mb_emit_byte (mb, CEE_STIND_I);
+ }
+
/* Call CleanUpManagedData */
mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
}
static int
-emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
- MonoMarshalSpec *spec,
- int conv_arg, MonoType **conv_arg_type,
- MarshalAction action)
+emit_marshal_safehandle (EmitMarshalContext *m, int argnum, MonoType *t,
+ MonoMarshalSpec *spec, int conv_arg,
+ MonoType **conv_arg_type, MarshalAction action)
{
MonoMethodBuilder *mb = m->mb;
- MonoClass *klass = t->data.klass;
- int pos, pos2, loc;
- if (mono_class_from_mono_type (t) == mono_defaults.object_class &&
- (!spec || (spec && spec->native != MONO_NATIVE_STRUCT)) &&
- (!spec || (spec && (spec->native != MONO_NATIVE_IUNKNOWN &&
- spec->native != MONO_NATIVE_IDISPATCH &&
- spec->native != MONO_NATIVE_INTERFACE)))) {
- mono_raise_exception (mono_get_exception_not_implemented ("Marshalling of type object is not implemented"));
- }
+ switch (action){
+ case MARSHAL_ACTION_CONV_IN: {
+ MonoType *intptr_type;
+ int dar_release_slot, pos;
- switch (action) {
- case MARSHAL_ACTION_CONV_IN:
- *conv_arg_type = &mono_defaults.int_class->byval_arg;
- conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+ intptr_type = &mono_defaults.int_class->byval_arg;
+ conv_arg = mono_mb_add_local (mb, intptr_type);
+ *conv_arg_type = intptr_type;
- m->orig_conv_args [argnum] = 0;
+ if (!sh_dangerous_add_ref)
+ init_safe_handle ();
- if (spec && spec->native == MONO_NATIVE_STRUCT)
- {
- static MonoMethod *get_native_variant_for_object = NULL;
- int local_variant;
- if (!get_native_variant_for_object)
- get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
+ mono_mb_emit_ldarg (mb, argnum);
+ pos = mono_mb_emit_branch (mb, CEE_BRTRUE);
+ mono_mb_emit_exception (mb, "ArgumentNullException", NULL);
+
+ mono_mb_patch_branch (mb, pos);
+ if (t->byref){
+ /*
+ * My tests in show that ref SafeHandles are not really
+ * passed as ref objects. Instead a NULL is passed as the
+ * value of the ref
+ */
+ mono_mb_emit_icon (mb, 0);
+ mono_mb_emit_stloc (mb, conv_arg);
+ break;
+ }
- *conv_arg_type = &mono_defaults.variant_class->byval_arg;
+ /* Create local to hold the ref parameter to DangerousAddRef */
+ dar_release_slot = mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
- local_variant = mono_mb_add_local (mb, &mono_defaults.variant_class->byval_arg);
- conv_arg = local_variant;
- mono_mb_emit_ldarg (mb, argnum);
- if (t->byref)
- mono_mb_emit_byte(mb, CEE_LDIND_REF);
- mono_mb_emit_ldloc_addr (mb, local_variant);
- mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
- }
- else if (spec && (spec->native == MONO_NATIVE_IUNKNOWN ||
- spec->native == MONO_NATIVE_IDISPATCH ||
- spec->native == MONO_NATIVE_INTERFACE)) {
- mono_mb_emit_ptr (mb, 0);
- mono_mb_emit_stloc (mb, conv_arg);
+ /* set release = false; */
+ mono_mb_emit_icon (mb, 0);
+ mono_mb_emit_stloc (mb, dar_release_slot);
- if (t->byref) {
- /* we dont need any conversions for out parameters */
- if (t->attrs & PARAM_ATTRIBUTE_OUT)
- break;
- else {
- char *msg = g_strdup_printf ("non out object references are no implemented");
- MonoException *exc = mono_get_exception_not_implemented (msg);
- g_warning (msg);
- g_free (msg);
- mono_raise_exception (exc);
+ /* safehandle.DangerousAddRef (ref release) */
+ mono_mb_emit_ldarg (mb, argnum);
+ mono_mb_emit_ldloc_addr (mb, dar_release_slot);
+ mono_mb_emit_managed_call (mb, sh_dangerous_add_ref, NULL);
- }
- } else {
- char *msg = NULL;
- guint32 pos_failed = 0, pos_rcw = 0;
- mono_mb_emit_ldarg (mb, argnum);
- // if null just break, conv arg was already inited to 0
- pos_failed = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
+ /* Pull the handle field from SafeHandle */
+ mono_mb_emit_ldarg (mb, argnum);
+ mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoSafeHandle, handle));
+ mono_mb_emit_byte (mb, CEE_LDIND_I);
+ mono_mb_emit_stloc (mb, conv_arg);
- mono_mb_emit_ldarg (mb, argnum);
- mono_mb_emit_icall (mb, cominterop_object_is_rcw);
- pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
+ break;
+ }
- mono_mb_emit_ldarg (mb, argnum);
- mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp));
- mono_mb_emit_byte (mb, CEE_LDIND_REF);
+ case MARSHAL_ACTION_PUSH:
+ if (t->byref)
+ mono_mb_emit_ldloc_addr (mb, conv_arg);
+ else
+ mono_mb_emit_ldloc (mb, conv_arg);
+ break;
- /* load the RCW from the ComInteropProxy*/
- mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoComInteropProxy, com_object));
- mono_mb_emit_byte (mb, CEE_LDIND_REF);
+ case MARSHAL_ACTION_CONV_OUT: {
+ /* The slot for the boolean is the next temporary created after conv_arg, see the CONV_IN code */
+ int dar_release_slot = conv_arg + 1;
+ int label_next;
- if (klass && klass != mono_defaults.object_class) {
- static MonoMethod* GetInterface = NULL;
-
- if (!GetInterface)
- GetInterface = mono_class_get_method_from_name (mono_defaults.com_object_class, "GetInterface", 1);
- mono_mb_emit_ptr (mb, t);
- mono_mb_emit_icall (mb, type_from_handle);
- mono_mb_emit_managed_call (mb, GetInterface, NULL);
- }
- else if (spec->native == MONO_NATIVE_IUNKNOWN) {
- static MonoProperty* iunknown = NULL;
-
- if (!iunknown)
- iunknown = mono_class_get_property_from_name (mono_defaults.com_object_class, "IUnknown");
- mono_mb_emit_managed_call (mb, iunknown->get, NULL);
- }
- else if (spec->native == MONO_NATIVE_IDISPATCH) {
- static MonoProperty* idispatch = NULL;
-
- if (!idispatch)
- idispatch = mono_class_get_property_from_name (mono_defaults.com_object_class, "IDispatch");
- mono_mb_emit_managed_call (mb, idispatch->get, NULL);
- }
- else {
- }
- mono_mb_emit_stloc (mb, conv_arg);
-
- // if not rcw
- mono_mb_patch_short_branch (mb, pos_rcw);
- msg = g_strdup ("Marshalling of COM Callable Wrappers is not yet implemented.");
- mono_mb_emit_exception_marshal_directive (mb, msg);
+ if (!sh_dangerous_release)
+ init_safe_handle ();
- // case if null
- mono_mb_patch_short_branch (mb, pos_failed);
- }
- }
- else if (klass->delegate) {
- g_assert (!t->byref);
- mono_mb_emit_ldarg (mb, argnum);
- mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN));
- mono_mb_emit_stloc (mb, conv_arg);
- } else if (klass == mono_defaults.stringbuilder_class) {
- MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, spec);
- MonoMarshalConv conv = mono_marshal_get_stringbuilder_to_ptr_conv (m->piinfo, spec);
+ if (t->byref){
+ MonoMethod *ctor;
- g_assert (!t->byref);
- mono_mb_emit_ldarg (mb, argnum);
-
- if (conv != -1)
- mono_mb_emit_icall (mb, conv_to_icall (conv));
- else {
- char *msg = g_strdup_printf ("stringbuilder marshalling conversion %d not implemented", encoding);
- MonoException *exc = mono_get_exception_not_implemented (msg);
- g_warning (msg);
- g_free (msg);
- mono_raise_exception (exc);
+ /*
+ * My tests indicate that ref SafeHandles parameters are not actually
+ * passed by ref, but instead a new Handle is created regardless of
+ * whether a change happens in the unmanaged side.
+ *
+ * Also, the Handle is created before calling into unmanaged code,
+ * but we do not support that mechanism (getting to the original
+ * handle) and it makes no difference where we create this
+ */
+ ctor = mono_class_get_method_from_name (t->data.klass, ".ctor", 0);
+ if (ctor == NULL){
+ mono_mb_emit_exception (mb, "MissingMethodException", "paramterless constructor required");
+ break;
}
-
- mono_mb_emit_stloc (mb, conv_arg);
- } else if (klass->blittable) {
- mono_mb_emit_byte (mb, CEE_LDNULL);
- mono_mb_emit_stloc (mb, conv_arg);
-
+ /* refval = new SafeHandleDerived ()*/
mono_mb_emit_ldarg (mb, argnum);
- pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
+ mono_mb_emit_op (mb, CEE_NEWOBJ, ctor);
+ mono_mb_emit_byte (mb, CEE_STIND_REF);
+ /* refval.handle = returned_handle */
mono_mb_emit_ldarg (mb, argnum);
- mono_mb_emit_ldflda (mb, sizeof (MonoObject));
- mono_mb_emit_stloc (mb, conv_arg);
-
- mono_mb_patch_branch (mb, pos);
- break;
+ mono_mb_emit_byte (mb, CEE_LDIND_REF);
+ mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoSafeHandle, handle));
+ mono_mb_emit_ldloc (mb, conv_arg);
+ mono_mb_emit_byte (mb, CEE_STIND_I);
} else {
- mono_mb_emit_byte (mb, CEE_LDNULL);
- mono_mb_emit_stloc (mb, conv_arg);
+ mono_mb_emit_ldloc (mb, dar_release_slot);
+ label_next = mono_mb_emit_branch (mb, CEE_BRFALSE);
+ mono_mb_emit_ldarg (mb, argnum);
+ mono_mb_emit_managed_call (mb, sh_dangerous_release, NULL);
+ mono_mb_patch_addr (mb, label_next, mb->pos - (label_next + 4));
+ }
+ break;
+ }
+
+ case MARSHAL_ACTION_CONV_RESULT: {
+ MonoMethod *ctor = NULL;
+ int intptr_handle_slot;
+
+ if (t->data.klass->flags & TYPE_ATTRIBUTE_ABSTRACT){
+ mono_mb_emit_byte (mb, CEE_POP);
+ mono_mb_emit_exception_marshal_directive (mb, "Returned SafeHandles should not be abstract");
+ break;
+ }
+
+ ctor = mono_class_get_method_from_name (t->data.klass, ".ctor", 0);
+ if (ctor == NULL){
+ mono_mb_emit_byte (mb, CEE_POP);
+ mono_mb_emit_exception (mb, "MissingMethodException", "paramterless constructor required");
+ break;
+ }
+ /* Store the IntPtr results into a local */
+ intptr_handle_slot = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+ mono_mb_emit_stloc (mb, intptr_handle_slot);
+
+ /* Create return value */
+ mono_mb_emit_op (mb, CEE_NEWOBJ, ctor);
+ mono_mb_emit_stloc (mb, 3);
+
+ /* Set the return.handle to the value, am using ldflda, not sure if thats a good idea */
+ mono_mb_emit_ldloc (mb, 3);
+ mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoSafeHandle, handle));
+ mono_mb_emit_ldloc (mb, intptr_handle_slot);
+ mono_mb_emit_byte (mb, CEE_STIND_I);
+ break;
+ }
+
+ case MARSHAL_ACTION_MANAGED_CONV_IN:
+ fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_IN\n");
+ break;
+
+ case MARSHAL_ACTION_MANAGED_CONV_OUT:
+ fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_OUT\n");
+ break;
+
+ case MARSHAL_ACTION_MANAGED_CONV_RESULT:
+ fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_RESULT\n");
+ break;
+ default:
+ printf ("Unhandled case for MarshalAction: %d\n", action);
+ }
+
+ return conv_arg;
+}
+
+static int
+emit_marshal_handleref (EmitMarshalContext *m, int argnum, MonoType *t,
+ MonoMarshalSpec *spec, int conv_arg,
+ MonoType **conv_arg_type, MarshalAction action)
+{
+ MonoMethodBuilder *mb = m->mb;
+
+ switch (action){
+ case MARSHAL_ACTION_CONV_IN: {
+ MonoType *intptr_type;
+
+ intptr_type = &mono_defaults.int_class->byval_arg;
+ conv_arg = mono_mb_add_local (mb, intptr_type);
+ *conv_arg_type = intptr_type;
+
+ if (t->byref){
+ mono_mb_emit_exception_marshal_directive (mb,
+ "HandleRefs can not be returned from unmanaged code (or passed by ref)");
+ break;
+ }
+ mono_mb_emit_ldarg_addr (mb, argnum);
+ mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoHandleRef, handle));
+ mono_mb_emit_byte (mb, CEE_ADD);
+ mono_mb_emit_byte (mb, CEE_LDIND_I);
+ mono_mb_emit_stloc (mb, conv_arg);
+ break;
+ }
+
+ case MARSHAL_ACTION_PUSH:
+ mono_mb_emit_ldloc (mb, conv_arg);
+ break;
+
+ case MARSHAL_ACTION_CONV_OUT: {
+ /* no resource release required */
+ break;
+ }
+
+ case MARSHAL_ACTION_CONV_RESULT: {
+ mono_mb_emit_exception_marshal_directive (mb,
+ "HandleRefs can not be returned from unmanaged code (or passed by ref)");
+ break;
+ }
+
+ case MARSHAL_ACTION_MANAGED_CONV_IN:
+ fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_IN\n");
+ break;
+
+ case MARSHAL_ACTION_MANAGED_CONV_OUT:
+ fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_OUT\n");
+ break;
+
+ case MARSHAL_ACTION_MANAGED_CONV_RESULT:
+ fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_RESULT\n");
+ break;
+ default:
+ fprintf (stderr, "Unhandled case for MarshalAction: %d\n", action);
+ }
+
+ return conv_arg;
+}
+
+static int
+emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
+ MonoMarshalSpec *spec,
+ int conv_arg, MonoType **conv_arg_type,
+ MarshalAction action)
+{
+ MonoMethodBuilder *mb = m->mb;
+ MonoClass *klass = t->data.klass;
+ int pos, pos2, loc;
+
+ if (mono_class_from_mono_type (t) == mono_defaults.object_class) {
+ mono_raise_exception (mono_get_exception_not_implemented ("Marshalling of type object is not implemented"));
+ }
+
+ switch (action) {
+ case MARSHAL_ACTION_CONV_IN:
+ *conv_arg_type = &mono_defaults.int_class->byval_arg;
+ conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+
+ m->orig_conv_args [argnum] = 0;
+
+ if (klass->delegate) {
+ g_assert (!t->byref);
+ mono_mb_emit_ldarg (mb, argnum);
+ mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN));
+ mono_mb_emit_stloc (mb, conv_arg);
+ } else if (klass == mono_defaults.stringbuilder_class) {
+ MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, spec);
+ MonoMarshalConv conv = mono_marshal_get_stringbuilder_to_ptr_conv (m->piinfo, spec);
+
+ g_assert (!t->byref);
+ mono_mb_emit_ldarg (mb, argnum);
+
+ if (conv != -1)
+ mono_mb_emit_icall (mb, conv_to_icall (conv));
+ else {
+ char *msg = g_strdup_printf ("stringbuilder marshalling conversion %d not implemented", encoding);
+ MonoException *exc = mono_get_exception_not_implemented (msg);
+ g_warning (msg);
+ g_free (msg);
+ mono_raise_exception (exc);
+ }
+
+ mono_mb_emit_stloc (mb, conv_arg);
+ } else if (klass->blittable) {
+ mono_mb_emit_byte (mb, CEE_LDNULL);
+ mono_mb_emit_stloc (mb, conv_arg);
+
+ mono_mb_emit_ldarg (mb, argnum);
+ pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
+
+ mono_mb_emit_ldarg (mb, argnum);
+ mono_mb_emit_ldflda (mb, sizeof (MonoObject));
+ mono_mb_emit_stloc (mb, conv_arg);
+
+ mono_mb_patch_branch (mb, pos);
+ break;
+ } else {
+ mono_mb_emit_byte (mb, CEE_LDNULL);
+ mono_mb_emit_stloc (mb, conv_arg);
if (t->byref) {
/* we dont need any conversions for out parameters */
break;
case MARSHAL_ACTION_CONV_OUT:
- if (spec && spec->native == MONO_NATIVE_STRUCT) {
- static MonoMethod *variant_clear = NULL;
- static MonoMethod *get_object_for_native_variant = NULL;
- if (!variant_clear)
- variant_clear = mono_class_get_method_from_name (mono_defaults.variant_class, "Clear", 0);
- if (!get_object_for_native_variant)
- get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
- if (t->byref) {
- mono_mb_emit_ldarg (mb, argnum);
- mono_mb_emit_ldloc_addr (mb, conv_arg);
- mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
- mono_mb_emit_byte (mb, CEE_STIND_REF);
- }
-
- mono_mb_emit_ldloc_addr (mb, conv_arg);
- mono_mb_emit_managed_call (mb, variant_clear, NULL);
- break;
- }
-
- if (spec && (spec->native == MONO_NATIVE_IUNKNOWN ||
- spec->native == MONO_NATIVE_IDISPATCH ||
- spec->native == MONO_NATIVE_INTERFACE)) {
- if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
- static MonoClass* com_interop_proxy_class = NULL;
- static MonoMethod* com_interop_proxy_get_proxy = NULL;
- static MonoMethod* get_transparent_proxy = NULL;
- int real_proxy;
- guint32 pos_failed = 0;
-
- mono_mb_emit_ldarg (mb, argnum);
- mono_mb_emit_byte (mb, CEE_LDNULL);
- mono_mb_emit_byte (mb, CEE_STIND_REF);
-
- mono_mb_emit_ldloc (mb, conv_arg);
- pos_failed = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
-
- if (!com_interop_proxy_class)
- com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
- if (!com_interop_proxy_get_proxy)
- com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (com_interop_proxy_class, "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE);
- if (!get_transparent_proxy)
- get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
-
- real_proxy = mono_mb_add_local (mb, &com_interop_proxy_class->byval_arg);
-
- mono_mb_emit_ldloc (mb, conv_arg);
- mono_mb_emit_ptr (mb, &mono_defaults.com_object_class->byval_arg);
- mono_mb_emit_icall (mb, type_from_handle);
- mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
- mono_mb_emit_stloc (mb, real_proxy);
-
-
- mono_mb_emit_ldarg (mb, argnum);
- mono_mb_emit_ldloc (mb, real_proxy);
- mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
- if (klass && klass != mono_defaults.object_class)
- mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
- mono_mb_emit_byte (mb, CEE_STIND_REF);
-
- // case if null
- mono_mb_patch_short_branch (mb, pos_failed);
- }
- break;
- }
if (klass == mono_defaults.stringbuilder_class) {
gboolean need_free;
MonoMarshalNative encoding;
mono_mb_emit_ldloc (mb, 0);
mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL));
mono_mb_emit_stloc (mb, 3);
- } else if (spec && (spec->native == MONO_NATIVE_IUNKNOWN ||
- spec->native == MONO_NATIVE_IDISPATCH ||
- spec->native == MONO_NATIVE_INTERFACE)) {
- char *msg = g_strdup ("Marshalling of COM Objects is not yet implemented.");
- mono_mb_emit_exception_marshal_directive (mb, msg);
} else {
/* set src */
mono_mb_emit_stloc (mb, 0);
mono_mb_emit_ldflda (mb, sizeof (MonoObject));
mono_mb_emit_stloc (mb, 0);
- /* Allocate and set dest */
- mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
- mono_mb_emit_byte (mb, CEE_CONV_I);
- mono_mb_emit_icall (mb, mono_marshal_alloc);
- mono_mb_emit_byte (mb, CEE_DUP);
- mono_mb_emit_stloc (mb, 1);
- mono_mb_emit_stloc (mb, 3);
+ /* Allocate and set dest */
+ mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
+ mono_mb_emit_byte (mb, CEE_CONV_I);
+ mono_mb_emit_icall (mb, mono_marshal_alloc);
+ mono_mb_emit_byte (mb, CEE_DUP);
+ mono_mb_emit_stloc (mb, 1);
+ mono_mb_emit_stloc (mb, 3);
+
+ emit_struct_conv (mb, klass, FALSE);
+
+ mono_mb_patch_branch (mb, pos2);
+ break;
+
+ default:
+ g_assert_not_reached ();
+ }
+
+ return conv_arg;
+}
+
+static int
+emit_marshal_com_interface (EmitMarshalContext *m, int argnum, MonoType *t,
+ MonoMarshalSpec *spec,
+ int conv_arg, MonoType **conv_arg_type,
+ MarshalAction action)
+{
+ MonoMethodBuilder *mb = m->mb;
+ MonoClass *klass = t->data.klass;
+ static MonoMethod* get_object_for_iunknown = NULL;
+ static MonoMethod* get_iunknown_for_object_internal = NULL;
+ static MonoMethod* get_com_interface_for_object_internal = NULL;
+ static MonoMethod* get_idispatch_for_object_internal = NULL;
+ if (!get_object_for_iunknown)
+ get_object_for_iunknown = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForIUnknown", 1);
+ if (!get_iunknown_for_object_internal)
+ get_iunknown_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIUnknownForObjectInternal", 1);
+ if (!get_idispatch_for_object_internal)
+ get_idispatch_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIDispatchForObjectInternal", 1);
+ if (!get_com_interface_for_object_internal)
+ get_com_interface_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetComInterfaceForObjectInternal", 2);
+
+ /* COM types are initialized lazily */
+ mono_init_com_types ();
+
+ switch (action) {
+ case MARSHAL_ACTION_CONV_IN: {
+ guint32 pos_null = 0;
+
+ *conv_arg_type = &mono_defaults.int_class->byval_arg;
+ conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+
+ mono_mb_emit_ptr (mb, NULL);
+ mono_mb_emit_stloc (mb, conv_arg);
+
+ /* we dont need any conversions for out parameters */
+ if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
+ break;
+
+ mono_mb_emit_ldarg (mb, argnum);
+ if (t->byref)
+ mono_mb_emit_byte (mb, CEE_LDIND_REF);
+ /* if null just break, conv arg was already inited to 0 */
+ pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
+
+ mono_mb_emit_ldarg (mb, argnum);
+ if (t->byref)
+ mono_mb_emit_byte (mb, CEE_LDIND_REF);
+
+ if (klass && klass != mono_defaults.object_class) {
+ mono_mb_emit_ptr (mb, t);
+ mono_mb_emit_icall (mb, type_from_handle);
+ mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
+ }
+ else if (spec->native == MONO_NATIVE_IUNKNOWN)
+ mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
+ else if (spec->native == MONO_NATIVE_IDISPATCH)
+ mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
+ else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
+ mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
+ else
+ g_assert_not_reached ();
+ mono_mb_emit_stloc (mb, conv_arg);
+ mono_mb_patch_short_branch (mb, pos_null);
+ break;
+ }
+
+ case MARSHAL_ACTION_CONV_OUT: {
+ if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
+ int ccw_obj;
+ guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
+ ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
+
+ mono_mb_emit_ldarg (mb, argnum);
+ mono_mb_emit_byte (mb, CEE_LDNULL);
+ mono_mb_emit_byte (mb, CEE_STIND_REF);
+
+ mono_mb_emit_ldloc (mb, conv_arg);
+ pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
+
+ mono_mb_emit_ldloc (mb, conv_arg);
+ mono_mb_emit_icon (mb, TRUE);
+ mono_mb_emit_icall (mb, cominterop_get_ccw_object);
+ mono_mb_emit_stloc (mb, ccw_obj);
+ mono_mb_emit_ldloc (mb, ccw_obj);
+ pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
+
+ mono_mb_emit_ldarg (mb, argnum);
+ mono_mb_emit_ldloc (mb, conv_arg);
+ mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
+
+ if (klass && klass != mono_defaults.object_class)
+ mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
+ mono_mb_emit_byte (mb, CEE_STIND_REF);
+ pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
+
+ /* is already managed object */
+ mono_mb_patch_short_branch (mb, pos_ccw);
+ mono_mb_emit_ldarg (mb, argnum);
+ mono_mb_emit_ldloc (mb, ccw_obj);
+
+ if (klass && klass != mono_defaults.object_class)
+ mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
+ mono_mb_emit_byte (mb, CEE_STIND_REF);
+
+
+ mono_mb_patch_short_branch (mb, pos_end);
+ /* case if null */
+ mono_mb_patch_short_branch (mb, pos_null);
+ }
+ break;
+ }
+ case MARSHAL_ACTION_PUSH:
+ if (t->byref)
+ mono_mb_emit_ldloc_addr (mb, conv_arg);
+ else
+ mono_mb_emit_ldloc (mb, conv_arg);
+ break;
+
+ case MARSHAL_ACTION_CONV_RESULT: {
+ char *msg = g_strdup ("Marshalling of COM Objects is not yet implemented.");
+ mono_mb_emit_exception_marshal_directive (mb, msg);
+ break;
+ }
+
+ case MARSHAL_ACTION_MANAGED_CONV_IN: {
+ int ccw_obj;
+ guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
+ ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
+
+ klass = mono_class_from_mono_type (t);
+ conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
+ *conv_arg_type = &mono_defaults.int_class->byval_arg;
+
+ mono_mb_emit_byte (mb, CEE_LDNULL);
+ mono_mb_emit_stloc (mb, conv_arg);
+ if (t->attrs & PARAM_ATTRIBUTE_OUT)
+ break;
+
+ mono_mb_emit_ldarg (mb, argnum);
+ if (t->byref)
+ mono_mb_emit_byte (mb, CEE_LDIND_REF);
+ pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
+
+ mono_mb_emit_ldarg (mb, argnum);
+ if (t->byref)
+ mono_mb_emit_byte (mb, CEE_LDIND_REF);
+ mono_mb_emit_icon (mb, TRUE);
+ mono_mb_emit_icall (mb, cominterop_get_ccw_object);
+ mono_mb_emit_stloc (mb, ccw_obj);
+ mono_mb_emit_ldloc (mb, ccw_obj);
+ pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
+
+
+ mono_mb_emit_ldarg (mb, argnum);
+ if (t->byref)
+ mono_mb_emit_byte (mb, CEE_LDIND_REF);
+ mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
+
+ if (klass && klass != mono_defaults.object_class)
+ mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
+ mono_mb_emit_stloc (mb, conv_arg);
+ pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
+
+ /* is already managed object */
+ mono_mb_patch_short_branch (mb, pos_ccw);
+ mono_mb_emit_ldloc (mb, ccw_obj);
+ if (klass && klass != mono_defaults.object_class)
+ mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
+ mono_mb_emit_stloc (mb, conv_arg);
+
+ mono_mb_patch_short_branch (mb, pos_end);
+ /* case if null */
+ mono_mb_patch_short_branch (mb, pos_null);
+ break;
+ }
+
+ case MARSHAL_ACTION_MANAGED_CONV_OUT: {
+ if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) {
+ static MonoMethod* AddRef = NULL;
+ guint32 pos_null = 0;
+
+ if (!AddRef)
+ AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
+
+ mono_mb_emit_ldloc (mb, conv_arg);
+ /* if null just break, conv arg was already inited to 0 */
+ pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
+
+ /* to store later */
+ mono_mb_emit_ldarg (mb, argnum);
+ mono_mb_emit_ldloc (mb, conv_arg);
+ if (klass && klass != mono_defaults.object_class) {
+ mono_mb_emit_ptr (mb, t);
+ mono_mb_emit_icall (mb, type_from_handle);
+ mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
+ }
+ else if (spec->native == MONO_NATIVE_IUNKNOWN)
+ mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
+ else if (spec->native == MONO_NATIVE_IDISPATCH)
+ mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
+ else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
+ mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
+ else
+ g_assert_not_reached ();
+ mono_mb_emit_byte (mb, CEE_STIND_I);
+
+ mono_mb_emit_ldarg (mb, argnum);
+ mono_mb_emit_byte (mb, CEE_LDIND_I);
+ mono_mb_emit_managed_call (mb, AddRef, NULL);
+ mono_mb_emit_byte (mb, CEE_POP);
+
+ mono_mb_patch_short_branch (mb, pos_null);
+ }
+ break;
+ }
+
+ case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
+ char *msg = g_strdup ("Marshalling of COM Objects is not yet implemented.");
+ mono_mb_emit_exception_marshal_directive (mb, msg);
+ break;
+ }
+
+ default:
+ g_assert_not_reached ();
+ }
+
+ return conv_arg;
+}
+
+static int
+emit_marshal_variant (EmitMarshalContext *m, int argnum, MonoType *t,
+ MonoMarshalSpec *spec,
+ int conv_arg, MonoType **conv_arg_type,
+ MarshalAction action)
+{
+ MonoMethodBuilder *mb = m->mb;
+ static MonoMethod *get_object_for_native_variant = NULL;
+ static MonoMethod *get_native_variant_for_object = NULL;
+
+ mono_init_com_types ();
+
+ if (!get_object_for_native_variant)
+ get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
+ g_assert (get_object_for_native_variant);
+
+ if (!get_native_variant_for_object)
+ get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
+ g_assert (get_native_variant_for_object);
+
+ switch (action) {
+ case MARSHAL_ACTION_CONV_IN: {
+ conv_arg = mono_mb_add_local (mb, &mono_defaults.variant_class->byval_arg);
+
+ if (t->byref)
+ *conv_arg_type = &mono_defaults.variant_class->this_arg;
+ else
+ *conv_arg_type = &mono_defaults.variant_class->byval_arg;
+
+ if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
+ break;
+
+ mono_mb_emit_ldarg (mb, argnum);
+ if (t->byref)
+ mono_mb_emit_byte(mb, CEE_LDIND_REF);
+ mono_mb_emit_ldloc_addr (mb, conv_arg);
+ mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
+ break;
+ }
+
+ case MARSHAL_ACTION_CONV_OUT: {
+ static MonoMethod *variant_clear = NULL;
+
+ if (!variant_clear)
+ variant_clear = mono_class_get_method_from_name (mono_defaults.variant_class, "Clear", 0);
+ g_assert (variant_clear);
+
+
+ if (t->byref) {
+ mono_mb_emit_ldarg (mb, argnum);
+ mono_mb_emit_ldloc_addr (mb, conv_arg);
+ mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
+ mono_mb_emit_byte (mb, CEE_STIND_REF);
+ }
+
+ mono_mb_emit_ldloc_addr (mb, conv_arg);
+ mono_mb_emit_managed_call (mb, variant_clear, NULL);
+ break;
+ }
+
+ case MARSHAL_ACTION_PUSH:
+ if (t->byref)
+ mono_mb_emit_ldloc_addr (mb, conv_arg);
+ else
+ mono_mb_emit_ldloc (mb, conv_arg);
+ break;
+
+ case MARSHAL_ACTION_CONV_RESULT: {
+ char *msg = g_strdup ("Marshalling of VARIANT not supported as a return type.");
+ mono_mb_emit_exception_marshal_directive (mb, msg);
+ break;
+ }
+
+ case MARSHAL_ACTION_MANAGED_CONV_IN: {
+ conv_arg = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
+
+ if (t->byref)
+ *conv_arg_type = &mono_defaults.variant_class->this_arg;
+ else
+ *conv_arg_type = &mono_defaults.variant_class->byval_arg;
+
+ if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
+ break;
- emit_struct_conv (mb, klass, FALSE);
+ if (t->byref)
+ mono_mb_emit_ldarg (mb, argnum);
+ else
+ mono_mb_emit_ldarg_addr (mb, argnum);
+ mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
+ mono_mb_emit_stloc (mb, conv_arg);
+ break;
+ }
- mono_mb_patch_branch (mb, pos2);
+ case MARSHAL_ACTION_MANAGED_CONV_OUT: {
+ if (t->byref) {
+ mono_mb_emit_ldloc (mb, conv_arg);
+ mono_mb_emit_ldarg (mb, argnum);
+ mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
+ }
break;
+ }
+
+ case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
+ char *msg = g_strdup ("Marshalling of VARIANT not supported as a return type.");
+ mono_mb_emit_exception_marshal_directive (mb, msg);
+ break;
+ }
default:
g_assert_not_reached ();
static int
emit_marshal_boolean (EmitMarshalContext *m, int argnum, MonoType *t,
- MonoMarshalSpec *spec,
- int conv_arg, MonoType **conv_arg_type,
- MarshalAction action)
+ MonoMarshalSpec *spec,
+ int conv_arg, MonoType **conv_arg_type,
+ MarshalAction action)
{
MonoMethodBuilder *mb = m->mb;
static int
emit_marshal_ptr (EmitMarshalContext *m, int argnum, MonoType *t,
- MonoMarshalSpec *spec, int conv_arg,
- MonoType **conv_arg_type, MarshalAction action)
+ MonoMarshalSpec *spec, int conv_arg,
+ MonoType **conv_arg_type, MarshalAction action)
{
MonoMethodBuilder *mb = m->mb;
static int
emit_marshal_char (EmitMarshalContext *m, int argnum, MonoType *t,
- MonoMarshalSpec *spec, int conv_arg,
- MonoType **conv_arg_type, MarshalAction action)
+ MonoMarshalSpec *spec, int conv_arg,
+ MonoType **conv_arg_type, MarshalAction action)
{
MonoMethodBuilder *mb = m->mb;
static int
emit_marshal_scalar (EmitMarshalContext *m, int argnum, MonoType *t,
- MonoMarshalSpec *spec, int conv_arg,
- MonoType **conv_arg_type, MarshalAction action)
+ MonoMarshalSpec *spec, int conv_arg,
+ MonoType **conv_arg_type, MarshalAction action)
{
MonoMethodBuilder *mb = m->mb;
static int
emit_marshal (EmitMarshalContext *m, int argnum, MonoType *t,
- MonoMarshalSpec *spec, int conv_arg,
- MonoType **conv_arg_type, MarshalAction action)
+ MonoMarshalSpec *spec, int conv_arg,
+ MonoType **conv_arg_type, MarshalAction action)
{
/* Ensure that we have marshalling info for this param */
mono_marshal_load_type_info (mono_class_from_mono_type (t));
switch (t->type) {
case MONO_TYPE_VALUETYPE:
+ if (t->data.klass == mono_defaults.handleref_class)
+ return emit_marshal_handleref (m, argnum, t, spec, conv_arg, conv_arg_type, action);
+
return emit_marshal_vtype (m, argnum, t, spec, conv_arg, conv_arg_type, action);
case MONO_TYPE_STRING:
return emit_marshal_string (m, argnum, t, spec, conv_arg, conv_arg_type, action);
case MONO_TYPE_CLASS:
case MONO_TYPE_OBJECT:
+ if (spec && spec->native == MONO_NATIVE_STRUCT)
+ return emit_marshal_variant (m, argnum, t, spec, conv_arg, conv_arg_type, action);
+
+ if (spec && (spec->native == MONO_NATIVE_IUNKNOWN ||
+ spec->native == MONO_NATIVE_IDISPATCH ||
+ spec->native == MONO_NATIVE_INTERFACE))
+ return emit_marshal_com_interface (m, argnum, t, spec, conv_arg, conv_arg_type, action);
+
+ if (mono_defaults.safehandle_class != NULL &&
+ mono_class_is_subclass_of (t->data.klass, mono_defaults.safehandle_class, FALSE))
+ return emit_marshal_safehandle (m, argnum, t, spec, conv_arg, conv_arg_type, action);
+
return emit_marshal_object (m, argnum, t, spec, conv_arg, conv_arg_type, action);
case MONO_TYPE_ARRAY:
case MONO_TYPE_SZARRAY:
return res;
}
-
-/*
- * generates IL code to call managed methods from unmanaged code
- */
-MonoMethod *
-mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, MonoObject *this)
+
+/* FIXME: moving GC */
+static void
+mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *invoke_sig, MonoMarshalSpec **mspecs, EmitMarshalContext* m, MonoMethod *method, MonoObject* this)
{
- static MonoClass *UnmanagedFunctionPointerAttribute;
- MonoMethodSignature *sig, *csig, *invoke_sig;
- MonoMethodBuilder *mb;
- MonoMethod *res, *invoke;
- MonoMarshalSpec **mspecs;
- MonoMethodPInvoke piinfo;
- GHashTable *cache;
+ MonoMethodSignature *sig, *csig;
int i, *tmp_locals;
- EmitMarshalContext m;
-
- g_assert (method != NULL);
- g_assert (!mono_method_signature (method)->pinvoke);
-
- /*
- * FIXME: Should cache the method+delegate type pair, since the same method
- * could be called with different delegates, thus different marshalling
- * options.
- */
- cache = method->klass->image->managed_wrapper_cache;
- if (!this && (res = mono_marshal_find_in_cache (cache, method)))
- return res;
- invoke = mono_class_get_method_from_name (delegate_klass, "Invoke", mono_method_signature (method)->param_count);
- invoke_sig = mono_method_signature (invoke);
-
- mspecs = g_new0 (MonoMarshalSpec*, mono_method_signature (invoke)->param_count + 1);
- mono_method_get_marshal_info (invoke, mspecs);
-
- sig = mono_method_signature (method);
-
- mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
+ sig = m->sig;
+ csig = m->csig;
/* allocate local 0 (pointer) src_ptr */
mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
mono_mb_emit_icon (mb, 0);
mono_mb_emit_stloc (mb, 2);
- /* we copy the signature, so that we can modify it */
- csig = signature_dup (method->klass->image, sig);
- csig->hasthis = 0;
- csig->pinvoke = 1;
-
- m.mb = mb;
- m.sig = sig;
- m.piinfo = NULL;
- m.retobj_var = 0;
- m.csig = csig;
- m.image = method->klass->image;
-
-#ifdef PLATFORM_WIN32
- /*
- * Under windows, delegates passed to native code must use the STDCALL
- * calling convention.
- */
- csig->call_convention = MONO_CALL_STDCALL;
-#endif
-
- /* Change default calling convention if needed */
- /* Why is this a modopt ? */
- if (invoke_sig->ret && invoke_sig->ret->num_mods) {
- for (i = 0; i < invoke_sig->ret->num_mods; ++i) {
- MonoClass *cmod_class = mono_class_get (delegate_klass->image, invoke_sig->ret->modifiers [i].token);
- g_assert (cmod_class);
- if ((cmod_class->image == mono_defaults.corlib) && !strcmp (cmod_class->name_space, "System.Runtime.CompilerServices")) {
- if (!strcmp (cmod_class->name, "CallConvCdecl"))
- csig->call_convention = MONO_CALL_C;
- else if (!strcmp (cmod_class->name, "CallConvStdcall"))
- csig->call_convention = MONO_CALL_STDCALL;
- else if (!strcmp (cmod_class->name, "CallConvFastcall"))
- csig->call_convention = MONO_CALL_FASTCALL;
- else if (!strcmp (cmod_class->name, "CallConvThiscall"))
- csig->call_convention = MONO_CALL_THISCALL;
- }
- }
- }
-
- /* Handle the UnmanagedFunctionPointerAttribute */
- if (!UnmanagedFunctionPointerAttribute)
- UnmanagedFunctionPointerAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "UnmanagedFunctionPointerAttribute");
-
- /* The attribute is only available in Net 2.0 */
- if (UnmanagedFunctionPointerAttribute) {
- MonoReflectionUnmanagedFunctionPointerAttribute *attr;
- MonoCustomAttrInfo *cinfo;
-
- /*
- * The pinvoke attributes are stored in a real custom attribute so we have to
- * construct it.
- */
- cinfo = mono_custom_attrs_from_class (delegate_klass);
- if (cinfo) {
- attr = (MonoReflectionUnmanagedFunctionPointerAttribute*)mono_custom_attrs_get_attr (cinfo, UnmanagedFunctionPointerAttribute);
- if (attr) {
- memset (&piinfo, 0, sizeof (piinfo));
- m.piinfo = &piinfo;
- piinfo.piflags = (attr->call_conv << 8) | (attr->charset ? (attr->charset - 1) * 2 : 1) | attr->set_last_error;
-
- csig->call_convention = attr->call_conv - 1;
- }
- if (!cinfo->cached)
- mono_custom_attrs_free (cinfo);
- }
- }
-
/* fixme: howto handle this ? */
if (sig->hasthis) {
if (this) {
+ /* FIXME: need a solution for the moving GC here */
mono_mb_emit_ptr (mb, this);
} else {
/* fixme: */
case MONO_TYPE_ARRAY:
case MONO_TYPE_SZARRAY:
case MONO_TYPE_STRING:
- tmp_locals [i] = emit_marshal (&m, i, sig->params [i], mspecs [i + 1], 0, &csig->params [i], MARSHAL_ACTION_MANAGED_CONV_IN);
+ tmp_locals [i] = emit_marshal (m, i, sig->params [i], mspecs [i + 1], 0, &csig->params [i], MARSHAL_ACTION_MANAGED_CONV_IN);
break;
default:
mono_mb_emit_managed_call (mb, method, NULL);
if (mspecs [0] && mspecs [0]->native == MONO_NATIVE_CUSTOM) {
- emit_marshal (&m, 0, sig->ret, mspecs [0], 0, NULL, MARSHAL_ACTION_MANAGED_CONV_RESULT);
+ emit_marshal (m, 0, sig->ret, mspecs [0], 0, NULL, MARSHAL_ACTION_MANAGED_CONV_RESULT);
}
else
if (!sig->ret->byref) {
break;
case MONO_TYPE_STRING:
csig->ret = &mono_defaults.int_class->byval_arg;
- emit_marshal (&m, 0, sig->ret, mspecs [0], 0, NULL, MARSHAL_ACTION_MANAGED_CONV_RESULT);
+ emit_marshal (m, 0, sig->ret, mspecs [0], 0, NULL, MARSHAL_ACTION_MANAGED_CONV_RESULT);
break;
case MONO_TYPE_VALUETYPE:
case MONO_TYPE_CLASS:
case MONO_TYPE_SZARRAY:
- emit_marshal (&m, 0, sig->ret, mspecs [0], 0, NULL, MARSHAL_ACTION_MANAGED_CONV_RESULT);
+ emit_marshal (m, 0, sig->ret, mspecs [0], 0, NULL, MARSHAL_ACTION_MANAGED_CONV_RESULT);
break;
default:
g_warning ("return type 0x%02x unknown", sig->ret->type);
mono_mb_emit_stloc (mb, 3);
}
- /* Convert byref arguments back */
- for (i = 0; i < sig->param_count; i ++) {
- MonoType *t = sig->params [i];
- MonoMarshalSpec *spec = mspecs [i + 1];
+ /* Convert byref arguments back */
+ for (i = 0; i < sig->param_count; i ++) {
+ MonoType *t = sig->params [i];
+ MonoMarshalSpec *spec = mspecs [i + 1];
+
+ if (spec && spec->native == MONO_NATIVE_CUSTOM) {
+ emit_marshal (m, i, t, mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_MANAGED_CONV_OUT);
+ }
+ else if (t->byref) {
+ switch (t->type) {
+ case MONO_TYPE_CLASS:
+ case MONO_TYPE_VALUETYPE:
+ case MONO_TYPE_OBJECT:
+ emit_marshal (m, i, t, mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_MANAGED_CONV_OUT);
+ break;
+ }
+ }
+ else if (invoke_sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT) {
+ /* The [Out] information is encoded in the delegate signature */
+ switch (t->type) {
+ case MONO_TYPE_SZARRAY:
+ case MONO_TYPE_CLASS:
+ case MONO_TYPE_VALUETYPE:
+ emit_marshal (m, i, invoke_sig->params [i], mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_MANAGED_CONV_OUT);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ }
+ }
+
+ if (m->retobj_var) {
+ mono_mb_emit_ldloc (mb, m->retobj_var);
+ mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+ mono_mb_emit_op (mb, CEE_MONO_RETOBJ, m->retobj_class);
+ }
+ else {
+ if (!MONO_TYPE_IS_VOID(sig->ret))
+ mono_mb_emit_ldloc (mb, 3);
+ mono_mb_emit_byte (mb, CEE_RET);
+ }
+}
+
+
+/*
+ * generates IL code to call managed methods from unmanaged code
+ */
+MonoMethod *
+mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, MonoObject *this)
+{
+ static MonoClass *UnmanagedFunctionPointerAttribute;
+ MonoMethodSignature *sig, *csig, *invoke_sig;
+ MonoMethodBuilder *mb;
+ MonoMethod *res, *invoke;
+ MonoMarshalSpec **mspecs;
+ MonoMethodPInvoke piinfo;
+ GHashTable *cache;
+ int i;
+ EmitMarshalContext m;
+
+ g_assert (method != NULL);
+ g_assert (!mono_method_signature (method)->pinvoke);
+
+ /*
+ * FIXME: Should cache the method+delegate type pair, since the same method
+ * could be called with different delegates, thus different marshalling
+ * options.
+ */
+ cache = method->klass->image->managed_wrapper_cache;
+ if (!this && (res = mono_marshal_find_in_cache (cache, method)))
+ return res;
+
+ invoke = mono_class_get_method_from_name (delegate_klass, "Invoke", mono_method_signature (method)->param_count);
+ invoke_sig = mono_method_signature (invoke);
+
+ mspecs = g_new0 (MonoMarshalSpec*, mono_method_signature (invoke)->param_count + 1);
+ mono_method_get_marshal_info (invoke, mspecs);
+
+ sig = mono_method_signature (method);
+
+ mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
+
+
+ /* we copy the signature, so that we can modify it */
+ csig = signature_dup (method->klass->image, sig);
+ csig->hasthis = 0;
+ csig->pinvoke = 1;
+
+ m.mb = mb;
+ m.sig = sig;
+ m.piinfo = NULL;
+ m.retobj_var = 0;
+ m.csig = csig;
+ m.image = method->klass->image;
+
+#ifdef PLATFORM_WIN32
+ /*
+ * Under windows, delegates passed to native code must use the STDCALL
+ * calling convention.
+ */
+ csig->call_convention = MONO_CALL_STDCALL;
+#endif
+
+ /* Change default calling convention if needed */
+ /* Why is this a modopt ? */
+ if (invoke_sig->ret && invoke_sig->ret->num_mods) {
+ for (i = 0; i < invoke_sig->ret->num_mods; ++i) {
+ MonoClass *cmod_class = mono_class_get (delegate_klass->image, invoke_sig->ret->modifiers [i].token);
+ g_assert (cmod_class);
+ if ((cmod_class->image == mono_defaults.corlib) && !strcmp (cmod_class->name_space, "System.Runtime.CompilerServices")) {
+ if (!strcmp (cmod_class->name, "CallConvCdecl"))
+ csig->call_convention = MONO_CALL_C;
+ else if (!strcmp (cmod_class->name, "CallConvStdcall"))
+ csig->call_convention = MONO_CALL_STDCALL;
+ else if (!strcmp (cmod_class->name, "CallConvFastcall"))
+ csig->call_convention = MONO_CALL_FASTCALL;
+ else if (!strcmp (cmod_class->name, "CallConvThiscall"))
+ csig->call_convention = MONO_CALL_THISCALL;
+ }
+ }
+ }
+
+ /* Handle the UnmanagedFunctionPointerAttribute */
+ if (!UnmanagedFunctionPointerAttribute)
+ UnmanagedFunctionPointerAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "UnmanagedFunctionPointerAttribute");
- if (spec && spec->native == MONO_NATIVE_CUSTOM) {
- emit_marshal (&m, i, t, mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_MANAGED_CONV_OUT);
- }
- else if (t->byref) {
- switch (t->type) {
- case MONO_TYPE_CLASS:
- case MONO_TYPE_VALUETYPE:
- emit_marshal (&m, i, t, mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_MANAGED_CONV_OUT);
- break;
- }
- }
- else if (invoke_sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT) {
- /* The [Out] information is encoded in the delegate signature */
- switch (t->type) {
- case MONO_TYPE_SZARRAY:
- case MONO_TYPE_CLASS:
- case MONO_TYPE_VALUETYPE:
- emit_marshal (&m, i, invoke_sig->params [i], mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_MANAGED_CONV_OUT);
- break;
- default:
- g_assert_not_reached ();
+ /* The attribute is only available in Net 2.0 */
+ if (UnmanagedFunctionPointerAttribute) {
+ MonoReflectionUnmanagedFunctionPointerAttribute *attr;
+ MonoCustomAttrInfo *cinfo;
+
+ /*
+ * The pinvoke attributes are stored in a real custom attribute so we have to
+ * construct it.
+ */
+ cinfo = mono_custom_attrs_from_class (delegate_klass);
+ if (cinfo) {
+ attr = (MonoReflectionUnmanagedFunctionPointerAttribute*)mono_custom_attrs_get_attr (cinfo, UnmanagedFunctionPointerAttribute);
+ if (attr) {
+ memset (&piinfo, 0, sizeof (piinfo));
+ m.piinfo = &piinfo;
+ piinfo.piflags = (attr->call_conv << 8) | (attr->charset ? (attr->charset - 1) * 2 : 1) | attr->set_last_error;
+
+ csig->call_convention = attr->call_conv - 1;
}
+ if (!cinfo->cached)
+ mono_custom_attrs_free (cinfo);
}
}
- if (m.retobj_var) {
- mono_mb_emit_ldloc (mb, m.retobj_var);
- mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
- mono_mb_emit_op (mb, CEE_MONO_RETOBJ, m.retobj_class);
- }
- else {
- if (!MONO_TYPE_IS_VOID(sig->ret))
- mono_mb_emit_ldloc (mb, 3);
- mono_mb_emit_byte (mb, CEE_RET);
- }
+ mono_marshal_emit_managed_wrapper (mb, invoke_sig, mspecs, &m, method, this);
if (!this)
res = mono_mb_create_and_cache (cache, method,
return ret;
}
+typedef struct {
+ int rank;
+ int elem_size;
+ MonoMethod *method;
+} ArrayElemAddr;
+
+/* LOCKING: vars accessed under the marshal lock */
+static ArrayElemAddr *elem_addr_cache = NULL;
+static int elem_addr_cache_size = 0;
+static int elem_addr_cache_next = 0;
+
+/**
+ * mono_marshal_get_array_address:
+ * @rank: rank of the array type
+ * @elem_size: size in bytes of an element of an array.
+ *
+ * Returns a MonoMethd that implements the code to get the address
+ * of an element in a multi-dimenasional array of @rank dimensions.
+ * The returned method takes an array as the first argument and then
+ * @rank indexes for the @rank dimensions.
+ */
+MonoMethod*
+mono_marshal_get_array_address (int rank, int elem_size)
+{
+ MonoMethod *ret;
+ MonoMethodBuilder *mb;
+ MonoMethodSignature *sig;
+ int i, bounds, ind, realidx;
+ int branch_pos, *branch_positions;
+ int cached;
+
+ ret = NULL;
+ mono_marshal_lock ();
+ for (i = 0; i < elem_addr_cache_next; ++i) {
+ if (elem_addr_cache [i].rank == rank && elem_addr_cache [i].elem_size == elem_size) {
+ ret = elem_addr_cache [i].method;
+ break;
+ }
+ }
+ mono_marshal_unlock ();
+ if (ret)
+ return ret;
+
+ branch_positions = g_new0 (int, rank);
+
+ sig = mono_metadata_signature_alloc (mono_defaults.corlib, 1 + rank);
+
+ /* void* address (void* array, int idx0, int idx1, int idx2, ...) */
+ sig->ret = &mono_defaults.int_class->byval_arg;
+ sig->params [0] = &mono_defaults.object_class->byval_arg;
+ for (i = 0; i < rank; ++i) {
+ sig->params [i + 1] = &mono_defaults.int32_class->byval_arg;
+ }
+
+ mb = mono_mb_new (mono_defaults.object_class, "ElementAddr", MONO_WRAPPER_MANAGED_TO_MANAGED);
+
+ bounds = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+ ind = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
+ realidx = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
+
+ /* bounds = array->bounds; */
+ mono_mb_emit_ldarg (mb, 0);
+ mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoArray, bounds));
+ mono_mb_emit_byte (mb, CEE_LDIND_I);
+ mono_mb_emit_stloc (mb, bounds);
+
+ /* ind is the overall element index, realidx is the partial index in a single dimension */
+ /* ind = idx0 - bounds [0].lower_bound */
+ mono_mb_emit_ldarg (mb, 1);
+ mono_mb_emit_ldloc (mb, bounds);
+ mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
+ mono_mb_emit_byte (mb, CEE_ADD);
+ mono_mb_emit_byte (mb, CEE_LDIND_I4);
+ mono_mb_emit_byte (mb, CEE_SUB);
+ mono_mb_emit_stloc (mb, ind);
+ /* if (ind >= bounds [0].length) goto exeception; */
+ mono_mb_emit_ldloc (mb, ind);
+ mono_mb_emit_ldloc (mb, bounds);
+ mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoArrayBounds, length));
+ mono_mb_emit_byte (mb, CEE_ADD);
+ mono_mb_emit_byte (mb, CEE_LDIND_I4);
+ /* note that we use unsigned comparison */
+ branch_pos = mono_mb_emit_branch (mb, CEE_BGE_UN);
+
+ /* For large ranks (> 4?) use a loop n IL later to reduce code size.
+ * We could also decide to ignore the passed elem_size and get it
+ * from the array object, to reduce the number of methods we generate:
+ * the additional cost is 3 memory loads and a non-immediate mul.
+ */
+ for (i = 1; i < rank; ++i) {
+ /* realidx = idxi - bounds [i].lower_bound */
+ mono_mb_emit_ldarg (mb, 1 + i);
+ mono_mb_emit_ldloc (mb, bounds);
+ mono_mb_emit_icon (mb, (i * sizeof (MonoArrayBounds)) + G_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
+ mono_mb_emit_byte (mb, CEE_ADD);
+ mono_mb_emit_byte (mb, CEE_LDIND_I4);
+ mono_mb_emit_byte (mb, CEE_SUB);
+ mono_mb_emit_stloc (mb, realidx);
+ /* if (realidx >= bounds [i].length) goto exeception; */
+ mono_mb_emit_ldloc (mb, realidx);
+ mono_mb_emit_ldloc (mb, bounds);
+ mono_mb_emit_icon (mb, (i * sizeof (MonoArrayBounds)) + G_STRUCT_OFFSET (MonoArrayBounds, length));
+ mono_mb_emit_byte (mb, CEE_ADD);
+ mono_mb_emit_byte (mb, CEE_LDIND_I4);
+ branch_positions [i] = mono_mb_emit_branch (mb, CEE_BGE_UN);
+ /* ind = ind * bounds [i].length + realidx */
+ mono_mb_emit_ldloc (mb, ind);
+ mono_mb_emit_ldloc (mb, bounds);
+ mono_mb_emit_icon (mb, (i * sizeof (MonoArrayBounds)) + G_STRUCT_OFFSET (MonoArrayBounds, length));
+ mono_mb_emit_byte (mb, CEE_ADD);
+ mono_mb_emit_byte (mb, CEE_LDIND_I4);
+ mono_mb_emit_byte (mb, CEE_MUL);
+ mono_mb_emit_ldloc (mb, realidx);
+ mono_mb_emit_byte (mb, CEE_ADD);
+ mono_mb_emit_stloc (mb, ind);
+ }
+
+ /* return array->vector + ind * element_size */
+ mono_mb_emit_ldarg (mb, 0);
+ mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoArray, vector));
+ mono_mb_emit_ldloc (mb, ind);
+ mono_mb_emit_icon (mb, elem_size);
+ mono_mb_emit_byte (mb, CEE_MUL);
+ mono_mb_emit_byte (mb, CEE_ADD);
+ mono_mb_emit_byte (mb, CEE_RET);
+
+ /* patch the branches to get here and throw */
+ for (i = 1; i < rank; ++i) {
+ mono_mb_patch_branch (mb, branch_positions [i]);
+ }
+ mono_mb_patch_branch (mb, branch_pos);
+ /* throw exception */
+ mono_mb_emit_exception (mb, "IndexOutOfRangeException", NULL);
+
+ g_free (branch_positions);
+ ret = mono_mb_create_method (mb, sig, 4);
+ mono_mb_free (mb);
+
+ /* cache the result */
+ cached = 0;
+ mono_marshal_lock ();
+ for (i = 0; i < elem_addr_cache_next; ++i) {
+ if (elem_addr_cache [i].rank == rank && elem_addr_cache [i].elem_size == elem_size) {
+ /* FIXME: free ret */
+ ret = elem_addr_cache [i].method;
+ cached = TRUE;
+ break;
+ }
+ }
+ if (!cached) {
+ if (elem_addr_cache_next >= elem_addr_cache_size) {
+ int new_size = elem_addr_cache_size + 4;
+ ArrayElemAddr *new_array = g_new0 (ArrayElemAddr, new_size);
+ memcpy (new_array, elem_addr_cache, elem_addr_cache_size * sizeof (ArrayElemAddr));
+ g_free (elem_addr_cache);
+ elem_addr_cache = new_array;
+ elem_addr_cache_size = new_size;
+ }
+ elem_addr_cache [elem_addr_cache_next].rank = rank;
+ elem_addr_cache [elem_addr_cache_next].elem_size = elem_size;
+ elem_addr_cache [elem_addr_cache_next].method = ret;
+ }
+ mono_marshal_unlock ();
+ return ret;
+}
+
MonoMethod*
mono_marshal_get_write_barrier (void)
{
g_free (ptr [i]);
}
-void *
-mono_marshal_realloc (gpointer ptr, gpointer size)
-{
- MONO_ARCH_SAVE_REGS;
-
- return g_try_realloc (ptr, (gulong)size);
-}
-
void *
mono_marshal_string_to_utf16 (MonoString *s)
{
MONO_CHECK_ARG_NULL (src);
MONO_CHECK_ARG_NULL (dest);
- g_assert (src->obj.vtable->klass->rank == 1);
- g_assert (start_index >= 0);
- g_assert (length >= 0);
- g_assert (start_index + length <= mono_array_length (src));
+ if (src->obj.vtable->klass->rank != 1)
+ mono_raise_exception (mono_get_exception_argument ("array", "array is multi-dimensional"));
+ if (start_index < 0)
+ mono_raise_exception (mono_get_exception_argument ("startIndex", "Must be >= 0"));
+ if (length < 0)
+ mono_raise_exception (mono_get_exception_argument ("length", "Must be >= 0"));
+ if (start_index + length > mono_array_length (src))
+ mono_raise_exception (mono_get_exception_argument ("length", "start_index + length > array length"));
element_size = mono_array_element_size (src->obj.vtable->klass);
MONO_CHECK_ARG_NULL (src);
MONO_CHECK_ARG_NULL (dest);
- g_assert (dest->obj.vtable->klass->rank == 1);
- g_assert (start_index >= 0);
- g_assert (length >= 0);
- g_assert (start_index + length <= mono_array_length (dest));
+ if (dest->obj.vtable->klass->rank != 1)
+ mono_raise_exception (mono_get_exception_argument ("array", "array is multi-dimensional"));
+ if (start_index < 0)
+ mono_raise_exception (mono_get_exception_argument ("startIndex", "Must be >= 0"));
+ if (length < 0)
+ mono_raise_exception (mono_get_exception_argument ("length", "Must be >= 0"));
+ if (start_index + length > mono_array_length (dest))
+ mono_raise_exception (mono_get_exception_argument ("length", "start_index + length > array length"));
element_size = mono_array_element_size (dest->obj.vtable->klass);
mono_raise_exception (mono_get_exception_argument_null ("ptr"));
g_assert_not_reached ();
return NULL;
- } else
+ } else {
return mono_string_new_len (mono_domain_get (), ptr, len);
+ }
}
MonoString *
mono_raise_exception (mono_get_exception_argument_null ("ptr"));
g_assert_not_reached ();
return NULL;
- } else
+ } else {
return mono_string_new_utf16 (domain, ptr, len);
+ }
}
MonoString *
return mono_string_to_bstr(ptr);
}
-// STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM
-#ifdef PLATFORM_WIN32
-#ifdef _MSC_VER
-#define STDCALL __stdcall
-#else
-#define STDCALL __attribute__((stdcall))
-#endif
-#else
-#define STDCALL
-#endif
-
typedef struct
{
int (STDCALL *QueryInterface)(gpointer pUnk, gpointer riid, gpointer* ppv);
}
int
-ves_icall_System_Runtime_InteropServices_Marshal_AddRef (gpointer pUnk)
+ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
{
- MONO_ARCH_SAVE_REGS;
-
+ g_assert (pUnk);
return (*(MonoIUnknown**)pUnk)->AddRef(pUnk);
}
int
-ves_icall_System_Runtime_InteropServices_Marshal_QueryInterface (gpointer pUnk, gpointer riid, gpointer* ppv)
+ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
{
- MONO_ARCH_SAVE_REGS;
-
+ g_assert (pUnk);
return (*(MonoIUnknown**)pUnk)->QueryInterface(pUnk, riid, ppv);
}
int
-ves_icall_System_Runtime_InteropServices_Marshal_Release (gpointer pUnk)
+ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
{
- MONO_ARCH_SAVE_REGS;
-
+ g_assert (pUnk);
return (*(MonoIUnknown**)pUnk)->Release(pUnk);
}
+static void*
+cominterop_get_idispatch_for_object (MonoObject* object)
+{
+ if (!object)
+ return NULL;
+
+ if (cominterop_object_is_rcw (object)) {
+ /* FIXME: Implement this case */
+ g_assert_not_reached ();
+ return NULL;
+ }
+ else {
+ return cominterop_get_ccw (object, mono_defaults.idispatch_class);
+ }
+}
+
+void*
+ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObject* object)
+{
+ if (!object)
+ return NULL;
+
+ if (cominterop_object_is_rcw (object)) {
+ MonoClass *klass = NULL;
+ MonoRealProxy* real_proxy = NULL;
+ if (!object)
+ return NULL;
+ klass = mono_object_class (object);
+ if (klass != mono_defaults.transparent_proxy_class) {
+ g_assert_not_reached ();
+ return NULL;
+ }
+
+ real_proxy = ((MonoTransparentProxy*)object)->rp;
+ if (!real_proxy) {
+ g_assert_not_reached ();
+ return NULL;
+ }
+
+ klass = mono_object_class (real_proxy);
+ if (klass != mono_defaults.com_interop_proxy_class) {
+ g_assert_not_reached ();
+ return NULL;
+ }
+
+ if (!((MonoComInteropProxy*)real_proxy)->com_object) {
+ g_assert_not_reached ();
+ return NULL;
+ }
+
+ return ((MonoComInteropProxy*)real_proxy)->com_object->iunknown;
+ }
+ else {
+ return cominterop_get_ccw (object, mono_defaults.iunknown_class);
+ }
+}
+
+MonoObject*
+ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk)
+{
+ MonoObject* object = NULL;
+
+ if (!pUnk)
+ return NULL;
+
+ /* see if it is a CCW */
+ object = cominterop_get_ccw_object ((MonoCCWInterface*)pUnk, TRUE);
+
+ return object;
+}
+
+void*
+ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject* object)
+{
+ return cominterop_get_idispatch_for_object (object);
+}
+
+void*
+ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObject* object, MonoReflectionType* type)
+{
+ MonoClass* klass = NULL;
+ void* itf = NULL;
+ g_assert (type);
+ g_assert (type->type);
+ klass = mono_type_get_class (type->type);
+ g_assert (klass);
+ itf = cominterop_get_ccw (object, klass);
+ g_assert (itf);
+ return itf;
+}
+
+
+MonoBoolean
+ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObject* object)
+{
+ return (MonoBoolean)cominterop_object_is_rcw (object);
+}
+
+gint32
+ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObject* object)
+{
+ MonoComInteropProxy* proxy = NULL;
+ gint32 ref_count = 0;
+
+ g_assert (object);
+ g_assert (cominterop_object_is_rcw (object));
+
+ proxy = (MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp;
+ g_assert (proxy);
+
+ ref_count = InterlockedDecrement (&proxy->ref_count);
+ g_assert (ref_count >= 0);
+
+ if (ref_count == 0)
+ ves_icall_System_ComObject_ReleaseInterfaces (proxy->com_object);
+
+ return ref_count;
+}
+
guint32
ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethod *m)
{
case MONO_MARSHAL_CONV_STR_LPWSTR:
/* We assume this field points inside a MonoString */
break;
- case MONO_MARSHAL_CONV_STR_LPSTR:
case MONO_MARSHAL_CONV_STR_LPTSTR:
+#ifdef PLATFORM_WIN32
+ /* We assume this field points inside a MonoString
+ * on Win32 */
+ break;
+#endif
+ case MONO_MARSHAL_CONV_STR_LPSTR:
case MONO_MARSHAL_CONV_STR_BSTR:
case MONO_MARSHAL_CONV_STR_ANSIBSTR:
case MONO_MARSHAL_CONV_STR_TBSTR:
mono_marshal_free (*(gpointer *)cpos);
break;
+
default:
continue;
}
mono_struct_delete_old (klass, (char *)src);
}
-
-/* FIXME: on win32 we should probably use GlobalAlloc(). */
void*
ves_icall_System_Runtime_InteropServices_Marshal_AllocHGlobal (int size)
{
/* This returns a valid pointer for size 0 on MS.NET */
size = 4;
+#ifdef PLATFORM_WIN32
+ res = GlobalAlloc (GMEM_FIXED, (gulong)size);
+#else
res = g_try_malloc ((gulong)size);
+#endif
+ if (!res)
+ mono_gc_out_of_memory ((gulong)size);
+
+ return res;
+}
+
+gpointer
+ves_icall_System_Runtime_InteropServices_Marshal_ReAllocHGlobal (gpointer ptr, int size)
+{
+ gpointer res;
+
+ if (ptr == NULL) {
+ mono_gc_out_of_memory ((gulong)size);
+ return NULL;
+ }
+
+#ifdef PLATFORM_WIN32
+ res = GlobalReAlloc (ptr, (gulong)size, 0);
+#else
+ res = g_try_realloc (ptr, (gulong)size);
+#endif
if (!res)
mono_gc_out_of_memory ((gulong)size);
{
MONO_ARCH_SAVE_REGS;
+#ifdef PLATFORM_WIN32
+ GlobalFree (ptr);
+#else
g_free (ptr);
+#endif
}
void*
#endif
}
+gpointer
+ves_icall_System_Runtime_InteropServices_Marshal_ReAllocCoTaskMem (gpointer ptr, int size)
+{
+ MONO_ARCH_SAVE_REGS;
+
+#ifdef PLATFORM_WIN32
+ return CoTaskMemRealloc (ptr, size);
+#else
+ return g_try_realloc (ptr, (gulong)size);
+#endif
+}
+
void*
ves_icall_System_Runtime_InteropServices_Marshal_UnsafeAddrOfPinnedArrayElement (MonoArray *arrayobj, int index)
{
static gboolean
cominterop_finalizer (gpointer key, gpointer value, gpointer user_data)
{
- ves_icall_System_Runtime_InteropServices_Marshal_Release (value);
+ ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value);
return TRUE;
}
void
-ves_icall_System_ComObject_Finalizer(MonoComObject* obj)
+ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject* obj)
{
g_assert(obj);
- if (obj->itf_hash)
+ if (obj->itf_hash) {
+ guint32 gchandle = 0;
+ mono_cominterop_lock ();
+ gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, obj->iunknown));
+ if (gchandle) {
+ mono_gchandle_free (gchandle);
+ g_hash_table_remove (rcw_hash, obj->iunknown);
+ }
+
g_hash_table_foreach_remove (obj->itf_hash, cominterop_finalizer, NULL);
- obj->itf_hash = NULL;
+ ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj->iunknown);
+ obj->itf_hash = obj->iunknown = NULL;
+ mono_cominterop_unlock ();
+ }
}
-#define MONO_IUNKNOWN_INTERFACE_SLOT 0
-
gpointer
ves_icall_System_ComObject_FindInterface (MonoComObject* obj, MonoReflectionType* type)
{
MonoClass* klass;
+ gpointer itf = NULL;
g_assert(obj);
- g_assert(obj->itf_hash);
+ g_assert(type);
+ if (!obj->itf_hash)
+ return NULL;
+ klass = mono_object_class (obj);
klass = mono_class_from_mono_type (type->type);
- return g_hash_table_lookup (obj->itf_hash, GUINT_TO_POINTER ((guint)klass->interface_id));
+ mono_cominterop_lock ();
+ itf = g_hash_table_lookup (obj->itf_hash, GUINT_TO_POINTER ((guint)klass->interface_id));
+ mono_cominterop_unlock ();
+
+ return itf;
}
void
-ves_icall_System_ComObject_CacheInterface (MonoComObject* obj, MonoReflectionType* type, gpointer pItf)
+ves_icall_System_ComObject_AddInterface (MonoComObject* obj, MonoReflectionType* type, gpointer pItf)
{
MonoClass* klass;
g_assert(obj);
- g_assert(obj->itf_hash);
+ g_assert(type);
+ if (!obj->itf_hash) {
+ mono_cominterop_lock ();
+ obj->itf_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
+ mono_cominterop_unlock ();
+ }
+ klass = mono_object_class (obj);
klass = mono_class_from_mono_type (type->type);
+ mono_cominterop_lock ();
g_hash_table_insert (obj->itf_hash, GUINT_TO_POINTER ((guint)klass->interface_id), pItf);
+ mono_cominterop_unlock ();
}
-gpointer
-ves_icall_System_ComObject_GetIUnknown (MonoComObject* obj)
+void
+ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy* proxy)
{
- g_assert(obj);
- if (!obj->itf_hash)
- return NULL;
- return g_hash_table_lookup (obj->itf_hash, MONO_IUNKNOWN_INTERFACE_SLOT);
+ guint32 gchandle = 0;
+ if (!rcw_hash) {
+ mono_cominterop_lock ();
+ rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
+ mono_cominterop_unlock ();
+ }
+
+ gchandle = mono_gchandle_new_weakref ((MonoObject*)proxy, FALSE);
+
+ mono_cominterop_lock ();
+ g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle));
+ mono_cominterop_unlock ();
}
-void
-ves_icall_System_ComObject_SetIUnknown (MonoComObject* obj, gpointer pUnk)
+MonoComInteropProxy*
+ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk)
{
- g_assert(obj);
- g_assert(!obj->itf_hash);
- obj->itf_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
- g_hash_table_insert (obj->itf_hash, MONO_IUNKNOWN_INTERFACE_SLOT, pUnk);
+ MonoComInteropProxy* proxy = NULL;
+ guint32 gchandle = 0;
+
+ mono_cominterop_lock ();
+ if (rcw_hash)
+ gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk));
+ mono_cominterop_unlock ();
+ if (gchandle) {
+ proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
+ /* proxy is null means we need to free up old RCW */
+ if (!proxy) {
+ mono_gchandle_free (gchandle);
+ g_hash_table_remove (rcw_hash, pUnk);
+ }
+ }
+ return proxy;
}
/**
return res;
}
+
+/* Put COM Interop related stuff here */
+
+/**
+ * cominterop_get_ccw_object:
+ * @ccw_entry: a pointer to the CCWEntry
+ * @verify: verify ccw_entry is in fact a ccw
+ *
+ * Returns: the corresponding object for the CCW
+ */
+static MonoObject*
+cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
+{
+ MonoCCW *ccw = NULL;
+
+ /* no CCW's exist yet */
+ if (!ccw_interface_hash)
+ return NULL;
+
+ if (verify) {
+ ccw = g_hash_table_lookup (ccw_interface_hash, ccw_entry);
+ }
+ else {
+ ccw = ccw_entry->ccw;
+ g_assert (ccw);
+ }
+ if (ccw)
+ return mono_gchandle_get_target (ccw->gc_handle);
+ else
+ return NULL;
+}
+
+static void
+cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
+{
+ MonoMethodSignature *sig, *csig;
+ sig = mono_method_signature (method);
+ /* we copy the signature, so that we can modify it */
+ /* FIXME: which to use? */
+ csig = signature_dup (method->klass->image, sig);
+ /* csig = mono_metadata_signature_dup (sig); */
+
+ /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
+#ifdef PLATFORM_WIN32
+ csig->call_convention = MONO_CALL_STDCALL;
+#else
+ csig->call_convention = MONO_CALL_C;
+#endif
+ csig->hasthis = 0;
+ csig->pinvoke = 1;
+
+ m->image = method->klass->image;
+ m->piinfo = NULL;
+ m->retobj_var = 0;
+ m->sig = sig;
+ m->csig = csig;
+}
+
+/**
+ * cominterop_get_ccw:
+ * @object: a pointer to the object
+ * @itf: interface type needed
+ *
+ * Returns: a value indicating if the object is a
+ * Runtime Callable Wrapper (RCW) for a COM object
+ */
+static gpointer
+cominterop_get_ccw (MonoObject* object, MonoClass* itf)
+{
+ int i;
+ MonoCCW *ccw = NULL;
+ MonoCCWInterface* ccw_entry = NULL;
+ gpointer *vtable = NULL;
+ static gpointer iunknown[3] = {NULL, NULL, NULL};
+ static gpointer idispatch[4] = {NULL, NULL, NULL, NULL};
+ MonoClass* iface = NULL;
+ MonoClass* klass = NULL;
+ EmitMarshalContext m;
+ int start_slot = 3;
+ int method_count = 0;
+ GList *ccw_list, *ccw_list_item;
+
+ if (!object)
+ return NULL;
+
+ klass = mono_object_get_class (object);
+
+ if (!ccw_hash)
+ ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
+ if (!ccw_interface_hash)
+ ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
+
+ ccw_list = g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
+
+ ccw_list_item = ccw_list;
+ while (ccw_list_item) {
+ MonoCCW* ccw_iter = ccw_list_item->data;
+ if (mono_gchandle_get_target (ccw_iter->gc_handle) == object) {
+ ccw = ccw_iter;
+ break;
+ }
+ ccw_list_item = g_list_next(ccw_list_item);
+ }
+
+ if (!iunknown [0]) {
+ iunknown [0] = cominterop_ccw_queryinterface;
+ iunknown [1] = cominterop_ccw_addref;
+ iunknown [2] = cominterop_ccw_release;
+ }
+
+ if (!idispatch [0]) {
+ idispatch [0] = cominterop_ccw_get_type_info_count;
+ idispatch [1] = cominterop_ccw_get_type_info;
+ idispatch [2] = cominterop_ccw_get_ids_of_names;
+ idispatch [3] = cominterop_ccw_invoke;
+ }
+
+ if (!ccw) {
+ ccw = g_new0 (MonoCCW, 1);
+ ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
+ ccw->ref_count = 0;
+ /* just alloc a weak handle until we are addref'd*/
+ ccw->gc_handle = mono_gchandle_new_weakref (object, FALSE);
+
+ if (!ccw_list) {
+ ccw_list = g_list_alloc ();
+ ccw_list->data = ccw;
+ }
+ else
+ ccw_list = g_list_append (ccw_list, ccw);
+ g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
+ /* register for finalization to clean up ccw */
+ mono_object_register_finalizer (object);
+ }
+
+ iface = itf;
+ if (iface == mono_defaults.iunknown_class) {
+ start_slot = 3;
+ }
+ else if (iface == mono_defaults.idispatch_class) {
+ start_slot = 7;
+ }
+ else {
+ while (iface) {
+ method_count += iface->method.count;
+ if (iface->interface_count) {
+ iface = iface->interfaces [0];
+ }
+ else {
+ start_slot = cominterop_get_com_slot_begin (iface);
+ iface = NULL;
+ }
+ }
+ }
+
+ ccw_entry = g_hash_table_lookup (ccw->vtable_hash, itf);
+
+ if (!ccw_entry) {
+ int vtable_index = method_count-1+start_slot;
+ mono_loader_lock ();
+ vtable = mono_mempool_alloc0 (klass->image->mempool, sizeof (gpointer)*(method_count+start_slot));
+ mono_loader_unlock ();
+ memcpy (vtable, iunknown, sizeof (iunknown));
+ if (start_slot == 7)
+ memcpy (vtable+3, idispatch, sizeof (idispatch));
+
+ iface = itf;
+ while (iface) {
+ for (i = iface->method.count-1; i >= 0;i--) {
+ int param_index = 0;
+ MonoMethodBuilder *mb;
+ MonoMarshalSpec ** mspecs;
+ MonoMethod *wrapper_method, *adjust_method;
+ MonoMethod *method = iface->methods [i];
+ MonoMethodSignature* sig_adjusted;
+ MonoMethodSignature* sig = mono_method_signature (method);
+ gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
+
+
+ mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
+ adjust_method = cominterop_get_managed_wrapper_adjusted (method);
+ sig_adjusted = mono_method_signature (adjust_method);
+
+ mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
+ mono_method_get_marshal_info (method, mspecs);
+
+
+ /* move managed args up one */
+ for (param_index = sig->param_count; param_index >= 1; param_index--)
+ mspecs [param_index+1] = mspecs [param_index];
+
+ /* first arg is IntPtr for interface */
+ mspecs [1] = NULL;
+
+ /* move return spec to last param */
+ if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
+ mspecs [sig_adjusted->param_count] = mspecs [0];
+
+ mspecs [0] = NULL;
+
+ cominterop_setup_marshal_context (&m, adjust_method);
+ m.mb = mb;
+ mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, NULL);
+ mono_loader_lock ();
+ mono_marshal_lock ();
+ wrapper_method = mono_mb_create_method (mb, sig_adjusted, sig_adjusted->param_count + 16);
+ 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);
+
+
+ for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
+ if (mspecs [param_index])
+ mono_metadata_free_marshal_spec (mspecs [param_index]);
+ g_free (mspecs);
+ }
+ if (iface->interface_count)
+ iface = iface->interfaces [0];
+ else
+ iface = NULL;
+ }
+
+ ccw_entry = g_new0 (MonoCCWInterface, 1);
+ ccw_entry->ccw = ccw;
+ ccw_entry->vtable = vtable;
+ g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
+ g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
+ }
+
+ return ccw_entry;
+}
+
+static gboolean
+mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
+{
+ g_assert (value);
+ g_free (value);
+ return TRUE;
+}
+
+/**
+ * mono_marshal_free_ccw:
+ * @object: the mono object
+ *
+ * Returns: whether the object had a CCW
+ */
+gboolean
+mono_marshal_free_ccw (MonoObject* object)
+{
+ GList *ccw_list, *ccw_list_orig, *ccw_list_item;
+ /* no ccw's were created */
+ if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
+ return FALSE;
+
+ /* need to cache orig list address to remove from hash_table if empty */
+ mono_cominterop_lock ();
+ ccw_list = ccw_list_orig = g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
+ mono_cominterop_unlock ();
+
+ if (!ccw_list)
+ return FALSE;
+
+ ccw_list_item = ccw_list;
+ while (ccw_list_item) {
+ MonoCCW* ccw_iter = ccw_list_item->data;
+ MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
+
+ /* Looks like the GC NULLs the weakref handle target before running the
+ * finalizer. So if we get a NULL target, destroy the CCW as well. */
+ if (!handle_target || handle_target == object) {
+ /* remove all interfaces */
+ g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
+ g_hash_table_destroy (ccw_iter->vtable_hash);
+
+ /* get next before we delete */
+ ccw_list_item = g_list_next(ccw_list_item);
+
+ /* remove ccw from list */
+ ccw_list = g_list_remove (ccw_list, ccw_iter);
+ g_free (ccw_iter);
+ }
+ else
+ ccw_list_item = g_list_next(ccw_list_item);
+ }
+
+ /* if list is empty remove original address from hash */
+ if (g_list_length (ccw_list) == 0)
+ g_hash_table_remove (ccw_hash, ccw_list_orig);
+
+
+ return TRUE;
+}
+
+/**
+ * cominterop_get_native_wrapper_adjusted:
+ * @method: managed COM Interop method
+ *
+ * Returns: the generated method to call with signature matching
+ * the unmanaged COM Method signature
+ */
+static MonoMethod *
+cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
+{
+ static MonoMethod *get_hr_for_exception = NULL;
+ MonoMethod *res = NULL;
+ MonoMethodBuilder *mb;
+ MonoMarshalSpec **mspecs;
+ MonoMethodSignature *sig, *sig_native;
+ MonoExceptionClause *main_clause = NULL;
+ MonoMethodHeader *header;
+ int pos_leave;
+ int hr = 0;
+ int i;
+ gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
+
+ if (!get_hr_for_exception)
+ get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
+
+ sig = mono_method_signature (method);
+
+ /* create unmanaged wrapper */
+ mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
+
+ sig_native = cominterop_method_signature (method);
+
+ mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
+
+ mono_method_get_marshal_info (method, mspecs);
+
+ /* move managed args up one */
+ for (i = sig->param_count; i >= 1; i--)
+ mspecs [i+1] = mspecs [i];
+
+ /* first arg is IntPtr for interface */
+ mspecs [1] = NULL;
+
+ /* move return spec to last param */
+ if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
+ mspecs [sig_native->param_count] = mspecs [0];
+
+ mspecs [0] = NULL;
+
+ if (!preserve_sig) {
+ hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
+
+ /* try */
+ main_clause = g_new0 (MonoExceptionClause, 1);
+ main_clause->try_offset = mb->pos;
+ }
+
+ /* load last param to store result if not preserve_sig and not void */
+ if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
+ mono_mb_emit_ldarg (mb, sig_native->param_count-1);
+
+ /* the CCW -> object conversion */
+ mono_mb_emit_ldarg (mb, 0);
+ mono_mb_emit_icon (mb, FALSE);
+ mono_mb_emit_icall (mb, cominterop_get_ccw_object);
+
+ for (i = 0; i < sig->param_count; i++)
+ mono_mb_emit_ldarg (mb, i+1);
+
+ mono_mb_emit_managed_call (mb, method, NULL);
+
+ if (!preserve_sig) {
+ /* store result if not preserve_sig and we have one */
+ if (!MONO_TYPE_IS_VOID (sig->ret))
+ mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
+
+ pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
+
+ /* Main exception catch */
+ main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
+ main_clause->try_len = mb->pos - main_clause->try_offset;
+ main_clause->data.catch_class = mono_defaults.object_class;
+
+ /* handler code */
+ main_clause->handler_offset = mb->pos;
+ mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
+ mono_mb_emit_stloc (mb, hr);
+ mono_mb_emit_branch (mb, CEE_LEAVE);
+ main_clause->handler_len = mb->pos - main_clause->handler_offset;
+ /* end catch */
+
+ mono_mb_patch_addr (mb, pos_leave, mb->pos - (pos_leave + 4));
+
+ mono_mb_emit_ldloc (mb, hr);
+ }
+
+ mono_mb_emit_byte (mb, CEE_RET);
+
+ mono_loader_lock ();
+ mono_marshal_lock ();
+ res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);
+ mono_marshal_unlock ();
+ mono_loader_unlock ();
+
+ mono_mb_free (mb);
+
+ for (i = sig_native->param_count; i >= 0; i--)
+ if (mspecs [i])
+ 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;
+}
+
+/**
+ * cominterop_mono_string_to_guid:
+ *
+ * Converts the standard string representation of a GUID
+ * to a 16 byte Microsoft GUID.
+ */
+static void
+cominterop_mono_string_to_guid (const MonoString* string, guint8 *guid) {
+ gunichar2 * chars = mono_string_chars (string);
+ int i = 0;
+ static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
+
+ for (i = 0; i < sizeof(indexes); i++)
+ guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
+
+ //guid [0] = g_unichar_xdigit_value (chars [7]) + (g_unichar_xdigit_value (chars [6]) << 4);
+ //guid [1] = g_unichar_xdigit_value (chars [5]) + (g_unichar_xdigit_value (chars [4]) << 4);
+ //guid [2] = g_unichar_xdigit_value (chars [3]) + (g_unichar_xdigit_value (chars [2]) << 4);
+ //guid [3] = g_unichar_xdigit_value (chars [1]) + (g_unichar_xdigit_value (chars [0]) << 4);
+ //guid [4] = g_unichar_xdigit_value (chars [12]) + (g_unichar_xdigit_value (chars [11]) << 4);
+ //guid [5] = g_unichar_xdigit_value (chars [10]) + (g_unichar_xdigit_value (chars [9]) << 4);
+ //guid [6] = g_unichar_xdigit_value (chars [17]) + (g_unichar_xdigit_value (chars [16]) << 4);
+ //guid [7] = g_unichar_xdigit_value (chars [15]) + (g_unichar_xdigit_value (chars [14]) << 4);
+ //guid [8] = g_unichar_xdigit_value (chars [20]) + (g_unichar_xdigit_value (chars [19]) << 4);
+ //guid [9] = g_unichar_xdigit_value (chars [22]) + (g_unichar_xdigit_value (chars [21]) << 4);
+ //guid [10] = g_unichar_xdigit_value (chars [25]) + (g_unichar_xdigit_value (chars [24]) << 4);
+ //guid [11] = g_unichar_xdigit_value (chars [27]) + (g_unichar_xdigit_value (chars [26]) << 4);
+ //guid [12] = g_unichar_xdigit_value (chars [29]) + (g_unichar_xdigit_value (chars [28]) << 4);
+ //guid [13] = g_unichar_xdigit_value (chars [31]) + (g_unichar_xdigit_value (chars [30]) << 4);
+ //guid [14] = g_unichar_xdigit_value (chars [33]) + (g_unichar_xdigit_value (chars [32]) << 4);
+ //guid [15] = g_unichar_xdigit_value (chars [35]) + (g_unichar_xdigit_value (chars [34]) << 4);
+}
+
+static gboolean
+cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
+{
+ static MonoClass *GuidAttribute = NULL;
+ MonoCustomAttrInfo *cinfo;
+
+ /* Handle the GuidAttribute */
+ if (!GuidAttribute)
+ GuidAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "GuidAttribute");
+
+ cinfo = mono_custom_attrs_from_class (klass);
+ if (cinfo) {
+ guint8 klass_guid [16];
+ MonoReflectionGuidAttribute *attr = (MonoReflectionGuidAttribute*)mono_custom_attrs_get_attr (cinfo, GuidAttribute);
+
+ if (!attr)
+ return FALSE;
+ if (!cinfo->cached)
+ mono_custom_attrs_free (cinfo);
+
+ cominterop_mono_string_to_guid (attr->guid, klass_guid);
+ return !memcmp (guid, klass_guid, sizeof (klass_guid));
+ }
+ return FALSE;
+}
+
+static int STDCALL
+cominterop_ccw_addref (MonoCCWInterface* ccwe)
+{
+ gint32 ref_count = 0;
+ MonoCCW* ccw = ccwe->ccw;
+ g_assert (ccw);
+ g_assert (ccw->gc_handle);
+ g_assert (ccw->ref_count >= 0);
+ ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
+ if (ref_count == 1) {
+ guint32 oldhandle = ccw->gc_handle;
+ g_assert (oldhandle);
+ /* since we now have a ref count, alloc a strong handle*/
+ ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
+ mono_gchandle_free (oldhandle);
+ }
+ return ref_count;
+}
+
+static int STDCALL
+cominterop_ccw_release (MonoCCWInterface* ccwe)
+{
+ gint32 ref_count = 0;
+ MonoCCW* ccw = ccwe->ccw;
+ g_assert (ccw);
+ g_assert (ccw->ref_count > 0);
+ ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
+ if (ref_count == 0) {
+ /* allow gc of object */
+ guint32 oldhandle = ccw->gc_handle;
+ g_assert (oldhandle);
+ ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
+ mono_gchandle_free (oldhandle);
+ }
+ return ref_count;
+}
+
+#define MONO_S_OK 0x00000000L
+#define MONO_E_NOINTERFACE 0x80004002L
+#define MONO_E_NOTIMPL 0x80004001L
+
+static int STDCALL
+cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
+{
+ GPtrArray *ifaces;
+ MonoClass *itf = NULL;
+ int i;
+ MonoCCW* ccw = ccwe->ccw;
+ MonoClass* klass = NULL;
+ MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
+
+ g_assert (object);
+ klass = mono_object_class (object);
+
+ if (ppv)
+ *ppv = NULL;
+
+ /* handle IUnknown special */
+ if (cominterop_class_guid_equal (riid, mono_defaults.iunknown_class)) {
+ *ppv = cominterop_get_ccw (object, mono_defaults.iunknown_class);
+ /* remember to addref on QI */
+ cominterop_ccw_addref (*ppv);
+ return MONO_S_OK;
+ }
+
+ /* handle IDispatch special */
+ if (cominterop_class_guid_equal (riid, mono_defaults.idispatch_class)) {
+ *ppv = cominterop_get_ccw (object, mono_defaults.idispatch_class);
+ /* remember to addref on QI */
+ cominterop_ccw_addref (*ppv);
+ return MONO_S_OK;
+ }
+
+ ifaces = mono_class_get_implemented_interfaces (klass);
+ if (ifaces) {
+ for (i = 0; i < ifaces->len; ++i) {
+ MonoClass *ic = NULL;
+ ic = g_ptr_array_index (ifaces, i);
+ if (cominterop_class_guid_equal (riid, ic)) {
+ itf = ic;
+ break;
+ }
+ }
+ g_ptr_array_free (ifaces, TRUE);
+ }
+ if (itf) {
+ *ppv = cominterop_get_ccw (object, itf);
+ /* remember to addref on QI */
+ cominterop_ccw_addref (*ppv);
+ return MONO_S_OK;
+ }
+
+ return MONO_E_NOINTERFACE;
+}
+
+static int STDCALL
+cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
+{
+ return MONO_E_NOTIMPL;
+}
+
+static int STDCALL
+cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
+{
+ return MONO_E_NOTIMPL;
+}
+
+static int STDCALL
+cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
+ gunichar2** rgszNames, guint32 cNames,
+ guint32 lcid, gint32 *rgDispId)
+{
+ return MONO_E_NOTIMPL;
+}
+
+static int STDCALL
+cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
+ gpointer riid, guint32 lcid,
+ guint16 wFlags, gpointer pDispParams,
+ gpointer pVarResult, gpointer pExcepInfo,
+ guint32 *puArgErr)
+{
+ return MONO_E_NOTIMPL;
+}