2002-08-14 Dietmar Maurer <dietmar@ximian.com>
authorDietmar Maurer <dietmar@mono-cvs.ximian.com>
Wed, 14 Aug 2002 16:08:11 +0000 (16:08 -0000)
committerDietmar Maurer <dietmar@mono-cvs.ximian.com>
Wed, 14 Aug 2002 16:08:11 +0000 (16:08 -0000)
* marshal.c (mono_marshal_get_runtime_invoke): unbox value types

* class.c (class_compute_field_layout): set blittable to false for Strings

* appdomain.c (mono_domain_transfer_object): added support for ISerializable

svn path=/trunk/mono/; revision=6637

mono/metadata/ChangeLog
mono/metadata/appdomain.c
mono/metadata/class.c
mono/metadata/domain.c
mono/metadata/exception.c
mono/metadata/exception.h
mono/metadata/loader.h
mono/metadata/marshal.c
mono/metadata/object.h
mono/tests/Makefile.am
mono/tests/appdomain2.cs [new file with mode: 0644]

index 24d4792d1650b439c6cdeec71628856d854c7665..3c63f9d6aa005a57f161a7ec7907ab2e1719b872 100644 (file)
@@ -1,3 +1,10 @@
+2002-08-14  Dietmar Maurer  <dietmar@ximian.com>
+
+       * marshal.c (mono_marshal_get_runtime_invoke): unbox value types
+
+       * class.c (class_compute_field_layout): set blittable to false for Strings
+
+       * appdomain.c (mono_domain_transfer_object): added support for ISerializable
 
 Wed Aug 14 17:26:27 CEST 2002 Paolo Molaro <lupus@ximian.com>
 
index 2d3b4a4be32a9527a6352726700e390b0762cd1d..274a09bf9ee9a81822b6cab7b40bb9b11b0566ec 100644 (file)
 #include <mono/metadata/exception.h>
 #include <mono/metadata/threads.h>
 #include <mono/metadata/socket-io.h>
+#include <mono/metadata/tabledefs.h>
 
 HANDLE mono_delegate_semaphore = NULL;
 CRITICAL_SECTION mono_delegate_section;
 int mono_runtime_shutdown = 0;
 
+static MonoObject *
+mono_domain_transfer_object (MonoDomain *src, MonoDomain *dst, MonoObject *obj);
+
 /*
  * mono_runtime_init:
  * @domain: domain returned by mono_init ()
@@ -84,6 +88,84 @@ ves_icall_System_AppDomainSetup_InitAppDomainSetup (MonoAppDomainSetup *setup)
        /* FIXME: implement me */
 }
 
