Add a new 'MONO_DEBUGGER_EVENT_TRAMPOLINE' notification for the debugger which also...
[mono.git] / mono / metadata / marshal.c
index 5893f09c7e200d47bd5a4300dc1ae244ecaa7b63..ea59d1fdb71593b47c00747bea29f32ce50677ad 100644 (file)
@@ -101,6 +101,9 @@ mono_string_to_lpstr (MonoString *string_obj);
 static MonoStringBuilder *
 mono_string_utf8_to_builder2 (char *text);
 
+static MonoStringBuilder *
+mono_string_utf16_to_builder2 (gunichar2 *text);
+
 static void
 mono_byvalarray_to_array (MonoArray *arr, gpointer native_arr, MonoClass *eltype, guint32 elnum);
 
@@ -116,9 +119,6 @@ mono_delegate_begin_invoke (MonoDelegate *delegate, gpointer *params);
 static MonoObject *
 mono_delegate_end_invoke (MonoDelegate *delegate, gpointer *params);
 
-static MonoObject *
-mono_marshal_xdomain_copy_value (MonoObject *val);
-
 static void
 mono_marshal_xdomain_copy_out_value (MonoObject *src, MonoObject *dst);
 
@@ -227,6 +227,7 @@ mono_marshal_init (void)
                register_icall (mono_string_utf8_to_builder, "mono_string_utf8_to_builder", "void ptr ptr", FALSE);
                register_icall (mono_string_utf8_to_builder2, "mono_string_utf8_to_builder2", "object ptr", FALSE);
                register_icall (mono_string_utf16_to_builder, "mono_string_utf16_to_builder", "void ptr ptr", FALSE);
+               register_icall (mono_string_utf16_to_builder2, "mono_string_utf16_to_builder2", "object ptr", FALSE);
                register_icall (mono_marshal_free_array, "mono_marshal_free_array", "void ptr int32", FALSE);
                register_icall (mono_string_to_byvalstr, "mono_string_to_byvalstr", "void ptr ptr int32", FALSE);
                register_icall (mono_string_to_byvalwstr, "mono_string_to_byvalwstr", "void ptr ptr int32", FALSE);
@@ -758,6 +759,45 @@ mono_string_utf16_to_builder (MonoStringBuilder *sb, gunichar2 *text)
        sb->length = len;
 }
 
+MonoStringBuilder *
+mono_string_utf16_to_builder2 (gunichar2 *text)
+{
+       int len;
+       MonoStringBuilder *sb;
+       static MonoClass *string_builder_class;
+       static MonoMethod *sb_ctor;
+       void *args [1];
+       MonoObject *exc;
+
+       if (!text)
+               return NULL;
+
+       if (!string_builder_class) {
+               MonoMethodDesc *desc;
+
+               string_builder_class = mono_class_from_name (mono_defaults.corlib, "System.Text", "StringBuilder");
+               g_assert (string_builder_class);
+               desc = mono_method_desc_new (":.ctor(int)", FALSE);
+               sb_ctor = mono_method_desc_search_in_class (desc, string_builder_class);
+               g_assert (sb_ctor);
+               mono_method_desc_free (desc);
+       }
+
+       for (len = 0; text [len] != 0; ++len)
+               ;
+
+       sb = (MonoStringBuilder*)mono_object_new (mono_domain_get (), string_builder_class);
+       g_assert (sb);
+       args [0] = &len;
+       mono_runtime_invoke (sb_ctor, sb, args, &exc);
+       g_assert (!exc);
+
+       sb->length = len;
+       memcpy (mono_string_chars (sb->str), text, len * 2);
+
+       return sb;
+}
+
 /**
  * mono_string_builder_to_utf8:
  * @sb: the string builder
@@ -1737,6 +1777,15 @@ emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object)
                return;
        }
 
+       if (klass != mono_defaults.safehandle_class) {
+               if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT) {
+                       char *msg = g_strdup_printf ("Type %s which is passed to unmanaged code must have a StructLayout attribute.",
+                                                                                mono_type_full_name (&klass->byval_arg));
+                       mono_mb_emit_exception_marshal_directive (mb, msg);
+                       return;
+               }
+       }
+
        for (i = 0; i < info->num_fields; i++) {
                MonoMarshalNative ntype;
                MonoMarshalConv conv;
@@ -1771,11 +1820,6 @@ emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object)
                                                 "reference field at the same offset as another field.",
                                                 mono_type_full_name (&klass->byval_arg));
                        }
-                       
-                       if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT)
-                               g_error ("Type %s which is passed to unmanaged code must have a StructLayout attribute",
-                                        mono_type_full_name (&klass->byval_arg));
-                       
                }
                
                switch (conv) {
@@ -2771,7 +2815,7 @@ mono_get_xdomain_marshal_type (MonoType *t)
 /* mono_marshal_xdomain_copy_value
  * Makes a copy of "val" suitable for the current domain.
  */
