mono_marshal_set_last_error_windows (int error);
static void
-mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func, gboolean check_exceptions);
+mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func, gboolean aot, gboolean check_exceptions);
static void init_safe_handle (void);
return FALSE;
}
+static gboolean
+cominterop_com_visible (MonoClass* klass)
+{
+ static MonoClass *ComVisibleAttribute = NULL;
+ MonoCustomAttrInfo *cinfo;
+
+ /* Handle the ComVisibleAttribute */
+ if (!ComVisibleAttribute)
+ ComVisibleAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "ComVisibleAttribute");
+
+ cinfo = mono_custom_attrs_from_class (klass);
+ if (cinfo) {
+ MonoReflectionComVisibleAttribute *attr = (MonoReflectionComVisibleAttribute*)mono_custom_attrs_get_attr (cinfo, ComVisibleAttribute);
+
+ if (!attr)
+ return FALSE;
+ if (!cinfo->cached)
+ mono_custom_attrs_free (cinfo);
+
+ if (attr->visible)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static void cominterop_raise_hr_exception (int hr)
+{
+ static MonoMethod* throw_exception_for_hr = NULL;
+ MonoException* ex;
+ void* params[1] = {&hr};
+ if (!throw_exception_for_hr)
+ throw_exception_for_hr = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetExceptionForHR", 1);
+ ex = (MonoException*)mono_runtime_invoke (throw_exception_for_hr, NULL, params, NULL);
+ mono_raise_exception (ex);
+}
+
/**
* cominterop_get_interface:
* @obj: managed wrapper object containing COM object
g_assert(found);
hr = ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (obj->iunknown, iid, &itf);
if (hr < 0 && throw_exception) {
- static MonoMethod* throw_exception_for_hr = NULL;
- MonoException* ex;
- void* params[1] = {&hr};
- if (!throw_exception_for_hr)
- throw_exception_for_hr = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetExceptionForHR", 1);
- ex = (MonoException*)mono_runtime_invoke (throw_exception_for_hr, NULL, params, NULL);
- mono_raise_exception (ex);
+ cominterop_raise_hr_exception (hr);
}
if (hr >= 0 && itf) {
mono_string_builder_to_utf8 (MonoStringBuilder *sb)
{
GError *error = NULL;
- glong *res;
- gchar *tmp;
+ gchar *tmp, *res = NULL;
if (!sb)
return NULL;
sb->cached_str = NULL;
}
- res = mono_marshal_alloc (mono_stringbuilder_capacity (sb) + 1);
-
- tmp = g_utf16_to_utf8 (mono_string_chars (sb->str), sb->length, NULL, res, &error);
+ tmp = g_utf16_to_utf8 (mono_string_chars (sb->str), sb->length, NULL, NULL, &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 {
+ res = mono_marshal_alloc (mono_stringbuilder_capacity (sb) + 1);
memcpy (res, tmp, sb->length + 1);
g_free (tmp);
}
}
}
- mono_marshal_emit_native_wrapper (method->klass->image, mb_native, sig_native, piinfo, mspecs, piinfo->addr, TRUE);
+ mono_marshal_emit_native_wrapper (method->klass->image, mb_native, sig_native, piinfo, mspecs, piinfo->addr, FALSE, TRUE);
res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16);
if (t->byref) {
mono_mb_emit_byte (mb, CEE_LDIND_I);
+ /* A Nullable<T> type don't have a boxed form, it's either null or a boxed T.
+ * So to make this work we unbox it to a local variablee and push a reference to that.
+ */
+ if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t))) {
+ int tmp_nullable_local = mono_mb_add_local (mb, &mono_class_from_mono_type (t)->byval_arg);
+
+ mono_mb_emit_op (mb, CEE_UNBOX_ANY, mono_class_from_mono_type (t));
+ mono_mb_emit_stloc (mb, tmp_nullable_local);
+ mono_mb_emit_ldloc_addr (mb, tmp_nullable_local);
+ }
continue;
}
MonoClass *klass;
int pos = 0, pos2;
- klass = t->data.klass;
+ klass = mono_class_from_mono_type (t);
switch (action) {
case MARSHAL_ACTION_CONV_IN:
MarshalAction action)
{
MonoMethodBuilder *mb = m->mb;
- MonoClass *klass = t->data.klass;
+ MonoClass *klass = mono_class_from_mono_type (t);
int pos, pos2, loc;
if (mono_class_from_mono_type (t) == mono_defaults.object_class) {
/* allocate a new object */
mono_mb_emit_ldarg (mb, argnum);
mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
- mono_mb_emit_op (mb, CEE_MONO_NEWOBJ, t->data.klass);
+ mono_mb_emit_op (mb, CEE_MONO_NEWOBJ, klass);
mono_mb_emit_byte (mb, CEE_STIND_REF);
}
mono_mb_emit_stloc (mb, 0);
/* emit valuetype conversion code */
- emit_struct_conv (mb, t->data.klass, TRUE);
+ emit_struct_conv (mb, klass, TRUE);
/* Free the structure returned by the native code */
emit_struct_free (mb, klass, conv_arg);
case MONO_TYPE_U8:
case MONO_TYPE_FNPTR:
return emit_marshal_scalar (m, argnum, t, spec, conv_arg, conv_arg_type, action);
+ case MONO_TYPE_GENERICINST:
+ if (mono_type_generic_inst_is_valuetype (t))
+ return emit_marshal_vtype (m, argnum, t, spec, conv_arg, conv_arg_type, action);
+ else
+ return emit_marshal_object (m, argnum, t, spec, conv_arg, conv_arg_type, action);
}
return conv_arg;
* @sig: The signature of the native function
* @piinfo: Marshalling information
* @mspecs: Marshalling information
- * @func: the native function to call
+ * @aot: whenever the created method will be compiled by the AOT compiler
+ * @method: if non-NULL, the pinvoke method to call
* @check_exceptions: Whenever to check for pending exceptions after the native call
*
* generates IL code for the pinvoke wrapper, the generated code calls @func.
*/
static void
-mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func, gboolean check_exceptions)
+mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func, gboolean aot, gboolean check_exceptions)
{
EmitMarshalContext m;
MonoMethodSignature *csig;
if (sig->hasthis)
mono_mb_emit_byte (mb, CEE_LDARG_0);
-
for (i = 0; i < sig->param_count; i++) {
emit_marshal (&m, i + sig->hasthis, sig->params [i], mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_PUSH);
}
#endif
}
else {
- mono_mb_emit_native_call (mb, csig, func);
+ if (aot) {
+ /* Reuse the ICALL_ADDR opcode for pinvokes too */
+ mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+ mono_mb_emit_op (mb, CEE_MONO_ICALL_ADDR, &piinfo->method);
+ mono_mb_emit_calli (mb, csig);
+ } else {
+ mono_mb_emit_native_call (mb, csig, func);
+ }
}
/* Set LastError if needed */
case MONO_TYPE_SZARRAY:
case MONO_TYPE_CHAR:
case MONO_TYPE_PTR:
+ case MONO_TYPE_GENERICINST:
emit_marshal (&m, 0, sig->ret, spec, 0, NULL, MARSHAL_ACTION_CONV_RESULT);
break;
case MONO_TYPE_TYPEDBYREF:
}
g_assert (pinvoke);
- g_assert (piinfo->addr);
+ if (!aot)
+ g_assert (piinfo->addr);
mspecs = g_new (MonoMarshalSpec*, sig->param_count + 1);
mono_method_get_marshal_info (method, mspecs);
- mono_marshal_emit_native_wrapper (mb->method->klass->image, mb, sig, piinfo, mspecs, piinfo->addr, check_exceptions);
+ mono_marshal_emit_native_wrapper (mb->method->klass->image, mb, sig, piinfo, mspecs, piinfo->addr, aot, check_exceptions);
csig = signature_dup (method->klass->image, sig);
csig->pinvoke = 0;
mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_MANAGED_TO_NATIVE);
mb->method->save_lmf = 1;
- mono_marshal_emit_native_wrapper (image, mb, sig, piinfo, mspecs, func, TRUE);
+ mono_marshal_emit_native_wrapper (image, mb, sig, piinfo, mspecs, func, FALSE, TRUE);
csig = signature_dup (image, sig);
csig->pinvoke = 0;
case MONO_TYPE_BOOLEAN:
case MONO_TYPE_I1:
case MONO_TYPE_U1:
+ case MONO_TYPE_CHAR:
case MONO_TYPE_I2:
case MONO_TYPE_U2:
case MONO_TYPE_I4:
mono_loader_unlock ();
clause->flags = MONO_EXCEPTION_CLAUSE_FINALLY;
+ mono_loader_lock ();
+
if (!enter_method) {
MonoMethodDesc *desc;
mono_method_desc_free (desc);
}
+ mono_loader_unlock ();
+
/* Push this or the type object */
if (method->flags & METHOD_ATTRIBUTE_STATIC) {
/* We have special handling for this in the JIT */
#ifndef DISABLE_COM
+#define MONO_S_OK 0x00000000L
+#define MONO_E_NOINTERFACE 0x80004002L
+#define MONO_E_NOTIMPL 0x80004001L
+
+static gboolean cominterop_can_support_dispatch (MonoClass* klass)
+{
+ if (!(klass->flags & TYPE_ATTRIBUTE_PUBLIC) )
+ return FALSE;
+
+ if (!cominterop_com_visible (klass))
+ return FALSE;
+
+ return TRUE;
+}
+
static void*
cominterop_get_idispatch_for_object (MonoObject* object)
{
mono_defaults.idispatch_class, TRUE);
}
else {
+ MonoClass* klass = mono_object_class (object);
+ if (!cominterop_can_support_dispatch (klass) )
+ cominterop_raise_hr_exception (MONO_E_NOINTERFACE);
return cominterop_get_ccw (object, mono_defaults.idispatch_class);
}
}
if (!object)
return NULL;
+ mono_init_com_types ();
+
if (cominterop_object_is_rcw (object)) {
MonoClass *klass = NULL;
MonoRealProxy* real_proxy = NULL;
ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject* object)
{
#ifndef DISABLE_COM
+ mono_init_com_types ();
+
return cominterop_get_idispatch_for_object (object);
#else
g_assert_not_reached ();
}
static gboolean
-cominterop_finalizer (gpointer key, gpointer value, gpointer user_data)
+cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data)
{
ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value);
return TRUE;
g_hash_table_remove (rcw_hash, obj->iunknown);
}
- g_hash_table_foreach_remove (obj->itf_hash, cominterop_finalizer, NULL);
+ g_hash_table_foreach_remove (obj->itf_hash, cominterop_rcw_interface_finalizer, NULL);
+ g_hash_table_destroy (obj->itf_hash);
ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj->iunknown);
obj->itf_hash = obj->iunknown = NULL;
mono_cominterop_unlock ();
}
}
+#ifndef DISABLE_COM
+
+static gboolean
+cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data)
+{
+ guint32 gchandle = 0;
+
+ gchandle = GPOINTER_TO_UINT (value);
+ if (gchandle) {
+ MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
+
+ if (proxy) {
+ if (proxy->com_object->itf_hash) {
+ g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL);
+ g_hash_table_destroy (proxy->com_object->itf_hash);
+ }
+ if (proxy->com_object->iunknown)
+ ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (proxy->com_object->iunknown);
+ proxy->com_object->itf_hash = proxy->com_object->iunknown = NULL;
+ }
+
+ mono_gchandle_free (gchandle);
+ }
+
+ return TRUE;
+}
+
+void
+cominterop_release_all_rcws ()
+{
+ if (!rcw_hash)
+ return;
+
+ mono_cominterop_lock ();
+
+ g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL);
+ g_hash_table_destroy (rcw_hash);
+ rcw_hash = NULL;
+
+ mono_cominterop_unlock ();
+}
+
+#endif
+
gpointer
ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception)
{
return klass->marshal_info->native_size;
}
+/* __alignof__ returns the preferred alignment of values not the actual alignment used by
+ the compiler so is wrong e.g. for Linux where doubles are aligned on a 4 byte boundary
+ but __alignof__ returns 8 - using G_STRUCT_OFFSET works better */
+#define ALIGNMENT(type) G_STRUCT_OFFSET(struct { char c; type x; }, x)
+
/*
* mono_type_native_stack_size:
* @t: the type to return the size it uses on the stack
align = &tmp;
if (t->byref) {
- *align = 4;
- return 4;
+ *align = sizeof (gpointer);
+ return sizeof (gpointer);
}
switch (t->type){
case MONO_TYPE_U2:
case MONO_TYPE_I4:
case MONO_TYPE_U4:
+ *align = 4;
+ return 4;
case MONO_TYPE_I:
case MONO_TYPE_U:
case MONO_TYPE_STRING:
case MONO_TYPE_PTR:
case MONO_TYPE_FNPTR:
case MONO_TYPE_ARRAY:
- *align = 4;
- return 4;
+ *align = sizeof (gpointer);
+ return sizeof (gpointer);
case MONO_TYPE_R4:
*align = 4;
return 4;
+ case MONO_TYPE_R8:
+ *align = ALIGNMENT (gdouble);
+ return 8;
case MONO_TYPE_I8:
case MONO_TYPE_U8:
- case MONO_TYPE_R8:
- *align = 4;
+ *align = ALIGNMENT (glong);
return 8;
+ case MONO_TYPE_GENERICINST:
+ if (!mono_type_generic_inst_is_valuetype (t)) {
+ *align = sizeof (gpointer);
+ return sizeof (gpointer);
+ }
+ /* Fall through */
case MONO_TYPE_TYPEDBYREF:
case MONO_TYPE_VALUETYPE: {
guint32 size;
+ MonoClass *klass = mono_class_from_mono_type (t);
- if (t->data.klass->enumtype)
- return mono_type_native_stack_size (t->data.klass->enum_basetype, align);
+ if (klass->enumtype)
+ return mono_type_native_stack_size (klass->enum_basetype, align);
else {
- size = mono_class_native_size (t->data.klass, align);
+ size = mono_class_native_size (klass, align);
*align = *align + 3;
*align &= ~3;
return 0;
}
-/* __alignof__ returns the preferred alignment of values not the actual alignment used by
- the compiler so is wrong e.g. for Linux where doubles are aligned on a 4 byte boundary
- but __alignof__ returns 8 - using G_STRUCT_OFFSET works better */
-#define ALIGNMENT(type) G_STRUCT_OFFSET(struct { char c; type x; }, x)
-
gint32
mono_marshal_type_size (MonoType *type, MonoMarshalSpec *mspec, guint32 *align,
gboolean as_field, gboolean unicode)
return ref_count;
}
-#define MONO_S_OK 0x00000000L
-#define MONO_E_NOINTERFACE 0x80004002L
-#define MONO_E_NOTIMPL 0x80004001L
-
#ifdef PLATFORM_WIN32
static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
#endif
+#ifdef PLATFORM_WIN32
/* All ccw objects are free threaded */
static int
cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv)
return MONO_E_NOINTERFACE;
#endif
}
+#endif
static int STDCALL
cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
/* handle IDispatch special */
if (cominterop_class_guid_equal (riid, mono_defaults.idispatch_class)) {
+ if (!cominterop_can_support_dispatch (klass))
+ return MONO_E_NOINTERFACE;
+
*ppv = cominterop_get_ccw (object, mono_defaults.idispatch_class);
/* remember to addref on QI */
cominterop_ccw_addref (*ppv);