[utils] Another try to fix the windows build.
[mono.git] / mono / metadata / class.c
index 349dce5c454a5b0cad3d6370e1d0b33925e6df1a..041b9e3dcd61c72b0fd2bd820763b8f53c62e59c 100644 (file)
@@ -52,6 +52,9 @@ gboolean mono_print_vtable = FALSE;
 guint32 inflated_classes, inflated_classes_size, inflated_methods_size;
 guint32 classes_size, class_ext_size;
 
+/* Low level lock which protects data structures in this module */
+static mono_mutex_t classes_mutex;
+
 /* Function supplied by the runtime to find classes by name using information from the AOT file */
 static MonoGetClassFromName get_class_from_name = NULL;
 
@@ -69,10 +72,6 @@ static guint32 mono_field_resolve_flags (MonoClassField *field);
 static void mono_class_setup_vtable_full (MonoClass *class, GList *in_setup);
 static void mono_generic_class_setup_parent (MonoClass *klass, MonoClass *gklass);
 
-
-void (*mono_debugger_class_init_func) (MonoClass *klass) = NULL;
-
-
 /*
 We use gclass recording to allow recursive system f types to be referenced by a parent.
 
@@ -100,6 +99,18 @@ static int record_gclass_instantiation;
 static GSList *gclass_recorded_list;
 typedef gboolean (*gclass_record_func) (MonoClass*, void*);
 
+static inline void
+classes_lock (void)
+{
+       mono_locks_acquire (&classes_mutex, ClassesLock);
+}
+
+static inline void
+classes_unlock (void)
+{
+       mono_locks_release (&classes_mutex, ClassesLock);
+}
+
 /* 
  * LOCKING: loader lock must be held until pairing disable_gclass_recording is called.
 */
@@ -151,59 +162,60 @@ MonoClass *
 mono_class_from_typeref (MonoImage *image, guint32 type_token)
 {
        MonoError error;
+       MonoClass *class = mono_class_from_typeref_checked (image, type_token, &error);
+       g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
+       return class;
+}
+
+MonoClass *
+mono_class_from_typeref_checked (MonoImage *image, guint32 type_token, MonoError *error)
+{
        guint32 cols [MONO_TYPEREF_SIZE];
        MonoTableInfo  *t = &image->tables [MONO_TABLE_TYPEREF];
        guint32 idx;
        const char *name, *nspace;
-       MonoClass *res;
+       MonoClass *res = NULL;
        MonoImage *module;
 
-       if (!mono_verifier_verify_typeref_row (image, (type_token & 0xffffff) - 1, &error)) {
-               mono_trace_warning (MONO_TRACE_TYPE, "Failed to resolve typeref from %s due to '%s'", image->name, mono_error_get_message (&error));
+       mono_error_init (error);
+
+       if (!mono_verifier_verify_typeref_row (image, (type_token & 0xffffff) - 1, error))
                return NULL;
-       }
 
        mono_metadata_decode_row (t, (type_token&0xffffff)-1, cols, MONO_TYPEREF_SIZE);
 
        name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
        nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
 
-       idx = cols [MONO_TYPEREF_SCOPE] >> MONO_RESOLTION_SCOPE_BITS;
-       switch (cols [MONO_TYPEREF_SCOPE] & MONO_RESOLTION_SCOPE_MASK) {
-       case MONO_RESOLTION_SCOPE_MODULE:
+       idx = cols [MONO_TYPEREF_SCOPE] >> MONO_RESOLUTION_SCOPE_BITS;
+       switch (cols [MONO_TYPEREF_SCOPE] & MONO_RESOLUTION_SCOPE_MASK) {
+       case MONO_RESOLUTION_SCOPE_MODULE:
                /*
                LAMESPEC The spec says that a null module resolution scope should go through the exported type table.
                This is not the observed behavior of existing implementations.
                The defacto behavior is that it's just a typedef in disguise.
                */
                /* a typedef in disguise */
-               return mono_class_from_name (image, nspace, name);
-       case MONO_RESOLTION_SCOPE_MODULEREF:
+               res = mono_class_from_name (image, nspace, name); /*FIXME proper error handling*/
+               goto done;
+
+       case MONO_RESOLUTION_SCOPE_MODULEREF:
                module = mono_image_load_module (image, idx);
                if (module)
-                       return mono_class_from_name (module, nspace, name);
-               else {
-                       char *msg = g_strdup_printf ("%s%s%s", nspace, nspace [0] ? "." : "", name);
-                       char *human_name;
-                       
-                       human_name = mono_stringify_assembly_name (&image->assembly->aname);
-                       mono_loader_set_error_type_load (msg, human_name);
-                       g_free (msg);
-                       g_free (human_name);
-               
-                       return NULL;
-               }
-       case MONO_RESOLTION_SCOPE_TYPEREF: {
+                       res = mono_class_from_name (module, nspace, name); /*FIXME proper error handling*/
+               goto done;
+
+       case MONO_RESOLUTION_SCOPE_TYPEREF: {
                MonoClass *enclosing;
                GList *tmp;
 
                if (idx == mono_metadata_token_index (type_token)) {
-                       mono_loader_set_error_bad_image (g_strdup_printf ("Image %s with self-referencing typeref token %08x.", image->name, type_token));
+                       mono_error_set_bad_image (error, image, "Image with self-referencing typeref token %08x.", type_token);
                        return NULL;
                }
 
-               enclosing = mono_class_from_typeref (image, MONO_TOKEN_TYPE_REF | idx);
-               if (!enclosing)
+               enclosing = mono_class_from_typeref_checked (image, MONO_TOKEN_TYPE_REF | idx, error); 
+               if (!mono_error_ok (error))
                        return NULL;
 
                if (enclosing->nested_classes_inited && enclosing->ext) {
@@ -221,28 +233,21 @@ mono_class_from_typeref (MonoImage *image, guint32 type_token)
                                guint32 string_offset = mono_metadata_decode_row_col (&enclosing->image->tables [MONO_TABLE_TYPEDEF], class_nested - 1, MONO_TYPEDEF_NAME);
                                const char *nname = mono_metadata_string_heap (enclosing->image, string_offset);
 
-                               if (strcmp (nname, name) == 0) {
-                                       MonoClass *res = mono_class_create_from_typedef (enclosing->image, MONO_TOKEN_TYPE_DEF | class_nested, &error);
-                                       if (!mono_error_ok (&error)) {
-                                               mono_loader_set_error_from_mono_error (&error);
-                                               mono_error_cleanup (&error); /*FIXME don't swallow error message.*/
-                                               return NULL;
-                                       }
-                                       return res;
-                               }
+                               if (strcmp (nname, name) == 0)
+                                       return mono_class_create_from_typedef (enclosing->image, MONO_TOKEN_TYPE_DEF | class_nested, error);
 
                                i = mono_metadata_nesting_typedef (enclosing->image, enclosing->type_token, i + 1);
                        }
                }
                g_warning ("TypeRef ResolutionScope not yet handled (%d) for %s.%s in image %s", idx, nspace, name, image->name);
-               return NULL;
+               goto done;
        }
-       case MONO_RESOLTION_SCOPE_ASSEMBLYREF:
+       case MONO_RESOLUTION_SCOPE_ASSEMBLYREF:
                break;
        }
 
        if (idx > image->tables [MONO_TABLE_ASSEMBLYREF].rows) {
-               mono_loader_set_error_bad_image (g_strdup_printf ("Image %s with invalid assemblyref token %08x.", image->name, idx));
+               mono_error_set_bad_image (error, image, "Image with invalid assemblyref token %08x.", idx);
                return NULL;
        }
 
@@ -257,13 +262,20 @@ mono_class_from_typeref (MonoImage *image, guint32 type_token)
                
                mono_assembly_get_assemblyref (image, idx - 1, &aname);
                human_name = mono_stringify_assembly_name (&aname);
-               mono_loader_set_error_assembly_load (human_name, image->assembly ? image->assembly->ref_only : FALSE);
-               g_free (human_name);
-               
+               mono_error_set_assembly_load_simple (error, human_name, image->assembly ? image->assembly->ref_only : FALSE);
                return NULL;
        }
 
-       return mono_class_from_name (image->references [idx - 1]->image, nspace, name);
+       res = mono_class_from_name (image->references [idx - 1]->image, nspace, name);
+
+done:
+       /* Generic case, should be avoided for when a better error is possible. */
+       if (!res && mono_error_ok (error)) {
+               char *name = mono_class_name_from_token (image, type_token);
+               char *assembly = mono_assembly_name_from_token (image, type_token);
+               mono_error_set_type_load_name (error, name, assembly, "Could not resolve type with token %08x", type_token);
+       }
+       return res;
 }
 
 
