#include <stdio.h>
#include <signal.h>
#include <string.h>
+#include <mono/metadata/mono-endian.h>
#include <mono/metadata/tabledefs.h>
+#include <mono/metadata/tokentype.h>
#include <mono/metadata/loader.h>
#include <mono/metadata/object.h>
+#include <mono/metadata/gc.h>
#include <mono/metadata/appdomain.h>
#if HAVE_BOEHM_GC
#include <gc/gc.h>
MonoStats mono_stats;
+/* next object id for object hashcode */
+static guint32 uoid = 0;
+
void
mono_runtime_object_init (MonoObject *this)
{
/* No class constructor found */
}
+static gpointer
+default_trampoline (MonoMethod *method)
+{
+ return method;
+}
+
+static gpointer
+default_remoting_trampoline (MonoMethod *method)
+{
+ g_error ("remoting not installed");
+ return NULL;
+}
+
+static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
+static MonoTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
+
+void
+mono_install_trampoline (MonoTrampoline func)
+{
+ arch_create_jit_trampoline = func? func: default_trampoline;
+}
+
+void
+mono_install_remoting_trampoline (MonoTrampoline func)
+{
+ arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
+}
+
+#if 0 && HAVE_BOEHM_GC
+static void
+vtable_finalizer (void *obj, void *data) {
+ g_print ("%s finalized (%p)\n", (char*)data, obj);
+}
+#endif
+
+/**
+ * mono_class_vtable:
+ * @domain: the application domain
+ * @class: the class to initialize
+ *
+ * VTables are domain specific because we create domain specific code, and
+ * they contain the domain specific static class data.
+ */
+MonoVTable *
+mono_class_vtable (MonoDomain *domain, MonoClass *class)
+{
+ MonoClass *k;
+ MonoVTable *vt;
+ MonoClassField *field;
+ guint32 cindex;
+ guint32 cols [MONO_CONSTANT_SIZE];
+ const char *p;
+ char *t;
+ int i, len;
+
+ g_assert (class);
+
+ /* can interfaces have static fields? */
+ if (class->flags & TYPE_ATTRIBUTE_INTERFACE)
+ g_assert_not_reached ();
+
+ mono_domain_lock (domain);
+ if ((vt = mono_g_hash_table_lookup (domain->class_vtable_hash, class))) {
+ mono_domain_unlock (domain);
+ return vt;
+ }
+
+ if (!class->inited)
+ mono_class_init (class);
+
+// mono_stats.used_class_count++;
+// mono_stats.class_vtable_size += sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
+
+ vt = mono_mempool_alloc0 (domain->mp, sizeof (MonoVTable) +
+ class->vtable_size * sizeof (gpointer));
+ vt->klass = class;
+ vt->domain = domain;
+
+ if (class->class_size) {
+#if HAVE_BOEHM_GC
+ vt->data = GC_malloc (class->class_size + 8);
+ /*vt->data = GC_debug_malloc (class->class_size + 8, class->name, 2);*/
+ /*GC_register_finalizer (vt->data, vtable_finalizer, class->name, NULL, NULL);*/
+ mono_g_hash_table_insert (domain->static_data_hash, class, vt->data);
+#else
+ vt->data = mono_mempool_alloc0 (domain->mp, class->class_size + 8);
+
+#endif
+// mono_stats.class_static_data_size += class->class_size + 8;
+ }
+
+ for (i = class->field.first; i < class->field.last; ++i) {
+ field = &class->fields [i - class->field.first];
+ if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
+ continue;
+ if (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT))
+ continue;
+ cindex = mono_metadata_get_constant_index (class->image, MONO_TOKEN_FIELD_DEF | (i + 1));
+ if (!cindex) {
+ g_warning ("constant for field %s not found", field->name);
+ continue;
+ }
+ mono_metadata_decode_row (&class->image->tables [MONO_TABLE_CONSTANT], cindex - 1, cols, MONO_CONSTANT_SIZE);
+ p = mono_metadata_blob_heap (class->image, cols [MONO_CONSTANT_VALUE]);
+ len = mono_metadata_decode_blob_size (p, &p);
+ t = (char*)vt->data + field->offset;
+ /* should we check that the type matches? */
+ switch (cols [MONO_CONSTANT_TYPE]) {
+ case MONO_TYPE_BOOLEAN:
+ case MONO_TYPE_U1:
+ case MONO_TYPE_I1:
+ *t = *p;
+ break;
+ case MONO_TYPE_CHAR:
+ case MONO_TYPE_U2:
+ case MONO_TYPE_I2: {
+ guint16 *val = (guint16*)t;
+ *val = read16 (p);
+ break;
+ }
+ case MONO_TYPE_U4:
+ case MONO_TYPE_I4: {
+ guint32 *val = (guint32*)t;
+ *val = read32 (p);
+ break;
+ }
+ case MONO_TYPE_U8:
+ case MONO_TYPE_I8: {
+ guint64 *val = (guint64*)t;
+ *val = read64 (p);
+ break;
+ }
+ case MONO_TYPE_R4: {
+ float *val = (float*)t;
+ readr4 (p, val);
+ break;
+ }
+ case MONO_TYPE_R8: {
+ double *val = (double*)t;
+ readr8 (p, val);
+ break;
+ }
+ case MONO_TYPE_STRING: {
+ //gpointer *val = (gpointer*)t;
+ //*val = mono_string_new_utf16 (domain, (const guint16*)p, len/2);
+ break;
+ }
+ case MONO_TYPE_CLASS:
+ /* nothing to do, we malloc0 the data and the value can be 0 only */
+ break;
+ default:
+ g_warning ("type 0x%02x should not be in constant table", cols [MONO_CONSTANT_TYPE]);
+ }
+ }
+
+ vt->max_interface_id = class->max_interface_id;
+
+ vt->interface_offsets = mono_mempool_alloc0 (domain->mp,
+ sizeof (gpointer) * (class->max_interface_id + 1));
+
+ /* initialize interface offsets */
+ for (k = class; k ; k = k->parent) {
+ for (i = 0; i < k->interface_count; i++) {
+ int slot;
+ MonoClass *ic = k->interfaces [i];
+ slot = class->interface_offsets [ic->interface_id];
+ vt->interface_offsets [ic->interface_id] = &vt->vtable [slot];
+ }
+ }
+
+ /* initialize vtable */
+ for (i = 0; i < class->vtable_size; ++i) {
+ MonoMethod *cm;
+
+ if ((cm = class->vtable [i]))
+ vt->vtable [i] = arch_create_jit_trampoline (cm);
+ }
+
+ mono_g_hash_table_insert (domain->class_vtable_hash, class, vt);
+ mono_domain_unlock (domain);
+
+ mono_runtime_class_init (class);
+
+ return vt;
+}
+
+/**
+ * mono_class_proxy_vtable:
+ * @domain: the application domain
+ * @class: the class to proxy
+ *
+ * Creates a vtable for transparent proxies. It is basically
+ * a copy of the real vtable of @class, but all function pointers invoke
+ * the remoting functions, and vtable->klass points to the
+ * transparent proxy class, and not to @class.
+ */
+MonoVTable *
+mono_class_proxy_vtable (MonoDomain *domain, MonoClass *class)
+{
+ MonoVTable *vt, *pvt;
+ int i, vtsize;
+
+ if ((pvt = mono_g_hash_table_lookup (domain->proxy_vtable_hash, class)))
+ return pvt;
+
+ vt = mono_class_vtable (domain, class);
+ vtsize = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
+
+// mono_stats.class_vtable_size += vtsize;
+
+ pvt = mono_mempool_alloc (domain->mp, vtsize);
+ memcpy (pvt, vt, vtsize);
+
+ pvt->klass = mono_defaults.transparent_proxy_class;
+
+ /* initialize vtable */
+ for (i = 0; i < class->vtable_size; ++i) {
+ MonoMethod *cm;
+
+ if ((cm = class->vtable [i]))
+ pvt->vtable [i] = arch_create_remoting_trampoline (cm);
+ }
+
+ mono_g_hash_table_insert (domain->proxy_vtable_hash, class, pvt);
+
+ return pvt;
+}
+
static MonoInvokeFunc default_mono_runtime_invoke = NULL;
MonoObject*
mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params)
{
MonoMethodSignature *sig = method->signature;
- gpointer *pa;
+ gpointer *pa = NULL;
int i;
+
+ if (NULL != params) {
+ pa = alloca (sizeof (gpointer) * mono_array_length (params));
+ for (i = 0; i < mono_array_length (params); i++) {
+ if (sig->params [i]->byref) {
+ /* nothing to do */
+ }
- pa = alloca (sizeof (gpointer) * params->bounds->length);
-
- for (i = 0; i < params->bounds->length; i++) {
- if (sig->params [i]->byref) {
- /* nothing to do */
- }
-
- switch (sig->params [i]->type) {
- case MONO_TYPE_U1:
- case MONO_TYPE_I1:
- case MONO_TYPE_BOOLEAN:
- case MONO_TYPE_U2:
- case MONO_TYPE_I2:
- case MONO_TYPE_CHAR:
- case MONO_TYPE_U:
- case MONO_TYPE_I:
- case MONO_TYPE_U4:
- case MONO_TYPE_I4:
- case MONO_TYPE_U8:
- case MONO_TYPE_I8:
- case MONO_TYPE_VALUETYPE:
- pa [i] = (char *)(((gpointer *)params->vector)[i]) + sizeof (MonoObject);
- break;
- case MONO_TYPE_STRING:
- case MONO_TYPE_OBJECT:
- case MONO_TYPE_CLASS:
- pa [i] = (char *)(((gpointer *)params->vector)[i]);
- break;
- default:
- g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
+ switch (sig->params [i]->type) {
+ case MONO_TYPE_U1:
+ case MONO_TYPE_I1:
+ case MONO_TYPE_BOOLEAN:
+ case MONO_TYPE_U2:
+ case MONO_TYPE_I2:
+ case MONO_TYPE_CHAR:
+ case MONO_TYPE_U:
+ case MONO_TYPE_I:
+ case MONO_TYPE_U4:
+ case MONO_TYPE_I4:
+ case MONO_TYPE_U8:
+ case MONO_TYPE_I8:
+ case MONO_TYPE_VALUETYPE:
+ pa [i] = (char *)(((gpointer *)params->vector)[i]) + sizeof (MonoObject);
+ break;
+ case MONO_TYPE_STRING:
+ case MONO_TYPE_OBJECT:
+ case MONO_TYPE_CLASS:
+ pa [i] = (char *)(((gpointer *)params->vector)[i]);
+ break;
+ default:
+ g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
+ }
}
}
mono_object_allocate (size_t size)
{
#if HAVE_BOEHM_GC
- void *o = GC_debug_malloc (size, "object", 1);
+ /* if this is changed to GC_debug_malloc(), we need to change also metadata/gc.c */
+ void *o = GC_malloc (size);
#else
void *o = calloc (1, size);
#endif
MonoObject *
mono_object_new (MonoDomain *domain, MonoClass *klass)
{
- static guint32 uoid = 0;
- MonoObject *o;
+ return mono_object_new_specific (mono_class_vtable (domain, klass));
+}
- mono_stats.new_object_count++;
+/**
+ * mono_object_new_specific:
+ * @vtable: the vtable of the object that we want to create
+ *
+ * Returns: A newly created object with class and domain specified
+ * by @vtable
+ */
+MonoObject *
+mono_object_new_specific (MonoVTable *vtable)
+{
+ MonoObject *o;
- if (!klass->inited)
- mono_class_init (klass);
+ mono_stats.new_object_count++; /* thread safe? */
- if (klass->ghcimpl) {
- o = mono_object_allocate (klass->instance_size);
- } else {
+ /* if the returned pointer is not the same as the address returned by GC_malloc(),
+ * we need to change also metadata/gc.c to take into account the new offset.
+ */
+ if (vtable->klass->ghcimpl)
+ o = mono_object_allocate (vtable->klass->instance_size);
+ else {
guint32 *t;
- t = mono_object_allocate (klass->instance_size + 4);
+ t = mono_object_allocate (vtable->klass->instance_size + 4);
*t = ++uoid;
o = (MonoObject *)(++t);
}
- o->vtable = mono_class_vtable (domain, klass);
-
+ o->vtable = vtable;
+ if (vtable->klass->has_finalize)
+ mono_object_register_finalizer (o);
+
return o;
}
memcpy (o, obj, size);
+ if (obj->vtable->klass->has_finalize)
+ mono_object_register_finalizer (o);
return o;
}
int size, i;
guint32 *sizes;
MonoClass *klass = array->obj.vtable->klass;
+
+ if (array->bounds == NULL) {
+ size = mono_array_length (array);
+ o = mono_array_new_full (((MonoObject *)array)->vtable->domain,
+ klass, &size, NULL);
+
+ size *= mono_array_element_size (klass);
+ memcpy (o, array, sizeof (MonoArray) + size);
+
+ return o;
+ }
sizes = alloca (klass->rank * sizeof(guint32) * 2);
size = mono_array_element_size (klass);
byte_len = mono_array_element_size (array_class);
len = 1;
-#if HAVE_BOEHM_GC
- bounds = GC_debug_malloc (sizeof (MonoArrayBounds) * array_class->rank, "bounds", 0);
-#else
- bounds = g_malloc0 (sizeof (MonoArrayBounds) * array_class->rank);
-#endif
- for (i = 0; i < array_class->rank; ++i) {
- bounds [i].length = lengths [i];
- len *= lengths [i];
+ if (array_class->rank == 1 &&
+ (lower_bounds == NULL || lower_bounds [0] == 0)) {
+ bounds = NULL;
+ len = lengths [0];
+ } else {
+ #if HAVE_BOEHM_GC
+ bounds = GC_malloc (sizeof (MonoArrayBounds) * array_class->rank);
+ #else
+ bounds = g_malloc0 (sizeof (MonoArrayBounds) * array_class->rank);
+ #endif
+ for (i = 0; i < array_class->rank; ++i) {
+ bounds [i].length = lengths [i];
+ len *= lengths [i];
+ }
+
+ if (lower_bounds)
+ for (i = 0; i < array_class->rank; ++i)
+ bounds [i].lower_bound = lower_bounds [i];
}
- if (lower_bounds)
- for (i = 0; i < array_class->rank; ++i)
- bounds [i].lower_bound = lower_bounds [i];
byte_len *= len;
/*
* Following three lines almost taken from mono_object_new ():
ac = mono_array_class_get (&eclass->byval_arg, 1);
g_assert (ac != NULL);
- return mono_array_new_full (domain, ac, &n, NULL);
+ return mono_array_new_specific (mono_class_vtable (domain, ac), n);
+}
+
+/*
+ * mono_array_new_specific:
+ * @vtable: a vtable in the appropriate domain for an initialized class
+ * @n: number of array elements
+ *
+ * This routine is a fast alternative to mono_array_new() for code which
+ * can be sure about the domain it operates in.
+ */
+MonoArray *
+mono_array_new_specific (MonoVTable *vtable, guint32 n)
+{
+ MonoObject *o;
+ MonoArray *ao;
+ gsize byte_len;
+
+ byte_len = n * mono_array_element_size (vtable->klass);
+ o = mono_object_allocate (sizeof (MonoArray) + byte_len);
+ if (!o)
+ G_BREAKPOINT ();
+ o->vtable = vtable;
+
+ ao = (MonoArray *)o;
+ ao->bounds = NULL;
+ ao->max_length = n;
+
+ return ao;
}
/**
mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
{
MonoString *s;
- MonoArray *ca;
-
- s = (MonoString*)mono_object_new (domain, mono_defaults.string_class);
+
+ s = mono_string_new_size (domain, len);
g_assert (s != NULL);
- ca = (MonoArray *)mono_array_new (domain, mono_defaults.char_class, len);
- g_assert (ca != NULL);
-
- s->c_str = ca;
- s->length = len;
+ memcpy (mono_string_chars (s), text, len * 2);
- memcpy (ca->vector, text, len * 2);
+ return s;
+}
+
+/**
+ * mono_string_new_size:
+ * @text: a pointer to an utf16 string
+ * @len: the length of the string
+ *
+ * Returns: A newly created string object of @len
+ */
+MonoString *
+mono_string_new_size (MonoDomain *domain, gint32 len)
+{
+ MonoString *s;
+
+ /*
+ * enable to get a good speedup: we still need to figure out
+ * how the sync structure is freed.
+ */
+#ifdef 0 && HAVE_BOEHM_GC
+ s = GC_malloc_atomic (sizeof (MonoString) + ((len + 1) * 2));
+ s->object.synchronisation = 0;
+ mono_string_chars (s) [len] = 0;
+#else
+ s = (MonoString*)mono_object_allocate (sizeof (MonoString) + ((len + 1) * 2));
+#endif
+ if (!s)
+ G_BREAKPOINT ();
+
+ s->object.vtable = mono_class_vtable (domain, mono_defaults.string_class);
+ s->length = len;
return s;
}
memcpy ((char *)res + sizeof (MonoObject), value, size);
+ if (class->has_finalize)
+ mono_object_register_finalizer (res);
return res;
}
#if G_BYTE_ORDER != G_LITTLE_ENDIAN
{
int i;
- char *p2 = mono_array_addr (str->c_str, char, 0);
+ char *p2 = mono_string_chars (str);
for (i = 0; i < str->length; ++i) {
*p++ = p2 [1];
*p++ = p2 [0];
}
}
#else
- memcpy (p, str->c_str->vector, str->length * 2);
+ memcpy (p, mono_string_chars (str), str->length * 2);
#endif
domain = ((MonoObject *)str)->vtable->domain;
ldstr_table = domain->ldstr_table;
char *
mono_string_to_utf8 (MonoString *s)
{
- char *as, *vector;
+ char *as;
GError *error = NULL;
g_assert (s != NULL);
- if (!s->length || !s->c_str)
+ if (!s->length)
return g_strdup ("");
- vector = (char*)s->c_str->vector;
-
- g_assert (vector != NULL);
-
- as = g_utf16_to_utf8 ((gunichar2 *)vector, s->length, NULL, NULL, &error);
+ as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, NULL, &error);
if (error)
g_warning (error->message);
as [(s->length * 2)] = '\0';
as [(s->length * 2) + 1] = '\0';
- if (!s->length || !s->c_str) {
+ if (!s->length) {
return (gunichar2 *)(as);
}
MonoDomain *domain = mono_domain_get ();
MonoMethod *method = msg->method->method;
MonoMethodSignature *sig = method->signature;
- MonoObject *res;
int i, j, outarg_count = 0;
for (i = 0; i < sig->param_count; i++) {