[runtime] New profiler API.
[mono.git] / mono / metadata / class.c
index 232a70e064d8f004bd36489f0c12d08275e19170..cd3f8bf703b433073663ebb089962c6306f760cf 100644 (file)
@@ -614,7 +614,6 @@ mono_type_get_full_name (MonoClass *klass)
 /**
  * mono_type_get_name:
  * \param type a type
- *
  * \returns The string representation for type as it would be represented in IL code.
  */
 char*
@@ -623,11 +622,10 @@ mono_type_get_name (MonoType *type)
        return mono_type_get_name_full (type, MONO_TYPE_NAME_FORMAT_IL);
 }
 
-/*
+/**
  * mono_type_get_underlying_type:
- * @type: a type
- *
- * Returns: The MonoType for the underlying integer type if @type
+ * \param type a type
+ * \returns The \c MonoType for the underlying integer type if \p type
  * is an enum and byref is false, otherwise the type itself.
  */
 MonoType*
@@ -1604,6 +1602,11 @@ mono_class_setup_fields (MonoClass *klass)
                        g_assert (field->type);
                }
 
+               if (!mono_type_get_underlying_type (field->type)) {
+                       mono_class_set_type_load_failure (klass, "Field '%s' is an enum type with a bad underlying type", field->name);
+                       break;
+               }
+
                if (mono_field_is_deleted (field))
                        continue;
                if (layout == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
@@ -1628,8 +1631,7 @@ mono_class_setup_fields (MonoClass *klass)
                        char *class_name = mono_type_get_full_name (klass);
                        char *type_name = mono_type_full_name (field->type);
 
-                       mono_class_set_type_load_failure (klass, "");
-                       g_warning ("Invalid type %s for instance field %s:%s", type_name, class_name, field->name);
+                       mono_class_set_type_load_failure (klass, "Invalid type %s for instance field %s:%s", type_name, class_name, field->name);
                        g_free (class_name);
                        g_free (type_name);
                        break;
@@ -3689,7 +3691,7 @@ is_wcf_hack_disabled (void)
        static gboolean disabled;
        static gboolean inited = FALSE;
        if (!inited) {
-               disabled = g_getenv ("MONO_DISABLE_WCF_HACK") != NULL;
+               disabled = g_hasenv ("MONO_DISABLE_WCF_HACK");
                inited = TRUE;
        }
        return disabled;
@@ -4036,6 +4038,32 @@ mono_class_need_stelemref_method (MonoClass *klass)
        return klass->rank == 1 && MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg);
 }
 
+static int
+apply_override (MonoClass *klass, MonoMethod **vtable, MonoMethod *decl, MonoMethod *override)
+{
+       int dslot;
+       dslot = mono_method_get_vtable_slot (decl);
+       if (dslot == -1) {
+               mono_class_set_type_load_failure (klass, "");
+               return FALSE;
+       }
+
+       dslot += mono_class_interface_offset (klass, decl->klass);
+       vtable [dslot] = override;
+       if (!MONO_CLASS_IS_INTERFACE (override->klass)) {
+               /*
+                * If override from an interface, then it is an override of a default interface method,
+                * don't override its slot.
+                */
+               vtable [dslot]->slot = dslot;
+       }
+
+       if (mono_security_core_clr_enabled ())
+               mono_security_core_clr_check_override (klass, vtable [dslot], decl);
+
+       return TRUE;
+}
+
 /*
  * LOCKING: this is supposed to be called with the loader lock held.
  */
@@ -4193,29 +4221,48 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o
        }
 
        TRACE_INTERFACE_VTABLE (print_vtable_full (klass, vtable, cur_slot, first_non_interface_slot, "AFTER INHERITING PARENT VTABLE", TRUE));
