2008-08-23 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / generic-sharing.c
index dc1f7423675da2e97b7909665b876f06cc738cbe..62b550e6a2ad79a06ba0424620ac798711cd0e6d 100644 (file)
 
 #include "mini.h"
 
-static int generic_class_lookups = 0;
-static int generic_class_lookup_failures = 0;
+/*
+ * mono_get_generic_context_from_code:
+ *
+ *   Return the runtime generic context belonging to the method whose native code
+ * contains CODE.
+ */
+MonoGenericSharingContext*
+mono_get_generic_context_from_code (guint8 *code)
+{
+       MonoJitInfo *jit_info = mono_jit_info_table_find (mono_domain_get (), (char*)code);
+
+       g_assert (jit_info);
+
+       return mono_jit_info_get_generic_sharing_context (jit_info);
+}
 
 /*
  * mini_method_get_context:
@@ -31,8 +44,8 @@ mini_method_get_context (MonoMethod *method)
 {
        if (method->is_inflated)
                return mono_method_get_context (method);
-       if (method->generic_container)
-               return &method->generic_container->context;
+       if (method->is_generic)
+               return &(mono_method_get_generic_container (method)->context);
        if (method->klass->generic_container)
                return &method->klass->generic_container->context;
        return NULL;
@@ -51,11 +64,15 @@ int
 mono_method_check_context_used (MonoMethod *method)
 {
        MonoGenericContext *method_context = mini_method_get_context (method);
+       int context_used;
 
        if (!method_context)
                return 0;
 
-       return mono_generic_context_check_used (method_context);
+       context_used = mono_generic_context_check_used (method_context);
+       context_used |= mono_class_check_context_used (method->klass);
+
+       return context_used;
 }
 
 static gboolean
@@ -105,25 +122,38 @@ mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_ty
  * mono_method_is_generic_impl:
  * @method: a method
  *
- * Returns whether the method is either inflated or part of an
- * inflated class.
+ * Returns whether the method is either generic or part of a generic
+ * class.
  */
 gboolean
 mono_method_is_generic_impl (MonoMethod *method)
 {
-       return method->klass->generic_class != NULL && method->is_inflated;
+       if (method->is_inflated) {
+               g_assert (method->wrapper_type == MONO_WRAPPER_NONE);
+               return TRUE;
+       }
+       /* We don't treat wrappers as generic code, i.e., we never
+          apply generic sharing to them.  This is especially
+          important for static rgctx invoke wrappers, which only work
+          if not compiled with sharing. */
+       if (method->wrapper_type != MONO_WRAPPER_NONE)
+               return FALSE;
+       if (method->klass->generic_container)
+               return TRUE;
+       return FALSE;
 }
 
 /*
  * mono_method_is_generic_sharable_impl:
  * @method: a method
+ * @allow_type_vars: whether to regard type variables as reference types
  *
  * Returns TRUE iff the method is inflated or part of an inflated
  * class, its context is sharable and it has no constraints on its
  * type parameters.  Otherwise returns FALSE.
  */
 gboolean
