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;
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 * Retrieve the MonoMethod that would to be called on obj if obj is passed as
913 * the instance of a callvirt of method.
916 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method) {
920 MonoMethod *res = NULL;
922 klass = mono_object_class (obj);
923 if (klass == mono_defaults.transparent_proxy_class) {
924 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
930 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
933 vtable = klass->vtable;
935 /* check method->slot is a valid index: perform isinstance? */
936 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
938 res = vtable [klass->interface_offsets [method->klass->interface_id] + method->slot];
940 if (method->slot != -1)
941 res = vtable [method->slot];
945 if (!res) res = method; /* It may be an interface or abstract class method */
946 res = mono_marshal_get_remoting_invoke (res);
955 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
957 g_error ("runtime invoke called on uninitialized runtime");
961 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
964 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
966 return default_mono_runtime_invoke (method, obj, params, exc);
970 set_value (MonoType *type, void *dest, void *value, int deref_pointer) {
973 gpointer *p = (gpointer*)dest;
980 case MONO_TYPE_BOOLEAN:
983 guint8 *p = (guint8*)dest;
984 *p = *(guint8*)value;
989 case MONO_TYPE_CHAR: {
990 guint16 *p = (guint16*)dest;
991 *p = *(guint16*)value;
994 #if SIZEOF_VOID_P == 4
1000 gint32 *p = (gint32*)dest;
1001 *p = *(gint32*)value;
1004 #if SIZEOF_VOID_P == 8
1009 case MONO_TYPE_U8: {
1010 gint64 *p = (gint64*)dest;
1011 *p = *(gint64*)value;
1014 case MONO_TYPE_R4: {
1015 float *p = (float*)dest;
1016 *p = *(float*)value;
1019 case MONO_TYPE_R8: {
1020 double *p = (double*)dest;
1021 *p = *(double*)value;
1024 case MONO_TYPE_STRING:
1025 case MONO_TYPE_SZARRAY:
1026 case MONO_TYPE_CLASS:
1027 case MONO_TYPE_OBJECT:
1028 case MONO_TYPE_ARRAY:
1029 case MONO_TYPE_PTR: {
1030 gpointer *p = (gpointer*)dest;
1031 *p = deref_pointer? *(gpointer*)value: value;
1034 case MONO_TYPE_VALUETYPE:
1035 if (type->data.klass->enumtype) {
1036 t = type->data.klass->enum_basetype->type;
1040 size = mono_class_value_size (type->data.klass, NULL);
1041 memcpy (dest, value, size);
1045 g_warning ("got type %x", type->type);
1046 g_assert_not_reached ();
1051 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
1055 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
1057 dest = (char*)obj + field->offset;
1058 set_value (field->type, dest, value, FALSE);
1062 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
1066 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
1068 dest = (char*)vt->data + field->offset;
1069 set_value (field->type, dest, value, FALSE);
1073 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
1077 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
1079 src = (char*)obj + field->offset;
1080 set_value (field->type, value, src, TRUE);
1084 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
1088 MonoVTable *vtable = NULL;
1090 gboolean is_static = FALSE;
1091 gboolean is_ref = FALSE;
1093 switch (field->type->type) {
1094 case MONO_TYPE_STRING:
1095 case MONO_TYPE_OBJECT:
1096 case MONO_TYPE_CLASS:
1097 case MONO_TYPE_ARRAY:
1098 case MONO_TYPE_SZARRAY:
1103 case MONO_TYPE_BOOLEAN:
1106 case MONO_TYPE_CHAR:
1115 case MONO_TYPE_VALUETYPE:
1116 is_ref = field->type->byref;
1119 g_error ("type 0x%x not handled in "
1120 "mono_field_get_value_object", field->type->type);
1124 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
1126 vtable = mono_class_vtable (domain, field->parent);
1127 if (!vtable->initialized)
1128 mono_runtime_class_init (vtable);
1133 mono_field_static_get_value (vtable, field, &o);
1135 mono_field_get_value (obj, field, &o);
1140 /* boxed value type */
1141 klass = mono_class_from_mono_type (field->type);
1142 o = mono_object_new (domain, klass);
1143 v = ((gchar *) o) + sizeof (MonoObject);
1145 mono_field_static_get_value (vtable, field, v);
1147 mono_field_get_value (obj, field, v);
1155 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
1159 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
1161 src = (char*)vt->data + field->offset;
1162 set_value (field->type, value, src, TRUE);
1166 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
1168 default_mono_runtime_invoke (prop->set, obj, params, exc);
1172 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
1174 return default_mono_runtime_invoke (prop->get, obj, params, exc);
1179 mono_get_delegate_invoke (MonoClass *klass)
1186 for (i = 0; i < klass->method.count; ++i) {
1187 if (klass->methods [i]->name[0] == 'I' &&
1188 !strcmp ("Invoke", klass->methods [i]->name)) {
1189 im = klass->methods [i];
1199 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
1203 im = mono_get_delegate_invoke (delegate->vtable->klass);
1206 return mono_runtime_invoke (im, delegate, params, exc);
1209 static MonoArray* main_args;
1212 mono_runtime_get_main_args (void)
1218 fire_process_exit_event (void)
1220 MonoClassField *field;
1221 MonoDomain *domain = mono_domain_get ();
1223 MonoObject *delegate, *exc;
1225 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
1228 if (domain != mono_get_root_domain ())
1231 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
1232 if (delegate == NULL)
1237 mono_runtime_delegate_invoke (delegate, pa, &exc);
1241 * Execute a standard Main() method (argc/argv contains the
1242 * executable name). This method also sets the command line argument value
1243 * needed by System.Environment.
1246 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
1250 MonoArray *args = NULL;
1251 MonoDomain *domain = mono_domain_get ();
1252 gchar *utf8_fullpath;
1255 main_thread = mono_thread_current ();
1257 main_args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
1259 if (!g_path_is_absolute (argv [0])) {
1260 gchar *basename = g_path_get_basename (argv [0]);
1261 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
1265 utf8_fullpath = mono_utf8_from_external (fullpath);
1266 if(utf8_fullpath == NULL) {
1267 /* Printing the arg text will cause glib to
1268 * whinge about "Invalid UTF-8", but at least
1269 * its relevant, and shows the problem text
1272 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
1273 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
1280 utf8_fullpath = mono_utf8_from_external (argv[0]);
1281 if(utf8_fullpath == NULL) {
1282 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
1283 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
1288 mono_array_set (main_args, gpointer, 0, mono_string_new (domain, utf8_fullpath));
1289 g_free (utf8_fullpath);
1291 for (i = 1; i < argc; ++i) {
1295 utf8_arg=mono_utf8_from_external (argv[i]);
1296 if(utf8_arg==NULL) {
1297 /* Ditto the comment about Invalid UTF-8 here */
1298 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
1299 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
1303 arg = mono_string_new (domain, utf8_arg);
1304 mono_array_set (main_args, gpointer, i, arg);
1308 if (method->signature->param_count) {
1309 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
1310 for (i = 0; i < argc; ++i) {
1311 /* The encodings should all work, given that
1312 * we've checked all these args for the
1315 MonoString *arg = mono_string_new (domain, mono_utf8_from_external (argv [i]));
1316 mono_array_set (args, gpointer, i, arg);
1319 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
1322 mono_assembly_set_main (method->klass->image->assembly);
1324 result = mono_runtime_exec_main (method, args, exc);
1325 fire_process_exit_event ();
1329 /* Used in mono_unhandled_exception */
1331 create_unhandled_exception_eventargs (MonoObject *exc)
1335 MonoMethod *method = NULL;
1336 MonoBoolean is_terminating = TRUE;
1340 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
1343 mono_class_init (klass);
1345 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
1346 for (i = 0; i < klass->method.count; ++i) {
1347 method = klass->methods [i];
1348 if (!strcmp (".ctor", method->name) &&
1349 method->signature->param_count == 2 &&
1350 method->flags & METHOD_ATTRIBUTE_PUBLIC)
1358 args [1] = &is_terminating;
1360 obj = mono_object_new (mono_domain_get (), klass);
1361 mono_runtime_invoke (method, obj, args, NULL);
1367 * We call this function when we detect an unhandled exception
1368 * in the default domain.
1369 * It invokes the * UnhandledException event in AppDomain or prints
1370 * a warning to the console
1373 mono_unhandled_exception (MonoObject *exc)
1375 MonoDomain *domain = mono_domain_get ();
1376 MonoClassField *field;
1377 MonoObject *delegate;
1379 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
1380 "UnhandledException");
1383 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
1384 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
1386 /* set exitcode only in the main thread */
1387 if (mono_thread_current () == main_thread)
1388 mono_environment_exitcode_set (1);
1389 if (domain != mono_get_root_domain () || !delegate) {
1390 mono_print_unhandled_exception (exc);
1392 MonoObject *e = NULL;
1395 pa [0] = domain->domain;
1396 pa [1] = create_unhandled_exception_eventargs (exc);
1397 mono_runtime_delegate_invoke (delegate, pa, &e);
1400 gchar *msg = mono_string_to_utf8 (((MonoException *) e)->message);
1401 g_warning ("exception inside UnhandledException handler: %s\n", msg);
1409 * Launch a new thread to start all setup that requires managed code
1412 * main_func is called back from the thread with main_args as the
1413 * parameter. The callback function is expected to start Main()
1414 * eventually. This function then waits for all managed threads to
1418 mono_runtime_exec_managed_code (MonoDomain *domain,
1419 MonoMainThreadFunc main_func,
1422 mono_thread_create (domain, main_func, main_args);
1424 mono_thread_manage ();
1428 * Execute a standard Main() method (args doesn't contain the
1432 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
1442 domain = mono_object_domain (args);
1443 if (!domain->entry_assembly) {
1445 gchar *config_suffix;
1446 MonoAssembly *assembly;
1448 assembly = method->klass->image->assembly;
1449 domain->entry_assembly = assembly;
1450 domain->setup->application_base = mono_string_new (domain, assembly->basedir);
1452 config_suffix = g_strconcat (assembly->aname.name, ".exe.config", NULL);
1453 str = g_build_filename (assembly->basedir, config_suffix, NULL);
1454 g_free (config_suffix);
1455 domain->setup->configuration_file = mono_string_new (domain, str);
1459 /* FIXME: check signature of method */
1460 if (method->signature->ret->type == MONO_TYPE_I4) {
1462 res = mono_runtime_invoke (method, NULL, pa, exc);
1464 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
1468 mono_environment_exitcode_set (rval);
1470 mono_runtime_invoke (method, NULL, pa, exc);
1474 /* If the return type of Main is void, only
1475 * set the exitcode if an exception was thrown
1476 * (we don't want to blow away an
1477 * explicitly-set exit code)
1480 mono_environment_exitcode_set (rval);
1488 mono_install_runtime_invoke (MonoInvokeFunc func)
1490 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
1494 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
1497 MonoMethodSignature *sig = method->signature;
1498 gpointer *pa = NULL;
1501 if (NULL != params) {
1502 pa = alloca (sizeof (gpointer) * mono_array_length (params));
1503 for (i = 0; i < mono_array_length (params); i++) {
1504 if (sig->params [i]->byref) {
1508 switch (sig->params [i]->type) {
1511 case MONO_TYPE_BOOLEAN:
1514 case MONO_TYPE_CHAR:
1523 case MONO_TYPE_VALUETYPE:
1524 if (sig->params [i]->byref) {
1525 /* MS seems to create the objects if a null is passed in */
1526 if (! ((gpointer *)params->vector)[i])
1527 ((gpointer*)params->vector)[i] = mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i]));
1530 g_assert (((gpointer*)params->vector) [i]);
1531 pa [i] = (char *)(((gpointer *)params->vector)[i]) + sizeof (MonoObject);
1533 case MONO_TYPE_STRING:
1534 case MONO_TYPE_OBJECT:
1535 case MONO_TYPE_CLASS:
1536 case MONO_TYPE_ARRAY:
1537 case MONO_TYPE_SZARRAY:
1538 if (sig->params [i]->byref)
1539 pa [i] = &(((gpointer *)params->vector)[i]);
1541 pa [i] = (char *)(((gpointer *)params->vector)[i]);
1544 g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
1549 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
1552 obj = mono_object_new (mono_domain_get (), method->klass);
1553 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
1554 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
1556 if (method->klass->valuetype)
1557 o = mono_object_unbox (obj);
1561 mono_runtime_invoke (method, o, pa, exc);
1564 /* obj must be already unboxed if needed */
1565 return mono_runtime_invoke (method, obj, pa, exc);
1570 out_of_memory (size_t size)
1573 * we could allocate at program startup some memory that we could release
1574 * back to the system at this point if we're really low on memory (ie, size is
1575 * lower than the memory we set apart)
1577 mono_raise_exception (mono_domain_get ()->out_of_memory_ex);
1581 * mono_object_allocate:
1582 * @size: number of bytes to allocate
1584 * This is a very simplistic routine until we have our GC-aware
1587 * Returns: an allocated object of size @size, or NULL on failure.
1589 static inline void *
1590 mono_object_allocate (size_t size)
1593 /* if this is changed to GC_debug_malloc(), we need to change also metadata/gc.c */
1594 void *o = GC_MALLOC (size);
1596 void *o = calloc (1, size);
1598 mono_stats.new_object_count++;
1601 out_of_memory (size);
1605 #if CREATION_SPEEDUP
1606 static inline void *
1607 mono_object_allocate_spec (size_t size, void *gcdescr)
1609 /* if this is changed to GC_debug_malloc(), we need to change also metadata/gc.c */
1610 void *o = GC_GCJ_MALLOC (size, gcdescr);
1611 mono_stats.new_object_count++;
1614 out_of_memory (size);
1621 * @klass: the class of the object that we want to create
1623 * Returns: A newly created object whose definition is
1624 * looked up using @klass
1627 mono_object_new (MonoDomain *domain, MonoClass *klass)
1629 MONO_ARCH_SAVE_REGS;
1630 return mono_object_new_specific (mono_class_vtable (domain, klass));
1634 * mono_object_new_specific:
1635 * @vtable: the vtable of the object that we want to create
1637 * Returns: A newly created object with class and domain specified
1641 mono_object_new_specific (MonoVTable *vtable)
1645 MONO_ARCH_SAVE_REGS;
1650 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
1653 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
1657 mono_class_init (klass);
1659 for (i = 0; i < klass->method.count; ++i) {
1660 if (!strcmp ("CreateProxyForType", klass->methods [i]->name) &&
1661 klass->methods [i]->signature->param_count == 1) {
1662 im = klass->methods [i];
1667 vtable->domain->create_proxy_for_type_method = im;
1670 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
1672 o = mono_runtime_invoke (im, NULL, pa, NULL);
1673 if (o != NULL) return o;
1676 return mono_object_new_alloc_specific (vtable);
1680 mono_object_new_fast (MonoVTable *vtable)
1683 MONO_ARCH_SAVE_REGS;
1685 #if CREATION_SPEEDUP
1686 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
1687 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
1689 // printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name);
1690 o = mono_object_allocate (vtable->klass->instance_size);
1694 o = mono_object_allocate (vtable->klass->instance_size);
1701 mono_object_new_alloc_specific (MonoVTable *vtable)
1705 #if CREATION_SPEEDUP
1706 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
1707 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
1709 // printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name);
1710 o = mono_object_allocate (vtable->klass->instance_size);
1714 o = mono_object_allocate (vtable->klass->instance_size);
1717 if (vtable->klass->has_finalize)
1718 mono_object_register_finalizer (o);
1720 mono_profiler_allocation (o, vtable->klass);
1725 * mono_object_new_from_token:
1726 * @image: Context where the type_token is hosted
1727 * @token: a token of the type that we want to create
1729 * Returns: A newly created object whose definition is
1730 * looked up using @token in the @image image
1733 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
1737 class = mono_class_get (image, token);
1739 return mono_object_new (domain, class);
1744 * mono_object_clone:
1745 * @obj: the object to clone
1747 * Returns: A newly created object who is a shallow copy of @obj
1750 mono_object_clone (MonoObject *obj)
1755 size = obj->vtable->klass->instance_size;
1756 o = mono_object_allocate (size);
1757 mono_profiler_allocation (o, obj->vtable->klass);
1759 memcpy (o, obj, size);
1761 if (obj->vtable->klass->has_finalize)
1762 mono_object_register_finalizer (o);
1768 * @array: the array to clone
1770 * Returns: A newly created array who is a shallow copy of @array
1773 mono_array_clone (MonoArray *array)
1778 MonoClass *klass = array->obj.vtable->klass;
1780 MONO_ARCH_SAVE_REGS;
1782 if (array->bounds == NULL) {
1783 size = mono_array_length (array);
1784 o = mono_array_new_full (((MonoObject *)array)->vtable->domain,
1785 klass, &size, NULL);
1787 size *= mono_array_element_size (klass);
1788 memcpy (o, array, sizeof (MonoArray) + size);
1793 sizes = alloca (klass->rank * sizeof(guint32) * 2);
1794 size = mono_array_element_size (klass);
1795 for (i = 0; i < klass->rank; ++i) {
1796 sizes [i] = array->bounds [i].length;
1797 size *= array->bounds [i].length;
1798 sizes [i + klass->rank] = array->bounds [i].lower_bound;
1800 o = mono_array_new_full (((MonoObject *)array)->vtable->domain,
1801 klass, sizes, sizes + klass->rank);
1802 memcpy (o, array, sizeof(MonoArray) + size);
1807 /* helper macros to check for overflow when calculating the size of arrays */
1808 #define MYGUINT32_MAX 4294967295U
1809 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1810 (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
1811 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1812 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1813 (guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a))
1816 * mono_array_new_full:
1817 * @domain: domain where the object is created
1818 * @array_class: array class
1819 * @lengths: lengths for each dimension in the array
1820 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
1822 * This routine creates a new array objects with the given dimensions,
1823 * lower bounds and type.
1826 mono_array_new_full (MonoDomain *domain, MonoClass *array_class,
1827 guint32 *lengths, guint32 *lower_bounds)
1829 guint32 byte_len, len;
1832 MonoArrayBounds *bounds;
1836 if (!array_class->inited)
1837 mono_class_init (array_class);
1839 byte_len = mono_array_element_size (array_class);
1842 if (array_class->rank == 1 &&
1843 (lower_bounds == NULL || lower_bounds [0] == 0)) {
1848 bounds = GC_MALLOC (sizeof (MonoArrayBounds) * array_class->rank);
1850 bounds = g_malloc0 (sizeof (MonoArrayBounds) * array_class->rank);
1852 for (i = 0; i < array_class->rank; ++i) {
1853 bounds [i].length = lengths [i];
1854 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
1855 out_of_memory (MYGUINT32_MAX);
1860 for (i = 0; i < array_class->rank; ++i)
1861 bounds [i].lower_bound = lower_bounds [i];
1864 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
1865 out_of_memory (MYGUINT32_MAX);
1867 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
1868 out_of_memory (MYGUINT32_MAX);
1869 byte_len += sizeof (MonoArray);
1871 * Following three lines almost taken from mono_object_new ():
1872 * they need to be kept in sync.
1874 vtable = mono_class_vtable (domain, array_class);
1875 #if CREATION_SPEEDUP
1876 if (vtable->gc_descr != GC_NO_DESCRIPTOR)
1877 o = mono_object_allocate_spec (byte_len, vtable);
1879 o = mono_object_allocate (byte_len);
1883 o = mono_object_allocate (byte_len);
1887 array = (MonoArray*)o;
1889 array->bounds = bounds;
1890 array->max_length = len;
1892 mono_profiler_allocation (o, array_class);
1899 * @domain: domain where the object is created
1900 * @eclass: element class
1901 * @n: number of array elements
1903 * This routine creates a new szarray with @n elements of type @eclass.
1906 mono_array_new (MonoDomain *domain, MonoClass *eclass, guint32 n)
1910 MONO_ARCH_SAVE_REGS;
1912 ac = mono_array_class_get (eclass, 1);
1913 g_assert (ac != NULL);
1915 return mono_array_new_specific (mono_class_vtable (domain, ac), n);
1919 * mono_array_new_specific:
1920 * @vtable: a vtable in the appropriate domain for an initialized class
1921 * @n: number of array elements
1923 * This routine is a fast alternative to mono_array_new() for code which
1924 * can be sure about the domain it operates in.
1927 mono_array_new_specific (MonoVTable *vtable, guint32 n)
1931 guint32 byte_len, elem_size;
1933 MONO_ARCH_SAVE_REGS;
1935 elem_size = mono_array_element_size (vtable->klass);
1936 if (CHECK_MUL_OVERFLOW_UN (n, elem_size))
1937 out_of_memory (MYGUINT32_MAX);
1938 byte_len = n * elem_size;
1939 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
1940 out_of_memory (MYGUINT32_MAX);
1941 byte_len += sizeof (MonoArray);
1942 #if CREATION_SPEEDUP
1943 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
1944 o = mono_object_allocate_spec (byte_len, vtable);
1946 // printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name);
1947 o = mono_object_allocate (byte_len);
1951 o = mono_object_allocate (byte_len);
1955 ao = (MonoArray *)o;
1958 mono_profiler_allocation (o, vtable->klass);
1964 * mono_string_new_utf16:
1965 * @text: a pointer to an utf16 string
1966 * @len: the length of the string
1968 * Returns: A newly created string object which contains @text.
1971 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
1975 s = mono_string_new_size (domain, len);
1976 g_assert (s != NULL);
1978 memcpy (mono_string_chars (s), text, len * 2);
1984 * mono_string_new_size:
1985 * @text: a pointer to an utf16 string
1986 * @len: the length of the string
1988 * Returns: A newly created string object of @len
1991 mono_string_new_size (MonoDomain *domain, gint32 len)
1995 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
1997 /* overflow ? can't fit it, can't allocate it! */
2001 vtable = mono_class_vtable (domain, mono_defaults.string_class);
2003 #if CREATION_SPEEDUP
2004 if (vtable->gc_descr != GC_NO_DESCRIPTOR)
2005 s = mono_object_allocate_spec (size, vtable);
2007 s = (MonoString*)mono_object_allocate (size);
2008 s->object.vtable = vtable;
2011 s = (MonoString*)mono_object_allocate (size);
2012 s->object.vtable = vtable;
2016 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
2022 * mono_string_new_len:
2023 * @text: a pointer to an utf8 string
2024 * @length: number of bytes in @text to consider
2026 * Returns: A newly created string object which contains @text.
2029 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
2031 GError *error = NULL;
2032 MonoString *o = NULL;
2034 glong items_written;
2036 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
2039 o = mono_string_new_utf16 (domain, ut, items_written);
2041 g_error_free (error);
2050 * @text: a pointer to an utf8 string
2052 * Returns: A newly created string object which contains @text.
2055 mono_string_new (MonoDomain *domain, const char *text)
2057 GError *error = NULL;
2058 MonoString *o = NULL;
2060 glong items_written;
2065 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
2068 o = mono_string_new_utf16 (domain, ut, items_written);
2070 g_error_free (error);
2078 * mono_string_new_wrapper:
2079 * @text: pointer to utf8 characters.
2081 * Helper function to create a string object from @text in the current domain.
2084 mono_string_new_wrapper (const char *text)
2086 MonoDomain *domain = mono_domain_get ();
2088 MONO_ARCH_SAVE_REGS;
2091 return mono_string_new (domain, text);
2098 * @class: the class of the value
2099 * @value: a pointer to the unboxed data
2101 * Returns: A newly created object which contains @value.
2104 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
2110 g_assert (class->valuetype);
2112 vtable = mono_class_vtable (domain, class);
2113 size = mono_class_instance_size (class);
2114 res = mono_object_allocate (size);
2115 res->vtable = vtable;
2116 mono_profiler_allocation (res, class);
2118 size = size - sizeof (MonoObject);
2120 #if NO_UNALIGNED_ACCESS
2121 memcpy ((char *)res + sizeof (MonoObject), value, size);
2125 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
2128 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
2131 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
2134 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
2137 memcpy ((char *)res + sizeof (MonoObject), value, size);
2140 if (class->has_finalize)
2141 mono_object_register_finalizer (res);
2146 mono_object_get_domain (MonoObject *obj)
2148 return mono_object_domain (obj);
2152 mono_object_get_class (MonoObject *obj)
2154 return mono_object_class (obj);
2158 mono_object_unbox (MonoObject *obj)
2160 /* add assert for valuetypes? */
2161 g_assert (obj->vtable->klass->valuetype);
2162 return ((char*)obj) + sizeof (MonoObject);
2166 * mono_object_isinst:
2168 * @klass: a pointer to a class
2170 * Returns: @obj if @obj is derived from @klass
2173 mono_object_isinst (MonoObject *obj, MonoClass *klass)
2176 mono_class_init (klass);
2178 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)
2179 return mono_object_isinst_mbyref (obj, klass);
2184 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
2188 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
2197 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2198 if ((klass->interface_id <= vt->max_interface_id) &&
2199 (vt->interface_offsets [klass->interface_id] != 0))
2203 MonoClass *oklass = vt->klass;
2204 if ((oklass == mono_defaults.transparent_proxy_class))
2205 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2207 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
2211 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
2213 MonoDomain *domain = mono_domain_get ();
2215 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
2216 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
2217 MonoMethod *im = NULL;
2221 for (i = 0; i < rpklass->method.count; ++i) {
2222 if (!strcmp ("CanCastTo", rpklass->methods [i]->name)) {
2223 im = rpklass->methods [i];
2228 im = mono_object_get_virtual_method (rp, im);
2231 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
2234 res = mono_runtime_invoke (im, rp, pa, NULL);
2236 if (*(MonoBoolean *) mono_object_unbox(res)) {
2237 /* Update the vtable of the remote type, so it can safely cast to this new type */
2238 mono_upgrade_remote_class (domain, ((MonoTransparentProxy *)obj)->remote_class, klass);
2239 obj->vtable = ((MonoTransparentProxy *)obj)->remote_class->vtable;
2248 * mono_object_castclass_mbyref:
2250 * @klass: a pointer to a class
2252 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
2255 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
2257 if (!obj) return NULL;
2258 if (mono_object_isinst_mbyref (obj, klass)) return obj;
2260 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
2262 "InvalidCastException"));
2267 MonoDomain *orig_domain;
2273 str_lookup (MonoDomain *domain, gpointer user_data)
2275 LDStrInfo *info = user_data;
2276 if (info->res || domain == info->orig_domain)
2278 mono_domain_lock (domain);
2279 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
2280 mono_domain_unlock (domain);
2284 mono_string_is_interned_lookup (MonoString *str, int insert)
2286 MonoGHashTable *ldstr_table;
2289 char *ins = g_malloc (4 + str->length * 2);
2292 /* Encode the length */
2293 /* Same code as in mono_image_insert_string () */
2295 mono_metadata_encode_value (1 | (2 * str->length), p, &p);
2298 * ins is stored in the hash table as a key and needs to have the same
2299 * representation as in the metadata: we swap the character bytes on big
2302 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
2305 char *p2 = (char *)mono_string_chars (str);
2306 for (i = 0; i < str->length; ++i) {
2313 memcpy (p, mono_string_chars (str), str->length * 2);
2315 domain = ((MonoObject *)str)->vtable->domain;
2316 ldstr_table = domain->ldstr_table;
2317 mono_domain_lock (domain);
2318 if ((res = mono_g_hash_table_lookup (ldstr_table, ins))) {
2319 mono_domain_unlock (domain);
2324 mono_g_hash_table_insert (ldstr_table, ins, str);
2325 mono_domain_unlock (domain);
2328 LDStrInfo ldstr_info;
2329 ldstr_info.orig_domain = domain;
2330 ldstr_info.ins = ins;
2331 ldstr_info.res = NULL;
2333 mono_domain_foreach (str_lookup, &ldstr_info);
2334 if (ldstr_info.res) {
2336 * the string was already interned in some other domain:
2337 * intern it in the current one as well.
2339 mono_g_hash_table_insert (ldstr_table, ins, str);
2340 mono_domain_unlock (domain);
2344 mono_domain_unlock (domain);
2350 mono_string_is_interned (MonoString *o)
2352 return mono_string_is_interned_lookup (o, FALSE);
2356 mono_string_intern (MonoString *str)
2358 return mono_string_is_interned_lookup (str, TRUE);
2363 * @domain: the domain where the string will be used.
2364 * @image: a metadata context
2365 * @idx: index into the user string table.
2367 * Implementation for the ldstr opcode.
2370 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
2372 const char *str, *sig;
2376 MONO_ARCH_SAVE_REGS;
2379 return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx);
2381 sig = str = mono_metadata_user_string (image, idx);
2383 mono_domain_lock (domain);
2384 if ((o = mono_g_hash_table_lookup (domain->ldstr_table, sig))) {
2385 mono_domain_unlock (domain);
2389 len2 = mono_metadata_decode_blob_size (str, &str);
2392 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
2393 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
2396 guint16 *p2 = (guint16*)mono_string_chars (o);
2397 for (i = 0; i < len2; ++i) {
2398 *p2 = GUINT16_FROM_LE (*p2);
2403 mono_g_hash_table_insert (domain->ldstr_table, (gpointer)sig, o);
2404 mono_domain_unlock (domain);
2410 * mono_string_to_utf8:
2411 * @s: a System.String
2413 * Return the UTF8 representation for @s.
2414 * the resulting buffer nedds to be freed with g_free().
2417 mono_string_to_utf8 (MonoString *s)
2420 GError *error = NULL;
2426 return g_strdup ("");
2428 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, NULL, &error);
2430 g_warning (error->message);
2431 g_error_free (error);
2438 * mono_string_to_utf16:
2441 * Return an null-terminated array of the utf-16 chars
2442 * contained in @s. The result must be freed with g_free().
2443 * This is a temporary helper until our string implementation
2444 * is reworked to always include the null terminating char.
2447 mono_string_to_utf16 (MonoString *s)
2454 as = g_malloc ((s->length * 2) + 2);
2455 as [(s->length * 2)] = '\0';
2456 as [(s->length * 2) + 1] = '\0';
2459 return (gunichar2 *)(as);
2462 memcpy (as, mono_string_chars(s), s->length * 2);
2463 return (gunichar2 *)(as);
2467 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString
2470 mono_string_from_utf16 (gunichar2 *data)
2472 MonoDomain *domain = mono_domain_get ();
2478 while (data [len]) len++;
2480 return mono_string_new_utf16 (domain, data, len);
2484 default_ex_handler (MonoException *ex)
2486 MonoObject *o = (MonoObject*)ex;
2487 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
2491 static MonoExceptionFunc ex_handler = default_ex_handler;
2494 mono_install_handler (MonoExceptionFunc func)
2496 ex_handler = func? func: default_ex_handler;
2500 * mono_raise_exception:
2501 * @ex: exception object
2503 * Signal the runtime that the exception @ex has been raised in unmanaged code.
2506 mono_raise_exception (MonoException *ex)
2509 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
2510 * that will cause gcc to omit the function epilog, causing problems when
2511 * the JIT tries to walk the stack, since the return address on the stack
2512 * will point into the next function in the executable, not this one.
2519 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
2521 MonoWaitHandle *res;
2523 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
2525 res->handle = handle;
2531 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data)
2533 MonoAsyncResult *res;
2535 res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
2538 res->async_state = state;
2540 res->handle = (MonoObject *) mono_wait_handle_new (domain, handle);
2542 res->sync_completed = FALSE;
2543 res->completed = FALSE;
2549 mono_message_init (MonoDomain *domain,
2550 MonoMethodMessage *this,
2551 MonoReflectionMethod *method,
2552 MonoArray *out_args)
2554 MonoMethodSignature *sig = method->method->signature;
2560 this->method = method;
2562 this->args = mono_array_new (domain, mono_defaults.object_class, sig->param_count);
2563 this->arg_types = mono_array_new (domain, mono_defaults.byte_class, sig->param_count);
2564 this->async_result = NULL;
2565 this->call_type = CallType_Sync;
2567 names = g_new (char *, sig->param_count);
2568 mono_method_get_param_names (method->method, (const char **) names);
2569 this->names = mono_array_new (domain, mono_defaults.string_class, sig->param_count);
2571 for (i = 0; i < sig->param_count; i++) {
2572 name = mono_string_new (domain, names [i]);
2573 mono_array_set (this->names, gpointer, i, name);
2577 for (i = 0, j = 0; i < sig->param_count; i++) {
2579 if (sig->params [i]->byref) {
2581 gpointer arg = mono_array_get (out_args, gpointer, j);
2582 mono_array_set (this->args, gpointer, i, arg);
2586 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
2591 mono_array_set (this->arg_types, guint8, i, arg_type);
2596 * mono_remoting_invoke:
2597 * @real_proxy: pointer to a RealProxy object
2598 * @msg: The MonoMethodMessage to execute
2599 * @exc: used to store exceptions
2600 * @out_args: used to store output arguments
2602 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
2603 * IMessage interface and it is not trivial to extract results from there. So
2604 * we call an helper method PrivateInvoke instead of calling
2605 * RealProxy::Invoke() directly.
2607 * Returns: the result object.
2610 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
2611 MonoObject **exc, MonoArray **out_args)
2613 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
2616 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
2622 klass = mono_defaults.real_proxy_class;
2624 for (i = 0; i < klass->method.count; ++i) {
2625 if (!strcmp ("PrivateInvoke", klass->methods [i]->name) &&
2626 klass->methods [i]->signature->param_count == 4) {
2627 im = klass->methods [i];
2633 real_proxy->vtable->domain->private_invoke_method = im;
2636 pa [0] = real_proxy;
2641 return mono_runtime_invoke (im, NULL, pa, exc);
2645 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
2646 MonoObject **exc, MonoArray **out_args)
2650 MonoMethodSignature *sig;
2651 int i, j, outarg_count = 0;
2653 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
2655 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
2656 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
2657 target = tp->rp->unwrapped_server;
2659 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
2663 domain = mono_domain_get ();
2664 method = msg->method->method;
2665 sig = method->signature;
2667 for (i = 0; i < sig->param_count; i++) {
2668 if (sig->params [i]->byref)
2672 *out_args = mono_array_new (domain, mono_defaults.object_class, outarg_count);
2675 for (i = 0, j = 0; i < sig->param_count; i++) {
2676 if (sig->params [i]->byref) {
2678 arg = mono_array_get (msg->args, gpointer, i);
2679 mono_array_set (*out_args, gpointer, j, arg);
2684 return mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
2688 mono_print_unhandled_exception (MonoObject *exc)
2690 char *message = (char *) "";
2694 gboolean free_message = FALSE;
2697 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
2698 klass = exc->vtable->klass;
2700 while (klass && method == NULL) {
2701 for (i = 0; i < klass->method.count; ++i) {
2702 method = klass->methods [i];
2703 if (!strcmp ("ToString", method->name) &&
2704 method->signature->param_count == 0 &&
2705 method->flags & METHOD_ATTRIBUTE_VIRTUAL &&
2706 method->flags & METHOD_ATTRIBUTE_PUBLIC) {
2713 klass = klass->parent;
2718 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
2720 message = mono_string_to_utf8 (str);
2721 free_message = TRUE;
2726 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
2727 * exc->vtable->klass->name, message);
2729 g_printerr ("\nUnhandled Exception: %s\n", message);
2736 * mono_delegate_ctor:
2737 * @this: pointer to an uninitialized delegate object
2738 * @target: target object
2739 * @addr: pointer to native code
2741 * This is used to initialize a delegate. We also insert the method_info if
2742 * we find the info with mono_jit_info_table_find().
2745 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
2747 MonoDomain *domain = mono_domain_get ();
2748 MonoDelegate *delegate = (MonoDelegate *)this;
2749 MonoMethod *method = NULL;
2756 class = this->vtable->klass;
2758 if ((ji = mono_jit_info_table_find (domain, addr))) {
2759 method = ji->method;
2760 delegate->method_info = mono_method_get_object (domain, method, NULL);
2763 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
2765 method = mono_marshal_get_remoting_invoke (method);
2766 delegate->method_ptr = mono_compile_method (method);
2767 delegate->target = target;
2769 delegate->method_ptr = addr;
2770 delegate->target = target;
2775 * mono_method_call_message_new:
2777 * Translates arguments pointers into a Message.
2780 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
2781 MonoDelegate **cb, MonoObject **state)
2783 MonoDomain *domain = mono_domain_get ();
2784 MonoMethodSignature *sig = method->signature;
2785 MonoMethodMessage *msg;
2788 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
2791 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
2792 count = sig->param_count - 2;
2794 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
2795 count = sig->param_count;
2798 for (i = 0; i < count; i++) {
2803 if (sig->params [i]->byref)
2804 vpos = *((gpointer *)params [i]);
2808 type = sig->params [i]->type;
2809 class = mono_class_from_mono_type (sig->params [i]);
2811 if (class->valuetype)
2812 arg = mono_value_box (domain, class, vpos);
2814 arg = *((MonoObject **)vpos);
2816 mono_array_set (msg->args, gpointer, i, arg);
2819 if (cb != NULL && state != NULL) {
2820 *cb = *((MonoDelegate **)params [i]);
2822 *state = *((MonoObject **)params [i]);
2829 * mono_method_return_message_restore:
2831 * Restore results from message based processing back to arguments pointers
2834 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
2836 MonoMethodSignature *sig = method->signature;
2837 int i, j, type, size;
2838 for (i = 0, j = 0; i < sig->param_count; i++) {
2839 MonoType *pt = sig->params [i];
2842 char *arg = mono_array_get (out_args, gpointer, j);
2846 case MONO_TYPE_VOID:
2847 g_assert_not_reached ();
2851 case MONO_TYPE_BOOLEAN:
2854 case MONO_TYPE_CHAR:
2861 case MONO_TYPE_VALUETYPE: {
2862 size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
2863 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
2866 case MONO_TYPE_STRING:
2867 case MONO_TYPE_CLASS:
2868 case MONO_TYPE_ARRAY:
2869 case MONO_TYPE_SZARRAY:
2870 case MONO_TYPE_OBJECT:
2871 **((MonoObject ***)params [i]) = (MonoObject *)arg;
2874 g_assert_not_reached ();
2883 * mono_load_remote_field:
2884 * @this: pointer to an object
2885 * @klass: klass of the object containing @field
2886 * @field: the field to load
2887 * @res: a storage to store the result
2889 * This method is called by the runtime on attempts to load fields of
2890 * transparent proxy objects. @this points to such TP, @klass is the class of
2891 * the object containing @field. @res is a storage location which can be
2892 * used to store the result.
2894 * Returns: an address pointing to the value of field.
2897 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
2899 static MonoMethod *getter = NULL;
2900 MonoDomain *domain = mono_domain_get ();
2901 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
2902 MonoClass *field_class;
2903 MonoMethodMessage *msg;
2904 MonoArray *out_args;
2908 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
2913 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
2914 mono_field_get_value (tp->rp->unwrapped_server, field, res);
2921 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
2922 MonoMethod *cm = mono_defaults.object_class->methods [i];
2924 if (!strcmp (cm->name, "FieldGetter")) {
2932 field_class = mono_class_from_mono_type (field->type);
2934 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
2935 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
2936 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
2938 mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
2939 mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
2941 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
2943 if (exc) mono_raise_exception ((MonoException *)exc);
2945 *res = mono_array_get (out_args, MonoObject *, 0);
2947 if (field_class->valuetype) {
2948 return ((char *)*res) + sizeof (MonoObject);
2954 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
2956 static MonoMethod *getter = NULL;
2957 MonoDomain *domain = mono_domain_get ();
2958 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
2959 MonoClass *field_class;
2960 MonoMethodMessage *msg;
2961 MonoArray *out_args;
2962 MonoObject *exc, *res;
2964 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
2966 field_class = mono_class_from_mono_type (field->type);
2968 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
2970 if (field_class->valuetype) {
2971 res = mono_object_new (domain, field_class);
2972 val = ((gchar *) res) + sizeof (MonoObject);
2976 mono_field_get_value (tp->rp->unwrapped_server, field, val);
2983 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
2984 MonoMethod *cm = mono_defaults.object_class->methods [i];
2986 if (!strcmp (cm->name, "FieldGetter")) {
2994 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
2995 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
2996 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
2998 mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
2999 mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3001 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3003 if (exc) mono_raise_exception ((MonoException *)exc);
3005 res = mono_array_get (out_args, MonoObject *, 0);
3011 * mono_store_remote_field:
3012 * @this: pointer to an object
3013 * @klass: klass of the object containing @field
3014 * @field: the field to load
3015 * @val: the value/object to store
3017 * This method is called by the runtime on attempts to store fields of
3018 * transparent proxy objects. @this points to such TP, @klass is the class of
3019 * the object containing @field. @val is the new value to store in @field.
3022 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
3024 static MonoMethod *setter = NULL;
3025 MonoDomain *domain = mono_domain_get ();
3026 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3027 MonoClass *field_class;
3028 MonoMethodMessage *msg;
3029 MonoArray *out_args;
3033 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3035 field_class = mono_class_from_mono_type (field->type);
3037 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3038 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
3039 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)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, "FieldSetter")) {
3057 if (field_class->valuetype)
3058 arg = mono_value_box (domain, field_class, val);
3060 arg = *((MonoObject **)val);
3063 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3064 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
3066 mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3067 mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3068 mono_array_set (msg->args, gpointer, 2, arg);
3070 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3072 if (exc) mono_raise_exception ((MonoException *)exc);
3076 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
3078 static MonoMethod *setter = NULL;
3079 MonoDomain *domain = mono_domain_get ();
3080 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3081 MonoClass *field_class;
3082 MonoMethodMessage *msg;
3083 MonoArray *out_args;
3086 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3088 field_class = mono_class_from_mono_type (field->type);
3090 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3091 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
3092 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
3099 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
3100 MonoMethod *cm = mono_defaults.object_class->methods [i];
3102 if (!strcmp (cm->name, "FieldSetter")) {
3110 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3111 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
3113 mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3114 mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3115 mono_array_set (msg->args, gpointer, 2, arg);
3117 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3119 if (exc) mono_raise_exception ((MonoException *)exc);