+
+       /* Process overrides from interface default methods */
+       // FIXME: Ordering between interfaces
+       for (int ifindex = 0; ifindex < klass->interface_offsets_count; ifindex++) {
+               ic = klass->interfaces_packed [ifindex];
+
+               mono_class_setup_methods (ic);
+               if (mono_class_has_failure (ic))
+                       goto fail;
+
+               MonoMethod **iface_overrides;
+               int iface_onum;
+               gboolean ok = mono_class_get_overrides_full (ic->image, ic->type_token, &iface_overrides, &iface_onum, mono_class_get_context (ic));
+               if (ok) {
+                       for (int i = 0; i < iface_onum; i++) {
+                               MonoMethod *decl = iface_overrides [i*2];
+                               MonoMethod *override = iface_overrides [i*2 + 1];
+                               if (!apply_override (klass, vtable, decl, override))
+                                       goto fail;
+
+                               if (!override_map)
+                                       override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
+                               g_hash_table_insert (override_map, decl, override);
+                       }
+                       g_free (iface_overrides);
+               }
+       }
+
        /* override interface methods */
        for (i = 0; i < onum; i++) {
                MonoMethod *decl = overrides [i*2];
+               MonoMethod *override = overrides [i*2 + 1];
                if (MONO_CLASS_IS_INTERFACE (decl->klass)) {
-                       int dslot;
-                       dslot = mono_method_get_vtable_slot (decl);
-                       if (dslot == -1) {
-                               mono_class_set_type_load_failure (klass, "");
+                       if (!apply_override (klass, vtable, decl, override))
                                goto fail;
-                       }
 
-                       dslot += mono_class_interface_offset (klass, decl->klass);
-                       vtable [dslot] = overrides [i*2 + 1];
-                       vtable [dslot]->slot = dslot;
                        if (!override_map)
                                override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
-
-                       g_hash_table_insert (override_map, overrides [i * 2], overrides [i * 2 + 1]);
-
-                       if (mono_security_core_clr_enabled ())
-                               mono_security_core_clr_check_override (klass, vtable [dslot], decl);
+                       g_hash_table_insert (override_map, decl, override);
                }
        }
+
        TRACE_INTERFACE_VTABLE (print_overrides (override_map, "AFTER OVERRIDING INTERFACE METHODS"));
        TRACE_INTERFACE_VTABLE (print_vtable_full (klass, vtable, cur_slot, first_non_interface_slot, "AFTER OVERRIDING INTERFACE METHODS", FALSE));
 
@@ -4321,6 +4368,13 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o
                                                TRACE_INTERFACE_VTABLE ((cm != NULL) && printf ("\n"));
                                        }
                                }
+
+                               if (vtable [im_slot] == NULL) {
+                                       if (!(im->flags & METHOD_ATTRIBUTE_ABSTRACT)) {
+                                               TRACE_INTERFACE_VTABLE (printf ("    Using default iface method %s.\n", mono_method_full_name (im, 1)));
+                                               vtable [im_slot] = im;
+                                       }
+                               }
                        } else {
                                g_assert (vtable [im_slot] == override_im);
                        }
@@ -5507,7 +5561,7 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError
        klass->name = name;
        klass->name_space = nspace;
 
-       mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
+       MONO_PROFILER_RAISE (class_loading, (klass));
 
        klass->image = image;
        klass->type_token = type_token;
@@ -5524,6 +5578,9 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError
                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);
+               MonoType *canonical_inst = &((MonoClassGtd*)klass)->canonical_inst;
+               canonical_inst->type = MONO_TYPE_GENERICINST;
+               canonical_inst->data.generic_class = mono_metadata_lookup_generic_class (klass, context->class_inst, FALSE);
                enable_gclass_recording ();
        }
 
