Merge pull request #3802 from lambdageek/dev-reference-attr-take3
authorAleksey Kliger (λgeek) <akliger@gmail.com>
Mon, 31 Oct 2016 14:16:05 +0000 (10:16 -0400)
committerGitHub <noreply@github.com>
Mon, 31 Oct 2016 14:16:05 +0000 (10:16 -0400)
[loader] Re-enable the reference assembly attribute check

1  2 
mono/metadata/assembly.c
mono/metadata/class.c
mono/mini/method-to-ir.c
mono/mini/mini-exceptions.c
mono/tests/Makefile.am

diff --combined mono/metadata/assembly.c
index 209e4ab4f988192fe280953fe7d5017c547d56b3,51a27929632acf27c1cb9060a7d2089911445d61..9efcf1db486445dec64ee79c733593dbd7511391
@@@ -570,7 -570,7 +570,7 @@@ mono_assembly_getrootdir (void
   * Returns: a string with the directory, this string should be freed by
   * the caller.
   */
 -G_CONST_RETURN gchar *
 +gchar *
  mono_native_getrootdir (void)
  {
        gchar* fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), mono_config_get_reloc_lib_dir(), NULL);
@@@ -1768,7 -1768,7 +1768,7 @@@ mono_assembly_load_friends (MonoAssembl
        if (ass->friend_assembly_names_inited)
                return;
  
-       attrs = mono_custom_attrs_from_assembly_checked (ass, &error);
+       attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, &error);
        mono_error_assert_ok (&error);
        if (!attrs) {
                mono_assemblies_lock ();
@@@ -1847,8 -1847,8 +1847,8 @@@ mono_assembly_has_reference_assembly_at
   * corlib, however, so we need a more robust version that doesn't care
   * about missing attributes.
   */
- #if 0
-       MonoCustomAttrInfo *attrs = mono_custom_attrs_from_assembly_checked (assembly, error);
+ #if 1
+       MonoCustomAttrInfo *attrs = mono_custom_attrs_from_assembly_checked (assembly, TRUE, error);
        return_val_if_nok (error, FALSE);
        if (!attrs)
                return FALSE;
@@@ -1999,6 -1999,8 +1999,8 @@@ mono_assembly_load_from_full (MonoImag
  
        mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Prepared to set up assembly '%s' (%s)", ass->aname.name, image->name);
  
+       image->assembly = ass;
        /* We need to check for ReferenceAssmeblyAttribute before we
         * mark the assembly as loaded and before we fire the load
         * hook. Otherwise mono_domain_fire_assembly_load () in
                mono_error_cleanup (&refasm_error);
        }
  
-       image->assembly = ass;
        loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
        mono_assemblies_unlock ();
  
diff --combined mono/metadata/class.c
index 1ef54f559e3fbfe45c157d17e7f3133fdac072e0,b0e5813d05b133fee53e4471298b8ad9e3b8e4fb..6b756589023be1a4a175abd0925c1de1c0b2c960
@@@ -111,8 -111,6 +111,8 @@@ typedef gboolean (*gclass_record_func) 
  /* 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)
  {
@@@ -1534,9 -1532,15 +1534,9 @@@ mono_class_set_type_load_failure_caused
   * Initializes klass->fields, computes class layout and sizes.
   * typebuilder_setup_fields () is the corresponding function for dynamic classes.
   * Sets the following fields in @klass:
 - *  - packing_size
 - *  - min_align
 - *  - blittable
 - *  - 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)
 + *  - all the fields initialized by mono_class_init_sizes ()
   *  - element_class/cast_class (for enums)
 + *  - field->type/offset for all fields
   *  - fields_inited
   *
   * LOCKING: Acquires the loader lock.
@@@ -1665,51 -1669,23 +1665,51 @@@ mono_class_setup_fields (MonoClass *kla
        mono_native_tls_set_value (setup_fields_tls_id, init_list);
  }
  
 +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;
 +      }
 +      else {
 +              if (!klass->size_inited)
 +                      mono_class_setup_fields (klass);
 +      }
 +}
  /*
 - * mono_class_has_references:
 +
 + * mono_class_init_sizes:
 + *
 + *   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);
  }
  
  /*
@@@ -1729,29 -1705,16 +1729,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;
  }
@@@ -3094,12 -3057,6 +3094,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
@@@ -3117,11 -3074,11 +3117,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;
         */
        all_interfaces = eclass->rank && eclass->element_class->rank? FALSE: TRUE;
  
 -      if (!generic_icollection_class) {
 -              generic_icollection_class = mono_class_load_from_name (mono_defaults.corlib,
 -                      "System.Collections.Generic", "ICollection`1");
 -              generic_ienumerable_class = mono_class_load_from_name (mono_defaults.corlib,
 -                      "System.Collections.Generic", "IEnumerable`1");
 -              generic_ienumerator_class = mono_class_load_from_name (mono_defaults.corlib,
 -                      "System.Collections.Generic", "IEnumerator`1");
 -              generic_ireadonlylist_class = mono_class_load_from_name (mono_defaults.corlib,
 -                      "System.Collections.Generic", "IReadOnlyList`1");
 -              generic_ireadonlycollection_class = mono_class_load_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);
  
@@@ -3529,8 -3493,8 +3529,8 @@@ 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 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)
                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;
                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++) {
        }
  
        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 ()
                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
