2 * object.c: Object creation for the Mono runtime
5 * Miguel de Icaza (miguel@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
8 * (C) 2001-2004 Ximian, Inc.
15 #include <mono/metadata/mono-endian.h>
16 #include <mono/metadata/tabledefs.h>
17 #include <mono/metadata/tokentype.h>
18 #include <mono/metadata/loader.h>
19 #include <mono/metadata/object.h>
20 #include <mono/metadata/gc-internal.h>
21 #include <mono/metadata/exception.h>
22 #include <mono/metadata/domain-internals.h>
23 #include "mono/metadata/metadata-internals.h"
24 #include "mono/metadata/class-internals.h"
25 #include <mono/metadata/assembly.h>
26 #include <mono/metadata/threadpool.h>
27 #include <mono/metadata/marshal.h>
28 #include "mono/metadata/debug-helpers.h"
29 #include "mono/metadata/marshal.h"
30 #include <mono/metadata/threads.h>
31 #include <mono/metadata/threads-types.h>
32 #include <mono/metadata/environment.h>
33 #include "mono/metadata/profiler-private.h"
34 #include <mono/os/gc_wrapper.h>
35 #include <mono/utils/strenc.h>
38 * Enable experimental typed allocation using the GC_gcj_malloc function.
40 #ifdef HAVE_GC_GCJ_MALLOC
41 #define CREATION_SPEEDUP 1
45 mono_runtime_object_init (MonoObject *this)
48 MonoMethod *method = NULL;
49 MonoClass *klass = this->vtable->klass;
51 for (i = 0; i < klass->method.count; ++i) {
52 if (!strcmp (".ctor", klass->methods [i]->name) &&
53 klass->methods [i]->signature->param_count == 0) {
54 method = klass->methods [i];
61 if (method->klass->valuetype)
62 this = mono_object_unbox (this);
63 mono_runtime_invoke (method, this, NULL, NULL);
66 /* The pseudo algorithm for type initialization from the spec
67 Note it doesn't say anything about domains - only threads.
69 2. If the type is initialized you are done.
70 2.1. If the type is not yet initialized, try to take an
72 2.2. If successful, record this thread as responsible for
73 initializing the type and proceed to step 2.3.
74 2.2.1. If not, see whether this thread or any thread
75 waiting for this thread to complete already holds the lock.
76 2.2.2. If so, return since blocking would create a deadlock. This thread
77 will now see an incompletely initialized state for the type,
78 but no deadlock will arise.
79 2.2.3 If not, block until the type is initialized then return.
80 2.3 Initialize the parent type and then all interfaces implemented
82 2.4 Execute the type initialization code for this type.
83 2.5 Mark the type as initialized, release the initialization lock,
84 awaken any threads waiting for this type to be initialized,
91 guint32 initializing_tid;
92 guint32 waiting_count;
93 CRITICAL_SECTION initialization_section;
94 } TypeInitializationLock;
96 /* for locking access to type_initialization_hash and blocked_thread_hash */
97 static CRITICAL_SECTION type_initialization_section;
99 /* from vtable to lock */
100 static GHashTable *type_initialization_hash;
102 /* from thread id to thread id being waited on */
103 static GHashTable *blocked_thread_hash;
106 static MonoThread *main_thread;
109 mono_type_initialization_init (void)
111 InitializeCriticalSection (&type_initialization_section);
112 type_initialization_hash = g_hash_table_new (NULL, NULL);
113 blocked_thread_hash = g_hash_table_new (NULL, NULL);
117 * mono_runtime_class_init:
118 * @vtable: vtable that needs to be initialized
120 * This routine calls the class constructor for @vtable.
123 mono_runtime_class_init (MonoVTable *vtable)
127 MonoException *exc_to_throw;
128 MonoMethod *method = NULL;
135 if (vtable->initialized)
140 klass = vtable->klass;
142 for (i = 0; i < klass->method.count; ++i) {
143 method = klass->methods [i];
144 if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) &&
145 (strcmp (".cctor", method->name) == 0)) {
152 MonoDomain *domain = vtable->domain;
153 TypeInitializationLock *lock;
154 guint32 tid = GetCurrentThreadId();
155 int do_initialization = 0;
156 MonoDomain *last_domain = NULL;
158 EnterCriticalSection (&type_initialization_section);
159 /* double check... */
160 if (vtable->initialized) {
161 LeaveCriticalSection (&type_initialization_section);
164 lock = g_hash_table_lookup (type_initialization_hash, vtable);
166 /* This thread will get to do the initialization */
167 if (mono_domain_get () != domain) {
168 /* Transfer into the target domain */
169 last_domain = mono_domain_get ();
170 if (!mono_domain_set (domain, FALSE)) {
171 vtable->initialized = 1;
172 LeaveCriticalSection (&type_initialization_section);
173 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
176 lock = g_malloc (sizeof(TypeInitializationLock));
177 InitializeCriticalSection (&lock->initialization_section);
178 lock->initializing_tid = tid;
179 lock->waiting_count = 1;
180 /* grab the vtable lock while this thread still owns type_initialization_section */
181 EnterCriticalSection (&lock->initialization_section);
182 g_hash_table_insert (type_initialization_hash, vtable, lock);
183 do_initialization = 1;
187 if (lock->initializing_tid == tid) {
188 LeaveCriticalSection (&type_initialization_section);
191 /* see if the thread doing the initialization is already blocked on this thread */
192 blocked = GUINT_TO_POINTER (lock->initializing_tid);
193 while ((blocked = g_hash_table_lookup (blocked_thread_hash, blocked))) {
194 if (blocked == GUINT_TO_POINTER (tid)) {
195 LeaveCriticalSection (&type_initialization_section);
199 ++lock->waiting_count;
200 /* record the fact that we are waiting on the initializing thread */
201 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), GUINT_TO_POINTER (lock->initializing_tid));
203 LeaveCriticalSection (&type_initialization_section);
205 if (do_initialization) {
206 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
208 mono_domain_set (last_domain, TRUE);
209 LeaveCriticalSection (&lock->initialization_section);
211 /* this just blocks until the initializing thread is done */
212 EnterCriticalSection (&lock->initialization_section);
213 LeaveCriticalSection (&lock->initialization_section);
216 EnterCriticalSection (&type_initialization_section);
217 if (lock->initializing_tid != tid)
218 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
219 --lock->waiting_count;
220 if (lock->waiting_count == 0) {
221 DeleteCriticalSection (&lock->initialization_section);
222 g_hash_table_remove (type_initialization_hash, vtable);
225 vtable->initialized = 1;
226 /* FIXME: if the cctor fails, the type must be marked as unusable */
227 LeaveCriticalSection (&type_initialization_section);
229 vtable->initialized = 1;
234 (klass->image == mono_defaults.corlib &&
235 !strcmp (klass->name_space, "System") &&
236 !strcmp (klass->name, "TypeInitializationException")))
237 return; /* No static constructor found or avoid infinite loop */
239 if (klass->name_space && *klass->name_space)
240 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
242 full_name = g_strdup (klass->name);
244 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
247 mono_raise_exception (exc_to_throw);
251 default_trampoline (MonoMethod *method)
257 default_remoting_trampoline (MonoMethod *method)
259 g_error ("remoting not installed");
263 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
264 static MonoTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
267 mono_install_trampoline (MonoTrampoline func)
269 arch_create_jit_trampoline = func? func: default_trampoline;
273 mono_install_remoting_trampoline (MonoTrampoline func)
275 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
278 static MonoCompileFunc default_mono_compile_method = NULL;
281 mono_install_compile_method (MonoCompileFunc func)
283 default_mono_compile_method = func;
287 mono_compile_method (MonoMethod *method)
289 if (!default_mono_compile_method) {
290 g_error ("compile method called on uninitialized runtime");
293 return default_mono_compile_method (method);
297 #if 0 && HAVE_BOEHM_GC
299 vtable_finalizer (void *obj, void *data) {
300 g_print ("%s finalized (%p)\n", (char*)data, obj);
306 #define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
309 * The vtables in the root appdomain are assumed to be reachable by other
310 * roots, and we don't use typed allocation in the other domains.
313 #define GC_HEADER_BITMAP (1 << (G_STRUCT_OFFSET (MonoObject,synchronisation) / sizeof(gpointer)))
316 mono_class_compute_gc_descriptor (MonoClass *class)
318 MonoClassField *field;
322 static gboolean gcj_inited = FALSE;
327 GC_init_gcj_malloc (5, NULL);
331 mono_class_init (class);
333 if (class->gc_descr_inited)
336 class->gc_descr_inited = TRUE;
337 class->gc_descr = GC_NO_DESCRIPTOR;
339 if (class == mono_defaults.string_class) {
340 bitmap = GC_HEADER_BITMAP;
341 class->gc_descr = (gpointer)GC_make_descriptor ((GC_bitmap)&bitmap, 2);
343 else if (class->rank) {
344 mono_class_compute_gc_descriptor (class->element_class);
346 if (class->element_class->valuetype && (class->element_class->gc_descr != GC_NO_DESCRIPTOR) && (class->element_class->gc_bitmap == GC_HEADER_BITMAP)) {
347 bitmap = GC_HEADER_BITMAP;
349 bitmap += 1 << (G_STRUCT_OFFSET (MonoArray,bounds) / sizeof(gpointer));
350 class->gc_descr = (gpointer)GC_make_descriptor ((GC_bitmap)&bitmap, 3);
354 static int count = 0;
358 /* GC 6.1 has trouble handling 64 bit descriptors... */
359 if ((class->instance_size / sizeof (gpointer)) > 30) {
360 /* printf ("TOO LARGE: %s %d.\n", class->name, class->instance_size / sizeof (gpointer)); */
364 bitmap = GC_HEADER_BITMAP;
368 /* if (count > 442) */
371 /* printf("KLASS: %s.\n", class->name); */
373 for (p = class; p != NULL; p = p->parent) {
374 for (i = 0; i < p->field.count; ++i) {
375 field = &p->fields [i];
376 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
378 if (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)
381 pos = field->offset / sizeof (gpointer);
383 if (field->type->byref)
386 switch (field->type->type) {
387 case MONO_TYPE_BOOLEAN:
399 /* printf ("F: %s %s %d %lld %llx.\n", class->name, field->name, field->offset, ((guint64)1) << pos, bitmap); */
402 case MONO_TYPE_STRING:
403 case MONO_TYPE_SZARRAY:
404 case MONO_TYPE_CLASS:
405 case MONO_TYPE_OBJECT:
406 case MONO_TYPE_ARRAY:
408 g_assert ((field->offset % sizeof(gpointer)) == 0);
410 bitmap |= ((guint64)1) << pos;
411 /* printf ("F: %s %s %d %d %lld %llx.\n", class->name, field->name, field->offset, pos, ((guint64)(1)) << pos, bitmap); */
413 case MONO_TYPE_VALUETYPE: {
414 MonoClass *fclass = field->type->data.klass;
415 if (!fclass->enumtype) {
416 mono_class_compute_gc_descriptor (fclass);
417 bitmap |= (fclass->gc_bitmap >> (sizeof (MonoObject) / sizeof (gpointer))) << pos;
427 /* printf("CLASS: %s.%s -> %d %llx.\n", class->name_space, class->name, class->instance_size / sizeof (gpointer), bitmap); */
428 class->gc_bitmap = bitmap;
429 /* Convert to the format expected by GC_make_descriptor */
430 bm [0] = (guint32)bitmap;
431 bm [1] = (guint32)(bitmap >> 32);
432 class->gc_descr = (gpointer)GC_make_descriptor ((GC_bitmap)&bm, class->instance_size / sizeof (gpointer));
435 #endif /* CREATION_SPEEDUP */
438 * field_is_special_static:
440 * Returns SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
441 * SPECIAL_STATIC_NONE otherwise.
444 field_is_special_static (MonoClass *fklass, MonoClassField *field)
446 MonoCustomAttrInfo *ainfo;
448 ainfo = mono_custom_attrs_from_field (fklass, field);
451 for (i = 0; i < ainfo->num_attrs; ++i) {
452 MonoClass *klass = ainfo->attrs [i].ctor->klass;
453 if (klass->image == mono_defaults.corlib) {
454 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
455 mono_custom_attrs_free (ainfo);
456 return SPECIAL_STATIC_THREAD;
458 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
459 mono_custom_attrs_free (ainfo);
460 return SPECIAL_STATIC_CONTEXT;
464 mono_custom_attrs_free (ainfo);
465 return SPECIAL_STATIC_NONE;
470 * @domain: the application domain
471 * @class: the class to initialize
473 * VTables are domain specific because we create domain specific code, and
474 * they contain the domain specific static class data.
477 mono_class_vtable (MonoDomain *domain, MonoClass *class)
479 MonoVTable *vt = NULL;
480 MonoClassField *field;
486 guint32 constant_cols [MONO_CONSTANT_SIZE];
490 vt = class->cached_vtable;
491 if (vt && vt->domain == domain)
494 mono_domain_lock (domain);
495 if ((vt = mono_g_hash_table_lookup (domain->class_vtable_hash, class))) {
496 mono_domain_unlock (domain);
501 mono_class_init (class);
503 mono_stats.used_class_count++;
504 mono_stats.class_vtable_size += sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
506 vtable_size = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
508 vt = mono_mempool_alloc0 (domain->mp, vtable_size);
514 mono_class_compute_gc_descriptor (class);
515 if (domain != mono_get_root_domain ())
517 * We can't use typed allocation in the non-root domains, since the
518 * collector needs the GC descriptor stored in the vtable even after
519 * the mempool containing the vtable is destroyed when the domain is
520 * unloaded. An alternative might be to allocate vtables in the GC
521 * heap, but this does not seem to work (it leads to crashes inside
522 * libgc). If that approach is tried, two gc descriptors need to be
523 * allocated for each class: one for the root domain, and one for all
524 * other domains. The second descriptor should contain a bit for the
525 * vtable field in MonoObject, since we can no longer assume the
526 * vtable is reachable by other roots after the appdomain is unloaded.
528 vt->gc_descr = GC_NO_DESCRIPTOR;
530 vt->gc_descr = class->gc_descr;
533 if (class->class_size) {
535 vt->data = GC_MALLOC (class->class_size + 8);
536 /*vt->data = GC_debug_malloc (class->class_size + 8, class->name, 2);*/
537 /*GC_register_finalizer (vt->data, vtable_finalizer, class->name, NULL, NULL);*/
538 mono_g_hash_table_insert (domain->static_data_hash, class, vt->data);
540 vt->data = mono_mempool_alloc0 (domain->mp, class->class_size + 8);
543 mono_stats.class_static_data_size += class->class_size + 8;
547 for (i = class->field.first; i < class->field.last; ++i) {
548 field = &class->fields [i - class->field.first];
549 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
551 if (mono_field_is_deleted (field))
553 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
554 gint32 special_static = field_is_special_static (class, field);
555 if (special_static != SPECIAL_STATIC_NONE) {
556 guint32 size, align, offset;
557 size = mono_type_size (field->type, &align);
558 offset = mono_alloc_special_static_data (special_static, size, align);
559 if (!domain->special_static_fields)
560 domain->special_static_fields = g_hash_table_new (NULL, NULL);
561 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
565 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
566 MonoClass *fklass = mono_class_from_mono_type (field->type);
567 t = (char*)vt->data + field->offset;
568 if (fklass->valuetype) {
569 memcpy (t, field->data, mono_class_value_size (fklass, NULL));
571 /* it's a pointer type: add check */
572 g_assert (fklass->byval_arg.type == MONO_TYPE_PTR);
573 *t = *(char *)field->data;
577 if (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT))
580 if (!field->def_value) {
581 cindex = mono_metadata_get_constant_index (class->image, MONO_TOKEN_FIELD_DEF | (i + 1), cindex + 1);
584 mono_metadata_decode_row (&class->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
585 field->def_value = g_new0 (MonoConstant, 1);
586 field->def_value->type = constant_cols [MONO_CONSTANT_TYPE];
587 field->def_value->value = (gpointer)mono_metadata_blob_heap (class->image, constant_cols [MONO_CONSTANT_VALUE]);
590 p = field->def_value->value;
591 len = mono_metadata_decode_blob_size (p, &p);
592 t = (char*)vt->data + field->offset;
593 /* should we check that the type matches? */
594 switch (field->def_value->type) {
595 case MONO_TYPE_BOOLEAN:
603 guint16 *val = (guint16*)t;
609 guint32 *val = (guint32*)t;
615 guint64 *val = (guint64*)t;
620 float *val = (float*)t;
625 double *val = (double*)t;
629 case MONO_TYPE_STRING: {
630 gpointer *val = (gpointer*)t;
631 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
632 gunichar2 *copy = g_malloc (len);
634 for (j = 0; j < len/2; j++) {
635 copy [j] = read16 (p);
638 *val = mono_string_new_utf16 (domain, copy, len/2);
641 *val = mono_string_new_utf16 (domain, (const guint16*)p, len/2);
645 case MONO_TYPE_CLASS:
646 /* nothing to do, we malloc0 the data and the value can be 0 only */
649 g_warning ("type 0x%02x should not be in constant table", field->def_value->type);
653 vt->max_interface_id = class->max_interface_id;
655 vt->interface_offsets = mono_mempool_alloc0 (domain->mp,
656 sizeof (gpointer) * (class->max_interface_id + 1));
658 /* initialize interface offsets */
659 for (i = 0; i <= class->max_interface_id; ++i) {
660 int slot = class->interface_offsets [i];
662 vt->interface_offsets [i] = &(vt->vtable [slot]);
666 * arch_create_jit_trampoline () can recursively call this function again
667 * because it compiles icall methods right away.
669 mono_g_hash_table_insert (domain->class_vtable_hash, class, vt);
670 if (!class->cached_vtable)
671 class->cached_vtable = vt;
673 /* initialize vtable */
674 for (i = 0; i < class->vtable_size; ++i) {
677 if ((cm = class->vtable [i]))
678 vt->vtable [i] = arch_create_jit_trampoline (cm);
681 mono_domain_unlock (domain);
683 /* make sure the the parent is initialized */
685 mono_class_vtable (domain, class->parent);
687 vt->type = mono_type_get_object (domain, &class->byval_arg);
688 if (class->contextbound)
697 * mono_class_proxy_vtable:
698 * @domain: the application domain
699 * @remove_class: the remote class
701 * Creates a vtable for transparent proxies. It is basically
702 * a copy of the real vtable of the class wrapped in @remote_class,
703 * but all function pointers invoke the remoting functions, and
704 * vtable->klass points to the transparent proxy class, and not to @class.
707 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class)
709 MonoVTable *vt, *pvt;
710 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
712 MonoClass *class = remote_class->proxy_class;
714 vt = mono_class_vtable (domain, class);
715 max_interface_id = vt->max_interface_id;
717 /* Calculate vtable space for extra interfaces */
718 for (j = 0; j < remote_class->interface_count; j++) {
719 MonoClass* iclass = remote_class->interfaces[j];
720 int method_count = iclass->method.count;
722 if (iclass->interface_id <= class->max_interface_id && class->interface_offsets[iclass->interface_id] != 0)
723 continue; /* interface implemented by the class */
725 for (i = 0; i < iclass->interface_count; i++)
726 method_count += iclass->interfaces[i]->method.count;
728 extra_interface_vtsize += method_count * sizeof (gpointer);
729 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
732 vtsize = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
734 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
736 pvt = mono_mempool_alloc (domain->mp, vtsize + extra_interface_vtsize);
737 memcpy (pvt, vt, vtsize);
739 pvt->klass = mono_defaults.transparent_proxy_class;
741 /* initialize vtable */
742 for (i = 0; i < class->vtable_size; ++i) {
745 if ((cm = class->vtable [i]))
746 pvt->vtable [i] = arch_create_remoting_trampoline (cm);
749 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT)
751 /* create trampolines for abstract methods */
752 for (k = class; k; k = k->parent) {
753 for (i = 0; i < k->method.count; i++) {
754 int slot = k->methods [i]->slot;
755 if (!pvt->vtable [slot])
756 pvt->vtable [slot] = arch_create_remoting_trampoline (k->methods[i]);
761 pvt->max_interface_id = max_interface_id;
762 pvt->interface_offsets = mono_mempool_alloc0 (domain->mp,
763 sizeof (gpointer) * (max_interface_id + 1));
765 /* initialize interface offsets */
766 for (i = 0; i <= class->max_interface_id; ++i) {
767 int slot = class->interface_offsets [i];
769 pvt->interface_offsets [i] = &(pvt->vtable [slot]);
772 if (remote_class->interface_count > 0)
774 int slot = class->vtable_size;
779 /* Create trampolines for the methods of the interfaces */
780 for (n = 0; n < remote_class->interface_count; n++)
782 iclass = remote_class->interfaces[n];
783 if (iclass->interface_id <= class->max_interface_id && class->interface_offsets[iclass->interface_id] != 0)
784 continue; /* interface implemented by the class */
789 pvt->interface_offsets [interf->interface_id] = &pvt->vtable [slot];
791 for (j = 0; j < interf->method.count; ++j) {
792 MonoMethod *cm = interf->methods [j];
793 pvt->vtable [slot + j] = arch_create_remoting_trampoline (cm);
795 slot += interf->method.count;
796 if (++i < iclass->interface_count) interf = iclass->interfaces[i];
808 * @domain: the application domain
809 * @class_name: name of the remote class
811 * Creates and initializes a MonoRemoteClass object for a remote type.
815 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
819 mono_domain_lock (domain);
820 rc = mono_g_hash_table_lookup (domain->proxy_vtable_hash, class_name);
823 mono_domain_unlock (domain);
827 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass));
829 rc->interface_count = 0;
830 rc->interfaces = NULL;
831 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
832 rc->proxy_class_name = mono_string_to_utf8 (class_name);
834 mono_g_hash_table_insert (domain->proxy_vtable_hash, class_name, rc);
835 mono_upgrade_remote_class (domain, rc, proxy_class);
837 if (rc->vtable == NULL)
838 rc->vtable = mono_class_proxy_vtable (domain, rc);
840 mono_domain_unlock (domain);
846 extend_interface_array (MonoDomain *domain, MonoRemoteClass *remote_class, int amount)
848 /* Extends the array of interfaces. Memory is extended using blocks of 5 pointers */
850 int current_size = ((remote_class->interface_count / 5) + 1) * 5;
851 remote_class->interface_count += amount;
853 if (remote_class->interface_count > current_size || remote_class->interfaces == NULL)
855 int new_size = ((remote_class->interface_count / 5) + 1) * 5;
856 MonoClass **new_array = mono_mempool_alloc (domain->mp, new_size * sizeof (MonoClass*));
858 if (remote_class->interfaces != NULL)
859 memcpy (new_array, remote_class->interfaces, current_size * sizeof (MonoClass*));
861 remote_class->interfaces = new_array;
867 * mono_upgrade_remote_class:
868 * @domain: the application domain
869 * @remote_class: the remote class
870 * @klass: class to which the remote class can be casted.
872 * Updates the vtable of the remote class by adding the necessary method slots
873 * and interface offsets so it can be safely casted to klass. klass can be a
874 * class or an interface.
876 void mono_upgrade_remote_class (MonoDomain *domain, MonoRemoteClass *remote_class, MonoClass *klass)
878 gboolean redo_vtable;
880 mono_domain_lock (domain);
882 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
885 for (i = 0; i < remote_class->interface_count; i++)
886 if (remote_class->interfaces[i] == klass) redo_vtable = FALSE;
889 extend_interface_array (domain, remote_class, 1);
890 remote_class->interfaces [remote_class->interface_count-1] = klass;
894 redo_vtable = (remote_class->proxy_class != klass);
895 remote_class->proxy_class = klass;
899 remote_class->vtable = mono_class_proxy_vtable (domain, remote_class);
902 printf ("remote class upgrade - class:%s num-interfaces:%d\n", remote_class->proxy_class_name, remote_class->interface_count);
904 for (n=0; n<remote_class->interface_count; n++)
905 printf (" I:%s\n", remote_class->interfaces[n]->name);
908 mono_domain_unlock (domain);
912 * mono_object_get_virtual_method:
914 * Retrieve the MonoMethod that would be called on obj if obj is passed as
915 * the instance of a callvirt of method.
918 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method) {
922 MonoMethod *res = NULL;
924 klass = mono_object_class (obj);
925 if (klass == mono_defaults.transparent_proxy_class) {
926 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
932 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
935 vtable = klass->vtable;
937 /* check method->slot is a valid index: perform isinstance? */
938 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
940 res = vtable [klass->interface_offsets [method->klass->interface_id] + method->slot];
942 if (method->slot != -1)
943 res = vtable [method->slot];
947 if (!res) res = method; /* It may be an interface or abstract class method */
948 res = mono_marshal_get_remoting_invoke (res);
957 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
959 g_error ("runtime invoke called on uninitialized runtime");
963 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
966 * mono_runtime_invoke:
968 * Invokes the method represented by `method' on the object `obj'.
970 * obj is the 'this' pointer, it should be NULL for static
971 * methods, a MonoObject* for object instances and a pointer to
972 * the value type for value types.
974 * The params array contains the arguments to the method with the
975 * same convention: MonoObject* pointers for object instances and
976 * pointers to the value type otherwise.
978 * From unmanaged code you'll usually use the
979 * mono_runtime_invoke() variant.
981 * Note that this function doesn't handle virtual methods for
982 * you, it will exec the exact method you pass: we still need to
983 * expose a function to lookup the derived class implementation
984 * of a virtual method (there are examples of this in the code,
987 * You can pass NULL as the exc argument if you don't want to
988 * catch exceptions, otherwise, *exc will be set to the exception
989 * thrown, if any. if an exception is thrown, you can't use the
990 * MonoObject* result from the function.
992 * If the method returns a value type, it is boxed in an object
996 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
998 return default_mono_runtime_invoke (method, obj, params, exc);
1002 set_value (MonoType *type, void *dest, void *value, int deref_pointer) {
1005 gpointer *p = (gpointer*)dest;
1012 case MONO_TYPE_BOOLEAN:
1014 case MONO_TYPE_U1: {
1015 guint8 *p = (guint8*)dest;
1016 *p = *(guint8*)value;
1021 case MONO_TYPE_CHAR: {
1022 guint16 *p = (guint16*)dest;
1023 *p = *(guint16*)value;
1026 #if SIZEOF_VOID_P == 4
1031 case MONO_TYPE_U4: {
1032 gint32 *p = (gint32*)dest;
1033 *p = *(gint32*)value;
1036 #if SIZEOF_VOID_P == 8
1041 case MONO_TYPE_U8: {
1042 gint64 *p = (gint64*)dest;
1043 *p = *(gint64*)value;
1046 case MONO_TYPE_R4: {
1047 float *p = (float*)dest;
1048 *p = *(float*)value;
1051 case MONO_TYPE_R8: {
1052 double *p = (double*)dest;
1053 *p = *(double*)value;
1056 case MONO_TYPE_STRING:
1057 case MONO_TYPE_SZARRAY:
1058 case MONO_TYPE_CLASS:
1059 case MONO_TYPE_OBJECT:
1060 case MONO_TYPE_ARRAY:
1061 case MONO_TYPE_PTR: {
1062 gpointer *p = (gpointer*)dest;
1063 *p = deref_pointer? *(gpointer*)value: value;
1066 case MONO_TYPE_VALUETYPE:
1067 if (type->data.klass->enumtype) {
1068 t = type->data.klass->enum_basetype->type;
1072 size = mono_class_value_size (type->data.klass, NULL);
1073 memcpy (dest, value, size);
1077 g_warning ("got type %x", type->type);
1078 g_assert_not_reached ();
1083 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
1087 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
1089 dest = (char*)obj + field->offset;
1090 set_value (field->type, dest, value, FALSE);
1094 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
1098 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
1100 dest = (char*)vt->data + field->offset;
1101 set_value (field->type, dest, value, FALSE);
1105 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
1109 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
1111 src = (char*)obj + field->offset;
1112 set_value (field->type, value, src, TRUE);
1116 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
1120 MonoVTable *vtable = NULL;
1122 gboolean is_static = FALSE;
1123 gboolean is_ref = FALSE;
1125 switch (field->type->type) {
1126 case MONO_TYPE_STRING:
1127 case MONO_TYPE_OBJECT:
1128 case MONO_TYPE_CLASS:
1129 case MONO_TYPE_ARRAY:
1130 case MONO_TYPE_SZARRAY:
1135 case MONO_TYPE_BOOLEAN:
1138 case MONO_TYPE_CHAR:
1147 case MONO_TYPE_VALUETYPE:
1148 is_ref = field->type->byref;
1151 g_error ("type 0x%x not handled in "
1152 "mono_field_get_value_object", field->type->type);
1156 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
1158 vtable = mono_class_vtable (domain, field->parent);
1159 if (!vtable->initialized)
1160 mono_runtime_class_init (vtable);
1165 mono_field_static_get_value (vtable, field, &o);
1167 mono_field_get_value (obj, field, &o);
1172 /* boxed value type */
1173 klass = mono_class_from_mono_type (field->type);
1174 o = mono_object_new (domain, klass);
1175 v = ((gchar *) o) + sizeof (MonoObject);
1177 mono_field_static_get_value (vtable, field, v);
1179 mono_field_get_value (obj, field, v);
1187 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
1191 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
1193 src = (char*)vt->data + field->offset;
1194 set_value (field->type, value, src, TRUE);
1198 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
1200 default_mono_runtime_invoke (prop->set, obj, params, exc);
1204 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
1206 return default_mono_runtime_invoke (prop->get, obj, params, exc);
1211 mono_get_delegate_invoke (MonoClass *klass)
1218 for (i = 0; i < klass->method.count; ++i) {
1219 if (klass->methods [i]->name[0] == 'I' &&
1220 !strcmp ("Invoke", klass->methods [i]->name)) {
1221 im = klass->methods [i];
1231 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
1235 im = mono_get_delegate_invoke (delegate->vtable->klass);
1238 return mono_runtime_invoke (im, delegate, params, exc);
1241 static MonoArray* main_args;
1244 mono_runtime_get_main_args (void)
1250 fire_process_exit_event (void)
1252 MonoClassField *field;
1253 MonoDomain *domain = mono_domain_get ();
1255 MonoObject *delegate, *exc;
1257 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
1260 if (domain != mono_get_root_domain ())
1263 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
1264 if (delegate == NULL)
1269 mono_runtime_delegate_invoke (delegate, pa, &exc);
1273 * Execute a standard Main() method (argc/argv contains the
1274 * executable name). This method also sets the command line argument value
1275 * needed by System.Environment.
1278 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
1282 MonoArray *args = NULL;
1283 MonoDomain *domain = mono_domain_get ();
1284 gchar *utf8_fullpath;
1287 main_thread = mono_thread_current ();
1289 main_args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
1291 if (!g_path_is_absolute (argv [0])) {
1292 gchar *basename = g_path_get_basename (argv [0]);
1293 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
1297 utf8_fullpath = mono_utf8_from_external (fullpath);
1298 if(utf8_fullpath == NULL) {
1299 /* Printing the arg text will cause glib to
1300 * whinge about "Invalid UTF-8", but at least
1301 * its relevant, and shows the problem text
1304 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
1305 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
1312 utf8_fullpath = mono_utf8_from_external (argv[0]);
1313 if(utf8_fullpath == NULL) {
1314 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
1315 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
1320 mono_array_set (main_args, gpointer, 0, mono_string_new (domain, utf8_fullpath));
1321 g_free (utf8_fullpath);
1323 for (i = 1; i < argc; ++i) {
1327 utf8_arg=mono_utf8_from_external (argv[i]);
1328 if(utf8_arg==NULL) {
1329 /* Ditto the comment about Invalid UTF-8 here */
1330 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
1331 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
1335 arg = mono_string_new (domain, utf8_arg);
1336 mono_array_set (main_args, gpointer, i, arg);
1340 if (method->signature->param_count) {
1341 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
1342 for (i = 0; i < argc; ++i) {
1343 /* The encodings should all work, given that
1344 * we've checked all these args for the
1347 MonoString *arg = mono_string_new (domain, mono_utf8_from_external (argv [i]));
1348 mono_array_set (args, gpointer, i, arg);
1351 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
1354 mono_assembly_set_main (method->klass->image->assembly);
1356 result = mono_runtime_exec_main (method, args, exc);
1357 fire_process_exit_event ();
1361 /* Used in mono_unhandled_exception */
1363 create_unhandled_exception_eventargs (MonoObject *exc)
1367 MonoMethod *method = NULL;
1368 MonoBoolean is_terminating = TRUE;
1372 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
1375 mono_class_init (klass);
1377 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
1378 for (i = 0; i < klass->method.count; ++i) {
1379 method = klass->methods [i];
1380 if (!strcmp (".ctor", method->name) &&
1381 method->signature->param_count == 2 &&
1382 method->flags & METHOD_ATTRIBUTE_PUBLIC)
1390 args [1] = &is_terminating;
1392 obj = mono_object_new (mono_domain_get (), klass);
1393 mono_runtime_invoke (method, obj, args, NULL);
1399 * We call this function when we detect an unhandled exception
1400 * in the default domain.
1401 * It invokes the * UnhandledException event in AppDomain or prints
1402 * a warning to the console
1405 mono_unhandled_exception (MonoObject *exc)
1407 MonoDomain *domain = mono_domain_get ();
1408 MonoClassField *field;
1409 MonoObject *delegate;
1411 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
1412 "UnhandledException");
1415 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
1416 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
1418 /* set exitcode only in the main thread */
1419 if (mono_thread_current () == main_thread)
1420 mono_environment_exitcode_set (1);
1421 if (domain != mono_get_root_domain () || !delegate) {
1422 mono_print_unhandled_exception (exc);
1424 MonoObject *e = NULL;
1427 pa [0] = domain->domain;
1428 pa [1] = create_unhandled_exception_eventargs (exc);
1429 mono_runtime_delegate_invoke (delegate, pa, &e);
1432 gchar *msg = mono_string_to_utf8 (((MonoException *) e)->message);
1433 g_warning ("exception inside UnhandledException handler: %s\n", msg);
1441 * Launch a new thread to start all setup that requires managed code
1444 * main_func is called back from the thread with main_args as the
1445 * parameter. The callback function is expected to start Main()
1446 * eventually. This function then waits for all managed threads to
1450 mono_runtime_exec_managed_code (MonoDomain *domain,
1451 MonoMainThreadFunc main_func,
1454 mono_thread_create (domain, main_func, main_args);
1456 mono_thread_manage ();
1460 * Execute a standard Main() method (args doesn't contain the
1464 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
1474 domain = mono_object_domain (args);
1475 if (!domain->entry_assembly) {
1477 gchar *config_suffix;
1478 MonoAssembly *assembly;
1480 assembly = method->klass->image->assembly;
1481 domain->entry_assembly = assembly;
1482 domain->setup->application_base = mono_string_new (domain, assembly->basedir);
1484 config_suffix = g_strconcat (assembly->aname.name, ".exe.config", NULL);
1485 str = g_build_filename (assembly->basedir, config_suffix, NULL);
1486 g_free (config_suffix);
1487 domain->setup->configuration_file = mono_string_new (domain, str);
1491 /* FIXME: check signature of method */
1492 if (method->signature->ret->type == MONO_TYPE_I4) {
1494 res = mono_runtime_invoke (method, NULL, pa, exc);
1496 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
1500 mono_environment_exitcode_set (rval);
1502 mono_runtime_invoke (method, NULL, pa, exc);
1506 /* If the return type of Main is void, only
1507 * set the exitcode if an exception was thrown
1508 * (we don't want to blow away an
1509 * explicitly-set exit code)
1512 mono_environment_exitcode_set (rval);
1520 mono_install_runtime_invoke (MonoInvokeFunc func)
1522 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
1526 * mono_runtime_invoke:
1528 * Invokes the method represented by `method' on the object `obj'.
1530 * obj is the 'this' pointer, it should be NULL for static
1531 * methods, a MonoObject* for object instances and a pointer to
1532 * the value type for value types.
1534 * The params array contains the arguments to the method with the
1535 * same convention: MonoObject* pointers for object instances and
1536 * pointers to the value type otherwise. The _invoke_array
1537 * variant takes a C# object[] as the params argument (MonoArray
1538 * *params): in this case the value types are boxed inside the
1539 * respective reference representation.
1541 * From unmanaged code you'll usually use the
1542 * mono_runtime_invoke() variant.
1544 * Note that this function doesn't handle virtual methods for
1545 * you, it will exec the exact method you pass: we still need to
1546 * expose a function to lookup the derived class implementation
1547 * of a virtual method (there are examples of this in the code,
1550 * You can pass NULL as the exc argument if you don't want to
1551 * catch exceptions, otherwise, *exc will be set to the exception
1552 * thrown, if any. if an exception is thrown, you can't use the
1553 * MonoObject* result from the function.
1555 * If the method returns a value type, it is boxed in an object
1559 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
1562 MonoMethodSignature *sig = method->signature;
1563 gpointer *pa = NULL;
1566 if (NULL != params) {
1567 pa = alloca (sizeof (gpointer) * mono_array_length (params));
1568 for (i = 0; i < mono_array_length (params); i++) {
1569 if (sig->params [i]->byref) {
1573 switch (sig->params [i]->type) {
1576 case MONO_TYPE_BOOLEAN:
1579 case MONO_TYPE_CHAR:
1588 case MONO_TYPE_VALUETYPE:
1589 /* MS seems to create the objects if a null is passed in */
1590 if (! ((gpointer *)params->vector)[i])
1591 ((gpointer*)params->vector)[i] = mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i]));
1592 pa [i] = (char *)(((gpointer *)params->vector)[i]) + sizeof (MonoObject);
1594 case MONO_TYPE_STRING:
1595 case MONO_TYPE_OBJECT:
1596 case MONO_TYPE_CLASS:
1597 case MONO_TYPE_ARRAY:
1598 case MONO_TYPE_SZARRAY:
1599 if (sig->params [i]->byref)
1600 pa [i] = &(((gpointer *)params->vector)[i]);
1602 pa [i] = (char *)(((gpointer *)params->vector)[i]);
1605 g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
1610 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
1613 obj = mono_object_new (mono_domain_get (), method->klass);
1614 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
1615 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
1617 if (method->klass->valuetype)
1618 o = mono_object_unbox (obj);
1622 mono_runtime_invoke (method, o, pa, exc);
1625 /* obj must be already unboxed if needed */
1626 return mono_runtime_invoke (method, obj, pa, exc);
1631 out_of_memory (size_t size)
1634 * we could allocate at program startup some memory that we could release
1635 * back to the system at this point if we're really low on memory (ie, size is
1636 * lower than the memory we set apart)
1638 mono_raise_exception (mono_domain_get ()->out_of_memory_ex);
1642 * mono_object_allocate:
1643 * @size: number of bytes to allocate
1645 * This is a very simplistic routine until we have our GC-aware
1648 * Returns: an allocated object of size @size, or NULL on failure.
1650 static inline void *
1651 mono_object_allocate (size_t size)
1654 /* if this is changed to GC_debug_malloc(), we need to change also metadata/gc.c */
1655 void *o = GC_MALLOC (size);
1657 void *o = calloc (1, size);
1659 mono_stats.new_object_count++;
1662 out_of_memory (size);
1666 #if CREATION_SPEEDUP
1667 static inline void *
1668 mono_object_allocate_spec (size_t size, void *gcdescr)
1670 /* if this is changed to GC_debug_malloc(), we need to change also metadata/gc.c */
1671 void *o = GC_GCJ_MALLOC (size, gcdescr);
1672 mono_stats.new_object_count++;
1675 out_of_memory (size);
1682 * @klass: the class of the object that we want to create
1684 * Returns a newly created object whose definition is
1685 * looked up using @klass. This will not invoke any constructors,
1686 * so the consumer of this routine has to invoke any constructors on
1687 * its own to initialize the object.
1690 mono_object_new (MonoDomain *domain, MonoClass *klass)
1692 MONO_ARCH_SAVE_REGS;
1693 return mono_object_new_specific (mono_class_vtable (domain, klass));
1697 * mono_object_new_specific:
1698 * @vtable: the vtable of the object that we want to create
1700 * Returns: A newly created object with class and domain specified
1704 mono_object_new_specific (MonoVTable *vtable)
1708 MONO_ARCH_SAVE_REGS;
1713 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
1716 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
1720 mono_class_init (klass);
1722 for (i = 0; i < klass->method.count; ++i) {
1723 if (!strcmp ("CreateProxyForType", klass->methods [i]->name) &&
1724 klass->methods [i]->signature->param_count == 1) {
1725 im = klass->methods [i];
1730 vtable->domain->create_proxy_for_type_method = im;
1733 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
1735 o = mono_runtime_invoke (im, NULL, pa, NULL);
1736 if (o != NULL) return o;
1739 return mono_object_new_alloc_specific (vtable);
1743 mono_object_new_fast (MonoVTable *vtable)
1746 MONO_ARCH_SAVE_REGS;
1748 #if CREATION_SPEEDUP
1749 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
1750 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
1752 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
1753 o = mono_object_allocate (vtable->klass->instance_size);
1757 o = mono_object_allocate (vtable->klass->instance_size);
1764 mono_object_new_alloc_specific (MonoVTable *vtable)
1768 #if CREATION_SPEEDUP
1769 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
1770 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
1772 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
1773 o = mono_object_allocate (vtable->klass->instance_size);
1777 o = mono_object_allocate (vtable->klass->instance_size);
1780 if (vtable->klass->has_finalize)
1781 mono_object_register_finalizer (o);
1783 mono_profiler_allocation (o, vtable->klass);
1788 * mono_object_new_from_token:
1789 * @image: Context where the type_token is hosted
1790 * @token: a token of the type that we want to create
1792 * Returns: A newly created object whose definition is
1793 * looked up using @token in the @image image
1796 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
1800 class = mono_class_get (image, token);
1802 return mono_object_new (domain, class);
1807 * mono_object_clone:
1808 * @obj: the object to clone
1810 * Returns: A newly created object who is a shallow copy of @obj
1813 mono_object_clone (MonoObject *obj)
1818 size = obj->vtable->klass->instance_size;
1819 o = mono_object_allocate (size);
1820 mono_profiler_allocation (o, obj->vtable->klass);
1822 memcpy (o, obj, size);
1824 if (obj->vtable->klass->has_finalize)
1825 mono_object_register_finalizer (o);
1831 * @array: the array to clone
1833 * Returns: A newly created array who is a shallow copy of @array
1836 mono_array_clone (MonoArray *array)
1841 MonoClass *klass = array->obj.vtable->klass;
1843 MONO_ARCH_SAVE_REGS;
1845 if (array->bounds == NULL) {
1846 size = mono_array_length (array);
1847 o = mono_array_new_full (((MonoObject *)array)->vtable->domain,
1848 klass, &size, NULL);
1850 size *= mono_array_element_size (klass);
1851 memcpy (o, array, sizeof (MonoArray) + size);
1856 sizes = alloca (klass->rank * sizeof(guint32) * 2);
1857 size = mono_array_element_size (klass);
1858 for (i = 0; i < klass->rank; ++i) {
1859 sizes [i] = array->bounds [i].length;
1860 size *= array->bounds [i].length;
1861 sizes [i + klass->rank] = array->bounds [i].lower_bound;
1863 o = mono_array_new_full (((MonoObject *)array)->vtable->domain,
1864 klass, sizes, sizes + klass->rank);
1865 memcpy (o, array, sizeof(MonoArray) + size);
1870 /* helper macros to check for overflow when calculating the size of arrays */
1871 #define MYGUINT32_MAX 4294967295U
1872 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1873 (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
1874 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1875 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1876 (guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a))
1879 * mono_array_new_full:
1880 * @domain: domain where the object is created
1881 * @array_class: array class
1882 * @lengths: lengths for each dimension in the array
1883 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
1885 * This routine creates a new array objects with the given dimensions,
1886 * lower bounds and type.
1889 mono_array_new_full (MonoDomain *domain, MonoClass *array_class,
1890 guint32 *lengths, guint32 *lower_bounds)
1892 guint32 byte_len, len;
1895 MonoArrayBounds *bounds;
1899 if (!array_class->inited)
1900 mono_class_init (array_class);
1902 byte_len = mono_array_element_size (array_class);
1905 if (array_class->rank == 1 &&
1906 (lower_bounds == NULL || lower_bounds [0] == 0)) {
1911 bounds = GC_MALLOC (sizeof (MonoArrayBounds) * array_class->rank);
1913 bounds = g_malloc0 (sizeof (MonoArrayBounds) * array_class->rank);
1915 for (i = 0; i < array_class->rank; ++i) {
1916 bounds [i].length = lengths [i];
1917 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
1918 out_of_memory (MYGUINT32_MAX);
1923 for (i = 0; i < array_class->rank; ++i)
1924 bounds [i].lower_bound = lower_bounds [i];
1927 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
1928 out_of_memory (MYGUINT32_MAX);
1930 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
1931 out_of_memory (MYGUINT32_MAX);
1932 byte_len += sizeof (MonoArray);
1934 * Following three lines almost taken from mono_object_new ():
1935 * they need to be kept in sync.
1937 vtable = mono_class_vtable (domain, array_class);
1938 #if CREATION_SPEEDUP
1939 if (vtable->gc_descr != GC_NO_DESCRIPTOR)
1940 o = mono_object_allocate_spec (byte_len, vtable);
1942 o = mono_object_allocate (byte_len);
1946 o = mono_object_allocate (byte_len);
1950 array = (MonoArray*)o;
1952 array->bounds = bounds;
1953 array->max_length = len;
1955 mono_profiler_allocation (o, array_class);
1962 * @domain: domain where the object is created
1963 * @eclass: element class
1964 * @n: number of array elements
1966 * This routine creates a new szarray with @n elements of type @eclass.
1969 mono_array_new (MonoDomain *domain, MonoClass *eclass, guint32 n)
1973 MONO_ARCH_SAVE_REGS;
1975 ac = mono_array_class_get (eclass, 1);
1976 g_assert (ac != NULL);
1978 return mono_array_new_specific (mono_class_vtable (domain, ac), n);
1982 * mono_array_new_specific:
1983 * @vtable: a vtable in the appropriate domain for an initialized class
1984 * @n: number of array elements
1986 * This routine is a fast alternative to mono_array_new() for code which
1987 * can be sure about the domain it operates in.
1990 mono_array_new_specific (MonoVTable *vtable, guint32 n)
1994 guint32 byte_len, elem_size;
1996 MONO_ARCH_SAVE_REGS;
1998 elem_size = mono_array_element_size (vtable->klass);
1999 if (CHECK_MUL_OVERFLOW_UN (n, elem_size))
2000 out_of_memory (MYGUINT32_MAX);
2001 byte_len = n * elem_size;
2002 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
2003 out_of_memory (MYGUINT32_MAX);
2004 byte_len += sizeof (MonoArray);
2005 #if CREATION_SPEEDUP
2006 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
2007 o = mono_object_allocate_spec (byte_len, vtable);
2009 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
2010 o = mono_object_allocate (byte_len);
2014 o = mono_object_allocate (byte_len);
2018 ao = (MonoArray *)o;
2021 mono_profiler_allocation (o, vtable->klass);
2027 * mono_string_new_utf16:
2028 * @text: a pointer to an utf16 string
2029 * @len: the length of the string
2031 * Returns: A newly created string object which contains @text.
2034 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
2038 s = mono_string_new_size (domain, len);
2039 g_assert (s != NULL);
2041 memcpy (mono_string_chars (s), text, len * 2);
2047 * mono_string_new_size:
2048 * @text: a pointer to an utf16 string
2049 * @len: the length of the string
2051 * Returns: A newly created string object of @len
2054 mono_string_new_size (MonoDomain *domain, gint32 len)
2058 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
2060 /* overflow ? can't fit it, can't allocate it! */
2064 vtable = mono_class_vtable (domain, mono_defaults.string_class);
2066 #if CREATION_SPEEDUP
2067 if (vtable->gc_descr != GC_NO_DESCRIPTOR)
2068 s = mono_object_allocate_spec (size, vtable);
2070 s = (MonoString*)mono_object_allocate (size);
2071 s->object.vtable = vtable;
2074 s = (MonoString*)mono_object_allocate (size);
2075 s->object.vtable = vtable;
2079 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
2085 * mono_string_new_len:
2086 * @text: a pointer to an utf8 string
2087 * @length: number of bytes in @text to consider
2089 * Returns: A newly created string object which contains @text.
2092 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
2094 GError *error = NULL;
2095 MonoString *o = NULL;
2097 glong items_written;
2099 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
2102 o = mono_string_new_utf16 (domain, ut, items_written);
2104 g_error_free (error);
2113 * @text: a pointer to an utf8 string
2115 * Returns: A newly created string object which contains @text.
2118 mono_string_new (MonoDomain *domain, const char *text)
2120 GError *error = NULL;
2121 MonoString *o = NULL;
2123 glong items_written;
2128 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
2131 o = mono_string_new_utf16 (domain, ut, items_written);
2133 g_error_free (error);
2141 * mono_string_new_wrapper:
2142 * @text: pointer to utf8 characters.
2144 * Helper function to create a string object from @text in the current domain.
2147 mono_string_new_wrapper (const char *text)
2149 MonoDomain *domain = mono_domain_get ();
2151 MONO_ARCH_SAVE_REGS;
2154 return mono_string_new (domain, text);
2161 * @class: the class of the value
2162 * @value: a pointer to the unboxed data
2164 * Returns: A newly created object which contains @value.
2167 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
2173 g_assert (class->valuetype);
2175 vtable = mono_class_vtable (domain, class);
2176 size = mono_class_instance_size (class);
2177 res = mono_object_allocate (size);
2178 res->vtable = vtable;
2179 mono_profiler_allocation (res, class);
2181 size = size - sizeof (MonoObject);
2183 #if NO_UNALIGNED_ACCESS
2184 memcpy ((char *)res + sizeof (MonoObject), value, size);
2188 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
2191 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
2194 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
2197 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
2200 memcpy ((char *)res + sizeof (MonoObject), value, size);
2203 if (class->has_finalize)
2204 mono_object_register_finalizer (res);
2209 mono_object_get_domain (MonoObject *obj)
2211 return mono_object_domain (obj);
2215 mono_object_get_class (MonoObject *obj)
2217 return mono_object_class (obj);
2221 mono_object_unbox (MonoObject *obj)
2223 /* add assert for valuetypes? */
2224 g_assert (obj->vtable->klass->valuetype);
2225 return ((char*)obj) + sizeof (MonoObject);
2229 * mono_object_isinst:
2231 * @klass: a pointer to a class
2233 * Returns: @obj if @obj is derived from @klass
2236 mono_object_isinst (MonoObject *obj, MonoClass *klass)
2239 mono_class_init (klass);
2241 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)
2242 return mono_object_isinst_mbyref (obj, klass);
2247 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
2251 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
2260 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2261 if ((klass->interface_id <= vt->max_interface_id) &&
2262 (vt->interface_offsets [klass->interface_id] != 0))
2266 MonoClass *oklass = vt->klass;
2267 if ((oklass == mono_defaults.transparent_proxy_class))
2268 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2270 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
2274 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
2276 MonoDomain *domain = mono_domain_get ();
2278 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
2279 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
2280 MonoMethod *im = NULL;
2284 for (i = 0; i < rpklass->method.count; ++i) {
2285 if (!strcmp ("CanCastTo", rpklass->methods [i]->name)) {
2286 im = rpklass->methods [i];
2291 im = mono_object_get_virtual_method (rp, im);
2294 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
2297 res = mono_runtime_invoke (im, rp, pa, NULL);
2299 if (*(MonoBoolean *) mono_object_unbox(res)) {
2300 /* Update the vtable of the remote type, so it can safely cast to this new type */
2301 mono_upgrade_remote_class (domain, ((MonoTransparentProxy *)obj)->remote_class, klass);
2302 obj->vtable = ((MonoTransparentProxy *)obj)->remote_class->vtable;
2311 * mono_object_castclass_mbyref:
2313 * @klass: a pointer to a class
2315 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
2318 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
2320 if (!obj) return NULL;
2321 if (mono_object_isinst_mbyref (obj, klass)) return obj;
2323 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
2325 "InvalidCastException"));
2330 MonoDomain *orig_domain;
2336 str_lookup (MonoDomain *domain, gpointer user_data)
2338 LDStrInfo *info = user_data;
2339 if (info->res || domain == info->orig_domain)
2341 mono_domain_lock (domain);
2342 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
2343 mono_domain_unlock (domain);
2347 mono_string_is_interned_lookup (MonoString *str, int insert)
2349 MonoGHashTable *ldstr_table;
2352 char *ins = g_malloc (4 + str->length * 2);
2355 /* Encode the length */
2356 /* Same code as in mono_image_insert_string () */
2358 mono_metadata_encode_value (1 | (2 * str->length), p, &p);
2361 * ins is stored in the hash table as a key and needs to have the same
2362 * representation as in the metadata: we swap the character bytes on big
2365 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
2368 char *p2 = (char *)mono_string_chars (str);
2369 for (i = 0; i < str->length; ++i) {
2376 memcpy (p, mono_string_chars (str), str->length * 2);
2378 domain = ((MonoObject *)str)->vtable->domain;
2379 ldstr_table = domain->ldstr_table;
2380 mono_domain_lock (domain);
2381 if ((res = mono_g_hash_table_lookup (ldstr_table, ins))) {
2382 mono_domain_unlock (domain);
2387 mono_g_hash_table_insert (ldstr_table, ins, str);
2388 mono_domain_unlock (domain);
2391 LDStrInfo ldstr_info;
2392 ldstr_info.orig_domain = domain;
2393 ldstr_info.ins = ins;
2394 ldstr_info.res = NULL;
2396 mono_domain_foreach (str_lookup, &ldstr_info);
2397 if (ldstr_info.res) {
2399 * the string was already interned in some other domain:
2400 * intern it in the current one as well.
2402 mono_g_hash_table_insert (ldstr_table, ins, str);
2403 mono_domain_unlock (domain);
2407 mono_domain_unlock (domain);
2413 mono_string_is_interned (MonoString *o)
2415 return mono_string_is_interned_lookup (o, FALSE);
2419 mono_string_intern (MonoString *str)
2421 return mono_string_is_interned_lookup (str, TRUE);
2426 * @domain: the domain where the string will be used.
2427 * @image: a metadata context
2428 * @idx: index into the user string table.
2430 * Implementation for the ldstr opcode.
2433 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
2435 const char *str, *sig;
2439 MONO_ARCH_SAVE_REGS;
2442 return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx);
2444 sig = str = mono_metadata_user_string (image, idx);
2446 mono_domain_lock (domain);
2447 if ((o = mono_g_hash_table_lookup (domain->ldstr_table, sig))) {
2448 mono_domain_unlock (domain);
2452 len2 = mono_metadata_decode_blob_size (str, &str);
2455 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
2456 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
2459 guint16 *p2 = (guint16*)mono_string_chars (o);
2460 for (i = 0; i < len2; ++i) {
2461 *p2 = GUINT16_FROM_LE (*p2);
2466 mono_g_hash_table_insert (domain->ldstr_table, (gpointer)sig, o);
2467 mono_domain_unlock (domain);
2473 * mono_string_to_utf8:
2474 * @s: a System.String
2476 * Return the UTF8 representation for @s.
2477 * the resulting buffer nedds to be freed with g_free().
2480 mono_string_to_utf8 (MonoString *s)
2483 GError *error = NULL;
2489 return g_strdup ("");
2491 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, NULL, &error);
2493 g_warning (error->message);
2494 g_error_free (error);
2501 * mono_string_to_utf16:
2504 * Return an null-terminated array of the utf-16 chars
2505 * contained in @s. The result must be freed with g_free().
2506 * This is a temporary helper until our string implementation
2507 * is reworked to always include the null terminating char.
2510 mono_string_to_utf16 (MonoString *s)
2517 as = g_malloc ((s->length * 2) + 2);
2518 as [(s->length * 2)] = '\0';
2519 as [(s->length * 2) + 1] = '\0';
2522 return (gunichar2 *)(as);
2525 memcpy (as, mono_string_chars(s), s->length * 2);
2526 return (gunichar2 *)(as);
2530 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString
2533 mono_string_from_utf16 (gunichar2 *data)
2535 MonoDomain *domain = mono_domain_get ();
2541 while (data [len]) len++;
2543 return mono_string_new_utf16 (domain, data, len);
2547 default_ex_handler (MonoException *ex)
2549 MonoObject *o = (MonoObject*)ex;
2550 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
2554 static MonoExceptionFunc ex_handler = default_ex_handler;
2557 mono_install_handler (MonoExceptionFunc func)
2559 ex_handler = func? func: default_ex_handler;
2563 * mono_raise_exception:
2564 * @ex: exception object
2566 * Signal the runtime that the exception @ex has been raised in unmanaged code.
2569 mono_raise_exception (MonoException *ex)
2572 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
2573 * that will cause gcc to omit the function epilog, causing problems when
2574 * the JIT tries to walk the stack, since the return address on the stack
2575 * will point into the next function in the executable, not this one.
2582 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
2584 MonoWaitHandle *res;
2586 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
2588 res->handle = handle;
2594 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data)
2596 MonoAsyncResult *res;
2598 res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
2601 res->async_state = state;
2603 res->handle = (MonoObject *) mono_wait_handle_new (domain, handle);
2605 res->sync_completed = FALSE;
2606 res->completed = FALSE;
2612 mono_message_init (MonoDomain *domain,
2613 MonoMethodMessage *this,
2614 MonoReflectionMethod *method,
2615 MonoArray *out_args)
2617 MonoMethodSignature *sig = method->method->signature;
2623 this->method = method;
2625 this->args = mono_array_new (domain, mono_defaults.object_class, sig->param_count);
2626 this->arg_types = mono_array_new (domain, mono_defaults.byte_class, sig->param_count);
2627 this->async_result = NULL;
2628 this->call_type = CallType_Sync;
2630 names = g_new (char *, sig->param_count);
2631 mono_method_get_param_names (method->method, (const char **) names);
2632 this->names = mono_array_new (domain, mono_defaults.string_class, sig->param_count);
2634 for (i = 0; i < sig->param_count; i++) {
2635 name = mono_string_new (domain, names [i]);
2636 mono_array_set (this->names, gpointer, i, name);
2640 for (i = 0, j = 0; i < sig->param_count; i++) {
2642 if (sig->params [i]->byref) {
2644 gpointer arg = mono_array_get (out_args, gpointer, j);
2645 mono_array_set (this->args, gpointer, i, arg);
2649 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
2654 mono_array_set (this->arg_types, guint8, i, arg_type);
2659 * mono_remoting_invoke:
2660 * @real_proxy: pointer to a RealProxy object
2661 * @msg: The MonoMethodMessage to execute
2662 * @exc: used to store exceptions
2663 * @out_args: used to store output arguments
2665 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
2666 * IMessage interface and it is not trivial to extract results from there. So
2667 * we call an helper method PrivateInvoke instead of calling
2668 * RealProxy::Invoke() directly.
2670 * Returns: the result object.
2673 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
2674 MonoObject **exc, MonoArray **out_args)
2676 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
2679 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
2685 klass = mono_defaults.real_proxy_class;
2687 for (i = 0; i < klass->method.count; ++i) {
2688 if (!strcmp ("PrivateInvoke", klass->methods [i]->name) &&
2689 klass->methods [i]->signature->param_count == 4) {
2690 im = klass->methods [i];
2696 real_proxy->vtable->domain->private_invoke_method = im;
2699 pa [0] = real_proxy;
2704 return mono_runtime_invoke (im, NULL, pa, exc);
2708 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
2709 MonoObject **exc, MonoArray **out_args)
2713 MonoMethodSignature *sig;
2714 int i, j, outarg_count = 0;
2716 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
2718 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
2719 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
2720 target = tp->rp->unwrapped_server;
2722 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
2726 domain = mono_domain_get ();
2727 method = msg->method->method;
2728 sig = method->signature;
2730 for (i = 0; i < sig->param_count; i++) {
2731 if (sig->params [i]->byref)
2735 *out_args = mono_array_new (domain, mono_defaults.object_class, outarg_count);
2738 for (i = 0, j = 0; i < sig->param_count; i++) {
2739 if (sig->params [i]->byref) {
2741 arg = mono_array_get (msg->args, gpointer, i);
2742 mono_array_set (*out_args, gpointer, j, arg);
2747 return mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
2751 mono_print_unhandled_exception (MonoObject *exc)
2753 char *message = (char *) "";
2757 gboolean free_message = FALSE;
2760 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
2761 klass = exc->vtable->klass;
2763 while (klass && method == NULL) {
2764 for (i = 0; i < klass->method.count; ++i) {
2765 method = klass->methods [i];
2766 if (!strcmp ("ToString", method->name) &&
2767 method->signature->param_count == 0 &&
2768 method->flags & METHOD_ATTRIBUTE_VIRTUAL &&
2769 method->flags & METHOD_ATTRIBUTE_PUBLIC) {
2776 klass = klass->parent;
2781 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
2783 message = mono_string_to_utf8 (str);
2784 free_message = TRUE;
2789 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
2790 * exc->vtable->klass->name, message);
2792 g_printerr ("\nUnhandled Exception: %s\n", message);
2799 * mono_delegate_ctor:
2800 * @this: pointer to an uninitialized delegate object
2801 * @target: target object
2802 * @addr: pointer to native code
2804 * This is used to initialize a delegate. We also insert the method_info if
2805 * we find the info with mono_jit_info_table_find().
2808 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
2810 MonoDomain *domain = mono_domain_get ();
2811 MonoDelegate *delegate = (MonoDelegate *)this;
2812 MonoMethod *method = NULL;
2819 class = this->vtable->klass;
2821 if ((ji = mono_jit_info_table_find (domain, addr))) {
2822 method = ji->method;
2823 delegate->method_info = mono_method_get_object (domain, method, NULL);
2826 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
2828 method = mono_marshal_get_remoting_invoke (method);
2829 delegate->method_ptr = mono_compile_method (method);
2830 delegate->target = target;
2832 delegate->method_ptr = addr;
2833 delegate->target = target;
2838 * mono_method_call_message_new:
2840 * Translates arguments pointers into a Message.
2843 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
2844 MonoDelegate **cb, MonoObject **state)
2846 MonoDomain *domain = mono_domain_get ();
2847 MonoMethodSignature *sig = method->signature;
2848 MonoMethodMessage *msg;
2851 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
2854 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
2855 count = sig->param_count - 2;
2857 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
2858 count = sig->param_count;
2861 for (i = 0; i < count; i++) {
2866 if (sig->params [i]->byref)
2867 vpos = *((gpointer *)params [i]);
2871 type = sig->params [i]->type;
2872 class = mono_class_from_mono_type (sig->params [i]);
2874 if (class->valuetype)
2875 arg = mono_value_box (domain, class, vpos);
2877 arg = *((MonoObject **)vpos);
2879 mono_array_set (msg->args, gpointer, i, arg);
2882 if (cb != NULL && state != NULL) {
2883 *cb = *((MonoDelegate **)params [i]);
2885 *state = *((MonoObject **)params [i]);
2892 * mono_method_return_message_restore:
2894 * Restore results from message based processing back to arguments pointers
2897 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
2899 MonoMethodSignature *sig = method->signature;
2900 int i, j, type, size;
2901 for (i = 0, j = 0; i < sig->param_count; i++) {
2902 MonoType *pt = sig->params [i];
2905 char *arg = mono_array_get (out_args, gpointer, j);
2909 case MONO_TYPE_VOID:
2910 g_assert_not_reached ();
2914 case MONO_TYPE_BOOLEAN:
2917 case MONO_TYPE_CHAR:
2924 case MONO_TYPE_VALUETYPE: {
2925 size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
2926 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
2929 case MONO_TYPE_STRING:
2930 case MONO_TYPE_CLASS:
2931 case MONO_TYPE_ARRAY:
2932 case MONO_TYPE_SZARRAY:
2933 case MONO_TYPE_OBJECT:
2934 **((MonoObject ***)params [i]) = (MonoObject *)arg;
2937 g_assert_not_reached ();
2946 * mono_load_remote_field:
2947 * @this: pointer to an object
2948 * @klass: klass of the object containing @field
2949 * @field: the field to load
2950 * @res: a storage to store the result
2952 * This method is called by the runtime on attempts to load fields of
2953 * transparent proxy objects. @this points to such TP, @klass is the class of
2954 * the object containing @field. @res is a storage location which can be
2955 * used to store the result.
2957 * Returns: an address pointing to the value of field.
2960 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
2962 static MonoMethod *getter = NULL;
2963 MonoDomain *domain = mono_domain_get ();
2964 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
2965 MonoClass *field_class;
2966 MonoMethodMessage *msg;
2967 MonoArray *out_args;
2971 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
2976 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
2977 mono_field_get_value (tp->rp->unwrapped_server, field, res);
2984 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
2985 MonoMethod *cm = mono_defaults.object_class->methods [i];
2987 if (!strcmp (cm->name, "FieldGetter")) {
2995 field_class = mono_class_from_mono_type (field->type);
2997 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
2998 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
2999 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
3001 mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3002 mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3004 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3006 if (exc) mono_raise_exception ((MonoException *)exc);
3008 *res = mono_array_get (out_args, MonoObject *, 0);
3010 if (field_class->valuetype) {
3011 return ((char *)*res) + sizeof (MonoObject);
3017 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
3019 static MonoMethod *getter = NULL;
3020 MonoDomain *domain = mono_domain_get ();
3021 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3022 MonoClass *field_class;
3023 MonoMethodMessage *msg;
3024 MonoArray *out_args;
3025 MonoObject *exc, *res;
3027 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3029 field_class = mono_class_from_mono_type (field->type);
3031 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3033 if (field_class->valuetype) {
3034 res = mono_object_new (domain, field_class);
3035 val = ((gchar *) res) + sizeof (MonoObject);
3039 mono_field_get_value (tp->rp->unwrapped_server, field, val);
3046 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
3047 MonoMethod *cm = mono_defaults.object_class->methods [i];
3049 if (!strcmp (cm->name, "FieldGetter")) {
3057 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3058 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
3059 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
3061 mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3062 mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3064 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3066 if (exc) mono_raise_exception ((MonoException *)exc);
3068 res = mono_array_get (out_args, MonoObject *, 0);
3074 * mono_store_remote_field:
3075 * @this: pointer to an object
3076 * @klass: klass of the object containing @field
3077 * @field: the field to load
3078 * @val: the value/object to store
3080 * This method is called by the runtime on attempts to store fields of
3081 * transparent proxy objects. @this points to such TP, @klass is the class of
3082 * the object containing @field. @val is the new value to store in @field.
3085 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
3087 static MonoMethod *setter = NULL;
3088 MonoDomain *domain = mono_domain_get ();
3089 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3090 MonoClass *field_class;
3091 MonoMethodMessage *msg;
3092 MonoArray *out_args;
3096 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3098 field_class = mono_class_from_mono_type (field->type);
3100 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3101 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
3102 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
3109 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
3110 MonoMethod *cm = mono_defaults.object_class->methods [i];
3112 if (!strcmp (cm->name, "FieldSetter")) {
3120 if (field_class->valuetype)
3121 arg = mono_value_box (domain, field_class, val);
3123 arg = *((MonoObject **)val);
3126 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3127 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
3129 mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3130 mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3131 mono_array_set (msg->args, gpointer, 2, arg);
3133 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3135 if (exc) mono_raise_exception ((MonoException *)exc);
3139 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
3141 static MonoMethod *setter = NULL;
3142 MonoDomain *domain = mono_domain_get ();
3143 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3144 MonoClass *field_class;
3145 MonoMethodMessage *msg;
3146 MonoArray *out_args;
3149 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3151 field_class = mono_class_from_mono_type (field->type);
3153 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3154 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
3155 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
3162 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
3163 MonoMethod *cm = mono_defaults.object_class->methods [i];
3165 if (!strcmp (cm->name, "FieldSetter")) {
3173 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3174 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
3176 mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3177 mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3178 mono_array_set (msg->args, gpointer, 2, arg);
3180 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3182 if (exc) mono_raise_exception ((MonoException *)exc);