#include <mono/metadata/assembly.h>
#include <mono/metadata/metadata.h>
#include <mono/metadata/metadata-internals.h>
+#include <mono/metadata/profiler-private.h>
#include <mono/metadata/tabledefs.h>
#include <mono/metadata/tokentype.h>
#include <mono/metadata/class-internals.h>
#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;
static MonoClass * mono_class_create_from_typedef (MonoImage *image, guint32 type_token);
static gboolean mono_class_get_cached_class_info (MonoClass *klass, MonoCachedClassInfo *res);
-void (*mono_debugger_start_class_init_func) (MonoClass *klass) = NULL;
void (*mono_debugger_class_init_func) (MonoClass *klass) = NULL;
+void (*mono_debugger_class_loaded_methods_func) (MonoClass *klass) = NULL;
/*
* mono_class_from_typeref:
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;
#define IS_GC_REFERENCE(t) ((t)->type == MONO_TYPE_U && class->image == mono_defaults.corlib)
#endif
+/*
+ * mono_type_get_basic_type_from_generic:
+ * @type: a type
+ *
+ * Returns a closed type corresponding to the possibly open type
+ * passed to it.
+ */
+MonoType*
+mono_type_get_basic_type_from_generic (MonoType *type)
+{
+ /* When we do generic sharing we let type variables stand for reference types. */
+ if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))
+ return &mono_defaults.object_class->byval_arg;
+ return type;
+}
+
/*
* mono_class_layout_fields:
* @class: a class
gboolean gc_aware_layout = FALSE;
MonoClassField *field;
- if (class->generic_container ||
- (class->generic_class && class->generic_class->context.class_inst->is_open))
- return;
+ /*
+ * When we do generic sharing we need to have layout
+ * information for open generic classes (either with a generic
+ * context containing type variables or with a generic
+ * container), so we don't return in that case anymore.
+ */
/*
* Enable GC aware auto layout: in this mode, reference
if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
ftype = mono_type_get_underlying_type (field->type);
+ ftype = mono_type_get_basic_type_from_generic (ftype);
if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype)))))
class->has_references = TRUE;
}
if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
ftype = mono_type_get_underlying_type (field->type);
+ ftype = mono_type_get_basic_type_from_generic (ftype);
if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype)))))
class->has_static_refs = TRUE;
}
field = &class->fields [i];
ftype = mono_type_get_underlying_type (field->type);
+ ftype = mono_type_get_basic_type_from_generic (ftype);
if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype))))) {
if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
class->has_static_refs = TRUE;
continue;
ftype = mono_type_get_underlying_type (field->type);
+ ftype = mono_type_get_basic_type_from_generic (ftype);
if (gc_aware_layout) {
if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype))))) {
if (pass == 1)
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).
*/
field->offset += sizeof (MonoObject);
ftype = mono_type_get_underlying_type (field->type);
+ ftype = mono_type_get_basic_type_from_generic (ftype);
if (MONO_TYPE_IS_REFERENCE (ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype))))) {
if (field->offset % sizeof (gpointer)) {
mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
return;
}
- if (class->generic_class && !class->generic_class->is_dynamic) {
+ if (class->generic_class) {
MonoClass *gklass = class->generic_class->container_class;
mono_class_init (gklass);
mono_class_setup_methods (gklass);
/* The + 1 makes this always non-NULL to pass the check in mono_class_setup_methods () */
+ class->method.count = gklass->method.count;
methods = g_new0 (MonoMethod *, class->method.count + 1);
for (i = 0; i < class->method.count; i++) {
/* Leave this assignment as the last op in this function */
class->methods = methods;
+ if (mono_debugger_class_loaded_methods_func)
+ mono_debugger_class_loaded_methods_func (class);
+
mono_loader_unlock ();
}
return;
}
- if (class->generic_class && !class->generic_class->is_dynamic) {
+ if (class->generic_class) {
MonoClass *gklass = class->generic_class->container_class;
class->property = gklass->property;
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);
}
interface_count *= 3;
real_count = interface_count;
if (internal_enumerator)
- real_count += idepth;
+ real_count += idepth + eclass->interface_offsets_count;
interfaces = g_malloc0 (sizeof (MonoClass*) * real_count);
if (MONO_CLASS_IS_INTERFACE (eclass)) {
interfaces [0] = mono_defaults.object_class;
/*g_print ("%s implements %s\n", class->name, mono_type_get_name_full (&interfaces [i]->byval_arg, 0));*/
j ++;
}
+ for (i = 0; i < eclass->interface_offsets_count; i++) {
+ MonoClass *iface = eclass->interfaces_packed [i];
+ MonoType *args [1];
+ args [0] = &iface->byval_arg;
+ interfaces [j] = mono_class_bind_generic_parameters (
+ generic_ienumerator_class, 1, args, FALSE);
+ /*g_print ("%s implements %s\n", class->name, mono_type_get_name_full (&interfaces [i]->byval_arg, 0));*/
+ j ++;
+ }
}
}
*num = real_count;
MonoGenericContext *context;
guint32 type_token;
int onum = 0;
+ int i;
gboolean ok = TRUE;
if (class->vtable)
type_token = class->type_token;
}
- if (class->image->dynamic)
- mono_reflection_get_dynamic_overrides (class, &overrides, &onum);
- else {
+ if (class->image->dynamic) {
+ if (class->generic_class) {
+ MonoClass *gklass = class->generic_class->container_class;
+
+ mono_reflection_get_dynamic_overrides (gklass, &overrides, &onum);
+ for (i = 0; i < onum; ++i) {
+ MonoMethod *override = overrides [(i * 2) + 1];
+ MonoMethod *inflated = NULL;
+ int j;
+
+ for (j = 0; j < class->method.count; ++j) {
+ if (gklass->methods [j] == override) {
+ inflated = class->methods [j];
+ break;
+ }
+ }
+ g_assert (inflated);
+
+ overrides [(i * 2) + 1] = inflated;
+ }
+ } else {
+ mono_reflection_get_dynamic_overrides (class, &overrides, &onum);
+ }
+ } else {
/* The following call fails if there are missing methods in the type */
ok = mono_class_get_overrides_full (class->image, type_token, &overrides, &onum, context);
}
}
}
+
+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;
GList *list = NULL, *tmp;
if (generic_array_method_num)
return generic_array_method_num;
+ mono_class_setup_methods (class->parent);
for (i = 0; i < class->parent->method.count; i++) {
MonoMethod *m = class->parent->methods [i];
if (!strncmp (m->name, "InternalArray__", 15)) {
break;
}
+ case MONO_EXCEPTION_BAD_IMAGE:
+ class->exception_data = error->msg;
+ break;
+
default :
g_assert_not_reached ();
}
if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
check_core_clr_inheritance (class);
- if (mono_debugger_start_class_init_func)
- mono_debugger_start_class_init_func (class);
-
mono_stats.initialized_class_count++;
if (class->generic_class && !class->generic_class->is_dynamic) {
/*class->enumtype = class->parent->enumtype; */
mono_class_setup_supertypes (class);
} else {
+ /* initialize com types if COM interfaces are present */
+ if (MONO_CLASS_IS_IMPORT (class))
+ mono_init_com_types ();
class->parent = NULL;
}
class->name = name;
class->name_space = nspace;
+ mono_profiler_class_event (class, MONO_PROFILE_START_LOAD);
+
class->image = image;
class->type_token = type_token;
class->flags = cols [MONO_TYPEDEF_FLAGS];
if (parent == NULL){
mono_internal_hash_table_remove (&image->class_cache, GUINT_TO_POINTER (type_token));
mono_loader_unlock ();
+ mono_profiler_class_loaded (class, MONO_PROFILE_FAILED);
return NULL;
}
}
if (!mono_metadata_interfaces_from_typedef_full (
image, type_token, &interfaces, &icount, context)){
mono_loader_unlock ();
+ mono_profiler_class_loaded (class, MONO_PROFILE_FAILED);
return NULL;
}
mono_loader_unlock ();
+ mono_profiler_class_loaded (class, MONO_PROFILE_OK);
+
return class;
}
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;
+ klass->field.count = gklass->field.count;
+ klass->property.count = gklass->property.count;
klass->generic_class = gclass;
klass->this_arg.type = klass->byval_arg.type = MONO_TYPE_GENERICINST;
klass->this_arg.data.generic_class = klass->byval_arg.data.generic_class = gclass;
klass->this_arg.byref = TRUE;
+ klass->enumtype = gklass->enumtype;
+ klass->valuetype = gklass->valuetype;
klass->cast_class = klass->element_class = klass;
if (mono_class_is_nullable (klass))
klass->cast_class = klass->element_class = mono_class_get_nullable_param (klass);
- if (gclass->is_dynamic) {
- klass->instance_size = gklass->instance_size;
- klass->sizes.class_size = gklass->sizes.class_size;
- klass->size_inited = 1;
- klass->inited = 1;
-
- klass->valuetype = gklass->valuetype;
-
- mono_class_setup_supertypes (klass);
- }
-
klass->interface_count = gklass->interface_count;
klass->interfaces = g_new0 (MonoClass *, klass->interface_count);
for (i = 0; i < klass->interface_count; i++) {
klass->cast_class = gklass->cast_class;
}
+ if (gclass->is_dynamic) {
+ klass->inited = 1;
+
+ mono_class_setup_supertypes (klass);
+
+ if (klass->enumtype) {
+ /*
+ * For enums, gklass->fields might not been set, but instance_size etc. is
+ * already set in mono_reflection_create_internal_class (). For non-enums,
+ * these will be computed normally in mono_class_layout_fields ().
+ */
+ klass->instance_size = gklass->instance_size;
+ klass->sizes.class_size = gklass->sizes.class_size;
+ klass->size_inited = 1;
+ }
+ }
+
if (MONO_CLASS_IS_INTERFACE (klass))
setup_interface_offsets (klass, 0);
+ mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
+
mono_loader_unlock ();
return klass;
klass = param->pklass = mono_mempool_alloc0 (image->mempool, sizeof (MonoClass));
+ if (param->name)
+ klass->name = param->name;
+ else {
+ klass->name = mono_mempool_alloc0 (image->mempool, 16);
+ sprintf ((char*)klass->name, is_mvar ? "!!%d" : "!%d", param->num);
+ }
+ klass->name_space = "";
+ mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
+
for (count = 0, ptr = param->constraints; ptr && *ptr; ptr++, count++)
;
klass->interfaces [i - pos] = param->constraints [i];
}
- if (param->name)
- klass->name = param->name;
- else {
- klass->name = mono_mempool_alloc0 (image->mempool, 16);
- sprintf ((char*)klass->name, is_mvar ? "!!%d" : "!%d", param->num);
- }
-
- klass->name_space = "";
-
if (!image)
image = mono_defaults.corlib;
mono_class_setup_supertypes (klass);
mono_loader_unlock ();
-
+
+ mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
+
return klass;
}
name = g_strdup_printf ("%s*", el_class->name);
result->name = mono_mempool_strdup (image->mempool, name);
g_free (name);
+
+ mono_profiler_class_event (result, MONO_PROFILE_START_LOAD);
+
result->image = el_class->image;
result->inited = TRUE;
result->flags = TYPE_ATTRIBUTE_CLASS | (el_class->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK);
mono_loader_unlock ();
+ mono_profiler_class_loaded (result, MONO_PROFILE_OK);
+
return result;
}
result->parent = NULL; /* no parent for PTR types */
result->name_space = "System";
result->name = "MonoFNPtrFakeClass";
+
+ mono_profiler_class_event (result, MONO_PROFILE_START_LOAD);
+
result->image = mono_defaults.corlib; /* need to fix... */
result->inited = TRUE;
result->flags = TYPE_ATTRIBUTE_CLASS; /* | (el_class->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK); */
mono_loader_unlock ();
+ mono_profiler_class_loaded (result, MONO_PROFILE_OK);
+
return result;
}
name [nsize + rank + 1] = 0;
class->name = mono_mempool_strdup (image->mempool, name);
g_free (name);
+
+ mono_profiler_class_event (class, MONO_PROFILE_START_LOAD);
+
class->type_token = 0;
/* all arrays are marked serializable and sealed, bug #42779 */
class->flags = TYPE_ATTRIBUTE_CLASS | TYPE_ATTRIBUTE_SERIALIZABLE | TYPE_ATTRIBUTE_SEALED |
mono_loader_unlock ();
+ mono_profiler_class_loaded (class, MONO_PROFILE_OK);
+
return class;
}
return 0;
}
+/*
+ * mono_class_get_field_default_value:
+ *
+ * Return the default value of the field as a pointer into the metadata blob.
+ */
+const char*
+mono_class_get_field_default_value (MonoClassField *field, MonoTypeEnum *def_type)
+{
+ guint32 cindex;
+ guint32 constant_cols [MONO_CONSTANT_SIZE];
+
+ g_assert (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT);
+
+ if (!field->data) {
+ cindex = mono_metadata_get_constant_index (field->parent->image, mono_class_get_field_token (field), cindex + 1);
+ g_assert (cindex);
+ g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA));
+
+ mono_metadata_decode_row (&field->parent->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
+ field->def_type = constant_cols [MONO_CONSTANT_TYPE];
+ field->data = (gpointer)mono_metadata_blob_heap (field->parent->image, constant_cols [MONO_CONSTANT_VALUE]);
+ }
+
+ *def_type = field->def_type;
+ return field->data;
+}
+
guint32
mono_class_get_event_token (MonoEvent *event)
{
{
MonoClass *class = NULL;
- if (image->dynamic)
+ if (image->dynamic) {
+ int table = mono_metadata_token_table (type_token);
+
+ if (table != MONO_TABLE_TYPEDEF && table != MONO_TABLE_TYPEREF && table != MONO_TABLE_TYPESPEC) {
+ mono_loader_set_error_bad_image (g_strdup ("Bad type token."));
+ return NULL;
+ }
return mono_lookup_dynamic_token (image, type_token, context);
+ }
switch (type_token & 0xff000000){
case MONO_TOKEN_TYPE_DEF:
/**
* 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.
*
GHashTable *nspace_table;
MonoImage *loaded_image;
guint32 token = 0;
+ int i;
MonoClass *class;
char *nested;
char buf [1024];
mono_loader_unlock ();
+ if (!token && image->dynamic && image->modules) {
+ /* Search modules as well */
+ for (i = 0; i < image->module_count; ++i) {
+ MonoImage *module = image->modules [i];
+
+ class = mono_class_from_name (module, name_space, name);
+ if (class)
+ return class;
+ }
+ }
+
if (!token)
return NULL;
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
{
if (image->dynamic) {
MonoClass *tmp_handle_class;
- gpointer obj = mono_lookup_dynamic_token_class (image, token, &tmp_handle_class, context);
+ gpointer obj = mono_lookup_dynamic_token_class (image, token, TRUE, &tmp_handle_class, context);
g_assert (tmp_handle_class);
if (handle_class)
{
MonoClass *handle_class;
- return lookup_dynamic (image, token, &handle_class, context);
+ return lookup_dynamic (image, token, TRUE, &handle_class, context);
}
gpointer
-mono_lookup_dynamic_token_class (MonoImage *image, guint32 token, MonoClass **handle_class, MonoGenericContext *context)
+mono_lookup_dynamic_token_class (MonoImage *image, guint32 token, gboolean valid_token, MonoClass **handle_class, MonoGenericContext *context)
{
- return lookup_dynamic (image, token, handle_class, context);
+ return lookup_dynamic (image, token, valid_token, handle_class, context);
}
static MonoGetCachedClassInfo get_cached_class_info = NULL;
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;
can_access_member (MonoClass *access_klass, MonoClass *member_klass, int access_level)
{
MonoClass *member_generic_def;
- if (access_klass->generic_class && access_klass->generic_class->container_class &&
+ if (((access_klass->generic_class && access_klass->generic_class->container_class) ||
+ access_klass->generic_container) &&
(member_generic_def = get_generic_definition_class (member_klass))) {
- if (can_access_member (access_klass->generic_class->container_class,
- member_generic_def, access_level))
+ MonoClass *access_container;
+
+ if (access_klass->generic_container)
+ access_container = access_klass;
+ else
+ access_container = access_klass->generic_class->container_class;
+
+ if (can_access_member (access_container, member_generic_def, access_level))
return TRUE;
}
{
return gklass->context.class_inst == gklass->container_class->generic_container->context.class_inst;
}
+
+/*
+ * mono_class_generic_sharing_enabled:
+ * @class: a class
+ *
+ * Returns whether generic sharing is enabled for class.
+ *
+ * This is a stop-gap measure to slowly introduce generic sharing
+ * until we have all the issues sorted out, at which time this
+ * function will disappear and generic sharing will always be enabled.
+ */
+gboolean
+mono_class_generic_sharing_enabled (MonoClass *class)
+{
+ static int generic_sharing = MONO_GENERIC_SHARING_CORLIB;
+ static gboolean inited = FALSE;
+
+ if (!inited) {
+ const char *option;
+
+ if ((option = g_getenv ("MONO_GENERIC_SHARING"))) {
+ if (strcmp (option, "corlib") == 0)
+ generic_sharing = MONO_GENERIC_SHARING_CORLIB;
+ else if (strcmp (option, "all") == 0)
+ generic_sharing = MONO_GENERIC_SHARING_ALL;
+ else if (strcmp (option, "none") == 0)
+ generic_sharing = MONO_GENERIC_SHARING_NONE;
+ else
+ g_warning ("Unknown generic sharing option `%s'.", option);
+ }
+
+ inited = TRUE;
+ }
+
+ switch (generic_sharing) {
+ case MONO_GENERIC_SHARING_NONE:
+ return FALSE;
+ case MONO_GENERIC_SHARING_ALL:
+ return TRUE;
+ case MONO_GENERIC_SHARING_CORLIB :
+ return class->image == mono_defaults.corlib;
+ default:
+ g_assert_not_reached ();
+ }
+}