[sre] Add MonoDynamicImageTokCollision arg to mono_dynamic_image_register_token
authorAleksey Kliger <aleksey@xamarin.com>
Wed, 26 Jul 2017 15:39:36 +0000 (11:39 -0400)
committerAleksey Kliger <aleksey@xamarin.com>
Thu, 27 Jul 2017 15:41:28 +0000 (11:41 -0400)
The new argument controls what should happen when the given token is already
present.

In some situations it's expected that we either see the same object, or we
unconditionally want to replace it (for example if we previously registered a
TypeBuilder or a MethodBuilder, after the type or method is created, we will
re-register the RuntimeType or MonoMethod in its place).  In other cases (for
example when a module references a MonoMethod from a different assembly), we
may still call `mono_image_create_token()` multiple times but we expect to see
the same MonoMethod object.

mono/metadata/dynamic-image-internals.h
mono/metadata/dynamic-image.c
mono/metadata/sre-encode.c
mono/metadata/sre.c

index 344d2d6e978efe3467ab9a88b8da6f4e79875812..bb1084e981ee9b3690626d5fe3bc44b2b25ce03b 100644 (file)
@@ -24,11 +24,17 @@ typedef struct {
 } MonoILT;
 
 
+typedef enum {
+       MONO_DYN_IMAGE_TOK_NEW, /* assert if same token is registered already */
+       MONO_DYN_IMAGE_TOK_SAME_OK, /* allow collision only with the same object */
+       MONO_DYN_IMAGE_TOK_REPLACE, /* keep the new object, always */
+} MonoDynamicImageTokCollision;
+
 void
 mono_dynamic_images_init (void);
 
 void
-mono_dynamic_image_register_token (MonoDynamicImage *assembly, guint32 token, MonoObjectHandle obj);
+mono_dynamic_image_register_token (MonoDynamicImage *assembly, guint32 token, MonoObjectHandle obj, int tok_collision);
 
 gboolean
 mono_dynamic_image_is_valid_token (MonoDynamicImage *image, guint32 token);
index 211ba26266f050be64153fbbe19701171d265f6b..063b8e5570d1e52747b5e40f7da15397eb219bca 100644 (file)
@@ -193,17 +193,32 @@ dynamic_image_unlock (MonoDynamicImage *image)
  * the Module.ResolveXXXToken () methods to work.
  */
 void
-mono_dynamic_image_register_token (MonoDynamicImage *assembly, guint32 token, MonoObjectHandle obj)
+mono_dynamic_image_register_token (MonoDynamicImage *assembly, guint32 token, MonoObjectHandle obj, int how_collide)
 {
        MONO_REQ_GC_UNSAFE_MODE;
 
+       g_assert (!MONO_HANDLE_IS_NULL (obj));
        dynamic_image_lock (assembly);
+       MonoObject *prev = (MonoObject *)mono_g_hash_table_lookup (assembly->tokens, GUINT_TO_POINTER (token));
+       if (prev) {
+               switch (how_collide) {
+               case MONO_DYN_IMAGE_TOK_NEW:
+                       g_assert_not_reached ();
+               case MONO_DYN_IMAGE_TOK_SAME_OK:
+                       g_assert (prev == MONO_HANDLE_RAW (obj));
+                       break;
+               case MONO_DYN_IMAGE_TOK_REPLACE:
+                       break;
+               default:
+                       g_assert_not_reached ();
+               }
+       }
        mono_g_hash_table_insert (assembly->tokens, GUINT_TO_POINTER (token), MONO_HANDLE_RAW (obj));
        dynamic_image_unlock (assembly);
 }
 #else
 void
-mono_dynamic_image_register_token (MonoDynamicImage *assembly, guint32 token, MonoObjectHandle obj)
+mono_dynamic_image_register_token (MonoDynamicImage *assembly, guint32 token, MonoObjectHandle obj, int how_collide)
 {
 }
 #endif
