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 res;
}
-static MonoMethodSignature*
-signature_no_pinvoke (MonoMethod *method)
+MonoMethodSignature*
+mono_signature_no_pinvoke (MonoMethod *method)
{
MonoMethodSignature *sig = mono_method_signature (method);
if (sig->pinvoke) {
guint32 ref_count;
guint32 gc_handle;
GHashTable* vtable_hash;
+#ifdef PLATFORM_WIN32
+ gpointer free_marshaler;
+#endif
} MonoCCW;
/* This type is the actual pointer passed to unmanaged code
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);
}
g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class &&
!strcmp (method->name, "BeginInvoke"));
- sig = signature_no_pinvoke (method);
+ sig = mono_signature_no_pinvoke (method);
cache = get_cache (&method->klass->image->delegate_begin_invoke_cache,
(GHashFunc)mono_signature_hash,
method = mono_class_get_method_from_name (klass, "EndInvoke", -1);
g_assert (method != NULL);
- sig = signature_no_pinvoke (method);
+ sig = mono_signature_no_pinvoke (method);
msg = mono_method_call_message_new (method, params, NULL, NULL, NULL);
g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class &&
!strcmp (method->name, "EndInvoke"));
- sig = signature_no_pinvoke (method);
+ sig = mono_signature_no_pinvoke (method);
cache = get_cache (&method->klass->image->delegate_end_invoke_cache,
(GHashFunc)mono_signature_hash,
}
}
- 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 ((res = mono_marshal_find_in_cache (cache, method)))
return res;
- sig = signature_no_pinvoke (method);
+ sig = mono_signature_no_pinvoke (method);
/* we cant remote methods without this pointer */
if (!sig->hasthis)
#endif
}
- sig = signature_no_pinvoke (method);
+ sig = mono_signature_no_pinvoke (method);
/* we cant remote methods without this pointer */
if (!sig->hasthis)
if ((res = mono_marshal_remoting_find_in_cache (method, MONO_WRAPPER_XDOMAIN_INVOKE)))
return res;
- sig = signature_no_pinvoke (method);
+ sig = mono_signature_no_pinvoke (method);
mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_XDOMAIN_INVOKE);
mb->method->save_lmf = 1;
if ((res = mono_marshal_remoting_find_in_cache (method, MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)))
return res;
- sig = signature_no_pinvoke (method);
+ sig = mono_signature_no_pinvoke (method);
mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK);
g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class &&
!strcmp (method->name, "Invoke"));
- sig = signature_no_pinvoke (method);
+ sig = mono_signature_no_pinvoke (method);
if (callvirt) {
/* We need to cache the signature+method pair */
return callsig;
}
-static inline MonoType*
-get_basic_type (MonoType *t)
+static MonoType*
+get_runtime_invoke_type (MonoType *t)
{
+ if (t->byref)
+ return &mono_defaults.int_class->byval_arg;
+
switch (t->type) {
case MONO_TYPE_U1:
return &mono_defaults.sbyte_class->byval_arg;
else
return t;
default:
+ if (MONO_TYPE_IS_REFERENCE (t))
+ return &mono_defaults.object_class->byval_arg;
return t;
}
}
-static inline gboolean
-runtime_invoke_type_equal (MonoType *t1, MonoType *t2)
-{
- if (MONO_TYPE_IS_REFERENCE (t1) && MONO_TYPE_IS_REFERENCE (t2))
- return TRUE;
- else if (t1->byref != t2->byref)
- return FALSE;
- else if (t1->byref && t2->byref)
- return TRUE;
- else if (t1->type == MONO_TYPE_PTR && t2->type == MONO_TYPE_PTR)
- return TRUE;
- else {
- t1 = get_basic_type (t1);
- t2 = get_basic_type (t2);
-
- return mono_metadata_type_equal (t1, t2);
- }
-}
-
-static inline guint
-runtime_invoke_type_hash (MonoType *t1)
-{
- if (MONO_TYPE_IS_REFERENCE (t1))
- return 0;
- else if (t1->byref)
- return 1;
- else if (t1->type == MONO_TYPE_PTR)
- return 2;
- else
- return mono_metadata_type_hash (get_basic_type (t1));
-}
-
/*
- * runtime_invoke_signature_equal:
+ * mono_marshal_get_runtime_invoke_sig:
*
- * Same as mono_metadata_signature_equal, but consider reference types equal.
+ * Return a common signature used for sharing runtime invoke wrappers.
*/
-static gboolean
-runtime_invoke_signature_equal (MonoMethodSignature *sig1, MonoMethodSignature *sig2)
+static MonoMethodSignature*
+mono_marshal_get_runtime_invoke_sig (MonoMethodSignature *sig)
{
+ MonoMethodSignature *res = mono_metadata_signature_dup (sig);
int i;
- if (sig1->hasthis != sig2->hasthis || sig1->param_count != sig2->param_count)
- return FALSE;
-
- if (sig1->generic_param_count != sig2->generic_param_count)
- return FALSE;
-
- /*
- * We're just comparing the signatures of two methods here:
- *
- * If we have two generic methods `void Foo<U> (U u)' and `void Bar<V> (V v)',
- * U and V are equal here.
- *
- * That's what the `signature_only' argument of do_mono_metadata_type_equal() is for.
- */
+ res->ret = get_runtime_invoke_type (sig->ret);
+ for (i = 0; i < res->param_count; ++i)
+ res->params [i] = get_runtime_invoke_type (sig->params [i]);
- for (i = 0; i < sig1->param_count; i++) {
- MonoType *p1 = sig1->params[i];
- MonoType *p2 = sig2->params[i];
-
- /* if (p1->attrs != p2->attrs)
- return FALSE;
- */
- if (!runtime_invoke_type_equal (p1, p2))
- return FALSE;
- }
-
- /* Can't share wrappers which return a vtype since it needs to be boxed */
- if (sig1->ret == sig2->ret)
- return TRUE;
- else if (MONO_TYPE_IS_REFERENCE (sig1->ret) && MONO_TYPE_IS_REFERENCE (sig2->ret))
- return TRUE;
- else
- return FALSE;
+ return res;
}
-static guint
-runtime_invoke_signature_hash (MonoMethodSignature *sig)
+static gboolean
+runtime_invoke_signature_equal (MonoMethodSignature *sig1, MonoMethodSignature *sig2)
{
- guint i, res = sig->ret->type;
-
- for (i = 0; i < sig->param_count; i++)
- res = (res << 5) - res + runtime_invoke_type_hash (sig->params[i]);
-
- return res;
+ /* Can't share wrappers which return a vtype since it needs to be boxed */
+ if (sig1->ret != sig2->ret && !(MONO_TYPE_IS_REFERENCE (sig1->ret) && MONO_TYPE_IS_REFERENCE (sig2->ret)))
+ return FALSE;
+ else
+ return mono_metadata_signature_equal (sig1, sig2);
}
/*
finalize_signature->hasthis = 1;
}
+ /*
+ * Use a separate cache indexed by methods to speed things up and to avoid the
+ * boundless mempool growth caused by the signature_dup stuff below.
+ */
+ cache = get_cache (&method->klass->image->runtime_invoke_direct_cache, mono_aligned_addr_hash, NULL);
+ res = mono_marshal_find_in_cache (cache, method);
+ if (res)
+ return res;
+
if (method->klass->rank && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
(method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
/*
*/
need_direct_wrapper = TRUE;
}
-
+
if (method->string_ctor) {
callsig = lookup_string_ctor_signature (mono_method_signature (method));
if (!callsig)
}
if (need_direct_wrapper) {
- cache = get_cache (&target_klass->image->runtime_invoke_direct_cache, mono_aligned_addr_hash, NULL);
- res = mono_marshal_find_in_cache (cache, method);
+ /* Already searched at the start */
} else {
+ callsig = mono_marshal_get_runtime_invoke_sig (callsig);
+
cache = get_cache (&target_klass->image->runtime_invoke_cache,
- (GHashFunc)runtime_invoke_signature_hash,
+ (GHashFunc)mono_signature_hash,
(GCompareFunc)runtime_invoke_signature_equal);
/* from mono_marshal_find_in_cache */
mono_marshal_lock ();
res = g_hash_table_lookup (cache, callsig);
mono_marshal_unlock ();
- }
- if (res) {
- return res;
+ if (res) {
+ g_free (callsig);
+ return res;
+ }
+
+ // FIXME: When to free callsig ?
}
/* to make it work with our special string constructors */
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;
}
res = newm;
g_hash_table_insert (cache, callsig, res);
/* Can't insert it into wrapper_hash since the key is a signature */
+ g_hash_table_insert (method->klass->image->runtime_invoke_direct_cache, method, res);
} else {
mono_free_method (newm);
}
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_mb_emit_byte (mb, CEE_RET);
- res = mono_mb_create_method (mb, signature_no_pinvoke (stoptr), 0);
+ res = mono_mb_create_method (mb, mono_signature_no_pinvoke (stoptr), 0);
mono_mb_free (mb);
klass->marshal_info->str_to_ptr = res;
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)
if (!ccw) {
ccw = g_new0 (MonoCCW, 1);
+#ifdef PLATFORM_WIN32
+ ccw->free_marshaler = 0;
+#endif
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*/
/* allow gc of object */
guint32 oldhandle = ccw->gc_handle;
g_assert (oldhandle);
+#ifdef PLATFORM_WIN32
+ if (ccw->free_marshaler)
+ ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw->free_marshaler);
+#endif
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
+#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)
+{
+#ifdef PLATFORM_WIN32
+ if (!ccw->free_marshaler) {
+ int ret = 0;
+ gpointer tunk;
+ tunk = cominterop_get_ccw (object, mono_defaults.iunknown_class);
+ /* remember to addref on QI */
+ cominterop_ccw_addref (tunk);
+ ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
+ cominterop_ccw_release(tunk);
+ }
+
+ if (!ccw->free_marshaler)
+ return MONO_E_NOINTERFACE;
+
+ return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
+#else
+ return MONO_E_NOINTERFACE;
+#endif
+}
+#endif
static int STDCALL
cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
if (ppv)
*ppv = NULL;
+ if (!mono_domain_get ())
+ mono_thread_attach (mono_get_root_domain ());
+
/* handle IUnknown special */
if (cominterop_class_guid_equal (riid, mono_defaults.iunknown_class)) {
*ppv = cominterop_get_ccw (object, mono_defaults.iunknown_class);
/* 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);
return MONO_S_OK;
}
+#ifdef PLATFORM_WIN32
+ /* handle IMarshal special */
+ if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
+ return cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv);
+ }
+#endif
+
ifaces = mono_class_get_implemented_interfaces (klass);
if (ifaces) {
for (i = 0; i < ifaces->len; ++i) {