Author: mprobst
Date: 2007-09-20 11:36:56 -0400 (Thu, 20 Sep 2007)
New Revision: 86066

Added:
   trunk/mono/mono/mini/generic-sharing.c
   trunk/mono/mono/tests/generics-sharing.2.cs
Modified:
   trunk/mono/mono/metadata/ChangeLog
   trunk/mono/mono/metadata/class-internals.h
   trunk/mono/mono/metadata/domain-internals.h
   trunk/mono/mono/metadata/domain.c
   trunk/mono/mono/mini/ChangeLog
   trunk/mono/mono/mini/Makefile.am
   trunk/mono/mono/mini/mini.c
   trunk/mono/mono/mini/mini.h
   trunk/mono/mono/mini/optflags-def.h
   trunk/mono/mono/tests/ChangeLog
   trunk/mono/mono/tests/Makefile.am
Log:
2007-09-20  Mark Probst  <[EMAIL PROTECTED]>

        * mini.c: First generics sharing implementation.  Can only share
        in very simple cases.  If sharing doesn't work it falls back to
        dedicated compilation.

        * mini.h: Flag in MonoCompile to specify whether generic
        compilation is shared.  Flags enum for marking which generic inst
        of a context is used.  Prototypes for helper functions.

        * generic-sharing.c: Helper functions for generic method sharing.

        * optflags-def.h: Optimization flag (gshared) for enabling generic
        method sharing added.

        * Makefile.am: generic-sharing.c added.

2007-09-20  Mark Probst  <[EMAIL PROTECTED]>

        * domain-internals.h: New flag in MonoJitInfo which marks shared
        generic methods.  New hash table (shared_generics_hash) in
        MonoDomain to keep track of shared generic methods.  Prototypes
        for functions to register and lookup shared generic methods.

        * domain.c: Support for registering and looking up shared generic
        methods via a hash table (shared_generics_hash) in MonoDomain.

        * class-internals.h: New exception to signal failure of shared
        compilation of a generic method.  New counters for generics
        sharing in MonoStats.

2007-09-20  Mark Probst  <[EMAIL PROTECTED]>

        * generics-sharing.2.cs: added

        * Makefile.am: added generics-sharing.2.cs


Modified: trunk/mono/mono/metadata/ChangeLog
===================================================================
--- trunk/mono/mono/metadata/ChangeLog  2007-09-20 15:25:36 UTC (rev 86065)
+++ trunk/mono/mono/metadata/ChangeLog  2007-09-20 15:36:56 UTC (rev 86066)
@@ -1,4 +1,17 @@
+2007-09-20  Mark Probst  <[EMAIL PROTECTED]>
 
+       * domain-internals.h: New flag in MonoJitInfo which marks shared
+       generic methods.  New hash table (shared_generics_hash) in
+       MonoDomain to keep track of shared generic methods.  Prototypes
+       for functions to register and lookup shared generic methods.
+
+       * domain.c: Support for registering and looking up shared generic
+       methods via a hash table (shared_generics_hash) in MonoDomain.
+
+       * class-internals.h: New exception to signal failure of shared
+       compilation of a generic method.  New counters for generics
+       sharing in MonoStats.
+
 Thu Sep 20 16:59:36 CEST 2007 Paolo Molaro <[EMAIL PROTECTED]>
 
        * image.c, metadata-internals.h: don't keep a file descriptor open

Modified: trunk/mono/mono/metadata/class-internals.h
===================================================================
--- trunk/mono/mono/metadata/class-internals.h  2007-09-20 15:25:36 UTC (rev 
86065)
+++ trunk/mono/mono/metadata/class-internals.h  2007-09-20 15:36:56 UTC (rev 
86066)
@@ -175,6 +175,7 @@
        MONO_EXCEPTION_FILE_NOT_FOUND = 8,
        MONO_EXCEPTION_METHOD_ACCESS = 9,
        MONO_EXCEPTION_FIELD_ACCESS = 10,
+       MONO_EXCEPTION_GENERIC_SHARING_FAILED = 11,
        /* add other exception type */
 };
 
@@ -529,6 +530,9 @@
        gulong jit_info_table_remove_count;
        gulong jit_info_table_lookup_count;
        gulong hazardous_pointer_count;
+       gulong generics_sharable_methods;
+       gulong generics_unsharable_methods;
+       gulong generics_shared_methods;
        gboolean enabled;
 } MonoStats;
 

Modified: trunk/mono/mono/metadata/domain-internals.h
===================================================================
--- trunk/mono/mono/metadata/domain-internals.h 2007-09-20 15:25:36 UTC (rev 
86065)
+++ trunk/mono/mono/metadata/domain-internals.h 2007-09-20 15:36:56 UTC (rev 
86066)
@@ -82,7 +82,7 @@
        gpointer    code_start;
        guint32     used_regs;
        int         code_size;
-       guint32     num_clauses:24;
+       guint32     num_clauses:16;
        /* Whenever the code is domain neutral or 'shared' */
        gboolean    domain_neutral:1;
        gboolean    cas_inited:1;
@@ -92,6 +92,7 @@
        gboolean    cas_method_assert:1;
        gboolean    cas_method_deny:1;
        gboolean    cas_method_permitonly:1;
+       gboolean    generic_shared:1;
        MonoJitExceptionInfo clauses [MONO_ZERO_LEN_ARRAY];
 };
 
@@ -179,6 +180,8 @@
        GHashTable         *finalizable_objects_hash;
        /* Used when accessing 'domain_assemblies' */
        CRITICAL_SECTION    assemblies_lock;
