Remove SRE.UnmanagedMarshal dependency from System.Reflection.
[mono-project.git] / mono / metadata / object.c
blob435bf26f942cf995f5d659166319b70f9f625ebe
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-2011 Novell, Inc (http://www.novell.com)
10 * Copyright 2001 Xamarin Inc (http://www.xamarin.com)
12 #include <config.h>
13 #ifdef HAVE_ALLOCA_H
14 #include <alloca.h>
15 #endif
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <signal.h>
19 #include <string.h>
20 #include <mono/metadata/mono-endian.h>
21 #include <mono/metadata/tabledefs.h>
22 #include <mono/metadata/tokentype.h>
23 #include <mono/metadata/loader.h>
24 #include <mono/metadata/object.h>
25 #include <mono/metadata/gc-internal.h>
26 #include <mono/metadata/exception.h>
27 #include <mono/metadata/domain-internals.h>
28 #include "mono/metadata/metadata-internals.h"
29 #include "mono/metadata/class-internals.h"
30 #include <mono/metadata/assembly.h>
31 #include <mono/metadata/threadpool.h>
32 #include <mono/metadata/marshal.h>
33 #include "mono/metadata/debug-helpers.h"
34 #include "mono/metadata/marshal.h"
35 #include <mono/metadata/threads.h>
36 #include <mono/metadata/threads-types.h>
37 #include <mono/metadata/environment.h>
38 #include "mono/metadata/profiler-private.h"
39 #include "mono/metadata/security-manager.h"
40 #include "mono/metadata/mono-debug-debugger.h"
41 #include <mono/metadata/gc-internal.h>
42 #include <mono/metadata/verify-internals.h>
43 #include <mono/utils/strenc.h>
44 #include <mono/utils/mono-counters.h>
45 #include <mono/utils/mono-error-internals.h>
46 #include <mono/utils/mono-memory-model.h>
47 #include "cominterop.h"
49 #ifdef HAVE_BOEHM_GC
50 #define NEED_TO_ZERO_PTRFREE 1
51 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = GC_MALLOC_ATOMIC ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
52 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = GC_MALLOC ((size)); (obj)->vtable = (vt);} while (0)
53 #ifdef HAVE_GC_GCJ_MALLOC
54 #define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
55 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_GCJ_MALLOC ((size),(type)); } while (0)
56 #else
57 #define GC_NO_DESCRIPTOR (NULL)
58 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_MALLOC ((size)); *(gpointer*)dest = (type);} while (0)
59 #endif
60 #else
61 #ifdef HAVE_SGEN_GC
62 #define GC_NO_DESCRIPTOR (NULL)
63 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
64 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
65 #define ALLOC_TYPED(dest,size,type) do { (dest) = mono_gc_alloc_obj (type, size);} while (0)
66 #else
67 #define NEED_TO_ZERO_PTRFREE 1
68 #define GC_NO_DESCRIPTOR (NULL)
69 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = malloc ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
70 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = calloc (1, (size)); (obj)->vtable = (vt);} while (0)
71 #define ALLOC_TYPED(dest,size,type) do { (dest) = calloc (1, (size)); *(gpointer*)dest = (type);} while (0)
72 #endif
73 #endif
75 static MonoObject* mono_object_new_ptrfree (MonoVTable *vtable);
76 static MonoObject* mono_object_new_ptrfree_box (MonoVTable *vtable);
78 static void
79 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
81 static MonoString*
82 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig);
84 static void
85 free_main_args (void);
87 #define ldstr_lock() EnterCriticalSection (&ldstr_section)
88 #define ldstr_unlock() LeaveCriticalSection (&ldstr_section)
89 static CRITICAL_SECTION ldstr_section;
91 static gboolean profile_allocs = TRUE;
93 void
94 mono_runtime_object_init (MonoObject *this)
96 MonoMethod *method = NULL;
97 MonoClass *klass = this->vtable->klass;
99 method = mono_class_get_method_from_name (klass, ".ctor", 0);
100 if (!method)
101 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
103 if (method->klass->valuetype)
104 this = mono_object_unbox (this);
105 mono_runtime_invoke (method, this, NULL, NULL);
108 /* The pseudo algorithm for type initialization from the spec
109 Note it doesn't say anything about domains - only threads.
111 2. If the type is initialized you are done.
112 2.1. If the type is not yet initialized, try to take an
113 initialization lock.
114 2.2. If successful, record this thread as responsible for
115 initializing the type and proceed to step 2.3.
116 2.2.1. If not, see whether this thread or any thread
117 waiting for this thread to complete already holds the lock.
118 2.2.2. If so, return since blocking would create a deadlock. This thread
119 will now see an incompletely initialized state for the type,
120 but no deadlock will arise.
121 2.2.3 If not, block until the type is initialized then return.
122 2.3 Initialize the parent type and then all interfaces implemented
123 by this type.
124 2.4 Execute the type initialization code for this type.
125 2.5 Mark the type as initialized, release the initialization lock,
126 awaken any threads waiting for this type to be initialized,
127 and return.
131 typedef struct
133 guint32 initializing_tid;
134 guint32 waiting_count;
135 gboolean done;
136 CRITICAL_SECTION initialization_section;
137 } TypeInitializationLock;
139 /* for locking access to type_initialization_hash and blocked_thread_hash */
140 #define mono_type_initialization_lock() EnterCriticalSection (&type_initialization_section)
141 #define mono_type_initialization_unlock() LeaveCriticalSection (&type_initialization_section)
142 static CRITICAL_SECTION type_initialization_section;
144 /* from vtable to lock */
145 static GHashTable *type_initialization_hash;
147 /* from thread id to thread id being waited on */
148 static GHashTable *blocked_thread_hash;
150 /* Main thread */
151 static MonoThread *main_thread;
153 /* Functions supplied by the runtime */
154 static MonoRuntimeCallbacks callbacks;
157 * mono_thread_set_main:
158 * @thread: thread to set as the main thread
160 * This function can be used to instruct the runtime to treat @thread
161 * as the main thread, ie, the thread that would normally execute the Main()
162 * method. This basically means that at the end of @thread, the runtime will
163 * wait for the existing foreground threads to quit and other such details.
165 void
166 mono_thread_set_main (MonoThread *thread)
168 static gboolean registered = FALSE;
170 if (!registered) {
171 MONO_GC_REGISTER_ROOT_SINGLE (main_thread);
172 registered = TRUE;
175 main_thread = thread;
178 MonoThread*
179 mono_thread_get_main (void)
181 return main_thread;
184 void
185 mono_type_initialization_init (void)
187 InitializeCriticalSection (&type_initialization_section);
188 type_initialization_hash = g_hash_table_new (NULL, NULL);
189 blocked_thread_hash = g_hash_table_new (NULL, NULL);
190 InitializeCriticalSection (&ldstr_section);
193 void
194 mono_type_initialization_cleanup (void)
196 #if 0
197 /* This is causing race conditions with
198 * mono_release_type_locks
200 DeleteCriticalSection (&type_initialization_section);
201 g_hash_table_destroy (type_initialization_hash);
202 type_initialization_hash = NULL;
203 #endif
204 DeleteCriticalSection (&ldstr_section);
205 g_hash_table_destroy (blocked_thread_hash);
206 blocked_thread_hash = NULL;
208 free_main_args ();
212 * get_type_init_exception_for_vtable:
214 * Return the stored type initialization exception for VTABLE.
216 static MonoException*
217 get_type_init_exception_for_vtable (MonoVTable *vtable)
219 MonoDomain *domain = vtable->domain;
220 MonoClass *klass = vtable->klass;
221 MonoException *ex;
222 gchar *full_name;
224 if (!vtable->init_failed)
225 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
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 if (!vtable->init_failed)
420 vtable->initialized = 1;
421 mono_type_initialization_unlock ();
423 if (vtable->init_failed) {
424 /* Either we were the initializing thread or we waited for the initialization */
425 if (raise_exception)
426 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
427 return get_type_init_exception_for_vtable (vtable);
429 } else {
430 vtable->initialized = 1;
431 return NULL;
433 return NULL;
436 static
437 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
439 MonoVTable *vtable = (MonoVTable*)key;
441 TypeInitializationLock *lock = (TypeInitializationLock*) value;
442 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
443 lock->done = TRUE;
445 * Have to set this since it cannot be set by the normal code in
446 * mono_runtime_class_init (). In this case, the exception object is not stored,
447 * and get_type_init_exception_for_class () needs to be aware of this.
449 vtable->init_failed = 1;
450 LeaveCriticalSection (&lock->initialization_section);
451 --lock->waiting_count;
452 if (lock->waiting_count == 0) {
453 DeleteCriticalSection (&lock->initialization_section);
454 g_free (lock);
455 return TRUE;
458 return FALSE;
461 void
462 mono_release_type_locks (MonoInternalThread *thread)
464 mono_type_initialization_lock ();
465 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
466 mono_type_initialization_unlock ();
469 static gpointer
470 default_trampoline (MonoMethod *method)
472 return method;
475 static gpointer
476 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
478 g_assert_not_reached ();
480 return NULL;
483 static gpointer
484 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
486 g_error ("remoting not installed");
487 return NULL;
490 static gpointer
491 default_delegate_trampoline (MonoDomain *domain, MonoClass *klass)
493 g_assert_not_reached ();
494 return NULL;
497 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
498 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
499 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
500 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
501 static MonoImtThunkBuilder imt_thunk_builder = NULL;
502 #define ARCH_USE_IMT (imt_thunk_builder != NULL)
503 #if (MONO_IMT_SIZE > 32)
504 #error "MONO_IMT_SIZE cannot be larger than 32"
505 #endif
507 void
508 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
510 memcpy (&callbacks, cbs, sizeof (*cbs));
513 MonoRuntimeCallbacks*
514 mono_get_runtime_callbacks (void)
516 return &callbacks;
519 void
520 mono_install_trampoline (MonoTrampoline func)
522 arch_create_jit_trampoline = func? func: default_trampoline;
525 void
526 mono_install_jump_trampoline (MonoJumpTrampoline func)
528 arch_create_jump_trampoline = func? func: default_jump_trampoline;
531 void
532 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
534 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
537 void
538 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
540 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
543 void
544 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
545 imt_thunk_builder = func;
548 static MonoCompileFunc default_mono_compile_method = NULL;
551 * mono_install_compile_method:
552 * @func: function to install
554 * This is a VM internal routine
556 void
557 mono_install_compile_method (MonoCompileFunc func)
559 default_mono_compile_method = func;
563 * mono_compile_method:
564 * @method: The method to compile.
566 * This JIT-compiles the method, and returns the pointer to the native code
567 * produced.
569 gpointer
570 mono_compile_method (MonoMethod *method)
572 if (!default_mono_compile_method) {
573 g_error ("compile method called on uninitialized runtime");
574 return NULL;
576 return default_mono_compile_method (method);
579 gpointer
580 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
582 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
585 gpointer
586 mono_runtime_create_delegate_trampoline (MonoClass *klass)
588 return arch_create_delegate_trampoline (mono_domain_get (), klass);
591 static MonoFreeMethodFunc default_mono_free_method = NULL;
594 * mono_install_free_method:
595 * @func: pointer to the MonoFreeMethodFunc used to release a method
597 * This is an internal VM routine, it is used for the engines to
598 * register a handler to release the resources associated with a method.
600 * Methods are freed when no more references to the delegate that holds
601 * them are left.
603 void
604 mono_install_free_method (MonoFreeMethodFunc func)
606 default_mono_free_method = func;
610 * mono_runtime_free_method:
611 * @domain; domain where the method is hosted
612 * @method: method to release
614 * This routine is invoked to free the resources associated with
615 * a method that has been JIT compiled. This is used to discard
616 * methods that were used only temporarily (for example, used in marshalling)
619 void
620 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
622 if (default_mono_free_method != NULL)
623 default_mono_free_method (domain, method);
625 mono_method_clear_object (domain, method);
627 mono_free_method (method);
631 * The vtables in the root appdomain are assumed to be reachable by other
632 * roots, and we don't use typed allocation in the other domains.
635 /* The sync block is no longer a GC pointer */
636 #define GC_HEADER_BITMAP (0)
638 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
640 static gsize*
641 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
643 MonoClassField *field;
644 MonoClass *p;
645 guint32 pos;
646 int max_size;
648 if (static_fields)
649 max_size = mono_class_data_size (class) / sizeof (gpointer);
650 else
651 max_size = class->instance_size / sizeof (gpointer);
652 if (max_size > size) {
653 g_assert (offset <= 0);
654 bitmap = g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
655 size = max_size;
658 #ifdef HAVE_SGEN_GC
659 /*An Ephemeron cannot be marked by sgen*/
660 if (!static_fields && class->image == mono_defaults.corlib && !strcmp ("Ephemeron", class->name)) {
661 *max_set = 0;
662 memset (bitmap, 0, size / 8);
663 return bitmap;
665 #endif
667 for (p = class; p != NULL; p = p->parent) {
668 gpointer iter = NULL;
669 while ((field = mono_class_get_fields (p, &iter))) {
670 MonoType *type;
672 if (static_fields) {
673 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
674 continue;
675 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
676 continue;
677 } else {
678 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
679 continue;
681 /* FIXME: should not happen, flag as type load error */
682 if (field->type->byref)
683 break;
685 if (static_fields && field->offset == -1)
686 /* special static */
687 continue;
689 pos = field->offset / sizeof (gpointer);
690 pos += offset;
692 type = mono_type_get_underlying_type (field->type);
693 switch (type->type) {
694 case MONO_TYPE_I:
695 case MONO_TYPE_PTR:
696 case MONO_TYPE_FNPTR:
697 break;
698 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
699 case MONO_TYPE_U:
700 #ifdef HAVE_SGEN_GC
701 break;
702 #else
703 if (class->image != mono_defaults.corlib)
704 break;
705 #endif
706 case MONO_TYPE_STRING:
707 case MONO_TYPE_SZARRAY:
708 case MONO_TYPE_CLASS:
709 case MONO_TYPE_OBJECT:
710 case MONO_TYPE_ARRAY:
711 g_assert ((field->offset % sizeof(gpointer)) == 0);
713 g_assert (pos < size || pos <= max_size);
714 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
715 *max_set = MAX (*max_set, pos);
716 break;
717 case MONO_TYPE_GENERICINST:
718 if (!mono_type_generic_inst_is_valuetype (type)) {
719 g_assert ((field->offset % sizeof(gpointer)) == 0);
721 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
722 *max_set = MAX (*max_set, pos);
723 break;
724 } else {
725 /* fall through */
727 case MONO_TYPE_VALUETYPE: {
728 MonoClass *fclass = mono_class_from_mono_type (field->type);
729 if (fclass->has_references) {
730 /* remove the object header */
731 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
733 break;
735 case MONO_TYPE_I1:
736 case MONO_TYPE_U1:
737 case MONO_TYPE_I2:
738 case MONO_TYPE_U2:
739 case MONO_TYPE_I4:
740 case MONO_TYPE_U4:
741 case MONO_TYPE_I8:
742 case MONO_TYPE_U8:
743 case MONO_TYPE_R4:
744 case MONO_TYPE_R8:
745 case MONO_TYPE_BOOLEAN:
746 case MONO_TYPE_CHAR:
747 break;
748 default:
749 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
750 break;
753 if (static_fields)
754 break;
756 return bitmap;
759 #if 0
761 * similar to the above, but sets the bits in the bitmap for any non-ref field
762 * and ignores static fields
764 static gsize*
765 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
767 MonoClassField *field;
768 MonoClass *p;
769 guint32 pos, pos2;
770 int max_size;
772 max_size = class->instance_size / sizeof (gpointer);
773 if (max_size >= size) {
774 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
777 for (p = class; p != NULL; p = p->parent) {
778 gpointer iter = NULL;
779 while ((field = mono_class_get_fields (p, &iter))) {
780 MonoType *type;
782 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
783 continue;
784 /* FIXME: should not happen, flag as type load error */
785 if (field->type->byref)
786 break;
788 pos = field->offset / sizeof (gpointer);
789 pos += offset;
791 type = mono_type_get_underlying_type (field->type);
792 switch (type->type) {
793 #if SIZEOF_VOID_P == 8
794 case MONO_TYPE_I:
795 case MONO_TYPE_U:
796 case MONO_TYPE_PTR:
797 case MONO_TYPE_FNPTR:
798 #endif
799 case MONO_TYPE_I8:
800 case MONO_TYPE_U8:
801 case MONO_TYPE_R8:
802 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
803 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
804 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
806 /* fall through */
807 #if SIZEOF_VOID_P == 4
808 case MONO_TYPE_I:
809 case MONO_TYPE_U:
810 case MONO_TYPE_PTR:
811 case MONO_TYPE_FNPTR:
812 #endif
813 case MONO_TYPE_I4:
814 case MONO_TYPE_U4:
815 case MONO_TYPE_R4:
816 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
817 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
818 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
820 /* fall through */
821 case MONO_TYPE_CHAR:
822 case MONO_TYPE_I2:
823 case MONO_TYPE_U2:
824 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
825 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
826 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
828 /* fall through */
829 case MONO_TYPE_BOOLEAN:
830 case MONO_TYPE_I1:
831 case MONO_TYPE_U1:
832 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
833 break;
834 case MONO_TYPE_STRING:
835 case MONO_TYPE_SZARRAY:
836 case MONO_TYPE_CLASS:
837 case MONO_TYPE_OBJECT:
838 case MONO_TYPE_ARRAY:
839 break;
840 case MONO_TYPE_GENERICINST:
841 if (!mono_type_generic_inst_is_valuetype (type)) {
842 break;
843 } else {
844 /* fall through */
846 case MONO_TYPE_VALUETYPE: {
847 MonoClass *fclass = mono_class_from_mono_type (field->type);
848 /* remove the object header */
849 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
850 break;
852 default:
853 g_assert_not_reached ();
854 break;
858 return bitmap;
862 * mono_class_insecure_overlapping:
863 * check if a class with explicit layout has references and non-references
864 * fields overlapping.
866 * Returns: TRUE if it is insecure to load the type.
868 gboolean
869 mono_class_insecure_overlapping (MonoClass *klass)
871 int max_set = 0;
872 gsize *bitmap;
873 gsize default_bitmap [4] = {0};
874 gsize *nrbitmap;
875 gsize default_nrbitmap [4] = {0};
876 int i, insecure = FALSE;
877 return FALSE;
879 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
880 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
882 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
883 int idx = i % (sizeof (bitmap [0]) * 8);
884 if (bitmap [idx] & nrbitmap [idx]) {
885 insecure = TRUE;
886 break;
889 if (bitmap != default_bitmap)
890 g_free (bitmap);
891 if (nrbitmap != default_nrbitmap)
892 g_free (nrbitmap);
893 if (insecure) {
894 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
895 return FALSE;
897 return insecure;
899 #endif
901 MonoString*
902 mono_string_alloc (int length)
904 return mono_string_new_size (mono_domain_get (), length);
907 void
908 mono_class_compute_gc_descriptor (MonoClass *class)
910 int max_set = 0;
911 gsize *bitmap;
912 gsize default_bitmap [4] = {0};
913 static gboolean gcj_inited = FALSE;
915 if (!gcj_inited) {
916 mono_loader_lock ();
918 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
919 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
920 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
921 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
923 #ifdef HAVE_GC_GCJ_MALLOC
925 * This is not needed unless the relevant code in mono_get_allocation_ftn () is
926 * turned on.
928 #if 0
929 #ifdef GC_REDIRECT_TO_LOCAL
930 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
931 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
932 #endif
933 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
934 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
935 #endif
937 #endif
938 gcj_inited = TRUE;
939 mono_loader_unlock ();
942 if (!class->inited)
943 mono_class_init (class);
945 if (class->gc_descr_inited)
946 return;
948 class->gc_descr_inited = TRUE;
949 class->gc_descr = GC_NO_DESCRIPTOR;
951 bitmap = default_bitmap;
952 if (class == mono_defaults.string_class) {
953 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
954 } else if (class->rank) {
955 mono_class_compute_gc_descriptor (class->element_class);
956 if (!class->element_class->valuetype) {
957 gsize abm = 1;
958 class->gc_descr = mono_gc_make_descr_for_array (TRUE, &abm, 1, sizeof (gpointer));
959 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
960 class->name_space, class->name);*/
961 } else {
962 /* remove the object header */
963 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
964 class->gc_descr = mono_gc_make_descr_for_array (TRUE, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
965 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
966 class->name_space, class->name);*/
967 if (bitmap != default_bitmap)
968 g_free (bitmap);
970 } else {
971 /*static int count = 0;
972 if (count++ > 58)
973 return;*/
974 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
975 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
977 if (class->gc_descr == GC_NO_DESCRIPTOR)
978 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
980 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
981 if (bitmap != default_bitmap)
982 g_free (bitmap);
987 * field_is_special_static:
988 * @fklass: The MonoClass to look up.
989 * @field: The MonoClassField describing the field.
991 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
992 * SPECIAL_STATIC_NONE otherwise.
994 static gint32
995 field_is_special_static (MonoClass *fklass, MonoClassField *field)
997 MonoCustomAttrInfo *ainfo;
998 int i;
999 ainfo = mono_custom_attrs_from_field (fklass, field);
1000 if (!ainfo)
1001 return FALSE;
1002 for (i = 0; i < ainfo->num_attrs; ++i) {
1003 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1004 if (klass->image == mono_defaults.corlib) {
1005 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1006 mono_custom_attrs_free (ainfo);
1007 return SPECIAL_STATIC_THREAD;
1009 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1010 mono_custom_attrs_free (ainfo);
1011 return SPECIAL_STATIC_CONTEXT;
1015 mono_custom_attrs_free (ainfo);
1016 return SPECIAL_STATIC_NONE;
1019 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1020 #define mix(a,b,c) { \
1021 a -= c; a ^= rot(c, 4); c += b; \
1022 b -= a; b ^= rot(a, 6); a += c; \
1023 c -= b; c ^= rot(b, 8); b += a; \
1024 a -= c; a ^= rot(c,16); c += b; \
1025 b -= a; b ^= rot(a,19); a += c; \
1026 c -= b; c ^= rot(b, 4); b += a; \
1028 #define final(a,b,c) { \
1029 c ^= b; c -= rot(b,14); \
1030 a ^= c; a -= rot(c,11); \
1031 b ^= a; b -= rot(a,25); \
1032 c ^= b; c -= rot(b,16); \
1033 a ^= c; a -= rot(c,4); \
1034 b ^= a; b -= rot(a,14); \
1035 c ^= b; c -= rot(b,24); \
1039 * mono_method_get_imt_slot:
1041 * The IMT slot is embedded into AOTed code, so this must return the same value
1042 * for the same method across all executions. This means:
1043 * - pointers shouldn't be used as hash values.
1044 * - mono_metadata_str_hash () should be used for hashing strings.
1046 guint32
1047 mono_method_get_imt_slot (MonoMethod *method)
1049 MonoMethodSignature *sig;
1050 int hashes_count;
1051 guint32 *hashes_start, *hashes;
1052 guint32 a, b, c;
1053 int i;
1055 /* This can be used to stress tests the collision code */
1056 //return 0;
1059 * We do this to simplify generic sharing. It will hurt
1060 * performance in cases where a class implements two different
1061 * instantiations of the same generic interface.
1062 * The code in build_imt_slots () depends on this.
1064 if (method->is_inflated)
1065 method = ((MonoMethodInflated*)method)->declaring;
1067 sig = mono_method_signature (method);
1068 hashes_count = sig->param_count + 4;
1069 hashes_start = malloc (hashes_count * sizeof (guint32));
1070 hashes = hashes_start;
1072 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1073 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1074 method->klass->name_space, method->klass->name, method->name);
1077 /* Initialize hashes */
1078 hashes [0] = mono_metadata_str_hash (method->klass->name);
1079 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1080 hashes [2] = mono_metadata_str_hash (method->name);
1081 hashes [3] = mono_metadata_type_hash (sig->ret);
1082 for (i = 0; i < sig->param_count; i++) {
1083 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1086 /* Setup internal state */
1087 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1089 /* Handle most of the hashes */
1090 while (hashes_count > 3) {
1091 a += hashes [0];
1092 b += hashes [1];
1093 c += hashes [2];
1094 mix (a,b,c);
1095 hashes_count -= 3;
1096 hashes += 3;
1099 /* Handle the last 3 hashes (all the case statements fall through) */
1100 switch (hashes_count) {
1101 case 3 : c += hashes [2];
1102 case 2 : b += hashes [1];
1103 case 1 : a += hashes [0];
1104 final (a,b,c);
1105 case 0: /* nothing left to add */
1106 break;
1109 free (hashes_start);
1110 /* Report the result */
1111 return c % MONO_IMT_SIZE;
1113 #undef rot
1114 #undef mix
1115 #undef final
1117 #define DEBUG_IMT 0
1119 static void
1120 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1121 guint32 imt_slot = mono_method_get_imt_slot (method);
1122 MonoImtBuilderEntry *entry;
1124 if (slot_num >= 0 && imt_slot != slot_num) {
1125 /* we build just a single imt slot and this is not it */
1126 return;
1129 entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
1130 entry->key = method;
1131 entry->value.vtable_slot = vtable_slot;
1132 entry->next = imt_builder [imt_slot];
1133 if (imt_builder [imt_slot] != NULL) {
1134 entry->children = imt_builder [imt_slot]->children + 1;
1135 if (entry->children == 1) {
1136 mono_stats.imt_slots_with_collisions++;
1137 *imt_collisions_bitmap |= (1 << imt_slot);
1139 } else {
1140 entry->children = 0;
1141 mono_stats.imt_used_slots++;
1143 imt_builder [imt_slot] = entry;
1144 #if DEBUG_IMT
1146 char *method_name = mono_method_full_name (method, TRUE);
1147 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1148 method, method_name, imt_slot, vtable_slot, entry->children);
1149 g_free (method_name);
1151 #endif
1154 #if DEBUG_IMT
1155 static void
1156 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1157 if (e != NULL) {
1158 MonoMethod *method = e->key;
1159 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1160 message,
1161 num,
1162 method,
1163 method->klass->name_space,
1164 method->klass->name,
1165 method->name);
1166 } else {
1167 printf (" * %s: NULL\n", message);
1170 #endif
1172 static int
1173 compare_imt_builder_entries (const void *p1, const void *p2) {
1174 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1175 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1177 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1180 static int
1181 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1183 int count = end - start;
1184 int chunk_start = out_array->len;
1185 if (count < 4) {
1186 int i;
1187 for (i = start; i < end; ++i) {
1188 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1189 item->key = sorted_array [i]->key;
1190 item->value = sorted_array [i]->value;
1191 item->has_target_code = sorted_array [i]->has_target_code;
1192 item->is_equals = TRUE;
1193 if (i < end - 1)
1194 item->check_target_idx = out_array->len + 1;
1195 else
1196 item->check_target_idx = 0;
1197 g_ptr_array_add (out_array, item);
1199 } else {
1200 int middle = start + count / 2;
1201 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1203 item->key = sorted_array [middle]->key;
1204 item->is_equals = FALSE;
1205 g_ptr_array_add (out_array, item);
1206 imt_emit_ir (sorted_array, start, middle, out_array);
1207 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1209 return chunk_start;
1212 static GPtrArray*
1213 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1214 int number_of_entries = entries->children + 1;
1215 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1216 GPtrArray *result = g_ptr_array_new ();
1217 MonoImtBuilderEntry *current_entry;
1218 int i;
1220 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1221 sorted_array [i] = current_entry;
1223 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1225 /*for (i = 0; i < number_of_entries; i++) {
1226 print_imt_entry (" sorted array:", sorted_array [i], i);
1229 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1231 free (sorted_array);
1232 return result;
1235 static gpointer
1236 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1238 if (imt_builder_entry != NULL) {
1239 if (imt_builder_entry->children == 0 && !fail_tramp) {
1240 /* No collision, return the vtable slot contents */
1241 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1242 } else {
1243 /* Collision, build the thunk */
1244 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1245 gpointer result;
1246 int i;
1247 result = imt_thunk_builder (vtable, domain,
1248 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1249 for (i = 0; i < imt_ir->len; ++i)
1250 g_free (g_ptr_array_index (imt_ir, i));
1251 g_ptr_array_free (imt_ir, TRUE);
1252 return result;
1254 } else {
1255 if (fail_tramp)
1256 return fail_tramp;
1257 else
1258 /* Empty slot */
1259 return NULL;
1263 static MonoImtBuilderEntry*
1264 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1267 * LOCKING: requires the loader and domain locks.
1270 static void
1271 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1273 int i;
1274 GSList *list_item;
1275 guint32 imt_collisions_bitmap = 0;
1276 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1277 int method_count = 0;
1278 gboolean record_method_count_for_max_collisions = FALSE;
1279 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1281 #if DEBUG_IMT
1282 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1283 #endif
1284 for (i = 0; i < klass->interface_offsets_count; ++i) {
1285 MonoClass *iface = klass->interfaces_packed [i];
1286 int interface_offset = klass->interface_offsets_packed [i];
1287 int method_slot_in_interface, vt_slot;
1289 if (mono_class_has_variant_generic_params (iface))
1290 has_variant_iface = TRUE;
1292 vt_slot = interface_offset;
1293 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1294 MonoMethod *method;
1296 if (slot_num >= 0 && iface->is_inflated) {
1298 * The imt slot of the method is the same as for its declaring method,
1299 * see the comment in mono_method_get_imt_slot (), so we can
1300 * avoid inflating methods which will be discarded by
1301 * add_imt_builder_entry anyway.
1303 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1304 if (mono_method_get_imt_slot (method) != slot_num) {
1305 vt_slot ++;
1306 continue;
1309 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1310 if (method->is_generic) {
1311 has_generic_virtual = TRUE;
1312 vt_slot ++;
1313 continue;
1316 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1317 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1318 vt_slot ++;
1322 if (extra_interfaces) {
1323 int interface_offset = klass->vtable_size;
1325 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1326 MonoClass* iface = list_item->data;
1327 int method_slot_in_interface;
1328 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1329 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1330 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1332 interface_offset += iface->method.count;
1335 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1336 /* overwrite the imt slot only if we're building all the entries or if
1337 * we're building this specific one
1339 if (slot_num < 0 || i == slot_num) {
1340 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1342 if (entries) {
1343 if (imt_builder [i]) {
1344 MonoImtBuilderEntry *entry;
1346 /* Link entries with imt_builder [i] */
1347 for (entry = entries; entry->next; entry = entry->next) {
1348 #if DEBUG_IMT
1349 MonoMethod *method = (MonoMethod*)entry->key;
1350 char *method_name = mono_method_full_name (method, TRUE);
1351 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1352 g_free (method_name);
1353 #endif
1355 entry->next = imt_builder [i];
1356 entries->children += imt_builder [i]->children + 1;
1358 imt_builder [i] = entries;
1361 if (has_generic_virtual || has_variant_iface) {
1363 * There might be collisions later when the the thunk is expanded.
1365 imt_collisions_bitmap |= (1 << i);
1368 * The IMT thunk might be called with an instance of one of the
1369 * generic virtual methods, so has to fallback to the IMT trampoline.
1371 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline ? callbacks.get_imt_trampoline (i) : NULL);
1372 } else {
1373 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1375 #if DEBUG_IMT
1376 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1377 #endif
1380 if (imt_builder [i] != NULL) {
1381 int methods_in_slot = imt_builder [i]->children + 1;
1382 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1383 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1384 record_method_count_for_max_collisions = TRUE;
1386 method_count += methods_in_slot;
1390 mono_stats.imt_number_of_methods += method_count;
1391 if (record_method_count_for_max_collisions) {
1392 mono_stats.imt_method_count_when_max_collisions = method_count;
1395 for (i = 0; i < MONO_IMT_SIZE; i++) {
1396 MonoImtBuilderEntry* entry = imt_builder [i];
1397 while (entry != NULL) {
1398 MonoImtBuilderEntry* next = entry->next;
1399 g_free (entry);
1400 entry = next;
1403 free (imt_builder);
1404 /* we OR the bitmap since we may build just a single imt slot at a time */
1405 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1408 static void
1409 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1410 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1414 * mono_vtable_build_imt_slot:
1415 * @vtable: virtual object table struct
1416 * @imt_slot: slot in the IMT table
1418 * Fill the given @imt_slot in the IMT table of @vtable with
1419 * a trampoline or a thunk for the case of collisions.
1420 * This is part of the internal mono API.
1422 * LOCKING: Take the domain lock.
1424 void
1425 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1427 gpointer *imt = (gpointer*)vtable;
1428 imt -= MONO_IMT_SIZE;
1429 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1431 /* no support for extra interfaces: the proxy objects will need
1432 * to build the complete IMT
1433 * Update and heck needs to ahppen inside the proper domain lock, as all
1434 * the changes made to a MonoVTable.
1436 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1437 mono_domain_lock (vtable->domain);
1438 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1439 if (imt [imt_slot] == callbacks.get_imt_trampoline (imt_slot))
1440 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1441 mono_domain_unlock (vtable->domain);
1442 mono_loader_unlock ();
1447 * The first two free list entries both belong to the wait list: The
1448 * first entry is the pointer to the head of the list and the second
1449 * entry points to the last element. That way appending and removing
1450 * the first element are both O(1) operations.
1452 #ifdef MONO_SMALL_CONFIG
1453 #define NUM_FREE_LISTS 6
1454 #else
1455 #define NUM_FREE_LISTS 12
1456 #endif
1457 #define FIRST_FREE_LIST_SIZE 64
1458 #define MAX_WAIT_LENGTH 50
1459 #define THUNK_THRESHOLD 10
1462 * LOCKING: The domain lock must be held.
1464 static void
1465 init_thunk_free_lists (MonoDomain *domain)
1467 if (domain->thunk_free_lists)
1468 return;
1469 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1472 static int
1473 list_index_for_size (int item_size)
1475 int i = 2;
1476 int size = FIRST_FREE_LIST_SIZE;
1478 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1479 i++;
1480 size <<= 1;
1483 return i;
1487 * mono_method_alloc_generic_virtual_thunk:
1488 * @domain: a domain
1489 * @size: size in bytes
1491 * Allocs size bytes to be used for the code of a generic virtual
1492 * thunk. It's either allocated from the domain's code manager or
1493 * reused from a previously invalidated piece.
1495 * LOCKING: The domain lock must be held.
1497 gpointer
1498 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1500 static gboolean inited = FALSE;
1501 static int generic_virtual_thunks_size = 0;
1503 guint32 *p;
1504 int i;
1505 MonoThunkFreeList **l;
1507 init_thunk_free_lists (domain);
1509 size += sizeof (guint32);
1510 if (size < sizeof (MonoThunkFreeList))
1511 size = sizeof (MonoThunkFreeList);
1513 i = list_index_for_size (size);
1514 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1515 if ((*l)->size >= size) {
1516 MonoThunkFreeList *item = *l;
1517 *l = item->next;
1518 return ((guint32*)item) + 1;
1522 /* no suitable item found - search lists of larger sizes */
1523 while (++i < NUM_FREE_LISTS) {
1524 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1525 if (!item)
1526 continue;
1527 g_assert (item->size > size);
1528 domain->thunk_free_lists [i] = item->next;
1529 return ((guint32*)item) + 1;
1532 /* still nothing found - allocate it */
1533 if (!inited) {
1534 mono_counters_register ("Generic virtual thunk bytes",
1535 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1536 inited = TRUE;
1538 generic_virtual_thunks_size += size;
1540 p = mono_domain_code_reserve (domain, size);
1541 *p = size;
1543 mono_domain_lock (domain);
1544 if (!domain->generic_virtual_thunks)
1545 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1546 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1547 mono_domain_unlock (domain);
1549 return p + 1;
1553 * LOCKING: The domain lock must be held.
1555 static void
1556 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1558 guint32 *p = code;
1559 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1560 gboolean found = FALSE;
1562 mono_domain_lock (domain);
1563 if (!domain->generic_virtual_thunks)
1564 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1565 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1566 found = TRUE;
1567 mono_domain_unlock (domain);
1569 if (!found)
1570 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1571 return;
1572 init_thunk_free_lists (domain);
1574 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1575 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1576 int length = item->length;
1577 int i;
1579 /* unlink the first item from the wait list */
1580 domain->thunk_free_lists [0] = item->next;
1581 domain->thunk_free_lists [0]->length = length - 1;
1583 i = list_index_for_size (item->size);
1585 /* put it in the free list */
1586 item->next = domain->thunk_free_lists [i];
1587 domain->thunk_free_lists [i] = item;
1590 l->next = NULL;
1591 if (domain->thunk_free_lists [1]) {
1592 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1593 domain->thunk_free_lists [0]->length++;
1594 } else {
1595 g_assert (!domain->thunk_free_lists [0]);
1597 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1598 domain->thunk_free_lists [0]->length = 1;
1602 typedef struct _GenericVirtualCase {
1603 MonoMethod *method;
1604 gpointer code;
1605 int count;
1606 struct _GenericVirtualCase *next;
1607 } GenericVirtualCase;
1610 * get_generic_virtual_entries:
1612 * Return IMT entries for the generic virtual method instances and
1613 * variant interface methods for vtable slot
1614 * VTABLE_SLOT.
1616 static MonoImtBuilderEntry*
1617 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1619 GenericVirtualCase *list;
1620 MonoImtBuilderEntry *entries;
1622 mono_domain_lock (domain);
1623 if (!domain->generic_virtual_cases)
1624 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1626 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1628 entries = NULL;
1629 for (; list; list = list->next) {
1630 MonoImtBuilderEntry *entry;
1632 if (list->count < THUNK_THRESHOLD)
1633 continue;
1635 entry = g_new0 (MonoImtBuilderEntry, 1);
1636 entry->key = list->method;
1637 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1638 entry->has_target_code = 1;
1639 if (entries)
1640 entry->children = entries->children + 1;
1641 entry->next = entries;
1642 entries = entry;
1645 mono_domain_unlock (domain);
1647 /* FIXME: Leaking memory ? */
1648 return entries;
1652 * mono_method_add_generic_virtual_invocation:
1653 * @domain: a domain
1654 * @vtable_slot: pointer to the vtable slot
1655 * @method: the inflated generic virtual method
1656 * @code: the method's code
1658 * Registers a call via unmanaged code to a generic virtual method
1659 * instantiation or variant interface method. If the number of calls reaches a threshold
1660 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1661 * virtual method thunk.
1663 void
1664 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1665 gpointer *vtable_slot,
1666 MonoMethod *method, gpointer code)
1668 static gboolean inited = FALSE;
1669 static int num_added = 0;
1671 GenericVirtualCase *gvc, *list;
1672 MonoImtBuilderEntry *entries;
1673 int i;
1674 GPtrArray *sorted;
1676 mono_domain_lock (domain);
1677 if (!domain->generic_virtual_cases)
1678 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1680 /* Check whether the case was already added */
1681 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1682 gvc = list;
1683 while (gvc) {
1684 if (gvc->method == method)
1685 break;
1686 gvc = gvc->next;
1689 /* If not found, make a new one */
1690 if (!gvc) {
1691 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1692 gvc->method = method;
1693 gvc->code = code;
1694 gvc->count = 0;
1695 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1697 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1699 if (!inited) {
1700 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1701 inited = TRUE;
1703 num_added++;
1706 if (++gvc->count == THUNK_THRESHOLD) {
1707 gpointer *old_thunk = *vtable_slot;
1708 gpointer vtable_trampoline = NULL;
1709 gpointer imt_trampoline = NULL;
1711 if ((gpointer)vtable_slot < (gpointer)vtable) {
1712 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1713 int imt_slot = MONO_IMT_SIZE + displacement;
1715 /* Force the rebuild of the thunk at the next call */
1716 imt_trampoline = callbacks.get_imt_trampoline (imt_slot);
1717 *vtable_slot = imt_trampoline;
1718 } else {
1719 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline ((gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1721 entries = get_generic_virtual_entries (domain, vtable_slot);
1723 sorted = imt_sort_slot_entries (entries);
1725 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1726 vtable_trampoline);
1728 while (entries) {
1729 MonoImtBuilderEntry *next = entries->next;
1730 g_free (entries);
1731 entries = next;
1734 for (i = 0; i < sorted->len; ++i)
1735 g_free (g_ptr_array_index (sorted, i));
1736 g_ptr_array_free (sorted, TRUE);
1739 #ifndef __native_client__
1740 /* We don't re-use any thunks as there is a lot of overhead */
1741 /* to deleting and re-using code in Native Client. */
1742 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1743 invalidate_generic_virtual_thunk (domain, old_thunk);
1744 #endif
1747 mono_domain_unlock (domain);
1750 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error);
1753 * mono_class_vtable:
1754 * @domain: the application domain
1755 * @class: the class to initialize
1757 * VTables are domain specific because we create domain specific code, and
1758 * they contain the domain specific static class data.
1759 * On failure, NULL is returned, and class->exception_type is set.
1761 MonoVTable *
1762 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1764 return mono_class_vtable_full (domain, class, FALSE);
1768 * mono_class_vtable_full:
1769 * @domain: the application domain
1770 * @class: the class to initialize
1771 * @raise_on_error if an exception should be raised on failure or not
1773 * VTables are domain specific because we create domain specific code, and
1774 * they contain the domain specific static class data.
1776 MonoVTable *
1777 mono_class_vtable_full (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1779 MonoClassRuntimeInfo *runtime_info;
1781 g_assert (class);
1783 if (class->exception_type) {
1784 if (raise_on_error)
1785 mono_raise_exception (mono_class_get_exception_for_failure (class));
1786 return NULL;
1789 /* this check can be inlined in jitted code, too */
1790 runtime_info = class->runtime_info;
1791 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1792 return runtime_info->domain_vtables [domain->domain_id];
1793 return mono_class_create_runtime_vtable (domain, class, raise_on_error);
1797 * mono_class_try_get_vtable:
1798 * @domain: the application domain
1799 * @class: the class to initialize
1801 * This function tries to get the associated vtable from @class if
1802 * it was already created.
1804 MonoVTable *
1805 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1807 MonoClassRuntimeInfo *runtime_info;
1809 g_assert (class);
1811 runtime_info = class->runtime_info;
1812 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1813 return runtime_info->domain_vtables [domain->domain_id];
1814 return NULL;
1817 static MonoVTable *
1818 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1820 MonoVTable *vt;
1821 MonoClassRuntimeInfo *runtime_info, *old_info;
1822 MonoClassField *field;
1823 char *t;
1824 int i;
1825 int imt_table_bytes = 0;
1826 int gc_bits;
1827 guint32 vtable_size, class_size;
1828 guint32 cindex;
1829 gpointer iter;
1830 gpointer *interface_offsets;
1832 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1833 mono_domain_lock (domain);
1834 runtime_info = class->runtime_info;
1835 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1836 mono_domain_unlock (domain);
1837 mono_loader_unlock ();
1838 return runtime_info->domain_vtables [domain->domain_id];
1840 if (!class->inited || class->exception_type) {
1841 if (!mono_class_init (class) || class->exception_type) {
1842 mono_domain_unlock (domain);
1843 mono_loader_unlock ();
1844 if (raise_on_error)
1845 mono_raise_exception (mono_class_get_exception_for_failure (class));
1846 return NULL;
1850 /* Array types require that their element type be valid*/
1851 if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
1852 MonoClass *element_class = class->element_class;
1853 if (!element_class->inited)
1854 mono_class_init (element_class);
1856 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1857 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1858 mono_class_setup_vtable (element_class);
1860 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1861 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1862 if (class->exception_type == MONO_EXCEPTION_NONE)
1863 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1864 mono_domain_unlock (domain);
1865 mono_loader_unlock ();
1866 if (raise_on_error)
1867 mono_raise_exception (mono_class_get_exception_for_failure (class));
1868 return NULL;
1873 * For some classes, mono_class_init () already computed class->vtable_size, and
1874 * that is all that is needed because of the vtable trampolines.
1876 if (!class->vtable_size)
1877 mono_class_setup_vtable (class);
1879 if (class->generic_class && !class->vtable)
1880 mono_class_check_vtable_constraints (class, NULL);
1882 /* Initialize klass->has_finalize */
1883 mono_class_has_finalizer (class);
1885 if (class->exception_type) {
1886 mono_domain_unlock (domain);
1887 mono_loader_unlock ();
1888 if (raise_on_error)
1889 mono_raise_exception (mono_class_get_exception_for_failure (class));
1890 return NULL;
1893 if (ARCH_USE_IMT) {
1894 vtable_size = MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1895 if (class->interface_offsets_count) {
1896 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1897 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1898 mono_stats.imt_number_of_tables++;
1899 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1901 } else {
1902 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1903 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1906 mono_stats.used_class_count++;
1907 mono_stats.class_vtable_size += vtable_size;
1908 interface_offsets = mono_domain_alloc0 (domain, vtable_size);
1910 if (ARCH_USE_IMT)
1911 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1912 else
1913 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1914 vt->klass = class;
1915 vt->rank = class->rank;
1916 vt->domain = domain;
1918 mono_class_compute_gc_descriptor (class);
1920 * We can't use typed allocation in the non-root domains, since the
1921 * collector needs the GC descriptor stored in the vtable even after
1922 * the mempool containing the vtable is destroyed when the domain is
1923 * unloaded. An alternative might be to allocate vtables in the GC
1924 * heap, but this does not seem to work (it leads to crashes inside
1925 * libgc). If that approach is tried, two gc descriptors need to be
1926 * allocated for each class: one for the root domain, and one for all
1927 * other domains. The second descriptor should contain a bit for the
1928 * vtable field in MonoObject, since we can no longer assume the
1929 * vtable is reachable by other roots after the appdomain is unloaded.
1931 #ifdef HAVE_BOEHM_GC
1932 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1933 vt->gc_descr = GC_NO_DESCRIPTOR;
1934 else
1935 #endif
1936 vt->gc_descr = class->gc_descr;
1938 gc_bits = mono_gc_get_vtable_bits (class);
1939 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
1941 vt->gc_bits = gc_bits;
1943 if ((class_size = mono_class_data_size (class))) {
1944 if (class->has_static_refs) {
1945 gpointer statics_gc_descr;
1946 int max_set = 0;
1947 gsize default_bitmap [4] = {0};
1948 gsize *bitmap;
1950 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1951 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1952 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1953 vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1954 mono_domain_add_class_static_data (domain, class, vt->data, NULL);
1955 if (bitmap != default_bitmap)
1956 g_free (bitmap);
1957 } else {
1958 vt->data = mono_domain_alloc0 (domain, class_size);
1960 mono_stats.class_static_data_size += class_size;
1963 cindex = -1;
1964 iter = NULL;
1965 while ((field = mono_class_get_fields (class, &iter))) {
1966 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1967 continue;
1968 if (mono_field_is_deleted (field))
1969 continue;
1970 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1971 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1972 if (special_static != SPECIAL_STATIC_NONE) {
1973 guint32 size, offset;
1974 gint32 align;
1975 gsize default_bitmap [4] = {0};
1976 gsize *bitmap;
1977 int max_set = 0;
1978 int numbits;
1979 MonoClass *fclass;
1980 if (mono_type_is_reference (field->type)) {
1981 default_bitmap [0] = 1;
1982 numbits = 1;
1983 bitmap = default_bitmap;
1984 } else if (mono_type_is_struct (field->type)) {
1985 fclass = mono_class_from_mono_type (field->type);
1986 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1987 numbits = max_set + 1;
1988 } else {
1989 default_bitmap [0] = 0;
1990 numbits = 0;
1991 bitmap = default_bitmap;
1993 size = mono_type_size (field->type, &align);
1994 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
1995 if (!domain->special_static_fields)
1996 domain->special_static_fields = g_hash_table_new (NULL, NULL);
1997 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
1998 if (bitmap != default_bitmap)
1999 g_free (bitmap);
2001 * This marks the field as special static to speed up the
2002 * checks in mono_field_static_get/set_value ().
2004 field->offset = -1;
2005 continue;
2008 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2009 MonoClass *fklass = mono_class_from_mono_type (field->type);
2010 const char *data = mono_field_get_data (field);
2012 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2013 t = (char*)vt->data + field->offset;
2014 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2015 if (!data)
2016 continue;
2017 if (fklass->valuetype) {
2018 memcpy (t, data, mono_class_value_size (fklass, NULL));
2019 } else {
2020 /* it's a pointer type: add check */
2021 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2022 *t = *(char *)data;
2024 continue;
2028 vt->max_interface_id = class->max_interface_id;
2029 vt->interface_bitmap = class->interface_bitmap;
2031 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2032 // class->name, class->interface_offsets_count);
2034 if (! ARCH_USE_IMT) {
2035 /* initialize interface offsets */
2036 for (i = 0; i < class->interface_offsets_count; ++i) {
2037 int interface_id = class->interfaces_packed [i]->interface_id;
2038 int slot = class->interface_offsets_packed [i];
2039 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
2043 /* Initialize vtable */
2044 if (callbacks.get_vtable_trampoline) {
2045 // This also covers the AOT case
2046 for (i = 0; i < class->vtable_size; ++i) {
2047 vt->vtable [i] = callbacks.get_vtable_trampoline (i);
2049 } else {
2050 mono_class_setup_vtable (class);
2052 for (i = 0; i < class->vtable_size; ++i) {
2053 MonoMethod *cm;
2055 if ((cm = class->vtable [i]))
2056 vt->vtable [i] = arch_create_jit_trampoline (cm);
2060 if (ARCH_USE_IMT && imt_table_bytes) {
2061 /* Now that the vtable is full, we can actually fill up the IMT */
2062 if (callbacks.get_imt_trampoline) {
2063 /* lazy construction of the IMT entries enabled */
2064 for (i = 0; i < MONO_IMT_SIZE; ++i)
2065 interface_offsets [i] = callbacks.get_imt_trampoline (i);
2066 } else {
2067 build_imt (class, vt, domain, interface_offsets, NULL);
2072 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2073 * re-acquire them and check if another thread has created the vtable in the meantime.
2075 /* Special case System.MonoType to avoid infinite recursion */
2076 if (class != mono_defaults.monotype_class) {
2077 /*FIXME check for OOM*/
2078 vt->type = mono_type_get_object (domain, &class->byval_arg);
2079 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2080 /* This is unregistered in
2081 unregister_vtable_reflection_type() in
2082 domain.c. */
2083 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2086 if (class->contextbound)
2087 vt->remote = 1;
2088 else
2089 vt->remote = 0;
2091 /* class_vtable_array keeps an array of created vtables
2093 g_ptr_array_add (domain->class_vtable_array, vt);
2094 /* class->runtime_info is protected by the loader lock, both when
2095 * it it enlarged and when it is stored info.
2099 * Store the vtable in class->runtime_info.
2100 * class->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2102 mono_memory_barrier ();
2104 old_info = class->runtime_info;
2105 if (old_info && old_info->max_domain >= domain->domain_id) {
2106 /* someone already created a large enough runtime info */
2107 old_info->domain_vtables [domain->domain_id] = vt;
2108 } else {
2109 int new_size = domain->domain_id;
2110 if (old_info)
2111 new_size = MAX (new_size, old_info->max_domain);
2112 new_size++;
2113 /* make the new size a power of two */
2114 i = 2;
2115 while (new_size > i)
2116 i <<= 1;
2117 new_size = i;
2118 /* this is a bounded memory retention issue: may want to
2119 * handle it differently when we'll have a rcu-like system.
2121 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2122 runtime_info->max_domain = new_size - 1;
2123 /* copy the stuff from the older info */
2124 if (old_info) {
2125 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2127 runtime_info->domain_vtables [domain->domain_id] = vt;
2128 /* keep this last*/
2129 mono_memory_barrier ();
2130 class->runtime_info = runtime_info;
2133 if (class == mono_defaults.monotype_class) {
2134 /*FIXME check for OOM*/
2135 vt->type = mono_type_get_object (domain, &class->byval_arg);
2136 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2137 /* This is unregistered in
2138 unregister_vtable_reflection_type() in
2139 domain.c. */
2140 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2143 mono_domain_unlock (domain);
2144 mono_loader_unlock ();
2146 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
2147 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
2148 mono_raise_exception (mono_class_get_exception_for_failure (class));
2150 /* make sure the parent is initialized */
2151 /*FIXME shouldn't this fail the current type?*/
2152 if (class->parent)
2153 mono_class_vtable_full (domain, class->parent, raise_on_error);
2155 return vt;
2159 * mono_class_proxy_vtable:
2160 * @domain: the application domain
2161 * @remove_class: the remote class
2163 * Creates a vtable for transparent proxies. It is basically
2164 * a copy of the real vtable of the class wrapped in @remote_class,
2165 * but all function pointers invoke the remoting functions, and
2166 * vtable->klass points to the transparent proxy class, and not to @class.
2168 static MonoVTable *
2169 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2171 MonoError error;
2172 MonoVTable *vt, *pvt;
2173 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2174 MonoClass *k;
2175 GSList *extra_interfaces = NULL;
2176 MonoClass *class = remote_class->proxy_class;
2177 gpointer *interface_offsets;
2178 uint8_t *bitmap;
2179 int bsize;
2181 #ifdef COMPRESSED_INTERFACE_BITMAP
2182 int bcsize;
2183 #endif
2185 vt = mono_class_vtable (domain, class);
2186 g_assert (vt); /*FIXME property handle failure*/
2187 max_interface_id = vt->max_interface_id;
2189 /* Calculate vtable space for extra interfaces */
2190 for (j = 0; j < remote_class->interface_count; j++) {
2191 MonoClass* iclass = remote_class->interfaces[j];
2192 GPtrArray *ifaces;
2193 int method_count;
2195 /*FIXME test for interfaces with variant generic arguments*/
2196 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2197 continue; /* interface implemented by the class */
2198 if (g_slist_find (extra_interfaces, iclass))
2199 continue;
2201 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2203 method_count = mono_class_num_methods (iclass);
2205 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2206 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2207 if (ifaces) {
2208 for (i = 0; i < ifaces->len; ++i) {
2209 MonoClass *ic = g_ptr_array_index (ifaces, i);
2210 /*FIXME test for interfaces with variant generic arguments*/
2211 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2212 continue; /* interface implemented by the class */
2213 if (g_slist_find (extra_interfaces, ic))
2214 continue;
2215 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2216 method_count += mono_class_num_methods (ic);
2218 g_ptr_array_free (ifaces, TRUE);
2221 extra_interface_vtsize += method_count * sizeof (gpointer);
2222 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2225 if (ARCH_USE_IMT) {
2226 mono_stats.imt_number_of_tables++;
2227 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
2228 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
2229 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2230 } else {
2231 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
2232 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2235 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2237 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
2238 if (ARCH_USE_IMT)
2239 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
2240 else
2241 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
2242 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2244 pvt->klass = mono_defaults.transparent_proxy_class;
2245 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2246 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2248 /* initialize vtable */
2249 mono_class_setup_vtable (class);
2250 for (i = 0; i < class->vtable_size; ++i) {
2251 MonoMethod *cm;
2253 if ((cm = class->vtable [i]))
2254 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2255 else
2256 pvt->vtable [i] = NULL;
2259 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2260 /* create trampolines for abstract methods */
2261 for (k = class; k; k = k->parent) {
2262 MonoMethod* m;
2263 gpointer iter = NULL;
2264 while ((m = mono_class_get_methods (k, &iter)))
2265 if (!pvt->vtable [m->slot])
2266 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2270 pvt->max_interface_id = max_interface_id;
2271 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2272 #ifdef COMPRESSED_INTERFACE_BITMAP
2273 bitmap = g_malloc0 (bsize);
2274 #else
2275 bitmap = mono_domain_alloc0 (domain, bsize);
2276 #endif
2278 if (! ARCH_USE_IMT) {
2279 /* initialize interface offsets */
2280 for (i = 0; i < class->interface_offsets_count; ++i) {
2281 int interface_id = class->interfaces_packed [i]->interface_id;
2282 int slot = class->interface_offsets_packed [i];
2283 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2286 for (i = 0; i < class->interface_offsets_count; ++i) {
2287 int interface_id = class->interfaces_packed [i]->interface_id;
2288 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2291 if (extra_interfaces) {
2292 int slot = class->vtable_size;
2293 MonoClass* interf;
2294 gpointer iter;
2295 MonoMethod* cm;
2296 GSList *list_item;
2298 /* Create trampolines for the methods of the interfaces */
2299 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2300 interf = list_item->data;
2302 if (! ARCH_USE_IMT) {
2303 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2305 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2307 iter = NULL;
2308 j = 0;
2309 while ((cm = mono_class_get_methods (interf, &iter)))
2310 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2312 slot += mono_class_num_methods (interf);
2314 if (! ARCH_USE_IMT) {
2315 g_slist_free (extra_interfaces);
2319 if (ARCH_USE_IMT) {
2320 /* Now that the vtable is full, we can actually fill up the IMT */
2321 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2322 if (extra_interfaces) {
2323 g_slist_free (extra_interfaces);
2327 #ifdef COMPRESSED_INTERFACE_BITMAP
2328 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2329 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2330 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2331 g_free (bitmap);
2332 #else
2333 pvt->interface_bitmap = bitmap;
2334 #endif
2335 return pvt;
2339 * mono_class_field_is_special_static:
2341 * Returns whether @field is a thread/context static field.
2343 gboolean
2344 mono_class_field_is_special_static (MonoClassField *field)
2346 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2347 return FALSE;
2348 if (mono_field_is_deleted (field))
2349 return FALSE;
2350 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2351 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2352 return TRUE;
2354 return FALSE;
2358 * mono_class_field_get_special_static_type:
2359 * @field: The MonoClassField describing the field.
2361 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2362 * SPECIAL_STATIC_NONE otherwise.
2364 guint32
2365 mono_class_field_get_special_static_type (MonoClassField *field)
2367 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2368 return SPECIAL_STATIC_NONE;
2369 if (mono_field_is_deleted (field))
2370 return SPECIAL_STATIC_NONE;
2371 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2372 return field_is_special_static (field->parent, field);
2373 return SPECIAL_STATIC_NONE;
2377 * mono_class_has_special_static_fields:
2379 * Returns whenever @klass has any thread/context static fields.
2381 gboolean
2382 mono_class_has_special_static_fields (MonoClass *klass)
2384 MonoClassField *field;
2385 gpointer iter;
2387 iter = NULL;
2388 while ((field = mono_class_get_fields (klass, &iter))) {
2389 g_assert (field->parent == klass);
2390 if (mono_class_field_is_special_static (field))
2391 return TRUE;
2394 return FALSE;
2398 * create_remote_class_key:
2399 * Creates an array of pointers that can be used as a hash key for a remote class.
2400 * The first element of the array is the number of pointers.
2402 static gpointer*
2403 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2405 gpointer *key;
2406 int i, j;
2408 if (remote_class == NULL) {
2409 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2410 key = g_malloc (sizeof(gpointer) * 3);
2411 key [0] = GINT_TO_POINTER (2);
2412 key [1] = mono_defaults.marshalbyrefobject_class;
2413 key [2] = extra_class;
2414 } else {
2415 key = g_malloc (sizeof(gpointer) * 2);
2416 key [0] = GINT_TO_POINTER (1);
2417 key [1] = extra_class;
2419 } else {
2420 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2421 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2422 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2423 key [1] = remote_class->proxy_class;
2425 // Keep the list of interfaces sorted
2426 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2427 if (extra_class && remote_class->interfaces [i] > extra_class) {
2428 key [j++] = extra_class;
2429 extra_class = NULL;
2431 key [j] = remote_class->interfaces [i];
2433 if (extra_class)
2434 key [j] = extra_class;
2435 } else {
2436 // Replace the old class. The interface list is the same
2437 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2438 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2439 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2440 for (i = 0; i < remote_class->interface_count; i++)
2441 key [2 + i] = remote_class->interfaces [i];
2445 return key;
2449 * copy_remote_class_key:
2451 * Make a copy of KEY in the domain and return the copy.
2453 static gpointer*
2454 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2456 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2457 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2459 memcpy (mp_key, key, key_size);
2461 return mp_key;
2465 * mono_remote_class:
2466 * @domain: the application domain
2467 * @class_name: name of the remote class
2469 * Creates and initializes a MonoRemoteClass object for a remote type.
2471 * Can raise an exception on failure.
2473 MonoRemoteClass*
2474 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2476 MonoError error;
2477 MonoRemoteClass *rc;
2478 gpointer* key, *mp_key;
2479 char *name;
2481 key = create_remote_class_key (NULL, proxy_class);
2483 mono_domain_lock (domain);
2484 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2486 if (rc) {
2487 g_free (key);
2488 mono_domain_unlock (domain);
2489 return rc;
2492 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2493 if (!mono_error_ok (&error)) {
2494 g_free (key);
2495 mono_domain_unlock (domain);
2496 mono_error_raise_exception (&error);
2499 mp_key = copy_remote_class_key (domain, key);
2500 g_free (key);
2501 key = mp_key;
2503 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2504 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2505 rc->interface_count = 1;
2506 rc->interfaces [0] = proxy_class;
2507 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2508 } else {
2509 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2510 rc->interface_count = 0;
2511 rc->proxy_class = proxy_class;
2514 rc->default_vtable = NULL;
2515 rc->xdomain_vtable = NULL;
2516 rc->proxy_class_name = name;
2517 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2519 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2521 mono_domain_unlock (domain);
2522 return rc;
2526 * clone_remote_class:
2527 * Creates a copy of the remote_class, adding the provided class or interface
2529 static MonoRemoteClass*
2530 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2532 MonoRemoteClass *rc;
2533 gpointer* key, *mp_key;
2535 key = create_remote_class_key (remote_class, extra_class);
2536 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2537 if (rc != NULL) {
2538 g_free (key);
2539 return rc;
2542 mp_key = copy_remote_class_key (domain, key);
2543 g_free (key);
2544 key = mp_key;
2546 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2547 int i,j;
2548 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2549 rc->proxy_class = remote_class->proxy_class;
2550 rc->interface_count = remote_class->interface_count + 1;
2552 // Keep the list of interfaces sorted, since the hash key of
2553 // the remote class depends on this
2554 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2555 if (remote_class->interfaces [i] > extra_class && i == j)
2556 rc->interfaces [j++] = extra_class;
2557 rc->interfaces [j] = remote_class->interfaces [i];
2559 if (i == j)
2560 rc->interfaces [j] = extra_class;
2561 } else {
2562 // Replace the old class. The interface array is the same
2563 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2564 rc->proxy_class = extra_class;
2565 rc->interface_count = remote_class->interface_count;
2566 if (rc->interface_count > 0)
2567 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2570 rc->default_vtable = NULL;
2571 rc->xdomain_vtable = NULL;
2572 rc->proxy_class_name = remote_class->proxy_class_name;
2574 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2576 return rc;
2579 gpointer
2580 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2582 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2583 mono_domain_lock (domain);
2584 if (rp->target_domain_id != -1) {
2585 if (remote_class->xdomain_vtable == NULL)
2586 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2587 mono_domain_unlock (domain);
2588 mono_loader_unlock ();
2589 return remote_class->xdomain_vtable;
2591 if (remote_class->default_vtable == NULL) {
2592 MonoType *type;
2593 MonoClass *klass;
2594 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2595 klass = mono_class_from_mono_type (type);
2596 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
2597 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2598 else
2599 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2602 mono_domain_unlock (domain);
2603 mono_loader_unlock ();
2604 return remote_class->default_vtable;
2608 * mono_upgrade_remote_class:
2609 * @domain: the application domain
2610 * @tproxy: the proxy whose remote class has to be upgraded.
2611 * @klass: class to which the remote class can be casted.
2613 * Updates the vtable of the remote class by adding the necessary method slots
2614 * and interface offsets so it can be safely casted to klass. klass can be a
2615 * class or an interface.
2617 void
2618 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2620 MonoTransparentProxy *tproxy;
2621 MonoRemoteClass *remote_class;
2622 gboolean redo_vtable;
2624 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2625 mono_domain_lock (domain);
2627 tproxy = (MonoTransparentProxy*) proxy_object;
2628 remote_class = tproxy->remote_class;
2630 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2631 int i;
2632 redo_vtable = TRUE;
2633 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2634 if (remote_class->interfaces [i] == klass)
2635 redo_vtable = FALSE;
2637 else {
2638 redo_vtable = (remote_class->proxy_class != klass);
2641 if (redo_vtable) {
2642 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2643 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2646 mono_domain_unlock (domain);
2647 mono_loader_unlock ();
2652 * mono_object_get_virtual_method:
2653 * @obj: object to operate on.
2654 * @method: method
2656 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2657 * the instance of a callvirt of method.
2659 MonoMethod*
2660 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2662 MonoClass *klass;
2663 MonoMethod **vtable;
2664 gboolean is_proxy;
2665 MonoMethod *res = NULL;
2667 klass = mono_object_class (obj);
2668 if (klass == mono_defaults.transparent_proxy_class) {
2669 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2670 is_proxy = TRUE;
2671 } else {
2672 is_proxy = FALSE;
2675 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2676 return method;
2678 mono_class_setup_vtable (klass);
2679 vtable = klass->vtable;
2681 if (method->slot == -1) {
2682 /* method->slot might not be set for instances of generic methods */
2683 if (method->is_inflated) {
2684 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2685 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2686 } else {
2687 if (!is_proxy)
2688 g_assert_not_reached ();
2692 /* check method->slot is a valid index: perform isinstance? */
2693 if (method->slot != -1) {
2694 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2695 if (!is_proxy) {
2696 gboolean variance_used = FALSE;
2697 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2698 g_assert (iface_offset > 0);
2699 res = vtable [iface_offset + method->slot];
2701 } else {
2702 res = vtable [method->slot];
2706 if (is_proxy) {
2707 /* It may be an interface, abstract class method or generic method */
2708 if (!res || mono_method_signature (res)->generic_param_count)
2709 res = method;
2711 /* generic methods demand invoke_with_check */
2712 if (mono_method_signature (res)->generic_param_count)
2713 res = mono_marshal_get_remoting_invoke_with_check (res);
2714 else {
2715 #ifndef DISABLE_COM
2716 if (klass == mono_defaults.com_object_class || klass->is_com_object)
2717 res = mono_cominterop_get_invoke (res);
2718 else
2719 #endif
2720 res = mono_marshal_get_remoting_invoke (res);
2722 } else {
2723 if (method->is_inflated) {
2724 /* Have to inflate the result */
2725 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2729 g_assert (res);
2731 return res;
2734 static MonoObject*
2735 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2737 g_error ("runtime invoke called on uninitialized runtime");
2738 return NULL;
2741 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2744 * mono_runtime_invoke:
2745 * @method: method to invoke
2746 * @obJ: object instance
2747 * @params: arguments to the method
2748 * @exc: exception information.
2750 * Invokes the method represented by @method on the object @obj.
2752 * obj is the 'this' pointer, it should be NULL for static
2753 * methods, a MonoObject* for object instances and a pointer to
2754 * the value type for value types.
2756 * The params array contains the arguments to the method with the
2757 * same convention: MonoObject* pointers for object instances and
2758 * pointers to the value type otherwise.
2760 * From unmanaged code you'll usually use the
2761 * mono_runtime_invoke() variant.
2763 * Note that this function doesn't handle virtual methods for
2764 * you, it will exec the exact method you pass: we still need to
2765 * expose a function to lookup the derived class implementation
2766 * of a virtual method (there are examples of this in the code,
2767 * though).
2769 * You can pass NULL as the exc argument if you don't want to
2770 * catch exceptions, otherwise, *exc will be set to the exception
2771 * thrown, if any. if an exception is thrown, you can't use the
2772 * MonoObject* result from the function.
2774 * If the method returns a value type, it is boxed in an object
2775 * reference.
2777 MonoObject*
2778 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2780 MonoObject *result;
2782 if (mono_runtime_get_no_exec ())
2783 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2785 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2786 mono_profiler_method_start_invoke (method);
2788 result = default_mono_runtime_invoke (method, obj, params, exc);
2790 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2791 mono_profiler_method_end_invoke (method);
2793 return result;
2797 * mono_method_get_unmanaged_thunk:
2798 * @method: method to generate a thunk for.
2800 * Returns an unmanaged->managed thunk that can be used to call
2801 * a managed method directly from C.
2803 * The thunk's C signature closely matches the managed signature:
2805 * C#: public bool Equals (object obj);
2806 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2807 * MonoObject*, MonoException**);
2809 * The 1st ("this") parameter must not be used with static methods:
2811 * C#: public static bool ReferenceEquals (object a, object b);
2812 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2813 * MonoException**);
2815 * The last argument must be a non-null pointer of a MonoException* pointer.
2816 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2817 * exception has been thrown in managed code. Otherwise it will point
2818 * to the MonoException* caught by the thunk. In this case, the result of
2819 * the thunk is undefined:
2821 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2822 * MonoException *ex = NULL;
2823 * Equals func = mono_method_get_unmanaged_thunk (method);
2824 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2825 * if (ex) {
2826 * // handle exception
2829 * The calling convention of the thunk matches the platform's default
2830 * convention. This means that under Windows, C declarations must
2831 * contain the __stdcall attribute:
2833 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2834 * MonoObject*, MonoException**);
2836 * LIMITATIONS
2838 * Value type arguments and return values are treated as they were objects:
2840 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2841 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2843 * Arguments must be properly boxed upon trunk's invocation, while return
2844 * values must be unboxed.
2846 gpointer
2847 mono_method_get_unmanaged_thunk (MonoMethod *method)
2849 method = mono_marshal_get_thunk_invoke_wrapper (method);
2850 return mono_compile_method (method);
2853 static void
2854 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2856 int t;
2857 if (type->byref) {
2858 /* object fields cannot be byref, so we don't need a
2859 wbarrier here */
2860 gpointer *p = (gpointer*)dest;
2861 *p = value;
2862 return;
2864 t = type->type;
2865 handle_enum:
2866 switch (t) {
2867 case MONO_TYPE_BOOLEAN:
2868 case MONO_TYPE_I1:
2869 case MONO_TYPE_U1: {
2870 guint8 *p = (guint8*)dest;
2871 *p = value ? *(guint8*)value : 0;
2872 return;
2874 case MONO_TYPE_I2:
2875 case MONO_TYPE_U2:
2876 case MONO_TYPE_CHAR: {
2877 guint16 *p = (guint16*)dest;
2878 *p = value ? *(guint16*)value : 0;
2879 return;
2881 #if SIZEOF_VOID_P == 4
2882 case MONO_TYPE_I:
2883 case MONO_TYPE_U:
2884 #endif
2885 case MONO_TYPE_I4:
2886 case MONO_TYPE_U4: {
2887 gint32 *p = (gint32*)dest;
2888 *p = value ? *(gint32*)value : 0;
2889 return;
2891 #if SIZEOF_VOID_P == 8
2892 case MONO_TYPE_I:
2893 case MONO_TYPE_U:
2894 #endif
2895 case MONO_TYPE_I8:
2896 case MONO_TYPE_U8: {
2897 gint64 *p = (gint64*)dest;
2898 *p = value ? *(gint64*)value : 0;
2899 return;
2901 case MONO_TYPE_R4: {
2902 float *p = (float*)dest;
2903 *p = value ? *(float*)value : 0;
2904 return;
2906 case MONO_TYPE_R8: {
2907 double *p = (double*)dest;
2908 *p = value ? *(double*)value : 0;
2909 return;
2911 case MONO_TYPE_STRING:
2912 case MONO_TYPE_SZARRAY:
2913 case MONO_TYPE_CLASS:
2914 case MONO_TYPE_OBJECT:
2915 case MONO_TYPE_ARRAY:
2916 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2917 return;
2918 case MONO_TYPE_FNPTR:
2919 case MONO_TYPE_PTR: {
2920 gpointer *p = (gpointer*)dest;
2921 *p = deref_pointer? *(gpointer*)value: value;
2922 return;
2924 case MONO_TYPE_VALUETYPE:
2925 /* note that 't' and 'type->type' can be different */
2926 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2927 t = mono_class_enum_basetype (type->data.klass)->type;
2928 goto handle_enum;
2929 } else {
2930 MonoClass *class = mono_class_from_mono_type (type);
2931 int size = mono_class_value_size (class, NULL);
2932 if (value == NULL)
2933 mono_gc_bzero (dest, size);
2934 else
2935 mono_gc_wbarrier_value_copy (dest, value, 1, class);
2937 return;
2938 case MONO_TYPE_GENERICINST:
2939 t = type->data.generic_class->container_class->byval_arg.type;
2940 goto handle_enum;
2941 default:
2942 g_error ("got type %x", type->type);
2947 * mono_field_set_value:
2948 * @obj: Instance object
2949 * @field: MonoClassField describing the field to set
2950 * @value: The value to be set
2952 * Sets the value of the field described by @field in the object instance @obj
2953 * to the value passed in @value. This method should only be used for instance
2954 * fields. For static fields, use mono_field_static_set_value.
2956 * The value must be on the native format of the field type.
2958 void
2959 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2961 void *dest;
2963 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2965 dest = (char*)obj + field->offset;
2966 set_value (field->type, dest, value, FALSE);
2970 * mono_field_static_set_value:
2971 * @field: MonoClassField describing the field to set
2972 * @value: The value to be set
2974 * Sets the value of the static field described by @field
2975 * to the value passed in @value.
2977 * The value must be on the native format of the field type.
2979 void
2980 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2982 void *dest;
2984 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2985 /* you cant set a constant! */
2986 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2988 if (field->offset == -1) {
2989 /* Special static */
2990 gpointer addr;
2992 mono_domain_lock (vt->domain);
2993 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2994 mono_domain_unlock (vt->domain);
2995 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2996 } else {
2997 dest = (char*)vt->data + field->offset;
2999 set_value (field->type, dest, value, FALSE);
3002 /* Used by the debugger */
3003 void *
3004 mono_vtable_get_static_field_data (MonoVTable *vt)
3006 return vt->data;
3009 static guint8*
3010 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3012 guint8 *src;
3014 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3015 if (field->offset == -1) {
3016 /* Special static */
3017 gpointer addr;
3019 mono_domain_lock (vt->domain);
3020 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3021 mono_domain_unlock (vt->domain);
3022 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3023 } else {
3024 src = (guint8*)vt->data + field->offset;
3026 } else {
3027 src = (guint8*)obj + field->offset;
3030 return src;
3034 * mono_field_get_value:
3035 * @obj: Object instance
3036 * @field: MonoClassField describing the field to fetch information from
3037 * @value: pointer to the location where the value will be stored
3039 * Use this routine to get the value of the field @field in the object
3040 * passed.
3042 * The pointer provided by value must be of the field type, for reference
3043 * types this is a MonoObject*, for value types its the actual pointer to
3044 * the value type.
3046 * For example:
3047 * int i;
3048 * mono_field_get_value (obj, int_field, &i);
3050 void
3051 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3053 void *src;
3055 g_assert (obj);
3057 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3059 src = (char*)obj + field->offset;
3060 set_value (field->type, value, src, TRUE);
3064 * mono_field_get_value_object:
3065 * @domain: domain where the object will be created (if boxing)
3066 * @field: MonoClassField describing the field to fetch information from
3067 * @obj: The object instance for the field.
3069 * Returns: a new MonoObject with the value from the given field. If the
3070 * field represents a value type, the value is boxed.
3073 MonoObject *
3074 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3076 MonoObject *o;
3077 MonoClass *klass;
3078 MonoVTable *vtable = NULL;
3079 gchar *v;
3080 gboolean is_static = FALSE;
3081 gboolean is_ref = FALSE;
3082 gboolean is_literal = FALSE;
3083 gboolean is_ptr = FALSE;
3084 MonoError error;
3085 MonoType *type = mono_field_get_type_checked (field, &error);
3087 if (!mono_error_ok (&error))
3088 mono_error_raise_exception (&error);
3090 switch (type->type) {
3091 case MONO_TYPE_STRING:
3092 case MONO_TYPE_OBJECT:
3093 case MONO_TYPE_CLASS:
3094 case MONO_TYPE_ARRAY:
3095 case MONO_TYPE_SZARRAY:
3096 is_ref = TRUE;
3097 break;
3098 case MONO_TYPE_U1:
3099 case MONO_TYPE_I1:
3100 case MONO_TYPE_BOOLEAN:
3101 case MONO_TYPE_U2:
3102 case MONO_TYPE_I2:
3103 case MONO_TYPE_CHAR:
3104 case MONO_TYPE_U:
3105 case MONO_TYPE_I:
3106 case MONO_TYPE_U4:
3107 case MONO_TYPE_I4:
3108 case MONO_TYPE_R4:
3109 case MONO_TYPE_U8:
3110 case MONO_TYPE_I8:
3111 case MONO_TYPE_R8:
3112 case MONO_TYPE_VALUETYPE:
3113 is_ref = type->byref;
3114 break;
3115 case MONO_TYPE_GENERICINST:
3116 is_ref = !mono_type_generic_inst_is_valuetype (type);
3117 break;
3118 case MONO_TYPE_PTR:
3119 is_ptr = TRUE;
3120 break;
3121 default:
3122 g_error ("type 0x%x not handled in "
3123 "mono_field_get_value_object", type->type);
3124 return NULL;
3127 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3128 is_literal = TRUE;
3130 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3131 is_static = TRUE;
3133 if (!is_literal) {
3134 vtable = mono_class_vtable (domain, field->parent);
3135 if (!vtable) {
3136 char *name = mono_type_get_full_name (field->parent);
3137 /*FIXME extend this to use the MonoError api*/
3138 g_warning ("Could not retrieve the vtable for type %s in mono_field_get_value_object", name);
3139 g_free (name);
3140 return NULL;
3142 if (!vtable->initialized)
3143 mono_runtime_class_init (vtable);
3145 } else {
3146 g_assert (obj);
3149 if (is_ref) {
3150 if (is_literal) {
3151 get_default_field_value (domain, field, &o);
3152 } else if (is_static) {
3153 mono_field_static_get_value (vtable, field, &o);
3154 } else {
3155 mono_field_get_value (obj, field, &o);
3157 return o;
3160 if (is_ptr) {
3161 static MonoMethod *m;
3162 gpointer args [2];
3163 gpointer *ptr;
3164 gpointer v;
3166 if (!m) {
3167 MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3168 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3169 g_assert (m);
3172 v = &ptr;
3173 if (is_literal) {
3174 get_default_field_value (domain, field, v);
3175 } else if (is_static) {
3176 mono_field_static_get_value (vtable, field, v);
3177 } else {
3178 mono_field_get_value (obj, field, v);
3181 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3182 args [0] = *ptr;
3183 args [1] = mono_type_get_object (mono_domain_get (), type);
3185 return mono_runtime_invoke (m, NULL, args, NULL);
3188 /* boxed value type */
3189 klass = mono_class_from_mono_type (type);
3191 if (mono_class_is_nullable (klass))
3192 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3194 o = mono_object_new (domain, klass);
3195 v = ((gchar *) o) + sizeof (MonoObject);
3197 if (is_literal) {
3198 get_default_field_value (domain, field, v);
3199 } else if (is_static) {
3200 mono_field_static_get_value (vtable, field, v);
3201 } else {
3202 mono_field_get_value (obj, field, v);
3205 return o;
3209 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3211 int retval = 0;
3212 const char *p = blob;
3213 mono_metadata_decode_blob_size (p, &p);
3215 switch (type) {
3216 case MONO_TYPE_BOOLEAN:
3217 case MONO_TYPE_U1:
3218 case MONO_TYPE_I1:
3219 *(guint8 *) value = *p;
3220 break;
3221 case MONO_TYPE_CHAR:
3222 case MONO_TYPE_U2:
3223 case MONO_TYPE_I2:
3224 *(guint16*) value = read16 (p);
3225 break;
3226 case MONO_TYPE_U4:
3227 case MONO_TYPE_I4:
3228 *(guint32*) value = read32 (p);
3229 break;
3230 case MONO_TYPE_U8:
3231 case MONO_TYPE_I8:
3232 *(guint64*) value = read64 (p);
3233 break;
3234 case MONO_TYPE_R4:
3235 readr4 (p, (float*) value);
3236 break;
3237 case MONO_TYPE_R8:
3238 readr8 (p, (double*) value);
3239 break;
3240 case MONO_TYPE_STRING:
3241 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3242 break;
3243 case MONO_TYPE_CLASS:
3244 *(gpointer*) value = NULL;
3245 break;
3246 default:
3247 retval = -1;
3248 g_warning ("type 0x%02x should not be in constant table", type);
3250 return retval;
3253 static void
3254 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3256 MonoTypeEnum def_type;
3257 const char* data;
3259 data = mono_class_get_field_default_value (field, &def_type);
3260 mono_get_constant_value_from_blob (domain, def_type, data, value);
3263 void
3264 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3266 void *src;
3268 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3270 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3271 get_default_field_value (vt->domain, field, value);
3272 return;
3275 if (field->offset == -1) {
3276 /* Special static */
3277 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3278 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3279 } else {
3280 src = (char*)vt->data + field->offset;
3282 set_value (field->type, value, src, TRUE);
3286 * mono_field_static_get_value:
3287 * @vt: vtable to the object
3288 * @field: MonoClassField describing the field to fetch information from
3289 * @value: where the value is returned
3291 * Use this routine to get the value of the static field @field value.
3293 * The pointer provided by value must be of the field type, for reference
3294 * types this is a MonoObject*, for value types its the actual pointer to
3295 * the value type.
3297 * For example:
3298 * int i;
3299 * mono_field_static_get_value (vt, int_field, &i);
3301 void
3302 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3304 return mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3308 * mono_property_set_value:
3309 * @prop: MonoProperty to set
3310 * @obj: instance object on which to act
3311 * @params: parameters to pass to the propery
3312 * @exc: optional exception
3314 * Invokes the property's set method with the given arguments on the
3315 * object instance obj (or NULL for static properties).
3317 * You can pass NULL as the exc argument if you don't want to
3318 * catch exceptions, otherwise, *exc will be set to the exception
3319 * thrown, if any. if an exception is thrown, you can't use the
3320 * MonoObject* result from the function.
3322 void
3323 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3325 default_mono_runtime_invoke (prop->set, obj, params, exc);
3329 * mono_property_get_value:
3330 * @prop: MonoProperty to fetch
3331 * @obj: instance object on which to act
3332 * @params: parameters to pass to the propery
3333 * @exc: optional exception
3335 * Invokes the property's get method with the given arguments on the
3336 * object instance obj (or NULL for static properties).
3338 * You can pass NULL as the exc argument if you don't want to
3339 * catch exceptions, otherwise, *exc will be set to the exception
3340 * thrown, if any. if an exception is thrown, you can't use the
3341 * MonoObject* result from the function.
3343 * Returns: the value from invoking the get method on the property.
3345 MonoObject*
3346 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3348 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3352 * mono_nullable_init:
3353 * @buf: The nullable structure to initialize.
3354 * @value: the value to initialize from
3355 * @klass: the type for the object
3357 * Initialize the nullable structure pointed to by @buf from @value which
3358 * should be a boxed value type. The size of @buf should be able to hold
3359 * as much data as the @klass->instance_size (which is the number of bytes
3360 * that will be copies).
3362 * Since Nullables have variable structure, we can not define a C
3363 * structure for them.
3365 void
3366 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3368 MonoClass *param_class = klass->cast_class;
3370 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3371 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3373 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3374 if (value) {
3375 if (param_class->has_references)
3376 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3377 else
3378 mono_gc_memmove (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3379 } else {
3380 mono_gc_bzero (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3385 * mono_nullable_box:
3386 * @buf: The buffer representing the data to be boxed
3387 * @klass: the type to box it as.
3389 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3390 * @buf.
3392 MonoObject*
3393 mono_nullable_box (guint8 *buf, MonoClass *klass)
3395 MonoClass *param_class = klass->cast_class;
3397 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3398 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3400 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3401 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3402 if (param_class->has_references)
3403 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3404 else
3405 mono_gc_memmove (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3406 return o;
3408 else
3409 return NULL;
3413 * mono_get_delegate_invoke:
3414 * @klass: The delegate class
3416 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3418 MonoMethod *
3419 mono_get_delegate_invoke (MonoClass *klass)
3421 MonoMethod *im;
3423 /* This is called at runtime, so avoid the slower search in metadata */
3424 mono_class_setup_methods (klass);
3425 if (klass->exception_type)
3426 return NULL;
3427 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3428 return im;
3432 * mono_runtime_delegate_invoke:
3433 * @delegate: pointer to a delegate object.
3434 * @params: parameters for the delegate.
3435 * @exc: Pointer to the exception result.
3437 * Invokes the delegate method @delegate with the parameters provided.
3439 * You can pass NULL as the exc argument if you don't want to
3440 * catch exceptions, otherwise, *exc will be set to the exception
3441 * thrown, if any. if an exception is thrown, you can't use the
3442 * MonoObject* result from the function.
3444 MonoObject*
3445 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3447 MonoMethod *im;
3448 MonoClass *klass = delegate->vtable->klass;
3450 im = mono_get_delegate_invoke (klass);
3451 if (!im)
3452 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3454 return mono_runtime_invoke (im, delegate, params, exc);
3457 static char **main_args = NULL;
3458 static int num_main_args;
3461 * mono_runtime_get_main_args:
3463 * Returns: a MonoArray with the arguments passed to the main program
3465 MonoArray*
3466 mono_runtime_get_main_args (void)
3468 MonoArray *res;
3469 int i;
3470 MonoDomain *domain = mono_domain_get ();
3472 if (!main_args)
3473 return NULL;
3475 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3477 for (i = 0; i < num_main_args; ++i)
3478 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3480 return res;
3483 static void
3484 free_main_args (void)
3486 int i;
3488 for (i = 0; i < num_main_args; ++i)
3489 g_free (main_args [i]);
3490 g_free (main_args);
3494 * mono_runtime_run_main:
3495 * @method: the method to start the application with (usually Main)
3496 * @argc: number of arguments from the command line
3497 * @argv: array of strings from the command line
3498 * @exc: excetption results
3500 * Execute a standard Main() method (argc/argv contains the
3501 * executable name). This method also sets the command line argument value
3502 * needed by System.Environment.
3507 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3508 MonoObject **exc)
3510 int i;
3511 MonoArray *args = NULL;
3512 MonoDomain *domain = mono_domain_get ();
3513 gchar *utf8_fullpath;
3514 MonoMethodSignature *sig;
3516 g_assert (method != NULL);
3518 mono_thread_set_main (mono_thread_current ());
3520 main_args = g_new0 (char*, argc);
3521 num_main_args = argc;
3523 if (!g_path_is_absolute (argv [0])) {
3524 gchar *basename = g_path_get_basename (argv [0]);
3525 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3526 basename,
3527 NULL);
3529 utf8_fullpath = mono_utf8_from_external (fullpath);
3530 if(utf8_fullpath == NULL) {
3531 /* Printing the arg text will cause glib to
3532 * whinge about "Invalid UTF-8", but at least
3533 * its relevant, and shows the problem text
3534 * string.
3536 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3537 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3538 exit (-1);
3541 g_free (fullpath);
3542 g_free (basename);
3543 } else {
3544 utf8_fullpath = mono_utf8_from_external (argv[0]);
3545 if(utf8_fullpath == NULL) {
3546 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3547 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3548 exit (-1);
3552 main_args [0] = utf8_fullpath;
3554 for (i = 1; i < argc; ++i) {
3555 gchar *utf8_arg;
3557 utf8_arg=mono_utf8_from_external (argv[i]);
3558 if(utf8_arg==NULL) {
3559 /* Ditto the comment about Invalid UTF-8 here */
3560 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3561 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3562 exit (-1);
3565 main_args [i] = utf8_arg;
3567 argc--;
3568 argv++;
3570 sig = mono_method_signature (method);
3571 if (!sig) {
3572 g_print ("Unable to load Main method.\n");
3573 exit (-1);
3576 if (sig->param_count) {
3577 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3578 for (i = 0; i < argc; ++i) {
3579 /* The encodings should all work, given that
3580 * we've checked all these args for the
3581 * main_args array.
3583 gchar *str = mono_utf8_from_external (argv [i]);
3584 MonoString *arg = mono_string_new (domain, str);
3585 mono_array_setref (args, i, arg);
3586 g_free (str);
3588 } else {
3589 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3592 mono_assembly_set_main (method->klass->image->assembly);
3594 return mono_runtime_exec_main (method, args, exc);
3597 static MonoObject*
3598 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3600 static MonoMethod *serialize_method;
3602 void *params [1];
3603 MonoObject *array;
3605 if (!serialize_method) {
3606 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3607 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3610 if (!serialize_method) {
3611 *failure = TRUE;
3612 return NULL;
3615 g_assert (!mono_object_class (obj)->marshalbyref);
3617 params [0] = obj;
3618 *exc = NULL;
3619 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3620 if (*exc)
3621 *failure = TRUE;
3623 return array;
3626 static MonoObject*
3627 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3629 static MonoMethod *deserialize_method;
3631 void *params [1];
3632 MonoObject *result;
3634 if (!deserialize_method) {
3635 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3636 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3638 if (!deserialize_method) {
3639 *failure = TRUE;
3640 return NULL;
3643 params [0] = obj;
3644 *exc = NULL;
3645 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3646 if (*exc)
3647 *failure = TRUE;
3649 return result;
3652 static MonoObject*
3653 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3655 static MonoMethod *get_proxy_method;
3657 MonoDomain *domain = mono_domain_get ();
3658 MonoRealProxy *real_proxy;
3659 MonoReflectionType *reflection_type;
3660 MonoTransparentProxy *transparent_proxy;
3662 if (!get_proxy_method)
3663 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3665 g_assert (obj->vtable->klass->marshalbyref);
3667 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3668 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3670 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3671 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3673 *exc = NULL;
3674 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3675 if (*exc)
3676 *failure = TRUE;
3678 return (MonoObject*) transparent_proxy;
3682 * mono_object_xdomain_representation
3683 * @obj: an object
3684 * @target_domain: a domain
3685 * @exc: pointer to a MonoObject*
3687 * Creates a representation of obj in the domain target_domain. This
3688 * is either a copy of obj arrived through via serialization and
3689 * deserialization or a proxy, depending on whether the object is
3690 * serializable or marshal by ref. obj must not be in target_domain.
3692 * If the object cannot be represented in target_domain, NULL is
3693 * returned and *exc is set to an appropriate exception.
3695 MonoObject*
3696 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3698 MonoObject *deserialized = NULL;
3699 gboolean failure = FALSE;
3701 *exc = NULL;
3703 if (mono_object_class (obj)->marshalbyref) {
3704 deserialized = make_transparent_proxy (obj, &failure, exc);
3705 } else {
3706 MonoDomain *domain = mono_domain_get ();
3707 MonoObject *serialized;
3709 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3710 serialized = serialize_object (obj, &failure, exc);
3711 mono_domain_set_internal_with_options (target_domain, FALSE);
3712 if (!failure)
3713 deserialized = deserialize_object (serialized, &failure, exc);
3714 if (domain != target_domain)
3715 mono_domain_set_internal_with_options (domain, FALSE);
3718 return deserialized;
3721 /* Used in call_unhandled_exception_delegate */
3722 static MonoObject *
3723 create_unhandled_exception_eventargs (MonoObject *exc)
3725 MonoClass *klass;
3726 gpointer args [2];
3727 MonoMethod *method = NULL;
3728 MonoBoolean is_terminating = TRUE;
3729 MonoObject *obj;
3731 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3732 g_assert (klass);
3734 mono_class_init (klass);
3736 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3737 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3738 g_assert (method);
3740 args [0] = exc;
3741 args [1] = &is_terminating;
3743 obj = mono_object_new (mono_domain_get (), klass);
3744 mono_runtime_invoke (method, obj, args, NULL);
3746 return obj;
3749 /* Used in mono_unhandled_exception */
3750 static void
3751 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3752 MonoObject *e = NULL;
3753 gpointer pa [2];
3754 MonoDomain *current_domain = mono_domain_get ();
3756 if (domain != current_domain)
3757 mono_domain_set_internal_with_options (domain, FALSE);
3759 g_assert (domain == mono_object_domain (domain->domain));
3761 if (mono_object_domain (exc) != domain) {
3762 MonoObject *serialization_exc;
3764 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
3765 if (!exc) {
3766 if (serialization_exc) {
3767 MonoObject *dummy;
3768 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
3769 g_assert (exc);
3770 } else {
3771 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
3772 "System.Runtime.Serialization", "SerializationException",
3773 "Could not serialize unhandled exception.");
3777 g_assert (mono_object_domain (exc) == domain);
3779 pa [0] = domain->domain;
3780 pa [1] = create_unhandled_exception_eventargs (exc);
3781 mono_runtime_delegate_invoke (delegate, pa, &e);
3783 if (domain != current_domain)
3784 mono_domain_set_internal_with_options (current_domain, FALSE);
3786 if (e) {
3787 MonoError error;
3788 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
3789 if (!mono_error_ok (&error)) {
3790 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
3791 mono_error_cleanup (&error);
3792 } else {
3793 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3794 g_free (msg);
3799 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3802 * mono_runtime_unhandled_exception_policy_set:
3803 * @policy: the new policy
3805 * This is a VM internal routine.
3807 * Sets the runtime policy for handling unhandled exceptions.
3809 void
3810 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3811 runtime_unhandled_exception_policy = policy;
3815 * mono_runtime_unhandled_exception_policy_get:
3817 * This is a VM internal routine.
3819 * Gets the runtime policy for handling unhandled exceptions.
3821 MonoRuntimeUnhandledExceptionPolicy
3822 mono_runtime_unhandled_exception_policy_get (void) {
3823 return runtime_unhandled_exception_policy;
3827 * mono_unhandled_exception:
3828 * @exc: exception thrown
3830 * This is a VM internal routine.
3832 * We call this function when we detect an unhandled exception
3833 * in the default domain.
3835 * It invokes the * UnhandledException event in AppDomain or prints
3836 * a warning to the console
3838 void
3839 mono_unhandled_exception (MonoObject *exc)
3841 MonoDomain *current_domain = mono_domain_get ();
3842 MonoDomain *root_domain = mono_get_root_domain ();
3843 MonoClassField *field;
3844 MonoObject *current_appdomain_delegate;
3845 MonoObject *root_appdomain_delegate;
3847 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3848 "UnhandledException");
3849 g_assert (field);
3851 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3852 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
3853 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3854 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3855 if (current_domain != root_domain) {
3856 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3857 } else {
3858 current_appdomain_delegate = NULL;
3861 /* set exitcode only if we will abort the process */
3862 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3863 if (abort_process)
3864 mono_environment_exitcode_set (1);
3865 mono_print_unhandled_exception (exc);
3866 } else {
3867 if (root_appdomain_delegate) {
3868 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3870 if (current_appdomain_delegate) {
3871 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3878 * mono_runtime_exec_managed_code:
3879 * @domain: Application domain
3880 * @main_func: function to invoke from the execution thread
3881 * @main_args: parameter to the main_func
3883 * Launch a new thread to execute a function
3885 * main_func is called back from the thread with main_args as the
3886 * parameter. The callback function is expected to start Main()
3887 * eventually. This function then waits for all managed threads to
3888 * finish.
3889 * It is not necesseray anymore to execute managed code in a subthread,
3890 * so this function should not be used anymore by default: just
3891 * execute the code and then call mono_thread_manage ().
3893 void
3894 mono_runtime_exec_managed_code (MonoDomain *domain,
3895 MonoMainThreadFunc main_func,
3896 gpointer main_args)
3898 mono_thread_create (domain, main_func, main_args);
3900 mono_thread_manage ();
3904 * Execute a standard Main() method (args doesn't contain the
3905 * executable name).
3908 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3910 MonoDomain *domain;
3911 gpointer pa [1];
3912 int rval;
3913 MonoCustomAttrInfo* cinfo;
3914 gboolean has_stathread_attribute;
3915 MonoInternalThread* thread = mono_thread_internal_current ();
3917 g_assert (args);
3919 pa [0] = args;
3921 domain = mono_object_domain (args);
3922 if (!domain->entry_assembly) {
3923 gchar *str;
3924 MonoAssembly *assembly;
3926 assembly = method->klass->image->assembly;
3927 domain->entry_assembly = assembly;
3928 /* Domains created from another domain already have application_base and configuration_file set */
3929 if (domain->setup->application_base == NULL) {
3930 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3933 if (domain->setup->configuration_file == NULL) {
3934 str = g_strconcat (assembly->image->name, ".config", NULL);
3935 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3936 g_free (str);
3937 mono_set_private_bin_path_from_config (domain);
3941 cinfo = mono_custom_attrs_from_method (method);
3942 if (cinfo) {
3943 static MonoClass *stathread_attribute = NULL;
3944 if (!stathread_attribute)
3945 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3946 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3947 if (!cinfo->cached)
3948 mono_custom_attrs_free (cinfo);
3949 } else {
3950 has_stathread_attribute = FALSE;
3952 if (has_stathread_attribute) {
3953 thread->apartment_state = ThreadApartmentState_STA;
3954 } else {
3955 thread->apartment_state = ThreadApartmentState_MTA;
3957 mono_thread_init_apartment_state ();
3959 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3961 /* FIXME: check signature of method */
3962 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3963 MonoObject *res;
3964 res = mono_runtime_invoke (method, NULL, pa, exc);
3965 if (!exc || !*exc)
3966 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
3967 else
3968 rval = -1;
3970 mono_environment_exitcode_set (rval);
3971 } else {
3972 mono_runtime_invoke (method, NULL, pa, exc);
3973 if (!exc || !*exc)
3974 rval = 0;
3975 else {
3976 /* If the return type of Main is void, only
3977 * set the exitcode if an exception was thrown
3978 * (we don't want to blow away an
3979 * explicitly-set exit code)
3981 rval = -1;
3982 mono_environment_exitcode_set (rval);
3986 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
3988 return rval;
3992 * mono_install_runtime_invoke:
3993 * @func: Function to install
3995 * This is a VM internal routine
3997 void
3998 mono_install_runtime_invoke (MonoInvokeFunc func)
4000 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
4005 * mono_runtime_invoke_array:
4006 * @method: method to invoke
4007 * @obJ: object instance
4008 * @params: arguments to the method
4009 * @exc: exception information.
4011 * Invokes the method represented by @method on the object @obj.
4013 * obj is the 'this' pointer, it should be NULL for static
4014 * methods, a MonoObject* for object instances and a pointer to
4015 * the value type for value types.
4017 * The params array contains the arguments to the method with the
4018 * same convention: MonoObject* pointers for object instances and
4019 * pointers to the value type otherwise. The _invoke_array
4020 * variant takes a C# object[] as the params argument (MonoArray
4021 * *params): in this case the value types are boxed inside the
4022 * respective reference representation.
4024 * From unmanaged code you'll usually use the
4025 * mono_runtime_invoke() variant.
4027 * Note that this function doesn't handle virtual methods for
4028 * you, it will exec the exact method you pass: we still need to
4029 * expose a function to lookup the derived class implementation
4030 * of a virtual method (there are examples of this in the code,
4031 * though).
4033 * You can pass NULL as the exc argument if you don't want to
4034 * catch exceptions, otherwise, *exc will be set to the exception
4035 * thrown, if any. if an exception is thrown, you can't use the
4036 * MonoObject* result from the function.
4038 * If the method returns a value type, it is boxed in an object
4039 * reference.
4041 MonoObject*
4042 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4043 MonoObject **exc)
4045 MonoMethodSignature *sig = mono_method_signature (method);
4046 gpointer *pa = NULL;
4047 MonoObject *res;
4048 int i;
4049 gboolean has_byref_nullables = FALSE;
4051 if (NULL != params) {
4052 pa = alloca (sizeof (gpointer) * mono_array_length (params));
4053 for (i = 0; i < mono_array_length (params); i++) {
4054 MonoType *t = sig->params [i];
4056 again:
4057 switch (t->type) {
4058 case MONO_TYPE_U1:
4059 case MONO_TYPE_I1:
4060 case MONO_TYPE_BOOLEAN:
4061 case MONO_TYPE_U2:
4062 case MONO_TYPE_I2:
4063 case MONO_TYPE_CHAR:
4064 case MONO_TYPE_U:
4065 case MONO_TYPE_I:
4066 case MONO_TYPE_U4:
4067 case MONO_TYPE_I4:
4068 case MONO_TYPE_U8:
4069 case MONO_TYPE_I8:
4070 case MONO_TYPE_R4:
4071 case MONO_TYPE_R8:
4072 case MONO_TYPE_VALUETYPE:
4073 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4074 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4075 pa [i] = mono_array_get (params, MonoObject*, i);
4076 if (t->byref)
4077 has_byref_nullables = TRUE;
4078 } else {
4079 /* MS seems to create the objects if a null is passed in */
4080 if (!mono_array_get (params, MonoObject*, i))
4081 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
4083 if (t->byref) {
4085 * We can't pass the unboxed vtype byref to the callee, since
4086 * that would mean the callee would be able to modify boxed
4087 * primitive types. So we (and MS) make a copy of the boxed
4088 * object, pass that to the callee, and replace the original
4089 * boxed object in the arg array with the copy.
4091 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4092 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4093 mono_array_setref (params, i, copy);
4096 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4098 break;
4099 case MONO_TYPE_STRING:
4100 case MONO_TYPE_OBJECT:
4101 case MONO_TYPE_CLASS:
4102 case MONO_TYPE_ARRAY:
4103 case MONO_TYPE_SZARRAY:
4104 if (t->byref)
4105 pa [i] = mono_array_addr (params, MonoObject*, i);
4106 // FIXME: I need to check this code path
4107 else
4108 pa [i] = mono_array_get (params, MonoObject*, i);
4109 break;
4110 case MONO_TYPE_GENERICINST:
4111 if (t->byref)
4112 t = &t->data.generic_class->container_class->this_arg;
4113 else
4114 t = &t->data.generic_class->container_class->byval_arg;
4115 goto again;
4116 case MONO_TYPE_PTR: {
4117 MonoObject *arg;
4119 /* The argument should be an IntPtr */
4120 arg = mono_array_get (params, MonoObject*, i);
4121 if (arg == NULL) {
4122 pa [i] = NULL;
4123 } else {
4124 g_assert (arg->vtable->klass == mono_defaults.int_class);
4125 pa [i] = ((MonoIntPtr*)arg)->m_value;
4127 break;
4129 default:
4130 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4135 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4136 void *o = obj;
4138 if (mono_class_is_nullable (method->klass)) {
4139 /* Need to create a boxed vtype instead */
4140 g_assert (!obj);
4142 if (!params)
4143 return NULL;
4144 else
4145 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4148 if (!obj) {
4149 obj = mono_object_new (mono_domain_get (), method->klass);
4150 g_assert (obj); /*maybe we should raise a TLE instead?*/
4151 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4152 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4154 if (method->klass->valuetype)
4155 o = mono_object_unbox (obj);
4156 else
4157 o = obj;
4158 } else if (method->klass->valuetype) {
4159 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4162 mono_runtime_invoke (method, o, pa, exc);
4163 return obj;
4164 } else {
4165 if (mono_class_is_nullable (method->klass)) {
4166 MonoObject *nullable;
4168 /* Convert the unboxed vtype into a Nullable structure */
4169 nullable = mono_object_new (mono_domain_get (), method->klass);
4171 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4172 obj = mono_object_unbox (nullable);
4175 /* obj must be already unboxed if needed */
4176 res = mono_runtime_invoke (method, obj, pa, exc);
4178 if (sig->ret->type == MONO_TYPE_PTR) {
4179 MonoClass *pointer_class;
4180 static MonoMethod *box_method;
4181 void *box_args [2];
4182 MonoObject *box_exc;
4185 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4186 * convert it to a Pointer object.
4188 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4189 if (!box_method)
4190 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4192 g_assert (res->vtable->klass == mono_defaults.int_class);
4193 box_args [0] = ((MonoIntPtr*)res)->m_value;
4194 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4195 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4196 g_assert (!box_exc);
4199 if (has_byref_nullables) {
4201 * The runtime invoke wrapper already converted byref nullables back,
4202 * and stored them in pa, we just need to copy them back to the
4203 * managed array.
4205 for (i = 0; i < mono_array_length (params); i++) {
4206 MonoType *t = sig->params [i];
4208 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4209 mono_array_setref (params, i, pa [i]);
4213 return res;
4217 static void
4218 arith_overflow (void)
4220 mono_raise_exception (mono_get_exception_overflow ());
4224 * mono_object_allocate:
4225 * @size: number of bytes to allocate
4227 * This is a very simplistic routine until we have our GC-aware
4228 * memory allocator.
4230 * Returns: an allocated object of size @size, or NULL on failure.
4232 static inline void *
4233 mono_object_allocate (size_t size, MonoVTable *vtable)
4235 MonoObject *o;
4236 mono_stats.new_object_count++;
4237 ALLOC_OBJECT (o, vtable, size);
4239 return o;
4243 * mono_object_allocate_ptrfree:
4244 * @size: number of bytes to allocate
4246 * Note that the memory allocated is not zeroed.
4247 * Returns: an allocated object of size @size, or NULL on failure.
4249 static inline void *
4250 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
4252 MonoObject *o;
4253 mono_stats.new_object_count++;
4254 ALLOC_PTRFREE (o, vtable, size);
4255 return o;
4258 static inline void *
4259 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
4261 void *o;
4262 ALLOC_TYPED (o, size, vtable);
4263 mono_stats.new_object_count++;
4265 return o;
4269 * mono_object_new:
4270 * @klass: the class of the object that we want to create
4272 * Returns: a newly created object whose definition is
4273 * looked up using @klass. This will not invoke any constructors,
4274 * so the consumer of this routine has to invoke any constructors on
4275 * its own to initialize the object.
4277 * It returns NULL on failure.
4279 MonoObject *
4280 mono_object_new (MonoDomain *domain, MonoClass *klass)
4282 MonoVTable *vtable;
4284 MONO_ARCH_SAVE_REGS;
4285 vtable = mono_class_vtable (domain, klass);
4286 if (!vtable)
4287 return NULL;
4288 return mono_object_new_specific (vtable);
4292 * mono_object_new_pinned:
4294 * Same as mono_object_new, but the returned object will be pinned.
4295 * For SGEN, these objects will only be freed at appdomain unload.
4297 MonoObject *
4298 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass)
4300 MonoVTable *vtable;
4302 MONO_ARCH_SAVE_REGS;
4303 vtable = mono_class_vtable (domain, klass);
4304 if (!vtable)
4305 return NULL;
4307 #ifdef HAVE_SGEN_GC
4308 return mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4309 #else
4310 return mono_object_new_specific (vtable);
4311 #endif
4315 * mono_object_new_specific:
4316 * @vtable: the vtable of the object that we want to create
4318 * Returns: A newly created object with class and domain specified
4319 * by @vtable
4321 MonoObject *
4322 mono_object_new_specific (MonoVTable *vtable)
4324 MonoObject *o;
4326 MONO_ARCH_SAVE_REGS;
4328 /* check for is_com_object for COM Interop */
4329 if (vtable->remote || vtable->klass->is_com_object)
4331 gpointer pa [1];
4332 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4334 if (im == NULL) {
4335 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4337 if (!klass->inited)
4338 mono_class_init (klass);
4340 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4341 g_assert (im);
4342 vtable->domain->create_proxy_for_type_method = im;
4345 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4347 o = mono_runtime_invoke (im, NULL, pa, NULL);
4348 if (o != NULL) return o;
4351 return mono_object_new_alloc_specific (vtable);
4354 MonoObject *
4355 mono_object_new_alloc_specific (MonoVTable *vtable)
4357 MonoObject *o;
4359 if (!vtable->klass->has_references) {
4360 o = mono_object_new_ptrfree (vtable);
4361 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4362 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
4363 } else {
4364 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4365 o = mono_object_allocate (vtable->klass->instance_size, vtable);
4367 if (G_UNLIKELY (vtable->klass->has_finalize))
4368 mono_object_register_finalizer (o);
4370 if (G_UNLIKELY (profile_allocs))
4371 mono_profiler_allocation (o, vtable->klass);
4372 return o;
4375 MonoObject*
4376 mono_object_new_fast (MonoVTable *vtable)
4378 MonoObject *o;
4379 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
4380 return o;
4383 static MonoObject*
4384 mono_object_new_ptrfree (MonoVTable *vtable)
4386 MonoObject *obj;
4387 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4388 #if NEED_TO_ZERO_PTRFREE
4389 /* an inline memset is much faster for the common vcase of small objects
4390 * note we assume the allocated size is a multiple of sizeof (void*).
4392 if (vtable->klass->instance_size < 128) {
4393 gpointer *p, *end;
4394 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
4395 p = (gpointer*)((char*)obj + sizeof (MonoObject));
4396 while (p < end) {
4397 *p = NULL;
4398 ++p;
4400 } else {
4401 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
4403 #endif
4404 return obj;
4407 static MonoObject*
4408 mono_object_new_ptrfree_box (MonoVTable *vtable)
4410 MonoObject *obj;
4411 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4412 /* the object will be boxed right away, no need to memzero it */
4413 return obj;
4417 * mono_class_get_allocation_ftn:
4418 * @vtable: vtable
4419 * @for_box: the object will be used for boxing
4420 * @pass_size_in_words:
4422 * Return the allocation function appropriate for the given class.
4425 void*
4426 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4428 *pass_size_in_words = FALSE;
4430 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4431 profile_allocs = FALSE;
4433 if (mono_class_has_finalizer (vtable->klass) || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4434 return mono_object_new_specific;
4436 if (!vtable->klass->has_references) {
4437 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
4438 if (for_box)
4439 return mono_object_new_ptrfree_box;
4440 return mono_object_new_ptrfree;
4443 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4445 return mono_object_new_fast;
4448 * FIXME: This is actually slower than mono_object_new_fast, because
4449 * of the overhead of parameter passing.
4452 *pass_size_in_words = TRUE;
4453 #ifdef GC_REDIRECT_TO_LOCAL
4454 return GC_local_gcj_fast_malloc;
4455 #else
4456 return GC_gcj_fast_malloc;
4457 #endif
4461 return mono_object_new_specific;
4465 * mono_object_new_from_token:
4466 * @image: Context where the type_token is hosted
4467 * @token: a token of the type that we want to create
4469 * Returns: A newly created object whose definition is
4470 * looked up using @token in the @image image
4472 MonoObject *
4473 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4475 MonoClass *class;
4477 class = mono_class_get (image, token);
4479 return mono_object_new (domain, class);
4484 * mono_object_clone:
4485 * @obj: the object to clone
4487 * Returns: A newly created object who is a shallow copy of @obj
4489 MonoObject *
4490 mono_object_clone (MonoObject *obj)
4492 MonoObject *o;
4493 int size = obj->vtable->klass->instance_size;
4495 if (obj->vtable->klass->rank)
4496 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
4498 o = mono_object_allocate (size, obj->vtable);
4500 if (obj->vtable->klass->has_references) {
4501 mono_gc_wbarrier_object_copy (o, obj);
4502 } else {
4503 int size = obj->vtable->klass->instance_size;
4504 /* do not copy the sync state */
4505 mono_gc_memmove ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
4507 if (G_UNLIKELY (profile_allocs))
4508 mono_profiler_allocation (o, obj->vtable->klass);
4510 if (obj->vtable->klass->has_finalize)
4511 mono_object_register_finalizer (o);
4512 return o;
4516 * mono_array_full_copy:
4517 * @src: source array to copy
4518 * @dest: destination array
4520 * Copies the content of one array to another with exactly the same type and size.
4522 void
4523 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4525 uintptr_t size;
4526 MonoClass *klass = src->obj.vtable->klass;
4528 MONO_ARCH_SAVE_REGS;
4530 g_assert (klass == dest->obj.vtable->klass);
4532 size = mono_array_length (src);
4533 g_assert (size == mono_array_length (dest));
4534 size *= mono_array_element_size (klass);
4535 #ifdef HAVE_SGEN_GC
4536 if (klass->element_class->valuetype) {
4537 if (klass->element_class->has_references)
4538 mono_value_copy_array (dest, 0, mono_array_addr_with_size (src, 0, 0), mono_array_length (src));
4539 else
4540 mono_gc_memmove (&dest->vector, &src->vector, size);
4541 } else {
4542 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4544 #else
4545 mono_gc_memmove (&dest->vector, &src->vector, size);
4546 #endif
4550 * mono_array_clone_in_domain:
4551 * @domain: the domain in which the array will be cloned into
4552 * @array: the array to clone
4554 * This routine returns a copy of the array that is hosted on the
4555 * specified MonoDomain.
4557 MonoArray*
4558 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4560 MonoArray *o;
4561 uintptr_t size, i;
4562 uintptr_t *sizes;
4563 MonoClass *klass = array->obj.vtable->klass;
4565 MONO_ARCH_SAVE_REGS;
4567 if (array->bounds == NULL) {
4568 size = mono_array_length (array);
4569 o = mono_array_new_full (domain, klass, &size, NULL);
4571 size *= mono_array_element_size (klass);
4572 #ifdef HAVE_SGEN_GC
4573 if (klass->element_class->valuetype) {
4574 if (klass->element_class->has_references)
4575 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4576 else
4577 mono_gc_memmove (&o->vector, &array->vector, size);
4578 } else {
4579 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4581 #else
4582 mono_gc_memmove (&o->vector, &array->vector, size);
4583 #endif
4584 return o;
4587 sizes = alloca (klass->rank * sizeof(intptr_t) * 2);
4588 size = mono_array_element_size (klass);
4589 for (i = 0; i < klass->rank; ++i) {
4590 sizes [i] = array->bounds [i].length;
4591 size *= array->bounds [i].length;
4592 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4594 o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
4595 #ifdef HAVE_SGEN_GC
4596 if (klass->element_class->valuetype) {
4597 if (klass->element_class->has_references)
4598 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4599 else
4600 mono_gc_memmove (&o->vector, &array->vector, size);
4601 } else {
4602 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4604 #else
4605 mono_gc_memmove (&o->vector, &array->vector, size);
4606 #endif
4608 return o;
4612 * mono_array_clone:
4613 * @array: the array to clone
4615 * Returns: A newly created array who is a shallow copy of @array
4617 MonoArray*
4618 mono_array_clone (MonoArray *array)
4620 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4623 /* helper macros to check for overflow when calculating the size of arrays */
4624 #ifdef MONO_BIG_ARRAYS
4625 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4626 #define MYGUINT_MAX MYGUINT64_MAX
4627 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4628 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4629 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4630 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4631 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4632 #else
4633 #define MYGUINT32_MAX 4294967295U
4634 #define MYGUINT_MAX MYGUINT32_MAX
4635 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4636 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4637 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4638 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4639 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4640 #endif
4642 gboolean
4643 mono_array_calc_byte_len (MonoClass *class, uintptr_t len, uintptr_t *res)
4645 uintptr_t byte_len;
4647 byte_len = mono_array_element_size (class);
4648 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4649 return FALSE;
4650 byte_len *= len;
4651 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4652 return FALSE;
4653 byte_len += sizeof (MonoArray);
4655 *res = byte_len;
4657 return TRUE;
4661 * mono_array_new_full:
4662 * @domain: domain where the object is created
4663 * @array_class: array class
4664 * @lengths: lengths for each dimension in the array
4665 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4667 * This routine creates a new array objects with the given dimensions,
4668 * lower bounds and type.
4670 MonoArray*
4671 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4673 uintptr_t byte_len, len, bounds_size;
4674 MonoObject *o;
4675 MonoArray *array;
4676 MonoArrayBounds *bounds;
4677 MonoVTable *vtable;
4678 int i;
4680 if (!array_class->inited)
4681 mono_class_init (array_class);
4683 len = 1;
4685 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4686 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4687 len = lengths [0];
4688 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4689 arith_overflow ();
4690 bounds_size = 0;
4691 } else {
4692 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4694 for (i = 0; i < array_class->rank; ++i) {
4695 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4696 arith_overflow ();
4697 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4698 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4699 len *= lengths [i];
4703 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4704 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4706 if (bounds_size) {
4707 /* align */
4708 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4709 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4710 byte_len = (byte_len + 3) & ~3;
4711 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4712 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4713 byte_len += bounds_size;
4716 * Following three lines almost taken from mono_object_new ():
4717 * they need to be kept in sync.
4719 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4720 #ifndef HAVE_SGEN_GC
4721 if (!array_class->has_references) {
4722 o = mono_object_allocate_ptrfree (byte_len, vtable);
4723 #if NEED_TO_ZERO_PTRFREE
4724 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4725 #endif
4726 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4727 o = mono_object_allocate_spec (byte_len, vtable);
4728 }else {
4729 o = mono_object_allocate (byte_len, vtable);
4732 array = (MonoArray*)o;
4733 array->max_length = len;
4735 if (bounds_size) {
4736 bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4737 array->bounds = bounds;
4739 #else
4740 if (bounds_size)
4741 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4742 else
4743 o = mono_gc_alloc_vector (vtable, byte_len, len);
4744 array = (MonoArray*)o;
4745 mono_stats.new_object_count++;
4747 bounds = array->bounds;
4748 #endif
4750 if (bounds_size) {
4751 for (i = 0; i < array_class->rank; ++i) {
4752 bounds [i].length = lengths [i];
4753 if (lower_bounds)
4754 bounds [i].lower_bound = lower_bounds [i];
4758 if (G_UNLIKELY (profile_allocs))
4759 mono_profiler_allocation (o, array_class);
4761 return array;
4765 * mono_array_new:
4766 * @domain: domain where the object is created
4767 * @eclass: element class
4768 * @n: number of array elements
4770 * This routine creates a new szarray with @n elements of type @eclass.
4772 MonoArray *
4773 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
4775 MonoClass *ac;
4777 MONO_ARCH_SAVE_REGS;
4779 ac = mono_array_class_get (eclass, 1);
4780 g_assert (ac);
4782 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4786 * mono_array_new_specific:
4787 * @vtable: a vtable in the appropriate domain for an initialized class
4788 * @n: number of array elements
4790 * This routine is a fast alternative to mono_array_new() for code which
4791 * can be sure about the domain it operates in.
4793 MonoArray *
4794 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
4796 MonoObject *o;
4797 MonoArray *ao;
4798 uintptr_t byte_len;
4800 MONO_ARCH_SAVE_REGS;
4802 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4803 arith_overflow ();
4804 return NULL;
4807 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4808 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4809 return NULL;
4811 #ifndef HAVE_SGEN_GC
4812 if (!vtable->klass->has_references) {
4813 o = mono_object_allocate_ptrfree (byte_len, vtable);
4814 #if NEED_TO_ZERO_PTRFREE
4815 ((MonoArray*)o)->bounds = NULL;
4816 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4817 #endif
4818 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4819 o = mono_object_allocate_spec (byte_len, vtable);
4820 } else {
4821 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4822 o = mono_object_allocate (byte_len, vtable);
4825 ao = (MonoArray *)o;
4826 ao->max_length = n;
4827 #else
4828 o = mono_gc_alloc_vector (vtable, byte_len, n);
4829 ao = (MonoArray*)o;
4830 mono_stats.new_object_count++;
4831 #endif
4833 if (G_UNLIKELY (profile_allocs))
4834 mono_profiler_allocation (o, vtable->klass);
4836 return ao;
4840 * mono_string_new_utf16:
4841 * @text: a pointer to an utf16 string
4842 * @len: the length of the string
4844 * Returns: A newly created string object which contains @text.
4846 MonoString *
4847 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4849 MonoString *s;
4851 s = mono_string_new_size (domain, len);
4852 g_assert (s != NULL);
4854 memcpy (mono_string_chars (s), text, len * 2);
4856 return s;
4860 * mono_string_new_size:
4861 * @text: a pointer to an utf16 string
4862 * @len: the length of the string
4864 * Returns: A newly created string object of @len
4866 MonoString *
4867 mono_string_new_size (MonoDomain *domain, gint32 len)
4869 MonoString *s;
4870 MonoVTable *vtable;
4871 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4873 /* overflow ? can't fit it, can't allocate it! */
4874 if (len > size)
4875 mono_gc_out_of_memory (-1);
4877 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4878 g_assert (vtable);
4880 #ifndef HAVE_SGEN_GC
4881 s = mono_object_allocate_ptrfree (size, vtable);
4883 s->length = len;
4884 #else
4885 s = mono_gc_alloc_string (vtable, size, len);
4886 #endif
4887 #if NEED_TO_ZERO_PTRFREE
4888 s->chars [len] = 0;
4889 #endif
4890 if (G_UNLIKELY (profile_allocs))
4891 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4893 return s;
4897 * mono_string_new_len:
4898 * @text: a pointer to an utf8 string
4899 * @length: number of bytes in @text to consider
4901 * Returns: A newly created string object which contains @text.
4903 MonoString*
4904 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4906 GError *error = NULL;
4907 MonoString *o = NULL;
4908 guint16 *ut;
4909 glong items_written;
4911 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
4913 if (!error)
4914 o = mono_string_new_utf16 (domain, ut, items_written);
4915 else
4916 g_error_free (error);
4918 g_free (ut);
4920 return o;
4924 * mono_string_new:
4925 * @text: a pointer to an utf8 string
4927 * Returns: A newly created string object which contains @text.
4929 MonoString*
4930 mono_string_new (MonoDomain *domain, const char *text)
4932 GError *error = NULL;
4933 MonoString *o = NULL;
4934 guint16 *ut;
4935 glong items_written;
4936 int l;
4938 l = strlen (text);
4940 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4942 if (!error)
4943 o = mono_string_new_utf16 (domain, ut, items_written);
4944 else
4945 g_error_free (error);
4947 g_free (ut);
4948 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4949 #if 0
4950 gunichar2 *str;
4951 const gchar *end;
4952 int len;
4953 MonoString *o = NULL;
4955 if (!g_utf8_validate (text, -1, &end))
4956 return NULL;
4958 len = g_utf8_strlen (text, -1);
4959 o = mono_string_new_size (domain, len);
4960 str = mono_string_chars (o);
4962 while (text < end) {
4963 *str++ = g_utf8_get_char (text);
4964 text = g_utf8_next_char (text);
4966 #endif
4967 return o;
4971 * mono_string_new_wrapper:
4972 * @text: pointer to utf8 characters.
4974 * Helper function to create a string object from @text in the current domain.
4976 MonoString*
4977 mono_string_new_wrapper (const char *text)
4979 MonoDomain *domain = mono_domain_get ();
4981 MONO_ARCH_SAVE_REGS;
4983 if (text)
4984 return mono_string_new (domain, text);
4986 return NULL;
4990 * mono_value_box:
4991 * @class: the class of the value
4992 * @value: a pointer to the unboxed data
4994 * Returns: A newly created object which contains @value.
4996 MonoObject *
4997 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
4999 MonoObject *res;
5000 int size;
5001 MonoVTable *vtable;
5003 g_assert (class->valuetype);
5004 if (mono_class_is_nullable (class))
5005 return mono_nullable_box (value, class);
5007 vtable = mono_class_vtable (domain, class);
5008 if (!vtable)
5009 return NULL;
5010 size = mono_class_instance_size (class);
5011 res = mono_object_new_alloc_specific (vtable);
5012 if (G_UNLIKELY (profile_allocs))
5013 mono_profiler_allocation (res, class);
5015 size = size - sizeof (MonoObject);
5017 #ifdef HAVE_SGEN_GC
5018 g_assert (size == mono_class_value_size (class, NULL));
5019 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
5020 #else
5021 #if NO_UNALIGNED_ACCESS
5022 mono_gc_memmove ((char *)res + sizeof (MonoObject), value, size);
5023 #else
5024 switch (size) {
5025 case 1:
5026 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5027 break;
5028 case 2:
5029 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5030 break;
5031 case 4:
5032 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5033 break;
5034 case 8:
5035 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5036 break;
5037 default:
5038 mono_gc_memmove ((char *)res + sizeof (MonoObject), value, size);
5040 #endif
5041 #endif
5042 if (class->has_finalize)
5043 mono_object_register_finalizer (res);
5044 return res;
5048 * mono_value_copy:
5049 * @dest: destination pointer
5050 * @src: source pointer
5051 * @klass: a valuetype class
5053 * Copy a valuetype from @src to @dest. This function must be used
5054 * when @klass contains references fields.
5056 void
5057 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5059 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5063 * mono_value_copy_array:
5064 * @dest: destination array
5065 * @dest_idx: index in the @dest array
5066 * @src: source pointer
5067 * @count: number of items
5069 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5070 * This function must be used when @klass contains references fields.
5071 * Overlap is handled.
5073 void
5074 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5076 int size = mono_array_element_size (dest->obj.vtable->klass);
5077 char *d = mono_array_addr_with_size (dest, size, dest_idx);
5078 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5079 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5083 * mono_object_get_domain:
5084 * @obj: object to query
5086 * Returns: the MonoDomain where the object is hosted
5088 MonoDomain*
5089 mono_object_get_domain (MonoObject *obj)
5091 return mono_object_domain (obj);
5095 * mono_object_get_class:
5096 * @obj: object to query
5098 * Returns: the MonOClass of the object.
5100 MonoClass*
5101 mono_object_get_class (MonoObject *obj)
5103 return mono_object_class (obj);
5106 * mono_object_get_size:
5107 * @o: object to query
5109 * Returns: the size, in bytes, of @o
5111 guint
5112 mono_object_get_size (MonoObject* o)
5114 MonoClass* klass = mono_object_class (o);
5115 if (klass == mono_defaults.string_class) {
5116 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5117 } else if (o->vtable->rank) {
5118 MonoArray *array = (MonoArray*)o;
5119 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
5120 if (array->bounds) {
5121 size += 3;
5122 size &= ~3;
5123 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5125 return size;
5126 } else {
5127 return mono_class_instance_size (klass);
5132 * mono_object_unbox:
5133 * @obj: object to unbox
5135 * Returns: a pointer to the start of the valuetype boxed in this
5136 * object.
5138 * This method will assert if the object passed is not a valuetype.
5140 gpointer
5141 mono_object_unbox (MonoObject *obj)
5143 /* add assert for valuetypes? */
5144 g_assert (obj->vtable->klass->valuetype);
5145 return ((char*)obj) + sizeof (MonoObject);
5149 * mono_object_isinst:
5150 * @obj: an object
5151 * @klass: a pointer to a class
5153 * Returns: @obj if @obj is derived from @klass
5155 MonoObject *
5156 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5158 if (!klass->inited)
5159 mono_class_init (klass);
5161 if (klass->marshalbyref || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5162 return mono_object_isinst_mbyref (obj, klass);
5164 if (!obj)
5165 return NULL;
5167 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5170 MonoObject *
5171 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5173 MonoVTable *vt;
5175 if (!obj)
5176 return NULL;
5178 vt = obj->vtable;
5180 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5181 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5182 return obj;
5185 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5186 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5187 return obj;
5188 } else {
5189 MonoClass *oklass = vt->klass;
5190 if ((oklass == mono_defaults.transparent_proxy_class))
5191 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5193 mono_class_setup_supertypes (klass);
5194 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5195 return obj;
5198 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5200 MonoDomain *domain = mono_domain_get ();
5201 MonoObject *res;
5202 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5203 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5204 MonoMethod *im = NULL;
5205 gpointer pa [2];
5207 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5208 im = mono_object_get_virtual_method (rp, im);
5209 g_assert (im);
5211 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5212 pa [1] = obj;
5214 res = mono_runtime_invoke (im, rp, pa, NULL);
5216 if (*(MonoBoolean *) mono_object_unbox(res)) {
5217 /* Update the vtable of the remote type, so it can safely cast to this new type */
5218 mono_upgrade_remote_class (domain, obj, klass);
5219 return obj;
5223 return NULL;
5227 * mono_object_castclass_mbyref:
5228 * @obj: an object
5229 * @klass: a pointer to a class
5231 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5233 MonoObject *
5234 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5236 if (!obj) return NULL;
5237 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5239 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5240 "System",
5241 "InvalidCastException"));
5242 return NULL;
5245 typedef struct {
5246 MonoDomain *orig_domain;
5247 MonoString *ins;
5248 MonoString *res;
5249 } LDStrInfo;
5251 static void
5252 str_lookup (MonoDomain *domain, gpointer user_data)
5254 LDStrInfo *info = user_data;
5255 if (info->res || domain == info->orig_domain)
5256 return;
5257 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5260 #ifdef HAVE_SGEN_GC
5262 static MonoString*
5263 mono_string_get_pinned (MonoString *str)
5265 int size;
5266 MonoString *news;
5267 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5268 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5269 if (news) {
5270 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5271 news->length = mono_string_length (str);
5273 return news;
5276 #else
5277 #define mono_string_get_pinned(str) (str)
5278 #endif
5280 static MonoString*
5281 mono_string_is_interned_lookup (MonoString *str, int insert)
5283 MonoGHashTable *ldstr_table;
5284 MonoString *res;
5285 MonoDomain *domain;
5287 domain = ((MonoObject *)str)->vtable->domain;
5288 ldstr_table = domain->ldstr_table;
5289 ldstr_lock ();
5290 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
5291 ldstr_unlock ();
5292 return res;
5294 if (insert) {
5295 str = mono_string_get_pinned (str);
5296 if (str)
5297 mono_g_hash_table_insert (ldstr_table, str, str);
5298 ldstr_unlock ();
5299 return str;
5300 } else {
5301 LDStrInfo ldstr_info;
5302 ldstr_info.orig_domain = domain;
5303 ldstr_info.ins = str;
5304 ldstr_info.res = NULL;
5306 mono_domain_foreach (str_lookup, &ldstr_info);
5307 if (ldstr_info.res) {
5309 * the string was already interned in some other domain:
5310 * intern it in the current one as well.
5312 mono_g_hash_table_insert (ldstr_table, str, str);
5313 ldstr_unlock ();
5314 return str;
5317 ldstr_unlock ();
5318 return NULL;
5322 * mono_string_is_interned:
5323 * @o: String to probe
5325 * Returns whether the string has been interned.
5327 MonoString*
5328 mono_string_is_interned (MonoString *o)
5330 return mono_string_is_interned_lookup (o, FALSE);
5334 * mono_string_intern:
5335 * @o: String to intern
5337 * Interns the string passed.
5338 * Returns: The interned string.
5340 MonoString*
5341 mono_string_intern (MonoString *str)
5343 return mono_string_is_interned_lookup (str, TRUE);
5347 * mono_ldstr:
5348 * @domain: the domain where the string will be used.
5349 * @image: a metadata context
5350 * @idx: index into the user string table.
5352 * Implementation for the ldstr opcode.
5353 * Returns: a loaded string from the @image/@idx combination.
5355 MonoString*
5356 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5358 MONO_ARCH_SAVE_REGS;
5360 if (image->dynamic) {
5361 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5362 return str;
5363 } else {
5364 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5365 return NULL; /*FIXME we should probably be raising an exception here*/
5366 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5371 * mono_ldstr_metadata_sig
5372 * @domain: the domain for the string
5373 * @sig: the signature of a metadata string
5375 * Returns: a MonoString for a string stored in the metadata
5377 static MonoString*
5378 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5380 const char *str = sig;
5381 MonoString *o, *interned;
5382 size_t len2;
5384 len2 = mono_metadata_decode_blob_size (str, &str);
5385 len2 >>= 1;
5387 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5388 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5390 int i;
5391 guint16 *p2 = (guint16*)mono_string_chars (o);
5392 for (i = 0; i < len2; ++i) {
5393 *p2 = GUINT16_FROM_LE (*p2);
5394 ++p2;
5397 #endif
5398 ldstr_lock ();
5399 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
5400 ldstr_unlock ();
5401 /* o will get garbage collected */
5402 return interned;
5405 o = mono_string_get_pinned (o);
5406 if (o)
5407 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5408 ldstr_unlock ();
5410 return o;
5414 * mono_string_to_utf8:
5415 * @s: a System.String
5417 * Returns the UTF8 representation for @s.
5418 * The resulting buffer needs to be freed with mono_free().
5420 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5422 char *
5423 mono_string_to_utf8 (MonoString *s)
5425 MonoError error;
5426 char *result = mono_string_to_utf8_checked (s, &error);
5428 if (!mono_error_ok (&error))
5429 mono_error_raise_exception (&error);
5430 return result;
5434 * mono_string_to_utf8_checked:
5435 * @s: a System.String
5436 * @error: a MonoError.
5438 * Converts a MonoString to its UTF8 representation. May fail; check
5439 * @error to determine whether the conversion was successful.
5440 * The resulting buffer should be freed with mono_free().
5442 char *
5443 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5445 long written = 0;
5446 char *as;
5447 GError *gerror = NULL;
5449 mono_error_init (error);
5451 if (s == NULL)
5452 return NULL;
5454 if (!s->length)
5455 return g_strdup ("");
5457 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5458 if (gerror) {
5459 mono_error_set_argument (error, "string", "%s", gerror->message);
5460 g_error_free (gerror);
5461 return NULL;
5463 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5464 if (s->length > written) {
5465 /* allocate the total length and copy the part of the string that has been converted */
5466 char *as2 = g_malloc0 (s->length);
5467 memcpy (as2, as, written);
5468 g_free (as);
5469 as = as2;
5472 return as;
5476 * mono_string_to_utf16:
5477 * @s: a MonoString
5479 * Return an null-terminated array of the utf-16 chars
5480 * contained in @s. The result must be freed with g_free().
5481 * This is a temporary helper until our string implementation
5482 * is reworked to always include the null terminating char.
5484 mono_unichar2*
5485 mono_string_to_utf16 (MonoString *s)
5487 char *as;
5489 if (s == NULL)
5490 return NULL;
5492 as = g_malloc ((s->length * 2) + 2);
5493 as [(s->length * 2)] = '\0';
5494 as [(s->length * 2) + 1] = '\0';
5496 if (!s->length) {
5497 return (gunichar2 *)(as);
5500 memcpy (as, mono_string_chars(s), s->length * 2);
5501 return (gunichar2 *)(as);
5505 * mono_string_from_utf16:
5506 * @data: the UTF16 string (LPWSTR) to convert
5508 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5510 * Returns: a MonoString.
5512 MonoString *
5513 mono_string_from_utf16 (gunichar2 *data)
5515 MonoDomain *domain = mono_domain_get ();
5516 int len = 0;
5518 if (!data)
5519 return NULL;
5521 while (data [len]) len++;
5523 return mono_string_new_utf16 (domain, data, len);
5527 static char *
5528 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, MonoError *error)
5530 char *r;
5531 char *mp_s;
5532 int len;
5534 r = mono_string_to_utf8_checked (s, error);
5535 if (!mono_error_ok (error))
5536 return NULL;
5538 if (!mp && !image)
5539 return r;
5541 len = strlen (r) + 1;
5542 if (mp)
5543 mp_s = mono_mempool_alloc (mp, len);
5544 else
5545 mp_s = mono_image_alloc (image, len);
5547 memcpy (mp_s, r, len);
5549 g_free (r);
5551 return mp_s;
5555 * mono_string_to_utf8_image:
5556 * @s: a System.String
5558 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5560 char *
5561 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5563 return mono_string_to_utf8_internal (NULL, image, s, error);
5567 * mono_string_to_utf8_mp:
5568 * @s: a System.String
5570 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5572 char *
5573 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5575 return mono_string_to_utf8_internal (mp, NULL, s, error);
5578 static void
5579 default_ex_handler (MonoException *ex)
5581 MonoObject *o = (MonoObject*)ex;
5582 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
5583 exit (1);
5586 static MonoExceptionFunc ex_handler = default_ex_handler;
5589 * mono_install_handler:
5590 * @func: exception handler
5592 * This is an internal JIT routine used to install the handler for exceptions
5593 * being throwh.
5595 void
5596 mono_install_handler (MonoExceptionFunc func)
5598 ex_handler = func? func: default_ex_handler;
5602 * mono_raise_exception:
5603 * @ex: exception object
5605 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5607 void
5608 mono_raise_exception (MonoException *ex)
5611 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5612 * that will cause gcc to omit the function epilog, causing problems when
5613 * the JIT tries to walk the stack, since the return address on the stack
5614 * will point into the next function in the executable, not this one.
5616 ex_handler (ex);
5620 * mono_wait_handle_new:
5621 * @domain: Domain where the object will be created
5622 * @handle: Handle for the wait handle
5624 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5626 MonoWaitHandle *
5627 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5629 MonoWaitHandle *res;
5630 gpointer params [1];
5631 static MonoMethod *handle_set;
5633 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5635 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5636 if (!handle_set)
5637 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5639 params [0] = &handle;
5640 mono_runtime_invoke (handle_set, res, params, NULL);
5642 return res;
5645 HANDLE
5646 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5648 static MonoClassField *f_os_handle;
5649 static MonoClassField *f_safe_handle;
5651 if (!f_os_handle && !f_safe_handle) {
5652 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5653 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5656 if (f_os_handle) {
5657 HANDLE retval;
5658 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5659 return retval;
5660 } else {
5661 MonoSafeHandle *sh;
5662 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5663 return sh->handle;
5668 static MonoObject*
5669 mono_runtime_capture_context (MonoDomain *domain)
5671 RuntimeInvokeFunction runtime_invoke;
5673 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5674 MonoMethod *method = mono_get_context_capture_method ();
5675 MonoMethod *wrapper;
5676 if (!method)
5677 return NULL;
5678 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5679 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5680 domain->capture_context_method = mono_compile_method (method);
5683 runtime_invoke = domain->capture_context_runtime_invoke;
5685 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5688 * mono_async_result_new:
5689 * @domain:domain where the object will be created.
5690 * @handle: wait handle.
5691 * @state: state to pass to AsyncResult
5692 * @data: C closure data.
5694 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5695 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5698 MonoAsyncResult *
5699 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5701 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5702 MonoObject *context = mono_runtime_capture_context (domain);
5703 /* we must capture the execution context from the original thread */
5704 if (context) {
5705 MONO_OBJECT_SETREF (res, execution_context, context);
5706 /* note: result may be null if the flow is suppressed */
5709 res->data = data;
5710 MONO_OBJECT_SETREF (res, object_data, object_data);
5711 MONO_OBJECT_SETREF (res, async_state, state);
5712 if (handle != NULL)
5713 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5715 res->sync_completed = FALSE;
5716 res->completed = FALSE;
5718 return res;
5721 void
5722 mono_message_init (MonoDomain *domain,
5723 MonoMethodMessage *this,
5724 MonoReflectionMethod *method,
5725 MonoArray *out_args)
5727 static MonoClass *object_array_klass;
5728 static MonoClass *byte_array_klass;
5729 static MonoClass *string_array_klass;
5730 MonoMethodSignature *sig = mono_method_signature (method->method);
5731 MonoString *name;
5732 int i, j;
5733 char **names;
5734 guint8 arg_type;
5736 if (!object_array_klass) {
5737 MonoClass *klass;
5739 klass = mono_array_class_get (mono_defaults.byte_class, 1);
5740 g_assert (klass);
5741 byte_array_klass = klass;
5743 klass = mono_array_class_get (mono_defaults.string_class, 1);
5744 g_assert (klass);
5745 string_array_klass = klass;
5747 klass = mono_array_class_get (mono_defaults.object_class, 1);
5748 g_assert (klass);
5750 mono_atomic_store_release (&object_array_klass, klass);
5753 MONO_OBJECT_SETREF (this, method, method);
5755 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
5756 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
5757 this->async_result = NULL;
5758 this->call_type = CallType_Sync;
5760 names = g_new (char *, sig->param_count);
5761 mono_method_get_param_names (method->method, (const char **) names);
5762 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
5764 for (i = 0; i < sig->param_count; i++) {
5765 name = mono_string_new (domain, names [i]);
5766 mono_array_setref (this->names, i, name);
5769 g_free (names);
5770 for (i = 0, j = 0; i < sig->param_count; i++) {
5771 if (sig->params [i]->byref) {
5772 if (out_args) {
5773 MonoObject* arg = mono_array_get (out_args, gpointer, j);
5774 mono_array_setref (this->args, i, arg);
5775 j++;
5777 arg_type = 2;
5778 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5779 arg_type |= 1;
5780 } else {
5781 arg_type = 1;
5782 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5783 arg_type |= 4;
5785 mono_array_set (this->arg_types, guint8, i, arg_type);
5790 * mono_remoting_invoke:
5791 * @real_proxy: pointer to a RealProxy object
5792 * @msg: The MonoMethodMessage to execute
5793 * @exc: used to store exceptions
5794 * @out_args: used to store output arguments
5796 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5797 * IMessage interface and it is not trivial to extract results from there. So
5798 * we call an helper method PrivateInvoke instead of calling
5799 * RealProxy::Invoke() directly.
5801 * Returns: the result object.
5803 MonoObject *
5804 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
5805 MonoObject **exc, MonoArray **out_args)
5807 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5808 gpointer pa [4];
5810 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5812 if (!im) {
5813 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
5814 g_assert (im);
5815 real_proxy->vtable->domain->private_invoke_method = im;
5818 pa [0] = real_proxy;
5819 pa [1] = msg;
5820 pa [2] = exc;
5821 pa [3] = out_args;
5823 return mono_runtime_invoke (im, NULL, pa, exc);
5826 MonoObject *
5827 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
5828 MonoObject **exc, MonoArray **out_args)
5830 static MonoClass *object_array_klass;
5831 MonoDomain *domain;
5832 MonoMethod *method;
5833 MonoMethodSignature *sig;
5834 MonoObject *ret;
5835 int i, j, outarg_count = 0;
5837 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5839 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
5840 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5841 target = tp->rp->unwrapped_server;
5842 } else {
5843 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
5847 domain = mono_domain_get ();
5848 method = msg->method->method;
5849 sig = mono_method_signature (method);
5851 for (i = 0; i < sig->param_count; i++) {
5852 if (sig->params [i]->byref)
5853 outarg_count++;
5856 if (!object_array_klass) {
5857 MonoClass *klass;
5859 klass = mono_array_class_get (mono_defaults.object_class, 1);
5860 g_assert (klass);
5862 mono_memory_barrier ();
5863 object_array_klass = klass;
5866 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
5867 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
5868 *exc = NULL;
5870 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
5872 for (i = 0, j = 0; i < sig->param_count; i++) {
5873 if (sig->params [i]->byref) {
5874 MonoObject* arg;
5875 arg = mono_array_get (msg->args, gpointer, i);
5876 mono_array_setref (*out_args, j, arg);
5877 j++;
5881 return ret;
5885 * mono_object_to_string:
5886 * @obj: The object
5887 * @exc: Any exception thrown by ToString (). May be NULL.
5889 * Returns: the result of calling ToString () on an object.
5891 MonoString *
5892 mono_object_to_string (MonoObject *obj, MonoObject **exc)
5894 static MonoMethod *to_string = NULL;
5895 MonoMethod *method;
5897 g_assert (obj);
5899 if (!to_string)
5900 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
5902 method = mono_object_get_virtual_method (obj, to_string);
5904 return (MonoString *) mono_runtime_invoke (method, obj, NULL, exc);
5908 * mono_print_unhandled_exception:
5909 * @exc: The exception
5911 * Prints the unhandled exception.
5913 void
5914 mono_print_unhandled_exception (MonoObject *exc)
5916 MonoString * str;
5917 char *message = (char*)"";
5918 gboolean free_message = FALSE;
5919 MonoError error;
5921 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
5922 message = g_strdup ("OutOfMemoryException");
5923 free_message = TRUE;
5924 } else {
5926 if (((MonoException*)exc)->native_trace_ips) {
5927 message = mono_exception_get_native_backtrace ((MonoException*)exc);
5928 free_message = TRUE;
5929 } else {
5930 MonoObject *inner_ex = NULL;
5931 str = mono_object_to_string (exc, &inner_ex);
5932 if (inner_ex) {
5933 message = g_strdup_printf ("recursive exception handling %s:%s", mono_object_get_class (exc)->name_space, mono_object_get_class (exc)->name);
5934 free_message = TRUE;
5935 } if (str) {
5936 message = mono_string_to_utf8_checked (str, &error);
5937 if (!mono_error_ok (&error)) {
5938 mono_error_cleanup (&error);
5939 message = (char *) "";
5940 } else {
5941 free_message = TRUE;
5948 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
5949 * exc->vtable->klass->name, message);
5951 g_printerr ("\nUnhandled Exception:\n%s\n", message);
5953 if (free_message)
5954 g_free (message);
5958 * mono_delegate_ctor:
5959 * @this: pointer to an uninitialized delegate object
5960 * @target: target object
5961 * @addr: pointer to native code
5962 * @method: method
5964 * Initialize a delegate and sets a specific method, not the one
5965 * associated with addr. This is useful when sharing generic code.
5966 * In that case addr will most probably not be associated with the
5967 * correct instantiation of the method.
5969 void
5970 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
5972 MonoDelegate *delegate = (MonoDelegate *)this;
5973 MonoClass *class;
5975 g_assert (this);
5976 g_assert (addr);
5978 if (method)
5979 delegate->method = method;
5981 class = this->vtable->klass;
5982 mono_stats.delegate_creations++;
5984 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5985 g_assert (method);
5986 method = mono_marshal_get_remoting_invoke (method);
5987 delegate->method_ptr = mono_compile_method (method);
5988 MONO_OBJECT_SETREF (delegate, target, target);
5989 } else if (method && mono_method_signature (method)->hasthis && method->klass->valuetype) {
5990 method = mono_marshal_get_unbox_wrapper (method);
5991 delegate->method_ptr = mono_compile_method (method);
5992 MONO_OBJECT_SETREF (delegate, target, target);
5993 } else {
5994 delegate->method_ptr = addr;
5995 MONO_OBJECT_SETREF (delegate, target, target);
5998 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
6002 * mono_delegate_ctor:
6003 * @this: pointer to an uninitialized delegate object
6004 * @target: target object
6005 * @addr: pointer to native code
6007 * This is used to initialize a delegate.
6009 void
6010 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
6012 MonoDomain *domain = mono_domain_get ();
6013 MonoJitInfo *ji;
6014 MonoMethod *method = NULL;
6016 g_assert (addr);
6018 ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr));
6019 /* Shared code */
6020 if (!ji && domain != mono_get_root_domain ())
6021 ji = mono_jit_info_table_find (mono_get_root_domain (), mono_get_addr_from_ftnptr (addr));
6022 if (ji) {
6023 method = ji->method;
6024 g_assert (!method->klass->generic_container);
6027 mono_delegate_ctor_with_method (this, target, addr, method);
6031 * mono_method_call_message_new:
6032 * @method: method to encapsulate
6033 * @params: parameters to the method
6034 * @invoke: optional, delegate invoke.
6035 * @cb: async callback delegate.
6036 * @state: state passed to the async callback.
6038 * Translates arguments pointers into a MonoMethodMessage.
6040 MonoMethodMessage *
6041 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
6042 MonoDelegate **cb, MonoObject **state)
6044 MonoDomain *domain = mono_domain_get ();
6045 MonoMethodSignature *sig = mono_method_signature (method);
6046 MonoMethodMessage *msg;
6047 int i, count, type;
6049 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6051 if (invoke) {
6052 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
6053 count = sig->param_count - 2;
6054 } else {
6055 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
6056 count = sig->param_count;
6059 for (i = 0; i < count; i++) {
6060 gpointer vpos;
6061 MonoClass *class;
6062 MonoObject *arg;
6064 if (sig->params [i]->byref)
6065 vpos = *((gpointer *)params [i]);
6066 else
6067 vpos = params [i];
6069 type = sig->params [i]->type;
6070 class = mono_class_from_mono_type (sig->params [i]);
6072 if (class->valuetype)
6073 arg = mono_value_box (domain, class, vpos);
6074 else
6075 arg = *((MonoObject **)vpos);
6077 mono_array_setref (msg->args, i, arg);
6080 if (cb != NULL && state != NULL) {
6081 *cb = *((MonoDelegate **)params [i]);
6082 i++;
6083 *state = *((MonoObject **)params [i]);
6086 return msg;
6090 * mono_method_return_message_restore:
6092 * Restore results from message based processing back to arguments pointers
6094 void
6095 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
6097 MonoMethodSignature *sig = mono_method_signature (method);
6098 int i, j, type, size, out_len;
6100 if (out_args == NULL)
6101 return;
6102 out_len = mono_array_length (out_args);
6103 if (out_len == 0)
6104 return;
6106 for (i = 0, j = 0; i < sig->param_count; i++) {
6107 MonoType *pt = sig->params [i];
6109 if (pt->byref) {
6110 char *arg;
6111 if (j >= out_len)
6112 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
6114 arg = mono_array_get (out_args, gpointer, j);
6115 type = pt->type;
6117 g_assert (type != MONO_TYPE_VOID);
6119 if (MONO_TYPE_IS_REFERENCE (pt)) {
6120 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
6121 } else {
6122 if (arg) {
6123 MonoClass *class = ((MonoObject*)arg)->vtable->klass;
6124 size = mono_class_value_size (class, NULL);
6125 if (class->has_references)
6126 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
6127 else
6128 mono_gc_memmove (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6129 } else {
6130 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6131 mono_gc_bzero (*((gpointer *)params [i]), size);
6135 j++;
6141 * mono_load_remote_field:
6142 * @this: pointer to an object
6143 * @klass: klass of the object containing @field
6144 * @field: the field to load
6145 * @res: a storage to store the result
6147 * This method is called by the runtime on attempts to load fields of
6148 * transparent proxy objects. @this points to such TP, @klass is the class of
6149 * the object containing @field. @res is a storage location which can be
6150 * used to store the result.
6152 * Returns: an address pointing to the value of field.
6154 gpointer
6155 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
6157 static MonoMethod *getter = NULL;
6158 MonoDomain *domain = mono_domain_get ();
6159 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6160 MonoClass *field_class;
6161 MonoMethodMessage *msg;
6162 MonoArray *out_args;
6163 MonoObject *exc;
6164 char* full_name;
6166 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6167 g_assert (res != NULL);
6169 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6170 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6171 return res;
6174 if (!getter) {
6175 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6176 g_assert (getter);
6179 field_class = mono_class_from_mono_type (field->type);
6181 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6182 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6183 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6185 full_name = mono_type_get_full_name (klass);
6186 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6187 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6188 g_free (full_name);
6190 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6192 if (exc) mono_raise_exception ((MonoException *)exc);
6194 if (mono_array_length (out_args) == 0)
6195 return NULL;
6197 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6199 if (field_class->valuetype) {
6200 return ((char *)*res) + sizeof (MonoObject);
6201 } else
6202 return res;
6206 * mono_load_remote_field_new:
6207 * @this:
6208 * @klass:
6209 * @field:
6211 * Missing documentation.
6213 MonoObject *
6214 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
6216 static MonoMethod *getter = NULL;
6217 MonoDomain *domain = mono_domain_get ();
6218 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6219 MonoClass *field_class;
6220 MonoMethodMessage *msg;
6221 MonoArray *out_args;
6222 MonoObject *exc, *res;
6223 char* full_name;
6225 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6227 field_class = mono_class_from_mono_type (field->type);
6229 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6230 gpointer val;
6231 if (field_class->valuetype) {
6232 res = mono_object_new (domain, field_class);
6233 val = ((gchar *) res) + sizeof (MonoObject);
6234 } else {
6235 val = &res;
6237 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6238 return res;
6241 if (!getter) {
6242 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6243 g_assert (getter);
6246 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6247 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6249 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6251 full_name = mono_type_get_full_name (klass);
6252 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6253 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6254 g_free (full_name);
6256 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6258 if (exc) mono_raise_exception ((MonoException *)exc);
6260 if (mono_array_length (out_args) == 0)
6261 res = NULL;
6262 else
6263 res = mono_array_get (out_args, MonoObject *, 0);
6265 return res;
6269 * mono_store_remote_field:
6270 * @this: pointer to an object
6271 * @klass: klass of the object containing @field
6272 * @field: the field to load
6273 * @val: the value/object to store
6275 * This method is called by the runtime on attempts to store fields of
6276 * transparent proxy objects. @this points to such TP, @klass is the class of
6277 * the object containing @field. @val is the new value to store in @field.
6279 void
6280 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
6282 static MonoMethod *setter = NULL;
6283 MonoDomain *domain = mono_domain_get ();
6284 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6285 MonoClass *field_class;
6286 MonoMethodMessage *msg;
6287 MonoArray *out_args;
6288 MonoObject *exc;
6289 MonoObject *arg;
6290 char* full_name;
6292 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6294 field_class = mono_class_from_mono_type (field->type);
6296 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6297 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6298 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6299 return;
6302 if (!setter) {
6303 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6304 g_assert (setter);
6307 if (field_class->valuetype)
6308 arg = mono_value_box (domain, field_class, val);
6309 else
6310 arg = *((MonoObject **)val);
6313 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6314 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6316 full_name = mono_type_get_full_name (klass);
6317 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6318 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6319 mono_array_setref (msg->args, 2, arg);
6320 g_free (full_name);
6322 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6324 if (exc) mono_raise_exception ((MonoException *)exc);
6328 * mono_store_remote_field_new:
6329 * @this:
6330 * @klass:
6331 * @field:
6332 * @arg:
6334 * Missing documentation
6336 void
6337 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6339 static MonoMethod *setter = NULL;
6340 MonoDomain *domain = mono_domain_get ();
6341 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6342 MonoClass *field_class;
6343 MonoMethodMessage *msg;
6344 MonoArray *out_args;
6345 MonoObject *exc;
6346 char* full_name;
6348 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6350 field_class = mono_class_from_mono_type (field->type);
6352 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6353 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6354 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6355 return;
6358 if (!setter) {
6359 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6360 g_assert (setter);
6363 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6364 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6366 full_name = mono_type_get_full_name (klass);
6367 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6368 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6369 mono_array_setref (msg->args, 2, arg);
6370 g_free (full_name);
6372 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6374 if (exc) mono_raise_exception ((MonoException *)exc);
6378 * mono_create_ftnptr:
6380 * Given a function address, create a function descriptor for it.
6381 * This is only needed on some platforms.
6383 gpointer
6384 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6386 return callbacks.create_ftnptr (domain, addr);
6390 * mono_get_addr_from_ftnptr:
6392 * Given a pointer to a function descriptor, return the function address.
6393 * This is only needed on some platforms.
6395 gpointer
6396 mono_get_addr_from_ftnptr (gpointer descr)
6398 return callbacks.get_addr_from_ftnptr (descr);
6402 * mono_string_chars:
6403 * @s: a MonoString
6405 * Returns a pointer to the UCS16 characters stored in the MonoString
6407 gunichar2 *
6408 mono_string_chars (MonoString *s)
6410 return s->chars;
6414 * mono_string_length:
6415 * @s: MonoString
6417 * Returns the lenght in characters of the string
6420 mono_string_length (MonoString *s)
6422 return s->length;
6426 * mono_array_length:
6427 * @array: a MonoArray*
6429 * Returns the total number of elements in the array. This works for
6430 * both vectors and multidimensional arrays.
6432 uintptr_t
6433 mono_array_length (MonoArray *array)
6435 return array->max_length;
6439 * mono_array_addr_with_size:
6440 * @array: a MonoArray*
6441 * @size: size of the array elements
6442 * @idx: index into the array
6444 * Returns the address of the @idx element in the array.
6446 char*
6447 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
6449 return ((char*)(array)->vector) + size * idx;