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/metadata/security-manager.h"
35 #include <mono/os/gc_wrapper.h>
36 #include <mono/utils/strenc.h>
39 #define NEED_TO_ZERO_PTRFREE 1
40 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = GC_MALLOC_ATOMIC ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
41 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = GC_MALLOC ((size)); (obj)->vtable = (vt);} while (0)
42 #ifdef HAVE_GC_GCJ_MALLOC
43 #define CREATION_SPEEDUP 1
44 #define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
45 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_GCJ_MALLOC ((size),(type)); } while (0)
46 #define MAKE_STRING_DESCRIPTOR(bitmap,sz) GC_make_descriptor((GC_bitmap)(bitmap),(sz))
47 #define MAKE_DESCRIPTOR(bitmap,sz,objsize) GC_make_descriptor((GC_bitmap)(bitmap),(sz))
49 #define GC_NO_DESCRIPTOR (NULL)
50 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_MALLOC ((size)); *(gpointer*)dest = (type);} while (0)
51 #define MAKE_STRING_DESCRIPTOR(bitmap,sz) NULL
52 #define MAKE_DESCRIPTOR(bitmap,sz,objsize) NULL
56 #define GC_NO_DESCRIPTOR (NULL)
57 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
58 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
59 #define ALLOC_TYPED(dest,size,type) do { (dest) = mono_gc_alloc_obj (type, size);} while (0)
60 #define MAKE_STRING_DESCRIPTOR(bitmap,sz) mono_gc_make_descr_for_string ()
61 #define MAKE_DESCRIPTOR(bitmap,sz,objsize) mono_gc_make_descr_for_object ((bitmap), (sz), (objsize))
63 #define NEED_TO_ZERO_PTRFREE 1
64 #define GC_NO_DESCRIPTOR (NULL)
65 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = malloc ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
66 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = calloc (1, (size)); (obj)->vtable = (vt);} while (0)
67 #define ALLOC_TYPED(dest,size,type) do { (dest) = calloc (1, (size)); *(gpointer*)dest = (type);} while (0)
68 #define MAKE_STRING_DESCRIPTOR(bitmap,sz) NULL
69 #define MAKE_DESCRIPTOR(bitmap,sz,objsize) NULL
73 static MonoObject* mono_object_new_ptrfree (MonoVTable *vtable);
74 static MonoObject* mono_object_new_ptrfree_box (MonoVTable *vtable);
77 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
80 mono_ldstr_metdata_sig (MonoDomain *domain, const char* sig);
83 mono_runtime_object_init (MonoObject *this)
85 MonoMethod *method = NULL;
86 MonoClass *klass = this->vtable->klass;
88 method = mono_class_get_method_from_name (klass, ".ctor", 0);
91 if (method->klass->valuetype)
92 this = mono_object_unbox (this);
93 mono_runtime_invoke (method, this, NULL, NULL);
96 /* The pseudo algorithm for type initialization from the spec
97 Note it doesn't say anything about domains - only threads.
99 2. If the type is initialized you are done.
100 2.1. If the type is not yet initialized, try to take an
102 2.2. If successful, record this thread as responsible for
103 initializing the type and proceed to step 2.3.
104 2.2.1. If not, see whether this thread or any thread
105 waiting for this thread to complete already holds the lock.
106 2.2.2. If so, return since blocking would create a deadlock. This thread
107 will now see an incompletely initialized state for the type,
108 but no deadlock will arise.
109 2.2.3 If not, block until the type is initialized then return.
110 2.3 Initialize the parent type and then all interfaces implemented
112 2.4 Execute the type initialization code for this type.
113 2.5 Mark the type as initialized, release the initialization lock,
114 awaken any threads waiting for this type to be initialized,
121 guint32 initializing_tid;
122 guint32 waiting_count;
124 CRITICAL_SECTION initialization_section;
125 } TypeInitializationLock;
127 /* for locking access to type_initialization_hash and blocked_thread_hash */
128 static CRITICAL_SECTION type_initialization_section;
130 /* from vtable to lock */
131 static GHashTable *type_initialization_hash;
133 /* from thread id to thread id being waited on */
134 static GHashTable *blocked_thread_hash;
137 static MonoThread *main_thread;
140 * mono_thread_set_main:
141 * @thread: thread to set as the main thread
143 * This function can be used to instruct the runtime to treat @thread
144 * as the main thread, ie, the thread that would normally execute the Main()
145 * method. This basically means that at the end of @thread, the runtime will
146 * wait for the existing foreground threads to quit and other such details.
149 mono_thread_set_main (MonoThread *thread)
151 main_thread = thread;
155 mono_thread_get_main (void)
161 mono_type_initialization_init (void)
163 InitializeCriticalSection (&type_initialization_section);
164 type_initialization_hash = g_hash_table_new (NULL, NULL);
165 blocked_thread_hash = g_hash_table_new (NULL, NULL);
169 * mono_runtime_class_init:
170 * @vtable: vtable that needs to be initialized
172 * This routine calls the class constructor for @vtable.
175 mono_runtime_class_init (MonoVTable *vtable)
178 MonoException *exc_to_throw;
179 MonoMethod *method = NULL;
185 if (vtable->initialized)
189 klass = vtable->klass;
191 method = mono_class_get_cctor (klass);
194 MonoDomain *domain = vtable->domain;
195 TypeInitializationLock *lock;
196 guint32 tid = GetCurrentThreadId();
197 int do_initialization = 0;
198 MonoDomain *last_domain = NULL;
200 EnterCriticalSection (&type_initialization_section);
201 /* double check... */
202 if (vtable->initialized) {
203 LeaveCriticalSection (&type_initialization_section);
206 lock = g_hash_table_lookup (type_initialization_hash, vtable);
208 /* This thread will get to do the initialization */
209 if (mono_domain_get () != domain) {
210 /* Transfer into the target domain */
211 last_domain = mono_domain_get ();
212 if (!mono_domain_set (domain, FALSE)) {
213 vtable->initialized = 1;
214 LeaveCriticalSection (&type_initialization_section);
215 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
218 lock = g_malloc (sizeof(TypeInitializationLock));
219 InitializeCriticalSection (&lock->initialization_section);
220 lock->initializing_tid = tid;
221 lock->waiting_count = 1;
223 /* grab the vtable lock while this thread still owns type_initialization_section */
224 EnterCriticalSection (&lock->initialization_section);
225 g_hash_table_insert (type_initialization_hash, vtable, lock);
226 do_initialization = 1;
229 TypeInitializationLock *pending_lock;
231 if (lock->initializing_tid == tid || lock->done) {
232 LeaveCriticalSection (&type_initialization_section);
235 /* see if the thread doing the initialization is already blocked on this thread */
236 blocked = GUINT_TO_POINTER (lock->initializing_tid);
237 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
238 if (pending_lock->initializing_tid == tid) {
239 if (!pending_lock->done) {
240 LeaveCriticalSection (&type_initialization_section);
243 /* the thread doing the initialization is blocked on this thread,
244 but on a lock that has already been freed. It just hasn't got
249 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
251 ++lock->waiting_count;
252 /* record the fact that we are waiting on the initializing thread */
253 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
255 LeaveCriticalSection (&type_initialization_section);
257 if (do_initialization) {
258 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
260 mono_domain_set (last_domain, TRUE);
262 LeaveCriticalSection (&lock->initialization_section);
264 /* this just blocks until the initializing thread is done */
265 EnterCriticalSection (&lock->initialization_section);
266 LeaveCriticalSection (&lock->initialization_section);
269 EnterCriticalSection (&type_initialization_section);
270 if (lock->initializing_tid != tid)
271 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
272 --lock->waiting_count;
273 if (lock->waiting_count == 0) {
274 DeleteCriticalSection (&lock->initialization_section);
275 g_hash_table_remove (type_initialization_hash, vtable);
278 vtable->initialized = 1;
279 /* FIXME: if the cctor fails, the type must be marked as unusable */
280 LeaveCriticalSection (&type_initialization_section);
282 vtable->initialized = 1;
287 (klass->image == mono_defaults.corlib &&
288 !strcmp (klass->name_space, "System") &&
289 !strcmp (klass->name, "TypeInitializationException")))
290 return; /* No static constructor found or avoid infinite loop */
292 if (klass->name_space && *klass->name_space)
293 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
295 full_name = g_strdup (klass->name);
297 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
300 mono_raise_exception (exc_to_throw);
304 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
306 TypeInitializationLock *lock = (TypeInitializationLock*) value;
307 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
309 LeaveCriticalSection (&lock->initialization_section);
310 --lock->waiting_count;
311 if (lock->waiting_count == 0) {
312 DeleteCriticalSection (&lock->initialization_section);
321 mono_release_type_locks (MonoThread *thread)
323 EnterCriticalSection (&type_initialization_section);
324 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
325 LeaveCriticalSection (&type_initialization_section);
329 default_trampoline (MonoMethod *method)
335 default_remoting_trampoline (MonoMethod *method, MonoRemotingTarget target)
337 g_error ("remoting not installed");
341 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
342 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
345 mono_install_trampoline (MonoTrampoline func)
347 arch_create_jit_trampoline = func? func: default_trampoline;
351 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
353 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
356 static MonoCompileFunc default_mono_compile_method = NULL;
359 * mono_install_compile_method:
360 * @func: function to install
362 * This is a VM internal routine
365 mono_install_compile_method (MonoCompileFunc func)
367 default_mono_compile_method = func;
371 * mono_compile_method:
372 * @method: The method to compile.
374 * This JIT-compiles the method, and returns the pointer to the native code
378 mono_compile_method (MonoMethod *method)
380 if (!default_mono_compile_method) {
381 g_error ("compile method called on uninitialized runtime");
384 return default_mono_compile_method (method);
387 static MonoFreeMethodFunc default_mono_free_method = NULL;
390 * mono_install_free_method:
391 * @func: pointer to the MonoFreeMethodFunc used to release a method
393 * This is an internal VM routine, it is used for the engines to
394 * register a handler to release the resources associated with a method.
396 * Methods are freed when no more references to the delegate that holds
400 mono_install_free_method (MonoFreeMethodFunc func)
402 default_mono_free_method = func;
406 * mono_runtime_free_method:
407 * @domain; domain where the method is hosted
408 * @method: method to release
410 * This routine is invoked to free the resources associated with
411 * a method that has been JIT compiled. This is used to discard
412 * methods that were used only temporarily (for example, used in marshalling)
416 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
418 if (default_mono_free_method != NULL)
419 default_mono_free_method (domain, method);
421 mono_free_method (method);
424 static MonoInitVTableFunc init_vtable_func = NULL;
427 * mono_install_init_vtable:
428 * @func: pointer to the function to be installed
430 * Register a function which will be called by the runtime to initialize the
431 * method pointers inside a vtable. The JIT can use this function to load the
432 * vtable from the AOT file for example.
435 mono_install_init_vtable (MonoInitVTableFunc func)
437 init_vtable_func = func;
441 * The vtables in the root appdomain are assumed to be reachable by other
442 * roots, and we don't use typed allocation in the other domains.
445 /* The sync block is no longer a GC pointer */
446 #define GC_HEADER_BITMAP (0)
448 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
451 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set)
453 MonoClassField *field;
456 int max_size = class->instance_size / sizeof (gpointer);
457 if (max_size > size) {
458 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
461 for (p = class; p != NULL; p = p->parent) {
462 gpointer iter = NULL;
463 while ((field = mono_class_get_fields (p, &iter))) {
466 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
468 /* FIXME: should not happen, flag as type load error */
469 if (field->type->byref)
472 pos = field->offset / sizeof (gpointer);
475 type = mono_type_get_underlying_type (field->type);
476 switch (type->type) {
477 /* FIXME: _I and _U and _PTR should be removed eventually */
481 case MONO_TYPE_FNPTR:
482 case MONO_TYPE_STRING:
483 case MONO_TYPE_SZARRAY:
484 case MONO_TYPE_CLASS:
485 case MONO_TYPE_OBJECT:
486 case MONO_TYPE_ARRAY:
487 g_assert ((field->offset % sizeof(gpointer)) == 0);
489 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
490 *max_set = MAX (*max_set, pos);
492 case MONO_TYPE_VALUETYPE: {
493 MonoClass *fclass = field->type->data.klass;
494 if (fclass->has_references) {
495 /* remove the object header */
496 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set);
510 case MONO_TYPE_BOOLEAN:
514 g_assert_not_reached ();
523 mono_class_compute_gc_descriptor (MonoClass *class)
527 gsize default_bitmap [4] = {0};
528 static gboolean gcj_inited = FALSE;
533 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
534 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
535 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
537 #ifdef HAVE_GC_GCJ_MALLOC
539 GC_init_gcj_malloc (5, NULL);
541 #ifdef GC_REDIRECT_TO_LOCAL
542 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
543 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
545 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
546 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
549 mono_loader_unlock ();
553 mono_class_init (class);
555 if (class->gc_descr_inited)
558 class->gc_descr_inited = TRUE;
559 class->gc_descr = GC_NO_DESCRIPTOR;
561 bitmap = default_bitmap;
562 if (class == mono_defaults.string_class) {
563 class->gc_descr = (gpointer)MAKE_STRING_DESCRIPTOR (bitmap, 2);
564 } else if (class->rank) {
565 mono_class_compute_gc_descriptor (class->element_class);
567 /* libgc has no usable support for arrays... */
568 if (!class->element_class->valuetype) {
570 class->gc_descr = mono_gc_make_descr_for_array (TRUE, &abm, 1, sizeof (gpointer));
571 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
572 class->name_space, class->name);*/
574 /* remove the object header */
575 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (sizeof (MonoObject) / sizeof (gpointer)), &max_set);
576 class->gc_descr = mono_gc_make_descr_for_array (TRUE, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
577 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
578 class->name_space, class->name);*/
579 if (bitmap != default_bitmap)
584 /*static int count = 0;
587 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set);
589 /* It seems there are issues when the bitmap doesn't fit: play it safe */
591 /*g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);*/
592 if (bitmap != default_bitmap)
597 class->gc_descr = (gpointer)MAKE_DESCRIPTOR (bitmap, max_set + 1, class->instance_size);
598 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
599 if (bitmap != default_bitmap)
605 * field_is_special_static:
606 * @fklass: The MonoClass to look up.
607 * @field: The MonoClassField describing the field.
609 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
610 * SPECIAL_STATIC_NONE otherwise.
613 field_is_special_static (MonoClass *fklass, MonoClassField *field)
615 MonoCustomAttrInfo *ainfo;
617 ainfo = mono_custom_attrs_from_field (fklass, field);
620 for (i = 0; i < ainfo->num_attrs; ++i) {
621 MonoClass *klass = ainfo->attrs [i].ctor->klass;
622 if (klass->image == mono_defaults.corlib) {
623 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
624 mono_custom_attrs_free (ainfo);
625 return SPECIAL_STATIC_THREAD;
627 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
628 mono_custom_attrs_free (ainfo);
629 return SPECIAL_STATIC_CONTEXT;
633 mono_custom_attrs_free (ainfo);
634 return SPECIAL_STATIC_NONE;
637 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class);
641 * @domain: the application domain
642 * @class: the class to initialize
644 * VTables are domain specific because we create domain specific code, and
645 * they contain the domain specific static class data.
648 mono_class_vtable (MonoDomain *domain, MonoClass *class)
650 MonoClassRuntimeInfo *runtime_info;
654 /* this check can be inlined in jitted code, too */
655 runtime_info = class->runtime_info;
656 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
657 return runtime_info->domain_vtables [domain->domain_id];
658 return mono_class_create_runtime_vtable (domain, class);
662 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
665 MonoClassRuntimeInfo *runtime_info, *old_info;
666 MonoClassField *field;
669 gboolean inited = FALSE;
672 guint32 constant_cols [MONO_CONSTANT_SIZE];
675 mono_domain_lock (domain);
676 runtime_info = class->runtime_info;
677 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
678 mono_domain_unlock (domain);
679 return runtime_info->domain_vtables [domain->domain_id];
682 mono_class_init (class);
684 mono_stats.used_class_count++;
685 mono_stats.class_vtable_size += sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
687 vtable_size = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
689 vt = mono_mempool_alloc0 (domain->mp, vtable_size);
692 vt->rank = class->rank;
695 mono_class_compute_gc_descriptor (class);
697 * We can't use typed allocation in the non-root domains, since the
698 * collector needs the GC descriptor stored in the vtable even after
699 * the mempool containing the vtable is destroyed when the domain is
700 * unloaded. An alternative might be to allocate vtables in the GC
701 * heap, but this does not seem to work (it leads to crashes inside
702 * libgc). If that approach is tried, two gc descriptors need to be
703 * allocated for each class: one for the root domain, and one for all
704 * other domains. The second descriptor should contain a bit for the
705 * vtable field in MonoObject, since we can no longer assume the
706 * vtable is reachable by other roots after the appdomain is unloaded.
709 if (domain != mono_get_root_domain ())
710 vt->gc_descr = GC_NO_DESCRIPTOR;
713 vt->gc_descr = class->gc_descr;
715 if (class->class_size) {
716 if (class->has_static_refs)
717 vt->data = mono_gc_alloc_fixed (class->class_size, NULL);
719 vt->data = mono_mempool_alloc0 (domain->mp, class->class_size);
720 mono_g_hash_table_insert (domain->static_data_hash, class, vt->data);
721 mono_stats.class_static_data_size += class->class_size;
726 while ((field = mono_class_get_fields (class, &iter))) {
727 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
729 if (mono_field_is_deleted (field))
731 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
732 gint32 special_static = field_is_special_static (class, field);
733 if (special_static != SPECIAL_STATIC_NONE) {
734 guint32 size, align, offset;
735 size = mono_type_size (field->type, &align);
736 offset = mono_alloc_special_static_data (special_static, size, align);
737 if (!domain->special_static_fields)
738 domain->special_static_fields = g_hash_table_new (NULL, NULL);
739 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
743 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
744 MonoClass *fklass = mono_class_from_mono_type (field->type);
745 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
746 t = (char*)vt->data + field->offset;
747 if (fklass->valuetype) {
748 memcpy (t, field->data, mono_class_value_size (fklass, NULL));
750 /* it's a pointer type: add check */
751 g_assert (fklass->byval_arg.type == MONO_TYPE_PTR);
752 *t = *(char *)field->data;
756 if (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT))
759 /* later do this only on demand if needed */
761 cindex = mono_metadata_get_constant_index (class->image, mono_class_get_field_token (field), cindex + 1);
763 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA));
765 mono_metadata_decode_row (&class->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
766 field->def_type = constant_cols [MONO_CONSTANT_TYPE];
767 field->data = (gpointer)mono_metadata_blob_heap (class->image, constant_cols [MONO_CONSTANT_VALUE]);
772 vt->max_interface_id = class->max_interface_id;
774 vt->interface_offsets = mono_mempool_alloc0 (domain->mp,
775 sizeof (gpointer) * (class->max_interface_id + 1));
777 /* initialize interface offsets */
778 for (i = 0; i <= class->max_interface_id; ++i) {
779 int slot = class->interface_offsets [i];
781 vt->interface_offsets [i] = &(vt->vtable [slot]);
785 * arch_create_jit_trampoline () can recursively call this function again
786 * because it compiles icall methods right away.
788 /* FIXME: class_vtable_hash is basically obsolete now: remove as soon
789 * as we change the code in appdomain.c to invalidate vtables by
790 * looking at the possible MonoClasses created for the domain.
791 * Or we can reuse static_data_hash, by using vtable as a key
792 * and always inserting into that hash.
794 g_hash_table_insert (domain->class_vtable_hash, class, vt);
795 /* class->runtime_info is protected by the loader lock, both when
796 * it it enlarged and when it is stored info.
799 old_info = class->runtime_info;
800 if (old_info && old_info->max_domain >= domain->domain_id) {
801 /* someone already created a large enough runtime info */
802 old_info->domain_vtables [domain->domain_id] = vt;
804 int new_size = domain->domain_id;
806 new_size = MAX (new_size, old_info->max_domain);
808 /* make the new size a power of two */
813 /* this is a bounded memory retention issue: may want to
814 * handle it differently when we'll have a rcu-like system.
816 runtime_info = mono_mempool_alloc0 (class->image->mempool, sizeof (MonoClassRuntimeInfo) + new_size * sizeof (gpointer));
817 runtime_info->max_domain = new_size - 1;
818 /* copy the stuff from the older info */
820 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
822 runtime_info->domain_vtables [domain->domain_id] = vt;
823 /* keep this last (add membarrier) */
824 class->runtime_info = runtime_info;
826 mono_loader_unlock ();
828 /* initialize vtable */
829 if (init_vtable_func)
830 inited = init_vtable_func (vt);
833 mono_class_setup_vtable (class);
835 for (i = 0; i < class->vtable_size; ++i) {
838 if ((cm = class->vtable [i])) {
839 if (mono_method_signature (cm)->generic_param_count)
842 vt->vtable [i] = arch_create_jit_trampoline (cm);
847 mono_domain_unlock (domain);
849 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
850 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND)) {
851 MonoException *exc = mono_class_get_exception_for_failure (class);
853 mono_raise_exception (exc);
856 /* make sure the the parent is initialized */
858 mono_class_vtable (domain, class->parent);
860 vt->type = mono_type_get_object (domain, &class->byval_arg);
861 if (class->contextbound)
870 * mono_class_proxy_vtable:
871 * @domain: the application domain
872 * @remove_class: the remote class
874 * Creates a vtable for transparent proxies. It is basically
875 * a copy of the real vtable of the class wrapped in @remote_class,
876 * but all function pointers invoke the remoting functions, and
877 * vtable->klass points to the transparent proxy class, and not to @class.
880 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
882 MonoVTable *vt, *pvt;
883 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
885 MonoClass *class = remote_class->proxy_class;
887 vt = mono_class_vtable (domain, class);
888 max_interface_id = vt->max_interface_id;
890 /* Calculate vtable space for extra interfaces */
891 for (j = 0; j < remote_class->interface_count; j++) {
892 MonoClass* iclass = remote_class->interfaces[j];
893 int method_count = mono_class_num_methods (iclass);
895 if (iclass->interface_id <= class->max_interface_id && class->interface_offsets[iclass->interface_id] != 0)
896 continue; /* interface implemented by the class */
898 for (i = 0; i < iclass->interface_count; i++)
899 method_count += mono_class_num_methods (iclass->interfaces[i]);
901 extra_interface_vtsize += method_count * sizeof (gpointer);
902 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
905 vtsize = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
907 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
909 pvt = mono_mempool_alloc (domain->mp, vtsize + extra_interface_vtsize);
910 memcpy (pvt, vt, vtsize);
912 pvt->klass = mono_defaults.transparent_proxy_class;
913 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
914 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
916 /* initialize vtable */
917 mono_class_setup_vtable (class);
918 for (i = 0; i < class->vtable_size; ++i) {
921 if ((cm = class->vtable [i]))
922 pvt->vtable [i] = arch_create_remoting_trampoline (cm, target_type);
925 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
926 /* create trampolines for abstract methods */
927 for (k = class; k; k = k->parent) {
929 gpointer iter = NULL;
930 while ((m = mono_class_get_methods (k, &iter)))
931 if (!pvt->vtable [m->slot])
932 pvt->vtable [m->slot] = arch_create_remoting_trampoline (m, target_type);
936 pvt->max_interface_id = max_interface_id;
937 pvt->interface_offsets = mono_mempool_alloc0 (domain->mp,
938 sizeof (gpointer) * (max_interface_id + 1));
940 /* initialize interface offsets */
941 for (i = 0; i <= class->max_interface_id; ++i) {
942 int slot = class->interface_offsets [i];
944 pvt->interface_offsets [i] = &(pvt->vtable [slot]);
947 if (remote_class->interface_count > 0)
949 int slot = class->vtable_size;
954 /* Create trampolines for the methods of the interfaces */
955 for (n = 0; n < remote_class->interface_count; n++)
957 iclass = remote_class->interfaces[n];
958 if (iclass->interface_id <= class->max_interface_id && class->interface_offsets[iclass->interface_id] != 0)
959 continue; /* interface implemented by the class */
967 pvt->interface_offsets [interf->interface_id] = &pvt->vtable [slot];
971 while ((cm = mono_class_get_methods (interf, &iter)))
972 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (cm, target_type);
974 slot += mono_class_num_methods (interf);
975 if (++i < iclass->interface_count) interf = iclass->interfaces[i];
987 * @domain: the application domain
988 * @class_name: name of the remote class
990 * Creates and initializes a MonoRemoteClass object for a remote type.
994 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
998 mono_domain_lock (domain);
999 rc = mono_g_hash_table_lookup (domain->proxy_vtable_hash, class_name);
1002 mono_domain_unlock (domain);
1006 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass));
1007 rc->default_vtable = NULL;
1008 rc->xdomain_vtable = NULL;
1009 rc->interface_count = 0;
1010 rc->interfaces = NULL;
1011 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
1012 rc->proxy_class_name = mono_string_to_utf8 (class_name);
1014 mono_g_hash_table_insert (domain->proxy_vtable_hash, class_name, rc);
1015 mono_upgrade_remote_class (domain, rc, proxy_class);
1017 mono_domain_unlock (domain);
1023 extend_interface_array (MonoDomain *domain, MonoRemoteClass *remote_class, int amount)
1025 /* Extends the array of interfaces. Memory is extended using blocks of 5 pointers */
1027 int current_size = ((remote_class->interface_count / 5) + 1) * 5;
1028 remote_class->interface_count += amount;
1030 if (remote_class->interface_count > current_size || remote_class->interfaces == NULL)
1032 int new_size = ((remote_class->interface_count / 5) + 1) * 5;
1033 MonoClass **new_array = mono_mempool_alloc (domain->mp, new_size * sizeof (MonoClass*));
1035 if (remote_class->interfaces != NULL)
1036 memcpy (new_array, remote_class->interfaces, current_size * sizeof (MonoClass*));
1038 remote_class->interfaces = new_array;
1043 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
1045 if (rp->target_domain_id != -1) {
1046 if (remote_class->xdomain_vtable == NULL)
1047 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
1048 return remote_class->xdomain_vtable;
1050 if (remote_class->default_vtable == NULL)
1051 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
1053 return remote_class->default_vtable;
1058 * mono_upgrade_remote_class:
1059 * @domain: the application domain
1060 * @remote_class: the remote class
1061 * @klass: class to which the remote class can be casted.
1063 * Updates the vtable of the remote class by adding the necessary method slots
1064 * and interface offsets so it can be safely casted to klass. klass can be a
1065 * class or an interface.
1067 void mono_upgrade_remote_class (MonoDomain *domain, MonoRemoteClass *remote_class, MonoClass *klass)
1069 gboolean redo_vtable;
1071 mono_domain_lock (domain);
1073 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1076 for (i = 0; i < remote_class->interface_count; i++)
1077 if (remote_class->interfaces[i] == klass) redo_vtable = FALSE;
1080 extend_interface_array (domain, remote_class, 1);
1081 remote_class->interfaces [remote_class->interface_count-1] = klass;
1085 redo_vtable = (remote_class->proxy_class != klass);
1086 remote_class->proxy_class = klass;
1090 remote_class->default_vtable = NULL;
1091 remote_class->xdomain_vtable = NULL;
1095 printf ("remote class upgrade - class:%s num-interfaces:%d\n", remote_class->proxy_class_name, remote_class->interface_count);
1097 for (n=0; n<remote_class->interface_count; n++)
1098 printf (" I:%s\n", remote_class->interfaces[n]->name);
1101 mono_domain_unlock (domain);
1105 * mono_object_get_virtual_method:
1106 * @obj: object to operate on.
1109 * Retrieves the MonoMethod that would be called on obj if obj is passed as
1110 * the instance of a callvirt of method.
1113 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
1116 MonoMethod **vtable;
1118 MonoMethod *res = NULL;
1120 klass = mono_object_class (obj);
1121 if (klass == mono_defaults.transparent_proxy_class) {
1122 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
1128 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
1131 mono_class_setup_vtable (klass);
1132 vtable = klass->vtable;
1134 /* check method->slot is a valid index: perform isinstance? */
1135 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1137 res = vtable [klass->interface_offsets [method->klass->interface_id] + method->slot];
1139 if (method->slot != -1)
1140 res = vtable [method->slot];
1144 if (!res) res = method; /* It may be an interface or abstract class method */
1145 res = mono_marshal_get_remoting_invoke (res);
1154 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
1156 g_error ("runtime invoke called on uninitialized runtime");
1160 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
1163 * mono_runtime_invoke:
1164 * @method: method to invoke
1165 * @obJ: object instance
1166 * @params: arguments to the method
1167 * @exc: exception information.
1169 * Invokes the method represented by @method on the object @obj.
1171 * obj is the 'this' pointer, it should be NULL for static
1172 * methods, a MonoObject* for object instances and a pointer to
1173 * the value type for value types.
1175 * The params array contains the arguments to the method with the
1176 * same convention: MonoObject* pointers for object instances and
1177 * pointers to the value type otherwise.
1179 * From unmanaged code you'll usually use the
1180 * mono_runtime_invoke() variant.
1182 * Note that this function doesn't handle virtual methods for
1183 * you, it will exec the exact method you pass: we still need to
1184 * expose a function to lookup the derived class implementation
1185 * of a virtual method (there are examples of this in the code,
1188 * You can pass NULL as the exc argument if you don't want to
1189 * catch exceptions, otherwise, *exc will be set to the exception
1190 * thrown, if any. if an exception is thrown, you can't use the
1191 * MonoObject* result from the function.
1193 * If the method returns a value type, it is boxed in an object
1197 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
1199 return default_mono_runtime_invoke (method, obj, params, exc);
1203 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
1207 gpointer *p = (gpointer*)dest;
1214 case MONO_TYPE_BOOLEAN:
1216 case MONO_TYPE_U1: {
1217 guint8 *p = (guint8*)dest;
1218 *p = value ? *(guint8*)value : 0;
1223 case MONO_TYPE_CHAR: {
1224 guint16 *p = (guint16*)dest;
1225 *p = value ? *(guint16*)value : 0;
1228 #if SIZEOF_VOID_P == 4
1233 case MONO_TYPE_U4: {
1234 gint32 *p = (gint32*)dest;
1235 *p = value ? *(gint32*)value : 0;
1238 #if SIZEOF_VOID_P == 8
1243 case MONO_TYPE_U8: {
1244 gint64 *p = (gint64*)dest;
1245 *p = value ? *(gint64*)value : 0;
1248 case MONO_TYPE_R4: {
1249 float *p = (float*)dest;
1250 *p = value ? *(float*)value : 0;
1253 case MONO_TYPE_R8: {
1254 double *p = (double*)dest;
1255 *p = value ? *(double*)value : 0;
1258 case MONO_TYPE_STRING:
1259 case MONO_TYPE_SZARRAY:
1260 case MONO_TYPE_CLASS:
1261 case MONO_TYPE_OBJECT:
1262 case MONO_TYPE_ARRAY:
1263 case MONO_TYPE_PTR: {
1264 gpointer *p = (gpointer*)dest;
1265 *p = deref_pointer? *(gpointer*)value: value;
1268 case MONO_TYPE_VALUETYPE:
1269 if (type->data.klass->enumtype) {
1270 t = type->data.klass->enum_basetype->type;
1274 size = mono_class_value_size (type->data.klass, NULL);
1276 memset (dest, 0, size);
1278 memcpy (dest, value, size);
1282 g_warning ("got type %x", type->type);
1283 g_assert_not_reached ();
1288 * mono_field_set_value:
1289 * @obj: Instance object
1290 * @field: MonoClassField describing the field to set
1291 * @value: The value to be set
1293 * Sets the value of the field described by @field in the object instance @obj
1294 * to the value passed in @value.
1296 * The value must be on the native format of the field type.
1299 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
1303 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
1305 dest = (char*)obj + field->offset;
1306 set_value (field->type, dest, value, FALSE);
1310 * mono_field_static_set_value:
1311 * @field: MonoClassField describing the field to set
1312 * @value: The value to be set
1314 * Sets the value of the static field described by @field
1315 * to the value passed in @value.
1317 * The value must be on the native format of the field type.
1320 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
1324 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
1325 /* you cant set a constant! */
1326 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
1328 dest = (char*)vt->data + field->offset;
1329 set_value (field->type, dest, value, FALSE);
1333 * mono_field_get_value:
1334 * @obj: Object instance
1335 * @field: MonoClassField describing the field to fetch information from
1336 * @value: pointer to the location where the value will be stored
1338 * Use this routine to get the value of the field @field in the object
1341 * The pointer provided by value must be of the field type, for reference
1342 * types this is a MonoObject*, for value types its the actual pointer to
1347 * mono_field_get_value (obj, int_field, &i);
1350 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
1354 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
1356 src = (char*)obj + field->offset;
1357 set_value (field->type, value, src, TRUE);
1361 * mono_field_get_value_object:
1362 * @domain: domain where the object will be created (if boxing)
1363 * @field: MonoClassField describing the field to fetch information from
1364 * @obj: The object instance for the field.
1366 * Returns: a new MonoObject with the value from the given field. If the
1367 * field represents a value type, the value is boxed.
1371 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
1375 MonoVTable *vtable = NULL;
1377 gboolean is_static = FALSE;
1378 gboolean is_ref = FALSE;
1380 switch (field->type->type) {
1381 case MONO_TYPE_STRING:
1382 case MONO_TYPE_OBJECT:
1383 case MONO_TYPE_CLASS:
1384 case MONO_TYPE_ARRAY:
1385 case MONO_TYPE_SZARRAY:
1390 case MONO_TYPE_BOOLEAN:
1393 case MONO_TYPE_CHAR:
1402 case MONO_TYPE_VALUETYPE:
1403 is_ref = field->type->byref;
1406 g_error ("type 0x%x not handled in "
1407 "mono_field_get_value_object", field->type->type);
1411 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
1413 vtable = mono_class_vtable (domain, field->parent);
1414 if (!vtable->initialized)
1415 mono_runtime_class_init (vtable);
1420 mono_field_static_get_value (vtable, field, &o);
1422 mono_field_get_value (obj, field, &o);
1427 /* boxed value type */
1428 klass = mono_class_from_mono_type (field->type);
1429 o = mono_object_new (domain, klass);
1430 v = ((gchar *) o) + sizeof (MonoObject);
1432 mono_field_static_get_value (vtable, field, v);
1434 mono_field_get_value (obj, field, v);
1441 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
1444 const char *p = blob;
1445 mono_metadata_decode_blob_size (p, &p);
1448 case MONO_TYPE_BOOLEAN:
1451 *(guint8 *) value = *p;
1453 case MONO_TYPE_CHAR:
1456 *(guint16*) value = read16 (p);
1460 *(guint32*) value = read32 (p);
1464 *(guint64*) value = read64 (p);
1467 readr4 (p, (float*) value);
1470 readr8 (p, (double*) value);
1472 case MONO_TYPE_STRING:
1473 *(gpointer*) value = mono_ldstr_metdata_sig (domain, blob);
1475 case MONO_TYPE_CLASS:
1476 *(gpointer*) value = NULL;
1480 g_warning ("type 0x%02x should not be in constant table", type);
1486 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
1488 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT);
1489 mono_get_constant_value_from_blob (domain, field->def_type, field->data, value);
1493 * mono_field_static_get_value:
1494 * @vt: vtable to the object
1495 * @field: MonoClassField describing the field to fetch information from
1496 * @value: where the value is returned
1498 * Use this routine to get the value of the static field @field value.
1500 * The pointer provided by value must be of the field type, for reference
1501 * types this is a MonoObject*, for value types its the actual pointer to
1506 * mono_field_static_get_value (vt, int_field, &i);
1509 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
1513 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
1515 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
1516 get_default_field_value (vt->domain, field, value);
1520 src = (char*)vt->data + field->offset;
1521 set_value (field->type, value, src, TRUE);
1525 * mono_property_set_value:
1526 * @prop: MonoProperty to set
1527 * @obj: instance object on which to act
1528 * @params: parameters to pass to the propery
1529 * @exc: optional exception
1531 * Invokes the property's set method with the given arguments on the
1532 * object instance obj (or NULL for static properties).
1534 * You can pass NULL as the exc argument if you don't want to
1535 * catch exceptions, otherwise, *exc will be set to the exception
1536 * thrown, if any. if an exception is thrown, you can't use the
1537 * MonoObject* result from the function.
1540 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
1542 default_mono_runtime_invoke (prop->set, obj, params, exc);
1546 * mono_property_get_value:
1547 * @prop: MonoProperty to fetch
1548 * @obj: instance object on which to act
1549 * @params: parameters to pass to the propery
1550 * @exc: optional exception
1552 * Invokes the property's get method with the given arguments on the
1553 * object instance obj (or NULL for static properties).
1555 * You can pass NULL as the exc argument if you don't want to
1556 * catch exceptions, otherwise, *exc will be set to the exception
1557 * thrown, if any. if an exception is thrown, you can't use the
1558 * MonoObject* result from the function.
1560 * Returns: the value from invoking the get method on the property.
1563 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
1565 return default_mono_runtime_invoke (prop->get, obj, params, exc);
1570 * mono_get_delegate_invoke:
1571 * @klass: The delegate class
1573 * Returns: the MonoMethod for the "Invoke" method in the delegate klass
1576 mono_get_delegate_invoke (MonoClass *klass)
1580 im = mono_class_get_method_from_name (klass, "Invoke", -1);
1587 * mono_runtime_delegate_invoke:
1588 * @delegate: pointer to a delegate object.
1589 * @params: parameters for the delegate.
1590 * @exc: Pointer to the exception result.
1592 * Invokes the delegate method @delegate with the parameters provided.
1594 * You can pass NULL as the exc argument if you don't want to
1595 * catch exceptions, otherwise, *exc will be set to the exception
1596 * thrown, if any. if an exception is thrown, you can't use the
1597 * MonoObject* result from the function.
1600 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
1604 im = mono_get_delegate_invoke (delegate->vtable->klass);
1607 return mono_runtime_invoke (im, delegate, params, exc);
1610 static char **main_args = NULL;
1611 static int num_main_args;
1614 * mono_runtime_get_main_args:
1616 * Returns: a MonoArray with the arguments passed to the main program
1619 mono_runtime_get_main_args (void)
1623 MonoDomain *domain = mono_domain_get ();
1628 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
1630 for (i = 0; i < num_main_args; ++i)
1631 mono_array_set (res, gpointer, i, mono_string_new (domain, main_args [i]));
1637 fire_process_exit_event (void)
1639 MonoClassField *field;
1640 MonoDomain *domain = mono_domain_get ();
1642 MonoObject *delegate, *exc;
1644 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
1647 if (domain != mono_get_root_domain ())
1650 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
1651 if (delegate == NULL)
1656 mono_runtime_delegate_invoke (delegate, pa, &exc);
1660 * mono_runtime_run_main:
1661 * @method: the method to start the application with (usually Main)
1662 * @argc: number of arguments from the command line
1663 * @argv: array of strings from the command line
1664 * @exc: excetption results
1666 * Execute a standard Main() method (argc/argv contains the
1667 * executable name). This method also sets the command line argument value
1668 * needed by System.Environment.
1673 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
1677 MonoArray *args = NULL;
1678 MonoDomain *domain = mono_domain_get ();
1679 gchar *utf8_fullpath;
1682 mono_thread_set_main (mono_thread_current ());
1684 main_args = g_new0 (char*, argc);
1685 num_main_args = argc;
1687 if (!g_path_is_absolute (argv [0])) {
1688 gchar *basename = g_path_get_basename (argv [0]);
1689 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
1693 utf8_fullpath = mono_utf8_from_external (fullpath);
1694 if(utf8_fullpath == NULL) {
1695 /* Printing the arg text will cause glib to
1696 * whinge about "Invalid UTF-8", but at least
1697 * its relevant, and shows the problem text
1700 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
1701 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
1708 utf8_fullpath = mono_utf8_from_external (argv[0]);
1709 if(utf8_fullpath == NULL) {
1710 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
1711 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
1716 main_args [0] = utf8_fullpath;
1718 for (i = 1; i < argc; ++i) {
1721 utf8_arg=mono_utf8_from_external (argv[i]);
1722 if(utf8_arg==NULL) {
1723 /* Ditto the comment about Invalid UTF-8 here */
1724 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
1725 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
1729 main_args [i] = utf8_arg;
1733 if (mono_method_signature (method)->param_count) {
1734 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
1735 for (i = 0; i < argc; ++i) {
1736 /* The encodings should all work, given that
1737 * we've checked all these args for the
1740 gchar *str = mono_utf8_from_external (argv [i]);
1741 MonoString *arg = mono_string_new (domain, str);
1742 mono_array_set (args, gpointer, i, arg);
1746 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
1749 mono_assembly_set_main (method->klass->image->assembly);
1751 result = mono_runtime_exec_main (method, args, exc);
1752 fire_process_exit_event ();
1756 /* Used in mono_unhandled_exception */
1758 create_unhandled_exception_eventargs (MonoObject *exc)
1762 MonoMethod *method = NULL;
1763 MonoBoolean is_terminating = TRUE;
1766 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
1769 mono_class_init (klass);
1771 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
1772 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
1776 args [1] = &is_terminating;
1778 obj = mono_object_new (mono_domain_get (), klass);
1779 mono_runtime_invoke (method, obj, args, NULL);
1785 * mono_unhandled_exception:
1786 * @exc: exception thrown
1788 * This is a VM internal routine.
1790 * We call this function when we detect an unhandled exception
1791 * in the default domain.
1793 * It invokes the * UnhandledException event in AppDomain or prints
1794 * a warning to the console
1797 mono_unhandled_exception (MonoObject *exc)
1799 MonoDomain *domain = mono_domain_get ();
1800 MonoClassField *field;
1801 MonoObject *delegate;
1803 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
1804 "UnhandledException");
1807 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
1808 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
1810 /* set exitcode only in the main thread */
1811 if (mono_thread_current () == main_thread)
1812 mono_environment_exitcode_set (1);
1813 if (domain != mono_get_root_domain () || !delegate) {
1814 mono_print_unhandled_exception (exc);
1816 MonoObject *e = NULL;
1819 pa [0] = domain->domain;
1820 pa [1] = create_unhandled_exception_eventargs (exc);
1821 mono_runtime_delegate_invoke (delegate, pa, &e);
1824 gchar *msg = mono_string_to_utf8 (((MonoException *) e)->message);
1825 g_warning ("exception inside UnhandledException handler: %s\n", msg);
1833 * Launch a new thread to execute a function
1835 * main_func is called back from the thread with main_args as the
1836 * parameter. The callback function is expected to start Main()
1837 * eventually. This function then waits for all managed threads to
1839 * It is not necesseray anymore to execute managed code in a subthread,
1840 * so this function should not be used anymore by default: just
1841 * execute the code and then call mono_thread_manage ().
1844 mono_runtime_exec_managed_code (MonoDomain *domain,
1845 MonoMainThreadFunc main_func,
1848 mono_thread_create (domain, main_func, main_args);
1850 mono_thread_manage ();
1854 * Execute a standard Main() method (args doesn't contain the
1858 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
1868 domain = mono_object_domain (args);
1869 if (!domain->entry_assembly) {
1871 gchar *config_suffix;
1872 MonoAssembly *assembly;
1874 assembly = method->klass->image->assembly;
1875 domain->entry_assembly = assembly;
1876 domain->setup->application_base = mono_string_new (domain, assembly->basedir);
1878 config_suffix = g_strconcat (assembly->aname.name, ".exe.config", NULL);
1879 str = g_build_filename (assembly->basedir, config_suffix, NULL);
1880 g_free (config_suffix);
1881 domain->setup->configuration_file = mono_string_new (domain, str);
1885 /* FIXME: check signature of method */
1886 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
1888 res = mono_runtime_invoke (method, NULL, pa, exc);
1890 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
1894 mono_environment_exitcode_set (rval);
1896 mono_runtime_invoke (method, NULL, pa, exc);
1900 /* If the return type of Main is void, only
1901 * set the exitcode if an exception was thrown
1902 * (we don't want to blow away an
1903 * explicitly-set exit code)
1906 mono_environment_exitcode_set (rval);
1914 * mono_install_runtime_invoke:
1915 * @func: Function to install
1917 * This is a VM internal routine
1920 mono_install_runtime_invoke (MonoInvokeFunc func)
1922 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
1926 * mono_runtime_invoke_array:
1927 * @method: method to invoke
1928 * @obJ: object instance
1929 * @params: arguments to the method
1930 * @exc: exception information.
1932 * Invokes the method represented by @method on the object @obj.
1934 * obj is the 'this' pointer, it should be NULL for static
1935 * methods, a MonoObject* for object instances and a pointer to
1936 * the value type for value types.
1938 * The params array contains the arguments to the method with the
1939 * same convention: MonoObject* pointers for object instances and
1940 * pointers to the value type otherwise. The _invoke_array
1941 * variant takes a C# object[] as the params argument (MonoArray
1942 * *params): in this case the value types are boxed inside the
1943 * respective reference representation.
1945 * From unmanaged code you'll usually use the
1946 * mono_runtime_invoke() variant.
1948 * Note that this function doesn't handle virtual methods for
1949 * you, it will exec the exact method you pass: we still need to
1950 * expose a function to lookup the derived class implementation
1951 * of a virtual method (there are examples of this in the code,
1954 * You can pass NULL as the exc argument if you don't want to
1955 * catch exceptions, otherwise, *exc will be set to the exception
1956 * thrown, if any. if an exception is thrown, you can't use the
1957 * MonoObject* result from the function.
1959 * If the method returns a value type, it is boxed in an object
1963 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
1966 MonoMethodSignature *sig = mono_method_signature (method);
1967 gpointer *pa = NULL;
1970 if (NULL != params) {
1971 pa = alloca (sizeof (gpointer) * mono_array_length (params));
1972 for (i = 0; i < mono_array_length (params); i++) {
1973 if (sig->params [i]->byref) {
1977 switch (sig->params [i]->type) {
1980 case MONO_TYPE_BOOLEAN:
1983 case MONO_TYPE_CHAR:
1992 case MONO_TYPE_VALUETYPE:
1993 /* MS seems to create the objects if a null is passed in */
1994 if (! ((gpointer *)params->vector)[i])
1995 ((gpointer*)params->vector)[i] = mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i]));
1996 pa [i] = (char *)(((gpointer *)params->vector)[i]) + sizeof (MonoObject);
1998 case MONO_TYPE_STRING:
1999 case MONO_TYPE_OBJECT:
2000 case MONO_TYPE_CLASS:
2001 case MONO_TYPE_ARRAY:
2002 case MONO_TYPE_SZARRAY:
2003 if (sig->params [i]->byref)
2004 pa [i] = &(((gpointer *)params->vector)[i]);
2006 pa [i] = (char *)(((gpointer *)params->vector)[i]);
2009 g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
2014 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
2017 obj = mono_object_new (mono_domain_get (), method->klass);
2018 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
2019 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
2021 if (method->klass->valuetype)
2022 o = mono_object_unbox (obj);
2026 else if (method->klass->valuetype)
2027 obj = mono_value_box (mono_domain_get (), method->klass, obj);
2029 mono_runtime_invoke (method, o, pa, exc);
2032 /* obj must be already unboxed if needed */
2033 return mono_runtime_invoke (method, obj, pa, exc);
2038 arith_overflow (void)
2040 mono_raise_exception (mono_get_exception_overflow ());
2044 * mono_object_allocate:
2045 * @size: number of bytes to allocate
2047 * This is a very simplistic routine until we have our GC-aware
2050 * Returns: an allocated object of size @size, or NULL on failure.
2052 static inline void *
2053 mono_object_allocate (size_t size, MonoVTable *vtable)
2056 mono_stats.new_object_count++;
2057 ALLOC_OBJECT (o, vtable, size);
2063 * mono_object_allocate_ptrfree:
2064 * @size: number of bytes to allocate
2066 * Note that the memory allocated is not zeroed.
2067 * Returns: an allocated object of size @size, or NULL on failure.
2069 static inline void *
2070 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
2073 mono_stats.new_object_count++;
2074 ALLOC_PTRFREE (o, vtable, size);
2078 static inline void *
2079 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
2082 ALLOC_TYPED (o, size, vtable);
2083 mono_stats.new_object_count++;
2090 * @klass: the class of the object that we want to create
2092 * Returns: a newly created object whose definition is
2093 * looked up using @klass. This will not invoke any constructors,
2094 * so the consumer of this routine has to invoke any constructors on
2095 * its own to initialize the object.
2098 mono_object_new (MonoDomain *domain, MonoClass *klass)
2100 MONO_ARCH_SAVE_REGS;
2101 return mono_object_new_specific (mono_class_vtable (domain, klass));
2105 * mono_object_new_specific:
2106 * @vtable: the vtable of the object that we want to create
2108 * Returns: A newly created object with class and domain specified
2112 mono_object_new_specific (MonoVTable *vtable)
2116 MONO_ARCH_SAVE_REGS;
2121 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
2124 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
2127 mono_class_init (klass);
2129 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
2131 vtable->domain->create_proxy_for_type_method = im;
2134 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
2136 o = mono_runtime_invoke (im, NULL, pa, NULL);
2137 if (o != NULL) return o;
2140 return mono_object_new_alloc_specific (vtable);
2144 mono_object_new_alloc_specific (MonoVTable *vtable)
2148 if (!vtable->klass->has_references) {
2149 o = mono_object_new_ptrfree (vtable);
2150 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
2151 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
2153 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
2154 o = mono_object_allocate (vtable->klass->instance_size, vtable);
2156 if (vtable->klass->has_finalize)
2157 mono_object_register_finalizer (o);
2159 mono_profiler_allocation (o, vtable->klass);
2164 mono_object_new_fast (MonoVTable *vtable)
2167 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
2172 mono_object_new_ptrfree (MonoVTable *vtable)
2175 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
2176 #if NEED_TO_ZERO_PTRFREE
2177 /* an inline memset is much faster for the common vcase of small objects
2178 * note we assume the allocated size is a multiple of sizeof (void*).
2180 if (vtable->klass->instance_size < 128) {
2182 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
2183 p = (gpointer*)((char*)obj + sizeof (MonoObject));
2189 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
2196 mono_object_new_ptrfree_box (MonoVTable *vtable)
2199 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
2200 /* the object will be boxed right away, no need to memzero it */
2205 * mono_class_get_allocation_ftn:
2207 * @for_box: the object will be used for boxing
2208 * @pass_size_in_words:
2210 * Return the allocation function appropriate for the given class.
2214 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
2216 *pass_size_in_words = FALSE;
2218 if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
2219 return mono_object_new_specific;
2221 if (!vtable->klass->has_references) {
2222 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
2224 return mono_object_new_ptrfree_box;
2225 return mono_object_new_ptrfree;
2228 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
2230 return mono_object_new_fast;
2233 * FIXME: This is actually slower than mono_object_new_fast, because
2234 * of the overhead of parameter passing.
2237 *pass_size_in_words = TRUE;
2238 #ifdef GC_REDIRECT_TO_LOCAL
2239 return GC_local_gcj_fast_malloc;
2241 return GC_gcj_fast_malloc;
2246 return mono_object_new_specific;
2250 * mono_object_new_from_token:
2251 * @image: Context where the type_token is hosted
2252 * @token: a token of the type that we want to create
2254 * Returns: A newly created object whose definition is
2255 * looked up using @token in the @image image
2258 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
2262 class = mono_class_get (image, token);
2264 return mono_object_new (domain, class);
2269 * mono_object_clone:
2270 * @obj: the object to clone
2272 * Returns: A newly created object who is a shallow copy of @obj
2275 mono_object_clone (MonoObject *obj)
2280 size = obj->vtable->klass->instance_size;
2281 o = mono_object_allocate (size, obj->vtable);
2282 /* do not copy the sync state */
2283 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
2285 mono_profiler_allocation (o, obj->vtable->klass);
2287 if (obj->vtable->klass->has_finalize)
2288 mono_object_register_finalizer (o);
2293 * mono_array_full_copy:
2294 * @src: source array to copy
2295 * @dest: destination array
2297 * Copies the content of one array to another with exactly the same type and size.
2300 mono_array_full_copy (MonoArray *src, MonoArray *dest)
2303 MonoClass *klass = src->obj.vtable->klass;
2305 MONO_ARCH_SAVE_REGS;
2307 g_assert (klass == dest->obj.vtable->klass);
2309 size = mono_array_length (src);
2310 g_assert (size == mono_array_length (dest));
2311 size *= mono_array_element_size (klass);
2312 memcpy (&dest->vector, &src->vector, size);
2316 * mono_array_clone_in_domain:
2317 * @domain: the domain in which the array will be cloned into
2318 * @array: the array to clone
2320 * This routine returns a copy of the array that is hosted on the
2321 * specified MonoDomain.
2324 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
2329 MonoClass *klass = array->obj.vtable->klass;
2331 MONO_ARCH_SAVE_REGS;
2333 if (array->bounds == NULL) {
2334 size = mono_array_length (array);
2335 o = mono_array_new_full (domain, klass, &size, NULL);
2337 size *= mono_array_element_size (klass);
2338 memcpy (&o->vector, &array->vector, size);
2342 sizes = alloca (klass->rank * sizeof(guint32) * 2);
2343 size = mono_array_element_size (klass);
2344 for (i = 0; i < klass->rank; ++i) {
2345 sizes [i] = array->bounds [i].length;
2346 size *= array->bounds [i].length;
2347 sizes [i + klass->rank] = array->bounds [i].lower_bound;
2349 o = mono_array_new_full (domain, klass, sizes, sizes + klass->rank);
2350 memcpy (&o->vector, &array->vector, size);
2357 * @array: the array to clone
2359 * Returns: A newly created array who is a shallow copy of @array
2362 mono_array_clone (MonoArray *array)
2364 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
2367 /* helper macros to check for overflow when calculating the size of arrays */
2368 #define MYGUINT32_MAX 4294967295U
2369 #define CHECK_ADD_OVERFLOW_UN(a,b) \
2370 (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
2371 #define CHECK_MUL_OVERFLOW_UN(a,b) \
2372 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
2373 (guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a))
2376 * mono_array_new_full:
2377 * @domain: domain where the object is created
2378 * @array_class: array class
2379 * @lengths: lengths for each dimension in the array
2380 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
2382 * This routine creates a new array objects with the given dimensions,
2383 * lower bounds and type.
2386 mono_array_new_full (MonoDomain *domain, MonoClass *array_class,
2387 guint32 *lengths, guint32 *lower_bounds)
2389 guint32 byte_len, len, bounds_size;
2395 if (!array_class->inited)
2396 mono_class_init (array_class);
2398 byte_len = mono_array_element_size (array_class);
2401 if (array_class->rank == 1 &&
2402 (lower_bounds == NULL || lower_bounds [0] == 0)) {
2408 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
2410 for (i = 0; i < array_class->rank; ++i) {
2411 if ((int) lengths [i] < 0)
2413 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
2414 mono_gc_out_of_memory (MYGUINT32_MAX);
2419 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
2420 mono_gc_out_of_memory (MYGUINT32_MAX);
2422 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
2423 mono_gc_out_of_memory (MYGUINT32_MAX);
2424 byte_len += sizeof (MonoArray);
2427 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
2428 mono_gc_out_of_memory (MYGUINT32_MAX);
2429 byte_len = (byte_len + 3) & ~3;
2430 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
2431 mono_gc_out_of_memory (MYGUINT32_MAX);
2432 byte_len += bounds_size;
2435 * Following three lines almost taken from mono_object_new ():
2436 * they need to be kept in sync.
2438 vtable = mono_class_vtable (domain, array_class);
2439 if (!array_class->has_references) {
2440 o = mono_object_allocate_ptrfree (byte_len, vtable);
2441 #if NEED_TO_ZERO_PTRFREE
2442 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
2444 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
2445 o = mono_object_allocate_spec (byte_len, vtable);
2447 o = mono_object_allocate (byte_len, vtable);
2450 array = (MonoArray*)o;
2451 array->max_length = len;
2454 MonoArrayBounds *bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
2455 array->bounds = bounds;
2456 for (i = 0; i < array_class->rank; ++i) {
2457 bounds [i].length = lengths [i];
2459 bounds [i].lower_bound = lower_bounds [i];
2463 mono_profiler_allocation (o, array_class);
2470 * @domain: domain where the object is created
2471 * @eclass: element class
2472 * @n: number of array elements
2474 * This routine creates a new szarray with @n elements of type @eclass.
2477 mono_array_new (MonoDomain *domain, MonoClass *eclass, guint32 n)
2481 MONO_ARCH_SAVE_REGS;
2483 ac = mono_array_class_get (eclass, 1);
2484 g_assert (ac != NULL);
2486 return mono_array_new_specific (mono_class_vtable (domain, ac), n);
2490 * mono_array_new_specific:
2491 * @vtable: a vtable in the appropriate domain for an initialized class
2492 * @n: number of array elements
2494 * This routine is a fast alternative to mono_array_new() for code which
2495 * can be sure about the domain it operates in.
2498 mono_array_new_specific (MonoVTable *vtable, guint32 n)
2502 guint32 byte_len, elem_size;
2504 MONO_ARCH_SAVE_REGS;
2509 elem_size = mono_array_element_size (vtable->klass);
2510 if (CHECK_MUL_OVERFLOW_UN (n, elem_size))
2511 mono_gc_out_of_memory (MYGUINT32_MAX);
2512 byte_len = n * elem_size;
2513 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
2514 mono_gc_out_of_memory (MYGUINT32_MAX);
2515 byte_len += sizeof (MonoArray);
2516 if (!vtable->klass->has_references) {
2517 o = mono_object_allocate_ptrfree (byte_len, vtable);
2518 #if NEED_TO_ZERO_PTRFREE
2519 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
2521 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
2522 o = mono_object_allocate_spec (byte_len, vtable);
2524 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
2525 o = mono_object_allocate (byte_len, vtable);
2528 ao = (MonoArray *)o;
2531 mono_profiler_allocation (o, vtable->klass);
2537 * mono_string_new_utf16:
2538 * @text: a pointer to an utf16 string
2539 * @len: the length of the string
2541 * Returns: A newly created string object which contains @text.
2544 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
2548 s = mono_string_new_size (domain, len);
2549 g_assert (s != NULL);
2551 memcpy (mono_string_chars (s), text, len * 2);
2557 * mono_string_new_size:
2558 * @text: a pointer to an utf16 string
2559 * @len: the length of the string
2561 * Returns: A newly created string object of @len
2564 mono_string_new_size (MonoDomain *domain, gint32 len)
2568 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
2570 /* overflow ? can't fit it, can't allocate it! */
2572 mono_gc_out_of_memory (-1);
2574 vtable = mono_class_vtable (domain, mono_defaults.string_class);
2576 s = mono_object_allocate_ptrfree (size, vtable);
2579 #if NEED_TO_ZERO_PTRFREE
2582 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
2588 * mono_string_new_len:
2589 * @text: a pointer to an utf8 string
2590 * @length: number of bytes in @text to consider
2592 * Returns: A newly created string object which contains @text.
2595 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
2597 GError *error = NULL;
2598 MonoString *o = NULL;
2600 glong items_written;
2602 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
2605 o = mono_string_new_utf16 (domain, ut, items_written);
2607 g_error_free (error);
2616 * @text: a pointer to an utf8 string
2618 * Returns: A newly created string object which contains @text.
2621 mono_string_new (MonoDomain *domain, const char *text)
2623 GError *error = NULL;
2624 MonoString *o = NULL;
2626 glong items_written;
2631 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
2634 o = mono_string_new_utf16 (domain, ut, items_written);
2636 g_error_free (error);
2644 * mono_string_new_wrapper:
2645 * @text: pointer to utf8 characters.
2647 * Helper function to create a string object from @text in the current domain.
2650 mono_string_new_wrapper (const char *text)
2652 MonoDomain *domain = mono_domain_get ();
2654 MONO_ARCH_SAVE_REGS;
2657 return mono_string_new (domain, text);
2664 * @class: the class of the value
2665 * @value: a pointer to the unboxed data
2667 * Returns: A newly created object which contains @value.
2670 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
2676 g_assert (class->valuetype);
2678 vtable = mono_class_vtable (domain, class);
2679 size = mono_class_instance_size (class);
2680 res = mono_object_allocate (size, vtable);
2681 mono_profiler_allocation (res, class);
2683 size = size - sizeof (MonoObject);
2685 #if NO_UNALIGNED_ACCESS
2686 memcpy ((char *)res + sizeof (MonoObject), value, size);
2690 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
2693 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
2696 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
2699 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
2702 memcpy ((char *)res + sizeof (MonoObject), value, size);
2705 if (class->has_finalize)
2706 mono_object_register_finalizer (res);
2711 * mono_object_get_domain:
2712 * @obj: object to query
2714 * Returns: the MonoDomain where the object is hosted
2717 mono_object_get_domain (MonoObject *obj)
2719 return mono_object_domain (obj);
2723 * mono_object_get_class:
2724 * @obj: object to query
2726 * Returns: the MonOClass of the object.
2729 mono_object_get_class (MonoObject *obj)
2731 return mono_object_class (obj);
2734 * mono_object_get_size:
2735 * @o: object to query
2737 * Returns: the size, in bytes, of @o
2740 mono_object_get_size (MonoObject* o)
2742 MonoClass* klass = mono_object_class (o);
2744 if (klass == mono_defaults.string_class)
2745 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
2746 else if (klass->parent == mono_defaults.array_class)
2747 return sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length ((MonoArray*) o);
2749 return mono_class_instance_size (klass);
2753 * mono_object_unbox:
2754 * @obj: object to unbox
2756 * Returns: a pointer to the start of the valuetype boxed in this
2759 * This method will assert if the object passed is not a valuetype.
2762 mono_object_unbox (MonoObject *obj)
2764 /* add assert for valuetypes? */
2765 g_assert (obj->vtable->klass->valuetype);
2766 return ((char*)obj) + sizeof (MonoObject);
2770 * mono_object_isinst:
2772 * @klass: a pointer to a class
2774 * Returns: @obj if @obj is derived from @klass
2777 mono_object_isinst (MonoObject *obj, MonoClass *klass)
2780 mono_class_init (klass);
2782 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)
2783 return mono_object_isinst_mbyref (obj, klass);
2788 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
2792 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
2801 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2802 if ((klass->interface_id <= vt->max_interface_id) &&
2803 (vt->interface_offsets [klass->interface_id] != 0))
2807 MonoClass *oklass = vt->klass;
2808 if ((oklass == mono_defaults.transparent_proxy_class))
2809 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2811 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
2815 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
2817 MonoDomain *domain = mono_domain_get ();
2819 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
2820 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
2821 MonoMethod *im = NULL;
2824 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
2825 im = mono_object_get_virtual_method (rp, im);
2828 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
2831 res = mono_runtime_invoke (im, rp, pa, NULL);
2833 if (*(MonoBoolean *) mono_object_unbox(res)) {
2834 /* Update the vtable of the remote type, so it can safely cast to this new type */
2835 mono_upgrade_remote_class (domain, ((MonoTransparentProxy *)obj)->remote_class, klass);
2836 obj->vtable = mono_remote_class_vtable (domain, ((MonoTransparentProxy *)obj)->remote_class, (MonoRealProxy *)rp);
2845 * mono_object_castclass_mbyref:
2847 * @klass: a pointer to a class
2849 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
2852 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
2854 if (!obj) return NULL;
2855 if (mono_object_isinst_mbyref (obj, klass)) return obj;
2857 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
2859 "InvalidCastException"));
2864 MonoDomain *orig_domain;
2870 str_lookup (MonoDomain *domain, gpointer user_data)
2872 LDStrInfo *info = user_data;
2873 if (info->res || domain == info->orig_domain)
2875 mono_domain_lock (domain);
2876 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
2877 mono_domain_unlock (domain);
2881 mono_string_is_interned_lookup (MonoString *str, int insert)
2883 MonoGHashTable *ldstr_table;
2887 domain = ((MonoObject *)str)->vtable->domain;
2888 ldstr_table = domain->ldstr_table;
2889 mono_domain_lock (domain);
2890 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
2891 mono_domain_unlock (domain);
2895 mono_g_hash_table_insert (ldstr_table, str, str);
2896 mono_domain_unlock (domain);
2899 LDStrInfo ldstr_info;
2900 ldstr_info.orig_domain = domain;
2901 ldstr_info.ins = str;
2902 ldstr_info.res = NULL;
2904 mono_domain_foreach (str_lookup, &ldstr_info);
2905 if (ldstr_info.res) {
2907 * the string was already interned in some other domain:
2908 * intern it in the current one as well.
2910 mono_g_hash_table_insert (ldstr_table, str, str);
2911 mono_domain_unlock (domain);
2915 mono_domain_unlock (domain);
2920 * mono_string_is_interned:
2921 * @o: String to probe
2923 * Returns whether the string has been interned.
2926 mono_string_is_interned (MonoString *o)
2928 return mono_string_is_interned_lookup (o, FALSE);
2932 * mono_string_interne:
2933 * @o: String to intern
2935 * Interns the string passed.
2936 * Returns: The interned string.
2939 mono_string_intern (MonoString *str)
2941 return mono_string_is_interned_lookup (str, TRUE);
2946 * @domain: the domain where the string will be used.
2947 * @image: a metadata context
2948 * @idx: index into the user string table.
2950 * Implementation for the ldstr opcode.
2951 * Returns: a loaded string from the @image/@idx combination.
2954 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
2956 MONO_ARCH_SAVE_REGS;
2959 return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx);
2961 return mono_ldstr_metdata_sig (domain, mono_metadata_user_string (image, idx));
2965 * mono_ldstr_metdata_sig
2966 * @domain: the domain for the string
2967 * @sig: the signature of a metadata string
2969 * Returns: a MonoString for a string stored in the metadata
2972 mono_ldstr_metdata_sig (MonoDomain *domain, const char* sig)
2974 const char *str = sig;
2975 MonoString *o, *interned;
2978 len2 = mono_metadata_decode_blob_size (str, &str);
2981 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
2982 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
2985 guint16 *p2 = (guint16*)mono_string_chars (o);
2986 for (i = 0; i < len2; ++i) {
2987 *p2 = GUINT16_FROM_LE (*p2);
2992 mono_domain_lock (domain);
2993 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
2994 mono_domain_unlock (domain);
2995 /* o will get garbage collected */
2999 mono_g_hash_table_insert (domain->ldstr_table, o, o);
3000 mono_domain_unlock (domain);
3006 * mono_string_to_utf8:
3007 * @s: a System.String
3009 * Return the UTF8 representation for @s.
3010 * the resulting buffer nedds to be freed with g_free().
3013 mono_string_to_utf8 (MonoString *s)
3016 GError *error = NULL;
3022 return g_strdup ("");
3024 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, NULL, &error);
3026 g_warning (error->message);
3027 g_error_free (error);
3034 * mono_string_to_utf16:
3037 * Return an null-terminated array of the utf-16 chars
3038 * contained in @s. The result must be freed with g_free().
3039 * This is a temporary helper until our string implementation
3040 * is reworked to always include the null terminating char.
3043 mono_string_to_utf16 (MonoString *s)
3050 as = g_malloc ((s->length * 2) + 2);
3051 as [(s->length * 2)] = '\0';
3052 as [(s->length * 2) + 1] = '\0';
3055 return (gunichar2 *)(as);
3058 memcpy (as, mono_string_chars(s), s->length * 2);
3059 return (gunichar2 *)(as);
3063 * mono_string_from_utf16:
3064 * @data: the UTF16 string (LPWSTR) to convert
3066 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
3068 * Returns: a MonoString.
3071 mono_string_from_utf16 (gunichar2 *data)
3073 MonoDomain *domain = mono_domain_get ();
3079 while (data [len]) len++;
3081 return mono_string_new_utf16 (domain, data, len);
3085 default_ex_handler (MonoException *ex)
3087 MonoObject *o = (MonoObject*)ex;
3088 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
3092 static MonoExceptionFunc ex_handler = default_ex_handler;
3095 * mono_install_handler:
3096 * @func: exception handler
3098 * This is an internal JIT routine used to install the handler for exceptions
3102 mono_install_handler (MonoExceptionFunc func)
3104 ex_handler = func? func: default_ex_handler;
3108 * mono_raise_exception:
3109 * @ex: exception object
3111 * Signal the runtime that the exception @ex has been raised in unmanaged code.
3114 mono_raise_exception (MonoException *ex)
3117 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
3118 * that will cause gcc to omit the function epilog, causing problems when
3119 * the JIT tries to walk the stack, since the return address on the stack
3120 * will point into the next function in the executable, not this one.
3123 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class)
3124 mono_thread_current ()->abort_exc = ex;
3130 * mono_wait_handle_new:
3131 * @domain: Domain where the object will be created
3132 * @handle: Handle for the wait handle
3134 * Returns: A new MonoWaitHandle created in the given domain for the given handle
3137 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
3139 MonoWaitHandle *res;
3141 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
3143 res->handle = handle;
3149 * mono_async_result_new:
3150 * @domain:domain where the object will be created.
3151 * @handle: wait handle.
3152 * @state: state to pass to AsyncResult
3153 * @data: C closure data.
3155 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
3156 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
3160 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data)
3162 MonoAsyncResult *res;
3164 res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
3167 res->async_state = state;
3169 res->handle = (MonoObject *) mono_wait_handle_new (domain, handle);
3171 res->sync_completed = FALSE;
3172 res->completed = FALSE;
3178 mono_message_init (MonoDomain *domain,
3179 MonoMethodMessage *this,
3180 MonoReflectionMethod *method,
3181 MonoArray *out_args)
3183 MonoMethodSignature *sig = mono_method_signature (method->method);
3189 this->method = method;
3191 this->args = mono_array_new (domain, mono_defaults.object_class, sig->param_count);
3192 this->arg_types = mono_array_new (domain, mono_defaults.byte_class, sig->param_count);
3193 this->async_result = NULL;
3194 this->call_type = CallType_Sync;
3196 names = g_new (char *, sig->param_count);
3197 mono_method_get_param_names (method->method, (const char **) names);
3198 this->names = mono_array_new (domain, mono_defaults.string_class, sig->param_count);
3200 for (i = 0; i < sig->param_count; i++) {
3201 name = mono_string_new (domain, names [i]);
3202 mono_array_set (this->names, gpointer, i, name);
3206 for (i = 0, j = 0; i < sig->param_count; i++) {
3208 if (sig->params [i]->byref) {
3210 gpointer arg = mono_array_get (out_args, gpointer, j);
3211 mono_array_set (this->args, gpointer, i, arg);
3215 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
3220 mono_array_set (this->arg_types, guint8, i, arg_type);
3225 * mono_remoting_invoke:
3226 * @real_proxy: pointer to a RealProxy object
3227 * @msg: The MonoMethodMessage to execute
3228 * @exc: used to store exceptions
3229 * @out_args: used to store output arguments
3231 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
3232 * IMessage interface and it is not trivial to extract results from there. So
3233 * we call an helper method PrivateInvoke instead of calling
3234 * RealProxy::Invoke() directly.
3236 * Returns: the result object.
3239 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
3240 MonoObject **exc, MonoArray **out_args)
3242 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
3245 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
3248 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
3250 real_proxy->vtable->domain->private_invoke_method = im;
3253 pa [0] = real_proxy;
3258 return mono_runtime_invoke (im, NULL, pa, exc);
3262 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
3263 MonoObject **exc, MonoArray **out_args)
3267 MonoMethodSignature *sig;
3269 int i, j, outarg_count = 0;
3271 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
3273 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
3274 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3275 target = tp->rp->unwrapped_server;
3277 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
3281 domain = mono_domain_get ();
3282 method = msg->method->method;
3283 sig = mono_method_signature (method);
3285 for (i = 0; i < sig->param_count; i++) {
3286 if (sig->params [i]->byref)
3290 *out_args = mono_array_new (domain, mono_defaults.object_class, outarg_count);
3293 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
3295 for (i = 0, j = 0; i < sig->param_count; i++) {
3296 if (sig->params [i]->byref) {
3298 arg = mono_array_get (msg->args, gpointer, i);
3299 mono_array_set (*out_args, gpointer, j, arg);
3308 * mono_print_unhandled_exception:
3309 * @exc: The exception
3311 * Prints the unhandled exception.
3314 mono_print_unhandled_exception (MonoObject *exc)
3316 char *message = (char *) "";
3320 gboolean free_message = FALSE;
3322 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
3323 klass = exc->vtable->klass;
3325 while (klass && method == NULL) {
3326 method = mono_class_get_method_from_name_flags (klass, "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
3328 klass = klass->parent;
3333 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
3335 message = mono_string_to_utf8 (str);
3336 free_message = TRUE;
3341 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
3342 * exc->vtable->klass->name, message);
3344 g_printerr ("\nUnhandled Exception: %s\n", message);
3351 * mono_delegate_ctor:
3352 * @this: pointer to an uninitialized delegate object
3353 * @target: target object
3354 * @addr: pointer to native code
3356 * This is used to initialize a delegate. We also insert the method_info if
3357 * we find the info with mono_jit_info_table_find().
3360 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
3362 MonoDomain *domain = mono_domain_get ();
3363 MonoDelegate *delegate = (MonoDelegate *)this;
3364 MonoMethod *method = NULL;
3371 class = this->vtable->klass;
3373 if ((ji = mono_jit_info_table_find (domain, addr))) {
3374 method = ji->method;
3375 delegate->method_info = mono_method_get_object (domain, method, NULL);
3378 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
3380 method = mono_marshal_get_remoting_invoke (method);
3381 delegate->method_ptr = mono_compile_method (method);
3382 delegate->target = target;
3383 } else if (mono_method_signature (method)->hasthis && method->klass->valuetype) {
3384 method = mono_marshal_get_unbox_wrapper (method);
3385 delegate->method_ptr = mono_compile_method (method);
3386 delegate->target = target;
3388 delegate->method_ptr = addr;
3389 delegate->target = target;
3394 * mono_method_call_message_new:
3395 * @method: method to encapsulate
3396 * @params: parameters to the method
3397 * @invoke: optional, delegate invoke.
3398 * @cb: async callback delegate.
3399 * @state: state passed to the async callback.
3401 * Translates arguments pointers into a MonoMethodMessage.
3404 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
3405 MonoDelegate **cb, MonoObject **state)
3407 MonoDomain *domain = mono_domain_get ();
3408 MonoMethodSignature *sig = mono_method_signature (method);
3409 MonoMethodMessage *msg;
3412 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3415 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
3416 count = sig->param_count - 2;
3418 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
3419 count = sig->param_count;
3422 for (i = 0; i < count; i++) {
3427 if (sig->params [i]->byref)
3428 vpos = *((gpointer *)params [i]);
3432 type = sig->params [i]->type;
3433 class = mono_class_from_mono_type (sig->params [i]);
3435 if (class->valuetype)
3436 arg = mono_value_box (domain, class, vpos);
3438 arg = *((MonoObject **)vpos);
3440 mono_array_set (msg->args, gpointer, i, arg);
3443 if (cb != NULL && state != NULL) {
3444 *cb = *((MonoDelegate **)params [i]);
3446 *state = *((MonoObject **)params [i]);
3453 * mono_method_return_message_restore:
3455 * Restore results from message based processing back to arguments pointers
3458 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
3460 MonoMethodSignature *sig = mono_method_signature (method);
3461 int i, j, type, size;
3462 for (i = 0, j = 0; i < sig->param_count; i++) {
3463 MonoType *pt = sig->params [i];
3466 char *arg = mono_array_get (out_args, gpointer, j);
3470 case MONO_TYPE_VOID:
3471 g_assert_not_reached ();
3475 case MONO_TYPE_BOOLEAN:
3478 case MONO_TYPE_CHAR:
3485 case MONO_TYPE_VALUETYPE: {
3486 size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
3487 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
3490 case MONO_TYPE_STRING:
3491 case MONO_TYPE_CLASS:
3492 case MONO_TYPE_ARRAY:
3493 case MONO_TYPE_SZARRAY:
3494 case MONO_TYPE_OBJECT:
3495 **((MonoObject ***)params [i]) = (MonoObject *)arg;
3498 g_assert_not_reached ();
3507 * mono_load_remote_field:
3508 * @this: pointer to an object
3509 * @klass: klass of the object containing @field
3510 * @field: the field to load
3511 * @res: a storage to store the result
3513 * This method is called by the runtime on attempts to load fields of
3514 * transparent proxy objects. @this points to such TP, @klass is the class of
3515 * the object containing @field. @res is a storage location which can be
3516 * used to store the result.
3518 * Returns: an address pointing to the value of field.
3521 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
3523 static MonoMethod *getter = NULL;
3524 MonoDomain *domain = mono_domain_get ();
3525 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3526 MonoClass *field_class;
3527 MonoMethodMessage *msg;
3528 MonoArray *out_args;
3532 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3537 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3538 mono_field_get_value (tp->rp->unwrapped_server, field, res);
3543 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
3547 field_class = mono_class_from_mono_type (field->type);
3549 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3550 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
3551 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
3553 mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3554 mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3556 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3558 if (exc) mono_raise_exception ((MonoException *)exc);
3560 if (mono_array_length (out_args) == 0)
3563 *res = mono_array_get (out_args, MonoObject *, 0);
3565 if (field_class->valuetype) {
3566 return ((char *)*res) + sizeof (MonoObject);
3572 * mono_load_remote_field_new:
3577 * Missing documentation.
3580 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
3582 static MonoMethod *getter = NULL;
3583 MonoDomain *domain = mono_domain_get ();
3584 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3585 MonoClass *field_class;
3586 MonoMethodMessage *msg;
3587 MonoArray *out_args;
3588 MonoObject *exc, *res;
3590 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3592 field_class = mono_class_from_mono_type (field->type);
3594 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3596 if (field_class->valuetype) {
3597 res = mono_object_new (domain, field_class);
3598 val = ((gchar *) res) + sizeof (MonoObject);
3602 mono_field_get_value (tp->rp->unwrapped_server, field, val);
3607 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
3611 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3612 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
3614 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
3616 mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3617 mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3619 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3621 if (exc) mono_raise_exception ((MonoException *)exc);
3623 if (mono_array_length (out_args) == 0)
3626 res = mono_array_get (out_args, MonoObject *, 0);
3632 * mono_store_remote_field:
3633 * @this: pointer to an object
3634 * @klass: klass of the object containing @field
3635 * @field: the field to load
3636 * @val: the value/object to store
3638 * This method is called by the runtime on attempts to store fields of
3639 * transparent proxy objects. @this points to such TP, @klass is the class of
3640 * the object containing @field. @val is the new value to store in @field.
3643 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
3645 static MonoMethod *setter = NULL;
3646 MonoDomain *domain = mono_domain_get ();
3647 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3648 MonoClass *field_class;
3649 MonoMethodMessage *msg;
3650 MonoArray *out_args;
3654 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3656 field_class = mono_class_from_mono_type (field->type);
3658 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3659 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
3660 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
3665 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
3669 if (field_class->valuetype)
3670 arg = mono_value_box (domain, field_class, val);
3672 arg = *((MonoObject **)val);
3675 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3676 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
3678 mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3679 mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3680 mono_array_set (msg->args, gpointer, 2, arg);
3682 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3684 if (exc) mono_raise_exception ((MonoException *)exc);
3688 * mono_store_remote_field_new:
3694 * Missing documentation
3697 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
3699 static MonoMethod *setter = NULL;
3700 MonoDomain *domain = mono_domain_get ();
3701 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3702 MonoClass *field_class;
3703 MonoMethodMessage *msg;
3704 MonoArray *out_args;
3707 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3709 field_class = mono_class_from_mono_type (field->type);
3711 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3712 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
3713 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
3718 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
3722 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3723 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
3725 mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3726 mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3727 mono_array_set (msg->args, gpointer, 2, arg);
3729 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3731 if (exc) mono_raise_exception ((MonoException *)exc);