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 mono_runtime_invoke (method, this, NULL, NULL);
64 /* The pseudo algorithm for type initialization from the spec
65 Note it doesn't say anything about domains - only threads.
67 2. If the type is initialized you are done.
68 2.1. If the type is not yet initialized, try to take an
70 2.2. If successful, record this thread as responsible for
71 initializing the type and proceed to step 2.3.
72 2.2.1. If not, see whether this thread or any thread
73 waiting for this thread to complete already holds the lock.
74 2.2.2. If so, return since blocking would create a deadlock. This thread
75 will now see an incompletely initialized state for the type,
76 but no deadlock will arise.
77 2.2.3 If not, block until the type is initialized then return.
78 2.3 Initialize the parent type and then all interfaces implemented
80 2.4 Execute the type initialization code for this type.
81 2.5 Mark the type as initialized, release the initialization lock,
82 awaken any threads waiting for this type to be initialized,
89 guint32 initializing_tid;
90 guint32 waiting_count;
91 CRITICAL_SECTION initialization_section;
92 } TypeInitializationLock;
94 /* for locking access to type_initialization_hash and blocked_thread_hash */
95 static CRITICAL_SECTION type_initialization_section;
97 /* from vtable to lock */
98 static GHashTable *type_initialization_hash;
100 /* from thread id to thread id being waited on */
101 static GHashTable *blocked_thread_hash;
104 static MonoThread *main_thread;
107 mono_type_initialization_init (void)
109 InitializeCriticalSection (&type_initialization_section);
110 type_initialization_hash = g_hash_table_new (NULL, NULL);
111 blocked_thread_hash = g_hash_table_new (NULL, NULL);
115 * mono_runtime_class_init:
116 * @vtable: vtable that needs to be initialized
118 * This routine calls the class constructor for @vtable.
121 mono_runtime_class_init (MonoVTable *vtable)
125 MonoException *exc_to_throw;
126 MonoMethod *method = NULL;
133 if (vtable->initialized)
138 klass = vtable->klass;
140 for (i = 0; i < klass->method.count; ++i) {
141 method = klass->methods [i];
142 if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) &&
143 (strcmp (".cctor", method->name) == 0)) {
150 MonoDomain *domain = vtable->domain;
151 TypeInitializationLock *lock;
152 guint32 tid = GetCurrentThreadId();
153 int do_initialization = 0;
154 MonoDomain *last_domain = NULL;
156 EnterCriticalSection (&type_initialization_section);
157 /* double check... */
158 if (vtable->initialized) {
159 LeaveCriticalSection (&type_initialization_section);
162 lock = g_hash_table_lookup (type_initialization_hash, vtable);
164 /* This thread will get to do the initialization */
165 if (mono_domain_get () != domain) {
166 /* Transfer into the target domain */
167 last_domain = mono_domain_get ();
168 if (!mono_domain_set (domain, FALSE)) {
169 vtable->initialized = 1;
170 LeaveCriticalSection (&type_initialization_section);
171 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
174 lock = g_malloc (sizeof(TypeInitializationLock));
175 InitializeCriticalSection (&lock->initialization_section);
176 lock->initializing_tid = tid;
177 lock->waiting_count = 1;
178 /* grab the vtable lock while this thread still owns type_initialization_section */
179 EnterCriticalSection (&lock->initialization_section);
180 g_hash_table_insert (type_initialization_hash, vtable, lock);
181 do_initialization = 1;
185 if (lock->initializing_tid == tid) {
186 LeaveCriticalSection (&type_initialization_section);
189 /* see if the thread doing the initialization is already blocked on this thread */
190 blocked = GUINT_TO_POINTER (lock->initializing_tid);
191 while ((blocked = g_hash_table_lookup (blocked_thread_hash, blocked))) {
192 if (blocked == GUINT_TO_POINTER (tid)) {
193 LeaveCriticalSection (&type_initialization_section);
197 ++lock->waiting_count;
198 /* record the fact that we are waiting on the initializing thread */
199 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), GUINT_TO_POINTER (lock->initializing_tid));
201 LeaveCriticalSection (&type_initialization_section);
203 if (do_initialization) {
204 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
206 mono_domain_set (last_domain, TRUE);
207 LeaveCriticalSection (&lock->initialization_section);
209 /* this just blocks until the initializing thread is done */
210 EnterCriticalSection (&lock->initialization_section);
211 LeaveCriticalSection (&lock->initialization_section);
214 EnterCriticalSection (&type_initialization_section);
215 if (lock->initializing_tid != tid)
216 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
217 --lock->waiting_count;
218 if (lock->waiting_count == 0) {
219 DeleteCriticalSection (&lock->initialization_section);
220 g_hash_table_remove (type_initialization_hash, vtable);
223 vtable->initialized = 1;
224 /* FIXME: if the cctor fails, the type must be marked as unusable */
225 LeaveCriticalSection (&type_initialization_section);
227 vtable->initialized = 1;
232 (klass->image == mono_defaults.corlib &&
233 !strcmp (klass->name_space, "System") &&
234 !strcmp (klass->name, "TypeInitializationException")))
235 return; /* No static constructor found or avoid infinite loop */
237 if (klass->name_space && *klass->name_space)
238 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
240 full_name = g_strdup (klass->name);
242 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
245 mono_raise_exception (exc_to_throw);
249 default_trampoline (MonoMethod *method)
255 default_remoting_trampoline (MonoMethod *method)
257 g_error ("remoting not installed");
261 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
262 static MonoTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
265 mono_install_trampoline (MonoTrampoline func)
267 arch_create_jit_trampoline = func? func: default_trampoline;
271 mono_install_remoting_trampoline (MonoTrampoline func)
273 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
276 static MonoCompileFunc default_mono_compile_method = NULL;
279 mono_install_compile_method (MonoCompileFunc func)
281 default_mono_compile_method = func;
285 mono_compile_method (MonoMethod *method)
287 if (!default_mono_compile_method) {
288 g_error ("compile method called on uninitialized runtime");
291 return default_mono_compile_method (method);
295 #if 0 && HAVE_BOEHM_GC
297 vtable_finalizer (void *obj, void *data) {
298 g_print ("%s finalized (%p)\n", (char*)data, obj);
304 #define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
307 * The vtables in the root appdomain are assumed to be reachable by other
308 * roots, and we don't use typed allocation in the other domains.
311 #define GC_HEADER_BITMAP (1 << (G_STRUCT_OFFSET (MonoObject,synchronisation) / sizeof(gpointer)))
314 mono_class_compute_gc_descriptor (MonoClass *class)
316 MonoClassField *field;
320 static gboolean gcj_inited = FALSE;
325 GC_init_gcj_malloc (5, NULL);
329 mono_class_init (class);
331 if (class->gc_descr_inited)
334 class->gc_descr_inited = TRUE;
335 class->gc_descr = GC_NO_DESCRIPTOR;
337 if (class == mono_defaults.string_class) {
338 bitmap = GC_HEADER_BITMAP;
339 class->gc_descr = (gpointer)GC_make_descriptor ((GC_bitmap)&bitmap, 2);
341 else if (class->rank) {
342 mono_class_compute_gc_descriptor (class->element_class);
344 if (class->element_class->valuetype && (class->element_class->gc_descr != GC_NO_DESCRIPTOR) && (class->element_class->gc_bitmap == GC_HEADER_BITMAP)) {
345 bitmap = GC_HEADER_BITMAP;
347 bitmap += 1 << (G_STRUCT_OFFSET (MonoArray,bounds) / sizeof(gpointer));
348 class->gc_descr = (gpointer)GC_make_descriptor ((GC_bitmap)&bitmap, 3);
352 static int count = 0;
356 /* GC 6.1 has trouble handling 64 bit descriptors... */
357 if ((class->instance_size / sizeof (gpointer)) > 30) {
358 // printf ("TOO LARGE: %s %d.\n", class->name, class->instance_size / sizeof (gpointer));
362 bitmap = GC_HEADER_BITMAP;
369 // printf("KLASS: %s.\n", class->name);
371 for (p = class; p != NULL; p = p->parent) {
372 for (i = 0; i < p->field.count; ++i) {
373 field = &p->fields [i];
374 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
376 if (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)
379 pos = field->offset / sizeof (gpointer);
381 if (field->type->byref)
384 switch (field->type->type) {
385 case MONO_TYPE_BOOLEAN:
397 // printf ("F: %s %s %d %lld %llx.\n", class->name, field->name, field->offset, ((guint64)1) << pos, bitmap);
400 case MONO_TYPE_STRING:
401 case MONO_TYPE_SZARRAY:
402 case MONO_TYPE_CLASS:
403 case MONO_TYPE_OBJECT:
404 case MONO_TYPE_ARRAY:
406 g_assert ((field->offset % sizeof(gpointer)) == 0);
408 bitmap |= ((guint64)1) << pos;
409 // printf ("F: %s %s %d %d %lld %llx.\n", class->name, field->name, field->offset, pos, ((guint64)(1)) << pos, bitmap);
411 case MONO_TYPE_VALUETYPE: {
412 MonoClass *fclass = field->type->data.klass;
413 if (!fclass->enumtype) {
414 mono_class_compute_gc_descriptor (fclass);
415 bitmap |= (fclass->gc_bitmap >> (sizeof (MonoObject) / sizeof (gpointer))) << pos;
425 // printf("CLASS: %s.%s -> %d %llx.\n", class->name_space, class->name, class->instance_size / sizeof (gpointer), bitmap);
426 class->gc_bitmap = bitmap;
427 /* Convert to the format expected by GC_make_descriptor */
428 bm [0] = (guint32)bitmap;
429 bm [1] = (guint32)(bitmap >> 32);
430 class->gc_descr = (gpointer)GC_make_descriptor ((GC_bitmap)&bm, class->instance_size / sizeof (gpointer));
433 #endif /* CREATION_SPEEDUP */
436 * field_is_special_static:
438 * Returns SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
439 * SPECIAL_STATIC_NONE otherwise.
442 field_is_special_static (MonoClass *fklass, MonoClassField *field)
444 MonoCustomAttrInfo *ainfo;
446 ainfo = mono_custom_attrs_from_field (fklass, field);
449 for (i = 0; i < ainfo->num_attrs; ++i) {
450 MonoClass *klass = ainfo->attrs [i].ctor->klass;
451 if (klass->image == mono_defaults.corlib) {
452 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
453 mono_custom_attrs_free (ainfo);
454 return SPECIAL_STATIC_THREAD;
456 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
457 mono_custom_attrs_free (ainfo);
458 return SPECIAL_STATIC_CONTEXT;
462 mono_custom_attrs_free (ainfo);
463 return SPECIAL_STATIC_NONE;
468 * @domain: the application domain
469 * @class: the class to initialize
471 * VTables are domain specific because we create domain specific code, and
472 * they contain the domain specific static class data.
475 mono_class_vtable (MonoDomain *domain, MonoClass *class)
477 MonoVTable *vt = NULL;
478 MonoClassField *field;
484 guint32 constant_cols [MONO_CONSTANT_SIZE];
488 vt = class->cached_vtable;
489 if (vt && vt->domain == domain)
492 mono_domain_lock (domain);
493 if ((vt = mono_g_hash_table_lookup (domain->class_vtable_hash, class))) {
494 mono_domain_unlock (domain);
499 mono_class_init (class);
501 mono_stats.used_class_count++;
502 mono_stats.class_vtable_size += sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
504 vtable_size = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
506 vt = mono_mempool_alloc0 (domain->mp, vtable_size);
512 mono_class_compute_gc_descriptor (class);
513 if (domain != mono_get_root_domain ())
515 * We can't use typed allocation in the non-root domains, since the
516 * collector needs the GC descriptor stored in the vtable even after
517 * the mempool containing the vtable is destroyed when the domain is
518 * unloaded. An alternative might be to allocate vtables in the GC
519 * heap, but this does not seem to work (it leads to crashes inside
520 * libgc). If that approach is tried, two gc descriptors need to be
521 * allocated for each class: one for the root domain, and one for all
522 * other domains. The second descriptor should contain a bit for the
523 * vtable field in MonoObject, since we can no longer assume the
524 * vtable is reachable by other roots after the appdomain is unloaded.
526 vt->gc_descr = GC_NO_DESCRIPTOR;
528 vt->gc_descr = class->gc_descr;
531 if (class->class_size) {
533 vt->data = GC_MALLOC (class->class_size + 8);
534 /*vt->data = GC_debug_malloc (class->class_size + 8, class->name, 2);*/
535 /*GC_register_finalizer (vt->data, vtable_finalizer, class->name, NULL, NULL);*/
536 mono_g_hash_table_insert (domain->static_data_hash, class, vt->data);
538 vt->data = mono_mempool_alloc0 (domain->mp, class->class_size + 8);
541 mono_stats.class_static_data_size += class->class_size + 8;
545 for (i = class->field.first; i < class->field.last; ++i) {
546 field = &class->fields [i - class->field.first];
547 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
549 if (mono_field_is_deleted (field))
551 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
552 gint32 special_static = field_is_special_static (class, field);
553 if (special_static != SPECIAL_STATIC_NONE) {
554 guint32 size, align, offset;
555 size = mono_type_size (field->type, &align);
556 offset = mono_alloc_special_static_data (special_static, size, align);
557 if (!domain->special_static_fields)
558 domain->special_static_fields = g_hash_table_new (NULL, NULL);
559 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
563 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
564 MonoClass *fklass = mono_class_from_mono_type (field->type);
565 t = (char*)vt->data + field->offset;
566 if (fklass->valuetype) {
567 memcpy (t, field->data, mono_class_value_size (fklass, NULL));
569 /* it's a pointer type: add check */
570 g_assert (fklass->byval_arg.type == MONO_TYPE_PTR);
571 *t = *(char *)field->data;
575 if (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT))
578 if (!field->def_value) {
579 cindex = mono_metadata_get_constant_index (class->image, MONO_TOKEN_FIELD_DEF | (i + 1), cindex + 1);
582 mono_metadata_decode_row (&class->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
583 field->def_value = g_new0 (MonoConstant, 1);
584 field->def_value->type = constant_cols [MONO_CONSTANT_TYPE];
585 field->def_value->value = (gpointer)mono_metadata_blob_heap (class->image, constant_cols [MONO_CONSTANT_VALUE]);
588 p = field->def_value->value;
589 len = mono_metadata_decode_blob_size (p, &p);
590 t = (char*)vt->data + field->offset;
591 /* should we check that the type matches? */
592 switch (field->def_value->type) {
593 case MONO_TYPE_BOOLEAN:
601 guint16 *val = (guint16*)t;
607 guint32 *val = (guint32*)t;
613 guint64 *val = (guint64*)t;
618 float *val = (float*)t;
623 double *val = (double*)t;
627 case MONO_TYPE_STRING: {
628 gpointer *val = (gpointer*)t;
629 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
630 gunichar2 *copy = g_malloc (len);
632 for (j = 0; j < len/2; j++) {
633 copy [j] = read16 (p);
636 *val = mono_string_new_utf16 (domain, copy, len/2);
639 *val = mono_string_new_utf16 (domain, (const guint16*)p, len/2);
643 case MONO_TYPE_CLASS:
644 /* nothing to do, we malloc0 the data and the value can be 0 only */
647 g_warning ("type 0x%02x should not be in constant table", field->def_value->type);
651 vt->max_interface_id = class->max_interface_id;
653 vt->interface_offsets = mono_mempool_alloc0 (domain->mp,
654 sizeof (gpointer) * (class->max_interface_id + 1));
656 /* initialize interface offsets */
657 for (i = 0; i <= class->max_interface_id; ++i) {
658 int slot = class->interface_offsets [i];
660 vt->interface_offsets [i] = &(vt->vtable [slot]);
664 * arch_create_jit_trampoline () can recursively call this function again
665 * because it compiles icall methods right away.
667 mono_g_hash_table_insert (domain->class_vtable_hash, class, vt);
668 if (!class->cached_vtable)
669 class->cached_vtable = vt;
671 /* initialize vtable */
672 for (i = 0; i < class->vtable_size; ++i) {
675 if ((cm = class->vtable [i]))
676 vt->vtable [i] = arch_create_jit_trampoline (cm);
679 mono_domain_unlock (domain);
681 /* make sure the the parent is initialized */
683 mono_class_vtable (domain, class->parent);
685 vt->type = mono_type_get_object (domain, &class->byval_arg);
686 if (class->contextbound)
695 * mono_class_proxy_vtable:
696 * @domain: the application domain
697 * @remove_class: the remote class
699 * Creates a vtable for transparent proxies. It is basically
700 * a copy of the real vtable of the class wrapped in @remote_class,
701 * but all function pointers invoke the remoting functions, and
702 * vtable->klass points to the transparent proxy class, and not to @class.
705 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class)
707 MonoVTable *vt, *pvt;
708 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
710 MonoClass *class = remote_class->proxy_class;
712 vt = mono_class_vtable (domain, class);
713 max_interface_id = vt->max_interface_id;
715 /* Calculate vtable space for extra interfaces */
716 for (j = 0; j < remote_class->interface_count; j++) {
717 MonoClass* iclass = remote_class->interfaces[j];
718 int method_count = iclass->method.count;
720 if (iclass->interface_id <= class->max_interface_id && class->interface_offsets[iclass->interface_id] != 0)
721 continue; /* interface implemented by the class */
723 for (i = 0; i < iclass->interface_count; i++)
724 method_count += iclass->interfaces[i]->method.count;
726 extra_interface_vtsize += method_count * sizeof (gpointer);
727 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
730 vtsize = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
732 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
734 pvt = mono_mempool_alloc (domain->mp, vtsize + extra_interface_vtsize);
735 memcpy (pvt, vt, vtsize);
737 pvt->klass = mono_defaults.transparent_proxy_class;
739 /* initialize vtable */
740 for (i = 0; i < class->vtable_size; ++i) {
743 if ((cm = class->vtable [i]))
744 pvt->vtable [i] = arch_create_remoting_trampoline (cm);
747 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT)
749 /* create trampolines for abstract methods */
750 for (k = class; k; k = k->parent) {
751 for (i = 0; i < k->method.count; i++) {
752 int slot = k->methods [i]->slot;
753 if (!pvt->vtable [slot])
754 pvt->vtable [slot] = arch_create_remoting_trampoline (k->methods[i]);
759 pvt->max_interface_id = max_interface_id;
760 pvt->interface_offsets = mono_mempool_alloc0 (domain->mp,
761 sizeof (gpointer) * (max_interface_id + 1));
763 /* initialize interface offsets */
764 for (i = 0; i <= class->max_interface_id; ++i) {
765 int slot = class->interface_offsets [i];
767 pvt->interface_offsets [i] = &(pvt->vtable [slot]);
770 if (remote_class->interface_count > 0)
772 int slot = class->vtable_size;
777 /* Create trampolines for the methods of the interfaces */
778 for (n = 0; n < remote_class->interface_count; n++)
780 iclass = remote_class->interfaces[n];
781 if (iclass->interface_id <= class->max_interface_id && class->interface_offsets[iclass->interface_id] != 0)
782 continue; /* interface implemented by the class */
787 pvt->interface_offsets [interf->interface_id] = &pvt->vtable [slot];
789 for (j = 0; j < interf->method.count; ++j) {
790 MonoMethod *cm = interf->methods [j];
791 pvt->vtable [slot + j] = arch_create_remoting_trampoline (cm);
793 slot += interf->method.count;
794 if (++i < iclass->interface_count) interf = iclass->interfaces[i];
806 * @domain: the application domain
807 * @class_name: name of the remote class
809 * Creates and initializes a MonoRemoteClass object for a remote type.
813 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
817 mono_domain_lock (domain);
818 rc = mono_g_hash_table_lookup (domain->proxy_vtable_hash, class_name);
821 mono_domain_unlock (domain);
825 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass));
827 rc->interface_count = 0;
828 rc->interfaces = NULL;
829 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
830 rc->proxy_class_name = mono_string_to_utf8 (class_name);
832 mono_g_hash_table_insert (domain->proxy_vtable_hash, class_name, rc);
833 mono_upgrade_remote_class (domain, rc, proxy_class);
835 if (rc->vtable == NULL)
836 rc->vtable = mono_class_proxy_vtable (domain, rc);
838 mono_domain_unlock (domain);
844 extend_interface_array (MonoDomain *domain, MonoRemoteClass *remote_class, int amount)
846 /* Extends the array of interfaces. Memory is extended using blocks of 5 pointers */
848 int current_size = ((remote_class->interface_count / 5) + 1) * 5;
849 remote_class->interface_count += amount;
851 if (remote_class->interface_count > current_size || remote_class->interfaces == NULL)
853 int new_size = ((remote_class->interface_count / 5) + 1) * 5;
854 MonoClass **new_array = mono_mempool_alloc (domain->mp, new_size * sizeof (MonoClass*));
856 if (remote_class->interfaces != NULL)
857 memcpy (new_array, remote_class->interfaces, current_size * sizeof (MonoClass*));
859 remote_class->interfaces = new_array;
865 * mono_upgrade_remote_class:
866 * @domain: the application domain
867 * @remote_class: the remote class
868 * @klass: class to which the remote class can be casted.
870 * Updates the vtable of the remote class by adding the necessary method slots
871 * and interface offsets so it can be safely casted to klass. klass can be a
872 * class or an interface.
874 void mono_upgrade_remote_class (MonoDomain *domain, MonoRemoteClass *remote_class, MonoClass *klass)
876 gboolean redo_vtable;
878 mono_domain_lock (domain);
880 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
883 for (i = 0; i < remote_class->interface_count; i++)
884 if (remote_class->interfaces[i] == klass) redo_vtable = FALSE;
887 extend_interface_array (domain, remote_class, 1);
888 remote_class->interfaces [remote_class->interface_count-1] = klass;
892 redo_vtable = (remote_class->proxy_class != klass);
893 remote_class->proxy_class = klass;
897 remote_class->vtable = mono_class_proxy_vtable (domain, remote_class);
900 printf ("remote class upgrade - class:%s num-interfaces:%d\n", remote_class->proxy_class_name, remote_class->interface_count);
902 for (n=0; n<remote_class->interface_count; n++)
903 printf (" I:%s\n", remote_class->interfaces[n]->name);
906 mono_domain_unlock (domain);
910 * Retrieve the MonoMethod that would to be called on obj if obj is passed as
911 * the instance of a callvirt of method.
914 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method) {
918 MonoMethod *res = NULL;
920 klass = mono_object_class (obj);
921 if (klass == mono_defaults.transparent_proxy_class) {
922 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
928 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
931 vtable = klass->vtable;
933 /* check method->slot is a valid index: perform isinstance? */
934 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
936 res = vtable [klass->interface_offsets [method->klass->interface_id] + method->slot];
938 if (method->slot != -1)
939 res = vtable [method->slot];
943 if (!res) res = method; /* It may be an interface or abstract class method */
944 res = mono_marshal_get_remoting_invoke (res);
953 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
955 g_error ("runtime invoke called on uninitialized runtime");
959 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
962 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
964 return default_mono_runtime_invoke (method, obj, params, exc);
968 set_value (MonoType *type, void *dest, void *value, int deref_pointer) {
971 gpointer *p = (gpointer*)dest;
978 case MONO_TYPE_BOOLEAN:
981 guint8 *p = (guint8*)dest;
982 *p = *(guint8*)value;
987 case MONO_TYPE_CHAR: {
988 guint16 *p = (guint16*)dest;
989 *p = *(guint16*)value;
992 #if SIZEOF_VOID_P == 4
998 gint32 *p = (gint32*)dest;
999 *p = *(gint32*)value;
1002 #if SIZEOF_VOID_P == 8
1007 case MONO_TYPE_U8: {
1008 gint64 *p = (gint64*)dest;
1009 *p = *(gint64*)value;
1012 case MONO_TYPE_R4: {
1013 float *p = (float*)dest;
1014 *p = *(float*)value;
1017 case MONO_TYPE_R8: {
1018 double *p = (double*)dest;
1019 *p = *(double*)value;
1022 case MONO_TYPE_STRING:
1023 case MONO_TYPE_SZARRAY:
1024 case MONO_TYPE_CLASS:
1025 case MONO_TYPE_OBJECT:
1026 case MONO_TYPE_ARRAY:
1027 case MONO_TYPE_PTR: {
1028 gpointer *p = (gpointer*)dest;
1029 *p = deref_pointer? *(gpointer*)value: value;
1032 case MONO_TYPE_VALUETYPE:
1033 if (type->data.klass->enumtype) {
1034 t = type->data.klass->enum_basetype->type;
1038 size = mono_class_value_size (type->data.klass, NULL);
1039 memcpy (dest, value, size);
1043 g_warning ("got type %x", type->type);
1044 g_assert_not_reached ();
1049 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
1053 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
1055 dest = (char*)obj + field->offset;
1056 set_value (field->type, dest, value, FALSE);
1060 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
1064 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
1066 dest = (char*)vt->data + field->offset;
1067 set_value (field->type, dest, value, FALSE);
1071 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
1075 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
1077 src = (char*)obj + field->offset;
1078 set_value (field->type, value, src, TRUE);
1082 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
1086 MonoVTable *vtable = NULL;
1088 gboolean is_static = FALSE;
1089 gboolean is_ref = FALSE;
1091 switch (field->type->type) {
1092 case MONO_TYPE_STRING:
1093 case MONO_TYPE_OBJECT:
1094 case MONO_TYPE_CLASS:
1095 case MONO_TYPE_ARRAY:
1096 case MONO_TYPE_SZARRAY:
1101 case MONO_TYPE_BOOLEAN:
1104 case MONO_TYPE_CHAR:
1113 case MONO_TYPE_VALUETYPE:
1114 is_ref = field->type->byref;
1117 g_error ("type 0x%x not handled in "
1118 "mono_field_get_value_object", field->type->type);
1122 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
1124 vtable = mono_class_vtable (domain, field->parent);
1125 if (!vtable->initialized)
1126 mono_runtime_class_init (vtable);
1131 mono_field_static_get_value (vtable, field, &o);
1133 mono_field_get_value (obj, field, &o);
1138 /* boxed value type */
1139 klass = mono_class_from_mono_type (field->type);
1140 o = mono_object_new (domain, klass);
1141 v = ((gchar *) o) + sizeof (MonoObject);
1143 mono_field_static_get_value (vtable, field, v);
1145 mono_field_get_value (obj, field, v);
1153 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
1157 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
1159 src = (char*)vt->data + field->offset;
1160 set_value (field->type, value, src, TRUE);
1164 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
1166 default_mono_runtime_invoke (prop->set, obj, params, exc);
1170 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
1172 return default_mono_runtime_invoke (prop->get, obj, params, exc);
1177 mono_get_delegate_invoke (MonoClass *klass)
1184 for (i = 0; i < klass->method.count; ++i) {
1185 if (klass->methods [i]->name[0] == 'I' &&
1186 !strcmp ("Invoke", klass->methods [i]->name)) {
1187 im = klass->methods [i];
1197 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
1201 im = mono_get_delegate_invoke (delegate->vtable->klass);
1204 return mono_runtime_invoke (im, delegate, params, exc);
1207 static MonoArray* main_args;
1210 mono_runtime_get_main_args (void)
1216 fire_process_exit_event (void)
1218 MonoClassField *field;
1219 MonoDomain *domain = mono_domain_get ();
1221 MonoObject *delegate, *exc;
1223 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
1226 if (domain != mono_get_root_domain ())
1229 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
1230 if (delegate == NULL)
1235 mono_runtime_delegate_invoke (delegate, pa, &exc);
1239 * Execute a standard Main() method (argc/argv contains the
1240 * executable name). This method also sets the command line argument value
1241 * needed by System.Environment.
1244 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
1248 MonoArray *args = NULL;
1249 MonoDomain *domain = mono_domain_get ();
1250 gchar *utf8_fullpath;
1253 main_thread = mono_thread_current ();
1255 main_args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
1257 if (!g_path_is_absolute (argv [0])) {
1258 gchar *basename = g_path_get_basename (argv [0]);
1259 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
1263 utf8_fullpath = mono_utf8_from_external (fullpath);
1264 if(utf8_fullpath == NULL) {
1265 /* Printing the arg text will cause glib to
1266 * whinge about "Invalid UTF-8", but at least
1267 * its relevant, and shows the problem text
1270 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
1271 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
1278 utf8_fullpath = mono_utf8_from_external (argv[0]);
1279 if(utf8_fullpath == NULL) {
1280 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
1281 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
1286 mono_array_set (main_args, gpointer, 0, mono_string_new (domain, utf8_fullpath));
1287 g_free (utf8_fullpath);
1289 for (i = 1; i < argc; ++i) {
1293 utf8_arg=mono_utf8_from_external (argv[i]);
1294 if(utf8_arg==NULL) {
1295 /* Ditto the comment about Invalid UTF-8 here */
1296 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
1297 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
1301 arg = mono_string_new (domain, utf8_arg);
1302 mono_array_set (main_args, gpointer, i, arg);
1306 if (method->signature->param_count) {
1307 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
1308 for (i = 0; i < argc; ++i) {
1309 /* The encodings should all work, given that
1310 * we've checked all these args for the
1313 MonoString *arg = mono_string_new (domain, mono_utf8_from_external (argv [i]));
1314 mono_array_set (args, gpointer, i, arg);
1317 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
1320 mono_assembly_set_main (method->klass->image->assembly);
1322 result = mono_runtime_exec_main (method, args, exc);
1323 fire_process_exit_event ();
1327 /* Used in mono_unhandled_exception */
1329 create_unhandled_exception_eventargs (MonoObject *exc)
1333 MonoMethod *method = NULL;
1334 MonoBoolean is_terminating = TRUE;
1338 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
1341 mono_class_init (klass);
1343 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
1344 for (i = 0; i < klass->method.count; ++i) {
1345 method = klass->methods [i];
1346 if (!strcmp (".ctor", method->name) &&
1347 method->signature->param_count == 2 &&
1348 method->flags & METHOD_ATTRIBUTE_PUBLIC)
1356 args [1] = &is_terminating;
1358 obj = mono_object_new (mono_domain_get (), klass);
1359 mono_runtime_invoke (method, obj, args, NULL);
1365 * We call this function when we detect an unhandled exception
1366 * in the default domain.
1367 * It invokes the * UnhandledException event in AppDomain or prints
1368 * a warning to the console
1371 mono_unhandled_exception (MonoObject *exc)
1373 MonoDomain *domain = mono_domain_get ();
1374 MonoClassField *field;
1375 MonoObject *delegate;
1377 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
1378 "UnhandledException");
1381 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
1382 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
1384 /* set exitcode only in the main thread */
1385 if (mono_thread_current () == main_thread)
1386 mono_environment_exitcode_set (1);
1387 if (domain != mono_get_root_domain () || !delegate) {
1388 mono_print_unhandled_exception (exc);
1390 MonoObject *e = NULL;
1393 pa [0] = domain->domain;
1394 pa [1] = create_unhandled_exception_eventargs (exc);
1395 mono_runtime_delegate_invoke (delegate, pa, &e);
1398 gchar *msg = mono_string_to_utf8 (((MonoException *) e)->message);
1399 g_warning ("exception inside UnhandledException handler: %s\n", msg);
1407 * Launch a new thread to start all setup that requires managed code
1410 * main_func is called back from the thread with main_args as the
1411 * parameter. The callback function is expected to start Main()
1412 * eventually. This function then waits for all managed threads to
1416 mono_runtime_exec_managed_code (MonoDomain *domain,
1417 MonoMainThreadFunc main_func,
1420 mono_thread_create (domain, main_func, main_args);
1422 mono_thread_manage ();
1426 * Execute a standard Main() method (args doesn't contain the
1430 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
1440 domain = mono_object_domain (args);
1441 if (!domain->entry_assembly) {
1443 gchar *config_suffix;
1444 MonoAssembly *assembly;
1446 assembly = method->klass->image->assembly;
1447 domain->entry_assembly = assembly;
1448 domain->setup->application_base = mono_string_new (domain, assembly->basedir);
1450 config_suffix = g_strconcat (assembly->aname.name, ".exe.config", NULL);
1451 str = g_build_filename (assembly->basedir, config_suffix, NULL);
1452 g_free (config_suffix);
1453 domain->setup->configuration_file = mono_string_new (domain, str);
1457 /* FIXME: check signature of method */
1458 if (method->signature->ret->type == MONO_TYPE_I4) {
1460 res = mono_runtime_invoke (method, NULL, pa, exc);
1462 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
1466 mono_environment_exitcode_set (rval);
1468 mono_runtime_invoke (method, NULL, pa, exc);
1472 /* If the return type of Main is void, only
1473 * set the exitcode if an exception was thrown
1474 * (we don't want to blow away an
1475 * explicitly-set exit code)
1478 mono_environment_exitcode_set (rval);
1486 mono_install_runtime_invoke (MonoInvokeFunc func)
1488 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
1492 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
1495 MonoMethodSignature *sig = method->signature;
1496 gpointer *pa = NULL;
1499 if (NULL != params) {
1500 pa = alloca (sizeof (gpointer) * mono_array_length (params));
1501 for (i = 0; i < mono_array_length (params); i++) {
1502 if (sig->params [i]->byref) {
1506 switch (sig->params [i]->type) {
1509 case MONO_TYPE_BOOLEAN:
1512 case MONO_TYPE_CHAR:
1521 case MONO_TYPE_VALUETYPE:
1522 if (sig->params [i]->byref) {
1523 /* MS seems to create the objects if a null is passed in */
1524 if (! ((gpointer *)params->vector)[i])
1525 ((gpointer*)params->vector)[i] = mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i]));
1528 g_assert (((gpointer*)params->vector) [i]);
1529 pa [i] = (char *)(((gpointer *)params->vector)[i]) + sizeof (MonoObject);
1531 case MONO_TYPE_STRING:
1532 case MONO_TYPE_OBJECT:
1533 case MONO_TYPE_CLASS:
1534 case MONO_TYPE_ARRAY:
1535 case MONO_TYPE_SZARRAY:
1536 if (sig->params [i]->byref)
1537 pa [i] = &(((gpointer *)params->vector)[i]);
1539 pa [i] = (char *)(((gpointer *)params->vector)[i]);
1542 g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
1547 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
1549 obj = mono_object_new (mono_domain_get (), method->klass);
1550 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
1551 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
1554 mono_runtime_invoke (method, obj, pa, exc);
1557 return mono_runtime_invoke (method, obj, pa, exc);
1561 out_of_memory (size_t size)
1564 * we could allocate at program startup some memory that we could release
1565 * back to the system at this point if we're really low on memory (ie, size is
1566 * lower than the memory we set apart)
1568 mono_raise_exception (mono_domain_get ()->out_of_memory_ex);
1572 * mono_object_allocate:
1573 * @size: number of bytes to allocate
1575 * This is a very simplistic routine until we have our GC-aware
1578 * Returns: an allocated object of size @size, or NULL on failure.
1580 static inline void *
1581 mono_object_allocate (size_t size)
1584 /* if this is changed to GC_debug_malloc(), we need to change also metadata/gc.c */
1585 void *o = GC_MALLOC (size);
1587 void *o = calloc (1, size);
1589 mono_stats.new_object_count++;
1592 out_of_memory (size);
1596 #if CREATION_SPEEDUP
1597 static inline void *
1598 mono_object_allocate_spec (size_t size, void *gcdescr)
1600 /* if this is changed to GC_debug_malloc(), we need to change also metadata/gc.c */
1601 void *o = GC_GCJ_MALLOC (size, gcdescr);
1602 mono_stats.new_object_count++;
1605 out_of_memory (size);
1612 * @klass: the class of the object that we want to create
1614 * Returns: A newly created object whose definition is
1615 * looked up using @klass
1618 mono_object_new (MonoDomain *domain, MonoClass *klass)
1620 MONO_ARCH_SAVE_REGS;
1621 return mono_object_new_specific (mono_class_vtable (domain, klass));
1625 * mono_object_new_specific:
1626 * @vtable: the vtable of the object that we want to create
1628 * Returns: A newly created object with class and domain specified
1632 mono_object_new_specific (MonoVTable *vtable)
1636 MONO_ARCH_SAVE_REGS;
1641 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
1644 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
1648 mono_class_init (klass);
1650 for (i = 0; i < klass->method.count; ++i) {
1651 if (!strcmp ("CreateProxyForType", klass->methods [i]->name) &&
1652 klass->methods [i]->signature->param_count == 1) {
1653 im = klass->methods [i];
1658 vtable->domain->create_proxy_for_type_method = im;
1661 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
1663 o = mono_runtime_invoke (im, NULL, pa, NULL);
1664 if (o != NULL) return o;
1667 return mono_object_new_alloc_specific (vtable);
1671 mono_object_new_fast (MonoVTable *vtable)
1674 MONO_ARCH_SAVE_REGS;
1676 #if CREATION_SPEEDUP
1677 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
1678 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
1680 // printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name);
1681 o = mono_object_allocate (vtable->klass->instance_size);
1685 o = mono_object_allocate (vtable->klass->instance_size);
1692 mono_object_new_alloc_specific (MonoVTable *vtable)
1696 #if CREATION_SPEEDUP
1697 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
1698 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
1700 // printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name);
1701 o = mono_object_allocate (vtable->klass->instance_size);
1705 o = mono_object_allocate (vtable->klass->instance_size);
1708 if (vtable->klass->has_finalize)
1709 mono_object_register_finalizer (o);
1711 mono_profiler_allocation (o, vtable->klass);
1716 * mono_object_new_from_token:
1717 * @image: Context where the type_token is hosted
1718 * @token: a token of the type that we want to create
1720 * Returns: A newly created object whose definition is
1721 * looked up using @token in the @image image
1724 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
1728 class = mono_class_get (image, token);
1730 return mono_object_new (domain, class);
1735 * mono_object_clone:
1736 * @obj: the object to clone
1738 * Returns: A newly created object who is a shallow copy of @obj
1741 mono_object_clone (MonoObject *obj)
1746 size = obj->vtable->klass->instance_size;
1747 o = mono_object_allocate (size);
1748 mono_profiler_allocation (o, obj->vtable->klass);
1750 memcpy (o, obj, size);
1752 if (obj->vtable->klass->has_finalize)
1753 mono_object_register_finalizer (o);
1759 * @array: the array to clone
1761 * Returns: A newly created array who is a shallow copy of @array
1764 mono_array_clone (MonoArray *array)
1769 MonoClass *klass = array->obj.vtable->klass;
1771 MONO_ARCH_SAVE_REGS;
1773 if (array->bounds == NULL) {
1774 size = mono_array_length (array);
1775 o = mono_array_new_full (((MonoObject *)array)->vtable->domain,
1776 klass, &size, NULL);
1778 size *= mono_array_element_size (klass);
1779 memcpy (o, array, sizeof (MonoArray) + size);
1784 sizes = alloca (klass->rank * sizeof(guint32) * 2);
1785 size = mono_array_element_size (klass);
1786 for (i = 0; i < klass->rank; ++i) {
1787 sizes [i] = array->bounds [i].length;
1788 size *= array->bounds [i].length;
1789 sizes [i + klass->rank] = array->bounds [i].lower_bound;
1791 o = mono_array_new_full (((MonoObject *)array)->vtable->domain,
1792 klass, sizes, sizes + klass->rank);
1793 memcpy (o, array, sizeof(MonoArray) + size);
1798 /* helper macros to check for overflow when calculating the size of arrays */
1799 #define MYGUINT32_MAX 4294967295U
1800 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1801 (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
1802 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1803 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1804 (guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a))
1807 * mono_array_new_full:
1808 * @domain: domain where the object is created
1809 * @array_class: array class
1810 * @lengths: lengths for each dimension in the array
1811 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
1813 * This routine creates a new array objects with the given dimensions,
1814 * lower bounds and type.
1817 mono_array_new_full (MonoDomain *domain, MonoClass *array_class,
1818 guint32 *lengths, guint32 *lower_bounds)
1820 guint32 byte_len, len;
1823 MonoArrayBounds *bounds;
1827 if (!array_class->inited)
1828 mono_class_init (array_class);
1830 byte_len = mono_array_element_size (array_class);
1833 if (array_class->rank == 1 &&
1834 (lower_bounds == NULL || lower_bounds [0] == 0)) {
1839 bounds = GC_MALLOC (sizeof (MonoArrayBounds) * array_class->rank);
1841 bounds = g_malloc0 (sizeof (MonoArrayBounds) * array_class->rank);
1843 for (i = 0; i < array_class->rank; ++i) {
1844 bounds [i].length = lengths [i];
1845 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
1846 out_of_memory (MYGUINT32_MAX);
1851 for (i = 0; i < array_class->rank; ++i)
1852 bounds [i].lower_bound = lower_bounds [i];
1855 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
1856 out_of_memory (MYGUINT32_MAX);
1858 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
1859 out_of_memory (MYGUINT32_MAX);
1860 byte_len += sizeof (MonoArray);
1862 * Following three lines almost taken from mono_object_new ():
1863 * they need to be kept in sync.
1865 vtable = mono_class_vtable (domain, array_class);
1866 #if CREATION_SPEEDUP
1867 if (vtable->gc_descr != GC_NO_DESCRIPTOR)
1868 o = mono_object_allocate_spec (byte_len, vtable);
1870 o = mono_object_allocate (byte_len);
1874 o = mono_object_allocate (byte_len);
1878 array = (MonoArray*)o;
1880 array->bounds = bounds;
1881 array->max_length = len;
1883 mono_profiler_allocation (o, array_class);
1890 * @domain: domain where the object is created
1891 * @eclass: element class
1892 * @n: number of array elements
1894 * This routine creates a new szarray with @n elements of type @eclass.
1897 mono_array_new (MonoDomain *domain, MonoClass *eclass, guint32 n)
1901 MONO_ARCH_SAVE_REGS;
1903 ac = mono_array_class_get (eclass, 1);
1904 g_assert (ac != NULL);
1906 return mono_array_new_specific (mono_class_vtable (domain, ac), n);
1910 * mono_array_new_specific:
1911 * @vtable: a vtable in the appropriate domain for an initialized class
1912 * @n: number of array elements
1914 * This routine is a fast alternative to mono_array_new() for code which
1915 * can be sure about the domain it operates in.
1918 mono_array_new_specific (MonoVTable *vtable, guint32 n)
1922 guint32 byte_len, elem_size;
1924 MONO_ARCH_SAVE_REGS;
1926 elem_size = mono_array_element_size (vtable->klass);
1927 if (CHECK_MUL_OVERFLOW_UN (n, elem_size))
1928 out_of_memory (MYGUINT32_MAX);
1929 byte_len = n * elem_size;
1930 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
1931 out_of_memory (MYGUINT32_MAX);
1932 byte_len += sizeof (MonoArray);
1933 #if CREATION_SPEEDUP
1934 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
1935 o = mono_object_allocate_spec (byte_len, vtable);
1937 // printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name);
1938 o = mono_object_allocate (byte_len);
1942 o = mono_object_allocate (byte_len);
1946 ao = (MonoArray *)o;
1949 mono_profiler_allocation (o, vtable->klass);
1955 * mono_string_new_utf16:
1956 * @text: a pointer to an utf16 string
1957 * @len: the length of the string
1959 * Returns: A newly created string object which contains @text.
1962 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
1966 s = mono_string_new_size (domain, len);
1967 g_assert (s != NULL);
1969 memcpy (mono_string_chars (s), text, len * 2);
1975 * mono_string_new_size:
1976 * @text: a pointer to an utf16 string
1977 * @len: the length of the string
1979 * Returns: A newly created string object of @len
1982 mono_string_new_size (MonoDomain *domain, gint32 len)
1986 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
1988 /* overflow ? can't fit it, can't allocate it! */
1992 vtable = mono_class_vtable (domain, mono_defaults.string_class);
1994 #if CREATION_SPEEDUP
1995 if (vtable->gc_descr != GC_NO_DESCRIPTOR)
1996 s = mono_object_allocate_spec (size, vtable);
1998 s = (MonoString*)mono_object_allocate (size);
1999 s->object.vtable = vtable;
2002 s = (MonoString*)mono_object_allocate (size);
2003 s->object.vtable = vtable;
2007 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
2013 * mono_string_new_len:
2014 * @text: a pointer to an utf8 string
2015 * @length: number of bytes in @text to consider
2017 * Returns: A newly created string object which contains @text.
2020 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
2022 GError *error = NULL;
2023 MonoString *o = NULL;
2025 glong items_written;
2027 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
2030 o = mono_string_new_utf16 (domain, ut, items_written);
2032 g_error_free (error);
2041 * @text: a pointer to an utf8 string
2043 * Returns: A newly created string object which contains @text.
2046 mono_string_new (MonoDomain *domain, const char *text)
2048 GError *error = NULL;
2049 MonoString *o = NULL;
2051 glong items_written;
2056 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
2059 o = mono_string_new_utf16 (domain, ut, items_written);
2061 g_error_free (error);
2069 * mono_string_new_wrapper:
2070 * @text: pointer to utf8 characters.
2072 * Helper function to create a string object from @text in the current domain.
2075 mono_string_new_wrapper (const char *text)
2077 MonoDomain *domain = mono_domain_get ();
2079 MONO_ARCH_SAVE_REGS;
2082 return mono_string_new (domain, text);
2089 * @class: the class of the value
2090 * @value: a pointer to the unboxed data
2092 * Returns: A newly created object which contains @value.
2095 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
2101 g_assert (class->valuetype);
2103 vtable = mono_class_vtable (domain, class);
2104 size = mono_class_instance_size (class);
2105 res = mono_object_allocate (size);
2106 res->vtable = vtable;
2107 mono_profiler_allocation (res, class);
2109 size = size - sizeof (MonoObject);
2111 #if NO_UNALIGNED_ACCESS
2112 memcpy ((char *)res + sizeof (MonoObject), value, size);
2116 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
2119 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
2122 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
2125 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
2128 memcpy ((char *)res + sizeof (MonoObject), value, size);
2131 if (class->has_finalize)
2132 mono_object_register_finalizer (res);
2137 mono_object_get_domain (MonoObject *obj)
2139 return mono_object_domain (obj);
2143 mono_object_get_class (MonoObject *obj)
2145 return mono_object_class (obj);
2149 mono_object_unbox (MonoObject *obj)
2151 /* add assert for valuetypes? */
2152 return ((char*)obj) + sizeof (MonoObject);
2156 * mono_object_isinst:
2158 * @klass: a pointer to a class
2160 * Returns: @obj if @obj is derived from @klass
2163 mono_object_isinst (MonoObject *obj, MonoClass *klass)
2166 mono_class_init (klass);
2168 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)
2169 return mono_object_isinst_mbyref (obj, klass);
2174 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
2178 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
2187 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2188 if ((klass->interface_id <= vt->max_interface_id) &&
2189 (vt->interface_offsets [klass->interface_id] != 0))
2193 MonoClass *oklass = vt->klass;
2194 if ((oklass == mono_defaults.transparent_proxy_class))
2195 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2197 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
2201 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
2203 MonoDomain *domain = mono_domain_get ();
2205 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
2206 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
2207 MonoMethod *im = NULL;
2211 for (i = 0; i < rpklass->method.count; ++i) {
2212 if (!strcmp ("CanCastTo", rpklass->methods [i]->name)) {
2213 im = rpklass->methods [i];
2218 im = mono_object_get_virtual_method (rp, im);
2221 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
2224 res = mono_runtime_invoke (im, rp, pa, NULL);
2226 if (*(MonoBoolean *) mono_object_unbox(res)) {
2227 /* Update the vtable of the remote type, so it can safely cast to this new type */
2228 mono_upgrade_remote_class (domain, ((MonoTransparentProxy *)obj)->remote_class, klass);
2229 obj->vtable = ((MonoTransparentProxy *)obj)->remote_class->vtable;
2238 * mono_object_castclass_mbyref:
2240 * @klass: a pointer to a class
2242 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
2245 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
2247 if (!obj) return NULL;
2248 if (mono_object_isinst_mbyref (obj, klass)) return obj;
2250 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
2252 "InvalidCastException"));
2257 MonoDomain *orig_domain;
2263 str_lookup (MonoDomain *domain, gpointer user_data)
2265 LDStrInfo *info = user_data;
2266 if (info->res || domain == info->orig_domain)
2268 mono_domain_lock (domain);
2269 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
2270 mono_domain_unlock (domain);
2274 mono_string_is_interned_lookup (MonoString *str, int insert)
2276 MonoGHashTable *ldstr_table;
2279 char *ins = g_malloc (4 + str->length * 2);
2282 /* Encode the length */
2283 /* Same code as in mono_image_insert_string () */
2285 mono_metadata_encode_value (1 | (2 * str->length), p, &p);
2288 * ins is stored in the hash table as a key and needs to have the same
2289 * representation as in the metadata: we swap the character bytes on big
2292 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
2295 char *p2 = (char *)mono_string_chars (str);
2296 for (i = 0; i < str->length; ++i) {
2303 memcpy (p, mono_string_chars (str), str->length * 2);
2305 domain = ((MonoObject *)str)->vtable->domain;
2306 ldstr_table = domain->ldstr_table;
2307 mono_domain_lock (domain);
2308 if ((res = mono_g_hash_table_lookup (ldstr_table, ins))) {
2309 mono_domain_unlock (domain);
2314 mono_g_hash_table_insert (ldstr_table, ins, str);
2315 mono_domain_unlock (domain);
2318 LDStrInfo ldstr_info;
2319 ldstr_info.orig_domain = domain;
2320 ldstr_info.ins = ins;
2321 ldstr_info.res = NULL;
2323 mono_domain_foreach (str_lookup, &ldstr_info);
2324 if (ldstr_info.res) {
2326 * the string was already interned in some other domain:
2327 * intern it in the current one as well.
2329 mono_g_hash_table_insert (ldstr_table, ins, str);
2330 mono_domain_unlock (domain);
2334 mono_domain_unlock (domain);
2340 mono_string_is_interned (MonoString *o)
2342 return mono_string_is_interned_lookup (o, FALSE);
2346 mono_string_intern (MonoString *str)
2348 return mono_string_is_interned_lookup (str, TRUE);
2353 * @domain: the domain where the string will be used.
2354 * @image: a metadata context
2355 * @idx: index into the user string table.
2357 * Implementation for the ldstr opcode.
2360 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
2362 const char *str, *sig;
2366 MONO_ARCH_SAVE_REGS;
2369 return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx);
2371 sig = str = mono_metadata_user_string (image, idx);
2373 mono_domain_lock (domain);
2374 if ((o = mono_g_hash_table_lookup (domain->ldstr_table, sig))) {
2375 mono_domain_unlock (domain);
2379 len2 = mono_metadata_decode_blob_size (str, &str);
2382 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
2383 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
2386 guint16 *p2 = (guint16*)mono_string_chars (o);
2387 for (i = 0; i < len2; ++i) {
2388 *p2 = GUINT16_FROM_LE (*p2);
2393 mono_g_hash_table_insert (domain->ldstr_table, (gpointer)sig, o);
2394 mono_domain_unlock (domain);
2400 * mono_string_to_utf8:
2401 * @s: a System.String
2403 * Return the UTF8 representation for @s.
2404 * the resulting buffer nedds to be freed with g_free().
2407 mono_string_to_utf8 (MonoString *s)
2410 GError *error = NULL;
2416 return g_strdup ("");
2418 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, NULL, &error);
2420 g_warning (error->message);
2421 g_error_free (error);
2428 * mono_string_to_utf16:
2431 * Return an null-terminated array of the utf-16 chars
2432 * contained in @s. The result must be freed with g_free().
2433 * This is a temporary helper until our string implementation
2434 * is reworked to always include the null terminating char.
2437 mono_string_to_utf16 (MonoString *s)
2444 as = g_malloc ((s->length * 2) + 2);
2445 as [(s->length * 2)] = '\0';
2446 as [(s->length * 2) + 1] = '\0';
2449 return (gunichar2 *)(as);
2452 memcpy (as, mono_string_chars(s), s->length * 2);
2453 return (gunichar2 *)(as);
2457 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString
2460 mono_string_from_utf16 (gunichar2 *data)
2462 MonoDomain *domain = mono_domain_get ();
2468 while (data [len]) len++;
2470 return mono_string_new_utf16 (domain, data, len);
2474 default_ex_handler (MonoException *ex)
2476 MonoObject *o = (MonoObject*)ex;
2477 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
2481 static MonoExceptionFunc ex_handler = default_ex_handler;
2484 mono_install_handler (MonoExceptionFunc func)
2486 ex_handler = func? func: default_ex_handler;
2490 * mono_raise_exception:
2491 * @ex: exception object
2493 * Signal the runtime that the exception @ex has been raised in unmanaged code.
2496 mono_raise_exception (MonoException *ex)
2499 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
2500 * that will cause gcc to omit the function epilog, causing problems when
2501 * the JIT tries to walk the stack, since the return address on the stack
2502 * will point into the next function in the executable, not this one.
2509 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
2511 MonoWaitHandle *res;
2513 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
2515 res->handle = handle;
2521 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data)
2523 MonoAsyncResult *res;
2525 res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
2528 res->async_state = state;
2530 res->handle = (MonoObject *) mono_wait_handle_new (domain, handle);
2532 res->sync_completed = FALSE;
2533 res->completed = FALSE;
2539 mono_message_init (MonoDomain *domain,
2540 MonoMethodMessage *this,
2541 MonoReflectionMethod *method,
2542 MonoArray *out_args)
2544 MonoMethodSignature *sig = method->method->signature;
2550 this->method = method;
2552 this->args = mono_array_new (domain, mono_defaults.object_class, sig->param_count);
2553 this->arg_types = mono_array_new (domain, mono_defaults.byte_class, sig->param_count);
2554 this->async_result = NULL;
2555 this->call_type = CallType_Sync;
2557 names = g_new (char *, sig->param_count);
2558 mono_method_get_param_names (method->method, (const char **) names);
2559 this->names = mono_array_new (domain, mono_defaults.string_class, sig->param_count);
2561 for (i = 0; i < sig->param_count; i++) {
2562 name = mono_string_new (domain, names [i]);
2563 mono_array_set (this->names, gpointer, i, name);
2567 for (i = 0, j = 0; i < sig->param_count; i++) {
2569 if (sig->params [i]->byref) {
2571 gpointer arg = mono_array_get (out_args, gpointer, j);
2572 mono_array_set (this->args, gpointer, i, arg);
2576 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
2581 mono_array_set (this->arg_types, guint8, i, arg_type);
2586 * mono_remoting_invoke:
2587 * @real_proxy: pointer to a RealProxy object
2588 * @msg: The MonoMethodMessage to execute
2589 * @exc: used to store exceptions
2590 * @out_args: used to store output arguments
2592 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
2593 * IMessage interface and it is not trivial to extract results from there. So
2594 * we call an helper method PrivateInvoke instead of calling
2595 * RealProxy::Invoke() directly.
2597 * Returns: the result object.
2600 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
2601 MonoObject **exc, MonoArray **out_args)
2603 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
2606 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
2612 klass = mono_defaults.real_proxy_class;
2614 for (i = 0; i < klass->method.count; ++i) {
2615 if (!strcmp ("PrivateInvoke", klass->methods [i]->name) &&
2616 klass->methods [i]->signature->param_count == 4) {
2617 im = klass->methods [i];
2623 real_proxy->vtable->domain->private_invoke_method = im;
2626 pa [0] = real_proxy;
2631 return mono_runtime_invoke (im, NULL, pa, exc);
2635 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
2636 MonoObject **exc, MonoArray **out_args)
2640 MonoMethodSignature *sig;
2641 int i, j, outarg_count = 0;
2643 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
2645 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
2646 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
2647 target = tp->rp->unwrapped_server;
2649 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
2653 domain = mono_domain_get ();
2654 method = msg->method->method;
2655 sig = method->signature;
2657 for (i = 0; i < sig->param_count; i++) {
2658 if (sig->params [i]->byref)
2662 *out_args = mono_array_new (domain, mono_defaults.object_class, outarg_count);
2665 for (i = 0, j = 0; i < sig->param_count; i++) {
2666 if (sig->params [i]->byref) {
2668 arg = mono_array_get (msg->args, gpointer, i);
2669 mono_array_set (*out_args, gpointer, j, arg);
2674 return mono_runtime_invoke_array (method, target, msg->args, exc);
2678 mono_print_unhandled_exception (MonoObject *exc)
2680 char *message = (char *) "";
2684 gboolean free_message = FALSE;
2687 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
2688 klass = exc->vtable->klass;
2690 while (klass && method == NULL) {
2691 for (i = 0; i < klass->method.count; ++i) {
2692 method = klass->methods [i];
2693 if (!strcmp ("ToString", method->name) &&
2694 method->signature->param_count == 0 &&
2695 method->flags & METHOD_ATTRIBUTE_VIRTUAL &&
2696 method->flags & METHOD_ATTRIBUTE_PUBLIC) {
2703 klass = klass->parent;
2708 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
2710 message = mono_string_to_utf8 (str);
2711 free_message = TRUE;
2716 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
2717 * exc->vtable->klass->name, message);
2719 g_printerr ("\nUnhandled Exception: %s\n", message);
2726 * mono_delegate_ctor:
2727 * @this: pointer to an uninitialized delegate object
2728 * @target: target object
2729 * @addr: pointer to native code
2731 * This is used to initialize a delegate. We also insert the method_info if
2732 * we find the info with mono_jit_info_table_find().
2735 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
2737 MonoDomain *domain = mono_domain_get ();
2738 MonoDelegate *delegate = (MonoDelegate *)this;
2739 MonoMethod *method = NULL;
2746 class = this->vtable->klass;
2748 if ((ji = mono_jit_info_table_find (domain, addr))) {
2749 method = ji->method;
2750 delegate->method_info = mono_method_get_object (domain, method, NULL);
2753 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
2755 method = mono_marshal_get_remoting_invoke (method);
2756 delegate->method_ptr = mono_compile_method (method);
2757 delegate->target = target;
2759 delegate->method_ptr = addr;
2760 delegate->target = target;
2765 * mono_method_call_message_new:
2767 * Translates arguments pointers into a Message.
2770 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
2771 MonoDelegate **cb, MonoObject **state)
2773 MonoDomain *domain = mono_domain_get ();
2774 MonoMethodSignature *sig = method->signature;
2775 MonoMethodMessage *msg;
2778 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
2781 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
2782 count = sig->param_count - 2;
2784 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
2785 count = sig->param_count;
2788 for (i = 0; i < count; i++) {
2793 if (sig->params [i]->byref)
2794 vpos = *((gpointer *)params [i]);
2798 type = sig->params [i]->type;
2799 class = mono_class_from_mono_type (sig->params [i]);
2801 if (class->valuetype)
2802 arg = mono_value_box (domain, class, vpos);
2804 arg = *((MonoObject **)vpos);
2806 mono_array_set (msg->args, gpointer, i, arg);
2809 if (cb != NULL && state != NULL) {
2810 *cb = *((MonoDelegate **)params [i]);
2812 *state = *((MonoObject **)params [i]);
2819 * mono_method_return_message_restore:
2821 * Restore results from message based processing back to arguments pointers
2824 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
2826 MonoMethodSignature *sig = method->signature;
2827 int i, j, type, size;
2828 for (i = 0, j = 0; i < sig->param_count; i++) {
2829 MonoType *pt = sig->params [i];
2832 char *arg = mono_array_get (out_args, gpointer, j);
2836 case MONO_TYPE_VOID:
2837 g_assert_not_reached ();
2841 case MONO_TYPE_BOOLEAN:
2844 case MONO_TYPE_CHAR:
2851 case MONO_TYPE_VALUETYPE: {
2852 size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
2853 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
2856 case MONO_TYPE_STRING:
2857 case MONO_TYPE_CLASS:
2858 case MONO_TYPE_ARRAY:
2859 case MONO_TYPE_SZARRAY:
2860 case MONO_TYPE_OBJECT:
2861 **((MonoObject ***)params [i]) = (MonoObject *)arg;
2864 g_assert_not_reached ();
2873 * mono_load_remote_field:
2874 * @this: pointer to an object
2875 * @klass: klass of the object containing @field
2876 * @field: the field to load
2877 * @res: a storage to store the result
2879 * This method is called by the runtime on attempts to load fields of
2880 * transparent proxy objects. @this points to such TP, @klass is the class of
2881 * the object containing @field. @res is a storage location which can be
2882 * used to store the result.
2884 * Returns: an address pointing to the value of field.
2887 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
2889 static MonoMethod *getter = NULL;
2890 MonoDomain *domain = mono_domain_get ();
2891 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
2892 MonoClass *field_class;
2893 MonoMethodMessage *msg;
2894 MonoArray *out_args;
2898 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
2903 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
2904 mono_field_get_value (tp->rp->unwrapped_server, field, res);
2911 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
2912 MonoMethod *cm = mono_defaults.object_class->methods [i];
2914 if (!strcmp (cm->name, "FieldGetter")) {
2922 field_class = mono_class_from_mono_type (field->type);
2924 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
2925 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
2926 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
2928 mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
2929 mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
2931 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
2933 if (exc) mono_raise_exception ((MonoException *)exc);
2935 *res = mono_array_get (out_args, MonoObject *, 0);
2937 if (field_class->valuetype) {
2938 return ((char *)*res) + sizeof (MonoObject);
2944 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
2946 static MonoMethod *getter = NULL;
2947 MonoDomain *domain = mono_domain_get ();
2948 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
2949 MonoClass *field_class;
2950 MonoMethodMessage *msg;
2951 MonoArray *out_args;
2952 MonoObject *exc, *res;
2954 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
2956 field_class = mono_class_from_mono_type (field->type);
2958 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
2960 if (field_class->valuetype) {
2961 res = mono_object_new (domain, field_class);
2962 val = ((gchar *) res) + sizeof (MonoObject);
2966 mono_field_get_value (tp->rp->unwrapped_server, field, val);
2973 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
2974 MonoMethod *cm = mono_defaults.object_class->methods [i];
2976 if (!strcmp (cm->name, "FieldGetter")) {
2984 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
2985 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
2986 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
2988 mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
2989 mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
2991 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
2993 if (exc) mono_raise_exception ((MonoException *)exc);
2995 res = mono_array_get (out_args, MonoObject *, 0);
3001 * mono_store_remote_field:
3002 * @this: pointer to an object
3003 * @klass: klass of the object containing @field
3004 * @field: the field to load
3005 * @val: the value/object to store
3007 * This method is called by the runtime on attempts to store fields of
3008 * transparent proxy objects. @this points to such TP, @klass is the class of
3009 * the object containing @field. @val is the new value to store in @field.
3012 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
3014 static MonoMethod *setter = NULL;
3015 MonoDomain *domain = mono_domain_get ();
3016 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3017 MonoClass *field_class;
3018 MonoMethodMessage *msg;
3019 MonoArray *out_args;
3023 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3025 field_class = mono_class_from_mono_type (field->type);
3027 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3028 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
3029 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
3036 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
3037 MonoMethod *cm = mono_defaults.object_class->methods [i];
3039 if (!strcmp (cm->name, "FieldSetter")) {
3047 if (field_class->valuetype)
3048 arg = mono_value_box (domain, field_class, val);
3050 arg = *((MonoObject **)val);
3053 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3054 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
3056 mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3057 mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3058 mono_array_set (msg->args, gpointer, 2, arg);
3060 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3062 if (exc) mono_raise_exception ((MonoException *)exc);
3066 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
3068 static MonoMethod *setter = NULL;
3069 MonoDomain *domain = mono_domain_get ();
3070 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3071 MonoClass *field_class;
3072 MonoMethodMessage *msg;
3073 MonoArray *out_args;
3076 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3078 field_class = mono_class_from_mono_type (field->type);
3080 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3081 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
3082 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
3089 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
3090 MonoMethod *cm = mono_defaults.object_class->methods [i];
3092 if (!strcmp (cm->name, "FieldSetter")) {
3100 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3101 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
3103 mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3104 mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3105 mono_array_set (msg->args, gpointer, 2, arg);
3107 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3109 if (exc) mono_raise_exception ((MonoException *)exc);