2 * object.c: Object creation for the Mono runtime
5 * Miguel de Icaza (miguel@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
8 * (C) 2001-2004 Ximian, Inc.
15 #include <mono/metadata/mono-endian.h>
16 #include <mono/metadata/tabledefs.h>
17 #include <mono/metadata/tokentype.h>
18 #include <mono/metadata/loader.h>
19 #include <mono/metadata/object.h>
20 #include <mono/metadata/gc-internal.h>
21 #include <mono/metadata/exception.h>
22 #include <mono/metadata/domain-internals.h>
23 #include "mono/metadata/metadata-internals.h"
24 #include "mono/metadata/class-internals.h"
25 #include <mono/metadata/assembly.h>
26 #include <mono/metadata/threadpool.h>
27 #include <mono/metadata/marshal.h>
28 #include "mono/metadata/debug-helpers.h"
29 #include "mono/metadata/marshal.h"
30 #include <mono/metadata/threads.h>
31 #include <mono/metadata/threads-types.h>
32 #include <mono/metadata/environment.h>
33 #include "mono/metadata/profiler-private.h"
34 #include "mono/metadata/security-manager.h"
35 #include <mono/os/gc_wrapper.h>
36 #include <mono/utils/strenc.h>
39 #define NEED_TO_ZERO_PTRFREE 1
40 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = GC_MALLOC_ATOMIC ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
41 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = GC_MALLOC ((size)); (obj)->vtable = (vt);} while (0)
42 #ifdef HAVE_GC_GCJ_MALLOC
43 #define CREATION_SPEEDUP 1
44 #define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
45 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_GCJ_MALLOC ((size),(type)); } while (0)
46 #define MAKE_STRING_DESCRIPTOR(bitmap,sz) GC_make_descriptor((GC_bitmap)(bitmap),(sz))
47 #define MAKE_DESCRIPTOR(bitmap,sz,objsize) GC_make_descriptor((GC_bitmap)(bitmap),(sz))
49 #define GC_NO_DESCRIPTOR (NULL)
50 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_MALLOC ((size)); *(gpointer*)dest = (type);} while (0)
51 #define MAKE_STRING_DESCRIPTOR(bitmap,sz) NULL
52 #define MAKE_DESCRIPTOR(bitmap,sz,objsize) NULL
56 #define GC_NO_DESCRIPTOR (NULL)
57 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
58 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
59 #define ALLOC_TYPED(dest,size,type) do { (dest) = mono_gc_alloc_obj (type, size);} while (0)
60 #define MAKE_STRING_DESCRIPTOR(bitmap,sz) mono_gc_make_descr_for_string ()
61 #define MAKE_DESCRIPTOR(bitmap,sz,objsize) mono_gc_make_descr_for_object ((bitmap), (sz), (objsize))
63 #define NEED_TO_ZERO_PTRFREE 1
64 #define GC_NO_DESCRIPTOR (NULL)
65 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = malloc ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
66 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = calloc (1, (size)); (obj)->vtable = (vt);} while (0)
67 #define ALLOC_TYPED(dest,size,type) do { (dest) = calloc (1, (size)); *(gpointer*)dest = (type);} while (0)
68 #define MAKE_STRING_DESCRIPTOR(bitmap,sz) NULL
69 #define MAKE_DESCRIPTOR(bitmap,sz,objsize) NULL
73 static MonoObject* mono_object_new_ptrfree (MonoVTable *vtable);
74 static MonoObject* mono_object_new_ptrfree_box (MonoVTable *vtable);
77 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
80 mono_ldstr_metdata_sig (MonoDomain *domain, const char* sig);
83 mono_runtime_object_init (MonoObject *this)
85 MonoMethod *method = NULL;
86 MonoClass *klass = this->vtable->klass;
88 method = mono_class_get_method_from_name (klass, ".ctor", 0);
91 if (method->klass->valuetype)
92 this = mono_object_unbox (this);
93 mono_runtime_invoke (method, this, NULL, NULL);
96 /* The pseudo algorithm for type initialization from the spec
97 Note it doesn't say anything about domains - only threads.
99 2. If the type is initialized you are done.
100 2.1. If the type is not yet initialized, try to take an
102 2.2. If successful, record this thread as responsible for
103 initializing the type and proceed to step 2.3.
104 2.2.1. If not, see whether this thread or any thread
105 waiting for this thread to complete already holds the lock.
106 2.2.2. If so, return since blocking would create a deadlock. This thread
107 will now see an incompletely initialized state for the type,
108 but no deadlock will arise.
109 2.2.3 If not, block until the type is initialized then return.
110 2.3 Initialize the parent type and then all interfaces implemented
112 2.4 Execute the type initialization code for this type.
113 2.5 Mark the type as initialized, release the initialization lock,
114 awaken any threads waiting for this type to be initialized,
121 guint32 initializing_tid;
122 guint32 waiting_count;
124 CRITICAL_SECTION initialization_section;
125 } TypeInitializationLock;
127 /* for locking access to type_initialization_hash and blocked_thread_hash */
128 static CRITICAL_SECTION type_initialization_section;
130 /* from vtable to lock */
131 static GHashTable *type_initialization_hash;
133 /* from thread id to thread id being waited on */
134 static GHashTable *blocked_thread_hash;
137 static MonoThread *main_thread;
140 * mono_thread_set_main:
141 * @thread: thread to set as the main thread
143 * This function can be used to instruct the runtime to treat @thread
144 * as the main thread, ie, the thread that would normally execute the Main()
145 * method. This basically means that at the end of @thread, the runtime will
146 * wait for the existing foreground threads to quit and other such details.
149 mono_thread_set_main (MonoThread *thread)
151 main_thread = thread;
155 mono_thread_get_main (void)
161 mono_type_initialization_init (void)
163 InitializeCriticalSection (&type_initialization_section);
164 type_initialization_hash = g_hash_table_new (NULL, NULL);
165 blocked_thread_hash = g_hash_table_new (NULL, NULL);
169 * mono_runtime_class_init:
170 * @vtable: vtable that needs to be initialized
172 * This routine calls the class constructor for @vtable.
175 mono_runtime_class_init (MonoVTable *vtable)
178 MonoException *exc_to_throw;
179 MonoMethod *method = NULL;
185 if (vtable->initialized)
189 klass = vtable->klass;
191 method = mono_class_get_cctor (klass);
194 MonoDomain *domain = vtable->domain;
195 TypeInitializationLock *lock;
196 guint32 tid = GetCurrentThreadId();
197 int do_initialization = 0;
198 MonoDomain *last_domain = NULL;
200 EnterCriticalSection (&type_initialization_section);
201 /* double check... */
202 if (vtable->initialized) {
203 LeaveCriticalSection (&type_initialization_section);
206 lock = g_hash_table_lookup (type_initialization_hash, vtable);
208 /* This thread will get to do the initialization */
209 if (mono_domain_get () != domain) {
210 /* Transfer into the target domain */
211 last_domain = mono_domain_get ();
212 if (!mono_domain_set (domain, FALSE)) {
213 vtable->initialized = 1;
214 LeaveCriticalSection (&type_initialization_section);
215 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
218 lock = g_malloc (sizeof(TypeInitializationLock));
219 InitializeCriticalSection (&lock->initialization_section);
220 lock->initializing_tid = tid;
221 lock->waiting_count = 1;
223 /* grab the vtable lock while this thread still owns type_initialization_section */
224 EnterCriticalSection (&lock->initialization_section);
225 g_hash_table_insert (type_initialization_hash, vtable, lock);
226 do_initialization = 1;
229 TypeInitializationLock *pending_lock;
231 if (lock->initializing_tid == tid || lock->done) {
232 LeaveCriticalSection (&type_initialization_section);
235 /* see if the thread doing the initialization is already blocked on this thread */
236 blocked = GUINT_TO_POINTER (lock->initializing_tid);
237 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
238 if (pending_lock->initializing_tid == tid) {
239 if (!pending_lock->done) {
240 LeaveCriticalSection (&type_initialization_section);
243 /* the thread doing the initialization is blocked on this thread,
244 but on a lock that has already been freed. It just hasn't got
249 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
251 ++lock->waiting_count;
252 /* record the fact that we are waiting on the initializing thread */
253 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
255 LeaveCriticalSection (&type_initialization_section);
257 if (do_initialization) {
258 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
260 mono_domain_set (last_domain, TRUE);
262 LeaveCriticalSection (&lock->initialization_section);
264 /* this just blocks until the initializing thread is done */
265 EnterCriticalSection (&lock->initialization_section);
266 LeaveCriticalSection (&lock->initialization_section);
269 EnterCriticalSection (&type_initialization_section);
270 if (lock->initializing_tid != tid)
271 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
272 --lock->waiting_count;
273 if (lock->waiting_count == 0) {
274 DeleteCriticalSection (&lock->initialization_section);
275 g_hash_table_remove (type_initialization_hash, vtable);
278 vtable->initialized = 1;
279 /* FIXME: if the cctor fails, the type must be marked as unusable */
280 LeaveCriticalSection (&type_initialization_section);
282 vtable->initialized = 1;
287 (klass->image == mono_defaults.corlib &&
288 !strcmp (klass->name_space, "System") &&
289 !strcmp (klass->name, "TypeInitializationException")))
290 return; /* No static constructor found or avoid infinite loop */
292 if (klass->name_space && *klass->name_space)
293 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
295 full_name = g_strdup (klass->name);
297 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
300 mono_raise_exception (exc_to_throw);
304 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
306 TypeInitializationLock *lock = (TypeInitializationLock*) value;
307 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
309 LeaveCriticalSection (&lock->initialization_section);
310 --lock->waiting_count;
311 if (lock->waiting_count == 0) {
312 DeleteCriticalSection (&lock->initialization_section);
321 mono_release_type_locks (MonoThread *thread)
323 EnterCriticalSection (&type_initialization_section);
324 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
325 LeaveCriticalSection (&type_initialization_section);
329 default_trampoline (MonoMethod *method)
335 default_remoting_trampoline (MonoMethod *method, MonoRemotingTarget target)
337 g_error ("remoting not installed");
341 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
342 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
345 mono_install_trampoline (MonoTrampoline func)
347 arch_create_jit_trampoline = func? func: default_trampoline;
351 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
353 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
356 static MonoCompileFunc default_mono_compile_method = NULL;
359 * mono_install_compile_method:
360 * @func: function to install
362 * This is a VM internal routine
365 mono_install_compile_method (MonoCompileFunc func)
367 default_mono_compile_method = func;
371 * mono_compile_method:
372 * @method: The method to compile.
374 * This JIT-compiles the method, and returns the pointer to the native code
378 mono_compile_method (MonoMethod *method)
380 if (!default_mono_compile_method) {
381 g_error ("compile method called on uninitialized runtime");
384 return default_mono_compile_method (method);
387 static MonoFreeMethodFunc default_mono_free_method = NULL;
390 * mono_install_free_method:
391 * @func: pointer to the MonoFreeMethodFunc used to release a method
393 * This is an internal VM routine, it is used for the engines to
394 * register a handler to release the resources associated with a method.
396 * Methods are freed when no more references to the delegate that holds
400 mono_install_free_method (MonoFreeMethodFunc func)
402 default_mono_free_method = func;
406 * mono_runtime_free_method:
407 * @domain; domain where the method is hosted
408 * @method: method to release
410 * This routine is invoked to free the resources associated with
411 * a method that has been JIT compiled. This is used to discard
412 * methods that were used only temporarily (for example, used in marshalling)
416 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
418 if (default_mono_free_method != NULL)
419 default_mono_free_method (domain, method);
421 mono_free_method (method);
424 static MonoInitVTableFunc init_vtable_func = NULL;
427 * mono_install_init_vtable:
428 * @func: pointer to the function to be installed
430 * Register a function which will be called by the runtime to initialize the
431 * method pointers inside a vtable. The JIT can use this function to load the
432 * vtable from the AOT file for example.
435 mono_install_init_vtable (MonoInitVTableFunc func)
437 init_vtable_func = func;
441 * The vtables in the root appdomain are assumed to be reachable by other
442 * roots, and we don't use typed allocation in the other domains.
445 /* The sync block is no longer a GC pointer */
446 #define GC_HEADER_BITMAP (0)
448 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
451 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set)
453 MonoClassField *field;
456 int max_size = class->instance_size / sizeof (gpointer);
457 if (max_size > size) {
458 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
461 for (p = class; p != NULL; p = p->parent) {
462 gpointer iter = NULL;
463 while ((field = mono_class_get_fields (p, &iter))) {
466 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
468 /* FIXME: should not happen, flag as type load error */
469 if (field->type->byref)
472 pos = field->offset / sizeof (gpointer);
475 type = mono_type_get_underlying_type (field->type);
476 switch (type->type) {
477 /* FIXME: _I and _U and _PTR should be removed eventually */
481 case MONO_TYPE_FNPTR:
482 case MONO_TYPE_STRING:
483 case MONO_TYPE_SZARRAY:
484 case MONO_TYPE_CLASS:
485 case MONO_TYPE_OBJECT:
486 case MONO_TYPE_ARRAY:
487 g_assert ((field->offset % sizeof(gpointer)) == 0);
489 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
490 *max_set = MAX (*max_set, pos);
492 case MONO_TYPE_VALUETYPE: {
493 MonoClass *fclass = field->type->data.klass;
494 if (fclass->has_references) {
495 /* remove the object header */
496 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set);
510 case MONO_TYPE_BOOLEAN:
514 g_assert_not_reached ();
523 mono_class_compute_gc_descriptor (MonoClass *class)
527 gsize default_bitmap [4] = {0};
528 static gboolean gcj_inited = FALSE;
533 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
534 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
535 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
537 #ifdef HAVE_GC_GCJ_MALLOC
539 GC_init_gcj_malloc (5, NULL);
541 #ifdef GC_REDIRECT_TO_LOCAL
542 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
543 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
545 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
546 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
549 mono_loader_unlock ();
553 mono_class_init (class);
555 if (class->gc_descr_inited)
558 class->gc_descr_inited = TRUE;
559 class->gc_descr = GC_NO_DESCRIPTOR;
561 bitmap = default_bitmap;
562 if (class == mono_defaults.string_class) {
563 class->gc_descr = (gpointer)MAKE_STRING_DESCRIPTOR (bitmap, 2);
564 } else if (class->rank) {
565 mono_class_compute_gc_descriptor (class->element_class);
567 /* libgc has no usable support for arrays... */
568 if (!class->element_class->valuetype) {
570 class->gc_descr = mono_gc_make_descr_for_array (TRUE, &abm, 1, sizeof (gpointer));
571 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
572 class->name_space, class->name);*/
574 /* remove the object header */
575 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (sizeof (MonoObject) / sizeof (gpointer)), &max_set);
576 class->gc_descr = mono_gc_make_descr_for_array (TRUE, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
577 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
578 class->name_space, class->name);*/
579 if (bitmap != default_bitmap)
584 /*static int count = 0;
587 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set);
589 /* It seems there are issues when the bitmap doesn't fit: play it safe */
591 /*g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);*/
592 if (bitmap != default_bitmap)
597 class->gc_descr = (gpointer)MAKE_DESCRIPTOR (bitmap, max_set + 1, class->instance_size);
598 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
599 if (bitmap != default_bitmap)
605 * field_is_special_static:
606 * @fklass: The MonoClass to look up.
607 * @field: The MonoClassField describing the field.
609 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
610 * SPECIAL_STATIC_NONE otherwise.
613 field_is_special_static (MonoClass *fklass, MonoClassField *field)
615 MonoCustomAttrInfo *ainfo;
617 ainfo = mono_custom_attrs_from_field (fklass, field);
620 for (i = 0; i < ainfo->num_attrs; ++i) {
621 MonoClass *klass = ainfo->attrs [i].ctor->klass;
622 if (klass->image == mono_defaults.corlib) {
623 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
624 mono_custom_attrs_free (ainfo);
625 return SPECIAL_STATIC_THREAD;
627 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
628 mono_custom_attrs_free (ainfo);
629 return SPECIAL_STATIC_CONTEXT;
633 mono_custom_attrs_free (ainfo);
634 return SPECIAL_STATIC_NONE;
637 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class);
641 * @domain: the application domain
642 * @class: the class to initialize
644 * VTables are domain specific because we create domain specific code, and
645 * they contain the domain specific static class data.
648 mono_class_vtable (MonoDomain *domain, MonoClass *class)
650 MonoClassRuntimeInfo *runtime_info;
654 /* this check can be inlined in jitted code, too */
655 runtime_info = class->runtime_info;
656 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
657 return runtime_info->domain_vtables [domain->domain_id];
658 return mono_class_create_runtime_vtable (domain, class);
662 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
665 MonoClassRuntimeInfo *runtime_info, *old_info;
666 MonoClassField *field;
669 gboolean inited = FALSE;
672 guint32 constant_cols [MONO_CONSTANT_SIZE];
675 mono_domain_lock (domain);
676 runtime_info = class->runtime_info;
677 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
678 mono_domain_unlock (domain);
679 return runtime_info->domain_vtables [domain->domain_id];
682 mono_class_init (class);
684 mono_stats.used_class_count++;
685 mono_stats.class_vtable_size += sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
687 vtable_size = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
689 vt = mono_mempool_alloc0 (domain->mp, vtable_size);
692 vt->rank = class->rank;
695 mono_class_compute_gc_descriptor (class);
697 * We can't use typed allocation in the non-root domains, since the
698 * collector needs the GC descriptor stored in the vtable even after
699 * the mempool containing the vtable is destroyed when the domain is
700 * unloaded. An alternative might be to allocate vtables in the GC
701 * heap, but this does not seem to work (it leads to crashes inside
702 * libgc). If that approach is tried, two gc descriptors need to be
703 * allocated for each class: one for the root domain, and one for all
704 * other domains. The second descriptor should contain a bit for the
705 * vtable field in MonoObject, since we can no longer assume the
706 * vtable is reachable by other roots after the appdomain is unloaded.
709 if (domain != mono_get_root_domain ())
710 vt->gc_descr = GC_NO_DESCRIPTOR;
713 vt->gc_descr = class->gc_descr;
715 if (class->class_size) {
716 if (class->has_static_refs)
717 vt->data = mono_gc_alloc_fixed (class->class_size, NULL);
719 vt->data = mono_mempool_alloc0 (domain->mp, class->class_size);
720 mono_g_hash_table_insert (domain->static_data_hash, class, vt->data);
721 mono_stats.class_static_data_size += class->class_size;
726 while ((field = mono_class_get_fields (class, &iter))) {
727 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
729 if (mono_field_is_deleted (field))
731 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
732 gint32 special_static = field_is_special_static (class, field);
733 if (special_static != SPECIAL_STATIC_NONE) {
734 guint32 size, offset;
736 size = mono_type_size (field->type, &align);
737 offset = mono_alloc_special_static_data (special_static, size, align);
738 if (!domain->special_static_fields)
739 domain->special_static_fields = g_hash_table_new (NULL, NULL);
740 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
744 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
745 MonoClass *fklass = mono_class_from_mono_type (field->type);
746 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
747 t = (char*)vt->data + field->offset;
748 if (fklass->valuetype) {
749 memcpy (t, field->data, mono_class_value_size (fklass, NULL));
751 /* it's a pointer type: add check */
752 g_assert (fklass->byval_arg.type == MONO_TYPE_PTR);
753 *t = *(char *)field->data;
757 if (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT))
760 /* later do this only on demand if needed */
762 cindex = mono_metadata_get_constant_index (class->image, mono_class_get_field_token (field), cindex + 1);
764 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA));
766 mono_metadata_decode_row (&class->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
767 field->def_type = constant_cols [MONO_CONSTANT_TYPE];
768 field->data = (gpointer)mono_metadata_blob_heap (class->image, constant_cols [MONO_CONSTANT_VALUE]);
773 vt->max_interface_id = class->max_interface_id;
775 vt->interface_offsets = mono_mempool_alloc0 (domain->mp,
776 sizeof (gpointer) * (class->max_interface_id + 1));
778 /* initialize interface offsets */
779 for (i = 0; i <= class->max_interface_id; ++i) {
780 int slot = class->interface_offsets [i];
782 vt->interface_offsets [i] = &(vt->vtable [slot]);
786 * arch_create_jit_trampoline () can recursively call this function again
787 * because it compiles icall methods right away.
789 /* FIXME: class_vtable_hash is basically obsolete now: remove as soon
790 * as we change the code in appdomain.c to invalidate vtables by
791 * looking at the possible MonoClasses created for the domain.
792 * Or we can reuse static_data_hash, by using vtable as a key
793 * and always inserting into that hash.
795 g_hash_table_insert (domain->class_vtable_hash, class, vt);
796 /* class->runtime_info is protected by the loader lock, both when
797 * it it enlarged and when it is stored info.
800 old_info = class->runtime_info;
801 if (old_info && old_info->max_domain >= domain->domain_id) {
802 /* someone already created a large enough runtime info */
803 old_info->domain_vtables [domain->domain_id] = vt;
805 int new_size = domain->domain_id;
807 new_size = MAX (new_size, old_info->max_domain);
809 /* make the new size a power of two */
814 /* this is a bounded memory retention issue: may want to
815 * handle it differently when we'll have a rcu-like system.
817 runtime_info = mono_mempool_alloc0 (class->image->mempool, sizeof (MonoClassRuntimeInfo) + new_size * sizeof (gpointer));
818 runtime_info->max_domain = new_size - 1;
819 /* copy the stuff from the older info */
821 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
823 runtime_info->domain_vtables [domain->domain_id] = vt;
824 /* keep this last (add membarrier) */
825 class->runtime_info = runtime_info;
827 mono_loader_unlock ();
829 /* initialize vtable */
830 if (init_vtable_func)
831 inited = init_vtable_func (vt);
834 mono_class_setup_vtable (class);
836 for (i = 0; i < class->vtable_size; ++i) {
839 if ((cm = class->vtable [i])) {
840 if (mono_method_signature (cm)->generic_param_count)
843 vt->vtable [i] = arch_create_jit_trampoline (cm);
848 mono_domain_unlock (domain);
850 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
851 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND)) {
852 MonoException *exc = mono_class_get_exception_for_failure (class);
854 mono_raise_exception (exc);
857 /* make sure the the parent is initialized */
859 mono_class_vtable (domain, class->parent);
861 vt->type = mono_type_get_object (domain, &class->byval_arg);
862 if (class->contextbound)
871 * mono_class_proxy_vtable:
872 * @domain: the application domain
873 * @remove_class: the remote class
875 * Creates a vtable for transparent proxies. It is basically
876 * a copy of the real vtable of the class wrapped in @remote_class,
877 * but all function pointers invoke the remoting functions, and
878 * vtable->klass points to the transparent proxy class, and not to @class.
881 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
883 MonoVTable *vt, *pvt;
884 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
886 GSList *extra_interfaces = NULL;
887 MonoClass *class = remote_class->proxy_class;
889 vt = mono_class_vtable (domain, class);
890 max_interface_id = vt->max_interface_id;
892 /* Calculate vtable space for extra interfaces */
893 for (j = 0; j < remote_class->interface_count; j++) {
894 MonoClass* iclass = remote_class->interfaces[j];
898 if (iclass->interface_id <= class->max_interface_id && class->interface_offsets[iclass->interface_id] != -1)
899 continue; /* interface implemented by the class */
900 if (g_slist_find (extra_interfaces, iclass))
903 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
905 method_count = mono_class_num_methods (iclass);
907 ifaces = mono_class_get_implemented_interfaces (iclass);
909 for (i = 0; i < ifaces->len; ++i) {
910 MonoClass *ic = g_ptr_array_index (ifaces, i);
911 if (ic->interface_id <= class->max_interface_id && class->interface_offsets[ic->interface_id] != -1)
912 continue; /* interface implemented by the class */
913 if (g_slist_find (extra_interfaces, ic))
915 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
916 method_count += mono_class_num_methods (ic);
918 g_ptr_array_free (ifaces, TRUE);
921 extra_interface_vtsize += method_count * sizeof (gpointer);
922 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
925 vtsize = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
927 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
929 pvt = mono_mempool_alloc (domain->mp, vtsize + extra_interface_vtsize);
930 memcpy (pvt, vt, vtsize);
932 pvt->klass = mono_defaults.transparent_proxy_class;
933 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
934 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
936 /* initialize vtable */
937 mono_class_setup_vtable (class);
938 for (i = 0; i < class->vtable_size; ++i) {
941 if ((cm = class->vtable [i]))
942 pvt->vtable [i] = arch_create_remoting_trampoline (cm, target_type);
945 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
946 /* create trampolines for abstract methods */
947 for (k = class; k; k = k->parent) {
949 gpointer iter = NULL;
950 while ((m = mono_class_get_methods (k, &iter)))
951 if (!pvt->vtable [m->slot])
952 pvt->vtable [m->slot] = arch_create_remoting_trampoline (m, target_type);
956 pvt->max_interface_id = max_interface_id;
957 pvt->interface_offsets = mono_mempool_alloc0 (domain->mp,
958 sizeof (gpointer) * (max_interface_id + 1));
960 /* initialize interface offsets */
961 for (i = 0; i <= class->max_interface_id; ++i) {
962 int slot = class->interface_offsets [i];
964 pvt->interface_offsets [i] = &(pvt->vtable [slot]);
967 if (extra_interfaces) {
968 int slot = class->vtable_size;
974 /* Create trampolines for the methods of the interfaces */
975 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
976 interf = list_item->data;
977 pvt->interface_offsets [interf->interface_id] = &pvt->vtable [slot];
981 while ((cm = mono_class_get_methods (interf, &iter)))
982 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (cm, target_type);
984 slot += mono_class_num_methods (interf);
986 g_slist_free (extra_interfaces);
993 * create_remote_class_key:
994 * Creates an array of pointers that can be used as a hash key for a remote class.
995 * The first element of the array is the number of pointers.
998 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
1003 if (remote_class == NULL) {
1004 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1005 key = g_malloc (sizeof(gpointer) * 3);
1006 key [0] = GINT_TO_POINTER (2);
1007 key [1] = mono_defaults.marshalbyrefobject_class;
1008 key [2] = extra_class;
1010 key = g_malloc (sizeof(gpointer) * 2);
1011 key [0] = GINT_TO_POINTER (1);
1012 key [1] = extra_class;
1015 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
1016 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
1017 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
1018 key [1] = remote_class->proxy_class;
1020 // Keep the list of interfaces sorted
1021 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
1022 if (extra_class && remote_class->interfaces [i] > extra_class) {
1023 key [j++] = extra_class;
1026 key [j] = remote_class->interfaces [i];
1029 key [j] = extra_class;
1031 // Replace the old class. The interface list is the same
1032 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
1033 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
1034 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
1035 for (i = 0; i < remote_class->interface_count; i++)
1036 key [2 + i] = remote_class->interfaces [i];
1044 * mono_remote_class:
1045 * @domain: the application domain
1046 * @class_name: name of the remote class
1048 * Creates and initializes a MonoRemoteClass object for a remote type.
1052 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
1054 MonoRemoteClass *rc;
1057 key = create_remote_class_key (NULL, proxy_class);
1059 mono_domain_lock (domain);
1060 rc = mono_g_hash_table_lookup (domain->proxy_vtable_hash, key);
1064 mono_domain_unlock (domain);
1068 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1069 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*));
1070 rc->interface_count = 1;
1071 rc->interfaces [0] = proxy_class;
1072 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
1074 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass));
1075 rc->interface_count = 0;
1076 rc->proxy_class = proxy_class;
1079 rc->default_vtable = NULL;
1080 rc->xdomain_vtable = NULL;
1081 rc->proxy_class_name = mono_string_to_utf8 (class_name);
1083 mono_g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
1085 mono_domain_unlock (domain);
1090 * clone_remote_class:
1091 * Creates a copy of the remote_class, adding the provided class or interface
1093 static MonoRemoteClass*
1094 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
1096 MonoRemoteClass *rc;
1099 key = create_remote_class_key (remote_class, extra_class);
1100 rc = mono_g_hash_table_lookup (domain->proxy_vtable_hash, key);
1106 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1108 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * (remote_class->interface_count + 1));
1109 rc->proxy_class = remote_class->proxy_class;
1110 rc->interface_count = remote_class->interface_count + 1;
1112 // Keep the list of interfaces sorted, since the hash key of
1113 // the remote class depends on this
1114 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
1115 if (remote_class->interfaces [i] > extra_class && i == j)
1116 rc->interfaces [j++] = extra_class;
1117 rc->interfaces [j] = remote_class->interfaces [i];
1120 rc->interfaces [j] = extra_class;
1122 // Replace the old class. The interface array is the same
1123 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * remote_class->interface_count);
1124 rc->proxy_class = extra_class;
1125 rc->interface_count = remote_class->interface_count;
1126 if (rc->interface_count > 0)
1127 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
1130 rc->default_vtable = NULL;
1131 rc->xdomain_vtable = NULL;
1132 rc->proxy_class_name = remote_class->proxy_class_name;
1134 mono_g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
1140 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
1142 mono_domain_lock (domain);
1143 if (rp->target_domain_id != -1) {
1144 if (remote_class->xdomain_vtable == NULL)
1145 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
1146 mono_domain_unlock (domain);
1147 return remote_class->xdomain_vtable;
1149 if (remote_class->default_vtable == NULL)
1150 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
1152 mono_domain_unlock (domain);
1153 return remote_class->default_vtable;
1157 * mono_upgrade_remote_class:
1158 * @domain: the application domain
1159 * @tproxy: the proxy whose remote class has to be upgraded.
1160 * @klass: class to which the remote class can be casted.
1162 * Updates the vtable of the remote class by adding the necessary method slots
1163 * and interface offsets so it can be safely casted to klass. klass can be a
1164 * class or an interface.
1167 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
1169 MonoTransparentProxy *tproxy;
1170 MonoRemoteClass *remote_class;
1171 gboolean redo_vtable;
1173 mono_domain_lock (domain);
1175 tproxy = (MonoTransparentProxy*) proxy_object;
1176 remote_class = tproxy->remote_class;
1178 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1181 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
1182 if (remote_class->interfaces [i] == klass)
1183 redo_vtable = FALSE;
1186 redo_vtable = (remote_class->proxy_class != klass);
1190 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
1191 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
1194 mono_domain_unlock (domain);
1199 * mono_object_get_virtual_method:
1200 * @obj: object to operate on.
1203 * Retrieves the MonoMethod that would be called on obj if obj is passed as
1204 * the instance of a callvirt of method.
1207 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
1210 MonoMethod **vtable;
1212 MonoMethod *res = NULL;
1214 klass = mono_object_class (obj);
1215 if (klass == mono_defaults.transparent_proxy_class) {
1216 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
1222 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
1225 mono_class_setup_vtable (klass);
1226 vtable = klass->vtable;
1228 /* check method->slot is a valid index: perform isinstance? */
1229 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1231 res = vtable [klass->interface_offsets [method->klass->interface_id] + method->slot];
1233 if (method->slot != -1)
1234 res = vtable [method->slot];
1238 if (!res) res = method; /* It may be an interface or abstract class method */
1239 res = mono_marshal_get_remoting_invoke (res);
1248 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
1250 g_error ("runtime invoke called on uninitialized runtime");
1254 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
1257 * mono_runtime_invoke:
1258 * @method: method to invoke
1259 * @obJ: object instance
1260 * @params: arguments to the method
1261 * @exc: exception information.
1263 * Invokes the method represented by @method on the object @obj.
1265 * obj is the 'this' pointer, it should be NULL for static
1266 * methods, a MonoObject* for object instances and a pointer to
1267 * the value type for value types.
1269 * The params array contains the arguments to the method with the
1270 * same convention: MonoObject* pointers for object instances and
1271 * pointers to the value type otherwise.
1273 * From unmanaged code you'll usually use the
1274 * mono_runtime_invoke() variant.
1276 * Note that this function doesn't handle virtual methods for
1277 * you, it will exec the exact method you pass: we still need to
1278 * expose a function to lookup the derived class implementation
1279 * of a virtual method (there are examples of this in the code,
1282 * You can pass NULL as the exc argument if you don't want to
1283 * catch exceptions, otherwise, *exc will be set to the exception
1284 * thrown, if any. if an exception is thrown, you can't use the
1285 * MonoObject* result from the function.
1287 * If the method returns a value type, it is boxed in an object
1291 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
1293 return default_mono_runtime_invoke (method, obj, params, exc);
1297 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
1301 gpointer *p = (gpointer*)dest;
1308 case MONO_TYPE_BOOLEAN:
1310 case MONO_TYPE_U1: {
1311 guint8 *p = (guint8*)dest;
1312 *p = value ? *(guint8*)value : 0;
1317 case MONO_TYPE_CHAR: {
1318 guint16 *p = (guint16*)dest;
1319 *p = value ? *(guint16*)value : 0;
1322 #if SIZEOF_VOID_P == 4
1327 case MONO_TYPE_U4: {
1328 gint32 *p = (gint32*)dest;
1329 *p = value ? *(gint32*)value : 0;
1332 #if SIZEOF_VOID_P == 8
1337 case MONO_TYPE_U8: {
1338 gint64 *p = (gint64*)dest;
1339 *p = value ? *(gint64*)value : 0;
1342 case MONO_TYPE_R4: {
1343 float *p = (float*)dest;
1344 *p = value ? *(float*)value : 0;
1347 case MONO_TYPE_R8: {
1348 double *p = (double*)dest;
1349 *p = value ? *(double*)value : 0;
1352 case MONO_TYPE_STRING:
1353 case MONO_TYPE_SZARRAY:
1354 case MONO_TYPE_CLASS:
1355 case MONO_TYPE_OBJECT:
1356 case MONO_TYPE_ARRAY:
1357 case MONO_TYPE_PTR: {
1358 gpointer *p = (gpointer*)dest;
1359 *p = deref_pointer? *(gpointer*)value: value;
1362 case MONO_TYPE_VALUETYPE:
1363 if (type->data.klass->enumtype) {
1364 t = type->data.klass->enum_basetype->type;
1368 size = mono_class_value_size (type->data.klass, NULL);
1370 memset (dest, 0, size);
1372 memcpy (dest, value, size);
1376 g_warning ("got type %x", type->type);
1377 g_assert_not_reached ();
1382 * mono_field_set_value:
1383 * @obj: Instance object
1384 * @field: MonoClassField describing the field to set
1385 * @value: The value to be set
1387 * Sets the value of the field described by @field in the object instance @obj
1388 * to the value passed in @value.
1390 * The value must be on the native format of the field type.
1393 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
1397 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
1399 dest = (char*)obj + field->offset;
1400 set_value (field->type, dest, value, FALSE);
1404 * mono_field_static_set_value:
1405 * @field: MonoClassField describing the field to set
1406 * @value: The value to be set
1408 * Sets the value of the static field described by @field
1409 * to the value passed in @value.
1411 * The value must be on the native format of the field type.
1414 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
1418 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
1419 /* you cant set a constant! */
1420 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
1422 dest = (char*)vt->data + field->offset;
1423 set_value (field->type, dest, value, FALSE);
1427 * mono_field_get_value:
1428 * @obj: Object instance
1429 * @field: MonoClassField describing the field to fetch information from
1430 * @value: pointer to the location where the value will be stored
1432 * Use this routine to get the value of the field @field in the object
1435 * The pointer provided by value must be of the field type, for reference
1436 * types this is a MonoObject*, for value types its the actual pointer to
1441 * mono_field_get_value (obj, int_field, &i);
1444 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
1448 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
1450 src = (char*)obj + field->offset;
1451 set_value (field->type, value, src, TRUE);
1455 * mono_field_get_value_object:
1456 * @domain: domain where the object will be created (if boxing)
1457 * @field: MonoClassField describing the field to fetch information from
1458 * @obj: The object instance for the field.
1460 * Returns: a new MonoObject with the value from the given field. If the
1461 * field represents a value type, the value is boxed.
1465 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
1469 MonoVTable *vtable = NULL;
1471 gboolean is_static = FALSE;
1472 gboolean is_ref = FALSE;
1474 switch (field->type->type) {
1475 case MONO_TYPE_STRING:
1476 case MONO_TYPE_OBJECT:
1477 case MONO_TYPE_CLASS:
1478 case MONO_TYPE_ARRAY:
1479 case MONO_TYPE_SZARRAY:
1484 case MONO_TYPE_BOOLEAN:
1487 case MONO_TYPE_CHAR:
1496 case MONO_TYPE_VALUETYPE:
1497 is_ref = field->type->byref;
1500 g_error ("type 0x%x not handled in "
1501 "mono_field_get_value_object", field->type->type);
1505 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
1507 vtable = mono_class_vtable (domain, field->parent);
1508 if (!vtable->initialized)
1509 mono_runtime_class_init (vtable);
1514 mono_field_static_get_value (vtable, field, &o);
1516 mono_field_get_value (obj, field, &o);
1521 /* boxed value type */
1522 klass = mono_class_from_mono_type (field->type);
1523 o = mono_object_new (domain, klass);
1524 v = ((gchar *) o) + sizeof (MonoObject);
1526 mono_field_static_get_value (vtable, field, v);
1528 mono_field_get_value (obj, field, v);
1535 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
1538 const char *p = blob;
1539 mono_metadata_decode_blob_size (p, &p);
1542 case MONO_TYPE_BOOLEAN:
1545 *(guint8 *) value = *p;
1547 case MONO_TYPE_CHAR:
1550 *(guint16*) value = read16 (p);
1554 *(guint32*) value = read32 (p);
1558 *(guint64*) value = read64 (p);
1561 readr4 (p, (float*) value);
1564 readr8 (p, (double*) value);
1566 case MONO_TYPE_STRING:
1567 *(gpointer*) value = mono_ldstr_metdata_sig (domain, blob);
1569 case MONO_TYPE_CLASS:
1570 *(gpointer*) value = NULL;
1574 g_warning ("type 0x%02x should not be in constant table", type);
1580 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
1582 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT);
1583 mono_get_constant_value_from_blob (domain, field->def_type, field->data, value);
1587 * mono_field_static_get_value:
1588 * @vt: vtable to the object
1589 * @field: MonoClassField describing the field to fetch information from
1590 * @value: where the value is returned
1592 * Use this routine to get the value of the static field @field value.
1594 * The pointer provided by value must be of the field type, for reference
1595 * types this is a MonoObject*, for value types its the actual pointer to
1600 * mono_field_static_get_value (vt, int_field, &i);
1603 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
1607 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
1609 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
1610 get_default_field_value (vt->domain, field, value);
1614 src = (char*)vt->data + field->offset;
1615 set_value (field->type, value, src, TRUE);
1619 * mono_property_set_value:
1620 * @prop: MonoProperty to set
1621 * @obj: instance object on which to act
1622 * @params: parameters to pass to the propery
1623 * @exc: optional exception
1625 * Invokes the property's set method with the given arguments on the
1626 * object instance obj (or NULL for static properties).
1628 * You can pass NULL as the exc argument if you don't want to
1629 * catch exceptions, otherwise, *exc will be set to the exception
1630 * thrown, if any. if an exception is thrown, you can't use the
1631 * MonoObject* result from the function.
1634 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
1636 default_mono_runtime_invoke (prop->set, obj, params, exc);
1640 * mono_property_get_value:
1641 * @prop: MonoProperty to fetch
1642 * @obj: instance object on which to act
1643 * @params: parameters to pass to the propery
1644 * @exc: optional exception
1646 * Invokes the property's get method with the given arguments on the
1647 * object instance obj (or NULL for static properties).
1649 * You can pass NULL as the exc argument if you don't want to
1650 * catch exceptions, otherwise, *exc will be set to the exception
1651 * thrown, if any. if an exception is thrown, you can't use the
1652 * MonoObject* result from the function.
1654 * Returns: the value from invoking the get method on the property.
1657 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
1659 return default_mono_runtime_invoke (prop->get, obj, params, exc);
1664 * mono_get_delegate_invoke:
1665 * @klass: The delegate class
1667 * Returns: the MonoMethod for the "Invoke" method in the delegate klass
1670 mono_get_delegate_invoke (MonoClass *klass)
1674 im = mono_class_get_method_from_name (klass, "Invoke", -1);
1681 * mono_runtime_delegate_invoke:
1682 * @delegate: pointer to a delegate object.
1683 * @params: parameters for the delegate.
1684 * @exc: Pointer to the exception result.
1686 * Invokes the delegate method @delegate with the parameters provided.
1688 * You can pass NULL as the exc argument if you don't want to
1689 * catch exceptions, otherwise, *exc will be set to the exception
1690 * thrown, if any. if an exception is thrown, you can't use the
1691 * MonoObject* result from the function.
1694 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
1698 im = mono_get_delegate_invoke (delegate->vtable->klass);
1701 return mono_runtime_invoke (im, delegate, params, exc);
1704 static char **main_args = NULL;
1705 static int num_main_args;
1708 * mono_runtime_get_main_args:
1710 * Returns: a MonoArray with the arguments passed to the main program
1713 mono_runtime_get_main_args (void)
1717 MonoDomain *domain = mono_domain_get ();
1722 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
1724 for (i = 0; i < num_main_args; ++i)
1725 mono_array_set (res, gpointer, i, mono_string_new (domain, main_args [i]));
1731 fire_process_exit_event (void)
1733 MonoClassField *field;
1734 MonoDomain *domain = mono_domain_get ();
1736 MonoObject *delegate, *exc;
1738 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
1741 if (domain != mono_get_root_domain ())
1744 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
1745 if (delegate == NULL)
1750 mono_runtime_delegate_invoke (delegate, pa, &exc);
1754 * mono_runtime_run_main:
1755 * @method: the method to start the application with (usually Main)
1756 * @argc: number of arguments from the command line
1757 * @argv: array of strings from the command line
1758 * @exc: excetption results
1760 * Execute a standard Main() method (argc/argv contains the
1761 * executable name). This method also sets the command line argument value
1762 * needed by System.Environment.
1767 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
1771 MonoArray *args = NULL;
1772 MonoDomain *domain = mono_domain_get ();
1773 gchar *utf8_fullpath;
1776 mono_thread_set_main (mono_thread_current ());
1778 main_args = g_new0 (char*, argc);
1779 num_main_args = argc;
1781 if (!g_path_is_absolute (argv [0])) {
1782 gchar *basename = g_path_get_basename (argv [0]);
1783 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
1787 utf8_fullpath = mono_utf8_from_external (fullpath);
1788 if(utf8_fullpath == NULL) {
1789 /* Printing the arg text will cause glib to
1790 * whinge about "Invalid UTF-8", but at least
1791 * its relevant, and shows the problem text
1794 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
1795 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
1802 utf8_fullpath = mono_utf8_from_external (argv[0]);
1803 if(utf8_fullpath == NULL) {
1804 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
1805 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
1810 main_args [0] = utf8_fullpath;
1812 for (i = 1; i < argc; ++i) {
1815 utf8_arg=mono_utf8_from_external (argv[i]);
1816 if(utf8_arg==NULL) {
1817 /* Ditto the comment about Invalid UTF-8 here */
1818 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
1819 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
1823 main_args [i] = utf8_arg;
1827 if (mono_method_signature (method)->param_count) {
1828 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
1829 for (i = 0; i < argc; ++i) {
1830 /* The encodings should all work, given that
1831 * we've checked all these args for the
1834 gchar *str = mono_utf8_from_external (argv [i]);
1835 MonoString *arg = mono_string_new (domain, str);
1836 mono_array_set (args, gpointer, i, arg);
1840 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
1843 mono_assembly_set_main (method->klass->image->assembly);
1845 result = mono_runtime_exec_main (method, args, exc);
1846 fire_process_exit_event ();
1850 /* Used in mono_unhandled_exception */
1852 create_unhandled_exception_eventargs (MonoObject *exc)
1856 MonoMethod *method = NULL;
1857 MonoBoolean is_terminating = TRUE;
1860 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
1863 mono_class_init (klass);
1865 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
1866 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
1870 args [1] = &is_terminating;
1872 obj = mono_object_new (mono_domain_get (), klass);
1873 mono_runtime_invoke (method, obj, args, NULL);
1879 * mono_unhandled_exception:
1880 * @exc: exception thrown
1882 * This is a VM internal routine.
1884 * We call this function when we detect an unhandled exception
1885 * in the default domain.
1887 * It invokes the * UnhandledException event in AppDomain or prints
1888 * a warning to the console
1891 mono_unhandled_exception (MonoObject *exc)
1893 MonoDomain *domain = mono_domain_get ();
1894 MonoClassField *field;
1895 MonoObject *delegate;
1897 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
1898 "UnhandledException");
1901 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
1902 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
1904 /* set exitcode only in the main thread */
1905 if (mono_thread_current () == main_thread)
1906 mono_environment_exitcode_set (1);
1907 if (domain != mono_get_root_domain () || !delegate) {
1908 mono_print_unhandled_exception (exc);
1910 MonoObject *e = NULL;
1913 pa [0] = domain->domain;
1914 pa [1] = create_unhandled_exception_eventargs (exc);
1915 mono_runtime_delegate_invoke (delegate, pa, &e);
1918 gchar *msg = mono_string_to_utf8 (((MonoException *) e)->message);
1919 g_warning ("exception inside UnhandledException handler: %s\n", msg);
1927 * Launch a new thread to execute a function
1929 * main_func is called back from the thread with main_args as the
1930 * parameter. The callback function is expected to start Main()
1931 * eventually. This function then waits for all managed threads to
1933 * It is not necesseray anymore to execute managed code in a subthread,
1934 * so this function should not be used anymore by default: just
1935 * execute the code and then call mono_thread_manage ().
1938 mono_runtime_exec_managed_code (MonoDomain *domain,
1939 MonoMainThreadFunc main_func,
1942 mono_thread_create (domain, main_func, main_args);
1944 mono_thread_manage ();
1948 * Execute a standard Main() method (args doesn't contain the
1952 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
1962 domain = mono_object_domain (args);
1963 if (!domain->entry_assembly) {
1965 gchar *config_suffix;
1966 MonoAssembly *assembly;
1968 assembly = method->klass->image->assembly;
1969 domain->entry_assembly = assembly;
1970 domain->setup->application_base = mono_string_new (domain, assembly->basedir);
1972 config_suffix = g_strconcat (assembly->aname.name, ".exe.config", NULL);
1973 str = g_build_filename (assembly->basedir, config_suffix, NULL);
1974 g_free (config_suffix);
1975 domain->setup->configuration_file = mono_string_new (domain, str);
1979 /* FIXME: check signature of method */
1980 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
1982 res = mono_runtime_invoke (method, NULL, pa, exc);
1984 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
1988 mono_environment_exitcode_set (rval);
1990 mono_runtime_invoke (method, NULL, pa, exc);
1994 /* If the return type of Main is void, only
1995 * set the exitcode if an exception was thrown
1996 * (we don't want to blow away an
1997 * explicitly-set exit code)
2000 mono_environment_exitcode_set (rval);
2008 * mono_install_runtime_invoke:
2009 * @func: Function to install
2011 * This is a VM internal routine
2014 mono_install_runtime_invoke (MonoInvokeFunc func)
2016 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
2020 * mono_runtime_invoke_array:
2021 * @method: method to invoke
2022 * @obJ: object instance
2023 * @params: arguments to the method
2024 * @exc: exception information.
2026 * Invokes the method represented by @method on the object @obj.
2028 * obj is the 'this' pointer, it should be NULL for static
2029 * methods, a MonoObject* for object instances and a pointer to
2030 * the value type for value types.
2032 * The params array contains the arguments to the method with the
2033 * same convention: MonoObject* pointers for object instances and
2034 * pointers to the value type otherwise. The _invoke_array
2035 * variant takes a C# object[] as the params argument (MonoArray
2036 * *params): in this case the value types are boxed inside the
2037 * respective reference representation.
2039 * From unmanaged code you'll usually use the
2040 * mono_runtime_invoke() variant.
2042 * Note that this function doesn't handle virtual methods for
2043 * you, it will exec the exact method you pass: we still need to
2044 * expose a function to lookup the derived class implementation
2045 * of a virtual method (there are examples of this in the code,
2048 * You can pass NULL as the exc argument if you don't want to
2049 * catch exceptions, otherwise, *exc will be set to the exception
2050 * thrown, if any. if an exception is thrown, you can't use the
2051 * MonoObject* result from the function.
2053 * If the method returns a value type, it is boxed in an object
2057 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
2060 MonoMethodSignature *sig = mono_method_signature (method);
2061 gpointer *pa = NULL;
2064 if (NULL != params) {
2065 pa = alloca (sizeof (gpointer) * mono_array_length (params));
2066 for (i = 0; i < mono_array_length (params); i++) {
2067 if (sig->params [i]->byref) {
2071 switch (sig->params [i]->type) {
2074 case MONO_TYPE_BOOLEAN:
2077 case MONO_TYPE_CHAR:
2086 case MONO_TYPE_VALUETYPE:
2087 /* MS seems to create the objects if a null is passed in */
2088 if (! ((gpointer *)params->vector)[i])
2089 ((gpointer*)params->vector)[i] = mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i]));
2090 pa [i] = (char *)(((gpointer *)params->vector)[i]) + sizeof (MonoObject);
2092 case MONO_TYPE_STRING:
2093 case MONO_TYPE_OBJECT:
2094 case MONO_TYPE_CLASS:
2095 case MONO_TYPE_ARRAY:
2096 case MONO_TYPE_SZARRAY:
2097 if (sig->params [i]->byref)
2098 pa [i] = &(((gpointer *)params->vector)[i]);
2100 pa [i] = (char *)(((gpointer *)params->vector)[i]);
2103 g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
2108 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
2111 obj = mono_object_new (mono_domain_get (), method->klass);
2112 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
2113 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
2115 if (method->klass->valuetype)
2116 o = mono_object_unbox (obj);
2120 else if (method->klass->valuetype)
2121 obj = mono_value_box (mono_domain_get (), method->klass, obj);
2123 mono_runtime_invoke (method, o, pa, exc);
2126 /* obj must be already unboxed if needed */
2127 return mono_runtime_invoke (method, obj, pa, exc);
2132 arith_overflow (void)
2134 mono_raise_exception (mono_get_exception_overflow ());
2138 * mono_object_allocate:
2139 * @size: number of bytes to allocate
2141 * This is a very simplistic routine until we have our GC-aware
2144 * Returns: an allocated object of size @size, or NULL on failure.
2146 static inline void *
2147 mono_object_allocate (size_t size, MonoVTable *vtable)
2150 mono_stats.new_object_count++;
2151 ALLOC_OBJECT (o, vtable, size);
2157 * mono_object_allocate_ptrfree:
2158 * @size: number of bytes to allocate
2160 * Note that the memory allocated is not zeroed.
2161 * Returns: an allocated object of size @size, or NULL on failure.
2163 static inline void *
2164 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
2167 mono_stats.new_object_count++;
2168 ALLOC_PTRFREE (o, vtable, size);
2172 static inline void *
2173 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
2176 ALLOC_TYPED (o, size, vtable);
2177 mono_stats.new_object_count++;
2184 * @klass: the class of the object that we want to create
2186 * Returns: a newly created object whose definition is
2187 * looked up using @klass. This will not invoke any constructors,
2188 * so the consumer of this routine has to invoke any constructors on
2189 * its own to initialize the object.
2192 mono_object_new (MonoDomain *domain, MonoClass *klass)
2194 MONO_ARCH_SAVE_REGS;
2195 return mono_object_new_specific (mono_class_vtable (domain, klass));
2199 * mono_object_new_specific:
2200 * @vtable: the vtable of the object that we want to create
2202 * Returns: A newly created object with class and domain specified
2206 mono_object_new_specific (MonoVTable *vtable)
2210 MONO_ARCH_SAVE_REGS;
2215 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
2218 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
2221 mono_class_init (klass);
2223 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
2225 vtable->domain->create_proxy_for_type_method = im;
2228 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
2230 o = mono_runtime_invoke (im, NULL, pa, NULL);
2231 if (o != NULL) return o;
2234 return mono_object_new_alloc_specific (vtable);
2238 mono_object_new_alloc_specific (MonoVTable *vtable)
2242 if (!vtable->klass->has_references) {
2243 o = mono_object_new_ptrfree (vtable);
2244 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
2245 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
2247 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
2248 o = mono_object_allocate (vtable->klass->instance_size, vtable);
2250 if (vtable->klass->has_finalize)
2251 mono_object_register_finalizer (o);
2253 mono_profiler_allocation (o, vtable->klass);
2258 mono_object_new_fast (MonoVTable *vtable)
2261 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
2266 mono_object_new_ptrfree (MonoVTable *vtable)
2269 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
2270 #if NEED_TO_ZERO_PTRFREE
2271 /* an inline memset is much faster for the common vcase of small objects
2272 * note we assume the allocated size is a multiple of sizeof (void*).
2274 if (vtable->klass->instance_size < 128) {
2276 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
2277 p = (gpointer*)((char*)obj + sizeof (MonoObject));
2283 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
2290 mono_object_new_ptrfree_box (MonoVTable *vtable)
2293 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
2294 /* the object will be boxed right away, no need to memzero it */
2299 * mono_class_get_allocation_ftn:
2301 * @for_box: the object will be used for boxing
2302 * @pass_size_in_words:
2304 * Return the allocation function appropriate for the given class.
2308 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
2310 *pass_size_in_words = FALSE;
2312 if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
2313 return mono_object_new_specific;
2315 if (!vtable->klass->has_references) {
2316 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
2318 return mono_object_new_ptrfree_box;
2319 return mono_object_new_ptrfree;
2322 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
2324 return mono_object_new_fast;
2327 * FIXME: This is actually slower than mono_object_new_fast, because
2328 * of the overhead of parameter passing.
2331 *pass_size_in_words = TRUE;
2332 #ifdef GC_REDIRECT_TO_LOCAL
2333 return GC_local_gcj_fast_malloc;
2335 return GC_gcj_fast_malloc;
2340 return mono_object_new_specific;
2344 * mono_object_new_from_token:
2345 * @image: Context where the type_token is hosted
2346 * @token: a token of the type that we want to create
2348 * Returns: A newly created object whose definition is
2349 * looked up using @token in the @image image
2352 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
2356 class = mono_class_get (image, token);
2358 return mono_object_new (domain, class);
2363 * mono_object_clone:
2364 * @obj: the object to clone
2366 * Returns: A newly created object who is a shallow copy of @obj
2369 mono_object_clone (MonoObject *obj)
2374 size = obj->vtable->klass->instance_size;
2375 o = mono_object_allocate (size, obj->vtable);
2376 /* do not copy the sync state */
2377 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
2379 mono_profiler_allocation (o, obj->vtable->klass);
2381 if (obj->vtable->klass->has_finalize)
2382 mono_object_register_finalizer (o);
2387 * mono_array_full_copy:
2388 * @src: source array to copy
2389 * @dest: destination array
2391 * Copies the content of one array to another with exactly the same type and size.
2394 mono_array_full_copy (MonoArray *src, MonoArray *dest)
2397 MonoClass *klass = src->obj.vtable->klass;
2399 MONO_ARCH_SAVE_REGS;
2401 g_assert (klass == dest->obj.vtable->klass);
2403 size = mono_array_length (src);
2404 g_assert (size == mono_array_length (dest));
2405 size *= mono_array_element_size (klass);
2406 memcpy (&dest->vector, &src->vector, size);
2410 * mono_array_clone_in_domain:
2411 * @domain: the domain in which the array will be cloned into
2412 * @array: the array to clone
2414 * This routine returns a copy of the array that is hosted on the
2415 * specified MonoDomain.
2418 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
2423 MonoClass *klass = array->obj.vtable->klass;
2425 MONO_ARCH_SAVE_REGS;
2427 if (array->bounds == NULL) {
2428 size = mono_array_length (array);
2429 o = mono_array_new_full (domain, klass, &size, NULL);
2431 size *= mono_array_element_size (klass);
2432 memcpy (&o->vector, &array->vector, size);
2436 sizes = alloca (klass->rank * sizeof(guint32) * 2);
2437 size = mono_array_element_size (klass);
2438 for (i = 0; i < klass->rank; ++i) {
2439 sizes [i] = array->bounds [i].length;
2440 size *= array->bounds [i].length;
2441 sizes [i + klass->rank] = array->bounds [i].lower_bound;
2443 o = mono_array_new_full (domain, klass, sizes, sizes + klass->rank);
2444 memcpy (&o->vector, &array->vector, size);
2451 * @array: the array to clone
2453 * Returns: A newly created array who is a shallow copy of @array
2456 mono_array_clone (MonoArray *array)
2458 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
2461 /* helper macros to check for overflow when calculating the size of arrays */
2462 #define MYGUINT32_MAX 4294967295U
2463 #define CHECK_ADD_OVERFLOW_UN(a,b) \
2464 (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
2465 #define CHECK_MUL_OVERFLOW_UN(a,b) \
2466 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
2467 (guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a))
2470 * mono_array_new_full:
2471 * @domain: domain where the object is created
2472 * @array_class: array class
2473 * @lengths: lengths for each dimension in the array
2474 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
2476 * This routine creates a new array objects with the given dimensions,
2477 * lower bounds and type.
2480 mono_array_new_full (MonoDomain *domain, MonoClass *array_class,
2481 guint32 *lengths, guint32 *lower_bounds)
2483 guint32 byte_len, len, bounds_size;
2489 if (!array_class->inited)
2490 mono_class_init (array_class);
2492 byte_len = mono_array_element_size (array_class);
2495 if (array_class->rank == 1 &&
2496 (lower_bounds == NULL || lower_bounds [0] == 0)) {
2502 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
2504 for (i = 0; i < array_class->rank; ++i) {
2505 if ((int) lengths [i] < 0)
2507 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
2508 mono_gc_out_of_memory (MYGUINT32_MAX);
2513 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
2514 mono_gc_out_of_memory (MYGUINT32_MAX);
2516 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
2517 mono_gc_out_of_memory (MYGUINT32_MAX);
2518 byte_len += sizeof (MonoArray);
2521 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
2522 mono_gc_out_of_memory (MYGUINT32_MAX);
2523 byte_len = (byte_len + 3) & ~3;
2524 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
2525 mono_gc_out_of_memory (MYGUINT32_MAX);
2526 byte_len += bounds_size;
2529 * Following three lines almost taken from mono_object_new ():
2530 * they need to be kept in sync.
2532 vtable = mono_class_vtable (domain, array_class);
2533 if (!array_class->has_references) {
2534 o = mono_object_allocate_ptrfree (byte_len, vtable);
2535 #if NEED_TO_ZERO_PTRFREE
2536 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
2538 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
2539 o = mono_object_allocate_spec (byte_len, vtable);
2541 o = mono_object_allocate (byte_len, vtable);
2544 array = (MonoArray*)o;
2545 array->max_length = len;
2548 MonoArrayBounds *bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
2549 array->bounds = bounds;
2550 for (i = 0; i < array_class->rank; ++i) {
2551 bounds [i].length = lengths [i];
2553 bounds [i].lower_bound = lower_bounds [i];
2557 mono_profiler_allocation (o, array_class);
2564 * @domain: domain where the object is created
2565 * @eclass: element class
2566 * @n: number of array elements
2568 * This routine creates a new szarray with @n elements of type @eclass.
2571 mono_array_new (MonoDomain *domain, MonoClass *eclass, guint32 n)
2575 MONO_ARCH_SAVE_REGS;
2577 ac = mono_array_class_get (eclass, 1);
2578 g_assert (ac != NULL);
2580 return mono_array_new_specific (mono_class_vtable (domain, ac), n);
2584 * mono_array_new_specific:
2585 * @vtable: a vtable in the appropriate domain for an initialized class
2586 * @n: number of array elements
2588 * This routine is a fast alternative to mono_array_new() for code which
2589 * can be sure about the domain it operates in.
2592 mono_array_new_specific (MonoVTable *vtable, guint32 n)
2596 guint32 byte_len, elem_size;
2598 MONO_ARCH_SAVE_REGS;
2603 elem_size = mono_array_element_size (vtable->klass);
2604 if (CHECK_MUL_OVERFLOW_UN (n, elem_size))
2605 mono_gc_out_of_memory (MYGUINT32_MAX);
2606 byte_len = n * elem_size;
2607 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
2608 mono_gc_out_of_memory (MYGUINT32_MAX);
2609 byte_len += sizeof (MonoArray);
2610 if (!vtable->klass->has_references) {
2611 o = mono_object_allocate_ptrfree (byte_len, vtable);
2612 #if NEED_TO_ZERO_PTRFREE
2613 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
2615 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
2616 o = mono_object_allocate_spec (byte_len, vtable);
2618 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
2619 o = mono_object_allocate (byte_len, vtable);
2622 ao = (MonoArray *)o;
2625 mono_profiler_allocation (o, vtable->klass);
2631 * mono_string_new_utf16:
2632 * @text: a pointer to an utf16 string
2633 * @len: the length of the string
2635 * Returns: A newly created string object which contains @text.
2638 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
2642 s = mono_string_new_size (domain, len);
2643 g_assert (s != NULL);
2645 memcpy (mono_string_chars (s), text, len * 2);
2651 * mono_string_new_size:
2652 * @text: a pointer to an utf16 string
2653 * @len: the length of the string
2655 * Returns: A newly created string object of @len
2658 mono_string_new_size (MonoDomain *domain, gint32 len)
2662 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
2664 /* overflow ? can't fit it, can't allocate it! */
2666 mono_gc_out_of_memory (-1);
2668 vtable = mono_class_vtable (domain, mono_defaults.string_class);
2670 s = mono_object_allocate_ptrfree (size, vtable);
2673 #if NEED_TO_ZERO_PTRFREE
2676 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
2682 * mono_string_new_len:
2683 * @text: a pointer to an utf8 string
2684 * @length: number of bytes in @text to consider
2686 * Returns: A newly created string object which contains @text.
2689 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
2691 GError *error = NULL;
2692 MonoString *o = NULL;
2694 glong items_written;
2696 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
2699 o = mono_string_new_utf16 (domain, ut, items_written);
2701 g_error_free (error);
2710 * @text: a pointer to an utf8 string
2712 * Returns: A newly created string object which contains @text.
2715 mono_string_new (MonoDomain *domain, const char *text)
2717 GError *error = NULL;
2718 MonoString *o = NULL;
2720 glong items_written;
2725 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
2728 o = mono_string_new_utf16 (domain, ut, items_written);
2730 g_error_free (error);
2738 * mono_string_new_wrapper:
2739 * @text: pointer to utf8 characters.
2741 * Helper function to create a string object from @text in the current domain.
2744 mono_string_new_wrapper (const char *text)
2746 MonoDomain *domain = mono_domain_get ();
2748 MONO_ARCH_SAVE_REGS;
2751 return mono_string_new (domain, text);
2758 * @class: the class of the value
2759 * @value: a pointer to the unboxed data
2761 * Returns: A newly created object which contains @value.
2764 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
2770 g_assert (class->valuetype);
2772 vtable = mono_class_vtable (domain, class);
2773 size = mono_class_instance_size (class);
2774 res = mono_object_allocate (size, vtable);
2775 mono_profiler_allocation (res, class);
2777 size = size - sizeof (MonoObject);
2779 #if NO_UNALIGNED_ACCESS
2780 memcpy ((char *)res + sizeof (MonoObject), value, size);
2784 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
2787 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
2790 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
2793 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
2796 memcpy ((char *)res + sizeof (MonoObject), value, size);
2799 if (class->has_finalize)
2800 mono_object_register_finalizer (res);
2805 * mono_object_get_domain:
2806 * @obj: object to query
2808 * Returns: the MonoDomain where the object is hosted
2811 mono_object_get_domain (MonoObject *obj)
2813 return mono_object_domain (obj);
2817 * mono_object_get_class:
2818 * @obj: object to query
2820 * Returns: the MonOClass of the object.
2823 mono_object_get_class (MonoObject *obj)
2825 return mono_object_class (obj);
2828 * mono_object_get_size:
2829 * @o: object to query
2831 * Returns: the size, in bytes, of @o
2834 mono_object_get_size (MonoObject* o)
2836 MonoClass* klass = mono_object_class (o);
2838 if (klass == mono_defaults.string_class)
2839 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
2840 else if (klass->parent == mono_defaults.array_class)
2841 return sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length ((MonoArray*) o);
2843 return mono_class_instance_size (klass);
2847 * mono_object_unbox:
2848 * @obj: object to unbox
2850 * Returns: a pointer to the start of the valuetype boxed in this
2853 * This method will assert if the object passed is not a valuetype.
2856 mono_object_unbox (MonoObject *obj)
2858 /* add assert for valuetypes? */
2859 g_assert (obj->vtable->klass->valuetype);
2860 return ((char*)obj) + sizeof (MonoObject);
2864 * mono_object_isinst:
2866 * @klass: a pointer to a class
2868 * Returns: @obj if @obj is derived from @klass
2871 mono_object_isinst (MonoObject *obj, MonoClass *klass)
2874 mono_class_init (klass);
2876 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)
2877 return mono_object_isinst_mbyref (obj, klass);
2882 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
2886 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
2895 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2896 if ((klass->interface_id <= vt->max_interface_id) &&
2897 (vt->interface_offsets [klass->interface_id] != 0))
2901 MonoClass *oklass = vt->klass;
2902 if ((oklass == mono_defaults.transparent_proxy_class))
2903 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2905 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
2909 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
2911 MonoDomain *domain = mono_domain_get ();
2913 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
2914 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
2915 MonoMethod *im = NULL;
2918 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
2919 im = mono_object_get_virtual_method (rp, im);
2922 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
2925 res = mono_runtime_invoke (im, rp, pa, NULL);
2927 if (*(MonoBoolean *) mono_object_unbox(res)) {
2928 /* Update the vtable of the remote type, so it can safely cast to this new type */
2929 mono_upgrade_remote_class (domain, obj, klass);
2938 * mono_object_castclass_mbyref:
2940 * @klass: a pointer to a class
2942 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
2945 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
2947 if (!obj) return NULL;
2948 if (mono_object_isinst_mbyref (obj, klass)) return obj;
2950 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
2952 "InvalidCastException"));
2957 MonoDomain *orig_domain;
2963 str_lookup (MonoDomain *domain, gpointer user_data)
2965 LDStrInfo *info = user_data;
2966 if (info->res || domain == info->orig_domain)
2968 mono_domain_lock (domain);
2969 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
2970 mono_domain_unlock (domain);
2974 mono_string_is_interned_lookup (MonoString *str, int insert)
2976 MonoGHashTable *ldstr_table;
2980 domain = ((MonoObject *)str)->vtable->domain;
2981 ldstr_table = domain->ldstr_table;
2982 mono_domain_lock (domain);
2983 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
2984 mono_domain_unlock (domain);
2988 mono_g_hash_table_insert (ldstr_table, str, str);
2989 mono_domain_unlock (domain);
2992 LDStrInfo ldstr_info;
2993 ldstr_info.orig_domain = domain;
2994 ldstr_info.ins = str;
2995 ldstr_info.res = NULL;
2997 mono_domain_foreach (str_lookup, &ldstr_info);
2998 if (ldstr_info.res) {
3000 * the string was already interned in some other domain:
3001 * intern it in the current one as well.
3003 mono_g_hash_table_insert (ldstr_table, str, str);
3004 mono_domain_unlock (domain);
3008 mono_domain_unlock (domain);
3013 * mono_string_is_interned:
3014 * @o: String to probe
3016 * Returns whether the string has been interned.
3019 mono_string_is_interned (MonoString *o)
3021 return mono_string_is_interned_lookup (o, FALSE);
3025 * mono_string_interne:
3026 * @o: String to intern
3028 * Interns the string passed.
3029 * Returns: The interned string.
3032 mono_string_intern (MonoString *str)
3034 return mono_string_is_interned_lookup (str, TRUE);
3039 * @domain: the domain where the string will be used.
3040 * @image: a metadata context
3041 * @idx: index into the user string table.
3043 * Implementation for the ldstr opcode.
3044 * Returns: a loaded string from the @image/@idx combination.
3047 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
3049 MONO_ARCH_SAVE_REGS;
3052 return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx);
3054 return mono_ldstr_metdata_sig (domain, mono_metadata_user_string (image, idx));
3058 * mono_ldstr_metdata_sig
3059 * @domain: the domain for the string
3060 * @sig: the signature of a metadata string
3062 * Returns: a MonoString for a string stored in the metadata
3065 mono_ldstr_metdata_sig (MonoDomain *domain, const char* sig)
3067 const char *str = sig;
3068 MonoString *o, *interned;
3071 len2 = mono_metadata_decode_blob_size (str, &str);
3074 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
3075 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
3078 guint16 *p2 = (guint16*)mono_string_chars (o);
3079 for (i = 0; i < len2; ++i) {
3080 *p2 = GUINT16_FROM_LE (*p2);
3085 mono_domain_lock (domain);
3086 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
3087 mono_domain_unlock (domain);
3088 /* o will get garbage collected */
3092 mono_g_hash_table_insert (domain->ldstr_table, o, o);
3093 mono_domain_unlock (domain);
3099 * mono_string_to_utf8:
3100 * @s: a System.String
3102 * Return the UTF8 representation for @s.
3103 * the resulting buffer nedds to be freed with g_free().
3106 mono_string_to_utf8 (MonoString *s)
3109 GError *error = NULL;
3115 return g_strdup ("");
3117 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, NULL, &error);
3119 g_warning (error->message);
3120 g_error_free (error);
3127 * mono_string_to_utf16:
3130 * Return an null-terminated array of the utf-16 chars
3131 * contained in @s. The result must be freed with g_free().
3132 * This is a temporary helper until our string implementation
3133 * is reworked to always include the null terminating char.
3136 mono_string_to_utf16 (MonoString *s)
3143 as = g_malloc ((s->length * 2) + 2);
3144 as [(s->length * 2)] = '\0';
3145 as [(s->length * 2) + 1] = '\0';
3148 return (gunichar2 *)(as);
3151 memcpy (as, mono_string_chars(s), s->length * 2);
3152 return (gunichar2 *)(as);
3156 * mono_string_from_utf16:
3157 * @data: the UTF16 string (LPWSTR) to convert
3159 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
3161 * Returns: a MonoString.
3164 mono_string_from_utf16 (gunichar2 *data)
3166 MonoDomain *domain = mono_domain_get ();
3172 while (data [len]) len++;
3174 return mono_string_new_utf16 (domain, data, len);
3178 default_ex_handler (MonoException *ex)
3180 MonoObject *o = (MonoObject*)ex;
3181 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
3185 static MonoExceptionFunc ex_handler = default_ex_handler;
3188 * mono_install_handler:
3189 * @func: exception handler
3191 * This is an internal JIT routine used to install the handler for exceptions
3195 mono_install_handler (MonoExceptionFunc func)
3197 ex_handler = func? func: default_ex_handler;
3201 * mono_raise_exception:
3202 * @ex: exception object
3204 * Signal the runtime that the exception @ex has been raised in unmanaged code.
3207 mono_raise_exception (MonoException *ex)
3210 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
3211 * that will cause gcc to omit the function epilog, causing problems when
3212 * the JIT tries to walk the stack, since the return address on the stack
3213 * will point into the next function in the executable, not this one.
3216 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class)
3217 mono_thread_current ()->abort_exc = ex;
3223 * mono_wait_handle_new:
3224 * @domain: Domain where the object will be created
3225 * @handle: Handle for the wait handle
3227 * Returns: A new MonoWaitHandle created in the given domain for the given handle
3230 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
3232 MonoWaitHandle *res;
3234 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
3236 res->handle = handle;
3242 * mono_async_result_new:
3243 * @domain:domain where the object will be created.
3244 * @handle: wait handle.
3245 * @state: state to pass to AsyncResult
3246 * @data: C closure data.
3248 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
3249 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
3253 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data)
3255 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
3256 MonoMethod *method = mono_get_context_capture_method ();
3258 /* we must capture the execution context from the original thread */
3260 res->execution_context = mono_runtime_invoke (method, NULL, NULL, NULL);
3261 /* note: result may be null if the flow is suppressed */
3265 res->async_state = state;
3267 res->handle = (MonoObject *) mono_wait_handle_new (domain, handle);
3269 res->sync_completed = FALSE;
3270 res->completed = FALSE;
3276 mono_message_init (MonoDomain *domain,
3277 MonoMethodMessage *this,
3278 MonoReflectionMethod *method,
3279 MonoArray *out_args)
3281 MonoMethodSignature *sig = mono_method_signature (method->method);
3287 this->method = method;
3289 this->args = mono_array_new (domain, mono_defaults.object_class, sig->param_count);
3290 this->arg_types = mono_array_new (domain, mono_defaults.byte_class, sig->param_count);
3291 this->async_result = NULL;
3292 this->call_type = CallType_Sync;
3294 names = g_new (char *, sig->param_count);
3295 mono_method_get_param_names (method->method, (const char **) names);
3296 this->names = mono_array_new (domain, mono_defaults.string_class, sig->param_count);
3298 for (i = 0; i < sig->param_count; i++) {
3299 name = mono_string_new (domain, names [i]);
3300 mono_array_set (this->names, gpointer, i, name);
3304 for (i = 0, j = 0; i < sig->param_count; i++) {
3306 if (sig->params [i]->byref) {
3308 gpointer arg = mono_array_get (out_args, gpointer, j);
3309 mono_array_set (this->args, gpointer, i, arg);
3313 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
3318 mono_array_set (this->arg_types, guint8, i, arg_type);
3323 * mono_remoting_invoke:
3324 * @real_proxy: pointer to a RealProxy object
3325 * @msg: The MonoMethodMessage to execute
3326 * @exc: used to store exceptions
3327 * @out_args: used to store output arguments
3329 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
3330 * IMessage interface and it is not trivial to extract results from there. So
3331 * we call an helper method PrivateInvoke instead of calling
3332 * RealProxy::Invoke() directly.
3334 * Returns: the result object.
3337 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
3338 MonoObject **exc, MonoArray **out_args)
3340 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
3343 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
3346 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
3348 real_proxy->vtable->domain->private_invoke_method = im;
3351 pa [0] = real_proxy;
3356 return mono_runtime_invoke (im, NULL, pa, exc);
3360 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
3361 MonoObject **exc, MonoArray **out_args)
3365 MonoMethodSignature *sig;
3367 int i, j, outarg_count = 0;
3369 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
3371 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
3372 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3373 target = tp->rp->unwrapped_server;
3375 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
3379 domain = mono_domain_get ();
3380 method = msg->method->method;
3381 sig = mono_method_signature (method);
3383 for (i = 0; i < sig->param_count; i++) {
3384 if (sig->params [i]->byref)
3388 *out_args = mono_array_new (domain, mono_defaults.object_class, outarg_count);
3391 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
3393 for (i = 0, j = 0; i < sig->param_count; i++) {
3394 if (sig->params [i]->byref) {
3396 arg = mono_array_get (msg->args, gpointer, i);
3397 mono_array_set (*out_args, gpointer, j, arg);
3406 * mono_print_unhandled_exception:
3407 * @exc: The exception
3409 * Prints the unhandled exception.
3412 mono_print_unhandled_exception (MonoObject *exc)
3414 char *message = (char *) "";
3418 gboolean free_message = FALSE;
3420 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
3421 klass = exc->vtable->klass;
3423 while (klass && method == NULL) {
3424 method = mono_class_get_method_from_name_flags (klass, "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
3426 klass = klass->parent;
3431 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
3433 message = mono_string_to_utf8 (str);
3434 free_message = TRUE;
3439 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
3440 * exc->vtable->klass->name, message);
3442 g_printerr ("\nUnhandled Exception: %s\n", message);
3449 * mono_delegate_ctor:
3450 * @this: pointer to an uninitialized delegate object
3451 * @target: target object
3452 * @addr: pointer to native code
3454 * This is used to initialize a delegate. We also insert the method_info if
3455 * we find the info with mono_jit_info_table_find().
3458 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
3460 MonoDomain *domain = mono_domain_get ();
3461 MonoDelegate *delegate = (MonoDelegate *)this;
3462 MonoMethod *method = NULL;
3469 class = this->vtable->klass;
3471 if ((ji = mono_jit_info_table_find (domain, addr))) {
3472 method = ji->method;
3473 delegate->method_info = mono_method_get_object (domain, method, NULL);
3476 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
3478 method = mono_marshal_get_remoting_invoke (method);
3479 delegate->method_ptr = mono_compile_method (method);
3480 delegate->target = target;
3481 } else if (mono_method_signature (method)->hasthis && method->klass->valuetype) {
3482 method = mono_marshal_get_unbox_wrapper (method);
3483 delegate->method_ptr = mono_compile_method (method);
3484 delegate->target = target;
3486 delegate->method_ptr = addr;
3487 delegate->target = target;
3492 * mono_method_call_message_new:
3493 * @method: method to encapsulate
3494 * @params: parameters to the method
3495 * @invoke: optional, delegate invoke.
3496 * @cb: async callback delegate.
3497 * @state: state passed to the async callback.
3499 * Translates arguments pointers into a MonoMethodMessage.
3502 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
3503 MonoDelegate **cb, MonoObject **state)
3505 MonoDomain *domain = mono_domain_get ();
3506 MonoMethodSignature *sig = mono_method_signature (method);
3507 MonoMethodMessage *msg;
3510 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3513 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
3514 count = sig->param_count - 2;
3516 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
3517 count = sig->param_count;
3520 for (i = 0; i < count; i++) {
3525 if (sig->params [i]->byref)
3526 vpos = *((gpointer *)params [i]);
3530 type = sig->params [i]->type;
3531 class = mono_class_from_mono_type (sig->params [i]);
3533 if (class->valuetype)
3534 arg = mono_value_box (domain, class, vpos);
3536 arg = *((MonoObject **)vpos);
3538 mono_array_set (msg->args, gpointer, i, arg);
3541 if (cb != NULL && state != NULL) {
3542 *cb = *((MonoDelegate **)params [i]);
3544 *state = *((MonoObject **)params [i]);
3551 * mono_method_return_message_restore:
3553 * Restore results from message based processing back to arguments pointers
3556 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
3558 MonoMethodSignature *sig = mono_method_signature (method);
3559 int i, j, type, size, out_len;
3561 if (out_args == NULL)
3563 out_len = mono_array_length (out_args);
3567 for (i = 0, j = 0; i < sig->param_count; i++) {
3568 MonoType *pt = sig->params [i];
3573 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
3575 arg = mono_array_get (out_args, gpointer, j);
3579 case MONO_TYPE_VOID:
3580 g_assert_not_reached ();
3584 case MONO_TYPE_BOOLEAN:
3587 case MONO_TYPE_CHAR:
3594 case MONO_TYPE_VALUETYPE: {
3595 size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
3596 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
3599 case MONO_TYPE_STRING:
3600 case MONO_TYPE_CLASS:
3601 case MONO_TYPE_ARRAY:
3602 case MONO_TYPE_SZARRAY:
3603 case MONO_TYPE_OBJECT:
3604 **((MonoObject ***)params [i]) = (MonoObject *)arg;
3607 g_assert_not_reached ();
3616 * mono_load_remote_field:
3617 * @this: pointer to an object
3618 * @klass: klass of the object containing @field
3619 * @field: the field to load
3620 * @res: a storage to store the result
3622 * This method is called by the runtime on attempts to load fields of
3623 * transparent proxy objects. @this points to such TP, @klass is the class of
3624 * the object containing @field. @res is a storage location which can be
3625 * used to store the result.
3627 * Returns: an address pointing to the value of field.
3630 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
3632 static MonoMethod *getter = NULL;
3633 MonoDomain *domain = mono_domain_get ();
3634 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3635 MonoClass *field_class;
3636 MonoMethodMessage *msg;
3637 MonoArray *out_args;
3641 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3646 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3647 mono_field_get_value (tp->rp->unwrapped_server, field, res);
3652 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
3656 field_class = mono_class_from_mono_type (field->type);
3658 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3659 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
3660 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
3662 mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3663 mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3665 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3667 if (exc) mono_raise_exception ((MonoException *)exc);
3669 if (mono_array_length (out_args) == 0)
3672 *res = mono_array_get (out_args, MonoObject *, 0);
3674 if (field_class->valuetype) {
3675 return ((char *)*res) + sizeof (MonoObject);
3681 * mono_load_remote_field_new:
3686 * Missing documentation.
3689 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
3691 static MonoMethod *getter = NULL;
3692 MonoDomain *domain = mono_domain_get ();
3693 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3694 MonoClass *field_class;
3695 MonoMethodMessage *msg;
3696 MonoArray *out_args;
3697 MonoObject *exc, *res;
3699 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3701 field_class = mono_class_from_mono_type (field->type);
3703 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3705 if (field_class->valuetype) {
3706 res = mono_object_new (domain, field_class);
3707 val = ((gchar *) res) + sizeof (MonoObject);
3711 mono_field_get_value (tp->rp->unwrapped_server, field, val);
3716 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
3720 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3721 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
3723 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
3725 mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3726 mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3728 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3730 if (exc) mono_raise_exception ((MonoException *)exc);
3732 if (mono_array_length (out_args) == 0)
3735 res = mono_array_get (out_args, MonoObject *, 0);
3741 * mono_store_remote_field:
3742 * @this: pointer to an object
3743 * @klass: klass of the object containing @field
3744 * @field: the field to load
3745 * @val: the value/object to store
3747 * This method is called by the runtime on attempts to store fields of
3748 * transparent proxy objects. @this points to such TP, @klass is the class of
3749 * the object containing @field. @val is the new value to store in @field.
3752 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
3754 static MonoMethod *setter = NULL;
3755 MonoDomain *domain = mono_domain_get ();
3756 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3757 MonoClass *field_class;
3758 MonoMethodMessage *msg;
3759 MonoArray *out_args;
3763 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3765 field_class = mono_class_from_mono_type (field->type);
3767 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3768 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
3769 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
3774 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
3778 if (field_class->valuetype)
3779 arg = mono_value_box (domain, field_class, val);
3781 arg = *((MonoObject **)val);
3784 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3785 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
3787 mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3788 mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3789 mono_array_set (msg->args, gpointer, 2, arg);
3791 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3793 if (exc) mono_raise_exception ((MonoException *)exc);
3797 * mono_store_remote_field_new:
3803 * Missing documentation
3806 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
3808 static MonoMethod *setter = NULL;
3809 MonoDomain *domain = mono_domain_get ();
3810 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3811 MonoClass *field_class;
3812 MonoMethodMessage *msg;
3813 MonoArray *out_args;
3816 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3818 field_class = mono_class_from_mono_type (field->type);
3820 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3821 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
3822 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
3827 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
3831 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3832 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
3834 mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3835 mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3836 mono_array_set (msg->args, gpointer, 2, arg);
3838 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3840 if (exc) mono_raise_exception ((MonoException *)exc);