#include <mono/metadata/loader.h>
#include <mono/metadata/object.h>
#include <mono/metadata/appdomain.h>
+#if HAVE_BOEHM_GC
+#include <gc/gc.h>
+#endif
-static void
-default_runtime_object_init (MonoObject *o)
+void
+mono_runtime_object_init (MonoObject *this)
{
- return;
-}
+ int i;
+ MonoMethod *method = NULL;
+ MonoClass *klass = this->vtable->klass;
+
+ for (i = 0; i < klass->method.count; ++i) {
+ if (!strcmp (".ctor", klass->methods [i]->name) &&
+ klass->methods [i]->signature->param_count == 0) {
+ method = klass->methods [i];
+ break;
+ }
+ }
+
+ g_assert (method);
-MonoRuntimeObjectInit mono_runtime_object_init = default_runtime_object_init;
-MonoRuntimeExecMain mono_runtime_exec_main = NULL;
+ mono_runtime_invoke (method, this, NULL);
+}
+/*
+ * runtime_class_init:
+ * @klass: klass that needs to be initialized
+ *
+ * This routine calls the class constructor for @class.
+ */
void
-mono_install_runtime_object_init (MonoRuntimeObjectInit func)
+mono_runtime_class_init (MonoClass *klass)
{
- mono_runtime_object_init = func? func: default_runtime_object_init;
+ int i;
+
+ for (i = 0; i < klass->method.count; ++i) {
+ MonoMethod *method = klass->methods [i];
+ if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) &&
+ (strcmp (".cctor", method->name) == 0)) {
+ mono_runtime_invoke (method, NULL, NULL);
+ return;
+ }
+ }
+ /* No class constructor found */
+
+}
+
+static MonoInvokeFunc default_mono_runtime_invoke = NULL;
+
+MonoObject*
+mono_runtime_invoke (MonoMethod *method, void *obj, void **params)
+{
+ if (!default_mono_runtime_invoke) {
+ g_error ("runtime invoke called on uninitialized runtime");
+ return NULL;
+ }
+ return default_mono_runtime_invoke (method, obj, params);
+}
+
+int
+mono_runtime_exec_main (MonoMethod *method, MonoArray *args)
+{
+ gpointer pa [1];
+
+ pa [0] = args;
+
+ if (method->signature->ret->type == MONO_TYPE_I4) {
+ MonoObject *res;
+ res = mono_runtime_invoke (method, NULL, pa);
+ return *(guint32 *)((char *)res + sizeof (MonoObject));
+ } else {
+ mono_runtime_invoke (method, NULL, pa);
+ return 0;
+ }
}
void
-mono_install_runtime_exec_main (MonoRuntimeExecMain func)
+mono_install_runtime_invoke (MonoInvokeFunc func)
{
- mono_runtime_exec_main = func;
+ default_mono_runtime_invoke = func;
+}
+
+MonoObject*
+mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params)
+{
+ MonoMethodSignature *sig = method->signature;
+ gpointer *pa;
+ int i;
+
+ 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);
+ }
+ }
+
+ if (!strcmp (method->name, ".ctor")) {
+ obj = mono_object_new (mono_domain_get (), method->klass);
+ mono_runtime_invoke (method, obj, pa);
+ return obj;
+ } else
+ return mono_runtime_invoke (method, obj, pa);
}
/**
void *
mono_object_allocate (size_t size)
{
+#if HAVE_BOEHM_GC
+ void *o = GC_debug_malloc (size, "object", 1);
+#else
void *o = calloc (1, size);
+#endif
return o;
}
void
mono_object_free (MonoObject *o)
{
+#if HAVE_BOEHM_GC
+ g_error ("mono_object_free called with boehm gc.");
+#else
MonoClass *c = o->vtable->klass;
memset (o, 0, c->instance_size);
free (o);
+#endif
}
/**
MonoObject *
mono_object_new (MonoDomain *domain, MonoClass *klass)
{
+ static guint32 uoid = 0;
MonoObject *o;
if (!klass->inited)
mono_class_init (klass);
- o = mono_object_allocate (klass->instance_size);
- o->vtable = mono_class_vtable (domain, klass);
+
+ if (klass->ghcimpl) {
+ o = mono_object_allocate (klass->instance_size);
+ o->vtable = mono_class_vtable (domain, klass);
+ } else {
+ guint32 *t;
+ t = mono_object_allocate (klass->instance_size + 4);
+ *t = ++uoid;
+ o = (MonoObject *)(++t);
+ o->vtable = mono_class_vtable (domain, klass);
+ }
return o;
}
return o;
}
+/*
+ * mono_array_new_full:
+ * @domain: domain where the object is created
+ * @array_class: array class
+ * @lengths: lengths for each dimension in the array
+ * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
+ *
+ * This routine creates a new array objects with the given dimensions,
+ * lower bounds and type.
+ */
MonoArray*
mono_array_new_full (MonoDomain *domain, MonoClass *array_class,
guint32 *lengths, guint32 *lower_bounds)
byte_len = mono_array_element_size (array_class);
+#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];
byte_len *= lengths [i];
/*
* mono_array_new:
- * @image: image where the object is being referenced
+ * @domain: domain where the object is created
* @eclass: element class
* @n: number of array elements
*
- * This routine creates a new szarray with @n elements of type @token
+ * This routine creates a new szarray with @n elements of type @eclass.
*/
MonoArray *
mono_array_new (MonoDomain *domain, MonoClass *eclass, guint32 n)
return s;
}
+/*
+ * mono_string_new_len:
+ * @text: a pointer to an utf8 string
+ * @length: number of bytes in @text to consider
+ *
+ * Returns: A newly created string object which contains @text.
+ */
MonoString*
-mono_string_new_len
-(MonoDomain *domain, const char *text, guint length)
+mono_string_new_len (MonoDomain *domain, const char *text, guint length)
{
GError *error = NULL;
MonoString *o = NULL;
return o;
}
+/*
+ * mono_string_new_wrapper:
+ * @text: pointer to utf8 characters.
+ *
+ * Helper function to create a string object from @text in the current domain.
+ */
+MonoString*
+mono_string_new_wrapper (const char *text)
+{
+ MonoDomain *domain = mono_domain_get ();
+
+ return mono_string_new (domain, text);
+}
+
/**
* mono_value_box:
* @class: the class of the value
vt->interface_offsets [klass->interface_id])
return obj;
} else {
+ if (oklass == mono_defaults.transparent_proxy_class) {
+ /* fixme: add check for IRemotingTypeInfo */
+ MonoRealProxy *rp = ((MonoTransparentProxy *)obj)->rp;
+ MonoType *type;
+ type = ((MonoReflectionType *)rp->class_to_proxy)->type;
+ oklass = mono_class_from_mono_type (type);
+ }
if (oklass->rank && oklass->rank == klass->rank) {
if ((oklass->element_class->baseval - klass->element_class->baseval) <=
klass->element_class->diffval)
return NULL;
}
-
-typedef struct {
- MonoString *obj;
- MonoString *found;
-} InternCheck;
-
-static void
-check_interned (gpointer key, MonoString *value, InternCheck *check)
-{
- if (value == check->obj)
- check->found = value;
-}
-
-MonoString*
-mono_string_is_interned (MonoString *o)
+static MonoString*
+mono_string_is_interned_lookup (MonoString *str, int insert)
{
- InternCheck check;
- check.obj = o;
- check.found = NULL;
-
- /*
- * Yes, this is slow. Our System.String implementation needs to be redone.
- * And GLib needs foreach() methods that can be stopped halfway.
- */
- g_hash_table_foreach (((MonoObject *)o)->vtable->domain->ldstr_table, (GHFunc)check_interned, &check);
- return check.found;
-}
-
-MonoString*
-mono_string_intern (MonoString *str)
-{
- GHashTable *ldstr_table;
+ MonoGHashTable *ldstr_table;
MonoString *res;
char *ins = g_malloc (4 + str->length * 2);
char *p;
memcpy (p, str->c_str->vector, str->length * 2);
#endif
ldstr_table = ((MonoObject *)str)->vtable->domain->ldstr_table;
- if ((res = g_hash_table_lookup (ldstr_table, ins))) {
+ if ((res = mono_g_hash_table_lookup (ldstr_table, ins))) {
g_free (ins);
return res;
}
- g_hash_table_insert (ldstr_table, ins, str);
- return str;
+ if (insert) {
+ mono_g_hash_table_insert (ldstr_table, ins, str);
+ return str;
+ }
+ g_free (ins);
+ return NULL;
}
MonoString*
-mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 index)
+mono_string_is_interned (MonoString *o)
+{
+ return mono_string_is_interned_lookup (o, FALSE);
+}
+
+MonoString*
+mono_string_intern (MonoString *str)
+{
+ return mono_string_is_interned_lookup (str, TRUE);
+}
+
+/*
+ * mono_ldstr:
+ * @domain: the domain where the string will be used.
+ * @image: a metadata context
+ * @idx: index into the user string table.
+ *
+ * Implementation for the ldstr opcode.
+ */
+MonoString*
+mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
{
const char *str, *sig;
MonoString *o;
size_t len2;
- sig = str = mono_metadata_user_string (image, index);
- len2 = mono_metadata_decode_blob_size (str, &str);
+ sig = str = mono_metadata_user_string (image, idx);
- if ((o = g_hash_table_lookup (domain->ldstr_table, sig)))
+ if ((o = mono_g_hash_table_lookup (domain->ldstr_table, sig)))
return o;
+ len2 = mono_metadata_decode_blob_size (str, &str);
len2 >>= 1;
o = mono_string_new_utf16 (domain, (guint16*)str, len2);
}
}
#endif
- g_hash_table_insert (domain->ldstr_table, (gpointer)sig, o);
+ mono_g_hash_table_insert (domain->ldstr_table, (gpointer)sig, o);
return o;
}
+/*
+ * mono_string_to_utf8:
+ * @s: a System.String
+ *
+ * Return the UTF8 representation for @s.
+ * the resulting buffer nedds to be freed with g_free().
+ */
char *
mono_string_to_utf8 (MonoString *s)
{
g_assert (vector != NULL);
as = g_utf16_to_utf8 ((gunichar2 *)vector, s->length, NULL, NULL, &error);
-
- g_assert (!error);
+ if (error)
+ g_warning (error->message);
return as;
}
-char *
+/*
+ * mono_string_to_utf16:
+ * @s: a MonoString
+ *
+ * Return an null-terminated array of the utf-16 chars
+ * contained in @s. The result must be freed with g_free().
+ * This is a temporary helper until our string implementation
+ * is reworked to always include the null terminating char.
+ */
+gunichar2 *
mono_string_to_utf16 (MonoString *s)
{
char *as;
as [(s->length * 2) + 1] = '\0';
if (!s->length || !s->c_str) {
- return (as);
+ return (gunichar2 *)(as);
}
memcpy (as, mono_string_chars(s), s->length * 2);
- return (as);
+ return (gunichar2 *)(as);
}
static void
ex_handler = func? func: default_ex_handler;
}
+/*
+ * mono_raise_exception:
+ * @ex: exception object
+ *
+ * Signal the runtime that the exception @ex has been raised in unmanaged code.
+ */
void
mono_raise_exception (MonoException *ex)
{
ex_handler (ex);
}
+MonoWaitHandle *
+mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
+{
+ MonoWaitHandle *res;
+
+ res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
+
+ res->handle = handle;
+
+ return res;
+}
+
+MonoAsyncResult *
+mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data)
+{
+ MonoAsyncResult *res;
+
+ res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
+
+ res->data = data;
+ res->async_state = state;
+ res->handle = (MonoObject *)mono_wait_handle_new (domain, handle);
+ res->sync_completed = FALSE;
+ res->completed = FALSE;
+
+ return res;
+}
+
+void
+mono_message_init (MonoDomain *domain,
+ MonoMethodMessage *this,
+ MonoReflectionMethod *method,
+ MonoArray *out_args)
+{
+ MonoMethodSignature *sig = method->method->signature;
+ MonoString *name;
+ int i, j;
+ char **names;
+ guint8 arg_type;
+
+ this->method = method;
+
+ this->args = mono_array_new (domain, mono_defaults.object_class, sig->param_count);
+ this->arg_types = mono_array_new (domain, mono_defaults.byte_class, sig->param_count);
+
+ names = g_new (char *, sig->param_count);
+ mono_method_get_param_names (method->method, (const char **) names);
+ this->names = mono_array_new (domain, mono_defaults.string_class, sig->param_count);
+
+ for (i = 0; i < sig->param_count; i++) {
+ name = mono_string_new (domain, names [i]);
+ mono_array_set (this->names, gpointer, i, name);
+ }
+
+ g_free (names);
+
+ for (i = 0, j = 0; i < sig->param_count; i++) {
+
+ if (sig->params [i]->byref) {
+ if (out_args) {
+ gpointer arg = mono_array_get (out_args, gpointer, j);
+ mono_array_set (this->args, gpointer, i, arg);
+ j++;
+ }
+ arg_type = 2;
+ if (sig->params [i]->attrs & PARAM_ATTRIBUTE_IN)
+ arg_type |= 1;
+ } else {
+ arg_type = 1;
+ }
+
+ mono_array_set (this->arg_types, guint8, i, arg_type);
+ }
+}
+
+/**
+ * mono_remoting_invoke:
+ * @real_proxy: pointer to a RealProxy object
+ * @msg: The MonoMethodMessage to execute
+ * @exc: used to store exceptions
+ * @out_args: used to store output arguments
+ *
+ * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
+ * IMessage interface and it is not trivial to extract results from there. So
+ * we call an helper method PrivateInvoke instead of calling
+ * RealProxy::Invoke() directly.
+ *
+ * Returns: the result object.
+ */
+MonoObject *
+mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
+ MonoObject **exc, MonoArray **out_args)
+{
+ static MonoMethod *im = NULL;
+ gpointer pa [4];
+
+ //static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;
+
+ /* fixme: make this domain dependent */
+ if (!im) {
+ MonoClass *klass;
+ int i;
+
+ klass = mono_defaults.real_proxy_class;
+
+ for (i = 0; i < klass->method.count; ++i) {
+ if (!strcmp ("PrivateInvoke", klass->methods [i]->name) &&
+ klass->methods [i]->signature->param_count == 4) {
+ im = klass->methods [i];
+ break;
+ }
+ }
+
+ g_assert (im);
+ }
+
+ pa [0] = real_proxy;
+ pa [1] = msg;
+ pa [2] = exc;
+ pa [3] = out_args;
+
+ return mono_runtime_invoke (im, NULL, pa);
+}
+
+MonoObject *
+mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
+ MonoObject **exc, MonoArray **out_args)
+{
+ if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
+
+ return mono_remoting_invoke ((MonoObject *)((MonoTransparentProxy *)target)->rp,
+ msg, exc, out_args);
+
+ } else {
+ 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++) {
+ if (sig->params [i]->byref)
+ outarg_count++;
+ }
+
+ *out_args = mono_array_new (domain, mono_defaults.object_class, outarg_count);
+ *exc = NULL;
+
+ for (i = 0, j = 0; i < sig->param_count; i++) {
+ if (sig->params [i]->byref) {
+ gpointer arg;
+ arg = mono_array_get (msg->args, gpointer, i);
+ mono_array_set (*out_args, gpointer, j, arg);
+ j++;
+ }
+ }
+
+ return mono_runtime_invoke_array (method, target, msg->args);
+ }
+}
+
+
+