@@ -878,7 +890,7 @@ mono_class_inflate_generic_type_no_copy (MonoImage *image, MonoType *type, MonoG
        return inflated;
 }
 
-static MonoClass*
+MonoClass*
 mono_class_inflate_generic_class_checked (MonoClass *gklass, MonoGenericContext *context, MonoError *error)
 {
        MonoClass *res;
@@ -1066,10 +1078,8 @@ mono_class_inflate_generic_method_full_checked (MonoMethod *method, MonoClass *k
                        iresult->context.class_inst = iresult->declaring->klass->generic_class->context.class_inst;
        }
 
-       mono_loader_lock ();
        cached = mono_method_inflated_lookup (iresult, FALSE);
        if (cached) {
-               mono_loader_unlock ();
                g_free (iresult);
                return (MonoMethod*)cached;
        }
@@ -1140,12 +1150,9 @@ mono_class_inflate_generic_method_full_checked (MonoMethod *method, MonoClass *k
         * is_generic_method_definition().
         */
 
-       mono_method_inflated_lookup (iresult, TRUE);
-       mono_loader_unlock ();
-       return result;
+       return (MonoMethod*)mono_method_inflated_lookup (iresult, TRUE);
 
 fail:
-       mono_loader_unlock ();
        g_free (iresult);
        return NULL;
 }
@@ -1225,7 +1232,7 @@ mono_method_get_generic_container (MonoMethod *method)
  * mono_method_set_generic_container:
  *
  *   Sets the generic container of METHOD to CONTAINER.
- * LOCKING: Acquires the loader lock.
+ * LOCKING: Acquires the image lock.
  */
 void
 mono_method_set_generic_container (MonoMethod *method, MonoGenericContainer* container)
@@ -1243,7 +1250,7 @@ mono_method_set_generic_container (MonoMethod *method, MonoGenericContainer* con
  * in a separate function since it is cheaper than calling mono_class_setup_fields.
  */
 static MonoType*
-mono_class_find_enum_basetype (MonoClass *class)
+mono_class_find_enum_basetype (MonoClass *class, MonoError *error)
 {
        MonoGenericContainer *container = NULL;
        MonoImage *m = class->image; 
@@ -1252,6 +1259,8 @@ mono_class_find_enum_basetype (MonoClass *class)
 
        g_assert (class->enumtype);
 
+       mono_error_init (error);
+
        if (class->generic_container)
                container = class->generic_container;
        else if (class->generic_class) {
@@ -1276,27 +1285,41 @@ mono_class_find_enum_basetype (MonoClass *class)
                if (cols [MONO_FIELD_FLAGS] & FIELD_ATTRIBUTE_STATIC) //no need to decode static fields
                        continue;
 
-               if (!mono_verifier_verify_field_signature (class->image, cols [MONO_FIELD_SIGNATURE], NULL))
-                       return NULL;
+               if (!mono_verifier_verify_field_signature (class->image, cols [MONO_FIELD_SIGNATURE], NULL)) {
+                       mono_error_set_bad_image (error, class->image, "Invalid field signature %x", cols [MONO_FIELD_SIGNATURE]);
+                       goto fail;
+               }
 
                sig = mono_metadata_blob_heap (m, cols [MONO_FIELD_SIGNATURE]);
                mono_metadata_decode_value (sig, &sig);
                /* FIELD signature == 0x06 */
-               if (*sig != 0x06)
-                       return NULL;
+               if (*sig != 0x06) {
+                       mono_error_set_bad_image (error, class->image, "Invalid field signature %x, expected 0x6 but got %x", cols [MONO_FIELD_SIGNATURE], *sig);
+                       goto fail;
+               }
 
                ftype = mono_metadata_parse_type_full (m, container, MONO_PARSE_FIELD, cols [MONO_FIELD_FLAGS], sig + 1, &sig);
-               if (!ftype)
-                       return NULL;
+               if (!ftype) {
+                       if (mono_loader_get_last_error ()) /*FIXME plug the above to not leak errors*/
+                               mono_error_set_from_loader_error (error);
+                       else
+                               mono_error_set_bad_image (error, class->image, "Could not parse type for field signature %x", cols [MONO_FIELD_SIGNATURE]);
+                       goto fail;
+               }
                if (class->generic_class) {
                        //FIXME do we leak here?
-                       ftype = mono_class_inflate_generic_type (ftype, mono_class_get_context (class));
+                       ftype = mono_class_inflate_generic_type_checked (ftype, mono_class_get_context (class), error);
+                       if (!mono_error_ok (error))
+                               goto fail;
                        ftype->attrs = cols [MONO_FIELD_FLAGS];
                }
 
                return ftype;
        }
+       mono_error_set_type_load_class (error, class, "Could not find base type");
 
+fail:
+       g_assert (!mono_loader_get_last_error ());
        return NULL;
 }
 
@@ -1536,8 +1559,8 @@ mono_class_setup_fields (MonoClass *class)
        explicit_size = mono_metadata_packing_from_typedef (class->image, class->type_token, &packing_size, &real_size);
 
        if (explicit_size) {
-               if ((packing_size & 0xfffffff0) != 0) {
-                       char *err_msg = g_strdup_printf ("Could not load struct '%s' with packing size %d >= 16", class->name, packing_size);
+               if ((packing_size & 0xffffff00) != 0) {
+                       char *err_msg = g_strdup_printf ("Could not load struct '%s' with packing size %d >= 256", class->name, packing_size);
                        mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, err_msg);
                        return;
                }
@@ -1610,6 +1633,10 @@ mono_class_setup_fields (MonoClass *class)
                                        mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Invalid negative field offset %d for %s", field->offset, field->name));
                                        break;
                                }
+                               if (class->generic_container) {
+                                       mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Generic class cannot have explicit layout."));
+                                       break;
+                               }
                        }
                }
 
@@ -1907,7 +1934,9 @@ mono_class_layout_fields (MonoClass *class)
                        }
                }
                break;
-       case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT:
+       case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT: {
+               guint8 *ref_bitmap;
+
                real_size = 0;
                for (i = 0; i < top; i++) {
                        gint32 align;
@@ -1920,7 +1949,6 @@ mono_class_layout_fields (MonoClass *class)
                         * There must be info about all the fields in a type if it
                         * uses explicit layout.
                         */
-
                        if (mono_field_is_deleted (field))
                                continue;
                        if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
@@ -1950,6 +1978,43 @@ mono_class_layout_fields (MonoClass *class)
                         */
                        real_size = MAX (real_size, size + field->offset);
                }
+
+               if (class->has_references) {
+                       ref_bitmap = g_new0 (guint8, real_size / sizeof (gpointer));
+
+                       /* Check for overlapping reference and non-reference fields */
+                       for (i = 0; i < top; i++) {
+                               MonoType *ftype;
+
+                               field = &class->fields [i];
+
+                               if (mono_field_is_deleted (field))
+                                       continue;
+                               if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
+                                       continue;
+                               ftype = mono_type_get_underlying_type (field->type);
+                               if (MONO_TYPE_IS_REFERENCE (ftype))
+                                       ref_bitmap [field->offset / sizeof (gpointer)] = 1;
+                       }
+                       for (i = 0; i < top; i++) {
+                               field = &class->fields [i];
+
+                               if (mono_field_is_deleted (field))
+                                       continue;
+                               if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
+                                       continue;
+
+                               // FIXME: Too much code does this
+#if 0
+                               if (!MONO_TYPE_IS_REFERENCE (field->type) && ref_bitmap [field->offset / sizeof (gpointer)]) {
+                                       char *err_msg = g_strdup_printf ("Could not load type '%s' because it contains an object field at offset %d that is incorrectly aligned or overlapped by a non-object field.", class->name, field->offset);
+                                       mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, err_msg);
+                               }
+#endif
+                       }
+                       g_free (ref_bitmap);
+               }
+
                class->instance_size = MAX (real_size, class->instance_size);
                if (class->instance_size & (class->min_align - 1)) {
                        class->instance_size += class->min_align - 1;
@@ -1957,6 +2022,7 @@ mono_class_layout_fields (MonoClass *class)
                }
                break;
        }