index 89f9a1fdaee0b1c09cf2c395c1b0bbecf2d8b41f..5ff236fc12edf97e008528de56ab031899af8e2b 100644 (file)
@@ -793,7 +793,8 @@ mono_dynimage_encode_typedef_or_ref_full (MonoDynamicImage *assembly, MonoType *
        if ((klass->image == &assembly->image) && (type->type != MONO_TYPE_VAR) && 
                        (type->type != MONO_TYPE_MVAR)) {
                token = MONO_TYPEDEFORREF_TYPEDEF | (MONO_HANDLE_GETVAL (tb, table_idx) << MONO_TYPEDEFORREF_BITS);
-               mono_dynamic_image_register_token (assembly, token, MONO_HANDLE_CAST (MonoObject, tb));
+               /* This function is called multiple times from sre and sre-save, so same object is okay */
+               mono_dynamic_image_register_token (assembly, token, MONO_HANDLE_CAST (MonoObject, tb), MONO_DYN_IMAGE_TOK_SAME_OK);
                goto leave;
        }
 
@@ -816,7 +817,13 @@ mono_dynimage_encode_typedef_or_ref_full (MonoDynamicImage *assembly, MonoType *
        token = MONO_TYPEDEFORREF_TYPEREF | (table->next_idx << MONO_TYPEDEFORREF_BITS); /* typeref */
        g_hash_table_insert (assembly->typeref, type, GUINT_TO_POINTER(token));
        table->next_idx ++;
-       mono_dynamic_image_register_token (assembly, token, MONO_HANDLE_CAST (MonoObject, tb));
+
+
+       if (!MONO_HANDLE_IS_NULL (tb)) {
+               /* This function is called multiple times from sre and sre-save, so same object is okay */
+               mono_dynamic_image_register_token (assembly, token, MONO_HANDLE_CAST (MonoObject, tb), MONO_DYN_IMAGE_TOK_SAME_OK);
+       }
+
 leave:
        HANDLE_FUNCTION_RETURN_VAL (token);
 }
index 3beb23242fba8111191c0656cdb74a6d96d10508..eda0cf400756e1bbb0283f4df6d054865a4aa768 100644 (file)
@@ -1022,7 +1022,7 @@ mono_image_insert_string (MonoReflectionModuleBuilderHandle ref_module, MonoStri
        }
 
        token = MONO_TOKEN_STRING | idx;
-       mono_dynamic_image_register_token (assembly, token, MONO_HANDLE_CAST (MonoObject, str));
+       mono_dynamic_image_register_token (assembly, token, MONO_HANDLE_CAST (MonoObject, str), MONO_DYN_IMAGE_TOK_NEW);
 
 leave:
        HANDLE_FUNCTION_RETURN_VAL (token);
@@ -1092,7 +1092,7 @@ mono_image_create_method_token (MonoDynamicImage *assembly, MonoObjectHandle obj
                g_error ("requested method token for %s\n", klass->name);
        }
 
-       mono_dynamic_image_register_token (assembly, token, obj);
+       mono_dynamic_image_register_token (assembly, token, obj, MONO_DYN_IMAGE_TOK_NEW);
        return token;
 fail:
        g_assert (!mono_error_ok (error));
@@ -1128,12 +1128,18 @@ mono_image_create_token (MonoDynamicImage *assembly, MonoObjectHandle obj,
                return 0;
        }
 
+       /* This function is called from ModuleBuilder:getToken multiple times for the same objects */
+       int how_collide = MONO_DYN_IMAGE_TOK_SAME_OK;
+
        if (strcmp (klass->name, "RuntimeType") == 0) {
                MonoType *type = mono_reflection_type_handle_mono_type (MONO_HANDLE_CAST (MonoReflectionType, obj), error);
                return_val_if_nok (error, 0);
                MonoClass *mc = mono_class_from_mono_type (type);
                token = mono_metadata_token_from_dor (
                        mono_dynimage_encode_typedef_or_ref_full (assembly, type, !mono_class_is_gtd (mc) || create_open_instance));
+               /* If it's a RuntimeType now, we could have registered a
+                * TypeBuilder for it before, so replacing is okay. */
+               how_collide = MONO_DYN_IMAGE_TOK_REPLACE;
        } else if (strcmp (klass->name, "MonoCMethod") == 0 ||
                           strcmp (klass->name, "MonoMethod") == 0) {
                MonoReflectionMethodHandle m = MONO_HANDLE_CAST (MonoReflectionMethod, obj);
@@ -1152,6 +1158,7 @@ mono_image_create_token (MonoDynamicImage *assembly, MonoObjectHandle obj,
                                 * FIXME: do the equivalent for Fields.
                                 */
                                token = method->token;
+                               how_collide = MONO_DYN_IMAGE_TOK_REPLACE;
                        } else {
                                /*
                                 * Each token should have a unique index, but the indexes are
@@ -1160,6 +1167,7 @@ mono_image_create_token (MonoDynamicImage *assembly, MonoObjectHandle obj,
                                 */
                                method_table_idx --;
                                token = MONO_TOKEN_METHOD_DEF | method_table_idx;
+                               how_collide = MONO_DYN_IMAGE_TOK_NEW;
                        }
                } else {
                        token = mono_image_get_methodref_token (assembly, method, create_open_instance);
@@ -1172,6 +1180,7 @@ mono_image_create_token (MonoDynamicImage *assembly, MonoObjectHandle obj,
                        static guint32 field_table_idx = 0xffffff;
                        field_table_idx --;
                        token = MONO_TOKEN_FIELD_DEF | field_table_idx;
+                       how_collide = MONO_DYN_IMAGE_TOK_NEW;
                } else {
                        token = mono_image_get_fieldref_token (assembly, obj, field);
                }
@@ -1194,7 +1203,7 @@ mono_image_create_token (MonoDynamicImage *assembly, MonoObjectHandle obj,
        }
 
        if (register_token)
-               mono_dynamic_image_register_token (assembly, token, obj);
+               mono_dynamic_image_register_token (assembly, token, obj, how_collide);
 
        return token;
 }
@@ -2474,7 +2483,7 @@ reflection_setup_internal_class_internal (MonoReflectionTypeBuilderHandle ref_tb
        */
        mono_image_append_class_to_reflection_info_set (klass);
 
-       mono_dynamic_image_register_token (dynamic_image, MONO_TOKEN_TYPE_DEF | table_idx, MONO_HANDLE_CAST (MonoObject, ref_tb));
+       mono_dynamic_image_register_token (dynamic_image, MONO_TOKEN_TYPE_DEF | table_idx, MONO_HANDLE_CAST (MonoObject, ref_tb), MONO_DYN_IMAGE_TOK_NEW);
 
        if ((!strcmp (klass->name, "ValueType") && !strcmp (klass->name_space, "System")) ||
                        (!strcmp (klass->name, "Object") && !strcmp (klass->name_space, "System")) ||
@@ -4337,7 +4346,9 @@ void
 ves_icall_ModuleBuilder_RegisterToken (MonoReflectionModuleBuilderHandle mb, MonoObjectHandle obj, guint32 token, MonoError *error)
 {
        error_init (error);
-       mono_dynamic_image_register_token (MONO_HANDLE_GETVAL (mb, dynamic_image), token, obj);
+       /* This function may be called by ModuleBuilder.FixupTokens to update
+        * an existing token, so replace is okay here. */
+       mono_dynamic_image_register_token (MONO_HANDLE_GETVAL (mb, dynamic_image), token, obj, MONO_DYN_IMAGE_TOK_REPLACE);
 }
 
 MonoObjectHandle