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 if (sig->params [i]->byref) {
1590 /* MS seems to create the objects if a null is passed in */
1591 if (! ((gpointer *)params->vector)[i])
1592 ((gpointer*)params->vector)[i] = mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i]));
1595 g_assert (((gpointer*)params->vector) [i]);
1596 pa [i] = (char *)(((gpointer *)params->vector)[i]) + sizeof (MonoObject);
1598 case MONO_TYPE_STRING:
1599 case MONO_TYPE_OBJECT:
1600 case MONO_TYPE_CLASS:
1601 case MONO_TYPE_ARRAY:
1602 case MONO_TYPE_SZARRAY:
1603 if (sig->params [i]->byref)
1604 pa [i] = &(((gpointer *)params->vector)[i]);
1606 pa [i] = (char *)(((gpointer *)params->vector)[i]);
1609 g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
1614 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
1617 obj = mono_object_new (mono_domain_get (), method->klass);
1618 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
1619 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
1621 if (method->klass->valuetype)
1622 o = mono_object_unbox (obj);
1626 mono_runtime_invoke (method, o, pa, exc);
1629 /* obj must be already unboxed if needed */
1630 return mono_runtime_invoke (method, obj, pa, exc);
1635 out_of_memory (size_t size)
1638 * we could allocate at program startup some memory that we could release
1639 * back to the system at this point if we're really low on memory (ie, size is
1640 * lower than the memory we set apart)
1642 mono_raise_exception (mono_domain_get ()->out_of_memory_ex);
1646 * mono_object_allocate:
1647 * @size: number of bytes to allocate
1649 * This is a very simplistic routine until we have our GC-aware
1652 * Returns: an allocated object of size @size, or NULL on failure.
1654 static inline void *
1655 mono_object_allocate (size_t size)
1658 /* if this is changed to GC_debug_malloc(), we need to change also metadata/gc.c */
1659 void *o = GC_MALLOC (size);
1661 void *o = calloc (1, size);
1663 mono_stats.new_object_count++;
1666 out_of_memory (size);
1670 #if CREATION_SPEEDUP
1671 static inline void *
1672 mono_object_allocate_spec (size_t size, void *gcdescr)
1674 /* if this is changed to GC_debug_malloc(), we need to change also metadata/gc.c */
1675 void *o = GC_GCJ_MALLOC (size, gcdescr);
1676 mono_stats.new_object_count++;
1679 out_of_memory (size);
1686 * @klass: the class of the object that we want to create
1688 * Returns a newly created object whose definition is
1689 * looked up using @klass. This will not invoke any constructors,
1690 * so the consumer of this routine has to invoke any constructors on
1691 * its own to initialize the object.
1694 mono_object_new (MonoDomain *domain, MonoClass *klass)
1696 MONO_ARCH_SAVE_REGS;
1697 return mono_object_new_specific (mono_class_vtable (domain, klass));
1701 * mono_object_new_specific:
1702 * @vtable: the vtable of the object that we want to create
1704 * Returns: A newly created object with class and domain specified
1708 mono_object_new_specific (MonoVTable *vtable)
1712 MONO_ARCH_SAVE_REGS;
1717 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
1720 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
1724 mono_class_init (klass);
1726 for (i = 0; i < klass->method.count; ++i) {
1727 if (!strcmp ("CreateProxyForType", klass->methods [i]->name) &&
1728 klass->methods [i]->signature->param_count == 1) {
1729 im = klass->methods [i];
1734 vtable->domain->create_proxy_for_type_method = im;
1737 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
1739 o = mono_runtime_invoke (im, NULL, pa, NULL);
1740 if (o != NULL) return o;
1743 return mono_object_new_alloc_specific (vtable);
1747 mono_object_new_fast (MonoVTable *vtable)
1750 MONO_ARCH_SAVE_REGS;
1752 #if CREATION_SPEEDUP
1753 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
1754 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
1756 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
1757 o = mono_object_allocate (vtable->klass->instance_size);
1761 o = mono_object_allocate (vtable->klass->instance_size);
1768 mono_object_new_alloc_specific (MonoVTable *vtable)
1772 #if CREATION_SPEEDUP
1773 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
1774 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
1776 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
1777 o = mono_object_allocate (vtable->klass->instance_size);
1781 o = mono_object_allocate (vtable->klass->instance_size);
1784 if (vtable->klass->has_finalize)
1785 mono_object_register_finalizer (o);
1787 mono_profiler_allocation (o, vtable->klass);
1792 * mono_object_new_from_token:
1793 * @image: Context where the type_token is hosted
1794 * @token: a token of the type that we want to create
1796 * Returns: A newly created object whose definition is
1797 * looked up using @token in the @image image
1800 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
1804 class = mono_class_get (image, token);
1806 return mono_object_new (domain, class);
1811 * mono_object_clone:
1812 * @obj: the object to clone
1814 * Returns: A newly created object who is a shallow copy of @obj
1817 mono_object_clone (MonoObject *obj)
1822 size = obj->vtable->klass->instance_size;
1823 o = mono_object_allocate (size);
1824 mono_profiler_allocation (o, obj->vtable->klass);
1826 memcpy (o, obj, size);
1828 if (obj->vtable->klass->has_finalize)
1829 mono_object_register_finalizer (o);
1835 * @array: the array to clone
1837 * Returns: A newly created array who is a shallow copy of @array
1840 mono_array_clone (MonoArray *array)
1845 MonoClass *klass = array->obj.vtable->klass;
1847 MONO_ARCH_SAVE_REGS;
1849 if (array->bounds == NULL) {
1850 size = mono_array_length (array);
1851 o = mono_array_new_full (((MonoObject *)array)->vtable->domain,
1852 klass, &size, NULL);
1854 size *= mono_array_element_size (klass);
1855 memcpy (o, array, sizeof (MonoArray) + size);
1860 sizes = alloca (klass->rank * sizeof(guint32) * 2);
1861 size = mono_array_element_size (klass);
1862 for (i = 0; i < klass->rank; ++i) {
1863 sizes [i] = array->bounds [i].length;
1864 size *= array->bounds [i].length;
1865 sizes [i + klass->rank] = array->bounds [i].lower_bound;
1867 o = mono_array_new_full (((MonoObject *)array)->vtable->domain,
1868 klass, sizes, sizes + klass->rank);
1869 memcpy (o, array, sizeof(MonoArray) + size);
1874 /* helper macros to check for overflow when calculating the size of arrays */
1875 #define MYGUINT32_MAX 4294967295U
1876 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1877 (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
1878 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1879 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1880 (guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a))
1883 * mono_array_new_full:
1884 * @domain: domain where the object is created
1885 * @array_class: array class
1886 * @lengths: lengths for each dimension in the array
1887 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
1889 * This routine creates a new array objects with the given dimensions,
1890 * lower bounds and type.
1893 mono_array_new_full (MonoDomain *domain, MonoClass *array_class,
1894 guint32 *lengths, guint32 *lower_bounds)
1896 guint32 byte_len, len;
1899 MonoArrayBounds *bounds;
1903 if (!array_class->inited)
1904 mono_class_init (array_class);
1906 byte_len = mono_array_element_size (array_class);
1909 if (array_class->rank == 1 &&
1910 (lower_bounds == NULL || lower_bounds [0] == 0)) {
1915 bounds = GC_MALLOC (sizeof (MonoArrayBounds) * array_class->rank);
1917 bounds = g_malloc0 (sizeof (MonoArrayBounds) * array_class->rank);
1919 for (i = 0; i < array_class->rank; ++i) {
1920 bounds [i].length = lengths [i];
1921 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
1922 out_of_memory (MYGUINT32_MAX);
1927 for (i = 0; i < array_class->rank; ++i)
1928 bounds [i].lower_bound = lower_bounds [i];
1931 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
1932 out_of_memory (MYGUINT32_MAX);
1934 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
1935 out_of_memory (MYGUINT32_MAX);
1936 byte_len += sizeof (MonoArray);
1938 * Following three lines almost taken from mono_object_new ():
1939 * they need to be kept in sync.
1941 vtable = mono_class_vtable (domain, array_class);
1942 #if CREATION_SPEEDUP
1943 if (vtable->gc_descr != GC_NO_DESCRIPTOR)
1944 o = mono_object_allocate_spec (byte_len, vtable);
1946 o = mono_object_allocate (byte_len);
1950 o = mono_object_allocate (byte_len);
1954 array = (MonoArray*)o;
1956 array->bounds = bounds;
1957 array->max_length = len;
1959 mono_profiler_allocation (o, array_class);
1966 * @domain: domain where the object is created
1967 * @eclass: element class
1968 * @n: number of array elements
1970 * This routine creates a new szarray with @n elements of type @eclass.
1973 mono_array_new (MonoDomain *domain, MonoClass *eclass, guint32 n)
1977 MONO_ARCH_SAVE_REGS;
1979 ac = mono_array_class_get (eclass, 1);
1980 g_assert (ac != NULL);
1982 return mono_array_new_specific (mono_class_vtable (domain, ac), n);
1986 * mono_array_new_specific:
1987 * @vtable: a vtable in the appropriate domain for an initialized class
1988 * @n: number of array elements
1990 * This routine is a fast alternative to mono_array_new() for code which
1991 * can be sure about the domain it operates in.
1994 mono_array_new_specific (MonoVTable *vtable, guint32 n)
1998 guint32 byte_len, elem_size;
2000 MONO_ARCH_SAVE_REGS;
2002 elem_size = mono_array_element_size (vtable->klass);
2003 if (CHECK_MUL_OVERFLOW_UN (n, elem_size))
2004 out_of_memory (MYGUINT32_MAX);
2005 byte_len = n * elem_size;
2006 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
2007 out_of_memory (MYGUINT32_MAX);
2008 byte_len += sizeof (MonoArray);
2009 #if CREATION_SPEEDUP
2010 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
2011 o = mono_object_allocate_spec (byte_len, vtable);
2013 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
2014 o = mono_object_allocate (byte_len);
2018 o = mono_object_allocate (byte_len);
2022 ao = (MonoArray *)o;
2025 mono_profiler_allocation (o, vtable->klass);
2031 * mono_string_new_utf16:
2032 * @text: a pointer to an utf16 string
2033 * @len: the length of the string
2035 * Returns: A newly created string object which contains @text.
2038 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
2042 s = mono_string_new_size (domain, len);
2043 g_assert (s != NULL);
2045 memcpy (mono_string_chars (s), text, len * 2);
2051 * mono_string_new_size:
2052 * @text: a pointer to an utf16 string
2053 * @len: the length of the string
2055 * Returns: A newly created string object of @len
2058 mono_string_new_size (MonoDomain *domain, gint32 len)
2062 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
2064 /* overflow ? can't fit it, can't allocate it! */
2068 vtable = mono_class_vtable (domain, mono_defaults.string_class);
2070 #if CREATION_SPEEDUP
2071 if (vtable->gc_descr != GC_NO_DESCRIPTOR)
2072 s = mono_object_allocate_spec (size, vtable);
2074 s = (MonoString*)mono_object_allocate (size);
2075 s->object.vtable = vtable;
2078 s = (MonoString*)mono_object_allocate (size);
2079 s->object.vtable = vtable;
2083 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
2089 * mono_string_new_len:
2090 * @text: a pointer to an utf8 string
2091 * @length: number of bytes in @text to consider
2093 * Returns: A newly created string object which contains @text.
2096 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
2098 GError *error = NULL;
2099 MonoString *o = NULL;
2101 glong items_written;
2103 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
2106 o = mono_string_new_utf16 (domain, ut, items_written);
2108 g_error_free (error);
2117 * @text: a pointer to an utf8 string
2119 * Returns: A newly created string object which contains @text.
2122 mono_string_new (MonoDomain *domain, const char *text)
2124 GError *error = NULL;
2125 MonoString *o = NULL;
2127 glong items_written;
2132 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
2135 o = mono_string_new_utf16 (domain, ut, items_written);
2137 g_error_free (error);
2145 * mono_string_new_wrapper:
2146 * @text: pointer to utf8 characters.
2148 * Helper function to create a string object from @text in the current domain.
2151 mono_string_new_wrapper (const char *text)
2153 MonoDomain *domain = mono_domain_get ();
2155 MONO_ARCH_SAVE_REGS;
2158 return mono_string_new (domain, text);
2165 * @class: the class of the value
2166 * @value: a pointer to the unboxed data
2168 * Returns: A newly created object which contains @value.
2171 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
2177 g_assert (class->valuetype);
2179 vtable = mono_class_vtable (domain, class);
2180 size = mono_class_instance_size (class);
2181 res = mono_object_allocate (size);
2182 res->vtable = vtable;
2183 mono_profiler_allocation (res, class);
2185 size = size - sizeof (MonoObject);
2187 #if NO_UNALIGNED_ACCESS
2188 memcpy ((char *)res + sizeof (MonoObject), value, size);
2192 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
2195 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
2198 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
2201 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
2204 memcpy ((char *)res + sizeof (MonoObject), value, size);
2207 if (class->has_finalize)
2208 mono_object_register_finalizer (res);
2213 mono_object_get_domain (MonoObject *obj)
2215 return mono_object_domain (obj);
2219 mono_object_get_class (MonoObject *obj)
2221 return mono_object_class (obj);
2225 mono_object_unbox (MonoObject *obj)
2227 /* add assert for valuetypes? */
2228 g_assert (obj->vtable->klass->valuetype);
2229 return ((char*)obj) + sizeof (MonoObject);
2233 * mono_object_isinst:
2235 * @klass: a pointer to a class
2237 * Returns: @obj if @obj is derived from @klass
2240 mono_object_isinst (MonoObject *obj, MonoClass *klass)
2243 mono_class_init (klass);
2245 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)
2246 return mono_object_isinst_mbyref (obj, klass);
2251 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
2255 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
2264 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2265 if ((klass->interface_id <= vt->max_interface_id) &&
2266 (vt->interface_offsets [klass->interface_id] != 0))
2270 MonoClass *oklass = vt->klass;
2271 if ((oklass == mono_defaults.transparent_proxy_class))
2272 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2274 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
2278 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
2280 MonoDomain *domain = mono_domain_get ();
2282 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
2283 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
2284 MonoMethod *im = NULL;
2288 for (i = 0; i < rpklass->method.count; ++i) {
2289 if (!strcmp ("CanCastTo", rpklass->methods [i]->name)) {
2290 im = rpklass->methods [i];
2295 im = mono_object_get_virtual_method (rp, im);
2298 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
2301 res = mono_runtime_invoke (im, rp, pa, NULL);
2303 if (*(MonoBoolean *) mono_object_unbox(res)) {
2304 /* Update the vtable of the remote type, so it can safely cast to this new type */
2305 mono_upgrade_remote_class (domain, ((MonoTransparentProxy *)obj)->remote_class, klass);
2306 obj->vtable = ((MonoTransparentProxy *)obj)->remote_class->vtable;
2315 * mono_object_castclass_mbyref:
2317 * @klass: a pointer to a class
2319 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
2322 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
2324 if (!obj) return NULL;
2325 if (mono_object_isinst_mbyref (obj, klass)) return obj;
2327 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
2329 "InvalidCastException"));
2334 MonoDomain *orig_domain;
2340 str_lookup (MonoDomain *domain, gpointer user_data)
2342 LDStrInfo *info = user_data;
2343 if (info->res || domain == info->orig_domain)
2345 mono_domain_lock (domain);
2346 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
2347 mono_domain_unlock (domain);
2351 mono_string_is_interned_lookup (MonoString *str, int insert)
2353 MonoGHashTable *ldstr_table;
2356 char *ins = g_malloc (4 + str->length * 2);
2359 /* Encode the length */
2360 /* Same code as in mono_image_insert_string () */
2362 mono_metadata_encode_value (1 | (2 * str->length), p, &p);
2365 * ins is stored in the hash table as a key and needs to have the same
2366 * representation as in the metadata: we swap the character bytes on big
2369 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
2372 char *p2 = (char *)mono_string_chars (str);
2373 for (i = 0; i < str->length; ++i) {
2380 memcpy (p, mono_string_chars (str), str->length * 2);
2382 domain = ((MonoObject *)str)->vtable->domain;
2383 ldstr_table = domain->ldstr_table;
2384 mono_domain_lock (domain);
2385 if ((res = mono_g_hash_table_lookup (ldstr_table, ins))) {
2386 mono_domain_unlock (domain);
2391 mono_g_hash_table_insert (ldstr_table, ins, str);
2392 mono_domain_unlock (domain);
2395 LDStrInfo ldstr_info;
2396 ldstr_info.orig_domain = domain;
2397 ldstr_info.ins = ins;
2398 ldstr_info.res = NULL;
2400 mono_domain_foreach (str_lookup, &ldstr_info);
2401 if (ldstr_info.res) {
2403 * the string was already interned in some other domain:
2404 * intern it in the current one as well.
2406 mono_g_hash_table_insert (ldstr_table, ins, str);
2407 mono_domain_unlock (domain);
2411 mono_domain_unlock (domain);
2417 mono_string_is_interned (MonoString *o)
2419 return mono_string_is_interned_lookup (o, FALSE);
2423 mono_string_intern (MonoString *str)
2425 return mono_string_is_interned_lookup (str, TRUE);
2430 * @domain: the domain where the string will be used.
2431 * @image: a metadata context
2432 * @idx: index into the user string table.
2434 * Implementation for the ldstr opcode.
2437 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
2439 const char *str, *sig;
2443 MONO_ARCH_SAVE_REGS;
2446 return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx);
2448 sig = str = mono_metadata_user_string (image, idx);
2450 mono_domain_lock (domain);
2451 if ((o = mono_g_hash_table_lookup (domain->ldstr_table, sig))) {
2452 mono_domain_unlock (domain);
2456 len2 = mono_metadata_decode_blob_size (str, &str);
2459 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
2460 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
2463 guint16 *p2 = (guint16*)mono_string_chars (o);
2464 for (i = 0; i < len2; ++i) {
2465 *p2 = GUINT16_FROM_LE (*p2);
2470 mono_g_hash_table_insert (domain->ldstr_table, (gpointer)sig, o);
2471 mono_domain_unlock (domain);
2477 * mono_string_to_utf8:
2478 * @s: a System.String
2480 * Return the UTF8 representation for @s.
2481 * the resulting buffer nedds to be freed with g_free().
2484 mono_string_to_utf8 (MonoString *s)
2487 GError *error = NULL;
2493 return g_strdup ("");
2495 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, NULL, &error);
2497 g_warning (error->message);
2498 g_error_free (error);
2505 * mono_string_to_utf16:
2508 * Return an null-terminated array of the utf-16 chars
2509 * contained in @s. The result must be freed with g_free().
2510 * This is a temporary helper until our string implementation
2511 * is reworked to always include the null terminating char.
2514 mono_string_to_utf16 (MonoString *s)
2521 as = g_malloc ((s->length * 2) + 2);
2522 as [(s->length * 2)] = '\0';
2523 as [(s->length * 2) + 1] = '\0';
2526 return (gunichar2 *)(as);
2529 memcpy (as, mono_string_chars(s), s->length * 2);
2530 return (gunichar2 *)(as);
2534 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString
2537 mono_string_from_utf16 (gunichar2 *data)
2539 MonoDomain *domain = mono_domain_get ();
2545 while (data [len]) len++;
2547 return mono_string_new_utf16 (domain, data, len);
2551 default_ex_handler (MonoException *ex)
2553 MonoObject *o = (MonoObject*)ex;
2554 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
2558 static MonoExceptionFunc ex_handler = default_ex_handler;
2561 mono_install_handler (MonoExceptionFunc func)
2563 ex_handler = func? func: default_ex_handler;
2567 * mono_raise_exception:
2568 * @ex: exception object
2570 * Signal the runtime that the exception @ex has been raised in unmanaged code.
2573 mono_raise_exception (MonoException *ex)
2576 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
2577 * that will cause gcc to omit the function epilog, causing problems when
2578 * the JIT tries to walk the stack, since the return address on the stack
2579 * will point into the next function in the executable, not this one.
2586 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
2588 MonoWaitHandle *res;
2590 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
2592 res->handle = handle;
2598 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data)
2600 MonoAsyncResult *res;
2602 res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
2605 res->async_state = state;
2607 res->handle = (MonoObject *) mono_wait_handle_new (domain, handle);
2609 res->sync_completed = FALSE;
2610 res->completed = FALSE;
2616 mono_message_init (MonoDomain *domain,
2617 MonoMethodMessage *this,
2618 MonoReflectionMethod *method,
2619 MonoArray *out_args)
2621 MonoMethodSignature *sig = method->method->signature;
2627 this->method = method;
2629 this->args = mono_array_new (domain, mono_defaults.object_class, sig->param_count);
2630 this->arg_types = mono_array_new (domain, mono_defaults.byte_class, sig->param_count);
2631 this->async_result = NULL;
2632 this->call_type = CallType_Sync;
2634 names = g_new (char *, sig->param_count);
2635 mono_method_get_param_names (method->method, (const char **) names);
2636 this->names = mono_array_new (domain, mono_defaults.string_class, sig->param_count);
2638 for (i = 0; i < sig->param_count; i++) {
2639 name = mono_string_new (domain, names [i]);
2640 mono_array_set (this->names, gpointer, i, name);
2644 for (i = 0, j = 0; i < sig->param_count; i++) {
2646 if (sig->params [i]->byref) {
2648 gpointer arg = mono_array_get (out_args, gpointer, j);
2649 mono_array_set (this->args, gpointer, i, arg);
2653 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
2658 mono_array_set (this->arg_types, guint8, i, arg_type);
2663 * mono_remoting_invoke:
2664 * @real_proxy: pointer to a RealProxy object
2665 * @msg: The MonoMethodMessage to execute
2666 * @exc: used to store exceptions
2667 * @out_args: used to store output arguments
2669 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
2670 * IMessage interface and it is not trivial to extract results from there. So
2671 * we call an helper method PrivateInvoke instead of calling
2672 * RealProxy::Invoke() directly.
2674 * Returns: the result object.
2677 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
2678 MonoObject **exc, MonoArray **out_args)
2680 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
2683 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
2689 klass = mono_defaults.real_proxy_class;
2691 for (i = 0; i < klass->method.count; ++i) {
2692 if (!strcmp ("PrivateInvoke", klass->methods [i]->name) &&
2693 klass->methods [i]->signature->param_count == 4) {
2694 im = klass->methods [i];
2700 real_proxy->vtable->domain->private_invoke_method = im;
2703 pa [0] = real_proxy;
2708 return mono_runtime_invoke (im, NULL, pa, exc);
2712 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
2713 MonoObject **exc, MonoArray **out_args)
2717 MonoMethodSignature *sig;
2718 int i, j, outarg_count = 0;
2720 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
2722 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
2723 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
2724 target = tp->rp->unwrapped_server;
2726 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
2730 domain = mono_domain_get ();
2731 method = msg->method->method;
2732 sig = method->signature;
2734 for (i = 0; i < sig->param_count; i++) {
2735 if (sig->params [i]->byref)
2739 *out_args = mono_array_new (domain, mono_defaults.object_class, outarg_count);
2742 for (i = 0, j = 0; i < sig->param_count; i++) {
2743 if (sig->params [i]->byref) {
2745 arg = mono_array_get (msg->args, gpointer, i);
2746 mono_array_set (*out_args, gpointer, j, arg);
2751 return mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
2755 mono_print_unhandled_exception (MonoObject *exc)
2757 char *message = (char *) "";
2761 gboolean free_message = FALSE;
2764 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
2765 klass = exc->vtable->klass;
2767 while (klass && method == NULL) {
2768 for (i = 0; i < klass->method.count; ++i) {
2769 method = klass->methods [i];
2770 if (!strcmp ("ToString", method->name) &&
2771 method->signature->param_count == 0 &&
2772 method->flags & METHOD_ATTRIBUTE_VIRTUAL &&
2773 method->flags & METHOD_ATTRIBUTE_PUBLIC) {
2780 klass = klass->parent;
2785 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
2787 message = mono_string_to_utf8 (str);
2788 free_message = TRUE;
2793 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
2794 * exc->vtable->klass->name, message);
2796 g_printerr ("\nUnhandled Exception: %s\n", message);
2803 * mono_delegate_ctor:
2804 * @this: pointer to an uninitialized delegate object
2805 * @target: target object
2806 * @addr: pointer to native code
2808 * This is used to initialize a delegate. We also insert the method_info if
2809 * we find the info with mono_jit_info_table_find().
2812 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
2814 MonoDomain *domain = mono_domain_get ();
2815 MonoDelegate *delegate = (MonoDelegate *)this;
2816 MonoMethod *method = NULL;
2823 class = this->vtable->klass;
2825 if ((ji = mono_jit_info_table_find (domain, addr))) {
2826 method = ji->method;
2827 delegate->method_info = mono_method_get_object (domain, method, NULL);
2830 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
2832 method = mono_marshal_get_remoting_invoke (method);
2833 delegate->method_ptr = mono_compile_method (method);
2834 delegate->target = target;
2836 delegate->method_ptr = addr;
2837 delegate->target = target;
2842 * mono_method_call_message_new:
2844 * Translates arguments pointers into a Message.
2847 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
2848 MonoDelegate **cb, MonoObject **state)
2850 MonoDomain *domain = mono_domain_get ();
2851 MonoMethodSignature *sig = method->signature;
2852 MonoMethodMessage *msg;
2855 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
2858 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
2859 count = sig->param_count - 2;
2861 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
2862 count = sig->param_count;
2865 for (i = 0; i < count; i++) {
2870 if (sig->params [i]->byref)
2871 vpos = *((gpointer *)params [i]);
2875 type = sig->params [i]->type;
2876 class = mono_class_from_mono_type (sig->params [i]);
2878 if (class->valuetype)
2879 arg = mono_value_box (domain, class, vpos);
2881 arg = *((MonoObject **)vpos);
2883 mono_array_set (msg->args, gpointer, i, arg);
2886 if (cb != NULL && state != NULL) {
2887 *cb = *((MonoDelegate **)params [i]);
2889 *state = *((MonoObject **)params [i]);
2896 * mono_method_return_message_restore:
2898 * Restore results from message based processing back to arguments pointers
2901 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
2903 MonoMethodSignature *sig = method->signature;
2904 int i, j, type, size;
2905 for (i = 0, j = 0; i < sig->param_count; i++) {
2906 MonoType *pt = sig->params [i];
2909 char *arg = mono_array_get (out_args, gpointer, j);
2913 case MONO_TYPE_VOID:
2914 g_assert_not_reached ();
2918 case MONO_TYPE_BOOLEAN:
2921 case MONO_TYPE_CHAR:
2928 case MONO_TYPE_VALUETYPE: {
2929 size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
2930 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
2933 case MONO_TYPE_STRING:
2934 case MONO_TYPE_CLASS:
2935 case MONO_TYPE_ARRAY:
2936 case MONO_TYPE_SZARRAY:
2937 case MONO_TYPE_OBJECT:
2938 **((MonoObject ***)params [i]) = (MonoObject *)arg;
2941 g_assert_not_reached ();
2950 * mono_load_remote_field:
2951 * @this: pointer to an object
2952 * @klass: klass of the object containing @field
2953 * @field: the field to load
2954 * @res: a storage to store the result
2956 * This method is called by the runtime on attempts to load fields of
2957 * transparent proxy objects. @this points to such TP, @klass is the class of
2958 * the object containing @field. @res is a storage location which can be
2959 * used to store the result.
2961 * Returns: an address pointing to the value of field.
2964 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
2966 static MonoMethod *getter = NULL;
2967 MonoDomain *domain = mono_domain_get ();
2968 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
2969 MonoClass *field_class;
2970 MonoMethodMessage *msg;
2971 MonoArray *out_args;
2975 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
2980 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
2981 mono_field_get_value (tp->rp->unwrapped_server, field, res);
2988 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
2989 MonoMethod *cm = mono_defaults.object_class->methods [i];
2991 if (!strcmp (cm->name, "FieldGetter")) {
2999 field_class = mono_class_from_mono_type (field->type);
3001 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3002 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
3003 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
3005 mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3006 mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3008 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3010 if (exc) mono_raise_exception ((MonoException *)exc);
3012 *res = mono_array_get (out_args, MonoObject *, 0);
3014 if (field_class->valuetype) {
3015 return ((char *)*res) + sizeof (MonoObject);
3021 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
3023 static MonoMethod *getter = NULL;
3024 MonoDomain *domain = mono_domain_get ();
3025 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3026 MonoClass *field_class;
3027 MonoMethodMessage *msg;
3028 MonoArray *out_args;
3029 MonoObject *exc, *res;
3031 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3033 field_class = mono_class_from_mono_type (field->type);
3035 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3037 if (field_class->valuetype) {
3038 res = mono_object_new (domain, field_class);
3039 val = ((gchar *) res) + sizeof (MonoObject);
3043 mono_field_get_value (tp->rp->unwrapped_server, field, val);
3050 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
3051 MonoMethod *cm = mono_defaults.object_class->methods [i];
3053 if (!strcmp (cm->name, "FieldGetter")) {
3061 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3062 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
3063 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
3065 mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3066 mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3068 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3070 if (exc) mono_raise_exception ((MonoException *)exc);
3072 res = mono_array_get (out_args, MonoObject *, 0);
3078 * mono_store_remote_field:
3079 * @this: pointer to an object
3080 * @klass: klass of the object containing @field
3081 * @field: the field to load
3082 * @val: the value/object to store
3084 * This method is called by the runtime on attempts to store fields of
3085 * transparent proxy objects. @this points to such TP, @klass is the class of
3086 * the object containing @field. @val is the new value to store in @field.
3089 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
3091 static MonoMethod *setter = NULL;
3092 MonoDomain *domain = mono_domain_get ();
3093 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3094 MonoClass *field_class;
3095 MonoMethodMessage *msg;
3096 MonoArray *out_args;
3100 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3102 field_class = mono_class_from_mono_type (field->type);
3104 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3105 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
3106 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
3113 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
3114 MonoMethod *cm = mono_defaults.object_class->methods [i];
3116 if (!strcmp (cm->name, "FieldSetter")) {
3124 if (field_class->valuetype)
3125 arg = mono_value_box (domain, field_class, val);
3127 arg = *((MonoObject **)val);
3130 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3131 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
3133 mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3134 mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3135 mono_array_set (msg->args, gpointer, 2, arg);
3137 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3139 if (exc) mono_raise_exception ((MonoException *)exc);
3143 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
3145 static MonoMethod *setter = NULL;
3146 MonoDomain *domain = mono_domain_get ();
3147 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3148 MonoClass *field_class;
3149 MonoMethodMessage *msg;
3150 MonoArray *out_args;
3153 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3155 field_class = mono_class_from_mono_type (field->type);
3157 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3158 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
3159 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
3166 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
3167 MonoMethod *cm = mono_defaults.object_class->methods [i];
3169 if (!strcmp (cm->name, "FieldSetter")) {
3177 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3178 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
3180 mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3181 mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3182 mono_array_set (msg->args, gpointer, 2, arg);
3184 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3186 if (exc) mono_raise_exception ((MonoException *)exc);