+/*
+ * invokes a method in a specific domain.
+ */
+static MonoObject*
+mono_runtime_invoke_in_domain (MonoDomain *domain, MonoMethod *method, void *obj, 
+                              void **params, MonoObject **exc)
+{
+       MonoDomain *cur = mono_domain_get ();
+       MonoObject **real_exc, *default_exc;
+       MonoObject *res;
+
+       if (domain == cur)
+               return mono_runtime_invoke (method, obj, params, exc);
+
+       if (!exc)
+               real_exc = &default_exc;
+       else
+               real_exc = exc;
+
+       *real_exc = NULL;
+       mono_domain_set (domain);
+       res = mono_runtime_invoke (method, obj, params, real_exc);
+       mono_domain_set (cur);
+
+       if (*real_exc && !exc)
+               mono_raise_exception ((MonoException *)*real_exc);
+
+       return res;
+}
+
+static MonoObject *
+mono_domain_transfer_array (MonoDomain *src, MonoDomain *dst, MonoArray *ao)
+{
+       MonoObject *res = NULL;
+       MonoClass *klass;
+       int esize, ecount, i;
+       guint32 *sizes;
+               
+       klass = ao->obj.vtable->klass;
+
+       esize = mono_array_element_size (klass);
+       if (ao->bounds == NULL) {
+               ecount = mono_array_length (ao);
+               res = (MonoObject *)mono_array_new_full (dst, klass, &ecount, NULL);
+       } else {
+               sizes = alloca (klass->rank * sizeof(guint32) * 2);
+               ecount = 1;
+               for (i = 0; i < klass->rank; ++i) {
+                       sizes [i] = ao->bounds [i].length;
+                       ecount *= ao->bounds [i].length;
+                       sizes [i + klass->rank] = ao->bounds [i].lower_bound;
+               }
+               res = (MonoObject *)mono_array_new_full (dst, klass, sizes, sizes + klass->rank);
+       }
+       if (klass->element_class->valuetype) {
+               if (klass->element_class->blittable) {
+                       memcpy (((MonoArray *)res)->vector, ao->vector, esize * ecount);
+               } else {
+                       for (i = 0; i < ecount; i++) {
+                               MonoObject *s, *d;
+                               gpointer *src_ea = (gpointer *)mono_array_addr_with_size (ao, esize, i);
+                               gpointer *dst_ea = (gpointer *)mono_array_addr_with_size ((MonoArray *)res, esize, i);
+                               s = mono_value_box (src, klass->element_class, src_ea);
+                               d = mono_domain_transfer_object (src, dst, s);
+                               memcpy (dst_ea, (char *)d + sizeof(MonoObject), esize);
+                       }
+               }
+       } else {
+               g_assert (esize == sizeof (gpointer));
+               for (i = 0; i < ecount; i++) {
+                       gpointer *src_ea = (gpointer *)mono_array_addr_with_size (ao, esize, i);
+                       gpointer *dst_ea = (gpointer *)mono_array_addr_with_size ((MonoArray *)res, esize, i);
+                       *dst_ea = mono_domain_transfer_object (src, dst, *src_ea);
+               }
+       }
+       return res;
+}
+
 /**
  * mono_domain_transfer_object:
  * @src: the source domain
@@ -96,60 +178,214 @@ ves_icall_System_AppDomainSetup_InitAppDomainSetup (MonoAppDomainSetup *setup)
 static MonoObject *
 mono_domain_transfer_object (MonoDomain *src, MonoDomain *dst, MonoObject *obj)
 {
+       MonoClass *sic = mono_defaults.serializationinfo_class;
        MonoClass *klass;
-       MonoObject *res;        
+       MonoObject *res = NULL; 
+       int i;
 
        if (!obj)
                return NULL;
 
        g_assert (obj->vtable->domain == src);
 
-       /* fixme: transfer an object from one domain into another */
-
        klass = obj->vtable->klass;
 
