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 if (class->generic_class || class->generic_container)
565 bitmap = default_bitmap;
566 if (class == mono_defaults.string_class) {
567 class->gc_descr = (gpointer)MAKE_STRING_DESCRIPTOR (bitmap, 2);
568 } else if (class->rank) {
569 mono_class_compute_gc_descriptor (class->element_class);
571 /* libgc has no usable support for arrays... */
572 if (!class->element_class->valuetype) {
574 class->gc_descr = mono_gc_make_descr_for_array (TRUE, &abm, 1, sizeof (gpointer));
575 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
576 class->name_space, class->name);*/
578 /* remove the object header */
579 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (sizeof (MonoObject) / sizeof (gpointer)), &max_set);
580 class->gc_descr = mono_gc_make_descr_for_array (TRUE, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
581 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
582 class->name_space, class->name);*/
583 if (bitmap != default_bitmap)
588 /*static int count = 0;
591 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set);
593 /* It seems there are issues when the bitmap doesn't fit: play it safe */
595 /*g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);*/
596 if (bitmap != default_bitmap)
601 class->gc_descr = (gpointer)MAKE_DESCRIPTOR (bitmap, max_set + 1, class->instance_size);
602 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
603 if (bitmap != default_bitmap)
609 * field_is_special_static:
610 * @fklass: The MonoClass to look up.
611 * @field: The MonoClassField describing the field.
613 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
614 * SPECIAL_STATIC_NONE otherwise.
617 field_is_special_static (MonoClass *fklass, MonoClassField *field)
619 MonoCustomAttrInfo *ainfo;
621 ainfo = mono_custom_attrs_from_field (fklass, field);
624 for (i = 0; i < ainfo->num_attrs; ++i) {
625 MonoClass *klass = ainfo->attrs [i].ctor->klass;
626 if (klass->image == mono_defaults.corlib) {
627 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
628 mono_custom_attrs_free (ainfo);
629 return SPECIAL_STATIC_THREAD;
631 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
632 mono_custom_attrs_free (ainfo);
633 return SPECIAL_STATIC_CONTEXT;
637 mono_custom_attrs_free (ainfo);
638 return SPECIAL_STATIC_NONE;
641 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class);
645 * @domain: the application domain
646 * @class: the class to initialize
648 * VTables are domain specific because we create domain specific code, and
649 * they contain the domain specific static class data.
652 mono_class_vtable (MonoDomain *domain, MonoClass *class)
654 MonoClassRuntimeInfo *runtime_info;
658 /* this check can be inlined in jitted code, too */
659 runtime_info = class->runtime_info;
660 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
661 return runtime_info->domain_vtables [domain->domain_id];
662 return mono_class_create_runtime_vtable (domain, class);
666 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
669 MonoClassRuntimeInfo *runtime_info, *old_info;
670 MonoClassField *field;
673 gboolean inited = FALSE;
676 guint32 constant_cols [MONO_CONSTANT_SIZE];
679 mono_domain_lock (domain);
680 runtime_info = class->runtime_info;
681 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
682 mono_domain_unlock (domain);
683 return runtime_info->domain_vtables [domain->domain_id];
686 mono_class_init (class);
688 mono_stats.used_class_count++;
689 mono_stats.class_vtable_size += sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
691 vtable_size = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
693 vt = mono_mempool_alloc0 (domain->mp, vtable_size);
696 vt->rank = class->rank;
699 mono_class_compute_gc_descriptor (class);
701 * We can't use typed allocation in the non-root domains, since the
702 * collector needs the GC descriptor stored in the vtable even after
703 * the mempool containing the vtable is destroyed when the domain is
704 * unloaded. An alternative might be to allocate vtables in the GC
705 * heap, but this does not seem to work (it leads to crashes inside
706 * libgc). If that approach is tried, two gc descriptors need to be
707 * allocated for each class: one for the root domain, and one for all
708 * other domains. The second descriptor should contain a bit for the
709 * vtable field in MonoObject, since we can no longer assume the
710 * vtable is reachable by other roots after the appdomain is unloaded.
713 if (domain != mono_get_root_domain ())
714 vt->gc_descr = GC_NO_DESCRIPTOR;
717 vt->gc_descr = class->gc_descr;
719 if (class->class_size) {
720 if (class->has_static_refs)
721 vt->data = mono_gc_alloc_fixed (class->class_size, NULL);
723 vt->data = mono_mempool_alloc0 (domain->mp, class->class_size);
724 mono_g_hash_table_insert (domain->static_data_hash, class, vt->data);
725 mono_stats.class_static_data_size += class->class_size;
730 while ((field = mono_class_get_fields (class, &iter))) {
731 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
733 if (mono_field_is_deleted (field))
735 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
736 gint32 special_static = field_is_special_static (class, field);
737 if (special_static != SPECIAL_STATIC_NONE) {
738 guint32 size, offset;
740 size = mono_type_size (field->type, &align);
741 offset = mono_alloc_special_static_data (special_static, size, align);
742 if (!domain->special_static_fields)
743 domain->special_static_fields = g_hash_table_new (NULL, NULL);
744 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
748 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
749 MonoClass *fklass = mono_class_from_mono_type (field->type);
750 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
751 t = (char*)vt->data + field->offset;
752 if (fklass->valuetype) {
753 memcpy (t, field->data, mono_class_value_size (fklass, NULL));
755 /* it's a pointer type: add check */
756 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
757 *t = *(char *)field->data;
761 if (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT))
764 /* later do this only on demand if needed */
766 cindex = mono_metadata_get_constant_index (class->image, mono_class_get_field_token (field), cindex + 1);
768 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA));
770 mono_metadata_decode_row (&class->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
771 field->def_type = constant_cols [MONO_CONSTANT_TYPE];
772 field->data = (gpointer)mono_metadata_blob_heap (class->image, constant_cols [MONO_CONSTANT_VALUE]);
777 vt->max_interface_id = class->max_interface_id;
779 vt->interface_offsets = mono_mempool_alloc0 (domain->mp,
780 sizeof (gpointer) * (class->max_interface_id + 1));
782 /* initialize interface offsets */
783 for (i = 0; i <= class->max_interface_id; ++i) {
784 int slot = class->interface_offsets [i];
786 vt->interface_offsets [i] = &(vt->vtable [slot]);
790 * arch_create_jit_trampoline () can recursively call this function again
791 * because it compiles icall methods right away.
793 /* FIXME: class_vtable_hash is basically obsolete now: remove as soon
794 * as we change the code in appdomain.c to invalidate vtables by
795 * looking at the possible MonoClasses created for the domain.
796 * Or we can reuse static_data_hash, by using vtable as a key
797 * and always inserting into that hash.
799 g_hash_table_insert (domain->class_vtable_hash, class, vt);
800 /* class->runtime_info is protected by the loader lock, both when
801 * it it enlarged and when it is stored info.
804 old_info = class->runtime_info;
805 if (old_info && old_info->max_domain >= domain->domain_id) {
806 /* someone already created a large enough runtime info */
807 old_info->domain_vtables [domain->domain_id] = vt;
809 int new_size = domain->domain_id;
811 new_size = MAX (new_size, old_info->max_domain);
813 /* make the new size a power of two */
818 /* this is a bounded memory retention issue: may want to
819 * handle it differently when we'll have a rcu-like system.
821 runtime_info = mono_mempool_alloc0 (class->image->mempool, sizeof (MonoClassRuntimeInfo) + new_size * sizeof (gpointer));
822 runtime_info->max_domain = new_size - 1;
823 /* copy the stuff from the older info */
825 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
827 runtime_info->domain_vtables [domain->domain_id] = vt;
828 /* keep this last (add membarrier) */
829 class->runtime_info = runtime_info;
831 mono_loader_unlock ();
833 /* initialize vtable */
834 if (init_vtable_func)
835 inited = init_vtable_func (vt);
838 mono_class_setup_vtable (class);
840 for (i = 0; i < class->vtable_size; ++i) {
843 if ((cm = class->vtable [i])) {
844 if (mono_method_signature (cm)->generic_param_count)
847 vt->vtable [i] = arch_create_jit_trampoline (cm);
852 mono_domain_unlock (domain);
854 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
855 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND)) {
856 MonoException *exc = mono_class_get_exception_for_failure (class);
858 mono_raise_exception (exc);
861 /* make sure the the parent is initialized */
863 mono_class_vtable (domain, class->parent);
865 vt->type = mono_type_get_object (domain, &class->byval_arg);
866 if (class->contextbound)
875 * mono_class_proxy_vtable:
876 * @domain: the application domain
877 * @remove_class: the remote class
879 * Creates a vtable for transparent proxies. It is basically
880 * a copy of the real vtable of the class wrapped in @remote_class,
881 * but all function pointers invoke the remoting functions, and
882 * vtable->klass points to the transparent proxy class, and not to @class.
885 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
887 MonoVTable *vt, *pvt;
888 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
890 GSList *extra_interfaces = NULL;
891 MonoClass *class = remote_class->proxy_class;
893 vt = mono_class_vtable (domain, class);
894 max_interface_id = vt->max_interface_id;
896 /* Calculate vtable space for extra interfaces */
897 for (j = 0; j < remote_class->interface_count; j++) {
898 MonoClass* iclass = remote_class->interfaces[j];
902 if (iclass->interface_id <= class->max_interface_id && class->interface_offsets[iclass->interface_id] != -1)
903 continue; /* interface implemented by the class */
904 if (g_slist_find (extra_interfaces, iclass))
907 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
909 method_count = mono_class_num_methods (iclass);
911 ifaces = mono_class_get_implemented_interfaces (iclass);
913 for (i = 0; i < ifaces->len; ++i) {
914 MonoClass *ic = g_ptr_array_index (ifaces, i);
915 if (ic->interface_id <= class->max_interface_id && class->interface_offsets[ic->interface_id] != -1)
916 continue; /* interface implemented by the class */
917 if (g_slist_find (extra_interfaces, ic))
919 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
920 method_count += mono_class_num_methods (ic);
922 g_ptr_array_free (ifaces, TRUE);
925 extra_interface_vtsize += method_count * sizeof (gpointer);
926 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
929 vtsize = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
931 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
933 pvt = mono_mempool_alloc (domain->mp, vtsize + extra_interface_vtsize);
934 memcpy (pvt, vt, vtsize);
936 pvt->klass = mono_defaults.transparent_proxy_class;
937 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
938 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
940 /* initialize vtable */
941 mono_class_setup_vtable (class);
942 for (i = 0; i < class->vtable_size; ++i) {
945 if ((cm = class->vtable [i]))
946 pvt->vtable [i] = arch_create_remoting_trampoline (cm, target_type);
949 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
950 /* create trampolines for abstract methods */
951 for (k = class; k; k = k->parent) {
953 gpointer iter = NULL;
954 while ((m = mono_class_get_methods (k, &iter)))
955 if (!pvt->vtable [m->slot])
956 pvt->vtable [m->slot] = arch_create_remoting_trampoline (m, target_type);
960 pvt->max_interface_id = max_interface_id;
961 pvt->interface_offsets = mono_mempool_alloc0 (domain->mp,
962 sizeof (gpointer) * (max_interface_id + 1));
964 /* initialize interface offsets */
965 for (i = 0; i <= class->max_interface_id; ++i) {
966 int slot = class->interface_offsets [i];
968 pvt->interface_offsets [i] = &(pvt->vtable [slot]);
971 if (extra_interfaces) {
972 int slot = class->vtable_size;
978 /* Create trampolines for the methods of the interfaces */
979 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
980 interf = list_item->data;
981 pvt->interface_offsets [interf->interface_id] = &pvt->vtable [slot];
985 while ((cm = mono_class_get_methods (interf, &iter)))
986 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (cm, target_type);
988 slot += mono_class_num_methods (interf);
990 g_slist_free (extra_interfaces);
997 * create_remote_class_key:
998 * Creates an array of pointers that can be used as a hash key for a remote class.
999 * The first element of the array is the number of pointers.
1002 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
1007 if (remote_class == NULL) {
1008 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1009 key = g_malloc (sizeof(gpointer) * 3);
1010 key [0] = GINT_TO_POINTER (2);
1011 key [1] = mono_defaults.marshalbyrefobject_class;
1012 key [2] = extra_class;
1014 key = g_malloc (sizeof(gpointer) * 2);
1015 key [0] = GINT_TO_POINTER (1);
1016 key [1] = extra_class;
1019 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
1020 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
1021 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
1022 key [1] = remote_class->proxy_class;
1024 // Keep the list of interfaces sorted
1025 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
1026 if (extra_class && remote_class->interfaces [i] > extra_class) {
1027 key [j++] = extra_class;
1030 key [j] = remote_class->interfaces [i];
1033 key [j] = extra_class;
1035 // Replace the old class. The interface list is the same
1036 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
1037 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
1038 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
1039 for (i = 0; i < remote_class->interface_count; i++)
1040 key [2 + i] = remote_class->interfaces [i];
1048 * mono_remote_class:
1049 * @domain: the application domain
1050 * @class_name: name of the remote class
1052 * Creates and initializes a MonoRemoteClass object for a remote type.
1056 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
1058 MonoRemoteClass *rc;
1061 key = create_remote_class_key (NULL, proxy_class);
1063 mono_domain_lock (domain);
1064 rc = mono_g_hash_table_lookup (domain->proxy_vtable_hash, key);
1068 mono_domain_unlock (domain);
1072 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1073 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*));
1074 rc->interface_count = 1;
1075 rc->interfaces [0] = proxy_class;
1076 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
1078 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass));
1079 rc->interface_count = 0;
1080 rc->proxy_class = proxy_class;
1083 rc->default_vtable = NULL;
1084 rc->xdomain_vtable = NULL;
1085 rc->proxy_class_name = mono_string_to_utf8 (class_name);
1087 mono_g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
1089 mono_domain_unlock (domain);
1094 * clone_remote_class:
1095 * Creates a copy of the remote_class, adding the provided class or interface
1097 static MonoRemoteClass*
1098 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
1100 MonoRemoteClass *rc;
1103 key = create_remote_class_key (remote_class, extra_class);
1104 rc = mono_g_hash_table_lookup (domain->proxy_vtable_hash, key);
1110 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1112 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * (remote_class->interface_count + 1));
1113 rc->proxy_class = remote_class->proxy_class;
1114 rc->interface_count = remote_class->interface_count + 1;
1116 // Keep the list of interfaces sorted, since the hash key of
1117 // the remote class depends on this
1118 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
1119 if (remote_class->interfaces [i] > extra_class && i == j)
1120 rc->interfaces [j++] = extra_class;
1121 rc->interfaces [j] = remote_class->interfaces [i];
1124 rc->interfaces [j] = extra_class;
1126 // Replace the old class. The interface array is the same
1127 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * remote_class->interface_count);
1128 rc->proxy_class = extra_class;
1129 rc->interface_count = remote_class->interface_count;
1130 if (rc->interface_count > 0)
1131 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
1134 rc->default_vtable = NULL;
1135 rc->xdomain_vtable = NULL;
1136 rc->proxy_class_name = remote_class->proxy_class_name;
1138 mono_g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
1144 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
1146 mono_domain_lock (domain);
1147 if (rp->target_domain_id != -1) {
1148 if (remote_class->xdomain_vtable == NULL)
1149 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
1150 mono_domain_unlock (domain);
1151 return remote_class->xdomain_vtable;
1153 if (remote_class->default_vtable == NULL)
1154 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
1156 mono_domain_unlock (domain);
1157 return remote_class->default_vtable;
1161 * mono_upgrade_remote_class:
1162 * @domain: the application domain
1163 * @tproxy: the proxy whose remote class has to be upgraded.
1164 * @klass: class to which the remote class can be casted.
1166 * Updates the vtable of the remote class by adding the necessary method slots
1167 * and interface offsets so it can be safely casted to klass. klass can be a
1168 * class or an interface.
1171 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
1173 MonoTransparentProxy *tproxy;
1174 MonoRemoteClass *remote_class;
1175 gboolean redo_vtable;
1177 mono_domain_lock (domain);
1179 tproxy = (MonoTransparentProxy*) proxy_object;
1180 remote_class = tproxy->remote_class;
1182 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1185 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
1186 if (remote_class->interfaces [i] == klass)
1187 redo_vtable = FALSE;
1190 redo_vtable = (remote_class->proxy_class != klass);
1194 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
1195 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
1198 mono_domain_unlock (domain);
1203 * mono_object_get_virtual_method:
1204 * @obj: object to operate on.
1207 * Retrieves the MonoMethod that would be called on obj if obj is passed as
1208 * the instance of a callvirt of method.
1211 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
1214 MonoMethod **vtable;
1216 MonoMethod *res = NULL;
1218 klass = mono_object_class (obj);
1219 if (klass == mono_defaults.transparent_proxy_class) {
1220 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
1226 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
1229 mono_class_setup_vtable (klass);
1230 vtable = klass->vtable;
1232 /* check method->slot is a valid index: perform isinstance? */
1233 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1235 res = vtable [klass->interface_offsets [method->klass->interface_id] + method->slot];
1237 if (method->slot != -1)
1238 res = vtable [method->slot];
1242 if (!res) res = method; /* It may be an interface or abstract class method */
1243 res = mono_marshal_get_remoting_invoke (res);
1252 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
1254 g_error ("runtime invoke called on uninitialized runtime");
1258 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
1261 * mono_runtime_invoke:
1262 * @method: method to invoke
1263 * @obJ: object instance
1264 * @params: arguments to the method
1265 * @exc: exception information.
1267 * Invokes the method represented by @method on the object @obj.
1269 * obj is the 'this' pointer, it should be NULL for static
1270 * methods, a MonoObject* for object instances and a pointer to
1271 * the value type for value types.
1273 * The params array contains the arguments to the method with the
1274 * same convention: MonoObject* pointers for object instances and
1275 * pointers to the value type otherwise.
1277 * From unmanaged code you'll usually use the
1278 * mono_runtime_invoke() variant.
1280 * Note that this function doesn't handle virtual methods for
1281 * you, it will exec the exact method you pass: we still need to
1282 * expose a function to lookup the derived class implementation
1283 * of a virtual method (there are examples of this in the code,
1286 * You can pass NULL as the exc argument if you don't want to
1287 * catch exceptions, otherwise, *exc will be set to the exception
1288 * thrown, if any. if an exception is thrown, you can't use the
1289 * MonoObject* result from the function.
1291 * If the method returns a value type, it is boxed in an object
1295 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
1297 return default_mono_runtime_invoke (method, obj, params, exc);
1301 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
1305 gpointer *p = (gpointer*)dest;
1312 case MONO_TYPE_BOOLEAN:
1314 case MONO_TYPE_U1: {
1315 guint8 *p = (guint8*)dest;
1316 *p = value ? *(guint8*)value : 0;
1321 case MONO_TYPE_CHAR: {
1322 guint16 *p = (guint16*)dest;
1323 *p = value ? *(guint16*)value : 0;
1326 #if SIZEOF_VOID_P == 4
1331 case MONO_TYPE_U4: {
1332 gint32 *p = (gint32*)dest;
1333 *p = value ? *(gint32*)value : 0;
1336 #if SIZEOF_VOID_P == 8
1341 case MONO_TYPE_U8: {
1342 gint64 *p = (gint64*)dest;
1343 *p = value ? *(gint64*)value : 0;
1346 case MONO_TYPE_R4: {
1347 float *p = (float*)dest;
1348 *p = value ? *(float*)value : 0;
1351 case MONO_TYPE_R8: {
1352 double *p = (double*)dest;
1353 *p = value ? *(double*)value : 0;
1356 case MONO_TYPE_STRING:
1357 case MONO_TYPE_SZARRAY:
1358 case MONO_TYPE_CLASS:
1359 case MONO_TYPE_OBJECT:
1360 case MONO_TYPE_ARRAY:
1361 case MONO_TYPE_PTR: {
1362 gpointer *p = (gpointer*)dest;
1363 *p = deref_pointer? *(gpointer*)value: value;
1366 case MONO_TYPE_VALUETYPE:
1367 if (type->data.klass->enumtype) {
1368 t = type->data.klass->enum_basetype->type;
1372 size = mono_class_value_size (type->data.klass, NULL);
1374 memset (dest, 0, size);
1376 memcpy (dest, value, size);
1379 case MONO_TYPE_GENERICINST:
1380 t = type->data.generic_class->container_class->byval_arg.type;
1383 g_warning ("got type %x", type->type);
1384 g_assert_not_reached ();
1389 * mono_field_set_value:
1390 * @obj: Instance object
1391 * @field: MonoClassField describing the field to set
1392 * @value: The value to be set
1394 * Sets the value of the field described by @field in the object instance @obj
1395 * to the value passed in @value.
1397 * The value must be on the native format of the field type.
1400 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
1404 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
1406 dest = (char*)obj + field->offset;
1407 set_value (field->type, dest, value, FALSE);
1411 * mono_field_static_set_value:
1412 * @field: MonoClassField describing the field to set
1413 * @value: The value to be set
1415 * Sets the value of the static field described by @field
1416 * to the value passed in @value.
1418 * The value must be on the native format of the field type.
1421 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
1425 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
1426 /* you cant set a constant! */
1427 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
1429 dest = (char*)vt->data + field->offset;
1430 set_value (field->type, dest, value, FALSE);
1434 * mono_field_get_value:
1435 * @obj: Object instance
1436 * @field: MonoClassField describing the field to fetch information from
1437 * @value: pointer to the location where the value will be stored
1439 * Use this routine to get the value of the field @field in the object
1442 * The pointer provided by value must be of the field type, for reference
1443 * types this is a MonoObject*, for value types its the actual pointer to
1448 * mono_field_get_value (obj, int_field, &i);
1451 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
1455 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
1457 src = (char*)obj + field->offset;
1458 set_value (field->type, value, src, TRUE);
1462 * mono_field_get_value_object:
1463 * @domain: domain where the object will be created (if boxing)
1464 * @field: MonoClassField describing the field to fetch information from
1465 * @obj: The object instance for the field.
1467 * Returns: a new MonoObject with the value from the given field. If the
1468 * field represents a value type, the value is boxed.
1472 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
1476 MonoVTable *vtable = NULL;
1478 gboolean is_static = FALSE;
1479 gboolean is_ref = FALSE;
1481 switch (field->type->type) {
1482 case MONO_TYPE_STRING:
1483 case MONO_TYPE_OBJECT:
1484 case MONO_TYPE_CLASS:
1485 case MONO_TYPE_ARRAY:
1486 case MONO_TYPE_SZARRAY:
1491 case MONO_TYPE_BOOLEAN:
1494 case MONO_TYPE_CHAR:
1503 case MONO_TYPE_VALUETYPE:
1504 is_ref = field->type->byref;
1507 g_error ("type 0x%x not handled in "
1508 "mono_field_get_value_object", field->type->type);
1512 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
1514 vtable = mono_class_vtable (domain, field->parent);
1515 if (!vtable->initialized)
1516 mono_runtime_class_init (vtable);
1521 mono_field_static_get_value (vtable, field, &o);
1523 mono_field_get_value (obj, field, &o);
1528 /* boxed value type */
1529 klass = mono_class_from_mono_type (field->type);
1530 o = mono_object_new (domain, klass);
1531 v = ((gchar *) o) + sizeof (MonoObject);
1533 mono_field_static_get_value (vtable, field, v);
1535 mono_field_get_value (obj, field, v);
1542 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
1545 const char *p = blob;
1546 mono_metadata_decode_blob_size (p, &p);
1549 case MONO_TYPE_BOOLEAN:
1552 *(guint8 *) value = *p;
1554 case MONO_TYPE_CHAR:
1557 *(guint16*) value = read16 (p);
1561 *(guint32*) value = read32 (p);
1565 *(guint64*) value = read64 (p);
1568 readr4 (p, (float*) value);
1571 readr8 (p, (double*) value);
1573 case MONO_TYPE_STRING:
1574 *(gpointer*) value = mono_ldstr_metdata_sig (domain, blob);
1576 case MONO_TYPE_CLASS:
1577 *(gpointer*) value = NULL;
1581 g_warning ("type 0x%02x should not be in constant table", type);
1587 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
1589 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT);
1590 mono_get_constant_value_from_blob (domain, field->def_type, field->data, value);
1594 * mono_field_static_get_value:
1595 * @vt: vtable to the object
1596 * @field: MonoClassField describing the field to fetch information from
1597 * @value: where the value is returned
1599 * Use this routine to get the value of the static field @field value.
1601 * The pointer provided by value must be of the field type, for reference
1602 * types this is a MonoObject*, for value types its the actual pointer to
1607 * mono_field_static_get_value (vt, int_field, &i);
1610 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
1614 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
1616 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
1617 get_default_field_value (vt->domain, field, value);
1621 src = (char*)vt->data + field->offset;
1622 set_value (field->type, value, src, TRUE);
1626 * mono_property_set_value:
1627 * @prop: MonoProperty to set
1628 * @obj: instance object on which to act
1629 * @params: parameters to pass to the propery
1630 * @exc: optional exception
1632 * Invokes the property's set method with the given arguments on the
1633 * object instance obj (or NULL for static properties).
1635 * You can pass NULL as the exc argument if you don't want to
1636 * catch exceptions, otherwise, *exc will be set to the exception
1637 * thrown, if any. if an exception is thrown, you can't use the
1638 * MonoObject* result from the function.
1641 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
1643 default_mono_runtime_invoke (prop->set, obj, params, exc);
1647 * mono_property_get_value:
1648 * @prop: MonoProperty to fetch
1649 * @obj: instance object on which to act
1650 * @params: parameters to pass to the propery
1651 * @exc: optional exception
1653 * Invokes the property's get method with the given arguments on the
1654 * object instance obj (or NULL for static properties).
1656 * You can pass NULL as the exc argument if you don't want to
1657 * catch exceptions, otherwise, *exc will be set to the exception
1658 * thrown, if any. if an exception is thrown, you can't use the
1659 * MonoObject* result from the function.
1661 * Returns: the value from invoking the get method on the property.
1664 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
1666 return default_mono_runtime_invoke (prop->get, obj, params, exc);
1671 * mono_get_delegate_invoke:
1672 * @klass: The delegate class
1674 * Returns: the MonoMethod for the "Invoke" method in the delegate klass
1677 mono_get_delegate_invoke (MonoClass *klass)
1681 im = mono_class_get_method_from_name (klass, "Invoke", -1);
1688 * mono_runtime_delegate_invoke:
1689 * @delegate: pointer to a delegate object.
1690 * @params: parameters for the delegate.
1691 * @exc: Pointer to the exception result.
1693 * Invokes the delegate method @delegate with the parameters provided.
1695 * You can pass NULL as the exc argument if you don't want to
1696 * catch exceptions, otherwise, *exc will be set to the exception
1697 * thrown, if any. if an exception is thrown, you can't use the
1698 * MonoObject* result from the function.
1701 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
1705 im = mono_get_delegate_invoke (delegate->vtable->klass);
1708 return mono_runtime_invoke (im, delegate, params, exc);
1711 static char **main_args = NULL;
1712 static int num_main_args;
1715 * mono_runtime_get_main_args:
1717 * Returns: a MonoArray with the arguments passed to the main program
1720 mono_runtime_get_main_args (void)
1724 MonoDomain *domain = mono_domain_get ();
1729 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
1731 for (i = 0; i < num_main_args; ++i)
1732 mono_array_set (res, gpointer, i, mono_string_new (domain, main_args [i]));
1738 fire_process_exit_event (void)
1740 MonoClassField *field;
1741 MonoDomain *domain = mono_domain_get ();
1743 MonoObject *delegate, *exc;
1745 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
1748 if (domain != mono_get_root_domain ())
1751 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
1752 if (delegate == NULL)
1757 mono_runtime_delegate_invoke (delegate, pa, &exc);
1761 * mono_runtime_run_main:
1762 * @method: the method to start the application with (usually Main)
1763 * @argc: number of arguments from the command line
1764 * @argv: array of strings from the command line
1765 * @exc: excetption results
1767 * Execute a standard Main() method (argc/argv contains the
1768 * executable name). This method also sets the command line argument value
1769 * needed by System.Environment.
1774 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
1778 MonoArray *args = NULL;
1779 MonoDomain *domain = mono_domain_get ();
1780 gchar *utf8_fullpath;
1783 mono_thread_set_main (mono_thread_current ());
1785 main_args = g_new0 (char*, argc);
1786 num_main_args = argc;
1788 if (!g_path_is_absolute (argv [0])) {
1789 gchar *basename = g_path_get_basename (argv [0]);
1790 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
1794 utf8_fullpath = mono_utf8_from_external (fullpath);
1795 if(utf8_fullpath == NULL) {
1796 /* Printing the arg text will cause glib to
1797 * whinge about "Invalid UTF-8", but at least
1798 * its relevant, and shows the problem text
1801 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
1802 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
1809 utf8_fullpath = mono_utf8_from_external (argv[0]);
1810 if(utf8_fullpath == NULL) {
1811 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
1812 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
1817 main_args [0] = utf8_fullpath;
1819 for (i = 1; i < argc; ++i) {
1822 utf8_arg=mono_utf8_from_external (argv[i]);
1823 if(utf8_arg==NULL) {
1824 /* Ditto the comment about Invalid UTF-8 here */
1825 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
1826 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
1830 main_args [i] = utf8_arg;
1834 if (mono_method_signature (method)->param_count) {
1835 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
1836 for (i = 0; i < argc; ++i) {
1837 /* The encodings should all work, given that
1838 * we've checked all these args for the
1841 gchar *str = mono_utf8_from_external (argv [i]);
1842 MonoString *arg = mono_string_new (domain, str);
1843 mono_array_set (args, gpointer, i, arg);
1847 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
1850 mono_assembly_set_main (method->klass->image->assembly);
1852 result = mono_runtime_exec_main (method, args, exc);
1853 fire_process_exit_event ();
1857 /* Used in mono_unhandled_exception */
1859 create_unhandled_exception_eventargs (MonoObject *exc)
1863 MonoMethod *method = NULL;
1864 MonoBoolean is_terminating = TRUE;
1867 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
1870 mono_class_init (klass);
1872 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
1873 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
1877 args [1] = &is_terminating;
1879 obj = mono_object_new (mono_domain_get (), klass);
1880 mono_runtime_invoke (method, obj, args, NULL);
1886 * mono_unhandled_exception:
1887 * @exc: exception thrown
1889 * This is a VM internal routine.
1891 * We call this function when we detect an unhandled exception
1892 * in the default domain.
1894 * It invokes the * UnhandledException event in AppDomain or prints
1895 * a warning to the console
1898 mono_unhandled_exception (MonoObject *exc)
1900 MonoDomain *domain = mono_domain_get ();
1901 MonoClassField *field;
1902 MonoObject *delegate;
1904 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
1905 "UnhandledException");
1908 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
1909 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
1911 /* set exitcode only in the main thread */
1912 if (mono_thread_current () == main_thread)
1913 mono_environment_exitcode_set (1);
1914 if (domain != mono_get_root_domain () || !delegate) {
1915 mono_print_unhandled_exception (exc);
1917 MonoObject *e = NULL;
1920 pa [0] = domain->domain;
1921 pa [1] = create_unhandled_exception_eventargs (exc);
1922 mono_runtime_delegate_invoke (delegate, pa, &e);
1925 gchar *msg = mono_string_to_utf8 (((MonoException *) e)->message);
1926 g_warning ("exception inside UnhandledException handler: %s\n", msg);
1934 * Launch a new thread to execute a function
1936 * main_func is called back from the thread with main_args as the
1937 * parameter. The callback function is expected to start Main()
1938 * eventually. This function then waits for all managed threads to
1940 * It is not necesseray anymore to execute managed code in a subthread,
1941 * so this function should not be used anymore by default: just
1942 * execute the code and then call mono_thread_manage ().
1945 mono_runtime_exec_managed_code (MonoDomain *domain,
1946 MonoMainThreadFunc main_func,
1949 mono_thread_create (domain, main_func, main_args);
1951 mono_thread_manage ();
1955 * Execute a standard Main() method (args doesn't contain the
1959 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
1969 domain = mono_object_domain (args);
1970 if (!domain->entry_assembly) {
1972 gchar *config_suffix;
1973 MonoAssembly *assembly;
1975 assembly = method->klass->image->assembly;
1976 domain->entry_assembly = assembly;
1977 domain->setup->application_base = mono_string_new (domain, assembly->basedir);
1979 config_suffix = g_strconcat (assembly->aname.name, ".exe.config", NULL);
1980 str = g_build_filename (assembly->basedir, config_suffix, NULL);
1981 g_free (config_suffix);
1982 domain->setup->configuration_file = mono_string_new (domain, str);
1986 /* FIXME: check signature of method */
1987 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
1989 res = mono_runtime_invoke (method, NULL, pa, exc);
1991 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
1995 mono_environment_exitcode_set (rval);
1997 mono_runtime_invoke (method, NULL, pa, exc);
2001 /* If the return type of Main is void, only
2002 * set the exitcode if an exception was thrown
2003 * (we don't want to blow away an
2004 * explicitly-set exit code)
2007 mono_environment_exitcode_set (rval);
2015 * mono_install_runtime_invoke:
2016 * @func: Function to install
2018 * This is a VM internal routine
2021 mono_install_runtime_invoke (MonoInvokeFunc func)
2023 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
2027 * mono_runtime_invoke_array:
2028 * @method: method to invoke
2029 * @obJ: object instance
2030 * @params: arguments to the method
2031 * @exc: exception information.
2033 * Invokes the method represented by @method on the object @obj.
2035 * obj is the 'this' pointer, it should be NULL for static
2036 * methods, a MonoObject* for object instances and a pointer to
2037 * the value type for value types.
2039 * The params array contains the arguments to the method with the
2040 * same convention: MonoObject* pointers for object instances and
2041 * pointers to the value type otherwise. The _invoke_array
2042 * variant takes a C# object[] as the params argument (MonoArray
2043 * *params): in this case the value types are boxed inside the
2044 * respective reference representation.
2046 * From unmanaged code you'll usually use the
2047 * mono_runtime_invoke() variant.
2049 * Note that this function doesn't handle virtual methods for
2050 * you, it will exec the exact method you pass: we still need to
2051 * expose a function to lookup the derived class implementation
2052 * of a virtual method (there are examples of this in the code,
2055 * You can pass NULL as the exc argument if you don't want to
2056 * catch exceptions, otherwise, *exc will be set to the exception
2057 * thrown, if any. if an exception is thrown, you can't use the
2058 * MonoObject* result from the function.
2060 * If the method returns a value type, it is boxed in an object
2064 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
2067 MonoMethodSignature *sig = mono_method_signature (method);
2068 gpointer *pa = NULL;
2071 if (NULL != params) {
2072 pa = alloca (sizeof (gpointer) * mono_array_length (params));
2073 for (i = 0; i < mono_array_length (params); i++) {
2074 if (sig->params [i]->byref) {
2078 switch (sig->params [i]->type) {
2081 case MONO_TYPE_BOOLEAN:
2084 case MONO_TYPE_CHAR:
2093 case MONO_TYPE_VALUETYPE:
2094 /* MS seems to create the objects if a null is passed in */
2095 if (! ((gpointer *)params->vector)[i])
2096 ((gpointer*)params->vector)[i] = mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i]));
2097 pa [i] = (char *)(((gpointer *)params->vector)[i]) + sizeof (MonoObject);
2099 case MONO_TYPE_STRING:
2100 case MONO_TYPE_OBJECT:
2101 case MONO_TYPE_CLASS:
2102 case MONO_TYPE_ARRAY:
2103 case MONO_TYPE_SZARRAY:
2104 if (sig->params [i]->byref)
2105 pa [i] = &(((gpointer *)params->vector)[i]);
2107 pa [i] = (char *)(((gpointer *)params->vector)[i]);
2110 g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
2115 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
2118 obj = mono_object_new (mono_domain_get (), method->klass);
2119 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
2120 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
2122 if (method->klass->valuetype)
2123 o = mono_object_unbox (obj);
2127 else if (method->klass->valuetype)
2128 obj = mono_value_box (mono_domain_get (), method->klass, obj);
2130 mono_runtime_invoke (method, o, pa, exc);
2133 /* obj must be already unboxed if needed */
2134 return mono_runtime_invoke (method, obj, pa, exc);
2139 arith_overflow (void)
2141 mono_raise_exception (mono_get_exception_overflow ());
2145 * mono_object_allocate:
2146 * @size: number of bytes to allocate
2148 * This is a very simplistic routine until we have our GC-aware
2151 * Returns: an allocated object of size @size, or NULL on failure.
2153 static inline void *
2154 mono_object_allocate (size_t size, MonoVTable *vtable)
2157 mono_stats.new_object_count++;
2158 ALLOC_OBJECT (o, vtable, size);
2164 * mono_object_allocate_ptrfree:
2165 * @size: number of bytes to allocate
2167 * Note that the memory allocated is not zeroed.
2168 * Returns: an allocated object of size @size, or NULL on failure.
2170 static inline void *
2171 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
2174 mono_stats.new_object_count++;
2175 ALLOC_PTRFREE (o, vtable, size);
2179 static inline void *
2180 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
2183 ALLOC_TYPED (o, size, vtable);
2184 mono_stats.new_object_count++;
2191 * @klass: the class of the object that we want to create
2193 * Returns: a newly created object whose definition is
2194 * looked up using @klass. This will not invoke any constructors,
2195 * so the consumer of this routine has to invoke any constructors on
2196 * its own to initialize the object.
2199 mono_object_new (MonoDomain *domain, MonoClass *klass)
2201 MONO_ARCH_SAVE_REGS;
2202 return mono_object_new_specific (mono_class_vtable (domain, klass));
2206 * mono_object_new_specific:
2207 * @vtable: the vtable of the object that we want to create
2209 * Returns: A newly created object with class and domain specified
2213 mono_object_new_specific (MonoVTable *vtable)
2217 MONO_ARCH_SAVE_REGS;
2222 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
2225 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
2228 mono_class_init (klass);
2230 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
2232 vtable->domain->create_proxy_for_type_method = im;
2235 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
2237 o = mono_runtime_invoke (im, NULL, pa, NULL);
2238 if (o != NULL) return o;
2241 return mono_object_new_alloc_specific (vtable);
2245 mono_object_new_alloc_specific (MonoVTable *vtable)
2249 if (!vtable->klass->has_references) {
2250 o = mono_object_new_ptrfree (vtable);
2251 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
2252 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
2254 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
2255 o = mono_object_allocate (vtable->klass->instance_size, vtable);
2257 if (vtable->klass->has_finalize)
2258 mono_object_register_finalizer (o);
2260 mono_profiler_allocation (o, vtable->klass);
2265 mono_object_new_fast (MonoVTable *vtable)
2268 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
2273 mono_object_new_ptrfree (MonoVTable *vtable)
2276 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
2277 #if NEED_TO_ZERO_PTRFREE
2278 /* an inline memset is much faster for the common vcase of small objects
2279 * note we assume the allocated size is a multiple of sizeof (void*).
2281 if (vtable->klass->instance_size < 128) {
2283 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
2284 p = (gpointer*)((char*)obj + sizeof (MonoObject));
2290 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
2297 mono_object_new_ptrfree_box (MonoVTable *vtable)
2300 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
2301 /* the object will be boxed right away, no need to memzero it */
2306 * mono_class_get_allocation_ftn:
2308 * @for_box: the object will be used for boxing
2309 * @pass_size_in_words:
2311 * Return the allocation function appropriate for the given class.
2315 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
2317 *pass_size_in_words = FALSE;
2319 if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
2320 return mono_object_new_specific;
2322 if (!vtable->klass->has_references) {
2323 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
2325 return mono_object_new_ptrfree_box;
2326 return mono_object_new_ptrfree;
2329 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
2331 return mono_object_new_fast;
2334 * FIXME: This is actually slower than mono_object_new_fast, because
2335 * of the overhead of parameter passing.
2338 *pass_size_in_words = TRUE;
2339 #ifdef GC_REDIRECT_TO_LOCAL
2340 return GC_local_gcj_fast_malloc;
2342 return GC_gcj_fast_malloc;
2347 return mono_object_new_specific;
2351 * mono_object_new_from_token:
2352 * @image: Context where the type_token is hosted
2353 * @token: a token of the type that we want to create
2355 * Returns: A newly created object whose definition is
2356 * looked up using @token in the @image image
2359 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
2363 class = mono_class_get (image, token);
2365 return mono_object_new (domain, class);
2370 * mono_object_clone:
2371 * @obj: the object to clone
2373 * Returns: A newly created object who is a shallow copy of @obj
2376 mono_object_clone (MonoObject *obj)
2381 size = obj->vtable->klass->instance_size;
2382 o = mono_object_allocate (size, obj->vtable);
2383 /* do not copy the sync state */
2384 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
2386 mono_profiler_allocation (o, obj->vtable->klass);
2388 if (obj->vtable->klass->has_finalize)
2389 mono_object_register_finalizer (o);
2394 * mono_array_full_copy:
2395 * @src: source array to copy
2396 * @dest: destination array
2398 * Copies the content of one array to another with exactly the same type and size.
2401 mono_array_full_copy (MonoArray *src, MonoArray *dest)
2404 MonoClass *klass = src->obj.vtable->klass;
2406 MONO_ARCH_SAVE_REGS;
2408 g_assert (klass == dest->obj.vtable->klass);
2410 size = mono_array_length (src);
2411 g_assert (size == mono_array_length (dest));
2412 size *= mono_array_element_size (klass);
2413 memcpy (&dest->vector, &src->vector, size);
2417 * mono_array_clone_in_domain:
2418 * @domain: the domain in which the array will be cloned into
2419 * @array: the array to clone
2421 * This routine returns a copy of the array that is hosted on the
2422 * specified MonoDomain.
2425 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
2430 MonoClass *klass = array->obj.vtable->klass;
2432 MONO_ARCH_SAVE_REGS;
2434 if (array->bounds == NULL) {
2435 size = mono_array_length (array);
2436 o = mono_array_new_full (domain, klass, &size, NULL);
2438 size *= mono_array_element_size (klass);
2439 memcpy (&o->vector, &array->vector, size);
2443 sizes = alloca (klass->rank * sizeof(guint32) * 2);
2444 size = mono_array_element_size (klass);
2445 for (i = 0; i < klass->rank; ++i) {
2446 sizes [i] = array->bounds [i].length;
2447 size *= array->bounds [i].length;
2448 sizes [i + klass->rank] = array->bounds [i].lower_bound;
2450 o = mono_array_new_full (domain, klass, sizes, sizes + klass->rank);
2451 memcpy (&o->vector, &array->vector, size);
2458 * @array: the array to clone
2460 * Returns: A newly created array who is a shallow copy of @array
2463 mono_array_clone (MonoArray *array)
2465 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
2468 /* helper macros to check for overflow when calculating the size of arrays */
2469 #define MYGUINT32_MAX 4294967295U
2470 #define CHECK_ADD_OVERFLOW_UN(a,b) \
2471 (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
2472 #define CHECK_MUL_OVERFLOW_UN(a,b) \
2473 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
2474 (guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a))
2477 * mono_array_new_full:
2478 * @domain: domain where the object is created
2479 * @array_class: array class
2480 * @lengths: lengths for each dimension in the array
2481 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
2483 * This routine creates a new array objects with the given dimensions,
2484 * lower bounds and type.
2487 mono_array_new_full (MonoDomain *domain, MonoClass *array_class,
2488 guint32 *lengths, guint32 *lower_bounds)
2490 guint32 byte_len, len, bounds_size;
2496 if (!array_class->inited)
2497 mono_class_init (array_class);
2499 byte_len = mono_array_element_size (array_class);
2502 if (array_class->rank == 1 &&
2503 (lower_bounds == NULL || lower_bounds [0] == 0)) {
2509 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
2511 for (i = 0; i < array_class->rank; ++i) {
2512 if ((int) lengths [i] < 0)
2514 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
2515 mono_gc_out_of_memory (MYGUINT32_MAX);
2520 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
2521 mono_gc_out_of_memory (MYGUINT32_MAX);
2523 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
2524 mono_gc_out_of_memory (MYGUINT32_MAX);
2525 byte_len += sizeof (MonoArray);
2528 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
2529 mono_gc_out_of_memory (MYGUINT32_MAX);
2530 byte_len = (byte_len + 3) & ~3;
2531 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
2532 mono_gc_out_of_memory (MYGUINT32_MAX);
2533 byte_len += bounds_size;
2536 * Following three lines almost taken from mono_object_new ():
2537 * they need to be kept in sync.
2539 vtable = mono_class_vtable (domain, array_class);
2540 if (!array_class->has_references) {
2541 o = mono_object_allocate_ptrfree (byte_len, vtable);
2542 #if NEED_TO_ZERO_PTRFREE
2543 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
2545 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
2546 o = mono_object_allocate_spec (byte_len, vtable);
2548 o = mono_object_allocate (byte_len, vtable);
2551 array = (MonoArray*)o;
2552 array->max_length = len;
2555 MonoArrayBounds *bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
2556 array->bounds = bounds;
2557 for (i = 0; i < array_class->rank; ++i) {
2558 bounds [i].length = lengths [i];
2560 bounds [i].lower_bound = lower_bounds [i];
2564 mono_profiler_allocation (o, array_class);
2571 * @domain: domain where the object is created
2572 * @eclass: element class
2573 * @n: number of array elements
2575 * This routine creates a new szarray with @n elements of type @eclass.
2578 mono_array_new (MonoDomain *domain, MonoClass *eclass, guint32 n)
2582 MONO_ARCH_SAVE_REGS;
2584 ac = mono_array_class_get (eclass, 1);
2585 g_assert (ac != NULL);
2587 return mono_array_new_specific (mono_class_vtable (domain, ac), n);
2591 * mono_array_new_specific:
2592 * @vtable: a vtable in the appropriate domain for an initialized class
2593 * @n: number of array elements
2595 * This routine is a fast alternative to mono_array_new() for code which
2596 * can be sure about the domain it operates in.
2599 mono_array_new_specific (MonoVTable *vtable, guint32 n)
2603 guint32 byte_len, elem_size;
2605 MONO_ARCH_SAVE_REGS;
2610 elem_size = mono_array_element_size (vtable->klass);
2611 if (CHECK_MUL_OVERFLOW_UN (n, elem_size))
2612 mono_gc_out_of_memory (MYGUINT32_MAX);
2613 byte_len = n * elem_size;
2614 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
2615 mono_gc_out_of_memory (MYGUINT32_MAX);
2616 byte_len += sizeof (MonoArray);
2617 if (!vtable->klass->has_references) {
2618 o = mono_object_allocate_ptrfree (byte_len, vtable);
2619 #if NEED_TO_ZERO_PTRFREE
2620 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
2622 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
2623 o = mono_object_allocate_spec (byte_len, vtable);
2625 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
2626 o = mono_object_allocate (byte_len, vtable);
2629 ao = (MonoArray *)o;
2632 mono_profiler_allocation (o, vtable->klass);
2638 * mono_string_new_utf16:
2639 * @text: a pointer to an utf16 string
2640 * @len: the length of the string
2642 * Returns: A newly created string object which contains @text.
2645 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
2649 s = mono_string_new_size (domain, len);
2650 g_assert (s != NULL);
2652 memcpy (mono_string_chars (s), text, len * 2);
2658 * mono_string_new_size:
2659 * @text: a pointer to an utf16 string
2660 * @len: the length of the string
2662 * Returns: A newly created string object of @len
2665 mono_string_new_size (MonoDomain *domain, gint32 len)
2669 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
2671 /* overflow ? can't fit it, can't allocate it! */
2673 mono_gc_out_of_memory (-1);
2675 vtable = mono_class_vtable (domain, mono_defaults.string_class);
2677 s = mono_object_allocate_ptrfree (size, vtable);
2680 #if NEED_TO_ZERO_PTRFREE
2683 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
2689 * mono_string_new_len:
2690 * @text: a pointer to an utf8 string
2691 * @length: number of bytes in @text to consider
2693 * Returns: A newly created string object which contains @text.
2696 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
2698 GError *error = NULL;
2699 MonoString *o = NULL;
2701 glong items_written;
2703 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
2706 o = mono_string_new_utf16 (domain, ut, items_written);
2708 g_error_free (error);
2717 * @text: a pointer to an utf8 string
2719 * Returns: A newly created string object which contains @text.
2722 mono_string_new (MonoDomain *domain, const char *text)
2724 GError *error = NULL;
2725 MonoString *o = NULL;
2727 glong items_written;
2732 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
2735 o = mono_string_new_utf16 (domain, ut, items_written);
2737 g_error_free (error);
2745 * mono_string_new_wrapper:
2746 * @text: pointer to utf8 characters.
2748 * Helper function to create a string object from @text in the current domain.
2751 mono_string_new_wrapper (const char *text)
2753 MonoDomain *domain = mono_domain_get ();
2755 MONO_ARCH_SAVE_REGS;
2758 return mono_string_new (domain, text);
2765 * @class: the class of the value
2766 * @value: a pointer to the unboxed data
2768 * Returns: A newly created object which contains @value.
2771 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
2777 g_assert (class->valuetype);
2779 vtable = mono_class_vtable (domain, class);
2780 size = mono_class_instance_size (class);
2781 res = mono_object_allocate (size, vtable);
2782 mono_profiler_allocation (res, class);
2784 size = size - sizeof (MonoObject);
2786 #if NO_UNALIGNED_ACCESS
2787 memcpy ((char *)res + sizeof (MonoObject), value, size);
2791 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
2794 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
2797 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
2800 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
2803 memcpy ((char *)res + sizeof (MonoObject), value, size);
2806 if (class->has_finalize)
2807 mono_object_register_finalizer (res);
2812 * mono_object_get_domain:
2813 * @obj: object to query
2815 * Returns: the MonoDomain where the object is hosted
2818 mono_object_get_domain (MonoObject *obj)
2820 return mono_object_domain (obj);
2824 * mono_object_get_class:
2825 * @obj: object to query
2827 * Returns: the MonOClass of the object.
2830 mono_object_get_class (MonoObject *obj)
2832 return mono_object_class (obj);
2835 * mono_object_get_size:
2836 * @o: object to query
2838 * Returns: the size, in bytes, of @o
2841 mono_object_get_size (MonoObject* o)
2843 MonoClass* klass = mono_object_class (o);
2845 if (klass == mono_defaults.string_class)
2846 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
2847 else if (klass->parent == mono_defaults.array_class)
2848 return sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length ((MonoArray*) o);
2850 return mono_class_instance_size (klass);
2854 * mono_object_unbox:
2855 * @obj: object to unbox
2857 * Returns: a pointer to the start of the valuetype boxed in this
2860 * This method will assert if the object passed is not a valuetype.
2863 mono_object_unbox (MonoObject *obj)
2865 /* add assert for valuetypes? */
2866 g_assert (obj->vtable->klass->valuetype);
2867 return ((char*)obj) + sizeof (MonoObject);
2871 * mono_object_isinst:
2873 * @klass: a pointer to a class
2875 * Returns: @obj if @obj is derived from @klass
2878 mono_object_isinst (MonoObject *obj, MonoClass *klass)
2881 mono_class_init (klass);
2883 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)
2884 return mono_object_isinst_mbyref (obj, klass);
2889 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
2893 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
2902 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2903 if ((klass->interface_id <= vt->max_interface_id) &&
2904 (vt->interface_offsets [klass->interface_id] != 0))
2908 MonoClass *oklass = vt->klass;
2909 if ((oklass == mono_defaults.transparent_proxy_class))
2910 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2912 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
2916 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
2918 MonoDomain *domain = mono_domain_get ();
2920 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
2921 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
2922 MonoMethod *im = NULL;
2925 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
2926 im = mono_object_get_virtual_method (rp, im);
2929 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
2932 res = mono_runtime_invoke (im, rp, pa, NULL);
2934 if (*(MonoBoolean *) mono_object_unbox(res)) {
2935 /* Update the vtable of the remote type, so it can safely cast to this new type */
2936 mono_upgrade_remote_class (domain, obj, klass);
2945 * mono_object_castclass_mbyref:
2947 * @klass: a pointer to a class
2949 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
2952 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
2954 if (!obj) return NULL;
2955 if (mono_object_isinst_mbyref (obj, klass)) return obj;
2957 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
2959 "InvalidCastException"));
2964 MonoDomain *orig_domain;
2970 str_lookup (MonoDomain *domain, gpointer user_data)
2972 LDStrInfo *info = user_data;
2973 if (info->res || domain == info->orig_domain)
2975 mono_domain_lock (domain);
2976 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
2977 mono_domain_unlock (domain);
2981 mono_string_is_interned_lookup (MonoString *str, int insert)
2983 MonoGHashTable *ldstr_table;
2987 domain = ((MonoObject *)str)->vtable->domain;
2988 ldstr_table = domain->ldstr_table;
2989 mono_domain_lock (domain);
2990 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
2991 mono_domain_unlock (domain);
2995 mono_g_hash_table_insert (ldstr_table, str, str);
2996 mono_domain_unlock (domain);
2999 LDStrInfo ldstr_info;
3000 ldstr_info.orig_domain = domain;
3001 ldstr_info.ins = str;
3002 ldstr_info.res = NULL;
3004 mono_domain_foreach (str_lookup, &ldstr_info);
3005 if (ldstr_info.res) {
3007 * the string was already interned in some other domain:
3008 * intern it in the current one as well.
3010 mono_g_hash_table_insert (ldstr_table, str, str);
3011 mono_domain_unlock (domain);
3015 mono_domain_unlock (domain);
3020 * mono_string_is_interned:
3021 * @o: String to probe
3023 * Returns whether the string has been interned.
3026 mono_string_is_interned (MonoString *o)
3028 return mono_string_is_interned_lookup (o, FALSE);
3032 * mono_string_interne:
3033 * @o: String to intern
3035 * Interns the string passed.
3036 * Returns: The interned string.
3039 mono_string_intern (MonoString *str)
3041 return mono_string_is_interned_lookup (str, TRUE);
3046 * @domain: the domain where the string will be used.
3047 * @image: a metadata context
3048 * @idx: index into the user string table.
3050 * Implementation for the ldstr opcode.
3051 * Returns: a loaded string from the @image/@idx combination.
3054 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
3056 MONO_ARCH_SAVE_REGS;
3059 return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx);
3061 return mono_ldstr_metdata_sig (domain, mono_metadata_user_string (image, idx));
3065 * mono_ldstr_metdata_sig
3066 * @domain: the domain for the string
3067 * @sig: the signature of a metadata string
3069 * Returns: a MonoString for a string stored in the metadata
3072 mono_ldstr_metdata_sig (MonoDomain *domain, const char* sig)
3074 const char *str = sig;
3075 MonoString *o, *interned;
3078 len2 = mono_metadata_decode_blob_size (str, &str);
3081 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
3082 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
3085 guint16 *p2 = (guint16*)mono_string_chars (o);
3086 for (i = 0; i < len2; ++i) {
3087 *p2 = GUINT16_FROM_LE (*p2);
3092 mono_domain_lock (domain);
3093 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
3094 mono_domain_unlock (domain);
3095 /* o will get garbage collected */
3099 mono_g_hash_table_insert (domain->ldstr_table, o, o);
3100 mono_domain_unlock (domain);
3106 * mono_string_to_utf8:
3107 * @s: a System.String
3109 * Return the UTF8 representation for @s.
3110 * the resulting buffer nedds to be freed with g_free().
3113 mono_string_to_utf8 (MonoString *s)
3116 GError *error = NULL;
3122 return g_strdup ("");
3124 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, NULL, &error);
3126 g_warning (error->message);
3127 g_error_free (error);
3134 * mono_string_to_utf16:
3137 * Return an null-terminated array of the utf-16 chars
3138 * contained in @s. The result must be freed with g_free().
3139 * This is a temporary helper until our string implementation
3140 * is reworked to always include the null terminating char.
3143 mono_string_to_utf16 (MonoString *s)
3150 as = g_malloc ((s->length * 2) + 2);
3151 as [(s->length * 2)] = '\0';
3152 as [(s->length * 2) + 1] = '\0';
3155 return (gunichar2 *)(as);
3158 memcpy (as, mono_string_chars(s), s->length * 2);
3159 return (gunichar2 *)(as);
3163 * mono_string_from_utf16:
3164 * @data: the UTF16 string (LPWSTR) to convert
3166 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
3168 * Returns: a MonoString.
3171 mono_string_from_utf16 (gunichar2 *data)
3173 MonoDomain *domain = mono_domain_get ();
3179 while (data [len]) len++;
3181 return mono_string_new_utf16 (domain, data, len);
3185 default_ex_handler (MonoException *ex)
3187 MonoObject *o = (MonoObject*)ex;
3188 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
3192 static MonoExceptionFunc ex_handler = default_ex_handler;
3195 * mono_install_handler:
3196 * @func: exception handler
3198 * This is an internal JIT routine used to install the handler for exceptions
3202 mono_install_handler (MonoExceptionFunc func)
3204 ex_handler = func? func: default_ex_handler;
3208 * mono_raise_exception:
3209 * @ex: exception object
3211 * Signal the runtime that the exception @ex has been raised in unmanaged code.
3214 mono_raise_exception (MonoException *ex)
3217 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
3218 * that will cause gcc to omit the function epilog, causing problems when
3219 * the JIT tries to walk the stack, since the return address on the stack
3220 * will point into the next function in the executable, not this one.
3223 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class)
3224 mono_thread_current ()->abort_exc = ex;
3230 * mono_wait_handle_new:
3231 * @domain: Domain where the object will be created
3232 * @handle: Handle for the wait handle
3234 * Returns: A new MonoWaitHandle created in the given domain for the given handle
3237 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
3239 MonoWaitHandle *res;
3241 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
3243 res->handle = handle;
3249 * mono_async_result_new:
3250 * @domain:domain where the object will be created.
3251 * @handle: wait handle.
3252 * @state: state to pass to AsyncResult
3253 * @data: C closure data.
3255 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
3256 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
3260 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data)
3262 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
3263 MonoMethod *method = mono_get_context_capture_method ();
3265 /* we must capture the execution context from the original thread */
3267 res->execution_context = mono_runtime_invoke (method, NULL, NULL, NULL);
3268 /* note: result may be null if the flow is suppressed */
3272 res->async_state = state;
3274 res->handle = (MonoObject *) mono_wait_handle_new (domain, handle);
3276 res->sync_completed = FALSE;
3277 res->completed = FALSE;
3283 mono_message_init (MonoDomain *domain,
3284 MonoMethodMessage *this,
3285 MonoReflectionMethod *method,
3286 MonoArray *out_args)
3288 MonoMethodSignature *sig = mono_method_signature (method->method);
3294 this->method = method;
3296 this->args = mono_array_new (domain, mono_defaults.object_class, sig->param_count);
3297 this->arg_types = mono_array_new (domain, mono_defaults.byte_class, sig->param_count);
3298 this->async_result = NULL;
3299 this->call_type = CallType_Sync;
3301 names = g_new (char *, sig->param_count);
3302 mono_method_get_param_names (method->method, (const char **) names);
3303 this->names = mono_array_new (domain, mono_defaults.string_class, sig->param_count);
3305 for (i = 0; i < sig->param_count; i++) {
3306 name = mono_string_new (domain, names [i]);
3307 mono_array_set (this->names, gpointer, i, name);
3311 for (i = 0, j = 0; i < sig->param_count; i++) {
3313 if (sig->params [i]->byref) {
3315 gpointer arg = mono_array_get (out_args, gpointer, j);
3316 mono_array_set (this->args, gpointer, i, arg);
3320 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
3324 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
3327 mono_array_set (this->arg_types, guint8, i, arg_type);
3332 * mono_remoting_invoke:
3333 * @real_proxy: pointer to a RealProxy object
3334 * @msg: The MonoMethodMessage to execute
3335 * @exc: used to store exceptions
3336 * @out_args: used to store output arguments
3338 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
3339 * IMessage interface and it is not trivial to extract results from there. So
3340 * we call an helper method PrivateInvoke instead of calling
3341 * RealProxy::Invoke() directly.
3343 * Returns: the result object.
3346 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
3347 MonoObject **exc, MonoArray **out_args)
3349 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
3352 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
3355 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
3357 real_proxy->vtable->domain->private_invoke_method = im;
3360 pa [0] = real_proxy;
3365 return mono_runtime_invoke (im, NULL, pa, exc);
3369 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
3370 MonoObject **exc, MonoArray **out_args)
3374 MonoMethodSignature *sig;
3376 int i, j, outarg_count = 0;
3378 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
3380 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
3381 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3382 target = tp->rp->unwrapped_server;
3384 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
3388 domain = mono_domain_get ();
3389 method = msg->method->method;
3390 sig = mono_method_signature (method);
3392 for (i = 0; i < sig->param_count; i++) {
3393 if (sig->params [i]->byref)
3397 *out_args = mono_array_new (domain, mono_defaults.object_class, outarg_count);
3400 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
3402 for (i = 0, j = 0; i < sig->param_count; i++) {
3403 if (sig->params [i]->byref) {
3405 arg = mono_array_get (msg->args, gpointer, i);
3406 mono_array_set (*out_args, gpointer, j, arg);
3415 * mono_print_unhandled_exception:
3416 * @exc: The exception
3418 * Prints the unhandled exception.
3421 mono_print_unhandled_exception (MonoObject *exc)
3423 char *message = (char *) "";
3427 gboolean free_message = FALSE;
3429 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
3430 klass = exc->vtable->klass;
3432 while (klass && method == NULL) {
3433 method = mono_class_get_method_from_name_flags (klass, "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
3435 klass = klass->parent;
3440 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
3442 message = mono_string_to_utf8 (str);
3443 free_message = TRUE;
3448 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
3449 * exc->vtable->klass->name, message);
3451 g_printerr ("\nUnhandled Exception: %s\n", message);
3458 * mono_delegate_ctor:
3459 * @this: pointer to an uninitialized delegate object
3460 * @target: target object
3461 * @addr: pointer to native code
3463 * This is used to initialize a delegate. We also insert the method_info if
3464 * we find the info with mono_jit_info_table_find().
3467 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
3469 MonoDomain *domain = mono_domain_get ();
3470 MonoDelegate *delegate = (MonoDelegate *)this;
3471 MonoMethod *method = NULL;
3478 class = this->vtable->klass;
3480 if ((ji = mono_jit_info_table_find (domain, addr))) {
3481 method = ji->method;
3482 delegate->method_info = mono_method_get_object (domain, method, NULL);
3485 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
3487 method = mono_marshal_get_remoting_invoke (method);
3488 delegate->method_ptr = mono_compile_method (method);
3489 delegate->target = target;
3490 } else if (mono_method_signature (method)->hasthis && method->klass->valuetype) {
3491 method = mono_marshal_get_unbox_wrapper (method);
3492 delegate->method_ptr = mono_compile_method (method);
3493 delegate->target = target;
3495 delegate->method_ptr = addr;
3496 delegate->target = target;
3501 * mono_method_call_message_new:
3502 * @method: method to encapsulate
3503 * @params: parameters to the method
3504 * @invoke: optional, delegate invoke.
3505 * @cb: async callback delegate.
3506 * @state: state passed to the async callback.
3508 * Translates arguments pointers into a MonoMethodMessage.
3511 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
3512 MonoDelegate **cb, MonoObject **state)
3514 MonoDomain *domain = mono_domain_get ();
3515 MonoMethodSignature *sig = mono_method_signature (method);
3516 MonoMethodMessage *msg;
3519 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3522 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
3523 count = sig->param_count - 2;
3525 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
3526 count = sig->param_count;
3529 for (i = 0; i < count; i++) {
3534 if (sig->params [i]->byref)
3535 vpos = *((gpointer *)params [i]);
3539 type = sig->params [i]->type;
3540 class = mono_class_from_mono_type (sig->params [i]);
3542 if (class->valuetype)
3543 arg = mono_value_box (domain, class, vpos);
3545 arg = *((MonoObject **)vpos);
3547 mono_array_set (msg->args, gpointer, i, arg);
3550 if (cb != NULL && state != NULL) {
3551 *cb = *((MonoDelegate **)params [i]);
3553 *state = *((MonoObject **)params [i]);
3560 * mono_method_return_message_restore:
3562 * Restore results from message based processing back to arguments pointers
3565 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
3567 MonoMethodSignature *sig = mono_method_signature (method);
3568 int i, j, type, size, out_len;
3570 if (out_args == NULL)
3572 out_len = mono_array_length (out_args);
3576 for (i = 0, j = 0; i < sig->param_count; i++) {
3577 MonoType *pt = sig->params [i];
3582 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
3584 arg = mono_array_get (out_args, gpointer, j);
3588 case MONO_TYPE_VOID:
3589 g_assert_not_reached ();
3593 case MONO_TYPE_BOOLEAN:
3596 case MONO_TYPE_CHAR:
3603 case MONO_TYPE_VALUETYPE: {
3604 size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
3605 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
3608 case MONO_TYPE_STRING:
3609 case MONO_TYPE_CLASS:
3610 case MONO_TYPE_ARRAY:
3611 case MONO_TYPE_SZARRAY:
3612 case MONO_TYPE_OBJECT:
3613 **((MonoObject ***)params [i]) = (MonoObject *)arg;
3616 g_assert_not_reached ();
3625 * mono_load_remote_field:
3626 * @this: pointer to an object
3627 * @klass: klass of the object containing @field
3628 * @field: the field to load
3629 * @res: a storage to store the result
3631 * This method is called by the runtime on attempts to load fields of
3632 * transparent proxy objects. @this points to such TP, @klass is the class of
3633 * the object containing @field. @res is a storage location which can be
3634 * used to store the result.
3636 * Returns: an address pointing to the value of field.
3639 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
3641 static MonoMethod *getter = NULL;
3642 MonoDomain *domain = mono_domain_get ();
3643 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3644 MonoClass *field_class;
3645 MonoMethodMessage *msg;
3646 MonoArray *out_args;
3650 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3655 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3656 mono_field_get_value (tp->rp->unwrapped_server, field, res);
3661 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
3665 field_class = mono_class_from_mono_type (field->type);
3667 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3668 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
3669 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
3671 mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3672 mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3674 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3676 if (exc) mono_raise_exception ((MonoException *)exc);
3678 if (mono_array_length (out_args) == 0)
3681 *res = mono_array_get (out_args, MonoObject *, 0);
3683 if (field_class->valuetype) {
3684 return ((char *)*res) + sizeof (MonoObject);
3690 * mono_load_remote_field_new:
3695 * Missing documentation.
3698 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
3700 static MonoMethod *getter = NULL;
3701 MonoDomain *domain = mono_domain_get ();
3702 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3703 MonoClass *field_class;
3704 MonoMethodMessage *msg;
3705 MonoArray *out_args;
3706 MonoObject *exc, *res;
3708 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3710 field_class = mono_class_from_mono_type (field->type);
3712 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3714 if (field_class->valuetype) {
3715 res = mono_object_new (domain, field_class);
3716 val = ((gchar *) res) + sizeof (MonoObject);
3720 mono_field_get_value (tp->rp->unwrapped_server, field, val);
3725 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
3729 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3730 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
3732 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
3734 mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3735 mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3737 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3739 if (exc) mono_raise_exception ((MonoException *)exc);
3741 if (mono_array_length (out_args) == 0)
3744 res = mono_array_get (out_args, MonoObject *, 0);
3750 * mono_store_remote_field:
3751 * @this: pointer to an object
3752 * @klass: klass of the object containing @field
3753 * @field: the field to load
3754 * @val: the value/object to store
3756 * This method is called by the runtime on attempts to store fields of
3757 * transparent proxy objects. @this points to such TP, @klass is the class of
3758 * the object containing @field. @val is the new value to store in @field.
3761 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
3763 static MonoMethod *setter = NULL;
3764 MonoDomain *domain = mono_domain_get ();
3765 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3766 MonoClass *field_class;
3767 MonoMethodMessage *msg;
3768 MonoArray *out_args;
3772 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3774 field_class = mono_class_from_mono_type (field->type);
3776 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3777 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
3778 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
3783 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
3787 if (field_class->valuetype)
3788 arg = mono_value_box (domain, field_class, val);
3790 arg = *((MonoObject **)val);
3793 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3794 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
3796 mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3797 mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3798 mono_array_set (msg->args, gpointer, 2, arg);
3800 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3802 if (exc) mono_raise_exception ((MonoException *)exc);
3806 * mono_store_remote_field_new:
3812 * Missing documentation
3815 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
3817 static MonoMethod *setter = NULL;
3818 MonoDomain *domain = mono_domain_get ();
3819 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3820 MonoClass *field_class;
3821 MonoMethodMessage *msg;
3822 MonoArray *out_args;
3825 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3827 field_class = mono_class_from_mono_type (field->type);
3829 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3830 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
3831 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
3836 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
3840 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3841 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
3843 mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3844 mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3845 mono_array_set (msg->args, gpointer, 2, arg);
3847 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3849 if (exc) mono_raise_exception ((MonoException *)exc);