2010-01-19 Rodrigo Kumpera <rkumpera@novell.com>
[mono.git] / mono / metadata / object.c
blobf65cc0466a0d1744f4aa6311729585296fabdead
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 for (p = class; p != NULL; p = p->parent) {
637 gpointer iter = NULL;
638 while ((field = mono_class_get_fields (p, &iter))) {
639 MonoType *type;
641 if (static_fields) {
642 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
643 continue;
644 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
645 continue;
646 } else {
647 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
648 continue;
650 /* FIXME: should not happen, flag as type load error */
651 if (field->type->byref)
652 break;
654 if (static_fields && field->offset == -1)
655 /* special static */
656 continue;
658 pos = field->offset / sizeof (gpointer);
659 pos += offset;
661 type = mono_type_get_underlying_type (field->type);
662 switch (type->type) {
663 case MONO_TYPE_I:
664 case MONO_TYPE_PTR:
665 case MONO_TYPE_FNPTR:
666 break;
667 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
668 case MONO_TYPE_U:
669 #ifdef HAVE_SGEN_GC
670 break;
671 #else
672 if (class->image != mono_defaults.corlib)
673 break;
674 #endif
675 case MONO_TYPE_STRING:
676 case MONO_TYPE_SZARRAY:
677 case MONO_TYPE_CLASS:
678 case MONO_TYPE_OBJECT:
679 case MONO_TYPE_ARRAY:
680 g_assert ((field->offset % sizeof(gpointer)) == 0);
682 g_assert (pos < size || pos <= max_size);
683 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
684 *max_set = MAX (*max_set, pos);
685 break;
686 case MONO_TYPE_GENERICINST:
687 if (!mono_type_generic_inst_is_valuetype (type)) {
688 g_assert ((field->offset % sizeof(gpointer)) == 0);
690 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
691 *max_set = MAX (*max_set, pos);
692 break;
693 } else {
694 /* fall through */
696 case MONO_TYPE_VALUETYPE: {
697 MonoClass *fclass = mono_class_from_mono_type (field->type);
698 if (fclass->has_references) {
699 /* remove the object header */
700 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
702 break;
704 case MONO_TYPE_I1:
705 case MONO_TYPE_U1:
706 case MONO_TYPE_I2:
707 case MONO_TYPE_U2:
708 case MONO_TYPE_I4:
709 case MONO_TYPE_U4:
710 case MONO_TYPE_I8:
711 case MONO_TYPE_U8:
712 case MONO_TYPE_R4:
713 case MONO_TYPE_R8:
714 case MONO_TYPE_BOOLEAN:
715 case MONO_TYPE_CHAR:
716 break;
717 default:
718 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
719 break;
722 if (static_fields)
723 break;
725 return bitmap;
728 #if 0
730 * similar to the above, but sets the bits in the bitmap for any non-ref field
731 * and ignores static fields
733 static gsize*
734 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
736 MonoClassField *field;
737 MonoClass *p;
738 guint32 pos, pos2;
739 int max_size;
741 max_size = class->instance_size / sizeof (gpointer);
742 if (max_size >= size) {
743 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
746 for (p = class; p != NULL; p = p->parent) {
747 gpointer iter = NULL;
748 while ((field = mono_class_get_fields (p, &iter))) {
749 MonoType *type;
751 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
752 continue;
753 /* FIXME: should not happen, flag as type load error */
754 if (field->type->byref)
755 break;
757 pos = field->offset / sizeof (gpointer);
758 pos += offset;
760 type = mono_type_get_underlying_type (field->type);
761 switch (type->type) {
762 #if SIZEOF_VOID_P == 8
763 case MONO_TYPE_I:
764 case MONO_TYPE_U:
765 case MONO_TYPE_PTR:
766 case MONO_TYPE_FNPTR:
767 #endif
768 case MONO_TYPE_I8:
769 case MONO_TYPE_U8:
770 case MONO_TYPE_R8:
771 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
772 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
773 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
775 /* fall through */
776 #if SIZEOF_VOID_P == 4
777 case MONO_TYPE_I:
778 case MONO_TYPE_U:
779 case MONO_TYPE_PTR:
780 case MONO_TYPE_FNPTR:
781 #endif
782 case MONO_TYPE_I4:
783 case MONO_TYPE_U4:
784 case MONO_TYPE_R4:
785 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
786 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
787 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
789 /* fall through */
790 case MONO_TYPE_CHAR:
791 case MONO_TYPE_I2:
792 case MONO_TYPE_U2:
793 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
794 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
795 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
797 /* fall through */
798 case MONO_TYPE_BOOLEAN:
799 case MONO_TYPE_I1:
800 case MONO_TYPE_U1:
801 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
802 break;
803 case MONO_TYPE_STRING:
804 case MONO_TYPE_SZARRAY:
805 case MONO_TYPE_CLASS:
806 case MONO_TYPE_OBJECT:
807 case MONO_TYPE_ARRAY:
808 break;
809 case MONO_TYPE_GENERICINST:
810 if (!mono_type_generic_inst_is_valuetype (type)) {
811 break;
812 } else {
813 /* fall through */
815 case MONO_TYPE_VALUETYPE: {
816 MonoClass *fclass = mono_class_from_mono_type (field->type);
817 /* remove the object header */
818 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
819 break;
821 default:
822 g_assert_not_reached ();
823 break;
827 return bitmap;
831 * mono_class_insecure_overlapping:
832 * check if a class with explicit layout has references and non-references
833 * fields overlapping.
835 * Returns: TRUE if it is insecure to load the type.
837 gboolean
838 mono_class_insecure_overlapping (MonoClass *klass)
840 int max_set = 0;
841 gsize *bitmap;
842 gsize default_bitmap [4] = {0};
843 gsize *nrbitmap;
844 gsize default_nrbitmap [4] = {0};
845 int i, insecure = FALSE;
846 return FALSE;
848 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
849 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
851 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
852 int idx = i % (sizeof (bitmap [0]) * 8);
853 if (bitmap [idx] & nrbitmap [idx]) {
854 insecure = TRUE;
855 break;
858 if (bitmap != default_bitmap)
859 g_free (bitmap);
860 if (nrbitmap != default_nrbitmap)
861 g_free (nrbitmap);
862 if (insecure) {
863 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
864 return FALSE;
866 return insecure;
868 #endif
870 MonoString*
871 mono_string_alloc (int length)
873 return mono_string_new_size (mono_domain_get (), length);
876 void
877 mono_class_compute_gc_descriptor (MonoClass *class)
879 int max_set = 0;
880 gsize *bitmap;
881 gsize default_bitmap [4] = {0};
882 static gboolean gcj_inited = FALSE;
884 if (!gcj_inited) {
885 mono_loader_lock ();
887 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
888 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
889 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
890 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
892 #ifdef HAVE_GC_GCJ_MALLOC
894 * This is not needed unless the relevant code in mono_get_allocation_ftn () is
895 * turned on.
897 #if 0
898 #ifdef GC_REDIRECT_TO_LOCAL
899 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
900 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
901 #endif
902 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
903 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
904 #endif
906 #endif
907 gcj_inited = TRUE;
908 mono_loader_unlock ();
911 if (!class->inited)
912 mono_class_init (class);
914 if (class->gc_descr_inited)
915 return;
917 class->gc_descr_inited = TRUE;
918 class->gc_descr = GC_NO_DESCRIPTOR;
920 bitmap = default_bitmap;
921 if (class == mono_defaults.string_class) {
922 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
923 } else if (class->rank) {
924 mono_class_compute_gc_descriptor (class->element_class);
925 if (!class->element_class->valuetype) {
926 gsize abm = 1;
927 class->gc_descr = mono_gc_make_descr_for_array (TRUE, &abm, 1, sizeof (gpointer));
928 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
929 class->name_space, class->name);*/
930 } else {
931 /* remove the object header */
932 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
933 class->gc_descr = mono_gc_make_descr_for_array (TRUE, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
934 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
935 class->name_space, class->name);*/
936 if (bitmap != default_bitmap)
937 g_free (bitmap);
939 } else {
940 /*static int count = 0;
941 if (count++ > 58)
942 return;*/
943 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
944 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
946 if (class->gc_descr == GC_NO_DESCRIPTOR)
947 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
949 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
950 if (bitmap != default_bitmap)
951 g_free (bitmap);
956 * field_is_special_static:
957 * @fklass: The MonoClass to look up.
958 * @field: The MonoClassField describing the field.
960 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
961 * SPECIAL_STATIC_NONE otherwise.
963 static gint32
964 field_is_special_static (MonoClass *fklass, MonoClassField *field)
966 MonoCustomAttrInfo *ainfo;
967 int i;
968 ainfo = mono_custom_attrs_from_field (fklass, field);
969 if (!ainfo)
970 return FALSE;
971 for (i = 0; i < ainfo->num_attrs; ++i) {
972 MonoClass *klass = ainfo->attrs [i].ctor->klass;
973 if (klass->image == mono_defaults.corlib) {
974 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
975 mono_custom_attrs_free (ainfo);
976 return SPECIAL_STATIC_THREAD;
978 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
979 mono_custom_attrs_free (ainfo);
980 return SPECIAL_STATIC_CONTEXT;
984 mono_custom_attrs_free (ainfo);
985 return SPECIAL_STATIC_NONE;
988 static gpointer imt_trampoline = NULL;
990 void
991 mono_install_imt_trampoline (gpointer tramp_code)
993 imt_trampoline = tramp_code;
996 static gpointer vtable_trampoline = NULL;
998 void
999 mono_install_vtable_trampoline (gpointer tramp_code)
1001 vtable_trampoline = tramp_code;
1004 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1005 #define mix(a,b,c) { \
1006 a -= c; a ^= rot(c, 4); c += b; \
1007 b -= a; b ^= rot(a, 6); a += c; \
1008 c -= b; c ^= rot(b, 8); b += a; \
1009 a -= c; a ^= rot(c,16); c += b; \
1010 b -= a; b ^= rot(a,19); a += c; \
1011 c -= b; c ^= rot(b, 4); b += a; \
1013 #define final(a,b,c) { \
1014 c ^= b; c -= rot(b,14); \
1015 a ^= c; a -= rot(c,11); \
1016 b ^= a; b -= rot(a,25); \
1017 c ^= b; c -= rot(b,16); \
1018 a ^= c; a -= rot(c,4); \
1019 b ^= a; b -= rot(a,14); \
1020 c ^= b; c -= rot(b,24); \
1024 * mono_method_get_imt_slot:
1026 * The IMT slot is embedded into AOTed code, so this must return the same value
1027 * for the same method across all executions. This means:
1028 * - pointers shouldn't be used as hash values.
1029 * - mono_metadata_str_hash () should be used for hashing strings.
1031 guint32
1032 mono_method_get_imt_slot (MonoMethod *method)
1034 MonoMethodSignature *sig;
1035 int hashes_count;
1036 guint32 *hashes_start, *hashes;
1037 guint32 a, b, c;
1038 int i;
1040 /* This can be used to stress tests the collision code */
1041 //return 0;
1044 * We do this to simplify generic sharing. It will hurt
1045 * performance in cases where a class implements two different
1046 * instantiations of the same generic interface.
1047 * The code in build_imt_slots () depends on this.
1049 if (method->is_inflated)
1050 method = ((MonoMethodInflated*)method)->declaring;
1052 sig = mono_method_signature (method);
1053 hashes_count = sig->param_count + 4;
1054 hashes_start = malloc (hashes_count * sizeof (guint32));
1055 hashes = hashes_start;
1057 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1058 printf ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod\n",
1059 method->klass->name_space, method->klass->name, method->name);
1060 g_assert_not_reached ();
1063 /* Initialize hashes */
1064 hashes [0] = mono_metadata_str_hash (method->klass->name);
1065 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1066 hashes [2] = mono_metadata_str_hash (method->name);
1067 hashes [3] = mono_metadata_type_hash (sig->ret);
1068 for (i = 0; i < sig->param_count; i++) {
1069 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1072 /* Setup internal state */
1073 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1075 /* Handle most of the hashes */
1076 while (hashes_count > 3) {
1077 a += hashes [0];
1078 b += hashes [1];
1079 c += hashes [2];
1080 mix (a,b,c);
1081 hashes_count -= 3;
1082 hashes += 3;
1085 /* Handle the last 3 hashes (all the case statements fall through) */
1086 switch (hashes_count) {
1087 case 3 : c += hashes [2];
1088 case 2 : b += hashes [1];
1089 case 1 : a += hashes [0];
1090 final (a,b,c);
1091 case 0: /* nothing left to add */
1092 break;
1095 free (hashes_start);
1096 /* Report the result */
1097 return c % MONO_IMT_SIZE;
1099 #undef rot
1100 #undef mix
1101 #undef final
1103 #define DEBUG_IMT 0
1105 static void
1106 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1107 guint32 imt_slot = mono_method_get_imt_slot (method);
1108 MonoImtBuilderEntry *entry;
1110 if (slot_num >= 0 && imt_slot != slot_num) {
1111 /* we build just a single imt slot and this is not it */
1112 return;
1115 entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
1116 entry->key = method;
1117 entry->value.vtable_slot = vtable_slot;
1118 entry->next = imt_builder [imt_slot];
1119 if (imt_builder [imt_slot] != NULL) {
1120 entry->children = imt_builder [imt_slot]->children + 1;
1121 if (entry->children == 1) {
1122 mono_stats.imt_slots_with_collisions++;
1123 *imt_collisions_bitmap |= (1 << imt_slot);
1125 } else {
1126 entry->children = 0;
1127 mono_stats.imt_used_slots++;
1129 imt_builder [imt_slot] = entry;
1130 #if DEBUG_IMT
1132 char *method_name = mono_method_full_name (method, TRUE);
1133 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1134 method, method_name, imt_slot, vtable_slot, entry->children);
1135 g_free (method_name);
1137 #endif
1140 #if DEBUG_IMT
1141 static void
1142 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1143 if (e != NULL) {
1144 MonoMethod *method = e->key;
1145 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1146 message,
1147 num,
1148 method,
1149 method->klass->name_space,
1150 method->klass->name,
1151 method->name);
1152 } else {
1153 printf (" * %s: NULL\n", message);
1156 #endif
1158 static int
1159 compare_imt_builder_entries (const void *p1, const void *p2) {
1160 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1161 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1163 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1166 static int
1167 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1169 int count = end - start;
1170 int chunk_start = out_array->len;
1171 if (count < 4) {
1172 int i;
1173 for (i = start; i < end; ++i) {
1174 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1175 item->key = sorted_array [i]->key;
1176 item->value = sorted_array [i]->value;
1177 item->has_target_code = sorted_array [i]->has_target_code;
1178 item->is_equals = TRUE;
1179 if (i < end - 1)
1180 item->check_target_idx = out_array->len + 1;
1181 else
1182 item->check_target_idx = 0;
1183 g_ptr_array_add (out_array, item);
1185 } else {
1186 int middle = start + count / 2;
1187 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1189 item->key = sorted_array [middle]->key;
1190 item->is_equals = FALSE;
1191 g_ptr_array_add (out_array, item);
1192 imt_emit_ir (sorted_array, start, middle, out_array);
1193 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1195 return chunk_start;
1198 static GPtrArray*
1199 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1200 int number_of_entries = entries->children + 1;
1201 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1202 GPtrArray *result = g_ptr_array_new ();
1203 MonoImtBuilderEntry *current_entry;
1204 int i;
1206 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1207 sorted_array [i] = current_entry;
1209 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1211 /*for (i = 0; i < number_of_entries; i++) {
1212 print_imt_entry (" sorted array:", sorted_array [i], i);
1215 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1217 free (sorted_array);
1218 return result;
1221 static gpointer
1222 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1224 if (imt_builder_entry != NULL) {
1225 if (imt_builder_entry->children == 0 && !fail_tramp) {
1226 /* No collision, return the vtable slot contents */
1227 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1228 } else {
1229 /* Collision, build the thunk */
1230 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1231 gpointer result;
1232 int i;
1233 result = imt_thunk_builder (vtable, domain,
1234 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1235 for (i = 0; i < imt_ir->len; ++i)
1236 g_free (g_ptr_array_index (imt_ir, i));
1237 g_ptr_array_free (imt_ir, TRUE);
1238 return result;
1240 } else {
1241 if (fail_tramp)
1242 return fail_tramp;
1243 else
1244 /* Empty slot */
1245 return NULL;
1249 static MonoImtBuilderEntry*
1250 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1253 * LOCKING: requires the loader and domain locks.
1256 static void
1257 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1259 int i;
1260 GSList *list_item;
1261 guint32 imt_collisions_bitmap = 0;
1262 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1263 int method_count = 0;
1264 gboolean record_method_count_for_max_collisions = FALSE;
1265 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1267 #if DEBUG_IMT
1268 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1269 #endif
1270 for (i = 0; i < klass->interface_offsets_count; ++i) {
1271 MonoClass *iface = klass->interfaces_packed [i];
1272 int interface_offset = klass->interface_offsets_packed [i];
1273 int method_slot_in_interface, vt_slot;
1275 if (mono_class_has_variant_generic_params (iface))
1276 has_variant_iface = TRUE;
1278 vt_slot = interface_offset;
1279 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1280 MonoMethod *method;
1282 if (slot_num >= 0 && iface->is_inflated) {
1284 * The imt slot of the method is the same as for its declaring method,
1285 * see the comment in mono_method_get_imt_slot (), so we can
1286 * avoid inflating methods which will be discarded by
1287 * add_imt_builder_entry anyway.
1289 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1290 if (mono_method_get_imt_slot (method) != slot_num) {
1291 vt_slot ++;
1292 continue;
1295 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1296 if (method->is_generic) {
1297 has_generic_virtual = TRUE;
1298 vt_slot ++;
1299 continue;
1302 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1303 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1304 vt_slot ++;
1308 if (extra_interfaces) {
1309 int interface_offset = klass->vtable_size;
1311 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1312 MonoClass* iface = list_item->data;
1313 int method_slot_in_interface;
1314 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1315 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1316 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1318 interface_offset += iface->method.count;
1321 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1322 /* overwrite the imt slot only if we're building all the entries or if
1323 * we're building this specific one
1325 if (slot_num < 0 || i == slot_num) {
1326 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1328 if (entries) {
1329 if (imt_builder [i]) {
1330 MonoImtBuilderEntry *entry;
1332 /* Link entries with imt_builder [i] */
1333 for (entry = entries; entry->next; entry = entry->next) {
1334 #if DEBUG_IMT
1335 MonoMethod *method = (MonoMethod*)entry->key;
1336 char *method_name = mono_method_full_name (method, TRUE);
1337 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1338 g_free (method_name);
1339 #endif
1341 entry->next = imt_builder [i];
1342 entries->children += imt_builder [i]->children + 1;
1344 imt_builder [i] = entries;
1347 if (has_generic_virtual || has_variant_iface) {
1349 * There might be collisions later when the the thunk is expanded.
1351 imt_collisions_bitmap |= (1 << i);
1354 * The IMT thunk might be called with an instance of one of the
1355 * generic virtual methods, so has to fallback to the IMT trampoline.
1357 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], imt_trampoline);
1358 } else {
1359 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1361 #if DEBUG_IMT
1362 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1363 #endif
1366 if (imt_builder [i] != NULL) {
1367 int methods_in_slot = imt_builder [i]->children + 1;
1368 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1369 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1370 record_method_count_for_max_collisions = TRUE;
1372 method_count += methods_in_slot;
1376 mono_stats.imt_number_of_methods += method_count;
1377 if (record_method_count_for_max_collisions) {
1378 mono_stats.imt_method_count_when_max_collisions = method_count;
1381 for (i = 0; i < MONO_IMT_SIZE; i++) {
1382 MonoImtBuilderEntry* entry = imt_builder [i];
1383 while (entry != NULL) {
1384 MonoImtBuilderEntry* next = entry->next;
1385 g_free (entry);
1386 entry = next;
1389 free (imt_builder);
1390 /* we OR the bitmap since we may build just a single imt slot at a time */
1391 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1394 static void
1395 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1396 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1400 * mono_vtable_build_imt_slot:
1401 * @vtable: virtual object table struct
1402 * @imt_slot: slot in the IMT table
1404 * Fill the given @imt_slot in the IMT table of @vtable with
1405 * a trampoline or a thunk for the case of collisions.
1406 * This is part of the internal mono API.
1408 * LOCKING: Take the domain lock.
1410 void
1411 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1413 gpointer *imt = (gpointer*)vtable;
1414 imt -= MONO_IMT_SIZE;
1415 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1417 /* no support for extra interfaces: the proxy objects will need
1418 * to build the complete IMT
1419 * Update and heck needs to ahppen inside the proper domain lock, as all
1420 * the changes made to a MonoVTable.
1422 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1423 mono_domain_lock (vtable->domain);
1424 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1425 if (imt [imt_slot] == imt_trampoline)
1426 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1427 mono_domain_unlock (vtable->domain);
1428 mono_loader_unlock ();
1433 * The first two free list entries both belong to the wait list: The
1434 * first entry is the pointer to the head of the list and the second
1435 * entry points to the last element. That way appending and removing
1436 * the first element are both O(1) operations.
1438 #define NUM_FREE_LISTS 12
1439 #define FIRST_FREE_LIST_SIZE 64
1440 #define MAX_WAIT_LENGTH 50
1441 #define THUNK_THRESHOLD 10
1444 * LOCKING: The domain lock must be held.
1446 static void
1447 init_thunk_free_lists (MonoDomain *domain)
1449 if (domain->thunk_free_lists)
1450 return;
1451 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1454 static int
1455 list_index_for_size (int item_size)
1457 int i = 2;
1458 int size = FIRST_FREE_LIST_SIZE;
1460 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1461 i++;
1462 size <<= 1;
1465 return i;
1469 * mono_method_alloc_generic_virtual_thunk:
1470 * @domain: a domain
1471 * @size: size in bytes
1473 * Allocs size bytes to be used for the code of a generic virtual
1474 * thunk. It's either allocated from the domain's code manager or
1475 * reused from a previously invalidated piece.
1477 * LOCKING: The domain lock must be held.
1479 gpointer
1480 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1482 static gboolean inited = FALSE;
1483 static int generic_virtual_thunks_size = 0;
1485 guint32 *p;
1486 int i;
1487 MonoThunkFreeList **l;
1489 init_thunk_free_lists (domain);
1491 size += sizeof (guint32);
1492 if (size < sizeof (MonoThunkFreeList))
1493 size = sizeof (MonoThunkFreeList);
1495 i = list_index_for_size (size);
1496 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1497 if ((*l)->size >= size) {
1498 MonoThunkFreeList *item = *l;
1499 *l = item->next;
1500 return ((guint32*)item) + 1;
1504 /* no suitable item found - search lists of larger sizes */
1505 while (++i < NUM_FREE_LISTS) {
1506 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1507 if (!item)
1508 continue;
1509 g_assert (item->size > size);
1510 domain->thunk_free_lists [i] = item->next;
1511 return ((guint32*)item) + 1;
1514 /* still nothing found - allocate it */
1515 if (!inited) {
1516 mono_counters_register ("Generic virtual thunk bytes",
1517 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1518 inited = TRUE;
1520 generic_virtual_thunks_size += size;
1522 p = mono_domain_code_reserve (domain, size);
1523 *p = size;
1525 return p + 1;
1529 * LOCKING: The domain lock must be held.
1531 static void
1532 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1534 guint32 *p = code;
1535 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1537 init_thunk_free_lists (domain);
1539 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1540 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1541 int length = item->length;
1542 int i;
1544 /* unlink the first item from the wait list */
1545 domain->thunk_free_lists [0] = item->next;
1546 domain->thunk_free_lists [0]->length = length - 1;
1548 i = list_index_for_size (item->size);
1550 /* put it in the free list */
1551 item->next = domain->thunk_free_lists [i];
1552 domain->thunk_free_lists [i] = item;
1555 l->next = NULL;
1556 if (domain->thunk_free_lists [1]) {
1557 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1558 domain->thunk_free_lists [0]->length++;
1559 } else {
1560 g_assert (!domain->thunk_free_lists [0]);
1562 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1563 domain->thunk_free_lists [0]->length = 1;
1567 typedef struct _GenericVirtualCase {
1568 MonoMethod *method;
1569 gpointer code;
1570 int count;
1571 struct _GenericVirtualCase *next;
1572 } GenericVirtualCase;
1575 * get_generic_virtual_entries:
1577 * Return IMT entries for the generic virtual method instances and
1578 * variant interface methods for vtable slot
1579 * VTABLE_SLOT.
1581 static MonoImtBuilderEntry*
1582 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1584 GenericVirtualCase *list;
1585 MonoImtBuilderEntry *entries;
1587 mono_domain_lock (domain);
1588 if (!domain->generic_virtual_cases)
1589 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1591 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1593 entries = NULL;
1594 for (; list; list = list->next) {
1595 MonoImtBuilderEntry *entry;
1597 if (list->count < THUNK_THRESHOLD)
1598 continue;
1600 entry = g_new0 (MonoImtBuilderEntry, 1);
1601 entry->key = list->method;
1602 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1603 entry->has_target_code = 1;
1604 if (entries)
1605 entry->children = entries->children + 1;
1606 entry->next = entries;
1607 entries = entry;
1610 mono_domain_unlock (domain);
1612 /* FIXME: Leaking memory ? */
1613 return entries;
1617 * mono_method_add_generic_virtual_invocation:
1618 * @domain: a domain
1619 * @vtable_slot: pointer to the vtable slot
1620 * @method: the inflated generic virtual method
1621 * @code: the method's code
1623 * Registers a call via unmanaged code to a generic virtual method
1624 * instantiation or variant interface method. If the number of calls reaches a threshold
1625 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1626 * virtual method thunk.
1628 void
1629 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1630 gpointer *vtable_slot,
1631 MonoMethod *method, gpointer code)
1633 static gboolean inited = FALSE;
1634 static int num_added = 0;
1636 GenericVirtualCase *gvc, *list;
1637 MonoImtBuilderEntry *entries;
1638 int i;
1639 GPtrArray *sorted;
1641 mono_domain_lock (domain);
1642 if (!domain->generic_virtual_cases)
1643 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1645 /* Check whether the case was already added */
1646 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1647 gvc = list;
1648 while (gvc) {
1649 if (gvc->method == method)
1650 break;
1651 gvc = gvc->next;
1654 /* If not found, make a new one */
1655 if (!gvc) {
1656 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1657 gvc->method = method;
1658 gvc->code = code;
1659 gvc->count = 0;
1660 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1662 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1664 if (!inited) {
1665 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1666 inited = TRUE;
1668 num_added++;
1671 if (++gvc->count == THUNK_THRESHOLD) {
1672 gpointer *old_thunk = *vtable_slot;
1674 if ((gpointer)vtable_slot < (gpointer)vtable)
1675 /* Force the rebuild of the thunk at the next call */
1676 *vtable_slot = imt_trampoline;
1677 else {
1678 entries = get_generic_virtual_entries (domain, vtable_slot);
1680 sorted = imt_sort_slot_entries (entries);
1682 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1683 vtable_trampoline);
1685 while (entries) {
1686 MonoImtBuilderEntry *next = entries->next;
1687 g_free (entries);
1688 entries = next;
1691 for (i = 0; i < sorted->len; ++i)
1692 g_free (g_ptr_array_index (sorted, i));
1693 g_ptr_array_free (sorted, TRUE);
1696 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1697 invalidate_generic_virtual_thunk (domain, old_thunk);
1700 mono_domain_unlock (domain);
1703 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error);
1706 * mono_class_vtable:
1707 * @domain: the application domain
1708 * @class: the class to initialize
1710 * VTables are domain specific because we create domain specific code, and
1711 * they contain the domain specific static class data.
1712 * On failure, NULL is returned, and class->exception_type is set.
1714 MonoVTable *
1715 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1717 return mono_class_vtable_full (domain, class, FALSE);
1721 * mono_class_vtable_full:
1722 * @domain: the application domain
1723 * @class: the class to initialize
1724 * @raise_on_error if an exception should be raised on failure or not
1726 * VTables are domain specific because we create domain specific code, and
1727 * they contain the domain specific static class data.
1729 MonoVTable *
1730 mono_class_vtable_full (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1732 MonoClassRuntimeInfo *runtime_info;
1734 g_assert (class);
1736 if (class->exception_type) {
1737 if (raise_on_error)
1738 mono_raise_exception (mono_class_get_exception_for_failure (class));
1739 return NULL;
1742 /* this check can be inlined in jitted code, too */
1743 runtime_info = class->runtime_info;
1744 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1745 return runtime_info->domain_vtables [domain->domain_id];
1746 return mono_class_create_runtime_vtable (domain, class, raise_on_error);
1750 * mono_class_try_get_vtable:
1751 * @domain: the application domain
1752 * @class: the class to initialize
1754 * This function tries to get the associated vtable from @class if
1755 * it was already created.
1757 MonoVTable *
1758 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1760 MonoClassRuntimeInfo *runtime_info;
1762 g_assert (class);
1764 runtime_info = class->runtime_info;
1765 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1766 return runtime_info->domain_vtables [domain->domain_id];
1767 return NULL;
1770 static MonoVTable *
1771 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1773 MonoVTable *vt;
1774 MonoClassRuntimeInfo *runtime_info, *old_info;
1775 MonoClassField *field;
1776 char *t;
1777 int i;
1778 int imt_table_bytes = 0;
1779 guint32 vtable_size, class_size;
1780 guint32 cindex;
1781 gpointer iter;
1782 gpointer *interface_offsets;
1784 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1785 mono_domain_lock (domain);
1786 runtime_info = class->runtime_info;
1787 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1788 mono_domain_unlock (domain);
1789 mono_loader_unlock ();
1790 return runtime_info->domain_vtables [domain->domain_id];
1792 if (!class->inited || class->exception_type) {
1793 if (!mono_class_init (class) || class->exception_type) {
1794 mono_domain_unlock (domain);
1795 mono_loader_unlock ();
1796 if (raise_on_error)
1797 mono_raise_exception (mono_class_get_exception_for_failure (class));
1798 return NULL;
1802 /* Array types require that their element type be valid*/
1803 if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
1804 MonoClass *element_class = class->element_class;
1805 if (!element_class->inited)
1806 mono_class_init (element_class);
1808 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1809 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1810 mono_class_setup_vtable (element_class);
1812 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1813 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1814 if (class->exception_type == MONO_EXCEPTION_NONE)
1815 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1816 mono_domain_unlock (domain);
1817 mono_loader_unlock ();
1818 if (raise_on_error)
1819 mono_raise_exception (mono_class_get_exception_for_failure (class));
1820 return NULL;
1825 * For some classes, mono_class_init () already computed class->vtable_size, and
1826 * that is all that is needed because of the vtable trampolines.
1828 if (!class->vtable_size)
1829 mono_class_setup_vtable (class);
1831 if (class->exception_type) {
1832 mono_domain_unlock (domain);
1833 mono_loader_unlock ();
1834 if (raise_on_error)
1835 mono_raise_exception (mono_class_get_exception_for_failure (class));
1836 return NULL;
1839 if (ARCH_USE_IMT) {
1840 vtable_size = MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1841 if (class->interface_offsets_count) {
1842 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1843 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1844 mono_stats.imt_number_of_tables++;
1845 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1847 } else {
1848 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1849 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1852 mono_stats.used_class_count++;
1853 mono_stats.class_vtable_size += vtable_size;
1854 interface_offsets = mono_domain_alloc0 (domain, vtable_size);
1856 if (ARCH_USE_IMT)
1857 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1858 else
1859 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1860 vt->klass = class;
1861 vt->rank = class->rank;
1862 vt->domain = domain;
1864 mono_class_compute_gc_descriptor (class);
1866 * We can't use typed allocation in the non-root domains, since the
1867 * collector needs the GC descriptor stored in the vtable even after
1868 * the mempool containing the vtable is destroyed when the domain is
1869 * unloaded. An alternative might be to allocate vtables in the GC
1870 * heap, but this does not seem to work (it leads to crashes inside
1871 * libgc). If that approach is tried, two gc descriptors need to be
1872 * allocated for each class: one for the root domain, and one for all
1873 * other domains. The second descriptor should contain a bit for the
1874 * vtable field in MonoObject, since we can no longer assume the
1875 * vtable is reachable by other roots after the appdomain is unloaded.
1877 #ifdef HAVE_BOEHM_GC
1878 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1879 vt->gc_descr = GC_NO_DESCRIPTOR;
1880 else
1881 #endif
1882 vt->gc_descr = class->gc_descr;
1884 if ((class_size = mono_class_data_size (class))) {
1885 if (class->has_static_refs) {
1886 gpointer statics_gc_descr;
1887 int max_set = 0;
1888 gsize default_bitmap [4] = {0};
1889 gsize *bitmap;
1891 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1892 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1893 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1894 vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1895 mono_domain_add_class_static_data (domain, class, vt->data, NULL);
1896 if (bitmap != default_bitmap)
1897 g_free (bitmap);
1898 } else {
1899 vt->data = mono_domain_alloc0 (domain, class_size);
1901 mono_stats.class_static_data_size += class_size;
1904 cindex = -1;
1905 iter = NULL;
1906 while ((field = mono_class_get_fields (class, &iter))) {
1907 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1908 continue;
1909 if (mono_field_is_deleted (field))
1910 continue;
1911 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1912 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1913 if (special_static != SPECIAL_STATIC_NONE) {
1914 guint32 size, offset;
1915 gint32 align;
1916 size = mono_type_size (field->type, &align);
1917 offset = mono_alloc_special_static_data (special_static, size, align);
1918 if (!domain->special_static_fields)
1919 domain->special_static_fields = g_hash_table_new (NULL, NULL);
1920 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
1922 * This marks the field as special static to speed up the
1923 * checks in mono_field_static_get/set_value ().
1925 field->offset = -1;
1926 continue;
1929 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
1930 MonoClass *fklass = mono_class_from_mono_type (field->type);
1931 const char *data = mono_field_get_data (field);
1933 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
1934 t = (char*)vt->data + field->offset;
1935 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
1936 if (!data)
1937 continue;
1938 if (fklass->valuetype) {
1939 memcpy (t, data, mono_class_value_size (fklass, NULL));
1940 } else {
1941 /* it's a pointer type: add check */
1942 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
1943 *t = *(char *)data;
1945 continue;
1949 vt->max_interface_id = class->max_interface_id;
1950 vt->interface_bitmap = class->interface_bitmap;
1952 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
1953 // class->name, class->interface_offsets_count);
1955 if (! ARCH_USE_IMT) {
1956 /* initialize interface offsets */
1957 for (i = 0; i < class->interface_offsets_count; ++i) {
1958 int interface_id = class->interfaces_packed [i]->interface_id;
1959 int slot = class->interface_offsets_packed [i];
1960 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
1964 /* FIXME: class_vtable_hash is basically obsolete now: remove as soon
1965 * as we change the code in appdomain.c to invalidate vtables by
1966 * looking at the possible MonoClasses created for the domain.
1968 g_hash_table_insert (domain->class_vtable_hash, class, vt);
1969 /* class->runtime_info is protected by the loader lock, both when
1970 * it it enlarged and when it is stored info.
1973 old_info = class->runtime_info;
1974 if (old_info && old_info->max_domain >= domain->domain_id) {
1975 /* someone already created a large enough runtime info */
1976 mono_memory_barrier ();
1977 old_info->domain_vtables [domain->domain_id] = vt;
1978 } else {
1979 int new_size = domain->domain_id;
1980 if (old_info)
1981 new_size = MAX (new_size, old_info->max_domain);
1982 new_size++;
1983 /* make the new size a power of two */
1984 i = 2;
1985 while (new_size > i)
1986 i <<= 1;
1987 new_size = i;
1988 /* this is a bounded memory retention issue: may want to
1989 * handle it differently when we'll have a rcu-like system.
1991 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
1992 runtime_info->max_domain = new_size - 1;
1993 /* copy the stuff from the older info */
1994 if (old_info) {
1995 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
1997 runtime_info->domain_vtables [domain->domain_id] = vt;
1998 /* keep this last*/
1999 mono_memory_barrier ();
2000 class->runtime_info = runtime_info;
2003 /* Initialize vtable */
2004 if (vtable_trampoline) {
2005 // This also covers the AOT case
2006 for (i = 0; i < class->vtable_size; ++i) {
2007 vt->vtable [i] = vtable_trampoline;
2009 } else {
2010 mono_class_setup_vtable (class);
2012 for (i = 0; i < class->vtable_size; ++i) {
2013 MonoMethod *cm;
2015 if ((cm = class->vtable [i]))
2016 vt->vtable [i] = vtable_trampoline? vtable_trampoline: arch_create_jit_trampoline (cm);
2020 if (ARCH_USE_IMT && imt_table_bytes) {
2021 /* Now that the vtable is full, we can actually fill up the IMT */
2022 if (imt_trampoline) {
2023 /* lazy construction of the IMT entries enabled */
2024 for (i = 0; i < MONO_IMT_SIZE; ++i)
2025 interface_offsets [i] = imt_trampoline;
2026 } else {
2027 build_imt (class, vt, domain, interface_offsets, NULL);
2031 mono_domain_unlock (domain);
2032 mono_loader_unlock ();
2034 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
2035 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
2036 mono_raise_exception (mono_class_get_exception_for_failure (class));
2038 /* make sure the parent is initialized */
2039 /*FIXME shouldn't this fail the current type?*/
2040 if (class->parent)
2041 mono_class_vtable_full (domain, class->parent, raise_on_error);
2043 /*FIXME check for OOM*/
2044 vt->type = mono_type_get_object (domain, &class->byval_arg);
2045 if (class->contextbound)
2046 vt->remote = 1;
2047 else
2048 vt->remote = 0;
2050 return vt;
2054 * mono_class_proxy_vtable:
2055 * @domain: the application domain
2056 * @remove_class: the remote class
2058 * Creates a vtable for transparent proxies. It is basically
2059 * a copy of the real vtable of the class wrapped in @remote_class,
2060 * but all function pointers invoke the remoting functions, and
2061 * vtable->klass points to the transparent proxy class, and not to @class.
2063 static MonoVTable *
2064 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2066 MonoError error;
2067 MonoVTable *vt, *pvt;
2068 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2069 MonoClass *k;
2070 GSList *extra_interfaces = NULL;
2071 MonoClass *class = remote_class->proxy_class;
2072 gpointer *interface_offsets;
2074 vt = mono_class_vtable (domain, class);
2075 g_assert (vt); /*FIXME property handle failure*/
2076 max_interface_id = vt->max_interface_id;
2078 /* Calculate vtable space for extra interfaces */
2079 for (j = 0; j < remote_class->interface_count; j++) {
2080 MonoClass* iclass = remote_class->interfaces[j];
2081 GPtrArray *ifaces;
2082 int method_count;
2084 /*FIXME test for interfaces with variant generic arguments*/
2085 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2086 continue; /* interface implemented by the class */
2087 if (g_slist_find (extra_interfaces, iclass))
2088 continue;
2090 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2092 method_count = mono_class_num_methods (iclass);
2094 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2095 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2096 if (ifaces) {
2097 for (i = 0; i < ifaces->len; ++i) {
2098 MonoClass *ic = g_ptr_array_index (ifaces, i);
2099 /*FIXME test for interfaces with variant generic arguments*/
2100 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2101 continue; /* interface implemented by the class */
2102 if (g_slist_find (extra_interfaces, ic))
2103 continue;
2104 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2105 method_count += mono_class_num_methods (ic);
2107 g_ptr_array_free (ifaces, TRUE);
2110 extra_interface_vtsize += method_count * sizeof (gpointer);
2111 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2114 if (ARCH_USE_IMT) {
2115 mono_stats.imt_number_of_tables++;
2116 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
2117 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
2118 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2119 } else {
2120 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
2121 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2124 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2126 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
2127 if (ARCH_USE_IMT)
2128 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
2129 else
2130 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
2131 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2133 pvt->klass = mono_defaults.transparent_proxy_class;
2134 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2135 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2137 /* initialize vtable */
2138 mono_class_setup_vtable (class);
2139 for (i = 0; i < class->vtable_size; ++i) {
2140 MonoMethod *cm;
2142 if ((cm = class->vtable [i]))
2143 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2144 else
2145 pvt->vtable [i] = NULL;
2148 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2149 /* create trampolines for abstract methods */
2150 for (k = class; k; k = k->parent) {
2151 MonoMethod* m;
2152 gpointer iter = NULL;
2153 while ((m = mono_class_get_methods (k, &iter)))
2154 if (!pvt->vtable [m->slot])
2155 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2159 pvt->max_interface_id = max_interface_id;
2160 pvt->interface_bitmap = mono_domain_alloc0 (domain, sizeof (guint8) * (max_interface_id/8 + 1 ));
2162 if (! ARCH_USE_IMT) {
2163 /* initialize interface offsets */
2164 for (i = 0; i < class->interface_offsets_count; ++i) {
2165 int interface_id = class->interfaces_packed [i]->interface_id;
2166 int slot = class->interface_offsets_packed [i];
2167 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2170 for (i = 0; i < class->interface_offsets_count; ++i) {
2171 int interface_id = class->interfaces_packed [i]->interface_id;
2172 pvt->interface_bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2175 if (extra_interfaces) {
2176 int slot = class->vtable_size;
2177 MonoClass* interf;
2178 gpointer iter;
2179 MonoMethod* cm;
2180 GSList *list_item;
2182 /* Create trampolines for the methods of the interfaces */
2183 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2184 interf = list_item->data;
2186 if (! ARCH_USE_IMT) {
2187 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2189 pvt->interface_bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2191 iter = NULL;
2192 j = 0;
2193 while ((cm = mono_class_get_methods (interf, &iter)))
2194 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2196 slot += mono_class_num_methods (interf);
2198 if (! ARCH_USE_IMT) {
2199 g_slist_free (extra_interfaces);
2203 if (ARCH_USE_IMT) {
2204 /* Now that the vtable is full, we can actually fill up the IMT */
2205 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2206 if (extra_interfaces) {
2207 g_slist_free (extra_interfaces);
2211 return pvt;
2215 * mono_class_field_is_special_static:
2217 * Returns whether @field is a thread/context static field.
2219 gboolean
2220 mono_class_field_is_special_static (MonoClassField *field)
2222 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2223 return FALSE;
2224 if (mono_field_is_deleted (field))
2225 return FALSE;
2226 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2227 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2228 return TRUE;
2230 return FALSE;
2234 * mono_class_has_special_static_fields:
2236 * Returns whenever @klass has any thread/context static fields.
2238 gboolean
2239 mono_class_has_special_static_fields (MonoClass *klass)
2241 MonoClassField *field;
2242 gpointer iter;
2244 iter = NULL;
2245 while ((field = mono_class_get_fields (klass, &iter))) {
2246 g_assert (field->parent == klass);
2247 if (mono_class_field_is_special_static (field))
2248 return TRUE;
2251 return FALSE;
2255 * create_remote_class_key:
2256 * Creates an array of pointers that can be used as a hash key for a remote class.
2257 * The first element of the array is the number of pointers.
2259 static gpointer*
2260 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2262 gpointer *key;
2263 int i, j;
2265 if (remote_class == NULL) {
2266 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2267 key = g_malloc (sizeof(gpointer) * 3);
2268 key [0] = GINT_TO_POINTER (2);
2269 key [1] = mono_defaults.marshalbyrefobject_class;
2270 key [2] = extra_class;
2271 } else {
2272 key = g_malloc (sizeof(gpointer) * 2);
2273 key [0] = GINT_TO_POINTER (1);
2274 key [1] = extra_class;
2276 } else {
2277 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2278 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2279 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2280 key [1] = remote_class->proxy_class;
2282 // Keep the list of interfaces sorted
2283 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2284 if (extra_class && remote_class->interfaces [i] > extra_class) {
2285 key [j++] = extra_class;
2286 extra_class = NULL;
2288 key [j] = remote_class->interfaces [i];
2290 if (extra_class)
2291 key [j] = extra_class;
2292 } else {
2293 // Replace the old class. The interface list is the same
2294 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2295 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2296 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2297 for (i = 0; i < remote_class->interface_count; i++)
2298 key [2 + i] = remote_class->interfaces [i];
2302 return key;
2306 * copy_remote_class_key:
2308 * Make a copy of KEY in the domain and return the copy.
2310 static gpointer*
2311 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2313 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2314 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2316 memcpy (mp_key, key, key_size);
2318 return mp_key;
2322 * mono_remote_class:
2323 * @domain: the application domain
2324 * @class_name: name of the remote class
2326 * Creates and initializes a MonoRemoteClass object for a remote type.
2328 * Can raise an exception on failure.
2330 MonoRemoteClass*
2331 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2333 MonoError error;
2334 MonoRemoteClass *rc;
2335 gpointer* key, *mp_key;
2336 char *name;
2338 key = create_remote_class_key (NULL, proxy_class);
2340 mono_domain_lock (domain);
2341 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2343 if (rc) {
2344 g_free (key);
2345 mono_domain_unlock (domain);
2346 return rc;
2349 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2350 if (!mono_error_ok (&error)) {
2351 g_free (key);
2352 mono_domain_unlock (domain);
2353 mono_error_raise_exception (&error);
2356 mp_key = copy_remote_class_key (domain, key);
2357 g_free (key);
2358 key = mp_key;
2360 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2361 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2362 rc->interface_count = 1;
2363 rc->interfaces [0] = proxy_class;
2364 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2365 } else {
2366 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2367 rc->interface_count = 0;
2368 rc->proxy_class = proxy_class;
2371 rc->default_vtable = NULL;
2372 rc->xdomain_vtable = NULL;
2373 rc->proxy_class_name = name;
2374 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2376 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2378 mono_domain_unlock (domain);
2379 return rc;
2383 * clone_remote_class:
2384 * Creates a copy of the remote_class, adding the provided class or interface
2386 static MonoRemoteClass*
2387 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2389 MonoRemoteClass *rc;
2390 gpointer* key, *mp_key;
2392 key = create_remote_class_key (remote_class, extra_class);
2393 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2394 if (rc != NULL) {
2395 g_free (key);
2396 return rc;
2399 mp_key = copy_remote_class_key (domain, key);
2400 g_free (key);
2401 key = mp_key;
2403 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2404 int i,j;
2405 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2406 rc->proxy_class = remote_class->proxy_class;
2407 rc->interface_count = remote_class->interface_count + 1;
2409 // Keep the list of interfaces sorted, since the hash key of
2410 // the remote class depends on this
2411 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2412 if (remote_class->interfaces [i] > extra_class && i == j)
2413 rc->interfaces [j++] = extra_class;
2414 rc->interfaces [j] = remote_class->interfaces [i];
2416 if (i == j)
2417 rc->interfaces [j] = extra_class;
2418 } else {
2419 // Replace the old class. The interface array is the same
2420 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2421 rc->proxy_class = extra_class;
2422 rc->interface_count = remote_class->interface_count;
2423 if (rc->interface_count > 0)
2424 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2427 rc->default_vtable = NULL;
2428 rc->xdomain_vtable = NULL;
2429 rc->proxy_class_name = remote_class->proxy_class_name;
2431 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2433 return rc;
2436 gpointer
2437 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2439 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2440 mono_domain_lock (domain);
2441 if (rp->target_domain_id != -1) {
2442 if (remote_class->xdomain_vtable == NULL)
2443 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2444 mono_domain_unlock (domain);
2445 mono_loader_unlock ();
2446 return remote_class->xdomain_vtable;
2448 if (remote_class->default_vtable == NULL) {
2449 MonoType *type;
2450 MonoClass *klass;
2451 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2452 klass = mono_class_from_mono_type (type);
2453 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
2454 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2455 else
2456 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2459 mono_domain_unlock (domain);
2460 mono_loader_unlock ();
2461 return remote_class->default_vtable;
2465 * mono_upgrade_remote_class:
2466 * @domain: the application domain
2467 * @tproxy: the proxy whose remote class has to be upgraded.
2468 * @klass: class to which the remote class can be casted.
2470 * Updates the vtable of the remote class by adding the necessary method slots
2471 * and interface offsets so it can be safely casted to klass. klass can be a
2472 * class or an interface.
2474 void
2475 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2477 MonoTransparentProxy *tproxy;
2478 MonoRemoteClass *remote_class;
2479 gboolean redo_vtable;
2481 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2482 mono_domain_lock (domain);
2484 tproxy = (MonoTransparentProxy*) proxy_object;
2485 remote_class = tproxy->remote_class;
2487 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2488 int i;
2489 redo_vtable = TRUE;
2490 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2491 if (remote_class->interfaces [i] == klass)
2492 redo_vtable = FALSE;
2494 else {
2495 redo_vtable = (remote_class->proxy_class != klass);
2498 if (redo_vtable) {
2499 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2500 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2503 mono_domain_unlock (domain);
2504 mono_loader_unlock ();
2509 * mono_object_get_virtual_method:
2510 * @obj: object to operate on.
2511 * @method: method
2513 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2514 * the instance of a callvirt of method.
2516 MonoMethod*
2517 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2519 MonoClass *klass;
2520 MonoMethod **vtable;
2521 gboolean is_proxy;
2522 MonoMethod *res = NULL;
2524 klass = mono_object_class (obj);
2525 if (klass == mono_defaults.transparent_proxy_class) {
2526 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2527 is_proxy = TRUE;
2528 } else {
2529 is_proxy = FALSE;
2532 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2533 return method;
2535 mono_class_setup_vtable (klass);
2536 vtable = klass->vtable;
2538 if (method->slot == -1) {
2539 /* method->slot might not be set for instances of generic methods */
2540 if (method->is_inflated) {
2541 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2542 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2543 } else {
2544 if (!is_proxy)
2545 g_assert_not_reached ();
2549 /* check method->slot is a valid index: perform isinstance? */
2550 if (method->slot != -1) {
2551 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2552 if (!is_proxy) {
2553 gboolean variance_used = FALSE;
2554 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2555 g_assert (iface_offset > 0);
2556 res = vtable [iface_offset + method->slot];
2558 } else {
2559 res = vtable [method->slot];
2563 if (is_proxy) {
2564 /* It may be an interface, abstract class method or generic method */
2565 if (!res || mono_method_signature (res)->generic_param_count)
2566 res = method;
2568 /* generic methods demand invoke_with_check */
2569 if (mono_method_signature (res)->generic_param_count)
2570 res = mono_marshal_get_remoting_invoke_with_check (res);
2571 else {
2572 #ifndef DISABLE_COM
2573 if (klass == mono_defaults.com_object_class || klass->is_com_object)
2574 res = mono_cominterop_get_invoke (res);
2575 else
2576 #endif
2577 res = mono_marshal_get_remoting_invoke (res);
2579 } else {
2580 if (method->is_inflated) {
2581 /* Have to inflate the result */
2582 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2586 g_assert (res);
2588 return res;
2591 static MonoObject*
2592 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2594 g_error ("runtime invoke called on uninitialized runtime");
2595 return NULL;
2598 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2601 * mono_runtime_invoke:
2602 * @method: method to invoke
2603 * @obJ: object instance
2604 * @params: arguments to the method
2605 * @exc: exception information.
2607 * Invokes the method represented by @method on the object @obj.
2609 * obj is the 'this' pointer, it should be NULL for static
2610 * methods, a MonoObject* for object instances and a pointer to
2611 * the value type for value types.
2613 * The params array contains the arguments to the method with the
2614 * same convention: MonoObject* pointers for object instances and
2615 * pointers to the value type otherwise.
2617 * From unmanaged code you'll usually use the
2618 * mono_runtime_invoke() variant.
2620 * Note that this function doesn't handle virtual methods for
2621 * you, it will exec the exact method you pass: we still need to
2622 * expose a function to lookup the derived class implementation
2623 * of a virtual method (there are examples of this in the code,
2624 * though).
2626 * You can pass NULL as the exc argument if you don't want to
2627 * catch exceptions, otherwise, *exc will be set to the exception
2628 * thrown, if any. if an exception is thrown, you can't use the
2629 * MonoObject* result from the function.
2631 * If the method returns a value type, it is boxed in an object
2632 * reference.
2634 MonoObject*
2635 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2637 MonoObject *result;
2639 if (mono_runtime_get_no_exec ())
2640 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2642 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2643 mono_profiler_method_start_invoke (method);
2645 result = default_mono_runtime_invoke (method, obj, params, exc);
2647 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2648 mono_profiler_method_end_invoke (method);
2650 return result;
2654 * mono_method_get_unmanaged_thunk:
2655 * @method: method to generate a thunk for.
2657 * Returns an unmanaged->managed thunk that can be used to call
2658 * a managed method directly from C.
2660 * The thunk's C signature closely matches the managed signature:
2662 * C#: public bool Equals (object obj);
2663 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2664 * MonoObject*, MonoException**);
2666 * The 1st ("this") parameter must not be used with static methods:
2668 * C#: public static bool ReferenceEquals (object a, object b);
2669 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2670 * MonoException**);
2672 * The last argument must be a non-null pointer of a MonoException* pointer.
2673 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2674 * exception has been thrown in managed code. Otherwise it will point
2675 * to the MonoException* caught by the thunk. In this case, the result of
2676 * the thunk is undefined:
2678 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2679 * MonoException *ex = NULL;
2680 * Equals func = mono_method_get_unmanaged_thunk (method);
2681 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2682 * if (ex) {
2683 * // handle exception
2686 * The calling convention of the thunk matches the platform's default
2687 * convention. This means that under Windows, C declarations must
2688 * contain the __stdcall attribute:
2690 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2691 * MonoObject*, MonoException**);
2693 * LIMITATIONS
2695 * Value type arguments and return values are treated as they were objects:
2697 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2698 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2700 * Arguments must be properly boxed upon trunk's invocation, while return
2701 * values must be unboxed.
2703 gpointer
2704 mono_method_get_unmanaged_thunk (MonoMethod *method)
2706 method = mono_marshal_get_thunk_invoke_wrapper (method);
2707 return mono_compile_method (method);
2710 static void
2711 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2713 int t;
2714 if (type->byref) {
2715 /* object fields cannot be byref, so we don't need a
2716 wbarrier here */
2717 gpointer *p = (gpointer*)dest;
2718 *p = value;
2719 return;
2721 t = type->type;
2722 handle_enum:
2723 switch (t) {
2724 case MONO_TYPE_BOOLEAN:
2725 case MONO_TYPE_I1:
2726 case MONO_TYPE_U1: {
2727 guint8 *p = (guint8*)dest;
2728 *p = value ? *(guint8*)value : 0;
2729 return;
2731 case MONO_TYPE_I2:
2732 case MONO_TYPE_U2:
2733 case MONO_TYPE_CHAR: {
2734 guint16 *p = (guint16*)dest;
2735 *p = value ? *(guint16*)value : 0;
2736 return;
2738 #if SIZEOF_VOID_P == 4
2739 case MONO_TYPE_I:
2740 case MONO_TYPE_U:
2741 #endif
2742 case MONO_TYPE_I4:
2743 case MONO_TYPE_U4: {
2744 gint32 *p = (gint32*)dest;
2745 *p = value ? *(gint32*)value : 0;
2746 return;
2748 #if SIZEOF_VOID_P == 8
2749 case MONO_TYPE_I:
2750 case MONO_TYPE_U:
2751 #endif
2752 case MONO_TYPE_I8:
2753 case MONO_TYPE_U8: {
2754 gint64 *p = (gint64*)dest;
2755 *p = value ? *(gint64*)value : 0;
2756 return;
2758 case MONO_TYPE_R4: {
2759 float *p = (float*)dest;
2760 *p = value ? *(float*)value : 0;
2761 return;
2763 case MONO_TYPE_R8: {
2764 double *p = (double*)dest;
2765 *p = value ? *(double*)value : 0;
2766 return;
2768 case MONO_TYPE_STRING:
2769 case MONO_TYPE_SZARRAY:
2770 case MONO_TYPE_CLASS:
2771 case MONO_TYPE_OBJECT:
2772 case MONO_TYPE_ARRAY:
2773 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2774 return;
2775 case MONO_TYPE_FNPTR:
2776 case MONO_TYPE_PTR: {
2777 gpointer *p = (gpointer*)dest;
2778 *p = deref_pointer? *(gpointer*)value: value;
2779 return;
2781 case MONO_TYPE_VALUETYPE:
2782 /* note that 't' and 'type->type' can be different */
2783 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2784 t = mono_class_enum_basetype (type->data.klass)->type;
2785 goto handle_enum;
2786 } else {
2787 MonoClass *class = mono_class_from_mono_type (type);
2788 int size = mono_class_value_size (class, NULL);
2789 if (value == NULL)
2790 memset (dest, 0, size);
2791 else
2792 mono_gc_wbarrier_value_copy (dest, value, 1, class);
2794 return;
2795 case MONO_TYPE_GENERICINST:
2796 t = type->data.generic_class->container_class->byval_arg.type;
2797 goto handle_enum;
2798 default:
2799 g_warning ("got type %x", type->type);
2800 g_assert_not_reached ();
2805 * mono_field_set_value:
2806 * @obj: Instance object
2807 * @field: MonoClassField describing the field to set
2808 * @value: The value to be set
2810 * Sets the value of the field described by @field in the object instance @obj
2811 * to the value passed in @value. This method should only be used for instance
2812 * fields. For static fields, use mono_field_static_set_value.
2814 * The value must be on the native format of the field type.
2816 void
2817 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2819 void *dest;
2821 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2823 dest = (char*)obj + field->offset;
2824 set_value (field->type, dest, value, FALSE);
2828 * mono_field_static_set_value:
2829 * @field: MonoClassField describing the field to set
2830 * @value: The value to be set
2832 * Sets the value of the static field described by @field
2833 * to the value passed in @value.
2835 * The value must be on the native format of the field type.
2837 void
2838 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2840 void *dest;
2842 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2843 /* you cant set a constant! */
2844 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2846 if (field->offset == -1) {
2847 /* Special static */
2848 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2849 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2850 } else {
2851 dest = (char*)vt->data + field->offset;
2853 set_value (field->type, dest, value, FALSE);
2856 /* Used by the debugger */
2857 void *
2858 mono_vtable_get_static_field_data (MonoVTable *vt)
2860 return vt->data;
2864 * mono_field_get_value:
2865 * @obj: Object instance
2866 * @field: MonoClassField describing the field to fetch information from
2867 * @value: pointer to the location where the value will be stored
2869 * Use this routine to get the value of the field @field in the object
2870 * passed.
2872 * The pointer provided by value must be of the field type, for reference
2873 * types this is a MonoObject*, for value types its the actual pointer to
2874 * the value type.
2876 * For example:
2877 * int i;
2878 * mono_field_get_value (obj, int_field, &i);
2880 void
2881 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
2883 void *src;
2885 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2887 src = (char*)obj + field->offset;
2888 set_value (field->type, value, src, TRUE);
2892 * mono_field_get_value_object:
2893 * @domain: domain where the object will be created (if boxing)
2894 * @field: MonoClassField describing the field to fetch information from
2895 * @obj: The object instance for the field.
2897 * Returns: a new MonoObject with the value from the given field. If the
2898 * field represents a value type, the value is boxed.
2901 MonoObject *
2902 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
2904 MonoObject *o;
2905 MonoClass *klass;
2906 MonoVTable *vtable = NULL;
2907 gchar *v;
2908 gboolean is_static = FALSE;
2909 gboolean is_ref = FALSE;
2911 switch (field->type->type) {
2912 case MONO_TYPE_STRING:
2913 case MONO_TYPE_OBJECT:
2914 case MONO_TYPE_CLASS:
2915 case MONO_TYPE_ARRAY:
2916 case MONO_TYPE_SZARRAY:
2917 is_ref = TRUE;
2918 break;
2919 case MONO_TYPE_U1:
2920 case MONO_TYPE_I1:
2921 case MONO_TYPE_BOOLEAN:
2922 case MONO_TYPE_U2:
2923 case MONO_TYPE_I2:
2924 case MONO_TYPE_CHAR:
2925 case MONO_TYPE_U:
2926 case MONO_TYPE_I:
2927 case MONO_TYPE_U4:
2928 case MONO_TYPE_I4:
2929 case MONO_TYPE_R4:
2930 case MONO_TYPE_U8:
2931 case MONO_TYPE_I8:
2932 case MONO_TYPE_R8:
2933 case MONO_TYPE_VALUETYPE:
2934 is_ref = field->type->byref;
2935 break;
2936 case MONO_TYPE_GENERICINST:
2937 is_ref = !field->type->data.generic_class->container_class->valuetype;
2938 break;
2939 default:
2940 g_error ("type 0x%x not handled in "
2941 "mono_field_get_value_object", field->type->type);
2942 return NULL;
2945 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2946 is_static = TRUE;
2947 vtable = mono_class_vtable (domain, field->parent);
2948 if (!vtable) {
2949 char *name = mono_type_get_full_name (field->parent);
2950 g_warning ("Could not retrieve the vtable for type %s in mono_field_get_value_object", name);
2951 g_free (name);
2952 return NULL;
2954 if (!vtable->initialized)
2955 mono_runtime_class_init (vtable);
2958 if (is_ref) {
2959 if (is_static) {
2960 mono_field_static_get_value (vtable, field, &o);
2961 } else {
2962 mono_field_get_value (obj, field, &o);
2964 return o;
2967 /* boxed value type */
2968 klass = mono_class_from_mono_type (field->type);
2969 o = mono_object_new (domain, klass);
2970 v = ((gchar *) o) + sizeof (MonoObject);
2971 if (is_static) {
2972 mono_field_static_get_value (vtable, field, v);
2973 } else {
2974 mono_field_get_value (obj, field, v);
2977 return o;
2981 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
2983 int retval = 0;
2984 const char *p = blob;
2985 mono_metadata_decode_blob_size (p, &p);
2987 switch (type) {
2988 case MONO_TYPE_BOOLEAN:
2989 case MONO_TYPE_U1:
2990 case MONO_TYPE_I1:
2991 *(guint8 *) value = *p;
2992 break;
2993 case MONO_TYPE_CHAR:
2994 case MONO_TYPE_U2:
2995 case MONO_TYPE_I2:
2996 *(guint16*) value = read16 (p);
2997 break;
2998 case MONO_TYPE_U4:
2999 case MONO_TYPE_I4:
3000 *(guint32*) value = read32 (p);
3001 break;
3002 case MONO_TYPE_U8:
3003 case MONO_TYPE_I8:
3004 *(guint64*) value = read64 (p);
3005 break;
3006 case MONO_TYPE_R4:
3007 readr4 (p, (float*) value);
3008 break;
3009 case MONO_TYPE_R8:
3010 readr8 (p, (double*) value);
3011 break;
3012 case MONO_TYPE_STRING:
3013 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3014 break;
3015 case MONO_TYPE_CLASS:
3016 *(gpointer*) value = NULL;
3017 break;
3018 default:
3019 retval = -1;
3020 g_warning ("type 0x%02x should not be in constant table", type);
3022 return retval;
3025 static void
3026 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3028 MonoTypeEnum def_type;
3029 const char* data;
3031 data = mono_class_get_field_default_value (field, &def_type);
3032 mono_get_constant_value_from_blob (domain, def_type, data, value);
3036 * mono_field_static_get_value:
3037 * @vt: vtable to the object
3038 * @field: MonoClassField describing the field to fetch information from
3039 * @value: where the value is returned
3041 * Use this routine to get the value of the static field @field value.
3043 * The pointer provided by value must be of the field type, for reference
3044 * types this is a MonoObject*, for value types its the actual pointer to
3045 * the value type.
3047 * For example:
3048 * int i;
3049 * mono_field_static_get_value (vt, int_field, &i);
3051 void
3052 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3054 void *src;
3056 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3058 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3059 get_default_field_value (vt->domain, field, value);
3060 return;
3063 if (field->offset == -1) {
3064 /* Special static */
3065 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3066 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3067 } else {
3068 src = (char*)vt->data + field->offset;
3070 set_value (field->type, value, src, TRUE);
3074 * mono_property_set_value:
3075 * @prop: MonoProperty to set
3076 * @obj: instance object on which to act
3077 * @params: parameters to pass to the propery
3078 * @exc: optional exception
3080 * Invokes the property's set method with the given arguments on the
3081 * object instance obj (or NULL for static properties).
3083 * You can pass NULL as the exc argument if you don't want to
3084 * catch exceptions, otherwise, *exc will be set to the exception
3085 * thrown, if any. if an exception is thrown, you can't use the
3086 * MonoObject* result from the function.
3088 void
3089 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3091 default_mono_runtime_invoke (prop->set, obj, params, exc);
3095 * mono_property_get_value:
3096 * @prop: MonoProperty to fetch
3097 * @obj: instance object on which to act
3098 * @params: parameters to pass to the propery
3099 * @exc: optional exception
3101 * Invokes the property's get method with the given arguments on the
3102 * object instance obj (or NULL for static properties).
3104 * You can pass NULL as the exc argument if you don't want to
3105 * catch exceptions, otherwise, *exc will be set to the exception
3106 * thrown, if any. if an exception is thrown, you can't use the
3107 * MonoObject* result from the function.
3109 * Returns: the value from invoking the get method on the property.
3111 MonoObject*
3112 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3114 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3118 * mono_nullable_init:
3119 * @buf: The nullable structure to initialize.
3120 * @value: the value to initialize from
3121 * @klass: the type for the object
3123 * Initialize the nullable structure pointed to by @buf from @value which
3124 * should be a boxed value type. The size of @buf should be able to hold
3125 * as much data as the @klass->instance_size (which is the number of bytes
3126 * that will be copies).
3128 * Since Nullables have variable structure, we can not define a C
3129 * structure for them.
3131 void
3132 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3134 MonoClass *param_class = klass->cast_class;
3136 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3137 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3139 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3140 if (value) {
3141 if (param_class->has_references)
3142 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3143 else
3144 memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3145 } else {
3146 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
3151 * mono_nullable_box:
3152 * @buf: The buffer representing the data to be boxed
3153 * @klass: the type to box it as.
3155 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3156 * @buf.
3158 MonoObject*
3159 mono_nullable_box (guint8 *buf, MonoClass *klass)
3161 MonoClass *param_class = klass->cast_class;
3163 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3164 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3166 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3167 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3168 if (param_class->has_references)
3169 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3170 else
3171 memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3172 return o;
3174 else
3175 return NULL;
3179 * mono_get_delegate_invoke:
3180 * @klass: The delegate class
3182 * Returns: the MonoMethod for the "Invoke" method in the delegate klass
3184 MonoMethod *
3185 mono_get_delegate_invoke (MonoClass *klass)
3187 MonoMethod *im;
3189 /* This is called at runtime, so avoid the slower search in metadata */
3190 mono_class_setup_methods (klass);
3191 if (klass->exception_type)
3192 return NULL;
3193 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3194 g_assert (im);
3196 return im;
3200 * mono_runtime_delegate_invoke:
3201 * @delegate: pointer to a delegate object.
3202 * @params: parameters for the delegate.
3203 * @exc: Pointer to the exception result.
3205 * Invokes the delegate method @delegate with the parameters provided.
3207 * You can pass NULL as the exc argument if you don't want to
3208 * catch exceptions, otherwise, *exc will be set to the exception
3209 * thrown, if any. if an exception is thrown, you can't use the
3210 * MonoObject* result from the function.
3212 MonoObject*
3213 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3215 MonoMethod *im;
3217 im = mono_get_delegate_invoke (delegate->vtable->klass);
3218 g_assert (im);
3220 return mono_runtime_invoke (im, delegate, params, exc);
3223 static char **main_args = NULL;
3224 static int num_main_args;
3227 * mono_runtime_get_main_args:
3229 * Returns: a MonoArray with the arguments passed to the main program
3231 MonoArray*
3232 mono_runtime_get_main_args (void)
3234 MonoArray *res;
3235 int i;
3236 MonoDomain *domain = mono_domain_get ();
3238 if (!main_args)
3239 return NULL;
3241 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3243 for (i = 0; i < num_main_args; ++i)
3244 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3246 return res;
3249 static void
3250 fire_process_exit_event (void)
3252 MonoClassField *field;
3253 MonoDomain *domain = mono_domain_get ();
3254 gpointer pa [2];
3255 MonoObject *delegate, *exc;
3257 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
3258 g_assert (field);
3260 if (domain != mono_get_root_domain ())
3261 return;
3263 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
3264 if (delegate == NULL)
3265 return;
3267 pa [0] = domain;
3268 pa [1] = NULL;
3269 mono_runtime_delegate_invoke (delegate, pa, &exc);
3273 * mono_runtime_run_main:
3274 * @method: the method to start the application with (usually Main)
3275 * @argc: number of arguments from the command line
3276 * @argv: array of strings from the command line
3277 * @exc: excetption results
3279 * Execute a standard Main() method (argc/argv contains the
3280 * executable name). This method also sets the command line argument value
3281 * needed by System.Environment.
3286 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3287 MonoObject **exc)
3289 int i;
3290 MonoArray *args = NULL;
3291 MonoDomain *domain = mono_domain_get ();
3292 gchar *utf8_fullpath;
3293 int result;
3295 g_assert (method != NULL);
3297 mono_thread_set_main (mono_thread_current ());
3299 main_args = g_new0 (char*, argc);
3300 num_main_args = argc;
3302 if (!g_path_is_absolute (argv [0])) {
3303 gchar *basename = g_path_get_basename (argv [0]);
3304 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3305 basename,
3306 NULL);
3308 utf8_fullpath = mono_utf8_from_external (fullpath);
3309 if(utf8_fullpath == NULL) {
3310 /* Printing the arg text will cause glib to
3311 * whinge about "Invalid UTF-8", but at least
3312 * its relevant, and shows the problem text
3313 * string.
3315 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3316 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3317 exit (-1);
3320 g_free (fullpath);
3321 g_free (basename);
3322 } else {
3323 utf8_fullpath = mono_utf8_from_external (argv[0]);
3324 if(utf8_fullpath == NULL) {
3325 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3326 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3327 exit (-1);
3331 main_args [0] = utf8_fullpath;
3333 for (i = 1; i < argc; ++i) {
3334 gchar *utf8_arg;
3336 utf8_arg=mono_utf8_from_external (argv[i]);
3337 if(utf8_arg==NULL) {
3338 /* Ditto the comment about Invalid UTF-8 here */
3339 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3340 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3341 exit (-1);
3344 main_args [i] = utf8_arg;
3346 argc--;
3347 argv++;
3348 if (mono_method_signature (method)->param_count) {
3349 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3350 for (i = 0; i < argc; ++i) {
3351 /* The encodings should all work, given that
3352 * we've checked all these args for the
3353 * main_args array.
3355 gchar *str = mono_utf8_from_external (argv [i]);
3356 MonoString *arg = mono_string_new (domain, str);
3357 mono_array_setref (args, i, arg);
3358 g_free (str);
3360 } else {
3361 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3364 mono_assembly_set_main (method->klass->image->assembly);
3366 result = mono_runtime_exec_main (method, args, exc);
3367 fire_process_exit_event ();
3368 return result;
3371 static MonoObject*
3372 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3374 static MonoMethod *serialize_method;
3376 void *params [1];
3377 MonoObject *array;
3379 if (!serialize_method) {
3380 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3381 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3384 if (!serialize_method) {
3385 *failure = TRUE;
3386 return NULL;
3389 g_assert (!mono_object_class (obj)->marshalbyref);
3391 params [0] = obj;
3392 *exc = NULL;
3393 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3394 if (*exc)
3395 *failure = TRUE;
3397 return array;
3400 static MonoObject*
3401 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3403 static MonoMethod *deserialize_method;
3405 void *params [1];
3406 MonoObject *result;
3408 if (!deserialize_method) {
3409 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3410 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3412 if (!deserialize_method) {
3413 *failure = TRUE;
3414 return NULL;
3417 params [0] = obj;
3418 *exc = NULL;
3419 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3420 if (*exc)
3421 *failure = TRUE;
3423 return result;
3426 static MonoObject*
3427 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3429 static MonoMethod *get_proxy_method;
3431 MonoDomain *domain = mono_domain_get ();
3432 MonoRealProxy *real_proxy;
3433 MonoReflectionType *reflection_type;
3434 MonoTransparentProxy *transparent_proxy;
3436 if (!get_proxy_method)
3437 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3439 g_assert (obj->vtable->klass->marshalbyref);
3441 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3442 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3444 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3445 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3447 *exc = NULL;
3448 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3449 if (*exc)
3450 *failure = TRUE;
3452 return (MonoObject*) transparent_proxy;
3456 * mono_object_xdomain_representation
3457 * @obj: an object
3458 * @target_domain: a domain
3459 * @exc: pointer to a MonoObject*
3461 * Creates a representation of obj in the domain target_domain. This
3462 * is either a copy of obj arrived through via serialization and
3463 * deserialization or a proxy, depending on whether the object is
3464 * serializable or marshal by ref. obj must not be in target_domain.
3466 * If the object cannot be represented in target_domain, NULL is
3467 * returned and *exc is set to an appropriate exception.
3469 MonoObject*
3470 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3472 MonoObject *deserialized = NULL;
3473 gboolean failure = FALSE;
3475 *exc = NULL;
3477 if (mono_object_class (obj)->marshalbyref) {
3478 deserialized = make_transparent_proxy (obj, &failure, exc);
3479 } else {
3480 MonoDomain *domain = mono_domain_get ();
3481 MonoObject *serialized;
3483 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3484 serialized = serialize_object (obj, &failure, exc);
3485 mono_domain_set_internal_with_options (target_domain, FALSE);
3486 if (!failure)
3487 deserialized = deserialize_object (serialized, &failure, exc);
3488 if (domain != target_domain)
3489 mono_domain_set_internal_with_options (domain, FALSE);
3492 return deserialized;
3495 /* Used in call_unhandled_exception_delegate */
3496 static MonoObject *
3497 create_unhandled_exception_eventargs (MonoObject *exc)
3499 MonoClass *klass;
3500 gpointer args [2];
3501 MonoMethod *method = NULL;
3502 MonoBoolean is_terminating = TRUE;
3503 MonoObject *obj;
3505 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3506 g_assert (klass);
3508 mono_class_init (klass);
3510 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3511 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3512 g_assert (method);
3514 args [0] = exc;
3515 args [1] = &is_terminating;
3517 obj = mono_object_new (mono_domain_get (), klass);
3518 mono_runtime_invoke (method, obj, args, NULL);
3520 return obj;
3523 /* Used in mono_unhandled_exception */
3524 static void
3525 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3526 MonoObject *e = NULL;
3527 gpointer pa [2];
3528 MonoDomain *current_domain = mono_domain_get ();
3530 if (domain != current_domain)
3531 mono_domain_set_internal_with_options (domain, FALSE);
3533 g_assert (domain == mono_object_domain (domain->domain));
3535 if (mono_object_domain (exc) != domain) {
3536 MonoObject *serialization_exc;
3538 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
3539 if (!exc) {
3540 if (serialization_exc) {
3541 MonoObject *dummy;
3542 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
3543 g_assert (exc);
3544 } else {
3545 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
3546 "System.Runtime.Serialization", "SerializationException",
3547 "Could not serialize unhandled exception.");
3551 g_assert (mono_object_domain (exc) == domain);
3553 pa [0] = domain->domain;
3554 pa [1] = create_unhandled_exception_eventargs (exc);
3555 mono_runtime_delegate_invoke (delegate, pa, &e);
3557 if (domain != current_domain)
3558 mono_domain_set_internal_with_options (current_domain, FALSE);
3560 if (e) {
3561 MonoError error;
3562 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
3563 if (!mono_error_ok (&error)) {
3564 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
3565 mono_error_cleanup (&error);
3566 } else {
3567 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3568 g_free (msg);
3573 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3576 * mono_runtime_unhandled_exception_policy_set:
3577 * @policy: the new policy
3579 * This is a VM internal routine.
3581 * Sets the runtime policy for handling unhandled exceptions.
3583 void
3584 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3585 runtime_unhandled_exception_policy = policy;
3589 * mono_runtime_unhandled_exception_policy_get:
3591 * This is a VM internal routine.
3593 * Gets the runtime policy for handling unhandled exceptions.
3595 MonoRuntimeUnhandledExceptionPolicy
3596 mono_runtime_unhandled_exception_policy_get (void) {
3597 return runtime_unhandled_exception_policy;
3601 * mono_unhandled_exception:
3602 * @exc: exception thrown
3604 * This is a VM internal routine.
3606 * We call this function when we detect an unhandled exception
3607 * in the default domain.
3609 * It invokes the * UnhandledException event in AppDomain or prints
3610 * a warning to the console
3612 void
3613 mono_unhandled_exception (MonoObject *exc)
3615 MonoDomain *current_domain = mono_domain_get ();
3616 MonoDomain *root_domain = mono_get_root_domain ();
3617 MonoClassField *field;
3618 MonoObject *current_appdomain_delegate;
3619 MonoObject *root_appdomain_delegate;
3621 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3622 "UnhandledException");
3623 g_assert (field);
3625 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3626 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
3627 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3628 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3629 if (current_domain != root_domain && (mono_framework_version () >= 2)) {
3630 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3631 } else {
3632 current_appdomain_delegate = NULL;
3635 /* set exitcode only if we will abort the process */
3636 if (abort_process)
3637 mono_environment_exitcode_set (1);
3638 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3639 mono_print_unhandled_exception (exc);
3640 } else {
3641 if (root_appdomain_delegate) {
3642 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3644 if (current_appdomain_delegate) {
3645 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3652 * Launch a new thread to execute a function
3654 * main_func is called back from the thread with main_args as the
3655 * parameter. The callback function is expected to start Main()
3656 * eventually. This function then waits for all managed threads to
3657 * finish.
3658 * It is not necesseray anymore to execute managed code in a subthread,
3659 * so this function should not be used anymore by default: just
3660 * execute the code and then call mono_thread_manage ().
3662 void
3663 mono_runtime_exec_managed_code (MonoDomain *domain,
3664 MonoMainThreadFunc main_func,
3665 gpointer main_args)
3667 mono_thread_create (domain, main_func, main_args);
3669 mono_thread_manage ();
3673 * Execute a standard Main() method (args doesn't contain the
3674 * executable name).
3677 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3679 MonoDomain *domain;
3680 gpointer pa [1];
3681 int rval;
3682 MonoCustomAttrInfo* cinfo;
3683 gboolean has_stathread_attribute;
3684 MonoInternalThread* thread = mono_thread_internal_current ();
3686 g_assert (args);
3688 pa [0] = args;
3690 domain = mono_object_domain (args);
3691 if (!domain->entry_assembly) {
3692 gchar *str;
3693 MonoAssembly *assembly;
3695 assembly = method->klass->image->assembly;
3696 domain->entry_assembly = assembly;
3697 /* Domains created from another domain already have application_base and configuration_file set */
3698 if (domain->setup->application_base == NULL) {
3699 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3702 if (domain->setup->configuration_file == NULL) {
3703 str = g_strconcat (assembly->image->name, ".config", NULL);
3704 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3705 g_free (str);
3706 mono_set_private_bin_path_from_config (domain);
3710 cinfo = mono_custom_attrs_from_method (method);
3711 if (cinfo) {
3712 static MonoClass *stathread_attribute = NULL;
3713 if (!stathread_attribute)
3714 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3715 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3716 if (!cinfo->cached)
3717 mono_custom_attrs_free (cinfo);
3718 } else {
3719 has_stathread_attribute = FALSE;
3721 if (has_stathread_attribute) {
3722 thread->apartment_state = ThreadApartmentState_STA;
3723 } else if (mono_framework_version () == 1) {
3724 thread->apartment_state = ThreadApartmentState_Unknown;
3725 } else {
3726 thread->apartment_state = ThreadApartmentState_MTA;
3728 mono_thread_init_apartment_state ();
3730 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3732 /* FIXME: check signature of method */
3733 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3734 MonoObject *res;
3735 res = mono_runtime_invoke (method, NULL, pa, exc);
3736 if (!exc || !*exc)
3737 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
3738 else
3739 rval = -1;
3741 mono_environment_exitcode_set (rval);
3742 } else {
3743 mono_runtime_invoke (method, NULL, pa, exc);
3744 if (!exc || !*exc)
3745 rval = 0;
3746 else {
3747 /* If the return type of Main is void, only
3748 * set the exitcode if an exception was thrown
3749 * (we don't want to blow away an
3750 * explicitly-set exit code)
3752 rval = -1;
3753 mono_environment_exitcode_set (rval);
3757 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
3759 return rval;
3763 * mono_install_runtime_invoke:
3764 * @func: Function to install
3766 * This is a VM internal routine
3768 void
3769 mono_install_runtime_invoke (MonoInvokeFunc func)
3771 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
3776 * mono_runtime_invoke_array:
3777 * @method: method to invoke
3778 * @obJ: object instance
3779 * @params: arguments to the method
3780 * @exc: exception information.
3782 * Invokes the method represented by @method on the object @obj.
3784 * obj is the 'this' pointer, it should be NULL for static
3785 * methods, a MonoObject* for object instances and a pointer to
3786 * the value type for value types.
3788 * The params array contains the arguments to the method with the
3789 * same convention: MonoObject* pointers for object instances and
3790 * pointers to the value type otherwise. The _invoke_array
3791 * variant takes a C# object[] as the params argument (MonoArray
3792 * *params): in this case the value types are boxed inside the
3793 * respective reference representation.
3795 * From unmanaged code you'll usually use the
3796 * mono_runtime_invoke() variant.
3798 * Note that this function doesn't handle virtual methods for
3799 * you, it will exec the exact method you pass: we still need to
3800 * expose a function to lookup the derived class implementation
3801 * of a virtual method (there are examples of this in the code,
3802 * though).
3804 * You can pass NULL as the exc argument if you don't want to
3805 * catch exceptions, otherwise, *exc will be set to the exception
3806 * thrown, if any. if an exception is thrown, you can't use the
3807 * MonoObject* result from the function.
3809 * If the method returns a value type, it is boxed in an object
3810 * reference.
3812 MonoObject*
3813 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
3814 MonoObject **exc)
3816 MonoMethodSignature *sig = mono_method_signature (method);
3817 gpointer *pa = NULL;
3818 MonoObject *res;
3819 int i;
3820 gboolean has_byref_nullables = FALSE;
3822 if (NULL != params) {
3823 pa = alloca (sizeof (gpointer) * mono_array_length (params));
3824 for (i = 0; i < mono_array_length (params); i++) {
3825 MonoType *t = sig->params [i];
3827 again:
3828 switch (t->type) {
3829 case MONO_TYPE_U1:
3830 case MONO_TYPE_I1:
3831 case MONO_TYPE_BOOLEAN:
3832 case MONO_TYPE_U2:
3833 case MONO_TYPE_I2:
3834 case MONO_TYPE_CHAR:
3835 case MONO_TYPE_U:
3836 case MONO_TYPE_I:
3837 case MONO_TYPE_U4:
3838 case MONO_TYPE_I4:
3839 case MONO_TYPE_U8:
3840 case MONO_TYPE_I8:
3841 case MONO_TYPE_R4:
3842 case MONO_TYPE_R8:
3843 case MONO_TYPE_VALUETYPE:
3844 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
3845 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
3846 pa [i] = mono_array_get (params, MonoObject*, i);
3847 if (t->byref)
3848 has_byref_nullables = TRUE;
3849 } else {
3850 /* MS seems to create the objects if a null is passed in */
3851 if (!mono_array_get (params, MonoObject*, i))
3852 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
3854 if (t->byref) {
3856 * We can't pass the unboxed vtype byref to the callee, since
3857 * that would mean the callee would be able to modify boxed
3858 * primitive types. So we (and MS) make a copy of the boxed
3859 * object, pass that to the callee, and replace the original
3860 * boxed object in the arg array with the copy.
3862 MonoObject *orig = mono_array_get (params, MonoObject*, i);
3863 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
3864 mono_array_setref (params, i, copy);
3867 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
3869 break;
3870 case MONO_TYPE_STRING:
3871 case MONO_TYPE_OBJECT:
3872 case MONO_TYPE_CLASS:
3873 case MONO_TYPE_ARRAY:
3874 case MONO_TYPE_SZARRAY:
3875 if (t->byref)
3876 pa [i] = mono_array_addr (params, MonoObject*, i);
3877 // FIXME: I need to check this code path
3878 else
3879 pa [i] = mono_array_get (params, MonoObject*, i);
3880 break;
3881 case MONO_TYPE_GENERICINST:
3882 if (t->byref)
3883 t = &t->data.generic_class->container_class->this_arg;
3884 else
3885 t = &t->data.generic_class->container_class->byval_arg;
3886 goto again;
3887 case MONO_TYPE_PTR: {
3888 MonoObject *arg;
3890 /* The argument should be an IntPtr */
3891 arg = mono_array_get (params, MonoObject*, i);
3892 if (arg == NULL) {
3893 pa [i] = NULL;
3894 } else {
3895 g_assert (arg->vtable->klass == mono_defaults.int_class);
3896 pa [i] = ((MonoIntPtr*)arg)->m_value;
3898 break;
3900 default:
3901 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
3906 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
3907 void *o = obj;
3909 if (mono_class_is_nullable (method->klass)) {
3910 /* Need to create a boxed vtype instead */
3911 g_assert (!obj);
3913 if (!params)
3914 return NULL;
3915 else
3916 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
3919 if (!obj) {
3920 obj = mono_object_new (mono_domain_get (), method->klass);
3921 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
3922 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
3924 if (method->klass->valuetype)
3925 o = mono_object_unbox (obj);
3926 else
3927 o = obj;
3928 } else if (method->klass->valuetype) {
3929 obj = mono_value_box (mono_domain_get (), method->klass, obj);
3932 mono_runtime_invoke (method, o, pa, exc);
3933 return obj;
3934 } else {
3935 if (mono_class_is_nullable (method->klass)) {
3936 MonoObject *nullable;
3938 /* Convert the unboxed vtype into a Nullable structure */
3939 nullable = mono_object_new (mono_domain_get (), method->klass);
3941 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
3942 obj = mono_object_unbox (nullable);
3945 /* obj must be already unboxed if needed */
3946 res = mono_runtime_invoke (method, obj, pa, exc);
3948 if (sig->ret->type == MONO_TYPE_PTR) {
3949 MonoClass *pointer_class;
3950 static MonoMethod *box_method;
3951 void *box_args [2];
3952 MonoObject *box_exc;
3955 * The runtime-invoke wrapper returns a boxed IntPtr, need to
3956 * convert it to a Pointer object.
3958 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3959 if (!box_method)
3960 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
3962 g_assert (res->vtable->klass == mono_defaults.int_class);
3963 box_args [0] = ((MonoIntPtr*)res)->m_value;
3964 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
3965 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
3966 g_assert (!box_exc);
3969 if (has_byref_nullables) {
3971 * The runtime invoke wrapper already converted byref nullables back,
3972 * and stored them in pa, we just need to copy them back to the
3973 * managed array.
3975 for (i = 0; i < mono_array_length (params); i++) {
3976 MonoType *t = sig->params [i];
3978 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
3979 mono_array_setref (params, i, pa [i]);
3983 return res;
3987 static void
3988 arith_overflow (void)
3990 mono_raise_exception (mono_get_exception_overflow ());
3994 * mono_object_allocate:
3995 * @size: number of bytes to allocate
3997 * This is a very simplistic routine until we have our GC-aware
3998 * memory allocator.
4000 * Returns: an allocated object of size @size, or NULL on failure.
4002 static inline void *
4003 mono_object_allocate (size_t size, MonoVTable *vtable)
4005 MonoObject *o;
4006 mono_stats.new_object_count++;
4007 ALLOC_OBJECT (o, vtable, size);
4009 return o;
4013 * mono_object_allocate_ptrfree:
4014 * @size: number of bytes to allocate
4016 * Note that the memory allocated is not zeroed.
4017 * Returns: an allocated object of size @size, or NULL on failure.
4019 static inline void *
4020 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
4022 MonoObject *o;
4023 mono_stats.new_object_count++;
4024 ALLOC_PTRFREE (o, vtable, size);
4025 return o;
4028 static inline void *
4029 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
4031 void *o;
4032 ALLOC_TYPED (o, size, vtable);
4033 mono_stats.new_object_count++;
4035 return o;
4039 * mono_object_new:
4040 * @klass: the class of the object that we want to create
4042 * Returns: a newly created object whose definition is
4043 * looked up using @klass. This will not invoke any constructors,
4044 * so the consumer of this routine has to invoke any constructors on
4045 * its own to initialize the object.
4047 * It returns NULL on failure.
4049 MonoObject *
4050 mono_object_new (MonoDomain *domain, MonoClass *klass)
4052 MonoVTable *vtable;
4054 MONO_ARCH_SAVE_REGS;
4055 vtable = mono_class_vtable (domain, klass);
4056 if (!vtable)
4057 return NULL;
4058 return mono_object_new_specific (vtable);
4062 * mono_object_new_specific:
4063 * @vtable: the vtable of the object that we want to create
4065 * Returns: A newly created object with class and domain specified
4066 * by @vtable
4068 MonoObject *
4069 mono_object_new_specific (MonoVTable *vtable)
4071 MonoObject *o;
4073 MONO_ARCH_SAVE_REGS;
4075 /* check for is_com_object for COM Interop */
4076 if (vtable->remote || vtable->klass->is_com_object)
4078 gpointer pa [1];
4079 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4081 if (im == NULL) {
4082 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4084 if (!klass->inited)
4085 mono_class_init (klass);
4087 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4088 g_assert (im);
4089 vtable->domain->create_proxy_for_type_method = im;
4092 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4094 o = mono_runtime_invoke (im, NULL, pa, NULL);
4095 if (o != NULL) return o;
4098 return mono_object_new_alloc_specific (vtable);
4101 MonoObject *
4102 mono_object_new_alloc_specific (MonoVTable *vtable)
4104 MonoObject *o;
4106 if (!vtable->klass->has_references) {
4107 o = mono_object_new_ptrfree (vtable);
4108 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4109 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
4110 } else {
4111 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4112 o = mono_object_allocate (vtable->klass->instance_size, vtable);
4114 if (G_UNLIKELY (vtable->klass->has_finalize))
4115 mono_object_register_finalizer (o);
4117 if (G_UNLIKELY (profile_allocs))
4118 mono_profiler_allocation (o, vtable->klass);
4119 return o;
4122 MonoObject*
4123 mono_object_new_fast (MonoVTable *vtable)
4125 MonoObject *o;
4126 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
4127 return o;
4130 static MonoObject*
4131 mono_object_new_ptrfree (MonoVTable *vtable)
4133 MonoObject *obj;
4134 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4135 #if NEED_TO_ZERO_PTRFREE
4136 /* an inline memset is much faster for the common vcase of small objects
4137 * note we assume the allocated size is a multiple of sizeof (void*).
4139 if (vtable->klass->instance_size < 128) {
4140 gpointer *p, *end;
4141 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
4142 p = (gpointer*)((char*)obj + sizeof (MonoObject));
4143 while (p < end) {
4144 *p = NULL;
4145 ++p;
4147 } else {
4148 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
4150 #endif
4151 return obj;
4154 static MonoObject*
4155 mono_object_new_ptrfree_box (MonoVTable *vtable)
4157 MonoObject *obj;
4158 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4159 /* the object will be boxed right away, no need to memzero it */
4160 return obj;
4164 * mono_class_get_allocation_ftn:
4165 * @vtable: vtable
4166 * @for_box: the object will be used for boxing
4167 * @pass_size_in_words:
4169 * Return the allocation function appropriate for the given class.
4172 void*
4173 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4175 *pass_size_in_words = FALSE;
4177 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4178 profile_allocs = FALSE;
4180 if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4181 return mono_object_new_specific;
4183 if (!vtable->klass->has_references) {
4184 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
4185 if (for_box)
4186 return mono_object_new_ptrfree_box;
4187 return mono_object_new_ptrfree;
4190 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4192 return mono_object_new_fast;
4195 * FIXME: This is actually slower than mono_object_new_fast, because
4196 * of the overhead of parameter passing.
4199 *pass_size_in_words = TRUE;
4200 #ifdef GC_REDIRECT_TO_LOCAL
4201 return GC_local_gcj_fast_malloc;
4202 #else
4203 return GC_gcj_fast_malloc;
4204 #endif
4208 return mono_object_new_specific;
4212 * mono_object_new_from_token:
4213 * @image: Context where the type_token is hosted
4214 * @token: a token of the type that we want to create
4216 * Returns: A newly created object whose definition is
4217 * looked up using @token in the @image image
4219 MonoObject *
4220 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4222 MonoClass *class;
4224 class = mono_class_get (image, token);
4226 return mono_object_new (domain, class);
4231 * mono_object_clone:
4232 * @obj: the object to clone
4234 * Returns: A newly created object who is a shallow copy of @obj
4236 MonoObject *
4237 mono_object_clone (MonoObject *obj)
4239 MonoObject *o;
4240 int size = obj->vtable->klass->instance_size;
4242 o = mono_object_allocate (size, obj->vtable);
4244 if (obj->vtable->klass->has_references) {
4245 mono_gc_wbarrier_object_copy (o, obj);
4246 } else {
4247 int size = obj->vtable->klass->instance_size;
4248 /* do not copy the sync state */
4249 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
4251 if (G_UNLIKELY (profile_allocs))
4252 mono_profiler_allocation (o, obj->vtable->klass);
4254 if (obj->vtable->klass->has_finalize)
4255 mono_object_register_finalizer (o);
4256 return o;
4260 * mono_array_full_copy:
4261 * @src: source array to copy
4262 * @dest: destination array
4264 * Copies the content of one array to another with exactly the same type and size.
4266 void
4267 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4269 mono_array_size_t size;
4270 MonoClass *klass = src->obj.vtable->klass;
4272 MONO_ARCH_SAVE_REGS;
4274 g_assert (klass == dest->obj.vtable->klass);
4276 size = mono_array_length (src);
4277 g_assert (size == mono_array_length (dest));
4278 size *= mono_array_element_size (klass);
4279 #ifdef HAVE_SGEN_GC
4280 if (klass->element_class->valuetype) {
4281 if (klass->element_class->has_references)
4282 mono_value_copy_array (dest, 0, mono_array_addr_with_size (src, 0, 0), mono_array_length (src));
4283 else
4284 memcpy (&dest->vector, &src->vector, size);
4285 } else {
4286 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4288 #else
4289 memcpy (&dest->vector, &src->vector, size);
4290 #endif
4294 * mono_array_clone_in_domain:
4295 * @domain: the domain in which the array will be cloned into
4296 * @array: the array to clone
4298 * This routine returns a copy of the array that is hosted on the
4299 * specified MonoDomain.
4301 MonoArray*
4302 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4304 MonoArray *o;
4305 mono_array_size_t size, i;
4306 mono_array_size_t *sizes;
4307 MonoClass *klass = array->obj.vtable->klass;
4309 MONO_ARCH_SAVE_REGS;
4311 if (array->bounds == NULL) {
4312 size = mono_array_length (array);
4313 o = mono_array_new_full (domain, klass, &size, NULL);
4315 size *= mono_array_element_size (klass);
4316 #ifdef HAVE_SGEN_GC
4317 if (klass->element_class->valuetype) {
4318 if (klass->element_class->has_references)
4319 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4320 else
4321 memcpy (&o->vector, &array->vector, size);
4322 } else {
4323 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4325 #else
4326 memcpy (&o->vector, &array->vector, size);
4327 #endif
4328 return o;
4331 sizes = alloca (klass->rank * sizeof(mono_array_size_t) * 2);
4332 size = mono_array_element_size (klass);
4333 for (i = 0; i < klass->rank; ++i) {
4334 sizes [i] = array->bounds [i].length;
4335 size *= array->bounds [i].length;
4336 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4338 o = mono_array_new_full (domain, klass, sizes, sizes + klass->rank);
4339 #ifdef HAVE_SGEN_GC
4340 if (klass->element_class->valuetype) {
4341 if (klass->element_class->has_references)
4342 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4343 else
4344 memcpy (&o->vector, &array->vector, size);
4345 } else {
4346 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4348 #else
4349 memcpy (&o->vector, &array->vector, size);
4350 #endif
4352 return o;
4356 * mono_array_clone:
4357 * @array: the array to clone
4359 * Returns: A newly created array who is a shallow copy of @array
4361 MonoArray*
4362 mono_array_clone (MonoArray *array)
4364 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4367 /* helper macros to check for overflow when calculating the size of arrays */
4368 #ifdef MONO_BIG_ARRAYS
4369 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4370 #define MYGUINT_MAX MYGUINT64_MAX
4371 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4372 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4373 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4374 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4375 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4376 #else
4377 #define MYGUINT32_MAX 4294967295U
4378 #define MYGUINT_MAX MYGUINT32_MAX
4379 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4380 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4381 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4382 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4383 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4384 #endif
4386 gboolean
4387 mono_array_calc_byte_len (MonoClass *class, mono_array_size_t len, mono_array_size_t *res)
4389 mono_array_size_t byte_len;
4391 byte_len = mono_array_element_size (class);
4392 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4393 return FALSE;
4394 byte_len *= len;
4395 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4396 return FALSE;
4397 byte_len += sizeof (MonoArray);
4399 *res = byte_len;
4401 return TRUE;
4405 * mono_array_new_full:
4406 * @domain: domain where the object is created
4407 * @array_class: array class
4408 * @lengths: lengths for each dimension in the array
4409 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4411 * This routine creates a new array objects with the given dimensions,
4412 * lower bounds and type.
4414 MonoArray*
4415 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, mono_array_size_t *lengths, mono_array_size_t *lower_bounds)
4417 mono_array_size_t byte_len, len, bounds_size;
4418 MonoObject *o;
4419 MonoArray *array;
4420 MonoArrayBounds *bounds;
4421 MonoVTable *vtable;
4422 int i;
4424 if (!array_class->inited)
4425 mono_class_init (array_class);
4427 len = 1;
4429 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4430 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4431 len = lengths [0];
4432 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4433 arith_overflow ();
4434 bounds_size = 0;
4435 } else {
4436 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4438 for (i = 0; i < array_class->rank; ++i) {
4439 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4440 arith_overflow ();
4441 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4442 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4443 len *= lengths [i];
4447 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4448 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4450 if (bounds_size) {
4451 /* align */
4452 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4453 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4454 byte_len = (byte_len + 3) & ~3;
4455 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4456 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4457 byte_len += bounds_size;
4460 * Following three lines almost taken from mono_object_new ():
4461 * they need to be kept in sync.
4463 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4464 #ifndef HAVE_SGEN_GC
4465 if (!array_class->has_references) {
4466 o = mono_object_allocate_ptrfree (byte_len, vtable);
4467 #if NEED_TO_ZERO_PTRFREE
4468 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4469 #endif
4470 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4471 o = mono_object_allocate_spec (byte_len, vtable);
4472 }else {
4473 o = mono_object_allocate (byte_len, vtable);
4476 array = (MonoArray*)o;
4477 array->max_length = len;
4479 if (bounds_size) {
4480 bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4481 array->bounds = bounds;
4483 #else
4484 if (bounds_size)
4485 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4486 else
4487 o = mono_gc_alloc_vector (vtable, byte_len, len);
4488 array = (MonoArray*)o;
4489 mono_stats.new_object_count++;
4491 bounds = array->bounds;
4492 #endif
4494 if (bounds_size) {
4495 for (i = 0; i < array_class->rank; ++i) {
4496 bounds [i].length = lengths [i];
4497 if (lower_bounds)
4498 bounds [i].lower_bound = lower_bounds [i];
4502 if (G_UNLIKELY (profile_allocs))
4503 mono_profiler_allocation (o, array_class);
4505 return array;
4509 * mono_array_new:
4510 * @domain: domain where the object is created
4511 * @eclass: element class
4512 * @n: number of array elements
4514 * This routine creates a new szarray with @n elements of type @eclass.
4516 MonoArray *
4517 mono_array_new (MonoDomain *domain, MonoClass *eclass, mono_array_size_t n)
4519 MonoClass *ac;
4521 MONO_ARCH_SAVE_REGS;
4523 ac = mono_array_class_get (eclass, 1);
4524 g_assert (ac);
4526 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4530 * mono_array_new_specific:
4531 * @vtable: a vtable in the appropriate domain for an initialized class
4532 * @n: number of array elements
4534 * This routine is a fast alternative to mono_array_new() for code which
4535 * can be sure about the domain it operates in.
4537 MonoArray *
4538 mono_array_new_specific (MonoVTable *vtable, mono_array_size_t n)
4540 MonoObject *o;
4541 MonoArray *ao;
4542 guint32 byte_len;
4544 MONO_ARCH_SAVE_REGS;
4546 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4547 arith_overflow ();
4548 return NULL;
4551 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4552 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4553 return NULL;
4555 #ifndef HAVE_SGEN_GC
4556 if (!vtable->klass->has_references) {
4557 o = mono_object_allocate_ptrfree (byte_len, vtable);
4558 #if NEED_TO_ZERO_PTRFREE
4559 ((MonoArray*)o)->bounds = NULL;
4560 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4561 #endif
4562 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4563 o = mono_object_allocate_spec (byte_len, vtable);
4564 } else {
4565 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4566 o = mono_object_allocate (byte_len, vtable);
4569 ao = (MonoArray *)o;
4570 ao->max_length = n;
4571 #else
4572 o = mono_gc_alloc_vector (vtable, byte_len, n);
4573 ao = (MonoArray*)o;
4574 mono_stats.new_object_count++;
4575 #endif
4577 if (G_UNLIKELY (profile_allocs))
4578 mono_profiler_allocation (o, vtable->klass);
4580 return ao;
4584 * mono_string_new_utf16:
4585 * @text: a pointer to an utf16 string
4586 * @len: the length of the string
4588 * Returns: A newly created string object which contains @text.
4590 MonoString *
4591 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4593 MonoString *s;
4595 s = mono_string_new_size (domain, len);
4596 g_assert (s != NULL);
4598 memcpy (mono_string_chars (s), text, len * 2);
4600 return s;
4604 * mono_string_new_size:
4605 * @text: a pointer to an utf16 string
4606 * @len: the length of the string
4608 * Returns: A newly created string object of @len
4610 MonoString *
4611 mono_string_new_size (MonoDomain *domain, gint32 len)
4613 MonoString *s;
4614 MonoVTable *vtable;
4615 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4617 /* overflow ? can't fit it, can't allocate it! */
4618 if (len > size)
4619 mono_gc_out_of_memory (-1);
4621 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4622 g_assert (vtable);
4624 s = mono_object_allocate_ptrfree (size, vtable);
4626 s->length = len;
4627 #if NEED_TO_ZERO_PTRFREE
4628 s->chars [len] = 0;
4629 #endif
4630 if (G_UNLIKELY (profile_allocs))
4631 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4633 return s;
4637 * mono_string_new_len:
4638 * @text: a pointer to an utf8 string
4639 * @length: number of bytes in @text to consider
4641 * Returns: A newly created string object which contains @text.
4643 MonoString*
4644 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4646 GError *error = NULL;
4647 MonoString *o = NULL;
4648 guint16 *ut;
4649 glong items_written;
4651 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
4653 if (!error)
4654 o = mono_string_new_utf16 (domain, ut, items_written);
4655 else
4656 g_error_free (error);
4658 g_free (ut);
4660 return o;
4664 * mono_string_new:
4665 * @text: a pointer to an utf8 string
4667 * Returns: A newly created string object which contains @text.
4669 MonoString*
4670 mono_string_new (MonoDomain *domain, const char *text)
4672 GError *error = NULL;
4673 MonoString *o = NULL;
4674 guint16 *ut;
4675 glong items_written;
4676 int l;
4678 l = strlen (text);
4680 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4682 if (!error)
4683 o = mono_string_new_utf16 (domain, ut, items_written);
4684 else
4685 g_error_free (error);
4687 g_free (ut);
4688 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4689 #if 0
4690 gunichar2 *str;
4691 const gchar *end;
4692 int len;
4693 MonoString *o = NULL;
4695 if (!g_utf8_validate (text, -1, &end))
4696 return NULL;
4698 len = g_utf8_strlen (text, -1);
4699 o = mono_string_new_size (domain, len);
4700 str = mono_string_chars (o);
4702 while (text < end) {
4703 *str++ = g_utf8_get_char (text);
4704 text = g_utf8_next_char (text);
4706 #endif
4707 return o;
4711 * mono_string_new_wrapper:
4712 * @text: pointer to utf8 characters.
4714 * Helper function to create a string object from @text in the current domain.
4716 MonoString*
4717 mono_string_new_wrapper (const char *text)
4719 MonoDomain *domain = mono_domain_get ();
4721 MONO_ARCH_SAVE_REGS;
4723 if (text)
4724 return mono_string_new (domain, text);
4726 return NULL;
4730 * mono_value_box:
4731 * @class: the class of the value
4732 * @value: a pointer to the unboxed data
4734 * Returns: A newly created object which contains @value.
4736 MonoObject *
4737 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
4739 MonoObject *res;
4740 int size;
4741 MonoVTable *vtable;
4743 g_assert (class->valuetype);
4744 if (mono_class_is_nullable (class))
4745 return mono_nullable_box (value, class);
4747 vtable = mono_class_vtable (domain, class);
4748 if (!vtable)
4749 return NULL;
4750 size = mono_class_instance_size (class);
4751 res = mono_object_new_alloc_specific (vtable);
4752 if (G_UNLIKELY (profile_allocs))
4753 mono_profiler_allocation (res, class);
4755 size = size - sizeof (MonoObject);
4757 #ifdef HAVE_SGEN_GC
4758 g_assert (size == mono_class_value_size (class, NULL));
4759 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
4760 #else
4761 #if NO_UNALIGNED_ACCESS
4762 memcpy ((char *)res + sizeof (MonoObject), value, size);
4763 #else
4764 switch (size) {
4765 case 1:
4766 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
4767 break;
4768 case 2:
4769 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
4770 break;
4771 case 4:
4772 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
4773 break;
4774 case 8:
4775 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
4776 break;
4777 default:
4778 memcpy ((char *)res + sizeof (MonoObject), value, size);
4780 #endif
4781 #endif
4782 if (class->has_finalize)
4783 mono_object_register_finalizer (res);
4784 return res;
4788 * mono_value_copy:
4789 * @dest: destination pointer
4790 * @src: source pointer
4791 * @klass: a valuetype class
4793 * Copy a valuetype from @src to @dest. This function must be used
4794 * when @klass contains references fields.
4796 void
4797 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
4799 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
4803 * mono_value_copy_array:
4804 * @dest: destination array
4805 * @dest_idx: index in the @dest array
4806 * @src: source pointer
4807 * @count: number of items
4809 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
4810 * This function must be used when @klass contains references fields.
4811 * Overlap is handled.
4813 void
4814 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
4816 int size = mono_array_element_size (dest->obj.vtable->klass);
4817 char *d = mono_array_addr_with_size (dest, size, dest_idx);
4818 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
4819 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
4823 * mono_object_get_domain:
4824 * @obj: object to query
4826 * Returns: the MonoDomain where the object is hosted
4828 MonoDomain*
4829 mono_object_get_domain (MonoObject *obj)
4831 return mono_object_domain (obj);
4835 * mono_object_get_class:
4836 * @obj: object to query
4838 * Returns: the MonOClass of the object.
4840 MonoClass*
4841 mono_object_get_class (MonoObject *obj)
4843 return mono_object_class (obj);
4846 * mono_object_get_size:
4847 * @o: object to query
4849 * Returns: the size, in bytes, of @o
4851 guint
4852 mono_object_get_size (MonoObject* o)
4854 MonoClass* klass = mono_object_class (o);
4855 if (klass == mono_defaults.string_class) {
4856 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
4857 } else if (o->vtable->rank) {
4858 MonoArray *array = (MonoArray*)o;
4859 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
4860 if (array->bounds) {
4861 size += 3;
4862 size &= ~3;
4863 size += sizeof (MonoArrayBounds) * o->vtable->rank;
4865 return size;
4866 } else {
4867 return mono_class_instance_size (klass);
4872 * mono_object_unbox:
4873 * @obj: object to unbox
4875 * Returns: a pointer to the start of the valuetype boxed in this
4876 * object.
4878 * This method will assert if the object passed is not a valuetype.
4880 gpointer
4881 mono_object_unbox (MonoObject *obj)
4883 /* add assert for valuetypes? */
4884 g_assert (obj->vtable->klass->valuetype);
4885 return ((char*)obj) + sizeof (MonoObject);
4889 * mono_object_isinst:
4890 * @obj: an object
4891 * @klass: a pointer to a class
4893 * Returns: @obj if @obj is derived from @klass
4895 MonoObject *
4896 mono_object_isinst (MonoObject *obj, MonoClass *klass)
4898 if (!klass->inited)
4899 mono_class_init (klass);
4901 if (klass->marshalbyref || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
4902 return mono_object_isinst_mbyref (obj, klass);
4904 if (!obj)
4905 return NULL;
4907 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
4910 MonoObject *
4911 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
4913 MonoVTable *vt;
4915 if (!obj)
4916 return NULL;
4918 vt = obj->vtable;
4920 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4921 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
4922 return obj;
4925 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
4926 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
4927 return obj;
4928 } else {
4929 MonoClass *oklass = vt->klass;
4930 if ((oklass == mono_defaults.transparent_proxy_class))
4931 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
4933 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
4934 return obj;
4937 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
4939 MonoDomain *domain = mono_domain_get ();
4940 MonoObject *res;
4941 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
4942 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
4943 MonoMethod *im = NULL;
4944 gpointer pa [2];
4946 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
4947 im = mono_object_get_virtual_method (rp, im);
4948 g_assert (im);
4950 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
4951 pa [1] = obj;
4953 res = mono_runtime_invoke (im, rp, pa, NULL);
4955 if (*(MonoBoolean *) mono_object_unbox(res)) {
4956 /* Update the vtable of the remote type, so it can safely cast to this new type */
4957 mono_upgrade_remote_class (domain, obj, klass);
4958 return obj;
4962 return NULL;
4966 * mono_object_castclass_mbyref:
4967 * @obj: an object
4968 * @klass: a pointer to a class
4970 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
4972 MonoObject *
4973 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
4975 if (!obj) return NULL;
4976 if (mono_object_isinst_mbyref (obj, klass)) return obj;
4978 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
4979 "System",
4980 "InvalidCastException"));
4981 return NULL;
4984 typedef struct {
4985 MonoDomain *orig_domain;
4986 MonoString *ins;
4987 MonoString *res;
4988 } LDStrInfo;
4990 static void
4991 str_lookup (MonoDomain *domain, gpointer user_data)
4993 LDStrInfo *info = user_data;
4994 if (info->res || domain == info->orig_domain)
4995 return;
4996 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
4999 #ifdef HAVE_SGEN_GC
5001 static MonoString*
5002 mono_string_get_pinned (MonoString *str)
5004 int size;
5005 MonoString *news;
5006 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5007 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5008 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5009 news->length = mono_string_length (str);
5010 return news;
5013 #else
5014 #define mono_string_get_pinned(str) (str)
5015 #endif
5017 static MonoString*
5018 mono_string_is_interned_lookup (MonoString *str, int insert)
5020 MonoGHashTable *ldstr_table;
5021 MonoString *res;
5022 MonoDomain *domain;
5024 domain = ((MonoObject *)str)->vtable->domain;
5025 ldstr_table = domain->ldstr_table;
5026 ldstr_lock ();
5027 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
5028 ldstr_unlock ();
5029 return res;
5031 if (insert) {
5032 str = mono_string_get_pinned (str);
5033 mono_g_hash_table_insert (ldstr_table, str, str);
5034 ldstr_unlock ();
5035 return str;
5036 } else {
5037 LDStrInfo ldstr_info;
5038 ldstr_info.orig_domain = domain;
5039 ldstr_info.ins = str;
5040 ldstr_info.res = NULL;
5042 mono_domain_foreach (str_lookup, &ldstr_info);
5043 if (ldstr_info.res) {
5045 * the string was already interned in some other domain:
5046 * intern it in the current one as well.
5048 mono_g_hash_table_insert (ldstr_table, str, str);
5049 ldstr_unlock ();
5050 return str;
5053 ldstr_unlock ();
5054 return NULL;
5058 * mono_string_is_interned:
5059 * @o: String to probe
5061 * Returns whether the string has been interned.
5063 MonoString*
5064 mono_string_is_interned (MonoString *o)
5066 return mono_string_is_interned_lookup (o, FALSE);
5070 * mono_string_intern:
5071 * @o: String to intern
5073 * Interns the string passed.
5074 * Returns: The interned string.
5076 MonoString*
5077 mono_string_intern (MonoString *str)
5079 return mono_string_is_interned_lookup (str, TRUE);
5083 * mono_ldstr:
5084 * @domain: the domain where the string will be used.
5085 * @image: a metadata context
5086 * @idx: index into the user string table.
5088 * Implementation for the ldstr opcode.
5089 * Returns: a loaded string from the @image/@idx combination.
5091 MonoString*
5092 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5094 MONO_ARCH_SAVE_REGS;
5096 if (image->dynamic) {
5097 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5098 if (mono_profiler_events & MONO_PROFILE_STRING_ALLOC)
5099 mono_profiler_string_allocation (domain, str);
5100 return str;
5101 } else {
5102 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5103 return NULL; /*FIXME we should probably be raising an exception here*/
5104 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5109 * mono_ldstr_metadata_sig
5110 * @domain: the domain for the string
5111 * @sig: the signature of a metadata string
5113 * Returns: a MonoString for a string stored in the metadata
5115 static MonoString*
5116 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5118 const char *str = sig;
5119 MonoString *o, *interned;
5120 size_t len2;
5122 len2 = mono_metadata_decode_blob_size (str, &str);
5123 len2 >>= 1;
5125 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5126 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5128 int i;
5129 guint16 *p2 = (guint16*)mono_string_chars (o);
5130 for (i = 0; i < len2; ++i) {
5131 *p2 = GUINT16_FROM_LE (*p2);
5132 ++p2;
5135 #endif
5136 ldstr_lock ();
5137 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
5138 ldstr_unlock ();
5139 /* o will get garbage collected */
5140 return interned;
5143 o = mono_string_get_pinned (o);
5144 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5145 ldstr_unlock ();
5147 if (mono_profiler_events & MONO_PROFILE_STRING_ALLOC)
5148 mono_profiler_string_allocation (domain, o);
5150 return o;
5154 * mono_string_to_utf8:
5155 * @s: a System.String
5157 * Return the UTF8 representation for @s.
5158 * the resulting buffer nedds to be freed with g_free().
5160 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5162 char *
5163 mono_string_to_utf8 (MonoString *s)
5165 MonoError error;
5166 char *result = mono_string_to_utf8_checked (s, &error);
5168 if (!mono_error_ok (&error))
5169 mono_error_raise_exception (&error);
5170 return result;
5173 char *
5174 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5176 long written = 0;
5177 char *as;
5178 GError *gerror = NULL;
5180 mono_error_init (error);
5182 if (s == NULL)
5183 return NULL;
5185 if (!s->length)
5186 return g_strdup ("");
5188 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5189 if (gerror) {
5190 mono_error_set_argument (error, "string", "%s", gerror->message);
5191 g_error_free (gerror);
5192 return NULL;
5194 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5195 if (s->length > written) {
5196 /* allocate the total length and copy the part of the string that has been converted */
5197 char *as2 = g_malloc0 (s->length);
5198 memcpy (as2, as, written);
5199 g_free (as);
5200 as = as2;
5203 return as;
5207 * mono_string_to_utf16:
5208 * @s: a MonoString
5210 * Return an null-terminated array of the utf-16 chars
5211 * contained in @s. The result must be freed with g_free().
5212 * This is a temporary helper until our string implementation
5213 * is reworked to always include the null terminating char.
5215 gunichar2 *
5216 mono_string_to_utf16 (MonoString *s)
5218 char *as;
5220 if (s == NULL)
5221 return NULL;
5223 as = g_malloc ((s->length * 2) + 2);
5224 as [(s->length * 2)] = '\0';
5225 as [(s->length * 2) + 1] = '\0';
5227 if (!s->length) {
5228 return (gunichar2 *)(as);
5231 memcpy (as, mono_string_chars(s), s->length * 2);
5232 return (gunichar2 *)(as);
5236 * mono_string_from_utf16:
5237 * @data: the UTF16 string (LPWSTR) to convert
5239 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5241 * Returns: a MonoString.
5243 MonoString *
5244 mono_string_from_utf16 (gunichar2 *data)
5246 MonoDomain *domain = mono_domain_get ();
5247 int len = 0;
5249 if (!data)
5250 return NULL;
5252 while (data [len]) len++;
5254 return mono_string_new_utf16 (domain, data, len);
5258 static char *
5259 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, MonoError *error)
5261 char *r;
5262 char *mp_s;
5263 int len;
5265 r = mono_string_to_utf8_checked (s, error);
5266 if (!mono_error_ok (error))
5267 return NULL;
5269 if (!mp && !image)
5270 return r;
5272 len = strlen (r) + 1;
5273 if (mp)
5274 mp_s = mono_mempool_alloc (mp, len);
5275 else
5276 mp_s = mono_image_alloc (image, len);
5278 memcpy (mp_s, r, len);
5280 g_free (r);
5282 return mp_s;
5286 * mono_string_to_utf8_image:
5287 * @s: a System.String
5289 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5291 char *
5292 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5294 return mono_string_to_utf8_internal (NULL, image, s, error);
5298 * mono_string_to_utf8_mp:
5299 * @s: a System.String
5301 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5303 char *
5304 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5306 return mono_string_to_utf8_internal (mp, NULL, s, error);
5309 static void
5310 default_ex_handler (MonoException *ex)
5312 MonoObject *o = (MonoObject*)ex;
5313 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
5314 exit (1);
5317 static MonoExceptionFunc ex_handler = default_ex_handler;
5320 * mono_install_handler:
5321 * @func: exception handler
5323 * This is an internal JIT routine used to install the handler for exceptions
5324 * being throwh.
5326 void
5327 mono_install_handler (MonoExceptionFunc func)
5329 ex_handler = func? func: default_ex_handler;
5333 * mono_raise_exception:
5334 * @ex: exception object
5336 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5338 void
5339 mono_raise_exception (MonoException *ex)
5342 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5343 * that will cause gcc to omit the function epilog, causing problems when
5344 * the JIT tries to walk the stack, since the return address on the stack
5345 * will point into the next function in the executable, not this one.
5348 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class) {
5349 MonoInternalThread *thread = mono_thread_internal_current ();
5350 g_assert (ex->object.vtable->domain == mono_domain_get ());
5351 MONO_OBJECT_SETREF (thread, abort_exc, ex);
5354 ex_handler (ex);
5358 * mono_wait_handle_new:
5359 * @domain: Domain where the object will be created
5360 * @handle: Handle for the wait handle
5362 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5364 MonoWaitHandle *
5365 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5367 MonoWaitHandle *res;
5368 gpointer params [1];
5369 static MonoMethod *handle_set;
5371 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5373 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5374 if (!handle_set)
5375 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5377 params [0] = &handle;
5378 mono_runtime_invoke (handle_set, res, params, NULL);
5380 return res;
5383 HANDLE
5384 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5386 static MonoClassField *f_os_handle;
5387 static MonoClassField *f_safe_handle;
5389 if (!f_os_handle && !f_safe_handle) {
5390 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5391 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5394 if (f_os_handle) {
5395 HANDLE retval;
5396 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5397 return retval;
5398 } else {
5399 MonoSafeHandle *sh;
5400 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5401 return sh->handle;
5406 static MonoObject*
5407 mono_runtime_capture_context (MonoDomain *domain)
5409 RuntimeInvokeFunction runtime_invoke;
5411 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5412 MonoMethod *method = mono_get_context_capture_method ();
5413 MonoMethod *wrapper;
5414 if (!method)
5415 return NULL;
5416 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5417 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5418 domain->capture_context_method = mono_compile_method (method);
5421 runtime_invoke = domain->capture_context_runtime_invoke;
5423 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5426 * mono_async_result_new:
5427 * @domain:domain where the object will be created.
5428 * @handle: wait handle.
5429 * @state: state to pass to AsyncResult
5430 * @data: C closure data.
5432 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5433 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5436 MonoAsyncResult *
5437 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5439 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5440 MonoObject *context = mono_runtime_capture_context (domain);
5441 /* we must capture the execution context from the original thread */
5442 if (context) {
5443 MONO_OBJECT_SETREF (res, execution_context, context);
5444 /* note: result may be null if the flow is suppressed */
5447 res->data = data;
5448 MONO_OBJECT_SETREF (res, object_data, object_data);
5449 MONO_OBJECT_SETREF (res, async_state, state);
5450 if (handle != NULL)
5451 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5453 res->sync_completed = FALSE;
5454 res->completed = FALSE;
5456 return res;
5459 void
5460 mono_message_init (MonoDomain *domain,
5461 MonoMethodMessage *this,
5462 MonoReflectionMethod *method,
5463 MonoArray *out_args)
5465 static MonoClass *object_array_klass;
5466 static MonoClass *byte_array_klass;
5467 static MonoClass *string_array_klass;
5468 MonoMethodSignature *sig = mono_method_signature (method->method);
5469 MonoString *name;
5470 int i, j;
5471 char **names;
5472 guint8 arg_type;
5474 if (!object_array_klass) {
5475 MonoClass *klass;
5477 klass = mono_array_class_get (mono_defaults.object_class, 1);
5478 g_assert (klass);
5480 mono_memory_barrier ();
5481 object_array_klass = klass;
5483 klass = mono_array_class_get (mono_defaults.byte_class, 1);
5484 g_assert (klass);
5486 mono_memory_barrier ();
5487 byte_array_klass = klass;
5489 klass = mono_array_class_get (mono_defaults.string_class, 1);
5490 g_assert (klass);
5492 mono_memory_barrier ();
5493 string_array_klass = klass;
5496 MONO_OBJECT_SETREF (this, method, method);
5498 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
5499 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
5500 this->async_result = NULL;
5501 this->call_type = CallType_Sync;
5503 names = g_new (char *, sig->param_count);
5504 mono_method_get_param_names (method->method, (const char **) names);
5505 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
5507 for (i = 0; i < sig->param_count; i++) {
5508 name = mono_string_new (domain, names [i]);
5509 mono_array_setref (this->names, i, name);
5512 g_free (names);
5513 for (i = 0, j = 0; i < sig->param_count; i++) {
5514 if (sig->params [i]->byref) {
5515 if (out_args) {
5516 MonoObject* arg = mono_array_get (out_args, gpointer, j);
5517 mono_array_setref (this->args, i, arg);
5518 j++;
5520 arg_type = 2;
5521 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5522 arg_type |= 1;
5523 } else {
5524 arg_type = 1;
5525 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5526 arg_type |= 4;
5528 mono_array_set (this->arg_types, guint8, i, arg_type);
5533 * mono_remoting_invoke:
5534 * @real_proxy: pointer to a RealProxy object
5535 * @msg: The MonoMethodMessage to execute
5536 * @exc: used to store exceptions
5537 * @out_args: used to store output arguments
5539 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5540 * IMessage interface and it is not trivial to extract results from there. So
5541 * we call an helper method PrivateInvoke instead of calling
5542 * RealProxy::Invoke() directly.
5544 * Returns: the result object.
5546 MonoObject *
5547 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
5548 MonoObject **exc, MonoArray **out_args)
5550 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5551 gpointer pa [4];
5553 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5555 if (!im) {
5556 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
5557 g_assert (im);
5558 real_proxy->vtable->domain->private_invoke_method = im;
5561 pa [0] = real_proxy;
5562 pa [1] = msg;
5563 pa [2] = exc;
5564 pa [3] = out_args;
5566 return mono_runtime_invoke (im, NULL, pa, exc);
5569 MonoObject *
5570 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
5571 MonoObject **exc, MonoArray **out_args)
5573 static MonoClass *object_array_klass;
5574 MonoDomain *domain;
5575 MonoMethod *method;
5576 MonoMethodSignature *sig;
5577 MonoObject *ret;
5578 int i, j, outarg_count = 0;
5580 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5582 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
5583 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5584 target = tp->rp->unwrapped_server;
5585 } else {
5586 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
5590 domain = mono_domain_get ();
5591 method = msg->method->method;
5592 sig = mono_method_signature (method);
5594 for (i = 0; i < sig->param_count; i++) {
5595 if (sig->params [i]->byref)
5596 outarg_count++;
5599 if (!object_array_klass) {
5600 MonoClass *klass;
5602 klass = mono_array_class_get (mono_defaults.object_class, 1);
5603 g_assert (klass);
5605 mono_memory_barrier ();
5606 object_array_klass = klass;
5609 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
5610 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
5611 *exc = NULL;
5613 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
5615 for (i = 0, j = 0; i < sig->param_count; i++) {
5616 if (sig->params [i]->byref) {
5617 MonoObject* arg;
5618 arg = mono_array_get (msg->args, gpointer, i);
5619 mono_array_setref (*out_args, j, arg);
5620 j++;
5624 return ret;
5628 * mono_print_unhandled_exception:
5629 * @exc: The exception
5631 * Prints the unhandled exception.
5633 void
5634 mono_print_unhandled_exception (MonoObject *exc)
5636 MonoError error;
5637 char *message = (char *) "";
5638 MonoString *str;
5639 MonoMethod *method;
5640 MonoClass *klass;
5641 gboolean free_message = FALSE;
5643 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
5644 klass = exc->vtable->klass;
5645 method = NULL;
5646 while (klass && method == NULL) {
5647 method = mono_class_get_method_from_name_flags (klass, "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
5648 if (method == NULL)
5649 klass = klass->parent;
5652 g_assert (method);
5654 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
5655 if (str) {
5656 message = mono_string_to_utf8_checked (str, &error);
5657 if (!mono_error_ok (&error)) {
5658 mono_error_cleanup (&error);
5659 message = (char *)"";
5660 } else {
5661 free_message = TRUE;
5667 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
5668 * exc->vtable->klass->name, message);
5670 g_printerr ("\nUnhandled Exception: %s\n", message);
5672 if (free_message)
5673 g_free (message);
5677 * mono_delegate_ctor:
5678 * @this: pointer to an uninitialized delegate object
5679 * @target: target object
5680 * @addr: pointer to native code
5681 * @method: method
5683 * Initialize a delegate and sets a specific method, not the one
5684 * associated with addr. This is useful when sharing generic code.
5685 * In that case addr will most probably not be associated with the
5686 * correct instantiation of the method.
5688 void
5689 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
5691 MonoDelegate *delegate = (MonoDelegate *)this;
5692 MonoClass *class;
5694 g_assert (this);
5695 g_assert (addr);
5697 if (method)
5698 delegate->method = method;
5700 class = this->vtable->klass;
5701 mono_stats.delegate_creations++;
5703 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5704 g_assert (method);
5705 method = mono_marshal_get_remoting_invoke (method);
5706 delegate->method_ptr = mono_compile_method (method);
5707 MONO_OBJECT_SETREF (delegate, target, target);
5708 } else if (method && mono_method_signature (method)->hasthis && method->klass->valuetype) {
5709 method = mono_marshal_get_unbox_wrapper (method);
5710 delegate->method_ptr = mono_compile_method (method);
5711 MONO_OBJECT_SETREF (delegate, target, target);
5712 } else {
5713 delegate->method_ptr = addr;
5714 MONO_OBJECT_SETREF (delegate, target, target);
5717 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
5721 * mono_delegate_ctor:
5722 * @this: pointer to an uninitialized delegate object
5723 * @target: target object
5724 * @addr: pointer to native code
5726 * This is used to initialize a delegate.
5728 void
5729 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
5731 MonoDomain *domain = mono_domain_get ();
5732 MonoJitInfo *ji;
5733 MonoMethod *method = NULL;
5735 g_assert (addr);
5737 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
5738 method = ji->method;
5739 g_assert (!method->klass->generic_container);
5742 mono_delegate_ctor_with_method (this, target, addr, method);
5746 * mono_method_call_message_new:
5747 * @method: method to encapsulate
5748 * @params: parameters to the method
5749 * @invoke: optional, delegate invoke.
5750 * @cb: async callback delegate.
5751 * @state: state passed to the async callback.
5753 * Translates arguments pointers into a MonoMethodMessage.
5755 MonoMethodMessage *
5756 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
5757 MonoDelegate **cb, MonoObject **state)
5759 MonoDomain *domain = mono_domain_get ();
5760 MonoMethodSignature *sig = mono_method_signature (method);
5761 MonoMethodMessage *msg;
5762 int i, count, type;
5764 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5766 if (invoke) {
5767 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
5768 count = sig->param_count - 2;
5769 } else {
5770 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
5771 count = sig->param_count;
5774 for (i = 0; i < count; i++) {
5775 gpointer vpos;
5776 MonoClass *class;
5777 MonoObject *arg;
5779 if (sig->params [i]->byref)
5780 vpos = *((gpointer *)params [i]);
5781 else
5782 vpos = params [i];
5784 type = sig->params [i]->type;
5785 class = mono_class_from_mono_type (sig->params [i]);
5787 if (class->valuetype)
5788 arg = mono_value_box (domain, class, vpos);
5789 else
5790 arg = *((MonoObject **)vpos);
5792 mono_array_setref (msg->args, i, arg);
5795 if (cb != NULL && state != NULL) {
5796 *cb = *((MonoDelegate **)params [i]);
5797 i++;
5798 *state = *((MonoObject **)params [i]);
5801 return msg;
5805 * mono_method_return_message_restore:
5807 * Restore results from message based processing back to arguments pointers
5809 void
5810 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
5812 MonoMethodSignature *sig = mono_method_signature (method);
5813 int i, j, type, size, out_len;
5815 if (out_args == NULL)
5816 return;
5817 out_len = mono_array_length (out_args);
5818 if (out_len == 0)
5819 return;
5821 for (i = 0, j = 0; i < sig->param_count; i++) {
5822 MonoType *pt = sig->params [i];
5824 if (pt->byref) {
5825 char *arg;
5826 if (j >= out_len)
5827 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
5829 arg = mono_array_get (out_args, gpointer, j);
5830 type = pt->type;
5832 g_assert (type != MONO_TYPE_VOID);
5834 if (MONO_TYPE_IS_REFERENCE (pt)) {
5835 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
5836 } else {
5837 if (arg) {
5838 MonoClass *class = ((MonoObject*)arg)->vtable->klass;
5839 size = mono_class_value_size (class, NULL);
5840 if (class->has_references)
5841 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
5842 else
5843 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
5844 } else {
5845 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
5846 memset (*((gpointer *)params [i]), 0, size);
5850 j++;
5856 * mono_load_remote_field:
5857 * @this: pointer to an object
5858 * @klass: klass of the object containing @field
5859 * @field: the field to load
5860 * @res: a storage to store the result
5862 * This method is called by the runtime on attempts to load fields of
5863 * transparent proxy objects. @this points to such TP, @klass is the class of
5864 * the object containing @field. @res is a storage location which can be
5865 * used to store the result.
5867 * Returns: an address pointing to the value of field.
5869 gpointer
5870 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
5872 static MonoMethod *getter = NULL;
5873 MonoDomain *domain = mono_domain_get ();
5874 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5875 MonoClass *field_class;
5876 MonoMethodMessage *msg;
5877 MonoArray *out_args;
5878 MonoObject *exc;
5879 char* full_name;
5881 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5882 g_assert (res != NULL);
5884 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5885 mono_field_get_value (tp->rp->unwrapped_server, field, res);
5886 return res;
5889 if (!getter) {
5890 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5891 g_assert (getter);
5894 field_class = mono_class_from_mono_type (field->type);
5896 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5897 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5898 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5900 full_name = mono_type_get_full_name (klass);
5901 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5902 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5903 g_free (full_name);
5905 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5907 if (exc) mono_raise_exception ((MonoException *)exc);
5909 if (mono_array_length (out_args) == 0)
5910 return NULL;
5912 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
5914 if (field_class->valuetype) {
5915 return ((char *)*res) + sizeof (MonoObject);
5916 } else
5917 return res;
5921 * mono_load_remote_field_new:
5922 * @this:
5923 * @klass:
5924 * @field:
5926 * Missing documentation.
5928 MonoObject *
5929 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
5931 static MonoMethod *getter = NULL;
5932 MonoDomain *domain = mono_domain_get ();
5933 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5934 MonoClass *field_class;
5935 MonoMethodMessage *msg;
5936 MonoArray *out_args;
5937 MonoObject *exc, *res;
5938 char* full_name;
5940 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5942 field_class = mono_class_from_mono_type (field->type);
5944 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5945 gpointer val;
5946 if (field_class->valuetype) {
5947 res = mono_object_new (domain, field_class);
5948 val = ((gchar *) res) + sizeof (MonoObject);
5949 } else {
5950 val = &res;
5952 mono_field_get_value (tp->rp->unwrapped_server, field, val);
5953 return res;
5956 if (!getter) {
5957 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5958 g_assert (getter);
5961 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5962 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5964 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5966 full_name = mono_type_get_full_name (klass);
5967 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5968 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5969 g_free (full_name);
5971 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5973 if (exc) mono_raise_exception ((MonoException *)exc);
5975 if (mono_array_length (out_args) == 0)
5976 res = NULL;
5977 else
5978 res = mono_array_get (out_args, MonoObject *, 0);
5980 return res;
5984 * mono_store_remote_field:
5985 * @this: pointer to an object
5986 * @klass: klass of the object containing @field
5987 * @field: the field to load
5988 * @val: the value/object to store
5990 * This method is called by the runtime on attempts to store fields of
5991 * transparent proxy objects. @this points to such TP, @klass is the class of
5992 * the object containing @field. @val is the new value to store in @field.
5994 void
5995 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
5997 static MonoMethod *setter = NULL;
5998 MonoDomain *domain = mono_domain_get ();
5999 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6000 MonoClass *field_class;
6001 MonoMethodMessage *msg;
6002 MonoArray *out_args;
6003 MonoObject *exc;
6004 MonoObject *arg;
6005 char* full_name;
6007 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6009 field_class = mono_class_from_mono_type (field->type);
6011 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6012 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6013 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6014 return;
6017 if (!setter) {
6018 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6019 g_assert (setter);
6022 if (field_class->valuetype)
6023 arg = mono_value_box (domain, field_class, val);
6024 else
6025 arg = *((MonoObject **)val);
6028 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6029 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6031 full_name = mono_type_get_full_name (klass);
6032 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6033 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6034 mono_array_setref (msg->args, 2, arg);
6035 g_free (full_name);
6037 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6039 if (exc) mono_raise_exception ((MonoException *)exc);
6043 * mono_store_remote_field_new:
6044 * @this:
6045 * @klass:
6046 * @field:
6047 * @arg:
6049 * Missing documentation
6051 void
6052 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6054 static MonoMethod *setter = NULL;
6055 MonoDomain *domain = mono_domain_get ();
6056 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6057 MonoClass *field_class;
6058 MonoMethodMessage *msg;
6059 MonoArray *out_args;
6060 MonoObject *exc;
6061 char* full_name;
6063 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6065 field_class = mono_class_from_mono_type (field->type);
6067 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6068 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6069 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6070 return;
6073 if (!setter) {
6074 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6075 g_assert (setter);
6078 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6079 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6081 full_name = mono_type_get_full_name (klass);
6082 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6083 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6084 mono_array_setref (msg->args, 2, arg);
6085 g_free (full_name);
6087 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6089 if (exc) mono_raise_exception ((MonoException *)exc);
6093 * mono_create_ftnptr:
6095 * Given a function address, create a function descriptor for it.
6096 * This is only needed on some platforms.
6098 gpointer
6099 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6101 return callbacks.create_ftnptr (domain, addr);
6105 * mono_get_addr_from_ftnptr:
6107 * Given a pointer to a function descriptor, return the function address.
6108 * This is only needed on some platforms.
6110 gpointer
6111 mono_get_addr_from_ftnptr (gpointer descr)
6113 return callbacks.get_addr_from_ftnptr (descr);
6116 #if 0
6118 * mono_string_chars:
6119 * @s: a MonoString
6121 * Returns a pointer to the UCS16 characters stored in the MonoString
6123 gunichar2 *
6124 mono_string_chars(MonoString *s)
6126 /* This method is here only for documentation extraction, this is a macro */
6130 * mono_string_length:
6131 * @s: MonoString
6133 * Returns the lenght in characters of the string
6136 mono_string_length (MonoString *s)
6138 /* This method is here only for documentation extraction, this is a macro */
6141 #endif