Add a write barrier before setting vtable->initalize to 1, since some places access...
[mono-project/dkf.git] / mono / metadata / object.c
blob17c28dd1e5e55d01e09a51f342f09a2fb71d7a92
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 static void
83 free_main_args (void);
85 static char *
86 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
89 #define ldstr_lock() EnterCriticalSection (&ldstr_section)
90 #define ldstr_unlock() LeaveCriticalSection (&ldstr_section)
91 static CRITICAL_SECTION ldstr_section;
93 static gboolean profile_allocs = TRUE;
95 void
96 mono_runtime_object_init (MonoObject *this)
98 MonoMethod *method = NULL;
99 MonoClass *klass = this->vtable->klass;
101 method = mono_class_get_method_from_name (klass, ".ctor", 0);
102 g_assert (method);
104 if (method->klass->valuetype)
105 this = mono_object_unbox (this);
106 mono_runtime_invoke (method, this, NULL, NULL);
109 /* The pseudo algorithm for type initialization from the spec
110 Note it doesn't say anything about domains - only threads.
112 2. If the type is initialized you are done.
113 2.1. If the type is not yet initialized, try to take an
114 initialization lock.
115 2.2. If successful, record this thread as responsible for
116 initializing the type and proceed to step 2.3.
117 2.2.1. If not, see whether this thread or any thread
118 waiting for this thread to complete already holds the lock.
119 2.2.2. If so, return since blocking would create a deadlock. This thread
120 will now see an incompletely initialized state for the type,
121 but no deadlock will arise.
122 2.2.3 If not, block until the type is initialized then return.
123 2.3 Initialize the parent type and then all interfaces implemented
124 by this type.
125 2.4 Execute the type initialization code for this type.
126 2.5 Mark the type as initialized, release the initialization lock,
127 awaken any threads waiting for this type to be initialized,
128 and return.
132 typedef struct
134 guint32 initializing_tid;
135 guint32 waiting_count;
136 gboolean done;
137 CRITICAL_SECTION initialization_section;
138 } TypeInitializationLock;
140 /* for locking access to type_initialization_hash and blocked_thread_hash */
141 #define mono_type_initialization_lock() EnterCriticalSection (&type_initialization_section)
142 #define mono_type_initialization_unlock() LeaveCriticalSection (&type_initialization_section)
143 static CRITICAL_SECTION type_initialization_section;
145 /* from vtable to lock */
146 static GHashTable *type_initialization_hash;
148 /* from thread id to thread id being waited on */
149 static GHashTable *blocked_thread_hash;
151 /* Main thread */
152 static MonoThread *main_thread;
154 /* Functions supplied by the runtime */
155 static MonoRuntimeCallbacks callbacks;
158 * mono_thread_set_main:
159 * @thread: thread to set as the main thread
161 * This function can be used to instruct the runtime to treat @thread
162 * as the main thread, ie, the thread that would normally execute the Main()
163 * method. This basically means that at the end of @thread, the runtime will
164 * wait for the existing foreground threads to quit and other such details.
166 void
167 mono_thread_set_main (MonoThread *thread)
169 static gboolean registered = FALSE;
171 if (!registered) {
172 MONO_GC_REGISTER_ROOT_SINGLE (main_thread);
173 registered = TRUE;
176 main_thread = thread;
179 MonoThread*
180 mono_thread_get_main (void)
182 return main_thread;
185 void
186 mono_type_initialization_init (void)
188 InitializeCriticalSection (&type_initialization_section);
189 type_initialization_hash = g_hash_table_new (NULL, NULL);
190 blocked_thread_hash = g_hash_table_new (NULL, NULL);
191 InitializeCriticalSection (&ldstr_section);
194 void
195 mono_type_initialization_cleanup (void)
197 #if 0
198 /* This is causing race conditions with
199 * mono_release_type_locks
201 DeleteCriticalSection (&type_initialization_section);
202 g_hash_table_destroy (type_initialization_hash);
203 type_initialization_hash = NULL;
204 #endif
205 DeleteCriticalSection (&ldstr_section);
206 g_hash_table_destroy (blocked_thread_hash);
207 blocked_thread_hash = NULL;
209 free_main_args ();
213 * get_type_init_exception_for_vtable:
215 * Return the stored type initialization exception for VTABLE.
217 static MonoException*
218 get_type_init_exception_for_vtable (MonoVTable *vtable)
220 MonoDomain *domain = vtable->domain;
221 MonoClass *klass = vtable->klass;
222 MonoException *ex;
223 gchar *full_name;
225 g_assert (vtable->init_failed);
228 * If the initializing thread was rudely aborted, the exception is not stored
229 * in the hash.
231 ex = NULL;
232 mono_domain_lock (domain);
233 if (domain->type_init_exception_hash)
234 ex = mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
235 mono_domain_unlock (domain);
237 if (!ex) {
238 if (klass->name_space && *klass->name_space)
239 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
240 else
241 full_name = g_strdup (klass->name);
242 ex = mono_get_exception_type_initialization (full_name, NULL);
243 g_free (full_name);
246 return ex;
249 * mono_runtime_class_init:
250 * @vtable: vtable that needs to be initialized
252 * This routine calls the class constructor for @vtable.
254 void
255 mono_runtime_class_init (MonoVTable *vtable)
257 mono_runtime_class_init_full (vtable, TRUE);
261 * mono_runtime_class_init_full:
262 * @vtable that neeeds to be initialized
263 * @raise_exception is TRUE, exceptions are raised intead of returned
266 MonoException *
267 mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
269 MonoException *exc;
270 MonoException *exc_to_throw;
271 MonoMethod *method = NULL;
272 MonoClass *klass;
273 gchar *full_name;
275 MONO_ARCH_SAVE_REGS;
277 if (vtable->initialized)
278 return NULL;
280 exc = NULL;
281 klass = vtable->klass;
283 if (!klass->image->checked_module_cctor) {
284 mono_image_check_for_module_cctor (klass->image);
285 if (klass->image->has_module_cctor) {
286 MonoClass *module_klass = mono_class_get (klass->image, MONO_TOKEN_TYPE_DEF | 1);
287 MonoVTable *module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception);
288 if (!module_vtable)
289 return NULL;
290 exc = mono_runtime_class_init_full (module_vtable, raise_exception);
291 if (exc)
292 return exc;
295 method = mono_class_get_cctor (klass);
297 if (method) {
298 MonoDomain *domain = vtable->domain;
299 TypeInitializationLock *lock;
300 guint32 tid = GetCurrentThreadId();
301 int do_initialization = 0;
302 MonoDomain *last_domain = NULL;
304 mono_type_initialization_lock ();
305 /* double check... */
306 if (vtable->initialized) {
307 mono_type_initialization_unlock ();
308 return NULL;
310 if (vtable->init_failed) {
311 mono_type_initialization_unlock ();
313 /* The type initialization already failed once, rethrow the same exception */
314 if (raise_exception)
315 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
316 return get_type_init_exception_for_vtable (vtable);
318 lock = g_hash_table_lookup (type_initialization_hash, vtable);
319 if (lock == NULL) {
320 /* This thread will get to do the initialization */
321 if (mono_domain_get () != domain) {
322 /* Transfer into the target domain */
323 last_domain = mono_domain_get ();
324 if (!mono_domain_set (domain, FALSE)) {
325 vtable->initialized = 1;
326 mono_type_initialization_unlock ();
327 if (raise_exception)
328 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
329 return mono_get_exception_appdomain_unloaded ();
332 lock = g_malloc (sizeof(TypeInitializationLock));
333 InitializeCriticalSection (&lock->initialization_section);
334 lock->initializing_tid = tid;
335 lock->waiting_count = 1;
336 lock->done = FALSE;
337 /* grab the vtable lock while this thread still owns type_initialization_section */
338 EnterCriticalSection (&lock->initialization_section);
339 g_hash_table_insert (type_initialization_hash, vtable, lock);
340 do_initialization = 1;
341 } else {
342 gpointer blocked;
343 TypeInitializationLock *pending_lock;
345 if (lock->initializing_tid == tid || lock->done) {
346 mono_type_initialization_unlock ();
347 return NULL;
349 /* see if the thread doing the initialization is already blocked on this thread */
350 blocked = GUINT_TO_POINTER (lock->initializing_tid);
351 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
352 if (pending_lock->initializing_tid == tid) {
353 if (!pending_lock->done) {
354 mono_type_initialization_unlock ();
355 return NULL;
356 } else {
357 /* the thread doing the initialization is blocked on this thread,
358 but on a lock that has already been freed. It just hasn't got
359 time to awake */
360 break;
363 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
365 ++lock->waiting_count;
366 /* record the fact that we are waiting on the initializing thread */
367 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
369 mono_type_initialization_unlock ();
371 if (do_initialization) {
372 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
374 /* If the initialization failed, mark the class as unusable. */
375 /* Avoid infinite loops */
376 if (!(exc == NULL ||
377 (klass->image == mono_defaults.corlib &&
378 !strcmp (klass->name_space, "System") &&
379 !strcmp (klass->name, "TypeInitializationException")))) {
380 vtable->init_failed = 1;
382 if (klass->name_space && *klass->name_space)
383 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
384 else
385 full_name = g_strdup (klass->name);
386 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
387 g_free (full_name);
390 * Store the exception object so it could be thrown on subsequent
391 * accesses.
393 mono_domain_lock (domain);
394 if (!domain->type_init_exception_hash)
395 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC);
396 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
397 mono_domain_unlock (domain);
400 if (last_domain)
401 mono_domain_set (last_domain, TRUE);
402 lock->done = TRUE;
403 LeaveCriticalSection (&lock->initialization_section);
404 } else {
405 /* this just blocks until the initializing thread is done */
406 EnterCriticalSection (&lock->initialization_section);
407 LeaveCriticalSection (&lock->initialization_section);
410 mono_type_initialization_lock ();
411 if (lock->initializing_tid != tid)
412 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
413 --lock->waiting_count;
414 if (lock->waiting_count == 0) {
415 DeleteCriticalSection (&lock->initialization_section);
416 g_hash_table_remove (type_initialization_hash, vtable);
417 g_free (lock);
419 mono_memory_barrier ();
420 if (!vtable->init_failed)
421 vtable->initialized = 1;
422 mono_type_initialization_unlock ();
424 if (vtable->init_failed) {
425 /* Either we were the initializing thread or we waited for the initialization */
426 if (raise_exception)
427 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
428 return get_type_init_exception_for_vtable (vtable);
430 } else {
431 vtable->initialized = 1;
432 return NULL;
434 return NULL;
437 static
438 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
440 MonoVTable *vtable = (MonoVTable*)key;
442 TypeInitializationLock *lock = (TypeInitializationLock*) value;
443 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
444 lock->done = TRUE;
446 * Have to set this since it cannot be set by the normal code in
447 * mono_runtime_class_init (). In this case, the exception object is not stored,
448 * and get_type_init_exception_for_class () needs to be aware of this.
450 vtable->init_failed = 1;
451 LeaveCriticalSection (&lock->initialization_section);
452 --lock->waiting_count;
453 if (lock->waiting_count == 0) {
454 DeleteCriticalSection (&lock->initialization_section);
455 g_free (lock);
456 return TRUE;
459 return FALSE;
462 void
463 mono_release_type_locks (MonoInternalThread *thread)
465 mono_type_initialization_lock ();
466 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
467 mono_type_initialization_unlock ();
470 static gpointer
471 default_trampoline (MonoMethod *method)
473 return method;
476 static gpointer
477 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
479 g_assert_not_reached ();
481 return NULL;
484 static gpointer
485 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
487 g_error ("remoting not installed");
488 return NULL;
491 static gpointer
492 default_delegate_trampoline (MonoClass *klass)
494 g_assert_not_reached ();
495 return NULL;
498 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
499 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
500 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
501 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
502 static MonoImtThunkBuilder imt_thunk_builder = NULL;
503 #define ARCH_USE_IMT (imt_thunk_builder != NULL)
504 #if (MONO_IMT_SIZE > 32)
505 #error "MONO_IMT_SIZE cannot be larger than 32"
506 #endif
508 void
509 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
511 memcpy (&callbacks, cbs, sizeof (*cbs));
514 MonoRuntimeCallbacks*
515 mono_get_runtime_callbacks (void)
517 return &callbacks;
520 void
521 mono_install_trampoline (MonoTrampoline func)
523 arch_create_jit_trampoline = func? func: default_trampoline;
526 void
527 mono_install_jump_trampoline (MonoJumpTrampoline func)
529 arch_create_jump_trampoline = func? func: default_jump_trampoline;
532 void
533 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
535 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
538 void
539 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
541 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
544 void
545 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
546 imt_thunk_builder = func;
549 static MonoCompileFunc default_mono_compile_method = NULL;
552 * mono_install_compile_method:
553 * @func: function to install
555 * This is a VM internal routine
557 void
558 mono_install_compile_method (MonoCompileFunc func)
560 default_mono_compile_method = func;
564 * mono_compile_method:
565 * @method: The method to compile.
567 * This JIT-compiles the method, and returns the pointer to the native code
568 * produced.
570 gpointer
571 mono_compile_method (MonoMethod *method)
573 if (!default_mono_compile_method) {
574 g_error ("compile method called on uninitialized runtime");
575 return NULL;
577 return default_mono_compile_method (method);
580 gpointer
581 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
583 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
586 gpointer
587 mono_runtime_create_delegate_trampoline (MonoClass *klass)
589 return arch_create_delegate_trampoline (klass);
592 static MonoFreeMethodFunc default_mono_free_method = NULL;
595 * mono_install_free_method:
596 * @func: pointer to the MonoFreeMethodFunc used to release a method
598 * This is an internal VM routine, it is used for the engines to
599 * register a handler to release the resources associated with a method.
601 * Methods are freed when no more references to the delegate that holds
602 * them are left.
604 void
605 mono_install_free_method (MonoFreeMethodFunc func)
607 default_mono_free_method = func;
611 * mono_runtime_free_method:
612 * @domain; domain where the method is hosted
613 * @method: method to release
615 * This routine is invoked to free the resources associated with
616 * a method that has been JIT compiled. This is used to discard
617 * methods that were used only temporarily (for example, used in marshalling)
620 void
621 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
623 if (default_mono_free_method != NULL)
624 default_mono_free_method (domain, method);
626 mono_method_clear_object (domain, method);
628 mono_free_method (method);
632 * The vtables in the root appdomain are assumed to be reachable by other
633 * roots, and we don't use typed allocation in the other domains.
636 /* The sync block is no longer a GC pointer */
637 #define GC_HEADER_BITMAP (0)
639 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
641 static gsize*
642 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
644 MonoClassField *field;
645 MonoClass *p;
646 guint32 pos;
647 int max_size;
649 if (static_fields)
650 max_size = mono_class_data_size (class) / sizeof (gpointer);
651 else
652 max_size = class->instance_size / sizeof (gpointer);
653 if (max_size > size) {
654 g_assert (offset <= 0);
655 bitmap = g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
656 size = max_size;
659 #ifdef HAVE_SGEN_GC
660 /*An Ephemeron cannot be marked by sgen*/
661 if (!static_fields && class->image == mono_defaults.corlib && !strcmp ("Ephemeron", class->name)) {
662 *max_set = 0;
663 memset (bitmap, 0, size / 8);
664 return bitmap;
666 #endif
668 for (p = class; p != NULL; p = p->parent) {
669 gpointer iter = NULL;
670 while ((field = mono_class_get_fields (p, &iter))) {
671 MonoType *type;
673 if (static_fields) {
674 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
675 continue;
676 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
677 continue;
678 } else {
679 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
680 continue;
682 /* FIXME: should not happen, flag as type load error */
683 if (field->type->byref)
684 break;
686 if (static_fields && field->offset == -1)
687 /* special static */
688 continue;
690 pos = field->offset / sizeof (gpointer);
691 pos += offset;
693 type = mono_type_get_underlying_type (field->type);
694 switch (type->type) {
695 case MONO_TYPE_I:
696 case MONO_TYPE_PTR:
697 case MONO_TYPE_FNPTR:
698 break;
699 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
700 case MONO_TYPE_U:
701 #ifdef HAVE_SGEN_GC
702 break;
703 #else
704 if (class->image != mono_defaults.corlib)
705 break;
706 #endif
707 case MONO_TYPE_STRING:
708 case MONO_TYPE_SZARRAY:
709 case MONO_TYPE_CLASS:
710 case MONO_TYPE_OBJECT:
711 case MONO_TYPE_ARRAY:
712 g_assert ((field->offset % sizeof(gpointer)) == 0);
714 g_assert (pos < size || pos <= max_size);
715 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
716 *max_set = MAX (*max_set, pos);
717 break;
718 case MONO_TYPE_GENERICINST:
719 if (!mono_type_generic_inst_is_valuetype (type)) {
720 g_assert ((field->offset % sizeof(gpointer)) == 0);
722 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
723 *max_set = MAX (*max_set, pos);
724 break;
725 } else {
726 /* fall through */
728 case MONO_TYPE_VALUETYPE: {
729 MonoClass *fclass = mono_class_from_mono_type (field->type);
730 if (fclass->has_references) {
731 /* remove the object header */
732 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
734 break;
736 case MONO_TYPE_I1:
737 case MONO_TYPE_U1:
738 case MONO_TYPE_I2:
739 case MONO_TYPE_U2:
740 case MONO_TYPE_I4:
741 case MONO_TYPE_U4:
742 case MONO_TYPE_I8:
743 case MONO_TYPE_U8:
744 case MONO_TYPE_R4:
745 case MONO_TYPE_R8:
746 case MONO_TYPE_BOOLEAN:
747 case MONO_TYPE_CHAR:
748 break;
749 default:
750 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
751 break;
754 if (static_fields)
755 break;
757 return bitmap;
761 * mono_class_compute_bitmap:
763 * Mono internal function to compute a bitmap of reference fields in a class.
765 gsize*
766 mono_class_compute_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
768 return compute_class_bitmap (class, bitmap, size, offset, max_set, static_fields);
771 #if 0
773 * similar to the above, but sets the bits in the bitmap for any non-ref field
774 * and ignores static fields
776 static gsize*
777 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
779 MonoClassField *field;
780 MonoClass *p;
781 guint32 pos, pos2;
782 int max_size;
784 max_size = class->instance_size / sizeof (gpointer);
785 if (max_size >= size) {
786 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
789 for (p = class; p != NULL; p = p->parent) {
790 gpointer iter = NULL;
791 while ((field = mono_class_get_fields (p, &iter))) {
792 MonoType *type;
794 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
795 continue;
796 /* FIXME: should not happen, flag as type load error */
797 if (field->type->byref)
798 break;
800 pos = field->offset / sizeof (gpointer);
801 pos += offset;
803 type = mono_type_get_underlying_type (field->type);
804 switch (type->type) {
805 #if SIZEOF_VOID_P == 8
806 case MONO_TYPE_I:
807 case MONO_TYPE_U:
808 case MONO_TYPE_PTR:
809 case MONO_TYPE_FNPTR:
810 #endif
811 case MONO_TYPE_I8:
812 case MONO_TYPE_U8:
813 case MONO_TYPE_R8:
814 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
815 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
816 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
818 /* fall through */
819 #if SIZEOF_VOID_P == 4
820 case MONO_TYPE_I:
821 case MONO_TYPE_U:
822 case MONO_TYPE_PTR:
823 case MONO_TYPE_FNPTR:
824 #endif
825 case MONO_TYPE_I4:
826 case MONO_TYPE_U4:
827 case MONO_TYPE_R4:
828 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
829 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
830 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
832 /* fall through */
833 case MONO_TYPE_CHAR:
834 case MONO_TYPE_I2:
835 case MONO_TYPE_U2:
836 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
837 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
838 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
840 /* fall through */
841 case MONO_TYPE_BOOLEAN:
842 case MONO_TYPE_I1:
843 case MONO_TYPE_U1:
844 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
845 break;
846 case MONO_TYPE_STRING:
847 case MONO_TYPE_SZARRAY:
848 case MONO_TYPE_CLASS:
849 case MONO_TYPE_OBJECT:
850 case MONO_TYPE_ARRAY:
851 break;
852 case MONO_TYPE_GENERICINST:
853 if (!mono_type_generic_inst_is_valuetype (type)) {
854 break;
855 } else {
856 /* fall through */
858 case MONO_TYPE_VALUETYPE: {
859 MonoClass *fclass = mono_class_from_mono_type (field->type);
860 /* remove the object header */
861 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
862 break;
864 default:
865 g_assert_not_reached ();
866 break;
870 return bitmap;
874 * mono_class_insecure_overlapping:
875 * check if a class with explicit layout has references and non-references
876 * fields overlapping.
878 * Returns: TRUE if it is insecure to load the type.
880 gboolean
881 mono_class_insecure_overlapping (MonoClass *klass)
883 int max_set = 0;
884 gsize *bitmap;
885 gsize default_bitmap [4] = {0};
886 gsize *nrbitmap;
887 gsize default_nrbitmap [4] = {0};
888 int i, insecure = FALSE;
889 return FALSE;
891 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
892 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
894 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
895 int idx = i % (sizeof (bitmap [0]) * 8);
896 if (bitmap [idx] & nrbitmap [idx]) {
897 insecure = TRUE;
898 break;
901 if (bitmap != default_bitmap)
902 g_free (bitmap);
903 if (nrbitmap != default_nrbitmap)
904 g_free (nrbitmap);
905 if (insecure) {
906 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
907 return FALSE;
909 return insecure;
911 #endif
913 MonoString*
914 mono_string_alloc (int length)
916 return mono_string_new_size (mono_domain_get (), length);
919 void
920 mono_class_compute_gc_descriptor (MonoClass *class)
922 int max_set = 0;
923 gsize *bitmap;
924 gsize default_bitmap [4] = {0};
925 static gboolean gcj_inited = FALSE;
927 if (!gcj_inited) {
928 mono_loader_lock ();
930 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
931 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
932 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
933 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
935 #ifdef HAVE_GC_GCJ_MALLOC
937 * This is not needed unless the relevant code in mono_get_allocation_ftn () is
938 * turned on.
940 #if 0
941 #ifdef GC_REDIRECT_TO_LOCAL
942 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
943 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
944 #endif
945 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
946 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
947 #endif
949 #endif
950 gcj_inited = TRUE;
951 mono_loader_unlock ();
954 if (!class->inited)
955 mono_class_init (class);
957 if (class->gc_descr_inited)
958 return;
960 class->gc_descr_inited = TRUE;
961 class->gc_descr = GC_NO_DESCRIPTOR;
963 bitmap = default_bitmap;
964 if (class == mono_defaults.string_class) {
965 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
966 } else if (class->rank) {
967 mono_class_compute_gc_descriptor (class->element_class);
968 if (!class->element_class->valuetype) {
969 gsize abm = 1;
970 class->gc_descr = mono_gc_make_descr_for_array (TRUE, &abm, 1, sizeof (gpointer));
971 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
972 class->name_space, class->name);*/
973 } else {
974 /* remove the object header */
975 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
976 class->gc_descr = mono_gc_make_descr_for_array (TRUE, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
977 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
978 class->name_space, class->name);*/
979 if (bitmap != default_bitmap)
980 g_free (bitmap);
982 } else {
983 /*static int count = 0;
984 if (count++ > 58)
985 return;*/
986 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
987 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
989 if (class->gc_descr == GC_NO_DESCRIPTOR)
990 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
992 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
993 if (bitmap != default_bitmap)
994 g_free (bitmap);
999 * field_is_special_static:
1000 * @fklass: The MonoClass to look up.
1001 * @field: The MonoClassField describing the field.
1003 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1004 * SPECIAL_STATIC_NONE otherwise.
1006 static gint32
1007 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1009 MonoCustomAttrInfo *ainfo;
1010 int i;
1011 ainfo = mono_custom_attrs_from_field (fklass, field);
1012 if (!ainfo)
1013 return FALSE;
1014 for (i = 0; i < ainfo->num_attrs; ++i) {
1015 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1016 if (klass->image == mono_defaults.corlib) {
1017 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1018 mono_custom_attrs_free (ainfo);
1019 return SPECIAL_STATIC_THREAD;
1021 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1022 mono_custom_attrs_free (ainfo);
1023 return SPECIAL_STATIC_CONTEXT;
1027 mono_custom_attrs_free (ainfo);
1028 return SPECIAL_STATIC_NONE;
1031 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1032 #define mix(a,b,c) { \
1033 a -= c; a ^= rot(c, 4); c += b; \
1034 b -= a; b ^= rot(a, 6); a += c; \
1035 c -= b; c ^= rot(b, 8); b += a; \
1036 a -= c; a ^= rot(c,16); c += b; \
1037 b -= a; b ^= rot(a,19); a += c; \
1038 c -= b; c ^= rot(b, 4); b += a; \
1040 #define final(a,b,c) { \
1041 c ^= b; c -= rot(b,14); \
1042 a ^= c; a -= rot(c,11); \
1043 b ^= a; b -= rot(a,25); \
1044 c ^= b; c -= rot(b,16); \
1045 a ^= c; a -= rot(c,4); \
1046 b ^= a; b -= rot(a,14); \
1047 c ^= b; c -= rot(b,24); \
1051 * mono_method_get_imt_slot:
1053 * The IMT slot is embedded into AOTed code, so this must return the same value
1054 * for the same method across all executions. This means:
1055 * - pointers shouldn't be used as hash values.
1056 * - mono_metadata_str_hash () should be used for hashing strings.
1058 guint32
1059 mono_method_get_imt_slot (MonoMethod *method)
1061 MonoMethodSignature *sig;
1062 int hashes_count;
1063 guint32 *hashes_start, *hashes;
1064 guint32 a, b, c;
1065 int i;
1067 /* This can be used to stress tests the collision code */
1068 //return 0;
1071 * We do this to simplify generic sharing. It will hurt
1072 * performance in cases where a class implements two different
1073 * instantiations of the same generic interface.
1074 * The code in build_imt_slots () depends on this.
1076 if (method->is_inflated)
1077 method = ((MonoMethodInflated*)method)->declaring;
1079 sig = mono_method_signature (method);
1080 hashes_count = sig->param_count + 4;
1081 hashes_start = malloc (hashes_count * sizeof (guint32));
1082 hashes = hashes_start;
1084 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1085 printf ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod\n",
1086 method->klass->name_space, method->klass->name, method->name);
1087 g_assert_not_reached ();
1090 /* Initialize hashes */
1091 hashes [0] = mono_metadata_str_hash (method->klass->name);
1092 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1093 hashes [2] = mono_metadata_str_hash (method->name);
1094 hashes [3] = mono_metadata_type_hash (sig->ret);
1095 for (i = 0; i < sig->param_count; i++) {
1096 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1099 /* Setup internal state */
1100 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1102 /* Handle most of the hashes */
1103 while (hashes_count > 3) {
1104 a += hashes [0];
1105 b += hashes [1];
1106 c += hashes [2];
1107 mix (a,b,c);
1108 hashes_count -= 3;
1109 hashes += 3;
1112 /* Handle the last 3 hashes (all the case statements fall through) */
1113 switch (hashes_count) {
1114 case 3 : c += hashes [2];
1115 case 2 : b += hashes [1];
1116 case 1 : a += hashes [0];
1117 final (a,b,c);
1118 case 0: /* nothing left to add */
1119 break;
1122 free (hashes_start);
1123 /* Report the result */
1124 return c % MONO_IMT_SIZE;
1126 #undef rot
1127 #undef mix
1128 #undef final
1130 #define DEBUG_IMT 0
1132 static void
1133 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1134 guint32 imt_slot = mono_method_get_imt_slot (method);
1135 MonoImtBuilderEntry *entry;
1137 if (slot_num >= 0 && imt_slot != slot_num) {
1138 /* we build just a single imt slot and this is not it */
1139 return;
1142 entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
1143 entry->key = method;
1144 entry->value.vtable_slot = vtable_slot;
1145 entry->next = imt_builder [imt_slot];
1146 if (imt_builder [imt_slot] != NULL) {
1147 entry->children = imt_builder [imt_slot]->children + 1;
1148 if (entry->children == 1) {
1149 mono_stats.imt_slots_with_collisions++;
1150 *imt_collisions_bitmap |= (1 << imt_slot);
1152 } else {
1153 entry->children = 0;
1154 mono_stats.imt_used_slots++;
1156 imt_builder [imt_slot] = entry;
1157 #if DEBUG_IMT
1159 char *method_name = mono_method_full_name (method, TRUE);
1160 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1161 method, method_name, imt_slot, vtable_slot, entry->children);
1162 g_free (method_name);
1164 #endif
1167 #if DEBUG_IMT
1168 static void
1169 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1170 if (e != NULL) {
1171 MonoMethod *method = e->key;
1172 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1173 message,
1174 num,
1175 method,
1176 method->klass->name_space,
1177 method->klass->name,
1178 method->name);
1179 } else {
1180 printf (" * %s: NULL\n", message);
1183 #endif
1185 static int
1186 compare_imt_builder_entries (const void *p1, const void *p2) {
1187 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1188 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1190 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1193 static int
1194 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1196 int count = end - start;
1197 int chunk_start = out_array->len;
1198 if (count < 4) {
1199 int i;
1200 for (i = start; i < end; ++i) {
1201 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1202 item->key = sorted_array [i]->key;
1203 item->value = sorted_array [i]->value;
1204 item->has_target_code = sorted_array [i]->has_target_code;
1205 item->is_equals = TRUE;
1206 if (i < end - 1)
1207 item->check_target_idx = out_array->len + 1;
1208 else
1209 item->check_target_idx = 0;
1210 g_ptr_array_add (out_array, item);
1212 } else {
1213 int middle = start + count / 2;
1214 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1216 item->key = sorted_array [middle]->key;
1217 item->is_equals = FALSE;
1218 g_ptr_array_add (out_array, item);
1219 imt_emit_ir (sorted_array, start, middle, out_array);
1220 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1222 return chunk_start;
1225 static GPtrArray*
1226 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1227 int number_of_entries = entries->children + 1;
1228 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1229 GPtrArray *result = g_ptr_array_new ();
1230 MonoImtBuilderEntry *current_entry;
1231 int i;
1233 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1234 sorted_array [i] = current_entry;
1236 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1238 /*for (i = 0; i < number_of_entries; i++) {
1239 print_imt_entry (" sorted array:", sorted_array [i], i);
1242 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1244 free (sorted_array);
1245 return result;
1248 static gpointer
1249 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1251 if (imt_builder_entry != NULL) {
1252 if (imt_builder_entry->children == 0 && !fail_tramp) {
1253 /* No collision, return the vtable slot contents */
1254 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1255 } else {
1256 /* Collision, build the thunk */
1257 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1258 gpointer result;
1259 int i;
1260 result = imt_thunk_builder (vtable, domain,
1261 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1262 for (i = 0; i < imt_ir->len; ++i)
1263 g_free (g_ptr_array_index (imt_ir, i));
1264 g_ptr_array_free (imt_ir, TRUE);
1265 return result;
1267 } else {
1268 if (fail_tramp)
1269 return fail_tramp;
1270 else
1271 /* Empty slot */
1272 return NULL;
1276 static MonoImtBuilderEntry*
1277 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1280 * LOCKING: requires the loader and domain locks.
1283 static void
1284 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1286 int i;
1287 GSList *list_item;
1288 guint32 imt_collisions_bitmap = 0;
1289 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1290 int method_count = 0;
1291 gboolean record_method_count_for_max_collisions = FALSE;
1292 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1294 #if DEBUG_IMT
1295 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1296 #endif
1297 for (i = 0; i < klass->interface_offsets_count; ++i) {
1298 MonoClass *iface = klass->interfaces_packed [i];
1299 int interface_offset = klass->interface_offsets_packed [i];
1300 int method_slot_in_interface, vt_slot;
1302 if (mono_class_has_variant_generic_params (iface))
1303 has_variant_iface = TRUE;
1305 vt_slot = interface_offset;
1306 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1307 MonoMethod *method;
1309 if (slot_num >= 0 && iface->is_inflated) {
1311 * The imt slot of the method is the same as for its declaring method,
1312 * see the comment in mono_method_get_imt_slot (), so we can
1313 * avoid inflating methods which will be discarded by
1314 * add_imt_builder_entry anyway.
1316 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1317 if (mono_method_get_imt_slot (method) != slot_num) {
1318 vt_slot ++;
1319 continue;
1322 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1323 if (method->is_generic) {
1324 has_generic_virtual = TRUE;
1325 vt_slot ++;
1326 continue;
1329 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1330 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1331 vt_slot ++;
1335 if (extra_interfaces) {
1336 int interface_offset = klass->vtable_size;
1338 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1339 MonoClass* iface = list_item->data;
1340 int method_slot_in_interface;
1341 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1342 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1343 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1345 interface_offset += iface->method.count;
1348 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1349 /* overwrite the imt slot only if we're building all the entries or if
1350 * we're building this specific one
1352 if (slot_num < 0 || i == slot_num) {
1353 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1355 if (entries) {
1356 if (imt_builder [i]) {
1357 MonoImtBuilderEntry *entry;
1359 /* Link entries with imt_builder [i] */
1360 for (entry = entries; entry->next; entry = entry->next) {
1361 #if DEBUG_IMT
1362 MonoMethod *method = (MonoMethod*)entry->key;
1363 char *method_name = mono_method_full_name (method, TRUE);
1364 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1365 g_free (method_name);
1366 #endif
1368 entry->next = imt_builder [i];
1369 entries->children += imt_builder [i]->children + 1;
1371 imt_builder [i] = entries;
1374 if (has_generic_virtual || has_variant_iface) {
1376 * There might be collisions later when the the thunk is expanded.
1378 imt_collisions_bitmap |= (1 << i);
1381 * The IMT thunk might be called with an instance of one of the
1382 * generic virtual methods, so has to fallback to the IMT trampoline.
1384 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline ? callbacks.get_imt_trampoline (i) : NULL);
1385 } else {
1386 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1388 #if DEBUG_IMT
1389 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1390 #endif
1393 if (imt_builder [i] != NULL) {
1394 int methods_in_slot = imt_builder [i]->children + 1;
1395 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1396 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1397 record_method_count_for_max_collisions = TRUE;
1399 method_count += methods_in_slot;
1403 mono_stats.imt_number_of_methods += method_count;
1404 if (record_method_count_for_max_collisions) {
1405 mono_stats.imt_method_count_when_max_collisions = method_count;
1408 for (i = 0; i < MONO_IMT_SIZE; i++) {
1409 MonoImtBuilderEntry* entry = imt_builder [i];
1410 while (entry != NULL) {
1411 MonoImtBuilderEntry* next = entry->next;
1412 g_free (entry);
1413 entry = next;
1416 free (imt_builder);
1417 /* we OR the bitmap since we may build just a single imt slot at a time */
1418 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1421 static void
1422 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1423 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1427 * mono_vtable_build_imt_slot:
1428 * @vtable: virtual object table struct
1429 * @imt_slot: slot in the IMT table
1431 * Fill the given @imt_slot in the IMT table of @vtable with
1432 * a trampoline or a thunk for the case of collisions.
1433 * This is part of the internal mono API.
1435 * LOCKING: Take the domain lock.
1437 void
1438 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1440 gpointer *imt = (gpointer*)vtable;
1441 imt -= MONO_IMT_SIZE;
1442 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1444 /* no support for extra interfaces: the proxy objects will need
1445 * to build the complete IMT
1446 * Update and heck needs to ahppen inside the proper domain lock, as all
1447 * the changes made to a MonoVTable.
1449 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1450 mono_domain_lock (vtable->domain);
1451 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1452 if (imt [imt_slot] == callbacks.get_imt_trampoline (imt_slot))
1453 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1454 mono_domain_unlock (vtable->domain);
1455 mono_loader_unlock ();
1460 * The first two free list entries both belong to the wait list: The
1461 * first entry is the pointer to the head of the list and the second
1462 * entry points to the last element. That way appending and removing
1463 * the first element are both O(1) operations.
1465 #ifdef MONO_SMALL_CONFIG
1466 #define NUM_FREE_LISTS 6
1467 #else
1468 #define NUM_FREE_LISTS 12
1469 #endif
1470 #define FIRST_FREE_LIST_SIZE 64
1471 #define MAX_WAIT_LENGTH 50
1472 #define THUNK_THRESHOLD 10
1475 * LOCKING: The domain lock must be held.
1477 static void
1478 init_thunk_free_lists (MonoDomain *domain)
1480 if (domain->thunk_free_lists)
1481 return;
1482 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1485 static int
1486 list_index_for_size (int item_size)
1488 int i = 2;
1489 int size = FIRST_FREE_LIST_SIZE;
1491 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1492 i++;
1493 size <<= 1;
1496 return i;
1500 * mono_method_alloc_generic_virtual_thunk:
1501 * @domain: a domain
1502 * @size: size in bytes
1504 * Allocs size bytes to be used for the code of a generic virtual
1505 * thunk. It's either allocated from the domain's code manager or
1506 * reused from a previously invalidated piece.
1508 * LOCKING: The domain lock must be held.
1510 gpointer
1511 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1513 static gboolean inited = FALSE;
1514 static int generic_virtual_thunks_size = 0;
1516 guint32 *p;
1517 int i;
1518 MonoThunkFreeList **l;
1520 init_thunk_free_lists (domain);
1522 size += sizeof (guint32);
1523 if (size < sizeof (MonoThunkFreeList))
1524 size = sizeof (MonoThunkFreeList);
1526 i = list_index_for_size (size);
1527 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1528 if ((*l)->size >= size) {
1529 MonoThunkFreeList *item = *l;
1530 *l = item->next;
1531 return ((guint32*)item) + 1;
1535 /* no suitable item found - search lists of larger sizes */
1536 while (++i < NUM_FREE_LISTS) {
1537 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1538 if (!item)
1539 continue;
1540 g_assert (item->size > size);
1541 domain->thunk_free_lists [i] = item->next;
1542 return ((guint32*)item) + 1;
1545 /* still nothing found - allocate it */
1546 if (!inited) {
1547 mono_counters_register ("Generic virtual thunk bytes",
1548 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1549 inited = TRUE;
1551 generic_virtual_thunks_size += size;
1553 p = mono_domain_code_reserve (domain, size);
1554 *p = size;
1556 mono_domain_lock (domain);
1557 if (!domain->generic_virtual_thunks)
1558 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1559 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1560 mono_domain_unlock (domain);
1562 return p + 1;
1566 * LOCKING: The domain lock must be held.
1568 static void
1569 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1571 guint32 *p = code;
1572 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1573 gboolean found = FALSE;
1575 mono_domain_lock (domain);
1576 if (!domain->generic_virtual_thunks)
1577 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1578 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1579 found = TRUE;
1580 mono_domain_unlock (domain);
1582 if (!found)
1583 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1584 return;
1585 init_thunk_free_lists (domain);
1587 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1588 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1589 int length = item->length;
1590 int i;
1592 /* unlink the first item from the wait list */
1593 domain->thunk_free_lists [0] = item->next;
1594 domain->thunk_free_lists [0]->length = length - 1;
1596 i = list_index_for_size (item->size);
1598 /* put it in the free list */
1599 item->next = domain->thunk_free_lists [i];
1600 domain->thunk_free_lists [i] = item;
1603 l->next = NULL;
1604 if (domain->thunk_free_lists [1]) {
1605 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1606 domain->thunk_free_lists [0]->length++;
1607 } else {
1608 g_assert (!domain->thunk_free_lists [0]);
1610 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1611 domain->thunk_free_lists [0]->length = 1;
1615 typedef struct _GenericVirtualCase {
1616 MonoMethod *method;
1617 gpointer code;
1618 int count;
1619 struct _GenericVirtualCase *next;
1620 } GenericVirtualCase;
1623 * get_generic_virtual_entries:
1625 * Return IMT entries for the generic virtual method instances and
1626 * variant interface methods for vtable slot
1627 * VTABLE_SLOT.
1629 static MonoImtBuilderEntry*
1630 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1632 GenericVirtualCase *list;
1633 MonoImtBuilderEntry *entries;
1635 mono_domain_lock (domain);
1636 if (!domain->generic_virtual_cases)
1637 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1639 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1641 entries = NULL;
1642 for (; list; list = list->next) {
1643 MonoImtBuilderEntry *entry;
1645 if (list->count < THUNK_THRESHOLD)
1646 continue;
1648 entry = g_new0 (MonoImtBuilderEntry, 1);
1649 entry->key = list->method;
1650 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1651 entry->has_target_code = 1;
1652 if (entries)
1653 entry->children = entries->children + 1;
1654 entry->next = entries;
1655 entries = entry;
1658 mono_domain_unlock (domain);
1660 /* FIXME: Leaking memory ? */
1661 return entries;
1665 * mono_method_add_generic_virtual_invocation:
1666 * @domain: a domain
1667 * @vtable_slot: pointer to the vtable slot
1668 * @method: the inflated generic virtual method
1669 * @code: the method's code
1671 * Registers a call via unmanaged code to a generic virtual method
1672 * instantiation or variant interface method. If the number of calls reaches a threshold
1673 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1674 * virtual method thunk.
1676 void
1677 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1678 gpointer *vtable_slot,
1679 MonoMethod *method, gpointer code)
1681 static gboolean inited = FALSE;
1682 static int num_added = 0;
1684 GenericVirtualCase *gvc, *list;
1685 MonoImtBuilderEntry *entries;
1686 int i;
1687 GPtrArray *sorted;
1689 mono_domain_lock (domain);
1690 if (!domain->generic_virtual_cases)
1691 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1693 /* Check whether the case was already added */
1694 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1695 gvc = list;
1696 while (gvc) {
1697 if (gvc->method == method)
1698 break;
1699 gvc = gvc->next;
1702 /* If not found, make a new one */
1703 if (!gvc) {
1704 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1705 gvc->method = method;
1706 gvc->code = code;
1707 gvc->count = 0;
1708 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1710 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1712 if (!inited) {
1713 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1714 inited = TRUE;
1716 num_added++;
1719 if (++gvc->count == THUNK_THRESHOLD) {
1720 gpointer *old_thunk = *vtable_slot;
1721 gpointer vtable_trampoline = NULL;
1722 gpointer imt_trampoline = NULL;
1724 if ((gpointer)vtable_slot < (gpointer)vtable) {
1725 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1726 int imt_slot = MONO_IMT_SIZE + displacement;
1728 /* Force the rebuild of the thunk at the next call */
1729 imt_trampoline = callbacks.get_imt_trampoline (imt_slot);
1730 *vtable_slot = imt_trampoline;
1731 } else {
1732 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline ((gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1734 entries = get_generic_virtual_entries (domain, vtable_slot);
1736 sorted = imt_sort_slot_entries (entries);
1738 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1739 vtable_trampoline);
1741 while (entries) {
1742 MonoImtBuilderEntry *next = entries->next;
1743 g_free (entries);
1744 entries = next;
1747 for (i = 0; i < sorted->len; ++i)
1748 g_free (g_ptr_array_index (sorted, i));
1749 g_ptr_array_free (sorted, TRUE);
1752 #ifndef __native_client__
1753 /* We don't re-use any thunks as there is a lot of overhead */
1754 /* to deleting and re-using code in Native Client. */
1755 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1756 invalidate_generic_virtual_thunk (domain, old_thunk);
1757 #endif
1760 mono_domain_unlock (domain);
1763 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error);
1766 * mono_class_vtable:
1767 * @domain: the application domain
1768 * @class: the class to initialize
1770 * VTables are domain specific because we create domain specific code, and
1771 * they contain the domain specific static class data.
1772 * On failure, NULL is returned, and class->exception_type is set.
1774 MonoVTable *
1775 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1777 return mono_class_vtable_full (domain, class, FALSE);
1781 * mono_class_vtable_full:
1782 * @domain: the application domain
1783 * @class: the class to initialize
1784 * @raise_on_error if an exception should be raised on failure or not
1786 * VTables are domain specific because we create domain specific code, and
1787 * they contain the domain specific static class data.
1789 MonoVTable *
1790 mono_class_vtable_full (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1792 MonoClassRuntimeInfo *runtime_info;
1794 g_assert (class);
1796 if (class->exception_type) {
1797 if (raise_on_error)
1798 mono_raise_exception (mono_class_get_exception_for_failure (class));
1799 return NULL;
1802 /* this check can be inlined in jitted code, too */
1803 runtime_info = class->runtime_info;
1804 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1805 return runtime_info->domain_vtables [domain->domain_id];
1806 return mono_class_create_runtime_vtable (domain, class, raise_on_error);
1810 * mono_class_try_get_vtable:
1811 * @domain: the application domain
1812 * @class: the class to initialize
1814 * This function tries to get the associated vtable from @class if
1815 * it was already created.
1817 MonoVTable *
1818 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1820 MonoClassRuntimeInfo *runtime_info;
1822 g_assert (class);
1824 runtime_info = class->runtime_info;
1825 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1826 return runtime_info->domain_vtables [domain->domain_id];
1827 return NULL;
1830 static MonoVTable *
1831 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1833 MonoVTable *vt;
1834 MonoClassRuntimeInfo *runtime_info, *old_info;
1835 MonoClassField *field;
1836 char *t;
1837 int i;
1838 int imt_table_bytes = 0;
1839 guint32 vtable_size, class_size;
1840 guint32 cindex;
1841 gpointer iter;
1842 gpointer *interface_offsets;
1844 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1845 mono_domain_lock (domain);
1846 runtime_info = class->runtime_info;
1847 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1848 mono_domain_unlock (domain);
1849 mono_loader_unlock ();
1850 return runtime_info->domain_vtables [domain->domain_id];
1852 if (!class->inited || class->exception_type) {
1853 if (!mono_class_init (class) || class->exception_type) {
1854 mono_domain_unlock (domain);
1855 mono_loader_unlock ();
1856 if (raise_on_error)
1857 mono_raise_exception (mono_class_get_exception_for_failure (class));
1858 return NULL;
1862 /* Array types require that their element type be valid*/
1863 if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
1864 MonoClass *element_class = class->element_class;
1865 if (!element_class->inited)
1866 mono_class_init (element_class);
1868 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1869 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1870 mono_class_setup_vtable (element_class);
1872 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1873 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1874 if (class->exception_type == MONO_EXCEPTION_NONE)
1875 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1876 mono_domain_unlock (domain);
1877 mono_loader_unlock ();
1878 if (raise_on_error)
1879 mono_raise_exception (mono_class_get_exception_for_failure (class));
1880 return NULL;
1885 * For some classes, mono_class_init () already computed class->vtable_size, and
1886 * that is all that is needed because of the vtable trampolines.
1888 if (!class->vtable_size)
1889 mono_class_setup_vtable (class);
1891 if (class->generic_class && !class->vtable)
1892 mono_class_check_vtable_constraints (class, NULL);
1894 /* Initialize klass->has_finalize */
1895 mono_class_has_finalizer (class);
1897 if (class->exception_type) {
1898 mono_domain_unlock (domain);
1899 mono_loader_unlock ();
1900 if (raise_on_error)
1901 mono_raise_exception (mono_class_get_exception_for_failure (class));
1902 return NULL;
1905 if (ARCH_USE_IMT) {
1906 vtable_size = MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1907 if (class->interface_offsets_count) {
1908 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1909 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1910 mono_stats.imt_number_of_tables++;
1911 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1913 } else {
1914 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1915 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1918 mono_stats.used_class_count++;
1919 mono_stats.class_vtable_size += vtable_size;
1920 interface_offsets = mono_domain_alloc0 (domain, vtable_size);
1922 if (ARCH_USE_IMT)
1923 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1924 else
1925 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1926 vt->klass = class;
1927 vt->rank = class->rank;
1928 vt->domain = domain;
1930 mono_class_compute_gc_descriptor (class);
1932 * We can't use typed allocation in the non-root domains, since the
1933 * collector needs the GC descriptor stored in the vtable even after
1934 * the mempool containing the vtable is destroyed when the domain is
1935 * unloaded. An alternative might be to allocate vtables in the GC
1936 * heap, but this does not seem to work (it leads to crashes inside
1937 * libgc). If that approach is tried, two gc descriptors need to be
1938 * allocated for each class: one for the root domain, and one for all
1939 * other domains. The second descriptor should contain a bit for the
1940 * vtable field in MonoObject, since we can no longer assume the
1941 * vtable is reachable by other roots after the appdomain is unloaded.
1943 #ifdef HAVE_BOEHM_GC
1944 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1945 vt->gc_descr = GC_NO_DESCRIPTOR;
1946 else
1947 #endif
1948 vt->gc_descr = class->gc_descr;
1950 if ((class_size = mono_class_data_size (class))) {
1951 if (class->has_static_refs) {
1952 gpointer statics_gc_descr;
1953 int max_set = 0;
1954 gsize default_bitmap [4] = {0};
1955 gsize *bitmap;
1957 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1958 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1959 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1960 vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1961 mono_domain_add_class_static_data (domain, class, vt->data, NULL);
1962 if (bitmap != default_bitmap)
1963 g_free (bitmap);
1964 } else {
1965 vt->data = mono_domain_alloc0 (domain, class_size);
1967 mono_stats.class_static_data_size += class_size;
1970 cindex = -1;
1971 iter = NULL;
1972 while ((field = mono_class_get_fields (class, &iter))) {
1973 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1974 continue;
1975 if (mono_field_is_deleted (field))
1976 continue;
1977 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1978 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1979 if (special_static != SPECIAL_STATIC_NONE) {
1980 guint32 size, offset;
1981 gint32 align;
1982 gsize default_bitmap [4] = {0};
1983 gsize *bitmap;
1984 int max_set = 0;
1985 MonoClass *fclass;
1986 if (mono_type_is_reference (field->type)) {
1987 default_bitmap [0] = 1;
1988 max_set = 1;
1989 bitmap = default_bitmap;
1990 } else if (mono_type_is_struct (field->type)) {
1991 fclass = mono_class_from_mono_type (field->type);
1992 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1993 } else {
1994 default_bitmap [0] = 0;
1995 max_set = 0;
1996 bitmap = default_bitmap;
1998 size = mono_type_size (field->type, &align);
1999 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, max_set);
2000 if (!domain->special_static_fields)
2001 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2002 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2003 if (bitmap != default_bitmap)
2004 g_free (bitmap);
2006 * This marks the field as special static to speed up the
2007 * checks in mono_field_static_get/set_value ().
2009 field->offset = -1;
2010 continue;
2013 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2014 MonoClass *fklass = mono_class_from_mono_type (field->type);
2015 const char *data = mono_field_get_data (field);
2017 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2018 t = (char*)vt->data + field->offset;
2019 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2020 if (!data)
2021 continue;
2022 if (fklass->valuetype) {
2023 memcpy (t, data, mono_class_value_size (fklass, NULL));
2024 } else {
2025 /* it's a pointer type: add check */
2026 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2027 *t = *(char *)data;
2029 continue;
2033 vt->max_interface_id = class->max_interface_id;
2034 vt->interface_bitmap = class->interface_bitmap;
2036 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2037 // class->name, class->interface_offsets_count);
2039 if (! ARCH_USE_IMT) {
2040 /* initialize interface offsets */
2041 for (i = 0; i < class->interface_offsets_count; ++i) {
2042 int interface_id = class->interfaces_packed [i]->interface_id;
2043 int slot = class->interface_offsets_packed [i];
2044 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
2048 /* class_vtable_array keeps an array of created vtables
2050 g_ptr_array_add (domain->class_vtable_array, vt);
2051 /* class->runtime_info is protected by the loader lock, both when
2052 * it it enlarged and when it is stored info.
2055 old_info = class->runtime_info;
2056 if (old_info && old_info->max_domain >= domain->domain_id) {
2057 /* someone already created a large enough runtime info */
2058 mono_memory_barrier ();
2059 old_info->domain_vtables [domain->domain_id] = vt;
2060 } else {
2061 int new_size = domain->domain_id;
2062 if (old_info)
2063 new_size = MAX (new_size, old_info->max_domain);
2064 new_size++;
2065 /* make the new size a power of two */
2066 i = 2;
2067 while (new_size > i)
2068 i <<= 1;
2069 new_size = i;
2070 /* this is a bounded memory retention issue: may want to
2071 * handle it differently when we'll have a rcu-like system.
2073 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2074 runtime_info->max_domain = new_size - 1;
2075 /* copy the stuff from the older info */
2076 if (old_info) {
2077 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2079 runtime_info->domain_vtables [domain->domain_id] = vt;
2080 /* keep this last*/
2081 mono_memory_barrier ();
2082 class->runtime_info = runtime_info;
2085 /* Initialize vtable */
2086 if (callbacks.get_vtable_trampoline) {
2087 // This also covers the AOT case
2088 for (i = 0; i < class->vtable_size; ++i) {
2089 vt->vtable [i] = callbacks.get_vtable_trampoline (i);
2091 } else {
2092 mono_class_setup_vtable (class);
2094 for (i = 0; i < class->vtable_size; ++i) {
2095 MonoMethod *cm;
2097 if ((cm = class->vtable [i]))
2098 vt->vtable [i] = arch_create_jit_trampoline (cm);
2102 if (ARCH_USE_IMT && imt_table_bytes) {
2103 /* Now that the vtable is full, we can actually fill up the IMT */
2104 if (callbacks.get_imt_trampoline) {
2105 /* lazy construction of the IMT entries enabled */
2106 for (i = 0; i < MONO_IMT_SIZE; ++i)
2107 interface_offsets [i] = callbacks.get_imt_trampoline (i);
2108 } else {
2109 build_imt (class, vt, domain, interface_offsets, NULL);
2113 mono_domain_unlock (domain);
2114 mono_loader_unlock ();
2116 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
2117 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
2118 mono_raise_exception (mono_class_get_exception_for_failure (class));
2120 /* make sure the parent is initialized */
2121 /*FIXME shouldn't this fail the current type?*/
2122 if (class->parent)
2123 mono_class_vtable_full (domain, class->parent, raise_on_error);
2125 /*FIXME check for OOM*/
2126 vt->type = mono_type_get_object (domain, &class->byval_arg);
2127 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2128 /* This is unregistered in
2129 unregister_vtable_reflection_type() in
2130 domain.c. */
2131 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2132 if (class->contextbound)
2133 vt->remote = 1;
2134 else
2135 vt->remote = 0;
2137 return vt;
2141 * mono_class_proxy_vtable:
2142 * @domain: the application domain
2143 * @remove_class: the remote class
2145 * Creates a vtable for transparent proxies. It is basically
2146 * a copy of the real vtable of the class wrapped in @remote_class,
2147 * but all function pointers invoke the remoting functions, and
2148 * vtable->klass points to the transparent proxy class, and not to @class.
2150 static MonoVTable *
2151 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2153 MonoError error;
2154 MonoVTable *vt, *pvt;
2155 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2156 MonoClass *k;
2157 GSList *extra_interfaces = NULL;
2158 MonoClass *class = remote_class->proxy_class;
2159 gpointer *interface_offsets;
2160 uint8_t *bitmap;
2161 int bsize;
2163 #ifdef COMPRESSED_INTERFACE_BITMAP
2164 int bcsize;
2165 #endif
2167 vt = mono_class_vtable (domain, class);
2168 g_assert (vt); /*FIXME property handle failure*/
2169 max_interface_id = vt->max_interface_id;
2171 /* Calculate vtable space for extra interfaces */
2172 for (j = 0; j < remote_class->interface_count; j++) {
2173 MonoClass* iclass = remote_class->interfaces[j];
2174 GPtrArray *ifaces;
2175 int method_count;
2177 /*FIXME test for interfaces with variant generic arguments*/
2178 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2179 continue; /* interface implemented by the class */
2180 if (g_slist_find (extra_interfaces, iclass))
2181 continue;
2183 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2185 method_count = mono_class_num_methods (iclass);
2187 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2188 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2189 if (ifaces) {
2190 for (i = 0; i < ifaces->len; ++i) {
2191 MonoClass *ic = g_ptr_array_index (ifaces, i);
2192 /*FIXME test for interfaces with variant generic arguments*/
2193 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2194 continue; /* interface implemented by the class */
2195 if (g_slist_find (extra_interfaces, ic))
2196 continue;
2197 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2198 method_count += mono_class_num_methods (ic);
2200 g_ptr_array_free (ifaces, TRUE);
2203 extra_interface_vtsize += method_count * sizeof (gpointer);
2204 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2207 if (ARCH_USE_IMT) {
2208 mono_stats.imt_number_of_tables++;
2209 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
2210 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
2211 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2212 } else {
2213 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
2214 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2217 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2219 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
2220 if (ARCH_USE_IMT)
2221 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
2222 else
2223 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
2224 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2226 pvt->klass = mono_defaults.transparent_proxy_class;
2227 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2228 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2230 /* initialize vtable */
2231 mono_class_setup_vtable (class);
2232 for (i = 0; i < class->vtable_size; ++i) {
2233 MonoMethod *cm;
2235 if ((cm = class->vtable [i]))
2236 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2237 else
2238 pvt->vtable [i] = NULL;
2241 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2242 /* create trampolines for abstract methods */
2243 for (k = class; k; k = k->parent) {
2244 MonoMethod* m;
2245 gpointer iter = NULL;
2246 while ((m = mono_class_get_methods (k, &iter)))
2247 if (!pvt->vtable [m->slot])
2248 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2252 pvt->max_interface_id = max_interface_id;
2253 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2254 #ifdef COMPRESSED_INTERFACE_BITMAP
2255 bitmap = g_malloc0 (bsize);
2256 #else
2257 bitmap = mono_domain_alloc0 (domain, bsize);
2258 #endif
2260 if (! ARCH_USE_IMT) {
2261 /* initialize interface offsets */
2262 for (i = 0; i < class->interface_offsets_count; ++i) {
2263 int interface_id = class->interfaces_packed [i]->interface_id;
2264 int slot = class->interface_offsets_packed [i];
2265 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2268 for (i = 0; i < class->interface_offsets_count; ++i) {
2269 int interface_id = class->interfaces_packed [i]->interface_id;
2270 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2273 if (extra_interfaces) {
2274 int slot = class->vtable_size;
2275 MonoClass* interf;
2276 gpointer iter;
2277 MonoMethod* cm;
2278 GSList *list_item;
2280 /* Create trampolines for the methods of the interfaces */
2281 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2282 interf = list_item->data;
2284 if (! ARCH_USE_IMT) {
2285 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2287 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2289 iter = NULL;
2290 j = 0;
2291 while ((cm = mono_class_get_methods (interf, &iter)))
2292 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2294 slot += mono_class_num_methods (interf);
2296 if (! ARCH_USE_IMT) {
2297 g_slist_free (extra_interfaces);
2301 if (ARCH_USE_IMT) {
2302 /* Now that the vtable is full, we can actually fill up the IMT */
2303 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2304 if (extra_interfaces) {
2305 g_slist_free (extra_interfaces);
2309 #ifdef COMPRESSED_INTERFACE_BITMAP
2310 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2311 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2312 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2313 g_free (bitmap);
2314 #else
2315 pvt->interface_bitmap = bitmap;
2316 #endif
2317 return pvt;
2321 * mono_class_field_is_special_static:
2323 * Returns whether @field is a thread/context static field.
2325 gboolean
2326 mono_class_field_is_special_static (MonoClassField *field)
2328 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2329 return FALSE;
2330 if (mono_field_is_deleted (field))
2331 return FALSE;
2332 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2333 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2334 return TRUE;
2336 return FALSE;
2340 * mono_class_field_get_special_static_type:
2341 * @field: The MonoClassField describing the field.
2343 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2344 * SPECIAL_STATIC_NONE otherwise.
2346 guint32
2347 mono_class_field_get_special_static_type (MonoClassField *field)
2349 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2350 return SPECIAL_STATIC_NONE;
2351 if (mono_field_is_deleted (field))
2352 return SPECIAL_STATIC_NONE;
2353 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2354 return field_is_special_static (field->parent, field);
2355 return SPECIAL_STATIC_NONE;
2359 * mono_class_has_special_static_fields:
2361 * Returns whenever @klass has any thread/context static fields.
2363 gboolean
2364 mono_class_has_special_static_fields (MonoClass *klass)
2366 MonoClassField *field;
2367 gpointer iter;
2369 iter = NULL;
2370 while ((field = mono_class_get_fields (klass, &iter))) {
2371 g_assert (field->parent == klass);
2372 if (mono_class_field_is_special_static (field))
2373 return TRUE;
2376 return FALSE;
2380 * create_remote_class_key:
2381 * Creates an array of pointers that can be used as a hash key for a remote class.
2382 * The first element of the array is the number of pointers.
2384 static gpointer*
2385 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2387 gpointer *key;
2388 int i, j;
2390 if (remote_class == NULL) {
2391 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2392 key = g_malloc (sizeof(gpointer) * 3);
2393 key [0] = GINT_TO_POINTER (2);
2394 key [1] = mono_defaults.marshalbyrefobject_class;
2395 key [2] = extra_class;
2396 } else {
2397 key = g_malloc (sizeof(gpointer) * 2);
2398 key [0] = GINT_TO_POINTER (1);
2399 key [1] = extra_class;
2401 } else {
2402 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2403 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2404 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2405 key [1] = remote_class->proxy_class;
2407 // Keep the list of interfaces sorted
2408 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2409 if (extra_class && remote_class->interfaces [i] > extra_class) {
2410 key [j++] = extra_class;
2411 extra_class = NULL;
2413 key [j] = remote_class->interfaces [i];
2415 if (extra_class)
2416 key [j] = extra_class;
2417 } else {
2418 // Replace the old class. The interface list is the same
2419 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2420 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2421 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2422 for (i = 0; i < remote_class->interface_count; i++)
2423 key [2 + i] = remote_class->interfaces [i];
2427 return key;
2431 * copy_remote_class_key:
2433 * Make a copy of KEY in the domain and return the copy.
2435 static gpointer*
2436 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2438 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2439 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2441 memcpy (mp_key, key, key_size);
2443 return mp_key;
2447 * mono_remote_class:
2448 * @domain: the application domain
2449 * @class_name: name of the remote class
2451 * Creates and initializes a MonoRemoteClass object for a remote type.
2453 * Can raise an exception on failure.
2455 MonoRemoteClass*
2456 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2458 MonoError error;
2459 MonoRemoteClass *rc;
2460 gpointer* key, *mp_key;
2461 char *name;
2463 key = create_remote_class_key (NULL, proxy_class);
2465 mono_domain_lock (domain);
2466 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2468 if (rc) {
2469 g_free (key);
2470 mono_domain_unlock (domain);
2471 return rc;
2474 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2475 if (!mono_error_ok (&error)) {
2476 g_free (key);
2477 mono_domain_unlock (domain);
2478 mono_error_raise_exception (&error);
2481 mp_key = copy_remote_class_key (domain, key);
2482 g_free (key);
2483 key = mp_key;
2485 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2486 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2487 rc->interface_count = 1;
2488 rc->interfaces [0] = proxy_class;
2489 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2490 } else {
2491 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2492 rc->interface_count = 0;
2493 rc->proxy_class = proxy_class;
2496 rc->default_vtable = NULL;
2497 rc->xdomain_vtable = NULL;
2498 rc->proxy_class_name = name;
2499 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2501 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2503 mono_domain_unlock (domain);
2504 return rc;
2508 * clone_remote_class:
2509 * Creates a copy of the remote_class, adding the provided class or interface
2511 static MonoRemoteClass*
2512 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2514 MonoRemoteClass *rc;
2515 gpointer* key, *mp_key;
2517 key = create_remote_class_key (remote_class, extra_class);
2518 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2519 if (rc != NULL) {
2520 g_free (key);
2521 return rc;
2524 mp_key = copy_remote_class_key (domain, key);
2525 g_free (key);
2526 key = mp_key;
2528 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2529 int i,j;
2530 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2531 rc->proxy_class = remote_class->proxy_class;
2532 rc->interface_count = remote_class->interface_count + 1;
2534 // Keep the list of interfaces sorted, since the hash key of
2535 // the remote class depends on this
2536 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2537 if (remote_class->interfaces [i] > extra_class && i == j)
2538 rc->interfaces [j++] = extra_class;
2539 rc->interfaces [j] = remote_class->interfaces [i];
2541 if (i == j)
2542 rc->interfaces [j] = extra_class;
2543 } else {
2544 // Replace the old class. The interface array is the same
2545 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2546 rc->proxy_class = extra_class;
2547 rc->interface_count = remote_class->interface_count;
2548 if (rc->interface_count > 0)
2549 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2552 rc->default_vtable = NULL;
2553 rc->xdomain_vtable = NULL;
2554 rc->proxy_class_name = remote_class->proxy_class_name;
2556 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2558 return rc;
2561 gpointer
2562 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2564 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2565 mono_domain_lock (domain);
2566 if (rp->target_domain_id != -1) {
2567 if (remote_class->xdomain_vtable == NULL)
2568 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2569 mono_domain_unlock (domain);
2570 mono_loader_unlock ();
2571 return remote_class->xdomain_vtable;
2573 if (remote_class->default_vtable == NULL) {
2574 MonoType *type;
2575 MonoClass *klass;
2576 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2577 klass = mono_class_from_mono_type (type);
2578 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
2579 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2580 else
2581 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2584 mono_domain_unlock (domain);
2585 mono_loader_unlock ();
2586 return remote_class->default_vtable;
2590 * mono_upgrade_remote_class:
2591 * @domain: the application domain
2592 * @tproxy: the proxy whose remote class has to be upgraded.
2593 * @klass: class to which the remote class can be casted.
2595 * Updates the vtable of the remote class by adding the necessary method slots
2596 * and interface offsets so it can be safely casted to klass. klass can be a
2597 * class or an interface.
2599 void
2600 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2602 MonoTransparentProxy *tproxy;
2603 MonoRemoteClass *remote_class;
2604 gboolean redo_vtable;
2606 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2607 mono_domain_lock (domain);
2609 tproxy = (MonoTransparentProxy*) proxy_object;
2610 remote_class = tproxy->remote_class;
2612 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2613 int i;
2614 redo_vtable = TRUE;
2615 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2616 if (remote_class->interfaces [i] == klass)
2617 redo_vtable = FALSE;
2619 else {
2620 redo_vtable = (remote_class->proxy_class != klass);
2623 if (redo_vtable) {
2624 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2625 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2628 mono_domain_unlock (domain);
2629 mono_loader_unlock ();
2634 * mono_object_get_virtual_method:
2635 * @obj: object to operate on.
2636 * @method: method
2638 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2639 * the instance of a callvirt of method.
2641 MonoMethod*
2642 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2644 MonoClass *klass;
2645 MonoMethod **vtable;
2646 gboolean is_proxy;
2647 MonoMethod *res = NULL;
2649 klass = mono_object_class (obj);
2650 if (klass == mono_defaults.transparent_proxy_class) {
2651 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2652 is_proxy = TRUE;
2653 } else {
2654 is_proxy = FALSE;
2657 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2658 return method;
2660 mono_class_setup_vtable (klass);
2661 vtable = klass->vtable;
2663 if (method->slot == -1) {
2664 /* method->slot might not be set for instances of generic methods */
2665 if (method->is_inflated) {
2666 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2667 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2668 } else {
2669 if (!is_proxy)
2670 g_assert_not_reached ();
2674 /* check method->slot is a valid index: perform isinstance? */
2675 if (method->slot != -1) {
2676 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2677 if (!is_proxy) {
2678 gboolean variance_used = FALSE;
2679 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2680 g_assert (iface_offset > 0);
2681 res = vtable [iface_offset + method->slot];
2683 } else {
2684 res = vtable [method->slot];
2688 if (is_proxy) {
2689 /* It may be an interface, abstract class method or generic method */
2690 if (!res || mono_method_signature (res)->generic_param_count)
2691 res = method;
2693 /* generic methods demand invoke_with_check */
2694 if (mono_method_signature (res)->generic_param_count)
2695 res = mono_marshal_get_remoting_invoke_with_check (res);
2696 else {
2697 #ifndef DISABLE_COM
2698 if (klass == mono_defaults.com_object_class || klass->is_com_object)
2699 res = mono_cominterop_get_invoke (res);
2700 else
2701 #endif
2702 res = mono_marshal_get_remoting_invoke (res);
2704 } else {
2705 if (method->is_inflated) {
2706 /* Have to inflate the result */
2707 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2711 g_assert (res);
2713 return res;
2716 static MonoObject*
2717 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2719 g_error ("runtime invoke called on uninitialized runtime");
2720 return NULL;
2723 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2726 * mono_runtime_invoke:
2727 * @method: method to invoke
2728 * @obJ: object instance
2729 * @params: arguments to the method
2730 * @exc: exception information.
2732 * Invokes the method represented by @method on the object @obj.
2734 * obj is the 'this' pointer, it should be NULL for static
2735 * methods, a MonoObject* for object instances and a pointer to
2736 * the value type for value types.
2738 * The params array contains the arguments to the method with the
2739 * same convention: MonoObject* pointers for object instances and
2740 * pointers to the value type otherwise.
2742 * From unmanaged code you'll usually use the
2743 * mono_runtime_invoke() variant.
2745 * Note that this function doesn't handle virtual methods for
2746 * you, it will exec the exact method you pass: we still need to
2747 * expose a function to lookup the derived class implementation
2748 * of a virtual method (there are examples of this in the code,
2749 * though).
2751 * You can pass NULL as the exc argument if you don't want to
2752 * catch exceptions, otherwise, *exc will be set to the exception
2753 * thrown, if any. if an exception is thrown, you can't use the
2754 * MonoObject* result from the function.
2756 * If the method returns a value type, it is boxed in an object
2757 * reference.
2759 MonoObject*
2760 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2762 MonoObject *result;
2764 if (mono_runtime_get_no_exec ())
2765 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2767 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2768 mono_profiler_method_start_invoke (method);
2770 result = default_mono_runtime_invoke (method, obj, params, exc);
2772 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2773 mono_profiler_method_end_invoke (method);
2775 return result;
2779 * mono_method_get_unmanaged_thunk:
2780 * @method: method to generate a thunk for.
2782 * Returns an unmanaged->managed thunk that can be used to call
2783 * a managed method directly from C.
2785 * The thunk's C signature closely matches the managed signature:
2787 * C#: public bool Equals (object obj);
2788 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2789 * MonoObject*, MonoException**);
2791 * The 1st ("this") parameter must not be used with static methods:
2793 * C#: public static bool ReferenceEquals (object a, object b);
2794 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2795 * MonoException**);
2797 * The last argument must be a non-null pointer of a MonoException* pointer.
2798 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2799 * exception has been thrown in managed code. Otherwise it will point
2800 * to the MonoException* caught by the thunk. In this case, the result of
2801 * the thunk is undefined:
2803 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2804 * MonoException *ex = NULL;
2805 * Equals func = mono_method_get_unmanaged_thunk (method);
2806 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2807 * if (ex) {
2808 * // handle exception
2811 * The calling convention of the thunk matches the platform's default
2812 * convention. This means that under Windows, C declarations must
2813 * contain the __stdcall attribute:
2815 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2816 * MonoObject*, MonoException**);
2818 * LIMITATIONS
2820 * Value type arguments and return values are treated as they were objects:
2822 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2823 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2825 * Arguments must be properly boxed upon trunk's invocation, while return
2826 * values must be unboxed.
2828 gpointer
2829 mono_method_get_unmanaged_thunk (MonoMethod *method)
2831 method = mono_marshal_get_thunk_invoke_wrapper (method);
2832 return mono_compile_method (method);
2835 static void
2836 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2838 int t;
2839 if (type->byref) {
2840 /* object fields cannot be byref, so we don't need a
2841 wbarrier here */
2842 gpointer *p = (gpointer*)dest;
2843 *p = value;
2844 return;
2846 t = type->type;
2847 handle_enum:
2848 switch (t) {
2849 case MONO_TYPE_BOOLEAN:
2850 case MONO_TYPE_I1:
2851 case MONO_TYPE_U1: {
2852 guint8 *p = (guint8*)dest;
2853 *p = value ? *(guint8*)value : 0;
2854 return;
2856 case MONO_TYPE_I2:
2857 case MONO_TYPE_U2:
2858 case MONO_TYPE_CHAR: {
2859 guint16 *p = (guint16*)dest;
2860 *p = value ? *(guint16*)value : 0;
2861 return;
2863 #if SIZEOF_VOID_P == 4
2864 case MONO_TYPE_I:
2865 case MONO_TYPE_U:
2866 #endif
2867 case MONO_TYPE_I4:
2868 case MONO_TYPE_U4: {
2869 gint32 *p = (gint32*)dest;
2870 *p = value ? *(gint32*)value : 0;
2871 return;
2873 #if SIZEOF_VOID_P == 8
2874 case MONO_TYPE_I:
2875 case MONO_TYPE_U:
2876 #endif
2877 case MONO_TYPE_I8:
2878 case MONO_TYPE_U8: {
2879 gint64 *p = (gint64*)dest;
2880 *p = value ? *(gint64*)value : 0;
2881 return;
2883 case MONO_TYPE_R4: {
2884 float *p = (float*)dest;
2885 *p = value ? *(float*)value : 0;
2886 return;
2888 case MONO_TYPE_R8: {
2889 double *p = (double*)dest;
2890 *p = value ? *(double*)value : 0;
2891 return;
2893 case MONO_TYPE_STRING:
2894 case MONO_TYPE_SZARRAY:
2895 case MONO_TYPE_CLASS:
2896 case MONO_TYPE_OBJECT:
2897 case MONO_TYPE_ARRAY:
2898 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2899 return;
2900 case MONO_TYPE_FNPTR:
2901 case MONO_TYPE_PTR: {
2902 gpointer *p = (gpointer*)dest;
2903 *p = deref_pointer? *(gpointer*)value: value;
2904 return;
2906 case MONO_TYPE_VALUETYPE:
2907 /* note that 't' and 'type->type' can be different */
2908 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2909 t = mono_class_enum_basetype (type->data.klass)->type;
2910 goto handle_enum;
2911 } else {
2912 MonoClass *class = mono_class_from_mono_type (type);
2913 int size = mono_class_value_size (class, NULL);
2914 if (value == NULL)
2915 memset (dest, 0, size);
2916 else
2917 mono_gc_wbarrier_value_copy (dest, value, 1, class);
2919 return;
2920 case MONO_TYPE_GENERICINST:
2921 t = type->data.generic_class->container_class->byval_arg.type;
2922 goto handle_enum;
2923 default:
2924 g_warning ("got type %x", type->type);
2925 g_assert_not_reached ();
2930 * mono_field_set_value:
2931 * @obj: Instance object
2932 * @field: MonoClassField describing the field to set
2933 * @value: The value to be set
2935 * Sets the value of the field described by @field in the object instance @obj
2936 * to the value passed in @value. This method should only be used for instance
2937 * fields. For static fields, use mono_field_static_set_value.
2939 * The value must be on the native format of the field type.
2941 void
2942 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2944 void *dest;
2946 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2948 dest = (char*)obj + field->offset;
2949 set_value (field->type, dest, value, FALSE);
2953 * mono_field_static_set_value:
2954 * @field: MonoClassField describing the field to set
2955 * @value: The value to be set
2957 * Sets the value of the static field described by @field
2958 * to the value passed in @value.
2960 * The value must be on the native format of the field type.
2962 void
2963 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2965 void *dest;
2967 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2968 /* you cant set a constant! */
2969 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2971 if (field->offset == -1) {
2972 /* Special static */
2973 gpointer addr;
2975 mono_domain_lock (vt->domain);
2976 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2977 mono_domain_unlock (vt->domain);
2978 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2979 } else {
2980 dest = (char*)vt->data + field->offset;
2982 set_value (field->type, dest, value, FALSE);
2985 /* Used by the debugger */
2986 void *
2987 mono_vtable_get_static_field_data (MonoVTable *vt)
2989 return vt->data;
2992 static guint8*
2993 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
2995 guint8 *src;
2997 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2998 if (field->offset == -1) {
2999 /* Special static */
3000 gpointer addr;
3002 mono_domain_lock (vt->domain);
3003 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3004 mono_domain_unlock (vt->domain);
3005 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3006 } else {
3007 src = (guint8*)vt->data + field->offset;
3009 } else {
3010 src = (guint8*)obj + field->offset;
3013 return src;
3017 * mono_field_get_value:
3018 * @obj: Object instance
3019 * @field: MonoClassField describing the field to fetch information from
3020 * @value: pointer to the location where the value will be stored
3022 * Use this routine to get the value of the field @field in the object
3023 * passed.
3025 * The pointer provided by value must be of the field type, for reference
3026 * types this is a MonoObject*, for value types its the actual pointer to
3027 * the value type.
3029 * For example:
3030 * int i;
3031 * mono_field_get_value (obj, int_field, &i);
3033 void
3034 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3036 void *src;
3038 g_assert (obj);
3040 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3042 src = (char*)obj + field->offset;
3043 set_value (field->type, value, src, TRUE);
3047 * mono_field_get_value_object:
3048 * @domain: domain where the object will be created (if boxing)
3049 * @field: MonoClassField describing the field to fetch information from
3050 * @obj: The object instance for the field.
3052 * Returns: a new MonoObject with the value from the given field. If the
3053 * field represents a value type, the value is boxed.
3056 MonoObject *
3057 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3059 MonoObject *o;
3060 MonoClass *klass;
3061 MonoVTable *vtable = NULL;
3062 gchar *v;
3063 gboolean is_static = FALSE;
3064 gboolean is_ref = FALSE;
3065 gboolean is_literal = FALSE;
3066 gboolean is_ptr = FALSE;
3067 MonoError error;
3068 MonoType *type = mono_field_get_type_checked (field, &error);
3070 if (!mono_error_ok (&error))
3071 mono_error_raise_exception (&error);
3073 switch (type->type) {
3074 case MONO_TYPE_STRING:
3075 case MONO_TYPE_OBJECT:
3076 case MONO_TYPE_CLASS:
3077 case MONO_TYPE_ARRAY:
3078 case MONO_TYPE_SZARRAY:
3079 is_ref = TRUE;
3080 break;
3081 case MONO_TYPE_U1:
3082 case MONO_TYPE_I1:
3083 case MONO_TYPE_BOOLEAN:
3084 case MONO_TYPE_U2:
3085 case MONO_TYPE_I2:
3086 case MONO_TYPE_CHAR:
3087 case MONO_TYPE_U:
3088 case MONO_TYPE_I:
3089 case MONO_TYPE_U4:
3090 case MONO_TYPE_I4:
3091 case MONO_TYPE_R4:
3092 case MONO_TYPE_U8:
3093 case MONO_TYPE_I8:
3094 case MONO_TYPE_R8:
3095 case MONO_TYPE_VALUETYPE:
3096 is_ref = type->byref;
3097 break;
3098 case MONO_TYPE_GENERICINST:
3099 is_ref = !mono_type_generic_inst_is_valuetype (type);
3100 break;
3101 case MONO_TYPE_PTR:
3102 is_ptr = TRUE;
3103 break;
3104 default:
3105 g_error ("type 0x%x not handled in "
3106 "mono_field_get_value_object", type->type);
3107 return NULL;
3110 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3111 is_literal = TRUE;
3113 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3114 is_static = TRUE;
3116 if (!is_literal) {
3117 vtable = mono_class_vtable (domain, field->parent);
3118 if (!vtable) {
3119 char *name = mono_type_get_full_name (field->parent);
3120 /*FIXME extend this to use the MonoError api*/
3121 g_warning ("Could not retrieve the vtable for type %s in mono_field_get_value_object", name);
3122 g_free (name);
3123 return NULL;
3125 if (!vtable->initialized)
3126 mono_runtime_class_init (vtable);
3128 } else {
3129 g_assert (obj);
3132 if (is_ref) {
3133 if (is_literal) {
3134 get_default_field_value (domain, field, &o);
3135 } else if (is_static) {
3136 mono_field_static_get_value (vtable, field, &o);
3137 } else {
3138 mono_field_get_value (obj, field, &o);
3140 return o;
3143 if (is_ptr) {
3144 static MonoMethod *m;
3145 gpointer args [2];
3146 gpointer *ptr;
3147 gpointer v;
3149 if (!m) {
3150 MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3151 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3152 g_assert (m);
3155 v = &ptr;
3156 if (is_literal) {
3157 get_default_field_value (domain, field, v);
3158 } else if (is_static) {
3159 mono_field_static_get_value (vtable, field, v);
3160 } else {
3161 mono_field_get_value (obj, field, v);
3164 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3165 args [0] = *ptr;
3166 args [1] = mono_type_get_object (mono_domain_get (), type);
3168 return mono_runtime_invoke (m, NULL, args, NULL);
3171 /* boxed value type */
3172 klass = mono_class_from_mono_type (type);
3174 if (mono_class_is_nullable (klass))
3175 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3177 o = mono_object_new (domain, klass);
3178 v = ((gchar *) o) + sizeof (MonoObject);
3180 if (is_literal) {
3181 get_default_field_value (domain, field, v);
3182 } else if (is_static) {
3183 mono_field_static_get_value (vtable, field, v);
3184 } else {
3185 mono_field_get_value (obj, field, v);
3188 return o;
3192 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3194 int retval = 0;
3195 const char *p = blob;
3196 mono_metadata_decode_blob_size (p, &p);
3198 switch (type) {
3199 case MONO_TYPE_BOOLEAN:
3200 case MONO_TYPE_U1:
3201 case MONO_TYPE_I1:
3202 *(guint8 *) value = *p;
3203 break;
3204 case MONO_TYPE_CHAR:
3205 case MONO_TYPE_U2:
3206 case MONO_TYPE_I2:
3207 *(guint16*) value = read16 (p);
3208 break;
3209 case MONO_TYPE_U4:
3210 case MONO_TYPE_I4:
3211 *(guint32*) value = read32 (p);
3212 break;
3213 case MONO_TYPE_U8:
3214 case MONO_TYPE_I8:
3215 *(guint64*) value = read64 (p);
3216 break;
3217 case MONO_TYPE_R4:
3218 readr4 (p, (float*) value);
3219 break;
3220 case MONO_TYPE_R8:
3221 readr8 (p, (double*) value);
3222 break;
3223 case MONO_TYPE_STRING:
3224 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3225 break;
3226 case MONO_TYPE_CLASS:
3227 *(gpointer*) value = NULL;
3228 break;
3229 default:
3230 retval = -1;
3231 g_warning ("type 0x%02x should not be in constant table", type);
3233 return retval;
3236 static void
3237 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3239 MonoTypeEnum def_type;
3240 const char* data;
3242 data = mono_class_get_field_default_value (field, &def_type);
3243 mono_get_constant_value_from_blob (domain, def_type, data, value);
3246 void
3247 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3249 void *src;
3251 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3253 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3254 get_default_field_value (vt->domain, field, value);
3255 return;
3258 if (field->offset == -1) {
3259 /* Special static */
3260 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3261 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3262 } else {
3263 src = (char*)vt->data + field->offset;
3265 set_value (field->type, value, src, TRUE);
3269 * mono_field_static_get_value:
3270 * @vt: vtable to the object
3271 * @field: MonoClassField describing the field to fetch information from
3272 * @value: where the value is returned
3274 * Use this routine to get the value of the static field @field value.
3276 * The pointer provided by value must be of the field type, for reference
3277 * types this is a MonoObject*, for value types its the actual pointer to
3278 * the value type.
3280 * For example:
3281 * int i;
3282 * mono_field_static_get_value (vt, int_field, &i);
3284 void
3285 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3287 return mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3291 * mono_property_set_value:
3292 * @prop: MonoProperty to set
3293 * @obj: instance object on which to act
3294 * @params: parameters to pass to the propery
3295 * @exc: optional exception
3297 * Invokes the property's set method with the given arguments on the
3298 * object instance obj (or NULL for static properties).
3300 * You can pass NULL as the exc argument if you don't want to
3301 * catch exceptions, otherwise, *exc will be set to the exception
3302 * thrown, if any. if an exception is thrown, you can't use the
3303 * MonoObject* result from the function.
3305 void
3306 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3308 default_mono_runtime_invoke (prop->set, obj, params, exc);
3312 * mono_property_get_value:
3313 * @prop: MonoProperty to fetch
3314 * @obj: instance object on which to act
3315 * @params: parameters to pass to the propery
3316 * @exc: optional exception
3318 * Invokes the property's get method with the given arguments on the
3319 * object instance obj (or NULL for static properties).
3321 * You can pass NULL as the exc argument if you don't want to
3322 * catch exceptions, otherwise, *exc will be set to the exception
3323 * thrown, if any. if an exception is thrown, you can't use the
3324 * MonoObject* result from the function.
3326 * Returns: the value from invoking the get method on the property.
3328 MonoObject*
3329 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3331 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3335 * mono_nullable_init:
3336 * @buf: The nullable structure to initialize.
3337 * @value: the value to initialize from
3338 * @klass: the type for the object
3340 * Initialize the nullable structure pointed to by @buf from @value which
3341 * should be a boxed value type. The size of @buf should be able to hold
3342 * as much data as the @klass->instance_size (which is the number of bytes
3343 * that will be copies).
3345 * Since Nullables have variable structure, we can not define a C
3346 * structure for them.
3348 void
3349 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3351 MonoClass *param_class = klass->cast_class;
3353 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3354 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3356 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3357 if (value) {
3358 if (param_class->has_references)
3359 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3360 else
3361 memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3362 } else {
3363 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
3368 * mono_nullable_box:
3369 * @buf: The buffer representing the data to be boxed
3370 * @klass: the type to box it as.
3372 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3373 * @buf.
3375 MonoObject*
3376 mono_nullable_box (guint8 *buf, MonoClass *klass)
3378 MonoClass *param_class = klass->cast_class;
3380 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3381 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3383 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3384 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3385 if (param_class->has_references)
3386 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3387 else
3388 memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3389 return o;
3391 else
3392 return NULL;
3396 * mono_get_delegate_invoke:
3397 * @klass: The delegate class
3399 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3401 MonoMethod *
3402 mono_get_delegate_invoke (MonoClass *klass)
3404 MonoMethod *im;
3406 /* This is called at runtime, so avoid the slower search in metadata */
3407 mono_class_setup_methods (klass);
3408 if (klass->exception_type)
3409 return NULL;
3410 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3411 return im;
3415 * mono_runtime_delegate_invoke:
3416 * @delegate: pointer to a delegate object.
3417 * @params: parameters for the delegate.
3418 * @exc: Pointer to the exception result.
3420 * Invokes the delegate method @delegate with the parameters provided.
3422 * You can pass NULL as the exc argument if you don't want to
3423 * catch exceptions, otherwise, *exc will be set to the exception
3424 * thrown, if any. if an exception is thrown, you can't use the
3425 * MonoObject* result from the function.
3427 MonoObject*
3428 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3430 MonoMethod *im;
3432 im = mono_get_delegate_invoke (delegate->vtable->klass);
3433 g_assert (im);
3435 return mono_runtime_invoke (im, delegate, params, exc);
3438 static char **main_args = NULL;
3439 static int num_main_args;
3442 * mono_runtime_get_main_args:
3444 * Returns: a MonoArray with the arguments passed to the main program
3446 MonoArray*
3447 mono_runtime_get_main_args (void)
3449 MonoArray *res;
3450 int i;
3451 MonoDomain *domain = mono_domain_get ();
3453 if (!main_args)
3454 return NULL;
3456 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3458 for (i = 0; i < num_main_args; ++i)
3459 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3461 return res;
3464 static void
3465 free_main_args (void)
3467 int i;
3469 for (i = 0; i < num_main_args; ++i)
3470 g_free (main_args [i]);
3471 g_free (main_args);
3475 * mono_runtime_run_main:
3476 * @method: the method to start the application with (usually Main)
3477 * @argc: number of arguments from the command line
3478 * @argv: array of strings from the command line
3479 * @exc: excetption results
3481 * Execute a standard Main() method (argc/argv contains the
3482 * executable name). This method also sets the command line argument value
3483 * needed by System.Environment.
3488 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3489 MonoObject **exc)
3491 int i;
3492 MonoArray *args = NULL;
3493 MonoDomain *domain = mono_domain_get ();
3494 gchar *utf8_fullpath;
3495 MonoMethodSignature *sig;
3497 g_assert (method != NULL);
3499 mono_thread_set_main (mono_thread_current ());
3501 main_args = g_new0 (char*, argc);
3502 num_main_args = argc;
3504 if (!g_path_is_absolute (argv [0])) {
3505 gchar *basename = g_path_get_basename (argv [0]);
3506 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3507 basename,
3508 NULL);
3510 utf8_fullpath = mono_utf8_from_external (fullpath);
3511 if(utf8_fullpath == NULL) {
3512 /* Printing the arg text will cause glib to
3513 * whinge about "Invalid UTF-8", but at least
3514 * its relevant, and shows the problem text
3515 * string.
3517 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3518 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3519 exit (-1);
3522 g_free (fullpath);
3523 g_free (basename);
3524 } else {
3525 utf8_fullpath = mono_utf8_from_external (argv[0]);
3526 if(utf8_fullpath == NULL) {
3527 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3528 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3529 exit (-1);
3533 main_args [0] = utf8_fullpath;
3535 for (i = 1; i < argc; ++i) {
3536 gchar *utf8_arg;
3538 utf8_arg=mono_utf8_from_external (argv[i]);
3539 if(utf8_arg==NULL) {
3540 /* Ditto the comment about Invalid UTF-8 here */
3541 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3542 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3543 exit (-1);
3546 main_args [i] = utf8_arg;
3548 argc--;
3549 argv++;
3551 sig = mono_method_signature (method);
3552 if (!sig) {
3553 g_print ("Unable to load Main method.\n");
3554 exit (-1);
3557 if (sig->param_count) {
3558 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3559 for (i = 0; i < argc; ++i) {
3560 /* The encodings should all work, given that
3561 * we've checked all these args for the
3562 * main_args array.
3564 gchar *str = mono_utf8_from_external (argv [i]);
3565 MonoString *arg = mono_string_new (domain, str);
3566 mono_array_setref (args, i, arg);
3567 g_free (str);
3569 } else {
3570 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3573 mono_assembly_set_main (method->klass->image->assembly);
3575 return mono_runtime_exec_main (method, args, exc);
3578 static MonoObject*
3579 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3581 static MonoMethod *serialize_method;
3583 void *params [1];
3584 MonoObject *array;
3586 if (!serialize_method) {
3587 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3588 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3591 if (!serialize_method) {
3592 *failure = TRUE;
3593 return NULL;
3596 g_assert (!mono_object_class (obj)->marshalbyref);
3598 params [0] = obj;
3599 *exc = NULL;
3600 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3601 if (*exc)
3602 *failure = TRUE;
3604 return array;
3607 static MonoObject*
3608 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3610 static MonoMethod *deserialize_method;
3612 void *params [1];
3613 MonoObject *result;
3615 if (!deserialize_method) {
3616 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3617 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3619 if (!deserialize_method) {
3620 *failure = TRUE;
3621 return NULL;
3624 params [0] = obj;
3625 *exc = NULL;
3626 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3627 if (*exc)
3628 *failure = TRUE;
3630 return result;
3633 static MonoObject*
3634 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3636 static MonoMethod *get_proxy_method;
3638 MonoDomain *domain = mono_domain_get ();
3639 MonoRealProxy *real_proxy;
3640 MonoReflectionType *reflection_type;
3641 MonoTransparentProxy *transparent_proxy;
3643 if (!get_proxy_method)
3644 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3646 g_assert (obj->vtable->klass->marshalbyref);
3648 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3649 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3651 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3652 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3654 *exc = NULL;
3655 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3656 if (*exc)
3657 *failure = TRUE;
3659 return (MonoObject*) transparent_proxy;
3663 * mono_object_xdomain_representation
3664 * @obj: an object
3665 * @target_domain: a domain
3666 * @exc: pointer to a MonoObject*
3668 * Creates a representation of obj in the domain target_domain. This
3669 * is either a copy of obj arrived through via serialization and
3670 * deserialization or a proxy, depending on whether the object is
3671 * serializable or marshal by ref. obj must not be in target_domain.
3673 * If the object cannot be represented in target_domain, NULL is
3674 * returned and *exc is set to an appropriate exception.
3676 MonoObject*
3677 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3679 MonoObject *deserialized = NULL;
3680 gboolean failure = FALSE;
3682 *exc = NULL;
3684 if (mono_object_class (obj)->marshalbyref) {
3685 deserialized = make_transparent_proxy (obj, &failure, exc);
3686 } else {
3687 MonoDomain *domain = mono_domain_get ();
3688 MonoObject *serialized;
3690 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3691 serialized = serialize_object (obj, &failure, exc);
3692 mono_domain_set_internal_with_options (target_domain, FALSE);
3693 if (!failure)
3694 deserialized = deserialize_object (serialized, &failure, exc);
3695 if (domain != target_domain)
3696 mono_domain_set_internal_with_options (domain, FALSE);
3699 return deserialized;
3702 /* Used in call_unhandled_exception_delegate */
3703 static MonoObject *
3704 create_unhandled_exception_eventargs (MonoObject *exc)
3706 MonoClass *klass;
3707 gpointer args [2];
3708 MonoMethod *method = NULL;
3709 MonoBoolean is_terminating = TRUE;
3710 MonoObject *obj;
3712 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3713 g_assert (klass);
3715 mono_class_init (klass);
3717 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3718 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3719 g_assert (method);
3721 args [0] = exc;
3722 args [1] = &is_terminating;
3724 obj = mono_object_new (mono_domain_get (), klass);
3725 mono_runtime_invoke (method, obj, args, NULL);
3727 return obj;
3730 /* Used in mono_unhandled_exception */
3731 static void
3732 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3733 MonoObject *e = NULL;
3734 gpointer pa [2];
3735 MonoDomain *current_domain = mono_domain_get ();
3737 if (domain != current_domain)
3738 mono_domain_set_internal_with_options (domain, FALSE);
3740 g_assert (domain == mono_object_domain (domain->domain));
3742 if (mono_object_domain (exc) != domain) {
3743 MonoObject *serialization_exc;
3745 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
3746 if (!exc) {
3747 if (serialization_exc) {
3748 MonoObject *dummy;
3749 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
3750 g_assert (exc);
3751 } else {
3752 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
3753 "System.Runtime.Serialization", "SerializationException",
3754 "Could not serialize unhandled exception.");
3758 g_assert (mono_object_domain (exc) == domain);
3760 pa [0] = domain->domain;
3761 pa [1] = create_unhandled_exception_eventargs (exc);
3762 mono_runtime_delegate_invoke (delegate, pa, &e);
3764 if (domain != current_domain)
3765 mono_domain_set_internal_with_options (current_domain, FALSE);
3767 if (e) {
3768 MonoError error;
3769 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
3770 if (!mono_error_ok (&error)) {
3771 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
3772 mono_error_cleanup (&error);
3773 } else {
3774 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3775 g_free (msg);
3780 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3783 * mono_runtime_unhandled_exception_policy_set:
3784 * @policy: the new policy
3786 * This is a VM internal routine.
3788 * Sets the runtime policy for handling unhandled exceptions.
3790 void
3791 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3792 runtime_unhandled_exception_policy = policy;
3796 * mono_runtime_unhandled_exception_policy_get:
3798 * This is a VM internal routine.
3800 * Gets the runtime policy for handling unhandled exceptions.
3802 MonoRuntimeUnhandledExceptionPolicy
3803 mono_runtime_unhandled_exception_policy_get (void) {
3804 return runtime_unhandled_exception_policy;
3808 * mono_unhandled_exception:
3809 * @exc: exception thrown
3811 * This is a VM internal routine.
3813 * We call this function when we detect an unhandled exception
3814 * in the default domain.
3816 * It invokes the * UnhandledException event in AppDomain or prints
3817 * a warning to the console
3819 void
3820 mono_unhandled_exception (MonoObject *exc)
3822 MonoDomain *current_domain = mono_domain_get ();
3823 MonoDomain *root_domain = mono_get_root_domain ();
3824 MonoClassField *field;
3825 MonoObject *current_appdomain_delegate;
3826 MonoObject *root_appdomain_delegate;
3828 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3829 "UnhandledException");
3830 g_assert (field);
3832 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3833 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
3834 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3835 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3836 if (current_domain != root_domain) {
3837 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3838 } else {
3839 current_appdomain_delegate = NULL;
3842 /* set exitcode only if we will abort the process */
3843 if (abort_process)
3844 mono_environment_exitcode_set (1);
3845 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3846 mono_print_unhandled_exception (exc);
3847 } else {
3848 if (root_appdomain_delegate) {
3849 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3851 if (current_appdomain_delegate) {
3852 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3859 * mono_runtime_exec_managed_code:
3860 * @domain: Application domain
3861 * @main_func: function to invoke from the execution thread
3862 * @main_args: parameter to the main_func
3864 * Launch a new thread to execute a function
3866 * main_func is called back from the thread with main_args as the
3867 * parameter. The callback function is expected to start Main()
3868 * eventually. This function then waits for all managed threads to
3869 * finish.
3870 * It is not necesseray anymore to execute managed code in a subthread,
3871 * so this function should not be used anymore by default: just
3872 * execute the code and then call mono_thread_manage ().
3874 void
3875 mono_runtime_exec_managed_code (MonoDomain *domain,
3876 MonoMainThreadFunc main_func,
3877 gpointer main_args)
3879 mono_thread_create (domain, main_func, main_args);
3881 mono_thread_manage ();
3885 * Execute a standard Main() method (args doesn't contain the
3886 * executable name).
3889 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3891 MonoDomain *domain;
3892 gpointer pa [1];
3893 int rval;
3894 MonoCustomAttrInfo* cinfo;
3895 gboolean has_stathread_attribute;
3896 MonoInternalThread* thread = mono_thread_internal_current ();
3898 g_assert (args);
3900 pa [0] = args;
3902 domain = mono_object_domain (args);
3903 if (!domain->entry_assembly) {
3904 gchar *str;
3905 MonoAssembly *assembly;
3907 assembly = method->klass->image->assembly;
3908 domain->entry_assembly = assembly;
3909 /* Domains created from another domain already have application_base and configuration_file set */
3910 if (domain->setup->application_base == NULL) {
3911 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3914 if (domain->setup->configuration_file == NULL) {
3915 str = g_strconcat (assembly->image->name, ".config", NULL);
3916 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3917 g_free (str);
3918 mono_set_private_bin_path_from_config (domain);
3922 cinfo = mono_custom_attrs_from_method (method);
3923 if (cinfo) {
3924 static MonoClass *stathread_attribute = NULL;
3925 if (!stathread_attribute)
3926 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3927 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3928 if (!cinfo->cached)
3929 mono_custom_attrs_free (cinfo);
3930 } else {
3931 has_stathread_attribute = FALSE;
3933 if (has_stathread_attribute) {
3934 thread->apartment_state = ThreadApartmentState_STA;
3935 } else {
3936 thread->apartment_state = ThreadApartmentState_MTA;
3938 mono_thread_init_apartment_state ();
3940 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3942 /* FIXME: check signature of method */
3943 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3944 MonoObject *res;
3945 res = mono_runtime_invoke (method, NULL, pa, exc);
3946 if (!exc || !*exc)
3947 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
3948 else
3949 rval = -1;
3951 mono_environment_exitcode_set (rval);
3952 } else {
3953 mono_runtime_invoke (method, NULL, pa, exc);
3954 if (!exc || !*exc)
3955 rval = 0;
3956 else {
3957 /* If the return type of Main is void, only
3958 * set the exitcode if an exception was thrown
3959 * (we don't want to blow away an
3960 * explicitly-set exit code)
3962 rval = -1;
3963 mono_environment_exitcode_set (rval);
3967 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
3969 return rval;
3973 * mono_install_runtime_invoke:
3974 * @func: Function to install
3976 * This is a VM internal routine
3978 void
3979 mono_install_runtime_invoke (MonoInvokeFunc func)
3981 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
3986 * mono_runtime_invoke_array:
3987 * @method: method to invoke
3988 * @obJ: object instance
3989 * @params: arguments to the method
3990 * @exc: exception information.
3992 * Invokes the method represented by @method on the object @obj.
3994 * obj is the 'this' pointer, it should be NULL for static
3995 * methods, a MonoObject* for object instances and a pointer to
3996 * the value type for value types.
3998 * The params array contains the arguments to the method with the
3999 * same convention: MonoObject* pointers for object instances and
4000 * pointers to the value type otherwise. The _invoke_array
4001 * variant takes a C# object[] as the params argument (MonoArray
4002 * *params): in this case the value types are boxed inside the
4003 * respective reference representation.
4005 * From unmanaged code you'll usually use the
4006 * mono_runtime_invoke() variant.
4008 * Note that this function doesn't handle virtual methods for
4009 * you, it will exec the exact method you pass: we still need to
4010 * expose a function to lookup the derived class implementation
4011 * of a virtual method (there are examples of this in the code,
4012 * though).
4014 * You can pass NULL as the exc argument if you don't want to
4015 * catch exceptions, otherwise, *exc will be set to the exception
4016 * thrown, if any. if an exception is thrown, you can't use the
4017 * MonoObject* result from the function.
4019 * If the method returns a value type, it is boxed in an object
4020 * reference.
4022 MonoObject*
4023 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4024 MonoObject **exc)
4026 MonoMethodSignature *sig = mono_method_signature (method);
4027 gpointer *pa = NULL;
4028 MonoObject *res;
4029 int i;
4030 gboolean has_byref_nullables = FALSE;
4032 if (NULL != params) {
4033 pa = alloca (sizeof (gpointer) * mono_array_length (params));
4034 for (i = 0; i < mono_array_length (params); i++) {
4035 MonoType *t = sig->params [i];
4037 again:
4038 switch (t->type) {
4039 case MONO_TYPE_U1:
4040 case MONO_TYPE_I1:
4041 case MONO_TYPE_BOOLEAN:
4042 case MONO_TYPE_U2:
4043 case MONO_TYPE_I2:
4044 case MONO_TYPE_CHAR:
4045 case MONO_TYPE_U:
4046 case MONO_TYPE_I:
4047 case MONO_TYPE_U4:
4048 case MONO_TYPE_I4:
4049 case MONO_TYPE_U8:
4050 case MONO_TYPE_I8:
4051 case MONO_TYPE_R4:
4052 case MONO_TYPE_R8:
4053 case MONO_TYPE_VALUETYPE:
4054 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4055 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4056 pa [i] = mono_array_get (params, MonoObject*, i);
4057 if (t->byref)
4058 has_byref_nullables = TRUE;
4059 } else {
4060 /* MS seems to create the objects if a null is passed in */
4061 if (!mono_array_get (params, MonoObject*, i))
4062 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
4064 if (t->byref) {
4066 * We can't pass the unboxed vtype byref to the callee, since
4067 * that would mean the callee would be able to modify boxed
4068 * primitive types. So we (and MS) make a copy of the boxed
4069 * object, pass that to the callee, and replace the original
4070 * boxed object in the arg array with the copy.
4072 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4073 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4074 mono_array_setref (params, i, copy);
4077 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4079 break;
4080 case MONO_TYPE_STRING:
4081 case MONO_TYPE_OBJECT:
4082 case MONO_TYPE_CLASS:
4083 case MONO_TYPE_ARRAY:
4084 case MONO_TYPE_SZARRAY:
4085 if (t->byref)
4086 pa [i] = mono_array_addr (params, MonoObject*, i);
4087 // FIXME: I need to check this code path
4088 else
4089 pa [i] = mono_array_get (params, MonoObject*, i);
4090 break;
4091 case MONO_TYPE_GENERICINST:
4092 if (t->byref)
4093 t = &t->data.generic_class->container_class->this_arg;
4094 else
4095 t = &t->data.generic_class->container_class->byval_arg;
4096 goto again;
4097 case MONO_TYPE_PTR: {
4098 MonoObject *arg;
4100 /* The argument should be an IntPtr */
4101 arg = mono_array_get (params, MonoObject*, i);
4102 if (arg == NULL) {
4103 pa [i] = NULL;
4104 } else {
4105 g_assert (arg->vtable->klass == mono_defaults.int_class);
4106 pa [i] = ((MonoIntPtr*)arg)->m_value;
4108 break;
4110 default:
4111 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4116 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4117 void *o = obj;
4119 if (mono_class_is_nullable (method->klass)) {
4120 /* Need to create a boxed vtype instead */
4121 g_assert (!obj);
4123 if (!params)
4124 return NULL;
4125 else
4126 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4129 if (!obj) {
4130 obj = mono_object_new (mono_domain_get (), method->klass);
4131 g_assert (obj); /*maybe we should raise a TLE instead?*/
4132 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4133 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4135 if (method->klass->valuetype)
4136 o = mono_object_unbox (obj);
4137 else
4138 o = obj;
4139 } else if (method->klass->valuetype) {
4140 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4143 mono_runtime_invoke (method, o, pa, exc);
4144 return obj;
4145 } else {
4146 if (mono_class_is_nullable (method->klass)) {
4147 MonoObject *nullable;
4149 /* Convert the unboxed vtype into a Nullable structure */
4150 nullable = mono_object_new (mono_domain_get (), method->klass);
4152 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4153 obj = mono_object_unbox (nullable);
4156 /* obj must be already unboxed if needed */
4157 res = mono_runtime_invoke (method, obj, pa, exc);
4159 if (sig->ret->type == MONO_TYPE_PTR) {
4160 MonoClass *pointer_class;
4161 static MonoMethod *box_method;
4162 void *box_args [2];
4163 MonoObject *box_exc;
4166 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4167 * convert it to a Pointer object.
4169 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4170 if (!box_method)
4171 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4173 g_assert (res->vtable->klass == mono_defaults.int_class);
4174 box_args [0] = ((MonoIntPtr*)res)->m_value;
4175 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4176 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4177 g_assert (!box_exc);
4180 if (has_byref_nullables) {
4182 * The runtime invoke wrapper already converted byref nullables back,
4183 * and stored them in pa, we just need to copy them back to the
4184 * managed array.
4186 for (i = 0; i < mono_array_length (params); i++) {
4187 MonoType *t = sig->params [i];
4189 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4190 mono_array_setref (params, i, pa [i]);
4194 return res;
4198 static void
4199 arith_overflow (void)
4201 mono_raise_exception (mono_get_exception_overflow ());
4205 * mono_object_allocate:
4206 * @size: number of bytes to allocate
4208 * This is a very simplistic routine until we have our GC-aware
4209 * memory allocator.
4211 * Returns: an allocated object of size @size, or NULL on failure.
4213 static inline void *
4214 mono_object_allocate (size_t size, MonoVTable *vtable)
4216 MonoObject *o;
4217 mono_stats.new_object_count++;
4218 ALLOC_OBJECT (o, vtable, size);
4220 return o;
4224 * mono_object_allocate_ptrfree:
4225 * @size: number of bytes to allocate
4227 * Note that the memory allocated is not zeroed.
4228 * Returns: an allocated object of size @size, or NULL on failure.
4230 static inline void *
4231 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
4233 MonoObject *o;
4234 mono_stats.new_object_count++;
4235 ALLOC_PTRFREE (o, vtable, size);
4236 return o;
4239 static inline void *
4240 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
4242 void *o;
4243 ALLOC_TYPED (o, size, vtable);
4244 mono_stats.new_object_count++;
4246 return o;
4250 * mono_object_new:
4251 * @klass: the class of the object that we want to create
4253 * Returns: a newly created object whose definition is
4254 * looked up using @klass. This will not invoke any constructors,
4255 * so the consumer of this routine has to invoke any constructors on
4256 * its own to initialize the object.
4258 * It returns NULL on failure.
4260 MonoObject *
4261 mono_object_new (MonoDomain *domain, MonoClass *klass)
4263 MonoVTable *vtable;
4265 MONO_ARCH_SAVE_REGS;
4266 vtable = mono_class_vtable (domain, klass);
4267 if (!vtable)
4268 return NULL;
4269 return mono_object_new_specific (vtable);
4273 * mono_object_new_pinned:
4275 * Same as mono_object_new, but the returned object will be pinned.
4276 * For SGEN, these objects will only be freed at appdomain unload.
4278 MonoObject *
4279 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass)
4281 MonoVTable *vtable;
4283 MONO_ARCH_SAVE_REGS;
4284 vtable = mono_class_vtable (domain, klass);
4285 if (!vtable)
4286 return NULL;
4288 #ifdef HAVE_SGEN_GC
4289 return mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4290 #else
4291 return mono_object_new_specific (vtable);
4292 #endif
4296 * mono_object_new_specific:
4297 * @vtable: the vtable of the object that we want to create
4299 * Returns: A newly created object with class and domain specified
4300 * by @vtable
4302 MonoObject *
4303 mono_object_new_specific (MonoVTable *vtable)
4305 MonoObject *o;
4307 MONO_ARCH_SAVE_REGS;
4309 /* check for is_com_object for COM Interop */
4310 if (vtable->remote || vtable->klass->is_com_object)
4312 gpointer pa [1];
4313 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4315 if (im == NULL) {
4316 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4318 if (!klass->inited)
4319 mono_class_init (klass);
4321 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4322 g_assert (im);
4323 vtable->domain->create_proxy_for_type_method = im;
4326 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4328 o = mono_runtime_invoke (im, NULL, pa, NULL);
4329 if (o != NULL) return o;
4332 return mono_object_new_alloc_specific (vtable);
4335 MonoObject *
4336 mono_object_new_alloc_specific (MonoVTable *vtable)
4338 MonoObject *o;
4340 if (!vtable->klass->has_references) {
4341 o = mono_object_new_ptrfree (vtable);
4342 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4343 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
4344 } else {
4345 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4346 o = mono_object_allocate (vtable->klass->instance_size, vtable);
4348 if (G_UNLIKELY (vtable->klass->has_finalize))
4349 mono_object_register_finalizer (o);
4351 if (G_UNLIKELY (profile_allocs))
4352 mono_profiler_allocation (o, vtable->klass);
4353 return o;
4356 MonoObject*
4357 mono_object_new_fast (MonoVTable *vtable)
4359 MonoObject *o;
4360 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
4361 return o;
4364 static MonoObject*
4365 mono_object_new_ptrfree (MonoVTable *vtable)
4367 MonoObject *obj;
4368 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4369 #if NEED_TO_ZERO_PTRFREE
4370 /* an inline memset is much faster for the common vcase of small objects
4371 * note we assume the allocated size is a multiple of sizeof (void*).
4373 if (vtable->klass->instance_size < 128) {
4374 gpointer *p, *end;
4375 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
4376 p = (gpointer*)((char*)obj + sizeof (MonoObject));
4377 while (p < end) {
4378 *p = NULL;
4379 ++p;
4381 } else {
4382 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
4384 #endif
4385 return obj;
4388 static MonoObject*
4389 mono_object_new_ptrfree_box (MonoVTable *vtable)
4391 MonoObject *obj;
4392 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4393 /* the object will be boxed right away, no need to memzero it */
4394 return obj;
4398 * mono_class_get_allocation_ftn:
4399 * @vtable: vtable
4400 * @for_box: the object will be used for boxing
4401 * @pass_size_in_words:
4403 * Return the allocation function appropriate for the given class.
4406 void*
4407 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4409 *pass_size_in_words = FALSE;
4411 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4412 profile_allocs = FALSE;
4414 if (mono_class_has_finalizer (vtable->klass) || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4415 return mono_object_new_specific;
4417 if (!vtable->klass->has_references) {
4418 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
4419 if (for_box)
4420 return mono_object_new_ptrfree_box;
4421 return mono_object_new_ptrfree;
4424 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4426 return mono_object_new_fast;
4429 * FIXME: This is actually slower than mono_object_new_fast, because
4430 * of the overhead of parameter passing.
4433 *pass_size_in_words = TRUE;
4434 #ifdef GC_REDIRECT_TO_LOCAL
4435 return GC_local_gcj_fast_malloc;
4436 #else
4437 return GC_gcj_fast_malloc;
4438 #endif
4442 return mono_object_new_specific;
4446 * mono_object_new_from_token:
4447 * @image: Context where the type_token is hosted
4448 * @token: a token of the type that we want to create
4450 * Returns: A newly created object whose definition is
4451 * looked up using @token in the @image image
4453 MonoObject *
4454 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4456 MonoClass *class;
4458 class = mono_class_get (image, token);
4460 return mono_object_new (domain, class);
4465 * mono_object_clone:
4466 * @obj: the object to clone
4468 * Returns: A newly created object who is a shallow copy of @obj
4470 MonoObject *
4471 mono_object_clone (MonoObject *obj)
4473 MonoObject *o;
4474 int size = obj->vtable->klass->instance_size;
4476 o = mono_object_allocate (size, obj->vtable);
4478 if (obj->vtable->klass->has_references) {
4479 mono_gc_wbarrier_object_copy (o, obj);
4480 } else {
4481 int size = obj->vtable->klass->instance_size;
4482 /* do not copy the sync state */
4483 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
4485 if (G_UNLIKELY (profile_allocs))
4486 mono_profiler_allocation (o, obj->vtable->klass);
4488 if (obj->vtable->klass->has_finalize)
4489 mono_object_register_finalizer (o);
4490 return o;
4494 * mono_array_full_copy:
4495 * @src: source array to copy
4496 * @dest: destination array
4498 * Copies the content of one array to another with exactly the same type and size.
4500 void
4501 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4503 uintptr_t size;
4504 MonoClass *klass = src->obj.vtable->klass;
4506 MONO_ARCH_SAVE_REGS;
4508 g_assert (klass == dest->obj.vtable->klass);
4510 size = mono_array_length (src);
4511 g_assert (size == mono_array_length (dest));
4512 size *= mono_array_element_size (klass);
4513 #ifdef HAVE_SGEN_GC
4514 if (klass->element_class->valuetype) {
4515 if (klass->element_class->has_references)
4516 mono_value_copy_array (dest, 0, mono_array_addr_with_size (src, 0, 0), mono_array_length (src));
4517 else
4518 memcpy (&dest->vector, &src->vector, size);
4519 } else {
4520 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4522 #else
4523 memcpy (&dest->vector, &src->vector, size);
4524 #endif
4528 * mono_array_clone_in_domain:
4529 * @domain: the domain in which the array will be cloned into
4530 * @array: the array to clone
4532 * This routine returns a copy of the array that is hosted on the
4533 * specified MonoDomain.
4535 MonoArray*
4536 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4538 MonoArray *o;
4539 uintptr_t size, i;
4540 uintptr_t *sizes;
4541 MonoClass *klass = array->obj.vtable->klass;
4543 MONO_ARCH_SAVE_REGS;
4545 if (array->bounds == NULL) {
4546 size = mono_array_length (array);
4547 o = mono_array_new_full (domain, klass, &size, NULL);
4549 size *= mono_array_element_size (klass);
4550 #ifdef HAVE_SGEN_GC
4551 if (klass->element_class->valuetype) {
4552 if (klass->element_class->has_references)
4553 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4554 else
4555 memcpy (&o->vector, &array->vector, size);
4556 } else {
4557 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4559 #else
4560 memcpy (&o->vector, &array->vector, size);
4561 #endif
4562 return o;
4565 sizes = alloca (klass->rank * sizeof(intptr_t) * 2);
4566 size = mono_array_element_size (klass);
4567 for (i = 0; i < klass->rank; ++i) {
4568 sizes [i] = array->bounds [i].length;
4569 size *= array->bounds [i].length;
4570 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4572 o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
4573 #ifdef HAVE_SGEN_GC
4574 if (klass->element_class->valuetype) {
4575 if (klass->element_class->has_references)
4576 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4577 else
4578 memcpy (&o->vector, &array->vector, size);
4579 } else {
4580 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4582 #else
4583 memcpy (&o->vector, &array->vector, size);
4584 #endif
4586 return o;
4590 * mono_array_clone:
4591 * @array: the array to clone
4593 * Returns: A newly created array who is a shallow copy of @array
4595 MonoArray*
4596 mono_array_clone (MonoArray *array)
4598 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4601 /* helper macros to check for overflow when calculating the size of arrays */
4602 #ifdef MONO_BIG_ARRAYS
4603 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4604 #define MYGUINT_MAX MYGUINT64_MAX
4605 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4606 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4607 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4608 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4609 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4610 #else
4611 #define MYGUINT32_MAX 4294967295U
4612 #define MYGUINT_MAX MYGUINT32_MAX
4613 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4614 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4615 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4616 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4617 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4618 #endif
4620 gboolean
4621 mono_array_calc_byte_len (MonoClass *class, uintptr_t len, uintptr_t *res)
4623 uintptr_t byte_len;
4625 byte_len = mono_array_element_size (class);
4626 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4627 return FALSE;
4628 byte_len *= len;
4629 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4630 return FALSE;
4631 byte_len += sizeof (MonoArray);
4633 *res = byte_len;
4635 return TRUE;
4639 * mono_array_new_full:
4640 * @domain: domain where the object is created
4641 * @array_class: array class
4642 * @lengths: lengths for each dimension in the array
4643 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4645 * This routine creates a new array objects with the given dimensions,
4646 * lower bounds and type.
4648 MonoArray*
4649 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4651 uintptr_t byte_len, len, bounds_size;
4652 MonoObject *o;
4653 MonoArray *array;
4654 MonoArrayBounds *bounds;
4655 MonoVTable *vtable;
4656 int i;
4658 if (!array_class->inited)
4659 mono_class_init (array_class);
4661 len = 1;
4663 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4664 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4665 len = lengths [0];
4666 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4667 arith_overflow ();
4668 bounds_size = 0;
4669 } else {
4670 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4672 for (i = 0; i < array_class->rank; ++i) {
4673 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4674 arith_overflow ();
4675 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4676 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4677 len *= lengths [i];
4681 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4682 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4684 if (bounds_size) {
4685 /* align */
4686 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4687 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4688 byte_len = (byte_len + 3) & ~3;
4689 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4690 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4691 byte_len += bounds_size;
4694 * Following three lines almost taken from mono_object_new ():
4695 * they need to be kept in sync.
4697 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4698 #ifndef HAVE_SGEN_GC
4699 if (!array_class->has_references) {
4700 o = mono_object_allocate_ptrfree (byte_len, vtable);
4701 #if NEED_TO_ZERO_PTRFREE
4702 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4703 #endif
4704 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4705 o = mono_object_allocate_spec (byte_len, vtable);
4706 }else {
4707 o = mono_object_allocate (byte_len, vtable);
4710 array = (MonoArray*)o;
4711 array->max_length = len;
4713 if (bounds_size) {
4714 bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4715 array->bounds = bounds;
4717 #else
4718 if (bounds_size)
4719 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4720 else
4721 o = mono_gc_alloc_vector (vtable, byte_len, len);
4722 array = (MonoArray*)o;
4723 mono_stats.new_object_count++;
4725 bounds = array->bounds;
4726 #endif
4728 if (bounds_size) {
4729 for (i = 0; i < array_class->rank; ++i) {
4730 bounds [i].length = lengths [i];
4731 if (lower_bounds)
4732 bounds [i].lower_bound = lower_bounds [i];
4736 if (G_UNLIKELY (profile_allocs))
4737 mono_profiler_allocation (o, array_class);
4739 return array;
4743 * mono_array_new:
4744 * @domain: domain where the object is created
4745 * @eclass: element class
4746 * @n: number of array elements
4748 * This routine creates a new szarray with @n elements of type @eclass.
4750 MonoArray *
4751 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
4753 MonoClass *ac;
4755 MONO_ARCH_SAVE_REGS;
4757 ac = mono_array_class_get (eclass, 1);
4758 g_assert (ac);
4760 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4764 * mono_array_new_specific:
4765 * @vtable: a vtable in the appropriate domain for an initialized class
4766 * @n: number of array elements
4768 * This routine is a fast alternative to mono_array_new() for code which
4769 * can be sure about the domain it operates in.
4771 MonoArray *
4772 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
4774 MonoObject *o;
4775 MonoArray *ao;
4776 uintptr_t byte_len;
4778 MONO_ARCH_SAVE_REGS;
4780 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4781 arith_overflow ();
4782 return NULL;
4785 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4786 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4787 return NULL;
4789 #ifndef HAVE_SGEN_GC
4790 if (!vtable->klass->has_references) {
4791 o = mono_object_allocate_ptrfree (byte_len, vtable);
4792 #if NEED_TO_ZERO_PTRFREE
4793 ((MonoArray*)o)->bounds = NULL;
4794 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4795 #endif
4796 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4797 o = mono_object_allocate_spec (byte_len, vtable);
4798 } else {
4799 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4800 o = mono_object_allocate (byte_len, vtable);
4803 ao = (MonoArray *)o;
4804 ao->max_length = n;
4805 #else
4806 o = mono_gc_alloc_vector (vtable, byte_len, n);
4807 ao = (MonoArray*)o;
4808 mono_stats.new_object_count++;
4809 #endif
4811 if (G_UNLIKELY (profile_allocs))
4812 mono_profiler_allocation (o, vtable->klass);
4814 return ao;
4818 * mono_string_new_utf16:
4819 * @text: a pointer to an utf16 string
4820 * @len: the length of the string
4822 * Returns: A newly created string object which contains @text.
4824 MonoString *
4825 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4827 MonoString *s;
4829 s = mono_string_new_size (domain, len);
4830 g_assert (s != NULL);
4832 memcpy (mono_string_chars (s), text, len * 2);
4834 return s;
4838 * mono_string_new_size:
4839 * @text: a pointer to an utf16 string
4840 * @len: the length of the string
4842 * Returns: A newly created string object of @len
4844 MonoString *
4845 mono_string_new_size (MonoDomain *domain, gint32 len)
4847 MonoString *s;
4848 MonoVTable *vtable;
4849 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4851 /* overflow ? can't fit it, can't allocate it! */
4852 if (len > size)
4853 mono_gc_out_of_memory (-1);
4855 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4856 g_assert (vtable);
4858 #ifndef HAVE_SGEN_GC
4859 s = mono_object_allocate_ptrfree (size, vtable);
4861 s->length = len;
4862 #else
4863 s = mono_gc_alloc_string (vtable, size, len);
4864 #endif
4865 #if NEED_TO_ZERO_PTRFREE
4866 s->chars [len] = 0;
4867 #endif
4868 if (G_UNLIKELY (profile_allocs))
4869 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4871 return s;
4875 * mono_string_new_len:
4876 * @text: a pointer to an utf8 string
4877 * @length: number of bytes in @text to consider
4879 * Returns: A newly created string object which contains @text.
4881 MonoString*
4882 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4884 GError *error = NULL;
4885 MonoString *o = NULL;
4886 guint16 *ut;
4887 glong items_written;
4889 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
4891 if (!error)
4892 o = mono_string_new_utf16 (domain, ut, items_written);
4893 else
4894 g_error_free (error);
4896 g_free (ut);
4898 return o;
4902 * mono_string_new:
4903 * @text: a pointer to an utf8 string
4905 * Returns: A newly created string object which contains @text.
4907 MonoString*
4908 mono_string_new (MonoDomain *domain, const char *text)
4910 GError *error = NULL;
4911 MonoString *o = NULL;
4912 guint16 *ut;
4913 glong items_written;
4914 int l;
4916 l = strlen (text);
4918 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4920 if (!error)
4921 o = mono_string_new_utf16 (domain, ut, items_written);
4922 else
4923 g_error_free (error);
4925 g_free (ut);
4926 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4927 #if 0
4928 gunichar2 *str;
4929 const gchar *end;
4930 int len;
4931 MonoString *o = NULL;
4933 if (!g_utf8_validate (text, -1, &end))
4934 return NULL;
4936 len = g_utf8_strlen (text, -1);
4937 o = mono_string_new_size (domain, len);
4938 str = mono_string_chars (o);
4940 while (text < end) {
4941 *str++ = g_utf8_get_char (text);
4942 text = g_utf8_next_char (text);
4944 #endif
4945 return o;
4949 * mono_string_new_wrapper:
4950 * @text: pointer to utf8 characters.
4952 * Helper function to create a string object from @text in the current domain.
4954 MonoString*
4955 mono_string_new_wrapper (const char *text)
4957 MonoDomain *domain = mono_domain_get ();
4959 MONO_ARCH_SAVE_REGS;
4961 if (text)
4962 return mono_string_new (domain, text);
4964 return NULL;
4968 * mono_value_box:
4969 * @class: the class of the value
4970 * @value: a pointer to the unboxed data
4972 * Returns: A newly created object which contains @value.
4974 MonoObject *
4975 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
4977 MonoObject *res;
4978 int size;
4979 MonoVTable *vtable;
4981 g_assert (class->valuetype);
4982 if (mono_class_is_nullable (class))
4983 return mono_nullable_box (value, class);
4985 vtable = mono_class_vtable (domain, class);
4986 if (!vtable)
4987 return NULL;
4988 size = mono_class_instance_size (class);
4989 res = mono_object_new_alloc_specific (vtable);
4990 if (G_UNLIKELY (profile_allocs))
4991 mono_profiler_allocation (res, class);
4993 size = size - sizeof (MonoObject);
4995 #ifdef HAVE_SGEN_GC
4996 g_assert (size == mono_class_value_size (class, NULL));
4997 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
4998 #else
4999 #if NO_UNALIGNED_ACCESS
5000 memcpy ((char *)res + sizeof (MonoObject), value, size);
5001 #else
5002 switch (size) {
5003 case 1:
5004 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5005 break;
5006 case 2:
5007 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5008 break;
5009 case 4:
5010 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5011 break;
5012 case 8:
5013 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5014 break;
5015 default:
5016 memcpy ((char *)res + sizeof (MonoObject), value, size);
5018 #endif
5019 #endif
5020 if (class->has_finalize)
5021 mono_object_register_finalizer (res);
5022 return res;
5026 * mono_value_copy:
5027 * @dest: destination pointer
5028 * @src: source pointer
5029 * @klass: a valuetype class
5031 * Copy a valuetype from @src to @dest. This function must be used
5032 * when @klass contains references fields.
5034 void
5035 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5037 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5041 * mono_value_copy_array:
5042 * @dest: destination array
5043 * @dest_idx: index in the @dest array
5044 * @src: source pointer
5045 * @count: number of items
5047 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5048 * This function must be used when @klass contains references fields.
5049 * Overlap is handled.
5051 void
5052 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5054 int size = mono_array_element_size (dest->obj.vtable->klass);
5055 char *d = mono_array_addr_with_size (dest, size, dest_idx);
5056 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5057 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5061 * mono_object_get_domain:
5062 * @obj: object to query
5064 * Returns: the MonoDomain where the object is hosted
5066 MonoDomain*
5067 mono_object_get_domain (MonoObject *obj)
5069 return mono_object_domain (obj);
5073 * mono_object_get_class:
5074 * @obj: object to query
5076 * Returns: the MonOClass of the object.
5078 MonoClass*
5079 mono_object_get_class (MonoObject *obj)
5081 return mono_object_class (obj);
5084 * mono_object_get_size:
5085 * @o: object to query
5087 * Returns: the size, in bytes, of @o
5089 guint
5090 mono_object_get_size (MonoObject* o)
5092 MonoClass* klass = mono_object_class (o);
5093 if (klass == mono_defaults.string_class) {
5094 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5095 } else if (o->vtable->rank) {
5096 MonoArray *array = (MonoArray*)o;
5097 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
5098 if (array->bounds) {
5099 size += 3;
5100 size &= ~3;
5101 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5103 return size;
5104 } else {
5105 return mono_class_instance_size (klass);
5110 * mono_object_unbox:
5111 * @obj: object to unbox
5113 * Returns: a pointer to the start of the valuetype boxed in this
5114 * object.
5116 * This method will assert if the object passed is not a valuetype.
5118 gpointer
5119 mono_object_unbox (MonoObject *obj)
5121 /* add assert for valuetypes? */
5122 g_assert (obj->vtable->klass->valuetype);
5123 return ((char*)obj) + sizeof (MonoObject);
5127 * mono_object_isinst:
5128 * @obj: an object
5129 * @klass: a pointer to a class
5131 * Returns: @obj if @obj is derived from @klass
5133 MonoObject *
5134 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5136 if (!klass->inited)
5137 mono_class_init (klass);
5139 if (klass->marshalbyref || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5140 return mono_object_isinst_mbyref (obj, klass);
5142 if (!obj)
5143 return NULL;
5145 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5148 MonoObject *
5149 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5151 MonoVTable *vt;
5153 if (!obj)
5154 return NULL;
5156 vt = obj->vtable;
5158 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5159 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5160 return obj;
5163 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5164 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5165 return obj;
5166 } else {
5167 MonoClass *oklass = vt->klass;
5168 if ((oklass == mono_defaults.transparent_proxy_class))
5169 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5171 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5172 return obj;
5175 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5177 MonoDomain *domain = mono_domain_get ();
5178 MonoObject *res;
5179 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5180 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5181 MonoMethod *im = NULL;
5182 gpointer pa [2];
5184 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5185 im = mono_object_get_virtual_method (rp, im);
5186 g_assert (im);
5188 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5189 pa [1] = obj;
5191 res = mono_runtime_invoke (im, rp, pa, NULL);
5193 if (*(MonoBoolean *) mono_object_unbox(res)) {
5194 /* Update the vtable of the remote type, so it can safely cast to this new type */
5195 mono_upgrade_remote_class (domain, obj, klass);
5196 return obj;
5200 return NULL;
5204 * mono_object_castclass_mbyref:
5205 * @obj: an object
5206 * @klass: a pointer to a class
5208 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5210 MonoObject *
5211 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5213 if (!obj) return NULL;
5214 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5216 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5217 "System",
5218 "InvalidCastException"));
5219 return NULL;
5222 typedef struct {
5223 MonoDomain *orig_domain;
5224 MonoString *ins;
5225 MonoString *res;
5226 } LDStrInfo;
5228 static void
5229 str_lookup (MonoDomain *domain, gpointer user_data)
5231 LDStrInfo *info = user_data;
5232 if (info->res || domain == info->orig_domain)
5233 return;
5234 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5237 #ifdef HAVE_SGEN_GC
5239 static MonoString*
5240 mono_string_get_pinned (MonoString *str)
5242 int size;
5243 MonoString *news;
5244 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5245 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5246 if (news) {
5247 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5248 news->length = mono_string_length (str);
5250 return news;
5253 #else
5254 #define mono_string_get_pinned(str) (str)
5255 #endif
5257 static MonoString*
5258 mono_string_is_interned_lookup (MonoString *str, int insert)
5260 MonoGHashTable *ldstr_table;
5261 MonoString *res;
5262 MonoDomain *domain;
5264 domain = ((MonoObject *)str)->vtable->domain;
5265 ldstr_table = domain->ldstr_table;
5266 ldstr_lock ();
5267 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
5268 ldstr_unlock ();
5269 return res;
5271 if (insert) {
5272 str = mono_string_get_pinned (str);
5273 if (str)
5274 mono_g_hash_table_insert (ldstr_table, str, str);
5275 ldstr_unlock ();
5276 return str;
5277 } else {
5278 LDStrInfo ldstr_info;
5279 ldstr_info.orig_domain = domain;
5280 ldstr_info.ins = str;
5281 ldstr_info.res = NULL;
5283 mono_domain_foreach (str_lookup, &ldstr_info);
5284 if (ldstr_info.res) {
5286 * the string was already interned in some other domain:
5287 * intern it in the current one as well.
5289 mono_g_hash_table_insert (ldstr_table, str, str);
5290 ldstr_unlock ();
5291 return str;
5294 ldstr_unlock ();
5295 return NULL;
5299 * mono_string_is_interned:
5300 * @o: String to probe
5302 * Returns whether the string has been interned.
5304 MonoString*
5305 mono_string_is_interned (MonoString *o)
5307 return mono_string_is_interned_lookup (o, FALSE);
5311 * mono_string_intern:
5312 * @o: String to intern
5314 * Interns the string passed.
5315 * Returns: The interned string.
5317 MonoString*
5318 mono_string_intern (MonoString *str)
5320 return mono_string_is_interned_lookup (str, TRUE);
5324 * mono_ldstr:
5325 * @domain: the domain where the string will be used.
5326 * @image: a metadata context
5327 * @idx: index into the user string table.
5329 * Implementation for the ldstr opcode.
5330 * Returns: a loaded string from the @image/@idx combination.
5332 MonoString*
5333 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5335 MONO_ARCH_SAVE_REGS;
5337 if (image->dynamic) {
5338 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5339 return str;
5340 } else {
5341 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5342 return NULL; /*FIXME we should probably be raising an exception here*/
5343 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5348 * mono_ldstr_metadata_sig
5349 * @domain: the domain for the string
5350 * @sig: the signature of a metadata string
5352 * Returns: a MonoString for a string stored in the metadata
5354 static MonoString*
5355 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5357 const char *str = sig;
5358 MonoString *o, *interned;
5359 size_t len2;
5361 len2 = mono_metadata_decode_blob_size (str, &str);
5362 len2 >>= 1;
5364 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5365 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5367 int i;
5368 guint16 *p2 = (guint16*)mono_string_chars (o);
5369 for (i = 0; i < len2; ++i) {
5370 *p2 = GUINT16_FROM_LE (*p2);
5371 ++p2;
5374 #endif
5375 ldstr_lock ();
5376 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
5377 ldstr_unlock ();
5378 /* o will get garbage collected */
5379 return interned;
5382 o = mono_string_get_pinned (o);
5383 if (o)
5384 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5385 ldstr_unlock ();
5387 return o;
5391 * mono_string_to_utf8:
5392 * @s: a System.String
5394 * Returns the UTF8 representation for @s.
5395 * The resulting buffer needs to be freed with mono_free().
5397 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5399 char *
5400 mono_string_to_utf8 (MonoString *s)
5402 MonoError error;
5403 char *result = mono_string_to_utf8_checked (s, &error);
5405 if (!mono_error_ok (&error))
5406 mono_error_raise_exception (&error);
5407 return result;
5411 * mono_string_to_utf8_checked:
5412 * @s: a System.String
5413 * @error: a MonoError.
5415 * Converts a MonoString to its UTF8 representation. May fail; check
5416 * @error to determine whether the conversion was successful.
5417 * The resulting buffer should be freed with mono_free().
5419 char *
5420 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5422 long written = 0;
5423 char *as;
5424 GError *gerror = NULL;
5426 mono_error_init (error);
5428 if (s == NULL)
5429 return NULL;
5431 if (!s->length)
5432 return g_strdup ("");
5434 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5435 if (gerror) {
5436 mono_error_set_argument (error, "string", "%s", gerror->message);
5437 g_error_free (gerror);
5438 return NULL;
5440 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5441 if (s->length > written) {
5442 /* allocate the total length and copy the part of the string that has been converted */
5443 char *as2 = g_malloc0 (s->length);
5444 memcpy (as2, as, written);
5445 g_free (as);
5446 as = as2;
5449 return as;
5453 * mono_string_to_utf8_ignore:
5454 * @s: a MonoString
5456 * Converts a MonoString to its UTF8 representation. Will ignore
5457 * invalid surrogate pairs.
5458 * The resulting buffer should be freed with mono_free().
5461 char *
5462 mono_string_to_utf8_ignore (MonoString *s)
5464 long written = 0;
5465 char *as;
5467 if (s == NULL)
5468 return NULL;
5470 if (!s->length)
5471 return g_strdup ("");
5473 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
5475 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5476 if (s->length > written) {
5477 /* allocate the total length and copy the part of the string that has been converted */
5478 char *as2 = g_malloc0 (s->length);
5479 memcpy (as2, as, written);
5480 g_free (as);
5481 as = as2;
5484 return as;
5488 * mono_string_to_utf8_image_ignore:
5489 * @s: a System.String
5491 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
5493 char *
5494 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
5496 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
5500 * mono_string_to_utf8_mp_ignore:
5501 * @s: a System.String
5503 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
5505 char *
5506 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
5508 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
5513 * mono_string_to_utf16:
5514 * @s: a MonoString
5516 * Return an null-terminated array of the utf-16 chars
5517 * contained in @s. The result must be freed with g_free().
5518 * This is a temporary helper until our string implementation
5519 * is reworked to always include the null terminating char.
5521 mono_unichar2*
5522 mono_string_to_utf16 (MonoString *s)
5524 char *as;
5526 if (s == NULL)
5527 return NULL;
5529 as = g_malloc ((s->length * 2) + 2);
5530 as [(s->length * 2)] = '\0';
5531 as [(s->length * 2) + 1] = '\0';
5533 if (!s->length) {
5534 return (gunichar2 *)(as);
5537 memcpy (as, mono_string_chars(s), s->length * 2);
5538 return (gunichar2 *)(as);
5542 * mono_string_from_utf16:
5543 * @data: the UTF16 string (LPWSTR) to convert
5545 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5547 * Returns: a MonoString.
5549 MonoString *
5550 mono_string_from_utf16 (gunichar2 *data)
5552 MonoDomain *domain = mono_domain_get ();
5553 int len = 0;
5555 if (!data)
5556 return NULL;
5558 while (data [len]) len++;
5560 return mono_string_new_utf16 (domain, data, len);
5564 static char *
5565 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
5567 char *r;
5568 char *mp_s;
5569 int len;
5571 if (ignore_error) {
5572 r = mono_string_to_utf8_ignore (s);
5573 } else {
5574 r = mono_string_to_utf8_checked (s, error);
5575 if (!mono_error_ok (error))
5576 return NULL;
5579 if (!mp && !image)
5580 return r;
5582 len = strlen (r) + 1;
5583 if (mp)
5584 mp_s = mono_mempool_alloc (mp, len);
5585 else
5586 mp_s = mono_image_alloc (image, len);
5588 memcpy (mp_s, r, len);
5590 g_free (r);
5592 return mp_s;
5596 * mono_string_to_utf8_image:
5597 * @s: a System.String
5599 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5601 char *
5602 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5604 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
5608 * mono_string_to_utf8_mp:
5609 * @s: a System.String
5611 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5613 char *
5614 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5616 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
5620 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
5622 void
5623 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
5625 eh_callbacks = *cbs;
5628 MonoRuntimeExceptionHandlingCallbacks *
5629 mono_get_eh_callbacks (void)
5631 return &eh_callbacks;
5635 * mono_raise_exception:
5636 * @ex: exception object
5638 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5640 void
5641 mono_raise_exception (MonoException *ex)
5644 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5645 * that will cause gcc to omit the function epilog, causing problems when
5646 * the JIT tries to walk the stack, since the return address on the stack
5647 * will point into the next function in the executable, not this one.
5650 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class) {
5651 MonoInternalThread *thread = mono_thread_internal_current ();
5652 g_assert (ex->object.vtable->domain == mono_domain_get ());
5653 MONO_OBJECT_SETREF (thread, abort_exc, ex);
5656 eh_callbacks.mono_raise_exception (ex);
5660 * mono_wait_handle_new:
5661 * @domain: Domain where the object will be created
5662 * @handle: Handle for the wait handle
5664 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5666 MonoWaitHandle *
5667 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5669 MonoWaitHandle *res;
5670 gpointer params [1];
5671 static MonoMethod *handle_set;
5673 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5675 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5676 if (!handle_set)
5677 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5679 params [0] = &handle;
5680 mono_runtime_invoke (handle_set, res, params, NULL);
5682 return res;
5685 HANDLE
5686 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5688 static MonoClassField *f_os_handle;
5689 static MonoClassField *f_safe_handle;
5691 if (!f_os_handle && !f_safe_handle) {
5692 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5693 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5696 if (f_os_handle) {
5697 HANDLE retval;
5698 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5699 return retval;
5700 } else {
5701 MonoSafeHandle *sh;
5702 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5703 return sh->handle;
5708 static MonoObject*
5709 mono_runtime_capture_context (MonoDomain *domain)
5711 RuntimeInvokeFunction runtime_invoke;
5713 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5714 MonoMethod *method = mono_get_context_capture_method ();
5715 MonoMethod *wrapper;
5716 if (!method)
5717 return NULL;
5718 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5719 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5720 domain->capture_context_method = mono_compile_method (method);
5723 runtime_invoke = domain->capture_context_runtime_invoke;
5725 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5728 * mono_async_result_new:
5729 * @domain:domain where the object will be created.
5730 * @handle: wait handle.
5731 * @state: state to pass to AsyncResult
5732 * @data: C closure data.
5734 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5735 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5738 MonoAsyncResult *
5739 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5741 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5742 MonoObject *context = mono_runtime_capture_context (domain);
5743 /* we must capture the execution context from the original thread */
5744 if (context) {
5745 MONO_OBJECT_SETREF (res, execution_context, context);
5746 /* note: result may be null if the flow is suppressed */
5749 res->data = data;
5750 MONO_OBJECT_SETREF (res, object_data, object_data);
5751 MONO_OBJECT_SETREF (res, async_state, state);
5752 if (handle != NULL)
5753 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5755 res->sync_completed = FALSE;
5756 res->completed = FALSE;
5758 return res;
5761 void
5762 mono_message_init (MonoDomain *domain,
5763 MonoMethodMessage *this,
5764 MonoReflectionMethod *method,
5765 MonoArray *out_args)
5767 static MonoClass *object_array_klass;
5768 static MonoClass *byte_array_klass;
5769 static MonoClass *string_array_klass;
5770 MonoMethodSignature *sig = mono_method_signature (method->method);
5771 MonoString *name;
5772 int i, j;
5773 char **names;
5774 guint8 arg_type;
5776 if (!object_array_klass) {
5777 MonoClass *klass;
5779 klass = mono_array_class_get (mono_defaults.object_class, 1);
5780 g_assert (klass);
5782 mono_memory_barrier ();
5783 object_array_klass = klass;
5785 klass = mono_array_class_get (mono_defaults.byte_class, 1);
5786 g_assert (klass);
5788 mono_memory_barrier ();
5789 byte_array_klass = klass;
5791 klass = mono_array_class_get (mono_defaults.string_class, 1);
5792 g_assert (klass);
5794 mono_memory_barrier ();
5795 string_array_klass = klass;
5798 MONO_OBJECT_SETREF (this, method, method);
5800 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
5801 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
5802 this->async_result = NULL;
5803 this->call_type = CallType_Sync;
5805 names = g_new (char *, sig->param_count);
5806 mono_method_get_param_names (method->method, (const char **) names);
5807 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
5809 for (i = 0; i < sig->param_count; i++) {
5810 name = mono_string_new (domain, names [i]);
5811 mono_array_setref (this->names, i, name);
5814 g_free (names);
5815 for (i = 0, j = 0; i < sig->param_count; i++) {
5816 if (sig->params [i]->byref) {
5817 if (out_args) {
5818 MonoObject* arg = mono_array_get (out_args, gpointer, j);
5819 mono_array_setref (this->args, i, arg);
5820 j++;
5822 arg_type = 2;
5823 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5824 arg_type |= 1;
5825 } else {
5826 arg_type = 1;
5827 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5828 arg_type |= 4;
5830 mono_array_set (this->arg_types, guint8, i, arg_type);
5835 * mono_remoting_invoke:
5836 * @real_proxy: pointer to a RealProxy object
5837 * @msg: The MonoMethodMessage to execute
5838 * @exc: used to store exceptions
5839 * @out_args: used to store output arguments
5841 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5842 * IMessage interface and it is not trivial to extract results from there. So
5843 * we call an helper method PrivateInvoke instead of calling
5844 * RealProxy::Invoke() directly.
5846 * Returns: the result object.
5848 MonoObject *
5849 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
5850 MonoObject **exc, MonoArray **out_args)
5852 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5853 gpointer pa [4];
5855 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5857 if (!im) {
5858 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
5859 g_assert (im);
5860 real_proxy->vtable->domain->private_invoke_method = im;
5863 pa [0] = real_proxy;
5864 pa [1] = msg;
5865 pa [2] = exc;
5866 pa [3] = out_args;
5868 return mono_runtime_invoke (im, NULL, pa, exc);
5871 MonoObject *
5872 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
5873 MonoObject **exc, MonoArray **out_args)
5875 static MonoClass *object_array_klass;
5876 MonoDomain *domain;
5877 MonoMethod *method;
5878 MonoMethodSignature *sig;
5879 MonoObject *ret;
5880 int i, j, outarg_count = 0;
5882 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5884 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
5885 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5886 target = tp->rp->unwrapped_server;
5887 } else {
5888 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
5892 domain = mono_domain_get ();
5893 method = msg->method->method;
5894 sig = mono_method_signature (method);
5896 for (i = 0; i < sig->param_count; i++) {
5897 if (sig->params [i]->byref)
5898 outarg_count++;
5901 if (!object_array_klass) {
5902 MonoClass *klass;
5904 klass = mono_array_class_get (mono_defaults.object_class, 1);
5905 g_assert (klass);
5907 mono_memory_barrier ();
5908 object_array_klass = klass;
5911 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
5912 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
5913 *exc = NULL;
5915 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
5917 for (i = 0, j = 0; i < sig->param_count; i++) {
5918 if (sig->params [i]->byref) {
5919 MonoObject* arg;
5920 arg = mono_array_get (msg->args, gpointer, i);
5921 mono_array_setref (*out_args, j, arg);
5922 j++;
5926 return ret;
5930 * mono_object_to_string:
5931 * @obj: The object
5932 * @exc: Any exception thrown by ToString (). May be NULL.
5934 * Returns: the result of calling ToString () on an object.
5936 MonoString *
5937 mono_object_to_string (MonoObject *obj, MonoObject **exc)
5939 static MonoMethod *to_string = NULL;
5940 MonoMethod *method;
5942 g_assert (obj);
5944 if (!to_string)
5945 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
5947 method = mono_object_get_virtual_method (obj, to_string);
5949 return (MonoString *) mono_runtime_invoke (method, obj, NULL, exc);
5953 * mono_print_unhandled_exception:
5954 * @exc: The exception
5956 * Prints the unhandled exception.
5958 void
5959 mono_print_unhandled_exception (MonoObject *exc)
5961 MonoString * str;
5962 char *message = (char*)"";
5963 gboolean free_message = FALSE;
5964 MonoError error;
5966 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
5967 message = g_strdup ("OutOfMemoryException");
5968 } else {
5969 str = mono_object_to_string (exc, NULL);
5970 if (str) {
5971 message = mono_string_to_utf8_checked (str, &error);
5972 if (!mono_error_ok (&error)) {
5973 mono_error_cleanup (&error);
5974 message = (char *) "";
5975 } else {
5976 free_message = TRUE;
5982 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
5983 * exc->vtable->klass->name, message);
5985 g_printerr ("\nUnhandled Exception: %s\n", message);
5987 if (free_message)
5988 g_free (message);
5992 * mono_delegate_ctor:
5993 * @this: pointer to an uninitialized delegate object
5994 * @target: target object
5995 * @addr: pointer to native code
5996 * @method: method
5998 * Initialize a delegate and sets a specific method, not the one
5999 * associated with addr. This is useful when sharing generic code.
6000 * In that case addr will most probably not be associated with the
6001 * correct instantiation of the method.
6003 void
6004 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
6006 MonoDelegate *delegate = (MonoDelegate *)this;
6007 MonoClass *class;
6009 g_assert (this);
6010 g_assert (addr);
6012 if (method)
6013 delegate->method = method;
6015 class = this->vtable->klass;
6016 mono_stats.delegate_creations++;
6018 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
6019 g_assert (method);
6020 method = mono_marshal_get_remoting_invoke (method);
6021 delegate->method_ptr = mono_compile_method (method);
6022 MONO_OBJECT_SETREF (delegate, target, target);
6023 } else if (method && mono_method_signature (method)->hasthis && method->klass->valuetype) {
6024 method = mono_marshal_get_unbox_wrapper (method);
6025 delegate->method_ptr = mono_compile_method (method);
6026 MONO_OBJECT_SETREF (delegate, target, target);
6027 } else {
6028 delegate->method_ptr = addr;
6029 MONO_OBJECT_SETREF (delegate, target, target);
6032 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
6036 * mono_delegate_ctor:
6037 * @this: pointer to an uninitialized delegate object
6038 * @target: target object
6039 * @addr: pointer to native code
6041 * This is used to initialize a delegate.
6043 void
6044 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
6046 MonoDomain *domain = mono_domain_get ();
6047 MonoJitInfo *ji;
6048 MonoMethod *method = NULL;
6050 g_assert (addr);
6052 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
6053 method = ji->method;
6054 g_assert (!method->klass->generic_container);
6057 mono_delegate_ctor_with_method (this, target, addr, method);
6061 * mono_method_call_message_new:
6062 * @method: method to encapsulate
6063 * @params: parameters to the method
6064 * @invoke: optional, delegate invoke.
6065 * @cb: async callback delegate.
6066 * @state: state passed to the async callback.
6068 * Translates arguments pointers into a MonoMethodMessage.
6070 MonoMethodMessage *
6071 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
6072 MonoDelegate **cb, MonoObject **state)
6074 MonoDomain *domain = mono_domain_get ();
6075 MonoMethodSignature *sig = mono_method_signature (method);
6076 MonoMethodMessage *msg;
6077 int i, count, type;
6079 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6081 if (invoke) {
6082 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
6083 count = sig->param_count - 2;
6084 } else {
6085 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
6086 count = sig->param_count;
6089 for (i = 0; i < count; i++) {
6090 gpointer vpos;
6091 MonoClass *class;
6092 MonoObject *arg;
6094 if (sig->params [i]->byref)
6095 vpos = *((gpointer *)params [i]);
6096 else
6097 vpos = params [i];
6099 type = sig->params [i]->type;
6100 class = mono_class_from_mono_type (sig->params [i]);
6102 if (class->valuetype)
6103 arg = mono_value_box (domain, class, vpos);
6104 else
6105 arg = *((MonoObject **)vpos);
6107 mono_array_setref (msg->args, i, arg);
6110 if (cb != NULL && state != NULL) {
6111 *cb = *((MonoDelegate **)params [i]);
6112 i++;
6113 *state = *((MonoObject **)params [i]);
6116 return msg;
6120 * mono_method_return_message_restore:
6122 * Restore results from message based processing back to arguments pointers
6124 void
6125 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
6127 MonoMethodSignature *sig = mono_method_signature (method);
6128 int i, j, type, size, out_len;
6130 if (out_args == NULL)
6131 return;
6132 out_len = mono_array_length (out_args);
6133 if (out_len == 0)
6134 return;
6136 for (i = 0, j = 0; i < sig->param_count; i++) {
6137 MonoType *pt = sig->params [i];
6139 if (pt->byref) {
6140 char *arg;
6141 if (j >= out_len)
6142 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
6144 arg = mono_array_get (out_args, gpointer, j);
6145 type = pt->type;
6147 g_assert (type != MONO_TYPE_VOID);
6149 if (MONO_TYPE_IS_REFERENCE (pt)) {
6150 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
6151 } else {
6152 if (arg) {
6153 MonoClass *class = ((MonoObject*)arg)->vtable->klass;
6154 size = mono_class_value_size (class, NULL);
6155 if (class->has_references)
6156 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
6157 else
6158 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6159 } else {
6160 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6161 memset (*((gpointer *)params [i]), 0, size);
6165 j++;
6171 * mono_load_remote_field:
6172 * @this: pointer to an object
6173 * @klass: klass of the object containing @field
6174 * @field: the field to load
6175 * @res: a storage to store the result
6177 * This method is called by the runtime on attempts to load fields of
6178 * transparent proxy objects. @this points to such TP, @klass is the class of
6179 * the object containing @field. @res is a storage location which can be
6180 * used to store the result.
6182 * Returns: an address pointing to the value of field.
6184 gpointer
6185 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
6187 static MonoMethod *getter = NULL;
6188 MonoDomain *domain = mono_domain_get ();
6189 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6190 MonoClass *field_class;
6191 MonoMethodMessage *msg;
6192 MonoArray *out_args;
6193 MonoObject *exc;
6194 char* full_name;
6196 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6197 g_assert (res != NULL);
6199 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6200 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6201 return res;
6204 if (!getter) {
6205 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6206 g_assert (getter);
6209 field_class = mono_class_from_mono_type (field->type);
6211 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6212 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6213 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6215 full_name = mono_type_get_full_name (klass);
6216 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6217 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6218 g_free (full_name);
6220 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6222 if (exc) mono_raise_exception ((MonoException *)exc);
6224 if (mono_array_length (out_args) == 0)
6225 return NULL;
6227 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6229 if (field_class->valuetype) {
6230 return ((char *)*res) + sizeof (MonoObject);
6231 } else
6232 return res;
6236 * mono_load_remote_field_new:
6237 * @this:
6238 * @klass:
6239 * @field:
6241 * Missing documentation.
6243 MonoObject *
6244 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
6246 static MonoMethod *getter = NULL;
6247 MonoDomain *domain = mono_domain_get ();
6248 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6249 MonoClass *field_class;
6250 MonoMethodMessage *msg;
6251 MonoArray *out_args;
6252 MonoObject *exc, *res;
6253 char* full_name;
6255 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6257 field_class = mono_class_from_mono_type (field->type);
6259 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6260 gpointer val;
6261 if (field_class->valuetype) {
6262 res = mono_object_new (domain, field_class);
6263 val = ((gchar *) res) + sizeof (MonoObject);
6264 } else {
6265 val = &res;
6267 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6268 return res;
6271 if (!getter) {
6272 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6273 g_assert (getter);
6276 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6277 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6279 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6281 full_name = mono_type_get_full_name (klass);
6282 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6283 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6284 g_free (full_name);
6286 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6288 if (exc) mono_raise_exception ((MonoException *)exc);
6290 if (mono_array_length (out_args) == 0)
6291 res = NULL;
6292 else
6293 res = mono_array_get (out_args, MonoObject *, 0);
6295 return res;
6299 * mono_store_remote_field:
6300 * @this: pointer to an object
6301 * @klass: klass of the object containing @field
6302 * @field: the field to load
6303 * @val: the value/object to store
6305 * This method is called by the runtime on attempts to store fields of
6306 * transparent proxy objects. @this points to such TP, @klass is the class of
6307 * the object containing @field. @val is the new value to store in @field.
6309 void
6310 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
6312 static MonoMethod *setter = NULL;
6313 MonoDomain *domain = mono_domain_get ();
6314 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6315 MonoClass *field_class;
6316 MonoMethodMessage *msg;
6317 MonoArray *out_args;
6318 MonoObject *exc;
6319 MonoObject *arg;
6320 char* full_name;
6322 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6324 field_class = mono_class_from_mono_type (field->type);
6326 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6327 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6328 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6329 return;
6332 if (!setter) {
6333 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6334 g_assert (setter);
6337 if (field_class->valuetype)
6338 arg = mono_value_box (domain, field_class, val);
6339 else
6340 arg = *((MonoObject **)val);
6343 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6344 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6346 full_name = mono_type_get_full_name (klass);
6347 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6348 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6349 mono_array_setref (msg->args, 2, arg);
6350 g_free (full_name);
6352 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6354 if (exc) mono_raise_exception ((MonoException *)exc);
6358 * mono_store_remote_field_new:
6359 * @this:
6360 * @klass:
6361 * @field:
6362 * @arg:
6364 * Missing documentation
6366 void
6367 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6369 static MonoMethod *setter = NULL;
6370 MonoDomain *domain = mono_domain_get ();
6371 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6372 MonoClass *field_class;
6373 MonoMethodMessage *msg;
6374 MonoArray *out_args;
6375 MonoObject *exc;
6376 char* full_name;
6378 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6380 field_class = mono_class_from_mono_type (field->type);
6382 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6383 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6384 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6385 return;
6388 if (!setter) {
6389 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6390 g_assert (setter);
6393 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6394 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6396 full_name = mono_type_get_full_name (klass);
6397 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6398 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6399 mono_array_setref (msg->args, 2, arg);
6400 g_free (full_name);
6402 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6404 if (exc) mono_raise_exception ((MonoException *)exc);
6408 * mono_create_ftnptr:
6410 * Given a function address, create a function descriptor for it.
6411 * This is only needed on some platforms.
6413 gpointer
6414 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6416 return callbacks.create_ftnptr (domain, addr);
6420 * mono_get_addr_from_ftnptr:
6422 * Given a pointer to a function descriptor, return the function address.
6423 * This is only needed on some platforms.
6425 gpointer
6426 mono_get_addr_from_ftnptr (gpointer descr)
6428 return callbacks.get_addr_from_ftnptr (descr);
6432 * mono_string_chars:
6433 * @s: a MonoString
6435 * Returns a pointer to the UCS16 characters stored in the MonoString
6437 gunichar2 *
6438 mono_string_chars (MonoString *s)
6440 return s->chars;
6444 * mono_string_length:
6445 * @s: MonoString
6447 * Returns the lenght in characters of the string
6450 mono_string_length (MonoString *s)
6452 return s->length;
6456 * mono_array_length:
6457 * @array: a MonoArray*
6459 * Returns the total number of elements in the array. This works for
6460 * both vectors and multidimensional arrays.
6462 uintptr_t
6463 mono_array_length (MonoArray *array)
6465 return array->max_length;
6469 * mono_array_addr_with_size:
6470 * @array: a MonoArray*
6471 * @size: size of the array elements
6472 * @idx: index into the array
6474 * Returns the address of the @idx element in the array.
6476 char*
6477 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
6479 return ((char*)(array)->vector) + size * idx;