From 96e48a63f67fdd2863103aead4355ce8ced864cb Mon Sep 17 00:00:00 2001 From: Rodrigo Kumpera Date: Thu, 7 Oct 2010 15:45:57 -0300 Subject: [PATCH] Add gsharing support for cached casts. * class-internals.h: Add new kind of rgctx slot. * method-to-ir.c (handle_castclass): Emit gsharing code for cast with caching. * method-to-ir.c (handle_isinst): * mini-generic-sharing.c: Implement MONO_RGCTX_INFO_CAST_CACHE slot type. It's a 2 word domain allocated memory block with the cache on the first word and the vtable on the second. This design does a single rgctx fetch instead of two. It's a bit faster and can potentialy save some slots. --- mono/metadata/class-internals.h | 3 +- mono/mini/method-to-ir.c | 44 +++++++++++++++++++++++++---- mono/mini/mini-generic-sharing.c | 48 ++++++++++++++++++++++++-------- 3 files changed, 76 insertions(+), 19 deletions(-) diff --git a/mono/metadata/class-internals.h b/mono/metadata/class-internals.h index c1652605d5b..50b11ddb834 100644 --- a/mono/metadata/class-internals.h +++ b/mono/metadata/class-internals.h @@ -226,7 +226,8 @@ enum { MONO_RGCTX_INFO_METHOD_RGCTX, MONO_RGCTX_INFO_METHOD_CONTEXT, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK, - MONO_RGCTX_INFO_METHOD_DELEGATE_CODE + MONO_RGCTX_INFO_METHOD_DELEGATE_CODE, + MONO_RGCTX_INFO_CAST_CACHE }; typedef struct _MonoRuntimeGenericContextOtherInfoTemplate { diff --git a/mono/mini/method-to-ir.c b/mono/mini/method-to-ir.c index b8483c0161f..4b02af1a4e1 100644 --- a/mono/mini/method-to-ir.c +++ b/mono/mini/method-to-ir.c @@ -3335,10 +3335,26 @@ handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context MonoInst *klass_inst = NULL; if (context_used) { - MonoInst *args [2]; + MonoInst *args [3]; + + if(mini_class_has_reference_variant_generic_argument (klass, context_used)) { + MonoInst *cache_ins; + + cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE); + + /* obj */ + args [0] = src; - klass_inst = emit_get_rgctx_klass (cfg, context_used, - klass, MONO_RGCTX_INFO_KLASS); + /* klass - it's the second element of the cache entry*/ + EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer)); + + /* cache */ + args [2] = cache_ins; + + return mono_emit_jit_icall (cfg, mono_object_castclass_with_cache, args); + } + + klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS); if (is_complex_isinst (klass)) { /* Complex case, handle by an icall */ @@ -3412,11 +3428,28 @@ handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_us MonoInst *klass_inst = NULL; if (context_used) { + MonoInst *args [3]; + + if(mini_class_has_reference_variant_generic_argument (klass, context_used)) { + MonoInst *cache_ins; + + cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE); + + /* obj */ + args [0] = src; + + /* klass - it's the second element of the cache entry*/ + EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer)); + + /* cache */ + args [2] = cache_ins; + + return mono_emit_jit_icall (cfg, mono_object_isinst_with_cache, args); + } + klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS); if (is_complex_isinst (klass)) { - MonoInst *args [2]; - /* Complex case, handle by an icall */ /* obj */ @@ -7892,7 +7925,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b /*FIXME AOT support*/ EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer))); - ins = mono_emit_jit_icall (cfg, mono_object_castclass_with_cache, args); *sp ++ = ins; ip += 5; diff --git a/mono/mini/mini-generic-sharing.c b/mono/mini/mini-generic-sharing.c index 28a472bfc72..018054018d8 100644 --- a/mono/mini/mini-generic-sharing.c +++ b/mono/mini/mini-generic-sharing.c @@ -359,6 +359,17 @@ alloc_oti (MonoImage *image) #define MONO_RGCTX_SLOT_USED_MARKER ((gpointer)&mono_defaults.object_class->byval_arg) +/* + * Return true if this info type has the notion of identify. + * + * Some info types expect that each insert results in a new slot been assigned. + */ +static int +other_info_has_identity (int info_type) +{ + return info_type != MONO_RGCTX_INFO_CAST_CACHE; +} + /* * LOCKING: loader lock */ @@ -494,7 +505,8 @@ inflate_other_data (gpointer data, int info_type, MonoGenericContext *context, M case MONO_RGCTX_INFO_KLASS: case MONO_RGCTX_INFO_VTABLE: case MONO_RGCTX_INFO_TYPE: - case MONO_RGCTX_INFO_REFLECTION_TYPE: { + case MONO_RGCTX_INFO_REFLECTION_TYPE: + case MONO_RGCTX_INFO_CAST_CACHE: { gpointer result = mono_class_inflate_generic_type_with_mempool (temporary ? NULL : class->image, data, context, &error); g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/ @@ -571,6 +583,7 @@ free_inflated_info (int info_type, gpointer info) case MONO_RGCTX_INFO_VTABLE: case MONO_RGCTX_INFO_TYPE: case MONO_RGCTX_INFO_REFLECTION_TYPE: + case MONO_RGCTX_INFO_CAST_CACHE: mono_metadata_free_type (info); break; default: @@ -844,6 +857,12 @@ class_type_info (MonoDomain *domain, MonoClass *class, int info_type) mono_raise_exception (mono_class_get_exception_for_failure (class)); return vtable; } + case MONO_RGCTX_INFO_CAST_CACHE: { + /*First slot is the cache itself, the second the vtable.*/ + gpointer **cache_data = mono_domain_alloc0 (domain, sizeof (gpointer) * 2); + cache_data [1] = (gpointer)class; + return cache_data; + } default: g_assert_not_reached (); } @@ -865,6 +884,7 @@ instantiate_other_info (MonoDomain *domain, MonoRuntimeGenericContextOtherInfoTe case MONO_RGCTX_INFO_STATIC_DATA: case MONO_RGCTX_INFO_KLASS: case MONO_RGCTX_INFO_VTABLE: + case MONO_RGCTX_INFO_CAST_CACHE: temporary = TRUE; break; default: @@ -876,7 +896,8 @@ instantiate_other_info (MonoDomain *domain, MonoRuntimeGenericContextOtherInfoTe switch (oti->info_type) { case MONO_RGCTX_INFO_STATIC_DATA: case MONO_RGCTX_INFO_KLASS: - case MONO_RGCTX_INFO_VTABLE: { + case MONO_RGCTX_INFO_VTABLE: + case MONO_RGCTX_INFO_CAST_CACHE: { MonoClass *arg_class = mono_class_from_mono_type (data); free_inflated_info (oti->info_type, data); @@ -1023,6 +1044,7 @@ other_info_equal (gpointer data1, gpointer data2, int info_type) case MONO_RGCTX_INFO_VTABLE: case MONO_RGCTX_INFO_TYPE: case MONO_RGCTX_INFO_REFLECTION_TYPE: + case MONO_RGCTX_INFO_CAST_CACHE: return mono_class_from_mono_type (data1) == mono_class_from_mono_type (data2); case MONO_RGCTX_INFO_METHOD: case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: @@ -1053,22 +1075,24 @@ lookup_or_register_other_info (MonoClass *class, int type_argc, gpointer data, i mono_loader_lock (); - oti_list = get_other_info_templates (rgctx_template, type_argc); + if (other_info_has_identity (info_type)) { + oti_list = get_other_info_templates (rgctx_template, type_argc); - for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) { - gpointer inflated_data; + for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) { + gpointer inflated_data; - if (oti->info_type != info_type || !oti->data) - continue; + if (oti->info_type != info_type || !oti->data) + continue; - inflated_data = inflate_other_info (oti, generic_context, class, TRUE); + inflated_data = inflate_other_info (oti, generic_context, class, TRUE); - if (other_info_equal (data, inflated_data, info_type)) { + if (other_info_equal (data, inflated_data, info_type)) { + free_inflated_info (info_type, inflated_data); + mono_loader_unlock (); + return i; + } free_inflated_info (info_type, inflated_data); - mono_loader_unlock (); - return i; } - free_inflated_info (info_type, inflated_data); } /* We haven't found the info */ -- 2.25.1