#include <mono/metadata/security-manager.h>
#include <mono/metadata/security-core-clr.h>
#include <mono/metadata/attrdefs.h>
-#include <mono/os/gc_wrapper.h>
+#include <mono/metadata/gc-internal.h>
#include <mono/utils/mono-counters.h>
MonoStats mono_stats;
MonoAssembly *ta = klass->image->assembly;
g_string_append_printf (
- str, ", %s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s",
+ str, ", %s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
ta->aname.name,
ta->aname.major, ta->aname.minor, ta->aname.build, ta->aname.revision,
ta->aname.culture && *ta->aname.culture? ta->aname.culture: "neutral",
- ta->aname.public_key_token [0] ? (char *)ta->aname.public_key_token : "null");
+ ta->aname.public_key_token [0] ? (char *)ta->aname.public_key_token : "null",
+ (ta->aname.flags & ASSEMBLYREF_RETARGETABLE_FLAG) ? ", Retargetable=Yes" : "");
}
static inline void
MonoMethodInflated *iresult, *cached;
MonoMethodSignature *sig;
MonoGenericContext tmp_context;
+ gboolean is_mb_open = FALSE;
/* The `method' has already been instantiated before => we need to peel out the instantiation and create a new context */
while (method->is_inflated) {
if (!method->generic_container && !method->klass->generic_container)
return method;
+ /*
+ * The reason for this hack is to fix the behavior of inflating generic methods that come from a MethodBuilder.
+ * What happens is that instantiating a generic MethodBuilder with its own arguments should create a diferent object.
+ * This is opposite to the way non-SRE MethodInfos behave.
+ *
+ * FIXME: express this better, somehow!
+ */
+ is_mb_open = method->generic_container &&
+ method->klass->image->dynamic && !method->klass->wastypebuilder &&
+ context->method_inst == method->generic_container->context.method_inst;
+
mono_stats.inflated_method_count++;
iresult = g_new0 (MonoMethodInflated, 1);
iresult->context = *context;
iresult->declaring = method;
+ iresult->is_mb_open = is_mb_open;
+
+ if (!context->method_inst && method->generic_container)
+ iresult->context.method_inst = method->generic_container->context.method_inst;
mono_loader_lock ();
cached = mono_method_inflated_lookup (iresult, FALSE);
sig = mono_method_signature (method);
if (sig->pinvoke) {
- iresult->method.pinvoke = *(MonoMethodPInvoke*)method;
+ memcpy (&iresult->method.pinvoke, method, sizeof (MonoMethodPInvoke));
} else {
- iresult->method.normal = *(MonoMethodNormal*)method;
+ memcpy (&iresult->method.normal, method, sizeof (MonoMethodNormal));
iresult->method.normal.header = NULL;
}
result = (MonoMethod *) iresult;
result->is_inflated = 1;
- /* result->generic_container = NULL; */
result->signature = NULL;
+ if (context->method_inst)
+ result->generic_container = NULL;
+
+ /* Due to the memcpy above, !context->method_inst => result->generic_container == method->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)
mono_metadata_free_type (inflated);
}
- if (context->method_inst)
- result->generic_container = NULL;
- else if (method->generic_container)
- iresult->context.method_inst = method->generic_container->context.method_inst;
-
mono_method_inflated_lookup (iresult, TRUE);
mono_loader_unlock ();
return result;
MonoClass *gklass = class->generic_class->container_class;
mono_class_setup_fields (gklass);
top = gklass->field.count;
+ class->field.count = gklass->field.count;
}
class->instance_size = 0;
continue;
size = mono_type_size (field->type, &align);
-
+ class->min_align = MAX (align, class->min_align);
+
/*
* When we get here, field->offset is already set by the
* loader (for either runtime fields or fields loaded from metadata).
for (i = 0; i < class->method.count; ++i) {
int idx = mono_metadata_translate_token_index (class->image, MONO_TABLE_METHOD, class->method.first + i + 1);
methods [i] = mono_get_method (class->image, MONO_TOKEN_METHOD_DEF | idx, class);
- if (class->valuetype && methods [i]->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED && !(methods [i]->flags & MONO_METHOD_ATTR_STATIC))
- mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
}
}
printf ("Packed interface table for class %s has size %d\n", klass->name, klass->interface_offsets_count);
for (i = 0; i < klass->interface_offsets_count; i++)
- printf (" [%d][UUID %d][SLOT %d] interface %s\n", i,
+ printf (" [%03d][UUID %03d][SLOT %03d][SIZE %03d] interface %s.%s\n", i,
klass->interfaces_packed [i]->interface_id,
klass->interface_offsets_packed [i],
+ klass->interfaces_packed [i]->method.count,
+ klass->interfaces_packed [i]->name_space,
klass->interfaces_packed [i]->name );
printf ("Interface flags: ");
for (i = 0; i <= klass->max_interface_id; i++)
for (i = 0; i < ifaces->len; i++) {
MonoClass *ic = g_ptr_array_index (ifaces, i);
printf (" [UIID %d] interface %s\n", ic->interface_id, ic->name);
+ printf (" [%03d][UUID %03d][SLOT %03d][SIZE %03d] interface %s.%s\n", i,
+ ic->interface_id,
+ mono_class_interface_offset (klass, ic),
+ ic->method.count,
+ ic->name_space,
+ ic->name );
}
g_ptr_array_free (ifaces, TRUE);
}
}
}
+
+static int __use_new_interface_vtable_code = -1;
+static gboolean
+use_new_interface_vtable_code (void) {
+ if (__use_new_interface_vtable_code == -1) {
+ char *env_var = getenv ("MONO_USE_NEW_INTERFACE_VTABLE_CODE");
+ if (env_var == NULL) {
+ __use_new_interface_vtable_code = TRUE;
+ } else {
+ if ((strcmp (env_var, "0") == 0) || (strcmp (env_var, "false") == 0) || (strcmp (env_var, "FALSE") == 0)) {
+ __use_new_interface_vtable_code = FALSE;
+ } else {
+ __use_new_interface_vtable_code = TRUE;
+ }
+ }
+ }
+ return __use_new_interface_vtable_code;
+}
+
+
+#define DEBUG_INTERFACE_VTABLE_CODE 0
+#define TRACE_INTERFACE_VTABLE_CODE 0
+
+#if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
+#define DEBUG_INTERFACE_VTABLE(stmt) do {\
+ stmt;\
+} while (0)
+#else
+#define DEBUG_INTERFACE_VTABLE(stmt)
+#endif
+
+#if TRACE_INTERFACE_VTABLE_CODE
+#define TRACE_INTERFACE_VTABLE(stmt) do {\
+ stmt;\
+} while (0)
+#else
+#define TRACE_INTERFACE_VTABLE(stmt)
+#endif
+
+
+#if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
+static char*
+mono_signature_get_full_desc (MonoMethodSignature *sig, gboolean include_namespace)
+{
+ int i;
+ char *result;
+ GString *res = g_string_new ("");
+
+ g_string_append_c (res, '(');
+ for (i = 0; i < sig->param_count; ++i) {
+ if (i > 0)
+ g_string_append_c (res, ',');
+ mono_type_get_desc (res, sig->params [i], include_namespace);
+ }
+ g_string_append (res, ")=>");
+ if (sig->ret != NULL) {
+ mono_type_get_desc (res, sig->ret, include_namespace);
+ } else {
+ g_string_append (res, "NULL");
+ }
+ result = res->str;
+ g_string_free (res, FALSE);
+ return result;
+}
+static void
+print_method_signatures (MonoMethod *im, MonoMethod *cm) {
+ char *im_sig = mono_signature_get_full_desc (mono_method_signature (im), TRUE);
+ char *cm_sig = mono_signature_get_full_desc (mono_method_signature (cm), TRUE);
+ printf ("(IM \"%s\", CM \"%s\")", im_sig, cm_sig);
+ g_free (im_sig);
+ g_free (cm_sig);
+
+}
+
+#endif
+static gboolean
+check_interface_method_override (MonoClass *class, MonoMethod *im, MonoMethod *cm, gboolean require_newslot, gboolean interface_is_explicitly_implemented_by_class, gboolean slot_is_empty, gboolean security_enabled) {
+ if (strcmp (im->name, cm->name) == 0) {
+ if (! (cm->flags & METHOD_ATTRIBUTE_PUBLIC)) {
+ TRACE_INTERFACE_VTABLE (printf ("[PUBLIC CHECK FAILED]"));
+ return FALSE;
+ }
+ if (! slot_is_empty) {
+ if (require_newslot) {
+ if (! interface_is_explicitly_implemented_by_class) {
+ TRACE_INTERFACE_VTABLE (printf ("[NOT EXPLICIT IMPLEMENTATION IN FULL SLOT REFUSED]"));
+ return FALSE;
+ }
+ if (! (cm->flags & METHOD_ATTRIBUTE_NEW_SLOT)) {
+ TRACE_INTERFACE_VTABLE (printf ("[NEWSLOT CHECK FAILED]"));
+ return FALSE;
+ }
+ } else {
+ TRACE_INTERFACE_VTABLE (printf ("[FULL SLOT REFUSED]"));
+ }
+ }
+ if (! mono_metadata_signature_equal (mono_method_signature (cm), mono_method_signature (im))) {
+ TRACE_INTERFACE_VTABLE (printf ("[SIGNATURE CHECK FAILED "));
+ TRACE_INTERFACE_VTABLE (print_method_signatures (im, cm));
+ TRACE_INTERFACE_VTABLE (printf ("]"));
+ return FALSE;
+ }
+ TRACE_INTERFACE_VTABLE (printf ("[SECURITY CHECKS]"));
+ /* CAS - SecurityAction.InheritanceDemand on interface */
+ if (security_enabled && (im->flags & METHOD_ATTRIBUTE_HAS_SECURITY)) {
+ mono_secman_inheritancedemand_method (cm, im);
+ }
+
+ if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
+ check_core_clr_override_method (class, cm, im);
+ TRACE_INTERFACE_VTABLE (printf ("[NAME CHECK OK]"));
+ return TRUE;
+ } else {
+ MonoClass *ic = im->klass;
+ const char *ic_name_space = ic->name_space;
+ const char *ic_name = ic->name;
+ char *subname;
+
+ if (! require_newslot) {
+ TRACE_INTERFACE_VTABLE (printf ("[INJECTED METHOD REFUSED]"));
+ return FALSE;
+ }
+ if (cm->klass->rank == 0) {
+ TRACE_INTERFACE_VTABLE (printf ("[RANK CHECK FAILED]"));
+ return FALSE;
+ }
+ if (! mono_metadata_signature_equal (mono_method_signature (cm), mono_method_signature (im))) {
+ TRACE_INTERFACE_VTABLE (printf ("[(INJECTED) SIGNATURE CHECK FAILED "));
+ TRACE_INTERFACE_VTABLE (print_method_signatures (im, cm));
+ TRACE_INTERFACE_VTABLE (printf ("]"));
+ return FALSE;
+ }
+ if (mono_class_get_image (ic) != mono_defaults.corlib) {
+ TRACE_INTERFACE_VTABLE (printf ("[INTERFACE CORLIB CHECK FAILED]"));
+ return FALSE;
+ }
+ if ((ic_name_space == NULL) || (strcmp (ic_name_space, "System.Collections.Generic") != 0)) {
+ TRACE_INTERFACE_VTABLE (printf ("[INTERFACE NAMESPACE CHECK FAILED]"));
+ return FALSE;
+ }
+ if ((ic_name == NULL) || ((strcmp (ic_name, "IEnumerable`1") != 0) && (strcmp (ic_name, "ICollection`1") != 0) && (strcmp (ic_name, "IList`1") != 0))) {
+ TRACE_INTERFACE_VTABLE (printf ("[INTERFACE NAME CHECK FAILED]"));
+ return FALSE;
+ }
+
+ subname = strstr (cm->name, ic_name_space);
+ if (subname != cm->name) {
+ TRACE_INTERFACE_VTABLE (printf ("[ACTUAL NAMESPACE CHECK FAILED]"));
+ return FALSE;
+ }
+ subname += strlen (ic_name_space);
+ if (subname [0] != '.') {
+ TRACE_INTERFACE_VTABLE (printf ("[FIRST DOT CHECK FAILED]"));
+ return FALSE;
+ }
+ subname ++;
+ if (strstr (subname, ic_name) != subname) {
+ TRACE_INTERFACE_VTABLE (printf ("[ACTUAL CLASS NAME CHECK FAILED]"));
+ return FALSE;
+ }
+ subname += strlen (ic_name);
+ if (subname [0] != '.') {
+ TRACE_INTERFACE_VTABLE (printf ("[SECOND DOT CHECK FAILED]"));
+ return FALSE;
+ }
+ subname ++;
+ if (strcmp (subname, im->name) != 0) {
+ TRACE_INTERFACE_VTABLE (printf ("[METHOD NAME CHECK FAILED]"));
+ return FALSE;
+ }
+
+ TRACE_INTERFACE_VTABLE (printf ("[SECURITY CHECKS (INJECTED CASE)]"));
+ /* CAS - SecurityAction.InheritanceDemand on interface */
+ if (security_enabled && (im->flags & METHOD_ATTRIBUTE_HAS_SECURITY)) {
+ mono_secman_inheritancedemand_method (cm, im);
+ }
+
+ if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
+ check_core_clr_override_method (class, cm, im);
+
+ TRACE_INTERFACE_VTABLE (printf ("[INJECTED INTERFACE CHECK OK]"));
+ return TRUE;
+ }
+}
+
+#if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
+static void
+foreach_override (gpointer key, gpointer value, gpointer user_data) {
+ MonoMethod *method = key;
+ MonoMethod *override = value;
+ MonoClass *method_class = mono_method_get_class (method);
+ MonoClass *override_class = mono_method_get_class (override);
+
+ printf (" Method '%s.%s:%s' has override '%s.%s:%s'\n",
+ mono_class_get_namespace (method_class), mono_class_get_name (method_class), mono_method_get_name (method),
+ mono_class_get_namespace (override_class), mono_class_get_name (override_class), mono_method_get_name (override));
+}
+static void
+print_overrides (GHashTable *override_map, const char *message) {
+ if (override_map) {
+ printf ("Override map \"%s\" START:\n", message);
+ g_hash_table_foreach (override_map, foreach_override, NULL);
+ printf ("Override map \"%s\" END.\n", message);
+ } else {
+ printf ("Override map \"%s\" EMPTY.\n", message);
+ }
+}
+static void
+print_vtable_full (MonoClass *class, MonoMethod** vtable, int size, int first_non_interface_slot, const char *message, gboolean print_interfaces) {
+ char *full_name = mono_type_full_name (&class->byval_arg);
+ int i;
+ int parent_size;
+
+ printf ("*** Vtable for class '%s' at \"%s\" (size %d)\n", full_name, message, size);
+
+ if (print_interfaces) {
+ print_implemented_interfaces (class);
+ printf ("* Interfaces for class '%s' done.\nStarting vtable (size %d):\n", full_name, size);
+ }
+
+ if (class->parent) {
+ parent_size = class->parent->vtable_size;
+ } else {
+ parent_size = 0;
+ }
+ for (i = 0; i < size; ++i) {
+ MonoMethod *cm = vtable [i];
+ if (cm) {
+ char *cm_name = mono_method_full_name (cm, TRUE);
+ char newness = (i < parent_size) ? 'O' : ((i < first_non_interface_slot) ? 'I' : 'N');
+ printf (" [%c][%03d][INDEX %03d] %s\n", newness, i, cm->slot, cm_name);
+ g_free (cm_name);
+ }
+ }
+
+ g_free (full_name);
+}
+#endif
+
+static void
+print_unimplemented_interface_method_info (MonoClass *class, MonoClass *ic, MonoMethod *im, int im_slot, MonoMethod **overrides, int onum) {
+ int index;
+ char *method_signature;
+
+ for (index = 0; index < onum; ++index) {
+ g_print (" at slot %d: %s (%d) overrides %s (%d)\n", im_slot, overrides [index*2+1]->name,
+ overrides [index*2+1]->slot, overrides [index*2]->name, overrides [index*2]->slot);
+ }
+ method_signature = mono_signature_get_desc (mono_method_signature (im), FALSE);
+ printf ("no implementation for interface method %s::%s(%s) in class %s.%s\n",
+ mono_type_get_name (&ic->byval_arg), im->name, method_signature, class->name_space, class->name);
+ g_free (method_signature);
+ for (index = 0; index < class->method.count; ++index) {
+ MonoMethod *cm = class->methods [index];
+ method_signature = mono_signature_get_desc (mono_method_signature (cm), TRUE);
+
+ printf ("METHOD %s(%s)\n", cm->name, method_signature);
+ g_free (method_signature);
+ }
+}
+
/*
* LOCKING: this is supposed to be called with the loader lock held.
*/
GPtrArray *ifaces, *pifaces = NULL;
GHashTable *override_map = NULL;
gboolean security_enabled = mono_is_security_manager_active ();
+#if (DEBUG_INTERFACE_VTABLE_CODE|TRACE_INTERFACE_VTABLE_CODE)
+ int first_non_interface_slot;
+#endif
if (class->vtable)
return;
max_vtsize += ic->method.count;
}
g_ptr_array_free (ifaces, TRUE);
+ ifaces = NULL;
}
if (class->parent) {
cur_slot = setup_interface_offsets (class, cur_slot);
max_iid = class->max_interface_id;
+ DEBUG_INTERFACE_VTABLE (first_non_interface_slot = cur_slot);
- if (class->parent && class->parent->vtable_size)
- memcpy (vtable, class->parent->vtable, sizeof (gpointer) * class->parent->vtable_size);
+ if (use_new_interface_vtable_code ()) {
+ if (class->parent && class->parent->vtable_size) {
+ MonoClass *parent = class->parent;
+ int i;
+
+ memcpy (vtable, parent->vtable, sizeof (gpointer) * parent->vtable_size);
+
+ // Also inherit parent interface vtables, just as a starting point.
+ // This is needed otherwise bug-77127.exe fails when the property methods
+ // have different names in the iterface and the class, because for child
+ // classes the ".override" information is not used anymore.
+ for (i = 0; i < parent->interface_offsets_count; i++) {
+ MonoClass *parent_interface = parent->interfaces_packed [i];
+ int interface_offset = mono_class_interface_offset (class, parent_interface);
+
+ if (interface_offset >= parent->vtable_size) {
+ int parent_interface_offset = mono_class_interface_offset (parent, parent_interface);
+ int j;
+
+ mono_class_setup_methods (parent_interface);
+ TRACE_INTERFACE_VTABLE (printf (" +++ Inheriting interface %s.%s\n", parent_interface->name_space, parent_interface->name));
+ for (j = 0; j < parent_interface->method.count; 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,
+ interface_offset + j, interface_offset, j));
+ }
+ }
+
+ }
+ }
+ } else {
+ if (class->parent && class->parent->vtable_size)
+ memcpy (vtable, class->parent->vtable, sizeof (gpointer) * class->parent->vtable_size);
+ }
+ TRACE_INTERFACE_VTABLE (print_vtable_full (class, vtable, cur_slot, first_non_interface_slot, "AFTER INHERITING PARENT VTABLE", TRUE));
/* override interface methods */
for (i = 0; i < onum; i++) {
MonoMethod *decl = overrides [i*2];
check_core_clr_override_method (class, vtable [dslot], decl);
}
}
+ TRACE_INTERFACE_VTABLE (print_overrides (override_map, "AFTER OVERRIDING INTERFACE METHODS"));
+ TRACE_INTERFACE_VTABLE (print_vtable_full (class, vtable, cur_slot, first_non_interface_slot, "AFTER OVERRIDING INTERFACE METHODS", FALSE));
- for (k = class; k ; k = k->parent) {
- int nifaces = 0;
-
- ifaces = mono_class_get_implemented_interfaces (k);
- if (ifaces) {
- nifaces = ifaces->len;
- if (k->generic_class) {
- pifaces = mono_class_get_implemented_interfaces (
- k->generic_class->container_class);
- g_assert (pifaces && (pifaces->len == nifaces));
- }
- }
- for (i = 0; i < nifaces; i++) {
- MonoClass *pic = NULL;
- int j, l, io;
-
- ic = g_ptr_array_index (ifaces, i);
- if (pifaces)
- pic = g_ptr_array_index (pifaces, i);
- g_assert (ic->interface_id <= k->max_interface_id);
- io = mono_class_interface_offset (k, ic);
-
- g_assert (io >= 0);
- g_assert (io <= max_vtsize);
-
- if (k == class) {
- mono_class_setup_methods (ic);
- for (l = 0; l < ic->method.count; l++) {
- MonoMethod *im = ic->methods [l];
-
- if (vtable [io + l] && !(vtable [io + l]->flags & METHOD_ATTRIBUTE_ABSTRACT))
- continue;
-
- for (j = 0; j < class->method.count; ++j) {
- MonoMethod *cm = class->methods [j];
- if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
- !((cm->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) == METHOD_ATTRIBUTE_PUBLIC) ||
- !(cm->flags & METHOD_ATTRIBUTE_NEW_SLOT))
- continue;
- if (!strcmp(cm->name, im->name) &&
- mono_metadata_signature_equal (mono_method_signature (cm), mono_method_signature (im))) {
-
- /* CAS - SecurityAction.InheritanceDemand on interface */
- if (security_enabled && (im->flags & METHOD_ATTRIBUTE_HAS_SECURITY)) {
- mono_secman_inheritancedemand_method (cm, im);
- }
-
- if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
- check_core_clr_override_method (class, cm, im);
+ if (use_new_interface_vtable_code ()) {
+ // Loop on all implemented interfaces...
+ for (i = 0; i < class->interface_offsets_count; i++) {
+ MonoClass *parent = class->parent;
+ int ic_offset;
+ gboolean interface_is_explicitly_implemented_by_class;
+ int im_index;
+
+ ic = class->interfaces_packed [i];
+ ic_offset = mono_class_interface_offset (class, ic);
- g_assert (io + l <= max_vtsize);
- vtable [io + l] = cm;
- }
+ mono_class_setup_methods (ic);
+
+ // Check if this interface is explicitly implemented (instead of just inherited)
+ if (parent != NULL) {
+ int implemented_interfaces_index;
+ interface_is_explicitly_implemented_by_class = FALSE;
+ for (implemented_interfaces_index = 0; implemented_interfaces_index < class->interface_count; implemented_interfaces_index++) {
+ if (ic == class->interfaces [implemented_interfaces_index]) {
+ interface_is_explicitly_implemented_by_class = TRUE;
+ break;
}
}
} else {
- /* already implemented */
- if (io >= k->vtable_size)
- continue;
+ interface_is_explicitly_implemented_by_class = TRUE;
}
-
- // Override methods with the same fully qualified name
- for (l = 0; l < ic->method.count; l++) {
- MonoMethod *im = ic->methods [l];
- char *qname, *fqname, *cname, *the_cname;
- MonoClass *k1;
+
+ // Loop on all interface methods...
+ for (im_index = 0; im_index < ic->method.count; im_index++) {
+ MonoMethod *im = ic->methods [im_index];
+ int im_slot = ic_offset + im->slot;
+ MonoMethod *override_im = (override_map != NULL) ? g_hash_table_lookup (override_map, im) : NULL;
- if (vtable [io + l])
+ if (im->flags & METHOD_ATTRIBUTE_STATIC)
continue;
- if (pic) {
- the_cname = mono_type_get_name_full (&pic->byval_arg, MONO_TYPE_NAME_FORMAT_IL);
- cname = the_cname;
+ // If there is an explicit implementation, just use it right away,
+ // otherwise look for a matching method
+ if (override_im == NULL) {
+ int cm_index;
+
+ // First look for a suitable method among the class methods
+ for (cm_index = 0; cm_index < class->method.count; cm_index++) {
+ MonoMethod *cm = class->methods [cm_index];
+
+ TRACE_INTERFACE_VTABLE (printf (" For slot %d ('%s'.'%s':'%s'), trying method '%s'.'%s':'%s'... [EXPLICIT IMPLEMENTATION = %d][SLOT IS NULL = %d]", im_slot, ic->name_space, ic->name, im->name, cm->klass->name_space, cm->klass->name, cm->name, interface_is_explicitly_implemented_by_class, (vtable [im_slot] == NULL)));
+ if ((cm->flags & METHOD_ATTRIBUTE_VIRTUAL) && check_interface_method_override (class, im, cm, TRUE, interface_is_explicitly_implemented_by_class, (vtable [im_slot] == NULL), security_enabled)) {
+ TRACE_INTERFACE_VTABLE (printf ("[check ok]: ASSIGNING"));
+ vtable [im_slot] = cm;
+ /* Why do we need this? */
+ if (cm->slot < 0) {
+ cm->slot = im_slot;
+ }
+ }
+ TRACE_INTERFACE_VTABLE (printf ("\n"));
+ }
+
+ // If the slot is still empty, look in all the inherited virtual methods...
+ if ((vtable [im_slot] == NULL) && class->parent != NULL) {
+ MonoClass *parent = class->parent;
+ // Reverse order, so that last added methods are preferred
+ for (cm_index = parent->vtable_size - 1; cm_index >= 0; cm_index--) {
+ MonoMethod *cm = parent->vtable [cm_index];
+
+ TRACE_INTERFACE_VTABLE ((cm != NULL) && printf (" For slot %d ('%s'.'%s':'%s'), trying (ancestor) method '%s'.'%s':'%s'... ", im_slot, ic->name_space, ic->name, im->name, cm->klass->name_space, cm->klass->name, cm->name));
+ if ((cm != NULL) && check_interface_method_override (class, im, cm, FALSE, FALSE, TRUE, security_enabled)) {
+ TRACE_INTERFACE_VTABLE (printf ("[everything ok]: ASSIGNING"));
+ vtable [im_slot] = cm;
+ /* Why do we need this? */
+ if (cm->slot < 0) {
+ cm->slot = im_slot;
+ }
+ break;
+ }
+ TRACE_INTERFACE_VTABLE ((cm != NULL) && printf ("\n"));
+ }
+ }
} else {
- the_cname = NULL;
- cname = (char*)ic->name;
+ g_assert (vtable [im_slot] == override_im);
}
+ }
+ }
+
+ // If the class is not abstract, check that all its interface slots are full.
+ // The check is done here and not directly at the end of the loop above because
+ // 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 (! (class->flags & TYPE_ATTRIBUTE_ABSTRACT)) {
+ for (i = 0; i < class->interface_offsets_count; i++) {
+ int ic_offset;
+ int im_index;
+
+ ic = class->interfaces_packed [i];
+ ic_offset = mono_class_interface_offset (class, ic);
+
+ for (im_index = 0; im_index < ic->method.count; im_index++) {
+ MonoMethod *im = ic->methods [im_index];
+ int im_slot = ic_offset + im->slot;
- qname = g_strconcat (cname, ".", im->name, NULL);
- if (ic->name_space && ic->name_space [0])
- fqname = g_strconcat (ic->name_space, ".", cname, ".", im->name, NULL);
- else
- fqname = NULL;
+ if (im->flags & METHOD_ATTRIBUTE_STATIC)
+ continue;
- for (k1 = class; k1; k1 = k1->parent) {
- for (j = 0; j < k1->method.count; ++j) {
- MonoMethod *cm = k1->methods [j];
+ TRACE_INTERFACE_VTABLE (printf (" [class is not abstract, checking slot %d for interface '%s'.'%s', method %s, slot check is %d]\n",
+ im_slot, ic->name_space, ic->name, im->name, (vtable [im_slot] == NULL)));
+ if (vtable [im_slot] == NULL) {
+ print_unimplemented_interface_method_info (class, ic, im, im_slot, overrides, onum);
+ mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ if (override_map)
+ g_hash_table_destroy (override_map);
+ return;
+ }
+ }
+ }
+ }
+ } else {
+ for (k = class; k ; k = k->parent) {
+ int nifaces = 0;
+
+ ifaces = mono_class_get_implemented_interfaces (k);
+ if (ifaces) {
+ nifaces = ifaces->len;
+ if (k->generic_class) {
+ pifaces = mono_class_get_implemented_interfaces (
+ k->generic_class->container_class);
+ g_assert (pifaces && (pifaces->len == nifaces));
+ }
+ }
+ for (i = 0; i < nifaces; i++) {
+ MonoClass *pic = NULL;
+ int j, l, io;
- if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL))
- continue;
+ ic = g_ptr_array_index (ifaces, i);
+ if (pifaces)
+ pic = g_ptr_array_index (pifaces, i);
+ g_assert (ic->interface_id <= k->max_interface_id);
+ io = mono_class_interface_offset (k, ic);
- if (((fqname && !strcmp (cm->name, fqname)) || !strcmp (cm->name, qname)) &&
- mono_metadata_signature_equal (mono_method_signature (cm), mono_method_signature (im)) &&
- ((vtable [io + l] == NULL) || mono_class_is_subclass_of (cm->klass, vtable [io + l]->klass, FALSE))) {
+ g_assert (io >= 0);
+ g_assert (io <= max_vtsize);
- /* CAS - SecurityAction.InheritanceDemand on interface */
- if (security_enabled && (im->flags & METHOD_ATTRIBUTE_HAS_SECURITY)) {
- mono_secman_inheritancedemand_method (cm, im);
- }
+ if (k == class) {
+ mono_class_setup_methods (ic);
+ for (l = 0; l < ic->method.count; l++) {
+ MonoMethod *im = ic->methods [l];
- if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
- check_core_clr_override_method (class, cm, im);
+ if (vtable [io + l] && !(vtable [io + l]->flags & METHOD_ATTRIBUTE_ABSTRACT))
+ continue;
- g_assert (io + l <= max_vtsize);
- vtable [io + l] = cm;
- break;
+ for (j = 0; j < class->method.count; ++j) {
+ MonoMethod *cm = class->methods [j];
+ if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
+ !((cm->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) == METHOD_ATTRIBUTE_PUBLIC) ||
+ !(cm->flags & METHOD_ATTRIBUTE_NEW_SLOT))
+ continue;
+ if (!strcmp(cm->name, im->name) &&
+ mono_metadata_signature_equal (mono_method_signature (cm), mono_method_signature (im))) {
+
+ /* CAS - SecurityAction.InheritanceDemand on interface */
+ if (security_enabled && (im->flags & METHOD_ATTRIBUTE_HAS_SECURITY)) {
+ mono_secman_inheritancedemand_method (cm, im);
+ }
+
+ if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
+ check_core_clr_override_method (class, cm, im);
+
+ g_assert (io + l <= max_vtsize);
+ vtable [io + l] = cm;
+ TRACE_INTERFACE_VTABLE (printf (" [NOA] Filling slot %d (%d+%d) with method '%s'.'%s':'%s' ", io + l, io, l, cm->klass->name_space, cm->klass->name, cm->name));
+ TRACE_INTERFACE_VTABLE (print_method_signatures (im, cm));
+ TRACE_INTERFACE_VTABLE (printf ("\n"));
+ }
}
}
+ } else {
+ /* already implemented */
+ if (io >= k->vtable_size)
+ continue;
}
- g_free (the_cname);
- g_free (qname);
- g_free (fqname);
- }
- // Override methods with the same name
- for (l = 0; l < ic->method.count; l++) {
- MonoMethod *im = ic->methods [l];
- MonoClass *k1;
-
- g_assert (io + l <= max_vtsize);
-
- if (vtable [io + l] && !(vtable [io + l]->flags & METHOD_ATTRIBUTE_ABSTRACT))
- continue;
+ // Override methods with the same fully qualified name
+ for (l = 0; l < ic->method.count; l++) {
+ MonoMethod *im = ic->methods [l];
+ char *qname, *fqname, *cname, *the_cname;
+ MonoClass *k1;
- for (k1 = class; k1; k1 = k1->parent) {
- for (j = 0; j < k1->method.count; ++j) {
- MonoMethod *cm = k1->methods [j];
+ if (vtable [io + l])
+ continue;
- if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
- !(cm->flags & METHOD_ATTRIBUTE_PUBLIC))
- continue;
+ if (pic) {
+ the_cname = mono_type_get_name_full (&pic->byval_arg, MONO_TYPE_NAME_FORMAT_IL);
+ cname = the_cname;
+ } else {
+ the_cname = NULL;
+ cname = (char*)ic->name;
+ }
- if (!strcmp(cm->name, im->name) &&
- mono_metadata_signature_equal (mono_method_signature (cm), mono_method_signature (im))) {
-
- /* CAS - SecurityAction.InheritanceDemand on interface */
- if (security_enabled && (im->flags & METHOD_ATTRIBUTE_HAS_SECURITY)) {
- mono_secman_inheritancedemand_method (cm, im);
+ qname = g_strconcat (cname, ".", im->name, NULL);
+ if (ic->name_space && ic->name_space [0])
+ fqname = g_strconcat (ic->name_space, ".", cname, ".", im->name, NULL);
+ else
+ fqname = NULL;
+
+ for (k1 = class; k1; k1 = k1->parent) {
+ for (j = 0; j < k1->method.count; ++j) {
+ MonoMethod *cm = k1->methods [j];
+
+ if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL))
+ continue;
+
+ if (((fqname && !strcmp (cm->name, fqname)) || !strcmp (cm->name, qname)) &&
+ mono_metadata_signature_equal (mono_method_signature (cm), mono_method_signature (im)) &&
+ ((vtable [io + l] == NULL) || mono_class_is_subclass_of (cm->klass, vtable [io + l]->klass, FALSE))) {
+
+ /* CAS - SecurityAction.InheritanceDemand on interface */
+ if (security_enabled && (im->flags & METHOD_ATTRIBUTE_HAS_SECURITY)) {
+ mono_secman_inheritancedemand_method (cm, im);
+ }
+
+ if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
+ check_core_clr_override_method (class, cm, im);
+
+ g_assert (io + l <= max_vtsize);
+ vtable [io + l] = cm;
+ TRACE_INTERFACE_VTABLE (printf (" [FQN] Filling slot %d (%d+%d) with method '%s'.'%s':'%s' ", io + l, io, l, cm->klass->name_space, cm->klass->name, cm->name));
+ TRACE_INTERFACE_VTABLE (print_method_signatures (im, cm));
+ TRACE_INTERFACE_VTABLE (printf ("\n"));
+ break;
}
-
- if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
- check_core_clr_override_method (class, cm, im);
-
- g_assert (io + l <= max_vtsize);
- vtable [io + l] = cm;
- break;
}
-
}
- g_assert (io + l <= max_vtsize);
- if (vtable [io + l] && !(vtable [io + l]->flags & METHOD_ATTRIBUTE_ABSTRACT))
- break;
+ g_free (the_cname);
+ g_free (qname);
+ g_free (fqname);
}
- }
- if (!(class->flags & TYPE_ATTRIBUTE_ABSTRACT)) {
+ // Override methods with the same name
for (l = 0; l < ic->method.count; l++) {
- char *msig;
- MonoMethod *im = ic->methods [l];
- if (im->flags & METHOD_ATTRIBUTE_STATIC)
- continue;
+ MonoMethod *im = ic->methods [l];
+ MonoClass *k1;
+
g_assert (io + l <= max_vtsize);
- /*
- * If one of our parents already implements this interface
- * we can inherit the implementation.
- */
- if (!(vtable [io + l])) {
- MonoClass *parent = class->parent;
+ if (vtable [io + l] && !(vtable [io + l]->flags & METHOD_ATTRIBUTE_ABSTRACT))
+ continue;
- for (; parent; parent = parent->parent) {
- if (MONO_CLASS_IMPLEMENTS_INTERFACE (parent, ic->interface_id) &&
- parent->vtable) {
- vtable [io + l] = parent->vtable [mono_class_interface_offset (parent, ic) + l];
+ for (k1 = class; k1; k1 = k1->parent) {
+ for (j = 0; j < k1->method.count; ++j) {
+ MonoMethod *cm = k1->methods [j];
+
+ if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
+ !(cm->flags & METHOD_ATTRIBUTE_PUBLIC))
+ continue;
+
+ if (!strcmp(cm->name, im->name) &&
+ mono_metadata_signature_equal (mono_method_signature (cm), mono_method_signature (im))) {
+
+ /* CAS - SecurityAction.InheritanceDemand on interface */
+ if (security_enabled && (im->flags & METHOD_ATTRIBUTE_HAS_SECURITY)) {
+ mono_secman_inheritancedemand_method (cm, im);
+ }
+
+ if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
+ check_core_clr_override_method (class, cm, im);
+
+ g_assert (io + l <= max_vtsize);
+ vtable [io + l] = cm;
+ TRACE_INTERFACE_VTABLE (printf (" [SQN] Filling slot %d (%d+%d) with method '%s'.'%s':'%s' ", io + l, io, l, cm->klass->name_space, cm->klass->name, cm->name));
+ TRACE_INTERFACE_VTABLE (print_method_signatures (im, cm));
+ TRACE_INTERFACE_VTABLE (printf ("\n"));
+ break;
}
+
}
+ g_assert (io + l <= max_vtsize);
+ if (vtable [io + l] && !(vtable [io + l]->flags & METHOD_ATTRIBUTE_ABSTRACT))
+ break;
}
+ }
- if (!(vtable [io + l])) {
- for (j = 0; j < onum; ++j) {
- g_print (" at slot %d: %s (%d) overrides %s (%d)\n", io+l, overrides [j*2+1]->name,
- overrides [j*2+1]->slot, overrides [j*2]->name, overrides [j*2]->slot);
- }
- msig = mono_signature_get_desc (mono_method_signature (im), FALSE);
- printf ("no implementation for interface method %s::%s(%s) in class %s.%s\n",
- mono_type_get_name (&ic->byval_arg), im->name, msig, class->name_space, class->name);
- g_free (msig);
- for (j = 0; j < class->method.count; ++j) {
- MonoMethod *cm = class->methods [j];
- msig = mono_signature_get_desc (mono_method_signature (cm), TRUE);
+ if (!(class->flags & TYPE_ATTRIBUTE_ABSTRACT)) {
+ for (l = 0; l < ic->method.count; l++) {
+ char *msig;
+ MonoMethod *im = ic->methods [l];
+ if (im->flags & METHOD_ATTRIBUTE_STATIC)
+ continue;
+ g_assert (io + l <= max_vtsize);
+
+ /*
+ * If one of our parents already implements this interface
+ * we can inherit the implementation.
+ */
+ if (!(vtable [io + l])) {
+ MonoClass *parent = class->parent;
- printf ("METHOD %s(%s)\n", cm->name, msig);
- g_free (msig);
+ for (; parent; parent = parent->parent) {
+ if (MONO_CLASS_IMPLEMENTS_INTERFACE (parent, ic->interface_id) &&
+ parent->vtable) {
+ vtable [io + l] = parent->vtable [mono_class_interface_offset (parent, ic) + l];
+ TRACE_INTERFACE_VTABLE (printf (" [INH] Filling slot %d (%d+%d) with method '%s'.'%s':'%s'\n", io + l, io, l, vtable [io + l]->klass->name_space, vtable [io + l]->klass->name, vtable [io + l]->name));
+ }
+ }
}
- mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ if (!(vtable [io + l])) {
+ for (j = 0; j < onum; ++j) {
+ g_print (" at slot %d: %s (%d) overrides %s (%d)\n", io+l, overrides [j*2+1]->name,
+ overrides [j*2+1]->slot, overrides [j*2]->name, overrides [j*2]->slot);
+ }
+ msig = mono_signature_get_desc (mono_method_signature (im), FALSE);
+ printf ("no implementation for interface method %s::%s(%s) in class %s.%s\n",
+ mono_type_get_name (&ic->byval_arg), im->name, msig, class->name_space, class->name);
+ g_free (msig);
+ for (j = 0; j < class->method.count; ++j) {
+ MonoMethod *cm = class->methods [j];
+ msig = mono_signature_get_desc (mono_method_signature (cm), TRUE);
+
+ printf ("METHOD %s(%s)\n", cm->name, msig);
+ g_free (msig);
+ }
- if (ifaces)
- g_ptr_array_free (ifaces, TRUE);
- if (override_map)
- g_hash_table_destroy (override_map);
+ mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
- return;
+ if (ifaces)
+ g_ptr_array_free (ifaces, TRUE);
+ if (override_map)
+ g_hash_table_destroy (override_map);
+
+ return;
+ }
}
}
- }
-
- for (l = 0; l < ic->method.count; l++) {
- MonoMethod *im = vtable [io + l];
-
- if (im) {
- g_assert (io + l <= max_vtsize);
- if (im->slot < 0) {
- /* FIXME: why do we need this ? */
- im->slot = io + l;
- /* g_assert_not_reached (); */
+
+ for (l = 0; l < ic->method.count; l++) {
+ MonoMethod *im = vtable [io + l];
+
+ if (im) {
+ g_assert (io + l <= max_vtsize);
+ if (im->slot < 0) {
+ /* FIXME: why do we need this ? */
+ im->slot = io + l;
+ /* g_assert_not_reached (); */
+ }
}
}
}
- }
- if (ifaces)
- g_ptr_array_free (ifaces, TRUE);
- }
+ if (ifaces)
+ g_ptr_array_free (ifaces, TRUE);
+ }
+ }
+ TRACE_INTERFACE_VTABLE (print_vtable_full (class, vtable, cur_slot, first_non_interface_slot, "AFTER SETTING UP INTERFACE METHODS", FALSE));
for (i = 0; i < class->method.count; ++i) {
MonoMethod *cm;
memcpy (class->vtable, vtable, sizeof (gpointer) * class->vtable_size);
}
+ DEBUG_INTERFACE_VTABLE (print_vtable_full (class, class->vtable, class->vtable_size, first_non_interface_slot, "FINALLY", FALSE));
if (mono_print_vtable) {
int icount = 0;
break;
}
+ case MONO_EXCEPTION_BAD_IMAGE:
+ class->exception_data = error->msg;
+ break;
+
default :
g_assert_not_reached ();
}
klass->name = gklass->name;
klass->name_space = gklass->name_space;
+
+ mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
+
klass->image = gklass->image;
klass->flags = gklass->flags;
klass->type_token = gklass->type_token;
if (MONO_CLASS_IS_INTERFACE (klass))
setup_interface_offsets (klass, 0);
+ mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
+
mono_loader_unlock ();
return klass;
/**
* mono_class_from_name_case:
- * @image: The MonoImage where the type is looked up in, or NULL for looking up in all loaded assemblies
+ * @image: The MonoImage where the type is looked up in
* @name_space: the type namespace
* @name: the type short name.
*
/**
* mono_class_from_name:
- * @image: The MonoImage where the type is looked up in, or NULL for looking up in all loaded assemblies
+ * @image: The MonoImage where the type is looked up in
* @name_space: the type namespace
* @name: the type short name.
*
return FALSE;
}
+/**
+ * mono_class_is_assignable_from:
+ * @klass: the class to be assigned to
+ * @oklass: the source class
+ *
+ * Return: 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)
{
return mono_class_has_parent (oklass, klass);
}
-/*
+/**
* 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 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)
}
}
-/*
+/**
* mono_class_needs_cctor_run:
+ * @klass: the MonoClass pointer
+ * @caller: a MonoMethod describing the caller
*
- * Determines whenever the class has a static constructor and whenever it
+ * Determines whenever the class has a static constructor and whenever it
* needs to be called when executing CALLER.
*/
gboolean
return field->type->attrs;
}
+/**
+ * mono_field_get_offset;
+ * @field: the MonoClassField to act on
+ *
+ * Returns: the field offset.
+ */
+guint32
+mono_field_get_offset (MonoClassField *field)
+{
+ return field->offset;
+}
+
/**
* mono_field_get_data;
* @field: the MonoClassField to act on
return ex;
}
+ case MONO_EXCEPTION_BAD_IMAGE: {
+ return mono_get_exception_bad_image_format (klass->exception_data);
+ }
default: {
MonoLoaderError *error;
MonoException *ex;