mono_error_set_type_load_name (error, name, assembly, "Could not resolve type with token %08x", type_token);
}
}
- g_assert (!mono_loader_get_last_error ());
+ mono_loader_assert_no_error ();
return res;
}
g_string_append_c (str, '&');
}
+/**
+ * mono_identifier_escape_type_name_chars:
+ * @str: a destination string
+ * @identifier: an IDENTIFIER in internal form
+ *
+ * Returns: str.
+ *
+ * The displayed form of the identifier is appended to str.
+ *
+ * The displayed form of an identifier has the characters ,+&*[]\
+ * that have special meaning in type names escaped with a preceeding
+ * backslash (\) character.
+ */
+static GString*
+mono_identifier_escape_type_name_chars (GString* str, const char* identifier)
+{
+ if (!identifier)
+ return str;
+
+ size_t n = str->len;
+ // reserve space for common case: there will be no escaped characters.
+ g_string_set_size(str, n + strlen(identifier));
+ g_string_set_size(str, n);
+
+ for (const char* s = identifier; *s != 0 ; s++) {
+ switch (*s) {
+ case ',':
+ case '+':
+ case '&':
+ case '*':
+ case '[':
+ case ']':
+ case '\\':
+ g_string_append_c (str, '\\');
+ g_string_append_c (str, *s);
+ break;
+ default:
+ g_string_append_c (str, *s);
+ break;
+ }
+ }
+ return str;
+}
+
static void
mono_type_get_name_recurse (MonoType *type, GString *str, gboolean is_recursed,
MonoTypeNameFormat format)
else
g_string_append_c (str, '+');
} else if (*klass->name_space) {
- g_string_append (str, klass->name_space);
+ if (format == MONO_TYPE_NAME_FORMAT_IL)
+ g_string_append (str, klass->name_space);
+ else
+ mono_identifier_escape_type_name_chars (str, klass->name_space);
g_string_append_c (str, '.');
}
if (format == MONO_TYPE_NAME_FORMAT_IL) {
char *s = strchr (klass->name, '`');
int len = s ? s - klass->name : strlen (klass->name);
-
g_string_append_len (str, klass->name, len);
- } else
- g_string_append (str, klass->name);
+ } else {
+ mono_identifier_escape_type_name_chars (str, klass->name);
+ }
if (is_recursed)
break;
if (klass->generic_class) {
MonoType *nt;
int num = mono_type_get_generic_param_num (type);
MonoGenericInst *inst = context->method_inst;
- if (!inst || !inst->type_argv)
+ if (!inst)
return NULL;
if (num >= inst->type_argc) {
MonoGenericParamInfo *info = mono_generic_param_info (type->data.generic_param);
MonoMethodInflated *iresult, *cached;
MonoMethodSignature *sig;
MonoGenericContext tmp_context;
- gboolean is_mb_open = FALSE;
mono_error_init (error);
(method->klass->generic_container && context->class_inst)))
return method;
- /*
- * The reason for this hack is to fix the behavior of inflating generic methods that come from a MethodBuilder.
- * What happens is that instantiating a generic MethodBuilder with its own arguments should create a diferent object.
- * This is opposite to the way non-SRE MethodInfos behave.
- *
- * This happens, for example, when we want to emit a recursive generic method. Given the following C# code:
- *
- * void Example<T> () {
- * Example<T> ();
- * }
- *
- * In Example, the method token must be encoded as: "void Example<!!0>()"
- *
- * The reference to the first generic argument, "!!0", must be explicit otherwise it won't be inflated
- * properly. To get that we need to inflate the MethodBuilder with its own arguments.
- *
- * On the other hand, inflating a non-SRE generic method with its own arguments should
- * return itself. For example:
- *
- * MethodInfo m = ... //m is a generic method definition
- * MethodInfo res = m.MakeGenericMethod (m.GetGenericArguments ());
- * res == m
- *
- * To allow such scenarios we must allow inflation of MethodBuilder to happen in a diferent way than
- * what happens with regular methods.
- *
- * There is one last touch to this madness, once a TypeBuilder is finished, IOW CreateType() is called,
- * everything should behave like a regular type or method.
- *
- */
- is_mb_open = method->is_generic &&
- image_is_dynamic (method->klass->image) && !method->klass->wastypebuilder && /* that is a MethodBuilder from an unfinished TypeBuilder */
- context->method_inst == mono_method_get_generic_container (method)->context.method_inst; /* and it's been instantiated with its own arguments. */
-
iresult = g_new0 (MonoMethodInflated, 1);
iresult->context = *context;
iresult->declaring = method;
- iresult->method.method.is_mb_open = is_mb_open;
if (!context->method_inst && method->is_generic)
iresult->context.method_inst = mono_method_get_generic_container (method)->context.method_inst;
if (!iresult->declaring->klass->generic_container && !iresult->declaring->klass->generic_class)
iresult->context.class_inst = NULL;
- cached = mono_method_inflated_lookup (iresult, FALSE);
+ MonoImageSet *set = mono_metadata_get_image_set_for_method (iresult);
+
+ // check cache
+ mono_image_set_lock (set);
+ cached = g_hash_table_lookup (set->gmethod_cache, iresult);
+ mono_image_set_unlock (set);
+
if (cached) {
g_free (iresult);
return (MonoMethod*)cached;
result->is_generic = FALSE;
result->sre_method = FALSE;
result->signature = NULL;
- result->is_mb_open = is_mb_open;
if (!context->method_inst) {
/* Set the generic_container of the result to the generic_container of method */
* is_generic_method_definition().
*/
- return (MonoMethod*)mono_method_inflated_lookup (iresult, TRUE);
+ // check cache
+ mono_image_set_lock (set);
+ cached = g_hash_table_lookup (set->gmethod_cache, iresult);
+ if (!cached) {
+ g_hash_table_insert (set->gmethod_cache, iresult, iresult);
+ iresult->owner = set;
+ cached = iresult;
+ }
+ mono_image_set_unlock (set);
+
+ return (MonoMethod*)cached;
fail:
g_free (iresult);
goto fail;
}
- ftype = mono_metadata_parse_type_full (m, container, MONO_PARSE_FIELD, cols [MONO_FIELD_FLAGS], sig + 1, &sig);
+ ftype = mono_metadata_parse_type_full (m, container, cols [MONO_FIELD_FLAGS], sig + 1, &sig);
if (!ftype) {
if (mono_loader_get_last_error ()) /*FIXME plug the above to not leak errors*/
mono_error_set_from_loader_error (error);
mono_error_set_type_load_class (error, class, "Could not find base type");
fail:
- g_assert (!mono_loader_get_last_error ());
+ mono_loader_assert_no_error ();
return NULL;
}
return;
}
- if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT)
+ if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT && !(mono_is_corlib_image (class->image) && !strcmp (class->name_space, "System") && !strcmp (class->name, "ValueType")))
blittable = FALSE;
/* Prevent infinite loops if the class references itself */
return type;
}
+static gboolean
+type_has_references (MonoClass *klass, MonoType *ftype)
+{
+ if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (klass, ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype)))))
+ return TRUE;
+ if (!ftype->byref && (ftype->type == MONO_TYPE_VAR || ftype->type == MONO_TYPE_MVAR)) {
+ MonoGenericParam *gparam = ftype->data.generic_param;
+
+ if (gparam->gshared_constraint)
+ return mono_class_has_references (mono_class_from_mono_type (gparam->gshared_constraint));
+ }
+ return FALSE;
+}
+
/*
* mono_class_layout_fields:
* @class: a class
if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
ftype = mono_type_get_underlying_type (field->type);
ftype = mono_type_get_basic_type_from_generic (ftype);
- if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype)))))
+ if (type_has_references (class, ftype))
class->has_references = TRUE;
}
}
if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
ftype = mono_type_get_underlying_type (field->type);
ftype = mono_type_get_basic_type_from_generic (ftype);
- if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype)))))
+ if (type_has_references (class, ftype))
class->has_static_refs = TRUE;
}
}
ftype = mono_type_get_underlying_type (field->type);
ftype = mono_type_get_basic_type_from_generic (ftype);
- if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype))))) {
+ if (type_has_references (class, ftype)) {
if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
class->has_static_refs = TRUE;
else
ftype = mono_type_get_underlying_type (field->type);
ftype = mono_type_get_basic_type_from_generic (ftype);
if (gc_aware_layout) {
- if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype))))) {
+ if (type_has_references (class, ftype)) {
if (pass == 1)
continue;
} else {
/* if the field has managed references, we need to force-align it
* see bug #77788
*/
- if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype)))))
+ if (type_has_references (class, ftype))
align = MAX (align, sizeof (gpointer));
class->min_align = MAX (align, class->min_align);
field->offset += sizeof (MonoObject);
ftype = mono_type_get_underlying_type (field->type);
ftype = mono_type_get_basic_type_from_generic (ftype);
- if (MONO_TYPE_IS_REFERENCE (ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype))))) {
+ if (type_has_references (class, ftype)) {
if (field->offset % sizeof (gpointer)) {
mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
}
MonoClass *gklass;
int i;
+ if (!method->klass->generic_class) {
+ g_assert (method->is_inflated);
+ return mono_method_get_vtable_slot (((MonoMethodInflated*)method)->declaring);
+ }
+
/* This can happen for abstract methods of generic instances due to the shortcut code in mono_class_setup_vtable_general (). */
g_assert (method->klass->generic_class);
gklass = method->klass->generic_class->container_class;
if (mono_metadata_token_table (type_token) != MONO_TABLE_TYPEDEF || tidx > tt->rows) {
mono_error_set_bad_image (error, image, "Invalid typedef token %x", type_token);
- g_assert (!mono_loader_get_last_error ());
+ mono_loader_assert_no_error ();
return NULL;
}
if ((class = mono_internal_hash_table_lookup (&image->class_cache, GUINT_TO_POINTER (type_token)))) {
mono_loader_unlock ();
- g_assert (!mono_loader_get_last_error ());
+ mono_loader_assert_no_error ();
return class;
}
mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup (mono_error_get_message (error)));
mono_loader_unlock ();
mono_profiler_class_loaded (class, MONO_PROFILE_FAILED);
- g_assert (!mono_loader_get_last_error ());
+ mono_loader_assert_no_error ();
return NULL;
}
}
mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup (mono_error_get_message (error)));
mono_loader_unlock ();
mono_profiler_class_loaded (class, MONO_PROFILE_FAILED);
- g_assert (!mono_loader_get_last_error ());
+ mono_loader_assert_no_error ();
return NULL;
}
class->cast_class = class->element_class = mono_class_from_mono_type (enum_basetype);
mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Could not load generic parameter constrains due to %s", mono_error_get_message (error)));
mono_loader_unlock ();
mono_profiler_class_loaded (class, MONO_PROFILE_FAILED);
- g_assert (!mono_loader_get_last_error ());
+ mono_loader_assert_no_error ();
return NULL;
}
mono_loader_unlock ();
mono_profiler_class_loaded (class, MONO_PROFILE_OK);
- g_assert (!mono_loader_get_last_error ());
+ mono_loader_assert_no_error ();
return class;
mono_class_setup_mono_type (class);
mono_loader_unlock ();
mono_profiler_class_loaded (class, MONO_PROFILE_FAILED);
- g_assert (!mono_loader_get_last_error ());
+ mono_loader_assert_no_error ();
return NULL;
}
MonoType *inflated = inflate_generic_type (NULL, t, context, error);
if (!mono_error_ok (error)) {
- g_assert (!mono_loader_get_last_error ());
+ mono_loader_assert_no_error ();
return NULL;
}
MonoClass *class = mono_class_get_checked (image, type_token, error);
if (!class) {
- g_assert (!mono_loader_get_last_error ());
+ mono_loader_assert_no_error ();
return NULL;
}
type = mono_type_retrieve_from_typespec (image, type_token, context, &inflated, error);
if (!type) {
- g_assert (!mono_loader_get_last_error ());
+ mono_loader_assert_no_error ();
return NULL;
}
const char *name;
const char *nspace;
guint32 i, visib, nspace_index;
- GHashTable *name_cache2, *nspace_table;
+ GHashTable *name_cache2, *nspace_table, *the_name_cache;
- mono_image_lock (image);
-
- if (image->name_cache) {
- mono_image_unlock (image);
+ if (image->name_cache)
return;
- }
- image->name_cache = g_hash_table_new (g_str_hash, g_str_equal);
+ the_name_cache = g_hash_table_new (g_str_hash, g_str_equal);
if (image_is_dynamic (image)) {
+ mono_image_lock (image);
+ if (image->name_cache) {
+ /* Somebody initialized it before us */
+ g_hash_table_destroy (the_name_cache);
+ } else {
+ mono_atomic_store_release (&image->name_cache, the_name_cache);
+ }
mono_image_unlock (image);
return;
}
nspace_table = g_hash_table_lookup (name_cache2, GUINT_TO_POINTER (nspace_index));
if (!nspace_table) {
nspace_table = g_hash_table_new (g_str_hash, g_str_equal);
- g_hash_table_insert (image->name_cache, (char*)nspace, nspace_table);
+ g_hash_table_insert (the_name_cache, (char*)nspace, nspace_table);
g_hash_table_insert (name_cache2, GUINT_TO_POINTER (nspace_index),
nspace_table);
}
nspace_table = g_hash_table_lookup (name_cache2, GUINT_TO_POINTER (nspace_index));
if (!nspace_table) {
nspace_table = g_hash_table_new (g_str_hash, g_str_equal);
- g_hash_table_insert (image->name_cache, (char*)nspace, nspace_table);
+ g_hash_table_insert (the_name_cache, (char*)nspace, nspace_table);
g_hash_table_insert (name_cache2, GUINT_TO_POINTER (nspace_index),
nspace_table);
}
}
g_hash_table_destroy (name_cache2);
+
+ mono_image_lock (image);
+ if (image->name_cache) {
+ /* Somebody initialized it before us */
+ g_hash_table_destroy (the_name_cache);
+ } else {
+ mono_atomic_store_release (&image->name_cache, the_name_cache);
+ }
mono_image_unlock (image);
}
GHashTable *name_cache;
guint32 old_index;
+ mono_image_init_name_cache (image);
mono_image_lock (image);
- if (!image->name_cache)
- mono_image_init_name_cache (image);
-
name_cache = image->name_cache;
if (!(nspace_table = g_hash_table_lookup (name_cache, nspace))) {
nspace_table = g_hash_table_new (g_str_hash, g_str_equal);
guint32 token = 0;
FindUserData user_data;
+ mono_image_init_name_cache (image);
mono_image_lock (image);
- if (!image->name_cache)
- mono_image_init_name_cache (image);
-
user_data.key = name_space;
user_data.value = NULL;
g_hash_table_foreach (image->name_cache, find_nocase, &user_data);
return NULL;
}
-MonoClass *
-mono_class_from_name_checked (MonoImage *image, const char* name_space, const char *name, MonoError *error)
+static MonoClass *
+mono_class_from_name_checked_aux (MonoImage *image, const char* name_space, const char *name, MonoError *error, GHashTable* visited_images)
{
GHashTable *nspace_table;
MonoImage *loaded_image;
mono_error_init (error);
+ // Checking visited images avoids stack overflows when cyclic references exist.
+ if (g_hash_table_lookup (visited_images, image))
+ return NULL;
+
+ g_hash_table_insert (visited_images, image, GUINT_TO_POINTER(1));
+
if ((nested = strchr (name, '/'))) {
int pos = nested - name;
int len = strlen (name);
}
}
+ mono_image_init_name_cache (image);
mono_image_lock (image);
- if (!image->name_cache)
- mono_image_init_name_cache (image);
-
nspace_table = g_hash_table_lookup (image->name_cache, name_space);
if (nspace_table)
loaded_image = mono_assembly_load_module (image->assembly, impl >> MONO_IMPLEMENTATION_BITS);
if (!loaded_image)
return NULL;
- class = mono_class_from_name (loaded_image, name_space, name);
+ class = mono_class_from_name_checked_aux (loaded_image, name_space, name, error, visited_images);
if (nested)
return return_nested_in (class, nested);
return class;
if (image->references [assembly_idx - 1] == (gpointer)-1)
return NULL;
else
- /* FIXME: Cycle detection */
- return mono_class_from_name (image->references [assembly_idx - 1]->image, name_space, name);
+ return mono_class_from_name_checked_aux (image->references [assembly_idx - 1]->image, name_space, name, error, visited_images);
} else {
g_error ("not yet implemented");
}
return class;
}
+MonoClass *
+mono_class_from_name_checked (MonoImage *image, const char* name_space, const char *name, MonoError *error)
+{
+ MonoClass *klass;
+ GHashTable *visited_images;
+
+ visited_images = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+ klass = mono_class_from_name_checked_aux (image, name_space, name, error, visited_images);
+
+ g_hash_table_destroy (visited_images);
+
+ return klass;
+}
+
/**
* mono_class_from_name:
* @image: The MonoImage where the type is looked up in
mono_metadata_decode_value (sig, &sig);
/* FIELD signature == 0x06 */
g_assert (*sig == 0x06);
- field->type = mono_metadata_parse_type_full (image, container, MONO_PARSE_FIELD, cols [MONO_FIELD_FLAGS], sig + 1, &sig);
+ field->type = mono_metadata_parse_type_full (image, container, cols [MONO_FIELD_FLAGS], sig + 1, &sig);
if (!field->type)
mono_class_set_failure_from_loader_error (class, error, g_strdup_printf ("Could not load field %s type", field->name));
}