@@@ -5085,30 -5051,21 +5085,30 @@@ concat_two_strings_with_zero (MonoImag
  
  /**
   * 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);
  
  
        /*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 || mono_class_has_failure (klass)) {
 -              mono_loader_unlock ();
 -              /* Somebody might have gotten in before us */
 -              return !mono_class_has_failure (klass);
 -      }
 -
 -      if (klass->init_pending) {
 +      /*
 +       * 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_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) 
                        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;
 -
                mono_class_init (gklass);
 -              // FIXME: Why is this needed ?
 -              if (!mono_class_has_failure (gklass))
 -                      mono_class_setup_methods (gklass);
                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 (mono_class_has_failure (klass))
 -                              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;
  
                /* 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 (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 */
  
                                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 (mono_class_has_failure (klass))
                                        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) {
 -              MonoError parent_error;
 -              mono_error_init (&parent_error);
 -              int first_iface_slot;
 -              /* This will compute klass->parent->vtable_size for some classes */
 -              mono_class_init (klass->parent);
 -              if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Parent class failed to initialize")) {
 -                      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 (!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 (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Parent class vtable failed to initialize")) {
 -                              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 (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 (klass->generic_class || 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);
  
        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 !mono_class_has_failure (klass);
  }
@@@ -5531,6 -5489,7 +5531,6 @@@ mono_class_setup_mono_type (MonoClass *
  
        if (MONO_CLASS_IS_INTERFACE (klass))
                klass->interface_id = mono_get_unique_iid (klass);
 -
  }
  
  #ifndef DISABLE_COM
@@@ -6748,7 -6707,8 +6748,7 @@@ mono_bounded_array_class_get (MonoClas
  
        if (eclass->generic_class)
                mono_class_init (eclass);
 -      if (!eclass->size_inited)
 -              mono_class_setup_fields (eclass);
 +      mono_class_init_sizes (eclass);
        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.*/
  
@@@ -6853,7 -6813,7 +6853,7 @@@ gint3
  mono_class_instance_size (MonoClass *klass)
  {     
        if (!klass->size_inited)
 -              mono_class_init (klass);
 +              mono_class_init_sizes (klass);
  
        return klass->instance_size;
  }
   *
   * Use to get the computed minimum alignment requirements for the specified class.
   *
 - * Returns: minimm alignment requirements 
 + * Returns: minimum alignment requirements
   */
  gint32
  mono_class_min_align (MonoClass *klass)
  {     
        if (!klass->size_inited)
 -              mono_class_init (klass);
 +              mono_class_init_sizes (klass);
  
        return klass->min_align;
  }
   * 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;
  
@@@ -6914,8 -6874,8 +6914,8 @@@ mono_class_data_size (MonoClass *klass
        if (!klass->inited)
                mono_class_init (klass);
        /* This can happen with dynamically created types */
 -      if (!klass->fields_inited)
 -              mono_class_setup_fields (klass);
 +      if (!klass->size_inited)
 +              mono_class_init_sizes (klass);
  
        /* in arrays, sizes.class_size is unioned with element_size
         * and arrays have no static fields
@@@ -10001,7 -9961,6 +10001,7 @@@ 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 ("Inflated methods size",
                                                        MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_methods_size);
  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);
@@@ -10680,12 -10638,16 +10680,16 @@@ mono_field_resolve_type (MonoClassFiel
                MonoClassField *gfield = &gtd->fields [field_idx];
                MonoType *gtype = mono_field_get_type_checked (gfield, error);
                if (!mono_error_ok (error)) {
-                       mono_class_set_type_load_failure (klass, "Could not load field %d type due to: %s", field_idx, mono_error_get_message (error));
+                       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)) {
-                       mono_class_set_type_load_failure (klass, "Could not load field %d type due to: %s", field_idx, mono_error_get_message (error));
+                       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;
                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);;
+                       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;
                }
  
  
                field->type = mono_metadata_parse_type_checked (image, container, cols [MONO_FIELD_FLAGS], FALSE, sig + 1, &sig, error);
                if (!field->type) {
-                       mono_class_set_type_load_failure (klass, "Could not load field %d type due to: %s", field_idx, mono_error_get_message (error));
+                       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);
                }
        }
  }
diff --combined mono/mini/method-to-ir.c
index 297516cb32c6290db4e4ded20a96f869000a95c3,8f00ad2c64b2560f1305a994dff701d209517493..5f42019f9d405dbef320c062a20e8dc99d409e4f
@@@ -7076,11 -7076,11 +7076,11 @@@ 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;
@@@ -7952,7 -7952,7 +7952,7 @@@ is_jit_optimizer_disabled (MonoMethod *
                return FALSE;
        }
  
-       attrs = mono_custom_attrs_from_assembly_checked (ass, &error);
+       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) {
@@@ -8151,22 -8151,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, 
index 5342deb8b3a3027b899169417ae12da197786480,402c60d00041a3040830471bfebe19b4ef2e1f91..120da0bc2bc49355b6d09d2f16b3766762e1fa5d
@@@ -1229,7 -1229,7 +1229,7 @@@ wrap_non_exception_throws (MonoMethod *
  
        klass = mono_class_get_runtime_compat_attr_class ();
  
-       attrs = mono_custom_attrs_from_assembly_checked (ass, &error);
+       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) {
@@@ -2724,7 -2724,7 +2724,7 @@@ mono_thread_state_init_from_sigctx (Mon
        MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
        if (!thread) {
                ctx->valid = FALSE;
 -              G_BREAKPOINT ();
 +              g_error ("Invoked mono_thread_state_init_from_sigctx from non-Mono thread");
                return FALSE;
        }
  
diff --combined mono/tests/Makefile.am
index 6439b02c37ce85d54c3ba9061751796f58271a4b,36488929a894a31f7c12d557ef7788b3327e78e1..887f48a244bb4c87face5e25f04ab42e0a6a2e81
@@@ -470,7 -470,8 +470,8 @@@ BASE_TEST_CS_SRC_UNIVERSAL=                
        bug-29585.cs    \
        priority.cs     \
        abort-cctor.cs  \
-       thread-native-exit.cs
+       thread-native-exit.cs \
+       reference-loader.cs
  
  if INSTALL_MOBILE_STATIC
  BASE_TEST_CS_SRC= \
@@@ -692,7 -693,6 +693,6 @@@ DISABLED_TESTS=                    
        bug-459094.exe \
        delegate-invoke.exe \
        bug-Xamarin-5278.exe \
-       reference-loader.cs \
        $(PLATFORM_DISABLED_TESTS) \
        $(EXTRA_DISABLED_TESTS) \
        $(COOP_DISABLED_TESTS) \
@@@ -789,8 -789,7 +789,8 @@@ TEST_IL_SRC_UNIVERSAL=                     
        delegate-with-null-target.il    \
        bug-318677.il   \
        gsharing-valuetype-layout.il    \
 -      invalid_generic_instantiation.il
 +      invalid_generic_instantiation.il \
 +      bug-45841-fpstack-exceptions.il
  
  if INSTALL_MOBILE_STATIC
  TEST_IL_SRC= \
@@@ -881,7 -880,9 +881,9 @@@ bug-324535-il.dll$(PLATFORM_AOT_SUFFIX
  bug-36848-a.dll$(PLATFORM_AOT_SUFFIX) \
  bug-81691-b.dll$(PLATFORM_AOT_SUFFIX) \
  bug-327438.2.exe$(PLATFORM_AOT_SUFFIX)        \
- bug-81466-lib.dll$(PLATFORM_AOT_SUFFIX)
+ bug-81466-lib.dll$(PLATFORM_AOT_SUFFIX)       \
+ TestingReferenceAssembly.dll$(PLATFORM_AOT_SUFFIX)    \
+ TestingReferenceReferenceAssembly.dll$(PLATFORM_AOT_SUFFIX)
  
  if INSTALL_MOBILE_STATIC
  prereqs: $(PREREQSI_IL_AOT) $(PREREQSI_CS_AOT) $(AOT_EXTRA_LIBS)
@@@ -1112,7 -1113,7 +1114,7 @@@ debug-casts
        @$(MCS) -r:TestDriver.dll $(srcdir)/debug-casts.cs
        @$(RUNTIME) --debug=casts debug-casts.exe
  
 -EXTRA_DIST += sgen-bridge.cs sgen-descriptors.cs sgen-gshared-vtype.cs sgen-bridge-major-fragmentation.cs sgen-domain-unload.cs sgen-weakref-stress.cs sgen-cementing-stress.cs sgen-case-23400.cs    finalizer-wait.cs critical-finalizers.cs sgen-domain-unload-2.cs sgen-suspend.cs sgen-new-threads-dont-join-stw.cs sgen-new-threads-dont-join-stw-2.cs sgen-bridge-xref.cs bug-17590.cs sgen-toggleref.cs sgen-bridge-gchandle.cs
 +EXTRA_DIST += sgen-bridge.cs sgen-descriptors.cs sgen-gshared-vtype.cs sgen-bridge-major-fragmentation.cs sgen-domain-unload.cs sgen-weakref-stress.cs sgen-cementing-stress.cs sgen-case-23400.cs    finalizer-wait.cs critical-finalizers.cs sgen-domain-unload-2.cs sgen-suspend.cs sgen-new-threads-dont-join-stw.cs sgen-new-threads-dont-join-stw-2.cs sgen-new-threads-collect.cs sgen-bridge-xref.cs bug-17590.cs sgen-toggleref.cs sgen-bridge-gchandle.cs
  
  
  sgen-tests:
@@@ -1137,7 -1138,6 +1139,7 @@@ SGEN_REGULAR_TESTS_UNIVERSAL =  
        sgen-case-23400.exe     \
        sgen-new-threads-dont-join-stw.exe      \
        sgen-new-threads-dont-join-stw-2.exe    \
 +      sgen-new-threads-collect.exe    \
        gc-graystack-stress.exe \
        bug-17590.exe