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, (gpointer)(gsize)(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");
342 default_delegate_trampoline (MonoMethod *method, gpointer addr)
344 g_assert_not_reached ();
348 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
349 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
350 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
353 mono_install_trampoline (MonoTrampoline func)
355 arch_create_jit_trampoline = func? func: default_trampoline;
359 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
361 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
365 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
367 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
370 static MonoCompileFunc default_mono_compile_method = NULL;
373 * mono_install_compile_method:
374 * @func: function to install
376 * This is a VM internal routine
379 mono_install_compile_method (MonoCompileFunc func)
381 default_mono_compile_method = func;
385 * mono_compile_method:
386 * @method: The method to compile.
388 * This JIT-compiles the method, and returns the pointer to the native code
392 mono_compile_method (MonoMethod *method)
394 if (!default_mono_compile_method) {
395 g_error ("compile method called on uninitialized runtime");
398 return default_mono_compile_method (method);
401 static MonoFreeMethodFunc default_mono_free_method = NULL;
404 * mono_install_free_method:
405 * @func: pointer to the MonoFreeMethodFunc used to release a method
407 * This is an internal VM routine, it is used for the engines to
408 * register a handler to release the resources associated with a method.
410 * Methods are freed when no more references to the delegate that holds
414 mono_install_free_method (MonoFreeMethodFunc func)
416 default_mono_free_method = func;
420 * mono_runtime_free_method:
421 * @domain; domain where the method is hosted
422 * @method: method to release
424 * This routine is invoked to free the resources associated with
425 * a method that has been JIT compiled. This is used to discard
426 * methods that were used only temporarily (for example, used in marshalling)
430 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
432 if (default_mono_free_method != NULL)
433 default_mono_free_method (domain, method);
435 mono_free_method (method);
438 static MonoInitVTableFunc init_vtable_func = NULL;
441 * mono_install_init_vtable:
442 * @func: pointer to the function to be installed
444 * Register a function which will be called by the runtime to initialize the
445 * method pointers inside a vtable. The JIT can use this function to load the
446 * vtable from the AOT file for example.
449 mono_install_init_vtable (MonoInitVTableFunc func)
451 init_vtable_func = func;
455 * The vtables in the root appdomain are assumed to be reachable by other
456 * roots, and we don't use typed allocation in the other domains.
459 /* The sync block is no longer a GC pointer */
460 #define GC_HEADER_BITMAP (0)
462 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
465 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set)
467 MonoClassField *field;
470 int max_size = class->instance_size / sizeof (gpointer);
471 if (max_size > size) {
472 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
475 for (p = class; p != NULL; p = p->parent) {
476 gpointer iter = NULL;
477 while ((field = mono_class_get_fields (p, &iter))) {
480 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
482 /* FIXME: should not happen, flag as type load error */
483 if (field->type->byref)
486 pos = field->offset / sizeof (gpointer);
489 type = mono_type_get_underlying_type (field->type);
490 switch (type->type) {
491 /* FIXME: _I and _U and _PTR should be removed eventually */
495 case MONO_TYPE_FNPTR:
496 case MONO_TYPE_STRING:
497 case MONO_TYPE_SZARRAY:
498 case MONO_TYPE_CLASS:
499 case MONO_TYPE_OBJECT:
500 case MONO_TYPE_ARRAY:
501 g_assert ((field->offset % sizeof(gpointer)) == 0);
503 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
504 *max_set = MAX (*max_set, pos);
506 case MONO_TYPE_VALUETYPE: {
507 MonoClass *fclass = field->type->data.klass;
508 if (fclass->has_references) {
509 /* remove the object header */
510 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set);
524 case MONO_TYPE_BOOLEAN:
528 g_assert_not_reached ();
537 mono_class_compute_gc_descriptor (MonoClass *class)
541 gsize default_bitmap [4] = {0};
542 static gboolean gcj_inited = FALSE;
547 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
548 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
549 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
551 #ifdef HAVE_GC_GCJ_MALLOC
553 GC_init_gcj_malloc (5, NULL);
555 #ifdef GC_REDIRECT_TO_LOCAL
556 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
557 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
559 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
560 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
563 mono_loader_unlock ();
567 mono_class_init (class);
569 if (class->gc_descr_inited)
572 class->gc_descr_inited = TRUE;
573 class->gc_descr = GC_NO_DESCRIPTOR;
575 if (class->generic_class || class->generic_container)
579 bitmap = default_bitmap;
580 if (class == mono_defaults.string_class) {
581 class->gc_descr = (gpointer)MAKE_STRING_DESCRIPTOR (bitmap, 2);
582 } else if (class->rank) {
583 mono_class_compute_gc_descriptor (class->element_class);
585 /* libgc has no usable support for arrays... */
586 if (!class->element_class->valuetype) {
588 class->gc_descr = mono_gc_make_descr_for_array (TRUE, &abm, 1, sizeof (gpointer));
589 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
590 class->name_space, class->name);*/
592 /* remove the object header */
593 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (sizeof (MonoObject) / sizeof (gpointer)), &max_set);
594 class->gc_descr = mono_gc_make_descr_for_array (TRUE, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
595 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
596 class->name_space, class->name);*/
597 if (bitmap != default_bitmap)
602 /*static int count = 0;
605 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set);
607 /* It seems there are issues when the bitmap doesn't fit: play it safe */
609 /*g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);*/
610 if (bitmap != default_bitmap)
615 class->gc_descr = (gpointer)MAKE_DESCRIPTOR (bitmap, max_set + 1, class->instance_size);
616 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
617 if (bitmap != default_bitmap)
623 * field_is_special_static:
624 * @fklass: The MonoClass to look up.
625 * @field: The MonoClassField describing the field.
627 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
628 * SPECIAL_STATIC_NONE otherwise.
631 field_is_special_static (MonoClass *fklass, MonoClassField *field)
633 MonoCustomAttrInfo *ainfo;
635 ainfo = mono_custom_attrs_from_field (fklass, field);
638 for (i = 0; i < ainfo->num_attrs; ++i) {
639 MonoClass *klass = ainfo->attrs [i].ctor->klass;
640 if (klass->image == mono_defaults.corlib) {
641 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
642 mono_custom_attrs_free (ainfo);
643 return SPECIAL_STATIC_THREAD;
645 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
646 mono_custom_attrs_free (ainfo);
647 return SPECIAL_STATIC_CONTEXT;
651 mono_custom_attrs_free (ainfo);
652 return SPECIAL_STATIC_NONE;
655 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class);
659 * @domain: the application domain
660 * @class: the class to initialize
662 * VTables are domain specific because we create domain specific code, and
663 * they contain the domain specific static class data.
666 mono_class_vtable (MonoDomain *domain, MonoClass *class)
668 MonoClassRuntimeInfo *runtime_info;
672 /* this check can be inlined in jitted code, too */
673 runtime_info = class->runtime_info;
674 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
675 return runtime_info->domain_vtables [domain->domain_id];
676 return mono_class_create_runtime_vtable (domain, class);
680 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
683 MonoClassRuntimeInfo *runtime_info, *old_info;
684 MonoClassField *field;
687 gboolean inited = FALSE;
690 guint32 constant_cols [MONO_CONSTANT_SIZE];
693 mono_domain_lock (domain);
694 runtime_info = class->runtime_info;
695 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
696 mono_domain_unlock (domain);
697 return runtime_info->domain_vtables [domain->domain_id];
700 mono_class_init (class);
702 mono_stats.used_class_count++;
703 mono_stats.class_vtable_size += sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
705 vtable_size = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
707 vt = mono_mempool_alloc0 (domain->mp, vtable_size);
710 vt->rank = class->rank;
713 mono_class_compute_gc_descriptor (class);
715 * We can't use typed allocation in the non-root domains, since the
716 * collector needs the GC descriptor stored in the vtable even after
717 * the mempool containing the vtable is destroyed when the domain is
718 * unloaded. An alternative might be to allocate vtables in the GC
719 * heap, but this does not seem to work (it leads to crashes inside
720 * libgc). If that approach is tried, two gc descriptors need to be
721 * allocated for each class: one for the root domain, and one for all
722 * other domains. The second descriptor should contain a bit for the
723 * vtable field in MonoObject, since we can no longer assume the
724 * vtable is reachable by other roots after the appdomain is unloaded.
727 if (domain != mono_get_root_domain ())
728 vt->gc_descr = GC_NO_DESCRIPTOR;
731 vt->gc_descr = class->gc_descr;
733 if (class->class_size) {
734 if (class->has_static_refs)
735 vt->data = mono_gc_alloc_fixed (class->class_size, NULL);
737 vt->data = mono_mempool_alloc0 (domain->mp, class->class_size);
738 mono_g_hash_table_insert (domain->static_data_hash, class, vt->data);
739 mono_stats.class_static_data_size += class->class_size;
744 while ((field = mono_class_get_fields (class, &iter))) {
745 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
747 if (mono_field_is_deleted (field))
749 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
750 gint32 special_static = field_is_special_static (class, field);
751 if (special_static != SPECIAL_STATIC_NONE) {
752 guint32 size, offset;
754 size = mono_type_size (field->type, &align);
755 offset = mono_alloc_special_static_data (special_static, size, align);
756 if (!domain->special_static_fields)
757 domain->special_static_fields = g_hash_table_new (NULL, NULL);
758 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
762 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
763 MonoClass *fklass = mono_class_from_mono_type (field->type);
764 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
765 t = (char*)vt->data + field->offset;
766 if (fklass->valuetype) {
767 memcpy (t, field->data, mono_class_value_size (fklass, NULL));
769 /* it's a pointer type: add check */
770 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
771 *t = *(char *)field->data;
775 if (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT))
778 /* later do this only on demand if needed */
780 cindex = mono_metadata_get_constant_index (class->image, mono_class_get_field_token (field), cindex + 1);
782 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA));
784 mono_metadata_decode_row (&class->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
785 field->def_type = constant_cols [MONO_CONSTANT_TYPE];
786 field->data = (gpointer)mono_metadata_blob_heap (class->image, constant_cols [MONO_CONSTANT_VALUE]);
791 vt->max_interface_id = class->max_interface_id;
793 vt->interface_offsets = mono_mempool_alloc0 (domain->mp,
794 sizeof (gpointer) * (class->max_interface_id + 1));
796 /* initialize interface offsets */
797 for (i = 0; i <= class->max_interface_id; ++i) {
798 int slot = class->interface_offsets [i];
800 vt->interface_offsets [i] = &(vt->vtable [slot]);
804 * arch_create_jit_trampoline () can recursively call this function again
805 * because it compiles icall methods right away.
807 /* FIXME: class_vtable_hash is basically obsolete now: remove as soon
808 * as we change the code in appdomain.c to invalidate vtables by
809 * looking at the possible MonoClasses created for the domain.
810 * Or we can reuse static_data_hash, by using vtable as a key
811 * and always inserting into that hash.
813 g_hash_table_insert (domain->class_vtable_hash, class, vt);
814 /* class->runtime_info is protected by the loader lock, both when
815 * it it enlarged and when it is stored info.
818 old_info = class->runtime_info;
819 if (old_info && old_info->max_domain >= domain->domain_id) {
820 /* someone already created a large enough runtime info */
821 old_info->domain_vtables [domain->domain_id] = vt;
823 int new_size = domain->domain_id;
825 new_size = MAX (new_size, old_info->max_domain);
827 /* make the new size a power of two */
832 /* this is a bounded memory retention issue: may want to
833 * handle it differently when we'll have a rcu-like system.
835 runtime_info = mono_mempool_alloc0 (class->image->mempool, sizeof (MonoClassRuntimeInfo) + new_size * sizeof (gpointer));
836 runtime_info->max_domain = new_size - 1;
837 /* copy the stuff from the older info */
839 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
841 runtime_info->domain_vtables [domain->domain_id] = vt;
842 /* keep this last (add membarrier) */
843 class->runtime_info = runtime_info;
845 mono_loader_unlock ();
847 /* initialize vtable */
848 if (init_vtable_func)
849 inited = init_vtable_func (vt);
852 mono_class_setup_vtable (class);
854 for (i = 0; i < class->vtable_size; ++i) {
857 if ((cm = class->vtable [i])) {
858 if (mono_method_signature (cm)->generic_param_count)
861 vt->vtable [i] = arch_create_jit_trampoline (cm);
866 mono_domain_unlock (domain);
868 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
869 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND)) {
870 MonoException *exc = mono_class_get_exception_for_failure (class);
872 mono_raise_exception (exc);
875 /* make sure the the parent is initialized */
877 mono_class_vtable (domain, class->parent);
879 vt->type = mono_type_get_object (domain, &class->byval_arg);
880 if (class->contextbound)
889 * mono_class_proxy_vtable:
890 * @domain: the application domain
891 * @remove_class: the remote class
893 * Creates a vtable for transparent proxies. It is basically
894 * a copy of the real vtable of the class wrapped in @remote_class,
895 * but all function pointers invoke the remoting functions, and
896 * vtable->klass points to the transparent proxy class, and not to @class.
899 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
901 MonoVTable *vt, *pvt;
902 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
904 GSList *extra_interfaces = NULL;
905 MonoClass *class = remote_class->proxy_class;
907 vt = mono_class_vtable (domain, class);
908 max_interface_id = vt->max_interface_id;
910 /* Calculate vtable space for extra interfaces */
911 for (j = 0; j < remote_class->interface_count; j++) {
912 MonoClass* iclass = remote_class->interfaces[j];
916 if (iclass->interface_id <= class->max_interface_id && class->interface_offsets[iclass->interface_id] != -1)
917 continue; /* interface implemented by the class */
918 if (g_slist_find (extra_interfaces, iclass))
921 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
923 method_count = mono_class_num_methods (iclass);
925 ifaces = mono_class_get_implemented_interfaces (iclass);
927 for (i = 0; i < ifaces->len; ++i) {
928 MonoClass *ic = g_ptr_array_index (ifaces, i);
929 if (ic->interface_id <= class->max_interface_id && class->interface_offsets[ic->interface_id] != -1)
930 continue; /* interface implemented by the class */
931 if (g_slist_find (extra_interfaces, ic))
933 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
934 method_count += mono_class_num_methods (ic);
936 g_ptr_array_free (ifaces, TRUE);
939 extra_interface_vtsize += method_count * sizeof (gpointer);
940 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
943 vtsize = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
945 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
947 pvt = mono_mempool_alloc (domain->mp, vtsize + extra_interface_vtsize);
948 memcpy (pvt, vt, vtsize);
950 pvt->klass = mono_defaults.transparent_proxy_class;
951 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
952 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
954 /* initialize vtable */
955 mono_class_setup_vtable (class);
956 for (i = 0; i < class->vtable_size; ++i) {
959 if ((cm = class->vtable [i]))
960 pvt->vtable [i] = arch_create_remoting_trampoline (cm, target_type);
963 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
964 /* create trampolines for abstract methods */
965 for (k = class; k; k = k->parent) {
967 gpointer iter = NULL;
968 while ((m = mono_class_get_methods (k, &iter)))
969 if (!pvt->vtable [m->slot])
970 pvt->vtable [m->slot] = arch_create_remoting_trampoline (m, target_type);
974 pvt->max_interface_id = max_interface_id;
975 pvt->interface_offsets = mono_mempool_alloc0 (domain->mp,
976 sizeof (gpointer) * (max_interface_id + 1));
978 /* initialize interface offsets */
979 for (i = 0; i <= class->max_interface_id; ++i) {
980 int slot = class->interface_offsets [i];
982 pvt->interface_offsets [i] = &(pvt->vtable [slot]);
985 if (extra_interfaces) {
986 int slot = class->vtable_size;
992 /* Create trampolines for the methods of the interfaces */
993 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
994 interf = list_item->data;
995 pvt->interface_offsets [interf->interface_id] = &pvt->vtable [slot];
999 while ((cm = mono_class_get_methods (interf, &iter)))
1000 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (cm, target_type);
1002 slot += mono_class_num_methods (interf);
1004 g_slist_free (extra_interfaces);
1011 * create_remote_class_key:
1012 * Creates an array of pointers that can be used as a hash key for a remote class.
1013 * The first element of the array is the number of pointers.
1016 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
1021 if (remote_class == NULL) {
1022 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1023 key = g_malloc (sizeof(gpointer) * 3);
1024 key [0] = GINT_TO_POINTER (2);
1025 key [1] = mono_defaults.marshalbyrefobject_class;
1026 key [2] = extra_class;
1028 key = g_malloc (sizeof(gpointer) * 2);
1029 key [0] = GINT_TO_POINTER (1);
1030 key [1] = extra_class;
1033 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
1034 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
1035 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
1036 key [1] = remote_class->proxy_class;
1038 // Keep the list of interfaces sorted
1039 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
1040 if (extra_class && remote_class->interfaces [i] > extra_class) {
1041 key [j++] = extra_class;
1044 key [j] = remote_class->interfaces [i];
1047 key [j] = extra_class;
1049 // Replace the old class. The interface list is the same
1050 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
1051 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
1052 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
1053 for (i = 0; i < remote_class->interface_count; i++)
1054 key [2 + i] = remote_class->interfaces [i];
1062 * mono_remote_class:
1063 * @domain: the application domain
1064 * @class_name: name of the remote class
1066 * Creates and initializes a MonoRemoteClass object for a remote type.
1070 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
1072 MonoRemoteClass *rc;
1075 key = create_remote_class_key (NULL, proxy_class);
1077 mono_domain_lock (domain);
1078 rc = mono_g_hash_table_lookup (domain->proxy_vtable_hash, key);
1082 mono_domain_unlock (domain);
1086 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1087 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*));
1088 rc->interface_count = 1;
1089 rc->interfaces [0] = proxy_class;
1090 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
1092 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass));
1093 rc->interface_count = 0;
1094 rc->proxy_class = proxy_class;
1097 rc->default_vtable = NULL;
1098 rc->xdomain_vtable = NULL;
1099 rc->proxy_class_name = mono_string_to_utf8 (class_name);
1101 mono_g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
1103 mono_domain_unlock (domain);
1108 * clone_remote_class:
1109 * Creates a copy of the remote_class, adding the provided class or interface
1111 static MonoRemoteClass*
1112 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
1114 MonoRemoteClass *rc;
1117 key = create_remote_class_key (remote_class, extra_class);
1118 rc = mono_g_hash_table_lookup (domain->proxy_vtable_hash, key);
1124 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1126 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * (remote_class->interface_count + 1));
1127 rc->proxy_class = remote_class->proxy_class;
1128 rc->interface_count = remote_class->interface_count + 1;
1130 // Keep the list of interfaces sorted, since the hash key of
1131 // the remote class depends on this
1132 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
1133 if (remote_class->interfaces [i] > extra_class && i == j)
1134 rc->interfaces [j++] = extra_class;
1135 rc->interfaces [j] = remote_class->interfaces [i];
1138 rc->interfaces [j] = extra_class;
1140 // Replace the old class. The interface array is the same
1141 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * remote_class->interface_count);
1142 rc->proxy_class = extra_class;
1143 rc->interface_count = remote_class->interface_count;
1144 if (rc->interface_count > 0)
1145 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
1148 rc->default_vtable = NULL;
1149 rc->xdomain_vtable = NULL;
1150 rc->proxy_class_name = remote_class->proxy_class_name;
1152 mono_g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
1158 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
1160 mono_domain_lock (domain);
1161 if (rp->target_domain_id != -1) {
1162 if (remote_class->xdomain_vtable == NULL)
1163 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
1164 mono_domain_unlock (domain);
1165 return remote_class->xdomain_vtable;
1167 if (remote_class->default_vtable == NULL)
1168 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
1170 mono_domain_unlock (domain);
1171 return remote_class->default_vtable;
1175 * mono_upgrade_remote_class:
1176 * @domain: the application domain
1177 * @tproxy: the proxy whose remote class has to be upgraded.
1178 * @klass: class to which the remote class can be casted.
1180 * Updates the vtable of the remote class by adding the necessary method slots
1181 * and interface offsets so it can be safely casted to klass. klass can be a
1182 * class or an interface.
1185 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
1187 MonoTransparentProxy *tproxy;
1188 MonoRemoteClass *remote_class;
1189 gboolean redo_vtable;
1191 mono_domain_lock (domain);
1193 tproxy = (MonoTransparentProxy*) proxy_object;
1194 remote_class = tproxy->remote_class;
1196 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1199 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
1200 if (remote_class->interfaces [i] == klass)
1201 redo_vtable = FALSE;
1204 redo_vtable = (remote_class->proxy_class != klass);
1208 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
1209 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
1212 mono_domain_unlock (domain);
1217 * mono_object_get_virtual_method:
1218 * @obj: object to operate on.
1221 * Retrieves the MonoMethod that would be called on obj if obj is passed as
1222 * the instance of a callvirt of method.
1225 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
1228 MonoMethod **vtable;
1230 MonoMethod *res = NULL;
1232 klass = mono_object_class (obj);
1233 if (klass == mono_defaults.transparent_proxy_class) {
1234 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
1240 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
1243 mono_class_setup_vtable (klass);
1244 vtable = klass->vtable;
1246 /* check method->slot is a valid index: perform isinstance? */
1247 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1249 res = vtable [klass->interface_offsets [method->klass->interface_id] + method->slot];
1251 if (method->slot != -1)
1252 res = vtable [method->slot];
1256 if (!res) res = method; /* It may be an interface or abstract class method */
1257 res = mono_marshal_get_remoting_invoke (res);
1266 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
1268 g_error ("runtime invoke called on uninitialized runtime");
1272 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
1275 * mono_runtime_invoke:
1276 * @method: method to invoke
1277 * @obJ: object instance
1278 * @params: arguments to the method
1279 * @exc: exception information.
1281 * Invokes the method represented by @method on the object @obj.
1283 * obj is the 'this' pointer, it should be NULL for static
1284 * methods, a MonoObject* for object instances and a pointer to
1285 * the value type for value types.
1287 * The params array contains the arguments to the method with the
1288 * same convention: MonoObject* pointers for object instances and
1289 * pointers to the value type otherwise.
1291 * From unmanaged code you'll usually use the
1292 * mono_runtime_invoke() variant.
1294 * Note that this function doesn't handle virtual methods for
1295 * you, it will exec the exact method you pass: we still need to
1296 * expose a function to lookup the derived class implementation
1297 * of a virtual method (there are examples of this in the code,
1300 * You can pass NULL as the exc argument if you don't want to
1301 * catch exceptions, otherwise, *exc will be set to the exception
1302 * thrown, if any. if an exception is thrown, you can't use the
1303 * MonoObject* result from the function.
1305 * If the method returns a value type, it is boxed in an object
1309 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
1311 return default_mono_runtime_invoke (method, obj, params, exc);
1315 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
1319 gpointer *p = (gpointer*)dest;
1326 case MONO_TYPE_BOOLEAN:
1328 case MONO_TYPE_U1: {
1329 guint8 *p = (guint8*)dest;
1330 *p = value ? *(guint8*)value : 0;
1335 case MONO_TYPE_CHAR: {
1336 guint16 *p = (guint16*)dest;
1337 *p = value ? *(guint16*)value : 0;
1340 #if SIZEOF_VOID_P == 4
1345 case MONO_TYPE_U4: {
1346 gint32 *p = (gint32*)dest;
1347 *p = value ? *(gint32*)value : 0;
1350 #if SIZEOF_VOID_P == 8
1355 case MONO_TYPE_U8: {
1356 gint64 *p = (gint64*)dest;
1357 *p = value ? *(gint64*)value : 0;
1360 case MONO_TYPE_R4: {
1361 float *p = (float*)dest;
1362 *p = value ? *(float*)value : 0;
1365 case MONO_TYPE_R8: {
1366 double *p = (double*)dest;
1367 *p = value ? *(double*)value : 0;
1370 case MONO_TYPE_STRING:
1371 case MONO_TYPE_SZARRAY:
1372 case MONO_TYPE_CLASS:
1373 case MONO_TYPE_OBJECT:
1374 case MONO_TYPE_ARRAY:
1375 case MONO_TYPE_PTR: {
1376 gpointer *p = (gpointer*)dest;
1377 *p = deref_pointer? *(gpointer*)value: value;
1380 case MONO_TYPE_VALUETYPE:
1381 if (type->data.klass->enumtype) {
1382 t = type->data.klass->enum_basetype->type;
1386 size = mono_class_value_size (type->data.klass, NULL);
1388 memset (dest, 0, size);
1390 memcpy (dest, value, size);
1393 case MONO_TYPE_GENERICINST:
1394 t = type->data.generic_class->container_class->byval_arg.type;
1397 g_warning ("got type %x", type->type);
1398 g_assert_not_reached ();
1403 * mono_field_set_value:
1404 * @obj: Instance object
1405 * @field: MonoClassField describing the field to set
1406 * @value: The value to be set
1408 * Sets the value of the field described by @field in the object instance @obj
1409 * to the value passed in @value.
1411 * The value must be on the native format of the field type.
1414 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
1418 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
1420 dest = (char*)obj + field->offset;
1421 set_value (field->type, dest, value, FALSE);
1425 * mono_field_static_set_value:
1426 * @field: MonoClassField describing the field to set
1427 * @value: The value to be set
1429 * Sets the value of the static field described by @field
1430 * to the value passed in @value.
1432 * The value must be on the native format of the field type.
1435 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
1439 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
1440 /* you cant set a constant! */
1441 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
1443 dest = (char*)vt->data + field->offset;
1444 set_value (field->type, dest, value, FALSE);
1448 * mono_field_get_value:
1449 * @obj: Object instance
1450 * @field: MonoClassField describing the field to fetch information from
1451 * @value: pointer to the location where the value will be stored
1453 * Use this routine to get the value of the field @field in the object
1456 * The pointer provided by value must be of the field type, for reference
1457 * types this is a MonoObject*, for value types its the actual pointer to
1462 * mono_field_get_value (obj, int_field, &i);
1465 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
1469 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
1471 src = (char*)obj + field->offset;
1472 set_value (field->type, value, src, TRUE);
1476 * mono_field_get_value_object:
1477 * @domain: domain where the object will be created (if boxing)
1478 * @field: MonoClassField describing the field to fetch information from
1479 * @obj: The object instance for the field.
1481 * Returns: a new MonoObject with the value from the given field. If the
1482 * field represents a value type, the value is boxed.
1486 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
1490 MonoVTable *vtable = NULL;
1492 gboolean is_static = FALSE;
1493 gboolean is_ref = FALSE;
1495 switch (field->type->type) {
1496 case MONO_TYPE_STRING:
1497 case MONO_TYPE_OBJECT:
1498 case MONO_TYPE_CLASS:
1499 case MONO_TYPE_ARRAY:
1500 case MONO_TYPE_SZARRAY:
1505 case MONO_TYPE_BOOLEAN:
1508 case MONO_TYPE_CHAR:
1517 case MONO_TYPE_VALUETYPE:
1518 is_ref = field->type->byref;
1521 g_error ("type 0x%x not handled in "
1522 "mono_field_get_value_object", field->type->type);
1526 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
1528 vtable = mono_class_vtable (domain, field->parent);
1529 if (!vtable->initialized)
1530 mono_runtime_class_init (vtable);
1535 mono_field_static_get_value (vtable, field, &o);
1537 mono_field_get_value (obj, field, &o);
1542 /* boxed value type */
1543 klass = mono_class_from_mono_type (field->type);
1544 o = mono_object_new (domain, klass);
1545 v = ((gchar *) o) + sizeof (MonoObject);
1547 mono_field_static_get_value (vtable, field, v);
1549 mono_field_get_value (obj, field, v);
1556 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
1559 const char *p = blob;
1560 mono_metadata_decode_blob_size (p, &p);
1563 case MONO_TYPE_BOOLEAN:
1566 *(guint8 *) value = *p;
1568 case MONO_TYPE_CHAR:
1571 *(guint16*) value = read16 (p);
1575 *(guint32*) value = read32 (p);
1579 *(guint64*) value = read64 (p);
1582 readr4 (p, (float*) value);
1585 readr8 (p, (double*) value);
1587 case MONO_TYPE_STRING:
1588 *(gpointer*) value = mono_ldstr_metdata_sig (domain, blob);
1590 case MONO_TYPE_CLASS:
1591 *(gpointer*) value = NULL;
1595 g_warning ("type 0x%02x should not be in constant table", type);
1601 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
1603 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT);
1604 mono_get_constant_value_from_blob (domain, field->def_type, field->data, value);
1608 * mono_field_static_get_value:
1609 * @vt: vtable to the object
1610 * @field: MonoClassField describing the field to fetch information from
1611 * @value: where the value is returned
1613 * Use this routine to get the value of the static field @field value.
1615 * The pointer provided by value must be of the field type, for reference
1616 * types this is a MonoObject*, for value types its the actual pointer to
1621 * mono_field_static_get_value (vt, int_field, &i);
1624 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
1628 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
1630 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
1631 get_default_field_value (vt->domain, field, value);
1635 src = (char*)vt->data + field->offset;
1636 set_value (field->type, value, src, TRUE);
1640 * mono_property_set_value:
1641 * @prop: MonoProperty to set
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 set 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.
1655 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
1657 default_mono_runtime_invoke (prop->set, obj, params, exc);
1661 * mono_property_get_value:
1662 * @prop: MonoProperty to fetch
1663 * @obj: instance object on which to act
1664 * @params: parameters to pass to the propery
1665 * @exc: optional exception
1667 * Invokes the property's get method with the given arguments on the
1668 * object instance obj (or NULL for static properties).
1670 * You can pass NULL as the exc argument if you don't want to
1671 * catch exceptions, otherwise, *exc will be set to the exception
1672 * thrown, if any. if an exception is thrown, you can't use the
1673 * MonoObject* result from the function.
1675 * Returns: the value from invoking the get method on the property.
1678 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
1680 return default_mono_runtime_invoke (prop->get, obj, params, exc);
1685 * mono_get_delegate_invoke:
1686 * @klass: The delegate class
1688 * Returns: the MonoMethod for the "Invoke" method in the delegate klass
1691 mono_get_delegate_invoke (MonoClass *klass)
1695 im = mono_class_get_method_from_name (klass, "Invoke", -1);
1702 * mono_runtime_delegate_invoke:
1703 * @delegate: pointer to a delegate object.
1704 * @params: parameters for the delegate.
1705 * @exc: Pointer to the exception result.
1707 * Invokes the delegate method @delegate with the parameters provided.
1709 * You can pass NULL as the exc argument if you don't want to
1710 * catch exceptions, otherwise, *exc will be set to the exception
1711 * thrown, if any. if an exception is thrown, you can't use the
1712 * MonoObject* result from the function.
1715 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
1719 im = mono_get_delegate_invoke (delegate->vtable->klass);
1722 return mono_runtime_invoke (im, delegate, params, exc);
1725 static char **main_args = NULL;
1726 static int num_main_args;
1729 * mono_runtime_get_main_args:
1731 * Returns: a MonoArray with the arguments passed to the main program
1734 mono_runtime_get_main_args (void)
1738 MonoDomain *domain = mono_domain_get ();
1743 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
1745 for (i = 0; i < num_main_args; ++i)
1746 mono_array_set (res, gpointer, i, mono_string_new (domain, main_args [i]));
1752 fire_process_exit_event (void)
1754 MonoClassField *field;
1755 MonoDomain *domain = mono_domain_get ();
1757 MonoObject *delegate, *exc;
1759 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
1762 if (domain != mono_get_root_domain ())
1765 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
1766 if (delegate == NULL)
1771 mono_runtime_delegate_invoke (delegate, pa, &exc);
1775 * mono_runtime_run_main:
1776 * @method: the method to start the application with (usually Main)
1777 * @argc: number of arguments from the command line
1778 * @argv: array of strings from the command line
1779 * @exc: excetption results
1781 * Execute a standard Main() method (argc/argv contains the
1782 * executable name). This method also sets the command line argument value
1783 * needed by System.Environment.
1788 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
1792 MonoArray *args = NULL;
1793 MonoDomain *domain = mono_domain_get ();
1794 gchar *utf8_fullpath;
1797 mono_thread_set_main (mono_thread_current ());
1799 main_args = g_new0 (char*, argc);
1800 num_main_args = argc;
1802 if (!g_path_is_absolute (argv [0])) {
1803 gchar *basename = g_path_get_basename (argv [0]);
1804 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
1808 utf8_fullpath = mono_utf8_from_external (fullpath);
1809 if(utf8_fullpath == NULL) {
1810 /* Printing the arg text will cause glib to
1811 * whinge about "Invalid UTF-8", but at least
1812 * its relevant, and shows the problem text
1815 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
1816 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
1823 utf8_fullpath = mono_utf8_from_external (argv[0]);
1824 if(utf8_fullpath == NULL) {
1825 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
1826 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
1831 main_args [0] = utf8_fullpath;
1833 for (i = 1; i < argc; ++i) {
1836 utf8_arg=mono_utf8_from_external (argv[i]);
1837 if(utf8_arg==NULL) {
1838 /* Ditto the comment about Invalid UTF-8 here */
1839 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
1840 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
1844 main_args [i] = utf8_arg;
1848 if (mono_method_signature (method)->param_count) {
1849 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
1850 for (i = 0; i < argc; ++i) {
1851 /* The encodings should all work, given that
1852 * we've checked all these args for the
1855 gchar *str = mono_utf8_from_external (argv [i]);
1856 MonoString *arg = mono_string_new (domain, str);
1857 mono_array_set (args, gpointer, i, arg);
1861 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
1864 mono_assembly_set_main (method->klass->image->assembly);
1866 result = mono_runtime_exec_main (method, args, exc);
1867 fire_process_exit_event ();
1871 /* Used in mono_unhandled_exception */
1873 create_unhandled_exception_eventargs (MonoObject *exc)
1877 MonoMethod *method = NULL;
1878 MonoBoolean is_terminating = TRUE;
1881 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
1884 mono_class_init (klass);
1886 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
1887 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
1891 args [1] = &is_terminating;
1893 obj = mono_object_new (mono_domain_get (), klass);
1894 mono_runtime_invoke (method, obj, args, NULL);
1900 * mono_unhandled_exception:
1901 * @exc: exception thrown
1903 * This is a VM internal routine.
1905 * We call this function when we detect an unhandled exception
1906 * in the default domain.
1908 * It invokes the * UnhandledException event in AppDomain or prints
1909 * a warning to the console
1912 mono_unhandled_exception (MonoObject *exc)
1914 MonoDomain *domain = mono_domain_get ();
1915 MonoClassField *field;
1916 MonoObject *delegate;
1918 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
1919 "UnhandledException");
1922 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
1923 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
1925 /* set exitcode only in the main thread */
1926 if (mono_thread_current () == main_thread)
1927 mono_environment_exitcode_set (1);
1928 if (domain != mono_get_root_domain () || !delegate) {
1929 mono_print_unhandled_exception (exc);
1931 MonoObject *e = NULL;
1934 pa [0] = domain->domain;
1935 pa [1] = create_unhandled_exception_eventargs (exc);
1936 mono_runtime_delegate_invoke (delegate, pa, &e);
1939 gchar *msg = mono_string_to_utf8 (((MonoException *) e)->message);
1940 g_warning ("exception inside UnhandledException handler: %s\n", msg);
1948 * Launch a new thread to execute a function
1950 * main_func is called back from the thread with main_args as the
1951 * parameter. The callback function is expected to start Main()
1952 * eventually. This function then waits for all managed threads to
1954 * It is not necesseray anymore to execute managed code in a subthread,
1955 * so this function should not be used anymore by default: just
1956 * execute the code and then call mono_thread_manage ().
1959 mono_runtime_exec_managed_code (MonoDomain *domain,
1960 MonoMainThreadFunc main_func,
1963 mono_thread_create (domain, main_func, main_args);
1965 mono_thread_manage ();
1969 * Execute a standard Main() method (args doesn't contain the
1973 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
1983 domain = mono_object_domain (args);
1984 if (!domain->entry_assembly) {
1986 MonoAssembly *assembly;
1988 assembly = method->klass->image->assembly;
1989 domain->entry_assembly = assembly;
1990 domain->setup->application_base = mono_string_new (domain, assembly->basedir);
1992 str = g_strconcat (assembly->image->name, ".config", NULL);
1993 domain->setup->configuration_file = mono_string_new (domain, str);
1997 /* FIXME: check signature of method */
1998 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
2000 res = mono_runtime_invoke (method, NULL, pa, exc);
2002 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
2006 mono_environment_exitcode_set (rval);
2008 mono_runtime_invoke (method, NULL, pa, exc);
2012 /* If the return type of Main is void, only
2013 * set the exitcode if an exception was thrown
2014 * (we don't want to blow away an
2015 * explicitly-set exit code)
2018 mono_environment_exitcode_set (rval);
2026 * mono_install_runtime_invoke:
2027 * @func: Function to install
2029 * This is a VM internal routine
2032 mono_install_runtime_invoke (MonoInvokeFunc func)
2034 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
2038 * mono_runtime_invoke_array:
2039 * @method: method to invoke
2040 * @obJ: object instance
2041 * @params: arguments to the method
2042 * @exc: exception information.
2044 * Invokes the method represented by @method on the object @obj.
2046 * obj is the 'this' pointer, it should be NULL for static
2047 * methods, a MonoObject* for object instances and a pointer to
2048 * the value type for value types.
2050 * The params array contains the arguments to the method with the
2051 * same convention: MonoObject* pointers for object instances and
2052 * pointers to the value type otherwise. The _invoke_array
2053 * variant takes a C# object[] as the params argument (MonoArray
2054 * *params): in this case the value types are boxed inside the
2055 * respective reference representation.
2057 * From unmanaged code you'll usually use the
2058 * mono_runtime_invoke() variant.
2060 * Note that this function doesn't handle virtual methods for
2061 * you, it will exec the exact method you pass: we still need to
2062 * expose a function to lookup the derived class implementation
2063 * of a virtual method (there are examples of this in the code,
2066 * You can pass NULL as the exc argument if you don't want to
2067 * catch exceptions, otherwise, *exc will be set to the exception
2068 * thrown, if any. if an exception is thrown, you can't use the
2069 * MonoObject* result from the function.
2071 * If the method returns a value type, it is boxed in an object
2075 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
2078 MonoMethodSignature *sig = mono_method_signature (method);
2079 gpointer *pa = NULL;
2082 if (NULL != params) {
2083 pa = alloca (sizeof (gpointer) * mono_array_length (params));
2084 for (i = 0; i < mono_array_length (params); i++) {
2085 if (sig->params [i]->byref) {
2089 switch (sig->params [i]->type) {
2092 case MONO_TYPE_BOOLEAN:
2095 case MONO_TYPE_CHAR:
2104 case MONO_TYPE_VALUETYPE:
2105 /* MS seems to create the objects if a null is passed in */
2106 if (! ((gpointer *)params->vector)[i])
2107 ((gpointer*)params->vector)[i] = mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i]));
2108 pa [i] = (char *)(((gpointer *)params->vector)[i]) + sizeof (MonoObject);
2110 case MONO_TYPE_STRING:
2111 case MONO_TYPE_OBJECT:
2112 case MONO_TYPE_CLASS:
2113 case MONO_TYPE_ARRAY:
2114 case MONO_TYPE_SZARRAY:
2115 if (sig->params [i]->byref)
2116 pa [i] = &(((gpointer *)params->vector)[i]);
2118 pa [i] = (char *)(((gpointer *)params->vector)[i]);
2121 g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
2126 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
2129 obj = mono_object_new (mono_domain_get (), method->klass);
2130 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
2131 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
2133 if (method->klass->valuetype)
2134 o = mono_object_unbox (obj);
2138 else if (method->klass->valuetype)
2139 obj = mono_value_box (mono_domain_get (), method->klass, obj);
2141 mono_runtime_invoke (method, o, pa, exc);
2144 /* obj must be already unboxed if needed */
2145 return mono_runtime_invoke (method, obj, pa, exc);
2150 arith_overflow (void)
2152 mono_raise_exception (mono_get_exception_overflow ());
2156 * mono_object_allocate:
2157 * @size: number of bytes to allocate
2159 * This is a very simplistic routine until we have our GC-aware
2162 * Returns: an allocated object of size @size, or NULL on failure.
2164 static inline void *
2165 mono_object_allocate (size_t size, MonoVTable *vtable)
2168 mono_stats.new_object_count++;
2169 ALLOC_OBJECT (o, vtable, size);
2175 * mono_object_allocate_ptrfree:
2176 * @size: number of bytes to allocate
2178 * Note that the memory allocated is not zeroed.
2179 * Returns: an allocated object of size @size, or NULL on failure.
2181 static inline void *
2182 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
2185 mono_stats.new_object_count++;
2186 ALLOC_PTRFREE (o, vtable, size);
2190 static inline void *
2191 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
2194 ALLOC_TYPED (o, size, vtable);
2195 mono_stats.new_object_count++;
2202 * @klass: the class of the object that we want to create
2204 * Returns: a newly created object whose definition is
2205 * looked up using @klass. This will not invoke any constructors,
2206 * so the consumer of this routine has to invoke any constructors on
2207 * its own to initialize the object.
2210 mono_object_new (MonoDomain *domain, MonoClass *klass)
2212 MONO_ARCH_SAVE_REGS;
2213 return mono_object_new_specific (mono_class_vtable (domain, klass));
2217 * mono_object_new_specific:
2218 * @vtable: the vtable of the object that we want to create
2220 * Returns: A newly created object with class and domain specified
2224 mono_object_new_specific (MonoVTable *vtable)
2228 MONO_ARCH_SAVE_REGS;
2233 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
2236 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
2239 mono_class_init (klass);
2241 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
2243 vtable->domain->create_proxy_for_type_method = im;
2246 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
2248 o = mono_runtime_invoke (im, NULL, pa, NULL);
2249 if (o != NULL) return o;
2252 return mono_object_new_alloc_specific (vtable);
2256 mono_object_new_alloc_specific (MonoVTable *vtable)
2260 if (!vtable->klass->has_references) {
2261 o = mono_object_new_ptrfree (vtable);
2262 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
2263 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
2265 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
2266 o = mono_object_allocate (vtable->klass->instance_size, vtable);
2268 if (vtable->klass->has_finalize)
2269 mono_object_register_finalizer (o);
2271 mono_profiler_allocation (o, vtable->klass);
2276 mono_object_new_fast (MonoVTable *vtable)
2279 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
2284 mono_object_new_ptrfree (MonoVTable *vtable)
2287 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
2288 #if NEED_TO_ZERO_PTRFREE
2289 /* an inline memset is much faster for the common vcase of small objects
2290 * note we assume the allocated size is a multiple of sizeof (void*).
2292 if (vtable->klass->instance_size < 128) {
2294 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
2295 p = (gpointer*)((char*)obj + sizeof (MonoObject));
2301 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
2308 mono_object_new_ptrfree_box (MonoVTable *vtable)
2311 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
2312 /* the object will be boxed right away, no need to memzero it */
2317 * mono_class_get_allocation_ftn:
2319 * @for_box: the object will be used for boxing
2320 * @pass_size_in_words:
2322 * Return the allocation function appropriate for the given class.
2326 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
2328 *pass_size_in_words = FALSE;
2330 if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
2331 return mono_object_new_specific;
2333 if (!vtable->klass->has_references) {
2334 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
2336 return mono_object_new_ptrfree_box;
2337 return mono_object_new_ptrfree;
2340 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
2342 return mono_object_new_fast;
2345 * FIXME: This is actually slower than mono_object_new_fast, because
2346 * of the overhead of parameter passing.
2349 *pass_size_in_words = TRUE;
2350 #ifdef GC_REDIRECT_TO_LOCAL
2351 return GC_local_gcj_fast_malloc;
2353 return GC_gcj_fast_malloc;
2358 return mono_object_new_specific;
2362 * mono_object_new_from_token:
2363 * @image: Context where the type_token is hosted
2364 * @token: a token of the type that we want to create
2366 * Returns: A newly created object whose definition is
2367 * looked up using @token in the @image image
2370 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
2374 class = mono_class_get (image, token);
2376 return mono_object_new (domain, class);
2381 * mono_object_clone:
2382 * @obj: the object to clone
2384 * Returns: A newly created object who is a shallow copy of @obj
2387 mono_object_clone (MonoObject *obj)
2392 size = obj->vtable->klass->instance_size;
2393 o = mono_object_allocate (size, obj->vtable);
2394 /* do not copy the sync state */
2395 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
2397 mono_profiler_allocation (o, obj->vtable->klass);
2399 if (obj->vtable->klass->has_finalize)
2400 mono_object_register_finalizer (o);
2405 * mono_array_full_copy:
2406 * @src: source array to copy
2407 * @dest: destination array
2409 * Copies the content of one array to another with exactly the same type and size.
2412 mono_array_full_copy (MonoArray *src, MonoArray *dest)
2415 MonoClass *klass = src->obj.vtable->klass;
2417 MONO_ARCH_SAVE_REGS;
2419 g_assert (klass == dest->obj.vtable->klass);
2421 size = mono_array_length (src);
2422 g_assert (size == mono_array_length (dest));
2423 size *= mono_array_element_size (klass);
2424 memcpy (&dest->vector, &src->vector, size);
2428 * mono_array_clone_in_domain:
2429 * @domain: the domain in which the array will be cloned into
2430 * @array: the array to clone
2432 * This routine returns a copy of the array that is hosted on the
2433 * specified MonoDomain.
2436 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
2441 MonoClass *klass = array->obj.vtable->klass;
2443 MONO_ARCH_SAVE_REGS;
2445 if (array->bounds == NULL) {
2446 size = mono_array_length (array);
2447 o = mono_array_new_full (domain, klass, &size, NULL);
2449 size *= mono_array_element_size (klass);
2450 memcpy (&o->vector, &array->vector, size);
2454 sizes = alloca (klass->rank * sizeof(guint32) * 2);
2455 size = mono_array_element_size (klass);
2456 for (i = 0; i < klass->rank; ++i) {
2457 sizes [i] = array->bounds [i].length;
2458 size *= array->bounds [i].length;
2459 sizes [i + klass->rank] = array->bounds [i].lower_bound;
2461 o = mono_array_new_full (domain, klass, sizes, sizes + klass->rank);
2462 memcpy (&o->vector, &array->vector, size);
2469 * @array: the array to clone
2471 * Returns: A newly created array who is a shallow copy of @array
2474 mono_array_clone (MonoArray *array)
2476 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
2479 /* helper macros to check for overflow when calculating the size of arrays */
2480 #define MYGUINT32_MAX 4294967295U
2481 #define CHECK_ADD_OVERFLOW_UN(a,b) \
2482 (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
2483 #define CHECK_MUL_OVERFLOW_UN(a,b) \
2484 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
2485 (guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a))
2488 * mono_array_new_full:
2489 * @domain: domain where the object is created
2490 * @array_class: array class
2491 * @lengths: lengths for each dimension in the array
2492 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
2494 * This routine creates a new array objects with the given dimensions,
2495 * lower bounds and type.
2498 mono_array_new_full (MonoDomain *domain, MonoClass *array_class,
2499 guint32 *lengths, guint32 *lower_bounds)
2501 guint32 byte_len, len, bounds_size;
2507 if (!array_class->inited)
2508 mono_class_init (array_class);
2510 byte_len = mono_array_element_size (array_class);
2513 if (array_class->rank == 1 && array_class->byval_arg.type == MONO_TYPE_SZARRAY) {
2519 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
2521 for (i = 0; i < array_class->rank; ++i) {
2522 if ((int) lengths [i] < 0)
2524 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
2525 mono_gc_out_of_memory (MYGUINT32_MAX);
2530 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
2531 mono_gc_out_of_memory (MYGUINT32_MAX);
2533 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
2534 mono_gc_out_of_memory (MYGUINT32_MAX);
2535 byte_len += sizeof (MonoArray);
2538 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
2539 mono_gc_out_of_memory (MYGUINT32_MAX);
2540 byte_len = (byte_len + 3) & ~3;
2541 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
2542 mono_gc_out_of_memory (MYGUINT32_MAX);
2543 byte_len += bounds_size;
2546 * Following three lines almost taken from mono_object_new ():
2547 * they need to be kept in sync.
2549 vtable = mono_class_vtable (domain, array_class);
2550 if (!array_class->has_references) {
2551 o = mono_object_allocate_ptrfree (byte_len, vtable);
2552 #if NEED_TO_ZERO_PTRFREE
2553 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
2555 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
2556 o = mono_object_allocate_spec (byte_len, vtable);
2558 o = mono_object_allocate (byte_len, vtable);
2561 array = (MonoArray*)o;
2562 array->max_length = len;
2565 MonoArrayBounds *bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
2566 array->bounds = bounds;
2567 for (i = 0; i < array_class->rank; ++i) {
2568 bounds [i].length = lengths [i];
2570 bounds [i].lower_bound = lower_bounds [i];
2574 mono_profiler_allocation (o, array_class);
2581 * @domain: domain where the object is created
2582 * @eclass: element class
2583 * @n: number of array elements
2585 * This routine creates a new szarray with @n elements of type @eclass.
2588 mono_array_new (MonoDomain *domain, MonoClass *eclass, guint32 n)
2592 MONO_ARCH_SAVE_REGS;
2594 ac = mono_array_class_get (eclass, 1);
2595 g_assert (ac != NULL);
2597 return mono_array_new_specific (mono_class_vtable (domain, ac), n);
2601 * mono_array_new_specific:
2602 * @vtable: a vtable in the appropriate domain for an initialized class
2603 * @n: number of array elements
2605 * This routine is a fast alternative to mono_array_new() for code which
2606 * can be sure about the domain it operates in.
2609 mono_array_new_specific (MonoVTable *vtable, guint32 n)
2613 guint32 byte_len, elem_size;
2615 MONO_ARCH_SAVE_REGS;
2620 elem_size = mono_array_element_size (vtable->klass);
2621 if (CHECK_MUL_OVERFLOW_UN (n, elem_size))
2622 mono_gc_out_of_memory (MYGUINT32_MAX);
2623 byte_len = n * elem_size;
2624 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
2625 mono_gc_out_of_memory (MYGUINT32_MAX);
2626 byte_len += sizeof (MonoArray);
2627 if (!vtable->klass->has_references) {
2628 o = mono_object_allocate_ptrfree (byte_len, vtable);
2629 #if NEED_TO_ZERO_PTRFREE
2630 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
2632 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
2633 o = mono_object_allocate_spec (byte_len, vtable);
2635 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
2636 o = mono_object_allocate (byte_len, vtable);
2639 ao = (MonoArray *)o;
2642 mono_profiler_allocation (o, vtable->klass);
2648 * mono_string_new_utf16:
2649 * @text: a pointer to an utf16 string
2650 * @len: the length of the string
2652 * Returns: A newly created string object which contains @text.
2655 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
2659 s = mono_string_new_size (domain, len);
2660 g_assert (s != NULL);
2662 memcpy (mono_string_chars (s), text, len * 2);
2668 * mono_string_new_size:
2669 * @text: a pointer to an utf16 string
2670 * @len: the length of the string
2672 * Returns: A newly created string object of @len
2675 mono_string_new_size (MonoDomain *domain, gint32 len)
2679 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
2681 /* overflow ? can't fit it, can't allocate it! */
2683 mono_gc_out_of_memory (-1);
2685 vtable = mono_class_vtable (domain, mono_defaults.string_class);
2687 s = mono_object_allocate_ptrfree (size, vtable);
2690 #if NEED_TO_ZERO_PTRFREE
2693 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
2699 * mono_string_new_len:
2700 * @text: a pointer to an utf8 string
2701 * @length: number of bytes in @text to consider
2703 * Returns: A newly created string object which contains @text.
2706 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
2708 GError *error = NULL;
2709 MonoString *o = NULL;
2711 glong items_written;
2713 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
2716 o = mono_string_new_utf16 (domain, ut, items_written);
2718 g_error_free (error);
2727 * @text: a pointer to an utf8 string
2729 * Returns: A newly created string object which contains @text.
2732 mono_string_new (MonoDomain *domain, const char *text)
2734 GError *error = NULL;
2735 MonoString *o = NULL;
2737 glong items_written;
2742 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
2745 o = mono_string_new_utf16 (domain, ut, items_written);
2747 g_error_free (error);
2755 * mono_string_new_wrapper:
2756 * @text: pointer to utf8 characters.
2758 * Helper function to create a string object from @text in the current domain.
2761 mono_string_new_wrapper (const char *text)
2763 MonoDomain *domain = mono_domain_get ();
2765 MONO_ARCH_SAVE_REGS;
2768 return mono_string_new (domain, text);
2775 * @class: the class of the value
2776 * @value: a pointer to the unboxed data
2778 * Returns: A newly created object which contains @value.
2781 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
2787 g_assert (class->valuetype);
2789 vtable = mono_class_vtable (domain, class);
2790 size = mono_class_instance_size (class);
2791 res = mono_object_allocate (size, vtable);
2792 mono_profiler_allocation (res, class);
2794 size = size - sizeof (MonoObject);
2796 #if NO_UNALIGNED_ACCESS
2797 memcpy ((char *)res + sizeof (MonoObject), value, size);
2801 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
2804 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
2807 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
2810 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
2813 memcpy ((char *)res + sizeof (MonoObject), value, size);
2816 if (class->has_finalize)
2817 mono_object_register_finalizer (res);
2822 * mono_object_get_domain:
2823 * @obj: object to query
2825 * Returns: the MonoDomain where the object is hosted
2828 mono_object_get_domain (MonoObject *obj)
2830 return mono_object_domain (obj);
2834 * mono_object_get_class:
2835 * @obj: object to query
2837 * Returns: the MonOClass of the object.
2840 mono_object_get_class (MonoObject *obj)
2842 return mono_object_class (obj);
2845 * mono_object_get_size:
2846 * @o: object to query
2848 * Returns: the size, in bytes, of @o
2851 mono_object_get_size (MonoObject* o)
2853 MonoClass* klass = mono_object_class (o);
2855 if (klass == mono_defaults.string_class)
2856 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
2857 else if (klass->parent == mono_defaults.array_class)
2858 return sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length ((MonoArray*) o);
2860 return mono_class_instance_size (klass);
2864 * mono_object_unbox:
2865 * @obj: object to unbox
2867 * Returns: a pointer to the start of the valuetype boxed in this
2870 * This method will assert if the object passed is not a valuetype.
2873 mono_object_unbox (MonoObject *obj)
2875 /* add assert for valuetypes? */
2876 g_assert (obj->vtable->klass->valuetype);
2877 return ((char*)obj) + sizeof (MonoObject);
2881 * mono_object_isinst:
2883 * @klass: a pointer to a class
2885 * Returns: @obj if @obj is derived from @klass
2888 mono_object_isinst (MonoObject *obj, MonoClass *klass)
2891 mono_class_init (klass);
2893 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)
2894 return mono_object_isinst_mbyref (obj, klass);
2899 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
2903 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
2912 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2913 if ((klass->interface_id <= vt->max_interface_id) &&
2914 (vt->interface_offsets [klass->interface_id] != 0))
2918 MonoClass *oklass = vt->klass;
2919 if ((oklass == mono_defaults.transparent_proxy_class))
2920 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2922 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
2926 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
2928 MonoDomain *domain = mono_domain_get ();
2930 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
2931 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
2932 MonoMethod *im = NULL;
2935 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
2936 im = mono_object_get_virtual_method (rp, im);
2939 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
2942 res = mono_runtime_invoke (im, rp, pa, NULL);
2944 if (*(MonoBoolean *) mono_object_unbox(res)) {
2945 /* Update the vtable of the remote type, so it can safely cast to this new type */
2946 mono_upgrade_remote_class (domain, obj, klass);
2955 * mono_object_castclass_mbyref:
2957 * @klass: a pointer to a class
2959 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
2962 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
2964 if (!obj) return NULL;
2965 if (mono_object_isinst_mbyref (obj, klass)) return obj;
2967 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
2969 "InvalidCastException"));
2974 MonoDomain *orig_domain;
2980 str_lookup (MonoDomain *domain, gpointer user_data)
2982 LDStrInfo *info = user_data;
2983 if (info->res || domain == info->orig_domain)
2985 mono_domain_lock (domain);
2986 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
2987 mono_domain_unlock (domain);
2991 mono_string_is_interned_lookup (MonoString *str, int insert)
2993 MonoGHashTable *ldstr_table;
2997 domain = ((MonoObject *)str)->vtable->domain;
2998 ldstr_table = domain->ldstr_table;
2999 mono_domain_lock (domain);
3000 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
3001 mono_domain_unlock (domain);
3005 mono_g_hash_table_insert (ldstr_table, str, str);
3006 mono_domain_unlock (domain);
3009 LDStrInfo ldstr_info;
3010 ldstr_info.orig_domain = domain;
3011 ldstr_info.ins = str;
3012 ldstr_info.res = NULL;
3014 mono_domain_foreach (str_lookup, &ldstr_info);
3015 if (ldstr_info.res) {
3017 * the string was already interned in some other domain:
3018 * intern it in the current one as well.
3020 mono_g_hash_table_insert (ldstr_table, str, str);
3021 mono_domain_unlock (domain);
3025 mono_domain_unlock (domain);
3030 * mono_string_is_interned:
3031 * @o: String to probe
3033 * Returns whether the string has been interned.
3036 mono_string_is_interned (MonoString *o)
3038 return mono_string_is_interned_lookup (o, FALSE);
3042 * mono_string_interne:
3043 * @o: String to intern
3045 * Interns the string passed.
3046 * Returns: The interned string.
3049 mono_string_intern (MonoString *str)
3051 return mono_string_is_interned_lookup (str, TRUE);
3056 * @domain: the domain where the string will be used.
3057 * @image: a metadata context
3058 * @idx: index into the user string table.
3060 * Implementation for the ldstr opcode.
3061 * Returns: a loaded string from the @image/@idx combination.
3064 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
3066 MONO_ARCH_SAVE_REGS;
3069 return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx);
3071 return mono_ldstr_metdata_sig (domain, mono_metadata_user_string (image, idx));
3075 * mono_ldstr_metdata_sig
3076 * @domain: the domain for the string
3077 * @sig: the signature of a metadata string
3079 * Returns: a MonoString for a string stored in the metadata
3082 mono_ldstr_metdata_sig (MonoDomain *domain, const char* sig)
3084 const char *str = sig;
3085 MonoString *o, *interned;
3088 len2 = mono_metadata_decode_blob_size (str, &str);
3091 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
3092 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
3095 guint16 *p2 = (guint16*)mono_string_chars (o);
3096 for (i = 0; i < len2; ++i) {
3097 *p2 = GUINT16_FROM_LE (*p2);
3102 mono_domain_lock (domain);
3103 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
3104 mono_domain_unlock (domain);
3105 /* o will get garbage collected */
3109 mono_g_hash_table_insert (domain->ldstr_table, o, o);
3110 mono_domain_unlock (domain);
3116 * mono_string_to_utf8:
3117 * @s: a System.String
3119 * Return the UTF8 representation for @s.
3120 * the resulting buffer nedds to be freed with g_free().
3123 mono_string_to_utf8 (MonoString *s)
3126 GError *error = NULL;
3132 return g_strdup ("");
3134 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, NULL, &error);
3136 g_warning (error->message);
3137 g_error_free (error);
3144 * mono_string_to_utf16:
3147 * Return an null-terminated array of the utf-16 chars
3148 * contained in @s. The result must be freed with g_free().
3149 * This is a temporary helper until our string implementation
3150 * is reworked to always include the null terminating char.
3153 mono_string_to_utf16 (MonoString *s)
3160 as = g_malloc ((s->length * 2) + 2);
3161 as [(s->length * 2)] = '\0';
3162 as [(s->length * 2) + 1] = '\0';
3165 return (gunichar2 *)(as);
3168 memcpy (as, mono_string_chars(s), s->length * 2);
3169 return (gunichar2 *)(as);
3173 * mono_string_from_utf16:
3174 * @data: the UTF16 string (LPWSTR) to convert
3176 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
3178 * Returns: a MonoString.
3181 mono_string_from_utf16 (gunichar2 *data)
3183 MonoDomain *domain = mono_domain_get ();
3189 while (data [len]) len++;
3191 return mono_string_new_utf16 (domain, data, len);
3195 default_ex_handler (MonoException *ex)
3197 MonoObject *o = (MonoObject*)ex;
3198 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
3202 static MonoExceptionFunc ex_handler = default_ex_handler;
3205 * mono_install_handler:
3206 * @func: exception handler
3208 * This is an internal JIT routine used to install the handler for exceptions
3212 mono_install_handler (MonoExceptionFunc func)
3214 ex_handler = func? func: default_ex_handler;
3218 * mono_raise_exception:
3219 * @ex: exception object
3221 * Signal the runtime that the exception @ex has been raised in unmanaged code.
3224 mono_raise_exception (MonoException *ex)
3227 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
3228 * that will cause gcc to omit the function epilog, causing problems when
3229 * the JIT tries to walk the stack, since the return address on the stack
3230 * will point into the next function in the executable, not this one.
3233 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class)
3234 mono_thread_current ()->abort_exc = ex;
3240 * mono_wait_handle_new:
3241 * @domain: Domain where the object will be created
3242 * @handle: Handle for the wait handle
3244 * Returns: A new MonoWaitHandle created in the given domain for the given handle
3247 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
3249 MonoWaitHandle *res;
3251 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
3253 res->handle = handle;
3259 * mono_async_result_new:
3260 * @domain:domain where the object will be created.
3261 * @handle: wait handle.
3262 * @state: state to pass to AsyncResult
3263 * @data: C closure data.
3265 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
3266 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
3270 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data)
3272 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
3273 MonoMethod *method = mono_get_context_capture_method ();
3275 /* we must capture the execution context from the original thread */
3277 res->execution_context = mono_runtime_invoke (method, NULL, NULL, NULL);
3278 /* note: result may be null if the flow is suppressed */
3282 res->async_state = state;
3284 res->handle = (MonoObject *) mono_wait_handle_new (domain, handle);
3286 res->sync_completed = FALSE;
3287 res->completed = FALSE;
3293 mono_message_init (MonoDomain *domain,
3294 MonoMethodMessage *this,
3295 MonoReflectionMethod *method,
3296 MonoArray *out_args)
3298 MonoMethodSignature *sig = mono_method_signature (method->method);
3304 this->method = method;
3306 this->args = mono_array_new (domain, mono_defaults.object_class, sig->param_count);
3307 this->arg_types = mono_array_new (domain, mono_defaults.byte_class, sig->param_count);
3308 this->async_result = NULL;
3309 this->call_type = CallType_Sync;
3311 names = g_new (char *, sig->param_count);
3312 mono_method_get_param_names (method->method, (const char **) names);
3313 this->names = mono_array_new (domain, mono_defaults.string_class, sig->param_count);
3315 for (i = 0; i < sig->param_count; i++) {
3316 name = mono_string_new (domain, names [i]);
3317 mono_array_set (this->names, gpointer, i, name);
3321 for (i = 0, j = 0; i < sig->param_count; i++) {
3323 if (sig->params [i]->byref) {
3325 gpointer arg = mono_array_get (out_args, gpointer, j);
3326 mono_array_set (this->args, gpointer, i, arg);
3330 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
3334 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
3337 mono_array_set (this->arg_types, guint8, i, arg_type);
3342 * mono_remoting_invoke:
3343 * @real_proxy: pointer to a RealProxy object
3344 * @msg: The MonoMethodMessage to execute
3345 * @exc: used to store exceptions
3346 * @out_args: used to store output arguments
3348 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
3349 * IMessage interface and it is not trivial to extract results from there. So
3350 * we call an helper method PrivateInvoke instead of calling
3351 * RealProxy::Invoke() directly.
3353 * Returns: the result object.
3356 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
3357 MonoObject **exc, MonoArray **out_args)
3359 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
3362 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
3365 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
3367 real_proxy->vtable->domain->private_invoke_method = im;
3370 pa [0] = real_proxy;
3375 return mono_runtime_invoke (im, NULL, pa, exc);
3379 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
3380 MonoObject **exc, MonoArray **out_args)
3384 MonoMethodSignature *sig;
3386 int i, j, outarg_count = 0;
3388 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
3390 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
3391 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3392 target = tp->rp->unwrapped_server;
3394 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
3398 domain = mono_domain_get ();
3399 method = msg->method->method;
3400 sig = mono_method_signature (method);
3402 for (i = 0; i < sig->param_count; i++) {
3403 if (sig->params [i]->byref)
3407 *out_args = mono_array_new (domain, mono_defaults.object_class, outarg_count);
3410 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
3412 for (i = 0, j = 0; i < sig->param_count; i++) {
3413 if (sig->params [i]->byref) {
3415 arg = mono_array_get (msg->args, gpointer, i);
3416 mono_array_set (*out_args, gpointer, j, arg);
3425 * mono_print_unhandled_exception:
3426 * @exc: The exception
3428 * Prints the unhandled exception.
3431 mono_print_unhandled_exception (MonoObject *exc)
3433 char *message = (char *) "";
3437 gboolean free_message = FALSE;
3439 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
3440 klass = exc->vtable->klass;
3442 while (klass && method == NULL) {
3443 method = mono_class_get_method_from_name_flags (klass, "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
3445 klass = klass->parent;
3450 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
3452 message = mono_string_to_utf8 (str);
3453 free_message = TRUE;
3458 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
3459 * exc->vtable->klass->name, message);
3461 g_printerr ("\nUnhandled Exception: %s\n", message);
3468 * mono_delegate_ctor:
3469 * @this: pointer to an uninitialized delegate object
3470 * @target: target object
3471 * @addr: pointer to native code
3473 * This is used to initialize a delegate. We also insert the method_info if
3474 * we find the info with mono_jit_info_table_find().
3477 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
3479 MonoDomain *domain = mono_domain_get ();
3480 MonoDelegate *delegate = (MonoDelegate *)this;
3481 MonoMethod *method = NULL;
3488 class = this->vtable->klass;
3490 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
3491 method = ji->method;
3492 delegate->method_info = mono_method_get_object (domain, method, NULL);
3495 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
3497 method = mono_marshal_get_remoting_invoke (method);
3498 delegate->method_ptr = mono_compile_method (method);
3499 delegate->target = target;
3500 } else if (mono_method_signature (method)->hasthis && method->klass->valuetype) {
3501 method = mono_marshal_get_unbox_wrapper (method);
3502 delegate->method_ptr = mono_compile_method (method);
3503 delegate->target = target;
3507 * Replace the original trampoline with a delegate trampoline
3508 * which will patch delegate->method_ptr with the address of the
3511 addr = arch_create_delegate_trampoline (method, addr);
3513 delegate->method_ptr = addr;
3514 delegate->target = target;
3519 * mono_method_call_message_new:
3520 * @method: method to encapsulate
3521 * @params: parameters to the method
3522 * @invoke: optional, delegate invoke.
3523 * @cb: async callback delegate.
3524 * @state: state passed to the async callback.
3526 * Translates arguments pointers into a MonoMethodMessage.
3529 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
3530 MonoDelegate **cb, MonoObject **state)
3532 MonoDomain *domain = mono_domain_get ();
3533 MonoMethodSignature *sig = mono_method_signature (method);
3534 MonoMethodMessage *msg;
3537 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3540 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
3541 count = sig->param_count - 2;
3543 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
3544 count = sig->param_count;
3547 for (i = 0; i < count; i++) {
3552 if (sig->params [i]->byref)
3553 vpos = *((gpointer *)params [i]);
3557 type = sig->params [i]->type;
3558 class = mono_class_from_mono_type (sig->params [i]);
3560 if (class->valuetype)
3561 arg = mono_value_box (domain, class, vpos);
3563 arg = *((MonoObject **)vpos);
3565 mono_array_set (msg->args, gpointer, i, arg);
3568 if (cb != NULL && state != NULL) {
3569 *cb = *((MonoDelegate **)params [i]);
3571 *state = *((MonoObject **)params [i]);
3578 * mono_method_return_message_restore:
3580 * Restore results from message based processing back to arguments pointers
3583 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
3585 MonoMethodSignature *sig = mono_method_signature (method);
3586 int i, j, type, size, out_len;
3588 if (out_args == NULL)
3590 out_len = mono_array_length (out_args);
3594 for (i = 0, j = 0; i < sig->param_count; i++) {
3595 MonoType *pt = sig->params [i];
3600 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
3602 arg = mono_array_get (out_args, gpointer, j);
3606 case MONO_TYPE_VOID:
3607 g_assert_not_reached ();
3611 case MONO_TYPE_BOOLEAN:
3614 case MONO_TYPE_CHAR:
3621 case MONO_TYPE_VALUETYPE: {
3622 size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
3623 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
3626 case MONO_TYPE_STRING:
3627 case MONO_TYPE_CLASS:
3628 case MONO_TYPE_ARRAY:
3629 case MONO_TYPE_SZARRAY:
3630 case MONO_TYPE_OBJECT:
3631 **((MonoObject ***)params [i]) = (MonoObject *)arg;
3634 g_assert_not_reached ();
3643 * mono_load_remote_field:
3644 * @this: pointer to an object
3645 * @klass: klass of the object containing @field
3646 * @field: the field to load
3647 * @res: a storage to store the result
3649 * This method is called by the runtime on attempts to load fields of
3650 * transparent proxy objects. @this points to such TP, @klass is the class of
3651 * the object containing @field. @res is a storage location which can be
3652 * used to store the result.
3654 * Returns: an address pointing to the value of field.
3657 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
3659 static MonoMethod *getter = NULL;
3660 MonoDomain *domain = mono_domain_get ();
3661 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3662 MonoClass *field_class;
3663 MonoMethodMessage *msg;
3664 MonoArray *out_args;
3668 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3673 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3674 mono_field_get_value (tp->rp->unwrapped_server, field, res);
3679 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
3683 field_class = mono_class_from_mono_type (field->type);
3685 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3686 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
3687 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
3689 mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3690 mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3692 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3694 if (exc) mono_raise_exception ((MonoException *)exc);
3696 if (mono_array_length (out_args) == 0)
3699 *res = mono_array_get (out_args, MonoObject *, 0);
3701 if (field_class->valuetype) {
3702 return ((char *)*res) + sizeof (MonoObject);
3708 * mono_load_remote_field_new:
3713 * Missing documentation.
3716 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
3718 static MonoMethod *getter = NULL;
3719 MonoDomain *domain = mono_domain_get ();
3720 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3721 MonoClass *field_class;
3722 MonoMethodMessage *msg;
3723 MonoArray *out_args;
3724 MonoObject *exc, *res;
3726 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3728 field_class = mono_class_from_mono_type (field->type);
3730 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3732 if (field_class->valuetype) {
3733 res = mono_object_new (domain, field_class);
3734 val = ((gchar *) res) + sizeof (MonoObject);
3738 mono_field_get_value (tp->rp->unwrapped_server, field, val);
3743 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
3747 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3748 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
3750 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
3752 mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3753 mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3755 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3757 if (exc) mono_raise_exception ((MonoException *)exc);
3759 if (mono_array_length (out_args) == 0)
3762 res = mono_array_get (out_args, MonoObject *, 0);
3768 * mono_store_remote_field:
3769 * @this: pointer to an object
3770 * @klass: klass of the object containing @field
3771 * @field: the field to load
3772 * @val: the value/object to store
3774 * This method is called by the runtime on attempts to store fields of
3775 * transparent proxy objects. @this points to such TP, @klass is the class of
3776 * the object containing @field. @val is the new value to store in @field.
3779 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
3781 static MonoMethod *setter = NULL;
3782 MonoDomain *domain = mono_domain_get ();
3783 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3784 MonoClass *field_class;
3785 MonoMethodMessage *msg;
3786 MonoArray *out_args;
3790 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3792 field_class = mono_class_from_mono_type (field->type);
3794 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3795 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
3796 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
3801 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
3805 if (field_class->valuetype)
3806 arg = mono_value_box (domain, field_class, val);
3808 arg = *((MonoObject **)val);
3811 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3812 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
3814 mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3815 mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3816 mono_array_set (msg->args, gpointer, 2, arg);
3818 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3820 if (exc) mono_raise_exception ((MonoException *)exc);
3824 * mono_store_remote_field_new:
3830 * Missing documentation
3833 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
3835 static MonoMethod *setter = NULL;
3836 MonoDomain *domain = mono_domain_get ();
3837 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3838 MonoClass *field_class;
3839 MonoMethodMessage *msg;
3840 MonoArray *out_args;
3843 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3845 field_class = mono_class_from_mono_type (field->type);
3847 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3848 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
3849 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
3854 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
3858 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3859 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
3861 mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3862 mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3863 mono_array_set (msg->args, gpointer, 2, arg);
3865 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3867 if (exc) mono_raise_exception ((MonoException *)exc);
3871 * mono_get_addr_from_ftnptr:
3873 * Given a pointer to a function descriptor, return the function address.
3874 * This is only needed on IA64.
3877 mono_get_addr_from_ftnptr (gpointer descr)
3880 return *(gpointer*)descr;