From 792b5367cd3a6ffa1a192c4d2d7ace3509cbb646 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Wed, 26 Jul 2017 11:39:36 -0400 Subject: [PATCH] [sre] Add MonoDynamicImageTokCollision arg to mono_dynamic_image_register_token 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 | 8 +++++++- mono/metadata/dynamic-image.c | 19 +++++++++++++++++-- mono/metadata/sre-encode.c | 11 +++++++++-- mono/metadata/sre.c | 21 ++++++++++++++++----- 4 files changed, 49 insertions(+), 10 deletions(-) diff --git a/mono/metadata/dynamic-image-internals.h b/mono/metadata/dynamic-image-internals.h index 344d2d6e978..bb1084e981e 100644 --- a/mono/metadata/dynamic-image-internals.h +++ b/mono/metadata/dynamic-image-internals.h @@ -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); diff --git a/mono/metadata/dynamic-image.c b/mono/metadata/dynamic-image.c index 211ba26266f..063b8e5570d 100644 --- a/mono/metadata/dynamic-image.c +++ b/mono/metadata/dynamic-image.c @@ -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 diff --git a/mono/metadata/sre-encode.c b/mono/metadata/sre-encode.c index 89f9a1fdaee..5ff236fc12e 100644 --- a/mono/metadata/sre-encode.c +++ b/mono/metadata/sre-encode.c @@ -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); } diff --git a/mono/metadata/sre.c b/mono/metadata/sre.c index 3beb23242fb..eda0cf40075 100644 --- a/mono/metadata/sre.c +++ b/mono/metadata/sre.c @@ -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 -- 2.25.1