+       }
 
        if (layout != TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
                /*
@@ -2030,7 +2096,7 @@ create_array_method (MonoClass *class, const char *name, MonoMethodSignature *si
  * mono_class_setup_methods:
  * @class: a class
  *
- *   Initializes the 'methods' array in the klass.
+ *   Initializes the 'methods' array in CLASS.
  * Calling this method should be avoided if possible since it allocates a lot 
  * of long-living MonoMethod structures.
  * Methods belonging to an interface are assigned a sequential slot starting
@@ -2041,19 +2107,12 @@ create_array_method (MonoClass *class, const char *name, MonoMethodSignature *si
 void
 mono_class_setup_methods (MonoClass *class)
 {
-       int i;
+       int i, count;
        MonoMethod **methods;
 
        if (class->methods)
                return;
 
-       mono_loader_lock ();
-
-       if (class->methods) {
-               mono_loader_unlock ();
-               return;
-       }
-
        if (class->generic_class) {
                MonoError error;
                MonoClass *gklass = class->generic_class->container_class;
@@ -2062,17 +2121,16 @@ mono_class_setup_methods (MonoClass *class)
                if (!gklass->exception_type)
                        mono_class_setup_methods (gklass);
                if (gklass->exception_type) {
-                       /*FIXME make exception_data less opaque so it's possible to dup it here*/
+                       /* FIXME make exception_data less opaque so it's possible to dup it here */
                        mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Generic type definition failed to load"));
-                       mono_loader_unlock ();
                        return;
                }
 
                /* The + 1 makes this always non-NULL to pass the check in mono_class_setup_methods () */
-               class->method.count = gklass->method.count;
-               methods = mono_class_alloc0 (class, sizeof (MonoMethod*) * (class->method.count + 1));
+               count = gklass->method.count;
+               methods = mono_class_alloc0 (class, sizeof (MonoMethod*) * (count + 1));
 
-               for (i = 0; i < class->method.count; i++) {
+               for (i = 0; i < count; i++) {
                        methods [i] = mono_class_inflate_generic_method_full_checked (
                                gklass->methods [i], class, mono_class_get_context (class), &error);
                        if (!mono_error_ok (&error)) {
@@ -2081,7 +2139,6 @@ mono_class_setup_methods (MonoClass *class)
 
                                g_free (method);
                                mono_error_cleanup (&error);
-                               mono_loader_unlock ();
                                return;                         
                        }
                }
@@ -2091,19 +2148,25 @@ mono_class_setup_methods (MonoClass *class)
                MonoMethodSignature *sig;
                int count_generic = 0, first_generic = 0;
                int method_num = 0;
+               gboolean jagged_ctor = FALSE;
 
-               class->method.count = 3 + (class->rank > 1? 2: 1);
+               count = 3 + (class->rank > 1? 2: 1);
 
                mono_class_setup_interfaces (class, &error);
                g_assert (mono_error_ok (&error)); /*FIXME can this fail for array types?*/
 
+               if (class->rank == 1 && class->element_class->rank) {
+                       jagged_ctor = TRUE;
+                       class->method.count ++;
+               }
+
                if (class->interface_count) {
                        count_generic = generic_array_methods (class);
-                       first_generic = class->method.count;
-                       class->method.count += class->interface_count * count_generic;
+                       first_generic = count;
+                       count += class->interface_count * count_generic;
                }
 
-               methods = mono_class_alloc0 (class, sizeof (MonoMethod*) * class->method.count);
+               methods = mono_class_alloc0 (class, sizeof (MonoMethod*) * count);
 
                sig = mono_metadata_signature_alloc (class->image, class->rank);
                sig->ret = &mono_defaults.void_class->byval_arg;
@@ -2125,6 +2188,19 @@ mono_class_setup_methods (MonoClass *class)
                        amethod = create_array_method (class, ".ctor", sig);
                        methods [method_num++] = amethod;
                }
+
+               if (jagged_ctor) {
+                       /* Jagged arrays have an extra ctor in .net which creates an array of arrays */
+                       sig = mono_metadata_signature_alloc (class->image, class->rank + 1);
+                       sig->ret = &mono_defaults.void_class->byval_arg;
+                       sig->pinvoke = TRUE;
+                       sig->hasthis = TRUE;
+                       for (i = 0; i < class->rank + 1; ++i)
+                               sig->params [i] = &mono_defaults.int32_class->byval_arg;
+                       amethod = create_array_method (class, ".ctor", sig);
+                       methods [method_num++] = amethod;
+               }
+
                /* element Get (idx11, [idx2, ...]) */
                sig = mono_metadata_signature_alloc (class->image, class->rank);
                sig->ret = &class->element_class->byval_arg;
@@ -2157,8 +2233,9 @@ mono_class_setup_methods (MonoClass *class)
                for (i = 0; i < class->interface_count; i++)
                        setup_generic_array_ifaces (class, class->interfaces [i], methods, first_generic + i * count_generic);
        } else {
-               methods = mono_class_alloc (class, sizeof (MonoMethod*) * class->method.count);
-               for (i = 0; i < class->method.count; ++i) {
+               count = class->method.count;
+               methods = mono_class_alloc (class, sizeof (MonoMethod*) * count);
+               for (i = 0; i < count; ++i) {
                        int idx = mono_metadata_translate_token_index (class->image, MONO_TABLE_METHOD, class->method.first + i + 1);
                        methods [i] = mono_get_method (class->image, MONO_TOKEN_METHOD_DEF | idx, class);
                }
@@ -2167,18 +2244,24 @@ mono_class_setup_methods (MonoClass *class)
        if (MONO_CLASS_IS_INTERFACE (class)) {
                int slot = 0;
                /*Only assign slots to virtual methods as interfaces are allowed to have static methods.*/
-               for (i = 0; i < class->method.count; ++i) {
+               for (i = 0; i < count; ++i) {
                        if (methods [i]->flags & METHOD_ATTRIBUTE_VIRTUAL)
                                methods [i]->slot = slot++;
                }
        }
 
-       /* Needed because of the double-checking locking pattern */
-       mono_memory_barrier ();
+       mono_image_lock (class->image);
 
-       class->methods = methods;
+       if (!class->methods) {
+               class->method.count = count;
 
-       mono_loader_unlock ();
+               /* Needed because of the double-checking locking pattern */
+               mono_memory_barrier ();
+
+               class->methods = methods;
+       }
+
+       mono_image_unlock (class->image);
 }
 
 /*
@@ -2388,16 +2471,16 @@ mono_class_setup_properties (MonoClass *class)
                }
        }
 
-       mono_loader_lock ();
+       mono_class_alloc_ext (class);
 
-       if (class->ext && class->ext->properties) {
+       mono_image_lock (class->image);
+
+       if (class->ext->properties) {
                /* We leak 'properties' which was allocated from the image mempool */
-               mono_loader_unlock ();
+               mono_image_unlock (class->image);
                return;
        }
 
-       mono_class_alloc_ext (class);
-
        class->ext->property.first = first;
        class->ext->property.count = count;
 
@@ -2407,7 +2490,7 @@ mono_class_setup_properties (MonoClass *class)
        /* Leave this assignment as the last op in the function */
        class->ext->properties = properties;
 
-       mono_loader_unlock ();
+       mono_image_unlock (class->image);
 }
 
 static MonoMethod**
@@ -2443,7 +2526,7 @@ mono_class_setup_events (MonoClass *class)
 
        if (class->generic_class) {
                MonoClass *gklass = class->generic_class->container_class;
-               MonoGenericContext *context;
+               MonoGenericContext *context = NULL;
 
                mono_class_setup_events (gklass);
                if (gklass->exception_type) {
@@ -2540,15 +2623,15 @@ mono_class_setup_events (MonoClass *class)
                }
        }
 
