#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:
{
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;
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
* 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;
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 &&
return FALSE;
}
+ if (method->klass->generic_container && !allow_type_vars)
+ return FALSE;
+
return TRUE;
}
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
}
/*
- * 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;
}
/*
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);
}