#include <mono/metadata/debug-helpers.h>
#include <mono/os/gc_wrapper.h>
+/*
+ * Uncomment this to enable GC aware auto layout: in this mode, reference
+ * fields are grouped together inside objects, increasing collector
+ * performance.
+ * Requires that all classes whose layout is known to the runtime be annotated
+ * with [StructLayout (LayoutKind.Sequential)]
+ */
+//#define GC_AWARE_AUTO_LAYOUT
+
#define CSIZE(x) (sizeof (x) / 4)
MonoStats mono_stats;
static MonoClass * mono_class_create_from_typedef (MonoImage *image, guint32 type_token);
+void (*mono_debugger_class_init_func) (MonoClass *klass) = NULL;
+
MonoClass *
mono_class_from_typeref (MonoImage *image, guint32 type_token)
{
guint32 idx;
const char *name, *nspace;
MonoClass *res;
+ MonoAssembly **references;
+ MonoImageOpenStatus status;
mono_metadata_decode_row (t, (type_token&0xffffff)-1, cols, MONO_TYPEREF_SIZE);
/* a typedef in disguise */
return mono_class_from_name (image, nspace, name);
case RESOLTION_SCOPE_MODULEREF:
- return mono_class_from_name (image->assembly->modules [idx - 1], nspace, name);
+ return mono_class_from_name (image->modules [idx - 1], nspace, name);
case RESOLTION_SCOPE_TYPEREF: {
MonoClass *enclosing = mono_class_from_typeref (image, MONO_TOKEN_TYPE_REF | idx);
GList *tmp;
break;
}
- if (!image->references || !image->references [idx-1]) {
+ mono_image_load_references (image, &status);
+ references = image->references;
+ if (!references || !references [idx-1]) {
/*
* detected a reference to mscorlib, we simply return a reference to a dummy
* until we have a better solution.
}
/* load referenced assembly */
- image = image->references [idx-1]->image;
+ image = references [idx-1]->image;
return mono_class_from_name (image, nspace, name);
}
MonoMarshalType *
mono_marshal_load_type_info (MonoClass* klass)
{
- int i, j, count = 0;
+ int i, j, count = 0, native_size = 0;
MonoMarshalType *info;
guint32 layout;
klass->marshal_info = info = g_malloc0 (sizeof (MonoMarshalType) + sizeof (MonoMarshalField) * count);
info->num_fields = count;
- if (klass->parent)
- info->native_size = mono_class_native_size (klass->parent, NULL);
+ /* Try to find a size for this type in metadata */
+ mono_metadata_packing_from_typedef (klass->image, klass->type_token, NULL, &native_size);
+
+ if (klass->parent) {
+ int parent_size = mono_class_native_size (klass->parent, NULL);
+ /* Add parent size to real size */
+ native_size += parent_size;
+ info->native_size = parent_size;
+ }
+
for (j = i = 0; i < klass->field.count; ++i) {
int size, align;
j++;
}
+ if(layout != TYPE_ATTRIBUTE_AUTO_LAYOUT) {
+ info->native_size = MAX (native_size, info->native_size);
+ }
+
if (info->native_size & (klass->min_align - 1)) {
info->native_size += klass->min_align - 1;
info->native_size &= ~(klass->min_align - 1);
const int top = class->field.count;
guint32 layout = class->flags & TYPE_ATTRIBUTE_LAYOUT_MASK;
MonoTableInfo *t = &m->tables [MONO_TABLE_FIELD];
- int i, blittable = TRUE;
+ int i, blittable = TRUE, real_size = 0;
guint32 rva;
guint32 packing_size = 0;
if (!class->parent->size_inited)
class_compute_field_layout (class->parent);
class->instance_size += class->parent->instance_size;
- class->class_size += class->parent->class_size;
class->min_align = class->parent->min_align;
+ blittable = class->blittable;
} else {
class->instance_size = sizeof (MonoObject);
class->min_align = 1;
}
- if (mono_metadata_packing_from_typedef (class->image, class->type_token, &packing_size, &class->instance_size)) {
- class->instance_size += sizeof (MonoObject);
- }
+ /* Get the real size */
+ mono_metadata_packing_from_typedef (class->image, class->type_token, &packing_size, &real_size);
g_assert ((packing_size & 0xfffffff0) == 0);
class->packing_size = packing_size;
for (i = 0; i < top; i++){
const char *sig;
guint32 cols [MONO_FIELD_SIZE];
+ guint32 constant_cols [MONO_CONSTANT_SIZE];
+ guint32 cindex;
int idx = class->field.first + i;
mono_metadata_decode_row (t, idx, cols, CSIZE (cols));
class->fields [i].type = mono_metadata_parse_field_type (
m, cols [MONO_FIELD_FLAGS], sig + 1, &sig);
+ class->fields [i].parent = class;
+
if (!(class->fields [i].type->attrs & FIELD_ATTRIBUTE_STATIC)) {
if (class->fields [i].type->byref) {
blittable = FALSE;
} else {
MonoClass *field_class = mono_class_from_mono_type (class->fields [i].type);
- if (!field_class->blittable)
+ if (!field_class || !field_class->blittable)
blittable = FALSE;
}
}
+ if (layout == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
+ mono_metadata_field_info (m, idx, &class->fields [i].offset, NULL, NULL);
+ if (class->fields [i].offset == (guint32)-1)
+ g_warning ("%s not initialized correctly (missing field layout info for %s)", class->name, class->fields [i].name);
+ }
if (cols [MONO_FIELD_FLAGS] & FIELD_ATTRIBUTE_HAS_FIELD_RVA) {
mono_metadata_field_info (m, idx, NULL, &rva, NULL);
if (class->enumtype && !(cols [MONO_FIELD_FLAGS] & FIELD_ATTRIBUTE_STATIC)) {
class->enum_basetype = class->fields [i].type;
- class->element_class = mono_class_from_mono_type (class->enum_basetype);
+ class->cast_class = class->element_class = mono_class_from_mono_type (class->enum_basetype);
blittable = class->element_class->blittable;
}
+
+ if ((class->fields [i].type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT) &&
+ (class->fields [i].type->attrs & FIELD_ATTRIBUTE_STATIC)) {
+ cindex = mono_metadata_get_constant_index (class->image, MONO_TOKEN_FIELD_DEF | (class->field.first + i + 1));
+ if (!cindex) {
+ g_warning ("constant for field %s:%s not found", class->name, class->fields [i].name);
+ continue;
+ }
+ mono_metadata_decode_row (&class->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
+ class->fields [i].def_value = g_new0 (MonoConstant, 1);
+ class->fields [i].def_value->type = constant_cols [MONO_CONSTANT_TYPE];
+ class->fields [i].def_value->value = (gpointer)mono_metadata_blob_heap (class->image, constant_cols [MONO_CONSTANT_VALUE]);
+ }
}
if (class == mono_defaults.string_class)
if (!((strcmp (class->name, "Enum") == 0) && (strcmp (class->name_space, "System") == 0)))
G_BREAKPOINT ();
}
+ mono_class_layout_fields (class);
+
+ if(real_size) {
+ if(class->parent)
+ real_size += class->parent->instance_size;
+
+ class->instance_size = MAX(real_size, class->instance_size);
+ }
+}
+
+void
+mono_class_layout_fields (MonoClass *class)
+{
+ int i;
+ const int top = class->field.count;
+ guint32 layout = class->flags & TYPE_ATTRIBUTE_LAYOUT_MASK;
+ guint32 pass, passes;
+
/*
* Compute field layout and total size (not considering static fields)
*/
+
switch (layout) {
case TYPE_ATTRIBUTE_AUTO_LAYOUT:
case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT:
- for (i = 0; i < top; i++){
- int size, align;
-
- if (class->fields [i].type->attrs & FIELD_ATTRIBUTE_STATIC)
- continue;
- size = mono_type_size (class->fields [i].type, &align);
-
- /* FIXME (LAMESPEC): should we also change the min alignment according to pack? */
- align = class->packing_size ? MIN (class->packing_size, align): align;
- class->min_align = MAX (align, class->min_align);
- class->fields [i].offset = class->instance_size;
- class->fields [i].offset += align - 1;
- class->fields [i].offset &= ~(align - 1);
- class->instance_size = class->fields [i].offset + size;
+#ifdef GC_AWARE_AUTO_LAYOUT
+ passes = 2;
+#else
+ passes = 1;
+#endif
+ if (layout != TYPE_ATTRIBUTE_AUTO_LAYOUT)
+ passes = 1;
- }
+ for (pass = 0; pass < passes; ++pass) {
+ for (i = 0; i < top; i++){
+ int size, align;
+
+ if (class->fields [i].type->attrs & FIELD_ATTRIBUTE_STATIC)
+ continue;
+
+#ifdef GC_AWARE_AUTO_LAYOUT
+ /* FIXME: Fix mono_marshal_load_type_info () too */
+ if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT) {
+ /*
+ * We process fields with reference type in the first pass,
+ * and fields with non-reference type in the second pass.
+ */
+ if (MONO_TYPE_IS_REFERENCE (class->fields [i].type)) {
+ if (pass == 1)
+ continue;
+ } else {
+ if (pass == 0)
+ continue;
+ }
+ }
+#endif
+
+ size = mono_type_size (class->fields [i].type, &align);
+
+ /* FIXME (LAMESPEC): should we also change the min alignment according to pack? */
+ align = class->packing_size ? MIN (class->packing_size, align): align;
+ class->min_align = MAX (align, class->min_align);
+ class->fields [i].offset = class->instance_size;
+ class->fields [i].offset += align - 1;
+ class->fields [i].offset &= ~(align - 1);
+ class->instance_size = class->fields [i].offset + size;
+ }
- if (class->instance_size & (class->min_align - 1)) {
- class->instance_size += class->min_align - 1;
- class->instance_size &= ~(class->min_align - 1);
+ if (class->instance_size & (class->min_align - 1)) {
+ class->instance_size += class->min_align - 1;
+ class->instance_size &= ~(class->min_align - 1);
+ }
}
break;
case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT:
for (i = 0; i < top; i++) {
int size, align;
- int idx = class->field.first + i;
/*
* There must be info about all the fields in a type if it
size = mono_type_size (class->fields [i].type, &align);
- mono_metadata_field_info (m, idx, &class->fields [i].offset, NULL, NULL);
- if (class->fields [i].offset == (guint32)-1)
- g_warning ("%s not initialized correctly (missing field layout info for %s)", class->name, class->fields [i].name);
/*
+ * When we get here, class->fields [i].offset is already set by the
+ * loader (for either runtime fields or fields loaded from metadata).
* The offset is from the start of the object: this works for both
* classes and valuetypes.
*/
class->fields [i].offset += sizeof (MonoObject);
+
/*
* Calc max size.
*/
class->fields [i].offset += align - 1;
class->fields [i].offset &= ~(align - 1);
class->class_size = class->fields [i].offset + size;
+
}
break;
case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT:
* There must be info about all the fields in a type if it
* uses explicit layout.
*/
-
if (!(class->fields [i].type->attrs & FIELD_ATTRIBUTE_STATIC))
continue;
return iid - 1;
}
-void
-mono_class_setup_vtable (MonoClass *class)
+static void
+collect_implemented_interfaces_aux (MonoClass *klass, GPtrArray *res)
{
- MonoClass *k, *ic;
- MonoMethod **vtable;
- int i, onum = 0, max_vtsize = 0, max_iid, cur_slot = 0;
- MonoMethod **overrides;
-
- for (i = 0; i < class->interface_count; i++)
- max_vtsize += class->interfaces [i]->method.count;
+ int i;
+ MonoClass *ic;
- if (class->parent) {
- max_vtsize += class->parent->vtable_size;
- cur_slot = class->parent->vtable_size;
+ for (i = 0; i < klass->interface_count; i++) {
+ ic = klass->interfaces [i];
+
+ g_ptr_array_add (res, ic);
+
+ collect_implemented_interfaces_aux (ic, res);
}
+}
- max_vtsize += class->method.count;
+static GPtrArray*
+collect_implemented_interfaces (MonoClass *klass)
+{
+ GPtrArray *res = g_ptr_array_new ();
- vtable = alloca (sizeof (gpointer) * max_vtsize);
- memset (vtable, 0, sizeof (gpointer) * max_vtsize);
+ collect_implemented_interfaces_aux (klass, res);
+ return res;
+}
- /* printf ("METAINIT %s.%s\n", class->name_space, class->name); */
+static int
+setup_interface_offsets (MonoClass *class, int cur_slot)
+{
+ MonoClass *k, *ic;
+ int i, max_iid;
+ GPtrArray *ifaces;
/* compute maximum number of slots and maximum interface id */
max_iid = 0;
max_iid = ic->interface_id;
}
}
-
+
+ if (class->flags & TYPE_ATTRIBUTE_INTERFACE) {
+ if (max_iid < class->interface_id)
+ max_iid = class->interface_id;
+ }
class->max_interface_id = max_iid;
/* compute vtable offset for interfaces */
class->interface_offsets = g_malloc (sizeof (gpointer) * (max_iid + 1));
for (i = 0; i <= max_iid; i++)
class->interface_offsets [i] = -1;
- for (i = 0; i < class->interface_count; i++) {
- ic = class->interfaces [i];
+ ifaces = collect_implemented_interfaces (class);
+ for (i = 0; i < ifaces->len; ++i) {
+ ic = g_ptr_array_index (ifaces, i);
class->interface_offsets [ic->interface_id] = cur_slot;
cur_slot += ic->method.count;
}
+ g_ptr_array_free (ifaces, TRUE);
for (k = class->parent; k ; k = k->parent) {
- for (i = 0; i < k->interface_count; i++) {
- ic = k->interfaces [i];
+ ifaces = collect_implemented_interfaces (k);
+ for (i = 0; i < ifaces->len; ++i) {
+ ic = g_ptr_array_index (ifaces, i);
+
if (class->interface_offsets [ic->interface_id] == -1) {
int io = k->interface_offsets [ic->interface_id];
g_assert (io >= 0);
- g_assert (io <= max_vtsize);
class->interface_offsets [ic->interface_id] = io;
}
}
+ g_ptr_array_free (ifaces, TRUE);
+ }
+ return cur_slot;
+}
+
+void
+mono_class_setup_vtable (MonoClass *class, MonoMethod **overrides, int onum)
+{
+ MonoClass *k, *ic;
+ MonoMethod **vtable;
+ int i, max_vtsize = 0, max_iid, cur_slot = 0;
+ GPtrArray *ifaces;
+ MonoGHashTable *override_map;
+
+ /* setup_vtable() must be called only once on the type */
+ if (class->interface_offsets) {
+ g_warning ("vtable already computed in %s.%s", class->name_space, class->name);
+ return;
+ }
+
+ ifaces = collect_implemented_interfaces (class);
+ for (i = 0; i < ifaces->len; i++) {
+ MonoClass *ic = g_ptr_array_index (ifaces, i);
+ max_vtsize += ic->method.count;
+ }
+ g_ptr_array_free (ifaces, TRUE);
+
+ if (class->parent) {
+ max_vtsize += class->parent->vtable_size;
+ cur_slot = class->parent->vtable_size;
}
+ max_vtsize += class->method.count;
+
+ vtable = alloca (sizeof (gpointer) * max_vtsize);
+ memset (vtable, 0, sizeof (gpointer) * max_vtsize);
+
+ /* printf ("METAINIT %s.%s\n", class->name_space, class->name); */
+
+ cur_slot = setup_interface_offsets (class, cur_slot);
+ max_iid = class->max_interface_id;
+
if (class->parent && class->parent->vtable_size)
memcpy (vtable, class->parent->vtable, sizeof (gpointer) * class->parent->vtable_size);
- overrides = mono_class_get_overrides (class->image, class->type_token, &onum);
+ override_map = mono_g_hash_table_new (NULL, NULL);
/* override interface methods */
for (i = 0; i < onum; i++) {
g_assert (decl->slot != -1);
dslot = decl->slot + class->interface_offsets [decl->klass->interface_id];
vtable [dslot] = overrides [i*2 + 1];
+ vtable [dslot]->slot = dslot;
+ mono_g_hash_table_insert (override_map, overrides [i * 2], overrides [i * 2 + 1]);
}
}
for (k = class; k ; k = k->parent) {
- for (i = 0; i < k->interface_count; i++) {
+ ifaces = collect_implemented_interfaces (k);
+ for (i = 0; i < ifaces->len; i++) {
int j, l, io;
- ic = k->interfaces [i];
+ ic = g_ptr_array_index (ifaces, i);
io = k->interface_offsets [ic->interface_id];
-
+
g_assert (io >= 0);
g_assert (io <= max_vtsize);
if (k == class) {
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_PUBLIC) ||
+ !((cm->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) == METHOD_ATTRIBUTE_PUBLIC) ||
!(cm->flags & METHOD_ATTRIBUTE_NEW_SLOT))
continue;
if (!strcmp(cm->name, im->name) &&
g_assert (io + l <= max_vtsize);
- if (vtable [io + l])
+ if (vtable [io + l] && !(vtable [io + l]->flags & METHOD_ATTRIBUTE_ABSTRACT))
continue;
for (k1 = class; k1; k1 = k1->parent) {
}
g_assert (io + l <= max_vtsize);
- if (vtable [io + l])
+ if (vtable [io + l] && !(vtable [io + l]->flags & METHOD_ATTRIBUTE_ABSTRACT))
break;
}
}
for (l = 0; l < ic->method.count; l++) {
MonoMethod *im = ic->methods [l];
char *qname, *fqname;
+ MonoClass *k1;
+ if (vtable [io + l])
+ continue;
+
qname = g_strconcat (ic->name, ".", im->name, NULL);
if (ic->name_space && ic->name_space [0])
fqname = g_strconcat (ic->name_space, ".", ic->name, ".", im->name, NULL);
else
fqname = NULL;
- for (j = 0; j < class->method.count; ++j) {
- MonoMethod *cm = class->methods [j];
+ 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 (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL))
+ continue;
- if (((fqname && !strcmp (cm->name, fqname)) || !strcmp (cm->name, qname)) &&
- mono_metadata_signature_equal (cm->signature, im->signature)) {
- g_assert (io + l <= max_vtsize);
- vtable [io + l] = cm;
- break;
+ if (((fqname && !strcmp (cm->name, fqname)) || !strcmp (cm->name, qname)) &&
+ mono_metadata_signature_equal (cm->signature, im->signature)) {
+ g_assert (io + l <= max_vtsize);
+ vtable [io + l] = cm;
+ break;
+ }
}
}
g_free (qname);
if (!(class->flags & TYPE_ATTRIBUTE_ABSTRACT)) {
for (l = 0; l < ic->method.count; l++) {
char *msig;
- MonoMethod *im = ic->methods [l];
+ MonoMethod *im = ic->methods [l];
+ if (im->flags & METHOD_ATTRIBUTE_STATIC)
+ continue;
g_assert (io + l <= max_vtsize);
if (!(vtable [io + l])) {
for (j = 0; j < onum; ++j) {
}
}
}
+ g_ptr_array_free (ifaces, TRUE);
}
for (i = 0; i < class->method.count; ++i) {
cm = class->methods [i];
-
-#if 0
- if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
- (cm->slot >= 0))
- continue;
-#else /* EXT_VTABLE_HACK */
- if (cm->slot >= 0)
- continue;
-#endif
-
if (!(cm->flags & METHOD_ATTRIBUTE_NEW_SLOT) && (cm->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
+ int slot = -1;
for (k = class->parent; k ; k = k->parent) {
int j;
for (j = 0; j < k->method.count; ++j) {
continue;
if (!strcmp(cm->name, m1->name) &&
mono_metadata_signature_equal (cm->signature, m1->signature)) {
- cm->slot = k->methods [j]->slot;
+ slot = k->methods [j]->slot;
g_assert (cm->slot < max_vtsize);
+ mono_g_hash_table_insert (override_map, m1, cm);
break;
}
}
- if (cm->slot >= 0)
+ if (slot >= 0)
break;
}
+ if (slot >= 0)
+ cm->slot = slot;
}
if (cm->slot < 0)
if (!(decl->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
g_assert (decl->slot != -1);
vtable [decl->slot] = overrides [i*2 + 1];
+ overrides [i * 2 + 1]->slot = decl->slot;
+ mono_g_hash_table_insert (override_map, decl, overrides [i * 2 + 1]);
}
}
-
- g_free (overrides);
+ /*
+ * If a method occupies more than one place in the vtable, and it is
+ * overriden, then change the other occurances too.
+ */
+ for (i = 0; i < max_vtsize; ++i)
+ if (vtable [i]) {
+ MonoMethod *cm = mono_g_hash_table_lookup (override_map, vtable [i]);
+ if (cm)
+ vtable [i] = cm;
+ }
+ mono_g_hash_table_destroy (override_map);
+
+
class->vtable_size = cur_slot;
class->vtable = g_malloc0 (sizeof (gpointer) * class->vtable_size);
memcpy (class->vtable, vtable, sizeof (gpointer) * class->vtable_size);
}
}
}
-
}
/**
static MonoMethod *default_finalize = NULL;
static int finalize_slot = -1;
static int ghc_slot = -1;
+ MonoMethod **overrides;
+ int onum = 0;
g_assert (class);
init_properties (class);
init_events (class);
- i = mono_metadata_nesting_typedef (class->image, class->type_token);
+ i = mono_metadata_nesting_typedef (class->image, class->type_token, 1);
while (i) {
MonoClass* nclass;
guint32 cols [MONO_NESTED_CLASS_SIZE];
mono_metadata_decode_row (&class->image->tables [MONO_TABLE_NESTEDCLASS], i - 1, cols, MONO_NESTED_CLASS_SIZE);
- if (cols [MONO_NESTED_CLASS_ENCLOSING] != mono_metadata_token_index (class->type_token))
- break;
nclass = mono_class_create_from_typedef (class->image, MONO_TOKEN_TYPE_DEF | cols [MONO_NESTED_CLASS_NESTED]);
class->nested_classes = g_list_prepend (class->nested_classes, nclass);
- ++i;
+
+ i = mono_metadata_nesting_typedef (class->image, class->type_token, i + 1);
}
+ mono_class_setup_supertypes (class);
+
if (class->flags & TYPE_ATTRIBUTE_INTERFACE) {
for (i = 0; i < class->method.count; ++i)
class->methods [i]->slot = i;
class->init_pending = 0;
class->inited = 1;
+ /*
+ * class->interface_offsets is needed for the castclass/isinst code, so
+ * we have to setup them for interfaces, too.
+ */
+ setup_interface_offsets (class, 0);
return;
}
- mono_class_setup_vtable (class);
+ overrides = mono_class_get_overrides (class->image, class->type_token, &onum);
+ mono_class_setup_vtable (class, overrides, onum);
+ g_free (overrides);
class->inited = 1;
class->init_pending = 0;
}
class->ghcimpl = 1;
- if (class != mono_defaults.object_class) {
+ if (class->parent) {
if (class->vtable [ghc_slot] == default_ghc) {
class->ghcimpl = 0;
/* Object::Finalize should have empty implemenatation */
class->has_finalize = 0;
- if (class != mono_defaults.object_class) {
+ if (class->parent) {
if (class->vtable [finalize_slot] != default_finalize)
class->has_finalize = 1;
}
+
+ if (mono_debugger_class_init_func)
+ mono_debugger_class_init_func (class);
}
const char *name = class->name;
const char *nspace = class->name_space;
+ if (class->flags & TYPE_ATTRIBUTE_INTERFACE)
+ class->interface_id = mono_get_unique_iid (class);
+
class->this_arg.byref = 1;
class->this_arg.data.klass = class;
class->this_arg.type = MONO_TYPE_CLASS;
class->this_arg.type = class->byval_arg.type = MONO_TYPE_OBJECT;
} else if (!strcmp (name, "String")) {
class->this_arg.type = class->byval_arg.type = MONO_TYPE_STRING;
+ } else if (!strcmp (name, "TypedReference")) {
+ class->this_arg.type = class->byval_arg.type = MONO_TYPE_TYPEDBYREF;
}
}
/*class->enumtype = class->parent->enumtype; */
class->parent->subclasses = g_list_prepend (class->parent->subclasses, class);
mono_compute_relative_numbering (mono_defaults.object_class, &rnum);
+ mono_class_setup_supertypes (class);
} else {
class->parent = NULL;
}
}
+void
+mono_class_setup_supertypes (MonoClass *class)
+{
+ MonoClass *k;
+ int ms, i;
+
+ if (class->supertypes)
+ return;
+
+ class->idepth = 0;
+ for (k = class; k ; k = k->parent) {
+ class->idepth++;
+ }
+
+ ms = MAX (MONO_DEFAULT_SUPERTABLE_SIZE, class->idepth);
+ class->supertypes = g_new0 (MonoClass *, ms);
+
+ if (class->parent) {
+ for (i = class->idepth, k = class; k ; k = k->parent)
+ class->supertypes [--i] = k;
+ } else {
+ class->supertypes [0] = class;
+ }
+}
+
/**
* @image: context where the image is created
* @type_token: typedef token
class->unicode = 1;
*/
- class->element_class = class;
+ class->cast_class = class->element_class = class;
/*g_print ("Init class %s\n", name);*/
g_assert (class->field.count == 0);
}
- if (class->flags & TYPE_ATTRIBUTE_INTERFACE)
- class->interface_id = mono_get_unique_iid (class);
-
- /*class->interfaces = mono_metadata_interfaces_from_typedef (image, type_token, &class->interface_count); */
-
if (class->enumtype)
class_compute_field_layout (class);
result->name_space = "MonoPtrFakeClass";
result->image = el_class->image;
result->inited = TRUE;
+ result->flags = TYPE_ATTRIBUTE_CLASS | (el_class->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK);
/* Can pointers get boxed? */
result->instance_size = sizeof (gpointer);
/*
* baseval, diffval: need them to allow casting ?
*/
- result->element_class = el_class;
+ result->cast_class = result->element_class = el_class;
result->enum_basetype = &result->element_class->byval_arg;
result->this_arg.type = result->byval_arg.type = MONO_TYPE_PTR;
return result;
}
+static MonoClass *
+mono_fnptr_class_get (MonoMethodSignature *sig)
+{
+ MonoClass *result;
+ static GHashTable *ptr_hash = NULL;
+
+ if (!ptr_hash)
+ ptr_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+ if ((result = g_hash_table_lookup (ptr_hash, sig)))
+ return result;
+ result = g_new0 (MonoClass, 1);
+
+ result->parent = NULL; /* no parent for PTR types */
+ result->name = "System";
+ result->name_space = "MonoFNPtrFakeClass";
+ result->image = NULL; /* need to fix... */
+ result->inited = TRUE;
+ result->flags = TYPE_ATTRIBUTE_CLASS; // | (el_class->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK);
+ /* Can pointers get boxed? */
+ result->instance_size = sizeof (gpointer);
+ /*
+ * baseval, diffval: need them to allow casting ?
+ */
+ result->cast_class = result->element_class = result;
+
+ result->this_arg.type = result->byval_arg.type = MONO_TYPE_FNPTR;
+ result->this_arg.data.method = result->byval_arg.data.method = sig;
+ result->this_arg.byref = TRUE;
+ result->enum_basetype = &result->element_class->byval_arg;
+
+ g_hash_table_insert (ptr_hash, sig, result);
+
+ return result;
+}
+
MonoClass *
mono_class_from_mono_type (MonoType *type)
{
return mono_defaults.double_class;
case MONO_TYPE_STRING:
return mono_defaults.string_class;
+ case MONO_TYPE_TYPEDBYREF:
+ return mono_defaults.typed_reference_class;
case MONO_TYPE_ARRAY:
return mono_array_class_get (type->data.array->type, type->data.array->rank);
case MONO_TYPE_PTR:
return mono_ptr_class_get (type->data.type);
+ case MONO_TYPE_FNPTR:
+ return mono_fnptr_class_get (type->data.method);
case MONO_TYPE_SZARRAY:
return mono_array_class_get (type->data.type, 1);
case MONO_TYPE_CLASS:
case MONO_TYPE_VALUETYPE:
return type->data.klass;
+
+ case MONO_TYPE_GENERICINST:
+ g_warning ("mono_class_from_type: implement me MONO_TYPE_GENERICINST");
+ g_assert_not_reached ();
+
+ case MONO_TYPE_VAR:
+ g_warning ("mono_class_from_type: implement me MONO_TYPE_VAR");
+ g_assert_not_reached ();
+
+ case MONO_TYPE_MVAR:
+ g_warning ("mono_class_from_type: implement me MONO_TYPE_MVAR");
+ g_assert_not_reached ();
+
default:
- g_warning ("implement me %02x\n", type->type);
+ g_warning ("implement me 0x%02x\n", type->type);
g_assert_not_reached ();
}
MonoClass *parent = NULL;
GSList *list;
int rnum = 0, nsize;
+ char *name;
eclass = mono_class_from_mono_type (element_type);
g_assert (rank <= 255);
class->image = image;
class->name_space = eclass->name_space;
nsize = strlen (eclass->name);
- class->name = g_malloc (nsize + 2 + rank);
- memcpy (class->name, eclass->name, nsize);
- class->name [nsize] = '[';
+ name = g_malloc (nsize + 2 + rank);
+ memcpy (name, eclass->name, nsize);
+ name [nsize] = '[';
if (rank > 1)
- memset (class->name + nsize + 1, ',', rank - 1);
- class->name [nsize + rank] = ']';
- class->name [nsize + rank + 1] = 0;
+ memset (name + nsize + 1, ',', rank - 1);
+ name [nsize + rank] = ']';
+ name [nsize + rank + 1] = 0;
+ class->name = name;
class->type_token = 0;
- class->flags = TYPE_ATTRIBUTE_CLASS;
+ /* all arrays are marked serializable and sealed, bug #42779 */
+ class->flags = TYPE_ATTRIBUTE_CLASS | TYPE_ATTRIBUTE_SERIALIZABLE | TYPE_ATTRIBUTE_SEALED |
+ (eclass->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK);
class->parent = parent;
class->instance_size = mono_class_instance_size (class->parent);
class->class_size = 0;
class->vtable_size = parent->vtable_size;
class->parent->subclasses = g_list_prepend (class->parent->subclasses, class);
mono_compute_relative_numbering (mono_defaults.object_class, &rnum);
+ mono_class_setup_supertypes (class);
class->rank = rank;
+
+ if (eclass->enumtype)
+ class->cast_class = eclass->element_class;
+ else
+ class->cast_class = eclass;
+
class->element_class = eclass;
+
if (rank > 1) {
MonoArrayType *at = g_new0 (MonoArrayType, 1);
class->byval_arg.type = MONO_TYPE_ARRAY;
{
MonoClass *class;
+ if (image->assembly->dynamic)
+ return mono_lookup_dynamic_token (image, type_token);
+
switch (type_token & 0xff000000){
case MONO_TOKEN_TYPE_DEF:
class = mono_class_create_from_typedef (image, type_token);
return NULL;
}
+static MonoImage*
+load_file_for_image (MonoImage *image, int fileidx)
+{
+ char *base_dir, *name;
+ MonoImage *res;
+ MonoTableInfo *t = &image->tables [MONO_TABLE_FILE];
+ const char *fname;
+ guint32 fname_id;
+
+ if (fileidx < 1 || fileidx > t->rows)
+ return NULL;
+ fname_id = mono_metadata_decode_row_col (t, fileidx - 1, MONO_FILE_NAME);
+ fname = mono_metadata_string_heap (image, fname_id);
+ base_dir = g_path_get_dirname (image->name);
+ name = g_build_filename (base_dir, fname, NULL);
+ res = mono_image_open (name, NULL);
+ if (res) {
+ int i;
+ t = &res->tables [MONO_TABLE_MODULEREF];
+ //g_print ("loaded file %s from %s (%p)\n", name, image->name, image->assembly);
+ res->assembly = image->assembly;
+ for (i = 0; i < t->rows; ++i) {
+ if (res->modules [i] && !res->modules [i]->assembly)
+ res->modules [i]->assembly = image->assembly;
+ }
+ mono_image_load_references (image, NULL);
+ }
+ g_free (name);
+ g_free (base_dir);
+ return res;
+}
+
+static MonoClass*
+return_nested_in (MonoClass *class, char *nested) {
+ MonoClass *found;
+ char *s = strchr (nested, '/');
+ GList *tmp;
+
+ if (s) {
+ *s = 0;
+ s++;
+ }
+ for (tmp = class->nested_classes; tmp; tmp = tmp->next) {
+ found = tmp->data;
+ if (strcmp (found->name, nested) == 0) {
+ if (s)
+ return return_nested_in (found, s);
+ return found;
+ }
+ }
+ return NULL;
+}
+
MonoClass *
mono_class_from_name (MonoImage *image, const char* name_space, const char *name)
{
GHashTable *nspace_table;
+ MonoImage *loaded_image;
guint32 token;
+ MonoClass *class;
+ char *nested;
+ char buf [1024];
+
+ if ((nested = strchr (name, '/'))) {
+ int pos = nested - name;
+ int len = strlen (name);
+ if (len > 1023)
+ return NULL;
+ memcpy (buf, name, len + 1);
+ buf [pos] = 0;
+ nested = buf + pos + 1;
+ name = buf;
+ }
nspace_table = g_hash_table_lookup (image->name_cache, name_space);
- if (!nspace_table)
- return 0;
- token = GPOINTER_TO_UINT (g_hash_table_lookup (nspace_table, name));
- if (!token) {
+ if (!nspace_table || !(token = GPOINTER_TO_UINT (g_hash_table_lookup (nspace_table, name)))) {
+ MonoTableInfo *t = &image->tables [MONO_TABLE_EXPORTEDTYPE];
+ guint32 cols [MONO_EXP_TYPE_SIZE];
+ int i;
+
+ for (i = 0; i < t->rows; ++i) {
+ const char *ename, *enspace;
+ mono_metadata_decode_row (t, i, cols, MONO_EXP_TYPE_SIZE);
+ ename = mono_metadata_string_heap (image, cols [MONO_EXP_TYPE_NAME]);
+ enspace = mono_metadata_string_heap (image, cols [MONO_EXP_TYPE_NAMESPACE]);
+
+ if (strcmp (name, ename) == 0 && strcmp (name_space, enspace) == 0) {
+ guint32 impl = cols [MONO_EXP_TYPE_IMPLEMENTATION];
+ if ((impl & IMPLEMENTATION_MASK) == IMPLEMENTATION_FILE) {
+ loaded_image = load_file_for_image (image, impl >> IMPLEMENTATION_BITS);
+ if (!loaded_image)
+ return NULL;
+ class = mono_class_from_name (loaded_image, name_space, name);
+ if (nested)
+ return return_nested_in (class, nested);
+ return class;
+ } else {
+ g_error ("not yet implemented");
+ }
+ }
+ }
/*g_warning ("token not found for %s.%s in image %s", name_space, name, image->name);*/
return NULL;
}
token = MONO_TOKEN_TYPE_DEF | token;
- return mono_class_get (image, token);
+ class = mono_class_get (image, token);
+ if (nested)
+ return return_nested_in (class, nested);
+ return class;
+}
+
+gboolean
+mono_class_is_subclass_of (MonoClass *klass, MonoClass *klassc,
+ gboolean check_interfaces)
+{
+ if (check_interfaces && (klassc->flags & TYPE_ATTRIBUTE_INTERFACE) && !(klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
+ if ((klassc->interface_id <= klass->max_interface_id) &&
+ (klass->interface_offsets [klassc->interface_id] >= 0))
+ return TRUE;
+ } else if (check_interfaces && (klassc->flags & TYPE_ATTRIBUTE_INTERFACE) && (klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
+ int i;
+
+ for (i = 0; i < klass->interface_count; i ++) {
+ MonoClass *ic = klass->interfaces [i];
+ if (ic == klassc)
+ return TRUE;
+ }
+ } else {
+ /*
+ * klass->baseval is 0 for interfaces
+ */
+ if (klass->baseval && ((klass->baseval - klassc->baseval) <= klassc->diffval))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*
+ * Returns the nnumber of bytes an element of type klass
+ * uses when stored into an array.
+ */
+gint32
+mono_class_array_element_size (MonoClass *klass)
+{
+ int t = klass->byval_arg.type;
+
+handle_enum:
+ switch (t) {
+ case MONO_TYPE_I1:
+ case MONO_TYPE_U1:
+ case MONO_TYPE_BOOLEAN:
+ return 1;
+ case MONO_TYPE_I2:
+ case MONO_TYPE_U2:
+ case MONO_TYPE_CHAR:
+ return 2;
+ case MONO_TYPE_I4:
+ case MONO_TYPE_U4:
+ case MONO_TYPE_R4:
+ return 4;
+ case MONO_TYPE_I:
+ case MONO_TYPE_U:
+ case MONO_TYPE_PTR:
+ case MONO_TYPE_CLASS:
+ case MONO_TYPE_STRING:
+ case MONO_TYPE_OBJECT:
+ case MONO_TYPE_SZARRAY:
+ case MONO_TYPE_ARRAY:
+ return sizeof (gpointer);
+ case MONO_TYPE_I8:
+ case MONO_TYPE_U8:
+ case MONO_TYPE_R8:
+ return 8;
+ case MONO_TYPE_VALUETYPE:
+ if (klass->enumtype) {
+ t = klass->enum_basetype->type;
+ goto handle_enum;
+ }
+ return mono_class_instance_size (klass) - sizeof (MonoObject);
+ default:
+ g_error ("unknown type 0x%02x in mono_class_array_element_size", t);
+ }
+ return -1;
}
/**
gint32
mono_array_element_size (MonoClass *ac)
{
- if (ac->element_class->valuetype)
- return mono_class_instance_size (ac->element_class) - sizeof (MonoObject);
- else
- return sizeof (gpointer);
+ return mono_class_array_element_size (ac->element_class);
}
gpointer
mono_ldtoken (MonoImage *image, guint32 token, MonoClass **handle_class)
{
+ if (image->assembly->dynamic) {
+ gpointer obj = mono_lookup_dynamic_token (image, token);
+
+ switch (token & 0xff000000) {
+ case MONO_TOKEN_TYPE_DEF:
+ case MONO_TOKEN_TYPE_REF:
+ case MONO_TOKEN_TYPE_SPEC:
+ if (handle_class)
+ *handle_class = mono_defaults.typehandle_class;
+ return &((MonoClass*)obj)->byval_arg;
+ case MONO_TOKEN_METHOD_DEF:
+ if (handle_class)
+ *handle_class = mono_defaults.methodhandle_class;
+ return obj;
+ case MONO_TOKEN_FIELD_DEF:
+ if (handle_class)
+ *handle_class = mono_defaults.fieldhandle_class;
+ return obj;
+ default:
+ g_assert_not_reached ();
+ }
+ }
+
switch (token & 0xff000000) {
case MONO_TOKEN_TYPE_DEF:
case MONO_TOKEN_TYPE_REF: {
class = mono_class_get (image, MONO_TOKEN_TYPE_DEF | type);
mono_class_init (class);
if (handle_class)
- *handle_class = mono_class_from_name (mono_defaults.corlib, "System", "RuntimeFieldHandle");
+ *handle_class = mono_defaults.fieldhandle_class;
return mono_class_get_field (class, token);
}
case MONO_TOKEN_METHOD_DEF:
return NULL;
}
+/**
+ * This function might need to call runtime functions so it can't be part
+ * of the metadata library.
+ */
+static MonoLookupDynamicToken lookup_dynamic = NULL;
+
+void
+mono_install_lookup_dynamic_token (MonoLookupDynamicToken func)
+{
+ lookup_dynamic = func;
+}
+
+gpointer
+mono_lookup_dynamic_token (MonoImage *image, guint32 token)
+{
+ return lookup_dynamic (image, token);
+}