+
+       GHashTable         *shared_generics_hash;
 };
 
 typedef struct  {
@@ -212,6 +215,13 @@
 void
 mono_jit_info_add_aot_module (MonoImage *image, gpointer start, gpointer end) 
MONO_INTERNAL;
 
+MonoJitInfo*
+mono_domain_lookup_shared_generic (MonoDomain *domain, MonoMethod *method) 
MONO_INTERNAL;
+
+void
+mono_domain_register_shared_generic (MonoDomain *domain, MonoMethod *method, 
MonoJitInfo *jit_info) MONO_INTERNAL;
+
+
 /* 
  * Installs a new function which is used to return a MonoJitInfo for a method 
inside
  * an AOT module.

Modified: trunk/mono/mono/metadata/domain.c
===================================================================
--- trunk/mono/mono/metadata/domain.c   2007-09-20 15:25:36 UTC (rev 86065)
+++ trunk/mono/mono/metadata/domain.c   2007-09-20 15:36:56 UTC (rev 86066)
@@ -1068,6 +1068,8 @@
        InitializeCriticalSection (&domain->lock);
        InitializeCriticalSection (&domain->assemblies_lock);
 
+       domain->shared_generics_hash = NULL;
+
        mono_debug_domain_create (domain);
 
        mono_appdomains_lock ();
@@ -1645,6 +1647,26 @@
        return ass;
 }
 
+MonoJitInfo*
+mono_domain_lookup_shared_generic (MonoDomain *domain, MonoMethod *method)
+{
+       if (!domain->shared_generics_hash)
+               return NULL;
+
+       return g_hash_table_lookup (domain->shared_generics_hash, method);
+}
+
+void
+mono_domain_register_shared_generic (MonoDomain *domain, MonoMethod *method, 
MonoJitInfo *jit_info)
+{
+       if (!domain->shared_generics_hash)
+               domain->shared_generics_hash = g_hash_table_new 
(mono_aligned_addr_hash, NULL);
+
+       g_assert (domain->shared_generics_hash);
+
+       g_hash_table_insert (domain->shared_generics_hash, method, jit_info);
+}
+
 static void
 dynamic_method_info_free (gpointer key, gpointer value, gpointer user_data)
 {
@@ -1758,6 +1780,10 @@
        domain->jit_trampoline_hash = NULL;
        g_hash_table_destroy (domain->delegate_trampoline_hash);
        domain->delegate_trampoline_hash = NULL;
+       if (domain->shared_generics_hash) {
+               g_hash_table_destroy (domain->shared_generics_hash);
+               domain->shared_generics_hash = NULL;
+       }
 
        DeleteCriticalSection (&domain->assemblies_lock);
        DeleteCriticalSection (&domain->lock);

Modified: trunk/mono/mono/mini/ChangeLog
===================================================================
--- trunk/mono/mono/mini/ChangeLog      2007-09-20 15:25:36 UTC (rev 86065)
+++ trunk/mono/mono/mini/ChangeLog      2007-09-20 15:36:56 UTC (rev 86066)
@@ -1,3 +1,20 @@
+2007-09-20  Mark Probst  <[EMAIL PROTECTED]>
+
+       * mini.c: First generics sharing implementation.  Can only share
+       in very simple cases.  If sharing doesn't work it falls back to
+       dedicated compilation.
+
+       * mini.h: Flag in MonoCompile to specify whether generic
+       compilation is shared.  Flags enum for marking which generic inst
+       of a context is used.  Prototypes for helper functions.
+
+       * generic-sharing.c: Helper functions for generic method sharing.
+
+       * optflags-def.h: Optimization flag (gshared) for enabling generic
+       method sharing added.
+
+       * Makefile.am: generic-sharing.c added.
+
 2007-09-19 Daniel Nauck <[EMAIL PROTECTED]>
 
        * mini.c (mono_thread_abort): fixed typo in r86014. It should be '==' 
instead of '!='.

Modified: trunk/mono/mono/mini/Makefile.am
===================================================================
--- trunk/mono/mono/mini/Makefile.am    2007-09-20 15:25:36 UTC (rev 86065)
+++ trunk/mono/mono/mini/Makefile.am    2007-09-20 15:36:56 UTC (rev 86066)
@@ -230,7 +230,8 @@
        declsec.c       \
        declsec.h       \
        wapihandles.c   \
-       branch-opts.c
+       branch-opts.c   \
+       generic-sharing.c
 
 test_sources =                 \
        basic-calls.cs  \

Added: trunk/mono/mono/mini/generic-sharing.c
===================================================================
--- trunk/mono/mono/mini/generic-sharing.c      2007-09-20 15:25:36 UTC (rev 
86065)
+++ trunk/mono/mono/mini/generic-sharing.c      2007-09-20 15:36:56 UTC (rev 
86066)
@@ -0,0 +1,209 @@
+/*
+ * generic-sharing.c: Support functions for generic sharing.
+ *
+ * Author:
+ *   Mark Probst ([EMAIL PROTECTED])
+ *
+ * (C) 2007 Novell, Inc.
+ */
+
+#include <config.h>
+
+#include <mono/metadata/class.h>
+
+#include "mini.h"
+
+static gboolean
+generic_inst_uses_type (MonoGenericInst *inst, MonoType *type)
+{
+       int i;
+
+       if (!inst)
+               return FALSE;
+
+       for (i = 0; i < inst->type_argc; ++i)
+               if (mono_metadata_type_equal (type, inst->type_argv [i]))
+                       return TRUE;
+       return FALSE;
+}
+
+static int context_check_context_used (MonoGenericContext *context, 
MonoGenericContext *shared_context);
+
+static int
+type_check_context_used (MonoType *type, MonoGenericContext *context, gboolean 
recursive)
+{
+       int context_used = 0;
+
+       if (generic_inst_uses_type (context->class_inst, type))
+               context_used |= MONO_GENERIC_CONTEXT_USED_CLASS;
+       if (generic_inst_uses_type (context->method_inst, type))
+               context_used |= MONO_GENERIC_CONTEXT_USED_METHOD;
+
+       if (recursive) {
+               int t = mono_type_get_type (type);
+
+               if (t == MONO_TYPE_CLASS)
+                       context_used |= mono_class_check_context_used 
(mono_type_get_class (type), context);
+               else if (t == MONO_TYPE_GENERICINST) {
+                       MonoGenericClass *gclass = type->data.generic_class;
+
+                       context_used |= context_check_context_used 
(&gclass->context, context);
+                       context_used |= mono_class_check_context_used 
(gclass->container_class, context);
+               }
+       }
+
+       return context_used;
+}
+
+static int
+inst_check_context_used (MonoGenericInst *inst, MonoGenericContext *context)
+{
+       int context_used = 0;
+       int i;
+
+       if (!inst)
+               return 0;
+
+       for (i = 0; i < inst->type_argc; ++i)
+               context_used |= type_check_context_used (inst->type_argv [i], 
context, TRUE);
+
+       return context_used;
+}
+
+static int
+context_check_context_used (MonoGenericContext *context, MonoGenericContext 
*shared_context)
+{
+       int context_used = 0;
+
+       context_used |= inst_check_context_used (context->class_inst, 
shared_context);
+       context_used |= inst_check_context_used (context->method_inst, 
shared_context);
+
+       return context_used;
+}
+
+int
+mono_method_check_context_used (MonoMethod *method, MonoGenericContext 
*context)
+{
+       MonoGenericContext *method_context = mono_method_get_context (method);
+
+       if (!method_context)
+               return 0;
+
+       return context_check_context_used (method_context, context);
+}
+
+int
+mono_class_check_context_used (MonoClass *class, MonoGenericContext *context)
+{
+       int context_used = 0;
+
+       context_used |= type_check_context_used (&class->this_arg, context, 
FALSE);
+       context_used |= type_check_context_used (&class->byval_arg, context, 
FALSE);
+
+       if (class->generic_class)
+               context_used |= context_check_context_used 
(&class->generic_class->context, context);
+
+       return context_used;
+}
+
+static gboolean
+generic_inst_is_sharable (MonoGenericInst *inst)
+{
+       int i;
+
+       for (i = 0; i < inst->type_argc; ++i) {
+               int type = mono_type_get_type (inst->type_argv [i]);
+
+               if (type != MONO_TYPE_CLASS && type != MONO_TYPE_STRING && type 
!= MONO_TYPE_OBJECT &&
+                               type != MONO_TYPE_SZARRAY && type != 
MONO_TYPE_ARRAY)
+                       return FALSE;
+       }
+
+       return TRUE;
+}
+
+static gboolean
+generic_context_is_sharable (MonoGenericContext *context)
+{
+       g_assert (context->class_inst || context->method_inst);
+
+       if (context->class_inst && !generic_inst_is_sharable 
(context->class_inst))
+               return FALSE;
+
+       if (context->method_inst && !generic_inst_is_sharable 
(context->method_inst))
+               return FALSE;
+
+       return TRUE;
+}
+
+gboolean
+mono_method_is_generic_impl (MonoMethod *method)
+{
+       return method->klass->generic_class != NULL && method->is_inflated;
+}
+
+gboolean
+mono_method_is_generic_sharable_impl (MonoMethod *method)
+{
+       if (!mono_method_is_generic_impl (method))
+               return FALSE;
+
+       if (method->is_inflated) {
+               MonoMethodInflated *inflated = (MonoMethodInflated*)method;
+               MonoGenericContext *context = &inflated->context;
+
+               if (!generic_context_is_sharable (context))
+                       return FALSE;
+
+               g_assert (inflated->declaring);
+
+               if (inflated->declaring->generic_container) {
+                       g_assert 
(inflated->declaring->generic_container->type_params);
+
+                       if 
(inflated->declaring->generic_container->type_params->constraints)
+                               return FALSE;
+               }
+       }
+
+       if (method->klass->generic_class) {
+               if (!generic_context_is_sharable 
(&method->klass->generic_class->context))
+                       return FALSE;
+
+               g_assert (method->klass->generic_class->container_class &&
+                               
method->klass->generic_class->container_class->generic_container &&
+                               
method->klass->generic_class->container_class->generic_container->type_params);
+
+               if 
(method->klass->generic_class->container_class->generic_container->type_params->constraints)
+                       return FALSE;
+       }
+
+       return TRUE;
+}
+
+static MonoGenericInst*
+share_generic_inst (MonoCompile *cfg, MonoGenericInst *inst)
+{
+       MonoType **type_argv;
+       int i;
+
+       if (!inst)
+               return NULL;
+
+       type_argv = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoType*) * 
inst->type_argc);
+
+       for (i = 0; i < inst->type_argc; ++i)
+               type_argv [i] = &mono_defaults.object_class->byval_arg;
+
+       return mono_metadata_get_generic_inst (inst->type_argc, type_argv);
+}
+
+MonoGenericContext*
+mono_make_shared_context (MonoCompile *cfg, MonoGenericContext *context)
+{
+       MonoGenericContext *shared = mono_mempool_alloc0 (cfg->mempool, sizeof 
(MonoGenericContext));
+
+       shared->class_inst = share_generic_inst (cfg, context->class_inst);
+       shared->method_inst = share_generic_inst (cfg, context->method_inst);
+
+       return shared;
+}