-       if (MONO_CLASS_IS_ARRAY (klass)) {
-               MonoArray *ao = (MonoArray *)obj;
-               int esize, ecount, i;
-               guint32 *sizes;
+       /* some special cases */
+       if (klass == mono_defaults.string_class) {
+               MonoString *str = (MonoString *)obj;
+               return (MonoObject *)mono_string_new_utf16 (dst, 
+                       (const guint16 *)mono_string_chars (str), str->length); 
+       } 
+
+       if (klass == mono_defaults.monotype_class)
+               return (MonoObject *) mono_type_get_object (dst, ((MonoReflectionType *)obj)->type);    
+
+       if (MONO_CLASS_IS_ARRAY (klass))
+               return mono_domain_transfer_array (src, dst, (MonoArray *)obj); 
+
+       if (mono_object_isinst (obj, mono_defaults.iserializeable_class)) {
+               static MonoMethod *serinfo_ctor1 = NULL, *serinfo_ctor2 = NULL, *get_entries = NULL;
+               MonoMethod *get_object_data, *ser_ctor;
+               MonoObject *src_serinfo, *dst_serinfo;
+               void *pa [2];
+               MonoStreamingContext ctx;
+               MonoArray *entries, *trans_entries;
+               int len;
+
+               /* get a pointer to the GetObjectData method */ 
+               get_object_data = klass->vtable [klass->interface_offsets [mono_defaults.iserializeable_class->interface_id]];
+               g_assert (get_object_data);
+
+               src_serinfo = mono_object_new (src, sic);
+
+               if (!serinfo_ctor1) {
+                       for (i = 0; i < sic->method.count; ++i) {
+                               if (!strcmp (".ctor", sic->methods [i]->name) &&
+                                   sic->methods [i]->signature->param_count == 1) {
+                                       serinfo_ctor1 = sic->methods [i];
+                                       break;
+                               }
+                       }
+                       g_assert (serinfo_ctor1);
+               }
                
-               esize = mono_array_element_size (klass);
-               if (ao->bounds == NULL) {
-                       ecount = mono_array_length (ao);
-                       res = (MonoObject *)mono_array_new_full (dst, klass, &ecount, NULL);
+               if (!serinfo_ctor2) {
+                       for (i = 0; i < sic->method.count; ++i) {
+                               if (!strcmp (".ctor", sic->methods [i]->name) &&
+                                   sic->methods [i]->signature->param_count == 2 &&
+                                   sic->methods [i]->signature->params [1]->type == MONO_TYPE_SZARRAY) {
+                                       serinfo_ctor2 = sic->methods [i];
+                                       break;
+                               }
+                       }
+                       g_assert (serinfo_ctor2);
                }
-               else {
-                       sizes = alloca (klass->rank * sizeof(guint32) * 2);
-                       ecount = 1;
-                       for (i = 0; i < klass->rank; ++i) {
-                               sizes [i] = ao->bounds [i].length;
-                               ecount *= ao->bounds [i].length;
-                               sizes [i + klass->rank] = ao->bounds [i].lower_bound;
+               
+               if (!get_entries) {
+                       for (i = 0; i < sic->method.count; ++i) {
+                               if (!strcmp ("get_entries", sic->methods [i]->name) &&
+                                   sic->methods [i]->signature->param_count == 0) {
+                                       get_entries = sic->methods [i];
+                                       break;
+                               }
                        }
-                       res = (MonoObject *)mono_array_new_full (dst, klass, sizes, sizes + klass->rank);
+                       g_assert (get_entries);
                }
-               if (klass->element_class->valuetype) {
-                       memcpy (((MonoArray *)res)->vector, ao->vector, esize * ecount);
-               } else {
-                       g_assert (esize == sizeof (gpointer));
-                       for (i = 0; i < ecount; i++) {
-                               gpointer *src_ea = (gpointer *)mono_array_addr_with_size (ao, esize, i);
-                               gpointer *dst_ea = (gpointer *)mono_array_addr_with_size ((MonoArray *)res, esize, i);
 
-                               *dst_ea = mono_domain_transfer_object (src, dst, *src_ea);
+               pa [0] = mono_type_get_object (src, &klass->byval_arg);
+               mono_runtime_invoke_in_domain (src, serinfo_ctor1, src_serinfo, pa, NULL);
+
+               ctx.additional = NULL;
+               ctx.state = 128; /* CrossAppDomain */
+               pa [0] = src_serinfo;
+               pa [1] = &ctx;
+               mono_runtime_invoke_in_domain (src, get_object_data, obj, pa, NULL);
+
+               entries = (MonoArray *)mono_runtime_invoke_in_domain (src, get_entries, src_serinfo, NULL, NULL);
+
+               g_assert (src_serinfo->vtable->domain == src);
+               g_assert (entries->obj.vtable->domain == src);
+
+               /* transfer all SerializationEntry objects */
+               len = mono_array_length ((MonoArray*)entries);
+               trans_entries = mono_array_new (dst, entries->obj.vtable->klass->element_class, len);
+
+               for (i = 0; i < len; i++) {
+                       MonoSerializationEntry *s, *d;
+                       s = (MonoSerializationEntry *)mono_array_addr_with_size (entries, 
+                               sizeof (MonoSerializationEntry), i);
+                       d = (MonoSerializationEntry *)mono_array_addr_with_size (trans_entries, 
+                                sizeof (MonoSerializationEntry), i);
+                       d->name = (MonoString *)mono_domain_transfer_object (src, dst, (MonoObject *)s->name);
+                       d->value = mono_domain_transfer_object (src, dst, s->value);
+                       d->type = (MonoReflectionType *)mono_domain_transfer_object (src, dst, (MonoObject *)s->type);
+               }
+
+               dst_serinfo = mono_object_new (dst, sic);
+
+               pa [0] = mono_type_get_object (dst, &klass->byval_arg);
+               pa [1] = trans_entries;
+               mono_runtime_invoke_in_domain (dst, serinfo_ctor2, dst_serinfo, pa, NULL);
+
+               ser_ctor = NULL;
+               for (i = 0; i < klass->method.count; i++) {
+                       MonoMethod *t = klass->methods [i];
+                       if (!strcmp (t->name, ".ctor") && t->signature->param_count == 2 &&
+                           mono_metadata_type_equal (t->signature->params [0], 
+                                                     &mono_defaults.serializationinfo_class->byval_arg) &&
+                           mono_metadata_type_equal (t->signature->params [1], 
+                                                     &mono_defaults.streamingcontext_class->byval_arg))
+                               ser_ctor = t;
+               }
+               g_assert (ser_ctor);
+
+               res = mono_object_new (dst, klass);
+
+               ctx.additional = NULL;
+               ctx.state = 128; /* CrossAppDomain */
+               pa [0] = dst_serinfo;
+               pa [1] = &ctx;
+               mono_runtime_invoke_in_domain (dst, ser_ctor, res, pa, NULL);
+
+               return res;
+       }
+
+       if (!(klass->flags & TYPE_ATTRIBUTE_SERIALIZABLE)) {
+               MonoException *exc = NULL;
+               char *msg;
+
+               msg = g_strdup_printf ("klass \"%s.%s\" is not serializable", 
+                                      klass->name_space, klass->name);
+               exc = mono_get_exception_serialization (msg);
+               g_free (msg);
+
+               mono_raise_exception (exc);
+       }
+
+       res = mono_object_new (dst, klass);
+
+       for (i = 0; i < klass->field.count; i++) {
+               MonoClassField *field = &klass->fields [i];
+               MonoType *type = field->type;
+               int size, align;
+               char *src_ptr, *dst_ptr;
+               int simple_type;
+
+               if (type->attrs & FIELD_ATTRIBUTE_STATIC ||
+                   type->attrs & FIELD_ATTRIBUTE_NOT_SERIALIZED)
+                       continue;
+
+               size = mono_type_size (type, &align);
+
+               dst_ptr = (char*)res + field->offset;
+               src_ptr = (char *)obj + field->offset;
+
+               g_assert (!type->byref);
+               
+               simple_type = type->type;
+       handle_enum:
+               switch (simple_type) {
+               case MONO_TYPE_BOOLEAN:
+               case MONO_TYPE_CHAR: 
+               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_I8: 
+               case MONO_TYPE_U8:
+               case MONO_TYPE_R4:
+               case MONO_TYPE_R8:
+                       memcpy (dst_ptr, src_ptr, size);
+                       break;
+               case MONO_TYPE_OBJECT:
+               case MONO_TYPE_ARRAY:
+               case MONO_TYPE_SZARRAY:
+               case MONO_TYPE_CLASS:
+               case MONO_TYPE_STRING: {
+                       *(MonoObject **)dst_ptr = mono_domain_transfer_object (src, dst, *(MonoObject **)src_ptr);
+                       break;
+               }
+               case MONO_TYPE_VALUETYPE: {
+                       MonoObject *boxed_src, *tmp;
+
+                       if (type->data.klass->enumtype) {
+                               simple_type = type->data.klass->enum_basetype->type;
+                               goto handle_enum;
                        }
+                       boxed_src = mono_value_box (src, type->data.klass, src_ptr);
+                       tmp = mono_domain_transfer_object (src, dst, boxed_src);
+                       memcpy (dst_ptr, (char *)tmp + sizeof (MonoObject), size);
+                       break;
+               }
+               default:
+                       g_assert_not_reached ();
                }
-       } else if (klass->valuetype) {
-               res = mono_value_box (dst, klass, (char *)obj + sizeof (MonoObject));
-       } else if (klass == mono_defaults.string_class) {
-               MonoString *str = (MonoString *)obj;
-               res = (MonoObject *)mono_string_new_utf16 (dst, 
-                       (const guint16 *)mono_string_chars (str), str->length); 
-       } else {
-               /* FIXME: we need generic marshalling code here */
-               g_assert_not_reached ();
        }
-       
+
        return res;
 }
 
@@ -210,7 +446,7 @@ ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObj
        o = mono_domain_transfer_object (cur, add, data);
 
        mono_domain_lock (add);
-       g_hash_table_insert (add->env, name, o);
+       mono_g_hash_table_insert (add->env, name, o);
 
        mono_domain_unlock (add);
 }
index b2129af584c42544fb81810fec770fe08a8a1e31..e39982c4d49abf66be8d0dd77317f14565b3e9c1 100644 (file)
@@ -261,6 +261,9 @@ class_compute_field_layout (MonoClass *class)
                }
        }
 
+       if (class == mono_defaults.string_class)
+               blittable = FALSE;
+
        class->blittable = blittable;
 
        if (class->enumtype && !class->enum_basetype) {
index 11c80d9fca019352e93b592b63eff38758092004..fcdcae7feb4b5ca50993b629597a359b9a3cff55 100644 (file)
@@ -397,6 +397,18 @@ mono_init (const char *filename)
                mono_defaults.corlib, "System.Runtime.InteropServices", "Marshal");
        g_assert (mono_defaults.marshal_class != 0);
 
+       mono_defaults.iserializeable_class = mono_class_from_name (
+               mono_defaults.corlib, "System.Runtime.Serialization", "ISerializable");
+       g_assert (mono_defaults.iserializeable_class != 0);
+
+       mono_defaults.serializationinfo_class = mono_class_from_name (
+               mono_defaults.corlib, "System.Runtime.Serialization", "SerializationInfo");
+       g_assert (mono_defaults.serializationinfo_class != 0);
+
+       mono_defaults.streamingcontext_class = mono_class_from_name (
+               mono_defaults.corlib, "System.Runtime.Serialization", "StreamingContext");
+       g_assert (mono_defaults.streamingcontext_class != 0);
+
        domain->friendly_name = g_path_get_basename (filename);
 
        return domain;
index 11826c8e95608644c1365613310c0016b36f6181..3996437c0a964b856867b175f1ab050814b4586d 100644 (file)
@@ -150,6 +150,23 @@ mono_get_exception_execution_engine (const guchar *msg)
        return ex;
 }
 
+MonoException *
+mono_get_exception_serialization (const guchar *msg)
+{
+       MonoException *ex;
+       MonoDomain *domain;
+
+       ex = mono_exception_from_name (mono_defaults.corlib, "System.Runtime.Serialization",
+                                      "SerializationException");
+
+       domain = ((MonoObject *)ex)->vtable->domain;
+
+       if (msg)
+               ex->message = mono_string_new (domain, msg);
+
+       return ex;
+}
+
 MonoException *
 mono_get_exception_invalid_cast ()
 {
index d70b611774853541aca1f16aa0c8976fecc3fadb..76c3d48dfb81979378e2a337f116d744db19f083 100644 (file)
@@ -40,6 +40,9 @@ mono_get_exception_thread_abort        (void);
 MonoException *
 mono_get_exception_thread_state        (const guchar *msg);
 
+MonoException *
+mono_get_exception_serialization       (const guchar *msg);
+
 MonoException *
 mono_get_exception_invalid_cast        (void);
 
index 3d9c055bd47cfcf6c0b55ff1b820e7265e39b186..6135661f300a9b6ce54e49187f9f5f367f75cc05 100644 (file)
@@ -95,6 +95,9 @@ typedef struct {
        MonoClass *stack_frame_class;
        MonoClass *stack_trace_class;
        MonoClass *marshal_class;
+       MonoClass *iserializeable_class;
+       MonoClass *serializationinfo_class;
+       MonoClass *streamingcontext_class;
 } MonoDefaults;
 
 extern MonoDefaults mono_defaults;
index f323e637b754ff6b579f77bd8b46aa9646a661bb..2c70d879435f60cec8b81cb9888bdf2040030d75 100644 (file)
@@ -1493,6 +1493,10 @@ mono_marshal_get_runtime_invoke (MonoMethod *method)
                        mono_mb_emit_i4 (mb, mono_mb_add_data (mb, string_dummy));
                } else {
                        mono_mb_emit_ldarg (mb, 0);
+                       if (method->klass->valuetype) {
+                               mono_mb_emit_byte (mb, CEE_UNBOX);
+                               mono_mb_emit_i4 (mb, mono_mb_add_data (mb, method->klass));
+                       } 
                }
        }
 