-mono_method_is_generic_sharable_impl (MonoMethod *method)
+mono_method_is_generic_sharable_impl (MonoMethod *method, gboolean allow_type_vars)
 {
        if (!mono_method_is_generic_impl (method))
                return FALSE;
@@ -132,21 +162,21 @@ mono_method_is_generic_sharable_impl (MonoMethod *method)
                MonoMethodInflated *inflated = (MonoMethodInflated*)method;
                MonoGenericContext *context = &inflated->context;
 
-               if (!mono_generic_context_is_sharable (context, FALSE))
+               if (!mono_generic_context_is_sharable (context, allow_type_vars))
                        return FALSE;
 
                g_assert (inflated->declaring);
 
-               if (inflated->declaring->generic_container) {
-                       g_assert (inflated->declaring->generic_container->type_params);
+               if (inflated->declaring->is_generic) {
+                       g_assert (mono_method_get_generic_container (inflated->declaring)->type_params);
 
-                       if (inflated->declaring->generic_container->type_params->constraints)
+                       if (mono_method_get_generic_container (inflated->declaring)->type_params->constraints)
                                return FALSE;
                }
        }
 
        if (method->klass->generic_class) {
-               if (!mono_generic_context_is_sharable (&method->klass->generic_class->context, FALSE))
+               if (!mono_generic_context_is_sharable (&method->klass->generic_class->context, allow_type_vars))
                        return FALSE;
 
                g_assert (method->klass->generic_class->container_class &&
@@ -157,6 +187,9 @@ mono_method_is_generic_sharable_impl (MonoMethod *method)
                        return FALSE;
        }
 
+       if (method->klass->generic_container && !allow_type_vars)
+               return FALSE;
+
        return TRUE;
 }
 
@@ -247,6 +280,18 @@ mini_get_basic_type_from_generic (MonoGenericSharingContext *gsctx, MonoType *ty
        return mono_type_get_basic_type_from_generic (type);
 }
 
+/*
+ * mini_type_get_underlying_type:
+ *
+ *   Return the underlying type of TYPE, taking into account enums and generic
+ * sharing.
+ */
+MonoType*
+mini_type_get_underlying_type (MonoGenericSharingContext *gsctx, MonoType *type)
+{
+       return mono_type_get_basic_type_from_generic (mono_type_get_underlying_type (type));
+}
+
 /*
  * mini_type_stack_size:
  * @gsctx: a generic sharing context
@@ -263,221 +308,29 @@ mini_type_stack_size (MonoGenericSharingContext *gsctx, MonoType *t, int *align)
 }
 
 /*
- * mono_method_get_declaring_generic_method:
- * @method: an inflated method
+ * mini_type_stack_size_full:
  *
- * Returns an inflated method's declaring method.
- */
-MonoMethod*
-mono_method_get_declaring_generic_method (MonoMethod *method)
-{
-       MonoMethodInflated *inflated;
-
-       g_assert (method->is_inflated);
-
-       inflated = (MonoMethodInflated*)method;
-
-       return inflated->declaring;
-}
-
-static gboolean
-inflated_type_is_equal_to_class (MonoType *inflated_type, MonoClass *klass)
-{
-       return klass == mono_class_from_mono_type (inflated_type);
-}
-
-/*
- * mono_class_generic_class_relation:
- * @klass: the class to be investigated
- * @method_klass: the reference class
- * @generic_context: the generic context of method_klass
- * @arg_num: where a value will be returned
- *
- * Discovers and returns the relation of klass with reference to
- * method_klass.  This can either be MINI_GENERIC_CLASS_RELATION_SELF,
- * meaning that klass is the same as method_klass,
- * MINI_GENERIC_CLASS_RELATION_ARGUMENT, meaning that klass is one of
- * the type arguments of method_klass, or otherwise
- * MINI_GENERIC_CLASS_RELATION_OTHER.  In the case of
- * MINI_GENERIC_CLASS_RELATION_ARGUMENT the number of the argument is
- * returned in *arg_num.
+ *   Same as mini_type_stack_size, but handle pinvoke data types as well.
  */
 int
-mono_class_generic_class_relation (MonoClass *klass, int info_type, MonoClass *method_klass,
-       MonoGenericContext *generic_context, int *arg_num)
+mini_type_stack_size_full (MonoGenericSharingContext *gsctx, MonoType *t, guint32 *align, gboolean pinvoke)
 {
-       MonoRuntimeGenericContextTemplate *rgctx_template =
-               mono_class_get_runtime_generic_context_template (method_klass);
-       int i;
-
-       /* Reflection types can only be handled in the extensible
-          rgctx part. */
-       if (info_type != MONO_RGCTX_INFO_REFLECTION_TYPE) {
-               for (i = 0; i < rgctx_template->num_arg_infos; ++i) {
-                       MonoType *arg_info = rgctx_template->arg_infos [i];
-                       MonoType *inflated_arg;
+       int size;
 
-                       if (arg_info == NULL)
-                               continue;
-
-                       inflated_arg = mono_class_inflate_generic_type(arg_info, generic_context);
-
-                       if (inflated_type_is_equal_to_class (inflated_arg, klass)) {
-                               if (arg_num)
-                                       *arg_num = i;
-                               return MINI_GENERIC_CLASS_RELATION_ARGUMENT;
-                       }
-               }
-
-               if (!klass->generic_class && !klass->generic_container)
-                       g_assert_not_reached ();
-
-               if (mini_class_get_container_class (klass) == mini_class_get_container_class (method_klass) &&
-                               mono_generic_context_equal_deep (mini_class_get_context (klass), generic_context))
-                       return MINI_GENERIC_CLASS_RELATION_SELF;
-       }
-
-       i = mono_class_lookup_or_register_other_info (method_klass, &klass->byval_arg, info_type, generic_context);
-       if (arg_num)
-               *arg_num = i;
-       return MINI_GENERIC_CLASS_RELATION_OTHER_TABLE;
-}
-
-typedef struct
-{
-       guint32 token;
-       MonoGenericContext *context;
-} MonoTokenAndContext;
-
-static guint
-token_context_hash (MonoTokenAndContext *tc)
-{
-       return (guint)((gulong)tc->token | (gulong)tc->context->class_inst | (gulong)tc->context->method_inst);
-}
-
-static gboolean
-token_context_equal (MonoTokenAndContext *tc1, MonoTokenAndContext *tc2)
-{
-       if (tc1->token != tc2->token)
-               return FALSE;
-
-       return tc1->context->class_inst == tc2->context->class_inst &&
-               tc1->context->method_inst == tc2->context->method_inst;
-}
-
-/*
- * mono_helper_get_rgctx_other_ptr:
- * @caller_class: the klass of the calling method
- * @rgctx: the runtime generic context
- * @token: the token which to look up
- * @token_source: what kind of item the token is for
- * @rgctx_type: the kind of value requested
- *
- * Is called from method to look up a token for a given runtime
- * generic sharing context and return some particular information
- * about the looked up class (the class itself, the vtable or the
- * static_data pointer).
- */
-gpointer
-mono_helper_get_rgctx_other_ptr (MonoClass *caller_class, MonoRuntimeGenericContext *rgctx,
-       guint32 token, guint32 token_source, guint32 rgctx_type, gint32 rgctx_index)
-{
-       MonoImage *image = caller_class->image;
-       int depth = caller_class->idepth;
-       MonoRuntimeGenericSuperInfo *super_info = &((MonoRuntimeGenericSuperInfo*)rgctx)[-depth];
-       MonoClass *klass = super_info->klass;
-       MonoClass *result = NULL;
-       MonoTokenAndContext tc = { token, &klass->generic_class->context };
-       gpointer rgctx_result_ptr, result_ptr;
-
-       mono_loader_lock ();
-
-       generic_class_lookups++;
-
-       if (!image->generic_class_cache) {
-               image->generic_class_cache = g_hash_table_new ((GHashFunc)token_context_hash,
-                       (GCompareFunc)token_context_equal);
-       }
-
-       result = g_hash_table_lookup (image->generic_class_cache, &tc);
-
-       mono_loader_unlock ();
-
-       if (!result) {
-               generic_class_lookup_failures++;
-
-               switch (token_source) {
-               case MINI_TOKEN_SOURCE_FIELD: {
-                       MonoClassField *field = mono_field_from_token (image, token, &result, &klass->generic_class->context);
-
-                       g_assert (field);
-                       break;
-               }
-               case MINI_TOKEN_SOURCE_CLASS:
-                       result = mono_class_get_full (image, token, &klass->generic_class->context);
-                       break;
-               case MINI_TOKEN_SOURCE_METHOD: {
-                       MonoMethod *cmethod = mono_get_method_full (image, token, NULL,
-                               &klass->generic_class->context);
-                       result = cmethod->klass;
-                       break;
-               }
-               default :
-                       g_assert_not_reached ();
-               }
-
-               g_assert (result);
-
-               mono_class_init (result);
-
-               mono_loader_lock ();
-
-               /*
-                * In the meantime another thread might have put this class in
-                * the cache, so check again.
-                */
-               if (!g_hash_table_lookup (image->generic_class_cache, &tc)) {
-                       MonoTokenAndContext *tcp = (MonoTokenAndContext*) mono_mempool_alloc0 (image->mempool,
-                               sizeof (MonoTokenAndContext));
-
-                       *tcp = tc;
-
-                       g_hash_table_insert (image->generic_class_cache, tcp, result);
-               }
-
-               mono_loader_unlock ();
-       }
-
-       g_assert (result);
-
-       switch (rgctx_type) {
-       case MONO_RGCTX_INFO_KLASS:
-               result_ptr = result;
-               break;
-       case MONO_RGCTX_INFO_STATIC_DATA: {
-               MonoVTable *vtable = mono_class_vtable (rgctx->domain, result);
-               result_ptr = vtable->data;
-               break;
-       }
-       case MONO_RGCTX_INFO_VTABLE:
-               result_ptr = mono_class_vtable (rgctx->domain, result);
-               break;
-       default:
-               g_assert_not_reached ();
-       }
-
-       g_assert (rgctx_index >= 0);
-       if (rgctx_index < MONO_RGCTX_MAX_OTHER_INFOS) {
-               rgctx_result_ptr = rgctx->other_infos [rgctx_index];
+       if (pinvoke) {
+               size = mono_type_native_stack_size (t, align);
        } else {
-               g_assert (rgctx->extra_other_infos);
+               int ialign;
 
-               rgctx_result_ptr = rgctx->extra_other_infos [rgctx_index - MONO_RGCTX_MAX_OTHER_INFOS];
+               if (align) {
+                       size = mini_type_stack_size (gsctx, t, &ialign);
+                       *align = ialign;
+               } else {
+                       size = mini_type_stack_size (gsctx, t, NULL);
+               }
        }
-
-       g_assert (rgctx_result_ptr == result);
-
-       return result_ptr;
+       
+       return size;
 }
 
 /*
@@ -488,8 +341,4 @@ mono_helper_get_rgctx_other_ptr (MonoClass *caller_class, MonoRuntimeGenericCont
 void
 mono_generic_sharing_init (void)
 {
-       mono_counters_register ("Generic class lookups", MONO_COUNTER_GENERICS | MONO_COUNTER_INT,
-                       &generic_class_lookups);
-       mono_counters_register ("Generic class lookup failures", MONO_COUNTER_GENERICS | MONO_COUNTER_INT,
-                       &generic_class_lookup_failures);
 }