Modified: trunk/mono/mono/mini/mini.c
===================================================================
--- trunk/mono/mono/mini/mini.c 2007-09-20 15:25:36 UTC (rev 86065)
+++ trunk/mono/mono/mini/mini.c 2007-09-20 15:36:56 UTC (rev 86066)
@@ -108,6 +108,13 @@
                g_free (field_fname);   \
                goto exception_exit;    \
        } while (0)
+#define GENERIC_SHARING_FAILURE do {   \
+               if (cfg->generic_shared) {      \
+                       /* g_print ("sharing failed for method %s.%s in 
%s:%d\n", method->klass->name, method->name, __FILE__, __LINE__); */ \
+                       cfg->exception_type = 
MONO_EXCEPTION_GENERIC_SHARING_FAILED;    \
+                       goto exception_exit;    \
+               }                       \
+       } while (0)
 
 /* 
  * this is used to determine when some branch optimizations are possible: we 
exclude FP compares
@@ -135,7 +142,7 @@
 
 static int mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, 
MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
                   int locals_offset, MonoInst *return_var, GList *dont_inline, 
MonoInst **inline_args, 
-                  guint inline_offset, gboolean is_virtual_call);
+                  guint inline_offset, gboolean is_virtual_call, 
MonoGenericContext *shared_context);
 
 /* helper methods signature */
 static MonoMethodSignature *helper_sig_class_init_trampoline = NULL;
