[sgen] One internal allocator per worker thread, to get rid of locking.
[mono-project/dkf.git] / mono / metadata / object.c
blob0eb1c1a9ee8a737ba8d9005824a6cfb46d21cf19
1 /*
2 * object.c: Object creation for the Mono runtime
4 * Author:
5 * Miguel de Icaza (miguel@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
8 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11 #include <config.h>
12 #ifdef HAVE_ALLOCA_H
13 #include <alloca.h>
14 #endif
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <signal.h>
18 #include <string.h>
19 #include <mono/metadata/mono-endian.h>
20 #include <mono/metadata/tabledefs.h>
21 #include <mono/metadata/tokentype.h>
22 #include <mono/metadata/loader.h>
23 #include <mono/metadata/object.h>
24 #include <mono/metadata/gc-internal.h>
25 #include <mono/metadata/exception.h>
26 #include <mono/metadata/domain-internals.h>
27 #include "mono/metadata/metadata-internals.h"
28 #include "mono/metadata/class-internals.h"
29 #include <mono/metadata/assembly.h>
30 #include <mono/metadata/threadpool.h>
31 #include <mono/metadata/marshal.h>
32 #include "mono/metadata/debug-helpers.h"
33 #include "mono/metadata/marshal.h"
34 #include <mono/metadata/threads.h>
35 #include <mono/metadata/threads-types.h>
36 #include <mono/metadata/environment.h>
37 #include "mono/metadata/profiler-private.h"
38 #include "mono/metadata/security-manager.h"
39 #include "mono/metadata/mono-debug-debugger.h"
40 #include <mono/metadata/gc-internal.h>
41 #include <mono/metadata/verify-internals.h>
42 #include <mono/utils/strenc.h>
43 #include <mono/utils/mono-counters.h>
44 #include <mono/utils/mono-error-internals.h>
45 #include "cominterop.h"
47 #ifdef HAVE_BOEHM_GC
48 #define NEED_TO_ZERO_PTRFREE 1
49 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = GC_MALLOC_ATOMIC ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
50 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = GC_MALLOC ((size)); (obj)->vtable = (vt);} while (0)
51 #ifdef HAVE_GC_GCJ_MALLOC
52 #define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
53 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_GCJ_MALLOC ((size),(type)); } while (0)
54 #else
55 #define GC_NO_DESCRIPTOR (NULL)
56 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_MALLOC ((size)); *(gpointer*)dest = (type);} while (0)
57 #endif
58 #else
59 #ifdef HAVE_SGEN_GC
60 #define GC_NO_DESCRIPTOR (NULL)
61 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
62 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
63 #define ALLOC_TYPED(dest,size,type) do { (dest) = mono_gc_alloc_obj (type, size);} while (0)
64 #else
65 #define NEED_TO_ZERO_PTRFREE 1
66 #define GC_NO_DESCRIPTOR (NULL)
67 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = malloc ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
68 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = calloc (1, (size)); (obj)->vtable = (vt);} while (0)
69 #define ALLOC_TYPED(dest,size,type) do { (dest) = calloc (1, (size)); *(gpointer*)dest = (type);} while (0)
70 #endif
71 #endif
73 static MonoObject* mono_object_new_ptrfree (MonoVTable *vtable);
74 static MonoObject* mono_object_new_ptrfree_box (MonoVTable *vtable);
76 static void
77 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
79 static MonoString*
80 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig);
82 #define ldstr_lock() EnterCriticalSection (&ldstr_section)
83 #define ldstr_unlock() LeaveCriticalSection (&ldstr_section)
84 static CRITICAL_SECTION ldstr_section;
86 static gboolean profile_allocs = TRUE;
88 void
89 mono_runtime_object_init (MonoObject *this)
91 MonoMethod *method = NULL;
92 MonoClass *klass = this->vtable->klass;
94 method = mono_class_get_method_from_name (klass, ".ctor", 0);
95 g_assert (method);
97 if (method->klass->valuetype)
98 this = mono_object_unbox (this);
99 mono_runtime_invoke (method, this, NULL, NULL);
102 /* The pseudo algorithm for type initialization from the spec
103 Note it doesn't say anything about domains - only threads.
105 2. If the type is initialized you are done.
106 2.1. If the type is not yet initialized, try to take an
107 initialization lock.
108 2.2. If successful, record this thread as responsible for
109 initializing the type and proceed to step 2.3.
110 2.2.1. If not, see whether this thread or any thread
111 waiting for this thread to complete already holds the lock.
112 2.2.2. If so, return since blocking would create a deadlock. This thread
113 will now see an incompletely initialized state for the type,
114 but no deadlock will arise.
115 2.2.3 If not, block until the type is initialized then return.
116 2.3 Initialize the parent type and then all interfaces implemented
117 by this type.
118 2.4 Execute the type initialization code for this type.
119 2.5 Mark the type as initialized, release the initialization lock,
120 awaken any threads waiting for this type to be initialized,
121 and return.
125 typedef struct
127 guint32 initializing_tid;
128 guint32 waiting_count;
129 gboolean done;
130 CRITICAL_SECTION initialization_section;
131 } TypeInitializationLock;
133 /* for locking access to type_initialization_hash and blocked_thread_hash */
134 #define mono_type_initialization_lock() EnterCriticalSection (&type_initialization_section)
135 #define mono_type_initialization_unlock() LeaveCriticalSection (&type_initialization_section)
136 static CRITICAL_SECTION type_initialization_section;
138 /* from vtable to lock */
139 static GHashTable *type_initialization_hash;
141 /* from thread id to thread id being waited on */
142 static GHashTable *blocked_thread_hash;
144 /* Main thread */
145 static MonoThread *main_thread;
147 /* Functions supplied by the runtime */
148 static MonoRuntimeCallbacks callbacks;
151 * mono_thread_set_main:
152 * @thread: thread to set as the main thread
154 * This function can be used to instruct the runtime to treat @thread
155 * as the main thread, ie, the thread that would normally execute the Main()
156 * method. This basically means that at the end of @thread, the runtime will
157 * wait for the existing foreground threads to quit and other such details.
159 void
160 mono_thread_set_main (MonoThread *thread)
162 main_thread = thread;
165 MonoThread*
166 mono_thread_get_main (void)
168 return main_thread;
171 void
172 mono_type_initialization_init (void)
174 InitializeCriticalSection (&type_initialization_section);
175 type_initialization_hash = g_hash_table_new (NULL, NULL);
176 blocked_thread_hash = g_hash_table_new (NULL, NULL);
177 InitializeCriticalSection (&ldstr_section);
180 void
181 mono_type_initialization_cleanup (void)
183 #if 0
184 /* This is causing race conditions with
185 * mono_release_type_locks
187 DeleteCriticalSection (&type_initialization_section);
188 #endif
189 DeleteCriticalSection (&ldstr_section);
193 * get_type_init_exception_for_vtable:
195 * Return the stored type initialization exception for VTABLE.
197 static MonoException*
198 get_type_init_exception_for_vtable (MonoVTable *vtable)
200 MonoDomain *domain = vtable->domain;
201 MonoClass *klass = vtable->klass;
202 MonoException *ex;
203 gchar *full_name;
205 g_assert (vtable->init_failed);
208 * If the initializing thread was rudely aborted, the exception is not stored
209 * in the hash.
211 ex = NULL;
212 mono_domain_lock (domain);
213 if (domain->type_init_exception_hash)
214 ex = mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
215 mono_domain_unlock (domain);
217 if (!ex) {
218 if (klass->name_space && *klass->name_space)
219 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
220 else
221 full_name = g_strdup (klass->name);
222 ex = mono_get_exception_type_initialization (full_name, NULL);
223 g_free (full_name);
226 return ex;
229 * mono_runtime_class_init:
230 * @vtable: vtable that needs to be initialized
232 * This routine calls the class constructor for @vtable.
234 void
235 mono_runtime_class_init (MonoVTable *vtable)
237 mono_runtime_class_init_full (vtable, TRUE);
241 * mono_runtime_class_init_full:
242 * @vtable that neeeds to be initialized
243 * @raise_exception is TRUE, exceptions are raised intead of returned
246 MonoException *
247 mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
249 MonoException *exc;
250 MonoException *exc_to_throw;
251 MonoMethod *method = NULL;
252 MonoClass *klass;
253 gchar *full_name;
255 MONO_ARCH_SAVE_REGS;
257 if (vtable->initialized)
258 return NULL;
260 exc = NULL;
261 klass = vtable->klass;
263 if (!klass->image->checked_module_cctor) {
264 mono_image_check_for_module_cctor (klass->image);
265 if (klass->image->has_module_cctor) {
266 MonoClass *module_klass = mono_class_get (klass->image, MONO_TOKEN_TYPE_DEF | 1);
267 MonoVTable *module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception);
268 if (!module_vtable)
269 return NULL;
270 mono_runtime_class_init (module_vtable);
273 method = mono_class_get_cctor (klass);
275 if (method) {
276 MonoDomain *domain = vtable->domain;
277 TypeInitializationLock *lock;
278 guint32 tid = GetCurrentThreadId();
279 int do_initialization = 0;
280 MonoDomain *last_domain = NULL;
282 mono_type_initialization_lock ();
283 /* double check... */
284 if (vtable->initialized) {
285 mono_type_initialization_unlock ();
286 return NULL;
288 if (vtable->init_failed) {
289 mono_type_initialization_unlock ();
291 /* The type initialization already failed once, rethrow the same exception */
292 if (raise_exception)
293 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
294 return get_type_init_exception_for_vtable (vtable);
296 lock = g_hash_table_lookup (type_initialization_hash, vtable);
297 if (lock == NULL) {
298 /* This thread will get to do the initialization */
299 if (mono_domain_get () != domain) {
300 /* Transfer into the target domain */
301 last_domain = mono_domain_get ();
302 if (!mono_domain_set (domain, FALSE)) {
303 vtable->initialized = 1;
304 mono_type_initialization_unlock ();
305 if (raise_exception)
306 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
307 return mono_get_exception_appdomain_unloaded ();
310 lock = g_malloc (sizeof(TypeInitializationLock));
311 InitializeCriticalSection (&lock->initialization_section);
312 lock->initializing_tid = tid;
313 lock->waiting_count = 1;
314 lock->done = FALSE;
315 /* grab the vtable lock while this thread still owns type_initialization_section */
316 EnterCriticalSection (&lock->initialization_section);
317 g_hash_table_insert (type_initialization_hash, vtable, lock);
318 do_initialization = 1;
319 } else {
320 gpointer blocked;
321 TypeInitializationLock *pending_lock;
323 if (lock->initializing_tid == tid || lock->done) {
324 mono_type_initialization_unlock ();
325 return NULL;
327 /* see if the thread doing the initialization is already blocked on this thread */
328 blocked = GUINT_TO_POINTER (lock->initializing_tid);
329 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
330 if (pending_lock->initializing_tid == tid) {
331 if (!pending_lock->done) {
332 mono_type_initialization_unlock ();
333 return NULL;
334 } else {
335 /* the thread doing the initialization is blocked on this thread,
336 but on a lock that has already been freed. It just hasn't got
337 time to awake */
338 break;
341 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
343 ++lock->waiting_count;
344 /* record the fact that we are waiting on the initializing thread */
345 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
347 mono_type_initialization_unlock ();
349 if (do_initialization) {
350 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
352 /* If the initialization failed, mark the class as unusable. */
353 /* Avoid infinite loops */
354 if (!(exc == NULL ||
355 (klass->image == mono_defaults.corlib &&
356 !strcmp (klass->name_space, "System") &&
357 !strcmp (klass->name, "TypeInitializationException")))) {
358 vtable->init_failed = 1;
360 if (klass->name_space && *klass->name_space)
361 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
362 else
363 full_name = g_strdup (klass->name);
364 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
365 g_free (full_name);
368 * Store the exception object so it could be thrown on subsequent
369 * accesses.
371 mono_domain_lock (domain);
372 if (!domain->type_init_exception_hash)
373 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC);
374 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
375 mono_domain_unlock (domain);
378 if (last_domain)
379 mono_domain_set (last_domain, TRUE);
380 lock->done = TRUE;
381 LeaveCriticalSection (&lock->initialization_section);
382 } else {
383 /* this just blocks until the initializing thread is done */
384 EnterCriticalSection (&lock->initialization_section);
385 LeaveCriticalSection (&lock->initialization_section);
388 mono_type_initialization_lock ();
389 if (lock->initializing_tid != tid)
390 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
391 --lock->waiting_count;
392 if (lock->waiting_count == 0) {
393 DeleteCriticalSection (&lock->initialization_section);
394 g_hash_table_remove (type_initialization_hash, vtable);
395 g_free (lock);
397 if (!vtable->init_failed)
398 vtable->initialized = 1;
399 mono_type_initialization_unlock ();
401 if (vtable->init_failed) {
402 /* Either we were the initializing thread or we waited for the initialization */
403 if (raise_exception)
404 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
405 return get_type_init_exception_for_vtable (vtable);
407 } else {
408 vtable->initialized = 1;
409 return NULL;
411 return NULL;
414 static
415 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
417 MonoVTable *vtable = (MonoVTable*)key;
419 TypeInitializationLock *lock = (TypeInitializationLock*) value;
420 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
421 lock->done = TRUE;
423 * Have to set this since it cannot be set by the normal code in
424 * mono_runtime_class_init (). In this case, the exception object is not stored,
425 * and get_type_init_exception_for_class () needs to be aware of this.
427 vtable->init_failed = 1;
428 LeaveCriticalSection (&lock->initialization_section);
429 --lock->waiting_count;
430 if (lock->waiting_count == 0) {
431 DeleteCriticalSection (&lock->initialization_section);
432 g_free (lock);
433 return TRUE;
436 return FALSE;
439 void
440 mono_release_type_locks (MonoInternalThread *thread)
442 mono_type_initialization_lock ();
443 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
444 mono_type_initialization_unlock ();
447 static gpointer
448 default_trampoline (MonoMethod *method)
450 return method;
453 static gpointer
454 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
456 g_assert_not_reached ();
458 return NULL;
461 static gpointer
462 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
464 g_error ("remoting not installed");
465 return NULL;
468 static gpointer
469 default_delegate_trampoline (MonoClass *klass)
471 g_assert_not_reached ();
472 return NULL;
475 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
476 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
477 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
478 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
479 static MonoImtThunkBuilder imt_thunk_builder = NULL;
480 #define ARCH_USE_IMT (imt_thunk_builder != NULL)
481 #if (MONO_IMT_SIZE > 32)
482 #error "MONO_IMT_SIZE cannot be larger than 32"
483 #endif
485 void
486 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
488 memcpy (&callbacks, cbs, sizeof (*cbs));
491 MonoRuntimeCallbacks*
492 mono_get_runtime_callbacks (void)
494 return &callbacks;
497 void
498 mono_install_trampoline (MonoTrampoline func)
500 arch_create_jit_trampoline = func? func: default_trampoline;
503 void
504 mono_install_jump_trampoline (MonoJumpTrampoline func)
506 arch_create_jump_trampoline = func? func: default_jump_trampoline;
509 void
510 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
512 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
515 void
516 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
518 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
521 void
522 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
523 imt_thunk_builder = func;
526 static MonoCompileFunc default_mono_compile_method = NULL;
529 * mono_install_compile_method:
530 * @func: function to install
532 * This is a VM internal routine
534 void
535 mono_install_compile_method (MonoCompileFunc func)
537 default_mono_compile_method = func;
541 * mono_compile_method:
542 * @method: The method to compile.
544 * This JIT-compiles the method, and returns the pointer to the native code
545 * produced.
547 gpointer
548 mono_compile_method (MonoMethod *method)
550 if (!default_mono_compile_method) {
551 g_error ("compile method called on uninitialized runtime");
552 return NULL;
554 return default_mono_compile_method (method);
557 gpointer
558 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
560 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
563 gpointer
564 mono_runtime_create_delegate_trampoline (MonoClass *klass)
566 return arch_create_delegate_trampoline (klass);
569 static MonoFreeMethodFunc default_mono_free_method = NULL;
572 * mono_install_free_method:
573 * @func: pointer to the MonoFreeMethodFunc used to release a method
575 * This is an internal VM routine, it is used for the engines to
576 * register a handler to release the resources associated with a method.
578 * Methods are freed when no more references to the delegate that holds
579 * them are left.
581 void
582 mono_install_free_method (MonoFreeMethodFunc func)
584 default_mono_free_method = func;
588 * mono_runtime_free_method:
589 * @domain; domain where the method is hosted
590 * @method: method to release
592 * This routine is invoked to free the resources associated with
593 * a method that has been JIT compiled. This is used to discard
594 * methods that were used only temporarily (for example, used in marshalling)
597 void
598 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
600 if (default_mono_free_method != NULL)
601 default_mono_free_method (domain, method);
603 mono_method_clear_object (domain, method);
605 mono_free_method (method);
609 * The vtables in the root appdomain are assumed to be reachable by other
610 * roots, and we don't use typed allocation in the other domains.
613 /* The sync block is no longer a GC pointer */
614 #define GC_HEADER_BITMAP (0)
616 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
618 static gsize*
619 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
621 MonoClassField *field;
622 MonoClass *p;
623 guint32 pos;
624 int max_size;
626 if (static_fields)
627 max_size = mono_class_data_size (class) / sizeof (gpointer);
628 else
629 max_size = class->instance_size / sizeof (gpointer);
630 if (max_size > size) {
631 g_assert (offset <= 0);
632 bitmap = g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
633 size = max_size;
636 #ifdef HAVE_SGEN_GC
637 /*An Ephemeron cannot be marked by sgen*/
638 if (!static_fields && class->image == mono_defaults.corlib && !strcmp ("Ephemeron", class->name)) {
639 *max_set = 0;
640 memset (bitmap, 0, size / 8);
641 return bitmap;
643 #endif
645 for (p = class; p != NULL; p = p->parent) {
646 gpointer iter = NULL;
647 while ((field = mono_class_get_fields (p, &iter))) {
648 MonoType *type;
650 if (static_fields) {
651 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
652 continue;
653 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
654 continue;
655 } else {
656 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
657 continue;
659 /* FIXME: should not happen, flag as type load error */
660 if (field->type->byref)
661 break;
663 if (static_fields && field->offset == -1)
664 /* special static */
665 continue;
667 pos = field->offset / sizeof (gpointer);
668 pos += offset;
670 type = mono_type_get_underlying_type (field->type);
671 switch (type->type) {
672 case MONO_TYPE_I:
673 case MONO_TYPE_PTR:
674 case MONO_TYPE_FNPTR:
675 break;
676 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
677 case MONO_TYPE_U:
678 #ifdef HAVE_SGEN_GC
679 break;
680 #else
681 if (class->image != mono_defaults.corlib)
682 break;
683 #endif
684 case MONO_TYPE_STRING:
685 case MONO_TYPE_SZARRAY:
686 case MONO_TYPE_CLASS:
687 case MONO_TYPE_OBJECT:
688 case MONO_TYPE_ARRAY:
689 g_assert ((field->offset % sizeof(gpointer)) == 0);
691 g_assert (pos < size || pos <= max_size);
692 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
693 *max_set = MAX (*max_set, pos);
694 break;
695 case MONO_TYPE_GENERICINST:
696 if (!mono_type_generic_inst_is_valuetype (type)) {
697 g_assert ((field->offset % sizeof(gpointer)) == 0);
699 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
700 *max_set = MAX (*max_set, pos);
701 break;
702 } else {
703 /* fall through */
705 case MONO_TYPE_VALUETYPE: {
706 MonoClass *fclass = mono_class_from_mono_type (field->type);
707 if (fclass->has_references) {
708 /* remove the object header */
709 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
711 break;
713 case MONO_TYPE_I1:
714 case MONO_TYPE_U1:
715 case MONO_TYPE_I2:
716 case MONO_TYPE_U2:
717 case MONO_TYPE_I4:
718 case MONO_TYPE_U4:
719 case MONO_TYPE_I8:
720 case MONO_TYPE_U8:
721 case MONO_TYPE_R4:
722 case MONO_TYPE_R8:
723 case MONO_TYPE_BOOLEAN:
724 case MONO_TYPE_CHAR:
725 break;
726 default:
727 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
728 break;
731 if (static_fields)
732 break;
734 return bitmap;
737 #if 0
739 * similar to the above, but sets the bits in the bitmap for any non-ref field
740 * and ignores static fields
742 static gsize*
743 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
745 MonoClassField *field;
746 MonoClass *p;
747 guint32 pos, pos2;
748 int max_size;
750 max_size = class->instance_size / sizeof (gpointer);
751 if (max_size >= size) {
752 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
755 for (p = class; p != NULL; p = p->parent) {
756 gpointer iter = NULL;
757 while ((field = mono_class_get_fields (p, &iter))) {
758 MonoType *type;
760 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
761 continue;
762 /* FIXME: should not happen, flag as type load error */
763 if (field->type->byref)
764 break;
766 pos = field->offset / sizeof (gpointer);
767 pos += offset;
769 type = mono_type_get_underlying_type (field->type);
770 switch (type->type) {
771 #if SIZEOF_VOID_P == 8
772 case MONO_TYPE_I:
773 case MONO_TYPE_U:
774 case MONO_TYPE_PTR:
775 case MONO_TYPE_FNPTR:
776 #endif
777 case MONO_TYPE_I8:
778 case MONO_TYPE_U8:
779 case MONO_TYPE_R8:
780 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
781 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
782 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
784 /* fall through */
785 #if SIZEOF_VOID_P == 4
786 case MONO_TYPE_I:
787 case MONO_TYPE_U:
788 case MONO_TYPE_PTR:
789 case MONO_TYPE_FNPTR:
790 #endif
791 case MONO_TYPE_I4:
792 case MONO_TYPE_U4:
793 case MONO_TYPE_R4:
794 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
795 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
796 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
798 /* fall through */
799 case MONO_TYPE_CHAR:
800 case MONO_TYPE_I2:
801 case MONO_TYPE_U2:
802 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
803 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
804 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
806 /* fall through */
807 case MONO_TYPE_BOOLEAN:
808 case MONO_TYPE_I1:
809 case MONO_TYPE_U1:
810 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
811 break;
812 case MONO_TYPE_STRING:
813 case MONO_TYPE_SZARRAY:
814 case MONO_TYPE_CLASS:
815 case MONO_TYPE_OBJECT:
816 case MONO_TYPE_ARRAY:
817 break;
818 case MONO_TYPE_GENERICINST:
819 if (!mono_type_generic_inst_is_valuetype (type)) {
820 break;
821 } else {
822 /* fall through */
824 case MONO_TYPE_VALUETYPE: {
825 MonoClass *fclass = mono_class_from_mono_type (field->type);
826 /* remove the object header */
827 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
828 break;
830 default:
831 g_assert_not_reached ();
832 break;
836 return bitmap;
840 * mono_class_insecure_overlapping:
841 * check if a class with explicit layout has references and non-references
842 * fields overlapping.
844 * Returns: TRUE if it is insecure to load the type.
846 gboolean
847 mono_class_insecure_overlapping (MonoClass *klass)
849 int max_set = 0;
850 gsize *bitmap;
851 gsize default_bitmap [4] = {0};
852 gsize *nrbitmap;
853 gsize default_nrbitmap [4] = {0};
854 int i, insecure = FALSE;
855 return FALSE;
857 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
858 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
860 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
861 int idx = i % (sizeof (bitmap [0]) * 8);
862 if (bitmap [idx] & nrbitmap [idx]) {
863 insecure = TRUE;
864 break;
867 if (bitmap != default_bitmap)
868 g_free (bitmap);
869 if (nrbitmap != default_nrbitmap)
870 g_free (nrbitmap);
871 if (insecure) {
872 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
873 return FALSE;
875 return insecure;
877 #endif
879 MonoString*
880 mono_string_alloc (int length)
882 return mono_string_new_size (mono_domain_get (), length);
885 void
886 mono_class_compute_gc_descriptor (MonoClass *class)
888 int max_set = 0;
889 gsize *bitmap;
890 gsize default_bitmap [4] = {0};
891 static gboolean gcj_inited = FALSE;
893 if (!gcj_inited) {
894 mono_loader_lock ();
896 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
897 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
898 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
899 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
901 #ifdef HAVE_GC_GCJ_MALLOC
903 * This is not needed unless the relevant code in mono_get_allocation_ftn () is
904 * turned on.
906 #if 0
907 #ifdef GC_REDIRECT_TO_LOCAL
908 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
909 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
910 #endif
911 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
912 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
913 #endif
915 #endif
916 gcj_inited = TRUE;
917 mono_loader_unlock ();
920 if (!class->inited)
921 mono_class_init (class);
923 if (class->gc_descr_inited)
924 return;
926 class->gc_descr_inited = TRUE;
927 class->gc_descr = GC_NO_DESCRIPTOR;
929 bitmap = default_bitmap;
930 if (class == mono_defaults.string_class) {
931 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
932 } else if (class->rank) {
933 mono_class_compute_gc_descriptor (class->element_class);
934 if (!class->element_class->valuetype) {
935 gsize abm = 1;
936 class->gc_descr = mono_gc_make_descr_for_array (TRUE, &abm, 1, sizeof (gpointer));
937 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
938 class->name_space, class->name);*/
939 } else {
940 /* remove the object header */
941 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
942 class->gc_descr = mono_gc_make_descr_for_array (TRUE, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
943 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
944 class->name_space, class->name);*/
945 if (bitmap != default_bitmap)
946 g_free (bitmap);
948 } else {
949 /*static int count = 0;
950 if (count++ > 58)
951 return;*/
952 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
953 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
955 if (class->gc_descr == GC_NO_DESCRIPTOR)
956 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
958 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
959 if (bitmap != default_bitmap)
960 g_free (bitmap);
965 * field_is_special_static:
966 * @fklass: The MonoClass to look up.
967 * @field: The MonoClassField describing the field.
969 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
970 * SPECIAL_STATIC_NONE otherwise.
972 static gint32
973 field_is_special_static (MonoClass *fklass, MonoClassField *field)
975 MonoCustomAttrInfo *ainfo;
976 int i;
977 ainfo = mono_custom_attrs_from_field (fklass, field);
978 if (!ainfo)
979 return FALSE;
980 for (i = 0; i < ainfo->num_attrs; ++i) {
981 MonoClass *klass = ainfo->attrs [i].ctor->klass;
982 if (klass->image == mono_defaults.corlib) {
983 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
984 mono_custom_attrs_free (ainfo);
985 return SPECIAL_STATIC_THREAD;
987 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
988 mono_custom_attrs_free (ainfo);
989 return SPECIAL_STATIC_CONTEXT;
993 mono_custom_attrs_free (ainfo);
994 return SPECIAL_STATIC_NONE;
997 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
998 #define mix(a,b,c) { \
999 a -= c; a ^= rot(c, 4); c += b; \
1000 b -= a; b ^= rot(a, 6); a += c; \
1001 c -= b; c ^= rot(b, 8); b += a; \
1002 a -= c; a ^= rot(c,16); c += b; \
1003 b -= a; b ^= rot(a,19); a += c; \
1004 c -= b; c ^= rot(b, 4); b += a; \
1006 #define final(a,b,c) { \
1007 c ^= b; c -= rot(b,14); \
1008 a ^= c; a -= rot(c,11); \
1009 b ^= a; b -= rot(a,25); \
1010 c ^= b; c -= rot(b,16); \
1011 a ^= c; a -= rot(c,4); \
1012 b ^= a; b -= rot(a,14); \
1013 c ^= b; c -= rot(b,24); \
1017 * mono_method_get_imt_slot:
1019 * The IMT slot is embedded into AOTed code, so this must return the same value
1020 * for the same method across all executions. This means:
1021 * - pointers shouldn't be used as hash values.
1022 * - mono_metadata_str_hash () should be used for hashing strings.
1024 guint32
1025 mono_method_get_imt_slot (MonoMethod *method)
1027 MonoMethodSignature *sig;
1028 int hashes_count;
1029 guint32 *hashes_start, *hashes;
1030 guint32 a, b, c;
1031 int i;
1033 /* This can be used to stress tests the collision code */
1034 //return 0;
1037 * We do this to simplify generic sharing. It will hurt
1038 * performance in cases where a class implements two different
1039 * instantiations of the same generic interface.
1040 * The code in build_imt_slots () depends on this.
1042 if (method->is_inflated)
1043 method = ((MonoMethodInflated*)method)->declaring;
1045 sig = mono_method_signature (method);
1046 hashes_count = sig->param_count + 4;
1047 hashes_start = malloc (hashes_count * sizeof (guint32));
1048 hashes = hashes_start;
1050 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1051 printf ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod\n",
1052 method->klass->name_space, method->klass->name, method->name);
1053 g_assert_not_reached ();
1056 /* Initialize hashes */
1057 hashes [0] = mono_metadata_str_hash (method->klass->name);
1058 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1059 hashes [2] = mono_metadata_str_hash (method->name);
1060 hashes [3] = mono_metadata_type_hash (sig->ret);
1061 for (i = 0; i < sig->param_count; i++) {
1062 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1065 /* Setup internal state */
1066 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1068 /* Handle most of the hashes */
1069 while (hashes_count > 3) {
1070 a += hashes [0];
1071 b += hashes [1];
1072 c += hashes [2];
1073 mix (a,b,c);
1074 hashes_count -= 3;
1075 hashes += 3;
1078 /* Handle the last 3 hashes (all the case statements fall through) */
1079 switch (hashes_count) {
1080 case 3 : c += hashes [2];
1081 case 2 : b += hashes [1];
1082 case 1 : a += hashes [0];
1083 final (a,b,c);
1084 case 0: /* nothing left to add */
1085 break;
1088 free (hashes_start);
1089 /* Report the result */
1090 return c % MONO_IMT_SIZE;
1092 #undef rot
1093 #undef mix
1094 #undef final
1096 #define DEBUG_IMT 0
1098 static void
1099 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1100 guint32 imt_slot = mono_method_get_imt_slot (method);
1101 MonoImtBuilderEntry *entry;
1103 if (slot_num >= 0 && imt_slot != slot_num) {
1104 /* we build just a single imt slot and this is not it */
1105 return;
1108 entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
1109 entry->key = method;
1110 entry->value.vtable_slot = vtable_slot;
1111 entry->next = imt_builder [imt_slot];
1112 if (imt_builder [imt_slot] != NULL) {
1113 entry->children = imt_builder [imt_slot]->children + 1;
1114 if (entry->children == 1) {
1115 mono_stats.imt_slots_with_collisions++;
1116 *imt_collisions_bitmap |= (1 << imt_slot);
1118 } else {
1119 entry->children = 0;
1120 mono_stats.imt_used_slots++;
1122 imt_builder [imt_slot] = entry;
1123 #if DEBUG_IMT
1125 char *method_name = mono_method_full_name (method, TRUE);
1126 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1127 method, method_name, imt_slot, vtable_slot, entry->children);
1128 g_free (method_name);
1130 #endif
1133 #if DEBUG_IMT
1134 static void
1135 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1136 if (e != NULL) {
1137 MonoMethod *method = e->key;
1138 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1139 message,
1140 num,
1141 method,
1142 method->klass->name_space,
1143 method->klass->name,
1144 method->name);
1145 } else {
1146 printf (" * %s: NULL\n", message);
1149 #endif
1151 static int
1152 compare_imt_builder_entries (const void *p1, const void *p2) {
1153 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1154 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1156 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1159 static int
1160 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1162 int count = end - start;
1163 int chunk_start = out_array->len;
1164 if (count < 4) {
1165 int i;
1166 for (i = start; i < end; ++i) {
1167 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1168 item->key = sorted_array [i]->key;
1169 item->value = sorted_array [i]->value;
1170 item->has_target_code = sorted_array [i]->has_target_code;
1171 item->is_equals = TRUE;
1172 if (i < end - 1)
1173 item->check_target_idx = out_array->len + 1;
1174 else
1175 item->check_target_idx = 0;
1176 g_ptr_array_add (out_array, item);
1178 } else {
1179 int middle = start + count / 2;
1180 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1182 item->key = sorted_array [middle]->key;
1183 item->is_equals = FALSE;
1184 g_ptr_array_add (out_array, item);
1185 imt_emit_ir (sorted_array, start, middle, out_array);
1186 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1188 return chunk_start;
1191 static GPtrArray*
1192 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1193 int number_of_entries = entries->children + 1;
1194 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1195 GPtrArray *result = g_ptr_array_new ();
1196 MonoImtBuilderEntry *current_entry;
1197 int i;
1199 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1200 sorted_array [i] = current_entry;
1202 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1204 /*for (i = 0; i < number_of_entries; i++) {
1205 print_imt_entry (" sorted array:", sorted_array [i], i);
1208 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1210 free (sorted_array);
1211 return result;
1214 static gpointer
1215 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1217 if (imt_builder_entry != NULL) {
1218 if (imt_builder_entry->children == 0 && !fail_tramp) {
1219 /* No collision, return the vtable slot contents */
1220 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1221 } else {
1222 /* Collision, build the thunk */
1223 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1224 gpointer result;
1225 int i;
1226 result = imt_thunk_builder (vtable, domain,
1227 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1228 for (i = 0; i < imt_ir->len; ++i)
1229 g_free (g_ptr_array_index (imt_ir, i));
1230 g_ptr_array_free (imt_ir, TRUE);
1231 return result;
1233 } else {
1234 if (fail_tramp)
1235 return fail_tramp;
1236 else
1237 /* Empty slot */
1238 return NULL;
1242 static MonoImtBuilderEntry*
1243 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1246 * LOCKING: requires the loader and domain locks.
1249 static void
1250 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1252 int i;
1253 GSList *list_item;
1254 guint32 imt_collisions_bitmap = 0;
1255 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1256 int method_count = 0;
1257 gboolean record_method_count_for_max_collisions = FALSE;
1258 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1260 #if DEBUG_IMT
1261 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1262 #endif
1263 for (i = 0; i < klass->interface_offsets_count; ++i) {
1264 MonoClass *iface = klass->interfaces_packed [i];
1265 int interface_offset = klass->interface_offsets_packed [i];
1266 int method_slot_in_interface, vt_slot;
1268 if (mono_class_has_variant_generic_params (iface))
1269 has_variant_iface = TRUE;
1271 vt_slot = interface_offset;
1272 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1273 MonoMethod *method;
1275 if (slot_num >= 0 && iface->is_inflated) {
1277 * The imt slot of the method is the same as for its declaring method,
1278 * see the comment in mono_method_get_imt_slot (), so we can
1279 * avoid inflating methods which will be discarded by
1280 * add_imt_builder_entry anyway.
1282 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1283 if (mono_method_get_imt_slot (method) != slot_num) {
1284 vt_slot ++;
1285 continue;
1288 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1289 if (method->is_generic) {
1290 has_generic_virtual = TRUE;
1291 vt_slot ++;
1292 continue;
1295 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1296 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1297 vt_slot ++;
1301 if (extra_interfaces) {
1302 int interface_offset = klass->vtable_size;
1304 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1305 MonoClass* iface = list_item->data;
1306 int method_slot_in_interface;
1307 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1308 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1309 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1311 interface_offset += iface->method.count;
1314 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1315 /* overwrite the imt slot only if we're building all the entries or if
1316 * we're building this specific one
1318 if (slot_num < 0 || i == slot_num) {
1319 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1321 if (entries) {
1322 if (imt_builder [i]) {
1323 MonoImtBuilderEntry *entry;
1325 /* Link entries with imt_builder [i] */
1326 for (entry = entries; entry->next; entry = entry->next) {
1327 #if DEBUG_IMT
1328 MonoMethod *method = (MonoMethod*)entry->key;
1329 char *method_name = mono_method_full_name (method, TRUE);
1330 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1331 g_free (method_name);
1332 #endif
1334 entry->next = imt_builder [i];
1335 entries->children += imt_builder [i]->children + 1;
1337 imt_builder [i] = entries;
1340 if (has_generic_virtual || has_variant_iface) {
1342 * There might be collisions later when the the thunk is expanded.
1344 imt_collisions_bitmap |= (1 << i);
1347 * The IMT thunk might be called with an instance of one of the
1348 * generic virtual methods, so has to fallback to the IMT trampoline.
1350 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline ? callbacks.get_imt_trampoline (i) : NULL);
1351 } else {
1352 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1354 #if DEBUG_IMT
1355 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1356 #endif
1359 if (imt_builder [i] != NULL) {
1360 int methods_in_slot = imt_builder [i]->children + 1;
1361 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1362 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1363 record_method_count_for_max_collisions = TRUE;
1365 method_count += methods_in_slot;
1369 mono_stats.imt_number_of_methods += method_count;
1370 if (record_method_count_for_max_collisions) {
1371 mono_stats.imt_method_count_when_max_collisions = method_count;
1374 for (i = 0; i < MONO_IMT_SIZE; i++) {
1375 MonoImtBuilderEntry* entry = imt_builder [i];
1376 while (entry != NULL) {
1377 MonoImtBuilderEntry* next = entry->next;
1378 g_free (entry);
1379 entry = next;
1382 free (imt_builder);
1383 /* we OR the bitmap since we may build just a single imt slot at a time */
1384 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1387 static void
1388 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1389 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1393 * mono_vtable_build_imt_slot:
1394 * @vtable: virtual object table struct
1395 * @imt_slot: slot in the IMT table
1397 * Fill the given @imt_slot in the IMT table of @vtable with
1398 * a trampoline or a thunk for the case of collisions.
1399 * This is part of the internal mono API.
1401 * LOCKING: Take the domain lock.
1403 void
1404 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1406 gpointer *imt = (gpointer*)vtable;
1407 imt -= MONO_IMT_SIZE;
1408 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1410 /* no support for extra interfaces: the proxy objects will need
1411 * to build the complete IMT
1412 * Update and heck needs to ahppen inside the proper domain lock, as all
1413 * the changes made to a MonoVTable.
1415 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1416 mono_domain_lock (vtable->domain);
1417 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1418 if (imt [imt_slot] == callbacks.get_imt_trampoline (imt_slot))
1419 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1420 mono_domain_unlock (vtable->domain);
1421 mono_loader_unlock ();
1426 * The first two free list entries both belong to the wait list: The
1427 * first entry is the pointer to the head of the list and the second
1428 * entry points to the last element. That way appending and removing
1429 * the first element are both O(1) operations.
1431 #ifdef MONO_SMALL_CONFIG
1432 #define NUM_FREE_LISTS 6
1433 #else
1434 #define NUM_FREE_LISTS 12
1435 #endif
1436 #define FIRST_FREE_LIST_SIZE 64
1437 #define MAX_WAIT_LENGTH 50
1438 #define THUNK_THRESHOLD 10
1441 * LOCKING: The domain lock must be held.
1443 static void
1444 init_thunk_free_lists (MonoDomain *domain)
1446 if (domain->thunk_free_lists)
1447 return;
1448 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1451 static int
1452 list_index_for_size (int item_size)
1454 int i = 2;
1455 int size = FIRST_FREE_LIST_SIZE;
1457 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1458 i++;
1459 size <<= 1;
1462 return i;
1466 * mono_method_alloc_generic_virtual_thunk:
1467 * @domain: a domain
1468 * @size: size in bytes
1470 * Allocs size bytes to be used for the code of a generic virtual
1471 * thunk. It's either allocated from the domain's code manager or
1472 * reused from a previously invalidated piece.
1474 * LOCKING: The domain lock must be held.
1476 gpointer
1477 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1479 static gboolean inited = FALSE;
1480 static int generic_virtual_thunks_size = 0;
1482 guint32 *p;
1483 int i;
1484 MonoThunkFreeList **l;
1486 init_thunk_free_lists (domain);
1488 size += sizeof (guint32);
1489 if (size < sizeof (MonoThunkFreeList))
1490 size = sizeof (MonoThunkFreeList);
1492 i = list_index_for_size (size);
1493 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1494 if ((*l)->size >= size) {
1495 MonoThunkFreeList *item = *l;
1496 *l = item->next;
1497 return ((guint32*)item) + 1;
1501 /* no suitable item found - search lists of larger sizes */
1502 while (++i < NUM_FREE_LISTS) {
1503 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1504 if (!item)
1505 continue;
1506 g_assert (item->size > size);
1507 domain->thunk_free_lists [i] = item->next;
1508 return ((guint32*)item) + 1;
1511 /* still nothing found - allocate it */
1512 if (!inited) {
1513 mono_counters_register ("Generic virtual thunk bytes",
1514 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1515 inited = TRUE;
1517 generic_virtual_thunks_size += size;
1519 p = mono_domain_code_reserve (domain, size);
1520 *p = size;
1522 return p + 1;
1526 * LOCKING: The domain lock must be held.
1528 static void
1529 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1531 guint32 *p = code;
1532 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1534 init_thunk_free_lists (domain);
1536 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1537 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1538 int length = item->length;
1539 int i;
1541 /* unlink the first item from the wait list */
1542 domain->thunk_free_lists [0] = item->next;
1543 domain->thunk_free_lists [0]->length = length - 1;
1545 i = list_index_for_size (item->size);
1547 /* put it in the free list */
1548 item->next = domain->thunk_free_lists [i];
1549 domain->thunk_free_lists [i] = item;
1552 l->next = NULL;
1553 if (domain->thunk_free_lists [1]) {
1554 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1555 domain->thunk_free_lists [0]->length++;
1556 } else {
1557 g_assert (!domain->thunk_free_lists [0]);
1559 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1560 domain->thunk_free_lists [0]->length = 1;
1564 typedef struct _GenericVirtualCase {
1565 MonoMethod *method;
1566 gpointer code;
1567 int count;
1568 struct _GenericVirtualCase *next;
1569 } GenericVirtualCase;
1572 * get_generic_virtual_entries:
1574 * Return IMT entries for the generic virtual method instances and
1575 * variant interface methods for vtable slot
1576 * VTABLE_SLOT.
1578 static MonoImtBuilderEntry*
1579 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1581 GenericVirtualCase *list;
1582 MonoImtBuilderEntry *entries;
1584 mono_domain_lock (domain);
1585 if (!domain->generic_virtual_cases)
1586 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1588 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1590 entries = NULL;
1591 for (; list; list = list->next) {
1592 MonoImtBuilderEntry *entry;
1594 if (list->count < THUNK_THRESHOLD)
1595 continue;
1597 entry = g_new0 (MonoImtBuilderEntry, 1);
1598 entry->key = list->method;
1599 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1600 entry->has_target_code = 1;
1601 if (entries)
1602 entry->children = entries->children + 1;
1603 entry->next = entries;
1604 entries = entry;
1607 mono_domain_unlock (domain);
1609 /* FIXME: Leaking memory ? */
1610 return entries;
1614 * mono_method_add_generic_virtual_invocation:
1615 * @domain: a domain
1616 * @vtable_slot: pointer to the vtable slot
1617 * @method: the inflated generic virtual method
1618 * @code: the method's code
1620 * Registers a call via unmanaged code to a generic virtual method
1621 * instantiation or variant interface method. If the number of calls reaches a threshold
1622 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1623 * virtual method thunk.
1625 void
1626 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1627 gpointer *vtable_slot,
1628 MonoMethod *method, gpointer code)
1630 static gboolean inited = FALSE;
1631 static int num_added = 0;
1633 GenericVirtualCase *gvc, *list;
1634 MonoImtBuilderEntry *entries;
1635 int i;
1636 GPtrArray *sorted;
1638 mono_domain_lock (domain);
1639 if (!domain->generic_virtual_cases)
1640 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1642 /* Check whether the case was already added */
1643 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1644 gvc = list;
1645 while (gvc) {
1646 if (gvc->method == method)
1647 break;
1648 gvc = gvc->next;
1651 /* If not found, make a new one */
1652 if (!gvc) {
1653 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1654 gvc->method = method;
1655 gvc->code = code;
1656 gvc->count = 0;
1657 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1659 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1661 if (!inited) {
1662 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1663 inited = TRUE;
1665 num_added++;
1668 if (++gvc->count == THUNK_THRESHOLD) {
1669 gpointer *old_thunk = *vtable_slot;
1670 gpointer vtable_trampoline = NULL;
1671 gpointer imt_trampoline = NULL;
1673 if ((gpointer)vtable_slot < (gpointer)vtable) {
1674 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1675 int imt_slot = MONO_IMT_SIZE + displacement;
1677 /* Force the rebuild of the thunk at the next call */
1678 imt_trampoline = callbacks.get_imt_trampoline (imt_slot);
1679 *vtable_slot = imt_trampoline;
1680 } else {
1681 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline ((gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1683 entries = get_generic_virtual_entries (domain, vtable_slot);
1685 sorted = imt_sort_slot_entries (entries);
1687 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1688 vtable_trampoline);
1690 while (entries) {
1691 MonoImtBuilderEntry *next = entries->next;
1692 g_free (entries);
1693 entries = next;
1696 for (i = 0; i < sorted->len; ++i)
1697 g_free (g_ptr_array_index (sorted, i));
1698 g_ptr_array_free (sorted, TRUE);
1701 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1702 invalidate_generic_virtual_thunk (domain, old_thunk);
1705 mono_domain_unlock (domain);
1708 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error);
1711 * mono_class_vtable:
1712 * @domain: the application domain
1713 * @class: the class to initialize
1715 * VTables are domain specific because we create domain specific code, and
1716 * they contain the domain specific static class data.
1717 * On failure, NULL is returned, and class->exception_type is set.
1719 MonoVTable *
1720 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1722 return mono_class_vtable_full (domain, class, FALSE);
1726 * mono_class_vtable_full:
1727 * @domain: the application domain
1728 * @class: the class to initialize
1729 * @raise_on_error if an exception should be raised on failure or not
1731 * VTables are domain specific because we create domain specific code, and
1732 * they contain the domain specific static class data.
1734 MonoVTable *
1735 mono_class_vtable_full (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1737 MonoClassRuntimeInfo *runtime_info;
1739 g_assert (class);
1741 if (class->exception_type) {
1742 if (raise_on_error)
1743 mono_raise_exception (mono_class_get_exception_for_failure (class));
1744 return NULL;
1747 /* this check can be inlined in jitted code, too */
1748 runtime_info = class->runtime_info;
1749 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1750 return runtime_info->domain_vtables [domain->domain_id];
1751 return mono_class_create_runtime_vtable (domain, class, raise_on_error);
1755 * mono_class_try_get_vtable:
1756 * @domain: the application domain
1757 * @class: the class to initialize
1759 * This function tries to get the associated vtable from @class if
1760 * it was already created.
1762 MonoVTable *
1763 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1765 MonoClassRuntimeInfo *runtime_info;
1767 g_assert (class);
1769 runtime_info = class->runtime_info;
1770 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1771 return runtime_info->domain_vtables [domain->domain_id];
1772 return NULL;
1775 static MonoVTable *
1776 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1778 MonoVTable *vt;
1779 MonoClassRuntimeInfo *runtime_info, *old_info;
1780 MonoClassField *field;
1781 char *t;
1782 int i;
1783 int imt_table_bytes = 0;
1784 guint32 vtable_size, class_size;
1785 guint32 cindex;
1786 gpointer iter;
1787 gpointer *interface_offsets;
1789 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1790 mono_domain_lock (domain);
1791 runtime_info = class->runtime_info;
1792 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1793 mono_domain_unlock (domain);
1794 mono_loader_unlock ();
1795 return runtime_info->domain_vtables [domain->domain_id];
1797 if (!class->inited || class->exception_type) {
1798 if (!mono_class_init (class) || class->exception_type) {
1799 mono_domain_unlock (domain);
1800 mono_loader_unlock ();
1801 if (raise_on_error)
1802 mono_raise_exception (mono_class_get_exception_for_failure (class));
1803 return NULL;
1807 /* Array types require that their element type be valid*/
1808 if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
1809 MonoClass *element_class = class->element_class;
1810 if (!element_class->inited)
1811 mono_class_init (element_class);
1813 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1814 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1815 mono_class_setup_vtable (element_class);
1817 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1818 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1819 if (class->exception_type == MONO_EXCEPTION_NONE)
1820 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1821 mono_domain_unlock (domain);
1822 mono_loader_unlock ();
1823 if (raise_on_error)
1824 mono_raise_exception (mono_class_get_exception_for_failure (class));
1825 return NULL;
1830 * For some classes, mono_class_init () already computed class->vtable_size, and
1831 * that is all that is needed because of the vtable trampolines.
1833 if (!class->vtable_size)
1834 mono_class_setup_vtable (class);
1836 if (class->exception_type) {
1837 mono_domain_unlock (domain);
1838 mono_loader_unlock ();
1839 if (raise_on_error)
1840 mono_raise_exception (mono_class_get_exception_for_failure (class));
1841 return NULL;
1844 if (ARCH_USE_IMT) {
1845 vtable_size = MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1846 if (class->interface_offsets_count) {
1847 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1848 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1849 mono_stats.imt_number_of_tables++;
1850 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1852 } else {
1853 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1854 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1857 mono_stats.used_class_count++;
1858 mono_stats.class_vtable_size += vtable_size;
1859 interface_offsets = mono_domain_alloc0 (domain, vtable_size);
1861 if (ARCH_USE_IMT)
1862 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1863 else
1864 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1865 vt->klass = class;
1866 vt->rank = class->rank;
1867 vt->domain = domain;
1869 mono_class_compute_gc_descriptor (class);
1871 * We can't use typed allocation in the non-root domains, since the
1872 * collector needs the GC descriptor stored in the vtable even after
1873 * the mempool containing the vtable is destroyed when the domain is
1874 * unloaded. An alternative might be to allocate vtables in the GC
1875 * heap, but this does not seem to work (it leads to crashes inside
1876 * libgc). If that approach is tried, two gc descriptors need to be
1877 * allocated for each class: one for the root domain, and one for all
1878 * other domains. The second descriptor should contain a bit for the
1879 * vtable field in MonoObject, since we can no longer assume the
1880 * vtable is reachable by other roots after the appdomain is unloaded.
1882 #ifdef HAVE_BOEHM_GC
1883 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1884 vt->gc_descr = GC_NO_DESCRIPTOR;
1885 else
1886 #endif
1887 vt->gc_descr = class->gc_descr;
1889 if ((class_size = mono_class_data_size (class))) {
1890 if (class->has_static_refs) {
1891 gpointer statics_gc_descr;
1892 int max_set = 0;
1893 gsize default_bitmap [4] = {0};
1894 gsize *bitmap;
1896 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1897 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1898 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1899 vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1900 mono_domain_add_class_static_data (domain, class, vt->data, NULL);
1901 if (bitmap != default_bitmap)
1902 g_free (bitmap);
1903 } else {
1904 vt->data = mono_domain_alloc0 (domain, class_size);
1906 mono_stats.class_static_data_size += class_size;
1909 cindex = -1;
1910 iter = NULL;
1911 while ((field = mono_class_get_fields (class, &iter))) {
1912 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1913 continue;
1914 if (mono_field_is_deleted (field))
1915 continue;
1916 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1917 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1918 if (special_static != SPECIAL_STATIC_NONE) {
1919 guint32 size, offset;
1920 gint32 align;
1921 gsize default_bitmap [4] = {0};
1922 gsize *bitmap;
1923 int max_set = 0;
1924 MonoClass *fclass;
1925 if (mono_type_is_reference (field->type)) {
1926 default_bitmap [0] = 1;
1927 max_set = 1;
1928 bitmap = default_bitmap;
1929 } else if (mono_type_is_struct (field->type)) {
1930 fclass = mono_class_from_mono_type (field->type);
1931 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1932 } else {
1933 default_bitmap [0] = 0;
1934 max_set = 0;
1935 bitmap = default_bitmap;
1937 size = mono_type_size (field->type, &align);
1938 offset = mono_alloc_special_static_data (special_static, size, align, bitmap, max_set);
1939 if (!domain->special_static_fields)
1940 domain->special_static_fields = g_hash_table_new (NULL, NULL);
1941 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
1942 if (bitmap != default_bitmap)
1943 g_free (bitmap);
1945 * This marks the field as special static to speed up the
1946 * checks in mono_field_static_get/set_value ().
1948 field->offset = -1;
1949 continue;
1952 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
1953 MonoClass *fklass = mono_class_from_mono_type (field->type);
1954 const char *data = mono_field_get_data (field);
1956 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
1957 t = (char*)vt->data + field->offset;
1958 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
1959 if (!data)
1960 continue;
1961 if (fklass->valuetype) {
1962 memcpy (t, data, mono_class_value_size (fklass, NULL));
1963 } else {
1964 /* it's a pointer type: add check */
1965 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
1966 *t = *(char *)data;
1968 continue;
1972 vt->max_interface_id = class->max_interface_id;
1973 vt->interface_bitmap = class->interface_bitmap;
1975 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
1976 // class->name, class->interface_offsets_count);
1978 if (! ARCH_USE_IMT) {
1979 /* initialize interface offsets */
1980 for (i = 0; i < class->interface_offsets_count; ++i) {
1981 int interface_id = class->interfaces_packed [i]->interface_id;
1982 int slot = class->interface_offsets_packed [i];
1983 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
1987 /* class_vtable_array keeps an array of created vtables
1989 g_ptr_array_add (domain->class_vtable_array, vt);
1990 /* class->runtime_info is protected by the loader lock, both when
1991 * it it enlarged and when it is stored info.
1994 old_info = class->runtime_info;
1995 if (old_info && old_info->max_domain >= domain->domain_id) {
1996 /* someone already created a large enough runtime info */
1997 mono_memory_barrier ();
1998 old_info->domain_vtables [domain->domain_id] = vt;
1999 } else {
2000 int new_size = domain->domain_id;
2001 if (old_info)
2002 new_size = MAX (new_size, old_info->max_domain);
2003 new_size++;
2004 /* make the new size a power of two */
2005 i = 2;
2006 while (new_size > i)
2007 i <<= 1;
2008 new_size = i;
2009 /* this is a bounded memory retention issue: may want to
2010 * handle it differently when we'll have a rcu-like system.
2012 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2013 runtime_info->max_domain = new_size - 1;
2014 /* copy the stuff from the older info */
2015 if (old_info) {
2016 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2018 runtime_info->domain_vtables [domain->domain_id] = vt;
2019 /* keep this last*/
2020 mono_memory_barrier ();
2021 class->runtime_info = runtime_info;
2024 /* Initialize vtable */
2025 if (callbacks.get_vtable_trampoline) {
2026 // This also covers the AOT case
2027 for (i = 0; i < class->vtable_size; ++i) {
2028 vt->vtable [i] = callbacks.get_vtable_trampoline (i);
2030 } else {
2031 mono_class_setup_vtable (class);
2033 for (i = 0; i < class->vtable_size; ++i) {
2034 MonoMethod *cm;
2036 if ((cm = class->vtable [i]))
2037 vt->vtable [i] = arch_create_jit_trampoline (cm);
2041 if (ARCH_USE_IMT && imt_table_bytes) {
2042 /* Now that the vtable is full, we can actually fill up the IMT */
2043 if (callbacks.get_imt_trampoline) {
2044 /* lazy construction of the IMT entries enabled */
2045 for (i = 0; i < MONO_IMT_SIZE; ++i)
2046 interface_offsets [i] = callbacks.get_imt_trampoline (i);
2047 } else {
2048 build_imt (class, vt, domain, interface_offsets, NULL);
2052 mono_domain_unlock (domain);
2053 mono_loader_unlock ();
2055 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
2056 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
2057 mono_raise_exception (mono_class_get_exception_for_failure (class));
2059 /* make sure the parent is initialized */
2060 /*FIXME shouldn't this fail the current type?*/
2061 if (class->parent)
2062 mono_class_vtable_full (domain, class->parent, raise_on_error);
2064 /*FIXME check for OOM*/
2065 vt->type = mono_type_get_object (domain, &class->byval_arg);
2066 #if HAVE_SGEN_GC
2067 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class) {
2068 static void *type_desc = NULL;
2070 if (!type_desc) {
2071 gsize bmap = 1;
2072 type_desc = mono_gc_make_descr_from_bitmap (&bmap, 1);
2075 /* This is unregistered in
2076 unregister_vtable_reflection_type() in
2077 domain.c. */
2078 mono_gc_register_root ((char*)&vt->type, sizeof (gpointer), type_desc);
2080 #endif
2081 if (class->contextbound)
2082 vt->remote = 1;
2083 else
2084 vt->remote = 0;
2086 return vt;
2090 * mono_class_proxy_vtable:
2091 * @domain: the application domain
2092 * @remove_class: the remote class
2094 * Creates a vtable for transparent proxies. It is basically
2095 * a copy of the real vtable of the class wrapped in @remote_class,
2096 * but all function pointers invoke the remoting functions, and
2097 * vtable->klass points to the transparent proxy class, and not to @class.
2099 static MonoVTable *
2100 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2102 MonoError error;
2103 MonoVTable *vt, *pvt;
2104 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2105 MonoClass *k;
2106 GSList *extra_interfaces = NULL;
2107 MonoClass *class = remote_class->proxy_class;
2108 gpointer *interface_offsets;
2109 uint8_t *bitmap;
2110 int bsize;
2112 #ifdef COMPRESSED_INTERFACE_BITMAP
2113 int bcsize;
2114 #endif
2116 vt = mono_class_vtable (domain, class);
2117 g_assert (vt); /*FIXME property handle failure*/
2118 max_interface_id = vt->max_interface_id;
2120 /* Calculate vtable space for extra interfaces */
2121 for (j = 0; j < remote_class->interface_count; j++) {
2122 MonoClass* iclass = remote_class->interfaces[j];
2123 GPtrArray *ifaces;
2124 int method_count;
2126 /*FIXME test for interfaces with variant generic arguments*/
2127 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2128 continue; /* interface implemented by the class */
2129 if (g_slist_find (extra_interfaces, iclass))
2130 continue;
2132 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2134 method_count = mono_class_num_methods (iclass);
2136 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2137 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2138 if (ifaces) {
2139 for (i = 0; i < ifaces->len; ++i) {
2140 MonoClass *ic = g_ptr_array_index (ifaces, i);
2141 /*FIXME test for interfaces with variant generic arguments*/
2142 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2143 continue; /* interface implemented by the class */
2144 if (g_slist_find (extra_interfaces, ic))
2145 continue;
2146 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2147 method_count += mono_class_num_methods (ic);
2149 g_ptr_array_free (ifaces, TRUE);
2152 extra_interface_vtsize += method_count * sizeof (gpointer);
2153 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2156 if (ARCH_USE_IMT) {
2157 mono_stats.imt_number_of_tables++;
2158 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
2159 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
2160 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2161 } else {
2162 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
2163 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2166 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2168 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
2169 if (ARCH_USE_IMT)
2170 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
2171 else
2172 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
2173 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2175 pvt->klass = mono_defaults.transparent_proxy_class;
2176 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2177 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2179 /* initialize vtable */
2180 mono_class_setup_vtable (class);
2181 for (i = 0; i < class->vtable_size; ++i) {
2182 MonoMethod *cm;
2184 if ((cm = class->vtable [i]))
2185 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2186 else
2187 pvt->vtable [i] = NULL;
2190 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2191 /* create trampolines for abstract methods */
2192 for (k = class; k; k = k->parent) {
2193 MonoMethod* m;
2194 gpointer iter = NULL;
2195 while ((m = mono_class_get_methods (k, &iter)))
2196 if (!pvt->vtable [m->slot])
2197 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2201 pvt->max_interface_id = max_interface_id;
2202 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2203 #ifdef COMPRESSED_INTERFACE_BITMAP
2204 bitmap = g_malloc0 (bsize);
2205 #else
2206 bitmap = mono_domain_alloc0 (domain, bsize);
2207 #endif
2209 if (! ARCH_USE_IMT) {
2210 /* initialize interface offsets */
2211 for (i = 0; i < class->interface_offsets_count; ++i) {
2212 int interface_id = class->interfaces_packed [i]->interface_id;
2213 int slot = class->interface_offsets_packed [i];
2214 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2217 for (i = 0; i < class->interface_offsets_count; ++i) {
2218 int interface_id = class->interfaces_packed [i]->interface_id;
2219 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2222 if (extra_interfaces) {
2223 int slot = class->vtable_size;
2224 MonoClass* interf;
2225 gpointer iter;
2226 MonoMethod* cm;
2227 GSList *list_item;
2229 /* Create trampolines for the methods of the interfaces */
2230 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2231 interf = list_item->data;
2233 if (! ARCH_USE_IMT) {
2234 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2236 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2238 iter = NULL;
2239 j = 0;
2240 while ((cm = mono_class_get_methods (interf, &iter)))
2241 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2243 slot += mono_class_num_methods (interf);
2245 if (! ARCH_USE_IMT) {
2246 g_slist_free (extra_interfaces);
2250 if (ARCH_USE_IMT) {
2251 /* Now that the vtable is full, we can actually fill up the IMT */
2252 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2253 if (extra_interfaces) {
2254 g_slist_free (extra_interfaces);
2258 #ifdef COMPRESSED_INTERFACE_BITMAP
2259 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2260 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2261 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2262 g_free (bitmap);
2263 #else
2264 pvt->interface_bitmap = bitmap;
2265 #endif
2266 return pvt;
2270 * mono_class_field_is_special_static:
2272 * Returns whether @field is a thread/context static field.
2274 gboolean
2275 mono_class_field_is_special_static (MonoClassField *field)
2277 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2278 return FALSE;
2279 if (mono_field_is_deleted (field))
2280 return FALSE;
2281 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2282 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2283 return TRUE;
2285 return FALSE;
2289 * mono_class_has_special_static_fields:
2291 * Returns whenever @klass has any thread/context static fields.
2293 gboolean
2294 mono_class_has_special_static_fields (MonoClass *klass)
2296 MonoClassField *field;
2297 gpointer iter;
2299 iter = NULL;
2300 while ((field = mono_class_get_fields (klass, &iter))) {
2301 g_assert (field->parent == klass);
2302 if (mono_class_field_is_special_static (field))
2303 return TRUE;
2306 return FALSE;
2310 * create_remote_class_key:
2311 * Creates an array of pointers that can be used as a hash key for a remote class.
2312 * The first element of the array is the number of pointers.
2314 static gpointer*
2315 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2317 gpointer *key;
2318 int i, j;
2320 if (remote_class == NULL) {
2321 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2322 key = g_malloc (sizeof(gpointer) * 3);
2323 key [0] = GINT_TO_POINTER (2);
2324 key [1] = mono_defaults.marshalbyrefobject_class;
2325 key [2] = extra_class;
2326 } else {
2327 key = g_malloc (sizeof(gpointer) * 2);
2328 key [0] = GINT_TO_POINTER (1);
2329 key [1] = extra_class;
2331 } else {
2332 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2333 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2334 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2335 key [1] = remote_class->proxy_class;
2337 // Keep the list of interfaces sorted
2338 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2339 if (extra_class && remote_class->interfaces [i] > extra_class) {
2340 key [j++] = extra_class;
2341 extra_class = NULL;
2343 key [j] = remote_class->interfaces [i];
2345 if (extra_class)
2346 key [j] = extra_class;
2347 } else {
2348 // Replace the old class. The interface list is the same
2349 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2350 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2351 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2352 for (i = 0; i < remote_class->interface_count; i++)
2353 key [2 + i] = remote_class->interfaces [i];
2357 return key;
2361 * copy_remote_class_key:
2363 * Make a copy of KEY in the domain and return the copy.
2365 static gpointer*
2366 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2368 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2369 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2371 memcpy (mp_key, key, key_size);
2373 return mp_key;
2377 * mono_remote_class:
2378 * @domain: the application domain
2379 * @class_name: name of the remote class
2381 * Creates and initializes a MonoRemoteClass object for a remote type.
2383 * Can raise an exception on failure.
2385 MonoRemoteClass*
2386 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2388 MonoError error;
2389 MonoRemoteClass *rc;
2390 gpointer* key, *mp_key;
2391 char *name;
2393 key = create_remote_class_key (NULL, proxy_class);
2395 mono_domain_lock (domain);
2396 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2398 if (rc) {
2399 g_free (key);
2400 mono_domain_unlock (domain);
2401 return rc;
2404 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2405 if (!mono_error_ok (&error)) {
2406 g_free (key);
2407 mono_domain_unlock (domain);
2408 mono_error_raise_exception (&error);
2411 mp_key = copy_remote_class_key (domain, key);
2412 g_free (key);
2413 key = mp_key;
2415 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2416 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2417 rc->interface_count = 1;
2418 rc->interfaces [0] = proxy_class;
2419 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2420 } else {
2421 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2422 rc->interface_count = 0;
2423 rc->proxy_class = proxy_class;
2426 rc->default_vtable = NULL;
2427 rc->xdomain_vtable = NULL;
2428 rc->proxy_class_name = name;
2429 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2431 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2433 mono_domain_unlock (domain);
2434 return rc;
2438 * clone_remote_class:
2439 * Creates a copy of the remote_class, adding the provided class or interface
2441 static MonoRemoteClass*
2442 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2444 MonoRemoteClass *rc;
2445 gpointer* key, *mp_key;
2447 key = create_remote_class_key (remote_class, extra_class);
2448 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2449 if (rc != NULL) {
2450 g_free (key);
2451 return rc;
2454 mp_key = copy_remote_class_key (domain, key);
2455 g_free (key);
2456 key = mp_key;
2458 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2459 int i,j;
2460 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2461 rc->proxy_class = remote_class->proxy_class;
2462 rc->interface_count = remote_class->interface_count + 1;
2464 // Keep the list of interfaces sorted, since the hash key of
2465 // the remote class depends on this
2466 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2467 if (remote_class->interfaces [i] > extra_class && i == j)
2468 rc->interfaces [j++] = extra_class;
2469 rc->interfaces [j] = remote_class->interfaces [i];
2471 if (i == j)
2472 rc->interfaces [j] = extra_class;
2473 } else {
2474 // Replace the old class. The interface array is the same
2475 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2476 rc->proxy_class = extra_class;
2477 rc->interface_count = remote_class->interface_count;
2478 if (rc->interface_count > 0)
2479 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2482 rc->default_vtable = NULL;
2483 rc->xdomain_vtable = NULL;
2484 rc->proxy_class_name = remote_class->proxy_class_name;
2486 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2488 return rc;
2491 gpointer
2492 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2494 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2495 mono_domain_lock (domain);
2496 if (rp->target_domain_id != -1) {
2497 if (remote_class->xdomain_vtable == NULL)
2498 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2499 mono_domain_unlock (domain);
2500 mono_loader_unlock ();
2501 return remote_class->xdomain_vtable;
2503 if (remote_class->default_vtable == NULL) {
2504 MonoType *type;
2505 MonoClass *klass;
2506 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2507 klass = mono_class_from_mono_type (type);
2508 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
2509 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2510 else
2511 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2514 mono_domain_unlock (domain);
2515 mono_loader_unlock ();
2516 return remote_class->default_vtable;
2520 * mono_upgrade_remote_class:
2521 * @domain: the application domain
2522 * @tproxy: the proxy whose remote class has to be upgraded.
2523 * @klass: class to which the remote class can be casted.
2525 * Updates the vtable of the remote class by adding the necessary method slots
2526 * and interface offsets so it can be safely casted to klass. klass can be a
2527 * class or an interface.
2529 void
2530 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2532 MonoTransparentProxy *tproxy;
2533 MonoRemoteClass *remote_class;
2534 gboolean redo_vtable;
2536 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2537 mono_domain_lock (domain);
2539 tproxy = (MonoTransparentProxy*) proxy_object;
2540 remote_class = tproxy->remote_class;
2542 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2543 int i;
2544 redo_vtable = TRUE;
2545 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2546 if (remote_class->interfaces [i] == klass)
2547 redo_vtable = FALSE;
2549 else {
2550 redo_vtable = (remote_class->proxy_class != klass);
2553 if (redo_vtable) {
2554 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2555 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2558 mono_domain_unlock (domain);
2559 mono_loader_unlock ();
2564 * mono_object_get_virtual_method:
2565 * @obj: object to operate on.
2566 * @method: method
2568 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2569 * the instance of a callvirt of method.
2571 MonoMethod*
2572 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2574 MonoClass *klass;
2575 MonoMethod **vtable;
2576 gboolean is_proxy;
2577 MonoMethod *res = NULL;
2579 klass = mono_object_class (obj);
2580 if (klass == mono_defaults.transparent_proxy_class) {
2581 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2582 is_proxy = TRUE;
2583 } else {
2584 is_proxy = FALSE;
2587 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2588 return method;
2590 mono_class_setup_vtable (klass);
2591 vtable = klass->vtable;
2593 if (method->slot == -1) {
2594 /* method->slot might not be set for instances of generic methods */
2595 if (method->is_inflated) {
2596 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2597 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2598 } else {
2599 if (!is_proxy)
2600 g_assert_not_reached ();
2604 /* check method->slot is a valid index: perform isinstance? */
2605 if (method->slot != -1) {
2606 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2607 if (!is_proxy) {
2608 gboolean variance_used = FALSE;
2609 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2610 g_assert (iface_offset > 0);
2611 res = vtable [iface_offset + method->slot];
2613 } else {
2614 res = vtable [method->slot];
2618 if (is_proxy) {
2619 /* It may be an interface, abstract class method or generic method */
2620 if (!res || mono_method_signature (res)->generic_param_count)
2621 res = method;
2623 /* generic methods demand invoke_with_check */
2624 if (mono_method_signature (res)->generic_param_count)
2625 res = mono_marshal_get_remoting_invoke_with_check (res);
2626 else {
2627 #ifndef DISABLE_COM
2628 if (klass == mono_defaults.com_object_class || klass->is_com_object)
2629 res = mono_cominterop_get_invoke (res);
2630 else
2631 #endif
2632 res = mono_marshal_get_remoting_invoke (res);
2634 } else {
2635 if (method->is_inflated) {
2636 /* Have to inflate the result */
2637 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2641 g_assert (res);
2643 return res;
2646 static MonoObject*
2647 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2649 g_error ("runtime invoke called on uninitialized runtime");
2650 return NULL;
2653 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2656 * mono_runtime_invoke:
2657 * @method: method to invoke
2658 * @obJ: object instance
2659 * @params: arguments to the method
2660 * @exc: exception information.
2662 * Invokes the method represented by @method on the object @obj.
2664 * obj is the 'this' pointer, it should be NULL for static
2665 * methods, a MonoObject* for object instances and a pointer to
2666 * the value type for value types.
2668 * The params array contains the arguments to the method with the
2669 * same convention: MonoObject* pointers for object instances and
2670 * pointers to the value type otherwise.
2672 * From unmanaged code you'll usually use the
2673 * mono_runtime_invoke() variant.
2675 * Note that this function doesn't handle virtual methods for
2676 * you, it will exec the exact method you pass: we still need to
2677 * expose a function to lookup the derived class implementation
2678 * of a virtual method (there are examples of this in the code,
2679 * though).
2681 * You can pass NULL as the exc argument if you don't want to
2682 * catch exceptions, otherwise, *exc will be set to the exception
2683 * thrown, if any. if an exception is thrown, you can't use the
2684 * MonoObject* result from the function.
2686 * If the method returns a value type, it is boxed in an object
2687 * reference.
2689 MonoObject*
2690 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2692 MonoObject *result;
2694 if (mono_runtime_get_no_exec ())
2695 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2697 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2698 mono_profiler_method_start_invoke (method);
2700 result = default_mono_runtime_invoke (method, obj, params, exc);
2702 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2703 mono_profiler_method_end_invoke (method);
2705 return result;
2709 * mono_method_get_unmanaged_thunk:
2710 * @method: method to generate a thunk for.
2712 * Returns an unmanaged->managed thunk that can be used to call
2713 * a managed method directly from C.
2715 * The thunk's C signature closely matches the managed signature:
2717 * C#: public bool Equals (object obj);
2718 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2719 * MonoObject*, MonoException**);
2721 * The 1st ("this") parameter must not be used with static methods:
2723 * C#: public static bool ReferenceEquals (object a, object b);
2724 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2725 * MonoException**);
2727 * The last argument must be a non-null pointer of a MonoException* pointer.
2728 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2729 * exception has been thrown in managed code. Otherwise it will point
2730 * to the MonoException* caught by the thunk. In this case, the result of
2731 * the thunk is undefined:
2733 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2734 * MonoException *ex = NULL;
2735 * Equals func = mono_method_get_unmanaged_thunk (method);
2736 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2737 * if (ex) {
2738 * // handle exception
2741 * The calling convention of the thunk matches the platform's default
2742 * convention. This means that under Windows, C declarations must
2743 * contain the __stdcall attribute:
2745 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2746 * MonoObject*, MonoException**);
2748 * LIMITATIONS
2750 * Value type arguments and return values are treated as they were objects:
2752 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2753 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2755 * Arguments must be properly boxed upon trunk's invocation, while return
2756 * values must be unboxed.
2758 gpointer
2759 mono_method_get_unmanaged_thunk (MonoMethod *method)
2761 method = mono_marshal_get_thunk_invoke_wrapper (method);
2762 return mono_compile_method (method);
2765 static void
2766 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2768 int t;
2769 if (type->byref) {
2770 /* object fields cannot be byref, so we don't need a
2771 wbarrier here */
2772 gpointer *p = (gpointer*)dest;
2773 *p = value;
2774 return;
2776 t = type->type;
2777 handle_enum:
2778 switch (t) {
2779 case MONO_TYPE_BOOLEAN:
2780 case MONO_TYPE_I1:
2781 case MONO_TYPE_U1: {
2782 guint8 *p = (guint8*)dest;
2783 *p = value ? *(guint8*)value : 0;
2784 return;
2786 case MONO_TYPE_I2:
2787 case MONO_TYPE_U2:
2788 case MONO_TYPE_CHAR: {
2789 guint16 *p = (guint16*)dest;
2790 *p = value ? *(guint16*)value : 0;
2791 return;
2793 #if SIZEOF_VOID_P == 4
2794 case MONO_TYPE_I:
2795 case MONO_TYPE_U:
2796 #endif
2797 case MONO_TYPE_I4:
2798 case MONO_TYPE_U4: {
2799 gint32 *p = (gint32*)dest;
2800 *p = value ? *(gint32*)value : 0;
2801 return;
2803 #if SIZEOF_VOID_P == 8
2804 case MONO_TYPE_I:
2805 case MONO_TYPE_U:
2806 #endif
2807 case MONO_TYPE_I8:
2808 case MONO_TYPE_U8: {
2809 gint64 *p = (gint64*)dest;
2810 *p = value ? *(gint64*)value : 0;
2811 return;
2813 case MONO_TYPE_R4: {
2814 float *p = (float*)dest;
2815 *p = value ? *(float*)value : 0;
2816 return;
2818 case MONO_TYPE_R8: {
2819 double *p = (double*)dest;
2820 *p = value ? *(double*)value : 0;
2821 return;
2823 case MONO_TYPE_STRING:
2824 case MONO_TYPE_SZARRAY:
2825 case MONO_TYPE_CLASS:
2826 case MONO_TYPE_OBJECT:
2827 case MONO_TYPE_ARRAY:
2828 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2829 return;
2830 case MONO_TYPE_FNPTR:
2831 case MONO_TYPE_PTR: {
2832 gpointer *p = (gpointer*)dest;
2833 *p = deref_pointer? *(gpointer*)value: value;
2834 return;
2836 case MONO_TYPE_VALUETYPE:
2837 /* note that 't' and 'type->type' can be different */
2838 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2839 t = mono_class_enum_basetype (type->data.klass)->type;
2840 goto handle_enum;
2841 } else {
2842 MonoClass *class = mono_class_from_mono_type (type);
2843 int size = mono_class_value_size (class, NULL);
2844 if (value == NULL)
2845 memset (dest, 0, size);
2846 else
2847 mono_gc_wbarrier_value_copy (dest, value, 1, class);
2849 return;
2850 case MONO_TYPE_GENERICINST:
2851 t = type->data.generic_class->container_class->byval_arg.type;
2852 goto handle_enum;
2853 default:
2854 g_warning ("got type %x", type->type);
2855 g_assert_not_reached ();
2860 * mono_field_set_value:
2861 * @obj: Instance object
2862 * @field: MonoClassField describing the field to set
2863 * @value: The value to be set
2865 * Sets the value of the field described by @field in the object instance @obj
2866 * to the value passed in @value. This method should only be used for instance
2867 * fields. For static fields, use mono_field_static_set_value.
2869 * The value must be on the native format of the field type.
2871 void
2872 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2874 void *dest;
2876 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2878 dest = (char*)obj + field->offset;
2879 set_value (field->type, dest, value, FALSE);
2883 * mono_field_static_set_value:
2884 * @field: MonoClassField describing the field to set
2885 * @value: The value to be set
2887 * Sets the value of the static field described by @field
2888 * to the value passed in @value.
2890 * The value must be on the native format of the field type.
2892 void
2893 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2895 void *dest;
2897 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2898 /* you cant set a constant! */
2899 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2901 if (field->offset == -1) {
2902 /* Special static */
2903 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2904 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2905 } else {
2906 dest = (char*)vt->data + field->offset;
2908 set_value (field->type, dest, value, FALSE);
2911 /* Used by the debugger */
2912 void *
2913 mono_vtable_get_static_field_data (MonoVTable *vt)
2915 return vt->data;
2918 static guint8*
2919 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
2921 guint8 *src;
2923 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2924 if (field->offset == -1) {
2925 /* Special static */
2926 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2927 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2928 } else {
2929 src = (guint8*)vt->data + field->offset;
2931 } else {
2932 src = (guint8*)obj + field->offset;
2935 return src;
2939 * mono_field_get_value:
2940 * @obj: Object instance
2941 * @field: MonoClassField describing the field to fetch information from
2942 * @value: pointer to the location where the value will be stored
2944 * Use this routine to get the value of the field @field in the object
2945 * passed.
2947 * The pointer provided by value must be of the field type, for reference
2948 * types this is a MonoObject*, for value types its the actual pointer to
2949 * the value type.
2951 * For example:
2952 * int i;
2953 * mono_field_get_value (obj, int_field, &i);
2955 void
2956 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
2958 void *src;
2960 g_assert (obj);
2962 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2964 src = (char*)obj + field->offset;
2965 set_value (field->type, value, src, TRUE);
2969 * mono_field_get_value_object:
2970 * @domain: domain where the object will be created (if boxing)
2971 * @field: MonoClassField describing the field to fetch information from
2972 * @obj: The object instance for the field.
2974 * Returns: a new MonoObject with the value from the given field. If the
2975 * field represents a value type, the value is boxed.
2978 MonoObject *
2979 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
2981 MonoObject *o;
2982 MonoClass *klass;
2983 MonoVTable *vtable = NULL;
2984 gchar *v;
2985 gboolean is_static = FALSE;
2986 gboolean is_ref = FALSE;
2987 gboolean is_literal = FALSE;
2989 switch (field->type->type) {
2990 case MONO_TYPE_STRING:
2991 case MONO_TYPE_OBJECT:
2992 case MONO_TYPE_CLASS:
2993 case MONO_TYPE_ARRAY:
2994 case MONO_TYPE_SZARRAY:
2995 is_ref = TRUE;
2996 break;
2997 case MONO_TYPE_U1:
2998 case MONO_TYPE_I1:
2999 case MONO_TYPE_BOOLEAN:
3000 case MONO_TYPE_U2:
3001 case MONO_TYPE_I2:
3002 case MONO_TYPE_CHAR:
3003 case MONO_TYPE_U:
3004 case MONO_TYPE_I:
3005 case MONO_TYPE_U4:
3006 case MONO_TYPE_I4:
3007 case MONO_TYPE_R4:
3008 case MONO_TYPE_U8:
3009 case MONO_TYPE_I8:
3010 case MONO_TYPE_R8:
3011 case MONO_TYPE_VALUETYPE:
3012 is_ref = field->type->byref;
3013 break;
3014 case MONO_TYPE_GENERICINST:
3015 is_ref = !mono_type_generic_inst_is_valuetype (field->type);
3016 break;
3017 default:
3018 g_error ("type 0x%x not handled in "
3019 "mono_field_get_value_object", field->type->type);
3020 return NULL;
3023 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
3024 is_literal = TRUE;
3026 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3027 is_static = TRUE;
3029 if (!is_literal) {
3030 vtable = mono_class_vtable (domain, field->parent);
3031 if (!vtable) {
3032 char *name = mono_type_get_full_name (field->parent);
3033 /*FIXME extend this to use the MonoError api*/
3034 g_warning ("Could not retrieve the vtable for type %s in mono_field_get_value_object", name);
3035 g_free (name);
3036 return NULL;
3038 if (!vtable->initialized)
3039 mono_runtime_class_init (vtable);
3041 } else {
3042 g_assert (obj);
3045 if (is_ref) {
3046 if (is_literal) {
3047 get_default_field_value (domain, field, &o);
3048 } else if (is_static) {
3049 mono_field_static_get_value (vtable, field, &o);
3050 } else {
3051 mono_field_get_value (obj, field, &o);
3053 return o;
3056 /* boxed value type */
3057 klass = mono_class_from_mono_type (field->type);
3059 if (mono_class_is_nullable (klass))
3060 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3062 o = mono_object_new (domain, klass);
3063 v = ((gchar *) o) + sizeof (MonoObject);
3065 if (is_literal) {
3066 get_default_field_value (domain, field, v);
3067 } else if (is_static) {
3068 mono_field_static_get_value (vtable, field, v);
3069 } else {
3070 mono_field_get_value (obj, field, v);
3073 return o;
3077 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3079 int retval = 0;
3080 const char *p = blob;
3081 mono_metadata_decode_blob_size (p, &p);
3083 switch (type) {
3084 case MONO_TYPE_BOOLEAN:
3085 case MONO_TYPE_U1:
3086 case MONO_TYPE_I1:
3087 *(guint8 *) value = *p;
3088 break;
3089 case MONO_TYPE_CHAR:
3090 case MONO_TYPE_U2:
3091 case MONO_TYPE_I2:
3092 *(guint16*) value = read16 (p);
3093 break;
3094 case MONO_TYPE_U4:
3095 case MONO_TYPE_I4:
3096 *(guint32*) value = read32 (p);
3097 break;
3098 case MONO_TYPE_U8:
3099 case MONO_TYPE_I8:
3100 *(guint64*) value = read64 (p);
3101 break;
3102 case MONO_TYPE_R4:
3103 readr4 (p, (float*) value);
3104 break;
3105 case MONO_TYPE_R8:
3106 readr8 (p, (double*) value);
3107 break;
3108 case MONO_TYPE_STRING:
3109 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3110 break;
3111 case MONO_TYPE_CLASS:
3112 *(gpointer*) value = NULL;
3113 break;
3114 default:
3115 retval = -1;
3116 g_warning ("type 0x%02x should not be in constant table", type);
3118 return retval;
3121 static void
3122 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3124 MonoTypeEnum def_type;
3125 const char* data;
3127 data = mono_class_get_field_default_value (field, &def_type);
3128 mono_get_constant_value_from_blob (domain, def_type, data, value);
3132 * mono_field_static_get_value:
3133 * @vt: vtable to the object
3134 * @field: MonoClassField describing the field to fetch information from
3135 * @value: where the value is returned
3137 * Use this routine to get the value of the static field @field value.
3139 * The pointer provided by value must be of the field type, for reference
3140 * types this is a MonoObject*, for value types its the actual pointer to
3141 * the value type.
3143 * For example:
3144 * int i;
3145 * mono_field_static_get_value (vt, int_field, &i);
3147 void
3148 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3150 void *src;
3152 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3154 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3155 get_default_field_value (vt->domain, field, value);
3156 return;
3159 if (field->offset == -1) {
3160 /* Special static */
3161 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3162 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3163 } else {
3164 src = (char*)vt->data + field->offset;
3166 set_value (field->type, value, src, TRUE);
3170 * mono_property_set_value:
3171 * @prop: MonoProperty to set
3172 * @obj: instance object on which to act
3173 * @params: parameters to pass to the propery
3174 * @exc: optional exception
3176 * Invokes the property's set method with the given arguments on the
3177 * object instance obj (or NULL for static properties).
3179 * You can pass NULL as the exc argument if you don't want to
3180 * catch exceptions, otherwise, *exc will be set to the exception
3181 * thrown, if any. if an exception is thrown, you can't use the
3182 * MonoObject* result from the function.
3184 void
3185 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3187 default_mono_runtime_invoke (prop->set, obj, params, exc);
3191 * mono_property_get_value:
3192 * @prop: MonoProperty to fetch
3193 * @obj: instance object on which to act
3194 * @params: parameters to pass to the propery
3195 * @exc: optional exception
3197 * Invokes the property's get method with the given arguments on the
3198 * object instance obj (or NULL for static properties).
3200 * You can pass NULL as the exc argument if you don't want to
3201 * catch exceptions, otherwise, *exc will be set to the exception
3202 * thrown, if any. if an exception is thrown, you can't use the
3203 * MonoObject* result from the function.
3205 * Returns: the value from invoking the get method on the property.
3207 MonoObject*
3208 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3210 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3214 * mono_nullable_init:
3215 * @buf: The nullable structure to initialize.
3216 * @value: the value to initialize from
3217 * @klass: the type for the object
3219 * Initialize the nullable structure pointed to by @buf from @value which
3220 * should be a boxed value type. The size of @buf should be able to hold
3221 * as much data as the @klass->instance_size (which is the number of bytes
3222 * that will be copies).
3224 * Since Nullables have variable structure, we can not define a C
3225 * structure for them.
3227 void
3228 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3230 MonoClass *param_class = klass->cast_class;
3232 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3233 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3235 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3236 if (value) {
3237 if (param_class->has_references)
3238 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3239 else
3240 memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3241 } else {
3242 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
3247 * mono_nullable_box:
3248 * @buf: The buffer representing the data to be boxed
3249 * @klass: the type to box it as.
3251 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3252 * @buf.
3254 MonoObject*
3255 mono_nullable_box (guint8 *buf, MonoClass *klass)
3257 MonoClass *param_class = klass->cast_class;
3259 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3260 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3262 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3263 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3264 if (param_class->has_references)
3265 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3266 else
3267 memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3268 return o;
3270 else
3271 return NULL;
3275 * mono_get_delegate_invoke:
3276 * @klass: The delegate class
3278 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3280 MonoMethod *
3281 mono_get_delegate_invoke (MonoClass *klass)
3283 MonoMethod *im;
3285 /* This is called at runtime, so avoid the slower search in metadata */
3286 mono_class_setup_methods (klass);
3287 if (klass->exception_type)
3288 return NULL;
3289 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3290 return im;
3294 * mono_runtime_delegate_invoke:
3295 * @delegate: pointer to a delegate object.
3296 * @params: parameters for the delegate.
3297 * @exc: Pointer to the exception result.
3299 * Invokes the delegate method @delegate with the parameters provided.
3301 * You can pass NULL as the exc argument if you don't want to
3302 * catch exceptions, otherwise, *exc will be set to the exception
3303 * thrown, if any. if an exception is thrown, you can't use the
3304 * MonoObject* result from the function.
3306 MonoObject*
3307 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3309 MonoMethod *im;
3311 im = mono_get_delegate_invoke (delegate->vtable->klass);
3312 g_assert (im);
3314 return mono_runtime_invoke (im, delegate, params, exc);
3317 static char **main_args = NULL;
3318 static int num_main_args;
3321 * mono_runtime_get_main_args:
3323 * Returns: a MonoArray with the arguments passed to the main program
3325 MonoArray*
3326 mono_runtime_get_main_args (void)
3328 MonoArray *res;
3329 int i;
3330 MonoDomain *domain = mono_domain_get ();
3332 if (!main_args)
3333 return NULL;
3335 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3337 for (i = 0; i < num_main_args; ++i)
3338 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3340 return res;
3344 * mono_runtime_run_main:
3345 * @method: the method to start the application with (usually Main)
3346 * @argc: number of arguments from the command line
3347 * @argv: array of strings from the command line
3348 * @exc: excetption results
3350 * Execute a standard Main() method (argc/argv contains the
3351 * executable name). This method also sets the command line argument value
3352 * needed by System.Environment.
3357 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3358 MonoObject **exc)
3360 int i;
3361 MonoArray *args = NULL;
3362 MonoDomain *domain = mono_domain_get ();
3363 gchar *utf8_fullpath;
3365 g_assert (method != NULL);
3367 mono_thread_set_main (mono_thread_current ());
3369 main_args = g_new0 (char*, argc);
3370 num_main_args = argc;
3372 if (!g_path_is_absolute (argv [0])) {
3373 gchar *basename = g_path_get_basename (argv [0]);
3374 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3375 basename,
3376 NULL);
3378 utf8_fullpath = mono_utf8_from_external (fullpath);
3379 if(utf8_fullpath == NULL) {
3380 /* Printing the arg text will cause glib to
3381 * whinge about "Invalid UTF-8", but at least
3382 * its relevant, and shows the problem text
3383 * string.
3385 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3386 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3387 exit (-1);
3390 g_free (fullpath);
3391 g_free (basename);
3392 } else {
3393 utf8_fullpath = mono_utf8_from_external (argv[0]);
3394 if(utf8_fullpath == NULL) {
3395 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3396 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3397 exit (-1);
3401 main_args [0] = utf8_fullpath;
3403 for (i = 1; i < argc; ++i) {
3404 gchar *utf8_arg;
3406 utf8_arg=mono_utf8_from_external (argv[i]);
3407 if(utf8_arg==NULL) {
3408 /* Ditto the comment about Invalid UTF-8 here */
3409 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3410 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3411 exit (-1);
3414 main_args [i] = utf8_arg;
3416 argc--;
3417 argv++;
3418 if (mono_method_signature (method)->param_count) {
3419 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3420 for (i = 0; i < argc; ++i) {
3421 /* The encodings should all work, given that
3422 * we've checked all these args for the
3423 * main_args array.
3425 gchar *str = mono_utf8_from_external (argv [i]);
3426 MonoString *arg = mono_string_new (domain, str);
3427 mono_array_setref (args, i, arg);
3428 g_free (str);
3430 } else {
3431 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3434 mono_assembly_set_main (method->klass->image->assembly);
3436 return mono_runtime_exec_main (method, args, exc);
3439 static MonoObject*
3440 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3442 static MonoMethod *serialize_method;
3444 void *params [1];
3445 MonoObject *array;
3447 if (!serialize_method) {
3448 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3449 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3452 if (!serialize_method) {
3453 *failure = TRUE;
3454 return NULL;
3457 g_assert (!mono_object_class (obj)->marshalbyref);
3459 params [0] = obj;
3460 *exc = NULL;
3461 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3462 if (*exc)
3463 *failure = TRUE;
3465 return array;
3468 static MonoObject*
3469 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3471 static MonoMethod *deserialize_method;
3473 void *params [1];
3474 MonoObject *result;
3476 if (!deserialize_method) {
3477 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3478 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3480 if (!deserialize_method) {
3481 *failure = TRUE;
3482 return NULL;
3485 params [0] = obj;
3486 *exc = NULL;
3487 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3488 if (*exc)
3489 *failure = TRUE;
3491 return result;
3494 static MonoObject*
3495 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3497 static MonoMethod *get_proxy_method;
3499 MonoDomain *domain = mono_domain_get ();
3500 MonoRealProxy *real_proxy;
3501 MonoReflectionType *reflection_type;
3502 MonoTransparentProxy *transparent_proxy;
3504 if (!get_proxy_method)
3505 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3507 g_assert (obj->vtable->klass->marshalbyref);
3509 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3510 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3512 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3513 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3515 *exc = NULL;
3516 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3517 if (*exc)
3518 *failure = TRUE;
3520 return (MonoObject*) transparent_proxy;
3524 * mono_object_xdomain_representation
3525 * @obj: an object
3526 * @target_domain: a domain
3527 * @exc: pointer to a MonoObject*
3529 * Creates a representation of obj in the domain target_domain. This
3530 * is either a copy of obj arrived through via serialization and
3531 * deserialization or a proxy, depending on whether the object is
3532 * serializable or marshal by ref. obj must not be in target_domain.
3534 * If the object cannot be represented in target_domain, NULL is
3535 * returned and *exc is set to an appropriate exception.
3537 MonoObject*
3538 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3540 MonoObject *deserialized = NULL;
3541 gboolean failure = FALSE;
3543 *exc = NULL;
3545 if (mono_object_class (obj)->marshalbyref) {
3546 deserialized = make_transparent_proxy (obj, &failure, exc);
3547 } else {
3548 MonoDomain *domain = mono_domain_get ();
3549 MonoObject *serialized;
3551 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3552 serialized = serialize_object (obj, &failure, exc);
3553 mono_domain_set_internal_with_options (target_domain, FALSE);
3554 if (!failure)
3555 deserialized = deserialize_object (serialized, &failure, exc);
3556 if (domain != target_domain)
3557 mono_domain_set_internal_with_options (domain, FALSE);
3560 return deserialized;
3563 /* Used in call_unhandled_exception_delegate */
3564 static MonoObject *
3565 create_unhandled_exception_eventargs (MonoObject *exc)
3567 MonoClass *klass;
3568 gpointer args [2];
3569 MonoMethod *method = NULL;
3570 MonoBoolean is_terminating = TRUE;
3571 MonoObject *obj;
3573 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3574 g_assert (klass);
3576 mono_class_init (klass);
3578 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3579 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3580 g_assert (method);
3582 args [0] = exc;
3583 args [1] = &is_terminating;
3585 obj = mono_object_new (mono_domain_get (), klass);
3586 mono_runtime_invoke (method, obj, args, NULL);
3588 return obj;
3591 /* Used in mono_unhandled_exception */
3592 static void
3593 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3594 MonoObject *e = NULL;
3595 gpointer pa [2];
3596 MonoDomain *current_domain = mono_domain_get ();
3598 if (domain != current_domain)
3599 mono_domain_set_internal_with_options (domain, FALSE);
3601 g_assert (domain == mono_object_domain (domain->domain));
3603 if (mono_object_domain (exc) != domain) {
3604 MonoObject *serialization_exc;
3606 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
3607 if (!exc) {
3608 if (serialization_exc) {
3609 MonoObject *dummy;
3610 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
3611 g_assert (exc);
3612 } else {
3613 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
3614 "System.Runtime.Serialization", "SerializationException",
3615 "Could not serialize unhandled exception.");
3619 g_assert (mono_object_domain (exc) == domain);
3621 pa [0] = domain->domain;
3622 pa [1] = create_unhandled_exception_eventargs (exc);
3623 mono_runtime_delegate_invoke (delegate, pa, &e);
3625 if (domain != current_domain)
3626 mono_domain_set_internal_with_options (current_domain, FALSE);
3628 if (e) {
3629 MonoError error;
3630 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
3631 if (!mono_error_ok (&error)) {
3632 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
3633 mono_error_cleanup (&error);
3634 } else {
3635 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3636 g_free (msg);
3641 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3644 * mono_runtime_unhandled_exception_policy_set:
3645 * @policy: the new policy
3647 * This is a VM internal routine.
3649 * Sets the runtime policy for handling unhandled exceptions.
3651 void
3652 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3653 runtime_unhandled_exception_policy = policy;
3657 * mono_runtime_unhandled_exception_policy_get:
3659 * This is a VM internal routine.
3661 * Gets the runtime policy for handling unhandled exceptions.
3663 MonoRuntimeUnhandledExceptionPolicy
3664 mono_runtime_unhandled_exception_policy_get (void) {
3665 return runtime_unhandled_exception_policy;
3669 * mono_unhandled_exception:
3670 * @exc: exception thrown
3672 * This is a VM internal routine.
3674 * We call this function when we detect an unhandled exception
3675 * in the default domain.
3677 * It invokes the * UnhandledException event in AppDomain or prints
3678 * a warning to the console
3680 void
3681 mono_unhandled_exception (MonoObject *exc)
3683 MonoDomain *current_domain = mono_domain_get ();
3684 MonoDomain *root_domain = mono_get_root_domain ();
3685 MonoClassField *field;
3686 MonoObject *current_appdomain_delegate;
3687 MonoObject *root_appdomain_delegate;
3689 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3690 "UnhandledException");
3691 g_assert (field);
3693 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3694 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
3695 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3696 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3697 if (current_domain != root_domain) {
3698 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3699 } else {
3700 current_appdomain_delegate = NULL;
3703 /* set exitcode only if we will abort the process */
3704 if (abort_process)
3705 mono_environment_exitcode_set (1);
3706 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3707 mono_print_unhandled_exception (exc);
3708 } else {
3709 if (root_appdomain_delegate) {
3710 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3712 if (current_appdomain_delegate) {
3713 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3720 * mono_runtime_exec_managed_code:
3721 * @domain: Application domain
3722 * @main_func: function to invoke from the execution thread
3723 * @main_args: parameter to the main_func
3725 * Launch a new thread to execute a function
3727 * main_func is called back from the thread with main_args as the
3728 * parameter. The callback function is expected to start Main()
3729 * eventually. This function then waits for all managed threads to
3730 * finish.
3731 * It is not necesseray anymore to execute managed code in a subthread,
3732 * so this function should not be used anymore by default: just
3733 * execute the code and then call mono_thread_manage ().
3735 void
3736 mono_runtime_exec_managed_code (MonoDomain *domain,
3737 MonoMainThreadFunc main_func,
3738 gpointer main_args)
3740 mono_thread_create (domain, main_func, main_args);
3742 mono_thread_manage ();
3746 * Execute a standard Main() method (args doesn't contain the
3747 * executable name).
3750 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3752 MonoDomain *domain;
3753 gpointer pa [1];
3754 int rval;
3755 MonoCustomAttrInfo* cinfo;
3756 gboolean has_stathread_attribute;
3757 MonoInternalThread* thread = mono_thread_internal_current ();
3759 g_assert (args);
3761 pa [0] = args;
3763 domain = mono_object_domain (args);
3764 if (!domain->entry_assembly) {
3765 gchar *str;
3766 MonoAssembly *assembly;
3768 assembly = method->klass->image->assembly;
3769 domain->entry_assembly = assembly;
3770 /* Domains created from another domain already have application_base and configuration_file set */
3771 if (domain->setup->application_base == NULL) {
3772 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3775 if (domain->setup->configuration_file == NULL) {
3776 str = g_strconcat (assembly->image->name, ".config", NULL);
3777 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3778 g_free (str);
3779 mono_set_private_bin_path_from_config (domain);
3783 cinfo = mono_custom_attrs_from_method (method);
3784 if (cinfo) {
3785 static MonoClass *stathread_attribute = NULL;
3786 if (!stathread_attribute)
3787 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3788 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3789 if (!cinfo->cached)
3790 mono_custom_attrs_free (cinfo);
3791 } else {
3792 has_stathread_attribute = FALSE;
3794 if (has_stathread_attribute) {
3795 thread->apartment_state = ThreadApartmentState_STA;
3796 } else {
3797 thread->apartment_state = ThreadApartmentState_MTA;
3799 mono_thread_init_apartment_state ();
3801 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3803 /* FIXME: check signature of method */
3804 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3805 MonoObject *res;
3806 res = mono_runtime_invoke (method, NULL, pa, exc);
3807 if (!exc || !*exc)
3808 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
3809 else
3810 rval = -1;
3812 mono_environment_exitcode_set (rval);
3813 } else {
3814 mono_runtime_invoke (method, NULL, pa, exc);
3815 if (!exc || !*exc)
3816 rval = 0;
3817 else {
3818 /* If the return type of Main is void, only
3819 * set the exitcode if an exception was thrown
3820 * (we don't want to blow away an
3821 * explicitly-set exit code)
3823 rval = -1;
3824 mono_environment_exitcode_set (rval);
3828 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
3830 return rval;
3834 * mono_install_runtime_invoke:
3835 * @func: Function to install
3837 * This is a VM internal routine
3839 void
3840 mono_install_runtime_invoke (MonoInvokeFunc func)
3842 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
3847 * mono_runtime_invoke_array:
3848 * @method: method to invoke
3849 * @obJ: object instance
3850 * @params: arguments to the method
3851 * @exc: exception information.
3853 * Invokes the method represented by @method on the object @obj.
3855 * obj is the 'this' pointer, it should be NULL for static
3856 * methods, a MonoObject* for object instances and a pointer to
3857 * the value type for value types.
3859 * The params array contains the arguments to the method with the
3860 * same convention: MonoObject* pointers for object instances and
3861 * pointers to the value type otherwise. The _invoke_array
3862 * variant takes a C# object[] as the params argument (MonoArray
3863 * *params): in this case the value types are boxed inside the
3864 * respective reference representation.
3866 * From unmanaged code you'll usually use the
3867 * mono_runtime_invoke() variant.
3869 * Note that this function doesn't handle virtual methods for
3870 * you, it will exec the exact method you pass: we still need to
3871 * expose a function to lookup the derived class implementation
3872 * of a virtual method (there are examples of this in the code,
3873 * though).
3875 * You can pass NULL as the exc argument if you don't want to
3876 * catch exceptions, otherwise, *exc will be set to the exception
3877 * thrown, if any. if an exception is thrown, you can't use the
3878 * MonoObject* result from the function.
3880 * If the method returns a value type, it is boxed in an object
3881 * reference.
3883 MonoObject*
3884 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
3885 MonoObject **exc)
3887 MonoMethodSignature *sig = mono_method_signature (method);
3888 gpointer *pa = NULL;
3889 MonoObject *res;
3890 int i;
3891 gboolean has_byref_nullables = FALSE;
3893 if (NULL != params) {
3894 pa = alloca (sizeof (gpointer) * mono_array_length (params));
3895 for (i = 0; i < mono_array_length (params); i++) {
3896 MonoType *t = sig->params [i];
3898 again:
3899 switch (t->type) {
3900 case MONO_TYPE_U1:
3901 case MONO_TYPE_I1:
3902 case MONO_TYPE_BOOLEAN:
3903 case MONO_TYPE_U2:
3904 case MONO_TYPE_I2:
3905 case MONO_TYPE_CHAR:
3906 case MONO_TYPE_U:
3907 case MONO_TYPE_I:
3908 case MONO_TYPE_U4:
3909 case MONO_TYPE_I4:
3910 case MONO_TYPE_U8:
3911 case MONO_TYPE_I8:
3912 case MONO_TYPE_R4:
3913 case MONO_TYPE_R8:
3914 case MONO_TYPE_VALUETYPE:
3915 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
3916 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
3917 pa [i] = mono_array_get (params, MonoObject*, i);
3918 if (t->byref)
3919 has_byref_nullables = TRUE;
3920 } else {
3921 /* MS seems to create the objects if a null is passed in */
3922 if (!mono_array_get (params, MonoObject*, i))
3923 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
3925 if (t->byref) {
3927 * We can't pass the unboxed vtype byref to the callee, since
3928 * that would mean the callee would be able to modify boxed
3929 * primitive types. So we (and MS) make a copy of the boxed
3930 * object, pass that to the callee, and replace the original
3931 * boxed object in the arg array with the copy.
3933 MonoObject *orig = mono_array_get (params, MonoObject*, i);
3934 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
3935 mono_array_setref (params, i, copy);
3938 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
3940 break;
3941 case MONO_TYPE_STRING:
3942 case MONO_TYPE_OBJECT:
3943 case MONO_TYPE_CLASS:
3944 case MONO_TYPE_ARRAY:
3945 case MONO_TYPE_SZARRAY:
3946 if (t->byref)
3947 pa [i] = mono_array_addr (params, MonoObject*, i);
3948 // FIXME: I need to check this code path
3949 else
3950 pa [i] = mono_array_get (params, MonoObject*, i);
3951 break;
3952 case MONO_TYPE_GENERICINST:
3953 if (t->byref)
3954 t = &t->data.generic_class->container_class->this_arg;
3955 else
3956 t = &t->data.generic_class->container_class->byval_arg;
3957 goto again;
3958 case MONO_TYPE_PTR: {
3959 MonoObject *arg;
3961 /* The argument should be an IntPtr */
3962 arg = mono_array_get (params, MonoObject*, i);
3963 if (arg == NULL) {
3964 pa [i] = NULL;
3965 } else {
3966 g_assert (arg->vtable->klass == mono_defaults.int_class);
3967 pa [i] = ((MonoIntPtr*)arg)->m_value;
3969 break;
3971 default:
3972 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
3977 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
3978 void *o = obj;
3980 if (mono_class_is_nullable (method->klass)) {
3981 /* Need to create a boxed vtype instead */
3982 g_assert (!obj);
3984 if (!params)
3985 return NULL;
3986 else
3987 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
3990 if (!obj) {
3991 obj = mono_object_new (mono_domain_get (), method->klass);
3992 g_assert (obj); /*maybe we should raise a TLE instead?*/
3993 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
3994 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
3996 if (method->klass->valuetype)
3997 o = mono_object_unbox (obj);
3998 else
3999 o = obj;
4000 } else if (method->klass->valuetype) {
4001 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4004 mono_runtime_invoke (method, o, pa, exc);
4005 return obj;
4006 } else {
4007 if (mono_class_is_nullable (method->klass)) {
4008 MonoObject *nullable;
4010 /* Convert the unboxed vtype into a Nullable structure */
4011 nullable = mono_object_new (mono_domain_get (), method->klass);
4013 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4014 obj = mono_object_unbox (nullable);
4017 /* obj must be already unboxed if needed */
4018 res = mono_runtime_invoke (method, obj, pa, exc);
4020 if (sig->ret->type == MONO_TYPE_PTR) {
4021 MonoClass *pointer_class;
4022 static MonoMethod *box_method;
4023 void *box_args [2];
4024 MonoObject *box_exc;
4027 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4028 * convert it to a Pointer object.
4030 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4031 if (!box_method)
4032 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4034 g_assert (res->vtable->klass == mono_defaults.int_class);
4035 box_args [0] = ((MonoIntPtr*)res)->m_value;
4036 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4037 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4038 g_assert (!box_exc);
4041 if (has_byref_nullables) {
4043 * The runtime invoke wrapper already converted byref nullables back,
4044 * and stored them in pa, we just need to copy them back to the
4045 * managed array.
4047 for (i = 0; i < mono_array_length (params); i++) {
4048 MonoType *t = sig->params [i];
4050 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4051 mono_array_setref (params, i, pa [i]);
4055 return res;
4059 static void
4060 arith_overflow (void)
4062 mono_raise_exception (mono_get_exception_overflow ());
4066 * mono_object_allocate:
4067 * @size: number of bytes to allocate
4069 * This is a very simplistic routine until we have our GC-aware
4070 * memory allocator.
4072 * Returns: an allocated object of size @size, or NULL on failure.
4074 static inline void *
4075 mono_object_allocate (size_t size, MonoVTable *vtable)
4077 MonoObject *o;
4078 mono_stats.new_object_count++;
4079 ALLOC_OBJECT (o, vtable, size);
4081 return o;
4085 * mono_object_allocate_ptrfree:
4086 * @size: number of bytes to allocate
4088 * Note that the memory allocated is not zeroed.
4089 * Returns: an allocated object of size @size, or NULL on failure.
4091 static inline void *
4092 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
4094 MonoObject *o;
4095 mono_stats.new_object_count++;
4096 ALLOC_PTRFREE (o, vtable, size);
4097 return o;
4100 static inline void *
4101 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
4103 void *o;
4104 ALLOC_TYPED (o, size, vtable);
4105 mono_stats.new_object_count++;
4107 return o;
4111 * mono_object_new:
4112 * @klass: the class of the object that we want to create
4114 * Returns: a newly created object whose definition is
4115 * looked up using @klass. This will not invoke any constructors,
4116 * so the consumer of this routine has to invoke any constructors on
4117 * its own to initialize the object.
4119 * It returns NULL on failure.
4121 MonoObject *
4122 mono_object_new (MonoDomain *domain, MonoClass *klass)
4124 MonoVTable *vtable;
4126 MONO_ARCH_SAVE_REGS;
4127 vtable = mono_class_vtable (domain, klass);
4128 if (!vtable)
4129 return NULL;
4130 return mono_object_new_specific (vtable);
4134 * mono_object_new_specific:
4135 * @vtable: the vtable of the object that we want to create
4137 * Returns: A newly created object with class and domain specified
4138 * by @vtable
4140 MonoObject *
4141 mono_object_new_specific (MonoVTable *vtable)
4143 MonoObject *o;
4145 MONO_ARCH_SAVE_REGS;
4147 /* check for is_com_object for COM Interop */
4148 if (vtable->remote || vtable->klass->is_com_object)
4150 gpointer pa [1];
4151 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4153 if (im == NULL) {
4154 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4156 if (!klass->inited)
4157 mono_class_init (klass);
4159 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4160 g_assert (im);
4161 vtable->domain->create_proxy_for_type_method = im;
4164 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4166 o = mono_runtime_invoke (im, NULL, pa, NULL);
4167 if (o != NULL) return o;
4170 return mono_object_new_alloc_specific (vtable);
4173 MonoObject *
4174 mono_object_new_alloc_specific (MonoVTable *vtable)
4176 MonoObject *o;
4178 if (!vtable->klass->has_references) {
4179 o = mono_object_new_ptrfree (vtable);
4180 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4181 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
4182 } else {
4183 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4184 o = mono_object_allocate (vtable->klass->instance_size, vtable);
4186 if (G_UNLIKELY (vtable->klass->has_finalize))
4187 mono_object_register_finalizer (o);
4189 if (G_UNLIKELY (profile_allocs))
4190 mono_profiler_allocation (o, vtable->klass);
4191 return o;
4194 MonoObject*
4195 mono_object_new_fast (MonoVTable *vtable)
4197 MonoObject *o;
4198 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
4199 return o;
4202 static MonoObject*
4203 mono_object_new_ptrfree (MonoVTable *vtable)
4205 MonoObject *obj;
4206 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4207 #if NEED_TO_ZERO_PTRFREE
4208 /* an inline memset is much faster for the common vcase of small objects
4209 * note we assume the allocated size is a multiple of sizeof (void*).
4211 if (vtable->klass->instance_size < 128) {
4212 gpointer *p, *end;
4213 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
4214 p = (gpointer*)((char*)obj + sizeof (MonoObject));
4215 while (p < end) {
4216 *p = NULL;
4217 ++p;
4219 } else {
4220 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
4222 #endif
4223 return obj;
4226 static MonoObject*
4227 mono_object_new_ptrfree_box (MonoVTable *vtable)
4229 MonoObject *obj;
4230 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4231 /* the object will be boxed right away, no need to memzero it */
4232 return obj;
4236 * mono_class_get_allocation_ftn:
4237 * @vtable: vtable
4238 * @for_box: the object will be used for boxing
4239 * @pass_size_in_words:
4241 * Return the allocation function appropriate for the given class.
4244 void*
4245 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4247 *pass_size_in_words = FALSE;
4249 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4250 profile_allocs = FALSE;
4252 if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4253 return mono_object_new_specific;
4255 if (!vtable->klass->has_references) {
4256 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
4257 if (for_box)
4258 return mono_object_new_ptrfree_box;
4259 return mono_object_new_ptrfree;
4262 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4264 return mono_object_new_fast;
4267 * FIXME: This is actually slower than mono_object_new_fast, because
4268 * of the overhead of parameter passing.
4271 *pass_size_in_words = TRUE;
4272 #ifdef GC_REDIRECT_TO_LOCAL
4273 return GC_local_gcj_fast_malloc;
4274 #else
4275 return GC_gcj_fast_malloc;
4276 #endif
4280 return mono_object_new_specific;
4284 * mono_object_new_from_token:
4285 * @image: Context where the type_token is hosted
4286 * @token: a token of the type that we want to create
4288 * Returns: A newly created object whose definition is
4289 * looked up using @token in the @image image
4291 MonoObject *
4292 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4294 MonoClass *class;
4296 class = mono_class_get (image, token);
4298 return mono_object_new (domain, class);
4303 * mono_object_clone:
4304 * @obj: the object to clone
4306 * Returns: A newly created object who is a shallow copy of @obj
4308 MonoObject *
4309 mono_object_clone (MonoObject *obj)
4311 MonoObject *o;
4312 int size = obj->vtable->klass->instance_size;
4314 o = mono_object_allocate (size, obj->vtable);
4316 if (obj->vtable->klass->has_references) {
4317 mono_gc_wbarrier_object_copy (o, obj);
4318 } else {
4319 int size = obj->vtable->klass->instance_size;
4320 /* do not copy the sync state */
4321 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
4323 if (G_UNLIKELY (profile_allocs))
4324 mono_profiler_allocation (o, obj->vtable->klass);
4326 if (obj->vtable->klass->has_finalize)
4327 mono_object_register_finalizer (o);
4328 return o;
4332 * mono_array_full_copy:
4333 * @src: source array to copy
4334 * @dest: destination array
4336 * Copies the content of one array to another with exactly the same type and size.
4338 void
4339 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4341 uintptr_t size;
4342 MonoClass *klass = src->obj.vtable->klass;
4344 MONO_ARCH_SAVE_REGS;
4346 g_assert (klass == dest->obj.vtable->klass);
4348 size = mono_array_length (src);
4349 g_assert (size == mono_array_length (dest));
4350 size *= mono_array_element_size (klass);
4351 #ifdef HAVE_SGEN_GC
4352 if (klass->element_class->valuetype) {
4353 if (klass->element_class->has_references)
4354 mono_value_copy_array (dest, 0, mono_array_addr_with_size (src, 0, 0), mono_array_length (src));
4355 else
4356 memcpy (&dest->vector, &src->vector, size);
4357 } else {
4358 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4360 #else
4361 memcpy (&dest->vector, &src->vector, size);
4362 #endif
4366 * mono_array_clone_in_domain:
4367 * @domain: the domain in which the array will be cloned into
4368 * @array: the array to clone
4370 * This routine returns a copy of the array that is hosted on the
4371 * specified MonoDomain.
4373 MonoArray*
4374 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4376 MonoArray *o;
4377 uintptr_t size, i;
4378 uintptr_t *sizes;
4379 MonoClass *klass = array->obj.vtable->klass;
4381 MONO_ARCH_SAVE_REGS;
4383 if (array->bounds == NULL) {
4384 size = mono_array_length (array);
4385 o = mono_array_new_full (domain, klass, &size, NULL);
4387 size *= mono_array_element_size (klass);
4388 #ifdef HAVE_SGEN_GC
4389 if (klass->element_class->valuetype) {
4390 if (klass->element_class->has_references)
4391 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4392 else
4393 memcpy (&o->vector, &array->vector, size);
4394 } else {
4395 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4397 #else
4398 memcpy (&o->vector, &array->vector, size);
4399 #endif
4400 return o;
4403 sizes = alloca (klass->rank * sizeof(intptr_t) * 2);
4404 size = mono_array_element_size (klass);
4405 for (i = 0; i < klass->rank; ++i) {
4406 sizes [i] = array->bounds [i].length;
4407 size *= array->bounds [i].length;
4408 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4410 o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
4411 #ifdef HAVE_SGEN_GC
4412 if (klass->element_class->valuetype) {
4413 if (klass->element_class->has_references)
4414 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4415 else
4416 memcpy (&o->vector, &array->vector, size);
4417 } else {
4418 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4420 #else
4421 memcpy (&o->vector, &array->vector, size);
4422 #endif
4424 return o;
4428 * mono_array_clone:
4429 * @array: the array to clone
4431 * Returns: A newly created array who is a shallow copy of @array
4433 MonoArray*
4434 mono_array_clone (MonoArray *array)
4436 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4439 /* helper macros to check for overflow when calculating the size of arrays */
4440 #ifdef MONO_BIG_ARRAYS
4441 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4442 #define MYGUINT_MAX MYGUINT64_MAX
4443 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4444 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4445 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4446 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4447 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4448 #else
4449 #define MYGUINT32_MAX 4294967295U
4450 #define MYGUINT_MAX MYGUINT32_MAX
4451 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4452 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4453 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4454 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4455 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4456 #endif
4458 gboolean
4459 mono_array_calc_byte_len (MonoClass *class, uintptr_t len, uintptr_t *res)
4461 uintptr_t byte_len;
4463 byte_len = mono_array_element_size (class);
4464 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4465 return FALSE;
4466 byte_len *= len;
4467 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4468 return FALSE;
4469 byte_len += sizeof (MonoArray);
4471 *res = byte_len;
4473 return TRUE;
4477 * mono_array_new_full:
4478 * @domain: domain where the object is created
4479 * @array_class: array class
4480 * @lengths: lengths for each dimension in the array
4481 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4483 * This routine creates a new array objects with the given dimensions,
4484 * lower bounds and type.
4486 MonoArray*
4487 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4489 uintptr_t byte_len, len, bounds_size;
4490 MonoObject *o;
4491 MonoArray *array;
4492 MonoArrayBounds *bounds;
4493 MonoVTable *vtable;
4494 int i;
4496 if (!array_class->inited)
4497 mono_class_init (array_class);
4499 len = 1;
4501 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4502 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4503 len = lengths [0];
4504 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4505 arith_overflow ();
4506 bounds_size = 0;
4507 } else {
4508 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4510 for (i = 0; i < array_class->rank; ++i) {
4511 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4512 arith_overflow ();
4513 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4514 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4515 len *= lengths [i];
4519 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4520 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4522 if (bounds_size) {
4523 /* align */
4524 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4525 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4526 byte_len = (byte_len + 3) & ~3;
4527 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4528 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4529 byte_len += bounds_size;
4532 * Following three lines almost taken from mono_object_new ():
4533 * they need to be kept in sync.
4535 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4536 #ifndef HAVE_SGEN_GC
4537 if (!array_class->has_references) {
4538 o = mono_object_allocate_ptrfree (byte_len, vtable);
4539 #if NEED_TO_ZERO_PTRFREE
4540 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4541 #endif
4542 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4543 o = mono_object_allocate_spec (byte_len, vtable);
4544 }else {
4545 o = mono_object_allocate (byte_len, vtable);
4548 array = (MonoArray*)o;
4549 array->max_length = len;
4551 if (bounds_size) {
4552 bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4553 array->bounds = bounds;
4555 #else
4556 if (bounds_size)
4557 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4558 else
4559 o = mono_gc_alloc_vector (vtable, byte_len, len);
4560 array = (MonoArray*)o;
4561 mono_stats.new_object_count++;
4563 bounds = array->bounds;
4564 #endif
4566 if (bounds_size) {
4567 for (i = 0; i < array_class->rank; ++i) {
4568 bounds [i].length = lengths [i];
4569 if (lower_bounds)
4570 bounds [i].lower_bound = lower_bounds [i];
4574 if (G_UNLIKELY (profile_allocs))
4575 mono_profiler_allocation (o, array_class);
4577 return array;
4581 * mono_array_new:
4582 * @domain: domain where the object is created
4583 * @eclass: element class
4584 * @n: number of array elements
4586 * This routine creates a new szarray with @n elements of type @eclass.
4588 MonoArray *
4589 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
4591 MonoClass *ac;
4593 MONO_ARCH_SAVE_REGS;
4595 ac = mono_array_class_get (eclass, 1);
4596 g_assert (ac);
4598 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4602 * mono_array_new_specific:
4603 * @vtable: a vtable in the appropriate domain for an initialized class
4604 * @n: number of array elements
4606 * This routine is a fast alternative to mono_array_new() for code which
4607 * can be sure about the domain it operates in.
4609 MonoArray *
4610 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
4612 MonoObject *o;
4613 MonoArray *ao;
4614 uintptr_t byte_len;
4616 MONO_ARCH_SAVE_REGS;
4618 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4619 arith_overflow ();
4620 return NULL;
4623 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4624 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4625 return NULL;
4627 #ifndef HAVE_SGEN_GC
4628 if (!vtable->klass->has_references) {
4629 o = mono_object_allocate_ptrfree (byte_len, vtable);
4630 #if NEED_TO_ZERO_PTRFREE
4631 ((MonoArray*)o)->bounds = NULL;
4632 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4633 #endif
4634 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4635 o = mono_object_allocate_spec (byte_len, vtable);
4636 } else {
4637 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4638 o = mono_object_allocate (byte_len, vtable);
4641 ao = (MonoArray *)o;
4642 ao->max_length = n;
4643 #else
4644 o = mono_gc_alloc_vector (vtable, byte_len, n);
4645 ao = (MonoArray*)o;
4646 mono_stats.new_object_count++;
4647 #endif
4649 if (G_UNLIKELY (profile_allocs))
4650 mono_profiler_allocation (o, vtable->klass);
4652 return ao;
4656 * mono_string_new_utf16:
4657 * @text: a pointer to an utf16 string
4658 * @len: the length of the string
4660 * Returns: A newly created string object which contains @text.
4662 MonoString *
4663 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4665 MonoString *s;
4667 s = mono_string_new_size (domain, len);
4668 g_assert (s != NULL);
4670 memcpy (mono_string_chars (s), text, len * 2);
4672 return s;
4676 * mono_string_new_size:
4677 * @text: a pointer to an utf16 string
4678 * @len: the length of the string
4680 * Returns: A newly created string object of @len
4682 MonoString *
4683 mono_string_new_size (MonoDomain *domain, gint32 len)
4685 MonoString *s;
4686 MonoVTable *vtable;
4687 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4689 /* overflow ? can't fit it, can't allocate it! */
4690 if (len > size)
4691 mono_gc_out_of_memory (-1);
4693 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4694 g_assert (vtable);
4696 #ifndef HAVE_SGEN_GC
4697 s = mono_object_allocate_ptrfree (size, vtable);
4699 s->length = len;
4700 #else
4701 s = mono_gc_alloc_string (vtable, size, len);
4702 #endif
4703 #if NEED_TO_ZERO_PTRFREE
4704 s->chars [len] = 0;
4705 #endif
4706 if (G_UNLIKELY (profile_allocs))
4707 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4709 return s;
4713 * mono_string_new_len:
4714 * @text: a pointer to an utf8 string
4715 * @length: number of bytes in @text to consider
4717 * Returns: A newly created string object which contains @text.
4719 MonoString*
4720 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4722 GError *error = NULL;
4723 MonoString *o = NULL;
4724 guint16 *ut;
4725 glong items_written;
4727 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
4729 if (!error)
4730 o = mono_string_new_utf16 (domain, ut, items_written);
4731 else
4732 g_error_free (error);
4734 g_free (ut);
4736 return o;
4740 * mono_string_new:
4741 * @text: a pointer to an utf8 string
4743 * Returns: A newly created string object which contains @text.
4745 MonoString*
4746 mono_string_new (MonoDomain *domain, const char *text)
4748 GError *error = NULL;
4749 MonoString *o = NULL;
4750 guint16 *ut;
4751 glong items_written;
4752 int l;
4754 l = strlen (text);
4756 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4758 if (!error)
4759 o = mono_string_new_utf16 (domain, ut, items_written);
4760 else
4761 g_error_free (error);
4763 g_free (ut);
4764 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4765 #if 0
4766 gunichar2 *str;
4767 const gchar *end;
4768 int len;
4769 MonoString *o = NULL;
4771 if (!g_utf8_validate (text, -1, &end))
4772 return NULL;
4774 len = g_utf8_strlen (text, -1);
4775 o = mono_string_new_size (domain, len);
4776 str = mono_string_chars (o);
4778 while (text < end) {
4779 *str++ = g_utf8_get_char (text);
4780 text = g_utf8_next_char (text);
4782 #endif
4783 return o;
4787 * mono_string_new_wrapper:
4788 * @text: pointer to utf8 characters.
4790 * Helper function to create a string object from @text in the current domain.
4792 MonoString*
4793 mono_string_new_wrapper (const char *text)
4795 MonoDomain *domain = mono_domain_get ();
4797 MONO_ARCH_SAVE_REGS;
4799 if (text)
4800 return mono_string_new (domain, text);
4802 return NULL;
4806 * mono_value_box:
4807 * @class: the class of the value
4808 * @value: a pointer to the unboxed data
4810 * Returns: A newly created object which contains @value.
4812 MonoObject *
4813 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
4815 MonoObject *res;
4816 int size;
4817 MonoVTable *vtable;
4819 g_assert (class->valuetype);
4820 if (mono_class_is_nullable (class))
4821 return mono_nullable_box (value, class);
4823 vtable = mono_class_vtable (domain, class);
4824 if (!vtable)
4825 return NULL;
4826 size = mono_class_instance_size (class);
4827 res = mono_object_new_alloc_specific (vtable);
4828 if (G_UNLIKELY (profile_allocs))
4829 mono_profiler_allocation (res, class);
4831 size = size - sizeof (MonoObject);
4833 #ifdef HAVE_SGEN_GC
4834 g_assert (size == mono_class_value_size (class, NULL));
4835 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
4836 #else
4837 #if NO_UNALIGNED_ACCESS
4838 memcpy ((char *)res + sizeof (MonoObject), value, size);
4839 #else
4840 switch (size) {
4841 case 1:
4842 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
4843 break;
4844 case 2:
4845 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
4846 break;
4847 case 4:
4848 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
4849 break;
4850 case 8:
4851 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
4852 break;
4853 default:
4854 memcpy ((char *)res + sizeof (MonoObject), value, size);
4856 #endif
4857 #endif
4858 if (class->has_finalize)
4859 mono_object_register_finalizer (res);
4860 return res;
4864 * mono_value_copy:
4865 * @dest: destination pointer
4866 * @src: source pointer
4867 * @klass: a valuetype class
4869 * Copy a valuetype from @src to @dest. This function must be used
4870 * when @klass contains references fields.
4872 void
4873 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
4875 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
4879 * mono_value_copy_array:
4880 * @dest: destination array
4881 * @dest_idx: index in the @dest array
4882 * @src: source pointer
4883 * @count: number of items
4885 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
4886 * This function must be used when @klass contains references fields.
4887 * Overlap is handled.
4889 void
4890 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
4892 int size = mono_array_element_size (dest->obj.vtable->klass);
4893 char *d = mono_array_addr_with_size (dest, size, dest_idx);
4894 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
4895 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
4899 * mono_object_get_domain:
4900 * @obj: object to query
4902 * Returns: the MonoDomain where the object is hosted
4904 MonoDomain*
4905 mono_object_get_domain (MonoObject *obj)
4907 return mono_object_domain (obj);
4911 * mono_object_get_class:
4912 * @obj: object to query
4914 * Returns: the MonOClass of the object.
4916 MonoClass*
4917 mono_object_get_class (MonoObject *obj)
4919 return mono_object_class (obj);
4922 * mono_object_get_size:
4923 * @o: object to query
4925 * Returns: the size, in bytes, of @o
4927 guint
4928 mono_object_get_size (MonoObject* o)
4930 MonoClass* klass = mono_object_class (o);
4931 if (klass == mono_defaults.string_class) {
4932 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
4933 } else if (o->vtable->rank) {
4934 MonoArray *array = (MonoArray*)o;
4935 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
4936 if (array->bounds) {
4937 size += 3;
4938 size &= ~3;
4939 size += sizeof (MonoArrayBounds) * o->vtable->rank;
4941 return size;
4942 } else {
4943 return mono_class_instance_size (klass);
4948 * mono_object_unbox:
4949 * @obj: object to unbox
4951 * Returns: a pointer to the start of the valuetype boxed in this
4952 * object.
4954 * This method will assert if the object passed is not a valuetype.
4956 gpointer
4957 mono_object_unbox (MonoObject *obj)
4959 /* add assert for valuetypes? */
4960 g_assert (obj->vtable->klass->valuetype);
4961 return ((char*)obj) + sizeof (MonoObject);
4965 * mono_object_isinst:
4966 * @obj: an object
4967 * @klass: a pointer to a class
4969 * Returns: @obj if @obj is derived from @klass
4971 MonoObject *
4972 mono_object_isinst (MonoObject *obj, MonoClass *klass)
4974 if (!klass->inited)
4975 mono_class_init (klass);
4977 if (klass->marshalbyref || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
4978 return mono_object_isinst_mbyref (obj, klass);
4980 if (!obj)
4981 return NULL;
4983 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
4986 MonoObject *
4987 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
4989 MonoVTable *vt;
4991 if (!obj)
4992 return NULL;
4994 vt = obj->vtable;
4996 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4997 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
4998 return obj;
5001 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5002 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5003 return obj;
5004 } else {
5005 MonoClass *oklass = vt->klass;
5006 if ((oklass == mono_defaults.transparent_proxy_class))
5007 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5009 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5010 return obj;
5013 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5015 MonoDomain *domain = mono_domain_get ();
5016 MonoObject *res;
5017 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5018 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5019 MonoMethod *im = NULL;
5020 gpointer pa [2];
5022 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5023 im = mono_object_get_virtual_method (rp, im);
5024 g_assert (im);
5026 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5027 pa [1] = obj;
5029 res = mono_runtime_invoke (im, rp, pa, NULL);
5031 if (*(MonoBoolean *) mono_object_unbox(res)) {
5032 /* Update the vtable of the remote type, so it can safely cast to this new type */
5033 mono_upgrade_remote_class (domain, obj, klass);
5034 return obj;
5038 return NULL;
5042 * mono_object_castclass_mbyref:
5043 * @obj: an object
5044 * @klass: a pointer to a class
5046 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5048 MonoObject *
5049 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5051 if (!obj) return NULL;
5052 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5054 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5055 "System",
5056 "InvalidCastException"));
5057 return NULL;
5060 typedef struct {
5061 MonoDomain *orig_domain;
5062 MonoString *ins;
5063 MonoString *res;
5064 } LDStrInfo;
5066 static void
5067 str_lookup (MonoDomain *domain, gpointer user_data)
5069 LDStrInfo *info = user_data;
5070 if (info->res || domain == info->orig_domain)
5071 return;
5072 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5075 #ifdef HAVE_SGEN_GC
5077 static MonoString*
5078 mono_string_get_pinned (MonoString *str)
5080 int size;
5081 MonoString *news;
5082 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5083 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5084 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5085 news->length = mono_string_length (str);
5086 return news;
5089 #else
5090 #define mono_string_get_pinned(str) (str)
5091 #endif
5093 static MonoString*
5094 mono_string_is_interned_lookup (MonoString *str, int insert)
5096 MonoGHashTable *ldstr_table;
5097 MonoString *res;
5098 MonoDomain *domain;
5100 domain = ((MonoObject *)str)->vtable->domain;
5101 ldstr_table = domain->ldstr_table;
5102 ldstr_lock ();
5103 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
5104 ldstr_unlock ();
5105 return res;
5107 if (insert) {
5108 str = mono_string_get_pinned (str);
5109 mono_g_hash_table_insert (ldstr_table, str, str);
5110 ldstr_unlock ();
5111 return str;
5112 } else {
5113 LDStrInfo ldstr_info;
5114 ldstr_info.orig_domain = domain;
5115 ldstr_info.ins = str;
5116 ldstr_info.res = NULL;
5118 mono_domain_foreach (str_lookup, &ldstr_info);
5119 if (ldstr_info.res) {
5121 * the string was already interned in some other domain:
5122 * intern it in the current one as well.
5124 mono_g_hash_table_insert (ldstr_table, str, str);
5125 ldstr_unlock ();
5126 return str;
5129 ldstr_unlock ();
5130 return NULL;
5134 * mono_string_is_interned:
5135 * @o: String to probe
5137 * Returns whether the string has been interned.
5139 MonoString*
5140 mono_string_is_interned (MonoString *o)
5142 return mono_string_is_interned_lookup (o, FALSE);
5146 * mono_string_intern:
5147 * @o: String to intern
5149 * Interns the string passed.
5150 * Returns: The interned string.
5152 MonoString*
5153 mono_string_intern (MonoString *str)
5155 return mono_string_is_interned_lookup (str, TRUE);
5159 * mono_ldstr:
5160 * @domain: the domain where the string will be used.
5161 * @image: a metadata context
5162 * @idx: index into the user string table.
5164 * Implementation for the ldstr opcode.
5165 * Returns: a loaded string from the @image/@idx combination.
5167 MonoString*
5168 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5170 MONO_ARCH_SAVE_REGS;
5172 if (image->dynamic) {
5173 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5174 return str;
5175 } else {
5176 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5177 return NULL; /*FIXME we should probably be raising an exception here*/
5178 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5183 * mono_ldstr_metadata_sig
5184 * @domain: the domain for the string
5185 * @sig: the signature of a metadata string
5187 * Returns: a MonoString for a string stored in the metadata
5189 static MonoString*
5190 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5192 const char *str = sig;
5193 MonoString *o, *interned;
5194 size_t len2;
5196 len2 = mono_metadata_decode_blob_size (str, &str);
5197 len2 >>= 1;
5199 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5200 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5202 int i;
5203 guint16 *p2 = (guint16*)mono_string_chars (o);
5204 for (i = 0; i < len2; ++i) {
5205 *p2 = GUINT16_FROM_LE (*p2);
5206 ++p2;
5209 #endif
5210 ldstr_lock ();
5211 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
5212 ldstr_unlock ();
5213 /* o will get garbage collected */
5214 return interned;
5217 o = mono_string_get_pinned (o);
5218 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5219 ldstr_unlock ();
5221 return o;
5225 * mono_string_to_utf8:
5226 * @s: a System.String
5228 * Returns the UTF8 representation for @s.
5229 * The resulting buffer needs to be freed with mono_free().
5231 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5233 char *
5234 mono_string_to_utf8 (MonoString *s)
5236 MonoError error;
5237 char *result = mono_string_to_utf8_checked (s, &error);
5239 if (!mono_error_ok (&error))
5240 mono_error_raise_exception (&error);
5241 return result;
5245 * mono_string_to_utf8_checked:
5246 * @s: a System.String
5247 * @error: a MonoError.
5249 * Converts a MonoString to its UTF8 representation. May fail; check
5250 * @error to determine whether the conversion was successful.
5251 * The resulting buffer should be freed with mono_free().
5253 char *
5254 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5256 long written = 0;
5257 char *as;
5258 GError *gerror = NULL;
5260 mono_error_init (error);
5262 if (s == NULL)
5263 return NULL;
5265 if (!s->length)
5266 return g_strdup ("");
5268 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5269 if (gerror) {
5270 mono_error_set_argument (error, "string", "%s", gerror->message);
5271 g_error_free (gerror);
5272 return NULL;
5274 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5275 if (s->length > written) {
5276 /* allocate the total length and copy the part of the string that has been converted */
5277 char *as2 = g_malloc0 (s->length);
5278 memcpy (as2, as, written);
5279 g_free (as);
5280 as = as2;
5283 return as;
5287 * mono_string_to_utf16:
5288 * @s: a MonoString
5290 * Return an null-terminated array of the utf-16 chars
5291 * contained in @s. The result must be freed with g_free().
5292 * This is a temporary helper until our string implementation
5293 * is reworked to always include the null terminating char.
5295 mono_unichar2*
5296 mono_string_to_utf16 (MonoString *s)
5298 char *as;
5300 if (s == NULL)
5301 return NULL;
5303 as = g_malloc ((s->length * 2) + 2);
5304 as [(s->length * 2)] = '\0';
5305 as [(s->length * 2) + 1] = '\0';
5307 if (!s->length) {
5308 return (gunichar2 *)(as);
5311 memcpy (as, mono_string_chars(s), s->length * 2);
5312 return (gunichar2 *)(as);
5316 * mono_string_from_utf16:
5317 * @data: the UTF16 string (LPWSTR) to convert
5319 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5321 * Returns: a MonoString.
5323 MonoString *
5324 mono_string_from_utf16 (gunichar2 *data)
5326 MonoDomain *domain = mono_domain_get ();
5327 int len = 0;
5329 if (!data)
5330 return NULL;
5332 while (data [len]) len++;
5334 return mono_string_new_utf16 (domain, data, len);
5338 static char *
5339 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, MonoError *error)
5341 char *r;
5342 char *mp_s;
5343 int len;
5345 r = mono_string_to_utf8_checked (s, error);
5346 if (!mono_error_ok (error))
5347 return NULL;
5349 if (!mp && !image)
5350 return r;
5352 len = strlen (r) + 1;
5353 if (mp)
5354 mp_s = mono_mempool_alloc (mp, len);
5355 else
5356 mp_s = mono_image_alloc (image, len);
5358 memcpy (mp_s, r, len);
5360 g_free (r);
5362 return mp_s;
5366 * mono_string_to_utf8_image:
5367 * @s: a System.String
5369 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5371 char *
5372 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5374 return mono_string_to_utf8_internal (NULL, image, s, error);
5378 * mono_string_to_utf8_mp:
5379 * @s: a System.String
5381 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5383 char *
5384 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5386 return mono_string_to_utf8_internal (mp, NULL, s, error);
5389 static void
5390 default_ex_handler (MonoException *ex)
5392 MonoObject *o = (MonoObject*)ex;
5393 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
5394 exit (1);
5397 static MonoExceptionFunc ex_handler = default_ex_handler;
5400 * mono_install_handler:
5401 * @func: exception handler
5403 * This is an internal JIT routine used to install the handler for exceptions
5404 * being throwh.
5406 void
5407 mono_install_handler (MonoExceptionFunc func)
5409 ex_handler = func? func: default_ex_handler;
5413 * mono_raise_exception:
5414 * @ex: exception object
5416 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5418 void
5419 mono_raise_exception (MonoException *ex)
5422 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5423 * that will cause gcc to omit the function epilog, causing problems when
5424 * the JIT tries to walk the stack, since the return address on the stack
5425 * will point into the next function in the executable, not this one.
5428 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class) {
5429 MonoInternalThread *thread = mono_thread_internal_current ();
5430 g_assert (ex->object.vtable->domain == mono_domain_get ());
5431 MONO_OBJECT_SETREF (thread, abort_exc, ex);
5434 ex_handler (ex);
5438 * mono_wait_handle_new:
5439 * @domain: Domain where the object will be created
5440 * @handle: Handle for the wait handle
5442 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5444 MonoWaitHandle *
5445 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5447 MonoWaitHandle *res;
5448 gpointer params [1];
5449 static MonoMethod *handle_set;
5451 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5453 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5454 if (!handle_set)
5455 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5457 params [0] = &handle;
5458 mono_runtime_invoke (handle_set, res, params, NULL);
5460 return res;
5463 HANDLE
5464 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5466 static MonoClassField *f_os_handle;
5467 static MonoClassField *f_safe_handle;
5469 if (!f_os_handle && !f_safe_handle) {
5470 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5471 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5474 if (f_os_handle) {
5475 HANDLE retval;
5476 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5477 return retval;
5478 } else {
5479 MonoSafeHandle *sh;
5480 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5481 return sh->handle;
5486 static MonoObject*
5487 mono_runtime_capture_context (MonoDomain *domain)
5489 RuntimeInvokeFunction runtime_invoke;
5491 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5492 MonoMethod *method = mono_get_context_capture_method ();
5493 MonoMethod *wrapper;
5494 if (!method)
5495 return NULL;
5496 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5497 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5498 domain->capture_context_method = mono_compile_method (method);
5501 runtime_invoke = domain->capture_context_runtime_invoke;
5503 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5506 * mono_async_result_new:
5507 * @domain:domain where the object will be created.
5508 * @handle: wait handle.
5509 * @state: state to pass to AsyncResult
5510 * @data: C closure data.
5512 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5513 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5516 MonoAsyncResult *
5517 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5519 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5520 MonoObject *context = mono_runtime_capture_context (domain);
5521 /* we must capture the execution context from the original thread */
5522 if (context) {
5523 MONO_OBJECT_SETREF (res, execution_context, context);
5524 /* note: result may be null if the flow is suppressed */
5527 res->data = data;
5528 MONO_OBJECT_SETREF (res, object_data, object_data);
5529 MONO_OBJECT_SETREF (res, async_state, state);
5530 if (handle != NULL)
5531 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5533 res->sync_completed = FALSE;
5534 res->completed = FALSE;
5536 return res;
5539 void
5540 mono_message_init (MonoDomain *domain,
5541 MonoMethodMessage *this,
5542 MonoReflectionMethod *method,
5543 MonoArray *out_args)
5545 static MonoClass *object_array_klass;
5546 static MonoClass *byte_array_klass;
5547 static MonoClass *string_array_klass;
5548 MonoMethodSignature *sig = mono_method_signature (method->method);
5549 MonoString *name;
5550 int i, j;
5551 char **names;
5552 guint8 arg_type;
5554 if (!object_array_klass) {
5555 MonoClass *klass;
5557 klass = mono_array_class_get (mono_defaults.object_class, 1);
5558 g_assert (klass);
5560 mono_memory_barrier ();
5561 object_array_klass = klass;
5563 klass = mono_array_class_get (mono_defaults.byte_class, 1);
5564 g_assert (klass);
5566 mono_memory_barrier ();
5567 byte_array_klass = klass;
5569 klass = mono_array_class_get (mono_defaults.string_class, 1);
5570 g_assert (klass);
5572 mono_memory_barrier ();
5573 string_array_klass = klass;
5576 MONO_OBJECT_SETREF (this, method, method);
5578 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
5579 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
5580 this->async_result = NULL;
5581 this->call_type = CallType_Sync;
5583 names = g_new (char *, sig->param_count);
5584 mono_method_get_param_names (method->method, (const char **) names);
5585 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
5587 for (i = 0; i < sig->param_count; i++) {
5588 name = mono_string_new (domain, names [i]);
5589 mono_array_setref (this->names, i, name);
5592 g_free (names);
5593 for (i = 0, j = 0; i < sig->param_count; i++) {
5594 if (sig->params [i]->byref) {
5595 if (out_args) {
5596 MonoObject* arg = mono_array_get (out_args, gpointer, j);
5597 mono_array_setref (this->args, i, arg);
5598 j++;
5600 arg_type = 2;
5601 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5602 arg_type |= 1;
5603 } else {
5604 arg_type = 1;
5605 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5606 arg_type |= 4;
5608 mono_array_set (this->arg_types, guint8, i, arg_type);
5613 * mono_remoting_invoke:
5614 * @real_proxy: pointer to a RealProxy object
5615 * @msg: The MonoMethodMessage to execute
5616 * @exc: used to store exceptions
5617 * @out_args: used to store output arguments
5619 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5620 * IMessage interface and it is not trivial to extract results from there. So
5621 * we call an helper method PrivateInvoke instead of calling
5622 * RealProxy::Invoke() directly.
5624 * Returns: the result object.
5626 MonoObject *
5627 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
5628 MonoObject **exc, MonoArray **out_args)
5630 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5631 gpointer pa [4];
5633 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5635 if (!im) {
5636 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
5637 g_assert (im);
5638 real_proxy->vtable->domain->private_invoke_method = im;
5641 pa [0] = real_proxy;
5642 pa [1] = msg;
5643 pa [2] = exc;
5644 pa [3] = out_args;
5646 return mono_runtime_invoke (im, NULL, pa, exc);
5649 MonoObject *
5650 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
5651 MonoObject **exc, MonoArray **out_args)
5653 static MonoClass *object_array_klass;
5654 MonoDomain *domain;
5655 MonoMethod *method;
5656 MonoMethodSignature *sig;
5657 MonoObject *ret;
5658 int i, j, outarg_count = 0;
5660 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5662 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
5663 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5664 target = tp->rp->unwrapped_server;
5665 } else {
5666 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
5670 domain = mono_domain_get ();
5671 method = msg->method->method;
5672 sig = mono_method_signature (method);
5674 for (i = 0; i < sig->param_count; i++) {
5675 if (sig->params [i]->byref)
5676 outarg_count++;
5679 if (!object_array_klass) {
5680 MonoClass *klass;
5682 klass = mono_array_class_get (mono_defaults.object_class, 1);
5683 g_assert (klass);
5685 mono_memory_barrier ();
5686 object_array_klass = klass;
5689 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
5690 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
5691 *exc = NULL;
5693 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
5695 for (i = 0, j = 0; i < sig->param_count; i++) {
5696 if (sig->params [i]->byref) {
5697 MonoObject* arg;
5698 arg = mono_array_get (msg->args, gpointer, i);
5699 mono_array_setref (*out_args, j, arg);
5700 j++;
5704 return ret;
5708 * mono_object_to_string:
5709 * @obj: The object
5710 * @exc: Any exception thrown by ToString (). May be NULL.
5712 * Returns: the result of calling ToString () on an object.
5714 MonoString *
5715 mono_object_to_string (MonoObject *obj, MonoObject **exc)
5717 static MonoMethod *to_string = NULL;
5718 MonoMethod *method;
5720 g_assert (obj);
5722 if (!to_string)
5723 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
5725 method = mono_object_get_virtual_method (obj, to_string);
5727 return (MonoString *) mono_runtime_invoke (method, obj, NULL, exc);
5731 * mono_print_unhandled_exception:
5732 * @exc: The exception
5734 * Prints the unhandled exception.
5736 void
5737 mono_print_unhandled_exception (MonoObject *exc)
5739 MonoString * str;
5740 char *message = (char*)"";
5741 gboolean free_message = FALSE;
5742 MonoError error;
5744 str = mono_object_to_string (exc, NULL);
5745 if (str) {
5746 message = mono_string_to_utf8_checked (str, &error);
5747 if (!mono_error_ok (&error)) {
5748 mono_error_cleanup (&error);
5749 message = (char *) "";
5750 } else {
5751 free_message = TRUE;
5756 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
5757 * exc->vtable->klass->name, message);
5759 g_printerr ("\nUnhandled Exception: %s\n", message);
5761 if (free_message)
5762 g_free (message);
5766 * mono_delegate_ctor:
5767 * @this: pointer to an uninitialized delegate object
5768 * @target: target object
5769 * @addr: pointer to native code
5770 * @method: method
5772 * Initialize a delegate and sets a specific method, not the one
5773 * associated with addr. This is useful when sharing generic code.
5774 * In that case addr will most probably not be associated with the
5775 * correct instantiation of the method.
5777 void
5778 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
5780 MonoDelegate *delegate = (MonoDelegate *)this;
5781 MonoClass *class;
5783 g_assert (this);
5784 g_assert (addr);
5786 if (method)
5787 delegate->method = method;
5789 class = this->vtable->klass;
5790 mono_stats.delegate_creations++;
5792 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5793 g_assert (method);
5794 method = mono_marshal_get_remoting_invoke (method);
5795 delegate->method_ptr = mono_compile_method (method);
5796 MONO_OBJECT_SETREF (delegate, target, target);
5797 } else if (method && mono_method_signature (method)->hasthis && method->klass->valuetype) {
5798 method = mono_marshal_get_unbox_wrapper (method);
5799 delegate->method_ptr = mono_compile_method (method);
5800 MONO_OBJECT_SETREF (delegate, target, target);
5801 } else {
5802 delegate->method_ptr = addr;
5803 MONO_OBJECT_SETREF (delegate, target, target);
5806 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
5810 * mono_delegate_ctor:
5811 * @this: pointer to an uninitialized delegate object
5812 * @target: target object
5813 * @addr: pointer to native code
5815 * This is used to initialize a delegate.
5817 void
5818 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
5820 MonoDomain *domain = mono_domain_get ();
5821 MonoJitInfo *ji;
5822 MonoMethod *method = NULL;
5824 g_assert (addr);
5826 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
5827 method = ji->method;
5828 g_assert (!method->klass->generic_container);
5831 mono_delegate_ctor_with_method (this, target, addr, method);
5835 * mono_method_call_message_new:
5836 * @method: method to encapsulate
5837 * @params: parameters to the method
5838 * @invoke: optional, delegate invoke.
5839 * @cb: async callback delegate.
5840 * @state: state passed to the async callback.
5842 * Translates arguments pointers into a MonoMethodMessage.
5844 MonoMethodMessage *
5845 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
5846 MonoDelegate **cb, MonoObject **state)
5848 MonoDomain *domain = mono_domain_get ();
5849 MonoMethodSignature *sig = mono_method_signature (method);
5850 MonoMethodMessage *msg;
5851 int i, count, type;
5853 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5855 if (invoke) {
5856 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
5857 count = sig->param_count - 2;
5858 } else {
5859 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
5860 count = sig->param_count;
5863 for (i = 0; i < count; i++) {
5864 gpointer vpos;
5865 MonoClass *class;
5866 MonoObject *arg;
5868 if (sig->params [i]->byref)
5869 vpos = *((gpointer *)params [i]);
5870 else
5871 vpos = params [i];
5873 type = sig->params [i]->type;
5874 class = mono_class_from_mono_type (sig->params [i]);
5876 if (class->valuetype)
5877 arg = mono_value_box (domain, class, vpos);
5878 else
5879 arg = *((MonoObject **)vpos);
5881 mono_array_setref (msg->args, i, arg);
5884 if (cb != NULL && state != NULL) {
5885 *cb = *((MonoDelegate **)params [i]);
5886 i++;
5887 *state = *((MonoObject **)params [i]);
5890 return msg;
5894 * mono_method_return_message_restore:
5896 * Restore results from message based processing back to arguments pointers
5898 void
5899 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
5901 MonoMethodSignature *sig = mono_method_signature (method);
5902 int i, j, type, size, out_len;
5904 if (out_args == NULL)
5905 return;
5906 out_len = mono_array_length (out_args);
5907 if (out_len == 0)
5908 return;
5910 for (i = 0, j = 0; i < sig->param_count; i++) {
5911 MonoType *pt = sig->params [i];
5913 if (pt->byref) {
5914 char *arg;
5915 if (j >= out_len)
5916 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
5918 arg = mono_array_get (out_args, gpointer, j);
5919 type = pt->type;
5921 g_assert (type != MONO_TYPE_VOID);
5923 if (MONO_TYPE_IS_REFERENCE (pt)) {
5924 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
5925 } else {
5926 if (arg) {
5927 MonoClass *class = ((MonoObject*)arg)->vtable->klass;
5928 size = mono_class_value_size (class, NULL);
5929 if (class->has_references)
5930 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
5931 else
5932 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
5933 } else {
5934 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
5935 memset (*((gpointer *)params [i]), 0, size);
5939 j++;
5945 * mono_load_remote_field:
5946 * @this: pointer to an object
5947 * @klass: klass of the object containing @field
5948 * @field: the field to load
5949 * @res: a storage to store the result
5951 * This method is called by the runtime on attempts to load fields of
5952 * transparent proxy objects. @this points to such TP, @klass is the class of
5953 * the object containing @field. @res is a storage location which can be
5954 * used to store the result.
5956 * Returns: an address pointing to the value of field.
5958 gpointer
5959 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
5961 static MonoMethod *getter = NULL;
5962 MonoDomain *domain = mono_domain_get ();
5963 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5964 MonoClass *field_class;
5965 MonoMethodMessage *msg;
5966 MonoArray *out_args;
5967 MonoObject *exc;
5968 char* full_name;
5970 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5971 g_assert (res != NULL);
5973 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5974 mono_field_get_value (tp->rp->unwrapped_server, field, res);
5975 return res;
5978 if (!getter) {
5979 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5980 g_assert (getter);
5983 field_class = mono_class_from_mono_type (field->type);
5985 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5986 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5987 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5989 full_name = mono_type_get_full_name (klass);
5990 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5991 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5992 g_free (full_name);
5994 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5996 if (exc) mono_raise_exception ((MonoException *)exc);
5998 if (mono_array_length (out_args) == 0)
5999 return NULL;
6001 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6003 if (field_class->valuetype) {
6004 return ((char *)*res) + sizeof (MonoObject);
6005 } else
6006 return res;
6010 * mono_load_remote_field_new:
6011 * @this:
6012 * @klass:
6013 * @field:
6015 * Missing documentation.
6017 MonoObject *
6018 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
6020 static MonoMethod *getter = NULL;
6021 MonoDomain *domain = mono_domain_get ();
6022 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6023 MonoClass *field_class;
6024 MonoMethodMessage *msg;
6025 MonoArray *out_args;
6026 MonoObject *exc, *res;
6027 char* full_name;
6029 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6031 field_class = mono_class_from_mono_type (field->type);
6033 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6034 gpointer val;
6035 if (field_class->valuetype) {
6036 res = mono_object_new (domain, field_class);
6037 val = ((gchar *) res) + sizeof (MonoObject);
6038 } else {
6039 val = &res;
6041 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6042 return res;
6045 if (!getter) {
6046 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6047 g_assert (getter);
6050 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6051 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6053 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6055 full_name = mono_type_get_full_name (klass);
6056 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6057 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6058 g_free (full_name);
6060 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6062 if (exc) mono_raise_exception ((MonoException *)exc);
6064 if (mono_array_length (out_args) == 0)
6065 res = NULL;
6066 else
6067 res = mono_array_get (out_args, MonoObject *, 0);
6069 return res;
6073 * mono_store_remote_field:
6074 * @this: pointer to an object
6075 * @klass: klass of the object containing @field
6076 * @field: the field to load
6077 * @val: the value/object to store
6079 * This method is called by the runtime on attempts to store fields of
6080 * transparent proxy objects. @this points to such TP, @klass is the class of
6081 * the object containing @field. @val is the new value to store in @field.
6083 void
6084 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
6086 static MonoMethod *setter = NULL;
6087 MonoDomain *domain = mono_domain_get ();
6088 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6089 MonoClass *field_class;
6090 MonoMethodMessage *msg;
6091 MonoArray *out_args;
6092 MonoObject *exc;
6093 MonoObject *arg;
6094 char* full_name;
6096 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6098 field_class = mono_class_from_mono_type (field->type);
6100 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6101 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6102 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6103 return;
6106 if (!setter) {
6107 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6108 g_assert (setter);
6111 if (field_class->valuetype)
6112 arg = mono_value_box (domain, field_class, val);
6113 else
6114 arg = *((MonoObject **)val);
6117 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6118 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6120 full_name = mono_type_get_full_name (klass);
6121 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6122 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6123 mono_array_setref (msg->args, 2, arg);
6124 g_free (full_name);
6126 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6128 if (exc) mono_raise_exception ((MonoException *)exc);
6132 * mono_store_remote_field_new:
6133 * @this:
6134 * @klass:
6135 * @field:
6136 * @arg:
6138 * Missing documentation
6140 void
6141 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6143 static MonoMethod *setter = NULL;
6144 MonoDomain *domain = mono_domain_get ();
6145 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6146 MonoClass *field_class;
6147 MonoMethodMessage *msg;
6148 MonoArray *out_args;
6149 MonoObject *exc;
6150 char* full_name;
6152 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6154 field_class = mono_class_from_mono_type (field->type);
6156 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6157 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6158 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6159 return;
6162 if (!setter) {
6163 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6164 g_assert (setter);
6167 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6168 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6170 full_name = mono_type_get_full_name (klass);
6171 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6172 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6173 mono_array_setref (msg->args, 2, arg);
6174 g_free (full_name);
6176 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6178 if (exc) mono_raise_exception ((MonoException *)exc);
6182 * mono_create_ftnptr:
6184 * Given a function address, create a function descriptor for it.
6185 * This is only needed on some platforms.
6187 gpointer
6188 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6190 return callbacks.create_ftnptr (domain, addr);
6194 * mono_get_addr_from_ftnptr:
6196 * Given a pointer to a function descriptor, return the function address.
6197 * This is only needed on some platforms.
6199 gpointer
6200 mono_get_addr_from_ftnptr (gpointer descr)
6202 return callbacks.get_addr_from_ftnptr (descr);
6206 * mono_string_chars:
6207 * @s: a MonoString
6209 * Returns a pointer to the UCS16 characters stored in the MonoString
6211 gunichar2 *
6212 mono_string_chars (MonoString *s)
6214 return s->chars;
6218 * mono_string_length:
6219 * @s: MonoString
6221 * Returns the lenght in characters of the string
6224 mono_string_length (MonoString *s)
6226 return s->length;
6230 * mono_array_length:
6231 * @array: a MonoArray*
6233 * Returns the total number of elements in the array. This works for
6234 * both vectors and multidimensional arrays.
6236 uintptr_t
6237 mono_array_length (MonoArray *array)
6239 return array->max_length;
6243 * mono_array_addr_with_size:
6244 * @array: a MonoArray*
6245 * @size: size of the array elements
6246 * @idx: index into the array
6248 * Returns the address of the @idx element in the array.
6250 char*
6251 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
6253 return ((char*)(array)->vector) + size * idx;