#include <mono/metadata/tokentype.h>
#include <mono/metadata/loader.h>
#include <mono/metadata/object.h>
-#include <mono/metadata/gc.h>
+#include <mono/metadata/gc-internal.h>
+#include <mono/metadata/exception.h>
#include <mono/metadata/appdomain.h>
#include <mono/metadata/assembly.h>
#include <mono/metadata/threadpool.h>
+#include <mono/metadata/marshal.h>
#include "mono/metadata/debug-helpers.h"
-#if HAVE_BOEHM_GC
-#include <gc/gc.h>
-#endif
+#include "mono/metadata/marshal.h"
+#include <mono/metadata/threads.h>
+#include <mono/metadata/environment.h>
+#include "mono/metadata/profiler-private.h"
+#include <mono/os/gc_wrapper.h>
+
+/*
+ * enable to get a good speedup: we still need to figure out
+ * how the sync structure is freed.
+ */
+#define CREATION_SPEEDUP 0
void
mono_runtime_object_init (MonoObject *this)
}
/*
- * runtime_class_init:
+ * mono_runtime_class_init:
* @klass: klass that needs to be initialized
*
* This routine calls the class constructor for @class.
mono_runtime_class_init (MonoClass *klass)
{
int i;
+ MonoException *exc = NULL;
+ MonoException *exc_to_throw;
+ MonoMethod *method;
+ gchar *full_name;
for (i = 0; i < klass->method.count; ++i) {
- MonoMethod *method = klass->methods [i];
+ method = klass->methods [i];
if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) &&
(strcmp (".cctor", method->name) == 0)) {
- mono_runtime_invoke (method, NULL, NULL, NULL);
+ mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
+ if (exc != NULL)
+ break;
return;
}
}
- /* No class constructor found */
+ if (exc == NULL ||
+ (klass->image == mono_defaults.corlib &&
+ !strcmp (klass->name_space, "System") &&
+ !strcmp (klass->name, "TypeInitializationException")))
+ return; /* No static constructor found or avoid infinite loop */
+
+ if (klass->name_space && *klass->name_space)
+ full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
+ else
+ full_name = g_strdup (klass->name);
+
+ exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
+ g_free (full_name);
+
+ mono_raise_exception (exc_to_throw);
}
static gpointer
if (vt && vt->domain == domain)
return vt;
- /* 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);
if (class->class_size) {
#if HAVE_BOEHM_GC
- vt->data = GC_malloc (class->class_size + 8);
+ 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);
if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
MonoClass *fklass = mono_class_from_mono_type (field->type);
t = (char*)vt->data + field->offset;
- g_assert (fklass->valuetype);
- memcpy (t, field->data, mono_class_value_size (fklass, NULL));
+ if (fklass->valuetype) {
+ memcpy (t, field->data, mono_class_value_size (fklass, NULL));
+ } else {
+ /* it's a pointer type: add check */
+ g_assert (fklass->byval_arg.type == MONO_TYPE_PTR);
+ *t = *(gpointer*)field->data;
+ }
continue;
}
if (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT))
break;
}
case MONO_TYPE_STRING: {
- /*gpointer *val = (gpointer*)t;
- *val = mono_string_new_utf16 (domain, (const guint16*)p, len/2);*/
+ gpointer *val = (gpointer*)t;
+#if G_BYTE_ORDER != G_LITTLE_ENDIAN
+ gunichar2 *copy = g_malloc (len);
+ int j;
+ for (j = 0; j < len/2; j++) {
+ copy [j] = read16 (p);
+ p += 2;
+ }
+ *val = mono_string_new_utf16 (domain, copy, len/2);
+ g_free (copy);
+#else
+ *val = mono_string_new_utf16 (domain, (const guint16*)p, len/2);
+#endif
break;
}
case MONO_TYPE_CLASS:
}
}
+ /*
+ * arch_create_jit_trampoline () can recursively call this function again
+ * because it compiles icall methods right away.
+ */
+ mono_g_hash_table_insert (domain->class_vtable_hash, class, vt);
+ if (!class->cached_vtable)
+ class->cached_vtable = vt;
+
/* initialize vtable */
for (i = 0; i < class->vtable_size; ++i) {
MonoMethod *cm;
vt->vtable [i] = arch_create_jit_trampoline (cm);
}
- mono_g_hash_table_insert (domain->class_vtable_hash, class, vt);
- if (!class->cached_vtable)
- class->cached_vtable = vt;
-
mono_domain_unlock (domain);
/* make sure the the parent is initialized */
return pvt;
}
-static MonoInvokeFunc default_mono_runtime_invoke = NULL;
+/*
+ * Retrieve the MonoMethod that would to be called on obj if obj is passed as
+ * the instance of a callvirt of method.
+ */
+MonoMethod*
+mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method) {
+ MonoClass *klass;
+ MonoMethod **vtable;
+ gboolean is_proxy;
+ MonoMethod *res;
+
+ if ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL))
+ return method;
+
+ klass = mono_object_class (obj);
+ if (klass == mono_defaults.transparent_proxy_class) {
+ klass = ((MonoTransparentProxy *)obj)->klass;
+ is_proxy = TRUE;
+ } else {
+ is_proxy = FALSE;
+ }
+ vtable = klass->vtable;
+
+ if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
+ res = vtable [method->klass->interface_id + method->slot];
+ } else {
+ res = vtable [method->slot];
+ }
+ g_assert (res);
+
+ if (is_proxy)
+ return mono_marshal_get_remoting_invoke (res);
+
+ return res;
+}
+
+static MonoObject*
+dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
+{
+ g_error ("runtime invoke called on uninitialized runtime");
+ return NULL;
+}
+
+static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
MonoObject*
mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
{
- if (!default_mono_runtime_invoke) {
- g_error ("runtime invoke called on uninitialized runtime");
- return NULL;
+ return default_mono_runtime_invoke (method, obj, params, exc);
+}
+
+static void
+set_value (MonoType *type, void *dest, void *value, int deref_pointer) {
+ int t;
+ if (type->byref) {
+ gpointer *p = (gpointer*)dest;
+ *p = value;
+ return;
+ }
+ t = type->type;
+handle_enum:
+ switch (t) {
+ case MONO_TYPE_BOOLEAN:
+ case MONO_TYPE_I1:
+ case MONO_TYPE_U1: {
+ guint8 *p = (guint8*)dest;
+ *p = *(guint8*)value;
+ return;
+ }
+ case MONO_TYPE_I2:
+ case MONO_TYPE_U2:
+ case MONO_TYPE_CHAR: {
+ guint16 *p = (guint16*)dest;
+ *p = *(guint16*)value;
+ return;
+ }
+#if SIZEOF_VOID_P == 4
+ case MONO_TYPE_I:
+ case MONO_TYPE_U:
+#endif
+ case MONO_TYPE_I4:
+ case MONO_TYPE_U4: {
+ gint32 *p = (gint32*)dest;
+ *p = *(gint32*)value;
+ return;
+ }
+#if SIZEOF_VOID_P == 8
+ case MONO_TYPE_I:
+ case MONO_TYPE_U:
+#endif
+ case MONO_TYPE_I8:
+ case MONO_TYPE_U8: {
+ gint64 *p = (gint64*)dest;
+ *p = *(gint64*)value;
+ return;
+ }
+ case MONO_TYPE_R4: {
+ float *p = (float*)dest;
+ *p = *(float*)value;
+ return;
}
+ case MONO_TYPE_R8: {
+ double *p = (double*)dest;
+ *p = *(double*)value;
+ return;
+ }
+ case MONO_TYPE_STRING:
+ case MONO_TYPE_SZARRAY:
+ case MONO_TYPE_CLASS:
+ case MONO_TYPE_OBJECT:
+ case MONO_TYPE_ARRAY:
+ case MONO_TYPE_PTR: {
+ gpointer *p = (gpointer*)dest;
+ *p = deref_pointer? *(gpointer*)value: value;
+ return;
+ }
+ case MONO_TYPE_VALUETYPE:
+ if (type->data.klass->enumtype) {
+ t = type->data.klass->enum_basetype->type;
+ goto handle_enum;
+ } else {
+ int size;
+ size = mono_class_value_size (type->data.klass, NULL);
+ memcpy (dest, value, size);
+ }
+ return;
+ default:
+ g_warning ("got type %x", type->type);
+ g_assert_not_reached ();
+ }
+}
- return default_mono_runtime_invoke (method, obj, params, exc);
+void
+mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
+{
+ void *dest;
+
+ g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
+
+ dest = (char*)obj + field->offset;
+ set_value (field->type, dest, value, FALSE);
}
+void
+mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
+{
+ void *dest;
+
+ g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
+
+ dest = (char*)vt->data + field->offset;
+ set_value (field->type, dest, value, FALSE);
+}
+
+void
+mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
+{
+ void *src;
+
+ g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
+
+ src = (char*)obj + field->offset;
+ set_value (field->type, value, src, TRUE);
+}
+
+void
+mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
+{
+ void *src;
+
+ g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
+
+ src = (char*)vt->data + field->offset;
+ set_value (field->type, value, src, TRUE);
+}
+
+void
+mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
+{
+ default_mono_runtime_invoke (prop->set, obj, params, exc);
+}
+
+MonoObject*
+mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
+{
+ return default_mono_runtime_invoke (prop->get, obj, params, exc);
+}
+
+
MonoMethod *
mono_get_delegate_invoke (MonoClass *klass)
{
MonoString *arg = mono_string_new (domain, argv [i]);
mono_array_set (args, gpointer, i, arg);
}
+ } else {
+ args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
}
mono_assembly_set_main (method->klass->image->assembly);
-
+
return mono_runtime_exec_main (method, args, exc);
}
"UnhandledException");
g_assert (field);
- delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
+ if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
+ delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
- if (!delegate) {
- mono_print_unhandled_exception (exc);
- } else {
- MonoObject *e = NULL;
- gpointer pa [2];
+ if (!delegate) {
+ mono_print_unhandled_exception (exc);
+ } else {
+ MonoObject *e = NULL;
+ gpointer pa [2];
- /* fixme: pass useful arguments */
- pa [0] = NULL;
- pa [1] = NULL;
- mono_runtime_delegate_invoke (delegate, pa, &e);
-
- if (e)
- g_warning ("exception inside UnhandledException handler!");
+ /* fixme: pass useful arguments */
+ pa [0] = NULL;
+ pa [1] = NULL;
+ mono_runtime_delegate_invoke (delegate, pa, &e);
+
+ if (e)
+ g_warning ("exception inside UnhandledException handler!");
+ }
}
}
+/*
+ * Launch a new thread to start all setup that requires managed code
+ * to be executed.
+ *
+ * main_func is called back from the thread with main_args as the
+ * parameter. The callback function is expected to start Main()
+ * eventually. This function then waits for all managed threads to
+ * finish.
+ */
+void
+mono_runtime_exec_managed_code (MonoDomain *domain,
+ MonoMainThreadFunc main_func,
+ gpointer main_args)
+{
+ mono_thread_create (domain, main_func, main_args);
+
+ mono_thread_manage ();
+}
+
/*
* Execute a standard Main() method (args doesn't contain the
* executable name).
int
mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
{
+ MonoDomain *domain;
gpointer pa [1];
+ MonoObject *res;
int rval;
+ g_assert (args);
+
pa [0] = args;
+ domain = mono_object_domain (args);
+ if (!domain->entry_assembly) {
+ domain->entry_assembly = method->klass->image->assembly;
+ ves_icall_System_AppDomainSetup_InitAppDomainSetup (domain->setup);
+ }
+
/* FIXME: check signature of method */
if (method->signature->ret->type == MONO_TYPE_I4) {
MonoObject *res;
rval = *(guint32 *)((char *)res + sizeof (MonoObject));
else
rval = -1;
+
+ mono_environment_exitcode_set (rval);
} else {
mono_runtime_invoke (method, NULL, pa, exc);
if (!exc || !*exc)
rval = 0;
- else
+ else {
+ /* If the return type of Main is void, only
+ * set the exitcode if an exception was thrown
+ * (we don't want to blow away an
+ * explicitly-set exit code)
+ */
rval = -1;
+ mono_environment_exitcode_set (rval);
+ }
}
return rval;
void
mono_install_runtime_invoke (MonoInvokeFunc func)
{
- default_mono_runtime_invoke = func;
+ default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
}
MonoObject*
case MONO_TYPE_I4:
case MONO_TYPE_U8:
case MONO_TYPE_I8:
+ case MONO_TYPE_R4:
+ case MONO_TYPE_R8:
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:
+ case MONO_TYPE_ARRAY:
case MONO_TYPE_SZARRAY:
pa [i] = (char *)(((gpointer *)params->vector)[i]);
break;
}
if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
- obj = mono_object_new (mono_domain_get (), method->klass);
+ if (!obj)
+ obj = mono_object_new (mono_domain_get (), method->klass);
mono_runtime_invoke (method, obj, pa, exc);
return obj;
} else
{
#if HAVE_BOEHM_GC
/* if this is changed to GC_debug_malloc(), we need to change also metadata/gc.c */
- void *o = GC_malloc (size);
+ void *o = GC_MALLOC (size);
#else
void *o = calloc (1, size);
#endif
+ mono_stats.new_object_count++;
+
return o;
}
{
MonoObject *o;
- mono_stats.new_object_count++;
-
o = mono_object_allocate (vtable->klass->instance_size);
o->vtable = vtable;
if (vtable->klass->has_finalize)
mono_object_register_finalizer (o);
+ mono_profiler_allocation (o, vtable->klass);
return o;
}
size = obj->vtable->klass->instance_size;
o = mono_object_allocate (size);
+ mono_profiler_allocation (o, obj->vtable->klass);
memcpy (o, obj, size);
guint32 *sizes;
MonoClass *klass = array->obj.vtable->klass;
+ MONO_ARCH_SAVE_REGS;
+
if (array->bounds == NULL) {
size = mono_array_length (array);
o = mono_array_new_full (((MonoObject *)array)->vtable->domain,
len = lengths [0];
} else {
#if HAVE_BOEHM_GC
- bounds = GC_malloc (sizeof (MonoArrayBounds) * array_class->rank);
+ bounds = GC_MALLOC (sizeof (MonoArrayBounds) * array_class->rank);
#else
bounds = g_malloc0 (sizeof (MonoArrayBounds) * array_class->rank);
#endif
array->bounds = bounds;
array->max_length = len;
+ mono_profiler_allocation (o, array_class);
+
return array;
}
gsize byte_len;
byte_len = n * mono_array_element_size (vtable->klass);
+#if CREATION_SPEEDUP
+ if (vtable->klass->element_class->byval_arg.type >= MONO_TYPE_BOOLEAN && vtable->klass->element_class->byval_arg.type <= MONO_TYPE_R4) {
+ o = GC_MALLOC_ATOMIC (sizeof (MonoArray) + byte_len);
+ o->synchronisation = 0;
+ memset (((MonoArray*)o)->vector, 0, byte_len);
+ } else {
+ o = mono_object_allocate (sizeof (MonoArray) + byte_len);
+ }
+#else
o = mono_object_allocate (sizeof (MonoArray) + byte_len);
+#endif
if (!o)
G_BREAKPOINT ();
o->vtable = vtable;
ao = (MonoArray *)o;
ao->bounds = NULL;
ao->max_length = n;
+ mono_profiler_allocation (o, vtable->klass);
return ao;
}
{
MonoString *s;
- /*
- * enable to get a good speedup: we still need to figure out
- * how the sync structure is freed.
- */
-#if 0
- s = GC_malloc_atomic (sizeof (MonoString) + ((len + 1) * 2));
+#if CREATION_SPEEDUP
+ s = GC_MALLOC_ATOMIC (sizeof (MonoString) + ((len + 1) * 2));
s->object.synchronisation = 0;
mono_string_chars (s) [len] = 0;
#else
s->object.vtable = mono_class_vtable (domain, mono_defaults.string_class);
s->length = len;
+ mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
return s;
}
size = mono_class_instance_size (class);
res = mono_object_allocate (size);
res->vtable = mono_class_vtable (domain, class);
+ mono_profiler_allocation (res, class);
size = size - sizeof (MonoObject);
}
if (klass->rank) {
if (oklass->rank == klass->rank &&
- (oklass->element_class->baseval - klass->element_class->baseval) <=
- klass->element_class->diffval)
+ (oklass->cast_class->baseval - klass->cast_class->baseval) <=
+ klass->cast_class->diffval)
return obj;
} else if ((oklass->baseval - klass->baseval) <= klass->diffval)
const char *str, *sig;
MonoString *o;
size_t len2;
-
- sig = str = mono_metadata_user_string (image, idx);
+
+ if (image->assembly->dynamic)
+ return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx);
+ else
+ sig = str = mono_metadata_user_string (image, idx);
mono_domain_lock (domain);
if ((o = mono_g_hash_table_lookup (domain->ldstr_table, sig))) {
return (gunichar2 *)(as);
}
+/*
+ * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString
+ */
+MonoString *
+mono_string_from_utf16 (gunichar2 *data)
+{
+ MonoDomain *domain = mono_domain_get ();
+ int len = 0;
+
+ if (!data)
+ return NULL;
+
+ while (data [len]) len++;
+
+ return mono_string_new_utf16 (domain, data, len);
+}
+
static void
default_ex_handler (MonoException *ex)
{
void
mono_print_unhandled_exception (MonoObject *exc)
{
- char *message = g_strdup ("");
- char *trace = g_strdup ("");
+ char *message = (char *) "";
MonoString *str;
+ MonoMethod *method;
+ MonoClass *klass;
+ gboolean free_message = FALSE;
+ gint i;
if (mono_object_isinst (exc, mono_defaults.exception_class)) {
- if ((str = ((MonoException *)exc)->message))
+ klass = exc->vtable->klass;
+ method = NULL;
+ while (klass && method == NULL) {
+ for (i = 0; i < klass->method.count; ++i) {
+ method = klass->methods [i];
+ if (!strcmp ("ToString", method->name) &&
+ method->signature->param_count == 0 &&
+ method->flags & METHOD_ATTRIBUTE_VIRTUAL &&
+ method->flags & METHOD_ATTRIBUTE_PUBLIC) {
+ break;
+ }
+ method = NULL;
+ }
+
+ if (method == NULL)
+ klass = klass->parent;
+ }
+
+ g_assert (method);
+
+ str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
+ if (str) {
message = mono_string_to_utf8 (str);
- if ((str = ((MonoException *)exc)->stack_trace))
- trace = mono_string_to_utf8 (str);
+ free_message = TRUE;
+ }
}
- g_warning ("unhandled exception %s.%s: \"%s\"", exc->vtable->klass->name_space,
- exc->vtable->klass->name, message);
+ /*
+ * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
+ * exc->vtable->klass->name, message);
+ */
+ g_printerr ("\nUnhandled Exception: %s\n", message);
- if (trace) {
- g_printerr (trace);
- g_printerr ("\n");
- }
-
- g_free (message);
- g_free (trace);
+ if (free_message)
+ g_free (message);
}
/**
if ((ji = mono_jit_info_table_find (domain, addr))) {
method = ji->method;
- delegate->method_info = mono_method_get_object (domain, method);
+ delegate->method_info = mono_method_get_object (domain, method, NULL);
}
if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
g_assert (method);
- delegate->method_ptr = arch_create_remoting_trampoline (method);
+ method = mono_marshal_get_remoting_invoke (method);
+ delegate->method_ptr = mono_compile_method (method);
delegate->target = target;
} else {
delegate->method_ptr = addr;
msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
if (invoke) {
- mono_message_init (domain, msg, mono_method_get_object (domain, invoke), NULL);
+ mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
count = sig->param_count - 2;
} else {
- mono_message_init (domain, msg, mono_method_get_object (domain, method), NULL);
+ mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
count = sig->param_count;
}
mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
{
MonoMethodSignature *sig = method->signature;
- int i, j, type, size, align;
+ int i, j, type, size;
for (i = 0, j = 0; i < sig->param_count; i++) {
- MonoType *pt = mono_get_param_info (sig, i, &size, &align);
+ MonoType *pt = sig->params [i];
+
+ size = mono_type_stack_size (pt, NULL);
if (pt->byref) {
char *arg = mono_array_get (out_args, gpointer, j);
}
}
+/**
+ * mono_load_remote_field:
+ * @this: pointer to an object
+ * @klass: klass of the object containing @field
+ * @field: the field to load
+ * @res: a storage to store the result
+ *
+ * This method is called by the runtime on attempts to load fields of
+ * transparent proxy objects. @this points to such TP, @klass is the class of
+ * the object containing @field. @res is a storage location which can be
+ * used to store the result.
+ *
+ * Returns: an address pointing to the value of field.
+ */
+gpointer
+mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
+{
+ static MonoMethod *getter = NULL;
+ MonoDomain *domain = mono_domain_get ();
+ MonoClass *field_class;
+ MonoMethodMessage *msg;
+ MonoArray *out_args;
+ MonoObject *exc;
+ gpointer tmp;
+
+ g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
+
+ if (!res)
+ res = &tmp;
+
+ if (!getter) {
+ int i;
+
+ for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
+ MonoMethod *cm = mono_defaults.object_class->methods [i];
+
+ if (!strcmp (cm->name, "FieldGetter")) {
+ getter = cm;
+ break;
+ }
+ }
+ g_assert (getter);
+ }
+
+ field_class = mono_class_from_mono_type (field->type);
+ msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
+ out_args = mono_array_new (domain, mono_defaults.object_class, 1);
+ mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
+ mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
+ mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
+
+ mono_remoting_invoke ((MonoObject *)((MonoTransparentProxy *)this)->rp, msg, &exc, &out_args);
+
+ *res = mono_array_get (out_args, MonoObject *, 0);
+
+ if (field_class->valuetype) {
+ return ((char *)*res) + sizeof (MonoObject);
+ } else
+ return res;
+}
+
+/**
+ * mono_store_remote_field:
+ * @this: pointer to an object
+ * @klass: klass of the object containing @field
+ * @field: the field to load
+ * @val: the value/object to store
+ *
+ * This method is called by the runtime on attempts to store fields of
+ * transparent proxy objects. @this points to such TP, @klass is the class of
+ * the object containing @field. @val is the new value to store in @field.
+ */
+void
+mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
+{
+ static MonoMethod *setter = NULL;
+ MonoDomain *domain = mono_domain_get ();
+ MonoClass *field_class;
+ MonoMethodMessage *msg;
+ MonoArray *out_args;
+ MonoObject *exc;
+ MonoObject *arg;
+
+ g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
+
+ if (!setter) {
+ int i;
+
+ for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
+ MonoMethod *cm = mono_defaults.object_class->methods [i];
+
+ if (!strcmp (cm->name, "FieldSetter")) {
+ setter = cm;
+ break;
+ }
+ }
+ g_assert (setter);
+ }
+
+ field_class = mono_class_from_mono_type (field->type);
+
+ if (field_class->valuetype)
+ arg = mono_value_box (domain, field_class, val);
+ else
+ arg = *((MonoObject **)val);
+
+
+ msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
+ mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
+
+ mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
+ mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
+ mono_array_set (msg->args, gpointer, 2, arg);
+
+ mono_remoting_invoke ((MonoObject *)((MonoTransparentProxy *)this)->rp, msg, &exc, &out_args);
+}