Merge pull request #2408 from tastywheattasteslikechicken/MoreInterfaceSupport
authorRodrigo Kumpera <kumpera@users.noreply.github.com>
Mon, 7 Nov 2016 16:04:29 +0000 (08:04 -0800)
committerGitHub <noreply@github.com>
Mon, 7 Nov 2016 16:04:29 +0000 (08:04 -0800)
Enhance maximum number of supported interfaces from 2^16.

1  2 
mono/metadata/class-internals.h
mono/metadata/class.c
mono/metadata/marshal.c
mono/metadata/object.c
mono/mini/method-to-ir.c
mono/mini/mini-runtime.c

index 1e34c340e3d6a616cd723d9c7829c3625b88c45f,f6db61641fdd8e0540ade5784a27d14bbd434435..0c14ec3b04236557fbc37d94da1ab3f042768355
@@@ -1,6 -1,5 +1,6 @@@
  /* 
   * Copyright 2012 Xamarin Inc
 + * Licensed under the MIT license. See LICENSE file in the project root for full license information.
   */
  #ifndef __MONO_METADATA_CLASS_INTERNALS_H__
  #define __MONO_METADATA_CLASS_INTERNALS_H__
@@@ -16,7 -15,7 +16,7 @@@
  
  #define MONO_CLASS_IS_ARRAY(c) ((c)->rank)
  
 -#define MONO_CLASS_HAS_STATIC_METADATA(klass) ((klass)->type_token && !(klass)->image->dynamic && !(klass)->generic_class)
 +#define MONO_CLASS_HAS_STATIC_METADATA(klass) ((klass)->type_token && !(klass)->image->dynamic && !mono_class_is_ginst (klass))
  
  #define MONO_DEFAULT_SUPERTABLE_SIZE 6
  
@@@ -194,7 -193,7 +194,7 @@@ struct _MonoEvent 
  };
  
  /* type of exception being "on hold" for later processing (see exception_type) */
 -enum {
 +typedef enum {
        MONO_EXCEPTION_NONE = 0,
        MONO_EXCEPTION_INVALID_PROGRAM = 3,
        MONO_EXCEPTION_UNVERIFIABLE_IL = 4,
        MONO_EXCEPTION_INLINE_FAILED = 15,
        MONO_EXCEPTION_MONO_ERROR = 16,
        /* add other exception type */
 -};
 +} MonoExceptionType;
  
  /* This struct collects the info needed for the runtime use of a class,
   * like the vtables for a domain, the GC descriptor, etc.
@@@ -256,15 -255,6 +256,15 @@@ typedef struct 
        GList      *nested_classes;
  } MonoClassExt;
  
 +typedef enum {
 +      MONO_CLASS_DEF = 1, /* non-generic type */
 +      MONO_CLASS_GTD, /* generic type definition */
 +      MONO_CLASS_GINST, /* generic instantiation */
 +      MONO_CLASS_GPARAM, /* generic parameter */
 +      MONO_CLASS_ARRAY, /* vector or array, bounded or not */
 +      MONO_CLASS_POINTER, /* pointer of function pointer*/
 +} MonoTypeKind;
 +
  struct _MonoClass {
        /* element class for arrays and enum basetype for enums */
        MonoClass *element_class; 
        int        instance_size; /* object instance size */
  
        guint inited          : 1;
 -      /* We use init_pending to detect cyclic calls to mono_class_init */
 -      guint init_pending    : 1;
  
        /* A class contains static and non static data. Static data can be
         * of the same type as the class itselfs, but it does not influence
        guint nested_classes_inited : 1; /* Whenever nested_class is initialized */
  
        /* next byte*/
 +      guint class_kind : 3; /* One of the values from MonoTypeKind */
        guint interfaces_inited : 1; /* interfaces is initialized */
        guint simd_type : 1; /* class is a simd intrinsic type */
 -      guint is_generic : 1; /* class is a generic type definition */
 -      guint is_inflated : 1; /* class is a generic instance */
        guint has_finalize_inited    : 1; /* has_finalize is initialized */
 -      guint fields_inited : 1; /* fields is initialized */
 -      guint setup_fields_called : 1; /* to prevent infinite loops in setup_fields */
 -
 -      guint8     exception_type;      /* MONO_EXCEPTION_* */
 -
 -      /* Additional information about the exception */
 -      /* Stored as property MONO_CLASS_PROP_EXCEPTION_DATA */
 -      //void       *exception_data;
 +      guint fields_inited : 1; /* setup_fields () has finished */
 +      guint has_failure : 1; /* See MONO_CLASS_PROP_EXCEPTION_DATA for a MonoErrorBoxed with the details */
  
        MonoClass  *parent;
        MonoClass  *nested_in;
        int        vtable_size; /* number of slots */
  
        guint16     interface_count;
-       guint16     interface_id;        /* unique inderface id (for interfaces) */
-       guint16     max_interface_id;
+       guint32     interface_id;        /* unique inderface id (for interfaces) */
+       guint32     max_interface_id;
        
        guint16     interface_offsets_count;
        MonoClass **interfaces_packed;
        /*
         * From the TypeDef table
         */
 -      guint32    flags;
        struct {
  #if MONO_SMALL_CONFIG
 -              guint16 first, count;
 +              guint16 count;
  #else
 -              guint32 first, count;
 +              guint32 count;
  #endif
 -      } field, method;
 +      } field;
 +      struct {
 +#if MONO_SMALL_CONFIG
 +              guint16 count;
 +#else
 +              guint32 count;
 +#endif
 +      } method;
  
        /* A GC handle pointing to the corresponding type builder/generic param builder */
        guint32 ref_info_handle;
        MonoType this_arg;
        MonoType byval_arg;
  
 -      MonoGenericClass *generic_class;
 -      MonoGenericContainer *generic_container;
 -
        MonoGCDescriptor gc_descr;
  
        MonoClassRuntimeInfo *runtime_info;
  
 -      /* next element in the class_cache hash list (in MonoImage) */
 -      MonoClass *next_class_cache;
 -
        /* Generic vtable. Initialized by a call to mono_class_setup_vtable () */
        MonoMethod **vtable;
  
        MonoClassExt *ext;
  };
  
 +typedef struct {
 +      MonoClass class;
 +      guint32 flags;
 +      /*
 +       * From the TypeDef table
 +       */
 +      guint32 first_method_idx;
 +      guint32 first_field_idx;
 +      /* next element in the class_cache hash list (in MonoImage) */
 +      MonoClass *next_class_cache;
 +} MonoClassDef;
 +
 +typedef struct {
 +      MonoClassDef class;
 +      MonoGenericContainer *generic_container;
 +} MonoClassGtd;
 +
 +typedef struct {
 +      MonoClass class;
 +      MonoGenericClass *generic_class;
 +} MonoClassGenericInst;
 +
 +typedef struct {
 +      MonoClass class;
 +} MonoClassGenericParam;
 +
 +typedef struct {
 +      MonoClass class;
 +} MonoClassArray;
 +
 +typedef struct {
 +      MonoClass class;
 +} MonoClassPointer;
 +
  #ifdef COMPRESSED_INTERFACE_BITMAP
  int mono_compress_bitmap (uint8_t *dest, const uint8_t *bitmap, int size);
  int mono_class_interface_match (const uint8_t *bitmap, int id);
@@@ -490,7 -455,7 +490,7 @@@ struct MonoVTable 
        MonoDomain *domain;  /* each object/vtable belongs to exactly one domain */
          gpointer    type; /* System.Type type for klass */
        guint8     *interface_bitmap;
-       guint16     max_interface_id;
+       guint32     max_interface_id;
        guint8      rank;
        guint remote          : 1; /* class is remotely activated */
        guint initialized     : 1; /* cctor has been run */
@@@ -552,6 -517,7 +552,6 @@@ struct _MonoMethodInflated 
                MonoMethod method;
                MonoMethodPInvoke pinvoke;
        } method;
 -      MonoMethodHeader *header;
        MonoMethod *declaring;          /* the generic method definition. */
        MonoGenericContext context;     /* The current instantiation */
        MonoImageSet *owner; /* The image set that the inflated method belongs to. */
  struct _MonoGenericClass {
        MonoClass *container_class;     /* the generic type definition */
        MonoGenericContext context;     /* a context that contains the type instantiation doesn't contain any method instantiation */ /* FIXME: Only the class_inst member of "context" is ever used, so this field could be replaced with just a monogenericinst */
 -      guint is_dynamic  : 1;          /* We're a MonoDynamicGenericClass */
 +      guint is_dynamic  : 1;          /* Contains dynamic types */
        guint is_tb_open  : 1;          /* This is the fully open instantiation for a type_builder. Quite ugly, but it's temporary.*/
 +      guint need_sync   : 1;      /* Only if dynamic. Need to be synchronized with its container class after its finished. */
        MonoClass *cached_class;        /* if present, the MonoClass corresponding to the instantiation.  */
  
        /* 
        MonoImageSet *owner;
  };
  
 -/*
 - * This is used when instantiating a generic type definition which is
 - * a TypeBuilder.
 - */
 -struct _MonoDynamicGenericClass {
 -      MonoGenericClass generic_class;
 -      int count_fields;
 -      MonoClassField *fields;
 -      guint initialized;
 -      /* The non-inflated types of the fields */
 -      MonoType **field_generic_types;
 -      /* The managed objects representing the fields */
 -      MonoObject **field_objects;
 -};
 -
  /*
   * A type parameter.
   */
@@@ -593,7 -573,6 +593,7 @@@ struct _MonoGenericParam 
  };
  
  /* Additional details about a MonoGenericParam */
 +/* Keep in sync with managed Mono.RuntimeStructs.GenericParamInfo */
  typedef struct {
        MonoClass *pklass;              /* The corresponding `MonoClass'. */
        const char *name;
@@@ -742,11 -721,21 +742,11 @@@ typedef struct 
        gboolean no_raise;
  } MonoJitICallInfo;
  
 -typedef struct {
 -      guint8 exception_type;
 -      char *class_name; /* If kind == TYPE */
 -      char *assembly_name; /* If kind == TYPE or ASSEMBLY */
 -      MonoClass *klass; /* If kind != TYPE */
 -      const char *member_name; /* If kind != TYPE */
 -      gboolean ref_only; /* If kind == ASSEMBLY */
 -      char *msg; /* If kind == BAD_IMAGE */
 -} MonoLoaderError;
 -
  void
  mono_class_setup_supertypes (MonoClass *klass);
  
  void
 -mono_class_setup_fields_locking (MonoClass *klass);
 +mono_class_setup_fields (MonoClass *klass);
  
  /* WARNING
   * Only call this function if you can ensure both @klass and @parent
@@@ -805,7 -794,7 +805,7 @@@ typedef struct 
        size_t imt_slots_with_collisions;
        size_t imt_max_collisions_in_slot;
        size_t imt_method_count_when_max_collisions;
 -      size_t imt_thunks_size;
 +      size_t imt_trampolines_size;
        size_t jit_info_table_insert_count;
        size_t jit_info_table_remove_count;
        size_t jit_info_table_lookup_count;
@@@ -926,9 -915,13 +926,9 @@@ typedef struct 
  
  extern MonoStats mono_stats;
  
 -typedef gpointer (*MonoTrampoline)       (MonoMethod *method);
 -typedef gpointer (*MonoJumpTrampoline)       (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper);
 -typedef gpointer (*MonoRemotingTrampoline)       (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target);
 +typedef gpointer (*MonoRemotingTrampoline)       (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error);
  typedef gpointer (*MonoDelegateTrampoline)       (MonoDomain *domain, MonoClass *klass);
  
 -typedef gpointer (*MonoLookupDynamicToken) (MonoImage *image, guint32 token, gboolean valid_token, MonoClass **handle_class, MonoGenericContext *context);
 -
  typedef gboolean (*MonoGetCachedClassInfo) (MonoClass *klass, MonoCachedClassInfo *res);
  
  typedef gboolean (*MonoGetClassFromName) (MonoImage *image, const char *name_space, const char *name, MonoClass **res);
@@@ -950,7 -943,7 +950,7 @@@ voi
  mono_classes_cleanup (void);
  
  void
 -mono_class_layout_fields   (MonoClass *klass);
 +mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_size, gboolean sre);
  
  void
  mono_class_setup_interface_offsets (MonoClass *klass);
@@@ -1016,17 -1009,26 +1016,17 @@@ mono_class_get_field_default_value (Mon
  const char*
  mono_class_get_property_default_value (MonoProperty *property, MonoTypeEnum *def_type);
  
 -void
 -mono_install_trampoline (MonoTrampoline func);
 -
 -void
 -mono_install_jump_trampoline (MonoJumpTrampoline func);
 -
  void
  mono_install_delegate_trampoline (MonoDelegateTrampoline func);
  
  gpointer
 -mono_lookup_dynamic_token (MonoImage *image, guint32 token, MonoGenericContext *context);
 +mono_lookup_dynamic_token (MonoImage *image, guint32 token, MonoGenericContext *context, MonoError *error);
  
  gpointer
 -mono_lookup_dynamic_token_class (MonoImage *image, guint32 token, gboolean check_token, MonoClass **handle_class, MonoGenericContext *context);
 -
 -void
 -mono_install_lookup_dynamic_token (MonoLookupDynamicToken func);
 +mono_lookup_dynamic_token_class (MonoImage *image, guint32 token, gboolean check_token, MonoClass **handle_class, MonoGenericContext *context, MonoError *error);
  
  gpointer
 -mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper);
 +mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper, MonoError *error);
  
  gpointer
  mono_runtime_create_delegate_trampoline (MonoClass *klass);
@@@ -1080,6 -1082,9 +1080,6 @@@ mono_metadata_get_inflated_signature (M
  MonoType*
  mono_class_inflate_generic_type_with_mempool (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error);
  
 -MonoClass*
 -mono_class_inflate_generic_class (MonoClass *gklass, MonoGenericContext *context);
 -
  MonoType*
  mono_class_inflate_generic_type_checked (MonoType *type, MonoGenericContext *context, MonoError *error);
  
@@@ -1118,6 -1123,7 +1118,6 @@@ typedef struct 
        MonoClass *fieldhandle_class;
        MonoClass *methodhandle_class;
        MonoClass *systemtype_class;
 -      MonoClass *monotype_class;
        MonoClass *runtimetype_class;
        MonoClass *exception_class;
        MonoClass *threadabortexception_class;
        MonoClass *typed_reference_class;
        MonoClass *argumenthandle_class;
        MonoClass *monitor_class;
 -      MonoClass *runtimesecurityframe_class;
 -      MonoClass *executioncontext_class;
 -      MonoClass *internals_visible_class;
        MonoClass *generic_ilist_class;
        MonoClass *generic_nullable_class;
 -      MonoClass *safehandle_class;
        MonoClass *handleref_class;
        MonoClass *attribute_class;
        MonoClass *customattribute_data_class;
 -      MonoClass *critical_finalizer_object;
 +      MonoClass *critical_finalizer_object; /* MAYBE NULL */
        MonoClass *generic_ireadonlylist_class;
        MonoClass *threadpool_wait_callback_class;
        MonoMethod *threadpool_perform_wait_callback_method;
  #define mono_object_is_transparent_proxy(object) (FALSE)
  #else
  MonoRemoteClass*
 -mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class);
 +mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class, MonoError *error);
  
  void
  mono_install_remoting_trampoline (MonoRemotingTrampoline func);
  #define GENERATE_GET_CLASS_WITH_CACHE_DECL(shortname) \
  MonoClass* mono_class_get_##shortname##_class (void);
  
 +#define GENERATE_TRY_GET_CLASS_WITH_CACHE_DECL(shortname) \
 +MonoClass* mono_class_try_get_##shortname##_class (void);
 +
  #define GENERATE_GET_CLASS_WITH_CACHE(shortname,namespace,name) \
  MonoClass*    \
  mono_class_get_##shortname##_class (void)     \
        static MonoClass *tmp_class;    \
        MonoClass *klass = tmp_class;   \
        if (!klass) {   \
 -              klass = mono_class_from_name (mono_defaults.corlib, #namespace, #name); \
 -              g_assert (klass);       \
 +              klass = mono_class_load_from_name (mono_defaults.corlib, #namespace, #name);    \
                mono_memory_barrier (); \
                tmp_class = klass;      \
        }       \
        return klass;   \
  }
  
 -#define GENERATE_STATIC_GET_CLASS_WITH_CACHE(shortname,namespace,name) \
 -static GENERATE_GET_CLASS_WITH_CACHE (shortname,namespace,name)
 +#define GENERATE_TRY_GET_CLASS_WITH_CACHE(shortname,namespace,name) \
 +MonoClass*    \
 +mono_class_try_get_##shortname##_class (void) \
 +{     \
 +      static volatile MonoClass *tmp_class;   \
 +      static volatile gboolean inited;        \
 +      MonoClass *klass = (MonoClass *)tmp_class;      \
 +      mono_memory_barrier (); \
 +      if (!inited) {  \
 +              klass = mono_class_try_load_from_name (mono_defaults.corlib, #namespace, #name);        \
 +              tmp_class = klass;      \
 +              mono_memory_barrier (); \
 +              inited = TRUE;  \
 +      }       \
 +      return klass;   \
 +}
  
 +GENERATE_TRY_GET_CLASS_WITH_CACHE_DECL (safehandle)
  
  #ifndef DISABLE_COM
  
@@@ -1244,6 -1237,32 +1244,6 @@@ mono_loader_lock_if_inited (void)
  void
  mono_loader_unlock_if_inited (void);
  
 -void
 -mono_loader_set_error_assembly_load (const char *assembly_name, gboolean ref_only);
 -
 -void
 -mono_loader_set_error_type_load (const char *class_name, const char *assembly_name);
 -
 -void
 -mono_loader_set_error_method_load (const char *class_name, const char *member_name);
 -
 -void
 -mono_loader_set_error_field_load (MonoClass *klass, const char *member_name);
 -void
 -mono_loader_set_error_bad_image (char *msg);
 -
 -MonoException *
 -mono_loader_error_prepare_exception (MonoLoaderError *error);
 -
 -MonoLoaderError *
 -mono_loader_get_last_error (void);
 -
 -void
 -mono_loader_clear_error    (void);
 -
 -void
 -mono_loader_assert_no_error (void);
 -
  void
  mono_reflection_init       (void);
  
@@@ -1292,7 -1311,10 +1292,7 @@@ const char
  mono_lookup_jit_icall_symbol (const char *name);
  
  gboolean
 -mono_class_set_failure (MonoClass *klass, guint32 ex_type, void *ex_data);
 -
 -gpointer
 -mono_class_get_exception_data (MonoClass *klass);
 +mono_class_set_type_load_failure (MonoClass *klass, const char * fmt, ...) MONO_ATTR_FORMAT_PRINTF(2,3);
  
  MonoException*
  mono_class_get_exception_for_failure (MonoClass *klass);
@@@ -1304,10 -1326,7 +1304,10 @@@ char
  mono_type_get_full_name (MonoClass *klass);
  
  char *
 -mono_method_get_name_full (MonoMethod *method, gboolean signature, MonoTypeNameFormat format);
 +mono_method_get_name_full (MonoMethod *method, gboolean signature, gboolean ret, MonoTypeNameFormat format);
 +
 +char *
 +mono_method_get_full_name (MonoMethod *method);
  
  MonoArrayType *mono_dup_array_type (MonoImage *image, MonoArrayType *a);
  MonoMethodSignature *mono_metadata_signature_deep_dup (MonoImage *image, MonoMethodSignature *sig);
@@@ -1378,11 -1397,8 +1378,11 @@@ mono_class_setup_interface_id (MonoClas
  MonoGenericContainer*
  mono_class_get_generic_container (MonoClass *klass);
  
 -MonoGenericClass*
 -mono_class_get_generic_class (MonoClass *klass);
 +gpointer
 +mono_class_alloc (MonoClass *klass, int size);
 +
 +gpointer
 +mono_class_alloc0 (MonoClass *klass, int size);
  
  void
  mono_class_alloc_ext (MonoClass *klass);
@@@ -1394,7 -1410,7 +1394,7 @@@ MonoClassField
  mono_class_get_field_from_name_full (MonoClass *klass, const char *name, MonoType *type);
  
  MonoVTable*
 -mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, gboolean raise_on_error);
 +mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error);
  
  gboolean
  mono_class_is_assignable_from_slow (MonoClass *target, MonoClass *candidate);
@@@ -1423,7 -1439,7 +1423,7 @@@ voi
  mono_unload_interface_id (MonoClass *klass);
  
  GPtrArray*
 -mono_class_get_methods_by_name (MonoClass *klass, const char *name, guint32 bflags, gboolean ignore_case, gboolean allow_ctors, MonoException **ex);
 +mono_class_get_methods_by_name (MonoClass *klass, const char *name, guint32 bflags, gboolean ignore_case, gboolean allow_ctors, MonoError *error);
  
  char*
  mono_class_full_name (MonoClass *klass);
@@@ -1458,47 -1474,4 +1458,47 @@@ get_image_for_generic_param (MonoGeneri
  char *
  make_generic_name_string (MonoImage *image, int num);
  
 +MonoClass *
 +mono_class_load_from_name (MonoImage *image, const char* name_space, const char *name) MONO_LLVM_INTERNAL;
 +
 +MonoClass*
 +mono_class_try_load_from_name (MonoImage *image, const char* name_space, const char *name);
 +
 +void
 +mono_error_set_for_class_failure (MonoError *orerror, const MonoClass *klass);
 +
 +gboolean
 +mono_class_has_failure (const MonoClass *klass);
 +
 +/* Kind specific accessors */
 +MonoGenericClass*
 +mono_class_get_generic_class (MonoClass *klass);
 +
 +MonoGenericClass*
 +mono_class_try_get_generic_class (MonoClass *klass);
 +
 +void
 +mono_class_set_flags (MonoClass *klass, guint32 flags);
 +
 +MonoGenericContainer*
 +mono_class_try_get_generic_container (MonoClass *klass);
 +
 +void
 +mono_class_set_generic_container (MonoClass *klass, MonoGenericContainer *container);
 +
 +guint32
 +mono_class_get_first_method_idx (MonoClass *klass);
 +
 +void
 +mono_class_set_first_method_idx (MonoClass *klass, guint32 idx);
 +
 +guint32
 +mono_class_get_first_field_idx (MonoClass *klass);
 +
 +void
 +mono_class_set_first_field_idx (MonoClass *klass, guint32 idx);
 +
 +/*Now that everything has been defined, let's include the inline functions */
 +#include <mono/metadata/class-inlines.h>
 +
  #endif /* __MONO_METADATA_CLASS_INTERNALS_H__ */
diff --combined mono/metadata/class.c
index 6e1fb1d8bb9a11e6d42e8bec8f61e50fa52e900e,60e320b6970e94c627e052492430b5ab8b21b71a..042c869adccf3ee198a8e02451ca412ce496b3db
@@@ -7,7 -7,6 +7,7 @@@
   * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
   * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
   * Copyright 2012 Xamarin Inc (http://www.xamarin.com)
 + * Licensed under the MIT license. See LICENSE file in the project root for full license information.
   */
  #include <config.h>
  #ifdef HAVE_ALLOCA_H
@@@ -18,9 -17,7 +18,9 @@@
  #include <string.h>
  #include <stdlib.h>
  #include <mono/metadata/image.h>
 +#include <mono/metadata/image-internals.h>
  #include <mono/metadata/assembly.h>
 +#include <mono/metadata/assembly-internals.h>
  #include <mono/metadata/metadata.h>
  #include <mono/metadata/metadata-internals.h>
  #include <mono/metadata/profiler-private.h>
@@@ -54,9 -51,8 +54,9 @@@ gboolean mono_print_vtable = FALSE
  gboolean mono_align_small_structs = FALSE;
  
  /* Statistics */
 -guint32 inflated_classes, inflated_classes_size, inflated_methods_size;
 -guint32 classes_size, class_ext_size;
 +guint32 inflated_classes_size, inflated_methods_size;
 +guint32 classes_size, class_ext_size, class_ext_count;
 +guint32 class_def_count, class_gtd_count, class_ginst_count, class_gparam_count, class_array_count, class_pointer_count;
  
  /* Low level lock which protects data structures in this module */
  static mono_mutex_t classes_mutex;
@@@ -78,10 -74,6 +78,10 @@@ static guint32 mono_field_resolve_flag
  static void mono_class_setup_vtable_full (MonoClass *klass, GList *in_setup);
  static void mono_generic_class_setup_parent (MonoClass *klass, MonoClass *gklass);
  
 +static gboolean mono_class_set_failure (MonoClass *klass, MonoErrorBoxed *boxed_error);
 +static gpointer mono_class_get_exception_data (const MonoClass *klass);
 +
 +
  /*
  We use gclass recording to allow recursive system f types to be referenced by a parent.
  
@@@ -109,11 -101,6 +109,11 @@@ static int record_gclass_instantiation
  static GSList *gclass_recorded_list;
  typedef gboolean (*gclass_record_func) (MonoClass*, void*);
  
 +/* This TLS variable points to a GSList of classes which have setup_fields () executing */
 +static MonoNativeTlsKey setup_fields_tls_id;
 +
 +static MonoNativeTlsKey init_pending_tls_id;
 +
  static inline void
  classes_lock (void)
  {
@@@ -163,14 -150,14 +163,14 @@@ disable_gclass_recording (gclass_record
        }
  }
  
 -/*
 +/**
   * mono_class_from_typeref:
   * @image: a MonoImage
   * @type_token: a TypeRef token
   *
   * Creates the MonoClass* structure representing the type defined by
   * the typeref token valid inside @image.
 - * Returns: the MonoClass* representing the typeref token, NULL ifcould
 + * Returns: The MonoClass* representing the typeref token, NULL ifcould
   * not be loaded.
   */
  MonoClass *
@@@ -182,19 -169,6 +182,19 @@@ mono_class_from_typeref (MonoImage *ima
        return klass;
  }
  
 +/**
 + * mono_class_from_typeref_checked:
 + * @image: a MonoImage
 + * @type_token: a TypeRef token
 + * @error: error return code, if any.
 + *
 + * Creates the MonoClass* structure representing the type defined by
 + * the typeref token valid inside @image.
 + *
 + * Returns: The MonoClass* representing the typeref token, NULL if it could
 + * not be loaded with the @error value filled with the information about the
 + * error.
 + */
  MonoClass *
  mono_class_from_typeref_checked (MonoImage *image, guint32 type_token, MonoError *error)
  {
                goto done;
  
        case MONO_RESOLUTION_SCOPE_MODULEREF:
 -              module = mono_image_load_module (image, idx);
 +              module = mono_image_load_module_checked (image, idx, error);
                if (module)
                        res = mono_class_from_name_checked (module, nspace, name, error);
                goto done;
                }
  
                enclosing = mono_class_from_typeref_checked (image, MONO_TOKEN_TYPE_REF | idx, error); 
 -              if (!mono_error_ok (error))
 -                      return NULL;
 +              return_val_if_nok (error, NULL);
  
                if (enclosing->nested_classes_inited && enclosing->ext) {
                        /* Micro-optimization: don't scan the metadata tables if enclosing is already inited */
  done:
        /* Generic case, should be avoided for when a better error is possible. */
        if (!res && mono_error_ok (error)) {
 -              if (mono_loader_get_last_error ()) { /*FIXME plug the above to not leak errors*/
 -                      mono_error_set_from_loader_error (error);
 -              } else {
 -                      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);
 -              }
 +              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);
        }
 -      mono_loader_assert_no_error ();
        return res;
  }
  
@@@ -507,8 -487,8 +507,8 @@@ mono_type_get_name_recurse (MonoType *t
                }
                if (is_recursed)
                        break;
 -              if (klass->generic_class) {
 -                      MonoGenericClass *gclass = klass->generic_class;
 +              if (mono_class_is_ginst (klass)) {
 +                      MonoGenericClass *gclass = mono_class_get_generic_class (klass);
                        MonoGenericInst *inst = gclass->context.class_inst;
                        MonoTypeNameFormat nested_format;
                        int i;
                                g_string_append_c (str, '>');
                        else
                                g_string_append_c (str, ']');
 -              } else if (klass->generic_container &&
 +              } else if (mono_class_is_gtd (klass) &&
                           (format != MONO_TYPE_NAME_FORMAT_FULL_NAME) &&
                           (format != MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)) {
                        int i;
                                g_string_append_c (str, '<');
                        else
                                g_string_append_c (str, '[');
 -                      for (i = 0; i < klass->generic_container->type_argc; i++) {
 +                      for (i = 0; i < mono_class_get_generic_container (klass)->type_argc; i++) {
                                if (i)
                                        g_string_append_c (str, ',');
 -                              g_string_append (str, mono_generic_container_get_param_info (klass->generic_container, i)->name);
 +                              g_string_append (str, mono_generic_container_get_param_info (mono_class_get_generic_container (klass), i)->name);
                        }
                        if (format == MONO_TYPE_NAME_FORMAT_IL) 
                                g_string_append_c (str, '>');
   * @format: the format for the return string.
   *
   * 
 - * Returns: the string representation in a number of formats:
 + * Returns: The string representation in a number of formats:
   *
   * if format is MONO_TYPE_NAME_FORMAT_REFLECTION, the return string is
   * returned in the formatrequired by System.Reflection, this is the
@@@ -601,7 -581,7 +601,7 @@@ mono_type_get_name_full (MonoType *type
   * mono_type_get_full_name:
   * @class: a class
   *
 - * Returns: the string representation for type as required by System.Reflection.
 + * Returns: The string representation for type as required by System.Reflection.
   * The inverse of mono_reflection_parse_type ().
   */
  char *
@@@ -614,7 -594,7 +614,7 @@@ mono_type_get_full_name (MonoClass *kla
   * mono_type_get_name:
   * @type: a type
   *
 - * Returns: the string representation for type as it would be represented in IL code.
 + * Returns: The string representation for type as it would be represented in IL code.
   */
  char*
  mono_type_get_name (MonoType *type)
   * mono_type_get_underlying_type:
   * @type: a type
   *
 - * Returns: the MonoType for the underlying integer type if @type
 + * Returns: The MonoType for the underlying integer type if @type
   * is an enum and byref is false, otherwise the type itself.
   */
  MonoType*
@@@ -639,11 -619,11 +639,11 @@@ mono_type_get_underlying_type (MonoTyp
        return type;
  }
  
 -/*
 +/**
   * mono_class_is_open_constructed_type:
   * @type: a type
   *
 - * Returns TRUE if type represents a generics open constructed type.
 + * Returns: TRUE if type represents a generics open constructed type.
   * IOW, not all type parameters required for the instantiation have
   * been provided or it's a generic type definition.
   *
@@@ -668,7 -648,7 +668,7 @@@ mono_class_is_open_constructed_type (Mo
                return t->data.generic_class->context.class_inst->is_open;
        case MONO_TYPE_CLASS:
        case MONO_TYPE_VALUETYPE:
 -              return t->data.klass->generic_container != NULL;
 +              return mono_class_is_gtd (t->data.klass);
        default:
                return FALSE;
        }
@@@ -776,8 -756,8 +776,8 @@@ inflate_generic_type (MonoImage *image
                        return NULL;
  
                inst = mono_metadata_inflate_generic_inst (gclass->context.class_inst, context, error);
 -              if (!mono_error_ok (error))
 -                      return NULL;
 +              return_val_if_nok (error, NULL);
 +
                if (inst != gclass->context.class_inst)
                        gclass = mono_metadata_lookup_generic_class (gclass->container_class, inst, gclass->is_dynamic);
  
        case MONO_TYPE_CLASS:
        case MONO_TYPE_VALUETYPE: {
                MonoClass *klass = type->data.klass;
 -              MonoGenericContainer *container = klass->generic_container;
 +              MonoGenericContainer *container = mono_class_try_get_generic_container (klass);
                MonoGenericInst *inst;
                MonoGenericClass *gclass = NULL;
                MonoType *nt;
  
                /* We can't use context->class_inst directly, since it can have more elements */
                inst = mono_metadata_inflate_generic_inst (container->context.class_inst, context, error);
 -              if (!mono_error_ok (error))
 -                      return NULL;
 +              return_val_if_nok (error, NULL);
 +
                if (inst == container->context.class_inst)
                        return NULL;
  
@@@ -828,8 -808,33 +828,8 @@@ mono_generic_class_get_context (MonoGen
  MonoGenericContext *
  mono_class_get_context (MonoClass *klass)
  {
 -       return klass->generic_class ? mono_generic_class_get_context (klass->generic_class) : NULL;
 -}
 -
 -/*
 - * mono_class_get_generic_container:
 - *
 - *   Return the generic container of KLASS which should be a generic type definition.
 - */
 -MonoGenericContainer*
 -mono_class_get_generic_container (MonoClass *klass)
 -{
 -      g_assert (klass->is_generic);
 -
 -      return klass->generic_container;
 -}
 -
 -/*
 - * mono_class_get_generic_class:
 - *
 - *   Return the MonoGenericClass of KLASS, which should be a generic instance.
 - */
 -MonoGenericClass*
 -mono_class_get_generic_class (MonoClass *klass)
 -{
 -      g_assert (klass->is_inflated);
 -
 -      return klass->generic_class;
 +      MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
 +      return gklass ? mono_generic_class_get_context (gklass) : NULL;
  }
  
  /*
@@@ -853,7 -858,8 +853,7 @@@ mono_class_inflate_generic_type_with_me
  
        if (context)
                inflated = inflate_generic_type (image, type, context, error);
 -      if (!mono_error_ok (error))
 -              return NULL;
 +      return_val_if_nok (error, NULL);
  
        if (!inflated) {
                MonoType *shared = mono_metadata_get_shared_type (type);
   * If @type is a generic type and @context is not NULL, instantiate it using the 
   * generics context @context.
   *
 - * Returns: the instantiated type or a copy of @type. The returned MonoType is allocated
 + * Returns: The instantiated type or a copy of @type. The returned MonoType is allocated
   * on the heap and is owned by the caller. Returns NULL on error.
   *
   * @deprecated Please use mono_class_inflate_generic_type_checked instead
@@@ -888,7 -894,11 +888,7 @@@ mono_class_inflate_generic_type (MonoTy
        MonoError error;
        MonoType *result;
        result = mono_class_inflate_generic_type_checked (type, context, &error);
 -
 -      if (!mono_error_ok (&error)) {
 -              mono_error_cleanup (&error);
 -              return NULL;
 -      }
 +      mono_error_cleanup (&error);
        return result;
  }
  
   * If @type is a generic type and @context is not NULL, instantiate it using the 
   * generics context @context.
   *
 - * Returns: the instantiated type or a copy of @type. The returned MonoType is allocated
 + * Returns: The instantiated type or a copy of @type. The returned MonoType is allocated
   * on the heap and is owned by the caller.
   */
  MonoType*
@@@ -924,7 -934,8 +924,7 @@@ mono_class_inflate_generic_type_no_cop
        mono_error_init (error);
        if (context) {
                inflated = inflate_generic_type (image, type, context, error);
 -              if (!mono_error_ok (error))
 -                      return NULL;
 +              return_val_if_nok (error, NULL);
        }
  
        if (!inflated)
        return inflated;
  }
  
 +/*
 + * mono_class_inflate_generic_class:
 + *
 + *   Inflate the class @gklass with @context. Set @error on failure.
 + */
  MonoClass*
  mono_class_inflate_generic_class_checked (MonoClass *gklass, MonoGenericContext *context, MonoError *error)
  {
        MonoType *inflated;
  
        inflated = mono_class_inflate_generic_type_checked (&gklass->byval_arg, context, error);
 -      if (!mono_error_ok (error))
 -              return NULL;
 +      return_val_if_nok (error, NULL);
  
        res = mono_class_from_mono_type (inflated);
        mono_metadata_free_type (inflated);
  
        return res;
  }
 -/*
 - * mono_class_inflate_generic_class:
 - *
 - *   Inflate the class GKLASS with CONTEXT.
 - */
 -MonoClass*
 -mono_class_inflate_generic_class (MonoClass *gklass, MonoGenericContext *context)
 -{
 -      MonoError error;
 -      MonoClass *res;
 -
 -      res = mono_class_inflate_generic_class_checked (gklass, context, &error);
 -      g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
 -
 -      return res;
 -}
 -
 -
  
  static MonoGenericContext
  inflate_generic_context (MonoGenericContext *context, MonoGenericContext *inflate_with, MonoError *error)
@@@ -988,7 -1013,7 +988,7 @@@ fail
   *
   * Instantiate the generic method @method using the generics context @context.
   *
 - * Returns: the new instantiated method
 + * Returns: The new instantiated method
   */
  MonoMethod *
  mono_class_inflate_generic_method (MonoMethod *method, MonoGenericContext *context)
@@@ -1041,8 -1066,8 +1041,8 @@@ mono_class_inflate_generic_method_full_
                MonoMethodInflated *imethod = (MonoMethodInflated *) method;
  
                tmp_context = inflate_generic_context (method_context, context, error);
 -              if (!mono_error_ok (error))
 -                      return NULL;
 +              return_val_if_nok (error, NULL);
 +
                context = &tmp_context;
  
                if (mono_metadata_generic_context_equal (method_context, context))
         * 
         */
        if (!((method->is_generic && context->method_inst) || 
 -              (method->klass->generic_container && context->class_inst)))
 +              (mono_class_is_gtd (method->klass) && context->class_inst)))
                return method;
  
        iresult = g_new0 (MonoMethodInflated, 1);
                iresult->context.method_inst = mono_method_get_generic_container (method)->context.method_inst;
  
        if (!context->class_inst) {
 -              g_assert (!iresult->declaring->klass->generic_class);
 -              if (iresult->declaring->klass->generic_container)
 -                      iresult->context.class_inst = iresult->declaring->klass->generic_container->context.class_inst;
 -              else if (iresult->declaring->klass->generic_class)
 -                      iresult->context.class_inst = iresult->declaring->klass->generic_class->context.class_inst;
 +              g_assert (!mono_class_is_ginst (iresult->declaring->klass));
 +              if (mono_class_is_gtd (iresult->declaring->klass))
 +                      iresult->context.class_inst = mono_class_get_generic_container (iresult->declaring->klass)->context.class_inst;
        }
        /* This can happen with some callers like mono_object_get_virtual_method () */
 -      if (!iresult->declaring->klass->generic_container && !iresult->declaring->klass->generic_class)
 +      if (!mono_class_is_gtd (iresult->declaring->klass) && !mono_class_is_ginst (iresult->declaring->klass))
                iresult->context.class_inst = NULL;
  
        MonoImageSet *set = mono_metadata_get_image_set_for_method (iresult);
        result->sre_method = FALSE;
        result->signature = NULL;
  
 -      if (!context->method_inst) {
 +      if (method->wrapper_type) {
 +              MonoMethodWrapper *mw = (MonoMethodWrapper*)method;
 +              MonoMethodWrapper *resw = (MonoMethodWrapper*)result;
 +              int len = GPOINTER_TO_INT (((void**)mw->method_data) [0]);
 +
 +              resw->method_data = (void **)g_malloc (sizeof (gpointer) * (len + 1));
 +              memcpy (resw->method_data, mw->method_data, sizeof (gpointer) * (len + 1));
 +      }
 +
 +      if (iresult->context.method_inst) {
                /* Set the generic_container of the result to the generic_container of method */
                MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
  
 -              if (generic_container) {
 +              if (generic_container && iresult->context.method_inst == generic_container->context.method_inst) {
                        result->is_generic = 1;
                        mono_method_set_generic_container (result, generic_container);
                }
        }
  
 -      if (!klass_hint || !klass_hint->generic_class ||
 -          klass_hint->generic_class->container_class != method->klass ||
 -          klass_hint->generic_class->context.class_inst != context->class_inst)
 -              klass_hint = NULL;
 +      if (klass_hint) {
 +              MonoGenericClass *gklass_hint = mono_class_try_get_generic_class (klass_hint);
 +              if (gklass_hint && (gklass_hint->container_class != method->klass || gklass_hint->context.class_inst != context->class_inst))
 +                      klass_hint = NULL;
 +      }
  
 -      if (method->klass->generic_container)
 +      if (mono_class_is_gtd (method->klass))
                result->klass = klass_hint;
  
        if (!result->klass) {
@@@ -1215,8 -1232,8 +1215,8 @@@ mono_method_get_context_general (MonoMe
                return NULL;
        if (method->is_generic)
                return &(mono_method_get_generic_container (method)->context);
 -      if (method->klass->generic_container)
 -              return &method->klass->generic_container->context;
 +      if (mono_class_is_gtd (method->klass))
 +              return &mono_class_get_generic_container (method->klass)->context;
        return NULL;
  }
  
@@@ -1281,31 -1298,31 +1281,31 @@@ mono_class_find_enum_basetype (MonoClas
        MonoGenericContainer *container = NULL;
        MonoImage *m = klass->image;
        const int top = klass->field.count;
 -      int i;
 +      int i, first_field_idx;
  
        g_assert (klass->enumtype);
  
        mono_error_init (error);
  
 -      if (klass->generic_container)
 -              container = klass->generic_container;
 -      else if (klass->generic_class) {
 -              MonoClass *gklass = klass->generic_class->container_class;
 +      container = mono_class_try_get_generic_container (klass);
 +      if (mono_class_is_ginst (klass)) {
 +              MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
  
 -              container = gklass->generic_container;
 +              container = mono_class_get_generic_container (gklass);
                g_assert (container);
        }
  
        /*
         * Fetch all the field information.
         */
 +      first_field_idx = mono_class_get_first_field_idx (klass);
        for (i = 0; i < top; i++){
                const char *sig;
                guint32 cols [MONO_FIELD_SIZE];
 -              int idx = klass->field.first + i;
 +              int idx = first_field_idx + i;
                MonoType *ftype;
  
 -              /* klass->field.first and idx points into the fieldptr table */
 +              /* first_field_idx and idx points into the fieldptr table */
                mono_metadata_decode_table_row (m, MONO_TABLE_FIELD, idx, cols, MONO_FIELD_SIZE);
  
                if (cols [MONO_FIELD_FLAGS] & FIELD_ATTRIBUTE_STATIC) //no need to decode static fields
                        goto fail;
                }
  
 -              ftype = mono_metadata_parse_type_full (m, container, cols [MONO_FIELD_FLAGS], sig + 1, &sig);
 -              if (!ftype) {
 -                      if (mono_loader_get_last_error ()) /*FIXME plug the above to not leak errors*/
 -                              mono_error_set_from_loader_error (error);
 -                      else
 -                              mono_error_set_bad_image (error, klass->image, "Could not parse type for field signature %x", cols [MONO_FIELD_SIGNATURE]);
 +              ftype = mono_metadata_parse_type_checked (m, container, cols [MONO_FIELD_FLAGS], FALSE, sig + 1, &sig, error);
 +              if (!ftype)
                        goto fail;
 -              }
 -              if (klass->generic_class) {
 +
 +              if (mono_class_is_ginst (klass)) {
                        //FIXME do we leak here?
                        ftype = mono_class_inflate_generic_type_checked (ftype, mono_class_get_context (klass), error);
                        if (!mono_error_ok (error))
        mono_error_set_type_load_class (error, klass, "Could not find base type");
  
  fail:
 -      mono_loader_assert_no_error ();
        return NULL;
  }
  
  /*
 - * Checks for MonoClass::exception_type without resolving all MonoType's into MonoClass'es
 + * Checks for MonoClass::has_failure without resolving all MonoType's into MonoClass'es
   */
  static gboolean
  mono_type_has_exceptions (MonoType *type)
        case MONO_TYPE_CLASS:
        case MONO_TYPE_VALUETYPE:
        case MONO_TYPE_SZARRAY:
 -              return type->data.klass->exception_type;
 +              return mono_class_has_failure (type->data.klass);
        case MONO_TYPE_ARRAY:
 -              return type->data.array->eklass->exception_type;
 +              return mono_class_has_failure (type->data.array->eklass);
        case MONO_TYPE_GENERICINST:
 -              return mono_generic_class_get_class (type->data.generic_class)->exception_type;
 +              return mono_class_has_failure (mono_generic_class_get_class (type->data.generic_class));
        default:
                return FALSE;
        }
  }
  
 +void
 +mono_error_set_for_class_failure (MonoError *oerror, const MonoClass *klass)
 +{
 +      g_assert (mono_class_has_failure (klass));
 +      MonoErrorBoxed *box = (MonoErrorBoxed*)mono_class_get_exception_data (klass);
 +      mono_error_set_from_boxed (oerror, box);
 +}
 +
 +
  /*
   * mono_class_alloc:
   *
   *   Allocate memory for some data belonging to CLASS, either from its image's mempool,
   * or from the heap.
   */
 -static gpointer
 +gpointer
  mono_class_alloc (MonoClass *klass, int size)
  {
 -      if (klass->generic_class)
 -              return mono_image_set_alloc (klass->generic_class->owner, size);
 +      MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
 +      if (gklass)
 +              return mono_image_set_alloc (gklass->owner, size);
        else
                return mono_image_alloc (klass->image, size);
  }
  
 -static gpointer
 +gpointer
  mono_class_alloc0 (MonoClass *klass, int size)
  {
        gpointer res;
   * mono_class_setup_basic_field_info:
   * @class: The class to initialize
   *
 - * Initializes the klass->fields.
 - * LOCKING: Assumes the loader lock is held.
 + * Initializes the following fields in MonoClass:
 + * * klass->fields (only field->parent and field->name)
 + * * klass->field.count
 + * * klass->first_field_idx
 + * LOCKING: Acquires the loader lock
   */
  static void
  mono_class_setup_basic_field_info (MonoClass *klass)
  {
 +      MonoGenericClass *gklass;
        MonoClassField *field;
 +      MonoClassField *fields;
        MonoClass *gtd;
        MonoImage *image;
        int i, top;
        if (klass->fields)
                return;
  
 -      gtd = klass->generic_class ? mono_class_get_generic_type_definition (klass) : NULL;
 +      gklass = mono_class_try_get_generic_class (klass);
 +      gtd = gklass ? mono_class_get_generic_type_definition (klass) : NULL;
        image = klass->image;
 -      top = klass->field.count;
  
 -      if (klass->generic_class && image_is_dynamic (klass->generic_class->container_class->image) && !klass->generic_class->container_class->wastypebuilder) {
 +
 +      if (gklass && image_is_dynamic (gklass->container_class->image) && !gklass->container_class->wastypebuilder) {
                /*
                 * This happens when a generic instance of an unfinished generic typebuilder
                 * is used as an element type for creating an array type. We can't initialize
        if (gtd) {
                mono_class_setup_basic_field_info (gtd);
  
 -              top = gtd->field.count;
 -              klass->field.first = gtd->field.first;
 +              mono_loader_lock ();
                klass->field.count = gtd->field.count;
 +              mono_loader_unlock ();
        }
  
 -      klass->fields = (MonoClassField *)mono_class_alloc0 (klass, sizeof (MonoClassField) * top);
 +      top = klass->field.count;
 +
 +      fields = (MonoClassField *)mono_class_alloc0 (klass, sizeof (MonoClassField) * top);
  
        /*
         * Fetch all the field information.
         */
 -      for (i = 0; i < top; i++){
 -              field = &klass->fields [i];
 +      int first_field_idx = mono_class_has_static_metadata (klass) ? mono_class_get_first_field_idx (klass) : 0;
 +      for (i = 0; i < top; i++) {
 +              field = &fields [i];
                field->parent = klass;
  
                if (gtd) {
                        field->name = mono_field_get_name (&gtd->fields [i]);
                } else {
 -                      int idx = klass->field.first + i;
 -                      /* klass->field.first and idx points into the fieldptr table */
 +                      int idx = first_field_idx + i;
 +                      /* first_field_idx and idx points into the fieldptr table */
                        guint32 name_idx = mono_metadata_decode_table_row_col (image, MONO_TABLE_FIELD, idx, MONO_FIELD_NAME);
                        /* The name is needed for fieldrefs */
                        field->name = mono_metadata_string_heap (image, name_idx);
                }
        }
 +
 +      mono_memory_barrier ();
 +
 +      mono_loader_lock ();
 +      if (!klass->fields)
 +              klass->fields = fields;
 +      mono_loader_unlock ();
  }
  
 +/**
 + * mono_class_set_failure_causedby_class:
 + * @klass: the class that is failing
 + * @caused_by: the class that caused the failure
 + * @msg: Why @klass is failing.
 + * 
 + * If @caused_by has a failure, sets a TypeLoadException failure on
 + * @klass with message "@msg, due to: {@caused_by message}".
 + *
 + * Returns: TRUE if a failiure was set, or FALSE if @caused_by doesn't have a failure.
 + */
 +static gboolean
 +mono_class_set_type_load_failure_causedby_class (MonoClass *klass, const MonoClass *caused_by, const gchar* msg)
 +{
 +      if (mono_class_has_failure (caused_by)) {
 +              MonoError cause_error;
 +              mono_error_init (&cause_error);
 +              mono_error_set_for_class_failure (&cause_error, caused_by);
 +              mono_class_set_type_load_failure (klass, "%s, due to: %s", msg, mono_error_get_message (&cause_error));
 +              mono_error_cleanup (&cause_error);
 +              return TRUE;
 +      } else {
 +              return FALSE;
 +      }
 +}
 +
 +
  /** 
   * mono_class_setup_fields:
 - * @class: The class to initialize
 + * @klass: The class to initialize
 + *
 + * Initializes klass->fields, computes class layout and sizes.
 + * typebuilder_setup_fields () is the corresponding function for dynamic classes.
 + * Sets the following fields in @klass:
 + *  - all the fields initialized by mono_class_init_sizes ()
 + *  - element_class/cast_class (for enums)
 + *  - field->type/offset for all fields
 + *  - fields_inited
   *
 - * Initializes the klass->fields.
 - * LOCKING: Assumes the loader lock is held.
 + * LOCKING: Acquires the loader lock.
   */
 -static void
 +void
  mono_class_setup_fields (MonoClass *klass)
  {
        MonoError error;
        MonoImage *m = klass->image;
        int top;
 -      guint32 layout = klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK;
 -      int i, blittable = TRUE;
 +      guint32 layout = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK;
 +      int i;
        guint32 real_size = 0;
        guint32 packing_size = 0;
 +      int instance_size;
        gboolean explicit_size;
        MonoClassField *field;
 -      MonoGenericContainer *container = NULL;
 -      MonoClass *gtd = klass->generic_class ? mono_class_get_generic_type_definition (klass) : NULL;
 +      MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
 +      MonoClass *gtd = gklass ? mono_class_get_generic_type_definition (klass) : NULL;
  
 -      /*
 -       * FIXME: We have a race condition here.  It's possible that this function returns
 -       * to its caller with `instance_size` set to `0` instead of the actual size.  This
 -       * is not a problem when the function is called recursively on the same class,
 -       * because the size will be initialized by the outer invocation.  What follows is a
 -       * description of how it can occur in other cases, too.  There it is a problem,
 -       * because it can lead to the GC being asked to allocate an object of size `0`,
 -       * which SGen chokes on.  The race condition is triggered infrequently by
 -       * `tests/sgen-suspend.cs`.
 -       *
 -       * This function is called for a class whenever one of its subclasses is inited.
 -       * For example, it's called for every subclass of Object.  What it does is this:
 -       *
 -       *     if (klass->setup_fields_called)
 -       *         return;
 -       *     ...
 -       *     klass->instance_size = 0;
 -       *     ...
 -       *     klass->setup_fields_called = 1;
 -       *     ... critical point
 -       *     klass->instance_size = actual_instance_size;
 -       *
 -       * The last two steps are sometimes reversed, but that only changes the way in which
 -       * the race condition works.
 -       *
 -       * Assume thread A goes through this function and makes it to the critical point.
 -       * Now thread B runs the function and, since `setup_fields_called` is set, returns
 -       * immediately, but `instance_size` is incorrect.
 -       *
 -       * The other case looks like this:
 -       *
 -       *     if (klass->setup_fields_called)
 -       *         return;
 -       *     ... critical point X
 -       *     klass->instance_size = 0;
 -       *     ... critical point Y
 -       *     klass->instance_size = actual_instance_size;
 -       *     ...
 -       *     klass->setup_fields_called = 1;
 -       *
 -       * Assume thread A goes through the function and makes it to critical point X.  Now
 -       * thread B runs through the whole of the function, returning, assuming
 -       * `instance_size` is set.  At that point thread A gets to run and makes it to
 -       * critical point Y, at which time `instance_size` is `0` again, invalidating thread
 -       * B's assumption.
 -       */
 -      if (klass->setup_fields_called)
 +      if (klass->fields_inited)
                return;
  
 -      if (klass->generic_class && image_is_dynamic (klass->generic_class->container_class->image) && !klass->generic_class->container_class->wastypebuilder) {
 +      if (gklass && image_is_dynamic (gklass->container_class->image) && !gklass->container_class->wastypebuilder) {
                /*
                 * This happens when a generic instance of an unfinished generic typebuilder
                 * is used as an element type for creating an array type. We can't initialize
  
        if (gtd) {
                mono_class_setup_fields (gtd);
 -              if (gtd->exception_type) {
 -                      mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
 +              if (mono_class_set_type_load_failure_causedby_class (klass, gtd, "Generic type definition failed"))
                        return;
 -              }
        }
  
 -      klass->instance_size = 0;
 -      if (!klass->rank)
 -              klass->sizes.class_size = 0;
 -
 +      instance_size = 0;
        if (klass->parent) {
                /* For generic instances, klass->parent might not have been initialized */
                mono_class_init (klass->parent);
 -              if (!klass->parent->size_inited) {
 -                      mono_class_setup_fields (klass->parent);
 -                      if (klass->parent->exception_type) {
 -                              mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
 -                              return;
 -                      }
 -              }
 -              klass->instance_size += klass->parent->instance_size;
 -              klass->min_align = klass->parent->min_align;
 -              /* we use |= since it may have been set already */
 -              klass->has_references |= klass->parent->has_references;
 -              blittable = klass->parent->blittable;
 +              mono_class_setup_fields (klass->parent);
 +              if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Could not set up parent class"))
 +                      return;
 +              instance_size = klass->parent->instance_size;
        } else {
 -              klass->instance_size = sizeof (MonoObject);
 -              klass->min_align = 1;
 +              instance_size = sizeof (MonoObject);
        }
  
 -      /* We can't really enable 16 bytes alignment until the GC supports it.
 -      The whole layout/instance size code must be reviewed because we do alignment calculation in terms of the
 -      boxed instance, which leads to unexplainable holes at the beginning of an object embedding a simd type.
 -      Bug #506144 is an example of this issue.
 -
 -       if (klass->simd_type)
 -              klass->min_align = 16;
 -       */
        /* Get the real size */
        explicit_size = mono_metadata_packing_from_typedef (klass->image, klass->type_token, &packing_size, &real_size);
 +      if (explicit_size)
 +              instance_size += real_size;
  
 -      if (explicit_size) {
 -              if ((packing_size & 0xffffff00) != 0) {
 -                      char *err_msg = g_strdup_printf ("Could not load struct '%s' with packing size %d >= 256", klass->name, packing_size);
 -                      mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, err_msg);
 -                      return;
 -              }
 -              klass->packing_size = packing_size;
 -              real_size += klass->instance_size;
 -      }
 -
 -      if (!top) {
 -              if (explicit_size && real_size) {
 -                      klass->instance_size = MAX (real_size, klass->instance_size);
 -              }
 -              klass->blittable = blittable;
 -              mono_memory_barrier ();
 -              klass->size_inited = 1;
 -              klass->fields_inited = 1;
 -              klass->setup_fields_called = 1;
 +      /*
 +       * This function can recursively call itself.
 +       * Prevent infinite recursion by using a list in TLS.
 +       */
 +      GSList *init_list = (GSList *)mono_native_tls_get_value (setup_fields_tls_id);
 +      if (g_slist_find (init_list, klass))
                return;
 -      }
 -
 -      if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT && !(mono_is_corlib_image (klass->image) && !strcmp (klass->name_space, "System") && !strcmp (klass->name, "ValueType")))
 -              blittable = FALSE;
 -
 -      /* Prevent infinite loops if the class references itself */
 -      klass->setup_fields_called = 1;
 -
 -      if (klass->generic_container) {
 -              container = klass->generic_container;
 -      } else if (gtd) {
 -              container = gtd->generic_container;
 -              g_assert (container);
 -      }
 +      init_list = g_slist_prepend (init_list, klass);
 +      mono_native_tls_set_value (setup_fields_tls_id, init_list);
  
        /*
         * Fetch all the field information.
         */
 -      for (i = 0; i < top; i++){
 -              int idx = klass->field.first + i;
 +      int first_field_idx = mono_class_has_static_metadata (klass) ? mono_class_get_first_field_idx (klass) : 0;
 +      for (i = 0; i < top; i++) {
 +              int idx = first_field_idx + i;
                field = &klass->fields [i];
  
 -              field->parent = klass;
 -
                if (!field->type) {
                        mono_field_resolve_type (field, &error);
                        if (!mono_error_ok (&error)) {
                                /*mono_field_resolve_type already failed class*/
                                mono_error_cleanup (&error);
 -                              return;
 +                              break;
                        }
                        if (!field->type)
                                g_error ("could not resolve %s:%s\n", mono_type_get_full_name(klass), field->name);
  
                if (mono_field_is_deleted (field))
                        continue;
 -              if (gtd) {
 -                      MonoClassField *gfield = &gtd->fields [i];
 -                      field->offset = gfield->offset;
 -              } else {
 -                      if (layout == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
 -                              guint32 offset;
 -                              mono_metadata_field_info (m, idx, &offset, NULL, NULL);
 -                              field->offset = offset;
 +              if (layout == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
 +                      guint32 uoffset;
 +                      mono_metadata_field_info (m, idx, &uoffset, NULL, NULL);
 +                      int offset = uoffset;
  
 -                              if (field->offset == (guint32)-1 && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
 -                                      mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Missing field layout info for %s", field->name));
 -                                      break;
 -                              }
 -                              if (field->offset < -1) { /*-1 is used to encode special static fields */
 -                                      mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Invalid negative field offset %d for %s", field->offset, field->name));
 -                                      break;
 -                              }
 -                              if (klass->generic_container) {
 -                                      mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Generic class cannot have explicit layout."));
 -                                      break;
 -                              }
 +                      if (offset == (guint32)-1 && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
 +                              mono_class_set_type_load_failure (klass, "Missing field layout info for %s", field->name);
 +                              break;
                        }
 -              }
 -
 -              /* Only do these checks if we still think this type is blittable */
 -              if (blittable && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
 -                      if (field->type->byref || MONO_TYPE_IS_REFERENCE (field->type)) {
 -                              blittable = FALSE;
 -                      } else {
 -                              MonoClass *field_class = mono_class_from_mono_type (field->type);
 -                              if (field_class) {
 -                                      mono_class_setup_fields (field_class);
 -                                      if (field_class->exception_type) {
 -                                              mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
 -                                              break;
 -                                      }
 -                              }
 -                              if (!field_class || !field_class->blittable)
 -                                      blittable = FALSE;
 +                      if (offset < -1) { /*-1 is used to encode special static fields */
 +                              mono_class_set_type_load_failure (klass, "Field '%s' has a negative offset %d", field->name, offset);
 +                              break;
 +                      }
 +                      if (mono_class_is_gtd (klass)) {
 +                              mono_class_set_type_load_failure (klass, "Generic class cannot have explicit layout.");
 +                              break;
                        }
                }
 -
 -              if (klass->enumtype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
 -                      klass->cast_class = klass->element_class = mono_class_from_mono_type (field->type);
 -                      blittable = klass->element_class->blittable;
 -              }
 -
                if (mono_type_has_exceptions (field->type)) {
                        char *class_name = mono_type_get_full_name (klass);
                        char *type_name = mono_type_full_name (field->type);
  
 -                      mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
 +                      mono_class_set_type_load_failure (klass, "");
                        g_warning ("Invalid type %s for instance field %s:%s", type_name, class_name, field->name);
                        g_free (class_name);
                        g_free (type_name);
                /* The def_value of fields is compute lazily during vtable creation */
        }
  
 -      if (klass == mono_defaults.string_class)
 -              blittable = FALSE;
 +      if (!mono_class_has_failure (klass))
 +              mono_class_layout_fields (klass, instance_size, packing_size, FALSE);
  
 -      klass->blittable = blittable;
 +      init_list = g_slist_remove (init_list, klass);
 +      mono_native_tls_set_value (setup_fields_tls_id, init_list);
 +}
  
 -      if (klass->enumtype && !mono_class_enum_basetype (klass)) {
 -              mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
 -              return;
 +static void
 +init_sizes_with_info (MonoClass *klass, MonoCachedClassInfo *cached_info)
 +{
 +      if (cached_info) {
 +              klass->instance_size = cached_info->instance_size;
 +              klass->sizes.class_size = cached_info->class_size;
 +              klass->packing_size = cached_info->packing_size;
 +              klass->min_align = cached_info->min_align;
 +              klass->blittable = cached_info->blittable;
 +              klass->has_references = cached_info->has_references;
 +              klass->has_static_refs = cached_info->has_static_refs;
 +              klass->no_special_static_fields = cached_info->no_special_static_fields;
        }
 -      if (explicit_size && real_size) {
 -              klass->instance_size = MAX (real_size, klass->instance_size);
 +      else {
 +              if (!klass->size_inited)
 +                      mono_class_setup_fields (klass);
        }
 -
 -      if (klass->exception_type)
 -              return;
 -      mono_class_layout_fields (klass);
 -
 -      /*valuetypes can't be neither bigger than 1Mb or empty. */
 -      if (klass->valuetype && (klass->instance_size <= 0 || klass->instance_size > (0x100000 + sizeof (MonoObject))))
 -              mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
 -
 -      mono_memory_barrier ();
 -      klass->fields_inited = 1;
  }
 +/*
  
 -/** 
 - * mono_class_setup_fields_locking:
 - * @class: The class to initialize
 + * mono_class_init_sizes:
   *
 - * Initializes the klass->fields array of fields.
 - * Aquires the loader lock.
 - */
 -void
 -mono_class_setup_fields_locking (MonoClass *klass)
 -{
 -      /* This can be checked without locks */
 -      if (klass->fields_inited)
 -              return;
 -      mono_loader_lock ();
 -      mono_class_setup_fields (klass);
 -      mono_loader_unlock ();
 -}
 -
 -/*
 - * mono_class_has_references:
 + *   Initializes the size related fields of @klass without loading all field data if possible.
 + * Sets the following fields in @klass:
 + * - instance_size
 + * - sizes.class_size
 + * - packing_size
 + * - min_align
 + * - blittable
 + * - has_references
 + * - has_static_refs
 + * - size_inited
 + * Can fail the class.
   *
 - *   Returns whenever @klass->has_references is set, initializing it if needed.
 - * Aquires the loader lock.
 + * LOCKING: Acquires the loader lock.
   */
 -static gboolean
 -mono_class_has_references (MonoClass *klass)
 +static void
 +mono_class_init_sizes (MonoClass *klass)
  {
 -      if (klass->init_pending) {
 -              /* Be conservative */
 -              return TRUE;
 -      } else {
 -              mono_class_init (klass);
 +      MonoCachedClassInfo cached_info;
 +      gboolean has_cached_info;
  
 -              return klass->has_references;
 -      }
 +      has_cached_info = mono_class_get_cached_class_info (klass, &cached_info);
 +
 +      init_sizes_with_info (klass, has_cached_info ? &cached_info : NULL);
  }
  
  /*
@@@ -1709,29 -1799,16 +1709,29 @@@ mono_type_get_basic_type_from_generic (
        return type;
  }
  
 +static gboolean
 +class_has_references (MonoClass *klass)
 +{
 +      mono_class_init_sizes (klass);
 +
 +      /*
 +       * has_references is not set if this is called recursively, but this is not a problem since this is only used
 +       * during field layout, and instance fields are initialized before static fields, and instance fields can't
 +       * embed themselves.
 +       */
 +      return klass->has_references;
 +}
 +
  static gboolean
  type_has_references (MonoClass *klass, MonoType *ftype)
  {
 -      if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (klass, ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype)))))
 +      if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (klass, ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && class_has_references (mono_class_from_mono_type (ftype)))))
                return TRUE;
        if (!ftype->byref && (ftype->type == MONO_TYPE_VAR || ftype->type == MONO_TYPE_MVAR)) {
                MonoGenericParam *gparam = ftype->data.generic_param;
  
                if (gparam->gshared_constraint)
 -                      return mono_class_has_references (mono_class_from_mono_type (gparam->gshared_constraint));
 +                      return class_has_references (mono_class_from_mono_type (gparam->gshared_constraint));
        }
        return FALSE;
  }
  /*
   * mono_class_layout_fields:
   * @class: a class
 + * @base_instance_size: base instance size
 + * @packing_size:
   *
 - * Compute the placement of fields inside an object or struct, according to
 - * the layout rules and set the following fields in @class:
 - *  - has_references (if the class contains instance references firled or structs that contain references)
 - *  - has_static_refs (same, but for static fields)
 - *  - instance_size (size of the object in memory)
 - *  - class_size (size needed for the static fields)
 - *  - size_inited (flag set when the instance_size is set)
 + * This contains the common code for computing the layout of classes and sizes.
 + * This should only be called from mono_class_setup_fields () and
 + * typebuilder_setup_fields ().
   *
 - * LOCKING: this is supposed to be called with the loader lock held.
 + * LOCKING: Acquires the loader lock
   */
  void
 -mono_class_layout_fields (MonoClass *klass)
 +mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_size, gboolean sre)
  {
        int i;
        const int top = klass->field.count;
 -      guint32 layout = klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK;
 +      guint32 layout = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK;
        guint32 pass, passes, real_size;
        gboolean gc_aware_layout = FALSE;
        gboolean has_static_fields = FALSE;
 +      gboolean has_references = FALSE;
 +      gboolean has_static_refs = FALSE;
        MonoClassField *field;
 +      gboolean blittable;
 +      int instance_size = base_instance_size;
 +      int class_size, min_align;
 +      int *field_offsets;
 +
 +      /*
 +       * We want to avoid doing complicated work inside locks, so we compute all the required
 +       * information and write it to @klass inside a lock.
 +       */
 +      if (klass->fields_inited)
 +              return;
 +
 +      if ((packing_size & 0xffffff00) != 0) {
 +              mono_class_set_type_load_failure (klass, "Could not load struct '%s' with packing size %d >= 256", klass->name, packing_size);
 +              return;
 +      }
 +
 +      if (klass->parent) {
 +              min_align = klass->parent->min_align;
 +              /* we use | since it may have been set already */
 +              has_references = klass->has_references | klass->parent->has_references;
 +      } else {
 +              min_align = 1;
 +      }
 +      /* We can't really enable 16 bytes alignment until the GC supports it.
 +      The whole layout/instance size code must be reviewed because we do alignment calculation in terms of the
 +      boxed instance, which leads to unexplainable holes at the beginning of an object embedding a simd type.
 +      Bug #506144 is an example of this issue.
 +
 +       if (klass->simd_type)
 +              min_align = 16;
 +       */
  
        /*
         * When we do generic sharing we need to have layout
         * container), so we don't return in that case anymore.
         */
  
 +      if (klass->enumtype) {
 +              for (i = 0; i < top; i++) {
 +                      field = &klass->fields [i];
 +                      if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
 +                              klass->cast_class = klass->element_class = mono_class_from_mono_type (field->type);
 +                              break;
 +                      }
 +              }
 +
 +              if (!mono_class_enum_basetype (klass)) {
 +                      mono_class_set_type_load_failure (klass, "The enumeration's base type is invalid.");
 +                      return;
 +              }
 +      }
 +
        /*
         * Enable GC aware auto layout: in this mode, reference
         * fields are grouped together inside objects, increasing collector 
                        gc_aware_layout = TRUE;
        }
  
 -      /* Compute klass->has_references */
 -      /* 
 -       * Process non-static fields first, since static fields might recursively
 -       * refer to the class itself.
 -       */
 +      /* Compute klass->blittable */
 +      blittable = TRUE;
 +      if (klass->parent)
 +              blittable = klass->parent->blittable;
 +      if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT && !(mono_is_corlib_image (klass->image) && !strcmp (klass->name_space, "System") && !strcmp (klass->name, "ValueType")) && top)
 +              blittable = FALSE;
        for (i = 0; i < top; i++) {
 -              MonoType *ftype;
 -
                field = &klass->fields [i];
  
 -              if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
 -                      ftype = mono_type_get_underlying_type (field->type);
 -                      ftype = mono_type_get_basic_type_from_generic (ftype);
 -                      if (type_has_references (klass, ftype))
 -                              klass->has_references = TRUE;
 +              if (mono_field_is_deleted (field))
 +                      continue;
 +              if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
 +                      continue;
 +              if (blittable) {
 +                      if (field->type->byref || MONO_TYPE_IS_REFERENCE (field->type)) {
 +                              blittable = FALSE;
 +                      } else {
 +                              MonoClass *field_class = mono_class_from_mono_type (field->type);
 +                              if (field_class) {
 +                                      mono_class_setup_fields (field_class);
 +                                      if (mono_class_has_failure (field_class)) {
 +                                              MonoError field_error;
 +                                              mono_error_init (&field_error);
 +                                              mono_error_set_for_class_failure (&field_error, field_class);
 +                                              mono_class_set_type_load_failure (klass, "Could not set up field '%s' due to: %s", field->name, mono_error_get_message (&field_error));
 +                                              mono_error_cleanup (&field_error);
 +                                              break;
 +                                      }
 +                              }
 +                              if (!field_class || !field_class->blittable)
 +                                      blittable = FALSE;
 +                      }
                }
 +              if (klass->enumtype)
 +                      blittable = klass->element_class->blittable;
        }
 +      if (mono_class_has_failure (klass))
 +              return;
 +      if (klass == mono_defaults.string_class)
 +              blittable = FALSE;
  
 +      /* Compute klass->has_references */
 +      /* 
 +       * Process non-static fields first, since static fields might recursively
 +       * refer to the class itself.
 +       */
        for (i = 0; i < top; i++) {
                MonoType *ftype;
  
                field = &klass->fields [i];
  
 -              if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
 +              if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
                        ftype = mono_type_get_underlying_type (field->type);
                        ftype = mono_type_get_basic_type_from_generic (ftype);
                        if (type_has_references (klass, ftype))
 -                              klass->has_static_refs = TRUE;
 -              }
 -      }
 -
 -      for (i = 0; i < top; i++) {
 -              MonoType *ftype;
 -
 -              field = &klass->fields [i];
 -
 -              ftype = mono_type_get_underlying_type (field->type);
 -              ftype = mono_type_get_basic_type_from_generic (ftype);
 -              if (type_has_references (klass, ftype)) {
 -                      if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
 -                              klass->has_static_refs = TRUE;
 -                      else
 -                              klass->has_references = TRUE;
 +                              has_references = TRUE;
                }
        }
  
        /*
         * Compute field layout and total size (not considering static fields)
         */
 -
 +      field_offsets = g_new0 (int, top);
 +      int first_field_idx = mono_class_has_static_metadata (klass) ? mono_class_get_first_field_idx (klass) : 0;
        switch (layout) {
        case TYPE_ATTRIBUTE_AUTO_LAYOUT:
        case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT:
 -
                if (gc_aware_layout)
                        passes = 2;
                else
  
                if (klass->parent) {
                        mono_class_setup_fields (klass->parent);
 -                      if (klass->parent->exception_type) {
 -                              mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
 +                      if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Cannot initialize parent class"))
                                return;
 -                      }
                        real_size = klass->parent->instance_size;
                } else {
                        real_size = sizeof (MonoObject);
                                        }
                                }
  
 -                              if ((top == 1) && (klass->instance_size == sizeof (MonoObject)) &&
 +                              if ((top == 1) && (instance_size == sizeof (MonoObject)) &&
                                        (strcmp (mono_field_get_name (field), "$PRIVATE$") == 0)) {
                                        /* This field is a hack inserted by MCS to empty structures */
                                        continue;
                                size = mono_type_size (field->type, &align);
                        
                                /* FIXME (LAMESPEC): should we also change the min alignment according to pack? */
 -                              align = klass->packing_size ? MIN (klass->packing_size, align): align;
 +                              align = packing_size ? MIN (packing_size, align): align;
                                /* if the field has managed references, we need to force-align it
                                 * see bug #77788
                                 */
                                if (type_has_references (klass, ftype))
                                        align = MAX (align, sizeof (gpointer));
  
 -                              klass->min_align = MAX (align, klass->min_align);
 -                              field->offset = real_size;
 +                              min_align = MAX (align, min_align);
 +                              field_offsets [i] = real_size;
                                if (align) {
 -                                      field->offset += align - 1;
 -                                      field->offset &= ~(align - 1);
 +                                      field_offsets [i] += align - 1;
 +                                      field_offsets [i] &= ~(align - 1);
                                }
                                /*TypeBuilders produce all sort of weird things*/
 -                              g_assert (image_is_dynamic (klass->image) || field->offset > 0);
 -                              real_size = field->offset + size;
 +                              g_assert (image_is_dynamic (klass->image) || field_offsets [i] > 0);
 +                              real_size = field_offsets [i] + size;
                        }
  
 -                      klass->instance_size = MAX (real_size, klass->instance_size);
 +                      instance_size = MAX (real_size, instance_size);
         
 -                      if (klass->instance_size & (klass->min_align - 1)) {
 -                              klass->instance_size += klass->min_align - 1;
 -                              klass->instance_size &= ~(klass->min_align - 1);
 +                      if (instance_size & (min_align - 1)) {
 +                              instance_size += min_align - 1;
 +                              instance_size &= ~(min_align - 1);
                        }
                }
                break;
                                continue;
  
                        size = mono_type_size (field->type, &align);
 -                      align = klass->packing_size ? MIN (klass->packing_size, align): align;
 -                      klass->min_align = MAX (align, klass->min_align);
 +                      align = packing_size ? MIN (packing_size, align): align;
 +                      min_align = MAX (align, min_align);
  
 -                      /*
 -                       * When we get here, field->offset is already set by the
 -                       * loader (for either runtime fields or fields loaded from metadata).
 -                       * The offset is from the start of the object: this works for both
 -                       * classes and valuetypes.
 -                       */
 -                      field->offset += sizeof (MonoObject);
 +                      if (sre) {
 +                              /* Already set by typebuilder_setup_fields () */
 +                              field_offsets [i] = field->offset + sizeof (MonoObject);
 +                      } else {
 +                              int idx = first_field_idx + i;
 +                              guint32 offset;
 +                              mono_metadata_field_info (klass->image, idx, &offset, NULL, NULL);
 +                              field_offsets [i] = offset + sizeof (MonoObject);
 +                      }
                        ftype = mono_type_get_underlying_type (field->type);
                        ftype = mono_type_get_basic_type_from_generic (ftype);
                        if (type_has_references (klass, ftype)) {
 -                              if (field->offset % sizeof (gpointer)) {
 -                                      mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
 +                              if (field_offsets [i] % sizeof (gpointer)) {
 +                                      mono_class_set_type_load_failure (klass, "Reference typed field '%s' has explicit offset that is not pointer-size aligned.", field->name);
                                }
                        }
  
                        /*
                         * Calc max size.
                         */
 -                      real_size = MAX (real_size, size + field->offset);
 +                      real_size = MAX (real_size, size + field_offsets [i]);
                }
  
                if (klass->has_references) {
                                        continue;
                                ftype = mono_type_get_underlying_type (field->type);
                                if (MONO_TYPE_IS_REFERENCE (ftype))
 -                                      ref_bitmap [field->offset / sizeof (gpointer)] = 1;
 +                                      ref_bitmap [field_offsets [i] / sizeof (gpointer)] = 1;
                        }
                        for (i = 0; i < top; i++) {
                                field = &klass->fields [i];
  
                                // 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.", klass->name, field->offset);
 -                                      mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, err_msg);
 +                              if (!MONO_TYPE_IS_REFERENCE (field->type) && ref_bitmap [field_offsets [i] / sizeof (gpointer)]) {
 +                                      mono_class_set_type_load_failure (klass, "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.", klass->name, field_offsets [i]);
                                }
  #endif
                        }
                        g_free (ref_bitmap);
                }
  
 -              klass->instance_size = MAX (real_size, klass->instance_size);
 -              if (klass->instance_size & (klass->min_align - 1)) {
 -                      klass->instance_size += klass->min_align - 1;
 -                      klass->instance_size &= ~(klass->min_align - 1);
 +              instance_size = MAX (real_size, instance_size);
 +              if (instance_size & (min_align - 1)) {
 +                      instance_size += min_align - 1;
 +                      instance_size &= ~(min_align - 1);
                }
                break;
        }
                 * performance, and since the JIT memset/memcpy code assumes this and generates 
                 * unaligned accesses otherwise. See #78990 for a testcase.
                 */
 -              if (mono_align_small_structs) {
 -                      if (klass->instance_size <= sizeof (MonoObject) + sizeof (gpointer))
 -                              klass->min_align = MAX (klass->min_align, klass->instance_size - sizeof (MonoObject));
 +              if (mono_align_small_structs && top) {
 +                      if (instance_size <= sizeof (MonoObject) + sizeof (gpointer))
 +                              min_align = MAX (min_align, instance_size - sizeof (MonoObject));
                }
        }
  
 +      if (klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR)
 +              instance_size = sizeof (MonoObject) + mono_type_stack_size_internal (&klass->byval_arg, NULL, TRUE);
 +      else if (klass->byval_arg.type == MONO_TYPE_PTR)
 +              instance_size = sizeof (MonoObject) + sizeof (gpointer);
 +
 +      /* Publish the data */
 +      mono_loader_lock ();
 +      if (klass->instance_size && !klass->image->dynamic) {
 +              /* Might be already set using cached info */
 +              g_assert (klass->instance_size == instance_size);
 +      } else {
 +              klass->instance_size = instance_size;
 +      }
 +      klass->blittable = blittable;
 +      klass->has_references = has_references;
 +      klass->packing_size = packing_size;
 +      klass->min_align = min_align;
 +      for (i = 0; i < top; ++i) {
 +              field = &klass->fields [i];
 +              if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
 +                      klass->fields [i].offset = field_offsets [i];
 +      }
 +
        mono_memory_barrier ();
        klass->size_inited = 1;
 +      mono_loader_unlock ();
  
        /*
         * Compute static field layout and size
 +       * Static fields can reference the class itself, so this has to be
 +       * done after instance_size etc. are initialized.
         */
 -      for (i = 0; i < top; i++){
 +      class_size = 0;
 +      for (i = 0; i < top; i++) {
                gint32 align;
                guint32 size;
  
                        continue;
  
                if (mono_type_has_exceptions (field->type)) {
 -                      mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
 +                      mono_class_set_type_load_failure (klass, "Field '%s' has an invalid type.", field->name);
                        break;
                }
  
                has_static_fields = TRUE;
  
                size = mono_type_size (field->type, &align);
 -              field->offset = klass->sizes.class_size;
 +              field_offsets [i] = class_size;
                /*align is always non-zero here*/
 -              field->offset += align - 1;
 -              field->offset &= ~(align - 1);
 -              klass->sizes.class_size = field->offset + size;
 +              field_offsets [i] += align - 1;
 +              field_offsets [i] &= ~(align - 1);
 +              class_size = field_offsets [i] + size;
        }
  
 -      if (has_static_fields && klass->sizes.class_size == 0)
 +      if (has_static_fields && class_size == 0)
                /* Simplify code which depends on class_size != 0 if the class has static fields */
 -              klass->sizes.class_size = 8;
 +              class_size = 8;
 +
 +      /* Compute klass->has_static_refs */
 +      has_static_refs = FALSE;
 +      for (i = 0; i < top; i++) {
 +              MonoType *ftype;
 +
 +              field = &klass->fields [i];
 +
 +              if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
 +                      ftype = mono_type_get_underlying_type (field->type);
 +                      ftype = mono_type_get_basic_type_from_generic (ftype);
 +                      if (type_has_references (klass, ftype))
 +                              has_static_refs = TRUE;
 +              }
 +      }
 +
 +      /*valuetypes can't be neither bigger than 1Mb or empty. */
 +      if (klass->valuetype && (klass->instance_size <= 0 || klass->instance_size > (0x100000 + sizeof (MonoObject))))
 +              mono_class_set_type_load_failure (klass, "Value type instance size (%d) cannot be zero, negative, or bigger than 1Mb", klass->instance_size);
 +
 +      /* Publish the data */
 +      mono_loader_lock ();
 +      if (!klass->rank)
 +              klass->sizes.class_size = class_size;
 +      klass->has_static_refs = has_static_refs;
 +      for (i = 0; i < top; ++i) {
 +              field = &klass->fields [i];
 +
 +              if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
 +                      field->offset = field_offsets [i];
 +      }
 +
 +      mono_memory_barrier ();
 +      klass->fields_inited = 1;
 +      mono_loader_unlock ();
 +
 +      g_free (field_offsets);
  }
  
  static MonoMethod*
@@@ -2212,7 -2166,7 +2212,7 @@@ create_array_method (MonoClass *klass, 
   * Methods belonging to an interface are assigned a sequential slot starting
   * from 0.
   *
 - * On failure this function sets klass->exception_type
 + * On failure this function sets klass->has_failure and stores a MonoErrorBoxed with details
   */
  void
  mono_class_setup_methods (MonoClass *klass)
        if (klass->methods)
                return;
  
 -      if (klass->generic_class) {
 +      if (mono_class_is_ginst (klass)) {
                MonoError error;
 -              MonoClass *gklass = klass->generic_class->container_class;
 +              MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
  
                mono_class_init (gklass);
 -              if (!gklass->exception_type)
 +              if (!mono_class_has_failure (gklass))
                        mono_class_setup_methods (gklass);
 -              if (gklass->exception_type) {
 -                      /* FIXME make exception_data less opaque so it's possible to dup it here */
 -                      mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Generic type definition failed to load"));
 +              if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load"))
                        return;
 -              }
  
                /* The + 1 makes this always non-NULL to pass the check in mono_class_setup_methods () */
                count = gklass->method.count;
                                gklass->methods [i], klass, mono_class_get_context (klass), &error);
                        if (!mono_error_ok (&error)) {
                                char *method = mono_method_full_name (gklass->methods [i], TRUE);
 -                              mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Could not inflate method %s due to %s", method, mono_error_get_message (&error)));
 +                              mono_class_set_type_load_failure (klass, "Could not inflate method %s due to %s", method, mono_error_get_message (&error));
  
                                g_free (method);
                                mono_error_cleanup (&error);
  
                for (i = 0; i < klass->interface_count; i++)
                        setup_generic_array_ifaces (klass, klass->interfaces [i], methods, first_generic + i * count_generic);
 -      } else {
 +      } else if (mono_class_has_static_metadata (klass)) {
                MonoError error;
 +              int first_idx = mono_class_get_first_method_idx (klass);
  
                count = klass->method.count;
                methods = (MonoMethod **)mono_class_alloc (klass, sizeof (MonoMethod*) * count);
                for (i = 0; i < count; ++i) {
 -                      int idx = mono_metadata_translate_token_index (klass->image, MONO_TABLE_METHOD, klass->method.first + i + 1);
 +                      int idx = mono_metadata_translate_token_index (klass->image, MONO_TABLE_METHOD, first_idx + i + 1);
                        methods [i] = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | idx, klass, NULL, &error);
                        if (!methods [i]) {
 -                              mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Could not load method %d due to %s", i, mono_error_get_message (&error)));
 +                              mono_class_set_type_load_failure (klass, "Could not load method %d due to %s", i, mono_error_get_message (&error));
                                mono_error_cleanup (&error);
                        }
                }
 +      } else {
 +              methods = (MonoMethod **)mono_class_alloc (klass, sizeof (MonoMethod*) * 1);
 +              count = 0;
        }
  
        if (MONO_CLASS_IS_INTERFACE (klass)) {
@@@ -2392,14 -2345,13 +2392,14 @@@ MonoMethod
  mono_class_get_method_by_index (MonoClass *klass, int index)
  {
        MonoError error;
 +
 +      MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
        /* Avoid calling setup_methods () if possible */
 -      if (klass->generic_class && !klass->methods) {
 -              MonoClass *gklass = klass->generic_class->container_class;
 +      if (gklass && !klass->methods) {
                MonoMethod *m;
  
                m = mono_class_inflate_generic_method_full_checked (
 -                              gklass->methods [index], klass, mono_class_get_context (klass), &error);
 +                              gklass->container_class->methods [index], klass, mono_class_get_context (klass), &error);
                g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
                /*
                 * If setup_methods () is called later for this class, no duplicates are created,
                return m;
        } else {
                mono_class_setup_methods (klass);
 -              if (klass->exception_type) /*FIXME do proper error handling*/
 +              if (mono_class_has_failure (klass)) /*FIXME do proper error handling*/
                        return NULL;
                g_assert (index >= 0 && index < klass->method.count);
                return klass->methods [index];
  MonoMethod*
  mono_class_get_inflated_method (MonoClass *klass, MonoMethod *method)
  {
 -      MonoClass *gklass = klass->generic_class->container_class;
 +      MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
        int i;
  
        g_assert (method->klass == gklass);
  
        mono_class_setup_methods (gklass);
 -      g_assert (!gklass->exception_type); /*FIXME do proper error handling*/
 +      g_assert (!mono_class_has_failure (gklass)); /*FIXME do proper error handling*/
  
        for (i = 0; i < gklass->method.count; ++i) {
                if (gklass->methods [i] == method) {
@@@ -2474,9 -2426,9 +2474,9 @@@ mono_class_get_vtable_entry (MonoClass 
                        return klass->parent->vtable [offset];
        }
  
 -      if (klass->generic_class) {
 +      if (mono_class_is_ginst (klass)) {
                MonoError error;
 -              MonoClass *gklass = klass->generic_class->container_class;
 +              MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
                mono_class_setup_vtable (gklass);
                m = gklass->vtable [offset];
  
                g_assert (mono_error_ok (&error)); /* FIXME don't swallow this error */
        } else {
                mono_class_setup_vtable (klass);
 -              if (klass->exception_type)
 +              if (mono_class_has_failure (klass))
                        return NULL;
                m = klass->vtable [offset];
        }
@@@ -2525,13 -2477,15 +2525,13 @@@ mono_class_setup_properties (MonoClass 
        if (klass->ext && klass->ext->properties)
                return;
  
 -      if (klass->generic_class) {
 -              MonoClass *gklass = klass->generic_class->container_class;
 +      if (mono_class_is_ginst (klass)) {
 +              MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
  
                mono_class_init (gklass);
                mono_class_setup_properties (gklass);
 -              if (gklass->exception_type) {
 -                      mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Generic type definition failed to load"));
 +              if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load"))
                        return;
 -              }
  
                properties = mono_class_new0 (klass, MonoProperty, gklass->ext->property.count + 1);
  
  
                if (count) {
                        mono_class_setup_methods (klass);
 -                      if (klass->exception_type)
 +                      if (mono_class_has_failure (klass))
                                return;
                }
  
                        properties [i - first].name = mono_metadata_string_heap (klass->image, cols [MONO_PROPERTY_NAME]);
  
                        startm = mono_metadata_methods_from_property (klass->image, i, &endm);
 +                      int first_idx = mono_class_get_first_method_idx (klass);
                        for (j = startm; j < endm; ++j) {
                                MonoMethod *method;
  
                                        method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | cols [MONO_METHOD_SEMA_METHOD], klass, NULL, &error);
                                        mono_error_cleanup (&error); /* FIXME don't swallow this error */
                                } else {
 -                                      method = klass->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - klass->method.first];
 +                                      method = klass->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - first_idx];
                                }
  
                                switch (cols [MONO_METHOD_SEMA_SEMANTICS]) {
@@@ -2657,13 -2610,15 +2657,13 @@@ mono_class_setup_events (MonoClass *kla
        if (klass->ext && klass->ext->events)
                return;
  
 -      if (klass->generic_class) {
 -              MonoClass *gklass = klass->generic_class->container_class;
 +      if (mono_class_is_ginst (klass)) {
 +              MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
                MonoGenericContext *context = NULL;
  
                mono_class_setup_events (gklass);
 -              if (gklass->exception_type) {
 -                      mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Generic type definition failed to load"));
 +              if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load"))
                        return;
 -              }
  
                first = gklass->ext->event.first;
                count = gklass->ext->event.count;
  
                if (count) {
                        mono_class_setup_methods (klass);
 -                      if (klass->exception_type) {
 -                              mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Generic type definition failed to load"));
 +                      if (mono_class_has_failure (klass)) {
                                return;
                        }
                }
                        event->name = mono_metadata_string_heap (klass->image, cols [MONO_EVENT_NAME]);
  
                        startm = mono_metadata_methods_from_event (klass->image, i, &endm);
 +                      int first_idx = mono_class_get_first_method_idx (klass);
                        for (j = startm; j < endm; ++j) {
                                MonoMethod *method;
  
                                        method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | cols [MONO_METHOD_SEMA_METHOD], klass, NULL, &error);
                                        mono_error_cleanup (&error); /* FIXME don't swallow this error */
                                } else {
 -                                      method = klass->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - klass->method.first];
 +                                      method = klass->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - first_idx];
                                }
  
                                switch (cols [MONO_METHOD_SEMA_SEMANTICS]) {
@@@ -2817,16 -2772,16 +2817,16 @@@ mono_unload_interface_id (MonoClass *kl
        }
  }
  
 -/*
 +/**
   * mono_get_unique_iid:
   * @class: interface
   *
   * Assign a unique integer ID to the interface represented by @class.
   * The ID will positive and as small as possible.
   * LOCKING: Acquires the classes lock.
 - * Returns: the new ID.
 + * Returns: The new ID.
   */
- static guint
+ static guint32
  mono_get_unique_iid (MonoClass *klass)
  {
        int iid;
        }
        mono_bitset_set (global_interface_bitset, iid);
        /* set the bit also in the per-image set */
 -      if (!klass->generic_class) {
 +      if (!mono_class_is_ginst (klass)) {
                if (klass->image->interface_bitset) {
                        if (iid >= mono_bitset_size (klass->image->interface_bitset)) {
                                MonoBitSet *new_set = mono_bitset_clone (klass->image->interface_bitset, iid + 1);
        if (mono_print_vtable) {
                int generic_id;
                char *type_name = mono_type_full_name (&klass->byval_arg);
 -              if (klass->generic_class && !klass->generic_class->context.class_inst->is_open) {
 -                      generic_id = klass->generic_class->context.class_inst->id;
 +              MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
 +              if (gklass && !gklass->context.class_inst->is_open) {
 +                      generic_id = gklass->context.class_inst->id;
                        g_assert (generic_id != 0);
                } else {
                        generic_id = 0;
        }
  #endif
  
-       g_assert (iid <= 65535);
+       /* I've confirmed iids safe past 16 bits, however bitset code uses a signed int while testing.
+        * Once this changes, it should be safe for us to allow 2^32-1 interfaces, until then 2^31-2 is the max. */
+       g_assert (iid < INT_MAX);
        return iid;
  }
  
@@@ -2891,7 -2847,8 +2893,7 @@@ collect_implemented_interfaces_aux (Mon
        MonoClass *ic;
  
        mono_class_setup_interfaces (klass, error);
 -      if (!mono_error_ok (error))
 -              return;
 +      return_if_nok (error);
  
        for (i = 0; i < klass->interface_count; i++) {
                ic = klass->interfaces [i];
                        *res = g_ptr_array_new ();
                g_ptr_array_add (*res, ic);
                mono_class_init (ic);
 -              if (ic->exception_type) {
 +              if (mono_class_has_failure (ic)) {
                        mono_error_set_type_load_class (error, ic, "Error Loading class");
                        return;
                }
  
                collect_implemented_interfaces_aux (ic, res, error);
 -              if (!mono_error_ok (error))
 -                      return;
 +              return_if_nok (error);
        }
  }
  
@@@ -2948,7 -2906,7 +2950,7 @@@ mono_class_interface_offset (MonoClass 
        }
  }
  
 -/*
 +/**
   * mono_class_interface_offset_with_variance:
   * 
   * Return the interface offset of @itf in @klass. Sets @non_exact_match to TRUE if the match required variance check
@@@ -3083,12 -3041,6 +3085,12 @@@ fill_valuetype_array_derived_types (Mon
                valuetype_types [1] = mono_class_from_mono_type (mono_class_enum_basetype (eclass));
  }
  
 +static GENERATE_GET_CLASS_WITH_CACHE (generic_icollection, System.Collections.Generic, ICollection`1)
 +static GENERATE_GET_CLASS_WITH_CACHE (generic_ienumerable, System.Collections.Generic, IEnumerable`1)
 +static GENERATE_GET_CLASS_WITH_CACHE (generic_ienumerator, System.Collections.Generic, IEnumerator`1)
 +static GENERATE_GET_CLASS_WITH_CACHE (generic_ireadonlylist, System.Collections.Generic, IReadOnlyList`1)
 +static GENERATE_GET_CLASS_WITH_CACHE (generic_ireadonlycollection, System.Collections.Generic, IReadOnlyCollection`1)
 +
  /* this won't be needed once bug #325495 is completely fixed
   * though we'll need something similar to know which interfaces to allow
   * in arrays when they'll be lazyly created
@@@ -3106,11 -3058,11 +3108,11 @@@ static MonoClass*
  get_implicit_generic_array_interfaces (MonoClass *klass, int *num, int *is_enumerator)
  {
        MonoClass *eclass = klass->element_class;
 -      static MonoClass* generic_icollection_class = NULL;
 -      static MonoClass* generic_ienumerable_class = NULL;
 -      static MonoClass* generic_ienumerator_class = NULL;
 -      static MonoClass* generic_ireadonlylist_class = NULL;
 -      static MonoClass* generic_ireadonlycollection_class = NULL;
 +      MonoClass* generic_icollection_class;
 +      MonoClass* generic_ienumerable_class;
 +      MonoClass* generic_ienumerator_class;
 +      MonoClass* generic_ireadonlylist_class;
 +      MonoClass* generic_ireadonlycollection_class;
        MonoClass *valuetype_types[2] = { NULL, NULL };
        MonoClass **interfaces = NULL;
        int i, nifaces, interface_count, real_count, original_rank;
        eclass_is_valuetype = FALSE;
        original_rank = eclass->rank;
        if (klass->byval_arg.type != MONO_TYPE_SZARRAY) {
 -              if (klass->generic_class && klass->nested_in == mono_defaults.array_class && strcmp (klass->name, "InternalEnumerator`1") == 0)  {
 +              MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
 +              if (gklass && klass->nested_in == mono_defaults.array_class && strcmp (klass->name, "InternalEnumerator`1") == 0)        {
                        /*
                         * For a Enumerator<T[]> we need to get the list of interfaces for T.
                         */
 -                      eclass = mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [0]);
 +                      eclass = mono_class_from_mono_type (gklass->context.class_inst->type_argv [0]);
                        original_rank = eclass->rank;
                        if (!eclass->rank)
                                eclass = eclass->element_class;
         */
        all_interfaces = eclass->rank && eclass->element_class->rank? FALSE: TRUE;
  
 -      if (!generic_icollection_class) {
 -              generic_icollection_class = mono_class_from_name (mono_defaults.corlib,
 -                      "System.Collections.Generic", "ICollection`1");
 -              generic_ienumerable_class = mono_class_from_name (mono_defaults.corlib,
 -                      "System.Collections.Generic", "IEnumerable`1");
 -              generic_ienumerator_class = mono_class_from_name (mono_defaults.corlib,
 -                      "System.Collections.Generic", "IEnumerator`1");
 -              generic_ireadonlylist_class = mono_class_from_name (mono_defaults.corlib,
 -                      "System.Collections.Generic", "IReadOnlyList`1");
 -              generic_ireadonlycollection_class = mono_class_from_name (mono_defaults.corlib,
 -                      "System.Collections.Generic", "IReadOnlyCollection`1");
 -      }
 +      generic_icollection_class = mono_class_get_generic_icollection_class ();
 +      generic_ienumerable_class = mono_class_get_generic_ienumerable_class ();
 +      generic_ienumerator_class = mono_class_get_generic_ienumerator_class ();
 +      generic_ireadonlylist_class = mono_class_get_generic_ireadonlylist_class ();
 +      generic_ireadonlycollection_class = mono_class_get_generic_ireadonlycollection_class ();
  
        mono_class_init (eclass);
  
@@@ -3335,7 -3293,7 +3337,7 @@@ count_virtual_methods (MonoClass *klass
  
        if (klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass)) {
                mono_class_setup_methods (klass);
 -              if (klass->exception_type)
 +              if (mono_class_has_failure (klass))
                        return -1;
  
                for (i = 0; i < klass->method.count; ++i) {
                                ++count;
                }
        } else {
 +              int first_idx = mono_class_get_first_method_idx (klass);
                for (i = 0; i < klass->method.count; ++i) {
 -                      flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, klass->method.first + i, MONO_METHOD_FLAGS);
 +                      flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, first_idx + i, MONO_METHOD_FLAGS);
  
                        if (flags & METHOD_ATTRIBUTE_VIRTUAL)
                                ++count;
@@@ -3458,7 -3415,7 +3460,7 @@@ set_interface_and_offset (int num_iface
   * the size of the buffer.
   * This compression algorithm assumes the bits set in the bitmap are
   * few and far between, like in interface bitmaps.
 - * Returns: the size of the compressed bitmap in bytes.
 + * Returns: The size of the compressed bitmap in bytes.
   */
  int
  mono_compress_bitmap (uint8_t *dest, const uint8_t *bitmap, int size)
   * be already checked for being smaller than the maximum id encoded in the
   * bitmap.
   *
 - * Returns: a non-zero value if bit @id is set in the bitmap @bitmap,
 + * Returns: A non-zero value if bit @id is set in the bitmap @bitmap,
   * #FALSE otherwise.
   */
  int
@@@ -3520,15 -3477,16 +3522,16 @@@ mono_class_interface_match (const uint8
  #endif
  
  /*
 - * LOCKING: this is supposed to be called with the loader lock held.
 - * Return -1 on failure and set exception_type
 + * Return -1 on failure and set klass->has_failure and store a MonoErrorBoxed with the details.
 + * LOCKING: Acquires the loader lock.
   */
  static int
  setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite)
  {
        MonoError error;
        MonoClass *k, *ic;
-       int i, j, max_iid, num_ifaces;
+       int i, j, num_ifaces;
+       guint32 max_iid;
        MonoClass **interfaces_full = NULL;
        int *interface_offsets_full = NULL;
        GPtrArray *ifaces;
                for (i = 0; i < k->interface_count; i++) {
                        ic = k->interfaces [i];
  
 -                      if (!ic->inited)
 -                              mono_class_init (ic);
 +                      mono_class_init (ic);
  
                        if (max_iid < ic->interface_id)
                                max_iid = ic->interface_id;
                ifaces = mono_class_get_implemented_interfaces (k, &error);
                if (!mono_error_ok (&error)) {
                        char *name = mono_type_get_full_name (k);
 -                      mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Error getting the interfaces of %s due to %s", name, mono_error_get_message (&error)));
 +                      mono_class_set_type_load_failure (klass, "Error getting the interfaces of %s due to %s", name, mono_error_get_message (&error));
                        g_free (name);
                        mono_error_cleanup (&error);
                        cur_slot = -1;
                if (max_iid < klass->interface_id)
                        max_iid = klass->interface_id;
        }
 -      klass->max_interface_id = max_iid;
 +
        /* compute vtable offset for interfaces */
        interfaces_full = (MonoClass **)g_malloc0 (sizeof (MonoClass*) * num_ifaces);
        interface_offsets_full = (int *)g_malloc (sizeof (int) * num_ifaces);
  
 -      for (i = 0; i < num_ifaces; i++) {
 +      for (i = 0; i < num_ifaces; i++)
                interface_offsets_full [i] = -1;
 -      }
  
        /* skip the current class */
        for (j = 0; j < klass->idepth - 1; j++) {
                        count = count_virtual_methods (ic);
                        if (count == -1) {
                                char *name = mono_type_get_full_name (ic);
 -                              mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Error calculating interface offset of %s", name));
 +                              mono_class_set_type_load_failure (klass, "Error calculating interface offset of %s", name);
                                g_free (name);
                                cur_slot = -1;
                                goto end;
                        for (i = 0; i < num_array_interfaces; ++i) {
                                int offset;
                                ic = array_interfaces [i];
 -                              if (ic->generic_class->container_class == mono_defaults.generic_ilist_class)
 +                              if (mono_class_get_generic_class (ic)->container_class == mono_defaults.generic_ilist_class)
                                        offset = ilist_offset;
                                else if (strcmp (ic->name, "ICollection`1") == 0)
                                        offset = icollection_offset;
        }
  
        for (interface_offsets_count = 0, i = 0; i < num_ifaces; i++) {
 -              if (interface_offsets_full [i] != -1) {
 +              if (interface_offsets_full [i] != -1)
                        interface_offsets_count ++;
 -              }
        }
  
 +      /* Publish the data */
 +      mono_loader_lock ();
 +
 +      klass->max_interface_id = max_iid;
        /*
         * We might get called multiple times:
         * - mono_class_init ()
                bitmap = (uint8_t *)mono_class_alloc0 (klass, bsize);
  #endif
                for (i = 0; i < interface_offsets_count; i++) {
-                       int id = interfaces_full [i]->interface_id;
+                       guint32 id = interfaces_full [i]->interface_id;
                        bitmap [id >> 3] |= (1 << (id & 7));
                        klass->interfaces_packed [i] = interfaces_full [i];
                        klass->interface_offsets_packed [i] = interface_offsets_full [i];
                klass->interface_bitmap = bitmap;
  #endif
        }
 +      mono_loader_unlock ();
  
  end:
        g_free (interfaces_full);
        
        //printf ("JUST DONE: ");
        //print_implemented_interfaces (klass);
 - 
 +
        return cur_slot;
  }
  
  void
  mono_class_setup_interface_offsets (MonoClass *klass)
  {
 -      mono_loader_lock ();
 -
        setup_interface_offsets (klass, 0, FALSE);
 -
 -      mono_loader_unlock ();
  }
  
  /*Checks if @klass has @parent as one of it's parents type gtd
@@@ -3800,17 -3760,18 +3803,17 @@@ mono_class_check_vtable_constraints (Mo
  {
        MonoGenericInst *ginst;
        int i;
 -      if (!klass->generic_class) {
 +
 +      if (!mono_class_is_ginst (klass)) {
                mono_class_setup_vtable_full (klass, in_setup);
 -              return klass->exception_type == 0;
 +              return !mono_class_has_failure (klass);
        }
  
        mono_class_setup_vtable_full (mono_class_get_generic_type_definition (klass), in_setup);
 -      if (klass->generic_class->container_class->exception_type) {
 -              mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Failed to load generic definition vtable"));
 +      if (mono_class_set_type_load_failure_causedby_class (klass, mono_class_get_generic_class (klass)->container_class, "Failed to load generic definition vtable"))
                return FALSE;
 -      }
  
 -      ginst = klass->generic_class->context.class_inst;
 +      ginst = mono_class_get_generic_class (klass)->context.class_inst;
        for (i = 0; i < ginst->type_argc; ++i) {
                MonoClass *arg;
                if (ginst->type_argv [i]->type != MONO_TYPE_GENERICINST)
                if (mono_class_has_gtd_parent (klass, arg) || mono_class_has_gtd_parent (arg, klass))
                        continue;
                if (!mono_class_check_vtable_constraints (arg, in_setup)) {
 -                      mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Failed to load generic parameter %d", i));
 +                      mono_class_set_type_load_failure (klass, "Failed to load generic parameter %d", i);
                        return FALSE;
                }
        }
   * - vtable
   * - vtable_size
   * Plus all the fields initialized by setup_interface_offsets ().
 - * If there is an error during vtable construction, klass->exception_type is set.
 + * If there is an error during vtable construction, klass->has_failure
 + * is set and details are stored in a MonoErrorBoxed.
   *
   * LOCKING: Acquires the loader lock.
   */
@@@ -3849,7 -3809,6 +3852,7 @@@ mono_class_setup_vtable (MonoClass *kla
  static void
  mono_class_setup_vtable_full (MonoClass *klass, GList *in_setup)
  {
 +      MonoError error;
        MonoMethod **overrides;
        MonoGenericContext *context;
        guint32 type_token;
                return;
        }
  
 -      if (klass->exception_type)
 +      if (mono_class_has_failure (klass))
                return;
  
        if (g_list_find (in_setup, klass))
        mono_stats.generic_vtable_count ++;
        in_setup = g_list_prepend (in_setup, klass);
  
 -      if (klass->generic_class) {
 +      if (mono_class_is_ginst (klass)) {
                if (!mono_class_check_vtable_constraints (klass, in_setup)) {
                        mono_loader_unlock ();
                        g_list_remove (in_setup, klass);
                }
  
                context = mono_class_get_context (klass);
 -              type_token = klass->generic_class->container_class->type_token;
 +              type_token = mono_class_get_generic_class (klass)->container_class->type_token;
        } else {
 -              context = (MonoGenericContext *) klass->generic_container;
 +              context = (MonoGenericContext *) mono_class_try_get_generic_container (klass); //FIXME is this a case of a try?
                type_token = klass->type_token;
        }
  
                 * This is true since we don't do layout all over again for them, we simply inflate
                 * the layout of the parent.
                 */
 -              mono_reflection_get_dynamic_overrides (klass, &overrides, &onum);
 +              mono_reflection_get_dynamic_overrides (klass, &overrides, &onum, &error);
 +              if (!is_ok (&error)) {
 +                      mono_loader_unlock ();
 +                      g_list_remove (in_setup, klass);
 +                      mono_class_set_type_load_failure (klass, "Could not load list of method overrides due to %s", mono_error_get_message (&error));
 +                      mono_error_cleanup (&error);
 +                      return;
 +              }
        } else {
                /* The following call fails if there are missing methods in the type */
                /* FIXME it's probably a good idea to avoid this for generic instances. */
        if (ok)
                mono_class_setup_vtable_general (klass, overrides, onum, in_setup);
        else
 -              mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Could not load list of method overrides"));
 +              mono_class_set_type_load_failure (klass, "Could not load list of method overrides");
                
        g_free (overrides);
  
@@@ -4033,7 -3985,7 +4036,7 @@@ check_interface_method_override (MonoCl
                cmsig = mono_method_signature (cm);
                imsig = mono_method_signature (im);
                if (!cmsig || !imsig) {
 -                      mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Could not resolve the signature of a virtual method"));
 +                      mono_class_set_type_load_failure (klass, "Could not resolve the signature of a virtual method");
                        return FALSE;
                }
  
                if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, im, NULL)) {
                        char *body_name = mono_method_full_name (cm, TRUE);
                        char *decl_name = mono_method_full_name (im, TRUE);
 -                      mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Method %s overrides method '%s' which is not accessible", body_name, decl_name));
 +                      mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
                        g_free (body_name);
                        g_free (decl_name);
                        return FALSE;
                cmsig = mono_method_signature (cm);
                imsig = mono_method_signature (im);
                if (!cmsig || !imsig) {
 -                      mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Could not resolve the signature of a virtual method"));
 +                      mono_class_set_type_load_failure (klass, "Could not resolve the signature of a virtual method");
                        return FALSE;
                }
  
                if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, im, NULL)) {
                        char *body_name = mono_method_full_name (cm, TRUE);
                        char *decl_name = mono_method_full_name (im, TRUE);
 -                      mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Method %s overrides method '%s' which is not accessible", body_name, decl_name));
 +                      mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
                        g_free (body_name);
                        g_free (decl_name);
                        return FALSE;
@@@ -4266,7 -4218,7 +4269,7 @@@ print_unimplemented_interface_method_in
        g_free (method_signature);
        g_free (type_name);
        mono_class_setup_methods (klass);
 -      if (klass->exception_type) {
 +      if (mono_class_has_failure (klass)) {
                char *name = mono_type_get_full_name (klass);
                mono_trace_warning (MONO_TRACE_TYPE, "CLASS %s failed to resolve methods\n", name);
                g_free (name);
@@@ -4299,28 -4251,28 +4302,28 @@@ verify_class_overrides (MonoClass *klas
                MonoMethod *body = overrides [i * 2 + 1];
  
                if (mono_class_get_generic_type_definition (body->klass) != mono_class_get_generic_type_definition (klass)) {
 -                      mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Method belongs to a different class than the declared one"));
 +                      mono_class_set_type_load_failure (klass, "Method belongs to a different class than the declared one");
                        return FALSE;
                }
  
                if (!(body->flags & METHOD_ATTRIBUTE_VIRTUAL) || (body->flags & METHOD_ATTRIBUTE_STATIC)) {
                        if (body->flags & METHOD_ATTRIBUTE_STATIC)
 -                              mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Method must not be static to override a base type"));
 +                              mono_class_set_type_load_failure (klass, "Method must not be static to override a base type");
                        else
 -                              mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Method must be virtual to override a base type"));
 +                              mono_class_set_type_load_failure (klass, "Method must be virtual to override a base type");
                        return FALSE;
                }
  
                if (!(decl->flags & METHOD_ATTRIBUTE_VIRTUAL) || (decl->flags & METHOD_ATTRIBUTE_STATIC)) {
                        if (body->flags & METHOD_ATTRIBUTE_STATIC)
 -                              mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Cannot override a static method in a base type"));
 +                              mono_class_set_type_load_failure (klass, "Cannot override a static method in a base type");
                        else
 -                              mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Cannot override a non virtual method in a base type"));
 +                              mono_class_set_type_load_failure (klass, "Cannot override a non virtual method in a base type");
                        return FALSE;
                }
  
                if (!mono_class_is_assignable_from_slow (decl->klass, klass)) {
 -                      mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Method overrides a class or interface that is not extended or implemented by this type"));
 +                      mono_class_set_type_load_failure (klass, "Method overrides a class or interface that is not extended or implemented by this type");
                        return FALSE;
                }
  
                if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (body, decl, NULL)) {
                        char *body_name = mono_method_full_name (body, TRUE);
                        char *decl_name = mono_method_full_name (decl, TRUE);
 -                      mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Method %s overrides method '%s' which is not accessible", body_name, decl_name));
 +                      mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
                        g_free (body_name);
                        g_free (decl_name);
                        return FALSE;
@@@ -4354,7 -4306,8 +4357,8 @@@ mono_class_setup_vtable_general (MonoCl
        MonoError error;
        MonoClass *k, *ic;
        MonoMethod **vtable;
-       int i, max_vtsize = 0, max_iid, cur_slot = 0;
+       int i, max_vtsize = 0, cur_slot = 0;
+       guint32 max_iid;
        GPtrArray *ifaces = NULL;
        GHashTable *override_map = NULL;
        MonoMethod *cm;
        ifaces = mono_class_get_implemented_interfaces (klass, &error);
        if (!mono_error_ok (&error)) {
                char *name = mono_type_get_full_name (klass);
 -              mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Could not resolve %s interfaces due to %s", name, mono_error_get_message (&error)));
 +              mono_class_set_type_load_failure (klass, "Could not resolve %s interfaces due to %s", name, mono_error_get_message (&error));
                g_free (name);
                mono_error_cleanup (&error);
                return;
                mono_class_init (klass->parent);
                mono_class_setup_vtable_full (klass->parent, in_setup);
  
 -              if (klass->parent->exception_type) {
 -                      char *name = mono_type_get_full_name (klass->parent);
 -                      mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Parent %s failed to load", name));
 -                      g_free (name);
 +              if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Parent class failed to load"))
                        return;
 -              }
  
                max_vtsize += klass->parent->vtable_size;
                cur_slot = klass->parent->vtable_size;
        DEBUG_INTERFACE_VTABLE (first_non_interface_slot = cur_slot);
  
        /* Optimized version for generic instances */
 -      if (klass->generic_class) {
 +      if (mono_class_is_ginst (klass)) {
                MonoError error;
 -              MonoClass *gklass = klass->generic_class->container_class;
 +              MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
                MonoMethod **tmp;
  
                mono_class_setup_vtable_full (gklass, in_setup);
 -              if (gklass->exception_type != MONO_EXCEPTION_NONE) {
 -                      mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
 +              if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Could not load generic definition"))
                        return;
 -              }
  
                tmp = (MonoMethod **)mono_class_alloc0 (klass, sizeof (gpointer) * gklass->vtable_size);
                klass->vtable_size = gklass->vtable_size;
                        if (gklass->vtable [i]) {
                                MonoMethod *inflated = mono_class_inflate_generic_method_full_checked (gklass->vtable [i], klass, mono_class_get_context (klass), &error);
                                if (!mono_error_ok (&error)) {
 -                                      char *err_msg = g_strdup_printf ("Could not inflate method due to %s", mono_error_get_message (&error));
 -                                      mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, err_msg);
 -                                      g_free (err_msg);
 +                                      mono_class_set_type_load_failure (klass, "Could not inflate method due to %s", mono_error_get_message (&error));
                                        mono_error_cleanup (&error);
                                        return;
                                }
                                
                                mono_class_setup_methods (parent_interface); /*FIXME Just kill this whole chunk of dead code*/
                                TRACE_INTERFACE_VTABLE (printf ("    +++ Inheriting interface %s.%s\n", parent_interface->name_space, parent_interface->name));
 -                              for (j = 0; j < parent_interface->method.count && !klass->exception_type; j++) {
 +                              for (j = 0; j < parent_interface->method.count && !mono_class_has_failure (klass); j++) {
                                        vtable [interface_offset + j] = parent->vtable [parent_interface_offset + j];
                                        TRACE_INTERFACE_VTABLE (printf ("    --- Inheriting: [%03d][(%03d)+(%03d)] => [%03d][(%03d)+(%03d)]\n",
                                                        parent_interface_offset + j, parent_interface_offset, j,
                        int dslot;
                        dslot = mono_method_get_vtable_slot (decl);
                        if (dslot == -1) {
 -                              mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
 +                              mono_class_set_type_load_failure (klass, "");
                                return;
                        }
  
                while ((cm = mono_class_get_virtual_methods (klass, &iter))) {
                        virt_methods = g_slist_prepend (virt_methods, cm);
                }
 -              if (klass->exception_type)
 +              if (mono_class_has_failure (klass))
                        goto fail;
        }
        
                ic_offset = mono_class_interface_offset (klass, ic);
  
                mono_class_setup_methods (ic);
 -              if (ic->exception_type)
 +              if (mono_class_has_failure (ic))
                        goto fail;
                
                // Check if this interface is explicitly implemented (instead of just inherited)
                                                }
                                        }
                                        TRACE_INTERFACE_VTABLE (printf ("\n"));
 -                                      if (klass->exception_type)  /*Might be set by check_interface_method_override*/
 +                                      if (mono_class_has_failure (klass))  /*Might be set by check_interface_method_override*/
                                                goto fail;
                                }
                                
                                                        }
                                                        break;
                                                }
 -                                              if (klass->exception_type) /*Might be set by check_interface_method_override*/
 +                                              if (mono_class_has_failure (klass)) /*Might be set by check_interface_method_override*/
                                                        goto fail;
                                                TRACE_INTERFACE_VTABLE ((cm != NULL) && printf ("\n"));
                                        }
        // it can happen (for injected generic array interfaces) that the same slot is
        // processed multiple times (those interfaces have overlapping slots), and it
        // will not always be the first pass the one that fills the slot.
 -      if (! (klass->flags & TYPE_ATTRIBUTE_ABSTRACT)) {
 +      if (!mono_class_is_abstract (klass)) {
                for (i = 0; i < klass->interface_offsets_count; i++) {
                        int ic_offset;
                        int im_index;
                                        m1sig = mono_method_signature (m1);
  
                                        if (!cmsig || !m1sig) {
 -                                              mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
 +                                              /* FIXME proper error message */
 +                                              mono_class_set_type_load_failure (klass, "");
                                                return;
                                        }
  
                                                if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, m1, NULL)) {
                                                        char *body_name = mono_method_full_name (cm, TRUE);
                                                        char *decl_name = mono_method_full_name (m1, TRUE);
 -                                                      mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Method %s overrides method '%s' which is not accessible", body_name, decl_name));
 +                                                      mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
                                                        g_free (body_name);
                                                        g_free (decl_name);
                                                        goto fail;
                                                break;
                                        }
                                }
 -                              if (k->exception_type)
 +                              if (mono_class_has_failure (k))
                                        goto fail;
                                
                                if (slot >= 0) 
        virt_methods = NULL;
  
        /* Ensure that all vtable slots are filled with concrete instance methods */
 -      if (!(klass->flags & TYPE_ATTRIBUTE_ABSTRACT)) {
 +      if (!mono_class_is_abstract (klass)) {
                for (i = 0; i < cur_slot; ++i) {
                        if (vtable [i] == NULL || (vtable [i]->flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_STATIC))) {
                                char *type_name = mono_type_get_full_name (klass);
                                char *method_name = vtable [i] ? mono_method_full_name (vtable [i], TRUE) : g_strdup ("none");
 -                              mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Type %s has invalid vtable method slot %d with method %s", type_name, i, method_name));
 +                              mono_class_set_type_load_failure (klass, "Type %s has invalid vtable method slot %d with method %s", type_name, i, method_name);
                                g_free (type_name);
                                g_free (method_name);
                                return;
                }
        }
  
 -      if (klass->generic_class) {
 -              MonoClass *gklass = klass->generic_class->container_class;
 +      if (mono_class_is_ginst (klass)) {
 +              MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
  
                mono_class_init (gklass);
  
  fail:
        {
        char *name = mono_type_get_full_name (klass);
 -      mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("VTable setup of type %s failed", name));
 +      mono_class_set_type_load_failure (klass, "VTable setup of type %s failed", name);
        g_free (name);
        if (override_map)
                g_hash_table_destroy (override_map);
@@@ -4893,20 -4853,20 +4897,20 @@@ mono_method_get_vtable_slot (MonoMetho
  {
        if (method->slot == -1) {
                mono_class_setup_vtable (method->klass);
 -              if (method->klass->exception_type)
 +              if (mono_class_has_failure (method->klass))
                        return -1;
                if (method->slot == -1) {
                        MonoClass *gklass;
                        int i;
  
 -                      if (!method->klass->generic_class) {
 +                      if (!mono_class_is_ginst (method->klass)) {
                                g_assert (method->is_inflated);
                                return mono_method_get_vtable_slot (((MonoMethodInflated*)method)->declaring);
                        }
  
                        /* This can happen for abstract methods of generic instances due to the shortcut code in mono_class_setup_vtable_general (). */
 -                      g_assert (method->klass->generic_class);
 -                      gklass = method->klass->generic_class->container_class;
 +                      g_assert (mono_class_is_ginst (method->klass));
 +                      gklass = mono_class_get_generic_class (method->klass)->container_class;
                        mono_class_setup_methods (method->klass);
                        g_assert (method->klass->methods);
                        for (i = 0; i < method->klass->method.count; ++i) {
@@@ -4989,7 -4949,7 +4993,7 @@@ generic_array_methods (MonoClass *klass
        if (generic_array_method_num)
                return generic_array_method_num;
        mono_class_setup_methods (klass->parent); /*This is setting up System.Array*/
 -      g_assert (!klass->parent->exception_type); /*So hitting this assert is a huge problem*/
 +      g_assert (!mono_class_has_failure (klass->parent)); /*So hitting this assert is a huge problem*/
        for (i = 0; i < klass->parent->method.count; i++) {
                MonoMethod *m = klass->parent->methods [i];
                if (!strncmp (m->name, "InternalArray__", 15)) {
@@@ -5047,7 -5007,7 +5051,7 @@@ setup_generic_array_ifaces (MonoClass *
        int i;
  
        tmp_context.class_inst = NULL;
 -      tmp_context.method_inst = iface->generic_class->context.class_inst;
 +      tmp_context.method_inst = mono_class_get_generic_class (iface)->context.class_inst;
        //g_print ("setting up array interface: %s\n", mono_type_get_name_full (&iface->byval_arg, 0));
  
        for (i = 0; i < generic_array_method_num; i++) {
@@@ -5075,80 -5035,138 +5079,80 @@@ concat_two_strings_with_zero (MonoImag
        return s;
  }
  
 -static void
 -set_failure_from_loader_error (MonoClass *klass, MonoLoaderError *error)
 -{
 -      gpointer exception_data = NULL;
 -
 -      switch (error->exception_type) {
 -      case MONO_EXCEPTION_TYPE_LOAD:
 -              exception_data = concat_two_strings_with_zero (klass->image, error->class_name, error->assembly_name);
 -              break;
 -
 -      case MONO_EXCEPTION_MISSING_METHOD:
 -              exception_data = concat_two_strings_with_zero (klass->image, error->class_name, error->member_name);
 -              break;
 -
 -      case MONO_EXCEPTION_MISSING_FIELD: {
 -              const char *name_space = error->klass->name_space ? error->klass->name_space : NULL;
 -              const char *class_name;
 -
 -              if (name_space)
 -                      class_name = g_strdup_printf ("%s.%s", name_space, error->klass->name);
 -              else
 -                      class_name = error->klass->name;
 -
 -              exception_data = concat_two_strings_with_zero (klass->image, class_name, error->member_name);
 -              
 -              if (name_space)
 -                      g_free ((void*)class_name);
 -              break;
 -      }
 -
 -      case MONO_EXCEPTION_FILE_NOT_FOUND: {
 -              const char *msg;
 -
 -              if (error->ref_only)
 -                      msg = "Cannot resolve dependency to assembly '%s' because it has not been preloaded. When using the ReflectionOnly APIs, dependent assemblies must be pre-loaded or loaded on demand through the ReflectionOnlyAssemblyResolve event.";
 -              else
 -                      msg = "Could not load file or assembly '%s' or one of its dependencies.";
 -
 -              exception_data = concat_two_strings_with_zero (klass->image, msg, error->assembly_name);
 -              break;
 -      }
 -
 -      case MONO_EXCEPTION_BAD_IMAGE:
 -              exception_data = error->msg;
 -              break;
 -
 -      default :
 -              g_assert_not_reached ();
 -      }
 -
 -      mono_class_set_failure (klass, error->exception_type, exception_data);
 -}
 -
  /**
   * mono_class_init:
 - * @class: the class to initialize
 + * @klass: the class to initialize
   *
   *   Compute the instance_size, class_size and other infos that cannot be 
   * computed at mono_class_get() time. Also compute vtable_size if possible. 
   * Returns TRUE on success or FALSE if there was a problem in loading
 - * the type (incorrect assemblies, missing assemblies, methods, etc). 
 + * the type (incorrect assemblies, missing assemblies, methods, etc).
 + * Initializes the following fields in @klass:
 + * - all the fields initialized by mono_class_init_sizes ()
 + * - has_cctor
 + * - ghcimpl
 + * - inited
   *
   * LOCKING: Acquires the loader lock.
   */
  gboolean
  mono_class_init (MonoClass *klass)
  {
 -      int i;
 +      int i, vtable_size = 0, array_method_count = 0;
        MonoCachedClassInfo cached_info;
        gboolean has_cached_info;
 +      gboolean locked = FALSE;
 +      gboolean ghcimpl = FALSE;
 +      gboolean has_cctor = FALSE;
 +      int first_iface_slot = 0;
        
        g_assert (klass);
  
        /* Double-checking locking pattern */
 -      if (klass->inited || klass->exception_type)
 -              return klass->exception_type == MONO_EXCEPTION_NONE;
 +      if (klass->inited || mono_class_has_failure (klass))
 +              return !mono_class_has_failure (klass);
  
        /*g_print ("Init class %s\n", mono_type_get_full_name (klass));*/
  
 -      /* We do everything inside the lock to prevent races */
 -      mono_loader_lock ();
 -
 -      if (klass->inited || klass->exception_type) {
 -              mono_loader_unlock ();
 -              /* Somebody might have gotten in before us */
 -              return klass->exception_type == MONO_EXCEPTION_NONE;
 -      }
 -
 -      if (klass->init_pending) {
 -              mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Recursive type definition detected"));
 +      /*
 +       * This function can recursively call itself.
 +       */
 +      GSList *init_list = (GSList *)mono_native_tls_get_value (init_pending_tls_id);
 +      if (g_slist_find (init_list, klass)) {
 +              mono_class_set_type_load_failure (klass, "Recursive type definition detected");
                goto leave;
        }
 +      init_list = g_slist_prepend (init_list, klass);
 +      mono_native_tls_set_value (init_pending_tls_id, init_list);
  
 -      klass->init_pending = 1;
 +      /*
 +       * We want to avoid doing complicated work inside locks, so we compute all the required
 +       * information and write it to @klass inside a lock.
 +       */
  
        if (mono_verifier_is_enabled_for_class (klass) && !mono_verifier_verify_class (klass)) {
 -              mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, concat_two_strings_with_zero (klass->image, klass->name, klass->image->assembly_name));
 +              mono_class_set_type_load_failure (klass, "%s", concat_two_strings_with_zero (klass->image, klass->name, klass->image->assembly_name));
                goto leave;
        }
  
 -
        if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
                MonoClass *element_class = klass->element_class;
                if (!element_class->inited) 
                        mono_class_init (element_class);
 -              if (element_class->exception_type != MONO_EXCEPTION_NONE) {
 -                      mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
 +              if (mono_class_set_type_load_failure_causedby_class (klass, element_class, "Could not load array element class"))
                        goto leave;
 -              }
        }
  
        mono_stats.initialized_class_count++;
  
 -      if (klass->generic_class && !klass->generic_class->is_dynamic) {
 -              MonoClass *gklass = klass->generic_class->container_class;
 -
 -              mono_stats.generic_class_count++;
 -
 -              klass->method = gklass->method;
 -              klass->field = gklass->field;
 +      if (mono_class_is_ginst (klass) && !mono_class_get_generic_class (klass)->is_dynamic) {
 +              MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
  
                mono_class_init (gklass);
 -              // FIXME: Why is this needed ?
 -              if (!gklass->exception_type)
 -                      mono_class_setup_methods (gklass);
 -              if (gklass->exception_type) {
 -                      mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Generic Type Defintion failed to init"));
 +              if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic Type Definition failed to init"))
                        goto leave;
 -              }
  
 -              if (MONO_CLASS_IS_INTERFACE (klass))
 -                      klass->interface_id = mono_get_unique_iid (klass);
 +              mono_class_setup_interface_id (klass);
        }
  
        if (klass->parent && !klass->parent->inited)
  
        has_cached_info = mono_class_get_cached_class_info (klass, &cached_info);
  
 -      if (klass->generic_class || image_is_dynamic (klass->image) || !klass->type_token || (has_cached_info && !cached_info.has_nested_classes))
 -              klass->nested_classes_inited = TRUE;
 -
 -      /*
 -       * Computes the size used by the fields, and their locations
 -       */
 -      if (has_cached_info) {
 -              klass->instance_size = cached_info.instance_size;
 -              klass->sizes.class_size = cached_info.class_size;
 -              klass->packing_size = cached_info.packing_size;
 -              klass->min_align = cached_info.min_align;
 -              klass->blittable = cached_info.blittable;
 -              klass->has_references = cached_info.has_references;
 -              klass->has_static_refs = cached_info.has_static_refs;
 -              klass->no_special_static_fields = cached_info.no_special_static_fields;
 -      }
 -      else
 -              if (!klass->size_inited){
 -                      mono_class_setup_fields (klass);
 -                      if (klass->exception_type || mono_loader_get_last_error ())
 -                              goto leave;
 -              }
 -                              
 -      /* Initialize arrays */
 -      if (klass->rank) {
 -              klass->method.count = 3 + (klass->rank > 1? 2: 1);
 -
 -              if (klass->interface_count) {
 -                      int count_generic = generic_array_methods (klass);
 -                      klass->method.count += klass->interface_count * count_generic;
 -              }
 -      }
 +      /* Compute instance size etc. */
 +      init_sizes_with_info (klass, has_cached_info ? &cached_info : NULL);
 +      if (mono_class_has_failure (klass))
 +              goto leave;
  
        mono_class_setup_supertypes (klass);
  
         */
        if (has_cached_info) {
                /* AOT case */
 -              klass->vtable_size = cached_info.vtable_size;
 -              klass->has_finalize = cached_info.has_finalize;
 -              klass->has_finalize_inited = TRUE;
 -              klass->ghcimpl = cached_info.ghcimpl;
 -              klass->has_cctor = cached_info.has_cctor;
 +              vtable_size = cached_info.vtable_size;
 +              ghcimpl = cached_info.ghcimpl;
 +              has_cctor = cached_info.has_cctor;
        } else if (klass->rank == 1 && klass->byval_arg.type == MONO_TYPE_SZARRAY) {
                /* SZARRAY can have 2 vtable layouts, with and without the stelemref method.
                 * The first slot if for array with.
                if (!szarray_vtable_size [slot]) {
                        mono_class_setup_vtable (klass);
                        szarray_vtable_size [slot] = klass->vtable_size;
 +                      vtable_size = klass->vtable_size;
                } else {
 -                      klass->vtable_size = szarray_vtable_size[slot];
 +                      vtable_size = szarray_vtable_size[slot];
                }
 -      } else if (klass->generic_class && !MONO_CLASS_IS_INTERFACE (klass)) {
 -              MonoClass *gklass = klass->generic_class->container_class;
 +      } else if (mono_class_is_ginst (klass) && !MONO_CLASS_IS_INTERFACE (klass)) {
 +              MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
  
                /* Generic instance case */
 -              klass->ghcimpl = gklass->ghcimpl;
 -              klass->has_cctor = gklass->has_cctor;
 +              ghcimpl = gklass->ghcimpl;
 +              has_cctor = gklass->has_cctor;
  
                mono_class_setup_vtable (gklass);
 -              if (gklass->exception_type) {
 -                      mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
 +              if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to init"))
                        goto leave;
 -              }
  
 -              klass->vtable_size = gklass->vtable_size;
 +              vtable_size = gklass->vtable_size;
        } else {
                /* General case */
  
                if (!MONO_CLASS_IS_INTERFACE (klass) || klass->image != mono_defaults.corlib) {
                        MonoMethod *cmethod = NULL;
  
 -                      if (klass->type_token && !image_is_dynamic(klass->image)) {
 +                      if (mono_class_is_ginst (klass)) {
 +                              MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
 +
 +                              /* Generic instance case */
 +                              ghcimpl = gklass->ghcimpl;
 +                              has_cctor = gklass->has_cctor;
 +                      } else if (klass->type_token && !image_is_dynamic(klass->image)) {
                                cmethod = find_method_in_metadata (klass, ".cctor", 0, METHOD_ATTRIBUTE_SPECIAL_NAME);
                                /* The find_method function ignores the 'flags' argument */
                                if (cmethod && (cmethod->flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
 -                                      klass->has_cctor = 1;
 +                                      has_cctor = 1;
                        } else {
                                mono_class_setup_methods (klass);
 -                              if (klass->exception_type)
 +                              if (mono_class_has_failure (klass))
                                        goto leave;
  
                                for (i = 0; i < klass->method.count; ++i) {
                                        MonoMethod *method = klass->methods [i];
                                        if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) && 
                                                (strcmp (".cctor", method->name) == 0)) {
 -                                              klass->has_cctor = 1;
 +                                              has_cctor = 1;
                                                break;
                                        }
                                }
                }
        }
  
 -      if (klass->parent) {
 -              int first_iface_slot;
 -              /* This will compute klass->parent->vtable_size for some classes */
 -              mono_class_init (klass->parent);
 -              if (klass->parent->exception_type) {
 -                      mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
 -                      goto leave;
 +      if (klass->rank) {
 +              array_method_count = 3 + (klass->rank > 1? 2: 1);
 +
 +              if (klass->interface_count) {
 +                      int count_generic = generic_array_methods (klass);
 +                      array_method_count += klass->interface_count * count_generic;
                }
 -              if (mono_loader_get_last_error ())
 -                      goto leave;
 -              if (!klass->parent->vtable_size) {
 -                      /* FIXME: Get rid of this somehow */
 +      }
 +
 +      if (klass->parent) {
 +              if (!klass->parent->vtable_size)
                        mono_class_setup_vtable (klass->parent);
 -                      if (klass->parent->exception_type) {
 -                              mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
 -                              goto leave;
 -                      }
 -                      if (mono_loader_get_last_error ())
 -                              goto leave;
 -              }
 +              if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Parent class vtable failed to initialize"))
 +                      goto leave;
 +              g_assert (klass->parent->vtable_size);
                first_iface_slot = klass->parent->vtable_size;
                if (mono_class_need_stelemref_method (klass))
                        ++first_iface_slot;
 -              setup_interface_offsets (klass, first_iface_slot, TRUE);
 -      } else {
 -              setup_interface_offsets (klass, 0, TRUE);
        }
  
 +      /*
 +       * Do the actual changes to @klass inside the loader lock
 +       */
 +      mono_loader_lock ();
 +      locked = TRUE;
 +
 +      if (klass->inited || mono_class_has_failure (klass)) {
 +              mono_loader_unlock ();
 +              /* Somebody might have gotten in before us */
 +              return !mono_class_has_failure (klass);
 +      }
 +
 +      mono_stats.initialized_class_count++;
 +
 +      if (mono_class_is_ginst (klass) && !mono_class_get_generic_class (klass)->is_dynamic) {
 +              MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
 +
 +              mono_stats.generic_class_count++;
 +
 +              klass->method = gklass->method;
 +              klass->field = gklass->field;
 +      }
 +
 +      if (mono_class_is_ginst (klass) || image_is_dynamic (klass->image) || !klass->type_token || (has_cached_info && !cached_info.has_nested_classes))
 +              klass->nested_classes_inited = TRUE;
 +      klass->ghcimpl = ghcimpl;
 +      klass->has_cctor = has_cctor;
 +      if (vtable_size)
 +              klass->vtable_size = vtable_size;
 +      if (has_cached_info) {
 +              klass->has_finalize = cached_info.has_finalize;
 +              klass->has_finalize_inited = TRUE;
 +      }
 +      if (klass->rank)
 +              klass->method.count = array_method_count;
 +
 +      mono_loader_unlock ();
 +      locked = FALSE;
 +
 +      setup_interface_offsets (klass, first_iface_slot, TRUE);
 +
        if (mono_security_core_clr_enabled ())
                mono_security_core_clr_check_inheritance (klass);
  
 -      if (mono_loader_get_last_error ()) {
 -              if (klass->exception_type == MONO_EXCEPTION_NONE) {
 -                      set_failure_from_loader_error (klass, mono_loader_get_last_error ());
 -              }
 -              mono_loader_clear_error ();
 -      }
 -
 -      if (klass->generic_class && !mono_verifier_class_is_valid_generic_instantiation (klass))
 -              mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Invalid generic instantiation"));
 +      if (mono_class_is_ginst (klass) && !mono_verifier_class_is_valid_generic_instantiation (klass))
 +              mono_class_set_type_load_failure (klass, "Invalid generic instantiation");
  
        goto leave;
  
   leave:
 +      init_list = g_slist_remove (init_list, klass);
 +      mono_native_tls_set_value (init_pending_tls_id, init_list);
 +
        /* Because of the double-checking locking pattern */
        mono_memory_barrier ();
        klass->inited = 1;
 -      klass->init_pending = 0;
  
 -      mono_loader_unlock ();
 +      if (locked)
 +              mono_loader_unlock ();
  
 -      return klass->exception_type == MONO_EXCEPTION_NONE;
 +      return !mono_class_has_failure (klass);
  }
  
  /*
@@@ -5353,8 -5367,8 +5357,8 @@@ mono_class_has_finalizer (MonoClass *kl
                MonoMethod *cmethod = NULL;
  
                if (klass->rank == 1 && klass->byval_arg.type == MONO_TYPE_SZARRAY) {
 -              } else if (klass->generic_class) {
 -                      MonoClass *gklass = klass->generic_class->container_class;
 +              } else if (mono_class_is_ginst (klass)) {
 +                      MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
  
                        has_finalize = mono_class_has_finalizer (gklass);
                } else if (klass->parent && klass->parent->has_finalize) {
                                 * ignores overrides.
                                 */
                                mono_class_setup_vtable (klass);
 -                              if (klass->exception_type || mono_loader_get_last_error ())
 +                              if (mono_class_has_failure (klass))
                                        cmethod = NULL;
                                else
                                        cmethod = klass->vtable [finalize_slot];
  gboolean
  mono_is_corlib_image (MonoImage *image)
  {
 -      /* FIXME: allow the dynamic case for our compilers and with full trust */
 -      if (image_is_dynamic (image))
 -              return image->assembly && !strcmp (image->assembly->aname.name, "mscorlib");
 -      else
 -              return image == mono_defaults.corlib;
 +      return image == mono_defaults.corlib;
  }
  
  /*
@@@ -5531,6 -5549,7 +5535,6 @@@ mono_class_setup_mono_type (MonoClass *
  
        if (MONO_CLASS_IS_INTERFACE (klass))
                klass->interface_id = mono_get_unique_iid (klass);
 -
  }
  
  #ifndef DISABLE_COM
@@@ -5550,7 -5569,7 +5554,7 @@@ init_com_from_comimport (MonoClass *kla
                        /* but it can not be made available for application (i.e. user code) since all COM calls
                         * are considered native calls. In this case we fail with a TypeLoadException (just like
                         * Silverlight 2 does */
 -                      mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
 +                      mono_class_set_type_load_failure (klass, "");
                        return;
                }
        }
@@@ -5594,13 -5613,12 +5598,13 @@@ mono_class_setup_parent (MonoClass *kla
                if (!parent) {
                        /* set the parent to something useful and safe, but mark the type as broken */
                        parent = mono_defaults.object_class;
 -                      mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
 +                      mono_class_set_type_load_failure (klass, "");
 +                      g_assert (parent);
                }
  
                klass->parent = parent;
  
 -              if (parent->generic_class && !parent->name) {
 +              if (mono_class_is_ginst (parent) && !parent->name) {
                        /*
                         * If the parent is a generic instance, we may get
                         * called before it is fully initialized, especially
@@@ -5700,7 -5718,7 +5704,7 @@@ fix_gclass_incomplete_instantiation (Mo
  {
        MonoClass *gtd = (MonoClass*)user_data;
        /* Only try to fix generic instances of @gtd */
 -      if (gclass->generic_class->container_class != gtd)
 +      if (mono_class_get_generic_class (gclass)->container_class != gtd)
                return FALSE;
  
        /* Check if the generic instance has no parent. */
  static void
  mono_class_set_failure_and_error (MonoClass *klass, MonoError *error, const char *msg)
  {
 -      mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup (msg));
 -      mono_error_set_type_load_class (error, klass, msg);
 -}
 -
 -static void
 -mono_class_set_failure_from_loader_error (MonoClass *klass, MonoError *error, char *msg)
 -{
 -      MonoLoaderError *lerror = mono_loader_get_last_error ();
 -
 -      if (lerror) {
 -              set_failure_from_loader_error (klass, lerror);
 -              mono_error_set_from_loader_error (error);
 -              if (msg)
 -                      g_free (msg);
 -      } else {
 -              mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, msg);
 -              mono_error_set_type_load_class (error, klass, msg);
 -      }
 +      mono_class_set_type_load_failure (klass, "%s", msg);
 +      mono_error_set_type_load_class (error, klass, "%s", msg);
  }
  
  /**
@@@ -5747,6 -5781,7 +5751,6 @@@ mono_class_create_from_typedef (MonoIma
  
        if (mono_metadata_token_table (type_token) != MONO_TABLE_TYPEDEF || tidx > tt->rows) {
                mono_error_set_bad_image (error, image, "Invalid typedef token %x", type_token);
 -              mono_loader_assert_no_error ();
                return NULL;
        }
  
  
        if ((klass = (MonoClass *)mono_internal_hash_table_lookup (&image->class_cache, GUINT_TO_POINTER (type_token)))) {
                mono_loader_unlock ();
 -              mono_loader_assert_no_error ();
                return klass;
        }
  
        name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
        nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
  
 -      klass = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClass));
 +      if (mono_metadata_has_generic_params (image, type_token)) {
 +              klass = mono_image_alloc0 (image, sizeof (MonoClassGtd));
 +              klass->class_kind = MONO_CLASS_GTD;
 +              classes_size += sizeof (MonoClassGtd);
 +              ++class_gtd_count;
 +      } else {
 +              klass = mono_image_alloc0 (image, sizeof (MonoClassDef));
 +              klass->class_kind = MONO_CLASS_DEF;
 +              classes_size += sizeof (MonoClassDef);
 +              ++class_def_count;
 +      }
  
        klass->name = name;
        klass->name_space = nspace;
  
        klass->image = image;
        klass->type_token = type_token;
 -      klass->flags = cols [MONO_TYPEDEF_FLAGS];
 +      mono_class_set_flags (klass, cols [MONO_TYPEDEF_FLAGS]);
  
        mono_internal_hash_table_insert (&image->class_cache, GUINT_TO_POINTER (type_token), klass);
  
 -      classes_size += sizeof (MonoClass);
 -
        /*
         * Check whether we're a generic type definition.
         */
 -      klass->generic_container = mono_metadata_load_generic_params (image, klass->type_token, NULL);
 -      if (klass->generic_container) {
 -              klass->is_generic = 1;
 -              klass->generic_container->owner.klass = klass;
 -              klass->generic_container->is_anonymous = FALSE; // Owner class is now known, container is no longer anonymous
 -              context = &klass->generic_container->context;
 -      }
 -
 -      if (klass->generic_container)
 +      if (mono_class_is_gtd (klass)) {
 +              MonoGenericContainer *generic_container = mono_metadata_load_generic_params (image, klass->type_token, NULL);
 +              generic_container->owner.klass = klass;
 +              generic_container->is_anonymous = FALSE; // Owner class is now known, container is no longer anonymous
 +              context = &generic_container->context;
 +              mono_class_set_generic_container (klass, generic_container);
                enable_gclass_recording ();
 +      }
  
        if (cols [MONO_TYPEDEF_EXTENDS]) {
                MonoClass *tmp;
                        parent = mono_class_inflate_generic_class_checked (parent, context, error);
  
                if (parent == NULL) {
 -                      mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup (mono_error_get_message (error)));
 +                      mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
                        goto parent_failure;
                }
  
                                mono_class_set_failure_and_error (klass, error, "Cycle found while resolving parent");
                                goto parent_failure;
                        }
 -                      if (klass->generic_container && tmp->generic_class && tmp->generic_class->container_class == klass) {
 +                      if (mono_class_is_gtd (klass) && mono_class_is_ginst (tmp) && mono_class_get_generic_class (tmp)->container_class == klass) {
                                mono_class_set_failure_and_error (klass, error, "Parent extends generic instance of this type");
                                goto parent_failure;
                        }
        /* uses ->valuetype, which is initialized by mono_class_setup_parent above */
        mono_class_setup_mono_type (klass);
  
 -      if (klass->generic_container)
 +      if (mono_class_is_gtd (klass))
                disable_gclass_recording (fix_gclass_incomplete_instantiation, klass);
  
        /* 
                klass->nested_in = mono_class_create_from_typedef (image, nesting_tokeen, error);
                if (!mono_error_ok (error)) {
                        /*FIXME implement a mono_class_set_failure_from_mono_error */
 -                      mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup (mono_error_get_message (error)));
 +                      mono_class_set_type_load_failure (klass, "%s",  mono_error_get_message (error));
                        mono_loader_unlock ();
                        mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED);
 -                      mono_loader_assert_no_error ();
                        return NULL;
                }
        }
  
 -      if ((klass->flags & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_UNICODE_CLASS)
 +      if ((mono_class_get_flags (klass) & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_UNICODE_CLASS)
                klass->unicode = 1;
  
  #ifdef HOST_WIN32
 -      if ((klass->flags & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_AUTO_CLASS)
 +      if ((mono_class_get_flags (klass) & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_AUTO_CLASS)
                klass->unicode = 1;
  #endif
  
                if (!mono_metadata_interfaces_from_typedef_full (
                            image, type_token, &interfaces, &icount, FALSE, context, error)){
  
 -                      mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup (mono_error_get_message (error)));
 +                      mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
                        mono_loader_unlock ();
                        mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED);
                        return NULL;
                }
  
+               /* This is required now that it is possible for more than 2^16 interfaces to exist. */
+               g_assert(icount <= 65535);
                klass->interfaces = interfaces;
                klass->interface_count = icount;
                klass->interfaces_inited = 1;
        /*
         * Compute the field and method lists
         */
 -      klass->field.first  = cols [MONO_TYPEDEF_FIELD_LIST] - 1;
 -      klass->method.first = cols [MONO_TYPEDEF_METHOD_LIST] - 1;
 +      int first_field_idx = cols [MONO_TYPEDEF_FIELD_LIST] - 1;
 +      mono_class_set_first_field_idx (klass, first_field_idx);
 +      int first_method_idx = cols [MONO_TYPEDEF_METHOD_LIST] - 1;
 +      mono_class_set_first_method_idx (klass, first_method_idx);
  
        if (tt->rows > tidx){           
                mono_metadata_decode_row (tt, tidx, cols_next, MONO_TYPEDEF_SIZE);
  
        if (cols [MONO_TYPEDEF_FIELD_LIST] && 
            cols [MONO_TYPEDEF_FIELD_LIST] <= image->tables [MONO_TABLE_FIELD].rows)
 -              klass->field.count = field_last - klass->field.first;
 +              klass->field.count = field_last - first_field_idx;
        else
                klass->field.count = 0;
  
        if (cols [MONO_TYPEDEF_METHOD_LIST] <= image->tables [MONO_TABLE_METHOD].rows)
 -              klass->method.count = method_last - klass->method.first;
 +              klass->method.count = method_last - first_method_idx;
        else
                klass->method.count = 0;
  
                if (!enum_basetype) {
                        /*set it to a default value as the whole runtime can't handle this to be null*/
                        klass->cast_class = klass->element_class = mono_defaults.int32_class;
 -                      mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup (mono_error_get_message (error)));
 +                      mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
                        mono_loader_unlock ();
                        mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED);
 -                      mono_loader_assert_no_error ();
                        return NULL;
                }
                klass->cast_class = klass->element_class = mono_class_from_mono_type (enum_basetype);
         * We must do this after the class has been constructed to make certain recursive scenarios
         * work.
         */
 -      if (klass->generic_container && !mono_metadata_load_generic_param_constraints_checked (image, type_token, klass->generic_container, error)) {
 -              mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Could not load generic parameter constrains due to %s", mono_error_get_message (error)));
 +      if (mono_class_is_gtd (klass) && !mono_metadata_load_generic_param_constraints_checked (image, type_token, mono_class_get_generic_container (klass), error)) {
 +              mono_class_set_type_load_failure (klass, "Could not load generic parameter constrains due to %s", mono_error_get_message (error));
                mono_loader_unlock ();
                mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED);
 -              mono_loader_assert_no_error ();
                return NULL;
        }
  
        mono_loader_unlock ();
  
        mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
 -      mono_loader_assert_no_error ();
  
        return klass;
  
@@@ -5954,6 -5989,7 +5961,6 @@@ parent_failure
        mono_class_setup_mono_type (klass);
        mono_loader_unlock ();
        mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED);
 -      mono_loader_assert_no_error ();
        return NULL;
  }
  
  gboolean
  mono_class_is_nullable (MonoClass *klass)
  {
 -       return klass->generic_class != NULL &&
 -               klass->generic_class->container_class == mono_defaults.generic_nullable_class;
 +      MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
 +      return gklass && gklass->container_class == mono_defaults.generic_nullable_class;
  }
  
  
@@@ -5971,7 -6007,7 +5978,7 @@@ MonoClass
  mono_class_get_nullable_param (MonoClass *klass)
  {
         g_assert (mono_class_is_nullable (klass));
 -       return mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [0]);
 +       return mono_class_from_mono_type (mono_class_get_generic_class (klass)->context.class_inst->type_argv [0]);
  }
  
  static void
@@@ -5979,13 -6015,13 +5986,13 @@@ mono_generic_class_setup_parent (MonoCl
  {
        if (gtd->parent) {
                MonoError error;
 -              MonoGenericClass *gclass = klass->generic_class;
 +              MonoGenericClass *gclass = mono_class_get_generic_class (klass);
  
                klass->parent = mono_class_inflate_generic_class_checked (gtd->parent, mono_generic_class_get_context (gclass), &error);
                if (!mono_error_ok (&error)) {
                        /*Set parent to something safe as the runtime doesn't handle well this kind of failure.*/
                        klass->parent = mono_defaults.object_class;
 -                      mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
 +                      mono_class_set_type_load_failure (klass, "Parent is a generic type instantiation that failed due to: %s", mono_error_get_message (&error));
                        mono_error_cleanup (&error);
                }
        }
@@@ -6017,7 -6053,7 +6024,7 @@@ mono_generic_class_get_class (MonoGener
                return gclass->cached_class;
        }
  
 -      klass = (MonoClass *)mono_image_set_alloc0 (gclass->owner, sizeof (MonoClass));
 +      klass = (MonoClass *)mono_image_set_alloc0 (gclass->owner, sizeof (MonoClassGenericInst));
  
        gklass = gclass->container_class;
  
        mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
        
        klass->image = gklass->image;
 -      klass->flags = gklass->flags;
        klass->type_token = gklass->type_token;
        klass->field.count = gklass->field.count;
  
 -      klass->is_inflated = 1;
 -      klass->generic_class = gclass;
 +      klass->class_kind = MONO_CLASS_GINST;
 +      //FIXME add setter
 +      ((MonoClassGenericInst*)klass)->generic_class = gclass;
  
        klass->byval_arg.type = MONO_TYPE_GENERICINST;
        klass->this_arg.type = klass->byval_arg.type;
  
        mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
  
 -      inflated_classes ++;
 -      inflated_classes_size += sizeof (MonoClass);
 +      ++class_ginst_count;
 +      inflated_classes_size += sizeof (MonoClassGenericInst);
        
        mono_loader_unlock ();
  
@@@ -6152,10 -6188,8 +6159,10 @@@ make_generic_param_class (MonoGenericPa
        gboolean is_mvar = container->is_method;
        gboolean is_anonymous = container->is_anonymous;
  
 -      klass = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClass));
 -      classes_size += sizeof (MonoClass);
 +      klass = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassGenericParam));
 +      klass->class_kind = MONO_CLASS_GPARAM;
 +      classes_size += sizeof (MonoClassGenericParam);
 +      ++class_gparam_count;
  
        if (pinfo) {
                CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name , pinfo->name );
                CHECKED_METADATA_WRITE_PTR ( klass->parent , pinfo->constraints [0] );
                pos++;
        } else if (pinfo && pinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) {
 -              CHECKED_METADATA_WRITE_PTR ( klass->parent , mono_class_from_name (mono_defaults.corlib, "System", "ValueType") );
 +              CHECKED_METADATA_WRITE_PTR ( klass->parent , mono_class_load_from_name (mono_defaults.corlib, "System", "ValueType") );
        } else {
                CHECKED_METADATA_WRITE_PTR ( klass->parent , mono_defaults.object_class );
        }
        klass->inited = TRUE;
        CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->cast_class ,    klass );
        CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->element_class , klass );
 -      klass->flags = TYPE_ATTRIBUTE_PUBLIC;
  
        klass->byval_arg.type = is_mvar ? MONO_TYPE_MVAR : MONO_TYPE_VAR;
        klass->this_arg.type = klass->byval_arg.type;
        klass->instance_size = sizeof (MonoObject) + mono_type_stack_size_internal (&klass->byval_arg, NULL, TRUE);
        mono_memory_barrier ();
        klass->size_inited = 1;
 -      klass->setup_fields_called = 1;
  
        mono_class_setup_supertypes (klass);
  
        if (count - pos > 0) {
                mono_class_setup_vtable (klass->parent);
 -              if (klass->parent->exception_type)
 -                      mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Failed to setup parent interfaces"));
 +              if (mono_class_has_failure (klass->parent))
 +                      mono_class_set_type_load_failure (klass, "Failed to setup parent interfaces");
                else
                        setup_interface_offsets (klass, klass->parent->vtable_size, TRUE);
        }
@@@ -6430,23 -6466,23 +6437,23 @@@ mono_ptr_class_get (MonoType *type
        }
        mono_image_unlock (image);
        
 -      result = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClass));
 +      result = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassPointer));
  
 -      classes_size += sizeof (MonoClass);
 +      classes_size += sizeof (MonoClassPointer);
 +      ++class_pointer_count;
  
        result->parent = NULL; /* no parent for PTR types */
        result->name_space = el_class->name_space;
        name = g_strdup_printf ("%s*", el_class->name);
        result->name = mono_image_strdup (image, name);
 +      result->class_kind = MONO_CLASS_POINTER;
        g_free (name);
  
        mono_profiler_class_event (result, MONO_PROFILE_START_LOAD);
  
        result->image = el_class->image;
        result->inited = TRUE;
 -      result->flags = TYPE_ATTRIBUTE_CLASS | (el_class->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK);
 -      /* Can pointers get boxed? */
 -      result->instance_size = sizeof (gpointer);
 +      result->instance_size = sizeof (MonoObject) + sizeof (gpointer);
        result->cast_class = result->element_class = el_class;
        result->blittable = TRUE;
  
@@@ -6495,19 -6531,17 +6502,19 @@@ mono_fnptr_class_get (MonoMethodSignatu
        }
        result = g_new0 (MonoClass, 1);
  
 +      classes_size += sizeof (MonoClassPointer);
 +      ++class_pointer_count;
 +
        result->parent = NULL; /* no parent for PTR types */
        result->name_space = "System";
        result->name = "MonoFNPtrFakeClass";
 +      result->class_kind = MONO_CLASS_POINTER;
  
        mono_profiler_class_event (result, MONO_PROFILE_START_LOAD);
  
        result->image = mono_defaults.corlib; /* need to fix... */
        result->inited = TRUE;
 -      result->flags = TYPE_ATTRIBUTE_CLASS; /* | (el_class->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK); */
 -      /* Can pointers get boxed? */
 -      result->instance_size = sizeof (gpointer);
 +      result->instance_size = sizeof (MonoObject) + sizeof (gpointer);
        result->cast_class = result->element_class = result;
        result->blittable = TRUE;
  
        return result;
  }
  
 +/**
 + * mono_class_from_mono_type:
 + * @type: describes the type to return
 + *
 + * This returns a MonoClass for the specified MonoType, the value is never NULL.
 + */
  MonoClass *
  mono_class_from_mono_type (MonoType *type)
  {
                g_warning ("mono_class_from_mono_type: implement me 0x%02x\n", type->type);
                g_assert_not_reached ();
        }
 -      
 +
 +      // Yes, this returns NULL, even if it is documented as not doing so, but there
 +      // is no way for the code to make it this far, due to the assert above.
        return NULL;
  }
  
@@@ -6620,6 -6646,7 +6627,6 @@@ mono_type_retrieve_from_typespec (MonoI
                MonoType *inflated = inflate_generic_type (NULL, t, context, error);
  
                if (!mono_error_ok (error)) {
 -                      mono_loader_assert_no_error ();
                        return NULL;
                }
  
@@@ -6643,7 -6670,8 +6650,7 @@@ mono_class_create_from_typespec (MonoIm
        MonoClass *ret;
        gboolean inflated = FALSE;
        MonoType *t = mono_type_retrieve_from_typespec (image, type_spec, context, &inflated, error);
 -      if (!mono_error_ok (error))
 -              return NULL;
 +      return_val_if_nok (error, NULL);
        ret = mono_class_from_mono_type (t);
        if (inflated)
                mono_metadata_free_type (t);
   * @rank: the dimension of the array class
   * @bounded: whenever the array has non-zero bounds
   *
 - * Returns: a class object describing the array with element type @element_type and 
 + * Returns: A class object describing the array with element type @element_type and 
   * dimension @rank. 
   */
  MonoClass *
@@@ -6668,6 -6696,7 +6675,6 @@@ mono_bounded_array_class_get (MonoClas
        GSList *list, *rootlist = NULL;
        int nsize;
        char *name;
 -      gboolean corlib_type = FALSE;
  
        g_assert (rank <= 255);
  
                }
        }
  
 -      /* for the building corlib use System.Array from it */
 -      if (image->assembly && assembly_is_dynamic (image->assembly) && image->assembly_name && strcmp (image->assembly_name, "mscorlib") == 0) {
 -              parent = mono_class_from_name (image, "System", "Array");
 -              corlib_type = TRUE;
 -      } else {
 -              parent = mono_defaults.array_class;
 -              if (!parent->inited)
 -                      mono_class_init (parent);
 -      }
 +      parent = mono_defaults.array_class;
 +      if (!parent->inited)
 +              mono_class_init (parent);
  
 -      klass = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClass));
 +      klass = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassArray));
  
        klass->image = image;
        klass->name_space = eclass->name_space;
 +      klass->class_kind = MONO_CLASS_ARRAY;
 +
        nsize = strlen (eclass->name);
        name = (char *)g_malloc (nsize + 2 + rank + 1);
        memcpy (name, eclass->name, nsize);
  
        mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
  
 -      classes_size += sizeof (MonoClass);
 +      classes_size += sizeof (MonoClassArray);
 +      ++class_array_count;
  
        klass->type_token = 0;
 -      /* all arrays are marked serializable and sealed, bug #42779 */
 -      klass->flags = TYPE_ATTRIBUTE_CLASS | TYPE_ATTRIBUTE_SERIALIZABLE | TYPE_ATTRIBUTE_SEALED | TYPE_ATTRIBUTE_PUBLIC;
        klass->parent = parent;
        klass->instance_size = mono_class_instance_size (klass->parent);
  
        if (eclass->byval_arg.type == MONO_TYPE_TYPEDBYREF || eclass->byval_arg.type == MONO_TYPE_VOID) {
                /*Arrays of those two types are invalid.*/
 -              mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
 +              MonoError prepared_error;
 +              mono_error_init (&prepared_error);
 +              mono_error_set_invalid_program (&prepared_error, "Arrays of void or System.TypedReference types are invalid.");
 +              mono_class_set_failure (klass, mono_error_box (&prepared_error, klass->image));
 +              mono_error_cleanup (&prepared_error);
        } else if (eclass->enumtype && !mono_class_enum_basetype (eclass)) {
                if (!eclass->ref_info_handle || eclass->wastypebuilder) {
                        g_warning ("Only incomplete TypeBuilder objects are allowed to be an enum without base_type");
  
        mono_class_setup_supertypes (klass);
  
 -      if (eclass->generic_class)
 +      if (mono_class_is_ginst (eclass))
                mono_class_init (eclass);
        if (!eclass->size_inited)
                mono_class_setup_fields (eclass);
 -      if (eclass->exception_type) /*FIXME we fail the array type, but we have to let other fields be set.*/
 -              mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
 +      mono_class_set_type_load_failure_causedby_class (klass, eclass, "Could not load array element type");
 +      /*FIXME we fail the array type, but we have to let other fields be set.*/
  
        klass->has_references = MONO_TYPE_IS_REFERENCE (&eclass->byval_arg) || eclass->has_references? TRUE: FALSE;
  
        }
        klass->this_arg = klass->byval_arg;
        klass->this_arg.byref = 1;
 -      if (corlib_type) {
 -              klass->inited = 1;
 -      }
  
 -      klass->generic_container = eclass->generic_container;
 +      //WTF was this? it's wrong
 +      // klass->generic_container = eclass->generic_container;
  
        if (rank == 1 && !bounded) {
                MonoClass *prev_class;
   * @element_class: element class 
   * @rank: the dimension of the array class
   *
 - * Returns: a class object describing the array with element type @element_type and 
 + * Returns: A class object describing the array with element type @element_type and 
   * dimension @rank. 
   */
  MonoClass *
@@@ -6860,10 -6892,8 +6867,10 @@@ mono_array_class_get (MonoClass *eclass
  /**
   * mono_class_instance_size:
   * @klass: a class 
 - * 
 - * Returns: the size of an object instance
 + *
 + * Use to get the size of a class in bytes.
 + *
 + * Returns: The size of an object instance
   */
  gint32
  mono_class_instance_size (MonoClass *klass)
  /**
   * mono_class_min_align:
   * @klass: a class 
 - * 
 - * Returns: minimm alignment requirements 
 + *
 + * Use to get the computed minimum alignment requirements for the specified class.
 + *
 + * Returns: minimum alignment requirements
   */
  gint32
  mono_class_min_align (MonoClass *klass)
   * Returns: the size of a value of kind @klass
   */
  gint32
 -mono_class_value_size      (MonoClass *klass, guint32 *align)
 +mono_class_value_size (MonoClass *klass, guint32 *align)
  {
        gint32 size;
  
   * mono_class_data_size:
   * @klass: a class 
   * 
 - * Returns: the size of the static class data
 + * Returns: The size of the static class data
   */
  gint32
  mono_class_data_size (MonoClass *klass)
                mono_class_init (klass);
        /* This can happen with dynamically created types */
        if (!klass->fields_inited)
 -              mono_class_setup_fields_locking (klass);
 +              mono_class_setup_fields (klass);
  
        /* in arrays, sizes.class_size is unioned with element_size
         * and arrays have no static fields
  static MonoClassField *
  mono_class_get_field_idx (MonoClass *klass, int idx)
  {
 -      mono_class_setup_fields_locking (klass);
 -      if (klass->exception_type)
 +      mono_class_setup_fields (klass);
 +      if (mono_class_has_failure (klass))
                return NULL;
  
        while (klass) {
 +              int first_field_idx = mono_class_get_first_field_idx (klass);
                if (klass->image->uncompressed_metadata) {
                        /* 
 -                       * klass->field.first points to the FieldPtr table, while idx points into the
 +                       * first_field_idx points to the FieldPtr table, while idx points into the
                         * Field table, so we have to do a search.
                         */
                        /*FIXME this is broken for types with multiple fields with the same name.*/
                        g_assert_not_reached ();
                } else {                        
                        if (klass->field.count) {
 -                              if ((idx >= klass->field.first) && (idx < klass->field.first + klass->field.count)){
 -                                      return &klass->fields [idx - klass->field.first];
 +                              if ((idx >= first_field_idx) && (idx < first_field_idx + klass->field.count)){
 +                                      return &klass->fields [idx - first_field_idx];
                                }
                        }
                }
@@@ -7006,7 -7033,7 +7013,7 @@@ mono_class_get_field (MonoClass *klass
   *
   * Search the class @klass and it's parents for a field with the name @name.
   * 
 - * Returns: the MonoClassField pointer of the named field or NULL
 + * Returns: The MonoClassField pointer of the named field or NULL
   */
  MonoClassField *
  mono_class_get_field_from_name (MonoClass *klass, const char *name)
   * If @klass is an inflated generic type, the type comparison is done with the equivalent field
   * of its generic type definition.
   *
 - * Returns: the MonoClassField pointer of the named field or NULL
 + * Returns: The MonoClassField pointer of the named field or NULL
   */
  MonoClassField *
  mono_class_get_field_from_name_full (MonoClass *klass, const char *name, MonoType *type)
  {
        int i;
  
 -      mono_class_setup_fields_locking (klass);
 -      if (klass->exception_type)
 +      mono_class_setup_fields (klass);
 +      if (mono_class_has_failure (klass))
                return NULL;
  
        while (klass) {
   * Get the token of a field. Note that the tokesn is only valid for the image
   * the field was loaded from. Don't use this function for fields in dynamic types.
   * 
 - * Returns: the token representing the field in the image it was loaded from.
 + * Returns: The token representing the field in the image it was loaded from.
   */
  guint32
  mono_class_get_field_token (MonoClassField *field)
        MonoClass *klass = field->parent;
        int i;
  
 -      mono_class_setup_fields_locking (klass);
 +      mono_class_setup_fields (klass);
  
        while (klass) {
                if (!klass->fields)
                        return 0;
 +              int first_field_idx = mono_class_get_first_field_idx (klass);
                for (i = 0; i < klass->field.count; ++i) {
                        if (&klass->fields [i] == field) {
 -                              int idx = klass->field.first + i + 1;
 +                              int idx = first_field_idx + i + 1;
  
                                if (klass->image->uncompressed_metadata)
                                        idx = mono_metadata_translate_token_index (klass->image, MONO_TABLE_FIELD, idx);
@@@ -7215,15 -7241,6 +7222,15 @@@ mono_class_get_event_token (MonoEvent *
        return 0;
  }
  
 +/**
 + * mono_class_get_property_from_name:
 + * @klass: a class
 + * @name: name of the property to lookup in the specified class
 + *
 + * Use this method to lookup a property in a class
 + * Returns: the MonoProperty with the given name, or NULL if the property
 + * does not exist on the @klass.
 + */
  MonoProperty*
  mono_class_get_property_from_name (MonoClass *klass, const char *name)
  {
        return NULL;
  }
  
 +/**
 + * mono_class_get_property_token:
 + * @prop: MonoProperty to query
 + *
 + * Returns: The ECMA token for the specified property.
 + */
  guint32
  mono_class_get_property_token (MonoProperty *prop)
  {
@@@ -7388,7 -7399,7 +7395,7 @@@ mono_assembly_name_from_token (MonoImag
   * @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
 + * Returns: The MonoClass that represents @type_token in @image
   */
  MonoClass *
  mono_class_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *context)
@@@ -7424,7 -7435,7 +7431,7 @@@ mono_class_get_and_inflate_typespec_che
   * @type_token: the token for the class
   * @error: error object to return any error
   *
 - * Returns: the MonoClass that represents @type_token in @image
 + * Returns: The MonoClass that represents @type_token in @image, or NULL on error.
   */
  MonoClass *
  mono_class_get_checked (MonoImage *image, guint32 type_token, MonoError *error)
                        mono_error_set_bad_image (error, image,"Bad token table for dynamic image: %x", table);
                        return NULL;
                }
 -              klass = (MonoClass *)mono_lookup_dynamic_token (image, type_token, NULL); /*FIXME proper error handling*/
 +              klass = (MonoClass *)mono_lookup_dynamic_token (image, type_token, NULL, error);
                goto done;
        }
  
@@@ -7479,7 -7490,7 +7486,7 @@@ done
   *
   * 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
 + * Returns: The MonoType that represents @type_token in @image
   */
  MonoType *
  mono_type_get_checked (MonoImage *image, guint32 type_token, MonoGenericContext *context, MonoError *error)
        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 ((MonoClass *)mono_lookup_dynamic_token (image, type_token, context));
 +      if (image_is_dynamic (image)) {
 +              MonoClass *klass = (MonoClass *)mono_lookup_dynamic_token (image, type_token, context, error);
 +              return_val_if_nok (error, NULL);
 +              return mono_class_get_type (klass);
 +      }
  
        if ((type_token & 0xff000000) != MONO_TOKEN_TYPE_SPEC) {
                MonoClass *klass = mono_class_get_checked (image, type_token, error);
  
                if (!klass) {
 -                      mono_loader_assert_no_error ();
                        return NULL;
                }
  
        type = mono_type_retrieve_from_typespec (image, type_token, context, &inflated, error);
  
        if (!type) {
 -              mono_loader_assert_no_error ();
                return NULL;
        }
  
        return type;
  }
  
 -
 +/**
 + * mono_class_get:
 + * @image: image where the class token will be looked up.
 + * @type_token: a type token from the image
 + *
 + * Returns the MonoClass with the given @type_token on the @image
 + */
  MonoClass *
  mono_class_get (MonoImage *image, guint32 type_token)
  {
@@@ -7690,7 -7694,7 +7697,7 @@@ find_nocase (gpointer key, gpointer val
   * @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
 + * @deprecated: use the mono_class_from_name_case_checked variant instead.
   *
   * Obtains a MonoClass with a given namespace and a given name which
   * is located in the given MonoImage.   The namespace and name
@@@ -7701,28 -7705,12 +7708,28 @@@ mono_class_from_name_case (MonoImage *i
  {
        MonoError error;
        MonoClass *res = mono_class_from_name_case_checked (image, name_space, name, &error);
 -      g_assert (!mono_error_ok (&error));
 +      mono_error_cleanup (&error);
 +
        return res;
  }
  
 +/**
 + * mono_class_from_name_case:
 + * @image: The MonoImage where the type is looked up in
 + * @name_space: the type namespace
 + * @name: the type short name.
 + * @error: if 
 + *
 + * Obtains a MonoClass with a given namespace and a given name which
 + * is located in the given MonoImage.   The namespace and name
 + * lookups are case insensitive.
 + *
 + * Returns: The MonoClass if the given namespace and name were found, or NULL if it
 + * was not found.   The @error object will contain information about the problem
 + * in that case.
 + */
  MonoClass *
 -mono_class_from_name_case_checked (MonoImage *image, const charname_space, const char *name, MonoError *error)
 +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];
@@@ -7805,15 -7793,13 +7812,15 @@@ return_nested_in (MonoClass *klass, cha
  }
  
  static MonoClass*
 -search_modules (MonoImage *image, const char *name_space, const char *name)
 +search_modules (MonoImage *image, const char *name_space, const char *name, MonoError *error)
  {
        MonoTableInfo *file_table = &image->tables [MONO_TABLE_FILE];
        MonoImage *file_image;
        MonoClass *klass;
        int i;
  
 +      mono_error_init (error);
 +
        /* 
         * The EXPORTEDTYPES table only contains public types, so have to search the
         * modules as well.
                if (cols [MONO_FILE_FLAGS] == FILE_CONTAINS_NO_METADATA)
                        continue;
  
 -              file_image = mono_image_load_file_for_image (image, i + 1);
 +              file_image = mono_image_load_file_for_image_checked (image, i + 1, error);
                if (file_image) {
 -                      klass = mono_class_from_name (file_image, name_space, name);
 -                      if (klass)
 +                      klass = mono_class_from_name_checked (file_image, name_space, name, error);
 +                      if (klass || !is_ok (error))
                                return klass;
                }
        }
  }
  
  static MonoClass *
 -mono_class_from_name_checked_aux (MonoImage *image, const char* name_space, const char *name, MonoError *error, GHashTable* visited_images)
 +mono_class_from_name_checked_aux (MonoImage *image, const char* name_space, const char *name, GHashTable* visited_images, MonoError *error)
  {
        GHashTable *nspace_table;
        MonoImage *loaded_image;
        if (get_class_from_name && image->tables [MONO_TABLE_EXPORTEDTYPE].rows == 0) {
                gboolean res = get_class_from_name (image, name_space, name, &klass);
                if (res) {
 -                      if (!klass)
 -                              klass = search_modules (image, name_space, name);
 +                      if (!klass) {
 +                              klass = search_modules (image, name_space, name, error);
 +                              if (!is_ok (error))
 +                                      return NULL;
 +                      }
                        if (nested)
                                return klass ? return_nested_in (klass, nested) : NULL;
                        else
                for (i = 0; i < image->module_count; ++i) {
                        MonoImage *module = image->modules [i];
  
 -                      klass = mono_class_from_name (module, name_space, name);
 -                      if (klass)
 +                      klass = mono_class_from_name_checked (module, name_space, name, error);
 +                      if (klass || !is_ok (error))
                                return klass;
                }
        }
  
        if (!token) {
 -              klass = search_modules (image, name_space, name);
 -              if (klass)
 +              klass = search_modules (image, name_space, name, error);
 +              if (klass || !is_ok (error))
                        return klass;
 -      }
 -
 -      if (!token)
                return NULL;
 +      }
  
        if (mono_metadata_token_table (token) == MONO_TABLE_EXPORTEDTYPE) {
                MonoTableInfo  *t = &image->tables [MONO_TABLE_EXPORTEDTYPE];
  
                impl = cols [MONO_EXP_TYPE_IMPLEMENTATION];
                if ((impl & MONO_IMPLEMENTATION_MASK) == MONO_IMPLEMENTATION_FILE) {
 -                      loaded_image = mono_assembly_load_module (image->assembly, impl >> MONO_IMPLEMENTATION_BITS);
 +                      loaded_image = mono_assembly_load_module_checked (image->assembly, impl >> MONO_IMPLEMENTATION_BITS, error);
                        if (!loaded_image)
                                return NULL;
 -                      klass = mono_class_from_name_checked_aux (loaded_image, name_space, name, error, visited_images);
 +                      klass = mono_class_from_name_checked_aux (loaded_image, name_space, name, visited_images, error);
                        if (nested)
                                return klass ? return_nested_in (klass, nested) : NULL;
                        return klass;
                        g_assert (image->references [assembly_idx - 1]);
                        if (image->references [assembly_idx - 1] == (gpointer)-1)
                                return NULL;                    
 -                      klass = mono_class_from_name_checked_aux (image->references [assembly_idx - 1]->image, name_space, name, error, visited_images);
 +                      klass = mono_class_from_name_checked_aux (image->references [assembly_idx - 1]->image, name_space, name, visited_images, error);
                        if (nested)
 -                              return return_nested_in (klass, nested);
 +                              return klass ? return_nested_in (klass, nested) : NULL;
                        return klass;
                } else {
                        g_assert_not_reached ();
        return klass;
  }
  
 +/**
 + * mono_class_from_name_checked:
 + * @image: The MonoImage where the type is looked up in
 + * @name_space: the type namespace
 + * @name: the type short name.
 + *
 + * Obtains a MonoClass with a given namespace and a given name which
 + * is located in the given MonoImage.
 + *
 + * Works like mono_class_from_name, but error handling is tricky. It can return NULL and have no error
 + * set if the class was not found or it will return NULL and set the error if there was a loading error.
 + */
  MonoClass *
  mono_class_from_name_checked (MonoImage *image, const char* name_space, const char *name, MonoError *error)
  {
  
        visited_images = g_hash_table_new (g_direct_hash, g_direct_equal);
  
 -      klass = mono_class_from_name_checked_aux (image, name_space, name, error, visited_images);
 +      klass = mono_class_from_name_checked_aux (image, name_space, name, visited_images, error);
  
        g_hash_table_destroy (visited_images);
  
@@@ -8002,61 -7975,13 +8009,61 @@@ mono_class_from_name (MonoImage *image
        MonoClass *klass;
  
        klass = mono_class_from_name_checked (image, name_space, name, &error);
 -      if (!mono_error_ok (&error)) {
 -              mono_loader_set_error_from_mono_error (&error);
 -              mono_error_cleanup (&error); /* FIXME Don't swallow the error */
 -      }
 +      mono_error_cleanup (&error); /* FIXME Don't swallow the error */
 +
 +      return klass;
 +}
 +
 +/**
 + * mono_class_load_from_name:
 + * @image: The MonoImage where the type is looked up in
 + * @name_space: the type namespace
 + * @name: the type short name.
 + *
 + * This function works exactly like mono_class_from_name but it will abort if the class is not found.
 + * This function should be used by the runtime for critical types to which there's no way to recover but crash
 + * If they are missing. Thing of System.Object or System.String.
 + */
 +MonoClass *
 +mono_class_load_from_name (MonoImage *image, const char* name_space, const char *name)
 +{
 +      MonoError error;
 +      MonoClass *klass;
 +
 +      klass = mono_class_from_name_checked (image, name_space, name, &error);
 +      if (!klass)
 +              g_error ("Runtime critical type %s.%s not found", name_space, name);
 +      if (!mono_error_ok (&error))
 +              g_error ("Could not load runtime critical type %s.%s due to %s", name_space, name, mono_error_get_message (&error));
 +      return klass;
 +}
 +
 +/**
 + * mono_class_try_load_from_name:
 + * @image: The MonoImage where the type is looked up in
 + * @name_space: the type namespace
 + * @name: the type short name.
 + *
 + * This function tries to load a type, returning the class was found or NULL otherwise.
 + * This function should be used by the runtime when probing for optional types, those that could have being linked out.
 + *
 + * Big design consideration. This function aborts if there was an error loading the type. This prevents us from missing
 + * a type that we would otherwise assume to be available but was not due some error.
 + *
 + */
 +MonoClass*
 +mono_class_try_load_from_name (MonoImage *image, const char* name_space, const char *name)
 +{
 +      MonoError error;
 +      MonoClass *klass;
 +
 +      klass = mono_class_from_name_checked (image, name_space, name, &error);
 +      if (!mono_error_ok (&error))
 +              g_error ("Could not load runtime critical type %s.%s due to %s", name_space, name, mono_error_get_message (&error));
        return klass;
  }
  
 +
  /**
   * mono_class_is_subclass_of:
   * @klass: class to probe if it is a subclass of another one
   * This method determines whether @klass is a subclass of @klassc.
   *
   * If the @check_interfaces flag is set, then if @klassc is an interface
 - * this method return true if the @klass implements the interface or
 + * this method return TRUE if the @klass implements the interface or
   * if @klass is an interface, if one of its base classes is @klass.
   *
   * If @check_interfaces is false then, then if @klass is not an interface
 - * then it returns true if the @klass is a subclass of @klassc.
 + * then it returns TRUE if the @klass is a subclass of @klassc.
   *
   * if @klass is an interface and @klassc is System.Object, then this function
   * return true.
@@@ -8080,9 -8005,7 +8087,9 @@@ gboolea
  mono_class_is_subclass_of (MonoClass *klass, MonoClass *klassc, 
                           gboolean check_interfaces)
  {
 -/*FIXME test for interfaces with variant generic arguments*/
 +      /* FIXME test for interfaces with variant generic arguments */
 +      mono_class_init (klass);
 +      mono_class_init (klassc);
        
        if (check_interfaces && MONO_CLASS_IS_INTERFACE (klassc) && !MONO_CLASS_IS_INTERFACE (klass)) {
                if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, klassc->interface_id))
@@@ -8122,10 -8045,10 +8129,10 @@@ mono_class_has_variant_generic_params (
        int i;
        MonoGenericContainer *container;
  
 -      if (!klass->generic_class)
 +      if (!mono_class_is_ginst (klass))
                return FALSE;
  
 -      container = klass->generic_class->container_class->generic_container;
 +      container = mono_class_get_generic_container (mono_class_get_generic_class (klass)->container_class);
  
        for (i = 0; i < container->type_argc; ++i)
                if (mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT))
@@@ -8159,9 -8082,8 +8166,9 @@@ mono_gparam_is_reference_conversible (M
   * @klass: the class to be assigned to
   * @oklass: the source class
   * 
 - * Both klass and oklass must be instances of the same generic interface.
 - * Return true if @klass can be assigned to a @klass variable
 + * Both @klass and @oklass must be instances of the same generic interface.
 + *
 + * Returns: TRUE if @klass can be assigned to a @klass variable
   */
  gboolean
  mono_class_is_variant_compatible (MonoClass *klass, MonoClass *oklass, gboolean check_for_reference_conv)
        int j;
        MonoType **klass_argv, **oklass_argv;
        MonoClass *klass_gtd = mono_class_get_generic_type_definition (klass);
 -      MonoGenericContainer *container = klass_gtd->generic_container;
 +      MonoGenericContainer *container = mono_class_get_generic_container (klass_gtd);
  
        if (klass == oklass)
                return TRUE;
        if (mono_class_get_generic_type_definition (oklass) != klass_gtd || oklass == klass_gtd)
                return FALSE;
  
 -      klass_argv = &klass->generic_class->context.class_inst->type_argv [0];
 -      oklass_argv = &oklass->generic_class->context.class_inst->type_argv [0];
 +      klass_argv = &mono_class_get_generic_class (klass)->context.class_inst->type_argv [0];
 +      oklass_argv = &mono_class_get_generic_class (oklass)->context.class_inst->type_argv [0];
  
        for (j = 0; j < container->type_argc; ++j) {
                MonoClass *param1_class = mono_class_from_mono_type (klass_argv [j]);
@@@ -8312,13 -8234,12 +8319,13 @@@ mono_gparam_is_assignable_from (MonoCla
   * @klass: the class to be assigned to
   * @oklass: the source class
   *
 - * Return: true if an instance of object oklass can be assigned to an
 + * Returns: TRUE if an instance of object oklass can be assigned to an
   * instance of object @klass
   */
  gboolean
  mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass)
  {
 +      MonoError error;
        /*FIXME this will cause a lot of irrelevant stuff to be loaded.*/
        if (!klass->inited)
                mono_class_init (klass);
        if (!oklass->inited)
                mono_class_init (oklass);
  
 -      if (klass->exception_type || oklass->exception_type)
 +      if (mono_class_has_failure (klass) || mono_class_has_failure  (oklass))
                return FALSE;
  
        if (mono_type_is_generic_argument (&klass->byval_arg)) {
                }
  
                /* interface_offsets might not be set for dynamic classes */
 -              if (oklass->ref_info_handle && !oklass->interface_bitmap)
 +              if (oklass->ref_info_handle && !oklass->interface_bitmap) {
                        /* 
                         * oklass might be a generic type parameter but they have 
                         * interface_offsets set.
                         */
 -                      return mono_reflection_call_is_assignable_to (oklass, klass);
 +                      gboolean result = mono_reflection_call_is_assignable_to (oklass, klass, &error);
 +                      if (!is_ok (&error)) {
 +                              mono_error_cleanup (&error);
 +                              return FALSE;
 +                      }
 +                      return result;
 +              }
                if (!oklass->interface_bitmap)
                        /* Happens with generic instances of not-yet created dynamic types */
                        return FALSE;
                        return TRUE;
  
                if (mono_class_has_variant_generic_params (klass)) {
 -                      MonoError error;
                        int i;
                        mono_class_setup_interfaces (oklass, &error);
                        if (!mono_error_ok (&error)) {
@@@ -8434,14 -8350,14 +8441,14 @@@ mono_class_is_variant_compatible_slow (
        int j;
        MonoType **klass_argv, **oklass_argv;
        MonoClass *klass_gtd = mono_class_get_generic_type_definition (klass);
 -      MonoGenericContainer *container = klass_gtd->generic_container;
 +      MonoGenericContainer *container = mono_class_get_generic_container (klass_gtd);
  
        /*Viable candidates are instances of the same generic interface*/
        if (mono_class_get_generic_type_definition (oklass) != klass_gtd || oklass == klass_gtd)
                return FALSE;
  
 -      klass_argv = &klass->generic_class->context.class_inst->type_argv [0];
 -      oklass_argv = &oklass->generic_class->context.class_inst->type_argv [0];
 +      klass_argv = &mono_class_get_generic_class (klass)->context.class_inst->type_argv [0];
 +      oklass_argv = &mono_class_get_generic_class (oklass)->context.class_inst->type_argv [0];
  
        for (j = 0; j < container->type_argc; ++j) {
                MonoClass *param1_class = mono_class_from_mono_type (klass_argv [j]);
@@@ -8592,7 -8508,7 +8599,7 @@@ mono_class_is_assignable_from_slow (Mon
   * mono_class_get_cctor:
   * @klass: A MonoClass pointer
   *
 - * Returns: the static constructor of @klass if it exists, NULL otherwise.
 + * Returns: The static constructor of @klass if it exists, NULL otherwise.
   */
  MonoMethod*
  mono_class_get_cctor (MonoClass *klass)
                return result;
        }
  
 -      if (klass->generic_class && !klass->methods)
 -              return mono_class_get_inflated_method (klass, mono_class_get_cctor (klass->generic_class->container_class));
 +      if (mono_class_is_ginst (klass) && !klass->methods)
 +              return mono_class_get_inflated_method (klass, mono_class_get_cctor (mono_class_get_generic_class (klass)->container_class));
  
        return mono_class_get_method_from_name_flags (klass, ".cctor", -1, METHOD_ATTRIBUTE_SPECIAL_NAME);
  }
   * mono_class_get_finalizer:
   * @klass: The MonoClass pointer
   *
 - * Returns: the finalizer method of @klass if it exists, NULL otherwise.
 + * Returns: The finalizer method of @klass if it exists, NULL otherwise.
   */
  MonoMethod*
  mono_class_get_finalizer (MonoClass *klass)
@@@ -8676,7 -8592,7 +8683,7 @@@ mono_class_needs_cctor_run (MonoClass *
   * mono_class_array_element_size:
   * @klass: 
   *
 - * Returns: the number of bytes an element of type @klass
 + * Returns: The number of bytes an element of type @klass
   * uses when stored into an array.
   */
  gint32
@@@ -8740,7 -8656,7 +8747,7 @@@ handle_enum
   * mono_array_element_size:
   * @ac: pointer to a #MonoArrayClass
   *
 - * Returns: the size of single array element.
 + * Returns: The size of single array element.
   */
  gint32
  mono_array_element_size (MonoClass *ac)
@@@ -8767,9 -8683,8 +8774,9 @@@ mono_ldtoken_checked (MonoImage *image
  
        if (image_is_dynamic (image)) {
                MonoClass *tmp_handle_class;
 -              gpointer obj = mono_lookup_dynamic_token_class (image, token, TRUE, &tmp_handle_class, context);
 +              gpointer obj = mono_lookup_dynamic_token_class (image, token, TRUE, &tmp_handle_class, context, error);
  
 +              mono_error_assert_ok (error);
                g_assert (tmp_handle_class);
                if (handle_class)
                        *handle_class = tmp_handle_class;
        return NULL;
  }
  
 -/**
 - * This function might need to call runtime functions so it can't be part
 - * of the metadata library.
 - */
 -static MonoLookupDynamicToken lookup_dynamic = NULL;
 -
 -void
 -mono_install_lookup_dynamic_token (MonoLookupDynamicToken func)
 -{
 -      lookup_dynamic = func;
 -}
 -
  gpointer
 -mono_lookup_dynamic_token (MonoImage *image, guint32 token, MonoGenericContext *context)
 +mono_lookup_dynamic_token (MonoImage *image, guint32 token, MonoGenericContext *context, MonoError *error)
  {
        MonoClass *handle_class;
 -
 -      return lookup_dynamic (image, token, TRUE, &handle_class, context);
 +      mono_error_init (error);
 +      return mono_reflection_lookup_dynamic_token (image, token, TRUE, &handle_class, context, error);
  }
  
  gpointer
 -mono_lookup_dynamic_token_class (MonoImage *image, guint32 token, gboolean valid_token, MonoClass **handle_class, MonoGenericContext *context)
 +mono_lookup_dynamic_token_class (MonoImage *image, guint32 token, gboolean valid_token, MonoClass **handle_class, MonoGenericContext *context, MonoError *error)
  {
 -      return lookup_dynamic (image, token, valid_token, handle_class, context);
 +      return mono_reflection_lookup_dynamic_token (image, token, valid_token, handle_class, context, error);
  }
  
  static MonoGetCachedClassInfo get_cached_class_info = NULL;
@@@ -8886,13 -8813,6 +8893,13 @@@ mono_install_get_class_from_name (MonoG
        get_class_from_name = func;
  }
  
 +/**
 + * mono_class_get_image:
 + *
 + * Use this method to get the `MonoImage*` where this class came from.
 + *
 + * Returns: The image where this class is defined.
 + */
  MonoImage*
  mono_class_get_image (MonoClass *klass)
  {
   * mono_class_get_element_class:
   * @klass: the MonoClass to act on
   *
 - * Returns: the element class of an array or an enumeration.
 + * Use this function to get the element class of an array.
 + *
 + * Returns: The element class of an array.
   */
  MonoClass*
  mono_class_get_element_class (MonoClass *klass)
   * mono_class_is_valuetype:
   * @klass: the MonoClass to act on
   *
 - * Returns: true if the MonoClass represents a ValueType.
 + * Use this method to determine if the provided `MonoClass*` represents a value type,
 + * or a reference type.
 + *
 + * Returns: TRUE if the MonoClass represents a ValueType, FALSE if it represents a reference type.
   */
  gboolean
  mono_class_is_valuetype (MonoClass *klass)
   * mono_class_is_enum:
   * @klass: the MonoClass to act on
   *
 - * Returns: true if the MonoClass represents an enumeration.
 + * Use this function to determine if the provided `MonoClass*` represents an enumeration.
 + *
 + * Returns: TRUE if the MonoClass represents an enumeration.
   */
  gboolean
  mono_class_is_enum (MonoClass *klass)
   * mono_class_enum_basetype:
   * @klass: the MonoClass to act on
   *
 - * Returns: the underlying type representation for an enumeration.
 + * Use this function to get the underlying type for an enumeration value.
 + * 
 + * Returns: The underlying type representation for an enumeration.
   */
  MonoType*
  mono_class_enum_basetype (MonoClass *klass)
   * mono_class_get_parent
   * @klass: the MonoClass to act on
   *
 - * Returns: the parent class for this class.
 + * Returns: The parent class for this class.
   */
  MonoClass*
  mono_class_get_parent (MonoClass *klass)
  }
  
  /**
 - * mono_class_get_nesting_type;
 + * mono_class_get_nesting_type:
   * @klass: the MonoClass to act on
   *
 - * Returns: the container type where this type is nested or NULL if this type is not a nested type.
 + * Use this function to obtain the class that the provided `MonoClass*` is nested on.
 + *
 + * If the return is NULL, this indicates that this class is not nested.
 + *
 + * Returns: The container type where this type is nested or NULL if this type is not a nested type.
   */
  MonoClass*
  mono_class_get_nesting_type (MonoClass *klass)
   * mono_class_get_rank:
   * @klass: the MonoClass to act on
   *
 - * Returns: the rank for the array (the number of dimensions).
 + * Returns: The rank for the array (the number of dimensions).
   */
  int
  mono_class_get_rank (MonoClass *klass)
        return klass->rank;
  }
  
 -/**
 - * mono_class_get_flags:
 - * @klass: the MonoClass to act on
 - *
 - * The type flags from the TypeDef table from the metadata.
 - * see the TYPE_ATTRIBUTE_* definitions on tabledefs.h for the
 - * different values.
 - *
 - * Returns: the flags from the TypeDef table.
 - */
 -guint32
 -mono_class_get_flags (MonoClass *klass)
 -{
 -      return klass->flags;
 -}
 -
  /**
   * mono_class_get_name
   * @klass: the MonoClass to act on
   *
 - * Returns: the name of the class.
 + * Returns: The name of the class.
   */
  const char*
  mono_class_get_name (MonoClass *klass)
   * mono_class_get_namespace:
   * @klass: the MonoClass to act on
   *
 - * Returns: the namespace of the class.
 + * Returns: The namespace of the class.
   */
  const char*
  mono_class_get_namespace (MonoClass *klass)
   *
   * This method returns the internal Type representation for the class.
   *
 - * Returns: the MonoType from the class.
 + * Returns: The MonoType from the class.
   */
  MonoType*
  mono_class_get_type (MonoClass *klass)
  }
  
  /**
 - * mono_class_get_type_token
 + * mono_class_get_type_token:
   * @klass: the MonoClass to act on
   *
   * This method returns type token for the class.
   *
 - * Returns: the type token for the class.
 + * Returns: The type token for the class.
   */
  guint32
  mono_class_get_type_token (MonoClass *klass)
@@@ -9068,7 -8991,7 +9075,7 @@@ mono_class_get_byref_type (MonoClass *k
   * mono_class_num_fields:
   * @klass: the MonoClass to act on
   *
 - * Returns: the number of static and instance fields in the class.
 + * Returns: The number of static and instance fields in the class.
   */
  int
  mono_class_num_fields (MonoClass *klass)
   * mono_class_num_methods:
   * @klass: the MonoClass to act on
   *
 - * Returns: the number of methods in the class.
 + * Returns: The number of methods in the class.
   */
  int
  mono_class_num_methods (MonoClass *klass)
   * mono_class_num_properties
   * @klass: the MonoClass to act on
   *
 - * Returns: the number of properties in the class.
 + * Returns: The number of properties in the class.
   */
  int
  mono_class_num_properties (MonoClass *klass)
   * mono_class_num_events:
   * @klass: the MonoClass to act on
   *
 - * Returns: the number of events in the class.
 + * Returns: The number of events in the class.
   */
  int
  mono_class_num_events (MonoClass *klass)
@@@ -9135,8 -9058,8 +9142,8 @@@ mono_class_get_fields (MonoClass* klass
        if (!iter)
                return NULL;
        if (!*iter) {
 -              mono_class_setup_fields_locking (klass);
 -              if (klass->exception_type)
 +              mono_class_setup_fields (klass);
 +              if (mono_class_has_failure (klass))
                        return NULL;
                /* start from the first */
                if (klass->field.count) {
@@@ -9251,12 -9174,11 +9258,12 @@@ mono_class_get_virtual_methods (MonoCla
                        start_index = GPOINTER_TO_UINT (*iter);
                }
  
 +              int first_idx = mono_class_get_first_method_idx (klass);
                for (i = start_index; i < klass->method.count; ++i) {
                        guint32 flags;
  
 -                      /* klass->method.first points into the methodptr table */
 -                      flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, klass->method.first + i, MONO_METHOD_FLAGS);
 +                      /* first_idx points into the methodptr table */
 +                      flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, first_idx + i, MONO_METHOD_FLAGS);
  
                        if (flags & METHOD_ATTRIBUTE_VIRTUAL)
                                break;
  
                if (i < klass->method.count) {
                        MonoError error;
 -                      res = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | (klass->method.first + i + 1), klass, NULL, &error);
 +                      res = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | (first_idx + i + 1), klass, NULL, &error);
                        mono_error_cleanup (&error); /* FIXME don't swallow the error */
  
                        /* Add 1 here so the if (*iter) check fails */
@@@ -9498,7 -9420,7 +9505,7 @@@ mono_class_get_nested_types (MonoClass
   * mono_class_is_delegate
   * @klass: the MonoClass to act on
   *
 - * Returns: true if the MonoClass represents a System.Delegate.
 + * Returns: TRUE if the MonoClass represents a System.Delegate.
   */
  mono_bool
  mono_class_is_delegate (MonoClass *klass)
   * @klass: The MonoClass to act on
   * @interface: The interface to check if @klass implements.
   *
 - * Returns: true if @klass implements @interface.
 + * Returns: TRUE if @klass implements @interface.
   */
  mono_bool
  mono_class_implements_interface (MonoClass* klass, MonoClass* iface)
   * mono_field_get_name:
   * @field: the MonoClassField to act on
   *
 - * Returns: the name of the field.
 + * Returns: The name of the field.
   */
  const char*
  mono_field_get_name (MonoClassField *field)
@@@ -9585,7 -9507,7 +9592,7 @@@ mono_field_get_parent (MonoClassField *
   * The metadata flags for a field are encoded using the
   * FIELD_ATTRIBUTE_* constants.  See the tabledefs.h file for details.
   *
 - * Returns: the flags for the field.
 + * Returns: The flags for the field.
   */
  guint32
  mono_field_get_flags (MonoClassField *field)
  }
  
  /**
 - * mono_field_get_offset;
 + * mono_field_get_offset:
   * @field: the MonoClassField to act on
   *
 - * Returns: the field offset.
 + * Returns: The field offset.
   */
  guint32
  mono_field_get_offset (MonoClassField *field)
@@@ -9631,8 -9553,7 +9638,8 @@@ mono_field_get_rva (MonoClassField *fie
        field_index = mono_field_get_index (field);
                
        if (!klass->ext->field_def_values [field_index].data && !image_is_dynamic (klass->image)) {
 -              mono_metadata_field_info (field->parent->image, klass->field.first + field_index, NULL, &rva, NULL);
 +              int first_field_idx = mono_class_get_first_field_idx (klass);
 +              mono_metadata_field_info (field->parent->image, first_field_idx + field_index, NULL, &rva, NULL);
                if (!rva)
                        g_warning ("field %s in %s should have RVA data, but hasn't", mono_field_get_name (field), field->parent->name);
                klass->ext->field_def_values [field_index].data = mono_image_rva_map (field->parent->image, rva);
  }
  
  /**
 - * mono_field_get_data;
 + * mono_field_get_data:
   * @field: the MonoClassField to act on
   *
 - * Returns: pointer to the metadata constant value or to the field
 + * Returns: pointer to the metadata constant value or to the field
   * data if it has an RVA flag.
   */
  const char *
@@@ -9666,7 -9587,7 +9673,7 @@@ mono_field_get_data (MonoClassField *fi
   * mono_property_get_name: 
   * @prop: the MonoProperty to act on
   *
 - * Returns: the name of the property
 + * Returns: The name of the property
   */
  const char*
  mono_property_get_name (MonoProperty *prop)
   * mono_property_get_set_method
   * @prop: the MonoProperty to act on.
   *
 - * Returns: the setter method of the property (A MonoMethod)
 + * Returns: The setter method of the property (A MonoMethod)
   */
  MonoMethod*
  mono_property_get_set_method (MonoProperty *prop)
   * mono_property_get_get_method
   * @prop: the MonoProperty to act on.
   *
 - * Returns: the setter method of the property (A MonoMethod)
 + * Returns: The setter method of the property (A MonoMethod)
   */
  MonoMethod*
  mono_property_get_get_method (MonoProperty *prop)
   * mono_property_get_parent:
   * @prop: the MonoProperty to act on.
   *
 - * Returns: the MonoClass where the property was defined.
 + * Returns: The MonoClass where the property was defined.
   */
  MonoClass*
  mono_property_get_parent (MonoProperty *prop)
   * The metadata flags for a property are encoded using the
   * PROPERTY_ATTRIBUTE_* constants.  See the tabledefs.h file for details.
   *
 - * Returns: the flags for the property.
 + * Returns: The flags for the property.
   */
  guint32
  mono_property_get_flags (MonoProperty *prop)
   * mono_event_get_name:
   * @event: the MonoEvent to act on
   *
 - * Returns: the name of the event.
 + * Returns: The name of the event.
   */
  const char*
  mono_event_get_name (MonoEvent *event)
   * mono_event_get_add_method:
   * @event: The MonoEvent to act on.
   *
 - * Returns: the @add' method for the event (a MonoMethod).
 + * Returns: The @add' method for the event (a MonoMethod).
   */
  MonoMethod*
  mono_event_get_add_method (MonoEvent *event)
   * mono_event_get_remove_method:
   * @event: The MonoEvent to act on.
   *
 - * Returns: the @remove method for the event (a MonoMethod).
 + * Returns: The @remove method for the event (a MonoMethod).
   */
  MonoMethod*
  mono_event_get_remove_method (MonoEvent *event)
   * mono_event_get_raise_method:
   * @event: The MonoEvent to act on.
   *
 - * Returns: the @raise method for the event (a MonoMethod).
 + * Returns: The @raise method for the event (a MonoMethod).
   */
  MonoMethod*
  mono_event_get_raise_method (MonoEvent *event)
   * mono_event_get_parent:
   * @event: the MonoEvent to act on.
   *
 - * Returns: the MonoClass where the event is defined.
 + * Returns: The MonoClass where the event is defined.
   */
  MonoClass*
  mono_event_get_parent (MonoEvent *event)
   * The metadata flags for an event are encoded using the
   * EVENT_* constants.  See the tabledefs.h file for details.
   *
 - * Returns: the flags for the event.
 + * Returns: The flags for the event.
   */
  guint32
  mono_event_get_flags (MonoEvent *event)
@@@ -9822,18 -9743,17 +9829,18 @@@ find_method_in_metadata (MonoClass *kla
        int i;
  
        /* Search directly in the metadata to avoid calling setup_methods () */
 +      int first_idx = mono_class_get_first_method_idx (klass);
        for (i = 0; i < klass->method.count; ++i) {
                MonoError error;
                guint32 cols [MONO_METHOD_SIZE];
                MonoMethod *method;
                MonoMethodSignature *sig;
  
 -              /* klass->method.first points into the methodptr table */
 -              mono_metadata_decode_table_row (klass->image, MONO_TABLE_METHOD, klass->method.first + i, cols, MONO_METHOD_SIZE);
 +              /* first_idx points into the methodptr table */
 +              mono_metadata_decode_table_row (klass->image, MONO_TABLE_METHOD, first_idx + i, cols, MONO_METHOD_SIZE);
  
                if (!strcmp (mono_metadata_string_heap (klass->image, cols [MONO_METHOD_NAME]), name)) {
 -                      method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | (klass->method.first + i + 1), klass, NULL, &error);
 +                      method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | (first_idx + i + 1), klass, NULL, &error);
                        if (!method) {
                                mono_error_cleanup (&error); /* FIXME don't swallow the error */
                                continue;
@@@ -9875,8 -9795,8 +9882,8 @@@ mono_class_get_method_from_name_flags (
  
        mono_class_init (klass);
  
 -      if (klass->generic_class && !klass->methods) {
 -              res = mono_class_get_method_from_name_flags (klass->generic_class->container_class, name, param_count, flags);
 +      if (mono_class_is_ginst (klass) && !klass->methods) {
 +              res = mono_class_get_method_from_name_flags (mono_class_get_generic_class (klass)->container_class, name, param_count, flags);
                if (res) {
                        MonoError error;
                        res = mono_class_inflate_generic_method_full_checked (res, klass, mono_class_get_context (klass), &error);
   *
   * LOCKING: Acquires the loader lock.
   */
 -gboolean
 -mono_class_set_failure (MonoClass *klass, guint32 ex_type, void *ex_data)
 +static gboolean
 +mono_class_set_failure (MonoClass *klass, MonoErrorBoxed *boxed_error)
  {
 -      if (klass->exception_type)
 +      g_assert (boxed_error != NULL);
 +
 +      if (mono_class_has_failure (klass))
                return FALSE;
  
        mono_loader_lock ();
 -      klass->exception_type = ex_type;
 -      if (ex_data)
 -              mono_image_property_insert (klass->image, klass, MONO_CLASS_PROP_EXCEPTION_DATA, ex_data);
 +      klass->has_failure = 1;
 +      mono_image_property_insert (klass->image, klass, MONO_CLASS_PROP_EXCEPTION_DATA, boxed_error);
        mono_loader_unlock ();
  
        return TRUE;
  }
  
 +gboolean
 +mono_class_has_failure (const MonoClass *klass)
 +{
 +      g_assert (klass != NULL);
 +      return klass->has_failure != 0;
 +}
 +
 +
 +/**
 + * mono_class_set_type_load_failure:
 + * @klass: class in which the failure was detected
 + * @fmt: Printf-style error message string.
 + *
 + * Collect detected failure informaion in the class for later processing.
 + * The error is stored as a MonoErrorBoxed as with mono_error_set_type_load_class ()
 + * Note that only the first failure is kept.
 + *
 + * Returns FALSE if a failure was already set on the class, or TRUE otherwise.
 + *
 + * LOCKING: Acquires the loader lock.
 + */
 +gboolean
 +mono_class_set_type_load_failure (MonoClass *klass, const char * fmt, ...)
 +{
 +      MonoError prepare_error;
 +      va_list args;
 +
 +      if (mono_class_has_failure (klass))
 +              return FALSE;
 +      
 +      mono_error_init (&prepare_error);
 +      
 +      va_start (args, fmt);
 +      mono_error_vset_type_load_class (&prepare_error, klass, fmt, args);
 +      va_end (args);
 +
 +      MonoErrorBoxed *box = mono_error_box (&prepare_error, klass->image);
 +      mono_error_cleanup (&prepare_error);
 +      return mono_class_set_failure (klass, box);
 +}
 +
  /*
   * mono_class_get_exception_data:
   *
   *
   * LOCKING: Acquires the loader lock.
   */
 -gpointer
 -mono_class_get_exception_data (MonoClass *klass)
 +static gpointer
 +mono_class_get_exception_data (const MonoClass *klass)
  {
 -      return mono_image_property_lookup (klass->image, klass, MONO_CLASS_PROP_EXCEPTION_DATA);
 +      return mono_image_property_lookup (klass->image, (MonoClass*)klass, MONO_CLASS_PROP_EXCEPTION_DATA);
  }
  
  /**
@@@ -10005,32 -9883,16 +10012,32 @@@ mono_classes_init (void
  {
        mono_os_mutex_init (&classes_mutex);
  
 +      mono_native_tls_alloc (&setup_fields_tls_id, NULL);
 +      mono_native_tls_alloc (&init_pending_tls_id, NULL);
 +
 +      mono_counters_register ("MonoClassDef count",
 +                                                      MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_def_count);
 +      mono_counters_register ("MonoClassGtd count",
 +                                                      MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_gtd_count);
 +      mono_counters_register ("MonoClassGenericInst count",
 +                                                      MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_ginst_count);
 +      mono_counters_register ("MonoClassGenericParam count",
 +                                                      MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_gparam_count);
 +      mono_counters_register ("MonoClassArray count",
 +                                                      MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_array_count);
 +      mono_counters_register ("MonoClassPointer count",
 +                                                      MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_pointer_count);
        mono_counters_register ("Inflated methods size",
                                                        MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_methods_size);
 -      mono_counters_register ("Inflated classes",
 -                                                      MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_classes);
        mono_counters_register ("Inflated classes size",
                                                        MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_classes_size);
        mono_counters_register ("MonoClass size",
                                                        MONO_COUNTER_METADATA | MONO_COUNTER_INT, &classes_size);
        mono_counters_register ("MonoClassExt size",
                                                        MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_ext_size);
 +
 +      mono_counters_register ("MonoClassExt count",
 +                                                      MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_ext_count);
  }
  
  /**
  void
  mono_classes_cleanup (void)
  {
 +      mono_native_tls_free (setup_fields_tls_id);
 +      mono_native_tls_free (init_pending_tls_id);
 +
        if (global_interface_bitset)
                mono_bitset_free (global_interface_bitset);
        global_interface_bitset = NULL;
  MonoException*
  mono_class_get_exception_for_failure (MonoClass *klass)
  {
 -      gpointer exception_data = mono_class_get_exception_data (klass);
 -
 -      switch (klass->exception_type) {
 -      case MONO_EXCEPTION_TYPE_LOAD: {
 -              MonoString *name;
 -              MonoException *ex;
 -              char *str = mono_type_get_full_name (klass);
 -              char *astr = klass->image->assembly? mono_stringify_assembly_name (&klass->image->assembly->aname): NULL;
 -              name = mono_string_new (mono_domain_get (), str);
 -              g_free (str);
 -              ex = mono_get_exception_type_load (name, astr);
 -              g_free (astr);
 -              return ex;
 -      }
 -      case MONO_EXCEPTION_MISSING_METHOD: {
 -              char *class_name = (char *)exception_data;
 -              char *assembly_name = class_name + strlen (class_name) + 1;
 -
 -              return mono_get_exception_missing_method (class_name, assembly_name);
 -      }
 -      case MONO_EXCEPTION_MISSING_FIELD: {
 -              char *class_name = (char *)exception_data;
 -              char *member_name = class_name + strlen (class_name) + 1;
 -
 -              return mono_get_exception_missing_field (class_name, member_name);
 -      }
 -      case MONO_EXCEPTION_FILE_NOT_FOUND: {
 -              char *msg_format = (char *)exception_data;
 -              char *assembly_name = msg_format + strlen (msg_format) + 1;
 -              char *msg = g_strdup_printf (msg_format, assembly_name);
 -              MonoException *ex;
 -
 -              ex = mono_get_exception_file_not_found2 (msg, mono_string_new (mono_domain_get (), assembly_name));
 -
 -              g_free (msg);
 -
 -              return ex;
 -      }
 -      case MONO_EXCEPTION_BAD_IMAGE: {
 -              return mono_get_exception_bad_image_format ((const char *)exception_data);
 -      }
 -      default: {
 -              MonoLoaderError *error;
 -              MonoException *ex;
 -              
 -              error = mono_loader_get_last_error ();
 -              if (error != NULL){
 -                      ex = mono_loader_error_prepare_exception (error);
 -                      return ex;
 -              }
 -              
 -              /* TODO - handle other class related failures */
 +      if (!mono_class_has_failure (klass))
                return NULL;
 -      }
 -      }
 +      MonoError unboxed_error;
 +      mono_error_init (&unboxed_error);
 +      mono_error_set_for_class_failure (&unboxed_error, klass);
 +      return mono_error_convert_to_exception (&unboxed_error);
  }
  
  static gboolean
@@@ -10085,8 -9993,7 +10092,8 @@@ is_nesting_type (MonoClass *outer_klass
  MonoClass *
  mono_class_get_generic_type_definition (MonoClass *klass)
  {
 -      return klass->generic_class ? klass->generic_class->container_class : klass;
 +      MonoGenericClass *gklass =  mono_class_try_get_generic_class (klass);
 +      return gklass ? gklass->container_class : klass;
  }
  
  /*
@@@ -10183,9 -10090,8 +10190,9 @@@ static MonoClass
  get_generic_definition_class (MonoClass *klass)
  {
        while (klass) {
 -              if (klass->generic_class && klass->generic_class->container_class)
 -                      return klass->generic_class->container_class;
 +              MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
 +              if (gklass && gklass->container_class)
 +                      return gklass->container_class;
                klass = klass->parent;
        }
        return NULL;
@@@ -10227,9 -10133,6 +10234,9 @@@ can_access_type (MonoClass *access_klas
  {
        int access_level;
  
 +      if (access_klass == member_klass)
 +              return TRUE;
 +
        if (access_klass->image->assembly && access_klass->image->assembly->corlib_internal)
                return TRUE;
  
        if (member_klass->element_class && !member_klass->enumtype)
                member_klass = member_klass->element_class;
  
 -      access_level = member_klass->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK;
 +      access_level = mono_class_get_flags (member_klass) & TYPE_ATTRIBUTE_VISIBILITY_MASK;
  
        if (member_klass->byval_arg.type == MONO_TYPE_VAR || member_klass->byval_arg.type == MONO_TYPE_MVAR)
                return TRUE;
  
 -      if (member_klass->generic_class && !can_access_instantiation (access_klass, member_klass->generic_class->context.class_inst))
 +      if (mono_class_is_ginst (member_klass) && !can_access_instantiation (access_klass, mono_class_get_generic_class (member_klass)->context.class_inst))
                return FALSE;
  
        if (is_nesting_type (access_klass, member_klass) || (access_klass->nested_in && is_nesting_type (access_klass->nested_in, member_klass)))
@@@ -10295,16 -10198,15 +10302,16 @@@ can_access_member (MonoClass *access_kl
        if (access_klass->image->assembly && access_klass->image->assembly->corlib_internal)
                return TRUE;
  
 -      if (((access_klass->generic_class && access_klass->generic_class->container_class) ||
 -                                      access_klass->generic_container) && 
 +      MonoGenericClass *access_gklass = mono_class_try_get_generic_class (access_klass);
 +      if (((access_gklass && access_gklass->container_class) ||
 +                                      mono_class_is_gtd (access_klass)) && 
                        (member_generic_def = get_generic_definition_class (member_klass))) {
                MonoClass *access_container;
  
 -              if (access_klass->generic_container)
 +              if (mono_class_is_gtd (access_klass))
                        access_container = access_klass;
                else
 -                      access_container = access_klass->generic_class->container_class;
 +                      access_container = access_gklass->container_class;
  
                if (can_access_member (access_container, member_generic_def, context_klass, access_level))
                        return TRUE;
        return FALSE;
  }
  
 +/**
 + * mono_method_can_access_field:
 + * @method: Method that will attempt to access the field
 + * @field: the field to access
 + *
 + * Used to determine if a method is allowed to access the specified field.
 + *
 + * Returns: TRUE if the given @method is allowed to access the @field while following
 + * the accessibility rules of the CLI.
 + */
  gboolean
  mono_method_can_access_field (MonoMethod *method, MonoClassField *field)
  {
        return can;
  }
  
 +/**
 + * mono_method_can_access_method:
 + * @method: Method that will attempt to access the other method
 + * @called: the method that we want to probe for accessibility.
 + *
 + * Used to determine if the @method is allowed to access the specified @called method.
 + *
 + * Returns: TRUE if the given @method is allowed to invoke the @called while following
 + * the accessibility rules of the CLI.
 + */
  gboolean
  mono_method_can_access_method (MonoMethod *method, MonoMethod *called)
  {
 -      int can = can_access_member (method->klass, called->klass, NULL, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
 -      if (!can) {
 -              MonoClass *nested = method->klass->nested_in;
 -              while (nested) {
 -                      can = can_access_member (nested, called->klass, NULL, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
 -                      if (can)
 -                              return TRUE;
 -                      nested = nested->nested_in;
 -              }
 -      }
 -      /* 
 -       * FIXME:
 -       * with generics calls to explicit interface implementations can be expressed
 -       * directly: the method is private, but we must allow it. This may be opening
 -       * a hole or the generics code should handle this differently.
 -       * Maybe just ensure the interface type is public.
 -       */
 -      if ((called->flags & METHOD_ATTRIBUTE_VIRTUAL) && (called->flags & METHOD_ATTRIBUTE_FINAL))
 -              return TRUE;
 -      return can;
 +      method = mono_method_get_method_definition (method);
 +      called = mono_method_get_method_definition (called);
 +      return mono_method_can_access_method_full (method, called, NULL);
  }
  
  /*
  gboolean
  mono_method_can_access_method_full (MonoMethod *method, MonoMethod *called, MonoClass *context_klass)
  {
 +      /* Wrappers are except from access checks */
 +      if (method->wrapper_type != MONO_WRAPPER_NONE || called->wrapper_type != MONO_WRAPPER_NONE)
 +              return TRUE;
 +
        MonoClass *access_class = method->klass;
        MonoClass *member_class = called->klass;
        int can = can_access_member (access_class, member_class, context_klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
@@@ -10542,9 -10437,7 +10549,9 @@@ gboolean mono_type_is_valid_enum_basety
   * FIXME: enum types are not allowed to have a cctor, but mono_reflection_create_runtime_class sets has_cctor to 1 for all types
   * FIXME: TypeBuilder enums can have any kind of static fields, but the spec is very explicit about that (P II 14.3)
   */
 -gboolean mono_class_is_valid_enum (MonoClass *klass) {
 +gboolean
 +mono_class_is_valid_enum (MonoClass *klass)
 +{
        MonoClassField * field;
        gpointer iter = NULL;
        gboolean found_base_field = FALSE;
                return FALSE;
        }
  
 -      if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) != TYPE_ATTRIBUTE_AUTO_LAYOUT)
 +      if (!mono_class_is_auto_layout (klass))
                return FALSE;
  
        while ((field = mono_class_get_fields (klass, &iter))) {
  gboolean
  mono_generic_class_is_generic_type_definition (MonoGenericClass *gklass)
  {
 -      return gklass->context.class_inst == gklass->container_class->generic_container->context.class_inst;
 +      return gklass->context.class_inst == mono_class_get_generic_container (gklass->container_class)->context.class_inst;
  }
  
  /*
@@@ -10618,7 -10511,6 +10625,7 @@@ mono_class_alloc_ext (MonoClass *klass
        if (!klass->ext)
                klass->ext = ext;
        class_ext_size += sizeof (MonoClassExt);
 +      ++class_ext_count;
        mono_image_unlock (klass->image);
  }
  
@@@ -10653,21 -10545,21 +10660,21 @@@ mono_class_setup_interfaces (MonoClass 
                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;
 +      } else if (mono_class_is_ginst (klass)) {
 +              MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
  
                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"));
 +                      mono_class_set_type_load_failure (klass, "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);
 +                      interfaces [i] = mono_class_inflate_generic_class_checked (gklass->interfaces [i], mono_generic_class_get_context (mono_class_get_generic_class (klass)), error);
                        if (!mono_error_ok (error)) {
 -                              mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Could not setup the interfaces"));
 +                              mono_class_set_type_load_failure (klass, "Could not setup the interfaces");
                                return;
                        }
                }
@@@ -10695,7 -10587,7 +10702,7 @@@ mono_field_resolve_type (MonoClassFiel
  {
        MonoClass *klass = field->parent;
        MonoImage *image = klass->image;
 -      MonoClass *gtd = klass->generic_class ? mono_class_get_generic_type_definition (klass) : NULL;
 +      MonoClass *gtd = mono_class_is_ginst (klass) ? mono_class_get_generic_type_definition (klass) : NULL;
        int field_idx = field - klass->fields;
  
        mono_error_init (error);
                MonoClassField *gfield = &gtd->fields [field_idx];
                MonoType *gtype = mono_field_get_type_checked (gfield, error);
                if (!mono_error_ok (error)) {
 -                      char *err_msg = g_strdup_printf ("Could not load field %d type due to: %s", field_idx, mono_error_get_message (error));
 -                      mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, err_msg);
 -                      g_free (err_msg);
 +                      char *full_name = mono_type_get_full_name (gtd);
 +                      mono_class_set_type_load_failure (klass, "Could not load generic type of field '%s:%s' (%d) due to: %s", full_name, gfield->name, field_idx, mono_error_get_message (error));
 +                      g_free (full_name);
                }
  
                field->type = mono_class_inflate_generic_type_no_copy (image, gtype, mono_class_get_context (klass), error);
                if (!mono_error_ok (error)) {
 -                      char *err_msg = g_strdup_printf ("Could not load field %d type due to: %s", field_idx, mono_error_get_message (error));
 -                      mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, err_msg);
 -                      g_free (err_msg);
 +                      char *full_name = mono_type_get_full_name (klass);
 +                      mono_class_set_type_load_failure (klass, "Could not load instantiated type of field '%s:%s' (%d) due to: %s", full_name, field->name, field_idx, mono_error_get_message (error));
 +                      g_free (full_name);
                }
        } else {
                const char *sig;
                guint32 cols [MONO_FIELD_SIZE];
                MonoGenericContainer *container = NULL;
 -              int idx = klass->field.first + field_idx;
 +              int idx = mono_class_get_first_field_idx (klass) + field_idx;
  
                /*FIXME, in theory we do not lazy load SRE fields*/
                g_assert (!image_is_dynamic (image));
  
 -              if (klass->generic_container) {
 -                      container = klass->generic_container;
 +              if (mono_class_is_gtd (klass)) {
 +                      container = mono_class_get_generic_container (klass);
                } else if (gtd) {
 -                      container = gtd->generic_container;
 +                      container = mono_class_get_generic_container (gtd);
                        g_assert (container);
                }
  
 -              /* klass->field.first and idx points into the fieldptr table */
 +              /* first_field_idx and idx points into the fieldptr table */
                mono_metadata_decode_table_row (image, MONO_TABLE_FIELD, idx, cols, MONO_FIELD_SIZE);
  
                if (!mono_verifier_verify_field_signature (image, cols [MONO_FIELD_SIGNATURE], NULL)) {
 -                      mono_error_set_type_load_class (error, klass, "Could not verify field %s signature", field->name);
 -                      mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
 +                      char *full_name = mono_type_get_full_name (klass);
 +                      mono_error_set_type_load_class (error, klass, "Could not verify field '%s:%s' signature", full_name, field->name);;
 +                      mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
 +                      g_free (full_name);
                        return;
                }
  
                mono_metadata_decode_value (sig, &sig);
                /* FIELD signature == 0x06 */
                g_assert (*sig == 0x06);
 -              field->type = mono_metadata_parse_type_full (image, container, cols [MONO_FIELD_FLAGS], sig + 1, &sig);
 -              if (!field->type)
 -                      mono_class_set_failure_from_loader_error (klass, error, g_strdup_printf ("Could not load field %s type", field->name));
 +
 +              field->type = mono_metadata_parse_type_checked (image, container, cols [MONO_FIELD_FLAGS], FALSE, sig + 1, &sig, error);
 +              if (!field->type) {
 +                      char *full_name = mono_type_get_full_name (klass);
 +                      mono_class_set_type_load_failure (klass, "Could not load type of field '%s:%s' (%d) due to: %s", full_name, field->name, field_idx, mono_error_get_message (error));
 +                      g_free (full_name);
 +              }
        }
  }
  
@@@ -10762,7 -10648,7 +10769,7 @@@ mono_field_resolve_flags (MonoClassFiel
  {
        MonoClass *klass = field->parent;
        MonoImage *image = klass->image;
 -      MonoClass *gtd = klass->generic_class ? mono_class_get_generic_type_definition (klass) : NULL;
 +      MonoClass *gtd = mono_class_is_ginst (klass) ? mono_class_get_generic_type_definition (klass) : NULL;
        int field_idx = field - klass->fields;
  
  
                MonoClassField *gfield = &gtd->fields [field_idx];
                return mono_field_get_flags (gfield);
        } else {
 -              int idx = klass->field.first + field_idx;
 +              int idx = mono_class_get_first_field_idx (klass) + field_idx;
  
                /*FIXME, in theory we do not lazy load SRE fields*/
                g_assert (!image_is_dynamic (image));
        }
  }
  
 -/**
 - * mono_class_setup_basic_field_info:
 - * @class: The class to initialize
 - *
 - * Initializes the klass->fields array of fields.
 - * Aquires the loader lock.
 - */
 -static void
 -mono_class_setup_basic_field_info_locking (MonoClass *klass)
 -{
 -      mono_loader_lock ();
 -      mono_class_setup_basic_field_info (klass);
 -      mono_loader_unlock ();
 -}
 -
  /**
   * mono_class_get_fields_lazy:
   * @klass: the MonoClass to act on
@@@ -10800,7 -10701,7 +10807,7 @@@ mono_class_get_fields_lazy (MonoClass* 
        if (!iter)
                return NULL;
        if (!*iter) {
 -              mono_class_setup_basic_field_info_locking (klass);
 +              mono_class_setup_basic_field_info (klass);
                if (!klass->fields)
                        return NULL;
                /* start from the first */
@@@ -10827,5 -10728,3 +10834,5 @@@ mono_class_full_name (MonoClass *klass
        return mono_type_full_name (&klass->byval_arg);
  }
  
 +/* Declare all shared lazy type lookup functions */
 +GENERATE_TRY_GET_CLASS_WITH_CACHE (safehandle, System.Runtime.InteropServices, SafeHandle)
diff --combined mono/metadata/marshal.c
index 4b02e7fb8b9fc2f987997d932452b6d1771c4671,711bede6320378668cbbe7b55e152a98a7b40254..a9674cc1aaf944357e8575c05b6d6a84de87b4a0
@@@ -8,7 -8,6 +8,7 @@@
   * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
   * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
   *
 + * Licensed under the MIT license. See LICENSE file in the project root for full license information.
   */
  
  #include "config.h"
@@@ -20,7 -19,6 +20,7 @@@
  #include "loader.h"
  #include "cil-coff.h"
  #include "metadata/marshal.h"
 +#include "metadata/marshal-internals.h"
  #include "metadata/method-builder.h"
  #include "metadata/tabledefs.h"
  #include "metadata/exception.h"
  #include "mono/metadata/remoting.h"
  #include "mono/metadata/reflection-internals.h"
  #include "mono/metadata/threadpool-ms.h"
 +#include "mono/metadata/handle.h"
  #include "mono/utils/mono-counters.h"
  #include "mono/utils/mono-tls.h"
  #include "mono/utils/mono-memory-model.h"
  #include "mono/utils/atomic.h"
  #include <mono/utils/mono-threads.h>
 +#include <mono/utils/mono-threads-coop.h>
 +#include <mono/utils/mono-error-internals.h>
  
  #include <string.h>
  #include <errno.h>
@@@ -82,23 -77,14 +82,23 @@@ static MonoNativeTlsKey load_type_info_
  
  static gboolean use_aot_wrappers;
  
 +static int class_marshal_info_count;
 +
 +static void ftnptr_eh_callback_default (guint32 gchandle);
 +
 +static MonoFtnPtrEHCallback ftnptr_eh_callback = ftnptr_eh_callback_default;
 +
  static void
  delegate_hash_table_add (MonoDelegate *d);
  
 +static void
 +delegate_hash_table_remove (MonoDelegate *d);
 +
  static void
  emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object);
  
  static void
 -emit_struct_conv_full (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object, MonoMarshalNative string_encoding);
 +emit_struct_conv_full (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object, int offset_of_first_child_field, MonoMarshalNative string_encoding);
  
  static void 
  mono_struct_delete_old (MonoClass *klass, char *ptr);
@@@ -110,7 -96,7 +110,7 @@@ static void 
  mono_marshal_string_to_utf16_copy (MonoString *s);
  
  static gpointer
 -mono_string_to_lpstr (MonoString *string_obj);
 +mono_string_to_utf8str (MonoString *string_obj);
  
  static MonoStringBuilder *
  mono_string_utf8_to_builder2 (char *text);
@@@ -153,91 -139,26 +153,91 @@@ mono_marshal_isinst_with_cache (MonoObj
  
  static void init_safe_handle (void);
  
 +static void*
 +ves_icall_marshal_alloc (gulong size);
 +
 +void
 +mono_string_utf8_to_builder (MonoStringBuilder *sb, char *text);
 +
 +void
 +mono_string_utf16_to_builder (MonoStringBuilder *sb, gunichar2 *text);
 +
 +gchar*
 +mono_string_builder_to_utf8 (MonoStringBuilder *sb);
 +
 +gunichar2*
 +mono_string_builder_to_utf16 (MonoStringBuilder *sb);
 +
 +void
 +mono_string_to_byvalstr (gpointer dst, MonoString *src, int size);
 +
 +void
 +mono_string_to_byvalwstr (gpointer dst, MonoString *src, int size);
 +
 +gpointer
 +mono_delegate_to_ftnptr (MonoDelegate *delegate);
 +
 +MonoDelegate*
 +mono_ftnptr_to_delegate (MonoClass *klass, gpointer ftn);
 +
 +gpointer
 +mono_array_to_savearray (MonoArray *array);
 +
 +gpointer
 +mono_array_to_lparray (MonoArray *array);
 +
 +void
 +mono_free_lparray (MonoArray *array, gpointer* nativeArray);
 +
 +gpointer
 +mono_marshal_asany (MonoObject *obj, MonoMarshalNative string_encoding, int param_attrs);
 +
 +void
 +mono_marshal_free_asany (MonoObject *o, gpointer ptr, MonoMarshalNative string_encoding, int param_attrs);
 +
 +gpointer
 +mono_array_to_savearray (MonoArray *array);
 +
 +gpointer
 +mono_array_to_lparray (MonoArray *array);
 +
 +void
 +mono_free_lparray (MonoArray *array, gpointer* nativeArray);
 +
 +static void
 +mono_marshal_ftnptr_eh_callback (guint32 gchandle);
 +
 +static MonoThreadInfo*
 +mono_icall_start (HandleStackMark *stackmark, MonoError *error);
 +
 +static void
 +mono_icall_end (MonoThreadInfo *info, HandleStackMark *stackmark, MonoError *error);
 +
 +/* Lazy class loading functions */
 +static GENERATE_GET_CLASS_WITH_CACHE (string_builder, System.Text, StringBuilder)
 +static GENERATE_GET_CLASS_WITH_CACHE (date_time, System, DateTime)
 +static GENERATE_TRY_GET_CLASS_WITH_CACHE (unmanaged_function_pointer_attribute, System.Runtime.InteropServices, UnmanagedFunctionPointerAttribute)
 +static GENERATE_TRY_GET_CLASS_WITH_CACHE (icustom_marshaler, System.Runtime.InteropServices, ICustomMarshaler)
 +
  /* MonoMethod pointers to SafeHandle::DangerousAddRef and ::DangerousRelease */
  static MonoMethod *sh_dangerous_add_ref;
  static MonoMethod *sh_dangerous_release;
  
 -
  static void
  init_safe_handle ()
  {
        sh_dangerous_add_ref = mono_class_get_method_from_name (
 -              mono_defaults.safehandle_class, "DangerousAddRef", 1);
 +              mono_class_try_get_safehandle_class (), "DangerousAddRef", 1);
        sh_dangerous_release = mono_class_get_method_from_name (
 -              mono_defaults.safehandle_class, "DangerousRelease", 0);
 +              mono_class_try_get_safehandle_class (), "DangerousRelease", 0);
  }
  
  static void
 -register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
 +register_icall (gpointer func, const char *name, const char *sigstr, gboolean no_wrapper)
  {
        MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
  
 -      mono_register_jit_icall (func, name, sig, save);
 +      mono_register_jit_icall (func, name, sig, no_wrapper);
  }
  
  MonoMethodSignature*
@@@ -259,33 -180,6 +259,33 @@@ mono_marshal_init_tls (void
        mono_native_tls_alloc (&load_type_info_tls_id, NULL);
  }
  
 +static MonoObject*
 +mono_object_isinst_icall (MonoObject *obj, MonoClass *klass)
 +{
 +      MonoError error;
 +      MonoObject *result = mono_object_isinst_checked (obj, klass, &error);
 +      mono_error_set_pending_exception (&error);
 +      return result;
 +}
 +
 +static MonoString*
 +ves_icall_mono_string_from_utf16 (gunichar2 *data)
 +{
 +      MonoError error;
 +      MonoString *result = mono_string_from_utf16_checked (data, &error);
 +      mono_error_set_pending_exception (&error);
 +      return result;
 +}
 +
 +static char*
 +ves_icall_mono_string_to_utf8 (MonoString *str)
 +{
 +      MonoError error;
 +      char *result = mono_string_to_utf8_checked (str, &error);
 +      mono_error_set_pending_exception (&error);
 +      return result;
 +}
 +
  void
  mono_marshal_init (void)
  {
                register_icall (mono_marshal_string_to_utf16, "mono_marshal_string_to_utf16", "ptr obj", FALSE);
                register_icall (mono_marshal_string_to_utf16_copy, "mono_marshal_string_to_utf16_copy", "ptr obj", FALSE);
                register_icall (mono_string_to_utf16, "mono_string_to_utf16", "ptr obj", FALSE);
 -              register_icall (mono_string_from_utf16, "mono_string_from_utf16", "obj ptr", FALSE);
 +              register_icall (ves_icall_mono_string_from_utf16, "ves_icall_mono_string_from_utf16", "obj ptr", FALSE);
                register_icall (mono_string_from_byvalstr, "mono_string_from_byvalstr", "obj ptr int", FALSE);
                register_icall (mono_string_from_byvalwstr, "mono_string_from_byvalwstr", "obj ptr int", FALSE);
                register_icall (mono_string_new_wrapper, "mono_string_new_wrapper", "obj ptr", FALSE);
                register_icall (mono_string_new_len_wrapper, "mono_string_new_len_wrapper", "obj ptr int", FALSE);
 -              register_icall (mono_string_to_utf8, "mono_string_to_utf8", "ptr obj", FALSE);
 -              register_icall (mono_string_to_lpstr, "mono_string_to_lpstr", "ptr obj", FALSE);
 +              register_icall (ves_icall_mono_string_to_utf8, "ves_icall_mono_string_to_utf8", "ptr obj", FALSE);
 +              register_icall (mono_string_to_utf8str, "mono_string_to_utf8str", "ptr obj", FALSE);
                register_icall (mono_string_to_ansibstr, "mono_string_to_ansibstr", "ptr object", FALSE);
                register_icall (mono_string_builder_to_utf8, "mono_string_builder_to_utf8", "ptr object", FALSE);
                register_icall (mono_string_builder_to_utf16, "mono_string_builder_to_utf16", "ptr object", FALSE);
                register_icall (mono_ftnptr_to_delegate, "mono_ftnptr_to_delegate", "object ptr ptr", FALSE);
                register_icall (mono_marshal_asany, "mono_marshal_asany", "ptr object int32 int32", FALSE);
                register_icall (mono_marshal_free_asany, "mono_marshal_free_asany", "void object ptr int32 int32", FALSE);
 -              register_icall (mono_marshal_alloc, "mono_marshal_alloc", "ptr int32", FALSE);
 +              register_icall (ves_icall_marshal_alloc, "ves_icall_marshal_alloc", "ptr int32", FALSE);
                register_icall (mono_marshal_free, "mono_marshal_free", "void ptr", FALSE);
                register_icall (mono_marshal_set_last_error, "mono_marshal_set_last_error", "void", FALSE);
                register_icall (mono_marshal_set_last_error_windows, "mono_marshal_set_last_error_windows", "void int32", FALSE);
                register_icall (mono_string_to_byvalstr, "mono_string_to_byvalstr", "void ptr ptr int32", FALSE);
                register_icall (mono_string_to_byvalwstr, "mono_string_to_byvalwstr", "void ptr ptr int32", FALSE);
                register_icall (g_free, "g_free", "void ptr", FALSE);
 -              register_icall (mono_object_isinst, "mono_object_isinst", "object object ptr", FALSE);
 +              register_icall (mono_object_isinst_icall, "mono_object_isinst_icall", "object object ptr", FALSE);
                register_icall (mono_struct_delete_old, "mono_struct_delete_old", "void ptr ptr", FALSE);
                register_icall (mono_delegate_begin_invoke, "mono_delegate_begin_invoke", "object object ptr", FALSE);
                register_icall (mono_delegate_end_invoke, "mono_delegate_end_invoke", "object object ptr", FALSE);
 -              register_icall (mono_compile_method, "mono_compile_method", "ptr ptr", FALSE);
                register_icall (mono_context_get, "mono_context_get", "object", FALSE);
                register_icall (mono_context_set, "mono_context_set", "void object", FALSE);
                register_icall (mono_gc_wbarrier_generic_nostore, "wb_generic", "void ptr", FALSE);
                register_icall (mono_gchandle_get_target, "mono_gchandle_get_target", "object int32", TRUE);
 +              register_icall (mono_gchandle_new, "mono_gchandle_new", "uint32 object bool", TRUE);
                register_icall (mono_marshal_isinst_with_cache, "mono_marshal_isinst_with_cache", "object object ptr ptr", FALSE);
 +              register_icall (mono_marshal_ftnptr_eh_callback, "mono_marshal_ftnptr_eh_callback", "void uint32", TRUE);
 +              register_icall (mono_threads_enter_gc_safe_region_unbalanced, "mono_threads_enter_gc_safe_region_unbalanced", "ptr ptr", TRUE);
 +              register_icall (mono_threads_exit_gc_safe_region_unbalanced, "mono_threads_exit_gc_safe_region_unbalanced", "void ptr ptr", TRUE);
 +              register_icall (mono_threads_attach_coop, "mono_threads_attach_coop", "ptr ptr ptr", TRUE);
 +              register_icall (mono_threads_detach_coop, "mono_threads_detach_coop", "void ptr ptr", TRUE);
 +              register_icall (mono_icall_start, "mono_icall_start", "ptr ptr ptr", TRUE);
 +              register_icall (mono_icall_end, "mono_icall_end", "void ptr ptr ptr", TRUE);
 +              register_icall (mono_handle_new, "mono_handle_new", "ptr ptr", TRUE);
  
                mono_cominterop_init ();
                mono_remoting_init ();
  
 -              if (mono_threads_is_coop_enabled ()) {
 -                      register_icall (mono_threads_prepare_blocking, "mono_threads_prepare_blocking", "ptr ptr", FALSE);
 -                      register_icall (mono_threads_finish_blocking, "mono_threads_finish_blocking", "void ptr ptr", FALSE);
 -                      register_icall (mono_threads_reset_blocking_start, "mono_threads_reset_blocking_start","ptr ptr", TRUE);
 -                      register_icall (mono_threads_reset_blocking_end, "mono_threads_reset_blocking_end","void ptr ptr", TRUE);
 -              }
 +              mono_counters_register ("MonoClass::class_marshal_info_count count",
 +                                                              MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_marshal_info_count);
 +
        }
  }
  
@@@ -384,11 -273,9 +384,11 @@@ mono_marshal_unlock_internal (void
        mono_marshal_unlock ();
  }
  
 +/* This is a JIT icall, it sets the pending exception and return NULL on error */
  gpointer
  mono_delegate_to_ftnptr (MonoDelegate *delegate)
  {
 +      MonoError error;
        MonoMethod *method, *wrapper;
        MonoClass *klass;
        uint32_t target_handle = 0;
        g_assert (klass->delegate);
  
        method = delegate->method;
 +      if (delegate->method_is_virtual)
 +              method = mono_object_get_virtual_method (delegate->target, method);
  
 -      if (mono_method_signature (method)->pinvoke) {
 +      if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
                const char *exc_class, *exc_arg;
                gpointer ftnptr;
  
                ftnptr = mono_lookup_pinvoke_call (method, &exc_class, &exc_arg);
                if (!ftnptr) {
                        g_assert (exc_class);
 -                      mono_raise_exception (mono_exception_from_name_msg (mono_defaults.corlib, "System", exc_class, exc_arg));
 +                      mono_set_pending_exception (mono_exception_from_name_msg (mono_defaults.corlib, "System", exc_class, exc_arg));
 +                      return NULL;
                }
                return ftnptr;
        }
  
        wrapper = mono_marshal_get_managed_wrapper (method, klass, target_handle);
  
 -      delegate->delegate_trampoline = mono_compile_method (wrapper);
 +      delegate->delegate_trampoline = mono_compile_method_checked (wrapper, &error);
 +      if (!is_ok (&error))
 +              goto fail;
  
        // Add the delegate to the delegate hash table
        delegate_hash_table_add (delegate);
        mono_object_register_finalizer ((MonoObject*)delegate);
  
        return delegate->delegate_trampoline;
 +
 +fail:
 +      if (target_handle != 0)
 +              mono_gchandle_free (target_handle);
 +      mono_error_set_pending_exception (&error);
 +      return NULL;
  }
  
  /* 
@@@ -508,23 -384,23 +508,23 @@@ mono_marshal_use_aot_wrappers (gboolea
  static void
  parse_unmanaged_function_pointer_attr (MonoClass *klass, MonoMethodPInvoke *piinfo)
  {
 -      static MonoClass *UnmanagedFunctionPointerAttribute;
 +      MonoError error;
        MonoCustomAttrInfo *cinfo;
        MonoReflectionUnmanagedFunctionPointerAttribute *attr;
  
 -      if (!UnmanagedFunctionPointerAttribute)
 -              UnmanagedFunctionPointerAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "UnmanagedFunctionPointerAttribute");
 -
        /* The attribute is only available in Net 2.0 */
 -      if (UnmanagedFunctionPointerAttribute) {
 +      if (mono_class_try_get_unmanaged_function_pointer_attribute_class ()) {
                /* 
                 * The pinvoke attributes are stored in a real custom attribute so we have to
                 * construct it.
                 */
 -              cinfo = mono_custom_attrs_from_class (klass);
 +              cinfo = mono_custom_attrs_from_class_checked (klass, &error);
 +              if (!mono_error_ok (&error)) {
 +                      g_warning ("Could not load UnmanagedFunctionPointerAttribute due to %s", mono_error_get_message (&error));
 +                      mono_error_cleanup (&error);
 +              }
                if (cinfo && !mono_runtime_get_no_exec ()) {
 -                      MonoError error;
 -                      attr = (MonoReflectionUnmanagedFunctionPointerAttribute*)mono_custom_attrs_get_attr_checked (cinfo, UnmanagedFunctionPointerAttribute, &error);
 +                      attr = (MonoReflectionUnmanagedFunctionPointerAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_try_get_unmanaged_function_pointer_attribute_class (), &error);
                        if (attr) {
                                piinfo->piflags = (attr->call_conv << 8) | (attr->charset ? (attr->charset - 1) * 2 : 1) | attr->set_last_error;
                        } else {
        }
  }
  
 +/* This is a JIT icall, it sets the pending exception and returns NULL on error */
  MonoDelegate*
  mono_ftnptr_to_delegate (MonoClass *klass, gpointer ftn)
  {
 +      MonoError error;
        guint32 gchandle;
        MonoDelegate *d;
  
  
                if (use_aot_wrappers) {
                        wrapper = mono_marshal_get_native_func_wrapper_aot (klass);
 -                      this_obj = mono_value_box (mono_domain_get (), mono_defaults.int_class, &ftn);
 +                      this_obj = mono_value_box_checked (mono_domain_get (), mono_defaults.int_class, &ftn, &error);
 +                      if (!is_ok (&error)) {
 +                              mono_error_set_pending_exception (&error);
 +                              return NULL;
 +                      }
                } else {
                        memset (&piinfo, 0, sizeof (piinfo));
                        parse_unmanaged_function_pointer_attr (klass, &piinfo);
                        g_free (sig);
                }
  
 -              d = (MonoDelegate*)mono_object_new (mono_domain_get (), klass);
 -              mono_delegate_ctor_with_method ((MonoObject*)d, this_obj, mono_compile_method (wrapper), wrapper);
 +              d = (MonoDelegate*)mono_object_new_checked (mono_domain_get (), klass, &error);
 +              if (!mono_error_ok (&error)) {
 +                      mono_error_set_pending_exception (&error);
 +                      return NULL;
 +              }
 +              gpointer compiled_ptr = mono_compile_method_checked (wrapper, &error);
 +              if (mono_error_set_pending_exception (&error))
 +                      return NULL;
 +              mono_delegate_ctor_with_method ((MonoObject*)d, this_obj, compiled_ptr, wrapper, &error);
 +              if (mono_error_set_pending_exception (&error))
 +                      return NULL;
        }
  
 -      if (d->object.vtable->domain != mono_domain_get ())
 -              mono_raise_exception (mono_get_exception_not_supported ("Delegates cannot be marshalled from native code into a domain other than their home domain"));
 +      if (d->object.vtable->domain != mono_domain_get ()) {
 +              mono_set_pending_exception (mono_get_exception_not_supported ("Delegates cannot be marshalled from native code into a domain other than their home domain"));
 +              return NULL;
 +      }
  
        return d;
  }
@@@ -659,11 -518,9 +659,11 @@@ mono_delegate_free_ftnptr (MonoDelegat
        }
  }
  
 +/* This is a JIT icall, it sets the pending exception and returns NULL on error */
  static MonoString *
  mono_string_from_byvalstr (const char *data, int max_len)
  {
 +      MonoError error;
        MonoDomain *domain = mono_domain_get ();
        int len = 0;
  
        while (len < max_len - 1 && data [len])
                len++;
  
 -      return mono_string_new_len (domain, data, len);
 +      MonoString *result = mono_string_new_len_checked (domain, data, len, &error);
 +      mono_error_set_pending_exception (&error);
 +      return result;
  }
  
 +/* This is a JIT icall, it sets the pending exception and return NULL on error */
  static MonoString *
  mono_string_from_byvalwstr (gunichar2 *data, int max_len)
  {
 +      MonoError error;
 +      MonoString *res = NULL;
        MonoDomain *domain = mono_domain_get ();
        int len = 0;
  
  
        while (data [len]) len++;
  
 -      return mono_string_new_utf16 (domain, data, MIN (len, max_len));
 +      res = mono_string_new_utf16_checked (domain, data, MIN (len, max_len), &error);
 +      if (!mono_error_ok (&error)) {
 +              mono_error_set_pending_exception (&error);
 +              return NULL;
 +      }
 +      return res;
  }
  
  gpointer
@@@ -785,7 -632,7 +785,7 @@@ mono_free_lparray (MonoArray *array, gp
        if (klass->element_class->byval_arg.type == MONO_TYPE_CLASS) {
                for(i = 0; i < array->max_length; ++i)
                        mono_marshal_free_ccw (mono_array_get (array, MonoObject*, i));
 -              free(nativeArray);
 +              g_free (nativeArray);
        }
  #endif
  }
@@@ -819,7 -666,6 +819,7 @@@ mono_byvalarray_to_byte_array (MonoArra
        mono_byvalarray_to_array (arr, native_arr, mono_defaults.byte_class, elnum);
  }
  
 +/* This is a JIT icall, it sets the pending exception and returns on error */
  static void
  mono_array_to_byvalarray (gpointer native_arr, MonoArray *arr, MonoClass *elclass, guint32 elnum)
  {
  
                as = g_utf16_to_utf8 (mono_array_addr (arr, gunichar2, 0), mono_array_length (arr), NULL, NULL, &error);
                if (error) {
 -                      MonoException *exc = mono_get_exception_argument ("string", error->message);
 +                      mono_set_pending_exception (mono_get_exception_argument ("string", error->message));
                        g_error_free (error);
 -                      mono_raise_exception (exc);
 +                      return;
                }
  
                memcpy (native_arr, as, MIN (strlen (as), elnum));
@@@ -855,8 -701,6 +855,8 @@@ mono_string_builder_new (int starting_s
        static MonoClass *string_builder_class;
        static MonoMethod *sb_ctor;
        static void *args [1];
 +
 +      MonoError error;
        int initial_len = starting_string_length;
  
        if (initial_len < 0)
                MonoMethodDesc *desc;
                MonoMethod *m;
  
 -              string_builder_class = mono_class_from_name (mono_defaults.corlib, "System.Text", "StringBuilder");
 +              string_builder_class = mono_class_get_string_builder_class ();
                g_assert (string_builder_class);
                desc = mono_method_desc_new (":.ctor(int)", FALSE);
                m = mono_method_desc_search_in_class (desc, string_builder_class);
        // array will always be garbage collected.
        args [0] = &initial_len;
  
 -      MonoStringBuilder *sb = (MonoStringBuilder*)mono_object_new (mono_domain_get (), string_builder_class);
 -      MonoObject *exc;
 -      g_assert (sb);
 +      MonoStringBuilder *sb = (MonoStringBuilder*)mono_object_new_checked (mono_domain_get (), string_builder_class, &error);
 +      mono_error_assert_ok (&error);
  
 -      mono_runtime_invoke (sb_ctor, sb, args, &exc);
 -      g_assert (!exc);
 +      MonoObject *exc;
 +      mono_runtime_try_invoke (sb_ctor, sb, args, &exc, &error);
 +      g_assert (exc == NULL);
 +      mono_error_assert_ok (&error);
  
        g_assert (sb->chunkChars->max_length >= initial_len);
  
@@@ -926,13 -769,13 +926,13 @@@ mono_string_utf8_to_builder (MonoString
        if (!sb || !text)
                return;
  
 -      int len = strlen (text);
 -      if (len > mono_string_builder_capacity (sb))
 -              len = mono_string_builder_capacity (sb);
 -
        GError *error = NULL;
        glong copied;
 -      gunichar2* ut = g_utf8_to_utf16 (text, len, NULL, &copied, &error);
 +      gunichar2* ut = g_utf8_to_utf16 (text, strlen (text), NULL, &copied, &error);
 +      int capacity = mono_string_builder_capacity (sb);
 +
 +      if (copied > capacity)
 +              copied = capacity;
  
        if (!error) {
                MONO_OBJECT_SETREF (sb, chunkPrevious, NULL);
@@@ -956,6 -799,7 +956,6 @@@ mono_string_utf8_to_builder2 (char *tex
        return sb;
  }
  
 -
  void
  mono_string_utf16_to_builder (MonoStringBuilder *sb, gunichar2 *text)
  {
   *
   * Returns: a utf8 string with the contents of the StringBuilder.
   *
 - * The return value must be released with g_free.
 + * The return value must be released with mono_marshal_free.
 + *
 + * This is a JIT icall, it sets the pending exception and returns NULL on error.
   */
  gchar*
  mono_string_builder_to_utf8 (MonoStringBuilder *sb)
  {
 -      GError *error = NULL;
 -
 +      MonoError error;
 +      GError *gerror = NULL;
 +      glong byte_count;
        if (!sb)
                return NULL;
  
 -
        gunichar2 *str_utf16 = mono_string_builder_to_utf16 (sb);
  
        guint str_len = mono_string_builder_string_length (sb);
  
 -      gchar *tmp = g_utf16_to_utf8 (str_utf16, str_len, NULL, NULL, &error);
 +      gchar *tmp = g_utf16_to_utf8 (str_utf16, str_len, NULL, &byte_count, &gerror);
  
 -      if (error) {
 -              g_error_free (error);
 -              g_free (str_utf16);
 -              mono_raise_exception (mono_get_exception_execution_engine ("Failed to convert StringBuilder from utf16 to utf8"));
 +      if (gerror) {
 +              g_error_free (gerror);
 +              mono_marshal_free (str_utf16);
 +              mono_set_pending_exception (mono_get_exception_execution_engine ("Failed to convert StringBuilder from utf16 to utf8"));
                return NULL;
        } else {
                guint len = mono_string_builder_capacity (sb) + 1;
 -              gchar *res = (gchar *)mono_marshal_alloc (len * sizeof (gchar));
 -              g_assert (str_len < len);
 -              memcpy (res, tmp, str_len * sizeof (gchar));
 -              res[str_len] = '\0';
 +              gchar *res = (gchar *)mono_marshal_alloc (MAX (byte_count+1, len * sizeof (gchar)), &error);
 +              if (!mono_error_ok (&error)) {
 +                      mono_marshal_free (str_utf16);
 +                      g_free (tmp);
 +                      mono_error_set_pending_exception (&error);
 +                      return NULL;
 +              }
  
 +              memcpy (res, tmp, byte_count);
 +              res[byte_count] = '\0';
  
 -              g_free (str_utf16);
 +              mono_marshal_free (str_utf16);
                g_free (tmp);
                return res;
        }
   *
   * Returns: a utf16 string with the contents of the StringBuilder.
   *
 - * The return value must not be freed.
 + * The return value must be released with mono_marshal_free.
 + *
 + * This is a JIT icall, it sets the pending exception and returns NULL on error.
   */
  gunichar2*
  mono_string_builder_to_utf16 (MonoStringBuilder *sb)
  {
 +      MonoError error;
 +
        if (!sb)
                return NULL;
  
        if (len == 0)
                len = 1;
  
 -      gunichar2 *str = (gunichar2 *)mono_marshal_alloc ((len + 1) * sizeof (gunichar2));
 +      gunichar2 *str = (gunichar2 *)mono_marshal_alloc ((len + 1) * sizeof (gunichar2), &error);
 +      if (!mono_error_ok (&error)) {
 +              mono_error_set_pending_exception (&error);
 +              return NULL;
 +      }
 +
        str[len] = '\0';
  
        if (len == 0)
        return str;
  }
  
 +/* This is a JIT icall, it sets the pending exception and returns NULL on error. */
  static gpointer
 -mono_string_to_lpstr (MonoString *s)
 +mono_string_to_utf8str (MonoString *s)
  {
 -#ifdef TARGET_WIN32
 -      char *as, *tmp;
 -      glong len;
 -      GError *error = NULL;
 -
 -      if (s == NULL)
 -              return NULL;
 -
 -      if (!s->length) {
 -              as = CoTaskMemAlloc (1);
 -              as [0] = '\0';
 -              return as;
 -      }
 -
 -      tmp = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &len, &error);
 -      if (error) {
 -              MonoException *exc = mono_get_exception_argument ("string", error->message);
 -              g_error_free (error);
 -              mono_raise_exception(exc);
 -              return NULL;
 -      } else {
 -              as = CoTaskMemAlloc (len + 1);
 -              memcpy (as, tmp, len + 1);
 -              g_free (tmp);
 -              return as;
 -      }
 -#else
 -      return mono_string_to_utf8 (s);
 -#endif
 -}     
 +      MonoError error;
 +      char *result = mono_string_to_utf8_checked (s, &error);
 +      mono_error_set_pending_exception (&error);
 +      return result;
 +}
  
  gpointer
  mono_string_to_ansibstr (MonoString *string_obj)
  void
  mono_string_to_byvalstr (gpointer dst, MonoString *src, int size)
  {
 +      MonoError error;
        char *s;
        int len;
  
        if (!src)
                return;
  
 -      s = mono_string_to_utf8 (src);
 +      s = mono_string_to_utf8_checked (src, &error);
 +      if (mono_error_set_pending_exception (&error))
 +              return;
        len = MIN (size, strlen (s));
        if (len >= size)
                len--;
@@@ -1160,14 -1009,10 +1160,14 @@@ mono_string_to_byvalwstr (gpointer dst
        *((gunichar2 *) dst + len) = 0;
  }
  
 +/* this is an icall, it sets the pending exception and returns NULL on error */
  static MonoString*
  mono_string_new_len_wrapper (const char *text, guint length)
  {
 -      return mono_string_new_len (mono_domain_get (), text, length);
 +      MonoError error;
 +      MonoString *result = mono_string_new_len_checked (mono_domain_get (), text, length, &error);
 +      mono_error_set_pending_exception (&error);
 +      return result;
  }
  
  #ifndef DISABLE_JIT
@@@ -1254,8 -1099,7 +1254,8 @@@ guin
  mono_type_to_stind (MonoType *type)
  {
        if (type->byref)
 -              return CEE_STIND_I;
 +              return MONO_TYPE_IS_REFERENCE (type) ? CEE_STIND_REF : CEE_STIND_I;
 +
  
  handle_enum:
        switch (type->type) {
@@@ -1351,7 -1195,7 +1351,7 @@@ emit_ptr_to_object_conv (MonoMethodBuil
                mono_mb_emit_ldloc (mb, 1);
                mono_mb_emit_icon (mb, mspec->data.array_data.num_elem);
                mono_mb_emit_op (mb, CEE_NEWARR, eklass);       
 -              mono_mb_emit_byte (mb, CEE_STIND_I);
 +              mono_mb_emit_byte (mb, CEE_STIND_REF);
  
                if (eklass->blittable) {
                        /* copy the elements */
                } else {
                        mono_mb_emit_ldloc (mb, 1);
                        mono_mb_emit_ldloc (mb, 0);
 -                      mono_mb_emit_icall (mb, mono_string_from_utf16);
 +                      mono_mb_emit_icall (mb, ves_icall_mono_string_from_utf16);
                }
                mono_mb_emit_byte (mb, CEE_STIND_REF);          
                break;          
                mono_mb_emit_ldloc (mb, 0);
                mono_mb_emit_byte (mb, CEE_LDIND_I);
  #ifdef TARGET_WIN32
 -              mono_mb_emit_icall (mb, mono_string_from_utf16);
 +              mono_mb_emit_icall (mb, ves_icall_mono_string_from_utf16);
  #else
                mono_mb_emit_icall (mb, mono_string_new_wrapper);
  #endif
                mono_mb_emit_byte (mb, CEE_STIND_REF);  
                break;
 +
 +              // In Mono historically LPSTR was treated as a UTF8STR
        case MONO_MARSHAL_CONV_STR_LPSTR:
 +      case MONO_MARSHAL_CONV_STR_UTF8STR:
                mono_mb_emit_ldloc (mb, 1);
                mono_mb_emit_ldloc (mb, 0);
                mono_mb_emit_byte (mb, CEE_LDIND_I);
                mono_mb_emit_ldloc (mb, 1);
                mono_mb_emit_ldloc (mb, 0);
                mono_mb_emit_byte (mb, CEE_LDIND_I);
 -              mono_mb_emit_icall (mb, mono_string_from_utf16);
 +              mono_mb_emit_icall (mb, ves_icall_mono_string_from_utf16);
                mono_mb_emit_byte (mb, CEE_STIND_REF);
                break;
        case MONO_MARSHAL_CONV_OBJECT_STRUCT: {
  }
  
  static gpointer
 -conv_to_icall (MonoMarshalConv conv)
 +conv_to_icall (MonoMarshalConv conv, int *ind_store_type)
  {
 +      int dummy;
 +      if (!ind_store_type)
 +              ind_store_type = &dummy;
 +      *ind_store_type = CEE_STIND_I;
        switch (conv) {
        case MONO_MARSHAL_CONV_STR_LPWSTR:
                return mono_marshal_string_to_utf16;            
        case MONO_MARSHAL_CONV_LPWSTR_STR:
 -              return mono_string_from_utf16;
 +              *ind_store_type = CEE_STIND_REF;
 +              return ves_icall_mono_string_from_utf16;
        case MONO_MARSHAL_CONV_LPTSTR_STR:
 +              *ind_store_type = CEE_STIND_REF;
                return mono_string_new_wrapper;
 +      case MONO_MARSHAL_CONV_UTF8STR_STR:
        case MONO_MARSHAL_CONV_LPSTR_STR:
 +              *ind_store_type = CEE_STIND_REF;
                return mono_string_new_wrapper;
        case MONO_MARSHAL_CONV_STR_LPTSTR:
  #ifdef TARGET_WIN32
                return mono_marshal_string_to_utf16;
  #else
 -              return mono_string_to_lpstr;
 +              return mono_string_to_utf8str;
  #endif
 +              // In Mono historically LPSTR was treated as a UTF8STR
 +      case MONO_MARSHAL_CONV_STR_UTF8STR:
        case MONO_MARSHAL_CONV_STR_LPSTR:
 -              return mono_string_to_lpstr;
 +              return mono_string_to_utf8str;
        case MONO_MARSHAL_CONV_STR_BSTR:
                return mono_string_to_bstr;
        case MONO_MARSHAL_CONV_BSTR_STR:
 -              return mono_string_from_bstr;
 +              *ind_store_type = CEE_STIND_REF;
 +              return mono_string_from_bstr_icall;
        case MONO_MARSHAL_CONV_STR_TBSTR:
        case MONO_MARSHAL_CONV_STR_ANSIBSTR:
                return mono_string_to_ansibstr;
 +      case MONO_MARSHAL_CONV_SB_UTF8STR:
        case MONO_MARSHAL_CONV_SB_LPSTR:
                return mono_string_builder_to_utf8;
        case MONO_MARSHAL_CONV_SB_LPTSTR:
        case MONO_MARSHAL_CONV_DEL_FTN:
                return mono_delegate_to_ftnptr;
        case MONO_MARSHAL_CONV_FTN_DEL:
 +              *ind_store_type = CEE_STIND_REF;
                return mono_ftnptr_to_delegate;
 +      case MONO_MARSHAL_CONV_UTF8STR_SB:
        case MONO_MARSHAL_CONV_LPSTR_SB:
 +              *ind_store_type = CEE_STIND_REF;
                return mono_string_utf8_to_builder;
        case MONO_MARSHAL_CONV_LPTSTR_SB:
 +              *ind_store_type = CEE_STIND_REF;
  #ifdef TARGET_WIN32
                return mono_string_utf16_to_builder;
  #else
                return mono_string_utf8_to_builder;
  #endif
        case MONO_MARSHAL_CONV_LPWSTR_SB:
 +              *ind_store_type = CEE_STIND_REF;
                return mono_string_utf16_to_builder;
        case MONO_MARSHAL_FREE_ARRAY:
                return mono_marshal_free_array;
@@@ -1682,7 -1506,6 +1682,7 @@@ static voi
  emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
  {
        int pos;
 +      int stind_op;
  
        switch (conv) {
        case MONO_MARSHAL_CONV_BOOL_I4:
                mono_mb_emit_byte (mb, CEE_NEG);
                mono_mb_emit_byte (mb, CEE_STIND_I2);
                break;
 +      // In Mono historically LPSTR was treated as a UTF8STR
 +      case MONO_MARSHAL_CONV_STR_UTF8STR:
        case MONO_MARSHAL_CONV_STR_LPWSTR:
        case MONO_MARSHAL_CONV_STR_LPSTR:
        case MONO_MARSHAL_CONV_STR_LPTSTR:
                mono_mb_emit_ldloc (mb, 1);
                mono_mb_emit_ldloc (mb, 0);
                mono_mb_emit_byte (mb, CEE_LDIND_REF);
 -              mono_mb_emit_icall (mb, conv_to_icall (conv));
 -              mono_mb_emit_byte (mb, CEE_STIND_I);    
 +              mono_mb_emit_icall (mb, conv_to_icall (conv, &stind_op));
 +              mono_mb_emit_byte (mb, stind_op);
                break;
        }
        case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
                mono_mb_emit_ldloc (mb, 1);
                mono_mb_emit_ldloc (mb, 0);
                mono_mb_emit_byte (mb, CEE_LDIND_REF);
 -              mono_mb_emit_icall (mb, conv_to_icall (conv));
 -              mono_mb_emit_byte (mb, CEE_STIND_I);    
 +              mono_mb_emit_icall (mb, conv_to_icall (conv, &stind_op));
 +              mono_mb_emit_byte (mb, stind_op);
                break;
        case MONO_MARSHAL_CONV_STR_BYVALSTR: 
        case MONO_MARSHAL_CONV_STR_BYVALWSTR: {
                mono_mb_emit_ldloc (mb, 0);     
                mono_mb_emit_byte (mb, CEE_LDIND_REF); /* src String */
                mono_mb_emit_icon (mb, mspec->data.array_data.num_elem);
 -              mono_mb_emit_icall (mb, conv_to_icall (conv));
 +              mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
                break;
        }
        case MONO_MARSHAL_CONV_ARRAY_BYVALARRAY: {
        }
                
        default: {
 -              char *msg = g_strdup_printf ("marshalling conversion %d not implemented", conv);
 -              MonoException *exc = mono_get_exception_not_implemented (msg);
 -              g_warning ("%s", msg);
 -              g_free (msg);
 -              mono_raise_exception (exc);
 +              g_error ("marshalling conversion %d not implemented", conv);
 +      }
        }
 +}
 +
 +static int offset_of_first_nonstatic_field(MonoClass *klass)
 +{
 +      int i;
 +      for (i = 0; i < klass->field.count; i++) {
 +              if (!(klass->fields[i].type->attrs & FIELD_ATTRIBUTE_STATIC) && !mono_field_is_deleted (&klass->fields[i]))
 +                      return klass->fields[i].offset - sizeof (MonoObject);
        }
 +
 +      return 0;
  }
  
  static void
  emit_struct_conv_full (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object,
 -                                         MonoMarshalNative string_encoding)
 +                                              int offset_of_first_child_field, MonoMarshalNative string_encoding)
  {
        MonoMarshalType *info;
        int i;
  
        if (klass->parent)
 -              emit_struct_conv(mb, klass->parent, to_object);
 +              emit_struct_conv_full (mb, klass->parent, to_object, offset_of_first_nonstatic_field (klass), string_encoding);
  
        info = mono_marshal_load_type_info (klass);
  
                return;
  
        if (klass->blittable) {
 -              int msize = mono_class_value_size (klass, NULL);
 -              g_assert (msize == info->native_size);
 +              int usize = mono_class_value_size (klass, NULL);
 +              g_assert (usize == info->native_size);
                mono_mb_emit_ldloc (mb, 1);
                mono_mb_emit_ldloc (mb, 0);
 -              mono_mb_emit_icon (mb, msize);
 +              mono_mb_emit_icon (mb, usize);
                mono_mb_emit_byte (mb, CEE_PREFIX1);
                mono_mb_emit_byte (mb, CEE_CPBLK);
  
 -              mono_mb_emit_add_to_local (mb, 0, msize);
 -              mono_mb_emit_add_to_local (mb, 1, msize);
 +              if (to_object) {
 +                      mono_mb_emit_add_to_local (mb, 0, usize);
 +                      mono_mb_emit_add_to_local (mb, 1, offset_of_first_child_field);
 +              } else {
 +                      mono_mb_emit_add_to_local (mb, 0, offset_of_first_child_field);
 +                      mono_mb_emit_add_to_local (mb, 1, usize);
 +              }
                return;
        }
  
 -      if (klass != mono_defaults.safehandle_class) {
 -              if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT) {
 +      if (klass != mono_class_try_get_safehandle_class ()) {
 +              if (mono_class_is_auto_layout (klass)) {
                        char *msg = g_strdup_printf ("Type %s which is passed to unmanaged code must have a StructLayout attribute.",
                                                                                 mono_type_full_name (&klass->byval_arg));
                        mono_mb_emit_exception_marshal_directive (mb, msg);
                        usize = info->fields [i + 1].offset - info->fields [i].offset;
                }
  
 -              if (klass != mono_defaults.safehandle_class){
 +              if (klass != mono_class_try_get_safehandle_class ()){
                        /* 
                         * FIXME: Should really check for usize==0 and msize>0, but we apply 
                         * the layout to the managed structure as well.
                         */
                        
 -                      if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) && (usize == 0)) {
 +                      if (mono_class_is_explicit_layout (klass) && (usize == 0)) {
                                if (MONO_TYPE_IS_REFERENCE (info->fields [i].field->type) ||
                                    ((!last_field && MONO_TYPE_IS_REFERENCE (info->fields [i + 1].field->type))))
                                        g_error ("Type %s which has an [ExplicitLayout] attribute cannot have a "
                case MONO_MARSHAL_CONV_NONE: {
                        int t;
  
 -                      if (ftype->byref || ftype->type == MONO_TYPE_I ||
 -                          ftype->type == MONO_TYPE_U) {
 +                      //XXX a byref field!?!? that's not allowed! and worse, it might miss a WB
 +                      g_assert (!ftype->byref);
 +                      if (ftype->type == MONO_TYPE_I || ftype->type == MONO_TYPE_U) {
                                mono_mb_emit_ldloc (mb, 1);
                                mono_mb_emit_ldloc (mb, 0);
                                mono_mb_emit_byte (mb, CEE_LDIND_I);
  static void
  emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object)
  {
 -      emit_struct_conv_full (mb, klass, to_object, (MonoMarshalNative)-1);
 +      emit_struct_conv_full (mb, klass, to_object, 0, (MonoMarshalNative)-1);
  }
  
  static void
@@@ -2236,26 -2044,24 +2236,26 @@@ mono_marshal_emit_thread_force_interrup
  
  #endif /* DISABLE_JIT */
  
 +/* This is a JIT icall, it sets the pending exception and returns NULL on error. */
  static MonoAsyncResult *
  mono_delegate_begin_invoke (MonoDelegate *delegate, gpointer *params)
  {
 +      MonoError error;
        MonoMulticastDelegate *mcast_delegate;
        MonoClass *klass;
        MonoMethod *method;
  
        g_assert (delegate);
        mcast_delegate = (MonoMulticastDelegate *) delegate;
 -      if (mcast_delegate->delegates != NULL)
 -              mono_raise_exception (mono_get_exception_argument (NULL, "The delegate must have only one target"));
 +      if (mcast_delegate->delegates != NULL) {
 +              mono_set_pending_exception (mono_get_exception_argument (NULL, "The delegate must have only one target"));
 +              return NULL;
 +      }
  
  #ifndef DISABLE_REMOTING
        if (delegate->target && mono_object_class (delegate->target) == mono_defaults.transparent_proxy_class) {
 -
                MonoTransparentProxy* tp = (MonoTransparentProxy *)delegate->target;
                if (!mono_class_is_contextbound (tp->remote_class->proxy_class) || tp->rp->context != (MonoObject *) mono_context_get ()) {
 -
                        /* If the target is a proxy, make a direct call. Is proxy's work
                        // to make the call asynchronous.
                        */
                        MonoArray *out_args;
                        method = delegate->method;
  
 -                      msg = mono_method_call_message_new (mono_marshal_method_from_wrapper (method), params, NULL, &async_callback, &state);
 -                      ares = mono_async_result_new (mono_domain_get (), NULL, state, NULL, NULL);
 +                      msg = mono_method_call_message_new (mono_marshal_method_from_wrapper (method), params, NULL, &async_callback, &state, &error);
 +                      if (mono_error_set_pending_exception (&error))
 +                              return NULL;
 +                      ares = mono_async_result_new (mono_domain_get (), NULL, state, NULL, NULL, &error);
 +                      if (mono_error_set_pending_exception (&error))
 +                              return NULL;
                        MONO_OBJECT_SETREF (ares, async_delegate, (MonoObject *)delegate);
                        MONO_OBJECT_SETREF (ares, async_callback, (MonoObject *)async_callback);
                        MONO_OBJECT_SETREF (msg, async_result, ares);
                        msg->call_type = CallType_BeginInvoke;
  
                        exc = NULL;
 -                      mono_remoting_invoke ((MonoObject *)tp->rp, msg, &exc, &out_args);
 +                      mono_remoting_invoke ((MonoObject *)tp->rp, msg, &exc, &out_args, &error);
 +                      if (!mono_error_ok (&error)) {
 +                              mono_error_set_pending_exception (&error);
 +                              return NULL;
 +                      }
                        if (exc)
 -                              mono_raise_exception ((MonoException *) exc);
 +                              mono_set_pending_exception ((MonoException *) exc);
                        return ares;
                }
        }
                method = mono_get_delegate_invoke (klass);
        g_assert (method);
  
 -      return mono_threadpool_ms_begin_invoke (mono_domain_get (), (MonoObject*) delegate, method, params);
 +      MonoAsyncResult *result = mono_threadpool_ms_begin_invoke (mono_domain_get (), (MonoObject*) delegate, method, params, &error);
 +      mono_error_set_pending_exception (&error);
 +      return result;
  }
  
  #ifndef DISABLE_JIT
@@@ -2428,10 -2224,8 +2428,10 @@@ mono_marshal_get_string_to_ptr_conv (Mo
                return MONO_MARSHAL_CONV_STR_LPTSTR;
        case MONO_NATIVE_BSTR:
                return MONO_MARSHAL_CONV_STR_BSTR;
 +      case MONO_NATIVE_UTF8STR:
 +              return MONO_MARSHAL_CONV_STR_UTF8STR;
        default:
 -              return (MonoMarshalConv)-1;
 +              return MONO_MARSHAL_CONV_INVALID;
        }
  }
  
@@@ -2443,14 -2237,15 +2443,14 @@@ mono_marshal_get_stringbuilder_to_ptr_c
        switch (encoding) {
        case MONO_NATIVE_LPWSTR:
                return MONO_MARSHAL_CONV_SB_LPWSTR;
 -              break;
        case MONO_NATIVE_LPSTR:
                return MONO_MARSHAL_CONV_SB_LPSTR;
 -              break;
 +      case MONO_NATIVE_UTF8STR:
 +              return MONO_MARSHAL_CONV_SB_UTF8STR;
        case MONO_NATIVE_LPTSTR:
                return MONO_MARSHAL_CONV_SB_LPTSTR;
 -              break;
        default:
 -              return (MonoMarshalConv)-1;
 +              return MONO_MARSHAL_CONV_INVALID;
        }
  }
  
@@@ -2465,8 -2260,6 +2465,8 @@@ mono_marshal_get_ptr_to_string_conv (Mo
        case MONO_NATIVE_LPWSTR:
                *need_free = FALSE;
                return MONO_MARSHAL_CONV_LPWSTR_STR;
 +      case MONO_NATIVE_UTF8STR:
 +              return MONO_MARSHAL_CONV_UTF8STR_STR;
        case MONO_NATIVE_LPSTR:
        case MONO_NATIVE_VBBYREFSTR:
                return MONO_MARSHAL_CONV_LPSTR_STR;
        case MONO_NATIVE_BSTR:
                return MONO_MARSHAL_CONV_BSTR_STR;
        default:
 -              return (MonoMarshalConv)-1;
 +              return MONO_MARSHAL_CONV_INVALID;
        }
  }
  
@@@ -2494,8 -2287,6 +2494,8 @@@ mono_marshal_get_ptr_to_stringbuilder_c
                 */
                *need_free = FALSE;
                return MONO_MARSHAL_CONV_LPWSTR_SB;
 +      case MONO_NATIVE_UTF8STR:
 +              return MONO_MARSHAL_CONV_UTF8STR_SB;
        case MONO_NATIVE_LPSTR:
                return MONO_MARSHAL_CONV_LPSTR_SB;
                break;
                return MONO_MARSHAL_CONV_LPTSTR_SB;
                break;
        default:
 -              return (MonoMarshalConv)-1;
 +              return MONO_MARSHAL_CONV_INVALID;
        }
  }
  
@@@ -2683,11 -2474,6 +2683,11 @@@ mono_marshal_method_from_wrapper (MonoM
                        return info->d.runtime_invoke.method;
                else
                        return NULL;
 +      case MONO_WRAPPER_DELEGATE_INVOKE:
 +              if (info)
 +                      return info->d.delegate_invoke.method;
 +              else
 +                      return NULL;
        default:
                return NULL;
        }
@@@ -2883,7 -2669,6 +2883,7 @@@ cache_generic_delegate_wrapper (GHashTa
  {
        MonoError error;
        MonoMethod *inst, *res;
 +      WrapperInfo *ginfo, *info;
  
        /*
         * We use the same cache for the generic definition and the instances.
        inst = mono_class_inflate_generic_method_checked (def, ctx, &error);
        g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
  
 +      ginfo = mono_marshal_get_wrapper_info (def);
 +      if (ginfo) {
 +              info = (WrapperInfo *)mono_image_alloc0 (def->klass->image, sizeof (WrapperInfo));
 +              info->subtype = ginfo->subtype;
 +              if (info->subtype == WRAPPER_SUBTYPE_NONE) {
 +                      info->d.delegate_invoke.method = mono_class_inflate_generic_method_checked (ginfo->d.delegate_invoke.method, ctx, &error);
 +                      mono_error_assert_ok (&error);
 +              }
 +      }
 +
        mono_memory_barrier ();
        mono_marshal_lock ();
        res = (MonoMethod *)g_hash_table_lookup (cache, orig_method->klass);
@@@ -2984,11 -2759,9 +2984,11 @@@ mono_marshal_get_delegate_begin_invoke 
        return res;
  }
  
 +/* This is a JIT icall, it sets the pending exception and returns NULL on error. */
  static MonoObject *
  mono_delegate_end_invoke (MonoDelegate *delegate, gpointer *params)
  {
 +      MonoError error;
        MonoDomain *domain = mono_domain_get ();
        MonoAsyncResult *ares;
        MonoMethod *method = NULL;
  
        if (!delegate->method_info) {
                g_assert (delegate->method);
 -              MONO_OBJECT_SETREF (delegate, method_info, mono_method_get_object (domain, delegate->method, NULL));
 +              MonoReflectionMethod *rm = mono_method_get_object_checked (domain, delegate->method, NULL, &error);
 +              if (!mono_error_ok (&error)) {
 +                      mono_error_set_pending_exception (&error);
 +                      return NULL;
 +              }
 +              MONO_OBJECT_SETREF (delegate, method_info, rm);
        }
  
        if (!delegate->method_info || !delegate->method_info->method)
  
        sig = mono_signature_no_pinvoke (method);
  
 -      msg = mono_method_call_message_new (method, params, NULL, NULL, NULL);
 +      msg = mono_method_call_message_new (method, params, NULL, NULL, NULL, &error);
 +      if (mono_error_set_pending_exception (&error))
 +              return NULL;
  
        ares = (MonoAsyncResult *)mono_array_get (msg->args, gpointer, sig->param_count - 1);
        if (ares == NULL) {
 -              mono_raise_exception (mono_exception_from_name_msg (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingException", "The async result object is null or of an unexpected type."));
 +              mono_set_pending_exception (mono_exception_from_name_msg (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingException", "The async result object is null or of an unexpected type."));
                return NULL;
        }
  
        if (ares->async_delegate != (MonoObject*)delegate) {
 -              mono_raise_exception (mono_get_exception_invalid_operation (
 +              mono_set_pending_exception (mono_get_exception_invalid_operation (
                        "The IAsyncResult object provided does not match this delegate."));
                return NULL;
        }
  #ifndef DISABLE_REMOTING
        if (delegate->target && mono_object_is_transparent_proxy (delegate->target)) {
                MonoTransparentProxy* tp = (MonoTransparentProxy *)delegate->target;
 -              msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
 -              mono_message_init (domain, msg, delegate->method_info, NULL);
 +              msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
 +              if (!mono_error_ok (&error)) {
 +                      mono_error_set_pending_exception (&error);
 +                      return NULL;
 +              }
 +              mono_message_init (domain, msg, delegate->method_info, NULL, &error);
 +              if (mono_error_set_pending_exception (&error))
 +                      return NULL;
                msg->call_type = CallType_EndInvoke;
                MONO_OBJECT_SETREF (msg, async_result, ares);
 -              res = mono_remoting_invoke ((MonoObject *)tp->rp, msg, &exc, &out_args);
 +              res = mono_remoting_invoke ((MonoObject *)tp->rp, msg, &exc, &out_args, &error);
 +              if (!mono_error_ok (&error)) {
 +                      mono_error_set_pending_exception (&error);
 +                      return NULL;
 +              }
        } else
  #endif
        {
 -              res = mono_threadpool_ms_end_invoke (ares, &out_args, &exc);
 +              res = mono_threadpool_ms_end_invoke (ares, &out_args, &exc, &error);
 +              if (mono_error_set_pending_exception (&error))
 +                      return NULL;
        }
  
        if (exc) {
                if (((MonoException*)exc)->stack_trace) {
 -                      char *strace = mono_string_to_utf8 (((MonoException*)exc)->stack_trace);
 -                      char  *tmp;
 -                      tmp = g_strdup_printf ("%s\nException Rethrown at:\n", strace);
 -                      g_free (strace);        
 -                      MONO_OBJECT_SETREF (((MonoException*)exc), stack_trace, mono_string_new (domain, tmp));
 -                      g_free (tmp);
 +                      MonoError inner_error;
 +                      char *strace = mono_string_to_utf8_checked (((MonoException*)exc)->stack_trace, &inner_error);
 +                      if (is_ok (&inner_error)) {
 +                              char  *tmp;
 +                              tmp = g_strdup_printf ("%s\nException Rethrown at:\n", strace);
 +                              g_free (strace);        
 +                              MONO_OBJECT_SETREF (((MonoException*)exc), stack_trace, mono_string_new (domain, tmp));
 +                              g_free (tmp);
 +                      } else
 +                              mono_error_cleanup (&inner_error); /* no stack trace, but at least throw the original exception */
                }
 -              mono_raise_exception ((MonoException*)exc);
 +              mono_set_pending_exception ((MonoException*)exc);
        }
  
 -      mono_method_return_message_restore (method, params, out_args);
 +      mono_method_return_message_restore (method, params, out_args, &error);
 +      mono_error_set_pending_exception (&error);
        return res;
  }
  
@@@ -3261,6 -3010,22 +3261,6 @@@ free_signature_pointer_pair (SignatureP
        g_free (pair);
  }
  
 -static MonoMethodSignature*
 -sig_to_rgctx_sig (MonoMethodSignature *sig)
 -{
 -      // FIXME: memory allocation
 -      MonoMethodSignature *res;
 -      int i;
 -
 -      res = (MonoMethodSignature *)g_malloc (MONO_SIZEOF_METHOD_SIGNATURE + (sig->param_count + 1) * sizeof (MonoType*));
 -      memcpy (res, sig, MONO_SIZEOF_METHOD_SIGNATURE);
 -      res->param_count = sig->param_count + 1;
 -      for (i = 0; i < sig->param_count; ++i)
 -              res->params [i] = sig->params [i];
 -      res->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
 -      return res;
 -}
 -
  MonoMethod *
  mono_marshal_get_delegate_invoke_internal (MonoMethod *method, gboolean callvirt, gboolean static_method_with_first_arg_bound, MonoMethod *target_method)
  {
        MonoMethod *res;
        GHashTable *cache;
        gpointer cache_key = NULL;
 -      SignaturePointerPair key;
 +      SignaturePointerPair key = { NULL, NULL };
        SignaturePointerPair *new_key;
        int local_i, local_len, local_delegates, local_d, local_target, local_res;
 -      int pos0, pos1, pos2, pos3, pos4;
 +      int pos0, pos1, pos2;
        char *name;
        MonoClass *target_class = NULL;
        gboolean closed_over_null = FALSE;
        MonoGenericContext *ctx = NULL;
        MonoGenericContainer *container = NULL;
 -      MonoMethod *orig_method = NULL;
 +      MonoMethod *orig_method = method;
        WrapperInfo *info;
        WrapperSubtype subtype = WRAPPER_SUBTYPE_NONE;
        gboolean found;
        if (callvirt) {
                subtype = WRAPPER_SUBTYPE_DELEGATE_INVOKE_VIRTUAL;
                if (target_method->is_inflated) {
 +                      MonoError error;
                        MonoType *target_type;
  
                        g_assert (method->signature->hasthis);
 -                      target_type = mono_class_inflate_generic_type (method->signature->params [0],
 -                              mono_method_get_context (method));
 +                      target_type = mono_class_inflate_generic_type_checked (method->signature->params [0],
 +                              mono_method_get_context (method), &error);
 +                      mono_error_assert_ok (&error); /* FIXME don't swallow the error */
                        target_class = mono_class_from_mono_type (target_type);
                } else {
                        target_class = target_method->klass;
         * For generic delegates, create a generic wrapper, and return an instance to help AOT.
         */
        if (method->is_inflated && subtype == WRAPPER_SUBTYPE_NONE) {
 -              orig_method = method;
                ctx = &((MonoMethodInflated*)method)->context;
                method = ((MonoMethodInflated*)method)->declaring;
  
                container = mono_method_get_generic_container (method);
                if (!container)
 -                      container = method->klass->generic_container;
 +                      container = mono_class_try_get_generic_container (method->klass); //FIXME is this a case of a try?
                g_assert (container);
  
                invoke_sig = sig = mono_signature_no_pinvoke (method);
        mono_mb_emit_byte (mb, CEE_LDIND_REF);
        mono_mb_emit_stloc (mb, local_delegates);
  
 -
        /* if (delegates == null) */
        mono_mb_emit_ldloc (mb, local_delegates);
        pos2 = mono_mb_emit_branch (mb, CEE_BRTRUE);
                        // FIXME:
                        mono_mb_emit_exception_full (mb, "System", "NotImplementedException", "");
                } else {
 -                      MonoMethodSignature *rgctx_sig;
 -
 -                      // FIXME: Support this for the other cases as well
 -                      mono_mb_emit_ldarg (mb, 0);
 -                      mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, rgctx));
 -                      mono_mb_emit_byte (mb, CEE_LDIND_I);
 -                      pos3 = mono_mb_emit_branch (mb, CEE_BRFALSE);
 -
 -                      /* Rgctx case */
 -                      rgctx_sig = sig_to_rgctx_sig (sig);
 -
                        mono_mb_emit_ldloc (mb, local_target);
                        for (i = 0; i < sig->param_count; ++i)
                                mono_mb_emit_ldarg (mb, i + 1);
                        mono_mb_emit_ldarg (mb, 0);
 -                      mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, rgctx));
 +                      mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, extra_arg));
                        mono_mb_emit_byte (mb, CEE_LDIND_I);
                        mono_mb_emit_ldarg (mb, 0);
                        mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
                        mono_mb_emit_byte (mb, CEE_LDIND_I);
 -                      mono_mb_emit_op (mb, CEE_CALLI, rgctx_sig);
 -                      pos4 = mono_mb_emit_branch (mb, CEE_BR);
 -
 -                      /* Non-rgctx case */
 -                      mono_mb_patch_branch (mb, pos3);
 -                      mono_mb_emit_ldloc (mb, local_target);
 -                      for (i = 0; i < sig->param_count; ++i)
 -                              mono_mb_emit_ldarg (mb, i + 1);
 -                      mono_mb_emit_ldarg (mb, 0);
 -                      mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
 -                      mono_mb_emit_byte (mb, CEE_LDIND_I );
 -                      mono_mb_emit_op (mb, CEE_CALLI, sig);
 -
 -                      mono_mb_patch_branch (mb, pos4);
 -
 +                      mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
 +                      mono_mb_emit_op (mb, CEE_MONO_CALLI_EXTRA_ARG, sig);
                        mono_mb_emit_byte (mb, CEE_RET);
                }
        
                        mono_mb_emit_op (mb, CEE_CALL, target_method);
                }
        } else {
 -              MonoMethodSignature *rgctx_sig;
 -
 -              mono_mb_emit_ldarg (mb, 0);
 -              mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, rgctx));
 -              mono_mb_emit_byte (mb, CEE_LDIND_I);
 -              pos3 = mono_mb_emit_branch (mb, CEE_BRFALSE);
 -
 -              /* Rgctx case */
 -              rgctx_sig = sig_to_rgctx_sig (invoke_sig);
 -
                if (static_method_with_first_arg_bound) {
                        mono_mb_emit_ldloc (mb, local_target);
                        if (!MONO_TYPE_IS_REFERENCE (invoke_sig->params[0]))
                for (i = 0; i < sig->param_count; ++i)
                        mono_mb_emit_ldarg (mb, i + 1);
                mono_mb_emit_ldarg (mb, 0);
 -              mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, rgctx));
 -              mono_mb_emit_byte (mb, CEE_LDIND_I);
 -              mono_mb_emit_ldarg (mb, 0);
 -              mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
 +              mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, extra_arg));
                mono_mb_emit_byte (mb, CEE_LDIND_I);
 -              mono_mb_emit_op (mb, CEE_CALLI, rgctx_sig);
 -              pos4 = mono_mb_emit_branch (mb, CEE_BR);
 -
 -              /* Non-rgctx case */
 -              mono_mb_patch_branch (mb, pos3);
 -              if (static_method_with_first_arg_bound) {
 -                      mono_mb_emit_ldloc (mb, local_target);
 -                      if (!MONO_TYPE_IS_REFERENCE (invoke_sig->params[0]))
 -                              mono_mb_emit_op (mb, CEE_UNBOX_ANY, mono_class_from_mono_type (invoke_sig->params[0]));
 -              }
 -              for (i = 0; i < sig->param_count; ++i)
 -                      mono_mb_emit_ldarg (mb, i + 1);
                mono_mb_emit_ldarg (mb, 0);
                mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
                mono_mb_emit_byte (mb, CEE_LDIND_I);
 -              mono_mb_emit_op (mb, CEE_CALLI, invoke_sig);
 -
 -              mono_mb_patch_branch (mb, pos4);
 +              mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
 +              mono_mb_emit_op (mb, CEE_MONO_CALLI_EXTRA_ARG, invoke_sig);
        }
  
        mono_mb_emit_byte (mb, CEE_RET);
        mb->skip_visibility = 1;
  #endif /* DISABLE_JIT */
  
 +      info = mono_wrapper_info_create (mb, subtype);
 +      info->d.delegate_invoke.method = method;
 +
        if (ctx) {
                MonoMethod *def;
  
 -              def = mono_mb_create_and_cache (cache, cache_key, mb, sig, sig->param_count + 16);
 +              def = mono_mb_create_and_cache_full (cache, cache_key, mb, sig, sig->param_count + 16, info, NULL);
                res = cache_generic_delegate_wrapper (cache, orig_method, def, ctx);
        } else if (callvirt) {
                new_key = g_new0 (SignaturePointerPair, 1);
                *new_key = key;
  
 -              info = mono_wrapper_info_create (mb, subtype);
 -
                res = mono_mb_create_and_cache_full (cache, new_key, mb, sig, sig->param_count + 16, info, &found);
                if (found)
                        g_free (new_key);
        } else {
 -              info = mono_wrapper_info_create (mb, subtype);
 -
                res = mono_mb_create_and_cache_full (cache, cache_key, mb, sig, sig->param_count + 16, info, NULL);
        }
        mono_mb_free (mb);
@@@ -3721,6 -3537,7 +3721,6 @@@ handle_enum
        case MONO_TYPE_CHAR:
                return &mono_defaults.uint16_class->byval_arg;
        case MONO_TYPE_U:
 -      case MONO_TYPE_PTR:
                return &mono_defaults.int_class->byval_arg;
        case MONO_TYPE_VALUETYPE:
                if (t->data.klass->enumtype) {
@@@ -4055,9 -3872,11 +4055,9 @@@ emit_runtime_invoke_body (MonoMethodBui
   * it means that the compiled code for METHOD does not have to be looked up 
   * before calling the runtime invoke wrapper. In this case, the wrapper ignores
   * its METHOD argument.
 - * If PASS_RGCTX is TRUE, the signature of the called method is changed to include a 'gpointer rgctx' as the
 - * last argument (after 'this').
   */
  MonoMethod *
 -mono_marshal_get_runtime_invoke (MonoMethod *method, gboolean virtual_, gboolean pass_rgctx)
 +mono_marshal_get_runtime_invoke (MonoMethod *method, gboolean virtual_)
  {
        MonoMethodSignature *sig, *csig, *callsig;
        MonoMethodBuilder *mb;
  
        sig = mono_method_signature (method);
  
 -      if (pass_rgctx) {
 -              sig = sig_to_rgctx_sig (sig);
 -              callsig = sig_to_rgctx_sig (callsig);
 -      }
 -
        target_klass = get_wrapper_target_class (method->klass->image);
  
        /* Try to share wrappers for non-corlib methods with simple signatures */
        csig->call_convention = MONO_CALL_C;
  #endif
  
 -      name = mono_signature_to_name (callsig, pass_rgctx ? (virtual_ ? "runtime_invoke_virtual_rgctx" : "runtime_invoke_rgctx") : (virtual_ ? "runtime_invoke_virtual" : "runtime_invoke"));
 +      name = mono_signature_to_name (callsig, virtual_ ? "runtime_invoke_virtual" : "runtime_invoke");
        mb = mono_mb_new (target_klass, name,  MONO_WRAPPER_RUNTIME_INVOKE);
        g_free (name);
  
  
                info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_RUNTIME_INVOKE_NORMAL);
                info->d.runtime_invoke.sig = callsig;
 -              info->d.runtime_invoke.pass_rgctx = pass_rgctx;
  
                /* Somebody may have created it before us */
                if (!res) {
   * ARGS should contain the this argument too.
   * This wrapper serves the same purpose as the runtime-invoke wrappers, but there
   * is only one copy of it, which is useful in full-aot.
 - * The wrapper info for the wrapper is a WrapperInfo structure.
   */
  MonoMethod*
  mono_marshal_get_runtime_invoke_dynamic (void)
@@@ -4480,6 -4306,7 +4480,6 @@@ mono_mb_emit_auto_layout_exception (Mon
  /*
   * generates IL code for the icall wrapper (the generated method
   * calls the unmanaged code in func)
 - * The wrapper info for the wrapper is a WrapperInfo structure.
   */
  MonoMethod *
  mono_marshal_get_icall_wrapper (MonoMethodSignature *sig, const char *name, gconstpointer func, gboolean check_exceptions)
        int i;
        WrapperInfo *info;
        
 +      GHashTable *cache = get_cache (&mono_defaults.object_class->image->icall_wrapper_cache, mono_aligned_addr_hash, NULL);
 +      if ((res = mono_marshal_find_in_cache (cache, (gpointer) func)))
 +              return res;
 +
        g_assert (sig->pinvoke);
  
        mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_MANAGED_TO_NATIVE);
  
        info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_ICALL_WRAPPER);
        info->d.icall.func = (gpointer)func;
 -      res = mono_mb_create (mb, csig, csig->param_count + 16, info);
 +      res = mono_mb_create_and_cache_full (cache, (gpointer) func, mb, csig, csig->param_count + 16, info, NULL);
        mono_mb_free (mb);
  
        return res;
@@@ -4545,7 -4368,6 +4545,7 @@@ emit_marshal_custom (EmitMarshalContex
                *conv_arg_type = &mono_defaults.int_class->byval_arg;
        return conv_arg;
  #else
 +      MonoError error;
        MonoType *mtype;
        MonoClass *mklass;
        static MonoClass *ICustomMarshaler = NULL;
        int pos2;
  
        if (!ICustomMarshaler) {
 -              MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "ICustomMarshaler");
 +              MonoClass *klass = mono_class_try_get_icustom_marshaler_class ();
                if (!klass) {
                        exception_msg = g_strdup ("Current profile doesn't support ICustomMarshaler");
                        goto handle_exception;
        }
  
        if (spec->data.custom_data.image)
 -              mtype = mono_reflection_type_from_name (spec->data.custom_data.custom_name, spec->data.custom_data.image);
 +              mtype = mono_reflection_type_from_name_checked (spec->data.custom_data.custom_name, spec->data.custom_data.image, &error);
        else
 -              mtype = mono_reflection_type_from_name (spec->data.custom_data.custom_name, m->image);
 +              mtype = mono_reflection_type_from_name_checked (spec->data.custom_data.custom_name, m->image, &error);
        g_assert (mtype != NULL);
 +      mono_error_assert_ok (&error);
        mklass = mono_class_from_mono_type (mtype);
        g_assert (mklass != NULL);
  
@@@ -4911,7 -4732,7 +4911,7 @@@ emit_marshal_vtype (EmitMarshalContext 
  
        klass = mono_class_from_mono_type (t);
  
 -      date_time_class = mono_class_from_name_cached (mono_defaults.corlib, "System", "DateTime");
 +      date_time_class = mono_class_get_date_time_class ();
  
        switch (action) {
        case MARSHAL_ACTION_CONV_IN:
                        break;
                }
  
 -              if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
 -                      klass->blittable || klass->enumtype)
 +              if (mono_class_is_explicit_layout (klass) || klass->blittable || klass->enumtype)
                        break;
  
                conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
                        /* Have to change the signature since the vtype is passed byref */
                        m->csig->params [argnum - m->csig->hasthis] = &mono_defaults.int_class->byval_arg;
  
 -                      if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
 -                              klass->blittable || klass->enumtype)
 +                      if (mono_class_is_explicit_layout (klass) || klass->blittable || klass->enumtype)
                                mono_mb_emit_ldarg_addr (mb, argnum);
                        else
                                mono_mb_emit_ldloc (mb, conv_arg);
                        break;
                }
  
 -              if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
 -                      klass->blittable || klass->enumtype) {
 +              if (mono_class_is_explicit_layout (klass) || klass->blittable || klass->enumtype) {
                        mono_mb_emit_ldarg (mb, argnum);
                        break;
                }                       
                        break;
                }
  
 -              if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
 -                      klass->blittable || klass->enumtype)
 +              if (mono_class_is_explicit_layout (klass) || klass->blittable || klass->enumtype)
                        break;
  
                if (t->byref) {
                break;
  
        case MARSHAL_ACTION_CONV_RESULT:
 -              if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
 -                      klass->blittable) {
 +              if (mono_class_is_explicit_layout (klass) || klass->blittable) {
                        mono_mb_emit_stloc (mb, 3);
                        break;
                }
  
                /* load pointer to returned value type */
 -              mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
 -              mono_mb_emit_byte (mb, CEE_MONO_VTADDR);
 +              g_assert (m->vtaddr_var);
 +              mono_mb_emit_ldloc (mb, m->vtaddr_var);
                /* store the address of the source into local variable 0 */
                mono_mb_emit_stloc (mb, 0);
                /* set dst_ptr */
                break;
  
        case MARSHAL_ACTION_MANAGED_CONV_IN:
 -              if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
 -                      klass->blittable || klass->enumtype) {
 +              if (mono_class_is_explicit_layout (klass) || klass->blittable || klass->enumtype) {
                        conv_arg = 0;
                        break;
                }
                break;
  
        case MARSHAL_ACTION_MANAGED_CONV_OUT:
 -              if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
 -                      klass->blittable || klass->enumtype) {
 +              if (mono_class_is_explicit_layout (klass) || klass->blittable || klass->enumtype)
                        break;
 -              }
 -
                if (t->byref && (t->attrs & PARAM_ATTRIBUTE_IN) && !(t->attrs & PARAM_ATTRIBUTE_OUT))
                        break;
  
                break;
  
        case MARSHAL_ACTION_MANAGED_CONV_RESULT:
 -              if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
 -                      klass->blittable || klass->enumtype) {
 +              if (mono_class_is_explicit_layout (klass) || klass->blittable || klass->enumtype) {
                        mono_mb_emit_stloc (mb, 3);
                        m->retobj_var = 0;
                        break;
                }
                        
                /* load pointer to returned value type */
 -              mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
 -              mono_mb_emit_byte (mb, CEE_MONO_VTADDR);
 +              g_assert (m->vtaddr_var);
 +              mono_mb_emit_ldloc (mb, m->vtaddr_var);
                        
                /* store the address of the source into local variable 0 */
                mono_mb_emit_stloc (mb, 0);
                g_assert (m->retobj_var);
                mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
                mono_mb_emit_byte (mb, CEE_CONV_I);
 -              mono_mb_emit_icall (mb, mono_marshal_alloc);
 +              mono_mb_emit_icall (mb, ves_icall_marshal_alloc);
                mono_mb_emit_stloc (mb, 1);
                mono_mb_emit_ldloc (mb, 1);
                mono_mb_emit_stloc (mb, m->retobj_var);
@@@ -5211,11 -5042,11 +5211,11 @@@ emit_marshal_string (EmitMarshalContex
                        mono_mb_emit_ldarg (mb, argnum);
                }
  
 -              if (conv == -1) {
 +              if (conv == MONO_MARSHAL_CONV_INVALID) {
                        char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding);
                        mono_mb_emit_exception_marshal_directive (mb, msg);
                } else {
 -                      mono_mb_emit_icall (mb, conv_to_icall (conv));
 +                      mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
  
                        mono_mb_emit_stloc (mb, conv_arg);
                }
  
        case MARSHAL_ACTION_CONV_OUT:
                conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free);
 -              if (conv == -1) {
 +              if (conv == MONO_MARSHAL_CONV_INVALID) {
                        char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding);
                        mono_mb_emit_exception_marshal_directive (mb, msg);
                        break;
                        mono_mb_emit_icall (mb, mono_string_new_len_wrapper);
                        mono_mb_emit_byte (mb, CEE_STIND_REF);
                } else if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT || !(t->attrs & PARAM_ATTRIBUTE_IN))) {
 +                      int stind_op;
                        mono_mb_emit_ldarg (mb, argnum);
                        mono_mb_emit_ldloc (mb, conv_arg);
 -                      mono_mb_emit_icall (mb, conv_to_icall (conv));
 -                      mono_mb_emit_byte (mb, CEE_STIND_REF);
 +                      mono_mb_emit_icall (mb, conv_to_icall (conv, &stind_op));
 +                      mono_mb_emit_byte (mb, stind_op);
                        need_free = TRUE;
                }
  
                mono_mb_emit_stloc (mb, 0);
                                
                conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free);
 -              if (conv == -1) {
 +              if (conv == MONO_MARSHAL_CONV_INVALID) {
                        char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding);
                        mono_mb_emit_exception_marshal_directive (mb, msg);
                        break;
                }
  
                mono_mb_emit_ldloc (mb, 0);
 -              mono_mb_emit_icall (mb, conv_to_icall (conv));
 +              mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
                mono_mb_emit_stloc (mb, 3);
  
                /* free the string */
                }
  
                conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free);
 -              if (conv == -1) {
 +              if (conv == MONO_MARSHAL_CONV_INVALID) {
                        char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding);
                        mono_mb_emit_exception_marshal_directive (mb, msg);
                        break;
                mono_mb_emit_ldarg (mb, argnum);
                if (t->byref)
                        mono_mb_emit_byte (mb, CEE_LDIND_I);
 -              mono_mb_emit_icall (mb, conv_to_icall (conv));
 +              mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
                mono_mb_emit_stloc (mb, conv_arg);
                break;
  
        case MARSHAL_ACTION_MANAGED_CONV_OUT:
                if (t->byref) {
                        if (conv_arg) {
 +                              int stind_op;
                                mono_mb_emit_ldarg (mb, argnum);
                                mono_mb_emit_ldloc (mb, conv_arg);
 -                              mono_mb_emit_icall (mb, conv_to_icall (conv));
 -                              mono_mb_emit_byte (mb, CEE_STIND_I);
 +                              mono_mb_emit_icall (mb, conv_to_icall (conv, &stind_op));
 +                              mono_mb_emit_byte (mb, stind_op);
                        }
                }
                break;
  
        case MARSHAL_ACTION_MANAGED_CONV_RESULT:
 -              if (conv_to_icall (conv) == mono_marshal_string_to_utf16)
 +              if (conv_to_icall (conv, NULL) == mono_marshal_string_to_utf16)
                        /* We need to make a copy so the caller is able to free it */
                        mono_mb_emit_icall (mb, mono_marshal_string_to_utf16_copy);
                else
 -                      mono_mb_emit_icall (mb, conv_to_icall (conv));
 +                      mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
                mono_mb_emit_stloc (mb, 3);
                break;
  
@@@ -5472,7 -5301,7 +5472,7 @@@ emit_marshal_safehandle (EmitMarshalCon
                MonoMethod *ctor = NULL;
                int intptr_handle_slot;
                
 -              if (t->data.klass->flags & TYPE_ATTRIBUTE_ABSTRACT){
 +              if (mono_class_is_abstract (t->data.klass)) {
                        mono_mb_emit_byte (mb, CEE_POP);
                        mono_mb_emit_exception_marshal_directive (mb, g_strdup ("Returned SafeHandles should not be abstract"));
                        break;
@@@ -5622,7 -5451,7 +5622,7 @@@ emit_marshal_object (EmitMarshalContex
                                mono_mb_emit_stloc (mb, conv_arg);
                        } else {
                                mono_mb_emit_ldarg (mb, argnum);
 -                              mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN));
 +                              mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN, NULL));
                                mono_mb_emit_stloc (mb, conv_arg);
                        }
                } else if (klass == mono_defaults.stringbuilder_class) {
                        if (t->byref && !(t->attrs & PARAM_ATTRIBUTE_IN) && (t->attrs & PARAM_ATTRIBUTE_OUT))
                                break;
  
 -                      if (conv == -1) {
 +                      if (conv == MONO_MARSHAL_CONV_INVALID) {
                                char *msg = g_strdup_printf ("stringbuilder marshalling conversion %d not implemented", encoding);
                                mono_mb_emit_exception_marshal_directive (mb, msg);
                                break;
                        if (t->byref)
                                mono_mb_emit_byte (mb, CEE_LDIND_I);
  
 -                      mono_mb_emit_icall (mb, conv_to_icall (conv));
 +                      mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
                        mono_mb_emit_stloc (mb, conv_arg);
                } else if (klass->blittable) {
                        mono_mb_emit_byte (mb, CEE_LDNULL);
                                case MONO_NATIVE_LPSTR:
                                        mono_mb_emit_icall (mb, mono_string_utf8_to_builder2);
                                        break;
 +                              case MONO_NATIVE_UTF8STR:
 +                                      mono_mb_emit_icall (mb, mono_string_utf8_to_builder2);
 +                                      break;
                                default:
                                        g_assert_not_reached ();
                                }
                                mono_mb_emit_ldarg (mb, argnum);
                                mono_mb_emit_ldloc (mb, conv_arg);
  
 -                              mono_mb_emit_icall (mb, conv_to_icall (conv));
 +                              mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
                        }
  
                        if (need_free) {
                                mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
                                mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass);
                                mono_mb_emit_ldloc (mb, conv_arg);
 -                              mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL));
 +                              mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL, NULL));
                                mono_mb_emit_byte (mb, CEE_STIND_REF);
                        }
                        break;
                        mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
                        mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass);
                        mono_mb_emit_ldloc (mb, 0);
 -                      mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL));
 +                      mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL, NULL));
                        mono_mb_emit_stloc (mb, 3);
 +              } else if (klass == mono_defaults.stringbuilder_class){
 +                      // FIXME: implement
                } else {
                        /* set src */
                        mono_mb_emit_stloc (mb, 0);
                        mono_mb_emit_ldarg (mb, argnum);
                        if (t->byref)
                                mono_mb_emit_byte (mb, CEE_LDIND_I);
 -                      mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL));
 +                      mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL, NULL));
                        mono_mb_emit_stloc (mb, conv_arg);
                        break;
                }
                        encoding = mono_marshal_get_string_encoding (m->piinfo, spec);
  
                        // FIXME:
 -                      g_assert (encoding == MONO_NATIVE_LPSTR);
 +                      g_assert (encoding == MONO_NATIVE_LPSTR || encoding == MONO_NATIVE_UTF8STR);
  
                        g_assert (!t->byref);
                        g_assert (encoding != -1);
                }
  
                /* The class can not have an automatic layout */
 -              if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT) {
 +              if (mono_class_is_auto_layout (klass)) {
                        mono_mb_emit_auto_layout_exception (mb, klass);
                        break;
                }
        case MARSHAL_ACTION_MANAGED_CONV_OUT:
                if (klass->delegate) {
                        if (t->byref) {
 +                              int stind_op;
                                mono_mb_emit_ldarg (mb, argnum);
                                mono_mb_emit_ldloc (mb, conv_arg);
 -                              mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN));
 -                              mono_mb_emit_byte (mb, CEE_STIND_I);
 +                              mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN, &stind_op));
 +                              mono_mb_emit_byte (mb, stind_op);
                                break;
                        }
                }
                        /* Allocate and set dest */
                        mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
                        mono_mb_emit_byte (mb, CEE_CONV_I);
 -                      mono_mb_emit_icall (mb, mono_marshal_alloc);
 +                      mono_mb_emit_icall (mb, ves_icall_marshal_alloc);
                        mono_mb_emit_stloc (mb, 1);
                        
                        /* Update argument pointer */
  
        case MARSHAL_ACTION_MANAGED_CONV_RESULT:
                if (klass->delegate) {
 -                      mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN));
 +                      mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN, NULL));
                        mono_mb_emit_stloc (mb, 3);
                        break;
                }
  
                /* The class can not have an automatic layout */
 -              if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT) {
 +              if (mono_class_is_auto_layout (klass)) {
                        mono_mb_emit_auto_layout_exception (mb, klass);
                        break;
                }
                /* Allocate and set dest */
                mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
                mono_mb_emit_byte (mb, CEE_CONV_I);
 -              mono_mb_emit_icall (mb, mono_marshal_alloc);
 +              mono_mb_emit_icall (mb, ves_icall_marshal_alloc);
                mono_mb_emit_byte (mb, CEE_DUP);
                mono_mb_emit_stloc (mb, 1);
                mono_mb_emit_stloc (mb, 3);
@@@ -6262,7 -6085,7 +6262,7 @@@ emit_marshal_array (EmitMarshalContext 
                        mono_mb_emit_ldarg (mb, argnum);
                        if (t->byref)
                                mono_mb_emit_byte (mb, CEE_LDIND_I);
 -                      mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_ARRAY_LPARRAY));
 +                      mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_ARRAY_LPARRAY, NULL));
                        mono_mb_emit_stloc (mb, conv_arg);
                } else {
                        MonoClass *eklass;
                                conv = mono_marshal_get_stringbuilder_to_ptr_conv (m->piinfo, spec);
                        }
                        else
 -                              conv = (MonoMarshalConv)-1;
 +                              conv = MONO_MARSHAL_CONV_INVALID;
  
 -                      if (is_string && conv == -1) {
 +                      if (is_string && conv == MONO_MARSHAL_CONV_INVALID) {
                                char *msg = g_strdup_printf ("string/stringbuilder marshalling conversion %d not implemented", encoding);
                                mono_mb_emit_exception_marshal_directive (mb, msg);
                                break;
                        /* Emit marshalling code */
  
                        if (is_string) {
 +                              int stind_op;
                                mono_mb_emit_ldloc (mb, dest_ptr);
                                mono_mb_emit_ldloc (mb, src_var);
                                mono_mb_emit_ldloc (mb, index_var);
                                mono_mb_emit_byte (mb, CEE_LDELEM_REF);
 -                              mono_mb_emit_icall (mb, conv_to_icall (conv));
 -                              mono_mb_emit_byte (mb, CEE_STIND_I);
 +                              mono_mb_emit_icall (mb, conv_to_icall (conv, &stind_op));
 +                              mono_mb_emit_byte (mb, stind_op);
                        } else {
                                /* set the src_ptr */
                                mono_mb_emit_ldloc (mb, src_var);
                                mono_mb_emit_stloc (mb, 1);
  
                                /* emit valuetype conversion code */
 -                              emit_struct_conv_full (mb, eklass, FALSE, eklass == mono_defaults.char_class ? encoding : (MonoMarshalNative)-1);
 +                              emit_struct_conv_full (mb, eklass, FALSE, 0, eklass == mono_defaults.char_class ? encoding : (MonoMarshalNative)-1);
                        }
  
                        mono_mb_emit_add_to_local (mb, index_var, 1);
                                mono_mb_emit_byte (mb, CEE_CONV_OVF_I);
                                mono_mb_emit_op (mb, CEE_NEWARR, klass->element_class);
                                /* Store into argument */
 -                              mono_mb_emit_byte (mb, CEE_STIND_I);
 +                              mono_mb_emit_byte (mb, CEE_STIND_REF);
                        }
                }
  
                                gboolean need_free2;
                                MonoMarshalConv conv = mono_marshal_get_ptr_to_stringbuilder_conv (m->piinfo, spec, &need_free2);
  
 -                              g_assert (conv != -1);
 +                              g_assert (conv != MONO_MARSHAL_CONV_INVALID);
  
                                /* dest */
                                mono_mb_emit_ldarg (mb, argnum);
                                mono_mb_emit_ldloc (mb, src_ptr);
                                mono_mb_emit_byte (mb, CEE_LDIND_I);
  
 -                              mono_mb_emit_icall (mb, conv_to_icall (conv));
 +                              mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
  
                                if (need_free) {
                                        /* src */
                                        mono_mb_emit_stloc (mb, 1);
  
                                        /* emit valuetype conversion code */
 -                                      emit_struct_conv_full (mb, eklass, TRUE, eklass == mono_defaults.char_class ? encoding : (MonoMarshalNative)-1);
 +                                      emit_struct_conv_full (mb, eklass, TRUE, 0, eklass == mono_defaults.char_class ? encoding : (MonoMarshalNative)-1);
                                }
  
                                if (need_free) {
                        if (t->byref)
                                mono_mb_emit_byte (mb, CEE_LDIND_REF);
                        mono_mb_emit_ldloc (mb, conv_arg);
 -                      mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_FREE_LPARRAY));
 +                      mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_FREE_LPARRAY, NULL));
                }
  
                break;
                        conv = mono_marshal_get_ptr_to_stringbuilder_conv (m->piinfo, spec, &need_free);
                }
                else
 -                      conv = (MonoMarshalConv)-1;
 +                      conv = MONO_MARSHAL_CONV_INVALID;
  
                mono_marshal_load_type_info (eklass);
  
                        mono_mb_emit_icon (mb, esize);
                        mono_mb_emit_byte (mb, CEE_MUL);
                        mono_mb_emit_byte (mb, CEE_PREFIX1);
 -                      mono_mb_emit_byte (mb, CEE_CPBLK);                      
 +                      mono_mb_emit_byte (mb, CEE_CPBLK);
 +                      mono_mb_patch_branch (mb, label1);
                        break;
                }
  
  
                /* Emit marshalling code */
                if (is_string) {
 -                      g_assert (conv != -1);
 +                      g_assert (conv != MONO_MARSHAL_CONV_INVALID);
  
                        mono_mb_emit_ldloc (mb, conv_arg);
                        mono_mb_emit_ldloc (mb, index_var);
                        mono_mb_emit_ldloc (mb, src_ptr);
                        mono_mb_emit_byte (mb, CEE_LDIND_I);
  
 -                      mono_mb_emit_icall (mb, conv_to_icall (conv));
 +                      mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
                        mono_mb_emit_byte (mb, CEE_STELEM_REF);
                }
                else {
                        conv = mono_marshal_get_stringbuilder_to_ptr_conv (m->piinfo, spec);
                }
                else
 -                      conv = (MonoMarshalConv)-1;
 +                      conv = MONO_MARSHAL_CONV_INVALID;
  
                mono_marshal_load_type_info (eklass);
  
  
                /* Emit marshalling code */
                if (is_string) {
 -                      g_assert (conv != -1);
 +                      int stind_op;
 +                      g_assert (conv != MONO_MARSHAL_CONV_INVALID);
  
                        /* dest */
                        mono_mb_emit_ldloc (mb, dest_ptr);
  
                        mono_mb_emit_byte (mb, CEE_LDELEM_REF);
  
 -                      mono_mb_emit_icall (mb, conv_to_icall (conv));
 -                      mono_mb_emit_byte (mb, CEE_STIND_I);
 +                      mono_mb_emit_icall (mb, conv_to_icall (conv, &stind_op));
 +                      mono_mb_emit_byte (mb, stind_op);
                }
                else {
                        char *msg = g_strdup ("Marshalling of non-string and non-blittable arrays to managed code is not implemented.");
                MonoClass *eklass;
                guint32 label1, label2, label3;
                int index_var, src, dest, esize;
 -              MonoMarshalConv conv = (MonoMarshalConv)-1;
 +              MonoMarshalConv conv = MONO_MARSHAL_CONV_INVALID;
                gboolean is_string = FALSE;
                
                g_assert (!t->byref);
                        mono_mb_emit_byte (mb, CEE_ADD);
                }
                mono_mb_emit_byte (mb, CEE_MUL);
 -              mono_mb_emit_icall (mb, mono_marshal_alloc);
 +              mono_mb_emit_icall (mb, ves_icall_marshal_alloc);
                mono_mb_emit_stloc (mb, dest);
                mono_mb_emit_ldloc (mb, dest);
                mono_mb_emit_stloc (mb, 3);
  
                /* Emit marshalling code */
                if (is_string) {
 -                      g_assert (conv != -1);
 +                      int stind_op;
 +                      g_assert (conv != MONO_MARSHAL_CONV_INVALID);
  
                        /* dest */
                        mono_mb_emit_ldloc (mb, dest);
  
                        mono_mb_emit_byte (mb, CEE_LDELEM_REF);
  
 -                      mono_mb_emit_icall (mb, conv_to_icall (conv));
 -                      mono_mb_emit_byte (mb, CEE_STIND_I);
 +                      mono_mb_emit_icall (mb, conv_to_icall (conv, &stind_op));
 +                      mono_mb_emit_byte (mb, stind_op);
                }
                else {
                        char *msg = g_strdup ("Marshalling of non-string arrays to managed code is not implemented.");
@@@ -7281,12 -7100,10 +7281,12 @@@ emit_marshal (EmitMarshalContext *m, in
                return emit_marshal_string (m, argnum, t, spec, conv_arg, conv_arg_type, action);
        case MONO_TYPE_CLASS:
        case MONO_TYPE_OBJECT:
 -#ifndef DISABLE_COM
 +#if !defined(DISABLE_COM) && !defined(DISABLE_JIT)
                if (spec && spec->native == MONO_NATIVE_STRUCT)
                        return emit_marshal_variant (m, argnum, t, spec, conv_arg, conv_arg_type, action);
 +#endif
  
 +#if !defined(DISABLE_COM)
                if (spec && (spec->native == MONO_NATIVE_IUNKNOWN ||
                        spec->native == MONO_NATIVE_IDISPATCH ||
                        spec->native == MONO_NATIVE_INTERFACE))
                        return mono_cominterop_emit_marshal_safearray (m, argnum, t, spec, conv_arg, conv_arg_type, action);
  #endif
  
 -              if (mono_defaults.safehandle_class != NULL && t->data.klass &&
 -                  mono_class_is_subclass_of (t->data.klass,  mono_defaults.safehandle_class, FALSE))
 +              if (mono_class_try_get_safehandle_class () != NULL && t->data.klass &&
 +                  mono_class_is_subclass_of (t->data.klass,  mono_class_try_get_safehandle_class (), FALSE))
                        return emit_marshal_safehandle (m, argnum, t, spec, conv_arg, conv_arg_type, action);
                
                return emit_marshal_object (m, argnum, t, spec, conv_arg, conv_arg_type, action);
@@@ -7357,6 -7174,7 +7357,6 @@@ mono_marshal_emit_native_wrapper (MonoI
        MonoClass *klass;
        int i, argnum, *tmp_locals;
        int type, param_shift = 0;
 -      static MonoMethodSignature *get_last_error_sig = NULL;
        int coop_gc_stack_dummy, coop_gc_var;
  
        memset (&m, 0, sizeof (m));
        mono_mb_emit_icon (mb, 0);
        mono_mb_emit_stloc (mb, 2);
  
 -      if (!MONO_TYPE_IS_VOID(sig->ret)) {
 +      if (!MONO_TYPE_IS_VOID (sig->ret)) {
                /* allocate local 3 to store the return value */
                mono_mb_add_local (mb, sig->ret);
        }
                coop_gc_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
        }
  
 -      if (mspecs [0] && mspecs [0]->native == MONO_NATIVE_CUSTOM) {
 -              /* Return type custom marshaling */
 -              /*
 -               * Since we can't determine the return type of the unmanaged function,
 +      /*
 +       * cookie = mono_threads_enter_gc_safe_region_unbalanced (ref dummy);
 +       *
 +       * ret = method (...);
 +       *
 +       * mono_threads_exit_gc_safe_region_unbalanced (cookie, ref dummy);
 +       *
 +       * <interrupt check>
 +       *
 +       * return ret;
 +       */
 +
 +      if (MONO_TYPE_ISSTRUCT (sig->ret))
 +              m.vtaddr_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
 +
 +      if (mspecs [0] && mspecs [0]->native == MONO_NATIVE_CUSTOM) {
 +              /* Return type custom marshaling */
 +              /*
 +               * Since we can't determine the return type of the unmanaged function,
                 * we assume it returns a pointer, and pass that pointer to
                 * MarshalNativeToManaged.
                 */
                tmp_locals [i] = emit_marshal (&m, i + param_shift, sig->params [i], mspecs [i + 1], 0, &csig->params [i], MARSHAL_ACTION_CONV_IN);
        }
  
 +      // In coop mode need to register blocking state during native call
 +      if (mono_threads_is_coop_enabled ()) {
 +              // Perform an extra, early lookup of the function address, so any exceptions
 +              // potentially resulting from the lookup occur before entering blocking mode.
 +              if (!func_param && !MONO_CLASS_IS_IMPORT (mb->method->klass) && aot) {
 +                      mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
 +                      mono_mb_emit_op (mb, CEE_MONO_ICALL_ADDR, &piinfo->method);
 +                      mono_mb_emit_byte (mb, CEE_POP); // Result not needed yet
 +              }
 +
 +              mono_mb_emit_ldloc_addr (mb, coop_gc_stack_dummy);
 +              mono_mb_emit_icall (mb, mono_threads_enter_gc_safe_region_unbalanced);
 +              mono_mb_emit_stloc (mb, coop_gc_var);
 +      }
 +
        /* push all arguments */
  
        if (sig->hasthis)
                emit_marshal (&m, i + param_shift, sig->params [i], mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_PUSH);
        }                       
  
 -      if (mono_threads_is_coop_enabled ()) {
 -              mono_mb_emit_ldloc_addr (mb, coop_gc_stack_dummy);
 -              mono_mb_emit_icall (mb, mono_threads_prepare_blocking);
 -              mono_mb_emit_stloc (mb, coop_gc_var);
 -      }
 -
        /* call the native method */
        if (func_param) {
                mono_mb_emit_byte (mb, CEE_LDARG_0);
  #else
                g_assert_not_reached ();
  #endif
 -      }
 -      else {
 +      } else {
                if (aot) {
                        /* Reuse the ICALL_ADDR opcode for pinvokes too */
                        mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
  
        /* Set LastError if needed */
        if (piinfo->piflags & PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR) {
 -              if (!get_last_error_sig) {
 -                      get_last_error_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
 -                      get_last_error_sig->ret = &mono_defaults.int_class->byval_arg;
 -                      get_last_error_sig->pinvoke = 1;
 -              }
 -
  #ifdef TARGET_WIN32
 -              /* 
 -               * Have to call GetLastError () early and without a wrapper, since various runtime components could
 -               * clobber its value.
 -               */
 -              mono_mb_emit_native_call (mb, get_last_error_sig, GetLastError);
 -              mono_mb_emit_icall (mb, mono_marshal_set_last_error_windows);
 +              if (!aot) {
 +                      static MonoMethodSignature *get_last_error_sig = NULL;
 +                      if (!get_last_error_sig) {
 +                              get_last_error_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
 +                              get_last_error_sig->ret = &mono_defaults.int_class->byval_arg;
 +                              get_last_error_sig->pinvoke = 1;
 +                      }
 +
 +                      /*
 +                       * Have to call GetLastError () early and without a wrapper, since various runtime components could
 +                       * clobber its value.
 +                       */
 +                      mono_mb_emit_native_call (mb, get_last_error_sig, GetLastError);
 +                      mono_mb_emit_icall (mb, mono_marshal_set_last_error_windows);
 +              } else {
 +                      mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
 +                      mono_mb_emit_byte (mb, CEE_MONO_GET_LAST_ERROR);
 +                      mono_mb_emit_icall (mb, mono_marshal_set_last_error_windows);
 +              }
  #else
                mono_mb_emit_icall (mb, mono_marshal_set_last_error);
  #endif
 -      }               
 +      }
 +
 +      if (MONO_TYPE_ISSTRUCT (sig->ret)) {
 +              MonoClass *klass = mono_class_from_mono_type (sig->ret);
 +              mono_class_init (klass);
 +              if (!(mono_class_is_explicit_layout (klass) || klass->blittable)) {
 +                      /* This is used by emit_marshal_vtype (), but it needs to go right before the call */
 +                      mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
 +                      mono_mb_emit_byte (mb, CEE_MONO_VTADDR);
 +                      mono_mb_emit_stloc (mb, m.vtaddr_var);
 +              }
 +      }
  
 +      /* Unblock before converting the result, since that can involve calls into the runtime */
        if (mono_threads_is_coop_enabled ()) {
                mono_mb_emit_ldloc (mb, coop_gc_var);
                mono_mb_emit_ldloc_addr (mb, coop_gc_stack_dummy);
 -              mono_mb_emit_icall (mb, mono_threads_finish_blocking);
 +              mono_mb_emit_icall (mb, mono_threads_exit_gc_safe_region_unbalanced);
        }
  
        /* convert the result */
                if (spec && spec->native == MONO_NATIVE_CUSTOM) {
                        emit_marshal (&m, 0, sig->ret, spec, 0, NULL, MARSHAL_ACTION_CONV_RESULT);
                } else {
 -
                handle_enum:
                        switch (type) {
                        case MONO_TYPE_VOID:
   *
   * generates IL code for the pinvoke wrapper (the generated method
   * calls the unmanaged code in piinfo->addr)
 - * The wrapper info for the wrapper is a WrapperInfo structure.
   */
  MonoMethod *
  mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions, gboolean aot)
                else
                        csig = mono_metadata_signature_dup_full (method->klass->image, sig);
  
 +              //printf ("%s\n", mono_method_full_name (method, 1));
 +
                /* hack - string constructors returns a value */
                if (method->string_ctor)
                        csig->ret = &mono_defaults.string_class->byval_arg;
  
  #ifndef DISABLE_JIT
 +              // FIXME:
 +              MonoClass *handle_stack_mark_class;
 +              MonoClass *error_class;
 +              int thread_info_var = -1, stack_mark_var = -1, error_var = -1;
 +              MonoMethodSignature *call_sig = csig;
 +              gboolean uses_handles = FALSE;
 +              (void) mono_lookup_internal_call_full (method, &uses_handles);
 +
 +
 +              /* If it uses handles and MonoError, it had better check exceptions */
 +              g_assert (!uses_handles || check_exceptions);
 +
 +              if (uses_handles) {
 +                      MonoMethodSignature *ret;
 +
 +                      /* Add a MonoError argument */
 +                      // FIXME: The stuff from mono_metadata_signature_dup_internal_with_padding ()
 +                      ret = mono_metadata_signature_alloc (method->klass->image, csig->param_count + 1);
 +
 +                      ret->param_count = csig->param_count + 1;
 +                      ret->ret = csig->ret;
 +                      for (int i = 0; i < csig->param_count; ++i) {
 +                              // FIXME: TODO implement handle wrapping for out and inout params.
 +                              g_assert (!mono_signature_param_is_out (csig, i));
 +                              ret->params [i] = csig->params [i];
 +                      }
 +                      ret->params [csig->param_count] = &mono_get_intptr_class ()->byval_arg;
 +                      call_sig = ret;
 +              }
 +
 +              if (uses_handles) {
 +                      handle_stack_mark_class = mono_class_load_from_name (mono_get_corlib (), "Mono", "RuntimeStructs/HandleStackMark");
 +                      error_class = mono_class_load_from_name (mono_get_corlib (), "Mono", "RuntimeStructs/MonoError");
 +
 +                      thread_info_var = mono_mb_add_local (mb, &mono_get_intptr_class ()->byval_arg);
 +                      stack_mark_var = mono_mb_add_local (mb, &handle_stack_mark_class->byval_arg);
 +                      error_var = mono_mb_add_local (mb, &error_class->byval_arg);
 +
 +                      // FIXME: Change csig so it passes a handle not an objref
 +              }
 +
                if (sig->hasthis) {
                        int pos;
  
                        pos = mono_mb_emit_branch (mb, CEE_BRTRUE);
                        mono_mb_emit_exception (mb, "NullReferenceException", NULL);
                        mono_mb_patch_branch (mb, pos);
 -
 -                      mono_mb_emit_byte (mb, CEE_LDARG_0);
                }
  
 -              for (i = 0; i < sig->param_count; i++)
 -                      mono_mb_emit_ldarg (mb, i + sig->hasthis);
 +              if (uses_handles) {
 +                      mono_mb_emit_ldloc_addr (mb, stack_mark_var);
 +                      mono_mb_emit_ldloc_addr (mb, error_var);
 +                      mono_mb_emit_icall (mb, mono_icall_start);
 +                      mono_mb_emit_stloc (mb, thread_info_var);
 +
 +                      if (sig->hasthis) {
 +                              mono_mb_emit_byte (mb, CEE_LDARG_0);
 +                              mono_mb_emit_icall (mb, mono_handle_new);
 +                      }
 +                      for (i = 0; i < sig->param_count; i++) {
 +                              mono_mb_emit_ldarg (mb, i + sig->hasthis);
 +                              if (MONO_TYPE_IS_REFERENCE (sig->params [i])) {
 +                                      mono_mb_emit_icall (mb, mono_handle_new);
 +                              }
 +                      }
 +                      mono_mb_emit_ldloc_addr (mb, error_var);
 +              } else {
 +                      if (sig->hasthis)
 +                              mono_mb_emit_byte (mb, CEE_LDARG_0);
 +                      for (i = 0; i < sig->param_count; i++)
 +                              mono_mb_emit_ldarg (mb, i + sig->hasthis);
 +              }
  
                if (aot) {
                        mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
                        mono_mb_emit_op (mb, CEE_MONO_ICALL_ADDR, &piinfo->method);
 -                      mono_mb_emit_calli (mb, csig);
 +                      mono_mb_emit_calli (mb, call_sig);
                } else {
                        g_assert (piinfo->addr);
 -                      mono_mb_emit_native_call (mb, csig, piinfo->addr);
 +                      mono_mb_emit_native_call (mb, call_sig, piinfo->addr);
                }
 +
 +              if (uses_handles) {
 +                      if (MONO_TYPE_IS_REFERENCE (sig->ret)) {
 +                              // if (ret != NULL_HANDLE) {
 +                              //   ret = MONO_HANDLE_RAW(ret)
 +                              // }
 +                              mono_mb_emit_byte (mb, CEE_DUP);
 +                              int pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
 +                              mono_mb_emit_ldflda (mb, MONO_HANDLE_PAYLOAD_OFFSET (MonoObject));
 +                              mono_mb_emit_byte (mb, CEE_LDIND_REF);
 +                              mono_mb_patch_branch (mb, pos);
 +                      }
 +                      mono_mb_emit_ldloc (mb, thread_info_var);
 +                      mono_mb_emit_ldloc_addr (mb, stack_mark_var);
 +                      mono_mb_emit_ldloc_addr (mb, error_var);
 +                      mono_mb_emit_icall (mb, mono_icall_end);
 +              }
 +
                if (check_exceptions)
                        emit_thread_interrupt_checkpoint (mb);
                mono_mb_emit_byte (mb, CEE_RET);
@@@ -8102,10 -7800,9 +8102,10 @@@ mono_marshal_emit_managed_wrapper (Mono
        }
  #else
        MonoMethodSignature *sig, *csig;
 -      int i, *tmp_locals;
 +      MonoExceptionClause *clauses, *clause_finally, *clause_catch;
 +      int i, *tmp_locals, ex_local, e_local, attach_cookie_local, attach_dummy_local;
 +      int leave_try_pos, leave_catch_pos, ex_m1_pos;
        gboolean closed = FALSE;
 -      int coop_gc_var, coop_gc_dummy_local;
  
        sig = m->sig;
        csig = m->csig;
                mono_mb_add_local (mb, sig->ret);
        }
  
 -      if (mono_threads_is_coop_enabled ()) {
 -              /* local 4, the local to be used when calling the reset_blocking funcs */
 -              /* tons of code hardcode 3 to be the return var */
 -              coop_gc_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
 -              /* local 5, the local used to get a stack address for suspend funcs */
 -              coop_gc_dummy_local = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
 -      }
 +      if (MONO_TYPE_ISSTRUCT (sig->ret))
 +              m->vtaddr_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
  
 -      mono_mb_emit_icon (mb, 0);
 -      mono_mb_emit_stloc (mb, 2);
 +      ex_local = mono_mb_add_local (mb, &mono_defaults.uint32_class->byval_arg);
 +      e_local = mono_mb_add_local (mb, &mono_defaults.exception_class->byval_arg);
 +
 +      attach_cookie_local = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
 +      attach_dummy_local = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
  
        /*
 -       * Might need to attach the thread to the JIT or change the
 -       * domain for the callback.
 +       * guint32 ex = -1;
 +       * try {
 +       *   // does (STARTING|RUNNING|BLOCKING) -> RUNNING + set/switch domain
 +       *   mono_threads_attach_coop ();
 +       *
 +       *   <interrupt check>
 +       *
 +       *   ret = method (...);
 +       * } catch (Exception e) {
 +       *   ex = mono_gchandle_new (e, false);
 +       * } finally {
 +       *   // does RUNNING -> (RUNNING|BLOCKING) + unset/switch domain
 +       *   mono_threads_detach_coop ();
 +       *
 +       *   if (ex != -1)
 +       *     mono_marshal_ftnptr_eh_callback (ex);
 +       * }
 +       *
 +       * return ret;
         */
 -      mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
 -      mono_mb_emit_byte (mb, CEE_MONO_JIT_ATTACH);
  
 -      if (mono_threads_is_coop_enabled ()) {
 -              /* XXX can we merge reset_blocking_start with JIT_ATTACH above and save one call? */
 -              mono_mb_emit_ldloc_addr (mb, coop_gc_dummy_local);
 -              mono_mb_emit_icall (mb, mono_threads_reset_blocking_start);
 -              mono_mb_emit_stloc (mb, coop_gc_var);
 +      clauses = g_new0 (MonoExceptionClause, 2);
 +
 +      clause_catch = &clauses [0];
 +      clause_catch->flags = MONO_EXCEPTION_CLAUSE_NONE;
 +      clause_catch->data.catch_class = mono_defaults.exception_class;
 +
 +      clause_finally = &clauses [1];
 +      clause_finally->flags = MONO_EXCEPTION_CLAUSE_FINALLY;
 +
 +      mono_mb_emit_icon (mb, 0);
 +      mono_mb_emit_stloc (mb, 2);
 +
 +      mono_mb_emit_icon (mb, -1);
 +      mono_mb_emit_byte (mb, CEE_CONV_U4);
 +      mono_mb_emit_stloc (mb, ex_local);
 +
 +      /* try { */
 +      clause_catch->try_offset = clause_finally->try_offset = mono_mb_get_label (mb);
 +
 +      if (!mono_threads_is_coop_enabled ()) {
 +              mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
 +              mono_mb_emit_byte (mb, CEE_MONO_JIT_ATTACH);
 +      } else {
 +              /* mono_threads_attach_coop (); */
 +              mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
 +              mono_mb_emit_byte (mb, CEE_MONO_LDDOMAIN);
 +              mono_mb_emit_ldloc_addr (mb, attach_dummy_local);
 +              mono_mb_emit_icall (mb, mono_threads_attach_coop);
 +              mono_mb_emit_stloc (mb, attach_cookie_local);
        }
  
 +      /* <interrupt check> */
 +      emit_thread_interrupt_checkpoint (mb);
 +
        /* we first do all conversions */
        tmp_locals = (int *)alloca (sizeof (int) * sig->param_count);
        for (i = 0; i < sig->param_count; i ++) {
                }
        }
  
 -      emit_thread_interrupt_checkpoint (mb);
 -
        if (sig->hasthis) {
                if (target_handle) {
                        mono_mb_emit_icon (mb, (gint32)target_handle);
                        mono_mb_emit_ldarg (mb, i);
        }
  
 +      /* ret = method (...) */
        mono_mb_emit_managed_call (mb, method, NULL);
  
 +      if (MONO_TYPE_ISSTRUCT (sig->ret)) {
 +              MonoClass *klass = mono_class_from_mono_type (sig->ret);
 +              mono_class_init (klass);
 +              if (!(mono_class_is_explicit_layout (klass) || klass->blittable)) {
 +                      /* This is used by emit_marshal_vtype (), but it needs to go right before the call */
 +                      mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
 +                      mono_mb_emit_byte (mb, CEE_MONO_VTADDR);
 +                      mono_mb_emit_stloc (mb, m->vtaddr_var);
 +              }
 +      }
 +
        if (mspecs [0] && mspecs [0]->native == MONO_NATIVE_CUSTOM) {
                emit_marshal (m, 0, sig->ret, mspecs [0], 0, NULL, MARSHAL_ACTION_MANAGED_CONV_RESULT);
        } else if (!sig->ret->byref) { 
                }
        }
  
 -      if (mono_threads_is_coop_enabled ()) {
 -              /* XXX merge reset_blocking_end with detach */
 -              mono_mb_emit_ldloc (mb, coop_gc_var);
 -              mono_mb_emit_ldloc_addr (mb, coop_gc_dummy_local);
 -              mono_mb_emit_icall (mb, mono_threads_reset_blocking_end);
 +      leave_try_pos = mono_mb_emit_branch (mb, CEE_LEAVE);
 +
 +      /* } [endtry] */
 +
 +      /* catch (Exception e) { */
 +      clause_catch->try_len = mono_mb_get_label (mb) - clause_catch->try_offset;
 +      clause_catch->handler_offset = mono_mb_get_label (mb);
 +
 +      mono_mb_emit_stloc (mb, e_local);
 +
 +      /* ex = mono_gchandle_new (e, false); */
 +      mono_mb_emit_ldloc (mb, e_local);
 +      mono_mb_emit_icon (mb, 0);
 +      mono_mb_emit_icall (mb, mono_gchandle_new);
 +      mono_mb_emit_stloc (mb, ex_local);
 +
 +      leave_catch_pos = mono_mb_emit_branch (mb, CEE_LEAVE);
 +
 +      /* } [endcatch] */
 +      clause_catch->handler_len = mono_mb_get_pos (mb) - clause_catch->handler_offset;
 +
 +      /* finally { */
 +      clause_finally->try_len = mono_mb_get_label (mb) - clause_finally->try_offset;
 +      clause_finally->handler_offset = mono_mb_get_label (mb);
 +
 +      if (!mono_threads_is_coop_enabled ()) {
 +              mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
 +              mono_mb_emit_byte (mb, CEE_MONO_JIT_DETACH);
 +      } else {
 +              /* mono_threads_detach_coop (); */
 +              mono_mb_emit_ldloc (mb, attach_cookie_local);
 +              mono_mb_emit_ldloc_addr (mb, attach_dummy_local);
 +              mono_mb_emit_icall (mb, mono_threads_detach_coop);
        }
  
 -      mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
 -      mono_mb_emit_byte (mb, CEE_MONO_JIT_DETACH);
 +      /* if (ex != -1) */
 +      mono_mb_emit_ldloc (mb, ex_local);
 +      mono_mb_emit_icon (mb, -1);
 +      mono_mb_emit_byte (mb, CEE_CONV_U4);
 +      ex_m1_pos = mono_mb_emit_branch (mb, CEE_BEQ);
 +
 +      /* mono_marshal_ftnptr_eh_callback (ex) */
 +      mono_mb_emit_ldloc (mb, ex_local);
 +      mono_mb_emit_icall (mb, mono_marshal_ftnptr_eh_callback);
  
 +      /* [ex == -1] */
 +      mono_mb_patch_branch (mb, ex_m1_pos);
 +
 +      mono_mb_emit_byte (mb, CEE_ENDFINALLY);
 +
 +      /* } [endfinally] */
 +      clause_finally->handler_len = mono_mb_get_pos (mb) - clause_finally->handler_offset;
 +
 +      mono_mb_patch_branch (mb, leave_try_pos);
 +      mono_mb_patch_branch (mb, leave_catch_pos);
 +
 +      /* return ret; */
        if (m->retobj_var) {
                mono_mb_emit_ldloc (mb, m->retobj_var);
                mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
                mono_mb_emit_byte (mb, CEE_RET);
        }
  
 +      mono_mb_set_clauses (mb, 2, clauses);
 +
        if (closed)
                g_free (sig);
  #endif
@@@ -8454,7 -8052,7 +8454,7 @@@ mono_marshal_set_callconv_from_modopt (
  MonoMethod *
  mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, uint32_t target_handle)
  {
 -      static MonoClass *UnmanagedFunctionPointerAttribute;
 +      MonoError error;
        MonoMethodSignature *sig, *csig, *invoke_sig;
        MonoMethodBuilder *mb;
        MonoMethod *res, *invoke;
        EmitMarshalContext m;
  
        g_assert (method != NULL);
 -      g_assert (!mono_method_signature (method)->pinvoke);
 +      g_assert (!(method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL));
  
        /* 
         * FIXME: Should cache the method+delegate type pair, since the same method
  
        mono_marshal_set_callconv_from_modopt (invoke, csig);
  
 -      /* Handle the UnmanagedFunctionPointerAttribute */
 -      if (!UnmanagedFunctionPointerAttribute)
 -              UnmanagedFunctionPointerAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "UnmanagedFunctionPointerAttribute");
 -
        /* The attribute is only available in Net 2.0 */
 -      if (UnmanagedFunctionPointerAttribute) {
 +      if (mono_class_try_get_unmanaged_function_pointer_attribute_class ()) {
                MonoCustomAttrInfo *cinfo;
                MonoCustomAttrEntry *attr;
  
                 * contents of the attribute without constructing it, as that might not be
                 * possible when running in cross-compiling mode.
                 */
 -              cinfo = mono_custom_attrs_from_class (delegate_klass);
 +              cinfo = mono_custom_attrs_from_class_checked (delegate_klass, &error);
 +              mono_error_assert_ok (&error);
                attr = NULL;
                if (cinfo) {
                        for (i = 0; i < cinfo->num_attrs; ++i) {
                                MonoClass *ctor_class = cinfo->attrs [i].ctor->klass;
 -                              if (mono_class_has_parent (ctor_class, UnmanagedFunctionPointerAttribute)) {
 +                              if (mono_class_has_parent (ctor_class, mono_class_try_get_unmanaged_function_pointer_attribute_class ())) {
                                        attr = &cinfo->attrs [i];
                                        break;
                                }
  gpointer
  mono_marshal_get_vtfixup_ftnptr (MonoImage *image, guint32 token, guint16 type)
  {
 +      MonoError error;
        MonoMethod *method;
        MonoMethodSignature *sig;
        MonoMethodBuilder *mb;
  
        g_assert (token);
  
 -      method = mono_get_method (image, token, NULL);
 +      method = mono_get_method_checked (image, token, NULL, NULL, &error);
 +      if (!method)
 +              g_error ("Could not load vtfixup token 0x%x due to %s", token, mono_error_get_message (&error));
        g_assert (method);
  
        if (type & (VTFIXUP_TYPE_FROM_UNMANAGED | VTFIXUP_TYPE_FROM_UNMANAGED_RETAIN_APPDOMAIN)) {
                                mono_metadata_free_marshal_spec (mspecs [i]);
                g_free (mspecs);
  
 -              return mono_compile_method (method);
 +              gpointer compiled_ptr = mono_compile_method_checked (method, &error);
 +              mono_error_assert_ok (&error);
 +              return compiled_ptr;
        }
  
        sig = mono_method_signature (method);
        method = mono_mb_create (mb, sig, param_count, NULL);
        mono_mb_free (mb);
  
 -      return mono_compile_method (method);
 +      gpointer compiled_ptr = mono_compile_method_checked (method, &error);
 +      mono_error_assert_ok (&error);
 +      return compiled_ptr;
  }
  
  #ifndef DISABLE_JIT
@@@ -8766,6 -8360,7 +8766,6 @@@ generate_check_cache (int obj_arg_posit
  
  /*
   * This does the equivalent of mono_object_castclass_with_cache.
 - * The wrapper info for the wrapper is a WrapperInfo structure.
   */
  MonoMethod *
  mono_marshal_get_castclass_with_cache (void)
        return cached;
  }
  
 +/* this is an icall */
  static MonoObject *
  mono_marshal_isinst_with_cache (MonoObject *obj, MonoClass *klass, uintptr_t *cache)
  {
 -      MonoObject *isinst = mono_object_isinst (obj, klass);
 +      MonoError error;
 +      MonoObject *isinst = mono_object_isinst_checked (obj, klass, &error);
 +      if (mono_error_set_pending_exception (&error))
 +              return NULL;
  
  #ifndef DISABLE_REMOTING
        if (obj->vtable->klass == mono_defaults.transparent_proxy_class)
  
  /*
   * This does the equivalent of mono_object_isinst_with_cache.
 - * The wrapper info for the wrapper is a WrapperInfo structure.
   */
  MonoMethod *
  mono_marshal_get_isinst_with_cache (void)
  
        // return obj
        mono_mb_patch_branch (mb, positive_cache_hit_pos);
 -      mono_mb_emit_ldarg (mb, 0);
 +      mono_mb_emit_ldarg (mb, obj_arg_position);
        mono_mb_emit_byte (mb, CEE_RET);
  #endif
  
@@@ -9027,6 -8619,7 +9027,6 @@@ mono_marshal_get_isinst (MonoClass *kla
   * an instance of the given type, icluding the case where the object is a proxy.
   * The generated function has the following signature:
   * MonoObject* __castclass_wrapper_ (MonoObject *obj)
 - * The wrapper info for the wrapper is a WrapperInfo structure.
   */
  MonoMethod *
  mono_marshal_get_castclass (MonoClass *klass)
   * @klass:
   *
   * generates IL code for StructureToPtr (object structure, IntPtr ptr, bool fDeleteOld)
 - * The wrapper info for the wrapper is a WrapperInfo structure.
   */
  MonoMethod *
  mono_marshal_get_struct_to_ptr (MonoClass *klass)
        res = mono_mb_create (mb, mono_signature_no_pinvoke (stoptr), 0, info);
        mono_mb_free (mb);
  
 -      klass->marshal_info->str_to_ptr = res;
 +      mono_marshal_lock ();
 +      if (!klass->marshal_info->str_to_ptr)
 +              klass->marshal_info->str_to_ptr = res;
 +      else
 +              res = klass->marshal_info->str_to_ptr;
 +      mono_marshal_unlock ();
        return res;
  }
  
   * @klass:
   *
   * generates IL code for PtrToStructure (IntPtr src, object structure)
 - * The wrapper info for the wrapper is a WrapperInfo structure.
   */
  MonoMethod *
  mono_marshal_get_ptr_to_struct (MonoClass *klass)
        res = mono_mb_create (mb, ptostr, 0, info);
        mono_mb_free (mb);
  
 -      klass->marshal_info->ptr_to_str = res;
 +      mono_marshal_lock ();
 +      if (!klass->marshal_info->ptr_to_str)
 +              klass->marshal_info->ptr_to_str = res;
 +      else
 +              res = klass->marshal_info->ptr_to_str;
 +      mono_marshal_unlock ();
        return res;
  }
  
   * This is used to avoid infinite recursion since it is hard to determine where to
   * replace a method with its synchronized wrapper, and where not.
   * The runtime should execute METHOD instead of the wrapper.
 - * The wrapper info for the wrapper is a WrapperInfo structure.
   */
  MonoMethod *
  mono_marshal_get_synchronized_inner_wrapper (MonoMethod *method)
                method = ((MonoMethodInflated*)method)->declaring;
                container = mono_method_get_generic_container (method);
                if (!container)
 -                      container = method->klass->generic_container;
 +                      container = mono_class_try_get_generic_container (method->klass); //FIXME is this a case of a try?
                g_assert (container);
        }
  
@@@ -9330,7 -8916,7 +9330,7 @@@ mono_marshal_get_synchronized_wrapper (
                method = ((MonoMethodInflated*)method)->declaring;
                container = mono_method_get_generic_container (method);
                if (!container)
 -                      container = method->klass->generic_container;
 +                      container = mono_class_try_get_generic_container (method->klass); //FIXME is this a case of a try?
                g_assert (container);
        }
  
  #endif
  
        if (method->klass->valuetype && !(method->flags & MONO_METHOD_ATTR_STATIC)) {
 -              mono_class_set_failure (method->klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
 +              /* FIXME Is this really the best way to signal an error here?  Isn't this called much later after class setup? -AK */
 +              mono_class_set_type_load_failure (method->klass, "");
  #ifndef DISABLE_JIT
                /* This will throw the type load exception when the wrapper is compiled */
                mono_mb_emit_byte (mb, CEE_LDNULL);
        if (!enter_method) {
                MonoMethodDesc *desc;
  
 -              desc = mono_method_desc_new ("Monitor:enter_with_atomic_var(object,bool&)", FALSE);
 +              desc = mono_method_desc_new ("Monitor:Enter(object,bool&)", FALSE);
                enter_method = mono_method_desc_search_in_class (desc, mono_defaults.monitor_class);
                g_assert (enter_method);
                mono_method_desc_free (desc);
@@@ -9557,7 -9142,7 +9557,7 @@@ is_monomorphic_array (MonoClass *klass
                return FALSE;
  
        element_class = klass->element_class;
 -      return (element_class->flags & TYPE_ATTRIBUTE_SEALED) || element_class->valuetype;
 +      return mono_class_is_sealed (element_class) || element_class->valuetype;
  }
  
  static int
@@@ -9577,7 -9162,7 +9577,7 @@@ get_virtual_stelemref_kind (MonoClass *
        /*Arrays are sealed but are covariant on their element type, We can't use any of the fast paths.*/
        if (mono_class_is_marshalbyref (element_class) || element_class->rank || mono_class_has_variant_generic_params (element_class))
                return STELEMREF_COMPLEX;
 -      if (element_class->flags & TYPE_ATTRIBUTE_SEALED)
 +      if (mono_class_is_sealed (element_class))
                return STELEMREF_SEALED_CLASS;
        return STELEMREF_CLASS;
  }
@@@ -9628,6 -9213,8 +9628,6 @@@ record_slot_vstore (MonoObject *array, 
  #endif
  
  /*
 - * The wrapper info for the wrapper is a WrapperInfo structure.
 - *
   * TODO:
   *    - Separate simple interfaces from variant interfaces or mbr types. This way we can avoid the icall for them.
   *    - Emit a (new) mono bytecode that produces OP_COND_EXC_NE_UN to raise ArrayTypeMismatch
@@@ -9643,7 -9230,7 +9643,7 @@@ get_virtual_stelemref_wrapper (int kind
        MonoMethod *res;
        char *name;
        const char *param_names [16];
 -      guint32 b1, b2, b3;
 +      guint32 b1, b2, b3, b4;
        int aklass, vklass, vtable, uiid;
        int array_slot_addr;
        WrapperInfo *info;
                /*if (mono_object_isinst (value, aklass)) */
                mono_mb_emit_ldarg (mb, 2);
                mono_mb_emit_ldloc (mb, aklass);
 -              mono_mb_emit_icall (mb, mono_object_isinst);
 +              mono_mb_emit_icall (mb, mono_object_isinst_icall);
                b2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
  
                /* do_store: */
                /*if (mono_object_isinst (value, aklass)) */
                mono_mb_emit_ldarg (mb, 2);
                mono_mb_emit_ldloc (mb, aklass);
 -              mono_mb_emit_icall (mb, mono_object_isinst);
 +              mono_mb_emit_icall (mb, mono_object_isinst_icall);
                b2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
  
                /* if (vklass->idepth < aklass->idepth) goto failue */
                mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoClass, idepth));
                mono_mb_emit_byte (mb, CEE_LDIND_U2);
  
 -              b2 = mono_mb_emit_branch (mb, CEE_BLT_UN);
 +              b3 = mono_mb_emit_branch (mb, CEE_BLT_UN);
  
                /* if (vklass->supertypes [aklass->idepth - 1] != aklass) goto failure */
                mono_mb_emit_ldloc (mb, vklass);
                mono_mb_emit_byte (mb, CEE_LDIND_I);
  
                mono_mb_emit_ldloc (mb, aklass);
 -              b3 = mono_mb_emit_branch (mb, CEE_BNE_UN);
 +              b4 = mono_mb_emit_branch (mb, CEE_BNE_UN);
  
                /* do_store: */
                mono_mb_patch_branch (mb, b1);
                /* do_exception: */
                mono_mb_patch_branch (mb, b2);
                mono_mb_patch_branch (mb, b3);
 +              mono_mb_patch_branch (mb, b4);
  
                mono_mb_emit_exception (mb, "ArrayTypeMismatchException", NULL);
                break;
                /* uiid = klass->interface_id; */
                mono_mb_emit_ldloc (mb, aklass);
                mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoClass, interface_id));
-               mono_mb_emit_byte (mb, CEE_LDIND_U2);
+               mono_mb_emit_byte (mb, CEE_LDIND_U4);
                mono_mb_emit_stloc (mb, uiid);
  
                /*if (uiid > vt->max_interface_id)*/
                mono_mb_emit_ldloc (mb, uiid);
                mono_mb_emit_ldloc (mb, vtable);
                mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id));
-               mono_mb_emit_byte (mb, CEE_LDIND_U2);
+               mono_mb_emit_byte (mb, CEE_LDIND_U4);
                b2 = mono_mb_emit_branch (mb, CEE_BGT_UN);
  
                /* if (!(vt->interface_bitmap [(uiid) >> 3] & (1 << ((uiid)&7)))) */
@@@ -10037,6 -9623,9 +10037,6 @@@ mono_marshal_get_virtual_stelemref_wrap
        return res;
  }
  
 -/*
 - * The wrapper info for the wrapper is a WrapperInfo structure.
 - */
  MonoMethod*
  mono_marshal_get_stelemref (void)
  {
        
        mono_mb_emit_ldarg (mb, 2);
        mono_mb_emit_ldloc (mb, aklass);
 -      mono_mb_emit_icall (mb, mono_object_isinst);
 +      mono_mb_emit_icall (mb, mono_object_isinst_icall);
        
        b4 = mono_mb_emit_branch (mb, CEE_BRTRUE);
        mono_mb_patch_addr (mb, b4, copy_pos - (b4 + 4));
   * mono_marshal_get_gsharedvt_in_wrapper:
   *
   *   This wrapper handles calls from normal code to gsharedvt code.
 - *
 - * The wrapper info for the wrapper is a WrapperInfo structure.
   */
  MonoMethod*
  mono_marshal_get_gsharedvt_in_wrapper (void)
   * mono_marshal_get_gsharedvt_out_wrapper:
   *
   *   This wrapper handles calls from gsharedvt code to normal code.
 - *
 - * The wrapper info for the wrapper is a WrapperInfo structure.
   */
  MonoMethod*
  mono_marshal_get_gsharedvt_out_wrapper (void)
@@@ -10519,59 -10112,29 +10519,59 @@@ mono_marshal_get_array_accessor_wrappe
        return res;     
  }
  
 +#ifndef HOST_WIN32
 +static inline void*
 +mono_marshal_alloc_co_task_mem (size_t size)
 +{
 +      if ((gulong)size == 0)
 +              /* This returns a valid pointer for size 0 on MS.NET */
 +              size = 4;
 +
 +      return g_try_malloc ((gulong)size);
 +}
 +#endif
 +
  void*
 -mono_marshal_alloc (gulong size)
 +mono_marshal_alloc (gulong size, MonoError *error)
  {
        gpointer res;
  
 -#ifdef HOST_WIN32
 -      res = CoTaskMemAlloc (size);
 -#else
 -      res = g_try_malloc ((gulong)size);
 +      mono_error_init (error);
 +
 +      res = mono_marshal_alloc_co_task_mem (size);
        if (!res)
 -              mono_gc_out_of_memory ((gulong)size);
 -#endif
 +              mono_error_set_out_of_memory (error, "Could not allocate %lu bytes", size);
 +
        return res;
  }
  
 -void
 -mono_marshal_free (gpointer ptr)
 +/* This is a JIT icall, it sets the pending exception and returns NULL on error. */
 +static void*
 +ves_icall_marshal_alloc (gulong size)
 +{
 +      MonoError error;
 +      void *ret = mono_marshal_alloc (size, &error);
 +      if (!mono_error_ok (&error)) {
 +              mono_error_set_pending_exception (&error);
 +              return NULL;
 +      }
 +
 +      return ret;
 +}
 +
 +#ifndef HOST_WIN32
 +static inline void
 +mono_marshal_free_co_task_mem (void *ptr)
  {
 -#ifdef HOST_WIN32
 -      CoTaskMemFree (ptr);
 -#else
        g_free (ptr);
 +      return;
 +}
  #endif
 +
 +void
 +mono_marshal_free (gpointer ptr)
 +{
 +      mono_marshal_free_co_task_mem (ptr);
  }
  
  void
@@@ -10593,19 -10156,13 +10593,19 @@@ mono_marshal_string_to_utf16 (MonoStrin
        return s ? mono_string_chars (s) : NULL;
  }
  
 +/* This is a JIT icall, it sets the pending exception and returns NULL on error. */
  static void *
  mono_marshal_string_to_utf16_copy (MonoString *s)
  {
        if (s == NULL) {
                return NULL;
        } else {
 -              gunichar2 *res = (gunichar2 *)mono_marshal_alloc ((mono_string_length (s) * 2) + 2);
 +              MonoError error;
 +              gunichar2 *res = (gunichar2 *)mono_marshal_alloc ((mono_string_length (s) * 2) + 2, &error);
 +              if (!mono_error_ok (&error)) {
 +                      mono_error_set_pending_exception (&error);
 +                      return NULL;
 +              }
                memcpy (res, mono_string_chars (s), mono_string_length (s) * 2);
                res [mono_string_length (s)] = 0;
                return res;
@@@ -10717,22 -10274,17 +10717,22 @@@ ves_icall_System_Runtime_InteropService
  MonoString *
  ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi_len (char *ptr, gint32 len)
  {
 -      if (ptr == NULL) {
 -              mono_set_pending_exception (mono_get_exception_argument_null ("ptr"));
 -              return NULL;
 -      } else {
 -              return mono_string_new_len (mono_domain_get (), ptr, len);
 -      }
 +      MonoError error;
 +      MonoString *result = NULL;
 +      mono_error_init (&error);
 +      if (ptr == NULL)
 +              mono_error_set_argument_null (&error, "ptr", "");
 +      else
 +              result = mono_string_new_len_checked (mono_domain_get (), ptr, len, &error);
 +      mono_error_set_pending_exception (&error);
 +      return result;
  }
  
  MonoString *
  ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni (guint16 *ptr)
  {
 +      MonoError error;
 +      MonoString *res = NULL;
        MonoDomain *domain = mono_domain_get (); 
        int len = 0;
        guint16 *t = ptr;
        while (*t++)
                len++;
  
 -      return mono_string_new_utf16 (domain, ptr, len);
 +      res = mono_string_new_utf16_checked (domain, ptr, len, &error);
 +      if (!mono_error_ok (&error)) {
 +              mono_error_set_pending_exception (&error);
 +              return NULL;
 +      }
 +      return res;
  }
  
  MonoString *
  ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni_len (guint16 *ptr, gint32 len)
  {
 +      MonoError error;
 +      MonoString *res = NULL;
        MonoDomain *domain = mono_domain_get (); 
  
 +      mono_error_init (&error);
 +
        if (ptr == NULL) {
 -              mono_set_pending_exception (mono_get_exception_argument_null ("ptr"));
 -              return NULL;
 +              res = NULL;
 +              mono_error_set_argument_null (&error, "ptr", "");
        } else {
 -              return mono_string_new_utf16 (domain, ptr, len);
 +              res = mono_string_new_utf16_checked (domain, ptr, len, &error);
        }
 +
 +      if (!mono_error_ok (&error))
 +              mono_error_set_pending_exception (&error);
 +      return res;
  }
  
  guint32 
@@@ -10794,7 -10333,7 +10794,7 @@@ ves_icall_System_Runtime_InteropService
                return 0;
        }
  
 -      layout = (klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK);
 +      layout = (mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK);
  
        if (type->type == MONO_TYPE_PTR || type->type == MONO_TYPE_FNPTR) {
                return sizeof (gpointer);
  void
  ves_icall_System_Runtime_InteropServices_Marshal_StructureToPtr (MonoObject *obj, gpointer dst, MonoBoolean delete_old)
  {
 +      MonoError error;
        MonoMethod *method;
        gpointer pa [3];
  
        pa [1] = &dst;
        pa [2] = &delete_old;
  
 -      mono_runtime_invoke (method, NULL, pa, NULL);
 +      mono_runtime_invoke_checked (method, NULL, pa, &error);
 +      if (!mono_error_ok (&error))
 +              mono_error_set_pending_exception (&error);
  }
  
  static void
 -ptr_to_structure (gpointer src, MonoObject *dst)
 +ptr_to_structure (gpointer src, MonoObject *dst, MonoError *error)
  {
        MonoMethod *method;
        gpointer pa [2];
  
 +      mono_error_init (error);
 +
        method = mono_marshal_get_ptr_to_struct (dst->vtable->klass);
  
        pa [0] = &src;
        pa [1] = dst;
  
 -      mono_runtime_invoke (method, NULL, pa, NULL);
 +      mono_runtime_invoke_checked (method, NULL, pa, error);
  }
  
  void
  ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure (gpointer src, MonoObject *dst)
  {
        MonoType *t;
 +      MonoError error;
  
        MONO_CHECK_ARG_NULL (src,);
        MONO_CHECK_ARG_NULL (dst,);
                return;
        }
  
 -      ptr_to_structure (src, dst);
 +      ptr_to_structure (src, dst, &error);
 +      if (!mono_error_ok (&error))
 +              mono_error_set_pending_exception (&error);
  }
  
  MonoObject *
  ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure_type (gpointer src, MonoReflectionType *type)
  {
 +      MonoError error;
        MonoClass *klass;
        MonoDomain *domain = mono_domain_get (); 
        MonoObject *res;
                return NULL;
        }
  
 -      res = mono_object_new (domain, klass);
 +      res = mono_object_new_checked (domain, klass, &error);
 +      if (!mono_error_ok (&error)) {
 +              mono_error_set_pending_exception (&error);
 +              return NULL;
 +      }
  
 -      ptr_to_structure (src, res);
 +      ptr_to_structure (src, res, &error);
 +      if (!mono_error_ok (&error)) {
 +              mono_error_set_pending_exception (&error);
 +              return NULL;
 +      }
  
        return res;
  }
  int
  ves_icall_System_Runtime_InteropServices_Marshal_OffsetOf (MonoReflectionType *type, MonoString *field_name)
  {
 +      MonoError error;
        MonoMarshalType *info;
        MonoClass *klass;
        char *fname;
        MONO_CHECK_ARG_NULL (type, 0);
        MONO_CHECK_ARG_NULL (field_name, 0);
  
 -      fname = mono_string_to_utf8 (field_name);
 +      fname = mono_string_to_utf8_checked (field_name, &error);
 +      if (mono_error_set_pending_exception (&error))
 +              return 0;
        klass = mono_class_from_mono_type (type->type);
        if (!mono_class_init (klass)) {
                mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
        return info->fields [match_index].offset;
  }
  
 +#ifndef HOST_WIN32
  gpointer
  ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalAnsi (MonoString *string)
  {
 -#ifdef HOST_WIN32
 -      char* tres, *ret;
 -      size_t len;
 -      tres = mono_string_to_utf8 (string);
 -      if (!tres)
 -              return tres;
 -
 -      len = strlen (tres) + 1;
 -      ret = ves_icall_System_Runtime_InteropServices_Marshal_AllocHGlobal (len);
 -      memcpy (ret, tres, len);
 -      g_free (tres);
 +      MonoError error;
 +      char *ret = mono_string_to_utf8_checked (string, &error);
 +      mono_error_set_pending_exception (&error);
        return ret;
 -
 -#else
 -      return mono_string_to_utf8 (string);
 -#endif
  }
  
  gpointer
@@@ -10986,14 -10516,17 +10986,14 @@@ ves_icall_System_Runtime_InteropService
        if (string == NULL)
                return NULL;
        else {
 -#ifdef TARGET_WIN32
 -              gunichar2 *res = ves_icall_System_Runtime_InteropServices_Marshal_AllocHGlobal 
 -                      ((mono_string_length (string) + 1) * 2);
 -#else
                gunichar2 *res = (gunichar2 *)g_malloc ((mono_string_length (string) + 1) * 2);
 -#endif
 +
                memcpy (res, mono_string_chars (string), mono_string_length (string) * 2);
                res [mono_string_length (string)] = 0;
                return res;
        }
  }
 +#endif /* !HOST_WIN32 */
  
  static void
  mono_struct_delete_old (MonoClass *klass, char *ptr)
                case MONO_MARSHAL_CONV_STR_BSTR:
                case MONO_MARSHAL_CONV_STR_ANSIBSTR:
                case MONO_MARSHAL_CONV_STR_TBSTR:
 +              case MONO_MARSHAL_CONV_STR_UTF8STR:
                        mono_marshal_free (*(gpointer *)cpos);
                        break;
  
@@@ -11063,14 -10595,6 +11063,14 @@@ ves_icall_System_Runtime_InteropService
        mono_struct_delete_old (klass, (char *)src);
  }
  
 +#ifndef HOST_WIN32
 +static inline void *
 +mono_marshal_alloc_hglobal (size_t size)
 +{
 +      return g_try_malloc (size);
 +}
 +#endif
 +
  void*
  ves_icall_System_Runtime_InteropServices_Marshal_AllocHGlobal (gpointer size)
  {
                /* This returns a valid pointer for size 0 on MS.NET */
                s = 4;
  
 -#ifdef HOST_WIN32
 -      res = GlobalAlloc (GMEM_FIXED, s);
 -#else
 -      res = g_try_malloc (s);
 -#endif
 -      if (!res)
 -              mono_gc_out_of_memory (s);
 +      res = mono_marshal_alloc_hglobal (s);
 +
 +      if (!res) {
 +              mono_set_pending_exception (mono_domain_get ()->out_of_memory_ex);
 +              return NULL;
 +      }
  
        return res;
  }
  
 +#ifndef HOST_WIN32
 +static inline gpointer
 +mono_marshal_realloc_hglobal (gpointer ptr, size_t size)
 +{
 +      return g_try_realloc (ptr, size);
 +}
 +#endif
 +
  gpointer
  ves_icall_System_Runtime_InteropServices_Marshal_ReAllocHGlobal (gpointer ptr, gpointer size)
  {
        size_t s = (size_t)size;
  
        if (ptr == NULL) {
 -              mono_gc_out_of_memory (s);
 +              mono_set_pending_exception (mono_domain_get ()->out_of_memory_ex);
                return NULL;
        }
  
 -#ifdef HOST_WIN32
 -      res = GlobalReAlloc (ptr, s, GMEM_MOVEABLE);
 -#else
 -      res = g_try_realloc (ptr, s);
 -#endif
 -      if (!res)
 -              mono_gc_out_of_memory (s);
 +      res = mono_marshal_realloc_hglobal (ptr, s);
 +
 +      if (!res) {
 +              mono_set_pending_exception (mono_domain_get ()->out_of_memory_ex);
 +              return NULL;
 +      }
  
        return res;
  }
  
 -void
 -ves_icall_System_Runtime_InteropServices_Marshal_FreeHGlobal (void *ptr)
 +#ifndef HOST_WIN32
 +static inline void
 +mono_marshal_free_hglobal (gpointer ptr)
  {
 -#ifdef HOST_WIN32
 -      GlobalFree (ptr);
 -#else
        g_free (ptr);
 +      return;
 +}
  #endif
 +
 +void
 +ves_icall_System_Runtime_InteropServices_Marshal_FreeHGlobal (void *ptr)
 +{
 +      mono_marshal_free_hglobal (ptr);
  }
  
  void*
  ves_icall_System_Runtime_InteropServices_Marshal_AllocCoTaskMem (int size)
  {
 -      void *res;
 +      void *res = mono_marshal_alloc_co_task_mem (size);
  
 -#ifdef HOST_WIN32
 -      res = CoTaskMemAlloc (size);
 -#else
 -      if ((gulong)size == 0)
 -              /* This returns a valid pointer for size 0 on MS.NET */
 -              size = 4;
 +      if (!res) {
 +              mono_set_pending_exception (mono_domain_get ()->out_of_memory_ex);
 +              return NULL;
 +      }
 +      return res;
 +}
  
 -      res = g_try_malloc ((gulong)size);
 -#endif
 -      if (!res)
 -              mono_gc_out_of_memory ((gulong)size);
 +void*
 +ves_icall_System_Runtime_InteropServices_Marshal_AllocCoTaskMemSize (gulong size)
 +{
 +      void *res = mono_marshal_alloc_co_task_mem (size);
 +
 +      if (!res) {
 +              mono_set_pending_exception (mono_domain_get ()->out_of_memory_ex);
 +              return NULL;
 +      }
        return res;
  }
  
  void
  ves_icall_System_Runtime_InteropServices_Marshal_FreeCoTaskMem (void *ptr)
  {
 -#ifdef HOST_WIN32
 -      CoTaskMemFree (ptr);
 -#else
 -      g_free (ptr);
 -#endif
 +      mono_marshal_free_co_task_mem (ptr);
 +      return;
 +}
 +
 +#ifndef HOST_WIN32
 +static inline gpointer
 +mono_marshal_realloc_co_task_mem (gpointer ptr, size_t size)
 +{
 +      return g_try_realloc (ptr, (gulong)size);
  }
 +#endif
  
  gpointer
  ves_icall_System_Runtime_InteropServices_Marshal_ReAllocCoTaskMem (gpointer ptr, int size)
  {
 -      void *res;
 +      void *res = mono_marshal_realloc_co_task_mem (ptr, size);
  
 -#ifdef HOST_WIN32
 -      res = CoTaskMemRealloc (ptr, size);
 -#else
 -      res = g_try_realloc (ptr, (gulong)size);
 -#endif
 -      if (!res)
 -              mono_gc_out_of_memory ((gulong)size);
 +      if (!res) {
 +              mono_set_pending_exception (mono_domain_get ()->out_of_memory_ex);
 +              return NULL;
 +      }
        return res;
  }
  
@@@ -11204,12 -10710,6 +11204,12 @@@ ves_icall_System_Runtime_InteropService
        return mono_ftnptr_to_delegate (klass, ftn);
  }
  
 +gpointer
 +ves_icall_System_Runtime_InteropServices_Marshal_GetFunctionPointerForDelegateInternal (MonoDelegate *delegate)
 +{
 +      return mono_delegate_to_ftnptr (delegate);
 +}
 +
  /**
   * mono_marshal_is_loading_type_info:
   *
@@@ -11273,7 -10773,7 +11273,7 @@@ mono_marshal_load_type_info (MonoClass
                count++;
        }
  
 -      layout = klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK;
 +      layout = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK;
  
        /* The mempool is protected by the loader lock */
        info = (MonoMarshalType *)mono_image_alloc0 (klass->image, MONO_SIZEOF_MARSHAL_TYPE + sizeof (MonoMarshalField) * count);
                j++;
        }
  
 +      if (klass->byval_arg.type == MONO_TYPE_PTR)
 +              info->native_size = sizeof (gpointer);
 +
        if (layout != TYPE_ATTRIBUTE_AUTO_LAYOUT) {
                info->native_size = MAX (native_size, info->native_size);
                /*
                /*We do double-checking locking on marshal_info */
                mono_memory_barrier ();
                klass->marshal_info = info;
 +              ++class_marshal_info_count;
        }
        mono_marshal_unlock ();
  
@@@ -11539,7 -11035,6 +11539,7 @@@ mono_marshal_type_size (MonoType *type
        case MONO_NATIVE_BSTR:
        case MONO_NATIVE_ANSIBSTR:
        case MONO_NATIVE_TBSTR:
 +      case MONO_NATIVE_UTF8STR:
        case MONO_NATIVE_LPARRAY:
        case MONO_NATIVE_SAFEARRAY:
        case MONO_NATIVE_IUNKNOWN:
        return 0;
  }
  
 +/* This is a JIT icall, it sets the pending exception and return NULL on error */
  gpointer
  mono_marshal_asany (MonoObject *o, MonoMarshalNative string_encoding, int param_attrs)
  {
 +      MonoError error;
        MonoType *t;
        MonoClass *klass;
  
                switch (string_encoding) {
                case MONO_NATIVE_LPWSTR:
                        return mono_marshal_string_to_utf16_copy ((MonoString*)o);
 -                      break;
                case MONO_NATIVE_LPSTR:
 -                      return mono_string_to_lpstr ((MonoString*)o);
 -                      break;
 +              case MONO_NATIVE_UTF8STR:
 +                      // Same code path, because in Mono, we treated strings as Utf8
 +                      return mono_string_to_utf8str ((MonoString*)o);
                default:
                        g_warning ("marshaling conversion %d not implemented", string_encoding);
                        g_assert_not_reached ();
  
                klass = t->data.klass;
  
 -              if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT)
 +              if (mono_class_is_auto_layout (klass))
                        break;
  
 -              if (klass->valuetype && (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
 -                      klass->blittable || klass->enumtype))
 +              if (klass->valuetype && (mono_class_is_explicit_layout (klass) || klass->blittable || klass->enumtype))
                        return mono_object_unbox (o);
  
 -              res = mono_marshal_alloc (mono_class_native_size (klass, NULL));
 +              res = mono_marshal_alloc (mono_class_native_size (klass, NULL), &error);
 +              if (!mono_error_ok (&error)) {
 +                      mono_error_set_pending_exception (&error);
 +                      return NULL;
 +              }
  
                if (!((param_attrs & PARAM_ATTRIBUTE_OUT) && !(param_attrs & PARAM_ATTRIBUTE_IN))) {
                        method = mono_marshal_get_struct_to_ptr (o->vtable->klass);
                        pa [1] = &res;
                        pa [2] = &delete_old;
  
 -                      mono_runtime_invoke (method, NULL, pa, NULL);
 +                      mono_runtime_invoke_checked (method, NULL, pa, &error);
 +                      if (!mono_error_ok (&error)) {
 +                              mono_error_set_pending_exception (&error);
 +                              return NULL;
 +                      }
                }
  
                return res;
        default:
                break;
        }
 -      mono_raise_exception (mono_get_exception_argument ("", "No PInvoke conversion exists for value passed to Object-typed parameter."));
 +      mono_set_pending_exception (mono_get_exception_argument ("", "No PInvoke conversion exists for value passed to Object-typed parameter."));
        return NULL;
  }
  
 +/* This is a JIT icall, it sets the pending exception */
  void
  mono_marshal_free_asany (MonoObject *o, gpointer ptr, MonoMarshalNative string_encoding, int param_attrs)
  {
 +      MonoError error;
        MonoType *t;
        MonoClass *klass;
  
                switch (string_encoding) {
                case MONO_NATIVE_LPWSTR:
                case MONO_NATIVE_LPSTR:
 +              case MONO_NATIVE_UTF8STR:
                        mono_marshal_free (ptr);
                        break;
                default:
        case MONO_TYPE_VALUETYPE: {
                klass = t->data.klass;
  
 -              if (klass->valuetype && (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
 -                                                               klass->blittable || klass->enumtype))
 +              if (klass->valuetype && (mono_class_is_explicit_layout (klass) || klass->blittable || klass->enumtype))
                        break;
  
                if (param_attrs & PARAM_ATTRIBUTE_OUT) {
                        pa [0] = &ptr;
                        pa [1] = o;
  
 -                      mono_runtime_invoke (method, NULL, pa, NULL);
 +                      mono_runtime_invoke_checked (method, NULL, pa, &error);
 +                      if (!mono_error_ok (&error)) {
 +                              mono_error_set_pending_exception (&error);
 +                              return;
 +                      }
                }
  
                if (!((param_attrs & PARAM_ATTRIBUTE_OUT) && !(param_attrs & PARAM_ATTRIBUTE_IN))) {
@@@ -11843,12 -11323,10 +11843,12 @@@ mono_marshal_get_thunk_invoke_wrapper (
        GHashTable *cache;
        MonoMethod *res;
        int i, param_count, sig_size, pos_leave;
 -      int coop_gc_var, coop_gc_dummy_local;
  
        g_assert (method);
  
 +      // FIXME: we need to store the exception into a MonoHandle
 +      g_assert (!mono_threads_is_coop_enabled ());
 +
        klass = method->klass;
        image = method->klass->image;
  
        if (!MONO_TYPE_IS_VOID (sig->ret))
                mono_mb_add_local (mb, sig->ret);
  
 -      if (mono_threads_is_coop_enabled ()) {
 -              /* local 4, the local to be used when calling the reset_blocking funcs */
 -              /* tons of code hardcode 3 to be the return var */
 -              coop_gc_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
 -              /* local 5, the local used to get a stack address for suspend funcs */
 -              coop_gc_dummy_local = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
 -      }
 -
        /* clear exception arg */
        mono_mb_emit_ldarg (mb, param_count - 1);
        mono_mb_emit_byte (mb, CEE_LDNULL);
        mono_mb_emit_byte (mb, CEE_STIND_REF);
  
 -      if (mono_threads_is_coop_enabled ()) {
 -              /* FIXME this is technically wrong as the callback itself must be executed in gc unsafe context. */
 -              mono_mb_emit_ldloc_addr (mb, coop_gc_dummy_local);
 -              mono_mb_emit_icall (mb, mono_threads_reset_blocking_start);
 -              mono_mb_emit_stloc (mb, coop_gc_var);
 -      }
 -
        /* try */
        clause = (MonoExceptionClause *)mono_image_alloc0 (image, sizeof (MonoExceptionClause));
        clause->try_offset = mono_mb_get_label (mb);
                        mono_mb_emit_op (mb, CEE_BOX, mono_class_from_mono_type (sig->ret));
        }
  
 -      if (mono_threads_is_coop_enabled ()) {
 -              /* XXX merge reset_blocking_end with detach */
 -              mono_mb_emit_ldloc (mb, coop_gc_var);
 -              mono_mb_emit_ldloc_addr (mb, coop_gc_dummy_local);
 -              mono_mb_emit_icall (mb, mono_threads_reset_blocking_end);
 -      }
 -
        mono_mb_emit_byte (mb, CEE_RET);
  #endif
  
@@@ -12011,57 -11511,3 +12011,57 @@@ mono_marshal_free_dynamic_wrappers (Mon
        if (marshal_mutex_initialized)
                mono_marshal_unlock ();
  }
 +
 +static void
 +mono_marshal_ftnptr_eh_callback (guint32 gchandle)
 +{
 +      g_assert (ftnptr_eh_callback);
 +      ftnptr_eh_callback (gchandle);
 +}
 +
 +static void
 +ftnptr_eh_callback_default (guint32 gchandle)
 +{
 +      MonoException *exc;
 +      gpointer stackdata;
 +
 +      mono_threads_enter_gc_unsafe_region_unbalanced (&stackdata);
 +
 +      exc = (MonoException*) mono_gchandle_get_target (gchandle);
 +
 +      mono_gchandle_free (gchandle);
 +
 +      mono_raise_exception (exc);
 +}
 +
 +/*
 + * mono_install_ftnptr_eh_callback:
 + *
 + *   Install a callback that should be called when there is a managed exception
 + *   in a native-to-managed wrapper. This is mainly used by iOS to convert a
 + *   managed exception to a native exception, to properly unwind the native
 + *   stack; this native exception will then be converted back to a managed
 + *   exception in their managed-to-native wrapper.
 + */
 +void
 +mono_install_ftnptr_eh_callback (MonoFtnPtrEHCallback callback)
 +{
 +      ftnptr_eh_callback = callback;
 +}
 +
 +static MonoThreadInfo*
 +mono_icall_start (HandleStackMark *stackmark, MonoError *error)
 +{
 +      MonoThreadInfo *info = mono_thread_info_current ();
 +
 +      mono_stack_mark_init (info, stackmark);
 +      mono_error_init (error);
 +      return info;
 +}
 +
 +static void
 +mono_icall_end (MonoThreadInfo *info, HandleStackMark *stackmark, MonoError *error)
 +{
 +      mono_stack_mark_pop (info, stackmark);
 +      mono_error_set_pending_exception (error);
 +}
diff --combined mono/metadata/object.c
index 78fe267412243c68b3731c189e923d828d31da17,db0047db6484424c6597c6505aef2821a9420789..c25a107fdeb502712987c0c7b5671e8258b1f49d
@@@ -8,7 -8,6 +8,7 @@@
   * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
   * Copyright 2004-2011 Novell, Inc (http://www.novell.com)
   * Copyright 2001 Xamarin Inc (http://www.xamarin.com)
 + * Licensed under the MIT license. See LICENSE file in the project root for full license information.
   */
  #include <config.h>
  #ifdef HAVE_ALLOCA_H
@@@ -24,7 -23,6 +24,7 @@@
  #include <mono/metadata/object.h>
  #include <mono/metadata/gc-internals.h>
  #include <mono/metadata/exception.h>
 +#include <mono/metadata/exception-internals.h>
  #include <mono/metadata/domain-internals.h>
  #include "mono/metadata/metadata-internals.h"
  #include "mono/metadata/class-internals.h"
  #include "mono/metadata/mono-debug-debugger.h"
  #include <mono/metadata/gc-internals.h>
  #include <mono/metadata/verify-internals.h>
 +#include <mono/metadata/reflection-internals.h>
 +#include <mono/metadata/w32event.h>
  #include <mono/utils/strenc.h>
  #include <mono/utils/mono-counters.h>
  #include <mono/utils/mono-error-internals.h>
  #include <mono/utils/mono-memory-model.h>
  #include <mono/utils/checked-build.h>
  #include <mono/utils/mono-threads.h>
 +#include <mono/utils/mono-threads-coop.h>
  #include "cominterop.h"
  
  static void
 -get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
 +get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error);
  
  static MonoString*
 -mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig);
 +mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error);
  
  static void
  free_main_args (void);
  static char *
  mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
  
 +/* Class lazy loading functions */
 +static GENERATE_GET_CLASS_WITH_CACHE (pointer, System.Reflection, Pointer)
 +static GENERATE_GET_CLASS_WITH_CACHE (remoting_services, System.Runtime.Remoting, RemotingServices)
 +static GENERATE_GET_CLASS_WITH_CACHE (unhandled_exception_event_args, System, UnhandledExceptionEventArgs)
 +static GENERATE_GET_CLASS_WITH_CACHE (sta_thread_attribute, System, STAThreadAttribute)
 +static GENERATE_GET_CLASS_WITH_CACHE (activation_services, System.Runtime.Remoting.Activation, ActivationServices)
 +
  
  #define ldstr_lock() mono_os_mutex_lock (&ldstr_section)
  #define ldstr_unlock() mono_os_mutex_unlock (&ldstr_section)
  static mono_mutex_t ldstr_section;
  
 +/**
 + * mono_runtime_object_init:
 + * @this_obj: the object to initialize
 + *
 + * This function calls the zero-argument constructor (which must
 + * exist) for the given object.
 + */
  void
  mono_runtime_object_init (MonoObject *this_obj)
 +{
 +      MonoError error;
 +      mono_runtime_object_init_checked (this_obj, &error);
 +      mono_error_assert_ok (&error);
 +}
 +
 +/**
 + * mono_runtime_object_init_checked:
 + * @this_obj: the object to initialize
 + * @error: set on error.
 + *
 + * This function calls the zero-argument constructor (which must
 + * exist) for the given object and returns TRUE on success, or FALSE
 + * on error and sets @error.
 + */
 +gboolean
 +mono_runtime_object_init_checked (MonoObject *this_obj, MonoError *error)
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
        MonoMethod *method = NULL;
        MonoClass *klass = this_obj->vtable->klass;
  
 +      mono_error_init (error);
        method = mono_class_get_method_from_name (klass, ".ctor", 0);
        if (!method)
                g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
  
        if (method->klass->valuetype)
                this_obj = (MonoObject *)mono_object_unbox (this_obj);
 -      mono_runtime_invoke (method, this_obj, NULL, NULL);
 +
 +      mono_runtime_invoke_checked (method, this_obj, NULL, error);
 +      return is_ok (error);
  }
  
  /* The pseudo algorithm for type initialization from the spec
@@@ -261,7 -222,6 +261,7 @@@ get_type_init_exception_for_vtable (Mon
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
 +      MonoError error;
        MonoDomain *domain = vtable->domain;
        MonoClass *klass = vtable->klass;
        MonoException *ex;
                        full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
                else
                        full_name = g_strdup (klass->name);
 -              ex = mono_get_exception_type_initialization (full_name, NULL);
 +              ex = mono_get_exception_type_initialization_checked (full_name, NULL, &error);
                g_free (full_name);
 +              return_val_if_nok (&error, NULL);
        }
  
        return ex;
  }
 +
  /*
   * mono_runtime_class_init:
   * @vtable: vtable that needs to be initialized
@@@ -303,25 -261,23 +303,25 @@@ voi
  mono_runtime_class_init (MonoVTable *vtable)
  {
        MONO_REQ_GC_UNSAFE_MODE;
 +      MonoError error;
  
 -      mono_runtime_class_init_full (vtable, TRUE);
 +      mono_runtime_class_init_full (vtable, &error);
 +      mono_error_assert_ok (&error);
  }
  
 -/*
 +/**
   * mono_runtime_class_init_full:
   * @vtable that neeeds to be initialized
 - * @raise_exception is TRUE, exceptions are raised intead of returned 
 + * @error set on error
 + *
 + * returns TRUE if class constructor .cctor has been initialized successfully, or FALSE otherwise and sets @error.
   * 
   */
 -MonoException *
 -mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
 +gboolean
 +mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
 -      MonoException *exc;
 -      MonoException *exc_to_throw;
        MonoMethod *method = NULL;
        MonoClass *klass;
        gchar *full_name;
        MonoNativeThreadId tid;
        int do_initialization = 0;
        MonoDomain *last_domain = NULL;
 +      MonoException * pending_tae = NULL;
 +
 +      mono_error_init (error);
  
        if (vtable->initialized)
 -              return NULL;
 +              return TRUE;
  
 -      exc = NULL;
        klass = vtable->klass;
  
        if (!klass->image->checked_module_cctor) {
                mono_image_check_for_module_cctor (klass->image);
                if (klass->image->has_module_cctor) {
 -                      MonoError error;
                        MonoClass *module_klass;
                        MonoVTable *module_vtable;
  
 -                      module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, &error);
 +                      module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, error);
                        if (!module_klass) {
 -                              exc = mono_error_convert_to_exception (&error);
 -                              if (raise_exception)
 -                                      mono_raise_exception (exc);
 -                              return exc; 
 +                              return FALSE;
                        }
                                
 -                      module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception);
 +                      module_vtable = mono_class_vtable_full (vtable->domain, module_klass, error);
                        if (!module_vtable)
 -                              return NULL;
 -                      exc = mono_runtime_class_init_full (module_vtable, raise_exception);
 -                      if (exc)
 -                              return exc;
 +                              return FALSE;
 +                      if (!mono_runtime_class_init_full (module_vtable, error))
 +                              return FALSE;
                }
        }
        method = mono_class_get_cctor (klass);
        if (!method) {
                vtable->initialized = 1;
 -              return NULL;
 +              return TRUE;
        }
  
        tid = mono_native_thread_id_get ();
        /* double check... */
        if (vtable->initialized) {
                mono_type_initialization_unlock ();
 -              return NULL;
 +              return TRUE;
        }
        if (vtable->init_failed) {
                mono_type_initialization_unlock ();
  
                /* The type initialization already failed once, rethrow the same exception */
 -              if (raise_exception)
 -                      mono_raise_exception (get_type_init_exception_for_vtable (vtable));
 -              return get_type_init_exception_for_vtable (vtable);
 +              mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
 +              return FALSE;
        }
        lock = (TypeInitializationLock *)g_hash_table_lookup (type_initialization_hash, vtable);
        if (lock == NULL) {
                        if (!mono_domain_set (domain, FALSE)) {
                                vtable->initialized = 1;
                                mono_type_initialization_unlock ();
 -                              if (raise_exception)
 -                                      mono_raise_exception (mono_get_exception_appdomain_unloaded ());
 -                              return mono_get_exception_appdomain_unloaded ();
 +                              mono_error_set_exception_instance (error, mono_get_exception_appdomain_unloaded ());
 +                              return FALSE;
                        }
                }
                lock = (TypeInitializationLock *)g_malloc (sizeof (TypeInitializationLock));
  
                if (mono_native_thread_id_equals (lock->initializing_tid, tid) || lock->done) {
                        mono_type_initialization_unlock ();
 -                      return NULL;
 +                      return TRUE;
                }
                /* see if the thread doing the initialization is already blocked on this thread */
                blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
                        if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
                                if (!pending_lock->done) {
                                        mono_type_initialization_unlock ();
 -                                      return NULL;
 +                                      return TRUE;
                                } else {
                                        /* the thread doing the initialization is blocked on this thread,
                                           but on a lock that has already been freed. It just hasn't got
        mono_type_initialization_unlock ();
  
        if (do_initialization) {
 -              mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
 +              MonoException *exc = NULL;
 +
 +              mono_threads_begin_abort_protected_block ();
 +              mono_runtime_try_invoke (method, NULL, NULL, (MonoObject**) &exc, error);
 +              mono_threads_end_abort_protected_block ();
 +
 +              //exception extracted, error will be set to the right value later
 +              if (exc == NULL && !mono_error_ok (error))//invoking failed but exc was not set
 +                      exc = mono_error_convert_to_exception (error);
 +              else
 +                      mono_error_cleanup (error);
 +
 +              mono_error_init (error);
  
                /* If the initialization failed, mark the class as unusable. */
                /* Avoid infinite loops */
 -              if (!(exc == NULL ||
 +              if (!(!exc ||
                          (klass->image == mono_defaults.corlib &&
                           !strcmp (klass->name_space, "System") &&
                           !strcmp (klass->name, "TypeInitializationException")))) {
                                full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
                        else
                                full_name = g_strdup (klass->name);
 -                      exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
 +
 +                      MonoException *exc_to_throw = mono_get_exception_type_initialization_checked (full_name, exc, error);
                        g_free (full_name);
  
 +                      mono_error_assert_ok (error); //We can't recover from this, no way to fail a type we can't alloc a failure.
 +
                        /*
                         * Store the exception object so it could be thrown on subsequent
                         * accesses.
                        mono_domain_set (last_domain, TRUE);
                lock->done = TRUE;
                mono_type_init_unlock (lock);
 +              if (exc && mono_object_class (exc) == mono_defaults.threadabortexception_class)
 +                      pending_tae = exc;
 +              //TAEs are blocked around .cctors, they must escape as soon as no cctor is left to run.
 +              if (!pending_tae)
 +                      pending_tae = mono_thread_try_resume_interruption ();
        } else {
                /* this just blocks until the initializing thread is done */
                mono_type_init_lock (lock);
                vtable->initialized = 1;
        mono_type_initialization_unlock ();
  
 -      if (vtable->init_failed) {
 +      //TAE wins over TIE
 +      if (pending_tae)
 +              mono_error_set_exception_instance (error, pending_tae);
 +      else if (vtable->init_failed) {
                /* Either we were the initializing thread or we waited for the initialization */
 -              if (raise_exception)
 -                      mono_raise_exception (get_type_init_exception_for_vtable (vtable));
 -              return get_type_init_exception_for_vtable (vtable);
 +              mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
 +              return FALSE;
        }
 -      return NULL;
 +      return TRUE;
  }
  
  static
@@@ -552,10 -491,24 +552,10 @@@ mono_release_type_locks (MonoInternalTh
        mono_type_initialization_unlock ();
  }
  
 -static gpointer
 -default_trampoline (MonoMethod *method)
 -{
 -      return method;
 -}
 -
 -static gpointer
 -default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
 -{
 -      g_assert_not_reached ();
 -
 -      return NULL;
 -}
 -
  #ifndef DISABLE_REMOTING
  
  static gpointer
 -default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
 +default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
  {
        g_error ("remoting not installed");
        return NULL;
@@@ -571,9 -524,11 +571,9 @@@ default_delegate_trampoline (MonoDomai
        return NULL;
  }
  
 -static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
 -static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
  static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
 -static MonoImtThunkBuilder imt_thunk_builder;
 -static gboolean always_build_imt_thunks;
 +static MonoImtTrampolineBuilder imt_trampoline_builder;
 +static gboolean always_build_imt_trampolines;
  
  #if (MONO_IMT_SIZE > 32)
  #error "MONO_IMT_SIZE cannot be larger than 32"
@@@ -591,6 -546,18 +591,6 @@@ mono_get_runtime_callbacks (void
        return &callbacks;
  }
  
 -void
 -mono_install_trampoline (MonoTrampoline func) 
 -{
 -      arch_create_jit_trampoline = func? func: default_trampoline;
 -}
 -
 -void
 -mono_install_jump_trampoline (MonoJumpTrampoline func) 
 -{
 -      arch_create_jump_trampoline = func? func: default_jump_trampoline;
 -}
 -
  #ifndef DISABLE_REMOTING
  void
  mono_install_remoting_trampoline (MonoRemotingTrampoline func) 
@@@ -606,68 -573,55 +606,68 @@@ mono_install_delegate_trampoline (MonoD
  }
  
  void
 -mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
 -      imt_thunk_builder = func;
 +mono_install_imt_trampoline_builder (MonoImtTrampolineBuilder func)
 +{
 +      imt_trampoline_builder = func;
  }
  
  void
 -mono_set_always_build_imt_thunks (gboolean value)
 +mono_set_always_build_imt_trampolines (gboolean value)
  {
 -      always_build_imt_thunks = value;
 +      always_build_imt_trampolines = value;
  }
  
 -static MonoCompileFunc default_mono_compile_method = NULL;
 -
  /**
 - * mono_install_compile_method:
 - * @func: function to install
 + * mono_compile_method:
 + * @method: The method to compile.
   *
 - * This is a VM internal routine
 + * This JIT-compiles the method, and returns the pointer to the native code
 + * produced.
   */
 -void        
 -mono_install_compile_method (MonoCompileFunc func)
 +gpointer 
 +mono_compile_method (MonoMethod *method)
  {
 -      default_mono_compile_method = func;
 +      MonoError error;
 +      gpointer result = mono_compile_method_checked (method, &error);
 +      mono_error_cleanup (&error);
 +      return result;
  }
  
  /**
   * mono_compile_method:
   * @method: The method to compile.
 + * @error: set on error.
   *
   * This JIT-compiles the method, and returns the pointer to the native code
 - * produced.
 + * produced.  On failure returns NULL and sets @error.
   */
 -gpointer 
 -mono_compile_method (MonoMethod *method)
 +gpointer
 +mono_compile_method_checked (MonoMethod *method, MonoError *error)
  {
 +      gpointer res;
 +
        MONO_REQ_GC_NEUTRAL_MODE
  
 -      if (!default_mono_compile_method) {
 +      mono_error_init (error);
 +
 +      if (!callbacks.compile_method) {
                g_error ("compile method called on uninitialized runtime");
                return NULL;
        }
 -      return default_mono_compile_method (method);
 +      res = callbacks.compile_method (method, error);
 +      return res;
  }
  
  gpointer
 -mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
 +mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper, MonoError *error)
  {
 -      MONO_REQ_GC_NEUTRAL_MODE
 +      gpointer res;
 +
 +      MONO_REQ_GC_NEUTRAL_MODE;
  
 -      return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
 +      mono_error_init (error);
 +      res = callbacks.create_jump_trampoline (domain, method, add_sync_wrapper, error);
 +      return res;
  }
  
  gpointer
@@@ -1006,13 -960,10 +1006,13 @@@ mono_class_insecure_overlapping (MonoCl
  #endif
  
  MonoString*
 -mono_string_alloc (int length)
 +ves_icall_string_alloc (int length)
  {
 -      MONO_REQ_GC_UNSAFE_MODE;
 -      return mono_string_new_size (mono_domain_get (), length);
 +      MonoError error;
 +      MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
 +      mono_error_set_pending_exception (&error);
 +
 +      return str;
  }
  
  void
@@@ -1028,8 -979,8 +1028,8 @@@ mono_class_compute_gc_descriptor (MonoC
        if (!gcj_inited) {
                mono_loader_lock ();
  
 -              mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
 -              mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
 +              mono_register_jit_icall (ves_icall_object_new_fast, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
 +              mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
  
                gcj_inited = TRUE;
                mono_loader_unlock ();
@@@ -1092,11 -1043,9 +1092,11 @@@ field_is_special_static (MonoClass *fkl
  {
        MONO_REQ_GC_NEUTRAL_MODE;
  
 +      MonoError error;
        MonoCustomAttrInfo *ainfo;
        int i;
 -      ainfo = mono_custom_attrs_from_field (fklass, field);
 +      ainfo = mono_custom_attrs_from_field_checked (fklass, field, &error);
 +      mono_error_cleanup (&error); /* FIXME don't swallow the error? */
        if (!ainfo)
                return FALSE;
        for (i = 0; i < ainfo->num_attrs; ++i) {
@@@ -1208,7 -1157,7 +1208,7 @@@ mono_method_get_imt_slot (MonoMethod *m
                break;
        }
        
 -      free (hashes_start);
 +      g_free (hashes_start);
        /* Report the result */
        return c % MONO_IMT_SIZE;
  }
@@@ -1336,7 -1285,7 +1336,7 @@@ imt_sort_slot_entries (MonoImtBuilderEn
  
        imt_emit_ir (sorted_array, 0, number_of_entries, result);
  
 -      free (sorted_array);
 +      g_free (sorted_array);
        return result;
  }
  
@@@ -1346,15 -1295,15 +1346,15 @@@ initialize_imt_slot (MonoVTable *vtable
        MONO_REQ_GC_NEUTRAL_MODE;
  
        if (imt_builder_entry != NULL) {
 -              if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_thunks) {
 +              if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_trampolines) {
                        /* No collision, return the vtable slot contents */
                        return vtable->vtable [imt_builder_entry->value.vtable_slot];
                } else {
 -                      /* Collision, build the thunk */
 +                      /* Collision, build the trampoline */
                        GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
                        gpointer result;
                        int i;
 -                      result = imt_thunk_builder (vtable, domain,
 +                      result = imt_trampoline_builder (vtable, domain,
                                (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
                        for (i = 0; i < imt_ir->len; ++i)
                                g_free (g_ptr_array_index (imt_ir, i));
@@@ -1406,14 -1355,14 +1406,14 @@@ build_imt_slots (MonoClass *klass, Mono
                for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
                        MonoMethod *method;
  
 -                      if (slot_num >= 0 && iface->is_inflated) {
 +                      if (slot_num >= 0 && mono_class_is_ginst (iface)) {
                                /*
                                 * The imt slot of the method is the same as for its declaring method,
                                 * see the comment in mono_method_get_imt_slot (), so we can
                                 * avoid inflating methods which will be discarded by 
                                 * add_imt_builder_entry anyway.
                                 */
 -                              method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
 +                              method = mono_class_get_method_by_index (mono_class_get_generic_class (iface)->container_class, method_slot_in_interface);
                                if (mono_method_get_imt_slot (method) != slot_num) {
                                        vt_slot ++;
                                        continue;
  
                        if (has_generic_virtual || has_variant_iface) {
                                /*
 -                               * There might be collisions later when the the thunk is expanded.
 +                               * There might be collisions later when the the trampoline is expanded.
                                 */
                                imt_collisions_bitmap |= (1 << i);
  
                                /* 
 -                               * The IMT thunk might be called with an instance of one of the 
 +                               * The IMT trampoline might be called with an instance of one of the 
                                 * generic virtual methods, so has to fallback to the IMT trampoline.
                                 */
                                imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
                        entry = next;
                }
        }
 -      free (imt_builder);
 +      g_free (imt_builder);
        /* we OR the bitmap since we may build just a single imt slot at a time */
        vt->imt_collisions_bitmap |= imt_collisions_bitmap;
  }
@@@ -1534,7 -1483,7 +1534,7 @@@ build_imt (MonoClass *klass, MonoVTabl
   * @imt_slot: slot in the IMT table
   *
   * Fill the given @imt_slot in the IMT table of @vtable with
 - * a trampoline or a thunk for the case of collisions.
 + * a trampoline or a trampoline for the case of collisions.
   * This is part of the internal mono API.
   *
   * LOCKING: Take the domain lock.
@@@ -1562,35 -1511,167 +1562,35 @@@ mono_vtable_build_imt_slot (MonoVTable
        mono_loader_unlock ();
  }
  
 -
 -/*
 - * The first two free list entries both belong to the wait list: The
 - * first entry is the pointer to the head of the list and the second
 - * entry points to the last element.  That way appending and removing
 - * the first element are both O(1) operations.
 - */
 -#ifdef MONO_SMALL_CONFIG
 -#define NUM_FREE_LISTS                6
 -#else
 -#define NUM_FREE_LISTS                12
 -#endif
 -#define FIRST_FREE_LIST_SIZE  64
 -#define MAX_WAIT_LENGTH       50
  #define THUNK_THRESHOLD               10
  
 -/*
 - * LOCKING: The domain lock must be held.
 - */
 -static void
 -init_thunk_free_lists (MonoDomain *domain)
 -{
 -      MONO_REQ_GC_NEUTRAL_MODE;
 -
 -      if (domain->thunk_free_lists)
 -              return;
 -      domain->thunk_free_lists = (MonoThunkFreeList **)mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
 -}
 -
 -static int
 -list_index_for_size (int item_size)
 -{
 -      int i = 2;
 -      int size = FIRST_FREE_LIST_SIZE;
 -
 -      while (item_size > size && i < NUM_FREE_LISTS - 1) {
 -              i++;
 -              size <<= 1;
 -      }
 -
 -      return i;
 -}
 -
  /**
 - * mono_method_alloc_generic_virtual_thunk:
 + * mono_method_alloc_generic_virtual_trampoline:
   * @domain: a domain
   * @size: size in bytes
   *
   * Allocs size bytes to be used for the code of a generic virtual
 - * thunk.  It's either allocated from the domain's code manager or
 + * trampoline.  It's either allocated from the domain's code manager or
   * reused from a previously invalidated piece.
   *
   * LOCKING: The domain lock must be held.
   */
  gpointer
 -mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
 +mono_method_alloc_generic_virtual_trampoline (MonoDomain *domain, int size)
  {
        MONO_REQ_GC_NEUTRAL_MODE;
  
        static gboolean inited = FALSE;
 -      static int generic_virtual_thunks_size = 0;
 -
 -      guint32 *p;
 -      int i;
 -      MonoThunkFreeList **l;
 -
 -      init_thunk_free_lists (domain);
 -
 -      size += sizeof (guint32);
 -      if (size < sizeof (MonoThunkFreeList))
 -              size = sizeof (MonoThunkFreeList);
 -
 -      i = list_index_for_size (size);
 -      for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
 -              if ((*l)->size >= size) {
 -                      MonoThunkFreeList *item = *l;
 -                      *l = item->next;
 -                      return ((guint32*)item) + 1;
 -              }
 -      }
 -
 -      /* no suitable item found - search lists of larger sizes */
 -      while (++i < NUM_FREE_LISTS) {
 -              MonoThunkFreeList *item = domain->thunk_free_lists [i];
 -              if (!item)
 -                      continue;
 -              g_assert (item->size > size);
 -              domain->thunk_free_lists [i] = item->next;
 -              return ((guint32*)item) + 1;
 -      }
 +      static int generic_virtual_trampolines_size = 0;
  
 -      /* still nothing found - allocate it */
        if (!inited) {
 -              mono_counters_register ("Generic virtual thunk bytes",
 -                              MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
 +              mono_counters_register ("Generic virtual trampoline bytes",
 +                              MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_trampolines_size);
                inited = TRUE;
        }
 -      generic_virtual_thunks_size += size;
 -
 -      p = (guint32 *)mono_domain_code_reserve (domain, size);
 -      *p = size;
 -
 -      mono_domain_lock (domain);
 -      if (!domain->generic_virtual_thunks)
 -              domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
 -      g_hash_table_insert (domain->generic_virtual_thunks, p, p);
 -      mono_domain_unlock (domain);
 -
 -      return p + 1;
 -}
 -
 -/*
 - * LOCKING: The domain lock must be held.
 - */
 -static void
 -invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
 -{
 -      MONO_REQ_GC_NEUTRAL_MODE;
 -
 -      guint32 *p = (guint32 *)code;
 -      MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
 -      gboolean found = FALSE;
 -
 -      mono_domain_lock (domain);
 -      if (!domain->generic_virtual_thunks)
 -              domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
 -      if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
 -              found = TRUE;
 -      mono_domain_unlock (domain);
 -
 -      if (!found)
 -              /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
 -              return;
 -      init_thunk_free_lists (domain);
 -
 -      while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
 -              MonoThunkFreeList *item = domain->thunk_free_lists [0];
 -              int length = item->length;
 -              int i;
 -
 -              /* unlink the first item from the wait list */
 -              domain->thunk_free_lists [0] = item->next;
 -              domain->thunk_free_lists [0]->length = length - 1;
 -
 -              i = list_index_for_size (item->size);
 -
 -              /* put it in the free list */
 -              item->next = domain->thunk_free_lists [i];
 -              domain->thunk_free_lists [i] = item;
 -      }
 -
 -      l->next = NULL;
 -      if (domain->thunk_free_lists [1]) {
 -              domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
 -              domain->thunk_free_lists [0]->length++;
 -      } else {
 -              g_assert (!domain->thunk_free_lists [0]);
 +      generic_virtual_trampolines_size += size;
  
 -              domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
 -              domain->thunk_free_lists [0]->length = 1;
 -      }
 +      return mono_domain_code_reserve (domain, size);
  }
  
  typedef struct _GenericVirtualCase {
@@@ -1654,7 -1735,7 +1654,7 @@@ get_generic_virtual_entries (MonoDomai
   * Registers a call via unmanaged code to a generic virtual method
   * instantiation or variant interface method.  If the number of calls reaches a threshold
   * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
 - * virtual method thunk.
 + * virtual method trampoline.
   */
  void
  mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
  
        static gboolean inited = FALSE;
        static int num_added = 0;
 +      static int num_freed = 0;
  
        GenericVirtualCase *gvc, *list;
        MonoImtBuilderEntry *entries;
        if (!domain->generic_virtual_cases)
                domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
  
 +      if (!inited) {
 +              mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
 +              mono_counters_register ("Freed IMT trampolines", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_freed);
 +              inited = TRUE;
 +      }
 +
        /* Check whether the case was already added */
        list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
        gvc = list;
  
                g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
  
 -              if (!inited) {
 -                      mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
 -                      inited = TRUE;
 -              }
                num_added++;
        }
  
                        int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
                        int imt_slot = MONO_IMT_SIZE + displacement;
  
 -                      /* Force the rebuild of the thunk at the next call */
 +                      /* Force the rebuild of the trampoline at the next call */
                        imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
                        *vtable_slot = imt_trampoline;
                } else {
  
                        sorted = imt_sort_slot_entries (entries);
  
 -                      *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
 -                                                                                        vtable_trampoline);
 +                      *vtable_slot = imt_trampoline_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
 +                                                                                                 vtable_trampoline);
  
                        while (entries) {
                                MonoImtBuilderEntry *next = entries->next;
                        for (i = 0; i < sorted->len; ++i)
                                g_free (g_ptr_array_index (sorted, i));
                        g_ptr_array_free (sorted, TRUE);
 -              }
  
 -#ifndef __native_client__
 -              /* We don't re-use any thunks as there is a lot of overhead */
 -              /* to deleting and re-using code in Native Client.          */
 -              if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
 -                      invalidate_generic_virtual_thunk (domain, old_thunk);
 -#endif
 +                      if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
 +                              num_freed ++;
 +              }
        }
  
        mono_domain_unlock (domain);
  }
  
 -static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, gboolean raise_on_error);
 +static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
  
  /**
   * mono_class_vtable:
  MonoVTable *
  mono_class_vtable (MonoDomain *domain, MonoClass *klass)
  {
 -      return mono_class_vtable_full (domain, klass, FALSE);
 +      MonoError error;
 +      MonoVTable* vtable = mono_class_vtable_full (domain, klass, &error);
 +      mono_error_cleanup (&error);
 +      return vtable;
  }
  
  /**
   * mono_class_vtable_full:
   * @domain: the application domain
   * @class: the class to initialize
 - * @raise_on_error if an exception should be raised on failure or not
 + * @error set on failure.
   *
   * VTables are domain specific because we create domain specific code, and 
   * they contain the domain specific static class data.
   */
  MonoVTable *
 -mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, gboolean raise_on_error)
 +mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
        MonoClassRuntimeInfo *runtime_info;
  
 +      mono_error_init (error);
 +
        g_assert (klass);
  
 -      if (klass->exception_type) {
 -              if (raise_on_error)
 -                      mono_raise_exception (mono_class_get_exception_for_failure (klass));
 +      if (mono_class_has_failure (klass)) {
 +              mono_error_set_for_class_failure (error, klass);
                return NULL;
        }
  
        runtime_info = klass->runtime_info;
        if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
                return runtime_info->domain_vtables [domain->domain_id];
 -      return mono_class_create_runtime_vtable (domain, klass, raise_on_error);
 +      return mono_class_create_runtime_vtable (domain, klass, error);
  }
  
  /**
@@@ -1843,7 -1921,7 +1843,7 @@@ alloc_vtable (MonoDomain *domain, size_
  }
  
  static MonoVTable *
 -mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, gboolean raise_on_error)
 +mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
        gpointer iter;
        gpointer *interface_offsets;
  
 +      mono_error_init (error);
 +
        mono_loader_lock (); /*FIXME mono_class_init acquires it*/
        mono_domain_lock (domain);
        runtime_info = klass->runtime_info;
                mono_loader_unlock ();
                return runtime_info->domain_vtables [domain->domain_id];
        }
 -      if (!klass->inited || klass->exception_type) {
 -              if (!mono_class_init (klass) || klass->exception_type) {
 +      if (!klass->inited || mono_class_has_failure (klass)) {
 +              if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
                        mono_domain_unlock (domain);
                        mono_loader_unlock ();
 -                      if (raise_on_error)
 -                              mono_raise_exception (mono_class_get_exception_for_failure (klass));
 +                      mono_error_set_for_class_failure (error, klass);
                        return NULL;
                }
        }
                        mono_class_init (element_class);
  
                /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
 -              if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
 +              if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
                        mono_class_setup_vtable (element_class);
                
 -              if (element_class->exception_type != MONO_EXCEPTION_NONE) {
 +              if (mono_class_has_failure (element_class)) {
                        /*Can happen if element_class only got bad after mono_class_setup_vtable*/
 -                      if (klass->exception_type == MONO_EXCEPTION_NONE)
 -                              mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
 +                      if (!mono_class_has_failure (klass))
 +                              mono_class_set_type_load_failure (klass, "");
                        mono_domain_unlock (domain);
                        mono_loader_unlock ();
 -                      if (raise_on_error)
 -                              mono_raise_exception (mono_class_get_exception_for_failure (klass));
 +                      mono_error_set_for_class_failure (error, klass);
                        return NULL;
                }
        }
        if (!klass->vtable_size)
                mono_class_setup_vtable (klass);
  
 -      if (klass->generic_class && !klass->vtable)
 +      if (mono_class_is_ginst (klass) && !klass->vtable)
                mono_class_check_vtable_constraints (klass, NULL);
  
        /* Initialize klass->has_finalize */
        mono_class_has_finalizer (klass);
  
 -      if (klass->exception_type) {
 +      if (mono_class_has_failure (klass)) {
                mono_domain_unlock (domain);
                mono_loader_unlock ();
 -              if (raise_on_error)
 -                      mono_raise_exception (mono_class_get_exception_for_failure (klass));
 +              mono_error_set_for_class_failure (error, klass);
                return NULL;
        }
  
                for (i = 0; i < klass->vtable_size; ++i) {
                        MonoMethod *cm;
  
 -                      if ((cm = klass->vtable [i]))
 -                              vt->vtable [i] = arch_create_jit_trampoline (cm);
 +                      cm = klass->vtable [i];
 +                      if (cm) {
 +                              vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
 +                              if (!is_ok (error)) {
 +                                      mono_domain_unlock (domain);
 +                                      mono_loader_unlock ();
 +                                      return NULL;
 +                              }
 +                      }
                }
        }
  
         * re-acquire them and check if another thread has created the vtable in the meantime.
         */
        /* Special case System.MonoType to avoid infinite recursion */
 -      if (klass != mono_defaults.monotype_class) {
 -              /*FIXME check for OOM*/
 -              vt->type = mono_type_get_object (domain, &klass->byval_arg);
 -              if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
 +      if (klass != mono_defaults.runtimetype_class) {
 +              vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
 +              if (!is_ok (error)) {
 +                      mono_domain_unlock (domain);
 +                      mono_loader_unlock ();
 +                      return NULL;
 +              }
 +
 +              if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
                        /* This is unregistered in
                           unregister_vtable_reflection_type() in
                           domain.c. */
                klass->runtime_info = runtime_info;
        }
  
 -      if (klass == mono_defaults.monotype_class) {
 -              /*FIXME check for OOM*/
 -              vt->type = mono_type_get_object (domain, &klass->byval_arg);
 -              if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
 +      if (klass == mono_defaults.runtimetype_class) {
 +              vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
 +              if (!is_ok (error)) {
 +                      mono_domain_unlock (domain);
 +                      mono_loader_unlock ();
 +                      return NULL;
 +              }
 +
 +              if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
                        /* This is unregistered in
                           unregister_vtable_reflection_type() in
                           domain.c. */
        /* make sure the parent is initialized */
        /*FIXME shouldn't this fail the current type?*/
        if (klass->parent)
 -              mono_class_vtable_full (domain, klass->parent, raise_on_error);
 +              mono_class_vtable_full (domain, klass->parent, error);
  
        return vt;
  }
   * mono_class_proxy_vtable:
   * @domain: the application domain
   * @remove_class: the remote class
 + * @error: set on error
   *
   * Creates a vtable for transparent proxies. It is basically
   * a copy of the real vtable of the class wrapped in @remote_class,
   * but all function pointers invoke the remoting functions, and
   * vtable->klass points to the transparent proxy class, and not to @class.
 + *
 + * On failure returns NULL and sets @error
   */
  static MonoVTable *
 -mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
 +mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type, MonoError *error)
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
 -      MonoError error;
        MonoVTable *vt, *pvt;
-       int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
+       int i, j, vtsize, extra_interface_vtsize = 0;
+       guint32 max_interface_id;
        MonoClass *k;
        GSList *extra_interfaces = NULL;
        MonoClass *klass = remote_class->proxy_class;
        gpointer *interface_offsets;
 -      uint8_t *bitmap;
 +      uint8_t *bitmap = NULL;
        int bsize;
        size_t imt_table_bytes;
        
        int bcsize;
  #endif
  
 +      mono_error_init (error);
 +
        vt = mono_class_vtable (domain, klass);
        g_assert (vt); /*FIXME property handle failure*/
        max_interface_id = vt->max_interface_id;
                
                method_count = mono_class_num_methods (iclass);
        
 -              ifaces = mono_class_get_implemented_interfaces (iclass, &error);
 -              g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
 +              ifaces = mono_class_get_implemented_interfaces (iclass, error);
 +              if (!is_ok (error))
 +                      goto failure;
                if (ifaces) {
                        for (i = 0; i < ifaces->len; ++i) {
                                MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
                                method_count += mono_class_num_methods (ic);
                        }
                        g_ptr_array_free (ifaces, TRUE);
 +                      ifaces = NULL;
                }
  
                extra_interface_vtsize += method_count * sizeof (gpointer);
        for (i = 0; i < klass->vtable_size; ++i) {
                MonoMethod *cm;
                    
 -              if ((cm = klass->vtable [i]))
 -                      pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
 -              else
 +              if ((cm = klass->vtable [i])) {
 +                      pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type, error);
 +                      if (!is_ok (error))
 +                              goto failure;
 +              } else
                        pvt->vtable [i] = NULL;
        }
  
 -      if (klass->flags & TYPE_ATTRIBUTE_ABSTRACT) {
 +      if (mono_class_is_abstract (klass)) {
                /* create trampolines for abstract methods */
                for (k = klass; k; k = k->parent) {
                        MonoMethod* m;
                        gpointer iter = NULL;
                        while ((m = mono_class_get_methods (k, &iter)))
 -                              if (!pvt->vtable [m->slot])
 -                                      pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
 +                              if (!pvt->vtable [m->slot]) {
 +                                      pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type, error);
 +                                      if (!is_ok (error))
 +                                              goto failure;
 +                              }
                }
        }
  
  
                        iter = NULL;
                        j = 0;
 -                      while ((cm = mono_class_get_methods (interf, &iter)))
 -                              pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
 +                      while ((cm = mono_class_get_methods (interf, &iter))) {
 +                              pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type, error);
 +                              if (!is_ok (error))
 +                                      goto failure;
 +                      }
                        
                        slot += mono_class_num_methods (interf);
                }
        pvt->interface_bitmap = bitmap;
  #endif
        return pvt;
 +failure:
 +      if (extra_interfaces)
 +              g_slist_free (extra_interfaces);
 +#ifdef COMPRESSED_INTERFACE_BITMAP
 +      g_free (bitmap);
 +#endif
 +      return NULL;
  }
  
  #endif /* DISABLE_REMOTING */
@@@ -2448,7 -2490,7 +2449,7 @@@ create_remote_class_key (MonoRemoteClas
        int i, j;
        
        if (remote_class == NULL) {
 -              if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
 +              if (mono_class_is_interface (extra_class)) {
                        key = (void **)g_malloc (sizeof(gpointer) * 3);
                        key [0] = GINT_TO_POINTER (2);
                        key [1] = mono_defaults.marshalbyrefobject_class;
                        key [1] = extra_class;
                }
        } else {
 -              if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
 +              if (extra_class != NULL && mono_class_is_interface (extra_class)) {
                        key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
                        key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
                        key [1] = remote_class->proxy_class;
@@@ -2509,23 -2551,21 +2510,23 @@@ copy_remote_class_key (MonoDomain *doma
   * mono_remote_class:
   * @domain: the application domain
   * @class_name: name of the remote class
 + * @error: set on error
   *
   * Creates and initializes a MonoRemoteClass object for a remote type. 
   *
 - * Can raise an exception on failure. 
 + * On failure returns NULL and sets @error
   */
  MonoRemoteClass*
 -mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
 +mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class, MonoError *error)
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
 -      MonoError error;
        MonoRemoteClass *rc;
        gpointer* key, *mp_key;
        char *name;
        
 +      mono_error_init (error);
 +
        key = create_remote_class_key (NULL, proxy_class);
        
        mono_domain_lock (domain);
                return rc;
        }
  
 -      name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
 -      if (!mono_error_ok (&error)) {
 +      name = mono_string_to_utf8_mp (domain->mp, class_name, error);
 +      if (!is_ok (error)) {
                g_free (key);
                mono_domain_unlock (domain);
 -              mono_error_raise_exception (&error);
 +              return NULL;
        }
  
        mp_key = copy_remote_class_key (domain, key);
        g_free (key);
        key = mp_key;
  
 -      if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
 +      if (mono_class_is_interface (proxy_class)) {
                rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
                rc->interface_count = 1;
                rc->interfaces [0] = proxy_class;
@@@ -2595,7 -2635,7 +2596,7 @@@ clone_remote_class (MonoDomain *domain
        g_free (key);
        key = mp_key;
  
 -      if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
 +      if (mono_class_is_interface (extra_class)) {
                int i,j;
                rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
                rc->proxy_class = remote_class->proxy_class;
  }
  
  gpointer
 -mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
 +mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp, MonoError *error)
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
 +      mono_error_init (error);
 +
        mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
        mono_domain_lock (domain);
        if (rp->target_domain_id != -1) {
                if (remote_class->xdomain_vtable == NULL)
 -                      remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
 +                      remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN, error);
                mono_domain_unlock (domain);
                mono_loader_unlock ();
 +              return_val_if_nok (error, NULL);
                return remote_class->xdomain_vtable;
        }
        if (remote_class->default_vtable == NULL) {
                klass = mono_class_from_mono_type (type);
  #ifndef DISABLE_COM
                if ((mono_class_is_com_object (klass) || (mono_class_get_com_object_class () && klass == mono_class_get_com_object_class ())) && !mono_vtable_is_remote (mono_class_vtable (mono_domain_get (), klass)))
 -                      remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
 +                      remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP, error);
                else
  #endif
 -                      remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
 +                      remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN, error);
 +              /* N.B. both branches of the if modify error */
 +              if (!is_ok (error)) {
 +                      mono_domain_unlock (domain);
 +                      mono_loader_unlock ();
 +                      return NULL;
 +              }
        }
        
        mono_domain_unlock (domain);
   * @domain: the application domain
   * @tproxy: the proxy whose remote class has to be upgraded.
   * @klass: class to which the remote class can be casted.
 + * @error: set on error
   *
   * Updates the vtable of the remote class by adding the necessary method slots
   * and interface offsets so it can be safely casted to klass. klass can be a
 - * class or an interface.
 + * class or an interface.  On success returns TRUE, on failure returns FALSE and sets @error.
   */
 -void
 -mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
 +gboolean
 +mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass, MonoError *error)
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
        MonoRemoteClass *remote_class;
        gboolean redo_vtable;
  
 +      mono_error_init (error);
        mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
        mono_domain_lock (domain);
  
        tproxy = (MonoTransparentProxy*) proxy_object;
        remote_class = tproxy->remote_class;
        
 -      if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
 +      if (mono_class_is_interface (klass)) {
                int i;
                redo_vtable = TRUE;
                for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
  
        if (redo_vtable) {
                tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
 -              proxy_object->vtable = (MonoVTable *)mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
 +              proxy_object->vtable = (MonoVTable *)mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp, error);
 +              if (!is_ok (error))
 +                      goto leave;
        }
        
 +leave:
        mono_domain_unlock (domain);
        mono_loader_unlock ();
 +      return is_ok (error);
  }
  #endif /* DISABLE_REMOTING */
  
@@@ -2767,7 -2792,7 +2768,7 @@@ mono_object_get_virtual_method (MonoObj
  
        /* check method->slot is a valid index: perform isinstance? */
        if (method->slot != -1) {
 -              if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
 +              if (mono_class_is_interface (method->klass)) {
                        if (!is_proxy) {
                                gboolean variance_used = FALSE;
                                int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
  }
  
  static MonoObject*
 -dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
 +do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
  {
 -      g_error ("runtime invoke called on uninitialized runtime");
 -      return NULL;
 -}
 +      MONO_REQ_GC_UNSAFE_MODE;
 +
 +      MonoObject *result = NULL;
 +
 +      g_assert (callbacks.runtime_invoke);
  
 -static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
 +      mono_error_init (error);
 +      
 +      if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
 +              mono_profiler_method_start_invoke (method);
 +
 +      result = callbacks.runtime_invoke (method, obj, params, exc, error);
 +
 +      if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
 +              mono_profiler_method_end_invoke (method);
 +
 +      if (!mono_error_ok (error))
 +              return NULL;
 +
 +      return result;
 +}
  
  /**
   * mono_runtime_invoke:
  MonoObject*
  mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
  {
 -      MONO_REQ_GC_UNSAFE_MODE;
 -
 -      MonoObject *result;
 -
 -      if (mono_runtime_get_no_exec ())
 -              g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
 -
 -      if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
 -              mono_profiler_method_start_invoke (method);
 -
 -      result = default_mono_runtime_invoke (method, obj, params, exc);
 -
 -      if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
 -              mono_profiler_method_end_invoke (method);
 -
 -      return result;
 +      MonoError error;
 +      MonoObject *res;
 +      if (exc) {
 +              res = mono_runtime_try_invoke (method, obj, params, exc, &error);
 +              if (*exc == NULL && !mono_error_ok(&error)) {
 +                      *exc = (MonoObject*) mono_error_convert_to_exception (&error);
 +              } else
 +                      mono_error_cleanup (&error);
 +      } else {
 +              res = mono_runtime_invoke_checked (method, obj, params, &error);
 +              mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
 +      }
 +      return res;
  }
  
  /**
 - * mono_method_get_unmanaged_thunk:
 - * @method: method to generate a thunk for.
 + * mono_runtime_try_invoke:
 + * @method: method to invoke
 + * @obJ: object instance
 + * @params: arguments to the method
 + * @exc: exception information.
 + * @error: set on error
   *
 - * Returns an unmanaged->managed thunk that can be used to call
 - * a managed method directly from C.
 + * Invokes the method represented by @method on the object @obj.
   *
 - * The thunk's C signature closely matches the managed signature:
 + * obj is the 'this' pointer, it should be NULL for static
 + * methods, a MonoObject* for object instances and a pointer to
 + * the value type for value types.
   *
 - * C#: public bool Equals (object obj);
 + * The params array contains the arguments to the method with the
 + * same convention: MonoObject* pointers for object instances and
 + * pointers to the value type otherwise. 
 + * 
 + * From unmanaged code you'll usually use the
 + * mono_runtime_invoke() variant.
 + *
 + * Note that this function doesn't handle virtual methods for
 + * you, it will exec the exact method you pass: we still need to
 + * expose a function to lookup the derived class implementation
 + * of a virtual method (there are examples of this in the code,
 + * though).
 + * 
 + * For this function, you must not pass NULL as the exc argument if
 + * you don't want to catch exceptions, use
 + * mono_runtime_invoke_checked().  If an exception is thrown, you
 + * can't use the MonoObject* result from the function.
 + * 
 + * If this method cannot be invoked, @error will be set and @exc and
 + * the return value must not be used.
 + *
 + * If the method returns a value type, it is boxed in an object
 + * reference.
 + */
 +MonoObject*
 +mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
 +{
 +      MONO_REQ_GC_UNSAFE_MODE;
 +
 +      g_assert (exc != NULL);
 +
 +      if (mono_runtime_get_no_exec ())
 +              g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
 +
 +      return do_runtime_invoke (method, obj, params, exc, error);
 +}
 +
 +/**
 + * mono_runtime_invoke_checked:
 + * @method: method to invoke
 + * @obJ: object instance
 + * @params: arguments to the method
 + * @error: set on error
 + *
 + * Invokes the method represented by @method on the object @obj.
 + *
 + * obj is the 'this' pointer, it should be NULL for static
 + * methods, a MonoObject* for object instances and a pointer to
 + * the value type for value types.
 + *
 + * The params array contains the arguments to the method with the
 + * same convention: MonoObject* pointers for object instances and
 + * pointers to the value type otherwise. 
 + * 
 + * From unmanaged code you'll usually use the
 + * mono_runtime_invoke() variant.
 + *
 + * Note that this function doesn't handle virtual methods for
 + * you, it will exec the exact method you pass: we still need to
 + * expose a function to lookup the derived class implementation
 + * of a virtual method (there are examples of this in the code,
 + * though).
 + * 
 + * If an exception is thrown, you can't use the MonoObject* result
 + * from the function.
 + * 
 + * If this method cannot be invoked, @error will be set.  If the
 + * method throws an exception (and we're in coop mode) the exception
 + * will be set in @error.
 + *
 + * If the method returns a value type, it is boxed in an object
 + * reference.
 + */
 +MonoObject*
 +mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
 +{
 +      MONO_REQ_GC_UNSAFE_MODE;
 +
 +      if (mono_runtime_get_no_exec ())
 +              g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
 +
 +      return do_runtime_invoke (method, obj, params, NULL, error);
 +}
 +
 +/**
 + * mono_method_get_unmanaged_thunk:
 + * @method: method to generate a thunk for.
 + *
 + * Returns an unmanaged->managed thunk that can be used to call
 + * a managed method directly from C.
 + *
 + * The thunk's C signature closely matches the managed signature:
 + *
 + * C#: public bool Equals (object obj);
   * C:  typedef MonoBoolean (*Equals)(MonoObject*,
   *             MonoObject*, MonoException**);
   *
@@@ -3043,16 -2957,12 +3044,16 @@@ mono_method_get_unmanaged_thunk (MonoMe
        MONO_REQ_GC_NEUTRAL_MODE;
        MONO_REQ_API_ENTRYPOINT;
  
 +      MonoError error;
        gpointer res;
  
 -      MONO_PREPARE_RESET_BLOCKING;
 +      g_assert (!mono_threads_is_coop_enabled ());
 +
 +      MONO_ENTER_GC_UNSAFE;
        method = mono_marshal_get_thunk_invoke_wrapper (method);
 -      res = mono_compile_method (method);
 -      MONO_FINISH_RESET_BLOCKING;
 +      res = mono_compile_method_checked (method, &error);
 +      mono_error_cleanup (&error);
 +      MONO_EXIT_GC_UNSAFE;
  
        return res;
  }
@@@ -3300,30 -3210,8 +3301,30 @@@ mono_field_get_value (MonoObject *obj, 
  MonoObject *
  mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
  {     
 +      MonoError error;
 +      MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
 +      mono_error_assert_ok (&error);
 +      return result;
 +}
 +
 +/**
 + * mono_field_get_value_object_checked:
 + * @domain: domain where the object will be created (if boxing)
 + * @field: MonoClassField describing the field to fetch information from
 + * @obj: The object instance for the field.
 + * @error: Set on error.
 + *
 + * Returns: a new MonoObject with the value from the given field.  If the
 + * field represents a value type, the value is boxed.  On error returns NULL and sets @error.
 + *
 + */
 +MonoObject *
 +mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
 +{
        MONO_REQ_GC_UNSAFE_MODE;
  
 +      mono_error_init (error);
 +
        MonoObject *o;
        MonoClass *klass;
        MonoVTable *vtable = NULL;
        gboolean is_ref = FALSE;
        gboolean is_literal = FALSE;
        gboolean is_ptr = FALSE;
 -      MonoError error;
 -      MonoType *type = mono_field_get_type_checked (field, &error);
 +      MonoType *type = mono_field_get_type_checked (field, error);
  
 -      if (!mono_error_ok (&error))
 -              mono_error_raise_exception (&error);
 +      return_val_if_nok (error, NULL);
  
        switch (type->type) {
        case MONO_TYPE_STRING:
                is_static = TRUE;
  
                if (!is_literal) {
 -                      vtable = mono_class_vtable_full (domain, field->parent, TRUE);
 -                      if (!vtable->initialized)
 -                              mono_runtime_class_init (vtable);
 +                      vtable = mono_class_vtable_full (domain, field->parent, error);
 +                      return_val_if_nok (error, NULL);
 +
 +                      if (!vtable->initialized) {
 +                              mono_runtime_class_init_full (vtable, error);
 +                              return_val_if_nok (error, NULL);
 +                      }
                }
        } else {
                g_assert (obj);
        
        if (is_ref) {
                if (is_literal) {
 -                      get_default_field_value (domain, field, &o);
 +                      get_default_field_value (domain, field, &o, error);
 +                      return_val_if_nok (error, NULL);
                } else if (is_static) {
 -                      mono_field_static_get_value (vtable, field, &o);
 +                      mono_field_static_get_value_checked (vtable, field, &o, error);
 +                      return_val_if_nok (error, NULL);
                } else {
                        mono_field_get_value (obj, field, &o);
                }
                gpointer v;
  
                if (!m) {
 -                      MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
 +                      MonoClass *ptr_klass = mono_class_get_pointer_class ();
                        m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
                        g_assert (m);
                }
  
                v = &ptr;
                if (is_literal) {
 -                      get_default_field_value (domain, field, v);
 +                      get_default_field_value (domain, field, v, error);
 +                      return_val_if_nok (error, NULL);
                } else if (is_static) {
 -                      mono_field_static_get_value (vtable, field, v);
 +                      mono_field_static_get_value_checked (vtable, field, v, error);
 +                      return_val_if_nok (error, NULL);
                } else {
                        mono_field_get_value (obj, field, v);
                }
  
                /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
                args [0] = ptr ? *ptr : NULL;
 -              args [1] = mono_type_get_object (mono_domain_get (), type);
 +              args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
 +              return_val_if_nok (error, NULL);
 +
 +              o = mono_runtime_invoke_checked (m, NULL, args, error);
 +              return_val_if_nok (error, NULL);
  
 -              return mono_runtime_invoke (m, NULL, args, NULL);
 +              return o;
        }
  
        /* boxed value type */
        klass = mono_class_from_mono_type (type);
  
        if (mono_class_is_nullable (klass))
 -              return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
 +              return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
  
 -      o = mono_object_new (domain, klass);
 +      o = mono_object_new_checked (domain, klass, error);
 +      return_val_if_nok (error, NULL);
        v = ((gchar *) o) + sizeof (MonoObject);
  
        if (is_literal) {
 -              get_default_field_value (domain, field, v);
 +              get_default_field_value (domain, field, v, error);
 +              return_val_if_nok (error, NULL);
        } else if (is_static) {
 -              mono_field_static_get_value (vtable, field, v);
 +              mono_field_static_get_value_checked (vtable, field, v, error);
 +              return_val_if_nok (error, NULL);
        } else {
                mono_field_get_value (obj, field, v);
        }
  }
  
  int
 -mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
 +mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
 +      mono_error_init (error);
        int retval = 0;
        const char *p = blob;
        mono_metadata_decode_blob_size (p, &p);
                readr8 (p, (double*) value);
                break;
        case MONO_TYPE_STRING:
 -              *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
 +              *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob, error);
                break;
        case MONO_TYPE_CLASS:
                *(gpointer*) value = NULL;
  }
  
  static void
 -get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
 +get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
  {
        MONO_REQ_GC_NEUTRAL_MODE;
  
        MonoTypeEnum def_type;
        const char* data;
 +
 +      mono_error_init (error);
        
        data = mono_class_get_field_default_value (field, &def_type);
 -      mono_get_constant_value_from_blob (domain, def_type, data, value);
 +      mono_get_constant_value_from_blob (domain, def_type, data, value, error);
  }
  
  void
 -mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
 +mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
        void *src;
  
 +      mono_error_init (error);
 +
        g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
        
        if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
 -              get_default_field_value (vt->domain, field, value);
 +              get_default_field_value (vt->domain, field, value, error);
                return;
        }
  
@@@ -3571,37 -3441,7 +3572,37 @@@ mono_field_static_get_value (MonoVTabl
  {
        MONO_REQ_GC_NEUTRAL_MODE;
  
 -      mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
 +      MonoError error;
 +      mono_field_static_get_value_checked (vt, field, value, &error);
 +      mono_error_cleanup (&error);
 +}
 +
 +/**
 + * mono_field_static_get_value_checked:
 + * @vt: vtable to the object
 + * @field: MonoClassField describing the field to fetch information from
 + * @value: where the value is returned
 + * @error: set on error
 + *
 + * Use this routine to get the value of the static field @field value.
 + *
 + * The pointer provided by value must be of the field type, for reference
 + * types this is a MonoObject*, for value types its the actual pointer to
 + * the value type.
 + *
 + * For example:
 + *     int i;
 + *     mono_field_static_get_value_checked (vt, int_field, &i, error);
 + *     if (!is_ok (error)) { ... }
 + *
 + * On failure sets @error.
 + */
 +void
 +mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
 +{
 +      MONO_REQ_GC_NEUTRAL_MODE;
 +
 +      mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
  }
  
  /**
@@@ -3624,40 -3464,7 +3625,40 @@@ mono_property_set_value (MonoProperty *
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
 -      default_mono_runtime_invoke (prop->set, obj, params, exc);
 +      MonoError error;
 +      do_runtime_invoke (prop->set, obj, params, exc, &error);
 +      if (exc && *exc == NULL && !mono_error_ok (&error)) {
 +              *exc = (MonoObject*) mono_error_convert_to_exception (&error);
 +      } else {
 +              mono_error_cleanup (&error);
 +      }
 +}
 +
 +/**
 + * mono_property_set_value_checked:
 + * @prop: MonoProperty to set
 + * @obj: instance object on which to act
 + * @params: parameters to pass to the propery
 + * @error: set on error
 + *
 + * Invokes the property's set method with the given arguments on the
 + * object instance obj (or NULL for static properties). 
 + * 
 + * Returns: TRUE on success.  On failure returns FALSE and sets @error.
 + * If an exception is thrown, it will be caught and returned via @error.
 + */
 +gboolean
 +mono_property_set_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
 +{
 +      MONO_REQ_GC_UNSAFE_MODE;
 +
 +      MonoObject *exc;
 +
 +      mono_error_init (error);
 +      do_runtime_invoke (prop->set, obj, params, &exc, error);
 +      if (exc != NULL && is_ok (error))
 +              mono_error_set_exception_instance (error, (MonoException*)exc);
 +      return is_ok (error);
  }
  
  /**
@@@ -3682,48 -3489,9 +3683,48 @@@ mono_property_get_value (MonoProperty *
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
 -      return default_mono_runtime_invoke (prop->get, obj, params, exc);
 +      MonoError error;
 +      MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
 +      if (exc && *exc == NULL && !mono_error_ok (&error)) {
 +              *exc = (MonoObject*) mono_error_convert_to_exception (&error);
 +      } else {
 +              mono_error_cleanup (&error); /* FIXME don't raise here */
 +      }
 +
 +      return val;
 +}
 +
 +/**
 + * mono_property_get_value_checked:
 + * @prop: MonoProperty to fetch
 + * @obj: instance object on which to act
 + * @params: parameters to pass to the propery
 + * @error: set on error
 + *
 + * Invokes the property's get method with the given arguments on the
 + * object instance obj (or NULL for static properties). 
 + * 
 + * If an exception is thrown, you can't use the
 + * MonoObject* result from the function.  The exception will be propagated via @error.
 + *
 + * Returns: the value from invoking the get method on the property. On
 + * failure returns NULL and sets @error.
 + */
 +MonoObject*
 +mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
 +{
 +      MONO_REQ_GC_UNSAFE_MODE;
 +
 +      MonoObject *exc;
 +      MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
 +      if (exc != NULL && !is_ok (error))
 +              mono_error_set_exception_instance (error, (MonoException*) exc);
 +      if (!is_ok (error))
 +              val = NULL;
 +      return val;
  }
  
 +
  /*
   * mono_nullable_init:
   * @buf: The nullable structure to initialize.
@@@ -3745,7 -3513,7 +3746,7 @@@ mono_nullable_init (guint8 *buf, MonoOb
  
        MonoClass *param_class = klass->cast_class;
  
 -      mono_class_setup_fields_locking (klass);
 +      mono_class_setup_fields (klass);
        g_assert (klass->fields_inited);
                                
        g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
   * mono_nullable_box:
   * @buf: The buffer representing the data to be boxed
   * @klass: the type to box it as.
 + * @error: set on oerr
   *
   * Creates a boxed vtype or NULL from the Nullable structure pointed to by
 - * @buf.
 + * @buf.  On failure returns NULL and sets @error
   */
  MonoObject*
 -mono_nullable_box (guint8 *buf, MonoClass *klass)
 +mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
 +      mono_error_init (error);
        MonoClass *param_class = klass->cast_class;
  
 -      mono_class_setup_fields_locking (klass);
 +      mono_class_setup_fields (klass);
        g_assert (klass->fields_inited);
  
        g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
        g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
  
        if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
 -              MonoObject *o = mono_object_new (mono_domain_get (), param_class);
 +              MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
 +              return_val_if_nok (error, NULL);
                if (param_class->has_references)
                        mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
                else
@@@ -3813,7 -3578,7 +3814,7 @@@ mono_get_delegate_invoke (MonoClass *kl
  
        /* This is called at runtime, so avoid the slower search in metadata */
        mono_class_setup_methods (klass);
 -      if (klass->exception_type)
 +      if (mono_class_has_failure (klass))
                return NULL;
        im = mono_class_get_method_from_name (klass, "Invoke", -1);
        return im;
@@@ -3834,7 -3599,7 +3835,7 @@@ mono_get_delegate_begin_invoke (MonoCla
  
        /* This is called at runtime, so avoid the slower search in metadata */
        mono_class_setup_methods (klass);
 -      if (klass->exception_type)
 +      if (mono_class_has_failure (klass))
                return NULL;
        im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
        return im;
@@@ -3855,7 -3620,7 +3856,7 @@@ mono_get_delegate_end_invoke (MonoClas
  
        /* This is called at runtime, so avoid the slower search in metadata */
        mono_class_setup_methods (klass);
 -      if (klass->exception_type)
 +      if (mono_class_has_failure (klass))
                return NULL;
        im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
        return im;
@@@ -3879,78 -3644,14 +3880,78 @@@ mono_runtime_delegate_invoke (MonoObjec
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
 +      MonoError error;
 +      if (exc) {
 +              MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, &error);
 +              if (*exc) {
 +                      mono_error_cleanup (&error);
 +                      return NULL;
 +              } else {
 +                      if (!is_ok (&error))
 +                              *exc = (MonoObject*)mono_error_convert_to_exception (&error);
 +                      return result;
 +              }
 +      } else {
 +              MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &error);
 +              mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
 +              return result;
 +      }
 +}
 +
 +/**
 + * mono_runtime_delegate_try_invoke:
 + * @delegate: pointer to a delegate object.
 + * @params: parameters for the delegate.
 + * @exc: Pointer to the exception result.
 + * @error: set on error
 + *
 + * Invokes the delegate method @delegate with the parameters provided.
 + *
 + * You can pass NULL as the exc argument if you don't want to
 + * catch exceptions, otherwise, *exc will be set to the exception
 + * thrown, if any.  On failure to execute, @error will be set.
 + * if an exception is thrown, you can't use the
 + * MonoObject* result from the function.
 + */
 +MonoObject*
 +mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
 +{
 +      MONO_REQ_GC_UNSAFE_MODE;
 +
 +      mono_error_init (error);
        MonoMethod *im;
        MonoClass *klass = delegate->vtable->klass;
 +      MonoObject *o;
  
        im = mono_get_delegate_invoke (klass);
        if (!im)
                g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
  
 -      return mono_runtime_invoke (im, delegate, params, exc);
 +      if (exc) {
 +              o = mono_runtime_try_invoke (im, delegate, params, exc, error);
 +      } else {
 +              o = mono_runtime_invoke_checked (im, delegate, params, error);
 +      }
 +
 +      return o;
 +}
 +
 +/**
 + * mono_runtime_delegate_invoke_checked:
 + * @delegate: pointer to a delegate object.
 + * @params: parameters for the delegate.
 + * @error: set on error
 + *
 + * Invokes the delegate method @delegate with the parameters provided.
 + *
 + * On failure @error will be set and you can't use the MonoObject*
 + * result from the function.
 + */
 +MonoObject*
 +mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
 +{
 +      mono_error_init (error);
 +      return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
  }
  
  static char **main_args = NULL;
@@@ -3965,30 -3666,12 +3966,30 @@@ MonoArray
  mono_runtime_get_main_args (void)
  {
        MONO_REQ_GC_UNSAFE_MODE;
 +      MonoError error;
 +      MonoArray *result = mono_runtime_get_main_args_checked (&error);
 +      mono_error_assert_ok (&error);
 +      return result;
 +}
  
 +/**
 + * mono_runtime_get_main_args:
 + * @error: set on error
 + *
 + * Returns: a MonoArray with the arguments passed to the main
 + * program. On failure returns NULL and sets @error.
 + */
 +MonoArray*
 +mono_runtime_get_main_args_checked (MonoError *error)
 +{
        MonoArray *res;
        int i;
        MonoDomain *domain = mono_domain_get ();
  
 -      res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
 +      mono_error_init (error);
 +
 +      res = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, num_main_args, error);
 +      return_val_if_nok (error, NULL);
  
        for (i = 0; i < num_main_args; ++i)
                mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
@@@ -4045,18 -3728,25 +4046,18 @@@ mono_runtime_set_main_args (int argc, c
        return 0;
  }
  
 -/**
 - * mono_runtime_run_main:
 - * @method: the method to start the application with (usually Main)
 - * @argc: number of arguments from the command line
 - * @argv: array of strings from the command line
 - * @exc: excetption results
 - *
 - * Execute a standard Main() method (argc/argv contains the
 - * executable name). This method also sets the command line argument value
 - * needed by System.Environment.
 - *
 +/*
 + * Prepare an array of arguments in order to execute a standard Main()
 + * method (argc/argv contains the executable name). This method also
 + * sets the command line argument value needed by System.Environment.
   * 
   */
 -int
 -mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
 -                     MonoObject **exc)
 +static MonoArray*
 +prepare_run_main (MonoMethod *method, int argc, char *argv[])
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
 +      MonoError error;
        int i;
        MonoArray *args = NULL;
        MonoDomain *domain = mono_domain_get ();
        }
  
        if (sig->param_count) {
 -              args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
 +              args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, &error);
 +              mono_error_assert_ok (&error);
                for (i = 0; i < argc; ++i) {
                        /* The encodings should all work, given that
                         * we've checked all these args for the
                        g_free (str);
                }
        } else {
 -              args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
 +              args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
 +              mono_error_assert_ok (&error);
        }
        
        mono_assembly_set_main (method->klass->image->assembly);
  
 -      return mono_runtime_exec_main (method, args, exc);
 +      return args;
 +}
 +
 +/**
 + * mono_runtime_run_main:
 + * @method: the method to start the application with (usually Main)
 + * @argc: number of arguments from the command line
 + * @argv: array of strings from the command line
 + * @exc: excetption results
 + *
 + * Execute a standard Main() method (argc/argv contains the
 + * executable name). This method also sets the command line argument value
 + * needed by System.Environment.
 + *
 + * 
 + */
 +int
 +mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
 +                     MonoObject **exc)
 +{
 +      MONO_REQ_GC_UNSAFE_MODE;
 +
 +      MonoError error;
 +      MonoArray *args = prepare_run_main (method, argc, argv);
 +      int res;
 +      if (exc) {
 +              res = mono_runtime_try_exec_main (method, args, exc);
 +      } else {
 +              res = mono_runtime_exec_main_checked (method, args, &error);
 +              mono_error_raise_exception (&error); /* OK to throw, external only without a better alternative */
 +      }
 +      return res;
 +}
 +
 +/**
 + * mono_runtime_run_main_checked:
 + * @method: the method to start the application with (usually Main)
 + * @argc: number of arguments from the command line
 + * @argv: array of strings from the command line
 + * @error: set on error
 + *
 + * Execute a standard Main() method (argc/argv contains the
 + * executable name). This method also sets the command line argument value
 + * needed by System.Environment.  On failure sets @error.
 + *
 + * 
 + */
 +int
 +mono_runtime_run_main_checked (MonoMethod *method, int argc, char* argv[],
 +                             MonoError *error)
 +{
 +      mono_error_init (error);
 +      MonoArray *args = prepare_run_main (method, argc, argv);
 +      return mono_runtime_exec_main_checked (method, args, error);
 +}
 +
 +/**
 + * mono_runtime_try_run_main:
 + * @method: the method to start the application with (usually Main)
 + * @argc: number of arguments from the command line
 + * @argv: array of strings from the command line
 + * @exc: set if Main throws an exception
 + * @error: set if Main can't be executed
 + *
 + * Execute a standard Main() method (argc/argv contains the executable
 + * name). This method also sets the command line argument value needed
 + * by System.Environment.  On failure sets @error if Main can't be
 + * executed or @exc if it threw and exception.
 + *
 + * 
 + */
 +int
 +mono_runtime_try_run_main (MonoMethod *method, int argc, char* argv[],
 +                         MonoObject **exc)
 +{
 +      g_assert (exc);
 +      MonoArray *args = prepare_run_main (method, argc, argv);
 +      return mono_runtime_try_exec_main (method, args, exc);
  }
  
 -static MonoObject*
 -serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
 -{
 -      static MonoMethod *serialize_method;
 -
 -      void *params [1];
 -      MonoObject *array;
 -
 -      if (!serialize_method) {
 -              MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
 -              serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
 -      }
 -
 -      if (!serialize_method) {
 -              *failure = TRUE;
 -              return NULL;
 -      }
 +
 +static MonoObject*
 +serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
 +{
 +      static MonoMethod *serialize_method;
 +
 +      MonoError error;
 +      void *params [1];
 +      MonoObject *array;
 +
 +      if (!serialize_method) {
 +              MonoClass *klass = mono_class_get_remoting_services_class ();
 +              serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
 +      }
 +
 +      if (!serialize_method) {
 +              *failure = TRUE;
 +              return NULL;
 +      }
  
        g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
  
        params [0] = obj;
        *exc = NULL;
 -      array = mono_runtime_invoke (serialize_method, NULL, params, exc);
 +
 +      array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
 +      if (*exc == NULL && !mono_error_ok (&error))
 +              *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
 +      else
 +              mono_error_cleanup (&error);
 +
        if (*exc)
                *failure = TRUE;
  
@@@ -4267,12 -3870,11 +4268,12 @@@ deserialize_object (MonoObject *obj, gb
  
        static MonoMethod *deserialize_method;
  
 +      MonoError error;
        void *params [1];
        MonoObject *result;
  
        if (!deserialize_method) {
 -              MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
 +              MonoClass *klass = mono_class_get_remoting_services_class ();
                deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
        }
        if (!deserialize_method) {
  
        params [0] = obj;
        *exc = NULL;
 -      result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
 +
 +      result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
 +      if (*exc == NULL && !mono_error_ok (&error))
 +              *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
 +      else
 +              mono_error_cleanup (&error);
 +
        if (*exc)
                *failure = TRUE;
  
  
  #ifndef DISABLE_REMOTING
  static MonoObject*
 -make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
 +make_transparent_proxy (MonoObject *obj, MonoError *error)
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
        MonoReflectionType *reflection_type;
        MonoTransparentProxy *transparent_proxy;
  
 +      mono_error_init (error);
 +
        if (!get_proxy_method)
                get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
  
        g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
  
 -      real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
 -      reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
 +      real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, error);
 +      return_val_if_nok (error, NULL);
 +      reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, error);
 +      return_val_if_nok (error, NULL);
  
        MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
        MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
  
 -      *exc = NULL;
 -      transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
 -      if (*exc)
 -              *failure = TRUE;
 +      MonoObject *exc = NULL;
 +
 +      transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, &exc, error);
 +      if (exc != NULL && is_ok (error))
 +              mono_error_set_exception_instance (error, (MonoException*)exc);
  
        return (MonoObject*) transparent_proxy;
  }
   * mono_object_xdomain_representation
   * @obj: an object
   * @target_domain: a domain
 - * @exc: pointer to a MonoObject*
 + * @error: set on error.
   *
   * Creates a representation of obj in the domain target_domain.  This
   * is either a copy of obj arrived through via serialization and
   * serializable or marshal by ref.  obj must not be in target_domain.
   *
   * If the object cannot be represented in target_domain, NULL is
 - * returned and *exc is set to an appropriate exception.
 + * returned and @error is set appropriately.
   */
  MonoObject*
 -mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
 +mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoError *error)
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
 +      mono_error_init (error);
        MonoObject *deserialized = NULL;
 -      gboolean failure = FALSE;
 -
 -      *exc = NULL;
  
  #ifndef DISABLE_REMOTING
        if (mono_class_is_marshalbyref (mono_object_class (obj))) {
 -              deserialized = make_transparent_proxy (obj, &failure, exc);
 +              deserialized = make_transparent_proxy (obj, error);
        } 
        else
  #endif
        {
 +              gboolean failure = FALSE;
                MonoDomain *domain = mono_domain_get ();
                MonoObject *serialized;
 +              MonoObject *exc = NULL;
  
                mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
 -              serialized = serialize_object (obj, &failure, exc);
 +              serialized = serialize_object (obj, &failure, &exc);
                mono_domain_set_internal_with_options (target_domain, FALSE);
                if (!failure)
 -                      deserialized = deserialize_object (serialized, &failure, exc);
 +                      deserialized = deserialize_object (serialized, &failure, &exc);
                if (domain != target_domain)
                        mono_domain_set_internal_with_options (domain, FALSE);
 +              if (failure)
 +                      mono_error_set_exception_instance (error, (MonoException*)exc);
        }
  
        return deserialized;
  
  /* Used in call_unhandled_exception_delegate */
  static MonoObject *
 -create_unhandled_exception_eventargs (MonoObject *exc)
 +create_unhandled_exception_eventargs (MonoObject *exc, MonoError *error)
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
 +      mono_error_init (error);
        MonoClass *klass;
        gpointer args [2];
        MonoMethod *method = NULL;
        MonoBoolean is_terminating = TRUE;
        MonoObject *obj;
  
 -      klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
 -      g_assert (klass);
 -
 +      klass = mono_class_get_unhandled_exception_event_args_class ();
        mono_class_init (klass);
  
        /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
        args [0] = exc;
        args [1] = &is_terminating;
  
 -      obj = mono_object_new (mono_domain_get (), klass);
 -      mono_runtime_invoke (method, obj, args, NULL);
 +      obj = mono_object_new_checked (mono_domain_get (), klass, error);
 +      return_val_if_nok (error, NULL);
 +
 +      mono_runtime_invoke_checked (method, obj, args, error);
 +      return_val_if_nok (error, NULL);
  
        return obj;
  }
@@@ -4418,7 -4005,6 +4419,7 @@@ static voi
  call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
        MONO_REQ_GC_UNSAFE_MODE;
  
 +      MonoError error;
        MonoObject *e = NULL;
        gpointer pa [2];
        MonoDomain *current_domain = mono_domain_get ();
        g_assert (domain == mono_object_domain (domain->domain));
  
        if (mono_object_domain (exc) != domain) {
 -              MonoObject *serialization_exc;
  
 -              exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
 +              exc = mono_object_xdomain_representation (exc, domain, &error);
                if (!exc) {
 -                      if (serialization_exc) {
 -                              MonoObject *dummy;
 -                              exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
 -                              g_assert (exc);
 +                      if (!is_ok (&error)) {
 +                              MonoError inner_error;
 +                              MonoException *serialization_exc = mono_error_convert_to_exception (&error);
 +                              exc = mono_object_xdomain_representation ((MonoObject*)serialization_exc, domain, &inner_error);
 +                              mono_error_assert_ok (&inner_error);
                        } else {
                                exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
                                                "System.Runtime.Serialization", "SerializationException",
        g_assert (mono_object_domain (exc) == domain);
  
        pa [0] = domain->domain;
 -      pa [1] = create_unhandled_exception_eventargs (exc);
 -      mono_runtime_delegate_invoke (delegate, pa, &e);
 +      pa [1] = create_unhandled_exception_eventargs (exc, &error);
 +      mono_error_assert_ok (&error);
 +      mono_runtime_delegate_try_invoke (delegate, pa, &e, &error);
 +      if (!is_ok (&error)) {
 +              if (e == NULL)
 +                      e = (MonoObject*)mono_error_convert_to_exception (&error);
 +              else
 +                      mono_error_cleanup (&error);
 +      }
  
        if (domain != current_domain)
                mono_domain_set_internal_with_options (current_domain, FALSE);
  
        if (e) {
 -              MonoError error;
                gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
                if (!mono_error_ok (&error)) {
                        g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
@@@ -4516,7 -4096,6 +4517,7 @@@ mono_unhandled_exception (MonoObject *e
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
 +      MonoError error;
        MonoClassField *field;
        MonoDomain *current_domain, *root_domain;
        MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
        current_domain = mono_domain_get ();
        root_domain = mono_get_root_domain ();
  
 -      root_appdomain_delegate = mono_field_get_value_object (root_domain, field, (MonoObject*) root_domain->domain);
 -      if (current_domain != root_domain)
 -              current_appdomain_delegate = mono_field_get_value_object (current_domain, field, (MonoObject*) current_domain->domain);
 +      root_appdomain_delegate = mono_field_get_value_object_checked (root_domain, field, (MonoObject*) root_domain->domain, &error);
 +      mono_error_assert_ok (&error);
 +      if (current_domain != root_domain) {
 +              current_appdomain_delegate = mono_field_get_value_object_checked (current_domain, field, (MonoObject*) current_domain->domain, &error);
 +              mono_error_assert_ok (&error);
 +      }
  
 -      /* set exitcode only if we will abort the process */
        if (!current_appdomain_delegate && !root_appdomain_delegate) {
 -              if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
 -                   || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
 -              {
 -                      mono_environment_exitcode_set (1);
 -              }
 -
                mono_print_unhandled_exception (exc);
        } else {
 +              /* unhandled exception callbacks must not be aborted */
 +              mono_threads_begin_abort_protected_block ();
                if (root_appdomain_delegate)
                        call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
                if (current_appdomain_delegate)
                        call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
 +              mono_threads_end_abort_protected_block ();
 +      }
 +
 +      /* set exitcode only if we will abort the process */
 +      if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
 +               || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
 +      {
 +              mono_environment_exitcode_set (1);
        }
  }
  
@@@ -4578,20 -4151,32 +4579,20 @@@ mono_runtime_exec_managed_code (MonoDom
                                MonoMainThreadFunc main_func,
                                gpointer main_args)
  {
 -      mono_thread_create (domain, main_func, main_args);
 +      MonoError error;
 +      mono_thread_create_checked (domain, main_func, main_args, &error);
 +      mono_error_assert_ok (&error);
  
        mono_thread_manage ();
  }
  
 -/*
 - * Execute a standard Main() method (args doesn't contain the
 - * executable name).
 - */
 -int
 -mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
 +static void
 +prepare_thread_to_exec_main (MonoDomain *domain, MonoMethod *method)
  {
 -      MONO_REQ_GC_UNSAFE_MODE;
 -
 -      MonoDomain *domain;
 -      gpointer pa [1];
 -      int rval;
 +      MonoInternalThread* thread = mono_thread_internal_current ();
        MonoCustomAttrInfo* cinfo;
        gboolean has_stathread_attribute;
 -      MonoInternalThread* thread = mono_thread_internal_current ();
 -
 -      g_assert (args);
  
 -      pa [0] = args;
 -
 -      domain = mono_object_domain (args);
        if (!domain->entry_assembly) {
                gchar *str;
                MonoAssembly *assembly;
                        str = g_strconcat (assembly->image->name, ".config", NULL);
                        MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
                        g_free (str);
 -                      mono_set_private_bin_path_from_config (domain);
 +                      mono_domain_set_options_from_config (domain);
                }
        }
  
 -      cinfo = mono_custom_attrs_from_method (method);
 +      MonoError cattr_error;
 +      cinfo = mono_custom_attrs_from_method_checked (method, &cattr_error);
 +      mono_error_cleanup (&cattr_error); /* FIXME warn here? */
        if (cinfo) {
 -              static MonoClass *stathread_attribute = NULL;
 -              if (!stathread_attribute)
 -                      stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
 -              has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
 +              has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
                if (!cinfo->cached)
                        mono_custom_attrs_free (cinfo);
        } else {
        }
        mono_thread_init_apartment_state ();
  
 +}
 +
 +static int
 +do_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
 +{
 +      MONO_REQ_GC_UNSAFE_MODE;
 +
 +      gpointer pa [1];
 +      int rval;
 +
 +      mono_error_init (error);
 +      g_assert (args);
 +
 +      pa [0] = args;
 +
 +      /* FIXME: check signature of method */
 +      if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
 +              MonoObject *res;
 +              res = mono_runtime_invoke_checked (method, NULL, pa, error);
 +              if (is_ok (error))
 +                      rval = *(guint32 *)((char *)res + sizeof (MonoObject));
 +              else
 +                      rval = -1;
 +              mono_environment_exitcode_set (rval);
 +      } else {
 +              mono_runtime_invoke_checked (method, NULL, pa, error);
 +
 +              if (is_ok (error))
 +                      rval = 0;
 +              else {
 +                      rval = -1;
 +              }
 +      }
 +      return rval;
 +}
 +
 +static int
 +do_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
 +{
 +      MONO_REQ_GC_UNSAFE_MODE;
 +
 +      gpointer pa [1];
 +      int rval;
 +
 +      g_assert (args);
 +      g_assert (exc);
 +
 +      pa [0] = args;
 +
        /* FIXME: check signature of method */
        if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
 +              MonoError inner_error;
                MonoObject *res;
 -              res = mono_runtime_invoke (method, NULL, pa, exc);
 -              if (!exc || !*exc)
 +              res = mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
 +              if (*exc == NULL && !mono_error_ok (&inner_error))
 +                      *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
 +              else
 +                      mono_error_cleanup (&inner_error);
 +
 +              if (*exc == NULL)
                        rval = *(guint32 *)((char *)res + sizeof (MonoObject));
                else
                        rval = -1;
  
                mono_environment_exitcode_set (rval);
        } else {
 -              mono_runtime_invoke (method, NULL, pa, exc);
 -              if (!exc || !*exc)
 +              MonoError inner_error;
 +              mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
 +              if (*exc == NULL && !mono_error_ok (&inner_error))
 +                      *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
 +              else
 +                      mono_error_cleanup (&inner_error);
 +
 +              if (*exc == NULL)
                        rval = 0;
                else {
                        /* If the return type of Main is void, only
        return rval;
  }
  
 -/**
 - * mono_install_runtime_invoke:
 - * @func: Function to install
 - *
 - * This is a VM internal routine
 +/*
 + * Execute a standard Main() method (args doesn't contain the
 + * executable name).
   */
 -void
 -mono_install_runtime_invoke (MonoInvokeFunc func)
 +int
 +mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
  {
 -      default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
 +      MonoError error;
 +      prepare_thread_to_exec_main (mono_object_domain (args), method);
 +      if (exc) {
 +              int rval = do_try_exec_main (method, args, exc);
 +              return rval;
 +      } else {
 +              int rval = do_exec_main_checked (method, args, &error);
 +              mono_error_raise_exception (&error); /* OK to throw, external only with no better option */
 +              return rval;
 +      }
  }
  
 -
 -/**
 - * mono_runtime_invoke_array:
 - * @method: method to invoke
 - * @obJ: object instance
 - * @params: arguments to the method
 - * @exc: exception information.
 - *
 - * Invokes the method represented by @method on the object @obj.
 - *
 - * obj is the 'this' pointer, it should be NULL for static
 - * methods, a MonoObject* for object instances and a pointer to
 - * the value type for value types.
 +/*
 + * Execute a standard Main() method (args doesn't contain the
 + * executable name).
   *
 - * The params array contains the arguments to the method with the
 - * same convention: MonoObject* pointers for object instances and
 - * pointers to the value type otherwise. The _invoke_array
 - * variant takes a C# object[] as the params argument (MonoArray
 - * *params): in this case the value types are boxed inside the
 - * respective reference representation.
 - * 
 - * From unmanaged code you'll usually use the
 - * mono_runtime_invoke() variant.
 + * On failure sets @error
 + */
 +int
 +mono_runtime_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
 +{
 +      mono_error_init (error);
 +      prepare_thread_to_exec_main (mono_object_domain (args), method);
 +      return do_exec_main_checked (method, args, error);
 +}
 +
 +/*
 + * Execute a standard Main() method (args doesn't contain the
 + * executable name).
   *
 - * Note that this function doesn't handle virtual methods for
 - * you, it will exec the exact method you pass: we still need to
 - * expose a function to lookup the derived class implementation
 - * of a virtual method (there are examples of this in the code,
 - * though).
 - * 
 - * You can pass NULL as the exc argument if you don't want to
 - * catch exceptions, otherwise, *exc will be set to the exception
 - * thrown, if any.  if an exception is thrown, you can't use the
 - * MonoObject* result from the function.
 - * 
 - * If the method returns a value type, it is boxed in an object
 - * reference.
 + * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
   */
 -MonoObject*
 -mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
 -                         MonoObject **exc)
 +int
 +mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
  {
 -      MONO_REQ_GC_UNSAFE_MODE;
 +      prepare_thread_to_exec_main (mono_object_domain (args), method);
 +      return do_try_exec_main (method, args, exc);
 +}
  
 -      MonoMethodSignature *sig = mono_method_signature (method);
 -      gpointer *pa = NULL;
 -      MonoObject *res;
 -      int i;
 -      gboolean has_byref_nullables = FALSE;
  
 -      if (NULL != params) {
 -              pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
 -              for (i = 0; i < mono_array_length (params); i++) {
 -                      MonoType *t = sig->params [i];
  
 +/** invoke_array_extract_argument:
 + * @params: array of arguments to the method.
 + * @i: the index of the argument to extract.
 + * @t: ith type from the method signature.
 + * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
 + * @error: set on error.
 + *
 + * Given an array of method arguments, return the ith one using the corresponding type
 + * to perform necessary unboxing.  If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
 + *
 + * On failure sets @error and returns NULL.
 + */
 +static gpointer
 +invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
 +{
 +      MonoType *t_orig = t;
 +      gpointer result = NULL;
 +      mono_error_init (error);
                again:
                        switch (t->type) {
                        case MONO_TYPE_U1:
                        case MONO_TYPE_R4:
                        case MONO_TYPE_R8:
                        case MONO_TYPE_VALUETYPE:
 -                              if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
 +                              if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
                                        /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
 -                                      pa [i] = mono_array_get (params, MonoObject*, i);
 +                                      result = mono_array_get (params, MonoObject*, i);
                                        if (t->byref)
 -                                              has_byref_nullables = TRUE;
 +                                              *has_byref_nullables = TRUE;
                                } else {
                                        /* MS seems to create the objects if a null is passed in */
 -                                      if (!mono_array_get (params, MonoObject*, i))
 -                                              mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i]))); 
 +                                      if (!mono_array_get (params, MonoObject*, i)) {
 +                                              MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
 +                                              return_val_if_nok (error, NULL);
 +                                              mono_array_setref (params, i, o); 
 +                                      }
  
                                        if (t->byref) {
                                                /*
                                                 * boxed object in the arg array with the copy.
                                                 */
                                                MonoObject *orig = mono_array_get (params, MonoObject*, i);
 -                                              MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
 +                                              MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
 +                                              return_val_if_nok (error, NULL);
                                                mono_array_setref (params, i, copy);
                                        }
                                                
 -                                      pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
 +                                      result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
                                }
                                break;
                        case MONO_TYPE_STRING:
                        case MONO_TYPE_ARRAY:
                        case MONO_TYPE_SZARRAY:
                                if (t->byref)
 -                                      pa [i] = mono_array_addr (params, MonoObject*, i);
 +                                      result = mono_array_addr (params, MonoObject*, i);
                                        // FIXME: I need to check this code path
                                else
 -                                      pa [i] = mono_array_get (params, MonoObject*, i);
 +                                      result = mono_array_get (params, MonoObject*, i);
                                break;
                        case MONO_TYPE_GENERICINST:
                                if (t->byref)
                                /* The argument should be an IntPtr */
                                arg = mono_array_get (params, MonoObject*, i);
                                if (arg == NULL) {
 -                                      pa [i] = NULL;
 +                                      result = NULL;
                                } else {
                                        g_assert (arg->vtable->klass == mono_defaults.int_class);
 -                                      pa [i] = ((MonoIntPtr*)arg)->m_value;
 +                                      result = ((MonoIntPtr*)arg)->m_value;
                                }
                                break;
                        }
                        default:
 -                              g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
 +                              g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
                        }
 +      return result;
 +}
 +/**
 + * mono_runtime_invoke_array:
 + * @method: method to invoke
 + * @obJ: object instance
 + * @params: arguments to the method
 + * @exc: exception information.
 + *
 + * Invokes the method represented by @method on the object @obj.
 + *
 + * obj is the 'this' pointer, it should be NULL for static
 + * methods, a MonoObject* for object instances and a pointer to
 + * the value type for value types.
 + *
 + * The params array contains the arguments to the method with the
 + * same convention: MonoObject* pointers for object instances and
 + * pointers to the value type otherwise. The _invoke_array
 + * variant takes a C# object[] as the params argument (MonoArray
 + * *params): in this case the value types are boxed inside the
 + * respective reference representation.
 + * 
 + * From unmanaged code you'll usually use the
 + * mono_runtime_invoke_checked() variant.
 + *
 + * Note that this function doesn't handle virtual methods for
 + * you, it will exec the exact method you pass: we still need to
 + * expose a function to lookup the derived class implementation
 + * of a virtual method (there are examples of this in the code,
 + * though).
 + * 
 + * You can pass NULL as the exc argument if you don't want to
 + * catch exceptions, otherwise, *exc will be set to the exception
 + * thrown, if any.  if an exception is thrown, you can't use the
 + * MonoObject* result from the function.
 + * 
 + * If the method returns a value type, it is boxed in an object
 + * reference.
 + */
 +MonoObject*
 +mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
 +                         MonoObject **exc)
 +{
 +      MonoError error;
 +      if (exc) {
 +              MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
 +              if (*exc) {
 +                      mono_error_cleanup (&error);
 +                      return NULL;
 +              } else {
 +                      if (!is_ok (&error))
 +                              *exc = (MonoObject*)mono_error_convert_to_exception (&error);
 +                      return result;
 +              }
 +      } else {
 +              MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
 +              mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
 +              return result;
 +      }
 +}
 +
 +/**
 + * mono_runtime_invoke_array_checked:
 + * @method: method to invoke
 + * @obJ: object instance
 + * @params: arguments to the method
 + * @error: set on failure.
 + *
 + * Invokes the method represented by @method on the object @obj.
 + *
 + * obj is the 'this' pointer, it should be NULL for static
 + * methods, a MonoObject* for object instances and a pointer to
 + * the value type for value types.
 + *
 + * The params array contains the arguments to the method with the
 + * same convention: MonoObject* pointers for object instances and
 + * pointers to the value type otherwise. The _invoke_array
 + * variant takes a C# object[] as the params argument (MonoArray
 + * *params): in this case the value types are boxed inside the
 + * respective reference representation.
 + *
 + * From unmanaged code you'll usually use the
 + * mono_runtime_invoke_checked() variant.
 + *
 + * Note that this function doesn't handle virtual methods for
 + * you, it will exec the exact method you pass: we still need to
 + * expose a function to lookup the derived class implementation
 + * of a virtual method (there are examples of this in the code,
 + * though).
 + *
 + * On failure or exception, @error will be set. In that case, you
 + * can't use the MonoObject* result from the function.
 + *
 + * If the method returns a value type, it is boxed in an object
 + * reference.
 + */
 +MonoObject*
 +mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
 +                                 MonoError *error)
 +{
 +      mono_error_init (error);
 +      return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
 +}
 +
 +/**
 + * mono_runtime_try_invoke_array:
 + * @method: method to invoke
 + * @obJ: object instance
 + * @params: arguments to the method
 + * @exc: exception information.
 + * @error: set on failure.
 + *
 + * Invokes the method represented by @method on the object @obj.
 + *
 + * obj is the 'this' pointer, it should be NULL for static
 + * methods, a MonoObject* for object instances and a pointer to
 + * the value type for value types.
 + *
 + * The params array contains the arguments to the method with the
 + * same convention: MonoObject* pointers for object instances and
 + * pointers to the value type otherwise. The _invoke_array
 + * variant takes a C# object[] as the params argument (MonoArray
 + * *params): in this case the value types are boxed inside the
 + * respective reference representation.
 + *
 + * From unmanaged code you'll usually use the
 + * mono_runtime_invoke_checked() variant.
 + *
 + * Note that this function doesn't handle virtual methods for
 + * you, it will exec the exact method you pass: we still need to
 + * expose a function to lookup the derived class implementation
 + * of a virtual method (there are examples of this in the code,
 + * though).
 + *
 + * You can pass NULL as the exc argument if you don't want to catch
 + * exceptions, otherwise, *exc will be set to the exception thrown, if
 + * any.  On other failures, @error will be set. If an exception is
 + * thrown or there's an error, you can't use the MonoObject* result
 + * from the function.
 + *
 + * If the method returns a value type, it is boxed in an object
 + * reference.
 + */
 +MonoObject*
 +mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
 +                             MonoObject **exc, MonoError *error)
 +{
 +      MONO_REQ_GC_UNSAFE_MODE;
 +
 +      mono_error_init (error);
 +
 +      MonoMethodSignature *sig = mono_method_signature (method);
 +      gpointer *pa = NULL;
 +      MonoObject *res;
 +      int i;
 +      gboolean has_byref_nullables = FALSE;
 +
 +      if (NULL != params) {
 +              pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
 +              for (i = 0; i < mono_array_length (params); i++) {
 +                      MonoType *t = sig->params [i];
 +                      pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
 +                      return_val_if_nok (error, NULL);
                }
        }
  
  
                        if (!params)
                                return NULL;
 -                      else
 -                              return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
 +                      else {
 +                              return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
 +                      }
                }
  
                if (!obj) {
 -                      obj = mono_object_new (mono_domain_get (), method->klass);
 +                      obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
 +                      mono_error_assert_ok (error);
                        g_assert (obj); /*maybe we should raise a TLE instead?*/
  #ifndef DISABLE_REMOTING
                        if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
                        else
                                o = obj;
                } else if (method->klass->valuetype) {
 -                      obj = mono_value_box (mono_domain_get (), method->klass, obj);
 +                      obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
 +                      return_val_if_nok (error, NULL);
 +              }
 +
 +              if (exc) {
 +                      mono_runtime_try_invoke (method, o, pa, exc, error);
 +              } else {
 +                      mono_runtime_invoke_checked (method, o, pa, error);
                }
  
 -              mono_runtime_invoke (method, o, pa, exc);
                return (MonoObject *)obj;
        } else {
                if (mono_class_is_nullable (method->klass)) {
                        MonoObject *nullable;
  
                        /* Convert the unboxed vtype into a Nullable structure */
 -                      nullable = mono_object_new (mono_domain_get (), method->klass);
 +                      nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
 +                      return_val_if_nok (error, NULL);
  
 -                      mono_nullable_init ((guint8 *)mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
 +                      MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
 +                      return_val_if_nok (error, NULL);
 +                      mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
                        obj = mono_object_unbox (nullable);
                }
  
                /* obj must be already unboxed if needed */
 -              res = mono_runtime_invoke (method, obj, pa, exc);
 +              if (exc) {
 +                      res = mono_runtime_try_invoke (method, obj, pa, exc, error);
 +              } else {
 +                      res = mono_runtime_invoke_checked (method, obj, pa, error);
 +              }
 +              return_val_if_nok (error, NULL);
  
                if (sig->ret->type == MONO_TYPE_PTR) {
                        MonoClass *pointer_class;
                         * The runtime-invoke wrapper returns a boxed IntPtr, need to 
                         * convert it to a Pointer object.
                         */
 -                      pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
 +                      pointer_class = mono_class_get_pointer_class ();
                        if (!box_method)
                                box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
  
                        g_assert (res->vtable->klass == mono_defaults.int_class);
                        box_args [0] = ((MonoIntPtr*)res)->m_value;
 -                      box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
 -                      res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
 -                      g_assert (!box_exc);
 +                      box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
 +                      return_val_if_nok (error, NULL);
 +
 +                      res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
 +                      g_assert (box_exc == NULL);
 +                      mono_error_assert_ok (error);
                }
  
                if (has_byref_nullables) {
        }
  }
  
 -static void
 -arith_overflow (void)
 +/**
 + * mono_object_new:
 + * @klass: the class of the object that we want to create
 + *
 + * Returns: a newly created object whose definition is
 + * looked up using @klass.   This will not invoke any constructors, 
 + * so the consumer of this routine has to invoke any constructors on
 + * its own to initialize the object.
 + * 
 + * It returns NULL on failure.
 + */
 +MonoObject *
 +mono_object_new (MonoDomain *domain, MonoClass *klass)
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
 -      mono_raise_exception (mono_get_exception_overflow ());
 +      MonoError error;
 +
 +      MonoObject * result = mono_object_new_checked (domain, klass, &error);
 +
 +      mono_error_cleanup (&error);
 +      return result;
 +}
 +
 +MonoObject *
 +ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
 +{
 +      MONO_REQ_GC_UNSAFE_MODE;
 +
 +      MonoError error;
 +
 +      MonoObject * result = mono_object_new_checked (domain, klass, &error);
 +
 +      mono_error_set_pending_exception (&error);
 +      return result;
  }
  
  /**
 - * mono_object_new:
 + * mono_object_new_checked:
   * @klass: the class of the object that we want to create
 + * @error: set on error
   *
   * Returns: a newly created object whose definition is
 - * looked up using @klass.   This will not invoke any constructors, 
 + * looked up using @klass.   This will not invoke any constructors,
   * so the consumer of this routine has to invoke any constructors on
   * its own to initialize the object.
 - * 
 - * It returns NULL on failure.
 + *
 + * It returns NULL on failure and sets @error.
   */
  MonoObject *
 -mono_object_new (MonoDomain *domain, MonoClass *klass)
 +mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
        MonoVTable *vtable;
  
        vtable = mono_class_vtable (domain, klass);
 -      if (!vtable)
 -              return NULL;
 -      return mono_object_new_specific (vtable);
 +      g_assert (vtable); /* FIXME don't swallow the error */
 +
 +      MonoObject *o = mono_object_new_specific_checked (vtable, error);
 +      return o;
  }
  
  /**
   * For SGEN, these objects will only be freed at appdomain unload.
   */
  MonoObject *
 -mono_object_new_pinned (MonoDomain *domain, MonoClass *klass)
 +mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
        MonoVTable *vtable;
  
 +      mono_error_init (error);
 +
        vtable = mono_class_vtable (domain, klass);
 -      if (!vtable)
 -              return NULL;
 +      g_assert (vtable); /* FIXME don't swallow the error */
  
 -#ifdef HAVE_SGEN_GC
 -      return (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
 -#else
 -      return mono_object_new_specific (vtable);
 -#endif
 +      MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
 +
 +      if (G_UNLIKELY (!o))
 +              mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
 +      else if (G_UNLIKELY (vtable->klass->has_finalize))
 +              mono_object_register_finalizer (o);
 +
 +      return o;
  }
  
  /**
   */
  MonoObject *
  mono_object_new_specific (MonoVTable *vtable)
 +{
 +      MonoError error;
 +      MonoObject *o = mono_object_new_specific_checked (vtable, &error);
 +      mono_error_cleanup (&error);
 +
 +      return o;
 +}
 +
 +MonoObject *
 +mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
        MonoObject *o;
  
 +      mono_error_init (error);
 +
        /* check for is_com_object for COM Interop */
        if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
        {
                MonoMethod *im = vtable->domain->create_proxy_for_type_method;
  
                if (im == NULL) {
 -                      MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
 +                      MonoClass *klass = mono_class_get_activation_services_class ();
  
                        if (!klass->inited)
                                mono_class_init (klass);
  
                        im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
 -                      if (!im)
 -                              mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
 +                      if (!im) {
 +                              mono_error_set_not_supported (error, "Linked away.");
 +                              return NULL;
 +                      }
                        vtable->domain->create_proxy_for_type_method = im;
                }
        
 -              pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
 +              pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
 +              if (!mono_error_ok (error))
 +                      return NULL;
  
 -              o = mono_runtime_invoke (im, NULL, pa, NULL);           
 -              if (o != NULL) return o;
 +              o = mono_runtime_invoke_checked (im, NULL, pa, error);
 +              if (!mono_error_ok (error))
 +                      return NULL;
 +
 +              if (o != NULL)
 +                      return o;
        }
  
 -      return mono_object_new_alloc_specific (vtable);
 +      return mono_object_new_alloc_specific_checked (vtable, error);
 +}
 +
 +MonoObject *
 +ves_icall_object_new_specific (MonoVTable *vtable)
 +{
 +      MonoError error;
 +      MonoObject *o = mono_object_new_specific_checked (vtable, &error);
 +      mono_error_set_pending_exception (&error);
 +
 +      return o;
  }
  
 +/**
 + * mono_object_new_alloc_specific:
 + * @vtable: virtual table for the object.
 + *
 + * This function allocates a new `MonoObject` with the type derived
 + * from the @vtable information.   If the class of this object has a 
 + * finalizer, then the object will be tracked for finalization.
 + *
 + * This method might raise an exception on errors.  Use the
 + * `mono_object_new_fast_checked` method if you want to manually raise
 + * the exception.
 + *
 + * Returns: the allocated object.   
 + */
  MonoObject *
  mono_object_new_alloc_specific (MonoVTable *vtable)
 +{
 +      MonoError error;
 +      MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
 +      mono_error_cleanup (&error);
 +
 +      return o;
 +}
 +
 +/**
 + * mono_object_new_alloc_specific_checked:
 + * @vtable: virtual table for the object.
 + * @error: holds the error return value.  
 + *
 + * This function allocates a new `MonoObject` with the type derived
 + * from the @vtable information. If the class of this object has a 
 + * finalizer, then the object will be tracked for finalization.
 + *
 + * If there is not enough memory, the @error parameter will be set
 + * and will contain a user-visible message with the amount of bytes
 + * that were requested.
 + *
 + * Returns: the allocated object, or NULL if there is not enough memory
 + *
 + */
 +MonoObject *
 +mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
 -      MonoObject *o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
 +      MonoObject *o;
 +
 +      mono_error_init (error);
 +
 +      o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
  
 -      if (G_UNLIKELY (vtable->klass->has_finalize))
 +      if (G_UNLIKELY (!o))
 +              mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
 +      else if (G_UNLIKELY (vtable->klass->has_finalize))
                mono_object_register_finalizer (o);
  
        return o;
  }
  
 +/**
 + * mono_object_new_fast:
 + * @vtable: virtual table for the object.
 + *
 + * This function allocates a new `MonoObject` with the type derived
 + * from the @vtable information.   The returned object is not tracked
 + * for finalization.   If your object implements a finalizer, you should
 + * use `mono_object_new_alloc_specific` instead.
 + *
 + * This method might raise an exception on errors.  Use the
 + * `mono_object_new_fast_checked` method if you want to manually raise
 + * the exception.
 + *
 + * Returns: the allocated object.   
 + */
  MonoObject*
  mono_object_new_fast (MonoVTable *vtable)
 +{
 +      MonoError error;
 +      MonoObject *o = mono_object_new_fast_checked (vtable, &error);
 +      mono_error_cleanup (&error);
 +
 +      return o;
 +}
 +
 +/**
 + * mono_object_new_fast_checked:
 + * @vtable: virtual table for the object.
 + * @error: holds the error return value.
 + *
 + * This function allocates a new `MonoObject` with the type derived
 + * from the @vtable information. The returned object is not tracked
 + * for finalization.   If your object implements a finalizer, you should
 + * use `mono_object_new_alloc_specific_checked` instead.
 + *
 + * If there is not enough memory, the @error parameter will be set
 + * and will contain a user-visible message with the amount of bytes
 + * that were requested.
 + *
 + * Returns: the allocated object, or NULL if there is not enough memory
 + *
 + */
 +MonoObject*
 +mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
 +{
 +      MONO_REQ_GC_UNSAFE_MODE;
 +
 +      MonoObject *o;
 +
 +      mono_error_init (error);
 +
 +      o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
 +
 +      if (G_UNLIKELY (!o))
 +              mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
 +
 +      return o;
 +}
 +
 +MonoObject *
 +ves_icall_object_new_fast (MonoVTable *vtable)
 +{
 +      MonoError error;
 +      MonoObject *o = mono_object_new_fast_checked (vtable, &error);
 +      mono_error_set_pending_exception (&error);
 +
 +      return o;
 +}
 +
 +MonoObject*
 +mono_object_new_mature (MonoVTable *vtable, MonoError *error)
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
 -      return (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
 +      MonoObject *o;
 +
 +      mono_error_init (error);
 +
 +      o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
 +
 +      if (G_UNLIKELY (!o))
 +              mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
 +      else if (G_UNLIKELY (vtable->klass->has_finalize))
 +              mono_object_register_finalizer (o);
 +
 +      return o;
  }
  
  /**
@@@ -5457,15 -4606,15 +5458,15 @@@ mono_class_get_allocation_ftn (MonoVTab
  
        *pass_size_in_words = FALSE;
  
 -      if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
 -              return mono_object_new_specific;
 +      if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass))
 +              return ves_icall_object_new_specific;
  
        if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
  
 -              return mono_object_new_fast;
 +              return ves_icall_object_new_fast;
  
                /* 
 -               * FIXME: This is actually slower than mono_object_new_fast, because
 +               * FIXME: This is actually slower than ves_icall_object_new_fast, because
                 * of the overhead of parameter passing.
                 */
                /*
                */
        }
  
 -      return mono_object_new_specific;
 +      return ves_icall_object_new_specific;
  }
  
  /**
@@@ -5495,17 -4644,12 +5496,17 @@@ mono_object_new_from_token  (MonoDomai
        MONO_REQ_GC_UNSAFE_MODE;
  
        MonoError error;
 +      MonoObject *result;
        MonoClass *klass;
  
        klass = mono_class_get_checked (image, token, &error);
 -      g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
 +      mono_error_assert_ok (&error);
 +      
 +      result = mono_object_new_checked (domain, klass, &error);
  
 -      return mono_object_new (domain, klass);
 +      mono_error_cleanup (&error);
 +      return result;
 +      
  }
  
  
   */
  MonoObject *
  mono_object_clone (MonoObject *obj)
 +{
 +      MonoError error;
 +      MonoObject *o = mono_object_clone_checked (obj, &error);
 +      mono_error_cleanup (&error);
 +
 +      return o;
 +}
 +
 +MonoObject *
 +mono_object_clone_checked (MonoObject *obj, MonoError *error)
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
        MonoObject *o;
 -      int size = obj->vtable->klass->instance_size;
 +      int size;
 +
 +      mono_error_init (error);
 +
 +      size = obj->vtable->klass->instance_size;
  
        if (obj->vtable->klass->rank)
 -              return (MonoObject*)mono_array_clone ((MonoArray*)obj);
 +              return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
  
        o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
  
 +      if (G_UNLIKELY (!o)) {
 +              mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
 +              return NULL;
 +      }
 +
        /* If the object doesn't contain references this will do a simple memmove. */
        mono_gc_wbarrier_object_copy (o, obj);
  
@@@ -5593,13 -4718,12 +5594,13 @@@ mono_array_full_copy (MonoArray *src, M
   * mono_array_clone_in_domain:
   * @domain: the domain in which the array will be cloned into
   * @array: the array to clone
 + * @error: set on error
   *
   * This routine returns a copy of the array that is hosted on the
 - * specified MonoDomain.
 + * specified MonoDomain.  On failure returns NULL and sets @error.
   */
  MonoArray*
 -mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
 +mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array, MonoError *error)
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
        uintptr_t *sizes;
        MonoClass *klass = array->obj.vtable->klass;
  
 +      mono_error_init (error);
 +
        if (array->bounds == NULL) {
                size = mono_array_length (array);
 -              o = mono_array_new_full (domain, klass, &size, NULL);
 +              o = mono_array_new_full_checked (domain, klass, &size, NULL, error);
 +              return_val_if_nok (error, NULL);
  
                size *= mono_array_element_size (klass);
  #ifdef HAVE_SGEN_GC
                size *= array->bounds [i].length;
                sizes [i + klass->rank] = array->bounds [i].lower_bound;
        }
 -      o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
 +      o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, error);
 +      return_val_if_nok (error, NULL);
  #ifdef HAVE_SGEN_GC
        if (klass->element_class->valuetype) {
                if (klass->element_class->has_references)
@@@ -5667,26 -4787,7 +5668,26 @@@ mono_array_clone (MonoArray *array
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
 -      return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
 +      MonoError error;
 +      MonoArray *result = mono_array_clone_checked (array, &error);
 +      mono_error_cleanup (&error);
 +      return result;
 +}
 +
 +/**
 + * mono_array_clone_checked:
 + * @array: the array to clone
 + * @error: set on error
 + *
 + * Returns: A newly created array who is a shallow copy of @array.  On
 + * failure returns NULL and sets @error.
 + */
 +MonoArray*
 +mono_array_clone_checked (MonoArray *array, MonoError *error)
 +{
 +
 +      MONO_REQ_GC_UNSAFE_MODE;
 +      return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array, error);
  }
  
  /* helper macros to check for overflow when calculating the size of arrays */
@@@ -5740,16 -4841,6 +5741,16 @@@ mono_array_calc_byte_len (MonoClass *kl
   */
  MonoArray*
  mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
 +{
 +      MonoError error;
 +      MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
 +      mono_error_cleanup (&error);
 +
 +      return array;
 +}
 +
 +MonoArray*
 +mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
        MonoVTable *vtable;
        int i;
  
 +      mono_error_init (error);
 +
        if (!array_class->inited)
                mono_class_init (array_class);
  
        /* A single dimensional array with a 0 lower bound is the same as an szarray */
        if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
                len = lengths [0];
 -              if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
 -                      arith_overflow ();
 +              if (len > MONO_ARRAY_MAX_INDEX) {
 +                      mono_error_set_generic_error (error, "System", "OverflowException", "");
 +                      return NULL;
 +              }
                bounds_size = 0;
        } else {
                bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
  
                for (i = 0; i < array_class->rank; ++i) {
 -                      if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
 -                              arith_overflow ();
 -                      if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
 -                              mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
 +                      if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
 +                              mono_error_set_generic_error (error, "System", "OverflowException", "");
 +                              return NULL;
 +                      }
 +                      if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
 +                              mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
 +                              return NULL;
 +                      }
                        len *= lengths [i];
                }
        }
  
 -      if (!mono_array_calc_byte_len (array_class, len, &byte_len))
 -              mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
 +      if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
 +              mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
 +              return NULL;
 +      }
  
        if (bounds_size) {
                /* align */
 -              if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
 -                      mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
 +              if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
 +                      mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
 +                      return NULL;
 +              }
                byte_len = (byte_len + 3) & ~3;
 -              if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
 -                      mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
 +              if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
 +                      mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
 +                      return NULL;
 +              }
                byte_len += bounds_size;
        }
        /* 
         * Following three lines almost taken from mono_object_new ():
         * they need to be kept in sync.
         */
 -      vtable = mono_class_vtable_full (domain, array_class, TRUE);
 +      vtable = mono_class_vtable_full (domain, array_class, error);
 +      return_val_if_nok (error, NULL);
 +
        if (bounds_size)
                o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
        else
                o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
 +
 +      if (G_UNLIKELY (!o)) {
 +              mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
 +              return NULL;
 +      }
 +
        array = (MonoArray*)o;
  
        bounds = array->bounds;
@@@ -5854,46 -4923,12 +5855,46 @@@ mono_array_new (MonoDomain *domain, Mon
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
 +      MonoError error;
 +      MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
 +      mono_error_cleanup (&error);
 +      return result;
 +}
 +
 +/**
 + * mono_array_new_checked:
 + * @domain: domain where the object is created
 + * @eclass: element class
 + * @n: number of array elements
 + * @error: set on error
 + *
 + * This routine creates a new szarray with @n elements of type @eclass.
 + * On failure returns NULL and sets @error.
 + */
 +MonoArray *
 +mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
 +{
        MonoClass *ac;
  
 +      mono_error_init (error);
 +
        ac = mono_array_class_get (eclass, 1);
        g_assert (ac);
  
 -      return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
 +      MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
 +      return_val_if_nok (error, NULL);
 +
 +      return mono_array_new_specific_checked (vtable, n, error);
 +}
 +
 +MonoArray*
 +ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
 +{
 +      MonoError error;
 +      MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
 +      mono_error_set_pending_exception (&error);
 +
 +      return arr;
  }
  
  /**
   */
  MonoArray *
  mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
 +{
 +      MonoError error;
 +      MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
 +      mono_error_cleanup (&error);
 +
 +      return arr;
 +}
 +
 +MonoArray*
 +mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
        MonoObject *o;
 -      MonoArray *ao;
        uintptr_t byte_len;
  
 +      mono_error_init (error);
 +
        if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
 -              arith_overflow ();
 +              mono_error_set_generic_error (error, "System", "OverflowException", "");
                return NULL;
        }
  
        if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
 -              mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
 +              mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
                return NULL;
        }
        o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
 -      ao = (MonoArray*)o;
  
 -      return ao;
 +      if (G_UNLIKELY (!o)) {
 +              mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
 +              return NULL;
 +      }
 +
 +      return (MonoArray*)o;
 +}
 +
 +MonoArray*
 +ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
 +{
 +      MonoError error;
 +      MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
 +      mono_error_set_pending_exception (&error);
 +
 +      return arr;
  }
  
  /**
@@@ -5965,35 -4975,12 +5966,35 @@@ mono_string_new_utf16 (MonoDomain *doma
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
 +      MonoError error;
 +      MonoString *res = NULL;
 +      res = mono_string_new_utf16_checked (domain, text, len, &error);
 +      mono_error_cleanup (&error);
 +
 +      return res;
 +}
 +
 +/**
 + * mono_string_new_utf16_checked:
 + * @text: a pointer to an utf16 string
 + * @len: the length of the string
 + * @error: written on error.
 + *
 + * Returns: A newly created string object which contains @text.
 + * On error, returns NULL and sets @error.
 + */
 +MonoString *
 +mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
 +{
 +      MONO_REQ_GC_UNSAFE_MODE;
 +
        MonoString *s;
        
 -      s = mono_string_new_size (domain, len);
 -      g_assert (s != NULL);
 -
 -      memcpy (mono_string_chars (s), text, len * 2);
 +      mono_error_init (error);
 +      
 +      s = mono_string_new_size_checked (domain, len, error);
 +      if (s != NULL)
 +              memcpy (mono_string_chars (s), text, len * 2);
  
        return s;
  }
   * mono_string_new_utf32:
   * @text: a pointer to an utf32 string
   * @len: the length of the string
 + * @error: set on failure.
   *
 - * Returns: A newly created string object which contains @text.
 + * Returns: A newly created string object which contains @text. On failure returns NULL and sets @error.
   */
 -MonoString *
 -mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
 +static MonoString *
 +mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
        MonoString *s;
        mono_unichar2 *utf16_output = NULL;
        gint32 utf16_len = 0;
 -      GError *error = NULL;
 +      GError *gerror = NULL;
        glong items_written;
        
 -      utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &error);
 +      mono_error_init (error);
 +      utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
        
 -      if (error)
 -              g_error_free (error);
 +      if (gerror)
 +              g_error_free (gerror);
  
        while (utf16_output [utf16_len]) utf16_len++;
        
 -      s = mono_string_new_size (domain, utf16_len);
 -      g_assert (s != NULL);
 +      s = mono_string_new_size_checked (domain, utf16_len, error);
 +      return_val_if_nok (error, NULL);
  
        memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
  
        return s;
  }
  
 +/**
 + * mono_string_new_utf32:
 + * @text: a pointer to an utf32 string
 + * @len: the length of the string
 + *
 + * Returns: A newly created string object which contains @text.
 + */
 +MonoString *
 +mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
 +{
 +      MonoError error;
 +      MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
 +      mono_error_cleanup (&error);
 +      return result;
 +}
 +
  /**
   * mono_string_new_size:
   * @text: a pointer to an utf16 string
   * Returns: A newly created string object of @len
   */
  MonoString *
 -mono_string_new_size (MonoDomain *domain, gint32 len)
 +mono_string_new_size (MonoDomain *domain, gint32 len)
 +{
 +      MonoError error;
 +      MonoString *str = mono_string_new_size_checked (domain, len, &error);
 +      mono_error_cleanup (&error);
 +
 +      return str;
 +}
 +
 +MonoString *
 +mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
        MonoVTable *vtable;
        size_t size;
  
 +      mono_error_init (error);
 +
        /* check for overflow */
 -      if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2))
 -              mono_gc_out_of_memory (-1);
 +      if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
 +              mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
 +              return NULL;
 +      }
  
        size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
        g_assert (size > 0);
  
        s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
  
 +      if (G_UNLIKELY (!s)) {
 +              mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", size);
 +              return NULL;
 +      }
 +
        return s;
  }
  
@@@ -6113,39 -5063,17 +6114,39 @@@ mono_string_new_len (MonoDomain *domain
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
 -      GError *error = NULL;
 +      MonoError error;
 +      MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
 +      mono_error_cleanup (&error);
 +      return result;
 +}
 +
 +/**
 + * mono_string_new_len_checked:
 + * @text: a pointer to an utf8 string
 + * @length: number of bytes in @text to consider
 + * @error: set on error
 + *
 + * Returns: A newly created string object which contains @text. On
 + * failure returns NULL and sets @error.
 + */
 +MonoString*
 +mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
 +{
 +      MONO_REQ_GC_UNSAFE_MODE;
 +
 +      mono_error_init (error);
 +
 +      GError *eg_error = NULL;
        MonoString *o = NULL;
 -      guint16 *ut;
 +      guint16 *ut = NULL;
        glong items_written;
  
 -      ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &error);
 +      ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
  
 -      if (!error)
 -              o = mono_string_new_utf16 (domain, ut, items_written);
 +      if (!eg_error)
 +              o = mono_string_new_utf16_checked (domain, ut, items_written, error);
        else 
 -              g_error_free (error);
 +              g_error_free (eg_error);
  
        g_free (ut);
  
   * @text: a pointer to an utf8 string
   *
   * Returns: A newly created string object which contains @text.
 + *
 + * This function asserts if it cannot allocate a new string.
 + *
 + * @deprecated Use mono_string_new_checked in new code.
   */
  MonoString*
  mono_string_new (MonoDomain *domain, const char *text)
 +{
 +      MonoError error;
 +      MonoString *res = NULL;
 +      res = mono_string_new_checked (domain, text, &error);
 +      mono_error_assert_ok (&error);
 +      return res;
 +}
 +
 +/**
 + * mono_string_new_checked:
 + * @text: a pointer to an utf8 string
 + * @merror: set on error
 + *
 + * Returns: A newly created string object which contains @text.
 + * On error returns NULL and sets @merror.
 + */
 +MonoString*
 +mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
 -    GError *error = NULL;
 +    GError *eg_error = NULL;
      MonoString *o = NULL;
      guint16 *ut;
      glong items_written;
      int l;
  
 +    mono_error_init (error);
 +
      l = strlen (text);
     
 -    ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
 +    ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
  
 -    if (!error)
 -        o = mono_string_new_utf16 (domain, ut, items_written);
 +    if (!eg_error)
 +          o = mono_string_new_utf16_checked (domain, ut, items_written, error);
      else
 -        g_error_free (error);
 +        g_error_free (eg_error);
  
      g_free (ut);
 +    
  /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
  #if 0
        gunichar2 *str;
        int len;
        MonoString *o = NULL;
  
 -      if (!g_utf8_validate (text, -1, &end))
 -              return NULL;
 +      if (!g_utf8_validate (text, -1, &end)) {
 +              mono_error_set_argument (error, "text", "Not a valid utf8 string");
 +              goto leave;
 +      }
  
        len = g_utf8_strlen (text, -1);
 -      o = mono_string_new_size (domain, len);
 +      o = mono_string_new_size_checked (domain, len, error);
 +      if (!o)
 +              goto leave;
        str = mono_string_chars (o);
  
        while (text < end) {
                *str++ = g_utf8_get_char (text);
                text = g_utf8_next_char (text);
        }
 +
 +leave:
  #endif
        return o;
  }
@@@ -6261,42 -5158,21 +6262,42 @@@ mono_string_new_wrapper (const char *te
  MonoObject *
  mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
  {
 -      MONO_REQ_GC_UNSAFE_MODE;
 +      MonoError error;
 +      MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
 +      mono_error_cleanup (&error);
 +      return result;
 +}
  
 +/**
 + * mono_value_box_checked:
 + * @domain: the domain of the new object
 + * @class: the class of the value
 + * @value: a pointer to the unboxed data
 + * @error: set on error
 + *
 + * Returns: A newly created object which contains @value. On failure
 + * returns NULL and sets @error.
 + */
 +MonoObject *
 +mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
 +{
 +      MONO_REQ_GC_UNSAFE_MODE;
        MonoObject *res;
        int size;
        MonoVTable *vtable;
  
 +      mono_error_init (error);
 +
        g_assert (klass->valuetype);
        if (mono_class_is_nullable (klass))
 -              return mono_nullable_box ((guint8 *)value, klass);
 +              return mono_nullable_box ((guint8 *)value, klass, error);
  
        vtable = mono_class_vtable (domain, klass);
        if (!vtable)
                return NULL;
        size = mono_class_instance_size (klass);
 -      res = mono_object_new_alloc_specific (vtable);
 +      res = mono_object_new_alloc_specific_checked (vtable, error);
 +      return_val_if_nok (error, NULL);
  
        size = size - sizeof (MonoObject);
  
        }
  #endif
  #endif
 -      if (klass->has_finalize)
 +      if (klass->has_finalize) {
                mono_object_register_finalizer (res);
 +              return_val_if_nok (error, NULL);
 +      }
        return res;
  }
  
 -/*
 +/**
   * mono_value_copy:
   * @dest: destination pointer
   * @src: source pointer
@@@ -6349,7 -5223,7 +6350,7 @@@ mono_value_copy (gpointer dest, gpointe
        mono_gc_wbarrier_value_copy (dest, src, 1, klass);
  }
  
 -/*
 +/**
   * mono_value_copy_array:
   * @dest: destination array
   * @dest_idx: index in the @dest array
@@@ -6388,10 -5262,8 +6389,10 @@@ mono_object_get_domain (MonoObject *obj
  /**
   * mono_object_get_class:
   * @obj: object to query
 - * 
 - * Returns: the MonOClass of the object.
 + *
 + * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
 + *
 + * Returns: the MonoClass of the object.
   */
  MonoClass*
  mono_object_get_class (MonoObject *obj)
@@@ -6452,45 -5324,18 +6453,45 @@@ mono_object_unbox (MonoObject *obj
   * @obj: an object
   * @klass: a pointer to a class 
   *
 - * Returns: @obj if @obj is derived from @klass
 + * Returns: @obj if @obj is derived from @klass or NULL otherwise.
   */
  MonoObject *
  mono_object_isinst (MonoObject *obj, MonoClass *klass)
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
 +      MonoError error;
 +      MonoObject *result = mono_object_isinst_checked (obj, klass, &error);
 +      mono_error_cleanup (&error);
 +      return result;
 +}
 +      
 +
 +/**
 + * mono_object_isinst_checked:
 + * @obj: an object
 + * @klass: a pointer to a class 
 + * @error: set on error
 + *
 + * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
 + * On failure returns NULL and sets @error.
 + */
 +MonoObject *
 +mono_object_isinst_checked (MonoObject *obj, MonoClass *klass, MonoError *error)
 +{
 +      MONO_REQ_GC_UNSAFE_MODE;
 +
 +      mono_error_init (error);
 +      
 +      MonoObject *result = NULL;
 +
        if (!klass->inited)
                mono_class_init (klass);
  
 -      if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
 -              return mono_object_isinst_mbyref (obj, klass);
 +      if (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass)) {
 +              result = mono_object_isinst_mbyref_checked (obj, klass, error);
 +              return result;
 +      }
  
        if (!obj)
                return NULL;
@@@ -6503,27 -5348,14 +6504,27 @@@ mono_object_isinst_mbyref (MonoObject *
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
 +      MonoError error;
 +      MonoObject *result = mono_object_isinst_mbyref_checked (obj, klass, &error);
 +      mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
 +      return result;
 +}
 +
 +MonoObject *
 +mono_object_isinst_mbyref_checked (MonoObject *obj, MonoClass *klass, MonoError *error)
 +{
 +      MONO_REQ_GC_UNSAFE_MODE;
 +
        MonoVTable *vt;
  
 +      mono_error_init (error);
 +
        if (!obj)
                return NULL;
  
        vt = obj->vtable;
        
 -      if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
 +      if (mono_class_is_interface (klass)) {
                if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
                        return obj;
                }
                gpointer pa [2];
  
                im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
 -              if (!im)
 -                      mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
 +              if (!im) {
 +                      mono_error_set_not_supported (error, "Linked away.");
 +                      return NULL;
 +              }
                im = mono_object_get_virtual_method (rp, im);
                g_assert (im);
        
 -              pa [0] = mono_type_get_object (domain, &klass->byval_arg);
 +              pa [0] = mono_type_get_object_checked (domain, &klass->byval_arg, error);
 +              return_val_if_nok (error, NULL);
                pa [1] = obj;
  
 -              res = mono_runtime_invoke (im, rp, pa, NULL);
 -      
 +              res = mono_runtime_invoke_checked (im, rp, pa, error);
 +              return_val_if_nok (error, NULL);
 +
                if (*(MonoBoolean *) mono_object_unbox(res)) {
                        /* Update the vtable of the remote type, so it can safely cast to this new type */
 -                      mono_upgrade_remote_class (domain, obj, klass);
 +                      mono_upgrade_remote_class (domain, obj, klass, error);
 +                      return_val_if_nok (error, NULL);
                        return obj;
                }
        }
   * @obj: an object
   * @klass: a pointer to a class 
   *
 - * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
 + * Returns: @obj if @obj is derived from @klass, returns NULL otherwise.
   */
  MonoObject *
  mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
  {
        MONO_REQ_GC_UNSAFE_MODE;
 +      MonoError error;
  
        if (!obj) return NULL;
 -      if (mono_object_isinst_mbyref (obj, klass)) return obj;
 -              
 -      mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
 -                                                      "System",
 -                                                      "InvalidCastException"));
 +      if (mono_object_isinst_mbyref_checked (obj, klass, &error)) return obj;
 +      mono_error_cleanup (&error);
        return NULL;
  }
  
@@@ -6612,16 -5441,13 +6613,16 @@@ str_lookup (MonoDomain *domain, gpointe
        info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
  }
  
 -#ifdef HAVE_SGEN_GC
 -
  static MonoString*
 -mono_string_get_pinned (MonoString *str)
 +mono_string_get_pinned (MonoString *str, MonoError *error)
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
 +      mono_error_init (error);
 +
 +      /* We only need to make a pinned version of a string if this is a moving GC */
 +      if (!mono_gc_is_moving ())
 +              return str;
        int size;
        MonoString *news;
        size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
        if (news) {
                memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
                news->length = mono_string_length (str);
 +      } else {
 +              mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
        }
        return news;
  }
  
 -#else
 -#define mono_string_get_pinned(str) (str)
 -#endif
 -
  static MonoString*
 -mono_string_is_interned_lookup (MonoString *str, int insert)
 +mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
        MonoString *s, *res;
        MonoDomain *domain;
        
 +      mono_error_init (error);
 +
        domain = ((MonoObject *)str)->vtable->domain;
        ldstr_table = domain->ldstr_table;
        ldstr_lock ();
        if (insert) {
                /* Allocate outside the lock */
                ldstr_unlock ();
 -              s = mono_string_get_pinned (str);
 +              s = mono_string_get_pinned (str, error);
 +              return_val_if_nok (error, NULL);
                if (s) {
                        ldstr_lock ();
                        res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
  MonoString*
  mono_string_is_interned (MonoString *o)
  {
 -      MONO_REQ_GC_UNSAFE_MODE;
 -
 -      return mono_string_is_interned_lookup (o, FALSE);
 +      MonoError error;
 +      MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
 +      /* This function does not fail. */
 +      mono_error_assert_ok (&error);
 +      return result;
  }
  
  /**
   */
  MonoString*
  mono_string_intern (MonoString *str)
 +{
 +      MonoError error;
 +      MonoString *result = mono_string_intern_checked (str, &error);
 +      mono_error_assert_ok (&error);
 +      return result;
 +}
 +
 +/**
 + * mono_string_intern_checked:
 + * @o: String to intern
 + * @error: set on error.
 + *
 + * Interns the string passed.
 + * Returns: The interned string.  On failure returns NULL and sets @error
 + */
 +MonoString*
 +mono_string_intern_checked (MonoString *str, MonoError *error)
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
 -      return mono_string_is_interned_lookup (str, TRUE);
 +      mono_error_init (error);
 +
 +      return mono_string_is_interned_lookup (str, TRUE, error);
  }
  
  /**
   */
  MonoString*
  mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
 +{
 +      MonoError error;
 +      MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
 +      mono_error_cleanup (&error);
 +      return result;
 +}
 +
 +/**
 + * mono_ldstr_checked:
 + * @domain: the domain where the string will be used.
 + * @image: a metadata context
 + * @idx: index into the user string table.
 + * @error: set on error.
 + * 
 + * Implementation for the ldstr opcode.
 + * Returns: a loaded string from the @image/@idx combination.
 + * On failure returns NULL and sets @error.
 + */
 +MonoString*
 +mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
  {
        MONO_REQ_GC_UNSAFE_MODE;
 +      mono_error_init (error);
  
        if (image->dynamic) {
 -              MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
 +              MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
                return str;
        } else {
                if (!mono_verifier_verify_string_signature (image, idx, NULL))
                        return NULL; /*FIXME we should probably be raising an exception here*/
 -              return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
 +              MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
 +              return str;
        }
  }
  
   * mono_ldstr_metadata_sig
   * @domain: the domain for the string
   * @sig: the signature of a metadata string
 + * @error: set on error
   *
 - * Returns: a MonoString for a string stored in the metadata
 + * Returns: a MonoString for a string stored in the metadata. On
 + * failure returns NULL and sets @error.
   */
  static MonoString*
 -mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
 +mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
 +      mono_error_init (error);
        const char *str = sig;
        MonoString *o, *interned;
        size_t len2;
        len2 = mono_metadata_decode_blob_size (str, &str);
        len2 >>= 1;
  
 -      o = mono_string_new_utf16 (domain, (guint16*)str, len2);
 +      o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
 +      return_val_if_nok (error, NULL);
  #if G_BYTE_ORDER != G_LITTLE_ENDIAN
        {
                int i;
        if (interned)
                return interned; /* o will get garbage collected */
  
 -      o = mono_string_get_pinned (o);
 +      o = mono_string_get_pinned (o, error);
        if (o) {
                ldstr_lock ();
                interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
        return interned;
  }
  
 +/*
 + * mono_ldstr_utf8:
 + *
 + *   Same as mono_ldstr, but return a NULL terminated utf8 string instead
 + * of an object.
 + */
 +char*
 +mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
 +{
 +      const char *str;
 +      size_t len2;
 +      long written = 0;
 +      char *as;
 +      GError *gerror = NULL;
 +
 +      mono_error_init (error);
 +
 +      if (!mono_verifier_verify_string_signature (image, idx, NULL))
 +              return NULL; /*FIXME we should probably be raising an exception here*/
 +      str = mono_metadata_user_string (image, idx);
 +
 +      len2 = mono_metadata_decode_blob_size (str, &str);
 +      len2 >>= 1;
 +
 +      as = g_utf16_to_utf8 ((guint16*)str, len2, NULL, &written, &gerror);
 +      if (gerror) {
 +              mono_error_set_argument (error, "string", "%s", gerror->message);
 +              g_error_free (gerror);
 +              return NULL;
 +      }
 +      /* g_utf16_to_utf8  may not be able to complete the convertion (e.g. NULL values were found, #335488) */
 +      if (len2 > written) {
 +              /* allocate the total length and copy the part of the string that has been converted */
 +              char *as2 = (char *)g_malloc0 (len2);
 +              memcpy (as2, as, written);
 +              g_free (as);
 +              as = as2;
 +      }
 +
 +      return as;
 +}
 +
  /**
   * mono_string_to_utf8:
   * @s: a System.String
@@@ -6900,10 -5636,8 +6901,10 @@@ mono_string_to_utf8 (MonoString *s
        MonoError error;
        char *result = mono_string_to_utf8_checked (s, &error);
        
 -      if (!mono_error_ok (&error))
 -              mono_error_raise_exception (&error);
 +      if (!is_ok (&error)) {
 +              mono_error_cleanup (&error);
 +              return NULL;
 +      }
        return result;
  }
  
@@@ -7086,28 -5820,8 +7087,28 @@@ mono_string_to_utf32 (MonoString *s
  MonoString *
  mono_string_from_utf16 (gunichar2 *data)
  {
 +      MonoError error;
 +      MonoString *result = mono_string_from_utf16_checked (data, &error);
 +      mono_error_cleanup (&error);
 +      return result;
 +}
 +
 +/**
 + * mono_string_from_utf16_checked:
 + * @data: the UTF16 string (LPWSTR) to convert
 + * @error: set on error
 + *
 + * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
 + *
 + * Returns: a MonoString. On failure sets @error and returns NULL.
 + */
 +MonoString *
 +mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
 +{
 +
        MONO_REQ_GC_UNSAFE_MODE;
  
 +      mono_error_init (error);
        MonoDomain *domain = mono_domain_get ();
        int len = 0;
  
  
        while (data [len]) len++;
  
 -      return mono_string_new_utf16 (domain, data, len);
 +      return mono_string_new_utf16_checked (domain, data, len, error);
  }
  
  /**
   */
  MonoString *
  mono_string_from_utf32 (mono_unichar4 *data)
 +{
 +      MonoError error;
 +      MonoString *result = mono_string_from_utf32_checked (data, &error);
 +      mono_error_cleanup (&error);
 +      return result;
 +}
 +
 +/**
 + * mono_string_from_utf32_checked:
 + * @data: the UTF32 string (LPWSTR) to convert
 + * @error: set on error
 + *
 + * Converts a UTF32 (UCS-4)to a MonoString.
 + *
 + * Returns: a MonoString. On failure returns NULL and sets @error.
 + */
 +MonoString *
 +mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
 +      mono_error_init (error);
        MonoString* result = NULL;
        mono_unichar2 *utf16_output = NULL;
 -      GError *error = NULL;
 +      GError *gerror = NULL;
        glong items_written;
        int len = 0;
  
  
        while (data [len]) len++;
  
 -      utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &error);
 +      utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
  
 -      if (error)
 -              g_error_free (error);
 +      if (gerror)
 +              g_error_free (gerror);
  
 -      result = mono_string_from_utf16 (utf16_output);
 +      result = mono_string_from_utf16_checked (utf16_output, error);
        g_free (utf16_output);
        return result;
  }
@@@ -7280,13 -5975,11 +7281,13 @@@ mono_raise_exception_with_context (Mono
   * mono_wait_handle_new:
   * @domain: Domain where the object will be created
   * @handle: Handle for the wait handle
 + * @error: set on error.
   *
 - * Returns: A new MonoWaitHandle created in the given domain for the given handle
 + * Returns: A new MonoWaitHandle created in the given domain for the
 + * given handle.  On failure returns NULL and sets @rror.
   */
  MonoWaitHandle *
 -mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
 +mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
        gpointer params [1];
        static MonoMethod *handle_set;
  
 -      res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
 +      mono_error_init (error);
 +      res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
 +      return_val_if_nok (error, NULL);
  
        /* Even though this method is virtual, it's safe to invoke directly, since the object type matches.  */
        if (!handle_set)
                handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
  
        params [0] = &handle;
 -      mono_runtime_invoke (handle_set, res, params, NULL);
  
 +      mono_runtime_invoke_checked (handle_set, res, params, error);
        return res;
  }
  
@@@ -7313,38 -6004,41 +7314,38 @@@ mono_wait_handle_get_handle (MonoWaitHa
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
 -      static MonoClassField *f_os_handle;
 -      static MonoClassField *f_safe_handle;
 +      static MonoClassField *f_safe_handle = NULL;
 +      MonoSafeHandle *sh;
  
 -      if (!f_os_handle && !f_safe_handle) {
 -              f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
 -              f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
 +      if (!f_safe_handle) {
 +              f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
 +              g_assert (f_safe_handle);
        }
  
 -      if (f_os_handle) {
 -              HANDLE retval;
 -              mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
 -              return retval;
 -      } else {
 -              MonoSafeHandle *sh;
 -              mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
 -              return sh->handle;
 -      }
 +      mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
 +      return sh->handle;
  }
  
  
  static MonoObject*
 -mono_runtime_capture_context (MonoDomain *domain)
 +mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
        RuntimeInvokeFunction runtime_invoke;
  
 +      mono_error_init (error);
 +
        if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
                MonoMethod *method = mono_get_context_capture_method ();
                MonoMethod *wrapper;
                if (!method)
                        return NULL;
 -              wrapper = mono_marshal_get_runtime_invoke (method, FALSE, FALSE);
 -              domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
 -              domain->capture_context_method = mono_compile_method (method);
 +              wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
 +              domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
 +              return_val_if_nok (error, NULL);
 +              domain->capture_context_method = mono_compile_method_checked (method, error);
 +              return_val_if_nok (error, NULL);
        }
  
        runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
   * @handle: wait handle.
   * @state: state to pass to AsyncResult
   * @data: C closure data.
 + * @error: set on error.
   *
   * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
   * If the handle is not null, the handle is initialized to a MonOWaitHandle.
 + * On failure returns NULL and sets @error.
   *
   */
  MonoAsyncResult *
 -mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
 +mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
 -      MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
 -      MonoObject *context = mono_runtime_capture_context (domain);
 +      mono_error_init (error);
 +      MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
 +      return_val_if_nok (error, NULL);
 +      MonoObject *context = mono_runtime_capture_context (domain, error);
 +      return_val_if_nok (error, NULL);
        /* we must capture the execution context from the original thread */
        if (context) {
                MONO_OBJECT_SETREF (res, execution_context, context);
        res->data = (void **)data;
        MONO_OBJECT_SETREF (res, object_data, object_data);
        MONO_OBJECT_SETREF (res, async_state, state);
 +      MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
 +      return_val_if_nok (error, NULL);
        if (handle != NULL)
 -              MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
 +              MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
  
        res->sync_completed = FALSE;
        res->completed = FALSE;
@@@ -7399,7 -6086,6 +7400,7 @@@ ves_icall_System_Runtime_Remoting_Messa
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
 +      MonoError error;
        MonoAsyncCall *ac;
        MonoObject *res;
  
  
        ac = (MonoAsyncCall*) ares->object_data;
        if (!ac) {
 -              res = mono_runtime_delegate_invoke (ares->async_delegate, (void**) &ares->async_state, NULL);
 +              res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
 +              if (mono_error_set_pending_exception (&error))
 +                      return NULL;
        } else {
                gpointer wait_event = NULL;
  
                ac->msg->exc = NULL;
 -              res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args);
 +
 +              res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
 +
 +              /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
 +              mono_threads_begin_abort_protected_block ();
 +
 +              if (!ac->msg->exc) {
 +                      MonoException *ex = mono_error_convert_to_exception (&error);
 +                      ac->msg->exc = (MonoObject *)ex;
 +              } else {
 +                      mono_error_cleanup (&error);
 +              }
 +
                MONO_OBJECT_SETREF (ac, res, res);
  
                mono_monitor_enter ((MonoObject*) ares);
                mono_monitor_exit ((MonoObject*) ares);
  
                if (wait_event != NULL)
 -                      SetEvent (wait_event);
 -
 -              if (ac->cb_method) {
 -                      /* we swallow the excepton as it is the behavior on .NET */
 -                      MonoObject *exc = NULL;
 -                      mono_runtime_invoke (ac->cb_method, ac->cb_target, (gpointer*) &ares, &exc);
 -                      if (exc)
 -                              mono_unhandled_exception (exc);
 -              }
 +                      mono_w32event_set (wait_event);
 +
 +              mono_error_init (&error); //the else branch would leave it in an undefined state
 +              if (ac->cb_method)
 +                      mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
 +
 +              mono_threads_end_abort_protected_block ();
 +
 +              if (mono_error_set_pending_exception (&error))
 +                      return NULL;
        }
  
        return res;
  }
  
 -void
 +gboolean
  mono_message_init (MonoDomain *domain,
                   MonoMethodMessage *this_obj, 
                   MonoReflectionMethod *method,
 -                 MonoArray *out_args)
 +                 MonoArray *out_args,
 +                 MonoError *error)
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
 -      static MonoClass *object_array_klass;
 -      static MonoClass *byte_array_klass;
 -      static MonoClass *string_array_klass;
 -      MonoMethodSignature *sig = mono_method_signature (method->method);
 -      MonoString *name;
 -      int i, j;
 -      char **names;
 -      guint8 arg_type;
 -
 -      if (!object_array_klass) {
 -              MonoClass *klass;
 -
 -              klass = mono_array_class_get (mono_defaults.byte_class, 1);
 -              g_assert (klass);
 -              byte_array_klass = klass;
 -
 -              klass = mono_array_class_get (mono_defaults.string_class, 1);
 -              g_assert (klass);
 -              string_array_klass = klass;
 -
 -              klass = mono_array_class_get (mono_defaults.object_class, 1);
 -              g_assert (klass);
 -
 -              mono_atomic_store_release (&object_array_klass, klass);
 -      }
 -
 -      MONO_OBJECT_SETREF (this_obj, method, method);
 -
 -      MONO_OBJECT_SETREF (this_obj, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
 -      MONO_OBJECT_SETREF (this_obj, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
 -      this_obj->async_result = NULL;
 -      this_obj->call_type = CallType_Sync;
 +      static MonoMethod *init_message_method = NULL;
  
 -      names = g_new (char *, sig->param_count);
 -      mono_method_get_param_names (method->method, (const char **) names);
 -      MONO_OBJECT_SETREF (this_obj, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
 -      
 -      for (i = 0; i < sig->param_count; i++) {
 -              name = mono_string_new (domain, names [i]);
 -              mono_array_setref (this_obj->names, i, name);   
 +      if (!init_message_method) {
 +              init_message_method = mono_class_get_method_from_name (mono_defaults.mono_method_message_class, "InitMessage", 2);
 +              g_assert (init_message_method != NULL);
        }
  
 -      g_free (names);
 -      for (i = 0, j = 0; i < sig->param_count; i++) {
 -              if (sig->params [i]->byref) {
 -                      if (out_args) {
 -                              MonoObject* arg = (MonoObject *)mono_array_get (out_args, gpointer, j);
 -                              mono_array_setref (this_obj->args, i, arg);
 -                              j++;
 -                      }
 -                      arg_type = 2;
 -                      if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
 -                              arg_type |= 1;
 -              } else {
 -                      arg_type = 1;
 -                      if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
 -                              arg_type |= 4;
 -              }
 -              mono_array_set (this_obj->arg_types, guint8, i, arg_type);
 -      }
 +      mono_error_init (error);
 +      /* FIXME set domain instead? */
 +      g_assert (domain == mono_domain_get ());
 +      
 +      gpointer args[2];
 +
 +      args[0] = method;
 +      args[1] = out_args;
 +
 +      mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
 +      return is_ok (error);
  }
  
  #ifndef DISABLE_REMOTING
   * Returns: the result object.
   */
  MonoObject *
 -mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, 
 -                    MonoObject **exc, MonoArray **out_args)
 +mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
 +      MonoObject *o;
        MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
        gpointer pa [4];
  
 +      g_assert (exc);
 +
 +      mono_error_init (error);
 +
        /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
  
        if (!im) {
                im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
 -              if (!im)
 -                      mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
 +              if (!im) {
 +                      mono_error_set_not_supported (error, "Linked away.");
 +                      return NULL;
 +              }
                real_proxy->vtable->domain->private_invoke_method = im;
        }
  
        pa [2] = exc;
        pa [3] = out_args;
  
 -      return mono_runtime_invoke (im, NULL, pa, exc);
 +      o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
 +      return_val_if_nok (error, NULL);
 +
 +      return o;
  }
  #endif
  
  MonoObject *
  mono_message_invoke (MonoObject *target, MonoMethodMessage *msg, 
 -                   MonoObject **exc, MonoArray **out_args) 
 +                   MonoObject **exc, MonoArray **out_args, MonoError *error
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
        static MonoClass *object_array_klass;
 +      mono_error_init (error);
 +
        MonoDomain *domain; 
        MonoMethod *method;
        MonoMethodSignature *sig;
 -      MonoObject *ret;
 +      MonoArray *arr;
        int i, j, outarg_count = 0;
  
  #ifndef DISABLE_REMOTING
                if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
                        target = tp->rp->unwrapped_server;
                } else {
 -                      return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
 +                      return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
                }
        }
  #endif
                object_array_klass = klass;
        }
  
 -      mono_gc_wbarrier_generic_store (out_args, (MonoObject*) mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count));
 +      arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
 +      return_val_if_nok (error, NULL);
 +
 +      mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
        *exc = NULL;
  
 -      ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
 +      MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
 +      return_val_if_nok (error, NULL);
  
        for (i = 0, j = 0; i < sig->param_count; i++) {
                if (sig->params [i]->byref) {
  }
  
  /**
 - * mono_object_to_string:
 + * prepare_to_string_method:
   * @obj: The object
 - * @exc: Any exception thrown by ToString (). May be NULL.
 + * @target: Set to @obj or unboxed value if a valuetype
   *
 - * Returns: the result of calling ToString () on an object.
 + * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
   */
 -MonoString *
 -mono_object_to_string (MonoObject *obj, MonoObject **exc)
 +static MonoMethod *
 +prepare_to_string_method (MonoObject *obj, void **target)
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
        static MonoMethod *to_string = NULL;
        MonoMethod *method;
 -      void *target = obj;
 -
 +      g_assert (target);
        g_assert (obj);
  
 +      *target = obj;
 +
        if (!to_string)
                to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
  
  
        // Unbox value type if needed
        if (mono_class_is_valuetype (mono_method_get_class (method))) {
 -              target = mono_object_unbox (obj);
 +              *target = mono_object_unbox (obj);
 +      }
 +      return method;
 +}
 +
 +/**
 + * mono_object_to_string:
 + * @obj: The object
 + * @exc: Any exception thrown by ToString (). May be NULL.
 + *
 + * Returns: the result of calling ToString () on an object.
 + */
 +MonoString *
 +mono_object_to_string (MonoObject *obj, MonoObject **exc)
 +{
 +      MonoError error;
 +      MonoString *s = NULL;
 +      void *target;
 +      MonoMethod *method = prepare_to_string_method (obj, &target);
 +      if (exc) {
 +              s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
 +              if (*exc == NULL && !mono_error_ok (&error))
 +                      *exc = (MonoObject*) mono_error_convert_to_exception (&error);
 +              else
 +                      mono_error_cleanup (&error);
 +      } else {
 +              s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
 +              mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
        }
  
 -      return (MonoString *) mono_runtime_invoke (method, target, NULL, exc);
 +      return s;
 +}
 +
 +/**
 + * mono_object_to_string_checked:
 + * @obj: The object
 + * @error: Set on error.
 + *
 + * Returns: the result of calling ToString () on an object. If the
 + * method cannot be invoked or if it raises an exception, sets @error
 + * and returns NULL.
 + */
 +MonoString *
 +mono_object_to_string_checked (MonoObject *obj, MonoError *error)
 +{
 +      mono_error_init (error);
 +      void *target;
 +      MonoMethod *method = prepare_to_string_method (obj, &target);
 +      return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
 +}
 +
 +/**
 + * mono_object_try_to_string:
 + * @obj: The object
 + * @exc: Any exception thrown by ToString (). Must not be NULL.
 + * @error: Set if method cannot be invoked.
 + *
 + * Returns: the result of calling ToString () on an object. If the
 + * method cannot be invoked sets @error, if it raises an exception sets @exc,
 + * and returns NULL.
 + */
 +MonoString *
 +mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
 +{
 +      g_assert (exc);
 +      mono_error_init (error);
 +      void *target;
 +      MonoMethod *method = prepare_to_string_method (obj, &target);
 +      return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
  }
  
 +
 +
  /**
   * mono_print_unhandled_exception:
   * @exc: The exception
@@@ -7726,11 -6355,7 +7727,11 @@@ mono_print_unhandled_exception (MonoObj
                        free_message = TRUE;
                } else {
                        MonoObject *other_exc = NULL;
 -                      str = mono_object_to_string (exc, &other_exc);
 +                      str = mono_object_try_to_string (exc, &other_exc, &error);
 +                      if (other_exc == NULL && !is_ok (&error))
 +                              other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
 +                      else
 +                              mono_error_cleanup (&error);
                        if (other_exc) {
                                char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
                                char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
  }
  
  /**
 - * mono_delegate_ctor:
 + * mono_delegate_ctor_with_method:
   * @this: pointer to an uninitialized delegate object
   * @target: target object
   * @addr: pointer to native code
   * @method: method
 + * @error: set on error.
   *
   * Initialize a delegate and sets a specific method, not the one
   * associated with addr.  This is useful when sharing generic code.
   * In that case addr will most probably not be associated with the
   * correct instantiation of the method.
 + * On failure returns FALSE and sets @error.
   */
 -void
 -mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method)
 +gboolean
 +mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method, MonoError *error)
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
 +      mono_error_init (error);
        MonoDelegate *delegate = (MonoDelegate *)this_obj;
  
        g_assert (this_obj);
        if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
                g_assert (method);
                method = mono_marshal_get_remoting_invoke (method);
 -              delegate->method_ptr = mono_compile_method (method);
 +              delegate->method_ptr = mono_compile_method_checked (method, error);
 +              return_val_if_nok (error, FALSE);
                MONO_OBJECT_SETREF (delegate, target, target);
        } else
  #endif
        }
  
        delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
 +      if (callbacks.init_delegate)
 +              callbacks.init_delegate (delegate);
 +      return TRUE;
  }
  
  /**
   * @this: pointer to an uninitialized delegate object
   * @target: target object
   * @addr: pointer to native code
 + * @error: set on error.
   *
   * This is used to initialize a delegate.
 + * On failure returns FALSE and sets @error.
   */
 -void
 -mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr)
 +gboolean
 +mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoError *error)
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
 +      mono_error_init (error);
        MonoDomain *domain = mono_domain_get ();
        MonoJitInfo *ji;
        MonoMethod *method = NULL;
                ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
        if (ji) {
                method = mono_jit_info_get_method (ji);
 -              g_assert (!method->klass->generic_container);
 +              g_assert (!mono_class_is_gtd (method->klass));
        }
  
 -      mono_delegate_ctor_with_method (this_obj, target, addr, method);
 +      return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
  }
  
  /**
   * @invoke: optional, delegate invoke.
   * @cb: async callback delegate.
   * @state: state passed to the async callback.
 + * @error: set on error.
   *
   * Translates arguments pointers into a MonoMethodMessage.
 + * On failure returns NULL and sets @error.
   */
  MonoMethodMessage *
  mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke, 
 -                            MonoDelegate **cb, MonoObject **state)
 +                            MonoDelegate **cb, MonoObject **state, MonoError *error)
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
 +      mono_error_init (error);
 +
        MonoDomain *domain = mono_domain_get ();
        MonoMethodSignature *sig = mono_method_signature (method);
        MonoMethodMessage *msg;
        int i, count;
  
 -      msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class); 
 -      
 +      msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error); 
 +      return_val_if_nok  (error, NULL);
 +
        if (invoke) {
 -              mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
 +              MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
 +              return_val_if_nok (error, NULL);
 +              mono_message_init (domain, msg, rm, NULL, error);
 +              return_val_if_nok (error, NULL);
                count =  sig->param_count - 2;
        } else {
 -              mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
 +              MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
 +              return_val_if_nok (error, NULL);
 +              mono_message_init (domain, msg, rm, NULL, error);
 +              return_val_if_nok (error, NULL);
                count =  sig->param_count;
        }
  
  
                klass = mono_class_from_mono_type (sig->params [i]);
  
 -              if (klass->valuetype)
 -                      arg = mono_value_box (domain, klass, vpos);
 -              else 
 +              if (klass->valuetype) {
 +                      arg = mono_value_box_checked (domain, klass, vpos, error);
 +                      return_val_if_nok (error, NULL);
 +              } else 
                        arg = *((MonoObject **)vpos);
                      
                mono_array_setref (msg->args, i, arg);
   * Restore results from message based processing back to arguments pointers
   */
  void
 -mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
 +mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
 +      mono_error_init (error);
 +
        MonoMethodSignature *sig = mono_method_signature (method);
        int i, j, type, size, out_len;
        
  
                if (pt->byref) {
                        char *arg;
 -                      if (j >= out_len)
 -                              mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
 +                      if (j >= out_len) {
 +                              mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
 +                              return;
 +                      }
  
                        arg = (char *)mono_array_get (out_args, gpointer, j);
                        type = pt->type;
   */
  gpointer
  mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
 +{
 +      MonoError error;
 +      gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
 +      mono_error_cleanup (&error);
 +      return result;
 +}
 +
 +/**
 + * mono_load_remote_field_checked:
 + * @this: pointer to an object
 + * @klass: klass of the object containing @field
 + * @field: the field to load
 + * @res: a storage to store the result
 + * @error: set on error
 + *
 + * This method is called by the runtime on attempts to load fields of
 + * transparent proxy objects. @this points to such TP, @klass is the class of
 + * the object containing @field. @res is a storage location which can be
 + * used to store the result.
 + *
 + * Returns: an address pointing to the value of field.  On failure returns NULL and sets @error.
 + */
 +gpointer
 +mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
        static MonoMethod *getter = NULL;
 +
 +      mono_error_init (error);
 +
        MonoDomain *domain = mono_domain_get ();
        MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
        MonoClass *field_class;
        
        if (!getter) {
                getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
 -              if (!getter)
 -                      mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
 +              if (!getter) {
 +                      mono_error_set_not_supported (error, "Linked away.");
 +                      return NULL;
 +              }
        }
        
        field_class = mono_class_from_mono_type (field->type);
  
 -      msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
 -      out_args = mono_array_new (domain, mono_defaults.object_class, 1);
 -      mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
 +      msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
 +      return_val_if_nok (error, NULL);
 +      out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
 +      return_val_if_nok (error, NULL);
 +      MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
 +      return_val_if_nok (error, NULL);
 +      mono_message_init (domain, msg, rm, out_args, error);
 +      return_val_if_nok (error, NULL);
  
        full_name = mono_type_get_full_name (klass);
        mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
        mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
        g_free (full_name);
  
 -      mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
 +      mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
 +      return_val_if_nok (error, NULL);
  
 -      if (exc) mono_raise_exception ((MonoException *)exc);
 +      if (exc) {
 +              mono_error_set_exception_instance (error, (MonoException *)exc);
 +              return NULL;
 +      }
  
        if (mono_array_length (out_args) == 0)
                return NULL;
  
 -      *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
 +      mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
  
        if (field_class->valuetype) {
                return ((char *)*res) + sizeof (MonoObject);
   */
  MonoObject *
  mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
 +{
 +      MonoError error;
 +
 +      MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
 +      mono_error_cleanup (&error);
 +      return result;
 +}
 +
 +/**
 + * mono_load_remote_field_new_checked:
 + * @this: pointer to an object
 + * @klass: klass of the object containing @field
 + * @field: the field to load
 + * @error: set on error.
 + *
 + * This method is called by the runtime on attempts to load fields of
 + * transparent proxy objects. @this points to such TP, @klass is the class of
 + * the object containing @field.
 + * 
 + * Returns: a freshly allocated object containing the value of the field.  On failure returns NULL and sets @error.
 + */
 +MonoObject *
 +mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
  {
        MONO_REQ_GC_UNSAFE_MODE;
  
 -      static MonoMethod *getter = NULL;
 -      MonoDomain *domain = mono_domain_get ();
 -      MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
 -      MonoClass *field_class;
 -      MonoMethodMessage *msg;
 -      MonoArray *out_args;
 -      MonoObject *exc, *res;
 -      char* full_name;
 +      mono_error_init (error);
  
 -      g_assert (mono_object_is_transparent_proxy (this_obj));
 +      static MonoMethod *tp_load = NULL;
  
 -      field_class = mono_class_from_mono_type (field->type);
 +      g_assert (mono_object_is_transparent_proxy (this_obj));
  
 -      if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
 -              gpointer val;
 -              if (field_class->valuetype) {
 -                      res = mono_object_new (domain, field_class);
 -                      val = ((gchar *) res) + sizeof (MonoObject);
 -              } else {
 -                      val = &res;
 +      if (!tp_load) {
 +              tp_load = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "LoadRemoteFieldNew", -1);
 +              if (!tp_load) {
 +                      mono_error_set_not_supported (error, "Linked away.");
 +                      return NULL;
                }
 -              mono_field_get_value (tp->rp->unwrapped_server, field, val);
 -              return res;
 -      }
 -
 -      if (!getter) {
 -              getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
 -              if (!getter)
 -                      mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
        }
        
 -      msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
 -      out_args = mono_array_new (domain, mono_defaults.object_class, 1);
 -
 -      mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
 -
 -      full_name = mono_type_get_full_name (klass);
 -      mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
 -      mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
 -      g_free (full_name);
 +      /* MonoType *type = mono_class_get_type (klass); */
  
 -      mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
 +      gpointer args[2];
 +      args [0] = &klass;
 +      args [1] = &field;
  
 -      if (exc) mono_raise_exception ((MonoException *)exc);
 -
 -      if (mono_array_length (out_args) == 0)
 -              res = NULL;
 -      else
 -              res = mono_array_get (out_args, MonoObject *, 0);
 -
 -      return res;
 +      return mono_runtime_invoke_checked (tp_load, this_obj, args, error);
  }
  
  /**
  void
  mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
  {
 +      MonoError error;
 +      (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
 +      mono_error_cleanup (&error);
 +}
 +
 +/**
 + * mono_store_remote_field_checked:
 + * @this_obj: pointer to an object
 + * @klass: klass of the object containing @field
 + * @field: the field to load
 + * @val: the value/object to store
 + * @error: set on error
 + *
 + * This method is called by the runtime on attempts to store fields of
 + * transparent proxy objects. @this_obj points to such TP, @klass is the class of
 + * the object containing @field. @val is the new value to store in @field.
 + *
 + * Returns: on success returns TRUE, on failure returns FALSE and sets @error.
 + */
 +gboolean
 +mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
 +{
 +      
        MONO_REQ_GC_UNSAFE_MODE;
  
 -      static MonoMethod *setter = NULL;
 +      mono_error_init (error);
 +
        MonoDomain *domain = mono_domain_get ();
 -      MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
        MonoClass *field_class;
 -      MonoMethodMessage *msg;
 -      MonoArray *out_args;
 -      MonoObject *exc;
        MonoObject *arg;
 -      char* full_name;
  
        g_assert (mono_object_is_transparent_proxy (this_obj));
  
        field_class = mono_class_from_mono_type (field->type);
  
 -      if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
 -              if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
 -              else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
 -              return;
 -      }
 -
 -      if (!setter) {
 -              setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
 -              if (!setter)
 -                      mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
 +      if (field_class->valuetype) {
 +              arg = mono_value_box_checked (domain, field_class, val, error);
 +              return_val_if_nok (error, FALSE);
 +      } else {
 +              arg = *((MonoObject**)val);
        }
  
 -      if (field_class->valuetype)
 -              arg = mono_value_box (domain, field_class, val);
 -      else 
 -              arg = *((MonoObject **)val);
 -              
 -
 -      msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
 -      mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
 -
 -      full_name = mono_type_get_full_name (klass);
 -      mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
 -      mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
 -      mono_array_setref (msg->args, 2, arg);
 -      g_free (full_name);
 -
 -      mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
 -
 -      if (exc) mono_raise_exception ((MonoException *)exc);
 +      return mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
  }
  
  /**
  void
  mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
  {
 -      MONO_REQ_GC_UNSAFE_MODE;
 +      MonoError error;
 +      (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
 +      mono_error_cleanup (&error);
 +}
  
 -      static MonoMethod *setter = NULL;
 -      MonoDomain *domain = mono_domain_get ();
 -      MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
 -      MonoClass *field_class;
 -      MonoMethodMessage *msg;
 -      MonoArray *out_args;
 -      MonoObject *exc;
 -      char* full_name;
 +/**
 + * mono_store_remote_field_new_checked:
 + * @this_obj:
 + * @klass:
 + * @field:
 + * @arg:
 + * @error:
 + *
 + * Missing documentation
 + */
 +gboolean
 +mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
 +{
 +      MONO_REQ_GC_UNSAFE_MODE;
  
 -      g_assert (mono_object_is_transparent_proxy (this_obj));
 +      static MonoMethod *tp_store = NULL;
  
 -      field_class = mono_class_from_mono_type (field->type);
 +      mono_error_init (error);
  
 -      if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
 -              if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
 -              else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
 -              return;
 -      }
 +      g_assert (mono_object_is_transparent_proxy (this_obj));
  
 -      if (!setter) {
 -              setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
 -              if (!setter)
 -                      mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
 +      if (!tp_store) {
 +              tp_store = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "StoreRemoteField", -1);
 +              if (!tp_store) {
 +                      mono_error_set_not_supported (error, "Linked away.");
 +                      return FALSE;
 +              }
        }
  
 -      msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
 -      mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
 -
 -      full_name = mono_type_get_full_name (klass);
 -      mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
 -      mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
 -      mono_array_setref (msg->args, 2, arg);
 -      g_free (full_name);
 -
 -      mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
 +      gpointer args[3];
 +      args [0] = &klass;
 +      args [1] = &field;
 +      args [2] = arg;
  
 -      if (exc) mono_raise_exception ((MonoException *)exc);
 +      mono_runtime_invoke_checked (tp_store, this_obj, args, error);
 +      return is_ok (error);
  }
  #endif
  
@@@ -8333,11 -6902,6 +8334,11 @@@ mono_array_length (MonoArray *array
   * @size: size of the array elements
   * @idx: index into the array
   *
 + * Use this function to obtain the address for the @idx item on the
 + * @array containing elements of size @size.
 + *
 + * This method performs no bounds checking or type checking.
 + *
   * Returns the address of the @idx element in the array.
   */
  char*
@@@ -8350,19 -6914,17 +8351,19 @@@ mono_array_addr_with_size (MonoArray *a
  
  
  MonoArray *
 -mono_glist_to_array (GList *list, MonoClass *eclass) 
 +mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error
  {
        MonoDomain *domain = mono_domain_get ();
        MonoArray *res;
        int len, i;
  
 +      mono_error_init (error);
        if (!list)
                return NULL;
  
        len = g_list_length (list);
 -      res = mono_array_new (domain, eclass, len);
 +      res = mono_array_new_checked (domain, eclass, len, error);
 +      return_val_if_nok (error, NULL);
  
        for (i = 0; list; list = list->next, i++)
                mono_array_set (res, gpointer, i, list->data);
        return res;
  }
  
 +#if NEVER_DEFINED
 +/*
 + * The following section is purely to declare prototypes and
 + * document the API, as these C files are processed by our
 + * tool
 + */
 +
 +/**
 + * mono_array_set:
 + * @array: array to alter
 + * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
 + * @index: index into the array
 + * @value: value to set
 + *
 + * Value Type version: This sets the @index's element of the @array
 + * with elements of size sizeof(type) to the provided @value.
 + *
 + * This macro does not attempt to perform type checking or bounds checking.
 + *
 + * Use this to set value types in a `MonoArray`.
 + */
 +void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
 +{
 +}
 +
 +/**
 + * mono_array_setref:
 + * @array: array to alter
 + * @index: index into the array
 + * @value: value to set
 + *
 + * Reference Type version: This sets the @index's element of the
 + * @array with elements of size sizeof(type) to the provided @value.
 + *
 + * This macro does not attempt to perform type checking or bounds checking.
 + *
 + * Use this to reference types in a `MonoArray`.
 + */
 +void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
 +{
 +}
 +
 +/**
 + * mono_array_get:
 + * @array: array on which to operate on
 + * @element_type: C element type (example: MonoString *, int, MonoObject *)
 + * @index: index into the array
 + *
 + * Use this macro to retrieve the @index element of an @array and
 + * extract the value assuming that the elements of the array match
 + * the provided type value.
 + *
 + * This method can be used with both arrays holding value types and
 + * reference types.   For reference types, the @type parameter should
 + * be a `MonoObject*` or any subclass of it, like `MonoString*`.
 + *
 + * This macro does not attempt to perform type checking or bounds checking.
 + *
 + * Returns: The element at the @index position in the @array.
 + */
 +Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)
 +{
 +}
 +#endif
 + 
diff --combined mono/mini/method-to-ir.c
index 52ffb7290d6dd76af740af12a491023e82574354,74095f58975957d44f67982cc533f7feca6af3db..3143431b6c48b11fab721ee8d1d0f6739519716b
@@@ -8,7 -8,6 +8,7 @@@
   * (C) 2002 Ximian, Inc.
   * Copyright 2003-2010 Novell, Inc (http://www.novell.com)
   * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
 + * Licensed under the MIT license. See LICENSE file in the project root for full license information.
   */
  
  #include <config.h>
  #include <mono/metadata/security-core-clr.h>
  #include <mono/metadata/profiler-private.h>
  #include <mono/metadata/profiler.h>
 +#include <mono/metadata/monitor.h>
  #include <mono/metadata/debug-mono-symfile.h>
  #include <mono/utils/mono-compiler.h>
  #include <mono/utils/mono-memory-model.h>
 +#include <mono/utils/mono-error-internals.h>
  #include <mono/metadata/mono-basic-block.h>
 +#include <mono/metadata/reflection-internals.h>
 +#include <mono/utils/mono-threads-coop.h>
  
  #include "trace.h"
  
                if (cfg->exception_type != MONO_EXCEPTION_NONE) \
                        goto exception_exit;                                            \
        } while (0)
 -#define METHOD_ACCESS_FAILURE(method, cmethod) do {                   \
 -              method_access_failure ((cfg), (method), (cmethod));                     \
 -              goto exception_exit;                                                                            \
 -      } while (0)
  #define FIELD_ACCESS_FAILURE(method, field) do {                                      \
                field_access_failure ((cfg), (method), (field));                        \
                goto exception_exit;    \
        }                                                                                                                                       \
        } while (0)
  #define OUT_OF_MEMORY_FAILURE do {    \
 -              mono_cfg_set_exception (cfg, MONO_EXCEPTION_OUT_OF_MEMORY);             \
 +              mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);                \
 +              mono_error_set_out_of_memory (&cfg->error, "");                                 \
                goto exception_exit;    \
        } while (0)
  #define DISABLE_AOT(cfg) do { \
@@@ -154,11 -152,7 +154,11 @@@ emit_llvmonly_virtual_call (MonoCompil
  /* helper methods signatures */
  static MonoMethodSignature *helper_sig_domain_get;
  static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
 -static MonoMethodSignature *helper_sig_llvmonly_imt_thunk;
 +static MonoMethodSignature *helper_sig_llvmonly_imt_trampoline;
 +
 +/* type loading helpers */
 +static GENERATE_GET_CLASS_WITH_CACHE (runtime_helpers, System.Runtime.CompilerServices, RuntimeHelpers)
 +static GENERATE_TRY_GET_CLASS_WITH_CACHE (debuggable_attribute, System.Diagnostics, DebuggableAttribute)
  
  /*
   * Instruction metadata
@@@ -363,7 -357,7 +363,7 @@@ mono_create_helper_signatures (void
  {
        helper_sig_domain_get = mono_create_icall_signature ("ptr");
        helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
 -      helper_sig_llvmonly_imt_thunk = mono_create_icall_signature ("ptr ptr ptr");
 +      helper_sig_llvmonly_imt_trampoline = mono_create_icall_signature ("ptr ptr ptr");
  }
  
  static MONO_NEVER_INLINE void
@@@ -373,13 -367,24 +373,13 @@@ break_on_unverified (void
                G_BREAKPOINT ();
  }
  
 -static MONO_NEVER_INLINE void
 -method_access_failure (MonoCompile *cfg, MonoMethod *method, MonoMethod *cil_method)
 -{
 -      char *method_fname = mono_method_full_name (method, TRUE);
 -      char *cil_method_fname = mono_method_full_name (cil_method, TRUE);
 -      mono_cfg_set_exception (cfg, MONO_EXCEPTION_METHOD_ACCESS);
 -      cfg->exception_message = g_strdup_printf ("Method `%s' is inaccessible from method `%s'\n", cil_method_fname, method_fname);
 -      g_free (method_fname);
 -      g_free (cil_method_fname);
 -}
 -
  static MONO_NEVER_INLINE void
  field_access_failure (MonoCompile *cfg, MonoMethod *method, MonoClassField *field)
  {
        char *method_fname = mono_method_full_name (method, TRUE);
        char *field_fname = mono_field_full_name (field);
 -      mono_cfg_set_exception (cfg, MONO_EXCEPTION_FIELD_ACCESS);
 -      cfg->exception_message = g_strdup_printf ("Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);
 +      mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
 +      mono_error_set_generic_error (&cfg->error, "System", "FieldAccessException", "Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);
        g_free (method_fname);
        g_free (field_fname);
  }
@@@ -660,24 -665,6 +660,24 @@@ mono_find_block_region (MonoCompile *cf
        return -1;
  }
  
 +static gboolean
 +ip_in_finally_clause (MonoCompile *cfg, int offset)
 +{
 +      MonoMethodHeader *header = cfg->header;
 +      MonoExceptionClause *clause;
 +      int i;
 +
 +      for (i = 0; i < header->num_clauses; ++i) {
 +              clause = &header->clauses [i];
 +              if (clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FAULT)
 +                      continue;
 +
 +              if (MONO_OFFSET_IN_HANDLER (clause, offset))
 +                      return TRUE;
 +      }
 +      return FALSE;
 +}
 +
  static GList*
  mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
  {
@@@ -1557,12 -1544,10 +1557,12 @@@ emit_runtime_constant (MonoCompile *cfg
        } else {
                MonoJumpInfo ji;
                gpointer target;
 +              MonoError error;
  
                ji.type = patch_type;
                ji.data.target = data;
 -              target = mono_resolve_patch_target (NULL, cfg->domain, NULL, &ji, FALSE);
 +              target = mono_resolve_patch_target (NULL, cfg->domain, NULL, &ji, FALSE, &error);
 +              mono_error_assert_ok (&error);
  
                EMIT_NEW_PCONST (cfg, ins, target);
        }
@@@ -1657,7 -1642,7 +1657,7 @@@ mini_emit_max_iid_check_vtable (MonoCom
  {
        int max_iid_reg = alloc_preg (cfg);
                
-       MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id));
+       MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU4_MEMBASE, max_iid_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id));
        mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
  }
  
@@@ -1668,7 -1653,7 +1668,7 @@@ mini_emit_max_iid_check_class (MonoComp
  {
        int max_iid_reg = alloc_preg (cfg);
  
-       MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, max_interface_id));
+       MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU4_MEMBASE, max_iid_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, max_interface_id));
        mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
  }
  
@@@ -1794,7 -1779,7 +1794,7 @@@ mini_emit_castclass_inst (MonoCompile *
                        mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
                } else if (klass->cast_class == mono_defaults.enum_class) {
                        mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
 -              } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
 +              } else if (mono_class_is_interface (klass->cast_class)) {
                        mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL);
                } else {
                        // Pass -1 as obj_reg to skip the check below for arrays of arrays
@@@ -2191,9 -2176,6 +2191,9 @@@ handle_enum
        return -1;
  }
  
 +//XXX this ignores if t is byref
 +#define MONO_TYPE_IS_PRIMITIVE_SCALAR(t) ((((((t)->type >= MONO_TYPE_BOOLEAN && (t)->type <= MONO_TYPE_U8) || ((t)->type >= MONO_TYPE_I && (t)->type <= MONO_TYPE_U)))))
 +
  /*
   * target_type_is_incompatible:
   * @cfg: MonoCompile context
@@@ -2214,19 -2196,10 +2214,19 @@@ target_type_is_incompatible (MonoCompil
        if (target->byref) {
                /* FIXME: check that the pointed to types match */
                if (arg->type == STACK_MP) {
 -                      MonoClass *base_class = mono_class_from_mono_type (target);
 -                      /* This is needed to handle gshared types + ldaddr */
 -                      simple_type = mini_get_underlying_type (&base_class->byval_arg);
 -                      return target->type != MONO_TYPE_I && arg->klass != base_class && arg->klass != mono_class_from_mono_type (simple_type);
 +                      /* This is needed to handle gshared types + ldaddr. We lower the types so we can handle enums and other typedef-like types. */
 +                      MonoClass *target_class_lowered = mono_class_from_mono_type (mini_get_underlying_type (&mono_class_from_mono_type (target)->byval_arg));
 +                      MonoClass *source_class_lowered = mono_class_from_mono_type (mini_get_underlying_type (&arg->klass->byval_arg));
 +
 +                      /* if the target is native int& or same type */
 +                      if (target->type == MONO_TYPE_I || target_class_lowered == source_class_lowered)
 +                              return 0;
 +
 +                      /* Both are primitive type byrefs and the source points to a larger type that the destination */
 +                      if (MONO_TYPE_IS_PRIMITIVE_SCALAR (&target_class_lowered->byval_arg) && MONO_TYPE_IS_PRIMITIVE_SCALAR (&source_class_lowered->byval_arg) &&
 +                              mono_class_instance_size (target_class_lowered) <= mono_class_instance_size (source_class_lowered))
 +                              return 0;
 +                      return 1;
                }
                if (arg->type == STACK_PTR)
                        return 0;
@@@ -2550,7 -2523,7 +2550,7 @@@ check_method_sharing (MonoCompile *cfg
        gboolean pass_mrgctx = FALSE;
  
        if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
 -              (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
 +              (mono_class_is_ginst (cmethod->klass) || mono_class_is_gtd (cmethod->klass))) {
                gboolean sharable = FALSE;
  
                if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE))
@@@ -2791,7 -2764,7 +2791,7 @@@ mono_emit_method_call_full (MonoCompil
        if (!sig)
                sig = mono_method_signature (method);
  
 -      if (cfg->llvm_only && (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE))
 +      if (cfg->llvm_only && (mono_class_is_interface (method->klass)))
                g_assert_not_reached ();
  
        if (rgctx_arg) {
        if (cfg->llvm_only && !call_target && virtual_ && (method->flags & METHOD_ATTRIBUTE_VIRTUAL))
                return emit_llvmonly_virtual_call (cfg, method, sig, 0, args);
  
 -      need_unbox_trampoline = method->klass == mono_defaults.object_class || (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
 +      need_unbox_trampoline = method->klass == mono_defaults.object_class || mono_class_is_interface (method->klass);
  
        call = mono_emit_call_args (cfg, sig, args, FALSE, virtual_, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
  
                } else {
                        vtable_reg = alloc_preg (cfg);
                        MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
 -                      if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
 +                      if (mono_class_is_interface (method->klass)) {
                                guint32 imt_slot = mono_method_get_imt_slot (method);
                                emit_imt_argument (cfg, call, call->method, imt_arg);
                                slot_reg = vtable_reg;
@@@ -3070,7 -3043,7 +3070,7 @@@ direct_icalls_enabled (MonoCompile *cfg
  {
        /* LLVM on amd64 can't handle calls to non-32 bit addresses */
  #ifdef TARGET_AMD64
 -      if (cfg->compile_llvm)
 +      if (cfg->compile_llvm && !cfg->llvm_only)
                return FALSE;
  #endif
        if (cfg->gen_sdb_seq_points || cfg->disable_direct_icalls)
  }
  
  MonoInst*
 -mono_emit_jit_icall_by_info (MonoCompile *cfg, MonoJitICallInfo *info, MonoInst **args)
 +mono_emit_jit_icall_by_info (MonoCompile *cfg, int il_offset, MonoJitICallInfo *info, MonoInst **args)
  {
        /*
         * Call the jit icall without a wrapper if possible.
                 * an exception check.
                 */
                costs = inline_method (cfg, info->wrapper_method, NULL,
 -                                                         args, NULL, cfg->real_offset, TRUE);
 +                                                         args, NULL, il_offset, TRUE);
                g_assert (costs > 0);
                g_assert (!MONO_TYPE_IS_VOID (info->sig->ret));
  
@@@ -3158,18 -3131,6 +3158,18 @@@ mono_emit_widen_call_res (MonoCompile *
        return ins;
  }
  
 +
 +static void
 +emit_method_access_failure (MonoCompile *cfg, MonoMethod *method, MonoMethod *cil_method)
 +{
 +      MonoInst *args [16];
 +
 +      args [0] = emit_get_rgctx_method (cfg, mono_method_check_context_used (method), method, MONO_RGCTX_INFO_METHOD);
 +      args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cil_method), cil_method, MONO_RGCTX_INFO_METHOD);
 +
 +      mono_emit_jit_icall (cfg, mono_throw_method_access, args);
 +}
 +
  static MonoMethod*
  get_memcpy_method (void)
  {
@@@ -4050,8 -4011,7 +4050,8 @@@ handle_unbox_nullable (MonoCompile* cfg
                   RGCTX. */
                addr = emit_get_rgctx_method (cfg, context_used, method,
                                                                          MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
 -              if (cfg->llvm_only && cfg->gsharedvt) {
 +              if (cfg->llvm_only) {
 +                      cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, mono_method_signature (method));
                        return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
                } else {
                        rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
@@@ -4233,10 -4193,10 +4233,10 @@@ handle_alloc (MonoCompile *cfg, MonoCla
                if (cfg->opt & MONO_OPT_SHARED) {
                        EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
                        iargs [1] = data;
 -                      alloc_ftn = mono_object_new;
 +                      alloc_ftn = ves_icall_object_new;
                } else {
                        iargs [0] = data;
 -                      alloc_ftn = mono_object_new_specific;
 +                      alloc_ftn = ves_icall_object_new_specific;
                }
  
                if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED)) {
                                if (size < sizeof (MonoObject))
                                        g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
  
 -                              EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (size));
 +                              EMIT_NEW_ICONST (cfg, iargs [1], size);
                        }
                        return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
                }
                EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
                EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
  
 -              alloc_ftn = mono_object_new;
 -      } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !klass->generic_class) {
 +              alloc_ftn = ves_icall_object_new;
 +      } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !mono_class_is_ginst (klass)) {
                /* This happens often in argument checking code, eg. throw new FooException... */
                /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
                EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
                                g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
  
                        EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
 -                      EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (size));
 +                      EMIT_NEW_ICONST (cfg, iargs [1], size);
                        return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
                }
                alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
@@@ -4432,11 -4392,11 +4432,11 @@@ mini_class_has_reference_variant_generi
        MonoGenericContainer *container;
        MonoGenericInst *ginst;
  
 -      if (klass->generic_class) {
 -              container = klass->generic_class->container_class->generic_container;
 -              ginst = klass->generic_class->context.class_inst;
 -      } else if (klass->generic_container && context_used) {
 -              container = klass->generic_container;
 +      if (mono_class_is_ginst (klass)) {
 +              container = mono_class_get_generic_container (mono_class_get_generic_class (klass)->container_class);
 +              ginst = mono_class_get_generic_class (klass)->context.class_inst;
 +      } else if (mono_class_is_gtd (klass) && context_used) {
 +              container = mono_class_get_generic_container (klass);
                ginst = container->context.class_inst;
        } else {
                return FALSE;
@@@ -4485,31 -4445,16 +4485,31 @@@ icall_is_direct_callable (MonoCompile *
        return FALSE;
  }
  
 -#define is_complex_isinst(klass) ((klass->flags & TYPE_ATTRIBUTE_INTERFACE) || klass->rank || mono_class_is_nullable (klass) || mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_SEALED) || klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR)
 +static gboolean
 +method_needs_stack_walk (MonoCompile *cfg, MonoMethod *cmethod)
 +{
 +      if (cmethod->klass == mono_defaults.systemtype_class) {
 +              if (!strcmp (cmethod->name, "GetType"))
 +                      return TRUE;
 +      }
 +      return FALSE;
 +}
 +
 +#define is_complex_isinst(klass) (mono_class_is_interface (klass) || klass->rank || mono_class_is_nullable (klass) || mono_class_is_marshalbyref (klass) || mono_class_is_sealed (klass) || klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR)
 +
 +static MonoInst*
 +emit_isinst_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args)
 +{
 +      MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
 +      return mono_emit_method_call (cfg, mono_isinst, args, NULL);
 +}
  
  static MonoInst*
  emit_castclass_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args)
  {
 -      MonoMethod *mono_castclass;
 +      MonoMethod *mono_castclass = mono_marshal_get_castclass_with_cache ();
        MonoInst *res;
  
 -      mono_castclass = mono_marshal_get_castclass_with_cache ();
 -
        save_cast_details (cfg, klass, args [0]->dreg, TRUE);
        res = mono_emit_method_call (cfg, mono_castclass, args, NULL);
        reset_cast_details (cfg);
@@@ -4525,22 -4470,6 +4525,22 @@@ get_castclass_cache_idx (MonoCompile *c
        return (cfg->method_index << 16) | cfg->castclass_cache_index;
  }
  
 +
 +static MonoInst*
 +emit_isinst_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass)
 +{
 +      MonoInst *args [3];
 +      int idx;
 +
 +      args [0] = obj; /* obj */
 +      EMIT_NEW_CLASSCONST (cfg, args [1], klass); /* klass */
 +
 +      idx = get_castclass_cache_idx (cfg); /* inline cache*/
 +      args [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
 +
 +      return emit_isinst_with_cache (cfg, klass, args);
 +}
 +
  static MonoInst*
  emit_castclass_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass)
  {
   * Returns NULL and set the cfg exception on error.
   */
  static MonoInst*
 -handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, guint8 *ip, int *inline_costs)
 +handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
  {
        MonoBasicBlock *is_null_bb;
        int obj_reg = src->dreg;
        int vtable_reg = alloc_preg (cfg);
 -      int context_used;
 -      MonoInst *klass_inst = NULL, *res;
 -
 -      context_used = mini_class_check_context_used (cfg, klass);
 -
 -      if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
 -              res = emit_castclass_with_cache_nonshared (cfg, src, klass);
 -              (*inline_costs) += 2;
 -              return res;
 -      } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
 -              MonoMethod *mono_castclass;
 -              MonoInst *iargs [1];
 -              int costs;
 -
 -              mono_castclass = mono_marshal_get_castclass (klass); 
 -              iargs [0] = src;
 -                              
 -              save_cast_details (cfg, klass, src->dreg, TRUE);
 -              costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
 -                                                         iargs, ip, cfg->real_offset, TRUE);
 -              reset_cast_details (cfg);
 -              CHECK_CFG_EXCEPTION;
 -              g_assert (costs > 0);
 -                              
 -              cfg->real_offset += 5;
 -
 -              (*inline_costs) += costs;
 +      MonoInst *klass_inst = NULL;
  
 +      if (MONO_INS_IS_PCONST_NULL (src))
                return src;
 -      }
  
        if (context_used) {
                MonoInst *args [3];
  
 -              if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
 +              if (mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
                        MonoInst *cache_ins;
  
                        cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
  
        save_cast_details (cfg, klass, obj_reg, FALSE);
  
 -      if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
 +      if (mono_class_is_interface (klass)) {
                MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
                mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL);
        } else {
  
                MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
  
 -              if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
 +              if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && mono_class_is_sealed (klass)) {
                        /* the remoting code is broken, access the class for now */
                        if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
                                MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
        reset_cast_details (cfg);
  
        return src;
 -
 -exception_exit:
 -      return NULL;
  }
  
  /*
@@@ -4658,15 -4616,21 +4658,15 @@@ handle_isinst (MonoCompile *cfg, MonoCl
                MonoInst *args [3];
  
                if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
 -                      MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
 -                      MonoInst *cache_ins;
 +                      MonoInst *cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
  
 -                      cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
 -
 -                      /* obj */
 -                      args [0] = src;
 +                      args [0] = src; /* obj */
  
                        /* klass - it's the second element of the cache entry*/
                        EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
  
 -                      /* cache */
 -                      args [2] = cache_ins;
 -
 -                      return mono_emit_method_call (cfg, mono_isinst, args, NULL);
 +                      args [2] = cache_ins; /* cache */
 +                      return emit_isinst_with_cache (cfg, klass, args);
                }
  
                klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
  
        MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
  
 -      if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
 +      if (mono_class_is_interface (klass)) {
                g_assert (!context_used);
                /* the is_null_bb target simply copies the input register to the output */
                mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
                        } else if (klass->cast_class == mono_defaults.enum_class) {
                                mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
                                MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
 -                      } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
 +                      } else if (mono_class_is_interface (klass->cast_class)) {
                                mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
                        } else {
                                if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
                        /* the is_null_bb target simply copies the input register to the output */
                        mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
                } else {
 -                      if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
 +                      if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && mono_class_is_sealed (klass)) {
                                g_assert (!context_used);
                                /* the remoting code is broken, access the class for now */
                                if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
@@@ -4805,7 -4769,7 +4805,7 @@@ handle_cisinst (MonoCompile *cfg, MonoC
        MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
        MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
  
 -      if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
 +      if (mono_class_is_interface (klass)) {
  #ifndef DISABLE_REMOTING
                NEW_BBLOCK (cfg, interface_fail_bb);
  #endif
@@@ -4909,7 -4873,7 +4909,7 @@@ handle_ccastclass (MonoCompile *cfg, Mo
  
        save_cast_details (cfg, klass, obj_reg, FALSE);
  
 -      if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
 +      if (mono_class_is_interface (klass)) {
  #ifndef DISABLE_REMOTING
                NEW_BBLOCK (cfg, interface_fail_bb);
        
@@@ -5052,11 -5016,27 +5052,11 @@@ handle_delegate_ctor (MonoCompile *cfg
        if (!obj)
                return NULL;
  
 -      if (cfg->llvm_only) {
 -              MonoInst *args [16];
 -
 -              /*
 -               * If the method to be called needs an rgctx, we can't fall back to mono_delegate_ctor (), since it might receive
 -               * the address of a gshared method. So use a JIT icall.
 -               * FIXME: Optimize this.
 -               */
 -              args [0] = obj;
 -              args [1] = target;
 -              args [2] = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
 -              mono_emit_jit_icall (cfg, virtual_ ? mono_init_delegate_virtual : mono_init_delegate, args);
 -
 -              return obj;
 -      }
 -
        /* Inline the contents of mono_delegate_ctor */
  
        /* Set target field */
        /* Optimize away setting of NULL target */
 -      if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
 +      if (!MONO_INS_IS_PCONST_NULL (target)) {
                MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
                if (cfg->gen_write_barriers) {
                        dreg = alloc_preg (cfg);
                MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);                
        }
  
 +      if (cfg->llvm_only) {
 +              MonoInst *args [16];
 +
 +              if (virtual_) {
 +                      args [0] = obj;
 +                      args [1] = target;
 +                      args [2] = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
 +                      mono_emit_jit_icall (cfg, mono_llvmonly_init_delegate_virtual, args);
 +              } else {
 +                      args [0] = obj;
 +                      mono_emit_jit_icall (cfg, mono_llvmonly_init_delegate, args);
 +              }
 +
 +              return obj;
 +      }
 +
        if (cfg->compile_aot) {
                MonoDelegateClassMethodPair *del_tramp;
  
@@@ -5161,7 -5125,6 +5161,7 @@@ handle_array_new (MonoCompile *cfg, in
        cfg->flags |= MONO_CFG_HAS_VARARGS;
  
        /* mono_array_new_va () needs a vararg calling convention */
 +      cfg->exception_message = g_strdup ("array-new");
        cfg->disable_llvm = TRUE;
  
        /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
@@@ -5186,7 -5149,7 +5186,7 @@@ handle_constrained_gsharedvt_call (Mono
         * This is hard to do with the current call code, since we would have to emit a branch and two different calls. So instead, we
         * pack the arguments into an array, and do the rest of the work in in an icall.
         */
 -      if (((cmethod->klass == mono_defaults.object_class) || (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
 +      if (((cmethod->klass == mono_defaults.object_class) || mono_class_is_interface (cmethod->klass) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
                (MONO_TYPE_IS_VOID (fsig->ret) || MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_IS_REFERENCE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret) || mini_is_gsharedvt_type (fsig->ret)) &&
                (fsig->param_count == 0 || (!fsig->hasthis && fsig->param_count == 1) || (fsig->param_count == 1 && (MONO_TYPE_IS_REFERENCE (fsig->params [0]) || fsig->params [0]->byref || mini_is_gsharedvt_type (fsig->params [0]))))) {
                MonoInst *args [16];
@@@ -5352,14 -5315,9 +5352,14 @@@ mono_method_check_inlining (MonoCompil
                        vtable = mono_class_vtable (cfg->domain, method->klass);
                        if (!vtable)
                                return FALSE;
 -                      if (!cfg->compile_aot)
 -                              mono_runtime_class_init (vtable);
 -              } else if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
 +                      if (!cfg->compile_aot) {
 +                              MonoError error;
 +                              if (!mono_runtime_class_init_full (vtable, &error)) {
 +                                      mono_error_cleanup (&error);
 +                                      return FALSE;
 +                              }
 +                      }
 +              } else if (mono_class_is_before_field_init (method->klass)) {
                        if (cfg->run_cctors && method->klass->has_cctor) {
                                /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
                                if (!method->klass->runtime_info)
                                /* running with a specific order... */
                                if (! vtable->initialized)
                                        return FALSE;
 -                              mono_runtime_class_init (vtable);
 +                              MonoError error;
 +                              if (!mono_runtime_class_init_full (vtable, &error)) {
 +                                      mono_error_cleanup (&error);
 +                                      return FALSE;
 +                              }
                        }
                } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
                        if (!method->klass->runtime_info)
                 * the cctor will need to be run at aot method load time, for example,
                 * or at the end of the compilation of the inlining method.
                 */
 -              if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
 +              if (mono_class_needs_cctor_run (method->klass, NULL) && !mono_class_is_before_field_init (method->klass))
                        return FALSE;
        }
  
@@@ -5425,7 -5379,7 +5425,7 @@@ mini_field_access_needs_cctor_run (Mono
                        return FALSE;
        }
  
 -      if (klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
 +      if (mono_class_is_before_field_init (klass)) {
                if (cfg->method == method)
                        return FALSE;
        }
@@@ -5678,7 -5632,7 +5678,7 @@@ emit_array_generic_access (MonoCompile 
        if (is_set) {
                EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
                EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
 -              if (mini_type_is_reference (fsig->params [2]))
 +              if (mini_type_is_reference (&eklass->byval_arg))
                        emit_write_barrier (cfg, addr, load);
        } else {
                EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
@@@ -5698,7 -5652,7 +5698,7 @@@ static MonoInst
  emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
  {
        if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
 -              !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) {
 +              !(MONO_INS_IS_PCONST_NULL (sp [2]))) {
                MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
                MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
                MonoInst *iargs [3];
@@@ -5913,7 -5867,7 +5913,7 @@@ llvm_emit_inst_for_method (MonoCompile 
                if (opcode && fsig->param_count == 1) {
                        MONO_INST_NEW (cfg, ins, opcode);
                        ins->type = STACK_R8;
 -                      ins->dreg = mono_alloc_freg (cfg);
 +                      ins->dreg = mono_alloc_dreg (cfg, ins->type);
                        ins->sreg1 = args [0]->dreg;
                        MONO_ADD_INS (cfg->cbb, ins);
                }
                if (opcode && fsig->param_count == 2) {
                        MONO_INST_NEW (cfg, ins, opcode);
                        ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
 -                      ins->dreg = mono_alloc_ireg (cfg);
 +                      ins->dreg = mono_alloc_dreg (cfg, ins->type);
                        ins->sreg1 = args [0]->dreg;
                        ins->sreg2 = args [1]->dreg;
                        MONO_ADD_INS (cfg->cbb, ins);
@@@ -5974,7 -5928,10 +5974,7 @@@ mini_emit_inst_for_method (MonoCompile 
  {
        MonoInst *ins = NULL;
  
 -      static MonoClass *runtime_helpers_class = NULL;
 -      if (! runtime_helpers_class)
 -              runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
 -                      "System.Runtime.CompilerServices", "RuntimeHelpers");
 +       MonoClass *runtime_helpers_class = mono_class_get_runtime_helpers_class ();
  
        if (cmethod->klass == mono_defaults.string_class) {
                if (strcmp (cmethod->name, "get_Chars") == 0 && fsig->param_count + fsig->hasthis == 2) {
                } else 
                        return NULL;
        } else if (cmethod->klass == mono_defaults.object_class) {
 -
                if (strcmp (cmethod->name, "GetType") == 0 && fsig->param_count + fsig->hasthis == 1) {
                        int dreg = alloc_ireg_ref (cfg);
                        int vt_reg = alloc_preg (cfg);
                } else
                        return NULL;
        } else if (cmethod->klass == runtime_helpers_class) {
 -
                if (strcmp (cmethod->name, "get_OffsetToStringData") == 0 && fsig->param_count == 0) {
                        EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars));
                        return ins;
                } else
                        return NULL;
 +      } else if (cmethod->klass == mono_defaults.monitor_class) {
 +              gboolean is_enter = FALSE;
 +              gboolean is_v4 = FALSE;
 +
 +              if (!strcmp (cmethod->name, "Enter") && fsig->param_count == 2 && fsig->params [1]->byref) {
 +                      is_enter = TRUE;
 +                      is_v4 = TRUE;
 +              }
 +              if (!strcmp (cmethod->name, "Enter") && fsig->param_count == 1)
 +                      is_enter = TRUE;
 +
 +              if (is_enter) {
 +                      /*
 +                       * To make async stack traces work, icalls which can block should have a wrapper.
 +                       * For Monitor.Enter, emit two calls: a fastpath which doesn't have a wrapper, and a slowpath, which does.
 +                       */
 +                      MonoBasicBlock *end_bb;
 +
 +                      NEW_BBLOCK (cfg, end_bb);
 +
 +                      ins = mono_emit_jit_icall (cfg, is_v4 ? (gpointer)mono_monitor_enter_v4_fast : (gpointer)mono_monitor_enter_fast, args);
 +                      MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, ins->dreg, 0);
 +                      MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, end_bb);
 +                      ins = mono_emit_jit_icall (cfg, is_v4 ? (gpointer)mono_monitor_enter_v4 : (gpointer)mono_monitor_enter, args);
 +                      MONO_START_BB (cfg, end_bb);
 +                      return ins;
 +              }
        } else if (cmethod->klass == mono_defaults.thread_class) {
                if (strcmp (cmethod->name, "SpinWait_nop") == 0 && fsig->param_count == 0) {
                        MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
                                if (opcode == OP_LOADI8_MEMBASE)
                                        ins = mono_decompose_opcode (cfg, ins);
  
 -                              emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
 +                              emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
  
                                return ins;
                        }
                                opcode = OP_STORE_MEMBASE_REG;
  
                        if (opcode) {
 -                              emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
 +                              emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
  
                                MONO_INST_NEW (cfg, ins, opcode);
                                ins->sreg1 = args [1]->dreg;
  
                if (!cfg->llvm_only && !strcmp (cmethod->name, "Read") && fsig->param_count == 1) {
                        guint32 opcode = 0;
 -                      gboolean is_ref = mini_type_is_reference (fsig->params [0]);
 -                      gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
 -
 -                      if (fsig->params [0]->type == MONO_TYPE_I1)
 +                      MonoType *t = fsig->params [0];
 +                      gboolean is_ref;
 +                      gboolean is_float = t->type == MONO_TYPE_R4 || t->type == MONO_TYPE_R8;
 +
 +                      g_assert (t->byref);
 +                      /* t is a byref type, so the reference check is more complicated */
 +                      is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
 +                      if (t->type == MONO_TYPE_I1)
                                opcode = OP_ATOMIC_LOAD_I1;
 -                      else if (fsig->params [0]->type == MONO_TYPE_U1 || fsig->params [0]->type == MONO_TYPE_BOOLEAN)
 +                      else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
                                opcode = OP_ATOMIC_LOAD_U1;
 -                      else if (fsig->params [0]->type == MONO_TYPE_I2)
 +                      else if (t->type == MONO_TYPE_I2)
                                opcode = OP_ATOMIC_LOAD_I2;
 -                      else if (fsig->params [0]->type == MONO_TYPE_U2)
 +                      else if (t->type == MONO_TYPE_U2)
                                opcode = OP_ATOMIC_LOAD_U2;
 -                      else if (fsig->params [0]->type == MONO_TYPE_I4)
 +                      else if (t->type == MONO_TYPE_I4)
                                opcode = OP_ATOMIC_LOAD_I4;
 -                      else if (fsig->params [0]->type == MONO_TYPE_U4)
 +                      else if (t->type == MONO_TYPE_U4)
                                opcode = OP_ATOMIC_LOAD_U4;
 -                      else if (fsig->params [0]->type == MONO_TYPE_R4)
 +                      else if (t->type == MONO_TYPE_R4)
                                opcode = OP_ATOMIC_LOAD_R4;
 -                      else if (fsig->params [0]->type == MONO_TYPE_R8)
 +                      else if (t->type == MONO_TYPE_R8)
                                opcode = OP_ATOMIC_LOAD_R8;
  #if SIZEOF_REGISTER == 8
 -                      else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_I)
 +                      else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
                                opcode = OP_ATOMIC_LOAD_I8;
 -                      else if (is_ref || fsig->params [0]->type == MONO_TYPE_U8 || fsig->params [0]->type == MONO_TYPE_U)
 +                      else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
                                opcode = OP_ATOMIC_LOAD_U8;
  #else
 -                      else if (fsig->params [0]->type == MONO_TYPE_I)
 +                      else if (t->type == MONO_TYPE_I)
                                opcode = OP_ATOMIC_LOAD_I4;
 -                      else if (is_ref || fsig->params [0]->type == MONO_TYPE_U)
 +                      else if (is_ref || t->type == MONO_TYPE_U)
                                opcode = OP_ATOMIC_LOAD_U4;
  #endif
  
                                ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_ACQ;
                                MONO_ADD_INS (cfg->cbb, ins);
  
 -                              switch (fsig->params [0]->type) {
 +                              switch (t->type) {
                                case MONO_TYPE_BOOLEAN:
                                case MONO_TYPE_I1:
                                case MONO_TYPE_U1:
                                        ins->type = STACK_R8;
                                        break;
                                default:
 -                                      g_assert (mini_type_is_reference (fsig->params [0]));
 +                                      g_assert (is_ref);
                                        ins->type = STACK_OBJ;
                                        break;
                                }
  
                if (!cfg->llvm_only && !strcmp (cmethod->name, "Write") && fsig->param_count == 2) {
                        guint32 opcode = 0;
 -                      gboolean is_ref = mini_type_is_reference (fsig->params [0]);
 +                      MonoType *t = fsig->params [0];
 +                      gboolean is_ref;
  
 -                      if (fsig->params [0]->type == MONO_TYPE_I1)
 +                      g_assert (t->byref);
 +                      is_ref = mini_type_is_reference (&mono_class_from_mono_type (t)->byval_arg);
 +                      if (t->type == MONO_TYPE_I1)
                                opcode = OP_ATOMIC_STORE_I1;
 -                      else if (fsig->params [0]->type == MONO_TYPE_U1 || fsig->params [0]->type == MONO_TYPE_BOOLEAN)
 +                      else if (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_BOOLEAN)
                                opcode = OP_ATOMIC_STORE_U1;
 -                      else if (fsig->params [0]->type == MONO_TYPE_I2)
 +                      else if (t->type == MONO_TYPE_I2)
                                opcode = OP_ATOMIC_STORE_I2;
 -                      else if (fsig->params [0]->type == MONO_TYPE_U2)
 +                      else if (t->type == MONO_TYPE_U2)
                                opcode = OP_ATOMIC_STORE_U2;
 -                      else if (fsig->params [0]->type == MONO_TYPE_I4)
 +                      else if (t->type == MONO_TYPE_I4)
                                opcode = OP_ATOMIC_STORE_I4;
 -                      else if (fsig->params [0]->type == MONO_TYPE_U4)
 +                      else if (t->type == MONO_TYPE_U4)
                                opcode = OP_ATOMIC_STORE_U4;
 -                      else if (fsig->params [0]->type == MONO_TYPE_R4)
 +                      else if (t->type == MONO_TYPE_R4)
                                opcode = OP_ATOMIC_STORE_R4;
 -                      else if (fsig->params [0]->type == MONO_TYPE_R8)
 +                      else if (t->type == MONO_TYPE_R8)
                                opcode = OP_ATOMIC_STORE_R8;
  #if SIZEOF_REGISTER == 8
 -                      else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_I)
 +                      else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_I)
                                opcode = OP_ATOMIC_STORE_I8;
 -                      else if (is_ref || fsig->params [0]->type == MONO_TYPE_U8 || fsig->params [0]->type == MONO_TYPE_U)
 +                      else if (is_ref || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U)
                                opcode = OP_ATOMIC_STORE_U8;
  #else
 -                      else if (fsig->params [0]->type == MONO_TYPE_I)
 +                      else if (t->type == MONO_TYPE_I)
                                opcode = OP_ATOMIC_STORE_I4;
 -                      else if (is_ref || fsig->params [0]->type == MONO_TYPE_U)
 +                      else if (is_ref || t->type == MONO_TYPE_U)
                                opcode = OP_ATOMIC_STORE_U4;
  #endif
  
                           (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
                           (strcmp (cmethod->klass->name, "Assembly") == 0)) {
                if (cfg->llvm_only && !strcmp (cmethod->name, "GetExecutingAssembly")) {
 -                      /* No stack walks are current available, so implement this as an intrinsic */
 +                      /* No stack walks are currently available, so implement this as an intrinsic */
                        MonoInst *assembly_ins;
  
                        EMIT_NEW_AOTCONST (cfg, assembly_ins, MONO_PATCH_INFO_IMAGE, cfg->method->klass->image);
                        ins = mono_emit_jit_icall (cfg, mono_get_assembly_object, &assembly_ins);
                        return ins;
                }
 +      } else if (cmethod->klass->image == mono_defaults.corlib &&
 +                         (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
 +                         (strcmp (cmethod->klass->name, "MethodBase") == 0)) {
 +              if (cfg->llvm_only && !strcmp (cmethod->name, "GetCurrentMethod")) {
 +                      /* No stack walks are currently available, so implement this as an intrinsic */
 +                      MonoInst *method_ins;
 +                      MonoMethod *declaring = cfg->method;
 +
 +                      /* This returns the declaring generic method */
 +                      if (declaring->is_inflated)
 +                              declaring = ((MonoMethodInflated*)cfg->method)->declaring;
 +                      EMIT_NEW_AOTCONST (cfg, method_ins, MONO_PATCH_INFO_METHODCONST, declaring);
 +                      ins = mono_emit_jit_icall (cfg, mono_get_method_object, &method_ins);
 +                      cfg->no_inline = TRUE;
 +                      if (cfg->method != cfg->current_method)
 +                              inline_failure (cfg, "MethodBase:GetCurrentMethod ()");
 +                      return ins;
 +              }
        } else if (cmethod->klass == mono_defaults.math_class) {
                /* 
                 * There is general branchless code for Min/Max, but it does not work for 
                    !strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) &&
                                !strcmp (cmethod->klass->name_space, "XamCore.ObjCRuntime") &&
                                !strcmp (cmethod->klass->name, "Selector")) ||
 -                         (!strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.iOS") &&
 +                         ((!strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.iOS") ||
 +                               !strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.Mac")) &&
                                !strcmp (cmethod->klass->name_space, "ObjCRuntime") &&
                                !strcmp (cmethod->klass->name, "Selector"))
                           ) {
 -              if (cfg->backend->have_objc_get_selector &&
 +              if ((cfg->backend->have_objc_get_selector || cfg->compile_llvm) &&
                        !strcmp (cmethod->name, "GetHandle") && fsig->param_count == 1 &&
                    (args [0]->opcode == OP_GOT_ENTRY || args [0]->opcode == OP_AOTCONST) &&
                    cfg->compile_aot) {
                        MonoInst *pi;
                        MonoJumpInfoToken *ji;
 -                      MonoString *s;
 -
 -                      cfg->disable_llvm = TRUE;
 +                      char *s;
  
                        if (args [0]->opcode == OP_GOT_ENTRY) {
                                pi = (MonoInst *)args [0]->inst_p1;
  
                        NULLIFY_INS (args [0]);
  
 -                      // FIXME: Ugly
 -                      s = mono_ldstr (cfg->domain, ji->image, mono_metadata_token_index (ji->token));
 +                      s = mono_ldstr_utf8 (ji->image, mono_metadata_token_index (ji->token), &cfg->error);
 +                      return_val_if_nok (&cfg->error, NULL);
 +
                        MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
                        ins->dreg = mono_alloc_ireg (cfg);
                        // FIXME: Leaks
 -                      ins->inst_p0 = mono_string_to_utf8 (s);
 +                      ins->inst_p0 = s;
                        MONO_ADD_INS (cfg->cbb, ins);
                        return ins;
                }
@@@ -7076,13 -6983,12 +7076,13 @@@ emit_init_local (MonoCompile *cfg, int 
  /*
   * inline_method:
   *
 - *   Return the cost of inlining CMETHOD.
 + * Return the cost of inlining CMETHOD, or zero if it should not be inlined.
   */
  static int
  inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
 -                         guchar *ip, guint real_offset, gboolean inline_always)
 +             guchar *ip, guint real_offset, gboolean inline_always)
  {
 +      MonoError error;
        MonoInst *ins, *rvar = NULL;
        MonoMethodHeader *cheader;
        MonoBasicBlock *ebblock, *sbblock;
        GHashTable *prev_cbb_hash;
        MonoBasicBlock **prev_cil_offset_to_bb;
        MonoBasicBlock *prev_cbb;
 -      unsigned char* prev_cil_start;
 +      const unsigned char *prev_ip;
 +      unsigned char *prev_cil_start;
        guint32 prev_cil_offset_to_bb_len;
        MonoMethod *prev_current_method;
        MonoGenericContext *prev_generic_context;
        }
  
        /* allocate local variables */
 -      cheader = mono_method_get_header (cmethod);
 -
 -      if (cheader == NULL || mono_loader_get_last_error ()) {
 -              MonoLoaderError *error = mono_loader_get_last_error ();
 -
 -              if (cheader)
 -                      mono_metadata_free_mh (cheader);
 -              if (inline_always && error)
 -                      mono_cfg_set_exception (cfg, error->exception_type);
 -
 -              mono_loader_clear_error ();
 +      cheader = mono_method_get_header_checked (cmethod, &error);
 +      if (!cheader) {
 +              if (inline_always) {
 +                      mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
 +                      mono_error_move (&cfg->error, &error);
 +              } else {
 +                      mono_error_cleanup (&error);
 +              }
                return 0;
        }
  
        prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
        prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
        prev_cil_start = cfg->cil_start;
 +      prev_ip = cfg->ip;
        prev_cbb = cfg->cbb;
        prev_current_method = cfg->current_method;
        prev_generic_context = cfg->generic_context;
        cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
        cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
        cfg->cil_start = prev_cil_start;
 +      cfg->ip = prev_ip;
        cfg->locals = prev_locals;
        cfg->args = prev_args;
        cfg->arg_types = prev_arg_types;
  
                if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
                        MonoBasicBlock *prev = ebblock->in_bb [0];
 -                      mono_merge_basic_blocks (cfg, prev, ebblock);
 -                      cfg->cbb = prev;
 -                      if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
 -                              mono_merge_basic_blocks (cfg, prev_cbb, prev);
 -                              cfg->cbb = prev_cbb;
 +
 +                      if (prev->next_bb == ebblock) {
 +                              mono_merge_basic_blocks (cfg, prev, ebblock);
 +                              cfg->cbb = prev;
 +                              if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
 +                                      mono_merge_basic_blocks (cfg, prev_cbb, prev);
 +                                      cfg->cbb = prev_cbb;
 +                              }
 +                      } else {
 +                              /* There could be a bblock after 'prev', and making 'prev' the current bb could cause problems */
 +                              cfg->cbb = ebblock;
                        }
                } else {
                        /* 
                if (cfg->verbose_level > 2)
                        printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
                cfg->exception_type = MONO_EXCEPTION_NONE;
 -              mono_loader_clear_error ();
  
                /* This gets rid of the newly added bblocks */
                cfg->cbb = prev_cbb;
  #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
  #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
  #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
 -#define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) TYPE_LOAD_ERROR ((klass))
 +#define CHECK_TYPELOAD(klass) if (!(klass) || mono_class_has_failure (klass)) TYPE_LOAD_ERROR ((klass))
  
  /* offset from br.s -> br like opcodes */
  #define BIG_BRANCH_OFFSET 13
@@@ -7422,19 -7323,19 +7422,19 @@@ exception_exit
  }
  
  static inline MonoMethod *
 -mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
 +mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context, MonoError *error)
  {
        MonoMethod *method;
  
 +      mono_error_init (error);
 +
        if (m->wrapper_type != MONO_WRAPPER_NONE) {
                method = (MonoMethod *)mono_method_get_wrapper_data (m, token);
                if (context) {
 -                      MonoError error;
 -                      method = mono_class_inflate_generic_method_checked (method, context, &error);
 -                      g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
 +                      method = mono_class_inflate_generic_method_checked (method, context, error);
                }
        } else {
 -              method = mono_get_method_full (m->klass->image, token, klass, context);
 +              method = mono_get_method_checked (m->klass->image, token, klass, context, error);
        }
  
        return method;
  static inline MonoMethod *
  mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
  {
 -      MonoMethod *method = mini_get_method_allow_open (m, token, klass, context);
 +      MonoError error;
 +      MonoMethod *method = mini_get_method_allow_open (m, token, klass, context, cfg ? &cfg->error : &error);
  
 -      if (method && cfg && !cfg->gshared && mono_class_is_open_constructed_type (&method->klass->byval_arg))
 -              return NULL;
 +      if (method && cfg && !cfg->gshared && mono_class_is_open_constructed_type (&method->klass->byval_arg)) {
 +              mono_error_set_bad_image (&cfg->error, cfg->method->klass->image, "Method with open type while not compiling gshared");
 +              method = NULL;
 +      }
 +
 +      if (!method && !cfg)
 +              mono_error_cleanup (&error); /* FIXME don't swallow the error */
  
        return method;
  }
@@@ -7465,10 -7360,8 +7465,10 @@@ mini_get_class (MonoMethod *method, gui
  
        if (method->wrapper_type != MONO_WRAPPER_NONE) {
                klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
 -              if (context)
 -                      klass = mono_class_inflate_generic_class (klass, context);
 +              if (context) {
 +                      klass = mono_class_inflate_generic_class_checked (klass, context, &error);
 +                      mono_error_cleanup (&error); /* FIXME don't swallow the error */
 +              }
        } else {
                klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
                mono_error_cleanup (&error); /* FIXME don't swallow the error */
  }
  
  static inline MonoMethodSignature*
 -mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context)
 +mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context, MonoError *error)
  {
        MonoMethodSignature *fsig;
  
 +      mono_error_init (error);
        if (method->wrapper_type != MONO_WRAPPER_NONE) {
                fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
        } else {
 -              fsig = mono_metadata_parse_signature (method->klass->image, token);
 +              fsig = mono_metadata_parse_signature_checked (method->klass->image, token, error);
 +              return_val_if_nok (error, NULL);
        }
        if (context) {
 -              MonoError error;
 -              fsig = mono_inflate_generic_signature(fsig, context, &error);
 -              // FIXME:
 -              g_assert(mono_error_ok(&error));
 +              fsig = mono_inflate_generic_signature(fsig, context, error);
        }
        return fsig;
  }
@@@ -7642,24 -7536,29 +7642,24 @@@ initialize_array_data (MonoMethod *meth
  static void
  set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
  {
 +      MonoError error;
        char *method_fname = mono_method_full_name (method, TRUE);
        char *method_code;
 -      MonoMethodHeader *header = mono_method_get_header (method);
 +      MonoMethodHeader *header = mono_method_get_header_checked (method, &error);
  
 -      if (header->code_size == 0)
 +      if (!header) {
 +              method_code = g_strdup_printf ("could not parse method body due to %s", mono_error_get_message (&error));
 +              mono_error_cleanup (&error);
 +      } else if (header->code_size == 0)
                method_code = g_strdup ("method body is empty.");
        else
                method_code = mono_disasm_code_one (NULL, method, ip, NULL);
 -      mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
 -      cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
 +      mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code));
        g_free (method_fname);
        g_free (method_code);
        cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
  }
  
 -static void
 -set_exception_object (MonoCompile *cfg, MonoException *exception)
 -{
 -      mono_cfg_set_exception (cfg, MONO_EXCEPTION_OBJECT_SUPPLIED);
 -      MONO_GC_REGISTER_ROOT_SINGLE (cfg->exception_ptr, MONO_ROOT_SOURCE_JIT, "jit exception");
 -      cfg->exception_ptr = exception;
 -}
 -
  static void
  emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
  {
@@@ -7716,9 -7615,8 +7716,9 @@@ emit_llvmonly_virtual_call (MonoCompil
        MonoInst *icall_args [16];
        MonoInst *call_target, *ins, *vtable_ins;
        int arg_reg, this_reg, vtable_reg;
 -      gboolean is_iface = cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE;
 +      gboolean is_iface = mono_class_is_interface (cmethod->klass);
        gboolean is_gsharedvt = cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig);
 +      gboolean variant_iface = FALSE;
        guint32 slot;
        int offset;
  
  
        this_reg = sp [0]->dreg;
  
 +      if (is_iface && mono_class_has_variant_generic_params (cmethod->klass))
 +              variant_iface = TRUE;
 +
        if (!fsig->generic_param_count && !is_iface && !is_gsharedvt) {
                /*
                 * The simplest case, a normal virtual call.
                return emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
        }
  
 -      if (!fsig->generic_param_count && is_iface && !is_gsharedvt) {
 +      if (!fsig->generic_param_count && is_iface && !variant_iface && !is_gsharedvt) {
                /*
                 * A simple interface call
                 *
                icall_args [0] = thunk_arg_ins;
                icall_args [1] = emit_get_rgctx_method (cfg, context_used,
                                                                                                cmethod, MONO_RGCTX_INFO_METHOD);
 -              ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_thunk, icall_args, thunk_addr_ins, NULL, NULL);
 +              ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_trampoline, icall_args, thunk_addr_ins, NULL, NULL);
  
                return emit_llvmonly_calli (cfg, fsig, sp, ftndesc_ins);
        }
  
 -      if (fsig->generic_param_count && !is_gsharedvt) {
 +      if ((fsig->generic_param_count || variant_iface) && !is_gsharedvt) {
                /*
                 * This is similar to the interface case, the vtable slot points to an imt thunk which is
                 * dynamically extended as more instantiations are discovered.
                icall_args [0] = thunk_arg_ins;
                icall_args [1] = emit_get_rgctx_method (cfg, context_used,
                                                                                                cmethod, MONO_RGCTX_INFO_METHOD);
 -              ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_thunk, icall_args, thunk_addr_ins, NULL, NULL);
 +              ftndesc_ins = mono_emit_calli (cfg, helper_sig_llvmonly_imt_trampoline, icall_args, thunk_addr_ins, NULL, NULL);
                ftndesc_ins->dreg = ftndesc_reg;
                /*
                 * Unlike normal iface calls, these imt thunks can return NULL, i.e. when they are passed an instantiation
@@@ -7931,10 -7826,9 +7931,10 @@@ is_exception_class (MonoClass *klass
  static gboolean
  is_jit_optimizer_disabled (MonoMethod *m)
  {
 +      MonoError error;
        MonoAssembly *ass = m->klass->image->assembly;
        MonoCustomAttrInfo* attrs;
 -      static MonoClass *klass;
 +      MonoClass *klass;
        int i;
        gboolean val = FALSE;
  
        if (ass->jit_optimizer_disabled_inited)
                return ass->jit_optimizer_disabled;
  
 -      if (!klass)
 -              klass = mono_class_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggableAttribute");
 +      klass = mono_class_try_get_debuggable_attribute_class ();
 +
        if (!klass) {
                /* Linked away */
                ass->jit_optimizer_disabled = FALSE;
                return FALSE;
        }
  
 -      attrs = mono_custom_attrs_from_assembly (ass);
 +      attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, &error);
 +      mono_error_cleanup (&error); /* FIXME don't swallow the error */
        if (attrs) {
                for (i = 0; i < attrs->num_attrs; ++i) {
                        MonoCustomAttrEntry *attr = &attrs->attrs [i];
@@@ -8151,22 -8044,7 +8151,22 @@@ emit_setret (MonoCompile *cfg, MonoIns
  /*
   * mono_method_to_ir:
   *
 - *   Translate the .net IL into linear IR.
 + * Translate the .net IL into linear IR.
 + *
 + * @start_bblock: if not NULL, the starting basic block, used during inlining.
 + * @end_bblock: if not NULL, the ending basic block, used during inlining.
 + * @return_var: if not NULL, the place where the return value is stored, used during inlining.   
 + * @inline_args: if not NULL, contains the arguments to the inline call
 + * @inline_offset: if not zero, the real offset from the inline call, or zero otherwise.
 + * @is_virtual_call: whether this method is being called as a result of a call to callvirt
 + *
 + * This method is used to turn ECMA IL into Mono's internal Linear IR
 + * reprensetation.  It is used both for entire methods, as well as
 + * inlining existing methods.  In the former case, the @start_bblock,
 + * @end_bblock, @return_var, @inline_args are all set to NULL, and the
 + * inline_offset is set to zero.
 + * 
 + * Returns: the inline cost, or -1 if there was an error processing this method.
   */
  int
  mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
        dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
  
        image = method->klass->image;
 -      header = mono_method_get_header (method);
 +      header = mono_method_get_header_checked (method, &cfg->error);
        if (!header) {
 -              MonoLoaderError *error;
 -
 -              if ((error = mono_loader_get_last_error ())) {
 -                      mono_cfg_set_exception (cfg, error->exception_type);
 -              } else {
 -                      mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
 -                      cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
 -              }
 +              mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
                goto exception_exit;
 +      } else {
 +              cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
        }
 +
        generic_container = mono_method_get_generic_container (method);
        sig = mono_method_signature (method);
        num_args = sig->hasthis + sig->param_count;
  
        /* we use a separate basic block for the initialization code */
        NEW_BBLOCK (cfg, init_localsbb);
 -      cfg->bb_init = init_localsbb;
 +      if (cfg->method == method)
 +              cfg->bb_init = init_localsbb;
        init_localsbb->real_offset = cfg->real_offset;
        start_bblock->next_bb = init_localsbb;
        init_localsbb->next_bb = cfg->cbb;
  
        skip_dead_blocks = !dont_verify;
        if (skip_dead_blocks) {
 -              original_bb = bb = mono_basic_block_split (method, &cfg->error);
 +              original_bb = bb = mono_basic_block_split (method, &cfg->error, header);
                CHECK_CFG_ERROR;
                g_assert (bb);
        }
                        token = read32 (ip + 1);
                        /* FIXME: check the signature matches */
                        cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
 -
 -                      if (!cmethod || mono_loader_get_last_error ())
 -                              LOAD_ERROR;
 +                      CHECK_CFG_ERROR;
   
                        if (cfg->gshared && mono_method_check_context_used (cmethod))
                                GENERIC_SHARING_FAILURE (CEE_JMP);
                                for (i = 0; i < n; ++i)
                                        EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
  
 +                              if (mini_type_is_vtype (mini_get_underlying_type (call->signature->ret)))
 +                                      call->vret_var = cfg->vret_addr;
 +
                                mono_arch_emit_call (cfg, call);
                                cfg->param_area = MAX(cfg->param_area, call->stack_usage);
                                MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
                        CHECK_STACK (1);
                        --sp;
                        addr = *sp;
 -                      fsig = mini_get_signature (method, token, generic_context);
 +                      fsig = mini_get_signature (method, token, generic_context, &cfg->error);
 +                      CHECK_CFG_ERROR;
  
                        if (method->dynamic && fsig->pinvoke) {
                                MonoInst *args [3];
                                        info_data = addr->inst_right->inst_left;
                                }
  
 -                              if (info_type == MONO_PATCH_INFO_ICALL_ADDR || info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
 +                              if (info_type == MONO_PATCH_INFO_ICALL_ADDR) {
 +                                      ins = (MonoInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_ICALL_ADDR_CALL, info_data, fsig, sp);
 +                                      NULLIFY_INS (addr);
 +                                      goto calli_end;
 +                              } else if (info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
                                        ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
                                        NULLIFY_INS (addr);
                                        goto calli_end;
                        ins = NULL;
  
                        cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
 +                      CHECK_CFG_ERROR;
 +
                        cil_method = cmethod;
                                
                        if (constrained_class) {
                                }
                        }
                                        
 -                      if (!cmethod || mono_loader_get_last_error ())
 -                              LOAD_ERROR;
                        if (!dont_verify && !cfg->skip_visibility) {
                                MonoMethod *target_method = cil_method;
                                if (method->is_inflated) {
 -                                      target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context));
 +                                      target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context), &cfg->error);
 +                                      CHECK_CFG_ERROR;
                                }
                                if (!mono_method_can_access_method (method_definition, target_method) &&
                                        !mono_method_can_access_method (method, cil_method))
 -                                      METHOD_ACCESS_FAILURE (method, cil_method);
 +                                      emit_method_access_failure (cfg, method, cil_method);
                        }
  
                        if (mono_security_core_clr_enabled ())
                                CHECK_CFG_ERROR;
                        }
  
 -                      if (cfg->llvm_only && !cfg->method->wrapper_type)
 +                      if (cfg->llvm_only && !cfg->method->wrapper_type && (!cmethod || cmethod->is_inflated))
                                cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
  
                        /* See code below */
  
                        n = fsig->param_count + fsig->hasthis;
  
 -                      if (!cfg->gshared && cmethod->klass->generic_container)
 +                      if (!cfg->gshared && mono_class_is_gtd (cmethod->klass))
                                UNVERIFIED;
  
                        if (!cfg->gshared)
                                if (mini_is_gsharedvt_klass (constrained_class)) {
                                        if ((cmethod->klass != mono_defaults.object_class) && constrained_class->valuetype && cmethod->klass->valuetype) {
                                                /* The 'Own method' case below */
 -                                      } else if (cmethod->klass->image != mono_defaults.corlib && !(cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !cmethod->klass->valuetype) {
 +                                      } else if (cmethod->klass->image != mono_defaults.corlib && !mono_class_is_interface (cmethod->klass) && !cmethod->klass->valuetype) {
                                                /* 'The type parameter is instantiated as a reference type' case below. */
                                        } else {
                                                ins = handle_constrained_gsharedvt_call (cfg, cmethod, fsig, sp, constrained_class, &emit_widen);
                                         * A simple solution would be to box always and make a normal virtual call, but that would
                                         * be bad performance wise.
                                         */
 -                                      if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE && cmethod->klass->generic_class) {
 +                                      if (mono_class_is_interface (cmethod->klass) && mono_class_is_ginst (cmethod->klass)) {
                                                /*
                                                 * The parent classes implement no generic interfaces, so the called method will be a vtype method, so no boxing neccessary.
                                                 */
                                                nonbox_call->dreg = ins->dreg;
                                                goto call_end;
                                        } else {
 -                                              g_assert (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
 +                                              g_assert (mono_class_is_interface (cmethod->klass));
                                                addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
                                                ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
                                                goto call_end;
                         * If the callee is a shared method, then its static cctor
                         * might not get called after the call was patched.
                         */
 -                      if (cfg->gshared && cmethod->klass != method->klass && cmethod->klass->generic_class && mono_method_is_generic_sharable (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) {
 +                      if (cfg->gshared && cmethod->klass != method->klass && mono_class_is_ginst (cmethod->klass) && mono_method_is_generic_sharable (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) {
                                emit_class_init (cfg, cmethod->klass);
                                CHECK_TYPELOAD (cmethod->klass);
                        }
  
                                context_used = mini_method_check_context_used (cfg, cmethod);
  
 -                              if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
 +                              if (context_used && mono_class_is_interface (cmethod->klass)) {
                                        /* Generic method interface
                                           calls are resolved via a
                                           helper function and don't
                                if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
                                        GSHAREDVT_FAILURE (*ip);
  
 -                              if (cfg->backend->have_generalized_imt_thunk && cfg->backend->gshared_supported && cmethod->wrapper_type == MONO_WRAPPER_NONE) {
 +                              if (cfg->backend->have_generalized_imt_trampoline && cfg->backend->gshared_supported && cmethod->wrapper_type == MONO_WRAPPER_NONE) {
                                        g_assert (!imt_arg);
                                        if (!context_used)
                                                g_assert (cmethod->is_inflated);
                                }
                                goto call_end;
                        }
 -
 +                      CHECK_CFG_ERROR;
 +                      
                        /* Inlining */
                        if ((cfg->opt & MONO_OPT_INLINE) &&
                                (!virtual_ || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
                                }
  
                                if (!has_vtargs) {
 +                                      if (need_seq_point) {
 +                                              emit_seq_point (cfg, method, ip, FALSE, TRUE);
 +                                              need_seq_point = FALSE;
 +                                      }
                                        for (i = 0; i < n; ++i)
                                                EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
                                        MONO_INST_NEW (cfg, ins, OP_BR);
  
                        inline_costs += 10 * num_calls++;
  
 +                      /*
 +                       * Synchronized wrappers.
 +                       * Its hard to determine where to replace a method with its synchronized
 +                       * wrapper without causing an infinite recursion. The current solution is
 +                       * to add the synchronized wrapper in the trampolines, and to
 +                       * change the called method to a dummy wrapper, and resolve that wrapper
 +                       * to the real method in mono_jit_compile_method ().
 +                       */
 +                      if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
 +                              MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
 +                              if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
 +                                      cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
 +                      }
 +
                        /*
                         * Making generic calls out of gsharedvt methods.
                         * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
                         * patching gshared method addresses into a gsharedvt method.
                         */
 -                      if (cfg->gsharedvt && (mini_is_gsharedvt_signature (fsig) || cmethod->is_inflated || cmethod->klass->generic_class) &&
 +                      if (cfg->gsharedvt && (mini_is_gsharedvt_signature (fsig) || cmethod->is_inflated || mono_class_is_ginst (cmethod->klass)) &&
                                !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY) &&
 -                              (!(cfg->llvm_only && virtual_))) {
 +                              (!(cfg->llvm_only && virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)))) {
                                MonoRgctxInfoType info_type;
  
                                if (virtual_) {
 -                                      //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
 +                                      //if (mono_class_is_interface (cmethod->klass))
                                                //GSHAREDVT_FAILURE (*ip);
                                        // disable for possible remoting calls
                                        if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
                                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
                                                /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
                                                vtable_arg = NULL;
 -                                      } else if ((cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !imt_arg) {
 +                                      } else if (mono_class_is_interface (cmethod->klass) && !imt_arg) {
                                                /* This can happen when we call a fully instantiated iface method */
                                                imt_arg = emit_get_rgctx_method (cfg, context_used,
                                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD);
                                if (fsig->hasthis)
                                        MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
  
 -                              addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
                                if (cfg->llvm_only) {
 +                                      if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig))
 +                                              addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER);
 +                                      else
 +                                              addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
                                        // FIXME: Avoid initializing imt_arg/vtable_arg
                                        ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
                                } else {
 +                                      addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
                                        ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
                                }
                                goto call_end;
                                        
                                        addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
                                        EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
 -                                      if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0))
 +                                      if (cfg->gen_write_barriers && val->type == STACK_OBJ && !MONO_INS_IS_PCONST_NULL (val))
                                                emit_write_barrier (cfg, addr, val);
                                        if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cmethod->klass))
                                                GSHAREDVT_FAILURE (*ip);
                                }
                        }
  
 -                      /* 
 -                       * Synchronized wrappers.
 -                       * Its hard to determine where to replace a method with its synchronized
 -                       * wrapper without causing an infinite recursion. The current solution is
 -                       * to add the synchronized wrapper in the trampolines, and to
 -                       * change the called method to a dummy wrapper, and resolve that wrapper
 -                       * to the real method in mono_jit_compile_method ().
 -                       */
 -                      if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
 -                              MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
 -                              if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
 -                                      cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
 -                      }
 -
                        /*
                         * Virtual calls in llvm-only mode.
                         */
                                EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
                        }
  
 +                      if (cfg->llvm_only && cmethod && method_needs_stack_walk (cfg, cmethod)) {
 +                              /*
 +                               * Clang can convert these calls to tail calls which screw up the stack
 +                               * walk. This happens even when the -fno-optimize-sibling-calls
 +                               * option is passed to clang.
 +                               * Work around this by emitting a dummy call.
 +                               */
 +                              mono_emit_jit_icall (cfg, mono_dummy_jit_icall, NULL);
 +                      }
 +
                        CHECK_CFG_EXCEPTION;
  
                        ip += 5;
  
                        MONO_ADD_INS (cfg->cbb, ins);
  
 -                      if (cfg->gen_write_barriers && *ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER && !((sp [1]->opcode == OP_PCONST) && (sp [1]->inst_p0 == 0)))
 +                      if (cfg->gen_write_barriers && *ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER && !MONO_INS_IS_PCONST_NULL (sp [1]))
                                emit_write_barrier (cfg, sp [0], sp [1]);
  
                        inline_costs += 1;
  
                        /* Use the immediate opcodes if possible */
                        if (((sp [1]->opcode == OP_ICONST) || (sp [1]->opcode == OP_I8CONST)) && mono_arch_is_inst_imm (sp [1]->opcode == OP_ICONST ? sp [1]->inst_c0 : sp [1]->inst_l)) {
 -                              int imm_opcode;
 -
 -                              imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
 -#if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
 -                              /* Keep emulated opcodes which are optimized away later */
 -                              if ((ins->opcode == OP_IREM_UN || ins->opcode == OP_IDIV_UN_IMM) && (cfg->opt & (MONO_OPT_CONSPROP | MONO_OPT_COPYPROP)) && sp [1]->opcode == OP_ICONST && mono_is_power_of_two (sp [1]->inst_c0) >= 0) {
 -                                      imm_opcode = mono_op_to_op_imm (ins->opcode);
 -                              }
 -#endif
 +                              int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
                                if (imm_opcode != -1) {
                                        ins->opcode = imm_opcode;
                                        if (sp [1]->opcode == OP_I8CONST) {
                                        EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
                                        EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
                                        EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
 -                                      *sp = mono_emit_jit_icall (cfg, mono_ldstr, iargs);
 -                                      mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
 +                                      *sp = mono_emit_jit_icall (cfg, ves_icall_mono_ldstr, iargs);
 +                                      mono_ldstr_checked (cfg->domain, image, mono_metadata_token_index (n), &cfg->error);
 +                                      CHECK_CFG_ERROR;
                                } else {
                                        if (cfg->cbb->out_of_line) {
                                                MonoInst *iargs [2];
                                        else {
                                                NEW_PCONST (cfg, ins, NULL);
                                                ins->type = STACK_OBJ;
 -                                              ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
 +                                              ins->inst_p0 = mono_ldstr_checked (cfg->domain, image, mono_metadata_token_index (n), &cfg->error);
 +                                              CHECK_CFG_ERROR;
 +                                              
                                                if (!ins->inst_p0)
                                                        OUT_OF_MEMORY_FAILURE;
  
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
                        cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
 -                      if (!cmethod || mono_loader_get_last_error ())
 -                              LOAD_ERROR;
 +                      CHECK_CFG_ERROR;
 +
                        fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
                        CHECK_CFG_ERROR;
  
                        if (mono_security_core_clr_enabled ())
                                ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
  
 -                      if (cfg->gshared && cmethod && cmethod->klass != method->klass && cmethod->klass->generic_class && mono_method_is_generic_sharable (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) {
 +                      if (cfg->gshared && cmethod && cmethod->klass != method->klass && mono_class_is_ginst (cmethod->klass) && mono_method_is_generic_sharable (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) {
                                emit_class_init (cfg, cmethod->klass);
                                CHECK_TYPELOAD (cmethod->klass);
                        }
                        break;
                }
                case CEE_CASTCLASS:
 -                      CHECK_STACK (1);
 -                      --sp;
 -                      CHECK_OPSIZE (5);
 -                      token = read32 (ip + 1);
 -                      klass = mini_get_class (method, token, generic_context);
 -                      CHECK_TYPELOAD (klass);
 -                      if (sp [0]->type != STACK_OBJ)
 -                              UNVERIFIED;
 -
 -                      ins = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
 -                      CHECK_CFG_EXCEPTION;
 -
 -                      *sp ++ = ins;
 -                      ip += 5;
 -                      break;
                case CEE_ISINST: {
                        CHECK_STACK (1);
                        --sp;
                        CHECK_TYPELOAD (klass);
                        if (sp [0]->type != STACK_OBJ)
                                UNVERIFIED;
 - 
 -                      context_used = mini_class_check_context_used (cfg, klass);
 -
 -                      if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
 -                              MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
 -                              MonoInst *args [3];
 -                              int idx;
 -
 -                              /* obj */
 -                              args [0] = *sp;
  
 -                              /* klass */
 -                              EMIT_NEW_CLASSCONST (cfg, args [1], klass);
 -
 -                              /* inline cache*/
 -                              idx = get_castclass_cache_idx (cfg);
 -                              args [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
 -
 -                              *sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL);
 -                              ip += 5;
 -                              inline_costs += 2;
 -                      } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
 -                              MonoMethod *mono_isinst;
 -                              MonoInst *iargs [1];
 -                              int costs;
 -
 -                              mono_isinst = mono_marshal_get_isinst (klass); 
 -                              iargs [0] = sp [0];
 -
 -                              costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), 
 -                                                                         iargs, ip, cfg->real_offset, TRUE);
 -                              CHECK_CFG_EXCEPTION;
 -                              g_assert (costs > 0);
 -                              
 -                              ip += 5;
 -                              cfg->real_offset += 5;
 +                      MONO_INST_NEW (cfg, ins, *ip == CEE_ISINST ? OP_ISINST : OP_CASTCLASS);
 +                      ins->dreg = alloc_preg (cfg);
 +                      ins->sreg1 = (*sp)->dreg;
 +                      ins->klass = klass;
 +                      ins->type = STACK_OBJ;
 +                      MONO_ADD_INS (cfg->cbb, ins);
  
 -                              *sp++= iargs [0];
 +                      CHECK_CFG_EXCEPTION;
 +                      *sp++ = ins;
 +                      ip += 5;
  
 -                              inline_costs += costs;
 -                      }
 -                      else {
 -                              ins = handle_isinst (cfg, klass, *sp, context_used);
 -                              CHECK_CFG_EXCEPTION;
 -                              *sp ++ = ins;
 -                              ip += 5;
 -                      }
 +                      cfg->flags |= MONO_CFG_HAS_TYPE_CHECK;
                        break;
                }
                case CEE_UNBOX_ANY: {
                                res = handle_unbox_gsharedvt (cfg, klass, *sp);
                                inline_costs += 2;
                        } else if (generic_class_is_reference_type (cfg, klass)) {
 -                              res = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
 -                              CHECK_CFG_EXCEPTION;
 +                              if (MONO_INS_IS_PCONST_NULL (*sp)) {
 +                                      EMIT_NEW_PCONST (cfg, res, NULL);
 +                                      res->type = STACK_OBJ;
 +                              } else {
 +                                      MONO_INST_NEW (cfg, res, OP_CASTCLASS);
 +                                      res->dreg = alloc_preg (cfg);
 +                                      res->sreg1 = (*sp)->dreg;
 +                                      res->klass = klass;
 +                                      res->type = STACK_OBJ;
 +                                      MONO_ADD_INS (cfg->cbb, res);
 +                                      cfg->flags |= MONO_CFG_HAS_TYPE_CHECK;
 +                              }
                        } else if (mono_class_is_nullable (klass)) {
                                res = handle_unbox_nullable (cfg, *sp, klass, context_used);
                        } else {
                                } else
  #endif
                                {
 -                                      MonoInst *store;
 +                                      MonoInst *store, *wbarrier_ptr_ins = NULL;
  
                                        MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
  
 +                                      if (ins_flag & MONO_INST_VOLATILE) {
 +                                              /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
 +                                              emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
 +                                      }
 +
                                        if (mini_is_gsharedvt_klass (klass)) {
                                                MonoInst *offset_ins;
  
                                                EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
                                                dreg = alloc_ireg_mp (cfg);
                                                EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
 +                                              wbarrier_ptr_ins = ins;
                                                /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
                                                EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
                                        } else {
                                        if (sp [0]->opcode != OP_LDADDR)
                                                store->flags |= MONO_INST_FAULT;
  
 -                              if (cfg->gen_write_barriers && mini_type_to_stind (cfg, field->type) == CEE_STIND_REF && !(sp [1]->opcode == OP_PCONST && sp [1]->inst_c0 == 0)) {
 -                                      /* insert call to write barrier */
 -                                      MonoInst *ptr;
 -                                      int dreg;
 +                                      if (cfg->gen_write_barriers && mini_type_to_stind (cfg, field->type) == CEE_STIND_REF && !MONO_INS_IS_PCONST_NULL (sp [1])) {
 +                                              if (mini_is_gsharedvt_klass (klass)) {
 +                                                      g_assert (wbarrier_ptr_ins);
 +                                                      emit_write_barrier (cfg, wbarrier_ptr_ins, sp [1]);
 +                                              } else {
 +                                                      /* insert call to write barrier */
 +                                                      MonoInst *ptr;
 +                                                      int dreg;
  
 -                                      dreg = alloc_ireg_mp (cfg);
 -                                      EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
 -                                      emit_write_barrier (cfg, ptr, sp [1]);
 -                              }
 +                                                      dreg = alloc_ireg_mp (cfg);
 +                                                      EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
 +                                                      emit_write_barrier (cfg, ptr, sp [1]);
 +                                              }
 +                                      }
  
                                        store->flags |= ins_flag;
                                }
                        /* STATIC CASE */
                        context_used = mini_class_check_context_used (cfg, klass);
  
 -                      if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL)
 -                              UNVERIFIED;
 +                      if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL) {
 +                              mono_error_set_field_load (&cfg->error, field->parent, field->name, "Using static instructions with literal field");
 +                              CHECK_CFG_ERROR;
 +                      }
  
                        /* The special_static_fields field is init'd in mono_class_vtable, so it needs
                         * to be called here.
                                                }
                                        } else {
                                                if (cfg->run_cctors) {
 -                                                      MonoException *ex;
                                                        /* This makes so that inline cannot trigger */
                                                        /* .cctors: too many apps depend on them */
                                                        /* running with a specific order... */
                                                        g_assert (vtable);
                                                        if (! vtable->initialized)
                                                                INLINE_FAILURE ("class init");
 -                                                      ex = mono_runtime_class_init_full (vtable, FALSE);
 -                                                      if (ex) {
 -                                                              set_exception_object (cfg, ex);
 +                                                      if (!mono_runtime_class_init_full (vtable, &cfg->error)) {
 +                                                              mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
                                                                goto exception_exit;
                                                        }
                                                }
                        EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
                        ins->flags |= ins_flag;
                        if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
 -                                      generic_class_is_reference_type (cfg, klass)) {
 +                              generic_class_is_reference_type (cfg, klass) && !MONO_INS_IS_PCONST_NULL (sp [1])) {
                                /* insert call to write barrier */
                                emit_write_barrier (cfg, sp [0], sp [1]);
                        }
                                if (managed_alloc)
                                        ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
                                else
 -                                      ins = mono_emit_jit_icall (cfg, mono_array_new_specific, args);
 +                                      ins = mono_emit_jit_icall (cfg, ves_icall_array_new_specific, args);
                        } else {
                                if (cfg->opt & MONO_OPT_SHARED) {
                                        /* Decompose now to avoid problems with references to the domainvar */
                                        EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
                                        iargs [2] = sp [0];
  
 -                                      ins = mono_emit_jit_icall (cfg, mono_array_new, iargs);
 +                                      ins = mono_emit_jit_icall (cfg, ves_icall_array_new, iargs);
                                } else {
                                        /* Decompose later since it is needed by abcrem */
                                        MonoClass *array_type = mono_array_class_get (klass, 1);
                                MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
                                MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
                                MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
 -                      } else if (cfg->compile_aot) {
 +                      } else {
                                int const_reg = alloc_preg (cfg);
                                int type_reg = alloc_preg (cfg);
  
                                MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
                                MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
                                MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
 -                      } else {
 -                              MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
 -                              MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), klass);
                        }
                        MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
  
                                                        EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
                                                }
                                        } else {
 -                                              EMIT_NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, (MonoType *)handle));
 +                                              MonoReflectionType *rt = mono_type_get_object_checked (cfg->domain, (MonoType *)handle, &cfg->error);
 +                                              CHECK_CFG_ERROR;
 +                                              EMIT_NEW_PCONST (cfg, ins, rt);
                                        }
                                        ins->type = STACK_OBJ;
                                        ins->klass = cmethod->klass;
                }
                case CEE_THROW:
                        CHECK_STACK (1);
 +                      if (sp [-1]->type != STACK_OBJ)
 +                              UNVERIFIED;
 +
                        MONO_INST_NEW (cfg, ins, OP_THROW);
                        --sp;
                        ins->sreg1 = sp [0]->dreg;
                                INLINE_FAILURE ("throw");
                        break;
                case CEE_ENDFINALLY:
 +                      if (!ip_in_finally_clause (cfg, ip - header->code))
 +                              UNVERIFIED;
                        /* mono_save_seq_point_info () depends on this */
                        if (sp != stack_start)
                                emit_seq_point (cfg, method, ip, FALSE, FALSE);
                                MONO_ADD_INS (cfg->cbb, iargs [0]);
                                NEW_CLASSCONST (cfg, iargs [1], klass);
                                MONO_ADD_INS (cfg->cbb, iargs [1]);
 -                              *sp++ = mono_emit_jit_icall (cfg, mono_object_new, iargs);
 +                              *sp++ = mono_emit_jit_icall (cfg, ves_icall_object_new, iargs);
                                ip += 6;
                                inline_costs += 10 * num_calls++;
                                break;
                                ip += 6;
                                break;
                        }
 +                      case CEE_MONO_ATOMIC_STORE_I4: {
 +                              g_assert (mono_arch_opcode_supported (OP_ATOMIC_STORE_I4));
 +
 +                              CHECK_OPSIZE (6);
 +                              CHECK_STACK (2);
 +                              sp -= 2;
 +
 +                              MONO_INST_NEW (cfg, ins, OP_ATOMIC_STORE_I4);
 +                              ins->dreg = sp [0]->dreg;
 +                              ins->sreg1 = sp [1]->dreg;
 +                              ins->backend.memory_barrier_kind = (int) read32 (ip + 2);
 +                              MONO_ADD_INS (cfg->cbb, ins);
 +
 +                              ip += 6;
 +                              break;
 +                      }
                        case CEE_MONO_JIT_ATTACH: {
                                MonoInst *args [16], *domain_ins;
                                MonoInst *ad_ins, *jit_tls_ins;
                                MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
  
 +                              g_assert (!mono_threads_is_coop_enabled ());
 +
                                cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
  
                                EMIT_NEW_PCONST (cfg, ins, NULL);
                                        MONO_START_BB (cfg, call_bb);
                                }
  
 -                              if (cfg->compile_aot) {
 -                                      /* AOT code is only used in the root domain */
 -                                      EMIT_NEW_PCONST (cfg, args [0], NULL);
 -                              } else {
 -                                      EMIT_NEW_PCONST (cfg, args [0], cfg->domain);
 -                              }
 +                              /* AOT code is only used in the root domain */
 +                              EMIT_NEW_PCONST (cfg, args [0], cfg->compile_aot ? NULL : cfg->domain);
                                ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
                                MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
  
                                if (next_bb)
                                        MONO_START_BB (cfg, next_bb);
 +
 +
                                ip += 2;
                                break;
                        }
                                ip += 2;
                                break;
                        }
 +                      case CEE_MONO_CALLI_EXTRA_ARG: {
 +                              MonoInst *addr;
 +                              MonoMethodSignature *fsig;
 +                              MonoInst *arg;
 +
 +                              /*
 +                               * This is the same as CEE_CALLI, but passes an additional argument
 +                               * to the called method in llvmonly mode.
 +                               * This is only used by delegate invoke wrappers to call the
 +                               * actual delegate method.
 +                               */
 +                              g_assert (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE);
 +
 +                              CHECK_OPSIZE (6);
 +                              token = read32 (ip + 2);
 +
 +                              ins = NULL;
 +
 +                              cmethod = NULL;
 +                              CHECK_STACK (1);
 +                              --sp;
 +                              addr = *sp;
 +                              fsig = mini_get_signature (method, token, generic_context, &cfg->error);
 +                              CHECK_CFG_ERROR;
 +
 +                              if (cfg->llvm_only)
 +                                      cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
 +
 +                              n = fsig->param_count + fsig->hasthis + 1;
 +
 +                              CHECK_STACK (n);
 +
 +                              sp -= n;
 +                              arg = sp [n - 1];
 +
 +                              if (cfg->llvm_only) {
 +                                      /*
 +                                       * The lowest bit of 'arg' determines whenever the callee uses the gsharedvt
 +                                       * cconv. This is set by mono_init_delegate ().
 +                                       */
 +                                      if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig)) {
 +                                              MonoInst *callee = addr;
 +                                              MonoInst *call, *localloc_ins;
 +                                              MonoBasicBlock *is_gsharedvt_bb, *end_bb;
 +                                              int low_bit_reg = alloc_preg (cfg);
 +
 +                                              NEW_BBLOCK (cfg, is_gsharedvt_bb);
 +                                              NEW_BBLOCK (cfg, end_bb);
 +
 +                                              MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
 +                                              MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
 +                                              MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
 +
 +                                              /* Normal case: callee uses a normal cconv, have to add an out wrapper */
 +                                              addr = emit_get_rgctx_sig (cfg, context_used,
 +                                                                                                 fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
 +                                              /*
 +                                               * ADDR points to a gsharedvt-out wrapper, have to pass <callee, arg> as an extra arg.
 +                                               */
 +                                              MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
 +                                              ins->dreg = alloc_preg (cfg);
 +                                              ins->inst_imm = 2 * SIZEOF_VOID_P;
 +                                              MONO_ADD_INS (cfg->cbb, ins);
 +                                              localloc_ins = ins;
 +                                              cfg->flags |= MONO_CFG_HAS_ALLOCA;
 +                                              MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
 +                                              MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
 +
 +                                              call = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
 +                                              MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
 +
 +                                              /* Gsharedvt case: callee uses a gsharedvt cconv, no conversion is needed */
 +                                              MONO_START_BB (cfg, is_gsharedvt_bb);
 +                                              MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
 +                                              ins = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
 +                                              ins->dreg = call->dreg;
 +
 +                                              MONO_START_BB (cfg, end_bb);
 +                                      } else {
 +                                              /* Caller uses a normal calling conv */
 +
 +                                              MonoInst *callee = addr;
 +                                              MonoInst *call, *localloc_ins;
 +                                              MonoBasicBlock *is_gsharedvt_bb, *end_bb;
 +                                              int low_bit_reg = alloc_preg (cfg);
 +
 +                                              NEW_BBLOCK (cfg, is_gsharedvt_bb);
 +                                              NEW_BBLOCK (cfg, end_bb);
 +
 +                                              MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, low_bit_reg, arg->dreg, 1);
 +                                              MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_bit_reg, 0);
 +                                              MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_gsharedvt_bb);
 +
 +                                              /* Normal case: callee uses a normal cconv, no conversion is needed */
 +                                              call = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
 +                                              MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
 +                                              /* Gsharedvt case: callee uses a gsharedvt cconv, have to add an in wrapper */
 +                                              MONO_START_BB (cfg, is_gsharedvt_bb);
 +                                              MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PXOR_IMM, arg->dreg, arg->dreg, 1);
 +                                              NEW_AOTCONST (cfg, addr, MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER, fsig);
 +                                              MONO_ADD_INS (cfg->cbb, addr);
 +                                              /*
 +                                               * ADDR points to a gsharedvt-in wrapper, have to pass <callee, arg> as an extra arg.
 +                                               */
 +                                              MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
 +                                              ins->dreg = alloc_preg (cfg);
 +                                              ins->inst_imm = 2 * SIZEOF_VOID_P;
 +                                              MONO_ADD_INS (cfg->cbb, ins);
 +                                              localloc_ins = ins;
 +                                              cfg->flags |= MONO_CFG_HAS_ALLOCA;
 +                                              MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, 0, callee->dreg);
 +                                              MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, localloc_ins->dreg, SIZEOF_VOID_P, arg->dreg);
 +
 +                                              ins = emit_extra_arg_calli (cfg, fsig, sp, localloc_ins->dreg, addr);
 +                                              ins->dreg = call->dreg;
 +                                              MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
 +
 +                                              MONO_START_BB (cfg, end_bb);
 +                                      }
 +                              } else {
 +                                      /* Same as CEE_CALLI */
 +                                      if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
 +                                              /*
 +                                               * We pass the address to the gsharedvt trampoline in the rgctx reg
 +                                               */
 +                                              MonoInst *callee = addr;
 +
 +                                              addr = emit_get_rgctx_sig (cfg, context_used,
 +                                                                                                 fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
 +                                              ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
 +                                      } else {
 +                                              ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
 +                                      }
 +                              }
 +
 +                              if (!MONO_TYPE_IS_VOID (fsig->ret))
 +                                      *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
 +
 +                              CHECK_CFG_EXCEPTION;
 +
 +                              ip += 6;
 +                              ins_flag = 0;
 +                              constrained_class = NULL;
 +                              break;
 +                      }
 +                      case CEE_MONO_LDDOMAIN:
 +                              CHECK_STACK_OVF (1);
 +                              EMIT_NEW_PCONST (cfg, ins, cfg->compile_aot ? NULL : cfg->domain);
 +                              ip += 2;
 +                              *sp++ = ins;
 +                              break;
 +                      case CEE_MONO_GET_LAST_ERROR:
 +                              CHECK_OPSIZE (2);
 +                              CHECK_STACK_OVF (1);
 +
 +                              MONO_INST_NEW (cfg, ins, OP_GET_LAST_ERROR);
 +                              ins->dreg = alloc_dreg (cfg, STACK_I4);
 +                              ins->type = STACK_I4;
 +                              MONO_ADD_INS (cfg->cbb, ins);
 +
 +                              ip += 2;
 +                              *sp++ = ins;
 +                              break;
                        default:
                                g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
                                break;
                                CHECK_OPSIZE (6);
                                n = read32 (ip + 2);
                                cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
 -                              if (!cmethod || mono_loader_get_last_error ())
 -                                      LOAD_ERROR;
 +                              CHECK_CFG_ERROR;
 +
                                mono_class_init (cmethod->klass);
  
                                mono_save_token_info (cfg, image, n, cmethod);
  
                                cil_method = cmethod;
                                if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
 -                                      METHOD_ACCESS_FAILURE (method, cil_method);
 +                                      emit_method_access_failure (cfg, method, cil_method);
  
                                if (mono_security_core_clr_enabled ())
                                        ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
                                CHECK_OPSIZE (6);
                                n = read32 (ip + 2);
                                cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
 -                              if (!cmethod || mono_loader_get_last_error ())
 -                                      LOAD_ERROR;
 +                              CHECK_CFG_ERROR;
 +
                                mono_class_init (cmethod->klass);
   
                                context_used = mini_method_check_context_used (cfg, cmethod);
                                ip += 4;
                                inline_costs += 1;
                                break;
 -                      case CEE_LOCALLOC:
 +                      case CEE_LOCALLOC: {
                                CHECK_STACK (1);
 +                              MonoBasicBlock *non_zero_bb, *end_bb;
 +                              int alloc_ptr = alloc_preg (cfg);
                                --sp;
                                if (sp != stack_start) 
                                        UNVERIFIED;
                                         */
                                        INLINE_FAILURE("localloc");
  
 +                              NEW_BBLOCK (cfg, non_zero_bb);
 +                              NEW_BBLOCK (cfg, end_bb);
 +
 +                              /* if size != zero */
 +                              MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
 +                              MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, non_zero_bb);
 +
 +                              //size is zero, so result is NULL
 +                              MONO_EMIT_NEW_PCONST (cfg, alloc_ptr, NULL);
 +                              MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
 +
 +                              MONO_START_BB (cfg, non_zero_bb);
                                MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
 -                              ins->dreg = alloc_preg (cfg);
 +                              ins->dreg = alloc_ptr;
                                ins->sreg1 = sp [0]->dreg;
                                ins->type = STACK_PTR;
                                MONO_ADD_INS (cfg->cbb, ins);
                                if (init_locals)
                                        ins->flags |= MONO_INST_INIT;
  
 +                              MONO_START_BB (cfg, end_bb);
 +                              EMIT_NEW_UNALU (cfg, ins, OP_MOVE, alloc_preg (cfg), alloc_ptr);
 +                              ins->type = STACK_PTR;
 +
                                *sp++ = ins;
                                ip += 2;
                                break;
 +                      }
                        case CEE_ENDFILTER: {
                                MonoExceptionClause *clause, *nearest;
                                int cc;
        if (cfg->method == method) {
                MonoBasicBlock *bb;
                for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
 -                      bb->region = mono_find_block_region (cfg, bb->real_offset);
 +                      if (bb == cfg->bb_init)
 +                              bb->region = -1;
 +                      else
 +                              bb->region = mono_find_block_region (cfg, bb->real_offset);
                        if (cfg->spvars)
                                mono_create_spvar_for_region (cfg, bb->region);
                        if (cfg->verbose_level > 2)
                                printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
                }
 +      } else {
 +              MonoBasicBlock *bb;
 +              /* get_most_deep_clause () in mini-llvm.c depends on this for inlined bblocks */
 +              for (bb = start_bblock; bb != end_bblock; bb  = bb->next_bb) {
 +                      bb->real_offset = inline_offset;
 +              }
        }
  
        if (inline_costs < 0) {
  
                /* Method is too large */
                mname = mono_method_full_name (method, TRUE);
 -              mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
 -              cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
 +              mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Method %s is too complex.", mname));
                g_free (mname);
        }
  
@@@ -13750,6 -13428,7 +13750,6 @@@ mono_error_exit
        g_slist_free (class_inits);
        mono_basic_block_free (original_bb);
        cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
 -      cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
        if (cfg->exception_type)
                return -1;
        else
@@@ -14303,8 -13982,8 +14303,8 @@@ mono_handle_global_vregs (MonoCompile *
                                         * Make the component vregs volatile since the optimizations can
                                         * get confused otherwise.
                                         */
 -                                      get_vreg_to_inst (cfg, vreg + 1)->flags |= MONO_INST_VOLATILE;
 -                                      get_vreg_to_inst (cfg, vreg + 2)->flags |= MONO_INST_VOLATILE;
 +                                      get_vreg_to_inst (cfg, MONO_LVREG_LS (vreg))->flags |= MONO_INST_VOLATILE;
 +                                      get_vreg_to_inst (cfg, MONO_LVREG_MS (vreg))->flags |= MONO_INST_VOLATILE;
                                }
  #endif
  
                                        /* Modify the two component vars too */
                                        MonoInst *var1;
  
 -                                      var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 1);
 +                                      var1 = get_vreg_to_inst (cfg, MONO_LVREG_LS (cfg->varinfo [pos]->dreg));
                                        var1->inst_c0 = pos;
 -                                      var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 2);
 +                                      var1 = get_vreg_to_inst (cfg, MONO_LVREG_MS (cfg->varinfo [pos]->dreg));
                                        var1->inst_c0 = pos;
                                }
  #endif
@@@ -14546,13 -14225,13 +14546,13 @@@ mono_spill_global_vars (MonoCompile *cf
  
                                g_assert (ins->opcode == OP_REGOFFSET);
  
 -                              tree = get_vreg_to_inst (cfg, ins->dreg + 1);
 +                              tree = get_vreg_to_inst (cfg, MONO_LVREG_LS (ins->dreg));
                                g_assert (tree);
                                tree->opcode = OP_REGOFFSET;
                                tree->inst_basereg = ins->inst_basereg;
                                tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
  
 -                              tree = get_vreg_to_inst (cfg, ins->dreg + 2);
 +                              tree = get_vreg_to_inst (cfg, MONO_LVREG_MS (ins->dreg));
                                g_assert (tree);
                                tree->opcode = OP_REGOFFSET;
                                tree->inst_basereg = ins->inst_basereg;
  
  #if SIZEOF_REGISTER != 8
                                        if (regtype == 'l') {
 -                                              NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET, ins->dreg + 1);
 +                                              NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET, MONO_LVREG_LS (ins->dreg));
                                                mono_bblock_insert_after_ins (bb, ins, store_ins);
 -                                              NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET, ins->dreg + 2);
 +                                              NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET, MONO_LVREG_MS (ins->dreg));
                                                mono_bblock_insert_after_ins (bb, ins, store_ins);
                                                def_ins = store_ins;
                                        }
  
  #if SIZEOF_REGISTER != 8
                                                if (regtype == 'l') {
 -                                                      NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 2, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
 +                                                      NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_MS (sreg), var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
                                                        mono_bblock_insert_before_ins (bb, ins, load_ins);
 -                                                      NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 1, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
 +                                                      NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, MONO_LVREG_LS (sreg), var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
                                                        mono_bblock_insert_before_ins (bb, ins, load_ins);
                                                        use_ins = load_ins;
                                                }
        g_free (live_range_end_bb);
  }
  
 +static void
 +mono_decompose_typecheck (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins)
 +{
 +      MonoInst *ret, *move, *source;
 +      MonoClass *klass = ins->klass;
 +      int context_used = mini_class_check_context_used (cfg, klass);
 +      int is_isinst = ins->opcode == OP_ISINST;
 +      g_assert (is_isinst || ins->opcode == OP_CASTCLASS);
 +      source = get_vreg_to_inst (cfg, ins->sreg1);
 +      if (!source || source == (MonoInst *) -1)
 +              source = mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, ins->sreg1);
 +      g_assert (source && source != (MonoInst *) -1);
 +
 +      MonoBasicBlock *first_bb;
 +      NEW_BBLOCK (cfg, first_bb);
 +      cfg->cbb = first_bb;
 +
 +      if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
 +              if (is_isinst)
 +                      ret = emit_isinst_with_cache_nonshared (cfg, source, klass);
 +              else
 +                      ret = emit_castclass_with_cache_nonshared (cfg, source, klass);
 +      } else if (!context_used && (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass))) {
 +              MonoInst *iargs [1];
 +              int costs;
 +
 +              iargs [0] = source;
 +              if (is_isinst) {
 +                      MonoMethod *wrapper = mono_marshal_get_isinst (klass);
 +                      costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), iargs, 0, 0, TRUE);
 +              } else {
 +                      MonoMethod *wrapper = mono_marshal_get_castclass (klass);
 +                      save_cast_details (cfg, klass, source->dreg, TRUE);
 +                      costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), iargs, 0, 0, TRUE);
 +                      reset_cast_details (cfg);
 +              }
 +              g_assert (costs > 0);
 +              ret = iargs [0];
 +      } else {
 +              if (is_isinst)
 +                      ret = handle_isinst (cfg, klass, source, context_used);
 +              else
 +                      ret = handle_castclass (cfg, klass, source, context_used);
 +      }
 +      EMIT_NEW_UNALU (cfg, move, OP_MOVE, ins->dreg, ret->dreg);
 +
 +      g_assert (cfg->cbb->code || first_bb->code);
 +      MonoInst *prev = ins->prev;
 +      mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
 +}
 +
 +void
 +mono_decompose_typechecks (MonoCompile *cfg)
 +{
 +      for (MonoBasicBlock *bb = cfg->bb_entry; bb; bb = bb->next_bb) {
 +              MonoInst *ins;
 +              MONO_BB_FOR_EACH_INS (bb, ins) {
 +                      switch (ins->opcode) {
 +                      case OP_ISINST:
 +                      case OP_CASTCLASS:
 +                              mono_decompose_typecheck (cfg, bb, ins);
 +                              break;
 +                      }
 +              }
 +      }
 +}
 +
 +
  /**
   * FIXME:
   * - use 'iadd' instead of 'int_add'
diff --combined mono/mini/mini-runtime.c
index 76647275f08a4462f2d7ff43dcef86ae344ea8cf,27ee9a2858593b7bccd1486372e0eeb66a1054d0..572048ff5ff8b401b415ab6ba0fe9de8e88cc02f
@@@ -1,4 -1,3 +1,4 @@@
 +
  /*
   * mini-runtime.c: Runtime code for the JIT
   *
@@@ -9,7 -8,6 +9,7 @@@
   * Copyright 2002-2003 Ximian, Inc.
   * Copyright 2003-2010 Novell, Inc.
   * Copyright 2011-2015 Xamarin, Inc (http://www.xamarin.com)
 + * Licensed under the MIT license. See LICENSE file in the project root for full license information.
   */
  
  #include <config.h>
@@@ -49,8 -47,6 +49,8 @@@
  #include <mono/metadata/mempool-internals.h>
  #include <mono/metadata/attach.h>
  #include <mono/metadata/runtime.h>
 +#include <mono/metadata/reflection-internals.h>
 +#include <mono/metadata/monitor.h>
  #include <mono/utils/mono-math.h>
  #include <mono/utils/mono-compiler.h>
  #include <mono/utils/mono-counters.h>
@@@ -63,9 -59,7 +63,9 @@@
  #include <mono/utils/dtrace.h>
  #include <mono/utils/mono-signal-handler.h>
  #include <mono/utils/mono-threads.h>
 +#include <mono/utils/mono-threads-coop.h>
  #include <mono/utils/checked-build.h>
 +#include <mono/metadata/w32handle.h>
  #include <mono/io-layer/io-layer.h>
  
  #include "mini.h"
@@@ -85,7 -79,6 +85,7 @@@
  #ifdef MONO_ARCH_LLVM_SUPPORTED
  #ifdef ENABLE_LLVM
  #include "mini-llvm-cpp.h"
 +#include "llvm-jit.h"
  #endif
  #endif
  
@@@ -165,8 -158,7 +165,8 @@@ G_GNUC_UNUSED static char
  get_method_from_ip (void *ip)
  {
        MonoJitInfo *ji;
 -      char *method;
 +      MonoMethod *method;
 +      char *method_name;
        char *res;
        MonoDomain *domain = mono_domain_get ();
        MonoDebugSourceLocation *location;
                return res;
        }
  
 -      method = mono_method_full_name (jinfo_get_method (ji), TRUE);
 +      method = jinfo_get_method (ji);
 +      method_name = mono_method_full_name (method, TRUE);
        /* FIXME: unused ? */
 -      location = mono_debug_lookup_source_location (jinfo_get_method (ji), (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
 +      location = mono_debug_lookup_source_location (method, (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
  
 -      res = g_strdup_printf (" %s + 0x%x (%p %p) [%p - %s]", method, (int)((char*)ip - (char*)ji->code_start), ji->code_start, (char*)ji->code_start + ji->code_size, domain, domain->friendly_name);
 +      res = g_strdup_printf (" %s {%p} + 0x%x (%p %p) [%p - %s]", method_name, method, (int)((char*)ip - (char*)ji->code_start), ji->code_start, (char*)ji->code_start + ji->code_size, domain, domain->friendly_name);
  
        mono_debug_free_source_location (location);
 -      g_free (method);
 +      g_free (method_name);
  
        return res;
  }
@@@ -341,7 -332,7 +341,7 @@@ void *mono_global_codeman_reserve (int 
        void *ptr;
  
        if (mono_aot_only)
 -              g_error ("Attempting to allocate from the global code manager while running with --aot-only.\n");
 +              g_error ("Attempting to allocate from the global code manager while running in aot-only mode.\n");
  
        if (!global_codeman) {
                /* This can happen during startup */
@@@ -364,6 -355,65 +364,6 @@@ mono_nacl_gc(
        __nacl_suspend_thread_if_needed();
  #endif
  }
 -
 -/* Given the temporary buffer (allocated by mono_global_codeman_reserve) into
 - * which we are generating code, return a pointer to the destination in the
 - * dynamic code segment into which the code will be copied when
 - * mono_global_codeman_commit is called.
 - * LOCKING: Acquires the jit lock.
 - */
 -void*
 -nacl_global_codeman_get_dest (void *data)
 -{
 -      void *dest;
 -      mono_jit_lock ();
 -      dest = nacl_code_manager_get_code_dest (global_codeman, data);
 -      mono_jit_unlock ();
 -      return dest;
 -}
 -
 -void
 -mono_global_codeman_commit (void *data, int size, int newsize)
 -{
 -      mono_jit_lock ();
 -      mono_code_manager_commit (global_codeman, data, size, newsize);
 -      mono_jit_unlock ();
 -}
 -
 -/*
 - * Convenience function which calls mono_global_codeman_commit to validate and
 - * copy the code. The caller sets *buf_base and *buf_size to the start and size
 - * of the buffer (allocated by mono_global_codeman_reserve), and *code_end to
 - * the byte after the last instruction byte. On return, *buf_base will point to
 - * the start of the copied in the code segment, and *code_end will point after
 - * the end of the copied code.
 - */
 -void
 -nacl_global_codeman_validate (guint8 **buf_base, int buf_size, guint8 **code_end)
 -{
 -      guint8 *tmp = nacl_global_codeman_get_dest (*buf_base);
 -      mono_global_codeman_commit (*buf_base, buf_size, *code_end - *buf_base);
 -      *code_end = tmp + (*code_end - *buf_base);
 -      *buf_base = tmp;
 -}
 -#else
 -/* no-op versions of Native Client functions */
 -void*
 -nacl_global_codeman_get_dest (void *data)
 -{
 -      return data;
 -}
 -
 -void
 -mono_global_codeman_commit (void *data, int size, int newsize)
 -{
 -}
 -
 -void
 -nacl_global_codeman_validate (guint8 **buf_base, int buf_size, guint8 **code_end)
 -{
 -}
 -
  #endif /* __native_client__ */
  
  /**
@@@ -559,7 -609,6 +559,7 @@@ mono_debug_count (void
  gconstpointer
  mono_icall_get_wrapper_full (MonoJitICallInfo* callinfo, gboolean do_compile)
  {
 +      MonoError error;
        char *name;
        MonoMethod *wrapper;
        gconstpointer trampoline;
        wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func, check_exc);
        g_free (name);
  
 -      if (do_compile)
 -              trampoline = mono_compile_method (wrapper);
 -      else
 -              trampoline = mono_create_ftnptr (domain, mono_create_jit_trampoline_in_domain (domain, wrapper));
 +      if (do_compile) {
 +              trampoline = mono_compile_method_checked (wrapper, &error);
 +              mono_error_assert_ok (&error);
 +      } else {
 +
 +              trampoline = mono_create_jit_trampoline (domain, wrapper, &error);
 +              mono_error_assert_ok (&error);
 +              trampoline = mono_create_ftnptr (domain, (gpointer)trampoline);
 +      }
  
        mono_loader_lock ();
        if (!callinfo->trampoline) {
@@@ -666,19 -710,6 +666,19 @@@ register_icall_no_wrapper (gpointer fun
        mono_register_jit_icall_full (func, name, sig, TRUE, FALSE, name);
  }
  
 +static void
 +register_icall_with_wrapper (gpointer func, const char *name, const char *sigstr)
 +{
 +      MonoMethodSignature *sig;
 +
 +      if (sigstr)
 +              sig = mono_create_icall_signature (sigstr);
 +      else
 +              sig = NULL;
 +
 +      mono_register_jit_icall_full (func, name, sig, FALSE, FALSE, NULL);
 +}
 +
  static void
  register_dyn_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
  {
@@@ -779,8 -810,7 +779,8 @@@ mono_get_lmf_addr (void
         * mono_get_lmf_addr, and mono_get_lmf_addr requires the thread to be attached.
         */
  
 -      mono_jit_thread_attach (NULL);
 +      mono_thread_attach (mono_get_root_domain ());
 +      mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
  
        if ((jit_tls = mono_native_tls_get_value (mono_jit_tls_id)))
                return &jit_tls->lmf;
@@@ -841,39 -871,33 +841,39 @@@ mono_set_lmf_addr (gpointer lmf_addr
  /*
   * mono_jit_thread_attach:
   *
 - * Called by native->managed wrappers. Returns the original domain which needs to be
 - * restored, or NULL.
 + * Called by Xamarin.Mac and other products. Attach thread to runtime if
 + * needed and switch to @domain.
 + *
 + * @return the original domain which needs to be restored, or NULL.
   */
  MonoDomain*
  mono_jit_thread_attach (MonoDomain *domain)
  {
        MonoDomain *orig;
 +      gboolean attached;
  
 -      if (!domain)
 -              /*
 -               * Happens when called from AOTed code which is only used in the root
 -               * domain.
 -               */
 +      g_assert (!mono_threads_is_coop_enabled ());
 +
 +      if (!domain) {
 +              /* Happens when called from AOTed code which is only used in the root domain. */
                domain = mono_get_root_domain ();
 +      }
 +
 +      g_assert (domain);
  
  #ifdef MONO_HAVE_FAST_TLS
 -      if (!MONO_FAST_TLS_GET (mono_lmf_addr)) {
 -              mono_thread_attach (domain);
 -              // #678164
 -              mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
 -      }
 +      attached = MONO_FAST_TLS_GET (mono_lmf_addr) != NULL;
  #else
 -      if (!mono_native_tls_get_value (mono_jit_tls_id)) {
 +      attached = mono_native_tls_get_value (mono_jit_tls_id) != NULL;
 +#endif
 +
 +      if (!attached) {
                mono_thread_attach (domain);
 +
 +              // #678164
                mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
        }
 -#endif
 +
        orig = mono_domain_get ();
        if (orig != domain)
                mono_domain_set (domain, TRUE);
        return orig != domain ? orig : NULL;
  }
  
 -/* Called by native->managed wrappers */
 +/*
 + * mono_jit_set_domain:
 + *
 + * Set domain to @domain if @domain is not null
 + */
  void
  mono_jit_set_domain (MonoDomain *domain)
  {
 +      g_assert (!mono_threads_is_coop_enabled ());
 +
        if (domain)
                mono_domain_set (domain, TRUE);
  }
@@@ -999,6 -1017,8 +999,6 @@@ mono_thread_attach_cb (intptr_t tid, gp
        thread = mono_thread_info_current_unchecked ();
        if (thread)
                thread->jit_data = jit_tls;
 -      if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
 -              mono_runtime_setup_stat_profiler ();
  
        mono_arch_cpu_init ();
  }
@@@ -1094,63 -1114,6 +1094,63 @@@ mono_patch_info_list_prepend (MonoJumpI
        return ji;
  }
  
 +#if !defined(DISABLE_LOGGING) && !defined(DISABLE_JIT)
 +
 +static const char* const patch_info_str[] = {
 +#define PATCH_INFO(a,b) "" #a,
 +#include "patch-info.h"
 +#undef PATCH_INFO
 +};
 +
 +const char*
 +mono_ji_type_to_string (MonoJumpInfoType type)
 +{
 +      return patch_info_str [type];
 +}
 +
 +void
 +mono_print_ji (const MonoJumpInfo *ji)
 +{
 +      switch (ji->type) {
 +      case MONO_PATCH_INFO_RGCTX_FETCH: {
 +              MonoJumpInfoRgctxEntry *entry = ji->data.rgctx_entry;
 +
 +              printf ("[RGCTX_FETCH ");
 +              mono_print_ji (entry->data);
 +              printf (" - %s]", mono_rgctx_info_type_to_str (entry->info_type));
 +              break;
 +      }
 +      case MONO_PATCH_INFO_METHODCONST: {
 +              char *s = mono_method_full_name (ji->data.method, TRUE);
 +              printf ("[METHODCONST - %s]", s);
 +              g_free (s);
 +              break;
 +      }
 +      case MONO_PATCH_INFO_INTERNAL_METHOD: {
 +              printf ("[INTERNAL_METHOD - %s]", ji->data.name);
 +              break;
 +      }
 +      default:
 +              printf ("[%s]", patch_info_str [ji->type]);
 +              break;
 +      }
 +}
 +
 +#else
 +
 +const char*
 +mono_ji_type_to_string (MonoJumpInfoType type)
 +{
 +      return "";
 +}
 +
 +void
 +mono_print_ji (const MonoJumpInfo *ji)
 +{
 +}
 +
 +#endif
 +
  /**
   * mono_patch_info_dup_mp:
   *
@@@ -1252,7 -1215,6 +1252,7 @@@ mono_patch_info_hash (gconstpointer dat
        case MONO_PATCH_INFO_METHOD_JUMP:
        case MONO_PATCH_INFO_IMAGE:
        case MONO_PATCH_INFO_ICALL_ADDR:
 +      case MONO_PATCH_INFO_ICALL_ADDR_CALL:
        case MONO_PATCH_INFO_FIELD:
        case MONO_PATCH_INFO_SFLDA:
        case MONO_PATCH_INFO_SEQ_POINT_INFO:
        case MONO_PATCH_INFO_GOT_OFFSET:
        case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
        case MONO_PATCH_INFO_AOT_MODULE:
 +      case MONO_PATCH_INFO_GET_TLS_TRAMP:
                return (ji->type << 8);
        case MONO_PATCH_INFO_CASTCLASS_CACHE:
                return (ji->type << 8) | (ji->data.index);
        }
        case MONO_PATCH_INFO_JIT_ICALL_ADDR:
                return (ji->type << 8) | g_str_hash (ji->data.target);
 +      case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
 +              return (ji->type << 8) | mono_signature_hash (ji->data.sig);
        default:
                printf ("info type: %d\n", ji->type);
                mono_print_ji (ji); printf ("\n");
@@@ -1367,8 -1326,6 +1367,8 @@@ mono_patch_info_equal (gconstpointer ka
                if (ji1->data.target == ji2->data.target)
                        return 1;
                return strcmp (ji1->data.target, ji2->data.target) == 0 ? 1 : 0;
 +      case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
 +              return mono_metadata_signature_equal (ji1->data.sig, ji2->data.sig) ? 1 : 0;
        default:
                if (ji1->data.target != ji2->data.target)
                        return 0;
  }
  
  gpointer
 -mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors)
 +mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors, MonoError *error)
  {
        unsigned char *ip = patch_info->ip.i + code;
        gconstpointer target = NULL;
  
 +      mono_error_init (error);
 +
        switch (patch_info->type) {
        case MONO_PATCH_INFO_BB:
                /*
                target = patch_info->data.inst->inst_c0 + code;
                break;
        case MONO_PATCH_INFO_IP:
 -#if defined(__native_client__) && defined(__native_client_codegen__)
 -              /* Need to transform to the destination address, it's */
 -              /* emitted as an immediate in the code. */
 -              target = nacl_inverse_modify_patch_target(ip);
 -#else
                target = ip;
 -#endif
                break;
        case MONO_PATCH_INFO_METHOD_REL:
                target = code + patch_info->data.offset;
                break;
        }
        case MONO_PATCH_INFO_METHOD_JUMP:
 -              target = mono_create_jump_trampoline (domain, patch_info->data.method, FALSE);
 -#if defined(__native_client__) && defined(__native_client_codegen__)
 -# if defined(TARGET_AMD64)
 -              /* This target is an absolute address, not relative to the */
 -              /* current code being emitted on AMD64. */
 -              target = nacl_inverse_modify_patch_target(target);
 -# endif
 -#endif
 +              target = mono_create_jump_trampoline (domain, patch_info->data.method, FALSE, error);
 +              if (!mono_error_ok (error))
 +                      return NULL;
                break;
        case MONO_PATCH_INFO_METHOD:
 -#if defined(__native_client_codegen__) && defined(USE_JUMP_TABLES)
 -              /*
 -               * If we use jumptables, for recursive calls we cannot
 -               * avoid trampoline, as we not yet know where we will
 -               * be installed.
 -               */
 -              target = mono_create_jit_trampoline_in_domain (domain, patch_info->data.method);
 -#else
                if (patch_info->data.method == method) {
                        target = code;
                } else {
                        /* get the trampoline to the method from the domain */
 -                      target = mono_create_jit_trampoline_in_domain (domain, patch_info->data.method);
 +                      target = mono_create_jit_trampoline (domain, patch_info->data.method, error);
 +                      if (!mono_error_ok (error))
 +                              return NULL;
                }
 -#endif
                break;
        case MONO_PATCH_INFO_METHOD_CODE_SLOT: {
                gpointer code_slot;
  #endif
  
                for (i = 0; i < patch_info->data.table->table_size; i++) {
 -#if defined(__native_client__) && defined(__native_client_codegen__)
 -                      /* 'code' is relative to the current code blob, we */
 -                      /* need to do this transform on it to make the     */
 -                      /* pointers in this table absolute                 */
 -                      jump_table [i] = nacl_inverse_modify_patch_target (code) + GPOINTER_TO_INT (patch_info->data.table->table [i]);
 -#else
                        jump_table [i] = code + GPOINTER_TO_INT (patch_info->data.table->table [i]);
 -#endif
                }
  
 -#if defined(__native_client__) && defined(__native_client_codegen__)
 -              /* jump_table is in the data section, we need to transform */
 -              /* it here so when it gets modified in amd64_patch it will */
 -              /* then point back to the absolute data address            */
 -              target = nacl_inverse_modify_patch_target (jump_table);
 -#else
                target = jump_table;
 -#endif
                break;
        }
        case MONO_PATCH_INFO_METHODCONST:
                break;
        case MONO_PATCH_INFO_IID:
                mono_class_init (patch_info->data.klass);
-               target = GINT_TO_POINTER ((int)patch_info->data.klass->interface_id);
+               target = GUINT_TO_POINTER (patch_info->data.klass->interface_id);
                break;
        case MONO_PATCH_INFO_ADJUSTED_IID:
                mono_class_init (patch_info->data.klass);
-               target = GINT_TO_POINTER ((int)(-((patch_info->data.klass->interface_id + 1) * SIZEOF_VOID_P)));
+               target = GUINT_TO_POINTER ((guint32)(-((patch_info->data.klass->interface_id + 1) * SIZEOF_VOID_P)));
                break;
        case MONO_PATCH_INFO_VTABLE:
                target = mono_class_vtable (domain, patch_info->data.klass);
                }
  
                g_assert (vtable);
 -              if (!vtable->initialized && !(vtable->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) && (method && mono_class_needs_cctor_run (vtable->klass, method)))
 +              if (!vtable->initialized && !mono_class_is_before_field_init (vtable->klass) && (method && mono_class_needs_cctor_run (vtable->klass, method)))
                        /* Done by the generated code */
                        ;
                else {
 -                      if (run_cctors)
 -                              mono_runtime_class_init (vtable);
 +                      if (run_cctors) {
 +                              if (!mono_runtime_class_init_full (vtable, error)) {
 +                                      return NULL;
 +                              }
 +                      }
                }
                target = (char*)mono_vtable_get_static_field_data (vtable) + patch_info->data.field->offset;
                break;
                break;
        case MONO_PATCH_INFO_LDSTR:
                target =
 -                      mono_ldstr (domain, patch_info->data.token->image,
 -                                              mono_metadata_token_index (patch_info->data.token->token));
 +                      mono_ldstr_checked (domain, patch_info->data.token->image,
 +                                          mono_metadata_token_index (patch_info->data.token->token), error);
                break;
        case MONO_PATCH_INFO_TYPE_FROM_HANDLE: {
                gpointer handle;
                MonoClass *handle_class;
 -              MonoError error;
  
                handle = mono_ldtoken_checked (patch_info->data.token->image,
 -                                                         patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, &error);
 -              if (!mono_error_ok (&error))
 -                      g_error ("Could not patch ldtoken due to %s", mono_error_get_message (&error));
 +                                                         patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
 +              if (!mono_error_ok (error))
 +                      return NULL;
                mono_class_init (handle_class);
                mono_class_init (mono_class_from_mono_type ((MonoType *)handle));
  
 -              target =
 -                      mono_type_get_object (domain, (MonoType *)handle);
 +              target = mono_type_get_object_checked (domain, (MonoType *)handle, error);
 +              if (!mono_error_ok (error))
 +                      return NULL;
                break;
        }
        case MONO_PATCH_INFO_LDTOKEN: {
                gpointer handle;
                MonoClass *handle_class;
 -              MonoError error;
  
                handle = mono_ldtoken_checked (patch_info->data.token->image,
 -                                                         patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, &error);
 -              if (!mono_error_ok (&error))
 -                      g_error ("Could not patch ldtoken due to %s", mono_error_get_message (&error));
 +                                                         patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
 +              if (!mono_error_ok (error))
 +                      g_error ("Could not patch ldtoken due to %s", mono_error_get_message (error));
                mono_class_init (handle_class);
  
                target = handle;
                target = (mono_metadata_blob_heap (patch_info->data.token->image, patch_info->data.token->token) + 2);
                break;
        case MONO_PATCH_INFO_ICALL_ADDR:
 +      case MONO_PATCH_INFO_ICALL_ADDR_CALL:
                /* run_cctors == 0 -> AOT */
                if (patch_info->data.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
                        const char *exc_class;
                        if (run_cctors) {
                                target = mono_lookup_pinvoke_call (patch_info->data.method, &exc_class, &exc_arg);
                                if (!target) {
 -                                      if (mono_aot_only)
 -                                              mono_raise_exception (mono_exception_from_name_msg (mono_defaults.corlib, "System", exc_class, exc_arg));
 +                                      if (mono_aot_only) {
 +                                              mono_error_set_exception_instance (error, mono_exception_from_name_msg (mono_defaults.corlib, "System", exc_class, exc_arg));
 +                                              return NULL;
 +                                      }
                                        g_error ("Unable to resolve pinvoke method '%s' Re-run with MONO_LOG_LEVEL=debug for more information.\n", mono_method_full_name (patch_info->data.method, TRUE));
                                }
                        } else {
  
                break;
        }
 +      case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
 +              target = mini_get_gsharedvt_wrapper (TRUE, NULL, patch_info->data.sig, NULL, -1, FALSE);
 +              break;
 +      case MONO_PATCH_INFO_GET_TLS_TRAMP:
 +#ifdef MONO_ARCH_HAVE_GET_TLS_TRAMP
 +              target = mono_arch_get_get_tls_tramp ();
 +#else
 +              target = NULL;
 +#endif
 +              break;
        default:
                g_assert_not_reached ();
        }
@@@ -1865,7 -1837,7 +1865,7 @@@ no_gsharedvt_in_wrapper (void
  }
  
  static gpointer
 -mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException **ex)
 +mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoError *error)
  {
        MonoDomain *target_domain, *domain = mono_domain_get ();
        MonoJitInfo *info;
        MonoJitICallInfo *callinfo = NULL;
        WrapperInfo *winfo = NULL;
  
 +      mono_error_init (error);
 +
 +      if (mono_llvm_only)
 +              /* Should be handled by the caller */
 +              g_assert (!(method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED));
 +
        /*
         * ICALL wrappers are handled specially, since there is only one copy of them
         * shared by all appdomains.
                                ctx = mono_method_get_context (method);
                        method = info->d.synchronized_inner.method;
                        if (ctx) {
 -                              MonoError error;
 -                              method = mono_class_inflate_generic_method_checked (method, ctx, &error);
 -                              g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
 +                              method = mono_class_inflate_generic_method_checked (method, ctx, error);
 +                              g_assert (mono_error_ok (error)); /* FIXME don't swallow the error */
                        }
                }
        }
                /* We can't use a domain specific method in another domain */
                if (! ((domain != target_domain) && !info->domain_neutral)) {
                        MonoVTable *vtable;
 -                      MonoException *tmpEx;
  
                        mono_jit_stats.methods_lookups++;
 -                      vtable = mono_class_vtable (domain, method->klass);
 +                      vtable = mono_class_vtable_full (domain, method->klass, error);
 +                      if (!is_ok (error))
 +                              return NULL;
                        g_assert (vtable);
 -                      tmpEx = mono_runtime_class_init_full (vtable, ex == NULL);
 -                      if (tmpEx) {
 -                              *ex = tmpEx;
 +                      if (!mono_runtime_class_init_full (vtable, error))
                                return NULL;
 -                      }
                        return mono_create_ftnptr (target_domain, info->code_start);
                }
        }
  
                mono_class_init (method->klass);
  
 -              if ((code = mono_aot_get_method (domain, method))) {
 +              if ((code = mono_aot_get_method_checked (domain, method, error))) {
                        MonoVTable *vtable;
  
 +                      if (mono_runtime_is_critical_method (method) || mono_gc_is_critical_method (method)) {
 +                              /*
 +                               * The suspend code needs to be able to lookup these methods by ip in async context,
 +                               * so preload their jit info.
 +                               */
 +                              MonoJitInfo *ji = mono_jit_info_table_find (domain, code);
 +                              g_assert (ji);
 +                      }
 +
                        /*
                         * In llvm-only mode, method might be a shared method, so we can't initialize its class.
                         * This is not a problem, since it will be initialized when the method is first
                        if (!mono_llvm_only) {
                                vtable = mono_class_vtable (domain, method->klass);
                                g_assert (vtable);
 -                              mono_runtime_class_init (vtable);
 +                              if (!mono_runtime_class_init_full (vtable, error))
 +                                      return NULL;
                        }
                }
 +              if (!is_ok (error))
 +                      return NULL;
        }
  #endif
  
 -      if (!code)
 -              code = mono_jit_compile_method_inner (method, target_domain, opt, ex);
 -
        if (!code && mono_llvm_only) {
                if (method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
                        WrapperInfo *info = mono_marshal_get_wrapper_info (method);
                                return no_gsharedvt_in_wrapper;
                        }
                }
 +      }
  
 +      if (!code)
 +              code = mono_jit_compile_method_inner (method, target_domain, opt, error);
 +      if (!mono_error_ok (error))
 +              return NULL;
 +
 +      if (!code && mono_llvm_only) {
                printf ("AOT method not found in llvmonly mode: %s\n", mono_method_full_name (method, 1));
                g_assert_not_reached ();
        }
  }
  
  gpointer
 -mono_jit_compile_method (MonoMethod *method)
 +mono_jit_compile_method (MonoMethod *method, MonoError *error)
  {
 -      MonoException *ex = NULL;
        gpointer code;
  
 -      code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), &ex);
 -      if (!code) {
 -              g_assert (ex);
 -              mono_raise_exception (ex);
 -      }
 -
 +      code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), error);
        return code;
  }
  
@@@ -2095,6 -2054,7 +2095,6 @@@ mono_jit_free_method (MonoDomain *domai
                }
                g_slist_free (remove);
        }
 -
        mono_domain_unlock (domain);
  
  #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
@@@ -2151,32 -2111,6 +2151,32 @@@ mono_jit_find_compiled_method_with_jit_
        return NULL;
  }
  
 +static guint32 bisect_opt = 0;
 +static GHashTable *bisect_methods_hash = NULL;
 +
 +void
 +mono_set_bisect_methods (guint32 opt, const char *method_list_filename)
 +{
 +      FILE *file;
 +      char method_name [2048];
 +
 +      bisect_opt = opt;
 +      bisect_methods_hash = g_hash_table_new (g_str_hash, g_str_equal);
 +      g_assert (bisect_methods_hash);
 +
 +      file = fopen (method_list_filename, "r");
 +      g_assert (file);
 +
 +      while (fgets (method_name, sizeof (method_name), file)) {
 +              size_t len = strlen (method_name);
 +              g_assert (len > 0);
 +              g_assert (method_name [len - 1] == '\n');
 +              method_name [len - 1] = 0;
 +              g_hash_table_insert (bisect_methods_hash, g_strdup (method_name), GINT_TO_POINTER (1));
 +      }
 +      g_assert (feof (file));
 +}
 +
  gboolean mono_do_single_method_regression = FALSE;
  guint32 mono_single_method_regression_opt = 0;
  MonoMethod *mono_current_single_method;
@@@ -2188,13 -2122,6 +2188,13 @@@ mono_get_optimizations_for_method (Mono
  {
        g_assert (method);
  
 +      if (bisect_methods_hash) {
 +              char *name = mono_method_full_name (method, TRUE);
 +              void *res = g_hash_table_lookup (bisect_methods_hash, name);
 +              g_free (name);
 +              if (res)
 +                      return default_opt | bisect_opt;
 +      }
        if (!mono_do_single_method_regression)
                return default_opt;
        if (!mono_current_single_method) {
@@@ -2224,31 -2151,42 +2224,31 @@@ typedef struct 
        MonoVTable *vtable;
        MonoDynCallInfo *dyn_call_info;
        MonoClass *ret_box_class;
 -      gboolean needs_rgctx;
        MonoMethodSignature *sig;
 +      gboolean gsharedvt_invoke;
        gpointer *wrapper_arg;
  } RuntimeInvokeInfo;
  
 -gboolean
 -mini_gsharedvt_runtime_invoke_supported (MonoMethodSignature *sig)
 -{
 -      gboolean supported = TRUE;
 -      int i;
 -
 -      for (i = 0; i < sig->param_count; ++i) {
 -              MonoType *t = sig->params [i];
 -
 -              if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
 -                      supported = FALSE;
 -      }
 -
 -      return supported;
 -}
 -
  static RuntimeInvokeInfo*
 -create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer compiled_method)
 +create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer compiled_method, gboolean callee_gsharedvt, MonoError *error)
  {
        MonoMethod *invoke;
        RuntimeInvokeInfo *info;
  
        info = g_new0 (RuntimeInvokeInfo, 1);
 -      info->needs_rgctx = mono_llvm_only && mono_method_needs_static_rgctx_invoke (method, TRUE);
        info->compiled_method = compiled_method;
 +      if (mono_llvm_only && method->string_ctor)
 +              info->sig = mono_marshal_get_string_ctor_signature (method);
 +      else
 +              info->sig = mono_method_signature (method);
  
 -      invoke = mono_marshal_get_runtime_invoke (method, FALSE, info->needs_rgctx);
 -      info->vtable = mono_class_vtable_full (domain, method->klass, TRUE);
 +      invoke = mono_marshal_get_runtime_invoke (method, FALSE);
 +      info->vtable = mono_class_vtable_full (domain, method->klass, error);
 +      if (!mono_error_ok (error))
 +              return NULL;
        g_assert (info->vtable);
  
 -      MonoMethodSignature *sig = mono_method_signature (method);
 +      MonoMethodSignature *sig = info->sig;
        MonoType *ret_type;
  
        /*
  
                if (method->string_ctor)
                        sig = mono_marshal_get_string_ctor_signature (method);
 -              g_assert (!info->needs_rgctx);
  
                for (i = 0; i < sig->param_count; ++i) {
                        MonoType *t = sig->params [i];
  
        if (!info->dyn_call_info) {
                if (mono_llvm_only) {
 -                      gboolean supported;
 -
 -                      supported = mini_gsharedvt_runtime_invoke_supported (sig);
 -
 -                      if (mono_class_is_contextbound (method->klass) || !info->compiled_method)
 -                              supported = FALSE;
 -
 -#ifndef ENABLE_GSHAREDVT
 -                      supported = FALSE;
 +#ifndef MONO_ARCH_GSHAREDVT_SUPPORTED
 +                      g_assert_not_reached ();
  #endif
 -
 -                      if (supported) {
 +                      info->gsharedvt_invoke = TRUE;
 +                      if (!callee_gsharedvt) {
                                /* Invoke a gsharedvt out wrapper instead */
                                MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
                                MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
  
                                info->wrapper_arg = g_malloc0 (2 * sizeof (gpointer));
 -                              info->wrapper_arg [0] = info->compiled_method;
 -                              info->wrapper_arg [1] = mono_method_needs_static_rgctx_invoke (method, TRUE) ? mini_method_get_rgctx (method) : NULL;
 +                              info->wrapper_arg [0] = mini_add_method_wrappers_llvmonly (method, info->compiled_method, FALSE, FALSE, &(info->wrapper_arg [1]));
  
                                /* Pass has_rgctx == TRUE since the wrapper has an extra arg */
                                invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
                                g_free (wrapper_sig);
  
 -                              info->compiled_method = mono_jit_compile_method (wrapper);
 +                              info->compiled_method = mono_jit_compile_method (wrapper, error);
 +                              if (!mono_error_ok (error)) {
 +                                      g_free (info);
 +                                      return NULL;
 +                              }
 +                      } else {
 +                              /* Gsharedvt methods can be invoked the same way */
 +                              /* The out wrapper has the same signature as the compiled gsharedvt method */
 +                              MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
 +
 +                              info->wrapper_arg = mono_method_needs_static_rgctx_invoke (method, TRUE) ? mini_method_get_rgctx (method) : NULL;
 +
 +                              invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
 +                              g_free (wrapper_sig);
                        }
                }
 -              info->runtime_invoke = mono_jit_compile_method (invoke);
 +              info->runtime_invoke = mono_jit_compile_method (invoke, error);
 +              if (!mono_error_ok (error)) {
 +                      g_free (info);
 +                      return NULL;
 +              }
        }
  
        return info;
  }
  
 +static MonoObject*
 +mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void *obj, void **params, MonoObject **exc, MonoError *error)
 +{
 +      MonoMethodSignature *sig = info->sig;
 +      MonoDomain *domain = mono_domain_get ();
 +      MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
 +      gpointer *args;
 +      gpointer retval_ptr;
 +      guint8 retval [256];
 +      gpointer *param_refs;
 +      int i, pindex;
 +
 +      mono_error_init (error);
 +
 +      g_assert (info->gsharedvt_invoke);
 +
 +      /*
 +       * Instead of invoking the method directly, we invoke a gsharedvt out wrapper.
 +       * The advantage of this is the gsharedvt out wrappers have a reduced set of
 +       * signatures, so we only have to generate runtime invoke wrappers for these
 +       * signatures.
 +       * This code also handles invocation of gsharedvt methods directly, no
 +       * out wrappers are used in that case.
 +       */
 +      args = (void **)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
 +      param_refs = (gpointer*)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
 +      pindex = 0;
 +      /*
 +       * The runtime invoke wrappers expects pointers to primitive types, so have to
 +       * use indirections.
 +       */
 +      if (sig->hasthis)
 +              args [pindex ++] = &obj;
 +      if (sig->ret->type != MONO_TYPE_VOID) {
 +              retval_ptr = (gpointer)&retval;
 +              args [pindex ++] = &retval_ptr;
 +      }
 +      for (i = 0; i < sig->param_count; ++i) {
 +              MonoType *t = sig->params [i];
 +
 +              if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t))) {
 +                      MonoClass *klass = mono_class_from_mono_type (t);
 +                      guint8 *nullable_buf;
 +                      int size;
 +
 +                      size = mono_class_value_size (klass, NULL);
 +                      nullable_buf = g_alloca (size);
 +                      g_assert (nullable_buf);
 +
 +                      /* The argument pointed to by params [i] is either a boxed vtype or null */
 +                      mono_nullable_init (nullable_buf, (MonoObject*)params [i], klass);
 +                      params [i] = nullable_buf;
 +              }
 +
 +              if (!t->byref && (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR)) {
 +                      param_refs [i] = params [i];
 +                      params [i] = &(param_refs [i]);
 +              }
 +              args [pindex ++] = &params [i];
 +      }
 +      /* The gsharedvt out wrapper has an extra argument which contains the method to call */
 +      args [pindex ++] = &info->wrapper_arg;
 +
 +      runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
 +
 +      runtime_invoke (NULL, args, exc, info->compiled_method);
 +      if (exc && *exc)
 +              return NULL;
 +
 +      if (sig->ret->type != MONO_TYPE_VOID && info->ret_box_class)
 +              return mono_value_box_checked (domain, info->ret_box_class, retval, error);
 +      else
 +              return *(MonoObject**)retval;
 +}
 +
  /**
   * mono_jit_runtime_invoke:
   * @method: the method to invoke
   * @obj: this pointer
   * @params: array of parameter values.
 - * @exc: used to catch exceptions objects
 + * @exc: Set to the exception raised in the managed method.  If NULL, error is thrown instead.
 + *       If coop is enabled, this argument is ignored - all exceptoins are caught and propagated
 + *       through @error
 + * @error: error or caught exception object
   */
  static MonoObject*
 -mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
 +mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
  {
        MonoMethod *invoke, *callee;
        MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
        MonoDomain *domain = mono_domain_get ();
        MonoJitDomainInfo *domain_info;
        RuntimeInvokeInfo *info, *info2;
 +      MonoJitInfo *ji = NULL;
 +      gboolean callee_gsharedvt = FALSE;
 +
 +      mono_error_init (error);
  
        if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
                g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
                         * but keep it just in case for moonlight.
                         */
                        mono_class_setup_vtable (method->klass);
 -                      if (method->klass->exception_type != MONO_EXCEPTION_NONE) {
 +                      if (mono_class_has_failure (method->klass)) {
 +                              mono_error_set_for_class_failure (error, method->klass);
                                if (exc)
                                        *exc = (MonoObject*)mono_class_get_exception_for_failure (method->klass);
 -                              else
 -                                      mono_raise_exception (mono_class_get_exception_for_failure (method->klass));
                                return NULL;
                        }
                }
                                MonoMethod *wrapper;
  
                                wrapper = mono_marshal_get_array_accessor_wrapper (method);
 -                              invoke = mono_marshal_get_runtime_invoke (wrapper, FALSE, FALSE);
 +                              invoke = mono_marshal_get_runtime_invoke (wrapper, FALSE);
                                callee = wrapper;
                        } else {
                                callee = NULL;
                }
  
                if (callee) {
 -                      MonoException *jit_ex = NULL;
 -
 -                      compiled_method = mono_jit_compile_method_with_opt (callee, mono_get_optimizations_for_method (callee, default_opt), &jit_ex);
 +                      compiled_method = mono_jit_compile_method_with_opt (callee, mono_get_optimizations_for_method (callee, default_opt), error);
                        if (!compiled_method) {
 -                              g_assert (jit_ex);
 -                              if (exc) {
 -                                      *exc = (MonoObject*)jit_ex;
 -                                      return NULL;
 -                              } else {
 -                                      mono_raise_exception (jit_ex);
 -                                      /* coverity[unreachable] */
 -                              }
 +                              g_assert (!mono_error_ok (error));
 +                              return NULL;
                        }
  
 -                      compiled_method = mini_add_method_trampoline (callee, compiled_method, mono_method_needs_static_rgctx_invoke (callee, TRUE), FALSE);
 +                      if (mono_llvm_only) {
 +                              ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method), NULL);
 +                              callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
 +                              if (callee_gsharedvt)
 +                                      callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
 +                      }
 +
 +                      if (!callee_gsharedvt)
 +                              compiled_method = mini_add_method_trampoline (callee, compiled_method, mono_method_needs_static_rgctx_invoke (callee, TRUE), FALSE);
                } else {
                        compiled_method = NULL;
                }
  
 -              info = create_runtime_invoke_info (domain, method, compiled_method);
 +              info = create_runtime_invoke_info (domain, method, compiled_method, callee_gsharedvt, error);
 +              if (!mono_error_ok (error))
 +                      return NULL;
  
                mono_domain_lock (domain);
                info2 = (RuntimeInvokeInfo *)mono_conc_hashtable_insert (domain_info->runtime_invoke_hash, method, info);
         * We need this here because mono_marshal_get_runtime_invoke can place
         * the helper method in System.Object and not the target class.
         */
 -      if (exc) {
 -              *exc = (MonoObject*)mono_runtime_class_init_full (info->vtable, FALSE);
 -              if (*exc)
 -                      return NULL;
 -      } else {
 -              mono_runtime_class_init (info->vtable);
 +      if (!mono_runtime_class_init_full (info->vtable, error)) {
 +              if (exc)
 +                      *exc = (MonoObject*) mono_error_convert_to_exception (error);
 +              return NULL;
        }
  
 +      /* If coop is enabled, and the caller didn't ask for the exception to be caught separately,
 +         we always catch the exception and propagate it through the MonoError */
 +      gboolean catchExcInMonoError =
 +              (exc == NULL) && mono_threads_is_coop_enabled ();
 +      MonoObject *invoke_exc = NULL;
 +      if (catchExcInMonoError)
 +              exc = &invoke_exc;
 +
        /* The wrappers expect this to be initialized to NULL */
        if (exc)
                *exc = NULL;
                int i, pindex;
                guint8 buf [512];
                guint8 retval [256];
 -              gpointer rgctx;
  
                if (!dyn_runtime_invoke) {
                        invoke = mono_marshal_get_runtime_invoke_dynamic ();
 -                      dyn_runtime_invoke = (RuntimeInvokeDynamicFunction)mono_jit_compile_method (invoke);
 +                      dyn_runtime_invoke = (RuntimeInvokeDynamicFunction)mono_jit_compile_method (invoke, error);
 +                      if (!mono_error_ok (error))
 +                              return NULL;
                }
  
                /* Convert the arguments to the format expected by start_dyn_call () */
 -              args = (void **)g_alloca ((sig->param_count + sig->hasthis + info->needs_rgctx) * sizeof (gpointer));
 +              args = (void **)g_alloca ((sig->param_count + sig->hasthis) * sizeof (gpointer));
                pindex = 0;
                if (sig->hasthis)
                        args [pindex ++] = &obj;
                                args [pindex ++] = params [i];
                        }
                }
 -              if (info->needs_rgctx) {
 -                      rgctx = mini_method_get_rgctx (method);
 -                      args [pindex ++] = &rgctx;
 -              }
  
                //printf ("M: %s\n", mono_method_full_name (method, TRUE));
  
                mono_arch_start_dyn_call (info->dyn_call_info, (gpointer**)args, retval, buf, sizeof (buf));
  
                dyn_runtime_invoke (buf, exc, info->compiled_method);
 -
                mono_arch_finish_dyn_call (info->dyn_call_info, buf);
  
 -              if (info->ret_box_class)
 -                      return mono_value_box (domain, info->ret_box_class, retval);
 -              else
 -                      return *(MonoObject**)retval;
 -      }
 -#endif
 -
 -      runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
 -
 -      if (info->wrapper_arg) {
 -              MonoMethodSignature *sig = mono_method_signature (method);
 -              gpointer *args;
 -              gpointer retval_ptr;
 -              guint8 retval [256];
 -              gpointer *param_refs;
 -              int i, pindex;
 -
 -              /*
 -               * Instead of invoking the method directly, we invoke a gsharedvt out wrapper.
 -               * The advantage of this is the gsharedvt out wrappers have a reduced set of
 -               * signatures, so we only have to generate runtime invoke wrappers for these
 -               * signatures.
 -               */
 -              args = (void **)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
 -              param_refs = (gpointer*)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
 -              pindex = 0;
 -              /*
 -               * The runtime invoke wrappers expects pointers to primitive types, so have to
 -               * use indirections.
 -               */
 -              if (sig->hasthis)
 -                      args [pindex ++] = &obj;
 -              if (sig->ret->type != MONO_TYPE_VOID) {
 -                      retval_ptr = (gpointer)&retval;
 -                      args [pindex ++] = &retval_ptr;
 -              }
 -              for (i = 0; i < sig->param_count; ++i) {
 -                      MonoType *t = sig->params [i];
 -
 -                      if (MONO_TYPE_IS_REFERENCE (t)) {
 -                              param_refs [i] = params [i];
 -                              params [i] = &(param_refs [i]);
 -                      }
 -                      args [pindex ++] = &params [i];
 +              if (catchExcInMonoError && *exc != NULL) {
 +                      mono_error_set_exception_instance (error, (MonoException*) *exc);
 +                      return NULL;
                }
 -              /* The gsharedvt out wrapper has an extra argument which contains the method to call */
 -              args [pindex ++] = &info->wrapper_arg;
 -              runtime_invoke (NULL, args, exc, info->compiled_method);
  
 -              if (sig->ret->type != MONO_TYPE_VOID && info->ret_box_class)
 -                              return mono_value_box (domain, info->ret_box_class, retval);
 +              if (info->ret_box_class)
 +                      return mono_value_box_checked (domain, info->ret_box_class, retval, error);
                else
                        return *(MonoObject**)retval;
        }
 +#endif
  
 -      // FIXME: Cache this
 -      if (info->needs_rgctx) {
 -              MonoMethodSignature *sig = mono_method_signature (method);
 -              gpointer rgctx;
 -              gpointer *args;
 -              int i, pindex;
 +      MonoObject *result;
  
 -              args = (void **)g_alloca ((sig->param_count + sig->hasthis + info->needs_rgctx) * sizeof (gpointer));
 -              pindex = 0;
 -              rgctx = mini_method_get_rgctx (method);
 -              for (i = 0; i < sig->param_count; ++i)
 -                      args [pindex ++] = params [i];
 -              args [pindex ++] = &rgctx;
 -              return runtime_invoke ((MonoObject *)obj, args, exc, info->compiled_method);
 +      if (mono_llvm_only) {
 +              result = mono_llvmonly_runtime_invoke (method, info, obj, params, exc, error);
 +              if (!is_ok (error))
 +                      return NULL;
        } else {
 -              return runtime_invoke ((MonoObject *)obj, params, exc, info->compiled_method);
 +              runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
 +
 +              result = runtime_invoke ((MonoObject *)obj, params, exc, info->compiled_method);
        }
 +      if (catchExcInMonoError && *exc != NULL)
 +              mono_error_set_exception_instance (error, (MonoException*) *exc);
 +      return result;
  }
  
  typedef struct {
        MonoVTable *vtable;
        int slot;
 -} IMTThunkInfo;
 +} IMTTrampInfo;
  
 -typedef gpointer (*IMTThunkFunc) (gpointer *arg, MonoMethod *imt_method);
 +typedef gpointer (*IMTTrampFunc) (gpointer *arg, MonoMethod *imt_method);
  
  /*
 - * mini_llvmonly_initial_imt_thunk:
 + * mini_llvmonly_initial_imt_tramp:
   *
 - *  This function is called the first time a call is made through an IMT thunk.
 - * It should have the same signature as the mono_llvmonly_imt_thunk_... functions.
 + *  This function is called the first time a call is made through an IMT trampoline.
 + * It should have the same signature as the mono_llvmonly_imt_tramp_... functions.
   */
  static gpointer
 -mini_llvmonly_initial_imt_thunk (gpointer *arg, MonoMethod *imt_method)
 +mini_llvmonly_initial_imt_tramp (gpointer *arg, MonoMethod *imt_method)
  {
 -      IMTThunkInfo *info = (IMTThunkInfo*)arg;
 +      IMTTrampInfo *info = (IMTTrampInfo*)arg;
        gpointer *imt;
        gpointer *ftndesc;
 -      IMTThunkFunc func;
 +      IMTTrampFunc func;
  
        mono_vtable_build_imt_slot (info->vtable, info->slot);
  
        imt = (gpointer*)info->vtable;
        imt -= MONO_IMT_SIZE;
  
 -      /* Return what the real IMT thunk returns */
 +      /* Return what the real IMT trampoline returns */
        ftndesc = imt [info->slot];
        func = ftndesc [0];
  
 -      if (func == (IMTThunkFunc)mini_llvmonly_initial_imt_thunk)
 +      if (func == (IMTTrampFunc)mini_llvmonly_initial_imt_tramp)
                /* Happens when the imt slot contains only a generic virtual method */
                return NULL;
        return func ((gpointer *)ftndesc [1], imt_method);
  
  /* This is called indirectly through an imt slot. */
  static gpointer
 -mono_llvmonly_imt_thunk (gpointer *arg, MonoMethod *imt_method)
 +mono_llvmonly_imt_tramp (gpointer *arg, MonoMethod *imt_method)
  {
        int i = 0;
  
 -      /* arg points to an array created in mono_llvmonly_get_imt_thunk () */
 +      /* arg points to an array created in mono_llvmonly_get_imt_trampoline () */
        while (arg [i] && arg [i] != imt_method)
                i += 2;
        g_assert (arg [i]);
        return arg [i + 1];
  }
  
 -/* Optimized versions of mono_llvmonly_imt_thunk () for different table sizes */
 +/* Optimized versions of mono_llvmonly_imt_trampoline () for different table sizes */
  static gpointer
 -mono_llvmonly_imt_thunk_1 (gpointer *arg, MonoMethod *imt_method)
 +mono_llvmonly_imt_tramp_1 (gpointer *arg, MonoMethod *imt_method)
  {
        //g_assert (arg [0] == imt_method);
        return arg [1];
  }
  
  static gpointer
 -mono_llvmonly_imt_thunk_2 (gpointer *arg, MonoMethod *imt_method)
 +mono_llvmonly_imt_tramp_2 (gpointer *arg, MonoMethod *imt_method)
  {
        //g_assert (arg [0] == imt_method || arg [2] == imt_method);
        if (arg [0] == imt_method)
  }
  
  static gpointer
 -mono_llvmonly_imt_thunk_3 (gpointer *arg, MonoMethod *imt_method)
 +mono_llvmonly_imt_tramp_3 (gpointer *arg, MonoMethod *imt_method)
  {
        //g_assert (arg [0] == imt_method || arg [2] == imt_method || arg [4] == imt_method);
        if (arg [0] == imt_method)
  }
  
  /*
 - * A version of the imt thunk used for generic virtual methods.
 - * Unlikely a normal imt thunk, its possible that IMT_METHOD is not found
 + * A version of the imt trampoline used for generic virtual/variant iface methods.
 + * Unlikely a normal imt trampoline, its possible that IMT_METHOD is not found
   * in the search table. The original JIT code had a 'fallback' trampoline it could
   * call, but we can't do that, so we just return NULL, and the compiled code
   * will handle it.
   */
  static gpointer
 -mono_llvmonly_generic_virtual_imt_thunk (gpointer *arg, MonoMethod *imt_method)
 +mono_llvmonly_fallback_imt_tramp (gpointer *arg, MonoMethod *imt_method)
  {
        int i = 0;
  
  }
  
  static gpointer
 -mono_llvmonly_get_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count, gpointer fail_tramp)
 +mono_llvmonly_get_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count, gpointer fail_tramp)
  {
        gpointer *buf;
        gpointer *res;
        gboolean virtual_generic = FALSE;
  
        /*
 -       * Create an array which is passed to the imt thunk functions.
 +       * Create an array which is passed to the imt trampoline functions.
         * The array contains MonoMethod-function descriptor pairs, terminated by a NULL entry.
         */
  
        res = (void **)mono_domain_alloc (domain, 2 * sizeof (gpointer));
        switch (real_count) {
        case 1:
 -              res [0] = mono_llvmonly_imt_thunk_1;
 +              res [0] = mono_llvmonly_imt_tramp_1;
                break;
        case 2:
 -              res [0] = mono_llvmonly_imt_thunk_2;
 +              res [0] = mono_llvmonly_imt_tramp_2;
                break;
        case 3:
 -              res [0] = mono_llvmonly_imt_thunk_3;
 +              res [0] = mono_llvmonly_imt_tramp_3;
                break;
        default:
 -              res [0] = mono_llvmonly_imt_thunk;
 +              res [0] = mono_llvmonly_imt_tramp;
                break;
        }
 -      if (virtual_generic)
 -              res [0] = mono_llvmonly_generic_virtual_imt_thunk;
 +      if (virtual_generic || fail_tramp)
 +              res [0] = mono_llvmonly_fallback_imt_tramp;
        res [1] = buf;
  
        return res;
@@@ -2856,16 -2747,9 +2856,16 @@@ MONO_SIG_HANDLER_FUNC (, mono_sigill_si
        MonoException *exc;
        MONO_SIG_HANDLER_GET_CONTEXT;
  
 +      if (mono_runtime_get_no_exec ())
 +              exit (1);
 +
 +      MONO_ENTER_GC_UNSAFE_UNBALANCED;
 +
        exc = mono_get_exception_execution_engine ("SIGILL");
  
        mono_arch_handle_exception (ctx, exc);
 +
 +      MONO_EXIT_GC_UNSAFE_UNBALANCED;
  }
  
  #if defined(MONO_ARCH_USE_SIGACTION) || defined(HOST_WIN32)
@@@ -2986,36 -2870,35 +2986,36 @@@ MONO_SIG_HANDLER_FUNC (, mono_sigint_si
   * Returns: a pointer to the newly created code
   */
  static gpointer
 -mono_jit_create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
 +mono_jit_create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
  {
        MonoMethod *nm;
        guint8 *addr = NULL;
  
 +      mono_error_init (error);
 +
        if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && mono_method_signature (method)->generic_param_count) {
                return mono_create_specific_trampoline (method, MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING,
                        domain, NULL);
        }
  
        if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
 -          (mono_method_signature (method)->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))) {
 +          (mono_method_signature (method)->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class)))
                nm = mono_marshal_get_remoting_invoke_for_target (method, target);
 -              addr = (guint8 *)mono_compile_method (nm);
 -      } else
 -      {
 -              addr = (guint8 *)mono_compile_method (method);
 -      }
 +      else
 +              nm = method;
 +      addr = (guint8 *)mono_compile_method_checked (nm, error);
 +      return_val_if_nok (error, NULL);
        return mono_get_addr_from_ftnptr (addr);
  }
  #endif
  
 -static void
 +static G_GNUC_UNUSED void
  no_imt_trampoline (void)
  {
        g_assert_not_reached ();
  }
  
 -static void
 +static G_GNUC_UNUSED void
  no_vcall_trampoline (void)
  {
        g_assert_not_reached ();
@@@ -3031,13 -2914,13 +3031,13 @@@ mini_get_vtable_trampoline (MonoVTable 
  
        if (mono_llvm_only) {
                if (slot_index < 0) {
 -                      /* Initialize the IMT thunks to a 'trampoline' so the generated code doesn't have to initialize it */
 +                      /* Initialize the IMT trampoline to a 'trampoline' so the generated code doesn't have to initialize it */
                        // FIXME: Memory management
                        gpointer *ftndesc = g_malloc (2 * sizeof (gpointer));
 -                      IMTThunkInfo *info = g_new0 (IMTThunkInfo, 1);
 +                      IMTTrampInfo *info = g_new0 (IMTTrampInfo, 1);
                        info->vtable = vt;
                        info->slot = index;
 -                      ftndesc [0] = mini_llvmonly_initial_imt_thunk;
 +                      ftndesc [0] = mini_llvmonly_initial_imt_tramp;
                        ftndesc [1] = info;
                        mono_memory_barrier ();
                        return ftndesc;
@@@ -3091,59 -2974,6 +3091,59 @@@ mini_imt_entry_inited (MonoVTable *vt, 
        return (imt [imt_slot_index] != mini_get_imt_trampoline (vt, imt_slot_index));
  }
  
 +static gboolean
 +is_callee_gsharedvt_variable (gpointer addr)
 +{
 +      MonoJitInfo *ji;
 +      gboolean callee_gsharedvt;
 +
 +      ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
 +      g_assert (ji);
 +      callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
 +      if (callee_gsharedvt)
 +              callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
 +      return callee_gsharedvt;
 +}
 +
 +gpointer
 +mini_get_delegate_arg (MonoMethod *method, gpointer method_ptr)
 +{
 +      gpointer arg = NULL;
 +
 +      if (mono_method_needs_static_rgctx_invoke (method, FALSE))
 +              arg = mini_method_get_rgctx (method);
 +
 +      /*
 +       * Avoid adding gsharedvt in wrappers since they might not exist if
 +       * this delegate is called through a gsharedvt delegate invoke wrapper.
 +       * Instead, encode that the method is gsharedvt in del->extra_arg,
 +       * the CEE_MONO_CALLI_EXTRA_ARG implementation in the JIT depends on this.
 +       */
 +      if (method->is_inflated && is_callee_gsharedvt_variable (method_ptr)) {
 +              g_assert ((((mgreg_t)arg) & 1) == 0);
 +              arg = (gpointer)(((mgreg_t)arg) | 1);
 +      }
 +      return arg;
 +}
 +
 +void
 +mini_init_delegate (MonoDelegate *del)
 +{
 +      if (mono_llvm_only)
 +              del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr);
 +}
 +
 +char*
 +mono_get_delegate_virtual_invoke_impl_name (gboolean load_imt_reg, int offset)
 +{
 +      int abs_offset;
 +
 +      abs_offset = offset;
 +      if (abs_offset < 0)
 +              abs_offset = - abs_offset;
 +      return g_strdup_printf ("delegate_virtual_invoke%s_%s%d", load_imt_reg ? "_imt" : "", offset < 0 ? "m_" : "", abs_offset / SIZEOF_VOID_P);
 +}
 +
  gpointer
  mono_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method)
  {
                return NULL;
  
        is_virtual_generic = method->is_inflated && mono_method_get_declaring_generic_method (method)->is_generic;
 -      is_interface = method->klass->flags & TYPE_ATTRIBUTE_INTERFACE ? TRUE : FALSE;
 +      is_interface = mono_class_is_interface (method->klass);
        load_imt_reg = is_virtual_generic || is_interface;
  
 -      if (is_interface && !is_virtual_generic)
 +      if (is_interface)
                offset = ((gint32)mono_method_get_imt_slot (method) - MONO_IMT_SIZE) * SIZEOF_VOID_P;
        else
                offset = G_STRUCT_OFFSET (MonoVTable, vtable) + ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
  
        /* FIXME Support more cases */
        if (mono_aot_only) {
 -              char tramp_name [256];
 -              const char *imt = load_imt_reg ? "_imt" : "";
 -              int ind = (load_imt_reg ? (-offset) : offset) / SIZEOF_VOID_P;
 -
 -              sprintf (tramp_name, "delegate_virtual_invoke%s_%d", imt, ind);
 -              cache [idx] = (guint8 *)mono_aot_get_trampoline (tramp_name);
 +              cache [idx] = (guint8 *)mono_aot_get_trampoline (mono_get_delegate_virtual_invoke_impl_name (load_imt_reg, offset));
                g_assert (cache [idx]);
        } else {
                cache [idx] = (guint8 *)mono_arch_get_delegate_virtual_invoke_impl (sig, method, offset, load_imt_reg);
        return cache [idx];
  }
  
 +/**
 + * mini_parse_debug_option:
 + * @option: The option to parse.
 + *
 + * Parses debug options for the mono runtime. The options are the same as for
 + * the MONO_DEBUG environment variable.
 + *
 + */
 +gboolean
 +mini_parse_debug_option (const char *option)
 +{
 +      if (!strcmp (option, "handle-sigint"))
 +              debug_options.handle_sigint = TRUE;
 +      else if (!strcmp (option, "keep-delegates"))
 +              debug_options.keep_delegates = TRUE;
 +      else if (!strcmp (option, "reverse-pinvoke-exceptions"))
 +              debug_options.reverse_pinvoke_exceptions = TRUE;
 +      else if (!strcmp (option, "collect-pagefault-stats"))
 +              debug_options.collect_pagefault_stats = TRUE;
 +      else if (!strcmp (option, "break-on-unverified"))
 +              debug_options.break_on_unverified = TRUE;
 +      else if (!strcmp (option, "no-gdb-backtrace"))
 +              debug_options.no_gdb_backtrace = TRUE;
 +      else if (!strcmp (option, "suspend-on-sigsegv"))
 +              debug_options.suspend_on_sigsegv = TRUE;
 +      else if (!strcmp (option, "suspend-on-exception"))
 +              debug_options.suspend_on_exception = TRUE;
 +      else if (!strcmp (option, "suspend-on-unhandled"))
 +              debug_options.suspend_on_unhandled = TRUE;
 +      else if (!strcmp (option, "dont-free-domains"))
 +              mono_dont_free_domains = TRUE;
 +      else if (!strcmp (option, "dyn-runtime-invoke"))
 +              debug_options.dyn_runtime_invoke = TRUE;
 +      else if (!strcmp (option, "gdb"))
 +              debug_options.gdb = TRUE;
 +      else if (!strcmp (option, "explicit-null-checks"))
 +              debug_options.explicit_null_checks = TRUE;
 +      else if (!strcmp (option, "gen-seq-points"))
 +              debug_options.gen_sdb_seq_points = TRUE;
 +      else if (!strcmp (option, "gen-compact-seq-points"))
 +              fprintf (stderr, "Mono Warning: option gen-compact-seq-points is deprecated.\n");
 +      else if (!strcmp (option, "no-compact-seq-points"))
 +              debug_options.no_seq_points_compact_data = TRUE;
 +      else if (!strcmp (option, "single-imm-size"))
 +              debug_options.single_imm_size = TRUE;
 +      else if (!strcmp (option, "init-stacks"))
 +              debug_options.init_stacks = TRUE;
 +      else if (!strcmp (option, "casts"))
 +              debug_options.better_cast_details = TRUE;
 +      else if (!strcmp (option, "soft-breakpoints"))
 +              debug_options.soft_breakpoints = TRUE;
 +      else if (!strcmp (option, "check-pinvoke-callconv"))
 +              debug_options.check_pinvoke_callconv = TRUE;
 +      else if (!strcmp (option, "arm-use-fallback-tls"))
 +              debug_options.arm_use_fallback_tls = TRUE;
 +      else if (!strcmp (option, "debug-domain-unload"))
 +              mono_enable_debug_domain_unload (TRUE);
 +      else if (!strcmp (option, "partial-sharing"))
 +              mono_set_partial_sharing_supported (TRUE);
 +      else if (!strcmp (option, "align-small-structs"))
 +              mono_align_small_structs = TRUE;
 +      else if (!strcmp (option, "native-debugger-break"))
 +              debug_options.native_debugger_break = TRUE;
 +      else if (!strcmp (option, "disable_omit_fp"))
 +              debug_options.disable_omit_fp = TRUE;
 +      else
 +              return FALSE;
 +
 +      return TRUE;
 +}
 +
  static void
  mini_parse_debug_options (void)
  {
        for (ptr = args; ptr && *ptr; ptr++) {
                const char *arg = *ptr;
  
 -              if (!strcmp (arg, "handle-sigint"))
 -                      debug_options.handle_sigint = TRUE;
 -              else if (!strcmp (arg, "keep-delegates"))
 -                      debug_options.keep_delegates = TRUE;
 -              else if (!strcmp (arg, "reverse-pinvoke-exceptions"))
 -                      debug_options.reverse_pinvoke_exceptions = TRUE;
 -              else if (!strcmp (arg, "collect-pagefault-stats"))
 -                      debug_options.collect_pagefault_stats = TRUE;
 -              else if (!strcmp (arg, "break-on-unverified"))
 -                      debug_options.break_on_unverified = TRUE;
 -              else if (!strcmp (arg, "no-gdb-backtrace"))
 -                      debug_options.no_gdb_backtrace = TRUE;
 -              else if (!strcmp (arg, "suspend-on-sigsegv"))
 -                      debug_options.suspend_on_sigsegv = TRUE;
 -              else if (!strcmp (arg, "suspend-on-exception"))
 -                      debug_options.suspend_on_exception = TRUE;
 -              else if (!strcmp (arg, "suspend-on-unhandled"))
 -                      debug_options.suspend_on_unhandled = TRUE;
 -              else if (!strcmp (arg, "dont-free-domains"))
 -                      mono_dont_free_domains = TRUE;
 -              else if (!strcmp (arg, "dyn-runtime-invoke"))
 -                      debug_options.dyn_runtime_invoke = TRUE;
 -              else if (!strcmp (arg, "gdb"))
 -                      debug_options.gdb = TRUE;
 -              else if (!strcmp (arg, "explicit-null-checks"))
 -                      debug_options.explicit_null_checks = TRUE;
 -              else if (!strcmp (arg, "gen-seq-points"))
 -                      debug_options.gen_sdb_seq_points = TRUE;
 -              else if (!strcmp (arg, "gen-compact-seq-points"))
 -                      debug_options.gen_seq_points_compact_data = TRUE;
 -              else if (!strcmp (arg, "single-imm-size"))
 -                      debug_options.single_imm_size = TRUE;
 -              else if (!strcmp (arg, "init-stacks"))
 -                      debug_options.init_stacks = TRUE;
 -              else if (!strcmp (arg, "casts"))
 -                      debug_options.better_cast_details = TRUE;
 -              else if (!strcmp (arg, "soft-breakpoints"))
 -                      debug_options.soft_breakpoints = TRUE;
 -              else if (!strcmp (arg, "check-pinvoke-callconv"))
 -                      debug_options.check_pinvoke_callconv = TRUE;
 -              else if (!strcmp (arg, "arm-use-fallback-tls"))
 -                      debug_options.arm_use_fallback_tls = TRUE;
 -              else if (!strcmp (arg, "debug-domain-unload"))
 -                      mono_enable_debug_domain_unload (TRUE);
 -              else if (!strcmp (arg, "partial-sharing"))
 -                      mono_set_partial_sharing_supported (TRUE);
 -              else if (!strcmp (arg, "align-small-structs"))
 -                      mono_align_small_structs = TRUE;
 -              else if (!strcmp (arg, "native-debugger-break"))
 -                      debug_options.native_debugger_break = TRUE;
 -              else {
 +              if (!mini_parse_debug_option (arg)) {
                        fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
 -                      fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'reverse-pinvoke-exceptions', 'collect-pagefault-stats', 'break-on-unverified', 'no-gdb-backtrace', 'suspend-on-sigsegv', 'suspend-on-exception', 'suspend-on-unhandled', 'dont-free-domains', 'dyn-runtime-invoke', 'gdb', 'explicit-null-checks', 'gen-seq-points', 'gen-compact-seq-points', 'single-imm-size', 'init-stacks', 'casts', 'soft-breakpoints', 'check-pinvoke-callconv', 'arm-use-fallback-tls', 'debug-domain-unload', 'partial-sharing', 'align-small-structs', 'native-debugger-break'\n");
 +                      fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'reverse-pinvoke-exceptions', 'collect-pagefault-stats', 'break-on-unverified', 'no-gdb-backtrace', 'suspend-on-sigsegv', 'suspend-on-exception', 'suspend-on-unhandled', 'dont-free-domains', 'dyn-runtime-invoke', 'gdb', 'explicit-null-checks', 'gen-seq-points', 'no-compact-seq-points', 'single-imm-size', 'init-stacks', 'casts', 'soft-breakpoints', 'check-pinvoke-callconv', 'arm-use-fallback-tls', 'debug-domain-unload', 'partial-sharing', 'align-small-structs', 'native-debugger-break'\n");
                        exit (1);
                }
        }
@@@ -3349,44 -3163,6 +3349,44 @@@ register_jit_stats (void
        mono_counters_register ("Methods from AOT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_aot);
        mono_counters_register ("Methods JITted using mono JIT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_without_llvm);
        mono_counters_register ("Methods JITted using LLVM", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_with_llvm);
 +      mono_counters_register ("JIT/method_to_ir (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_method_to_ir);
 +      mono_counters_register ("JIT/liveness_handle_exception_clauses (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_liveness_handle_exception_clauses);
 +      mono_counters_register ("JIT/handle_out_of_line_bblock (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_out_of_line_bblock);
 +      mono_counters_register ("JIT/decompose_long_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_long_opts);
 +      mono_counters_register ("JIT/decompose_typechecks (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_typechecks);
 +      mono_counters_register ("JIT/local_cprop (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop);
 +      mono_counters_register ("JIT/local_emulate_ops (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_emulate_ops);
 +      mono_counters_register ("JIT/optimize_branches (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_optimize_branches);
 +      mono_counters_register ("JIT/handle_global_vregs (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_global_vregs);
 +      mono_counters_register ("JIT/local_deadce (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce);
 +      mono_counters_register ("JIT/local_alias_analysis (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_alias_analysis);
 +      mono_counters_register ("JIT/if_conversion (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_if_conversion);
 +      mono_counters_register ("JIT/bb_ordering (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_bb_ordering);
 +      mono_counters_register ("JIT/compile_dominator_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_compile_dominator_info);
 +      mono_counters_register ("JIT/compute_natural_loops (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_compute_natural_loops);
 +      mono_counters_register ("JIT/insert_safepoints (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_insert_safepoints);
 +      mono_counters_register ("JIT/ssa_compute (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_compute);
 +      mono_counters_register ("JIT/ssa_cprop (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_cprop);
 +      mono_counters_register ("JIT/ssa_deadce(sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_deadce);
 +      mono_counters_register ("JIT/perform_abc_removal (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_perform_abc_removal);
 +      mono_counters_register ("JIT/ssa_remove (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_ssa_remove);
 +      mono_counters_register ("JIT/local_cprop2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop2);
 +      mono_counters_register ("JIT/handle_global_vregs2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_global_vregs2);
 +      mono_counters_register ("JIT/local_deadce2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce2);
 +      mono_counters_register ("JIT/optimize_branches2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_optimize_branches2);
 +      mono_counters_register ("JIT/decompose_vtype_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_vtype_opts);
 +      mono_counters_register ("JIT/decompose_array_access_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_array_access_opts);
 +      mono_counters_register ("JIT/liveness_handle_exception_clauses2 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_liveness_handle_exception_clauses2);
 +      mono_counters_register ("JIT/analyze_liveness (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_analyze_liveness);
 +      mono_counters_register ("JIT/linear_scan (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_linear_scan);
 +      mono_counters_register ("JIT/arch_allocate_vars (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_arch_allocate_vars);
 +      mono_counters_register ("JIT/spill_global_vars (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_spill_global_vars);
 +      mono_counters_register ("JIT/local_cprop3 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop3);
 +      mono_counters_register ("JIT/local_deadce3 (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_deadce3);
 +      mono_counters_register ("JIT/codegen (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_codegen);
 +      mono_counters_register ("JIT/create_jit_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_create_jit_info);
 +      mono_counters_register ("JIT/gc_create_gc_map (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_gc_create_gc_map);
 +      mono_counters_register ("JIT/save_seq_point_info (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_save_seq_point_info);
        mono_counters_register ("Total time spent JITting (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_time);
        mono_counters_register ("Basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.basic_blocks);
        mono_counters_register ("Max basic blocks", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.max_basic_blocks);
        mono_counters_register ("Aliases eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_removed);
        mono_counters_register ("Aliased loads eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.loads_eliminated);
        mono_counters_register ("Aliased stores eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.stores_eliminated);
 +      mono_counters_register ("Optimized immediate divisions", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.optimized_divisions);
  }
  
  static void runtime_invoke_info_free (gpointer value);
@@@ -3478,12 -3253,6 +3478,12 @@@ runtime_invoke_info_free (gpointer valu
        g_free (info);
  }
  
 +static void
 +free_jit_callee_list (gpointer key, gpointer value, gpointer user_data)
 +{
 +      g_slist_free (value);
 +}
 +
  static void
  mini_free_jit_domain_info (MonoDomain *domain)
  {
                mono_debugger_agent_free_domain_info (domain);
        if (info->gsharedvt_arg_tramp_hash)
                g_hash_table_destroy (info->gsharedvt_arg_tramp_hash);
 +      if (info->llvm_jit_callees) {
 +              g_hash_table_foreach (info->llvm_jit_callees, free_jit_callee_list, NULL);
 +              g_hash_table_destroy (info->llvm_jit_callees);
 +      }
  #ifdef ENABLE_LLVM
        mono_llvm_free_domain_info (domain);
  #endif
@@@ -3566,7 -3331,6 +3566,7 @@@ mini_llvm_init (void
  MonoDomain *
  mini_init (const char *filename, const char *runtime_version)
  {
 +      MonoError error;
        MonoDomain *domain;
        MonoRuntimeCallbacks callbacks;
        MonoThreadInfoRuntimeCallbacks ticallbacks;
        callbacks.debug_log = mono_debugger_agent_debug_log;
        callbacks.debug_log_is_enabled = mono_debugger_agent_debug_log_is_enabled;
        callbacks.tls_key_supported = mini_tls_key_supported;
 -
        callbacks.get_vtable_trampoline = mini_get_vtable_trampoline;
        callbacks.get_imt_trampoline = mini_get_imt_trampoline;
        callbacks.imt_entry_inited = mini_imt_entry_inited;
 +      callbacks.init_delegate = mini_init_delegate;
 +#define JIT_INVOKE_WORKS
 +#ifdef JIT_INVOKE_WORKS
 +      callbacks.runtime_invoke = mono_jit_runtime_invoke;
 +#endif
 +#define JIT_TRAMPOLINES_WORK
 +#ifdef JIT_TRAMPOLINES_WORK
 +      callbacks.compile_method = mono_jit_compile_method;
 +      callbacks.create_jump_trampoline = mono_create_jump_trampoline;
 +      callbacks.create_jit_trampoline = mono_create_jit_trampoline;
 +#endif
  
        mono_install_callbacks (&callbacks);
  
  
        mono_counters_init ();
  
 +#ifndef HOST_WIN32
 +      mono_w32handle_init ();
 +#endif
 +
        mono_threads_runtime_init (&ticallbacks);
  
        if (g_getenv ("MONO_DEBUG") != NULL)
  #endif
        mono_threads_install_cleanup (mini_thread_cleanup);
  
 -#define JIT_TRAMPOLINES_WORK
  #ifdef JIT_TRAMPOLINES_WORK
 -      mono_install_compile_method (mono_jit_compile_method);
        mono_install_free_method (mono_jit_free_method);
 -      mono_install_trampoline (mono_create_jit_trampoline);
 -      mono_install_jump_trampoline (mono_create_jump_trampoline);
  #ifndef DISABLE_REMOTING
        mono_install_remoting_trampoline (mono_jit_create_remoting_trampoline);
  #endif
        mono_install_delegate_trampoline (mono_create_delegate_trampoline);
        mono_install_create_domain_hook (mini_create_jit_domain_info);
        mono_install_free_domain_hook (mini_free_jit_domain_info);
 -#endif
 -#define JIT_INVOKE_WORKS
 -#ifdef JIT_INVOKE_WORKS
 -      mono_install_runtime_invoke (mono_jit_runtime_invoke);
  #endif
        mono_install_get_cached_class_info (mono_aot_get_cached_class_info);
        mono_install_get_class_from_name (mono_aot_get_class_from_name);
        }
  
        if (mono_llvm_only) {
 -              mono_install_imt_thunk_builder (mono_llvmonly_get_imt_thunk);
 -              mono_set_always_build_imt_thunks (TRUE);
 +              mono_install_imt_trampoline_builder (mono_llvmonly_get_imt_trampoline);
 +              mono_set_always_build_imt_trampolines (TRUE);
        } else if (mono_aot_only) {
 -              mono_install_imt_thunk_builder (mono_aot_get_imt_thunk);
 +              mono_install_imt_trampoline_builder (mono_aot_get_imt_trampoline);
        } else {
 -              mono_install_imt_thunk_builder (mono_arch_build_imt_thunk);
 +              mono_install_imt_trampoline_builder (mono_arch_build_imt_trampoline);
        }
  
        /*Init arch tls information only after the metadata side is inited to make sure we see dynamic appdomain tls keys*/
        mono_simd_intrinsics_init ();
  #endif
  
 -#if MONO_SUPPORT_TASKLETS
        mono_tasklets_init ();
 -#endif
  
        register_trampolines (domain);
  
                 */
                mono_runtime_set_no_exec (TRUE);
  
 +      mono_mem_account_register_counters ();
 +
  #define JIT_RUNTIME_WORKS
  #ifdef JIT_RUNTIME_WORKS
        mono_install_runtime_cleanup ((MonoDomainFunc)mini_cleanup);
 -      mono_runtime_init (domain, mono_thread_start_cb, mono_thread_attach_cb);
 +      mono_runtime_init_checked (domain, mono_thread_start_cb, mono_thread_attach_cb, &error);
 +      mono_error_assert_ok (&error);
        mono_thread_attach (domain);
  #endif
  
 +      if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
 +              mono_runtime_setup_stat_profiler ();
 +
        mono_profiler_runtime_initialized ();
  
        MONO_VES_INIT_END ();
@@@ -3817,8 -3571,6 +3817,8 @@@ register_icalls (void
                                ves_icall_get_trace);
        mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers",
                                mono_runtime_install_handlers);
 +      mono_add_internal_call ("Mono.Runtime::mono_runtime_cleanup_handlers",
 +                              mono_runtime_cleanup_handlers);
  
  #if defined(PLATFORM_ANDROID) || defined(TARGET_ANDROID)
        mono_add_internal_call ("System.Diagnostics.Debugger::Mono_UnhandledException_internal",
        register_icall (mono_llvm_match_exception, "mono_llvm_match_exception", "int ptr int int", TRUE);
        register_icall (mono_llvm_clear_exception, "mono_llvm_clear_exception", NULL, TRUE);
        register_icall (mono_llvm_load_exception, "mono_llvm_load_exception", "object", TRUE);
 -      register_icall (mono_llvm_throw_corlib_exception, "mono_llvm_throw_corlib_exception", "void int", FALSE);
 +      register_icall (mono_llvm_throw_corlib_exception, "mono_llvm_throw_corlib_exception", "void int", TRUE);
  #if defined(ENABLE_LLVM) && !defined(MONO_LLVM_LOADED)
        register_icall (mono_llvm_set_unhandled_exception_handler, "mono_llvm_set_unhandled_exception_handler", NULL, TRUE);
  
        register_icall (mono_thread_get_undeniable_exception, "mono_thread_get_undeniable_exception", "object", FALSE);
        register_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", "object", FALSE);
        register_icall (mono_thread_force_interruption_checkpoint_noraise, "mono_thread_force_interruption_checkpoint_noraise", "object", FALSE);
 -      register_icall (mono_thread_force_interruption_checkpoint, "mono_thread_force_interruption_checkpoint", "void", FALSE);
 -#ifndef DISABLE_REMOTING
 -      register_icall (mono_load_remote_field_new, "mono_load_remote_field_new", "object object ptr ptr", FALSE);
 -      register_icall (mono_store_remote_field_new, "mono_store_remote_field_new", "void object ptr ptr object", FALSE);
 -#endif
  
  #if defined(__native_client__) || defined(__native_client_codegen__)
        register_icall (mono_nacl_gc, "mono_nacl_gc", "void", FALSE);
        register_opcode_emulation (OP_LCONV_TO_R_UN, "__emul_lconv_to_r8_un", "double long", mono_lconv_to_r8_un, "mono_lconv_to_r8_un", FALSE);
  #endif
  #ifdef MONO_ARCH_EMULATE_FREM
 -#if defined(__default_codegen__)
 +#if !defined(__native_client__)
        register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", fmod, "fmod", FALSE);
        register_opcode_emulation (OP_RREM, "__emul_rrem", "float float float", fmodf, "fmodf", FALSE);
 -#elif defined(__native_client_codegen__)
 +#else
        register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", mono_fmod, "mono_fmod", FALSE);
  #endif
  #endif
  #endif
  
        /* other jit icalls */
 -      register_icall (mono_delegate_ctor, "mono_delegate_ctor", "void object object ptr", FALSE);
 +      register_icall (ves_icall_mono_delegate_ctor, "ves_icall_mono_delegate_ctor", "void object object ptr", FALSE);
        register_icall (mono_class_static_field_address , "mono_class_static_field_address",
                                 "ptr ptr ptr", FALSE);
        register_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", "ptr ptr ptr ptr", FALSE);
        register_icall (mono_ldtoken_wrapper_generic_shared, "mono_ldtoken_wrapper_generic_shared",
                "ptr ptr ptr ptr", FALSE);
        register_icall (mono_get_special_static_data, "mono_get_special_static_data", "ptr int", FALSE);
 -      register_icall (mono_ldstr, "mono_ldstr", "object ptr ptr int32", FALSE);
 +      register_icall (ves_icall_mono_ldstr, "ves_icall_mono_ldstr", "object ptr ptr int32", FALSE);
        register_icall (mono_helper_stelem_ref_check, "mono_helper_stelem_ref_check", "void object object", FALSE);
 -      register_icall (mono_object_new, "mono_object_new", "object ptr ptr", FALSE);
 -      register_icall (mono_object_new_specific, "mono_object_new_specific", "object ptr", FALSE);
 -      register_icall (mono_array_new, "mono_array_new", "object ptr ptr int32", FALSE);
 -      register_icall (mono_array_new_specific, "mono_array_new_specific", "object ptr int32", FALSE);
 -      register_icall (mono_runtime_class_init, "mono_runtime_class_init", "void ptr", FALSE);
 +      register_icall (ves_icall_object_new, "ves_icall_object_new", "object ptr ptr", FALSE);
 +      register_icall (ves_icall_object_new_specific, "ves_icall_object_new_specific", "object ptr", FALSE);
 +      register_icall (ves_icall_array_new, "ves_icall_array_new", "object ptr ptr int32", FALSE);
 +      register_icall (ves_icall_array_new_specific, "ves_icall_array_new_specific", "object ptr int32", FALSE);
 +      register_icall (ves_icall_runtime_class_init, "ves_icall_runtime_class_init", "void ptr", FALSE);
        register_icall (mono_ldftn, "mono_ldftn", "ptr ptr", FALSE);
        register_icall (mono_ldvirtfn, "mono_ldvirtfn", "ptr object ptr", FALSE);
        register_icall (mono_ldvirtfn_gshared, "mono_ldvirtfn_gshared", "ptr object ptr", FALSE);
        register_icall (mono_object_castclass_with_cache, "mono_object_castclass_with_cache", "object object ptr ptr", FALSE);
        register_icall (mono_object_isinst_with_cache, "mono_object_isinst_with_cache", "object object ptr ptr", FALSE);
        register_icall (mono_generic_class_init, "mono_generic_class_init", "void ptr", FALSE);
 -      register_icall (mono_fill_class_rgctx, "mono_class_fill_rgctx", "ptr ptr int", FALSE);
 -      register_icall (mono_fill_method_rgctx, "mono_method_fill_rgctx", "ptr ptr int", FALSE);
 +      register_icall (mono_fill_class_rgctx, "mono_fill_class_rgctx", "ptr ptr int", FALSE);
 +      register_icall (mono_fill_method_rgctx, "mono_fill_method_rgctx", "ptr ptr int", FALSE);
  
        register_icall (mono_debugger_agent_user_break, "mono_debugger_agent_user_break", "void", FALSE);
  
        register_icall (mono_aot_init_llvm_method, "mono_aot_init_llvm_method", "void ptr int", TRUE);
        register_icall (mono_aot_init_gshared_method_this, "mono_aot_init_gshared_method_this", "void ptr int object", TRUE);
 -      register_icall (mono_aot_init_gshared_method_rgctx, "mono_aot_init_gshared_method_rgctx", "void ptr int ptr", TRUE);
 +      register_icall (mono_aot_init_gshared_method_mrgctx, "mono_aot_init_gshared_method_mrgctx", "void ptr int ptr", TRUE);
 +      register_icall (mono_aot_init_gshared_method_vtable, "mono_aot_init_gshared_method_vtable", "void ptr int ptr", TRUE);
  
        register_icall_no_wrapper (mono_resolve_iface_call_gsharedvt, "mono_resolve_iface_call_gsharedvt", "ptr object int ptr ptr");
        register_icall_no_wrapper (mono_resolve_vcall_gsharedvt, "mono_resolve_vcall_gsharedvt", "ptr object int ptr ptr");
        register_icall_no_wrapper (mono_resolve_generic_virtual_iface_call, "mono_resolve_generic_virtual_iface_call", "ptr ptr int ptr");
        /* This needs a wrapper so it can have a preserveall cconv */
        register_icall (mono_init_vtable_slot, "mono_init_vtable_slot", "ptr ptr int", FALSE);
 -      register_icall (mono_init_delegate, "mono_init_delegate", "void object object ptr", TRUE);
 -      register_icall (mono_init_delegate_virtual, "mono_init_delegate_virtual", "void object object ptr", TRUE);
 +      register_icall (mono_llvmonly_init_delegate, "mono_llvmonly_init_delegate", "void object", TRUE);
 +      register_icall (mono_llvmonly_init_delegate_virtual, "mono_llvmonly_init_delegate_virtual", "void object object ptr", TRUE);
        register_icall (mono_get_assembly_object, "mono_get_assembly_object", "object ptr", TRUE);
 +      register_icall (mono_get_method_object, "mono_get_method_object", "object ptr", TRUE);
 +      register_icall (mono_throw_method_access, "mono_throw_method_access", "void ptr ptr", FALSE);
 +      register_icall_no_wrapper (mono_dummy_jit_icall, "mono_dummy_jit_icall", "void");
 +
 +      register_icall_with_wrapper (mono_monitor_enter, "mono_monitor_enter", "void obj");
 +      register_icall_with_wrapper (mono_monitor_enter_v4, "mono_monitor_enter_v4", "void obj ptr");
 +      register_icall_no_wrapper (mono_monitor_enter_fast, "mono_monitor_enter_fast", "int obj");
 +      register_icall_no_wrapper (mono_monitor_enter_v4_fast, "mono_monitor_enter_v4_fast", "int obj ptr");
  
  #ifdef TARGET_IOS
        register_icall (pthread_getspecific, "pthread_getspecific", "ptr ptr", TRUE);
@@@ -4109,7 -3857,7 +4109,7 @@@ print_jit_stats (void
                g_print ("IMT colliding slots:    %ld\n", mono_stats.imt_slots_with_collisions);
                g_print ("IMT max collisions:     %ld\n", mono_stats.imt_max_collisions_in_slot);
                g_print ("IMT methods at max col: %ld\n", mono_stats.imt_method_count_when_max_collisions);
 -              g_print ("IMT thunks size:        %ld\n", mono_stats.imt_thunks_size);
 +              g_print ("IMT trampolines size:   %ld\n", mono_stats.imt_trampolines_size);
  
                g_print ("JIT info table inserts: %ld\n", mono_stats.jit_info_table_insert_count);
                g_print ("JIT info table removes: %ld\n", mono_stats.jit_info_table_remove_count);
  void
  mini_cleanup (MonoDomain *domain)
  {
 -      mono_runtime_shutdown_stat_profiler ();
 +      if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
 +              mono_runtime_shutdown_stat_profiler ();
  
  #ifndef DISABLE_COM
        cominterop_release_all_rcws ();
        /* This accesses metadata so needs to be called before runtime shutdown */
        print_jit_stats ();
  
 -      mono_profiler_shutdown ();
 -
  #ifndef MONO_CROSS_COMPILE
        mono_runtime_cleanup (domain);
  #endif
  
 +      mono_profiler_shutdown ();
 +
        free_jit_tls_data ((MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id));
  
        mono_icall_cleanup ();
  
        mono_code_manager_cleanup ();
  
 -#ifdef USE_JUMP_TABLES
 -      mono_jumptable_cleanup ();
 +#ifndef HOST_WIN32
 +      mono_w32handle_cleanup ();
  #endif
  }
  
@@@ -4266,16 -4013,10 +4266,16 @@@ mono_precompile_assembly (MonoAssembly 
                printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image));
  
        for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
 -              method = mono_get_method (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL);
 +              MonoError error;
 +
 +              method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, &error);
 +              if (!method) {
 +                      mono_error_cleanup (&error); /* FIXME don't swallow the error */
 +                      continue;
 +              }
                if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
                        continue;
 -              if (method->is_generic || method->klass->generic_container)
 +              if (method->is_generic || mono_class_is_gtd (method->klass))
                        continue;
  
                count++;
                        g_print ("Compiling %d %s\n", count, desc);
                        g_free (desc);
                }
 -              mono_compile_method (method);
 +              mono_compile_method_checked (method, &error);
 +              if (!is_ok (&error)) {
 +                      mono_error_cleanup (&error); /* FIXME don't swallow the error */
 +                      continue;
 +              }
                if (strcmp (method->name, "Finalize") == 0) {
 -                      invoke = mono_marshal_get_runtime_invoke (method, FALSE, FALSE);
 -                      mono_compile_method (invoke);
 +                      invoke = mono_marshal_get_runtime_invoke (method, FALSE);
 +                      mono_compile_method_checked (invoke, &error);
 +                      mono_error_assert_ok (&error);
                }
  #ifndef DISABLE_REMOTING
                if (mono_class_is_marshalbyref (method->klass) && mono_method_signature (method)->hasthis) {
                        invoke = mono_marshal_get_remoting_invoke_with_check (method);
 -                      mono_compile_method (invoke);
 +                      mono_compile_method_checked (invoke, &error);
 +                      mono_error_assert_ok (&error);
                }
  #endif
        }
@@@ -4331,22 -4066,97 +4331,22 @@@ mono_personality (void
        g_assert_not_reached ();
  }
  
 -#ifdef USE_JUMP_TABLES
 -#define DEFAULT_JUMPTABLE_CHUNK_ELEMENTS 128
 -
 -typedef struct MonoJumpTableChunk {
 -      guint32 total;
 -      guint32 active;
 -      struct MonoJumpTableChunk *previous;
 -      /* gpointer entries[total]; */
 -} MonoJumpTableChunk;
 -
 -static MonoJumpTableChunk* g_jumptable;
 -#define mono_jumptable_lock() mono_os_mutex_lock (&jumptable_mutex)
 -#define mono_jumptable_unlock() mono_os_mutex_unlock (&jumptable_mutex)
 -static mono_mutex_t jumptable_mutex;
 -
 -static  MonoJumpTableChunk*
 -mono_create_jumptable_chunk (guint32 max_entries)
 -{
 -      guint32 size = sizeof (MonoJumpTableChunk) + max_entries * sizeof(gpointer);
 -      MonoJumpTableChunk *chunk = (MonoJumpTableChunk*) g_new0 (guchar, size);
 -      chunk->total = max_entries;
 -      return chunk;
 -}
 -
 -void
 -mono_jumptable_init (void)
 -{
 -      if (g_jumptable == NULL) {
 -              mono_os_mutex_init_recursive (&jumptable_mutex);
 -              g_jumptable = mono_create_jumptable_chunk (DEFAULT_JUMPTABLE_CHUNK_ELEMENTS);
 -      }
 -}
 -
 -gpointer*
 -mono_jumptable_add_entry (void)
 -{
 -      return mono_jumptable_add_entries (1);
 -}
 -
 -gpointer*
 -mono_jumptable_add_entries (guint32 entries)
 +// Custom handlers currently only implemented by Windows.
 +#ifndef HOST_WIN32
 +gboolean
 +mono_runtime_install_custom_handlers (const char *handlers)
  {
 -      guint32 index;
 -      gpointer *result;
 -
 -      mono_jumptable_init ();
 -      mono_jumptable_lock ();
 -      index = g_jumptable->active;
 -      if (index + entries >= g_jumptable->total) {
 -              /*
 -               * Grow jumptable, by adding one more chunk.
 -               * We cannot realloc jumptable, as there could be pointers
 -               * to existing jump table entries in the code, so instead
 -               * we just add one more chunk.
 -               */
 -              guint32 max_entries = entries;
 -              MonoJumpTableChunk *new_chunk;
 -
 -              if (max_entries < DEFAULT_JUMPTABLE_CHUNK_ELEMENTS)
 -                      max_entries = DEFAULT_JUMPTABLE_CHUNK_ELEMENTS;
 -              new_chunk = mono_create_jumptable_chunk (max_entries);
 -              /* Link old jumptable, so that we could free it up later. */
 -              new_chunk->previous = g_jumptable;
 -              g_jumptable = new_chunk;
 -              index = 0;
 -      }
 -      g_jumptable->active = index + entries;
 -      result = (gpointer*)((guchar*)g_jumptable + sizeof(MonoJumpTableChunk)) + index;
 -      mono_jumptable_unlock();
 -
 -      return result;
 +      return FALSE;
  }
  
  void
 -mono_jumptable_cleanup (void)
 -{
 -      if (g_jumptable) {
 -              MonoJumpTableChunk *current = g_jumptable, *prev;
 -              while (current != NULL) {
 -                      prev = current->previous;
 -                      g_free (current);
 -                      current = prev;
 -              }
 -              g_jumptable = NULL;
 -              mono_os_mutex_destroy (&jumptable_mutex);
 -      }
 -}
 -
 -gpointer*
 -mono_jumptable_get_entry (guint8 *code_ptr)
 +mono_runtime_install_custom_handlers_usage (void)
  {
 -      return mono_arch_jumptable_entry_from_code (code_ptr);
 +      fprintf (stdout,
 +               "Custom Handlers:\n"
 +               "   --handlers=HANDLERS            Enable handler support, HANDLERS is a comma\n"
 +               "                                  separated list of available handlers to install.\n"
 +               "\n"
 +               "No handlers supported on current platform.\n");
  }
 -#endif
 +#endif /* HOST_WIN32 */