@@ -5578,7 +5635,7 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError
                        /*FIXME implement a mono_class_set_failure_from_mono_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_PROFILER_RAISE (class_failed, (klass));
                        return NULL;
                }
        }
@@ -5635,7 +5692,7 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError
 
                        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_PROFILER_RAISE (class_failed, (klass));
                        return NULL;
                }
 
@@ -5685,7 +5742,7 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError
                        klass->cast_class = klass->element_class = mono_defaults.int32_class;
                        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_PROFILER_RAISE (class_failed, (klass));
                        return NULL;
                }
                klass->cast_class = klass->element_class = mono_class_from_mono_type (enum_basetype);
@@ -5699,7 +5756,7 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError
        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_PROFILER_RAISE (class_failed, (klass));
                return NULL;
        }
 
@@ -5713,7 +5770,7 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError
 
        mono_loader_unlock ();
 
-       mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
+       MONO_PROFILER_RAISE (class_loaded, (klass));
 
        return klass;
 
@@ -5723,7 +5780,7 @@ parent_failure:
 
        mono_class_setup_mono_type (klass);
        mono_loader_unlock ();
-       mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED);
+       MONO_PROFILER_RAISE (class_failed, (klass));
        return NULL;
 }
 
@@ -5860,7 +5917,7 @@ mono_generic_class_get_class (MonoGenericClass *gclass)
        if (mono_class_is_nullable (klass))
                klass->cast_class = klass->element_class = mono_class_get_nullable_param (klass);
 
-       mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
+       MONO_PROFILER_RAISE (class_loading, (klass));
 
        mono_generic_class_setup_parent (klass, gklass);
 
@@ -5870,7 +5927,7 @@ mono_generic_class_get_class (MonoGenericClass *gclass)
        mono_memory_barrier ();
        gclass->cached_class = klass;
 
-       mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
+       MONO_PROFILER_RAISE (class_loaded, (klass));
 
        ++class_ginst_count;
        inflated_classes_size += sizeof (MonoClassGenericInst);
@@ -5956,7 +6013,7 @@ make_generic_param_class (MonoGenericParam *param, MonoGenericParamInfo *pinfo)
                CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name_space , oklass ? oklass->name_space : "" );
        }
 
-       mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
+       MONO_PROFILER_RAISE (class_loading, (klass));
 
        // Count non-NULL items in pinfo->constraints
        count = 0;
@@ -6172,9 +6229,9 @@ mono_class_from_generic_parameter_internal (MonoGenericParam *param)
 
        /* FIXME: Should this go inside 'make_generic_param_klass'? */
        if (klass2)
-               mono_profiler_class_loaded (klass2, MONO_PROFILE_FAILED); // Alert profiler about botched class create
+               MONO_PROFILER_RAISE (class_failed, (klass2));
        else
-               mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
+               MONO_PROFILER_RAISE (class_loaded, (klass));
 
        return klass;
 }
@@ -6191,6 +6248,9 @@ mono_class_from_generic_parameter (MonoGenericParam *param, MonoImage *arg2 G_GN
        return mono_class_from_generic_parameter_internal (param);
 }
 
+/**
+ * mono_ptr_class_get:
+ */
 MonoClass *
 mono_ptr_class_get (MonoType *type)
 {
@@ -6223,7 +6283,7 @@ mono_ptr_class_get (MonoType *type)
        result->class_kind = MONO_CLASS_POINTER;
        g_free (name);
 
-       mono_profiler_class_event (result, MONO_PROFILE_START_LOAD);
+       MONO_PROFILER_RAISE (class_loading, (result));
 
        result->image = el_class->image;
        result->inited = TRUE;
@@ -6243,7 +6303,7 @@ mono_ptr_class_get (MonoType *type)
                MonoClass *result2;
                if ((result2 = (MonoClass *)g_hash_table_lookup (image->ptr_cache, el_class))) {
                        mono_image_unlock (image);
-                       mono_profiler_class_loaded (result, MONO_PROFILE_FAILED);
+                       MONO_PROFILER_RAISE (class_failed, (result));
                        return result2;
                }
        } else {
@@ -6252,7 +6312,7 @@ mono_ptr_class_get (MonoType *type)
        g_hash_table_insert (image->ptr_cache, el_class, result);
        mono_image_unlock (image);
 
-       mono_profiler_class_loaded (result, MONO_PROFILE_OK);
+       MONO_PROFILER_RAISE (class_loaded, (result));
 
        return result;
 }
@@ -6301,7 +6361,7 @@ mono_fnptr_class_get (MonoMethodSignature *sig)
                return cached;
        }
 
-       mono_profiler_class_event (result, MONO_PROFILE_START_LOAD);
+       MONO_PROFILER_RAISE (class_loading, (result));
 
        classes_size += sizeof (MonoClassPointer);
        ++class_pointer_count;
@@ -6310,7 +6370,7 @@ mono_fnptr_class_get (MonoMethodSignature *sig)
 
        mono_loader_unlock ();
 
