X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fmarshal.c;h=57a01980dd3fe56a603a0dd91002350e1cfd2cd8;hb=94d44cb64a97e7252140bf7dd8e77071eda8480d;hp=81d16e9e9e1256d2853534af78633038adc59d6b;hpb=813eb3e3d2efaa0f4e622a97aaa3911cc4e79843;p=mono.git diff --git a/mono/metadata/marshal.c b/mono/metadata/marshal.c index 81d16e9e9e1..57a01980dd3 100644 --- a/mono/metadata/marshal.c +++ b/mono/metadata/marshal.c @@ -23,6 +23,7 @@ #include "mono/metadata/domain-internals.h" #include "mono/metadata/gc-internal.h" #include "mono/metadata/threads-types.h" +#include "mono/metadata/string-icalls.h" #include #include #include @@ -50,6 +51,7 @@ struct _MonoMethodBuilder { char *name; GList *locals_list; int locals; + gboolean dynamic; guint32 code_size, pos; unsigned char *code; }; @@ -135,12 +137,21 @@ mono_marshal_xdomain_copy_out_value (MonoObject *src, MonoObject *dst); static gint32 mono_marshal_set_domain_by_id (gint32 id, MonoBoolean push); +static gboolean +mono_marshal_check_domain_image (gint32 domain_id, MonoImage *image); + void mono_upgrade_remote_class_wrapper (MonoReflectionType *rtype, MonoTransparentProxy *tproxy); static MonoReflectionType * type_from_handle (MonoType *handle); +static void +mono_marshal_set_last_error_windows (int error); + +static void +mono_marshal_emit_native_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func); + static void register_icall (gpointer func, const char *name, const char *sigstr, gboolean save) { @@ -150,29 +161,188 @@ register_icall (gpointer func, const char *name, const char *sigstr, gboolean sa } static MonoMethodSignature* -signature_dup_mp (MonoMemPool *mp, MonoMethodSignature *sig) +signature_dup (MonoImage *image, MonoMethodSignature *sig) { MonoMethodSignature *res; int sigsize; sigsize = sizeof (MonoMethodSignature) + ((sig->param_count - MONO_ZERO_LEN_ARRAY) * sizeof (MonoType *)); - res = mono_mempool_alloc (mp, sigsize); + mono_loader_lock (); + res = mono_mempool_alloc (image->mempool, sigsize); + mono_loader_unlock (); memcpy (res, sig, sigsize); return res; } static MonoMethodSignature* -signature_no_pinvoke (MonoMethodSignature* sig) +signature_no_pinvoke (MonoMethod *method) { + MonoMethodSignature *sig = mono_method_signature (method); if (sig->pinvoke) { - sig = mono_metadata_signature_dup (sig); + sig = signature_dup (method->klass->image, sig); sig->pinvoke = FALSE; } return sig; } +/** + * signature_cominterop: + * @image: a image + * @sig: managed method signature + * + * Returns: the corresponding unmanaged method signature for a managed COM + * method. + */ +static MonoMethodSignature* +signature_cominterop (MonoImage *image, MonoMethodSignature *sig) +{ + MonoMethodSignature *res; + int sigsize; + int i; + int param_count = sig->param_count + 1; // convert this arg into IntPtr arg + + if (!MONO_TYPE_IS_VOID (sig->ret)) + param_count++; + + sigsize = sizeof (MonoMethodSignature) + ((param_count - MONO_ZERO_LEN_ARRAY) * sizeof (MonoType *)); + mono_loader_lock (); + res = mono_mempool_alloc (image->mempool, sigsize); + mono_loader_unlock (); + memcpy (res, sig, sigsize); + + // now move args forward one + for (i = sig->param_count-1; i >= 0; i--) + res->params[i+1] = sig->params[i]; + + // 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; + } + + // no pinvoke + res->pinvoke = FALSE; + + // no hasthis + res->hasthis = 0; + + // set param_count + res->param_count = param_count; + + // return type is always int32 (HRESULT) + res->ret = &mono_defaults.int32_class->byval_arg; + + // com is always stdcall + res->call_convention = MONO_CALL_STDCALL; + + return res; +} + +/** + * cominterop_get_function_pointer: + * @itf: a pointer to the COM interface + * @slot: the vtable slot of the method pointer to return + * + * Returns: the unmanaged vtable function pointer from the interface + */ +static gpointer +cominterop_get_function_pointer (gpointer itf, int slot) +{ + gpointer func; + func = *((*(gpointer**)itf)+slot); + return func; +} + +/** + * cominterop_get_com_slot_for_method: + * @method: a method + * + * Returns: the method's slot in the COM interface vtable + */ +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 = method->klass; + int i; + + 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; + } + } + g_ptr_array_free (ifaces, TRUE); + } + + 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; +} + +/** + * cominterop_get_method_interface: + * @method: method being called + * + * Returns: the Type on which the method is defined on + */ +static MonoReflectionType* +cominterop_get_method_interface (MonoMethod* method) +{ + GPtrArray *ifaces; + MonoClass *ic = method->klass; + int i; + MonoReflectionType* rt = NULL; + + 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; + } + g_ptr_array_free (ifaces, TRUE); + } + + if (ic) { + MonoType* t = mono_class_get_type (ic); + rt = mono_type_get_object (mono_domain_get(), t); + } + + return rt; +} + void mono_marshal_init (void) { @@ -207,6 +377,7 @@ mono_marshal_init (void) register_icall (mono_marshal_alloc, "mono_marshal_alloc", "ptr int32", FALSE); register_icall (mono_marshal_free, "mono_marshal_free", "void ptr", FALSE); register_icall (mono_marshal_set_last_error, "mono_marshal_set_last_error", "void", FALSE); + register_icall (mono_marshal_set_last_error_windows, "mono_marshal_set_last_error_windows", "void int32", FALSE); register_icall (mono_string_utf8_to_builder, "mono_string_utf8_to_builder", "void ptr ptr", FALSE); register_icall (mono_string_utf16_to_builder, "mono_string_utf16_to_builder", "void ptr ptr", FALSE); register_icall (mono_marshal_free_array, "mono_marshal_free_array", "void ptr int32", FALSE); @@ -221,11 +392,15 @@ mono_marshal_init (void) register_icall (mono_marshal_xdomain_copy_value, "mono_marshal_xdomain_copy_value", "object object", FALSE); register_icall (mono_marshal_xdomain_copy_out_value, "mono_marshal_xdomain_copy_out_value", "void object object", FALSE); register_icall (mono_marshal_set_domain_by_id, "mono_marshal_set_domain_by_id", "int32 int32 int32", FALSE); + register_icall (mono_marshal_check_domain_image, "mono_marshal_check_domain_image", "int32 int32 ptr", FALSE); register_icall (mono_compile_method, "mono_compile_method", "ptr ptr", FALSE); register_icall (mono_context_get, "mono_context_get", "object", FALSE); register_icall (mono_context_set, "mono_context_set", "void object", FALSE); register_icall (mono_upgrade_remote_class_wrapper, "mono_upgrade_remote_class_wrapper", "void object object", FALSE); register_icall (type_from_handle, "type_from_handle", "object ptr", FALSE); + register_icall (mono_gc_wbarrier_generic_store, "wb_generic", "void ptr object", FALSE); + 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); } } @@ -381,6 +556,7 @@ mono_ftnptr_to_delegate (MonoClass *klass, gpointer ftn) mspecs = g_new0 (MonoMarshalSpec*, mono_method_signature (invoke)->param_count + 1); mono_method_get_marshal_info (invoke, mspecs); + /* Freed below so don't alloc from mempool */ sig = mono_metadata_signature_dup (mono_method_signature (invoke)); sig->hasthis = 0; @@ -611,6 +787,7 @@ mono_string_to_lpstr (MonoString *s) MonoException *exc = mono_get_exception_argument ("string", error->message); g_error_free (error); mono_raise_exception(exc); + return NULL; } else { as = CoTaskMemAlloc (len + 1); @@ -693,24 +870,25 @@ mono_string_to_byvalwstr (gpointer dst, MonoString *src, int size) g_assert (size > 1); if (!src) { - memset (dst, 0, size); + memset (dst, 0, size * 2); return; } - len = MIN (size, (mono_string_length (src) * 2)); - memcpy (dst, mono_string_chars (src), len); + len = MIN (size, (mono_string_length (src))); + memcpy (dst, mono_string_chars (src), len * 2); - *((char *)dst + size - 1) = 0; - *((char *)dst + size - 2) = 0; + *((gunichar2 *)dst + len - 1) = 0; } void mono_mb_free (MonoMethodBuilder *mb) { g_list_free (mb->locals_list); - g_free (mb->method); - g_free (mb->name); - g_free (mb->code); + if (!mb->dynamic) { + g_free (mb->method); + g_free (mb->name); + g_free (mb->code); + } g_free (mb); } @@ -741,11 +919,12 @@ mono_mb_new (MonoClass *klass, const char *name, MonoWrapperType type) int mono_mb_add_local (MonoMethodBuilder *mb, MonoType *type) { - int res = mb->locals; + int res; g_assert (mb != NULL); g_assert (type != NULL); + res = mb->locals; mb->locals_list = g_list_append (mb->locals_list, type); mb->locals++; @@ -774,15 +953,30 @@ mono_mb_create_method (MonoMethodBuilder *mb, MonoMethodSignature *signature, in mp = mb->method->klass->image->mempool; - /* Realloc the method info into a mempool */ + if (mb->dynamic) { + method = mb->method; + + method->name = mb->name; + method->dynamic = TRUE; + + ((MonoMethodNormal *)method)->header = header = (MonoMethodHeader *) + g_malloc0 (sizeof (MonoMethodHeader) + mb->locals * sizeof (MonoType *)); + + header->code = mb->code; + } else { + /* Realloc the method info into a mempool */ + + method = mono_mempool_alloc (mp, sizeof (MonoMethodWrapper)); + memcpy (method, mb->method, sizeof (MonoMethodWrapper)); - method = mono_mempool_alloc (mp, sizeof (MonoMethodWrapper)); - memcpy (method, mb->method, sizeof (MonoMethodWrapper)); + method->name = mono_mempool_strdup (mp, mb->name); - method->name = mono_mempool_strdup (mp, mb->name); + ((MonoMethodNormal *)method)->header = header = (MonoMethodHeader *) + mono_mempool_alloc0 (mp, sizeof (MonoMethodHeader) + mb->locals * sizeof (MonoType *)); - ((MonoMethodNormal *)method)->header = header = (MonoMethodHeader *) - mono_mempool_alloc0 (mp, sizeof (MonoMethodHeader) + mb->locals * sizeof (MonoType *)); + header->code = mono_mempool_alloc (mp, mb->pos); + memcpy ((char*)header->code, mb->code, mb->pos); + } if (max_stack < 8) max_stack = 8; @@ -794,8 +988,7 @@ mono_mb_create_method (MonoMethodBuilder *mb, MonoMethodSignature *signature, in } method->signature = signature; - header->code = mono_mempool_alloc (mp, mb->pos); - memcpy ((char*)header->code, mb->code, mb->pos); + header->code_size = mb->pos; header->num_locals = mb->locals; @@ -805,7 +998,10 @@ mono_mb_create_method (MonoMethodBuilder *mb, MonoMethodSignature *signature, in GList *tmp; void **data; l = g_list_reverse (mw->method_data); - data = mono_mempool_alloc (mp, sizeof (gpointer) * (i + 1)); + if (method->dynamic) + data = g_malloc (sizeof (gpointer) * (i + 1)); + else + data = mono_mempool_alloc (mp, sizeof (gpointer) * (i + 1)); /* store the size in the first element */ data [0] = GUINT_TO_POINTER (i); i = 1; @@ -943,14 +1139,19 @@ mono_mb_emit_i2 (MonoMethodBuilder *mb, gint16 data) mb->pos += 2; } +static inline void +mono_mb_emit_op (MonoMethodBuilder *mb, guint8 op, gpointer data) +{ + mono_mb_emit_byte (mb, op); + mono_mb_emit_i4 (mb, mono_mb_add_data (mb, data)); +} + void mono_mb_emit_ldstr (MonoMethodBuilder *mb, char *str) { - mono_mb_emit_byte (mb, CEE_LDSTR); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, str)); + mono_mb_emit_op (mb, CEE_LDSTR, str); } - void mono_mb_emit_ldarg (MonoMethodBuilder *mb, guint argnum) { @@ -1046,26 +1247,46 @@ mono_mb_emit_branch (MonoMethodBuilder *mb, guint8 op) return res; } +guint32 +mono_mb_emit_short_branch (MonoMethodBuilder *mb, guint8 op) +{ + guint32 res; + mono_mb_emit_byte (mb, op); + res = mb->pos; + mono_mb_emit_byte (mb, 0); + + return res; +} + +static void +mono_mb_patch_branch (MonoMethodBuilder *mb, guint32 pos) +{ + mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4)); +} + +static void +mono_mb_patch_short_branch (MonoMethodBuilder *mb, guint32 pos) +{ + mono_mb_patch_addr_s (mb, pos, mb->pos - (pos + 1)); +} + static void mono_mb_emit_ptr (MonoMethodBuilder *mb, gpointer ptr) { mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - mono_mb_emit_byte (mb, CEE_MONO_LDPTR); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, ptr)); + mono_mb_emit_op (mb, CEE_MONO_LDPTR, ptr); } static void mono_mb_emit_calli (MonoMethodBuilder *mb, MonoMethodSignature *sig) { - mono_mb_emit_byte (mb, CEE_CALLI); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, sig)); + mono_mb_emit_op (mb, CEE_CALLI, sig); } void mono_mb_emit_managed_call (MonoMethodBuilder *mb, MonoMethod *method, MonoMethodSignature *opt_sig) { - mono_mb_emit_byte (mb, CEE_CALL); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, method)); + mono_mb_emit_op (mb, CEE_CALL, method); } void @@ -1083,8 +1304,22 @@ static void mono_mb_emit_icall (MonoMethodBuilder *mb, gpointer func) { mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - mono_mb_emit_byte (mb, CEE_MONO_ICALL); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, func)); + mono_mb_emit_op (mb, CEE_MONO_ICALL, func); +} + +static void +mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethod* method) +{ + // get function pointer from 1st arg, the COM interface pointer + mono_mb_emit_ldarg (mb, 0); + mono_mb_emit_icon (mb, cominterop_get_com_slot_for_method (method)); + mono_mb_emit_icall (mb, cominterop_get_function_pointer); + + mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); + mono_mb_emit_byte (mb, CEE_MONO_SAVE_LMF); + mono_mb_emit_calli (mb, sig); + mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); + mono_mb_emit_byte (mb, CEE_MONO_RESTORE_LMF); } static void @@ -1096,8 +1331,7 @@ mono_mb_emit_exception_full (MonoMethodBuilder *mb, const char *exc_nspace, cons mono_class_init (mme); ctor = mono_class_get_method_from_name (mme, ".ctor", 0); g_assert (ctor); - mono_mb_emit_byte (mb, CEE_NEWOBJ); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, ctor)); + mono_mb_emit_op (mb, CEE_NEWOBJ, ctor); if (msg != NULL) { mono_mb_emit_byte (mb, CEE_DUP); mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoException, message)); @@ -1268,39 +1502,92 @@ emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv mono_mb_emit_byte (mb, CEE_STIND_I1); break; case MONO_MARSHAL_CONV_ARRAY_BYVALARRAY: { - MonoClass *eclass = NULL; + MonoClass *eklass = NULL; int esize; if (type->type == MONO_TYPE_SZARRAY) { - eclass = type->data.klass; + eklass = type->data.klass; } else { g_assert_not_reached (); } - if (eclass->valuetype) - esize = mono_class_instance_size (eclass) - sizeof (MonoObject); - else - esize = sizeof (gpointer); + esize = mono_class_native_size (eklass, NULL); /* create a new array */ mono_mb_emit_ldloc (mb, 1); mono_mb_emit_icon (mb, mspec->data.array_data.num_elem); - mono_mb_emit_byte (mb, CEE_NEWARR); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, eclass)); + mono_mb_emit_op (mb, CEE_NEWARR, eklass); mono_mb_emit_byte (mb, CEE_STIND_I); - // FIXME: This only works if the array is blittable + if (eklass->blittable) { + /* copy the elements */ + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoArray, vector)); + mono_mb_emit_byte (mb, CEE_ADD); + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_icon (mb, mspec->data.array_data.num_elem * esize); + mono_mb_emit_byte (mb, CEE_PREFIX1); + mono_mb_emit_byte (mb, CEE_CPBLK); + } + else { + int array_var, src_var, dst_var, index_var; + guint32 label2, label3; + + array_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg); + src_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg); + dst_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg); - /* copy the elements */ - mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_byte (mb, CEE_LDIND_I); - mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoArray, vector)); - mono_mb_emit_byte (mb, CEE_ADD); - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_icon (mb, mspec->data.array_data.num_elem * esize); - mono_mb_emit_byte (mb, CEE_PREFIX1); - mono_mb_emit_byte (mb, CEE_CPBLK); + /* set array_var */ + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_byte (mb, CEE_LDIND_REF); + mono_mb_emit_stloc (mb, array_var); + + /* save the old src pointer */ + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_stloc (mb, src_var); + /* save the old dst pointer */ + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_stloc (mb, dst_var); + + /* Emit marshalling loop */ + index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg); + mono_mb_emit_byte (mb, CEE_LDC_I4_0); + mono_mb_emit_stloc (mb, index_var); + + /* Loop header */ + label2 = mb->pos; + mono_mb_emit_ldloc (mb, index_var); + mono_mb_emit_ldloc (mb, array_var); + mono_mb_emit_byte (mb, CEE_LDLEN); + label3 = mono_mb_emit_branch (mb, CEE_BGE); + + /* src is already set */ + + /* Set dst */ + mono_mb_emit_ldloc (mb, array_var); + mono_mb_emit_ldloc (mb, index_var); + mono_mb_emit_op (mb, CEE_LDELEMA, eklass); + mono_mb_emit_stloc (mb, 1); + /* Do the conversion */ + emit_struct_conv (mb, eklass, TRUE); + + /* Loop footer */ + mono_mb_emit_add_to_local (mb, index_var, 1); + + mono_mb_emit_byte (mb, CEE_BR); + mono_mb_emit_i4 (mb, label2 - (mb->pos + 4)); + + mono_mb_patch_branch (mb, label3); + + /* restore the old src pointer */ + mono_mb_emit_ldloc (mb, src_var); + mono_mb_emit_stloc (mb, 0); + /* restore the old dst pointer */ + mono_mb_emit_ldloc (mb, dst_var); + mono_mb_emit_stloc (mb, 1); + } break; } case MONO_MARSHAL_CONV_ARRAY_BYVALCHARARRAY: { @@ -1309,12 +1596,11 @@ emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv /* create a new array */ mono_mb_emit_ldloc (mb, 1); mono_mb_emit_icon (mb, mspec->data.array_data.num_elem); - mono_mb_emit_byte (mb, CEE_NEWARR); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, eclass)); - mono_mb_emit_byte (mb, CEE_STIND_I); + mono_mb_emit_op (mb, CEE_NEWARR, eclass); + mono_mb_emit_byte (mb, CEE_STIND_REF); mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_byte (mb, CEE_LDIND_REF); mono_mb_emit_ldloc (mb, 0); mono_mb_emit_ptr (mb, mono_defaults.byte_class); mono_mb_emit_icon (mb, mspec->data.array_data.num_elem); @@ -1325,13 +1611,13 @@ emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv mono_mb_emit_ldloc (mb, 1); mono_mb_emit_ldloc (mb, 0); mono_mb_emit_icall (mb, mono_string_new_wrapper); - mono_mb_emit_byte (mb, CEE_STIND_I); + mono_mb_emit_byte (mb, CEE_STIND_REF); break; case MONO_MARSHAL_CONV_STR_BYVALWSTR: mono_mb_emit_ldloc (mb, 1); mono_mb_emit_ldloc (mb, 0); mono_mb_emit_icall (mb, mono_string_from_utf16); - mono_mb_emit_byte (mb, CEE_STIND_I); + mono_mb_emit_byte (mb, CEE_STIND_REF); break; case MONO_MARSHAL_CONV_STR_LPTSTR: case MONO_MARSHAL_CONV_STR_LPSTR: @@ -1339,14 +1625,14 @@ emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv mono_mb_emit_ldloc (mb, 0); mono_mb_emit_byte (mb, CEE_LDIND_I); mono_mb_emit_icall (mb, mono_string_new_wrapper); - mono_mb_emit_byte (mb, CEE_STIND_I); + mono_mb_emit_byte (mb, CEE_STIND_REF); break; case MONO_MARSHAL_CONV_STR_LPWSTR: mono_mb_emit_ldloc (mb, 1); mono_mb_emit_ldloc (mb, 0); mono_mb_emit_byte (mb, CEE_LDIND_I); mono_mb_emit_icall (mb, mono_string_from_utf16); - mono_mb_emit_byte (mb, CEE_STIND_I); + mono_mb_emit_byte (mb, CEE_STIND_REF); break; case MONO_MARSHAL_CONV_OBJECT_STRUCT: { MonoClass *klass = mono_class_from_mono_type (type); @@ -1358,9 +1644,8 @@ emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv /* *dst = new object */ mono_mb_emit_ldloc (mb, 1); mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - mono_mb_emit_byte (mb, CEE_MONO_NEWOBJ); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass)); - mono_mb_emit_byte (mb, CEE_STIND_I); + mono_mb_emit_op (mb, CEE_MONO_NEWOBJ, klass); + mono_mb_emit_byte (mb, CEE_STIND_REF); /* save the old src pointer */ mono_mb_emit_ldloc (mb, 0); @@ -1374,7 +1659,7 @@ emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv mono_mb_emit_byte (mb, CEE_LDIND_I); mono_mb_emit_icon (mb, sizeof (MonoObject)); mono_mb_emit_byte (mb, CEE_ADD); - mono_mb_emit_byte (mb, CEE_STLOC_1); + mono_mb_emit_stloc (mb, 1); emit_struct_conv (mb, klass, TRUE); @@ -1383,7 +1668,7 @@ emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv mono_mb_emit_stloc (mb, 0); /* restore the old dst pointer */ mono_mb_emit_ldloc (mb, dst_var); - mono_mb_emit_byte (mb, CEE_STLOC_1); + mono_mb_emit_stloc (mb, 1); break; } case MONO_MARSHAL_CONV_DEL_FTN: { @@ -1391,12 +1676,11 @@ emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv mono_mb_emit_ldloc (mb, 1); mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - mono_mb_emit_byte (mb, CEE_MONO_CLASSCONST); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass)); + mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass); mono_mb_emit_ldloc (mb, 0); mono_mb_emit_byte (mb, CEE_LDIND_I); mono_mb_emit_icall (mb, mono_ftnptr_to_delegate); - mono_mb_emit_byte (mb, CEE_STIND_I); + mono_mb_emit_byte (mb, CEE_STIND_REF); break; } case MONO_MARSHAL_CONV_ARRAY_LPARRAY: @@ -1492,17 +1776,15 @@ emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv /* free space if free == true */ mono_mb_emit_ldloc (mb, 2); - mono_mb_emit_byte (mb, CEE_BRFALSE_S); - pos = mb->pos; - mono_mb_emit_byte (mb, 0); + pos = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S); mono_mb_emit_ldloc (mb, 1); mono_mb_emit_byte (mb, CEE_LDIND_I); mono_mb_emit_icall (mb, g_free); - mono_mb_patch_addr_s (mb, pos, mb->pos - pos - 1); + mono_mb_patch_short_branch (mb, pos); mono_mb_emit_ldloc (mb, 1); mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_byte (mb, CEE_LDIND_REF); mono_mb_emit_icall (mb, conv_to_icall (conv)); mono_mb_emit_byte (mb, CEE_STIND_I); break; @@ -1512,7 +1794,7 @@ emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv case MONO_MARSHAL_CONV_DEL_FTN: mono_mb_emit_ldloc (mb, 1); mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_byte (mb, CEE_LDIND_REF); mono_mb_emit_icall (mb, conv_to_icall (conv)); mono_mb_emit_byte (mb, CEE_STIND_I); break; @@ -1522,61 +1804,112 @@ emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv mono_mb_emit_ldloc (mb, 1); /* dst */ mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte (mb, CEE_LDIND_I); /* src String */ + mono_mb_emit_byte (mb, CEE_LDIND_REF); /* src String */ mono_mb_emit_icon (mb, mspec->data.array_data.num_elem); mono_mb_emit_icall (mb, conv_to_icall (conv)); break; } case MONO_MARSHAL_CONV_ARRAY_BYVALARRAY: { - MonoClass *eclass = NULL; + MonoClass *eklass = NULL; int esize; if (type->type == MONO_TYPE_SZARRAY) { - eclass = type->data.klass; + eklass = type->data.klass; } else { g_assert_not_reached (); } - if (eclass->valuetype) - esize = mono_class_native_size (eclass, NULL); + if (eklass->valuetype) + esize = mono_class_native_size (eklass, NULL); else esize = sizeof (gpointer); mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte (mb, CEE_LDIND_I); - mono_mb_emit_byte (mb, CEE_BRFALSE_S); - pos = mb->pos; - mono_mb_emit_byte (mb, 0); + mono_mb_emit_byte (mb, CEE_LDIND_REF); + pos = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S); + + if (eklass->blittable) { + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_byte (mb, CEE_LDIND_REF); + mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoArray, vector)); + mono_mb_emit_icon (mb, mspec->data.array_data.num_elem * esize); + mono_mb_emit_byte (mb, CEE_PREFIX1); + mono_mb_emit_byte (mb, CEE_CPBLK); + } else { + int array_var, src_var, dst_var, index_var; + guint32 label2, label3; - // FIXME: This only works if the array is blittable + array_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg); + src_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg); + dst_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg); - mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte (mb, CEE_LDIND_I); - mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - mono_mb_emit_byte (mb, CEE_MONO_OBJADDR); - mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoArray, vector)); - mono_mb_emit_byte (mb, CEE_ADD); - mono_mb_emit_icon (mb, mspec->data.array_data.num_elem * esize); - mono_mb_emit_byte (mb, CEE_PREFIX1); - mono_mb_emit_byte (mb, CEE_CPBLK); - mono_mb_patch_addr_s (mb, pos, mb->pos - pos - 1); + /* set array_var */ + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_byte (mb, CEE_LDIND_REF); + mono_mb_emit_stloc (mb, array_var); + + /* save the old src pointer */ + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_stloc (mb, src_var); + /* save the old dst pointer */ + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_stloc (mb, dst_var); + + /* Emit marshalling loop */ + index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg); + mono_mb_emit_byte (mb, CEE_LDC_I4_0); + mono_mb_emit_stloc (mb, index_var); + + /* Loop header */ + label2 = mb->pos; + mono_mb_emit_ldloc (mb, index_var); + mono_mb_emit_ldloc (mb, array_var); + mono_mb_emit_byte (mb, CEE_LDLEN); + label3 = mono_mb_emit_branch (mb, CEE_BGE); + + /* Set src */ + mono_mb_emit_ldloc (mb, array_var); + mono_mb_emit_ldloc (mb, index_var); + mono_mb_emit_op (mb, CEE_LDELEMA, eklass); + mono_mb_emit_stloc (mb, 0); + + /* dst is already set */ + + /* Do the conversion */ + emit_struct_conv (mb, eklass, FALSE); + + /* Loop footer */ + mono_mb_emit_add_to_local (mb, index_var, 1); + + mono_mb_emit_byte (mb, CEE_BR); + mono_mb_emit_i4 (mb, label2 - (mb->pos + 4)); + + mono_mb_patch_branch (mb, label3); + + /* restore the old src pointer */ + mono_mb_emit_ldloc (mb, src_var); + mono_mb_emit_stloc (mb, 0); + /* restore the old dst pointer */ + mono_mb_emit_ldloc (mb, dst_var); + mono_mb_emit_stloc (mb, 1); + } + + mono_mb_patch_short_branch (mb, pos); break; } case MONO_MARSHAL_CONV_ARRAY_BYVALCHARARRAY: { mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte (mb, CEE_LDIND_I); - mono_mb_emit_byte (mb, CEE_BRFALSE_S); - pos = mb->pos; - mono_mb_emit_byte (mb, 0); + mono_mb_emit_byte (mb, CEE_LDIND_REF); + pos = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S); mono_mb_emit_ldloc (mb, 1); mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_byte (mb, CEE_LDIND_REF); mono_mb_emit_ptr (mb, mono_defaults.byte_class); mono_mb_emit_icon (mb, mspec->data.array_data.num_elem); mono_mb_emit_icall (mb, mono_array_to_byvalarray); - mono_mb_patch_addr_s (mb, pos, mb->pos - pos - 1); + mono_mb_patch_short_branch (mb, pos); break; } case MONO_MARSHAL_CONV_OBJECT_STRUCT: { @@ -1586,10 +1919,8 @@ emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv dst_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg); mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte (mb, CEE_LDIND_I); - mono_mb_emit_byte (mb, CEE_BRFALSE_S); - pos = mb->pos; - mono_mb_emit_byte (mb, 0); + mono_mb_emit_byte (mb, CEE_LDIND_I); + pos = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S); /* save the old src pointer */ mono_mb_emit_ldloc (mb, 0); @@ -1612,9 +1943,9 @@ emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv mono_mb_emit_stloc (mb, 0); /* restore the old dst pointer */ mono_mb_emit_ldloc (mb, dst_var); - mono_mb_emit_byte (mb, CEE_STLOC_1); + mono_mb_emit_stloc (mb, 1); - mono_mb_patch_addr_s (mb, pos, mb->pos - pos - 1); + mono_mb_patch_short_branch (mb, pos); break; } default: { @@ -1747,7 +2078,7 @@ emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object) mono_mb_emit_stloc (mb, 0); /* restore the old dst pointer */ mono_mb_emit_ldloc (mb, dst_var); - mono_mb_emit_byte (mb, CEE_STLOC_1); + mono_mb_emit_stloc (mb, 1); break; } @@ -1780,7 +2111,7 @@ emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object) mono_mb_emit_stloc (mb, 0); /* restore the old dst pointer */ mono_mb_emit_ldloc (mb, dst_var); - mono_mb_emit_byte (mb, CEE_STLOC_1); + mono_mb_emit_stloc (mb, 1); } } @@ -1800,8 +2131,7 @@ emit_struct_free (MonoMethodBuilder *mb, MonoClass *klass, int struct_var) /* Call DestroyStructure */ /* FIXME: Only do this if needed */ mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - mono_mb_emit_byte (mb, CEE_MONO_CLASSCONST); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass)); + mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass); mono_mb_emit_ldloc (mb, struct_var); mono_mb_emit_icall (mb, mono_struct_delete_old); } @@ -1866,7 +2196,7 @@ mono_delegate_begin_invoke (MonoDelegate *delegate, gpointer *params) msg = mono_method_call_message_new (mono_marshal_method_from_wrapper (method), params, NULL, &async_callback, &state); handle = CreateEvent (NULL, TRUE, FALSE, NULL); - ares = mono_async_result_new (mono_domain_get (), handle, state, handle); + 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); MONO_OBJECT_SETREF (msg, async_result, ares); @@ -2231,7 +2561,7 @@ mono_marshal_get_delegate_begin_invoke (MonoMethod *method) g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class && !strcmp (method->name, "BeginInvoke")); - sig = signature_no_pinvoke (mono_method_signature (method)); + sig = signature_no_pinvoke (method); cache = method->klass->image->delegate_begin_invoke_cache; if ((res = mono_marshal_find_in_cache (cache, sig))) @@ -2280,7 +2610,7 @@ mono_delegate_end_invoke (MonoDelegate *delegate, gpointer *params) method = mono_class_get_method_from_name (klass, "EndInvoke", -1); g_assert (method != NULL); - sig = signature_no_pinvoke (mono_method_signature (method)); + sig = signature_no_pinvoke (method); msg = mono_method_call_message_new (method, params, NULL, NULL, NULL); @@ -2348,8 +2678,7 @@ mono_mb_emit_restore_result (MonoMethodBuilder *mb, MonoType *return_type) case MONO_TYPE_I8: case MONO_TYPE_R4: case MONO_TYPE_R8: - mono_mb_emit_byte (mb, CEE_UNBOX); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (return_type))); + mono_mb_emit_op (mb, CEE_UNBOX, mono_class_from_mono_type (return_type)); mono_mb_emit_byte (mb, mono_type_to_ldind (return_type)); break; case MONO_TYPE_GENERICINST: @@ -2357,12 +2686,9 @@ mono_mb_emit_restore_result (MonoMethodBuilder *mb, MonoType *return_type) break; /* fall through */ case MONO_TYPE_VALUETYPE: { - int class; - mono_mb_emit_byte (mb, CEE_UNBOX); - class = mono_mb_add_data (mb, mono_class_from_mono_type (return_type)); - mono_mb_emit_i4 (mb, class); - mono_mb_emit_byte (mb, CEE_LDOBJ); - mono_mb_emit_i4 (mb, class); + MonoClass *klass = mono_class_from_mono_type (return_type); + mono_mb_emit_op (mb, CEE_UNBOX, klass); + mono_mb_emit_op (mb, CEE_LDOBJ, klass); break; } default: @@ -2386,7 +2712,7 @@ mono_marshal_get_delegate_end_invoke (MonoMethod *method) g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class && !strcmp (method->name, "EndInvoke")); - sig = signature_no_pinvoke (mono_method_signature (method)); + sig = signature_no_pinvoke (method); cache = method->klass->image->delegate_end_invoke_cache; if ((res = mono_marshal_find_in_cache (cache, sig))) @@ -2470,20 +2796,271 @@ mono_remoting_wrapper (MonoMethod *method, gpointer *params) return res; } -MonoMethod * -mono_marshal_get_remoting_invoke (MonoMethod *method) +/** + * 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_native_wrapper_adjusted (MonoMethod *method) { - MonoMethodSignature *sig; - MonoMethodBuilder *mb; MonoMethod *res; - int params_var; - - g_assert (method); + MonoMethodBuilder *mb_native; + MonoMarshalSpec **mspecs; + MonoMethodSignature *sig, *sig_native; + MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method; + int i; + + sig = mono_method_signature (method); + + // 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); + + mspecs = g_new (MonoMarshalSpec*, sig_native->param_count+1); + memset (mspecs, 0, sizeof(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 (!MONO_TYPE_IS_VOID (sig->ret)) + mspecs[sig_native->param_count] = mspecs[0]; + + mspecs[0] = NULL; + + mono_marshal_emit_native_wrapper(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); + + for (i = sig_native->param_count; i >= 0; i--) + if (mspecs [i]) + mono_metadata_free_marshal_spec (mspecs [i]); + g_free (mspecs); + + return res; +} + +/** + * cominterop_get_native_wrapper: + * @method: managed method + * + * Returns: the generated method to call + */ +static MonoMethod * +cominterop_get_native_wrapper (MonoMethod *method) +{ + MonoMethod *res; + GHashTable *cache; + MonoMethodBuilder *mb; + MonoMethodSignature *sig, *csig; + + g_assert (method); + + cache = method->klass->image->cominterop_wrapper_cache; + if ((res = mono_marshal_find_in_cache (cache, method))) + return res; + + sig = mono_method_signature (method); + mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP); + + /* if method klass is import, that means method + * is really a com call. let interop system emit it. + */ + if (MONO_CLASS_IS_IMPORT(method->klass)) { + /* FIXME: we have to call actual class .ctor + * instead of just __ComObject .ctor. + */ + if (!strcmp(method->name, ".ctor")) { + static MonoMethod *ctor = NULL; + + if (!ctor) + ctor = mono_class_get_method_from_name (mono_defaults.com_object_class, ".ctor", 0); + mono_mb_emit_ldarg (mb, 0); + mono_mb_emit_managed_call (mb, ctor, NULL); + mono_mb_emit_byte (mb, CEE_RET); + } + else { + static MonoMethod * ThrowExceptionForHR = NULL; + static MonoMethod * GetInterface = NULL; + MonoMethod *adjusted_method; + int hr; + int retval = 0; + int ptr_this; + int i; + 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); + + // get the type for the interface the method is defined on + // and then get the underlying COM interface for that type + mono_mb_emit_ldarg (mb, 0); + mono_mb_emit_ptr (mb, method); + mono_mb_emit_icall (mb, cominterop_get_method_interface); + mono_mb_emit_managed_call (mb, GetInterface, NULL); + mono_mb_emit_stloc (mb, ptr_this); + + // arg 1 is unmanaged this pointer + mono_mb_emit_ldloc (mb, ptr_this); + + // load args + for (i = 1; i <= sig->param_count; i++) + mono_mb_emit_ldarg (mb, i); + + // push managed return value as byref last argument + if (!MONO_TYPE_IS_VOID (sig->ret)) + 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); + + // 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); + } + + + } + /* Does this case ever get hit? */ + else { + char *msg = g_strdup ("non imported interfaces on \ + imported classes is not yet implemented."); + mono_mb_emit_exception (mb, "NotSupportedException", msg); + } + csig = signature_dup (method->klass->image, sig); + csig->pinvoke = 0; + res = mono_mb_create_and_cache (cache, method, + mb, csig, csig->param_count + 16); + mono_mb_free (mb); + return res; +} + +/** + * cominterop_get_invoke: + * @method: managed method + * + * Returns: the generated method that calls the underlying __ComObject + * rather than the proxy object. + */ +static MonoMethod * +cominterop_get_invoke (MonoMethod *method) +{ + MonoMethodSignature *sig; + MonoMethodBuilder *mb; + MonoMethod *res; + int i, temp_obj; + GHashTable* cache = method->klass->image->cominterop_invoke_cache; + + g_assert (method); + + if ((res = mono_marshal_find_in_cache (cache, method))) + return res; + + sig = signature_no_pinvoke (method); + + /* we cant remote methods without this pointer */ + if (!sig->hasthis) + return method; + + mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP_INVOKE); + + /* get real proxy object, which is a ComInteropProxy in this case*/ + temp_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg); + mono_mb_emit_ldarg (mb, 0); + mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp)); + mono_mb_emit_byte (mb, CEE_LDIND_REF); + + /* 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); + + /* load args and make the call on the RCW */ + for (i = 1; i <= sig->param_count; i++) + mono_mb_emit_ldarg (mb, i); + + if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) { + MonoMethod * native_wrapper = cominterop_get_native_wrapper(method); + mono_mb_emit_managed_call (mb, native_wrapper, NULL); + } + else { + if (method->flags & METHOD_ATTRIBUTE_VIRTUAL) + mono_mb_emit_op (mb, CEE_CALLVIRT, method); + else + mono_mb_emit_op (mb, CEE_CALL, method); + } + + if (!strcmp(method->name, ".ctor")) { + static MonoClass *com_interop_proxy_class = NULL; + static MonoMethod *cache_proxy = NULL; + + if (!com_interop_proxy_class) + com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy"); + if (!cache_proxy) + cache_proxy = mono_class_get_method_from_name (com_interop_proxy_class, "CacheProxy", 0); + + mono_mb_emit_ldarg (mb, 0); + mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp)); + mono_mb_emit_byte (mb, CEE_LDIND_REF); + mono_mb_emit_managed_call (mb, cache_proxy, NULL); + } + + emit_thread_interrupt_checkpoint (mb); + + mono_mb_emit_byte (mb, CEE_RET); + + res = mono_mb_create_and_cache (cache, method, mb, sig, sig->param_count + 16); + mono_mb_free (mb); + + return res; +} + +MonoMethod * +mono_marshal_get_remoting_invoke (MonoMethod *method) +{ + MonoMethodSignature *sig; + MonoMethodBuilder *mb; + MonoMethod *res; + int params_var; + + g_assert (method); if (method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE || method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE) return method; - sig = signature_no_pinvoke (mono_method_signature (method)); + /* this seems to be the best plase to put this, as all remoting invokes seem to get filtered through here */ + if ((method->klass->is_com_object || method->klass == mono_defaults.com_object_class) && !mono_class_vtable (mono_domain_get (), method->klass)->remote) + return cominterop_get_invoke(method); + + sig = signature_no_pinvoke (method); /* we cant remote methods without this pointer */ if (!sig->hasthis) @@ -2660,8 +3237,7 @@ static void mono_marshal_emit_xdomain_copy_value (MonoMethodBuilder *mb, MonoClass *pclass) { mono_mb_emit_icall (mb, mono_marshal_xdomain_copy_value); - mono_mb_emit_byte (mb, CEE_CASTCLASS); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, pclass)); + mono_mb_emit_op (mb, CEE_CASTCLASS, pclass); } static void @@ -2717,6 +3293,31 @@ mono_marshal_emit_load_domain_method (MonoMethodBuilder *mb, MonoMethod *method) mono_mb_emit_icall (mb, mono_compile_method); } +/* mono_marshal_check_domain_image () + * Returns TRUE if the image is loaded in the specified + * application domain. + */ +static gboolean +mono_marshal_check_domain_image (gint32 domain_id, MonoImage *image) +{ + MonoAssembly* ass; + GSList *tmp; + + MonoDomain *domain = mono_domain_get_by_id (domain_id); + if (!domain) + return FALSE; + + mono_domain_assemblies_lock (domain); + for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) { + ass = tmp->data; + if (ass->image == image) + break; + } + mono_domain_assemblies_unlock (domain); + + return tmp != NULL; +} + /* mono_marshal_get_xappdomain_dispatch () * Generates a method that dispatches a method call from another domain into * the current domain. @@ -2786,9 +3387,7 @@ mono_marshal_get_xappdomain_dispatch (MonoMethod *method, int *marshal_types, in mono_mb_emit_ldarg (mb, 1); mono_mb_emit_byte (mb, CEE_LDIND_REF); mono_mb_emit_byte (mb, CEE_DUP); - mono_mb_emit_byte (mb, CEE_BRFALSE_S); - pos = mb->pos; - mono_mb_emit_byte (mb, 0); + pos = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S); mono_marshal_emit_xdomain_copy_value (mb, byte_array_class); mono_mb_emit_managed_call (mb, method_rs_deserialize, NULL); @@ -2821,24 +3420,19 @@ mono_marshal_get_xappdomain_dispatch (MonoMethod *method, int *marshal_types, in if (pt->byref) { if (pclass->valuetype) { mono_mb_emit_byte (mb, CEE_LDELEM_REF); - mono_mb_emit_byte (mb, CEE_UNBOX); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, pclass)); + mono_mb_emit_op (mb, CEE_UNBOX, pclass); } else { - mono_mb_emit_byte (mb, CEE_LDELEMA); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, pclass)); + mono_mb_emit_op (mb, CEE_LDELEMA, pclass); } } else { if (pclass->valuetype) { mono_mb_emit_byte (mb, CEE_LDELEM_REF); - mono_mb_emit_byte (mb, CEE_UNBOX); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, pclass)); - mono_mb_emit_byte (mb, CEE_LDOBJ); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, pclass)); + mono_mb_emit_op (mb, CEE_UNBOX, pclass); + mono_mb_emit_op (mb, CEE_LDOBJ, pclass); } else { mono_mb_emit_byte (mb, CEE_LDELEM_REF); if (pclass != mono_defaults.object_class) { - mono_mb_emit_byte (mb, CEE_CASTCLASS); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, pclass)); + mono_mb_emit_op (mb, CEE_CASTCLASS, pclass); } } } @@ -2877,8 +3471,7 @@ mono_marshal_get_xappdomain_dispatch (MonoMethod *method, int *marshal_types, in emit_thread_force_interrupt_checkpoint (mb); - mono_mb_emit_byte (mb, CEE_CALLVIRT); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, method)); + mono_mb_emit_op (mb, CEE_CALLVIRT, method); if (sig->ret->type != MONO_TYPE_VOID) mono_mb_emit_stloc (mb, loc_return); @@ -2920,8 +3513,7 @@ mono_marshal_get_xappdomain_dispatch (MonoMethod *method, int *marshal_types, in mono_mb_emit_icon (mb, complex_count); /* The array has an additional slot to hold the ret value */ mono_mb_emit_ldloc (mb, loc_return); if (ret_class->valuetype) { - mono_mb_emit_byte (mb, CEE_BOX); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, ret_class)); + mono_mb_emit_op (mb, CEE_BOX, ret_class); } mono_mb_emit_byte (mb, CEE_STELEM_REF); } @@ -2936,8 +3528,7 @@ mono_marshal_get_xappdomain_dispatch (MonoMethod *method, int *marshal_types, in mono_mb_emit_ldarg (mb, 1); mono_mb_emit_ldloc (mb, loc_return); if (ret_class->valuetype) { - mono_mb_emit_byte (mb, CEE_BOX); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, ret_class)); + mono_mb_emit_op (mb, CEE_BOX, ret_class); } mono_mb_emit_managed_call (mb, method_rs_serialize, NULL); mono_mb_emit_byte (mb, CEE_STIND_REF); @@ -2951,9 +3542,7 @@ mono_marshal_get_xappdomain_dispatch (MonoMethod *method, int *marshal_types, in mono_mb_emit_ldarg (mb, 2); mono_mb_emit_byte (mb, CEE_LDNULL); mono_mb_emit_byte (mb, CEE_STIND_REF); - mono_mb_emit_byte (mb, CEE_LEAVE); - pos_leave = mb->pos; - mono_mb_emit_i4 (mb, 0); + pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE); /* Main exception catch */ main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE; @@ -2967,8 +3556,7 @@ mono_marshal_get_xappdomain_dispatch (MonoMethod *method, int *marshal_types, in mono_mb_emit_ldarg (mb, 2); mono_mb_emit_ldloc (mb, loc_serialized_exc); mono_mb_emit_byte (mb, CEE_STIND_REF); - mono_mb_emit_byte (mb, CEE_LEAVE); - mono_mb_emit_i4 (mb, 0); + mono_mb_emit_branch (mb, CEE_LEAVE); main_clause->handler_len = mb->pos - main_clause->handler_offset; /* end catch */ @@ -3004,8 +3592,8 @@ mono_marshal_get_xappdomain_invoke (MonoMethod *method) MonoMethod *xdomain_method; int ret_marshal_type = MONO_MARSHAL_NONE; int loc_array=0, loc_serialized_data=-1, loc_real_proxy; - int loc_old_domainid, loc_return=0, loc_serialized_exc=0, loc_context; - int pos, pos_noex; + int loc_old_domainid, loc_domainid, loc_return=0, loc_serialized_exc=0, loc_context; + int pos, pos_dispatch, pos_noex; gboolean copy_return = FALSE; g_assert (method); @@ -3025,7 +3613,7 @@ mono_marshal_get_xappdomain_invoke (MonoMethod *method) if ((res = mono_marshal_remoting_find_in_cache (method, MONO_WRAPPER_XDOMAIN_INVOKE))) return res; - sig = signature_no_pinvoke (mono_method_signature (method)); + sig = signature_no_pinvoke (method); mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_XDOMAIN_INVOKE); mb->method->save_lmf = 1; @@ -3065,6 +3653,7 @@ mono_marshal_get_xappdomain_invoke (MonoMethod *method) if (copy_return) loc_return = mono_mb_add_local (mb, sig->ret); loc_old_domainid = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg); + loc_domainid = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg); loc_serialized_exc = mono_mb_add_local (mb, &byte_array_class->byval_arg); loc_context = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg); @@ -3078,24 +3667,48 @@ mono_marshal_get_xappdomain_invoke (MonoMethod *method) * through the whole remoting sink, since the context is going to change */ mono_mb_emit_managed_call (mb, method_needs_context_sink, NULL); - mono_mb_emit_byte (mb, CEE_BRFALSE_S); - pos = mb->pos; - mono_mb_emit_byte (mb, 0); + pos = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S); + /* Another case in which the fast path can't be used: when the target domain + * has a different image for the same assembly. + */ + + /* Get the target domain id */ + + mono_mb_emit_ldarg (mb, 0); + mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp)); + mono_mb_emit_byte (mb, CEE_LDIND_REF); + mono_mb_emit_byte (mb, CEE_DUP); + mono_mb_emit_stloc (mb, loc_real_proxy); + + mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoRealProxy, target_domain_id)); + mono_mb_emit_byte (mb, CEE_LDIND_I4); + mono_mb_emit_stloc (mb, loc_domainid); + + /* Check if the target domain has the same image for the required assembly */ + + mono_mb_emit_ldloc (mb, loc_domainid); + mono_mb_emit_ptr (mb, method->klass->image); + mono_mb_emit_icall (mb, mono_marshal_check_domain_image); + pos_dispatch = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S); + + /* Use the whole remoting sink to dispatch this message */ + + mono_mb_patch_short_branch (mb, pos); + mono_mb_emit_ldarg (mb, 0); for (i = 0; i < sig->param_count; i++) mono_mb_emit_ldarg (mb, i + 1); mono_mb_emit_managed_call (mb, mono_marshal_get_remoting_invoke (method), NULL); mono_mb_emit_byte (mb, CEE_RET); - mono_mb_patch_addr_s (mb, pos, mb->pos - pos - 1); + mono_mb_patch_short_branch (mb, pos_dispatch); /* Create the array that will hold the parameters to be serialized */ if (complex_count > 0) { mono_mb_emit_icon (mb, (ret_marshal_type == MONO_MARSHAL_SERIALIZE && complex_out_count > 0) ? complex_count + 1 : complex_count); /* +1 for the return type */ - mono_mb_emit_byte (mb, CEE_NEWARR); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_defaults.object_class)); + mono_mb_emit_op (mb, CEE_NEWARR, mono_defaults.object_class); j = 0; for (i = 0; i < sig->param_count; i++) { @@ -3106,17 +3719,13 @@ mono_marshal_get_xappdomain_invoke (MonoMethod *method) mono_mb_emit_icon (mb, j); mono_mb_emit_ldarg (mb, i + 1); /* 0=this */ if (sig->params[i]->byref) { - if (pclass->valuetype) { - mono_mb_emit_byte (mb, CEE_LDOBJ); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, pclass)); - } else { + if (pclass->valuetype) + mono_mb_emit_op (mb, CEE_LDOBJ, pclass); + else mono_mb_emit_byte (mb, CEE_LDIND_REF); - } - } - if (pclass->valuetype) { - mono_mb_emit_byte (mb, CEE_BOX); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, pclass)); } + if (pclass->valuetype) + mono_mb_emit_op (mb, CEE_BOX, pclass); mono_mb_emit_byte (mb, CEE_STELEM_REF); j++; } @@ -3133,20 +3742,10 @@ mono_marshal_get_xappdomain_invoke (MonoMethod *method) mono_mb_emit_stloc (mb, loc_serialized_data); } - /* Get the target domain id */ - - mono_mb_emit_ldarg (mb, 0); - mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp)); - mono_mb_emit_byte (mb, CEE_LDIND_REF); - mono_mb_emit_byte (mb, CEE_DUP); - mono_mb_emit_stloc (mb, loc_real_proxy); - - mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoRealProxy, target_domain_id)); - mono_mb_emit_byte (mb, CEE_LDIND_I4); - mono_mb_emit_byte (mb, CEE_LDC_I4_1); - /* switch domain */ + mono_mb_emit_ldloc (mb, loc_domainid); + mono_mb_emit_byte (mb, CEE_LDC_I4_1); mono_marshal_emit_switch_domain (mb); mono_mb_emit_stloc (mb, loc_old_domainid); @@ -3206,15 +3805,12 @@ mono_marshal_get_xappdomain_invoke (MonoMethod *method) /* if (loc_serialized_exc != null) ... */ mono_mb_emit_ldloc (mb, loc_serialized_exc); - mono_mb_emit_byte (mb, CEE_BRFALSE_S); - pos_noex = mb->pos; - mono_mb_emit_byte (mb, 0); + pos_noex = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S); mono_mb_emit_ldloc (mb, loc_serialized_exc); mono_marshal_emit_xdomain_copy_value (mb, byte_array_class); mono_mb_emit_managed_call (mb, method_rs_deserialize, NULL); - mono_mb_emit_byte (mb, CEE_CASTCLASS); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_defaults.exception_class)); + mono_mb_emit_op (mb, CEE_CASTCLASS, mono_defaults.exception_class); mono_mb_emit_managed_call (mb, method_exc_fixexc, NULL); mono_mb_emit_byte (mb, CEE_THROW); mono_mb_patch_addr_s (mb, pos_noex, mb->pos - pos_noex - 1); @@ -3250,17 +3846,12 @@ mono_marshal_get_xappdomain_invoke (MonoMethod *method) mono_mb_emit_icon (mb, j); mono_mb_emit_byte (mb, CEE_LDELEM_REF); if (pclass->valuetype) { - mono_mb_emit_byte (mb, CEE_UNBOX); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, pclass)); - mono_mb_emit_byte (mb, CEE_LDOBJ); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, pclass)); - mono_mb_emit_byte (mb, CEE_STOBJ); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, pclass)); + mono_mb_emit_op (mb, CEE_UNBOX, pclass); + mono_mb_emit_op (mb, CEE_LDOBJ, pclass); + mono_mb_emit_op (mb, CEE_STOBJ, pclass); } else { - if (pclass != mono_defaults.object_class) { - mono_mb_emit_byte (mb, CEE_CASTCLASS); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, pclass)); - } + if (pclass != mono_defaults.object_class) + mono_mb_emit_op (mb, CEE_CASTCLASS, pclass); mono_mb_emit_byte (mb, CEE_STIND_REF); } } @@ -3272,10 +3863,8 @@ mono_marshal_get_xappdomain_invoke (MonoMethod *method) mono_mb_emit_icon (mb, complex_count); mono_mb_emit_byte (mb, CEE_LDELEM_REF); if (ret_class->valuetype) { - mono_mb_emit_byte (mb, CEE_UNBOX); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, ret_class)); - mono_mb_emit_byte (mb, CEE_LDOBJ); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, ret_class)); + mono_mb_emit_op (mb, CEE_UNBOX, ret_class); + mono_mb_emit_op (mb, CEE_LDOBJ, ret_class); } } } else if (ret_marshal_type == MONO_MARSHAL_SERIALIZE) { @@ -3283,20 +3872,15 @@ mono_marshal_get_xappdomain_invoke (MonoMethod *method) mono_marshal_emit_xdomain_copy_value (mb, byte_array_class); mono_mb_emit_managed_call (mb, method_rs_deserialize, NULL); if (ret_class->valuetype) { - mono_mb_emit_byte (mb, CEE_UNBOX); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, ret_class)); - mono_mb_emit_byte (mb, CEE_LDOBJ); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, ret_class)); + mono_mb_emit_op (mb, CEE_UNBOX, ret_class); + mono_mb_emit_op (mb, CEE_LDOBJ, ret_class); } else if (ret_class != mono_defaults.object_class) { - mono_mb_emit_byte (mb, CEE_CASTCLASS); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, ret_class)); + mono_mb_emit_op (mb, CEE_CASTCLASS, ret_class); } } else { mono_mb_emit_ldloc (mb, loc_serialized_data); mono_mb_emit_byte (mb, CEE_DUP); - mono_mb_emit_byte (mb, CEE_BRFALSE_S); - pos = mb->pos; - mono_mb_emit_byte (mb, 0); + pos = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S); mono_marshal_emit_xdomain_copy_value (mb, byte_array_class); mono_mb_patch_addr_s (mb, pos, mb->pos - (pos + 1)); @@ -3323,6 +3907,8 @@ mono_marshal_get_remoting_invoke_for_target (MonoMethod *method, MonoRemotingTar { if (target_type == MONO_REMOTING_TARGET_APPDOMAIN) return mono_marshal_get_xappdomain_invoke (method); + else if (target_type == MONO_REMOTING_TARGET_COMINTEROP) + return cominterop_get_invoke (method); else return mono_marshal_get_remoting_invoke (method); } @@ -3349,7 +3935,7 @@ mono_marshal_get_remoting_invoke_with_check (MonoMethod *method) if (method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) return method; - sig = signature_no_pinvoke (mono_method_signature (method)); + sig = signature_no_pinvoke (method); /* we cant remote methods without this pointer */ g_assert (sig->hasthis); @@ -3382,7 +3968,7 @@ mono_marshal_get_remoting_invoke_with_check (MonoMethod *method) mono_mb_emit_byte (mb, CEE_RET); /* not a proxy */ - mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4)); + mono_mb_patch_branch (mb, pos); mono_mb_emit_managed_call (mb, method, mono_method_signature (method)); mono_mb_emit_byte (mb, CEE_RET); @@ -3409,13 +3995,13 @@ mono_marshal_get_delegate_invoke (MonoMethod *method) g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class && !strcmp (method->name, "Invoke")); - sig = signature_no_pinvoke (mono_method_signature (method)); + sig = signature_no_pinvoke (method); cache = method->klass->image->delegate_invoke_cache; if ((res = mono_marshal_find_in_cache (cache, sig))) return res; - static_sig = mono_metadata_signature_dup (sig); + static_sig = signature_dup (method->klass->image, sig); static_sig->hasthis = 0; name = mono_signature_to_name (sig, "invoke"); @@ -3444,10 +4030,7 @@ mono_marshal_get_delegate_invoke (MonoMethod *method) /* if prev != null */ mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte (mb, CEE_BRFALSE); - - pos0 = mb->pos; - mono_mb_emit_i4 (mb, 0); + pos0 = mono_mb_emit_branch (mb, CEE_BRFALSE); /* then recurse */ mono_mb_emit_ldloc (mb, 0); @@ -3458,7 +4041,7 @@ mono_marshal_get_delegate_invoke (MonoMethod *method) mono_mb_emit_byte (mb, CEE_POP); /* continued or prev == null */ - mono_mb_patch_addr (mb, pos0, mb->pos - (pos0 + 4)); + mono_mb_patch_branch (mb, pos0); /* get this->target */ mono_mb_emit_ldarg (mb, 0); @@ -3468,9 +4051,7 @@ mono_marshal_get_delegate_invoke (MonoMethod *method) /* if target != null */ mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte (mb, CEE_BRFALSE); - pos0 = mb->pos; - mono_mb_emit_i4 (mb, 0); + pos0 = mono_mb_emit_branch (mb, CEE_BRFALSE); /* then call this->method_ptr nonstatic */ mono_mb_emit_ldloc (mb, 0); @@ -3479,26 +4060,22 @@ mono_marshal_get_delegate_invoke (MonoMethod *method) mono_mb_emit_ldarg (mb, 0); mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoDelegate, method_ptr)); mono_mb_emit_byte (mb, CEE_LDIND_I ); - mono_mb_emit_byte (mb, CEE_CALLI); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, sig)); + mono_mb_emit_op (mb, CEE_CALLI, sig); - mono_mb_emit_byte (mb, CEE_BR); - pos1 = mb->pos; - mono_mb_emit_i4 (mb, 0); + pos1 = mono_mb_emit_branch (mb, CEE_BR); /* else [target == null] call this->method_ptr static */ - mono_mb_patch_addr (mb, pos0, mb->pos - (pos0 + 4)); + mono_mb_patch_branch (mb, pos0); for (i = 0; i < sig->param_count; ++i) mono_mb_emit_ldarg (mb, i + 1); mono_mb_emit_ldarg (mb, 0); mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoDelegate, method_ptr)); mono_mb_emit_byte (mb, CEE_LDIND_I ); - mono_mb_emit_byte (mb, CEE_CALLI); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, static_sig)); + mono_mb_emit_op (mb, CEE_CALLI, static_sig); /* return */ - mono_mb_patch_addr (mb, pos1, mb->pos - (pos1 + 4)); + mono_mb_patch_branch (mb, pos1); mono_mb_emit_byte (mb, CEE_RET); res = mono_mb_create_and_cache (cache, sig, @@ -3578,7 +4155,7 @@ mono_marshal_get_runtime_invoke (MonoMethod *method) } } if (!callsig) { - callsig = mono_metadata_signature_dup (mono_method_signature (method)); + 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; @@ -3649,7 +4226,7 @@ mono_marshal_get_runtime_invoke (MonoMethod *method) mono_mb_emit_byte (mb, 3); mono_mb_emit_byte (mb, CEE_LDARG_2); mono_mb_emit_byte (mb, CEE_LDNULL); - mono_mb_emit_byte (mb, CEE_STIND_I); + mono_mb_emit_byte (mb, CEE_STIND_REF); emit_thread_force_interrupt_checkpoint (mb); @@ -3702,6 +4279,13 @@ handle_enum: case MONO_TYPE_OBJECT: /* do nothing */ break; + case MONO_TYPE_GENERICINST: + if (!mono_type_generic_inst_is_valuetype (sig->params [i])) { + /* do nothing */ + break; + } + + /* fall through */ case MONO_TYPE_VALUETYPE: if (t->data.klass->enumtype) { type = t->data.klass->enum_basetype->type; @@ -3709,19 +4293,12 @@ handle_enum: } if (mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) { /* Need to convert a boxed vtype to an mp to a Nullable struct */ - mono_mb_emit_byte (mb, CEE_UNBOX); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (sig->params [i]))); - mono_mb_emit_byte (mb, CEE_LDOBJ); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (sig->params [i]))); + mono_mb_emit_op (mb, CEE_UNBOX, mono_class_from_mono_type (sig->params [i])); + mono_mb_emit_op (mb, CEE_LDOBJ, mono_class_from_mono_type (sig->params [i])); } else { - mono_mb_emit_byte (mb, CEE_LDOBJ); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, t->data.klass)); + mono_mb_emit_op (mb, CEE_LDOBJ, mono_class_from_mono_type (sig->params [i])); } break; - case MONO_TYPE_GENERICINST: - t = &t->data.generic_class->container_class->byval_arg; - type = t->type; - goto handle_enum; default: g_assert_not_reached (); } @@ -3759,8 +4336,7 @@ handle_enum: case MONO_TYPE_TYPEDBYREF: case MONO_TYPE_GENERICINST: /* box value types */ - mono_mb_emit_byte (mb, CEE_BOX); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (sig->ret))); + mono_mb_emit_op (mb, CEE_BOX, mono_class_from_mono_type (sig->ret)); break; case MONO_TYPE_STRING: case MONO_TYPE_CLASS: @@ -3776,9 +4352,7 @@ handle_enum: mono_mb_emit_stloc (mb, 0); - mono_mb_emit_byte (mb, CEE_LEAVE); - pos = mb->pos; - mono_mb_emit_i4 (mb, 0); + pos = mono_mb_emit_branch (mb, CEE_LEAVE); mono_loader_lock (); clause = mono_mempool_alloc0 (target_klass->image->mempool, sizeof (MonoExceptionClause)); @@ -3805,30 +4379,26 @@ handle_enum: mono_mb_emit_byte (mb, CEE_LDARG_2); mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_byte (mb, CEE_STIND_I); + mono_mb_emit_byte (mb, CEE_STIND_REF); mono_mb_emit_byte (mb, CEE_LDNULL); mono_mb_emit_stloc (mb, 0); /* Check for the abort exception */ mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_byte (mb, CEE_ISINST); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_defaults.threadabortexception_class)); - mono_mb_emit_byte (mb, CEE_BRFALSE_S); - posna = mb->pos; - mono_mb_emit_byte (mb, 0); + mono_mb_emit_op (mb, CEE_ISINST, mono_defaults.threadabortexception_class); + posna = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S); /* Delay the abort exception */ mono_mb_emit_native_call (mb, dealy_abort_sig, ves_icall_System_Threading_Thread_ResetAbort); - mono_mb_patch_addr_s (mb, posna, mb->pos - posna - 1); - mono_mb_emit_byte (mb, CEE_LEAVE); - mono_mb_emit_i4 (mb, 0); + mono_mb_patch_short_branch (mb, posna); + mono_mb_emit_branch (mb, CEE_LEAVE); clause->handler_len = mb->pos - clause->handler_offset; /* return result */ - mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4)); + mono_mb_patch_branch (mb, pos); mono_mb_emit_ldloc (mb, 0); mono_mb_emit_byte (mb, CEE_RET); @@ -4007,17 +4577,14 @@ mono_marshal_get_ldfld_wrapper (MonoType *type) */ if (klass->valuetype) { - mono_mb_emit_byte (mb, CEE_UNBOX); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass)); - mono_mb_emit_byte (mb, CEE_BR); - pos1 = mb->pos; - mono_mb_emit_i4 (mb, 0); + mono_mb_emit_op (mb, CEE_UNBOX, klass); + pos1 = mono_mb_emit_branch (mb, CEE_BR); } else { mono_mb_emit_byte (mb, CEE_RET); } - mono_mb_patch_addr (mb, pos0, mb->pos - (pos0 + 4)); + mono_mb_patch_branch (mb, pos0); mono_mb_emit_ldarg (mb, 0); mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); @@ -4026,7 +4593,7 @@ mono_marshal_get_ldfld_wrapper (MonoType *type) mono_mb_emit_byte (mb, CEE_ADD); if (klass->valuetype) - mono_mb_patch_addr (mb, pos1, mb->pos - (pos1 + 4)); + mono_mb_patch_branch (mb, pos1); switch (t) { case MONO_TYPE_I1: @@ -4054,13 +4621,11 @@ mono_marshal_get_ldfld_wrapper (MonoType *type) break; case MONO_TYPE_VALUETYPE: g_assert (!klass->enumtype); - mono_mb_emit_byte (mb, CEE_LDOBJ); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass)); + mono_mb_emit_op (mb, CEE_LDOBJ, klass); break; case MONO_TYPE_GENERICINST: if (mono_type_generic_inst_is_valuetype (type)) { - mono_mb_emit_byte (mb, CEE_LDOBJ); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass)); + mono_mb_emit_op (mb, CEE_LDOBJ, klass); } else { mono_mb_emit_byte (mb, CEE_LDIND_REF); } @@ -4145,7 +4710,7 @@ mono_marshal_get_ldflda_wrapper (MonoType *type) /* FIXME: Only throw this if the object is in another appdomain */ mono_mb_emit_exception_full (mb, "System", "InvalidOperationException", "Attempt to load field address from object in another appdomain."); - mono_mb_patch_addr (mb, pos0, mb->pos - (pos0 + 4)); + mono_mb_patch_branch (mb, pos0); mono_mb_emit_ldarg (mb, 0); mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); @@ -4200,10 +4765,8 @@ mono_marshal_get_stfld_remote_wrapper (MonoClass *klass) mono_mb_emit_ldarg (mb, 2); mono_mb_emit_ldarg (mb, 3); - if (klass->valuetype) { - mono_mb_emit_byte (mb, CEE_BOX); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass)); - } + if (klass->valuetype) + mono_mb_emit_op (mb, CEE_BOX, klass); csig = mono_metadata_signature_alloc (mono_defaults.corlib, 4); csig->params [0] = &mono_defaults.object_class->byval_arg; @@ -4297,7 +4860,7 @@ mono_marshal_get_stfld_wrapper (MonoType *type) mono_mb_emit_byte (mb, CEE_RET); - mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4)); + mono_mb_patch_branch (mb, pos); mono_mb_emit_ldarg (mb, 0); mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); @@ -4332,12 +4895,10 @@ mono_marshal_get_stfld_wrapper (MonoType *type) break; case MONO_TYPE_VALUETYPE: g_assert (!klass->enumtype); - mono_mb_emit_byte (mb, CEE_STOBJ); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass)); + mono_mb_emit_op (mb, CEE_STOBJ, klass); break; case MONO_TYPE_GENERICINST: - mono_mb_emit_byte (mb, CEE_STOBJ); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass)); + mono_mb_emit_op (mb, CEE_STOBJ, klass); break; default: g_warning ("type %x not implemented", type->type); @@ -4383,9 +4944,7 @@ mono_marshal_get_icall_wrapper (MonoMethodSignature *sig, const char *name, gcon emit_thread_interrupt_checkpoint (mb); mono_mb_emit_byte (mb, CEE_RET); - mono_loader_lock (); - csig = signature_dup_mp (mono_defaults.corlib->mempool, sig); - mono_loader_unlock (); + csig = signature_dup (mono_defaults.corlib, sig); csig->pinvoke = 0; if (csig->call_convention == MONO_CALL_VARARG) csig->call_convention = 0; @@ -4403,6 +4962,7 @@ typedef struct { int *orig_conv_args; /* Locals containing the original values of byref args */ int retobj_var; MonoClass *retobj_class; + MonoMethodSignature *csig; /* Might need to be changed due to MarshalAs directives */ } EmitMarshalContext; typedef enum { @@ -4524,8 +5084,7 @@ emit_marshal_custom (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie)); - mono_mb_emit_byte (mb, CEE_CALL); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, get_instance)); + mono_mb_emit_op (mb, CEE_CALL, get_instance); mono_mb_emit_ldarg (mb, argnum); if (t->byref) @@ -4538,15 +5097,13 @@ emit_marshal_custom (EmitMarshalContext *m, int argnum, MonoType *t, */ *conv_arg_type = &mono_defaults.int_class->byval_arg; - mono_mb_emit_byte (mb, CEE_BOX); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (t))); + mono_mb_emit_op (mb, CEE_BOX, mono_class_from_mono_type (t)); } - mono_mb_emit_byte (mb, CEE_CALLVIRT); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, marshal_managed_to_native)); + mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_managed_to_native); mono_mb_emit_stloc (mb, conv_arg); - mono_mb_patch_addr (mb, pos2, mb->pos - (pos2 + 4)); + mono_mb_patch_branch (mb, pos2); break; case MARSHAL_ACTION_CONV_OUT: @@ -4559,26 +5116,22 @@ emit_marshal_custom (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie)); - mono_mb_emit_byte (mb, CEE_CALL); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, get_instance)); + mono_mb_emit_op (mb, CEE_CALL, get_instance); mono_mb_emit_ldloc (mb, conv_arg); - mono_mb_emit_byte (mb, CEE_CALLVIRT); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, marshal_native_to_managed)); - mono_mb_emit_byte (mb, CEE_STIND_I); + mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed); + mono_mb_emit_byte (mb, CEE_STIND_REF); } mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie)); - mono_mb_emit_byte (mb, CEE_CALL); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, get_instance)); + mono_mb_emit_op (mb, CEE_CALL, get_instance); mono_mb_emit_ldloc (mb, conv_arg); - mono_mb_emit_byte (mb, CEE_CALLVIRT); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, cleanup_native)); + mono_mb_emit_op (mb, CEE_CALLVIRT, cleanup_native); - mono_mb_patch_addr (mb, pos2, mb->pos - (pos2 + 4)); + mono_mb_patch_branch (mb, pos2); break; case MARSHAL_ACTION_PUSH: @@ -4602,20 +5155,17 @@ emit_marshal_custom (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie)); - mono_mb_emit_byte (mb, CEE_CALL); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, get_instance)); + mono_mb_emit_op (mb, CEE_CALL, get_instance); mono_mb_emit_byte (mb, CEE_DUP); mono_mb_emit_ldloc (mb, 3); - mono_mb_emit_byte (mb, CEE_CALLVIRT); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, marshal_native_to_managed)); + mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed); mono_mb_emit_stloc (mb, 3); mono_mb_emit_ldloc (mb, loc1); - mono_mb_emit_byte (mb, CEE_CALLVIRT); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, cleanup_native)); + mono_mb_emit_op (mb, CEE_CALLVIRT, cleanup_native); - mono_mb_patch_addr (mb, pos2, mb->pos - (pos2 + 4)); + mono_mb_patch_branch (mb, pos2); break; case MARSHAL_ACTION_MANAGED_CONV_IN: @@ -4634,16 +5184,14 @@ emit_marshal_custom (EmitMarshalContext *m, int argnum, MonoType *t, pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE); mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie)); - mono_mb_emit_byte (mb, CEE_CALL); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, get_instance)); + mono_mb_emit_op (mb, CEE_CALL, get_instance); mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_byte (mb, CEE_CALLVIRT); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, marshal_native_to_managed)); + mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed); mono_mb_emit_stloc (mb, conv_arg); - mono_mb_patch_addr (mb, pos2, mb->pos - (pos2 + 4)); + mono_mb_patch_branch (mb, pos2); break; case MARSHAL_ACTION_MANAGED_CONV_RESULT: @@ -4661,20 +5209,17 @@ emit_marshal_custom (EmitMarshalContext *m, int argnum, MonoType *t, pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE); mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie)); - mono_mb_emit_byte (mb, CEE_CALL); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, get_instance)); + mono_mb_emit_op (mb, CEE_CALL, get_instance); mono_mb_emit_byte (mb, CEE_DUP); mono_mb_emit_ldloc (mb, 3); - mono_mb_emit_byte (mb, CEE_CALLVIRT); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, marshal_managed_to_native)); + mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_managed_to_native); mono_mb_emit_stloc (mb, 3); mono_mb_emit_ldloc (mb, loc1); - mono_mb_emit_byte (mb, CEE_CALLVIRT); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, cleanup_managed)); + mono_mb_emit_op (mb, CEE_CALLVIRT, cleanup_managed); - mono_mb_patch_addr (mb, pos2, mb->pos - (pos2 + 4)); + mono_mb_patch_branch (mb, pos2); break; case MARSHAL_ACTION_MANAGED_CONV_OUT: @@ -4687,14 +5232,12 @@ emit_marshal_custom (EmitMarshalContext *m, int argnum, MonoType *t, /* Call CleanUpManagedData */ mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie)); - mono_mb_emit_byte (mb, CEE_CALL); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, get_instance)); + mono_mb_emit_op (mb, CEE_CALL, get_instance); mono_mb_emit_ldloc (mb, conv_arg); - mono_mb_emit_byte (mb, CEE_CALLVIRT); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, cleanup_managed)); + mono_mb_emit_op (mb, CEE_CALLVIRT, cleanup_managed); - mono_mb_patch_addr (mb, pos2, mb->pos - (pos2 + 4)); + mono_mb_patch_branch (mb, pos2); break; default: @@ -4787,25 +5330,38 @@ emit_marshal_vtype (EmitMarshalContext *m, int argnum, MonoType *t, if (t->byref) { mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte (mb, CEE_BRFALSE); - pos = mb->pos; - mono_mb_emit_i4 (mb, 0); + pos = mono_mb_emit_branch (mb, CEE_BRFALSE); } if (!(t->byref && !(t->attrs & PARAM_ATTRIBUTE_IN) && (t->attrs & PARAM_ATTRIBUTE_OUT))) { /* set dst_ptr */ mono_mb_emit_ldloc (mb, conv_arg); - mono_mb_emit_byte (mb, CEE_STLOC_1); + mono_mb_emit_stloc (mb, 1); /* emit valuetype conversion code */ emit_struct_conv (mb, klass, FALSE); } if (t->byref) - mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4)); + mono_mb_patch_branch (mb, pos); break; case MARSHAL_ACTION_PUSH: + if (spec && spec->native == MONO_NATIVE_LPSTRUCT) { + /* FIXME: */ + g_assert (!t->byref); + + /* Have to change the signature since the vtype is passed byref */ + m->csig->params [argnum - m->csig->hasthis] = &mono_defaults.int_class->byval_arg; + + if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) || + klass->blittable || klass->enumtype) + mono_mb_emit_ldarg_addr (mb, argnum); + else + mono_mb_emit_ldloc (mb, conv_arg); + break; + } + if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) || klass->blittable || klass->enumtype) { mono_mb_emit_ldarg (mb, argnum); @@ -4814,8 +5370,7 @@ emit_marshal_vtype (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_ldloc (mb, conv_arg); if (!t->byref) { mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - mono_mb_emit_byte (mb, CEE_MONO_LDNATIVEOBJ); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass)); + mono_mb_emit_op (mb, CEE_MONO_LDNATIVEOBJ, klass); } break; @@ -4827,12 +5382,10 @@ emit_marshal_vtype (EmitMarshalContext *m, int argnum, MonoType *t, if (t->byref) { /* dst = argument */ mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_byte (mb, CEE_STLOC_1); + mono_mb_emit_stloc (mb, 1); mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_byte (mb, CEE_BRFALSE); - pos = mb->pos; - mono_mb_emit_i4 (mb, 0); + pos = mono_mb_emit_branch (mb, CEE_BRFALSE); if (!((t->attrs & PARAM_ATTRIBUTE_IN) && !(t->attrs & PARAM_ATTRIBUTE_OUT))) { /* src = tmp_locals [i] */ @@ -4847,7 +5400,7 @@ emit_marshal_vtype (EmitMarshalContext *m, int argnum, MonoType *t, emit_struct_free (mb, klass, conv_arg); if (t->byref) - mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4)); + mono_mb_patch_branch (mb, pos); break; case MARSHAL_ACTION_CONV_RESULT: @@ -4863,7 +5416,7 @@ emit_marshal_vtype (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_stloc (mb, 0); /* set dst_ptr */ mono_mb_emit_ldloc_addr (mb, 3); - mono_mb_emit_byte (mb, CEE_STLOC_1); + mono_mb_emit_stloc (mb, 1); /* emit valuetype conversion code */ emit_struct_conv (mb, klass, TRUE); @@ -4889,19 +5442,17 @@ emit_marshal_vtype (EmitMarshalContext *m, int argnum, MonoType *t, if (t->byref) { mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte (mb, CEE_BRFALSE); - pos = mb->pos; - mono_mb_emit_i4 (mb, 0); + pos = mono_mb_emit_branch (mb, CEE_BRFALSE); } mono_mb_emit_ldloc_addr (mb, conv_arg); - mono_mb_emit_byte (mb, CEE_STLOC_1); + mono_mb_emit_stloc (mb, 1); /* emit valuetype conversion code */ emit_struct_conv (mb, klass, TRUE); if (t->byref) - mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4)); + mono_mb_patch_branch (mb, pos); break; case MARSHAL_ACTION_MANAGED_CONV_OUT: @@ -4920,12 +5471,12 @@ emit_marshal_vtype (EmitMarshalContext *m, int argnum, MonoType *t, /* Set dest */ mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_byte (mb, CEE_STLOC_1); + mono_mb_emit_stloc (mb, 1); /* emit valuetype conversion code */ emit_struct_conv (mb, klass, FALSE); - mono_mb_patch_addr (mb, pos2, mb->pos - (pos2 + 4)); + mono_mb_patch_branch (mb, pos2); break; case MARSHAL_ACTION_MANAGED_CONV_RESULT: @@ -4950,7 +5501,7 @@ emit_marshal_vtype (EmitMarshalContext *m, int argnum, MonoType *t, 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_STLOC_1); + mono_mb_emit_stloc (mb, 1); mono_mb_emit_ldloc (mb, 1); mono_mb_emit_stloc (mb, m->retobj_var); @@ -5016,7 +5567,7 @@ emit_marshal_string (EmitMarshalContext *m, int argnum, MonoType *t, } else mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_LPSTR_STR)); - mono_mb_emit_byte (mb, CEE_STIND_I); + mono_mb_emit_byte (mb, CEE_STIND_REF); } else { if (mono_marshal_need_free (t, m->piinfo, spec)) { mono_mb_emit_ldloc (mb, conv_arg); @@ -5028,6 +5579,13 @@ emit_marshal_string (EmitMarshalContext *m, int argnum, MonoType *t, } 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: mono_mb_emit_stloc (mb, 0); @@ -5093,7 +5651,11 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t, MonoClass *klass = t->data.klass; int pos, pos2, loc; - if (mono_class_from_mono_type (t) == mono_defaults.object_class) { + 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")); } @@ -5104,35 +5666,112 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t, m->orig_conv_args [argnum] = 0; - if (klass->delegate) { - g_assert (!t->byref); + 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); + + *conv_arg_type = &mono_defaults.variant_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); - mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN)); + 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); - } 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); + 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); + + } + } else { + guint32 pos_failed = 0; + mono_mb_emit_ldarg (mb, argnum); + // if null just break, conv arg was already inited to 0 + pos_failed = mono_mb_emit_branch (mb, CEE_BRFALSE); + + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp)); + mono_mb_emit_byte (mb, CEE_LDIND_REF); + + /* 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); + + 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); + + // case if null + mono_mb_patch_addr (mb, pos_failed, mb->pos - (pos_failed + 4)); + } + } + 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); + + 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_ldarg (mb, argnum); - mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - mono_mb_emit_byte (mb, CEE_MONO_OBJADDR); - mono_mb_emit_icon (mb, sizeof (MonoObject)); - mono_mb_emit_byte (mb, CEE_ADD); + mono_mb_emit_ldflda (mb, sizeof (MonoObject)); mono_mb_emit_stloc (mb, conv_arg); break; } else { @@ -5156,9 +5795,7 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t, /* store the address of the source into local variable 0 */ mono_mb_emit_stloc (mb, 0); mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte (mb, CEE_BRFALSE); - pos = mb->pos; - mono_mb_emit_i4 (mb, 0); + pos = mono_mb_emit_branch (mb, CEE_BRFALSE); /* allocate space for the native struct and store the address */ mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL)); @@ -5175,24 +5812,85 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t, /* set the src_ptr */ mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - mono_mb_emit_byte (mb, CEE_MONO_OBJADDR); - mono_mb_emit_icon (mb, sizeof (MonoObject)); - mono_mb_emit_byte (mb, CEE_ADD); + mono_mb_emit_ldflda (mb, sizeof (MonoObject)); mono_mb_emit_stloc (mb, 0); /* set dst_ptr */ mono_mb_emit_ldloc (mb, conv_arg); - mono_mb_emit_byte (mb, CEE_STLOC_1); + mono_mb_emit_stloc (mb, 1); /* emit valuetype conversion code */ emit_struct_conv (mb, klass, FALSE); - mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4)); + mono_mb_patch_branch (mb, pos); } 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_branch (mb, CEE_BRFALSE); + + 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_addr (mb, pos_failed, mb->pos - (pos_failed + 4)); + } + break; + } if (klass == mono_defaults.stringbuilder_class) { gboolean need_free; MonoMarshalNative encoding; @@ -5223,9 +5921,8 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t, /* allocate a new object */ mono_mb_emit_ldarg (mb, argnum); mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - mono_mb_emit_byte (mb, CEE_MONO_NEWOBJ); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, t->data.klass)); - mono_mb_emit_byte (mb, CEE_STIND_I); + mono_mb_emit_op (mb, CEE_MONO_NEWOBJ, t->data.klass); + mono_mb_emit_byte (mb, CEE_STIND_REF); } /* dst = *argument */ @@ -5234,18 +5931,16 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t, if (t->byref) mono_mb_emit_byte (mb, CEE_LDIND_I); - mono_mb_emit_byte (mb, CEE_STLOC_1); + mono_mb_emit_stloc (mb, 1); mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_byte (mb, CEE_BRFALSE); - pos = mb->pos; - mono_mb_emit_i4 (mb, 0); + pos = mono_mb_emit_branch (mb, CEE_BRFALSE); if (t->byref || (t->attrs & PARAM_ATTRIBUTE_OUT)) { mono_mb_emit_ldloc (mb, 1); mono_mb_emit_icon (mb, sizeof (MonoObject)); mono_mb_emit_byte (mb, CEE_ADD); - mono_mb_emit_byte (mb, CEE_STLOC_1); + mono_mb_emit_stloc (mb, 1); /* src = tmp_locals [i] */ mono_mb_emit_ldloc (mb, conv_arg); @@ -5264,9 +5959,7 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t, */ mono_mb_emit_ldloc (mb, m->orig_conv_args [argnum]); mono_mb_emit_ldloc (mb, conv_arg); - mono_mb_emit_byte (mb, CEE_BEQ); - pos2 = mb->pos; - mono_mb_emit_i4 (mb, 0); + pos2 = mono_mb_emit_branch (mb, CEE_BEQ); if (!(t->attrs & PARAM_ATTRIBUTE_OUT)) { g_assert (m->orig_conv_args [argnum]); @@ -5277,14 +5970,21 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_ldloc (mb, conv_arg); mono_mb_emit_icall (mb, g_free); - mono_mb_patch_addr (mb, pos2, mb->pos - (pos2 + 4)); + mono_mb_patch_branch (mb, pos2); } } else /* Free the original structure passed to native code */ emit_struct_free (mb, klass, conv_arg); - mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4)); + mono_mb_patch_branch (mb, pos); + 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: @@ -5292,11 +5992,15 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t, g_assert (!t->byref); mono_mb_emit_stloc (mb, 0); mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - mono_mb_emit_byte (mb, CEE_MONO_CLASSCONST); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass)); + mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass); 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); @@ -5310,25 +6014,19 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_stloc (mb, 3); mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte (mb, CEE_BRFALSE); - pos = mb->pos; - mono_mb_emit_i4 (mb, 0); + pos = mono_mb_emit_branch (mb, CEE_BRFALSE); /* allocate result object */ mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - mono_mb_emit_byte (mb, CEE_MONO_NEWOBJ); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass)); + mono_mb_emit_op (mb, CEE_MONO_NEWOBJ, klass); mono_mb_emit_stloc (mb, 3); /* set dst */ mono_mb_emit_ldloc (mb, 3); - mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - mono_mb_emit_byte (mb, CEE_MONO_OBJADDR); - mono_mb_emit_icon (mb, sizeof (MonoObject)); - mono_mb_emit_byte (mb, CEE_ADD); - mono_mb_emit_byte (mb, CEE_STLOC_1); + mono_mb_emit_ldflda (mb, sizeof (MonoObject)); + mono_mb_emit_stloc (mb, 1); /* emit conversion code */ emit_struct_conv (mb, klass, TRUE); @@ -5338,7 +6036,7 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t, /* Free the pointer allocated by unmanaged code */ mono_mb_emit_ldloc (mb, loc); mono_mb_emit_icall (mb, g_free); - mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4)); + mono_mb_patch_branch (mb, pos); } break; @@ -5348,8 +6046,7 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t, if (klass->delegate) { g_assert (!t->byref); mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - mono_mb_emit_byte (mb, CEE_MONO_CLASSCONST); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass)); + mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass); mono_mb_emit_ldarg (mb, argnum); mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL)); mono_mb_emit_stloc (mb, conv_arg); @@ -5374,13 +6071,11 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t, int pos2; /* Check for NULL and raise an exception */ - mono_mb_emit_byte (mb, CEE_BRTRUE); - pos2 = mb->pos; - mono_mb_emit_i4 (mb, 0); + pos2 = mono_mb_emit_branch (mb, CEE_BRTRUE); mono_mb_emit_exception (mb, "ArgumentNullException", NULL); - mono_mb_patch_addr (mb, pos2, mb->pos - (pos2 + 4)); + mono_mb_patch_branch (mb, pos2); mono_mb_emit_ldarg (mb, argnum); mono_mb_emit_byte (mb, CEE_LDIND_I); } @@ -5391,26 +6086,20 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_stloc (mb, conv_arg); mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte (mb, CEE_BRFALSE); - pos = mb->pos; - mono_mb_emit_i4 (mb, 0); + pos = mono_mb_emit_branch (mb, CEE_BRFALSE); /* Create and set dst */ mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - mono_mb_emit_byte (mb, CEE_MONO_NEWOBJ); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass)); + mono_mb_emit_op (mb, CEE_MONO_NEWOBJ, klass); mono_mb_emit_stloc (mb, conv_arg); mono_mb_emit_ldloc (mb, conv_arg); - mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - mono_mb_emit_byte (mb, CEE_MONO_OBJADDR); - mono_mb_emit_icon (mb, sizeof (MonoObject)); - mono_mb_emit_byte (mb, CEE_ADD); - mono_mb_emit_byte (mb, CEE_STLOC_1); + mono_mb_emit_ldflda (mb, sizeof (MonoObject)); + mono_mb_emit_stloc (mb, 1); /* emit valuetype conversion code */ emit_struct_conv (mb, klass, TRUE); - mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4)); + mono_mb_patch_branch (mb, pos); break; case MARSHAL_ACTION_MANAGED_CONV_OUT: @@ -5419,24 +6108,21 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t, pos = mono_mb_emit_branch (mb, CEE_BRTRUE); mono_mb_emit_ldarg (mb, argnum); mono_mb_emit_byte (mb, CEE_LDC_I4_0); - mono_mb_emit_byte (mb, CEE_STIND_I); + mono_mb_emit_byte (mb, CEE_STIND_REF); pos2 = mono_mb_emit_branch (mb, CEE_BR); - mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4)); + mono_mb_patch_branch (mb, pos); /* Set src */ mono_mb_emit_ldloc (mb, conv_arg); - mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - mono_mb_emit_byte (mb, CEE_MONO_OBJADDR); - mono_mb_emit_icon (mb, sizeof (MonoObject)); - mono_mb_emit_byte (mb, CEE_ADD); + 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_STLOC_1); + mono_mb_emit_stloc (mb, 1); /* Update argument pointer */ mono_mb_emit_ldarg (mb, argnum); @@ -5446,7 +6132,7 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t, /* emit valuetype conversion code */ emit_struct_conv (mb, klass, FALSE); - mono_mb_patch_addr (mb, pos2, mb->pos - (pos2 + 4)); + mono_mb_patch_branch (mb, pos2); break; case MARSHAL_ACTION_MANAGED_CONV_RESULT: @@ -5470,14 +6156,11 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_stloc (mb, 3); pos2 = mono_mb_emit_branch (mb, CEE_BR); - mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4)); + mono_mb_patch_branch (mb, pos); /* Set src */ mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - mono_mb_emit_byte (mb, CEE_MONO_OBJADDR); - mono_mb_emit_icon (mb, sizeof (MonoObject)); - mono_mb_emit_byte (mb, CEE_ADD); + mono_mb_emit_ldflda (mb, sizeof (MonoObject)); mono_mb_emit_stloc (mb, 0); /* Allocate and set dest */ @@ -5485,12 +6168,12 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t, 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_byte (mb, CEE_STLOC_1); + mono_mb_emit_stloc (mb, 1); mono_mb_emit_stloc (mb, 3); emit_struct_conv (mb, klass, FALSE); - mono_mb_patch_addr (mb, pos2, mb->pos - (pos2 + 4)); + mono_mb_patch_branch (mb, pos2); break; default: @@ -5556,9 +6239,7 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_ldloc (mb, src_var); mono_mb_emit_stloc (mb, conv_arg); mono_mb_emit_ldloc (mb, src_var); - mono_mb_emit_byte (mb, CEE_BRFALSE); - label1 = mb->pos; - mono_mb_emit_i4 (mb, 0); + label1 = mono_mb_emit_branch (mb, CEE_BRFALSE); if (is_string) { if (conv == -1) { @@ -5601,9 +6282,7 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_ldloc (mb, index_var); mono_mb_emit_ldloc (mb, src_var); mono_mb_emit_byte (mb, CEE_LDLEN); - mono_mb_emit_byte (mb, CEE_BGE); - label3 = mb->pos; - mono_mb_emit_i4 (mb, 0); + label3 = mono_mb_emit_branch (mb, CEE_BGE); /* Emit marshalling code */ @@ -5618,13 +6297,12 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t, /* set the src_ptr */ mono_mb_emit_ldloc (mb, src_var); mono_mb_emit_ldloc (mb, index_var); - mono_mb_emit_byte (mb, CEE_LDELEMA); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, eklass)); + mono_mb_emit_op (mb, CEE_LDELEMA, eklass); mono_mb_emit_stloc (mb, 0); /* set dst_ptr */ mono_mb_emit_ldloc (mb, dest_ptr); - mono_mb_emit_byte (mb, CEE_STLOC_1); + mono_mb_emit_stloc (mb, 1); /* emit valuetype conversion code */ emit_struct_conv (mb, eklass, FALSE); @@ -5636,7 +6314,7 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_byte (mb, CEE_BR); mono_mb_emit_i4 (mb, label2 - (mb->pos + 4)); - mono_mb_patch_addr (mb, label3, mb->pos - (label3 + 4)); + mono_mb_patch_branch (mb, label3); if (eklass == mono_defaults.string_class) { /* Null terminate */ @@ -5645,7 +6323,7 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_byte (mb, CEE_STIND_REF); } - mono_mb_patch_addr (mb, label1, mb->pos - (label1 + 4)); + mono_mb_patch_branch (mb, label1); } break; @@ -5674,9 +6352,7 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_ldarg (mb, argnum); if (t->byref) mono_mb_emit_byte (mb, CEE_LDIND_I); - mono_mb_emit_byte (mb, CEE_BRFALSE); - label1 = mb->pos; - mono_mb_emit_i4 (mb, 0); + label1 = mono_mb_emit_branch (mb, CEE_BRFALSE); mono_mb_emit_ldloc (mb, conv_arg); mono_mb_emit_stloc (mb, src_ptr); @@ -5691,9 +6367,7 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t, if (t->byref) mono_mb_emit_byte (mb, CEE_LDIND_REF); mono_mb_emit_byte (mb, CEE_LDLEN); - mono_mb_emit_byte (mb, CEE_BGE); - label3 = mb->pos; - mono_mb_emit_i4 (mb, 0); + label3 = mono_mb_emit_branch (mb, CEE_BGE); /* Emit marshalling code */ @@ -5744,9 +6418,8 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t, if (t->byref) mono_mb_emit_byte (mb, CEE_LDIND_I); mono_mb_emit_ldloc (mb, index_var); - mono_mb_emit_byte (mb, CEE_LDELEMA); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, eklass)); - mono_mb_emit_byte (mb, CEE_STLOC_1); + mono_mb_emit_op (mb, CEE_LDELEMA, eklass); + mono_mb_emit_stloc (mb, 1); /* emit valuetype conversion code */ emit_struct_conv (mb, eklass, TRUE); @@ -5767,11 +6440,18 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_byte (mb, CEE_BR); mono_mb_emit_i4 (mb, label2 - (mb->pos + 4)); - mono_mb_patch_addr (mb, label1, mb->pos - (label1 + 4)); - mono_mb_patch_addr (mb, label3, mb->pos - (label3 + 4)); + mono_mb_patch_branch (mb, label1); + mono_mb_patch_branch (mb, label3); } 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: /* fixme: we need conversions here */ mono_mb_emit_stloc (mb, 3); @@ -5870,9 +6550,7 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t, /* Check null */ mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_byte (mb, CEE_BRFALSE); - label1 = mb->pos; - mono_mb_emit_i4 (mb, 0); + label1 = mono_mb_emit_branch (mb, CEE_BRFALSE); mono_mb_emit_ldarg (mb, argnum); mono_mb_emit_stloc (mb, src_ptr); @@ -5895,8 +6573,7 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t, } } - mono_mb_emit_byte (mb, CEE_NEWARR); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, eklass)); + mono_mb_emit_op (mb, CEE_NEWARR, eklass); mono_mb_emit_stloc (mb, conv_arg); if (eklass->blittable) { @@ -5922,9 +6599,7 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_ldloc (mb, index_var); mono_mb_emit_ldloc (mb, conv_arg); mono_mb_emit_byte (mb, CEE_LDLEN); - mono_mb_emit_byte (mb, CEE_BGE); - label3 = mb->pos; - mono_mb_emit_i4 (mb, 0); + label3 = mono_mb_emit_branch (mb, CEE_BGE); /* Emit marshalling code */ if (is_string) { @@ -5951,8 +6626,8 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_byte (mb, CEE_BR); mono_mb_emit_i4 (mb, label2 - (mb->pos + 4)); - mono_mb_patch_addr (mb, label1, mb->pos - (label1 + 4)); - mono_mb_patch_addr (mb, label3, mb->pos - (label3 + 4)); + mono_mb_patch_branch (mb, label1); + mono_mb_patch_branch (mb, label3); break; } @@ -6007,9 +6682,7 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t, /* Check null */ mono_mb_emit_ldloc (mb, conv_arg); - mono_mb_emit_byte (mb, CEE_BRFALSE); - label1 = mb->pos; - mono_mb_emit_i4 (mb, 0); + label1 = mono_mb_emit_branch (mb, CEE_BRFALSE); mono_mb_emit_ldarg (mb, argnum); mono_mb_emit_stloc (mb, dest_ptr); @@ -6040,9 +6713,7 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_ldloc (mb, index_var); mono_mb_emit_ldloc (mb, conv_arg); mono_mb_emit_byte (mb, CEE_LDLEN); - mono_mb_emit_byte (mb, CEE_BGE); - label3 = mb->pos; - mono_mb_emit_i4 (mb, 0); + label3 = mono_mb_emit_branch (mb, CEE_BGE); /* Emit marshalling code */ if (is_string) { @@ -6072,8 +6743,8 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_byte (mb, CEE_BR); mono_mb_emit_i4 (mb, label2 - (mb->pos + 4)); - mono_mb_patch_addr (mb, label1, mb->pos - (label1 + 4)); - mono_mb_patch_addr (mb, label3, mb->pos - (label3 + 4)); + mono_mb_patch_branch (mb, label1); + mono_mb_patch_branch (mb, label3); break; } @@ -6168,8 +6839,8 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_byte (mb, CEE_BR); mono_mb_emit_i4 (mb, label2 - (mb->pos + 4)); - mono_mb_patch_addr (mb, label3, mb->pos - (label3 + 4)); - mono_mb_patch_addr (mb, label1, mb->pos - (label1 + 4)); + mono_mb_patch_branch (mb, label3); + mono_mb_patch_branch (mb, label1); break; } default: @@ -6220,6 +6891,23 @@ emit_marshal_boolean (EmitMarshalContext *m, int argnum, MonoType *t, break; } + case MARSHAL_ACTION_CONV_OUT: + if (!t->byref) + break; + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldloc (mb, conv_arg); + if (spec != NULL && spec->native == MONO_NATIVE_VARIANTBOOL) + mono_mb_emit_byte (mb, CEE_NEG); + mono_mb_emit_byte (mb, CEE_STIND_I1); + break; + + case MARSHAL_ACTION_PUSH: + if (t->byref) + mono_mb_emit_ldloc_addr (mb, conv_arg); + else + mono_mb_emit_ldarg (mb, argnum); + break; + case MARSHAL_ACTION_CONV_RESULT: /* maybe we need to make sure that it fits within 8 bits */ mono_mb_emit_stloc (mb, 3); @@ -6237,6 +6925,8 @@ emit_marshal_ptr (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: if (MONO_TYPE_ISSTRUCT (t->data.type)) { @@ -6244,6 +6934,67 @@ emit_marshal_ptr (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_exception_marshal_directive (m->mb, msg); } break; + + case MARSHAL_ACTION_PUSH: + mono_mb_emit_ldarg (mb, argnum); + break; + + case MARSHAL_ACTION_CONV_RESULT: + /* no conversions necessary */ + mono_mb_emit_stloc (mb, 3); + break; + + default: + break; + } + + return conv_arg; +} + +static int +emit_marshal_char (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_PUSH: + /* fixme: dont know how to marshal that. We cant simply + * convert it to a one byte UTF8 character, because an + * unicode character may need more that one byte in UTF8 */ + mono_mb_emit_ldarg (mb, argnum); + break; + + case MARSHAL_ACTION_CONV_RESULT: + /* fixme: we need conversions here */ + mono_mb_emit_stloc (mb, 3); + break; + + default: + break; + } + + return conv_arg; +} + +static int +emit_marshal_scalar (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_PUSH: + mono_mb_emit_ldarg (mb, argnum); + break; + + case MARSHAL_ACTION_CONV_RESULT: + /* no conversions necessary */ + mono_mb_emit_stloc (mb, 3); + break; + default: break; } @@ -6280,6 +7031,22 @@ emit_marshal (EmitMarshalContext *m, int argnum, MonoType *t, return emit_marshal_boolean (m, argnum, t, spec, conv_arg, conv_arg_type, action); case MONO_TYPE_PTR: return emit_marshal_ptr (m, argnum, t, spec, conv_arg, conv_arg_type, action); + case MONO_TYPE_CHAR: + return emit_marshal_char (m, argnum, t, spec, conv_arg, conv_arg_type, action); + case MONO_TYPE_I1: + case MONO_TYPE_U1: + case MONO_TYPE_I2: + case MONO_TYPE_U2: + case MONO_TYPE_I4: + case MONO_TYPE_U4: + case MONO_TYPE_I: + case MONO_TYPE_U: + case MONO_TYPE_R4: + case MONO_TYPE_R8: + case MONO_TYPE_I8: + case MONO_TYPE_U8: + case MONO_TYPE_FNPTR: + return emit_marshal_scalar (m, argnum, t, spec, conv_arg, conv_arg_type, action); } return conv_arg; @@ -6302,13 +7069,15 @@ mono_marshal_emit_native_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *si MonoClass *klass; int i, argnum, *tmp_locals; int type; + static MonoMethodSignature *get_last_error_sig = NULL; m.mb = mb; m.piinfo = piinfo; /* we copy the signature, so that we can set pinvoke to 0 */ - csig = mono_metadata_signature_dup (sig); + csig = signature_dup (mb->method->klass->image, sig); csig->pinvoke = 1; + m.csig = csig; /* we allocate local for use with emit_struct_conv() */ /* allocate local 0 (pointer) src_ptr */ @@ -6350,73 +7119,37 @@ mono_marshal_emit_native_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *si if (sig->hasthis) mono_mb_emit_byte (mb, CEE_LDARG_0); - 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) || (spec->native == MONO_NATIVE_ASANY))) - emit_marshal (&m, i + sig->hasthis, t, spec, tmp_locals [i], NULL, MARSHAL_ACTION_PUSH); - else { - argnum = i + sig->hasthis; - switch (t->type) { - case MONO_TYPE_BOOLEAN: - if (t->byref) { - g_assert (tmp_locals [i]); - mono_mb_emit_ldloc_addr (mb, tmp_locals [i]); - } else - mono_mb_emit_ldarg (mb, argnum); - break; - case MONO_TYPE_I1: - case MONO_TYPE_U1: - case MONO_TYPE_I2: - case MONO_TYPE_U2: - case MONO_TYPE_I4: - case MONO_TYPE_U4: - case MONO_TYPE_I: - case MONO_TYPE_U: - case MONO_TYPE_PTR: - case MONO_TYPE_R4: - case MONO_TYPE_R8: - case MONO_TYPE_I8: - case MONO_TYPE_U8: - case MONO_TYPE_FNPTR: - mono_mb_emit_ldarg (mb, argnum); - break; - case MONO_TYPE_VALUETYPE: - emit_marshal (&m, i + sig->hasthis, t, spec, tmp_locals [i], NULL, MARSHAL_ACTION_PUSH); - break; - case MONO_TYPE_STRING: - case MONO_TYPE_CLASS: - case MONO_TYPE_OBJECT: - case MONO_TYPE_ARRAY: - case MONO_TYPE_SZARRAY: - g_assert (tmp_locals [i]); - if (t->byref) - mono_mb_emit_ldloc_addr (mb, tmp_locals [i]); - else - mono_mb_emit_ldloc (mb, tmp_locals [i]); - break; - case MONO_TYPE_CHAR: - /* fixme: dont know how to marshal that. We cant simply - * convert it to a one byte UTF8 character, because an - * unicode character may need more that one byte in UTF8 */ - mono_mb_emit_ldarg (mb, argnum); - break; - case MONO_TYPE_TYPEDBYREF: - default: - g_warning ("type 0x%02x unknown", t->type); - g_assert_not_reached (); - } - } + 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); } /* call the native method */ - mono_mb_emit_native_call (mb, csig, func); + if (MONO_CLASS_IS_IMPORT (mb->method->klass)) { + mono_mb_emit_cominterop_call (mb, csig, &piinfo->method); + } + else { + mono_mb_emit_native_call (mb, csig, func); + } /* Set LastError if needed */ if (piinfo->piflags & PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR) { + if (!get_last_error_sig) { + get_last_error_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 0); + get_last_error_sig->ret = &mono_defaults.int_class->byval_arg; + get_last_error_sig->pinvoke = 1; + } + +#ifdef PLATFORM_WIN32 + /* + * Have to call GetLastError () early and without a wrapper, since various runtime components could + * clobber its value. + */ + mono_mb_emit_native_call (mb, get_last_error_sig, GetLastError); + mono_mb_emit_icall (mb, mono_marshal_set_last_error_windows); +#else mono_mb_emit_icall (mb, mono_marshal_set_last_error); +#endif } /* convert the result */ @@ -6432,6 +7165,14 @@ mono_marshal_emit_native_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *si switch (type) { case MONO_TYPE_VOID: break; + case MONO_TYPE_VALUETYPE: + klass = sig->ret->data.klass; + if (klass->enumtype) { + type = sig->ret->data.klass->enum_basetype->type; + goto handle_enum; + } + emit_marshal (&m, 0, sig->ret, spec, 0, NULL, MARSHAL_ACTION_CONV_RESULT); + break; case MONO_TYPE_I1: case MONO_TYPE_U1: case MONO_TYPE_I2: @@ -6440,34 +7181,20 @@ mono_marshal_emit_native_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *si case MONO_TYPE_U4: case MONO_TYPE_I: case MONO_TYPE_U: - case MONO_TYPE_PTR: case MONO_TYPE_R4: case MONO_TYPE_R8: case MONO_TYPE_I8: case MONO_TYPE_U8: case MONO_TYPE_FNPTR: - /* no conversions necessary */ - mono_mb_emit_stloc (mb, 3); - break; - case MONO_TYPE_VALUETYPE: - klass = sig->ret->data.klass; - if (klass->enumtype) { - type = sig->ret->data.klass->enum_basetype->type; - goto handle_enum; - } - emit_marshal (&m, 0, sig->ret, spec, 0, NULL, MARSHAL_ACTION_CONV_RESULT); - break; case MONO_TYPE_STRING: case MONO_TYPE_CLASS: case MONO_TYPE_OBJECT: case MONO_TYPE_BOOLEAN: case MONO_TYPE_ARRAY: case MONO_TYPE_SZARRAY: - emit_marshal (&m, 0, sig->ret, spec, 0, NULL, MARSHAL_ACTION_CONV_RESULT); - break; case MONO_TYPE_CHAR: - /* fixme: we need conversions here */ - mono_mb_emit_stloc (mb, 3); + case MONO_TYPE_PTR: + emit_marshal (&m, 0, sig->ret, spec, 0, NULL, MARSHAL_ACTION_CONV_RESULT); break; case MONO_TYPE_TYPEDBYREF: default: @@ -6503,16 +7230,9 @@ mono_marshal_emit_native_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *si case MONO_TYPE_CLASS: case MONO_TYPE_OBJECT: case MONO_TYPE_SZARRAY: + case MONO_TYPE_BOOLEAN: emit_marshal (&m, argnum, t, spec, tmp_locals [i], NULL, MARSHAL_ACTION_CONV_OUT); break; - case MONO_TYPE_BOOLEAN: - if (!t->byref) - continue; - mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_ldloc (mb, tmp_locals [i]); - if (mspecs [i + 1] != NULL && mspecs [i + 1]->native == MONO_NATIVE_VARIANTBOOL) - mono_mb_emit_byte (mb, CEE_NEG); - mono_mb_emit_byte (mb, CEE_STIND_I1); } } @@ -6539,6 +7259,7 @@ mono_marshal_get_native_wrapper (MonoMethod *method) MonoMethod *res; GHashTable *cache; gboolean pinvoke = FALSE; + gpointer iter; int i; const char *exc_class = "MissingMethodException"; const char *exc_arg = NULL; @@ -6550,6 +7271,9 @@ mono_marshal_get_native_wrapper (MonoMethod *method) if ((res = mono_marshal_find_in_cache (cache, method))) return res; + if (MONO_CLASS_IS_IMPORT (method->klass)) + return cominterop_get_native_wrapper (method); + sig = mono_method_signature (method); if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && @@ -6563,16 +7287,57 @@ mono_marshal_get_native_wrapper (MonoMethod *method) piinfo->addr = mono_lookup_internal_call (method); } + /* hack - redirect certain string constructors to CreateString */ + if (piinfo->addr == ves_icall_System_String_ctor_RedirectToCreateString) { + g_assert (!pinvoke); + g_assert (method->string_ctor); + g_assert (sig->hasthis); + + /* CreateString returns a value */ + csig = signature_dup (method->klass->image, sig); + csig->ret = &mono_defaults.string_class->byval_arg; + csig->pinvoke = 0; + + iter = NULL; + while ((res = mono_class_get_methods (mono_defaults.string_class, &iter))) { + if (!strcmp ("CreateString", res->name) && + mono_metadata_signature_equal (csig, mono_method_signature (res))) { + + g_assert (!(res->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)); + g_assert (!(res->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)); + + /* create a wrapper to preserve .ctor in stack trace */ + mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_MANAGED); + + mono_mb_emit_byte (mb, CEE_LDARG_0); + for (i = 1; i <= csig->param_count; i++) + mono_mb_emit_ldarg (mb, i); + mono_mb_emit_managed_call (mb, res, NULL); + mono_mb_emit_byte (mb, CEE_RET); + + /* use native_wrapper_cache because internal calls are looked up there */ + res = mono_mb_create_and_cache (cache, method, + mb, csig, csig->param_count + 1); + + mono_mb_free (mb); + + return res; + } + } + + /* exception will be thrown */ + piinfo->addr = NULL; + g_warning ("cannot find CreateString for .ctor"); + } + mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE); mb->method->save_lmf = 1; if (!piinfo->addr) { mono_mb_emit_exception (mb, exc_class, exc_arg); - mono_loader_lock (); - csig = signature_dup_mp (method->klass->image->mempool, sig); + csig = signature_dup (method->klass->image, sig); csig->pinvoke = 0; - mono_loader_unlock (); res = mono_mb_create_and_cache (cache, method, mb, csig, csig->param_count + 16); mono_mb_free (mb); @@ -6584,7 +7349,7 @@ mono_marshal_get_native_wrapper (MonoMethod *method) /* hack - string constructors returns a value */ if (method->string_ctor) { - csig = mono_metadata_signature_dup (sig); + csig = signature_dup (method->klass->image, sig); csig->ret = &mono_defaults.string_class->byval_arg; } else csig = sig; @@ -6600,10 +7365,8 @@ mono_marshal_get_native_wrapper (MonoMethod *method) emit_thread_interrupt_checkpoint (mb); mono_mb_emit_byte (mb, CEE_RET); - mono_loader_lock (); - csig = signature_dup_mp (method->klass->image->mempool, csig); + csig = signature_dup (method->klass->image, csig); csig->pinvoke = 0; - mono_loader_unlock (); res = mono_mb_create_and_cache (cache, method, mb, csig, csig->param_count + 16); mono_mb_free (mb); @@ -6617,10 +7380,8 @@ mono_marshal_get_native_wrapper (MonoMethod *method) mono_marshal_emit_native_wrapper (mb, sig, piinfo, mspecs, piinfo->addr); - mono_loader_lock (); - csig = signature_dup_mp (method->klass->image->mempool, sig); + csig = signature_dup (method->klass->image, sig); csig->pinvoke = 0; - mono_loader_unlock (); res = mono_mb_create_and_cache (cache, method, mb, csig, csig->param_count + 16); mono_mb_free (mb); @@ -6664,10 +7425,8 @@ mono_marshal_get_native_func_wrapper (MonoMethodSignature *sig, mono_marshal_emit_native_wrapper (mb, sig, piinfo, mspecs, func); - mono_loader_lock (); - csig = signature_dup_mp (mb->method->klass->image->mempool, sig); + csig = signature_dup (mb->method->klass->image, sig); csig->pinvoke = 0; - mono_loader_unlock (); res = mono_mb_create_and_cache (cache, func, mb, csig, csig->param_count + 16); mono_mb_free (mb); @@ -6731,7 +7490,7 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, mono_mb_emit_stloc (mb, 2); /* we copy the signature, so that we can modify it */ - csig = mono_metadata_signature_dup (sig); + csig = signature_dup (method->klass->image, sig); csig->hasthis = 0; csig->pinvoke = 1; @@ -6739,6 +7498,7 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, m.sig = sig; m.piinfo = NULL; m.retobj_var = 0; + m.csig = csig; #ifdef PLATFORM_WIN32 /* @@ -6916,8 +7676,7 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, if (m.retobj_var) { mono_mb_emit_ldloc (mb, m.retobj_var); mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - mono_mb_emit_byte (mb, CEE_MONO_RETOBJ); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, m.retobj_class)); + mono_mb_emit_op (mb, CEE_MONO_RETOBJ, m.retobj_class); } else { if (!MONO_TYPE_IS_VOID(sig->ret)) @@ -6929,8 +7688,8 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, res = mono_mb_create_and_cache (cache, method, mb, csig, sig->param_count + 16); else { + mb->dynamic = 1; res = mono_mb_create_method (mb, csig, sig->param_count + 16); - res->dynamic = 1; } mono_mb_free (mb); @@ -6995,8 +7754,7 @@ mono_marshal_get_isinst (MonoClass *klass) /* check if the object is a proxy that needs special cast */ mono_mb_emit_ldarg (mb, 0); mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - mono_mb_emit_byte (mb, CEE_MONO_CISINST); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass)); + mono_mb_emit_op (mb, CEE_MONO_CISINST, klass); /* The result of MONO_ISINST can be: 0) the type check succeeded @@ -7078,8 +7836,7 @@ mono_marshal_get_castclass (MonoClass *klass) /* check if the object is a proxy that needs special cast */ mono_mb_emit_ldarg (mb, 0); mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - mono_mb_emit_byte (mb, CEE_MONO_CCASTCLASS); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass)); + mono_mb_emit_op (mb, CEE_MONO_CCASTCLASS, klass); /* The result of MONO_ISINST can be: 0) the cast is valid @@ -7157,9 +7914,7 @@ mono_marshal_get_proxy_cancast (MonoClass *klass) can_cast_to = mono_method_desc_search_in_class (desc, mono_defaults.iremotingtypeinfo_class); g_assert (can_cast_to); mono_method_desc_free (desc); - mono_mb_emit_byte (mb, CEE_CALLVIRT); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, can_cast_to)); - + mono_mb_emit_op (mb, CEE_CALLVIRT, can_cast_to); pos_failed = mono_mb_emit_branch (mb, CEE_BRFALSE); @@ -7250,7 +8005,7 @@ mono_marshal_get_struct_to_ptr (MonoClass *klass) /* initialize dst_ptr */ mono_mb_emit_byte (mb, CEE_LDARG_1); - mono_mb_emit_byte (mb, CEE_STLOC_1); + mono_mb_emit_stloc (mb, 1); emit_struct_conv (mb, klass, FALSE); } @@ -7312,8 +8067,7 @@ mono_marshal_get_ptr_to_struct (MonoClass *klass) /* initialize dst_ptr */ mono_mb_emit_byte (mb, CEE_LDARG_1); - mono_mb_emit_byte (mb, CEE_UNBOX); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass)); + mono_mb_emit_op (mb, CEE_UNBOX, klass); mono_mb_emit_stloc (mb, 1); emit_struct_conv (mb, klass, TRUE); @@ -7353,10 +8107,8 @@ mono_marshal_get_synchronized_wrapper (MonoMethod *method) if ((res = mono_marshal_find_in_cache (cache, method))) return res; - mono_loader_lock (); - sig = signature_dup_mp (method->klass->image->mempool, mono_method_signature (method)); + sig = signature_dup (method->klass->image, mono_method_signature (method)); sig->pinvoke = 0; - mono_loader_unlock (); mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_SYNCHRONIZED); @@ -7413,16 +8165,13 @@ mono_marshal_get_synchronized_wrapper (MonoMethod *method) /* this is needed to avoid recursion */ mono_mb_emit_byte (mb, CEE_PREFIX1); - mono_mb_emit_byte (mb, CEE_LDFTN); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, method)); + mono_mb_emit_op (mb, CEE_LDFTN, method); mono_mb_emit_calli (mb, mono_method_signature (method)); if (!MONO_TYPE_IS_VOID (sig->ret)) mono_mb_emit_stloc (mb, ret_local); - mono_mb_emit_byte (mb, CEE_LEAVE); - pos = mb->pos; - mono_mb_emit_i4 (mb, 0); + pos = mono_mb_emit_branch (mb, CEE_LEAVE); clause->try_len = mb->pos - clause->try_offset; clause->handler_offset = mb->pos; @@ -7435,7 +8184,7 @@ mono_marshal_get_synchronized_wrapper (MonoMethod *method) clause->handler_len = mb->pos - clause->handler_offset; - mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4)); + mono_mb_patch_branch (mb, pos); if (!MONO_TYPE_IS_VOID (sig->ret)) mono_mb_emit_ldloc (mb, ret_local); mono_mb_emit_byte (mb, CEE_RET); @@ -7548,8 +8297,7 @@ mono_marshal_get_stelemref () /* ldelema (implicit bound check) */ mono_mb_emit_ldarg (mb, 0); mono_mb_emit_ldarg (mb, 1); - mono_mb_emit_byte (mb, CEE_LDELEMA); - mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_defaults.object_class)); + mono_mb_emit_op (mb, CEE_LDELEMA, mono_defaults.object_class); mono_mb_emit_stloc (mb, array_slot_addr); /* if (!value) goto do_store */ @@ -7606,7 +8354,7 @@ mono_marshal_get_stelemref () copy_pos = mb->pos; /* do_store */ - mono_mb_patch_addr (mb, b1, mb->pos - (b1 + 4)); + mono_mb_patch_branch (mb, b1); mono_mb_emit_ldloc (mb, array_slot_addr); mono_mb_emit_ldarg (mb, 2); mono_mb_emit_byte (mb, CEE_STIND_REF); @@ -7614,8 +8362,8 @@ mono_marshal_get_stelemref () mono_mb_emit_byte (mb, CEE_RET); /* the hard way */ - mono_mb_patch_addr (mb, b2, mb->pos - (b2 + 4)); - mono_mb_patch_addr (mb, b3, mb->pos - (b3 + 4)); + mono_mb_patch_branch (mb, b2); + mono_mb_patch_branch (mb, b3); mono_mb_emit_ldarg (mb, 2); mono_mb_emit_ldloc (mb, aklass); @@ -7631,6 +8379,46 @@ mono_marshal_get_stelemref () return ret; } +MonoMethod* +mono_marshal_get_write_barrier (void) +{ + static MonoMethod* ret = NULL; + MonoMethodSignature *sig; + MonoMethodBuilder *mb; + int max_stack = 2; + + if (ret) + return ret; + + mb = mono_mb_new (mono_defaults.object_class, "writebarrier", MONO_WRAPPER_WRITE_BARRIER); + + sig = mono_metadata_signature_alloc (mono_defaults.corlib, 2); + + /* void writebarrier (MonoObject** addr, MonoObject* obj) */ + sig->ret = &mono_defaults.void_class->byval_arg; + sig->params [0] = &mono_defaults.object_class->this_arg; + sig->params [1] = &mono_defaults.object_class->byval_arg; + + /* just the store right now: add an hook for the GC to use, maybe something + * that can be used for stelemref as well + * We need a write barrier variant to be used with struct copies as well, though + * there are also other approaches possible, like writing a wrapper specific to + * the struct or to the reference pattern in the struct... + * Depending on the GC, we may want variants that take the object we store to + * when it is available. + */ + mono_mb_emit_ldarg (mb, 0); + mono_mb_emit_ldarg (mb, 1); + mono_mb_emit_icall (mb, mono_gc_wbarrier_generic_store); + /*mono_mb_emit_byte (mb, CEE_STIND_REF);*/ + + mono_mb_emit_byte (mb, CEE_RET); + + ret = mono_mb_create_method (mb, sig, max_stack); + mono_mb_free (mb); + return ret; +} + void* mono_marshal_alloc (gulong size) { @@ -7699,6 +8487,14 @@ mono_marshal_set_last_error (void) #endif } +static void +mono_marshal_set_last_error_windows (int error) +{ +#ifdef WIN32 + TlsSetValue (last_error_tls_id, GINT_TO_POINTER (error)); +#endif +} + void ves_icall_System_Runtime_InteropServices_Marshal_copy_to_unmanaged (MonoArray *src, gint32 start_index, gpointer dest, gint32 length) @@ -7938,6 +8734,23 @@ ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr) return mono_string_to_bstr(ptr); } +#ifdef __i386__ +#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 (STDCALL *AddRef)(gpointer pUnk); + int (STDCALL *Release)(gpointer pUnk); +} MonoIUnknown; + void ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr) { @@ -7946,6 +8759,38 @@ ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr) mono_free_bstr (ptr); } +int +ves_icall_System_Runtime_InteropServices_Marshal_AddRef (gpointer pUnk) +{ + MONO_ARCH_SAVE_REGS; + + return (*(MonoIUnknown**)pUnk)->AddRef(pUnk); +} + +int +ves_icall_System_Runtime_InteropServices_Marshal_QueryInterface (gpointer pUnk, gpointer riid, gpointer* ppv) +{ + MONO_ARCH_SAVE_REGS; + + return (*(MonoIUnknown**)pUnk)->QueryInterface(pUnk, riid, ppv); +} + +int +ves_icall_System_Runtime_InteropServices_Marshal_Release (gpointer pUnk) +{ + MONO_ARCH_SAVE_REGS; + + return (*(MonoIUnknown**)pUnk)->Release(pUnk); +} + +guint32 +ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethod *m) +{ + MONO_ARCH_SAVE_REGS; + + return cominterop_get_com_slot_for_method (m->method); +} + guint32 ves_icall_System_Runtime_InteropServices_Marshal_GetLastWin32Error (void) { @@ -8003,23 +8848,45 @@ ves_icall_System_Runtime_InteropServices_Marshal_StructureToPtr (MonoObject *obj mono_runtime_invoke (method, NULL, pa, NULL); } -void -ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure (gpointer src, MonoObject *dst) +static void +ptr_to_structure (gpointer src, MonoObject *dst) { MonoMethod *method; gpointer pa [2]; + method = mono_marshal_get_ptr_to_struct (dst->vtable->klass); + + pa [0] = &src; + pa [1] = dst; + + mono_runtime_invoke (method, NULL, pa, NULL); +} + +void +ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure (gpointer src, MonoObject *dst) +{ + MonoType *t; + MONO_ARCH_SAVE_REGS; MONO_CHECK_ARG_NULL (src); MONO_CHECK_ARG_NULL (dst); + + t = mono_type_get_underlying_type (mono_class_get_type (dst->vtable->klass)); - method = mono_marshal_get_ptr_to_struct (dst->vtable->klass); + if (t->type == MONO_TYPE_VALUETYPE) { + MonoException *exc; + gchar *tmp; - pa [0] = &src; - pa [1] = dst; + tmp = g_strdup_printf ("Destination is a boxed value type."); + exc = mono_get_exception_argument ("dst", tmp); + g_free (tmp); - mono_runtime_invoke (method, NULL, pa, NULL); + mono_raise_exception (exc); + return; + } + + ptr_to_structure (src, dst); } MonoObject * @@ -8035,7 +8902,7 @@ ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure_type (gpointer s res = mono_object_new (domain, mono_class_from_mono_type (type->type)); - ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure (src, res); + ptr_to_structure (src, res); return res; } @@ -8241,6 +9108,89 @@ ves_icall_System_Runtime_InteropServices_Marshal_GetDelegateForFunctionPointerIn return mono_ftnptr_to_delegate (mono_type_get_class (type->type), ftn); } +/* Only used for COM RCWs */ +MonoObject * +ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type) +{ + MonoClass *klass; + MonoDomain *domain; + MonoObject *obj; + + MONO_ARCH_SAVE_REGS; + + domain = mono_object_domain (type); + klass = mono_class_from_mono_type (type->type); + + /* call mono_object_new_alloc_specific instead of mono_object_new + * because we want to actually create object. mono_object_new checks + * to see if type is import and creates transparent proxy. this method + * is called by the corresponding real proxy to create the real RCW. + * Constructor does not need to be called. Will be called later. + */ + obj = mono_object_new_alloc_specific (mono_class_vtable (domain, klass)); + return obj; +} + +static gboolean +cominterop_finalizer (gpointer key, gpointer value, gpointer user_data) +{ + ves_icall_System_Runtime_InteropServices_Marshal_Release (value); + return TRUE; +} + +void +ves_icall_System_ComObject_Finalizer(MonoComObject* obj) +{ + g_assert(obj); + if (obj->itf_hash) + g_hash_table_foreach_remove (obj->itf_hash, cominterop_finalizer, NULL); + obj->itf_hash = NULL; +} + +#define MONO_IUNKNOWN_INTERFACE_SLOT 0 + +gpointer +ves_icall_System_ComObject_FindInterface (MonoComObject* obj, MonoReflectionType* type) +{ + MonoClass* klass; + g_assert(obj); + g_assert(obj->itf_hash); + + klass = mono_class_from_mono_type (type->type); + + return g_hash_table_lookup (obj->itf_hash, GUINT_TO_POINTER ((guint)klass->interface_id)); +} + +void +ves_icall_System_ComObject_CacheInterface (MonoComObject* obj, MonoReflectionType* type, gpointer pItf) +{ + MonoClass* klass; + g_assert(obj); + g_assert(obj->itf_hash); + + klass = mono_class_from_mono_type (type->type); + + g_hash_table_insert (obj->itf_hash, GUINT_TO_POINTER ((guint)klass->interface_id), pItf); +} + +gpointer +ves_icall_System_ComObject_GetIUnknown (MonoComObject* obj) +{ + g_assert(obj); + if (!obj->itf_hash) + return NULL; + return g_hash_table_lookup (obj->itf_hash, MONO_IUNKNOWN_INTERFACE_SLOT); +} + +void +ves_icall_System_ComObject_SetIUnknown (MonoComObject* obj, 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); +} + MonoMarshalType * mono_marshal_load_type_info (MonoClass* klass) {