Merge pull request #1455 from esdrubal/caching
[mono.git] / mono / metadata / icall.c
index 3bdaefe42bbb8c445ad5558f58f7db3dc30a57fc..bc3bb782175165fb6805fc1a08dc21aa92dc20f2 100644 (file)
@@ -5,10 +5,11 @@
  *   Dietmar Maurer (dietmar@ximian.com)
  *   Paolo Molaro (lupus@ximian.com)
  *      Patrik Torstensson (patrik.torstensson@labs2.com)
+ *   Marek Safar (marek.safar@gmail.com)
  *
  * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
  * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
- * Copyright 2011-2012 Xamarin Inc (http://www.xamarin.com).
+ * Copyright 2011-2014 Xamarin Inc (http://www.xamarin.com).
  */
 
 #include <config.h>
@@ -74,6 +75,7 @@
 #include <mono/metadata/mono-ptr-array.h>
 #include <mono/metadata/verify-internals.h>
 #include <mono/metadata/runtime.h>
+#include <mono/metadata/file-mmap.h>
 #include <mono/io-layer/io-layer.h>
 #include <mono/utils/strtod.h>
 #include <mono/utils/monobitset.h>
@@ -85,6 +87,8 @@
 #include <mono/utils/mono-io-portability.h>
 #include <mono/utils/mono-digest.h>
 #include <mono/utils/bsearch.h>
+#include <mono/utils/mono-mutex.h>
+#include <mono/utils/mono-threads.h>
 
 #if defined (HOST_WIN32)
 #include <windows.h>
@@ -123,17 +127,12 @@ mono_double_ParseImpl (char *ptr, double *result)
 
        MONO_ARCH_SAVE_REGS;
 
-#ifdef __arm__
-       if (*ptr)
-               *result = strtod (ptr, &endptr);
-#else
        if (*ptr){
                /* mono_strtod () is not thread-safe */
-               EnterCriticalSection (&mono_strtod_mutex);
+               mono_mutex_lock (&mono_strtod_mutex);
                *result = mono_strtod (ptr, &endptr);
-               LeaveCriticalSection (&mono_strtod_mutex);
+               mono_mutex_unlock (&mono_strtod_mutex);
        }
-#endif
 
        if (!*ptr || (endptr && *endptr))
                return FALSE;
@@ -238,7 +237,7 @@ ves_icall_System_Array_SetValueImpl (MonoArray *this, MonoObject *value, guint32
        }
 
        if (!value) {
-               mono_gc_bzero (ea, esize);
+               mono_gc_bzero_atomic (ea, esize);
                return;
        }
 
@@ -301,7 +300,7 @@ ves_icall_System_Array_SetValueImpl (MonoArray *this, MonoObject *value, guint32
                if (ec->has_references)
                        mono_value_copy (ea, (char*)value + sizeof (MonoObject), ec);
                else
-                       mono_gc_memmove (ea, (char *)value + sizeof (MonoObject), esize);
+                       mono_gc_memmove_atomic (ea, (char *)value + sizeof (MonoObject), esize);
                return;
        }
 
@@ -685,7 +684,7 @@ ICALL_EXPORT void
 ves_icall_System_Array_ClearInternal (MonoArray *arr, int idx, int length)
 {
        int sz = mono_array_element_size (mono_object_class (arr));
-       mono_gc_bzero (mono_array_addr_with_size_fast (arr, sz, idx), length * sz);
+       mono_gc_bzero_atomic (mono_array_addr_with_size_fast (arr, sz, idx), length * sz);
 }
 
 ICALL_EXPORT gboolean
@@ -743,7 +742,7 @@ ves_icall_System_Array_FastCopy (MonoArray *source, int source_idx, MonoArray* d
                        mono_value_copy_array (dest, dest_idx, source_addr, length);
                } else {
                        dest_addr = mono_array_addr_with_size_fast (dest, element_size, dest_idx);
-                       mono_gc_memmove (dest_addr, source_addr, element_size * length);
+                       mono_gc_memmove_atomic (dest_addr, source_addr, element_size * length);
                }
        } else {
                mono_array_memcpy_refs_fast (dest, dest_idx, source, source_idx, length);
@@ -768,7 +767,7 @@ ves_icall_System_Array_GetGenericValueImpl (MonoObject *this, guint32 pos, gpoin
        esize = mono_array_element_size (ac);
        ea = (gpointer*)((char*)ao->vector + (pos * esize));
 
-       mono_gc_memmove (value, ea, esize);
+       mono_gc_memmove_atomic (value, ea, esize);
 }
 
 ICALL_EXPORT void
@@ -797,7 +796,7 @@ ves_icall_System_Array_SetGenericValueImpl (MonoObject *this, guint32 pos, gpoin
                if (ec->has_references)
                        mono_gc_wbarrier_value_copy (ea, value, 1, ec);
                else
-                       mono_gc_memmove (ea, value, esize);
+                       mono_gc_memmove_atomic (ea, value, esize);
        }
 }
 
@@ -908,11 +907,12 @@ ves_icall_System_Runtime_CompilerServices_RuntimeHelpers_RunClassConstructor (Mo
 ICALL_EXPORT void
 ves_icall_System_Runtime_CompilerServices_RuntimeHelpers_RunModuleConstructor (MonoImage *image)
 {
-       MONO_ARCH_SAVE_REGS;
+       MonoError error;
 
        mono_image_check_for_module_cctor (image);
        if (image->has_module_cctor) {
-               MonoClass *module_klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | 1);
+               MonoClass *module_klass = mono_class_get_checked (image, MONO_TOKEN_TYPE_DEF | 1, &error);
+               mono_error_raise_exception (&error);
                /*It's fine to raise the exception here*/
                mono_runtime_class_init (mono_class_vtable_full (mono_domain_get (), module_klass, TRUE));
        }
@@ -926,10 +926,15 @@ ves_icall_System_Runtime_CompilerServices_RuntimeHelpers_SufficientExecutionStac
        size_t stack_size;
        /* later make this configurable and per-arch */
        int min_size = 4096 * 4 * sizeof (void*);
-       mono_thread_get_stack_bounds (&stack_addr, &stack_size);
+       mono_thread_info_get_stack_bounds (&stack_addr, &stack_size);
        /* if we have no info we are optimistic and assume there is enough room */
        if (!stack_addr)
                return TRUE;
+#ifdef HOST_WIN32
+       // FIXME: Windows dynamically extends the stack, so stack_addr might be close
+       // to the current sp
+       return TRUE;
+#endif
        current = (guint8 *)&stack_addr;
        if (current > stack_addr) {
                if ((current - stack_addr) < min_size)
@@ -956,7 +961,7 @@ ves_icall_System_ValueType_InternalGetHashCode (MonoObject *this, MonoArray **fi
        MonoObject **values = NULL;
        MonoObject *o;
        int count = 0;
-       gint32 result = 0;
+       gint32 result = (int)(gsize)mono_defaults.int32_class;
        MonoClassField* field;
        gpointer iter;
 
@@ -965,7 +970,7 @@ ves_icall_System_ValueType_InternalGetHashCode (MonoObject *this, MonoArray **fi
        klass = mono_object_class (this);
 
        if (mono_class_num_fields (klass) == 0)
-               return mono_object_hash (this);
+               return result;
 
        /*
         * Compute the starting value of the hashcode for fields of primitive
@@ -1257,6 +1262,8 @@ get_caller_no_reflection (MonoMethod *m, gint32 no, gint32 ilo, gboolean managed
 static MonoReflectionType *
 type_from_name (const char *str, MonoBoolean ignoreCase)
 {
+       MonoMethod *m, *dest;
+
        MonoType *type = NULL;
        MonoAssembly *assembly = NULL;
        MonoTypeNameParse info;
@@ -1272,32 +1279,38 @@ type_from_name (const char *str, MonoBoolean ignoreCase)
                return NULL;
        }
 
-       if (info.assembly.name) {
-               assembly = mono_assembly_load (&info.assembly, NULL, NULL);
-       } else {
-               MonoMethod *m = mono_method_get_last_managed ();
-               MonoMethod *dest = m;
 
-               mono_stack_walk_no_il (get_caller_no_reflection, &dest);
-               if (!dest)
-                       dest = m;
+       /*
+        * We must compute the calling assembly as type loading must happen under a metadata context.
+        * For example. The main assembly is a.exe and Type.GetType is called from dir/b.dll. Without
+        * the metadata context (basedir currently) set to dir/b.dll we won't be able to load a dir/c.dll.
+        */
+       m = mono_method_get_last_managed ();
+       dest = m;
 
-               /*
-                * FIXME: mono_method_get_last_managed() sometimes returns NULL, thus
-                *        causing ves_icall_System_Reflection_Assembly_GetCallingAssembly()
-                *        to crash.  This only seems to happen in some strange remoting
-                *        scenarios and I was unable to figure out what's happening there.
-                *        Dec 10, 2005 - Martin.
-                */
+       mono_stack_walk_no_il (get_caller_no_reflection, &dest);
+       if (!dest)
+               dest = m;
 
-               if (dest) {
-                       assembly = dest->klass->image->assembly;
-                       type_resolve = TRUE;
-               } else {
-                       g_warning (G_STRLOC);
-               }
+       /*
+        * FIXME: mono_method_get_last_managed() sometimes returns NULL, thus
+        *        causing ves_icall_System_Reflection_Assembly_GetCallingAssembly()
+        *        to crash.  This only seems to happen in some strange remoting
+        *        scenarios and I was unable to figure out what's happening there.
+        *        Dec 10, 2005 - Martin.
+        */
+
+       if (dest) {
+               assembly = dest->klass->image->assembly;
+               type_resolve = TRUE;
+       } else {
+               g_warning (G_STRLOC);
        }
 
+       if (info.assembly.name)
+               assembly = mono_assembly_load (&info.assembly, assembly ? assembly->basedir : NULL, NULL);
+
+
        if (assembly) {
                /* When loading from the current assembly, AppDomain.TypeResolve will not be called yet */
                type = mono_reflection_get_type (assembly->image, &info, ignoreCase, &type_resolve);
@@ -1510,10 +1523,8 @@ ves_icall_type_is_subtype_of (MonoReflectionType *type, MonoReflectionType *c, M
                mono_class_init_or_throw (klass);
                mono_class_init_or_throw (klassc);
        } else if (!klass->supertypes || !klassc->supertypes) {
-               mono_loader_lock ();
                mono_class_setup_supertypes (klass);
                mono_class_setup_supertypes (klassc);
-               mono_loader_unlock ();
        }
 
        if (type->type->byref)
@@ -1555,9 +1566,6 @@ ves_icall_type_is_assignable_from (MonoReflectionType *type, MonoReflectionType
        klass = mono_class_from_mono_type (type->type);
        klassc = mono_class_from_mono_type (c->type);
 
-       mono_class_init_or_throw (klass);
-       mono_class_init_or_throw (klassc);
-
        if (type->type->byref ^ c->type->byref)
                return FALSE;
 
@@ -1606,12 +1614,17 @@ ves_icall_System_Reflection_FieldInfo_get_marshal_info (MonoReflectionField *fie
 {
        MonoClass *klass = field->field->parent;
        MonoMarshalType *info;
+       MonoType *ftype;
        int i;
 
        if (klass->generic_container ||
            (klass->generic_class && klass->generic_class->context.class_inst->is_open))
                return NULL;
 
+       ftype = mono_field_get_type (field->field);
+       if (ftype && !(ftype->attrs & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL))
+               return NULL;
+
        info = mono_marshal_load_type_info (klass);
 
        for (i = 0; i < info->num_fields; ++i) {
@@ -1661,8 +1674,7 @@ ves_icall_System_Reflection_FieldInfo_GetTypeModifiers (MonoReflectionField *fie
 {
        MonoError error;
        MonoType *type = mono_field_get_type_checked (field->field, &error);
-       if (!mono_error_ok (&error))
-               mono_error_raise_exception (&error);
+       mono_error_raise_exception (&error);
 
        return type_array_from_modifiers (field->field->parent->image, type, optional);
 }
@@ -1737,6 +1749,7 @@ ves_icall_MonoField_GetFieldOffset (MonoReflectionField *field)
        MonoClass *parent = field->field->parent;
        if (!parent->size_inited)
                mono_class_init (parent);
+       mono_class_setup_fields_locking (parent);
 
        return field->field->offset - sizeof (MonoObject);
 }
@@ -1884,15 +1897,24 @@ ves_icall_MonoField_GetRawConstantValue (MonoReflectionField *this)
        if (!(t->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT))
                mono_raise_exception (mono_get_exception_invalid_operation (NULL));
 
-       if (field->parent->image->dynamic) {
-               /* FIXME: */
-               g_assert_not_reached ();
+       if (image_is_dynamic (field->parent->image)) {
+               MonoClass *klass = field->parent;
+               int fidx = field - klass->fields;
+
+               g_assert (fidx >= 0 && fidx < klass->field.count);
+               g_assert (klass->ext);
+               g_assert (klass->ext->field_def_values);
+               def_type = klass->ext->field_def_values [fidx].def_type;
+               def_value = klass->ext->field_def_values [fidx].data;
+               if (def_type == MONO_TYPE_END)
+                       mono_raise_exception (mono_get_exception_invalid_operation (NULL));
+       } else {
+               def_value = mono_class_get_field_default_value (field, &def_type);
+               /* FIXME, maybe we should try to raise TLE if field->parent is broken */
+               if (!def_value)
+                       mono_raise_exception (mono_get_exception_invalid_operation (NULL));
        }
 
-       def_value = mono_class_get_field_default_value (field, &def_type);
-       if (!def_value) /*FIXME, maybe we should try to raise TLE if field->parent is broken */
-               mono_raise_exception (mono_get_exception_invalid_operation (NULL));
-
        /*FIXME unify this with reflection.c:mono_get_object_from_blob*/
        switch (def_type) {
        case MONO_TYPE_U1:
@@ -2164,7 +2186,7 @@ ves_icall_Type_GetPacking (MonoReflectionType *type, guint32 *packing, guint32 *
        MonoClass *klass = mono_class_from_mono_type (type->type);
        mono_class_init_or_throw (klass);
 
-       if (klass->image->dynamic) {
+       if (image_is_dynamic (klass->image)) {
                MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder*)type;
                *packing = tb->packing_size;
                *size = tb->class_size;
@@ -2263,12 +2285,15 @@ ves_icall_MonoType_get_DeclaringType (MonoReflectionType *type)
 
        if (type->type->byref)
                return NULL;
-       if (type->type->type == MONO_TYPE_VAR)
-               class = mono_type_get_generic_param_owner (type->type)->owner.klass;
-       else if (type->type->type == MONO_TYPE_MVAR)
-               class = mono_type_get_generic_param_owner (type->type)->owner.method->klass;
-       else
+       if (type->type->type == MONO_TYPE_VAR) {
+               MonoGenericContainer *param = mono_type_get_generic_param_owner (type->type);
+               class = param ? param->owner.klass : NULL;
+       } else if (type->type->type == MONO_TYPE_MVAR) {
+               MonoGenericContainer *param = mono_type_get_generic_param_owner (type->type);
+               class = param ? param->owner.method->klass : NULL;
+       } else {
                class = mono_class_from_mono_type (type->type)->nested_in;
+       }
 
        return class ? mono_type_get_object (domain, &class->byval_arg) : NULL;
 }
@@ -2597,7 +2622,7 @@ ves_icall_MonoMethod_GetDllImportAttribute (MonoMethod *method)
                g_assert (DllImportAttributeClass);
        }
                                                                                                                
-       if (method->klass->image->dynamic) {
+       if (image_is_dynamic (method->klass->image)) {
                MonoReflectionMethodAux *method_aux = 
                        g_hash_table_lookup (
                                                                          ((MonoDynamicImage*)method->klass->image)->method_aux_hash, method);
@@ -2661,7 +2686,7 @@ ves_icall_MonoMethod_GetGenericMethodDefinition (MonoReflectionMethod *method)
        if (!result->is_generic)
                return NULL;
 
-       if (method->method->klass->image->dynamic) {
+       if (image_is_dynamic (method->method->klass->image)) {
                MonoDynamicImage *image = (MonoDynamicImage*)method->method->klass->image;
                MonoReflectionMethod *res;
 
@@ -2669,9 +2694,9 @@ ves_icall_MonoMethod_GetGenericMethodDefinition (MonoReflectionMethod *method)
                 * FIXME: Why is this stuff needed at all ? Why can't the code below work for
                 * the dynamic case as well ?
                 */
-               mono_loader_lock ();
+               mono_image_lock ((MonoImage*)image);
                res = mono_g_hash_table_lookup (image->generic_def_objects, imethod);
-               mono_loader_unlock ();
+               mono_image_unlock ((MonoImage*)image);
 
                if (res)
                        return res;
@@ -2812,7 +2837,7 @@ ves_icall_InternalInvoke (MonoReflectionMethod *method, MonoObject *this, MonoAr
                return NULL;
        }
 
-       if (image->dynamic && !((MonoDynamicImage*)image)->run) {
+       if (image_is_dynamic (image) && !((MonoDynamicImage*)image)->run) {
                mono_gc_wbarrier_generic_store (exc, (MonoObject*) mono_get_exception_not_supported ("Cannot invoke a method in a dynamic assembly without run access."));
                return NULL;
        }
@@ -2827,6 +2852,18 @@ ves_icall_InternalInvoke (MonoReflectionMethod *method, MonoObject *this, MonoAr
                for (i = 0; i < pcount; ++i)
                        lengths [i] = *(int32_t*) ((char*)mono_array_get (params, gpointer, i) + sizeof (MonoObject));
 
+               if (m->klass->rank == 1 && sig->param_count == 2 && m->klass->element_class->rank) {
+                       /* This is a ctor for jagged arrays. MS creates an array of arrays. */
+                       MonoArray *arr = mono_array_new_full (mono_object_domain (params), m->klass, lengths, NULL);
+
+                       for (i = 0; i < mono_array_length (arr); ++i) {
+                               MonoArray *subarray = mono_array_new_full (mono_object_domain (params), m->klass->element_class, &lengths [1], NULL);
+
+                               mono_array_setref_fast (arr, i, subarray);
+                       }
+                       return (MonoObject*)arr;
+               }
+
                if (m->klass->rank == pcount) {
                        /* Only lengths provided. */
                        lower_bounds = NULL;
@@ -2976,10 +3013,12 @@ static guint64
 read_enum_value (char *mem, int type)
 {
        switch (type) {
+       case MONO_TYPE_BOOLEAN:
        case MONO_TYPE_U1:
                return *(guint8*)mem;
        case MONO_TYPE_I1:
                return *(gint8*)mem;
+       case MONO_TYPE_CHAR:
        case MONO_TYPE_U2:
                return *(guint16*)mem;
        case MONO_TYPE_I2:
@@ -3055,7 +3094,7 @@ ves_icall_System_Enum_ToObject (MonoReflectionType *enumType, MonoObject *value)
 
        if (!enumc->enumtype)
                mono_raise_exception (mono_get_exception_argument ("enumType", "Type provided must be an Enum."));
-       if (!((objc->enumtype) || (objc->byval_arg.type >= MONO_TYPE_I1 && objc->byval_arg.type <= MONO_TYPE_U8)))
+       if (!((objc->enumtype) || (objc->byval_arg.type >= MONO_TYPE_BOOLEAN && objc->byval_arg.type <= MONO_TYPE_U8)))
                mono_raise_exception (mono_get_exception_argument ("value", "The value passed in must be an enum base or an underlying type for an enum, such as an Int32."));
 
        etype = mono_class_enum_basetype (enumc);
@@ -3132,14 +3171,6 @@ ves_icall_System_Enum_compare_value_to (MonoObject *this, MonoObject *other)
                return me > other ? 1 : -1; \
        } while (0)
 
-#define COMPARE_ENUM_VALUES_RANGE(ENUM_TYPE) do { \
-               ENUM_TYPE me = *((ENUM_TYPE*)tdata); \
-               ENUM_TYPE other = *((ENUM_TYPE*)odata); \
-               if (me == other) \
-                       return 0; \
-               return me - other; \
-       } while (0)
-
        switch (basetype->type) {
                case MONO_TYPE_U1:
                        COMPARE_ENUM_VALUES (guint8);
@@ -3147,7 +3178,7 @@ ves_icall_System_Enum_compare_value_to (MonoObject *this, MonoObject *other)
                        COMPARE_ENUM_VALUES (gint8);
                case MONO_TYPE_CHAR:
                case MONO_TYPE_U2:
-                       COMPARE_ENUM_VALUES_RANGE (guint16);
+                       COMPARE_ENUM_VALUES (guint16);
                case MONO_TYPE_I2:
                        COMPARE_ENUM_VALUES (gint16);
                case MONO_TYPE_U4:
@@ -3161,7 +3192,6 @@ ves_icall_System_Enum_compare_value_to (MonoObject *this, MonoObject *other)
                default:
                        g_error ("Implement type 0x%02x in get_hashcode", basetype->type);
        }
-#undef COMPARE_ENUM_VALUES_RANGE
 #undef COMPARE_ENUM_VALUES
        return 0;
 }
@@ -3885,6 +3915,21 @@ handle_parent:
        return NULL;
 }
 
+static guint
+event_hash (gconstpointer data)
+{
+       MonoEvent *event = (MonoEvent*)data;
+
+       return g_str_hash (event->name);
+}
+
+static gboolean
+event_equal (MonoEvent *event1, MonoEvent *event2)
+{
+       // Events are hide-by-name
+       return g_str_equal (event1->name, event2->name);
+}
+
 ICALL_EXPORT MonoArray*
 ves_icall_Type_GetEvents_internal (MonoReflectionType *type, guint32 bflags, MonoReflectionType *reftype)
 {
@@ -3897,7 +3942,7 @@ ves_icall_Type_GetEvents_internal (MonoReflectionType *type, guint32 bflags, Mon
        MonoEvent *event;
        int i, match;
        gpointer iter;
-       
+       GHashTable *events = NULL;
        MonoPtrArray tmp_array;
 
        MONO_ARCH_SAVE_REGS;
@@ -3913,6 +3958,7 @@ ves_icall_Type_GetEvents_internal (MonoReflectionType *type, guint32 bflags, Mon
                return mono_array_new_cached (domain, System_Reflection_EventInfo, 0);
        klass = startklass = mono_class_from_mono_type (type->type);
 
+       events = g_hash_table_new (event_hash, (GEqualFunc)event_equal);
 handle_parent:
        mono_class_setup_vtable (klass);
        if (klass->exception_type != MONO_EXCEPTION_NONE || mono_loader_get_last_error ())
@@ -3956,11 +4002,19 @@ handle_parent:
                                match ++;
                if (!match)
                        continue;
+
+               if (g_hash_table_lookup (events, event))
+                       continue;
+
                mono_ptr_array_append (tmp_array, mono_event_get_object (domain, startklass, event));
+
+               g_hash_table_insert (events, event, event);
        }
        if (!(bflags & BFLAGS_DeclaredOnly) && (klass = klass->parent))
                goto handle_parent;
 
+       g_hash_table_destroy (events);
+
        res = mono_array_new_cached (domain, System_Reflection_EventInfo, mono_ptr_array_size (tmp_array));
 
        for (i = 0; i < mono_ptr_array_size (tmp_array); ++i)
@@ -4143,7 +4197,7 @@ ves_icall_System_Reflection_Assembly_InternalGetType (MonoReflectionAssembly *as
                        type = NULL;
        }
        else
-               if (assembly->assembly->dynamic) {
+               if (assembly_is_dynamic (assembly->assembly)) {
                        /* Enumerate all modules */
                        MonoReflectionAssemblyBuilder *abuilder = (MonoReflectionAssemblyBuilder*)assembly;
                        int i;
@@ -4693,7 +4747,7 @@ ves_icall_System_Reflection_Assembly_GetModulesInternal (MonoReflectionAssembly
        MonoImage *image = assembly->assembly->image;
 
        g_assert (image != NULL);
-       g_assert (!assembly->assembly->dynamic);
+       g_assert (!assembly_is_dynamic (assembly->assembly));
 
        table = &image->tables [MONO_TABLE_FILE];
        file_count = table->rows;
@@ -5130,21 +5184,16 @@ mono_module_get_types (MonoDomain *domain, MonoImage *image, MonoArray **excepti
                attrs = mono_metadata_decode_row_col (tdef, i, MONO_TYPEDEF_FLAGS);
                visibility = attrs & TYPE_ATTRIBUTE_VISIBILITY_MASK;
                if (!exportedOnly || (visibility == TYPE_ATTRIBUTE_PUBLIC || visibility == TYPE_ATTRIBUTE_NESTED_PUBLIC)) {
-                       klass = mono_class_get (image, (i + 1) | MONO_TOKEN_TYPE_DEF);
+                       MonoError error;
+                       klass = mono_class_get_checked (image, (i + 1) | MONO_TOKEN_TYPE_DEF, &error);
+                       g_assert (!mono_loader_get_last_error ()); /* Plug any leaks */
+                       
                        if (klass) {
                                mono_array_setref (res, count, mono_type_get_object (domain, &klass->byval_arg));
                        } else {
-                               MonoLoaderError *error;
-                               MonoException *ex;
-                               
-                               error = mono_loader_get_last_error ();
-                               g_assert (error != NULL);
-       
-                               ex = mono_loader_error_prepare_exception (error);
+                               MonoException *ex = mono_error_convert_to_exception (&error);
                                mono_array_setref (*exceptions, count, ex);
                        }
-                       if (mono_loader_get_last_error ())
-                               mono_loader_clear_error ();
                        count++;
                }
        }
@@ -5167,7 +5216,7 @@ ves_icall_System_Reflection_Assembly_GetTypes (MonoReflectionAssembly *assembly,
 
        domain = mono_object_domain (assembly);
 
-       g_assert (!assembly->assembly->dynamic);
+       g_assert (!assembly_is_dynamic (assembly->assembly));
        image = assembly->assembly->image;
        table = &image->tables [MONO_TABLE_FILE];
        res = mono_module_get_types (domain, image, &exceptions, exportedOnly);
@@ -5235,7 +5284,7 @@ ves_icall_System_Reflection_Assembly_GetTypes (MonoReflectionAssembly *assembly,
                mono_loader_clear_error ();
 
                exl = mono_array_new (domain, mono_defaults.exception_class, length);
-               /* Types for which mono_class_get () succeeded */
+               /* Types for which mono_class_get_checked () succeeded */
                for (i = 0, tmp = list; tmp; i++, tmp = tmp->next) {
                        MonoException *exc = mono_class_get_exception_for_failure (tmp->data);
                        mono_array_setref (exl, i, exc);
@@ -5290,6 +5339,7 @@ ves_icall_System_Reflection_AssemblyName_ParseName (MonoReflectionAssemblyName *
 ICALL_EXPORT MonoReflectionType*
 ves_icall_System_Reflection_Module_GetGlobalType (MonoReflectionModule *module)
 {
+       MonoError error;
        MonoDomain *domain = mono_object_domain (module); 
        MonoClass *klass;
 
@@ -5297,11 +5347,12 @@ ves_icall_System_Reflection_Module_GetGlobalType (MonoReflectionModule *module)
 
        g_assert (module->image);
 
-       if (module->image->dynamic && ((MonoDynamicImage*)(module->image))->initial_image)
+       if (image_is_dynamic (module->image) && ((MonoDynamicImage*)(module->image))->initial_image)
                /* These images do not have a global type */
                return NULL;
 
-       klass = mono_class_get (module->image, 1 | MONO_TOKEN_TYPE_DEF);
+       klass = mono_class_get_checked (module->image, 1 | MONO_TOKEN_TYPE_DEF, &error);
+       mono_error_raise_exception (&error);
        return mono_type_get_object (domain, &klass->byval_arg);
 }
 
@@ -5337,7 +5388,7 @@ ves_icall_System_Reflection_Module_GetHINSTANCE (MonoReflectionModule *module)
 ICALL_EXPORT void
 ves_icall_System_Reflection_Module_GetPEKind (MonoImage *image, gint32 *pe_kind, gint32 *machine)
 {
-       if (image->dynamic) {
+       if (image_is_dynamic (image)) {
                MonoDynamicImage *dyn = (MonoDynamicImage*)image;
                *pe_kind = dyn->pe_kind;
                *machine = dyn->machine;
@@ -5378,7 +5429,7 @@ ves_icall_System_Reflection_Module_InternalGetTypes (MonoReflectionModule *modul
 static gboolean
 mono_memberref_is_method (MonoImage *image, guint32 token)
 {
-       if (!image->dynamic) {
+       if (!image_is_dynamic (image)) {
                guint32 cols [MONO_MEMBERREF_SIZE];
                const char *sig;
                mono_metadata_decode_row (&image->tables [MONO_TABLE_MEMBERREF], mono_metadata_token_index (token) - 1, cols, MONO_MEMBERREF_SIZE);
@@ -5411,23 +5462,24 @@ init_generic_context_from_args (MonoGenericContext *context, MonoArray *type_arg
 }
 
 ICALL_EXPORT MonoType*
-ves_icall_System_Reflection_Module_ResolveTypeToken (MonoImage *image, guint32 token, MonoArray *type_args, MonoArray *method_args, MonoResolveTokenError *error)
+ves_icall_System_Reflection_Module_ResolveTypeToken (MonoImage *image, guint32 token, MonoArray *type_args, MonoArray *method_args, MonoResolveTokenError *resolve_error)
 {
        MonoClass *klass;
        int table = mono_metadata_token_table (token);
        int index = mono_metadata_token_index (token);
        MonoGenericContext context;
+       MonoError error;
 
-       *error = ResolveTokenError_Other;
+       *resolve_error = ResolveTokenError_Other;
 
        /* Validate token */
        if ((table != MONO_TABLE_TYPEDEF) && (table != MONO_TABLE_TYPEREF) && 
                (table != MONO_TABLE_TYPESPEC)) {
-               *error = ResolveTokenError_BadTable;
+               *resolve_error = ResolveTokenError_BadTable;
                return NULL;
        }
 
-       if (image->dynamic) {
+       if (image_is_dynamic (image)) {
                if ((table == MONO_TABLE_TYPEDEF) || (table == MONO_TABLE_TYPEREF)) {
                        klass = mono_lookup_dynamic_token_class (image, token, FALSE, NULL, NULL);
                        return klass ? &klass->byval_arg : NULL;
@@ -5439,15 +5491,15 @@ ves_icall_System_Reflection_Module_ResolveTypeToken (MonoImage *image, guint32 t
        }
 
        if ((index <= 0) || (index > image->tables [table].rows)) {
-               *error = ResolveTokenError_OutOfRange;
+               *resolve_error = ResolveTokenError_OutOfRange;
                return NULL;
        }
 
        init_generic_context_from_args (&context, type_args, method_args);
-       klass = mono_class_get_full (image, token, &context);
-
-       if (mono_loader_get_last_error ())
-               mono_raise_exception (mono_loader_error_prepare_exception (mono_loader_get_last_error ()));
+       klass = mono_class_get_checked (image, token, &error);
+       if (klass)
+               klass = mono_class_inflate_generic_class_checked (klass, &context, &error);
+       mono_error_raise_exception (&error);
 
        if (klass)
                return &klass->byval_arg;
@@ -5472,7 +5524,7 @@ ves_icall_System_Reflection_Module_ResolveMethodToken (MonoImage *image, guint32
                return NULL;
        }
 
-       if (image->dynamic) {
+       if (image_is_dynamic (image)) {
                if (table == MONO_TABLE_METHOD)
                        return mono_lookup_dynamic_token_class (image, token, FALSE, NULL, NULL);
 
@@ -5516,7 +5568,7 @@ ves_icall_System_Reflection_Module_ResolveStringToken (MonoImage *image, guint32
                return NULL;
        }
 
-       if (image->dynamic)
+       if (image_is_dynamic (image))
                return mono_lookup_dynamic_token_class (image, token, FALSE, NULL, NULL);
 
        if ((index <= 0) || (index >= image->heap_us.size)) {
@@ -5530,28 +5582,29 @@ ves_icall_System_Reflection_Module_ResolveStringToken (MonoImage *image, guint32
 }
 
 ICALL_EXPORT MonoClassField*
-ves_icall_System_Reflection_Module_ResolveFieldToken (MonoImage *image, guint32 token, MonoArray *type_args, MonoArray *method_args, MonoResolveTokenError *error)
+ves_icall_System_Reflection_Module_ResolveFieldToken (MonoImage *image, guint32 token, MonoArray *type_args, MonoArray *method_args, MonoResolveTokenError *resolve_error)
 {
+       MonoError error;
        MonoClass *klass;
        int table = mono_metadata_token_table (token);
        int index = mono_metadata_token_index (token);
        MonoGenericContext context;
        MonoClassField *field;
 
-       *error = ResolveTokenError_Other;
+       *resolve_error = ResolveTokenError_Other;
 
        /* Validate token */
        if ((table != MONO_TABLE_FIELD) && (table != MONO_TABLE_MEMBERREF)) {
-               *error = ResolveTokenError_BadTable;
+               *resolve_error = ResolveTokenError_BadTable;
                return NULL;
        }
 
-       if (image->dynamic) {
+       if (image_is_dynamic (image)) {
                if (table == MONO_TABLE_FIELD)
                        return mono_lookup_dynamic_token_class (image, token, FALSE, NULL, NULL);
 
                if (mono_memberref_is_method (image, token)) {
-                       *error = ResolveTokenError_BadTable;
+                       *resolve_error = ResolveTokenError_BadTable;
                        return NULL;
                }
 
@@ -5560,19 +5613,17 @@ ves_icall_System_Reflection_Module_ResolveFieldToken (MonoImage *image, guint32
        }
 
        if ((index <= 0) || (index > image->tables [table].rows)) {
-               *error = ResolveTokenError_OutOfRange;
+               *resolve_error = ResolveTokenError_OutOfRange;
                return NULL;
        }
        if ((table == MONO_TABLE_MEMBERREF) && (mono_memberref_is_method (image, token))) {
-               *error = ResolveTokenError_BadTable;
+               *resolve_error = ResolveTokenError_BadTable;
                return NULL;
        }
 
        init_generic_context_from_args (&context, type_args, method_args);
-       field = mono_field_from_token (image, token, &klass, &context);
-
-       if (mono_loader_get_last_error ())
-               mono_raise_exception (mono_loader_error_prepare_exception (mono_loader_get_last_error ()));
+       field = mono_field_from_token_checked (image, token, &klass, &context, &error);
+       mono_error_raise_exception (&error);
        
        return field;
 }
@@ -5650,7 +5701,7 @@ ves_icall_System_Reflection_Module_ResolveSignature (MonoImage *image, guint32 t
        if (table != MONO_TABLE_STANDALONESIG)
                return NULL;
 
-       if (image->dynamic)
+       if (image_is_dynamic (image))
                return NULL;
 
        if ((idx == 0) || (idx > tables [MONO_TABLE_STANDALONESIG].rows))
@@ -5822,7 +5873,7 @@ ves_icall_System_Delegate_CreateDelegate_internal (MonoReflectionType *type, Mon
 
        delegate = mono_object_new (mono_object_domain (type), delegate_class);
 
-       if (method->dynamic) {
+       if (method_is_dynamic (method)) {
                /* Creating a trampoline would leak memory */
                func = mono_compile_method (method);
        } else {
@@ -6100,14 +6151,6 @@ ves_icall_System_CurrentSystemTimeZone_GetTimeZoneData (guint32 year, MonoArray
 #endif
 }
 
-ICALL_EXPORT gpointer
-ves_icall_System_Object_obj_address (MonoObject *this) 
-{
-       MONO_ARCH_SAVE_REGS;
-
-       return this;
-}
-
 /* System.Buffer */
 
 static inline gint32 
@@ -6197,7 +6240,7 @@ ves_icall_System_Buffer_BlockCopyInternal (MonoArray *src, gint32 src_offset, Mo
        if (src != dest)
                memcpy (dest_buf, src_buf, count);
        else
-               mono_gc_memmove (dest_buf, src_buf, count); /* Source and dest are the same array */
+               memmove (dest_buf, src_buf, count); /* Source and dest are the same array */
 
        return TRUE;
 }
@@ -6450,12 +6493,11 @@ ves_icall_System_Environment_GetEnvironmentVariableNames (void)
 ICALL_EXPORT void
 ves_icall_System_Environment_InternalSetEnvironmentVariable (MonoString *name, MonoString *value)
 {
-       MonoError error;
 #ifdef HOST_WIN32
-
        gunichar2 *utf16_name, *utf16_value;
 #else
        gchar *utf8_name, *utf8_value;
+       MonoError error;
 #endif
 
        MONO_ARCH_SAVE_REGS;
@@ -6500,6 +6542,8 @@ ves_icall_System_Environment_Exit (int result)
 {
        MONO_ARCH_SAVE_REGS;
 
+       mono_environment_exitcode_set (result);
+
 /* FIXME: There are some cleanup hangs that should be worked out, but
  * if the program is going to exit, everything will be cleaned up when
  * NaCl exits anyway.
@@ -6711,7 +6755,7 @@ ICALL_EXPORT void
 ves_icall_System_Environment_BroadcastSettingChange (void)
 {
 #ifdef HOST_WIN32
-       SendMessageTimeout (HWND_BROADCAST, WM_SETTINGCHANGE, NULL, L"Environment", SMTO_ABORTIFHUNG, 2000, 0);
+       SendMessageTimeout (HWND_BROADCAST, WM_SETTINGCHANGE, (WPARAM)NULL, (LPARAM)L"Environment", SMTO_ABORTIFHUNG, 2000, 0);
 #endif
 }
 
@@ -7031,7 +7075,7 @@ ves_icall_get_resources_ptr (MonoReflectionAssembly *assembly, gpointer *result,
 ICALL_EXPORT MonoBoolean
 ves_icall_System_Diagnostics_Debugger_IsAttached_internal (void)
 {
-       return mono_debug_using_mono_debugger () || mono_is_debugger_attached ();
+       return mono_is_debugger_attached ();
 }
 
 ICALL_EXPORT MonoBoolean
@@ -7388,15 +7432,11 @@ ves_icall_System_Char_GetDataTablePointers (int category_data_version,
        *to_upper_data_high = ToUpperDataHigh;
 }
 
-ICALL_EXPORT gint32
-ves_icall_MonoDebugger_GetMethodToken (MonoReflectionMethod *method)
-{
-       return method->method->token;
-}
-
 /*
  * We return NULL for no modifiers so the corlib code can return Type.EmptyTypes
  * and avoid useless allocations.
+ * 
+ * MAY THROW
  */
 static MonoArray*
 type_array_from_modifiers (MonoImage *image, MonoType *type, int optional)
@@ -7413,7 +7453,9 @@ type_array_from_modifiers (MonoImage *image, MonoType *type, int optional)
        count = 0;
        for (i = 0; i < type->num_mods; ++i) {
                if ((optional && !type->modifiers [i].required) || (!optional && type->modifiers [i].required)) {
-                       MonoClass *klass = mono_class_get (image, type->modifiers [i].token);
+                       MonoError error;
+                       MonoClass *klass = mono_class_get_checked (image, type->modifiers [i].token, &error);
+                       mono_error_raise_exception (&error); /* this is safe, no cleanup needed on callers */ 
                        mono_array_setref (res, count, mono_type_get_object (mono_domain_get (), &klass->byval_arg));
                        count++;
                }
@@ -7559,8 +7601,8 @@ custom_attrs_get_by_type (MonoObject *obj, MonoReflectionType *attr_type)
                mono_class_init_or_throw (attr_class);
 
        res = mono_reflection_get_custom_attrs_by_type (obj, attr_class, &error);
-       if (!mono_error_ok (&error))
-               mono_error_raise_exception (&error);
+       mono_error_raise_exception (&error);
+
        if (mono_loader_get_last_error ()) {
                mono_raise_exception (mono_loader_error_prepare_exception (mono_loader_get_last_error ()));
                g_assert_not_reached ();
@@ -7857,6 +7899,7 @@ icall_symbols [] = {
 
 #endif /* DISABLE_ICALL_TABLES */
 
+static mono_mutex_t icall_mutex;
 static GHashTable *icall_hash = NULL;
 static GHashTable *jit_icall_hash_name = NULL;
 static GHashTable *jit_icall_hash_addr = NULL;
@@ -7894,6 +7937,19 @@ mono_icall_init (void)
 #endif
 
        icall_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+       mono_mutex_init (&icall_mutex);
+}
+
+static void
+mono_icall_lock (void)
+{
+       mono_locks_mutex_acquire (&icall_mutex, IcallLock);
+}
+
+static void
+mono_icall_unlock (void)
+{
+       mono_locks_mutex_release (&icall_mutex, IcallLock);
 }
 
 void
@@ -7902,16 +7958,17 @@ mono_icall_cleanup (void)
        g_hash_table_destroy (icall_hash);
        g_hash_table_destroy (jit_icall_hash_name);
        g_hash_table_destroy (jit_icall_hash_addr);
+       mono_mutex_destroy (&icall_mutex);
 }
 
 void
 mono_add_internal_call (const char *name, gconstpointer method)
 {
-       mono_loader_lock ();
+       mono_icall_lock ();
 
        g_hash_table_insert (icall_hash, g_strdup (name), (gpointer) method);
 
-       mono_loader_unlock ();
+       mono_icall_unlock ();
 }
 
 #ifndef DISABLE_ICALL_TABLES
@@ -8074,23 +8131,23 @@ mono_lookup_internal_call (MonoMethod *method)
        sigstart [siglen + 2] = 0;
        g_free (tmpsig);
        
-       mono_loader_lock ();
+       mono_icall_lock ();
 
        res = g_hash_table_lookup (icall_hash, mname);
        if (res) {
-               mono_loader_unlock ();
+               mono_icall_unlock ();;
                return res;
        }
        /* try without signature */
        *sigstart = 0;
        res = g_hash_table_lookup (icall_hash, mname);
        if (res) {
-               mono_loader_unlock ();
+               mono_icall_unlock ();
                return res;
        }
 
 #ifdef DISABLE_ICALL_TABLES
-       mono_loader_unlock ();
+       mono_icall_unlock ();
        /* Fail only when the result is actually used */
        /* mono_marshal_get_native_wrapper () depends on this */
        if (method->klass == mono_defaults.string_class && !strcmp (method->name, ".ctor"))
@@ -8100,19 +8157,19 @@ mono_lookup_internal_call (MonoMethod *method)
 #else
        /* it wasn't found in the static call tables */
        if (!imap) {
-               mono_loader_unlock ();
+               mono_icall_unlock ();
                return NULL;
        }
        res = find_method_icall (imap, sigstart - mlen);
        if (res) {
-               mono_loader_unlock ();
+               mono_icall_unlock ();
                return res;
        }
        /* try _with_ signature */
        *sigstart = '(';
        res = find_method_icall (imap, sigstart - mlen);
        if (res) {
-               mono_loader_unlock ();
+               mono_icall_unlock ();
                return res;
        }
 
@@ -8124,7 +8181,7 @@ mono_lookup_internal_call (MonoMethod *method)
        g_print ("If you see other errors or faults after this message they are probably related\n");
        g_print ("and you need to fix your mono install first.\n");
 
-       mono_loader_unlock ();
+       mono_icall_unlock ();
 
        return NULL;
 #endif
@@ -8249,20 +8306,24 @@ type_from_typename (char *typename)
        return &klass->byval_arg;
 }
 
+/**
+ * LOCKING: Take the corlib image lock.
+ */
 MonoMethodSignature*
 mono_create_icall_signature (const char *sigstr)
 {
        gchar **parts;
        int i, len;
        gchar **tmp;
-       MonoMethodSignature *res;
+       MonoMethodSignature *res, *res2;
+       MonoImage *corlib = mono_defaults.corlib;
 
-       mono_loader_lock ();
-       res = g_hash_table_lookup (mono_defaults.corlib->helper_signatures, sigstr);
-       if (res) {
-               mono_loader_unlock ();
+       mono_image_lock (corlib);
+       res = g_hash_table_lookup (corlib->helper_signatures, sigstr);
+       mono_image_unlock (corlib);
+
+       if (res)
                return res;
-       }
 
        parts = g_strsplit (sigstr, " ", 256);
 
@@ -8273,7 +8334,7 @@ mono_create_icall_signature (const char *sigstr)
                tmp ++;
        }
 
-       res = mono_metadata_signature_alloc (mono_defaults.corlib, len - 1);
+       res = mono_metadata_signature_alloc (corlib, len - 1);
        res->pinvoke = 1;
 
 #ifdef HOST_WIN32
@@ -8291,9 +8352,13 @@ mono_create_icall_signature (const char *sigstr)
 
        g_strfreev (parts);
 
-       g_hash_table_insert (mono_defaults.corlib->helper_signatures, (gpointer)sigstr, res);
-
-       mono_loader_unlock ();
+       mono_image_lock (corlib);
+       res2 = g_hash_table_lookup (corlib->helper_signatures, sigstr);
+       if (res2)
+               res = res2; /*Value is allocated in the image pool*/
+       else
+               g_hash_table_insert (corlib->helper_signatures, (gpointer)sigstr, res);
+       mono_image_unlock (corlib);
 
        return res;
 }
@@ -8304,9 +8369,9 @@ mono_find_jit_icall_by_name (const char *name)
        MonoJitICallInfo *info;
        g_assert (jit_icall_hash_name);
 
-       mono_loader_lock ();
+       mono_icall_lock ();
        info = g_hash_table_lookup (jit_icall_hash_name, name);
-       mono_loader_unlock ();
+       mono_icall_unlock ();
        return info;
 }
 
@@ -8316,9 +8381,9 @@ mono_find_jit_icall_by_addr (gconstpointer addr)
        MonoJitICallInfo *info;
        g_assert (jit_icall_hash_addr);
 
-       mono_loader_lock ();
+       mono_icall_lock ();
        info = g_hash_table_lookup (jit_icall_hash_addr, (gpointer)addr);
-       mono_loader_unlock ();
+       mono_icall_unlock ();
 
        return info;
 }
@@ -8327,7 +8392,7 @@ mono_find_jit_icall_by_addr (gconstpointer addr)
  * mono_get_jit_icall_info:
  *
  *   Return the hashtable mapping JIT icall names to MonoJitICallInfo structures. The
- * caller should access it while holding the loader lock.
+ * caller should access it while holding the icall lock.
  */
 GHashTable*
 mono_get_jit_icall_info (void)
@@ -8346,20 +8411,20 @@ mono_lookup_jit_icall_symbol (const char *name)
        MonoJitICallInfo *info;
        const char *res = NULL;
 
-       mono_loader_lock ();
+       mono_icall_lock ();
        info = g_hash_table_lookup (jit_icall_hash_name, name);
        if (info)
                res = info->c_symbol;
-       mono_loader_unlock ();
+       mono_icall_unlock ();
        return res;
 }
 
 void
 mono_register_jit_icall_wrapper (MonoJitICallInfo *info, gconstpointer wrapper)
 {
-       mono_loader_lock ();
+       mono_icall_lock ();
        g_hash_table_insert (jit_icall_hash_addr, (gpointer)wrapper, info);
-       mono_loader_unlock ();
+       mono_icall_unlock ();
 }
 
 MonoJitICallInfo *
@@ -8370,7 +8435,7 @@ mono_register_jit_icall_full (gconstpointer func, const char *name, MonoMethodSi
        g_assert (func);
        g_assert (name);
 
-       mono_loader_lock ();
+       mono_icall_lock ();
 
        if (!jit_icall_hash_name) {
                jit_icall_hash_name = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free);
@@ -8398,7 +8463,7 @@ mono_register_jit_icall_full (gconstpointer func, const char *name, MonoMethodSi
        g_hash_table_insert (jit_icall_hash_name, (gpointer)info->name, info);
        g_hash_table_insert (jit_icall_hash_addr, (gpointer)func, info);
 
-       mono_loader_unlock ();
+       mono_icall_unlock ();
        return info;
 }