2010-05-14 Rodrigo Kumpera <rkumpera@novell.com>
[mono-project.git] / mono / metadata / object.c
blob11043d598276bfce9d4ae0587376a3276f4de7fa
1 /*
2 * object.c: Object creation for the Mono runtime
4 * Author:
5 * Miguel de Icaza (miguel@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
8 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11 #include <config.h>
12 #ifdef HAVE_ALLOCA_H
13 #include <alloca.h>
14 #endif
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <signal.h>
18 #include <string.h>
19 #include <mono/metadata/mono-endian.h>
20 #include <mono/metadata/tabledefs.h>
21 #include <mono/metadata/tokentype.h>
22 #include <mono/metadata/loader.h>
23 #include <mono/metadata/object.h>
24 #include <mono/metadata/gc-internal.h>
25 #include <mono/metadata/exception.h>
26 #include <mono/metadata/domain-internals.h>
27 #include "mono/metadata/metadata-internals.h"
28 #include "mono/metadata/class-internals.h"
29 #include <mono/metadata/assembly.h>
30 #include <mono/metadata/threadpool.h>
31 #include <mono/metadata/marshal.h>
32 #include "mono/metadata/debug-helpers.h"
33 #include "mono/metadata/marshal.h"
34 #include <mono/metadata/threads.h>
35 #include <mono/metadata/threads-types.h>
36 #include <mono/metadata/environment.h>
37 #include "mono/metadata/profiler-private.h"
38 #include "mono/metadata/security-manager.h"
39 #include "mono/metadata/mono-debug-debugger.h"
40 #include <mono/metadata/gc-internal.h>
41 #include <mono/metadata/verify-internals.h>
42 #include <mono/utils/strenc.h>
43 #include <mono/utils/mono-counters.h>
44 #include <mono/utils/mono-error-internals.h>
45 #include "cominterop.h"
47 #ifdef HAVE_BOEHM_GC
48 #define NEED_TO_ZERO_PTRFREE 1
49 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = GC_MALLOC_ATOMIC ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
50 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = GC_MALLOC ((size)); (obj)->vtable = (vt);} while (0)
51 #ifdef HAVE_GC_GCJ_MALLOC
52 #define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
53 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_GCJ_MALLOC ((size),(type)); } while (0)
54 #else
55 #define GC_NO_DESCRIPTOR (NULL)
56 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_MALLOC ((size)); *(gpointer*)dest = (type);} while (0)
57 #endif
58 #else
59 #ifdef HAVE_SGEN_GC
60 #define GC_NO_DESCRIPTOR (NULL)
61 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
62 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
63 #define ALLOC_TYPED(dest,size,type) do { (dest) = mono_gc_alloc_obj (type, size);} while (0)
64 #else
65 #define NEED_TO_ZERO_PTRFREE 1
66 #define GC_NO_DESCRIPTOR (NULL)
67 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = malloc ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
68 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = calloc (1, (size)); (obj)->vtable = (vt);} while (0)
69 #define ALLOC_TYPED(dest,size,type) do { (dest) = calloc (1, (size)); *(gpointer*)dest = (type);} while (0)
70 #endif
71 #endif
73 static MonoObject* mono_object_new_ptrfree (MonoVTable *vtable);
74 static MonoObject* mono_object_new_ptrfree_box (MonoVTable *vtable);
76 static void
77 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
79 static MonoString*
80 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig);
82 #define ldstr_lock() EnterCriticalSection (&ldstr_section)
83 #define ldstr_unlock() LeaveCriticalSection (&ldstr_section)
84 static CRITICAL_SECTION ldstr_section;
86 static gboolean profile_allocs = TRUE;
88 void
89 mono_runtime_object_init (MonoObject *this)
91 MonoMethod *method = NULL;
92 MonoClass *klass = this->vtable->klass;
94 method = mono_class_get_method_from_name (klass, ".ctor", 0);
95 g_assert (method);
97 if (method->klass->valuetype)
98 this = mono_object_unbox (this);
99 mono_runtime_invoke (method, this, NULL, NULL);
102 /* The pseudo algorithm for type initialization from the spec
103 Note it doesn't say anything about domains - only threads.
105 2. If the type is initialized you are done.
106 2.1. If the type is not yet initialized, try to take an
107 initialization lock.
108 2.2. If successful, record this thread as responsible for
109 initializing the type and proceed to step 2.3.
110 2.2.1. If not, see whether this thread or any thread
111 waiting for this thread to complete already holds the lock.
112 2.2.2. If so, return since blocking would create a deadlock. This thread
113 will now see an incompletely initialized state for the type,
114 but no deadlock will arise.
115 2.2.3 If not, block until the type is initialized then return.
116 2.3 Initialize the parent type and then all interfaces implemented
117 by this type.
118 2.4 Execute the type initialization code for this type.
119 2.5 Mark the type as initialized, release the initialization lock,
120 awaken any threads waiting for this type to be initialized,
121 and return.
125 typedef struct
127 guint32 initializing_tid;
128 guint32 waiting_count;
129 gboolean done;
130 CRITICAL_SECTION initialization_section;
131 } TypeInitializationLock;
133 /* for locking access to type_initialization_hash and blocked_thread_hash */
134 #define mono_type_initialization_lock() EnterCriticalSection (&type_initialization_section)
135 #define mono_type_initialization_unlock() LeaveCriticalSection (&type_initialization_section)
136 static CRITICAL_SECTION type_initialization_section;
138 /* from vtable to lock */
139 static GHashTable *type_initialization_hash;
141 /* from thread id to thread id being waited on */
142 static GHashTable *blocked_thread_hash;
144 /* Main thread */
145 static MonoThread *main_thread;
147 /* Functions supplied by the runtime */
148 static MonoRuntimeCallbacks callbacks;
151 * mono_thread_set_main:
152 * @thread: thread to set as the main thread
154 * This function can be used to instruct the runtime to treat @thread
155 * as the main thread, ie, the thread that would normally execute the Main()
156 * method. This basically means that at the end of @thread, the runtime will
157 * wait for the existing foreground threads to quit and other such details.
159 void
160 mono_thread_set_main (MonoThread *thread)
162 main_thread = thread;
165 MonoThread*
166 mono_thread_get_main (void)
168 return main_thread;
171 void
172 mono_type_initialization_init (void)
174 InitializeCriticalSection (&type_initialization_section);
175 type_initialization_hash = g_hash_table_new (NULL, NULL);
176 blocked_thread_hash = g_hash_table_new (NULL, NULL);
177 InitializeCriticalSection (&ldstr_section);
180 void
181 mono_type_initialization_cleanup (void)
183 #if 0
184 /* This is causing race conditions with
185 * mono_release_type_locks
187 DeleteCriticalSection (&type_initialization_section);
188 #endif
189 DeleteCriticalSection (&ldstr_section);
193 * get_type_init_exception_for_vtable:
195 * Return the stored type initialization exception for VTABLE.
197 static MonoException*
198 get_type_init_exception_for_vtable (MonoVTable *vtable)
200 MonoDomain *domain = vtable->domain;
201 MonoClass *klass = vtable->klass;
202 MonoException *ex;
203 gchar *full_name;
205 g_assert (vtable->init_failed);
208 * If the initializing thread was rudely aborted, the exception is not stored
209 * in the hash.
211 ex = NULL;
212 mono_domain_lock (domain);
213 if (domain->type_init_exception_hash)
214 ex = mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
215 mono_domain_unlock (domain);
217 if (!ex) {
218 if (klass->name_space && *klass->name_space)
219 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
220 else
221 full_name = g_strdup (klass->name);
222 ex = mono_get_exception_type_initialization (full_name, NULL);
223 g_free (full_name);
226 return ex;
229 * mono_runtime_class_init:
230 * @vtable: vtable that needs to be initialized
232 * This routine calls the class constructor for @vtable.
234 void
235 mono_runtime_class_init (MonoVTable *vtable)
237 mono_runtime_class_init_full (vtable, TRUE);
241 * mono_runtime_class_init_full:
242 * @vtable that neeeds to be initialized
243 * @raise_exception is TRUE, exceptions are raised intead of returned
246 MonoException *
247 mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
249 MonoException *exc;
250 MonoException *exc_to_throw;
251 MonoMethod *method = NULL;
252 MonoClass *klass;
253 gchar *full_name;
255 MONO_ARCH_SAVE_REGS;
257 if (vtable->initialized)
258 return NULL;
260 exc = NULL;
261 klass = vtable->klass;
263 if (!klass->image->checked_module_cctor) {
264 mono_image_check_for_module_cctor (klass->image);
265 if (klass->image->has_module_cctor) {
266 MonoClass *module_klass = mono_class_get (klass->image, MONO_TOKEN_TYPE_DEF | 1);
267 MonoVTable *module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception);
268 if (!module_vtable)
269 return NULL;
270 mono_runtime_class_init (module_vtable);
273 method = mono_class_get_cctor (klass);
275 if (method) {
276 MonoDomain *domain = vtable->domain;
277 TypeInitializationLock *lock;
278 guint32 tid = GetCurrentThreadId();
279 int do_initialization = 0;
280 MonoDomain *last_domain = NULL;
282 mono_type_initialization_lock ();
283 /* double check... */
284 if (vtable->initialized) {
285 mono_type_initialization_unlock ();
286 return NULL;
288 if (vtable->init_failed) {
289 mono_type_initialization_unlock ();
291 /* The type initialization already failed once, rethrow the same exception */
292 if (raise_exception)
293 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
294 return get_type_init_exception_for_vtable (vtable);
296 lock = g_hash_table_lookup (type_initialization_hash, vtable);
297 if (lock == NULL) {
298 /* This thread will get to do the initialization */
299 if (mono_domain_get () != domain) {
300 /* Transfer into the target domain */
301 last_domain = mono_domain_get ();
302 if (!mono_domain_set (domain, FALSE)) {
303 vtable->initialized = 1;
304 mono_type_initialization_unlock ();
305 if (raise_exception)
306 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
307 return mono_get_exception_appdomain_unloaded ();
310 lock = g_malloc (sizeof(TypeInitializationLock));
311 InitializeCriticalSection (&lock->initialization_section);
312 lock->initializing_tid = tid;
313 lock->waiting_count = 1;
314 lock->done = FALSE;
315 /* grab the vtable lock while this thread still owns type_initialization_section */
316 EnterCriticalSection (&lock->initialization_section);
317 g_hash_table_insert (type_initialization_hash, vtable, lock);
318 do_initialization = 1;
319 } else {
320 gpointer blocked;
321 TypeInitializationLock *pending_lock;
323 if (lock->initializing_tid == tid || lock->done) {
324 mono_type_initialization_unlock ();
325 return NULL;
327 /* see if the thread doing the initialization is already blocked on this thread */
328 blocked = GUINT_TO_POINTER (lock->initializing_tid);
329 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
330 if (pending_lock->initializing_tid == tid) {
331 if (!pending_lock->done) {
332 mono_type_initialization_unlock ();
333 return NULL;
334 } else {
335 /* the thread doing the initialization is blocked on this thread,
336 but on a lock that has already been freed. It just hasn't got
337 time to awake */
338 break;
341 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
343 ++lock->waiting_count;
344 /* record the fact that we are waiting on the initializing thread */
345 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
347 mono_type_initialization_unlock ();
349 if (do_initialization) {
350 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
352 /* If the initialization failed, mark the class as unusable. */
353 /* Avoid infinite loops */
354 if (!(exc == NULL ||
355 (klass->image == mono_defaults.corlib &&
356 !strcmp (klass->name_space, "System") &&
357 !strcmp (klass->name, "TypeInitializationException")))) {
358 vtable->init_failed = 1;
360 if (klass->name_space && *klass->name_space)
361 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
362 else
363 full_name = g_strdup (klass->name);
364 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
365 g_free (full_name);
368 * Store the exception object so it could be thrown on subsequent
369 * accesses.
371 mono_domain_lock (domain);
372 if (!domain->type_init_exception_hash)
373 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC);
374 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
375 mono_domain_unlock (domain);
378 if (last_domain)
379 mono_domain_set (last_domain, TRUE);
380 lock->done = TRUE;
381 LeaveCriticalSection (&lock->initialization_section);
382 } else {
383 /* this just blocks until the initializing thread is done */
384 EnterCriticalSection (&lock->initialization_section);
385 LeaveCriticalSection (&lock->initialization_section);
388 mono_type_initialization_lock ();
389 if (lock->initializing_tid != tid)
390 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
391 --lock->waiting_count;
392 if (lock->waiting_count == 0) {
393 DeleteCriticalSection (&lock->initialization_section);
394 g_hash_table_remove (type_initialization_hash, vtable);
395 g_free (lock);
397 if (!vtable->init_failed)
398 vtable->initialized = 1;
399 mono_type_initialization_unlock ();
401 if (vtable->init_failed) {
402 /* Either we were the initializing thread or we waited for the initialization */
403 if (raise_exception)
404 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
405 return get_type_init_exception_for_vtable (vtable);
407 } else {
408 vtable->initialized = 1;
409 return NULL;
411 return NULL;
414 static
415 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
417 MonoVTable *vtable = (MonoVTable*)key;
419 TypeInitializationLock *lock = (TypeInitializationLock*) value;
420 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
421 lock->done = TRUE;
423 * Have to set this since it cannot be set by the normal code in
424 * mono_runtime_class_init (). In this case, the exception object is not stored,
425 * and get_type_init_exception_for_class () needs to be aware of this.
427 vtable->init_failed = 1;
428 LeaveCriticalSection (&lock->initialization_section);
429 --lock->waiting_count;
430 if (lock->waiting_count == 0) {
431 DeleteCriticalSection (&lock->initialization_section);
432 g_free (lock);
433 return TRUE;
436 return FALSE;
439 void
440 mono_release_type_locks (MonoInternalThread *thread)
442 mono_type_initialization_lock ();
443 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
444 mono_type_initialization_unlock ();
447 static gpointer
448 default_trampoline (MonoMethod *method)
450 return method;
453 static gpointer
454 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
456 g_assert_not_reached ();
458 return NULL;
461 static gpointer
462 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
464 g_error ("remoting not installed");
465 return NULL;
468 static gpointer
469 default_delegate_trampoline (MonoClass *klass)
471 g_assert_not_reached ();
472 return NULL;
475 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
476 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
477 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
478 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
479 static MonoImtThunkBuilder imt_thunk_builder = NULL;
480 #define ARCH_USE_IMT (imt_thunk_builder != NULL)
481 #if (MONO_IMT_SIZE > 32)
482 #error "MONO_IMT_SIZE cannot be larger than 32"
483 #endif
485 void
486 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
488 memcpy (&callbacks, cbs, sizeof (*cbs));
491 MonoRuntimeCallbacks*
492 mono_get_runtime_callbacks (void)
494 return &callbacks;
497 void
498 mono_install_trampoline (MonoTrampoline func)
500 arch_create_jit_trampoline = func? func: default_trampoline;
503 void
504 mono_install_jump_trampoline (MonoJumpTrampoline func)
506 arch_create_jump_trampoline = func? func: default_jump_trampoline;
509 void
510 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
512 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
515 void
516 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
518 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
521 void
522 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
523 imt_thunk_builder = func;
526 static MonoCompileFunc default_mono_compile_method = NULL;
529 * mono_install_compile_method:
530 * @func: function to install
532 * This is a VM internal routine
534 void
535 mono_install_compile_method (MonoCompileFunc func)
537 default_mono_compile_method = func;
541 * mono_compile_method:
542 * @method: The method to compile.
544 * This JIT-compiles the method, and returns the pointer to the native code
545 * produced.
547 gpointer
548 mono_compile_method (MonoMethod *method)
550 if (!default_mono_compile_method) {
551 g_error ("compile method called on uninitialized runtime");
552 return NULL;
554 return default_mono_compile_method (method);
557 gpointer
558 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
560 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
563 gpointer
564 mono_runtime_create_delegate_trampoline (MonoClass *klass)
566 return arch_create_delegate_trampoline (klass);
569 static MonoFreeMethodFunc default_mono_free_method = NULL;
572 * mono_install_free_method:
573 * @func: pointer to the MonoFreeMethodFunc used to release a method
575 * This is an internal VM routine, it is used for the engines to
576 * register a handler to release the resources associated with a method.
578 * Methods are freed when no more references to the delegate that holds
579 * them are left.
581 void
582 mono_install_free_method (MonoFreeMethodFunc func)
584 default_mono_free_method = func;
588 * mono_runtime_free_method:
589 * @domain; domain where the method is hosted
590 * @method: method to release
592 * This routine is invoked to free the resources associated with
593 * a method that has been JIT compiled. This is used to discard
594 * methods that were used only temporarily (for example, used in marshalling)
597 void
598 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
600 if (default_mono_free_method != NULL)
601 default_mono_free_method (domain, method);
603 mono_method_clear_object (domain, method);
605 mono_free_method (method);
609 * The vtables in the root appdomain are assumed to be reachable by other
610 * roots, and we don't use typed allocation in the other domains.
613 /* The sync block is no longer a GC pointer */
614 #define GC_HEADER_BITMAP (0)
616 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
618 static gsize*
619 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
621 MonoClassField *field;
622 MonoClass *p;
623 guint32 pos;
624 int max_size;
626 if (static_fields)
627 max_size = mono_class_data_size (class) / sizeof (gpointer);
628 else
629 max_size = class->instance_size / sizeof (gpointer);
630 if (max_size > size) {
631 g_assert (offset <= 0);
632 bitmap = g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
633 size = max_size;
636 #ifdef HAVE_SGEN_GC
637 /*An Ephemeron cannot be marked by sgen*/
638 if (!static_fields && class->image == mono_defaults.corlib && !strcmp ("Ephemeron", class->name)) {
639 *max_set = 0;
640 memset (bitmap, 0, size / 8);
641 return bitmap;
643 #endif
645 for (p = class; p != NULL; p = p->parent) {
646 gpointer iter = NULL;
647 while ((field = mono_class_get_fields (p, &iter))) {
648 MonoType *type;
650 if (static_fields) {
651 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
652 continue;
653 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
654 continue;
655 } else {
656 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
657 continue;
659 /* FIXME: should not happen, flag as type load error */
660 if (field->type->byref)
661 break;
663 if (static_fields && field->offset == -1)
664 /* special static */
665 continue;
667 pos = field->offset / sizeof (gpointer);
668 pos += offset;
670 type = mono_type_get_underlying_type (field->type);
671 switch (type->type) {
672 case MONO_TYPE_I:
673 case MONO_TYPE_PTR:
674 case MONO_TYPE_FNPTR:
675 break;
676 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
677 case MONO_TYPE_U:
678 #ifdef HAVE_SGEN_GC
679 break;
680 #else
681 if (class->image != mono_defaults.corlib)
682 break;
683 #endif
684 case MONO_TYPE_STRING:
685 case MONO_TYPE_SZARRAY:
686 case MONO_TYPE_CLASS:
687 case MONO_TYPE_OBJECT:
688 case MONO_TYPE_ARRAY:
689 g_assert ((field->offset % sizeof(gpointer)) == 0);
691 g_assert (pos < size || pos <= max_size);
692 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
693 *max_set = MAX (*max_set, pos);
694 break;
695 case MONO_TYPE_GENERICINST:
696 if (!mono_type_generic_inst_is_valuetype (type)) {
697 g_assert ((field->offset % sizeof(gpointer)) == 0);
699 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
700 *max_set = MAX (*max_set, pos);
701 break;
702 } else {
703 /* fall through */
705 case MONO_TYPE_VALUETYPE: {
706 MonoClass *fclass = mono_class_from_mono_type (field->type);
707 if (fclass->has_references) {
708 /* remove the object header */
709 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
711 break;
713 case MONO_TYPE_I1:
714 case MONO_TYPE_U1:
715 case MONO_TYPE_I2:
716 case MONO_TYPE_U2:
717 case MONO_TYPE_I4:
718 case MONO_TYPE_U4:
719 case MONO_TYPE_I8:
720 case MONO_TYPE_U8:
721 case MONO_TYPE_R4:
722 case MONO_TYPE_R8:
723 case MONO_TYPE_BOOLEAN:
724 case MONO_TYPE_CHAR:
725 break;
726 default:
727 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
728 break;
731 if (static_fields)
732 break;
734 return bitmap;
737 #if 0
739 * similar to the above, but sets the bits in the bitmap for any non-ref field
740 * and ignores static fields
742 static gsize*
743 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
745 MonoClassField *field;
746 MonoClass *p;
747 guint32 pos, pos2;
748 int max_size;
750 max_size = class->instance_size / sizeof (gpointer);
751 if (max_size >= size) {
752 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
755 for (p = class; p != NULL; p = p->parent) {
756 gpointer iter = NULL;
757 while ((field = mono_class_get_fields (p, &iter))) {
758 MonoType *type;
760 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
761 continue;
762 /* FIXME: should not happen, flag as type load error */
763 if (field->type->byref)
764 break;
766 pos = field->offset / sizeof (gpointer);
767 pos += offset;
769 type = mono_type_get_underlying_type (field->type);
770 switch (type->type) {
771 #if SIZEOF_VOID_P == 8
772 case MONO_TYPE_I:
773 case MONO_TYPE_U:
774 case MONO_TYPE_PTR:
775 case MONO_TYPE_FNPTR:
776 #endif
777 case MONO_TYPE_I8:
778 case MONO_TYPE_U8:
779 case MONO_TYPE_R8:
780 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
781 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
782 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
784 /* fall through */
785 #if SIZEOF_VOID_P == 4
786 case MONO_TYPE_I:
787 case MONO_TYPE_U:
788 case MONO_TYPE_PTR:
789 case MONO_TYPE_FNPTR:
790 #endif
791 case MONO_TYPE_I4:
792 case MONO_TYPE_U4:
793 case MONO_TYPE_R4:
794 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
795 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
796 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
798 /* fall through */
799 case MONO_TYPE_CHAR:
800 case MONO_TYPE_I2:
801 case MONO_TYPE_U2:
802 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
803 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
804 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
806 /* fall through */
807 case MONO_TYPE_BOOLEAN:
808 case MONO_TYPE_I1:
809 case MONO_TYPE_U1:
810 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
811 break;
812 case MONO_TYPE_STRING:
813 case MONO_TYPE_SZARRAY:
814 case MONO_TYPE_CLASS:
815 case MONO_TYPE_OBJECT:
816 case MONO_TYPE_ARRAY:
817 break;
818 case MONO_TYPE_GENERICINST:
819 if (!mono_type_generic_inst_is_valuetype (type)) {
820 break;
821 } else {
822 /* fall through */
824 case MONO_TYPE_VALUETYPE: {
825 MonoClass *fclass = mono_class_from_mono_type (field->type);
826 /* remove the object header */
827 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
828 break;
830 default:
831 g_assert_not_reached ();
832 break;
836 return bitmap;
840 * mono_class_insecure_overlapping:
841 * check if a class with explicit layout has references and non-references
842 * fields overlapping.
844 * Returns: TRUE if it is insecure to load the type.
846 gboolean
847 mono_class_insecure_overlapping (MonoClass *klass)
849 int max_set = 0;
850 gsize *bitmap;
851 gsize default_bitmap [4] = {0};
852 gsize *nrbitmap;
853 gsize default_nrbitmap [4] = {0};
854 int i, insecure = FALSE;
855 return FALSE;
857 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
858 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
860 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
861 int idx = i % (sizeof (bitmap [0]) * 8);
862 if (bitmap [idx] & nrbitmap [idx]) {
863 insecure = TRUE;
864 break;
867 if (bitmap != default_bitmap)
868 g_free (bitmap);
869 if (nrbitmap != default_nrbitmap)
870 g_free (nrbitmap);
871 if (insecure) {
872 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
873 return FALSE;
875 return insecure;
877 #endif
879 MonoString*
880 mono_string_alloc (int length)
882 return mono_string_new_size (mono_domain_get (), length);
885 void
886 mono_class_compute_gc_descriptor (MonoClass *class)
888 int max_set = 0;
889 gsize *bitmap;
890 gsize default_bitmap [4] = {0};
891 static gboolean gcj_inited = FALSE;
893 if (!gcj_inited) {
894 mono_loader_lock ();
896 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
897 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
898 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
899 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
901 #ifdef HAVE_GC_GCJ_MALLOC
903 * This is not needed unless the relevant code in mono_get_allocation_ftn () is
904 * turned on.
906 #if 0
907 #ifdef GC_REDIRECT_TO_LOCAL
908 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
909 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
910 #endif
911 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
912 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
913 #endif
915 #endif
916 gcj_inited = TRUE;
917 mono_loader_unlock ();
920 if (!class->inited)
921 mono_class_init (class);
923 if (class->gc_descr_inited)
924 return;
926 class->gc_descr_inited = TRUE;
927 class->gc_descr = GC_NO_DESCRIPTOR;
929 bitmap = default_bitmap;
930 if (class == mono_defaults.string_class) {
931 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
932 } else if (class->rank) {
933 mono_class_compute_gc_descriptor (class->element_class);
934 if (!class->element_class->valuetype) {
935 gsize abm = 1;
936 class->gc_descr = mono_gc_make_descr_for_array (TRUE, &abm, 1, sizeof (gpointer));
937 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
938 class->name_space, class->name);*/
939 } else {
940 /* remove the object header */
941 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
942 class->gc_descr = mono_gc_make_descr_for_array (TRUE, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
943 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
944 class->name_space, class->name);*/
945 if (bitmap != default_bitmap)
946 g_free (bitmap);
948 } else {
949 /*static int count = 0;
950 if (count++ > 58)
951 return;*/
952 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
953 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
955 if (class->gc_descr == GC_NO_DESCRIPTOR)
956 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
958 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
959 if (bitmap != default_bitmap)
960 g_free (bitmap);
965 * field_is_special_static:
966 * @fklass: The MonoClass to look up.
967 * @field: The MonoClassField describing the field.
969 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
970 * SPECIAL_STATIC_NONE otherwise.
972 static gint32
973 field_is_special_static (MonoClass *fklass, MonoClassField *field)
975 MonoCustomAttrInfo *ainfo;
976 int i;
977 ainfo = mono_custom_attrs_from_field (fklass, field);
978 if (!ainfo)
979 return FALSE;
980 for (i = 0; i < ainfo->num_attrs; ++i) {
981 MonoClass *klass = ainfo->attrs [i].ctor->klass;
982 if (klass->image == mono_defaults.corlib) {
983 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
984 mono_custom_attrs_free (ainfo);
985 return SPECIAL_STATIC_THREAD;
987 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
988 mono_custom_attrs_free (ainfo);
989 return SPECIAL_STATIC_CONTEXT;
993 mono_custom_attrs_free (ainfo);
994 return SPECIAL_STATIC_NONE;
997 static gpointer imt_trampoline = NULL;
999 void
1000 mono_install_imt_trampoline (gpointer tramp_code)
1002 imt_trampoline = tramp_code;
1005 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1006 #define mix(a,b,c) { \
1007 a -= c; a ^= rot(c, 4); c += b; \
1008 b -= a; b ^= rot(a, 6); a += c; \
1009 c -= b; c ^= rot(b, 8); b += a; \
1010 a -= c; a ^= rot(c,16); c += b; \
1011 b -= a; b ^= rot(a,19); a += c; \
1012 c -= b; c ^= rot(b, 4); b += a; \
1014 #define final(a,b,c) { \
1015 c ^= b; c -= rot(b,14); \
1016 a ^= c; a -= rot(c,11); \
1017 b ^= a; b -= rot(a,25); \
1018 c ^= b; c -= rot(b,16); \
1019 a ^= c; a -= rot(c,4); \
1020 b ^= a; b -= rot(a,14); \
1021 c ^= b; c -= rot(b,24); \
1025 * mono_method_get_imt_slot:
1027 * The IMT slot is embedded into AOTed code, so this must return the same value
1028 * for the same method across all executions. This means:
1029 * - pointers shouldn't be used as hash values.
1030 * - mono_metadata_str_hash () should be used for hashing strings.
1032 guint32
1033 mono_method_get_imt_slot (MonoMethod *method)
1035 MonoMethodSignature *sig;
1036 int hashes_count;
1037 guint32 *hashes_start, *hashes;
1038 guint32 a, b, c;
1039 int i;
1041 /* This can be used to stress tests the collision code */
1042 //return 0;
1045 * We do this to simplify generic sharing. It will hurt
1046 * performance in cases where a class implements two different
1047 * instantiations of the same generic interface.
1048 * The code in build_imt_slots () depends on this.
1050 if (method->is_inflated)
1051 method = ((MonoMethodInflated*)method)->declaring;
1053 sig = mono_method_signature (method);
1054 hashes_count = sig->param_count + 4;
1055 hashes_start = malloc (hashes_count * sizeof (guint32));
1056 hashes = hashes_start;
1058 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1059 printf ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod\n",
1060 method->klass->name_space, method->klass->name, method->name);
1061 g_assert_not_reached ();
1064 /* Initialize hashes */
1065 hashes [0] = mono_metadata_str_hash (method->klass->name);
1066 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1067 hashes [2] = mono_metadata_str_hash (method->name);
1068 hashes [3] = mono_metadata_type_hash (sig->ret);
1069 for (i = 0; i < sig->param_count; i++) {
1070 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1073 /* Setup internal state */
1074 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1076 /* Handle most of the hashes */
1077 while (hashes_count > 3) {
1078 a += hashes [0];
1079 b += hashes [1];
1080 c += hashes [2];
1081 mix (a,b,c);
1082 hashes_count -= 3;
1083 hashes += 3;
1086 /* Handle the last 3 hashes (all the case statements fall through) */
1087 switch (hashes_count) {
1088 case 3 : c += hashes [2];
1089 case 2 : b += hashes [1];
1090 case 1 : a += hashes [0];
1091 final (a,b,c);
1092 case 0: /* nothing left to add */
1093 break;
1096 free (hashes_start);
1097 /* Report the result */
1098 return c % MONO_IMT_SIZE;
1100 #undef rot
1101 #undef mix
1102 #undef final
1104 #define DEBUG_IMT 0
1106 static void
1107 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1108 guint32 imt_slot = mono_method_get_imt_slot (method);
1109 MonoImtBuilderEntry *entry;
1111 if (slot_num >= 0 && imt_slot != slot_num) {
1112 /* we build just a single imt slot and this is not it */
1113 return;
1116 entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
1117 entry->key = method;
1118 entry->value.vtable_slot = vtable_slot;
1119 entry->next = imt_builder [imt_slot];
1120 if (imt_builder [imt_slot] != NULL) {
1121 entry->children = imt_builder [imt_slot]->children + 1;
1122 if (entry->children == 1) {
1123 mono_stats.imt_slots_with_collisions++;
1124 *imt_collisions_bitmap |= (1 << imt_slot);
1126 } else {
1127 entry->children = 0;
1128 mono_stats.imt_used_slots++;
1130 imt_builder [imt_slot] = entry;
1131 #if DEBUG_IMT
1133 char *method_name = mono_method_full_name (method, TRUE);
1134 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1135 method, method_name, imt_slot, vtable_slot, entry->children);
1136 g_free (method_name);
1138 #endif
1141 #if DEBUG_IMT
1142 static void
1143 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1144 if (e != NULL) {
1145 MonoMethod *method = e->key;
1146 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1147 message,
1148 num,
1149 method,
1150 method->klass->name_space,
1151 method->klass->name,
1152 method->name);
1153 } else {
1154 printf (" * %s: NULL\n", message);
1157 #endif
1159 static int
1160 compare_imt_builder_entries (const void *p1, const void *p2) {
1161 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1162 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1164 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1167 static int
1168 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1170 int count = end - start;
1171 int chunk_start = out_array->len;
1172 if (count < 4) {
1173 int i;
1174 for (i = start; i < end; ++i) {
1175 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1176 item->key = sorted_array [i]->key;
1177 item->value = sorted_array [i]->value;
1178 item->has_target_code = sorted_array [i]->has_target_code;
1179 item->is_equals = TRUE;
1180 if (i < end - 1)
1181 item->check_target_idx = out_array->len + 1;
1182 else
1183 item->check_target_idx = 0;
1184 g_ptr_array_add (out_array, item);
1186 } else {
1187 int middle = start + count / 2;
1188 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1190 item->key = sorted_array [middle]->key;
1191 item->is_equals = FALSE;
1192 g_ptr_array_add (out_array, item);
1193 imt_emit_ir (sorted_array, start, middle, out_array);
1194 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1196 return chunk_start;
1199 static GPtrArray*
1200 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1201 int number_of_entries = entries->children + 1;
1202 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1203 GPtrArray *result = g_ptr_array_new ();
1204 MonoImtBuilderEntry *current_entry;
1205 int i;
1207 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1208 sorted_array [i] = current_entry;
1210 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1212 /*for (i = 0; i < number_of_entries; i++) {
1213 print_imt_entry (" sorted array:", sorted_array [i], i);
1216 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1218 free (sorted_array);
1219 return result;
1222 static gpointer
1223 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1225 if (imt_builder_entry != NULL) {
1226 if (imt_builder_entry->children == 0 && !fail_tramp) {
1227 /* No collision, return the vtable slot contents */
1228 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1229 } else {
1230 /* Collision, build the thunk */
1231 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1232 gpointer result;
1233 int i;
1234 result = imt_thunk_builder (vtable, domain,
1235 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1236 for (i = 0; i < imt_ir->len; ++i)
1237 g_free (g_ptr_array_index (imt_ir, i));
1238 g_ptr_array_free (imt_ir, TRUE);
1239 return result;
1241 } else {
1242 if (fail_tramp)
1243 return fail_tramp;
1244 else
1245 /* Empty slot */
1246 return NULL;
1250 static MonoImtBuilderEntry*
1251 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1254 * LOCKING: requires the loader and domain locks.
1257 static void
1258 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1260 int i;
1261 GSList *list_item;
1262 guint32 imt_collisions_bitmap = 0;
1263 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1264 int method_count = 0;
1265 gboolean record_method_count_for_max_collisions = FALSE;
1266 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1268 #if DEBUG_IMT
1269 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1270 #endif
1271 for (i = 0; i < klass->interface_offsets_count; ++i) {
1272 MonoClass *iface = klass->interfaces_packed [i];
1273 int interface_offset = klass->interface_offsets_packed [i];
1274 int method_slot_in_interface, vt_slot;
1276 if (mono_class_has_variant_generic_params (iface))
1277 has_variant_iface = TRUE;
1279 vt_slot = interface_offset;
1280 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1281 MonoMethod *method;
1283 if (slot_num >= 0 && iface->is_inflated) {
1285 * The imt slot of the method is the same as for its declaring method,
1286 * see the comment in mono_method_get_imt_slot (), so we can
1287 * avoid inflating methods which will be discarded by
1288 * add_imt_builder_entry anyway.
1290 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1291 if (mono_method_get_imt_slot (method) != slot_num) {
1292 vt_slot ++;
1293 continue;
1296 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1297 if (method->is_generic) {
1298 has_generic_virtual = TRUE;
1299 vt_slot ++;
1300 continue;
1303 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1304 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1305 vt_slot ++;
1309 if (extra_interfaces) {
1310 int interface_offset = klass->vtable_size;
1312 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1313 MonoClass* iface = list_item->data;
1314 int method_slot_in_interface;
1315 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1316 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1317 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1319 interface_offset += iface->method.count;
1322 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1323 /* overwrite the imt slot only if we're building all the entries or if
1324 * we're building this specific one
1326 if (slot_num < 0 || i == slot_num) {
1327 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1329 if (entries) {
1330 if (imt_builder [i]) {
1331 MonoImtBuilderEntry *entry;
1333 /* Link entries with imt_builder [i] */
1334 for (entry = entries; entry->next; entry = entry->next) {
1335 #if DEBUG_IMT
1336 MonoMethod *method = (MonoMethod*)entry->key;
1337 char *method_name = mono_method_full_name (method, TRUE);
1338 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1339 g_free (method_name);
1340 #endif
1342 entry->next = imt_builder [i];
1343 entries->children += imt_builder [i]->children + 1;
1345 imt_builder [i] = entries;
1348 if (has_generic_virtual || has_variant_iface) {
1350 * There might be collisions later when the the thunk is expanded.
1352 imt_collisions_bitmap |= (1 << i);
1355 * The IMT thunk might be called with an instance of one of the
1356 * generic virtual methods, so has to fallback to the IMT trampoline.
1358 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], imt_trampoline);
1359 } else {
1360 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1362 #if DEBUG_IMT
1363 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1364 #endif
1367 if (imt_builder [i] != NULL) {
1368 int methods_in_slot = imt_builder [i]->children + 1;
1369 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1370 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1371 record_method_count_for_max_collisions = TRUE;
1373 method_count += methods_in_slot;
1377 mono_stats.imt_number_of_methods += method_count;
1378 if (record_method_count_for_max_collisions) {
1379 mono_stats.imt_method_count_when_max_collisions = method_count;
1382 for (i = 0; i < MONO_IMT_SIZE; i++) {
1383 MonoImtBuilderEntry* entry = imt_builder [i];
1384 while (entry != NULL) {
1385 MonoImtBuilderEntry* next = entry->next;
1386 g_free (entry);
1387 entry = next;
1390 free (imt_builder);
1391 /* we OR the bitmap since we may build just a single imt slot at a time */
1392 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1395 static void
1396 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1397 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1401 * mono_vtable_build_imt_slot:
1402 * @vtable: virtual object table struct
1403 * @imt_slot: slot in the IMT table
1405 * Fill the given @imt_slot in the IMT table of @vtable with
1406 * a trampoline or a thunk for the case of collisions.
1407 * This is part of the internal mono API.
1409 * LOCKING: Take the domain lock.
1411 void
1412 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1414 gpointer *imt = (gpointer*)vtable;
1415 imt -= MONO_IMT_SIZE;
1416 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1418 /* no support for extra interfaces: the proxy objects will need
1419 * to build the complete IMT
1420 * Update and heck needs to ahppen inside the proper domain lock, as all
1421 * the changes made to a MonoVTable.
1423 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1424 mono_domain_lock (vtable->domain);
1425 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1426 if (imt [imt_slot] == imt_trampoline)
1427 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1428 mono_domain_unlock (vtable->domain);
1429 mono_loader_unlock ();
1434 * The first two free list entries both belong to the wait list: The
1435 * first entry is the pointer to the head of the list and the second
1436 * entry points to the last element. That way appending and removing
1437 * the first element are both O(1) operations.
1439 #ifdef MONO_SMALL_CONFIG
1440 #define NUM_FREE_LISTS 6
1441 #else
1442 #define NUM_FREE_LISTS 12
1443 #endif
1444 #define FIRST_FREE_LIST_SIZE 64
1445 #define MAX_WAIT_LENGTH 50
1446 #define THUNK_THRESHOLD 10
1449 * LOCKING: The domain lock must be held.
1451 static void
1452 init_thunk_free_lists (MonoDomain *domain)
1454 if (domain->thunk_free_lists)
1455 return;
1456 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1459 static int
1460 list_index_for_size (int item_size)
1462 int i = 2;
1463 int size = FIRST_FREE_LIST_SIZE;
1465 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1466 i++;
1467 size <<= 1;
1470 return i;
1474 * mono_method_alloc_generic_virtual_thunk:
1475 * @domain: a domain
1476 * @size: size in bytes
1478 * Allocs size bytes to be used for the code of a generic virtual
1479 * thunk. It's either allocated from the domain's code manager or
1480 * reused from a previously invalidated piece.
1482 * LOCKING: The domain lock must be held.
1484 gpointer
1485 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1487 static gboolean inited = FALSE;
1488 static int generic_virtual_thunks_size = 0;
1490 guint32 *p;
1491 int i;
1492 MonoThunkFreeList **l;
1494 init_thunk_free_lists (domain);
1496 size += sizeof (guint32);
1497 if (size < sizeof (MonoThunkFreeList))
1498 size = sizeof (MonoThunkFreeList);
1500 i = list_index_for_size (size);
1501 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1502 if ((*l)->size >= size) {
1503 MonoThunkFreeList *item = *l;
1504 *l = item->next;
1505 return ((guint32*)item) + 1;
1509 /* no suitable item found - search lists of larger sizes */
1510 while (++i < NUM_FREE_LISTS) {
1511 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1512 if (!item)
1513 continue;
1514 g_assert (item->size > size);
1515 domain->thunk_free_lists [i] = item->next;
1516 return ((guint32*)item) + 1;
1519 /* still nothing found - allocate it */
1520 if (!inited) {
1521 mono_counters_register ("Generic virtual thunk bytes",
1522 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1523 inited = TRUE;
1525 generic_virtual_thunks_size += size;
1527 p = mono_domain_code_reserve (domain, size);
1528 *p = size;
1530 return p + 1;
1534 * LOCKING: The domain lock must be held.
1536 static void
1537 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1539 guint32 *p = code;
1540 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1542 init_thunk_free_lists (domain);
1544 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1545 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1546 int length = item->length;
1547 int i;
1549 /* unlink the first item from the wait list */
1550 domain->thunk_free_lists [0] = item->next;
1551 domain->thunk_free_lists [0]->length = length - 1;
1553 i = list_index_for_size (item->size);
1555 /* put it in the free list */
1556 item->next = domain->thunk_free_lists [i];
1557 domain->thunk_free_lists [i] = item;
1560 l->next = NULL;
1561 if (domain->thunk_free_lists [1]) {
1562 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1563 domain->thunk_free_lists [0]->length++;
1564 } else {
1565 g_assert (!domain->thunk_free_lists [0]);
1567 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1568 domain->thunk_free_lists [0]->length = 1;
1572 typedef struct _GenericVirtualCase {
1573 MonoMethod *method;
1574 gpointer code;
1575 int count;
1576 struct _GenericVirtualCase *next;
1577 } GenericVirtualCase;
1580 * get_generic_virtual_entries:
1582 * Return IMT entries for the generic virtual method instances and
1583 * variant interface methods for vtable slot
1584 * VTABLE_SLOT.
1586 static MonoImtBuilderEntry*
1587 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1589 GenericVirtualCase *list;
1590 MonoImtBuilderEntry *entries;
1592 mono_domain_lock (domain);
1593 if (!domain->generic_virtual_cases)
1594 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1596 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1598 entries = NULL;
1599 for (; list; list = list->next) {
1600 MonoImtBuilderEntry *entry;
1602 if (list->count < THUNK_THRESHOLD)
1603 continue;
1605 entry = g_new0 (MonoImtBuilderEntry, 1);
1606 entry->key = list->method;
1607 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1608 entry->has_target_code = 1;
1609 if (entries)
1610 entry->children = entries->children + 1;
1611 entry->next = entries;
1612 entries = entry;
1615 mono_domain_unlock (domain);
1617 /* FIXME: Leaking memory ? */
1618 return entries;
1622 * mono_method_add_generic_virtual_invocation:
1623 * @domain: a domain
1624 * @vtable_slot: pointer to the vtable slot
1625 * @method: the inflated generic virtual method
1626 * @code: the method's code
1628 * Registers a call via unmanaged code to a generic virtual method
1629 * instantiation or variant interface method. If the number of calls reaches a threshold
1630 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1631 * virtual method thunk.
1633 void
1634 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1635 gpointer *vtable_slot,
1636 MonoMethod *method, gpointer code)
1638 static gboolean inited = FALSE;
1639 static int num_added = 0;
1641 GenericVirtualCase *gvc, *list;
1642 MonoImtBuilderEntry *entries;
1643 int i;
1644 GPtrArray *sorted;
1646 mono_domain_lock (domain);
1647 if (!domain->generic_virtual_cases)
1648 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1650 /* Check whether the case was already added */
1651 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1652 gvc = list;
1653 while (gvc) {
1654 if (gvc->method == method)
1655 break;
1656 gvc = gvc->next;
1659 /* If not found, make a new one */
1660 if (!gvc) {
1661 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1662 gvc->method = method;
1663 gvc->code = code;
1664 gvc->count = 0;
1665 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1667 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1669 if (!inited) {
1670 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1671 inited = TRUE;
1673 num_added++;
1676 if (++gvc->count == THUNK_THRESHOLD) {
1677 gpointer *old_thunk = *vtable_slot;
1678 gpointer vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline ((gpointer*)vtable_slot - (gpointer*)vtable) : NULL;
1680 if ((gpointer)vtable_slot < (gpointer)vtable)
1681 /* Force the rebuild of the thunk at the next call */
1682 *vtable_slot = imt_trampoline;
1683 else {
1684 entries = get_generic_virtual_entries (domain, vtable_slot);
1686 sorted = imt_sort_slot_entries (entries);
1688 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1689 vtable_trampoline);
1691 while (entries) {
1692 MonoImtBuilderEntry *next = entries->next;
1693 g_free (entries);
1694 entries = next;
1697 for (i = 0; i < sorted->len; ++i)
1698 g_free (g_ptr_array_index (sorted, i));
1699 g_ptr_array_free (sorted, TRUE);
1702 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1703 invalidate_generic_virtual_thunk (domain, old_thunk);
1706 mono_domain_unlock (domain);
1709 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error);
1712 * mono_class_vtable:
1713 * @domain: the application domain
1714 * @class: the class to initialize
1716 * VTables are domain specific because we create domain specific code, and
1717 * they contain the domain specific static class data.
1718 * On failure, NULL is returned, and class->exception_type is set.
1720 MonoVTable *
1721 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1723 return mono_class_vtable_full (domain, class, FALSE);
1727 * mono_class_vtable_full:
1728 * @domain: the application domain
1729 * @class: the class to initialize
1730 * @raise_on_error if an exception should be raised on failure or not
1732 * VTables are domain specific because we create domain specific code, and
1733 * they contain the domain specific static class data.
1735 MonoVTable *
1736 mono_class_vtable_full (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1738 MonoClassRuntimeInfo *runtime_info;
1740 g_assert (class);
1742 if (class->exception_type) {
1743 if (raise_on_error)
1744 mono_raise_exception (mono_class_get_exception_for_failure (class));
1745 return NULL;
1748 /* this check can be inlined in jitted code, too */
1749 runtime_info = class->runtime_info;
1750 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1751 return runtime_info->domain_vtables [domain->domain_id];
1752 return mono_class_create_runtime_vtable (domain, class, raise_on_error);
1756 * mono_class_try_get_vtable:
1757 * @domain: the application domain
1758 * @class: the class to initialize
1760 * This function tries to get the associated vtable from @class if
1761 * it was already created.
1763 MonoVTable *
1764 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1766 MonoClassRuntimeInfo *runtime_info;
1768 g_assert (class);
1770 runtime_info = class->runtime_info;
1771 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1772 return runtime_info->domain_vtables [domain->domain_id];
1773 return NULL;
1776 static MonoVTable *
1777 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1779 MonoVTable *vt;
1780 MonoClassRuntimeInfo *runtime_info, *old_info;
1781 MonoClassField *field;
1782 char *t;
1783 int i;
1784 int imt_table_bytes = 0;
1785 guint32 vtable_size, class_size;
1786 guint32 cindex;
1787 gpointer iter;
1788 gpointer *interface_offsets;
1790 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1791 mono_domain_lock (domain);
1792 runtime_info = class->runtime_info;
1793 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1794 mono_domain_unlock (domain);
1795 mono_loader_unlock ();
1796 return runtime_info->domain_vtables [domain->domain_id];
1798 if (!class->inited || class->exception_type) {
1799 if (!mono_class_init (class) || class->exception_type) {
1800 mono_domain_unlock (domain);
1801 mono_loader_unlock ();
1802 if (raise_on_error)
1803 mono_raise_exception (mono_class_get_exception_for_failure (class));
1804 return NULL;
1808 /* Array types require that their element type be valid*/
1809 if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
1810 MonoClass *element_class = class->element_class;
1811 if (!element_class->inited)
1812 mono_class_init (element_class);
1814 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1815 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1816 mono_class_setup_vtable (element_class);
1818 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1819 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1820 if (class->exception_type == MONO_EXCEPTION_NONE)
1821 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1822 mono_domain_unlock (domain);
1823 mono_loader_unlock ();
1824 if (raise_on_error)
1825 mono_raise_exception (mono_class_get_exception_for_failure (class));
1826 return NULL;
1831 * For some classes, mono_class_init () already computed class->vtable_size, and
1832 * that is all that is needed because of the vtable trampolines.
1834 if (!class->vtable_size)
1835 mono_class_setup_vtable (class);
1837 if (class->exception_type) {
1838 mono_domain_unlock (domain);
1839 mono_loader_unlock ();
1840 if (raise_on_error)
1841 mono_raise_exception (mono_class_get_exception_for_failure (class));
1842 return NULL;
1845 if (ARCH_USE_IMT) {
1846 vtable_size = MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1847 if (class->interface_offsets_count) {
1848 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1849 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1850 mono_stats.imt_number_of_tables++;
1851 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1853 } else {
1854 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1855 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1858 mono_stats.used_class_count++;
1859 mono_stats.class_vtable_size += vtable_size;
1860 interface_offsets = mono_domain_alloc0 (domain, vtable_size);
1862 if (ARCH_USE_IMT)
1863 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1864 else
1865 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1866 vt->klass = class;
1867 vt->rank = class->rank;
1868 vt->domain = domain;
1870 mono_class_compute_gc_descriptor (class);
1872 * We can't use typed allocation in the non-root domains, since the
1873 * collector needs the GC descriptor stored in the vtable even after
1874 * the mempool containing the vtable is destroyed when the domain is
1875 * unloaded. An alternative might be to allocate vtables in the GC
1876 * heap, but this does not seem to work (it leads to crashes inside
1877 * libgc). If that approach is tried, two gc descriptors need to be
1878 * allocated for each class: one for the root domain, and one for all
1879 * other domains. The second descriptor should contain a bit for the
1880 * vtable field in MonoObject, since we can no longer assume the
1881 * vtable is reachable by other roots after the appdomain is unloaded.
1883 #ifdef HAVE_BOEHM_GC
1884 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1885 vt->gc_descr = GC_NO_DESCRIPTOR;
1886 else
1887 #endif
1888 vt->gc_descr = class->gc_descr;
1890 if ((class_size = mono_class_data_size (class))) {
1891 if (class->has_static_refs) {
1892 gpointer statics_gc_descr;
1893 int max_set = 0;
1894 gsize default_bitmap [4] = {0};
1895 gsize *bitmap;
1897 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1898 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1899 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1900 vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1901 mono_domain_add_class_static_data (domain, class, vt->data, NULL);
1902 if (bitmap != default_bitmap)
1903 g_free (bitmap);
1904 } else {
1905 vt->data = mono_domain_alloc0 (domain, class_size);
1907 mono_stats.class_static_data_size += class_size;
1910 cindex = -1;
1911 iter = NULL;
1912 while ((field = mono_class_get_fields (class, &iter))) {
1913 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1914 continue;
1915 if (mono_field_is_deleted (field))
1916 continue;
1917 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1918 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1919 if (special_static != SPECIAL_STATIC_NONE) {
1920 guint32 size, offset;
1921 gint32 align;
1922 gsize default_bitmap [4] = {0};
1923 gsize *bitmap;
1924 int max_set = 0;
1925 MonoClass *fclass;
1926 if (mono_type_is_reference (field->type)) {
1927 default_bitmap [0] = 1;
1928 max_set = 1;
1929 bitmap = default_bitmap;
1930 } else if (mono_type_is_struct (field->type)) {
1931 fclass = mono_class_from_mono_type (field->type);
1932 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1933 } else {
1934 default_bitmap [0] = 0;
1935 max_set = 0;
1936 bitmap = default_bitmap;
1938 size = mono_type_size (field->type, &align);
1939 offset = mono_alloc_special_static_data (special_static, size, align, bitmap, max_set);
1940 if (!domain->special_static_fields)
1941 domain->special_static_fields = g_hash_table_new (NULL, NULL);
1942 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
1943 if (bitmap != default_bitmap)
1944 g_free (bitmap);
1946 * This marks the field as special static to speed up the
1947 * checks in mono_field_static_get/set_value ().
1949 field->offset = -1;
1950 continue;
1953 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
1954 MonoClass *fklass = mono_class_from_mono_type (field->type);
1955 const char *data = mono_field_get_data (field);
1957 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
1958 t = (char*)vt->data + field->offset;
1959 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
1960 if (!data)
1961 continue;
1962 if (fklass->valuetype) {
1963 memcpy (t, data, mono_class_value_size (fklass, NULL));
1964 } else {
1965 /* it's a pointer type: add check */
1966 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
1967 *t = *(char *)data;
1969 continue;
1973 vt->max_interface_id = class->max_interface_id;
1974 vt->interface_bitmap = class->interface_bitmap;
1976 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
1977 // class->name, class->interface_offsets_count);
1979 if (! ARCH_USE_IMT) {
1980 /* initialize interface offsets */
1981 for (i = 0; i < class->interface_offsets_count; ++i) {
1982 int interface_id = class->interfaces_packed [i]->interface_id;
1983 int slot = class->interface_offsets_packed [i];
1984 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
1988 /* class_vtable_array keeps an array of created vtables
1990 g_ptr_array_add (domain->class_vtable_array, vt);
1991 /* class->runtime_info is protected by the loader lock, both when
1992 * it it enlarged and when it is stored info.
1995 old_info = class->runtime_info;
1996 if (old_info && old_info->max_domain >= domain->domain_id) {
1997 /* someone already created a large enough runtime info */
1998 mono_memory_barrier ();
1999 old_info->domain_vtables [domain->domain_id] = vt;
2000 } else {
2001 int new_size = domain->domain_id;
2002 if (old_info)
2003 new_size = MAX (new_size, old_info->max_domain);
2004 new_size++;
2005 /* make the new size a power of two */
2006 i = 2;
2007 while (new_size > i)
2008 i <<= 1;
2009 new_size = i;
2010 /* this is a bounded memory retention issue: may want to
2011 * handle it differently when we'll have a rcu-like system.
2013 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2014 runtime_info->max_domain = new_size - 1;
2015 /* copy the stuff from the older info */
2016 if (old_info) {
2017 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2019 runtime_info->domain_vtables [domain->domain_id] = vt;
2020 /* keep this last*/
2021 mono_memory_barrier ();
2022 class->runtime_info = runtime_info;
2025 /* Initialize vtable */
2026 if (callbacks.get_vtable_trampoline) {
2027 // This also covers the AOT case
2028 for (i = 0; i < class->vtable_size; ++i) {
2029 vt->vtable [i] = callbacks.get_vtable_trampoline (i);
2031 } else {
2032 mono_class_setup_vtable (class);
2034 for (i = 0; i < class->vtable_size; ++i) {
2035 MonoMethod *cm;
2037 if ((cm = class->vtable [i]))
2038 vt->vtable [i] = arch_create_jit_trampoline (cm);
2042 if (ARCH_USE_IMT && imt_table_bytes) {
2043 /* Now that the vtable is full, we can actually fill up the IMT */
2044 if (imt_trampoline) {
2045 /* lazy construction of the IMT entries enabled */
2046 for (i = 0; i < MONO_IMT_SIZE; ++i)
2047 interface_offsets [i] = imt_trampoline;
2048 } else {
2049 build_imt (class, vt, domain, interface_offsets, NULL);
2053 mono_domain_unlock (domain);
2054 mono_loader_unlock ();
2056 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
2057 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
2058 mono_raise_exception (mono_class_get_exception_for_failure (class));
2060 /* make sure the parent is initialized */
2061 /*FIXME shouldn't this fail the current type?*/
2062 if (class->parent)
2063 mono_class_vtable_full (domain, class->parent, raise_on_error);
2065 /*FIXME check for OOM*/
2066 vt->type = mono_type_get_object (domain, &class->byval_arg);
2067 #if HAVE_SGEN_GC
2068 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class) {
2069 static void *type_desc = NULL;
2071 if (!type_desc) {
2072 gsize bmap = 1;
2073 type_desc = mono_gc_make_descr_from_bitmap (&bmap, 1);
2076 /* This is unregistered in
2077 unregister_vtable_reflection_type() in
2078 domain.c. */
2079 mono_gc_register_root ((char*)&vt->type, sizeof (gpointer), type_desc);
2081 #endif
2082 if (class->contextbound)
2083 vt->remote = 1;
2084 else
2085 vt->remote = 0;
2087 return vt;
2091 * mono_class_proxy_vtable:
2092 * @domain: the application domain
2093 * @remove_class: the remote class
2095 * Creates a vtable for transparent proxies. It is basically
2096 * a copy of the real vtable of the class wrapped in @remote_class,
2097 * but all function pointers invoke the remoting functions, and
2098 * vtable->klass points to the transparent proxy class, and not to @class.
2100 static MonoVTable *
2101 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2103 MonoError error;
2104 MonoVTable *vt, *pvt;
2105 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2106 MonoClass *k;
2107 GSList *extra_interfaces = NULL;
2108 MonoClass *class = remote_class->proxy_class;
2109 gpointer *interface_offsets;
2110 uint8_t *bitmap;
2111 int bsize;
2113 #ifdef COMPRESSED_INTERFACE_BITMAP
2114 int bcsize;
2115 #endif
2117 vt = mono_class_vtable (domain, class);
2118 g_assert (vt); /*FIXME property handle failure*/
2119 max_interface_id = vt->max_interface_id;
2121 /* Calculate vtable space for extra interfaces */
2122 for (j = 0; j < remote_class->interface_count; j++) {
2123 MonoClass* iclass = remote_class->interfaces[j];
2124 GPtrArray *ifaces;
2125 int method_count;
2127 /*FIXME test for interfaces with variant generic arguments*/
2128 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2129 continue; /* interface implemented by the class */
2130 if (g_slist_find (extra_interfaces, iclass))
2131 continue;
2133 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2135 method_count = mono_class_num_methods (iclass);
2137 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2138 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2139 if (ifaces) {
2140 for (i = 0; i < ifaces->len; ++i) {
2141 MonoClass *ic = g_ptr_array_index (ifaces, i);
2142 /*FIXME test for interfaces with variant generic arguments*/
2143 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2144 continue; /* interface implemented by the class */
2145 if (g_slist_find (extra_interfaces, ic))
2146 continue;
2147 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2148 method_count += mono_class_num_methods (ic);
2150 g_ptr_array_free (ifaces, TRUE);
2153 extra_interface_vtsize += method_count * sizeof (gpointer);
2154 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2157 if (ARCH_USE_IMT) {
2158 mono_stats.imt_number_of_tables++;
2159 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
2160 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
2161 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2162 } else {
2163 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
2164 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2167 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2169 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
2170 if (ARCH_USE_IMT)
2171 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
2172 else
2173 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
2174 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2176 pvt->klass = mono_defaults.transparent_proxy_class;
2177 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2178 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2180 /* initialize vtable */
2181 mono_class_setup_vtable (class);
2182 for (i = 0; i < class->vtable_size; ++i) {
2183 MonoMethod *cm;
2185 if ((cm = class->vtable [i]))
2186 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2187 else
2188 pvt->vtable [i] = NULL;
2191 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2192 /* create trampolines for abstract methods */
2193 for (k = class; k; k = k->parent) {
2194 MonoMethod* m;
2195 gpointer iter = NULL;
2196 while ((m = mono_class_get_methods (k, &iter)))
2197 if (!pvt->vtable [m->slot])
2198 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2202 pvt->max_interface_id = max_interface_id;
2203 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2204 #ifdef COMPRESSED_INTERFACE_BITMAP
2205 bitmap = g_malloc0 (bsize);
2206 #else
2207 bitmap = mono_domain_alloc0 (domain, bsize);
2208 #endif
2210 if (! ARCH_USE_IMT) {
2211 /* initialize interface offsets */
2212 for (i = 0; i < class->interface_offsets_count; ++i) {
2213 int interface_id = class->interfaces_packed [i]->interface_id;
2214 int slot = class->interface_offsets_packed [i];
2215 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2218 for (i = 0; i < class->interface_offsets_count; ++i) {
2219 int interface_id = class->interfaces_packed [i]->interface_id;
2220 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2223 if (extra_interfaces) {
2224 int slot = class->vtable_size;
2225 MonoClass* interf;
2226 gpointer iter;
2227 MonoMethod* cm;
2228 GSList *list_item;
2230 /* Create trampolines for the methods of the interfaces */
2231 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2232 interf = list_item->data;
2234 if (! ARCH_USE_IMT) {
2235 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2237 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2239 iter = NULL;
2240 j = 0;
2241 while ((cm = mono_class_get_methods (interf, &iter)))
2242 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2244 slot += mono_class_num_methods (interf);
2246 if (! ARCH_USE_IMT) {
2247 g_slist_free (extra_interfaces);
2251 if (ARCH_USE_IMT) {
2252 /* Now that the vtable is full, we can actually fill up the IMT */
2253 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2254 if (extra_interfaces) {
2255 g_slist_free (extra_interfaces);
2259 #ifdef COMPRESSED_INTERFACE_BITMAP
2260 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2261 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2262 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2263 g_free (bitmap);
2264 #else
2265 pvt->interface_bitmap = bitmap;
2266 #endif
2267 return pvt;
2271 * mono_class_field_is_special_static:
2273 * Returns whether @field is a thread/context static field.
2275 gboolean
2276 mono_class_field_is_special_static (MonoClassField *field)
2278 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2279 return FALSE;
2280 if (mono_field_is_deleted (field))
2281 return FALSE;
2282 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2283 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2284 return TRUE;
2286 return FALSE;
2290 * mono_class_has_special_static_fields:
2292 * Returns whenever @klass has any thread/context static fields.
2294 gboolean
2295 mono_class_has_special_static_fields (MonoClass *klass)
2297 MonoClassField *field;
2298 gpointer iter;
2300 iter = NULL;
2301 while ((field = mono_class_get_fields (klass, &iter))) {
2302 g_assert (field->parent == klass);
2303 if (mono_class_field_is_special_static (field))
2304 return TRUE;
2307 return FALSE;
2311 * create_remote_class_key:
2312 * Creates an array of pointers that can be used as a hash key for a remote class.
2313 * The first element of the array is the number of pointers.
2315 static gpointer*
2316 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2318 gpointer *key;
2319 int i, j;
2321 if (remote_class == NULL) {
2322 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2323 key = g_malloc (sizeof(gpointer) * 3);
2324 key [0] = GINT_TO_POINTER (2);
2325 key [1] = mono_defaults.marshalbyrefobject_class;
2326 key [2] = extra_class;
2327 } else {
2328 key = g_malloc (sizeof(gpointer) * 2);
2329 key [0] = GINT_TO_POINTER (1);
2330 key [1] = extra_class;
2332 } else {
2333 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2334 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2335 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2336 key [1] = remote_class->proxy_class;
2338 // Keep the list of interfaces sorted
2339 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2340 if (extra_class && remote_class->interfaces [i] > extra_class) {
2341 key [j++] = extra_class;
2342 extra_class = NULL;
2344 key [j] = remote_class->interfaces [i];
2346 if (extra_class)
2347 key [j] = extra_class;
2348 } else {
2349 // Replace the old class. The interface list is the same
2350 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2351 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2352 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2353 for (i = 0; i < remote_class->interface_count; i++)
2354 key [2 + i] = remote_class->interfaces [i];
2358 return key;
2362 * copy_remote_class_key:
2364 * Make a copy of KEY in the domain and return the copy.
2366 static gpointer*
2367 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2369 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2370 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2372 memcpy (mp_key, key, key_size);
2374 return mp_key;
2378 * mono_remote_class:
2379 * @domain: the application domain
2380 * @class_name: name of the remote class
2382 * Creates and initializes a MonoRemoteClass object for a remote type.
2384 * Can raise an exception on failure.
2386 MonoRemoteClass*
2387 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2389 MonoError error;
2390 MonoRemoteClass *rc;
2391 gpointer* key, *mp_key;
2392 char *name;
2394 key = create_remote_class_key (NULL, proxy_class);
2396 mono_domain_lock (domain);
2397 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2399 if (rc) {
2400 g_free (key);
2401 mono_domain_unlock (domain);
2402 return rc;
2405 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2406 if (!mono_error_ok (&error)) {
2407 g_free (key);
2408 mono_domain_unlock (domain);
2409 mono_error_raise_exception (&error);
2412 mp_key = copy_remote_class_key (domain, key);
2413 g_free (key);
2414 key = mp_key;
2416 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2417 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2418 rc->interface_count = 1;
2419 rc->interfaces [0] = proxy_class;
2420 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2421 } else {
2422 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2423 rc->interface_count = 0;
2424 rc->proxy_class = proxy_class;
2427 rc->default_vtable = NULL;
2428 rc->xdomain_vtable = NULL;
2429 rc->proxy_class_name = name;
2430 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2432 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2434 mono_domain_unlock (domain);
2435 return rc;
2439 * clone_remote_class:
2440 * Creates a copy of the remote_class, adding the provided class or interface
2442 static MonoRemoteClass*
2443 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2445 MonoRemoteClass *rc;
2446 gpointer* key, *mp_key;
2448 key = create_remote_class_key (remote_class, extra_class);
2449 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2450 if (rc != NULL) {
2451 g_free (key);
2452 return rc;
2455 mp_key = copy_remote_class_key (domain, key);
2456 g_free (key);
2457 key = mp_key;
2459 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2460 int i,j;
2461 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2462 rc->proxy_class = remote_class->proxy_class;
2463 rc->interface_count = remote_class->interface_count + 1;
2465 // Keep the list of interfaces sorted, since the hash key of
2466 // the remote class depends on this
2467 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2468 if (remote_class->interfaces [i] > extra_class && i == j)
2469 rc->interfaces [j++] = extra_class;
2470 rc->interfaces [j] = remote_class->interfaces [i];
2472 if (i == j)
2473 rc->interfaces [j] = extra_class;
2474 } else {
2475 // Replace the old class. The interface array is the same
2476 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2477 rc->proxy_class = extra_class;
2478 rc->interface_count = remote_class->interface_count;
2479 if (rc->interface_count > 0)
2480 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2483 rc->default_vtable = NULL;
2484 rc->xdomain_vtable = NULL;
2485 rc->proxy_class_name = remote_class->proxy_class_name;
2487 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2489 return rc;
2492 gpointer
2493 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2495 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2496 mono_domain_lock (domain);
2497 if (rp->target_domain_id != -1) {
2498 if (remote_class->xdomain_vtable == NULL)
2499 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2500 mono_domain_unlock (domain);
2501 mono_loader_unlock ();
2502 return remote_class->xdomain_vtable;
2504 if (remote_class->default_vtable == NULL) {
2505 MonoType *type;
2506 MonoClass *klass;
2507 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2508 klass = mono_class_from_mono_type (type);
2509 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
2510 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2511 else
2512 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2515 mono_domain_unlock (domain);
2516 mono_loader_unlock ();
2517 return remote_class->default_vtable;
2521 * mono_upgrade_remote_class:
2522 * @domain: the application domain
2523 * @tproxy: the proxy whose remote class has to be upgraded.
2524 * @klass: class to which the remote class can be casted.
2526 * Updates the vtable of the remote class by adding the necessary method slots
2527 * and interface offsets so it can be safely casted to klass. klass can be a
2528 * class or an interface.
2530 void
2531 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2533 MonoTransparentProxy *tproxy;
2534 MonoRemoteClass *remote_class;
2535 gboolean redo_vtable;
2537 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2538 mono_domain_lock (domain);
2540 tproxy = (MonoTransparentProxy*) proxy_object;
2541 remote_class = tproxy->remote_class;
2543 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2544 int i;
2545 redo_vtable = TRUE;
2546 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2547 if (remote_class->interfaces [i] == klass)
2548 redo_vtable = FALSE;
2550 else {
2551 redo_vtable = (remote_class->proxy_class != klass);
2554 if (redo_vtable) {
2555 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2556 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2559 mono_domain_unlock (domain);
2560 mono_loader_unlock ();
2565 * mono_object_get_virtual_method:
2566 * @obj: object to operate on.
2567 * @method: method
2569 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2570 * the instance of a callvirt of method.
2572 MonoMethod*
2573 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2575 MonoClass *klass;
2576 MonoMethod **vtable;
2577 gboolean is_proxy;
2578 MonoMethod *res = NULL;
2580 klass = mono_object_class (obj);
2581 if (klass == mono_defaults.transparent_proxy_class) {
2582 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2583 is_proxy = TRUE;
2584 } else {
2585 is_proxy = FALSE;
2588 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2589 return method;
2591 mono_class_setup_vtable (klass);
2592 vtable = klass->vtable;
2594 if (method->slot == -1) {
2595 /* method->slot might not be set for instances of generic methods */
2596 if (method->is_inflated) {
2597 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2598 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2599 } else {
2600 if (!is_proxy)
2601 g_assert_not_reached ();
2605 /* check method->slot is a valid index: perform isinstance? */
2606 if (method->slot != -1) {
2607 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2608 if (!is_proxy) {
2609 gboolean variance_used = FALSE;
2610 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2611 g_assert (iface_offset > 0);
2612 res = vtable [iface_offset + method->slot];
2614 } else {
2615 res = vtable [method->slot];
2619 if (is_proxy) {
2620 /* It may be an interface, abstract class method or generic method */
2621 if (!res || mono_method_signature (res)->generic_param_count)
2622 res = method;
2624 /* generic methods demand invoke_with_check */
2625 if (mono_method_signature (res)->generic_param_count)
2626 res = mono_marshal_get_remoting_invoke_with_check (res);
2627 else {
2628 #ifndef DISABLE_COM
2629 if (klass == mono_defaults.com_object_class || klass->is_com_object)
2630 res = mono_cominterop_get_invoke (res);
2631 else
2632 #endif
2633 res = mono_marshal_get_remoting_invoke (res);
2635 } else {
2636 if (method->is_inflated) {
2637 /* Have to inflate the result */
2638 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2642 g_assert (res);
2644 return res;
2647 static MonoObject*
2648 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2650 g_error ("runtime invoke called on uninitialized runtime");
2651 return NULL;
2654 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2657 * mono_runtime_invoke:
2658 * @method: method to invoke
2659 * @obJ: object instance
2660 * @params: arguments to the method
2661 * @exc: exception information.
2663 * Invokes the method represented by @method on the object @obj.
2665 * obj is the 'this' pointer, it should be NULL for static
2666 * methods, a MonoObject* for object instances and a pointer to
2667 * the value type for value types.
2669 * The params array contains the arguments to the method with the
2670 * same convention: MonoObject* pointers for object instances and
2671 * pointers to the value type otherwise.
2673 * From unmanaged code you'll usually use the
2674 * mono_runtime_invoke() variant.
2676 * Note that this function doesn't handle virtual methods for
2677 * you, it will exec the exact method you pass: we still need to
2678 * expose a function to lookup the derived class implementation
2679 * of a virtual method (there are examples of this in the code,
2680 * though).
2682 * You can pass NULL as the exc argument if you don't want to
2683 * catch exceptions, otherwise, *exc will be set to the exception
2684 * thrown, if any. if an exception is thrown, you can't use the
2685 * MonoObject* result from the function.
2687 * If the method returns a value type, it is boxed in an object
2688 * reference.
2690 MonoObject*
2691 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2693 MonoObject *result;
2695 if (mono_runtime_get_no_exec ())
2696 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2698 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2699 mono_profiler_method_start_invoke (method);
2701 result = default_mono_runtime_invoke (method, obj, params, exc);
2703 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2704 mono_profiler_method_end_invoke (method);
2706 return result;
2710 * mono_method_get_unmanaged_thunk:
2711 * @method: method to generate a thunk for.
2713 * Returns an unmanaged->managed thunk that can be used to call
2714 * a managed method directly from C.
2716 * The thunk's C signature closely matches the managed signature:
2718 * C#: public bool Equals (object obj);
2719 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2720 * MonoObject*, MonoException**);
2722 * The 1st ("this") parameter must not be used with static methods:
2724 * C#: public static bool ReferenceEquals (object a, object b);
2725 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2726 * MonoException**);
2728 * The last argument must be a non-null pointer of a MonoException* pointer.
2729 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2730 * exception has been thrown in managed code. Otherwise it will point
2731 * to the MonoException* caught by the thunk. In this case, the result of
2732 * the thunk is undefined:
2734 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2735 * MonoException *ex = NULL;
2736 * Equals func = mono_method_get_unmanaged_thunk (method);
2737 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2738 * if (ex) {
2739 * // handle exception
2742 * The calling convention of the thunk matches the platform's default
2743 * convention. This means that under Windows, C declarations must
2744 * contain the __stdcall attribute:
2746 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2747 * MonoObject*, MonoException**);
2749 * LIMITATIONS
2751 * Value type arguments and return values are treated as they were objects:
2753 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2754 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2756 * Arguments must be properly boxed upon trunk's invocation, while return
2757 * values must be unboxed.
2759 gpointer
2760 mono_method_get_unmanaged_thunk (MonoMethod *method)
2762 method = mono_marshal_get_thunk_invoke_wrapper (method);
2763 return mono_compile_method (method);
2766 static void
2767 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2769 int t;
2770 if (type->byref) {
2771 /* object fields cannot be byref, so we don't need a
2772 wbarrier here */
2773 gpointer *p = (gpointer*)dest;
2774 *p = value;
2775 return;
2777 t = type->type;
2778 handle_enum:
2779 switch (t) {
2780 case MONO_TYPE_BOOLEAN:
2781 case MONO_TYPE_I1:
2782 case MONO_TYPE_U1: {
2783 guint8 *p = (guint8*)dest;
2784 *p = value ? *(guint8*)value : 0;
2785 return;
2787 case MONO_TYPE_I2:
2788 case MONO_TYPE_U2:
2789 case MONO_TYPE_CHAR: {
2790 guint16 *p = (guint16*)dest;
2791 *p = value ? *(guint16*)value : 0;
2792 return;
2794 #if SIZEOF_VOID_P == 4
2795 case MONO_TYPE_I:
2796 case MONO_TYPE_U:
2797 #endif
2798 case MONO_TYPE_I4:
2799 case MONO_TYPE_U4: {
2800 gint32 *p = (gint32*)dest;
2801 *p = value ? *(gint32*)value : 0;
2802 return;
2804 #if SIZEOF_VOID_P == 8
2805 case MONO_TYPE_I:
2806 case MONO_TYPE_U:
2807 #endif
2808 case MONO_TYPE_I8:
2809 case MONO_TYPE_U8: {
2810 gint64 *p = (gint64*)dest;
2811 *p = value ? *(gint64*)value : 0;
2812 return;
2814 case MONO_TYPE_R4: {
2815 float *p = (float*)dest;
2816 *p = value ? *(float*)value : 0;
2817 return;
2819 case MONO_TYPE_R8: {
2820 double *p = (double*)dest;
2821 *p = value ? *(double*)value : 0;
2822 return;
2824 case MONO_TYPE_STRING:
2825 case MONO_TYPE_SZARRAY:
2826 case MONO_TYPE_CLASS:
2827 case MONO_TYPE_OBJECT:
2828 case MONO_TYPE_ARRAY:
2829 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2830 return;
2831 case MONO_TYPE_FNPTR:
2832 case MONO_TYPE_PTR: {
2833 gpointer *p = (gpointer*)dest;
2834 *p = deref_pointer? *(gpointer*)value: value;
2835 return;
2837 case MONO_TYPE_VALUETYPE:
2838 /* note that 't' and 'type->type' can be different */
2839 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2840 t = mono_class_enum_basetype (type->data.klass)->type;
2841 goto handle_enum;
2842 } else {
2843 MonoClass *class = mono_class_from_mono_type (type);
2844 int size = mono_class_value_size (class, NULL);
2845 if (value == NULL)
2846 memset (dest, 0, size);
2847 else
2848 mono_gc_wbarrier_value_copy (dest, value, 1, class);
2850 return;
2851 case MONO_TYPE_GENERICINST:
2852 t = type->data.generic_class->container_class->byval_arg.type;
2853 goto handle_enum;
2854 default:
2855 g_warning ("got type %x", type->type);
2856 g_assert_not_reached ();
2861 * mono_field_set_value:
2862 * @obj: Instance object
2863 * @field: MonoClassField describing the field to set
2864 * @value: The value to be set
2866 * Sets the value of the field described by @field in the object instance @obj
2867 * to the value passed in @value. This method should only be used for instance
2868 * fields. For static fields, use mono_field_static_set_value.
2870 * The value must be on the native format of the field type.
2872 void
2873 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2875 void *dest;
2877 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2879 dest = (char*)obj + field->offset;
2880 set_value (field->type, dest, value, FALSE);
2884 * mono_field_static_set_value:
2885 * @field: MonoClassField describing the field to set
2886 * @value: The value to be set
2888 * Sets the value of the static field described by @field
2889 * to the value passed in @value.
2891 * The value must be on the native format of the field type.
2893 void
2894 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2896 void *dest;
2898 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2899 /* you cant set a constant! */
2900 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2902 if (field->offset == -1) {
2903 /* Special static */
2904 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2905 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2906 } else {
2907 dest = (char*)vt->data + field->offset;
2909 set_value (field->type, dest, value, FALSE);
2912 /* Used by the debugger */
2913 void *
2914 mono_vtable_get_static_field_data (MonoVTable *vt)
2916 return vt->data;
2919 static guint8*
2920 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
2922 guint8 *src;
2924 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2925 if (field->offset == -1) {
2926 /* Special static */
2927 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2928 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2929 } else {
2930 src = (guint8*)vt->data + field->offset;
2932 } else {
2933 src = (guint8*)obj + field->offset;
2936 return src;
2940 * mono_field_get_value:
2941 * @obj: Object instance
2942 * @field: MonoClassField describing the field to fetch information from
2943 * @value: pointer to the location where the value will be stored
2945 * Use this routine to get the value of the field @field in the object
2946 * passed.
2948 * The pointer provided by value must be of the field type, for reference
2949 * types this is a MonoObject*, for value types its the actual pointer to
2950 * the value type.
2952 * For example:
2953 * int i;
2954 * mono_field_get_value (obj, int_field, &i);
2956 void
2957 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
2959 void *src;
2961 g_assert (obj);
2963 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2965 src = (char*)obj + field->offset;
2966 set_value (field->type, value, src, TRUE);
2970 * mono_field_get_value_object:
2971 * @domain: domain where the object will be created (if boxing)
2972 * @field: MonoClassField describing the field to fetch information from
2973 * @obj: The object instance for the field.
2975 * Returns: a new MonoObject with the value from the given field. If the
2976 * field represents a value type, the value is boxed.
2979 MonoObject *
2980 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
2982 MonoObject *o;
2983 MonoClass *klass;
2984 MonoVTable *vtable = NULL;
2985 gchar *v;
2986 gboolean is_static = FALSE;
2987 gboolean is_ref = FALSE;
2988 gboolean is_literal = FALSE;
2990 switch (field->type->type) {
2991 case MONO_TYPE_STRING:
2992 case MONO_TYPE_OBJECT:
2993 case MONO_TYPE_CLASS:
2994 case MONO_TYPE_ARRAY:
2995 case MONO_TYPE_SZARRAY:
2996 is_ref = TRUE;
2997 break;
2998 case MONO_TYPE_U1:
2999 case MONO_TYPE_I1:
3000 case MONO_TYPE_BOOLEAN:
3001 case MONO_TYPE_U2:
3002 case MONO_TYPE_I2:
3003 case MONO_TYPE_CHAR:
3004 case MONO_TYPE_U:
3005 case MONO_TYPE_I:
3006 case MONO_TYPE_U4:
3007 case MONO_TYPE_I4:
3008 case MONO_TYPE_R4:
3009 case MONO_TYPE_U8:
3010 case MONO_TYPE_I8:
3011 case MONO_TYPE_R8:
3012 case MONO_TYPE_VALUETYPE:
3013 is_ref = field->type->byref;
3014 break;
3015 case MONO_TYPE_GENERICINST:
3016 is_ref = !mono_type_generic_inst_is_valuetype (field->type);
3017 break;
3018 default:
3019 g_error ("type 0x%x not handled in "
3020 "mono_field_get_value_object", field->type->type);
3021 return NULL;
3024 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
3025 is_literal = TRUE;
3027 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3028 is_static = TRUE;
3030 if (!is_literal) {
3031 vtable = mono_class_vtable (domain, field->parent);
3032 if (!vtable) {
3033 char *name = mono_type_get_full_name (field->parent);
3034 /*FIXME extend this to use the MonoError api*/
3035 g_warning ("Could not retrieve the vtable for type %s in mono_field_get_value_object", name);
3036 g_free (name);
3037 return NULL;
3039 if (!vtable->initialized)
3040 mono_runtime_class_init (vtable);
3042 } else {
3043 g_assert (obj);
3046 if (is_ref) {
3047 if (is_literal) {
3048 get_default_field_value (domain, field, &o);
3049 } else if (is_static) {
3050 mono_field_static_get_value (vtable, field, &o);
3051 } else {
3052 mono_field_get_value (obj, field, &o);
3054 return o;
3057 /* boxed value type */
3058 klass = mono_class_from_mono_type (field->type);
3060 if (mono_class_is_nullable (klass))
3061 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3063 o = mono_object_new (domain, klass);
3064 v = ((gchar *) o) + sizeof (MonoObject);
3066 if (is_literal) {
3067 get_default_field_value (domain, field, v);
3068 } else if (is_static) {
3069 mono_field_static_get_value (vtable, field, v);
3070 } else {
3071 mono_field_get_value (obj, field, v);
3074 return o;
3078 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3080 int retval = 0;
3081 const char *p = blob;
3082 mono_metadata_decode_blob_size (p, &p);
3084 switch (type) {
3085 case MONO_TYPE_BOOLEAN:
3086 case MONO_TYPE_U1:
3087 case MONO_TYPE_I1:
3088 *(guint8 *) value = *p;
3089 break;
3090 case MONO_TYPE_CHAR:
3091 case MONO_TYPE_U2:
3092 case MONO_TYPE_I2:
3093 *(guint16*) value = read16 (p);
3094 break;
3095 case MONO_TYPE_U4:
3096 case MONO_TYPE_I4:
3097 *(guint32*) value = read32 (p);
3098 break;
3099 case MONO_TYPE_U8:
3100 case MONO_TYPE_I8:
3101 *(guint64*) value = read64 (p);
3102 break;
3103 case MONO_TYPE_R4:
3104 readr4 (p, (float*) value);
3105 break;
3106 case MONO_TYPE_R8:
3107 readr8 (p, (double*) value);
3108 break;
3109 case MONO_TYPE_STRING:
3110 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3111 break;
3112 case MONO_TYPE_CLASS:
3113 *(gpointer*) value = NULL;
3114 break;
3115 default:
3116 retval = -1;
3117 g_warning ("type 0x%02x should not be in constant table", type);
3119 return retval;
3122 static void
3123 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3125 MonoTypeEnum def_type;
3126 const char* data;
3128 data = mono_class_get_field_default_value (field, &def_type);
3129 mono_get_constant_value_from_blob (domain, def_type, data, value);
3133 * mono_field_static_get_value:
3134 * @vt: vtable to the object
3135 * @field: MonoClassField describing the field to fetch information from
3136 * @value: where the value is returned
3138 * Use this routine to get the value of the static field @field value.
3140 * The pointer provided by value must be of the field type, for reference
3141 * types this is a MonoObject*, for value types its the actual pointer to
3142 * the value type.
3144 * For example:
3145 * int i;
3146 * mono_field_static_get_value (vt, int_field, &i);
3148 void
3149 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3151 void *src;
3153 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3155 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3156 get_default_field_value (vt->domain, field, value);
3157 return;
3160 if (field->offset == -1) {
3161 /* Special static */
3162 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3163 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3164 } else {
3165 src = (char*)vt->data + field->offset;
3167 set_value (field->type, value, src, TRUE);
3171 * mono_property_set_value:
3172 * @prop: MonoProperty to set
3173 * @obj: instance object on which to act
3174 * @params: parameters to pass to the propery
3175 * @exc: optional exception
3177 * Invokes the property's set method with the given arguments on the
3178 * object instance obj (or NULL for static properties).
3180 * You can pass NULL as the exc argument if you don't want to
3181 * catch exceptions, otherwise, *exc will be set to the exception
3182 * thrown, if any. if an exception is thrown, you can't use the
3183 * MonoObject* result from the function.
3185 void
3186 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3188 default_mono_runtime_invoke (prop->set, obj, params, exc);
3192 * mono_property_get_value:
3193 * @prop: MonoProperty to fetch
3194 * @obj: instance object on which to act
3195 * @params: parameters to pass to the propery
3196 * @exc: optional exception
3198 * Invokes the property's get method with the given arguments on the
3199 * object instance obj (or NULL for static properties).
3201 * You can pass NULL as the exc argument if you don't want to
3202 * catch exceptions, otherwise, *exc will be set to the exception
3203 * thrown, if any. if an exception is thrown, you can't use the
3204 * MonoObject* result from the function.
3206 * Returns: the value from invoking the get method on the property.
3208 MonoObject*
3209 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3211 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3215 * mono_nullable_init:
3216 * @buf: The nullable structure to initialize.
3217 * @value: the value to initialize from
3218 * @klass: the type for the object
3220 * Initialize the nullable structure pointed to by @buf from @value which
3221 * should be a boxed value type. The size of @buf should be able to hold
3222 * as much data as the @klass->instance_size (which is the number of bytes
3223 * that will be copies).
3225 * Since Nullables have variable structure, we can not define a C
3226 * structure for them.
3228 void
3229 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3231 MonoClass *param_class = klass->cast_class;
3233 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3234 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3236 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3237 if (value) {
3238 if (param_class->has_references)
3239 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3240 else
3241 memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3242 } else {
3243 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
3248 * mono_nullable_box:
3249 * @buf: The buffer representing the data to be boxed
3250 * @klass: the type to box it as.
3252 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3253 * @buf.
3255 MonoObject*
3256 mono_nullable_box (guint8 *buf, MonoClass *klass)
3258 MonoClass *param_class = klass->cast_class;
3260 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3261 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3263 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3264 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3265 if (param_class->has_references)
3266 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3267 else
3268 memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3269 return o;
3271 else
3272 return NULL;
3276 * mono_get_delegate_invoke:
3277 * @klass: The delegate class
3279 * Returns: the MonoMethod for the "Invoke" method in the delegate klass
3281 MonoMethod *
3282 mono_get_delegate_invoke (MonoClass *klass)
3284 MonoMethod *im;
3286 /* This is called at runtime, so avoid the slower search in metadata */
3287 mono_class_setup_methods (klass);
3288 if (klass->exception_type)
3289 return NULL;
3290 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3291 g_assert (im);
3293 return im;
3297 * mono_runtime_delegate_invoke:
3298 * @delegate: pointer to a delegate object.
3299 * @params: parameters for the delegate.
3300 * @exc: Pointer to the exception result.
3302 * Invokes the delegate method @delegate with the parameters provided.
3304 * You can pass NULL as the exc argument if you don't want to
3305 * catch exceptions, otherwise, *exc will be set to the exception
3306 * thrown, if any. if an exception is thrown, you can't use the
3307 * MonoObject* result from the function.
3309 MonoObject*
3310 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3312 MonoMethod *im;
3314 im = mono_get_delegate_invoke (delegate->vtable->klass);
3315 g_assert (im);
3317 return mono_runtime_invoke (im, delegate, params, exc);
3320 static char **main_args = NULL;
3321 static int num_main_args;
3324 * mono_runtime_get_main_args:
3326 * Returns: a MonoArray with the arguments passed to the main program
3328 MonoArray*
3329 mono_runtime_get_main_args (void)
3331 MonoArray *res;
3332 int i;
3333 MonoDomain *domain = mono_domain_get ();
3335 if (!main_args)
3336 return NULL;
3338 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3340 for (i = 0; i < num_main_args; ++i)
3341 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3343 return res;
3346 static void
3347 fire_process_exit_event (void)
3349 MonoClassField *field;
3350 MonoDomain *domain = mono_domain_get ();
3351 gpointer pa [2];
3352 MonoObject *delegate, *exc;
3354 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
3355 g_assert (field);
3357 if (domain != mono_get_root_domain ())
3358 return;
3360 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
3361 if (delegate == NULL)
3362 return;
3364 pa [0] = domain;
3365 pa [1] = NULL;
3366 mono_runtime_delegate_invoke (delegate, pa, &exc);
3370 * mono_runtime_run_main:
3371 * @method: the method to start the application with (usually Main)
3372 * @argc: number of arguments from the command line
3373 * @argv: array of strings from the command line
3374 * @exc: excetption results
3376 * Execute a standard Main() method (argc/argv contains the
3377 * executable name). This method also sets the command line argument value
3378 * needed by System.Environment.
3383 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3384 MonoObject **exc)
3386 int i;
3387 MonoArray *args = NULL;
3388 MonoDomain *domain = mono_domain_get ();
3389 gchar *utf8_fullpath;
3390 int result;
3392 g_assert (method != NULL);
3394 mono_thread_set_main (mono_thread_current ());
3396 main_args = g_new0 (char*, argc);
3397 num_main_args = argc;
3399 if (!g_path_is_absolute (argv [0])) {
3400 gchar *basename = g_path_get_basename (argv [0]);
3401 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3402 basename,
3403 NULL);
3405 utf8_fullpath = mono_utf8_from_external (fullpath);
3406 if(utf8_fullpath == NULL) {
3407 /* Printing the arg text will cause glib to
3408 * whinge about "Invalid UTF-8", but at least
3409 * its relevant, and shows the problem text
3410 * string.
3412 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3413 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3414 exit (-1);
3417 g_free (fullpath);
3418 g_free (basename);
3419 } else {
3420 utf8_fullpath = mono_utf8_from_external (argv[0]);
3421 if(utf8_fullpath == NULL) {
3422 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3423 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3424 exit (-1);
3428 main_args [0] = utf8_fullpath;
3430 for (i = 1; i < argc; ++i) {
3431 gchar *utf8_arg;
3433 utf8_arg=mono_utf8_from_external (argv[i]);
3434 if(utf8_arg==NULL) {
3435 /* Ditto the comment about Invalid UTF-8 here */
3436 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3437 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3438 exit (-1);
3441 main_args [i] = utf8_arg;
3443 argc--;
3444 argv++;
3445 if (mono_method_signature (method)->param_count) {
3446 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3447 for (i = 0; i < argc; ++i) {
3448 /* The encodings should all work, given that
3449 * we've checked all these args for the
3450 * main_args array.
3452 gchar *str = mono_utf8_from_external (argv [i]);
3453 MonoString *arg = mono_string_new (domain, str);
3454 mono_array_setref (args, i, arg);
3455 g_free (str);
3457 } else {
3458 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3461 mono_assembly_set_main (method->klass->image->assembly);
3463 result = mono_runtime_exec_main (method, args, exc);
3464 fire_process_exit_event ();
3465 return result;
3468 static MonoObject*
3469 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3471 static MonoMethod *serialize_method;
3473 void *params [1];
3474 MonoObject *array;
3476 if (!serialize_method) {
3477 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3478 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3481 if (!serialize_method) {
3482 *failure = TRUE;
3483 return NULL;
3486 g_assert (!mono_object_class (obj)->marshalbyref);
3488 params [0] = obj;
3489 *exc = NULL;
3490 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3491 if (*exc)
3492 *failure = TRUE;
3494 return array;
3497 static MonoObject*
3498 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3500 static MonoMethod *deserialize_method;
3502 void *params [1];
3503 MonoObject *result;
3505 if (!deserialize_method) {
3506 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3507 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3509 if (!deserialize_method) {
3510 *failure = TRUE;
3511 return NULL;
3514 params [0] = obj;
3515 *exc = NULL;
3516 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3517 if (*exc)
3518 *failure = TRUE;
3520 return result;
3523 static MonoObject*
3524 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3526 static MonoMethod *get_proxy_method;
3528 MonoDomain *domain = mono_domain_get ();
3529 MonoRealProxy *real_proxy;
3530 MonoReflectionType *reflection_type;
3531 MonoTransparentProxy *transparent_proxy;
3533 if (!get_proxy_method)
3534 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3536 g_assert (obj->vtable->klass->marshalbyref);
3538 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3539 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3541 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3542 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3544 *exc = NULL;
3545 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3546 if (*exc)
3547 *failure = TRUE;
3549 return (MonoObject*) transparent_proxy;
3553 * mono_object_xdomain_representation
3554 * @obj: an object
3555 * @target_domain: a domain
3556 * @exc: pointer to a MonoObject*
3558 * Creates a representation of obj in the domain target_domain. This
3559 * is either a copy of obj arrived through via serialization and
3560 * deserialization or a proxy, depending on whether the object is
3561 * serializable or marshal by ref. obj must not be in target_domain.
3563 * If the object cannot be represented in target_domain, NULL is
3564 * returned and *exc is set to an appropriate exception.
3566 MonoObject*
3567 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3569 MonoObject *deserialized = NULL;
3570 gboolean failure = FALSE;
3572 *exc = NULL;
3574 if (mono_object_class (obj)->marshalbyref) {
3575 deserialized = make_transparent_proxy (obj, &failure, exc);
3576 } else {
3577 MonoDomain *domain = mono_domain_get ();
3578 MonoObject *serialized;
3580 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3581 serialized = serialize_object (obj, &failure, exc);
3582 mono_domain_set_internal_with_options (target_domain, FALSE);
3583 if (!failure)
3584 deserialized = deserialize_object (serialized, &failure, exc);
3585 if (domain != target_domain)
3586 mono_domain_set_internal_with_options (domain, FALSE);
3589 return deserialized;
3592 /* Used in call_unhandled_exception_delegate */
3593 static MonoObject *
3594 create_unhandled_exception_eventargs (MonoObject *exc)
3596 MonoClass *klass;
3597 gpointer args [2];
3598 MonoMethod *method = NULL;
3599 MonoBoolean is_terminating = TRUE;
3600 MonoObject *obj;
3602 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3603 g_assert (klass);
3605 mono_class_init (klass);
3607 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3608 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3609 g_assert (method);
3611 args [0] = exc;
3612 args [1] = &is_terminating;
3614 obj = mono_object_new (mono_domain_get (), klass);
3615 mono_runtime_invoke (method, obj, args, NULL);
3617 return obj;
3620 /* Used in mono_unhandled_exception */
3621 static void
3622 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3623 MonoObject *e = NULL;
3624 gpointer pa [2];
3625 MonoDomain *current_domain = mono_domain_get ();
3627 if (domain != current_domain)
3628 mono_domain_set_internal_with_options (domain, FALSE);
3630 g_assert (domain == mono_object_domain (domain->domain));
3632 if (mono_object_domain (exc) != domain) {
3633 MonoObject *serialization_exc;
3635 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
3636 if (!exc) {
3637 if (serialization_exc) {
3638 MonoObject *dummy;
3639 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
3640 g_assert (exc);
3641 } else {
3642 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
3643 "System.Runtime.Serialization", "SerializationException",
3644 "Could not serialize unhandled exception.");
3648 g_assert (mono_object_domain (exc) == domain);
3650 pa [0] = domain->domain;
3651 pa [1] = create_unhandled_exception_eventargs (exc);
3652 mono_runtime_delegate_invoke (delegate, pa, &e);
3654 if (domain != current_domain)
3655 mono_domain_set_internal_with_options (current_domain, FALSE);
3657 if (e) {
3658 MonoError error;
3659 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
3660 if (!mono_error_ok (&error)) {
3661 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
3662 mono_error_cleanup (&error);
3663 } else {
3664 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3665 g_free (msg);
3670 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3673 * mono_runtime_unhandled_exception_policy_set:
3674 * @policy: the new policy
3676 * This is a VM internal routine.
3678 * Sets the runtime policy for handling unhandled exceptions.
3680 void
3681 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3682 runtime_unhandled_exception_policy = policy;
3686 * mono_runtime_unhandled_exception_policy_get:
3688 * This is a VM internal routine.
3690 * Gets the runtime policy for handling unhandled exceptions.
3692 MonoRuntimeUnhandledExceptionPolicy
3693 mono_runtime_unhandled_exception_policy_get (void) {
3694 return runtime_unhandled_exception_policy;
3698 * mono_unhandled_exception:
3699 * @exc: exception thrown
3701 * This is a VM internal routine.
3703 * We call this function when we detect an unhandled exception
3704 * in the default domain.
3706 * It invokes the * UnhandledException event in AppDomain or prints
3707 * a warning to the console
3709 void
3710 mono_unhandled_exception (MonoObject *exc)
3712 MonoDomain *current_domain = mono_domain_get ();
3713 MonoDomain *root_domain = mono_get_root_domain ();
3714 MonoClassField *field;
3715 MonoObject *current_appdomain_delegate;
3716 MonoObject *root_appdomain_delegate;
3718 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3719 "UnhandledException");
3720 g_assert (field);
3722 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3723 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
3724 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3725 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3726 if (current_domain != root_domain) {
3727 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3728 } else {
3729 current_appdomain_delegate = NULL;
3732 /* set exitcode only if we will abort the process */
3733 if (abort_process)
3734 mono_environment_exitcode_set (1);
3735 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3736 mono_print_unhandled_exception (exc);
3737 } else {
3738 if (root_appdomain_delegate) {
3739 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3741 if (current_appdomain_delegate) {
3742 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3749 * mono_runtime_exec_managed_code:
3750 * @domain: Application domain
3751 * @main_func: function to invoke from the execution thread
3752 * @main_args: parameter to the main_func
3754 * Launch a new thread to execute a function
3756 * main_func is called back from the thread with main_args as the
3757 * parameter. The callback function is expected to start Main()
3758 * eventually. This function then waits for all managed threads to
3759 * finish.
3760 * It is not necesseray anymore to execute managed code in a subthread,
3761 * so this function should not be used anymore by default: just
3762 * execute the code and then call mono_thread_manage ().
3764 void
3765 mono_runtime_exec_managed_code (MonoDomain *domain,
3766 MonoMainThreadFunc main_func,
3767 gpointer main_args)
3769 mono_thread_create (domain, main_func, main_args);
3771 mono_thread_manage ();
3775 * Execute a standard Main() method (args doesn't contain the
3776 * executable name).
3779 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3781 MonoDomain *domain;
3782 gpointer pa [1];
3783 int rval;
3784 MonoCustomAttrInfo* cinfo;
3785 gboolean has_stathread_attribute;
3786 MonoInternalThread* thread = mono_thread_internal_current ();
3788 g_assert (args);
3790 pa [0] = args;
3792 domain = mono_object_domain (args);
3793 if (!domain->entry_assembly) {
3794 gchar *str;
3795 MonoAssembly *assembly;
3797 assembly = method->klass->image->assembly;
3798 domain->entry_assembly = assembly;
3799 /* Domains created from another domain already have application_base and configuration_file set */
3800 if (domain->setup->application_base == NULL) {
3801 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3804 if (domain->setup->configuration_file == NULL) {
3805 str = g_strconcat (assembly->image->name, ".config", NULL);
3806 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3807 g_free (str);
3808 mono_set_private_bin_path_from_config (domain);
3812 cinfo = mono_custom_attrs_from_method (method);
3813 if (cinfo) {
3814 static MonoClass *stathread_attribute = NULL;
3815 if (!stathread_attribute)
3816 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3817 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3818 if (!cinfo->cached)
3819 mono_custom_attrs_free (cinfo);
3820 } else {
3821 has_stathread_attribute = FALSE;
3823 if (has_stathread_attribute) {
3824 thread->apartment_state = ThreadApartmentState_STA;
3825 } else {
3826 thread->apartment_state = ThreadApartmentState_MTA;
3828 mono_thread_init_apartment_state ();
3830 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3832 /* FIXME: check signature of method */
3833 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3834 MonoObject *res;
3835 res = mono_runtime_invoke (method, NULL, pa, exc);
3836 if (!exc || !*exc)
3837 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
3838 else
3839 rval = -1;
3841 mono_environment_exitcode_set (rval);
3842 } else {
3843 mono_runtime_invoke (method, NULL, pa, exc);
3844 if (!exc || !*exc)
3845 rval = 0;
3846 else {
3847 /* If the return type of Main is void, only
3848 * set the exitcode if an exception was thrown
3849 * (we don't want to blow away an
3850 * explicitly-set exit code)
3852 rval = -1;
3853 mono_environment_exitcode_set (rval);
3857 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
3859 return rval;
3863 * mono_install_runtime_invoke:
3864 * @func: Function to install
3866 * This is a VM internal routine
3868 void
3869 mono_install_runtime_invoke (MonoInvokeFunc func)
3871 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
3876 * mono_runtime_invoke_array:
3877 * @method: method to invoke
3878 * @obJ: object instance
3879 * @params: arguments to the method
3880 * @exc: exception information.
3882 * Invokes the method represented by @method on the object @obj.
3884 * obj is the 'this' pointer, it should be NULL for static
3885 * methods, a MonoObject* for object instances and a pointer to
3886 * the value type for value types.
3888 * The params array contains the arguments to the method with the
3889 * same convention: MonoObject* pointers for object instances and
3890 * pointers to the value type otherwise. The _invoke_array
3891 * variant takes a C# object[] as the params argument (MonoArray
3892 * *params): in this case the value types are boxed inside the
3893 * respective reference representation.
3895 * From unmanaged code you'll usually use the
3896 * mono_runtime_invoke() variant.
3898 * Note that this function doesn't handle virtual methods for
3899 * you, it will exec the exact method you pass: we still need to
3900 * expose a function to lookup the derived class implementation
3901 * of a virtual method (there are examples of this in the code,
3902 * though).
3904 * You can pass NULL as the exc argument if you don't want to
3905 * catch exceptions, otherwise, *exc will be set to the exception
3906 * thrown, if any. if an exception is thrown, you can't use the
3907 * MonoObject* result from the function.
3909 * If the method returns a value type, it is boxed in an object
3910 * reference.
3912 MonoObject*
3913 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
3914 MonoObject **exc)
3916 MonoMethodSignature *sig = mono_method_signature (method);
3917 gpointer *pa = NULL;
3918 MonoObject *res;
3919 int i;
3920 gboolean has_byref_nullables = FALSE;
3922 if (NULL != params) {
3923 pa = alloca (sizeof (gpointer) * mono_array_length (params));
3924 for (i = 0; i < mono_array_length (params); i++) {
3925 MonoType *t = sig->params [i];
3927 again:
3928 switch (t->type) {
3929 case MONO_TYPE_U1:
3930 case MONO_TYPE_I1:
3931 case MONO_TYPE_BOOLEAN:
3932 case MONO_TYPE_U2:
3933 case MONO_TYPE_I2:
3934 case MONO_TYPE_CHAR:
3935 case MONO_TYPE_U:
3936 case MONO_TYPE_I:
3937 case MONO_TYPE_U4:
3938 case MONO_TYPE_I4:
3939 case MONO_TYPE_U8:
3940 case MONO_TYPE_I8:
3941 case MONO_TYPE_R4:
3942 case MONO_TYPE_R8:
3943 case MONO_TYPE_VALUETYPE:
3944 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
3945 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
3946 pa [i] = mono_array_get (params, MonoObject*, i);
3947 if (t->byref)
3948 has_byref_nullables = TRUE;
3949 } else {
3950 /* MS seems to create the objects if a null is passed in */
3951 if (!mono_array_get (params, MonoObject*, i))
3952 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
3954 if (t->byref) {
3956 * We can't pass the unboxed vtype byref to the callee, since
3957 * that would mean the callee would be able to modify boxed
3958 * primitive types. So we (and MS) make a copy of the boxed
3959 * object, pass that to the callee, and replace the original
3960 * boxed object in the arg array with the copy.
3962 MonoObject *orig = mono_array_get (params, MonoObject*, i);
3963 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
3964 mono_array_setref (params, i, copy);
3967 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
3969 break;
3970 case MONO_TYPE_STRING:
3971 case MONO_TYPE_OBJECT:
3972 case MONO_TYPE_CLASS:
3973 case MONO_TYPE_ARRAY:
3974 case MONO_TYPE_SZARRAY:
3975 if (t->byref)
3976 pa [i] = mono_array_addr (params, MonoObject*, i);
3977 // FIXME: I need to check this code path
3978 else
3979 pa [i] = mono_array_get (params, MonoObject*, i);
3980 break;
3981 case MONO_TYPE_GENERICINST:
3982 if (t->byref)
3983 t = &t->data.generic_class->container_class->this_arg;
3984 else
3985 t = &t->data.generic_class->container_class->byval_arg;
3986 goto again;
3987 case MONO_TYPE_PTR: {
3988 MonoObject *arg;
3990 /* The argument should be an IntPtr */
3991 arg = mono_array_get (params, MonoObject*, i);
3992 if (arg == NULL) {
3993 pa [i] = NULL;
3994 } else {
3995 g_assert (arg->vtable->klass == mono_defaults.int_class);
3996 pa [i] = ((MonoIntPtr*)arg)->m_value;
3998 break;
4000 default:
4001 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4006 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4007 void *o = obj;
4009 if (mono_class_is_nullable (method->klass)) {
4010 /* Need to create a boxed vtype instead */
4011 g_assert (!obj);
4013 if (!params)
4014 return NULL;
4015 else
4016 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4019 if (!obj) {
4020 obj = mono_object_new (mono_domain_get (), method->klass);
4021 g_assert (obj); /*maybe we should raise a TLE instead?*/
4022 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4023 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4025 if (method->klass->valuetype)
4026 o = mono_object_unbox (obj);
4027 else
4028 o = obj;
4029 } else if (method->klass->valuetype) {
4030 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4033 mono_runtime_invoke (method, o, pa, exc);
4034 return obj;
4035 } else {
4036 if (mono_class_is_nullable (method->klass)) {
4037 MonoObject *nullable;
4039 /* Convert the unboxed vtype into a Nullable structure */
4040 nullable = mono_object_new (mono_domain_get (), method->klass);
4042 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4043 obj = mono_object_unbox (nullable);
4046 /* obj must be already unboxed if needed */
4047 res = mono_runtime_invoke (method, obj, pa, exc);
4049 if (sig->ret->type == MONO_TYPE_PTR) {
4050 MonoClass *pointer_class;
4051 static MonoMethod *box_method;
4052 void *box_args [2];
4053 MonoObject *box_exc;
4056 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4057 * convert it to a Pointer object.
4059 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4060 if (!box_method)
4061 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4063 g_assert (res->vtable->klass == mono_defaults.int_class);
4064 box_args [0] = ((MonoIntPtr*)res)->m_value;
4065 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4066 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4067 g_assert (!box_exc);
4070 if (has_byref_nullables) {
4072 * The runtime invoke wrapper already converted byref nullables back,
4073 * and stored them in pa, we just need to copy them back to the
4074 * managed array.
4076 for (i = 0; i < mono_array_length (params); i++) {
4077 MonoType *t = sig->params [i];
4079 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4080 mono_array_setref (params, i, pa [i]);
4084 return res;
4088 static void
4089 arith_overflow (void)
4091 mono_raise_exception (mono_get_exception_overflow ());
4095 * mono_object_allocate:
4096 * @size: number of bytes to allocate
4098 * This is a very simplistic routine until we have our GC-aware
4099 * memory allocator.
4101 * Returns: an allocated object of size @size, or NULL on failure.
4103 static inline void *
4104 mono_object_allocate (size_t size, MonoVTable *vtable)
4106 MonoObject *o;
4107 mono_stats.new_object_count++;
4108 ALLOC_OBJECT (o, vtable, size);
4110 return o;
4114 * mono_object_allocate_ptrfree:
4115 * @size: number of bytes to allocate
4117 * Note that the memory allocated is not zeroed.
4118 * Returns: an allocated object of size @size, or NULL on failure.
4120 static inline void *
4121 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
4123 MonoObject *o;
4124 mono_stats.new_object_count++;
4125 ALLOC_PTRFREE (o, vtable, size);
4126 return o;
4129 static inline void *
4130 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
4132 void *o;
4133 ALLOC_TYPED (o, size, vtable);
4134 mono_stats.new_object_count++;
4136 return o;
4140 * mono_object_new:
4141 * @klass: the class of the object that we want to create
4143 * Returns: a newly created object whose definition is
4144 * looked up using @klass. This will not invoke any constructors,
4145 * so the consumer of this routine has to invoke any constructors on
4146 * its own to initialize the object.
4148 * It returns NULL on failure.
4150 MonoObject *
4151 mono_object_new (MonoDomain *domain, MonoClass *klass)
4153 MonoVTable *vtable;
4155 MONO_ARCH_SAVE_REGS;
4156 vtable = mono_class_vtable (domain, klass);
4157 if (!vtable)
4158 return NULL;
4159 return mono_object_new_specific (vtable);
4163 * mono_object_new_specific:
4164 * @vtable: the vtable of the object that we want to create
4166 * Returns: A newly created object with class and domain specified
4167 * by @vtable
4169 MonoObject *
4170 mono_object_new_specific (MonoVTable *vtable)
4172 MonoObject *o;
4174 MONO_ARCH_SAVE_REGS;
4176 /* check for is_com_object for COM Interop */
4177 if (vtable->remote || vtable->klass->is_com_object)
4179 gpointer pa [1];
4180 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4182 if (im == NULL) {
4183 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4185 if (!klass->inited)
4186 mono_class_init (klass);
4188 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4189 g_assert (im);
4190 vtable->domain->create_proxy_for_type_method = im;
4193 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4195 o = mono_runtime_invoke (im, NULL, pa, NULL);
4196 if (o != NULL) return o;
4199 return mono_object_new_alloc_specific (vtable);
4202 MonoObject *
4203 mono_object_new_alloc_specific (MonoVTable *vtable)
4205 MonoObject *o;
4207 if (!vtable->klass->has_references) {
4208 o = mono_object_new_ptrfree (vtable);
4209 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4210 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
4211 } else {
4212 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4213 o = mono_object_allocate (vtable->klass->instance_size, vtable);
4215 if (G_UNLIKELY (vtable->klass->has_finalize))
4216 mono_object_register_finalizer (o);
4218 if (G_UNLIKELY (profile_allocs))
4219 mono_profiler_allocation (o, vtable->klass);
4220 return o;
4223 MonoObject*
4224 mono_object_new_fast (MonoVTable *vtable)
4226 MonoObject *o;
4227 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
4228 return o;
4231 static MonoObject*
4232 mono_object_new_ptrfree (MonoVTable *vtable)
4234 MonoObject *obj;
4235 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4236 #if NEED_TO_ZERO_PTRFREE
4237 /* an inline memset is much faster for the common vcase of small objects
4238 * note we assume the allocated size is a multiple of sizeof (void*).
4240 if (vtable->klass->instance_size < 128) {
4241 gpointer *p, *end;
4242 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
4243 p = (gpointer*)((char*)obj + sizeof (MonoObject));
4244 while (p < end) {
4245 *p = NULL;
4246 ++p;
4248 } else {
4249 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
4251 #endif
4252 return obj;
4255 static MonoObject*
4256 mono_object_new_ptrfree_box (MonoVTable *vtable)
4258 MonoObject *obj;
4259 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4260 /* the object will be boxed right away, no need to memzero it */
4261 return obj;
4265 * mono_class_get_allocation_ftn:
4266 * @vtable: vtable
4267 * @for_box: the object will be used for boxing
4268 * @pass_size_in_words:
4270 * Return the allocation function appropriate for the given class.
4273 void*
4274 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4276 *pass_size_in_words = FALSE;
4278 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4279 profile_allocs = FALSE;
4281 if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4282 return mono_object_new_specific;
4284 if (!vtable->klass->has_references) {
4285 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
4286 if (for_box)
4287 return mono_object_new_ptrfree_box;
4288 return mono_object_new_ptrfree;
4291 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4293 return mono_object_new_fast;
4296 * FIXME: This is actually slower than mono_object_new_fast, because
4297 * of the overhead of parameter passing.
4300 *pass_size_in_words = TRUE;
4301 #ifdef GC_REDIRECT_TO_LOCAL
4302 return GC_local_gcj_fast_malloc;
4303 #else
4304 return GC_gcj_fast_malloc;
4305 #endif
4309 return mono_object_new_specific;
4313 * mono_object_new_from_token:
4314 * @image: Context where the type_token is hosted
4315 * @token: a token of the type that we want to create
4317 * Returns: A newly created object whose definition is
4318 * looked up using @token in the @image image
4320 MonoObject *
4321 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4323 MonoClass *class;
4325 class = mono_class_get (image, token);
4327 return mono_object_new (domain, class);
4332 * mono_object_clone:
4333 * @obj: the object to clone
4335 * Returns: A newly created object who is a shallow copy of @obj
4337 MonoObject *
4338 mono_object_clone (MonoObject *obj)
4340 MonoObject *o;
4341 int size = obj->vtable->klass->instance_size;
4343 o = mono_object_allocate (size, obj->vtable);
4345 if (obj->vtable->klass->has_references) {
4346 mono_gc_wbarrier_object_copy (o, obj);
4347 } else {
4348 int size = obj->vtable->klass->instance_size;
4349 /* do not copy the sync state */
4350 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
4352 if (G_UNLIKELY (profile_allocs))
4353 mono_profiler_allocation (o, obj->vtable->klass);
4355 if (obj->vtable->klass->has_finalize)
4356 mono_object_register_finalizer (o);
4357 return o;
4361 * mono_array_full_copy:
4362 * @src: source array to copy
4363 * @dest: destination array
4365 * Copies the content of one array to another with exactly the same type and size.
4367 void
4368 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4370 uintptr_t size;
4371 MonoClass *klass = src->obj.vtable->klass;
4373 MONO_ARCH_SAVE_REGS;
4375 g_assert (klass == dest->obj.vtable->klass);
4377 size = mono_array_length (src);
4378 g_assert (size == mono_array_length (dest));
4379 size *= mono_array_element_size (klass);
4380 #ifdef HAVE_SGEN_GC
4381 if (klass->element_class->valuetype) {
4382 if (klass->element_class->has_references)
4383 mono_value_copy_array (dest, 0, mono_array_addr_with_size (src, 0, 0), mono_array_length (src));
4384 else
4385 memcpy (&dest->vector, &src->vector, size);
4386 } else {
4387 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4389 #else
4390 memcpy (&dest->vector, &src->vector, size);
4391 #endif
4395 * mono_array_clone_in_domain:
4396 * @domain: the domain in which the array will be cloned into
4397 * @array: the array to clone
4399 * This routine returns a copy of the array that is hosted on the
4400 * specified MonoDomain.
4402 MonoArray*
4403 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4405 MonoArray *o;
4406 uintptr_t size, i;
4407 uintptr_t *sizes;
4408 MonoClass *klass = array->obj.vtable->klass;
4410 MONO_ARCH_SAVE_REGS;
4412 if (array->bounds == NULL) {
4413 size = mono_array_length (array);
4414 o = mono_array_new_full (domain, klass, &size, NULL);
4416 size *= mono_array_element_size (klass);
4417 #ifdef HAVE_SGEN_GC
4418 if (klass->element_class->valuetype) {
4419 if (klass->element_class->has_references)
4420 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4421 else
4422 memcpy (&o->vector, &array->vector, size);
4423 } else {
4424 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4426 #else
4427 memcpy (&o->vector, &array->vector, size);
4428 #endif
4429 return o;
4432 sizes = alloca (klass->rank * sizeof(intptr_t) * 2);
4433 size = mono_array_element_size (klass);
4434 for (i = 0; i < klass->rank; ++i) {
4435 sizes [i] = array->bounds [i].length;
4436 size *= array->bounds [i].length;
4437 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4439 o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
4440 #ifdef HAVE_SGEN_GC
4441 if (klass->element_class->valuetype) {
4442 if (klass->element_class->has_references)
4443 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4444 else
4445 memcpy (&o->vector, &array->vector, size);
4446 } else {
4447 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4449 #else
4450 memcpy (&o->vector, &array->vector, size);
4451 #endif
4453 return o;
4457 * mono_array_clone:
4458 * @array: the array to clone
4460 * Returns: A newly created array who is a shallow copy of @array
4462 MonoArray*
4463 mono_array_clone (MonoArray *array)
4465 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4468 /* helper macros to check for overflow when calculating the size of arrays */
4469 #ifdef MONO_BIG_ARRAYS
4470 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4471 #define MYGUINT_MAX MYGUINT64_MAX
4472 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4473 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4474 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4475 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4476 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4477 #else
4478 #define MYGUINT32_MAX 4294967295U
4479 #define MYGUINT_MAX MYGUINT32_MAX
4480 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4481 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4482 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4483 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4484 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4485 #endif
4487 gboolean
4488 mono_array_calc_byte_len (MonoClass *class, uintptr_t len, uintptr_t *res)
4490 uintptr_t byte_len;
4492 byte_len = mono_array_element_size (class);
4493 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4494 return FALSE;
4495 byte_len *= len;
4496 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4497 return FALSE;
4498 byte_len += sizeof (MonoArray);
4500 *res = byte_len;
4502 return TRUE;
4506 * mono_array_new_full:
4507 * @domain: domain where the object is created
4508 * @array_class: array class
4509 * @lengths: lengths for each dimension in the array
4510 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4512 * This routine creates a new array objects with the given dimensions,
4513 * lower bounds and type.
4515 MonoArray*
4516 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4518 uintptr_t byte_len, len, bounds_size;
4519 MonoObject *o;
4520 MonoArray *array;
4521 MonoArrayBounds *bounds;
4522 MonoVTable *vtable;
4523 int i;
4525 if (!array_class->inited)
4526 mono_class_init (array_class);
4528 len = 1;
4530 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4531 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4532 len = lengths [0];
4533 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4534 arith_overflow ();
4535 bounds_size = 0;
4536 } else {
4537 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4539 for (i = 0; i < array_class->rank; ++i) {
4540 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4541 arith_overflow ();
4542 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4543 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4544 len *= lengths [i];
4548 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4549 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4551 if (bounds_size) {
4552 /* align */
4553 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4554 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4555 byte_len = (byte_len + 3) & ~3;
4556 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4557 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4558 byte_len += bounds_size;
4561 * Following three lines almost taken from mono_object_new ():
4562 * they need to be kept in sync.
4564 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4565 #ifndef HAVE_SGEN_GC
4566 if (!array_class->has_references) {
4567 o = mono_object_allocate_ptrfree (byte_len, vtable);
4568 #if NEED_TO_ZERO_PTRFREE
4569 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4570 #endif
4571 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4572 o = mono_object_allocate_spec (byte_len, vtable);
4573 }else {
4574 o = mono_object_allocate (byte_len, vtable);
4577 array = (MonoArray*)o;
4578 array->max_length = len;
4580 if (bounds_size) {
4581 bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4582 array->bounds = bounds;
4584 #else
4585 if (bounds_size)
4586 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4587 else
4588 o = mono_gc_alloc_vector (vtable, byte_len, len);
4589 array = (MonoArray*)o;
4590 mono_stats.new_object_count++;
4592 bounds = array->bounds;
4593 #endif
4595 if (bounds_size) {
4596 for (i = 0; i < array_class->rank; ++i) {
4597 bounds [i].length = lengths [i];
4598 if (lower_bounds)
4599 bounds [i].lower_bound = lower_bounds [i];
4603 if (G_UNLIKELY (profile_allocs))
4604 mono_profiler_allocation (o, array_class);
4606 return array;
4610 * mono_array_new:
4611 * @domain: domain where the object is created
4612 * @eclass: element class
4613 * @n: number of array elements
4615 * This routine creates a new szarray with @n elements of type @eclass.
4617 MonoArray *
4618 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
4620 MonoClass *ac;
4622 MONO_ARCH_SAVE_REGS;
4624 ac = mono_array_class_get (eclass, 1);
4625 g_assert (ac);
4627 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4631 * mono_array_new_specific:
4632 * @vtable: a vtable in the appropriate domain for an initialized class
4633 * @n: number of array elements
4635 * This routine is a fast alternative to mono_array_new() for code which
4636 * can be sure about the domain it operates in.
4638 MonoArray *
4639 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
4641 MonoObject *o;
4642 MonoArray *ao;
4643 uintptr_t byte_len;
4645 MONO_ARCH_SAVE_REGS;
4647 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4648 arith_overflow ();
4649 return NULL;
4652 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4653 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4654 return NULL;
4656 #ifndef HAVE_SGEN_GC
4657 if (!vtable->klass->has_references) {
4658 o = mono_object_allocate_ptrfree (byte_len, vtable);
4659 #if NEED_TO_ZERO_PTRFREE
4660 ((MonoArray*)o)->bounds = NULL;
4661 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4662 #endif
4663 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4664 o = mono_object_allocate_spec (byte_len, vtable);
4665 } else {
4666 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4667 o = mono_object_allocate (byte_len, vtable);
4670 ao = (MonoArray *)o;
4671 ao->max_length = n;
4672 #else
4673 o = mono_gc_alloc_vector (vtable, byte_len, n);
4674 ao = (MonoArray*)o;
4675 mono_stats.new_object_count++;
4676 #endif
4678 if (G_UNLIKELY (profile_allocs))
4679 mono_profiler_allocation (o, vtable->klass);
4681 return ao;
4685 * mono_string_new_utf16:
4686 * @text: a pointer to an utf16 string
4687 * @len: the length of the string
4689 * Returns: A newly created string object which contains @text.
4691 MonoString *
4692 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4694 MonoString *s;
4696 s = mono_string_new_size (domain, len);
4697 g_assert (s != NULL);
4699 memcpy (mono_string_chars (s), text, len * 2);
4701 return s;
4705 * mono_string_new_size:
4706 * @text: a pointer to an utf16 string
4707 * @len: the length of the string
4709 * Returns: A newly created string object of @len
4711 MonoString *
4712 mono_string_new_size (MonoDomain *domain, gint32 len)
4714 MonoString *s;
4715 MonoVTable *vtable;
4716 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4718 /* overflow ? can't fit it, can't allocate it! */
4719 if (len > size)
4720 mono_gc_out_of_memory (-1);
4722 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4723 g_assert (vtable);
4725 #ifndef HAVE_SGEN_GC
4726 s = mono_object_allocate_ptrfree (size, vtable);
4728 s->length = len;
4729 #else
4730 s = mono_gc_alloc_string (vtable, size, len);
4731 #endif
4732 #if NEED_TO_ZERO_PTRFREE
4733 s->chars [len] = 0;
4734 #endif
4735 if (G_UNLIKELY (profile_allocs))
4736 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4738 return s;
4742 * mono_string_new_len:
4743 * @text: a pointer to an utf8 string
4744 * @length: number of bytes in @text to consider
4746 * Returns: A newly created string object which contains @text.
4748 MonoString*
4749 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4751 GError *error = NULL;
4752 MonoString *o = NULL;
4753 guint16 *ut;
4754 glong items_written;
4756 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
4758 if (!error)
4759 o = mono_string_new_utf16 (domain, ut, items_written);
4760 else
4761 g_error_free (error);
4763 g_free (ut);
4765 return o;
4769 * mono_string_new:
4770 * @text: a pointer to an utf8 string
4772 * Returns: A newly created string object which contains @text.
4774 MonoString*
4775 mono_string_new (MonoDomain *domain, const char *text)
4777 GError *error = NULL;
4778 MonoString *o = NULL;
4779 guint16 *ut;
4780 glong items_written;
4781 int l;
4783 l = strlen (text);
4785 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4787 if (!error)
4788 o = mono_string_new_utf16 (domain, ut, items_written);
4789 else
4790 g_error_free (error);
4792 g_free (ut);
4793 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4794 #if 0
4795 gunichar2 *str;
4796 const gchar *end;
4797 int len;
4798 MonoString *o = NULL;
4800 if (!g_utf8_validate (text, -1, &end))
4801 return NULL;
4803 len = g_utf8_strlen (text, -1);
4804 o = mono_string_new_size (domain, len);
4805 str = mono_string_chars (o);
4807 while (text < end) {
4808 *str++ = g_utf8_get_char (text);
4809 text = g_utf8_next_char (text);
4811 #endif
4812 return o;
4816 * mono_string_new_wrapper:
4817 * @text: pointer to utf8 characters.
4819 * Helper function to create a string object from @text in the current domain.
4821 MonoString*
4822 mono_string_new_wrapper (const char *text)
4824 MonoDomain *domain = mono_domain_get ();
4826 MONO_ARCH_SAVE_REGS;
4828 if (text)
4829 return mono_string_new (domain, text);
4831 return NULL;
4835 * mono_value_box:
4836 * @class: the class of the value
4837 * @value: a pointer to the unboxed data
4839 * Returns: A newly created object which contains @value.
4841 MonoObject *
4842 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
4844 MonoObject *res;
4845 int size;
4846 MonoVTable *vtable;
4848 g_assert (class->valuetype);
4849 if (mono_class_is_nullable (class))
4850 return mono_nullable_box (value, class);
4852 vtable = mono_class_vtable (domain, class);
4853 if (!vtable)
4854 return NULL;
4855 size = mono_class_instance_size (class);
4856 res = mono_object_new_alloc_specific (vtable);
4857 if (G_UNLIKELY (profile_allocs))
4858 mono_profiler_allocation (res, class);
4860 size = size - sizeof (MonoObject);
4862 #ifdef HAVE_SGEN_GC
4863 g_assert (size == mono_class_value_size (class, NULL));
4864 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
4865 #else
4866 #if NO_UNALIGNED_ACCESS
4867 memcpy ((char *)res + sizeof (MonoObject), value, size);
4868 #else
4869 switch (size) {
4870 case 1:
4871 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
4872 break;
4873 case 2:
4874 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
4875 break;
4876 case 4:
4877 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
4878 break;
4879 case 8:
4880 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
4881 break;
4882 default:
4883 memcpy ((char *)res + sizeof (MonoObject), value, size);
4885 #endif
4886 #endif
4887 if (class->has_finalize)
4888 mono_object_register_finalizer (res);
4889 return res;
4893 * mono_value_copy:
4894 * @dest: destination pointer
4895 * @src: source pointer
4896 * @klass: a valuetype class
4898 * Copy a valuetype from @src to @dest. This function must be used
4899 * when @klass contains references fields.
4901 void
4902 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
4904 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
4908 * mono_value_copy_array:
4909 * @dest: destination array
4910 * @dest_idx: index in the @dest array
4911 * @src: source pointer
4912 * @count: number of items
4914 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
4915 * This function must be used when @klass contains references fields.
4916 * Overlap is handled.
4918 void
4919 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
4921 int size = mono_array_element_size (dest->obj.vtable->klass);
4922 char *d = mono_array_addr_with_size (dest, size, dest_idx);
4923 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
4924 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
4928 * mono_object_get_domain:
4929 * @obj: object to query
4931 * Returns: the MonoDomain where the object is hosted
4933 MonoDomain*
4934 mono_object_get_domain (MonoObject *obj)
4936 return mono_object_domain (obj);
4940 * mono_object_get_class:
4941 * @obj: object to query
4943 * Returns: the MonOClass of the object.
4945 MonoClass*
4946 mono_object_get_class (MonoObject *obj)
4948 return mono_object_class (obj);
4951 * mono_object_get_size:
4952 * @o: object to query
4954 * Returns: the size, in bytes, of @o
4956 guint
4957 mono_object_get_size (MonoObject* o)
4959 MonoClass* klass = mono_object_class (o);
4960 if (klass == mono_defaults.string_class) {
4961 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
4962 } else if (o->vtable->rank) {
4963 MonoArray *array = (MonoArray*)o;
4964 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
4965 if (array->bounds) {
4966 size += 3;
4967 size &= ~3;
4968 size += sizeof (MonoArrayBounds) * o->vtable->rank;
4970 return size;
4971 } else {
4972 return mono_class_instance_size (klass);
4977 * mono_object_unbox:
4978 * @obj: object to unbox
4980 * Returns: a pointer to the start of the valuetype boxed in this
4981 * object.
4983 * This method will assert if the object passed is not a valuetype.
4985 gpointer
4986 mono_object_unbox (MonoObject *obj)
4988 /* add assert for valuetypes? */
4989 g_assert (obj->vtable->klass->valuetype);
4990 return ((char*)obj) + sizeof (MonoObject);
4994 * mono_object_isinst:
4995 * @obj: an object
4996 * @klass: a pointer to a class
4998 * Returns: @obj if @obj is derived from @klass
5000 MonoObject *
5001 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5003 if (!klass->inited)
5004 mono_class_init (klass);
5006 if (klass->marshalbyref || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5007 return mono_object_isinst_mbyref (obj, klass);
5009 if (!obj)
5010 return NULL;
5012 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5015 MonoObject *
5016 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5018 MonoVTable *vt;
5020 if (!obj)
5021 return NULL;
5023 vt = obj->vtable;
5025 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5026 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5027 return obj;
5030 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5031 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5032 return obj;
5033 } else {
5034 MonoClass *oklass = vt->klass;
5035 if ((oklass == mono_defaults.transparent_proxy_class))
5036 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5038 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5039 return obj;
5042 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5044 MonoDomain *domain = mono_domain_get ();
5045 MonoObject *res;
5046 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5047 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5048 MonoMethod *im = NULL;
5049 gpointer pa [2];
5051 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5052 im = mono_object_get_virtual_method (rp, im);
5053 g_assert (im);
5055 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5056 pa [1] = obj;
5058 res = mono_runtime_invoke (im, rp, pa, NULL);
5060 if (*(MonoBoolean *) mono_object_unbox(res)) {
5061 /* Update the vtable of the remote type, so it can safely cast to this new type */
5062 mono_upgrade_remote_class (domain, obj, klass);
5063 return obj;
5067 return NULL;
5071 * mono_object_castclass_mbyref:
5072 * @obj: an object
5073 * @klass: a pointer to a class
5075 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5077 MonoObject *
5078 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5080 if (!obj) return NULL;
5081 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5083 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5084 "System",
5085 "InvalidCastException"));
5086 return NULL;
5089 typedef struct {
5090 MonoDomain *orig_domain;
5091 MonoString *ins;
5092 MonoString *res;
5093 } LDStrInfo;
5095 static void
5096 str_lookup (MonoDomain *domain, gpointer user_data)
5098 LDStrInfo *info = user_data;
5099 if (info->res || domain == info->orig_domain)
5100 return;
5101 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5104 #ifdef HAVE_SGEN_GC
5106 static MonoString*
5107 mono_string_get_pinned (MonoString *str)
5109 int size;
5110 MonoString *news;
5111 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5112 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5113 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5114 news->length = mono_string_length (str);
5115 return news;
5118 #else
5119 #define mono_string_get_pinned(str) (str)
5120 #endif
5122 static MonoString*
5123 mono_string_is_interned_lookup (MonoString *str, int insert)
5125 MonoGHashTable *ldstr_table;
5126 MonoString *res;
5127 MonoDomain *domain;
5129 domain = ((MonoObject *)str)->vtable->domain;
5130 ldstr_table = domain->ldstr_table;
5131 ldstr_lock ();
5132 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
5133 ldstr_unlock ();
5134 return res;
5136 if (insert) {
5137 str = mono_string_get_pinned (str);
5138 mono_g_hash_table_insert (ldstr_table, str, str);
5139 ldstr_unlock ();
5140 return str;
5141 } else {
5142 LDStrInfo ldstr_info;
5143 ldstr_info.orig_domain = domain;
5144 ldstr_info.ins = str;
5145 ldstr_info.res = NULL;
5147 mono_domain_foreach (str_lookup, &ldstr_info);
5148 if (ldstr_info.res) {
5150 * the string was already interned in some other domain:
5151 * intern it in the current one as well.
5153 mono_g_hash_table_insert (ldstr_table, str, str);
5154 ldstr_unlock ();
5155 return str;
5158 ldstr_unlock ();
5159 return NULL;
5163 * mono_string_is_interned:
5164 * @o: String to probe
5166 * Returns whether the string has been interned.
5168 MonoString*
5169 mono_string_is_interned (MonoString *o)
5171 return mono_string_is_interned_lookup (o, FALSE);
5175 * mono_string_intern:
5176 * @o: String to intern
5178 * Interns the string passed.
5179 * Returns: The interned string.
5181 MonoString*
5182 mono_string_intern (MonoString *str)
5184 return mono_string_is_interned_lookup (str, TRUE);
5188 * mono_ldstr:
5189 * @domain: the domain where the string will be used.
5190 * @image: a metadata context
5191 * @idx: index into the user string table.
5193 * Implementation for the ldstr opcode.
5194 * Returns: a loaded string from the @image/@idx combination.
5196 MonoString*
5197 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5199 MONO_ARCH_SAVE_REGS;
5201 if (image->dynamic) {
5202 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5203 return str;
5204 } else {
5205 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5206 return NULL; /*FIXME we should probably be raising an exception here*/
5207 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5212 * mono_ldstr_metadata_sig
5213 * @domain: the domain for the string
5214 * @sig: the signature of a metadata string
5216 * Returns: a MonoString for a string stored in the metadata
5218 static MonoString*
5219 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5221 const char *str = sig;
5222 MonoString *o, *interned;
5223 size_t len2;
5225 len2 = mono_metadata_decode_blob_size (str, &str);
5226 len2 >>= 1;
5228 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5229 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5231 int i;
5232 guint16 *p2 = (guint16*)mono_string_chars (o);
5233 for (i = 0; i < len2; ++i) {
5234 *p2 = GUINT16_FROM_LE (*p2);
5235 ++p2;
5238 #endif
5239 ldstr_lock ();
5240 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
5241 ldstr_unlock ();
5242 /* o will get garbage collected */
5243 return interned;
5246 o = mono_string_get_pinned (o);
5247 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5248 ldstr_unlock ();
5250 return o;
5254 * mono_string_to_utf8:
5255 * @s: a System.String
5257 * Return the UTF8 representation for @s.
5258 * the resulting buffer nedds to be freed with g_free().
5260 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5262 char *
5263 mono_string_to_utf8 (MonoString *s)
5265 MonoError error;
5266 char *result = mono_string_to_utf8_checked (s, &error);
5268 if (!mono_error_ok (&error))
5269 mono_error_raise_exception (&error);
5270 return result;
5273 char *
5274 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5276 long written = 0;
5277 char *as;
5278 GError *gerror = NULL;
5280 mono_error_init (error);
5282 if (s == NULL)
5283 return NULL;
5285 if (!s->length)
5286 return g_strdup ("");
5288 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5289 if (gerror) {
5290 mono_error_set_argument (error, "string", "%s", gerror->message);
5291 g_error_free (gerror);
5292 return NULL;
5294 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5295 if (s->length > written) {
5296 /* allocate the total length and copy the part of the string that has been converted */
5297 char *as2 = g_malloc0 (s->length);
5298 memcpy (as2, as, written);
5299 g_free (as);
5300 as = as2;
5303 return as;
5307 * mono_string_to_utf16:
5308 * @s: a MonoString
5310 * Return an null-terminated array of the utf-16 chars
5311 * contained in @s. The result must be freed with g_free().
5312 * This is a temporary helper until our string implementation
5313 * is reworked to always include the null terminating char.
5315 mono_unichar2*
5316 mono_string_to_utf16 (MonoString *s)
5318 char *as;
5320 if (s == NULL)
5321 return NULL;
5323 as = g_malloc ((s->length * 2) + 2);
5324 as [(s->length * 2)] = '\0';
5325 as [(s->length * 2) + 1] = '\0';
5327 if (!s->length) {
5328 return (gunichar2 *)(as);
5331 memcpy (as, mono_string_chars(s), s->length * 2);
5332 return (gunichar2 *)(as);
5336 * mono_string_from_utf16:
5337 * @data: the UTF16 string (LPWSTR) to convert
5339 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5341 * Returns: a MonoString.
5343 MonoString *
5344 mono_string_from_utf16 (gunichar2 *data)
5346 MonoDomain *domain = mono_domain_get ();
5347 int len = 0;
5349 if (!data)
5350 return NULL;
5352 while (data [len]) len++;
5354 return mono_string_new_utf16 (domain, data, len);
5358 static char *
5359 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, MonoError *error)
5361 char *r;
5362 char *mp_s;
5363 int len;
5365 r = mono_string_to_utf8_checked (s, error);
5366 if (!mono_error_ok (error))
5367 return NULL;
5369 if (!mp && !image)
5370 return r;
5372 len = strlen (r) + 1;
5373 if (mp)
5374 mp_s = mono_mempool_alloc (mp, len);
5375 else
5376 mp_s = mono_image_alloc (image, len);
5378 memcpy (mp_s, r, len);
5380 g_free (r);
5382 return mp_s;
5386 * mono_string_to_utf8_image:
5387 * @s: a System.String
5389 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5391 char *
5392 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5394 return mono_string_to_utf8_internal (NULL, image, s, error);
5398 * mono_string_to_utf8_mp:
5399 * @s: a System.String
5401 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5403 char *
5404 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5406 return mono_string_to_utf8_internal (mp, NULL, s, error);
5409 static void
5410 default_ex_handler (MonoException *ex)
5412 MonoObject *o = (MonoObject*)ex;
5413 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
5414 exit (1);
5417 static MonoExceptionFunc ex_handler = default_ex_handler;
5420 * mono_install_handler:
5421 * @func: exception handler
5423 * This is an internal JIT routine used to install the handler for exceptions
5424 * being throwh.
5426 void
5427 mono_install_handler (MonoExceptionFunc func)
5429 ex_handler = func? func: default_ex_handler;
5433 * mono_raise_exception:
5434 * @ex: exception object
5436 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5438 void
5439 mono_raise_exception (MonoException *ex)
5442 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5443 * that will cause gcc to omit the function epilog, causing problems when
5444 * the JIT tries to walk the stack, since the return address on the stack
5445 * will point into the next function in the executable, not this one.
5448 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class) {
5449 MonoInternalThread *thread = mono_thread_internal_current ();
5450 g_assert (ex->object.vtable->domain == mono_domain_get ());
5451 MONO_OBJECT_SETREF (thread, abort_exc, ex);
5454 ex_handler (ex);
5458 * mono_wait_handle_new:
5459 * @domain: Domain where the object will be created
5460 * @handle: Handle for the wait handle
5462 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5464 MonoWaitHandle *
5465 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5467 MonoWaitHandle *res;
5468 gpointer params [1];
5469 static MonoMethod *handle_set;
5471 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5473 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5474 if (!handle_set)
5475 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5477 params [0] = &handle;
5478 mono_runtime_invoke (handle_set, res, params, NULL);
5480 return res;
5483 HANDLE
5484 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5486 static MonoClassField *f_os_handle;
5487 static MonoClassField *f_safe_handle;
5489 if (!f_os_handle && !f_safe_handle) {
5490 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5491 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5494 if (f_os_handle) {
5495 HANDLE retval;
5496 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5497 return retval;
5498 } else {
5499 MonoSafeHandle *sh;
5500 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5501 return sh->handle;
5506 static MonoObject*
5507 mono_runtime_capture_context (MonoDomain *domain)
5509 RuntimeInvokeFunction runtime_invoke;
5511 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5512 MonoMethod *method = mono_get_context_capture_method ();
5513 MonoMethod *wrapper;
5514 if (!method)
5515 return NULL;
5516 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5517 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5518 domain->capture_context_method = mono_compile_method (method);
5521 runtime_invoke = domain->capture_context_runtime_invoke;
5523 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5526 * mono_async_result_new:
5527 * @domain:domain where the object will be created.
5528 * @handle: wait handle.
5529 * @state: state to pass to AsyncResult
5530 * @data: C closure data.
5532 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5533 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5536 MonoAsyncResult *
5537 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5539 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5540 MonoObject *context = mono_runtime_capture_context (domain);
5541 /* we must capture the execution context from the original thread */
5542 if (context) {
5543 MONO_OBJECT_SETREF (res, execution_context, context);
5544 /* note: result may be null if the flow is suppressed */
5547 res->data = data;
5548 MONO_OBJECT_SETREF (res, object_data, object_data);
5549 MONO_OBJECT_SETREF (res, async_state, state);
5550 if (handle != NULL)
5551 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5553 res->sync_completed = FALSE;
5554 res->completed = FALSE;
5556 return res;
5559 void
5560 mono_message_init (MonoDomain *domain,
5561 MonoMethodMessage *this,
5562 MonoReflectionMethod *method,
5563 MonoArray *out_args)
5565 static MonoClass *object_array_klass;
5566 static MonoClass *byte_array_klass;
5567 static MonoClass *string_array_klass;
5568 MonoMethodSignature *sig = mono_method_signature (method->method);
5569 MonoString *name;
5570 int i, j;
5571 char **names;
5572 guint8 arg_type;
5574 if (!object_array_klass) {
5575 MonoClass *klass;
5577 klass = mono_array_class_get (mono_defaults.object_class, 1);
5578 g_assert (klass);
5580 mono_memory_barrier ();
5581 object_array_klass = klass;
5583 klass = mono_array_class_get (mono_defaults.byte_class, 1);
5584 g_assert (klass);
5586 mono_memory_barrier ();
5587 byte_array_klass = klass;
5589 klass = mono_array_class_get (mono_defaults.string_class, 1);
5590 g_assert (klass);
5592 mono_memory_barrier ();
5593 string_array_klass = klass;
5596 MONO_OBJECT_SETREF (this, method, method);
5598 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
5599 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
5600 this->async_result = NULL;
5601 this->call_type = CallType_Sync;
5603 names = g_new (char *, sig->param_count);
5604 mono_method_get_param_names (method->method, (const char **) names);
5605 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
5607 for (i = 0; i < sig->param_count; i++) {
5608 name = mono_string_new (domain, names [i]);
5609 mono_array_setref (this->names, i, name);
5612 g_free (names);
5613 for (i = 0, j = 0; i < sig->param_count; i++) {
5614 if (sig->params [i]->byref) {
5615 if (out_args) {
5616 MonoObject* arg = mono_array_get (out_args, gpointer, j);
5617 mono_array_setref (this->args, i, arg);
5618 j++;
5620 arg_type = 2;
5621 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5622 arg_type |= 1;
5623 } else {
5624 arg_type = 1;
5625 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5626 arg_type |= 4;
5628 mono_array_set (this->arg_types, guint8, i, arg_type);
5633 * mono_remoting_invoke:
5634 * @real_proxy: pointer to a RealProxy object
5635 * @msg: The MonoMethodMessage to execute
5636 * @exc: used to store exceptions
5637 * @out_args: used to store output arguments
5639 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5640 * IMessage interface and it is not trivial to extract results from there. So
5641 * we call an helper method PrivateInvoke instead of calling
5642 * RealProxy::Invoke() directly.
5644 * Returns: the result object.
5646 MonoObject *
5647 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
5648 MonoObject **exc, MonoArray **out_args)
5650 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5651 gpointer pa [4];
5653 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5655 if (!im) {
5656 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
5657 g_assert (im);
5658 real_proxy->vtable->domain->private_invoke_method = im;
5661 pa [0] = real_proxy;
5662 pa [1] = msg;
5663 pa [2] = exc;
5664 pa [3] = out_args;
5666 return mono_runtime_invoke (im, NULL, pa, exc);
5669 MonoObject *
5670 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
5671 MonoObject **exc, MonoArray **out_args)
5673 static MonoClass *object_array_klass;
5674 MonoDomain *domain;
5675 MonoMethod *method;
5676 MonoMethodSignature *sig;
5677 MonoObject *ret;
5678 int i, j, outarg_count = 0;
5680 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5682 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
5683 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5684 target = tp->rp->unwrapped_server;
5685 } else {
5686 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
5690 domain = mono_domain_get ();
5691 method = msg->method->method;
5692 sig = mono_method_signature (method);
5694 for (i = 0; i < sig->param_count; i++) {
5695 if (sig->params [i]->byref)
5696 outarg_count++;
5699 if (!object_array_klass) {
5700 MonoClass *klass;
5702 klass = mono_array_class_get (mono_defaults.object_class, 1);
5703 g_assert (klass);
5705 mono_memory_barrier ();
5706 object_array_klass = klass;
5709 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
5710 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
5711 *exc = NULL;
5713 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
5715 for (i = 0, j = 0; i < sig->param_count; i++) {
5716 if (sig->params [i]->byref) {
5717 MonoObject* arg;
5718 arg = mono_array_get (msg->args, gpointer, i);
5719 mono_array_setref (*out_args, j, arg);
5720 j++;
5724 return ret;
5728 * mono_print_unhandled_exception:
5729 * @exc: The exception
5731 * Prints the unhandled exception.
5733 void
5734 mono_print_unhandled_exception (MonoObject *exc)
5736 MonoError error;
5737 char *message = (char *) "";
5738 MonoString *str;
5739 MonoMethod *method;
5740 MonoClass *klass;
5741 gboolean free_message = FALSE;
5743 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
5744 klass = exc->vtable->klass;
5745 method = NULL;
5746 while (klass && method == NULL) {
5747 method = mono_class_get_method_from_name_flags (klass, "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
5748 if (method == NULL)
5749 klass = klass->parent;
5752 g_assert (method);
5754 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
5755 if (str) {
5756 message = mono_string_to_utf8_checked (str, &error);
5757 if (!mono_error_ok (&error)) {
5758 mono_error_cleanup (&error);
5759 message = (char *)"";
5760 } else {
5761 free_message = TRUE;
5767 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
5768 * exc->vtable->klass->name, message);
5770 g_printerr ("\nUnhandled Exception: %s\n", message);
5772 if (free_message)
5773 g_free (message);
5777 * mono_delegate_ctor:
5778 * @this: pointer to an uninitialized delegate object
5779 * @target: target object
5780 * @addr: pointer to native code
5781 * @method: method
5783 * Initialize a delegate and sets a specific method, not the one
5784 * associated with addr. This is useful when sharing generic code.
5785 * In that case addr will most probably not be associated with the
5786 * correct instantiation of the method.
5788 void
5789 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
5791 MonoDelegate *delegate = (MonoDelegate *)this;
5792 MonoClass *class;
5794 g_assert (this);
5795 g_assert (addr);
5797 if (method)
5798 delegate->method = method;
5800 class = this->vtable->klass;
5801 mono_stats.delegate_creations++;
5803 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5804 g_assert (method);
5805 method = mono_marshal_get_remoting_invoke (method);
5806 delegate->method_ptr = mono_compile_method (method);
5807 MONO_OBJECT_SETREF (delegate, target, target);
5808 } else if (method && mono_method_signature (method)->hasthis && method->klass->valuetype) {
5809 method = mono_marshal_get_unbox_wrapper (method);
5810 delegate->method_ptr = mono_compile_method (method);
5811 MONO_OBJECT_SETREF (delegate, target, target);
5812 } else {
5813 delegate->method_ptr = addr;
5814 MONO_OBJECT_SETREF (delegate, target, target);
5817 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
5821 * mono_delegate_ctor:
5822 * @this: pointer to an uninitialized delegate object
5823 * @target: target object
5824 * @addr: pointer to native code
5826 * This is used to initialize a delegate.
5828 void
5829 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
5831 MonoDomain *domain = mono_domain_get ();
5832 MonoJitInfo *ji;
5833 MonoMethod *method = NULL;
5835 g_assert (addr);
5837 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
5838 method = ji->method;
5839 g_assert (!method->klass->generic_container);
5842 mono_delegate_ctor_with_method (this, target, addr, method);
5846 * mono_method_call_message_new:
5847 * @method: method to encapsulate
5848 * @params: parameters to the method
5849 * @invoke: optional, delegate invoke.
5850 * @cb: async callback delegate.
5851 * @state: state passed to the async callback.
5853 * Translates arguments pointers into a MonoMethodMessage.
5855 MonoMethodMessage *
5856 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
5857 MonoDelegate **cb, MonoObject **state)
5859 MonoDomain *domain = mono_domain_get ();
5860 MonoMethodSignature *sig = mono_method_signature (method);
5861 MonoMethodMessage *msg;
5862 int i, count, type;
5864 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5866 if (invoke) {
5867 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
5868 count = sig->param_count - 2;
5869 } else {
5870 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
5871 count = sig->param_count;
5874 for (i = 0; i < count; i++) {
5875 gpointer vpos;
5876 MonoClass *class;
5877 MonoObject *arg;
5879 if (sig->params [i]->byref)
5880 vpos = *((gpointer *)params [i]);
5881 else
5882 vpos = params [i];
5884 type = sig->params [i]->type;
5885 class = mono_class_from_mono_type (sig->params [i]);
5887 if (class->valuetype)
5888 arg = mono_value_box (domain, class, vpos);
5889 else
5890 arg = *((MonoObject **)vpos);
5892 mono_array_setref (msg->args, i, arg);
5895 if (cb != NULL && state != NULL) {
5896 *cb = *((MonoDelegate **)params [i]);
5897 i++;
5898 *state = *((MonoObject **)params [i]);
5901 return msg;
5905 * mono_method_return_message_restore:
5907 * Restore results from message based processing back to arguments pointers
5909 void
5910 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
5912 MonoMethodSignature *sig = mono_method_signature (method);
5913 int i, j, type, size, out_len;
5915 if (out_args == NULL)
5916 return;
5917 out_len = mono_array_length (out_args);
5918 if (out_len == 0)
5919 return;
5921 for (i = 0, j = 0; i < sig->param_count; i++) {
5922 MonoType *pt = sig->params [i];
5924 if (pt->byref) {
5925 char *arg;
5926 if (j >= out_len)
5927 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
5929 arg = mono_array_get (out_args, gpointer, j);
5930 type = pt->type;
5932 g_assert (type != MONO_TYPE_VOID);
5934 if (MONO_TYPE_IS_REFERENCE (pt)) {
5935 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
5936 } else {
5937 if (arg) {
5938 MonoClass *class = ((MonoObject*)arg)->vtable->klass;
5939 size = mono_class_value_size (class, NULL);
5940 if (class->has_references)
5941 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
5942 else
5943 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
5944 } else {
5945 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
5946 memset (*((gpointer *)params [i]), 0, size);
5950 j++;
5956 * mono_load_remote_field:
5957 * @this: pointer to an object
5958 * @klass: klass of the object containing @field
5959 * @field: the field to load
5960 * @res: a storage to store the result
5962 * This method is called by the runtime on attempts to load fields of
5963 * transparent proxy objects. @this points to such TP, @klass is the class of
5964 * the object containing @field. @res is a storage location which can be
5965 * used to store the result.
5967 * Returns: an address pointing to the value of field.
5969 gpointer
5970 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
5972 static MonoMethod *getter = NULL;
5973 MonoDomain *domain = mono_domain_get ();
5974 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5975 MonoClass *field_class;
5976 MonoMethodMessage *msg;
5977 MonoArray *out_args;
5978 MonoObject *exc;
5979 char* full_name;
5981 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5982 g_assert (res != NULL);
5984 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5985 mono_field_get_value (tp->rp->unwrapped_server, field, res);
5986 return res;
5989 if (!getter) {
5990 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5991 g_assert (getter);
5994 field_class = mono_class_from_mono_type (field->type);
5996 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5997 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5998 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6000 full_name = mono_type_get_full_name (klass);
6001 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6002 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6003 g_free (full_name);
6005 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6007 if (exc) mono_raise_exception ((MonoException *)exc);
6009 if (mono_array_length (out_args) == 0)
6010 return NULL;
6012 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6014 if (field_class->valuetype) {
6015 return ((char *)*res) + sizeof (MonoObject);
6016 } else
6017 return res;
6021 * mono_load_remote_field_new:
6022 * @this:
6023 * @klass:
6024 * @field:
6026 * Missing documentation.
6028 MonoObject *
6029 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
6031 static MonoMethod *getter = NULL;
6032 MonoDomain *domain = mono_domain_get ();
6033 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6034 MonoClass *field_class;
6035 MonoMethodMessage *msg;
6036 MonoArray *out_args;
6037 MonoObject *exc, *res;
6038 char* full_name;
6040 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6042 field_class = mono_class_from_mono_type (field->type);
6044 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6045 gpointer val;
6046 if (field_class->valuetype) {
6047 res = mono_object_new (domain, field_class);
6048 val = ((gchar *) res) + sizeof (MonoObject);
6049 } else {
6050 val = &res;
6052 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6053 return res;
6056 if (!getter) {
6057 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6058 g_assert (getter);
6061 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6062 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6064 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6066 full_name = mono_type_get_full_name (klass);
6067 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6068 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6069 g_free (full_name);
6071 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6073 if (exc) mono_raise_exception ((MonoException *)exc);
6075 if (mono_array_length (out_args) == 0)
6076 res = NULL;
6077 else
6078 res = mono_array_get (out_args, MonoObject *, 0);
6080 return res;
6084 * mono_store_remote_field:
6085 * @this: pointer to an object
6086 * @klass: klass of the object containing @field
6087 * @field: the field to load
6088 * @val: the value/object to store
6090 * This method is called by the runtime on attempts to store fields of
6091 * transparent proxy objects. @this points to such TP, @klass is the class of
6092 * the object containing @field. @val is the new value to store in @field.
6094 void
6095 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
6097 static MonoMethod *setter = NULL;
6098 MonoDomain *domain = mono_domain_get ();
6099 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6100 MonoClass *field_class;
6101 MonoMethodMessage *msg;
6102 MonoArray *out_args;
6103 MonoObject *exc;
6104 MonoObject *arg;
6105 char* full_name;
6107 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6109 field_class = mono_class_from_mono_type (field->type);
6111 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6112 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6113 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6114 return;
6117 if (!setter) {
6118 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6119 g_assert (setter);
6122 if (field_class->valuetype)
6123 arg = mono_value_box (domain, field_class, val);
6124 else
6125 arg = *((MonoObject **)val);
6128 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6129 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6131 full_name = mono_type_get_full_name (klass);
6132 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6133 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6134 mono_array_setref (msg->args, 2, arg);
6135 g_free (full_name);
6137 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6139 if (exc) mono_raise_exception ((MonoException *)exc);
6143 * mono_store_remote_field_new:
6144 * @this:
6145 * @klass:
6146 * @field:
6147 * @arg:
6149 * Missing documentation
6151 void
6152 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6154 static MonoMethod *setter = NULL;
6155 MonoDomain *domain = mono_domain_get ();
6156 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6157 MonoClass *field_class;
6158 MonoMethodMessage *msg;
6159 MonoArray *out_args;
6160 MonoObject *exc;
6161 char* full_name;
6163 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6165 field_class = mono_class_from_mono_type (field->type);
6167 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6168 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6169 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6170 return;
6173 if (!setter) {
6174 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6175 g_assert (setter);
6178 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6179 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6181 full_name = mono_type_get_full_name (klass);
6182 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6183 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6184 mono_array_setref (msg->args, 2, arg);
6185 g_free (full_name);
6187 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6189 if (exc) mono_raise_exception ((MonoException *)exc);
6193 * mono_create_ftnptr:
6195 * Given a function address, create a function descriptor for it.
6196 * This is only needed on some platforms.
6198 gpointer
6199 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6201 return callbacks.create_ftnptr (domain, addr);
6205 * mono_get_addr_from_ftnptr:
6207 * Given a pointer to a function descriptor, return the function address.
6208 * This is only needed on some platforms.
6210 gpointer
6211 mono_get_addr_from_ftnptr (gpointer descr)
6213 return callbacks.get_addr_from_ftnptr (descr);
6217 * mono_string_chars:
6218 * @s: a MonoString
6220 * Returns a pointer to the UCS16 characters stored in the MonoString
6222 gunichar2 *
6223 mono_string_chars (MonoString *s)
6225 return s->chars;
6229 * mono_string_length:
6230 * @s: MonoString
6232 * Returns the lenght in characters of the string
6235 mono_string_length (MonoString *s)
6237 return s->length;
6241 * mono_array_length:
6242 * @array: a MonoArray*
6244 * Returns the total number of elements in the array. This works for
6245 * both vectors and multidimensional arrays.
6247 uintptr_t
6248 mono_array_length (MonoArray *array)
6250 return array->max_length;
6254 * mono_array_addr_with_size:
6255 * @array: a MonoArray*
6256 * @size: size of the array elements
6257 * @idx: index into the array
6259 * Returns the address of the @idx element in the array.
6261 char*
6262 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
6264 return ((char*)(array)->vector) + size * idx;