2007-03-12 Zoltan Varga <vargaz@gmail.com>
authorZoltan Varga <vargaz@gmail.com>
Mon, 12 Mar 2007 12:38:14 +0000 (12:38 -0000)
committerZoltan Varga <vargaz@gmail.com>
Mon, 12 Mar 2007 12:38:14 +0000 (12:38 -0000)
* reflection.c (mono_reflection_create_dynamic_method): Add support for
circular references among dynamic methods. Fixes #81091.

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

mono/metadata/ChangeLog
mono/metadata/reflection.c

index c68061094bcf9dc4f42e052d4ab1b00a8ec58936..a04632392c766a026b31970a08b6aa235679e497 100644 (file)
@@ -1,5 +1,8 @@
 2007-03-12  Zoltan Varga  <vargaz@gmail.com>
 
+       * reflection.c (mono_reflection_create_dynamic_method): Add support for 
+       circular references among dynamic methods. Fixes #81091.
+
        * object-internals.h (MonoReflectionDynamicMethod): Add 'referenced_by' field.
 
 2007-03-09  Martin Baulig  <martin@ximian.com>
index 27b00905d6ffbdc524e83bbdf5c2ca7f0315ded8..8e71602f69bacb451674123050c11363967a3760 100644 (file)
@@ -9523,6 +9523,7 @@ mono_reflection_create_dynamic_method (MonoReflectionDynamicMethod *mb)
 {
        ReflectionMethodBuilder rmb;
        MonoMethodSignature *sig;
+       GSList *l;
        int i;
 
        sig = dynamic_method_to_signature (mb);
@@ -9540,13 +9541,35 @@ mono_reflection_create_dynamic_method (MonoReflectionDynamicMethod *mb)
        rmb.refs = g_new0 (gpointer, mb->nrefs + 1);
        for (i = 0; i < mb->nrefs; i += 2) {
                MonoClass *handle_class;
-               gpointer ref = resolve_object (mb->module->image, 
-                                              mono_array_get (mb->refs, MonoObject*, i), &handle_class);
-               if (!ref) {
-                       g_free (rmb.refs);
-                       mono_raise_exception (mono_get_exception_type_load (NULL, NULL));
-                       return;
+               gpointer ref;
+               MonoObject *obj = mono_array_get (mb->refs, MonoObject*, i);
+
+               if (strcmp (obj->vtable->klass->name, "DynamicMethod") == 0) {
+                       MonoReflectionDynamicMethod *method = (MonoReflectionDynamicMethod*)obj;
+                       /*
+                        * The referenced DynamicMethod should already be created by the managed
+                        * code, except in the case of circular references. In that case, we store
+                        * NULL in the refs array, and fix it up later when the referenced 
+                        * DynamicMethod is created.
+                        */
+                       if (method->mhandle) {
+                               ref = method->mhandle;
+                       } else {
+                               ref = NULL;
+
+                               /* FIXME: GC object stored in unmanaged memory */
+                               method->referenced_by = g_slist_append (method->referenced_by, mb);
+                       }
+                       handle_class = mono_defaults.methodhandle_class;
+               } else {
+                       ref = resolve_object (mb->module->image, obj, &handle_class);
+                       if (!ref) {
+                               g_free (rmb.refs);
+                               mono_raise_exception (mono_get_exception_type_load (NULL, NULL));
+                               return;
+                       }
                }
+
                rmb.refs [i] = ref; /* FIXME: GC object stored in unmanaged memory (change also resolve_object() signature) */
                rmb.refs [i + 1] = handle_class;
        }               
@@ -9554,6 +9577,22 @@ mono_reflection_create_dynamic_method (MonoReflectionDynamicMethod *mb)
        /* FIXME: class */
        mb->mhandle = reflection_methodbuilder_to_mono_method (mono_defaults.object_class, &rmb, sig);
 
+       /* Fix up refs entries pointing at us */
+       for (l = mb->referenced_by; l; l = l->next) {
+               MonoReflectionDynamicMethod *method = (MonoReflectionDynamicMethod*)l->data;
+               MonoMethodWrapper *wrapper = (MonoMethodWrapper*)method->mhandle;
+               gpointer *data;
+               
+               g_assert (method->mhandle);
+
+               data = (gpointer*)wrapper->method_data;
+               for (i = 0; i < GPOINTER_TO_UINT (data [0]); i += 2) {
+                       if ((data [i + 1] == NULL) && (data [i + 1 + 1] == mono_defaults.methodhandle_class))
+                               data [i + 1] = mb->mhandle;
+               }
+       }
+       g_slist_free (mb->referenced_by);
+
        g_free (rmb.refs);
 
        /* ilgen is no longer needed */