@@ -1584,6 +1588,7 @@ handle_enum:
                g_assert_not_reached ();
        }
 
+
        switch (sig->ret->type) {
        case MONO_TYPE_VOID:
                if (!method->string_ctor)
index 9fcd9c6bb5e2111c96c11be1d8fd955e32c932a0..0bcc8300b3970ccd2df361ed403b35ca2029a8c4 100644 (file)
@@ -176,6 +176,17 @@ typedef struct {
        MonoObject *abort_state;
 } MonoThread;
 
+typedef struct {
+       MonoString *name;
+       MonoReflectionType *type;
+       MonoObject *value;
+} MonoSerializationEntry;
+
+typedef struct {
+       guint32 state;
+       MonoObject *additional;
+} MonoStreamingContext;
+
 typedef MonoObject* (*MonoInvokeFunc)        (MonoMethod *method, void *obj, void **params, MonoObject **exc);
 typedef gpointer    (*MonoCompileFunc)       (MonoMethod *method);
 
index 41cd952f89f2d99dd327b979d5a8ff4d59c8a1f0..0afd1578be049c586a9a0022d7ec7aef2a5ab2f6 100644 (file)
@@ -102,6 +102,7 @@ TEST_CS_SRC=                        \
        time.cs                 \
        appdomain.cs            \
        appdomain1.cs           \
+       appdomain2.cs           \
        appdomain-client.cs     \
        pointer.cs              \
        vararg.cs               \
diff --git a/mono/tests/appdomain2.cs b/mono/tests/appdomain2.cs
new file mode 100644 (file)
index 0000000..b1f436a
--- /dev/null
@@ -0,0 +1,81 @@
+using System;
+using System.Security.Policy;
+using System.Threading;
+using System.Runtime.Serialization;
+
+class Container {
+
+       [Serializable]
+       public struct c2 : ISerializable {
+               public int a;
+               public string s1;
+
+               private c2 (SerializationInfo info, StreamingContext context) {
+                       a = info.GetInt32("a");
+                       s1 = info.GetString("s1");
+                       Console.WriteLine ("SetObjectData called: " + info.AssemblyName + "," +
+                                          info.FullTypeName + " " + s1 + ", " + a);
+               }
+
+               public void GetObjectData (SerializationInfo info, StreamingContext context) {
+                       Console.WriteLine ("GetObjectData called: " + info.AssemblyName + "," +
+                                          info.FullTypeName + " " + s1 + ", " + a);
+                       info.AddValue ("a", a);
+                       if (s1 != null)
+                               info.AddValue ("s1", s1);
+                       else
+                               info.AddValue ("s1", "(null)");
+               }
+       }
+       
+       [Serializable]
+       public class c1 {
+               public c1 () {
+                       e1.a = 3;
+                       e1.s1 = "SS";
+               }
+               public int a = 1;
+               public int b = 2;
+               public string s1 = "TEST1";
+               [NonSerialized] public string s2 = "TEST2";
+               public c2 [] sa = new c2 [2];
+               public c2 e1;
+       }
+       
+       static int Main ()
+       {
+               AppDomainSetup setup = new AppDomainSetup ();
+               setup.ApplicationBase = ".";
+
+               Console.WriteLine (AppDomain.CurrentDomain.FriendlyName);
+                       
+               AppDomain newDomain = AppDomain.CreateDomain ("NewDomain", new Evidence (), setup);
+
+               c1 a1 = new c1 ();
+               
+               newDomain.SetData ("TEST", a1);
+               c1 r1 = (c1)newDomain.GetData ("TEST");
+               if (r1.a != 1 || r1.b !=2)
+                       return 1;
+               
+               if (r1.s1 != "TEST1")
+                       return 2;
+               
+               if (r1.s2 != null)
+                       return 3;
+
+               if (r1.e1.a != 3)
+                       return 4;
+
+               if (r1.e1.s1 != "SS")
+                       return 4;
+               
+               if (r1.sa [0].s1 != "(null)")
+                       return 5;
+               
+               if (r1.sa [0].a != 0)
+                       return 6;
+
+               return 0;
+       }
+}