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