-       mono_loader_lock ();
+       mono_class_alloc_ext (class);
 
-       if (class->ext && class->ext->events) {
-               mono_loader_unlock ();
+       mono_image_lock (class->image);
+
+       if (class->ext->events) {
+               mono_image_unlock (class->image);
                return;
        }
 
-       mono_class_alloc_ext (class);
-
        class->ext->event.first = first;
        class->ext->event.count = count;
 
@@ -2558,12 +2641,12 @@ mono_class_setup_events (MonoClass *class)
        /* Leave this assignment as the last op in the function */
        class->ext->events = events;
 
-       mono_loader_unlock ();
+       mono_image_unlock (class->image);
 }
 
 /*
  * Global pool of interface IDs, represented as a bitset.
- * LOCKING: this is supposed to be accessed with the loader lock held.
+ * LOCKING: Protected by the classes lock.
  */
 static MonoBitSet *global_interface_bitset = NULL;
 
@@ -2578,18 +2661,18 @@ static MonoBitSet *global_interface_bitset = NULL;
 void
 mono_unload_interface_ids (MonoBitSet *bitset)
 {
-       mono_loader_lock ();
+       classes_lock ();
        mono_bitset_sub (global_interface_bitset, bitset);
-       mono_loader_unlock ();
+       classes_unlock ();
 }
 
 void
 mono_unload_interface_id (MonoClass *class)
 {
        if (global_interface_bitset && class->interface_id) {
-               mono_loader_lock ();
+               classes_lock ();
                mono_bitset_clear (global_interface_bitset, class->interface_id);
-               mono_loader_unlock ();
+               classes_unlock ();
        }
 }
 
@@ -2599,7 +2682,7 @@ mono_unload_interface_id (MonoClass *class)
  *
  * Assign a unique integer ID to the interface represented by @class.
  * The ID will positive and as small as possible.
- * LOCKING: this is supposed to be called with the loader lock held.
+ * LOCKING: Acquires the classes lock.
  * Returns: the new ID.
  */
 static guint
@@ -2609,6 +2692,8 @@ mono_get_unique_iid (MonoClass *class)
        
        g_assert (MONO_CLASS_IS_INTERFACE (class));
 
+       classes_lock ();
+
        if (!global_interface_bitset) {
                global_interface_bitset = mono_bitset_new (128, 0);
        }
@@ -2636,6 +2721,8 @@ mono_get_unique_iid (MonoClass *class)
                mono_bitset_set (class->image->interface_bitset, iid);
        }
 
+       classes_unlock ();
+
 #ifndef MONO_SMALL_CONFIG
        if (mono_print_vtable) {
                int generic_id;
@@ -5068,14 +5155,11 @@ mono_class_init (MonoClass *class)
                } else {
                        class->vtable_size = szarray_vtable_size[slot];
                }
-               class->has_finalize_inited = TRUE;
        } else if (class->generic_class && !MONO_CLASS_IS_INTERFACE (class)) {
                MonoClass *gklass = class->generic_class->container_class;
 
                /* Generic instance case */
                class->ghcimpl = gklass->ghcimpl;
-               class->has_finalize = mono_class_has_finalizer (gklass);
-               class->has_finalize_inited = TRUE;
                class->has_cctor = gklass->has_cctor;
 
                mono_class_setup_vtable (gklass);
@@ -5177,9 +5261,6 @@ mono_class_init (MonoClass *class)
 
        mono_loader_unlock ();
 
-       if (mono_debugger_class_init_func)
-               mono_debugger_class_init_func (class);
-
        return class->exception_type == MONO_EXCEPTION_NONE;
 }
 
