From 6df483ca4345faf066e377dd3cbdde31ce66e55d Mon Sep 17 00:00:00 2001 From: Zoltan Varga Date: Wed, 8 Feb 2017 18:16:09 -0500 Subject: [PATCH] [runtime] Add a cache for generic array helper wrappers to reduce the number created. This works because there are a lot of duplicates due to the fact that the interfaces passed to setup_generic_array_ifaces () have the same context. (#4343) --- mono/metadata/class.c | 24 +++++++++++++++--------- mono/metadata/marshal.c | 8 +++++++- mono/metadata/marshal.h | 3 +-- 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/mono/metadata/class.c b/mono/metadata/class.c index 585999a6dab..c1ebbbb3a96 100644 --- a/mono/metadata/class.c +++ b/mono/metadata/class.c @@ -69,7 +69,7 @@ static gboolean mono_class_get_cached_class_info (MonoClass *klass, MonoCachedCl static gboolean can_access_type (MonoClass *access_klass, MonoClass *member_klass); static MonoMethod* find_method_in_metadata (MonoClass *klass, const char *name, int param_count, int flags); static int generic_array_methods (MonoClass *klass); -static void setup_generic_array_ifaces (MonoClass *klass, MonoClass *iface, MonoMethod **methods, int pos); +static void setup_generic_array_ifaces (MonoClass *klass, MonoClass *iface, MonoMethod **methods, int pos, GHashTable *cache); static MonoMethod* mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter); static char* mono_assembly_name_from_token (MonoImage *image, guint32 type_token); @@ -2363,8 +2363,10 @@ mono_class_setup_methods (MonoClass *klass) amethod = create_array_method (klass, "Set", sig); methods [method_num++] = amethod; + GHashTable *cache = g_hash_table_new (NULL, NULL); for (i = 0; i < klass->interface_count; i++) - setup_generic_array_ifaces (klass, klass->interfaces [i], methods, first_generic + i * count_generic); + setup_generic_array_ifaces (klass, klass->interfaces [i], methods, first_generic + i * count_generic, cache); + g_hash_table_destroy (cache); } else if (mono_class_has_static_metadata (klass)) { MonoError error; int first_idx = mono_class_get_first_method_idx (klass); @@ -4742,7 +4744,7 @@ generic_array_methods (MonoClass *klass) } static void -setup_generic_array_ifaces (MonoClass *klass, MonoClass *iface, MonoMethod **methods, int pos) +setup_generic_array_ifaces (MonoClass *klass, MonoClass *iface, MonoMethod **methods, int pos, GHashTable *cache) { MonoGenericContext tmp_context; int i; @@ -4754,11 +4756,16 @@ setup_generic_array_ifaces (MonoClass *klass, MonoClass *iface, MonoMethod **met for (i = 0; i < generic_array_method_num; i++) { MonoError error; MonoMethod *m = generic_array_method_info [i].array_method; - MonoMethod *inflated; + MonoMethod *inflated, *helper; inflated = mono_class_inflate_generic_method_checked (m, &tmp_context, &error); - g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/ - methods [pos++] = mono_marshal_get_generic_array_helper (klass, iface, generic_array_method_info [i].name, inflated); + mono_error_assert_ok (&error); + helper = g_hash_table_lookup (cache, inflated); + if (!helper) { + helper = mono_marshal_get_generic_array_helper (klass, generic_array_method_info [i].name, inflated); + g_hash_table_insert (cache, inflated, helper); + } + methods [pos ++] = helper; } } @@ -10409,14 +10416,13 @@ mono_class_setup_interfaces (MonoClass *klass, MonoError *error) MonoType *args [1]; /* generic IList, ICollection, IEnumerable */ - interface_count = mono_defaults.generic_ireadonlylist_class ? 2 : 1; + interface_count = 2; interfaces = (MonoClass **)mono_image_alloc0 (klass->image, sizeof (MonoClass*) * interface_count); args [0] = &klass->element_class->byval_arg; interfaces [0] = mono_class_bind_generic_parameters ( mono_defaults.generic_ilist_class, 1, args, FALSE); - if (interface_count > 1) - interfaces [1] = mono_class_bind_generic_parameters ( + interfaces [1] = mono_class_bind_generic_parameters ( mono_defaults.generic_ireadonlylist_class, 1, args, FALSE); } else if (mono_class_is_ginst (klass)) { MonoClass *gklass = mono_class_get_generic_class (klass)->container_class; diff --git a/mono/metadata/marshal.c b/mono/metadata/marshal.c index b06c455707d..6020bf50eb4 100644 --- a/mono/metadata/marshal.c +++ b/mono/metadata/marshal.c @@ -11754,8 +11754,14 @@ mono_marshal_free_asany (MonoObject *o, gpointer ptr, MonoMarshalNative string_e } } +/* + * mono_marshal_get_generic_array_helper: + * + * Return a wrapper which is used to implement the implicit interfaces on arrays. + * The wrapper routes calls to METHOD, which is one of the InternalArray_ methods in Array. + */ MonoMethod * -mono_marshal_get_generic_array_helper (MonoClass *klass, MonoClass *iface, gchar *name, MonoMethod *method) +mono_marshal_get_generic_array_helper (MonoClass *klass, gchar *name, MonoMethod *method) { MonoMethodSignature *sig, *csig; MonoMethodBuilder *mb; diff --git a/mono/metadata/marshal.h b/mono/metadata/marshal.h index a0884c66ca4..e00661b1b59 100644 --- a/mono/metadata/marshal.h +++ b/mono/metadata/marshal.h @@ -384,8 +384,7 @@ MonoMethod * mono_marshal_get_array_accessor_wrapper (MonoMethod *method); MonoMethod * -mono_marshal_get_generic_array_helper (MonoClass *klass, MonoClass *iface, - gchar *name, MonoMethod *method); +mono_marshal_get_generic_array_helper (MonoClass *klass, gchar *name, MonoMethod *method); MonoMethod * mono_marshal_get_thunk_invoke_wrapper (MonoMethod *method); -- 2.25.1