-static MonoObject *
+MonoObject *
 mono_marshal_xdomain_copy_value (MonoObject *val)
 {
        MonoDomain *domain;
@@ -5534,17 +5578,38 @@ emit_marshal_vtype (EmitMarshalContext *m, int argnum, MonoType *t,
                                        MarshalAction action)
 {
        MonoMethodBuilder *mb = m->mb;
-       MonoClass *klass;
+       MonoClass *klass, *date_time_class;
        int pos = 0, pos2;
 
        klass = mono_class_from_mono_type (t);
 
+       date_time_class = mono_class_from_name_cached (mono_defaults.corlib, "System", "DateTime");
+
        switch (action) {
        case MARSHAL_ACTION_CONV_IN:
                if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
                        klass->blittable || klass->enumtype)
                        break;
 
+               if (klass == date_time_class) {
+                       /* Convert it to an OLE DATE type */
+                       static MonoMethod *to_oadate;
+
+                       if (!to_oadate)
+                               to_oadate = mono_class_get_method_from_name (date_time_class, "ToOADate", 0);
+                       g_assert (to_oadate);
+
+                       if (t->byref)
+                               g_assert_not_reached ();
+
+                       conv_arg = mono_mb_add_local (mb, &mono_defaults.double_class->byval_arg);
+
+                       mono_mb_emit_ldarg_addr (mb, argnum);
+                       mono_mb_emit_managed_call (mb, to_oadate, NULL);
+                       mono_mb_emit_stloc (mb, conv_arg);
+                       break;
+               }
+
                conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
                        
                /* store the address of the source into local variable 0 */
@@ -5596,6 +5661,11 @@ emit_marshal_vtype (EmitMarshalContext *m, int argnum, MonoType *t,
                        break;
                }
 
+               if (klass == date_time_class) {
+                       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);
@@ -5643,6 +5713,7 @@ emit_marshal_vtype (EmitMarshalContext *m, int argnum, MonoType *t,
                        mono_mb_emit_stloc (mb, 3);
                        break;
                }
+
                /* load pointer to returned value type */
                mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
                mono_mb_emit_byte (mb, CEE_MONO_VTADDR);
@@ -6148,7 +6219,14 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
                        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);
+                       if (t->byref) {
+                               if (!(t->attrs & PARAM_ATTRIBUTE_OUT)) {
+                                       char *msg = g_strdup_printf ("Byref marshalling of stringbuilders is not implemented.");
+                                       mono_mb_emit_exception_marshal_directive (mb, msg);
+                               }
+                               break;
+                       }
+
                        mono_mb_emit_ldarg (mb, argnum);
 
                        if (conv != -1)
@@ -6236,13 +6314,34 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
                        encoding = mono_marshal_get_string_encoding (m->piinfo, spec);
                        conv = mono_marshal_get_ptr_to_stringbuilder_conv (m->piinfo, spec, &need_free);
 
-                       g_assert (!t->byref);
                        g_assert (encoding != -1);
 
-                       mono_mb_emit_ldarg (mb, argnum);
-                       mono_mb_emit_ldloc (mb, conv_arg);
+                       if (t->byref) {
+                               g_assert ((t->attrs & PARAM_ATTRIBUTE_OUT));
 
-                       mono_mb_emit_icall (mb, conv_to_icall (conv));
+                               need_free = TRUE;
+
+                               mono_mb_emit_ldarg (mb, argnum);
+                               mono_mb_emit_ldloc (mb, conv_arg);
+
+                               switch (encoding) {
+                               case MONO_NATIVE_LPWSTR:
+                                       mono_mb_emit_icall (mb, mono_string_utf16_to_builder2);
+                                       break;
+                               case MONO_NATIVE_LPSTR:
+                                       mono_mb_emit_icall (mb, mono_string_utf8_to_builder2);
+                                       break;
+                               default:
+                                       g_assert_not_reached ();
+                               }
+
+                               mono_mb_emit_byte (mb, CEE_STIND_REF);
+                       } else {
+                               mono_mb_emit_ldarg (mb, argnum);
+                               mono_mb_emit_ldloc (mb, conv_arg);
+
+                               mono_mb_emit_icall (mb, conv_to_icall (conv));
+                       }
 
                        if (need_free) {
                                mono_mb_emit_ldloc (mb, conv_arg);