@@ -5192,55 +5273,61 @@ mono_class_init (MonoClass *class)
 gboolean
 mono_class_has_finalizer (MonoClass *klass)
 {
-       if (!klass->has_finalize_inited) {
-               MonoClass *class = klass;
+       MonoClass *class = klass;
+       gboolean has_finalize = FALSE;
 
-               mono_loader_lock ();
+       if (klass->has_finalize_inited)
+               return klass->has_finalize;
 
-               /* Interfaces and valuetypes are not supposed to have finalizers */
-               if (!(MONO_CLASS_IS_INTERFACE (class) || class->valuetype)) {
-                       MonoMethod *cmethod = NULL;
+       /* Interfaces and valuetypes are not supposed to have finalizers */
+       if (!(MONO_CLASS_IS_INTERFACE (class) || class->valuetype)) {
+               MonoMethod *cmethod = NULL;
 
-                       if (class->parent && class->parent->has_finalize) {
-                               class->has_finalize = 1;
-                       } else {
-                               if (class->parent) {
-                                       /*
-                                        * Can't search in metadata for a method named Finalize, because that
-                                        * ignores overrides.
-                                        */
-                                       mono_class_setup_vtable (class);
-                                       if (class->exception_type || mono_loader_get_last_error ())
-                                               goto leave;
+               if (class->rank == 1 && class->byval_arg.type == MONO_TYPE_SZARRAY) {
+               } else if (class->generic_class) {
+                       MonoClass *gklass = class->generic_class->container_class;
+
+                       has_finalize = mono_class_has_finalizer (gklass);
+               } else if (class->parent && class->parent->has_finalize) {
+                       has_finalize = TRUE;
+               } else {
+                       if (class->parent) {
+                               /*
+                                * Can't search in metadata for a method named Finalize, because that
+                                * ignores overrides.
+                                */
+                               mono_class_setup_vtable (class);
+                               if (class->exception_type || mono_loader_get_last_error ())
+                                       cmethod = NULL;
+                               else
                                        cmethod = class->vtable [finalize_slot];
-                               }
+                       }
 
-                               if (cmethod) {
-                                       g_assert (class->vtable_size > finalize_slot);
+                       if (cmethod) {
+                               g_assert (class->vtable_size > finalize_slot);
 
-                                       class->has_finalize = 0;
-                                       if (class->parent) { 
-                                               if (cmethod->is_inflated)
-                                                       cmethod = ((MonoMethodInflated*)cmethod)->declaring;
-                                               if (cmethod != default_finalize) {
-                                                       class->has_finalize = 1;
-                                               }
-                                       }
+                               if (class->parent) {
+                                       if (cmethod->is_inflated)
+                                               cmethod = ((MonoMethodInflated*)cmethod)->declaring;
+                                       if (cmethod != default_finalize)
+                                               has_finalize = TRUE;
                                }
                        }
                }
+       }
+
+       mono_image_lock (klass->image);
+
+       if (!klass->has_finalize_inited) {
+               klass->has_finalize = has_finalize ? 1 : 0;
 
                mono_memory_barrier ();
                klass->has_finalize_inited = TRUE;
-
-               mono_loader_unlock ();
        }
 
-       return klass->has_finalize;
+       mono_image_unlock (klass->image);
 
- leave:
-       mono_loader_unlock ();
-       return FALSE;
+       return klass->has_finalize;
 }
 
 gboolean
@@ -5661,10 +5748,12 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError
                        class->byval_arg.data.klass = class;
                        class->byval_arg.type = MONO_TYPE_CLASS;
                }
-               parent = mono_class_get_full (image, parent_token, context);
+               parent = mono_class_get_checked (image, parent_token, error);
+               if (parent && context) /* Always inflate */
+                       parent = mono_class_inflate_generic_class_checked (parent, context, error);
 
                if (parent == NULL) {
-                       mono_class_set_failure_from_loader_error (class, error, g_strdup_printf ("Could not load parent, token is %x", parent_token));
+                       mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup (mono_error_get_message (error)));
                        goto parent_failure;
                }
 
@@ -5763,11 +5852,11 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError
        }
 
        if (class->enumtype) {
-               MonoType *enum_basetype = mono_class_find_enum_basetype (class);
+               MonoType *enum_basetype = mono_class_find_enum_basetype (class, error);
                if (!enum_basetype) {
                        /*set it to a default value as the whole runtime can't handle this to be null*/
                        class->cast_class = class->element_class = mono_defaults.int32_class;
-                       mono_class_set_failure_and_error (class, error, "Could not enum basetype");
+                       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 ());
@@ -5781,8 +5870,8 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError
         * We must do this after the class has been constructed to make certain recursive scenarios
         * work.
         */
-       if (class->generic_container && !mono_metadata_load_generic_param_constraints_full (image, type_token, class->generic_container)){
-               mono_class_set_failure_from_loader_error (class, error, g_strdup ("Could not load generic parameter constraints"));
+       if (class->generic_container && !mono_metadata_load_generic_param_constraints_checked (image, type_token, class->generic_container, error)) {
+               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 ());
@@ -6036,8 +6125,11 @@ make_generic_param_class (MonoGenericParam *param, MonoImage *image, gboolean is
 
 #define FAST_CACHE_SIZE 16
 
+/*
+ * LOCKING: Takes the image lock depending on @take_lock.
+ */
 static MonoClass *
-get_anon_gparam_class (MonoGenericParam *param, gboolean is_mvar)
+get_anon_gparam_class (MonoGenericParam *param, gboolean is_mvar, gboolean take_lock)
 {
        int n = mono_generic_param_num (param) | ((guint32)param->serial << 16);
        MonoImage *image = param->image;
@@ -6051,26 +6143,33 @@ get_anon_gparam_class (MonoGenericParam *param, gboolean is_mvar)
                else
                        return image->var_cache_fast ? image->var_cache_fast [n] : NULL;
        } else {
+               MonoClass *klass = NULL;
                ht = is_mvar ? image->mvar_cache_slow : image->var_cache_slow;
-               return ht ? g_hash_table_lookup (ht, GINT_TO_POINTER (n)) : NULL;
+               if (ht) {
+                       if (take_lock)
+                               mono_image_lock (image);
+                       klass = g_hash_table_lookup (ht, GINT_TO_POINTER (n));
+                       if (take_lock)
+                               mono_image_unlock (image);
+               }
+               return klass;
        }
 }
 
 /*
- * LOCKING: Acquires the loader lock.
+ * LOCKING: Image lock (param->image) must be held
  */
 static void
 set_anon_gparam_class (MonoGenericParam *param, gboolean is_mvar, MonoClass *klass)
 {
        int n = mono_generic_param_num (param) | ((guint32)param->serial << 16);
        MonoImage *image = param->image;
-       GHashTable *ht;
 
        g_assert (image);
 
        if (n < FAST_CACHE_SIZE) {
                if (is_mvar) {
-                       /* No locking needed */
+                       /* Requires locking to avoid droping an already published class */
                        if (!image->mvar_cache_fast)
                                image->mvar_cache_fast = mono_image_alloc0 (image, sizeof (MonoClass*) * FAST_CACHE_SIZE);
                        image->mvar_cache_fast [n] = klass;
@@ -6079,54 +6178,42 @@ set_anon_gparam_class (MonoGenericParam *param, gboolean is_mvar, MonoClass *kla
                                image->var_cache_fast = mono_image_alloc0 (image, sizeof (MonoClass*) * FAST_CACHE_SIZE);
                        image->var_cache_fast [n] = klass;
                }
-               return;
-       }
-       ht = is_mvar ? image->mvar_cache_slow : image->var_cache_slow;
-       if (!ht) {
-               mono_loader_lock ();
-               ht = is_mvar ? image->mvar_cache_slow : image->var_cache_slow;
+       } else {
+               GHashTable *ht = is_mvar ? image->mvar_cache_slow : image->var_cache_slow;
                if (!ht) {
-                       ht = g_hash_table_new (NULL, NULL);
-                       mono_memory_barrier ();
-                       if (is_mvar)
-                               image->mvar_cache_slow = ht;
-                       else
-                               image->var_cache_slow = ht;
+                       ht = is_mvar ? image->mvar_cache_slow : image->var_cache_slow;
+                       if (!ht) {
+                               ht = g_hash_table_new (NULL, NULL);
+                               mono_memory_barrier ();
+                               if (is_mvar)
+                                       image->mvar_cache_slow = ht;
+                               else
+                                       image->var_cache_slow = ht;
+                       }
                }
-               mono_loader_unlock ();
+               g_hash_table_insert (ht, GINT_TO_POINTER (n), klass);
        }
-
-       g_hash_table_insert (ht, GINT_TO_POINTER (n), klass);
 }
 
 /*
- * LOCKING: Acquires the loader lock.
+ * LOCKING: Acquires the image lock (@image).
  */
 MonoClass *
 mono_class_from_generic_parameter (MonoGenericParam *param, MonoImage *image, gboolean is_mvar)
 {
        MonoGenericContainer *container = mono_generic_param_owner (param);
-       MonoGenericParamInfo *pinfo;
-       MonoClass *klass;
-
-       mono_loader_lock ();
+       MonoGenericParamInfo *pinfo = NULL;
+       MonoClass *klass, *klass2;
 
        if (container) {
                pinfo = mono_generic_param_info (param);
-               if (pinfo->pklass) {
-                       mono_loader_unlock ();
-                       return pinfo->pklass;
-               }
+               klass = pinfo->pklass;
        } else {
-               pinfo = NULL;
                image = NULL;
-
-               klass = get_anon_gparam_class (param, is_mvar);
-               if (klass) {
-                       mono_loader_unlock ();
-                       return klass;
-               }
+               klass = get_anon_gparam_class (param, is_mvar, TRUE);
        }
+       if (klass)
+               return klass;
 
        if (!image && container) {
                if (is_mvar) {
@@ -6144,15 +6231,30 @@ mono_class_from_generic_parameter (MonoGenericParam *param, MonoImage *image, gb
 
        mono_memory_barrier ();
 
+       if (!image) //FIXME is this only needed by monodis? Can't we fix monodis instead of having this hack?
+               image = mono_defaults.corlib;
+
+       mono_image_lock (image);
        if (container)
-               pinfo->pklass = klass;
+               klass2 = pinfo->pklass;
        else
-               set_anon_gparam_class (param, is_mvar, klass);
+               klass2 = get_anon_gparam_class (param, is_mvar, FALSE);
 
-       mono_loader_unlock ();
+       if (klass2) {
+               klass = klass2;
+       } else {
+               if (container)
+                       pinfo->pklass = klass;
+               else
+                       set_anon_gparam_class (param, is_mvar, klass);
+       }
+       mono_image_unlock (image);
 
        /* FIXME: Should this go inside 'make_generic_param_klass'? */
-       mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
+       if (klass2)
+               mono_profiler_class_loaded (klass2, MONO_PROFILE_FAILED);
+       else
+               mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
 
        return klass;
 }
@@ -6168,15 +6270,15 @@ mono_ptr_class_get (MonoType *type)
        el_class = mono_class_from_mono_type (type);
        image = el_class->image;
 
-       mono_loader_lock ();
-
-       if (!image->ptr_cache)
-               image->ptr_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
-
-       if ((result = g_hash_table_lookup (image->ptr_cache, el_class))) {
-               mono_loader_unlock ();
-               return result;
+       mono_image_lock (image);
+       if (image->ptr_cache) {
+               if ((result = g_hash_table_lookup (image->ptr_cache, el_class))) {
+                       mono_image_unlock (image);
+                       return result;
+               }
        }
+       mono_image_unlock (image);
+       
        result = mono_image_alloc0 (image, sizeof (MonoClass));
 
        classes_size += sizeof (MonoClass);
@@ -6203,9 +6305,19 @@ mono_ptr_class_get (MonoType *type)
 
        mono_class_setup_supertypes (result);
 
+       mono_image_lock (image);
+       if (image->ptr_cache) {
+               MonoClass *result2;
+               if ((result2 = g_hash_table_lookup (image->ptr_cache, el_class))) {
+                       mono_image_unlock (image);
+                       mono_profiler_class_loaded (result, MONO_PROFILE_FAILED);
+                       return result2;
+               }
+       } else {
+               image->ptr_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
+       }
        g_hash_table_insert (image->ptr_cache, el_class, result);
-
-       mono_loader_unlock ();
+       mono_image_unlock (image);
 
        mono_profiler_class_loaded (result, MONO_PROFILE_OK);
 
@@ -6335,23 +6447,20 @@ mono_class_from_mono_type (MonoType *type)
 static MonoType *
 mono_type_retrieve_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context, gboolean *did_inflate, MonoError *error)
 {
-       MonoType *t = mono_type_create_from_typespec (image, type_spec);
+       MonoType *t = mono_type_create_from_typespec_checked (image, type_spec, error);
 
-       mono_error_init (error);
        *did_inflate = FALSE;
 
-       if (!t) {
-               char *name = mono_class_name_from_token (image, type_spec);
-               char *assembly = mono_assembly_name_from_token (image, type_spec);
-               mono_error_set_type_load_name (error, name, assembly, "Could not resolve typespec token %08x", type_spec);
+       if (!t)
                return NULL;
-       }
 
        if (context && (context->class_inst || context->method_inst)) {
                MonoType *inflated = inflate_generic_type (NULL, t, context, error);
 
-               if (!mono_error_ok (error))
+               if (!mono_error_ok (error)) {
+                       g_assert (!mono_loader_get_last_error ());
                        return NULL;
+               }
 
                if (inflated) {
                        t = inflated;
@@ -6845,11 +6954,17 @@ mono_class_get_field_default_value (MonoClassField *field, MonoTypeEnum *def_typ
        g_assert (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT);
 
        if (!klass->ext || !klass->ext->field_def_values) {
-               mono_loader_lock ();
+               MonoFieldDefaultValue *def_values;
+
                mono_class_alloc_ext (klass);
+
+               def_values = mono_class_alloc0 (klass, sizeof (MonoFieldDefaultValue) * klass->field.count);
+
+               mono_image_lock (klass->image);
+               mono_memory_barrier ();
                if (!klass->ext->field_def_values)
-                       klass->ext->field_def_values = mono_class_alloc0 (klass, sizeof (MonoFieldDefaultValue) * klass->field.count);
-               mono_loader_unlock ();
+                       klass->ext->field_def_values = def_values;
+               mono_image_unlock (klass->image);
        }
 
        field_index = mono_field_get_index (field);
@@ -7058,18 +7173,18 @@ mono_assembly_name_from_token (MonoImage *image, guint32 type_token)
                }
                mono_metadata_decode_row (t, idx-1, cols, MONO_TYPEREF_SIZE);
 
-               idx = cols [MONO_TYPEREF_SCOPE] >> MONO_RESOLTION_SCOPE_BITS;
-               switch (cols [MONO_TYPEREF_SCOPE] & MONO_RESOLTION_SCOPE_MASK) {
-               case MONO_RESOLTION_SCOPE_MODULE:
+               idx = cols [MONO_TYPEREF_SCOPE] >> MONO_RESOLUTION_SCOPE_BITS;
+               switch (cols [MONO_TYPEREF_SCOPE] & MONO_RESOLUTION_SCOPE_MASK) {
+               case MONO_RESOLUTION_SCOPE_MODULE:
                        /* FIXME: */
                        return g_strdup ("");
-               case MONO_RESOLTION_SCOPE_MODULEREF:
+               case MONO_RESOLUTION_SCOPE_MODULEREF:
                        /* FIXME: */
                        return g_strdup ("");
-               case MONO_RESOLTION_SCOPE_TYPEREF:
+               case MONO_RESOLUTION_SCOPE_TYPEREF:
                        /* FIXME: */
                        return g_strdup ("");
-               case MONO_RESOLTION_SCOPE_ASSEMBLYREF:
+               case MONO_RESOLUTION_SCOPE_ASSEMBLYREF:
                        mono_assembly_get_assemblyref (image, idx - 1, &aname);
                        return mono_stringify_assembly_name (&aname);
                default:
@@ -7092,6 +7207,7 @@ mono_assembly_name_from_token (MonoImage *image, guint32 type_token)
  * @image: the image where the class resides
  * @type_token: the token for the class
  * @context: the generic context used to evaluate generic instantiations in
+ * @deprecated: Functions that expose MonoGenericContext are going away in mono 4.0
  *
  * Returns: the MonoClass that represents @type_token in @image
  */
@@ -7099,49 +7215,79 @@ MonoClass *
 mono_class_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *context)
 {
        MonoError error;
+       MonoClass *class;
+       class = mono_class_get_checked (image, type_token, &error);
+
+       if (class && context && mono_metadata_token_table (type_token) == MONO_TABLE_TYPESPEC)
+               class = mono_class_inflate_generic_class_checked (class, context, &error);
+
+       if (!class) {
+               mono_loader_set_error_from_mono_error (&error);
+               mono_error_cleanup (&error); /*FIXME don't swallow this error */
+       }
+       return class;
+}
+
+
+MonoClass *
+mono_class_get_and_inflate_typespec_checked (MonoImage *image, guint32 type_token, MonoGenericContext *context, MonoError *error)
+{
+       MonoClass *class;
+
+       mono_error_init (error);
+       class = mono_class_get_checked (image, type_token, error);
+
+       if (class && context && mono_metadata_token_table (type_token) == MONO_TABLE_TYPESPEC)
+               class = mono_class_inflate_generic_class_checked (class, context, error);
+
+       return class;
+}
+/**
+ * mono_class_get_checked:
+ * @image: the image where the class resides
+ * @type_token: the token for the class
+ * @error: error object to return any error
+ *
+ * Returns: the MonoClass that represents @type_token in @image
+ */
+MonoClass *
+mono_class_get_checked (MonoImage *image, guint32 type_token, MonoError *error)
+{
        MonoClass *class = NULL;
 
+       mono_error_init (error);
+
        if (image_is_dynamic (image)) {
                int table = mono_metadata_token_table (type_token);
 
                if (table != MONO_TABLE_TYPEDEF && table != MONO_TABLE_TYPEREF && table != MONO_TABLE_TYPESPEC) {
-                       mono_loader_set_error_bad_image (g_strdup ("Bad type token."));
+                       mono_error_set_bad_image (error, image,"Bad token table for dynamic image: %x", table);
                        return NULL;
                }
-               return mono_lookup_dynamic_token (image, type_token, context);
+               class = mono_lookup_dynamic_token (image, type_token, NULL); /*FIXME proper error handling*/
+               goto done;
        }
 
        switch (type_token & 0xff000000){
        case MONO_TOKEN_TYPE_DEF:
-               class = mono_class_create_from_typedef (image, type_token, &error);
-               if (!mono_error_ok (&error)) {
-                       mono_loader_set_error_from_mono_error (&error);
-                       /*FIXME don't swallow the error message*/
-                       mono_error_cleanup (&error);
-                       return NULL;
-               }
+               class = mono_class_create_from_typedef (image, type_token, error);
                break;          
        case MONO_TOKEN_TYPE_REF:
-               class = mono_class_from_typeref (image, type_token);
+               class = mono_class_from_typeref_checked (image, type_token, error);
                break;
        case MONO_TOKEN_TYPE_SPEC:
-               class = mono_class_create_from_typespec (image, type_token, context, &error);
-               if (!mono_error_ok (&error)) {
-                       /*FIXME don't swallow the error message*/
-                       mono_error_cleanup (&error);
-               }
+               class = mono_class_create_from_typespec (image, type_token, NULL, error);
                break;
        default:
-               g_warning ("unknown token type %x", type_token & 0xff000000);
-               g_assert_not_reached ();
+               mono_error_set_bad_image (error, image, "Unknown type token %x", type_token & 0xff000000);
        }
 
-       if (!class){
+done:
+       /* Generic case, should be avoided for when a better error is possible. */
+       if (!class && mono_error_ok (error)) {
                char *name = mono_class_name_from_token (image, type_token);
                char *assembly = mono_assembly_name_from_token (image, type_token);
-               mono_loader_set_error_type_load (name, assembly);
-               g_free (name);
-               g_free (assembly);
+               mono_error_set_type_load_name (error, name, assembly, "Could not resolve type with token %08x", type_token);
        }
 
        return class;
@@ -7149,42 +7295,44 @@ mono_class_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *c
 
 
 /**
- * mono_type_get_full:
+ * mono_type_get_checked:
  * @image: the image where the type resides
  * @type_token: the token for the type
  * @context: the generic context used to evaluate generic instantiations in
+ * @error: Error handling context
  *
  * This functions exists to fullfill the fact that sometimes it's desirable to have access to the 
  * 
  * Returns: the MonoType that represents @type_token in @image
  */
 MonoType *
-mono_type_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *context)
+mono_type_get_checked (MonoImage *image, guint32 type_token, MonoGenericContext *context, MonoError *error)
 {
-       MonoError error;
        MonoType *type = NULL;
        gboolean inflated = FALSE;
 
+       mono_error_init (error);
+
        //FIXME: this will not fix the very issue for which mono_type_get_full exists -but how to do it then?
        if (image_is_dynamic (image))
                return mono_class_get_type (mono_lookup_dynamic_token (image, type_token, context));
 
        if ((type_token & 0xff000000) != MONO_TOKEN_TYPE_SPEC) {
-               MonoClass *class = mono_class_get_full (image, type_token, context);
-               return class ? mono_class_get_type (class) : NULL;
-       }
+               MonoClass *class = mono_class_get_checked (image, type_token, error);
 
-       type = mono_type_retrieve_from_typespec (image, type_token, context, &inflated, &error);
+               if (!class) {
+                       g_assert (!mono_loader_get_last_error ());
+                       return NULL;
+               }
 
-       if (!mono_error_ok (&error)) {
-               /*FIXME don't swalloc the error message.*/
-               char *name = mono_class_name_from_token (image, type_token);
-               char *assembly = mono_assembly_name_from_token (image, type_token);
+               g_assert (class);
+               return mono_class_get_type (class);
+       }
 
-               g_warning ("Error loading type %s from %s due to %s", name, assembly, mono_error_get_message (&error));
+       type = mono_type_retrieve_from_typespec (image, type_token, context, &inflated, error);
 
-               mono_error_cleanup (&error);
-               mono_loader_set_error_type_load (name, assembly);
+       if (!type) {
+               g_assert (!mono_loader_get_last_error ());
                return NULL;
        }
 
@@ -7344,6 +7492,7 @@ find_nocase (gpointer key, gpointer value, gpointer user_data)
  * @image: The MonoImage where the type is looked up in
  * @name_space: the type namespace
  * @name: the type short name.
+ * @deprecated: use the _checked variant
  *
  * Obtains a MonoClass with a given namespace and a given name which
  * is located in the given MonoImage.   The namespace and name
@@ -7351,6 +7500,15 @@ find_nocase (gpointer key, gpointer value, gpointer user_data)
  */
 MonoClass *
 mono_class_from_name_case (MonoImage *image, const char* name_space, const char *name)
+{
+       MonoError error;
+       MonoClass *res = mono_class_from_name_case_checked (image, name_space, name, &error);
+       g_assert (!mono_error_ok (&error));
+       return res;
+}
+
+MonoClass *
+mono_class_from_name_case_checked (MonoImage *image, const char* name_space, const char *name, MonoError *error)
 {
        MonoTableInfo  *t = &image->tables [MONO_TABLE_TYPEDEF];
        guint32 cols [MONO_TYPEDEF_SIZE];
@@ -7358,6 +7516,8 @@ mono_class_from_name_case (MonoImage *image, const char* name_space, const char
        const char *nspace;
        guint32 i, visib;
 
+       mono_error_init (error);
+
        if (image_is_dynamic (image)) {
                guint32 token = 0;
                FindUserData user_data;
@@ -7386,7 +7546,7 @@ mono_class_from_name_case (MonoImage *image, const char* name_space, const char
                mono_image_unlock (image);
                
                if (token)
-                       return mono_class_get (image, MONO_TOKEN_TYPE_DEF | token);
+                       return mono_class_get_checked (image, MONO_TOKEN_TYPE_DEF | token, error);
                else
                        return NULL;
 
@@ -7405,7 +7565,7 @@ mono_class_from_name_case (MonoImage *image, const char* name_space, const char
                n = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
                nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
                if (mono_utf8_strcasecmp (n, name) == 0 && mono_utf8_strcasecmp (nspace, name_space) == 0)
-                       return mono_class_get (image, MONO_TOKEN_TYPE_DEF | i);
+                       return mono_class_get_checked (image, MONO_TOKEN_TYPE_DEF | i, error);
        }
        return NULL;
 }
@@ -8279,26 +8439,34 @@ mono_ldtoken (MonoImage *image, guint32 token, MonoClass **handle_class,
        case MONO_TOKEN_TYPE_DEF:
        case MONO_TOKEN_TYPE_REF:
        case MONO_TOKEN_TYPE_SPEC: {
+               MonoError error;
                MonoType *type;
                if (handle_class)
                        *handle_class = mono_defaults.typehandle_class;
-               type = mono_type_get_full (image, token, context);
-               if (!type)
+               type = mono_type_get_checked (image, token, context, &error);
+               if (!type) {
+                       mono_loader_set_error_from_mono_error (&error);
+                       mono_error_cleanup (&error); /* FIXME Don't swallow the error */
                        return NULL;
+               }
                mono_class_init (mono_class_from_mono_type (type));
                /* We return a MonoType* as handle */
                return type;
        }
        case MONO_TOKEN_FIELD_DEF: {
                MonoClass *class;
+               MonoError error;
                guint32 type = mono_metadata_typedef_from_field (image, mono_metadata_token_index (token));
                if (!type)
                        return NULL;
                if (handle_class)
                        *handle_class = mono_defaults.fieldhandle_class;
-               class = mono_class_get_full (image, MONO_TOKEN_TYPE_DEF | type, context);
-               if (!class)
+               class = mono_class_get_and_inflate_typespec_checked (image, MONO_TOKEN_TYPE_DEF | type, context, &error);
+               if (!class) {
+                       mono_loader_set_error_from_mono_error (&error);
+                       mono_error_cleanup (&error); /* FIXME Don't swallow the error */
                        return NULL;
+               }
                mono_class_init (class);
                return mono_class_get_field (class, token);
        }
@@ -8317,11 +8485,16 @@ mono_ldtoken (MonoImage *image, guint32 token, MonoClass **handle_class,
                sig = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]);
                mono_metadata_decode_blob_size (sig, &sig);
                if (*sig == 0x6) { /* it's a field */
+                       MonoError error;
                        MonoClass *klass;
                        MonoClassField *field;
-                       field = mono_field_from_token (image, token, &klass, context);
+                       field = mono_field_from_token_checked (image, token, &klass, context, &error);
                        if (handle_class)
                                *handle_class = mono_defaults.fieldhandle_class;
+                       if (!field) {
+                               mono_loader_set_error_from_mono_error (&error);
+                               mono_error_cleanup (&error); /* FIXME Don't swallow the error */
+                       }
                        return field;
                } else {
                        MonoMethod *meth;
@@ -8886,6 +9059,58 @@ mono_class_get_interfaces (MonoClass* klass, gpointer *iter)
        return NULL;
 }
 
+static void
+setup_nested_types (MonoClass *klass)
+{
+       MonoError error;
+       GList *classes, *nested_classes, *l;
+       int i;
+
+       if (klass->nested_classes_inited)
+               return;
+
+       if (!klass->type_token)
+               klass->nested_classes_inited = TRUE;
+
+       i = mono_metadata_nesting_typedef (klass->image, klass->type_token, 1);
+       classes = NULL;
+       while (i) {
+               MonoClass* nclass;
+               guint32 cols [MONO_NESTED_CLASS_SIZE];
+               mono_metadata_decode_row (&klass->image->tables [MONO_TABLE_NESTEDCLASS], i - 1, cols, MONO_NESTED_CLASS_SIZE);
+               nclass = mono_class_create_from_typedef (klass->image, MONO_TOKEN_TYPE_DEF | cols [MONO_NESTED_CLASS_NESTED], &error);
+               if (!mono_error_ok (&error)) {
+                       /*FIXME don't swallow the error message*/
+                       mono_error_cleanup (&error);
+
+                       i = mono_metadata_nesting_typedef (klass->image, klass->type_token, i + 1);
+                       continue;
+               }
+
+               classes = g_list_prepend (classes, nclass);
+
+               i = mono_metadata_nesting_typedef (klass->image, klass->type_token, i + 1);
+       }
+
+       mono_class_alloc_ext (klass);
+
+       nested_classes = NULL;
+       for (l = classes; l; l = l->next)
+               nested_classes = g_list_prepend_image (klass->image, nested_classes, l->data);
+       g_list_free (classes);
+
+       mono_image_lock (klass->image);
+
+       mono_memory_barrier ();
+       if (!klass->nested_classes_inited) {
+               klass->ext->nested_classes = nested_classes;
+               mono_memory_barrier ();
+               klass->nested_classes_inited = TRUE;
+       }
+
+       mono_image_unlock (klass->image);
+}
+
 /**
  * mono_class_get_nested_types
  * @klass: the MonoClass to act on
@@ -8902,40 +9127,12 @@ mono_class_get_interfaces (MonoClass* klass, gpointer *iter)
 MonoClass*
 mono_class_get_nested_types (MonoClass* klass, gpointer *iter)
 {
-       MonoError error;
        GList *item;
-       int i;
 
        if (!iter)
                return NULL;
-       if (!klass->nested_classes_inited) {
-               if (!klass->type_token)
-                       klass->nested_classes_inited = TRUE;
-               mono_loader_lock ();
-               if (!klass->nested_classes_inited) {
-                       i = mono_metadata_nesting_typedef (klass->image, klass->type_token, 1);
-                       while (i) {
-                               MonoClass* nclass;
-                               guint32 cols [MONO_NESTED_CLASS_SIZE];
-                               mono_metadata_decode_row (&klass->image->tables [MONO_TABLE_NESTEDCLASS], i - 1, cols, MONO_NESTED_CLASS_SIZE);
-                               nclass = mono_class_create_from_typedef (klass->image, MONO_TOKEN_TYPE_DEF | cols [MONO_NESTED_CLASS_NESTED], &error);
-                               if (!mono_error_ok (&error)) {
-                                       /*FIXME don't swallow the error message*/
-                                       mono_error_cleanup (&error);
-
-                                       i = mono_metadata_nesting_typedef (klass->image, klass->type_token, i + 1);
-                                       continue;
-                               }
-                               mono_class_alloc_ext (klass);
-                               klass->ext->nested_classes = g_list_prepend_image (klass->image, klass->ext->nested_classes, nclass);
-
-                               i = mono_metadata_nesting_typedef (klass->image, klass->type_token, i + 1);
-                       }
-               }
-               mono_memory_barrier ();
-               klass->nested_classes_inited = TRUE;
-               mono_loader_unlock ();
-       }
+       if (!klass->nested_classes_inited)
+               setup_nested_types (klass);
 
        if (!*iter) {
                /* start from the first */
@@ -9076,15 +9273,19 @@ mono_field_get_rva (MonoClassField *field)
        guint32 rva;
        int field_index;
        MonoClass *klass = field->parent;
+       MonoFieldDefaultValue *field_def_values;
 
        g_assert (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA);
 
        if (!klass->ext || !klass->ext->field_def_values) {
-               mono_loader_lock ();
                mono_class_alloc_ext (klass);
+
+               field_def_values = mono_class_alloc0 (klass, sizeof (MonoFieldDefaultValue) * klass->field.count);
+
+               mono_image_lock (klass->image);
                if (!klass->ext->field_def_values)
-                       klass->ext->field_def_values = mono_class_alloc0 (klass, sizeof (MonoFieldDefaultValue) * klass->field.count);
-               mono_loader_unlock ();
+                       klass->ext->field_def_values = field_def_values;
+               mono_image_unlock (klass->image);
        }
 
        field_index = mono_field_get_index (field);
@@ -9405,6 +9606,8 @@ mono_class_get_exception_data (MonoClass *klass)
 void
 mono_classes_init (void)
 {
+       mono_mutex_init (&classes_mutex);
+
        mono_counters_register ("Inflated methods size",
                                                        MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_methods_size);
        mono_counters_register ("Inflated classes",
@@ -9428,6 +9631,7 @@ mono_classes_cleanup (void)
        if (global_interface_bitset)
                mono_bitset_free (global_interface_bitset);
        global_interface_bitset = NULL;
+       mono_mutex_destroy (&classes_mutex);
 }
 
 /**
@@ -10032,15 +10236,22 @@ mono_class_setup_interface_id (MonoClass *class)
  * mono_class_alloc_ext:
  *
  *   Allocate klass->ext if not already done.
- * LOCKING: Assumes the loader lock is held.
  */
 void
 mono_class_alloc_ext (MonoClass *klass)
 {
-       if (!klass->ext) {
-               klass->ext = mono_class_alloc0 (klass, sizeof (MonoClassExt));
-               class_ext_size += sizeof (MonoClassExt);
-       }
+       MonoClassExt *ext;
+
+       if (klass->ext)
+               return;
+
+       ext = mono_class_alloc0 (klass, sizeof (MonoClassExt));
+       mono_image_lock (klass->image);
+       mono_memory_barrier ();
+       if (!klass->ext)
+               klass->ext = ext;
+       class_ext_size += sizeof (MonoClassExt);
+       mono_image_unlock (klass->image);
 }
 
 /*
@@ -10053,53 +10264,62 @@ mono_class_alloc_ext (MonoClass *klass)
 void
 mono_class_setup_interfaces (MonoClass *klass, MonoError *error)
 {
-       int i;
+       int i, interface_count;
+       MonoClass **interfaces;
 
        mono_error_init (error);
 
        if (klass->interfaces_inited)
                return;
 
-       mono_loader_lock ();
-
-       if (klass->interfaces_inited) {
-               mono_loader_unlock ();
-               return;
-       }
-
        if (klass->rank == 1 && klass->byval_arg.type != MONO_TYPE_ARRAY) {
                MonoType *args [1];
 
                /* generic IList, ICollection, IEnumerable */
-               klass->interface_count = mono_defaults.generic_ireadonlylist_class ? 2 : 1;
-               klass->interfaces = mono_image_alloc0 (klass->image, sizeof (MonoClass*) * klass->interface_count);
+               interface_count = mono_defaults.generic_ireadonlylist_class ? 2 : 1;
+               interfaces = mono_image_alloc0 (klass->image, sizeof (MonoClass*) * interface_count);
 
                args [0] = &klass->element_class->byval_arg;
-               klass->interfaces [0] = mono_class_bind_generic_parameters (
+               interfaces [0] = mono_class_bind_generic_parameters (
                        mono_defaults.generic_ilist_class, 1, args, FALSE);
-               if (klass->interface_count > 1)
-                       klass->interfaces [1] = mono_class_bind_generic_parameters (
+               if (interface_count > 1)
+                       interfaces [1] = mono_class_bind_generic_parameters (
                           mono_defaults.generic_ireadonlylist_class, 1, args, FALSE);
        } else if (klass->generic_class) {
                MonoClass *gklass = klass->generic_class->container_class;
 
-               klass->interface_count = gklass->interface_count;
-               klass->interfaces = mono_class_new0 (klass, MonoClass *, klass->interface_count);
-               for (i = 0; i < klass->interface_count; i++) {
-                       klass->interfaces [i] = mono_class_inflate_generic_class_checked (gklass->interfaces [i], mono_generic_class_get_context (klass->generic_class), error);
+               mono_class_setup_interfaces (gklass, error);
+               if (!mono_error_ok (error)) {
+                       mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Could not setup the interfaces"));
+                       return;
+               }
+
+               interface_count = gklass->interface_count;
+               interfaces = mono_class_new0 (klass, MonoClass *, interface_count);
+               for (i = 0; i < interface_count; i++) {
+                       interfaces [i] = mono_class_inflate_generic_class_checked (gklass->interfaces [i], mono_generic_class_get_context (klass->generic_class), error);
                        if (!mono_error_ok (error)) {
                                mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Could not setup the interfaces"));
-                               klass->interfaces = NULL;
                                return;
                        }
                }
+       } else {
+               interface_count = 0;
+               interfaces = NULL;
        }
 
-       mono_memory_barrier ();
+       mono_image_lock (klass->image);
 
-       klass->interfaces_inited = TRUE;
+       if (!klass->interfaces_inited) {
+               klass->interface_count = interface_count;
+               klass->interfaces = interfaces;
 
-       mono_loader_unlock ();
+               mono_memory_barrier ();
+
+               klass->interfaces_inited = TRUE;
+       }
+
+       mono_image_unlock (klass->image);
 }
 
 static void