@@ -3508,7 +3515,7 @@
 
 static int
 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature 
*fsig, MonoBasicBlock *bblock, MonoInst **sp,
-               guchar *ip, guint real_offset, GList *dont_inline, 
MonoBasicBlock **last_b, gboolean inline_allways)
+               guchar *ip, guint real_offset, GList *dont_inline, 
MonoBasicBlock **last_b, gboolean inline_allways, MonoGenericContext 
*shared_context)
 {
        MonoInst *ins, *rvar = NULL;
        MonoMethodHeader *cheader;
@@ -3566,7 +3573,7 @@
        prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
        prev_cil_start = cfg->cil_start;
 
-       costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, 
new_locals_offset, rvar, dont_inline, sp, real_offset, *ip == CEE_CALLVIRT);
+       costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, 
new_locals_offset, rvar, dont_inline, sp, real_offset, *ip == CEE_CALLVIRT, 
shared_context);
 
        cfg->inlined_method = prev_inlined_method;
        cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
@@ -3985,7 +3992,7 @@
 static int
 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock 
*start_bblock, MonoBasicBlock *end_bblock, 
                   int locals_offset, MonoInst *return_var, GList *dont_inline, 
MonoInst **inline_args, 
-                  guint inline_offset, gboolean is_virtual_call)
+                  guint inline_offset, gboolean is_virtual_call, 
MonoGenericContext *shared_context)
 {
        MonoInst *zero_int32, *zero_int64, *zero_ptr, *zero_obj, *zero_r8;
        MonoInst *ins, **sp, **stack_start;
@@ -4044,7 +4051,10 @@
        end = ip + header->code_size;
        mono_jit_stats.cil_code_size += header->code_size;
 
-       if (sig->is_inflated)
+       if (cfg->generic_shared) {
+               g_assert (shared_context);
+               generic_context = shared_context;
+       } else if (sig->is_inflated)
                generic_context = mono_method_get_context (method);
        else if (generic_container)
                generic_context = &generic_container->context;
@@ -4684,6 +4694,9 @@
                        if (!cmethod)
                                goto load_error;
 
+                       if (cfg->generic_shared && 
mono_method_check_context_used (cmethod, generic_context))
+                               GENERIC_SHARING_FAILURE;
+
                        if (mono_security_get_mode () == 
MONO_SECURITY_MODE_CAS) {
                                if (check_linkdemand (cfg, method, cmethod, 
bblock, ip))
                                        INLINE_FAILURE;
@@ -4780,6 +4793,9 @@
                        if (cmethod && cmethod->klass->generic_container)
                                UNVERIFIED;
 
+                       if (cfg->generic_shared && cmethod && 
mono_method_check_context_used (cmethod, generic_context))
+                               GENERIC_SHARING_FAILURE;
+
                        CHECK_STACK (n);
 
                        //g_assert (!virtual || fsig->hasthis);
@@ -4953,7 +4969,7 @@
                                        allways = TRUE;
                                }
 
-                               if ((costs = inline_method (cfg, cmethod, fsig, 
bblock, sp, ip, real_offset, dont_inline, &ebblock, allways))) {
+                               if ((costs = inline_method (cfg, cmethod, fsig, 
bblock, sp, ip, real_offset, dont_inline, &ebblock, allways, shared_context))) {
                                        ip += 5;
                                        real_offset += 5;
 
@@ -5743,7 +5759,7 @@
                        MonoInst *iargs [2];
                        MonoMethodSignature *fsig;
                        int temp;
-                       
+
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
                        cmethod = mini_get_method (method, token, NULL, 
generic_context);
@@ -5756,6 +5772,9 @@
                        if (!mono_class_init (cmethod->klass))
                                goto load_error;
 
+                       if (cfg->generic_shared && 
mono_method_check_context_used (cmethod, generic_context))
+                               GENERIC_SHARING_FAILURE;
+
                        if (mono_security_get_mode () == 
MONO_SECURITY_MODE_CAS) {
                                if (check_linkdemand (cfg, method, cmethod, 
bblock, ip))
                                        INLINE_FAILURE;
@@ -5816,7 +5835,7 @@
                                    !g_list_find (dont_inline, cmethod)) {
                                        int costs;
                                        MonoBasicBlock *ebblock;
-                                       if ((costs = inline_method (cfg, 
cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock, FALSE))) {
+                                       if ((costs = inline_method (cfg, 
cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock, FALSE, 
shared_context))) {
 
                                                ip += 5;
                                                real_offset += 5;
@@ -5865,6 +5884,9 @@
                        if (sp [0]->type != STACK_OBJ)
                                UNVERIFIED;
 
+                       if (cfg->generic_shared && 
mono_class_check_context_used (klass, generic_context))
+                               GENERIC_SHARING_FAILURE;
+
                        /* Needed by the code generated in inssel.brg */
                        mono_get_got_var (cfg);
 
@@ -5880,7 +5902,7 @@
                                iargs [0] = sp [0];
                                
                                costs = inline_method (cfg, mono_isinst, 
mono_method_signature (mono_isinst), bblock, 
-                                                          iargs, ip, 
real_offset, dont_inline, &ebblock, TRUE);
+                                                      iargs, ip, real_offset, 
dont_inline, &ebblock, TRUE, shared_context);
                        
                                g_assert (costs > 0);
                                
@@ -5920,6 +5942,9 @@
                        klass = mini_get_class (method, token, generic_context);
                        CHECK_TYPELOAD (klass);
 
+                       if (cfg->generic_shared && 
mono_class_check_context_used (klass, generic_context))
+                               GENERIC_SHARING_FAILURE;
+
                        if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
                                /* CASTCLASS */
                                if (klass->marshalbyref || klass->flags & 
TYPE_ATTRIBUTE_INTERFACE) {
@@ -5933,7 +5958,7 @@
                                        iargs [0] = sp [0];
                                        
                                        costs = inline_method (cfg, 
mono_castclass, mono_method_signature (mono_castclass), bblock, 
-                                                                  iargs, ip, 
real_offset, dont_inline, &ebblock, TRUE);
+                                                       iargs, ip, real_offset, 
dont_inline, &ebblock, TRUE, shared_context);
                                
                                        g_assert (costs > 0);
                                        
@@ -6017,6 +6042,9 @@
                        klass = mini_get_class (method, token, generic_context);
                        CHECK_TYPELOAD (klass);
 
+                       if (cfg->generic_shared && 
mono_class_check_context_used (klass, generic_context))
+                               GENERIC_SHARING_FAILURE;
+
                        if (mono_class_is_nullable (klass)) {
                                int v = handle_unbox_nullable (cfg, bblock, 
*sp, ip, klass);
                                NEW_TEMPLOAD (cfg, *sp, v);
@@ -6056,6 +6084,9 @@
                        if (sp [0]->type != STACK_OBJ)
                                UNVERIFIED;
 
+                       if (cfg->generic_shared && 
mono_class_check_context_used (klass, generic_context))
+                               GENERIC_SHARING_FAILURE;
+
                        /* Needed by the code generated in inssel.brg */
                        mono_get_got_var (cfg);
                
@@ -6071,7 +6102,7 @@
                                iargs [0] = sp [0];
                                
                                costs = inline_method (cfg, mono_castclass, 
mono_method_signature (mono_castclass), bblock, 
-                                                          iargs, ip, 
real_offset, dont_inline, &ebblock, TRUE);
+                                               iargs, ip, real_offset, 
dont_inline, &ebblock, TRUE, shared_context);
                        
                                g_assert (costs > 0);
                                
@@ -6167,7 +6198,7 @@
 
                                        if (cfg->opt & MONO_OPT_INLINE) {
                                                costs = inline_method (cfg, 
stfld_wrapper, mono_method_signature (stfld_wrapper), bblock, 
-                                                                      iargs, 
ip, real_offset, dont_inline, &ebblock, TRUE);
+                                                               iargs, ip, 
real_offset, dont_inline, &ebblock, TRUE, shared_context);
                                                g_assert (costs > 0);
                                                      
                                                ip += 5;
@@ -6247,7 +6278,7 @@
                                        NEW_ICONST (cfg, iargs [3], 
klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
                                        if ((cfg->opt & MONO_OPT_INLINE) && 
!MONO_TYPE_ISSTRUCT (mono_method_signature (wrapper)->ret)) {
                                                costs = inline_method (cfg, 
wrapper, mono_method_signature (wrapper), bblock, 
-                                                                      iargs, 
ip, real_offset, dont_inline, &ebblock, TRUE);
+                                                               iargs, ip, 
real_offset, dont_inline, &ebblock, TRUE, shared_context);
                                                g_assert (costs > 0);
                                                      
                                                ip += 5;
@@ -6327,6 +6358,9 @@
                        if (!dont_verify && !cfg->skip_visibility && 
!mono_method_can_access_field (method, field))
                                FIELD_ACCESS_FAILURE;
 
+                       if (cfg->generic_shared && 
mono_class_check_context_used (klass, generic_context))
+                               GENERIC_SHARING_FAILURE;
+
                        g_assert (!(field->type->attrs & 
FIELD_ATTRIBUTE_LITERAL));
 
                        if ((*ip) == CEE_STSFLD)
@@ -6532,6 +6566,7 @@
                        break;
                case CEE_BOX: {
                        MonoInst *val;
+
                        CHECK_STACK (1);
                        --sp;
                        val = *sp;
@@ -6540,6 +6575,9 @@
                        klass = mini_get_class (method, token, generic_context);
                        CHECK_TYPELOAD (klass);
 
+                       if (cfg->generic_shared && 
mono_class_check_context_used (klass, generic_context))
+                               GENERIC_SHARING_FAILURE;
+
                        if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
                                *sp++ = val;
                                ip += 5;
@@ -6591,7 +6629,9 @@
                        inline_costs += 1;
                        break;
                }
-               case CEE_NEWARR:
+               case CEE_NEWARR: {
+                       int context_used;
+
                        CHECK_STACK (1);
                        MONO_INST_NEW (cfg, ins, *ip);
                        ins->cil_code = ip;
@@ -6612,6 +6652,15 @@
 
                        klass = mini_get_class (method, token, generic_context);
                        CHECK_TYPELOAD (klass);
+
+                       if (cfg->generic_shared)
+                               context_used = mono_class_check_context_used 
(klass, generic_context);
+                       else
+                               context_used = 0;
+
+                       if (context_used)
+                               GENERIC_SHARING_FAILURE;
+
                        ins->inst_newa_class = klass;
                        ins->inst_newa_len = *sp;
                        ins->type = STACK_OBJ;
@@ -6664,6 +6713,7 @@
                        }
                        inline_costs += 1;
                        break;
+               }
                case CEE_LDLEN:
                        CHECK_STACK (1);
                        --sp;
@@ -6956,6 +7006,9 @@
                        mono_class_init (klass);
                        ins->cil_code = ip;
 
+                       if (cfg->generic_shared && 
mono_class_check_context_used (klass, generic_context))
+                               GENERIC_SHARING_FAILURE;
+
                        loc = mono_compile_create_var (cfg, 
&mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
                        NEW_TEMPLOADA (cfg, ins->inst_right, loc->inst_c0);
 
@@ -6986,6 +7039,9 @@
                        }
                        else {
                                handle = mono_ldtoken (image, n, &handle_class, 
generic_context);
+                               if (cfg->generic_shared &&
+                                               mono_class_check_context_used 
(handle_class, generic_context))
+                                       GENERIC_SHARING_FAILURE;
                        }
                        if (!handle)
                                goto load_error;
@@ -6995,6 +7051,8 @@
                                int temp;
                                MonoInst *res, *store, *addr, *vtvar, *iargs 
[3];
 
+                               GENERIC_SHARING_FAILURE;
+
                                vtvar = mono_compile_create_var (cfg, 
&handle_class->byval_arg, OP_LOCAL); 
 
                                NEW_IMAGECONST (cfg, iargs [0], image);
@@ -7434,6 +7492,9 @@
                                        goto load_error;
                                mono_class_init (cmethod->klass);
 
+                               if (cfg->generic_shared && 
mono_method_check_context_used (cmethod, generic_context))
+                                       GENERIC_SHARING_FAILURE;
+
                                cil_method = cmethod;
                                if (!dont_verify && !cfg->skip_visibility && 
!mono_method_can_access_method (method, cmethod))
                                        METHOD_ACCESS_FAILURE;
@@ -7471,6 +7532,9 @@
                                        goto load_error;
                                mono_class_init (cmethod->klass);
 
+                               if (cfg->generic_shared && 
mono_method_check_context_used (cmethod, generic_context))
+                                       GENERIC_SHARING_FAILURE;
+
                                if (mono_security_get_mode () == 
MONO_SECURITY_MODE_CAS) {
                                        if (check_linkdemand (cfg, method, 
cmethod, bblock, ip))
                                                INLINE_FAILURE;
@@ -7654,6 +7718,10 @@
                                token = read32 (ip + 2);
                                klass = mini_get_class (method, token, 
generic_context);
                                CHECK_TYPELOAD (klass);
+
+                               if (cfg->generic_shared && 
mono_class_check_context_used (klass, generic_context))
+                                       GENERIC_SHARING_FAILURE;
+
                                if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) 
{
                                        MonoInst *store, *load;
                                        NEW_PCONST (cfg, load, NULL);
@@ -7745,6 +7813,8 @@
                                break;
                        }
                        case CEE_SIZEOF:
+                               GENERIC_SHARING_FAILURE;
+
                                CHECK_STACK_OVF (1);
                                CHECK_OPSIZE (6);
                                token = read32 (ip + 2);
@@ -10534,11 +10604,21 @@
        MonoJitInfo *jinfo;
        int dfn = 0, i, code_size_ratio;
        gboolean deadce_has_run = FALSE;
+       gboolean try_generic_shared = (opts & MONO_OPT_GSHARED) && 
mono_method_is_generic_sharable_impl (method);
+       MonoGenericContext *shared_context;
 
        mono_jit_stats.methods_compiled++;
        if (mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)
                mono_profiler_method_jit (method);
 
+       if (opts & MONO_OPT_GSHARED) {
+               if (try_generic_shared)
+                       mono_stats.generics_sharable_methods++;
+               else if (mono_method_is_generic_impl (method))
+                       mono_stats.generics_unsharable_methods++;
+       }
+
+ restart_compile:
        cfg = g_new0 (MonoCompile, 1);
        cfg->method = method;
        cfg->mempool = mono_mempool_new ();
@@ -10549,6 +10629,7 @@
        cfg->verbose_level = mini_verbose;
        cfg->compile_aot = compile_aot;
        cfg->skip_visibility = method->skip_visibility;
+       cfg->generic_shared = try_generic_shared;
        cfg->token_info_hash = g_hash_table_new (NULL, NULL);
        if (!header) {
                cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
@@ -10571,7 +10652,19 @@
         */
        mono_compile_create_vars (cfg);
 
-       if ((i = mono_method_to_ir (cfg, method, NULL, NULL, cfg->locals_start, 
NULL, NULL, NULL, 0, FALSE)) < 0) {
+       if (try_generic_shared)
+               shared_context = mono_make_shared_context (cfg, 
mono_method_get_context (method));
+       else
+               shared_context = NULL;
+
+       if ((i = mono_method_to_ir (cfg, method, NULL, NULL, cfg->locals_start, 
NULL, NULL, NULL, 0, FALSE, shared_context)) < 0) {
+               if (try_generic_shared && cfg->exception_type == 
MONO_EXCEPTION_GENERIC_SHARING_FAILED) {
+                       mono_destroy_compile (cfg);
+                       try_generic_shared = FALSE;
+                       goto restart_compile;
+               }
+               g_assert (cfg->exception_type != 
MONO_EXCEPTION_GENERIC_SHARING_FAILED);
+
                if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
                        mono_profiler_method_end_jit (method, NULL, 
MONO_PROFILE_FAILED);
                /* cfg contains the details of the failure, so let the caller 
cleanup */
@@ -10802,6 +10895,7 @@
        jinfo->used_regs = cfg->used_int_regs;
        jinfo->domain_neutral = (cfg->opt & MONO_OPT_SHARED) != 0;
        jinfo->cas_inited = FALSE; /* initialization delayed at the first stalk 
walk using this method */
+       jinfo->generic_shared = cfg->generic_shared;
 
        if (header->num_clauses) {
                int i;
@@ -10873,6 +10967,42 @@
        return cfg;
 }
 
+static MonoMethod*
+method_get_declaring_generic_method (MonoMethod *method)
+{
+       MonoMethodInflated *inflated;
+
+       g_assert (method->is_inflated);
+
+       inflated = (MonoMethodInflated*)method;
+
+       return inflated->declaring;
+}
+
+static MonoJitInfo*
+lookup_generic_method (MonoDomain *domain, MonoMethod *method)
+{
+       MonoMethod *open_method;
+
+       if (!mono_method_is_generic_sharable_impl (method))
+               return NULL;
+
+       open_method = method_get_declaring_generic_method (method);
+
+       return mono_domain_lookup_shared_generic (domain, open_method);
+}
+
+static MonoJitInfo*
+lookup_method (MonoDomain *domain, MonoMethod *method)
+{
+       MonoJitInfo *ji = mono_internal_hash_table_lookup 
(&domain->jit_code_hash, method);
+
+       if (ji != NULL)
+               return ji;
+
+       return lookup_generic_method (domain, method);
+}
+
 static gpointer
 mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, 
int opt)
 {
@@ -11022,7 +11152,7 @@
        /* Check if some other thread already did the job. In this case, we can
        discard the code this thread generated. */
 
-       if ((info = mono_internal_hash_table_lookup 
(&target_domain->jit_code_hash, method))) {
+       if ((info = lookup_method (target_domain, method))) {
                /* We can't use a domain specific method in another domain */
                if ((target_domain == mono_domain_get ()) || 
info->domain_neutral) {
                        code = info->code_start;
@@ -11033,6 +11163,13 @@
        if (code == NULL) {
                mono_internal_hash_table_insert (&target_domain->jit_code_hash, 
method, cfg->jit_info);
                code = cfg->native_code;
+
+               if (cfg->generic_shared && mono_method_is_generic_sharable_impl 
(method)) {
+                       /* g_print ("inserting method %s.%s.%s\n", 
method->klass->name_space, method->klass->name, method->name); */
+                       mono_domain_register_shared_generic (target_domain, 
+                               method_get_declaring_generic_method (method), 
cfg->jit_info);
+                       mono_stats.generics_shared_methods++;
+               }
        }
 
        mono_destroy_compile (cfg);
@@ -11090,7 +11227,7 @@
 
        mono_domain_lock (target_domain);
 
-       if ((info = mono_internal_hash_table_lookup 
(&target_domain->jit_code_hash, method))) {
+       if ((info = lookup_method (target_domain, method))) {
                /* We can't use a domain specific method in another domain */
                if (! ((domain != target_domain) && !info->domain_neutral)) {
                        mono_domain_unlock (target_domain);
@@ -11196,7 +11333,7 @@
 
        mono_domain_lock (target_domain);
 
-       if ((info = mono_internal_hash_table_lookup 
(&target_domain->jit_code_hash, method))) {
+       if ((info = lookup_method (target_domain, method))) {
                /* We can't use a domain specific method in another domain */
                if (! ((domain != target_domain) && !info->domain_neutral)) {
                        mono_domain_unlock (target_domain);
@@ -12224,6 +12361,10 @@
                g_print ("Generics metadata size: %ld\n", 
mono_stats.generics_metadata_size);
                g_print ("Generics virtual invokes: %ld\n", 
mono_jit_stats.generic_virtual_invocations);
 
+               g_print ("Sharable generic methods: %ld\n", 
mono_stats.generics_sharable_methods);
+               g_print ("Unsharable generic methods: %ld\n", 
mono_stats.generics_unsharable_methods);
+               g_print ("Shared generic methods: %ld\n", 
mono_stats.generics_shared_methods);
+
                g_print ("Dynamic code allocs:    %ld\n", 
mono_stats.dynamic_code_alloc_count);
                g_print ("Dynamic code bytes:     %ld\n", 
mono_stats.dynamic_code_bytes_count);
                g_print ("Dynamic code frees:     %ld\n", 
mono_stats.dynamic_code_frees_count);

Modified: trunk/mono/mono/mini/mini.h
===================================================================
--- trunk/mono/mono/mini/mini.h 2007-09-20 15:25:36 UTC (rev 86065)
+++ trunk/mono/mono/mini/mini.h 2007-09-20 15:36:56 UTC (rev 86066)
@@ -608,6 +608,7 @@
        guint            dont_verify_stack_merge : 1;
        guint            unverifiable : 1;
        guint            skip_visibility : 1;
+       guint            generic_shared : 1;
        gpointer         debug_info;
        guint32          lmf_offset;
        guint16          *intvars;
@@ -828,6 +829,16 @@
        MONO_EXC_INTRINS_NUM
 };
 
+/*
+ * Flags for which contexts were used in inflating a generic.
+ */
+enum {
+       MONO_GENERIC_CONTEXT_USED_CLASS = 1,
+       MONO_GENERIC_CONTEXT_USED_METHOD = 2
+};
+
+#define MONO_GENERIC_CONTEXT_USED_BOTH         
(MONO_GENERIC_CONTEXT_USED_CLASS | MONO_GENERIC_CONTEXT_USED_METHOD)
+
 typedef void (*MonoInstFunc) (MonoInst *tree, gpointer data);
 
 /* main function */
@@ -1101,4 +1112,15 @@
 int mini_wapi_semdel  (int argc, char **argv);
 int mini_wapi_seminfo (int argc, char **argv);
 
+/* Generic sharing */
+
+int mono_method_check_context_used (MonoMethod *method, MonoGenericContext 
*context) MONO_INTERNAL;
+int mono_class_check_context_used (MonoClass *class, MonoGenericContext 
*context) MONO_INTERNAL;
+
+gboolean mono_method_is_generic_impl (MonoMethod *method) MONO_INTERNAL;
+gboolean mono_method_is_generic_sharable_impl (MonoMethod *method) 
MONO_INTERNAL;
+
+MonoGenericContext* mono_make_shared_context (MonoCompile *cfg, 
MonoGenericContext *context) MONO_INTERNAL;
+
+
 #endif /* __MONO_MINI_H__ */

Modified: trunk/mono/mono/mini/optflags-def.h
===================================================================
--- trunk/mono/mono/mini/optflags-def.h 2007-09-20 15:25:36 UTC (rev 86065)
+++ trunk/mono/mono/mini/optflags-def.h 2007-09-20 15:36:56 UTC (rev 86066)
@@ -22,3 +22,4 @@
 OPTFLAG(SSA      ,21, "ssa",        "Use plain SSA form")
 OPTFLAG(TREEPROP ,22, "treeprop",   "Tree propagation")
 OPTFLAG(SSE2     ,23, "sse2",       "SSE2 instructions on x86")
+OPTFLAG(GSHARED  ,24, "gshared",    "Share generics")

Modified: trunk/mono/mono/tests/ChangeLog
===================================================================
--- trunk/mono/mono/tests/ChangeLog     2007-09-20 15:25:36 UTC (rev 86065)
+++ trunk/mono/mono/tests/ChangeLog     2007-09-20 15:36:56 UTC (rev 86066)
@@ -1,3 +1,9 @@
+2007-09-20  Mark Probst  <[EMAIL PROTECTED]>
+
+       * generics-sharing.2.cs: added
+
+       * Makefile.am: added generics-sharing.2.cs
+
 2007-09-19  Marek Habersack  <[EMAIL PROTECTED]>
 
        * assemblyresolve/Makefile.am (prereq): build the assemblies in

Modified: trunk/mono/mono/tests/Makefile.am
===================================================================
--- trunk/mono/mono/tests/Makefile.am   2007-09-20 15:25:36 UTC (rev 86065)
+++ trunk/mono/mono/tests/Makefile.am   2007-09-20 15:36:56 UTC (rev 86066)
@@ -295,6 +295,7 @@
        module-cctor-loader.2.cs        \
        generics-invoke-byref.2.cs      \
        generic-signature-compare.2.cs  \
+       generics-sharing.2.cs   \
        bug-80392.2.cs          \
        bug-82194.2.cs
 

Added: trunk/mono/mono/tests/generics-sharing.2.cs
===================================================================
--- trunk/mono/mono/tests/generics-sharing.2.cs 2007-09-20 15:25:36 UTC (rev 
86065)
+++ trunk/mono/mono/tests/generics-sharing.2.cs 2007-09-20 15:36:56 UTC (rev 
86066)
@@ -0,0 +1,124 @@
+using System;
+using System.Collections.Generic;
+
+public class ClassA {}
+public class ClassB {}
+public class ClassC {}
+
+public class NonGen {
+       public static int field = 123;
+}
+
+public class GenA<T> {
+       static T[] arr;
+
+       public static GenA () {
+               arr = new T [3];
+       }
+
+       public GenA () {}
+
+       public GenA<T> newGen () {
+               return new GenA<T> ();
+       }
+
+       public GenA<int> newGenInt () {
+               return new GenA<int> ();
+       }
+
+       public int getGenField () {
+               return GenB<ClassA>.field;
+       }
+
+       public int getNonGenField () {
+               return NonGen.field;
+       }
+
+       public T[] getArr () {
+               return arr;
+       }
+
+       public T[] newArr () {
+               return new T [3];
+       }
+
+       public GenB<GenB<T>>[] newArrNested () {
+               /*
+               GenB<GenB<T>>[] arr = null;
+               for (int i = 0; i < 10000000; ++i)
+                       arr = new GenB<GenB<T>> [3];
+               */
+               return new GenB<GenB<T>> [3];
+       }
+
+       public int hash (T obj) {
+               return obj.GetHashCode ();
+       }
+
+       public T ident (T obj) {
+               return obj;
+       }
+
+       public T cast (Object obj) {
+               return (T)obj;
+       }
+}
+
+public class GenB<T> {
+       public static int field = 345;
+}
+
+public class main {
+       static bool haveError = false;
+
+       public static void error (string message) {
+               haveError = true;
+               Console.WriteLine (message);
+       }
+
+       public static void typeCheck (String method, Object obj, Type t) {
+               if (obj.GetType () != t)
+                       error ("object from " + method + " should have type " + 
t.ToString () + " but has type " + obj.GetType ().ToString ());
+       }
+
+       public static void work<T> (T obj) {
+               EqualityComparer<T> comp = EqualityComparer<T>.Default;
+
+               GenA<T> ga = new GenA<T> ();
+
+               typeCheck ("newGen", ga.newGen (), typeof (GenA<T>));
+               typeCheck ("newGenInt", ga.newGenInt (), typeof (GenA<int>));
+               typeCheck ("getArr", ga.getArr (), typeof (T[]));
+               typeCheck ("newArr", ga.newArr (), typeof (T[]));
+               //ga.newArrNested ();
+               typeCheck ("newArrNested", ga.newArrNested (), typeof 
(GenB<GenB<T>>[]));
+
+               if (ga.getGenField () != 345)
+                       error ("getGenField");
+
+               if (ga.getNonGenField () != 123)
+                       error ("getNonGenField");
+
+               ga.hash (obj);
+
+               if (!comp.Equals (ga.ident (obj), obj))
+                       error ("ident");
+
+               if (!comp.Equals (ga.cast (obj), obj))
+                       error ("cast");
+       }
+
+       public static int Main ()
+       {
+               work<ClassA> (new ClassA ());
+               work<ClassB> (new ClassB ());
+               work<ClassC> (new ClassC ());
+               work<GenA<ClassA>> (new GenA<ClassA> ());
+               work<int[]> (new int[3]);
+               work<int> (123);
+
+               if (haveError)
+                       return 1;
+               return 0;
+       }
+}

_______________________________________________
Mono-patches maillist  -  [email protected]
http://lists.ximian.com/mailman/listinfo/mono-patches

Reply via email to