-       mono_profiler_class_loaded (result, MONO_PROFILE_OK);
+       MONO_PROFILER_RAISE (class_loaded, (result));
 
        return result;
 }
@@ -6441,7 +6501,6 @@ mono_class_create_from_typespec (MonoImage *image, guint32 type_spec, MonoGeneri
  * \param element_class element class 
  * \param rank the dimension of the array class
  * \param bounded whenever the array has non-zero bounds
- *
  * \returns A class object describing the array with element type \p element_type and 
  * dimension \p rank.
  */
@@ -6630,7 +6689,7 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded)
                return cached;
        }
 
-       mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
+       MONO_PROFILER_RAISE (class_loading, (klass));
 
        classes_size += sizeof (MonoClassArray);
        ++class_array_count;
@@ -6646,7 +6705,7 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded)
 
        mono_loader_unlock ();
 
-       mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
+       MONO_PROFILER_RAISE (class_loaded, (klass));
 
        return klass;
 }
@@ -9047,10 +9106,25 @@ mono_class_get_methods (MonoClass* klass, gpointer *iter)
 static MonoMethod*
 mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter)
 {
-       MonoMethod** method;
+       gboolean static_iter = FALSE;
+
        if (!iter)
                return NULL;
-       if (klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass)) {
+
+       /*
+        * If the lowest bit of the iterator is 1, this is an iterator for static metadata,
+        * and the upper bits contain an index. Otherwise, the iterator is a pointer into
+        * klass->methods.
+        */
+       if ((gsize)(*iter) & 1)
+               static_iter = TRUE;
+       /* Use the static metadata only if klass->methods is not yet initialized */
+       if (!static_iter && !(klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass)))
+               static_iter = TRUE;
+
+       if (!static_iter) {
+               MonoMethod** methodptr;
+
                if (!*iter) {
                        mono_class_setup_methods (klass);
                        /*
@@ -9060,20 +9134,22 @@ mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter)
                        if (!klass->methods)
                                return NULL;
                        /* start from the first */
-                       method = &klass->methods [0];
+                       methodptr = &klass->methods [0];
                } else {
-                       method = (MonoMethod **)*iter;
-                       method++;
+                       methodptr = (MonoMethod **)*iter;
+                       methodptr++;
                }
+               if (*iter)
+                       g_assert ((guint64)(*iter) > 0x100);
                int mcount = mono_class_get_method_count (klass);
-               while (method < &klass->methods [mcount]) {
-                       if (*method && ((*method)->flags & METHOD_ATTRIBUTE_VIRTUAL))
+               while (methodptr < &klass->methods [mcount]) {
+                       if (*methodptr && ((*methodptr)->flags & METHOD_ATTRIBUTE_VIRTUAL))
                                break;
-                       method ++;
+                       methodptr ++;
                }
-               if (method < &klass->methods [mcount]) {
-                       *iter = method;
-                       return *method;
+               if (methodptr < &klass->methods [mcount]) {
+                       *iter = methodptr;
+                       return *methodptr;
                } else {
                        return NULL;
                }
@@ -9085,7 +9161,7 @@ mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter)
                if (!*iter) {
                        start_index = 0;
                } else {
-                       start_index = GPOINTER_TO_UINT (*iter);
+                       start_index = GPOINTER_TO_UINT (*iter) >> 1;
                }
 
                int first_idx = mono_class_get_first_method_idx (klass);
@@ -9106,7 +9182,7 @@ mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter)
                        mono_error_cleanup (&error); /* FIXME don't swallow the error */
 
                        /* Add 1 here so the if (*iter) check fails */
-                       *iter = GUINT_TO_POINTER (i + 1);
+                       *iter  = GUINT_TO_POINTER (((i + 1) << 1) | 1);
                        return res;
                } else {
                        return NULL;
@@ -9973,7 +10049,7 @@ can_access_internals (MonoAssembly *accessing, MonoAssembly* accessed)
                /* Be conservative with checks */
                if (!friend_->name)
                        continue;
-               if (strcmp (accessing->aname.name, friend_->name))
+               if (g_ascii_strcasecmp (accessing->aname.name, friend_->name))
                        continue;
                if (friend_->public_key_token [0]) {
                        if (!accessing->aname.public_key_token [0])